// 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.
// Package acme provides an implementation of the
// Automatic Certificate Management Environment (ACME) spec,
// most famously used by Let's Encrypt.
//
// The initial implementation of this package was based on an early version
// of the spec. The current implementation supports only the modern
// RFC 8555 but some of the old API surface remains for compatibility.
// While code using the old API will still compile, it will return an error.
// Note the deprecation comments to update your code.
//
// See https://tools.ietf.org/html/rfc8555 for the spec.
//
// Most common scenarios will want to use autocert subdirectory instead,
// which provides automatic access to certificates from Let's Encrypt
// and any other ACME-based CA.
package acme
import (
"context"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"math/big"
"net"
"net/http"
"strings"
"sync"
"time"
)
const (
// LetsEncryptURL is the Directory endpoint of Let's Encrypt CA.
LetsEncryptURL = "https://acme-v02.api.letsencrypt.org/directory"
// ALPNProto is the ALPN protocol name used by a CA server when validating
// tls-alpn-01 challenges.
//
// Package users must ensure their servers can negotiate the ACME ALPN in
// order for tls-alpn-01 challenge verifications to succeed.
// See the crypto/tls package's Config.NextProtos field.
ALPNProto = "acme-tls/1"
)
// idPeACMEIdentifier is the OID for the ACME extension for the TLS-ALPN challenge.
// https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-05#section-5.1
var idPeACMEIdentifier = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 31}
const (
maxChainLen = 5 // max depth and breadth of a certificate chain
maxCertSize = 1 << 20 // max size of a certificate, in DER bytes
// Used for decoding certs from application/pem-certificate-chain response,
// the default when in RFC mode.
maxCertChainSize = maxCertSize * maxChainLen
// Max number of collected nonces kept in memory.
// Expect usual peak of 1 or 2.
maxNonces = 100
)
// Client is an ACME client.
//
// The only required field is Key. An example of creating a client with a new key
// is as follows:
//
// key, err := rsa.GenerateKey(rand.Reader, 2048)
// if err != nil {
// log.Fatal(err)
// }
// client := &Client{Key: key}
type Client struct {
// Key is the account key used to register with a CA and sign requests.
// Key.Public() must return a *rsa.PublicKey or *ecdsa.PublicKey.
//
// The following algorithms are supported:
// RS256, ES256, ES384 and ES512.
// See RFC 7518 for more details about the algorithms.
Key crypto.Signer
// HTTPClient optionally specifies an HTTP client to use
// instead of http.DefaultClient.
HTTPClient *http.Client
// DirectoryURL points to the CA directory endpoint.
// If empty, LetsEncryptURL is used.
// Mutating this value after a successful call of Client's Discover method
// will have no effect.
DirectoryURL string
// RetryBackoff computes the duration after which the nth retry of a failed request
// should occur. The value of n for the first call on failure is 1.
// The values of r and resp are the request and response of the last failed attempt.
// If the returned value is negative or zero, no more retries are done and an error
// is returned to the caller of the original method.
//
// Requests which result in a 4xx client error are not retried,
// except for 400 Bad Request due to "bad nonce" errors and 429 Too Many Requests.
//
// If RetryBackoff is nil, a truncated exponential backoff algorithm
// with the ceiling of 10 seconds is used, where each subsequent retry n
// is done after either ("Retry-After" + jitter) or (2^n seconds + jitter),
// preferring the former if "Retry-After" header is found in the resp.
// The jitter is a random value up to 1 second.
RetryBackoff func(n int, r *http.Request, resp *http.Response) time.Duration
// UserAgent is prepended to the User-Agent header sent to the ACME server,
// which by default is this package's name and version.
//
// Reusable libraries and tools in particular should set this value to be
// identifiable by the server, in case they are causing issues.
UserAgent string
cacheMu sync.Mutex
dir *Directory // cached result of Client's Discover method
// KID is the key identifier provided by the CA. If not provided it will be
// retrieved from the CA by making a call to the registration endpoint.
KID KeyID
noncesMu sync.Mutex
nonces map[string]struct{} // nonces collected from previous responses
}
// accountKID returns a key ID associated with c.Key, the account identity
// provided by the CA during RFC based registration.
// It assumes c.Discover has already been called.
//
// accountKID requires at most one network roundtrip.
// It caches only successful result.
//
// When in pre-RFC mode or when c.getRegRFC responds with an error, accountKID
// returns noKeyID.
func (c *Client) accountKID(ctx context.Context) KeyID {
c.cacheMu.Lock()
defer c.cacheMu.Unlock()
if c.KID != noKeyID {
return c.KID
}
a, err := c.getRegRFC(ctx)
if err != nil {
return noKeyID
}
c.KID = KeyID(a.URI)
return c.KID
}
var errPreRFC = errors.New("acme: server does not support the RFC 8555 version of ACME")
// Discover performs ACME server discovery using c.DirectoryURL.
//
// It caches successful result. So, subsequent calls will not result in
// a network round-trip. This also means mutating c.DirectoryURL after successful call
// of this method will have no effect.
func (c *Client) Discover(ctx context.Context) (Directory, error) {
c.cacheMu.Lock()
defer c.cacheMu.Unlock()
if c.dir != nil {
return *c.dir, nil
}
res, err := c.get(ctx, c.directoryURL(), wantStatus(http.StatusOK))
if err != nil {
return Directory{}, err
}
defer res.Body.Close()
c.addNonce(res.Header)
var v struct {
Reg string `json:"newAccount"`
Authz string `json:"newAuthz"`
Order string `json:"newOrder"`
Revoke string `json:"revokeCert"`
Nonce string `json:"newNonce"`
KeyChange string `json:"keyChange"`
Meta struct {
Terms string `json:"termsOfService"`
Website string `json:"website"`
CAA []string `json:"caaIdentities"`
ExternalAcct bool `json:"externalAccountRequired"`
}
}
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
return Directory{}, err
}
if v.Order == "" {
return Directory{}, errPreRFC
}
c.dir = &Directory{
RegURL: v.Reg,
AuthzURL: v.Authz,
OrderURL: v.Order,
RevokeURL: v.Revoke,
NonceURL: v.Nonce,
KeyChangeURL: v.KeyChange,
Terms: v.Meta.Terms,
Website: v.Meta.Website,
CAA: v.Meta.CAA,
ExternalAccountRequired: v.Meta.ExternalAcct,
}
return *c.dir, nil
}
func (c *Client) directoryURL() string {
if c.DirectoryURL != "" {
return c.DirectoryURL
}
return LetsEncryptURL
}
// CreateCert was part of the old version of ACME. It is incompatible with RFC 8555.
//
// Deprecated: this was for the pre-RFC 8555 version of ACME. Callers should use CreateOrderCert.
func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration, bundle bool) (der [][]byte, certURL string, err error) {
return nil, "", errPreRFC
}
// FetchCert retrieves already issued certificate from the given url, in DER format.
// It retries the request until the certificate is successfully retrieved,
// context is cancelled by the caller or an error response is received.
//
// If the bundle argument is true, the returned value also contains the CA (issuer)
// certificate chain.
//
// FetchCert returns an error if the CA's response or chain was unreasonably large.
// Callers are encouraged to parse the returned value to ensure the certificate is valid
// and has expected features.
func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error) {
if _, err := c.Discover(ctx); err != nil {
return nil, err
}
return c.fetchCertRFC(ctx, url, bundle)
}
// RevokeCert revokes a previously issued certificate cert, provided in DER format.
//
// The key argument, used to sign the request, must be authorized
// to revoke the certificate. It's up to the CA to decide which keys are authorized.
// For instance, the key pair of the certificate may be authorized.
// If the key is nil, c.Key is used instead.
func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte, reason CRLReasonCode) error {
if _, err := c.Discover(ctx); err != nil {
return err
}
return c.revokeCertRFC(ctx, key, cert, reason)
}
// AcceptTOS always returns true to indicate the acceptance of a CA's Terms of Service
// during account registration. See Register method of Client for more details.
func AcceptTOS(tosURL string) bool { return true }
// Register creates a new account with the CA using c.Key.
// It returns the registered account. The account acct is not modified.
//
// The registration may require the caller to agree to the CA's Terms of Service (TOS).
// If so, and the account has not indicated the acceptance of the terms (see Account for details),
// Register calls prompt with a TOS URL provided by the CA. Prompt should report
// whether the caller agrees to the terms. To always accept the terms, the caller can use AcceptTOS.
//
// When interfacing with an RFC-compliant CA, non-RFC 8555 fields of acct are ignored
// and prompt is called if Directory's Terms field is non-zero.
// Also see Error's Instance field for when a CA requires already registered accounts to agree
// to an updated Terms of Service.
func (c *Client) Register(ctx context.Context, acct *Account, prompt func(tosURL string) bool) (*Account, error) {
if c.Key == nil {
return nil, errors.New("acme: client.Key must be set to Register")
}
if _, err := c.Discover(ctx); err != nil {
return nil, err
}
return c.registerRFC(ctx, acct, prompt)
}
// GetReg retrieves an existing account associated with c.Key.
//
// The url argument is a legacy artifact of the pre-RFC 8555 API
// and is ignored.
func (c *Client) GetReg(ctx context.Context, url string) (*Account, error) {
if _, err := c.Discover(ctx); err != nil {
return nil, err
}
return c.getRegRFC(ctx)
}
// UpdateReg updates an existing registration.
// It returns an updated account copy. The provided account is not modified.
//
// The account's URI is ignored and the account URL associated with
// c.Key is used instead.
func (c *Client) UpdateReg(ctx context.Context, acct *Account) (*Account, error) {
if _, err := c.Discover(ctx); err != nil {
return nil, err
}
return c.updateRegRFC(ctx, acct)
}
// AccountKeyRollover attempts to transition a client's account key to a new key.
// On success client's Key is updated which is not concurrency safe.
// On failure an error will be returned.
// The new key is already registered with the ACME provider if the following is true:
// - error is of type acme.Error
// - StatusCode should be 409 (Conflict)
// - Location header will have the KID of the associated account
//
// More about account key rollover can be found at
// https://tools.ietf.org/html/rfc8555#section-7.3.5.
func (c *Client) AccountKeyRollover(ctx context.Context, newKey crypto.Signer) error {
return c.accountKeyRollover(ctx, newKey)
}
// Authorize performs the initial step in the pre-authorization flow,
// as opposed to order-based flow.
// The caller will then need to choose from and perform a set of returned
// challenges using c.Accept in order to successfully complete authorization.
//
// Once complete, the caller can use AuthorizeOrder which the CA
// should provision with the already satisfied authorization.
// For pre-RFC CAs, the caller can proceed directly to requesting a certificate
// using CreateCert method.
//
// If an authorization has been previously granted, the CA may return
// a valid authorization which has its Status field set to StatusValid.
//
// More about pre-authorization can be found at
// https://tools.ietf.org/html/rfc8555#section-7.4.1.
func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, error) {
return c.authorize(ctx, "dns", domain)
}
// AuthorizeIP is the same as Authorize but requests IP address authorization.
// Clients which successfully obtain such authorization may request to issue
// a certificate for IP addresses.
//
// See the ACME spec extension for more details about IP address identifiers:
// https://tools.ietf.org/html/draft-ietf-acme-ip.
func (c *Client) AuthorizeIP(ctx context.Context, ipaddr string) (*Authorization, error) {
return c.authorize(ctx, "ip", ipaddr)
}
func (c *Client) authorize(ctx context.Context, typ, val string) (*Authorization, error) {
if _, err := c.Discover(ctx); err != nil {
return nil, err
}
if c.dir.AuthzURL == "" {
// Pre-Authorization is unsupported
return nil, errPreAuthorizationNotSupported
}
type authzID struct {
Type string `json:"type"`
Value string `json:"value"`
}
req := struct {
Resource string `json:"resource"`
Identifier authzID `json:"identifier"`
}{
Resource: "new-authz",
Identifier: authzID{Type: typ, Value: val},
}
res, err := c.post(ctx, nil, c.dir.AuthzURL, req, wantStatus(http.StatusCreated))
if err != nil {
return nil, err
}
defer res.Body.Close()
var v wireAuthz
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
return nil, fmt.Errorf("acme: invalid response: %v", err)
}
if v.Status != StatusPending && v.Status != StatusValid {
return nil, fmt.Errorf("acme: unexpected status: %s", v.Status)
}
return v.authorization(res.Header.Get("Location")), nil
}
// GetAuthorization retrieves an authorization identified by the given URL.
//
// If a caller needs to poll an authorization until its status is final,
// see the WaitAuthorization method.
func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorization, error) {
if _, err := c.Discover(ctx); err != nil {
return nil, err
}
res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK))
if err != nil {
return nil, err
}
defer res.Body.Close()
var v wireAuthz
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
return nil, fmt.Errorf("acme: invalid response: %v", err)
}
return v.authorization(url), nil
}
// RevokeAuthorization relinquishes an existing authorization identified
// by the given URL.
// The url argument is an Authorization.URI value.
//
// If successful, the caller will be required to obtain a new authorization
// using the Authorize or AuthorizeOrder methods before being able to request
// a new certificate for the domain associated with the authorization.
//
// It does not revoke existing certificates.
func (c *Client) RevokeAuthorization(ctx context.Context, url string) error {
if _, err := c.Discover(ctx); err != nil {
return err
}
req := struct {
Resource string `json:"resource"`
Status string `json:"status"`
Delete bool `json:"delete"`
}{
Resource: "authz",
Status: "deactivated",
Delete: true,
}
res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK))
if err != nil {
return err
}
defer res.Body.Close()
return nil
}
// WaitAuthorization polls an authorization at the given URL
// until it is in one of the final states, StatusValid or StatusInvalid,
// the ACME CA responded with a 4xx error code, or the context is done.
//
// It returns a non-nil Authorization only if its Status is StatusValid.
// In all other cases WaitAuthorization returns an error.
// If the Status is StatusInvalid, the returned error is of type *AuthorizationError.
func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorization, error) {
if _, err := c.Discover(ctx); err != nil {
return nil, err
}
for {
res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
if err != nil {
return nil, err
}
var raw wireAuthz
err = json.NewDecoder(res.Body).Decode(&raw)
res.Body.Close()
switch {
case err != nil:
// Skip and retry.
case raw.Status == StatusValid:
return raw.authorization(url), nil
case raw.Status == StatusInvalid:
return nil, raw.error(url)
}
// Exponential backoff is implemented in c.get above.
// This is just to prevent continuously hitting the CA
// while waiting for a final authorization status.
d := retryAfter(res.Header.Get("Retry-After"))
if d == 0 {
// Given that the fastest challenges TLS-ALPN and HTTP-01
// require a CA to make at least 1 network round trip
// and most likely persist a challenge state,
// this default delay seems reasonable.
d = time.Second
}
t := time.NewTimer(d)
select {
case <-ctx.Done():
t.Stop()
return nil, ctx.Err()
case <-t.C:
// Retry.
}
}
}
// GetChallenge retrieves the current status of an challenge.
//
// A client typically polls a challenge status using this method.
func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, error) {
if _, err := c.Discover(ctx); err != nil {
return nil, err
}
res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
if err != nil {
return nil, err
}
defer res.Body.Close()
v := wireChallenge{URI: url}
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
return nil, fmt.Errorf("acme: invalid response: %v", err)
}
return v.challenge(), nil
}
// Accept informs the server that the client accepts one of its challenges
// previously obtained with c.Authorize.
//
// The server will then perform the validation asynchronously.
func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error) {
if _, err := c.Discover(ctx); err != nil {
return nil, err
}
payload := json.RawMessage("{}")
if len(chal.Payload) != 0 {
payload = chal.Payload
}
res, err := c.post(ctx, nil, chal.URI, payload, wantStatus(
http.StatusOK, // according to the spec
http.StatusAccepted, // Let's Encrypt: see https://goo.gl/WsJ7VT (acme-divergences.md)
))
if err != nil {
return nil, err
}
defer res.Body.Close()
var v wireChallenge
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
return nil, fmt.Errorf("acme: invalid response: %v", err)
}
return v.challenge(), nil
}
// DNS01ChallengeRecord returns a DNS record value for a dns-01 challenge response.
// A TXT record containing the returned value must be provisioned under
// "_acme-challenge" name of the domain being validated.
//
// The token argument is a Challenge.Token value.
func (c *Client) DNS01ChallengeRecord(token string) (string, error) {
ka, err := keyAuth(c.Key.Public(), token)
if err != nil {
return "", err
}
b := sha256.Sum256([]byte(ka))
return base64.RawURLEncoding.EncodeToString(b[:]), nil
}
// HTTP01ChallengeResponse returns the response for an http-01 challenge.
// Servers should respond with the value to HTTP requests at the URL path
// provided by HTTP01ChallengePath to validate the challenge and prove control
// over a domain name.
//
// The token argument is a Challenge.Token value.
func (c *Client) HTTP01ChallengeResponse(token string) (string, error) {
return keyAuth(c.Key.Public(), token)
}
// HTTP01ChallengePath returns the URL path at which the response for an http-01 challenge
// should be provided by the servers.
// The response value can be obtained with HTTP01ChallengeResponse.
//
// The token argument is a Challenge.Token value.
func (c *Client) HTTP01ChallengePath(token string) string {
return "/.well-known/acme-challenge/" + token
}
// TLSSNI01ChallengeCert creates a certificate for TLS-SNI-01 challenge response.
// Always returns an error.
//
// Deprecated: This challenge type was only present in pre-standardized ACME
// protocol drafts and is insecure for use in shared hosting environments.
func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (tls.Certificate, string, error) {
return tls.Certificate{}, "", errPreRFC
}
// TLSSNI02ChallengeCert creates a certificate for TLS-SNI-02 challenge response.
// Always returns an error.
//
// Deprecated: This challenge type was only present in pre-standardized ACME
// protocol drafts and is insecure for use in shared hosting environments.
func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (tls.Certificate, string, error) {
return tls.Certificate{}, "", errPreRFC
}
// TLSALPN01ChallengeCert creates a certificate for TLS-ALPN-01 challenge response.
// Servers can present the certificate to validate the challenge and prove control
// over an identifier (either a DNS name or the textual form of an IPv4 or IPv6
// address). For more details on TLS-ALPN-01 see
// https://www.rfc-editor.org/rfc/rfc8737 and https://www.rfc-editor.org/rfc/rfc8738
//
// The token argument is a Challenge.Token value.
// If a WithKey option is provided, its private part signs the returned cert,
// and the public part is used to specify the signee.
// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve.
//
// The returned certificate is valid for the next 24 hours and must be presented only when
// the server name in the TLS ClientHello matches the identifier, and the special acme-tls/1 ALPN protocol
// has been specified.
//
// Validation requests for IP address identifiers will use the reverse DNS form in the server name
// in the TLS ClientHello since the SNI extension is not supported for IP addresses.
// See RFC 8738 Section 6 for more information.
func (c *Client) TLSALPN01ChallengeCert(token, identifier string, opt ...CertOption) (cert tls.Certificate, err error) {
ka, err := keyAuth(c.Key.Public(), token)
if err != nil {
return tls.Certificate{}, err
}
shasum := sha256.Sum256([]byte(ka))
extValue, err := asn1.Marshal(shasum[:])
if err != nil {
return tls.Certificate{}, err
}
acmeExtension := pkix.Extension{
Id: idPeACMEIdentifier,
Critical: true,
Value: extValue,
}
tmpl := defaultTLSChallengeCertTemplate()
var newOpt []CertOption
for _, o := range opt {
switch o := o.(type) {
case *certOptTemplate:
t := *(*x509.Certificate)(o) // shallow copy is ok
tmpl = &t
default:
newOpt = append(newOpt, o)
}
}
tmpl.ExtraExtensions = append(tmpl.ExtraExtensions, acmeExtension)
newOpt = append(newOpt, WithTemplate(tmpl))
return tlsChallengeCert(identifier, newOpt)
}
// popNonce returns a nonce value previously stored with c.addNonce
// or fetches a fresh one from c.dir.NonceURL.
// If NonceURL is empty, it first tries c.directoryURL() and, failing that,
// the provided url.
func (c *Client) popNonce(ctx context.Context, url string) (string, error) {
c.noncesMu.Lock()
defer c.noncesMu.Unlock()
if len(c.nonces) == 0 {
if c.dir != nil && c.dir.NonceURL != "" {
return c.fetchNonce(ctx, c.dir.NonceURL)
}
dirURL := c.directoryURL()
v, err := c.fetchNonce(ctx, dirURL)
if err != nil && url != dirURL {
v, err = c.fetchNonce(ctx, url)
}
return v, err
}
var nonce string
for nonce = range c.nonces {
delete(c.nonces, nonce)
break
}
return nonce, nil
}
// clearNonces clears any stored nonces
func (c *Client) clearNonces() {
c.noncesMu.Lock()
defer c.noncesMu.Unlock()
c.nonces = make(map[string]struct{})
}
// 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 (c *Client) fetchNonce(ctx context.Context, url string) (string, error) {
r, err := http.NewRequestWithContext(ctx, "HEAD", url, nil)
if err != nil {
return "", err
}
resp, err := c.doNoRetry(ctx, r)
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")
}
// linkHeader returns URI-Reference values of all Link headers
// with relation-type rel.
// See https://tools.ietf.org/html/rfc5988#section-5 for details.
func linkHeader(h http.Header, rel string) []string {
var links []string
for _, v := range h["Link"] {
parts := strings.Split(v, ";")
for _, p := range parts {
p = strings.TrimSpace(p)
if !strings.HasPrefix(p, "rel=") {
continue
}
if v := strings.Trim(p[4:], `"`); v == rel {
links = append(links, strings.Trim(parts[0], "<>"))
}
}
}
return links
}
// keyAuth generates a key authorization string for a given token.
func keyAuth(pub crypto.PublicKey, token string) (string, error) {
th, err := JWKThumbprint(pub)
if err != nil {
return "", err
}
return fmt.Sprintf("%s.%s", token, th), nil
}
// defaultTLSChallengeCertTemplate is a template used to create challenge certs for TLS challenges.
func defaultTLSChallengeCertTemplate() *x509.Certificate {
return &x509.Certificate{
SerialNumber: big.NewInt(1),
NotBefore: time.Now(),
NotAfter: time.Now().Add(24 * time.Hour),
BasicConstraintsValid: true,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
}
}
// tlsChallengeCert creates a temporary certificate for TLS-ALPN challenges
// for the given identifier, using an auto-generated public/private key pair.
//
// If the provided identifier is a domain name, it will be used as a DNS type SAN and for the
// subject common name. If the provided identifier is an IP address it will be used as an IP type
// SAN.
//
// To create a cert with a custom key pair, specify WithKey option.
func tlsChallengeCert(identifier string, opt []CertOption) (tls.Certificate, error) {
var key crypto.Signer
tmpl := defaultTLSChallengeCertTemplate()
for _, o := range opt {
switch o := o.(type) {
case *certOptKey:
if key != nil {
return tls.Certificate{}, errors.New("acme: duplicate key option")
}
key = o.key
case *certOptTemplate:
t := *(*x509.Certificate)(o) // shallow copy is ok
tmpl = &t
default:
// package's fault, if we let this happen:
panic(fmt.Sprintf("unsupported option type %T", o))
}
}
if key == nil {
var err error
if key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader); err != nil {
return tls.Certificate{}, err
}
}
if ip := net.ParseIP(identifier); ip != nil {
tmpl.IPAddresses = []net.IP{ip}
} else {
tmpl.DNSNames = []string{identifier}
tmpl.Subject.CommonName = identifier
}
der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, key.Public(), key)
if err != nil {
return tls.Certificate{}, err
}
return tls.Certificate{
Certificate: [][]byte{der},
PrivateKey: key,
}, nil
}
// timeNow is time.Now, except in tests which can mess with it.
var timeNow = time.Now
// 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.
// Package autocert provides automatic access to certificates from Let's Encrypt
// and any other ACME-based CA.
//
// This package is a work in progress and makes no API stability promises.
package autocert
import (
"bytes"
"context"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"errors"
"fmt"
"io"
mathrand "math/rand"
"net"
"net/http"
"path"
"strings"
"sync"
"time"
"golang.org/x/crypto/acme"
"golang.org/x/net/idna"
)
// DefaultACMEDirectory is the default ACME Directory URL used when the Manager's Client is nil.
const DefaultACMEDirectory = "https://acme-v02.api.letsencrypt.org/directory"
// createCertRetryAfter is how much time to wait before removing a failed state
// entry due to an unsuccessful createCert call.
// This is a variable instead of a const for testing.
// TODO: Consider making it configurable or an exp backoff?
var createCertRetryAfter = time.Minute
// pseudoRand is safe for concurrent use.
var pseudoRand *lockedMathRand
var errPreRFC = errors.New("autocert: ACME server doesn't support RFC 8555")
func init() {
src := mathrand.NewSource(time.Now().UnixNano())
pseudoRand = &lockedMathRand{rnd: mathrand.New(src)}
}
// AcceptTOS is a Manager.Prompt function that always returns true to
// indicate acceptance of the CA's Terms of Service during account
// registration.
func AcceptTOS(tosURL string) bool { return true }
// HostPolicy specifies which host names the Manager is allowed to respond to.
// It returns a non-nil error if the host should be rejected.
// The returned error is accessible via tls.Conn.Handshake and its callers.
// See Manager's HostPolicy field and GetCertificate method docs for more details.
type HostPolicy func(ctx context.Context, host string) error
// HostWhitelist returns a policy where only the specified host names are allowed.
// Only exact matches are currently supported. Subdomains, regexp or wildcard
// will not match.
//
// Note that all hosts will be converted to Punycode via idna.Lookup.ToASCII so that
// Manager.GetCertificate can handle the Unicode IDN and mixedcase hosts correctly.
// Invalid hosts will be silently ignored.
func HostWhitelist(hosts ...string) HostPolicy {
whitelist := make(map[string]bool, len(hosts))
for _, h := range hosts {
if h, err := idna.Lookup.ToASCII(h); err == nil {
whitelist[h] = true
}
}
return func(_ context.Context, host string) error {
if !whitelist[host] {
return fmt.Errorf("acme/autocert: host %q not configured in HostWhitelist", host)
}
return nil
}
}
// defaultHostPolicy is used when Manager.HostPolicy is not set.
func defaultHostPolicy(context.Context, string) error {
return nil
}
// Manager is a stateful certificate manager built on top of acme.Client.
// It obtains and refreshes certificates automatically using "tls-alpn-01"
// or "http-01" challenge types, as well as providing them to a TLS server
// via tls.Config.
//
// You must specify a cache implementation, such as DirCache,
// to reuse obtained certificates across program restarts.
// Otherwise your server is very likely to exceed the certificate
// issuer's request rate limits.
type Manager struct {
// Prompt specifies a callback function to conditionally accept a CA's Terms of Service (TOS).
// The registration may require the caller to agree to the CA's TOS.
// If so, Manager calls Prompt with a TOS URL provided by the CA. Prompt should report
// whether the caller agrees to the terms.
//
// To always accept the terms, the callers can use AcceptTOS.
Prompt func(tosURL string) bool
// Cache optionally stores and retrieves previously-obtained certificates
// and other state. If nil, certs will only be cached for the lifetime of
// the Manager. Multiple Managers can share the same Cache.
//
// Using a persistent Cache, such as DirCache, is strongly recommended.
Cache Cache
// HostPolicy controls which domains the Manager will attempt
// to retrieve new certificates for. It does not affect cached certs.
//
// If non-nil, HostPolicy is called before requesting a new cert.
// If nil, all hosts are currently allowed. This is not recommended,
// as it opens a potential attack where clients connect to a server
// by IP address and pretend to be asking for an incorrect host name.
// Manager will attempt to obtain a certificate for that host, incorrectly,
// eventually reaching the CA's rate limit for certificate requests
// and making it impossible to obtain actual certificates.
//
// See GetCertificate for more details.
HostPolicy HostPolicy
// RenewBefore optionally specifies how early certificates should
// be renewed before they expire.
//
// If zero, they're renewed 30 days before expiration.
RenewBefore time.Duration
// Client is used to perform low-level operations, such as account registration
// and requesting new certificates.
//
// If Client is nil, a zero-value acme.Client is used with DefaultACMEDirectory
// as the directory endpoint.
// If the Client.Key is nil, a new ECDSA P-256 key is generated and,
// if Cache is not nil, stored in cache.
//
// Mutating the field after the first call of GetCertificate method will have no effect.
Client *acme.Client
// Email optionally specifies a contact email address.
// This is used by CAs, such as Let's Encrypt, to notify about problems
// with issued certificates.
//
// If the Client's account key is already registered, Email is not used.
Email string
// ForceRSA used to make the Manager generate RSA certificates. It is now ignored.
//
// Deprecated: the Manager will request the correct type of certificate based
// on what each client supports.
ForceRSA bool
// ExtraExtensions are used when generating a new CSR (Certificate Request),
// thus allowing customization of the resulting certificate.
// For instance, TLS Feature Extension (RFC 7633) can be used
// to prevent an OCSP downgrade attack.
//
// The field value is passed to crypto/x509.CreateCertificateRequest
// in the template's ExtraExtensions field as is.
ExtraExtensions []pkix.Extension
// ExternalAccountBinding optionally represents an arbitrary binding to an
// account of the CA to which the ACME server is tied.
// See RFC 8555, Section 7.3.4 for more details.
ExternalAccountBinding *acme.ExternalAccountBinding
clientMu sync.Mutex
client *acme.Client // initialized by acmeClient method
stateMu sync.Mutex
state map[certKey]*certState
// renewal tracks the set of domains currently running renewal timers.
renewalMu sync.Mutex
renewal map[certKey]*domainRenewal
// challengeMu guards tryHTTP01, certTokens and httpTokens.
challengeMu sync.RWMutex
// tryHTTP01 indicates whether the Manager should try "http-01" challenge type
// during the authorization flow.
tryHTTP01 bool
// httpTokens contains response body values for http-01 challenges
// and is keyed by the URL path at which a challenge response is expected
// to be provisioned.
// The entries are stored for the duration of the authorization flow.
httpTokens map[string][]byte
// certTokens contains temporary certificates for tls-alpn-01 challenges
// and is keyed by the domain name which matches the ClientHello server name.
// The entries are stored for the duration of the authorization flow.
certTokens map[string]*tls.Certificate
// nowFunc, if not nil, returns the current time. This may be set for
// testing purposes.
nowFunc func() time.Time
}
// certKey is the key by which certificates are tracked in state, renewal and cache.
type certKey struct {
domain string // without trailing dot
isRSA bool // RSA cert for legacy clients (as opposed to default ECDSA)
isToken bool // tls-based challenge token cert; key type is undefined regardless of isRSA
}
func (c certKey) String() string {
if c.isToken {
return c.domain + "+token"
}
if c.isRSA {
return c.domain + "+rsa"
}
return c.domain
}
// TLSConfig creates a new TLS config suitable for net/http.Server servers,
// supporting HTTP/2 and the tls-alpn-01 ACME challenge type.
func (m *Manager) TLSConfig() *tls.Config {
return &tls.Config{
GetCertificate: m.GetCertificate,
NextProtos: []string{
"h2", "http/1.1", // enable HTTP/2
acme.ALPNProto, // enable tls-alpn ACME challenges
},
}
}
// GetCertificate implements the tls.Config.GetCertificate hook.
// It provides a TLS certificate for hello.ServerName host, including answering
// tls-alpn-01 challenges.
// All other fields of hello are ignored.
//
// If m.HostPolicy is non-nil, GetCertificate calls the policy before requesting
// a new cert. A non-nil error returned from m.HostPolicy halts TLS negotiation.
// The error is propagated back to the caller of GetCertificate and is user-visible.
// This does not affect cached certs. See HostPolicy field description for more details.
//
// If GetCertificate is used directly, instead of via Manager.TLSConfig, package users will
// also have to add acme.ALPNProto to NextProtos for tls-alpn-01, or use HTTPHandler for http-01.
func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
if m.Prompt == nil {
return nil, errors.New("acme/autocert: Manager.Prompt not set")
}
name := hello.ServerName
if name == "" {
return nil, errors.New("acme/autocert: missing server name")
}
if !strings.Contains(strings.Trim(name, "."), ".") {
return nil, errors.New("acme/autocert: server name component count invalid")
}
// Note that this conversion is necessary because some server names in the handshakes
// started by some clients (such as cURL) are not converted to Punycode, which will
// prevent us from obtaining certificates for them. In addition, we should also treat
// example.com and EXAMPLE.COM as equivalent and return the same certificate for them.
// Fortunately, this conversion also helped us deal with this kind of mixedcase problems.
//
// Due to the "σςΣ" problem (see https://unicode.org/faq/idn.html#22), we can't use
// idna.Punycode.ToASCII (or just idna.ToASCII) here.
name, err := idna.Lookup.ToASCII(name)
if err != nil {
return nil, errors.New("acme/autocert: server name contains invalid character")
}
// In the worst-case scenario, the timeout needs to account for caching, host policy,
// domain ownership verification and certificate issuance.
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
// Check whether this is a token cert requested for TLS-ALPN challenge.
if wantsTokenCert(hello) {
m.challengeMu.RLock()
defer m.challengeMu.RUnlock()
if cert := m.certTokens[name]; cert != nil {
return cert, nil
}
if cert, err := m.cacheGet(ctx, certKey{domain: name, isToken: true}); err == nil {
return cert, nil
}
// TODO: cache error results?
return nil, fmt.Errorf("acme/autocert: no token cert for %q", name)
}
// regular domain
if err := m.hostPolicy()(ctx, name); err != nil {
return nil, err
}
ck := certKey{
domain: strings.TrimSuffix(name, "."), // golang.org/issue/18114
isRSA: !supportsECDSA(hello),
}
cert, err := m.cert(ctx, ck)
if err == nil {
return cert, nil
}
if err != ErrCacheMiss {
return nil, err
}
// first-time
cert, err = m.createCert(ctx, ck)
if err != nil {
return nil, err
}
m.cachePut(ctx, ck, cert)
return cert, nil
}
// wantsTokenCert reports whether a TLS request with SNI is made by a CA server
// for a challenge verification.
func wantsTokenCert(hello *tls.ClientHelloInfo) bool {
// tls-alpn-01
if len(hello.SupportedProtos) == 1 && hello.SupportedProtos[0] == acme.ALPNProto {
return true
}
return false
}
func supportsECDSA(hello *tls.ClientHelloInfo) bool {
// The "signature_algorithms" extension, if present, limits the key exchange
// algorithms allowed by the cipher suites. See RFC 5246, section 7.4.1.4.1.
if hello.SignatureSchemes != nil {
ecdsaOK := false
schemeLoop:
for _, scheme := range hello.SignatureSchemes {
const tlsECDSAWithSHA1 tls.SignatureScheme = 0x0203 // constant added in Go 1.10
switch scheme {
case tlsECDSAWithSHA1, tls.ECDSAWithP256AndSHA256,
tls.ECDSAWithP384AndSHA384, tls.ECDSAWithP521AndSHA512:
ecdsaOK = true
break schemeLoop
}
}
if !ecdsaOK {
return false
}
}
if hello.SupportedCurves != nil {
ecdsaOK := false
for _, curve := range hello.SupportedCurves {
if curve == tls.CurveP256 {
ecdsaOK = true
break
}
}
if !ecdsaOK {
return false
}
}
for _, suite := range hello.CipherSuites {
switch suite {
case tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305:
return true
}
}
return false
}
// HTTPHandler configures the Manager to provision ACME "http-01" challenge responses.
// It returns an http.Handler that responds to the challenges and must be
// running on port 80. If it receives a request that is not an ACME challenge,
// it delegates the request to the optional fallback handler.
//
// If fallback is nil, the returned handler redirects all GET and HEAD requests
// to the default TLS port 443 with 302 Found status code, preserving the original
// request path and query. It responds with 400 Bad Request to all other HTTP methods.
// The fallback is not protected by the optional HostPolicy.
//
// Because the fallback handler is run with unencrypted port 80 requests,
// the fallback should not serve TLS-only requests.
//
// If HTTPHandler is never called, the Manager will only use the "tls-alpn-01"
// challenge for domain verification.
func (m *Manager) HTTPHandler(fallback http.Handler) http.Handler {
m.challengeMu.Lock()
defer m.challengeMu.Unlock()
m.tryHTTP01 = true
if fallback == nil {
fallback = http.HandlerFunc(handleHTTPRedirect)
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !strings.HasPrefix(r.URL.Path, "/.well-known/acme-challenge/") {
fallback.ServeHTTP(w, r)
return
}
// A reasonable context timeout for cache and host policy only,
// because we don't wait for a new certificate issuance here.
ctx, cancel := context.WithTimeout(r.Context(), time.Minute)
defer cancel()
if err := m.hostPolicy()(ctx, r.Host); err != nil {
http.Error(w, err.Error(), http.StatusForbidden)
return
}
data, err := m.httpToken(ctx, r.URL.Path)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}
w.Write(data)
})
}
func handleHTTPRedirect(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" && r.Method != "HEAD" {
http.Error(w, "Use HTTPS", http.StatusBadRequest)
return
}
target := "https://" + stripPort(r.Host) + r.URL.RequestURI()
http.Redirect(w, r, target, http.StatusFound)
}
func stripPort(hostport string) string {
host, _, err := net.SplitHostPort(hostport)
if err != nil {
return hostport
}
return net.JoinHostPort(host, "443")
}
// cert returns an existing certificate either from m.state or cache.
// If a certificate is found in cache but not in m.state, the latter will be filled
// with the cached value.
func (m *Manager) cert(ctx context.Context, ck certKey) (*tls.Certificate, error) {
m.stateMu.Lock()
if s, ok := m.state[ck]; ok {
m.stateMu.Unlock()
s.RLock()
defer s.RUnlock()
return s.tlscert()
}
defer m.stateMu.Unlock()
cert, err := m.cacheGet(ctx, ck)
if err != nil {
return nil, err
}
signer, ok := cert.PrivateKey.(crypto.Signer)
if !ok {
return nil, errors.New("acme/autocert: private key cannot sign")
}
if m.state == nil {
m.state = make(map[certKey]*certState)
}
s := &certState{
key: signer,
cert: cert.Certificate,
leaf: cert.Leaf,
}
m.state[ck] = s
m.startRenew(ck, s.key, s.leaf.NotAfter)
return cert, nil
}
// cacheGet always returns a valid certificate, or an error otherwise.
// If a cached certificate exists but is not valid, ErrCacheMiss is returned.
func (m *Manager) cacheGet(ctx context.Context, ck certKey) (*tls.Certificate, error) {
if m.Cache == nil {
return nil, ErrCacheMiss
}
data, err := m.Cache.Get(ctx, ck.String())
if err != nil {
return nil, err
}
// private
priv, pub := pem.Decode(data)
if priv == nil || !strings.Contains(priv.Type, "PRIVATE") {
return nil, ErrCacheMiss
}
privKey, err := parsePrivateKey(priv.Bytes)
if err != nil {
return nil, err
}
// public
var pubDER [][]byte
for len(pub) > 0 {
var b *pem.Block
b, pub = pem.Decode(pub)
if b == nil {
break
}
pubDER = append(pubDER, b.Bytes)
}
if len(pub) > 0 {
// Leftover content not consumed by pem.Decode. Corrupt. Ignore.
return nil, ErrCacheMiss
}
// verify and create TLS cert
leaf, err := validCert(ck, pubDER, privKey, m.now())
if err != nil {
return nil, ErrCacheMiss
}
tlscert := &tls.Certificate{
Certificate: pubDER,
PrivateKey: privKey,
Leaf: leaf,
}
return tlscert, nil
}
func (m *Manager) cachePut(ctx context.Context, ck certKey, tlscert *tls.Certificate) error {
if m.Cache == nil {
return nil
}
// contains PEM-encoded data
var buf bytes.Buffer
// private
switch key := tlscert.PrivateKey.(type) {
case *ecdsa.PrivateKey:
if err := encodeECDSAKey(&buf, key); err != nil {
return err
}
case *rsa.PrivateKey:
b := x509.MarshalPKCS1PrivateKey(key)
pb := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: b}
if err := pem.Encode(&buf, pb); err != nil {
return err
}
default:
return errors.New("acme/autocert: unknown private key type")
}
// public
for _, b := range tlscert.Certificate {
pb := &pem.Block{Type: "CERTIFICATE", Bytes: b}
if err := pem.Encode(&buf, pb); err != nil {
return err
}
}
return m.Cache.Put(ctx, ck.String(), buf.Bytes())
}
func encodeECDSAKey(w io.Writer, key *ecdsa.PrivateKey) error {
b, err := x509.MarshalECPrivateKey(key)
if err != nil {
return err
}
pb := &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
return pem.Encode(w, pb)
}
// createCert starts the domain ownership verification and returns a certificate
// for that domain upon success.
//
// If the domain is already being verified, it waits for the existing verification to complete.
// Either way, createCert blocks for the duration of the whole process.
func (m *Manager) createCert(ctx context.Context, ck certKey) (*tls.Certificate, error) {
// TODO: maybe rewrite this whole piece using sync.Once
state, err := m.certState(ck)
if err != nil {
return nil, err
}
// state may exist if another goroutine is already working on it
// in which case just wait for it to finish
if !state.locked {
state.RLock()
defer state.RUnlock()
return state.tlscert()
}
// We are the first; state is locked.
// Unblock the readers when domain ownership is verified
// and we got the cert or the process failed.
defer state.Unlock()
state.locked = false
der, leaf, err := m.authorizedCert(ctx, state.key, ck)
if err != nil {
// Remove the failed state after some time,
// making the manager call createCert again on the following TLS hello.
didRemove := testDidRemoveState // The lifetime of this timer is untracked, so copy mutable local state to avoid races.
time.AfterFunc(createCertRetryAfter, func() {
defer didRemove(ck)
m.stateMu.Lock()
defer m.stateMu.Unlock()
// Verify the state hasn't changed and it's still invalid
// before deleting.
s, ok := m.state[ck]
if !ok {
return
}
if _, err := validCert(ck, s.cert, s.key, m.now()); err == nil {
return
}
delete(m.state, ck)
})
return nil, err
}
state.cert = der
state.leaf = leaf
m.startRenew(ck, state.key, state.leaf.NotAfter)
return state.tlscert()
}
// certState returns a new or existing certState.
// If a new certState is returned, state.exist is false and the state is locked.
// The returned error is non-nil only in the case where a new state could not be created.
func (m *Manager) certState(ck certKey) (*certState, error) {
m.stateMu.Lock()
defer m.stateMu.Unlock()
if m.state == nil {
m.state = make(map[certKey]*certState)
}
// existing state
if state, ok := m.state[ck]; ok {
return state, nil
}
// new locked state
var (
err error
key crypto.Signer
)
if ck.isRSA {
key, err = rsa.GenerateKey(rand.Reader, 2048)
} else {
key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
}
if err != nil {
return nil, err
}
state := &certState{
key: key,
locked: true,
}
state.Lock() // will be unlocked by m.certState caller
m.state[ck] = state
return state, nil
}
// authorizedCert starts the domain ownership verification process and requests a new cert upon success.
// The key argument is the certificate private key.
func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, ck certKey) (der [][]byte, leaf *x509.Certificate, err error) {
csr, err := certRequest(key, ck.domain, m.ExtraExtensions)
if err != nil {
return nil, nil, err
}
client, err := m.acmeClient(ctx)
if err != nil {
return nil, nil, err
}
dir, err := client.Discover(ctx)
if err != nil {
return nil, nil, err
}
if dir.OrderURL == "" {
return nil, nil, errPreRFC
}
o, err := m.verifyRFC(ctx, client, ck.domain)
if err != nil {
return nil, nil, err
}
chain, _, err := client.CreateOrderCert(ctx, o.FinalizeURL, csr, true)
if err != nil {
return nil, nil, err
}
leaf, err = validCert(ck, chain, key, m.now())
if err != nil {
return nil, nil, err
}
return chain, leaf, nil
}
// verifyRFC runs the identifier (domain) order-based authorization flow for RFC compliant CAs
// using each applicable ACME challenge type.
func (m *Manager) verifyRFC(ctx context.Context, client *acme.Client, domain string) (*acme.Order, error) {
// Try each supported challenge type starting with a new order each time.
// The nextTyp index of the next challenge type to try is shared across
// all order authorizations: if we've tried a challenge type once and it didn't work,
// it will most likely not work on another order's authorization either.
challengeTypes := m.supportedChallengeTypes()
nextTyp := 0 // challengeTypes index
AuthorizeOrderLoop:
for {
o, err := client.AuthorizeOrder(ctx, acme.DomainIDs(domain))
if err != nil {
return nil, err
}
// Remove all hanging authorizations to reduce rate limit quotas
// after we're done.
defer func(urls []string) {
go m.deactivatePendingAuthz(urls)
}(o.AuthzURLs)
// Check if there's actually anything we need to do.
switch o.Status {
case acme.StatusReady:
// Already authorized.
return o, nil
case acme.StatusPending:
// Continue normal Order-based flow.
default:
return nil, fmt.Errorf("acme/autocert: invalid new order status %q; order URL: %q", o.Status, o.URI)
}
// Satisfy all pending authorizations.
for _, zurl := range o.AuthzURLs {
z, err := client.GetAuthorization(ctx, zurl)
if err != nil {
return nil, err
}
if z.Status != acme.StatusPending {
// We are interested only in pending authorizations.
continue
}
// Pick the next preferred challenge.
var chal *acme.Challenge
for chal == nil && nextTyp < len(challengeTypes) {
chal = pickChallenge(challengeTypes[nextTyp], z.Challenges)
nextTyp++
}
if chal == nil {
return nil, fmt.Errorf("acme/autocert: unable to satisfy %q for domain %q: no viable challenge type found", z.URI, domain)
}
// Respond to the challenge and wait for validation result.
cleanup, err := m.fulfill(ctx, client, chal, domain)
if err != nil {
continue AuthorizeOrderLoop
}
defer cleanup()
if _, err := client.Accept(ctx, chal); err != nil {
continue AuthorizeOrderLoop
}
if _, err := client.WaitAuthorization(ctx, z.URI); err != nil {
continue AuthorizeOrderLoop
}
}
// All authorizations are satisfied.
// Wait for the CA to update the order status.
o, err = client.WaitOrder(ctx, o.URI)
if err != nil {
continue AuthorizeOrderLoop
}
return o, nil
}
}
func pickChallenge(typ string, chal []*acme.Challenge) *acme.Challenge {
for _, c := range chal {
if c.Type == typ {
return c
}
}
return nil
}
func (m *Manager) supportedChallengeTypes() []string {
m.challengeMu.RLock()
defer m.challengeMu.RUnlock()
typ := []string{"tls-alpn-01"}
if m.tryHTTP01 {
typ = append(typ, "http-01")
}
return typ
}
// deactivatePendingAuthz relinquishes all authorizations identified by the elements
// of the provided uri slice which are in "pending" state.
// It ignores revocation errors.
//
// deactivatePendingAuthz takes no context argument and instead runs with its own
// "detached" context because deactivations are done in a goroutine separate from
// that of the main issuance or renewal flow.
func (m *Manager) deactivatePendingAuthz(uri []string) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
client, err := m.acmeClient(ctx)
if err != nil {
return
}
for _, u := range uri {
z, err := client.GetAuthorization(ctx, u)
if err == nil && z.Status == acme.StatusPending {
client.RevokeAuthorization(ctx, u)
}
}
}
// fulfill provisions a response to the challenge chal.
// The cleanup is non-nil only if provisioning succeeded.
func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.Challenge, domain string) (cleanup func(), err error) {
switch chal.Type {
case "tls-alpn-01":
cert, err := client.TLSALPN01ChallengeCert(chal.Token, domain)
if err != nil {
return nil, err
}
m.putCertToken(ctx, domain, &cert)
return func() { go m.deleteCertToken(domain) }, nil
case "http-01":
resp, err := client.HTTP01ChallengeResponse(chal.Token)
if err != nil {
return nil, err
}
p := client.HTTP01ChallengePath(chal.Token)
m.putHTTPToken(ctx, p, resp)
return func() { go m.deleteHTTPToken(p) }, nil
}
return nil, fmt.Errorf("acme/autocert: unknown challenge type %q", chal.Type)
}
// putCertToken stores the token certificate with the specified name
// in both m.certTokens map and m.Cache.
func (m *Manager) putCertToken(ctx context.Context, name string, cert *tls.Certificate) {
m.challengeMu.Lock()
defer m.challengeMu.Unlock()
if m.certTokens == nil {
m.certTokens = make(map[string]*tls.Certificate)
}
m.certTokens[name] = cert
m.cachePut(ctx, certKey{domain: name, isToken: true}, cert)
}
// deleteCertToken removes the token certificate with the specified name
// from both m.certTokens map and m.Cache.
func (m *Manager) deleteCertToken(name string) {
m.challengeMu.Lock()
defer m.challengeMu.Unlock()
delete(m.certTokens, name)
if m.Cache != nil {
ck := certKey{domain: name, isToken: true}
m.Cache.Delete(context.Background(), ck.String())
}
}
// httpToken retrieves an existing http-01 token value from an in-memory map
// or the optional cache.
func (m *Manager) httpToken(ctx context.Context, tokenPath string) ([]byte, error) {
m.challengeMu.RLock()
defer m.challengeMu.RUnlock()
if v, ok := m.httpTokens[tokenPath]; ok {
return v, nil
}
if m.Cache == nil {
return nil, fmt.Errorf("acme/autocert: no token at %q", tokenPath)
}
return m.Cache.Get(ctx, httpTokenCacheKey(tokenPath))
}
// putHTTPToken stores an http-01 token value using tokenPath as key
// in both in-memory map and the optional Cache.
//
// It ignores any error returned from Cache.Put.
func (m *Manager) putHTTPToken(ctx context.Context, tokenPath, val string) {
m.challengeMu.Lock()
defer m.challengeMu.Unlock()
if m.httpTokens == nil {
m.httpTokens = make(map[string][]byte)
}
b := []byte(val)
m.httpTokens[tokenPath] = b
if m.Cache != nil {
m.Cache.Put(ctx, httpTokenCacheKey(tokenPath), b)
}
}
// deleteHTTPToken removes an http-01 token value from both in-memory map
// and the optional Cache, ignoring any error returned from the latter.
//
// If m.Cache is non-nil, it blocks until Cache.Delete returns without a timeout.
func (m *Manager) deleteHTTPToken(tokenPath string) {
m.challengeMu.Lock()
defer m.challengeMu.Unlock()
delete(m.httpTokens, tokenPath)
if m.Cache != nil {
m.Cache.Delete(context.Background(), httpTokenCacheKey(tokenPath))
}
}
// httpTokenCacheKey returns a key at which an http-01 token value may be stored
// in the Manager's optional Cache.
func httpTokenCacheKey(tokenPath string) string {
return path.Base(tokenPath) + "+http-01"
}
// startRenew starts a cert renewal timer loop, one per domain.
//
// The loop is scheduled in two cases:
// - a cert was fetched from cache for the first time (wasn't in m.state)
// - a new cert was created by m.createCert
//
// The key argument is a certificate private key.
// The exp argument is the cert expiration time (NotAfter).
func (m *Manager) startRenew(ck certKey, key crypto.Signer, exp time.Time) {
m.renewalMu.Lock()
defer m.renewalMu.Unlock()
if m.renewal[ck] != nil {
// another goroutine is already on it
return
}
if m.renewal == nil {
m.renewal = make(map[certKey]*domainRenewal)
}
dr := &domainRenewal{m: m, ck: ck, key: key}
m.renewal[ck] = dr
dr.start(exp)
}
// stopRenew stops all currently running cert renewal timers.
// The timers are not restarted during the lifetime of the Manager.
func (m *Manager) stopRenew() {
m.renewalMu.Lock()
defer m.renewalMu.Unlock()
for name, dr := range m.renewal {
delete(m.renewal, name)
dr.stop()
}
}
func (m *Manager) accountKey(ctx context.Context) (crypto.Signer, error) {
const keyName = "acme_account+key"
// Previous versions of autocert stored the value under a different key.
const legacyKeyName = "acme_account.key"
genKey := func() (*ecdsa.PrivateKey, error) {
return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
}
if m.Cache == nil {
return genKey()
}
data, err := m.Cache.Get(ctx, keyName)
if err == ErrCacheMiss {
data, err = m.Cache.Get(ctx, legacyKeyName)
}
if err == ErrCacheMiss {
key, err := genKey()
if err != nil {
return nil, err
}
var buf bytes.Buffer
if err := encodeECDSAKey(&buf, key); err != nil {
return nil, err
}
if err := m.Cache.Put(ctx, keyName, buf.Bytes()); err != nil {
return nil, err
}
return key, nil
}
if err != nil {
return nil, err
}
priv, _ := pem.Decode(data)
if priv == nil || !strings.Contains(priv.Type, "PRIVATE") {
return nil, errors.New("acme/autocert: invalid account key found in cache")
}
return parsePrivateKey(priv.Bytes)
}
func (m *Manager) acmeClient(ctx context.Context) (*acme.Client, error) {
m.clientMu.Lock()
defer m.clientMu.Unlock()
if m.client != nil {
return m.client, nil
}
client := m.Client
if client == nil {
client = &acme.Client{DirectoryURL: DefaultACMEDirectory}
}
if client.Key == nil {
var err error
client.Key, err = m.accountKey(ctx)
if err != nil {
return nil, err
}
}
if client.UserAgent == "" {
client.UserAgent = "autocert"
}
var contact []string
if m.Email != "" {
contact = []string{"mailto:" + m.Email}
}
a := &acme.Account{Contact: contact, ExternalAccountBinding: m.ExternalAccountBinding}
_, err := client.Register(ctx, a, m.Prompt)
if err == nil || isAccountAlreadyExist(err) {
m.client = client
err = nil
}
return m.client, err
}
// isAccountAlreadyExist reports whether the err, as returned from acme.Client.Register,
// indicates the account has already been registered.
func isAccountAlreadyExist(err error) bool {
if err == acme.ErrAccountAlreadyExists {
return true
}
ae, ok := err.(*acme.Error)
return ok && ae.StatusCode == http.StatusConflict
}
func (m *Manager) hostPolicy() HostPolicy {
if m.HostPolicy != nil {
return m.HostPolicy
}
return defaultHostPolicy
}
func (m *Manager) renewBefore() time.Duration {
if m.RenewBefore > renewJitter {
return m.RenewBefore
}
return 720 * time.Hour // 30 days
}
func (m *Manager) now() time.Time {
if m.nowFunc != nil {
return m.nowFunc()
}
return time.Now()
}
// certState is ready when its mutex is unlocked for reading.
type certState struct {
sync.RWMutex
locked bool // locked for read/write
key crypto.Signer // private key for cert
cert [][]byte // DER encoding
leaf *x509.Certificate // parsed cert[0]; always non-nil if cert != nil
}
// tlscert creates a tls.Certificate from s.key and s.cert.
// Callers should wrap it in s.RLock() and s.RUnlock().
func (s *certState) tlscert() (*tls.Certificate, error) {
if s.key == nil {
return nil, errors.New("acme/autocert: missing signer")
}
if len(s.cert) == 0 {
return nil, errors.New("acme/autocert: missing certificate")
}
return &tls.Certificate{
PrivateKey: s.key,
Certificate: s.cert,
Leaf: s.leaf,
}, nil
}
// certRequest generates a CSR for the given common name.
func certRequest(key crypto.Signer, name string, ext []pkix.Extension) ([]byte, error) {
req := &x509.CertificateRequest{
Subject: pkix.Name{CommonName: name},
DNSNames: []string{name},
ExtraExtensions: ext,
}
return x509.CreateCertificateRequest(rand.Reader, req, key)
}
// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates
// PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys.
// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three.
//
// Inspired by parsePrivateKey in crypto/tls/tls.go.
func parsePrivateKey(der []byte) (crypto.Signer, error) {
if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
return key, nil
}
if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
switch key := key.(type) {
case *rsa.PrivateKey:
return key, nil
case *ecdsa.PrivateKey:
return key, nil
default:
return nil, errors.New("acme/autocert: unknown private key type in PKCS#8 wrapping")
}
}
if key, err := x509.ParseECPrivateKey(der); err == nil {
return key, nil
}
return nil, errors.New("acme/autocert: failed to parse private key")
}
// validCert parses a cert chain provided as der argument and verifies the leaf and der[0]
// correspond to the private key, the domain and key type match, and expiration dates
// are valid. It doesn't do any revocation checking.
//
// The returned value is the verified leaf cert.
func validCert(ck certKey, der [][]byte, key crypto.Signer, now time.Time) (leaf *x509.Certificate, err error) {
// parse public part(s)
var n int
for _, b := range der {
n += len(b)
}
pub := make([]byte, n)
n = 0
for _, b := range der {
n += copy(pub[n:], b)
}
x509Cert, err := x509.ParseCertificates(pub)
if err != nil || len(x509Cert) == 0 {
return nil, errors.New("acme/autocert: no public key found")
}
// verify the leaf is not expired and matches the domain name
leaf = x509Cert[0]
if now.Before(leaf.NotBefore) {
return nil, errors.New("acme/autocert: certificate is not valid yet")
}
if now.After(leaf.NotAfter) {
return nil, errors.New("acme/autocert: expired certificate")
}
if err := leaf.VerifyHostname(ck.domain); err != nil {
return nil, err
}
// renew certificates revoked by Let's Encrypt in January 2022
if isRevokedLetsEncrypt(leaf) {
return nil, errors.New("acme/autocert: certificate was probably revoked by Let's Encrypt")
}
// ensure the leaf corresponds to the private key and matches the certKey type
switch pub := leaf.PublicKey.(type) {
case *rsa.PublicKey:
prv, ok := key.(*rsa.PrivateKey)
if !ok {
return nil, errors.New("acme/autocert: private key type does not match public key type")
}
if pub.N.Cmp(prv.N) != 0 {
return nil, errors.New("acme/autocert: private key does not match public key")
}
if !ck.isRSA && !ck.isToken {
return nil, errors.New("acme/autocert: key type does not match expected value")
}
case *ecdsa.PublicKey:
prv, ok := key.(*ecdsa.PrivateKey)
if !ok {
return nil, errors.New("acme/autocert: private key type does not match public key type")
}
if pub.X.Cmp(prv.X) != 0 || pub.Y.Cmp(prv.Y) != 0 {
return nil, errors.New("acme/autocert: private key does not match public key")
}
if ck.isRSA && !ck.isToken {
return nil, errors.New("acme/autocert: key type does not match expected value")
}
default:
return nil, errors.New("acme/autocert: unknown public key algorithm")
}
return leaf, nil
}
// https://community.letsencrypt.org/t/2022-01-25-issue-with-tls-alpn-01-validation-method/170450
var letsEncryptFixDeployTime = time.Date(2022, time.January, 26, 00, 48, 0, 0, time.UTC)
// isRevokedLetsEncrypt returns whether the certificate is likely to be part of
// a batch of certificates revoked by Let's Encrypt in January 2022. This check
// can be safely removed from May 2022.
func isRevokedLetsEncrypt(cert *x509.Certificate) bool {
O := cert.Issuer.Organization
return len(O) == 1 && O[0] == "Let's Encrypt" &&
cert.NotBefore.Before(letsEncryptFixDeployTime)
}
type lockedMathRand struct {
sync.Mutex
rnd *mathrand.Rand
}
func (r *lockedMathRand) int63n(max int64) int64 {
r.Lock()
n := r.rnd.Int63n(max)
r.Unlock()
return n
}
// For easier testing.
var (
// Called when a state is removed.
testDidRemoveState = func(certKey) {}
)
// 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.
package autocert
import (
"context"
"errors"
"os"
"path/filepath"
)
// ErrCacheMiss is returned when a certificate is not found in cache.
var ErrCacheMiss = errors.New("acme/autocert: certificate cache miss")
// Cache is used by Manager to store and retrieve previously obtained certificates
// and other account data as opaque blobs.
//
// Cache implementations should not rely on the key naming pattern. Keys can
// include any printable ASCII characters, except the following: \/:*?"<>|
type Cache interface {
// Get returns a certificate data for the specified key.
// If there's no such key, Get returns ErrCacheMiss.
Get(ctx context.Context, key string) ([]byte, error)
// Put stores the data in the cache under the specified key.
// Underlying implementations may use any data storage format,
// as long as the reverse operation, Get, results in the original data.
Put(ctx context.Context, key string, data []byte) error
// Delete removes a certificate data from the cache under the specified key.
// If there's no such key in the cache, Delete returns nil.
Delete(ctx context.Context, key string) error
}
// DirCache implements Cache using a directory on the local filesystem.
// If the directory does not exist, it will be created with 0700 permissions.
type DirCache string
// Get reads a certificate data from the specified file name.
func (d DirCache) Get(ctx context.Context, name string) ([]byte, error) {
name = filepath.Join(string(d), filepath.Clean("/"+name))
var (
data []byte
err error
done = make(chan struct{})
)
go func() {
data, err = os.ReadFile(name)
close(done)
}()
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-done:
}
if os.IsNotExist(err) {
return nil, ErrCacheMiss
}
return data, err
}
// Put writes the certificate data to the specified file name.
// The file will be created with 0600 permissions.
func (d DirCache) Put(ctx context.Context, name string, data []byte) error {
if err := os.MkdirAll(string(d), 0700); err != nil {
return err
}
done := make(chan struct{})
var err error
go func() {
defer close(done)
var tmp string
if tmp, err = d.writeTempFile(name, data); err != nil {
return
}
defer os.Remove(tmp)
select {
case <-ctx.Done():
// Don't overwrite the file if the context was canceled.
default:
newName := filepath.Join(string(d), filepath.Clean("/"+name))
err = os.Rename(tmp, newName)
}
}()
select {
case <-ctx.Done():
return ctx.Err()
case <-done:
}
return err
}
// Delete removes the specified file name.
func (d DirCache) Delete(ctx context.Context, name string) error {
name = filepath.Join(string(d), filepath.Clean("/"+name))
var (
err error
done = make(chan struct{})
)
go func() {
err = os.Remove(name)
close(done)
}()
select {
case <-ctx.Done():
return ctx.Err()
case <-done:
}
if err != nil && !os.IsNotExist(err) {
return err
}
return nil
}
// writeTempFile writes b to a temporary file, closes the file and returns its path.
func (d DirCache) writeTempFile(prefix string, b []byte) (name string, reterr error) {
// TempFile uses 0600 permissions
f, err := os.CreateTemp(string(d), prefix)
if err != nil {
return "", err
}
defer func() {
if reterr != nil {
os.Remove(f.Name())
}
}()
if _, err := f.Write(b); err != nil {
f.Close()
return "", err
}
return f.Name(), f.Close()
}
// 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 autocert
import (
"crypto/tls"
"log"
"net"
"os"
"path/filepath"
"time"
)
// NewListener returns a net.Listener that listens on the standard TLS
// port (443) on all interfaces and returns *tls.Conn connections with
// LetsEncrypt certificates for the provided domain or domains.
//
// It enables one-line HTTPS servers:
//
// log.Fatal(http.Serve(autocert.NewListener("example.com"), handler))
//
// NewListener is a convenience function for a common configuration.
// More complex or custom configurations can use the autocert.Manager
// type instead.
//
// Use of this function implies acceptance of the LetsEncrypt Terms of
// Service. If domains is not empty, the provided domains are passed
// to HostWhitelist. If domains is empty, the listener will do
// LetsEncrypt challenges for any requested domain, which is not
// recommended.
//
// Certificates are cached in a "golang-autocert" directory under an
// operating system-specific cache or temp directory. This may not
// be suitable for servers spanning multiple machines.
//
// The returned listener uses a *tls.Config that enables HTTP/2, and
// should only be used with servers that support HTTP/2.
//
// The returned Listener also enables TCP keep-alives on the accepted
// connections. The returned *tls.Conn are returned before their TLS
// handshake has completed.
func NewListener(domains ...string) net.Listener {
m := &Manager{
Prompt: AcceptTOS,
}
if len(domains) > 0 {
m.HostPolicy = HostWhitelist(domains...)
}
dir := cacheDir()
if err := os.MkdirAll(dir, 0700); err != nil {
log.Printf("warning: autocert.NewListener not using a cache: %v", err)
} else {
m.Cache = DirCache(dir)
}
return m.Listener()
}
// Listener listens on the standard TLS port (443) on all interfaces
// and returns a net.Listener returning *tls.Conn connections.
//
// The returned listener uses a *tls.Config that enables HTTP/2, and
// should only be used with servers that support HTTP/2.
//
// The returned Listener also enables TCP keep-alives on the accepted
// connections. The returned *tls.Conn are returned before their TLS
// handshake has completed.
//
// Unlike NewListener, it is the caller's responsibility to initialize
// the Manager m's Prompt, Cache, HostPolicy, and other desired options.
func (m *Manager) Listener() net.Listener {
ln := &listener{
conf: m.TLSConfig(),
}
ln.tcpListener, ln.tcpListenErr = net.Listen("tcp", ":443")
return ln
}
type listener struct {
conf *tls.Config
tcpListener net.Listener
tcpListenErr error
}
func (ln *listener) Accept() (net.Conn, error) {
if ln.tcpListenErr != nil {
return nil, ln.tcpListenErr
}
conn, err := ln.tcpListener.Accept()
if err != nil {
return nil, err
}
tcpConn := conn.(*net.TCPConn)
// Because Listener is a convenience function, help out with
// this too. This is not possible for the caller to set once
// we return a *tcp.Conn wrapping an inaccessible net.Conn.
// If callers don't want this, they can do things the manual
// way and tweak as needed. But this is what net/http does
// itself, so copy that. If net/http changes, we can change
// here too.
tcpConn.SetKeepAlive(true)
tcpConn.SetKeepAlivePeriod(3 * time.Minute)
return tls.Server(tcpConn, ln.conf), nil
}
func (ln *listener) Addr() net.Addr {
if ln.tcpListener != nil {
return ln.tcpListener.Addr()
}
// net.Listen failed. Return something non-nil in case callers
// call Addr before Accept:
return &net.TCPAddr{IP: net.IP{0, 0, 0, 0}, Port: 443}
}
func (ln *listener) Close() error {
if ln.tcpListenErr != nil {
return ln.tcpListenErr
}
return ln.tcpListener.Close()
}
func cacheDir() string {
const base = "golang-autocert"
cache, err := os.UserCacheDir()
if err != nil {
// Fall back to the root directory.
cache = "/.cache"
}
return filepath.Join(cache, base)
}
// 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.
package autocert
import (
"context"
"crypto"
"sync"
"time"
)
// renewJitter is the maximum deviation from Manager.RenewBefore.
const renewJitter = time.Hour
// domainRenewal tracks the state used by the periodic timers
// renewing a single domain's cert.
type domainRenewal struct {
m *Manager
ck certKey
key crypto.Signer
timerMu sync.Mutex
timer *time.Timer
timerClose chan struct{} // if non-nil, renew closes this channel (and nils out the timer fields) instead of running
}
// start starts a cert renewal timer at the time
// defined by the certificate expiration time exp.
//
// If the timer is already started, calling start is a noop.
func (dr *domainRenewal) start(exp time.Time) {
dr.timerMu.Lock()
defer dr.timerMu.Unlock()
if dr.timer != nil {
return
}
dr.timer = time.AfterFunc(dr.next(exp), dr.renew)
}
// stop stops the cert renewal timer and waits for any in-flight calls to renew
// to complete. If the timer is already stopped, calling stop is a noop.
func (dr *domainRenewal) stop() {
dr.timerMu.Lock()
defer dr.timerMu.Unlock()
for {
if dr.timer == nil {
return
}
if dr.timer.Stop() {
dr.timer = nil
return
} else {
// dr.timer fired, and we acquired dr.timerMu before the renew callback did.
// (We know this because otherwise the renew callback would have reset dr.timer!)
timerClose := make(chan struct{})
dr.timerClose = timerClose
dr.timerMu.Unlock()
<-timerClose
dr.timerMu.Lock()
}
}
}
// renew is called periodically by a timer.
// The first renew call is kicked off by dr.start.
func (dr *domainRenewal) renew() {
dr.timerMu.Lock()
defer dr.timerMu.Unlock()
if dr.timerClose != nil {
close(dr.timerClose)
dr.timer, dr.timerClose = nil, nil
return
}
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
defer cancel()
// TODO: rotate dr.key at some point?
next, err := dr.do(ctx)
if err != nil {
next = renewJitter / 2
next += time.Duration(pseudoRand.int63n(int64(next)))
}
testDidRenewLoop(next, err)
dr.timer = time.AfterFunc(next, dr.renew)
}
// updateState locks and replaces the relevant Manager.state item with the given
// state. It additionally updates dr.key with the given state's key.
func (dr *domainRenewal) updateState(state *certState) {
dr.m.stateMu.Lock()
defer dr.m.stateMu.Unlock()
dr.key = state.key
dr.m.state[dr.ck] = state
}
// do is similar to Manager.createCert but it doesn't lock a Manager.state item.
// Instead, it requests a new certificate independently and, upon success,
// replaces dr.m.state item with a new one and updates cache for the given domain.
//
// It may lock and update the Manager.state if the expiration date of the currently
// cached cert is far enough in the future.
//
// The returned value is a time interval after which the renewal should occur again.
func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
// a race is likely unavoidable in a distributed environment
// but we try nonetheless
if tlscert, err := dr.m.cacheGet(ctx, dr.ck); err == nil {
next := dr.next(tlscert.Leaf.NotAfter)
if next > dr.m.renewBefore()+renewJitter {
signer, ok := tlscert.PrivateKey.(crypto.Signer)
if ok {
state := &certState{
key: signer,
cert: tlscert.Certificate,
leaf: tlscert.Leaf,
}
dr.updateState(state)
return next, nil
}
}
}
der, leaf, err := dr.m.authorizedCert(ctx, dr.key, dr.ck)
if err != nil {
return 0, err
}
state := &certState{
key: dr.key,
cert: der,
leaf: leaf,
}
tlscert, err := state.tlscert()
if err != nil {
return 0, err
}
if err := dr.m.cachePut(ctx, dr.ck, tlscert); err != nil {
return 0, err
}
dr.updateState(state)
return dr.next(leaf.NotAfter), nil
}
func (dr *domainRenewal) next(expiry time.Time) time.Duration {
d := expiry.Sub(dr.m.now()) - dr.m.renewBefore()
// add a bit of randomness to renew deadline
n := pseudoRand.int63n(int64(renewJitter))
d -= time.Duration(n)
if d < 0 {
return 0
}
return d
}
var testDidRenewLoop = func(next time.Duration, err error) {}
// Copyright 2018 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 acme
import (
"bytes"
"context"
"crypto"
"crypto/rand"
"encoding/json"
"errors"
"fmt"
"io"
"math/big"
"net/http"
"runtime/debug"
"strconv"
"strings"
"time"
)
// retryTimer encapsulates common logic for retrying unsuccessful requests.
// It is not safe for concurrent use.
type retryTimer struct {
// backoffFn provides backoff delay sequence for retries.
// See Client.RetryBackoff doc comment.
backoffFn func(n int, r *http.Request, res *http.Response) time.Duration
// n is the current retry attempt.
n int
}
func (t *retryTimer) inc() {
t.n++
}
// backoff pauses the current goroutine as described in Client.RetryBackoff.
func (t *retryTimer) backoff(ctx context.Context, r *http.Request, res *http.Response) error {
d := t.backoffFn(t.n, r, res)
if d <= 0 {
return fmt.Errorf("acme: no more retries for %s; tried %d time(s)", r.URL, t.n)
}
wakeup := time.NewTimer(d)
defer wakeup.Stop()
select {
case <-ctx.Done():
return ctx.Err()
case <-wakeup.C:
return nil
}
}
func (c *Client) retryTimer() *retryTimer {
f := c.RetryBackoff
if f == nil {
f = defaultBackoff
}
return &retryTimer{backoffFn: f}
}
// defaultBackoff provides default Client.RetryBackoff implementation
// using a truncated exponential backoff algorithm,
// as described in Client.RetryBackoff.
//
// The n argument is always bounded between 1 and 30.
// The returned value is always greater than 0.
func defaultBackoff(n int, r *http.Request, res *http.Response) time.Duration {
const maxVal = 10 * time.Second
var jitter time.Duration
if x, err := rand.Int(rand.Reader, big.NewInt(1000)); err == nil {
// Set the minimum to 1ms to avoid a case where
// an invalid Retry-After value is parsed into 0 below,
// resulting in the 0 returned value which would unintentionally
// stop the retries.
jitter = (1 + time.Duration(x.Int64())) * time.Millisecond
}
if v, ok := res.Header["Retry-After"]; ok {
return retryAfter(v[0]) + jitter
}
if n < 1 {
n = 1
}
if n > 30 {
n = 30
}
d := time.Duration(1<<uint(n-1))*time.Second + jitter
return min(d, maxVal)
}
// retryAfter parses a Retry-After HTTP header value,
// trying to convert v into an int (seconds) or use http.ParseTime otherwise.
// It returns zero value if v cannot be parsed.
func retryAfter(v string) time.Duration {
if i, err := strconv.Atoi(v); err == nil {
return time.Duration(i) * time.Second
}
t, err := http.ParseTime(v)
if err != nil {
return 0
}
return t.Sub(timeNow())
}
// resOkay is a function that reports whether the provided response is okay.
// It is expected to keep the response body unread.
type resOkay func(*http.Response) bool
// wantStatus returns a function which reports whether the code
// matches the status code of a response.
func wantStatus(codes ...int) resOkay {
return func(res *http.Response) bool {
for _, code := range codes {
if code == res.StatusCode {
return true
}
}
return false
}
}
// get issues an unsigned GET request to the specified URL.
// It returns a non-error value only when ok reports true.
//
// get retries unsuccessful attempts according to c.RetryBackoff
// until the context is done or a non-retriable error is received.
func (c *Client) get(ctx context.Context, url string, ok resOkay) (*http.Response, error) {
retry := c.retryTimer()
for {
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return nil, err
}
res, err := c.doNoRetry(ctx, req)
switch {
case err != nil:
return nil, err
case ok(res):
return res, nil
case isRetriable(res.StatusCode):
retry.inc()
resErr := responseError(res)
res.Body.Close()
// Ignore the error value from retry.backoff
// and return the one from last retry, as received from the CA.
if retry.backoff(ctx, req, res) != nil {
return nil, resErr
}
default:
defer res.Body.Close()
return nil, responseError(res)
}
}
}
// postAsGet is POST-as-GET, a replacement for GET in RFC 8555
// as described in https://tools.ietf.org/html/rfc8555#section-6.3.
// It makes a POST request in KID form with zero JWS payload.
// See nopayload doc comments in jws.go.
func (c *Client) postAsGet(ctx context.Context, url string, ok resOkay) (*http.Response, error) {
return c.post(ctx, nil, url, noPayload, ok)
}
// post issues a signed POST request in JWS format using the provided key
// to the specified URL. If key is nil, c.Key is used instead.
// It returns a non-error value only when ok reports true.
//
// post retries unsuccessful attempts according to c.RetryBackoff
// until the context is done or a non-retriable error is received.
// It uses postNoRetry to make individual requests.
func (c *Client) post(ctx context.Context, key crypto.Signer, url string, body interface{}, ok resOkay) (*http.Response, error) {
retry := c.retryTimer()
for {
res, req, err := c.postNoRetry(ctx, key, url, body)
if err != nil {
return nil, err
}
if ok(res) {
return res, nil
}
resErr := responseError(res)
res.Body.Close()
switch {
// Check for bad nonce before isRetriable because it may have been returned
// with an unretriable response code such as 400 Bad Request.
case isBadNonce(resErr):
// Consider any previously stored nonce values to be invalid.
c.clearNonces()
case !isRetriable(res.StatusCode):
return nil, resErr
}
retry.inc()
// Ignore the error value from retry.backoff
// and return the one from last retry, as received from the CA.
if err := retry.backoff(ctx, req, res); err != nil {
return nil, resErr
}
}
}
// postNoRetry signs the body with the given key and POSTs it to the provided url.
// It is used by c.post to retry unsuccessful attempts.
// The body argument must be JSON-serializable.
//
// If key argument is nil, c.Key is used to sign the request.
// If key argument is nil and c.accountKID returns a non-zero keyID,
// the request is sent in KID form. Otherwise, JWK form is used.
//
// In practice, when interfacing with RFC-compliant CAs most requests are sent in KID form
// and JWK is used only when KID is unavailable: new account endpoint and certificate
// revocation requests authenticated by a cert key.
// See jwsEncodeJSON for other details.
func (c *Client) postNoRetry(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, *http.Request, error) {
kid := noKeyID
if key == nil {
if c.Key == nil {
return nil, nil, errors.New("acme: Client.Key must be populated to make POST requests")
}
key = c.Key
kid = c.accountKID(ctx)
}
nonce, err := c.popNonce(ctx, url)
if err != nil {
return nil, nil, err
}
b, err := jwsEncodeJSON(body, key, kid, nonce, url)
if err != nil {
return nil, nil, err
}
req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(b))
if err != nil {
return nil, nil, err
}
req.Header.Set("Content-Type", "application/jose+json")
res, err := c.doNoRetry(ctx, req)
if err != nil {
return nil, nil, err
}
c.addNonce(res.Header)
return res, req, nil
}
// doNoRetry issues a request req, replacing its context (if any) with ctx.
func (c *Client) doNoRetry(ctx context.Context, req *http.Request) (*http.Response, error) {
req.Header.Set("User-Agent", c.userAgent())
res, err := c.httpClient().Do(req.WithContext(ctx))
if err != nil {
select {
case <-ctx.Done():
// Prefer the unadorned context error.
// (The acme package had tests assuming this, previously from ctxhttp's
// behavior, predating net/http supporting contexts natively)
// TODO(bradfitz): reconsider this in the future. But for now this
// requires no test updates.
return nil, ctx.Err()
default:
return nil, err
}
}
return res, nil
}
func (c *Client) httpClient() *http.Client {
if c.HTTPClient != nil {
return c.HTTPClient
}
return http.DefaultClient
}
// packageVersion is the version of the module that contains this package, for
// sending as part of the User-Agent header.
var packageVersion string
func init() {
// Set packageVersion if the binary was built in modules mode and x/crypto
// was not replaced with a different module.
info, ok := debug.ReadBuildInfo()
if !ok {
return
}
for _, m := range info.Deps {
if m.Path != "golang.org/x/crypto" {
continue
}
if m.Replace == nil {
packageVersion = m.Version
}
break
}
}
// userAgent returns the User-Agent header value. It includes the package name,
// the module version (if available), and the c.UserAgent value (if set).
func (c *Client) userAgent() string {
ua := "golang.org/x/crypto/acme"
if packageVersion != "" {
ua += "@" + packageVersion
}
if c.UserAgent != "" {
ua = c.UserAgent + " " + ua
}
return ua
}
// isBadNonce reports whether err is an ACME "badnonce" error.
func isBadNonce(err error) bool {
// According to the spec badNonce is urn:ietf:params:acme:error:badNonce.
// However, ACME servers in the wild return their versions of the error.
// See https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-5.4
// and https://github.com/letsencrypt/boulder/blob/0e07eacb/docs/acme-divergences.md#section-66.
ae, ok := err.(*Error)
return ok && strings.HasSuffix(strings.ToLower(ae.ProblemType), ":badnonce")
}
// isRetriable reports whether a request can be retried
// based on the response status code.
//
// Note that a "bad nonce" error is returned with a non-retriable 400 Bad Request code.
// Callers should parse the response and check with isBadNonce.
func isRetriable(code int) bool {
return code <= 399 || code >= 500 || code == http.StatusTooManyRequests
}
// responseError creates an error of Error type from resp.
func responseError(resp *http.Response) error {
// don't care if ReadAll returns an error:
// json.Unmarshal will fail in that case anyway
b, _ := io.ReadAll(resp.Body)
e := &wireError{Status: resp.StatusCode}
if err := json.Unmarshal(b, e); err != nil {
// this is not a regular error response:
// populate detail with anything we received,
// e.Status will already contain HTTP response code value
e.Detail = string(b)
if e.Detail == "" {
e.Detail = resp.Status
}
}
return e.error(resp.Header)
}
// 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.
package acme
import (
"crypto"
"crypto/ecdsa"
"crypto/hmac"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
_ "crypto/sha512" // need for EC keys
"encoding/asn1"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"math/big"
)
// KeyID is the account key identity provided by a CA during registration.
type KeyID string
// noKeyID indicates that jwsEncodeJSON should compute and use JWK instead of a KID.
// See jwsEncodeJSON for details.
const noKeyID = KeyID("")
// noPayload indicates jwsEncodeJSON will encode zero-length octet string
// in a JWS request. This is called POST-as-GET in RFC 8555 and is used to make
// authenticated GET requests via POSTing with an empty payload.
// See https://tools.ietf.org/html/rfc8555#section-6.3 for more details.
const noPayload = ""
// noNonce indicates that the nonce should be omitted from the protected header.
// See jwsEncodeJSON for details.
const noNonce = ""
// jsonWebSignature can be easily serialized into a JWS following
// https://tools.ietf.org/html/rfc7515#section-3.2.
type jsonWebSignature struct {
Protected string `json:"protected"`
Payload string `json:"payload"`
Sig string `json:"signature"`
}
// jwsEncodeJSON signs claimset using provided key and a nonce.
// The result is serialized in JSON format containing either kid or jwk
// fields based on the provided KeyID value.
//
// The claimset is marshalled using json.Marshal unless it is a string.
// In which case it is inserted directly into the message.
//
// If kid is non-empty, its quoted value is inserted in the protected header
// as "kid" field value. Otherwise, JWK is computed using jwkEncode and inserted
// as "jwk" field value. The "jwk" and "kid" fields are mutually exclusive.
//
// If nonce is non-empty, its quoted value is inserted in the protected header.
//
// See https://tools.ietf.org/html/rfc7515#section-7.
func jwsEncodeJSON(claimset interface{}, key crypto.Signer, kid KeyID, nonce, url string) ([]byte, error) {
if key == nil {
return nil, errors.New("nil key")
}
alg, sha := jwsHasher(key.Public())
if alg == "" || !sha.Available() {
return nil, ErrUnsupportedKey
}
headers := struct {
Alg string `json:"alg"`
KID string `json:"kid,omitempty"`
JWK json.RawMessage `json:"jwk,omitempty"`
Nonce string `json:"nonce,omitempty"`
URL string `json:"url"`
}{
Alg: alg,
Nonce: nonce,
URL: url,
}
switch kid {
case noKeyID:
jwk, err := jwkEncode(key.Public())
if err != nil {
return nil, err
}
headers.JWK = json.RawMessage(jwk)
default:
headers.KID = string(kid)
}
phJSON, err := json.Marshal(headers)
if err != nil {
return nil, err
}
phead := base64.RawURLEncoding.EncodeToString(phJSON)
var payload string
if val, ok := claimset.(string); ok {
payload = val
} else {
cs, err := json.Marshal(claimset)
if err != nil {
return nil, err
}
payload = base64.RawURLEncoding.EncodeToString(cs)
}
hash := sha.New()
hash.Write([]byte(phead + "." + payload))
sig, err := jwsSign(key, sha, hash.Sum(nil))
if err != nil {
return nil, err
}
enc := jsonWebSignature{
Protected: phead,
Payload: payload,
Sig: base64.RawURLEncoding.EncodeToString(sig),
}
return json.Marshal(&enc)
}
// jwsWithMAC creates and signs a JWS using the given key and the HS256
// algorithm. kid and url are included in the protected header. rawPayload
// should not be base64-URL-encoded.
func jwsWithMAC(key []byte, kid, url string, rawPayload []byte) (*jsonWebSignature, error) {
if len(key) == 0 {
return nil, errors.New("acme: cannot sign JWS with an empty MAC key")
}
header := struct {
Algorithm string `json:"alg"`
KID string `json:"kid"`
URL string `json:"url,omitempty"`
}{
// Only HMAC-SHA256 is supported.
Algorithm: "HS256",
KID: kid,
URL: url,
}
rawProtected, err := json.Marshal(header)
if err != nil {
return nil, err
}
protected := base64.RawURLEncoding.EncodeToString(rawProtected)
payload := base64.RawURLEncoding.EncodeToString(rawPayload)
h := hmac.New(sha256.New, key)
if _, err := h.Write([]byte(protected + "." + payload)); err != nil {
return nil, err
}
mac := h.Sum(nil)
return &jsonWebSignature{
Protected: protected,
Payload: payload,
Sig: base64.RawURLEncoding.EncodeToString(mac),
}, nil
}
// jwkEncode encodes public part of an RSA or ECDSA key into a JWK.
// The result is also suitable for creating a JWK thumbprint.
// https://tools.ietf.org/html/rfc7517
func jwkEncode(pub crypto.PublicKey) (string, error) {
switch pub := pub.(type) {
case *rsa.PublicKey:
// https://tools.ietf.org/html/rfc7518#section-6.3.1
n := pub.N
e := big.NewInt(int64(pub.E))
// Field order is important.
// See https://tools.ietf.org/html/rfc7638#section-3.3 for details.
return fmt.Sprintf(`{"e":"%s","kty":"RSA","n":"%s"}`,
base64.RawURLEncoding.EncodeToString(e.Bytes()),
base64.RawURLEncoding.EncodeToString(n.Bytes()),
), nil
case *ecdsa.PublicKey:
// https://tools.ietf.org/html/rfc7518#section-6.2.1
p := pub.Curve.Params()
n := p.BitSize / 8
if p.BitSize%8 != 0 {
n++
}
x := pub.X.Bytes()
if n > len(x) {
x = append(make([]byte, n-len(x)), x...)
}
y := pub.Y.Bytes()
if n > len(y) {
y = append(make([]byte, n-len(y)), y...)
}
// Field order is important.
// See https://tools.ietf.org/html/rfc7638#section-3.3 for details.
return fmt.Sprintf(`{"crv":"%s","kty":"EC","x":"%s","y":"%s"}`,
p.Name,
base64.RawURLEncoding.EncodeToString(x),
base64.RawURLEncoding.EncodeToString(y),
), nil
}
return "", ErrUnsupportedKey
}
// jwsSign signs the digest using the given key.
// The hash is unused for ECDSA keys.
func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) {
switch pub := key.Public().(type) {
case *rsa.PublicKey:
return key.Sign(rand.Reader, digest, hash)
case *ecdsa.PublicKey:
sigASN1, err := key.Sign(rand.Reader, digest, hash)
if err != nil {
return nil, err
}
var rs struct{ R, S *big.Int }
if _, err := asn1.Unmarshal(sigASN1, &rs); err != nil {
return nil, err
}
rb, sb := rs.R.Bytes(), rs.S.Bytes()
size := pub.Params().BitSize / 8
if size%8 > 0 {
size++
}
sig := make([]byte, size*2)
copy(sig[size-len(rb):], rb)
copy(sig[size*2-len(sb):], sb)
return sig, nil
}
return nil, ErrUnsupportedKey
}
// jwsHasher indicates suitable JWS algorithm name and a hash function
// to use for signing a digest with the provided key.
// It returns ("", 0) if the key is not supported.
func jwsHasher(pub crypto.PublicKey) (string, crypto.Hash) {
switch pub := pub.(type) {
case *rsa.PublicKey:
return "RS256", crypto.SHA256
case *ecdsa.PublicKey:
switch pub.Params().Name {
case "P-256":
return "ES256", crypto.SHA256
case "P-384":
return "ES384", crypto.SHA384
case "P-521":
return "ES512", crypto.SHA512
}
}
return "", 0
}
// JWKThumbprint creates a JWK thumbprint out of pub
// as specified in https://tools.ietf.org/html/rfc7638.
func JWKThumbprint(pub crypto.PublicKey) (string, error) {
jwk, err := jwkEncode(pub)
if err != nil {
return "", err
}
b := sha256.Sum256([]byte(jwk))
return base64.RawURLEncoding.EncodeToString(b[:]), nil
}
// Copyright 2019 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 acme
import (
"context"
"crypto"
"encoding/base64"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"io"
"net/http"
"time"
)
// DeactivateReg permanently disables an existing account associated with c.Key.
// A deactivated account can no longer request certificate issuance or access
// resources related to the account, such as orders or authorizations.
//
// It only works with CAs implementing RFC 8555.
func (c *Client) DeactivateReg(ctx context.Context) error {
if _, err := c.Discover(ctx); err != nil { // required by c.accountKID
return err
}
url := string(c.accountKID(ctx))
if url == "" {
return ErrNoAccount
}
req := json.RawMessage(`{"status": "deactivated"}`)
res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK))
if err != nil {
return err
}
res.Body.Close()
return nil
}
// registerRFC is equivalent to c.Register but for CAs implementing RFC 8555.
// It expects c.Discover to have already been called.
func (c *Client) registerRFC(ctx context.Context, acct *Account, prompt func(tosURL string) bool) (*Account, error) {
c.cacheMu.Lock() // guard c.kid access
defer c.cacheMu.Unlock()
req := struct {
TermsAgreed bool `json:"termsOfServiceAgreed,omitempty"`
Contact []string `json:"contact,omitempty"`
ExternalAccountBinding *jsonWebSignature `json:"externalAccountBinding,omitempty"`
}{
Contact: acct.Contact,
}
if c.dir.Terms != "" {
req.TermsAgreed = prompt(c.dir.Terms)
}
// set 'externalAccountBinding' field if requested
if acct.ExternalAccountBinding != nil {
eabJWS, err := c.encodeExternalAccountBinding(acct.ExternalAccountBinding)
if err != nil {
return nil, fmt.Errorf("acme: failed to encode external account binding: %v", err)
}
req.ExternalAccountBinding = eabJWS
}
res, err := c.post(ctx, c.Key, c.dir.RegURL, req, wantStatus(
http.StatusOK, // account with this key already registered
http.StatusCreated, // new account created
))
if err != nil {
return nil, err
}
defer res.Body.Close()
a, err := responseAccount(res)
if err != nil {
return nil, err
}
// Cache Account URL even if we return an error to the caller.
// It is by all means a valid and usable "kid" value for future requests.
c.KID = KeyID(a.URI)
if res.StatusCode == http.StatusOK {
return nil, ErrAccountAlreadyExists
}
return a, nil
}
// encodeExternalAccountBinding will encode an external account binding stanza
// as described in https://tools.ietf.org/html/rfc8555#section-7.3.4.
func (c *Client) encodeExternalAccountBinding(eab *ExternalAccountBinding) (*jsonWebSignature, error) {
jwk, err := jwkEncode(c.Key.Public())
if err != nil {
return nil, err
}
return jwsWithMAC(eab.Key, eab.KID, c.dir.RegURL, []byte(jwk))
}
// updateRegRFC is equivalent to c.UpdateReg but for CAs implementing RFC 8555.
// It expects c.Discover to have already been called.
func (c *Client) updateRegRFC(ctx context.Context, a *Account) (*Account, error) {
url := string(c.accountKID(ctx))
if url == "" {
return nil, ErrNoAccount
}
req := struct {
Contact []string `json:"contact,omitempty"`
}{
Contact: a.Contact,
}
res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK))
if err != nil {
return nil, err
}
defer res.Body.Close()
return responseAccount(res)
}
// getRegRFC is equivalent to c.GetReg but for CAs implementing RFC 8555.
// It expects c.Discover to have already been called.
func (c *Client) getRegRFC(ctx context.Context) (*Account, error) {
req := json.RawMessage(`{"onlyReturnExisting": true}`)
res, err := c.post(ctx, c.Key, c.dir.RegURL, req, wantStatus(http.StatusOK))
if e, ok := err.(*Error); ok && e.ProblemType == "urn:ietf:params:acme:error:accountDoesNotExist" {
return nil, ErrNoAccount
}
if err != nil {
return nil, err
}
defer res.Body.Close()
return responseAccount(res)
}
func responseAccount(res *http.Response) (*Account, error) {
var v struct {
Status string
Contact []string
Orders string
}
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
return nil, fmt.Errorf("acme: invalid account response: %v", err)
}
return &Account{
URI: res.Header.Get("Location"),
Status: v.Status,
Contact: v.Contact,
OrdersURL: v.Orders,
}, nil
}
// accountKeyRollover attempts to perform account key rollover.
// On success it will change client.Key to the new key.
func (c *Client) accountKeyRollover(ctx context.Context, newKey crypto.Signer) error {
dir, err := c.Discover(ctx) // Also required by c.accountKID
if err != nil {
return err
}
kid := c.accountKID(ctx)
if kid == noKeyID {
return ErrNoAccount
}
oldKey, err := jwkEncode(c.Key.Public())
if err != nil {
return err
}
payload := struct {
Account string `json:"account"`
OldKey json.RawMessage `json:"oldKey"`
}{
Account: string(kid),
OldKey: json.RawMessage(oldKey),
}
inner, err := jwsEncodeJSON(payload, newKey, noKeyID, noNonce, dir.KeyChangeURL)
if err != nil {
return err
}
res, err := c.post(ctx, nil, dir.KeyChangeURL, base64.RawURLEncoding.EncodeToString(inner), wantStatus(http.StatusOK))
if err != nil {
return err
}
defer res.Body.Close()
c.Key = newKey
return nil
}
// AuthorizeOrder initiates the order-based application for certificate issuance,
// as opposed to pre-authorization in Authorize.
// It is only supported by CAs implementing RFC 8555.
//
// The caller then needs to fetch each authorization with GetAuthorization,
// identify those with StatusPending status and fulfill a challenge using Accept.
// Once all authorizations are satisfied, the caller will typically want to poll
// order status using WaitOrder until it's in StatusReady state.
// To finalize the order and obtain a certificate, the caller submits a CSR with CreateOrderCert.
func (c *Client) AuthorizeOrder(ctx context.Context, id []AuthzID, opt ...OrderOption) (*Order, error) {
dir, err := c.Discover(ctx)
if err != nil {
return nil, err
}
req := struct {
Identifiers []wireAuthzID `json:"identifiers"`
NotBefore string `json:"notBefore,omitempty"`
NotAfter string `json:"notAfter,omitempty"`
}{}
for _, v := range id {
req.Identifiers = append(req.Identifiers, wireAuthzID{
Type: v.Type,
Value: v.Value,
})
}
for _, o := range opt {
switch o := o.(type) {
case orderNotBeforeOpt:
req.NotBefore = time.Time(o).Format(time.RFC3339)
case orderNotAfterOpt:
req.NotAfter = time.Time(o).Format(time.RFC3339)
default:
// Package's fault if we let this happen.
panic(fmt.Sprintf("unsupported order option type %T", o))
}
}
res, err := c.post(ctx, nil, dir.OrderURL, req, wantStatus(http.StatusCreated))
if err != nil {
return nil, err
}
defer res.Body.Close()
return responseOrder(res)
}
// GetOrder retrieves an order identified by the given URL.
// For orders created with AuthorizeOrder, the url value is Order.URI.
//
// If a caller needs to poll an order until its status is final,
// see the WaitOrder method.
func (c *Client) GetOrder(ctx context.Context, url string) (*Order, error) {
if _, err := c.Discover(ctx); err != nil {
return nil, err
}
res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK))
if err != nil {
return nil, err
}
defer res.Body.Close()
return responseOrder(res)
}
// WaitOrder polls an order from the given URL until it is in one of the final states,
// StatusReady, StatusValid or StatusInvalid, the CA responded with a non-retryable error
// or the context is done.
//
// It returns a non-nil Order only if its Status is StatusReady or StatusValid.
// In all other cases WaitOrder returns an error.
// If the Status is StatusInvalid, the returned error is of type *OrderError.
func (c *Client) WaitOrder(ctx context.Context, url string) (*Order, error) {
if _, err := c.Discover(ctx); err != nil {
return nil, err
}
for {
res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK))
if err != nil {
return nil, err
}
o, err := responseOrder(res)
res.Body.Close()
switch {
case err != nil:
// Skip and retry.
case o.Status == StatusInvalid:
return nil, &OrderError{OrderURL: o.URI, Status: o.Status, Problem: o.Error}
case o.Status == StatusReady || o.Status == StatusValid:
return o, nil
}
d := retryAfter(res.Header.Get("Retry-After"))
if d == 0 {
// Default retry-after.
// Same reasoning as in WaitAuthorization.
d = time.Second
}
t := time.NewTimer(d)
select {
case <-ctx.Done():
t.Stop()
return nil, ctx.Err()
case <-t.C:
// Retry.
}
}
}
func responseOrder(res *http.Response) (*Order, error) {
var v struct {
Status string
Expires time.Time
Identifiers []wireAuthzID
NotBefore time.Time
NotAfter time.Time
Error *wireError
Authorizations []string
Finalize string
Certificate string
}
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
return nil, fmt.Errorf("acme: error reading order: %v", err)
}
o := &Order{
URI: res.Header.Get("Location"),
Status: v.Status,
Expires: v.Expires,
NotBefore: v.NotBefore,
NotAfter: v.NotAfter,
AuthzURLs: v.Authorizations,
FinalizeURL: v.Finalize,
CertURL: v.Certificate,
}
for _, id := range v.Identifiers {
o.Identifiers = append(o.Identifiers, AuthzID{Type: id.Type, Value: id.Value})
}
if v.Error != nil {
o.Error = v.Error.error(nil /* headers */)
}
return o, nil
}
// CreateOrderCert submits the CSR (Certificate Signing Request) to a CA at the specified URL.
// The URL is the FinalizeURL field of an Order created with AuthorizeOrder.
//
// If the bundle argument is true, the returned value also contain the CA (issuer)
// certificate chain. Otherwise, only a leaf certificate is returned.
// The returned URL can be used to re-fetch the certificate using FetchCert.
//
// This method is only supported by CAs implementing RFC 8555. See CreateCert for pre-RFC CAs.
//
// CreateOrderCert returns an error if the CA's response is unreasonably large.
// Callers are encouraged to parse the returned value to ensure the certificate is valid and has the expected features.
func (c *Client) CreateOrderCert(ctx context.Context, url string, csr []byte, bundle bool) (der [][]byte, certURL string, err error) {
if _, err := c.Discover(ctx); err != nil { // required by c.accountKID
return nil, "", err
}
// RFC describes this as "finalize order" request.
req := struct {
CSR string `json:"csr"`
}{
CSR: base64.RawURLEncoding.EncodeToString(csr),
}
res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK))
if err != nil {
return nil, "", err
}
defer res.Body.Close()
o, err := responseOrder(res)
if err != nil {
return nil, "", err
}
// Wait for CA to issue the cert if they haven't.
if o.Status != StatusValid {
o, err = c.WaitOrder(ctx, o.URI)
}
if err != nil {
return nil, "", err
}
// The only acceptable status post finalize and WaitOrder is "valid".
if o.Status != StatusValid {
return nil, "", &OrderError{OrderURL: o.URI, Status: o.Status, Problem: o.Error}
}
crt, err := c.fetchCertRFC(ctx, o.CertURL, bundle)
return crt, o.CertURL, err
}
// fetchCertRFC downloads issued certificate from the given URL.
// It expects the CA to respond with PEM-encoded certificate chain.
//
// The URL argument is the CertURL field of Order.
func (c *Client) fetchCertRFC(ctx context.Context, url string, bundle bool) ([][]byte, error) {
res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK))
if err != nil {
return nil, err
}
defer res.Body.Close()
// Get all the bytes up to a sane maximum.
// Account very roughly for base64 overhead.
const max = maxCertChainSize + maxCertChainSize/33
b, err := io.ReadAll(io.LimitReader(res.Body, max+1))
if err != nil {
return nil, fmt.Errorf("acme: fetch cert response stream: %v", err)
}
if len(b) > max {
return nil, errors.New("acme: certificate chain is too big")
}
// Decode PEM chain.
var chain [][]byte
for {
var p *pem.Block
p, b = pem.Decode(b)
if p == nil {
break
}
if p.Type != "CERTIFICATE" {
return nil, fmt.Errorf("acme: invalid PEM cert type %q", p.Type)
}
chain = append(chain, p.Bytes)
if !bundle {
return chain, nil
}
if len(chain) > maxChainLen {
return nil, errors.New("acme: certificate chain is too long")
}
}
if len(chain) == 0 {
return nil, errors.New("acme: certificate chain is empty")
}
return chain, nil
}
// sends a cert revocation request in either JWK form when key is non-nil or KID form otherwise.
func (c *Client) revokeCertRFC(ctx context.Context, key crypto.Signer, cert []byte, reason CRLReasonCode) error {
req := &struct {
Cert string `json:"certificate"`
Reason int `json:"reason"`
}{
Cert: base64.RawURLEncoding.EncodeToString(cert),
Reason: int(reason),
}
res, err := c.post(ctx, key, c.dir.RevokeURL, req, wantStatus(http.StatusOK))
if err != nil {
if isAlreadyRevoked(err) {
// Assume it is not an error to revoke an already revoked cert.
return nil
}
return err
}
defer res.Body.Close()
return nil
}
func isAlreadyRevoked(err error) bool {
e, ok := err.(*Error)
return ok && e.ProblemType == "urn:ietf:params:acme:error:alreadyRevoked"
}
// ListCertAlternates retrieves any alternate certificate chain URLs for the
// given certificate chain URL. These alternate URLs can be passed to FetchCert
// in order to retrieve the alternate certificate chains.
//
// If there are no alternate issuer certificate chains, a nil slice will be
// returned.
func (c *Client) ListCertAlternates(ctx context.Context, url string) ([]string, error) {
if _, err := c.Discover(ctx); err != nil { // required by c.accountKID
return nil, err
}
res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK))
if err != nil {
return nil, err
}
defer res.Body.Close()
// We don't need the body but we need to discard it so we don't end up
// preventing keep-alive
if _, err := io.Copy(io.Discard, res.Body); err != nil {
return nil, fmt.Errorf("acme: cert alternates response stream: %v", err)
}
alts := linkHeader(res.Header, "alternate")
return alts, nil
}
// 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.
package acme
import (
"crypto"
"crypto/x509"
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
"time"
)
// ACME status values of Account, Order, Authorization and Challenge objects.
// See https://tools.ietf.org/html/rfc8555#section-7.1.6 for details.
const (
StatusDeactivated = "deactivated"
StatusExpired = "expired"
StatusInvalid = "invalid"
StatusPending = "pending"
StatusProcessing = "processing"
StatusReady = "ready"
StatusRevoked = "revoked"
StatusUnknown = "unknown"
StatusValid = "valid"
)
// CRLReasonCode identifies the reason for a certificate revocation.
type CRLReasonCode int
// CRL reason codes as defined in RFC 5280.
const (
CRLReasonUnspecified CRLReasonCode = 0
CRLReasonKeyCompromise CRLReasonCode = 1
CRLReasonCACompromise CRLReasonCode = 2
CRLReasonAffiliationChanged CRLReasonCode = 3
CRLReasonSuperseded CRLReasonCode = 4
CRLReasonCessationOfOperation CRLReasonCode = 5
CRLReasonCertificateHold CRLReasonCode = 6
CRLReasonRemoveFromCRL CRLReasonCode = 8
CRLReasonPrivilegeWithdrawn CRLReasonCode = 9
CRLReasonAACompromise CRLReasonCode = 10
)
var (
// ErrUnsupportedKey is returned when an unsupported key type is encountered.
ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported")
// ErrAccountAlreadyExists indicates that the Client's key has already been registered
// with the CA. It is returned by Register method.
ErrAccountAlreadyExists = errors.New("acme: account already exists")
// ErrNoAccount indicates that the Client's key has not been registered with the CA.
ErrNoAccount = errors.New("acme: account does not exist")
// errPreAuthorizationNotSupported indicates that the server does not
// support pre-authorization of identifiers.
errPreAuthorizationNotSupported = errors.New("acme: pre-authorization is not supported")
)
// A Subproblem describes an ACME subproblem as reported in an Error.
type Subproblem struct {
// Type is a URI reference that identifies the problem type,
// typically in a "urn:acme:error:xxx" form.
Type string
// Detail is a human-readable explanation specific to this occurrence of the problem.
Detail string
// Instance indicates a URL that the client should direct a human user to visit
// in order for instructions on how to agree to the updated Terms of Service.
// In such an event CA sets StatusCode to 403, Type to
// "urn:ietf:params:acme:error:userActionRequired", and adds a Link header with relation
// "terms-of-service" containing the latest TOS URL.
Instance string
// Identifier may contain the ACME identifier that the error is for.
Identifier *AuthzID
}
func (sp Subproblem) String() string {
str := fmt.Sprintf("%s: ", sp.Type)
if sp.Identifier != nil {
str += fmt.Sprintf("[%s: %s] ", sp.Identifier.Type, sp.Identifier.Value)
}
str += sp.Detail
return str
}
// Error is an ACME error, defined in Problem Details for HTTP APIs doc
// http://tools.ietf.org/html/draft-ietf-appsawg-http-problem.
type Error struct {
// StatusCode is The HTTP status code generated by the origin server.
StatusCode int
// ProblemType is a URI reference that identifies the problem type,
// typically in a "urn:acme:error:xxx" form.
ProblemType string
// Detail is a human-readable explanation specific to this occurrence of the problem.
Detail string
// Instance indicates a URL that the client should direct a human user to visit
// in order for instructions on how to agree to the updated Terms of Service.
// In such an event CA sets StatusCode to 403, ProblemType to
// "urn:ietf:params:acme:error:userActionRequired" and a Link header with relation
// "terms-of-service" containing the latest TOS URL.
Instance string
// Header is the original server error response headers.
// It may be nil.
Header http.Header
// Subproblems may contain more detailed information about the individual problems
// that caused the error. This field is only sent by RFC 8555 compatible ACME
// servers. Defined in RFC 8555 Section 6.7.1.
Subproblems []Subproblem
}
func (e *Error) Error() string {
str := fmt.Sprintf("%d %s: %s", e.StatusCode, e.ProblemType, e.Detail)
if len(e.Subproblems) > 0 {
str += fmt.Sprintf("; subproblems:")
for _, sp := range e.Subproblems {
str += fmt.Sprintf("\n\t%s", sp)
}
}
return str
}
// AuthorizationError indicates that an authorization for an identifier
// did not succeed.
// It contains all errors from Challenge items of the failed Authorization.
type AuthorizationError struct {
// URI uniquely identifies the failed Authorization.
URI string
// Identifier is an AuthzID.Value of the failed Authorization.
Identifier string
// Errors is a collection of non-nil error values of Challenge items
// of the failed Authorization.
Errors []error
}
func (a *AuthorizationError) Error() string {
e := make([]string, len(a.Errors))
for i, err := range a.Errors {
e[i] = err.Error()
}
if a.Identifier != "" {
return fmt.Sprintf("acme: authorization error for %s: %s", a.Identifier, strings.Join(e, "; "))
}
return fmt.Sprintf("acme: authorization error: %s", strings.Join(e, "; "))
}
// OrderError is returned from Client's order related methods.
// It indicates the order is unusable and the clients should start over with
// AuthorizeOrder. A Problem description may be provided with details on
// what caused the order to become unusable.
//
// The clients can still fetch the order object from CA using GetOrder
// to inspect its state.
type OrderError struct {
OrderURL string
Status string
// Problem is the error that occurred while processing the order.
Problem *Error
}
func (oe *OrderError) Error() string {
return fmt.Sprintf("acme: order %s status: %s", oe.OrderURL, oe.Status)
}
// RateLimit reports whether err represents a rate limit error and
// any Retry-After duration returned by the server.
//
// See the following for more details on rate limiting:
// https://tools.ietf.org/html/draft-ietf-acme-acme-05#section-5.6
func RateLimit(err error) (time.Duration, bool) {
e, ok := err.(*Error)
if !ok {
return 0, false
}
// Some CA implementations may return incorrect values.
// Use case-insensitive comparison.
if !strings.HasSuffix(strings.ToLower(e.ProblemType), ":ratelimited") {
return 0, false
}
if e.Header == nil {
return 0, true
}
return retryAfter(e.Header.Get("Retry-After")), true
}
// Account is a user account. It is associated with a private key.
// Non-RFC 8555 fields are empty when interfacing with a compliant CA.
type Account struct {
// URI is the account unique ID, which is also a URL used to retrieve
// account data from the CA.
// When interfacing with RFC 8555-compliant CAs, URI is the "kid" field
// value in JWS signed requests.
URI string
// Contact is a slice of contact info used during registration.
// See https://tools.ietf.org/html/rfc8555#section-7.3 for supported
// formats.
Contact []string
// Status indicates current account status as returned by the CA.
// Possible values are StatusValid, StatusDeactivated, and StatusRevoked.
Status string
// OrdersURL is a URL from which a list of orders submitted by this account
// can be fetched.
OrdersURL string
// The terms user has agreed to.
// A value not matching CurrentTerms indicates that the user hasn't agreed
// to the actual Terms of Service of the CA.
//
// It is non-RFC 8555 compliant. Package users can store the ToS they agree to
// during Client's Register call in the prompt callback function.
AgreedTerms string
// Actual terms of a CA.
//
// It is non-RFC 8555 compliant. Use Directory's Terms field.
// When a CA updates their terms and requires an account agreement,
// a URL at which instructions to do so is available in Error's Instance field.
CurrentTerms string
// Authz is the authorization URL used to initiate a new authz flow.
//
// It is non-RFC 8555 compliant. Use Directory's AuthzURL or OrderURL.
Authz string
// Authorizations is a URI from which a list of authorizations
// granted to this account can be fetched via a GET request.
//
// It is non-RFC 8555 compliant and is obsoleted by OrdersURL.
Authorizations string
// Certificates is a URI from which a list of certificates
// issued for this account can be fetched via a GET request.
//
// It is non-RFC 8555 compliant and is obsoleted by OrdersURL.
Certificates string
// ExternalAccountBinding represents an arbitrary binding to an account of
// the CA which the ACME server is tied to.
// See https://tools.ietf.org/html/rfc8555#section-7.3.4 for more details.
ExternalAccountBinding *ExternalAccountBinding
}
// ExternalAccountBinding contains the data needed to form a request with
// an external account binding.
// See https://tools.ietf.org/html/rfc8555#section-7.3.4 for more details.
type ExternalAccountBinding struct {
// KID is the Key ID of the symmetric MAC key that the CA provides to
// identify an external account from ACME.
KID string
// Key is the bytes of the symmetric key that the CA provides to identify
// the account. Key must correspond to the KID.
Key []byte
}
func (e *ExternalAccountBinding) String() string {
return fmt.Sprintf("&{KID: %q, Key: redacted}", e.KID)
}
// Directory is ACME server discovery data.
// See https://tools.ietf.org/html/rfc8555#section-7.1.1 for more details.
type Directory struct {
// NonceURL indicates an endpoint where to fetch fresh nonce values from.
NonceURL string
// RegURL is an account endpoint URL, allowing for creating new accounts.
// Pre-RFC 8555 CAs also allow modifying existing accounts at this URL.
RegURL string
// OrderURL is used to initiate the certificate issuance flow
// as described in RFC 8555.
OrderURL string
// AuthzURL is used to initiate identifier pre-authorization flow.
// Empty string indicates the flow is unsupported by the CA.
AuthzURL string
// CertURL is a new certificate issuance endpoint URL.
// It is non-RFC 8555 compliant and is obsoleted by OrderURL.
CertURL string
// RevokeURL is used to initiate a certificate revocation flow.
RevokeURL string
// KeyChangeURL allows to perform account key rollover flow.
KeyChangeURL string
// Terms is a URI identifying the current terms of service.
Terms string
// Website is an HTTP or HTTPS URL locating a website
// providing more information about the ACME server.
Website string
// CAA consists of lowercase hostname elements, which the ACME server
// recognises as referring to itself for the purposes of CAA record validation
// as defined in RFC 6844.
CAA []string
// ExternalAccountRequired indicates that the CA requires for all account-related
// requests to include external account binding information.
ExternalAccountRequired bool
}
// Order represents a client's request for a certificate.
// It tracks the request flow progress through to issuance.
type Order struct {
// URI uniquely identifies an order.
URI string
// Status represents the current status of the order.
// It indicates which action the client should take.
//
// Possible values are StatusPending, StatusReady, StatusProcessing, StatusValid and StatusInvalid.
// Pending means the CA does not believe that the client has fulfilled the requirements.
// Ready indicates that the client has fulfilled all the requirements and can submit a CSR
// to obtain a certificate. This is done with Client's CreateOrderCert.
// Processing means the certificate is being issued.
// Valid indicates the CA has issued the certificate. It can be downloaded
// from the Order's CertURL. This is done with Client's FetchCert.
// Invalid means the certificate will not be issued. Users should consider this order
// abandoned.
Status string
// Expires is the timestamp after which CA considers this order invalid.
Expires time.Time
// Identifiers contains all identifier objects which the order pertains to.
Identifiers []AuthzID
// NotBefore is the requested value of the notBefore field in the certificate.
NotBefore time.Time
// NotAfter is the requested value of the notAfter field in the certificate.
NotAfter time.Time
// AuthzURLs represents authorizations to complete before a certificate
// for identifiers specified in the order can be issued.
// It also contains unexpired authorizations that the client has completed
// in the past.
//
// Authorization objects can be fetched using Client's GetAuthorization method.
//
// The required authorizations are dictated by CA policies.
// There may not be a 1:1 relationship between the identifiers and required authorizations.
// Required authorizations can be identified by their StatusPending status.
//
// For orders in the StatusValid or StatusInvalid state these are the authorizations
// which were completed.
AuthzURLs []string
// FinalizeURL is the endpoint at which a CSR is submitted to obtain a certificate
// once all the authorizations are satisfied.
FinalizeURL string
// CertURL points to the certificate that has been issued in response to this order.
CertURL string
// The error that occurred while processing the order as received from a CA, if any.
Error *Error
}
// OrderOption allows customizing Client.AuthorizeOrder call.
type OrderOption interface {
privateOrderOpt()
}
// WithOrderNotBefore sets order's NotBefore field.
func WithOrderNotBefore(t time.Time) OrderOption {
return orderNotBeforeOpt(t)
}
// WithOrderNotAfter sets order's NotAfter field.
func WithOrderNotAfter(t time.Time) OrderOption {
return orderNotAfterOpt(t)
}
type orderNotBeforeOpt time.Time
func (orderNotBeforeOpt) privateOrderOpt() {}
type orderNotAfterOpt time.Time
func (orderNotAfterOpt) privateOrderOpt() {}
// Authorization encodes an authorization response.
type Authorization struct {
// URI uniquely identifies a authorization.
URI string
// Status is the current status of an authorization.
// Possible values are StatusPending, StatusValid, StatusInvalid, StatusDeactivated,
// StatusExpired and StatusRevoked.
Status string
// Identifier is what the account is authorized to represent.
Identifier AuthzID
// The timestamp after which the CA considers the authorization invalid.
Expires time.Time
// Wildcard is true for authorizations of a wildcard domain name.
Wildcard bool
// Challenges that the client needs to fulfill in order to prove possession
// of the identifier (for pending authorizations).
// For valid authorizations, the challenge that was validated.
// For invalid authorizations, the challenge that was attempted and failed.
//
// RFC 8555 compatible CAs require users to fuflfill only one of the challenges.
Challenges []*Challenge
// A collection of sets of challenges, each of which would be sufficient
// to prove possession of the identifier.
// Clients must complete a set of challenges that covers at least one set.
// Challenges are identified by their indices in the challenges array.
// If this field is empty, the client needs to complete all challenges.
//
// This field is unused in RFC 8555.
Combinations [][]int
}
// AuthzID is an identifier that an account is authorized to represent.
type AuthzID struct {
Type string // The type of identifier, "dns" or "ip".
Value string // The identifier itself, e.g. "example.org".
}
// DomainIDs creates a slice of AuthzID with "dns" identifier type.
func DomainIDs(names ...string) []AuthzID {
a := make([]AuthzID, len(names))
for i, v := range names {
a[i] = AuthzID{Type: "dns", Value: v}
}
return a
}
// IPIDs creates a slice of AuthzID with "ip" identifier type.
// Each element of addr is textual form of an address as defined
// in RFC 1123 Section 2.1 for IPv4 and in RFC 5952 Section 4 for IPv6.
func IPIDs(addr ...string) []AuthzID {
a := make([]AuthzID, len(addr))
for i, v := range addr {
a[i] = AuthzID{Type: "ip", Value: v}
}
return a
}
// wireAuthzID is ACME JSON representation of authorization identifier objects.
type wireAuthzID struct {
Type string `json:"type"`
Value string `json:"value"`
}
// wireAuthz is ACME JSON representation of Authorization objects.
type wireAuthz struct {
Identifier wireAuthzID
Status string
Expires time.Time
Wildcard bool
Challenges []wireChallenge
Combinations [][]int
Error *wireError
}
func (z *wireAuthz) authorization(uri string) *Authorization {
a := &Authorization{
URI: uri,
Status: z.Status,
Identifier: AuthzID{Type: z.Identifier.Type, Value: z.Identifier.Value},
Expires: z.Expires,
Wildcard: z.Wildcard,
Challenges: make([]*Challenge, len(z.Challenges)),
Combinations: z.Combinations, // shallow copy
}
for i, v := range z.Challenges {
a.Challenges[i] = v.challenge()
}
return a
}
func (z *wireAuthz) error(uri string) *AuthorizationError {
err := &AuthorizationError{
URI: uri,
Identifier: z.Identifier.Value,
}
if z.Error != nil {
err.Errors = append(err.Errors, z.Error.error(nil))
}
for _, raw := range z.Challenges {
if raw.Error != nil {
err.Errors = append(err.Errors, raw.Error.error(nil))
}
}
return err
}
// Challenge encodes a returned CA challenge.
// Its Error field may be non-nil if the challenge is part of an Authorization
// with StatusInvalid.
type Challenge struct {
// Type is the challenge type, e.g. "http-01", "tls-alpn-01", "dns-01".
Type string
// URI is where a challenge response can be posted to.
URI string
// Token is a random value that uniquely identifies the challenge.
Token string
// Status identifies the status of this challenge.
// In RFC 8555, possible values are StatusPending, StatusProcessing, StatusValid,
// and StatusInvalid.
Status string
// Validated is the time at which the CA validated this challenge.
// Always zero value in pre-RFC 8555.
Validated time.Time
// Error indicates the reason for an authorization failure
// when this challenge was used.
// The type of a non-nil value is *Error.
Error error
// Payload is the JSON-formatted payload that the client sends
// to the server to indicate it is ready to respond to the challenge.
// When unset, it defaults to an empty JSON object: {}.
// For most challenges, the client must not set Payload,
// see https://tools.ietf.org/html/rfc8555#section-7.5.1.
// Payload is used only for newer challenges (such as "device-attest-01")
// where the client must send additional data for the server to validate
// the challenge.
Payload json.RawMessage
}
// wireChallenge is ACME JSON challenge representation.
type wireChallenge struct {
URL string `json:"url"` // RFC
URI string `json:"uri"` // pre-RFC
Type string
Token string
Status string
Validated time.Time
Error *wireError
}
func (c *wireChallenge) challenge() *Challenge {
v := &Challenge{
URI: c.URL,
Type: c.Type,
Token: c.Token,
Status: c.Status,
}
if v.URI == "" {
v.URI = c.URI // c.URL was empty; use legacy
}
if v.Status == "" {
v.Status = StatusPending
}
if c.Error != nil {
v.Error = c.Error.error(nil)
}
return v
}
// wireError is a subset of fields of the Problem Details object
// as described in https://tools.ietf.org/html/rfc7807#section-3.1.
type wireError struct {
Status int
Type string
Detail string
Instance string
Subproblems []Subproblem
}
func (e *wireError) error(h http.Header) *Error {
err := &Error{
StatusCode: e.Status,
ProblemType: e.Type,
Detail: e.Detail,
Instance: e.Instance,
Header: h,
Subproblems: e.Subproblems,
}
return err
}
// CertOption is an optional argument type for the TLS ChallengeCert methods for
// customizing a temporary certificate for TLS-based challenges.
type CertOption interface {
privateCertOpt()
}
// WithKey creates an option holding a private/public key pair.
// The private part signs a certificate, and the public part represents the signee.
func WithKey(key crypto.Signer) CertOption {
return &certOptKey{key}
}
type certOptKey struct {
key crypto.Signer
}
func (*certOptKey) privateCertOpt() {}
// WithTemplate creates an option for specifying a certificate template.
// See x509.CreateCertificate for template usage details.
//
// In TLS ChallengeCert methods, the template is also used as parent,
// resulting in a self-signed certificate.
// The DNSNames or IPAddresses fields of t are always overwritten for tls-alpn challenge certs.
func WithTemplate(t *x509.Certificate) CertOption {
return (*certOptTemplate)(t)
}
type certOptTemplate x509.Certificate
func (*certOptTemplate) privateCertOpt() {}
// 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 argon2 implements the key derivation function Argon2.
// Argon2 was selected as the winner of the Password Hashing Competition and can
// be used to derive cryptographic keys from passwords.
//
// For a detailed specification of Argon2 see [argon2-specs.pdf].
//
// If you aren't sure which function you need, use Argon2id (IDKey) and
// the parameter recommendations for your scenario.
//
// # Argon2i
//
// Argon2i (implemented by Key) is the side-channel resistant version of Argon2.
// It uses data-independent memory access, which is preferred for password
// hashing and password-based key derivation. Argon2i requires more passes over
// memory than Argon2id to protect from trade-off attacks. The recommended
// parameters (taken from [RFC 9106 Section 7.3]) for non-interactive operations are time=3 and to
// use the maximum available memory.
//
// # Argon2id
//
// Argon2id (implemented by IDKey) is a hybrid version of Argon2 combining
// Argon2i and Argon2d. It uses data-independent memory access for the first
// half of the first iteration over the memory and data-dependent memory access
// for the rest. Argon2id is side-channel resistant and provides better brute-
// force cost savings due to time-memory tradeoffs than Argon2i. The recommended
// parameters for non-interactive operations (taken from [RFC 9106 Section 7.3]) are time=1 and to
// use the maximum available memory.
//
// [argon2-specs.pdf]: https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
// [RFC 9106 Section 7.3]: https://www.rfc-editor.org/rfc/rfc9106.html#section-7.3
package argon2
import (
"encoding/binary"
"sync"
"golang.org/x/crypto/blake2b"
)
// The Argon2 version implemented by this package.
const Version = 0x13
const (
argon2d = iota
argon2i
argon2id
)
// Key derives a key from the password, salt, and cost parameters using Argon2i
// returning a byte slice of length keyLen that can be used as cryptographic
// key. The CPU cost and parallelism degree must be greater than zero.
//
// For example, you can get a derived key for e.g. AES-256 (which needs a
// 32-byte key) by doing:
//
// key := argon2.Key([]byte("some password"), salt, 3, 32*1024, 4, 32)
//
// [RFC 9106 Section 7.3] recommends time=3, and memory=32*1024 as a sensible number.
// If using that amount of memory (32 MB) is not possible in some contexts then
// the time parameter can be increased to compensate.
//
// The time parameter specifies the number of passes over the memory and the
// memory parameter specifies the size of the memory in KiB. For example
// memory=32*1024 sets the memory cost to ~32 MB. The number of threads can be
// adjusted to the number of available CPUs. The cost parameters should be
// increased as memory latency and CPU parallelism increases. Remember to get a
// good random salt.
//
// [RFC 9106 Section 7.3]: https://www.rfc-editor.org/rfc/rfc9106.html#section-7.3
func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
return deriveKey(argon2i, password, salt, nil, nil, time, memory, threads, keyLen)
}
// IDKey derives a key from the password, salt, and cost parameters using
// Argon2id returning a byte slice of length keyLen that can be used as
// cryptographic key. The CPU cost and parallelism degree must be greater than
// zero.
//
// For example, you can get a derived key for e.g. AES-256 (which needs a
// 32-byte key) by doing:
//
// key := argon2.IDKey([]byte("some password"), salt, 1, 64*1024, 4, 32)
//
// [RFC 9106 Section 7.3] recommends time=1, and memory=64*1024 as a sensible number.
// If using that amount of memory (64 MB) is not possible in some contexts then
// the time parameter can be increased to compensate.
//
// The time parameter specifies the number of passes over the memory and the
// memory parameter specifies the size of the memory in KiB. For example
// memory=64*1024 sets the memory cost to ~64 MB. The number of threads can be
// adjusted to the numbers of available CPUs. The cost parameters should be
// increased as memory latency and CPU parallelism increases. Remember to get a
// good random salt.
//
// [RFC 9106 Section 7.3]: https://www.rfc-editor.org/rfc/rfc9106.html#section-7.3
func IDKey(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
return deriveKey(argon2id, password, salt, nil, nil, time, memory, threads, keyLen)
}
func deriveKey(mode int, password, salt, secret, data []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
if time < 1 {
panic("argon2: number of rounds too small")
}
if threads < 1 {
panic("argon2: parallelism degree too low")
}
h0 := initHash(password, salt, secret, data, time, memory, uint32(threads), keyLen, mode)
memory = memory / (syncPoints * uint32(threads)) * (syncPoints * uint32(threads))
if memory < 2*syncPoints*uint32(threads) {
memory = 2 * syncPoints * uint32(threads)
}
B := initBlocks(&h0, memory, uint32(threads))
processBlocks(B, time, memory, uint32(threads), mode)
return extractKey(B, memory, uint32(threads), keyLen)
}
const (
blockLength = 128
syncPoints = 4
)
type block [blockLength]uint64
func initHash(password, salt, key, data []byte, time, memory, threads, keyLen uint32, mode int) [blake2b.Size + 8]byte {
var (
h0 [blake2b.Size + 8]byte
params [24]byte
tmp [4]byte
)
b2, _ := blake2b.New512(nil)
binary.LittleEndian.PutUint32(params[0:4], threads)
binary.LittleEndian.PutUint32(params[4:8], keyLen)
binary.LittleEndian.PutUint32(params[8:12], memory)
binary.LittleEndian.PutUint32(params[12:16], time)
binary.LittleEndian.PutUint32(params[16:20], uint32(Version))
binary.LittleEndian.PutUint32(params[20:24], uint32(mode))
b2.Write(params[:])
binary.LittleEndian.PutUint32(tmp[:], uint32(len(password)))
b2.Write(tmp[:])
b2.Write(password)
binary.LittleEndian.PutUint32(tmp[:], uint32(len(salt)))
b2.Write(tmp[:])
b2.Write(salt)
binary.LittleEndian.PutUint32(tmp[:], uint32(len(key)))
b2.Write(tmp[:])
b2.Write(key)
binary.LittleEndian.PutUint32(tmp[:], uint32(len(data)))
b2.Write(tmp[:])
b2.Write(data)
b2.Sum(h0[:0])
return h0
}
func initBlocks(h0 *[blake2b.Size + 8]byte, memory, threads uint32) []block {
var block0 [1024]byte
B := make([]block, memory)
for lane := uint32(0); lane < threads; lane++ {
j := lane * (memory / threads)
binary.LittleEndian.PutUint32(h0[blake2b.Size+4:], lane)
binary.LittleEndian.PutUint32(h0[blake2b.Size:], 0)
blake2bHash(block0[:], h0[:])
for i := range B[j+0] {
B[j+0][i] = binary.LittleEndian.Uint64(block0[i*8:])
}
binary.LittleEndian.PutUint32(h0[blake2b.Size:], 1)
blake2bHash(block0[:], h0[:])
for i := range B[j+1] {
B[j+1][i] = binary.LittleEndian.Uint64(block0[i*8:])
}
}
return B
}
func processBlocks(B []block, time, memory, threads uint32, mode int) {
lanes := memory / threads
segments := lanes / syncPoints
processSegment := func(n, slice, lane uint32, wg *sync.WaitGroup) {
var addresses, in, zero block
if mode == argon2i || (mode == argon2id && n == 0 && slice < syncPoints/2) {
in[0] = uint64(n)
in[1] = uint64(lane)
in[2] = uint64(slice)
in[3] = uint64(memory)
in[4] = uint64(time)
in[5] = uint64(mode)
}
index := uint32(0)
if n == 0 && slice == 0 {
index = 2 // we have already generated the first two blocks
if mode == argon2i || mode == argon2id {
in[6]++
processBlock(&addresses, &in, &zero)
processBlock(&addresses, &addresses, &zero)
}
}
offset := lane*lanes + slice*segments + index
var random uint64
for index < segments {
prev := offset - 1
if index == 0 && slice == 0 {
prev += lanes // last block in lane
}
if mode == argon2i || (mode == argon2id && n == 0 && slice < syncPoints/2) {
if index%blockLength == 0 {
in[6]++
processBlock(&addresses, &in, &zero)
processBlock(&addresses, &addresses, &zero)
}
random = addresses[index%blockLength]
} else {
random = B[prev][0]
}
newOffset := indexAlpha(random, lanes, segments, threads, n, slice, lane, index)
processBlockXOR(&B[offset], &B[prev], &B[newOffset])
index, offset = index+1, offset+1
}
wg.Done()
}
for n := uint32(0); n < time; n++ {
for slice := uint32(0); slice < syncPoints; slice++ {
var wg sync.WaitGroup
for lane := uint32(0); lane < threads; lane++ {
wg.Add(1)
go processSegment(n, slice, lane, &wg)
}
wg.Wait()
}
}
}
func extractKey(B []block, memory, threads, keyLen uint32) []byte {
lanes := memory / threads
for lane := uint32(0); lane < threads-1; lane++ {
for i, v := range B[(lane*lanes)+lanes-1] {
B[memory-1][i] ^= v
}
}
var block [1024]byte
for i, v := range B[memory-1] {
binary.LittleEndian.PutUint64(block[i*8:], v)
}
key := make([]byte, keyLen)
blake2bHash(key, block[:])
return key
}
func indexAlpha(rand uint64, lanes, segments, threads, n, slice, lane, index uint32) uint32 {
refLane := uint32(rand>>32) % threads
if n == 0 && slice == 0 {
refLane = lane
}
m, s := 3*segments, ((slice+1)%syncPoints)*segments
if lane == refLane {
m += index
}
if n == 0 {
m, s = slice*segments, 0
if slice == 0 || lane == refLane {
m += index
}
}
if index == 0 || lane == refLane {
m--
}
return phi(rand, uint64(m), uint64(s), refLane, lanes)
}
func phi(rand, m, s uint64, lane, lanes uint32) uint32 {
p := rand & 0xFFFFFFFF
p = (p * p) >> 32
p = (p * m) >> 32
return lane*lanes + uint32((s+m-(p+1))%uint64(lanes))
}
// 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 argon2
import (
"encoding/binary"
"hash"
"golang.org/x/crypto/blake2b"
)
// blake2bHash computes an arbitrary long hash value of in
// and writes the hash to out.
func blake2bHash(out []byte, in []byte) {
var b2 hash.Hash
if n := len(out); n < blake2b.Size {
b2, _ = blake2b.New(n, nil)
} else {
b2, _ = blake2b.New512(nil)
}
var buffer [blake2b.Size]byte
binary.LittleEndian.PutUint32(buffer[:4], uint32(len(out)))
b2.Write(buffer[:4])
b2.Write(in)
if len(out) <= blake2b.Size {
b2.Sum(out[:0])
return
}
outLen := len(out)
b2.Sum(buffer[:0])
b2.Reset()
copy(out, buffer[:32])
out = out[32:]
for len(out) > blake2b.Size {
b2.Write(buffer[:])
b2.Sum(buffer[:0])
copy(out, buffer[:32])
out = out[32:]
b2.Reset()
}
if outLen%blake2b.Size > 0 { // outLen > 64
r := ((outLen + 31) / 32) - 2 // ⌈τ /32⌉-2
b2, _ = blake2b.New(outLen-32*r, nil)
}
b2.Write(buffer[:])
b2.Sum(out[:0])
}
// 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.
//go:build amd64 && gc && !purego
package argon2
import "golang.org/x/sys/cpu"
func init() {
useSSE4 = cpu.X86.HasSSE41
}
//go:noescape
func mixBlocksSSE2(out, a, b, c *block)
//go:noescape
func xorBlocksSSE2(out, a, b, c *block)
//go:noescape
func blamkaSSE4(b *block)
func processBlockSSE(out, in1, in2 *block, xor bool) {
var t block
mixBlocksSSE2(&t, in1, in2, &t)
if useSSE4 {
blamkaSSE4(&t)
} else {
for i := 0; i < blockLength; i += 16 {
blamkaGeneric(
&t[i+0], &t[i+1], &t[i+2], &t[i+3],
&t[i+4], &t[i+5], &t[i+6], &t[i+7],
&t[i+8], &t[i+9], &t[i+10], &t[i+11],
&t[i+12], &t[i+13], &t[i+14], &t[i+15],
)
}
for i := 0; i < blockLength/8; i += 2 {
blamkaGeneric(
&t[i], &t[i+1], &t[16+i], &t[16+i+1],
&t[32+i], &t[32+i+1], &t[48+i], &t[48+i+1],
&t[64+i], &t[64+i+1], &t[80+i], &t[80+i+1],
&t[96+i], &t[96+i+1], &t[112+i], &t[112+i+1],
)
}
}
if xor {
xorBlocksSSE2(out, in1, in2, &t)
} else {
mixBlocksSSE2(out, in1, in2, &t)
}
}
func processBlock(out, in1, in2 *block) {
processBlockSSE(out, in1, in2, false)
}
func processBlockXOR(out, in1, in2 *block) {
processBlockSSE(out, in1, in2, true)
}
// 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 argon2
var useSSE4 bool
func processBlockGeneric(out, in1, in2 *block, xor bool) {
var t block
for i := range t {
t[i] = in1[i] ^ in2[i]
}
for i := 0; i < blockLength; i += 16 {
blamkaGeneric(
&t[i+0], &t[i+1], &t[i+2], &t[i+3],
&t[i+4], &t[i+5], &t[i+6], &t[i+7],
&t[i+8], &t[i+9], &t[i+10], &t[i+11],
&t[i+12], &t[i+13], &t[i+14], &t[i+15],
)
}
for i := 0; i < blockLength/8; i += 2 {
blamkaGeneric(
&t[i], &t[i+1], &t[16+i], &t[16+i+1],
&t[32+i], &t[32+i+1], &t[48+i], &t[48+i+1],
&t[64+i], &t[64+i+1], &t[80+i], &t[80+i+1],
&t[96+i], &t[96+i+1], &t[112+i], &t[112+i+1],
)
}
if xor {
for i := range t {
out[i] ^= in1[i] ^ in2[i] ^ t[i]
}
} else {
for i := range t {
out[i] = in1[i] ^ in2[i] ^ t[i]
}
}
}
func blamkaGeneric(t00, t01, t02, t03, t04, t05, t06, t07, t08, t09, t10, t11, t12, t13, t14, t15 *uint64) {
v00, v01, v02, v03 := *t00, *t01, *t02, *t03
v04, v05, v06, v07 := *t04, *t05, *t06, *t07
v08, v09, v10, v11 := *t08, *t09, *t10, *t11
v12, v13, v14, v15 := *t12, *t13, *t14, *t15
v00 += v04 + 2*uint64(uint32(v00))*uint64(uint32(v04))
v12 ^= v00
v12 = v12>>32 | v12<<32
v08 += v12 + 2*uint64(uint32(v08))*uint64(uint32(v12))
v04 ^= v08
v04 = v04>>24 | v04<<40
v00 += v04 + 2*uint64(uint32(v00))*uint64(uint32(v04))
v12 ^= v00
v12 = v12>>16 | v12<<48
v08 += v12 + 2*uint64(uint32(v08))*uint64(uint32(v12))
v04 ^= v08
v04 = v04>>63 | v04<<1
v01 += v05 + 2*uint64(uint32(v01))*uint64(uint32(v05))
v13 ^= v01
v13 = v13>>32 | v13<<32
v09 += v13 + 2*uint64(uint32(v09))*uint64(uint32(v13))
v05 ^= v09
v05 = v05>>24 | v05<<40
v01 += v05 + 2*uint64(uint32(v01))*uint64(uint32(v05))
v13 ^= v01
v13 = v13>>16 | v13<<48
v09 += v13 + 2*uint64(uint32(v09))*uint64(uint32(v13))
v05 ^= v09
v05 = v05>>63 | v05<<1
v02 += v06 + 2*uint64(uint32(v02))*uint64(uint32(v06))
v14 ^= v02
v14 = v14>>32 | v14<<32
v10 += v14 + 2*uint64(uint32(v10))*uint64(uint32(v14))
v06 ^= v10
v06 = v06>>24 | v06<<40
v02 += v06 + 2*uint64(uint32(v02))*uint64(uint32(v06))
v14 ^= v02
v14 = v14>>16 | v14<<48
v10 += v14 + 2*uint64(uint32(v10))*uint64(uint32(v14))
v06 ^= v10
v06 = v06>>63 | v06<<1
v03 += v07 + 2*uint64(uint32(v03))*uint64(uint32(v07))
v15 ^= v03
v15 = v15>>32 | v15<<32
v11 += v15 + 2*uint64(uint32(v11))*uint64(uint32(v15))
v07 ^= v11
v07 = v07>>24 | v07<<40
v03 += v07 + 2*uint64(uint32(v03))*uint64(uint32(v07))
v15 ^= v03
v15 = v15>>16 | v15<<48
v11 += v15 + 2*uint64(uint32(v11))*uint64(uint32(v15))
v07 ^= v11
v07 = v07>>63 | v07<<1
v00 += v05 + 2*uint64(uint32(v00))*uint64(uint32(v05))
v15 ^= v00
v15 = v15>>32 | v15<<32
v10 += v15 + 2*uint64(uint32(v10))*uint64(uint32(v15))
v05 ^= v10
v05 = v05>>24 | v05<<40
v00 += v05 + 2*uint64(uint32(v00))*uint64(uint32(v05))
v15 ^= v00
v15 = v15>>16 | v15<<48
v10 += v15 + 2*uint64(uint32(v10))*uint64(uint32(v15))
v05 ^= v10
v05 = v05>>63 | v05<<1
v01 += v06 + 2*uint64(uint32(v01))*uint64(uint32(v06))
v12 ^= v01
v12 = v12>>32 | v12<<32
v11 += v12 + 2*uint64(uint32(v11))*uint64(uint32(v12))
v06 ^= v11
v06 = v06>>24 | v06<<40
v01 += v06 + 2*uint64(uint32(v01))*uint64(uint32(v06))
v12 ^= v01
v12 = v12>>16 | v12<<48
v11 += v12 + 2*uint64(uint32(v11))*uint64(uint32(v12))
v06 ^= v11
v06 = v06>>63 | v06<<1
v02 += v07 + 2*uint64(uint32(v02))*uint64(uint32(v07))
v13 ^= v02
v13 = v13>>32 | v13<<32
v08 += v13 + 2*uint64(uint32(v08))*uint64(uint32(v13))
v07 ^= v08
v07 = v07>>24 | v07<<40
v02 += v07 + 2*uint64(uint32(v02))*uint64(uint32(v07))
v13 ^= v02
v13 = v13>>16 | v13<<48
v08 += v13 + 2*uint64(uint32(v08))*uint64(uint32(v13))
v07 ^= v08
v07 = v07>>63 | v07<<1
v03 += v04 + 2*uint64(uint32(v03))*uint64(uint32(v04))
v14 ^= v03
v14 = v14>>32 | v14<<32
v09 += v14 + 2*uint64(uint32(v09))*uint64(uint32(v14))
v04 ^= v09
v04 = v04>>24 | v04<<40
v03 += v04 + 2*uint64(uint32(v03))*uint64(uint32(v04))
v14 ^= v03
v14 = v14>>16 | v14<<48
v09 += v14 + 2*uint64(uint32(v09))*uint64(uint32(v14))
v04 ^= v09
v04 = v04>>63 | v04<<1
*t00, *t01, *t02, *t03 = v00, v01, v02, v03
*t04, *t05, *t06, *t07 = v04, v05, v06, v07
*t08, *t09, *t10, *t11 = v08, v09, v10, v11
*t12, *t13, *t14, *t15 = v12, v13, v14, v15
}
// Copyright 2011 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 bcrypt
import "encoding/base64"
const alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
var bcEncoding = base64.NewEncoding(alphabet)
func base64Encode(src []byte) []byte {
n := bcEncoding.EncodedLen(len(src))
dst := make([]byte, n)
bcEncoding.Encode(dst, src)
for dst[n-1] == '=' {
n--
}
return dst[:n]
}
func base64Decode(src []byte) ([]byte, error) {
numOfEquals := 4 - (len(src) % 4)
for i := 0; i < numOfEquals; i++ {
src = append(src, '=')
}
dst := make([]byte, bcEncoding.DecodedLen(len(src)))
n, err := bcEncoding.Decode(dst, src)
if err != nil {
return nil, err
}
return dst[:n], nil
}
// Copyright 2011 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 bcrypt implements Provos and Mazières's bcrypt adaptive hashing
// algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf
package bcrypt
// The code is a port of Provos and Mazières's C implementation.
import (
"crypto/rand"
"crypto/subtle"
"errors"
"fmt"
"io"
"strconv"
"golang.org/x/crypto/blowfish"
)
const (
MinCost int = 4 // the minimum allowable cost as passed in to GenerateFromPassword
MaxCost int = 31 // the maximum allowable cost as passed in to GenerateFromPassword
DefaultCost int = 10 // the cost that will actually be set if a cost below MinCost is passed into GenerateFromPassword
)
// The error returned from CompareHashAndPassword when a password and hash do
// not match.
var ErrMismatchedHashAndPassword = errors.New("crypto/bcrypt: hashedPassword is not the hash of the given password")
// The error returned from CompareHashAndPassword when a hash is too short to
// be a bcrypt hash.
var ErrHashTooShort = errors.New("crypto/bcrypt: hashedSecret too short to be a bcrypted password")
// The error returned from CompareHashAndPassword when a hash was created with
// a bcrypt algorithm newer than this implementation.
type HashVersionTooNewError byte
func (hv HashVersionTooNewError) Error() string {
return fmt.Sprintf("crypto/bcrypt: bcrypt algorithm version '%c' requested is newer than current version '%c'", byte(hv), majorVersion)
}
// The error returned from CompareHashAndPassword when a hash starts with something other than '$'
type InvalidHashPrefixError byte
func (ih InvalidHashPrefixError) Error() string {
return fmt.Sprintf("crypto/bcrypt: bcrypt hashes must start with '$', but hashedSecret started with '%c'", byte(ih))
}
type InvalidCostError int
func (ic InvalidCostError) Error() string {
return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed inclusive range %d..%d", int(ic), MinCost, MaxCost)
}
const (
majorVersion = '2'
minorVersion = 'a'
maxSaltSize = 16
maxCryptedHashSize = 23
encodedSaltSize = 22
encodedHashSize = 31
minHashSize = 59
)
// magicCipherData is an IV for the 64 Blowfish encryption calls in
// bcrypt(). It's the string "OrpheanBeholderScryDoubt" in big-endian bytes.
var magicCipherData = []byte{
0x4f, 0x72, 0x70, 0x68,
0x65, 0x61, 0x6e, 0x42,
0x65, 0x68, 0x6f, 0x6c,
0x64, 0x65, 0x72, 0x53,
0x63, 0x72, 0x79, 0x44,
0x6f, 0x75, 0x62, 0x74,
}
type hashed struct {
hash []byte
salt []byte
cost int // allowed range is MinCost to MaxCost
major byte
minor byte
}
// ErrPasswordTooLong is returned when the password passed to
// GenerateFromPassword is too long (i.e. > 72 bytes).
var ErrPasswordTooLong = errors.New("bcrypt: password length exceeds 72 bytes")
// GenerateFromPassword returns the bcrypt hash of the password at the given
// cost. If the cost given is less than MinCost, the cost will be set to
// DefaultCost, instead. Use CompareHashAndPassword, as defined in this package,
// to compare the returned hashed password with its cleartext version.
// GenerateFromPassword does not accept passwords longer than 72 bytes, which
// is the longest password bcrypt will operate on.
func GenerateFromPassword(password []byte, cost int) ([]byte, error) {
if len(password) > 72 {
return nil, ErrPasswordTooLong
}
p, err := newFromPassword(password, cost)
if err != nil {
return nil, err
}
return p.Hash(), nil
}
// CompareHashAndPassword compares a bcrypt hashed password with its possible
// plaintext equivalent. Returns nil on success, or an error on failure.
func CompareHashAndPassword(hashedPassword, password []byte) error {
p, err := newFromHash(hashedPassword)
if err != nil {
return err
}
otherHash, err := bcrypt(password, p.cost, p.salt)
if err != nil {
return err
}
otherP := &hashed{otherHash, p.salt, p.cost, p.major, p.minor}
if subtle.ConstantTimeCompare(p.Hash(), otherP.Hash()) == 1 {
return nil
}
return ErrMismatchedHashAndPassword
}
// Cost returns the hashing cost used to create the given hashed
// password. When, in the future, the hashing cost of a password system needs
// to be increased in order to adjust for greater computational power, this
// function allows one to establish which passwords need to be updated.
func Cost(hashedPassword []byte) (int, error) {
p, err := newFromHash(hashedPassword)
if err != nil {
return 0, err
}
return p.cost, nil
}
func newFromPassword(password []byte, cost int) (*hashed, error) {
if cost < MinCost {
cost = DefaultCost
}
p := new(hashed)
p.major = majorVersion
p.minor = minorVersion
err := checkCost(cost)
if err != nil {
return nil, err
}
p.cost = cost
unencodedSalt := make([]byte, maxSaltSize)
_, err = io.ReadFull(rand.Reader, unencodedSalt)
if err != nil {
return nil, err
}
p.salt = base64Encode(unencodedSalt)
hash, err := bcrypt(password, p.cost, p.salt)
if err != nil {
return nil, err
}
p.hash = hash
return p, err
}
func newFromHash(hashedSecret []byte) (*hashed, error) {
if len(hashedSecret) < minHashSize {
return nil, ErrHashTooShort
}
p := new(hashed)
n, err := p.decodeVersion(hashedSecret)
if err != nil {
return nil, err
}
hashedSecret = hashedSecret[n:]
n, err = p.decodeCost(hashedSecret)
if err != nil {
return nil, err
}
hashedSecret = hashedSecret[n:]
// The "+2" is here because we'll have to append at most 2 '=' to the salt
// when base64 decoding it in expensiveBlowfishSetup().
p.salt = make([]byte, encodedSaltSize, encodedSaltSize+2)
copy(p.salt, hashedSecret[:encodedSaltSize])
hashedSecret = hashedSecret[encodedSaltSize:]
p.hash = make([]byte, len(hashedSecret))
copy(p.hash, hashedSecret)
return p, nil
}
func bcrypt(password []byte, cost int, salt []byte) ([]byte, error) {
cipherData := make([]byte, len(magicCipherData))
copy(cipherData, magicCipherData)
c, err := expensiveBlowfishSetup(password, uint32(cost), salt)
if err != nil {
return nil, err
}
for i := 0; i < 24; i += 8 {
for j := 0; j < 64; j++ {
c.Encrypt(cipherData[i:i+8], cipherData[i:i+8])
}
}
// Bug compatibility with C bcrypt implementations. We only encode 23 of
// the 24 bytes encrypted.
hsh := base64Encode(cipherData[:maxCryptedHashSize])
return hsh, nil
}
func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cipher, error) {
csalt, err := base64Decode(salt)
if err != nil {
return nil, err
}
// Bug compatibility with C bcrypt implementations. They use the trailing
// NULL in the key string during expansion.
// We copy the key to prevent changing the underlying array.
ckey := append(key[:len(key):len(key)], 0)
c, err := blowfish.NewSaltedCipher(ckey, csalt)
if err != nil {
return nil, err
}
var i, rounds uint64
rounds = 1 << cost
for i = 0; i < rounds; i++ {
blowfish.ExpandKey(ckey, c)
blowfish.ExpandKey(csalt, c)
}
return c, nil
}
func (p *hashed) Hash() []byte {
arr := make([]byte, 60)
arr[0] = '$'
arr[1] = p.major
n := 2
if p.minor != 0 {
arr[2] = p.minor
n = 3
}
arr[n] = '$'
n++
copy(arr[n:], []byte(fmt.Sprintf("%02d", p.cost)))
n += 2
arr[n] = '$'
n++
copy(arr[n:], p.salt)
n += encodedSaltSize
copy(arr[n:], p.hash)
n += encodedHashSize
return arr[:n]
}
func (p *hashed) decodeVersion(sbytes []byte) (int, error) {
if sbytes[0] != '$' {
return -1, InvalidHashPrefixError(sbytes[0])
}
if sbytes[1] > majorVersion {
return -1, HashVersionTooNewError(sbytes[1])
}
p.major = sbytes[1]
n := 3
if sbytes[2] != '$' {
p.minor = sbytes[2]
n++
}
return n, nil
}
// sbytes should begin where decodeVersion left off.
func (p *hashed) decodeCost(sbytes []byte) (int, error) {
cost, err := strconv.Atoi(string(sbytes[0:2]))
if err != nil {
return -1, err
}
err = checkCost(cost)
if err != nil {
return -1, err
}
p.cost = cost
return 3, nil
}
func (p *hashed) String() string {
return fmt.Sprintf("&{hash: %#v, salt: %#v, cost: %d, major: %c, minor: %c}", string(p.hash), p.salt, p.cost, p.major, p.minor)
}
func checkCost(cost int) error {
if cost < MinCost || cost > MaxCost {
return InvalidCostError(cost)
}
return nil
}
// 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.
// Package blake2b implements the BLAKE2b hash algorithm defined by RFC 7693
// and the extendable output function (XOF) BLAKE2Xb.
//
// BLAKE2b is optimized for 64-bit platforms—including NEON-enabled ARMs—and
// produces digests of any size between 1 and 64 bytes.
// For a detailed specification of BLAKE2b see https://blake2.net/blake2.pdf
// and for BLAKE2Xb see https://blake2.net/blake2x.pdf
//
// If you aren't sure which function you need, use BLAKE2b (Sum512 or New512).
// If you need a secret-key MAC (message authentication code), use the New512
// function with a non-nil key.
//
// BLAKE2X is a construction to compute hash values larger than 64 bytes. It
// can produce hash values between 0 and 4 GiB.
package blake2b
import (
"encoding/binary"
"errors"
"hash"
)
const (
// The blocksize of BLAKE2b in bytes.
BlockSize = 128
// The hash size of BLAKE2b-512 in bytes.
Size = 64
// The hash size of BLAKE2b-384 in bytes.
Size384 = 48
// The hash size of BLAKE2b-256 in bytes.
Size256 = 32
)
var (
useAVX2 bool
useAVX bool
useSSE4 bool
)
var (
errKeySize = errors.New("blake2b: invalid key size")
errHashSize = errors.New("blake2b: invalid hash size")
)
var iv = [8]uint64{
0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
}
// Sum512 returns the BLAKE2b-512 checksum of the data.
func Sum512(data []byte) [Size]byte {
var sum [Size]byte
checkSum(&sum, Size, data)
return sum
}
// Sum384 returns the BLAKE2b-384 checksum of the data.
func Sum384(data []byte) [Size384]byte {
var sum [Size]byte
var sum384 [Size384]byte
checkSum(&sum, Size384, data)
copy(sum384[:], sum[:Size384])
return sum384
}
// Sum256 returns the BLAKE2b-256 checksum of the data.
func Sum256(data []byte) [Size256]byte {
var sum [Size]byte
var sum256 [Size256]byte
checkSum(&sum, Size256, data)
copy(sum256[:], sum[:Size256])
return sum256
}
// New512 returns a new hash.Hash computing the BLAKE2b-512 checksum. A non-nil
// key turns the hash into a MAC. The key must be between zero and 64 bytes long.
func New512(key []byte) (hash.Hash, error) { return newDigest(Size, key) }
// New384 returns a new hash.Hash computing the BLAKE2b-384 checksum. A non-nil
// key turns the hash into a MAC. The key must be between zero and 64 bytes long.
func New384(key []byte) (hash.Hash, error) { return newDigest(Size384, key) }
// New256 returns a new hash.Hash computing the BLAKE2b-256 checksum. A non-nil
// key turns the hash into a MAC. The key must be between zero and 64 bytes long.
func New256(key []byte) (hash.Hash, error) { return newDigest(Size256, key) }
// New returns a new hash.Hash computing the BLAKE2b checksum with a custom length.
// A non-nil key turns the hash into a MAC. The key must be between zero and 64 bytes long.
// The hash size can be a value between 1 and 64 but it is highly recommended to use
// values equal or greater than:
// - 32 if BLAKE2b is used as a hash function (The key is zero bytes long).
// - 16 if BLAKE2b is used as a MAC function (The key is at least 16 bytes long).
// When the key is nil, the returned hash.Hash implements BinaryMarshaler
// and BinaryUnmarshaler for state (de)serialization as documented by hash.Hash.
func New(size int, key []byte) (hash.Hash, error) { return newDigest(size, key) }
func newDigest(hashSize int, key []byte) (*digest, error) {
if hashSize < 1 || hashSize > Size {
return nil, errHashSize
}
if len(key) > Size {
return nil, errKeySize
}
d := &digest{
size: hashSize,
keyLen: len(key),
}
copy(d.key[:], key)
d.Reset()
return d, nil
}
func checkSum(sum *[Size]byte, hashSize int, data []byte) {
h := iv
h[0] ^= uint64(hashSize) | (1 << 16) | (1 << 24)
var c [2]uint64
if length := len(data); length > BlockSize {
n := length &^ (BlockSize - 1)
if length == n {
n -= BlockSize
}
hashBlocks(&h, &c, 0, data[:n])
data = data[n:]
}
var block [BlockSize]byte
offset := copy(block[:], data)
remaining := uint64(BlockSize - offset)
if c[0] < remaining {
c[1]--
}
c[0] -= remaining
hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:])
for i, v := range h[:(hashSize+7)/8] {
binary.LittleEndian.PutUint64(sum[8*i:], v)
}
}
type digest struct {
h [8]uint64
c [2]uint64
size int
block [BlockSize]byte
offset int
key [BlockSize]byte
keyLen int
}
const (
magic = "b2b"
marshaledSize = len(magic) + 8*8 + 2*8 + 1 + BlockSize + 1
)
func (d *digest) MarshalBinary() ([]byte, error) {
if d.keyLen != 0 {
return nil, errors.New("crypto/blake2b: cannot marshal MACs")
}
b := make([]byte, 0, marshaledSize)
b = append(b, magic...)
for i := 0; i < 8; i++ {
b = appendUint64(b, d.h[i])
}
b = appendUint64(b, d.c[0])
b = appendUint64(b, d.c[1])
// Maximum value for size is 64
b = append(b, byte(d.size))
b = append(b, d.block[:]...)
b = append(b, byte(d.offset))
return b, nil
}
func (d *digest) UnmarshalBinary(b []byte) error {
if len(b) < len(magic) || string(b[:len(magic)]) != magic {
return errors.New("crypto/blake2b: invalid hash state identifier")
}
if len(b) != marshaledSize {
return errors.New("crypto/blake2b: invalid hash state size")
}
b = b[len(magic):]
for i := 0; i < 8; i++ {
b, d.h[i] = consumeUint64(b)
}
b, d.c[0] = consumeUint64(b)
b, d.c[1] = consumeUint64(b)
d.size = int(b[0])
b = b[1:]
copy(d.block[:], b[:BlockSize])
b = b[BlockSize:]
d.offset = int(b[0])
return nil
}
func (d *digest) BlockSize() int { return BlockSize }
func (d *digest) Size() int { return d.size }
func (d *digest) Reset() {
d.h = iv
d.h[0] ^= uint64(d.size) | (uint64(d.keyLen) << 8) | (1 << 16) | (1 << 24)
d.offset, d.c[0], d.c[1] = 0, 0, 0
if d.keyLen > 0 {
d.block = d.key
d.offset = BlockSize
}
}
func (d *digest) Write(p []byte) (n int, err error) {
n = len(p)
if d.offset > 0 {
remaining := BlockSize - d.offset
if n <= remaining {
d.offset += copy(d.block[d.offset:], p)
return
}
copy(d.block[d.offset:], p[:remaining])
hashBlocks(&d.h, &d.c, 0, d.block[:])
d.offset = 0
p = p[remaining:]
}
if length := len(p); length > BlockSize {
nn := length &^ (BlockSize - 1)
if length == nn {
nn -= BlockSize
}
hashBlocks(&d.h, &d.c, 0, p[:nn])
p = p[nn:]
}
if len(p) > 0 {
d.offset += copy(d.block[:], p)
}
return
}
func (d *digest) Sum(sum []byte) []byte {
var hash [Size]byte
d.finalize(&hash)
return append(sum, hash[:d.size]...)
}
func (d *digest) finalize(hash *[Size]byte) {
var block [BlockSize]byte
copy(block[:], d.block[:d.offset])
remaining := uint64(BlockSize - d.offset)
c := d.c
if c[0] < remaining {
c[1]--
}
c[0] -= remaining
h := d.h
hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:])
for i, v := range h {
binary.LittleEndian.PutUint64(hash[8*i:], v)
}
}
func appendUint64(b []byte, x uint64) []byte {
var a [8]byte
binary.BigEndian.PutUint64(a[:], x)
return append(b, a[:]...)
}
func appendUint32(b []byte, x uint32) []byte {
var a [4]byte
binary.BigEndian.PutUint32(a[:], x)
return append(b, a[:]...)
}
func consumeUint64(b []byte) ([]byte, uint64) {
x := binary.BigEndian.Uint64(b)
return b[8:], x
}
func consumeUint32(b []byte) ([]byte, uint32) {
x := binary.BigEndian.Uint32(b)
return b[4:], x
}
// 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.
//go:build amd64 && gc && !purego
package blake2b
import "golang.org/x/sys/cpu"
func init() {
useAVX2 = cpu.X86.HasAVX2
useAVX = cpu.X86.HasAVX
useSSE4 = cpu.X86.HasSSE41
}
//go:noescape
func hashBlocksAVX2(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
//go:noescape
func hashBlocksAVX(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
//go:noescape
func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) {
switch {
case useAVX2:
hashBlocksAVX2(h, c, flag, blocks)
case useAVX:
hashBlocksAVX(h, c, flag, blocks)
case useSSE4:
hashBlocksSSE4(h, c, flag, blocks)
default:
hashBlocksGeneric(h, c, flag, blocks)
}
}
// 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.
package blake2b
import (
"encoding/binary"
"math/bits"
)
// the precomputed values for BLAKE2b
// there are 12 16-byte arrays - one for each round
// the entries are calculated from the sigma constants.
var precomputed = [12][16]byte{
{0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15},
{14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3},
{11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4},
{7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8},
{9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13},
{2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9},
{12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11},
{13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10},
{6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5},
{10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0},
{0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15}, // equal to the first
{14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3}, // equal to the second
}
func hashBlocksGeneric(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) {
var m [16]uint64
c0, c1 := c[0], c[1]
for i := 0; i < len(blocks); {
c0 += BlockSize
if c0 < BlockSize {
c1++
}
v0, v1, v2, v3, v4, v5, v6, v7 := h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7]
v8, v9, v10, v11, v12, v13, v14, v15 := iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7]
v12 ^= c0
v13 ^= c1
v14 ^= flag
for j := range m {
m[j] = binary.LittleEndian.Uint64(blocks[i:])
i += 8
}
for j := range precomputed {
s := &(precomputed[j])
v0 += m[s[0]]
v0 += v4
v12 ^= v0
v12 = bits.RotateLeft64(v12, -32)
v8 += v12
v4 ^= v8
v4 = bits.RotateLeft64(v4, -24)
v1 += m[s[1]]
v1 += v5
v13 ^= v1
v13 = bits.RotateLeft64(v13, -32)
v9 += v13
v5 ^= v9
v5 = bits.RotateLeft64(v5, -24)
v2 += m[s[2]]
v2 += v6
v14 ^= v2
v14 = bits.RotateLeft64(v14, -32)
v10 += v14
v6 ^= v10
v6 = bits.RotateLeft64(v6, -24)
v3 += m[s[3]]
v3 += v7
v15 ^= v3
v15 = bits.RotateLeft64(v15, -32)
v11 += v15
v7 ^= v11
v7 = bits.RotateLeft64(v7, -24)
v0 += m[s[4]]
v0 += v4
v12 ^= v0
v12 = bits.RotateLeft64(v12, -16)
v8 += v12
v4 ^= v8
v4 = bits.RotateLeft64(v4, -63)
v1 += m[s[5]]
v1 += v5
v13 ^= v1
v13 = bits.RotateLeft64(v13, -16)
v9 += v13
v5 ^= v9
v5 = bits.RotateLeft64(v5, -63)
v2 += m[s[6]]
v2 += v6
v14 ^= v2
v14 = bits.RotateLeft64(v14, -16)
v10 += v14
v6 ^= v10
v6 = bits.RotateLeft64(v6, -63)
v3 += m[s[7]]
v3 += v7
v15 ^= v3
v15 = bits.RotateLeft64(v15, -16)
v11 += v15
v7 ^= v11
v7 = bits.RotateLeft64(v7, -63)
v0 += m[s[8]]
v0 += v5
v15 ^= v0
v15 = bits.RotateLeft64(v15, -32)
v10 += v15
v5 ^= v10
v5 = bits.RotateLeft64(v5, -24)
v1 += m[s[9]]
v1 += v6
v12 ^= v1
v12 = bits.RotateLeft64(v12, -32)
v11 += v12
v6 ^= v11
v6 = bits.RotateLeft64(v6, -24)
v2 += m[s[10]]
v2 += v7
v13 ^= v2
v13 = bits.RotateLeft64(v13, -32)
v8 += v13
v7 ^= v8
v7 = bits.RotateLeft64(v7, -24)
v3 += m[s[11]]
v3 += v4
v14 ^= v3
v14 = bits.RotateLeft64(v14, -32)
v9 += v14
v4 ^= v9
v4 = bits.RotateLeft64(v4, -24)
v0 += m[s[12]]
v0 += v5
v15 ^= v0
v15 = bits.RotateLeft64(v15, -16)
v10 += v15
v5 ^= v10
v5 = bits.RotateLeft64(v5, -63)
v1 += m[s[13]]
v1 += v6
v12 ^= v1
v12 = bits.RotateLeft64(v12, -16)
v11 += v12
v6 ^= v11
v6 = bits.RotateLeft64(v6, -63)
v2 += m[s[14]]
v2 += v7
v13 ^= v2
v13 = bits.RotateLeft64(v13, -16)
v8 += v13
v7 ^= v8
v7 = bits.RotateLeft64(v7, -63)
v3 += m[s[15]]
v3 += v4
v14 ^= v3
v14 = bits.RotateLeft64(v14, -16)
v9 += v14
v4 ^= v9
v4 = bits.RotateLeft64(v4, -63)
}
h[0] ^= v0 ^ v8
h[1] ^= v1 ^ v9
h[2] ^= v2 ^ v10
h[3] ^= v3 ^ v11
h[4] ^= v4 ^ v12
h[5] ^= v5 ^ v13
h[6] ^= v6 ^ v14
h[7] ^= v7 ^ v15
}
c[0], c[1] = c0, c1
}
// 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 blake2b
import (
"encoding/binary"
"errors"
"io"
)
// XOF defines the interface to hash functions that
// support arbitrary-length output.
//
// New callers should prefer the standard library [hash.XOF].
type XOF interface {
// Write absorbs more data into the hash's state. It panics if called
// after Read.
io.Writer
// Read reads more output from the hash. It returns io.EOF if the limit
// has been reached.
io.Reader
// Clone returns a copy of the XOF in its current state.
Clone() XOF
// Reset resets the XOF to its initial state.
Reset()
}
// OutputLengthUnknown can be used as the size argument to NewXOF to indicate
// the length of the output is not known in advance.
const OutputLengthUnknown = 0
// magicUnknownOutputLength is a magic value for the output size that indicates
// an unknown number of output bytes.
const magicUnknownOutputLength = (1 << 32) - 1
// maxOutputLength is the absolute maximum number of bytes to produce when the
// number of output bytes is unknown.
const maxOutputLength = (1 << 32) * 64
// NewXOF creates a new variable-output-length hash. The hash either produce a
// known number of bytes (1 <= size < 2**32-1), or an unknown number of bytes
// (size == OutputLengthUnknown). In the latter case, an absolute limit of
// 256GiB applies.
//
// A non-nil key turns the hash into a MAC. The key must between
// zero and 32 bytes long.
//
// The result can be safely interface-upgraded to [hash.XOF].
func NewXOF(size uint32, key []byte) (XOF, error) {
if len(key) > Size {
return nil, errKeySize
}
if size == magicUnknownOutputLength {
// 2^32-1 indicates an unknown number of bytes and thus isn't a
// valid length.
return nil, errors.New("blake2b: XOF length too large")
}
if size == OutputLengthUnknown {
size = magicUnknownOutputLength
}
x := &xof{
d: digest{
size: Size,
keyLen: len(key),
},
length: size,
}
copy(x.d.key[:], key)
x.Reset()
return x, nil
}
type xof struct {
d digest
length uint32
remaining uint64
cfg, root, block [Size]byte
offset int
nodeOffset uint32
readMode bool
}
func (x *xof) Write(p []byte) (n int, err error) {
if x.readMode {
panic("blake2b: write to XOF after read")
}
return x.d.Write(p)
}
func (x *xof) Clone() XOF {
clone := *x
return &clone
}
func (x *xof) BlockSize() int {
return x.d.BlockSize()
}
func (x *xof) Reset() {
x.cfg[0] = byte(Size)
binary.LittleEndian.PutUint32(x.cfg[4:], uint32(Size)) // leaf length
binary.LittleEndian.PutUint32(x.cfg[12:], x.length) // XOF length
x.cfg[17] = byte(Size) // inner hash size
x.d.Reset()
x.d.h[1] ^= uint64(x.length) << 32
x.remaining = uint64(x.length)
if x.remaining == magicUnknownOutputLength {
x.remaining = maxOutputLength
}
x.offset, x.nodeOffset = 0, 0
x.readMode = false
}
func (x *xof) Read(p []byte) (n int, err error) {
if !x.readMode {
x.d.finalize(&x.root)
x.readMode = true
}
if x.remaining == 0 {
return 0, io.EOF
}
n = len(p)
if uint64(n) > x.remaining {
n = int(x.remaining)
p = p[:n]
}
if x.offset > 0 {
blockRemaining := Size - x.offset
if n < blockRemaining {
x.offset += copy(p, x.block[x.offset:])
x.remaining -= uint64(n)
return
}
copy(p, x.block[x.offset:])
p = p[blockRemaining:]
x.offset = 0
x.remaining -= uint64(blockRemaining)
}
for len(p) >= Size {
binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)
x.nodeOffset++
x.d.initConfig(&x.cfg)
x.d.Write(x.root[:])
x.d.finalize(&x.block)
copy(p, x.block[:])
p = p[Size:]
x.remaining -= uint64(Size)
}
if todo := len(p); todo > 0 {
if x.remaining < uint64(Size) {
x.cfg[0] = byte(x.remaining)
}
binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)
x.nodeOffset++
x.d.initConfig(&x.cfg)
x.d.Write(x.root[:])
x.d.finalize(&x.block)
x.offset = copy(p, x.block[:todo])
x.remaining -= uint64(todo)
}
return
}
func (d *digest) initConfig(cfg *[Size]byte) {
d.offset, d.c[0], d.c[1] = 0, 0, 0
for i := range d.h {
d.h[i] = iv[i] ^ binary.LittleEndian.Uint64(cfg[i*8:])
}
}
// 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 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)
}
// 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.
// Package blake2s implements the BLAKE2s hash algorithm defined by RFC 7693
// and the extendable output function (XOF) BLAKE2Xs.
//
// BLAKE2s is optimized for 8- to 32-bit platforms and produces digests of any
// size between 1 and 32 bytes.
// For a detailed specification of BLAKE2s see https://blake2.net/blake2.pdf
// and for BLAKE2Xs see https://blake2.net/blake2x.pdf
//
// If you aren't sure which function you need, use BLAKE2s (Sum256 or New256).
// If you need a secret-key MAC (message authentication code), use the New256
// function with a non-nil key.
//
// BLAKE2X is a construction to compute hash values larger than 32 bytes. It
// can produce hash values between 0 and 65535 bytes.
package blake2s
import (
"crypto"
"encoding/binary"
"errors"
"hash"
)
const (
// The blocksize of BLAKE2s in bytes.
BlockSize = 64
// The hash size of BLAKE2s-256 in bytes.
Size = 32
// The hash size of BLAKE2s-128 in bytes.
Size128 = 16
)
var errKeySize = errors.New("blake2s: invalid key size")
var iv = [8]uint32{
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
}
// Sum256 returns the BLAKE2s-256 checksum of the data.
func Sum256(data []byte) [Size]byte {
var sum [Size]byte
checkSum(&sum, Size, data)
return sum
}
// New256 returns a new hash.Hash computing the BLAKE2s-256 checksum. A non-nil
// key turns the hash into a MAC. The key must between zero and 32 bytes long.
// When the key is nil, the returned hash.Hash implements BinaryMarshaler
// and BinaryUnmarshaler for state (de)serialization as documented by hash.Hash.
func New256(key []byte) (hash.Hash, error) { return newDigest(Size, key) }
func init() {
crypto.RegisterHash(crypto.BLAKE2s_256, func() hash.Hash {
h, _ := New256(nil)
return h
})
}
// New128 returns a new hash.Hash computing the BLAKE2s-128 checksum given a
// non-empty key. Note that a 128-bit digest is too small to be secure as a
// cryptographic hash and should only be used as a MAC, thus the key argument
// is not optional.
func New128(key []byte) (hash.Hash, error) {
if len(key) == 0 {
return nil, errors.New("blake2s: a key is required for a 128-bit hash")
}
return newDigest(Size128, key)
}
func newDigest(hashSize int, key []byte) (*digest, error) {
if len(key) > Size {
return nil, errKeySize
}
d := &digest{
size: hashSize,
keyLen: len(key),
}
copy(d.key[:], key)
d.Reset()
return d, nil
}
func checkSum(sum *[Size]byte, hashSize int, data []byte) {
var (
h [8]uint32
c [2]uint32
)
h = iv
h[0] ^= uint32(hashSize) | (1 << 16) | (1 << 24)
if length := len(data); length > BlockSize {
n := length &^ (BlockSize - 1)
if length == n {
n -= BlockSize
}
hashBlocks(&h, &c, 0, data[:n])
data = data[n:]
}
var block [BlockSize]byte
offset := copy(block[:], data)
remaining := uint32(BlockSize - offset)
if c[0] < remaining {
c[1]--
}
c[0] -= remaining
hashBlocks(&h, &c, 0xFFFFFFFF, block[:])
for i, v := range h {
binary.LittleEndian.PutUint32(sum[4*i:], v)
}
}
type digest struct {
h [8]uint32
c [2]uint32
size int
block [BlockSize]byte
offset int
key [BlockSize]byte
keyLen int
}
const (
magic = "b2s"
marshaledSize = len(magic) + 8*4 + 2*4 + 1 + BlockSize + 1
)
func (d *digest) MarshalBinary() ([]byte, error) {
if d.keyLen != 0 {
return nil, errors.New("crypto/blake2s: cannot marshal MACs")
}
b := make([]byte, 0, marshaledSize)
b = append(b, magic...)
for i := 0; i < 8; i++ {
b = appendUint32(b, d.h[i])
}
b = appendUint32(b, d.c[0])
b = appendUint32(b, d.c[1])
// Maximum value for size is 32
b = append(b, byte(d.size))
b = append(b, d.block[:]...)
b = append(b, byte(d.offset))
return b, nil
}
func (d *digest) UnmarshalBinary(b []byte) error {
if len(b) < len(magic) || string(b[:len(magic)]) != magic {
return errors.New("crypto/blake2s: invalid hash state identifier")
}
if len(b) != marshaledSize {
return errors.New("crypto/blake2s: invalid hash state size")
}
b = b[len(magic):]
for i := 0; i < 8; i++ {
b, d.h[i] = consumeUint32(b)
}
b, d.c[0] = consumeUint32(b)
b, d.c[1] = consumeUint32(b)
d.size = int(b[0])
b = b[1:]
copy(d.block[:], b[:BlockSize])
b = b[BlockSize:]
d.offset = int(b[0])
return nil
}
func (d *digest) BlockSize() int { return BlockSize }
func (d *digest) Size() int { return d.size }
func (d *digest) Reset() {
d.h = iv
d.h[0] ^= uint32(d.size) | (uint32(d.keyLen) << 8) | (1 << 16) | (1 << 24)
d.offset, d.c[0], d.c[1] = 0, 0, 0
if d.keyLen > 0 {
d.block = d.key
d.offset = BlockSize
}
}
func (d *digest) Write(p []byte) (n int, err error) {
n = len(p)
if d.offset > 0 {
remaining := BlockSize - d.offset
if n <= remaining {
d.offset += copy(d.block[d.offset:], p)
return
}
copy(d.block[d.offset:], p[:remaining])
hashBlocks(&d.h, &d.c, 0, d.block[:])
d.offset = 0
p = p[remaining:]
}
if length := len(p); length > BlockSize {
nn := length &^ (BlockSize - 1)
if length == nn {
nn -= BlockSize
}
hashBlocks(&d.h, &d.c, 0, p[:nn])
p = p[nn:]
}
d.offset += copy(d.block[:], p)
return
}
func (d *digest) Sum(sum []byte) []byte {
var hash [Size]byte
d.finalize(&hash)
return append(sum, hash[:d.size]...)
}
func (d *digest) finalize(hash *[Size]byte) {
var block [BlockSize]byte
h := d.h
c := d.c
copy(block[:], d.block[:d.offset])
remaining := uint32(BlockSize - d.offset)
if c[0] < remaining {
c[1]--
}
c[0] -= remaining
hashBlocks(&h, &c, 0xFFFFFFFF, block[:])
for i, v := range h {
binary.LittleEndian.PutUint32(hash[4*i:], v)
}
}
func appendUint32(b []byte, x uint32) []byte {
var a [4]byte
binary.BigEndian.PutUint32(a[:], x)
return append(b, a[:]...)
}
func consumeUint32(b []byte) ([]byte, uint32) {
x := binary.BigEndian.Uint32(b)
return b[4:], x
}
// 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.
//go:build amd64 && gc && !purego
package blake2s
import "golang.org/x/sys/cpu"
var (
useSSE4 = cpu.X86.HasSSE41
useSSSE3 = cpu.X86.HasSSSE3
useSSE2 = cpu.X86.HasSSE2
)
//go:noescape
func hashBlocksSSE2(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
//go:noescape
func hashBlocksSSSE3(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
//go:noescape
func hashBlocksSSE4(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
func hashBlocks(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) {
switch {
case useSSE4:
hashBlocksSSE4(h, c, flag, blocks)
case useSSSE3:
hashBlocksSSSE3(h, c, flag, blocks)
case useSSE2:
hashBlocksSSE2(h, c, flag, blocks)
default:
hashBlocksGeneric(h, c, flag, blocks)
}
}
// 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.
package blake2s
import (
"math/bits"
)
// the precomputed values for BLAKE2s
// there are 10 16-byte arrays - one for each round
// the entries are calculated from the sigma constants.
var precomputed = [10][16]byte{
{0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15},
{14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3},
{11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4},
{7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8},
{9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13},
{2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9},
{12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11},
{13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10},
{6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5},
{10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0},
}
func hashBlocksGeneric(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) {
var m [16]uint32
c0, c1 := c[0], c[1]
for i := 0; i < len(blocks); {
c0 += BlockSize
if c0 < BlockSize {
c1++
}
v0, v1, v2, v3, v4, v5, v6, v7 := h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7]
v8, v9, v10, v11, v12, v13, v14, v15 := iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7]
v12 ^= c0
v13 ^= c1
v14 ^= flag
for j := range m {
m[j] = uint32(blocks[i]) | uint32(blocks[i+1])<<8 | uint32(blocks[i+2])<<16 | uint32(blocks[i+3])<<24
i += 4
}
for k := range precomputed {
s := &(precomputed[k])
v0 += m[s[0]]
v0 += v4
v12 ^= v0
v12 = bits.RotateLeft32(v12, -16)
v8 += v12
v4 ^= v8
v4 = bits.RotateLeft32(v4, -12)
v1 += m[s[1]]
v1 += v5
v13 ^= v1
v13 = bits.RotateLeft32(v13, -16)
v9 += v13
v5 ^= v9
v5 = bits.RotateLeft32(v5, -12)
v2 += m[s[2]]
v2 += v6
v14 ^= v2
v14 = bits.RotateLeft32(v14, -16)
v10 += v14
v6 ^= v10
v6 = bits.RotateLeft32(v6, -12)
v3 += m[s[3]]
v3 += v7
v15 ^= v3
v15 = bits.RotateLeft32(v15, -16)
v11 += v15
v7 ^= v11
v7 = bits.RotateLeft32(v7, -12)
v0 += m[s[4]]
v0 += v4
v12 ^= v0
v12 = bits.RotateLeft32(v12, -8)
v8 += v12
v4 ^= v8
v4 = bits.RotateLeft32(v4, -7)
v1 += m[s[5]]
v1 += v5
v13 ^= v1
v13 = bits.RotateLeft32(v13, -8)
v9 += v13
v5 ^= v9
v5 = bits.RotateLeft32(v5, -7)
v2 += m[s[6]]
v2 += v6
v14 ^= v2
v14 = bits.RotateLeft32(v14, -8)
v10 += v14
v6 ^= v10
v6 = bits.RotateLeft32(v6, -7)
v3 += m[s[7]]
v3 += v7
v15 ^= v3
v15 = bits.RotateLeft32(v15, -8)
v11 += v15
v7 ^= v11
v7 = bits.RotateLeft32(v7, -7)
v0 += m[s[8]]
v0 += v5
v15 ^= v0
v15 = bits.RotateLeft32(v15, -16)
v10 += v15
v5 ^= v10
v5 = bits.RotateLeft32(v5, -12)
v1 += m[s[9]]
v1 += v6
v12 ^= v1
v12 = bits.RotateLeft32(v12, -16)
v11 += v12
v6 ^= v11
v6 = bits.RotateLeft32(v6, -12)
v2 += m[s[10]]
v2 += v7
v13 ^= v2
v13 = bits.RotateLeft32(v13, -16)
v8 += v13
v7 ^= v8
v7 = bits.RotateLeft32(v7, -12)
v3 += m[s[11]]
v3 += v4
v14 ^= v3
v14 = bits.RotateLeft32(v14, -16)
v9 += v14
v4 ^= v9
v4 = bits.RotateLeft32(v4, -12)
v0 += m[s[12]]
v0 += v5
v15 ^= v0
v15 = bits.RotateLeft32(v15, -8)
v10 += v15
v5 ^= v10
v5 = bits.RotateLeft32(v5, -7)
v1 += m[s[13]]
v1 += v6
v12 ^= v1
v12 = bits.RotateLeft32(v12, -8)
v11 += v12
v6 ^= v11
v6 = bits.RotateLeft32(v6, -7)
v2 += m[s[14]]
v2 += v7
v13 ^= v2
v13 = bits.RotateLeft32(v13, -8)
v8 += v13
v7 ^= v8
v7 = bits.RotateLeft32(v7, -7)
v3 += m[s[15]]
v3 += v4
v14 ^= v3
v14 = bits.RotateLeft32(v14, -8)
v9 += v14
v4 ^= v9
v4 = bits.RotateLeft32(v4, -7)
}
h[0] ^= v0 ^ v8
h[1] ^= v1 ^ v9
h[2] ^= v2 ^ v10
h[3] ^= v3 ^ v11
h[4] ^= v4 ^ v12
h[5] ^= v5 ^ v13
h[6] ^= v6 ^ v14
h[7] ^= v7 ^ v15
}
c[0], c[1] = c0, c1
}
// 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 blake2s
import (
"encoding/binary"
"errors"
"io"
)
// XOF defines the interface to hash functions that
// support arbitrary-length output.
type XOF interface {
// Write absorbs more data into the hash's state. It panics if called
// after Read.
io.Writer
// Read reads more output from the hash. It returns io.EOF if the limit
// has been reached.
io.Reader
// Clone returns a copy of the XOF in its current state.
Clone() XOF
// Reset resets the XOF to its initial state.
Reset()
}
// OutputLengthUnknown can be used as the size argument to NewXOF to indicate
// the length of the output is not known in advance.
const OutputLengthUnknown = 0
// magicUnknownOutputLength is a magic value for the output size that indicates
// an unknown number of output bytes.
const magicUnknownOutputLength = 65535
// maxOutputLength is the absolute maximum number of bytes to produce when the
// number of output bytes is unknown.
const maxOutputLength = (1 << 32) * 32
// NewXOF creates a new variable-output-length hash. The hash either produce a
// known number of bytes (1 <= size < 65535), or an unknown number of bytes
// (size == OutputLengthUnknown). In the latter case, an absolute limit of
// 128GiB applies.
//
// A non-nil key turns the hash into a MAC. The key must between
// zero and 32 bytes long.
func NewXOF(size uint16, key []byte) (XOF, error) {
if len(key) > Size {
return nil, errKeySize
}
if size == magicUnknownOutputLength {
// 2^16-1 indicates an unknown number of bytes and thus isn't a
// valid length.
return nil, errors.New("blake2s: XOF length too large")
}
if size == OutputLengthUnknown {
size = magicUnknownOutputLength
}
x := &xof{
d: digest{
size: Size,
keyLen: len(key),
},
length: size,
}
copy(x.d.key[:], key)
x.Reset()
return x, nil
}
type xof struct {
d digest
length uint16
remaining uint64
cfg, root, block [Size]byte
offset int
nodeOffset uint32
readMode bool
}
func (x *xof) Write(p []byte) (n int, err error) {
if x.readMode {
panic("blake2s: write to XOF after read")
}
return x.d.Write(p)
}
func (x *xof) Clone() XOF {
clone := *x
return &clone
}
func (x *xof) Reset() {
x.cfg[0] = byte(Size)
binary.LittleEndian.PutUint32(x.cfg[4:], uint32(Size)) // leaf length
binary.LittleEndian.PutUint16(x.cfg[12:], x.length) // XOF length
x.cfg[15] = byte(Size) // inner hash size
x.d.Reset()
x.d.h[3] ^= uint32(x.length)
x.remaining = uint64(x.length)
if x.remaining == magicUnknownOutputLength {
x.remaining = maxOutputLength
}
x.offset, x.nodeOffset = 0, 0
x.readMode = false
}
func (x *xof) Read(p []byte) (n int, err error) {
if !x.readMode {
x.d.finalize(&x.root)
x.readMode = true
}
if x.remaining == 0 {
return 0, io.EOF
}
n = len(p)
if uint64(n) > x.remaining {
n = int(x.remaining)
p = p[:n]
}
if x.offset > 0 {
blockRemaining := Size - x.offset
if n < blockRemaining {
x.offset += copy(p, x.block[x.offset:])
x.remaining -= uint64(n)
return
}
copy(p, x.block[x.offset:])
p = p[blockRemaining:]
x.offset = 0
x.remaining -= uint64(blockRemaining)
}
for len(p) >= Size {
binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)
x.nodeOffset++
x.d.initConfig(&x.cfg)
x.d.Write(x.root[:])
x.d.finalize(&x.block)
copy(p, x.block[:])
p = p[Size:]
x.remaining -= uint64(Size)
}
if todo := len(p); todo > 0 {
if x.remaining < uint64(Size) {
x.cfg[0] = byte(x.remaining)
}
binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)
x.nodeOffset++
x.d.initConfig(&x.cfg)
x.d.Write(x.root[:])
x.d.finalize(&x.block)
x.offset = copy(p, x.block[:todo])
x.remaining -= uint64(todo)
}
return
}
func (d *digest) initConfig(cfg *[Size]byte) {
d.offset, d.c[0], d.c[1] = 0, 0, 0
for i := range d.h {
d.h[i] = iv[i] ^ binary.LittleEndian.Uint32(cfg[i*4:])
}
}
// Copyright 2010 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 blowfish
// getNextWord returns the next big-endian uint32 value from the byte slice
// at the given position in a circular manner, updating the position.
func getNextWord(b []byte, pos *int) uint32 {
var w uint32
j := *pos
for i := 0; i < 4; i++ {
w = w<<8 | uint32(b[j])
j++
if j >= len(b) {
j = 0
}
}
*pos = j
return w
}
// ExpandKey performs a key expansion on the given *Cipher. Specifically, it
// performs the Blowfish algorithm's key schedule which sets up the *Cipher's
// pi and substitution tables for calls to Encrypt. This is used, primarily,
// by the bcrypt package to reuse the Blowfish key schedule during its
// set up. It's unlikely that you need to use this directly.
func ExpandKey(key []byte, c *Cipher) {
j := 0
for i := 0; i < 18; i++ {
// Using inlined getNextWord for performance.
var d uint32
for k := 0; k < 4; k++ {
d = d<<8 | uint32(key[j])
j++
if j >= len(key) {
j = 0
}
}
c.p[i] ^= d
}
var l, r uint32
for i := 0; i < 18; i += 2 {
l, r = encryptBlock(l, r, c)
c.p[i], c.p[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l, r = encryptBlock(l, r, c)
c.s0[i], c.s0[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l, r = encryptBlock(l, r, c)
c.s1[i], c.s1[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l, r = encryptBlock(l, r, c)
c.s2[i], c.s2[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l, r = encryptBlock(l, r, c)
c.s3[i], c.s3[i+1] = l, r
}
}
// This is similar to ExpandKey, but folds the salt during the key
// schedule. While ExpandKey is essentially expandKeyWithSalt with an all-zero
// salt passed in, reusing ExpandKey turns out to be a place of inefficiency
// and specializing it here is useful.
func expandKeyWithSalt(key []byte, salt []byte, c *Cipher) {
j := 0
for i := 0; i < 18; i++ {
c.p[i] ^= getNextWord(key, &j)
}
j = 0
var l, r uint32
for i := 0; i < 18; i += 2 {
l ^= getNextWord(salt, &j)
r ^= getNextWord(salt, &j)
l, r = encryptBlock(l, r, c)
c.p[i], c.p[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l ^= getNextWord(salt, &j)
r ^= getNextWord(salt, &j)
l, r = encryptBlock(l, r, c)
c.s0[i], c.s0[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l ^= getNextWord(salt, &j)
r ^= getNextWord(salt, &j)
l, r = encryptBlock(l, r, c)
c.s1[i], c.s1[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l ^= getNextWord(salt, &j)
r ^= getNextWord(salt, &j)
l, r = encryptBlock(l, r, c)
c.s2[i], c.s2[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l ^= getNextWord(salt, &j)
r ^= getNextWord(salt, &j)
l, r = encryptBlock(l, r, c)
c.s3[i], c.s3[i+1] = l, r
}
}
func encryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
xl, xr := l, r
xl ^= c.p[0]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[1]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[2]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[3]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[4]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[5]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[6]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[7]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[8]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[9]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[10]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[11]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[12]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[13]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[14]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[15]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[16]
xr ^= c.p[17]
return xr, xl
}
func decryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
xl, xr := l, r
xl ^= c.p[17]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[16]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[15]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[14]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[13]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[12]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[11]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[10]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[9]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[8]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[7]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[6]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[5]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[4]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[3]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[2]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[1]
xr ^= c.p[0]
return xr, xl
}
// Copyright 2010 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 blowfish implements Bruce Schneier's Blowfish encryption algorithm.
//
// Blowfish is a legacy cipher and its short block size makes it vulnerable to
// birthday bound attacks (see https://sweet32.info). It should only be used
// where compatibility with legacy systems, not security, is the goal.
//
// Deprecated: any new system should use AES (from crypto/aes, if necessary in
// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
// golang.org/x/crypto/chacha20poly1305).
package blowfish
// The code is a port of Bruce Schneier's C implementation.
// See https://www.schneier.com/blowfish.html.
import "strconv"
// The Blowfish block size in bytes.
const BlockSize = 8
// A Cipher is an instance of Blowfish encryption using a particular key.
type Cipher struct {
p [18]uint32
s0, s1, s2, s3 [256]uint32
}
type KeySizeError int
func (k KeySizeError) Error() string {
return "crypto/blowfish: invalid key size " + strconv.Itoa(int(k))
}
// NewCipher creates and returns a Cipher.
// The key argument should be the Blowfish key, from 1 to 56 bytes.
func NewCipher(key []byte) (*Cipher, error) {
var result Cipher
if k := len(key); k < 1 || k > 56 {
return nil, KeySizeError(k)
}
initCipher(&result)
ExpandKey(key, &result)
return &result, nil
}
// NewSaltedCipher creates a returns a Cipher that folds a salt into its key
// schedule. For most purposes, NewCipher, instead of NewSaltedCipher, is
// sufficient and desirable. For bcrypt compatibility, the key can be over 56
// bytes.
func NewSaltedCipher(key, salt []byte) (*Cipher, error) {
if len(salt) == 0 {
return NewCipher(key)
}
var result Cipher
if k := len(key); k < 1 {
return nil, KeySizeError(k)
}
initCipher(&result)
expandKeyWithSalt(key, salt, &result)
return &result, nil
}
// BlockSize returns the Blowfish block size, 8 bytes.
// It is necessary to satisfy the Block interface in the
// package "crypto/cipher".
func (c *Cipher) BlockSize() int { return BlockSize }
// Encrypt encrypts the 8-byte buffer src using the key k
// and stores the result in dst.
// Note that for amounts of data larger than a block,
// it is not safe to just call Encrypt on successive blocks;
// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
func (c *Cipher) Encrypt(dst, src []byte) {
l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
l, r = encryptBlock(l, r, c)
dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
}
// Decrypt decrypts the 8-byte buffer src using the key k
// and stores the result in dst.
func (c *Cipher) Decrypt(dst, src []byte) {
l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
l, r = decryptBlock(l, r, c)
dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
}
func initCipher(c *Cipher) {
copy(c.p[0:], p[0:])
copy(c.s0[0:], s0[0:])
copy(c.s1[0:], s1[0:])
copy(c.s2[0:], s2[0:])
copy(c.s3[0:], s3[0:])
}
// Copyright 2010 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 cast5 implements CAST5, as defined in RFC 2144.
//
// CAST5 is a legacy cipher and its short block size makes it vulnerable to
// birthday bound attacks (see https://sweet32.info). It should only be used
// where compatibility with legacy systems, not security, is the goal.
//
// Deprecated: any new system should use AES (from crypto/aes, if necessary in
// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
// golang.org/x/crypto/chacha20poly1305).
package cast5
import (
"errors"
"math/bits"
)
const BlockSize = 8
const KeySize = 16
type Cipher struct {
masking [16]uint32
rotate [16]uint8
}
func NewCipher(key []byte) (c *Cipher, err error) {
if len(key) != KeySize {
return nil, errors.New("CAST5: keys must be 16 bytes")
}
c = new(Cipher)
c.keySchedule(key)
return
}
func (c *Cipher) BlockSize() int {
return BlockSize
}
func (c *Cipher) Encrypt(dst, src []byte) {
l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
l, r = r, l^f1(r, c.masking[0], c.rotate[0])
l, r = r, l^f2(r, c.masking[1], c.rotate[1])
l, r = r, l^f3(r, c.masking[2], c.rotate[2])
l, r = r, l^f1(r, c.masking[3], c.rotate[3])
l, r = r, l^f2(r, c.masking[4], c.rotate[4])
l, r = r, l^f3(r, c.masking[5], c.rotate[5])
l, r = r, l^f1(r, c.masking[6], c.rotate[6])
l, r = r, l^f2(r, c.masking[7], c.rotate[7])
l, r = r, l^f3(r, c.masking[8], c.rotate[8])
l, r = r, l^f1(r, c.masking[9], c.rotate[9])
l, r = r, l^f2(r, c.masking[10], c.rotate[10])
l, r = r, l^f3(r, c.masking[11], c.rotate[11])
l, r = r, l^f1(r, c.masking[12], c.rotate[12])
l, r = r, l^f2(r, c.masking[13], c.rotate[13])
l, r = r, l^f3(r, c.masking[14], c.rotate[14])
l, r = r, l^f1(r, c.masking[15], c.rotate[15])
dst[0] = uint8(r >> 24)
dst[1] = uint8(r >> 16)
dst[2] = uint8(r >> 8)
dst[3] = uint8(r)
dst[4] = uint8(l >> 24)
dst[5] = uint8(l >> 16)
dst[6] = uint8(l >> 8)
dst[7] = uint8(l)
}
func (c *Cipher) Decrypt(dst, src []byte) {
l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
l, r = r, l^f1(r, c.masking[15], c.rotate[15])
l, r = r, l^f3(r, c.masking[14], c.rotate[14])
l, r = r, l^f2(r, c.masking[13], c.rotate[13])
l, r = r, l^f1(r, c.masking[12], c.rotate[12])
l, r = r, l^f3(r, c.masking[11], c.rotate[11])
l, r = r, l^f2(r, c.masking[10], c.rotate[10])
l, r = r, l^f1(r, c.masking[9], c.rotate[9])
l, r = r, l^f3(r, c.masking[8], c.rotate[8])
l, r = r, l^f2(r, c.masking[7], c.rotate[7])
l, r = r, l^f1(r, c.masking[6], c.rotate[6])
l, r = r, l^f3(r, c.masking[5], c.rotate[5])
l, r = r, l^f2(r, c.masking[4], c.rotate[4])
l, r = r, l^f1(r, c.masking[3], c.rotate[3])
l, r = r, l^f3(r, c.masking[2], c.rotate[2])
l, r = r, l^f2(r, c.masking[1], c.rotate[1])
l, r = r, l^f1(r, c.masking[0], c.rotate[0])
dst[0] = uint8(r >> 24)
dst[1] = uint8(r >> 16)
dst[2] = uint8(r >> 8)
dst[3] = uint8(r)
dst[4] = uint8(l >> 24)
dst[5] = uint8(l >> 16)
dst[6] = uint8(l >> 8)
dst[7] = uint8(l)
}
type keyScheduleA [4][7]uint8
type keyScheduleB [4][5]uint8
// keyScheduleRound contains the magic values for a round of the key schedule.
// The keyScheduleA deals with the lines like:
// z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]
// Conceptually, both x and z are in the same array, x first. The first
// element describes which word of this array gets written to and the
// second, which word gets read. So, for the line above, it's "4, 0", because
// it's writing to the first word of z, which, being after x, is word 4, and
// reading from the first word of x: word 0.
//
// Next are the indexes into the S-boxes. Now the array is treated as bytes. So
// "xD" is 0xd. The first byte of z is written as "16 + 0", just to be clear
// that it's z that we're indexing.
//
// keyScheduleB deals with lines like:
// K1 = S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2]
// "K1" is ignored because key words are always written in order. So the five
// elements are the S-box indexes. They use the same form as in keyScheduleA,
// above.
type keyScheduleRound struct{}
type keySchedule []keyScheduleRound
var schedule = []struct {
a keyScheduleA
b keyScheduleB
}{
{
keyScheduleA{
{4, 0, 0xd, 0xf, 0xc, 0xe, 0x8},
{5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa},
{6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9},
{7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb},
},
keyScheduleB{
{16 + 8, 16 + 9, 16 + 7, 16 + 6, 16 + 2},
{16 + 0xa, 16 + 0xb, 16 + 5, 16 + 4, 16 + 6},
{16 + 0xc, 16 + 0xd, 16 + 3, 16 + 2, 16 + 9},
{16 + 0xe, 16 + 0xf, 16 + 1, 16 + 0, 16 + 0xc},
},
},
{
keyScheduleA{
{0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0},
{1, 4, 0, 2, 1, 3, 16 + 2},
{2, 5, 7, 6, 5, 4, 16 + 1},
{3, 7, 0xa, 9, 0xb, 8, 16 + 3},
},
keyScheduleB{
{3, 2, 0xc, 0xd, 8},
{1, 0, 0xe, 0xf, 0xd},
{7, 6, 8, 9, 3},
{5, 4, 0xa, 0xb, 7},
},
},
{
keyScheduleA{
{4, 0, 0xd, 0xf, 0xc, 0xe, 8},
{5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa},
{6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9},
{7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb},
},
keyScheduleB{
{16 + 3, 16 + 2, 16 + 0xc, 16 + 0xd, 16 + 9},
{16 + 1, 16 + 0, 16 + 0xe, 16 + 0xf, 16 + 0xc},
{16 + 7, 16 + 6, 16 + 8, 16 + 9, 16 + 2},
{16 + 5, 16 + 4, 16 + 0xa, 16 + 0xb, 16 + 6},
},
},
{
keyScheduleA{
{0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0},
{1, 4, 0, 2, 1, 3, 16 + 2},
{2, 5, 7, 6, 5, 4, 16 + 1},
{3, 7, 0xa, 9, 0xb, 8, 16 + 3},
},
keyScheduleB{
{8, 9, 7, 6, 3},
{0xa, 0xb, 5, 4, 7},
{0xc, 0xd, 3, 2, 8},
{0xe, 0xf, 1, 0, 0xd},
},
},
}
func (c *Cipher) keySchedule(in []byte) {
var t [8]uint32
var k [32]uint32
for i := 0; i < 4; i++ {
j := i * 4
t[i] = uint32(in[j])<<24 | uint32(in[j+1])<<16 | uint32(in[j+2])<<8 | uint32(in[j+3])
}
x := []byte{6, 7, 4, 5}
ki := 0
for half := 0; half < 2; half++ {
for _, round := range schedule {
for j := 0; j < 4; j++ {
var a [7]uint8
copy(a[:], round.a[j][:])
w := t[a[1]]
w ^= sBox[4][(t[a[2]>>2]>>(24-8*(a[2]&3)))&0xff]
w ^= sBox[5][(t[a[3]>>2]>>(24-8*(a[3]&3)))&0xff]
w ^= sBox[6][(t[a[4]>>2]>>(24-8*(a[4]&3)))&0xff]
w ^= sBox[7][(t[a[5]>>2]>>(24-8*(a[5]&3)))&0xff]
w ^= sBox[x[j]][(t[a[6]>>2]>>(24-8*(a[6]&3)))&0xff]
t[a[0]] = w
}
for j := 0; j < 4; j++ {
var b [5]uint8
copy(b[:], round.b[j][:])
w := sBox[4][(t[b[0]>>2]>>(24-8*(b[0]&3)))&0xff]
w ^= sBox[5][(t[b[1]>>2]>>(24-8*(b[1]&3)))&0xff]
w ^= sBox[6][(t[b[2]>>2]>>(24-8*(b[2]&3)))&0xff]
w ^= sBox[7][(t[b[3]>>2]>>(24-8*(b[3]&3)))&0xff]
w ^= sBox[4+j][(t[b[4]>>2]>>(24-8*(b[4]&3)))&0xff]
k[ki] = w
ki++
}
}
}
for i := 0; i < 16; i++ {
c.masking[i] = k[i]
c.rotate[i] = uint8(k[16+i] & 0x1f)
}
}
// These are the three 'f' functions. See RFC 2144, section 2.2.
func f1(d, m uint32, r uint8) uint32 {
t := m + d
I := bits.RotateLeft32(t, int(r))
return ((sBox[0][I>>24] ^ sBox[1][(I>>16)&0xff]) - sBox[2][(I>>8)&0xff]) + sBox[3][I&0xff]
}
func f2(d, m uint32, r uint8) uint32 {
t := m ^ d
I := bits.RotateLeft32(t, int(r))
return ((sBox[0][I>>24] - sBox[1][(I>>16)&0xff]) + sBox[2][(I>>8)&0xff]) ^ sBox[3][I&0xff]
}
func f3(d, m uint32, r uint8) uint32 {
t := m - d
I := bits.RotateLeft32(t, int(r))
return ((sBox[0][I>>24] + sBox[1][(I>>16)&0xff]) ^ sBox[2][(I>>8)&0xff]) - sBox[3][I&0xff]
}
var sBox = [8][256]uint32{
{
0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949,
0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0,
0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7,
0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d,
0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3,
0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167,
0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779,
0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2,
0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d,
0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5,
0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,
0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96,
0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,
0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,
0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872,
0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,
0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9,
0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf,
},
{
0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651,
0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b,
0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b,
0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c,
0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb,
0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd,
0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b,
0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c,
0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f,
0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58,
0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6,
0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f,
0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9,
0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1,
},
{
0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90,
0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5,
0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240,
0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71,
0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15,
0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2,
0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148,
0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc,
0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e,
0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a,
0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b,
0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49,
0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a,
0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783,
},
{
0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1,
0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf,
0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121,
0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25,
0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb,
0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5,
0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6,
0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23,
0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119,
0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a,
0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79,
0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab,
0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2,
0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919,
0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab,
0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282,
0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2,
},
{
0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f,
0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a,
0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9,
0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981,
0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655,
0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2,
0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1,
0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da,
0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f,
0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba,
0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3,
0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840,
0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2,
0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7,
0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e,
0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8,
0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4,
},
{
0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac,
0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138,
0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98,
0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8,
0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54,
0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387,
0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf,
0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf,
0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289,
0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950,
0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b,
0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be,
0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976,
0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0,
0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da,
0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc,
0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25,
0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121,
0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd,
0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f,
},
{
0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f,
0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de,
0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19,
0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2,
0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816,
0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264,
0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28,
0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3,
0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566,
0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e,
0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c,
0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301,
0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767,
0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647,
0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c,
0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3,
},
{
0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5,
0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc,
0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d,
0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2,
0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc,
0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c,
0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039,
0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5,
0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472,
0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c,
0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb,
0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70,
0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc,
0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3,
0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4,
0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f,
0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e,
0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c,
0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384,
0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e,
},
}
// 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.
// Package chacha20 implements the ChaCha20 and XChaCha20 encryption algorithms
// as specified in RFC 8439 and draft-irtf-cfrg-xchacha-01.
package chacha20
import (
"crypto/cipher"
"encoding/binary"
"errors"
"math/bits"
"golang.org/x/crypto/internal/alias"
)
const (
// KeySize is the size of the key used by this cipher, in bytes.
KeySize = 32
// NonceSize is the size of the nonce used with the standard variant of this
// cipher, in bytes.
//
// Note that this is too short to be safely generated at random if the same
// key is reused more than 2³² times.
NonceSize = 12
// NonceSizeX is the size of the nonce used with the XChaCha20 variant of
// this cipher, in bytes.
NonceSizeX = 24
)
// Cipher is a stateful instance of ChaCha20 or XChaCha20 using a particular key
// and nonce. A *Cipher implements the cipher.Stream interface.
type Cipher struct {
// The ChaCha20 state is 16 words: 4 constant, 8 of key, 1 of counter
// (incremented after each block), and 3 of nonce.
key [8]uint32
counter uint32
nonce [3]uint32
// The last len bytes of buf are leftover key stream bytes from the previous
// XORKeyStream invocation. The size of buf depends on how many blocks are
// computed at a time by xorKeyStreamBlocks.
buf [bufSize]byte
len int
// overflow is set when the counter overflowed, no more blocks can be
// generated, and the next XORKeyStream call should panic.
overflow bool
// The counter-independent results of the first round are cached after they
// are computed the first time.
precompDone bool
p1, p5, p9, p13 uint32
p2, p6, p10, p14 uint32
p3, p7, p11, p15 uint32
}
var _ cipher.Stream = (*Cipher)(nil)
// NewUnauthenticatedCipher creates a new ChaCha20 stream cipher with the given
// 32 bytes key and a 12 or 24 bytes nonce. If a nonce of 24 bytes is provided,
// the XChaCha20 construction will be used. It returns an error if key or nonce
// have any other length.
//
// Note that ChaCha20, like all stream ciphers, is not authenticated and allows
// attackers to silently tamper with the plaintext. For this reason, it is more
// appropriate as a building block than as a standalone encryption mechanism.
// Instead, consider using package golang.org/x/crypto/chacha20poly1305.
func NewUnauthenticatedCipher(key, nonce []byte) (*Cipher, error) {
// This function is split into a wrapper so that the Cipher allocation will
// be inlined, and depending on how the caller uses the return value, won't
// escape to the heap.
c := &Cipher{}
return newUnauthenticatedCipher(c, key, nonce)
}
func newUnauthenticatedCipher(c *Cipher, key, nonce []byte) (*Cipher, error) {
if len(key) != KeySize {
return nil, errors.New("chacha20: wrong key size")
}
if len(nonce) == NonceSizeX {
// XChaCha20 uses the ChaCha20 core to mix 16 bytes of the nonce into a
// derived key, allowing it to operate on a nonce of 24 bytes. See
// draft-irtf-cfrg-xchacha-01, Section 2.3.
key, _ = HChaCha20(key, nonce[0:16])
cNonce := make([]byte, NonceSize)
copy(cNonce[4:12], nonce[16:24])
nonce = cNonce
} else if len(nonce) != NonceSize {
return nil, errors.New("chacha20: wrong nonce size")
}
key, nonce = key[:KeySize], nonce[:NonceSize] // bounds check elimination hint
c.key = [8]uint32{
binary.LittleEndian.Uint32(key[0:4]),
binary.LittleEndian.Uint32(key[4:8]),
binary.LittleEndian.Uint32(key[8:12]),
binary.LittleEndian.Uint32(key[12:16]),
binary.LittleEndian.Uint32(key[16:20]),
binary.LittleEndian.Uint32(key[20:24]),
binary.LittleEndian.Uint32(key[24:28]),
binary.LittleEndian.Uint32(key[28:32]),
}
c.nonce = [3]uint32{
binary.LittleEndian.Uint32(nonce[0:4]),
binary.LittleEndian.Uint32(nonce[4:8]),
binary.LittleEndian.Uint32(nonce[8:12]),
}
return c, nil
}
// The constant first 4 words of the ChaCha20 state.
const (
j0 uint32 = 0x61707865 // expa
j1 uint32 = 0x3320646e // nd 3
j2 uint32 = 0x79622d32 // 2-by
j3 uint32 = 0x6b206574 // te k
)
const blockSize = 64
// quarterRound is the core of ChaCha20. It shuffles the bits of 4 state words.
// It's executed 4 times for each of the 20 ChaCha20 rounds, operating on all 16
// words each round, in columnar or diagonal groups of 4 at a time.
func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
a += b
d ^= a
d = bits.RotateLeft32(d, 16)
c += d
b ^= c
b = bits.RotateLeft32(b, 12)
a += b
d ^= a
d = bits.RotateLeft32(d, 8)
c += d
b ^= c
b = bits.RotateLeft32(b, 7)
return a, b, c, d
}
// SetCounter sets the Cipher counter. The next invocation of XORKeyStream will
// behave as if (64 * counter) bytes had been encrypted so far.
//
// To prevent accidental counter reuse, SetCounter panics if counter is less
// than the current value.
//
// Note that the execution time of XORKeyStream is not independent of the
// counter value.
func (s *Cipher) SetCounter(counter uint32) {
// Internally, s may buffer multiple blocks, which complicates this
// implementation slightly. When checking whether the counter has rolled
// back, we must use both s.counter and s.len to determine how many blocks
// we have already output.
outputCounter := s.counter - uint32(s.len)/blockSize
if s.overflow || counter < outputCounter {
panic("chacha20: SetCounter attempted to rollback counter")
}
// In the general case, we set the new counter value and reset s.len to 0,
// causing the next call to XORKeyStream to refill the buffer. However, if
// we're advancing within the existing buffer, we can save work by simply
// setting s.len.
if counter < s.counter {
s.len = int(s.counter-counter) * blockSize
} else {
s.counter = counter
s.len = 0
}
}
// XORKeyStream XORs each byte in the given slice with a byte from the
// cipher's key stream. Dst and src must overlap entirely or not at all.
//
// If len(dst) < len(src), XORKeyStream will panic. It is acceptable
// to pass a dst bigger than src, and in that case, XORKeyStream will
// only update dst[:len(src)] and will not touch the rest of dst.
//
// Multiple calls to XORKeyStream behave as if the concatenation of
// the src buffers was passed in a single run. That is, Cipher
// maintains state and does not reset at each XORKeyStream call.
func (s *Cipher) XORKeyStream(dst, src []byte) {
if len(src) == 0 {
return
}
if len(dst) < len(src) {
panic("chacha20: output smaller than input")
}
dst = dst[:len(src)]
if alias.InexactOverlap(dst, src) {
panic("chacha20: invalid buffer overlap")
}
// First, drain any remaining key stream from a previous XORKeyStream.
if s.len != 0 {
keyStream := s.buf[bufSize-s.len:]
if len(src) < len(keyStream) {
keyStream = keyStream[:len(src)]
}
_ = src[len(keyStream)-1] // bounds check elimination hint
for i, b := range keyStream {
dst[i] = src[i] ^ b
}
s.len -= len(keyStream)
dst, src = dst[len(keyStream):], src[len(keyStream):]
}
if len(src) == 0 {
return
}
// If we'd need to let the counter overflow and keep generating output,
// panic immediately. If instead we'd only reach the last block, remember
// not to generate any more output after the buffer is drained.
numBlocks := (uint64(len(src)) + blockSize - 1) / blockSize
if s.overflow || uint64(s.counter)+numBlocks > 1<<32 {
panic("chacha20: counter overflow")
} else if uint64(s.counter)+numBlocks == 1<<32 {
s.overflow = true
}
// xorKeyStreamBlocks implementations expect input lengths that are a
// multiple of bufSize. Platform-specific ones process multiple blocks at a
// time, so have bufSizes that are a multiple of blockSize.
full := len(src) - len(src)%bufSize
if full > 0 {
s.xorKeyStreamBlocks(dst[:full], src[:full])
}
dst, src = dst[full:], src[full:]
// If using a multi-block xorKeyStreamBlocks would overflow, use the generic
// one that does one block at a time.
const blocksPerBuf = bufSize / blockSize
if uint64(s.counter)+blocksPerBuf > 1<<32 {
s.buf = [bufSize]byte{}
numBlocks := (len(src) + blockSize - 1) / blockSize
buf := s.buf[bufSize-numBlocks*blockSize:]
copy(buf, src)
s.xorKeyStreamBlocksGeneric(buf, buf)
s.len = len(buf) - copy(dst, buf)
return
}
// If we have a partial (multi-)block, pad it for xorKeyStreamBlocks, and
// keep the leftover keystream for the next XORKeyStream invocation.
if len(src) > 0 {
s.buf = [bufSize]byte{}
copy(s.buf[:], src)
s.xorKeyStreamBlocks(s.buf[:], s.buf[:])
s.len = bufSize - copy(dst, s.buf[:])
}
}
func (s *Cipher) xorKeyStreamBlocksGeneric(dst, src []byte) {
if len(dst) != len(src) || len(dst)%blockSize != 0 {
panic("chacha20: internal error: wrong dst and/or src length")
}
// To generate each block of key stream, the initial cipher state
// (represented below) is passed through 20 rounds of shuffling,
// alternatively applying quarterRounds by columns (like 1, 5, 9, 13)
// or by diagonals (like 1, 6, 11, 12).
//
// 0:cccccccc 1:cccccccc 2:cccccccc 3:cccccccc
// 4:kkkkkkkk 5:kkkkkkkk 6:kkkkkkkk 7:kkkkkkkk
// 8:kkkkkkkk 9:kkkkkkkk 10:kkkkkkkk 11:kkkkkkkk
// 12:bbbbbbbb 13:nnnnnnnn 14:nnnnnnnn 15:nnnnnnnn
//
// c=constant k=key b=blockcount n=nonce
var (
c0, c1, c2, c3 = j0, j1, j2, j3
c4, c5, c6, c7 = s.key[0], s.key[1], s.key[2], s.key[3]
c8, c9, c10, c11 = s.key[4], s.key[5], s.key[6], s.key[7]
_, c13, c14, c15 = s.counter, s.nonce[0], s.nonce[1], s.nonce[2]
)
// Three quarters of the first round don't depend on the counter, so we can
// calculate them here, and reuse them for multiple blocks in the loop, and
// for future XORKeyStream invocations.
if !s.precompDone {
s.p1, s.p5, s.p9, s.p13 = quarterRound(c1, c5, c9, c13)
s.p2, s.p6, s.p10, s.p14 = quarterRound(c2, c6, c10, c14)
s.p3, s.p7, s.p11, s.p15 = quarterRound(c3, c7, c11, c15)
s.precompDone = true
}
// A condition of len(src) > 0 would be sufficient, but this also
// acts as a bounds check elimination hint.
for len(src) >= 64 && len(dst) >= 64 {
// The remainder of the first column round.
fcr0, fcr4, fcr8, fcr12 := quarterRound(c0, c4, c8, s.counter)
// The second diagonal round.
x0, x5, x10, x15 := quarterRound(fcr0, s.p5, s.p10, s.p15)
x1, x6, x11, x12 := quarterRound(s.p1, s.p6, s.p11, fcr12)
x2, x7, x8, x13 := quarterRound(s.p2, s.p7, fcr8, s.p13)
x3, x4, x9, x14 := quarterRound(s.p3, fcr4, s.p9, s.p14)
// The remaining 18 rounds.
for i := 0; i < 9; i++ {
// Column round.
x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
// Diagonal round.
x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
}
// Add back the initial state to generate the key stream, then
// XOR the key stream with the source and write out the result.
addXor(dst[0:4], src[0:4], x0, c0)
addXor(dst[4:8], src[4:8], x1, c1)
addXor(dst[8:12], src[8:12], x2, c2)
addXor(dst[12:16], src[12:16], x3, c3)
addXor(dst[16:20], src[16:20], x4, c4)
addXor(dst[20:24], src[20:24], x5, c5)
addXor(dst[24:28], src[24:28], x6, c6)
addXor(dst[28:32], src[28:32], x7, c7)
addXor(dst[32:36], src[32:36], x8, c8)
addXor(dst[36:40], src[36:40], x9, c9)
addXor(dst[40:44], src[40:44], x10, c10)
addXor(dst[44:48], src[44:48], x11, c11)
addXor(dst[48:52], src[48:52], x12, s.counter)
addXor(dst[52:56], src[52:56], x13, c13)
addXor(dst[56:60], src[56:60], x14, c14)
addXor(dst[60:64], src[60:64], x15, c15)
s.counter += 1
src, dst = src[blockSize:], dst[blockSize:]
}
}
// HChaCha20 uses the ChaCha20 core to generate a derived key from a 32 bytes
// key and a 16 bytes nonce. It returns an error if key or nonce have any other
// length. It is used as part of the XChaCha20 construction.
func HChaCha20(key, nonce []byte) ([]byte, error) {
// This function is split into a wrapper so that the slice allocation will
// be inlined, and depending on how the caller uses the return value, won't
// escape to the heap.
out := make([]byte, 32)
return hChaCha20(out, key, nonce)
}
func hChaCha20(out, key, nonce []byte) ([]byte, error) {
if len(key) != KeySize {
return nil, errors.New("chacha20: wrong HChaCha20 key size")
}
if len(nonce) != 16 {
return nil, errors.New("chacha20: wrong HChaCha20 nonce size")
}
x0, x1, x2, x3 := j0, j1, j2, j3
x4 := binary.LittleEndian.Uint32(key[0:4])
x5 := binary.LittleEndian.Uint32(key[4:8])
x6 := binary.LittleEndian.Uint32(key[8:12])
x7 := binary.LittleEndian.Uint32(key[12:16])
x8 := binary.LittleEndian.Uint32(key[16:20])
x9 := binary.LittleEndian.Uint32(key[20:24])
x10 := binary.LittleEndian.Uint32(key[24:28])
x11 := binary.LittleEndian.Uint32(key[28:32])
x12 := binary.LittleEndian.Uint32(nonce[0:4])
x13 := binary.LittleEndian.Uint32(nonce[4:8])
x14 := binary.LittleEndian.Uint32(nonce[8:12])
x15 := binary.LittleEndian.Uint32(nonce[12:16])
for i := 0; i < 10; i++ {
// Diagonal round.
x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
// Column round.
x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
}
_ = out[31] // bounds check elimination hint
binary.LittleEndian.PutUint32(out[0:4], x0)
binary.LittleEndian.PutUint32(out[4:8], x1)
binary.LittleEndian.PutUint32(out[8:12], x2)
binary.LittleEndian.PutUint32(out[12:16], x3)
binary.LittleEndian.PutUint32(out[16:20], x12)
binary.LittleEndian.PutUint32(out[20:24], x13)
binary.LittleEndian.PutUint32(out[24:28], x14)
binary.LittleEndian.PutUint32(out[28:32], x15)
return out, nil
}
// Copyright 2018 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.
//go:build (!arm64 && !s390x && !ppc64 && !ppc64le) || !gc || purego
package chacha20
const bufSize = blockSize
func (s *Cipher) xorKeyStreamBlocks(dst, src []byte) {
s.xorKeyStreamBlocksGeneric(dst, src)
}
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found src the LICENSE file.
package chacha20
import "runtime"
// Platforms that have fast unaligned 32-bit little endian accesses.
const unaligned = runtime.GOARCH == "386" ||
runtime.GOARCH == "amd64" ||
runtime.GOARCH == "arm64" ||
runtime.GOARCH == "ppc64le" ||
runtime.GOARCH == "s390x"
// addXor reads a little endian uint32 from src, XORs it with (a + b) and
// places the result in little endian byte order in dst.
func addXor(dst, src []byte, a, b uint32) {
_, _ = src[3], dst[3] // bounds check elimination hint
if unaligned {
// The compiler should optimize this code into
// 32-bit unaligned little endian loads and stores.
// TODO: delete once the compiler does a reliably
// good job with the generic code below.
// See issue #25111 for more details.
v := uint32(src[0])
v |= uint32(src[1]) << 8
v |= uint32(src[2]) << 16
v |= uint32(src[3]) << 24
v ^= a + b
dst[0] = byte(v)
dst[1] = byte(v >> 8)
dst[2] = byte(v >> 16)
dst[3] = byte(v >> 24)
} else {
a += b
dst[0] = src[0] ^ byte(a)
dst[1] = src[1] ^ byte(a>>8)
dst[2] = src[2] ^ byte(a>>16)
dst[3] = src[3] ^ byte(a>>24)
}
}
// 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.
// Package chacha20poly1305 implements the ChaCha20-Poly1305 AEAD and its
// extended nonce variant XChaCha20-Poly1305, as specified in RFC 8439 and
// draft-irtf-cfrg-xchacha-01.
package chacha20poly1305
import (
"crypto/cipher"
"errors"
)
const (
// KeySize is the size of the key used by this AEAD, in bytes.
KeySize = 32
// NonceSize is the size of the nonce used with the standard variant of this
// AEAD, in bytes.
//
// Note that this is too short to be safely generated at random if the same
// key is reused more than 2³² times.
NonceSize = 12
// NonceSizeX is the size of the nonce used with the XChaCha20-Poly1305
// variant of this AEAD, in bytes.
NonceSizeX = 24
// Overhead is the size of the Poly1305 authentication tag, and the
// difference between a ciphertext length and its plaintext.
Overhead = 16
)
type chacha20poly1305 struct {
key [KeySize]byte
}
// New returns a ChaCha20-Poly1305 AEAD that uses the given 256-bit key.
func New(key []byte) (cipher.AEAD, error) {
if len(key) != KeySize {
return nil, errors.New("chacha20poly1305: bad key length")
}
ret := new(chacha20poly1305)
copy(ret.key[:], key)
return ret, nil
}
func (c *chacha20poly1305) NonceSize() int {
return NonceSize
}
func (c *chacha20poly1305) Overhead() int {
return Overhead
}
func (c *chacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
if len(nonce) != NonceSize {
panic("chacha20poly1305: bad nonce length passed to Seal")
}
if uint64(len(plaintext)) > (1<<38)-64 {
panic("chacha20poly1305: plaintext too large")
}
return c.seal(dst, nonce, plaintext, additionalData)
}
var errOpen = errors.New("chacha20poly1305: message authentication failed")
func (c *chacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
if len(nonce) != NonceSize {
panic("chacha20poly1305: bad nonce length passed to Open")
}
if len(ciphertext) < 16 {
return nil, errOpen
}
if uint64(len(ciphertext)) > (1<<38)-48 {
panic("chacha20poly1305: ciphertext too large")
}
return c.open(dst, nonce, ciphertext, additionalData)
}
// sliceForAppend takes a slice and a requested number of bytes. It returns a
// slice with the contents of the given slice followed by that many bytes and a
// second slice that aliases into it and contains only the extra bytes. If the
// original slice has sufficient capacity then no allocation is performed.
func sliceForAppend(in []byte, n int) (head, tail []byte) {
if total := len(in) + n; cap(in) >= total {
head = in[:total]
} else {
head = make([]byte, total)
copy(head, in)
}
tail = head[len(in):]
return
}
// 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.
//go:build gc && !purego
package chacha20poly1305
import (
"encoding/binary"
"golang.org/x/crypto/internal/alias"
"golang.org/x/sys/cpu"
)
//go:noescape
func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool
//go:noescape
func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte)
var (
useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI2
)
// setupState writes a ChaCha20 input matrix to state. See
// https://tools.ietf.org/html/rfc7539#section-2.3.
func setupState(state *[16]uint32, key *[32]byte, nonce []byte) {
state[0] = 0x61707865
state[1] = 0x3320646e
state[2] = 0x79622d32
state[3] = 0x6b206574
state[4] = binary.LittleEndian.Uint32(key[0:4])
state[5] = binary.LittleEndian.Uint32(key[4:8])
state[6] = binary.LittleEndian.Uint32(key[8:12])
state[7] = binary.LittleEndian.Uint32(key[12:16])
state[8] = binary.LittleEndian.Uint32(key[16:20])
state[9] = binary.LittleEndian.Uint32(key[20:24])
state[10] = binary.LittleEndian.Uint32(key[24:28])
state[11] = binary.LittleEndian.Uint32(key[28:32])
state[12] = 0
state[13] = binary.LittleEndian.Uint32(nonce[0:4])
state[14] = binary.LittleEndian.Uint32(nonce[4:8])
state[15] = binary.LittleEndian.Uint32(nonce[8:12])
}
func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
if !cpu.X86.HasSSSE3 {
return c.sealGeneric(dst, nonce, plaintext, additionalData)
}
var state [16]uint32
setupState(&state, &c.key, nonce)
ret, out := sliceForAppend(dst, len(plaintext)+16)
if alias.InexactOverlap(out, plaintext) {
panic("chacha20poly1305: invalid buffer overlap of output and input")
}
if alias.AnyOverlap(out, additionalData) {
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
}
chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
return ret
}
func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
if !cpu.X86.HasSSSE3 {
return c.openGeneric(dst, nonce, ciphertext, additionalData)
}
var state [16]uint32
setupState(&state, &c.key, nonce)
ciphertext = ciphertext[:len(ciphertext)-16]
ret, out := sliceForAppend(dst, len(ciphertext))
if alias.InexactOverlap(out, ciphertext) {
panic("chacha20poly1305: invalid buffer overlap of output and input")
}
if alias.AnyOverlap(out, additionalData) {
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
}
if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
for i := range out {
out[i] = 0
}
return nil, errOpen
}
return ret, nil
}
// 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.
package chacha20poly1305
import (
"encoding/binary"
"golang.org/x/crypto/chacha20"
"golang.org/x/crypto/internal/alias"
"golang.org/x/crypto/internal/poly1305"
)
func writeWithPadding(p *poly1305.MAC, b []byte) {
p.Write(b)
if rem := len(b) % 16; rem != 0 {
var buf [16]byte
padLen := 16 - rem
p.Write(buf[:padLen])
}
}
func writeUint64(p *poly1305.MAC, n int) {
var buf [8]byte
binary.LittleEndian.PutUint64(buf[:], uint64(n))
p.Write(buf[:])
}
func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte {
ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
ciphertext, tag := out[:len(plaintext)], out[len(plaintext):]
if alias.InexactOverlap(out, plaintext) {
panic("chacha20poly1305: invalid buffer overlap of output and input")
}
if alias.AnyOverlap(out, additionalData) {
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
}
var polyKey [32]byte
s, _ := chacha20.NewUnauthenticatedCipher(c.key[:], nonce)
s.XORKeyStream(polyKey[:], polyKey[:])
s.SetCounter(1) // set the counter to 1, skipping 32 bytes
s.XORKeyStream(ciphertext, plaintext)
p := poly1305.New(&polyKey)
writeWithPadding(p, additionalData)
writeWithPadding(p, ciphertext)
writeUint64(p, len(additionalData))
writeUint64(p, len(plaintext))
p.Sum(tag[:0])
return ret
}
func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
tag := ciphertext[len(ciphertext)-16:]
ciphertext = ciphertext[:len(ciphertext)-16]
var polyKey [32]byte
s, _ := chacha20.NewUnauthenticatedCipher(c.key[:], nonce)
s.XORKeyStream(polyKey[:], polyKey[:])
s.SetCounter(1) // set the counter to 1, skipping 32 bytes
p := poly1305.New(&polyKey)
writeWithPadding(p, additionalData)
writeWithPadding(p, ciphertext)
writeUint64(p, len(additionalData))
writeUint64(p, len(ciphertext))
ret, out := sliceForAppend(dst, len(ciphertext))
if alias.InexactOverlap(out, ciphertext) {
panic("chacha20poly1305: invalid buffer overlap of output and input")
}
if alias.AnyOverlap(out, additionalData) {
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
}
if !p.Verify(tag) {
for i := range out {
out[i] = 0
}
return nil, errOpen
}
s.XORKeyStream(out, ciphertext)
return ret, nil
}
// Copyright 2018 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 chacha20poly1305
import (
"crypto/cipher"
"errors"
"golang.org/x/crypto/chacha20"
)
type xchacha20poly1305 struct {
key [KeySize]byte
}
// NewX returns a XChaCha20-Poly1305 AEAD that uses the given 256-bit key.
//
// XChaCha20-Poly1305 is a ChaCha20-Poly1305 variant that takes a longer nonce,
// suitable to be generated randomly without risk of collisions. It should be
// preferred when nonce uniqueness cannot be trivially ensured, or whenever
// nonces are randomly generated.
func NewX(key []byte) (cipher.AEAD, error) {
if len(key) != KeySize {
return nil, errors.New("chacha20poly1305: bad key length")
}
ret := new(xchacha20poly1305)
copy(ret.key[:], key)
return ret, nil
}
func (*xchacha20poly1305) NonceSize() int {
return NonceSizeX
}
func (*xchacha20poly1305) Overhead() int {
return Overhead
}
func (x *xchacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
if len(nonce) != NonceSizeX {
panic("chacha20poly1305: bad nonce length passed to Seal")
}
// XChaCha20-Poly1305 technically supports a 64-bit counter, so there is no
// size limit. However, since we reuse the ChaCha20-Poly1305 implementation,
// the second half of the counter is not available. This is unlikely to be
// an issue because the cipher.AEAD API requires the entire message to be in
// memory, and the counter overflows at 256 GB.
if uint64(len(plaintext)) > (1<<38)-64 {
panic("chacha20poly1305: plaintext too large")
}
c := new(chacha20poly1305)
hKey, _ := chacha20.HChaCha20(x.key[:], nonce[0:16])
copy(c.key[:], hKey)
// The first 4 bytes of the final nonce are unused counter space.
cNonce := make([]byte, NonceSize)
copy(cNonce[4:12], nonce[16:24])
return c.seal(dst, cNonce[:], plaintext, additionalData)
}
func (x *xchacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
if len(nonce) != NonceSizeX {
panic("chacha20poly1305: bad nonce length passed to Open")
}
if len(ciphertext) < 16 {
return nil, errOpen
}
if uint64(len(ciphertext)) > (1<<38)-48 {
panic("chacha20poly1305: ciphertext too large")
}
c := new(chacha20poly1305)
hKey, _ := chacha20.HChaCha20(x.key[:], nonce[0:16])
copy(c.key[:], hKey)
// The first 4 bytes of the final nonce are unused counter space.
cNonce := make([]byte, NonceSize)
copy(cNonce[4:12], nonce[16:24])
return c.open(dst, cNonce[:], ciphertext, additionalData)
}
// 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 "encoding/asn1"
"fmt"
"math/big"
"reflect"
"time"
"golang.org/x/crypto/cryptobyte/asn1"
)
// This file contains ASN.1-related methods for String and Builder.
// Builder
// AddASN1Int64 appends a DER-encoded ASN.1 INTEGER.
func (b *Builder) AddASN1Int64(v int64) {
b.addASN1Signed(asn1.INTEGER, v)
}
// AddASN1Int64WithTag appends a DER-encoded ASN.1 INTEGER with the
// given tag.
func (b *Builder) AddASN1Int64WithTag(v int64, tag asn1.Tag) {
b.addASN1Signed(tag, v)
}
// AddASN1Enum appends a DER-encoded ASN.1 ENUMERATION.
func (b *Builder) AddASN1Enum(v int64) {
b.addASN1Signed(asn1.ENUM, v)
}
func (b *Builder) addASN1Signed(tag asn1.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.INTEGER, 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.INTEGER, 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 len(bytes) == 0 || 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.OCTET_STRING, 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.GeneralizedTime, func(c *Builder) {
c.AddBytes([]byte(t.Format(generalizedTimeFormatStr)))
})
}
// AddASN1UTCTime appends a DER-encoded ASN.1 UTCTime.
func (b *Builder) AddASN1UTCTime(t time.Time) {
b.AddASN1(asn1.UTCTime, func(c *Builder) {
// As utilized by the X.509 profile, UTCTime can only
// represent the years 1950 through 2049.
if t.Year() < 1950 || t.Year() >= 2050 {
b.err = fmt.Errorf("cryptobyte: cannot represent %v as a UTCTime", t)
return
}
c.AddBytes([]byte(t.Format(defaultUTCTimeFormatStr)))
})
}
// AddASN1BitString appends a DER-encoded ASN.1 BIT STRING. This does not
// support BIT STRINGs that are not a whole number of bytes.
func (b *Builder) AddASN1BitString(data []byte) {
b.AddASN1(asn1.BIT_STRING, func(b *Builder) {
b.AddUint8(0)
b.AddBytes(data)
})
}
func (b *Builder) addBase128Int(n int64) {
var length int
if n == 0 {
length = 1
} else {
for i := n; i > 0; i >>= 7 {
length++
}
}
for i := length - 1; i >= 0; i-- {
o := byte(n >> uint(i*7))
o &= 0x7f
if i != 0 {
o |= 0x80
}
b.add(o)
}
}
func isValidOID(oid encoding_asn1.ObjectIdentifier) bool {
if len(oid) < 2 {
return false
}
if oid[0] > 2 || (oid[0] <= 1 && oid[1] >= 40) {
return false
}
for _, v := range oid {
if v < 0 {
return false
}
}
return true
}
func (b *Builder) AddASN1ObjectIdentifier(oid encoding_asn1.ObjectIdentifier) {
b.AddASN1(asn1.OBJECT_IDENTIFIER, func(b *Builder) {
if !isValidOID(oid) {
b.err = fmt.Errorf("cryptobyte: invalid OID: %v", oid)
return
}
b.addBase128Int(int64(oid[0])*40 + int64(oid[1]))
for _, v := range oid[2:] {
b.addBase128Int(int64(v))
}
})
}
func (b *Builder) AddASN1Boolean(v bool) {
b.AddASN1(asn1.BOOLEAN, func(b *Builder) {
if v {
b.AddUint8(0xff)
} else {
b.AddUint8(0)
}
})
}
func (b *Builder) AddASN1NULL() {
b.add(uint8(asn1.NULL), 0)
}
// MarshalASN1 calls encoding_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
// encoding_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 := encoding_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 asn1.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 octets not supported: 0x%x", tag)
return
}
b.AddUint8(uint8(tag))
b.addLengthPrefixed(1, true, f)
}
// String
// ReadASN1Boolean decodes an ASN.1 BOOLEAN and converts it to a boolean
// representation into out and advances. It reports whether the read
// was successful.
func (s *String) ReadASN1Boolean(out *bool) bool {
var bytes String
if !s.ReadASN1(&bytes, asn1.BOOLEAN) || len(bytes) != 1 {
return false
}
switch bytes[0] {
case 0:
*out = false
case 0xff:
*out = true
default:
return false
}
return true
}
// ReadASN1Integer decodes an ASN.1 INTEGER into out and advances. If out does
// not point to an integer, to a big.Int, or to a []byte it panics. Only
// positive and zero values can be decoded into []byte, and they are returned as
// big-endian binary values that share memory with s. Positive values will have
// no leading zeroes, and zero will be returned as a single zero byte.
// ReadASN1Integer reports whether the read was successful.
func (s *String) ReadASN1Integer(out interface{}) bool {
switch out := out.(type) {
case *int, *int8, *int16, *int32, *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 *uint, *uint8, *uint16, *uint32, *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 *big.Int:
return s.readASN1BigInt(out)
case *[]byte:
return s.readASN1Bytes(out)
default:
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.INTEGER) || !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) readASN1Bytes(out *[]byte) bool {
var bytes String
if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) {
return false
}
if bytes[0]&0x80 == 0x80 {
return false
}
for len(bytes) > 1 && bytes[0] == 0 {
bytes = bytes[1:]
}
*out = bytes
return true
}
func (s *String) readASN1Int64(out *int64) bool {
var bytes String
if !s.ReadASN1(&bytes, asn1.INTEGER) || !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.INTEGER) || !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
}
// ReadASN1Int64WithTag decodes an ASN.1 INTEGER with the given tag into out
// and advances. It reports whether the read was successful and resulted in a
// value that can be represented in an int64.
func (s *String) ReadASN1Int64WithTag(out *int64, tag asn1.Tag) bool {
var bytes String
return s.ReadASN1(&bytes, tag) && checkASN1Integer(bytes) && asn1Signed(out, bytes)
}
// ReadASN1Enum decodes an ASN.1 ENUMERATION into out and advances. It reports
// whether the read was successful.
func (s *String) ReadASN1Enum(out *int) bool {
var bytes String
var i int64
if !s.ReadASN1(&bytes, asn1.ENUM) || !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 == 5 {
return false
}
// Avoid overflowing int on a 32-bit platform.
// We don't want different behavior based on the architecture.
if ret >= 1<<(31-7) {
return false
}
ret <<= 7
b := s.read(1)[0]
// ITU-T X.690, section 8.19.2:
// The subidentifier shall be encoded in the fewest possible octets,
// that is, the leading octet of the subidentifier shall not have the value 0x80.
if i == 0 && b == 0x80 {
return false
}
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 reports whether the read was successful.
func (s *String) ReadASN1ObjectIdentifier(out *encoding_asn1.ObjectIdentifier) bool {
var bytes String
if !s.ReadASN1(&bytes, asn1.OBJECT_IDENTIFIER) || 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 reports whether the read was successful.
func (s *String) ReadASN1GeneralizedTime(out *time.Time) bool {
var bytes String
if !s.ReadASN1(&bytes, asn1.GeneralizedTime) {
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
}
const defaultUTCTimeFormatStr = "060102150405Z0700"
// ReadASN1UTCTime decodes an ASN.1 UTCTime into out and advances.
// It reports whether the read was successful.
func (s *String) ReadASN1UTCTime(out *time.Time) bool {
var bytes String
if !s.ReadASN1(&bytes, asn1.UTCTime) {
return false
}
t := string(bytes)
formatStr := defaultUTCTimeFormatStr
var err error
res, err := time.Parse(formatStr, t)
if err != nil {
// Fallback to minute precision if we can't parse second
// precision. If we are following X.509 or X.690 we shouldn't
// support this, but we do.
formatStr = "0601021504Z0700"
res, err = time.Parse(formatStr, t)
}
if err != nil {
return false
}
if serialized := res.Format(formatStr); serialized != t {
return false
}
if res.Year() >= 2050 {
// UTCTime interprets the low order digits 50-99 as 1950-99.
// This only applies to its use in the X.509 profile.
// See https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
res = res.AddDate(-100, 0, 0)
}
*out = res
return true
}
// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances.
// It reports whether the read was successful.
func (s *String) ReadASN1BitString(out *encoding_asn1.BitString) bool {
var bytes String
if !s.ReadASN1(&bytes, asn1.BIT_STRING) || len(bytes) == 0 ||
len(bytes)*8/8 != len(bytes) {
return false
}
paddingBits := 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
}
// ReadASN1BitStringAsBytes decodes an ASN.1 BIT STRING into out and advances. It is
// an error if the BIT STRING is not a whole number of bytes. It reports
// whether the read was successful.
func (s *String) ReadASN1BitStringAsBytes(out *[]byte) bool {
var bytes String
if !s.ReadASN1(&bytes, asn1.BIT_STRING) || len(bytes) == 0 {
return false
}
paddingBits := bytes[0]
if paddingBits != 0 {
return false
}
*out = bytes[1:]
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 reports whether the read was successful.
func (s *String) ReadASN1Bytes(out *[]byte, tag asn1.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 reports whether the read was successful.
//
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
func (s *String) ReadASN1(out *String, tag asn1.Tag) bool {
var t asn1.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 reports whether the read was successful.
//
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
func (s *String) ReadASN1Element(out *String, tag asn1.Tag) bool {
var t asn1.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 reports whether the read was successful.
//
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
func (s *String) ReadAnyASN1(out *String, outTag *asn1.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 reports whether the read was successful.
//
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
func (s *String) ReadAnyASN1Element(out *String, outTag *asn1.Tag) bool {
return s.readASN1(out, outTag, false /* include header */)
}
// PeekASN1Tag reports whether the next ASN.1 value on the string starts with
// the given tag.
func (s String) PeekASN1Tag(tag asn1.Tag) bool {
if len(s) == 0 {
return false
}
return asn1.Tag(s[0]) == tag
}
// SkipASN1 reads and discards an ASN.1 element with the given tag. It
// reports whether the operation was successful.
func (s *String) SkipASN1(tag asn1.Tag) bool {
var unused String
return s.ReadASN1(&unused, tag)
}
// ReadOptionalASN1 attempts to read the contents of a DER-encoded ASN.1
// 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 reports whether the read was successful.
func (s *String) ReadOptionalASN1(out *String, outPresent *bool, tag asn1.Tag) bool {
present := s.PeekASN1Tag(tag)
if outPresent != nil {
*outPresent = present
}
if present && !s.ReadASN1(out, tag) {
return false
}
return true
}
// SkipOptionalASN1 advances s over an ASN.1 element with the given tag, or
// else leaves s unchanged. It reports whether the operation was successful.
func (s *String) SkipOptionalASN1(tag asn1.Tag) bool {
if !s.PeekASN1Tag(tag) {
return true
}
var unused String
return s.ReadASN1(&unused, tag)
}
// 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. Otherwise, it behaves like
// ReadASN1Integer.
func (s *String) ReadOptionalASN1Integer(out interface{}, tag asn1.Tag, defaultValue interface{}) bool {
var present bool
var i String
if !s.ReadOptionalASN1(&i, &present, tag) {
return false
}
if !present {
switch out.(type) {
case *int, *int8, *int16, *int32, *int64,
*uint, *uint8, *uint16, *uint32, *uint64, *[]byte:
reflect.ValueOf(out).Elem().Set(reflect.ValueOf(defaultValue))
case *big.Int:
if defaultValue, ok := defaultValue.(*big.Int); ok {
out.(*big.Int).Set(defaultValue)
} else {
panic("out points to big.Int, but defaultValue does not")
}
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 sets "out" to nil instead. It reports
// whether the read was successful.
func (s *String) ReadOptionalASN1OctetString(out *[]byte, outPresent *bool, tag asn1.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.OCTET_STRING) || !child.Empty() {
return false
}
*out = oct
} else {
*out = nil
}
return true
}
// ReadOptionalASN1Boolean attempts to read an optional ASN.1 BOOLEAN
// explicitly tagged with tag into out and advances. If no element with a
// matching tag is present, it sets "out" to defaultValue instead. It reports
// whether the read was successful.
func (s *String) ReadOptionalASN1Boolean(out *bool, tag asn1.Tag, defaultValue bool) bool {
var present bool
var child String
if !s.ReadOptionalASN1(&child, &present, tag) {
return false
}
if !present {
*out = defaultValue
return true
}
return child.ReadASN1Boolean(out)
}
func (s *String) readASN1(out *String, outTag *asn1.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 = asn1.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 int(length) < 0 || !s.ReadBytes((*[]byte)(out), int(length)) {
return false
}
if skipHeader && !out.Skip(int(headerLen)) {
panic("cryptobyte: internal error")
}
return true
}
// 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 asn1 contains supporting types for parsing and building ASN.1
// messages with the cryptobyte package.
package asn1
// Tag represents an ASN.1 identifier octet, consisting of a tag number
// (indicating a type) and class (such as context-specific or constructed).
//
// Methods in the cryptobyte 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
const (
classConstructed = 0x20
classContextSpecific = 0x80
)
// Constructed returns t with the constructed class bit set.
func (t Tag) Constructed() Tag { return t | classConstructed }
// ContextSpecific returns t with the context-specific class bit set.
func (t Tag) ContextSpecific() Tag { return t | classContextSpecific }
// The following is a list of standard tag and class combinations.
const (
BOOLEAN = Tag(1)
INTEGER = Tag(2)
BIT_STRING = Tag(3)
OCTET_STRING = Tag(4)
NULL = Tag(5)
OBJECT_IDENTIFIER = Tag(6)
ENUM = Tag(10)
UTF8String = Tag(12)
SEQUENCE = Tag(16 | classConstructed)
SET = Tag(17 | classConstructed)
PrintableString = Tag(19)
T61String = Tag(20)
IA5String = Tag(22)
UTCTime = Tag(23)
GeneralizedTime = Tag(24)
GeneralString = Tag(27)
)
// 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.
// Builders either allocate space as needed, or are ‘fixed’, which means that
// they write into a given buffer and produce an error if it's exhausted.
//
// The zero value is a usable Builder that allocates space as needed.
//
// Simple values are marshaled and appended to a Builder using methods on the
// Builder. Length-prefixed values are marshaled by providing a
// BuilderContinuation, which is a function that writes the inner contents of
// the value to a given Builder. See the documentation for BuilderContinuation
// for details.
type Builder struct {
err error
result []byte
fixedSize bool
child *Builder
offset int
pendingLenLen int
pendingIsASN1 bool
inContinuation *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,
}
}
// SetError sets the value to be returned as the error from Bytes. Writes
// performed after calling SetError are ignored.
func (b *Builder) SetError(err error) {
b.err = err
}
// Bytes returns the bytes written by the builder or an error if one has
// occurred 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))
}
// AddUint48 appends a big-endian, 48-bit value to the byte string.
func (b *Builder) AddUint48(v uint64) {
b.add(byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
}
// AddUint64 appends a big-endian, 64-bit value to the byte string.
func (b *Builder) AddUint64(v uint64) {
b.add(byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), 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 a continuation-passing interface for building
// length-prefixed byte sequences. Builder methods for length-prefixed
// sequences (AddUint8LengthPrefixed etc) will invoke the BuilderContinuation
// supplied to them. The child builder passed to the continuation can be used
// to build the content of the length-prefixed sequence. For example:
//
// parent := cryptobyte.NewBuilder()
// parent.AddUint8LengthPrefixed(func (child *Builder) {
// child.AddUint8(42)
// child.AddUint8LengthPrefixed(func (grandchild *Builder) {
// grandchild.AddUint8(5)
// })
// })
//
// It is an error to write more bytes to the child than allowed by the reserved
// length prefix. After the continuation returns, the child must be considered
// invalid, i.e. users must not store any copies or references of the child
// that outlive the continuation.
//
// If the continuation panics with a value of type BuildError then the inner
// error will be returned as the error from Bytes. If the child panics
// otherwise then Bytes will repanic with the same value.
type BuilderContinuation func(child *Builder)
// BuildError wraps an error. If a BuilderContinuation panics with this value,
// the panic will be recovered and the inner error will be returned from
// Builder.Bytes.
type BuildError struct {
Err error
}
// 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)
}
// AddUint32LengthPrefixed adds a big-endian, 32-bit length-prefixed byte sequence.
func (b *Builder) AddUint32LengthPrefixed(f BuilderContinuation) {
b.addLengthPrefixed(4, false, f)
}
func (b *Builder) callContinuation(f BuilderContinuation, arg *Builder) {
if !*b.inContinuation {
*b.inContinuation = true
defer func() {
*b.inContinuation = false
r := recover()
if r == nil {
return
}
if buildError, ok := r.(BuildError); ok {
b.err = buildError.Err
} else {
panic(r)
}
}()
}
f(arg)
}
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)...)
if b.inContinuation == nil {
b.inContinuation = new(bool)
}
b.child = &Builder{
result: b.result,
fixedSize: b.fixedSize,
offset: offset,
pendingLenLen: lenLen,
pendingIsASN1: isASN1,
inContinuation: b.inContinuation,
}
b.callContinuation(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[0] != &child.result[0] {
panic("cryptobyte: BuilderContinuation reallocated a fixed-size buffer")
}
b.result = child.result
}
func (b *Builder) add(bytes ...byte) {
if b.err != nil {
return
}
if b.child != nil {
panic("cryptobyte: 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...)
}
// Unwrite rolls back non-negative n bytes written directly to the Builder.
// An attempt by a child builder passed to a continuation to unwrite bytes
// from its parent will panic.
func (b *Builder) Unwrite(n int) {
if b.err != nil {
return
}
if b.child != nil {
panic("cryptobyte: attempted unwrite while child is pending")
}
length := len(b.result) - b.pendingLenLen - b.offset
if length < 0 {
panic("cryptobyte: internal error")
}
if n < 0 {
panic("cryptobyte: attempted to unwrite negative number of bytes")
}
if n > length {
panic("cryptobyte: attempted to unwrite more than was written")
}
b.result = b.result[:len(b.result)-n]
}
// 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
}
}
// 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 contains types that help with parsing and constructing
// length-prefixed, binary messages, including ASN.1 DER. (The asn1 subpackage
// contains useful ASN.1 constants.)
//
// The String type is for parsing. It wraps a []byte slice and provides helper
// functions for consuming structures, value by value.
//
// The Builder type is for constructing messages. It providers helper functions
// for appending values and also for appending length-prefixed submessages –
// without having to worry about calculating the length prefix ahead of time.
//
// See the documentation and 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 || n < 0 {
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 reports whether the read was successful.
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 reports whether the read was successful.
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 reports whether the read was successful.
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 reports whether the read was successful.
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
}
// ReadUint48 decodes a big-endian, 48-bit value into out and advances over it.
// It reports whether the read was successful.
func (s *String) ReadUint48(out *uint64) bool {
v := s.read(6)
if v == nil {
return false
}
*out = uint64(v[0])<<40 | uint64(v[1])<<32 | uint64(v[2])<<24 | uint64(v[3])<<16 | uint64(v[4])<<8 | uint64(v[5])
return true
}
// ReadUint64 decodes a big-endian, 64-bit value into out and advances over it.
// It reports whether the read was successful.
func (s *String) ReadUint64(out *uint64) bool {
v := s.read(8)
if v == nil {
return false
}
*out = uint64(v[0])<<56 | uint64(v[1])<<48 | uint64(v[2])<<40 | uint64(v[3])<<32 | uint64(v[4])<<24 | uint64(v[5])<<16 | uint64(v[6])<<8 | uint64(v[7])
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)
}
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 reports whether the read was successful.
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 reports whether the
// read was successful.
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 reports whether
// the read was successful.
func (s *String) ReadUint24LengthPrefixed(out *String) bool {
return s.readLengthPrefixed(3, out)
}
// ReadBytes reads n bytes into out and advances over them. It reports
// whether the read was successful.
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 reports
// whether the copy operation was successful
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
}
// Copyright 2019 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 curve25519 provides an implementation of the X25519 function, which
// performs scalar multiplication on the elliptic curve known as Curve25519
// according to [RFC 7748].
//
// The curve25519 package is a wrapper for the X25519 implementation in the
// crypto/ecdh package. It is [frozen] and is not accepting new features.
//
// [RFC 7748]: https://datatracker.ietf.org/doc/html/rfc7748
// [frozen]: https://go.dev/wiki/Frozen
package curve25519
import "crypto/ecdh"
// ScalarMult sets dst to the product scalar * point.
//
// Deprecated: when provided a low-order point, ScalarMult will set dst to all
// zeroes, irrespective of the scalar. Instead, use the X25519 function, which
// will return an error.
func ScalarMult(dst, scalar, point *[32]byte) {
if _, err := x25519(dst, scalar[:], point[:]); err != nil {
// The only error condition for x25519 when the inputs are 32 bytes long
// is if the output would have been the all-zero value.
for i := range dst {
dst[i] = 0
}
}
}
// ScalarBaseMult sets dst to the product scalar * base where base is the
// standard generator.
//
// It is recommended to use the X25519 function with Basepoint instead, as
// copying into fixed size arrays can lead to unexpected bugs.
func ScalarBaseMult(dst, scalar *[32]byte) {
curve := ecdh.X25519()
priv, err := curve.NewPrivateKey(scalar[:])
if err != nil {
panic("curve25519: " + err.Error())
}
copy(dst[:], priv.PublicKey().Bytes())
}
const (
// ScalarSize is the size of the scalar input to X25519.
ScalarSize = 32
// PointSize is the size of the point input to X25519.
PointSize = 32
)
// Basepoint is the canonical Curve25519 generator.
var Basepoint []byte
var basePoint = [32]byte{9}
func init() { Basepoint = basePoint[:] }
// X25519 returns the result of the scalar multiplication (scalar * point),
// according to RFC 7748, Section 5. scalar, point and the return value are
// slices of 32 bytes.
//
// scalar can be generated at random, for example with crypto/rand. point should
// be either Basepoint or the output of another X25519 call.
//
// If point is Basepoint (but not if it's a different slice with the same
// contents) a precomputed implementation might be used for performance.
func X25519(scalar, point []byte) ([]byte, error) {
// Outline the body of function, to let the allocation be inlined in the
// caller, and possibly avoid escaping to the heap.
var dst [32]byte
return x25519(&dst, scalar, point)
}
func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) {
curve := ecdh.X25519()
pub, err := curve.NewPublicKey(point)
if err != nil {
return nil, err
}
priv, err := curve.NewPrivateKey(scalar)
if err != nil {
return nil, err
}
out, err := priv.ECDH(pub)
if err != nil {
return nil, err
}
copy(dst[:], out)
return dst[:], nil
}
// Copyright 2019 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 ed25519 implements the Ed25519 signature algorithm.
//
// These functions are also compatible with the “Ed25519” function defined in
// [RFC 8032]. However, unlike RFC 8032's formulation, this package's private key
// representation includes a public key suffix to make multiple signing
// operations with the same key more efficient. This package refers to the RFC
// 8032 private key as the “seed”.
//
// The ed25519 package is a wrapper for the Ed25519 implementation in the
// crypto/ed25519 package. It is [frozen] and is not accepting new features.
//
// [RFC 8032]: https://datatracker.ietf.org/doc/html/rfc8032
// [frozen]: https://go.dev/wiki/Frozen
package ed25519
import (
"crypto/ed25519"
"io"
)
const (
// PublicKeySize is the size, in bytes, of public keys as used in this package.
PublicKeySize = 32
// PrivateKeySize is the size, in bytes, of private keys as used in this package.
PrivateKeySize = 64
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
SignatureSize = 64
// SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
SeedSize = 32
)
// PublicKey is the type of Ed25519 public keys.
//
// This type is an alias for crypto/ed25519's PublicKey type.
// See the crypto/ed25519 package for the methods on this type.
type PublicKey = ed25519.PublicKey
// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer.
//
// This type is an alias for crypto/ed25519's PrivateKey type.
// See the crypto/ed25519 package for the methods on this type.
type PrivateKey = ed25519.PrivateKey
// GenerateKey generates a public/private key pair using entropy from rand.
// If rand is nil, crypto/rand.Reader will be used.
func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
return ed25519.GenerateKey(rand)
}
// NewKeyFromSeed calculates a private key from a seed. It will panic if
// len(seed) is not SeedSize. This function is provided for interoperability
// with RFC 8032. RFC 8032's private keys correspond to seeds in this
// package.
func NewKeyFromSeed(seed []byte) PrivateKey {
return ed25519.NewKeyFromSeed(seed)
}
// Sign signs the message with privateKey and returns a signature. It will
// panic if len(privateKey) is not PrivateKeySize.
func Sign(privateKey PrivateKey, message []byte) []byte {
return ed25519.Sign(privateKey, message)
}
// Verify reports whether sig is a valid signature of message by publicKey. It
// will panic if len(publicKey) is not PublicKeySize.
func Verify(publicKey PublicKey, message, sig []byte) bool {
return ed25519.Verify(publicKey, message, sig)
}
//go:build gofuzz
package fuzz_ng_x_crypto_acme_autocert
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/acme/autocert"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_AcceptTOS:
autocert.AcceptTOS(a.AcceptTOS.TosURL)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_AcceptTOS:
w.WriteString(fmt.Sprintf("autocert.AcceptTOS(%#+v)\n", a.AcceptTOS.TosURL))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_acme_autocert
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type AcceptTOSArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
TosURL string `protobuf:"bytes,1,opt,name=tosURL,proto3" json:"tosURL,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *AcceptTOSArgs) Reset() {
*x = AcceptTOSArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AcceptTOSArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AcceptTOSArgs) ProtoMessage() {}
func (x *AcceptTOSArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AcceptTOSArgs.ProtoReflect.Descriptor instead.
func (*AcceptTOSArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *AcceptTOSArgs) GetTosURL() string {
if x != nil {
return x.TosURL
}
return ""
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_AcceptTOS
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetAcceptTOS() *AcceptTOSArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_AcceptTOS); ok {
return x.AcceptTOS
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_AcceptTOS struct {
AcceptTOS *AcceptTOSArgs `protobuf:"bytes,1,opt,name=AcceptTOS,proto3,oneof"`
}
func (*NgoloFuzzOne_AcceptTOS) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"'\n" +
"\rAcceptTOSArgs\x12\x16\n" +
"\x06tosURL\x18\x01 \x01(\tR\x06tosURL\"P\n" +
"\fNgoloFuzzOne\x128\n" +
"\tAcceptTOS\x18\x01 \x01(\v2\x18.ngolofuzz.AcceptTOSArgsH\x00R\tAcceptTOSB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB#Z!./;fuzz_ng_x_crypto_acme_autocertb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_ngolofuzz_proto_goTypes = []any{
(*AcceptTOSArgs)(nil), // 0: ngolofuzz.AcceptTOSArgs
(*NgoloFuzzOne)(nil), // 1: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 2: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 3: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.AcceptTOS:type_name -> ngolofuzz.AcceptTOSArgs
1, // 1: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[1].OneofWrappers = []any{
(*NgoloFuzzOne_AcceptTOS)(nil),
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_argon2
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/argon2"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Key:
arg4 := uint8(a.Key.Threads)
argon2.Key(a.Key.Password, a.Key.Salt, a.Key.Time, a.Key.Memory, arg4, a.Key.KeyLen)
case *NgoloFuzzOne_IDKey:
arg4 := uint8(a.IDKey.Threads)
argon2.IDKey(a.IDKey.Password, a.IDKey.Salt, a.IDKey.Time, a.IDKey.Memory, arg4, a.IDKey.KeyLen)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Key:
w.WriteString(fmt.Sprintf("argon2.Key(%#+v, %#+v, %#+v, %#+v, uint8(%#+v), %#+v)\n", a.Key.Password, a.Key.Salt, a.Key.Time, a.Key.Memory, a.Key.Threads, a.Key.KeyLen))
case *NgoloFuzzOne_IDKey:
w.WriteString(fmt.Sprintf("argon2.IDKey(%#+v, %#+v, %#+v, %#+v, uint8(%#+v), %#+v)\n", a.IDKey.Password, a.IDKey.Salt, a.IDKey.Time, a.IDKey.Memory, a.IDKey.Threads, a.IDKey.KeyLen))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_argon2
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type KeyArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Password []byte `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"`
Salt []byte `protobuf:"bytes,2,opt,name=salt,proto3" json:"salt,omitempty"`
Time uint32 `protobuf:"varint,3,opt,name=time,proto3" json:"time,omitempty"`
Memory uint32 `protobuf:"varint,4,opt,name=memory,proto3" json:"memory,omitempty"`
Threads uint32 `protobuf:"varint,5,opt,name=threads,proto3" json:"threads,omitempty"`
KeyLen uint32 `protobuf:"varint,6,opt,name=keyLen,proto3" json:"keyLen,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *KeyArgs) Reset() {
*x = KeyArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *KeyArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*KeyArgs) ProtoMessage() {}
func (x *KeyArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use KeyArgs.ProtoReflect.Descriptor instead.
func (*KeyArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *KeyArgs) GetPassword() []byte {
if x != nil {
return x.Password
}
return nil
}
func (x *KeyArgs) GetSalt() []byte {
if x != nil {
return x.Salt
}
return nil
}
func (x *KeyArgs) GetTime() uint32 {
if x != nil {
return x.Time
}
return 0
}
func (x *KeyArgs) GetMemory() uint32 {
if x != nil {
return x.Memory
}
return 0
}
func (x *KeyArgs) GetThreads() uint32 {
if x != nil {
return x.Threads
}
return 0
}
func (x *KeyArgs) GetKeyLen() uint32 {
if x != nil {
return x.KeyLen
}
return 0
}
type IDKeyArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Password []byte `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"`
Salt []byte `protobuf:"bytes,2,opt,name=salt,proto3" json:"salt,omitempty"`
Time uint32 `protobuf:"varint,3,opt,name=time,proto3" json:"time,omitempty"`
Memory uint32 `protobuf:"varint,4,opt,name=memory,proto3" json:"memory,omitempty"`
Threads uint32 `protobuf:"varint,5,opt,name=threads,proto3" json:"threads,omitempty"`
KeyLen uint32 `protobuf:"varint,6,opt,name=keyLen,proto3" json:"keyLen,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *IDKeyArgs) Reset() {
*x = IDKeyArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *IDKeyArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*IDKeyArgs) ProtoMessage() {}
func (x *IDKeyArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use IDKeyArgs.ProtoReflect.Descriptor instead.
func (*IDKeyArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *IDKeyArgs) GetPassword() []byte {
if x != nil {
return x.Password
}
return nil
}
func (x *IDKeyArgs) GetSalt() []byte {
if x != nil {
return x.Salt
}
return nil
}
func (x *IDKeyArgs) GetTime() uint32 {
if x != nil {
return x.Time
}
return 0
}
func (x *IDKeyArgs) GetMemory() uint32 {
if x != nil {
return x.Memory
}
return 0
}
func (x *IDKeyArgs) GetThreads() uint32 {
if x != nil {
return x.Threads
}
return 0
}
func (x *IDKeyArgs) GetKeyLen() uint32 {
if x != nil {
return x.KeyLen
}
return 0
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_Key
// *NgoloFuzzOne_IDKey
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetKey() *KeyArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Key); ok {
return x.Key
}
}
return nil
}
func (x *NgoloFuzzOne) GetIDKey() *IDKeyArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_IDKey); ok {
return x.IDKey
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_Key struct {
Key *KeyArgs `protobuf:"bytes,1,opt,name=Key,proto3,oneof"`
}
type NgoloFuzzOne_IDKey struct {
IDKey *IDKeyArgs `protobuf:"bytes,2,opt,name=IDKey,proto3,oneof"`
}
func (*NgoloFuzzOne_Key) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_IDKey) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x97\x01\n" +
"\aKeyArgs\x12\x1a\n" +
"\bpassword\x18\x01 \x01(\fR\bpassword\x12\x12\n" +
"\x04salt\x18\x02 \x01(\fR\x04salt\x12\x12\n" +
"\x04time\x18\x03 \x01(\rR\x04time\x12\x16\n" +
"\x06memory\x18\x04 \x01(\rR\x06memory\x12\x18\n" +
"\athreads\x18\x05 \x01(\rR\athreads\x12\x16\n" +
"\x06keyLen\x18\x06 \x01(\rR\x06keyLen\"\x99\x01\n" +
"\tIDKeyArgs\x12\x1a\n" +
"\bpassword\x18\x01 \x01(\fR\bpassword\x12\x12\n" +
"\x04salt\x18\x02 \x01(\fR\x04salt\x12\x12\n" +
"\x04time\x18\x03 \x01(\rR\x04time\x12\x16\n" +
"\x06memory\x18\x04 \x01(\rR\x06memory\x12\x18\n" +
"\athreads\x18\x05 \x01(\rR\athreads\x12\x16\n" +
"\x06keyLen\x18\x06 \x01(\rR\x06keyLen\"l\n" +
"\fNgoloFuzzOne\x12&\n" +
"\x03Key\x18\x01 \x01(\v2\x12.ngolofuzz.KeyArgsH\x00R\x03Key\x12,\n" +
"\x05IDKey\x18\x02 \x01(\v2\x14.ngolofuzz.IDKeyArgsH\x00R\x05IDKeyB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1cZ\x1a./;fuzz_ng_x_crypto_argon2b\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_ngolofuzz_proto_goTypes = []any{
(*KeyArgs)(nil), // 0: ngolofuzz.KeyArgs
(*IDKeyArgs)(nil), // 1: ngolofuzz.IDKeyArgs
(*NgoloFuzzOne)(nil), // 2: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 3: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 4: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.Key:type_name -> ngolofuzz.KeyArgs
1, // 1: ngolofuzz.NgoloFuzzOne.IDKey:type_name -> ngolofuzz.IDKeyArgs
2, // 2: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzOne_Key)(nil),
(*NgoloFuzzOne_IDKey)(nil),
}
file_ngolofuzz_proto_msgTypes[3].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_bcrypt
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/bcrypt"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_GenerateFromPassword:
arg1 := int(a.GenerateFromPassword.Cost)
_, r1 := bcrypt.GenerateFromPassword(a.GenerateFromPassword.Password, arg1)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_CompareHashAndPassword:
r0 := bcrypt.CompareHashAndPassword(a.CompareHashAndPassword.HashedPassword, a.CompareHashAndPassword.Password)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_Cost:
_, r1 := bcrypt.Cost(a.Cost.HashedPassword)
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_GenerateFromPassword:
w.WriteString(fmt.Sprintf("bcrypt.GenerateFromPassword(%#+v, int(%#+v))\n", a.GenerateFromPassword.Password, a.GenerateFromPassword.Cost))
case *NgoloFuzzOne_CompareHashAndPassword:
w.WriteString(fmt.Sprintf("bcrypt.CompareHashAndPassword(%#+v, %#+v)\n", a.CompareHashAndPassword.HashedPassword, a.CompareHashAndPassword.Password))
case *NgoloFuzzOne_Cost:
w.WriteString(fmt.Sprintf("bcrypt.Cost(%#+v)\n", a.Cost.HashedPassword))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_bcrypt
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type GenerateFromPasswordArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Password []byte `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"`
Cost int64 `protobuf:"varint,2,opt,name=cost,proto3" json:"cost,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GenerateFromPasswordArgs) Reset() {
*x = GenerateFromPasswordArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GenerateFromPasswordArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GenerateFromPasswordArgs) ProtoMessage() {}
func (x *GenerateFromPasswordArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GenerateFromPasswordArgs.ProtoReflect.Descriptor instead.
func (*GenerateFromPasswordArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *GenerateFromPasswordArgs) GetPassword() []byte {
if x != nil {
return x.Password
}
return nil
}
func (x *GenerateFromPasswordArgs) GetCost() int64 {
if x != nil {
return x.Cost
}
return 0
}
type CompareHashAndPasswordArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
HashedPassword []byte `protobuf:"bytes,1,opt,name=hashedPassword,proto3" json:"hashedPassword,omitempty"`
Password []byte `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CompareHashAndPasswordArgs) Reset() {
*x = CompareHashAndPasswordArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CompareHashAndPasswordArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CompareHashAndPasswordArgs) ProtoMessage() {}
func (x *CompareHashAndPasswordArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CompareHashAndPasswordArgs.ProtoReflect.Descriptor instead.
func (*CompareHashAndPasswordArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *CompareHashAndPasswordArgs) GetHashedPassword() []byte {
if x != nil {
return x.HashedPassword
}
return nil
}
func (x *CompareHashAndPasswordArgs) GetPassword() []byte {
if x != nil {
return x.Password
}
return nil
}
type CostArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
HashedPassword []byte `protobuf:"bytes,1,opt,name=hashedPassword,proto3" json:"hashedPassword,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CostArgs) Reset() {
*x = CostArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CostArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CostArgs) ProtoMessage() {}
func (x *CostArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CostArgs.ProtoReflect.Descriptor instead.
func (*CostArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *CostArgs) GetHashedPassword() []byte {
if x != nil {
return x.HashedPassword
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_GenerateFromPassword
// *NgoloFuzzOne_CompareHashAndPassword
// *NgoloFuzzOne_Cost
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetGenerateFromPassword() *GenerateFromPasswordArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_GenerateFromPassword); ok {
return x.GenerateFromPassword
}
}
return nil
}
func (x *NgoloFuzzOne) GetCompareHashAndPassword() *CompareHashAndPasswordArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CompareHashAndPassword); ok {
return x.CompareHashAndPassword
}
}
return nil
}
func (x *NgoloFuzzOne) GetCost() *CostArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Cost); ok {
return x.Cost
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_GenerateFromPassword struct {
GenerateFromPassword *GenerateFromPasswordArgs `protobuf:"bytes,1,opt,name=GenerateFromPassword,proto3,oneof"`
}
type NgoloFuzzOne_CompareHashAndPassword struct {
CompareHashAndPassword *CompareHashAndPasswordArgs `protobuf:"bytes,2,opt,name=CompareHashAndPassword,proto3,oneof"`
}
type NgoloFuzzOne_Cost struct {
Cost *CostArgs `protobuf:"bytes,3,opt,name=Cost,proto3,oneof"`
}
func (*NgoloFuzzOne_GenerateFromPassword) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CompareHashAndPassword) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Cost) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"J\n" +
"\x18GenerateFromPasswordArgs\x12\x1a\n" +
"\bpassword\x18\x01 \x01(\fR\bpassword\x12\x12\n" +
"\x04cost\x18\x02 \x01(\x03R\x04cost\"`\n" +
"\x1aCompareHashAndPasswordArgs\x12&\n" +
"\x0ehashedPassword\x18\x01 \x01(\fR\x0ehashedPassword\x12\x1a\n" +
"\bpassword\x18\x02 \x01(\fR\bpassword\"2\n" +
"\bCostArgs\x12&\n" +
"\x0ehashedPassword\x18\x01 \x01(\fR\x0ehashedPassword\"\xfd\x01\n" +
"\fNgoloFuzzOne\x12Y\n" +
"\x14GenerateFromPassword\x18\x01 \x01(\v2#.ngolofuzz.GenerateFromPasswordArgsH\x00R\x14GenerateFromPassword\x12_\n" +
"\x16CompareHashAndPassword\x18\x02 \x01(\v2%.ngolofuzz.CompareHashAndPasswordArgsH\x00R\x16CompareHashAndPassword\x12)\n" +
"\x04Cost\x18\x03 \x01(\v2\x13.ngolofuzz.CostArgsH\x00R\x04CostB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1cZ\x1a./;fuzz_ng_x_crypto_bcryptb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_ngolofuzz_proto_goTypes = []any{
(*GenerateFromPasswordArgs)(nil), // 0: ngolofuzz.GenerateFromPasswordArgs
(*CompareHashAndPasswordArgs)(nil), // 1: ngolofuzz.CompareHashAndPasswordArgs
(*CostArgs)(nil), // 2: ngolofuzz.CostArgs
(*NgoloFuzzOne)(nil), // 3: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 4: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 5: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.GenerateFromPassword:type_name -> ngolofuzz.GenerateFromPasswordArgs
1, // 1: ngolofuzz.NgoloFuzzOne.CompareHashAndPassword:type_name -> ngolofuzz.CompareHashAndPasswordArgs
2, // 2: ngolofuzz.NgoloFuzzOne.Cost:type_name -> ngolofuzz.CostArgs
3, // 3: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[3].OneofWrappers = []any{
(*NgoloFuzzOne_GenerateFromPassword)(nil),
(*NgoloFuzzOne_CompareHashAndPassword)(nil),
(*NgoloFuzzOne_Cost)(nil),
}
file_ngolofuzz_proto_msgTypes[4].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 6,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_blake2b
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/blake2b"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Sum512:
blake2b.Sum512(a.Sum512.Data)
case *NgoloFuzzOne_Sum384:
blake2b.Sum384(a.Sum384.Data)
case *NgoloFuzzOne_Sum256:
blake2b.Sum256(a.Sum256.Data)
case *NgoloFuzzOne_New512:
_, r1 := blake2b.New512(a.New512.Key)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_New384:
_, r1 := blake2b.New384(a.New384.Key)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_New256:
_, r1 := blake2b.New256(a.New256.Key)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_New:
arg0 := int(a.New.Size)
_, r1 := blake2b.New(arg0, a.New.Key)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_NewXOF:
_, r1 := blake2b.NewXOF(a.NewXOF.Size, a.NewXOF.Key)
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Sum512:
w.WriteString(fmt.Sprintf("blake2b.Sum512(%#+v)\n", a.Sum512.Data))
case *NgoloFuzzOne_Sum384:
w.WriteString(fmt.Sprintf("blake2b.Sum384(%#+v)\n", a.Sum384.Data))
case *NgoloFuzzOne_Sum256:
w.WriteString(fmt.Sprintf("blake2b.Sum256(%#+v)\n", a.Sum256.Data))
case *NgoloFuzzOne_New512:
w.WriteString(fmt.Sprintf("blake2b.New512(%#+v)\n", a.New512.Key))
case *NgoloFuzzOne_New384:
w.WriteString(fmt.Sprintf("blake2b.New384(%#+v)\n", a.New384.Key))
case *NgoloFuzzOne_New256:
w.WriteString(fmt.Sprintf("blake2b.New256(%#+v)\n", a.New256.Key))
case *NgoloFuzzOne_New:
w.WriteString(fmt.Sprintf("blake2b.New(int(%#+v), %#+v)\n", a.New.Size, a.New.Key))
case *NgoloFuzzOne_NewXOF:
w.WriteString(fmt.Sprintf("blake2b.NewXOF(%#+v, %#+v)\n", a.NewXOF.Size, a.NewXOF.Key))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_blake2b
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Sum512Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Sum512Args) Reset() {
*x = Sum512Args{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Sum512Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Sum512Args) ProtoMessage() {}
func (x *Sum512Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Sum512Args.ProtoReflect.Descriptor instead.
func (*Sum512Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *Sum512Args) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
type Sum384Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Sum384Args) Reset() {
*x = Sum384Args{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Sum384Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Sum384Args) ProtoMessage() {}
func (x *Sum384Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Sum384Args.ProtoReflect.Descriptor instead.
func (*Sum384Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *Sum384Args) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
type Sum256Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Sum256Args) Reset() {
*x = Sum256Args{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Sum256Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Sum256Args) ProtoMessage() {}
func (x *Sum256Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Sum256Args.ProtoReflect.Descriptor instead.
func (*Sum256Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *Sum256Args) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
type New512Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *New512Args) Reset() {
*x = New512Args{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *New512Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*New512Args) ProtoMessage() {}
func (x *New512Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use New512Args.ProtoReflect.Descriptor instead.
func (*New512Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *New512Args) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
type New384Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *New384Args) Reset() {
*x = New384Args{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *New384Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*New384Args) ProtoMessage() {}
func (x *New384Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use New384Args.ProtoReflect.Descriptor instead.
func (*New384Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *New384Args) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
type New256Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *New256Args) Reset() {
*x = New256Args{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *New256Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*New256Args) ProtoMessage() {}
func (x *New256Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use New256Args.ProtoReflect.Descriptor instead.
func (*New256Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *New256Args) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
type NewArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Size int64 `protobuf:"varint,1,opt,name=size,proto3" json:"size,omitempty"`
Key []byte `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewArgs) Reset() {
*x = NewArgs{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewArgs) ProtoMessage() {}
func (x *NewArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewArgs.ProtoReflect.Descriptor instead.
func (*NewArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *NewArgs) GetSize() int64 {
if x != nil {
return x.Size
}
return 0
}
func (x *NewArgs) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
type NewXOFArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Size uint32 `protobuf:"varint,1,opt,name=size,proto3" json:"size,omitempty"`
Key []byte `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewXOFArgs) Reset() {
*x = NewXOFArgs{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewXOFArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewXOFArgs) ProtoMessage() {}
func (x *NewXOFArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewXOFArgs.ProtoReflect.Descriptor instead.
func (*NewXOFArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
func (x *NewXOFArgs) GetSize() uint32 {
if x != nil {
return x.Size
}
return 0
}
func (x *NewXOFArgs) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_Sum512
// *NgoloFuzzOne_Sum384
// *NgoloFuzzOne_Sum256
// *NgoloFuzzOne_New512
// *NgoloFuzzOne_New384
// *NgoloFuzzOne_New256
// *NgoloFuzzOne_New
// *NgoloFuzzOne_NewXOF
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetSum512() *Sum512Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Sum512); ok {
return x.Sum512
}
}
return nil
}
func (x *NgoloFuzzOne) GetSum384() *Sum384Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Sum384); ok {
return x.Sum384
}
}
return nil
}
func (x *NgoloFuzzOne) GetSum256() *Sum256Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Sum256); ok {
return x.Sum256
}
}
return nil
}
func (x *NgoloFuzzOne) GetNew512() *New512Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_New512); ok {
return x.New512
}
}
return nil
}
func (x *NgoloFuzzOne) GetNew384() *New384Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_New384); ok {
return x.New384
}
}
return nil
}
func (x *NgoloFuzzOne) GetNew256() *New256Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_New256); ok {
return x.New256
}
}
return nil
}
func (x *NgoloFuzzOne) GetNew() *NewArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_New); ok {
return x.New
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewXOF() *NewXOFArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewXOF); ok {
return x.NewXOF
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_Sum512 struct {
Sum512 *Sum512Args `protobuf:"bytes,1,opt,name=Sum512,proto3,oneof"`
}
type NgoloFuzzOne_Sum384 struct {
Sum384 *Sum384Args `protobuf:"bytes,2,opt,name=Sum384,proto3,oneof"`
}
type NgoloFuzzOne_Sum256 struct {
Sum256 *Sum256Args `protobuf:"bytes,3,opt,name=Sum256,proto3,oneof"`
}
type NgoloFuzzOne_New512 struct {
New512 *New512Args `protobuf:"bytes,4,opt,name=New512,proto3,oneof"`
}
type NgoloFuzzOne_New384 struct {
New384 *New384Args `protobuf:"bytes,5,opt,name=New384,proto3,oneof"`
}
type NgoloFuzzOne_New256 struct {
New256 *New256Args `protobuf:"bytes,6,opt,name=New256,proto3,oneof"`
}
type NgoloFuzzOne_New struct {
New *NewArgs `protobuf:"bytes,7,opt,name=New,proto3,oneof"`
}
type NgoloFuzzOne_NewXOF struct {
NewXOF *NewXOFArgs `protobuf:"bytes,8,opt,name=NewXOF,proto3,oneof"`
}
func (*NgoloFuzzOne_Sum512) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Sum384) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Sum256) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_New512) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_New384) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_New256) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_New) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewXOF) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{10}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\" \n" +
"\n" +
"Sum512Args\x12\x12\n" +
"\x04data\x18\x01 \x01(\fR\x04data\" \n" +
"\n" +
"Sum384Args\x12\x12\n" +
"\x04data\x18\x01 \x01(\fR\x04data\" \n" +
"\n" +
"Sum256Args\x12\x12\n" +
"\x04data\x18\x01 \x01(\fR\x04data\"\x1e\n" +
"\n" +
"New512Args\x12\x10\n" +
"\x03key\x18\x01 \x01(\fR\x03key\"\x1e\n" +
"\n" +
"New384Args\x12\x10\n" +
"\x03key\x18\x01 \x01(\fR\x03key\"\x1e\n" +
"\n" +
"New256Args\x12\x10\n" +
"\x03key\x18\x01 \x01(\fR\x03key\"/\n" +
"\aNewArgs\x12\x12\n" +
"\x04size\x18\x01 \x01(\x03R\x04size\x12\x10\n" +
"\x03key\x18\x02 \x01(\fR\x03key\"2\n" +
"\n" +
"NewXOFArgs\x12\x12\n" +
"\x04size\x18\x01 \x01(\rR\x04size\x12\x10\n" +
"\x03key\x18\x02 \x01(\fR\x03key\"\x95\x03\n" +
"\fNgoloFuzzOne\x12/\n" +
"\x06Sum512\x18\x01 \x01(\v2\x15.ngolofuzz.Sum512ArgsH\x00R\x06Sum512\x12/\n" +
"\x06Sum384\x18\x02 \x01(\v2\x15.ngolofuzz.Sum384ArgsH\x00R\x06Sum384\x12/\n" +
"\x06Sum256\x18\x03 \x01(\v2\x15.ngolofuzz.Sum256ArgsH\x00R\x06Sum256\x12/\n" +
"\x06New512\x18\x04 \x01(\v2\x15.ngolofuzz.New512ArgsH\x00R\x06New512\x12/\n" +
"\x06New384\x18\x05 \x01(\v2\x15.ngolofuzz.New384ArgsH\x00R\x06New384\x12/\n" +
"\x06New256\x18\x06 \x01(\v2\x15.ngolofuzz.New256ArgsH\x00R\x06New256\x12&\n" +
"\x03New\x18\a \x01(\v2\x12.ngolofuzz.NewArgsH\x00R\x03New\x12/\n" +
"\x06NewXOF\x18\b \x01(\v2\x15.ngolofuzz.NewXOFArgsH\x00R\x06NewXOFB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1dZ\x1b./;fuzz_ng_x_crypto_blake2bb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
var file_ngolofuzz_proto_goTypes = []any{
(*Sum512Args)(nil), // 0: ngolofuzz.Sum512Args
(*Sum384Args)(nil), // 1: ngolofuzz.Sum384Args
(*Sum256Args)(nil), // 2: ngolofuzz.Sum256Args
(*New512Args)(nil), // 3: ngolofuzz.New512Args
(*New384Args)(nil), // 4: ngolofuzz.New384Args
(*New256Args)(nil), // 5: ngolofuzz.New256Args
(*NewArgs)(nil), // 6: ngolofuzz.NewArgs
(*NewXOFArgs)(nil), // 7: ngolofuzz.NewXOFArgs
(*NgoloFuzzOne)(nil), // 8: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 9: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 10: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.Sum512:type_name -> ngolofuzz.Sum512Args
1, // 1: ngolofuzz.NgoloFuzzOne.Sum384:type_name -> ngolofuzz.Sum384Args
2, // 2: ngolofuzz.NgoloFuzzOne.Sum256:type_name -> ngolofuzz.Sum256Args
3, // 3: ngolofuzz.NgoloFuzzOne.New512:type_name -> ngolofuzz.New512Args
4, // 4: ngolofuzz.NgoloFuzzOne.New384:type_name -> ngolofuzz.New384Args
5, // 5: ngolofuzz.NgoloFuzzOne.New256:type_name -> ngolofuzz.New256Args
6, // 6: ngolofuzz.NgoloFuzzOne.New:type_name -> ngolofuzz.NewArgs
7, // 7: ngolofuzz.NgoloFuzzOne.NewXOF:type_name -> ngolofuzz.NewXOFArgs
8, // 8: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
9, // [9:9] is the sub-list for method output_type
9, // [9:9] is the sub-list for method input_type
9, // [9:9] is the sub-list for extension type_name
9, // [9:9] is the sub-list for extension extendee
0, // [0:9] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[8].OneofWrappers = []any{
(*NgoloFuzzOne_Sum512)(nil),
(*NgoloFuzzOne_Sum384)(nil),
(*NgoloFuzzOne_Sum256)(nil),
(*NgoloFuzzOne_New512)(nil),
(*NgoloFuzzOne_New384)(nil),
(*NgoloFuzzOne_New256)(nil),
(*NgoloFuzzOne_New)(nil),
(*NgoloFuzzOne_NewXOF)(nil),
}
file_ngolofuzz_proto_msgTypes[9].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 11,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_blake2s
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/blake2s"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Sum256:
blake2s.Sum256(a.Sum256.Data)
case *NgoloFuzzOne_New256:
_, r1 := blake2s.New256(a.New256.Key)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_New128:
_, r1 := blake2s.New128(a.New128.Key)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_NewXOF:
arg0 := uint16(a.NewXOF.Size)
_, r1 := blake2s.NewXOF(arg0, a.NewXOF.Key)
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Sum256:
w.WriteString(fmt.Sprintf("blake2s.Sum256(%#+v)\n", a.Sum256.Data))
case *NgoloFuzzOne_New256:
w.WriteString(fmt.Sprintf("blake2s.New256(%#+v)\n", a.New256.Key))
case *NgoloFuzzOne_New128:
w.WriteString(fmt.Sprintf("blake2s.New128(%#+v)\n", a.New128.Key))
case *NgoloFuzzOne_NewXOF:
w.WriteString(fmt.Sprintf("blake2s.NewXOF(uint16(%#+v), %#+v)\n", a.NewXOF.Size, a.NewXOF.Key))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_blake2s
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Sum256Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Sum256Args) Reset() {
*x = Sum256Args{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Sum256Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Sum256Args) ProtoMessage() {}
func (x *Sum256Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Sum256Args.ProtoReflect.Descriptor instead.
func (*Sum256Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *Sum256Args) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
type New256Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *New256Args) Reset() {
*x = New256Args{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *New256Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*New256Args) ProtoMessage() {}
func (x *New256Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use New256Args.ProtoReflect.Descriptor instead.
func (*New256Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *New256Args) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
type New128Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *New128Args) Reset() {
*x = New128Args{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *New128Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*New128Args) ProtoMessage() {}
func (x *New128Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use New128Args.ProtoReflect.Descriptor instead.
func (*New128Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *New128Args) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
type NewXOFArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Size uint32 `protobuf:"varint,1,opt,name=size,proto3" json:"size,omitempty"`
Key []byte `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewXOFArgs) Reset() {
*x = NewXOFArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewXOFArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewXOFArgs) ProtoMessage() {}
func (x *NewXOFArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewXOFArgs.ProtoReflect.Descriptor instead.
func (*NewXOFArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NewXOFArgs) GetSize() uint32 {
if x != nil {
return x.Size
}
return 0
}
func (x *NewXOFArgs) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_Sum256
// *NgoloFuzzOne_New256
// *NgoloFuzzOne_New128
// *NgoloFuzzOne_NewXOF
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetSum256() *Sum256Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Sum256); ok {
return x.Sum256
}
}
return nil
}
func (x *NgoloFuzzOne) GetNew256() *New256Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_New256); ok {
return x.New256
}
}
return nil
}
func (x *NgoloFuzzOne) GetNew128() *New128Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_New128); ok {
return x.New128
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewXOF() *NewXOFArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewXOF); ok {
return x.NewXOF
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_Sum256 struct {
Sum256 *Sum256Args `protobuf:"bytes,1,opt,name=Sum256,proto3,oneof"`
}
type NgoloFuzzOne_New256 struct {
New256 *New256Args `protobuf:"bytes,2,opt,name=New256,proto3,oneof"`
}
type NgoloFuzzOne_New128 struct {
New128 *New128Args `protobuf:"bytes,3,opt,name=New128,proto3,oneof"`
}
type NgoloFuzzOne_NewXOF struct {
NewXOF *NewXOFArgs `protobuf:"bytes,4,opt,name=NewXOF,proto3,oneof"`
}
func (*NgoloFuzzOne_Sum256) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_New256) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_New128) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewXOF) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\" \n" +
"\n" +
"Sum256Args\x12\x12\n" +
"\x04data\x18\x01 \x01(\fR\x04data\"\x1e\n" +
"\n" +
"New256Args\x12\x10\n" +
"\x03key\x18\x01 \x01(\fR\x03key\"\x1e\n" +
"\n" +
"New128Args\x12\x10\n" +
"\x03key\x18\x01 \x01(\fR\x03key\"2\n" +
"\n" +
"NewXOFArgs\x12\x12\n" +
"\x04size\x18\x01 \x01(\rR\x04size\x12\x10\n" +
"\x03key\x18\x02 \x01(\fR\x03key\"\xda\x01\n" +
"\fNgoloFuzzOne\x12/\n" +
"\x06Sum256\x18\x01 \x01(\v2\x15.ngolofuzz.Sum256ArgsH\x00R\x06Sum256\x12/\n" +
"\x06New256\x18\x02 \x01(\v2\x15.ngolofuzz.New256ArgsH\x00R\x06New256\x12/\n" +
"\x06New128\x18\x03 \x01(\v2\x15.ngolofuzz.New128ArgsH\x00R\x06New128\x12/\n" +
"\x06NewXOF\x18\x04 \x01(\v2\x15.ngolofuzz.NewXOFArgsH\x00R\x06NewXOFB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1dZ\x1b./;fuzz_ng_x_crypto_blake2sb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_ngolofuzz_proto_goTypes = []any{
(*Sum256Args)(nil), // 0: ngolofuzz.Sum256Args
(*New256Args)(nil), // 1: ngolofuzz.New256Args
(*New128Args)(nil), // 2: ngolofuzz.New128Args
(*NewXOFArgs)(nil), // 3: ngolofuzz.NewXOFArgs
(*NgoloFuzzOne)(nil), // 4: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 5: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 6: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.Sum256:type_name -> ngolofuzz.Sum256Args
1, // 1: ngolofuzz.NgoloFuzzOne.New256:type_name -> ngolofuzz.New256Args
2, // 2: ngolofuzz.NgoloFuzzOne.New128:type_name -> ngolofuzz.New128Args
3, // 3: ngolofuzz.NgoloFuzzOne.NewXOF:type_name -> ngolofuzz.NewXOFArgs
4, // 4: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[4].OneofWrappers = []any{
(*NgoloFuzzOne_Sum256)(nil),
(*NgoloFuzzOne_New256)(nil),
(*NgoloFuzzOne_New128)(nil),
(*NgoloFuzzOne_NewXOF)(nil),
}
file_ngolofuzz_proto_msgTypes[5].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 7,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_blowfish
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/blowfish"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var CipherResults []*blowfish.Cipher
CipherResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_ExpandKey:
if len(CipherResults) == 0 {
continue
}
arg1 := CipherResults[CipherResultsIndex]
CipherResultsIndex = (CipherResultsIndex + 1) % len(CipherResults)
blowfish.ExpandKey(a.ExpandKey.Key, arg1)
case *NgoloFuzzOne_NewCipher:
r0, r1 := blowfish.NewCipher(a.NewCipher.Key)
if r0 != nil{
CipherResults = append(CipherResults, r0)
}
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_NewSaltedCipher:
r0, r1 := blowfish.NewSaltedCipher(a.NewSaltedCipher.Key, a.NewSaltedCipher.Salt)
if r0 != nil{
CipherResults = append(CipherResults, r0)
}
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_CipherNgdotBlockSize:
if len(CipherResults) == 0 {
continue
}
arg0 := CipherResults[CipherResultsIndex]
CipherResultsIndex = (CipherResultsIndex + 1) % len(CipherResults)
arg0.BlockSize()
case *NgoloFuzzOne_CipherNgdotEncrypt:
if len(CipherResults) == 0 {
continue
}
arg0 := CipherResults[CipherResultsIndex]
CipherResultsIndex = (CipherResultsIndex + 1) % len(CipherResults)
a.CipherNgdotEncrypt.Dst = make([]byte, 2*len(a.CipherNgdotEncrypt.Src))
arg0.Encrypt(a.CipherNgdotEncrypt.Dst, a.CipherNgdotEncrypt.Src)
case *NgoloFuzzOne_CipherNgdotDecrypt:
if len(CipherResults) == 0 {
continue
}
arg0 := CipherResults[CipherResultsIndex]
CipherResultsIndex = (CipherResultsIndex + 1) % len(CipherResults)
a.CipherNgdotDecrypt.Dst = make([]byte, 2*len(a.CipherNgdotDecrypt.Src))
arg0.Decrypt(a.CipherNgdotDecrypt.Dst, a.CipherNgdotDecrypt.Src)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
CipherNb := 0
CipherResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_ExpandKey:
if CipherNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("blowfish.ExpandKey(%#+v, Cipher%d)\n", a.ExpandKey.Key, (CipherResultsIndex + 0) % CipherNb))
CipherResultsIndex = (CipherResultsIndex + 1) % CipherNb
case *NgoloFuzzOne_NewCipher:
w.WriteString(fmt.Sprintf("Cipher%d, _ := blowfish.NewCipher(%#+v)\n", CipherNb, a.NewCipher.Key))
CipherNb = CipherNb + 1
case *NgoloFuzzOne_NewSaltedCipher:
w.WriteString(fmt.Sprintf("Cipher%d, _ := blowfish.NewSaltedCipher(%#+v, %#+v)\n", CipherNb, a.NewSaltedCipher.Key, a.NewSaltedCipher.Salt))
CipherNb = CipherNb + 1
case *NgoloFuzzOne_CipherNgdotBlockSize:
if CipherNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Cipher%d.BlockSize()\n", CipherResultsIndex))
CipherResultsIndex = (CipherResultsIndex + 1) % CipherNb
case *NgoloFuzzOne_CipherNgdotEncrypt:
if CipherNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Cipher%d.Encrypt(%#+v, %#+v)\n", CipherResultsIndex, a.CipherNgdotEncrypt.Dst, a.CipherNgdotEncrypt.Src))
CipherResultsIndex = (CipherResultsIndex + 1) % CipherNb
case *NgoloFuzzOne_CipherNgdotDecrypt:
if CipherNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Cipher%d.Decrypt(%#+v, %#+v)\n", CipherResultsIndex, a.CipherNgdotDecrypt.Dst, a.CipherNgdotDecrypt.Src))
CipherResultsIndex = (CipherResultsIndex + 1) % CipherNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_blowfish
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ExpandKeyArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ExpandKeyArgs) Reset() {
*x = ExpandKeyArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ExpandKeyArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ExpandKeyArgs) ProtoMessage() {}
func (x *ExpandKeyArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ExpandKeyArgs.ProtoReflect.Descriptor instead.
func (*ExpandKeyArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *ExpandKeyArgs) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
type NewCipherArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewCipherArgs) Reset() {
*x = NewCipherArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewCipherArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewCipherArgs) ProtoMessage() {}
func (x *NewCipherArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewCipherArgs.ProtoReflect.Descriptor instead.
func (*NewCipherArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *NewCipherArgs) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
type NewSaltedCipherArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Salt []byte `protobuf:"bytes,2,opt,name=salt,proto3" json:"salt,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewSaltedCipherArgs) Reset() {
*x = NewSaltedCipherArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewSaltedCipherArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewSaltedCipherArgs) ProtoMessage() {}
func (x *NewSaltedCipherArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewSaltedCipherArgs.ProtoReflect.Descriptor instead.
func (*NewSaltedCipherArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NewSaltedCipherArgs) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
func (x *NewSaltedCipherArgs) GetSalt() []byte {
if x != nil {
return x.Salt
}
return nil
}
type CipherNgdotBlockSizeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CipherNgdotBlockSizeArgs) Reset() {
*x = CipherNgdotBlockSizeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CipherNgdotBlockSizeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CipherNgdotBlockSizeArgs) ProtoMessage() {}
func (x *CipherNgdotBlockSizeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CipherNgdotBlockSizeArgs.ProtoReflect.Descriptor instead.
func (*CipherNgdotBlockSizeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
type CipherNgdotEncryptArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Dst []byte `protobuf:"bytes,1,opt,name=dst,proto3" json:"dst,omitempty"`
Src []byte `protobuf:"bytes,2,opt,name=src,proto3" json:"src,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CipherNgdotEncryptArgs) Reset() {
*x = CipherNgdotEncryptArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CipherNgdotEncryptArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CipherNgdotEncryptArgs) ProtoMessage() {}
func (x *CipherNgdotEncryptArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CipherNgdotEncryptArgs.ProtoReflect.Descriptor instead.
func (*CipherNgdotEncryptArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *CipherNgdotEncryptArgs) GetDst() []byte {
if x != nil {
return x.Dst
}
return nil
}
func (x *CipherNgdotEncryptArgs) GetSrc() []byte {
if x != nil {
return x.Src
}
return nil
}
type CipherNgdotDecryptArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Dst []byte `protobuf:"bytes,1,opt,name=dst,proto3" json:"dst,omitempty"`
Src []byte `protobuf:"bytes,2,opt,name=src,proto3" json:"src,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CipherNgdotDecryptArgs) Reset() {
*x = CipherNgdotDecryptArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CipherNgdotDecryptArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CipherNgdotDecryptArgs) ProtoMessage() {}
func (x *CipherNgdotDecryptArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CipherNgdotDecryptArgs.ProtoReflect.Descriptor instead.
func (*CipherNgdotDecryptArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *CipherNgdotDecryptArgs) GetDst() []byte {
if x != nil {
return x.Dst
}
return nil
}
func (x *CipherNgdotDecryptArgs) GetSrc() []byte {
if x != nil {
return x.Src
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_ExpandKey
// *NgoloFuzzOne_NewCipher
// *NgoloFuzzOne_NewSaltedCipher
// *NgoloFuzzOne_CipherNgdotBlockSize
// *NgoloFuzzOne_CipherNgdotEncrypt
// *NgoloFuzzOne_CipherNgdotDecrypt
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetExpandKey() *ExpandKeyArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ExpandKey); ok {
return x.ExpandKey
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewCipher() *NewCipherArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewCipher); ok {
return x.NewCipher
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewSaltedCipher() *NewSaltedCipherArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewSaltedCipher); ok {
return x.NewSaltedCipher
}
}
return nil
}
func (x *NgoloFuzzOne) GetCipherNgdotBlockSize() *CipherNgdotBlockSizeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CipherNgdotBlockSize); ok {
return x.CipherNgdotBlockSize
}
}
return nil
}
func (x *NgoloFuzzOne) GetCipherNgdotEncrypt() *CipherNgdotEncryptArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CipherNgdotEncrypt); ok {
return x.CipherNgdotEncrypt
}
}
return nil
}
func (x *NgoloFuzzOne) GetCipherNgdotDecrypt() *CipherNgdotDecryptArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CipherNgdotDecrypt); ok {
return x.CipherNgdotDecrypt
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_ExpandKey struct {
ExpandKey *ExpandKeyArgs `protobuf:"bytes,1,opt,name=ExpandKey,proto3,oneof"`
}
type NgoloFuzzOne_NewCipher struct {
NewCipher *NewCipherArgs `protobuf:"bytes,2,opt,name=NewCipher,proto3,oneof"`
}
type NgoloFuzzOne_NewSaltedCipher struct {
NewSaltedCipher *NewSaltedCipherArgs `protobuf:"bytes,3,opt,name=NewSaltedCipher,proto3,oneof"`
}
type NgoloFuzzOne_CipherNgdotBlockSize struct {
CipherNgdotBlockSize *CipherNgdotBlockSizeArgs `protobuf:"bytes,4,opt,name=CipherNgdotBlockSize,proto3,oneof"`
}
type NgoloFuzzOne_CipherNgdotEncrypt struct {
CipherNgdotEncrypt *CipherNgdotEncryptArgs `protobuf:"bytes,5,opt,name=CipherNgdotEncrypt,proto3,oneof"`
}
type NgoloFuzzOne_CipherNgdotDecrypt struct {
CipherNgdotDecrypt *CipherNgdotDecryptArgs `protobuf:"bytes,6,opt,name=CipherNgdotDecrypt,proto3,oneof"`
}
func (*NgoloFuzzOne_ExpandKey) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewCipher) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewSaltedCipher) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CipherNgdotBlockSize) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CipherNgdotEncrypt) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CipherNgdotDecrypt) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"!\n" +
"\rExpandKeyArgs\x12\x10\n" +
"\x03key\x18\x01 \x01(\fR\x03key\"!\n" +
"\rNewCipherArgs\x12\x10\n" +
"\x03key\x18\x01 \x01(\fR\x03key\";\n" +
"\x13NewSaltedCipherArgs\x12\x10\n" +
"\x03key\x18\x01 \x01(\fR\x03key\x12\x12\n" +
"\x04salt\x18\x02 \x01(\fR\x04salt\"\x1a\n" +
"\x18CipherNgdotBlockSizeArgs\"<\n" +
"\x16CipherNgdotEncryptArgs\x12\x10\n" +
"\x03dst\x18\x01 \x01(\fR\x03dst\x12\x10\n" +
"\x03src\x18\x02 \x01(\fR\x03src\"<\n" +
"\x16CipherNgdotDecryptArgs\x12\x10\n" +
"\x03dst\x18\x01 \x01(\fR\x03dst\x12\x10\n" +
"\x03src\x18\x02 \x01(\fR\x03src\"\xdb\x03\n" +
"\fNgoloFuzzOne\x128\n" +
"\tExpandKey\x18\x01 \x01(\v2\x18.ngolofuzz.ExpandKeyArgsH\x00R\tExpandKey\x128\n" +
"\tNewCipher\x18\x02 \x01(\v2\x18.ngolofuzz.NewCipherArgsH\x00R\tNewCipher\x12J\n" +
"\x0fNewSaltedCipher\x18\x03 \x01(\v2\x1e.ngolofuzz.NewSaltedCipherArgsH\x00R\x0fNewSaltedCipher\x12Y\n" +
"\x14CipherNgdotBlockSize\x18\x04 \x01(\v2#.ngolofuzz.CipherNgdotBlockSizeArgsH\x00R\x14CipherNgdotBlockSize\x12S\n" +
"\x12CipherNgdotEncrypt\x18\x05 \x01(\v2!.ngolofuzz.CipherNgdotEncryptArgsH\x00R\x12CipherNgdotEncrypt\x12S\n" +
"\x12CipherNgdotDecrypt\x18\x06 \x01(\v2!.ngolofuzz.CipherNgdotDecryptArgsH\x00R\x12CipherNgdotDecryptB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1eZ\x1c./;fuzz_ng_x_crypto_blowfishb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
var file_ngolofuzz_proto_goTypes = []any{
(*ExpandKeyArgs)(nil), // 0: ngolofuzz.ExpandKeyArgs
(*NewCipherArgs)(nil), // 1: ngolofuzz.NewCipherArgs
(*NewSaltedCipherArgs)(nil), // 2: ngolofuzz.NewSaltedCipherArgs
(*CipherNgdotBlockSizeArgs)(nil), // 3: ngolofuzz.CipherNgdotBlockSizeArgs
(*CipherNgdotEncryptArgs)(nil), // 4: ngolofuzz.CipherNgdotEncryptArgs
(*CipherNgdotDecryptArgs)(nil), // 5: ngolofuzz.CipherNgdotDecryptArgs
(*NgoloFuzzOne)(nil), // 6: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 7: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 8: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.ExpandKey:type_name -> ngolofuzz.ExpandKeyArgs
1, // 1: ngolofuzz.NgoloFuzzOne.NewCipher:type_name -> ngolofuzz.NewCipherArgs
2, // 2: ngolofuzz.NgoloFuzzOne.NewSaltedCipher:type_name -> ngolofuzz.NewSaltedCipherArgs
3, // 3: ngolofuzz.NgoloFuzzOne.CipherNgdotBlockSize:type_name -> ngolofuzz.CipherNgdotBlockSizeArgs
4, // 4: ngolofuzz.NgoloFuzzOne.CipherNgdotEncrypt:type_name -> ngolofuzz.CipherNgdotEncryptArgs
5, // 5: ngolofuzz.NgoloFuzzOne.CipherNgdotDecrypt:type_name -> ngolofuzz.CipherNgdotDecryptArgs
6, // 6: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
7, // [7:7] is the sub-list for method output_type
7, // [7:7] is the sub-list for method input_type
7, // [7:7] is the sub-list for extension type_name
7, // [7:7] is the sub-list for extension extendee
0, // [0:7] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[6].OneofWrappers = []any{
(*NgoloFuzzOne_ExpandKey)(nil),
(*NgoloFuzzOne_NewCipher)(nil),
(*NgoloFuzzOne_NewSaltedCipher)(nil),
(*NgoloFuzzOne_CipherNgdotBlockSize)(nil),
(*NgoloFuzzOne_CipherNgdotEncrypt)(nil),
(*NgoloFuzzOne_CipherNgdotDecrypt)(nil),
}
file_ngolofuzz_proto_msgTypes[7].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 9,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_cast5
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/cast5"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var CipherResults []*cast5.Cipher
CipherResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewCipher:
r0, r1 := cast5.NewCipher(a.NewCipher.Key)
if r0 != nil{
CipherResults = append(CipherResults, r0)
}
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_CipherNgdotBlockSize:
if len(CipherResults) == 0 {
continue
}
arg0 := CipherResults[CipherResultsIndex]
CipherResultsIndex = (CipherResultsIndex + 1) % len(CipherResults)
arg0.BlockSize()
case *NgoloFuzzOne_CipherNgdotEncrypt:
if len(CipherResults) == 0 {
continue
}
arg0 := CipherResults[CipherResultsIndex]
CipherResultsIndex = (CipherResultsIndex + 1) % len(CipherResults)
a.CipherNgdotEncrypt.Dst = make([]byte, 2*len(a.CipherNgdotEncrypt.Src))
arg0.Encrypt(a.CipherNgdotEncrypt.Dst, a.CipherNgdotEncrypt.Src)
case *NgoloFuzzOne_CipherNgdotDecrypt:
if len(CipherResults) == 0 {
continue
}
arg0 := CipherResults[CipherResultsIndex]
CipherResultsIndex = (CipherResultsIndex + 1) % len(CipherResults)
a.CipherNgdotDecrypt.Dst = make([]byte, 2*len(a.CipherNgdotDecrypt.Src))
arg0.Decrypt(a.CipherNgdotDecrypt.Dst, a.CipherNgdotDecrypt.Src)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
CipherNb := 0
CipherResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewCipher:
w.WriteString(fmt.Sprintf("Cipher%d, _ := cast5.NewCipher(%#+v)\n", CipherNb, a.NewCipher.Key))
CipherNb = CipherNb + 1
case *NgoloFuzzOne_CipherNgdotBlockSize:
if CipherNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Cipher%d.BlockSize()\n", CipherResultsIndex))
CipherResultsIndex = (CipherResultsIndex + 1) % CipherNb
case *NgoloFuzzOne_CipherNgdotEncrypt:
if CipherNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Cipher%d.Encrypt(%#+v, %#+v)\n", CipherResultsIndex, a.CipherNgdotEncrypt.Dst, a.CipherNgdotEncrypt.Src))
CipherResultsIndex = (CipherResultsIndex + 1) % CipherNb
case *NgoloFuzzOne_CipherNgdotDecrypt:
if CipherNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Cipher%d.Decrypt(%#+v, %#+v)\n", CipherResultsIndex, a.CipherNgdotDecrypt.Dst, a.CipherNgdotDecrypt.Src))
CipherResultsIndex = (CipherResultsIndex + 1) % CipherNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_cast5
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type NewCipherArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewCipherArgs) Reset() {
*x = NewCipherArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewCipherArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewCipherArgs) ProtoMessage() {}
func (x *NewCipherArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewCipherArgs.ProtoReflect.Descriptor instead.
func (*NewCipherArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *NewCipherArgs) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
type CipherNgdotBlockSizeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CipherNgdotBlockSizeArgs) Reset() {
*x = CipherNgdotBlockSizeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CipherNgdotBlockSizeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CipherNgdotBlockSizeArgs) ProtoMessage() {}
func (x *CipherNgdotBlockSizeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CipherNgdotBlockSizeArgs.ProtoReflect.Descriptor instead.
func (*CipherNgdotBlockSizeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
type CipherNgdotEncryptArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Dst []byte `protobuf:"bytes,1,opt,name=dst,proto3" json:"dst,omitempty"`
Src []byte `protobuf:"bytes,2,opt,name=src,proto3" json:"src,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CipherNgdotEncryptArgs) Reset() {
*x = CipherNgdotEncryptArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CipherNgdotEncryptArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CipherNgdotEncryptArgs) ProtoMessage() {}
func (x *CipherNgdotEncryptArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CipherNgdotEncryptArgs.ProtoReflect.Descriptor instead.
func (*CipherNgdotEncryptArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *CipherNgdotEncryptArgs) GetDst() []byte {
if x != nil {
return x.Dst
}
return nil
}
func (x *CipherNgdotEncryptArgs) GetSrc() []byte {
if x != nil {
return x.Src
}
return nil
}
type CipherNgdotDecryptArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Dst []byte `protobuf:"bytes,1,opt,name=dst,proto3" json:"dst,omitempty"`
Src []byte `protobuf:"bytes,2,opt,name=src,proto3" json:"src,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CipherNgdotDecryptArgs) Reset() {
*x = CipherNgdotDecryptArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CipherNgdotDecryptArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CipherNgdotDecryptArgs) ProtoMessage() {}
func (x *CipherNgdotDecryptArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CipherNgdotDecryptArgs.ProtoReflect.Descriptor instead.
func (*CipherNgdotDecryptArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *CipherNgdotDecryptArgs) GetDst() []byte {
if x != nil {
return x.Dst
}
return nil
}
func (x *CipherNgdotDecryptArgs) GetSrc() []byte {
if x != nil {
return x.Src
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_NewCipher
// *NgoloFuzzOne_CipherNgdotBlockSize
// *NgoloFuzzOne_CipherNgdotEncrypt
// *NgoloFuzzOne_CipherNgdotDecrypt
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetNewCipher() *NewCipherArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewCipher); ok {
return x.NewCipher
}
}
return nil
}
func (x *NgoloFuzzOne) GetCipherNgdotBlockSize() *CipherNgdotBlockSizeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CipherNgdotBlockSize); ok {
return x.CipherNgdotBlockSize
}
}
return nil
}
func (x *NgoloFuzzOne) GetCipherNgdotEncrypt() *CipherNgdotEncryptArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CipherNgdotEncrypt); ok {
return x.CipherNgdotEncrypt
}
}
return nil
}
func (x *NgoloFuzzOne) GetCipherNgdotDecrypt() *CipherNgdotDecryptArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CipherNgdotDecrypt); ok {
return x.CipherNgdotDecrypt
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_NewCipher struct {
NewCipher *NewCipherArgs `protobuf:"bytes,1,opt,name=NewCipher,proto3,oneof"`
}
type NgoloFuzzOne_CipherNgdotBlockSize struct {
CipherNgdotBlockSize *CipherNgdotBlockSizeArgs `protobuf:"bytes,2,opt,name=CipherNgdotBlockSize,proto3,oneof"`
}
type NgoloFuzzOne_CipherNgdotEncrypt struct {
CipherNgdotEncrypt *CipherNgdotEncryptArgs `protobuf:"bytes,3,opt,name=CipherNgdotEncrypt,proto3,oneof"`
}
type NgoloFuzzOne_CipherNgdotDecrypt struct {
CipherNgdotDecrypt *CipherNgdotDecryptArgs `protobuf:"bytes,4,opt,name=CipherNgdotDecrypt,proto3,oneof"`
}
func (*NgoloFuzzOne_NewCipher) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CipherNgdotBlockSize) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CipherNgdotEncrypt) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CipherNgdotDecrypt) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"!\n" +
"\rNewCipherArgs\x12\x10\n" +
"\x03key\x18\x01 \x01(\fR\x03key\"\x1a\n" +
"\x18CipherNgdotBlockSizeArgs\"<\n" +
"\x16CipherNgdotEncryptArgs\x12\x10\n" +
"\x03dst\x18\x01 \x01(\fR\x03dst\x12\x10\n" +
"\x03src\x18\x02 \x01(\fR\x03src\"<\n" +
"\x16CipherNgdotDecryptArgs\x12\x10\n" +
"\x03dst\x18\x01 \x01(\fR\x03dst\x12\x10\n" +
"\x03src\x18\x02 \x01(\fR\x03src\"\xd5\x02\n" +
"\fNgoloFuzzOne\x128\n" +
"\tNewCipher\x18\x01 \x01(\v2\x18.ngolofuzz.NewCipherArgsH\x00R\tNewCipher\x12Y\n" +
"\x14CipherNgdotBlockSize\x18\x02 \x01(\v2#.ngolofuzz.CipherNgdotBlockSizeArgsH\x00R\x14CipherNgdotBlockSize\x12S\n" +
"\x12CipherNgdotEncrypt\x18\x03 \x01(\v2!.ngolofuzz.CipherNgdotEncryptArgsH\x00R\x12CipherNgdotEncrypt\x12S\n" +
"\x12CipherNgdotDecrypt\x18\x04 \x01(\v2!.ngolofuzz.CipherNgdotDecryptArgsH\x00R\x12CipherNgdotDecryptB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1bZ\x19./;fuzz_ng_x_crypto_cast5b\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_ngolofuzz_proto_goTypes = []any{
(*NewCipherArgs)(nil), // 0: ngolofuzz.NewCipherArgs
(*CipherNgdotBlockSizeArgs)(nil), // 1: ngolofuzz.CipherNgdotBlockSizeArgs
(*CipherNgdotEncryptArgs)(nil), // 2: ngolofuzz.CipherNgdotEncryptArgs
(*CipherNgdotDecryptArgs)(nil), // 3: ngolofuzz.CipherNgdotDecryptArgs
(*NgoloFuzzOne)(nil), // 4: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 5: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 6: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.NewCipher:type_name -> ngolofuzz.NewCipherArgs
1, // 1: ngolofuzz.NgoloFuzzOne.CipherNgdotBlockSize:type_name -> ngolofuzz.CipherNgdotBlockSizeArgs
2, // 2: ngolofuzz.NgoloFuzzOne.CipherNgdotEncrypt:type_name -> ngolofuzz.CipherNgdotEncryptArgs
3, // 3: ngolofuzz.NgoloFuzzOne.CipherNgdotDecrypt:type_name -> ngolofuzz.CipherNgdotDecryptArgs
4, // 4: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[4].OneofWrappers = []any{
(*NgoloFuzzOne_NewCipher)(nil),
(*NgoloFuzzOne_CipherNgdotBlockSize)(nil),
(*NgoloFuzzOne_CipherNgdotEncrypt)(nil),
(*NgoloFuzzOne_CipherNgdotDecrypt)(nil),
}
file_ngolofuzz_proto_msgTypes[5].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 7,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_chacha20
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/chacha20"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var CipherResults []*chacha20.Cipher
CipherResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewUnauthenticatedCipher:
r0, r1 := chacha20.NewUnauthenticatedCipher(a.NewUnauthenticatedCipher.Key, a.NewUnauthenticatedCipher.Nonce)
if r0 != nil{
CipherResults = append(CipherResults, r0)
}
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_CipherNgdotSetCounter:
if len(CipherResults) == 0 {
continue
}
arg0 := CipherResults[CipherResultsIndex]
CipherResultsIndex = (CipherResultsIndex + 1) % len(CipherResults)
arg0.SetCounter(a.CipherNgdotSetCounter.Counter)
case *NgoloFuzzOne_CipherNgdotXORKeyStream:
if len(CipherResults) == 0 {
continue
}
arg0 := CipherResults[CipherResultsIndex]
CipherResultsIndex = (CipherResultsIndex + 1) % len(CipherResults)
a.CipherNgdotXORKeyStream.Dst = make([]byte, 2*len(a.CipherNgdotXORKeyStream.Src))
arg0.XORKeyStream(a.CipherNgdotXORKeyStream.Dst, a.CipherNgdotXORKeyStream.Src)
case *NgoloFuzzOne_HChaCha20:
_, r1 := chacha20.HChaCha20(a.HChaCha20.Key, a.HChaCha20.Nonce)
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
CipherNb := 0
CipherResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewUnauthenticatedCipher:
w.WriteString(fmt.Sprintf("Cipher%d, _ := chacha20.NewUnauthenticatedCipher(%#+v, %#+v)\n", CipherNb, a.NewUnauthenticatedCipher.Key, a.NewUnauthenticatedCipher.Nonce))
CipherNb = CipherNb + 1
case *NgoloFuzzOne_CipherNgdotSetCounter:
if CipherNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Cipher%d.SetCounter(%#+v)\n", CipherResultsIndex, a.CipherNgdotSetCounter.Counter))
CipherResultsIndex = (CipherResultsIndex + 1) % CipherNb
case *NgoloFuzzOne_CipherNgdotXORKeyStream:
if CipherNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Cipher%d.XORKeyStream(%#+v, %#+v)\n", CipherResultsIndex, a.CipherNgdotXORKeyStream.Dst, a.CipherNgdotXORKeyStream.Src))
CipherResultsIndex = (CipherResultsIndex + 1) % CipherNb
case *NgoloFuzzOne_HChaCha20:
w.WriteString(fmt.Sprintf("chacha20.HChaCha20(%#+v, %#+v)\n", a.HChaCha20.Key, a.HChaCha20.Nonce))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_chacha20
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type NewUnauthenticatedCipherArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Nonce []byte `protobuf:"bytes,2,opt,name=nonce,proto3" json:"nonce,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewUnauthenticatedCipherArgs) Reset() {
*x = NewUnauthenticatedCipherArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewUnauthenticatedCipherArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewUnauthenticatedCipherArgs) ProtoMessage() {}
func (x *NewUnauthenticatedCipherArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewUnauthenticatedCipherArgs.ProtoReflect.Descriptor instead.
func (*NewUnauthenticatedCipherArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *NewUnauthenticatedCipherArgs) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
func (x *NewUnauthenticatedCipherArgs) GetNonce() []byte {
if x != nil {
return x.Nonce
}
return nil
}
type CipherNgdotSetCounterArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Counter uint32 `protobuf:"varint,1,opt,name=counter,proto3" json:"counter,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CipherNgdotSetCounterArgs) Reset() {
*x = CipherNgdotSetCounterArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CipherNgdotSetCounterArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CipherNgdotSetCounterArgs) ProtoMessage() {}
func (x *CipherNgdotSetCounterArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CipherNgdotSetCounterArgs.ProtoReflect.Descriptor instead.
func (*CipherNgdotSetCounterArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *CipherNgdotSetCounterArgs) GetCounter() uint32 {
if x != nil {
return x.Counter
}
return 0
}
type CipherNgdotXORKeyStreamArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Dst []byte `protobuf:"bytes,1,opt,name=dst,proto3" json:"dst,omitempty"`
Src []byte `protobuf:"bytes,2,opt,name=src,proto3" json:"src,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CipherNgdotXORKeyStreamArgs) Reset() {
*x = CipherNgdotXORKeyStreamArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CipherNgdotXORKeyStreamArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CipherNgdotXORKeyStreamArgs) ProtoMessage() {}
func (x *CipherNgdotXORKeyStreamArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CipherNgdotXORKeyStreamArgs.ProtoReflect.Descriptor instead.
func (*CipherNgdotXORKeyStreamArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *CipherNgdotXORKeyStreamArgs) GetDst() []byte {
if x != nil {
return x.Dst
}
return nil
}
func (x *CipherNgdotXORKeyStreamArgs) GetSrc() []byte {
if x != nil {
return x.Src
}
return nil
}
type HChaCha20Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Nonce []byte `protobuf:"bytes,2,opt,name=nonce,proto3" json:"nonce,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HChaCha20Args) Reset() {
*x = HChaCha20Args{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HChaCha20Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HChaCha20Args) ProtoMessage() {}
func (x *HChaCha20Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HChaCha20Args.ProtoReflect.Descriptor instead.
func (*HChaCha20Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *HChaCha20Args) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
func (x *HChaCha20Args) GetNonce() []byte {
if x != nil {
return x.Nonce
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_NewUnauthenticatedCipher
// *NgoloFuzzOne_CipherNgdotSetCounter
// *NgoloFuzzOne_CipherNgdotXORKeyStream
// *NgoloFuzzOne_HChaCha20
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetNewUnauthenticatedCipher() *NewUnauthenticatedCipherArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewUnauthenticatedCipher); ok {
return x.NewUnauthenticatedCipher
}
}
return nil
}
func (x *NgoloFuzzOne) GetCipherNgdotSetCounter() *CipherNgdotSetCounterArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CipherNgdotSetCounter); ok {
return x.CipherNgdotSetCounter
}
}
return nil
}
func (x *NgoloFuzzOne) GetCipherNgdotXORKeyStream() *CipherNgdotXORKeyStreamArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CipherNgdotXORKeyStream); ok {
return x.CipherNgdotXORKeyStream
}
}
return nil
}
func (x *NgoloFuzzOne) GetHChaCha20() *HChaCha20Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_HChaCha20); ok {
return x.HChaCha20
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_NewUnauthenticatedCipher struct {
NewUnauthenticatedCipher *NewUnauthenticatedCipherArgs `protobuf:"bytes,1,opt,name=NewUnauthenticatedCipher,proto3,oneof"`
}
type NgoloFuzzOne_CipherNgdotSetCounter struct {
CipherNgdotSetCounter *CipherNgdotSetCounterArgs `protobuf:"bytes,2,opt,name=CipherNgdotSetCounter,proto3,oneof"`
}
type NgoloFuzzOne_CipherNgdotXORKeyStream struct {
CipherNgdotXORKeyStream *CipherNgdotXORKeyStreamArgs `protobuf:"bytes,3,opt,name=CipherNgdotXORKeyStream,proto3,oneof"`
}
type NgoloFuzzOne_HChaCha20 struct {
HChaCha20 *HChaCha20Args `protobuf:"bytes,4,opt,name=HChaCha20,proto3,oneof"`
}
func (*NgoloFuzzOne_NewUnauthenticatedCipher) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CipherNgdotSetCounter) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CipherNgdotXORKeyStream) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_HChaCha20) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"F\n" +
"\x1cNewUnauthenticatedCipherArgs\x12\x10\n" +
"\x03key\x18\x01 \x01(\fR\x03key\x12\x14\n" +
"\x05nonce\x18\x02 \x01(\fR\x05nonce\"5\n" +
"\x19CipherNgdotSetCounterArgs\x12\x18\n" +
"\acounter\x18\x01 \x01(\rR\acounter\"A\n" +
"\x1bCipherNgdotXORKeyStreamArgs\x12\x10\n" +
"\x03dst\x18\x01 \x01(\fR\x03dst\x12\x10\n" +
"\x03src\x18\x02 \x01(\fR\x03src\"7\n" +
"\rHChaCha20Args\x12\x10\n" +
"\x03key\x18\x01 \x01(\fR\x03key\x12\x14\n" +
"\x05nonce\x18\x02 \x01(\fR\x05nonce\"\xf9\x02\n" +
"\fNgoloFuzzOne\x12e\n" +
"\x18NewUnauthenticatedCipher\x18\x01 \x01(\v2'.ngolofuzz.NewUnauthenticatedCipherArgsH\x00R\x18NewUnauthenticatedCipher\x12\\\n" +
"\x15CipherNgdotSetCounter\x18\x02 \x01(\v2$.ngolofuzz.CipherNgdotSetCounterArgsH\x00R\x15CipherNgdotSetCounter\x12b\n" +
"\x17CipherNgdotXORKeyStream\x18\x03 \x01(\v2&.ngolofuzz.CipherNgdotXORKeyStreamArgsH\x00R\x17CipherNgdotXORKeyStream\x128\n" +
"\tHChaCha20\x18\x04 \x01(\v2\x18.ngolofuzz.HChaCha20ArgsH\x00R\tHChaCha20B\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1eZ\x1c./;fuzz_ng_x_crypto_chacha20b\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_ngolofuzz_proto_goTypes = []any{
(*NewUnauthenticatedCipherArgs)(nil), // 0: ngolofuzz.NewUnauthenticatedCipherArgs
(*CipherNgdotSetCounterArgs)(nil), // 1: ngolofuzz.CipherNgdotSetCounterArgs
(*CipherNgdotXORKeyStreamArgs)(nil), // 2: ngolofuzz.CipherNgdotXORKeyStreamArgs
(*HChaCha20Args)(nil), // 3: ngolofuzz.HChaCha20Args
(*NgoloFuzzOne)(nil), // 4: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 5: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 6: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.NewUnauthenticatedCipher:type_name -> ngolofuzz.NewUnauthenticatedCipherArgs
1, // 1: ngolofuzz.NgoloFuzzOne.CipherNgdotSetCounter:type_name -> ngolofuzz.CipherNgdotSetCounterArgs
2, // 2: ngolofuzz.NgoloFuzzOne.CipherNgdotXORKeyStream:type_name -> ngolofuzz.CipherNgdotXORKeyStreamArgs
3, // 3: ngolofuzz.NgoloFuzzOne.HChaCha20:type_name -> ngolofuzz.HChaCha20Args
4, // 4: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[4].OneofWrappers = []any{
(*NgoloFuzzOne_NewUnauthenticatedCipher)(nil),
(*NgoloFuzzOne_CipherNgdotSetCounter)(nil),
(*NgoloFuzzOne_CipherNgdotXORKeyStream)(nil),
(*NgoloFuzzOne_HChaCha20)(nil),
}
file_ngolofuzz_proto_msgTypes[5].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 7,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_chacha20poly1305
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/chacha20poly1305"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_New:
_, r1 := chacha20poly1305.New(a.New.Key)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_NewX:
_, r1 := chacha20poly1305.NewX(a.NewX.Key)
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_New:
w.WriteString(fmt.Sprintf("chacha20poly1305.New(%#+v)\n", a.New.Key))
case *NgoloFuzzOne_NewX:
w.WriteString(fmt.Sprintf("chacha20poly1305.NewX(%#+v)\n", a.NewX.Key))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_chacha20poly1305
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type NewArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewArgs) Reset() {
*x = NewArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewArgs) ProtoMessage() {}
func (x *NewArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewArgs.ProtoReflect.Descriptor instead.
func (*NewArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *NewArgs) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
type NewXArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewXArgs) Reset() {
*x = NewXArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewXArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewXArgs) ProtoMessage() {}
func (x *NewXArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewXArgs.ProtoReflect.Descriptor instead.
func (*NewXArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *NewXArgs) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_New
// *NgoloFuzzOne_NewX
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetNew() *NewArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_New); ok {
return x.New
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewX() *NewXArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewX); ok {
return x.NewX
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_New struct {
New *NewArgs `protobuf:"bytes,1,opt,name=New,proto3,oneof"`
}
type NgoloFuzzOne_NewX struct {
NewX *NewXArgs `protobuf:"bytes,2,opt,name=NewX,proto3,oneof"`
}
func (*NgoloFuzzOne_New) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewX) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x1b\n" +
"\aNewArgs\x12\x10\n" +
"\x03key\x18\x01 \x01(\fR\x03key\"\x1c\n" +
"\bNewXArgs\x12\x10\n" +
"\x03key\x18\x01 \x01(\fR\x03key\"i\n" +
"\fNgoloFuzzOne\x12&\n" +
"\x03New\x18\x01 \x01(\v2\x12.ngolofuzz.NewArgsH\x00R\x03New\x12)\n" +
"\x04NewX\x18\x02 \x01(\v2\x13.ngolofuzz.NewXArgsH\x00R\x04NewXB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB&Z$./;fuzz_ng_x_crypto_chacha20poly1305b\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_ngolofuzz_proto_goTypes = []any{
(*NewArgs)(nil), // 0: ngolofuzz.NewArgs
(*NewXArgs)(nil), // 1: ngolofuzz.NewXArgs
(*NgoloFuzzOne)(nil), // 2: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 3: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 4: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.New:type_name -> ngolofuzz.NewArgs
1, // 1: ngolofuzz.NgoloFuzzOne.NewX:type_name -> ngolofuzz.NewXArgs
2, // 2: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzOne_New)(nil),
(*NgoloFuzzOne_NewX)(nil),
}
file_ngolofuzz_proto_msgTypes[3].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_cryptobyte
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/cryptobyte"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var BuilderResults []*cryptobyte.Builder
BuilderResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_BuilderNgdotAddASN1Int64:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
arg0.AddASN1Int64(a.BuilderNgdotAddASN1Int64.V)
case *NgoloFuzzOne_BuilderNgdotAddASN1Enum:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
arg0.AddASN1Enum(a.BuilderNgdotAddASN1Enum.V)
case *NgoloFuzzOne_BuilderNgdotAddASN1Uint64:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
arg0.AddASN1Uint64(a.BuilderNgdotAddASN1Uint64.V)
case *NgoloFuzzOne_BuilderNgdotAddASN1BigInt:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
arg1 := CreateBigInt(a.BuilderNgdotAddASN1BigInt.N)
arg0.AddASN1BigInt(arg1)
case *NgoloFuzzOne_BuilderNgdotAddASN1OctetString:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
arg0.AddASN1OctetString(a.BuilderNgdotAddASN1OctetString.Bytes)
case *NgoloFuzzOne_BuilderNgdotAddASN1BitString:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
arg0.AddASN1BitString(a.BuilderNgdotAddASN1BitString.Data)
case *NgoloFuzzOne_BuilderNgdotAddASN1Boolean:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
arg0.AddASN1Boolean(a.BuilderNgdotAddASN1Boolean.V)
case *NgoloFuzzOne_BuilderNgdotAddASN1NULL:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
arg0.AddASN1NULL()
case *NgoloFuzzOne_BuilderNgdotMarshalASN1:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
arg0.MarshalASN1(a.BuilderNgdotMarshalASN1.V)
case *NgoloFuzzOne_NewBuilder:
r0 := cryptobyte.NewBuilder(a.NewBuilder.Buffer)
if r0 != nil{
BuilderResults = append(BuilderResults, r0)
}
case *NgoloFuzzOne_NewFixedBuilder:
r0 := cryptobyte.NewFixedBuilder(a.NewFixedBuilder.Buffer)
if r0 != nil{
BuilderResults = append(BuilderResults, r0)
}
case *NgoloFuzzOne_BuilderNgdotBytes:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
_, r1 := arg0.Bytes()
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_BuilderNgdotBytesOrPanic:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
arg0.BytesOrPanic()
case *NgoloFuzzOne_BuilderNgdotAddUint8:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
arg1 := uint8(a.BuilderNgdotAddUint8.V)
arg0.AddUint8(arg1)
case *NgoloFuzzOne_BuilderNgdotAddUint16:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
arg1 := uint16(a.BuilderNgdotAddUint16.V)
arg0.AddUint16(arg1)
case *NgoloFuzzOne_BuilderNgdotAddUint24:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
arg0.AddUint24(a.BuilderNgdotAddUint24.V)
case *NgoloFuzzOne_BuilderNgdotAddUint32:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
arg0.AddUint32(a.BuilderNgdotAddUint32.V)
case *NgoloFuzzOne_BuilderNgdotAddUint48:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
arg0.AddUint48(a.BuilderNgdotAddUint48.V)
case *NgoloFuzzOne_BuilderNgdotAddUint64:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
arg0.AddUint64(a.BuilderNgdotAddUint64.V)
case *NgoloFuzzOne_BuilderNgdotAddBytes:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
arg0.AddBytes(a.BuilderNgdotAddBytes.V)
case *NgoloFuzzOne_BuilderNgdotUnwrite:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
arg1 := int(a.BuilderNgdotUnwrite.N)
arg0.Unwrite(arg1)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
BuilderNb := 0
BuilderResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_BuilderNgdotAddASN1Int64:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.AddASN1Int64(%#+v)\n", BuilderResultsIndex, a.BuilderNgdotAddASN1Int64.V))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotAddASN1Enum:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.AddASN1Enum(%#+v)\n", BuilderResultsIndex, a.BuilderNgdotAddASN1Enum.V))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotAddASN1Uint64:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.AddASN1Uint64(%#+v)\n", BuilderResultsIndex, a.BuilderNgdotAddASN1Uint64.V))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotAddASN1BigInt:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.AddASN1BigInt(CreateBigInt(%#+v))\n", BuilderResultsIndex, a.BuilderNgdotAddASN1BigInt.N))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotAddASN1OctetString:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.AddASN1OctetString(%#+v)\n", BuilderResultsIndex, a.BuilderNgdotAddASN1OctetString.Bytes))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotAddASN1BitString:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.AddASN1BitString(%#+v)\n", BuilderResultsIndex, a.BuilderNgdotAddASN1BitString.Data))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotAddASN1Boolean:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.AddASN1Boolean(%#+v)\n", BuilderResultsIndex, a.BuilderNgdotAddASN1Boolean.V))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotAddASN1NULL:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.AddASN1NULL()\n", BuilderResultsIndex))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotMarshalASN1:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.MarshalASN1(%#+v)\n", BuilderResultsIndex, a.BuilderNgdotMarshalASN1.V))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_NewBuilder:
w.WriteString(fmt.Sprintf("Builder%d := cryptobyte.NewBuilder(%#+v)\n", BuilderNb, a.NewBuilder.Buffer))
BuilderNb = BuilderNb + 1
case *NgoloFuzzOne_NewFixedBuilder:
w.WriteString(fmt.Sprintf("Builder%d := cryptobyte.NewFixedBuilder(%#+v)\n", BuilderNb, a.NewFixedBuilder.Buffer))
BuilderNb = BuilderNb + 1
case *NgoloFuzzOne_BuilderNgdotBytes:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.Bytes()\n", BuilderResultsIndex))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotBytesOrPanic:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.BytesOrPanic()\n", BuilderResultsIndex))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotAddUint8:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.AddUint8(uint8(%#+v))\n", BuilderResultsIndex, a.BuilderNgdotAddUint8.V))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotAddUint16:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.AddUint16(uint16(%#+v))\n", BuilderResultsIndex, a.BuilderNgdotAddUint16.V))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotAddUint24:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.AddUint24(%#+v)\n", BuilderResultsIndex, a.BuilderNgdotAddUint24.V))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotAddUint32:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.AddUint32(%#+v)\n", BuilderResultsIndex, a.BuilderNgdotAddUint32.V))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotAddUint48:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.AddUint48(%#+v)\n", BuilderResultsIndex, a.BuilderNgdotAddUint48.V))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotAddUint64:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.AddUint64(%#+v)\n", BuilderResultsIndex, a.BuilderNgdotAddUint64.V))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotAddBytes:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.AddBytes(%#+v)\n", BuilderResultsIndex, a.BuilderNgdotAddBytes.V))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotUnwrite:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.Unwrite(int(%#+v))\n", BuilderResultsIndex, a.BuilderNgdotUnwrite.N))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_cryptobyte
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type BuilderNgdotAddASN1Int64Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
V int64 `protobuf:"varint,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotAddASN1Int64Args) Reset() {
*x = BuilderNgdotAddASN1Int64Args{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotAddASN1Int64Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotAddASN1Int64Args) ProtoMessage() {}
func (x *BuilderNgdotAddASN1Int64Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotAddASN1Int64Args.ProtoReflect.Descriptor instead.
func (*BuilderNgdotAddASN1Int64Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *BuilderNgdotAddASN1Int64Args) GetV() int64 {
if x != nil {
return x.V
}
return 0
}
type BuilderNgdotAddASN1EnumArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
V int64 `protobuf:"varint,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotAddASN1EnumArgs) Reset() {
*x = BuilderNgdotAddASN1EnumArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotAddASN1EnumArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotAddASN1EnumArgs) ProtoMessage() {}
func (x *BuilderNgdotAddASN1EnumArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotAddASN1EnumArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotAddASN1EnumArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *BuilderNgdotAddASN1EnumArgs) GetV() int64 {
if x != nil {
return x.V
}
return 0
}
type BuilderNgdotAddASN1Uint64Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
V uint64 `protobuf:"varint,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotAddASN1Uint64Args) Reset() {
*x = BuilderNgdotAddASN1Uint64Args{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotAddASN1Uint64Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotAddASN1Uint64Args) ProtoMessage() {}
func (x *BuilderNgdotAddASN1Uint64Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotAddASN1Uint64Args.ProtoReflect.Descriptor instead.
func (*BuilderNgdotAddASN1Uint64Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *BuilderNgdotAddASN1Uint64Args) GetV() uint64 {
if x != nil {
return x.V
}
return 0
}
type BuilderNgdotAddASN1BigIntArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
N []byte `protobuf:"bytes,1,opt,name=n,proto3" json:"n,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotAddASN1BigIntArgs) Reset() {
*x = BuilderNgdotAddASN1BigIntArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotAddASN1BigIntArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotAddASN1BigIntArgs) ProtoMessage() {}
func (x *BuilderNgdotAddASN1BigIntArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotAddASN1BigIntArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotAddASN1BigIntArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *BuilderNgdotAddASN1BigIntArgs) GetN() []byte {
if x != nil {
return x.N
}
return nil
}
type BuilderNgdotAddASN1OctetStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Bytes []byte `protobuf:"bytes,1,opt,name=bytes,proto3" json:"bytes,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotAddASN1OctetStringArgs) Reset() {
*x = BuilderNgdotAddASN1OctetStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotAddASN1OctetStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotAddASN1OctetStringArgs) ProtoMessage() {}
func (x *BuilderNgdotAddASN1OctetStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotAddASN1OctetStringArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotAddASN1OctetStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *BuilderNgdotAddASN1OctetStringArgs) GetBytes() []byte {
if x != nil {
return x.Bytes
}
return nil
}
type BuilderNgdotAddASN1BitStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotAddASN1BitStringArgs) Reset() {
*x = BuilderNgdotAddASN1BitStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotAddASN1BitStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotAddASN1BitStringArgs) ProtoMessage() {}
func (x *BuilderNgdotAddASN1BitStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotAddASN1BitStringArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotAddASN1BitStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *BuilderNgdotAddASN1BitStringArgs) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
type BuilderNgdotAddASN1BooleanArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
V bool `protobuf:"varint,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotAddASN1BooleanArgs) Reset() {
*x = BuilderNgdotAddASN1BooleanArgs{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotAddASN1BooleanArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotAddASN1BooleanArgs) ProtoMessage() {}
func (x *BuilderNgdotAddASN1BooleanArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotAddASN1BooleanArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotAddASN1BooleanArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *BuilderNgdotAddASN1BooleanArgs) GetV() bool {
if x != nil {
return x.V
}
return false
}
type BuilderNgdotAddASN1NULLArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotAddASN1NULLArgs) Reset() {
*x = BuilderNgdotAddASN1NULLArgs{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotAddASN1NULLArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotAddASN1NULLArgs) ProtoMessage() {}
func (x *BuilderNgdotAddASN1NULLArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotAddASN1NULLArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotAddASN1NULLArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
type BuilderNgdotMarshalASN1Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
V *NgoloFuzzAny `protobuf:"bytes,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotMarshalASN1Args) Reset() {
*x = BuilderNgdotMarshalASN1Args{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotMarshalASN1Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotMarshalASN1Args) ProtoMessage() {}
func (x *BuilderNgdotMarshalASN1Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotMarshalASN1Args.ProtoReflect.Descriptor instead.
func (*BuilderNgdotMarshalASN1Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
func (x *BuilderNgdotMarshalASN1Args) GetV() *NgoloFuzzAny {
if x != nil {
return x.V
}
return nil
}
type NewBuilderArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Buffer []byte `protobuf:"bytes,1,opt,name=buffer,proto3" json:"buffer,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewBuilderArgs) Reset() {
*x = NewBuilderArgs{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewBuilderArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewBuilderArgs) ProtoMessage() {}
func (x *NewBuilderArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewBuilderArgs.ProtoReflect.Descriptor instead.
func (*NewBuilderArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
func (x *NewBuilderArgs) GetBuffer() []byte {
if x != nil {
return x.Buffer
}
return nil
}
type NewFixedBuilderArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Buffer []byte `protobuf:"bytes,1,opt,name=buffer,proto3" json:"buffer,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewFixedBuilderArgs) Reset() {
*x = NewFixedBuilderArgs{}
mi := &file_ngolofuzz_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewFixedBuilderArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewFixedBuilderArgs) ProtoMessage() {}
func (x *NewFixedBuilderArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewFixedBuilderArgs.ProtoReflect.Descriptor instead.
func (*NewFixedBuilderArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{10}
}
func (x *NewFixedBuilderArgs) GetBuffer() []byte {
if x != nil {
return x.Buffer
}
return nil
}
type BuilderNgdotBytesArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotBytesArgs) Reset() {
*x = BuilderNgdotBytesArgs{}
mi := &file_ngolofuzz_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotBytesArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotBytesArgs) ProtoMessage() {}
func (x *BuilderNgdotBytesArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[11]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotBytesArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotBytesArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{11}
}
type BuilderNgdotBytesOrPanicArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotBytesOrPanicArgs) Reset() {
*x = BuilderNgdotBytesOrPanicArgs{}
mi := &file_ngolofuzz_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotBytesOrPanicArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotBytesOrPanicArgs) ProtoMessage() {}
func (x *BuilderNgdotBytesOrPanicArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[12]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotBytesOrPanicArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotBytesOrPanicArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{12}
}
type BuilderNgdotAddUint8Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
V uint32 `protobuf:"varint,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotAddUint8Args) Reset() {
*x = BuilderNgdotAddUint8Args{}
mi := &file_ngolofuzz_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotAddUint8Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotAddUint8Args) ProtoMessage() {}
func (x *BuilderNgdotAddUint8Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[13]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotAddUint8Args.ProtoReflect.Descriptor instead.
func (*BuilderNgdotAddUint8Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{13}
}
func (x *BuilderNgdotAddUint8Args) GetV() uint32 {
if x != nil {
return x.V
}
return 0
}
type BuilderNgdotAddUint16Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
V uint32 `protobuf:"varint,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotAddUint16Args) Reset() {
*x = BuilderNgdotAddUint16Args{}
mi := &file_ngolofuzz_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotAddUint16Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotAddUint16Args) ProtoMessage() {}
func (x *BuilderNgdotAddUint16Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[14]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotAddUint16Args.ProtoReflect.Descriptor instead.
func (*BuilderNgdotAddUint16Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{14}
}
func (x *BuilderNgdotAddUint16Args) GetV() uint32 {
if x != nil {
return x.V
}
return 0
}
type BuilderNgdotAddUint24Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
V uint32 `protobuf:"varint,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotAddUint24Args) Reset() {
*x = BuilderNgdotAddUint24Args{}
mi := &file_ngolofuzz_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotAddUint24Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotAddUint24Args) ProtoMessage() {}
func (x *BuilderNgdotAddUint24Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[15]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotAddUint24Args.ProtoReflect.Descriptor instead.
func (*BuilderNgdotAddUint24Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{15}
}
func (x *BuilderNgdotAddUint24Args) GetV() uint32 {
if x != nil {
return x.V
}
return 0
}
type BuilderNgdotAddUint32Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
V uint32 `protobuf:"varint,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotAddUint32Args) Reset() {
*x = BuilderNgdotAddUint32Args{}
mi := &file_ngolofuzz_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotAddUint32Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotAddUint32Args) ProtoMessage() {}
func (x *BuilderNgdotAddUint32Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[16]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotAddUint32Args.ProtoReflect.Descriptor instead.
func (*BuilderNgdotAddUint32Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{16}
}
func (x *BuilderNgdotAddUint32Args) GetV() uint32 {
if x != nil {
return x.V
}
return 0
}
type BuilderNgdotAddUint48Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
V uint64 `protobuf:"varint,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotAddUint48Args) Reset() {
*x = BuilderNgdotAddUint48Args{}
mi := &file_ngolofuzz_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotAddUint48Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotAddUint48Args) ProtoMessage() {}
func (x *BuilderNgdotAddUint48Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[17]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotAddUint48Args.ProtoReflect.Descriptor instead.
func (*BuilderNgdotAddUint48Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{17}
}
func (x *BuilderNgdotAddUint48Args) GetV() uint64 {
if x != nil {
return x.V
}
return 0
}
type BuilderNgdotAddUint64Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
V uint64 `protobuf:"varint,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotAddUint64Args) Reset() {
*x = BuilderNgdotAddUint64Args{}
mi := &file_ngolofuzz_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotAddUint64Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotAddUint64Args) ProtoMessage() {}
func (x *BuilderNgdotAddUint64Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[18]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotAddUint64Args.ProtoReflect.Descriptor instead.
func (*BuilderNgdotAddUint64Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{18}
}
func (x *BuilderNgdotAddUint64Args) GetV() uint64 {
if x != nil {
return x.V
}
return 0
}
type BuilderNgdotAddBytesArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
V []byte `protobuf:"bytes,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotAddBytesArgs) Reset() {
*x = BuilderNgdotAddBytesArgs{}
mi := &file_ngolofuzz_proto_msgTypes[19]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotAddBytesArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotAddBytesArgs) ProtoMessage() {}
func (x *BuilderNgdotAddBytesArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[19]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotAddBytesArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotAddBytesArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{19}
}
func (x *BuilderNgdotAddBytesArgs) GetV() []byte {
if x != nil {
return x.V
}
return nil
}
type BuilderNgdotUnwriteArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
N int64 `protobuf:"varint,1,opt,name=n,proto3" json:"n,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotUnwriteArgs) Reset() {
*x = BuilderNgdotUnwriteArgs{}
mi := &file_ngolofuzz_proto_msgTypes[20]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotUnwriteArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotUnwriteArgs) ProtoMessage() {}
func (x *BuilderNgdotUnwriteArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[20]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotUnwriteArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotUnwriteArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{20}
}
func (x *BuilderNgdotUnwriteArgs) GetN() int64 {
if x != nil {
return x.N
}
return 0
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_BuilderNgdotAddASN1Int64
// *NgoloFuzzOne_BuilderNgdotAddASN1Enum
// *NgoloFuzzOne_BuilderNgdotAddASN1Uint64
// *NgoloFuzzOne_BuilderNgdotAddASN1BigInt
// *NgoloFuzzOne_BuilderNgdotAddASN1OctetString
// *NgoloFuzzOne_BuilderNgdotAddASN1BitString
// *NgoloFuzzOne_BuilderNgdotAddASN1Boolean
// *NgoloFuzzOne_BuilderNgdotAddASN1NULL
// *NgoloFuzzOne_BuilderNgdotMarshalASN1
// *NgoloFuzzOne_NewBuilder
// *NgoloFuzzOne_NewFixedBuilder
// *NgoloFuzzOne_BuilderNgdotBytes
// *NgoloFuzzOne_BuilderNgdotBytesOrPanic
// *NgoloFuzzOne_BuilderNgdotAddUint8
// *NgoloFuzzOne_BuilderNgdotAddUint16
// *NgoloFuzzOne_BuilderNgdotAddUint24
// *NgoloFuzzOne_BuilderNgdotAddUint32
// *NgoloFuzzOne_BuilderNgdotAddUint48
// *NgoloFuzzOne_BuilderNgdotAddUint64
// *NgoloFuzzOne_BuilderNgdotAddBytes
// *NgoloFuzzOne_BuilderNgdotUnwrite
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[21]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[21]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{21}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotAddASN1Int64() *BuilderNgdotAddASN1Int64Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotAddASN1Int64); ok {
return x.BuilderNgdotAddASN1Int64
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotAddASN1Enum() *BuilderNgdotAddASN1EnumArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotAddASN1Enum); ok {
return x.BuilderNgdotAddASN1Enum
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotAddASN1Uint64() *BuilderNgdotAddASN1Uint64Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotAddASN1Uint64); ok {
return x.BuilderNgdotAddASN1Uint64
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotAddASN1BigInt() *BuilderNgdotAddASN1BigIntArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotAddASN1BigInt); ok {
return x.BuilderNgdotAddASN1BigInt
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotAddASN1OctetString() *BuilderNgdotAddASN1OctetStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotAddASN1OctetString); ok {
return x.BuilderNgdotAddASN1OctetString
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotAddASN1BitString() *BuilderNgdotAddASN1BitStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotAddASN1BitString); ok {
return x.BuilderNgdotAddASN1BitString
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotAddASN1Boolean() *BuilderNgdotAddASN1BooleanArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotAddASN1Boolean); ok {
return x.BuilderNgdotAddASN1Boolean
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotAddASN1NULL() *BuilderNgdotAddASN1NULLArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotAddASN1NULL); ok {
return x.BuilderNgdotAddASN1NULL
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotMarshalASN1() *BuilderNgdotMarshalASN1Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotMarshalASN1); ok {
return x.BuilderNgdotMarshalASN1
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewBuilder() *NewBuilderArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewBuilder); ok {
return x.NewBuilder
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewFixedBuilder() *NewFixedBuilderArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewFixedBuilder); ok {
return x.NewFixedBuilder
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotBytes() *BuilderNgdotBytesArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotBytes); ok {
return x.BuilderNgdotBytes
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotBytesOrPanic() *BuilderNgdotBytesOrPanicArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotBytesOrPanic); ok {
return x.BuilderNgdotBytesOrPanic
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotAddUint8() *BuilderNgdotAddUint8Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotAddUint8); ok {
return x.BuilderNgdotAddUint8
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotAddUint16() *BuilderNgdotAddUint16Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotAddUint16); ok {
return x.BuilderNgdotAddUint16
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotAddUint24() *BuilderNgdotAddUint24Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotAddUint24); ok {
return x.BuilderNgdotAddUint24
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotAddUint32() *BuilderNgdotAddUint32Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotAddUint32); ok {
return x.BuilderNgdotAddUint32
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotAddUint48() *BuilderNgdotAddUint48Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotAddUint48); ok {
return x.BuilderNgdotAddUint48
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotAddUint64() *BuilderNgdotAddUint64Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotAddUint64); ok {
return x.BuilderNgdotAddUint64
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotAddBytes() *BuilderNgdotAddBytesArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotAddBytes); ok {
return x.BuilderNgdotAddBytes
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotUnwrite() *BuilderNgdotUnwriteArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotUnwrite); ok {
return x.BuilderNgdotUnwrite
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_BuilderNgdotAddASN1Int64 struct {
BuilderNgdotAddASN1Int64 *BuilderNgdotAddASN1Int64Args `protobuf:"bytes,1,opt,name=BuilderNgdotAddASN1Int64,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotAddASN1Enum struct {
BuilderNgdotAddASN1Enum *BuilderNgdotAddASN1EnumArgs `protobuf:"bytes,2,opt,name=BuilderNgdotAddASN1Enum,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotAddASN1Uint64 struct {
BuilderNgdotAddASN1Uint64 *BuilderNgdotAddASN1Uint64Args `protobuf:"bytes,3,opt,name=BuilderNgdotAddASN1Uint64,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotAddASN1BigInt struct {
BuilderNgdotAddASN1BigInt *BuilderNgdotAddASN1BigIntArgs `protobuf:"bytes,4,opt,name=BuilderNgdotAddASN1BigInt,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotAddASN1OctetString struct {
BuilderNgdotAddASN1OctetString *BuilderNgdotAddASN1OctetStringArgs `protobuf:"bytes,5,opt,name=BuilderNgdotAddASN1OctetString,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotAddASN1BitString struct {
BuilderNgdotAddASN1BitString *BuilderNgdotAddASN1BitStringArgs `protobuf:"bytes,6,opt,name=BuilderNgdotAddASN1BitString,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotAddASN1Boolean struct {
BuilderNgdotAddASN1Boolean *BuilderNgdotAddASN1BooleanArgs `protobuf:"bytes,7,opt,name=BuilderNgdotAddASN1Boolean,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotAddASN1NULL struct {
BuilderNgdotAddASN1NULL *BuilderNgdotAddASN1NULLArgs `protobuf:"bytes,8,opt,name=BuilderNgdotAddASN1NULL,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotMarshalASN1 struct {
BuilderNgdotMarshalASN1 *BuilderNgdotMarshalASN1Args `protobuf:"bytes,9,opt,name=BuilderNgdotMarshalASN1,proto3,oneof"`
}
type NgoloFuzzOne_NewBuilder struct {
NewBuilder *NewBuilderArgs `protobuf:"bytes,10,opt,name=NewBuilder,proto3,oneof"`
}
type NgoloFuzzOne_NewFixedBuilder struct {
NewFixedBuilder *NewFixedBuilderArgs `protobuf:"bytes,11,opt,name=NewFixedBuilder,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotBytes struct {
BuilderNgdotBytes *BuilderNgdotBytesArgs `protobuf:"bytes,12,opt,name=BuilderNgdotBytes,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotBytesOrPanic struct {
BuilderNgdotBytesOrPanic *BuilderNgdotBytesOrPanicArgs `protobuf:"bytes,13,opt,name=BuilderNgdotBytesOrPanic,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotAddUint8 struct {
BuilderNgdotAddUint8 *BuilderNgdotAddUint8Args `protobuf:"bytes,14,opt,name=BuilderNgdotAddUint8,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotAddUint16 struct {
BuilderNgdotAddUint16 *BuilderNgdotAddUint16Args `protobuf:"bytes,15,opt,name=BuilderNgdotAddUint16,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotAddUint24 struct {
BuilderNgdotAddUint24 *BuilderNgdotAddUint24Args `protobuf:"bytes,16,opt,name=BuilderNgdotAddUint24,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotAddUint32 struct {
BuilderNgdotAddUint32 *BuilderNgdotAddUint32Args `protobuf:"bytes,17,opt,name=BuilderNgdotAddUint32,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotAddUint48 struct {
BuilderNgdotAddUint48 *BuilderNgdotAddUint48Args `protobuf:"bytes,18,opt,name=BuilderNgdotAddUint48,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotAddUint64 struct {
BuilderNgdotAddUint64 *BuilderNgdotAddUint64Args `protobuf:"bytes,19,opt,name=BuilderNgdotAddUint64,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotAddBytes struct {
BuilderNgdotAddBytes *BuilderNgdotAddBytesArgs `protobuf:"bytes,20,opt,name=BuilderNgdotAddBytes,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotUnwrite struct {
BuilderNgdotUnwrite *BuilderNgdotUnwriteArgs `protobuf:"bytes,21,opt,name=BuilderNgdotUnwrite,proto3,oneof"`
}
func (*NgoloFuzzOne_BuilderNgdotAddASN1Int64) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotAddASN1Enum) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotAddASN1Uint64) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotAddASN1BigInt) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotAddASN1OctetString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotAddASN1BitString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotAddASN1Boolean) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotAddASN1NULL) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotMarshalASN1) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewBuilder) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewFixedBuilder) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotBytes) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotBytesOrPanic) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotAddUint8) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotAddUint16) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotAddUint24) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotAddUint32) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotAddUint48) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotAddUint64) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotAddBytes) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotUnwrite) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[22]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[22]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{22}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[23]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[23]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{23}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\",\n" +
"\x1cBuilderNgdotAddASN1Int64Args\x12\f\n" +
"\x01v\x18\x01 \x01(\x03R\x01v\"+\n" +
"\x1bBuilderNgdotAddASN1EnumArgs\x12\f\n" +
"\x01v\x18\x01 \x01(\x03R\x01v\"-\n" +
"\x1dBuilderNgdotAddASN1Uint64Args\x12\f\n" +
"\x01v\x18\x01 \x01(\x04R\x01v\"-\n" +
"\x1dBuilderNgdotAddASN1BigIntArgs\x12\f\n" +
"\x01n\x18\x01 \x01(\fR\x01n\":\n" +
"\"BuilderNgdotAddASN1OctetStringArgs\x12\x14\n" +
"\x05bytes\x18\x01 \x01(\fR\x05bytes\"6\n" +
" BuilderNgdotAddASN1BitStringArgs\x12\x12\n" +
"\x04data\x18\x01 \x01(\fR\x04data\".\n" +
"\x1eBuilderNgdotAddASN1BooleanArgs\x12\f\n" +
"\x01v\x18\x01 \x01(\bR\x01v\"\x1d\n" +
"\x1bBuilderNgdotAddASN1NULLArgs\"D\n" +
"\x1bBuilderNgdotMarshalASN1Args\x12%\n" +
"\x01v\x18\x01 \x01(\v2\x17.ngolofuzz.NgoloFuzzAnyR\x01v\"(\n" +
"\x0eNewBuilderArgs\x12\x16\n" +
"\x06buffer\x18\x01 \x01(\fR\x06buffer\"-\n" +
"\x13NewFixedBuilderArgs\x12\x16\n" +
"\x06buffer\x18\x01 \x01(\fR\x06buffer\"\x17\n" +
"\x15BuilderNgdotBytesArgs\"\x1e\n" +
"\x1cBuilderNgdotBytesOrPanicArgs\"(\n" +
"\x18BuilderNgdotAddUint8Args\x12\f\n" +
"\x01v\x18\x01 \x01(\rR\x01v\")\n" +
"\x19BuilderNgdotAddUint16Args\x12\f\n" +
"\x01v\x18\x01 \x01(\rR\x01v\")\n" +
"\x19BuilderNgdotAddUint24Args\x12\f\n" +
"\x01v\x18\x01 \x01(\rR\x01v\")\n" +
"\x19BuilderNgdotAddUint32Args\x12\f\n" +
"\x01v\x18\x01 \x01(\rR\x01v\")\n" +
"\x19BuilderNgdotAddUint48Args\x12\f\n" +
"\x01v\x18\x01 \x01(\x04R\x01v\")\n" +
"\x19BuilderNgdotAddUint64Args\x12\f\n" +
"\x01v\x18\x01 \x01(\x04R\x01v\"(\n" +
"\x18BuilderNgdotAddBytesArgs\x12\f\n" +
"\x01v\x18\x01 \x01(\fR\x01v\"'\n" +
"\x17BuilderNgdotUnwriteArgs\x12\f\n" +
"\x01n\x18\x01 \x01(\x03R\x01n\"\xfc\x0f\n" +
"\fNgoloFuzzOne\x12e\n" +
"\x18BuilderNgdotAddASN1Int64\x18\x01 \x01(\v2'.ngolofuzz.BuilderNgdotAddASN1Int64ArgsH\x00R\x18BuilderNgdotAddASN1Int64\x12b\n" +
"\x17BuilderNgdotAddASN1Enum\x18\x02 \x01(\v2&.ngolofuzz.BuilderNgdotAddASN1EnumArgsH\x00R\x17BuilderNgdotAddASN1Enum\x12h\n" +
"\x19BuilderNgdotAddASN1Uint64\x18\x03 \x01(\v2(.ngolofuzz.BuilderNgdotAddASN1Uint64ArgsH\x00R\x19BuilderNgdotAddASN1Uint64\x12h\n" +
"\x19BuilderNgdotAddASN1BigInt\x18\x04 \x01(\v2(.ngolofuzz.BuilderNgdotAddASN1BigIntArgsH\x00R\x19BuilderNgdotAddASN1BigInt\x12w\n" +
"\x1eBuilderNgdotAddASN1OctetString\x18\x05 \x01(\v2-.ngolofuzz.BuilderNgdotAddASN1OctetStringArgsH\x00R\x1eBuilderNgdotAddASN1OctetString\x12q\n" +
"\x1cBuilderNgdotAddASN1BitString\x18\x06 \x01(\v2+.ngolofuzz.BuilderNgdotAddASN1BitStringArgsH\x00R\x1cBuilderNgdotAddASN1BitString\x12k\n" +
"\x1aBuilderNgdotAddASN1Boolean\x18\a \x01(\v2).ngolofuzz.BuilderNgdotAddASN1BooleanArgsH\x00R\x1aBuilderNgdotAddASN1Boolean\x12b\n" +
"\x17BuilderNgdotAddASN1NULL\x18\b \x01(\v2&.ngolofuzz.BuilderNgdotAddASN1NULLArgsH\x00R\x17BuilderNgdotAddASN1NULL\x12b\n" +
"\x17BuilderNgdotMarshalASN1\x18\t \x01(\v2&.ngolofuzz.BuilderNgdotMarshalASN1ArgsH\x00R\x17BuilderNgdotMarshalASN1\x12;\n" +
"\n" +
"NewBuilder\x18\n" +
" \x01(\v2\x19.ngolofuzz.NewBuilderArgsH\x00R\n" +
"NewBuilder\x12J\n" +
"\x0fNewFixedBuilder\x18\v \x01(\v2\x1e.ngolofuzz.NewFixedBuilderArgsH\x00R\x0fNewFixedBuilder\x12P\n" +
"\x11BuilderNgdotBytes\x18\f \x01(\v2 .ngolofuzz.BuilderNgdotBytesArgsH\x00R\x11BuilderNgdotBytes\x12e\n" +
"\x18BuilderNgdotBytesOrPanic\x18\r \x01(\v2'.ngolofuzz.BuilderNgdotBytesOrPanicArgsH\x00R\x18BuilderNgdotBytesOrPanic\x12Y\n" +
"\x14BuilderNgdotAddUint8\x18\x0e \x01(\v2#.ngolofuzz.BuilderNgdotAddUint8ArgsH\x00R\x14BuilderNgdotAddUint8\x12\\\n" +
"\x15BuilderNgdotAddUint16\x18\x0f \x01(\v2$.ngolofuzz.BuilderNgdotAddUint16ArgsH\x00R\x15BuilderNgdotAddUint16\x12\\\n" +
"\x15BuilderNgdotAddUint24\x18\x10 \x01(\v2$.ngolofuzz.BuilderNgdotAddUint24ArgsH\x00R\x15BuilderNgdotAddUint24\x12\\\n" +
"\x15BuilderNgdotAddUint32\x18\x11 \x01(\v2$.ngolofuzz.BuilderNgdotAddUint32ArgsH\x00R\x15BuilderNgdotAddUint32\x12\\\n" +
"\x15BuilderNgdotAddUint48\x18\x12 \x01(\v2$.ngolofuzz.BuilderNgdotAddUint48ArgsH\x00R\x15BuilderNgdotAddUint48\x12\\\n" +
"\x15BuilderNgdotAddUint64\x18\x13 \x01(\v2$.ngolofuzz.BuilderNgdotAddUint64ArgsH\x00R\x15BuilderNgdotAddUint64\x12Y\n" +
"\x14BuilderNgdotAddBytes\x18\x14 \x01(\v2#.ngolofuzz.BuilderNgdotAddBytesArgsH\x00R\x14BuilderNgdotAddBytes\x12V\n" +
"\x13BuilderNgdotUnwrite\x18\x15 \x01(\v2\".ngolofuzz.BuilderNgdotUnwriteArgsH\x00R\x13BuilderNgdotUnwriteB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB Z\x1e./;fuzz_ng_x_crypto_cryptobyteb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 24)
var file_ngolofuzz_proto_goTypes = []any{
(*BuilderNgdotAddASN1Int64Args)(nil), // 0: ngolofuzz.BuilderNgdotAddASN1Int64Args
(*BuilderNgdotAddASN1EnumArgs)(nil), // 1: ngolofuzz.BuilderNgdotAddASN1EnumArgs
(*BuilderNgdotAddASN1Uint64Args)(nil), // 2: ngolofuzz.BuilderNgdotAddASN1Uint64Args
(*BuilderNgdotAddASN1BigIntArgs)(nil), // 3: ngolofuzz.BuilderNgdotAddASN1BigIntArgs
(*BuilderNgdotAddASN1OctetStringArgs)(nil), // 4: ngolofuzz.BuilderNgdotAddASN1OctetStringArgs
(*BuilderNgdotAddASN1BitStringArgs)(nil), // 5: ngolofuzz.BuilderNgdotAddASN1BitStringArgs
(*BuilderNgdotAddASN1BooleanArgs)(nil), // 6: ngolofuzz.BuilderNgdotAddASN1BooleanArgs
(*BuilderNgdotAddASN1NULLArgs)(nil), // 7: ngolofuzz.BuilderNgdotAddASN1NULLArgs
(*BuilderNgdotMarshalASN1Args)(nil), // 8: ngolofuzz.BuilderNgdotMarshalASN1Args
(*NewBuilderArgs)(nil), // 9: ngolofuzz.NewBuilderArgs
(*NewFixedBuilderArgs)(nil), // 10: ngolofuzz.NewFixedBuilderArgs
(*BuilderNgdotBytesArgs)(nil), // 11: ngolofuzz.BuilderNgdotBytesArgs
(*BuilderNgdotBytesOrPanicArgs)(nil), // 12: ngolofuzz.BuilderNgdotBytesOrPanicArgs
(*BuilderNgdotAddUint8Args)(nil), // 13: ngolofuzz.BuilderNgdotAddUint8Args
(*BuilderNgdotAddUint16Args)(nil), // 14: ngolofuzz.BuilderNgdotAddUint16Args
(*BuilderNgdotAddUint24Args)(nil), // 15: ngolofuzz.BuilderNgdotAddUint24Args
(*BuilderNgdotAddUint32Args)(nil), // 16: ngolofuzz.BuilderNgdotAddUint32Args
(*BuilderNgdotAddUint48Args)(nil), // 17: ngolofuzz.BuilderNgdotAddUint48Args
(*BuilderNgdotAddUint64Args)(nil), // 18: ngolofuzz.BuilderNgdotAddUint64Args
(*BuilderNgdotAddBytesArgs)(nil), // 19: ngolofuzz.BuilderNgdotAddBytesArgs
(*BuilderNgdotUnwriteArgs)(nil), // 20: ngolofuzz.BuilderNgdotUnwriteArgs
(*NgoloFuzzOne)(nil), // 21: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 22: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 23: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
22, // 0: ngolofuzz.BuilderNgdotMarshalASN1Args.v:type_name -> ngolofuzz.NgoloFuzzAny
0, // 1: ngolofuzz.NgoloFuzzOne.BuilderNgdotAddASN1Int64:type_name -> ngolofuzz.BuilderNgdotAddASN1Int64Args
1, // 2: ngolofuzz.NgoloFuzzOne.BuilderNgdotAddASN1Enum:type_name -> ngolofuzz.BuilderNgdotAddASN1EnumArgs
2, // 3: ngolofuzz.NgoloFuzzOne.BuilderNgdotAddASN1Uint64:type_name -> ngolofuzz.BuilderNgdotAddASN1Uint64Args
3, // 4: ngolofuzz.NgoloFuzzOne.BuilderNgdotAddASN1BigInt:type_name -> ngolofuzz.BuilderNgdotAddASN1BigIntArgs
4, // 5: ngolofuzz.NgoloFuzzOne.BuilderNgdotAddASN1OctetString:type_name -> ngolofuzz.BuilderNgdotAddASN1OctetStringArgs
5, // 6: ngolofuzz.NgoloFuzzOne.BuilderNgdotAddASN1BitString:type_name -> ngolofuzz.BuilderNgdotAddASN1BitStringArgs
6, // 7: ngolofuzz.NgoloFuzzOne.BuilderNgdotAddASN1Boolean:type_name -> ngolofuzz.BuilderNgdotAddASN1BooleanArgs
7, // 8: ngolofuzz.NgoloFuzzOne.BuilderNgdotAddASN1NULL:type_name -> ngolofuzz.BuilderNgdotAddASN1NULLArgs
8, // 9: ngolofuzz.NgoloFuzzOne.BuilderNgdotMarshalASN1:type_name -> ngolofuzz.BuilderNgdotMarshalASN1Args
9, // 10: ngolofuzz.NgoloFuzzOne.NewBuilder:type_name -> ngolofuzz.NewBuilderArgs
10, // 11: ngolofuzz.NgoloFuzzOne.NewFixedBuilder:type_name -> ngolofuzz.NewFixedBuilderArgs
11, // 12: ngolofuzz.NgoloFuzzOne.BuilderNgdotBytes:type_name -> ngolofuzz.BuilderNgdotBytesArgs
12, // 13: ngolofuzz.NgoloFuzzOne.BuilderNgdotBytesOrPanic:type_name -> ngolofuzz.BuilderNgdotBytesOrPanicArgs
13, // 14: ngolofuzz.NgoloFuzzOne.BuilderNgdotAddUint8:type_name -> ngolofuzz.BuilderNgdotAddUint8Args
14, // 15: ngolofuzz.NgoloFuzzOne.BuilderNgdotAddUint16:type_name -> ngolofuzz.BuilderNgdotAddUint16Args
15, // 16: ngolofuzz.NgoloFuzzOne.BuilderNgdotAddUint24:type_name -> ngolofuzz.BuilderNgdotAddUint24Args
16, // 17: ngolofuzz.NgoloFuzzOne.BuilderNgdotAddUint32:type_name -> ngolofuzz.BuilderNgdotAddUint32Args
17, // 18: ngolofuzz.NgoloFuzzOne.BuilderNgdotAddUint48:type_name -> ngolofuzz.BuilderNgdotAddUint48Args
18, // 19: ngolofuzz.NgoloFuzzOne.BuilderNgdotAddUint64:type_name -> ngolofuzz.BuilderNgdotAddUint64Args
19, // 20: ngolofuzz.NgoloFuzzOne.BuilderNgdotAddBytes:type_name -> ngolofuzz.BuilderNgdotAddBytesArgs
20, // 21: ngolofuzz.NgoloFuzzOne.BuilderNgdotUnwrite:type_name -> ngolofuzz.BuilderNgdotUnwriteArgs
21, // 22: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
23, // [23:23] is the sub-list for method output_type
23, // [23:23] is the sub-list for method input_type
23, // [23:23] is the sub-list for extension type_name
23, // [23:23] is the sub-list for extension extendee
0, // [0:23] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[21].OneofWrappers = []any{
(*NgoloFuzzOne_BuilderNgdotAddASN1Int64)(nil),
(*NgoloFuzzOne_BuilderNgdotAddASN1Enum)(nil),
(*NgoloFuzzOne_BuilderNgdotAddASN1Uint64)(nil),
(*NgoloFuzzOne_BuilderNgdotAddASN1BigInt)(nil),
(*NgoloFuzzOne_BuilderNgdotAddASN1OctetString)(nil),
(*NgoloFuzzOne_BuilderNgdotAddASN1BitString)(nil),
(*NgoloFuzzOne_BuilderNgdotAddASN1Boolean)(nil),
(*NgoloFuzzOne_BuilderNgdotAddASN1NULL)(nil),
(*NgoloFuzzOne_BuilderNgdotMarshalASN1)(nil),
(*NgoloFuzzOne_NewBuilder)(nil),
(*NgoloFuzzOne_NewFixedBuilder)(nil),
(*NgoloFuzzOne_BuilderNgdotBytes)(nil),
(*NgoloFuzzOne_BuilderNgdotBytesOrPanic)(nil),
(*NgoloFuzzOne_BuilderNgdotAddUint8)(nil),
(*NgoloFuzzOne_BuilderNgdotAddUint16)(nil),
(*NgoloFuzzOne_BuilderNgdotAddUint24)(nil),
(*NgoloFuzzOne_BuilderNgdotAddUint32)(nil),
(*NgoloFuzzOne_BuilderNgdotAddUint48)(nil),
(*NgoloFuzzOne_BuilderNgdotAddUint64)(nil),
(*NgoloFuzzOne_BuilderNgdotAddBytes)(nil),
(*NgoloFuzzOne_BuilderNgdotUnwrite)(nil),
}
file_ngolofuzz_proto_msgTypes[22].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 24,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_curve25519
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/curve25519"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_X25519:
_, r1 := curve25519.X25519(a.X25519.Scalar, a.X25519.Point)
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_X25519:
w.WriteString(fmt.Sprintf("curve25519.X25519(%#+v, %#+v)\n", a.X25519.Scalar, a.X25519.Point))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_curve25519
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type X25519Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
Scalar []byte `protobuf:"bytes,1,opt,name=scalar,proto3" json:"scalar,omitempty"`
Point []byte `protobuf:"bytes,2,opt,name=point,proto3" json:"point,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *X25519Args) Reset() {
*x = X25519Args{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *X25519Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*X25519Args) ProtoMessage() {}
func (x *X25519Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use X25519Args.ProtoReflect.Descriptor instead.
func (*X25519Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *X25519Args) GetScalar() []byte {
if x != nil {
return x.Scalar
}
return nil
}
func (x *X25519Args) GetPoint() []byte {
if x != nil {
return x.Point
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_X25519
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetX25519() *X25519Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_X25519); ok {
return x.X25519
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_X25519 struct {
X25519 *X25519Args `protobuf:"bytes,1,opt,name=X25519,proto3,oneof"`
}
func (*NgoloFuzzOne_X25519) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\":\n" +
"\n" +
"X25519Args\x12\x16\n" +
"\x06scalar\x18\x01 \x01(\fR\x06scalar\x12\x14\n" +
"\x05point\x18\x02 \x01(\fR\x05point\"G\n" +
"\fNgoloFuzzOne\x12/\n" +
"\x06X25519\x18\x01 \x01(\v2\x15.ngolofuzz.X25519ArgsH\x00R\x06X25519B\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB Z\x1e./;fuzz_ng_x_crypto_curve25519b\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_ngolofuzz_proto_goTypes = []any{
(*X25519Args)(nil), // 0: ngolofuzz.X25519Args
(*NgoloFuzzOne)(nil), // 1: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 2: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 3: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.X25519:type_name -> ngolofuzz.X25519Args
1, // 1: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[1].OneofWrappers = []any{
(*NgoloFuzzOne_X25519)(nil),
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_ed25519
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/ed25519"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var PublicKeyResults []*ed25519.PublicKey
PublicKeyResultsIndex := 0
var PrivateKeyResults []*ed25519.PrivateKey
PrivateKeyResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_GenerateKey:
arg0 := bytes.NewReader(a.GenerateKey.Rand)
r0, r1, r2 := ed25519.GenerateKey(arg0)
PublicKeyResults = append(PublicKeyResults, &r0)
PrivateKeyResults = append(PrivateKeyResults, &r1)
if r2 != nil{
r2.Error()
return 0
}
case *NgoloFuzzOne_NewKeyFromSeed:
r0 := ed25519.NewKeyFromSeed(a.NewKeyFromSeed.Seed)
PrivateKeyResults = append(PrivateKeyResults, &r0)
case *NgoloFuzzOne_Sign:
if len(PrivateKeyResults) == 0 {
continue
}
arg0 := *PrivateKeyResults[PrivateKeyResultsIndex]
PrivateKeyResultsIndex = (PrivateKeyResultsIndex + 1) % len(PrivateKeyResults)
ed25519.Sign(arg0, a.Sign.Message)
case *NgoloFuzzOne_Verify:
if len(PublicKeyResults) == 0 {
continue
}
arg0 := *PublicKeyResults[PublicKeyResultsIndex]
PublicKeyResultsIndex = (PublicKeyResultsIndex + 1) % len(PublicKeyResults)
ed25519.Verify(arg0, a.Verify.Message, a.Verify.Sig)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
PublicKeyNb := 0
PublicKeyResultsIndex := 0
PrivateKeyNb := 0
PrivateKeyResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_GenerateKey:
w.WriteString(fmt.Sprintf("PublicKey%d, PrivateKey%d, _ := ed25519.GenerateKey(bytes.NewReader(%#+v))\n", PublicKeyNb, PrivateKeyNb, a.GenerateKey.Rand))
PublicKeyNb = PublicKeyNb + 1
PrivateKeyNb = PrivateKeyNb + 1
case *NgoloFuzzOne_NewKeyFromSeed:
w.WriteString(fmt.Sprintf("PrivateKey%d := ed25519.NewKeyFromSeed(%#+v)\n", PrivateKeyNb, a.NewKeyFromSeed.Seed))
PrivateKeyNb = PrivateKeyNb + 1
case *NgoloFuzzOne_Sign:
if PrivateKeyNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("ed25519.Sign(PrivateKey%d, %#+v)\n", (PrivateKeyResultsIndex + 0) % PrivateKeyNb, a.Sign.Message))
PrivateKeyResultsIndex = (PrivateKeyResultsIndex + 1) % PrivateKeyNb
case *NgoloFuzzOne_Verify:
if PublicKeyNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("ed25519.Verify(PublicKey%d, %#+v, %#+v)\n", (PublicKeyResultsIndex + 0) % PublicKeyNb, a.Verify.Message, a.Verify.Sig))
PublicKeyResultsIndex = (PublicKeyResultsIndex + 1) % PublicKeyNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_ed25519
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type GenerateKeyArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Rand []byte `protobuf:"bytes,1,opt,name=rand,proto3" json:"rand,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GenerateKeyArgs) Reset() {
*x = GenerateKeyArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GenerateKeyArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GenerateKeyArgs) ProtoMessage() {}
func (x *GenerateKeyArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GenerateKeyArgs.ProtoReflect.Descriptor instead.
func (*GenerateKeyArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *GenerateKeyArgs) GetRand() []byte {
if x != nil {
return x.Rand
}
return nil
}
type NewKeyFromSeedArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Seed []byte `protobuf:"bytes,1,opt,name=seed,proto3" json:"seed,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewKeyFromSeedArgs) Reset() {
*x = NewKeyFromSeedArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewKeyFromSeedArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewKeyFromSeedArgs) ProtoMessage() {}
func (x *NewKeyFromSeedArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewKeyFromSeedArgs.ProtoReflect.Descriptor instead.
func (*NewKeyFromSeedArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *NewKeyFromSeedArgs) GetSeed() []byte {
if x != nil {
return x.Seed
}
return nil
}
type SignArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Message []byte `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SignArgs) Reset() {
*x = SignArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SignArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SignArgs) ProtoMessage() {}
func (x *SignArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SignArgs.ProtoReflect.Descriptor instead.
func (*SignArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *SignArgs) GetMessage() []byte {
if x != nil {
return x.Message
}
return nil
}
type VerifyArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Message []byte `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
Sig []byte `protobuf:"bytes,2,opt,name=sig,proto3" json:"sig,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *VerifyArgs) Reset() {
*x = VerifyArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *VerifyArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*VerifyArgs) ProtoMessage() {}
func (x *VerifyArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use VerifyArgs.ProtoReflect.Descriptor instead.
func (*VerifyArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *VerifyArgs) GetMessage() []byte {
if x != nil {
return x.Message
}
return nil
}
func (x *VerifyArgs) GetSig() []byte {
if x != nil {
return x.Sig
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_GenerateKey
// *NgoloFuzzOne_NewKeyFromSeed
// *NgoloFuzzOne_Sign
// *NgoloFuzzOne_Verify
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetGenerateKey() *GenerateKeyArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_GenerateKey); ok {
return x.GenerateKey
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewKeyFromSeed() *NewKeyFromSeedArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewKeyFromSeed); ok {
return x.NewKeyFromSeed
}
}
return nil
}
func (x *NgoloFuzzOne) GetSign() *SignArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Sign); ok {
return x.Sign
}
}
return nil
}
func (x *NgoloFuzzOne) GetVerify() *VerifyArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Verify); ok {
return x.Verify
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_GenerateKey struct {
GenerateKey *GenerateKeyArgs `protobuf:"bytes,1,opt,name=GenerateKey,proto3,oneof"`
}
type NgoloFuzzOne_NewKeyFromSeed struct {
NewKeyFromSeed *NewKeyFromSeedArgs `protobuf:"bytes,2,opt,name=NewKeyFromSeed,proto3,oneof"`
}
type NgoloFuzzOne_Sign struct {
Sign *SignArgs `protobuf:"bytes,3,opt,name=Sign,proto3,oneof"`
}
type NgoloFuzzOne_Verify struct {
Verify *VerifyArgs `protobuf:"bytes,4,opt,name=Verify,proto3,oneof"`
}
func (*NgoloFuzzOne_GenerateKey) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewKeyFromSeed) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Sign) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Verify) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"%\n" +
"\x0fGenerateKeyArgs\x12\x12\n" +
"\x04rand\x18\x01 \x01(\fR\x04rand\"(\n" +
"\x12NewKeyFromSeedArgs\x12\x12\n" +
"\x04seed\x18\x01 \x01(\fR\x04seed\"$\n" +
"\bSignArgs\x12\x18\n" +
"\amessage\x18\x01 \x01(\fR\amessage\"8\n" +
"\n" +
"VerifyArgs\x12\x18\n" +
"\amessage\x18\x01 \x01(\fR\amessage\x12\x10\n" +
"\x03sig\x18\x02 \x01(\fR\x03sig\"\xfb\x01\n" +
"\fNgoloFuzzOne\x12>\n" +
"\vGenerateKey\x18\x01 \x01(\v2\x1a.ngolofuzz.GenerateKeyArgsH\x00R\vGenerateKey\x12G\n" +
"\x0eNewKeyFromSeed\x18\x02 \x01(\v2\x1d.ngolofuzz.NewKeyFromSeedArgsH\x00R\x0eNewKeyFromSeed\x12)\n" +
"\x04Sign\x18\x03 \x01(\v2\x13.ngolofuzz.SignArgsH\x00R\x04Sign\x12/\n" +
"\x06Verify\x18\x04 \x01(\v2\x15.ngolofuzz.VerifyArgsH\x00R\x06VerifyB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1dZ\x1b./;fuzz_ng_x_crypto_ed25519b\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_ngolofuzz_proto_goTypes = []any{
(*GenerateKeyArgs)(nil), // 0: ngolofuzz.GenerateKeyArgs
(*NewKeyFromSeedArgs)(nil), // 1: ngolofuzz.NewKeyFromSeedArgs
(*SignArgs)(nil), // 2: ngolofuzz.SignArgs
(*VerifyArgs)(nil), // 3: ngolofuzz.VerifyArgs
(*NgoloFuzzOne)(nil), // 4: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 5: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 6: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.GenerateKey:type_name -> ngolofuzz.GenerateKeyArgs
1, // 1: ngolofuzz.NgoloFuzzOne.NewKeyFromSeed:type_name -> ngolofuzz.NewKeyFromSeedArgs
2, // 2: ngolofuzz.NgoloFuzzOne.Sign:type_name -> ngolofuzz.SignArgs
3, // 3: ngolofuzz.NgoloFuzzOne.Verify:type_name -> ngolofuzz.VerifyArgs
4, // 4: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[4].OneofWrappers = []any{
(*NgoloFuzzOne_GenerateKey)(nil),
(*NgoloFuzzOne_NewKeyFromSeed)(nil),
(*NgoloFuzzOne_Sign)(nil),
(*NgoloFuzzOne_Verify)(nil),
}
file_ngolofuzz_proto_msgTypes[5].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 7,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_nacl_box
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/nacl/box"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_GenerateKey:
arg0 := bytes.NewReader(a.GenerateKey.Rand)
_, _, r2 := box.GenerateKey(arg0)
if r2 != nil{
r2.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_GenerateKey:
w.WriteString(fmt.Sprintf("box.GenerateKey(bytes.NewReader(%#+v))\n", a.GenerateKey.Rand))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_nacl_box
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type GenerateKeyArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Rand []byte `protobuf:"bytes,1,opt,name=rand,proto3" json:"rand,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GenerateKeyArgs) Reset() {
*x = GenerateKeyArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GenerateKeyArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GenerateKeyArgs) ProtoMessage() {}
func (x *GenerateKeyArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GenerateKeyArgs.ProtoReflect.Descriptor instead.
func (*GenerateKeyArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *GenerateKeyArgs) GetRand() []byte {
if x != nil {
return x.Rand
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_GenerateKey
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetGenerateKey() *GenerateKeyArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_GenerateKey); ok {
return x.GenerateKey
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_GenerateKey struct {
GenerateKey *GenerateKeyArgs `protobuf:"bytes,1,opt,name=GenerateKey,proto3,oneof"`
}
func (*NgoloFuzzOne_GenerateKey) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"%\n" +
"\x0fGenerateKeyArgs\x12\x12\n" +
"\x04rand\x18\x01 \x01(\fR\x04rand\"V\n" +
"\fNgoloFuzzOne\x12>\n" +
"\vGenerateKey\x18\x01 \x01(\v2\x1a.ngolofuzz.GenerateKeyArgsH\x00R\vGenerateKeyB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1eZ\x1c./;fuzz_ng_x_crypto_nacl_boxb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_ngolofuzz_proto_goTypes = []any{
(*GenerateKeyArgs)(nil), // 0: ngolofuzz.GenerateKeyArgs
(*NgoloFuzzOne)(nil), // 1: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 2: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 3: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.GenerateKey:type_name -> ngolofuzz.GenerateKeyArgs
1, // 1: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[1].OneofWrappers = []any{
(*NgoloFuzzOne_GenerateKey)(nil),
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_nacl_sign
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/nacl/sign"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_GenerateKey:
arg0 := bytes.NewReader(a.GenerateKey.Rand)
_, _, r2 := sign.GenerateKey(arg0)
if r2 != nil{
r2.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_GenerateKey:
w.WriteString(fmt.Sprintf("sign.GenerateKey(bytes.NewReader(%#+v))\n", a.GenerateKey.Rand))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_nacl_sign
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type GenerateKeyArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Rand []byte `protobuf:"bytes,1,opt,name=rand,proto3" json:"rand,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GenerateKeyArgs) Reset() {
*x = GenerateKeyArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GenerateKeyArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GenerateKeyArgs) ProtoMessage() {}
func (x *GenerateKeyArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GenerateKeyArgs.ProtoReflect.Descriptor instead.
func (*GenerateKeyArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *GenerateKeyArgs) GetRand() []byte {
if x != nil {
return x.Rand
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_GenerateKey
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetGenerateKey() *GenerateKeyArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_GenerateKey); ok {
return x.GenerateKey
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_GenerateKey struct {
GenerateKey *GenerateKeyArgs `protobuf:"bytes,1,opt,name=GenerateKey,proto3,oneof"`
}
func (*NgoloFuzzOne_GenerateKey) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"%\n" +
"\x0fGenerateKeyArgs\x12\x12\n" +
"\x04rand\x18\x01 \x01(\fR\x04rand\"V\n" +
"\fNgoloFuzzOne\x12>\n" +
"\vGenerateKey\x18\x01 \x01(\v2\x1a.ngolofuzz.GenerateKeyArgsH\x00R\vGenerateKeyB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1fZ\x1d./;fuzz_ng_x_crypto_nacl_signb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_ngolofuzz_proto_goTypes = []any{
(*GenerateKeyArgs)(nil), // 0: ngolofuzz.GenerateKeyArgs
(*NgoloFuzzOne)(nil), // 1: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 2: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 3: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.GenerateKey:type_name -> ngolofuzz.GenerateKeyArgs
1, // 1: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[1].OneofWrappers = []any{
(*NgoloFuzzOne_GenerateKey)(nil),
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_openpgp
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/openpgp"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var EntityResults []*openpgp.Entity
EntityResultsIndex := 0
var EntityListResults []*openpgp.EntityList
EntityListResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_EntityListNgdotKeysById:
if len(EntityListResults) == 0 {
continue
}
arg0 := EntityListResults[EntityListResultsIndex]
EntityListResultsIndex = (EntityListResultsIndex + 1) % len(EntityListResults)
arg0.KeysById(a.EntityListNgdotKeysById.Id)
case *NgoloFuzzOne_EntityListNgdotKeysByIdUsage:
if len(EntityListResults) == 0 {
continue
}
arg0 := EntityListResults[EntityListResultsIndex]
EntityListResultsIndex = (EntityListResultsIndex + 1) % len(EntityListResults)
arg2 := byte(a.EntityListNgdotKeysByIdUsage.RequiredUsage)
arg0.KeysByIdUsage(a.EntityListNgdotKeysByIdUsage.Id, arg2)
case *NgoloFuzzOne_EntityListNgdotDecryptionKeys:
if len(EntityListResults) == 0 {
continue
}
arg0 := EntityListResults[EntityListResultsIndex]
EntityListResultsIndex = (EntityListResultsIndex + 1) % len(EntityListResults)
arg0.DecryptionKeys()
case *NgoloFuzzOne_ReadArmoredKeyRing:
arg0 := bytes.NewReader(a.ReadArmoredKeyRing.R)
r0, r1 := openpgp.ReadArmoredKeyRing(arg0)
EntityListResults = append(EntityListResults, &r0)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_ReadKeyRing:
arg0 := bytes.NewReader(a.ReadKeyRing.R)
r0, r1 := openpgp.ReadKeyRing(arg0)
EntityListResults = append(EntityListResults, &r0)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_EntityNgdotSerialize:
if len(EntityResults) == 0 {
continue
}
arg0 := EntityResults[EntityResultsIndex]
EntityResultsIndex = (EntityResultsIndex + 1) % len(EntityResults)
arg1 := bytes.NewBuffer(a.EntityNgdotSerialize.W)
r0 := arg0.Serialize(arg1)
if r0 != nil{
r0.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
EntityNb := 0
EntityResultsIndex := 0
EntityListNb := 0
EntityListResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_EntityListNgdotKeysById:
if EntityListNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("EntityList%d.KeysById(%#+v)\n", EntityListResultsIndex, a.EntityListNgdotKeysById.Id))
EntityListResultsIndex = (EntityListResultsIndex + 1) % EntityListNb
case *NgoloFuzzOne_EntityListNgdotKeysByIdUsage:
if EntityListNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("EntityList%d.KeysByIdUsage(%#+v, byte(%#+v))\n", EntityListResultsIndex, a.EntityListNgdotKeysByIdUsage.Id, a.EntityListNgdotKeysByIdUsage.RequiredUsage))
EntityListResultsIndex = (EntityListResultsIndex + 1) % EntityListNb
case *NgoloFuzzOne_EntityListNgdotDecryptionKeys:
if EntityListNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("EntityList%d.DecryptionKeys()\n", EntityListResultsIndex))
EntityListResultsIndex = (EntityListResultsIndex + 1) % EntityListNb
case *NgoloFuzzOne_ReadArmoredKeyRing:
w.WriteString(fmt.Sprintf("EntityList%d, _ := openpgp.ReadArmoredKeyRing(bytes.NewReader(%#+v))\n", EntityListNb, a.ReadArmoredKeyRing.R))
EntityListNb = EntityListNb + 1
case *NgoloFuzzOne_ReadKeyRing:
w.WriteString(fmt.Sprintf("EntityList%d, _ := openpgp.ReadKeyRing(bytes.NewReader(%#+v))\n", EntityListNb, a.ReadKeyRing.R))
EntityListNb = EntityListNb + 1
case *NgoloFuzzOne_EntityNgdotSerialize:
if EntityNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Entity%d.Serialize(bytes.NewBuffer(%#+v))\n", EntityResultsIndex, a.EntityNgdotSerialize.W))
EntityResultsIndex = (EntityResultsIndex + 1) % EntityNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_openpgp
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type EntityListNgdotKeysByIdArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *EntityListNgdotKeysByIdArgs) Reset() {
*x = EntityListNgdotKeysByIdArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *EntityListNgdotKeysByIdArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EntityListNgdotKeysByIdArgs) ProtoMessage() {}
func (x *EntityListNgdotKeysByIdArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EntityListNgdotKeysByIdArgs.ProtoReflect.Descriptor instead.
func (*EntityListNgdotKeysByIdArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *EntityListNgdotKeysByIdArgs) GetId() uint64 {
if x != nil {
return x.Id
}
return 0
}
type EntityListNgdotKeysByIdUsageArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
RequiredUsage uint32 `protobuf:"varint,2,opt,name=requiredUsage,proto3" json:"requiredUsage,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *EntityListNgdotKeysByIdUsageArgs) Reset() {
*x = EntityListNgdotKeysByIdUsageArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *EntityListNgdotKeysByIdUsageArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EntityListNgdotKeysByIdUsageArgs) ProtoMessage() {}
func (x *EntityListNgdotKeysByIdUsageArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EntityListNgdotKeysByIdUsageArgs.ProtoReflect.Descriptor instead.
func (*EntityListNgdotKeysByIdUsageArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *EntityListNgdotKeysByIdUsageArgs) GetId() uint64 {
if x != nil {
return x.Id
}
return 0
}
func (x *EntityListNgdotKeysByIdUsageArgs) GetRequiredUsage() uint32 {
if x != nil {
return x.RequiredUsage
}
return 0
}
type EntityListNgdotDecryptionKeysArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *EntityListNgdotDecryptionKeysArgs) Reset() {
*x = EntityListNgdotDecryptionKeysArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *EntityListNgdotDecryptionKeysArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EntityListNgdotDecryptionKeysArgs) ProtoMessage() {}
func (x *EntityListNgdotDecryptionKeysArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EntityListNgdotDecryptionKeysArgs.ProtoReflect.Descriptor instead.
func (*EntityListNgdotDecryptionKeysArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
type ReadArmoredKeyRingArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R []byte `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ReadArmoredKeyRingArgs) Reset() {
*x = ReadArmoredKeyRingArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ReadArmoredKeyRingArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReadArmoredKeyRingArgs) ProtoMessage() {}
func (x *ReadArmoredKeyRingArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReadArmoredKeyRingArgs.ProtoReflect.Descriptor instead.
func (*ReadArmoredKeyRingArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *ReadArmoredKeyRingArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
type ReadKeyRingArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R []byte `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ReadKeyRingArgs) Reset() {
*x = ReadKeyRingArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ReadKeyRingArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReadKeyRingArgs) ProtoMessage() {}
func (x *ReadKeyRingArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReadKeyRingArgs.ProtoReflect.Descriptor instead.
func (*ReadKeyRingArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *ReadKeyRingArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
type EntityNgdotSerializeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
W []byte `protobuf:"bytes,1,opt,name=w,proto3" json:"w,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *EntityNgdotSerializeArgs) Reset() {
*x = EntityNgdotSerializeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *EntityNgdotSerializeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EntityNgdotSerializeArgs) ProtoMessage() {}
func (x *EntityNgdotSerializeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EntityNgdotSerializeArgs.ProtoReflect.Descriptor instead.
func (*EntityNgdotSerializeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *EntityNgdotSerializeArgs) GetW() []byte {
if x != nil {
return x.W
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_EntityListNgdotKeysById
// *NgoloFuzzOne_EntityListNgdotKeysByIdUsage
// *NgoloFuzzOne_EntityListNgdotDecryptionKeys
// *NgoloFuzzOne_ReadArmoredKeyRing
// *NgoloFuzzOne_ReadKeyRing
// *NgoloFuzzOne_EntityNgdotSerialize
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetEntityListNgdotKeysById() *EntityListNgdotKeysByIdArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_EntityListNgdotKeysById); ok {
return x.EntityListNgdotKeysById
}
}
return nil
}
func (x *NgoloFuzzOne) GetEntityListNgdotKeysByIdUsage() *EntityListNgdotKeysByIdUsageArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_EntityListNgdotKeysByIdUsage); ok {
return x.EntityListNgdotKeysByIdUsage
}
}
return nil
}
func (x *NgoloFuzzOne) GetEntityListNgdotDecryptionKeys() *EntityListNgdotDecryptionKeysArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_EntityListNgdotDecryptionKeys); ok {
return x.EntityListNgdotDecryptionKeys
}
}
return nil
}
func (x *NgoloFuzzOne) GetReadArmoredKeyRing() *ReadArmoredKeyRingArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ReadArmoredKeyRing); ok {
return x.ReadArmoredKeyRing
}
}
return nil
}
func (x *NgoloFuzzOne) GetReadKeyRing() *ReadKeyRingArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ReadKeyRing); ok {
return x.ReadKeyRing
}
}
return nil
}
func (x *NgoloFuzzOne) GetEntityNgdotSerialize() *EntityNgdotSerializeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_EntityNgdotSerialize); ok {
return x.EntityNgdotSerialize
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_EntityListNgdotKeysById struct {
EntityListNgdotKeysById *EntityListNgdotKeysByIdArgs `protobuf:"bytes,1,opt,name=EntityListNgdotKeysById,proto3,oneof"`
}
type NgoloFuzzOne_EntityListNgdotKeysByIdUsage struct {
EntityListNgdotKeysByIdUsage *EntityListNgdotKeysByIdUsageArgs `protobuf:"bytes,2,opt,name=EntityListNgdotKeysByIdUsage,proto3,oneof"`
}
type NgoloFuzzOne_EntityListNgdotDecryptionKeys struct {
EntityListNgdotDecryptionKeys *EntityListNgdotDecryptionKeysArgs `protobuf:"bytes,3,opt,name=EntityListNgdotDecryptionKeys,proto3,oneof"`
}
type NgoloFuzzOne_ReadArmoredKeyRing struct {
ReadArmoredKeyRing *ReadArmoredKeyRingArgs `protobuf:"bytes,4,opt,name=ReadArmoredKeyRing,proto3,oneof"`
}
type NgoloFuzzOne_ReadKeyRing struct {
ReadKeyRing *ReadKeyRingArgs `protobuf:"bytes,5,opt,name=ReadKeyRing,proto3,oneof"`
}
type NgoloFuzzOne_EntityNgdotSerialize struct {
EntityNgdotSerialize *EntityNgdotSerializeArgs `protobuf:"bytes,6,opt,name=EntityNgdotSerialize,proto3,oneof"`
}
func (*NgoloFuzzOne_EntityListNgdotKeysById) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_EntityListNgdotKeysByIdUsage) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_EntityListNgdotDecryptionKeys) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ReadArmoredKeyRing) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ReadKeyRing) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_EntityNgdotSerialize) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"-\n" +
"\x1bEntityListNgdotKeysByIdArgs\x12\x0e\n" +
"\x02id\x18\x01 \x01(\x04R\x02id\"X\n" +
" EntityListNgdotKeysByIdUsageArgs\x12\x0e\n" +
"\x02id\x18\x01 \x01(\x04R\x02id\x12$\n" +
"\rrequiredUsage\x18\x02 \x01(\rR\rrequiredUsage\"#\n" +
"!EntityListNgdotDecryptionKeysArgs\"&\n" +
"\x16ReadArmoredKeyRingArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\fR\x01r\"\x1f\n" +
"\x0fReadKeyRingArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\fR\x01r\"(\n" +
"\x18EntityNgdotSerializeArgs\x12\f\n" +
"\x01w\x18\x01 \x01(\fR\x01w\"\xd3\x04\n" +
"\fNgoloFuzzOne\x12b\n" +
"\x17EntityListNgdotKeysById\x18\x01 \x01(\v2&.ngolofuzz.EntityListNgdotKeysByIdArgsH\x00R\x17EntityListNgdotKeysById\x12q\n" +
"\x1cEntityListNgdotKeysByIdUsage\x18\x02 \x01(\v2+.ngolofuzz.EntityListNgdotKeysByIdUsageArgsH\x00R\x1cEntityListNgdotKeysByIdUsage\x12t\n" +
"\x1dEntityListNgdotDecryptionKeys\x18\x03 \x01(\v2,.ngolofuzz.EntityListNgdotDecryptionKeysArgsH\x00R\x1dEntityListNgdotDecryptionKeys\x12S\n" +
"\x12ReadArmoredKeyRing\x18\x04 \x01(\v2!.ngolofuzz.ReadArmoredKeyRingArgsH\x00R\x12ReadArmoredKeyRing\x12>\n" +
"\vReadKeyRing\x18\x05 \x01(\v2\x1a.ngolofuzz.ReadKeyRingArgsH\x00R\vReadKeyRing\x12Y\n" +
"\x14EntityNgdotSerialize\x18\x06 \x01(\v2#.ngolofuzz.EntityNgdotSerializeArgsH\x00R\x14EntityNgdotSerializeB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1dZ\x1b./;fuzz_ng_x_crypto_openpgpb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
var file_ngolofuzz_proto_goTypes = []any{
(*EntityListNgdotKeysByIdArgs)(nil), // 0: ngolofuzz.EntityListNgdotKeysByIdArgs
(*EntityListNgdotKeysByIdUsageArgs)(nil), // 1: ngolofuzz.EntityListNgdotKeysByIdUsageArgs
(*EntityListNgdotDecryptionKeysArgs)(nil), // 2: ngolofuzz.EntityListNgdotDecryptionKeysArgs
(*ReadArmoredKeyRingArgs)(nil), // 3: ngolofuzz.ReadArmoredKeyRingArgs
(*ReadKeyRingArgs)(nil), // 4: ngolofuzz.ReadKeyRingArgs
(*EntityNgdotSerializeArgs)(nil), // 5: ngolofuzz.EntityNgdotSerializeArgs
(*NgoloFuzzOne)(nil), // 6: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 7: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 8: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.EntityListNgdotKeysById:type_name -> ngolofuzz.EntityListNgdotKeysByIdArgs
1, // 1: ngolofuzz.NgoloFuzzOne.EntityListNgdotKeysByIdUsage:type_name -> ngolofuzz.EntityListNgdotKeysByIdUsageArgs
2, // 2: ngolofuzz.NgoloFuzzOne.EntityListNgdotDecryptionKeys:type_name -> ngolofuzz.EntityListNgdotDecryptionKeysArgs
3, // 3: ngolofuzz.NgoloFuzzOne.ReadArmoredKeyRing:type_name -> ngolofuzz.ReadArmoredKeyRingArgs
4, // 4: ngolofuzz.NgoloFuzzOne.ReadKeyRing:type_name -> ngolofuzz.ReadKeyRingArgs
5, // 5: ngolofuzz.NgoloFuzzOne.EntityNgdotSerialize:type_name -> ngolofuzz.EntityNgdotSerializeArgs
6, // 6: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
7, // [7:7] is the sub-list for method output_type
7, // [7:7] is the sub-list for method input_type
7, // [7:7] is the sub-list for extension type_name
7, // [7:7] is the sub-list for extension extendee
0, // [0:7] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[6].OneofWrappers = []any{
(*NgoloFuzzOne_EntityListNgdotKeysById)(nil),
(*NgoloFuzzOne_EntityListNgdotKeysByIdUsage)(nil),
(*NgoloFuzzOne_EntityListNgdotDecryptionKeys)(nil),
(*NgoloFuzzOne_ReadArmoredKeyRing)(nil),
(*NgoloFuzzOne_ReadKeyRing)(nil),
(*NgoloFuzzOne_EntityNgdotSerialize)(nil),
}
file_ngolofuzz_proto_msgTypes[7].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 9,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_openpgp_armor
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/openpgp/armor"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Decode:
arg0 := bytes.NewReader(a.Decode.In)
_, r1 := armor.Decode(arg0)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_Encode:
arg0 := bytes.NewBuffer(a.Encode.Out)
_, r1 := armor.Encode(arg0, a.Encode.BlockType, a.Encode.Headers)
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Decode:
w.WriteString(fmt.Sprintf("armor.Decode(bytes.NewReader(%#+v))\n", a.Decode.In))
case *NgoloFuzzOne_Encode:
w.WriteString(fmt.Sprintf("armor.Encode(bytes.NewBuffer(%#+v), %#+v, %#+v)\n", a.Encode.Out, a.Encode.BlockType, a.Encode.Headers))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_openpgp_armor
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type DecodeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
In []byte `protobuf:"bytes,1,opt,name=in,proto3" json:"in,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecodeArgs) Reset() {
*x = DecodeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecodeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecodeArgs) ProtoMessage() {}
func (x *DecodeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecodeArgs.ProtoReflect.Descriptor instead.
func (*DecodeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *DecodeArgs) GetIn() []byte {
if x != nil {
return x.In
}
return nil
}
type EncodeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Out []byte `protobuf:"bytes,1,opt,name=out,proto3" json:"out,omitempty"`
BlockType string `protobuf:"bytes,2,opt,name=blockType,proto3" json:"blockType,omitempty"`
Headers map[string]string `protobuf:"bytes,3,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *EncodeArgs) Reset() {
*x = EncodeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *EncodeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EncodeArgs) ProtoMessage() {}
func (x *EncodeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EncodeArgs.ProtoReflect.Descriptor instead.
func (*EncodeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *EncodeArgs) GetOut() []byte {
if x != nil {
return x.Out
}
return nil
}
func (x *EncodeArgs) GetBlockType() string {
if x != nil {
return x.BlockType
}
return ""
}
func (x *EncodeArgs) GetHeaders() map[string]string {
if x != nil {
return x.Headers
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_Decode
// *NgoloFuzzOne_Encode
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetDecode() *DecodeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Decode); ok {
return x.Decode
}
}
return nil
}
func (x *NgoloFuzzOne) GetEncode() *EncodeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Encode); ok {
return x.Encode
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_Decode struct {
Decode *DecodeArgs `protobuf:"bytes,1,opt,name=Decode,proto3,oneof"`
}
type NgoloFuzzOne_Encode struct {
Encode *EncodeArgs `protobuf:"bytes,2,opt,name=Encode,proto3,oneof"`
}
func (*NgoloFuzzOne_Decode) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Encode) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x1c\n" +
"\n" +
"DecodeArgs\x12\x0e\n" +
"\x02in\x18\x01 \x01(\fR\x02in\"\xb6\x01\n" +
"\n" +
"EncodeArgs\x12\x10\n" +
"\x03out\x18\x01 \x01(\fR\x03out\x12\x1c\n" +
"\tblockType\x18\x02 \x01(\tR\tblockType\x12<\n" +
"\aheaders\x18\x03 \x03(\v2\".ngolofuzz.EncodeArgs.HeadersEntryR\aheaders\x1a:\n" +
"\fHeadersEntry\x12\x10\n" +
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"x\n" +
"\fNgoloFuzzOne\x12/\n" +
"\x06Decode\x18\x01 \x01(\v2\x15.ngolofuzz.DecodeArgsH\x00R\x06Decode\x12/\n" +
"\x06Encode\x18\x02 \x01(\v2\x15.ngolofuzz.EncodeArgsH\x00R\x06EncodeB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB#Z!./;fuzz_ng_x_crypto_openpgp_armorb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_ngolofuzz_proto_goTypes = []any{
(*DecodeArgs)(nil), // 0: ngolofuzz.DecodeArgs
(*EncodeArgs)(nil), // 1: ngolofuzz.EncodeArgs
(*NgoloFuzzOne)(nil), // 2: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 3: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 4: ngolofuzz.NgoloFuzzList
nil, // 5: ngolofuzz.EncodeArgs.HeadersEntry
}
var file_ngolofuzz_proto_depIdxs = []int32{
5, // 0: ngolofuzz.EncodeArgs.headers:type_name -> ngolofuzz.EncodeArgs.HeadersEntry
0, // 1: ngolofuzz.NgoloFuzzOne.Decode:type_name -> ngolofuzz.DecodeArgs
1, // 2: ngolofuzz.NgoloFuzzOne.Encode:type_name -> ngolofuzz.EncodeArgs
2, // 3: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzOne_Decode)(nil),
(*NgoloFuzzOne_Encode)(nil),
}
file_ngolofuzz_proto_msgTypes[3].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 6,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_openpgp_clearsign
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/openpgp/clearsign"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Decode:
clearsign.Decode(a.Decode.Data)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Decode:
w.WriteString(fmt.Sprintf("clearsign.Decode(%#+v)\n", a.Decode.Data))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_openpgp_clearsign
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type DecodeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecodeArgs) Reset() {
*x = DecodeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecodeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecodeArgs) ProtoMessage() {}
func (x *DecodeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecodeArgs.ProtoReflect.Descriptor instead.
func (*DecodeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *DecodeArgs) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_Decode
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetDecode() *DecodeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Decode); ok {
return x.Decode
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_Decode struct {
Decode *DecodeArgs `protobuf:"bytes,1,opt,name=Decode,proto3,oneof"`
}
func (*NgoloFuzzOne_Decode) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\" \n" +
"\n" +
"DecodeArgs\x12\x12\n" +
"\x04data\x18\x01 \x01(\fR\x04data\"G\n" +
"\fNgoloFuzzOne\x12/\n" +
"\x06Decode\x18\x01 \x01(\v2\x15.ngolofuzz.DecodeArgsH\x00R\x06DecodeB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB'Z%./;fuzz_ng_x_crypto_openpgp_clearsignb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_ngolofuzz_proto_goTypes = []any{
(*DecodeArgs)(nil), // 0: ngolofuzz.DecodeArgs
(*NgoloFuzzOne)(nil), // 1: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 2: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 3: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.Decode:type_name -> ngolofuzz.DecodeArgs
1, // 1: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[1].OneofWrappers = []any{
(*NgoloFuzzOne_Decode)(nil),
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_openpgp_s2k
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/openpgp/s2k"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Parse:
arg0 := bytes.NewReader(a.Parse.R)
s2k.Parse(arg0)
case *NgoloFuzzOne_HashIdToHash:
arg0 := byte(a.HashIdToHash.Id)
s2k.HashIdToHash(arg0)
case *NgoloFuzzOne_HashIdToString:
arg0 := byte(a.HashIdToString.Id)
s2k.HashIdToString(arg0)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Parse:
w.WriteString(fmt.Sprintf("s2k.Parse(bytes.NewReader(%#+v))\n", a.Parse.R))
case *NgoloFuzzOne_HashIdToHash:
w.WriteString(fmt.Sprintf("s2k.HashIdToHash(byte(%#+v))\n", a.HashIdToHash.Id))
case *NgoloFuzzOne_HashIdToString:
w.WriteString(fmt.Sprintf("s2k.HashIdToString(byte(%#+v))\n", a.HashIdToString.Id))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_openpgp_s2k
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ParseArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R []byte `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ParseArgs) Reset() {
*x = ParseArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ParseArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ParseArgs) ProtoMessage() {}
func (x *ParseArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ParseArgs.ProtoReflect.Descriptor instead.
func (*ParseArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *ParseArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
type HashIdToHashArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Id uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HashIdToHashArgs) Reset() {
*x = HashIdToHashArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HashIdToHashArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HashIdToHashArgs) ProtoMessage() {}
func (x *HashIdToHashArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HashIdToHashArgs.ProtoReflect.Descriptor instead.
func (*HashIdToHashArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *HashIdToHashArgs) GetId() uint32 {
if x != nil {
return x.Id
}
return 0
}
type HashIdToStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Id uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HashIdToStringArgs) Reset() {
*x = HashIdToStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HashIdToStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HashIdToStringArgs) ProtoMessage() {}
func (x *HashIdToStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HashIdToStringArgs.ProtoReflect.Descriptor instead.
func (*HashIdToStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *HashIdToStringArgs) GetId() uint32 {
if x != nil {
return x.Id
}
return 0
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_Parse
// *NgoloFuzzOne_HashIdToHash
// *NgoloFuzzOne_HashIdToString
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetParse() *ParseArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Parse); ok {
return x.Parse
}
}
return nil
}
func (x *NgoloFuzzOne) GetHashIdToHash() *HashIdToHashArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_HashIdToHash); ok {
return x.HashIdToHash
}
}
return nil
}
func (x *NgoloFuzzOne) GetHashIdToString() *HashIdToStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_HashIdToString); ok {
return x.HashIdToString
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_Parse struct {
Parse *ParseArgs `protobuf:"bytes,1,opt,name=Parse,proto3,oneof"`
}
type NgoloFuzzOne_HashIdToHash struct {
HashIdToHash *HashIdToHashArgs `protobuf:"bytes,2,opt,name=HashIdToHash,proto3,oneof"`
}
type NgoloFuzzOne_HashIdToString struct {
HashIdToString *HashIdToStringArgs `protobuf:"bytes,3,opt,name=HashIdToString,proto3,oneof"`
}
func (*NgoloFuzzOne_Parse) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_HashIdToHash) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_HashIdToString) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x19\n" +
"\tParseArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\fR\x01r\"\"\n" +
"\x10HashIdToHashArgs\x12\x0e\n" +
"\x02id\x18\x01 \x01(\rR\x02id\"$\n" +
"\x12HashIdToStringArgs\x12\x0e\n" +
"\x02id\x18\x01 \x01(\rR\x02id\"\xd0\x01\n" +
"\fNgoloFuzzOne\x12,\n" +
"\x05Parse\x18\x01 \x01(\v2\x14.ngolofuzz.ParseArgsH\x00R\x05Parse\x12A\n" +
"\fHashIdToHash\x18\x02 \x01(\v2\x1b.ngolofuzz.HashIdToHashArgsH\x00R\fHashIdToHash\x12G\n" +
"\x0eHashIdToString\x18\x03 \x01(\v2\x1d.ngolofuzz.HashIdToStringArgsH\x00R\x0eHashIdToStringB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB!Z\x1f./;fuzz_ng_x_crypto_openpgp_s2kb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_ngolofuzz_proto_goTypes = []any{
(*ParseArgs)(nil), // 0: ngolofuzz.ParseArgs
(*HashIdToHashArgs)(nil), // 1: ngolofuzz.HashIdToHashArgs
(*HashIdToStringArgs)(nil), // 2: ngolofuzz.HashIdToStringArgs
(*NgoloFuzzOne)(nil), // 3: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 4: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 5: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.Parse:type_name -> ngolofuzz.ParseArgs
1, // 1: ngolofuzz.NgoloFuzzOne.HashIdToHash:type_name -> ngolofuzz.HashIdToHashArgs
2, // 2: ngolofuzz.NgoloFuzzOne.HashIdToString:type_name -> ngolofuzz.HashIdToStringArgs
3, // 3: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[3].OneofWrappers = []any{
(*NgoloFuzzOne_Parse)(nil),
(*NgoloFuzzOne_HashIdToHash)(nil),
(*NgoloFuzzOne_HashIdToString)(nil),
}
file_ngolofuzz_proto_msgTypes[4].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 6,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_pkcs12
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/pkcs12"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_ToPEM:
_, r1 := pkcs12.ToPEM(a.ToPEM.PfxData, a.ToPEM.Password)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_Decode:
_, _, r2 := pkcs12.Decode(a.Decode.PfxData, a.Decode.Password)
if r2 != nil{
r2.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_ToPEM:
w.WriteString(fmt.Sprintf("pkcs12.ToPEM(%#+v, %#+v)\n", a.ToPEM.PfxData, a.ToPEM.Password))
case *NgoloFuzzOne_Decode:
w.WriteString(fmt.Sprintf("pkcs12.Decode(%#+v, %#+v)\n", a.Decode.PfxData, a.Decode.Password))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_pkcs12
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ToPEMArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
PfxData []byte `protobuf:"bytes,1,opt,name=pfxData,proto3" json:"pfxData,omitempty"`
Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ToPEMArgs) Reset() {
*x = ToPEMArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ToPEMArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ToPEMArgs) ProtoMessage() {}
func (x *ToPEMArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ToPEMArgs.ProtoReflect.Descriptor instead.
func (*ToPEMArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *ToPEMArgs) GetPfxData() []byte {
if x != nil {
return x.PfxData
}
return nil
}
func (x *ToPEMArgs) GetPassword() string {
if x != nil {
return x.Password
}
return ""
}
type DecodeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
PfxData []byte `protobuf:"bytes,1,opt,name=pfxData,proto3" json:"pfxData,omitempty"`
Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecodeArgs) Reset() {
*x = DecodeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecodeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecodeArgs) ProtoMessage() {}
func (x *DecodeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecodeArgs.ProtoReflect.Descriptor instead.
func (*DecodeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *DecodeArgs) GetPfxData() []byte {
if x != nil {
return x.PfxData
}
return nil
}
func (x *DecodeArgs) GetPassword() string {
if x != nil {
return x.Password
}
return ""
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_ToPEM
// *NgoloFuzzOne_Decode
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetToPEM() *ToPEMArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ToPEM); ok {
return x.ToPEM
}
}
return nil
}
func (x *NgoloFuzzOne) GetDecode() *DecodeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Decode); ok {
return x.Decode
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_ToPEM struct {
ToPEM *ToPEMArgs `protobuf:"bytes,1,opt,name=ToPEM,proto3,oneof"`
}
type NgoloFuzzOne_Decode struct {
Decode *DecodeArgs `protobuf:"bytes,2,opt,name=Decode,proto3,oneof"`
}
func (*NgoloFuzzOne_ToPEM) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Decode) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"A\n" +
"\tToPEMArgs\x12\x18\n" +
"\apfxData\x18\x01 \x01(\fR\apfxData\x12\x1a\n" +
"\bpassword\x18\x02 \x01(\tR\bpassword\"B\n" +
"\n" +
"DecodeArgs\x12\x18\n" +
"\apfxData\x18\x01 \x01(\fR\apfxData\x12\x1a\n" +
"\bpassword\x18\x02 \x01(\tR\bpassword\"u\n" +
"\fNgoloFuzzOne\x12,\n" +
"\x05ToPEM\x18\x01 \x01(\v2\x14.ngolofuzz.ToPEMArgsH\x00R\x05ToPEM\x12/\n" +
"\x06Decode\x18\x02 \x01(\v2\x15.ngolofuzz.DecodeArgsH\x00R\x06DecodeB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1cZ\x1a./;fuzz_ng_x_crypto_pkcs12b\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_ngolofuzz_proto_goTypes = []any{
(*ToPEMArgs)(nil), // 0: ngolofuzz.ToPEMArgs
(*DecodeArgs)(nil), // 1: ngolofuzz.DecodeArgs
(*NgoloFuzzOne)(nil), // 2: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 3: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 4: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.ToPEM:type_name -> ngolofuzz.ToPEMArgs
1, // 1: ngolofuzz.NgoloFuzzOne.Decode:type_name -> ngolofuzz.DecodeArgs
2, // 2: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzOne_ToPEM)(nil),
(*NgoloFuzzOne_Decode)(nil),
}
file_ngolofuzz_proto_msgTypes[3].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_poly1305
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/poly1305"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var MACResults []*poly1305.MAC
MACResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_MACNgdotSize:
if len(MACResults) == 0 {
continue
}
arg0 := MACResults[MACResultsIndex]
MACResultsIndex = (MACResultsIndex + 1) % len(MACResults)
arg0.Size()
case *NgoloFuzzOne_MACNgdotWrite:
if len(MACResults) == 0 {
continue
}
arg0 := MACResults[MACResultsIndex]
MACResultsIndex = (MACResultsIndex + 1) % len(MACResults)
_, r1 := arg0.Write(a.MACNgdotWrite.P)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_MACNgdotSum:
if len(MACResults) == 0 {
continue
}
arg0 := MACResults[MACResultsIndex]
MACResultsIndex = (MACResultsIndex + 1) % len(MACResults)
arg0.Sum(a.MACNgdotSum.B)
case *NgoloFuzzOne_MACNgdotVerify:
if len(MACResults) == 0 {
continue
}
arg0 := MACResults[MACResultsIndex]
MACResultsIndex = (MACResultsIndex + 1) % len(MACResults)
arg0.Verify(a.MACNgdotVerify.Expected)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
MACNb := 0
MACResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_MACNgdotSize:
if MACNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("MAC%d.Size()\n", MACResultsIndex))
MACResultsIndex = (MACResultsIndex + 1) % MACNb
case *NgoloFuzzOne_MACNgdotWrite:
if MACNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("MAC%d.Write(%#+v)\n", MACResultsIndex, a.MACNgdotWrite.P))
MACResultsIndex = (MACResultsIndex + 1) % MACNb
case *NgoloFuzzOne_MACNgdotSum:
if MACNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("MAC%d.Sum(%#+v)\n", MACResultsIndex, a.MACNgdotSum.B))
MACResultsIndex = (MACResultsIndex + 1) % MACNb
case *NgoloFuzzOne_MACNgdotVerify:
if MACNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("MAC%d.Verify(%#+v)\n", MACResultsIndex, a.MACNgdotVerify.Expected))
MACResultsIndex = (MACResultsIndex + 1) % MACNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_poly1305
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type MACNgdotSizeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *MACNgdotSizeArgs) Reset() {
*x = MACNgdotSizeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *MACNgdotSizeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MACNgdotSizeArgs) ProtoMessage() {}
func (x *MACNgdotSizeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MACNgdotSizeArgs.ProtoReflect.Descriptor instead.
func (*MACNgdotSizeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type MACNgdotWriteArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
P []byte `protobuf:"bytes,1,opt,name=p,proto3" json:"p,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *MACNgdotWriteArgs) Reset() {
*x = MACNgdotWriteArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *MACNgdotWriteArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MACNgdotWriteArgs) ProtoMessage() {}
func (x *MACNgdotWriteArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MACNgdotWriteArgs.ProtoReflect.Descriptor instead.
func (*MACNgdotWriteArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *MACNgdotWriteArgs) GetP() []byte {
if x != nil {
return x.P
}
return nil
}
type MACNgdotSumArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
B []byte `protobuf:"bytes,1,opt,name=b,proto3" json:"b,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *MACNgdotSumArgs) Reset() {
*x = MACNgdotSumArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *MACNgdotSumArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MACNgdotSumArgs) ProtoMessage() {}
func (x *MACNgdotSumArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MACNgdotSumArgs.ProtoReflect.Descriptor instead.
func (*MACNgdotSumArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *MACNgdotSumArgs) GetB() []byte {
if x != nil {
return x.B
}
return nil
}
type MACNgdotVerifyArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Expected []byte `protobuf:"bytes,1,opt,name=expected,proto3" json:"expected,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *MACNgdotVerifyArgs) Reset() {
*x = MACNgdotVerifyArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *MACNgdotVerifyArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MACNgdotVerifyArgs) ProtoMessage() {}
func (x *MACNgdotVerifyArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MACNgdotVerifyArgs.ProtoReflect.Descriptor instead.
func (*MACNgdotVerifyArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *MACNgdotVerifyArgs) GetExpected() []byte {
if x != nil {
return x.Expected
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_MACNgdotSize
// *NgoloFuzzOne_MACNgdotWrite
// *NgoloFuzzOne_MACNgdotSum
// *NgoloFuzzOne_MACNgdotVerify
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetMACNgdotSize() *MACNgdotSizeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_MACNgdotSize); ok {
return x.MACNgdotSize
}
}
return nil
}
func (x *NgoloFuzzOne) GetMACNgdotWrite() *MACNgdotWriteArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_MACNgdotWrite); ok {
return x.MACNgdotWrite
}
}
return nil
}
func (x *NgoloFuzzOne) GetMACNgdotSum() *MACNgdotSumArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_MACNgdotSum); ok {
return x.MACNgdotSum
}
}
return nil
}
func (x *NgoloFuzzOne) GetMACNgdotVerify() *MACNgdotVerifyArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_MACNgdotVerify); ok {
return x.MACNgdotVerify
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_MACNgdotSize struct {
MACNgdotSize *MACNgdotSizeArgs `protobuf:"bytes,1,opt,name=MACNgdotSize,proto3,oneof"`
}
type NgoloFuzzOne_MACNgdotWrite struct {
MACNgdotWrite *MACNgdotWriteArgs `protobuf:"bytes,2,opt,name=MACNgdotWrite,proto3,oneof"`
}
type NgoloFuzzOne_MACNgdotSum struct {
MACNgdotSum *MACNgdotSumArgs `protobuf:"bytes,3,opt,name=MACNgdotSum,proto3,oneof"`
}
type NgoloFuzzOne_MACNgdotVerify struct {
MACNgdotVerify *MACNgdotVerifyArgs `protobuf:"bytes,4,opt,name=MACNgdotVerify,proto3,oneof"`
}
func (*NgoloFuzzOne_MACNgdotSize) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_MACNgdotWrite) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_MACNgdotSum) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_MACNgdotVerify) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x12\n" +
"\x10MACNgdotSizeArgs\"!\n" +
"\x11MACNgdotWriteArgs\x12\f\n" +
"\x01p\x18\x01 \x01(\fR\x01p\"\x1f\n" +
"\x0fMACNgdotSumArgs\x12\f\n" +
"\x01b\x18\x01 \x01(\fR\x01b\"0\n" +
"\x12MACNgdotVerifyArgs\x12\x1a\n" +
"\bexpected\x18\x01 \x01(\fR\bexpected\"\xa8\x02\n" +
"\fNgoloFuzzOne\x12A\n" +
"\fMACNgdotSize\x18\x01 \x01(\v2\x1b.ngolofuzz.MACNgdotSizeArgsH\x00R\fMACNgdotSize\x12D\n" +
"\rMACNgdotWrite\x18\x02 \x01(\v2\x1c.ngolofuzz.MACNgdotWriteArgsH\x00R\rMACNgdotWrite\x12>\n" +
"\vMACNgdotSum\x18\x03 \x01(\v2\x1a.ngolofuzz.MACNgdotSumArgsH\x00R\vMACNgdotSum\x12G\n" +
"\x0eMACNgdotVerify\x18\x04 \x01(\v2\x1d.ngolofuzz.MACNgdotVerifyArgsH\x00R\x0eMACNgdotVerifyB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1eZ\x1c./;fuzz_ng_x_crypto_poly1305b\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_ngolofuzz_proto_goTypes = []any{
(*MACNgdotSizeArgs)(nil), // 0: ngolofuzz.MACNgdotSizeArgs
(*MACNgdotWriteArgs)(nil), // 1: ngolofuzz.MACNgdotWriteArgs
(*MACNgdotSumArgs)(nil), // 2: ngolofuzz.MACNgdotSumArgs
(*MACNgdotVerifyArgs)(nil), // 3: ngolofuzz.MACNgdotVerifyArgs
(*NgoloFuzzOne)(nil), // 4: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 5: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 6: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.MACNgdotSize:type_name -> ngolofuzz.MACNgdotSizeArgs
1, // 1: ngolofuzz.NgoloFuzzOne.MACNgdotWrite:type_name -> ngolofuzz.MACNgdotWriteArgs
2, // 2: ngolofuzz.NgoloFuzzOne.MACNgdotSum:type_name -> ngolofuzz.MACNgdotSumArgs
3, // 3: ngolofuzz.NgoloFuzzOne.MACNgdotVerify:type_name -> ngolofuzz.MACNgdotVerifyArgs
4, // 4: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[4].OneofWrappers = []any{
(*NgoloFuzzOne_MACNgdotSize)(nil),
(*NgoloFuzzOne_MACNgdotWrite)(nil),
(*NgoloFuzzOne_MACNgdotSum)(nil),
(*NgoloFuzzOne_MACNgdotVerify)(nil),
}
file_ngolofuzz_proto_msgTypes[5].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 7,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_scrypt
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/scrypt"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Key:
arg2 := int(a.Key.N)
arg3 := int(a.Key.R)
arg4 := int(a.Key.P)
arg5 := int(a.Key.KeyLen)
_, r1 := scrypt.Key(a.Key.Password, a.Key.Salt, arg2, arg3, arg4, arg5)
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Key:
w.WriteString(fmt.Sprintf("scrypt.Key(%#+v, %#+v, int(%#+v), int(%#+v), int(%#+v), int(%#+v))\n", a.Key.Password, a.Key.Salt, a.Key.N, a.Key.R, a.Key.P, a.Key.KeyLen))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_scrypt
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type KeyArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Password []byte `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"`
Salt []byte `protobuf:"bytes,2,opt,name=salt,proto3" json:"salt,omitempty"`
N int64 `protobuf:"varint,3,opt,name=N,proto3" json:"N,omitempty"`
R int64 `protobuf:"varint,4,opt,name=r,proto3" json:"r,omitempty"`
P int64 `protobuf:"varint,5,opt,name=p,proto3" json:"p,omitempty"`
KeyLen int64 `protobuf:"varint,6,opt,name=keyLen,proto3" json:"keyLen,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *KeyArgs) Reset() {
*x = KeyArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *KeyArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*KeyArgs) ProtoMessage() {}
func (x *KeyArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use KeyArgs.ProtoReflect.Descriptor instead.
func (*KeyArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *KeyArgs) GetPassword() []byte {
if x != nil {
return x.Password
}
return nil
}
func (x *KeyArgs) GetSalt() []byte {
if x != nil {
return x.Salt
}
return nil
}
func (x *KeyArgs) GetN() int64 {
if x != nil {
return x.N
}
return 0
}
func (x *KeyArgs) GetR() int64 {
if x != nil {
return x.R
}
return 0
}
func (x *KeyArgs) GetP() int64 {
if x != nil {
return x.P
}
return 0
}
func (x *KeyArgs) GetKeyLen() int64 {
if x != nil {
return x.KeyLen
}
return 0
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_Key
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetKey() *KeyArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Key); ok {
return x.Key
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_Key struct {
Key *KeyArgs `protobuf:"bytes,1,opt,name=Key,proto3,oneof"`
}
func (*NgoloFuzzOne_Key) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"{\n" +
"\aKeyArgs\x12\x1a\n" +
"\bpassword\x18\x01 \x01(\fR\bpassword\x12\x12\n" +
"\x04salt\x18\x02 \x01(\fR\x04salt\x12\f\n" +
"\x01N\x18\x03 \x01(\x03R\x01N\x12\f\n" +
"\x01r\x18\x04 \x01(\x03R\x01r\x12\f\n" +
"\x01p\x18\x05 \x01(\x03R\x01p\x12\x16\n" +
"\x06keyLen\x18\x06 \x01(\x03R\x06keyLen\">\n" +
"\fNgoloFuzzOne\x12&\n" +
"\x03Key\x18\x01 \x01(\v2\x12.ngolofuzz.KeyArgsH\x00R\x03KeyB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1cZ\x1a./;fuzz_ng_x_crypto_scryptb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_ngolofuzz_proto_goTypes = []any{
(*KeyArgs)(nil), // 0: ngolofuzz.KeyArgs
(*NgoloFuzzOne)(nil), // 1: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 2: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 3: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.Key:type_name -> ngolofuzz.KeyArgs
1, // 1: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[1].OneofWrappers = []any{
(*NgoloFuzzOne_Key)(nil),
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_sha3
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/sha3"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_New224:
sha3.New224()
case *NgoloFuzzOne_New256:
sha3.New256()
case *NgoloFuzzOne_New384:
sha3.New384()
case *NgoloFuzzOne_New512:
sha3.New512()
case *NgoloFuzzOne_Sum224:
sha3.Sum224(a.Sum224.Data)
case *NgoloFuzzOne_Sum256:
sha3.Sum256(a.Sum256.Data)
case *NgoloFuzzOne_Sum384:
sha3.Sum384(a.Sum384.Data)
case *NgoloFuzzOne_Sum512:
sha3.Sum512(a.Sum512.Data)
case *NgoloFuzzOne_NewLegacyKeccak256:
sha3.NewLegacyKeccak256()
case *NgoloFuzzOne_NewLegacyKeccak512:
sha3.NewLegacyKeccak512()
case *NgoloFuzzOne_NewShake128:
sha3.NewShake128()
case *NgoloFuzzOne_NewShake256:
sha3.NewShake256()
case *NgoloFuzzOne_NewCShake128:
sha3.NewCShake128(a.NewCShake128.N, a.NewCShake128.S)
case *NgoloFuzzOne_NewCShake256:
sha3.NewCShake256(a.NewCShake256.N, a.NewCShake256.S)
case *NgoloFuzzOne_ShakeSum128:
sha3.ShakeSum128(a.ShakeSum128.Hash, a.ShakeSum128.Data)
case *NgoloFuzzOne_ShakeSum256:
sha3.ShakeSum256(a.ShakeSum256.Hash, a.ShakeSum256.Data)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_New224:
w.WriteString(fmt.Sprintf("sha3.New224()\n"))
case *NgoloFuzzOne_New256:
w.WriteString(fmt.Sprintf("sha3.New256()\n"))
case *NgoloFuzzOne_New384:
w.WriteString(fmt.Sprintf("sha3.New384()\n"))
case *NgoloFuzzOne_New512:
w.WriteString(fmt.Sprintf("sha3.New512()\n"))
case *NgoloFuzzOne_Sum224:
w.WriteString(fmt.Sprintf("sha3.Sum224(%#+v)\n", a.Sum224.Data))
case *NgoloFuzzOne_Sum256:
w.WriteString(fmt.Sprintf("sha3.Sum256(%#+v)\n", a.Sum256.Data))
case *NgoloFuzzOne_Sum384:
w.WriteString(fmt.Sprintf("sha3.Sum384(%#+v)\n", a.Sum384.Data))
case *NgoloFuzzOne_Sum512:
w.WriteString(fmt.Sprintf("sha3.Sum512(%#+v)\n", a.Sum512.Data))
case *NgoloFuzzOne_NewLegacyKeccak256:
w.WriteString(fmt.Sprintf("sha3.NewLegacyKeccak256()\n"))
case *NgoloFuzzOne_NewLegacyKeccak512:
w.WriteString(fmt.Sprintf("sha3.NewLegacyKeccak512()\n"))
case *NgoloFuzzOne_NewShake128:
w.WriteString(fmt.Sprintf("sha3.NewShake128()\n"))
case *NgoloFuzzOne_NewShake256:
w.WriteString(fmt.Sprintf("sha3.NewShake256()\n"))
case *NgoloFuzzOne_NewCShake128:
w.WriteString(fmt.Sprintf("sha3.NewCShake128(%#+v, %#+v)\n", a.NewCShake128.N, a.NewCShake128.S))
case *NgoloFuzzOne_NewCShake256:
w.WriteString(fmt.Sprintf("sha3.NewCShake256(%#+v, %#+v)\n", a.NewCShake256.N, a.NewCShake256.S))
case *NgoloFuzzOne_ShakeSum128:
w.WriteString(fmt.Sprintf("sha3.ShakeSum128(%#+v, %#+v)\n", a.ShakeSum128.Hash, a.ShakeSum128.Data))
case *NgoloFuzzOne_ShakeSum256:
w.WriteString(fmt.Sprintf("sha3.ShakeSum256(%#+v, %#+v)\n", a.ShakeSum256.Hash, a.ShakeSum256.Data))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_sha3
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type New224Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *New224Args) Reset() {
*x = New224Args{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *New224Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*New224Args) ProtoMessage() {}
func (x *New224Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use New224Args.ProtoReflect.Descriptor instead.
func (*New224Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type New256Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *New256Args) Reset() {
*x = New256Args{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *New256Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*New256Args) ProtoMessage() {}
func (x *New256Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use New256Args.ProtoReflect.Descriptor instead.
func (*New256Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
type New384Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *New384Args) Reset() {
*x = New384Args{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *New384Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*New384Args) ProtoMessage() {}
func (x *New384Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use New384Args.ProtoReflect.Descriptor instead.
func (*New384Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
type New512Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *New512Args) Reset() {
*x = New512Args{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *New512Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*New512Args) ProtoMessage() {}
func (x *New512Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use New512Args.ProtoReflect.Descriptor instead.
func (*New512Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
type Sum224Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Sum224Args) Reset() {
*x = Sum224Args{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Sum224Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Sum224Args) ProtoMessage() {}
func (x *Sum224Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Sum224Args.ProtoReflect.Descriptor instead.
func (*Sum224Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *Sum224Args) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
type Sum256Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Sum256Args) Reset() {
*x = Sum256Args{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Sum256Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Sum256Args) ProtoMessage() {}
func (x *Sum256Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Sum256Args.ProtoReflect.Descriptor instead.
func (*Sum256Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *Sum256Args) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
type Sum384Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Sum384Args) Reset() {
*x = Sum384Args{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Sum384Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Sum384Args) ProtoMessage() {}
func (x *Sum384Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Sum384Args.ProtoReflect.Descriptor instead.
func (*Sum384Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *Sum384Args) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
type Sum512Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Sum512Args) Reset() {
*x = Sum512Args{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Sum512Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Sum512Args) ProtoMessage() {}
func (x *Sum512Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Sum512Args.ProtoReflect.Descriptor instead.
func (*Sum512Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
func (x *Sum512Args) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
type NewLegacyKeccak256Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewLegacyKeccak256Args) Reset() {
*x = NewLegacyKeccak256Args{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewLegacyKeccak256Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewLegacyKeccak256Args) ProtoMessage() {}
func (x *NewLegacyKeccak256Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewLegacyKeccak256Args.ProtoReflect.Descriptor instead.
func (*NewLegacyKeccak256Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
type NewLegacyKeccak512Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewLegacyKeccak512Args) Reset() {
*x = NewLegacyKeccak512Args{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewLegacyKeccak512Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewLegacyKeccak512Args) ProtoMessage() {}
func (x *NewLegacyKeccak512Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewLegacyKeccak512Args.ProtoReflect.Descriptor instead.
func (*NewLegacyKeccak512Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
type NewShake128Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewShake128Args) Reset() {
*x = NewShake128Args{}
mi := &file_ngolofuzz_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewShake128Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewShake128Args) ProtoMessage() {}
func (x *NewShake128Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewShake128Args.ProtoReflect.Descriptor instead.
func (*NewShake128Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{10}
}
type NewShake256Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewShake256Args) Reset() {
*x = NewShake256Args{}
mi := &file_ngolofuzz_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewShake256Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewShake256Args) ProtoMessage() {}
func (x *NewShake256Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[11]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewShake256Args.ProtoReflect.Descriptor instead.
func (*NewShake256Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{11}
}
type NewCShake128Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
N []byte `protobuf:"bytes,1,opt,name=N,proto3" json:"N,omitempty"`
S []byte `protobuf:"bytes,2,opt,name=S,proto3" json:"S,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewCShake128Args) Reset() {
*x = NewCShake128Args{}
mi := &file_ngolofuzz_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewCShake128Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewCShake128Args) ProtoMessage() {}
func (x *NewCShake128Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[12]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewCShake128Args.ProtoReflect.Descriptor instead.
func (*NewCShake128Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{12}
}
func (x *NewCShake128Args) GetN() []byte {
if x != nil {
return x.N
}
return nil
}
func (x *NewCShake128Args) GetS() []byte {
if x != nil {
return x.S
}
return nil
}
type NewCShake256Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
N []byte `protobuf:"bytes,1,opt,name=N,proto3" json:"N,omitempty"`
S []byte `protobuf:"bytes,2,opt,name=S,proto3" json:"S,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewCShake256Args) Reset() {
*x = NewCShake256Args{}
mi := &file_ngolofuzz_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewCShake256Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewCShake256Args) ProtoMessage() {}
func (x *NewCShake256Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[13]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewCShake256Args.ProtoReflect.Descriptor instead.
func (*NewCShake256Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{13}
}
func (x *NewCShake256Args) GetN() []byte {
if x != nil {
return x.N
}
return nil
}
func (x *NewCShake256Args) GetS() []byte {
if x != nil {
return x.S
}
return nil
}
type ShakeSum128Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"`
Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ShakeSum128Args) Reset() {
*x = ShakeSum128Args{}
mi := &file_ngolofuzz_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ShakeSum128Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ShakeSum128Args) ProtoMessage() {}
func (x *ShakeSum128Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[14]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ShakeSum128Args.ProtoReflect.Descriptor instead.
func (*ShakeSum128Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{14}
}
func (x *ShakeSum128Args) GetHash() []byte {
if x != nil {
return x.Hash
}
return nil
}
func (x *ShakeSum128Args) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
type ShakeSum256Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"`
Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ShakeSum256Args) Reset() {
*x = ShakeSum256Args{}
mi := &file_ngolofuzz_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ShakeSum256Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ShakeSum256Args) ProtoMessage() {}
func (x *ShakeSum256Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[15]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ShakeSum256Args.ProtoReflect.Descriptor instead.
func (*ShakeSum256Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{15}
}
func (x *ShakeSum256Args) GetHash() []byte {
if x != nil {
return x.Hash
}
return nil
}
func (x *ShakeSum256Args) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_New224
// *NgoloFuzzOne_New256
// *NgoloFuzzOne_New384
// *NgoloFuzzOne_New512
// *NgoloFuzzOne_Sum224
// *NgoloFuzzOne_Sum256
// *NgoloFuzzOne_Sum384
// *NgoloFuzzOne_Sum512
// *NgoloFuzzOne_NewLegacyKeccak256
// *NgoloFuzzOne_NewLegacyKeccak512
// *NgoloFuzzOne_NewShake128
// *NgoloFuzzOne_NewShake256
// *NgoloFuzzOne_NewCShake128
// *NgoloFuzzOne_NewCShake256
// *NgoloFuzzOne_ShakeSum128
// *NgoloFuzzOne_ShakeSum256
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[16]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{16}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetNew224() *New224Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_New224); ok {
return x.New224
}
}
return nil
}
func (x *NgoloFuzzOne) GetNew256() *New256Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_New256); ok {
return x.New256
}
}
return nil
}
func (x *NgoloFuzzOne) GetNew384() *New384Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_New384); ok {
return x.New384
}
}
return nil
}
func (x *NgoloFuzzOne) GetNew512() *New512Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_New512); ok {
return x.New512
}
}
return nil
}
func (x *NgoloFuzzOne) GetSum224() *Sum224Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Sum224); ok {
return x.Sum224
}
}
return nil
}
func (x *NgoloFuzzOne) GetSum256() *Sum256Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Sum256); ok {
return x.Sum256
}
}
return nil
}
func (x *NgoloFuzzOne) GetSum384() *Sum384Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Sum384); ok {
return x.Sum384
}
}
return nil
}
func (x *NgoloFuzzOne) GetSum512() *Sum512Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Sum512); ok {
return x.Sum512
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewLegacyKeccak256() *NewLegacyKeccak256Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewLegacyKeccak256); ok {
return x.NewLegacyKeccak256
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewLegacyKeccak512() *NewLegacyKeccak512Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewLegacyKeccak512); ok {
return x.NewLegacyKeccak512
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewShake128() *NewShake128Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewShake128); ok {
return x.NewShake128
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewShake256() *NewShake256Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewShake256); ok {
return x.NewShake256
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewCShake128() *NewCShake128Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewCShake128); ok {
return x.NewCShake128
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewCShake256() *NewCShake256Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewCShake256); ok {
return x.NewCShake256
}
}
return nil
}
func (x *NgoloFuzzOne) GetShakeSum128() *ShakeSum128Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ShakeSum128); ok {
return x.ShakeSum128
}
}
return nil
}
func (x *NgoloFuzzOne) GetShakeSum256() *ShakeSum256Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ShakeSum256); ok {
return x.ShakeSum256
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_New224 struct {
New224 *New224Args `protobuf:"bytes,1,opt,name=New224,proto3,oneof"`
}
type NgoloFuzzOne_New256 struct {
New256 *New256Args `protobuf:"bytes,2,opt,name=New256,proto3,oneof"`
}
type NgoloFuzzOne_New384 struct {
New384 *New384Args `protobuf:"bytes,3,opt,name=New384,proto3,oneof"`
}
type NgoloFuzzOne_New512 struct {
New512 *New512Args `protobuf:"bytes,4,opt,name=New512,proto3,oneof"`
}
type NgoloFuzzOne_Sum224 struct {
Sum224 *Sum224Args `protobuf:"bytes,5,opt,name=Sum224,proto3,oneof"`
}
type NgoloFuzzOne_Sum256 struct {
Sum256 *Sum256Args `protobuf:"bytes,6,opt,name=Sum256,proto3,oneof"`
}
type NgoloFuzzOne_Sum384 struct {
Sum384 *Sum384Args `protobuf:"bytes,7,opt,name=Sum384,proto3,oneof"`
}
type NgoloFuzzOne_Sum512 struct {
Sum512 *Sum512Args `protobuf:"bytes,8,opt,name=Sum512,proto3,oneof"`
}
type NgoloFuzzOne_NewLegacyKeccak256 struct {
NewLegacyKeccak256 *NewLegacyKeccak256Args `protobuf:"bytes,9,opt,name=NewLegacyKeccak256,proto3,oneof"`
}
type NgoloFuzzOne_NewLegacyKeccak512 struct {
NewLegacyKeccak512 *NewLegacyKeccak512Args `protobuf:"bytes,10,opt,name=NewLegacyKeccak512,proto3,oneof"`
}
type NgoloFuzzOne_NewShake128 struct {
NewShake128 *NewShake128Args `protobuf:"bytes,11,opt,name=NewShake128,proto3,oneof"`
}
type NgoloFuzzOne_NewShake256 struct {
NewShake256 *NewShake256Args `protobuf:"bytes,12,opt,name=NewShake256,proto3,oneof"`
}
type NgoloFuzzOne_NewCShake128 struct {
NewCShake128 *NewCShake128Args `protobuf:"bytes,13,opt,name=NewCShake128,proto3,oneof"`
}
type NgoloFuzzOne_NewCShake256 struct {
NewCShake256 *NewCShake256Args `protobuf:"bytes,14,opt,name=NewCShake256,proto3,oneof"`
}
type NgoloFuzzOne_ShakeSum128 struct {
ShakeSum128 *ShakeSum128Args `protobuf:"bytes,15,opt,name=ShakeSum128,proto3,oneof"`
}
type NgoloFuzzOne_ShakeSum256 struct {
ShakeSum256 *ShakeSum256Args `protobuf:"bytes,16,opt,name=ShakeSum256,proto3,oneof"`
}
func (*NgoloFuzzOne_New224) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_New256) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_New384) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_New512) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Sum224) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Sum256) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Sum384) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Sum512) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewLegacyKeccak256) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewLegacyKeccak512) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewShake128) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewShake256) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewCShake128) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewCShake256) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ShakeSum128) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ShakeSum256) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[17]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{17}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[18]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{18}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\f\n" +
"\n" +
"New224Args\"\f\n" +
"\n" +
"New256Args\"\f\n" +
"\n" +
"New384Args\"\f\n" +
"\n" +
"New512Args\" \n" +
"\n" +
"Sum224Args\x12\x12\n" +
"\x04data\x18\x01 \x01(\fR\x04data\" \n" +
"\n" +
"Sum256Args\x12\x12\n" +
"\x04data\x18\x01 \x01(\fR\x04data\" \n" +
"\n" +
"Sum384Args\x12\x12\n" +
"\x04data\x18\x01 \x01(\fR\x04data\" \n" +
"\n" +
"Sum512Args\x12\x12\n" +
"\x04data\x18\x01 \x01(\fR\x04data\"\x18\n" +
"\x16NewLegacyKeccak256Args\"\x18\n" +
"\x16NewLegacyKeccak512Args\"\x11\n" +
"\x0fNewShake128Args\"\x11\n" +
"\x0fNewShake256Args\".\n" +
"\x10NewCShake128Args\x12\f\n" +
"\x01N\x18\x01 \x01(\fR\x01N\x12\f\n" +
"\x01S\x18\x02 \x01(\fR\x01S\".\n" +
"\x10NewCShake256Args\x12\f\n" +
"\x01N\x18\x01 \x01(\fR\x01N\x12\f\n" +
"\x01S\x18\x02 \x01(\fR\x01S\"9\n" +
"\x0fShakeSum128Args\x12\x12\n" +
"\x04hash\x18\x01 \x01(\fR\x04hash\x12\x12\n" +
"\x04data\x18\x02 \x01(\fR\x04data\"9\n" +
"\x0fShakeSum256Args\x12\x12\n" +
"\x04hash\x18\x01 \x01(\fR\x04hash\x12\x12\n" +
"\x04data\x18\x02 \x01(\fR\x04data\"\xce\a\n" +
"\fNgoloFuzzOne\x12/\n" +
"\x06New224\x18\x01 \x01(\v2\x15.ngolofuzz.New224ArgsH\x00R\x06New224\x12/\n" +
"\x06New256\x18\x02 \x01(\v2\x15.ngolofuzz.New256ArgsH\x00R\x06New256\x12/\n" +
"\x06New384\x18\x03 \x01(\v2\x15.ngolofuzz.New384ArgsH\x00R\x06New384\x12/\n" +
"\x06New512\x18\x04 \x01(\v2\x15.ngolofuzz.New512ArgsH\x00R\x06New512\x12/\n" +
"\x06Sum224\x18\x05 \x01(\v2\x15.ngolofuzz.Sum224ArgsH\x00R\x06Sum224\x12/\n" +
"\x06Sum256\x18\x06 \x01(\v2\x15.ngolofuzz.Sum256ArgsH\x00R\x06Sum256\x12/\n" +
"\x06Sum384\x18\a \x01(\v2\x15.ngolofuzz.Sum384ArgsH\x00R\x06Sum384\x12/\n" +
"\x06Sum512\x18\b \x01(\v2\x15.ngolofuzz.Sum512ArgsH\x00R\x06Sum512\x12S\n" +
"\x12NewLegacyKeccak256\x18\t \x01(\v2!.ngolofuzz.NewLegacyKeccak256ArgsH\x00R\x12NewLegacyKeccak256\x12S\n" +
"\x12NewLegacyKeccak512\x18\n" +
" \x01(\v2!.ngolofuzz.NewLegacyKeccak512ArgsH\x00R\x12NewLegacyKeccak512\x12>\n" +
"\vNewShake128\x18\v \x01(\v2\x1a.ngolofuzz.NewShake128ArgsH\x00R\vNewShake128\x12>\n" +
"\vNewShake256\x18\f \x01(\v2\x1a.ngolofuzz.NewShake256ArgsH\x00R\vNewShake256\x12A\n" +
"\fNewCShake128\x18\r \x01(\v2\x1b.ngolofuzz.NewCShake128ArgsH\x00R\fNewCShake128\x12A\n" +
"\fNewCShake256\x18\x0e \x01(\v2\x1b.ngolofuzz.NewCShake256ArgsH\x00R\fNewCShake256\x12>\n" +
"\vShakeSum128\x18\x0f \x01(\v2\x1a.ngolofuzz.ShakeSum128ArgsH\x00R\vShakeSum128\x12>\n" +
"\vShakeSum256\x18\x10 \x01(\v2\x1a.ngolofuzz.ShakeSum256ArgsH\x00R\vShakeSum256B\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1aZ\x18./;fuzz_ng_x_crypto_sha3b\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 19)
var file_ngolofuzz_proto_goTypes = []any{
(*New224Args)(nil), // 0: ngolofuzz.New224Args
(*New256Args)(nil), // 1: ngolofuzz.New256Args
(*New384Args)(nil), // 2: ngolofuzz.New384Args
(*New512Args)(nil), // 3: ngolofuzz.New512Args
(*Sum224Args)(nil), // 4: ngolofuzz.Sum224Args
(*Sum256Args)(nil), // 5: ngolofuzz.Sum256Args
(*Sum384Args)(nil), // 6: ngolofuzz.Sum384Args
(*Sum512Args)(nil), // 7: ngolofuzz.Sum512Args
(*NewLegacyKeccak256Args)(nil), // 8: ngolofuzz.NewLegacyKeccak256Args
(*NewLegacyKeccak512Args)(nil), // 9: ngolofuzz.NewLegacyKeccak512Args
(*NewShake128Args)(nil), // 10: ngolofuzz.NewShake128Args
(*NewShake256Args)(nil), // 11: ngolofuzz.NewShake256Args
(*NewCShake128Args)(nil), // 12: ngolofuzz.NewCShake128Args
(*NewCShake256Args)(nil), // 13: ngolofuzz.NewCShake256Args
(*ShakeSum128Args)(nil), // 14: ngolofuzz.ShakeSum128Args
(*ShakeSum256Args)(nil), // 15: ngolofuzz.ShakeSum256Args
(*NgoloFuzzOne)(nil), // 16: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 17: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 18: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.New224:type_name -> ngolofuzz.New224Args
1, // 1: ngolofuzz.NgoloFuzzOne.New256:type_name -> ngolofuzz.New256Args
2, // 2: ngolofuzz.NgoloFuzzOne.New384:type_name -> ngolofuzz.New384Args
3, // 3: ngolofuzz.NgoloFuzzOne.New512:type_name -> ngolofuzz.New512Args
4, // 4: ngolofuzz.NgoloFuzzOne.Sum224:type_name -> ngolofuzz.Sum224Args
5, // 5: ngolofuzz.NgoloFuzzOne.Sum256:type_name -> ngolofuzz.Sum256Args
6, // 6: ngolofuzz.NgoloFuzzOne.Sum384:type_name -> ngolofuzz.Sum384Args
7, // 7: ngolofuzz.NgoloFuzzOne.Sum512:type_name -> ngolofuzz.Sum512Args
8, // 8: ngolofuzz.NgoloFuzzOne.NewLegacyKeccak256:type_name -> ngolofuzz.NewLegacyKeccak256Args
9, // 9: ngolofuzz.NgoloFuzzOne.NewLegacyKeccak512:type_name -> ngolofuzz.NewLegacyKeccak512Args
10, // 10: ngolofuzz.NgoloFuzzOne.NewShake128:type_name -> ngolofuzz.NewShake128Args
11, // 11: ngolofuzz.NgoloFuzzOne.NewShake256:type_name -> ngolofuzz.NewShake256Args
12, // 12: ngolofuzz.NgoloFuzzOne.NewCShake128:type_name -> ngolofuzz.NewCShake128Args
13, // 13: ngolofuzz.NgoloFuzzOne.NewCShake256:type_name -> ngolofuzz.NewCShake256Args
14, // 14: ngolofuzz.NgoloFuzzOne.ShakeSum128:type_name -> ngolofuzz.ShakeSum128Args
15, // 15: ngolofuzz.NgoloFuzzOne.ShakeSum256:type_name -> ngolofuzz.ShakeSum256Args
16, // 16: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
17, // [17:17] is the sub-list for method output_type
17, // [17:17] is the sub-list for method input_type
17, // [17:17] is the sub-list for extension type_name
17, // [17:17] is the sub-list for extension extendee
0, // [0:17] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[16].OneofWrappers = []any{
(*NgoloFuzzOne_New224)(nil),
(*NgoloFuzzOne_New256)(nil),
(*NgoloFuzzOne_New384)(nil),
(*NgoloFuzzOne_New512)(nil),
(*NgoloFuzzOne_Sum224)(nil),
(*NgoloFuzzOne_Sum256)(nil),
(*NgoloFuzzOne_Sum384)(nil),
(*NgoloFuzzOne_Sum512)(nil),
(*NgoloFuzzOne_NewLegacyKeccak256)(nil),
(*NgoloFuzzOne_NewLegacyKeccak512)(nil),
(*NgoloFuzzOne_NewShake128)(nil),
(*NgoloFuzzOne_NewShake256)(nil),
(*NgoloFuzzOne_NewCShake128)(nil),
(*NgoloFuzzOne_NewCShake256)(nil),
(*NgoloFuzzOne_ShakeSum128)(nil),
(*NgoloFuzzOne_ShakeSum256)(nil),
}
file_ngolofuzz_proto_msgTypes[17].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 19,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_ssh_knownhosts
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/ssh/knownhosts"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Normalize:
knownhosts.Normalize(a.Normalize.Address)
case *NgoloFuzzOne_HashHostname:
knownhosts.HashHostname(a.HashHostname.Hostname)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Normalize:
w.WriteString(fmt.Sprintf("knownhosts.Normalize(%#+v)\n", a.Normalize.Address))
case *NgoloFuzzOne_HashHostname:
w.WriteString(fmt.Sprintf("knownhosts.HashHostname(%#+v)\n", a.HashHostname.Hostname))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_ssh_knownhosts
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type NormalizeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NormalizeArgs) Reset() {
*x = NormalizeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NormalizeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NormalizeArgs) ProtoMessage() {}
func (x *NormalizeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NormalizeArgs.ProtoReflect.Descriptor instead.
func (*NormalizeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *NormalizeArgs) GetAddress() string {
if x != nil {
return x.Address
}
return ""
}
type HashHostnameArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Hostname string `protobuf:"bytes,1,opt,name=hostname,proto3" json:"hostname,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HashHostnameArgs) Reset() {
*x = HashHostnameArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HashHostnameArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HashHostnameArgs) ProtoMessage() {}
func (x *HashHostnameArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HashHostnameArgs.ProtoReflect.Descriptor instead.
func (*HashHostnameArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *HashHostnameArgs) GetHostname() string {
if x != nil {
return x.Hostname
}
return ""
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_Normalize
// *NgoloFuzzOne_HashHostname
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetNormalize() *NormalizeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Normalize); ok {
return x.Normalize
}
}
return nil
}
func (x *NgoloFuzzOne) GetHashHostname() *HashHostnameArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_HashHostname); ok {
return x.HashHostname
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_Normalize struct {
Normalize *NormalizeArgs `protobuf:"bytes,1,opt,name=Normalize,proto3,oneof"`
}
type NgoloFuzzOne_HashHostname struct {
HashHostname *HashHostnameArgs `protobuf:"bytes,2,opt,name=HashHostname,proto3,oneof"`
}
func (*NgoloFuzzOne_Normalize) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_HashHostname) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\")\n" +
"\rNormalizeArgs\x12\x18\n" +
"\aaddress\x18\x01 \x01(\tR\aaddress\".\n" +
"\x10HashHostnameArgs\x12\x1a\n" +
"\bhostname\x18\x01 \x01(\tR\bhostname\"\x93\x01\n" +
"\fNgoloFuzzOne\x128\n" +
"\tNormalize\x18\x01 \x01(\v2\x18.ngolofuzz.NormalizeArgsH\x00R\tNormalize\x12A\n" +
"\fHashHostname\x18\x02 \x01(\v2\x1b.ngolofuzz.HashHostnameArgsH\x00R\fHashHostnameB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB$Z\"./;fuzz_ng_x_crypto_ssh_knownhostsb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_ngolofuzz_proto_goTypes = []any{
(*NormalizeArgs)(nil), // 0: ngolofuzz.NormalizeArgs
(*HashHostnameArgs)(nil), // 1: ngolofuzz.HashHostnameArgs
(*NgoloFuzzOne)(nil), // 2: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 3: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 4: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.Normalize:type_name -> ngolofuzz.NormalizeArgs
1, // 1: ngolofuzz.NgoloFuzzOne.HashHostname:type_name -> ngolofuzz.HashHostnameArgs
2, // 2: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzOne_Normalize)(nil),
(*NgoloFuzzOne_HashHostname)(nil),
}
file_ngolofuzz_proto_msgTypes[3].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_ssh_terminal
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/ssh/terminal"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var StateResults []*terminal.State
StateResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_IsTerminal:
arg0 := int(a.IsTerminal.Fd)
terminal.IsTerminal(arg0)
case *NgoloFuzzOne_ReadPassword:
arg0 := int(a.ReadPassword.Fd)
_, r1 := terminal.ReadPassword(arg0)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_MakeRaw:
arg0 := int(a.MakeRaw.Fd)
r0, r1 := terminal.MakeRaw(arg0)
if r0 != nil{
StateResults = append(StateResults, r0)
}
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_Restore:
arg0 := int(a.Restore.Fd)
if len(StateResults) == 0 {
continue
}
arg1 := StateResults[StateResultsIndex]
StateResultsIndex = (StateResultsIndex + 1) % len(StateResults)
r0 := terminal.Restore(arg0, arg1)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_GetState:
arg0 := int(a.GetState.Fd)
r0, r1 := terminal.GetState(arg0)
if r0 != nil{
StateResults = append(StateResults, r0)
}
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_GetSize:
arg0 := int(a.GetSize.Fd)
_, _, r2 := terminal.GetSize(arg0)
if r2 != nil{
r2.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
StateNb := 0
StateResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_IsTerminal:
w.WriteString(fmt.Sprintf("terminal.IsTerminal(int(%#+v))\n", a.IsTerminal.Fd))
case *NgoloFuzzOne_ReadPassword:
w.WriteString(fmt.Sprintf("terminal.ReadPassword(int(%#+v))\n", a.ReadPassword.Fd))
case *NgoloFuzzOne_MakeRaw:
w.WriteString(fmt.Sprintf("State%d, _ := terminal.MakeRaw(int(%#+v))\n", StateNb, a.MakeRaw.Fd))
StateNb = StateNb + 1
case *NgoloFuzzOne_Restore:
if StateNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("terminal.Restore(int(%#+v), State%d)\n", a.Restore.Fd, (StateResultsIndex + 0) % StateNb))
StateResultsIndex = (StateResultsIndex + 1) % StateNb
case *NgoloFuzzOne_GetState:
w.WriteString(fmt.Sprintf("State%d, _ := terminal.GetState(int(%#+v))\n", StateNb, a.GetState.Fd))
StateNb = StateNb + 1
case *NgoloFuzzOne_GetSize:
w.WriteString(fmt.Sprintf("terminal.GetSize(int(%#+v))\n", a.GetSize.Fd))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_ssh_terminal
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type IsTerminalArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Fd int64 `protobuf:"varint,1,opt,name=fd,proto3" json:"fd,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *IsTerminalArgs) Reset() {
*x = IsTerminalArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *IsTerminalArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*IsTerminalArgs) ProtoMessage() {}
func (x *IsTerminalArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use IsTerminalArgs.ProtoReflect.Descriptor instead.
func (*IsTerminalArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *IsTerminalArgs) GetFd() int64 {
if x != nil {
return x.Fd
}
return 0
}
type ReadPasswordArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Fd int64 `protobuf:"varint,1,opt,name=fd,proto3" json:"fd,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ReadPasswordArgs) Reset() {
*x = ReadPasswordArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ReadPasswordArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReadPasswordArgs) ProtoMessage() {}
func (x *ReadPasswordArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReadPasswordArgs.ProtoReflect.Descriptor instead.
func (*ReadPasswordArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *ReadPasswordArgs) GetFd() int64 {
if x != nil {
return x.Fd
}
return 0
}
type MakeRawArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Fd int64 `protobuf:"varint,1,opt,name=fd,proto3" json:"fd,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *MakeRawArgs) Reset() {
*x = MakeRawArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *MakeRawArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MakeRawArgs) ProtoMessage() {}
func (x *MakeRawArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MakeRawArgs.ProtoReflect.Descriptor instead.
func (*MakeRawArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *MakeRawArgs) GetFd() int64 {
if x != nil {
return x.Fd
}
return 0
}
type RestoreArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Fd int64 `protobuf:"varint,1,opt,name=fd,proto3" json:"fd,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RestoreArgs) Reset() {
*x = RestoreArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RestoreArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RestoreArgs) ProtoMessage() {}
func (x *RestoreArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RestoreArgs.ProtoReflect.Descriptor instead.
func (*RestoreArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *RestoreArgs) GetFd() int64 {
if x != nil {
return x.Fd
}
return 0
}
type GetStateArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Fd int64 `protobuf:"varint,1,opt,name=fd,proto3" json:"fd,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetStateArgs) Reset() {
*x = GetStateArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetStateArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetStateArgs) ProtoMessage() {}
func (x *GetStateArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetStateArgs.ProtoReflect.Descriptor instead.
func (*GetStateArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *GetStateArgs) GetFd() int64 {
if x != nil {
return x.Fd
}
return 0
}
type GetSizeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Fd int64 `protobuf:"varint,1,opt,name=fd,proto3" json:"fd,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetSizeArgs) Reset() {
*x = GetSizeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetSizeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetSizeArgs) ProtoMessage() {}
func (x *GetSizeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetSizeArgs.ProtoReflect.Descriptor instead.
func (*GetSizeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *GetSizeArgs) GetFd() int64 {
if x != nil {
return x.Fd
}
return 0
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_IsTerminal
// *NgoloFuzzOne_ReadPassword
// *NgoloFuzzOne_MakeRaw
// *NgoloFuzzOne_Restore
// *NgoloFuzzOne_GetState
// *NgoloFuzzOne_GetSize
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetIsTerminal() *IsTerminalArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_IsTerminal); ok {
return x.IsTerminal
}
}
return nil
}
func (x *NgoloFuzzOne) GetReadPassword() *ReadPasswordArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ReadPassword); ok {
return x.ReadPassword
}
}
return nil
}
func (x *NgoloFuzzOne) GetMakeRaw() *MakeRawArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_MakeRaw); ok {
return x.MakeRaw
}
}
return nil
}
func (x *NgoloFuzzOne) GetRestore() *RestoreArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Restore); ok {
return x.Restore
}
}
return nil
}
func (x *NgoloFuzzOne) GetGetState() *GetStateArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_GetState); ok {
return x.GetState
}
}
return nil
}
func (x *NgoloFuzzOne) GetGetSize() *GetSizeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_GetSize); ok {
return x.GetSize
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_IsTerminal struct {
IsTerminal *IsTerminalArgs `protobuf:"bytes,1,opt,name=IsTerminal,proto3,oneof"`
}
type NgoloFuzzOne_ReadPassword struct {
ReadPassword *ReadPasswordArgs `protobuf:"bytes,2,opt,name=ReadPassword,proto3,oneof"`
}
type NgoloFuzzOne_MakeRaw struct {
MakeRaw *MakeRawArgs `protobuf:"bytes,3,opt,name=MakeRaw,proto3,oneof"`
}
type NgoloFuzzOne_Restore struct {
Restore *RestoreArgs `protobuf:"bytes,4,opt,name=Restore,proto3,oneof"`
}
type NgoloFuzzOne_GetState struct {
GetState *GetStateArgs `protobuf:"bytes,5,opt,name=GetState,proto3,oneof"`
}
type NgoloFuzzOne_GetSize struct {
GetSize *GetSizeArgs `protobuf:"bytes,6,opt,name=GetSize,proto3,oneof"`
}
func (*NgoloFuzzOne_IsTerminal) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ReadPassword) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_MakeRaw) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Restore) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_GetState) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_GetSize) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\" \n" +
"\x0eIsTerminalArgs\x12\x0e\n" +
"\x02fd\x18\x01 \x01(\x03R\x02fd\"\"\n" +
"\x10ReadPasswordArgs\x12\x0e\n" +
"\x02fd\x18\x01 \x01(\x03R\x02fd\"\x1d\n" +
"\vMakeRawArgs\x12\x0e\n" +
"\x02fd\x18\x01 \x01(\x03R\x02fd\"\x1d\n" +
"\vRestoreArgs\x12\x0e\n" +
"\x02fd\x18\x01 \x01(\x03R\x02fd\"\x1e\n" +
"\fGetStateArgs\x12\x0e\n" +
"\x02fd\x18\x01 \x01(\x03R\x02fd\"\x1d\n" +
"\vGetSizeArgs\x12\x0e\n" +
"\x02fd\x18\x01 \x01(\x03R\x02fd\"\xe9\x02\n" +
"\fNgoloFuzzOne\x12;\n" +
"\n" +
"IsTerminal\x18\x01 \x01(\v2\x19.ngolofuzz.IsTerminalArgsH\x00R\n" +
"IsTerminal\x12A\n" +
"\fReadPassword\x18\x02 \x01(\v2\x1b.ngolofuzz.ReadPasswordArgsH\x00R\fReadPassword\x122\n" +
"\aMakeRaw\x18\x03 \x01(\v2\x16.ngolofuzz.MakeRawArgsH\x00R\aMakeRaw\x122\n" +
"\aRestore\x18\x04 \x01(\v2\x16.ngolofuzz.RestoreArgsH\x00R\aRestore\x125\n" +
"\bGetState\x18\x05 \x01(\v2\x17.ngolofuzz.GetStateArgsH\x00R\bGetState\x122\n" +
"\aGetSize\x18\x06 \x01(\v2\x16.ngolofuzz.GetSizeArgsH\x00R\aGetSizeB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\"Z ./;fuzz_ng_x_crypto_ssh_terminalb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
var file_ngolofuzz_proto_goTypes = []any{
(*IsTerminalArgs)(nil), // 0: ngolofuzz.IsTerminalArgs
(*ReadPasswordArgs)(nil), // 1: ngolofuzz.ReadPasswordArgs
(*MakeRawArgs)(nil), // 2: ngolofuzz.MakeRawArgs
(*RestoreArgs)(nil), // 3: ngolofuzz.RestoreArgs
(*GetStateArgs)(nil), // 4: ngolofuzz.GetStateArgs
(*GetSizeArgs)(nil), // 5: ngolofuzz.GetSizeArgs
(*NgoloFuzzOne)(nil), // 6: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 7: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 8: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.IsTerminal:type_name -> ngolofuzz.IsTerminalArgs
1, // 1: ngolofuzz.NgoloFuzzOne.ReadPassword:type_name -> ngolofuzz.ReadPasswordArgs
2, // 2: ngolofuzz.NgoloFuzzOne.MakeRaw:type_name -> ngolofuzz.MakeRawArgs
3, // 3: ngolofuzz.NgoloFuzzOne.Restore:type_name -> ngolofuzz.RestoreArgs
4, // 4: ngolofuzz.NgoloFuzzOne.GetState:type_name -> ngolofuzz.GetStateArgs
5, // 5: ngolofuzz.NgoloFuzzOne.GetSize:type_name -> ngolofuzz.GetSizeArgs
6, // 6: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
7, // [7:7] is the sub-list for method output_type
7, // [7:7] is the sub-list for method input_type
7, // [7:7] is the sub-list for extension type_name
7, // [7:7] is the sub-list for extension extendee
0, // [0:7] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[6].OneofWrappers = []any{
(*NgoloFuzzOne_IsTerminal)(nil),
(*NgoloFuzzOne_ReadPassword)(nil),
(*NgoloFuzzOne_MakeRaw)(nil),
(*NgoloFuzzOne_Restore)(nil),
(*NgoloFuzzOne_GetState)(nil),
(*NgoloFuzzOne_GetSize)(nil),
}
file_ngolofuzz_proto_msgTypes[7].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 9,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_tea
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/tea"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewCipher:
_, r1 := tea.NewCipher(a.NewCipher.Key)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_NewCipherWithRounds:
arg1 := int(a.NewCipherWithRounds.Rounds)
_, r1 := tea.NewCipherWithRounds(a.NewCipherWithRounds.Key, arg1)
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewCipher:
w.WriteString(fmt.Sprintf("tea.NewCipher(%#+v)\n", a.NewCipher.Key))
case *NgoloFuzzOne_NewCipherWithRounds:
w.WriteString(fmt.Sprintf("tea.NewCipherWithRounds(%#+v, int(%#+v))\n", a.NewCipherWithRounds.Key, a.NewCipherWithRounds.Rounds))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_tea
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type NewCipherArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewCipherArgs) Reset() {
*x = NewCipherArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewCipherArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewCipherArgs) ProtoMessage() {}
func (x *NewCipherArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewCipherArgs.ProtoReflect.Descriptor instead.
func (*NewCipherArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *NewCipherArgs) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
type NewCipherWithRoundsArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Rounds int64 `protobuf:"varint,2,opt,name=rounds,proto3" json:"rounds,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewCipherWithRoundsArgs) Reset() {
*x = NewCipherWithRoundsArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewCipherWithRoundsArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewCipherWithRoundsArgs) ProtoMessage() {}
func (x *NewCipherWithRoundsArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewCipherWithRoundsArgs.ProtoReflect.Descriptor instead.
func (*NewCipherWithRoundsArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *NewCipherWithRoundsArgs) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
func (x *NewCipherWithRoundsArgs) GetRounds() int64 {
if x != nil {
return x.Rounds
}
return 0
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_NewCipher
// *NgoloFuzzOne_NewCipherWithRounds
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetNewCipher() *NewCipherArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewCipher); ok {
return x.NewCipher
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewCipherWithRounds() *NewCipherWithRoundsArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewCipherWithRounds); ok {
return x.NewCipherWithRounds
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_NewCipher struct {
NewCipher *NewCipherArgs `protobuf:"bytes,1,opt,name=NewCipher,proto3,oneof"`
}
type NgoloFuzzOne_NewCipherWithRounds struct {
NewCipherWithRounds *NewCipherWithRoundsArgs `protobuf:"bytes,2,opt,name=NewCipherWithRounds,proto3,oneof"`
}
func (*NgoloFuzzOne_NewCipher) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewCipherWithRounds) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"!\n" +
"\rNewCipherArgs\x12\x10\n" +
"\x03key\x18\x01 \x01(\fR\x03key\"C\n" +
"\x17NewCipherWithRoundsArgs\x12\x10\n" +
"\x03key\x18\x01 \x01(\fR\x03key\x12\x16\n" +
"\x06rounds\x18\x02 \x01(\x03R\x06rounds\"\xa8\x01\n" +
"\fNgoloFuzzOne\x128\n" +
"\tNewCipher\x18\x01 \x01(\v2\x18.ngolofuzz.NewCipherArgsH\x00R\tNewCipher\x12V\n" +
"\x13NewCipherWithRounds\x18\x02 \x01(\v2\".ngolofuzz.NewCipherWithRoundsArgsH\x00R\x13NewCipherWithRoundsB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x19Z\x17./;fuzz_ng_x_crypto_teab\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_ngolofuzz_proto_goTypes = []any{
(*NewCipherArgs)(nil), // 0: ngolofuzz.NewCipherArgs
(*NewCipherWithRoundsArgs)(nil), // 1: ngolofuzz.NewCipherWithRoundsArgs
(*NgoloFuzzOne)(nil), // 2: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 3: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 4: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.NewCipher:type_name -> ngolofuzz.NewCipherArgs
1, // 1: ngolofuzz.NgoloFuzzOne.NewCipherWithRounds:type_name -> ngolofuzz.NewCipherWithRoundsArgs
2, // 2: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzOne_NewCipher)(nil),
(*NgoloFuzzOne_NewCipherWithRounds)(nil),
}
file_ngolofuzz_proto_msgTypes[3].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_twofish
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/twofish"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var CipherResults []*twofish.Cipher
CipherResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewCipher:
r0, r1 := twofish.NewCipher(a.NewCipher.Key)
if r0 != nil{
CipherResults = append(CipherResults, r0)
}
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_CipherNgdotBlockSize:
if len(CipherResults) == 0 {
continue
}
arg0 := CipherResults[CipherResultsIndex]
CipherResultsIndex = (CipherResultsIndex + 1) % len(CipherResults)
arg0.BlockSize()
case *NgoloFuzzOne_CipherNgdotEncrypt:
if len(CipherResults) == 0 {
continue
}
arg0 := CipherResults[CipherResultsIndex]
CipherResultsIndex = (CipherResultsIndex + 1) % len(CipherResults)
a.CipherNgdotEncrypt.Dst = make([]byte, 2*len(a.CipherNgdotEncrypt.Src))
arg0.Encrypt(a.CipherNgdotEncrypt.Dst, a.CipherNgdotEncrypt.Src)
case *NgoloFuzzOne_CipherNgdotDecrypt:
if len(CipherResults) == 0 {
continue
}
arg0 := CipherResults[CipherResultsIndex]
CipherResultsIndex = (CipherResultsIndex + 1) % len(CipherResults)
a.CipherNgdotDecrypt.Dst = make([]byte, 2*len(a.CipherNgdotDecrypt.Src))
arg0.Decrypt(a.CipherNgdotDecrypt.Dst, a.CipherNgdotDecrypt.Src)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
CipherNb := 0
CipherResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewCipher:
w.WriteString(fmt.Sprintf("Cipher%d, _ := twofish.NewCipher(%#+v)\n", CipherNb, a.NewCipher.Key))
CipherNb = CipherNb + 1
case *NgoloFuzzOne_CipherNgdotBlockSize:
if CipherNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Cipher%d.BlockSize()\n", CipherResultsIndex))
CipherResultsIndex = (CipherResultsIndex + 1) % CipherNb
case *NgoloFuzzOne_CipherNgdotEncrypt:
if CipherNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Cipher%d.Encrypt(%#+v, %#+v)\n", CipherResultsIndex, a.CipherNgdotEncrypt.Dst, a.CipherNgdotEncrypt.Src))
CipherResultsIndex = (CipherResultsIndex + 1) % CipherNb
case *NgoloFuzzOne_CipherNgdotDecrypt:
if CipherNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Cipher%d.Decrypt(%#+v, %#+v)\n", CipherResultsIndex, a.CipherNgdotDecrypt.Dst, a.CipherNgdotDecrypt.Src))
CipherResultsIndex = (CipherResultsIndex + 1) % CipherNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_twofish
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type NewCipherArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewCipherArgs) Reset() {
*x = NewCipherArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewCipherArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewCipherArgs) ProtoMessage() {}
func (x *NewCipherArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewCipherArgs.ProtoReflect.Descriptor instead.
func (*NewCipherArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *NewCipherArgs) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
type CipherNgdotBlockSizeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CipherNgdotBlockSizeArgs) Reset() {
*x = CipherNgdotBlockSizeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CipherNgdotBlockSizeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CipherNgdotBlockSizeArgs) ProtoMessage() {}
func (x *CipherNgdotBlockSizeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CipherNgdotBlockSizeArgs.ProtoReflect.Descriptor instead.
func (*CipherNgdotBlockSizeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
type CipherNgdotEncryptArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Dst []byte `protobuf:"bytes,1,opt,name=dst,proto3" json:"dst,omitempty"`
Src []byte `protobuf:"bytes,2,opt,name=src,proto3" json:"src,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CipherNgdotEncryptArgs) Reset() {
*x = CipherNgdotEncryptArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CipherNgdotEncryptArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CipherNgdotEncryptArgs) ProtoMessage() {}
func (x *CipherNgdotEncryptArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CipherNgdotEncryptArgs.ProtoReflect.Descriptor instead.
func (*CipherNgdotEncryptArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *CipherNgdotEncryptArgs) GetDst() []byte {
if x != nil {
return x.Dst
}
return nil
}
func (x *CipherNgdotEncryptArgs) GetSrc() []byte {
if x != nil {
return x.Src
}
return nil
}
type CipherNgdotDecryptArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Dst []byte `protobuf:"bytes,1,opt,name=dst,proto3" json:"dst,omitempty"`
Src []byte `protobuf:"bytes,2,opt,name=src,proto3" json:"src,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CipherNgdotDecryptArgs) Reset() {
*x = CipherNgdotDecryptArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CipherNgdotDecryptArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CipherNgdotDecryptArgs) ProtoMessage() {}
func (x *CipherNgdotDecryptArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CipherNgdotDecryptArgs.ProtoReflect.Descriptor instead.
func (*CipherNgdotDecryptArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *CipherNgdotDecryptArgs) GetDst() []byte {
if x != nil {
return x.Dst
}
return nil
}
func (x *CipherNgdotDecryptArgs) GetSrc() []byte {
if x != nil {
return x.Src
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_NewCipher
// *NgoloFuzzOne_CipherNgdotBlockSize
// *NgoloFuzzOne_CipherNgdotEncrypt
// *NgoloFuzzOne_CipherNgdotDecrypt
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetNewCipher() *NewCipherArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewCipher); ok {
return x.NewCipher
}
}
return nil
}
func (x *NgoloFuzzOne) GetCipherNgdotBlockSize() *CipherNgdotBlockSizeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CipherNgdotBlockSize); ok {
return x.CipherNgdotBlockSize
}
}
return nil
}
func (x *NgoloFuzzOne) GetCipherNgdotEncrypt() *CipherNgdotEncryptArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CipherNgdotEncrypt); ok {
return x.CipherNgdotEncrypt
}
}
return nil
}
func (x *NgoloFuzzOne) GetCipherNgdotDecrypt() *CipherNgdotDecryptArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CipherNgdotDecrypt); ok {
return x.CipherNgdotDecrypt
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_NewCipher struct {
NewCipher *NewCipherArgs `protobuf:"bytes,1,opt,name=NewCipher,proto3,oneof"`
}
type NgoloFuzzOne_CipherNgdotBlockSize struct {
CipherNgdotBlockSize *CipherNgdotBlockSizeArgs `protobuf:"bytes,2,opt,name=CipherNgdotBlockSize,proto3,oneof"`
}
type NgoloFuzzOne_CipherNgdotEncrypt struct {
CipherNgdotEncrypt *CipherNgdotEncryptArgs `protobuf:"bytes,3,opt,name=CipherNgdotEncrypt,proto3,oneof"`
}
type NgoloFuzzOne_CipherNgdotDecrypt struct {
CipherNgdotDecrypt *CipherNgdotDecryptArgs `protobuf:"bytes,4,opt,name=CipherNgdotDecrypt,proto3,oneof"`
}
func (*NgoloFuzzOne_NewCipher) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CipherNgdotBlockSize) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CipherNgdotEncrypt) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CipherNgdotDecrypt) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"!\n" +
"\rNewCipherArgs\x12\x10\n" +
"\x03key\x18\x01 \x01(\fR\x03key\"\x1a\n" +
"\x18CipherNgdotBlockSizeArgs\"<\n" +
"\x16CipherNgdotEncryptArgs\x12\x10\n" +
"\x03dst\x18\x01 \x01(\fR\x03dst\x12\x10\n" +
"\x03src\x18\x02 \x01(\fR\x03src\"<\n" +
"\x16CipherNgdotDecryptArgs\x12\x10\n" +
"\x03dst\x18\x01 \x01(\fR\x03dst\x12\x10\n" +
"\x03src\x18\x02 \x01(\fR\x03src\"\xd5\x02\n" +
"\fNgoloFuzzOne\x128\n" +
"\tNewCipher\x18\x01 \x01(\v2\x18.ngolofuzz.NewCipherArgsH\x00R\tNewCipher\x12Y\n" +
"\x14CipherNgdotBlockSize\x18\x02 \x01(\v2#.ngolofuzz.CipherNgdotBlockSizeArgsH\x00R\x14CipherNgdotBlockSize\x12S\n" +
"\x12CipherNgdotEncrypt\x18\x03 \x01(\v2!.ngolofuzz.CipherNgdotEncryptArgsH\x00R\x12CipherNgdotEncrypt\x12S\n" +
"\x12CipherNgdotDecrypt\x18\x04 \x01(\v2!.ngolofuzz.CipherNgdotDecryptArgsH\x00R\x12CipherNgdotDecryptB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1dZ\x1b./;fuzz_ng_x_crypto_twofishb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_ngolofuzz_proto_goTypes = []any{
(*NewCipherArgs)(nil), // 0: ngolofuzz.NewCipherArgs
(*CipherNgdotBlockSizeArgs)(nil), // 1: ngolofuzz.CipherNgdotBlockSizeArgs
(*CipherNgdotEncryptArgs)(nil), // 2: ngolofuzz.CipherNgdotEncryptArgs
(*CipherNgdotDecryptArgs)(nil), // 3: ngolofuzz.CipherNgdotDecryptArgs
(*NgoloFuzzOne)(nil), // 4: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 5: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 6: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.NewCipher:type_name -> ngolofuzz.NewCipherArgs
1, // 1: ngolofuzz.NgoloFuzzOne.CipherNgdotBlockSize:type_name -> ngolofuzz.CipherNgdotBlockSizeArgs
2, // 2: ngolofuzz.NgoloFuzzOne.CipherNgdotEncrypt:type_name -> ngolofuzz.CipherNgdotEncryptArgs
3, // 3: ngolofuzz.NgoloFuzzOne.CipherNgdotDecrypt:type_name -> ngolofuzz.CipherNgdotDecryptArgs
4, // 4: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[4].OneofWrappers = []any{
(*NgoloFuzzOne_NewCipher)(nil),
(*NgoloFuzzOne_CipherNgdotBlockSize)(nil),
(*NgoloFuzzOne_CipherNgdotEncrypt)(nil),
(*NgoloFuzzOne_CipherNgdotDecrypt)(nil),
}
file_ngolofuzz_proto_msgTypes[5].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 7,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_x509roots_nss
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/x509roots/nss"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Parse:
arg0 := bytes.NewReader(a.Parse.R)
_, r1 := nss.Parse(arg0)
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Parse:
w.WriteString(fmt.Sprintf("nss.Parse(bytes.NewReader(%#+v))\n", a.Parse.R))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_x509roots_nss
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ParseArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R []byte `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ParseArgs) Reset() {
*x = ParseArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ParseArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ParseArgs) ProtoMessage() {}
func (x *ParseArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ParseArgs.ProtoReflect.Descriptor instead.
func (*ParseArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *ParseArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_Parse
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetParse() *ParseArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Parse); ok {
return x.Parse
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_Parse struct {
Parse *ParseArgs `protobuf:"bytes,1,opt,name=Parse,proto3,oneof"`
}
func (*NgoloFuzzOne_Parse) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x19\n" +
"\tParseArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\fR\x01r\"D\n" +
"\fNgoloFuzzOne\x12,\n" +
"\x05Parse\x18\x01 \x01(\v2\x14.ngolofuzz.ParseArgsH\x00R\x05ParseB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB#Z!./;fuzz_ng_x_crypto_x509roots_nssb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_ngolofuzz_proto_goTypes = []any{
(*ParseArgs)(nil), // 0: ngolofuzz.ParseArgs
(*NgoloFuzzOne)(nil), // 1: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 2: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 3: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.Parse:type_name -> ngolofuzz.ParseArgs
1, // 1: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[1].OneofWrappers = []any{
(*NgoloFuzzOne_Parse)(nil),
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_xtea
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/xtea"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var CipherResults []*xtea.Cipher
CipherResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewCipher:
r0, r1 := xtea.NewCipher(a.NewCipher.Key)
if r0 != nil{
CipherResults = append(CipherResults, r0)
}
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_CipherNgdotBlockSize:
if len(CipherResults) == 0 {
continue
}
arg0 := CipherResults[CipherResultsIndex]
CipherResultsIndex = (CipherResultsIndex + 1) % len(CipherResults)
arg0.BlockSize()
case *NgoloFuzzOne_CipherNgdotEncrypt:
if len(CipherResults) == 0 {
continue
}
arg0 := CipherResults[CipherResultsIndex]
CipherResultsIndex = (CipherResultsIndex + 1) % len(CipherResults)
a.CipherNgdotEncrypt.Dst = make([]byte, 2*len(a.CipherNgdotEncrypt.Src))
arg0.Encrypt(a.CipherNgdotEncrypt.Dst, a.CipherNgdotEncrypt.Src)
case *NgoloFuzzOne_CipherNgdotDecrypt:
if len(CipherResults) == 0 {
continue
}
arg0 := CipherResults[CipherResultsIndex]
CipherResultsIndex = (CipherResultsIndex + 1) % len(CipherResults)
a.CipherNgdotDecrypt.Dst = make([]byte, 2*len(a.CipherNgdotDecrypt.Src))
arg0.Decrypt(a.CipherNgdotDecrypt.Dst, a.CipherNgdotDecrypt.Src)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
CipherNb := 0
CipherResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewCipher:
w.WriteString(fmt.Sprintf("Cipher%d, _ := xtea.NewCipher(%#+v)\n", CipherNb, a.NewCipher.Key))
CipherNb = CipherNb + 1
case *NgoloFuzzOne_CipherNgdotBlockSize:
if CipherNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Cipher%d.BlockSize()\n", CipherResultsIndex))
CipherResultsIndex = (CipherResultsIndex + 1) % CipherNb
case *NgoloFuzzOne_CipherNgdotEncrypt:
if CipherNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Cipher%d.Encrypt(%#+v, %#+v)\n", CipherResultsIndex, a.CipherNgdotEncrypt.Dst, a.CipherNgdotEncrypt.Src))
CipherResultsIndex = (CipherResultsIndex + 1) % CipherNb
case *NgoloFuzzOne_CipherNgdotDecrypt:
if CipherNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Cipher%d.Decrypt(%#+v, %#+v)\n", CipherResultsIndex, a.CipherNgdotDecrypt.Dst, a.CipherNgdotDecrypt.Src))
CipherResultsIndex = (CipherResultsIndex + 1) % CipherNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_xtea
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type NewCipherArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewCipherArgs) Reset() {
*x = NewCipherArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewCipherArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewCipherArgs) ProtoMessage() {}
func (x *NewCipherArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewCipherArgs.ProtoReflect.Descriptor instead.
func (*NewCipherArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *NewCipherArgs) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
type CipherNgdotBlockSizeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CipherNgdotBlockSizeArgs) Reset() {
*x = CipherNgdotBlockSizeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CipherNgdotBlockSizeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CipherNgdotBlockSizeArgs) ProtoMessage() {}
func (x *CipherNgdotBlockSizeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CipherNgdotBlockSizeArgs.ProtoReflect.Descriptor instead.
func (*CipherNgdotBlockSizeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
type CipherNgdotEncryptArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Dst []byte `protobuf:"bytes,1,opt,name=dst,proto3" json:"dst,omitempty"`
Src []byte `protobuf:"bytes,2,opt,name=src,proto3" json:"src,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CipherNgdotEncryptArgs) Reset() {
*x = CipherNgdotEncryptArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CipherNgdotEncryptArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CipherNgdotEncryptArgs) ProtoMessage() {}
func (x *CipherNgdotEncryptArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CipherNgdotEncryptArgs.ProtoReflect.Descriptor instead.
func (*CipherNgdotEncryptArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *CipherNgdotEncryptArgs) GetDst() []byte {
if x != nil {
return x.Dst
}
return nil
}
func (x *CipherNgdotEncryptArgs) GetSrc() []byte {
if x != nil {
return x.Src
}
return nil
}
type CipherNgdotDecryptArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Dst []byte `protobuf:"bytes,1,opt,name=dst,proto3" json:"dst,omitempty"`
Src []byte `protobuf:"bytes,2,opt,name=src,proto3" json:"src,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CipherNgdotDecryptArgs) Reset() {
*x = CipherNgdotDecryptArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CipherNgdotDecryptArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CipherNgdotDecryptArgs) ProtoMessage() {}
func (x *CipherNgdotDecryptArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CipherNgdotDecryptArgs.ProtoReflect.Descriptor instead.
func (*CipherNgdotDecryptArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *CipherNgdotDecryptArgs) GetDst() []byte {
if x != nil {
return x.Dst
}
return nil
}
func (x *CipherNgdotDecryptArgs) GetSrc() []byte {
if x != nil {
return x.Src
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_NewCipher
// *NgoloFuzzOne_CipherNgdotBlockSize
// *NgoloFuzzOne_CipherNgdotEncrypt
// *NgoloFuzzOne_CipherNgdotDecrypt
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetNewCipher() *NewCipherArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewCipher); ok {
return x.NewCipher
}
}
return nil
}
func (x *NgoloFuzzOne) GetCipherNgdotBlockSize() *CipherNgdotBlockSizeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CipherNgdotBlockSize); ok {
return x.CipherNgdotBlockSize
}
}
return nil
}
func (x *NgoloFuzzOne) GetCipherNgdotEncrypt() *CipherNgdotEncryptArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CipherNgdotEncrypt); ok {
return x.CipherNgdotEncrypt
}
}
return nil
}
func (x *NgoloFuzzOne) GetCipherNgdotDecrypt() *CipherNgdotDecryptArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CipherNgdotDecrypt); ok {
return x.CipherNgdotDecrypt
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_NewCipher struct {
NewCipher *NewCipherArgs `protobuf:"bytes,1,opt,name=NewCipher,proto3,oneof"`
}
type NgoloFuzzOne_CipherNgdotBlockSize struct {
CipherNgdotBlockSize *CipherNgdotBlockSizeArgs `protobuf:"bytes,2,opt,name=CipherNgdotBlockSize,proto3,oneof"`
}
type NgoloFuzzOne_CipherNgdotEncrypt struct {
CipherNgdotEncrypt *CipherNgdotEncryptArgs `protobuf:"bytes,3,opt,name=CipherNgdotEncrypt,proto3,oneof"`
}
type NgoloFuzzOne_CipherNgdotDecrypt struct {
CipherNgdotDecrypt *CipherNgdotDecryptArgs `protobuf:"bytes,4,opt,name=CipherNgdotDecrypt,proto3,oneof"`
}
func (*NgoloFuzzOne_NewCipher) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CipherNgdotBlockSize) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CipherNgdotEncrypt) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CipherNgdotDecrypt) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"!\n" +
"\rNewCipherArgs\x12\x10\n" +
"\x03key\x18\x01 \x01(\fR\x03key\"\x1a\n" +
"\x18CipherNgdotBlockSizeArgs\"<\n" +
"\x16CipherNgdotEncryptArgs\x12\x10\n" +
"\x03dst\x18\x01 \x01(\fR\x03dst\x12\x10\n" +
"\x03src\x18\x02 \x01(\fR\x03src\"<\n" +
"\x16CipherNgdotDecryptArgs\x12\x10\n" +
"\x03dst\x18\x01 \x01(\fR\x03dst\x12\x10\n" +
"\x03src\x18\x02 \x01(\fR\x03src\"\xd5\x02\n" +
"\fNgoloFuzzOne\x128\n" +
"\tNewCipher\x18\x01 \x01(\v2\x18.ngolofuzz.NewCipherArgsH\x00R\tNewCipher\x12Y\n" +
"\x14CipherNgdotBlockSize\x18\x02 \x01(\v2#.ngolofuzz.CipherNgdotBlockSizeArgsH\x00R\x14CipherNgdotBlockSize\x12S\n" +
"\x12CipherNgdotEncrypt\x18\x03 \x01(\v2!.ngolofuzz.CipherNgdotEncryptArgsH\x00R\x12CipherNgdotEncrypt\x12S\n" +
"\x12CipherNgdotDecrypt\x18\x04 \x01(\v2!.ngolofuzz.CipherNgdotDecryptArgsH\x00R\x12CipherNgdotDecryptB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1aZ\x18./;fuzz_ng_x_crypto_xteab\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_ngolofuzz_proto_goTypes = []any{
(*NewCipherArgs)(nil), // 0: ngolofuzz.NewCipherArgs
(*CipherNgdotBlockSizeArgs)(nil), // 1: ngolofuzz.CipherNgdotBlockSizeArgs
(*CipherNgdotEncryptArgs)(nil), // 2: ngolofuzz.CipherNgdotEncryptArgs
(*CipherNgdotDecryptArgs)(nil), // 3: ngolofuzz.CipherNgdotDecryptArgs
(*NgoloFuzzOne)(nil), // 4: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 5: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 6: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.NewCipher:type_name -> ngolofuzz.NewCipherArgs
1, // 1: ngolofuzz.NgoloFuzzOne.CipherNgdotBlockSize:type_name -> ngolofuzz.CipherNgdotBlockSizeArgs
2, // 2: ngolofuzz.NgoloFuzzOne.CipherNgdotEncrypt:type_name -> ngolofuzz.CipherNgdotEncryptArgs
3, // 3: ngolofuzz.NgoloFuzzOne.CipherNgdotDecrypt:type_name -> ngolofuzz.CipherNgdotDecryptArgs
4, // 4: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[4].OneofWrappers = []any{
(*NgoloFuzzOne_NewCipher)(nil),
(*NgoloFuzzOne_CipherNgdotBlockSize)(nil),
(*NgoloFuzzOne_CipherNgdotEncrypt)(nil),
(*NgoloFuzzOne_CipherNgdotDecrypt)(nil),
}
file_ngolofuzz_proto_msgTypes[5].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 7,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_crypto_xts
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/crypto/xts"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var CipherResults []*xts.Cipher
CipherResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_CipherNgdotEncrypt:
if len(CipherResults) == 0 {
continue
}
arg0 := CipherResults[CipherResultsIndex]
CipherResultsIndex = (CipherResultsIndex + 1) % len(CipherResults)
arg0.Encrypt(a.CipherNgdotEncrypt.Ciphertext, a.CipherNgdotEncrypt.Plaintext, a.CipherNgdotEncrypt.SectorNum)
case *NgoloFuzzOne_CipherNgdotDecrypt:
if len(CipherResults) == 0 {
continue
}
arg0 := CipherResults[CipherResultsIndex]
CipherResultsIndex = (CipherResultsIndex + 1) % len(CipherResults)
arg0.Decrypt(a.CipherNgdotDecrypt.Plaintext, a.CipherNgdotDecrypt.Ciphertext, a.CipherNgdotDecrypt.SectorNum)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
CipherNb := 0
CipherResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_CipherNgdotEncrypt:
if CipherNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Cipher%d.Encrypt(%#+v, %#+v, %#+v)\n", CipherResultsIndex, a.CipherNgdotEncrypt.Ciphertext, a.CipherNgdotEncrypt.Plaintext, a.CipherNgdotEncrypt.SectorNum))
CipherResultsIndex = (CipherResultsIndex + 1) % CipherNb
case *NgoloFuzzOne_CipherNgdotDecrypt:
if CipherNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Cipher%d.Decrypt(%#+v, %#+v, %#+v)\n", CipherResultsIndex, a.CipherNgdotDecrypt.Plaintext, a.CipherNgdotDecrypt.Ciphertext, a.CipherNgdotDecrypt.SectorNum))
CipherResultsIndex = (CipherResultsIndex + 1) % CipherNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_crypto_xts
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type CipherNgdotEncryptArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Ciphertext []byte `protobuf:"bytes,1,opt,name=ciphertext,proto3" json:"ciphertext,omitempty"`
Plaintext []byte `protobuf:"bytes,2,opt,name=plaintext,proto3" json:"plaintext,omitempty"`
SectorNum uint64 `protobuf:"varint,3,opt,name=sectorNum,proto3" json:"sectorNum,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CipherNgdotEncryptArgs) Reset() {
*x = CipherNgdotEncryptArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CipherNgdotEncryptArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CipherNgdotEncryptArgs) ProtoMessage() {}
func (x *CipherNgdotEncryptArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CipherNgdotEncryptArgs.ProtoReflect.Descriptor instead.
func (*CipherNgdotEncryptArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *CipherNgdotEncryptArgs) GetCiphertext() []byte {
if x != nil {
return x.Ciphertext
}
return nil
}
func (x *CipherNgdotEncryptArgs) GetPlaintext() []byte {
if x != nil {
return x.Plaintext
}
return nil
}
func (x *CipherNgdotEncryptArgs) GetSectorNum() uint64 {
if x != nil {
return x.SectorNum
}
return 0
}
type CipherNgdotDecryptArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Plaintext []byte `protobuf:"bytes,1,opt,name=plaintext,proto3" json:"plaintext,omitempty"`
Ciphertext []byte `protobuf:"bytes,2,opt,name=ciphertext,proto3" json:"ciphertext,omitempty"`
SectorNum uint64 `protobuf:"varint,3,opt,name=sectorNum,proto3" json:"sectorNum,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CipherNgdotDecryptArgs) Reset() {
*x = CipherNgdotDecryptArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CipherNgdotDecryptArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CipherNgdotDecryptArgs) ProtoMessage() {}
func (x *CipherNgdotDecryptArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CipherNgdotDecryptArgs.ProtoReflect.Descriptor instead.
func (*CipherNgdotDecryptArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *CipherNgdotDecryptArgs) GetPlaintext() []byte {
if x != nil {
return x.Plaintext
}
return nil
}
func (x *CipherNgdotDecryptArgs) GetCiphertext() []byte {
if x != nil {
return x.Ciphertext
}
return nil
}
func (x *CipherNgdotDecryptArgs) GetSectorNum() uint64 {
if x != nil {
return x.SectorNum
}
return 0
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_CipherNgdotEncrypt
// *NgoloFuzzOne_CipherNgdotDecrypt
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetCipherNgdotEncrypt() *CipherNgdotEncryptArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CipherNgdotEncrypt); ok {
return x.CipherNgdotEncrypt
}
}
return nil
}
func (x *NgoloFuzzOne) GetCipherNgdotDecrypt() *CipherNgdotDecryptArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CipherNgdotDecrypt); ok {
return x.CipherNgdotDecrypt
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_CipherNgdotEncrypt struct {
CipherNgdotEncrypt *CipherNgdotEncryptArgs `protobuf:"bytes,1,opt,name=CipherNgdotEncrypt,proto3,oneof"`
}
type NgoloFuzzOne_CipherNgdotDecrypt struct {
CipherNgdotDecrypt *CipherNgdotDecryptArgs `protobuf:"bytes,2,opt,name=CipherNgdotDecrypt,proto3,oneof"`
}
func (*NgoloFuzzOne_CipherNgdotEncrypt) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CipherNgdotDecrypt) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"t\n" +
"\x16CipherNgdotEncryptArgs\x12\x1e\n" +
"\n" +
"ciphertext\x18\x01 \x01(\fR\n" +
"ciphertext\x12\x1c\n" +
"\tplaintext\x18\x02 \x01(\fR\tplaintext\x12\x1c\n" +
"\tsectorNum\x18\x03 \x01(\x04R\tsectorNum\"t\n" +
"\x16CipherNgdotDecryptArgs\x12\x1c\n" +
"\tplaintext\x18\x01 \x01(\fR\tplaintext\x12\x1e\n" +
"\n" +
"ciphertext\x18\x02 \x01(\fR\n" +
"ciphertext\x12\x1c\n" +
"\tsectorNum\x18\x03 \x01(\x04R\tsectorNum\"\xc0\x01\n" +
"\fNgoloFuzzOne\x12S\n" +
"\x12CipherNgdotEncrypt\x18\x01 \x01(\v2!.ngolofuzz.CipherNgdotEncryptArgsH\x00R\x12CipherNgdotEncrypt\x12S\n" +
"\x12CipherNgdotDecrypt\x18\x02 \x01(\v2!.ngolofuzz.CipherNgdotDecryptArgsH\x00R\x12CipherNgdotDecryptB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x19Z\x17./;fuzz_ng_x_crypto_xtsb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_ngolofuzz_proto_goTypes = []any{
(*CipherNgdotEncryptArgs)(nil), // 0: ngolofuzz.CipherNgdotEncryptArgs
(*CipherNgdotDecryptArgs)(nil), // 1: ngolofuzz.CipherNgdotDecryptArgs
(*NgoloFuzzOne)(nil), // 2: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 3: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 4: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.CipherNgdotEncrypt:type_name -> ngolofuzz.CipherNgdotEncryptArgs
1, // 1: ngolofuzz.NgoloFuzzOne.CipherNgdotDecrypt:type_name -> ngolofuzz.CipherNgdotDecryptArgs
2, // 2: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzOne_CipherNgdotEncrypt)(nil),
(*NgoloFuzzOne_CipherNgdotDecrypt)(nil),
}
file_ngolofuzz_proto_msgTypes[3].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
// Copyright 2018 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.
//go:build !purego
// Package alias implements memory aliasing tests.
package alias
import "unsafe"
// AnyOverlap reports whether x and y share memory at any (not necessarily
// corresponding) index. The memory beyond the slice length is ignored.
func AnyOverlap(x, y []byte) bool {
return len(x) > 0 && len(y) > 0 &&
uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
}
// InexactOverlap reports whether x and y share memory at any non-corresponding
// index. The memory beyond the slice length is ignored. Note that x and y can
// have different lengths and still not have any inexact overlap.
//
// InexactOverlap can be used to implement the requirements of the crypto/cipher
// AEAD, Block, BlockMode and Stream interfaces.
func InexactOverlap(x, y []byte) bool {
if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
return false
}
return AnyOverlap(x, y)
}
// 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.
// Package poly1305 implements Poly1305 one-time message authentication code as
// specified in https://cr.yp.to/mac/poly1305-20050329.pdf.
//
// Poly1305 is a fast, one-time authentication function. It is infeasible for an
// attacker to generate an authenticator for a message without the key. However, a
// key must only be used for a single message. Authenticating two different
// messages with the same key allows an attacker to forge authenticators for other
// messages with the same key.
//
// Poly1305 was originally coupled with AES in order to make Poly1305-AES. AES was
// used with a fixed key in order to generate one-time keys from an nonce.
// However, in this package AES isn't used and the one-time key is specified
// directly.
package poly1305
import "crypto/subtle"
// TagSize is the size, in bytes, of a poly1305 authenticator.
const TagSize = 16
// Sum generates an authenticator for msg using a one-time key and puts the
// 16-byte result into out. Authenticating two different messages with the same
// key allows an attacker to forge messages at will.
func Sum(out *[16]byte, m []byte, key *[32]byte) {
h := New(key)
h.Write(m)
h.Sum(out[:0])
}
// Verify returns true if mac is a valid authenticator for m with the given key.
func Verify(mac *[16]byte, m []byte, key *[32]byte) bool {
var tmp [16]byte
Sum(&tmp, m, key)
return subtle.ConstantTimeCompare(tmp[:], mac[:]) == 1
}
// New returns a new MAC computing an authentication
// tag of all data written to it with the given key.
// This allows writing the message progressively instead
// of passing it as a single slice. Common users should use
// the Sum function instead.
//
// The key must be unique for each message, as authenticating
// two different messages with the same key allows an attacker
// to forge messages at will.
func New(key *[32]byte) *MAC {
m := &MAC{}
initialize(key, &m.macState)
return m
}
// MAC is an io.Writer computing an authentication tag
// of the data written to it.
//
// MAC cannot be used like common hash.Hash implementations,
// because using a poly1305 key twice breaks its security.
// Therefore writing data to a running MAC after calling
// Sum or Verify causes it to panic.
type MAC struct {
mac // platform-dependent implementation
finalized bool
}
// Size returns the number of bytes Sum will return.
func (h *MAC) Size() int { return TagSize }
// Write adds more data to the running message authentication code.
// It never returns an error.
//
// It must not be called after the first call of Sum or Verify.
func (h *MAC) Write(p []byte) (n int, err error) {
if h.finalized {
panic("poly1305: write to MAC after Sum or Verify")
}
return h.mac.Write(p)
}
// Sum computes the authenticator of all data written to the
// message authentication code.
func (h *MAC) Sum(b []byte) []byte {
var mac [TagSize]byte
h.mac.Sum(&mac)
h.finalized = true
return append(b, mac[:]...)
}
// Verify returns whether the authenticator of all data written to
// the message authentication code matches the expected value.
func (h *MAC) Verify(expected []byte) bool {
var mac [TagSize]byte
h.mac.Sum(&mac)
h.finalized = true
return subtle.ConstantTimeCompare(expected, mac[:]) == 1
}
// 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.
//go:build gc && !purego && (amd64 || loong64 || ppc64 || ppc64le)
package poly1305
//go:noescape
func update(state *macState, msg []byte)
// mac is a wrapper for macGeneric that redirects calls that would have gone to
// updateGeneric to update.
//
// Its Write and Sum methods are otherwise identical to the macGeneric ones, but
// using function pointers would carry a major performance cost.
type mac struct{ macGeneric }
func (h *mac) Write(p []byte) (int, error) {
nn := len(p)
if h.offset > 0 {
n := copy(h.buffer[h.offset:], p)
if h.offset+n < TagSize {
h.offset += n
return nn, nil
}
p = p[n:]
h.offset = 0
update(&h.macState, h.buffer[:])
}
if n := len(p) - (len(p) % TagSize); n > 0 {
update(&h.macState, p[:n])
p = p[n:]
}
if len(p) > 0 {
h.offset += copy(h.buffer[h.offset:], p)
}
return nn, nil
}
func (h *mac) Sum(out *[16]byte) {
state := h.macState
if h.offset > 0 {
update(&state, h.buffer[:h.offset])
}
finalize(out, &state.h, &state.s)
}
// Copyright 2018 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 file provides the generic implementation of Sum and MAC. Other files
// might provide optimized assembly implementations of some of this code.
package poly1305
import (
"encoding/binary"
"math/bits"
)
// Poly1305 [RFC 7539] is a relatively simple algorithm: the authentication tag
// for a 64 bytes message is approximately
//
// s + m[0:16] * r⁴ + m[16:32] * r³ + m[32:48] * r² + m[48:64] * r mod 2¹³⁰ - 5
//
// for some secret r and s. It can be computed sequentially like
//
// for len(msg) > 0:
// h += read(msg, 16)
// h *= r
// h %= 2¹³⁰ - 5
// return h + s
//
// All the complexity is about doing performant constant-time math on numbers
// larger than any available numeric type.
func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) {
h := newMACGeneric(key)
h.Write(msg)
h.Sum(out)
}
func newMACGeneric(key *[32]byte) macGeneric {
m := macGeneric{}
initialize(key, &m.macState)
return m
}
// macState holds numbers in saturated 64-bit little-endian limbs. That is,
// the value of [x0, x1, x2] is x[0] + x[1] * 2⁶⁴ + x[2] * 2¹²⁸.
type macState struct {
// h is the main accumulator. It is to be interpreted modulo 2¹³⁰ - 5, but
// can grow larger during and after rounds. It must, however, remain below
// 2 * (2¹³⁰ - 5).
h [3]uint64
// r and s are the private key components.
r [2]uint64
s [2]uint64
}
type macGeneric struct {
macState
buffer [TagSize]byte
offset int
}
// Write splits the incoming message into TagSize chunks, and passes them to
// update. It buffers incomplete chunks.
func (h *macGeneric) Write(p []byte) (int, error) {
nn := len(p)
if h.offset > 0 {
n := copy(h.buffer[h.offset:], p)
if h.offset+n < TagSize {
h.offset += n
return nn, nil
}
p = p[n:]
h.offset = 0
updateGeneric(&h.macState, h.buffer[:])
}
if n := len(p) - (len(p) % TagSize); n > 0 {
updateGeneric(&h.macState, p[:n])
p = p[n:]
}
if len(p) > 0 {
h.offset += copy(h.buffer[h.offset:], p)
}
return nn, nil
}
// Sum flushes the last incomplete chunk from the buffer, if any, and generates
// the MAC output. It does not modify its state, in order to allow for multiple
// calls to Sum, even if no Write is allowed after Sum.
func (h *macGeneric) Sum(out *[TagSize]byte) {
state := h.macState
if h.offset > 0 {
updateGeneric(&state, h.buffer[:h.offset])
}
finalize(out, &state.h, &state.s)
}
// [rMask0, rMask1] is the specified Poly1305 clamping mask in little-endian. It
// clears some bits of the secret coefficient to make it possible to implement
// multiplication more efficiently.
const (
rMask0 = 0x0FFFFFFC0FFFFFFF
rMask1 = 0x0FFFFFFC0FFFFFFC
)
// initialize loads the 256-bit key into the two 128-bit secret values r and s.
func initialize(key *[32]byte, m *macState) {
m.r[0] = binary.LittleEndian.Uint64(key[0:8]) & rMask0
m.r[1] = binary.LittleEndian.Uint64(key[8:16]) & rMask1
m.s[0] = binary.LittleEndian.Uint64(key[16:24])
m.s[1] = binary.LittleEndian.Uint64(key[24:32])
}
// uint128 holds a 128-bit number as two 64-bit limbs, for use with the
// bits.Mul64 and bits.Add64 intrinsics.
type uint128 struct {
lo, hi uint64
}
func mul64(a, b uint64) uint128 {
hi, lo := bits.Mul64(a, b)
return uint128{lo, hi}
}
func add128(a, b uint128) uint128 {
lo, c := bits.Add64(a.lo, b.lo, 0)
hi, c := bits.Add64(a.hi, b.hi, c)
if c != 0 {
panic("poly1305: unexpected overflow")
}
return uint128{lo, hi}
}
func shiftRightBy2(a uint128) uint128 {
a.lo = a.lo>>2 | (a.hi&3)<<62
a.hi = a.hi >> 2
return a
}
// updateGeneric absorbs msg into the state.h accumulator. For each chunk m of
// 128 bits of message, it computes
//
// h₊ = (h + m) * r mod 2¹³⁰ - 5
//
// If the msg length is not a multiple of TagSize, it assumes the last
// incomplete chunk is the final one.
func updateGeneric(state *macState, msg []byte) {
h0, h1, h2 := state.h[0], state.h[1], state.h[2]
r0, r1 := state.r[0], state.r[1]
for len(msg) > 0 {
var c uint64
// For the first step, h + m, we use a chain of bits.Add64 intrinsics.
// The resulting value of h might exceed 2¹³⁰ - 5, but will be partially
// reduced at the end of the multiplication below.
//
// The spec requires us to set a bit just above the message size, not to
// hide leading zeroes. For full chunks, that's 1 << 128, so we can just
// add 1 to the most significant (2¹²⁸) limb, h2.
if len(msg) >= TagSize {
h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0)
h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(msg[8:16]), c)
h2 += c + 1
msg = msg[TagSize:]
} else {
var buf [TagSize]byte
copy(buf[:], msg)
buf[len(msg)] = 1
h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0)
h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(buf[8:16]), c)
h2 += c
msg = nil
}
// Multiplication of big number limbs is similar to elementary school
// columnar multiplication. Instead of digits, there are 64-bit limbs.
//
// We are multiplying a 3 limbs number, h, by a 2 limbs number, r.
//
// h2 h1 h0 x
// r1 r0 =
// ----------------
// h2r0 h1r0 h0r0 <-- individual 128-bit products
// + h2r1 h1r1 h0r1
// ------------------------
// m3 m2 m1 m0 <-- result in 128-bit overlapping limbs
// ------------------------
// m3.hi m2.hi m1.hi m0.hi <-- carry propagation
// + m3.lo m2.lo m1.lo m0.lo
// -------------------------------
// t4 t3 t2 t1 t0 <-- final result in 64-bit limbs
//
// The main difference from pen-and-paper multiplication is that we do
// carry propagation in a separate step, as if we wrote two digit sums
// at first (the 128-bit limbs), and then carried the tens all at once.
h0r0 := mul64(h0, r0)
h1r0 := mul64(h1, r0)
h2r0 := mul64(h2, r0)
h0r1 := mul64(h0, r1)
h1r1 := mul64(h1, r1)
h2r1 := mul64(h2, r1)
// Since h2 is known to be at most 7 (5 + 1 + 1), and r0 and r1 have their
// top 4 bits cleared by rMask{0,1}, we know that their product is not going
// to overflow 64 bits, so we can ignore the high part of the products.
//
// This also means that the product doesn't have a fifth limb (t4).
if h2r0.hi != 0 {
panic("poly1305: unexpected overflow")
}
if h2r1.hi != 0 {
panic("poly1305: unexpected overflow")
}
m0 := h0r0
m1 := add128(h1r0, h0r1) // These two additions don't overflow thanks again
m2 := add128(h2r0, h1r1) // to the 4 masked bits at the top of r0 and r1.
m3 := h2r1
t0 := m0.lo
t1, c := bits.Add64(m1.lo, m0.hi, 0)
t2, c := bits.Add64(m2.lo, m1.hi, c)
t3, _ := bits.Add64(m3.lo, m2.hi, c)
// Now we have the result as 4 64-bit limbs, and we need to reduce it
// modulo 2¹³⁰ - 5. The special shape of this Crandall prime lets us do
// a cheap partial reduction according to the reduction identity
//
// c * 2¹³⁰ + n = c * 5 + n mod 2¹³⁰ - 5
//
// because 2¹³⁰ = 5 mod 2¹³⁰ - 5. Partial reduction since the result is
// likely to be larger than 2¹³⁰ - 5, but still small enough to fit the
// assumptions we make about h in the rest of the code.
//
// See also https://speakerdeck.com/gtank/engineering-prime-numbers?slide=23
// We split the final result at the 2¹³⁰ mark into h and cc, the carry.
// Note that the carry bits are effectively shifted left by 2, in other
// words, cc = c * 4 for the c in the reduction identity.
h0, h1, h2 = t0, t1, t2&maskLow2Bits
cc := uint128{t2 & maskNotLow2Bits, t3}
// To add c * 5 to h, we first add cc = c * 4, and then add (cc >> 2) = c.
h0, c = bits.Add64(h0, cc.lo, 0)
h1, c = bits.Add64(h1, cc.hi, c)
h2 += c
cc = shiftRightBy2(cc)
h0, c = bits.Add64(h0, cc.lo, 0)
h1, c = bits.Add64(h1, cc.hi, c)
h2 += c
// h2 is at most 3 + 1 + 1 = 5, making the whole of h at most
//
// 5 * 2¹²⁸ + (2¹²⁸ - 1) = 6 * 2¹²⁸ - 1
}
state.h[0], state.h[1], state.h[2] = h0, h1, h2
}
const (
maskLow2Bits uint64 = 0x0000000000000003
maskNotLow2Bits uint64 = ^maskLow2Bits
)
// select64 returns x if v == 1 and y if v == 0, in constant time.
func select64(v, x, y uint64) uint64 { return ^(v-1)&x | (v-1)&y }
// [p0, p1, p2] is 2¹³⁰ - 5 in little endian order.
const (
p0 = 0xFFFFFFFFFFFFFFFB
p1 = 0xFFFFFFFFFFFFFFFF
p2 = 0x0000000000000003
)
// finalize completes the modular reduction of h and computes
//
// out = h + s mod 2¹²⁸
func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) {
h0, h1, h2 := h[0], h[1], h[2]
// After the partial reduction in updateGeneric, h might be more than
// 2¹³⁰ - 5, but will be less than 2 * (2¹³⁰ - 5). To complete the reduction
// in constant time, we compute t = h - (2¹³⁰ - 5), and select h as the
// result if the subtraction underflows, and t otherwise.
hMinusP0, b := bits.Sub64(h0, p0, 0)
hMinusP1, b := bits.Sub64(h1, p1, b)
_, b = bits.Sub64(h2, p2, b)
// h = h if h < p else h - p
h0 = select64(b, h0, hMinusP0)
h1 = select64(b, h1, hMinusP1)
// Finally, we compute the last Poly1305 step
//
// tag = h + s mod 2¹²⁸
//
// by just doing a wide addition with the 128 low bits of h and discarding
// the overflow.
h0, c := bits.Add64(h0, s[0], 0)
h1, _ = bits.Add64(h1, s[1], c)
binary.LittleEndian.PutUint64(out[0:8], h0)
binary.LittleEndian.PutUint64(out[8:16], h1)
}
// 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.
/*
Package box authenticates and encrypts small messages using public-key cryptography.
Box uses Curve25519, XSalsa20 and Poly1305 to encrypt and authenticate
messages. The length of messages is not hidden.
It is the caller's responsibility to ensure the uniqueness of nonces—for
example, by using nonce 1 for the first message, nonce 2 for the second
message, etc. Nonces are long enough that randomly generated nonces have
negligible risk of collision.
Messages should be small because:
1. The whole message needs to be held in memory to be processed.
2. Using large messages pressures implementations on small machines to decrypt
and process plaintext before authenticating it. This is very dangerous, and
this API does not allow it, but a protocol that uses excessive message sizes
might present some implementations with no other choice.
3. Fixed overheads will be sufficiently amortised by messages as small as 8KB.
4. Performance may be improved by working with messages that fit into data caches.
Thus large amounts of data should be chunked so that each message is small.
(Each message still needs a unique nonce.) If in doubt, 16KB is a reasonable
chunk size.
This package is interoperable with NaCl: https://nacl.cr.yp.to/box.html.
Anonymous sealing/opening is an extension of NaCl defined by and interoperable
with libsodium:
https://libsodium.gitbook.io/doc/public-key_cryptography/sealed_boxes.
*/
package box
import (
cryptorand "crypto/rand"
"io"
"golang.org/x/crypto/blake2b"
"golang.org/x/crypto/curve25519"
"golang.org/x/crypto/nacl/secretbox"
"golang.org/x/crypto/salsa20/salsa"
)
const (
// Overhead is the number of bytes of overhead when boxing a message.
Overhead = secretbox.Overhead
// AnonymousOverhead is the number of bytes of overhead when using anonymous
// sealed boxes.
AnonymousOverhead = Overhead + 32
)
// GenerateKey generates a new public/private key pair suitable for use with
// Seal and Open.
func GenerateKey(rand io.Reader) (publicKey, privateKey *[32]byte, err error) {
publicKey = new([32]byte)
privateKey = new([32]byte)
_, err = io.ReadFull(rand, privateKey[:])
if err != nil {
publicKey = nil
privateKey = nil
return
}
curve25519.ScalarBaseMult(publicKey, privateKey)
return
}
var zeros [16]byte
// Precompute calculates the shared key between peersPublicKey and privateKey
// and writes it to sharedKey. The shared key can be used with
// OpenAfterPrecomputation and SealAfterPrecomputation to speed up processing
// when using the same pair of keys repeatedly.
func Precompute(sharedKey, peersPublicKey, privateKey *[32]byte) {
curve25519.ScalarMult(sharedKey, privateKey, peersPublicKey)
salsa.HSalsa20(sharedKey, &zeros, sharedKey, &salsa.Sigma)
}
// Seal appends an encrypted and authenticated copy of message to out, which
// will be Overhead bytes longer than the original and must not overlap it. The
// nonce must be unique for each distinct message for a given pair of keys.
func Seal(out, message []byte, nonce *[24]byte, peersPublicKey, privateKey *[32]byte) []byte {
var sharedKey [32]byte
Precompute(&sharedKey, peersPublicKey, privateKey)
return secretbox.Seal(out, message, nonce, &sharedKey)
}
// SealAfterPrecomputation performs the same actions as Seal, but takes a
// shared key as generated by Precompute.
func SealAfterPrecomputation(out, message []byte, nonce *[24]byte, sharedKey *[32]byte) []byte {
return secretbox.Seal(out, message, nonce, sharedKey)
}
// Open authenticates and decrypts a box produced by Seal and appends the
// message to out, which must not overlap box. The output will be Overhead
// bytes smaller than box.
func Open(out, box []byte, nonce *[24]byte, peersPublicKey, privateKey *[32]byte) ([]byte, bool) {
var sharedKey [32]byte
Precompute(&sharedKey, peersPublicKey, privateKey)
return secretbox.Open(out, box, nonce, &sharedKey)
}
// OpenAfterPrecomputation performs the same actions as Open, but takes a
// shared key as generated by Precompute.
func OpenAfterPrecomputation(out, box []byte, nonce *[24]byte, sharedKey *[32]byte) ([]byte, bool) {
return secretbox.Open(out, box, nonce, sharedKey)
}
// SealAnonymous appends an encrypted and authenticated copy of message to out,
// which will be AnonymousOverhead bytes longer than the original and must not
// overlap it. This differs from Seal in that the sender is not required to
// provide a private key.
func SealAnonymous(out, message []byte, recipient *[32]byte, rand io.Reader) ([]byte, error) {
if rand == nil {
rand = cryptorand.Reader
}
ephemeralPub, ephemeralPriv, err := GenerateKey(rand)
if err != nil {
return nil, err
}
var nonce [24]byte
if err := sealNonce(ephemeralPub, recipient, &nonce); err != nil {
return nil, err
}
if total := len(out) + AnonymousOverhead + len(message); cap(out) < total {
original := out
out = make([]byte, 0, total)
out = append(out, original...)
}
out = append(out, ephemeralPub[:]...)
return Seal(out, message, &nonce, recipient, ephemeralPriv), nil
}
// OpenAnonymous authenticates and decrypts a box produced by SealAnonymous and
// appends the message to out, which must not overlap box. The output will be
// AnonymousOverhead bytes smaller than box.
func OpenAnonymous(out, box []byte, publicKey, privateKey *[32]byte) (message []byte, ok bool) {
if len(box) < AnonymousOverhead {
return nil, false
}
var ephemeralPub [32]byte
copy(ephemeralPub[:], box[:32])
var nonce [24]byte
if err := sealNonce(&ephemeralPub, publicKey, &nonce); err != nil {
return nil, false
}
return Open(out, box[32:], &nonce, &ephemeralPub, privateKey)
}
// sealNonce generates a 24 byte nonce that is a blake2b digest of the
// ephemeral public key and the receiver's public key.
func sealNonce(ephemeralPub, peersPublicKey *[32]byte, nonce *[24]byte) error {
h, err := blake2b.New(24, nil)
if err != nil {
return err
}
if _, err = h.Write(ephemeralPub[:]); err != nil {
return err
}
if _, err = h.Write(peersPublicKey[:]); err != nil {
return err
}
h.Sum(nonce[:0])
return nil
}
// 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.
/*
Package secretbox encrypts and authenticates small messages.
Secretbox uses XSalsa20 and Poly1305 to encrypt and authenticate messages with
secret-key cryptography. The length of messages is not hidden.
It is the caller's responsibility to ensure the uniqueness of nonces—for
example, by using nonce 1 for the first message, nonce 2 for the second
message, etc. Nonces are long enough that randomly generated nonces have
negligible risk of collision.
Messages should be small because:
1. The whole message needs to be held in memory to be processed.
2. Using large messages pressures implementations on small machines to decrypt
and process plaintext before authenticating it. This is very dangerous, and
this API does not allow it, but a protocol that uses excessive message sizes
might present some implementations with no other choice.
3. Fixed overheads will be sufficiently amortised by messages as small as 8KB.
4. Performance may be improved by working with messages that fit into data caches.
Thus large amounts of data should be chunked so that each message is small.
(Each message still needs a unique nonce.) If in doubt, 16KB is a reasonable
chunk size.
This package is interoperable with NaCl: https://nacl.cr.yp.to/secretbox.html.
*/
package secretbox
import (
"golang.org/x/crypto/internal/alias"
"golang.org/x/crypto/internal/poly1305"
"golang.org/x/crypto/salsa20/salsa"
)
// Overhead is the number of bytes of overhead when boxing a message.
const Overhead = poly1305.TagSize
// setup produces a sub-key and Salsa20 counter given a nonce and key.
func setup(subKey *[32]byte, counter *[16]byte, nonce *[24]byte, key *[32]byte) {
// We use XSalsa20 for encryption so first we need to generate a
// key and nonce with HSalsa20.
var hNonce [16]byte
copy(hNonce[:], nonce[:])
salsa.HSalsa20(subKey, &hNonce, key, &salsa.Sigma)
// The final 8 bytes of the original nonce form the new nonce.
copy(counter[:], nonce[16:])
}
// sliceForAppend takes a slice and a requested number of bytes. It returns a
// slice with the contents of the given slice followed by that many bytes and a
// second slice that aliases into it and contains only the extra bytes. If the
// original slice has sufficient capacity then no allocation is performed.
func sliceForAppend(in []byte, n int) (head, tail []byte) {
if total := len(in) + n; cap(in) >= total {
head = in[:total]
} else {
head = make([]byte, total)
copy(head, in)
}
tail = head[len(in):]
return
}
// Seal appends an encrypted and authenticated copy of message to out, which
// must not overlap message. The key and nonce pair must be unique for each
// distinct message and the output will be Overhead bytes longer than message.
func Seal(out, message []byte, nonce *[24]byte, key *[32]byte) []byte {
var subKey [32]byte
var counter [16]byte
setup(&subKey, &counter, nonce, key)
// The Poly1305 key is generated by encrypting 32 bytes of zeros. Since
// Salsa20 works with 64-byte blocks, we also generate 32 bytes of
// keystream as a side effect.
var firstBlock [64]byte
salsa.XORKeyStream(firstBlock[:], firstBlock[:], &counter, &subKey)
var poly1305Key [32]byte
copy(poly1305Key[:], firstBlock[:])
ret, out := sliceForAppend(out, len(message)+poly1305.TagSize)
if alias.AnyOverlap(out, message) {
panic("nacl: invalid buffer overlap")
}
// We XOR up to 32 bytes of message with the keystream generated from
// the first block.
firstMessageBlock := message
if len(firstMessageBlock) > 32 {
firstMessageBlock = firstMessageBlock[:32]
}
tagOut := out
out = out[poly1305.TagSize:]
for i, x := range firstMessageBlock {
out[i] = firstBlock[32+i] ^ x
}
message = message[len(firstMessageBlock):]
ciphertext := out
out = out[len(firstMessageBlock):]
// Now encrypt the rest.
counter[8] = 1
salsa.XORKeyStream(out, message, &counter, &subKey)
var tag [poly1305.TagSize]byte
poly1305.Sum(&tag, ciphertext, &poly1305Key)
copy(tagOut, tag[:])
return ret
}
// Open authenticates and decrypts a box produced by Seal and appends the
// message to out, which must not overlap box. The output will be Overhead
// bytes smaller than box.
func Open(out, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool) {
if len(box) < Overhead {
return nil, false
}
var subKey [32]byte
var counter [16]byte
setup(&subKey, &counter, nonce, key)
// The Poly1305 key is generated by encrypting 32 bytes of zeros. Since
// Salsa20 works with 64-byte blocks, we also generate 32 bytes of
// keystream as a side effect.
var firstBlock [64]byte
salsa.XORKeyStream(firstBlock[:], firstBlock[:], &counter, &subKey)
var poly1305Key [32]byte
copy(poly1305Key[:], firstBlock[:])
var tag [poly1305.TagSize]byte
copy(tag[:], box)
if !poly1305.Verify(&tag, box[poly1305.TagSize:], &poly1305Key) {
return nil, false
}
ret, out := sliceForAppend(out, len(box)-Overhead)
if alias.AnyOverlap(out, box) {
panic("nacl: invalid buffer overlap")
}
// We XOR up to 32 bytes of box with the keystream generated from
// the first block.
box = box[Overhead:]
firstMessageBlock := box
if len(firstMessageBlock) > 32 {
firstMessageBlock = firstMessageBlock[:32]
}
for i, x := range firstMessageBlock {
out[i] = firstBlock[32+i] ^ x
}
box = box[len(firstMessageBlock):]
out = out[len(firstMessageBlock):]
// Now decrypt the rest.
counter[8] = 1
salsa.XORKeyStream(out, box, &counter, &subKey)
return ret, true
}
// Copyright 2018 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 sign signs small messages using public-key cryptography.
//
// This package is interoperable with [libsodium], as well as [TweetNaCl].
//
// The sign package is essentially a wrapper for the Ed25519 signature
// algorithm (implemented by crypto/ed25519). It is [frozen] and is not accepting
// new features.
//
// [libsodium]: https://libsodium.gitbook.io/doc/public-key_cryptography/public-key_signatures
// [TweetNaCl]: https://tweetnacl.cr.yp.to/
// [frozen]: https://go.dev/wiki/Frozen
package sign
import (
"crypto/ed25519"
"io"
"golang.org/x/crypto/internal/alias"
)
// Overhead is the number of bytes of overhead when signing a message.
const Overhead = 64
// GenerateKey generates a new public/private key pair suitable for use with
// Sign and Open.
func GenerateKey(rand io.Reader) (publicKey *[32]byte, privateKey *[64]byte, err error) {
pub, priv, err := ed25519.GenerateKey(rand)
if err != nil {
return nil, nil, err
}
publicKey, privateKey = new([32]byte), new([64]byte)
copy((*publicKey)[:], pub)
copy((*privateKey)[:], priv)
return publicKey, privateKey, nil
}
// Sign appends a signed copy of message to out, which will be Overhead bytes
// longer than the original and must not overlap it.
func Sign(out, message []byte, privateKey *[64]byte) []byte {
sig := ed25519.Sign(ed25519.PrivateKey((*privateKey)[:]), message)
ret, out := sliceForAppend(out, Overhead+len(message))
if alias.AnyOverlap(out, message) {
panic("nacl: invalid buffer overlap")
}
copy(out, sig)
copy(out[Overhead:], message)
return ret
}
// Open verifies a signed message produced by Sign and appends the message to
// out, which must not overlap the signed message. The output will be Overhead
// bytes smaller than the signed message.
func Open(out, signedMessage []byte, publicKey *[32]byte) ([]byte, bool) {
if len(signedMessage) < Overhead {
return nil, false
}
if !ed25519.Verify(ed25519.PublicKey((*publicKey)[:]), signedMessage[Overhead:], signedMessage[:Overhead]) {
return nil, false
}
ret, out := sliceForAppend(out, len(signedMessage)-Overhead)
if alias.AnyOverlap(out, signedMessage) {
panic("nacl: invalid buffer overlap")
}
copy(out, signedMessage[Overhead:])
return ret, true
}
// sliceForAppend takes a slice and a requested number of bytes. It returns a
// slice with the contents of the given slice followed by that many bytes and a
// second slice that aliases into it and contains only the extra bytes. If the
// original slice has sufficient capacity then no allocation is performed.
func sliceForAppend(in []byte, n int) (head, tail []byte) {
if total := len(in) + n; cap(in) >= total {
head = in[:total]
} else {
head = make([]byte, total)
copy(head, in)
}
tail = head[len(in):]
return
}
// Copyright 2010 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 armor implements OpenPGP ASCII Armor, see RFC 4880. OpenPGP Armor is
// very similar to PEM except that it has an additional CRC checksum.
//
// Deprecated: this package is unmaintained except for security fixes. New
// applications should consider a more focused, modern alternative to OpenPGP
// for their specific task. If you are required to interoperate with OpenPGP
// systems and need a maintained package, consider a community fork.
// See https://golang.org/issue/44226.
package armor
import (
"bufio"
"bytes"
"encoding/base64"
"io"
"golang.org/x/crypto/openpgp/errors"
)
// A Block represents an OpenPGP armored structure.
//
// The encoded form is:
//
// -----BEGIN Type-----
// Headers
//
// base64-encoded Bytes
// '=' base64 encoded checksum
// -----END Type-----
//
// where Headers is a possibly empty sequence of Key: Value lines.
//
// Since the armored data can be very large, this package presents a streaming
// interface.
type Block struct {
Type string // The type, taken from the preamble (i.e. "PGP SIGNATURE").
Header map[string]string // Optional headers.
Body io.Reader // A Reader from which the contents can be read
lReader lineReader
oReader openpgpReader
}
var ArmorCorrupt error = errors.StructuralError("armor invalid")
const crc24Init = 0xb704ce
const crc24Poly = 0x1864cfb
const crc24Mask = 0xffffff
// crc24 calculates the OpenPGP checksum as specified in RFC 4880, section 6.1
func crc24(crc uint32, d []byte) uint32 {
for _, b := range d {
crc ^= uint32(b) << 16
for i := 0; i < 8; i++ {
crc <<= 1
if crc&0x1000000 != 0 {
crc ^= crc24Poly
}
}
}
return crc
}
var armorStart = []byte("-----BEGIN ")
var armorEnd = []byte("-----END ")
var armorEndOfLine = []byte("-----")
// lineReader wraps a line based reader. It watches for the end of an armor
// block and records the expected CRC value.
type lineReader struct {
in *bufio.Reader
buf []byte
eof bool
crc uint32
crcSet bool
}
func (l *lineReader) Read(p []byte) (n int, err error) {
if l.eof {
return 0, io.EOF
}
if len(l.buf) > 0 {
n = copy(p, l.buf)
l.buf = l.buf[n:]
return
}
line, isPrefix, err := l.in.ReadLine()
if err != nil {
return
}
if isPrefix {
return 0, ArmorCorrupt
}
if bytes.HasPrefix(line, armorEnd) {
l.eof = true
return 0, io.EOF
}
if len(line) == 5 && line[0] == '=' {
// This is the checksum line
var expectedBytes [3]byte
var m int
m, err = base64.StdEncoding.Decode(expectedBytes[0:], line[1:])
if m != 3 || err != nil {
return
}
l.crc = uint32(expectedBytes[0])<<16 |
uint32(expectedBytes[1])<<8 |
uint32(expectedBytes[2])
line, _, err = l.in.ReadLine()
if err != nil && err != io.EOF {
return
}
if !bytes.HasPrefix(line, armorEnd) {
return 0, ArmorCorrupt
}
l.eof = true
l.crcSet = true
return 0, io.EOF
}
if len(line) > 96 {
return 0, ArmorCorrupt
}
n = copy(p, line)
bytesToSave := len(line) - n
if bytesToSave > 0 {
if cap(l.buf) < bytesToSave {
l.buf = make([]byte, 0, bytesToSave)
}
l.buf = l.buf[0:bytesToSave]
copy(l.buf, line[n:])
}
return
}
// openpgpReader passes Read calls to the underlying base64 decoder, but keeps
// a running CRC of the resulting data and checks the CRC against the value
// found by the lineReader at EOF.
type openpgpReader struct {
lReader *lineReader
b64Reader io.Reader
currentCRC uint32
}
func (r *openpgpReader) Read(p []byte) (n int, err error) {
n, err = r.b64Reader.Read(p)
r.currentCRC = crc24(r.currentCRC, p[:n])
if err == io.EOF && r.lReader.crcSet && r.lReader.crc != r.currentCRC&crc24Mask {
return 0, ArmorCorrupt
}
return
}
// Decode reads a PGP armored block from the given Reader. It will ignore
// leading garbage. If it doesn't find a block, it will return nil, io.EOF. The
// given Reader is not usable after calling this function: an arbitrary amount
// of data may have been read past the end of the block.
func Decode(in io.Reader) (p *Block, err error) {
r := bufio.NewReaderSize(in, 100)
var line []byte
ignoreNext := false
TryNextBlock:
p = nil
// Skip leading garbage
for {
ignoreThis := ignoreNext
line, ignoreNext, err = r.ReadLine()
if err != nil {
return
}
if ignoreNext || ignoreThis {
continue
}
line = bytes.TrimSpace(line)
if len(line) > len(armorStart)+len(armorEndOfLine) && bytes.HasPrefix(line, armorStart) {
break
}
}
p = new(Block)
p.Type = string(line[len(armorStart) : len(line)-len(armorEndOfLine)])
p.Header = make(map[string]string)
nextIsContinuation := false
var lastKey string
// Read headers
for {
isContinuation := nextIsContinuation
line, nextIsContinuation, err = r.ReadLine()
if err != nil {
p = nil
return
}
if isContinuation {
p.Header[lastKey] += string(line)
continue
}
line = bytes.TrimSpace(line)
if len(line) == 0 {
break
}
i := bytes.Index(line, []byte(": "))
if i == -1 {
goto TryNextBlock
}
lastKey = string(line[:i])
p.Header[lastKey] = string(line[i+2:])
}
p.lReader.in = r
p.oReader.currentCRC = crc24Init
p.oReader.lReader = &p.lReader
p.oReader.b64Reader = base64.NewDecoder(base64.StdEncoding, &p.lReader)
p.Body = &p.oReader
return
}
// Copyright 2010 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 armor
import (
"encoding/base64"
"io"
)
var armorHeaderSep = []byte(": ")
var blockEnd = []byte("\n=")
var newline = []byte("\n")
var armorEndOfLineOut = []byte("-----\n")
// writeSlices writes its arguments to the given Writer.
func writeSlices(out io.Writer, slices ...[]byte) (err error) {
for _, s := range slices {
_, err = out.Write(s)
if err != nil {
return err
}
}
return
}
// lineBreaker breaks data across several lines, all of the same byte length
// (except possibly the last). Lines are broken with a single '\n'.
type lineBreaker struct {
lineLength int
line []byte
used int
out io.Writer
haveWritten bool
}
func newLineBreaker(out io.Writer, lineLength int) *lineBreaker {
return &lineBreaker{
lineLength: lineLength,
line: make([]byte, lineLength),
used: 0,
out: out,
}
}
func (l *lineBreaker) Write(b []byte) (n int, err error) {
n = len(b)
if n == 0 {
return
}
if l.used == 0 && l.haveWritten {
_, err = l.out.Write([]byte{'\n'})
if err != nil {
return
}
}
if l.used+len(b) < l.lineLength {
l.used += copy(l.line[l.used:], b)
return
}
l.haveWritten = true
_, err = l.out.Write(l.line[0:l.used])
if err != nil {
return
}
excess := l.lineLength - l.used
l.used = 0
_, err = l.out.Write(b[0:excess])
if err != nil {
return
}
_, err = l.Write(b[excess:])
return
}
func (l *lineBreaker) Close() (err error) {
if l.used > 0 {
_, err = l.out.Write(l.line[0:l.used])
if err != nil {
return
}
}
return
}
// encoding keeps track of a running CRC24 over the data which has been written
// to it and outputs a OpenPGP checksum when closed, followed by an armor
// trailer.
//
// It's built into a stack of io.Writers:
//
// encoding -> base64 encoder -> lineBreaker -> out
type encoding struct {
out io.Writer
breaker *lineBreaker
b64 io.WriteCloser
crc uint32
blockType []byte
}
func (e *encoding) Write(data []byte) (n int, err error) {
e.crc = crc24(e.crc, data)
return e.b64.Write(data)
}
func (e *encoding) Close() (err error) {
err = e.b64.Close()
if err != nil {
return
}
e.breaker.Close()
var checksumBytes [3]byte
checksumBytes[0] = byte(e.crc >> 16)
checksumBytes[1] = byte(e.crc >> 8)
checksumBytes[2] = byte(e.crc)
var b64ChecksumBytes [4]byte
base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:])
return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine)
}
// Encode returns a WriteCloser which will encode the data written to it in
// OpenPGP armor.
func Encode(out io.Writer, blockType string, headers map[string]string) (w io.WriteCloser, err error) {
bType := []byte(blockType)
err = writeSlices(out, armorStart, bType, armorEndOfLineOut)
if err != nil {
return
}
for k, v := range headers {
err = writeSlices(out, []byte(k), armorHeaderSep, []byte(v), newline)
if err != nil {
return
}
}
_, err = out.Write(newline)
if err != nil {
return
}
e := &encoding{
out: out,
breaker: newLineBreaker(out, 64),
crc: crc24Init,
blockType: bType,
}
e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker)
return e, nil
}
// Copyright 2011 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 openpgp
import "hash"
// NewCanonicalTextHash reformats text written to it into the canonical
// form and then applies the hash h. See RFC 4880, section 5.2.1.
func NewCanonicalTextHash(h hash.Hash) hash.Hash {
return &canonicalTextHash{h, 0}
}
type canonicalTextHash struct {
h hash.Hash
s int
}
var newline = []byte{'\r', '\n'}
func (cth *canonicalTextHash) Write(buf []byte) (int, error) {
start := 0
for i, c := range buf {
switch cth.s {
case 0:
if c == '\r' {
cth.s = 1
} else if c == '\n' {
cth.h.Write(buf[start:i])
cth.h.Write(newline)
start = i + 1
}
case 1:
cth.s = 0
}
}
cth.h.Write(buf[start:])
return len(buf), nil
}
func (cth *canonicalTextHash) Sum(in []byte) []byte {
return cth.h.Sum(in)
}
func (cth *canonicalTextHash) Reset() {
cth.h.Reset()
cth.s = 0
}
func (cth *canonicalTextHash) Size() int {
return cth.h.Size()
}
func (cth *canonicalTextHash) BlockSize() int {
return cth.h.BlockSize()
}
// 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.
// Package clearsign generates and processes OpenPGP, clear-signed data. See
// RFC 4880, section 7.
//
// Clearsigned messages are cryptographically signed, but the contents of the
// message are kept in plaintext so that it can be read without special tools.
//
// Deprecated: this package is unmaintained except for security fixes. New
// applications should consider a more focused, modern alternative to OpenPGP
// for their specific task. If you are required to interoperate with OpenPGP
// systems and need a maintained package, consider a community fork.
// See https://golang.org/issue/44226.
package clearsign
import (
"bufio"
"bytes"
"crypto"
"fmt"
"hash"
"io"
"net/textproto"
"strconv"
"strings"
"golang.org/x/crypto/openpgp/armor"
"golang.org/x/crypto/openpgp/errors"
"golang.org/x/crypto/openpgp/packet"
)
// A Block represents a clearsigned message. A signature on a Block can
// be checked by passing Bytes into openpgp.CheckDetachedSignature.
type Block struct {
Headers textproto.MIMEHeader // Optional unverified Hash headers
Plaintext []byte // The original message text
Bytes []byte // The signed message
ArmoredSignature *armor.Block // The signature block
}
// start is the marker which denotes the beginning of a clearsigned message.
var start = []byte("\n-----BEGIN PGP SIGNED MESSAGE-----")
// dashEscape is prefixed to any lines that begin with a hyphen so that they
// can't be confused with endText.
var dashEscape = []byte("- ")
// endText is a marker which denotes the end of the message and the start of
// an armored signature.
var endText = []byte("-----BEGIN PGP SIGNATURE-----")
// end is a marker which denotes the end of the armored signature.
var end = []byte("\n-----END PGP SIGNATURE-----")
var crlf = []byte("\r\n")
var lf = byte('\n')
// getLine returns the first \r\n or \n delineated line from the given byte
// array. The line does not include the \r\n or \n. The remainder of the byte
// array (also not including the new line bytes) is also returned and this will
// always be smaller than the original argument.
func getLine(data []byte) (line, rest []byte) {
i := bytes.Index(data, []byte{'\n'})
var j int
if i < 0 {
i = len(data)
j = i
} else {
j = i + 1
if i > 0 && data[i-1] == '\r' {
i--
}
}
return data[0:i], data[j:]
}
// Decode finds the first clearsigned message in data and returns it, as well as
// the suffix of data which remains after the message. Any prefix data is
// discarded.
//
// If no message is found, or if the message is invalid, Decode returns nil and
// the whole data slice. The only allowed header type is Hash, and it is not
// verified against the signature hash.
func Decode(data []byte) (b *Block, rest []byte) {
// start begins with a newline. However, at the very beginning of
// the byte array, we'll accept the start string without it.
rest = data
if bytes.HasPrefix(data, start[1:]) {
rest = rest[len(start)-1:]
} else if i := bytes.Index(data, start); i >= 0 {
rest = rest[i+len(start):]
} else {
return nil, data
}
// Consume the start line and check it does not have a suffix.
suffix, rest := getLine(rest)
if len(suffix) != 0 {
return nil, data
}
var line []byte
b = &Block{
Headers: make(textproto.MIMEHeader),
}
// Next come a series of header lines.
for {
// This loop terminates because getLine's second result is
// always smaller than its argument.
if len(rest) == 0 {
return nil, data
}
// An empty line marks the end of the headers.
if line, rest = getLine(rest); len(line) == 0 {
break
}
// Reject headers with control or Unicode characters.
if i := bytes.IndexFunc(line, func(r rune) bool {
return r < 0x20 || r > 0x7e
}); i != -1 {
return nil, data
}
i := bytes.Index(line, []byte{':'})
if i == -1 {
return nil, data
}
key, val := string(line[0:i]), string(line[i+1:])
key = strings.TrimSpace(key)
if key != "Hash" {
return nil, data
}
val = strings.TrimSpace(val)
b.Headers.Add(key, val)
}
firstLine := true
for {
start := rest
line, rest = getLine(rest)
if len(line) == 0 && len(rest) == 0 {
// No armored data was found, so this isn't a complete message.
return nil, data
}
if bytes.Equal(line, endText) {
// Back up to the start of the line because armor expects to see the
// header line.
rest = start
break
}
// The final CRLF isn't included in the hash so we don't write it until
// we've seen the next line.
if firstLine {
firstLine = false
} else {
b.Bytes = append(b.Bytes, crlf...)
}
if bytes.HasPrefix(line, dashEscape) {
line = line[2:]
}
line = bytes.TrimRight(line, " \t")
b.Bytes = append(b.Bytes, line...)
b.Plaintext = append(b.Plaintext, line...)
b.Plaintext = append(b.Plaintext, lf)
}
// We want to find the extent of the armored data (including any newlines at
// the end).
i := bytes.Index(rest, end)
if i == -1 {
return nil, data
}
i += len(end)
for i < len(rest) && (rest[i] == '\r' || rest[i] == '\n') {
i++
}
armored := rest[:i]
rest = rest[i:]
var err error
b.ArmoredSignature, err = armor.Decode(bytes.NewBuffer(armored))
if err != nil {
return nil, data
}
return b, rest
}
// A dashEscaper is an io.WriteCloser which processes the body of a clear-signed
// message. The clear-signed message is written to buffered and a hash, suitable
// for signing, is maintained in h.
//
// When closed, an armored signature is created and written to complete the
// message.
type dashEscaper struct {
buffered *bufio.Writer
hashers []hash.Hash // one per key in privateKeys
hashType crypto.Hash
toHash io.Writer // writes to all the hashes in hashers
atBeginningOfLine bool
isFirstLine bool
whitespace []byte
byteBuf []byte // a one byte buffer to save allocations
privateKeys []*packet.PrivateKey
config *packet.Config
}
func (d *dashEscaper) Write(data []byte) (n int, err error) {
for _, b := range data {
d.byteBuf[0] = b
if d.atBeginningOfLine {
// The final CRLF isn't included in the hash so we have to wait
// until this point (the start of the next line) before writing it.
if !d.isFirstLine {
d.toHash.Write(crlf)
}
d.isFirstLine = false
}
// Any whitespace at the end of the line has to be removed so we
// buffer it until we find out whether there's more on this line.
if b == ' ' || b == '\t' || b == '\r' {
d.whitespace = append(d.whitespace, b)
d.atBeginningOfLine = false
continue
}
if d.atBeginningOfLine {
// At the beginning of a line, hyphens have to be escaped.
if b == '-' {
// The signature isn't calculated over the dash-escaped text so
// the escape is only written to buffered.
if _, err = d.buffered.Write(dashEscape); err != nil {
return
}
d.toHash.Write(d.byteBuf)
d.atBeginningOfLine = false
} else if b == '\n' {
// Nothing to do because we delay writing CRLF to the hash.
} else {
d.toHash.Write(d.byteBuf)
d.atBeginningOfLine = false
}
if err = d.buffered.WriteByte(b); err != nil {
return
}
} else {
if b == '\n' {
// We got a raw \n. Drop any trailing whitespace and write a
// CRLF.
d.whitespace = d.whitespace[:0]
// We delay writing CRLF to the hash until the start of the
// next line.
if err = d.buffered.WriteByte(b); err != nil {
return
}
d.atBeginningOfLine = true
} else {
// Any buffered whitespace wasn't at the end of the line so
// we need to write it out.
if len(d.whitespace) > 0 {
d.toHash.Write(d.whitespace)
if _, err = d.buffered.Write(d.whitespace); err != nil {
return
}
d.whitespace = d.whitespace[:0]
}
d.toHash.Write(d.byteBuf)
if err = d.buffered.WriteByte(b); err != nil {
return
}
}
}
}
n = len(data)
return
}
func (d *dashEscaper) Close() (err error) {
if !d.atBeginningOfLine {
if err = d.buffered.WriteByte(lf); err != nil {
return
}
}
out, err := armor.Encode(d.buffered, "PGP SIGNATURE", nil)
if err != nil {
return
}
t := d.config.Now()
for i, k := range d.privateKeys {
sig := new(packet.Signature)
sig.SigType = packet.SigTypeText
sig.PubKeyAlgo = k.PubKeyAlgo
sig.Hash = d.hashType
sig.CreationTime = t
sig.IssuerKeyId = &k.KeyId
if err = sig.Sign(d.hashers[i], k, d.config); err != nil {
return
}
if err = sig.Serialize(out); err != nil {
return
}
}
if err = out.Close(); err != nil {
return
}
if err = d.buffered.Flush(); err != nil {
return
}
return
}
// Encode returns a WriteCloser which will clear-sign a message with privateKey
// and write it to w. If config is nil, sensible defaults are used.
func Encode(w io.Writer, privateKey *packet.PrivateKey, config *packet.Config) (plaintext io.WriteCloser, err error) {
return EncodeMulti(w, []*packet.PrivateKey{privateKey}, config)
}
// EncodeMulti returns a WriteCloser which will clear-sign a message with all the
// private keys indicated and write it to w. If config is nil, sensible defaults
// are used.
func EncodeMulti(w io.Writer, privateKeys []*packet.PrivateKey, config *packet.Config) (plaintext io.WriteCloser, err error) {
for _, k := range privateKeys {
if k.Encrypted {
return nil, errors.InvalidArgumentError(fmt.Sprintf("signing key %s is encrypted", k.KeyIdString()))
}
}
hashType := config.Hash()
name := nameOfHash(hashType)
if len(name) == 0 {
return nil, errors.UnsupportedError("unknown hash type: " + strconv.Itoa(int(hashType)))
}
if !hashType.Available() {
return nil, errors.UnsupportedError("unsupported hash type: " + strconv.Itoa(int(hashType)))
}
var hashers []hash.Hash
var ws []io.Writer
for range privateKeys {
h := hashType.New()
hashers = append(hashers, h)
ws = append(ws, h)
}
toHash := io.MultiWriter(ws...)
buffered := bufio.NewWriter(w)
// start has a \n at the beginning that we don't want here.
if _, err = buffered.Write(start[1:]); err != nil {
return
}
if err = buffered.WriteByte(lf); err != nil {
return
}
if _, err = buffered.WriteString("Hash: "); err != nil {
return
}
if _, err = buffered.WriteString(name); err != nil {
return
}
if err = buffered.WriteByte(lf); err != nil {
return
}
if err = buffered.WriteByte(lf); err != nil {
return
}
plaintext = &dashEscaper{
buffered: buffered,
hashers: hashers,
hashType: hashType,
toHash: toHash,
atBeginningOfLine: true,
isFirstLine: true,
byteBuf: make([]byte, 1),
privateKeys: privateKeys,
config: config,
}
return
}
// nameOfHash returns the OpenPGP name for the given hash, or the empty string
// if the name isn't known. See RFC 4880, section 9.4.
func nameOfHash(h crypto.Hash) string {
switch h {
case crypto.MD5:
return "MD5"
case crypto.SHA1:
return "SHA1"
case crypto.RIPEMD160:
return "RIPEMD160"
case crypto.SHA224:
return "SHA224"
case crypto.SHA256:
return "SHA256"
case crypto.SHA384:
return "SHA384"
case crypto.SHA512:
return "SHA512"
}
return ""
}
// Copyright 2011 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 elgamal implements ElGamal encryption, suitable for OpenPGP,
// as specified in "A Public-Key Cryptosystem and a Signature Scheme Based on
// Discrete Logarithms," IEEE Transactions on Information Theory, v. IT-31,
// n. 4, 1985, pp. 469-472.
//
// This form of ElGamal embeds PKCS#1 v1.5 padding, which may make it
// unsuitable for other protocols. RSA should be used in preference in any
// case.
//
// Deprecated: this package was only provided to support ElGamal encryption in
// OpenPGP. The golang.org/x/crypto/openpgp package is now deprecated (see
// https://golang.org/issue/44226), and ElGamal in the OpenPGP ecosystem has
// compatibility and security issues (see https://eprint.iacr.org/2021/923).
// Moreover, this package doesn't protect against side-channel attacks.
package elgamal
import (
"crypto/rand"
"crypto/subtle"
"errors"
"io"
"math/big"
)
// PublicKey represents an ElGamal public key.
type PublicKey struct {
G, P, Y *big.Int
}
// PrivateKey represents an ElGamal private key.
type PrivateKey struct {
PublicKey
X *big.Int
}
// Encrypt encrypts the given message to the given public key. The result is a
// pair of integers. Errors can result from reading random, or because msg is
// too large to be encrypted to the public key.
func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err error) {
pLen := (pub.P.BitLen() + 7) / 8
if len(msg) > pLen-11 {
err = errors.New("elgamal: message too long")
return
}
// EM = 0x02 || PS || 0x00 || M
em := make([]byte, pLen-1)
em[0] = 2
ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):]
err = nonZeroRandomBytes(ps, random)
if err != nil {
return
}
em[len(em)-len(msg)-1] = 0
copy(mm, msg)
m := new(big.Int).SetBytes(em)
k, err := rand.Int(random, pub.P)
if err != nil {
return
}
c1 = new(big.Int).Exp(pub.G, k, pub.P)
s := new(big.Int).Exp(pub.Y, k, pub.P)
c2 = s.Mul(s, m)
c2.Mod(c2, pub.P)
return
}
// Decrypt takes two integers, resulting from an ElGamal encryption, and
// returns the plaintext of the message. An error can result only if the
// ciphertext is invalid. Users should keep in mind that this is a padding
// oracle and thus, if exposed to an adaptive chosen ciphertext attack, can
// be used to break the cryptosystem. See “Chosen Ciphertext Attacks
// Against Protocols Based on the RSA Encryption Standard PKCS #1”, Daniel
// Bleichenbacher, Advances in Cryptology (Crypto '98),
func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) {
s := new(big.Int).Exp(c1, priv.X, priv.P)
if s.ModInverse(s, priv.P) == nil {
return nil, errors.New("elgamal: invalid private key")
}
s.Mul(s, c2)
s.Mod(s, priv.P)
em := s.Bytes()
firstByteIsTwo := subtle.ConstantTimeByteEq(em[0], 2)
// The remainder of the plaintext must be a string of non-zero random
// octets, followed by a 0, followed by the message.
// lookingForIndex: 1 iff we are still looking for the zero.
// index: the offset of the first zero byte.
var lookingForIndex, index int
lookingForIndex = 1
for i := 1; i < len(em); i++ {
equals0 := subtle.ConstantTimeByteEq(em[i], 0)
index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index)
lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex)
}
if firstByteIsTwo != 1 || lookingForIndex != 0 || index < 9 {
return nil, errors.New("elgamal: decryption error")
}
return em[index+1:], nil
}
// nonZeroRandomBytes fills the given slice with non-zero random octets.
func nonZeroRandomBytes(s []byte, rand io.Reader) (err error) {
_, err = io.ReadFull(rand, s)
if err != nil {
return
}
for i := 0; i < len(s); i++ {
for s[i] == 0 {
_, err = io.ReadFull(rand, s[i:i+1])
if err != nil {
return
}
}
}
return
}
// Copyright 2010 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 errors contains common error types for the OpenPGP packages.
//
// Deprecated: this package is unmaintained except for security fixes. New
// applications should consider a more focused, modern alternative to OpenPGP
// for their specific task. If you are required to interoperate with OpenPGP
// systems and need a maintained package, consider a community fork.
// See https://golang.org/issue/44226.
package errors
import (
"strconv"
)
// A StructuralError is returned when OpenPGP data is found to be syntactically
// invalid.
type StructuralError string
func (s StructuralError) Error() string {
return "openpgp: invalid data: " + string(s)
}
// UnsupportedError indicates that, although the OpenPGP data is valid, it
// makes use of currently unimplemented features.
type UnsupportedError string
func (s UnsupportedError) Error() string {
return "openpgp: unsupported feature: " + string(s)
}
// InvalidArgumentError indicates that the caller is in error and passed an
// incorrect value.
type InvalidArgumentError string
func (i InvalidArgumentError) Error() string {
return "openpgp: invalid argument: " + string(i)
}
// SignatureError indicates that a syntactically valid signature failed to
// validate.
type SignatureError string
func (b SignatureError) Error() string {
return "openpgp: invalid signature: " + string(b)
}
type keyIncorrectError int
func (ki keyIncorrectError) Error() string {
return "openpgp: incorrect key"
}
var ErrKeyIncorrect error = keyIncorrectError(0)
type unknownIssuerError int
func (unknownIssuerError) Error() string {
return "openpgp: signature made by unknown entity"
}
var ErrUnknownIssuer error = unknownIssuerError(0)
type keyRevokedError int
func (keyRevokedError) Error() string {
return "openpgp: signature made by revoked key"
}
var ErrKeyRevoked error = keyRevokedError(0)
type UnknownPacketTypeError uint8
func (upte UnknownPacketTypeError) Error() string {
return "openpgp: unknown packet type: " + strconv.Itoa(int(upte))
}
// Copyright 2011 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 openpgp
import (
"crypto/rsa"
"io"
"time"
"golang.org/x/crypto/openpgp/armor"
"golang.org/x/crypto/openpgp/errors"
"golang.org/x/crypto/openpgp/packet"
)
// PublicKeyType is the armor type for a PGP public key.
var PublicKeyType = "PGP PUBLIC KEY BLOCK"
// PrivateKeyType is the armor type for a PGP private key.
var PrivateKeyType = "PGP PRIVATE KEY BLOCK"
// An Entity represents the components of an OpenPGP key: a primary public key
// (which must be a signing key), one or more identities claimed by that key,
// and zero or more subkeys, which may be encryption keys.
type Entity struct {
PrimaryKey *packet.PublicKey
PrivateKey *packet.PrivateKey
Identities map[string]*Identity // indexed by Identity.Name
Revocations []*packet.Signature
Subkeys []Subkey
}
// An Identity represents an identity claimed by an Entity and zero or more
// assertions by other entities about that claim.
type Identity struct {
Name string // by convention, has the form "Full Name (comment) <email@example.com>"
UserId *packet.UserId
SelfSignature *packet.Signature
Signatures []*packet.Signature
}
// A Subkey is an additional public key in an Entity. Subkeys can be used for
// encryption.
type Subkey struct {
PublicKey *packet.PublicKey
PrivateKey *packet.PrivateKey
Sig *packet.Signature
}
// A Key identifies a specific public key in an Entity. This is either the
// Entity's primary key or a subkey.
type Key struct {
Entity *Entity
PublicKey *packet.PublicKey
PrivateKey *packet.PrivateKey
SelfSignature *packet.Signature
}
// A KeyRing provides access to public and private keys.
type KeyRing interface {
// KeysById returns the set of keys that have the given key id.
KeysById(id uint64) []Key
// KeysByIdUsage returns the set of keys with the given id
// that also meet the key usage given by requiredUsage.
// The requiredUsage is expressed as the bitwise-OR of
// packet.KeyFlag* values.
KeysByIdUsage(id uint64, requiredUsage byte) []Key
// DecryptionKeys returns all private keys that are valid for
// decryption.
DecryptionKeys() []Key
}
// primaryIdentity returns the Identity marked as primary or the first identity
// if none are so marked.
func (e *Entity) primaryIdentity() *Identity {
var firstIdentity *Identity
for _, ident := range e.Identities {
if firstIdentity == nil {
firstIdentity = ident
}
if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId {
return ident
}
}
return firstIdentity
}
// encryptionKey returns the best candidate Key for encrypting a message to the
// given Entity.
func (e *Entity) encryptionKey(now time.Time) (Key, bool) {
candidateSubkey := -1
// Iterate the keys to find the newest key
var maxTime time.Time
for i, subkey := range e.Subkeys {
if subkey.Sig.FlagsValid &&
subkey.Sig.FlagEncryptCommunications &&
subkey.PublicKey.PubKeyAlgo.CanEncrypt() &&
!subkey.Sig.KeyExpired(now) &&
(maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) {
candidateSubkey = i
maxTime = subkey.Sig.CreationTime
}
}
if candidateSubkey != -1 {
subkey := e.Subkeys[candidateSubkey]
return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}, true
}
// If we don't have any candidate subkeys for encryption and
// the primary key doesn't have any usage metadata then we
// assume that the primary key is ok. Or, if the primary key is
// marked as ok to encrypt to, then we can obviously use it.
i := e.primaryIdentity()
if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications &&
e.PrimaryKey.PubKeyAlgo.CanEncrypt() &&
!i.SelfSignature.KeyExpired(now) {
return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}, true
}
// This Entity appears to be signing only.
return Key{}, false
}
// signingKey return the best candidate Key for signing a message with this
// Entity.
func (e *Entity) signingKey(now time.Time) (Key, bool) {
candidateSubkey := -1
for i, subkey := range e.Subkeys {
if subkey.Sig.FlagsValid &&
subkey.Sig.FlagSign &&
subkey.PublicKey.PubKeyAlgo.CanSign() &&
!subkey.Sig.KeyExpired(now) {
candidateSubkey = i
break
}
}
if candidateSubkey != -1 {
subkey := e.Subkeys[candidateSubkey]
return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}, true
}
// If we have no candidate subkey then we assume that it's ok to sign
// with the primary key.
i := e.primaryIdentity()
if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagSign &&
!i.SelfSignature.KeyExpired(now) {
return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}, true
}
return Key{}, false
}
// An EntityList contains one or more Entities.
type EntityList []*Entity
// KeysById returns the set of keys that have the given key id.
func (el EntityList) KeysById(id uint64) (keys []Key) {
for _, e := range el {
if e.PrimaryKey.KeyId == id {
var selfSig *packet.Signature
for _, ident := range e.Identities {
if selfSig == nil {
selfSig = ident.SelfSignature
} else if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId {
selfSig = ident.SelfSignature
break
}
}
keys = append(keys, Key{e, e.PrimaryKey, e.PrivateKey, selfSig})
}
for _, subKey := range e.Subkeys {
if subKey.PublicKey.KeyId == id {
keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig})
}
}
}
return
}
// KeysByIdUsage returns the set of keys with the given id that also meet
// the key usage given by requiredUsage. The requiredUsage is expressed as
// the bitwise-OR of packet.KeyFlag* values.
func (el EntityList) KeysByIdUsage(id uint64, requiredUsage byte) (keys []Key) {
for _, key := range el.KeysById(id) {
if len(key.Entity.Revocations) > 0 {
continue
}
if key.SelfSignature.RevocationReason != nil {
continue
}
if key.SelfSignature.FlagsValid && requiredUsage != 0 {
var usage byte
if key.SelfSignature.FlagCertify {
usage |= packet.KeyFlagCertify
}
if key.SelfSignature.FlagSign {
usage |= packet.KeyFlagSign
}
if key.SelfSignature.FlagEncryptCommunications {
usage |= packet.KeyFlagEncryptCommunications
}
if key.SelfSignature.FlagEncryptStorage {
usage |= packet.KeyFlagEncryptStorage
}
if usage&requiredUsage != requiredUsage {
continue
}
}
keys = append(keys, key)
}
return
}
// DecryptionKeys returns all private keys that are valid for decryption.
func (el EntityList) DecryptionKeys() (keys []Key) {
for _, e := range el {
for _, subKey := range e.Subkeys {
if subKey.PrivateKey != nil && (!subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications) {
keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig})
}
}
}
return
}
// ReadArmoredKeyRing reads one or more public/private keys from an armor keyring file.
func ReadArmoredKeyRing(r io.Reader) (EntityList, error) {
block, err := armor.Decode(r)
if err == io.EOF {
return nil, errors.InvalidArgumentError("no armored data found")
}
if err != nil {
return nil, err
}
if block.Type != PublicKeyType && block.Type != PrivateKeyType {
return nil, errors.InvalidArgumentError("expected public or private key block, got: " + block.Type)
}
return ReadKeyRing(block.Body)
}
// ReadKeyRing reads one or more public/private keys. Unsupported keys are
// ignored as long as at least a single valid key is found.
func ReadKeyRing(r io.Reader) (el EntityList, err error) {
packets := packet.NewReader(r)
var lastUnsupportedError error
for {
var e *Entity
e, err = ReadEntity(packets)
if err != nil {
// TODO: warn about skipped unsupported/unreadable keys
if _, ok := err.(errors.UnsupportedError); ok {
lastUnsupportedError = err
err = readToNextPublicKey(packets)
} else if _, ok := err.(errors.StructuralError); ok {
// Skip unreadable, badly-formatted keys
lastUnsupportedError = err
err = readToNextPublicKey(packets)
}
if err == io.EOF {
err = nil
break
}
if err != nil {
el = nil
break
}
} else {
el = append(el, e)
}
}
if len(el) == 0 && err == nil {
err = lastUnsupportedError
}
return
}
// readToNextPublicKey reads packets until the start of the entity and leaves
// the first packet of the new entity in the Reader.
func readToNextPublicKey(packets *packet.Reader) (err error) {
var p packet.Packet
for {
p, err = packets.Next()
if err == io.EOF {
return
} else if err != nil {
if _, ok := err.(errors.UnsupportedError); ok {
err = nil
continue
}
return
}
if pk, ok := p.(*packet.PublicKey); ok && !pk.IsSubkey {
packets.Unread(p)
return
}
}
}
// ReadEntity reads an entity (public key, identities, subkeys etc) from the
// given Reader.
func ReadEntity(packets *packet.Reader) (*Entity, error) {
e := new(Entity)
e.Identities = make(map[string]*Identity)
p, err := packets.Next()
if err != nil {
return nil, err
}
var ok bool
if e.PrimaryKey, ok = p.(*packet.PublicKey); !ok {
if e.PrivateKey, ok = p.(*packet.PrivateKey); !ok {
packets.Unread(p)
return nil, errors.StructuralError("first packet was not a public/private key")
}
e.PrimaryKey = &e.PrivateKey.PublicKey
}
if !e.PrimaryKey.PubKeyAlgo.CanSign() {
return nil, errors.StructuralError("primary key cannot be used for signatures")
}
var revocations []*packet.Signature
EachPacket:
for {
p, err := packets.Next()
if err == io.EOF {
break
} else if err != nil {
return nil, err
}
switch pkt := p.(type) {
case *packet.UserId:
if err := addUserID(e, packets, pkt); err != nil {
return nil, err
}
case *packet.Signature:
if pkt.SigType == packet.SigTypeKeyRevocation {
revocations = append(revocations, pkt)
} else if pkt.SigType == packet.SigTypeDirectSignature {
// TODO: RFC4880 5.2.1 permits signatures
// directly on keys (eg. to bind additional
// revocation keys).
}
// Else, ignoring the signature as it does not follow anything
// we would know to attach it to.
case *packet.PrivateKey:
if pkt.IsSubkey == false {
packets.Unread(p)
break EachPacket
}
err = addSubkey(e, packets, &pkt.PublicKey, pkt)
if err != nil {
return nil, err
}
case *packet.PublicKey:
if pkt.IsSubkey == false {
packets.Unread(p)
break EachPacket
}
err = addSubkey(e, packets, pkt, nil)
if err != nil {
return nil, err
}
default:
// we ignore unknown packets
}
}
if len(e.Identities) == 0 {
return nil, errors.StructuralError("entity without any identities")
}
for _, revocation := range revocations {
err = e.PrimaryKey.VerifyRevocationSignature(revocation)
if err == nil {
e.Revocations = append(e.Revocations, revocation)
} else {
// TODO: RFC 4880 5.2.3.15 defines revocation keys.
return nil, errors.StructuralError("revocation signature signed by alternate key")
}
}
return e, nil
}
func addUserID(e *Entity, packets *packet.Reader, pkt *packet.UserId) error {
// Make a new Identity object, that we might wind up throwing away.
// We'll only add it if we get a valid self-signature over this
// userID.
identity := new(Identity)
identity.Name = pkt.Id
identity.UserId = pkt
for {
p, err := packets.Next()
if err == io.EOF {
break
} else if err != nil {
return err
}
sig, ok := p.(*packet.Signature)
if !ok {
packets.Unread(p)
break
}
if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId {
if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil {
return errors.StructuralError("user ID self-signature invalid: " + err.Error())
}
identity.SelfSignature = sig
e.Identities[pkt.Id] = identity
} else {
identity.Signatures = append(identity.Signatures, sig)
}
}
return nil
}
func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error {
var subKey Subkey
subKey.PublicKey = pub
subKey.PrivateKey = priv
for {
p, err := packets.Next()
if err == io.EOF {
break
} else if err != nil {
return errors.StructuralError("subkey signature invalid: " + err.Error())
}
sig, ok := p.(*packet.Signature)
if !ok {
packets.Unread(p)
break
}
if sig.SigType != packet.SigTypeSubkeyBinding && sig.SigType != packet.SigTypeSubkeyRevocation {
return errors.StructuralError("subkey signature with wrong type")
}
if err := e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, sig); err != nil {
return errors.StructuralError("subkey signature invalid: " + err.Error())
}
switch sig.SigType {
case packet.SigTypeSubkeyRevocation:
subKey.Sig = sig
case packet.SigTypeSubkeyBinding:
if shouldReplaceSubkeySig(subKey.Sig, sig) {
subKey.Sig = sig
}
}
}
if subKey.Sig == nil {
return errors.StructuralError("subkey packet not followed by signature")
}
e.Subkeys = append(e.Subkeys, subKey)
return nil
}
func shouldReplaceSubkeySig(existingSig, potentialNewSig *packet.Signature) bool {
if potentialNewSig == nil {
return false
}
if existingSig == nil {
return true
}
if existingSig.SigType == packet.SigTypeSubkeyRevocation {
return false // never override a revocation signature
}
return potentialNewSig.CreationTime.After(existingSig.CreationTime)
}
const defaultRSAKeyBits = 2048
// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a
// single identity composed of the given full name, comment and email, any of
// which may be empty but must not contain any of "()<>\x00".
// If config is nil, sensible defaults will be used.
func NewEntity(name, comment, email string, config *packet.Config) (*Entity, error) {
creationTime := config.Now()
bits := defaultRSAKeyBits
if config != nil && config.RSABits != 0 {
bits = config.RSABits
}
uid := packet.NewUserId(name, comment, email)
if uid == nil {
return nil, errors.InvalidArgumentError("user id field contained invalid characters")
}
signingPriv, err := rsa.GenerateKey(config.Random(), bits)
if err != nil {
return nil, err
}
encryptingPriv, err := rsa.GenerateKey(config.Random(), bits)
if err != nil {
return nil, err
}
e := &Entity{
PrimaryKey: packet.NewRSAPublicKey(creationTime, &signingPriv.PublicKey),
PrivateKey: packet.NewRSAPrivateKey(creationTime, signingPriv),
Identities: make(map[string]*Identity),
}
isPrimaryId := true
e.Identities[uid.Id] = &Identity{
Name: uid.Id,
UserId: uid,
SelfSignature: &packet.Signature{
CreationTime: creationTime,
SigType: packet.SigTypePositiveCert,
PubKeyAlgo: packet.PubKeyAlgoRSA,
Hash: config.Hash(),
IsPrimaryId: &isPrimaryId,
FlagsValid: true,
FlagSign: true,
FlagCertify: true,
IssuerKeyId: &e.PrimaryKey.KeyId,
},
}
err = e.Identities[uid.Id].SelfSignature.SignUserId(uid.Id, e.PrimaryKey, e.PrivateKey, config)
if err != nil {
return nil, err
}
// If the user passes in a DefaultHash via packet.Config,
// set the PreferredHash for the SelfSignature.
if config != nil && config.DefaultHash != 0 {
e.Identities[uid.Id].SelfSignature.PreferredHash = []uint8{hashToHashId(config.DefaultHash)}
}
// Likewise for DefaultCipher.
if config != nil && config.DefaultCipher != 0 {
e.Identities[uid.Id].SelfSignature.PreferredSymmetric = []uint8{uint8(config.DefaultCipher)}
}
e.Subkeys = make([]Subkey, 1)
e.Subkeys[0] = Subkey{
PublicKey: packet.NewRSAPublicKey(creationTime, &encryptingPriv.PublicKey),
PrivateKey: packet.NewRSAPrivateKey(creationTime, encryptingPriv),
Sig: &packet.Signature{
CreationTime: creationTime,
SigType: packet.SigTypeSubkeyBinding,
PubKeyAlgo: packet.PubKeyAlgoRSA,
Hash: config.Hash(),
FlagsValid: true,
FlagEncryptStorage: true,
FlagEncryptCommunications: true,
IssuerKeyId: &e.PrimaryKey.KeyId,
},
}
e.Subkeys[0].PublicKey.IsSubkey = true
e.Subkeys[0].PrivateKey.IsSubkey = true
err = e.Subkeys[0].Sig.SignKey(e.Subkeys[0].PublicKey, e.PrivateKey, config)
if err != nil {
return nil, err
}
return e, nil
}
// SerializePrivate serializes an Entity, including private key material, but
// excluding signatures from other entities, to the given Writer.
// Identities and subkeys are re-signed in case they changed since NewEntry.
// If config is nil, sensible defaults will be used.
func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error) {
err = e.PrivateKey.Serialize(w)
if err != nil {
return
}
for _, ident := range e.Identities {
err = ident.UserId.Serialize(w)
if err != nil {
return
}
err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey, config)
if err != nil {
return
}
err = ident.SelfSignature.Serialize(w)
if err != nil {
return
}
}
for _, subkey := range e.Subkeys {
err = subkey.PrivateKey.Serialize(w)
if err != nil {
return
}
err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config)
if err != nil {
return
}
err = subkey.Sig.Serialize(w)
if err != nil {
return
}
}
return nil
}
// Serialize writes the public part of the given Entity to w, including
// signatures from other entities. No private key material will be output.
func (e *Entity) Serialize(w io.Writer) error {
err := e.PrimaryKey.Serialize(w)
if err != nil {
return err
}
for _, ident := range e.Identities {
err = ident.UserId.Serialize(w)
if err != nil {
return err
}
err = ident.SelfSignature.Serialize(w)
if err != nil {
return err
}
for _, sig := range ident.Signatures {
err = sig.Serialize(w)
if err != nil {
return err
}
}
}
for _, subkey := range e.Subkeys {
err = subkey.PublicKey.Serialize(w)
if err != nil {
return err
}
err = subkey.Sig.Serialize(w)
if err != nil {
return err
}
}
return nil
}
// SignIdentity adds a signature to e, from signer, attesting that identity is
// associated with e. The provided identity must already be an element of
// e.Identities and the private key of signer must have been decrypted if
// necessary.
// If config is nil, sensible defaults will be used.
func (e *Entity) SignIdentity(identity string, signer *Entity, config *packet.Config) error {
if signer.PrivateKey == nil {
return errors.InvalidArgumentError("signing Entity must have a private key")
}
if signer.PrivateKey.Encrypted {
return errors.InvalidArgumentError("signing Entity's private key must be decrypted")
}
ident, ok := e.Identities[identity]
if !ok {
return errors.InvalidArgumentError("given identity string not found in Entity")
}
sig := &packet.Signature{
SigType: packet.SigTypeGenericCert,
PubKeyAlgo: signer.PrivateKey.PubKeyAlgo,
Hash: config.Hash(),
CreationTime: config.Now(),
IssuerKeyId: &signer.PrivateKey.KeyId,
}
if err := sig.SignUserId(identity, e.PrimaryKey, signer.PrivateKey, config); err != nil {
return err
}
ident.Signatures = append(ident.Signatures, sig)
return nil
}
// Copyright 2011 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 packet
import (
"compress/bzip2"
"compress/flate"
"compress/zlib"
"golang.org/x/crypto/openpgp/errors"
"io"
"strconv"
)
// Compressed represents a compressed OpenPGP packet. The decompressed contents
// will contain more OpenPGP packets. See RFC 4880, section 5.6.
type Compressed struct {
Body io.Reader
}
const (
NoCompression = flate.NoCompression
BestSpeed = flate.BestSpeed
BestCompression = flate.BestCompression
DefaultCompression = flate.DefaultCompression
)
// CompressionConfig contains compressor configuration settings.
type CompressionConfig struct {
// Level is the compression level to use. It must be set to
// between -1 and 9, with -1 causing the compressor to use the
// default compression level, 0 causing the compressor to use
// no compression and 1 to 9 representing increasing (better,
// slower) compression levels. If Level is less than -1 or
// more then 9, a non-nil error will be returned during
// encryption. See the constants above for convenient common
// settings for Level.
Level int
}
func (c *Compressed) parse(r io.Reader) error {
var buf [1]byte
_, err := readFull(r, buf[:])
if err != nil {
return err
}
switch buf[0] {
case 1:
c.Body = flate.NewReader(r)
case 2:
c.Body, err = zlib.NewReader(r)
case 3:
c.Body = bzip2.NewReader(r)
default:
err = errors.UnsupportedError("unknown compression algorithm: " + strconv.Itoa(int(buf[0])))
}
return err
}
// compressedWriteCloser represents the serialized compression stream
// header and the compressor. Its Close() method ensures that both the
// compressor and serialized stream header are closed. Its Write()
// method writes to the compressor.
type compressedWriteCloser struct {
sh io.Closer // Stream Header
c io.WriteCloser // Compressor
}
func (cwc compressedWriteCloser) Write(p []byte) (int, error) {
return cwc.c.Write(p)
}
func (cwc compressedWriteCloser) Close() (err error) {
err = cwc.c.Close()
if err != nil {
return err
}
return cwc.sh.Close()
}
// SerializeCompressed serializes a compressed data packet to w and
// returns a WriteCloser to which the literal data packets themselves
// can be written and which MUST be closed on completion. If cc is
// nil, sensible defaults will be used to configure the compression
// algorithm.
func SerializeCompressed(w io.WriteCloser, algo CompressionAlgo, cc *CompressionConfig) (literaldata io.WriteCloser, err error) {
compressed, err := serializeStreamHeader(w, packetTypeCompressed)
if err != nil {
return
}
_, err = compressed.Write([]byte{uint8(algo)})
if err != nil {
return
}
level := DefaultCompression
if cc != nil {
level = cc.Level
}
var compressor io.WriteCloser
switch algo {
case CompressionZIP:
compressor, err = flate.NewWriter(compressed, level)
case CompressionZLIB:
compressor, err = zlib.NewWriterLevel(compressed, level)
default:
s := strconv.Itoa(int(algo))
err = errors.UnsupportedError("Unsupported compression algorithm: " + s)
}
if err != nil {
return
}
literaldata = compressedWriteCloser{compressed, compressor}
return
}
// 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.
package packet
import (
"crypto"
"crypto/rand"
"io"
"time"
)
// Config collects a number of parameters along with sensible defaults.
// A nil *Config is valid and results in all default values.
type Config struct {
// Rand provides the source of entropy.
// If nil, the crypto/rand Reader is used.
Rand io.Reader
// DefaultHash is the default hash function to be used.
// If zero, SHA-256 is used.
DefaultHash crypto.Hash
// DefaultCipher is the cipher to be used.
// If zero, AES-128 is used.
DefaultCipher CipherFunction
// Time returns the current time as the number of seconds since the
// epoch. If Time is nil, time.Now is used.
Time func() time.Time
// DefaultCompressionAlgo is the compression algorithm to be
// applied to the plaintext before encryption. If zero, no
// compression is done.
DefaultCompressionAlgo CompressionAlgo
// CompressionConfig configures the compression settings.
CompressionConfig *CompressionConfig
// S2KCount is only used for symmetric encryption. It
// determines the strength of the passphrase stretching when
// the said passphrase is hashed to produce a key. S2KCount
// should be between 1024 and 65011712, inclusive. If Config
// is nil or S2KCount is 0, the value 65536 used. Not all
// values in the above range can be represented. S2KCount will
// be rounded up to the next representable value if it cannot
// be encoded exactly. When set, it is strongly encrouraged to
// use a value that is at least 65536. See RFC 4880 Section
// 3.7.1.3.
S2KCount int
// RSABits is the number of bits in new RSA keys made with NewEntity.
// If zero, then 2048 bit keys are created.
RSABits int
}
func (c *Config) Random() io.Reader {
if c == nil || c.Rand == nil {
return rand.Reader
}
return c.Rand
}
func (c *Config) Hash() crypto.Hash {
if c == nil || uint(c.DefaultHash) == 0 {
return crypto.SHA256
}
return c.DefaultHash
}
func (c *Config) Cipher() CipherFunction {
if c == nil || uint8(c.DefaultCipher) == 0 {
return CipherAES128
}
return c.DefaultCipher
}
func (c *Config) Now() time.Time {
if c == nil || c.Time == nil {
return time.Now()
}
return c.Time()
}
func (c *Config) Compression() CompressionAlgo {
if c == nil {
return CompressionNone
}
return c.DefaultCompressionAlgo
}
func (c *Config) PasswordHashIterations() int {
if c == nil || c.S2KCount == 0 {
return 0
}
return c.S2KCount
}
// Copyright 2011 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 packet
import (
"crypto"
"crypto/rsa"
"encoding/binary"
"io"
"math/big"
"strconv"
"golang.org/x/crypto/openpgp/elgamal"
"golang.org/x/crypto/openpgp/errors"
)
const encryptedKeyVersion = 3
// EncryptedKey represents a public-key encrypted session key. See RFC 4880,
// section 5.1.
type EncryptedKey struct {
KeyId uint64
Algo PublicKeyAlgorithm
CipherFunc CipherFunction // only valid after a successful Decrypt
Key []byte // only valid after a successful Decrypt
encryptedMPI1, encryptedMPI2 parsedMPI
}
func (e *EncryptedKey) parse(r io.Reader) (err error) {
var buf [10]byte
_, err = readFull(r, buf[:])
if err != nil {
return
}
if buf[0] != encryptedKeyVersion {
return errors.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0])))
}
e.KeyId = binary.BigEndian.Uint64(buf[1:9])
e.Algo = PublicKeyAlgorithm(buf[9])
switch e.Algo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r)
if err != nil {
return
}
case PubKeyAlgoElGamal:
e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r)
if err != nil {
return
}
e.encryptedMPI2.bytes, e.encryptedMPI2.bitLength, err = readMPI(r)
if err != nil {
return
}
}
_, err = consumeAll(r)
return
}
func checksumKeyMaterial(key []byte) uint16 {
var checksum uint16
for _, v := range key {
checksum += uint16(v)
}
return checksum
}
// Decrypt decrypts an encrypted session key with the given private key. The
// private key must have been decrypted first.
// If config is nil, sensible defaults will be used.
func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error {
var err error
var b []byte
// TODO(agl): use session key decryption routines here to avoid
// padding oracle attacks.
switch priv.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
// Supports both *rsa.PrivateKey and crypto.Decrypter
k := priv.PrivateKey.(crypto.Decrypter)
b, err = k.Decrypt(config.Random(), padToKeySize(k.Public().(*rsa.PublicKey), e.encryptedMPI1.bytes), nil)
case PubKeyAlgoElGamal:
c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes)
c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes)
b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2)
default:
err = errors.InvalidArgumentError("cannot decrypted encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
}
if err != nil {
return err
}
e.CipherFunc = CipherFunction(b[0])
e.Key = b[1 : len(b)-2]
expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1])
checksum := checksumKeyMaterial(e.Key)
if checksum != expectedChecksum {
return errors.StructuralError("EncryptedKey checksum incorrect")
}
return nil
}
// Serialize writes the encrypted key packet, e, to w.
func (e *EncryptedKey) Serialize(w io.Writer) error {
var mpiLen int
switch e.Algo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
mpiLen = 2 + len(e.encryptedMPI1.bytes)
case PubKeyAlgoElGamal:
mpiLen = 2 + len(e.encryptedMPI1.bytes) + 2 + len(e.encryptedMPI2.bytes)
default:
return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo)))
}
serializeHeader(w, packetTypeEncryptedKey, 1 /* version */ +8 /* key id */ +1 /* algo */ +mpiLen)
w.Write([]byte{encryptedKeyVersion})
binary.Write(w, binary.BigEndian, e.KeyId)
w.Write([]byte{byte(e.Algo)})
switch e.Algo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
writeMPIs(w, e.encryptedMPI1)
case PubKeyAlgoElGamal:
writeMPIs(w, e.encryptedMPI1, e.encryptedMPI2)
default:
panic("internal error")
}
return nil
}
// SerializeEncryptedKey serializes an encrypted key packet to w that contains
// key, encrypted to pub.
// If config is nil, sensible defaults will be used.
func SerializeEncryptedKey(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, key []byte, config *Config) error {
var buf [10]byte
buf[0] = encryptedKeyVersion
binary.BigEndian.PutUint64(buf[1:9], pub.KeyId)
buf[9] = byte(pub.PubKeyAlgo)
keyBlock := make([]byte, 1 /* cipher type */ +len(key)+2 /* checksum */)
keyBlock[0] = byte(cipherFunc)
copy(keyBlock[1:], key)
checksum := checksumKeyMaterial(key)
keyBlock[1+len(key)] = byte(checksum >> 8)
keyBlock[1+len(key)+1] = byte(checksum)
switch pub.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
return serializeEncryptedKeyRSA(w, config.Random(), buf, pub.PublicKey.(*rsa.PublicKey), keyBlock)
case PubKeyAlgoElGamal:
return serializeEncryptedKeyElGamal(w, config.Random(), buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock)
case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly:
return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
}
return errors.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
}
func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub *rsa.PublicKey, keyBlock []byte) error {
cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock)
if err != nil {
return errors.InvalidArgumentError("RSA encryption failed: " + err.Error())
}
packetLen := 10 /* header length */ + 2 /* mpi size */ + len(cipherText)
err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
if err != nil {
return err
}
_, err = w.Write(header[:])
if err != nil {
return err
}
return writeMPI(w, 8*uint16(len(cipherText)), cipherText)
}
func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) error {
c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock)
if err != nil {
return errors.InvalidArgumentError("ElGamal encryption failed: " + err.Error())
}
packetLen := 10 /* header length */
packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8
packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8
err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
if err != nil {
return err
}
_, err = w.Write(header[:])
if err != nil {
return err
}
err = writeBig(w, c1)
if err != nil {
return err
}
return writeBig(w, c2)
}
// Copyright 2011 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 packet
import (
"encoding/binary"
"io"
)
// LiteralData represents an encrypted file. See RFC 4880, section 5.9.
type LiteralData struct {
IsBinary bool
FileName string
Time uint32 // Unix epoch time. Either creation time or modification time. 0 means undefined.
Body io.Reader
}
// ForEyesOnly returns whether the contents of the LiteralData have been marked
// as especially sensitive.
func (l *LiteralData) ForEyesOnly() bool {
return l.FileName == "_CONSOLE"
}
func (l *LiteralData) parse(r io.Reader) (err error) {
var buf [256]byte
_, err = readFull(r, buf[:2])
if err != nil {
return
}
l.IsBinary = buf[0] == 'b'
fileNameLen := int(buf[1])
_, err = readFull(r, buf[:fileNameLen])
if err != nil {
return
}
l.FileName = string(buf[:fileNameLen])
_, err = readFull(r, buf[:4])
if err != nil {
return
}
l.Time = binary.BigEndian.Uint32(buf[:4])
l.Body = r
return
}
// SerializeLiteral serializes a literal data packet to w and returns a
// WriteCloser to which the data itself can be written and which MUST be closed
// on completion. The fileName is truncated to 255 bytes.
func SerializeLiteral(w io.WriteCloser, isBinary bool, fileName string, time uint32) (plaintext io.WriteCloser, err error) {
var buf [4]byte
buf[0] = 't'
if isBinary {
buf[0] = 'b'
}
if len(fileName) > 255 {
fileName = fileName[:255]
}
buf[1] = byte(len(fileName))
inner, err := serializeStreamHeader(w, packetTypeLiteralData)
if err != nil {
return
}
_, err = inner.Write(buf[:2])
if err != nil {
return
}
_, err = inner.Write([]byte(fileName))
if err != nil {
return
}
binary.BigEndian.PutUint32(buf[:], time)
_, err = inner.Write(buf[:])
if err != nil {
return
}
plaintext = inner
return
}
// Copyright 2010 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.
// OpenPGP CFB Mode. http://tools.ietf.org/html/rfc4880#section-13.9
package packet
import (
"crypto/cipher"
)
type ocfbEncrypter struct {
b cipher.Block
fre []byte
outUsed int
}
// An OCFBResyncOption determines if the "resynchronization step" of OCFB is
// performed.
type OCFBResyncOption bool
const (
OCFBResync OCFBResyncOption = true
OCFBNoResync OCFBResyncOption = false
)
// NewOCFBEncrypter returns a cipher.Stream which encrypts data with OpenPGP's
// cipher feedback mode using the given cipher.Block, and an initial amount of
// ciphertext. randData must be random bytes and be the same length as the
// cipher.Block's block size. Resync determines if the "resynchronization step"
// from RFC 4880, 13.9 step 7 is performed. Different parts of OpenPGP vary on
// this point.
func NewOCFBEncrypter(block cipher.Block, randData []byte, resync OCFBResyncOption) (cipher.Stream, []byte) {
blockSize := block.BlockSize()
if len(randData) != blockSize {
return nil, nil
}
x := &ocfbEncrypter{
b: block,
fre: make([]byte, blockSize),
outUsed: 0,
}
prefix := make([]byte, blockSize+2)
block.Encrypt(x.fre, x.fre)
for i := 0; i < blockSize; i++ {
prefix[i] = randData[i] ^ x.fre[i]
}
block.Encrypt(x.fre, prefix[:blockSize])
prefix[blockSize] = x.fre[0] ^ randData[blockSize-2]
prefix[blockSize+1] = x.fre[1] ^ randData[blockSize-1]
if resync {
block.Encrypt(x.fre, prefix[2:])
} else {
x.fre[0] = prefix[blockSize]
x.fre[1] = prefix[blockSize+1]
x.outUsed = 2
}
return x, prefix
}
func (x *ocfbEncrypter) XORKeyStream(dst, src []byte) {
for i := 0; i < len(src); i++ {
if x.outUsed == len(x.fre) {
x.b.Encrypt(x.fre, x.fre)
x.outUsed = 0
}
x.fre[x.outUsed] ^= src[i]
dst[i] = x.fre[x.outUsed]
x.outUsed++
}
}
type ocfbDecrypter struct {
b cipher.Block
fre []byte
outUsed int
}
// NewOCFBDecrypter returns a cipher.Stream which decrypts data with OpenPGP's
// cipher feedback mode using the given cipher.Block. Prefix must be the first
// blockSize + 2 bytes of the ciphertext, where blockSize is the cipher.Block's
// block size. If an incorrect key is detected then nil is returned. On
// successful exit, blockSize+2 bytes of decrypted data are written into
// prefix. Resync determines if the "resynchronization step" from RFC 4880,
// 13.9 step 7 is performed. Different parts of OpenPGP vary on this point.
func NewOCFBDecrypter(block cipher.Block, prefix []byte, resync OCFBResyncOption) cipher.Stream {
blockSize := block.BlockSize()
if len(prefix) != blockSize+2 {
return nil
}
x := &ocfbDecrypter{
b: block,
fre: make([]byte, blockSize),
outUsed: 0,
}
prefixCopy := make([]byte, len(prefix))
copy(prefixCopy, prefix)
block.Encrypt(x.fre, x.fre)
for i := 0; i < blockSize; i++ {
prefixCopy[i] ^= x.fre[i]
}
block.Encrypt(x.fre, prefix[:blockSize])
prefixCopy[blockSize] ^= x.fre[0]
prefixCopy[blockSize+1] ^= x.fre[1]
if prefixCopy[blockSize-2] != prefixCopy[blockSize] ||
prefixCopy[blockSize-1] != prefixCopy[blockSize+1] {
return nil
}
if resync {
block.Encrypt(x.fre, prefix[2:])
} else {
x.fre[0] = prefix[blockSize]
x.fre[1] = prefix[blockSize+1]
x.outUsed = 2
}
copy(prefix, prefixCopy)
return x
}
func (x *ocfbDecrypter) XORKeyStream(dst, src []byte) {
for i := 0; i < len(src); i++ {
if x.outUsed == len(x.fre) {
x.b.Encrypt(x.fre, x.fre)
x.outUsed = 0
}
c := src[i]
dst[i] = x.fre[x.outUsed] ^ src[i]
x.fre[x.outUsed] = c
x.outUsed++
}
}
// Copyright 2011 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 packet
import (
"crypto"
"encoding/binary"
"golang.org/x/crypto/openpgp/errors"
"golang.org/x/crypto/openpgp/s2k"
"io"
"strconv"
)
// OnePassSignature represents a one-pass signature packet. See RFC 4880,
// section 5.4.
type OnePassSignature struct {
SigType SignatureType
Hash crypto.Hash
PubKeyAlgo PublicKeyAlgorithm
KeyId uint64
IsLast bool
}
const onePassSignatureVersion = 3
func (ops *OnePassSignature) parse(r io.Reader) (err error) {
var buf [13]byte
_, err = readFull(r, buf[:])
if err != nil {
return
}
if buf[0] != onePassSignatureVersion {
err = errors.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0])))
}
var ok bool
ops.Hash, ok = s2k.HashIdToHash(buf[2])
if !ok {
return errors.UnsupportedError("hash function: " + strconv.Itoa(int(buf[2])))
}
ops.SigType = SignatureType(buf[1])
ops.PubKeyAlgo = PublicKeyAlgorithm(buf[3])
ops.KeyId = binary.BigEndian.Uint64(buf[4:12])
ops.IsLast = buf[12] != 0
return
}
// Serialize marshals the given OnePassSignature to w.
func (ops *OnePassSignature) Serialize(w io.Writer) error {
var buf [13]byte
buf[0] = onePassSignatureVersion
buf[1] = uint8(ops.SigType)
var ok bool
buf[2], ok = s2k.HashToHashId(ops.Hash)
if !ok {
return errors.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash)))
}
buf[3] = uint8(ops.PubKeyAlgo)
binary.BigEndian.PutUint64(buf[4:12], ops.KeyId)
if ops.IsLast {
buf[12] = 1
}
if err := serializeHeader(w, packetTypeOnePassSignature, len(buf)); err != nil {
return err
}
_, err := w.Write(buf[:])
return err
}
// 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.
package packet
import (
"bytes"
"io"
"golang.org/x/crypto/openpgp/errors"
)
// OpaquePacket represents an OpenPGP packet as raw, unparsed data. This is
// useful for splitting and storing the original packet contents separately,
// handling unsupported packet types or accessing parts of the packet not yet
// implemented by this package.
type OpaquePacket struct {
// Packet type
Tag uint8
// Reason why the packet was parsed opaquely
Reason error
// Binary contents of the packet data
Contents []byte
}
func (op *OpaquePacket) parse(r io.Reader) (err error) {
op.Contents, err = io.ReadAll(r)
return
}
// Serialize marshals the packet to a writer in its original form, including
// the packet header.
func (op *OpaquePacket) Serialize(w io.Writer) (err error) {
err = serializeHeader(w, packetType(op.Tag), len(op.Contents))
if err == nil {
_, err = w.Write(op.Contents)
}
return
}
// Parse attempts to parse the opaque contents into a structure supported by
// this package. If the packet is not known then the result will be another
// OpaquePacket.
func (op *OpaquePacket) Parse() (p Packet, err error) {
hdr := bytes.NewBuffer(nil)
err = serializeHeader(hdr, packetType(op.Tag), len(op.Contents))
if err != nil {
op.Reason = err
return op, err
}
p, err = Read(io.MultiReader(hdr, bytes.NewBuffer(op.Contents)))
if err != nil {
op.Reason = err
p = op
}
return
}
// OpaqueReader reads OpaquePackets from an io.Reader.
type OpaqueReader struct {
r io.Reader
}
func NewOpaqueReader(r io.Reader) *OpaqueReader {
return &OpaqueReader{r: r}
}
// Read the next OpaquePacket.
func (or *OpaqueReader) Next() (op *OpaquePacket, err error) {
tag, _, contents, err := readHeader(or.r)
if err != nil {
return
}
op = &OpaquePacket{Tag: uint8(tag), Reason: err}
err = op.parse(contents)
if err != nil {
consumeAll(contents)
}
return
}
// OpaqueSubpacket represents an unparsed OpenPGP subpacket,
// as found in signature and user attribute packets.
type OpaqueSubpacket struct {
SubType uint8
Contents []byte
}
// OpaqueSubpackets extracts opaque, unparsed OpenPGP subpackets from
// their byte representation.
func OpaqueSubpackets(contents []byte) (result []*OpaqueSubpacket, err error) {
var (
subHeaderLen int
subPacket *OpaqueSubpacket
)
for len(contents) > 0 {
subHeaderLen, subPacket, err = nextSubpacket(contents)
if err != nil {
break
}
result = append(result, subPacket)
contents = contents[subHeaderLen+len(subPacket.Contents):]
}
return
}
func nextSubpacket(contents []byte) (subHeaderLen int, subPacket *OpaqueSubpacket, err error) {
// RFC 4880, section 5.2.3.1
var subLen uint32
if len(contents) < 1 {
goto Truncated
}
subPacket = &OpaqueSubpacket{}
switch {
case contents[0] < 192:
subHeaderLen = 2 // 1 length byte, 1 subtype byte
if len(contents) < subHeaderLen {
goto Truncated
}
subLen = uint32(contents[0])
contents = contents[1:]
case contents[0] < 255:
subHeaderLen = 3 // 2 length bytes, 1 subtype
if len(contents) < subHeaderLen {
goto Truncated
}
subLen = uint32(contents[0]-192)<<8 + uint32(contents[1]) + 192
contents = contents[2:]
default:
subHeaderLen = 6 // 5 length bytes, 1 subtype
if len(contents) < subHeaderLen {
goto Truncated
}
subLen = uint32(contents[1])<<24 |
uint32(contents[2])<<16 |
uint32(contents[3])<<8 |
uint32(contents[4])
contents = contents[5:]
}
if subLen > uint32(len(contents)) || subLen == 0 {
goto Truncated
}
subPacket.SubType = contents[0]
subPacket.Contents = contents[1:subLen]
return
Truncated:
err = errors.StructuralError("subpacket truncated")
return
}
func (osp *OpaqueSubpacket) Serialize(w io.Writer) (err error) {
buf := make([]byte, 6)
n := serializeSubpacketLength(buf, len(osp.Contents)+1)
buf[n] = osp.SubType
if _, err = w.Write(buf[:n+1]); err != nil {
return
}
_, err = w.Write(osp.Contents)
return
}
// Copyright 2011 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 packet implements parsing and serialization of OpenPGP packets, as
// specified in RFC 4880.
//
// Deprecated: this package is unmaintained except for security fixes. New
// applications should consider a more focused, modern alternative to OpenPGP
// for their specific task. If you are required to interoperate with OpenPGP
// systems and need a maintained package, consider a community fork.
// See https://golang.org/issue/44226.
package packet
import (
"bufio"
"crypto/aes"
"crypto/cipher"
"crypto/des"
"crypto/rsa"
"io"
"math/big"
"math/bits"
"golang.org/x/crypto/cast5"
"golang.org/x/crypto/openpgp/errors"
)
// readFull is the same as io.ReadFull except that reading zero bytes returns
// ErrUnexpectedEOF rather than EOF.
func readFull(r io.Reader, buf []byte) (n int, err error) {
n, err = io.ReadFull(r, buf)
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return
}
// readLength reads an OpenPGP length from r. See RFC 4880, section 4.2.2.
func readLength(r io.Reader) (length int64, isPartial bool, err error) {
var buf [4]byte
_, err = readFull(r, buf[:1])
if err != nil {
return
}
switch {
case buf[0] < 192:
length = int64(buf[0])
case buf[0] < 224:
length = int64(buf[0]-192) << 8
_, err = readFull(r, buf[0:1])
if err != nil {
return
}
length += int64(buf[0]) + 192
case buf[0] < 255:
length = int64(1) << (buf[0] & 0x1f)
isPartial = true
default:
_, err = readFull(r, buf[0:4])
if err != nil {
return
}
length = int64(buf[0])<<24 |
int64(buf[1])<<16 |
int64(buf[2])<<8 |
int64(buf[3])
}
return
}
// partialLengthReader wraps an io.Reader and handles OpenPGP partial lengths.
// The continuation lengths are parsed and removed from the stream and EOF is
// returned at the end of the packet. See RFC 4880, section 4.2.2.4.
type partialLengthReader struct {
r io.Reader
remaining int64
isPartial bool
}
func (r *partialLengthReader) Read(p []byte) (n int, err error) {
for r.remaining == 0 {
if !r.isPartial {
return 0, io.EOF
}
r.remaining, r.isPartial, err = readLength(r.r)
if err != nil {
return 0, err
}
}
toRead := int64(len(p))
if toRead > r.remaining {
toRead = r.remaining
}
n, err = r.r.Read(p[:int(toRead)])
r.remaining -= int64(n)
if n < int(toRead) && err == io.EOF {
err = io.ErrUnexpectedEOF
}
return
}
// partialLengthWriter writes a stream of data using OpenPGP partial lengths.
// See RFC 4880, section 4.2.2.4.
type partialLengthWriter struct {
w io.WriteCloser
lengthByte [1]byte
sentFirst bool
buf []byte
}
// RFC 4880 4.2.2.4: the first partial length MUST be at least 512 octets long.
const minFirstPartialWrite = 512
func (w *partialLengthWriter) Write(p []byte) (n int, err error) {
off := 0
if !w.sentFirst {
if len(w.buf) > 0 || len(p) < minFirstPartialWrite {
off = len(w.buf)
w.buf = append(w.buf, p...)
if len(w.buf) < minFirstPartialWrite {
return len(p), nil
}
p = w.buf
w.buf = nil
}
w.sentFirst = true
}
power := uint8(30)
for len(p) > 0 {
l := 1 << power
if len(p) < l {
power = uint8(bits.Len32(uint32(len(p)))) - 1
l = 1 << power
}
w.lengthByte[0] = 224 + power
_, err = w.w.Write(w.lengthByte[:])
if err == nil {
var m int
m, err = w.w.Write(p[:l])
n += m
}
if err != nil {
if n < off {
return 0, err
}
return n - off, err
}
p = p[l:]
}
return n - off, nil
}
func (w *partialLengthWriter) Close() error {
if len(w.buf) > 0 {
// In this case we can't send a 512 byte packet.
// Just send what we have.
p := w.buf
w.sentFirst = true
w.buf = nil
if _, err := w.Write(p); err != nil {
return err
}
}
w.lengthByte[0] = 0
_, err := w.w.Write(w.lengthByte[:])
if err != nil {
return err
}
return w.w.Close()
}
// A spanReader is an io.LimitReader, but it returns ErrUnexpectedEOF if the
// underlying Reader returns EOF before the limit has been reached.
type spanReader struct {
r io.Reader
n int64
}
func (l *spanReader) Read(p []byte) (n int, err error) {
if l.n <= 0 {
return 0, io.EOF
}
if int64(len(p)) > l.n {
p = p[0:l.n]
}
n, err = l.r.Read(p)
l.n -= int64(n)
if l.n > 0 && err == io.EOF {
err = io.ErrUnexpectedEOF
}
return
}
// readHeader parses a packet header and returns an io.Reader which will return
// the contents of the packet. See RFC 4880, section 4.2.
func readHeader(r io.Reader) (tag packetType, length int64, contents io.Reader, err error) {
var buf [4]byte
_, err = io.ReadFull(r, buf[:1])
if err != nil {
return
}
if buf[0]&0x80 == 0 {
err = errors.StructuralError("tag byte does not have MSB set")
return
}
if buf[0]&0x40 == 0 {
// Old format packet
tag = packetType((buf[0] & 0x3f) >> 2)
lengthType := buf[0] & 3
if lengthType == 3 {
length = -1
contents = r
return
}
lengthBytes := 1 << lengthType
_, err = readFull(r, buf[0:lengthBytes])
if err != nil {
return
}
for i := 0; i < lengthBytes; i++ {
length <<= 8
length |= int64(buf[i])
}
contents = &spanReader{r, length}
return
}
// New format packet
tag = packetType(buf[0] & 0x3f)
length, isPartial, err := readLength(r)
if err != nil {
return
}
if isPartial {
contents = &partialLengthReader{
remaining: length,
isPartial: true,
r: r,
}
length = -1
} else {
contents = &spanReader{r, length}
}
return
}
// serializeHeader writes an OpenPGP packet header to w. See RFC 4880, section
// 4.2.
func serializeHeader(w io.Writer, ptype packetType, length int) (err error) {
var buf [6]byte
var n int
buf[0] = 0x80 | 0x40 | byte(ptype)
if length < 192 {
buf[1] = byte(length)
n = 2
} else if length < 8384 {
length -= 192
buf[1] = 192 + byte(length>>8)
buf[2] = byte(length)
n = 3
} else {
buf[1] = 255
buf[2] = byte(length >> 24)
buf[3] = byte(length >> 16)
buf[4] = byte(length >> 8)
buf[5] = byte(length)
n = 6
}
_, err = w.Write(buf[:n])
return
}
// serializeStreamHeader writes an OpenPGP packet header to w where the
// length of the packet is unknown. It returns a io.WriteCloser which can be
// used to write the contents of the packet. See RFC 4880, section 4.2.
func serializeStreamHeader(w io.WriteCloser, ptype packetType) (out io.WriteCloser, err error) {
var buf [1]byte
buf[0] = 0x80 | 0x40 | byte(ptype)
_, err = w.Write(buf[:])
if err != nil {
return
}
out = &partialLengthWriter{w: w}
return
}
// Packet represents an OpenPGP packet. Users are expected to try casting
// instances of this interface to specific packet types.
type Packet interface {
parse(io.Reader) error
}
// consumeAll reads from the given Reader until error, returning the number of
// bytes read.
func consumeAll(r io.Reader) (n int64, err error) {
var m int
var buf [1024]byte
for {
m, err = r.Read(buf[:])
n += int64(m)
if err == io.EOF {
err = nil
return
}
if err != nil {
return
}
}
}
// packetType represents the numeric ids of the different OpenPGP packet types. See
// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-2
type packetType uint8
const (
packetTypeEncryptedKey packetType = 1
packetTypeSignature packetType = 2
packetTypeSymmetricKeyEncrypted packetType = 3
packetTypeOnePassSignature packetType = 4
packetTypePrivateKey packetType = 5
packetTypePublicKey packetType = 6
packetTypePrivateSubkey packetType = 7
packetTypeCompressed packetType = 8
packetTypeSymmetricallyEncrypted packetType = 9
packetTypeLiteralData packetType = 11
packetTypeUserId packetType = 13
packetTypePublicSubkey packetType = 14
packetTypeUserAttribute packetType = 17
packetTypeSymmetricallyEncryptedMDC packetType = 18
)
// peekVersion detects the version of a public key packet about to
// be read. A bufio.Reader at the original position of the io.Reader
// is returned.
func peekVersion(r io.Reader) (bufr *bufio.Reader, ver byte, err error) {
bufr = bufio.NewReader(r)
var verBuf []byte
if verBuf, err = bufr.Peek(1); err != nil {
return
}
ver = verBuf[0]
return
}
// Read reads a single OpenPGP packet from the given io.Reader. If there is an
// error parsing a packet, the whole packet is consumed from the input.
func Read(r io.Reader) (p Packet, err error) {
tag, _, contents, err := readHeader(r)
if err != nil {
return
}
switch tag {
case packetTypeEncryptedKey:
p = new(EncryptedKey)
case packetTypeSignature:
var version byte
// Detect signature version
if contents, version, err = peekVersion(contents); err != nil {
return
}
if version < 4 {
p = new(SignatureV3)
} else {
p = new(Signature)
}
case packetTypeSymmetricKeyEncrypted:
p = new(SymmetricKeyEncrypted)
case packetTypeOnePassSignature:
p = new(OnePassSignature)
case packetTypePrivateKey, packetTypePrivateSubkey:
pk := new(PrivateKey)
if tag == packetTypePrivateSubkey {
pk.IsSubkey = true
}
p = pk
case packetTypePublicKey, packetTypePublicSubkey:
var version byte
if contents, version, err = peekVersion(contents); err != nil {
return
}
isSubkey := tag == packetTypePublicSubkey
if version < 4 {
p = &PublicKeyV3{IsSubkey: isSubkey}
} else {
p = &PublicKey{IsSubkey: isSubkey}
}
case packetTypeCompressed:
p = new(Compressed)
case packetTypeSymmetricallyEncrypted:
p = new(SymmetricallyEncrypted)
case packetTypeLiteralData:
p = new(LiteralData)
case packetTypeUserId:
p = new(UserId)
case packetTypeUserAttribute:
p = new(UserAttribute)
case packetTypeSymmetricallyEncryptedMDC:
se := new(SymmetricallyEncrypted)
se.MDC = true
p = se
default:
err = errors.UnknownPacketTypeError(tag)
}
if p != nil {
err = p.parse(contents)
}
if err != nil {
consumeAll(contents)
}
return
}
// SignatureType represents the different semantic meanings of an OpenPGP
// signature. See RFC 4880, section 5.2.1.
type SignatureType uint8
const (
SigTypeBinary SignatureType = 0
SigTypeText = 1
SigTypeGenericCert = 0x10
SigTypePersonaCert = 0x11
SigTypeCasualCert = 0x12
SigTypePositiveCert = 0x13
SigTypeSubkeyBinding = 0x18
SigTypePrimaryKeyBinding = 0x19
SigTypeDirectSignature = 0x1F
SigTypeKeyRevocation = 0x20
SigTypeSubkeyRevocation = 0x28
)
// PublicKeyAlgorithm represents the different public key system specified for
// OpenPGP. See
// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-12
type PublicKeyAlgorithm uint8
const (
PubKeyAlgoRSA PublicKeyAlgorithm = 1
PubKeyAlgoElGamal PublicKeyAlgorithm = 16
PubKeyAlgoDSA PublicKeyAlgorithm = 17
// RFC 6637, Section 5.
PubKeyAlgoECDH PublicKeyAlgorithm = 18
PubKeyAlgoECDSA PublicKeyAlgorithm = 19
// Deprecated in RFC 4880, Section 13.5. Use key flags instead.
PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2
PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3
)
// CanEncrypt returns true if it's possible to encrypt a message to a public
// key of the given type.
func (pka PublicKeyAlgorithm) CanEncrypt() bool {
switch pka {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal:
return true
}
return false
}
// CanSign returns true if it's possible for a public key of the given type to
// sign a message.
func (pka PublicKeyAlgorithm) CanSign() bool {
switch pka {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA:
return true
}
return false
}
// CipherFunction represents the different block ciphers specified for OpenPGP. See
// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13
type CipherFunction uint8
const (
Cipher3DES CipherFunction = 2
CipherCAST5 CipherFunction = 3
CipherAES128 CipherFunction = 7
CipherAES192 CipherFunction = 8
CipherAES256 CipherFunction = 9
)
// KeySize returns the key size, in bytes, of cipher.
func (cipher CipherFunction) KeySize() int {
switch cipher {
case Cipher3DES:
return 24
case CipherCAST5:
return cast5.KeySize
case CipherAES128:
return 16
case CipherAES192:
return 24
case CipherAES256:
return 32
}
return 0
}
// blockSize returns the block size, in bytes, of cipher.
func (cipher CipherFunction) blockSize() int {
switch cipher {
case Cipher3DES:
return des.BlockSize
case CipherCAST5:
return 8
case CipherAES128, CipherAES192, CipherAES256:
return 16
}
return 0
}
// new returns a fresh instance of the given cipher.
func (cipher CipherFunction) new(key []byte) (block cipher.Block) {
switch cipher {
case Cipher3DES:
block, _ = des.NewTripleDESCipher(key)
case CipherCAST5:
block, _ = cast5.NewCipher(key)
case CipherAES128, CipherAES192, CipherAES256:
block, _ = aes.NewCipher(key)
}
return
}
// readMPI reads a big integer from r. The bit length returned is the bit
// length that was specified in r. This is preserved so that the integer can be
// reserialized exactly.
func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err error) {
var buf [2]byte
_, err = readFull(r, buf[0:])
if err != nil {
return
}
bitLength = uint16(buf[0])<<8 | uint16(buf[1])
numBytes := (int(bitLength) + 7) / 8
mpi = make([]byte, numBytes)
_, err = readFull(r, mpi)
// According to RFC 4880 3.2. we should check that the MPI has no leading
// zeroes (at least when not an encrypted MPI?), but this implementation
// does generate leading zeroes, so we keep accepting them.
return
}
// writeMPI serializes a big integer to w.
func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err error) {
// Note that we can produce leading zeroes, in violation of RFC 4880 3.2.
// Implementations seem to be tolerant of them, and stripping them would
// make it complex to guarantee matching re-serialization.
_, err = w.Write([]byte{byte(bitLength >> 8), byte(bitLength)})
if err == nil {
_, err = w.Write(mpiBytes)
}
return
}
// writeBig serializes a *big.Int to w.
func writeBig(w io.Writer, i *big.Int) error {
return writeMPI(w, uint16(i.BitLen()), i.Bytes())
}
// padToKeySize left-pads a MPI with zeroes to match the length of the
// specified RSA public.
func padToKeySize(pub *rsa.PublicKey, b []byte) []byte {
k := (pub.N.BitLen() + 7) / 8
if len(b) >= k {
return b
}
bb := make([]byte, k)
copy(bb[len(bb)-len(b):], b)
return bb
}
// CompressionAlgo Represents the different compression algorithms
// supported by OpenPGP (except for BZIP2, which is not currently
// supported). See Section 9.3 of RFC 4880.
type CompressionAlgo uint8
const (
CompressionNone CompressionAlgo = 0
CompressionZIP CompressionAlgo = 1
CompressionZLIB CompressionAlgo = 2
)
// Copyright 2011 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 packet
import (
"bytes"
"crypto"
"crypto/cipher"
"crypto/dsa"
"crypto/ecdsa"
"crypto/rsa"
"crypto/sha1"
"io"
"math/big"
"strconv"
"time"
"golang.org/x/crypto/openpgp/elgamal"
"golang.org/x/crypto/openpgp/errors"
"golang.org/x/crypto/openpgp/s2k"
)
// PrivateKey represents a possibly encrypted private key. See RFC 4880,
// section 5.5.3.
type PrivateKey struct {
PublicKey
Encrypted bool // if true then the private key is unavailable until Decrypt has been called.
encryptedData []byte
cipher CipherFunction
s2k func(out, in []byte)
PrivateKey interface{} // An *{rsa|dsa|ecdsa}.PrivateKey or crypto.Signer/crypto.Decrypter (Decryptor RSA only).
sha1Checksum bool
iv []byte
}
func NewRSAPrivateKey(creationTime time.Time, priv *rsa.PrivateKey) *PrivateKey {
pk := new(PrivateKey)
pk.PublicKey = *NewRSAPublicKey(creationTime, &priv.PublicKey)
pk.PrivateKey = priv
return pk
}
func NewDSAPrivateKey(creationTime time.Time, priv *dsa.PrivateKey) *PrivateKey {
pk := new(PrivateKey)
pk.PublicKey = *NewDSAPublicKey(creationTime, &priv.PublicKey)
pk.PrivateKey = priv
return pk
}
func NewElGamalPrivateKey(creationTime time.Time, priv *elgamal.PrivateKey) *PrivateKey {
pk := new(PrivateKey)
pk.PublicKey = *NewElGamalPublicKey(creationTime, &priv.PublicKey)
pk.PrivateKey = priv
return pk
}
func NewECDSAPrivateKey(creationTime time.Time, priv *ecdsa.PrivateKey) *PrivateKey {
pk := new(PrivateKey)
pk.PublicKey = *NewECDSAPublicKey(creationTime, &priv.PublicKey)
pk.PrivateKey = priv
return pk
}
// NewSignerPrivateKey creates a PrivateKey from a crypto.Signer that
// implements RSA or ECDSA.
func NewSignerPrivateKey(creationTime time.Time, signer crypto.Signer) *PrivateKey {
pk := new(PrivateKey)
// In general, the public Keys should be used as pointers. We still
// type-switch on the values, for backwards-compatibility.
switch pubkey := signer.Public().(type) {
case *rsa.PublicKey:
pk.PublicKey = *NewRSAPublicKey(creationTime, pubkey)
case rsa.PublicKey:
pk.PublicKey = *NewRSAPublicKey(creationTime, &pubkey)
case *ecdsa.PublicKey:
pk.PublicKey = *NewECDSAPublicKey(creationTime, pubkey)
case ecdsa.PublicKey:
pk.PublicKey = *NewECDSAPublicKey(creationTime, &pubkey)
default:
panic("openpgp: unknown crypto.Signer type in NewSignerPrivateKey")
}
pk.PrivateKey = signer
return pk
}
func (pk *PrivateKey) parse(r io.Reader) (err error) {
err = (&pk.PublicKey).parse(r)
if err != nil {
return
}
var buf [1]byte
_, err = readFull(r, buf[:])
if err != nil {
return
}
s2kType := buf[0]
switch s2kType {
case 0:
pk.s2k = nil
pk.Encrypted = false
case 254, 255:
_, err = readFull(r, buf[:])
if err != nil {
return
}
pk.cipher = CipherFunction(buf[0])
pk.Encrypted = true
pk.s2k, err = s2k.Parse(r)
if err != nil {
return
}
if s2kType == 254 {
pk.sha1Checksum = true
}
default:
return errors.UnsupportedError("deprecated s2k function in private key")
}
if pk.Encrypted {
blockSize := pk.cipher.blockSize()
if blockSize == 0 {
return errors.UnsupportedError("unsupported cipher in private key: " + strconv.Itoa(int(pk.cipher)))
}
pk.iv = make([]byte, blockSize)
_, err = readFull(r, pk.iv)
if err != nil {
return
}
}
pk.encryptedData, err = io.ReadAll(r)
if err != nil {
return
}
if !pk.Encrypted {
return pk.parsePrivateKey(pk.encryptedData)
}
return
}
func mod64kHash(d []byte) uint16 {
var h uint16
for _, b := range d {
h += uint16(b)
}
return h
}
func (pk *PrivateKey) Serialize(w io.Writer) (err error) {
// TODO(agl): support encrypted private keys
buf := bytes.NewBuffer(nil)
err = pk.PublicKey.serializeWithoutHeaders(buf)
if err != nil {
return
}
buf.WriteByte(0 /* no encryption */)
privateKeyBuf := bytes.NewBuffer(nil)
switch priv := pk.PrivateKey.(type) {
case *rsa.PrivateKey:
err = serializeRSAPrivateKey(privateKeyBuf, priv)
case *dsa.PrivateKey:
err = serializeDSAPrivateKey(privateKeyBuf, priv)
case *elgamal.PrivateKey:
err = serializeElGamalPrivateKey(privateKeyBuf, priv)
case *ecdsa.PrivateKey:
err = serializeECDSAPrivateKey(privateKeyBuf, priv)
default:
err = errors.InvalidArgumentError("unknown private key type")
}
if err != nil {
return
}
ptype := packetTypePrivateKey
contents := buf.Bytes()
privateKeyBytes := privateKeyBuf.Bytes()
if pk.IsSubkey {
ptype = packetTypePrivateSubkey
}
err = serializeHeader(w, ptype, len(contents)+len(privateKeyBytes)+2)
if err != nil {
return
}
_, err = w.Write(contents)
if err != nil {
return
}
_, err = w.Write(privateKeyBytes)
if err != nil {
return
}
checksum := mod64kHash(privateKeyBytes)
var checksumBytes [2]byte
checksumBytes[0] = byte(checksum >> 8)
checksumBytes[1] = byte(checksum)
_, err = w.Write(checksumBytes[:])
return
}
func serializeRSAPrivateKey(w io.Writer, priv *rsa.PrivateKey) error {
err := writeBig(w, priv.D)
if err != nil {
return err
}
err = writeBig(w, priv.Primes[1])
if err != nil {
return err
}
err = writeBig(w, priv.Primes[0])
if err != nil {
return err
}
return writeBig(w, priv.Precomputed.Qinv)
}
func serializeDSAPrivateKey(w io.Writer, priv *dsa.PrivateKey) error {
return writeBig(w, priv.X)
}
func serializeElGamalPrivateKey(w io.Writer, priv *elgamal.PrivateKey) error {
return writeBig(w, priv.X)
}
func serializeECDSAPrivateKey(w io.Writer, priv *ecdsa.PrivateKey) error {
return writeBig(w, priv.D)
}
// Decrypt decrypts an encrypted private key using a passphrase.
func (pk *PrivateKey) Decrypt(passphrase []byte) error {
if !pk.Encrypted {
return nil
}
key := make([]byte, pk.cipher.KeySize())
pk.s2k(key, passphrase)
block := pk.cipher.new(key)
cfb := cipher.NewCFBDecrypter(block, pk.iv)
data := make([]byte, len(pk.encryptedData))
cfb.XORKeyStream(data, pk.encryptedData)
if pk.sha1Checksum {
if len(data) < sha1.Size {
return errors.StructuralError("truncated private key data")
}
h := sha1.New()
h.Write(data[:len(data)-sha1.Size])
sum := h.Sum(nil)
if !bytes.Equal(sum, data[len(data)-sha1.Size:]) {
return errors.StructuralError("private key checksum failure")
}
data = data[:len(data)-sha1.Size]
} else {
if len(data) < 2 {
return errors.StructuralError("truncated private key data")
}
var sum uint16
for i := 0; i < len(data)-2; i++ {
sum += uint16(data[i])
}
if data[len(data)-2] != uint8(sum>>8) ||
data[len(data)-1] != uint8(sum) {
return errors.StructuralError("private key checksum failure")
}
data = data[:len(data)-2]
}
return pk.parsePrivateKey(data)
}
func (pk *PrivateKey) parsePrivateKey(data []byte) (err error) {
switch pk.PublicKey.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoRSAEncryptOnly:
return pk.parseRSAPrivateKey(data)
case PubKeyAlgoDSA:
return pk.parseDSAPrivateKey(data)
case PubKeyAlgoElGamal:
return pk.parseElGamalPrivateKey(data)
case PubKeyAlgoECDSA:
return pk.parseECDSAPrivateKey(data)
}
panic("impossible")
}
func (pk *PrivateKey) parseRSAPrivateKey(data []byte) (err error) {
rsaPub := pk.PublicKey.PublicKey.(*rsa.PublicKey)
rsaPriv := new(rsa.PrivateKey)
rsaPriv.PublicKey = *rsaPub
buf := bytes.NewBuffer(data)
d, _, err := readMPI(buf)
if err != nil {
return
}
p, _, err := readMPI(buf)
if err != nil {
return
}
q, _, err := readMPI(buf)
if err != nil {
return
}
rsaPriv.D = new(big.Int).SetBytes(d)
rsaPriv.Primes = make([]*big.Int, 2)
rsaPriv.Primes[0] = new(big.Int).SetBytes(p)
rsaPriv.Primes[1] = new(big.Int).SetBytes(q)
if err := rsaPriv.Validate(); err != nil {
return err
}
rsaPriv.Precompute()
pk.PrivateKey = rsaPriv
pk.Encrypted = false
pk.encryptedData = nil
return nil
}
func (pk *PrivateKey) parseDSAPrivateKey(data []byte) (err error) {
dsaPub := pk.PublicKey.PublicKey.(*dsa.PublicKey)
dsaPriv := new(dsa.PrivateKey)
dsaPriv.PublicKey = *dsaPub
buf := bytes.NewBuffer(data)
x, _, err := readMPI(buf)
if err != nil {
return
}
dsaPriv.X = new(big.Int).SetBytes(x)
pk.PrivateKey = dsaPriv
pk.Encrypted = false
pk.encryptedData = nil
return nil
}
func (pk *PrivateKey) parseElGamalPrivateKey(data []byte) (err error) {
pub := pk.PublicKey.PublicKey.(*elgamal.PublicKey)
priv := new(elgamal.PrivateKey)
priv.PublicKey = *pub
buf := bytes.NewBuffer(data)
x, _, err := readMPI(buf)
if err != nil {
return
}
priv.X = new(big.Int).SetBytes(x)
pk.PrivateKey = priv
pk.Encrypted = false
pk.encryptedData = nil
return nil
}
func (pk *PrivateKey) parseECDSAPrivateKey(data []byte) (err error) {
ecdsaPub := pk.PublicKey.PublicKey.(*ecdsa.PublicKey)
buf := bytes.NewBuffer(data)
d, _, err := readMPI(buf)
if err != nil {
return
}
pk.PrivateKey = &ecdsa.PrivateKey{
PublicKey: *ecdsaPub,
D: new(big.Int).SetBytes(d),
}
pk.Encrypted = false
pk.encryptedData = nil
return nil
}
// Copyright 2011 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 packet
import (
"bytes"
"crypto"
"crypto/dsa"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"crypto/sha1"
_ "crypto/sha256"
_ "crypto/sha512"
"encoding/binary"
"fmt"
"hash"
"io"
"math/big"
"strconv"
"time"
"golang.org/x/crypto/openpgp/elgamal"
"golang.org/x/crypto/openpgp/errors"
)
var (
// NIST curve P-256
oidCurveP256 []byte = []byte{0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07}
// NIST curve P-384
oidCurveP384 []byte = []byte{0x2B, 0x81, 0x04, 0x00, 0x22}
// NIST curve P-521
oidCurveP521 []byte = []byte{0x2B, 0x81, 0x04, 0x00, 0x23}
)
const maxOIDLength = 8
// ecdsaKey stores the algorithm-specific fields for ECDSA keys.
// as defined in RFC 6637, Section 9.
type ecdsaKey struct {
// oid contains the OID byte sequence identifying the elliptic curve used
oid []byte
// p contains the elliptic curve point that represents the public key
p parsedMPI
}
// parseOID reads the OID for the curve as defined in RFC 6637, Section 9.
func parseOID(r io.Reader) (oid []byte, err error) {
buf := make([]byte, maxOIDLength)
if _, err = readFull(r, buf[:1]); err != nil {
return
}
oidLen := buf[0]
if int(oidLen) > len(buf) {
err = errors.UnsupportedError("invalid oid length: " + strconv.Itoa(int(oidLen)))
return
}
oid = buf[:oidLen]
_, err = readFull(r, oid)
return
}
func (f *ecdsaKey) parse(r io.Reader) (err error) {
if f.oid, err = parseOID(r); err != nil {
return err
}
f.p.bytes, f.p.bitLength, err = readMPI(r)
return
}
func (f *ecdsaKey) serialize(w io.Writer) (err error) {
buf := make([]byte, maxOIDLength+1)
buf[0] = byte(len(f.oid))
copy(buf[1:], f.oid)
if _, err = w.Write(buf[:len(f.oid)+1]); err != nil {
return
}
return writeMPIs(w, f.p)
}
func (f *ecdsaKey) newECDSA() (*ecdsa.PublicKey, error) {
var c elliptic.Curve
if bytes.Equal(f.oid, oidCurveP256) {
c = elliptic.P256()
} else if bytes.Equal(f.oid, oidCurveP384) {
c = elliptic.P384()
} else if bytes.Equal(f.oid, oidCurveP521) {
c = elliptic.P521()
} else {
return nil, errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", f.oid))
}
x, y := elliptic.Unmarshal(c, f.p.bytes)
if x == nil {
return nil, errors.UnsupportedError("failed to parse EC point")
}
return &ecdsa.PublicKey{Curve: c, X: x, Y: y}, nil
}
func (f *ecdsaKey) byteLen() int {
return 1 + len(f.oid) + 2 + len(f.p.bytes)
}
type kdfHashFunction byte
type kdfAlgorithm byte
// ecdhKdf stores key derivation function parameters
// used for ECDH encryption. See RFC 6637, Section 9.
type ecdhKdf struct {
KdfHash kdfHashFunction
KdfAlgo kdfAlgorithm
}
func (f *ecdhKdf) parse(r io.Reader) (err error) {
buf := make([]byte, 1)
if _, err = readFull(r, buf); err != nil {
return
}
kdfLen := int(buf[0])
if kdfLen < 3 {
return errors.UnsupportedError("Unsupported ECDH KDF length: " + strconv.Itoa(kdfLen))
}
buf = make([]byte, kdfLen)
if _, err = readFull(r, buf); err != nil {
return
}
reserved := int(buf[0])
f.KdfHash = kdfHashFunction(buf[1])
f.KdfAlgo = kdfAlgorithm(buf[2])
if reserved != 0x01 {
return errors.UnsupportedError("Unsupported KDF reserved field: " + strconv.Itoa(reserved))
}
return
}
func (f *ecdhKdf) serialize(w io.Writer) (err error) {
buf := make([]byte, 4)
// See RFC 6637, Section 9, Algorithm-Specific Fields for ECDH keys.
buf[0] = byte(0x03) // Length of the following fields
buf[1] = byte(0x01) // Reserved for future extensions, must be 1 for now
buf[2] = byte(f.KdfHash)
buf[3] = byte(f.KdfAlgo)
_, err = w.Write(buf[:])
return
}
func (f *ecdhKdf) byteLen() int {
return 4
}
// PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2.
type PublicKey struct {
CreationTime time.Time
PubKeyAlgo PublicKeyAlgorithm
PublicKey interface{} // *rsa.PublicKey, *dsa.PublicKey or *ecdsa.PublicKey
Fingerprint [20]byte
KeyId uint64
IsSubkey bool
n, e, p, q, g, y parsedMPI
// RFC 6637 fields
ec *ecdsaKey
ecdh *ecdhKdf
}
// signingKey provides a convenient abstraction over signature verification
// for v3 and v4 public keys.
type signingKey interface {
SerializeSignaturePrefix(io.Writer)
serializeWithoutHeaders(io.Writer) error
}
func fromBig(n *big.Int) parsedMPI {
return parsedMPI{
bytes: n.Bytes(),
bitLength: uint16(n.BitLen()),
}
}
// NewRSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey.
func NewRSAPublicKey(creationTime time.Time, pub *rsa.PublicKey) *PublicKey {
pk := &PublicKey{
CreationTime: creationTime,
PubKeyAlgo: PubKeyAlgoRSA,
PublicKey: pub,
n: fromBig(pub.N),
e: fromBig(big.NewInt(int64(pub.E))),
}
pk.setFingerPrintAndKeyId()
return pk
}
// NewDSAPublicKey returns a PublicKey that wraps the given dsa.PublicKey.
func NewDSAPublicKey(creationTime time.Time, pub *dsa.PublicKey) *PublicKey {
pk := &PublicKey{
CreationTime: creationTime,
PubKeyAlgo: PubKeyAlgoDSA,
PublicKey: pub,
p: fromBig(pub.P),
q: fromBig(pub.Q),
g: fromBig(pub.G),
y: fromBig(pub.Y),
}
pk.setFingerPrintAndKeyId()
return pk
}
// NewElGamalPublicKey returns a PublicKey that wraps the given elgamal.PublicKey.
func NewElGamalPublicKey(creationTime time.Time, pub *elgamal.PublicKey) *PublicKey {
pk := &PublicKey{
CreationTime: creationTime,
PubKeyAlgo: PubKeyAlgoElGamal,
PublicKey: pub,
p: fromBig(pub.P),
g: fromBig(pub.G),
y: fromBig(pub.Y),
}
pk.setFingerPrintAndKeyId()
return pk
}
func NewECDSAPublicKey(creationTime time.Time, pub *ecdsa.PublicKey) *PublicKey {
pk := &PublicKey{
CreationTime: creationTime,
PubKeyAlgo: PubKeyAlgoECDSA,
PublicKey: pub,
ec: new(ecdsaKey),
}
switch pub.Curve {
case elliptic.P256():
pk.ec.oid = oidCurveP256
case elliptic.P384():
pk.ec.oid = oidCurveP384
case elliptic.P521():
pk.ec.oid = oidCurveP521
default:
panic("unknown elliptic curve")
}
pk.ec.p.bytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y)
// The bit length is 3 (for the 0x04 specifying an uncompressed key)
// plus two field elements (for x and y), which are rounded up to the
// nearest byte. See https://tools.ietf.org/html/rfc6637#section-6
fieldBytes := (pub.Curve.Params().BitSize + 7) & ^7
pk.ec.p.bitLength = uint16(3 + fieldBytes + fieldBytes)
pk.setFingerPrintAndKeyId()
return pk
}
func (pk *PublicKey) parse(r io.Reader) (err error) {
// RFC 4880, section 5.5.2
var buf [6]byte
_, err = readFull(r, buf[:])
if err != nil {
return
}
if buf[0] != 4 {
return errors.UnsupportedError("public key version")
}
pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0)
pk.PubKeyAlgo = PublicKeyAlgorithm(buf[5])
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
err = pk.parseRSA(r)
case PubKeyAlgoDSA:
err = pk.parseDSA(r)
case PubKeyAlgoElGamal:
err = pk.parseElGamal(r)
case PubKeyAlgoECDSA:
pk.ec = new(ecdsaKey)
if err = pk.ec.parse(r); err != nil {
return err
}
pk.PublicKey, err = pk.ec.newECDSA()
case PubKeyAlgoECDH:
pk.ec = new(ecdsaKey)
if err = pk.ec.parse(r); err != nil {
return
}
pk.ecdh = new(ecdhKdf)
if err = pk.ecdh.parse(r); err != nil {
return
}
// The ECDH key is stored in an ecdsa.PublicKey for convenience.
pk.PublicKey, err = pk.ec.newECDSA()
default:
err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo)))
}
if err != nil {
return
}
pk.setFingerPrintAndKeyId()
return
}
func (pk *PublicKey) setFingerPrintAndKeyId() {
// RFC 4880, section 12.2
fingerPrint := sha1.New()
pk.SerializeSignaturePrefix(fingerPrint)
pk.serializeWithoutHeaders(fingerPrint)
copy(pk.Fingerprint[:], fingerPrint.Sum(nil))
pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[12:20])
}
// parseRSA parses RSA public key material from the given Reader. See RFC 4880,
// section 5.5.2.
func (pk *PublicKey) parseRSA(r io.Reader) (err error) {
pk.n.bytes, pk.n.bitLength, err = readMPI(r)
if err != nil {
return
}
pk.e.bytes, pk.e.bitLength, err = readMPI(r)
if err != nil {
return
}
if len(pk.e.bytes) > 3 {
err = errors.UnsupportedError("large public exponent")
return
}
rsa := &rsa.PublicKey{
N: new(big.Int).SetBytes(pk.n.bytes),
E: 0,
}
for i := 0; i < len(pk.e.bytes); i++ {
rsa.E <<= 8
rsa.E |= int(pk.e.bytes[i])
}
pk.PublicKey = rsa
return
}
// parseDSA parses DSA public key material from the given Reader. See RFC 4880,
// section 5.5.2.
func (pk *PublicKey) parseDSA(r io.Reader) (err error) {
pk.p.bytes, pk.p.bitLength, err = readMPI(r)
if err != nil {
return
}
pk.q.bytes, pk.q.bitLength, err = readMPI(r)
if err != nil {
return
}
pk.g.bytes, pk.g.bitLength, err = readMPI(r)
if err != nil {
return
}
pk.y.bytes, pk.y.bitLength, err = readMPI(r)
if err != nil {
return
}
dsa := new(dsa.PublicKey)
dsa.P = new(big.Int).SetBytes(pk.p.bytes)
dsa.Q = new(big.Int).SetBytes(pk.q.bytes)
dsa.G = new(big.Int).SetBytes(pk.g.bytes)
dsa.Y = new(big.Int).SetBytes(pk.y.bytes)
pk.PublicKey = dsa
return
}
// parseElGamal parses ElGamal public key material from the given Reader. See
// RFC 4880, section 5.5.2.
func (pk *PublicKey) parseElGamal(r io.Reader) (err error) {
pk.p.bytes, pk.p.bitLength, err = readMPI(r)
if err != nil {
return
}
pk.g.bytes, pk.g.bitLength, err = readMPI(r)
if err != nil {
return
}
pk.y.bytes, pk.y.bitLength, err = readMPI(r)
if err != nil {
return
}
elgamal := new(elgamal.PublicKey)
elgamal.P = new(big.Int).SetBytes(pk.p.bytes)
elgamal.G = new(big.Int).SetBytes(pk.g.bytes)
elgamal.Y = new(big.Int).SetBytes(pk.y.bytes)
pk.PublicKey = elgamal
return
}
// SerializeSignaturePrefix writes the prefix for this public key to the given Writer.
// The prefix is used when calculating a signature over this public key. See
// RFC 4880, section 5.2.4.
func (pk *PublicKey) SerializeSignaturePrefix(h io.Writer) {
var pLength uint16
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
pLength += 2 + uint16(len(pk.n.bytes))
pLength += 2 + uint16(len(pk.e.bytes))
case PubKeyAlgoDSA:
pLength += 2 + uint16(len(pk.p.bytes))
pLength += 2 + uint16(len(pk.q.bytes))
pLength += 2 + uint16(len(pk.g.bytes))
pLength += 2 + uint16(len(pk.y.bytes))
case PubKeyAlgoElGamal:
pLength += 2 + uint16(len(pk.p.bytes))
pLength += 2 + uint16(len(pk.g.bytes))
pLength += 2 + uint16(len(pk.y.bytes))
case PubKeyAlgoECDSA:
pLength += uint16(pk.ec.byteLen())
case PubKeyAlgoECDH:
pLength += uint16(pk.ec.byteLen())
pLength += uint16(pk.ecdh.byteLen())
default:
panic("unknown public key algorithm")
}
pLength += 6
h.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)})
return
}
func (pk *PublicKey) Serialize(w io.Writer) (err error) {
length := 6 // 6 byte header
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
length += 2 + len(pk.n.bytes)
length += 2 + len(pk.e.bytes)
case PubKeyAlgoDSA:
length += 2 + len(pk.p.bytes)
length += 2 + len(pk.q.bytes)
length += 2 + len(pk.g.bytes)
length += 2 + len(pk.y.bytes)
case PubKeyAlgoElGamal:
length += 2 + len(pk.p.bytes)
length += 2 + len(pk.g.bytes)
length += 2 + len(pk.y.bytes)
case PubKeyAlgoECDSA:
length += pk.ec.byteLen()
case PubKeyAlgoECDH:
length += pk.ec.byteLen()
length += pk.ecdh.byteLen()
default:
panic("unknown public key algorithm")
}
packetType := packetTypePublicKey
if pk.IsSubkey {
packetType = packetTypePublicSubkey
}
err = serializeHeader(w, packetType, length)
if err != nil {
return
}
return pk.serializeWithoutHeaders(w)
}
// serializeWithoutHeaders marshals the PublicKey to w in the form of an
// OpenPGP public key packet, not including the packet header.
func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err error) {
var buf [6]byte
buf[0] = 4
t := uint32(pk.CreationTime.Unix())
buf[1] = byte(t >> 24)
buf[2] = byte(t >> 16)
buf[3] = byte(t >> 8)
buf[4] = byte(t)
buf[5] = byte(pk.PubKeyAlgo)
_, err = w.Write(buf[:])
if err != nil {
return
}
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
return writeMPIs(w, pk.n, pk.e)
case PubKeyAlgoDSA:
return writeMPIs(w, pk.p, pk.q, pk.g, pk.y)
case PubKeyAlgoElGamal:
return writeMPIs(w, pk.p, pk.g, pk.y)
case PubKeyAlgoECDSA:
return pk.ec.serialize(w)
case PubKeyAlgoECDH:
if err = pk.ec.serialize(w); err != nil {
return
}
return pk.ecdh.serialize(w)
}
return errors.InvalidArgumentError("bad public-key algorithm")
}
// CanSign returns true iff this public key can generate signatures
func (pk *PublicKey) CanSign() bool {
return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElGamal
}
// VerifySignature returns nil iff sig is a valid signature, made by this
// public key, of the data hashed into signed. signed is mutated by this call.
func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err error) {
if !pk.CanSign() {
return errors.InvalidArgumentError("public key cannot generate signatures")
}
signed.Write(sig.HashSuffix)
hashBytes := signed.Sum(nil)
if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] {
return errors.SignatureError("hash tag doesn't match")
}
if pk.PubKeyAlgo != sig.PubKeyAlgo {
return errors.InvalidArgumentError("public key and signature use different algorithms")
}
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey)
err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, padToKeySize(rsaPublicKey, sig.RSASignature.bytes))
if err != nil {
return errors.SignatureError("RSA verification failure")
}
return nil
case PubKeyAlgoDSA:
dsaPublicKey, _ := pk.PublicKey.(*dsa.PublicKey)
// Need to truncate hashBytes to match FIPS 186-3 section 4.6.
subgroupSize := (dsaPublicKey.Q.BitLen() + 7) / 8
if len(hashBytes) > subgroupSize {
hashBytes = hashBytes[:subgroupSize]
}
if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.bytes), new(big.Int).SetBytes(sig.DSASigS.bytes)) {
return errors.SignatureError("DSA verification failure")
}
return nil
case PubKeyAlgoECDSA:
ecdsaPublicKey := pk.PublicKey.(*ecdsa.PublicKey)
if !ecdsa.Verify(ecdsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.ECDSASigR.bytes), new(big.Int).SetBytes(sig.ECDSASigS.bytes)) {
return errors.SignatureError("ECDSA verification failure")
}
return nil
default:
return errors.SignatureError("Unsupported public key algorithm used in signature")
}
}
// VerifySignatureV3 returns nil iff sig is a valid signature, made by this
// public key, of the data hashed into signed. signed is mutated by this call.
func (pk *PublicKey) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err error) {
if !pk.CanSign() {
return errors.InvalidArgumentError("public key cannot generate signatures")
}
suffix := make([]byte, 5)
suffix[0] = byte(sig.SigType)
binary.BigEndian.PutUint32(suffix[1:], uint32(sig.CreationTime.Unix()))
signed.Write(suffix)
hashBytes := signed.Sum(nil)
if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] {
return errors.SignatureError("hash tag doesn't match")
}
if pk.PubKeyAlgo != sig.PubKeyAlgo {
return errors.InvalidArgumentError("public key and signature use different algorithms")
}
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
rsaPublicKey := pk.PublicKey.(*rsa.PublicKey)
if err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, padToKeySize(rsaPublicKey, sig.RSASignature.bytes)); err != nil {
return errors.SignatureError("RSA verification failure")
}
return
case PubKeyAlgoDSA:
dsaPublicKey := pk.PublicKey.(*dsa.PublicKey)
// Need to truncate hashBytes to match FIPS 186-3 section 4.6.
subgroupSize := (dsaPublicKey.Q.BitLen() + 7) / 8
if len(hashBytes) > subgroupSize {
hashBytes = hashBytes[:subgroupSize]
}
if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.bytes), new(big.Int).SetBytes(sig.DSASigS.bytes)) {
return errors.SignatureError("DSA verification failure")
}
return nil
default:
panic("shouldn't happen")
}
}
// keySignatureHash returns a Hash of the message that needs to be signed for
// pk to assert a subkey relationship to signed.
func keySignatureHash(pk, signed signingKey, hashFunc crypto.Hash) (h hash.Hash, err error) {
if !hashFunc.Available() {
return nil, errors.UnsupportedError("hash function")
}
h = hashFunc.New()
// RFC 4880, section 5.2.4
pk.SerializeSignaturePrefix(h)
pk.serializeWithoutHeaders(h)
signed.SerializeSignaturePrefix(h)
signed.serializeWithoutHeaders(h)
return
}
// VerifyKeySignature returns nil iff sig is a valid signature, made by this
// public key, of signed.
func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) error {
h, err := keySignatureHash(pk, signed, sig.Hash)
if err != nil {
return err
}
if err = pk.VerifySignature(h, sig); err != nil {
return err
}
if sig.FlagSign {
// Signing subkeys must be cross-signed. See
// https://www.gnupg.org/faq/subkey-cross-certify.html.
if sig.EmbeddedSignature == nil {
return errors.StructuralError("signing subkey is missing cross-signature")
}
// Verify the cross-signature. This is calculated over the same
// data as the main signature, so we cannot just recursively
// call signed.VerifyKeySignature(...)
if h, err = keySignatureHash(pk, signed, sig.EmbeddedSignature.Hash); err != nil {
return errors.StructuralError("error while hashing for cross-signature: " + err.Error())
}
if err := signed.VerifySignature(h, sig.EmbeddedSignature); err != nil {
return errors.StructuralError("error while verifying cross-signature: " + err.Error())
}
}
return nil
}
func keyRevocationHash(pk signingKey, hashFunc crypto.Hash) (h hash.Hash, err error) {
if !hashFunc.Available() {
return nil, errors.UnsupportedError("hash function")
}
h = hashFunc.New()
// RFC 4880, section 5.2.4
pk.SerializeSignaturePrefix(h)
pk.serializeWithoutHeaders(h)
return
}
// VerifyRevocationSignature returns nil iff sig is a valid signature, made by this
// public key.
func (pk *PublicKey) VerifyRevocationSignature(sig *Signature) (err error) {
h, err := keyRevocationHash(pk, sig.Hash)
if err != nil {
return err
}
return pk.VerifySignature(h, sig)
}
// userIdSignatureHash returns a Hash of the message that needs to be signed
// to assert that pk is a valid key for id.
func userIdSignatureHash(id string, pk *PublicKey, hashFunc crypto.Hash) (h hash.Hash, err error) {
if !hashFunc.Available() {
return nil, errors.UnsupportedError("hash function")
}
h = hashFunc.New()
// RFC 4880, section 5.2.4
pk.SerializeSignaturePrefix(h)
pk.serializeWithoutHeaders(h)
var buf [5]byte
buf[0] = 0xb4
buf[1] = byte(len(id) >> 24)
buf[2] = byte(len(id) >> 16)
buf[3] = byte(len(id) >> 8)
buf[4] = byte(len(id))
h.Write(buf[:])
h.Write([]byte(id))
return
}
// VerifyUserIdSignature returns nil iff sig is a valid signature, made by this
// public key, that id is the identity of pub.
func (pk *PublicKey) VerifyUserIdSignature(id string, pub *PublicKey, sig *Signature) (err error) {
h, err := userIdSignatureHash(id, pub, sig.Hash)
if err != nil {
return err
}
return pk.VerifySignature(h, sig)
}
// VerifyUserIdSignatureV3 returns nil iff sig is a valid signature, made by this
// public key, that id is the identity of pub.
func (pk *PublicKey) VerifyUserIdSignatureV3(id string, pub *PublicKey, sig *SignatureV3) (err error) {
h, err := userIdSignatureV3Hash(id, pub, sig.Hash)
if err != nil {
return err
}
return pk.VerifySignatureV3(h, sig)
}
// KeyIdString returns the public key's fingerprint in capital hex
// (e.g. "6C7EE1B8621CC013").
func (pk *PublicKey) KeyIdString() string {
return fmt.Sprintf("%X", pk.Fingerprint[12:20])
}
// KeyIdShortString returns the short form of public key's fingerprint
// in capital hex, as shown by gpg --list-keys (e.g. "621CC013").
func (pk *PublicKey) KeyIdShortString() string {
return fmt.Sprintf("%X", pk.Fingerprint[16:20])
}
// A parsedMPI is used to store the contents of a big integer, along with the
// bit length that was specified in the original input. This allows the MPI to
// be reserialized exactly.
type parsedMPI struct {
bytes []byte
bitLength uint16
}
// writeMPIs is a utility function for serializing several big integers to the
// given Writer.
func writeMPIs(w io.Writer, mpis ...parsedMPI) (err error) {
for _, mpi := range mpis {
err = writeMPI(w, mpi.bitLength, mpi.bytes)
if err != nil {
return
}
}
return
}
// BitLength returns the bit length for the given public key.
func (pk *PublicKey) BitLength() (bitLength uint16, err error) {
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
bitLength = pk.n.bitLength
case PubKeyAlgoDSA:
bitLength = pk.p.bitLength
case PubKeyAlgoElGamal:
bitLength = pk.p.bitLength
default:
err = errors.InvalidArgumentError("bad public-key algorithm")
}
return
}
// Copyright 2013 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 packet
import (
"crypto"
"crypto/md5"
"crypto/rsa"
"encoding/binary"
"fmt"
"hash"
"io"
"math/big"
"strconv"
"time"
"golang.org/x/crypto/openpgp/errors"
)
// PublicKeyV3 represents older, version 3 public keys. These keys are less secure and
// should not be used for signing or encrypting. They are supported here only for
// parsing version 3 key material and validating signatures.
// See RFC 4880, section 5.5.2.
type PublicKeyV3 struct {
CreationTime time.Time
DaysToExpire uint16
PubKeyAlgo PublicKeyAlgorithm
PublicKey *rsa.PublicKey
Fingerprint [16]byte
KeyId uint64
IsSubkey bool
n, e parsedMPI
}
// newRSAPublicKeyV3 returns a PublicKey that wraps the given rsa.PublicKey.
// Included here for testing purposes only. RFC 4880, section 5.5.2:
// "an implementation MUST NOT generate a V3 key, but MAY accept it."
func newRSAPublicKeyV3(creationTime time.Time, pub *rsa.PublicKey) *PublicKeyV3 {
pk := &PublicKeyV3{
CreationTime: creationTime,
PublicKey: pub,
n: fromBig(pub.N),
e: fromBig(big.NewInt(int64(pub.E))),
}
pk.setFingerPrintAndKeyId()
return pk
}
func (pk *PublicKeyV3) parse(r io.Reader) (err error) {
// RFC 4880, section 5.5.2
var buf [8]byte
if _, err = readFull(r, buf[:]); err != nil {
return
}
if buf[0] < 2 || buf[0] > 3 {
return errors.UnsupportedError("public key version")
}
pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0)
pk.DaysToExpire = binary.BigEndian.Uint16(buf[5:7])
pk.PubKeyAlgo = PublicKeyAlgorithm(buf[7])
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
err = pk.parseRSA(r)
default:
err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo)))
}
if err != nil {
return
}
pk.setFingerPrintAndKeyId()
return
}
func (pk *PublicKeyV3) setFingerPrintAndKeyId() {
// RFC 4880, section 12.2
fingerPrint := md5.New()
fingerPrint.Write(pk.n.bytes)
fingerPrint.Write(pk.e.bytes)
fingerPrint.Sum(pk.Fingerprint[:0])
pk.KeyId = binary.BigEndian.Uint64(pk.n.bytes[len(pk.n.bytes)-8:])
}
// parseRSA parses RSA public key material from the given Reader. See RFC 4880,
// section 5.5.2.
func (pk *PublicKeyV3) parseRSA(r io.Reader) (err error) {
if pk.n.bytes, pk.n.bitLength, err = readMPI(r); err != nil {
return
}
if pk.e.bytes, pk.e.bitLength, err = readMPI(r); err != nil {
return
}
// RFC 4880 Section 12.2 requires the low 8 bytes of the
// modulus to form the key id.
if len(pk.n.bytes) < 8 {
return errors.StructuralError("v3 public key modulus is too short")
}
if len(pk.e.bytes) > 3 {
err = errors.UnsupportedError("large public exponent")
return
}
rsa := &rsa.PublicKey{N: new(big.Int).SetBytes(pk.n.bytes)}
for i := 0; i < len(pk.e.bytes); i++ {
rsa.E <<= 8
rsa.E |= int(pk.e.bytes[i])
}
pk.PublicKey = rsa
return
}
// SerializeSignaturePrefix writes the prefix for this public key to the given Writer.
// The prefix is used when calculating a signature over this public key. See
// RFC 4880, section 5.2.4.
func (pk *PublicKeyV3) SerializeSignaturePrefix(w io.Writer) {
var pLength uint16
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
pLength += 2 + uint16(len(pk.n.bytes))
pLength += 2 + uint16(len(pk.e.bytes))
default:
panic("unknown public key algorithm")
}
pLength += 6
w.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)})
return
}
func (pk *PublicKeyV3) Serialize(w io.Writer) (err error) {
length := 8 // 8 byte header
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
length += 2 + len(pk.n.bytes)
length += 2 + len(pk.e.bytes)
default:
panic("unknown public key algorithm")
}
packetType := packetTypePublicKey
if pk.IsSubkey {
packetType = packetTypePublicSubkey
}
if err = serializeHeader(w, packetType, length); err != nil {
return
}
return pk.serializeWithoutHeaders(w)
}
// serializeWithoutHeaders marshals the PublicKey to w in the form of an
// OpenPGP public key packet, not including the packet header.
func (pk *PublicKeyV3) serializeWithoutHeaders(w io.Writer) (err error) {
var buf [8]byte
// Version 3
buf[0] = 3
// Creation time
t := uint32(pk.CreationTime.Unix())
buf[1] = byte(t >> 24)
buf[2] = byte(t >> 16)
buf[3] = byte(t >> 8)
buf[4] = byte(t)
// Days to expire
buf[5] = byte(pk.DaysToExpire >> 8)
buf[6] = byte(pk.DaysToExpire)
// Public key algorithm
buf[7] = byte(pk.PubKeyAlgo)
if _, err = w.Write(buf[:]); err != nil {
return
}
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
return writeMPIs(w, pk.n, pk.e)
}
return errors.InvalidArgumentError("bad public-key algorithm")
}
// CanSign returns true iff this public key can generate signatures
func (pk *PublicKeyV3) CanSign() bool {
return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly
}
// VerifySignatureV3 returns nil iff sig is a valid signature, made by this
// public key, of the data hashed into signed. signed is mutated by this call.
func (pk *PublicKeyV3) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err error) {
if !pk.CanSign() {
return errors.InvalidArgumentError("public key cannot generate signatures")
}
suffix := make([]byte, 5)
suffix[0] = byte(sig.SigType)
binary.BigEndian.PutUint32(suffix[1:], uint32(sig.CreationTime.Unix()))
signed.Write(suffix)
hashBytes := signed.Sum(nil)
if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] {
return errors.SignatureError("hash tag doesn't match")
}
if pk.PubKeyAlgo != sig.PubKeyAlgo {
return errors.InvalidArgumentError("public key and signature use different algorithms")
}
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
if err = rsa.VerifyPKCS1v15(pk.PublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes); err != nil {
return errors.SignatureError("RSA verification failure")
}
return
default:
// V3 public keys only support RSA.
panic("shouldn't happen")
}
}
// VerifyUserIdSignatureV3 returns nil iff sig is a valid signature, made by this
// public key, that id is the identity of pub.
func (pk *PublicKeyV3) VerifyUserIdSignatureV3(id string, pub *PublicKeyV3, sig *SignatureV3) (err error) {
h, err := userIdSignatureV3Hash(id, pk, sig.Hash)
if err != nil {
return err
}
return pk.VerifySignatureV3(h, sig)
}
// VerifyKeySignatureV3 returns nil iff sig is a valid signature, made by this
// public key, of signed.
func (pk *PublicKeyV3) VerifyKeySignatureV3(signed *PublicKeyV3, sig *SignatureV3) (err error) {
h, err := keySignatureHash(pk, signed, sig.Hash)
if err != nil {
return err
}
return pk.VerifySignatureV3(h, sig)
}
// userIdSignatureV3Hash returns a Hash of the message that needs to be signed
// to assert that pk is a valid key for id.
func userIdSignatureV3Hash(id string, pk signingKey, hfn crypto.Hash) (h hash.Hash, err error) {
if !hfn.Available() {
return nil, errors.UnsupportedError("hash function")
}
h = hfn.New()
// RFC 4880, section 5.2.4
pk.SerializeSignaturePrefix(h)
pk.serializeWithoutHeaders(h)
h.Write([]byte(id))
return
}
// KeyIdString returns the public key's fingerprint in capital hex
// (e.g. "6C7EE1B8621CC013").
func (pk *PublicKeyV3) KeyIdString() string {
return fmt.Sprintf("%X", pk.KeyId)
}
// KeyIdShortString returns the short form of public key's fingerprint
// in capital hex, as shown by gpg --list-keys (e.g. "621CC013").
func (pk *PublicKeyV3) KeyIdShortString() string {
return fmt.Sprintf("%X", pk.KeyId&0xFFFFFFFF)
}
// BitLength returns the bit length for the given public key.
func (pk *PublicKeyV3) BitLength() (bitLength uint16, err error) {
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
bitLength = pk.n.bitLength
default:
err = errors.InvalidArgumentError("bad public-key algorithm")
}
return
}
// Copyright 2011 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 packet
import (
"golang.org/x/crypto/openpgp/errors"
"io"
)
// Reader reads packets from an io.Reader and allows packets to be 'unread' so
// that they result from the next call to Next.
type Reader struct {
q []Packet
readers []io.Reader
}
// New io.Readers are pushed when a compressed or encrypted packet is processed
// and recursively treated as a new source of packets. However, a carefully
// crafted packet can trigger an infinite recursive sequence of packets. See
// http://mumble.net/~campbell/misc/pgp-quine
// https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2013-4402
// This constant limits the number of recursive packets that may be pushed.
const maxReaders = 32
// Next returns the most recently unread Packet, or reads another packet from
// the top-most io.Reader. Unknown packet types are skipped.
func (r *Reader) Next() (p Packet, err error) {
if len(r.q) > 0 {
p = r.q[len(r.q)-1]
r.q = r.q[:len(r.q)-1]
return
}
for len(r.readers) > 0 {
p, err = Read(r.readers[len(r.readers)-1])
if err == nil {
return
}
if err == io.EOF {
r.readers = r.readers[:len(r.readers)-1]
continue
}
if _, ok := err.(errors.UnknownPacketTypeError); !ok {
return nil, err
}
}
return nil, io.EOF
}
// Push causes the Reader to start reading from a new io.Reader. When an EOF
// error is seen from the new io.Reader, it is popped and the Reader continues
// to read from the next most recent io.Reader. Push returns a StructuralError
// if pushing the reader would exceed the maximum recursion level, otherwise it
// returns nil.
func (r *Reader) Push(reader io.Reader) (err error) {
if len(r.readers) >= maxReaders {
return errors.StructuralError("too many layers of packets")
}
r.readers = append(r.readers, reader)
return nil
}
// Unread causes the given Packet to be returned from the next call to Next.
func (r *Reader) Unread(p Packet) {
r.q = append(r.q, p)
}
func NewReader(r io.Reader) *Reader {
return &Reader{
q: nil,
readers: []io.Reader{r},
}
}
// Copyright 2011 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 packet
import (
"bytes"
"crypto"
"crypto/dsa"
"crypto/ecdsa"
"encoding/asn1"
"encoding/binary"
"hash"
"io"
"math/big"
"strconv"
"time"
"golang.org/x/crypto/openpgp/errors"
"golang.org/x/crypto/openpgp/s2k"
)
const (
// See RFC 4880, section 5.2.3.21 for details.
KeyFlagCertify = 1 << iota
KeyFlagSign
KeyFlagEncryptCommunications
KeyFlagEncryptStorage
)
// Signature represents a signature. See RFC 4880, section 5.2.
type Signature struct {
SigType SignatureType
PubKeyAlgo PublicKeyAlgorithm
Hash crypto.Hash
// HashSuffix is extra data that is hashed in after the signed data.
HashSuffix []byte
// HashTag contains the first two bytes of the hash for fast rejection
// of bad signed data.
HashTag [2]byte
CreationTime time.Time
RSASignature parsedMPI
DSASigR, DSASigS parsedMPI
ECDSASigR, ECDSASigS parsedMPI
// rawSubpackets contains the unparsed subpackets, in order.
rawSubpackets []outputSubpacket
// The following are optional so are nil when not included in the
// signature.
SigLifetimeSecs, KeyLifetimeSecs *uint32
PreferredSymmetric, PreferredHash, PreferredCompression []uint8
IssuerKeyId *uint64
IsPrimaryId *bool
// FlagsValid is set if any flags were given. See RFC 4880, section
// 5.2.3.21 for details.
FlagsValid bool
FlagCertify, FlagSign, FlagEncryptCommunications, FlagEncryptStorage bool
// RevocationReason is set if this signature has been revoked.
// See RFC 4880, section 5.2.3.23 for details.
RevocationReason *uint8
RevocationReasonText string
// MDC is set if this signature has a feature packet that indicates
// support for MDC subpackets.
MDC bool
// EmbeddedSignature, if non-nil, is a signature of the parent key, by
// this key. This prevents an attacker from claiming another's signing
// subkey as their own.
EmbeddedSignature *Signature
outSubpackets []outputSubpacket
}
func (sig *Signature) parse(r io.Reader) (err error) {
// RFC 4880, section 5.2.3
var buf [5]byte
_, err = readFull(r, buf[:1])
if err != nil {
return
}
if buf[0] != 4 {
err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0])))
return
}
_, err = readFull(r, buf[:5])
if err != nil {
return
}
sig.SigType = SignatureType(buf[0])
sig.PubKeyAlgo = PublicKeyAlgorithm(buf[1])
switch sig.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA:
default:
err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo)))
return
}
var ok bool
sig.Hash, ok = s2k.HashIdToHash(buf[2])
if !ok {
return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2])))
}
hashedSubpacketsLength := int(buf[3])<<8 | int(buf[4])
l := 6 + hashedSubpacketsLength
sig.HashSuffix = make([]byte, l+6)
sig.HashSuffix[0] = 4
copy(sig.HashSuffix[1:], buf[:5])
hashedSubpackets := sig.HashSuffix[6:l]
_, err = readFull(r, hashedSubpackets)
if err != nil {
return
}
// See RFC 4880, section 5.2.4
trailer := sig.HashSuffix[l:]
trailer[0] = 4
trailer[1] = 0xff
trailer[2] = uint8(l >> 24)
trailer[3] = uint8(l >> 16)
trailer[4] = uint8(l >> 8)
trailer[5] = uint8(l)
err = parseSignatureSubpackets(sig, hashedSubpackets, true)
if err != nil {
return
}
_, err = readFull(r, buf[:2])
if err != nil {
return
}
unhashedSubpacketsLength := int(buf[0])<<8 | int(buf[1])
unhashedSubpackets := make([]byte, unhashedSubpacketsLength)
_, err = readFull(r, unhashedSubpackets)
if err != nil {
return
}
err = parseSignatureSubpackets(sig, unhashedSubpackets, false)
if err != nil {
return
}
_, err = readFull(r, sig.HashTag[:2])
if err != nil {
return
}
switch sig.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r)
case PubKeyAlgoDSA:
sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r)
if err == nil {
sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r)
}
case PubKeyAlgoECDSA:
sig.ECDSASigR.bytes, sig.ECDSASigR.bitLength, err = readMPI(r)
if err == nil {
sig.ECDSASigS.bytes, sig.ECDSASigS.bitLength, err = readMPI(r)
}
default:
panic("unreachable")
}
return
}
// parseSignatureSubpackets parses subpackets of the main signature packet. See
// RFC 4880, section 5.2.3.1.
func parseSignatureSubpackets(sig *Signature, subpackets []byte, isHashed bool) (err error) {
for len(subpackets) > 0 {
subpackets, err = parseSignatureSubpacket(sig, subpackets, isHashed)
if err != nil {
return
}
}
if sig.CreationTime.IsZero() {
err = errors.StructuralError("no creation time in signature")
}
return
}
type signatureSubpacketType uint8
const (
creationTimeSubpacket signatureSubpacketType = 2
signatureExpirationSubpacket signatureSubpacketType = 3
keyExpirationSubpacket signatureSubpacketType = 9
prefSymmetricAlgosSubpacket signatureSubpacketType = 11
issuerSubpacket signatureSubpacketType = 16
prefHashAlgosSubpacket signatureSubpacketType = 21
prefCompressionSubpacket signatureSubpacketType = 22
primaryUserIdSubpacket signatureSubpacketType = 25
keyFlagsSubpacket signatureSubpacketType = 27
reasonForRevocationSubpacket signatureSubpacketType = 29
featuresSubpacket signatureSubpacketType = 30
embeddedSignatureSubpacket signatureSubpacketType = 32
)
// parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1.
func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (rest []byte, err error) {
// RFC 4880, section 5.2.3.1
var (
length uint32
packetType signatureSubpacketType
isCritical bool
)
switch {
case subpacket[0] < 192:
length = uint32(subpacket[0])
subpacket = subpacket[1:]
case subpacket[0] < 255:
if len(subpacket) < 2 {
goto Truncated
}
length = uint32(subpacket[0]-192)<<8 + uint32(subpacket[1]) + 192
subpacket = subpacket[2:]
default:
if len(subpacket) < 5 {
goto Truncated
}
length = uint32(subpacket[1])<<24 |
uint32(subpacket[2])<<16 |
uint32(subpacket[3])<<8 |
uint32(subpacket[4])
subpacket = subpacket[5:]
}
if length > uint32(len(subpacket)) {
goto Truncated
}
rest = subpacket[length:]
subpacket = subpacket[:length]
if len(subpacket) == 0 {
err = errors.StructuralError("zero length signature subpacket")
return
}
packetType = signatureSubpacketType(subpacket[0] & 0x7f)
isCritical = subpacket[0]&0x80 == 0x80
subpacket = subpacket[1:]
sig.rawSubpackets = append(sig.rawSubpackets, outputSubpacket{isHashed, packetType, isCritical, subpacket})
switch packetType {
case creationTimeSubpacket:
if !isHashed {
err = errors.StructuralError("signature creation time in non-hashed area")
return
}
if len(subpacket) != 4 {
err = errors.StructuralError("signature creation time not four bytes")
return
}
t := binary.BigEndian.Uint32(subpacket)
sig.CreationTime = time.Unix(int64(t), 0)
case signatureExpirationSubpacket:
// Signature expiration time, section 5.2.3.10
if !isHashed {
return
}
if len(subpacket) != 4 {
err = errors.StructuralError("expiration subpacket with bad length")
return
}
sig.SigLifetimeSecs = new(uint32)
*sig.SigLifetimeSecs = binary.BigEndian.Uint32(subpacket)
case keyExpirationSubpacket:
// Key expiration time, section 5.2.3.6
if !isHashed {
return
}
if len(subpacket) != 4 {
err = errors.StructuralError("key expiration subpacket with bad length")
return
}
sig.KeyLifetimeSecs = new(uint32)
*sig.KeyLifetimeSecs = binary.BigEndian.Uint32(subpacket)
case prefSymmetricAlgosSubpacket:
// Preferred symmetric algorithms, section 5.2.3.7
if !isHashed {
return
}
sig.PreferredSymmetric = make([]byte, len(subpacket))
copy(sig.PreferredSymmetric, subpacket)
case issuerSubpacket:
// Issuer, section 5.2.3.5
if len(subpacket) != 8 {
err = errors.StructuralError("issuer subpacket with bad length")
return
}
sig.IssuerKeyId = new(uint64)
*sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket)
case prefHashAlgosSubpacket:
// Preferred hash algorithms, section 5.2.3.8
if !isHashed {
return
}
sig.PreferredHash = make([]byte, len(subpacket))
copy(sig.PreferredHash, subpacket)
case prefCompressionSubpacket:
// Preferred compression algorithms, section 5.2.3.9
if !isHashed {
return
}
sig.PreferredCompression = make([]byte, len(subpacket))
copy(sig.PreferredCompression, subpacket)
case primaryUserIdSubpacket:
// Primary User ID, section 5.2.3.19
if !isHashed {
return
}
if len(subpacket) != 1 {
err = errors.StructuralError("primary user id subpacket with bad length")
return
}
sig.IsPrimaryId = new(bool)
if subpacket[0] > 0 {
*sig.IsPrimaryId = true
}
case keyFlagsSubpacket:
// Key flags, section 5.2.3.21
if !isHashed {
return
}
if len(subpacket) == 0 {
err = errors.StructuralError("empty key flags subpacket")
return
}
sig.FlagsValid = true
if subpacket[0]&KeyFlagCertify != 0 {
sig.FlagCertify = true
}
if subpacket[0]&KeyFlagSign != 0 {
sig.FlagSign = true
}
if subpacket[0]&KeyFlagEncryptCommunications != 0 {
sig.FlagEncryptCommunications = true
}
if subpacket[0]&KeyFlagEncryptStorage != 0 {
sig.FlagEncryptStorage = true
}
case reasonForRevocationSubpacket:
// Reason For Revocation, section 5.2.3.23
if !isHashed {
return
}
if len(subpacket) == 0 {
err = errors.StructuralError("empty revocation reason subpacket")
return
}
sig.RevocationReason = new(uint8)
*sig.RevocationReason = subpacket[0]
sig.RevocationReasonText = string(subpacket[1:])
case featuresSubpacket:
// Features subpacket, section 5.2.3.24 specifies a very general
// mechanism for OpenPGP implementations to signal support for new
// features. In practice, the subpacket is used exclusively to
// indicate support for MDC-protected encryption.
sig.MDC = len(subpacket) >= 1 && subpacket[0]&1 == 1
case embeddedSignatureSubpacket:
// Only usage is in signatures that cross-certify
// signing subkeys. section 5.2.3.26 describes the
// format, with its usage described in section 11.1
if sig.EmbeddedSignature != nil {
err = errors.StructuralError("Cannot have multiple embedded signatures")
return
}
sig.EmbeddedSignature = new(Signature)
// Embedded signatures are required to be v4 signatures see
// section 12.1. However, we only parse v4 signatures in this
// file anyway.
if err := sig.EmbeddedSignature.parse(bytes.NewBuffer(subpacket)); err != nil {
return nil, err
}
if sigType := sig.EmbeddedSignature.SigType; sigType != SigTypePrimaryKeyBinding {
return nil, errors.StructuralError("cross-signature has unexpected type " + strconv.Itoa(int(sigType)))
}
default:
if isCritical {
err = errors.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType)))
return
}
}
return
Truncated:
err = errors.StructuralError("signature subpacket truncated")
return
}
// subpacketLengthLength returns the length, in bytes, of an encoded length value.
func subpacketLengthLength(length int) int {
if length < 192 {
return 1
}
if length < 16320 {
return 2
}
return 5
}
// serializeSubpacketLength marshals the given length into to.
func serializeSubpacketLength(to []byte, length int) int {
// RFC 4880, Section 4.2.2.
if length < 192 {
to[0] = byte(length)
return 1
}
if length < 16320 {
length -= 192
to[0] = byte((length >> 8) + 192)
to[1] = byte(length)
return 2
}
to[0] = 255
to[1] = byte(length >> 24)
to[2] = byte(length >> 16)
to[3] = byte(length >> 8)
to[4] = byte(length)
return 5
}
// subpacketsLength returns the serialized length, in bytes, of the given
// subpackets.
func subpacketsLength(subpackets []outputSubpacket, hashed bool) (length int) {
for _, subpacket := range subpackets {
if subpacket.hashed == hashed {
length += subpacketLengthLength(len(subpacket.contents) + 1)
length += 1 // type byte
length += len(subpacket.contents)
}
}
return
}
// serializeSubpackets marshals the given subpackets into to.
func serializeSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) {
for _, subpacket := range subpackets {
if subpacket.hashed == hashed {
n := serializeSubpacketLength(to, len(subpacket.contents)+1)
to[n] = byte(subpacket.subpacketType)
to = to[1+n:]
n = copy(to, subpacket.contents)
to = to[n:]
}
}
return
}
// KeyExpired returns whether sig is a self-signature of a key that has
// expired.
func (sig *Signature) KeyExpired(currentTime time.Time) bool {
if sig.KeyLifetimeSecs == nil {
return false
}
expiry := sig.CreationTime.Add(time.Duration(*sig.KeyLifetimeSecs) * time.Second)
return currentTime.After(expiry)
}
// buildHashSuffix constructs the HashSuffix member of sig in preparation for signing.
func (sig *Signature) buildHashSuffix() (err error) {
hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true)
var ok bool
l := 6 + hashedSubpacketsLen
sig.HashSuffix = make([]byte, l+6)
sig.HashSuffix[0] = 4
sig.HashSuffix[1] = uint8(sig.SigType)
sig.HashSuffix[2] = uint8(sig.PubKeyAlgo)
sig.HashSuffix[3], ok = s2k.HashToHashId(sig.Hash)
if !ok {
sig.HashSuffix = nil
return errors.InvalidArgumentError("hash cannot be represented in OpenPGP: " + strconv.Itoa(int(sig.Hash)))
}
sig.HashSuffix[4] = byte(hashedSubpacketsLen >> 8)
sig.HashSuffix[5] = byte(hashedSubpacketsLen)
serializeSubpackets(sig.HashSuffix[6:l], sig.outSubpackets, true)
trailer := sig.HashSuffix[l:]
trailer[0] = 4
trailer[1] = 0xff
trailer[2] = byte(l >> 24)
trailer[3] = byte(l >> 16)
trailer[4] = byte(l >> 8)
trailer[5] = byte(l)
return
}
func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err error) {
err = sig.buildHashSuffix()
if err != nil {
return
}
h.Write(sig.HashSuffix)
digest = h.Sum(nil)
copy(sig.HashTag[:], digest)
return
}
// Sign signs a message with a private key. The hash, h, must contain
// the hash of the message to be signed and will be mutated by this function.
// On success, the signature is stored in sig. Call Serialize to write it out.
// If config is nil, sensible defaults will be used.
func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err error) {
sig.outSubpackets = sig.buildSubpackets()
digest, err := sig.signPrepareHash(h)
if err != nil {
return
}
switch priv.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
// supports both *rsa.PrivateKey and crypto.Signer
sig.RSASignature.bytes, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash)
sig.RSASignature.bitLength = uint16(8 * len(sig.RSASignature.bytes))
case PubKeyAlgoDSA:
dsaPriv := priv.PrivateKey.(*dsa.PrivateKey)
// Need to truncate hashBytes to match FIPS 186-3 section 4.6.
subgroupSize := (dsaPriv.Q.BitLen() + 7) / 8
if len(digest) > subgroupSize {
digest = digest[:subgroupSize]
}
r, s, err := dsa.Sign(config.Random(), dsaPriv, digest)
if err == nil {
sig.DSASigR.bytes = r.Bytes()
sig.DSASigR.bitLength = uint16(8 * len(sig.DSASigR.bytes))
sig.DSASigS.bytes = s.Bytes()
sig.DSASigS.bitLength = uint16(8 * len(sig.DSASigS.bytes))
}
case PubKeyAlgoECDSA:
var r, s *big.Int
if pk, ok := priv.PrivateKey.(*ecdsa.PrivateKey); ok {
// direct support, avoid asn1 wrapping/unwrapping
r, s, err = ecdsa.Sign(config.Random(), pk, digest)
} else {
var b []byte
b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash)
if err == nil {
r, s, err = unwrapECDSASig(b)
}
}
if err == nil {
sig.ECDSASigR = fromBig(r)
sig.ECDSASigS = fromBig(s)
}
default:
err = errors.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo)))
}
return
}
// unwrapECDSASig parses the two integer components of an ASN.1-encoded ECDSA
// signature.
func unwrapECDSASig(b []byte) (r, s *big.Int, err error) {
var ecsdaSig struct {
R, S *big.Int
}
_, err = asn1.Unmarshal(b, &ecsdaSig)
if err != nil {
return
}
return ecsdaSig.R, ecsdaSig.S, nil
}
// SignUserId computes a signature from priv, asserting that pub is a valid
// key for the identity id. On success, the signature is stored in sig. Call
// Serialize to write it out.
// If config is nil, sensible defaults will be used.
func (sig *Signature) SignUserId(id string, pub *PublicKey, priv *PrivateKey, config *Config) error {
h, err := userIdSignatureHash(id, pub, sig.Hash)
if err != nil {
return err
}
return sig.Sign(h, priv, config)
}
// SignKey computes a signature from priv, asserting that pub is a subkey. On
// success, the signature is stored in sig. Call Serialize to write it out.
// If config is nil, sensible defaults will be used.
func (sig *Signature) SignKey(pub *PublicKey, priv *PrivateKey, config *Config) error {
h, err := keySignatureHash(&priv.PublicKey, pub, sig.Hash)
if err != nil {
return err
}
return sig.Sign(h, priv, config)
}
// Serialize marshals sig to w. Sign, SignUserId or SignKey must have been
// called first.
func (sig *Signature) Serialize(w io.Writer) (err error) {
if len(sig.outSubpackets) == 0 {
sig.outSubpackets = sig.rawSubpackets
}
if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil && sig.ECDSASigR.bytes == nil {
return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize")
}
sigLength := 0
switch sig.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
sigLength = 2 + len(sig.RSASignature.bytes)
case PubKeyAlgoDSA:
sigLength = 2 + len(sig.DSASigR.bytes)
sigLength += 2 + len(sig.DSASigS.bytes)
case PubKeyAlgoECDSA:
sigLength = 2 + len(sig.ECDSASigR.bytes)
sigLength += 2 + len(sig.ECDSASigS.bytes)
default:
panic("impossible")
}
unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false)
length := len(sig.HashSuffix) - 6 /* trailer not included */ +
2 /* length of unhashed subpackets */ + unhashedSubpacketsLen +
2 /* hash tag */ + sigLength
err = serializeHeader(w, packetTypeSignature, length)
if err != nil {
return
}
_, err = w.Write(sig.HashSuffix[:len(sig.HashSuffix)-6])
if err != nil {
return
}
unhashedSubpackets := make([]byte, 2+unhashedSubpacketsLen)
unhashedSubpackets[0] = byte(unhashedSubpacketsLen >> 8)
unhashedSubpackets[1] = byte(unhashedSubpacketsLen)
serializeSubpackets(unhashedSubpackets[2:], sig.outSubpackets, false)
_, err = w.Write(unhashedSubpackets)
if err != nil {
return
}
_, err = w.Write(sig.HashTag[:])
if err != nil {
return
}
switch sig.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
err = writeMPIs(w, sig.RSASignature)
case PubKeyAlgoDSA:
err = writeMPIs(w, sig.DSASigR, sig.DSASigS)
case PubKeyAlgoECDSA:
err = writeMPIs(w, sig.ECDSASigR, sig.ECDSASigS)
default:
panic("impossible")
}
return
}
// outputSubpacket represents a subpacket to be marshaled.
type outputSubpacket struct {
hashed bool // true if this subpacket is in the hashed area.
subpacketType signatureSubpacketType
isCritical bool
contents []byte
}
func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) {
creationTime := make([]byte, 4)
binary.BigEndian.PutUint32(creationTime, uint32(sig.CreationTime.Unix()))
subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime})
if sig.IssuerKeyId != nil {
keyId := make([]byte, 8)
binary.BigEndian.PutUint64(keyId, *sig.IssuerKeyId)
subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, false, keyId})
}
if sig.SigLifetimeSecs != nil && *sig.SigLifetimeSecs != 0 {
sigLifetime := make([]byte, 4)
binary.BigEndian.PutUint32(sigLifetime, *sig.SigLifetimeSecs)
subpackets = append(subpackets, outputSubpacket{true, signatureExpirationSubpacket, true, sigLifetime})
}
// Key flags may only appear in self-signatures or certification signatures.
if sig.FlagsValid {
var flags byte
if sig.FlagCertify {
flags |= KeyFlagCertify
}
if sig.FlagSign {
flags |= KeyFlagSign
}
if sig.FlagEncryptCommunications {
flags |= KeyFlagEncryptCommunications
}
if sig.FlagEncryptStorage {
flags |= KeyFlagEncryptStorage
}
subpackets = append(subpackets, outputSubpacket{true, keyFlagsSubpacket, false, []byte{flags}})
}
// The following subpackets may only appear in self-signatures
if sig.KeyLifetimeSecs != nil && *sig.KeyLifetimeSecs != 0 {
keyLifetime := make([]byte, 4)
binary.BigEndian.PutUint32(keyLifetime, *sig.KeyLifetimeSecs)
subpackets = append(subpackets, outputSubpacket{true, keyExpirationSubpacket, true, keyLifetime})
}
if sig.IsPrimaryId != nil && *sig.IsPrimaryId {
subpackets = append(subpackets, outputSubpacket{true, primaryUserIdSubpacket, false, []byte{1}})
}
if len(sig.PreferredSymmetric) > 0 {
subpackets = append(subpackets, outputSubpacket{true, prefSymmetricAlgosSubpacket, false, sig.PreferredSymmetric})
}
if len(sig.PreferredHash) > 0 {
subpackets = append(subpackets, outputSubpacket{true, prefHashAlgosSubpacket, false, sig.PreferredHash})
}
if len(sig.PreferredCompression) > 0 {
subpackets = append(subpackets, outputSubpacket{true, prefCompressionSubpacket, false, sig.PreferredCompression})
}
return
}
// Copyright 2013 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 packet
import (
"crypto"
"encoding/binary"
"fmt"
"io"
"strconv"
"time"
"golang.org/x/crypto/openpgp/errors"
"golang.org/x/crypto/openpgp/s2k"
)
// SignatureV3 represents older version 3 signatures. These signatures are less secure
// than version 4 and should not be used to create new signatures. They are included
// here for backwards compatibility to read and validate with older key material.
// See RFC 4880, section 5.2.2.
type SignatureV3 struct {
SigType SignatureType
CreationTime time.Time
IssuerKeyId uint64
PubKeyAlgo PublicKeyAlgorithm
Hash crypto.Hash
HashTag [2]byte
RSASignature parsedMPI
DSASigR, DSASigS parsedMPI
}
func (sig *SignatureV3) parse(r io.Reader) (err error) {
// RFC 4880, section 5.2.2
var buf [8]byte
if _, err = readFull(r, buf[:1]); err != nil {
return
}
if buf[0] < 2 || buf[0] > 3 {
err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0])))
return
}
if _, err = readFull(r, buf[:1]); err != nil {
return
}
if buf[0] != 5 {
err = errors.UnsupportedError(
"invalid hashed material length " + strconv.Itoa(int(buf[0])))
return
}
// Read hashed material: signature type + creation time
if _, err = readFull(r, buf[:5]); err != nil {
return
}
sig.SigType = SignatureType(buf[0])
t := binary.BigEndian.Uint32(buf[1:5])
sig.CreationTime = time.Unix(int64(t), 0)
// Eight-octet Key ID of signer.
if _, err = readFull(r, buf[:8]); err != nil {
return
}
sig.IssuerKeyId = binary.BigEndian.Uint64(buf[:])
// Public-key and hash algorithm
if _, err = readFull(r, buf[:2]); err != nil {
return
}
sig.PubKeyAlgo = PublicKeyAlgorithm(buf[0])
switch sig.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA:
default:
err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo)))
return
}
var ok bool
if sig.Hash, ok = s2k.HashIdToHash(buf[1]); !ok {
return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2])))
}
// Two-octet field holding left 16 bits of signed hash value.
if _, err = readFull(r, sig.HashTag[:2]); err != nil {
return
}
switch sig.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r)
case PubKeyAlgoDSA:
if sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r); err != nil {
return
}
sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r)
default:
panic("unreachable")
}
return
}
// Serialize marshals sig to w. Sign, SignUserId or SignKey must have been
// called first.
func (sig *SignatureV3) Serialize(w io.Writer) (err error) {
buf := make([]byte, 8)
// Write the sig type and creation time
buf[0] = byte(sig.SigType)
binary.BigEndian.PutUint32(buf[1:5], uint32(sig.CreationTime.Unix()))
if _, err = w.Write(buf[:5]); err != nil {
return
}
// Write the issuer long key ID
binary.BigEndian.PutUint64(buf[:8], sig.IssuerKeyId)
if _, err = w.Write(buf[:8]); err != nil {
return
}
// Write public key algorithm, hash ID, and hash value
buf[0] = byte(sig.PubKeyAlgo)
hashId, ok := s2k.HashToHashId(sig.Hash)
if !ok {
return errors.UnsupportedError(fmt.Sprintf("hash function %v", sig.Hash))
}
buf[1] = hashId
copy(buf[2:4], sig.HashTag[:])
if _, err = w.Write(buf[:4]); err != nil {
return
}
if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil {
return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize")
}
switch sig.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
err = writeMPIs(w, sig.RSASignature)
case PubKeyAlgoDSA:
err = writeMPIs(w, sig.DSASigR, sig.DSASigS)
default:
panic("impossible")
}
return
}
// Copyright 2011 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 packet
import (
"bytes"
"crypto/cipher"
"io"
"strconv"
"golang.org/x/crypto/openpgp/errors"
"golang.org/x/crypto/openpgp/s2k"
)
// This is the largest session key that we'll support. Since no 512-bit cipher
// has even been seriously used, this is comfortably large.
const maxSessionKeySizeInBytes = 64
// SymmetricKeyEncrypted represents a passphrase protected session key. See RFC
// 4880, section 5.3.
type SymmetricKeyEncrypted struct {
CipherFunc CipherFunction
s2k func(out, in []byte)
encryptedKey []byte
}
const symmetricKeyEncryptedVersion = 4
func (ske *SymmetricKeyEncrypted) parse(r io.Reader) error {
// RFC 4880, section 5.3.
var buf [2]byte
if _, err := readFull(r, buf[:]); err != nil {
return err
}
if buf[0] != symmetricKeyEncryptedVersion {
return errors.UnsupportedError("SymmetricKeyEncrypted version")
}
ske.CipherFunc = CipherFunction(buf[1])
if ske.CipherFunc.KeySize() == 0 {
return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1])))
}
var err error
ske.s2k, err = s2k.Parse(r)
if err != nil {
return err
}
encryptedKey := make([]byte, maxSessionKeySizeInBytes)
// The session key may follow. We just have to try and read to find
// out. If it exists then we limit it to maxSessionKeySizeInBytes.
n, err := readFull(r, encryptedKey)
if err != nil && err != io.ErrUnexpectedEOF {
return err
}
if n != 0 {
if n == maxSessionKeySizeInBytes {
return errors.UnsupportedError("oversized encrypted session key")
}
ske.encryptedKey = encryptedKey[:n]
}
return nil
}
// Decrypt attempts to decrypt an encrypted session key and returns the key and
// the cipher to use when decrypting a subsequent Symmetrically Encrypted Data
// packet.
func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) ([]byte, CipherFunction, error) {
key := make([]byte, ske.CipherFunc.KeySize())
ske.s2k(key, passphrase)
if len(ske.encryptedKey) == 0 {
return key, ske.CipherFunc, nil
}
// the IV is all zeros
iv := make([]byte, ske.CipherFunc.blockSize())
c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv)
plaintextKey := make([]byte, len(ske.encryptedKey))
c.XORKeyStream(plaintextKey, ske.encryptedKey)
cipherFunc := CipherFunction(plaintextKey[0])
if cipherFunc.blockSize() == 0 {
return nil, ske.CipherFunc, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc)))
}
plaintextKey = plaintextKey[1:]
if l, cipherKeySize := len(plaintextKey), cipherFunc.KeySize(); l != cipherFunc.KeySize() {
return nil, cipherFunc, errors.StructuralError("length of decrypted key (" + strconv.Itoa(l) + ") " +
"not equal to cipher keysize (" + strconv.Itoa(cipherKeySize) + ")")
}
return plaintextKey, cipherFunc, nil
}
// SerializeSymmetricKeyEncrypted serializes a symmetric key packet to w. The
// packet contains a random session key, encrypted by a key derived from the
// given passphrase. The session key is returned and must be passed to
// SerializeSymmetricallyEncrypted.
// If config is nil, sensible defaults will be used.
func SerializeSymmetricKeyEncrypted(w io.Writer, passphrase []byte, config *Config) (key []byte, err error) {
cipherFunc := config.Cipher()
keySize := cipherFunc.KeySize()
if keySize == 0 {
return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc)))
}
s2kBuf := new(bytes.Buffer)
keyEncryptingKey := make([]byte, keySize)
// s2k.Serialize salts and stretches the passphrase, and writes the
// resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf.
err = s2k.Serialize(s2kBuf, keyEncryptingKey, config.Random(), passphrase, &s2k.Config{Hash: config.Hash(), S2KCount: config.PasswordHashIterations()})
if err != nil {
return
}
s2kBytes := s2kBuf.Bytes()
packetLength := 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize
err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength)
if err != nil {
return
}
var buf [2]byte
buf[0] = symmetricKeyEncryptedVersion
buf[1] = byte(cipherFunc)
_, err = w.Write(buf[:])
if err != nil {
return
}
_, err = w.Write(s2kBytes)
if err != nil {
return
}
sessionKey := make([]byte, keySize)
_, err = io.ReadFull(config.Random(), sessionKey)
if err != nil {
return
}
iv := make([]byte, cipherFunc.blockSize())
c := cipher.NewCFBEncrypter(cipherFunc.new(keyEncryptingKey), iv)
encryptedCipherAndKey := make([]byte, keySize+1)
c.XORKeyStream(encryptedCipherAndKey, buf[1:])
c.XORKeyStream(encryptedCipherAndKey[1:], sessionKey)
_, err = w.Write(encryptedCipherAndKey)
if err != nil {
return
}
key = sessionKey
return
}
// Copyright 2011 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 packet
import (
"crypto/cipher"
"crypto/sha1"
"crypto/subtle"
"golang.org/x/crypto/openpgp/errors"
"hash"
"io"
"strconv"
)
// SymmetricallyEncrypted represents a symmetrically encrypted byte string. The
// encrypted contents will consist of more OpenPGP packets. See RFC 4880,
// sections 5.7 and 5.13.
type SymmetricallyEncrypted struct {
MDC bool // true iff this is a type 18 packet and thus has an embedded MAC.
contents io.Reader
prefix []byte
}
const symmetricallyEncryptedVersion = 1
func (se *SymmetricallyEncrypted) parse(r io.Reader) error {
if se.MDC {
// See RFC 4880, section 5.13.
var buf [1]byte
_, err := readFull(r, buf[:])
if err != nil {
return err
}
if buf[0] != symmetricallyEncryptedVersion {
return errors.UnsupportedError("unknown SymmetricallyEncrypted version")
}
}
se.contents = r
return nil
}
// Decrypt returns a ReadCloser, from which the decrypted contents of the
// packet can be read. An incorrect key can, with high probability, be detected
// immediately and this will result in a KeyIncorrect error being returned.
func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, error) {
keySize := c.KeySize()
if keySize == 0 {
return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c)))
}
if len(key) != keySize {
return nil, errors.InvalidArgumentError("SymmetricallyEncrypted: incorrect key length")
}
if se.prefix == nil {
se.prefix = make([]byte, c.blockSize()+2)
_, err := readFull(se.contents, se.prefix)
if err != nil {
return nil, err
}
} else if len(se.prefix) != c.blockSize()+2 {
return nil, errors.InvalidArgumentError("can't try ciphers with different block lengths")
}
ocfbResync := OCFBResync
if se.MDC {
// MDC packets use a different form of OCFB mode.
ocfbResync = OCFBNoResync
}
s := NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync)
if s == nil {
return nil, errors.ErrKeyIncorrect
}
plaintext := cipher.StreamReader{S: s, R: se.contents}
if se.MDC {
// MDC packets have an embedded hash that we need to check.
h := sha1.New()
h.Write(se.prefix)
return &seMDCReader{in: plaintext, h: h}, nil
}
// Otherwise, we just need to wrap plaintext so that it's a valid ReadCloser.
return seReader{plaintext}, nil
}
// seReader wraps an io.Reader with a no-op Close method.
type seReader struct {
in io.Reader
}
func (ser seReader) Read(buf []byte) (int, error) {
return ser.in.Read(buf)
}
func (ser seReader) Close() error {
return nil
}
const mdcTrailerSize = 1 /* tag byte */ + 1 /* length byte */ + sha1.Size
// An seMDCReader wraps an io.Reader, maintains a running hash and keeps hold
// of the most recent 22 bytes (mdcTrailerSize). Upon EOF, those bytes form an
// MDC packet containing a hash of the previous contents which is checked
// against the running hash. See RFC 4880, section 5.13.
type seMDCReader struct {
in io.Reader
h hash.Hash
trailer [mdcTrailerSize]byte
scratch [mdcTrailerSize]byte
trailerUsed int
error bool
eof bool
}
func (ser *seMDCReader) Read(buf []byte) (n int, err error) {
if ser.error {
err = io.ErrUnexpectedEOF
return
}
if ser.eof {
err = io.EOF
return
}
// If we haven't yet filled the trailer buffer then we must do that
// first.
for ser.trailerUsed < mdcTrailerSize {
n, err = ser.in.Read(ser.trailer[ser.trailerUsed:])
ser.trailerUsed += n
if err == io.EOF {
if ser.trailerUsed != mdcTrailerSize {
n = 0
err = io.ErrUnexpectedEOF
ser.error = true
return
}
ser.eof = true
n = 0
return
}
if err != nil {
n = 0
return
}
}
// If it's a short read then we read into a temporary buffer and shift
// the data into the caller's buffer.
if len(buf) <= mdcTrailerSize {
n, err = readFull(ser.in, ser.scratch[:len(buf)])
copy(buf, ser.trailer[:n])
ser.h.Write(buf[:n])
copy(ser.trailer[:], ser.trailer[n:])
copy(ser.trailer[mdcTrailerSize-n:], ser.scratch[:])
if n < len(buf) {
ser.eof = true
err = io.EOF
}
return
}
n, err = ser.in.Read(buf[mdcTrailerSize:])
copy(buf, ser.trailer[:])
ser.h.Write(buf[:n])
copy(ser.trailer[:], buf[n:])
if err == io.EOF {
ser.eof = true
}
return
}
// This is a new-format packet tag byte for a type 19 (MDC) packet.
const mdcPacketTagByte = byte(0x80) | 0x40 | 19
func (ser *seMDCReader) Close() error {
if ser.error {
return errors.SignatureError("error during reading")
}
for !ser.eof {
// We haven't seen EOF so we need to read to the end
var buf [1024]byte
_, err := ser.Read(buf[:])
if err == io.EOF {
break
}
if err != nil {
return errors.SignatureError("error during reading")
}
}
if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size {
return errors.SignatureError("MDC packet not found")
}
ser.h.Write(ser.trailer[:2])
final := ser.h.Sum(nil)
if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 {
return errors.SignatureError("hash mismatch")
}
return nil
}
// An seMDCWriter writes through to an io.WriteCloser while maintains a running
// hash of the data written. On close, it emits an MDC packet containing the
// running hash.
type seMDCWriter struct {
w io.WriteCloser
h hash.Hash
}
func (w *seMDCWriter) Write(buf []byte) (n int, err error) {
w.h.Write(buf)
return w.w.Write(buf)
}
func (w *seMDCWriter) Close() (err error) {
var buf [mdcTrailerSize]byte
buf[0] = mdcPacketTagByte
buf[1] = sha1.Size
w.h.Write(buf[:2])
digest := w.h.Sum(nil)
copy(buf[2:], digest)
_, err = w.w.Write(buf[:])
if err != nil {
return
}
return w.w.Close()
}
// noOpCloser is like an io.NopCloser, but for an io.Writer.
type noOpCloser struct {
w io.Writer
}
func (c noOpCloser) Write(data []byte) (n int, err error) {
return c.w.Write(data)
}
func (c noOpCloser) Close() error {
return nil
}
// SerializeSymmetricallyEncrypted serializes a symmetrically encrypted packet
// to w and returns a WriteCloser to which the to-be-encrypted packets can be
// written.
// If config is nil, sensible defaults will be used.
func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, key []byte, config *Config) (contents io.WriteCloser, err error) {
if c.KeySize() != len(key) {
return nil, errors.InvalidArgumentError("SymmetricallyEncrypted.Serialize: bad key length")
}
writeCloser := noOpCloser{w}
ciphertext, err := serializeStreamHeader(writeCloser, packetTypeSymmetricallyEncryptedMDC)
if err != nil {
return
}
_, err = ciphertext.Write([]byte{symmetricallyEncryptedVersion})
if err != nil {
return
}
block := c.new(key)
blockSize := block.BlockSize()
iv := make([]byte, blockSize)
_, err = config.Random().Read(iv)
if err != nil {
return
}
s, prefix := NewOCFBEncrypter(block, iv, OCFBNoResync)
_, err = ciphertext.Write(prefix)
if err != nil {
return
}
plaintext := cipher.StreamWriter{S: s, W: ciphertext}
h := sha1.New()
h.Write(iv)
h.Write(iv[blockSize-2:])
contents = &seMDCWriter{w: plaintext, h: h}
return
}
// Copyright 2013 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 packet
import (
"bytes"
"image"
"image/jpeg"
"io"
)
const UserAttrImageSubpacket = 1
// UserAttribute is capable of storing other types of data about a user
// beyond name, email and a text comment. In practice, user attributes are typically used
// to store a signed thumbnail photo JPEG image of the user.
// See RFC 4880, section 5.12.
type UserAttribute struct {
Contents []*OpaqueSubpacket
}
// NewUserAttributePhoto creates a user attribute packet
// containing the given images.
func NewUserAttributePhoto(photos ...image.Image) (uat *UserAttribute, err error) {
uat = new(UserAttribute)
for _, photo := range photos {
var buf bytes.Buffer
// RFC 4880, Section 5.12.1.
data := []byte{
0x10, 0x00, // Little-endian image header length (16 bytes)
0x01, // Image header version 1
0x01, // JPEG
0, 0, 0, 0, // 12 reserved octets, must be all zero.
0, 0, 0, 0,
0, 0, 0, 0}
if _, err = buf.Write(data); err != nil {
return
}
if err = jpeg.Encode(&buf, photo, nil); err != nil {
return
}
uat.Contents = append(uat.Contents, &OpaqueSubpacket{
SubType: UserAttrImageSubpacket,
Contents: buf.Bytes()})
}
return
}
// NewUserAttribute creates a new user attribute packet containing the given subpackets.
func NewUserAttribute(contents ...*OpaqueSubpacket) *UserAttribute {
return &UserAttribute{Contents: contents}
}
func (uat *UserAttribute) parse(r io.Reader) (err error) {
// RFC 4880, section 5.13
b, err := io.ReadAll(r)
if err != nil {
return
}
uat.Contents, err = OpaqueSubpackets(b)
return
}
// Serialize marshals the user attribute to w in the form of an OpenPGP packet, including
// header.
func (uat *UserAttribute) Serialize(w io.Writer) (err error) {
var buf bytes.Buffer
for _, sp := range uat.Contents {
sp.Serialize(&buf)
}
if err = serializeHeader(w, packetTypeUserAttribute, buf.Len()); err != nil {
return err
}
_, err = w.Write(buf.Bytes())
return
}
// ImageData returns zero or more byte slices, each containing
// JPEG File Interchange Format (JFIF), for each photo in the
// user attribute packet.
func (uat *UserAttribute) ImageData() (imageData [][]byte) {
for _, sp := range uat.Contents {
if sp.SubType == UserAttrImageSubpacket && len(sp.Contents) > 16 {
imageData = append(imageData, sp.Contents[16:])
}
}
return
}
// Copyright 2011 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 packet
import (
"io"
"strings"
)
// UserId contains text that is intended to represent the name and email
// address of the key holder. See RFC 4880, section 5.11. By convention, this
// takes the form "Full Name (Comment) <email@example.com>"
type UserId struct {
Id string // By convention, this takes the form "Full Name (Comment) <email@example.com>" which is split out in the fields below.
Name, Comment, Email string
}
func hasInvalidCharacters(s string) bool {
for _, c := range s {
switch c {
case '(', ')', '<', '>', 0:
return true
}
}
return false
}
// NewUserId returns a UserId or nil if any of the arguments contain invalid
// characters. The invalid characters are '\x00', '(', ')', '<' and '>'
func NewUserId(name, comment, email string) *UserId {
// RFC 4880 doesn't deal with the structure of userid strings; the
// name, comment and email form is just a convention. However, there's
// no convention about escaping the metacharacters and GPG just refuses
// to create user ids where, say, the name contains a '('. We mirror
// this behaviour.
if hasInvalidCharacters(name) || hasInvalidCharacters(comment) || hasInvalidCharacters(email) {
return nil
}
uid := new(UserId)
uid.Name, uid.Comment, uid.Email = name, comment, email
uid.Id = name
if len(comment) > 0 {
if len(uid.Id) > 0 {
uid.Id += " "
}
uid.Id += "("
uid.Id += comment
uid.Id += ")"
}
if len(email) > 0 {
if len(uid.Id) > 0 {
uid.Id += " "
}
uid.Id += "<"
uid.Id += email
uid.Id += ">"
}
return uid
}
func (uid *UserId) parse(r io.Reader) (err error) {
// RFC 4880, section 5.11
b, err := io.ReadAll(r)
if err != nil {
return
}
uid.Id = string(b)
uid.Name, uid.Comment, uid.Email = parseUserId(uid.Id)
return
}
// Serialize marshals uid to w in the form of an OpenPGP packet, including
// header.
func (uid *UserId) Serialize(w io.Writer) error {
err := serializeHeader(w, packetTypeUserId, len(uid.Id))
if err != nil {
return err
}
_, err = w.Write([]byte(uid.Id))
return err
}
// parseUserId extracts the name, comment and email from a user id string that
// is formatted as "Full Name (Comment) <email@example.com>".
func parseUserId(id string) (name, comment, email string) {
var n, c, e struct {
start, end int
}
var state int
for offset, rune := range id {
switch state {
case 0:
// Entering name
n.start = offset
state = 1
fallthrough
case 1:
// In name
if rune == '(' {
state = 2
n.end = offset
} else if rune == '<' {
state = 5
n.end = offset
}
case 2:
// Entering comment
c.start = offset
state = 3
fallthrough
case 3:
// In comment
if rune == ')' {
state = 4
c.end = offset
}
case 4:
// Between comment and email
if rune == '<' {
state = 5
}
case 5:
// Entering email
e.start = offset
state = 6
fallthrough
case 6:
// In email
if rune == '>' {
state = 7
e.end = offset
}
default:
// After email
}
}
switch state {
case 1:
// ended in the name
n.end = len(id)
case 3:
// ended in comment
c.end = len(id)
case 6:
// ended in email
e.end = len(id)
}
name = strings.TrimSpace(id[n.start:n.end])
comment = strings.TrimSpace(id[c.start:c.end])
email = strings.TrimSpace(id[e.start:e.end])
return
}
// Copyright 2011 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 openpgp implements high level operations on OpenPGP messages.
//
// Deprecated: this package is unmaintained except for security fixes. New
// applications should consider a more focused, modern alternative to OpenPGP
// for their specific task. If you are required to interoperate with OpenPGP
// systems and need a maintained package, consider a community fork.
// See https://golang.org/issue/44226.
package openpgp
import (
"crypto"
_ "crypto/sha256"
"hash"
"io"
"strconv"
"golang.org/x/crypto/openpgp/armor"
"golang.org/x/crypto/openpgp/errors"
"golang.org/x/crypto/openpgp/packet"
)
// SignatureType is the armor type for a PGP signature.
var SignatureType = "PGP SIGNATURE"
// readArmored reads an armored block with the given type.
func readArmored(r io.Reader, expectedType string) (body io.Reader, err error) {
block, err := armor.Decode(r)
if err != nil {
return
}
if block.Type != expectedType {
return nil, errors.InvalidArgumentError("expected '" + expectedType + "', got: " + block.Type)
}
return block.Body, nil
}
// MessageDetails contains the result of parsing an OpenPGP encrypted and/or
// signed message.
type MessageDetails struct {
IsEncrypted bool // true if the message was encrypted.
EncryptedToKeyIds []uint64 // the list of recipient key ids.
IsSymmetricallyEncrypted bool // true if a passphrase could have decrypted the message.
DecryptedWith Key // the private key used to decrypt the message, if any.
IsSigned bool // true if the message is signed.
SignedByKeyId uint64 // the key id of the signer, if any.
SignedBy *Key // the key of the signer, if available.
LiteralData *packet.LiteralData // the metadata of the contents
UnverifiedBody io.Reader // the contents of the message.
// If IsSigned is true and SignedBy is non-zero then the signature will
// be verified as UnverifiedBody is read. The signature cannot be
// checked until the whole of UnverifiedBody is read so UnverifiedBody
// must be consumed until EOF before the data can be trusted. Even if a
// message isn't signed (or the signer is unknown) the data may contain
// an authentication code that is only checked once UnverifiedBody has
// been consumed. Once EOF has been seen, the following fields are
// valid. (An authentication code failure is reported as a
// SignatureError error when reading from UnverifiedBody.)
SignatureError error // nil if the signature is good.
Signature *packet.Signature // the signature packet itself, if v4 (default)
SignatureV3 *packet.SignatureV3 // the signature packet if it is a v2 or v3 signature
decrypted io.ReadCloser
}
// A PromptFunction is used as a callback by functions that may need to decrypt
// a private key, or prompt for a passphrase. It is called with a list of
// acceptable, encrypted private keys and a boolean that indicates whether a
// passphrase is usable. It should either decrypt a private key or return a
// passphrase to try. If the decrypted private key or given passphrase isn't
// correct, the function will be called again, forever. Any error returned will
// be passed up.
type PromptFunction func(keys []Key, symmetric bool) ([]byte, error)
// A keyEnvelopePair is used to store a private key with the envelope that
// contains a symmetric key, encrypted with that key.
type keyEnvelopePair struct {
key Key
encryptedKey *packet.EncryptedKey
}
// ReadMessage parses an OpenPGP message that may be signed and/or encrypted.
// The given KeyRing should contain both public keys (for signature
// verification) and, possibly encrypted, private keys for decrypting.
// If config is nil, sensible defaults will be used.
func ReadMessage(r io.Reader, keyring KeyRing, prompt PromptFunction, config *packet.Config) (md *MessageDetails, err error) {
var p packet.Packet
var symKeys []*packet.SymmetricKeyEncrypted
var pubKeys []keyEnvelopePair
var se *packet.SymmetricallyEncrypted
packets := packet.NewReader(r)
md = new(MessageDetails)
md.IsEncrypted = true
// The message, if encrypted, starts with a number of packets
// containing an encrypted decryption key. The decryption key is either
// encrypted to a public key, or with a passphrase. This loop
// collects these packets.
ParsePackets:
for {
p, err = packets.Next()
if err != nil {
return nil, err
}
switch p := p.(type) {
case *packet.SymmetricKeyEncrypted:
// This packet contains the decryption key encrypted with a passphrase.
md.IsSymmetricallyEncrypted = true
symKeys = append(symKeys, p)
case *packet.EncryptedKey:
// This packet contains the decryption key encrypted to a public key.
md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId)
switch p.Algo {
case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal:
break
default:
continue
}
var keys []Key
if p.KeyId == 0 {
keys = keyring.DecryptionKeys()
} else {
keys = keyring.KeysById(p.KeyId)
}
for _, k := range keys {
pubKeys = append(pubKeys, keyEnvelopePair{k, p})
}
case *packet.SymmetricallyEncrypted:
se = p
break ParsePackets
case *packet.Compressed, *packet.LiteralData, *packet.OnePassSignature:
// This message isn't encrypted.
if len(symKeys) != 0 || len(pubKeys) != 0 {
return nil, errors.StructuralError("key material not followed by encrypted message")
}
packets.Unread(p)
return readSignedMessage(packets, nil, keyring)
}
}
var candidates []Key
var decrypted io.ReadCloser
// Now that we have the list of encrypted keys we need to decrypt at
// least one of them or, if we cannot, we need to call the prompt
// function so that it can decrypt a key or give us a passphrase.
FindKey:
for {
// See if any of the keys already have a private key available
candidates = candidates[:0]
candidateFingerprints := make(map[string]bool)
for _, pk := range pubKeys {
if pk.key.PrivateKey == nil {
continue
}
if !pk.key.PrivateKey.Encrypted {
if len(pk.encryptedKey.Key) == 0 {
pk.encryptedKey.Decrypt(pk.key.PrivateKey, config)
}
if len(pk.encryptedKey.Key) == 0 {
continue
}
decrypted, err = se.Decrypt(pk.encryptedKey.CipherFunc, pk.encryptedKey.Key)
if err != nil && err != errors.ErrKeyIncorrect {
return nil, err
}
if decrypted != nil {
md.DecryptedWith = pk.key
break FindKey
}
} else {
fpr := string(pk.key.PublicKey.Fingerprint[:])
if v := candidateFingerprints[fpr]; v {
continue
}
candidates = append(candidates, pk.key)
candidateFingerprints[fpr] = true
}
}
if len(candidates) == 0 && len(symKeys) == 0 {
return nil, errors.ErrKeyIncorrect
}
if prompt == nil {
return nil, errors.ErrKeyIncorrect
}
passphrase, err := prompt(candidates, len(symKeys) != 0)
if err != nil {
return nil, err
}
// Try the symmetric passphrase first
if len(symKeys) != 0 && passphrase != nil {
for _, s := range symKeys {
key, cipherFunc, err := s.Decrypt(passphrase)
if err == nil {
decrypted, err = se.Decrypt(cipherFunc, key)
if err != nil && err != errors.ErrKeyIncorrect {
return nil, err
}
if decrypted != nil {
break FindKey
}
}
}
}
}
md.decrypted = decrypted
if err := packets.Push(decrypted); err != nil {
return nil, err
}
return readSignedMessage(packets, md, keyring)
}
// readSignedMessage reads a possibly signed message if mdin is non-zero then
// that structure is updated and returned. Otherwise a fresh MessageDetails is
// used.
func readSignedMessage(packets *packet.Reader, mdin *MessageDetails, keyring KeyRing) (md *MessageDetails, err error) {
if mdin == nil {
mdin = new(MessageDetails)
}
md = mdin
var p packet.Packet
var h hash.Hash
var wrappedHash hash.Hash
FindLiteralData:
for {
p, err = packets.Next()
if err != nil {
return nil, err
}
switch p := p.(type) {
case *packet.Compressed:
if err := packets.Push(p.Body); err != nil {
return nil, err
}
case *packet.OnePassSignature:
if !p.IsLast {
return nil, errors.UnsupportedError("nested signatures")
}
h, wrappedHash, err = hashForSignature(p.Hash, p.SigType)
if err != nil {
md = nil
return
}
md.IsSigned = true
md.SignedByKeyId = p.KeyId
keys := keyring.KeysByIdUsage(p.KeyId, packet.KeyFlagSign)
if len(keys) > 0 {
md.SignedBy = &keys[0]
}
case *packet.LiteralData:
md.LiteralData = p
break FindLiteralData
}
}
if md.SignedBy != nil {
md.UnverifiedBody = &signatureCheckReader{packets, h, wrappedHash, md}
} else if md.decrypted != nil {
md.UnverifiedBody = checkReader{md}
} else {
md.UnverifiedBody = md.LiteralData.Body
}
return md, nil
}
// hashForSignature returns a pair of hashes that can be used to verify a
// signature. The signature may specify that the contents of the signed message
// should be preprocessed (i.e. to normalize line endings). Thus this function
// returns two hashes. The second should be used to hash the message itself and
// performs any needed preprocessing.
func hashForSignature(hashId crypto.Hash, sigType packet.SignatureType) (hash.Hash, hash.Hash, error) {
if !hashId.Available() {
return nil, nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashId)))
}
h := hashId.New()
switch sigType {
case packet.SigTypeBinary:
return h, h, nil
case packet.SigTypeText:
return h, NewCanonicalTextHash(h), nil
}
return nil, nil, errors.UnsupportedError("unsupported signature type: " + strconv.Itoa(int(sigType)))
}
// checkReader wraps an io.Reader from a LiteralData packet. When it sees EOF
// it closes the ReadCloser from any SymmetricallyEncrypted packet to trigger
// MDC checks.
type checkReader struct {
md *MessageDetails
}
func (cr checkReader) Read(buf []byte) (n int, err error) {
n, err = cr.md.LiteralData.Body.Read(buf)
if err == io.EOF {
mdcErr := cr.md.decrypted.Close()
if mdcErr != nil {
err = mdcErr
}
}
return
}
// signatureCheckReader wraps an io.Reader from a LiteralData packet and hashes
// the data as it is read. When it sees an EOF from the underlying io.Reader
// it parses and checks a trailing Signature packet and triggers any MDC checks.
type signatureCheckReader struct {
packets *packet.Reader
h, wrappedHash hash.Hash
md *MessageDetails
}
func (scr *signatureCheckReader) Read(buf []byte) (n int, err error) {
n, err = scr.md.LiteralData.Body.Read(buf)
scr.wrappedHash.Write(buf[:n])
if err == io.EOF {
var p packet.Packet
p, scr.md.SignatureError = scr.packets.Next()
if scr.md.SignatureError != nil {
return
}
var ok bool
if scr.md.Signature, ok = p.(*packet.Signature); ok {
scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature)
} else if scr.md.SignatureV3, ok = p.(*packet.SignatureV3); ok {
scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignatureV3(scr.h, scr.md.SignatureV3)
} else {
scr.md.SignatureError = errors.StructuralError("LiteralData not followed by Signature")
return
}
// The SymmetricallyEncrypted packet, if any, might have an
// unsigned hash of its own. In order to check this we need to
// close that Reader.
if scr.md.decrypted != nil {
mdcErr := scr.md.decrypted.Close()
if mdcErr != nil {
err = mdcErr
}
}
}
return
}
// CheckDetachedSignature takes a signed file and a detached signature and
// returns the signer if the signature is valid. If the signer isn't known,
// ErrUnknownIssuer is returned.
func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) {
var issuerKeyId uint64
var hashFunc crypto.Hash
var sigType packet.SignatureType
var keys []Key
var p packet.Packet
packets := packet.NewReader(signature)
for {
p, err = packets.Next()
if err == io.EOF {
return nil, errors.ErrUnknownIssuer
}
if err != nil {
return nil, err
}
switch sig := p.(type) {
case *packet.Signature:
if sig.IssuerKeyId == nil {
return nil, errors.StructuralError("signature doesn't have an issuer")
}
issuerKeyId = *sig.IssuerKeyId
hashFunc = sig.Hash
sigType = sig.SigType
case *packet.SignatureV3:
issuerKeyId = sig.IssuerKeyId
hashFunc = sig.Hash
sigType = sig.SigType
default:
return nil, errors.StructuralError("non signature packet found")
}
keys = keyring.KeysByIdUsage(issuerKeyId, packet.KeyFlagSign)
if len(keys) > 0 {
break
}
}
if len(keys) == 0 {
panic("unreachable")
}
h, wrappedHash, err := hashForSignature(hashFunc, sigType)
if err != nil {
return nil, err
}
if _, err := io.Copy(wrappedHash, signed); err != nil && err != io.EOF {
return nil, err
}
for _, key := range keys {
switch sig := p.(type) {
case *packet.Signature:
err = key.PublicKey.VerifySignature(h, sig)
case *packet.SignatureV3:
err = key.PublicKey.VerifySignatureV3(h, sig)
default:
panic("unreachable")
}
if err == nil {
return key.Entity, nil
}
}
return nil, err
}
// CheckArmoredDetachedSignature performs the same actions as
// CheckDetachedSignature but expects the signature to be armored.
func CheckArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) {
body, err := readArmored(signature, SignatureType)
if err != nil {
return
}
return CheckDetachedSignature(keyring, signed, body)
}
// Copyright 2011 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 s2k implements the various OpenPGP string-to-key transforms as
// specified in RFC 4800 section 3.7.1.
//
// Deprecated: this package is unmaintained except for security fixes. New
// applications should consider a more focused, modern alternative to OpenPGP
// for their specific task. If you are required to interoperate with OpenPGP
// systems and need a maintained package, consider a community fork.
// See https://golang.org/issue/44226.
package s2k
import (
"crypto"
"hash"
"io"
"strconv"
"golang.org/x/crypto/openpgp/errors"
)
// Config collects configuration parameters for s2k key-stretching
// transformatioms. A nil *Config is valid and results in all default
// values. Currently, Config is used only by the Serialize function in
// this package.
type Config struct {
// Hash is the default hash function to be used. If
// nil, SHA1 is used.
Hash crypto.Hash
// S2KCount is only used for symmetric encryption. It
// determines the strength of the passphrase stretching when
// the said passphrase is hashed to produce a key. S2KCount
// should be between 1024 and 65011712, inclusive. If Config
// is nil or S2KCount is 0, the value 65536 used. Not all
// values in the above range can be represented. S2KCount will
// be rounded up to the next representable value if it cannot
// be encoded exactly. When set, it is strongly encrouraged to
// use a value that is at least 65536. See RFC 4880 Section
// 3.7.1.3.
S2KCount int
}
func (c *Config) hash() crypto.Hash {
if c == nil || uint(c.Hash) == 0 {
// SHA1 is the historical default in this package.
return crypto.SHA1
}
return c.Hash
}
func (c *Config) encodedCount() uint8 {
if c == nil || c.S2KCount == 0 {
return 96 // The common case. Corresponding to 65536
}
i := c.S2KCount
switch {
// Behave like GPG. Should we make 65536 the lowest value used?
case i < 1024:
i = 1024
case i > 65011712:
i = 65011712
}
return encodeCount(i)
}
// encodeCount converts an iterative "count" in the range 1024 to
// 65011712, inclusive, to an encoded count. The return value is the
// octet that is actually stored in the GPG file. encodeCount panics
// if i is not in the above range (encodedCount above takes care to
// pass i in the correct range). See RFC 4880 Section 3.7.7.1.
func encodeCount(i int) uint8 {
if i < 1024 || i > 65011712 {
panic("count arg i outside the required range")
}
for encoded := 0; encoded < 256; encoded++ {
count := decodeCount(uint8(encoded))
if count >= i {
return uint8(encoded)
}
}
return 255
}
// decodeCount returns the s2k mode 3 iterative "count" corresponding to
// the encoded octet c.
func decodeCount(c uint8) int {
return (16 + int(c&15)) << (uint32(c>>4) + 6)
}
// Simple writes to out the result of computing the Simple S2K function (RFC
// 4880, section 3.7.1.1) using the given hash and input passphrase.
func Simple(out []byte, h hash.Hash, in []byte) {
Salted(out, h, in, nil)
}
var zero [1]byte
// Salted writes to out the result of computing the Salted S2K function (RFC
// 4880, section 3.7.1.2) using the given hash, input passphrase and salt.
func Salted(out []byte, h hash.Hash, in []byte, salt []byte) {
done := 0
var digest []byte
for i := 0; done < len(out); i++ {
h.Reset()
for j := 0; j < i; j++ {
h.Write(zero[:])
}
h.Write(salt)
h.Write(in)
digest = h.Sum(digest[:0])
n := copy(out[done:], digest)
done += n
}
}
// Iterated writes to out the result of computing the Iterated and Salted S2K
// function (RFC 4880, section 3.7.1.3) using the given hash, input passphrase,
// salt and iteration count.
func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) {
combined := make([]byte, len(in)+len(salt))
copy(combined, salt)
copy(combined[len(salt):], in)
if count < len(combined) {
count = len(combined)
}
done := 0
var digest []byte
for i := 0; done < len(out); i++ {
h.Reset()
for j := 0; j < i; j++ {
h.Write(zero[:])
}
written := 0
for written < count {
if written+len(combined) > count {
todo := count - written
h.Write(combined[:todo])
written = count
} else {
h.Write(combined)
written += len(combined)
}
}
digest = h.Sum(digest[:0])
n := copy(out[done:], digest)
done += n
}
}
// Parse reads a binary specification for a string-to-key transformation from r
// and returns a function which performs that transform.
func Parse(r io.Reader) (f func(out, in []byte), err error) {
var buf [9]byte
_, err = io.ReadFull(r, buf[:2])
if err != nil {
return
}
hash, ok := HashIdToHash(buf[1])
if !ok {
return nil, errors.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(buf[1])))
}
if !hash.Available() {
return nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hash)))
}
h := hash.New()
switch buf[0] {
case 0:
f := func(out, in []byte) {
Simple(out, h, in)
}
return f, nil
case 1:
_, err = io.ReadFull(r, buf[:8])
if err != nil {
return
}
f := func(out, in []byte) {
Salted(out, h, in, buf[:8])
}
return f, nil
case 3:
_, err = io.ReadFull(r, buf[:9])
if err != nil {
return
}
count := decodeCount(buf[8])
f := func(out, in []byte) {
Iterated(out, h, in, buf[:8], count)
}
return f, nil
}
return nil, errors.UnsupportedError("S2K function")
}
// Serialize salts and stretches the given passphrase and writes the
// resulting key into key. It also serializes an S2K descriptor to
// w. The key stretching can be configured with c, which may be
// nil. In that case, sensible defaults will be used.
func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte, c *Config) error {
var buf [11]byte
buf[0] = 3 /* iterated and salted */
buf[1], _ = HashToHashId(c.hash())
salt := buf[2:10]
if _, err := io.ReadFull(rand, salt); err != nil {
return err
}
encodedCount := c.encodedCount()
count := decodeCount(encodedCount)
buf[10] = encodedCount
if _, err := w.Write(buf[:]); err != nil {
return err
}
Iterated(key, c.hash().New(), passphrase, salt, count)
return nil
}
// hashToHashIdMapping contains pairs relating OpenPGP's hash identifier with
// Go's crypto.Hash type. See RFC 4880, section 9.4.
var hashToHashIdMapping = []struct {
id byte
hash crypto.Hash
name string
}{
{1, crypto.MD5, "MD5"},
{2, crypto.SHA1, "SHA1"},
{3, crypto.RIPEMD160, "RIPEMD160"},
{8, crypto.SHA256, "SHA256"},
{9, crypto.SHA384, "SHA384"},
{10, crypto.SHA512, "SHA512"},
{11, crypto.SHA224, "SHA224"},
}
// HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP
// hash id.
func HashIdToHash(id byte) (h crypto.Hash, ok bool) {
for _, m := range hashToHashIdMapping {
if m.id == id {
return m.hash, true
}
}
return 0, false
}
// HashIdToString returns the name of the hash function corresponding to the
// given OpenPGP hash id.
func HashIdToString(id byte) (name string, ok bool) {
for _, m := range hashToHashIdMapping {
if m.id == id {
return m.name, true
}
}
return "", false
}
// HashToHashId returns an OpenPGP hash id which corresponds the given Hash.
func HashToHashId(h crypto.Hash) (id byte, ok bool) {
for _, m := range hashToHashIdMapping {
if m.hash == h {
return m.id, true
}
}
return 0, false
}
// Copyright 2011 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 openpgp
import (
"crypto"
"hash"
"io"
"strconv"
"time"
"golang.org/x/crypto/openpgp/armor"
"golang.org/x/crypto/openpgp/errors"
"golang.org/x/crypto/openpgp/packet"
"golang.org/x/crypto/openpgp/s2k"
)
// DetachSign signs message with the private key from signer (which must
// already have been decrypted) and writes the signature to w.
// If config is nil, sensible defaults will be used.
func DetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error {
return detachSign(w, signer, message, packet.SigTypeBinary, config)
}
// ArmoredDetachSign signs message with the private key from signer (which
// must already have been decrypted) and writes an armored signature to w.
// If config is nil, sensible defaults will be used.
func ArmoredDetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) (err error) {
return armoredDetachSign(w, signer, message, packet.SigTypeBinary, config)
}
// DetachSignText signs message (after canonicalising the line endings) with
// the private key from signer (which must already have been decrypted) and
// writes the signature to w.
// If config is nil, sensible defaults will be used.
func DetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error {
return detachSign(w, signer, message, packet.SigTypeText, config)
}
// ArmoredDetachSignText signs message (after canonicalising the line endings)
// with the private key from signer (which must already have been decrypted)
// and writes an armored signature to w.
// If config is nil, sensible defaults will be used.
func ArmoredDetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error {
return armoredDetachSign(w, signer, message, packet.SigTypeText, config)
}
func armoredDetachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) {
out, err := armor.Encode(w, SignatureType, nil)
if err != nil {
return
}
err = detachSign(out, signer, message, sigType, config)
if err != nil {
return
}
return out.Close()
}
func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) {
if signer.PrivateKey == nil {
return errors.InvalidArgumentError("signing key doesn't have a private key")
}
if signer.PrivateKey.Encrypted {
return errors.InvalidArgumentError("signing key is encrypted")
}
sig := new(packet.Signature)
sig.SigType = sigType
sig.PubKeyAlgo = signer.PrivateKey.PubKeyAlgo
sig.Hash = config.Hash()
sig.CreationTime = config.Now()
sig.IssuerKeyId = &signer.PrivateKey.KeyId
h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType)
if err != nil {
return
}
io.Copy(wrappedHash, message)
err = sig.Sign(h, signer.PrivateKey, config)
if err != nil {
return
}
return sig.Serialize(w)
}
// FileHints contains metadata about encrypted files. This metadata is, itself,
// encrypted.
type FileHints struct {
// IsBinary can be set to hint that the contents are binary data.
IsBinary bool
// FileName hints at the name of the file that should be written. It's
// truncated to 255 bytes if longer. It may be empty to suggest that the
// file should not be written to disk. It may be equal to "_CONSOLE" to
// suggest the data should not be written to disk.
FileName string
// ModTime contains the modification time of the file, or the zero time if not applicable.
ModTime time.Time
}
// SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase.
// The resulting WriteCloser must be closed after the contents of the file have
// been written.
// If config is nil, sensible defaults will be used.
func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
if hints == nil {
hints = &FileHints{}
}
key, err := packet.SerializeSymmetricKeyEncrypted(ciphertext, passphrase, config)
if err != nil {
return
}
w, err := packet.SerializeSymmetricallyEncrypted(ciphertext, config.Cipher(), key, config)
if err != nil {
return
}
literaldata := w
if algo := config.Compression(); algo != packet.CompressionNone {
var compConfig *packet.CompressionConfig
if config != nil {
compConfig = config.CompressionConfig
}
literaldata, err = packet.SerializeCompressed(w, algo, compConfig)
if err != nil {
return
}
}
var epochSeconds uint32
if !hints.ModTime.IsZero() {
epochSeconds = uint32(hints.ModTime.Unix())
}
return packet.SerializeLiteral(literaldata, hints.IsBinary, hints.FileName, epochSeconds)
}
// intersectPreferences mutates and returns a prefix of a that contains only
// the values in the intersection of a and b. The order of a is preserved.
func intersectPreferences(a []uint8, b []uint8) (intersection []uint8) {
var j int
for _, v := range a {
for _, v2 := range b {
if v == v2 {
a[j] = v
j++
break
}
}
}
return a[:j]
}
func hashToHashId(h crypto.Hash) uint8 {
v, ok := s2k.HashToHashId(h)
if !ok {
panic("tried to convert unknown hash")
}
return v
}
// writeAndSign writes the data as a payload package and, optionally, signs
// it. hints contains optional information, that is also encrypted,
// that aids the recipients in processing the message. The resulting
// WriteCloser must be closed after the contents of the file have been
// written. If config is nil, sensible defaults will be used.
func writeAndSign(payload io.WriteCloser, candidateHashes []uint8, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
var signer *packet.PrivateKey
if signed != nil {
signKey, ok := signed.signingKey(config.Now())
if !ok {
return nil, errors.InvalidArgumentError("no valid signing keys")
}
signer = signKey.PrivateKey
if signer == nil {
return nil, errors.InvalidArgumentError("no private key in signing key")
}
if signer.Encrypted {
return nil, errors.InvalidArgumentError("signing key must be decrypted")
}
}
var hash crypto.Hash
for _, hashId := range candidateHashes {
if h, ok := s2k.HashIdToHash(hashId); ok && h.Available() {
hash = h
break
}
}
// If the hash specified by config is a candidate, we'll use that.
if configuredHash := config.Hash(); configuredHash.Available() {
for _, hashId := range candidateHashes {
if h, ok := s2k.HashIdToHash(hashId); ok && h == configuredHash {
hash = h
break
}
}
}
if hash == 0 {
hashId := candidateHashes[0]
name, ok := s2k.HashIdToString(hashId)
if !ok {
name = "#" + strconv.Itoa(int(hashId))
}
return nil, errors.InvalidArgumentError("cannot encrypt because no candidate hash functions are compiled in. (Wanted " + name + " in this case.)")
}
if signer != nil {
ops := &packet.OnePassSignature{
SigType: packet.SigTypeBinary,
Hash: hash,
PubKeyAlgo: signer.PubKeyAlgo,
KeyId: signer.KeyId,
IsLast: true,
}
if err := ops.Serialize(payload); err != nil {
return nil, err
}
}
if hints == nil {
hints = &FileHints{}
}
w := payload
if signer != nil {
// If we need to write a signature packet after the literal
// data then we need to stop literalData from closing
// encryptedData.
w = noOpCloser{w}
}
var epochSeconds uint32
if !hints.ModTime.IsZero() {
epochSeconds = uint32(hints.ModTime.Unix())
}
literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds)
if err != nil {
return nil, err
}
if signer != nil {
return signatureWriter{payload, literalData, hash, hash.New(), signer, config}, nil
}
return literalData, nil
}
// Encrypt encrypts a message to a number of recipients and, optionally, signs
// it. hints contains optional information, that is also encrypted, that aids
// the recipients in processing the message. The resulting WriteCloser must
// be closed after the contents of the file have been written.
// If config is nil, sensible defaults will be used.
func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
if len(to) == 0 {
return nil, errors.InvalidArgumentError("no encryption recipient provided")
}
// These are the possible ciphers that we'll use for the message.
candidateCiphers := []uint8{
uint8(packet.CipherAES128),
uint8(packet.CipherAES256),
uint8(packet.CipherCAST5),
}
// These are the possible hash functions that we'll use for the signature.
candidateHashes := []uint8{
hashToHashId(crypto.SHA256),
hashToHashId(crypto.SHA384),
hashToHashId(crypto.SHA512),
hashToHashId(crypto.SHA1),
hashToHashId(crypto.RIPEMD160),
}
// In the event that a recipient doesn't specify any supported ciphers
// or hash functions, these are the ones that we assume that every
// implementation supports.
defaultCiphers := candidateCiphers[len(candidateCiphers)-1:]
defaultHashes := candidateHashes[len(candidateHashes)-1:]
encryptKeys := make([]Key, len(to))
for i := range to {
var ok bool
encryptKeys[i], ok = to[i].encryptionKey(config.Now())
if !ok {
return nil, errors.InvalidArgumentError("cannot encrypt a message to key id " + strconv.FormatUint(to[i].PrimaryKey.KeyId, 16) + " because it has no encryption keys")
}
sig := to[i].primaryIdentity().SelfSignature
preferredSymmetric := sig.PreferredSymmetric
if len(preferredSymmetric) == 0 {
preferredSymmetric = defaultCiphers
}
preferredHashes := sig.PreferredHash
if len(preferredHashes) == 0 {
preferredHashes = defaultHashes
}
candidateCiphers = intersectPreferences(candidateCiphers, preferredSymmetric)
candidateHashes = intersectPreferences(candidateHashes, preferredHashes)
}
if len(candidateCiphers) == 0 || len(candidateHashes) == 0 {
return nil, errors.InvalidArgumentError("cannot encrypt because recipient set shares no common algorithms")
}
cipher := packet.CipherFunction(candidateCiphers[0])
// If the cipher specified by config is a candidate, we'll use that.
configuredCipher := config.Cipher()
for _, c := range candidateCiphers {
cipherFunc := packet.CipherFunction(c)
if cipherFunc == configuredCipher {
cipher = cipherFunc
break
}
}
symKey := make([]byte, cipher.KeySize())
if _, err := io.ReadFull(config.Random(), symKey); err != nil {
return nil, err
}
for _, key := range encryptKeys {
if err := packet.SerializeEncryptedKey(ciphertext, key.PublicKey, cipher, symKey, config); err != nil {
return nil, err
}
}
payload, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey, config)
if err != nil {
return
}
return writeAndSign(payload, candidateHashes, signed, hints, config)
}
// Sign signs a message. The resulting WriteCloser must be closed after the
// contents of the file have been written. hints contains optional information
// that aids the recipients in processing the message.
// If config is nil, sensible defaults will be used.
func Sign(output io.Writer, signed *Entity, hints *FileHints, config *packet.Config) (input io.WriteCloser, err error) {
if signed == nil {
return nil, errors.InvalidArgumentError("no signer provided")
}
// These are the possible hash functions that we'll use for the signature.
candidateHashes := []uint8{
hashToHashId(crypto.SHA256),
hashToHashId(crypto.SHA384),
hashToHashId(crypto.SHA512),
hashToHashId(crypto.SHA1),
hashToHashId(crypto.RIPEMD160),
}
defaultHashes := candidateHashes[len(candidateHashes)-1:]
preferredHashes := signed.primaryIdentity().SelfSignature.PreferredHash
if len(preferredHashes) == 0 {
preferredHashes = defaultHashes
}
candidateHashes = intersectPreferences(candidateHashes, preferredHashes)
return writeAndSign(noOpCloser{output}, candidateHashes, signed, hints, config)
}
// signatureWriter hashes the contents of a message while passing it along to
// literalData. When closed, it closes literalData, writes a signature packet
// to encryptedData and then also closes encryptedData.
type signatureWriter struct {
encryptedData io.WriteCloser
literalData io.WriteCloser
hashType crypto.Hash
h hash.Hash
signer *packet.PrivateKey
config *packet.Config
}
func (s signatureWriter) Write(data []byte) (int, error) {
s.h.Write(data)
return s.literalData.Write(data)
}
func (s signatureWriter) Close() error {
sig := &packet.Signature{
SigType: packet.SigTypeBinary,
PubKeyAlgo: s.signer.PubKeyAlgo,
Hash: s.hashType,
CreationTime: s.config.Now(),
IssuerKeyId: &s.signer.KeyId,
}
if err := sig.Sign(s.h, s.signer, s.config); err != nil {
return err
}
if err := s.literalData.Close(); err != nil {
return err
}
if err := sig.Serialize(s.encryptedData); err != nil {
return err
}
return s.encryptedData.Close()
}
// noOpCloser is like an io.NopCloser, but for an io.Writer.
// TODO: we have two of these in OpenPGP packages alone. This probably needs
// to be promoted somewhere more common.
type noOpCloser struct {
w io.Writer
}
func (c noOpCloser) Write(data []byte) (n int, err error) {
return c.w.Write(data)
}
func (c noOpCloser) Close() error {
return nil
}
// 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.
/*
Package pbkdf2 implements the key derivation function PBKDF2 as defined in RFC
2898 / PKCS #5 v2.0.
A key derivation function is useful when encrypting data based on a password
or any other not-fully-random data. It uses a pseudorandom function to derive
a secure encryption key based on the password.
While v2.0 of the standard defines only one pseudorandom function to use,
HMAC-SHA1, the drafted v2.1 specification allows use of all five FIPS Approved
Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To
choose, you can pass the `New` functions from the different SHA packages to
pbkdf2.Key.
*/
package pbkdf2
import (
"crypto/hmac"
"hash"
)
// Key derives a key from the password, salt and iteration count, returning a
// []byte of length keylen that can be used as cryptographic key. The key is
// derived based on the method described as PBKDF2 with the HMAC variant using
// the supplied hash function.
//
// For example, to use a HMAC-SHA-1 based PBKDF2 key derivation function, you
// can get a derived key for e.g. AES-256 (which needs a 32-byte key) by
// doing:
//
// dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New)
//
// Remember to get a good random salt. At least 8 bytes is recommended by the
// RFC.
//
// Using a higher iteration count will increase the cost of an exhaustive
// search but will also make derivation proportionally slower.
func Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
prf := hmac.New(h, password)
hashLen := prf.Size()
numBlocks := (keyLen + hashLen - 1) / hashLen
var buf [4]byte
dk := make([]byte, 0, numBlocks*hashLen)
U := make([]byte, hashLen)
for block := 1; block <= numBlocks; block++ {
// N.B.: || means concatenation, ^ means XOR
// for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter
// U_1 = PRF(password, salt || uint(i))
prf.Reset()
prf.Write(salt)
buf[0] = byte(block >> 24)
buf[1] = byte(block >> 16)
buf[2] = byte(block >> 8)
buf[3] = byte(block)
prf.Write(buf[:4])
dk = prf.Sum(dk)
T := dk[len(dk)-hashLen:]
copy(U, T)
// U_n = PRF(password, U_(n-1))
for n := 2; n <= iter; n++ {
prf.Reset()
prf.Write(U)
U = U[:0]
U = prf.Sum(U)
for x := range U {
T[x] ^= U[x]
}
}
}
return dk[:keyLen]
}
// 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.
package pkcs12
import (
"errors"
"unicode/utf16"
)
// bmpString returns s encoded in UCS-2 with a zero terminator.
func bmpString(s string) ([]byte, error) {
// References:
// https://tools.ietf.org/html/rfc7292#appendix-B.1
// https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane
// - non-BMP characters are encoded in UTF 16 by using a surrogate pair of 16-bit codes
// EncodeRune returns 0xfffd if the rune does not need special encoding
// - the above RFC provides the info that BMPStrings are NULL terminated.
ret := make([]byte, 0, 2*len(s)+2)
for _, r := range s {
if t, _ := utf16.EncodeRune(r); t != 0xfffd {
return nil, errors.New("pkcs12: string contains characters that cannot be encoded in UCS-2")
}
ret = append(ret, byte(r/256), byte(r%256))
}
return append(ret, 0, 0), nil
}
func decodeBMPString(bmpString []byte) (string, error) {
if len(bmpString)%2 != 0 {
return "", errors.New("pkcs12: odd-length BMP string")
}
// strip terminator if present
if l := len(bmpString); l >= 2 && bmpString[l-1] == 0 && bmpString[l-2] == 0 {
bmpString = bmpString[:l-2]
}
s := make([]uint16, 0, len(bmpString)/2)
for len(bmpString) > 0 {
s = append(s, uint16(bmpString[0])<<8+uint16(bmpString[1]))
bmpString = bmpString[2:]
}
return string(utf16.Decode(s)), nil
}
// 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.
package pkcs12
import (
"bytes"
"crypto/cipher"
"crypto/des"
"crypto/x509/pkix"
"encoding/asn1"
"errors"
"golang.org/x/crypto/pkcs12/internal/rc2"
)
var (
oidPBEWithSHAAnd3KeyTripleDESCBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 3})
oidPBEWithSHAAnd40BitRC2CBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 6})
)
// pbeCipher is an abstraction of a PKCS#12 cipher.
type pbeCipher interface {
// create returns a cipher.Block given a key.
create(key []byte) (cipher.Block, error)
// deriveKey returns a key derived from the given password and salt.
deriveKey(salt, password []byte, iterations int) []byte
// deriveIV returns an IV derived from the given password and salt.
deriveIV(salt, password []byte, iterations int) []byte
}
type shaWithTripleDESCBC struct{}
func (shaWithTripleDESCBC) create(key []byte) (cipher.Block, error) {
return des.NewTripleDESCipher(key)
}
func (shaWithTripleDESCBC) deriveKey(salt, password []byte, iterations int) []byte {
return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 24)
}
func (shaWithTripleDESCBC) deriveIV(salt, password []byte, iterations int) []byte {
return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8)
}
type shaWith40BitRC2CBC struct{}
func (shaWith40BitRC2CBC) create(key []byte) (cipher.Block, error) {
return rc2.New(key, len(key)*8)
}
func (shaWith40BitRC2CBC) deriveKey(salt, password []byte, iterations int) []byte {
return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 5)
}
func (shaWith40BitRC2CBC) deriveIV(salt, password []byte, iterations int) []byte {
return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8)
}
type pbeParams struct {
Salt []byte
Iterations int
}
func pbDecrypterFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher.BlockMode, int, error) {
var cipherType pbeCipher
switch {
case algorithm.Algorithm.Equal(oidPBEWithSHAAnd3KeyTripleDESCBC):
cipherType = shaWithTripleDESCBC{}
case algorithm.Algorithm.Equal(oidPBEWithSHAAnd40BitRC2CBC):
cipherType = shaWith40BitRC2CBC{}
default:
return nil, 0, NotImplementedError("algorithm " + algorithm.Algorithm.String() + " is not supported")
}
var params pbeParams
if err := unmarshal(algorithm.Parameters.FullBytes, ¶ms); err != nil {
return nil, 0, err
}
key := cipherType.deriveKey(params.Salt, password, params.Iterations)
iv := cipherType.deriveIV(params.Salt, password, params.Iterations)
block, err := cipherType.create(key)
if err != nil {
return nil, 0, err
}
return cipher.NewCBCDecrypter(block, iv), block.BlockSize(), nil
}
func pbDecrypt(info decryptable, password []byte) (decrypted []byte, err error) {
cbc, blockSize, err := pbDecrypterFor(info.Algorithm(), password)
if err != nil {
return nil, err
}
encrypted := info.Data()
if len(encrypted) == 0 {
return nil, errors.New("pkcs12: empty encrypted data")
}
if len(encrypted)%blockSize != 0 {
return nil, errors.New("pkcs12: input is not a multiple of the block size")
}
decrypted = make([]byte, len(encrypted))
cbc.CryptBlocks(decrypted, encrypted)
psLen := int(decrypted[len(decrypted)-1])
if psLen == 0 || psLen > blockSize {
return nil, ErrDecryption
}
if len(decrypted) < psLen {
return nil, ErrDecryption
}
ps := decrypted[len(decrypted)-psLen:]
decrypted = decrypted[:len(decrypted)-psLen]
if !bytes.Equal(ps, bytes.Repeat([]byte{byte(psLen)}, psLen)) {
return nil, ErrDecryption
}
return
}
// decryptable abstracts an object that contains ciphertext.
type decryptable interface {
Algorithm() pkix.AlgorithmIdentifier
Data() []byte
}
// 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.
package pkcs12
import "errors"
var (
// ErrDecryption represents a failure to decrypt the input.
ErrDecryption = errors.New("pkcs12: decryption error, incorrect padding")
// ErrIncorrectPassword is returned when an incorrect password is detected.
// Usually, P12/PFX data is signed to be able to verify the password.
ErrIncorrectPassword = errors.New("pkcs12: decryption password incorrect")
)
// NotImplementedError indicates that the input is not currently supported.
type NotImplementedError string
func (e NotImplementedError) Error() string {
return "pkcs12: " + string(e)
}
// 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.
// Package rc2 implements the RC2 cipher
/*
https://www.ietf.org/rfc/rfc2268.txt
http://people.csail.mit.edu/rivest/pubs/KRRR98.pdf
This code is licensed under the MIT license.
*/
package rc2
import (
"crypto/cipher"
"encoding/binary"
"math/bits"
)
// The rc2 block size in bytes
const BlockSize = 8
type rc2Cipher struct {
k [64]uint16
}
// New returns a new rc2 cipher with the given key and effective key length t1
func New(key []byte, t1 int) (cipher.Block, error) {
// TODO(dgryski): error checking for key length
return &rc2Cipher{
k: expandKey(key, t1),
}, nil
}
func (*rc2Cipher) BlockSize() int { return BlockSize }
var piTable = [256]byte{
0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d,
0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2,
0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13, 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32,
0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82,
0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc,
0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1, 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26,
0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03,
0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7,
0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7, 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a,
0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec,
0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39,
0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a, 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31,
0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9,
0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9,
0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0, 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e,
0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad,
}
func expandKey(key []byte, t1 int) [64]uint16 {
l := make([]byte, 128)
copy(l, key)
var t = len(key)
var t8 = (t1 + 7) / 8
var tm = byte(255 % uint(1<<(8+uint(t1)-8*uint(t8))))
for i := len(key); i < 128; i++ {
l[i] = piTable[l[i-1]+l[uint8(i-t)]]
}
l[128-t8] = piTable[l[128-t8]&tm]
for i := 127 - t8; i >= 0; i-- {
l[i] = piTable[l[i+1]^l[i+t8]]
}
var k [64]uint16
for i := range k {
k[i] = uint16(l[2*i]) + uint16(l[2*i+1])*256
}
return k
}
func (c *rc2Cipher) Encrypt(dst, src []byte) {
r0 := binary.LittleEndian.Uint16(src[0:])
r1 := binary.LittleEndian.Uint16(src[2:])
r2 := binary.LittleEndian.Uint16(src[4:])
r3 := binary.LittleEndian.Uint16(src[6:])
var j int
for j <= 16 {
// mix r0
r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1)
r0 = bits.RotateLeft16(r0, 1)
j++
// mix r1
r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2)
r1 = bits.RotateLeft16(r1, 2)
j++
// mix r2
r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3)
r2 = bits.RotateLeft16(r2, 3)
j++
// mix r3
r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0)
r3 = bits.RotateLeft16(r3, 5)
j++
}
r0 = r0 + c.k[r3&63]
r1 = r1 + c.k[r0&63]
r2 = r2 + c.k[r1&63]
r3 = r3 + c.k[r2&63]
for j <= 40 {
// mix r0
r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1)
r0 = bits.RotateLeft16(r0, 1)
j++
// mix r1
r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2)
r1 = bits.RotateLeft16(r1, 2)
j++
// mix r2
r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3)
r2 = bits.RotateLeft16(r2, 3)
j++
// mix r3
r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0)
r3 = bits.RotateLeft16(r3, 5)
j++
}
r0 = r0 + c.k[r3&63]
r1 = r1 + c.k[r0&63]
r2 = r2 + c.k[r1&63]
r3 = r3 + c.k[r2&63]
for j <= 60 {
// mix r0
r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1)
r0 = bits.RotateLeft16(r0, 1)
j++
// mix r1
r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2)
r1 = bits.RotateLeft16(r1, 2)
j++
// mix r2
r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3)
r2 = bits.RotateLeft16(r2, 3)
j++
// mix r3
r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0)
r3 = bits.RotateLeft16(r3, 5)
j++
}
binary.LittleEndian.PutUint16(dst[0:], r0)
binary.LittleEndian.PutUint16(dst[2:], r1)
binary.LittleEndian.PutUint16(dst[4:], r2)
binary.LittleEndian.PutUint16(dst[6:], r3)
}
func (c *rc2Cipher) Decrypt(dst, src []byte) {
r0 := binary.LittleEndian.Uint16(src[0:])
r1 := binary.LittleEndian.Uint16(src[2:])
r2 := binary.LittleEndian.Uint16(src[4:])
r3 := binary.LittleEndian.Uint16(src[6:])
j := 63
for j >= 44 {
// unmix r3
r3 = bits.RotateLeft16(r3, 16-5)
r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0)
j--
// unmix r2
r2 = bits.RotateLeft16(r2, 16-3)
r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3)
j--
// unmix r1
r1 = bits.RotateLeft16(r1, 16-2)
r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2)
j--
// unmix r0
r0 = bits.RotateLeft16(r0, 16-1)
r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1)
j--
}
r3 = r3 - c.k[r2&63]
r2 = r2 - c.k[r1&63]
r1 = r1 - c.k[r0&63]
r0 = r0 - c.k[r3&63]
for j >= 20 {
// unmix r3
r3 = bits.RotateLeft16(r3, 16-5)
r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0)
j--
// unmix r2
r2 = bits.RotateLeft16(r2, 16-3)
r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3)
j--
// unmix r1
r1 = bits.RotateLeft16(r1, 16-2)
r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2)
j--
// unmix r0
r0 = bits.RotateLeft16(r0, 16-1)
r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1)
j--
}
r3 = r3 - c.k[r2&63]
r2 = r2 - c.k[r1&63]
r1 = r1 - c.k[r0&63]
r0 = r0 - c.k[r3&63]
for j >= 0 {
// unmix r3
r3 = bits.RotateLeft16(r3, 16-5)
r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0)
j--
// unmix r2
r2 = bits.RotateLeft16(r2, 16-3)
r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3)
j--
// unmix r1
r1 = bits.RotateLeft16(r1, 16-2)
r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2)
j--
// unmix r0
r0 = bits.RotateLeft16(r0, 16-1)
r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1)
j--
}
binary.LittleEndian.PutUint16(dst[0:], r0)
binary.LittleEndian.PutUint16(dst[2:], r1)
binary.LittleEndian.PutUint16(dst[4:], r2)
binary.LittleEndian.PutUint16(dst[6:], r3)
}
// 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.
package pkcs12
import (
"crypto/hmac"
"crypto/sha1"
"crypto/x509/pkix"
"encoding/asn1"
)
type macData struct {
Mac digestInfo
MacSalt []byte
Iterations int `asn1:"optional,default:1"`
}
// from PKCS#7:
type digestInfo struct {
Algorithm pkix.AlgorithmIdentifier
Digest []byte
}
var (
oidSHA1 = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26})
)
func verifyMac(macData *macData, message, password []byte) error {
if !macData.Mac.Algorithm.Algorithm.Equal(oidSHA1) {
return NotImplementedError("unknown digest algorithm: " + macData.Mac.Algorithm.Algorithm.String())
}
key := pbkdf(sha1Sum, 20, 64, macData.MacSalt, password, macData.Iterations, 3, 20)
mac := hmac.New(sha1.New, key)
mac.Write(message)
expectedMAC := mac.Sum(nil)
if !hmac.Equal(macData.Mac.Digest, expectedMAC) {
return ErrIncorrectPassword
}
return nil
}
// 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.
package pkcs12
import (
"bytes"
"crypto/sha1"
"math/big"
)
var (
one = big.NewInt(1)
)
// sha1Sum returns the SHA-1 hash of in.
func sha1Sum(in []byte) []byte {
sum := sha1.Sum(in)
return sum[:]
}
// fillWithRepeats returns v*ceiling(len(pattern) / v) bytes consisting of
// repeats of pattern.
func fillWithRepeats(pattern []byte, v int) []byte {
if len(pattern) == 0 {
return nil
}
outputLen := v * ((len(pattern) + v - 1) / v)
return bytes.Repeat(pattern, (outputLen+len(pattern)-1)/len(pattern))[:outputLen]
}
func pbkdf(hash func([]byte) []byte, u, v int, salt, password []byte, r int, ID byte, size int) (key []byte) {
// implementation of https://tools.ietf.org/html/rfc7292#appendix-B.2 , RFC text verbatim in comments
// Let H be a hash function built around a compression function f:
// Z_2^u x Z_2^v -> Z_2^u
// (that is, H has a chaining variable and output of length u bits, and
// the message input to the compression function of H is v bits). The
// values for u and v are as follows:
// HASH FUNCTION VALUE u VALUE v
// MD2, MD5 128 512
// SHA-1 160 512
// SHA-224 224 512
// SHA-256 256 512
// SHA-384 384 1024
// SHA-512 512 1024
// SHA-512/224 224 1024
// SHA-512/256 256 1024
// Furthermore, let r be the iteration count.
// We assume here that u and v are both multiples of 8, as are the
// lengths of the password and salt strings (which we denote by p and s,
// respectively) and the number n of pseudorandom bits required. In
// addition, u and v are of course non-zero.
// For information on security considerations for MD5 [19], see [25] and
// [1], and on those for MD2, see [18].
// The following procedure can be used to produce pseudorandom bits for
// a particular "purpose" that is identified by a byte called "ID".
// This standard specifies 3 different values for the ID byte:
// 1. If ID=1, then the pseudorandom bits being produced are to be used
// as key material for performing encryption or decryption.
// 2. If ID=2, then the pseudorandom bits being produced are to be used
// as an IV (Initial Value) for encryption or decryption.
// 3. If ID=3, then the pseudorandom bits being produced are to be used
// as an integrity key for MACing.
// 1. Construct a string, D (the "diversifier"), by concatenating v/8
// copies of ID.
var D []byte
for i := 0; i < v; i++ {
D = append(D, ID)
}
// 2. Concatenate copies of the salt together to create a string S of
// length v(ceiling(s/v)) bits (the final copy of the salt may be
// truncated to create S). Note that if the salt is the empty
// string, then so is S.
S := fillWithRepeats(salt, v)
// 3. Concatenate copies of the password together to create a string P
// of length v(ceiling(p/v)) bits (the final copy of the password
// may be truncated to create P). Note that if the password is the
// empty string, then so is P.
P := fillWithRepeats(password, v)
// 4. Set I=S||P to be the concatenation of S and P.
I := append(S, P...)
// 5. Set c=ceiling(n/u).
c := (size + u - 1) / u
// 6. For i=1, 2, ..., c, do the following:
A := make([]byte, c*20)
var IjBuf []byte
for i := 0; i < c; i++ {
// A. Set A2=H^r(D||I). (i.e., the r-th hash of D||1,
// H(H(H(... H(D||I))))
Ai := hash(append(D, I...))
for j := 1; j < r; j++ {
Ai = hash(Ai)
}
copy(A[i*20:], Ai[:])
if i < c-1 { // skip on last iteration
// B. Concatenate copies of Ai to create a string B of length v
// bits (the final copy of Ai may be truncated to create B).
var B []byte
for len(B) < v {
B = append(B, Ai[:]...)
}
B = B[:v]
// C. Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit
// blocks, where k=ceiling(s/v)+ceiling(p/v), modify I by
// setting I_j=(I_j+B+1) mod 2^v for each j.
{
Bbi := new(big.Int).SetBytes(B)
Ij := new(big.Int)
for j := 0; j < len(I)/v; j++ {
Ij.SetBytes(I[j*v : (j+1)*v])
Ij.Add(Ij, Bbi)
Ij.Add(Ij, one)
Ijb := Ij.Bytes()
// We expect Ijb to be exactly v bytes,
// if it is longer or shorter we must
// adjust it accordingly.
if len(Ijb) > v {
Ijb = Ijb[len(Ijb)-v:]
}
if len(Ijb) < v {
if IjBuf == nil {
IjBuf = make([]byte, v)
}
bytesShort := v - len(Ijb)
for i := 0; i < bytesShort; i++ {
IjBuf[i] = 0
}
copy(IjBuf[bytesShort:], Ijb)
Ijb = IjBuf
}
copy(I[j*v:(j+1)*v], Ijb)
}
}
}
}
// 7. Concatenate A_1, A_2, ..., A_c together to form a pseudorandom
// bit string, A.
// 8. Use the first n bits of A as the output of this entire process.
return A[:size]
// If the above process is being used to generate a DES key, the process
// should be used to create 64 random bits, and the key's parity bits
// should be set after the 64 bits have been produced. Similar concerns
// hold for 2-key and 3-key triple-DES keys, for CDMF keys, and for any
// similar keys with parity bits "built into them".
}
// 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.
// Package pkcs12 implements some of PKCS#12.
//
// This implementation is distilled from [RFC 7292] and referenced documents.
// It is intended for decoding P12/PFX-stored certificates and keys for use
// with the crypto/tls package.
//
// The pkcs12 package is [frozen] and is not accepting new features.
// If it's missing functionality you need, consider an alternative like
// software.sslmate.com/src/go-pkcs12.
//
// [RFC 7292]: https://datatracker.ietf.org/doc/html/rfc7292
// [frozen]: https://go.dev/wiki/Frozen
package pkcs12
import (
"crypto/ecdsa"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/hex"
"encoding/pem"
"errors"
)
var (
oidDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 1})
oidEncryptedDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 6})
oidFriendlyName = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 20})
oidLocalKeyID = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 21})
oidMicrosoftCSPName = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 4, 1, 311, 17, 1})
errUnknownAttributeOID = errors.New("pkcs12: unknown attribute OID")
)
type pfxPdu struct {
Version int
AuthSafe contentInfo
MacData macData `asn1:"optional"`
}
type contentInfo struct {
ContentType asn1.ObjectIdentifier
Content asn1.RawValue `asn1:"tag:0,explicit,optional"`
}
type encryptedData struct {
Version int
EncryptedContentInfo encryptedContentInfo
}
type encryptedContentInfo struct {
ContentType asn1.ObjectIdentifier
ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
EncryptedContent []byte `asn1:"tag:0,optional"`
}
func (i encryptedContentInfo) Algorithm() pkix.AlgorithmIdentifier {
return i.ContentEncryptionAlgorithm
}
func (i encryptedContentInfo) Data() []byte { return i.EncryptedContent }
type safeBag struct {
Id asn1.ObjectIdentifier
Value asn1.RawValue `asn1:"tag:0,explicit"`
Attributes []pkcs12Attribute `asn1:"set,optional"`
}
type pkcs12Attribute struct {
Id asn1.ObjectIdentifier
Value asn1.RawValue `asn1:"set"`
}
type encryptedPrivateKeyInfo struct {
AlgorithmIdentifier pkix.AlgorithmIdentifier
EncryptedData []byte
}
func (i encryptedPrivateKeyInfo) Algorithm() pkix.AlgorithmIdentifier {
return i.AlgorithmIdentifier
}
func (i encryptedPrivateKeyInfo) Data() []byte {
return i.EncryptedData
}
// PEM block types
const (
certificateType = "CERTIFICATE"
privateKeyType = "PRIVATE KEY"
)
// unmarshal calls asn1.Unmarshal, but also returns an error if there is any
// trailing data after unmarshaling.
func unmarshal(in []byte, out interface{}) error {
trailing, err := asn1.Unmarshal(in, out)
if err != nil {
return err
}
if len(trailing) != 0 {
return errors.New("pkcs12: trailing data found")
}
return nil
}
// ToPEM converts all "safe bags" contained in pfxData to PEM blocks.
// Unknown attributes are discarded.
//
// Note that although the returned PEM blocks for private keys have type
// "PRIVATE KEY", the bytes are not encoded according to PKCS #8, but according
// to PKCS #1 for RSA keys and SEC 1 for ECDSA keys.
func ToPEM(pfxData []byte, password string) ([]*pem.Block, error) {
encodedPassword, err := bmpString(password)
if err != nil {
return nil, ErrIncorrectPassword
}
bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
if err != nil {
return nil, err
}
blocks := make([]*pem.Block, 0, len(bags))
for _, bag := range bags {
block, err := convertBag(&bag, encodedPassword)
if err != nil {
return nil, err
}
blocks = append(blocks, block)
}
return blocks, nil
}
func convertBag(bag *safeBag, password []byte) (*pem.Block, error) {
block := &pem.Block{
Headers: make(map[string]string),
}
for _, attribute := range bag.Attributes {
k, v, err := convertAttribute(&attribute)
if err == errUnknownAttributeOID {
continue
}
if err != nil {
return nil, err
}
block.Headers[k] = v
}
switch {
case bag.Id.Equal(oidCertBag):
block.Type = certificateType
certsData, err := decodeCertBag(bag.Value.Bytes)
if err != nil {
return nil, err
}
block.Bytes = certsData
case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
block.Type = privateKeyType
key, err := decodePkcs8ShroudedKeyBag(bag.Value.Bytes, password)
if err != nil {
return nil, err
}
switch key := key.(type) {
case *rsa.PrivateKey:
block.Bytes = x509.MarshalPKCS1PrivateKey(key)
case *ecdsa.PrivateKey:
block.Bytes, err = x509.MarshalECPrivateKey(key)
if err != nil {
return nil, err
}
default:
return nil, errors.New("found unknown private key type in PKCS#8 wrapping")
}
default:
return nil, errors.New("don't know how to convert a safe bag of type " + bag.Id.String())
}
return block, nil
}
func convertAttribute(attribute *pkcs12Attribute) (key, value string, err error) {
isString := false
switch {
case attribute.Id.Equal(oidFriendlyName):
key = "friendlyName"
isString = true
case attribute.Id.Equal(oidLocalKeyID):
key = "localKeyId"
case attribute.Id.Equal(oidMicrosoftCSPName):
// This key is chosen to match OpenSSL.
key = "Microsoft CSP Name"
isString = true
default:
return "", "", errUnknownAttributeOID
}
if isString {
if err := unmarshal(attribute.Value.Bytes, &attribute.Value); err != nil {
return "", "", err
}
if value, err = decodeBMPString(attribute.Value.Bytes); err != nil {
return "", "", err
}
} else {
var id []byte
if err := unmarshal(attribute.Value.Bytes, &id); err != nil {
return "", "", err
}
value = hex.EncodeToString(id)
}
return key, value, nil
}
// Decode extracts a certificate and private key from pfxData. This function
// assumes that there is only one certificate and only one private key in the
// pfxData; if there are more use ToPEM instead.
func Decode(pfxData []byte, password string) (privateKey interface{}, certificate *x509.Certificate, err error) {
encodedPassword, err := bmpString(password)
if err != nil {
return nil, nil, err
}
bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
if err != nil {
return nil, nil, err
}
if len(bags) != 2 {
err = errors.New("pkcs12: expected exactly two safe bags in the PFX PDU")
return
}
for _, bag := range bags {
switch {
case bag.Id.Equal(oidCertBag):
if certificate != nil {
err = errors.New("pkcs12: expected exactly one certificate bag")
}
certsData, err := decodeCertBag(bag.Value.Bytes)
if err != nil {
return nil, nil, err
}
certs, err := x509.ParseCertificates(certsData)
if err != nil {
return nil, nil, err
}
if len(certs) != 1 {
err = errors.New("pkcs12: expected exactly one certificate in the certBag")
return nil, nil, err
}
certificate = certs[0]
case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
if privateKey != nil {
err = errors.New("pkcs12: expected exactly one key bag")
return nil, nil, err
}
if privateKey, err = decodePkcs8ShroudedKeyBag(bag.Value.Bytes, encodedPassword); err != nil {
return nil, nil, err
}
}
}
if certificate == nil {
return nil, nil, errors.New("pkcs12: certificate missing")
}
if privateKey == nil {
return nil, nil, errors.New("pkcs12: private key missing")
}
return
}
func getSafeContents(p12Data, password []byte) (bags []safeBag, updatedPassword []byte, err error) {
pfx := new(pfxPdu)
if err := unmarshal(p12Data, pfx); err != nil {
return nil, nil, errors.New("pkcs12: error reading P12 data: " + err.Error())
}
if pfx.Version != 3 {
return nil, nil, NotImplementedError("can only decode v3 PFX PDU's")
}
if !pfx.AuthSafe.ContentType.Equal(oidDataContentType) {
return nil, nil, NotImplementedError("only password-protected PFX is implemented")
}
// unmarshal the explicit bytes in the content for type 'data'
if err := unmarshal(pfx.AuthSafe.Content.Bytes, &pfx.AuthSafe.Content); err != nil {
return nil, nil, err
}
if len(pfx.MacData.Mac.Algorithm.Algorithm) == 0 {
return nil, nil, errors.New("pkcs12: no MAC in data")
}
if err := verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password); err != nil {
if err == ErrIncorrectPassword && len(password) == 2 && password[0] == 0 && password[1] == 0 {
// some implementations use an empty byte array
// for the empty string password try one more
// time with empty-empty password
password = nil
err = verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password)
}
if err != nil {
return nil, nil, err
}
}
var authenticatedSafe []contentInfo
if err := unmarshal(pfx.AuthSafe.Content.Bytes, &authenticatedSafe); err != nil {
return nil, nil, err
}
if len(authenticatedSafe) != 2 {
return nil, nil, NotImplementedError("expected exactly two items in the authenticated safe")
}
for _, ci := range authenticatedSafe {
var data []byte
switch {
case ci.ContentType.Equal(oidDataContentType):
if err := unmarshal(ci.Content.Bytes, &data); err != nil {
return nil, nil, err
}
case ci.ContentType.Equal(oidEncryptedDataContentType):
var encryptedData encryptedData
if err := unmarshal(ci.Content.Bytes, &encryptedData); err != nil {
return nil, nil, err
}
if encryptedData.Version != 0 {
return nil, nil, NotImplementedError("only version 0 of EncryptedData is supported")
}
if data, err = pbDecrypt(encryptedData.EncryptedContentInfo, password); err != nil {
return nil, nil, err
}
default:
return nil, nil, NotImplementedError("only data and encryptedData content types are supported in authenticated safe")
}
var safeContents []safeBag
if err := unmarshal(data, &safeContents); err != nil {
return nil, nil, err
}
bags = append(bags, safeContents...)
}
return bags, password, nil
}
// 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.
package pkcs12
import (
"crypto/x509"
"encoding/asn1"
"errors"
)
var (
// see https://tools.ietf.org/html/rfc7292#appendix-D
oidCertTypeX509Certificate = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 22, 1})
oidPKCS8ShroundedKeyBag = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 10, 1, 2})
oidCertBag = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 10, 1, 3})
)
type certBag struct {
Id asn1.ObjectIdentifier
Data []byte `asn1:"tag:0,explicit"`
}
func decodePkcs8ShroudedKeyBag(asn1Data, password []byte) (privateKey interface{}, err error) {
pkinfo := new(encryptedPrivateKeyInfo)
if err = unmarshal(asn1Data, pkinfo); err != nil {
return nil, errors.New("pkcs12: error decoding PKCS#8 shrouded key bag: " + err.Error())
}
pkData, err := pbDecrypt(pkinfo, password)
if err != nil {
return nil, errors.New("pkcs12: error decrypting PKCS#8 shrouded key bag: " + err.Error())
}
ret := new(asn1.RawValue)
if err = unmarshal(pkData, ret); err != nil {
return nil, errors.New("pkcs12: error unmarshaling decrypted private key: " + err.Error())
}
if privateKey, err = x509.ParsePKCS8PrivateKey(pkData); err != nil {
return nil, errors.New("pkcs12: error parsing PKCS#8 private key: " + err.Error())
}
return privateKey, nil
}
func decodeCertBag(asn1Data []byte) (x509Certificates []byte, err error) {
bag := new(certBag)
if err := unmarshal(asn1Data, bag); err != nil {
return nil, errors.New("pkcs12: error decoding cert bag: " + err.Error())
}
if !bag.Id.Equal(oidCertTypeX509Certificate) {
return nil, NotImplementedError("only X509 certificates are supported")
}
return bag.Data, nil
}
// 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.
// Package poly1305 implements Poly1305 one-time message authentication code as
// specified in https://cr.yp.to/mac/poly1305-20050329.pdf.
//
// Poly1305 is a fast, one-time authentication function. It is infeasible for an
// attacker to generate an authenticator for a message without the key. However, a
// key must only be used for a single message. Authenticating two different
// messages with the same key allows an attacker to forge authenticators for other
// messages with the same key.
//
// Poly1305 was originally coupled with AES in order to make Poly1305-AES. AES was
// used with a fixed key in order to generate one-time keys from an nonce.
// However, in this package AES isn't used and the one-time key is specified
// directly.
//
// Deprecated: Poly1305 as implemented by this package is a cryptographic
// building block that is not safe for general purpose use.
// For encryption, use the full ChaCha20-Poly1305 construction implemented by
// golang.org/x/crypto/chacha20poly1305. For authentication, use a general
// purpose MAC such as HMAC implemented by crypto/hmac.
package poly1305
import "golang.org/x/crypto/internal/poly1305"
// TagSize is the size, in bytes, of a poly1305 authenticator.
//
// For use with golang.org/x/crypto/chacha20poly1305, chacha20poly1305.Overhead
// can be used instead.
const TagSize = 16
// Sum generates an authenticator for msg using a one-time key and puts the
// 16-byte result into out. Authenticating two different messages with the same
// key allows an attacker to forge messages at will.
func Sum(out *[16]byte, m []byte, key *[32]byte) {
poly1305.Sum(out, m, key)
}
// Verify returns true if mac is a valid authenticator for m with the given key.
func Verify(mac *[16]byte, m []byte, key *[32]byte) bool {
return poly1305.Verify(mac, m, key)
}
// New returns a new MAC computing an authentication
// tag of all data written to it with the given key.
// This allows writing the message progressively instead
// of passing it as a single slice. Common users should use
// the Sum function instead.
//
// The key must be unique for each message, as authenticating
// two different messages with the same key allows an attacker
// to forge messages at will.
func New(key *[32]byte) *MAC {
return &MAC{mac: poly1305.New(key)}
}
// MAC is an io.Writer computing an authentication tag
// of the data written to it.
//
// MAC cannot be used like common hash.Hash implementations,
// because using a poly1305 key twice breaks its security.
// Therefore writing data to a running MAC after calling
// Sum or Verify causes it to panic.
type MAC struct {
mac *poly1305.MAC
}
// Size returns the number of bytes Sum will return.
func (h *MAC) Size() int { return TagSize }
// Write adds more data to the running message authentication code.
// It never returns an error.
//
// It must not be called after the first call of Sum or Verify.
func (h *MAC) Write(p []byte) (n int, err error) {
return h.mac.Write(p)
}
// Sum computes the authenticator of all data written to the
// message authentication code.
func (h *MAC) Sum(b []byte) []byte {
return h.mac.Sum(b)
}
// Verify returns whether the authenticator of all data written to
// the message authentication code matches the expected value.
func (h *MAC) Verify(expected []byte) bool {
return h.mac.Verify(expected)
}
// 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.
// Package salsa provides low-level access to functions in the Salsa family.
//
// Deprecated: this package exposes unsafe low-level operations. New applications
// should consider using the AEAD construction in golang.org/x/crypto/chacha20poly1305
// instead. Existing users should migrate to golang.org/x/crypto/salsa20.
package salsa
import "math/bits"
// Sigma is the Salsa20 constant for 256-bit keys.
var Sigma = [16]byte{'e', 'x', 'p', 'a', 'n', 'd', ' ', '3', '2', '-', 'b', 'y', 't', 'e', ' ', 'k'}
// HSalsa20 applies the HSalsa20 core function to a 16-byte input in, 32-byte
// key k, and 16-byte constant c, and puts the result into the 32-byte array
// out.
func HSalsa20(out *[32]byte, in *[16]byte, k *[32]byte, c *[16]byte) {
x0 := uint32(c[0]) | uint32(c[1])<<8 | uint32(c[2])<<16 | uint32(c[3])<<24
x1 := uint32(k[0]) | uint32(k[1])<<8 | uint32(k[2])<<16 | uint32(k[3])<<24
x2 := uint32(k[4]) | uint32(k[5])<<8 | uint32(k[6])<<16 | uint32(k[7])<<24
x3 := uint32(k[8]) | uint32(k[9])<<8 | uint32(k[10])<<16 | uint32(k[11])<<24
x4 := uint32(k[12]) | uint32(k[13])<<8 | uint32(k[14])<<16 | uint32(k[15])<<24
x5 := uint32(c[4]) | uint32(c[5])<<8 | uint32(c[6])<<16 | uint32(c[7])<<24
x6 := uint32(in[0]) | uint32(in[1])<<8 | uint32(in[2])<<16 | uint32(in[3])<<24
x7 := uint32(in[4]) | uint32(in[5])<<8 | uint32(in[6])<<16 | uint32(in[7])<<24
x8 := uint32(in[8]) | uint32(in[9])<<8 | uint32(in[10])<<16 | uint32(in[11])<<24
x9 := uint32(in[12]) | uint32(in[13])<<8 | uint32(in[14])<<16 | uint32(in[15])<<24
x10 := uint32(c[8]) | uint32(c[9])<<8 | uint32(c[10])<<16 | uint32(c[11])<<24
x11 := uint32(k[16]) | uint32(k[17])<<8 | uint32(k[18])<<16 | uint32(k[19])<<24
x12 := uint32(k[20]) | uint32(k[21])<<8 | uint32(k[22])<<16 | uint32(k[23])<<24
x13 := uint32(k[24]) | uint32(k[25])<<8 | uint32(k[26])<<16 | uint32(k[27])<<24
x14 := uint32(k[28]) | uint32(k[29])<<8 | uint32(k[30])<<16 | uint32(k[31])<<24
x15 := uint32(c[12]) | uint32(c[13])<<8 | uint32(c[14])<<16 | uint32(c[15])<<24
for i := 0; i < 20; i += 2 {
u := x0 + x12
x4 ^= bits.RotateLeft32(u, 7)
u = x4 + x0
x8 ^= bits.RotateLeft32(u, 9)
u = x8 + x4
x12 ^= bits.RotateLeft32(u, 13)
u = x12 + x8
x0 ^= bits.RotateLeft32(u, 18)
u = x5 + x1
x9 ^= bits.RotateLeft32(u, 7)
u = x9 + x5
x13 ^= bits.RotateLeft32(u, 9)
u = x13 + x9
x1 ^= bits.RotateLeft32(u, 13)
u = x1 + x13
x5 ^= bits.RotateLeft32(u, 18)
u = x10 + x6
x14 ^= bits.RotateLeft32(u, 7)
u = x14 + x10
x2 ^= bits.RotateLeft32(u, 9)
u = x2 + x14
x6 ^= bits.RotateLeft32(u, 13)
u = x6 + x2
x10 ^= bits.RotateLeft32(u, 18)
u = x15 + x11
x3 ^= bits.RotateLeft32(u, 7)
u = x3 + x15
x7 ^= bits.RotateLeft32(u, 9)
u = x7 + x3
x11 ^= bits.RotateLeft32(u, 13)
u = x11 + x7
x15 ^= bits.RotateLeft32(u, 18)
u = x0 + x3
x1 ^= bits.RotateLeft32(u, 7)
u = x1 + x0
x2 ^= bits.RotateLeft32(u, 9)
u = x2 + x1
x3 ^= bits.RotateLeft32(u, 13)
u = x3 + x2
x0 ^= bits.RotateLeft32(u, 18)
u = x5 + x4
x6 ^= bits.RotateLeft32(u, 7)
u = x6 + x5
x7 ^= bits.RotateLeft32(u, 9)
u = x7 + x6
x4 ^= bits.RotateLeft32(u, 13)
u = x4 + x7
x5 ^= bits.RotateLeft32(u, 18)
u = x10 + x9
x11 ^= bits.RotateLeft32(u, 7)
u = x11 + x10
x8 ^= bits.RotateLeft32(u, 9)
u = x8 + x11
x9 ^= bits.RotateLeft32(u, 13)
u = x9 + x8
x10 ^= bits.RotateLeft32(u, 18)
u = x15 + x14
x12 ^= bits.RotateLeft32(u, 7)
u = x12 + x15
x13 ^= bits.RotateLeft32(u, 9)
u = x13 + x12
x14 ^= bits.RotateLeft32(u, 13)
u = x14 + x13
x15 ^= bits.RotateLeft32(u, 18)
}
out[0] = byte(x0)
out[1] = byte(x0 >> 8)
out[2] = byte(x0 >> 16)
out[3] = byte(x0 >> 24)
out[4] = byte(x5)
out[5] = byte(x5 >> 8)
out[6] = byte(x5 >> 16)
out[7] = byte(x5 >> 24)
out[8] = byte(x10)
out[9] = byte(x10 >> 8)
out[10] = byte(x10 >> 16)
out[11] = byte(x10 >> 24)
out[12] = byte(x15)
out[13] = byte(x15 >> 8)
out[14] = byte(x15 >> 16)
out[15] = byte(x15 >> 24)
out[16] = byte(x6)
out[17] = byte(x6 >> 8)
out[18] = byte(x6 >> 16)
out[19] = byte(x6 >> 24)
out[20] = byte(x7)
out[21] = byte(x7 >> 8)
out[22] = byte(x7 >> 16)
out[23] = byte(x7 >> 24)
out[24] = byte(x8)
out[25] = byte(x8 >> 8)
out[26] = byte(x8 >> 16)
out[27] = byte(x8 >> 24)
out[28] = byte(x9)
out[29] = byte(x9 >> 8)
out[30] = byte(x9 >> 16)
out[31] = byte(x9 >> 24)
}
// 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.
package salsa
import "math/bits"
// Core208 applies the Salsa20/8 core function to the 64-byte array in and puts
// the result into the 64-byte array out. The input and output may be the same array.
func Core208(out *[64]byte, in *[64]byte) {
j0 := uint32(in[0]) | uint32(in[1])<<8 | uint32(in[2])<<16 | uint32(in[3])<<24
j1 := uint32(in[4]) | uint32(in[5])<<8 | uint32(in[6])<<16 | uint32(in[7])<<24
j2 := uint32(in[8]) | uint32(in[9])<<8 | uint32(in[10])<<16 | uint32(in[11])<<24
j3 := uint32(in[12]) | uint32(in[13])<<8 | uint32(in[14])<<16 | uint32(in[15])<<24
j4 := uint32(in[16]) | uint32(in[17])<<8 | uint32(in[18])<<16 | uint32(in[19])<<24
j5 := uint32(in[20]) | uint32(in[21])<<8 | uint32(in[22])<<16 | uint32(in[23])<<24
j6 := uint32(in[24]) | uint32(in[25])<<8 | uint32(in[26])<<16 | uint32(in[27])<<24
j7 := uint32(in[28]) | uint32(in[29])<<8 | uint32(in[30])<<16 | uint32(in[31])<<24
j8 := uint32(in[32]) | uint32(in[33])<<8 | uint32(in[34])<<16 | uint32(in[35])<<24
j9 := uint32(in[36]) | uint32(in[37])<<8 | uint32(in[38])<<16 | uint32(in[39])<<24
j10 := uint32(in[40]) | uint32(in[41])<<8 | uint32(in[42])<<16 | uint32(in[43])<<24
j11 := uint32(in[44]) | uint32(in[45])<<8 | uint32(in[46])<<16 | uint32(in[47])<<24
j12 := uint32(in[48]) | uint32(in[49])<<8 | uint32(in[50])<<16 | uint32(in[51])<<24
j13 := uint32(in[52]) | uint32(in[53])<<8 | uint32(in[54])<<16 | uint32(in[55])<<24
j14 := uint32(in[56]) | uint32(in[57])<<8 | uint32(in[58])<<16 | uint32(in[59])<<24
j15 := uint32(in[60]) | uint32(in[61])<<8 | uint32(in[62])<<16 | uint32(in[63])<<24
x0, x1, x2, x3, x4, x5, x6, x7, x8 := j0, j1, j2, j3, j4, j5, j6, j7, j8
x9, x10, x11, x12, x13, x14, x15 := j9, j10, j11, j12, j13, j14, j15
for i := 0; i < 8; i += 2 {
u := x0 + x12
x4 ^= bits.RotateLeft32(u, 7)
u = x4 + x0
x8 ^= bits.RotateLeft32(u, 9)
u = x8 + x4
x12 ^= bits.RotateLeft32(u, 13)
u = x12 + x8
x0 ^= bits.RotateLeft32(u, 18)
u = x5 + x1
x9 ^= bits.RotateLeft32(u, 7)
u = x9 + x5
x13 ^= bits.RotateLeft32(u, 9)
u = x13 + x9
x1 ^= bits.RotateLeft32(u, 13)
u = x1 + x13
x5 ^= bits.RotateLeft32(u, 18)
u = x10 + x6
x14 ^= bits.RotateLeft32(u, 7)
u = x14 + x10
x2 ^= bits.RotateLeft32(u, 9)
u = x2 + x14
x6 ^= bits.RotateLeft32(u, 13)
u = x6 + x2
x10 ^= bits.RotateLeft32(u, 18)
u = x15 + x11
x3 ^= bits.RotateLeft32(u, 7)
u = x3 + x15
x7 ^= bits.RotateLeft32(u, 9)
u = x7 + x3
x11 ^= bits.RotateLeft32(u, 13)
u = x11 + x7
x15 ^= bits.RotateLeft32(u, 18)
u = x0 + x3
x1 ^= bits.RotateLeft32(u, 7)
u = x1 + x0
x2 ^= bits.RotateLeft32(u, 9)
u = x2 + x1
x3 ^= bits.RotateLeft32(u, 13)
u = x3 + x2
x0 ^= bits.RotateLeft32(u, 18)
u = x5 + x4
x6 ^= bits.RotateLeft32(u, 7)
u = x6 + x5
x7 ^= bits.RotateLeft32(u, 9)
u = x7 + x6
x4 ^= bits.RotateLeft32(u, 13)
u = x4 + x7
x5 ^= bits.RotateLeft32(u, 18)
u = x10 + x9
x11 ^= bits.RotateLeft32(u, 7)
u = x11 + x10
x8 ^= bits.RotateLeft32(u, 9)
u = x8 + x11
x9 ^= bits.RotateLeft32(u, 13)
u = x9 + x8
x10 ^= bits.RotateLeft32(u, 18)
u = x15 + x14
x12 ^= bits.RotateLeft32(u, 7)
u = x12 + x15
x13 ^= bits.RotateLeft32(u, 9)
u = x13 + x12
x14 ^= bits.RotateLeft32(u, 13)
u = x14 + x13
x15 ^= bits.RotateLeft32(u, 18)
}
x0 += j0
x1 += j1
x2 += j2
x3 += j3
x4 += j4
x5 += j5
x6 += j6
x7 += j7
x8 += j8
x9 += j9
x10 += j10
x11 += j11
x12 += j12
x13 += j13
x14 += j14
x15 += j15
out[0] = byte(x0)
out[1] = byte(x0 >> 8)
out[2] = byte(x0 >> 16)
out[3] = byte(x0 >> 24)
out[4] = byte(x1)
out[5] = byte(x1 >> 8)
out[6] = byte(x1 >> 16)
out[7] = byte(x1 >> 24)
out[8] = byte(x2)
out[9] = byte(x2 >> 8)
out[10] = byte(x2 >> 16)
out[11] = byte(x2 >> 24)
out[12] = byte(x3)
out[13] = byte(x3 >> 8)
out[14] = byte(x3 >> 16)
out[15] = byte(x3 >> 24)
out[16] = byte(x4)
out[17] = byte(x4 >> 8)
out[18] = byte(x4 >> 16)
out[19] = byte(x4 >> 24)
out[20] = byte(x5)
out[21] = byte(x5 >> 8)
out[22] = byte(x5 >> 16)
out[23] = byte(x5 >> 24)
out[24] = byte(x6)
out[25] = byte(x6 >> 8)
out[26] = byte(x6 >> 16)
out[27] = byte(x6 >> 24)
out[28] = byte(x7)
out[29] = byte(x7 >> 8)
out[30] = byte(x7 >> 16)
out[31] = byte(x7 >> 24)
out[32] = byte(x8)
out[33] = byte(x8 >> 8)
out[34] = byte(x8 >> 16)
out[35] = byte(x8 >> 24)
out[36] = byte(x9)
out[37] = byte(x9 >> 8)
out[38] = byte(x9 >> 16)
out[39] = byte(x9 >> 24)
out[40] = byte(x10)
out[41] = byte(x10 >> 8)
out[42] = byte(x10 >> 16)
out[43] = byte(x10 >> 24)
out[44] = byte(x11)
out[45] = byte(x11 >> 8)
out[46] = byte(x11 >> 16)
out[47] = byte(x11 >> 24)
out[48] = byte(x12)
out[49] = byte(x12 >> 8)
out[50] = byte(x12 >> 16)
out[51] = byte(x12 >> 24)
out[52] = byte(x13)
out[53] = byte(x13 >> 8)
out[54] = byte(x13 >> 16)
out[55] = byte(x13 >> 24)
out[56] = byte(x14)
out[57] = byte(x14 >> 8)
out[58] = byte(x14 >> 16)
out[59] = byte(x14 >> 24)
out[60] = byte(x15)
out[61] = byte(x15 >> 8)
out[62] = byte(x15 >> 16)
out[63] = byte(x15 >> 24)
}
// 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.
//go:build amd64 && !purego && gc
package salsa
//go:noescape
// salsa2020XORKeyStream is implemented in salsa20_amd64.s.
func salsa2020XORKeyStream(out, in *byte, n uint64, nonce, key *byte)
// XORKeyStream crypts bytes from in to out using the given key and counters.
// In and out must overlap entirely or not at all. Counter
// contains the raw salsa20 counter bytes (both nonce and block counter).
func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
if len(in) == 0 {
return
}
_ = out[len(in)-1]
salsa2020XORKeyStream(&out[0], &in[0], uint64(len(in)), &counter[0], &key[0])
}
// 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.
package salsa
import "math/bits"
const rounds = 20
// core applies the Salsa20 core function to 16-byte input in, 32-byte key k,
// and 16-byte constant c, and puts the result into 64-byte array out.
func core(out *[64]byte, in *[16]byte, k *[32]byte, c *[16]byte) {
j0 := uint32(c[0]) | uint32(c[1])<<8 | uint32(c[2])<<16 | uint32(c[3])<<24
j1 := uint32(k[0]) | uint32(k[1])<<8 | uint32(k[2])<<16 | uint32(k[3])<<24
j2 := uint32(k[4]) | uint32(k[5])<<8 | uint32(k[6])<<16 | uint32(k[7])<<24
j3 := uint32(k[8]) | uint32(k[9])<<8 | uint32(k[10])<<16 | uint32(k[11])<<24
j4 := uint32(k[12]) | uint32(k[13])<<8 | uint32(k[14])<<16 | uint32(k[15])<<24
j5 := uint32(c[4]) | uint32(c[5])<<8 | uint32(c[6])<<16 | uint32(c[7])<<24
j6 := uint32(in[0]) | uint32(in[1])<<8 | uint32(in[2])<<16 | uint32(in[3])<<24
j7 := uint32(in[4]) | uint32(in[5])<<8 | uint32(in[6])<<16 | uint32(in[7])<<24
j8 := uint32(in[8]) | uint32(in[9])<<8 | uint32(in[10])<<16 | uint32(in[11])<<24
j9 := uint32(in[12]) | uint32(in[13])<<8 | uint32(in[14])<<16 | uint32(in[15])<<24
j10 := uint32(c[8]) | uint32(c[9])<<8 | uint32(c[10])<<16 | uint32(c[11])<<24
j11 := uint32(k[16]) | uint32(k[17])<<8 | uint32(k[18])<<16 | uint32(k[19])<<24
j12 := uint32(k[20]) | uint32(k[21])<<8 | uint32(k[22])<<16 | uint32(k[23])<<24
j13 := uint32(k[24]) | uint32(k[25])<<8 | uint32(k[26])<<16 | uint32(k[27])<<24
j14 := uint32(k[28]) | uint32(k[29])<<8 | uint32(k[30])<<16 | uint32(k[31])<<24
j15 := uint32(c[12]) | uint32(c[13])<<8 | uint32(c[14])<<16 | uint32(c[15])<<24
x0, x1, x2, x3, x4, x5, x6, x7, x8 := j0, j1, j2, j3, j4, j5, j6, j7, j8
x9, x10, x11, x12, x13, x14, x15 := j9, j10, j11, j12, j13, j14, j15
for i := 0; i < rounds; i += 2 {
u := x0 + x12
x4 ^= bits.RotateLeft32(u, 7)
u = x4 + x0
x8 ^= bits.RotateLeft32(u, 9)
u = x8 + x4
x12 ^= bits.RotateLeft32(u, 13)
u = x12 + x8
x0 ^= bits.RotateLeft32(u, 18)
u = x5 + x1
x9 ^= bits.RotateLeft32(u, 7)
u = x9 + x5
x13 ^= bits.RotateLeft32(u, 9)
u = x13 + x9
x1 ^= bits.RotateLeft32(u, 13)
u = x1 + x13
x5 ^= bits.RotateLeft32(u, 18)
u = x10 + x6
x14 ^= bits.RotateLeft32(u, 7)
u = x14 + x10
x2 ^= bits.RotateLeft32(u, 9)
u = x2 + x14
x6 ^= bits.RotateLeft32(u, 13)
u = x6 + x2
x10 ^= bits.RotateLeft32(u, 18)
u = x15 + x11
x3 ^= bits.RotateLeft32(u, 7)
u = x3 + x15
x7 ^= bits.RotateLeft32(u, 9)
u = x7 + x3
x11 ^= bits.RotateLeft32(u, 13)
u = x11 + x7
x15 ^= bits.RotateLeft32(u, 18)
u = x0 + x3
x1 ^= bits.RotateLeft32(u, 7)
u = x1 + x0
x2 ^= bits.RotateLeft32(u, 9)
u = x2 + x1
x3 ^= bits.RotateLeft32(u, 13)
u = x3 + x2
x0 ^= bits.RotateLeft32(u, 18)
u = x5 + x4
x6 ^= bits.RotateLeft32(u, 7)
u = x6 + x5
x7 ^= bits.RotateLeft32(u, 9)
u = x7 + x6
x4 ^= bits.RotateLeft32(u, 13)
u = x4 + x7
x5 ^= bits.RotateLeft32(u, 18)
u = x10 + x9
x11 ^= bits.RotateLeft32(u, 7)
u = x11 + x10
x8 ^= bits.RotateLeft32(u, 9)
u = x8 + x11
x9 ^= bits.RotateLeft32(u, 13)
u = x9 + x8
x10 ^= bits.RotateLeft32(u, 18)
u = x15 + x14
x12 ^= bits.RotateLeft32(u, 7)
u = x12 + x15
x13 ^= bits.RotateLeft32(u, 9)
u = x13 + x12
x14 ^= bits.RotateLeft32(u, 13)
u = x14 + x13
x15 ^= bits.RotateLeft32(u, 18)
}
x0 += j0
x1 += j1
x2 += j2
x3 += j3
x4 += j4
x5 += j5
x6 += j6
x7 += j7
x8 += j8
x9 += j9
x10 += j10
x11 += j11
x12 += j12
x13 += j13
x14 += j14
x15 += j15
out[0] = byte(x0)
out[1] = byte(x0 >> 8)
out[2] = byte(x0 >> 16)
out[3] = byte(x0 >> 24)
out[4] = byte(x1)
out[5] = byte(x1 >> 8)
out[6] = byte(x1 >> 16)
out[7] = byte(x1 >> 24)
out[8] = byte(x2)
out[9] = byte(x2 >> 8)
out[10] = byte(x2 >> 16)
out[11] = byte(x2 >> 24)
out[12] = byte(x3)
out[13] = byte(x3 >> 8)
out[14] = byte(x3 >> 16)
out[15] = byte(x3 >> 24)
out[16] = byte(x4)
out[17] = byte(x4 >> 8)
out[18] = byte(x4 >> 16)
out[19] = byte(x4 >> 24)
out[20] = byte(x5)
out[21] = byte(x5 >> 8)
out[22] = byte(x5 >> 16)
out[23] = byte(x5 >> 24)
out[24] = byte(x6)
out[25] = byte(x6 >> 8)
out[26] = byte(x6 >> 16)
out[27] = byte(x6 >> 24)
out[28] = byte(x7)
out[29] = byte(x7 >> 8)
out[30] = byte(x7 >> 16)
out[31] = byte(x7 >> 24)
out[32] = byte(x8)
out[33] = byte(x8 >> 8)
out[34] = byte(x8 >> 16)
out[35] = byte(x8 >> 24)
out[36] = byte(x9)
out[37] = byte(x9 >> 8)
out[38] = byte(x9 >> 16)
out[39] = byte(x9 >> 24)
out[40] = byte(x10)
out[41] = byte(x10 >> 8)
out[42] = byte(x10 >> 16)
out[43] = byte(x10 >> 24)
out[44] = byte(x11)
out[45] = byte(x11 >> 8)
out[46] = byte(x11 >> 16)
out[47] = byte(x11 >> 24)
out[48] = byte(x12)
out[49] = byte(x12 >> 8)
out[50] = byte(x12 >> 16)
out[51] = byte(x12 >> 24)
out[52] = byte(x13)
out[53] = byte(x13 >> 8)
out[54] = byte(x13 >> 16)
out[55] = byte(x13 >> 24)
out[56] = byte(x14)
out[57] = byte(x14 >> 8)
out[58] = byte(x14 >> 16)
out[59] = byte(x14 >> 24)
out[60] = byte(x15)
out[61] = byte(x15 >> 8)
out[62] = byte(x15 >> 16)
out[63] = byte(x15 >> 24)
}
// genericXORKeyStream is the generic implementation of XORKeyStream to be used
// when no assembly implementation is available.
func genericXORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
var block [64]byte
var counterCopy [16]byte
copy(counterCopy[:], counter[:])
for len(in) >= 64 {
core(&block, &counterCopy, key, &Sigma)
for i, x := range block {
out[i] = in[i] ^ x
}
u := uint32(1)
for i := 8; i < 16; i++ {
u += uint32(counterCopy[i])
counterCopy[i] = byte(u)
u >>= 8
}
in = in[64:]
out = out[64:]
}
if len(in) > 0 {
core(&block, &counterCopy, key, &Sigma)
for i, v := range in {
out[i] = v ^ block[i]
}
}
}
// 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.
// Package scrypt implements the scrypt key derivation function as defined in
// Colin Percival's paper "Stronger Key Derivation via Sequential Memory-Hard
// Functions" (https://www.tarsnap.com/scrypt/scrypt.pdf).
package scrypt
import (
"crypto/sha256"
"encoding/binary"
"errors"
"math/bits"
"golang.org/x/crypto/pbkdf2"
)
const maxInt = int(^uint(0) >> 1)
// blockCopy copies n numbers from src into dst.
func blockCopy(dst, src []uint32, n int) {
copy(dst, src[:n])
}
// blockXOR XORs numbers from dst with n numbers from src.
func blockXOR(dst, src []uint32, n int) {
for i, v := range src[:n] {
dst[i] ^= v
}
}
// salsaXOR applies Salsa20/8 to the XOR of 16 numbers from tmp and in,
// and puts the result into both tmp and out.
func salsaXOR(tmp *[16]uint32, in, out []uint32) {
w0 := tmp[0] ^ in[0]
w1 := tmp[1] ^ in[1]
w2 := tmp[2] ^ in[2]
w3 := tmp[3] ^ in[3]
w4 := tmp[4] ^ in[4]
w5 := tmp[5] ^ in[5]
w6 := tmp[6] ^ in[6]
w7 := tmp[7] ^ in[7]
w8 := tmp[8] ^ in[8]
w9 := tmp[9] ^ in[9]
w10 := tmp[10] ^ in[10]
w11 := tmp[11] ^ in[11]
w12 := tmp[12] ^ in[12]
w13 := tmp[13] ^ in[13]
w14 := tmp[14] ^ in[14]
w15 := tmp[15] ^ in[15]
x0, x1, x2, x3, x4, x5, x6, x7, x8 := w0, w1, w2, w3, w4, w5, w6, w7, w8
x9, x10, x11, x12, x13, x14, x15 := w9, w10, w11, w12, w13, w14, w15
for i := 0; i < 8; i += 2 {
x4 ^= bits.RotateLeft32(x0+x12, 7)
x8 ^= bits.RotateLeft32(x4+x0, 9)
x12 ^= bits.RotateLeft32(x8+x4, 13)
x0 ^= bits.RotateLeft32(x12+x8, 18)
x9 ^= bits.RotateLeft32(x5+x1, 7)
x13 ^= bits.RotateLeft32(x9+x5, 9)
x1 ^= bits.RotateLeft32(x13+x9, 13)
x5 ^= bits.RotateLeft32(x1+x13, 18)
x14 ^= bits.RotateLeft32(x10+x6, 7)
x2 ^= bits.RotateLeft32(x14+x10, 9)
x6 ^= bits.RotateLeft32(x2+x14, 13)
x10 ^= bits.RotateLeft32(x6+x2, 18)
x3 ^= bits.RotateLeft32(x15+x11, 7)
x7 ^= bits.RotateLeft32(x3+x15, 9)
x11 ^= bits.RotateLeft32(x7+x3, 13)
x15 ^= bits.RotateLeft32(x11+x7, 18)
x1 ^= bits.RotateLeft32(x0+x3, 7)
x2 ^= bits.RotateLeft32(x1+x0, 9)
x3 ^= bits.RotateLeft32(x2+x1, 13)
x0 ^= bits.RotateLeft32(x3+x2, 18)
x6 ^= bits.RotateLeft32(x5+x4, 7)
x7 ^= bits.RotateLeft32(x6+x5, 9)
x4 ^= bits.RotateLeft32(x7+x6, 13)
x5 ^= bits.RotateLeft32(x4+x7, 18)
x11 ^= bits.RotateLeft32(x10+x9, 7)
x8 ^= bits.RotateLeft32(x11+x10, 9)
x9 ^= bits.RotateLeft32(x8+x11, 13)
x10 ^= bits.RotateLeft32(x9+x8, 18)
x12 ^= bits.RotateLeft32(x15+x14, 7)
x13 ^= bits.RotateLeft32(x12+x15, 9)
x14 ^= bits.RotateLeft32(x13+x12, 13)
x15 ^= bits.RotateLeft32(x14+x13, 18)
}
x0 += w0
x1 += w1
x2 += w2
x3 += w3
x4 += w4
x5 += w5
x6 += w6
x7 += w7
x8 += w8
x9 += w9
x10 += w10
x11 += w11
x12 += w12
x13 += w13
x14 += w14
x15 += w15
out[0], tmp[0] = x0, x0
out[1], tmp[1] = x1, x1
out[2], tmp[2] = x2, x2
out[3], tmp[3] = x3, x3
out[4], tmp[4] = x4, x4
out[5], tmp[5] = x5, x5
out[6], tmp[6] = x6, x6
out[7], tmp[7] = x7, x7
out[8], tmp[8] = x8, x8
out[9], tmp[9] = x9, x9
out[10], tmp[10] = x10, x10
out[11], tmp[11] = x11, x11
out[12], tmp[12] = x12, x12
out[13], tmp[13] = x13, x13
out[14], tmp[14] = x14, x14
out[15], tmp[15] = x15, x15
}
func blockMix(tmp *[16]uint32, in, out []uint32, r int) {
blockCopy(tmp[:], in[(2*r-1)*16:], 16)
for i := 0; i < 2*r; i += 2 {
salsaXOR(tmp, in[i*16:], out[i*8:])
salsaXOR(tmp, in[i*16+16:], out[i*8+r*16:])
}
}
func integer(b []uint32, r int) uint64 {
j := (2*r - 1) * 16
return uint64(b[j]) | uint64(b[j+1])<<32
}
func smix(b []byte, r, N int, v, xy []uint32) {
var tmp [16]uint32
R := 32 * r
x := xy
y := xy[R:]
j := 0
for i := 0; i < R; i++ {
x[i] = binary.LittleEndian.Uint32(b[j:])
j += 4
}
for i := 0; i < N; i += 2 {
blockCopy(v[i*R:], x, R)
blockMix(&tmp, x, y, r)
blockCopy(v[(i+1)*R:], y, R)
blockMix(&tmp, y, x, r)
}
for i := 0; i < N; i += 2 {
j := int(integer(x, r) & uint64(N-1))
blockXOR(x, v[j*R:], R)
blockMix(&tmp, x, y, r)
j = int(integer(y, r) & uint64(N-1))
blockXOR(y, v[j*R:], R)
blockMix(&tmp, y, x, r)
}
j = 0
for _, v := range x[:R] {
binary.LittleEndian.PutUint32(b[j:], v)
j += 4
}
}
// Key derives a key from the password, salt, and cost parameters, returning
// a byte slice of length keyLen that can be used as cryptographic key.
//
// N is a CPU/memory cost parameter, which must be a power of two greater than 1.
// r and p must satisfy r * p < 2³⁰. If the parameters do not satisfy the
// limits, the function returns a nil byte slice and an error.
//
// For example, you can get a derived key for e.g. AES-256 (which needs a
// 32-byte key) by doing:
//
// dk, err := scrypt.Key([]byte("some password"), salt, 32768, 8, 1, 32)
//
// The recommended parameters for interactive logins as of 2017 are N=32768, r=8
// and p=1. The parameters N, r, and p should be increased as memory latency and
// CPU parallelism increases; consider setting N to the highest power of 2 you
// can derive within 100 milliseconds. Remember to get a good random salt.
func Key(password, salt []byte, N, r, p, keyLen int) ([]byte, error) {
if N <= 1 || N&(N-1) != 0 {
return nil, errors.New("scrypt: N must be > 1 and a power of 2")
}
if uint64(r)*uint64(p) >= 1<<30 || r > maxInt/128/p || r > maxInt/256 || N > maxInt/128/r {
return nil, errors.New("scrypt: parameters are too large")
}
xy := make([]uint32, 64*r)
v := make([]uint32, 32*N*r)
b := pbkdf2.Key(password, salt, 1, p*128*r, sha256.New)
for i := 0; i < p; i++ {
smix(b[i*128*r:], r, N, v, xy)
}
return pbkdf2.Key(password, b, 1, keyLen, sha256.New), nil
}
// 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 sha3 implements the SHA-3 hash algorithms and the SHAKE extendable
// output functions defined in FIPS 202.
//
// Most of this package is a wrapper around the crypto/sha3 package in the
// standard library. The only exception is the legacy Keccak hash functions.
package sha3
import (
"crypto/sha3"
"hash"
)
// New224 creates a new SHA3-224 hash.
// Its generic security strength is 224 bits against preimage attacks,
// and 112 bits against collision attacks.
//
// It is a wrapper for the [sha3.New224] function in the standard library.
//
//go:fix inline
func New224() hash.Hash {
return sha3.New224()
}
// New256 creates a new SHA3-256 hash.
// Its generic security strength is 256 bits against preimage attacks,
// and 128 bits against collision attacks.
//
// It is a wrapper for the [sha3.New256] function in the standard library.
//
//go:fix inline
func New256() hash.Hash {
return sha3.New256()
}
// New384 creates a new SHA3-384 hash.
// Its generic security strength is 384 bits against preimage attacks,
// and 192 bits against collision attacks.
//
// It is a wrapper for the [sha3.New384] function in the standard library.
//
//go:fix inline
func New384() hash.Hash {
return sha3.New384()
}
// New512 creates a new SHA3-512 hash.
// Its generic security strength is 512 bits against preimage attacks,
// and 256 bits against collision attacks.
//
// It is a wrapper for the [sha3.New512] function in the standard library.
//
//go:fix inline
func New512() hash.Hash {
return sha3.New512()
}
// Sum224 returns the SHA3-224 digest of the data.
//
// It is a wrapper for the [sha3.Sum224] function in the standard library.
//
//go:fix inline
func Sum224(data []byte) [28]byte {
return sha3.Sum224(data)
}
// Sum256 returns the SHA3-256 digest of the data.
//
// It is a wrapper for the [sha3.Sum256] function in the standard library.
//
//go:fix inline
func Sum256(data []byte) [32]byte {
return sha3.Sum256(data)
}
// Sum384 returns the SHA3-384 digest of the data.
//
// It is a wrapper for the [sha3.Sum384] function in the standard library.
//
//go:fix inline
func Sum384(data []byte) [48]byte {
return sha3.Sum384(data)
}
// Sum512 returns the SHA3-512 digest of the data.
//
// It is a wrapper for the [sha3.Sum512] function in the standard library.
//
//go:fix inline
func Sum512(data []byte) [64]byte {
return sha3.Sum512(data)
}
// 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 sha3
// This implementation is only used for NewLegacyKeccak256 and
// NewLegacyKeccak512, which are not implemented by crypto/sha3.
// All other functions in this package are wrappers around crypto/sha3.
import (
"crypto/subtle"
"encoding/binary"
"errors"
"hash"
"unsafe"
"golang.org/x/sys/cpu"
)
const (
dsbyteKeccak = 0b00000001
// rateK[c] is the rate in bytes for Keccak[c] where c is the capacity in
// bits. Given the sponge size is 1600 bits, the rate is 1600 - c bits.
rateK256 = (1600 - 256) / 8
rateK512 = (1600 - 512) / 8
rateK1024 = (1600 - 1024) / 8
)
// NewLegacyKeccak256 creates a new Keccak-256 hash.
//
// Only use this function if you require compatibility with an existing cryptosystem
// that uses non-standard padding. All other users should use New256 instead.
func NewLegacyKeccak256() hash.Hash {
return &state{rate: rateK512, outputLen: 32, dsbyte: dsbyteKeccak}
}
// NewLegacyKeccak512 creates a new Keccak-512 hash.
//
// Only use this function if you require compatibility with an existing cryptosystem
// that uses non-standard padding. All other users should use New512 instead.
func NewLegacyKeccak512() hash.Hash {
return &state{rate: rateK1024, outputLen: 64, dsbyte: dsbyteKeccak}
}
// spongeDirection indicates the direction bytes are flowing through the sponge.
type spongeDirection int
const (
// spongeAbsorbing indicates that the sponge is absorbing input.
spongeAbsorbing spongeDirection = iota
// spongeSqueezing indicates that the sponge is being squeezed.
spongeSqueezing
)
type state struct {
a [1600 / 8]byte // main state of the hash
// a[n:rate] is the buffer. If absorbing, it's the remaining space to XOR
// into before running the permutation. If squeezing, it's the remaining
// output to produce before running the permutation.
n, rate int
// dsbyte contains the "domain separation" bits and the first bit of
// the padding. Sections 6.1 and 6.2 of [1] separate the outputs of the
// SHA-3 and SHAKE functions by appending bitstrings to the message.
// Using a little-endian bit-ordering convention, these are "01" for SHA-3
// and "1111" for SHAKE, or 00000010b and 00001111b, respectively. Then the
// padding rule from section 5.1 is applied to pad the message to a multiple
// of the rate, which involves adding a "1" bit, zero or more "0" bits, and
// a final "1" bit. We merge the first "1" bit from the padding into dsbyte,
// giving 00000110b (0x06) and 00011111b (0x1f).
// [1] http://csrc.nist.gov/publications/drafts/fips-202/fips_202_draft.pdf
// "Draft FIPS 202: SHA-3 Standard: Permutation-Based Hash and
// Extendable-Output Functions (May 2014)"
dsbyte byte
outputLen int // the default output size in bytes
state spongeDirection // whether the sponge is absorbing or squeezing
}
// BlockSize returns the rate of sponge underlying this hash function.
func (d *state) BlockSize() int { return d.rate }
// Size returns the output size of the hash function in bytes.
func (d *state) Size() int { return d.outputLen }
// Reset clears the internal state by zeroing the sponge state and
// the buffer indexes, and setting Sponge.state to absorbing.
func (d *state) Reset() {
// Zero the permutation's state.
for i := range d.a {
d.a[i] = 0
}
d.state = spongeAbsorbing
d.n = 0
}
func (d *state) clone() *state {
ret := *d
return &ret
}
// permute applies the KeccakF-1600 permutation.
func (d *state) permute() {
var a *[25]uint64
if cpu.IsBigEndian {
a = new([25]uint64)
for i := range a {
a[i] = binary.LittleEndian.Uint64(d.a[i*8:])
}
} else {
a = (*[25]uint64)(unsafe.Pointer(&d.a))
}
keccakF1600(a)
d.n = 0
if cpu.IsBigEndian {
for i := range a {
binary.LittleEndian.PutUint64(d.a[i*8:], a[i])
}
}
}
// pads appends the domain separation bits in dsbyte, applies
// the multi-bitrate 10..1 padding rule, and permutes the state.
func (d *state) padAndPermute() {
// Pad with this instance's domain-separator bits. We know that there's
// at least one byte of space in the sponge because, if it were full,
// permute would have been called to empty it. dsbyte also contains the
// first one bit for the padding. See the comment in the state struct.
d.a[d.n] ^= d.dsbyte
// This adds the final one bit for the padding. Because of the way that
// bits are numbered from the LSB upwards, the final bit is the MSB of
// the last byte.
d.a[d.rate-1] ^= 0x80
// Apply the permutation
d.permute()
d.state = spongeSqueezing
}
// Write absorbs more data into the hash's state. It panics if any
// output has already been read.
func (d *state) Write(p []byte) (n int, err error) {
if d.state != spongeAbsorbing {
panic("sha3: Write after Read")
}
n = len(p)
for len(p) > 0 {
x := subtle.XORBytes(d.a[d.n:d.rate], d.a[d.n:d.rate], p)
d.n += x
p = p[x:]
// If the sponge is full, apply the permutation.
if d.n == d.rate {
d.permute()
}
}
return
}
// Read squeezes an arbitrary number of bytes from the sponge.
func (d *state) Read(out []byte) (n int, err error) {
// If we're still absorbing, pad and apply the permutation.
if d.state == spongeAbsorbing {
d.padAndPermute()
}
n = len(out)
// Now, do the squeezing.
for len(out) > 0 {
// Apply the permutation if we've squeezed the sponge dry.
if d.n == d.rate {
d.permute()
}
x := copy(out, d.a[d.n:d.rate])
d.n += x
out = out[x:]
}
return
}
// Sum applies padding to the hash state and then squeezes out the desired
// number of output bytes. It panics if any output has already been read.
func (d *state) Sum(in []byte) []byte {
if d.state != spongeAbsorbing {
panic("sha3: Sum after Read")
}
// Make a copy of the original hash so that caller can keep writing
// and summing.
dup := d.clone()
hash := make([]byte, dup.outputLen, 64) // explicit cap to allow stack allocation
dup.Read(hash)
return append(in, hash...)
}
const (
magicKeccak = "sha\x0b"
// magic || rate || main state || n || sponge direction
marshaledSize = len(magicKeccak) + 1 + 200 + 1 + 1
)
func (d *state) MarshalBinary() ([]byte, error) {
return d.AppendBinary(make([]byte, 0, marshaledSize))
}
func (d *state) AppendBinary(b []byte) ([]byte, error) {
switch d.dsbyte {
case dsbyteKeccak:
b = append(b, magicKeccak...)
default:
panic("unknown dsbyte")
}
// rate is at most 168, and n is at most rate.
b = append(b, byte(d.rate))
b = append(b, d.a[:]...)
b = append(b, byte(d.n), byte(d.state))
return b, nil
}
func (d *state) UnmarshalBinary(b []byte) error {
if len(b) != marshaledSize {
return errors.New("sha3: invalid hash state")
}
magic := string(b[:len(magicKeccak)])
b = b[len(magicKeccak):]
switch {
case magic == magicKeccak && d.dsbyte == dsbyteKeccak:
default:
return errors.New("sha3: invalid hash state identifier")
}
rate := int(b[0])
b = b[1:]
if rate != d.rate {
return errors.New("sha3: invalid hash state function")
}
copy(d.a[:], b)
b = b[len(d.a):]
n, state := int(b[0]), spongeDirection(b[1])
if n > d.rate {
return errors.New("sha3: invalid hash state")
}
d.n = n
if state != spongeAbsorbing && state != spongeSqueezing {
return errors.New("sha3: invalid hash state")
}
d.state = state
return nil
}
// 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 sha3
// This implementation is only used for NewLegacyKeccak256 and
// NewLegacyKeccak512, which are not implemented by crypto/sha3.
// All other functions in this package are wrappers around crypto/sha3.
import "math/bits"
// rc stores the round constants for use in the ι step.
var rc = [24]uint64{
0x0000000000000001,
0x0000000000008082,
0x800000000000808A,
0x8000000080008000,
0x000000000000808B,
0x0000000080000001,
0x8000000080008081,
0x8000000000008009,
0x000000000000008A,
0x0000000000000088,
0x0000000080008009,
0x000000008000000A,
0x000000008000808B,
0x800000000000008B,
0x8000000000008089,
0x8000000000008003,
0x8000000000008002,
0x8000000000000080,
0x000000000000800A,
0x800000008000000A,
0x8000000080008081,
0x8000000000008080,
0x0000000080000001,
0x8000000080008008,
}
// keccakF1600 applies the Keccak permutation to a 1600b-wide
// state represented as a slice of 25 uint64s.
func keccakF1600(a *[25]uint64) {
// Implementation translated from Keccak-inplace.c
// in the keccak reference code.
var t, bc0, bc1, bc2, bc3, bc4, d0, d1, d2, d3, d4 uint64
for i := 0; i < 24; i += 4 {
// Combines the 5 steps in each round into 2 steps.
// Unrolls 4 rounds per loop and spreads some steps across rounds.
// Round 1
bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
d0 = bc4 ^ (bc1<<1 | bc1>>63)
d1 = bc0 ^ (bc2<<1 | bc2>>63)
d2 = bc1 ^ (bc3<<1 | bc3>>63)
d3 = bc2 ^ (bc4<<1 | bc4>>63)
d4 = bc3 ^ (bc0<<1 | bc0>>63)
bc0 = a[0] ^ d0
t = a[6] ^ d1
bc1 = bits.RotateLeft64(t, 44)
t = a[12] ^ d2
bc2 = bits.RotateLeft64(t, 43)
t = a[18] ^ d3
bc3 = bits.RotateLeft64(t, 21)
t = a[24] ^ d4
bc4 = bits.RotateLeft64(t, 14)
a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i]
a[6] = bc1 ^ (bc3 &^ bc2)
a[12] = bc2 ^ (bc4 &^ bc3)
a[18] = bc3 ^ (bc0 &^ bc4)
a[24] = bc4 ^ (bc1 &^ bc0)
t = a[10] ^ d0
bc2 = bits.RotateLeft64(t, 3)
t = a[16] ^ d1
bc3 = bits.RotateLeft64(t, 45)
t = a[22] ^ d2
bc4 = bits.RotateLeft64(t, 61)
t = a[3] ^ d3
bc0 = bits.RotateLeft64(t, 28)
t = a[9] ^ d4
bc1 = bits.RotateLeft64(t, 20)
a[10] = bc0 ^ (bc2 &^ bc1)
a[16] = bc1 ^ (bc3 &^ bc2)
a[22] = bc2 ^ (bc4 &^ bc3)
a[3] = bc3 ^ (bc0 &^ bc4)
a[9] = bc4 ^ (bc1 &^ bc0)
t = a[20] ^ d0
bc4 = bits.RotateLeft64(t, 18)
t = a[1] ^ d1
bc0 = bits.RotateLeft64(t, 1)
t = a[7] ^ d2
bc1 = bits.RotateLeft64(t, 6)
t = a[13] ^ d3
bc2 = bits.RotateLeft64(t, 25)
t = a[19] ^ d4
bc3 = bits.RotateLeft64(t, 8)
a[20] = bc0 ^ (bc2 &^ bc1)
a[1] = bc1 ^ (bc3 &^ bc2)
a[7] = bc2 ^ (bc4 &^ bc3)
a[13] = bc3 ^ (bc0 &^ bc4)
a[19] = bc4 ^ (bc1 &^ bc0)
t = a[5] ^ d0
bc1 = bits.RotateLeft64(t, 36)
t = a[11] ^ d1
bc2 = bits.RotateLeft64(t, 10)
t = a[17] ^ d2
bc3 = bits.RotateLeft64(t, 15)
t = a[23] ^ d3
bc4 = bits.RotateLeft64(t, 56)
t = a[4] ^ d4
bc0 = bits.RotateLeft64(t, 27)
a[5] = bc0 ^ (bc2 &^ bc1)
a[11] = bc1 ^ (bc3 &^ bc2)
a[17] = bc2 ^ (bc4 &^ bc3)
a[23] = bc3 ^ (bc0 &^ bc4)
a[4] = bc4 ^ (bc1 &^ bc0)
t = a[15] ^ d0
bc3 = bits.RotateLeft64(t, 41)
t = a[21] ^ d1
bc4 = bits.RotateLeft64(t, 2)
t = a[2] ^ d2
bc0 = bits.RotateLeft64(t, 62)
t = a[8] ^ d3
bc1 = bits.RotateLeft64(t, 55)
t = a[14] ^ d4
bc2 = bits.RotateLeft64(t, 39)
a[15] = bc0 ^ (bc2 &^ bc1)
a[21] = bc1 ^ (bc3 &^ bc2)
a[2] = bc2 ^ (bc4 &^ bc3)
a[8] = bc3 ^ (bc0 &^ bc4)
a[14] = bc4 ^ (bc1 &^ bc0)
// Round 2
bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
d0 = bc4 ^ (bc1<<1 | bc1>>63)
d1 = bc0 ^ (bc2<<1 | bc2>>63)
d2 = bc1 ^ (bc3<<1 | bc3>>63)
d3 = bc2 ^ (bc4<<1 | bc4>>63)
d4 = bc3 ^ (bc0<<1 | bc0>>63)
bc0 = a[0] ^ d0
t = a[16] ^ d1
bc1 = bits.RotateLeft64(t, 44)
t = a[7] ^ d2
bc2 = bits.RotateLeft64(t, 43)
t = a[23] ^ d3
bc3 = bits.RotateLeft64(t, 21)
t = a[14] ^ d4
bc4 = bits.RotateLeft64(t, 14)
a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+1]
a[16] = bc1 ^ (bc3 &^ bc2)
a[7] = bc2 ^ (bc4 &^ bc3)
a[23] = bc3 ^ (bc0 &^ bc4)
a[14] = bc4 ^ (bc1 &^ bc0)
t = a[20] ^ d0
bc2 = bits.RotateLeft64(t, 3)
t = a[11] ^ d1
bc3 = bits.RotateLeft64(t, 45)
t = a[2] ^ d2
bc4 = bits.RotateLeft64(t, 61)
t = a[18] ^ d3
bc0 = bits.RotateLeft64(t, 28)
t = a[9] ^ d4
bc1 = bits.RotateLeft64(t, 20)
a[20] = bc0 ^ (bc2 &^ bc1)
a[11] = bc1 ^ (bc3 &^ bc2)
a[2] = bc2 ^ (bc4 &^ bc3)
a[18] = bc3 ^ (bc0 &^ bc4)
a[9] = bc4 ^ (bc1 &^ bc0)
t = a[15] ^ d0
bc4 = bits.RotateLeft64(t, 18)
t = a[6] ^ d1
bc0 = bits.RotateLeft64(t, 1)
t = a[22] ^ d2
bc1 = bits.RotateLeft64(t, 6)
t = a[13] ^ d3
bc2 = bits.RotateLeft64(t, 25)
t = a[4] ^ d4
bc3 = bits.RotateLeft64(t, 8)
a[15] = bc0 ^ (bc2 &^ bc1)
a[6] = bc1 ^ (bc3 &^ bc2)
a[22] = bc2 ^ (bc4 &^ bc3)
a[13] = bc3 ^ (bc0 &^ bc4)
a[4] = bc4 ^ (bc1 &^ bc0)
t = a[10] ^ d0
bc1 = bits.RotateLeft64(t, 36)
t = a[1] ^ d1
bc2 = bits.RotateLeft64(t, 10)
t = a[17] ^ d2
bc3 = bits.RotateLeft64(t, 15)
t = a[8] ^ d3
bc4 = bits.RotateLeft64(t, 56)
t = a[24] ^ d4
bc0 = bits.RotateLeft64(t, 27)
a[10] = bc0 ^ (bc2 &^ bc1)
a[1] = bc1 ^ (bc3 &^ bc2)
a[17] = bc2 ^ (bc4 &^ bc3)
a[8] = bc3 ^ (bc0 &^ bc4)
a[24] = bc4 ^ (bc1 &^ bc0)
t = a[5] ^ d0
bc3 = bits.RotateLeft64(t, 41)
t = a[21] ^ d1
bc4 = bits.RotateLeft64(t, 2)
t = a[12] ^ d2
bc0 = bits.RotateLeft64(t, 62)
t = a[3] ^ d3
bc1 = bits.RotateLeft64(t, 55)
t = a[19] ^ d4
bc2 = bits.RotateLeft64(t, 39)
a[5] = bc0 ^ (bc2 &^ bc1)
a[21] = bc1 ^ (bc3 &^ bc2)
a[12] = bc2 ^ (bc4 &^ bc3)
a[3] = bc3 ^ (bc0 &^ bc4)
a[19] = bc4 ^ (bc1 &^ bc0)
// Round 3
bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
d0 = bc4 ^ (bc1<<1 | bc1>>63)
d1 = bc0 ^ (bc2<<1 | bc2>>63)
d2 = bc1 ^ (bc3<<1 | bc3>>63)
d3 = bc2 ^ (bc4<<1 | bc4>>63)
d4 = bc3 ^ (bc0<<1 | bc0>>63)
bc0 = a[0] ^ d0
t = a[11] ^ d1
bc1 = bits.RotateLeft64(t, 44)
t = a[22] ^ d2
bc2 = bits.RotateLeft64(t, 43)
t = a[8] ^ d3
bc3 = bits.RotateLeft64(t, 21)
t = a[19] ^ d4
bc4 = bits.RotateLeft64(t, 14)
a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+2]
a[11] = bc1 ^ (bc3 &^ bc2)
a[22] = bc2 ^ (bc4 &^ bc3)
a[8] = bc3 ^ (bc0 &^ bc4)
a[19] = bc4 ^ (bc1 &^ bc0)
t = a[15] ^ d0
bc2 = bits.RotateLeft64(t, 3)
t = a[1] ^ d1
bc3 = bits.RotateLeft64(t, 45)
t = a[12] ^ d2
bc4 = bits.RotateLeft64(t, 61)
t = a[23] ^ d3
bc0 = bits.RotateLeft64(t, 28)
t = a[9] ^ d4
bc1 = bits.RotateLeft64(t, 20)
a[15] = bc0 ^ (bc2 &^ bc1)
a[1] = bc1 ^ (bc3 &^ bc2)
a[12] = bc2 ^ (bc4 &^ bc3)
a[23] = bc3 ^ (bc0 &^ bc4)
a[9] = bc4 ^ (bc1 &^ bc0)
t = a[5] ^ d0
bc4 = bits.RotateLeft64(t, 18)
t = a[16] ^ d1
bc0 = bits.RotateLeft64(t, 1)
t = a[2] ^ d2
bc1 = bits.RotateLeft64(t, 6)
t = a[13] ^ d3
bc2 = bits.RotateLeft64(t, 25)
t = a[24] ^ d4
bc3 = bits.RotateLeft64(t, 8)
a[5] = bc0 ^ (bc2 &^ bc1)
a[16] = bc1 ^ (bc3 &^ bc2)
a[2] = bc2 ^ (bc4 &^ bc3)
a[13] = bc3 ^ (bc0 &^ bc4)
a[24] = bc4 ^ (bc1 &^ bc0)
t = a[20] ^ d0
bc1 = bits.RotateLeft64(t, 36)
t = a[6] ^ d1
bc2 = bits.RotateLeft64(t, 10)
t = a[17] ^ d2
bc3 = bits.RotateLeft64(t, 15)
t = a[3] ^ d3
bc4 = bits.RotateLeft64(t, 56)
t = a[14] ^ d4
bc0 = bits.RotateLeft64(t, 27)
a[20] = bc0 ^ (bc2 &^ bc1)
a[6] = bc1 ^ (bc3 &^ bc2)
a[17] = bc2 ^ (bc4 &^ bc3)
a[3] = bc3 ^ (bc0 &^ bc4)
a[14] = bc4 ^ (bc1 &^ bc0)
t = a[10] ^ d0
bc3 = bits.RotateLeft64(t, 41)
t = a[21] ^ d1
bc4 = bits.RotateLeft64(t, 2)
t = a[7] ^ d2
bc0 = bits.RotateLeft64(t, 62)
t = a[18] ^ d3
bc1 = bits.RotateLeft64(t, 55)
t = a[4] ^ d4
bc2 = bits.RotateLeft64(t, 39)
a[10] = bc0 ^ (bc2 &^ bc1)
a[21] = bc1 ^ (bc3 &^ bc2)
a[7] = bc2 ^ (bc4 &^ bc3)
a[18] = bc3 ^ (bc0 &^ bc4)
a[4] = bc4 ^ (bc1 &^ bc0)
// Round 4
bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
d0 = bc4 ^ (bc1<<1 | bc1>>63)
d1 = bc0 ^ (bc2<<1 | bc2>>63)
d2 = bc1 ^ (bc3<<1 | bc3>>63)
d3 = bc2 ^ (bc4<<1 | bc4>>63)
d4 = bc3 ^ (bc0<<1 | bc0>>63)
bc0 = a[0] ^ d0
t = a[1] ^ d1
bc1 = bits.RotateLeft64(t, 44)
t = a[2] ^ d2
bc2 = bits.RotateLeft64(t, 43)
t = a[3] ^ d3
bc3 = bits.RotateLeft64(t, 21)
t = a[4] ^ d4
bc4 = bits.RotateLeft64(t, 14)
a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+3]
a[1] = bc1 ^ (bc3 &^ bc2)
a[2] = bc2 ^ (bc4 &^ bc3)
a[3] = bc3 ^ (bc0 &^ bc4)
a[4] = bc4 ^ (bc1 &^ bc0)
t = a[5] ^ d0
bc2 = bits.RotateLeft64(t, 3)
t = a[6] ^ d1
bc3 = bits.RotateLeft64(t, 45)
t = a[7] ^ d2
bc4 = bits.RotateLeft64(t, 61)
t = a[8] ^ d3
bc0 = bits.RotateLeft64(t, 28)
t = a[9] ^ d4
bc1 = bits.RotateLeft64(t, 20)
a[5] = bc0 ^ (bc2 &^ bc1)
a[6] = bc1 ^ (bc3 &^ bc2)
a[7] = bc2 ^ (bc4 &^ bc3)
a[8] = bc3 ^ (bc0 &^ bc4)
a[9] = bc4 ^ (bc1 &^ bc0)
t = a[10] ^ d0
bc4 = bits.RotateLeft64(t, 18)
t = a[11] ^ d1
bc0 = bits.RotateLeft64(t, 1)
t = a[12] ^ d2
bc1 = bits.RotateLeft64(t, 6)
t = a[13] ^ d3
bc2 = bits.RotateLeft64(t, 25)
t = a[14] ^ d4
bc3 = bits.RotateLeft64(t, 8)
a[10] = bc0 ^ (bc2 &^ bc1)
a[11] = bc1 ^ (bc3 &^ bc2)
a[12] = bc2 ^ (bc4 &^ bc3)
a[13] = bc3 ^ (bc0 &^ bc4)
a[14] = bc4 ^ (bc1 &^ bc0)
t = a[15] ^ d0
bc1 = bits.RotateLeft64(t, 36)
t = a[16] ^ d1
bc2 = bits.RotateLeft64(t, 10)
t = a[17] ^ d2
bc3 = bits.RotateLeft64(t, 15)
t = a[18] ^ d3
bc4 = bits.RotateLeft64(t, 56)
t = a[19] ^ d4
bc0 = bits.RotateLeft64(t, 27)
a[15] = bc0 ^ (bc2 &^ bc1)
a[16] = bc1 ^ (bc3 &^ bc2)
a[17] = bc2 ^ (bc4 &^ bc3)
a[18] = bc3 ^ (bc0 &^ bc4)
a[19] = bc4 ^ (bc1 &^ bc0)
t = a[20] ^ d0
bc3 = bits.RotateLeft64(t, 41)
t = a[21] ^ d1
bc4 = bits.RotateLeft64(t, 2)
t = a[22] ^ d2
bc0 = bits.RotateLeft64(t, 62)
t = a[23] ^ d3
bc1 = bits.RotateLeft64(t, 55)
t = a[24] ^ d4
bc2 = bits.RotateLeft64(t, 39)
a[20] = bc0 ^ (bc2 &^ bc1)
a[21] = bc1 ^ (bc3 &^ bc2)
a[22] = bc2 ^ (bc4 &^ bc3)
a[23] = bc3 ^ (bc0 &^ bc4)
a[24] = bc4 ^ (bc1 &^ bc0)
}
}
// 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 sha3
import (
"crypto/sha3"
"hash"
"io"
)
// ShakeHash defines the interface to hash functions that support
// arbitrary-length output. When used as a plain [hash.Hash], it
// produces minimum-length outputs that provide full-strength generic
// security.
type ShakeHash interface {
hash.Hash
// Read reads more output from the hash; reading affects the hash's
// state. (ShakeHash.Read is thus very different from Hash.Sum.)
// It never returns an error, but subsequent calls to Write or Sum
// will panic.
io.Reader
// Clone returns a copy of the ShakeHash in its current state.
Clone() ShakeHash
}
// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash.
// Its generic security strength is 128 bits against all attacks if at
// least 32 bytes of its output are used.
func NewShake128() ShakeHash {
return &shakeWrapper{sha3.NewSHAKE128(), 32, false, sha3.NewSHAKE128}
}
// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash.
// Its generic security strength is 256 bits against all attacks if
// at least 64 bytes of its output are used.
func NewShake256() ShakeHash {
return &shakeWrapper{sha3.NewSHAKE256(), 64, false, sha3.NewSHAKE256}
}
// NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash,
// a customizable variant of SHAKE128.
// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
// desired. S is a customization byte string used for domain separation - two cSHAKE
// computations on same input with different S yield unrelated outputs.
// When N and S are both empty, this is equivalent to NewShake128.
func NewCShake128(N, S []byte) ShakeHash {
return &shakeWrapper{sha3.NewCSHAKE128(N, S), 32, false, func() *sha3.SHAKE {
return sha3.NewCSHAKE128(N, S)
}}
}
// NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash,
// a customizable variant of SHAKE256.
// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
// desired. S is a customization byte string used for domain separation - two cSHAKE
// computations on same input with different S yield unrelated outputs.
// When N and S are both empty, this is equivalent to NewShake256.
func NewCShake256(N, S []byte) ShakeHash {
return &shakeWrapper{sha3.NewCSHAKE256(N, S), 64, false, func() *sha3.SHAKE {
return sha3.NewCSHAKE256(N, S)
}}
}
// ShakeSum128 writes an arbitrary-length digest of data into hash.
func ShakeSum128(hash, data []byte) {
h := NewShake128()
h.Write(data)
h.Read(hash)
}
// ShakeSum256 writes an arbitrary-length digest of data into hash.
func ShakeSum256(hash, data []byte) {
h := NewShake256()
h.Write(data)
h.Read(hash)
}
// shakeWrapper adds the Size, Sum, and Clone methods to a sha3.SHAKE
// to implement the ShakeHash interface.
type shakeWrapper struct {
*sha3.SHAKE
outputLen int
squeezing bool
newSHAKE func() *sha3.SHAKE
}
func (w *shakeWrapper) Read(p []byte) (n int, err error) {
w.squeezing = true
return w.SHAKE.Read(p)
}
func (w *shakeWrapper) Clone() ShakeHash {
s := w.newSHAKE()
b, err := w.MarshalBinary()
if err != nil {
panic(err) // unreachable
}
if err := s.UnmarshalBinary(b); err != nil {
panic(err) // unreachable
}
return &shakeWrapper{s, w.outputLen, w.squeezing, w.newSHAKE}
}
func (w *shakeWrapper) Size() int { return w.outputLen }
func (w *shakeWrapper) Sum(b []byte) []byte {
if w.squeezing {
panic("sha3: Sum after Read")
}
out := make([]byte, w.outputLen)
// Clone the state so that we don't affect future Write calls.
s := w.Clone()
s.Read(out)
return append(b, out...)
}
// 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.
package ssh
import (
"io"
"sync"
)
// buffer provides a linked list buffer for data exchange
// between producer and consumer. Theoretically the buffer is
// of unlimited capacity as it does no allocation of its own.
type buffer struct {
// protects concurrent access to head, tail and closed
*sync.Cond
head *element // the buffer that will be read first
tail *element // the buffer that will be read last
closed bool
}
// An element represents a single link in a linked list.
type element struct {
buf []byte
next *element
}
// newBuffer returns an empty buffer that is not closed.
func newBuffer() *buffer {
e := new(element)
b := &buffer{
Cond: newCond(),
head: e,
tail: e,
}
return b
}
// write makes buf available for Read to receive.
// buf must not be modified after the call to write.
func (b *buffer) write(buf []byte) {
b.Cond.L.Lock()
e := &element{buf: buf}
b.tail.next = e
b.tail = e
b.Cond.Signal()
b.Cond.L.Unlock()
}
// eof closes the buffer. Reads from the buffer once all
// the data has been consumed will receive io.EOF.
func (b *buffer) eof() {
b.Cond.L.Lock()
b.closed = true
b.Cond.Signal()
b.Cond.L.Unlock()
}
// Read reads data from the internal buffer in buf. Reads will block
// if no data is available, or until the buffer is closed.
func (b *buffer) Read(buf []byte) (n int, err error) {
b.Cond.L.Lock()
defer b.Cond.L.Unlock()
for len(buf) > 0 {
// if there is data in b.head, copy it
if len(b.head.buf) > 0 {
r := copy(buf, b.head.buf)
buf, b.head.buf = buf[r:], b.head.buf[r:]
n += r
continue
}
// if there is a next buffer, make it the head
if len(b.head.buf) == 0 && b.head != b.tail {
b.head = b.head.next
continue
}
// if at least one byte has been copied, return
if n > 0 {
break
}
// if nothing was read, and there is nothing outstanding
// check to see if the buffer is closed.
if b.closed {
err = io.EOF
break
}
// out of buffers, wait for producer
b.Cond.Wait()
}
return
}
// 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.
package ssh
import (
"bytes"
"errors"
"fmt"
"io"
"net"
"sort"
"time"
)
// Certificate algorithm names from [PROTOCOL.certkeys]. These values can appear
// in Certificate.Type, PublicKey.Type, and ClientConfig.HostKeyAlgorithms.
// Unlike key algorithm names, these are not passed to AlgorithmSigner nor
// returned by MultiAlgorithmSigner and don't appear in the Signature.Format
// field.
const (
CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com"
// Deprecated: DSA is only supported at insecure key sizes, and was removed
// from major implementations.
CertAlgoDSAv01 = InsecureCertAlgoDSAv01
// Deprecated: DSA is only supported at insecure key sizes, and was removed
// from major implementations.
InsecureCertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com"
CertAlgoECDSA256v01 = "ecdsa-sha2-nistp256-cert-v01@openssh.com"
CertAlgoECDSA384v01 = "ecdsa-sha2-nistp384-cert-v01@openssh.com"
CertAlgoECDSA521v01 = "ecdsa-sha2-nistp521-cert-v01@openssh.com"
CertAlgoSKECDSA256v01 = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
CertAlgoED25519v01 = "ssh-ed25519-cert-v01@openssh.com"
CertAlgoSKED25519v01 = "sk-ssh-ed25519-cert-v01@openssh.com"
// CertAlgoRSASHA256v01 and CertAlgoRSASHA512v01 can't appear as a
// Certificate.Type (or PublicKey.Type), but only in
// ClientConfig.HostKeyAlgorithms.
CertAlgoRSASHA256v01 = "rsa-sha2-256-cert-v01@openssh.com"
CertAlgoRSASHA512v01 = "rsa-sha2-512-cert-v01@openssh.com"
)
const (
// Deprecated: use CertAlgoRSAv01.
CertSigAlgoRSAv01 = CertAlgoRSAv01
// Deprecated: use CertAlgoRSASHA256v01.
CertSigAlgoRSASHA2256v01 = CertAlgoRSASHA256v01
// Deprecated: use CertAlgoRSASHA512v01.
CertSigAlgoRSASHA2512v01 = CertAlgoRSASHA512v01
)
// Certificate types distinguish between host and user
// certificates. The values can be set in the CertType field of
// Certificate.
const (
UserCert = 1
HostCert = 2
)
// Signature represents a cryptographic signature.
type Signature struct {
Format string
Blob []byte
Rest []byte `ssh:"rest"`
}
// CertTimeInfinity can be used for OpenSSHCertV01.ValidBefore to indicate that
// a certificate does not expire.
const CertTimeInfinity = 1<<64 - 1
// An Certificate represents an OpenSSH certificate as defined in
// [PROTOCOL.certkeys]?rev=1.8. The Certificate type implements the
// PublicKey interface, so it can be unmarshaled using
// ParsePublicKey.
type Certificate struct {
Nonce []byte
Key PublicKey
Serial uint64
CertType uint32
KeyId string
ValidPrincipals []string
ValidAfter uint64
ValidBefore uint64
Permissions
Reserved []byte
SignatureKey PublicKey
Signature *Signature
}
// genericCertData holds the key-independent part of the certificate data.
// Overall, certificates contain an nonce, public key fields and
// key-independent fields.
type genericCertData struct {
Serial uint64
CertType uint32
KeyId string
ValidPrincipals []byte
ValidAfter uint64
ValidBefore uint64
CriticalOptions []byte
Extensions []byte
Reserved []byte
SignatureKey []byte
Signature []byte
}
func marshalStringList(namelist []string) []byte {
var to []byte
for _, name := range namelist {
s := struct{ N string }{name}
to = append(to, Marshal(&s)...)
}
return to
}
type optionsTuple struct {
Key string
Value []byte
}
type optionsTupleValue struct {
Value string
}
// serialize a map of critical options or extensions
// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
// we need two length prefixes for a non-empty string value
func marshalTuples(tups map[string]string) []byte {
keys := make([]string, 0, len(tups))
for key := range tups {
keys = append(keys, key)
}
sort.Strings(keys)
var ret []byte
for _, key := range keys {
s := optionsTuple{Key: key}
if value := tups[key]; len(value) > 0 {
s.Value = Marshal(&optionsTupleValue{value})
}
ret = append(ret, Marshal(&s)...)
}
return ret
}
// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
// we need two length prefixes for a non-empty option value
func parseTuples(in []byte) (map[string]string, error) {
tups := map[string]string{}
var lastKey string
var haveLastKey bool
for len(in) > 0 {
var key, val, extra []byte
var ok bool
if key, in, ok = parseString(in); !ok {
return nil, errShortRead
}
keyStr := string(key)
// according to [PROTOCOL.certkeys], the names must be in
// lexical order.
if haveLastKey && keyStr <= lastKey {
return nil, fmt.Errorf("ssh: certificate options are not in lexical order")
}
lastKey, haveLastKey = keyStr, true
// the next field is a data field, which if non-empty has a string embedded
if val, in, ok = parseString(in); !ok {
return nil, errShortRead
}
if len(val) > 0 {
val, extra, ok = parseString(val)
if !ok {
return nil, errShortRead
}
if len(extra) > 0 {
return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value")
}
tups[keyStr] = string(val)
} else {
tups[keyStr] = ""
}
}
return tups, nil
}
func parseCert(in []byte, privAlgo string) (*Certificate, error) {
nonce, rest, ok := parseString(in)
if !ok {
return nil, errShortRead
}
key, rest, err := parsePubKey(rest, privAlgo)
if err != nil {
return nil, err
}
var g genericCertData
if err := Unmarshal(rest, &g); err != nil {
return nil, err
}
c := &Certificate{
Nonce: nonce,
Key: key,
Serial: g.Serial,
CertType: g.CertType,
KeyId: g.KeyId,
ValidAfter: g.ValidAfter,
ValidBefore: g.ValidBefore,
}
for principals := g.ValidPrincipals; len(principals) > 0; {
principal, rest, ok := parseString(principals)
if !ok {
return nil, errShortRead
}
c.ValidPrincipals = append(c.ValidPrincipals, string(principal))
principals = rest
}
c.CriticalOptions, err = parseTuples(g.CriticalOptions)
if err != nil {
return nil, err
}
c.Extensions, err = parseTuples(g.Extensions)
if err != nil {
return nil, err
}
c.Reserved = g.Reserved
k, err := ParsePublicKey(g.SignatureKey)
if err != nil {
return nil, err
}
// The Type() function is intended to return only certificate key types, but
// we use certKeyAlgoNames anyway for safety, to match [Certificate.Type].
if _, ok := certKeyAlgoNames[k.Type()]; ok {
return nil, fmt.Errorf("ssh: the signature key type %q is invalid for certificates", k.Type())
}
c.SignatureKey = k
c.Signature, rest, ok = parseSignatureBody(g.Signature)
if !ok || len(rest) > 0 {
return nil, errors.New("ssh: signature parse error")
}
return c, nil
}
type openSSHCertSigner struct {
pub *Certificate
signer Signer
}
type algorithmOpenSSHCertSigner struct {
*openSSHCertSigner
algorithmSigner AlgorithmSigner
}
// NewCertSigner returns a Signer that signs with the given Certificate, whose
// private key is held by signer. It returns an error if the public key in cert
// doesn't match the key used by signer.
func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) {
if !bytes.Equal(cert.Key.Marshal(), signer.PublicKey().Marshal()) {
return nil, errors.New("ssh: signer and cert have different public key")
}
switch s := signer.(type) {
case MultiAlgorithmSigner:
return &multiAlgorithmSigner{
AlgorithmSigner: &algorithmOpenSSHCertSigner{
&openSSHCertSigner{cert, signer}, s},
supportedAlgorithms: s.Algorithms(),
}, nil
case AlgorithmSigner:
return &algorithmOpenSSHCertSigner{
&openSSHCertSigner{cert, signer}, s}, nil
default:
return &openSSHCertSigner{cert, signer}, nil
}
}
func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
return s.signer.Sign(rand, data)
}
func (s *openSSHCertSigner) PublicKey() PublicKey {
return s.pub
}
func (s *algorithmOpenSSHCertSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
return s.algorithmSigner.SignWithAlgorithm(rand, data, algorithm)
}
const sourceAddressCriticalOption = "source-address"
// CertChecker does the work of verifying a certificate. Its methods
// can be plugged into ClientConfig.HostKeyCallback and
// ServerConfig.PublicKeyCallback. For the CertChecker to work,
// minimally, the IsAuthority callback should be set.
type CertChecker struct {
// SupportedCriticalOptions lists the CriticalOptions that the
// server application layer understands. These are only used
// for user certificates.
SupportedCriticalOptions []string
// IsUserAuthority should return true if the key is recognized as an
// authority for user certificate. This must be set if this CertChecker
// will be checking user certificates.
IsUserAuthority func(auth PublicKey) bool
// IsHostAuthority should report whether the key is recognized as
// an authority for this host. This must be set if this CertChecker
// will be checking host certificates.
IsHostAuthority func(auth PublicKey, address string) bool
// Clock is used for verifying time stamps. If nil, time.Now
// is used.
Clock func() time.Time
// UserKeyFallback is called when CertChecker.Authenticate encounters a
// public key that is not a certificate. It must implement validation
// of user keys or else, if nil, all such keys are rejected.
UserKeyFallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
// HostKeyFallback is called when CertChecker.CheckHostKey encounters a
// public key that is not a certificate. It must implement host key
// validation or else, if nil, all such keys are rejected.
HostKeyFallback HostKeyCallback
// IsRevoked is called for each certificate so that revocation checking
// can be implemented. It should return true if the given certificate
// is revoked and false otherwise. If nil, no certificates are
// considered to have been revoked.
IsRevoked func(cert *Certificate) bool
}
// CheckHostKey checks a host key certificate. This method can be
// plugged into ClientConfig.HostKeyCallback.
func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error {
cert, ok := key.(*Certificate)
if !ok {
if c.HostKeyFallback != nil {
return c.HostKeyFallback(addr, remote, key)
}
return errors.New("ssh: non-certificate host key")
}
if cert.CertType != HostCert {
return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType)
}
if !c.IsHostAuthority(cert.SignatureKey, addr) {
return fmt.Errorf("ssh: no authorities for hostname: %v", addr)
}
hostname, _, err := net.SplitHostPort(addr)
if err != nil {
return err
}
// Pass hostname only as principal for host certificates (consistent with OpenSSH)
return c.CheckCert(hostname, cert)
}
// Authenticate checks a user certificate. Authenticate can be used as
// a value for ServerConfig.PublicKeyCallback.
func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) {
cert, ok := pubKey.(*Certificate)
if !ok {
if c.UserKeyFallback != nil {
return c.UserKeyFallback(conn, pubKey)
}
return nil, errors.New("ssh: normal key pairs not accepted")
}
if cert.CertType != UserCert {
return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType)
}
if !c.IsUserAuthority(cert.SignatureKey) {
return nil, fmt.Errorf("ssh: certificate signed by unrecognized authority")
}
if err := c.CheckCert(conn.User(), cert); err != nil {
return nil, err
}
return &cert.Permissions, nil
}
// CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and
// the signature of the certificate.
func (c *CertChecker) CheckCert(principal string, cert *Certificate) error {
if c.IsRevoked != nil && c.IsRevoked(cert) {
return fmt.Errorf("ssh: certificate serial %d revoked", cert.Serial)
}
for opt := range cert.CriticalOptions {
// sourceAddressCriticalOption will be enforced by
// serverAuthenticate
if opt == sourceAddressCriticalOption {
continue
}
found := false
for _, supp := range c.SupportedCriticalOptions {
if supp == opt {
found = true
break
}
}
if !found {
return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt)
}
}
if len(cert.ValidPrincipals) > 0 {
// By default, certs are valid for all users/hosts.
found := false
for _, p := range cert.ValidPrincipals {
if p == principal {
found = true
break
}
}
if !found {
return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals)
}
}
clock := c.Clock
if clock == nil {
clock = time.Now
}
unixNow := clock().Unix()
if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) {
return fmt.Errorf("ssh: cert is not yet valid")
}
if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) {
return fmt.Errorf("ssh: cert has expired")
}
if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil {
return fmt.Errorf("ssh: certificate signature does not verify")
}
return nil
}
// SignCert signs the certificate with an authority, setting the Nonce,
// SignatureKey, and Signature fields. If the authority implements the
// MultiAlgorithmSigner interface the first algorithm in the list is used. This
// is useful if you want to sign with a specific algorithm. As specified in
// [SSH-CERTS], Section 2.1.1, authority can't be a [Certificate].
func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
c.Nonce = make([]byte, 32)
if _, err := io.ReadFull(rand, c.Nonce); err != nil {
return err
}
// The Type() function is intended to return only certificate key types, but
// we use certKeyAlgoNames anyway for safety, to match [Certificate.Type].
if _, ok := certKeyAlgoNames[authority.PublicKey().Type()]; ok {
return fmt.Errorf("ssh: certificates cannot be used as authority (public key type %q)",
authority.PublicKey().Type())
}
c.SignatureKey = authority.PublicKey()
if v, ok := authority.(MultiAlgorithmSigner); ok {
if len(v.Algorithms()) == 0 {
return errors.New("the provided authority has no signature algorithm")
}
// Use the first algorithm in the list.
sig, err := v.SignWithAlgorithm(rand, c.bytesForSigning(), v.Algorithms()[0])
if err != nil {
return err
}
c.Signature = sig
return nil
} else if v, ok := authority.(AlgorithmSigner); ok && v.PublicKey().Type() == KeyAlgoRSA {
// Default to KeyAlgoRSASHA512 for ssh-rsa signers.
// TODO: consider using KeyAlgoRSASHA256 as default.
sig, err := v.SignWithAlgorithm(rand, c.bytesForSigning(), KeyAlgoRSASHA512)
if err != nil {
return err
}
c.Signature = sig
return nil
}
sig, err := authority.Sign(rand, c.bytesForSigning())
if err != nil {
return err
}
c.Signature = sig
return nil
}
// certKeyAlgoNames is a mapping from known certificate algorithm names to the
// corresponding public key signature algorithm.
//
// This map must be kept in sync with the one in agent/client.go.
var certKeyAlgoNames = map[string]string{
CertAlgoRSAv01: KeyAlgoRSA,
CertAlgoRSASHA256v01: KeyAlgoRSASHA256,
CertAlgoRSASHA512v01: KeyAlgoRSASHA512,
InsecureCertAlgoDSAv01: InsecureKeyAlgoDSA,
CertAlgoECDSA256v01: KeyAlgoECDSA256,
CertAlgoECDSA384v01: KeyAlgoECDSA384,
CertAlgoECDSA521v01: KeyAlgoECDSA521,
CertAlgoSKECDSA256v01: KeyAlgoSKECDSA256,
CertAlgoED25519v01: KeyAlgoED25519,
CertAlgoSKED25519v01: KeyAlgoSKED25519,
}
// underlyingAlgo returns the signature algorithm associated with algo (which is
// an advertised or negotiated public key or host key algorithm). These are
// usually the same, except for certificate algorithms.
func underlyingAlgo(algo string) string {
if a, ok := certKeyAlgoNames[algo]; ok {
return a
}
return algo
}
// certificateAlgo returns the certificate algorithms that uses the provided
// underlying signature algorithm.
func certificateAlgo(algo string) (certAlgo string, ok bool) {
for certName, algoName := range certKeyAlgoNames {
if algoName == algo {
return certName, true
}
}
return "", false
}
func (cert *Certificate) bytesForSigning() []byte {
c2 := *cert
c2.Signature = nil
out := c2.Marshal()
// Drop trailing signature length.
return out[:len(out)-4]
}
// Marshal serializes c into OpenSSH's wire format. It is part of the
// PublicKey interface.
func (c *Certificate) Marshal() []byte {
generic := genericCertData{
Serial: c.Serial,
CertType: c.CertType,
KeyId: c.KeyId,
ValidPrincipals: marshalStringList(c.ValidPrincipals),
ValidAfter: uint64(c.ValidAfter),
ValidBefore: uint64(c.ValidBefore),
CriticalOptions: marshalTuples(c.CriticalOptions),
Extensions: marshalTuples(c.Extensions),
Reserved: c.Reserved,
SignatureKey: c.SignatureKey.Marshal(),
}
if c.Signature != nil {
generic.Signature = Marshal(c.Signature)
}
genericBytes := Marshal(&generic)
keyBytes := c.Key.Marshal()
_, keyBytes, _ = parseString(keyBytes)
prefix := Marshal(&struct {
Name string
Nonce []byte
Key []byte `ssh:"rest"`
}{c.Type(), c.Nonce, keyBytes})
result := make([]byte, 0, len(prefix)+len(genericBytes))
result = append(result, prefix...)
result = append(result, genericBytes...)
return result
}
// Type returns the certificate algorithm name. It is part of the PublicKey interface.
func (c *Certificate) Type() string {
certName, ok := certificateAlgo(c.Key.Type())
if !ok {
panic("unknown certificate type for key type " + c.Key.Type())
}
return certName
}
// Verify verifies a signature against the certificate's public
// key. It is part of the PublicKey interface.
func (c *Certificate) Verify(data []byte, sig *Signature) error {
return c.Key.Verify(data, sig)
}
func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) {
format, in, ok := parseString(in)
if !ok {
return
}
out = &Signature{
Format: string(format),
}
if out.Blob, in, ok = parseString(in); !ok {
return
}
switch out.Format {
case KeyAlgoSKECDSA256, CertAlgoSKECDSA256v01, KeyAlgoSKED25519, CertAlgoSKED25519v01:
out.Rest = in
return out, nil, ok
}
return out, in, ok
}
func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) {
sigBytes, rest, ok := parseString(in)
if !ok {
return
}
out, trailing, ok := parseSignatureBody(sigBytes)
if !ok || len(trailing) > 0 {
return nil, nil, false
}
return
}
// Copyright 2011 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 ssh
import (
"encoding/binary"
"errors"
"fmt"
"io"
"log"
"sync"
)
const (
minPacketLength = 9
// channelMaxPacket contains the maximum number of bytes that will be
// sent in a single packet. As per RFC 4253, section 6.1, 32k is also
// the minimum.
channelMaxPacket = 1 << 15
// We follow OpenSSH here.
channelWindowSize = 64 * channelMaxPacket
)
// NewChannel represents an incoming request to a channel. It must either be
// accepted for use by calling Accept, or rejected by calling Reject.
type NewChannel interface {
// Accept accepts the channel creation request. It returns the Channel
// and a Go channel containing SSH requests. The Go channel must be
// serviced otherwise the Channel will hang.
Accept() (Channel, <-chan *Request, error)
// Reject rejects the channel creation request. After calling
// this, no other methods on the Channel may be called.
Reject(reason RejectionReason, message string) error
// ChannelType returns the type of the channel, as supplied by the
// client.
ChannelType() string
// ExtraData returns the arbitrary payload for this channel, as supplied
// by the client. This data is specific to the channel type.
ExtraData() []byte
}
// A Channel is an ordered, reliable, flow-controlled, duplex stream
// that is multiplexed over an SSH connection.
type Channel interface {
// Read reads up to len(data) bytes from the channel.
Read(data []byte) (int, error)
// Write writes len(data) bytes to the channel.
Write(data []byte) (int, error)
// Close signals end of channel use. No data may be sent after this
// call.
Close() error
// CloseWrite signals the end of sending in-band
// data. Requests may still be sent, and the other side may
// still send data
CloseWrite() error
// SendRequest sends a channel request. If wantReply is true,
// it will wait for a reply and return the result as a
// boolean, otherwise the return value will be false. Channel
// requests are out-of-band messages so they may be sent even
// if the data stream is closed or blocked by flow control.
// If the channel is closed before a reply is returned, io.EOF
// is returned.
SendRequest(name string, wantReply bool, payload []byte) (bool, error)
// Stderr returns an io.ReadWriter that writes to this channel
// with the extended data type set to stderr. Stderr may
// safely be read and written from a different goroutine than
// Read and Write respectively.
Stderr() io.ReadWriter
}
// Request is a request sent outside of the normal stream of
// data. Requests can either be specific to an SSH channel, or they
// can be global.
type Request struct {
Type string
WantReply bool
Payload []byte
ch *channel
mux *mux
}
// Reply sends a response to a request. It must be called for all requests
// where WantReply is true and is a no-op otherwise. The payload argument is
// ignored for replies to channel-specific requests.
func (r *Request) Reply(ok bool, payload []byte) error {
if !r.WantReply {
return nil
}
if r.ch == nil {
return r.mux.ackRequest(ok, payload)
}
return r.ch.ackRequest(ok)
}
// RejectionReason is an enumeration used when rejecting channel creation
// requests. See RFC 4254, section 5.1.
type RejectionReason uint32
const (
Prohibited RejectionReason = iota + 1
ConnectionFailed
UnknownChannelType
ResourceShortage
)
// String converts the rejection reason to human readable form.
func (r RejectionReason) String() string {
switch r {
case Prohibited:
return "administratively prohibited"
case ConnectionFailed:
return "connect failed"
case UnknownChannelType:
return "unknown channel type"
case ResourceShortage:
return "resource shortage"
}
return fmt.Sprintf("unknown reason %d", int(r))
}
func min(a uint32, b int) uint32 {
if a < uint32(b) {
return a
}
return uint32(b)
}
type channelDirection uint8
const (
channelInbound channelDirection = iota
channelOutbound
)
// channel is an implementation of the Channel interface that works
// with the mux class.
type channel struct {
// R/O after creation
chanType string
extraData []byte
localId, remoteId uint32
// maxIncomingPayload and maxRemotePayload are the maximum
// payload sizes of normal and extended data packets for
// receiving and sending, respectively. The wire packet will
// be 9 or 13 bytes larger (excluding encryption overhead).
maxIncomingPayload uint32
maxRemotePayload uint32
mux *mux
// decided is set to true if an accept or reject message has been sent
// (for outbound channels) or received (for inbound channels).
decided bool
// direction contains either channelOutbound, for channels created
// locally, or channelInbound, for channels created by the peer.
direction channelDirection
// Pending internal channel messages.
msg chan interface{}
// Since requests have no ID, there can be only one request
// with WantReply=true outstanding. This lock is held by a
// goroutine that has such an outgoing request pending.
sentRequestMu sync.Mutex
incomingRequests chan *Request
sentEOF bool
// thread-safe data
remoteWin window
pending *buffer
extPending *buffer
// windowMu protects myWindow, the flow-control window, and myConsumed,
// the number of bytes consumed since we last increased myWindow
windowMu sync.Mutex
myWindow uint32
myConsumed uint32
// writeMu serializes calls to mux.conn.writePacket() and
// protects sentClose and packetPool. This mutex must be
// different from windowMu, as writePacket can block if there
// is a key exchange pending.
writeMu sync.Mutex
sentClose bool
// packetPool has a buffer for each extended channel ID to
// save allocations during writes.
packetPool map[uint32][]byte
}
// writePacket sends a packet. If the packet is a channel close, it updates
// sentClose. This method takes the lock c.writeMu.
func (ch *channel) writePacket(packet []byte) error {
ch.writeMu.Lock()
if ch.sentClose {
ch.writeMu.Unlock()
return io.EOF
}
ch.sentClose = (packet[0] == msgChannelClose)
err := ch.mux.conn.writePacket(packet)
ch.writeMu.Unlock()
return err
}
func (ch *channel) sendMessage(msg interface{}) error {
if debugMux {
log.Printf("send(%d): %#v", ch.mux.chanList.offset, msg)
}
p := Marshal(msg)
binary.BigEndian.PutUint32(p[1:], ch.remoteId)
return ch.writePacket(p)
}
// WriteExtended writes data to a specific extended stream. These streams are
// used, for example, for stderr.
func (ch *channel) WriteExtended(data []byte, extendedCode uint32) (n int, err error) {
if ch.sentEOF {
return 0, io.EOF
}
// 1 byte message type, 4 bytes remoteId, 4 bytes data length
opCode := byte(msgChannelData)
headerLength := uint32(9)
if extendedCode > 0 {
headerLength += 4
opCode = msgChannelExtendedData
}
ch.writeMu.Lock()
packet := ch.packetPool[extendedCode]
// We don't remove the buffer from packetPool, so
// WriteExtended calls from different goroutines will be
// flagged as errors by the race detector.
ch.writeMu.Unlock()
for len(data) > 0 {
space := min(ch.maxRemotePayload, len(data))
if space, err = ch.remoteWin.reserve(space); err != nil {
return n, err
}
if want := headerLength + space; uint32(cap(packet)) < want {
packet = make([]byte, want)
} else {
packet = packet[:want]
}
todo := data[:space]
packet[0] = opCode
binary.BigEndian.PutUint32(packet[1:], ch.remoteId)
if extendedCode > 0 {
binary.BigEndian.PutUint32(packet[5:], uint32(extendedCode))
}
binary.BigEndian.PutUint32(packet[headerLength-4:], uint32(len(todo)))
copy(packet[headerLength:], todo)
if err = ch.writePacket(packet); err != nil {
return n, err
}
n += len(todo)
data = data[len(todo):]
}
ch.writeMu.Lock()
ch.packetPool[extendedCode] = packet
ch.writeMu.Unlock()
return n, err
}
func (ch *channel) handleData(packet []byte) error {
headerLen := 9
isExtendedData := packet[0] == msgChannelExtendedData
if isExtendedData {
headerLen = 13
}
if len(packet) < headerLen {
// malformed data packet
return parseError(packet[0])
}
var extended uint32
if isExtendedData {
extended = binary.BigEndian.Uint32(packet[5:])
}
length := binary.BigEndian.Uint32(packet[headerLen-4 : headerLen])
if length == 0 {
return nil
}
if length > ch.maxIncomingPayload {
// TODO(hanwen): should send Disconnect?
return errors.New("ssh: incoming packet exceeds maximum payload size")
}
data := packet[headerLen:]
if length != uint32(len(data)) {
return errors.New("ssh: wrong packet length")
}
ch.windowMu.Lock()
if ch.myWindow < length {
ch.windowMu.Unlock()
// TODO(hanwen): should send Disconnect with reason?
return errors.New("ssh: remote side wrote too much")
}
ch.myWindow -= length
ch.windowMu.Unlock()
if extended == 1 {
ch.extPending.write(data)
} else if extended > 0 {
// discard other extended data.
} else {
ch.pending.write(data)
}
return nil
}
func (c *channel) adjustWindow(adj uint32) error {
c.windowMu.Lock()
// Since myConsumed and myWindow are managed on our side, and can never
// exceed the initial window setting, we don't worry about overflow.
c.myConsumed += adj
var sendAdj uint32
if (channelWindowSize-c.myWindow > 3*c.maxIncomingPayload) ||
(c.myWindow < channelWindowSize/2) {
sendAdj = c.myConsumed
c.myConsumed = 0
c.myWindow += sendAdj
}
c.windowMu.Unlock()
if sendAdj == 0 {
return nil
}
return c.sendMessage(windowAdjustMsg{
AdditionalBytes: sendAdj,
})
}
func (c *channel) ReadExtended(data []byte, extended uint32) (n int, err error) {
switch extended {
case 1:
n, err = c.extPending.Read(data)
case 0:
n, err = c.pending.Read(data)
default:
return 0, fmt.Errorf("ssh: extended code %d unimplemented", extended)
}
if n > 0 {
err = c.adjustWindow(uint32(n))
// sendWindowAdjust can return io.EOF if the remote
// peer has closed the connection, however we want to
// defer forwarding io.EOF to the caller of Read until
// the buffer has been drained.
if n > 0 && err == io.EOF {
err = nil
}
}
return n, err
}
func (c *channel) close() {
c.pending.eof()
c.extPending.eof()
close(c.msg)
close(c.incomingRequests)
c.writeMu.Lock()
// This is not necessary for a normal channel teardown, but if
// there was another error, it is.
c.sentClose = true
c.writeMu.Unlock()
// Unblock writers.
c.remoteWin.close()
}
// responseMessageReceived is called when a success or failure message is
// received on a channel to check that such a message is reasonable for the
// given channel.
func (ch *channel) responseMessageReceived() error {
if ch.direction == channelInbound {
return errors.New("ssh: channel response message received on inbound channel")
}
if ch.decided {
return errors.New("ssh: duplicate response received for channel")
}
ch.decided = true
return nil
}
func (ch *channel) handlePacket(packet []byte) error {
switch packet[0] {
case msgChannelData, msgChannelExtendedData:
return ch.handleData(packet)
case msgChannelClose:
ch.sendMessage(channelCloseMsg{PeersID: ch.remoteId})
ch.mux.chanList.remove(ch.localId)
ch.close()
return nil
case msgChannelEOF:
// RFC 4254 is mute on how EOF affects dataExt messages but
// it is logical to signal EOF at the same time.
ch.extPending.eof()
ch.pending.eof()
return nil
}
decoded, err := decode(packet)
if err != nil {
return err
}
switch msg := decoded.(type) {
case *channelOpenFailureMsg:
if err := ch.responseMessageReceived(); err != nil {
return err
}
ch.mux.chanList.remove(msg.PeersID)
ch.msg <- msg
case *channelOpenConfirmMsg:
if err := ch.responseMessageReceived(); err != nil {
return err
}
if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 {
return fmt.Errorf("ssh: invalid MaxPacketSize %d from peer", msg.MaxPacketSize)
}
ch.remoteId = msg.MyID
ch.maxRemotePayload = msg.MaxPacketSize
ch.remoteWin.add(msg.MyWindow)
ch.msg <- msg
case *windowAdjustMsg:
if !ch.remoteWin.add(msg.AdditionalBytes) {
return fmt.Errorf("ssh: invalid window update for %d bytes", msg.AdditionalBytes)
}
case *channelRequestMsg:
req := Request{
Type: msg.Request,
WantReply: msg.WantReply,
Payload: msg.RequestSpecificData,
ch: ch,
}
ch.incomingRequests <- &req
default:
ch.msg <- msg
}
return nil
}
func (m *mux) newChannel(chanType string, direction channelDirection, extraData []byte) *channel {
ch := &channel{
remoteWin: window{Cond: newCond()},
myWindow: channelWindowSize,
pending: newBuffer(),
extPending: newBuffer(),
direction: direction,
incomingRequests: make(chan *Request, chanSize),
msg: make(chan interface{}, chanSize),
chanType: chanType,
extraData: extraData,
mux: m,
packetPool: make(map[uint32][]byte),
}
ch.localId = m.chanList.add(ch)
return ch
}
var errUndecided = errors.New("ssh: must Accept or Reject channel")
var errDecidedAlready = errors.New("ssh: can call Accept or Reject only once")
type extChannel struct {
code uint32
ch *channel
}
func (e *extChannel) Write(data []byte) (n int, err error) {
return e.ch.WriteExtended(data, e.code)
}
func (e *extChannel) Read(data []byte) (n int, err error) {
return e.ch.ReadExtended(data, e.code)
}
func (ch *channel) Accept() (Channel, <-chan *Request, error) {
if ch.decided {
return nil, nil, errDecidedAlready
}
ch.maxIncomingPayload = channelMaxPacket
confirm := channelOpenConfirmMsg{
PeersID: ch.remoteId,
MyID: ch.localId,
MyWindow: ch.myWindow,
MaxPacketSize: ch.maxIncomingPayload,
}
ch.decided = true
if err := ch.sendMessage(confirm); err != nil {
return nil, nil, err
}
return ch, ch.incomingRequests, nil
}
func (ch *channel) Reject(reason RejectionReason, message string) error {
if ch.decided {
return errDecidedAlready
}
reject := channelOpenFailureMsg{
PeersID: ch.remoteId,
Reason: reason,
Message: message,
Language: "en",
}
ch.decided = true
return ch.sendMessage(reject)
}
func (ch *channel) Read(data []byte) (int, error) {
if !ch.decided {
return 0, errUndecided
}
return ch.ReadExtended(data, 0)
}
func (ch *channel) Write(data []byte) (int, error) {
if !ch.decided {
return 0, errUndecided
}
return ch.WriteExtended(data, 0)
}
func (ch *channel) CloseWrite() error {
if !ch.decided {
return errUndecided
}
ch.sentEOF = true
return ch.sendMessage(channelEOFMsg{
PeersID: ch.remoteId})
}
func (ch *channel) Close() error {
if !ch.decided {
return errUndecided
}
return ch.sendMessage(channelCloseMsg{
PeersID: ch.remoteId})
}
// Extended returns an io.ReadWriter that sends and receives data on the given,
// SSH extended stream. Such streams are used, for example, for stderr.
func (ch *channel) Extended(code uint32) io.ReadWriter {
if !ch.decided {
return nil
}
return &extChannel{code, ch}
}
func (ch *channel) Stderr() io.ReadWriter {
return ch.Extended(1)
}
func (ch *channel) SendRequest(name string, wantReply bool, payload []byte) (bool, error) {
if !ch.decided {
return false, errUndecided
}
if wantReply {
ch.sentRequestMu.Lock()
defer ch.sentRequestMu.Unlock()
}
msg := channelRequestMsg{
PeersID: ch.remoteId,
Request: name,
WantReply: wantReply,
RequestSpecificData: payload,
}
if err := ch.sendMessage(msg); err != nil {
return false, err
}
if wantReply {
m, ok := (<-ch.msg)
if !ok {
return false, io.EOF
}
switch m.(type) {
case *channelRequestFailureMsg:
return false, nil
case *channelRequestSuccessMsg:
return true, nil
default:
return false, fmt.Errorf("ssh: unexpected response to channel request: %#v", m)
}
}
return false, nil
}
// ackRequest either sends an ack or nack to the channel request.
func (ch *channel) ackRequest(ok bool) error {
if !ch.decided {
return errUndecided
}
var msg interface{}
if !ok {
msg = channelRequestFailureMsg{
PeersID: ch.remoteId,
}
} else {
msg = channelRequestSuccessMsg{
PeersID: ch.remoteId,
}
}
return ch.sendMessage(msg)
}
func (ch *channel) ChannelType() string {
return ch.chanType
}
func (ch *channel) ExtraData() []byte {
return ch.extraData
}
// Copyright 2011 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 ssh
import (
"crypto/aes"
"crypto/cipher"
"crypto/des"
"crypto/fips140"
"crypto/rc4"
"crypto/subtle"
"encoding/binary"
"errors"
"fmt"
"hash"
"io"
"slices"
"golang.org/x/crypto/chacha20"
"golang.org/x/crypto/internal/poly1305"
)
const (
packetSizeMultiple = 16 // TODO(huin) this should be determined by the cipher.
// RFC 4253 section 6.1 defines a minimum packet size of 32768 that implementations
// MUST be able to process (plus a few more kilobytes for padding and mac). The RFC
// indicates implementations SHOULD be able to handle larger packet sizes, but then
// waffles on about reasonable limits.
//
// OpenSSH caps their maxPacket at 256kB so we choose to do
// the same. maxPacket is also used to ensure that uint32
// length fields do not overflow, so it should remain well
// below 4G.
maxPacket = 256 * 1024
)
// noneCipher implements cipher.Stream and provides no encryption. It is used
// by the transport before the first key-exchange.
type noneCipher struct{}
func (c noneCipher) XORKeyStream(dst, src []byte) {
copy(dst, src)
}
func newAESCTR(key, iv []byte) (cipher.Stream, error) {
c, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
return cipher.NewCTR(c, iv), nil
}
func newRC4(key, iv []byte) (cipher.Stream, error) {
return rc4.NewCipher(key)
}
type cipherMode struct {
keySize int
ivSize int
create func(key, iv []byte, macKey []byte, algs DirectionAlgorithms) (packetCipher, error)
}
func streamCipherMode(skip int, createFunc func(key, iv []byte) (cipher.Stream, error)) func(key, iv []byte, macKey []byte, algs DirectionAlgorithms) (packetCipher, error) {
return func(key, iv, macKey []byte, algs DirectionAlgorithms) (packetCipher, error) {
stream, err := createFunc(key, iv)
if err != nil {
return nil, err
}
var streamDump []byte
if skip > 0 {
streamDump = make([]byte, 512)
}
for remainingToDump := skip; remainingToDump > 0; {
dumpThisTime := remainingToDump
if dumpThisTime > len(streamDump) {
dumpThisTime = len(streamDump)
}
stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime])
remainingToDump -= dumpThisTime
}
mac := macModes[algs.MAC].new(macKey)
return &streamPacketCipher{
mac: mac,
etm: macModes[algs.MAC].etm,
macResult: make([]byte, mac.Size()),
cipher: stream,
}, nil
}
}
// cipherModes documents properties of supported ciphers. Ciphers not included
// are not supported and will not be negotiated, even if explicitly configured.
// When FIPS mode is enabled, only FIPS-approved algorithms are included.
var cipherModes = map[string]*cipherMode{}
func init() {
cipherModes[CipherAES128CTR] = &cipherMode{16, aes.BlockSize, streamCipherMode(0, newAESCTR)}
cipherModes[CipherAES192CTR] = &cipherMode{24, aes.BlockSize, streamCipherMode(0, newAESCTR)}
cipherModes[CipherAES256CTR] = &cipherMode{32, aes.BlockSize, streamCipherMode(0, newAESCTR)}
// Use of GCM with arbitrary IVs is not allowed in FIPS 140-only mode,
// we'll wire it up to NewGCMForSSH in Go 1.26.
//
// For now it means we'll work with fips140=on but not fips140=only.
cipherModes[CipherAES128GCM] = &cipherMode{16, 12, newGCMCipher}
cipherModes[CipherAES256GCM] = &cipherMode{32, 12, newGCMCipher}
if fips140.Enabled() {
defaultCiphers = slices.DeleteFunc(defaultCiphers, func(algo string) bool {
_, ok := cipherModes[algo]
return !ok
})
return
}
cipherModes[CipherChaCha20Poly1305] = &cipherMode{64, 0, newChaCha20Cipher}
// Insecure ciphers not included in the default configuration.
cipherModes[InsecureCipherRC4128] = &cipherMode{16, 0, streamCipherMode(1536, newRC4)}
cipherModes[InsecureCipherRC4256] = &cipherMode{32, 0, streamCipherMode(1536, newRC4)}
cipherModes[InsecureCipherRC4] = &cipherMode{16, 0, streamCipherMode(0, newRC4)}
// CBC mode is insecure and so is not included in the default config.
// (See https://www.ieee-security.org/TC/SP2013/papers/4977a526.pdf). If absolutely
// needed, it's possible to specify a custom Config to enable it.
// You should expect that an active attacker can recover plaintext if
// you do.
cipherModes[InsecureCipherAES128CBC] = &cipherMode{16, aes.BlockSize, newAESCBCCipher}
cipherModes[InsecureCipherTripleDESCBC] = &cipherMode{24, des.BlockSize, newTripleDESCBCCipher}
}
// prefixLen is the length of the packet prefix that contains the packet length
// and number of padding bytes.
const prefixLen = 5
// streamPacketCipher is a packetCipher using a stream cipher.
type streamPacketCipher struct {
mac hash.Hash
cipher cipher.Stream
etm bool
// The following members are to avoid per-packet allocations.
prefix [prefixLen]byte
seqNumBytes [4]byte
padding [2 * packetSizeMultiple]byte
packetData []byte
macResult []byte
}
// readCipherPacket reads and decrypt a single packet from the reader argument.
func (s *streamPacketCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
if _, err := io.ReadFull(r, s.prefix[:]); err != nil {
return nil, err
}
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])
var macSize uint32
if s.mac != nil {
s.mac.Reset()
binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
s.mac.Write(s.seqNumBytes[:])
if s.etm {
s.mac.Write(s.prefix[:4])
s.mac.Write(encryptedPaddingLength[:])
} else {
s.mac.Write(s.prefix[:])
}
macSize = uint32(s.mac.Size())
}
if length <= paddingLength+1 {
return nil, errors.New("ssh: invalid packet length, packet too small")
}
if length > maxPacket {
return nil, errors.New("ssh: invalid packet length, packet too large")
}
// the maxPacket check above ensures that length-1+macSize
// does not overflow.
if uint32(cap(s.packetData)) < length-1+macSize {
s.packetData = make([]byte, length-1+macSize)
} else {
s.packetData = s.packetData[:length-1+macSize]
}
if _, err := io.ReadFull(r, s.packetData); err != nil {
return nil, 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 {
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")
}
}
return s.packetData[:length-paddingLength-1], nil
}
// writeCipherPacket encrypts and sends a packet of data to the writer argument
func (s *streamPacketCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
if len(packet) > maxPacket {
return errors.New("ssh: packet too large")
}
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
}
length := len(packet) + 1 + paddingLength
binary.BigEndian.PutUint32(s.prefix[:], uint32(length))
s.prefix[4] = byte(paddingLength)
padding := s.padding[:paddingLength]
if _, err := io.ReadFull(rand, padding); err != nil {
return err
}
if s.mac != nil {
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)
}
if _, err := w.Write(s.prefix[:]); err != nil {
return err
}
if _, err := w.Write(packet); err != nil {
return err
}
if _, err := w.Write(padding); err != nil {
return err
}
if s.mac != nil {
s.macResult = s.mac.Sum(s.macResult[:0])
if _, err := w.Write(s.macResult); err != nil {
return err
}
}
return nil
}
type gcmCipher struct {
aead cipher.AEAD
prefix [4]byte
iv []byte
buf []byte
}
func newGCMCipher(key, iv, unusedMacKey []byte, unusedAlgs DirectionAlgorithms) (packetCipher, error) {
c, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
aead, err := cipher.NewGCM(c)
if err != nil {
return nil, err
}
return &gcmCipher{
aead: aead,
iv: iv,
}, nil
}
const gcmTagSize = 16
func (c *gcmCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
// Pad out to multiple of 16 bytes. This is different from the
// stream cipher because that encrypts the length too.
padding := byte(packetSizeMultiple - (1+len(packet))%packetSizeMultiple)
if padding < 4 {
padding += packetSizeMultiple
}
length := uint32(len(packet) + int(padding) + 1)
binary.BigEndian.PutUint32(c.prefix[:], length)
if _, err := w.Write(c.prefix[:]); err != nil {
return err
}
if cap(c.buf) < int(length) {
c.buf = make([]byte, length)
} else {
c.buf = c.buf[:length]
}
c.buf[0] = padding
copy(c.buf[1:], packet)
if _, err := io.ReadFull(rand, c.buf[1+len(packet):]); err != nil {
return err
}
c.buf = c.aead.Seal(c.buf[:0], c.iv, c.buf, c.prefix[:])
if _, err := w.Write(c.buf); err != nil {
return err
}
c.incIV()
return nil
}
func (c *gcmCipher) incIV() {
for i := 4 + 7; i >= 4; i-- {
c.iv[i]++
if c.iv[i] != 0 {
break
}
}
}
func (c *gcmCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
if _, err := io.ReadFull(r, c.prefix[:]); err != nil {
return nil, err
}
length := binary.BigEndian.Uint32(c.prefix[:])
if length > maxPacket {
return nil, errors.New("ssh: max packet length exceeded")
}
if cap(c.buf) < int(length+gcmTagSize) {
c.buf = make([]byte, length+gcmTagSize)
} else {
c.buf = c.buf[:length+gcmTagSize]
}
if _, err := io.ReadFull(r, c.buf); err != nil {
return nil, err
}
plain, err := c.aead.Open(c.buf[:0], c.iv, c.buf, c.prefix[:])
if err != nil {
return nil, err
}
c.incIV()
if len(plain) == 0 {
return nil, errors.New("ssh: empty packet")
}
padding := plain[0]
if padding < 4 {
// padding is a byte, so it automatically satisfies
// the maximum size, which is 255.
return nil, fmt.Errorf("ssh: illegal padding %d", padding)
}
if int(padding+1) >= len(plain) {
return nil, fmt.Errorf("ssh: padding %d too large", padding)
}
plain = plain[1 : length-uint32(padding)]
return plain, nil
}
// cbcCipher implements aes128-cbc cipher defined in RFC 4253 section 6.1
type cbcCipher struct {
mac hash.Hash
macSize uint32
decrypter cipher.BlockMode
encrypter cipher.BlockMode
// The following members are to avoid per-packet allocations.
seqNumBytes [4]byte
packetData []byte
macResult []byte
// Amount of data we should still read to hide which
// verification error triggered.
oracleCamouflage uint32
}
func newCBCCipher(c cipher.Block, key, iv, macKey []byte, algs DirectionAlgorithms) (packetCipher, error) {
cbc := &cbcCipher{
mac: macModes[algs.MAC].new(macKey),
decrypter: cipher.NewCBCDecrypter(c, iv),
encrypter: cipher.NewCBCEncrypter(c, iv),
packetData: make([]byte, 1024),
}
if cbc.mac != nil {
cbc.macSize = uint32(cbc.mac.Size())
}
return cbc, nil
}
func newAESCBCCipher(key, iv, macKey []byte, algs DirectionAlgorithms) (packetCipher, error) {
c, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
cbc, err := newCBCCipher(c, key, iv, macKey, algs)
if err != nil {
return nil, err
}
return cbc, nil
}
func newTripleDESCBCCipher(key, iv, macKey []byte, algs DirectionAlgorithms) (packetCipher, error) {
c, err := des.NewTripleDESCipher(key)
if err != nil {
return nil, err
}
cbc, err := newCBCCipher(c, key, iv, macKey, algs)
if err != nil {
return nil, err
}
return cbc, nil
}
func maxUInt32(a, b int) uint32 {
if a > b {
return uint32(a)
}
return uint32(b)
}
const (
cbcMinPacketSizeMultiple = 8
cbcMinPacketSize = 16
cbcMinPaddingSize = 4
)
// cbcError represents a verification error that may leak information.
type cbcError string
func (e cbcError) Error() string { return string(e) }
func (c *cbcCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
p, err := c.readCipherPacketLeaky(seqNum, r)
if err != nil {
if _, ok := err.(cbcError); ok {
// Verification error: read a fixed amount of
// data, to make distinguishing between
// failing MAC and failing length check more
// difficult.
io.CopyN(io.Discard, r, int64(c.oracleCamouflage))
}
}
return p, err
}
func (c *cbcCipher) readCipherPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) {
blockSize := c.decrypter.BlockSize()
// Read the header, which will include some of the subsequent data in the
// case of block ciphers - this is copied back to the payload later.
// How many bytes of payload/padding will be read with this first read.
firstBlockLength := uint32((prefixLen + blockSize - 1) / blockSize * blockSize)
firstBlock := c.packetData[:firstBlockLength]
if _, err := io.ReadFull(r, firstBlock); err != nil {
return nil, err
}
c.oracleCamouflage = maxPacket + 4 + c.macSize - firstBlockLength
c.decrypter.CryptBlocks(firstBlock, firstBlock)
length := binary.BigEndian.Uint32(firstBlock[:4])
if length > maxPacket {
return nil, cbcError("ssh: packet too large")
}
if length+4 < maxUInt32(cbcMinPacketSize, blockSize) {
// The minimum size of a packet is 16 (or the cipher block size, whichever
// is larger) bytes.
return nil, cbcError("ssh: packet too small")
}
// The length of the packet (including the length field but not the MAC) must
// be a multiple of the block size or 8, whichever is larger.
if (length+4)%maxUInt32(cbcMinPacketSizeMultiple, blockSize) != 0 {
return nil, cbcError("ssh: invalid packet length multiple")
}
paddingLength := uint32(firstBlock[4])
if paddingLength < cbcMinPaddingSize || length <= paddingLength+1 {
return nil, cbcError("ssh: invalid packet length")
}
// Positions within the c.packetData buffer:
macStart := 4 + length
paddingStart := macStart - paddingLength
// Entire packet size, starting before length, ending at end of mac.
entirePacketSize := macStart + c.macSize
// Ensure c.packetData is large enough for the entire packet data.
if uint32(cap(c.packetData)) < entirePacketSize {
// Still need to upsize and copy, but this should be rare at runtime, only
// on upsizing the packetData buffer.
c.packetData = make([]byte, entirePacketSize)
copy(c.packetData, firstBlock)
} else {
c.packetData = c.packetData[:entirePacketSize]
}
n, err := io.ReadFull(r, c.packetData[firstBlockLength:])
if err != nil {
return nil, err
}
c.oracleCamouflage -= uint32(n)
remainingCrypted := c.packetData[firstBlockLength:macStart]
c.decrypter.CryptBlocks(remainingCrypted, remainingCrypted)
mac := c.packetData[macStart:]
if c.mac != nil {
c.mac.Reset()
binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum)
c.mac.Write(c.seqNumBytes[:])
c.mac.Write(c.packetData[:macStart])
c.macResult = c.mac.Sum(c.macResult[:0])
if subtle.ConstantTimeCompare(c.macResult, mac) != 1 {
return nil, cbcError("ssh: MAC failure")
}
}
return c.packetData[prefixLen:paddingStart], nil
}
func (c *cbcCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
effectiveBlockSize := maxUInt32(cbcMinPacketSizeMultiple, c.encrypter.BlockSize())
// Length of encrypted portion of the packet (header, payload, padding).
// Enforce minimum padding and packet size.
encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPaddingSize)
// Enforce block size.
encLength = (encLength + effectiveBlockSize - 1) / effectiveBlockSize * effectiveBlockSize
length := encLength - 4
paddingLength := int(length) - (1 + len(packet))
// Overall buffer contains: header, payload, padding, mac.
// Space for the MAC is reserved in the capacity but not the slice length.
bufferSize := encLength + c.macSize
if uint32(cap(c.packetData)) < bufferSize {
c.packetData = make([]byte, encLength, bufferSize)
} else {
c.packetData = c.packetData[:encLength]
}
p := c.packetData
// Packet header.
binary.BigEndian.PutUint32(p, length)
p = p[4:]
p[0] = byte(paddingLength)
// Payload.
p = p[1:]
copy(p, packet)
// Padding.
p = p[len(packet):]
if _, err := io.ReadFull(rand, p); err != nil {
return err
}
if c.mac != nil {
c.mac.Reset()
binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum)
c.mac.Write(c.seqNumBytes[:])
c.mac.Write(c.packetData)
// The MAC is now appended into the capacity reserved for it earlier.
c.packetData = c.mac.Sum(c.packetData)
}
c.encrypter.CryptBlocks(c.packetData[:encLength], c.packetData[:encLength])
if _, err := w.Write(c.packetData); err != nil {
return err
}
return nil
}
// chacha20Poly1305Cipher implements the chacha20-poly1305@openssh.com
// AEAD, which is described here:
//
// https://tools.ietf.org/html/draft-josefsson-ssh-chacha20-poly1305-openssh-00
//
// the methods here also implement padding, which RFC 4253 Section 6
// also requires of stream ciphers.
type chacha20Poly1305Cipher struct {
lengthKey [32]byte
contentKey [32]byte
buf []byte
}
func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs DirectionAlgorithms) (packetCipher, error) {
if len(key) != 64 {
panic(len(key))
}
c := &chacha20Poly1305Cipher{
buf: make([]byte, 256),
}
copy(c.contentKey[:], key[:32])
copy(c.lengthKey[:], key[32:])
return c, nil
}
func (c *chacha20Poly1305Cipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
nonce := make([]byte, 12)
binary.BigEndian.PutUint32(nonce[8:], seqNum)
s, err := chacha20.NewUnauthenticatedCipher(c.contentKey[:], nonce)
if err != nil {
return nil, err
}
var polyKey, discardBuf [32]byte
s.XORKeyStream(polyKey[:], polyKey[:])
s.XORKeyStream(discardBuf[:], discardBuf[:]) // skip the next 32 bytes
encryptedLength := c.buf[:4]
if _, err := io.ReadFull(r, encryptedLength); err != nil {
return nil, err
}
var lenBytes [4]byte
ls, err := chacha20.NewUnauthenticatedCipher(c.lengthKey[:], nonce)
if err != nil {
return nil, err
}
ls.XORKeyStream(lenBytes[:], encryptedLength)
length := binary.BigEndian.Uint32(lenBytes[:])
if length > maxPacket {
return nil, errors.New("ssh: invalid packet length, packet too large")
}
contentEnd := 4 + length
packetEnd := contentEnd + poly1305.TagSize
if uint32(cap(c.buf)) < packetEnd {
c.buf = make([]byte, packetEnd)
copy(c.buf[:], encryptedLength)
} else {
c.buf = c.buf[:packetEnd]
}
if _, err := io.ReadFull(r, c.buf[4:packetEnd]); err != nil {
return nil, err
}
var mac [poly1305.TagSize]byte
copy(mac[:], c.buf[contentEnd:packetEnd])
if !poly1305.Verify(&mac, c.buf[:contentEnd], &polyKey) {
return nil, errors.New("ssh: MAC failure")
}
plain := c.buf[4:contentEnd]
s.XORKeyStream(plain, plain)
if len(plain) == 0 {
return nil, errors.New("ssh: empty packet")
}
padding := plain[0]
if padding < 4 {
// padding is a byte, so it automatically satisfies
// the maximum size, which is 255.
return nil, fmt.Errorf("ssh: illegal padding %d", padding)
}
if int(padding)+1 >= len(plain) {
return nil, fmt.Errorf("ssh: padding %d too large", padding)
}
plain = plain[1 : len(plain)-int(padding)]
return plain, nil
}
func (c *chacha20Poly1305Cipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error {
nonce := make([]byte, 12)
binary.BigEndian.PutUint32(nonce[8:], seqNum)
s, err := chacha20.NewUnauthenticatedCipher(c.contentKey[:], nonce)
if err != nil {
return err
}
var polyKey, discardBuf [32]byte
s.XORKeyStream(polyKey[:], polyKey[:])
s.XORKeyStream(discardBuf[:], discardBuf[:]) // skip the next 32 bytes
// There is no blocksize, so fall back to multiple of 8 byte
// padding, as described in RFC 4253, Sec 6.
const packetSizeMultiple = 8
padding := packetSizeMultiple - (1+len(payload))%packetSizeMultiple
if padding < 4 {
padding += packetSizeMultiple
}
// size (4 bytes), padding (1), payload, padding, tag.
totalLength := 4 + 1 + len(payload) + padding + poly1305.TagSize
if cap(c.buf) < totalLength {
c.buf = make([]byte, totalLength)
} else {
c.buf = c.buf[:totalLength]
}
binary.BigEndian.PutUint32(c.buf, uint32(1+len(payload)+padding))
ls, err := chacha20.NewUnauthenticatedCipher(c.lengthKey[:], nonce)
if err != nil {
return err
}
ls.XORKeyStream(c.buf, c.buf[:4])
c.buf[4] = byte(padding)
copy(c.buf[5:], payload)
packetEnd := 5 + len(payload) + padding
if _, err := io.ReadFull(rand, c.buf[5+len(payload):packetEnd]); err != nil {
return err
}
s.XORKeyStream(c.buf[4:], c.buf[4:packetEnd])
var mac [poly1305.TagSize]byte
poly1305.Sum(&mac, c.buf[:packetEnd], &polyKey)
copy(c.buf[packetEnd:], mac[:])
if _, err := w.Write(c.buf); err != nil {
return err
}
return nil
}
// Copyright 2011 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 ssh
import (
"bytes"
"errors"
"fmt"
"net"
"os"
"sync"
"time"
)
// Client implements a traditional SSH client that supports shells,
// subprocesses, TCP port/streamlocal forwarding and tunneled dialing.
type Client struct {
Conn
handleForwardsOnce sync.Once // guards calling (*Client).handleForwards
forwards forwardList // forwarded tcpip connections from the remote side
mu sync.Mutex
channelHandlers map[string]chan NewChannel
}
// HandleChannelOpen returns a channel on which NewChannel requests
// for the given type are sent. If the type already is being handled,
// nil is returned. The channel is closed when the connection is closed.
func (c *Client) HandleChannelOpen(channelType string) <-chan NewChannel {
c.mu.Lock()
defer c.mu.Unlock()
if c.channelHandlers == nil {
// The SSH channel has been closed.
c := make(chan NewChannel)
close(c)
return c
}
ch := c.channelHandlers[channelType]
if ch != nil {
return nil
}
ch = make(chan NewChannel, chanSize)
c.channelHandlers[channelType] = ch
return ch
}
// NewClient creates a Client on top of the given connection.
func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client {
conn := &Client{
Conn: c,
channelHandlers: make(map[string]chan NewChannel, 1),
}
go conn.handleGlobalRequests(reqs)
go conn.handleChannelOpens(chans)
go func() {
conn.Wait()
conn.forwards.closeAll()
}()
return conn
}
// NewClientConn establishes an authenticated SSH connection using c
// as the underlying transport. The Request and NewChannel channels
// must be serviced or the connection will hang.
func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan NewChannel, <-chan *Request, error) {
fullConf := *config
fullConf.SetDefaults()
if fullConf.HostKeyCallback == nil {
c.Close()
return nil, nil, nil, errors.New("ssh: must specify HostKeyCallback")
}
conn := &connection{
sshConn: sshConn{conn: c, user: fullConf.User},
}
if err := conn.clientHandshake(addr, &fullConf); err != nil {
c.Close()
return nil, nil, nil, fmt.Errorf("ssh: handshake failed: %w", err)
}
conn.mux = newMux(conn.transport)
return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil
}
// clientHandshake performs the client side key exchange. See RFC 4253 Section
// 7.
func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) error {
if config.ClientVersion != "" {
c.clientVersion = []byte(config.ClientVersion)
} else {
c.clientVersion = []byte(packageVersion)
}
var err error
c.serverVersion, err = exchangeVersions(c.sshConn.conn, c.clientVersion)
if err != nil {
return err
}
c.transport = newClientTransport(
newTransport(c.sshConn.conn, config.Rand, true /* is client */),
c.clientVersion, c.serverVersion, config, dialAddress, c.sshConn.RemoteAddr())
if err := c.transport.waitSession(); err != nil {
return err
}
c.sessionID = c.transport.getSessionID()
c.algorithms = c.transport.getAlgorithms()
return c.clientAuthenticate(config)
}
// verifyHostKeySignature verifies the host key obtained in the key exchange.
// algo is the negotiated algorithm, and may be a certificate type.
func verifyHostKeySignature(hostKey PublicKey, algo string, result *kexResult) error {
sig, rest, ok := parseSignatureBody(result.Signature)
if len(rest) > 0 || !ok {
return errors.New("ssh: signature parse error")
}
if a := underlyingAlgo(algo); sig.Format != a {
return fmt.Errorf("ssh: invalid signature algorithm %q, expected %q", sig.Format, a)
}
return hostKey.Verify(result.H, sig)
}
// NewSession opens a new Session for this client. (A session is a remote
// execution of a program.)
func (c *Client) NewSession() (*Session, error) {
ch, in, err := c.OpenChannel("session", nil)
if err != nil {
return nil, err
}
return newSession(ch, in)
}
func (c *Client) handleGlobalRequests(incoming <-chan *Request) {
for r := range incoming {
// This handles keepalive messages and matches
// the behaviour of OpenSSH.
r.Reply(false, nil)
}
}
// handleChannelOpens channel open messages from the remote side.
func (c *Client) handleChannelOpens(in <-chan NewChannel) {
for ch := range in {
c.mu.Lock()
handler := c.channelHandlers[ch.ChannelType()]
c.mu.Unlock()
if handler != nil {
handler <- ch
} else {
ch.Reject(UnknownChannelType, fmt.Sprintf("unknown channel type: %v", ch.ChannelType()))
}
}
c.mu.Lock()
for _, ch := range c.channelHandlers {
close(ch)
}
c.channelHandlers = nil
c.mu.Unlock()
}
// Dial starts a client connection to the given SSH server. It is a
// convenience function that connects to the given network address,
// initiates the SSH handshake, and then sets up a Client. For access
// to incoming channels and requests, use net.Dial with NewClientConn
// instead.
func Dial(network, addr string, config *ClientConfig) (*Client, error) {
conn, err := net.DialTimeout(network, addr, config.Timeout)
if err != nil {
return nil, err
}
c, chans, reqs, err := NewClientConn(conn, addr, config)
if err != nil {
return nil, err
}
return NewClient(c, chans, reqs), nil
}
// HostKeyCallback is the function type used for verifying server
// keys. A HostKeyCallback must return nil if the host key is OK, or
// an error to reject it. It receives the hostname as passed to Dial
// or NewClientConn. The remote address is the RemoteAddr of the
// net.Conn underlying the SSH connection.
type HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error
// BannerCallback is the function type used for treat the banner sent by
// the server. A BannerCallback receives the message sent by the remote server.
type BannerCallback func(message string) error
// A ClientConfig structure is used to configure a Client. It must not be
// modified after having been passed to an SSH function.
type ClientConfig struct {
// Config contains configuration that is shared between clients and
// servers.
Config
// User contains the username to authenticate as.
User string
// Auth contains possible authentication methods to use with the
// server. Only the first instance of a particular RFC 4252 method will
// be used during authentication.
Auth []AuthMethod
// HostKeyCallback is called during the cryptographic
// handshake to validate the server's host key. The client
// configuration must supply this callback for the connection
// to succeed. The functions InsecureIgnoreHostKey or
// FixedHostKey can be used for simplistic host key checks.
HostKeyCallback HostKeyCallback
// BannerCallback is called during the SSH dance to display a custom
// server's message. The client configuration can supply this callback to
// handle it as wished. The function BannerDisplayStderr can be used for
// simplistic display on Stderr.
BannerCallback BannerCallback
// ClientVersion contains the version identification string that will
// be used for the connection. If empty, a reasonable default is used.
ClientVersion string
// HostKeyAlgorithms lists the public key algorithms that the client will
// accept from the server for host key authentication, in order of
// preference. If empty, a reasonable default is used. Any
// string returned from a PublicKey.Type method may be used, or
// any of the CertAlgo and KeyAlgo constants.
HostKeyAlgorithms []string
// Timeout is the maximum amount of time for the TCP connection to establish.
//
// A Timeout of zero means no timeout.
Timeout time.Duration
}
// InsecureIgnoreHostKey returns a function that can be used for
// ClientConfig.HostKeyCallback to accept any host key. It should
// not be used for production code.
func InsecureIgnoreHostKey() HostKeyCallback {
return func(hostname string, remote net.Addr, key PublicKey) error {
return nil
}
}
type fixedHostKey struct {
key PublicKey
}
func (f *fixedHostKey) check(hostname string, remote net.Addr, key PublicKey) error {
if f.key == nil {
return fmt.Errorf("ssh: required host key was nil")
}
if !bytes.Equal(key.Marshal(), f.key.Marshal()) {
return fmt.Errorf("ssh: host key mismatch")
}
return nil
}
// FixedHostKey returns a function for use in
// ClientConfig.HostKeyCallback to accept only a specific host key.
func FixedHostKey(key PublicKey) HostKeyCallback {
hk := &fixedHostKey{key}
return hk.check
}
// BannerDisplayStderr returns a function that can be used for
// ClientConfig.BannerCallback to display banners on os.Stderr.
func BannerDisplayStderr() BannerCallback {
return func(banner string) error {
_, err := os.Stderr.WriteString(banner)
return err
}
}
// Copyright 2011 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 ssh
import (
"bytes"
"errors"
"fmt"
"io"
"slices"
"strings"
)
type authResult int
const (
authFailure authResult = iota
authPartialSuccess
authSuccess
)
// clientAuthenticate authenticates with the remote server. See RFC 4252.
func (c *connection) clientAuthenticate(config *ClientConfig) error {
// initiate user auth session
if err := c.transport.writePacket(Marshal(&serviceRequestMsg{serviceUserAuth})); err != nil {
return err
}
packet, err := c.transport.readPacket()
if err != nil {
return err
}
// The server may choose to send a SSH_MSG_EXT_INFO at this point (if we
// advertised willingness to receive one, which we always do) or not. See
// RFC 8308, Section 2.4.
extensions := make(map[string][]byte)
if len(packet) > 0 && packet[0] == msgExtInfo {
var extInfo extInfoMsg
if err := Unmarshal(packet, &extInfo); err != nil {
return err
}
payload := extInfo.Payload
for i := uint32(0); i < extInfo.NumExtensions; i++ {
name, rest, ok := parseString(payload)
if !ok {
return parseError(msgExtInfo)
}
value, rest, ok := parseString(rest)
if !ok {
return parseError(msgExtInfo)
}
extensions[string(name)] = value
payload = rest
}
packet, err = c.transport.readPacket()
if err != nil {
return err
}
}
var serviceAccept serviceAcceptMsg
if err := Unmarshal(packet, &serviceAccept); err != nil {
return err
}
// during the authentication phase the client first attempts the "none" method
// then any untried methods suggested by the server.
var tried []string
var lastMethods []string
sessionID := c.transport.getSessionID()
for auth := AuthMethod(new(noneAuth)); auth != nil; {
ok, methods, err := auth.auth(sessionID, config.User, c.transport, config.Rand, extensions)
if err != nil {
// On disconnect, return error immediately
if _, ok := err.(*disconnectMsg); ok {
return err
}
// We return the error later if there is no other method left to
// try.
ok = authFailure
}
if ok == authSuccess {
// success
return nil
} else if ok == authFailure {
if m := auth.method(); !slices.Contains(tried, m) {
tried = append(tried, m)
}
}
if methods == nil {
methods = lastMethods
}
lastMethods = methods
auth = nil
findNext:
for _, a := range config.Auth {
candidateMethod := a.method()
if slices.Contains(tried, candidateMethod) {
continue
}
for _, meth := range methods {
if meth == candidateMethod {
auth = a
break findNext
}
}
}
if auth == nil && err != nil {
// We have an error and there are no other authentication methods to
// try, so we return it.
return err
}
}
return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", tried)
}
// An AuthMethod represents an instance of an RFC 4252 authentication method.
type AuthMethod interface {
// auth authenticates user over transport t.
// Returns true if authentication is successful.
// If authentication is not successful, a []string of alternative
// method names is returned. If the slice is nil, it will be ignored
// and the previous set of possible methods will be reused.
auth(session []byte, user string, p packetConn, rand io.Reader, extensions map[string][]byte) (authResult, []string, error)
// method returns the RFC 4252 method name.
method() string
}
// "none" authentication, RFC 4252 section 5.2.
type noneAuth int
func (n *noneAuth) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) {
if err := c.writePacket(Marshal(&userAuthRequestMsg{
User: user,
Service: serviceSSH,
Method: "none",
})); err != nil {
return authFailure, nil, err
}
return handleAuthResponse(c)
}
func (n *noneAuth) method() string {
return "none"
}
// passwordCallback is an AuthMethod that fetches the password through
// a function call, e.g. by prompting the user.
type passwordCallback func() (password string, err error)
func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) {
type passwordAuthMsg struct {
User string `sshtype:"50"`
Service string
Method string
Reply bool
Password string
}
pw, err := cb()
// REVIEW NOTE: is there a need to support skipping a password attempt?
// The program may only find out that the user doesn't have a password
// when prompting.
if err != nil {
return authFailure, nil, err
}
if err := c.writePacket(Marshal(&passwordAuthMsg{
User: user,
Service: serviceSSH,
Method: cb.method(),
Reply: false,
Password: pw,
})); err != nil {
return authFailure, nil, err
}
return handleAuthResponse(c)
}
func (cb passwordCallback) method() string {
return "password"
}
// Password returns an AuthMethod using the given password.
func Password(secret string) AuthMethod {
return passwordCallback(func() (string, error) { return secret, nil })
}
// PasswordCallback returns an AuthMethod that uses a callback for
// fetching a password.
func PasswordCallback(prompt func() (secret string, err error)) AuthMethod {
return passwordCallback(prompt)
}
type publickeyAuthMsg struct {
User string `sshtype:"50"`
Service string
Method string
// HasSig indicates to the receiver packet that the auth request is signed and
// should be used for authentication of the request.
HasSig bool
Algoname string
PubKey []byte
// Sig is tagged with "rest" so Marshal will exclude it during
// validateKey
Sig []byte `ssh:"rest"`
}
// publicKeyCallback is an AuthMethod that uses a set of key
// pairs for authentication.
type publicKeyCallback func() ([]Signer, error)
func (cb publicKeyCallback) method() string {
return "publickey"
}
func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte) (MultiAlgorithmSigner, string, error) {
var as MultiAlgorithmSigner
keyFormat := signer.PublicKey().Type()
// If the signer implements MultiAlgorithmSigner we use the algorithms it
// support, if it implements AlgorithmSigner we assume it supports all
// algorithms, otherwise only the key format one.
switch s := signer.(type) {
case MultiAlgorithmSigner:
as = s
case AlgorithmSigner:
as = &multiAlgorithmSigner{
AlgorithmSigner: s,
supportedAlgorithms: algorithmsForKeyFormat(underlyingAlgo(keyFormat)),
}
default:
as = &multiAlgorithmSigner{
AlgorithmSigner: algorithmSignerWrapper{signer},
supportedAlgorithms: []string{underlyingAlgo(keyFormat)},
}
}
getFallbackAlgo := func() (string, error) {
// Fallback to use if there is no "server-sig-algs" extension or a
// common algorithm cannot be found. We use the public key format if the
// MultiAlgorithmSigner supports it, otherwise we return an error.
if !slices.Contains(as.Algorithms(), underlyingAlgo(keyFormat)) {
return "", fmt.Errorf("ssh: no common public key signature algorithm, server only supports %q for key type %q, signer only supports %v",
underlyingAlgo(keyFormat), keyFormat, as.Algorithms())
}
return keyFormat, nil
}
extPayload, ok := extensions["server-sig-algs"]
if !ok {
// If there is no "server-sig-algs" extension use the fallback
// algorithm.
algo, err := getFallbackAlgo()
return as, algo, err
}
// The server-sig-algs extension only carries underlying signature
// algorithm, but we are trying to select a protocol-level public key
// algorithm, which might be a certificate type. Extend the list of server
// supported algorithms to include the corresponding certificate algorithms.
serverAlgos := strings.Split(string(extPayload), ",")
for _, algo := range serverAlgos {
if certAlgo, ok := certificateAlgo(algo); ok {
serverAlgos = append(serverAlgos, certAlgo)
}
}
// Filter algorithms based on those supported by MultiAlgorithmSigner.
var keyAlgos []string
for _, algo := range algorithmsForKeyFormat(keyFormat) {
if slices.Contains(as.Algorithms(), underlyingAlgo(algo)) {
keyAlgos = append(keyAlgos, algo)
}
}
algo, err := findCommon("public key signature algorithm", keyAlgos, serverAlgos, true)
if err != nil {
// If there is no overlap, return the fallback algorithm to support
// servers that fail to list all supported algorithms.
algo, err := getFallbackAlgo()
return as, algo, err
}
return as, algo, nil
}
func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader, extensions map[string][]byte) (authResult, []string, error) {
// Authentication is performed by sending an enquiry to test if a key is
// acceptable to the remote. If the key is acceptable, the client will
// attempt to authenticate with the valid key. If not the client will repeat
// the process with the remaining keys.
signers, err := cb()
if err != nil {
return authFailure, nil, err
}
var methods []string
var errSigAlgo error
origSignersLen := len(signers)
for idx := 0; idx < len(signers); idx++ {
signer := signers[idx]
pub := signer.PublicKey()
as, algo, err := pickSignatureAlgorithm(signer, extensions)
if err != nil && errSigAlgo == nil {
// If we cannot negotiate a signature algorithm store the first
// error so we can return it to provide a more meaningful message if
// no other signers work.
errSigAlgo = err
continue
}
ok, err := validateKey(pub, algo, user, c)
if err != nil {
return authFailure, nil, err
}
// OpenSSH 7.2-7.7 advertises support for rsa-sha2-256 and rsa-sha2-512
// in the "server-sig-algs" extension but doesn't support these
// algorithms for certificate authentication, so if the server rejects
// the key try to use the obtained algorithm as if "server-sig-algs" had
// not been implemented if supported from the algorithm signer.
if !ok && idx < origSignersLen && isRSACert(algo) && algo != CertAlgoRSAv01 {
if slices.Contains(as.Algorithms(), KeyAlgoRSA) {
// We retry using the compat algorithm after all signers have
// been tried normally.
signers = append(signers, &multiAlgorithmSigner{
AlgorithmSigner: as,
supportedAlgorithms: []string{KeyAlgoRSA},
})
}
}
if !ok {
continue
}
pubKey := pub.Marshal()
data := buildDataSignedForAuth(session, userAuthRequestMsg{
User: user,
Service: serviceSSH,
Method: cb.method(),
}, algo, pubKey)
sign, err := as.SignWithAlgorithm(rand, data, underlyingAlgo(algo))
if err != nil {
return authFailure, nil, err
}
// manually wrap the serialized signature in a string
s := Marshal(sign)
sig := make([]byte, stringLength(len(s)))
marshalString(sig, s)
msg := publickeyAuthMsg{
User: user,
Service: serviceSSH,
Method: cb.method(),
HasSig: true,
Algoname: algo,
PubKey: pubKey,
Sig: sig,
}
p := Marshal(&msg)
if err := c.writePacket(p); err != nil {
return authFailure, nil, err
}
var success authResult
success, methods, err = handleAuthResponse(c)
if err != nil {
return authFailure, nil, err
}
// If authentication succeeds or the list of available methods does not
// contain the "publickey" method, do not attempt to authenticate with any
// other keys. According to RFC 4252 Section 7, the latter can occur when
// additional authentication methods are required.
if success == authSuccess || !slices.Contains(methods, cb.method()) {
return success, methods, err
}
}
return authFailure, methods, errSigAlgo
}
// validateKey validates the key provided is acceptable to the server.
func validateKey(key PublicKey, algo string, user string, c packetConn) (bool, error) {
pubKey := key.Marshal()
msg := publickeyAuthMsg{
User: user,
Service: serviceSSH,
Method: "publickey",
HasSig: false,
Algoname: algo,
PubKey: pubKey,
}
if err := c.writePacket(Marshal(&msg)); err != nil {
return false, err
}
return confirmKeyAck(key, c)
}
func confirmKeyAck(key PublicKey, c packetConn) (bool, error) {
pubKey := key.Marshal()
for {
packet, err := c.readPacket()
if err != nil {
return false, err
}
switch packet[0] {
case msgUserAuthBanner:
if err := handleBannerResponse(c, packet); err != nil {
return false, err
}
case msgUserAuthPubKeyOk:
var msg userAuthPubKeyOkMsg
if err := Unmarshal(packet, &msg); err != nil {
return false, err
}
// According to RFC 4252 Section 7 the algorithm in
// SSH_MSG_USERAUTH_PK_OK should match that of the request but some
// servers send the key type instead. OpenSSH allows any algorithm
// that matches the public key, so we do the same.
// https://github.com/openssh/openssh-portable/blob/86bdd385/sshconnect2.c#L709
if !slices.Contains(algorithmsForKeyFormat(key.Type()), msg.Algo) {
return false, nil
}
if !bytes.Equal(msg.PubKey, pubKey) {
return false, nil
}
return true, nil
case msgUserAuthFailure:
return false, nil
default:
return false, unexpectedMessageError(msgUserAuthPubKeyOk, packet[0])
}
}
}
// PublicKeys returns an AuthMethod that uses the given key
// pairs.
func PublicKeys(signers ...Signer) AuthMethod {
return publicKeyCallback(func() ([]Signer, error) { return signers, nil })
}
// PublicKeysCallback returns an AuthMethod that runs the given
// function to obtain a list of key pairs.
func PublicKeysCallback(getSigners func() (signers []Signer, err error)) AuthMethod {
return publicKeyCallback(getSigners)
}
// handleAuthResponse returns whether the preceding authentication request succeeded
// along with a list of remaining authentication methods to try next and
// an error if an unexpected response was received.
func handleAuthResponse(c packetConn) (authResult, []string, error) {
gotMsgExtInfo := false
for {
packet, err := c.readPacket()
if err != nil {
return authFailure, nil, err
}
switch packet[0] {
case msgUserAuthBanner:
if err := handleBannerResponse(c, packet); err != nil {
return authFailure, nil, err
}
case msgExtInfo:
// Ignore post-authentication RFC 8308 extensions, once.
if gotMsgExtInfo {
return authFailure, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0])
}
gotMsgExtInfo = true
case msgUserAuthFailure:
var msg userAuthFailureMsg
if err := Unmarshal(packet, &msg); err != nil {
return authFailure, nil, err
}
if msg.PartialSuccess {
return authPartialSuccess, msg.Methods, nil
}
return authFailure, msg.Methods, nil
case msgUserAuthSuccess:
return authSuccess, nil, nil
default:
return authFailure, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0])
}
}
}
func handleBannerResponse(c packetConn, packet []byte) error {
var msg userAuthBannerMsg
if err := Unmarshal(packet, &msg); err != nil {
return err
}
transport, ok := c.(*handshakeTransport)
if !ok {
return nil
}
if transport.bannerCallback != nil {
return transport.bannerCallback(msg.Message)
}
return nil
}
// KeyboardInteractiveChallenge should print questions, optionally
// disabling echoing (e.g. for passwords), and return all the answers.
// Challenge may be called multiple times in a single session. After
// successful authentication, the server may send a challenge with no
// questions, for which the name and instruction messages should be
// printed. RFC 4256 section 3.3 details how the UI should behave for
// both CLI and GUI environments.
type KeyboardInteractiveChallenge func(name, instruction string, questions []string, echos []bool) (answers []string, err error)
// KeyboardInteractive returns an AuthMethod using a prompt/response
// sequence controlled by the server.
func KeyboardInteractive(challenge KeyboardInteractiveChallenge) AuthMethod {
return challenge
}
func (cb KeyboardInteractiveChallenge) method() string {
return "keyboard-interactive"
}
func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) {
type initiateMsg struct {
User string `sshtype:"50"`
Service string
Method string
Language string
Submethods string
}
if err := c.writePacket(Marshal(&initiateMsg{
User: user,
Service: serviceSSH,
Method: "keyboard-interactive",
})); err != nil {
return authFailure, nil, err
}
gotMsgExtInfo := false
gotUserAuthInfoRequest := false
for {
packet, err := c.readPacket()
if err != nil {
return authFailure, nil, err
}
// like handleAuthResponse, but with less options.
switch packet[0] {
case msgUserAuthBanner:
if err := handleBannerResponse(c, packet); err != nil {
return authFailure, nil, err
}
continue
case msgExtInfo:
// Ignore post-authentication RFC 8308 extensions, once.
if gotMsgExtInfo {
return authFailure, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0])
}
gotMsgExtInfo = true
continue
case msgUserAuthInfoRequest:
// OK
case msgUserAuthFailure:
var msg userAuthFailureMsg
if err := Unmarshal(packet, &msg); err != nil {
return authFailure, nil, err
}
if msg.PartialSuccess {
return authPartialSuccess, msg.Methods, nil
}
if !gotUserAuthInfoRequest {
return authFailure, msg.Methods, unexpectedMessageError(msgUserAuthInfoRequest, packet[0])
}
return authFailure, msg.Methods, nil
case msgUserAuthSuccess:
return authSuccess, nil, nil
default:
return authFailure, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0])
}
var msg userAuthInfoRequestMsg
if err := Unmarshal(packet, &msg); err != nil {
return authFailure, nil, err
}
gotUserAuthInfoRequest = true
// Manually unpack the prompt/echo pairs.
rest := msg.Prompts
var prompts []string
var echos []bool
for i := 0; i < int(msg.NumPrompts); i++ {
prompt, r, ok := parseString(rest)
if !ok || len(r) == 0 {
return authFailure, nil, errors.New("ssh: prompt format error")
}
prompts = append(prompts, string(prompt))
echos = append(echos, r[0] != 0)
rest = r[1:]
}
if len(rest) != 0 {
return authFailure, nil, errors.New("ssh: extra data following keyboard-interactive pairs")
}
answers, err := cb(msg.Name, msg.Instruction, prompts, echos)
if err != nil {
return authFailure, nil, err
}
if len(answers) != len(prompts) {
return authFailure, nil, fmt.Errorf("ssh: incorrect number of answers from keyboard-interactive callback %d (expected %d)", len(answers), len(prompts))
}
responseLength := 1 + 4
for _, a := range answers {
responseLength += stringLength(len(a))
}
serialized := make([]byte, responseLength)
p := serialized
p[0] = msgUserAuthInfoResponse
p = p[1:]
p = marshalUint32(p, uint32(len(answers)))
for _, a := range answers {
p = marshalString(p, []byte(a))
}
if err := c.writePacket(serialized); err != nil {
return authFailure, nil, err
}
}
}
type retryableAuthMethod struct {
authMethod AuthMethod
maxTries int
}
func (r *retryableAuthMethod) auth(session []byte, user string, c packetConn, rand io.Reader, extensions map[string][]byte) (ok authResult, methods []string, err error) {
for i := 0; r.maxTries <= 0 || i < r.maxTries; i++ {
ok, methods, err = r.authMethod.auth(session, user, c, rand, extensions)
if ok != authFailure || err != nil { // either success, partial success or error terminate
return ok, methods, err
}
}
return ok, methods, err
}
func (r *retryableAuthMethod) method() string {
return r.authMethod.method()
}
// RetryableAuthMethod is a decorator for other auth methods enabling them to
// be retried up to maxTries before considering that AuthMethod itself failed.
// If maxTries is <= 0, will retry indefinitely
//
// This is useful for interactive clients using challenge/response type
// authentication (e.g. Keyboard-Interactive, Password, etc) where the user
// could mistype their response resulting in the server issuing a
// SSH_MSG_USERAUTH_FAILURE (rfc4252 #8 [password] and rfc4256 #3.4
// [keyboard-interactive]); Without this decorator, the non-retryable
// AuthMethod would be removed from future consideration, and never tried again
// (and so the user would never be able to retry their entry).
func RetryableAuthMethod(auth AuthMethod, maxTries int) AuthMethod {
return &retryableAuthMethod{authMethod: auth, maxTries: maxTries}
}
// GSSAPIWithMICAuthMethod is an AuthMethod with "gssapi-with-mic" authentication.
// See RFC 4462 section 3
// gssAPIClient is implementation of the GSSAPIClient interface, see the definition of the interface for details.
// target is the server host you want to log in to.
func GSSAPIWithMICAuthMethod(gssAPIClient GSSAPIClient, target string) AuthMethod {
if gssAPIClient == nil {
panic("gss-api client must be not nil with enable gssapi-with-mic")
}
return &gssAPIWithMICCallback{gssAPIClient: gssAPIClient, target: target}
}
type gssAPIWithMICCallback struct {
gssAPIClient GSSAPIClient
target string
}
func (g *gssAPIWithMICCallback) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) {
m := &userAuthRequestMsg{
User: user,
Service: serviceSSH,
Method: g.method(),
}
// The GSS-API authentication method is initiated when the client sends an SSH_MSG_USERAUTH_REQUEST.
// See RFC 4462 section 3.2.
m.Payload = appendU32(m.Payload, 1)
m.Payload = appendString(m.Payload, string(krb5OID))
if err := c.writePacket(Marshal(m)); err != nil {
return authFailure, nil, err
}
// The server responds to the SSH_MSG_USERAUTH_REQUEST with either an
// SSH_MSG_USERAUTH_FAILURE if none of the mechanisms are supported or
// with an SSH_MSG_USERAUTH_GSSAPI_RESPONSE.
// See RFC 4462 section 3.3.
// OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication,so I don't want to check
// selected mech if it is valid.
packet, err := c.readPacket()
if err != nil {
return authFailure, nil, err
}
userAuthGSSAPIResp := &userAuthGSSAPIResponse{}
if err := Unmarshal(packet, userAuthGSSAPIResp); err != nil {
return authFailure, nil, err
}
// Start the loop into the exchange token.
// See RFC 4462 section 3.4.
var token []byte
defer g.gssAPIClient.DeleteSecContext()
for {
// Initiates the establishment of a security context between the application and a remote peer.
nextToken, needContinue, err := g.gssAPIClient.InitSecContext("host@"+g.target, token, false)
if err != nil {
return authFailure, nil, err
}
if len(nextToken) > 0 {
if err := c.writePacket(Marshal(&userAuthGSSAPIToken{
Token: nextToken,
})); err != nil {
return authFailure, nil, err
}
}
if !needContinue {
break
}
packet, err = c.readPacket()
if err != nil {
return authFailure, nil, err
}
switch packet[0] {
case msgUserAuthFailure:
var msg userAuthFailureMsg
if err := Unmarshal(packet, &msg); err != nil {
return authFailure, nil, err
}
if msg.PartialSuccess {
return authPartialSuccess, msg.Methods, nil
}
return authFailure, msg.Methods, nil
case msgUserAuthGSSAPIError:
userAuthGSSAPIErrorResp := &userAuthGSSAPIError{}
if err := Unmarshal(packet, userAuthGSSAPIErrorResp); err != nil {
return authFailure, nil, err
}
return authFailure, nil, fmt.Errorf("GSS-API Error:\n"+
"Major Status: %d\n"+
"Minor Status: %d\n"+
"Error Message: %s\n", userAuthGSSAPIErrorResp.MajorStatus, userAuthGSSAPIErrorResp.MinorStatus,
userAuthGSSAPIErrorResp.Message)
case msgUserAuthGSSAPIToken:
userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
return authFailure, nil, err
}
token = userAuthGSSAPITokenReq.Token
}
}
// Binding Encryption Keys.
// See RFC 4462 section 3.5.
micField := buildMIC(string(session), user, "ssh-connection", "gssapi-with-mic")
micToken, err := g.gssAPIClient.GetMIC(micField)
if err != nil {
return authFailure, nil, err
}
if err := c.writePacket(Marshal(&userAuthGSSAPIMIC{
MIC: micToken,
})); err != nil {
return authFailure, nil, err
}
return handleAuthResponse(c)
}
func (g *gssAPIWithMICCallback) method() string {
return "gssapi-with-mic"
}
// Copyright 2011 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 ssh
import (
"crypto"
"crypto/fips140"
"crypto/rand"
"fmt"
"io"
"math"
"slices"
"sync"
_ "crypto/sha1"
_ "crypto/sha256"
_ "crypto/sha512"
)
// These are string constants in the SSH protocol.
const (
compressionNone = "none"
serviceUserAuth = "ssh-userauth"
serviceSSH = "ssh-connection"
)
// The ciphers currently or previously implemented by this library, to use in
// [Config.Ciphers]. For a list, see the [Algorithms.Ciphers] returned by
// [SupportedAlgorithms] or [InsecureAlgorithms].
const (
CipherAES128GCM = "aes128-gcm@openssh.com"
CipherAES256GCM = "aes256-gcm@openssh.com"
CipherChaCha20Poly1305 = "chacha20-poly1305@openssh.com"
CipherAES128CTR = "aes128-ctr"
CipherAES192CTR = "aes192-ctr"
CipherAES256CTR = "aes256-ctr"
InsecureCipherAES128CBC = "aes128-cbc"
InsecureCipherTripleDESCBC = "3des-cbc"
InsecureCipherRC4 = "arcfour"
InsecureCipherRC4128 = "arcfour128"
InsecureCipherRC4256 = "arcfour256"
)
// The key exchanges currently or previously implemented by this library, to use
// in [Config.KeyExchanges]. For a list, see the
// [Algorithms.KeyExchanges] returned by [SupportedAlgorithms] or
// [InsecureAlgorithms].
const (
InsecureKeyExchangeDH1SHA1 = "diffie-hellman-group1-sha1"
InsecureKeyExchangeDH14SHA1 = "diffie-hellman-group14-sha1"
KeyExchangeDH14SHA256 = "diffie-hellman-group14-sha256"
KeyExchangeDH16SHA512 = "diffie-hellman-group16-sha512"
KeyExchangeECDHP256 = "ecdh-sha2-nistp256"
KeyExchangeECDHP384 = "ecdh-sha2-nistp384"
KeyExchangeECDHP521 = "ecdh-sha2-nistp521"
KeyExchangeCurve25519 = "curve25519-sha256"
InsecureKeyExchangeDHGEXSHA1 = "diffie-hellman-group-exchange-sha1"
KeyExchangeDHGEXSHA256 = "diffie-hellman-group-exchange-sha256"
// KeyExchangeMLKEM768X25519 is supported from Go 1.24.
KeyExchangeMLKEM768X25519 = "mlkem768x25519-sha256"
// An alias for KeyExchangeCurve25519SHA256. This kex ID will be added if
// KeyExchangeCurve25519SHA256 is requested for backward compatibility with
// OpenSSH versions up to 7.2.
keyExchangeCurve25519LibSSH = "curve25519-sha256@libssh.org"
)
// The message authentication code (MAC) currently or previously implemented by
// this library, to use in [Config.MACs]. For a list, see the
// [Algorithms.MACs] returned by [SupportedAlgorithms] or
// [InsecureAlgorithms].
const (
HMACSHA256ETM = "hmac-sha2-256-etm@openssh.com"
HMACSHA512ETM = "hmac-sha2-512-etm@openssh.com"
HMACSHA256 = "hmac-sha2-256"
HMACSHA512 = "hmac-sha2-512"
HMACSHA1 = "hmac-sha1"
InsecureHMACSHA196 = "hmac-sha1-96"
)
var (
// supportedKexAlgos specifies key-exchange algorithms implemented by this
// package in preference order, excluding those with security issues.
supportedKexAlgos = []string{
KeyExchangeMLKEM768X25519,
KeyExchangeCurve25519,
KeyExchangeECDHP256,
KeyExchangeECDHP384,
KeyExchangeECDHP521,
KeyExchangeDH14SHA256,
KeyExchangeDH16SHA512,
KeyExchangeDHGEXSHA256,
}
// defaultKexAlgos specifies the default preference for key-exchange
// algorithms in preference order.
defaultKexAlgos = []string{
KeyExchangeMLKEM768X25519,
KeyExchangeCurve25519,
KeyExchangeECDHP256,
KeyExchangeECDHP384,
KeyExchangeECDHP521,
KeyExchangeDH14SHA256,
InsecureKeyExchangeDH14SHA1,
}
// insecureKexAlgos specifies key-exchange algorithms implemented by this
// package and which have security issues.
insecureKexAlgos = []string{
InsecureKeyExchangeDH14SHA1,
InsecureKeyExchangeDH1SHA1,
InsecureKeyExchangeDHGEXSHA1,
}
// supportedCiphers specifies cipher algorithms implemented by this package
// in preference order, excluding those with security issues.
supportedCiphers = []string{
CipherAES128GCM,
CipherAES256GCM,
CipherChaCha20Poly1305,
CipherAES128CTR,
CipherAES192CTR,
CipherAES256CTR,
}
// defaultCiphers specifies the default preference for ciphers algorithms
// in preference order.
defaultCiphers = supportedCiphers
// insecureCiphers specifies cipher algorithms implemented by this
// package and which have security issues.
insecureCiphers = []string{
InsecureCipherAES128CBC,
InsecureCipherTripleDESCBC,
InsecureCipherRC4256,
InsecureCipherRC4128,
InsecureCipherRC4,
}
// supportedMACs specifies MAC algorithms implemented by this package in
// preference order, excluding those with security issues.
supportedMACs = []string{
HMACSHA256ETM,
HMACSHA512ETM,
HMACSHA256,
HMACSHA512,
HMACSHA1,
}
// defaultMACs specifies the default preference for MAC algorithms in
// preference order.
defaultMACs = []string{
HMACSHA256ETM,
HMACSHA512ETM,
HMACSHA256,
HMACSHA512,
HMACSHA1,
InsecureHMACSHA196,
}
// insecureMACs specifies MAC algorithms implemented by this
// package and which have security issues.
insecureMACs = []string{
InsecureHMACSHA196,
}
// supportedHostKeyAlgos specifies the supported host-key algorithms (i.e.
// methods of authenticating servers) implemented by this package in
// preference order, excluding those with security issues.
supportedHostKeyAlgos = []string{
CertAlgoRSASHA256v01,
CertAlgoRSASHA512v01,
CertAlgoECDSA256v01,
CertAlgoECDSA384v01,
CertAlgoECDSA521v01,
CertAlgoED25519v01,
KeyAlgoRSASHA256,
KeyAlgoRSASHA512,
KeyAlgoECDSA256,
KeyAlgoECDSA384,
KeyAlgoECDSA521,
KeyAlgoED25519,
}
// defaultHostKeyAlgos specifies the default preference for host-key
// algorithms in preference order.
defaultHostKeyAlgos = []string{
CertAlgoRSASHA256v01,
CertAlgoRSASHA512v01,
CertAlgoRSAv01,
InsecureCertAlgoDSAv01,
CertAlgoECDSA256v01,
CertAlgoECDSA384v01,
CertAlgoECDSA521v01,
CertAlgoED25519v01,
KeyAlgoECDSA256,
KeyAlgoECDSA384,
KeyAlgoECDSA521,
KeyAlgoRSASHA256,
KeyAlgoRSASHA512,
KeyAlgoRSA,
InsecureKeyAlgoDSA,
KeyAlgoED25519,
}
// insecureHostKeyAlgos specifies host-key algorithms implemented by this
// package and which have security issues.
insecureHostKeyAlgos = []string{
KeyAlgoRSA,
InsecureKeyAlgoDSA,
CertAlgoRSAv01,
InsecureCertAlgoDSAv01,
}
// supportedPubKeyAuthAlgos specifies the supported client public key
// authentication algorithms. Note that this doesn't include certificate
// types since those use the underlying algorithm. Order is irrelevant.
supportedPubKeyAuthAlgos = []string{
KeyAlgoED25519,
KeyAlgoSKED25519,
KeyAlgoSKECDSA256,
KeyAlgoECDSA256,
KeyAlgoECDSA384,
KeyAlgoECDSA521,
KeyAlgoRSASHA256,
KeyAlgoRSASHA512,
}
// defaultPubKeyAuthAlgos specifies the preferred client public key
// authentication algorithms. This list is sent to the client if it supports
// the server-sig-algs extension. Order is irrelevant.
defaultPubKeyAuthAlgos = []string{
KeyAlgoED25519,
KeyAlgoSKED25519,
KeyAlgoSKECDSA256,
KeyAlgoECDSA256,
KeyAlgoECDSA384,
KeyAlgoECDSA521,
KeyAlgoRSASHA256,
KeyAlgoRSASHA512,
KeyAlgoRSA,
InsecureKeyAlgoDSA,
}
// insecurePubKeyAuthAlgos specifies client public key authentication
// algorithms implemented by this package and which have security issues.
insecurePubKeyAuthAlgos = []string{
KeyAlgoRSA,
InsecureKeyAlgoDSA,
}
)
// NegotiatedAlgorithms defines algorithms negotiated between client and server.
type NegotiatedAlgorithms struct {
KeyExchange string
HostKey string
Read DirectionAlgorithms
Write DirectionAlgorithms
}
// Algorithms defines a set of algorithms that can be configured in the client
// or server config for negotiation during a handshake.
type Algorithms struct {
KeyExchanges []string
Ciphers []string
MACs []string
HostKeys []string
PublicKeyAuths []string
}
func init() {
if fips140.Enabled() {
defaultHostKeyAlgos = slices.DeleteFunc(defaultHostKeyAlgos, func(algo string) bool {
_, err := hashFunc(underlyingAlgo(algo))
return err != nil
})
defaultPubKeyAuthAlgos = slices.DeleteFunc(defaultPubKeyAuthAlgos, func(algo string) bool {
_, err := hashFunc(underlyingAlgo(algo))
return err != nil
})
}
}
func hashFunc(format string) (crypto.Hash, error) {
switch format {
case KeyAlgoRSASHA256, KeyAlgoECDSA256, KeyAlgoSKED25519, KeyAlgoSKECDSA256:
return crypto.SHA256, nil
case KeyAlgoECDSA384:
return crypto.SHA384, nil
case KeyAlgoRSASHA512, KeyAlgoECDSA521:
return crypto.SHA512, nil
case KeyAlgoED25519:
// KeyAlgoED25519 doesn't pre-hash.
return 0, nil
case KeyAlgoRSA, InsecureKeyAlgoDSA:
if fips140.Enabled() {
return 0, fmt.Errorf("ssh: hash algorithm for format %q not allowed in FIPS 140 mode", format)
}
return crypto.SHA1, nil
default:
return 0, fmt.Errorf("ssh: hash algorithm for format %q not mapped", format)
}
}
// SupportedAlgorithms returns algorithms currently implemented by this package,
// excluding those with security issues, which are returned by
// InsecureAlgorithms. The algorithms listed here are in preference order.
func SupportedAlgorithms() Algorithms {
return Algorithms{
Ciphers: slices.Clone(supportedCiphers),
MACs: slices.Clone(supportedMACs),
KeyExchanges: slices.Clone(supportedKexAlgos),
HostKeys: slices.Clone(supportedHostKeyAlgos),
PublicKeyAuths: slices.Clone(supportedPubKeyAuthAlgos),
}
}
// InsecureAlgorithms returns algorithms currently implemented by this package
// and which have security issues.
func InsecureAlgorithms() Algorithms {
return Algorithms{
KeyExchanges: slices.Clone(insecureKexAlgos),
Ciphers: slices.Clone(insecureCiphers),
MACs: slices.Clone(insecureMACs),
HostKeys: slices.Clone(insecureHostKeyAlgos),
PublicKeyAuths: slices.Clone(insecurePubKeyAuthAlgos),
}
}
var supportedCompressions = []string{compressionNone}
// algorithmsForKeyFormat returns the supported signature algorithms for a given
// public key format (PublicKey.Type), in order of preference. See RFC 8332,
// Section 2. See also the note in sendKexInit on backwards compatibility.
func algorithmsForKeyFormat(keyFormat string) []string {
switch keyFormat {
case KeyAlgoRSA:
return []string{KeyAlgoRSASHA256, KeyAlgoRSASHA512, KeyAlgoRSA}
case CertAlgoRSAv01:
return []string{CertAlgoRSASHA256v01, CertAlgoRSASHA512v01, CertAlgoRSAv01}
default:
return []string{keyFormat}
}
}
// keyFormatForAlgorithm returns the key format corresponding to the given
// signature algorithm. It returns an empty string if the signature algorithm is
// invalid or unsupported.
func keyFormatForAlgorithm(sigAlgo string) string {
switch sigAlgo {
case KeyAlgoRSA, KeyAlgoRSASHA256, KeyAlgoRSASHA512:
return KeyAlgoRSA
case CertAlgoRSAv01, CertAlgoRSASHA256v01, CertAlgoRSASHA512v01:
return CertAlgoRSAv01
case KeyAlgoED25519,
KeyAlgoSKED25519,
KeyAlgoSKECDSA256,
KeyAlgoECDSA256,
KeyAlgoECDSA384,
KeyAlgoECDSA521,
InsecureKeyAlgoDSA,
InsecureCertAlgoDSAv01,
CertAlgoECDSA256v01,
CertAlgoECDSA384v01,
CertAlgoECDSA521v01,
CertAlgoSKECDSA256v01,
CertAlgoED25519v01,
CertAlgoSKED25519v01:
return sigAlgo
default:
return ""
}
}
// isRSA returns whether algo is a supported RSA algorithm, including certificate
// algorithms.
func isRSA(algo string) bool {
algos := algorithmsForKeyFormat(KeyAlgoRSA)
return slices.Contains(algos, underlyingAlgo(algo))
}
func isRSACert(algo string) bool {
_, ok := certKeyAlgoNames[algo]
if !ok {
return false
}
return isRSA(algo)
}
// unexpectedMessageError results when the SSH message that we received didn't
// match what we wanted.
func unexpectedMessageError(expected, got uint8) error {
return fmt.Errorf("ssh: unexpected message type %d (expected %d)", got, expected)
}
// parseError results from a malformed SSH message.
func parseError(tag uint8) error {
return fmt.Errorf("ssh: parse error in message type %d", tag)
}
func findCommon(what string, client []string, server []string, isClient bool) (string, error) {
for _, c := range client {
for _, s := range server {
if c == s {
return c, nil
}
}
}
err := &AlgorithmNegotiationError{
What: what,
}
if isClient {
err.SupportedAlgorithms = client
err.RequestedAlgorithms = server
} else {
err.SupportedAlgorithms = server
err.RequestedAlgorithms = client
}
return "", err
}
// AlgorithmNegotiationError defines the error returned if the client and the
// server cannot agree on an algorithm for key exchange, host key, cipher, MAC.
type AlgorithmNegotiationError struct {
What string
// RequestedAlgorithms lists the algorithms supported by the peer.
RequestedAlgorithms []string
// SupportedAlgorithms lists the algorithms supported on our side.
SupportedAlgorithms []string
}
func (a *AlgorithmNegotiationError) Error() string {
return fmt.Sprintf("ssh: no common algorithm for %s; we offered: %v, peer offered: %v",
a.What, a.SupportedAlgorithms, a.RequestedAlgorithms)
}
// DirectionAlgorithms defines the algorithms negotiated in one direction
// (either read or write).
type DirectionAlgorithms struct {
Cipher string
MAC string
compression string
}
// rekeyBytes returns a rekeying intervals in bytes.
func (a *DirectionAlgorithms) rekeyBytes() int64 {
// According to RFC 4344 block ciphers should rekey after
// 2^(BLOCKSIZE/4) blocks. For all AES flavors BLOCKSIZE is
// 128.
switch a.Cipher {
case CipherAES128CTR, CipherAES192CTR, CipherAES256CTR, CipherAES128GCM, CipherAES256GCM, InsecureCipherAES128CBC:
return 16 * (1 << 32)
}
// For others, stick with RFC 4253 recommendation to rekey after 1 Gb of data.
return 1 << 30
}
var aeadCiphers = map[string]bool{
CipherAES128GCM: true,
CipherAES256GCM: true,
CipherChaCha20Poly1305: true,
}
func findAgreedAlgorithms(isClient bool, clientKexInit, serverKexInit *kexInitMsg) (algs *NegotiatedAlgorithms, err error) {
result := &NegotiatedAlgorithms{}
result.KeyExchange, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos, isClient)
if err != nil {
return
}
result.HostKey, err = findCommon("host key", clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos, isClient)
if err != nil {
return
}
stoc, ctos := &result.Write, &result.Read
if isClient {
ctos, stoc = stoc, ctos
}
ctos.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer, isClient)
if err != nil {
return
}
stoc.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient, isClient)
if err != nil {
return
}
if !aeadCiphers[ctos.Cipher] {
ctos.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer, isClient)
if err != nil {
return
}
}
if !aeadCiphers[stoc.Cipher] {
stoc.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient, isClient)
if err != nil {
return
}
}
ctos.compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer, isClient)
if err != nil {
return
}
stoc.compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient, isClient)
if err != nil {
return
}
return result, nil
}
// If rekeythreshold is too small, we can't make any progress sending
// stuff.
const minRekeyThreshold uint64 = 256
// Config contains configuration data common to both ServerConfig and
// ClientConfig.
type Config struct {
// Rand provides the source of entropy for cryptographic
// primitives. If Rand is nil, the cryptographic random reader
// in package crypto/rand will be used.
Rand io.Reader
// The maximum number of bytes sent or received after which a
// new key is negotiated. It must be at least 256. If
// unspecified, a size suitable for the chosen cipher is used.
RekeyThreshold uint64
// The allowed key exchanges algorithms. If unspecified then a default set
// of algorithms is used. Unsupported values are silently ignored.
KeyExchanges []string
// The allowed cipher algorithms. If unspecified then a sensible default is
// used. Unsupported values are silently ignored.
Ciphers []string
// The allowed MAC algorithms. If unspecified then a sensible default is
// used. Unsupported values are silently ignored.
MACs []string
}
// SetDefaults sets sensible values for unset fields in config. This is
// exported for testing: Configs passed to SSH functions are copied and have
// default values set automatically.
func (c *Config) SetDefaults() {
if c.Rand == nil {
c.Rand = rand.Reader
}
if c.Ciphers == nil {
c.Ciphers = defaultCiphers
}
var ciphers []string
for _, c := range c.Ciphers {
if cipherModes[c] != nil {
// Ignore the cipher if we have no cipherModes definition.
ciphers = append(ciphers, c)
}
}
c.Ciphers = ciphers
if c.KeyExchanges == nil {
c.KeyExchanges = defaultKexAlgos
}
var kexs []string
for _, k := range c.KeyExchanges {
if kexAlgoMap[k] != nil {
// Ignore the KEX if we have no kexAlgoMap definition.
kexs = append(kexs, k)
if k == KeyExchangeCurve25519 && !slices.Contains(c.KeyExchanges, keyExchangeCurve25519LibSSH) {
kexs = append(kexs, keyExchangeCurve25519LibSSH)
}
}
}
c.KeyExchanges = kexs
if c.MACs == nil {
c.MACs = defaultMACs
}
var macs []string
for _, m := range c.MACs {
if macModes[m] != nil {
// Ignore the MAC if we have no macModes definition.
macs = append(macs, m)
}
}
c.MACs = macs
if c.RekeyThreshold == 0 {
// cipher specific default
} else if c.RekeyThreshold < minRekeyThreshold {
c.RekeyThreshold = minRekeyThreshold
} else if c.RekeyThreshold >= math.MaxInt64 {
// Avoid weirdness if somebody uses -1 as a threshold.
c.RekeyThreshold = math.MaxInt64
}
}
// buildDataSignedForAuth returns the data that is signed in order to prove
// possession of a private key. See RFC 4252, section 7. algo is the advertised
// algorithm, and may be a certificate type.
func buildDataSignedForAuth(sessionID []byte, req userAuthRequestMsg, algo string, pubKey []byte) []byte {
data := struct {
Session []byte
Type byte
User string
Service string
Method string
Sign bool
Algo string
PubKey []byte
}{
sessionID,
msgUserAuthRequest,
req.User,
req.Service,
req.Method,
true,
algo,
pubKey,
}
return Marshal(data)
}
func appendU16(buf []byte, n uint16) []byte {
return append(buf, byte(n>>8), byte(n))
}
func appendU32(buf []byte, n uint32) []byte {
return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
}
func appendU64(buf []byte, n uint64) []byte {
return append(buf,
byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32),
byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
}
func appendInt(buf []byte, n int) []byte {
return appendU32(buf, uint32(n))
}
func appendString(buf []byte, s string) []byte {
buf = appendU32(buf, uint32(len(s)))
buf = append(buf, s...)
return buf
}
func appendBool(buf []byte, b bool) []byte {
if b {
return append(buf, 1)
}
return append(buf, 0)
}
// newCond is a helper to hide the fact that there is no usable zero
// value for sync.Cond.
func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) }
// window represents the buffer available to clients
// wishing to write to a channel.
type window struct {
*sync.Cond
win uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1
writeWaiters int
closed bool
}
// add adds win to the amount of window available
// for consumers.
func (w *window) add(win uint32) bool {
// a zero sized window adjust is a noop.
if win == 0 {
return true
}
w.L.Lock()
if w.win+win < win {
w.L.Unlock()
return false
}
w.win += win
// It is unusual that multiple goroutines would be attempting to reserve
// window space, but not guaranteed. Use broadcast to notify all waiters
// that additional window is available.
w.Broadcast()
w.L.Unlock()
return true
}
// close sets the window to closed, so all reservations fail
// immediately.
func (w *window) close() {
w.L.Lock()
w.closed = true
w.Broadcast()
w.L.Unlock()
}
// reserve reserves win from the available window capacity.
// If no capacity remains, reserve will block. reserve may
// return less than requested.
func (w *window) reserve(win uint32) (uint32, error) {
var err error
w.L.Lock()
w.writeWaiters++
w.Broadcast()
for w.win == 0 && !w.closed {
w.Wait()
}
w.writeWaiters--
if w.win < win {
win = w.win
}
w.win -= win
if w.closed {
err = io.EOF
}
w.L.Unlock()
return win, err
}
// waitWriterBlocked waits until some goroutine is blocked for further
// writes. It is used in tests only.
func (w *window) waitWriterBlocked() {
w.Cond.L.Lock()
for w.writeWaiters == 0 {
w.Cond.Wait()
}
w.Cond.L.Unlock()
}
// Copyright 2013 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 ssh
import (
"fmt"
"net"
)
// OpenChannelError is returned if the other side rejects an
// OpenChannel request.
type OpenChannelError struct {
Reason RejectionReason
Message string
}
func (e *OpenChannelError) Error() string {
return fmt.Sprintf("ssh: rejected: %s (%s)", e.Reason, e.Message)
}
// ConnMetadata holds metadata for the connection.
type ConnMetadata interface {
// User returns the user ID for this connection.
User() string
// SessionID returns the session hash, also denoted by H.
SessionID() []byte
// ClientVersion returns the client's version string as hashed
// into the session ID.
ClientVersion() []byte
// ServerVersion returns the server's version string as hashed
// into the session ID.
ServerVersion() []byte
// RemoteAddr returns the remote address for this connection.
RemoteAddr() net.Addr
// LocalAddr returns the local address for this connection.
LocalAddr() net.Addr
}
// Conn represents an SSH connection for both server and client roles.
// Conn is the basis for implementing an application layer, such
// as ClientConn, which implements the traditional shell access for
// clients.
type Conn interface {
ConnMetadata
// SendRequest sends a global request, and returns the
// reply. If wantReply is true, it returns the response status
// and payload. See also RFC 4254, section 4.
SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error)
// OpenChannel tries to open an channel. If the request is
// rejected, it returns *OpenChannelError. On success it returns
// the SSH Channel and a Go channel for incoming, out-of-band
// requests. The Go channel must be serviced, or the
// connection will hang.
OpenChannel(name string, data []byte) (Channel, <-chan *Request, error)
// Close closes the underlying network connection
Close() error
// Wait blocks until the connection has shut down, and returns the
// error causing the shutdown.
Wait() error
// TODO(hanwen): consider exposing:
// RequestKeyChange
// Disconnect
}
// AlgorithmsConnMetadata is a ConnMetadata that can return the algorithms
// negotiated between client and server.
type AlgorithmsConnMetadata interface {
ConnMetadata
Algorithms() NegotiatedAlgorithms
}
// DiscardRequests consumes and rejects all requests from the
// passed-in channel.
func DiscardRequests(in <-chan *Request) {
for req := range in {
if req.WantReply {
req.Reply(false, nil)
}
}
}
// A connection represents an incoming connection.
type connection struct {
transport *handshakeTransport
sshConn
// The connection protocol.
*mux
}
func (c *connection) Close() error {
return c.sshConn.conn.Close()
}
// sshConn provides net.Conn metadata, but disallows direct reads and
// writes.
type sshConn struct {
conn net.Conn
user string
sessionID []byte
clientVersion []byte
serverVersion []byte
algorithms NegotiatedAlgorithms
}
func dup(src []byte) []byte {
dst := make([]byte, len(src))
copy(dst, src)
return dst
}
func (c *sshConn) User() string {
return c.user
}
func (c *sshConn) RemoteAddr() net.Addr {
return c.conn.RemoteAddr()
}
func (c *sshConn) Close() error {
return c.conn.Close()
}
func (c *sshConn) LocalAddr() net.Addr {
return c.conn.LocalAddr()
}
func (c *sshConn) SessionID() []byte {
return dup(c.sessionID)
}
func (c *sshConn) ClientVersion() []byte {
return dup(c.clientVersion)
}
func (c *sshConn) ServerVersion() []byte {
return dup(c.serverVersion)
}
func (c *sshConn) Algorithms() NegotiatedAlgorithms {
return c.algorithms
}
// Copyright 2013 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 ssh
import (
"errors"
"fmt"
"io"
"log"
"net"
"slices"
"strings"
"sync"
)
// debugHandshake, if set, prints messages sent and received. Key
// exchange messages are printed as if DH were used, so the debug
// messages are wrong when using ECDH.
const debugHandshake = false
// chanSize sets the amount of buffering SSH connections. This is
// primarily for testing: setting chanSize=0 uncovers deadlocks more
// quickly.
const chanSize = 16
// maxPendingPackets sets the maximum number of packets to queue while waiting
// for KEX to complete. This limits the total pending data to maxPendingPackets
// * maxPacket bytes, which is ~16.8MB.
const maxPendingPackets = 64
// keyingTransport is a packet based transport that supports key
// changes. It need not be thread-safe. It should pass through
// msgNewKeys in both directions.
type keyingTransport interface {
packetConn
// prepareKeyChange sets up a key change. The key change for a
// direction will be effected if a msgNewKeys message is sent
// or received.
prepareKeyChange(*NegotiatedAlgorithms, *kexResult) error
// setStrictMode sets the strict KEX mode, notably triggering
// sequence number resets on sending or receiving msgNewKeys.
// If the sequence number is already > 1 when setStrictMode
// is called, an error is returned.
setStrictMode() error
// setInitialKEXDone indicates to the transport that the initial key exchange
// was completed
setInitialKEXDone()
}
// handshakeTransport implements rekeying on top of a keyingTransport
// and offers a thread-safe writePacket() interface.
type handshakeTransport struct {
conn keyingTransport
config *Config
serverVersion []byte
clientVersion []byte
// hostKeys is non-empty if we are the server. In that case,
// it contains all host keys that can be used to sign the
// connection.
hostKeys []Signer
// publicKeyAuthAlgorithms is non-empty if we are the server. In that case,
// it contains the supported client public key authentication algorithms.
publicKeyAuthAlgorithms []string
// hostKeyAlgorithms is non-empty if we are the client. In that case,
// we accept these key types from the server as host key.
hostKeyAlgorithms []string
// On read error, incoming is closed, and readError is set.
incoming chan []byte
readError error
mu sync.Mutex
// Condition for the above mutex. It is used to notify a completed key
// exchange or a write failure. Writes can wait for this condition while a
// key exchange is in progress.
writeCond *sync.Cond
writeError error
sentInitPacket []byte
sentInitMsg *kexInitMsg
// Used to queue writes when a key exchange is in progress. The length is
// limited by pendingPacketsSize. Once full, writes will block until the key
// exchange is completed or an error occurs. If not empty, it is emptied
// all at once when the key exchange is completed in kexLoop.
pendingPackets [][]byte
writePacketsLeft uint32
writeBytesLeft int64
userAuthComplete bool // whether the user authentication phase is complete
// If the read loop wants to schedule a kex, it pings this
// channel, and the write loop will send out a kex
// 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.
startKex chan *pendingKex
kexLoopDone chan struct{} // closed (with writeError non-nil) when kexLoop exits
// data for host key checking
hostKeyCallback HostKeyCallback
dialAddress string
remoteAddr net.Addr
// bannerCallback is non-empty if we are the client and it has been set in
// ClientConfig. In that case it is called during the user authentication
// dance to handle a custom server's message.
bannerCallback BannerCallback
// Algorithms agreed in the last key exchange.
algorithms *NegotiatedAlgorithms
// Counters exclusively owned by readLoop.
readPacketsLeft uint32
readBytesLeft int64
// The session ID or nil if first kex did not complete yet.
sessionID []byte
// strictMode indicates if the other side of the handshake indicated
// that we should be following the strict KEX protocol restrictions.
strictMode bool
}
type pendingKex struct {
otherInit []byte
done chan error
}
func newHandshakeTransport(conn keyingTransport, config *Config, clientVersion, serverVersion []byte) *handshakeTransport {
t := &handshakeTransport{
conn: conn,
serverVersion: serverVersion,
clientVersion: clientVersion,
incoming: make(chan []byte, chanSize),
requestKex: make(chan struct{}, 1),
startKex: make(chan *pendingKex),
kexLoopDone: make(chan struct{}),
config: config,
}
t.writeCond = sync.NewCond(&t.mu)
t.resetReadThresholds()
t.resetWriteThresholds()
// We always start with a mandatory key exchange.
t.requestKex <- struct{}{}
return t
}
func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ClientConfig, dialAddr string, addr net.Addr) *handshakeTransport {
t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion)
t.dialAddress = dialAddr
t.remoteAddr = addr
t.hostKeyCallback = config.HostKeyCallback
t.bannerCallback = config.BannerCallback
if config.HostKeyAlgorithms != nil {
t.hostKeyAlgorithms = config.HostKeyAlgorithms
} else {
t.hostKeyAlgorithms = defaultHostKeyAlgos
}
go t.readLoop()
go t.kexLoop()
return t
}
func newServerTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ServerConfig) *handshakeTransport {
t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion)
t.hostKeys = config.hostKeys
t.publicKeyAuthAlgorithms = config.PublicKeyAuthAlgorithms
go t.readLoop()
go t.kexLoop()
return t
}
func (t *handshakeTransport) getSessionID() []byte {
return t.sessionID
}
func (t *handshakeTransport) getAlgorithms() NegotiatedAlgorithms {
return *t.algorithms
}
// waitSession waits for the session to be established. This should be
// the first thing to call after instantiating handshakeTransport.
func (t *handshakeTransport) waitSession() error {
p, err := t.readPacket()
if err != nil {
return err
}
if p[0] != msgNewKeys {
return fmt.Errorf("ssh: first packet should be msgNewKeys")
}
return nil
}
func (t *handshakeTransport) id() string {
if len(t.hostKeys) > 0 {
return "server"
}
return "client"
}
func (t *handshakeTransport) printPacket(p []byte, write bool) {
action := "got"
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 {
msg, err := decode(p)
log.Printf("%s %s %T %v (%v)", t.id(), action, msg, msg, err)
}
}
func (t *handshakeTransport) readPacket() ([]byte, error) {
p, ok := <-t.incoming
if !ok {
return nil, t.readError
}
return p, nil
}
func (t *handshakeTransport) readLoop() {
first := true
for {
p, err := t.readOnePacket(first)
first = false
if err != nil {
t.readError = err
close(t.incoming)
break
}
// If this is the first kex, and strict KEX mode is enabled,
// we don't ignore any messages, as they may be used to manipulate
// the packet sequence numbers.
if !(t.sessionID == nil && t.strictMode) && (p[0] == msgIgnore || p[0] == msgDebug) {
continue
}
t.incoming <- p
}
// Stop writers too.
t.recordWriteError(t.readError)
// Unblock the writer should it wait for this.
close(t.startKex)
// Don't close t.requestKex; it's also written to from writePacket.
}
func (t *handshakeTransport) pushPacket(p []byte) error {
if debugHandshake {
t.printPacket(p, true)
}
return t.conn.writePacket(p)
}
func (t *handshakeTransport) getWriteError() error {
t.mu.Lock()
defer t.mu.Unlock()
return t.writeError
}
func (t *handshakeTransport) recordWriteError(err error) {
t.mu.Lock()
defer t.mu.Unlock()
if t.writeError == nil && err != nil {
t.writeError = err
t.writeCond.Broadcast()
}
}
func (t *handshakeTransport) requestKeyExchange() {
select {
case t.requestKex <- struct{}{}:
default:
// something already requested a kex, so do nothing.
}
}
func (t *handshakeTransport) resetWriteThresholds() {
t.writePacketsLeft = packetRekeyThreshold
if t.config.RekeyThreshold > 0 {
t.writeBytesLeft = int64(t.config.RekeyThreshold)
} else if t.algorithms != nil {
t.writeBytesLeft = t.algorithms.Write.rekeyBytes()
} else {
t.writeBytesLeft = 1 << 30
}
}
func (t *handshakeTransport) kexLoop() {
write:
for t.getWriteError() == nil {
var request *pendingKex
var sent bool
for request == nil || !sent {
var ok bool
select {
case request, ok = <-t.startKex:
if !ok {
break write
}
case <-t.requestKex:
break
}
if !sent {
if err := t.sendKexInit(); err != nil {
t.recordWriteError(err)
break
}
sent = true
}
}
if err := t.getWriteError(); err != nil {
if request != nil {
request.done <- err
}
break
}
// We're not servicing t.requestKex, but that is OK:
// we never block on sending to t.requestKex.
// 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, until we close the done
// channel on the pendingKex request.
err := t.enterKeyExchange(request.otherInit)
t.mu.Lock()
t.writeError = err
t.sentInitPacket = nil
t.sentInitMsg = nil
t.resetWriteThresholds()
// 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
// the kex was in progress. Don't look at t.startKex
// and don't increment writtenSinceKex: if we trigger
// another kex while we are still busy with the last
// one, things will become very confusing.
for _, p := range t.pendingPackets {
t.writeError = t.pushPacket(p)
if t.writeError != nil {
break
}
}
t.pendingPackets = t.pendingPackets[:0]
// Unblock writePacket if waiting for KEX.
t.writeCond.Broadcast()
t.mu.Unlock()
}
// Unblock reader.
t.conn.Close()
// drain startKex channel. We don't service t.requestKex
// because nobody does blocking sends there.
for request := range t.startKex {
request.done <- t.getWriteError()
}
// Mark that the loop is done so that Close can return.
close(t.kexLoopDone)
}
// The protocol uses uint32 for packet counters, so we can't let them
// reach 1<<32. We will actually read and write more packets than
// this, though: the other side may send more packets, and after we
// hit this limit on writing we will send a few more packets for the
// key exchange itself.
const packetRekeyThreshold = (1 << 31)
func (t *handshakeTransport) resetReadThresholds() {
t.readPacketsLeft = packetRekeyThreshold
if t.config.RekeyThreshold > 0 {
t.readBytesLeft = int64(t.config.RekeyThreshold)
} else if t.algorithms != nil {
t.readBytesLeft = t.algorithms.Read.rekeyBytes()
} else {
t.readBytesLeft = 1 << 30
}
}
func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) {
p, err := t.conn.readPacket()
if err != nil {
return nil, err
}
if t.readPacketsLeft > 0 {
t.readPacketsLeft--
} else {
t.requestKeyExchange()
}
if t.readBytesLeft > 0 {
t.readBytesLeft -= int64(len(p))
} else {
t.requestKeyExchange()
}
if debugHandshake {
t.printPacket(p, false)
}
if first && p[0] != msgKexInit {
return nil, fmt.Errorf("ssh: first packet should be msgKexInit")
}
if p[0] != msgKexInit {
return p, nil
}
firstKex := t.sessionID == nil
kex := pendingKex{
done: make(chan error, 1),
otherInit: p,
}
t.startKex <- &kex
err = <-kex.done
if debugHandshake {
log.Printf("%s exited key exchange (first %v), err %v", t.id(), firstKex, err)
}
if err != nil {
return nil, err
}
t.resetReadThresholds()
// By default, a key exchange is hidden from higher layers by
// translating it into msgIgnore.
successPacket := []byte{msgIgnore}
if firstKex {
// sendKexInit() for the first kex waits for
// msgNewKeys so the authentication process is
// guaranteed to happen over an encrypted transport.
successPacket = []byte{msgNewKeys}
}
return successPacket, nil
}
const (
kexStrictClient = "kex-strict-c-v00@openssh.com"
kexStrictServer = "kex-strict-s-v00@openssh.com"
)
// sendKexInit sends a key change message.
func (t *handshakeTransport) sendKexInit() error {
t.mu.Lock()
defer t.mu.Unlock()
if t.sentInitMsg != nil {
// kexInits may be sent either in response to the other side,
// or because our side wants to initiate a key change, so we
// may have already sent a kexInit. In that case, don't send a
// second kexInit.
return nil
}
msg := &kexInitMsg{
CiphersClientServer: t.config.Ciphers,
CiphersServerClient: t.config.Ciphers,
MACsClientServer: t.config.MACs,
MACsServerClient: t.config.MACs,
CompressionClientServer: supportedCompressions,
CompressionServerClient: supportedCompressions,
}
io.ReadFull(t.config.Rand, msg.Cookie[:])
// We mutate the KexAlgos slice, in order to add the kex-strict extension algorithm,
// and possibly to add the ext-info extension algorithm. Since the slice may be the
// user owned KeyExchanges, we create our own slice in order to avoid using user
// owned memory by mistake.
msg.KexAlgos = make([]string, 0, len(t.config.KeyExchanges)+2) // room for kex-strict and ext-info
msg.KexAlgos = append(msg.KexAlgos, t.config.KeyExchanges...)
isServer := len(t.hostKeys) > 0
if isServer {
for _, k := range t.hostKeys {
// If k is a MultiAlgorithmSigner, we restrict the signature
// algorithms. If k is a AlgorithmSigner, presume it supports all
// signature algorithms associated with the key format. If k is not
// an AlgorithmSigner, we can only assume it only supports the
// algorithms that matches the key format. (This means that Sign
// can't pick a different default).
keyFormat := k.PublicKey().Type()
switch s := k.(type) {
case MultiAlgorithmSigner:
for _, algo := range algorithmsForKeyFormat(keyFormat) {
if slices.Contains(s.Algorithms(), underlyingAlgo(algo)) {
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algo)
}
}
case AlgorithmSigner:
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algorithmsForKeyFormat(keyFormat)...)
default:
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, keyFormat)
}
}
if t.sessionID == nil {
msg.KexAlgos = append(msg.KexAlgos, kexStrictServer)
}
} else {
msg.ServerHostKeyAlgos = t.hostKeyAlgorithms
// As a client we opt in to receiving SSH_MSG_EXT_INFO so we know what
// algorithms the server supports for public key authentication. See RFC
// 8308, Section 2.1.
//
// We also send the strict KEX mode extension algorithm, in order to opt
// into the strict KEX mode.
if firstKeyExchange := t.sessionID == nil; firstKeyExchange {
msg.KexAlgos = append(msg.KexAlgos, "ext-info-c")
msg.KexAlgos = append(msg.KexAlgos, kexStrictClient)
}
}
packet := Marshal(msg)
// writePacket destroys the contents, so save a copy.
packetCopy := make([]byte, len(packet))
copy(packetCopy, packet)
if err := t.pushPacket(packetCopy); err != nil {
return err
}
t.sentInitMsg = msg
t.sentInitPacket = packet
return nil
}
var errSendBannerPhase = errors.New("ssh: SendAuthBanner outside of authentication phase")
func (t *handshakeTransport) writePacket(p []byte) error {
t.mu.Lock()
defer t.mu.Unlock()
switch p[0] {
case msgKexInit:
return errors.New("ssh: only handshakeTransport can send kexInit")
case msgNewKeys:
return errors.New("ssh: only handshakeTransport can send newKeys")
case msgUserAuthBanner:
if t.userAuthComplete {
return errSendBannerPhase
}
case msgUserAuthSuccess:
t.userAuthComplete = true
}
if t.writeError != nil {
return t.writeError
}
if t.sentInitMsg != nil {
if len(t.pendingPackets) < maxPendingPackets {
// Copy the packet so the writer can reuse the buffer.
cp := make([]byte, len(p))
copy(cp, p)
t.pendingPackets = append(t.pendingPackets, cp)
return nil
}
for t.sentInitMsg != nil {
// Block and wait for KEX to complete or an error.
t.writeCond.Wait()
if t.writeError != nil {
return t.writeError
}
}
}
if t.writeBytesLeft > 0 {
t.writeBytesLeft -= int64(len(p))
} else {
t.requestKeyExchange()
}
if t.writePacketsLeft > 0 {
t.writePacketsLeft--
} else {
t.requestKeyExchange()
}
if err := t.pushPacket(p); err != nil {
t.writeError = err
t.writeCond.Broadcast()
}
return nil
}
func (t *handshakeTransport) Close() error {
// Close the connection. This should cause the readLoop goroutine to wake up
// and close t.startKex, which will shut down kexLoop if running.
err := t.conn.Close()
// Wait for the kexLoop goroutine to complete.
// At that point we know that the readLoop goroutine is complete too,
// because kexLoop itself waits for readLoop to close the startKex channel.
<-t.kexLoopDone
return err
}
func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
if debugHandshake {
log.Printf("%s entered key exchange", t.id())
}
otherInit := &kexInitMsg{}
if err := Unmarshal(otherInitPacket, otherInit); err != nil {
return err
}
magics := handshakeMagics{
clientVersion: t.clientVersion,
serverVersion: t.serverVersion,
clientKexInit: otherInitPacket,
serverKexInit: t.sentInitPacket,
}
clientInit := otherInit
serverInit := t.sentInitMsg
isClient := len(t.hostKeys) == 0
if isClient {
clientInit, serverInit = serverInit, clientInit
magics.clientKexInit = t.sentInitPacket
magics.serverKexInit = otherInitPacket
}
var err error
t.algorithms, err = findAgreedAlgorithms(isClient, clientInit, serverInit)
if err != nil {
return err
}
if t.sessionID == nil && ((isClient && slices.Contains(serverInit.KexAlgos, kexStrictServer)) || (!isClient && slices.Contains(clientInit.KexAlgos, kexStrictClient))) {
t.strictMode = true
if err := t.conn.setStrictMode(); err != nil {
return err
}
}
// We don't send FirstKexFollows, but we handle receiving it.
//
// RFC 4253 section 7 defines the kex and the agreement method for
// first_kex_packet_follows. It states that the guessed packet
// should be ignored if the "kex algorithm and/or the host
// key algorithm is guessed wrong (server and client have
// different preferred algorithm), or if any of the other
// algorithms cannot be agreed upon". The other algorithms have
// already been checked above so the kex algorithm and host key
// algorithm are checked here.
if otherInit.FirstKexFollows && (clientInit.KexAlgos[0] != serverInit.KexAlgos[0] || clientInit.ServerHostKeyAlgos[0] != serverInit.ServerHostKeyAlgos[0]) {
// other side sent a kex message for the wrong algorithm,
// which we have to ignore.
if _, err := t.conn.readPacket(); err != nil {
return err
}
}
kex, ok := kexAlgoMap[t.algorithms.KeyExchange]
if !ok {
return fmt.Errorf("ssh: unexpected key exchange algorithm %v", t.algorithms.KeyExchange)
}
var result *kexResult
if len(t.hostKeys) > 0 {
result, err = t.server(kex, &magics)
} else {
result, err = t.client(kex, &magics)
}
if err != nil {
return err
}
firstKeyExchange := t.sessionID == nil
if firstKeyExchange {
t.sessionID = result.H
}
result.SessionID = t.sessionID
if err := t.conn.prepareKeyChange(t.algorithms, result); err != nil {
return err
}
if err = t.conn.writePacket([]byte{msgNewKeys}); err != nil {
return err
}
// On the server side, after the first SSH_MSG_NEWKEYS, send a SSH_MSG_EXT_INFO
// message with the server-sig-algs extension if the client supports it. See
// RFC 8308, Sections 2.4 and 3.1, and [PROTOCOL], Section 1.9.
if !isClient && firstKeyExchange && slices.Contains(clientInit.KexAlgos, "ext-info-c") {
supportedPubKeyAuthAlgosList := strings.Join(t.publicKeyAuthAlgorithms, ",")
extInfo := &extInfoMsg{
NumExtensions: 2,
Payload: make([]byte, 0, 4+15+4+len(supportedPubKeyAuthAlgosList)+4+16+4+1),
}
extInfo.Payload = appendInt(extInfo.Payload, len("server-sig-algs"))
extInfo.Payload = append(extInfo.Payload, "server-sig-algs"...)
extInfo.Payload = appendInt(extInfo.Payload, len(supportedPubKeyAuthAlgosList))
extInfo.Payload = append(extInfo.Payload, supportedPubKeyAuthAlgosList...)
extInfo.Payload = appendInt(extInfo.Payload, len("ping@openssh.com"))
extInfo.Payload = append(extInfo.Payload, "ping@openssh.com"...)
extInfo.Payload = appendInt(extInfo.Payload, 1)
extInfo.Payload = append(extInfo.Payload, "0"...)
if err := t.conn.writePacket(Marshal(extInfo)); err != nil {
return err
}
}
if packet, err := t.conn.readPacket(); err != nil {
return err
} else if packet[0] != msgNewKeys {
return unexpectedMessageError(msgNewKeys, packet[0])
}
if firstKeyExchange {
// Indicates to the transport that the first key exchange is completed
// after receiving SSH_MSG_NEWKEYS.
t.conn.setInitialKEXDone()
}
return nil
}
// algorithmSignerWrapper is an AlgorithmSigner that only supports the default
// key format algorithm.
//
// This is technically a violation of the AlgorithmSigner interface, but it
// should be unreachable given where we use this. Anyway, at least it returns an
// error instead of panicing or producing an incorrect signature.
type algorithmSignerWrapper struct {
Signer
}
func (a algorithmSignerWrapper) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
if algorithm != underlyingAlgo(a.PublicKey().Type()) {
return nil, errors.New("ssh: internal error: algorithmSignerWrapper invoked with non-default algorithm")
}
return a.Sign(rand, data)
}
func pickHostKey(hostKeys []Signer, algo string) AlgorithmSigner {
for _, k := range hostKeys {
if s, ok := k.(MultiAlgorithmSigner); ok {
if !slices.Contains(s.Algorithms(), underlyingAlgo(algo)) {
continue
}
}
if algo == k.PublicKey().Type() {
return algorithmSignerWrapper{k}
}
k, ok := k.(AlgorithmSigner)
if !ok {
continue
}
for _, a := range algorithmsForKeyFormat(k.PublicKey().Type()) {
if algo == a {
return k
}
}
}
return nil
}
func (t *handshakeTransport) server(kex kexAlgorithm, magics *handshakeMagics) (*kexResult, error) {
hostKey := pickHostKey(t.hostKeys, t.algorithms.HostKey)
if hostKey == nil {
return nil, errors.New("ssh: internal error: negotiated unsupported signature type")
}
r, err := kex.Server(t.conn, t.config.Rand, magics, hostKey, t.algorithms.HostKey)
return r, err
}
func (t *handshakeTransport) client(kex kexAlgorithm, magics *handshakeMagics) (*kexResult, error) {
result, err := kex.Client(t.conn, t.config.Rand, magics)
if err != nil {
return nil, err
}
hostKey, err := ParsePublicKey(result.HostKey)
if err != nil {
return nil, err
}
if err := verifyHostKeySignature(hostKey, t.algorithms.HostKey, result); err != nil {
return nil, err
}
err = t.hostKeyCallback(t.dialAddress, t.remoteAddr, hostKey)
if err != nil {
return nil, err
}
return result, nil
}
// 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 bcrypt_pbkdf implements bcrypt_pbkdf(3) from OpenBSD.
//
// See https://flak.tedunangst.com/post/bcrypt-pbkdf and
// https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libutil/bcrypt_pbkdf.c.
package bcrypt_pbkdf
import (
"crypto/sha512"
"errors"
"golang.org/x/crypto/blowfish"
)
const blockSize = 32
// Key derives a key from the password, salt and rounds count, returning a
// []byte of length keyLen that can be used as cryptographic key.
func Key(password, salt []byte, rounds, keyLen int) ([]byte, error) {
if rounds < 1 {
return nil, errors.New("bcrypt_pbkdf: number of rounds is too small")
}
if len(password) == 0 {
return nil, errors.New("bcrypt_pbkdf: empty password")
}
if len(salt) == 0 || len(salt) > 1<<20 {
return nil, errors.New("bcrypt_pbkdf: bad salt length")
}
if keyLen > 1024 {
return nil, errors.New("bcrypt_pbkdf: keyLen is too large")
}
numBlocks := (keyLen + blockSize - 1) / blockSize
key := make([]byte, numBlocks*blockSize)
h := sha512.New()
h.Write(password)
shapass := h.Sum(nil)
shasalt := make([]byte, 0, sha512.Size)
cnt, tmp := make([]byte, 4), make([]byte, blockSize)
for block := 1; block <= numBlocks; block++ {
h.Reset()
h.Write(salt)
cnt[0] = byte(block >> 24)
cnt[1] = byte(block >> 16)
cnt[2] = byte(block >> 8)
cnt[3] = byte(block)
h.Write(cnt)
bcryptHash(tmp, shapass, h.Sum(shasalt))
out := make([]byte, blockSize)
copy(out, tmp)
for i := 2; i <= rounds; i++ {
h.Reset()
h.Write(tmp)
bcryptHash(tmp, shapass, h.Sum(shasalt))
for j := 0; j < len(out); j++ {
out[j] ^= tmp[j]
}
}
for i, v := range out {
key[i*numBlocks+(block-1)] = v
}
}
return key[:keyLen], nil
}
var magic = []byte("OxychromaticBlowfishSwatDynamite")
func bcryptHash(out, shapass, shasalt []byte) {
c, err := blowfish.NewSaltedCipher(shapass, shasalt)
if err != nil {
panic(err)
}
for i := 0; i < 64; i++ {
blowfish.ExpandKey(shasalt, c)
blowfish.ExpandKey(shapass, c)
}
copy(out, magic)
for i := 0; i < 32; i += 8 {
for j := 0; j < 64; j++ {
c.Encrypt(out[i:i+8], out[i:i+8])
}
}
// Swap bytes due to different endianness.
for i := 0; i < 32; i += 4 {
out[i+3], out[i+2], out[i+1], out[i] = out[i], out[i+1], out[i+2], out[i+3]
}
}
// Copyright 2013 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 ssh
import (
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/fips140"
"crypto/rand"
"encoding/binary"
"errors"
"fmt"
"io"
"math/big"
"slices"
"golang.org/x/crypto/curve25519"
)
const (
// This is the group called diffie-hellman-group1-sha1 in RFC 4253 and
// Oakley Group 2 in RFC 2409.
oakleyGroup2 = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
// This is the group called diffie-hellman-group14-sha1 in RFC 4253 and
// Oakley Group 14 in RFC 3526.
oakleyGroup14 = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF"
// This is the group called diffie-hellman-group15-sha512 in RFC 8268 and
// Oakley Group 15 in RFC 3526.
oakleyGroup15 = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF"
// This is the group called diffie-hellman-group16-sha512 in RFC 8268 and
// Oakley Group 16 in RFC 3526.
oakleyGroup16 = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF"
)
// kexResult captures the outcome of a key exchange.
type kexResult struct {
// Session hash. See also RFC 4253, section 8.
H []byte
// Shared secret. See also RFC 4253, section 8.
K []byte
// Host key as hashed into H.
HostKey []byte
// Signature of H.
Signature []byte
// A cryptographic hash function that matches the security
// level of the key exchange algorithm. It is used for
// calculating H, and for deriving keys from H and K.
Hash crypto.Hash
// The session ID, which is the first H computed. This is used
// to derive key material inside the transport.
SessionID []byte
}
// handshakeMagics contains data that is always included in the
// session hash.
type handshakeMagics struct {
clientVersion, serverVersion []byte
clientKexInit, serverKexInit []byte
}
func (m *handshakeMagics) write(w io.Writer) {
writeString(w, m.clientVersion)
writeString(w, m.serverVersion)
writeString(w, m.clientKexInit)
writeString(w, m.serverKexInit)
}
// kexAlgorithm abstracts different key exchange algorithms.
type kexAlgorithm interface {
// Server runs server-side key agreement, signing the result
// with a hostkey. algo is the negotiated algorithm, and may
// be a certificate type.
Server(p packetConn, rand io.Reader, magics *handshakeMagics, s AlgorithmSigner, algo string) (*kexResult, error)
// Client runs the client-side key agreement. Caller is
// responsible for verifying the host key signature.
Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error)
}
// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
type dhGroup struct {
g, p, pMinus1 *big.Int
hashFunc crypto.Hash
}
func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) {
if theirPublic.Cmp(bigOne) <= 0 || theirPublic.Cmp(group.pMinus1) >= 0 {
return nil, errors.New("ssh: DH parameter out of bounds")
}
return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil
}
func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
var x *big.Int
for {
var err error
if x, err = rand.Int(randSource, group.pMinus1); err != nil {
return nil, err
}
if x.Sign() > 0 {
break
}
}
X := new(big.Int).Exp(group.g, x, group.p)
kexDHInit := kexDHInitMsg{
X: X,
}
if err := c.writePacket(Marshal(&kexDHInit)); err != nil {
return nil, err
}
packet, err := c.readPacket()
if err != nil {
return nil, err
}
var kexDHReply kexDHReplyMsg
if err = Unmarshal(packet, &kexDHReply); err != nil {
return nil, err
}
ki, err := group.diffieHellman(kexDHReply.Y, x)
if err != nil {
return nil, err
}
h := group.hashFunc.New()
magics.write(h)
writeString(h, kexDHReply.HostKey)
writeInt(h, X)
writeInt(h, kexDHReply.Y)
K := make([]byte, intLength(ki))
marshalInt(K, ki)
h.Write(K)
return &kexResult{
H: h.Sum(nil),
K: K,
HostKey: kexDHReply.HostKey,
Signature: kexDHReply.Signature,
Hash: group.hashFunc,
}, nil
}
func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
packet, err := c.readPacket()
if err != nil {
return
}
var kexDHInit kexDHInitMsg
if err = Unmarshal(packet, &kexDHInit); err != nil {
return
}
var y *big.Int
for {
if y, err = rand.Int(randSource, group.pMinus1); err != nil {
return
}
if y.Sign() > 0 {
break
}
}
Y := new(big.Int).Exp(group.g, y, group.p)
ki, err := group.diffieHellman(kexDHInit.X, y)
if err != nil {
return nil, err
}
hostKeyBytes := priv.PublicKey().Marshal()
h := group.hashFunc.New()
magics.write(h)
writeString(h, hostKeyBytes)
writeInt(h, kexDHInit.X)
writeInt(h, Y)
K := make([]byte, intLength(ki))
marshalInt(K, ki)
h.Write(K)
H := h.Sum(nil)
// H is already a hash, but the hostkey signing will apply its
// own key-specific hash algorithm.
sig, err := signAndMarshal(priv, randSource, H, algo)
if err != nil {
return nil, err
}
kexDHReply := kexDHReplyMsg{
HostKey: hostKeyBytes,
Y: Y,
Signature: sig,
}
packet = Marshal(&kexDHReply)
err = c.writePacket(packet)
return &kexResult{
H: H,
K: K,
HostKey: hostKeyBytes,
Signature: sig,
Hash: group.hashFunc,
}, err
}
// ecdh performs Elliptic Curve Diffie-Hellman key exchange as
// described in RFC 5656, section 4.
type ecdh struct {
curve elliptic.Curve
}
func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
if err != nil {
return nil, err
}
kexInit := kexECDHInitMsg{
ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y),
}
serialized := Marshal(&kexInit)
if err := c.writePacket(serialized); err != nil {
return nil, err
}
packet, err := c.readPacket()
if err != nil {
return nil, err
}
var reply kexECDHReplyMsg
if err = Unmarshal(packet, &reply); err != nil {
return nil, err
}
x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey)
if err != nil {
return nil, err
}
// generate shared secret
secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes())
h := ecHash(kex.curve).New()
magics.write(h)
writeString(h, reply.HostKey)
writeString(h, kexInit.ClientPubKey)
writeString(h, reply.EphemeralPubKey)
K := make([]byte, intLength(secret))
marshalInt(K, secret)
h.Write(K)
return &kexResult{
H: h.Sum(nil),
K: K,
HostKey: reply.HostKey,
Signature: reply.Signature,
Hash: ecHash(kex.curve),
}, nil
}
// unmarshalECKey parses and checks an EC key.
func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) {
x, y = elliptic.Unmarshal(curve, pubkey)
if x == nil {
return nil, nil, errors.New("ssh: elliptic.Unmarshal failure")
}
if !validateECPublicKey(curve, x, y) {
return nil, nil, errors.New("ssh: public key not on curve")
}
return x, y, nil
}
// validateECPublicKey checks that the point is a valid public key for
// the given curve. See [SEC1], 3.2.2
func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool {
if x.Sign() == 0 && y.Sign() == 0 {
return false
}
if x.Cmp(curve.Params().P) >= 0 {
return false
}
if y.Cmp(curve.Params().P) >= 0 {
return false
}
if !curve.IsOnCurve(x, y) {
return false
}
// We don't check if N * PubKey == 0, since
//
// - the NIST curves have cofactor = 1, so this is implicit.
// (We don't foresee an implementation that supports non NIST
// curves)
//
// - for ephemeral keys, we don't need to worry about small
// subgroup attacks.
return true
}
func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
packet, err := c.readPacket()
if err != nil {
return nil, err
}
var kexECDHInit kexECDHInitMsg
if err = Unmarshal(packet, &kexECDHInit); err != nil {
return nil, err
}
clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey)
if err != nil {
return nil, err
}
// We could cache this key across multiple users/multiple
// connection attempts, but the benefit is small. OpenSSH
// generates a new key for each incoming connection.
ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
if err != nil {
return nil, err
}
hostKeyBytes := priv.PublicKey().Marshal()
serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y)
// generate shared secret
secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes())
h := ecHash(kex.curve).New()
magics.write(h)
writeString(h, hostKeyBytes)
writeString(h, kexECDHInit.ClientPubKey)
writeString(h, serializedEphKey)
K := make([]byte, intLength(secret))
marshalInt(K, secret)
h.Write(K)
H := h.Sum(nil)
// H is already a hash, but the hostkey signing will apply its
// own key-specific hash algorithm.
sig, err := signAndMarshal(priv, rand, H, algo)
if err != nil {
return nil, err
}
reply := kexECDHReplyMsg{
EphemeralPubKey: serializedEphKey,
HostKey: hostKeyBytes,
Signature: sig,
}
serialized := Marshal(&reply)
if err := c.writePacket(serialized); err != nil {
return nil, err
}
return &kexResult{
H: H,
K: K,
HostKey: reply.HostKey,
Signature: sig,
Hash: ecHash(kex.curve),
}, nil
}
// ecHash returns the hash to match the given elliptic curve, see RFC
// 5656, section 6.2.1
func ecHash(curve elliptic.Curve) crypto.Hash {
bitSize := curve.Params().BitSize
switch {
case bitSize <= 256:
return crypto.SHA256
case bitSize <= 384:
return crypto.SHA384
}
return crypto.SHA512
}
// kexAlgoMap defines the supported KEXs. KEXs not included are not supported
// and will not be negotiated, even if explicitly configured. When FIPS mode is
// enabled, only FIPS-approved algorithms are included.
var kexAlgoMap = map[string]kexAlgorithm{}
func init() {
// mlkem768x25519-sha256 we'll work with fips140=on but not fips140=only
// until Go 1.26.
kexAlgoMap[KeyExchangeMLKEM768X25519] = &mlkem768WithCurve25519sha256{}
kexAlgoMap[KeyExchangeECDHP521] = &ecdh{elliptic.P521()}
kexAlgoMap[KeyExchangeECDHP384] = &ecdh{elliptic.P384()}
kexAlgoMap[KeyExchangeECDHP256] = &ecdh{elliptic.P256()}
if fips140.Enabled() {
defaultKexAlgos = slices.DeleteFunc(defaultKexAlgos, func(algo string) bool {
_, ok := kexAlgoMap[algo]
return !ok
})
return
}
p, _ := new(big.Int).SetString(oakleyGroup2, 16)
kexAlgoMap[InsecureKeyExchangeDH1SHA1] = &dhGroup{
g: new(big.Int).SetInt64(2),
p: p,
pMinus1: new(big.Int).Sub(p, bigOne),
hashFunc: crypto.SHA1,
}
p, _ = new(big.Int).SetString(oakleyGroup14, 16)
group14 := &dhGroup{
g: new(big.Int).SetInt64(2),
p: p,
pMinus1: new(big.Int).Sub(p, bigOne),
}
kexAlgoMap[InsecureKeyExchangeDH14SHA1] = &dhGroup{
g: group14.g, p: group14.p, pMinus1: group14.pMinus1,
hashFunc: crypto.SHA1,
}
kexAlgoMap[KeyExchangeDH14SHA256] = &dhGroup{
g: group14.g, p: group14.p, pMinus1: group14.pMinus1,
hashFunc: crypto.SHA256,
}
p, _ = new(big.Int).SetString(oakleyGroup16, 16)
kexAlgoMap[KeyExchangeDH16SHA512] = &dhGroup{
g: new(big.Int).SetInt64(2),
p: p,
pMinus1: new(big.Int).Sub(p, bigOne),
hashFunc: crypto.SHA512,
}
kexAlgoMap[KeyExchangeCurve25519] = &curve25519sha256{}
kexAlgoMap[keyExchangeCurve25519LibSSH] = &curve25519sha256{}
kexAlgoMap[InsecureKeyExchangeDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1}
kexAlgoMap[KeyExchangeDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256}
}
// curve25519sha256 implements the curve25519-sha256 (formerly known as
// curve25519-sha256@libssh.org) key exchange method, as described in RFC 8731.
type curve25519sha256 struct{}
type curve25519KeyPair struct {
priv [32]byte
pub [32]byte
}
func (kp *curve25519KeyPair) generate(rand io.Reader) error {
if _, err := io.ReadFull(rand, kp.priv[:]); err != nil {
return err
}
p, err := curve25519.X25519(kp.priv[:], curve25519.Basepoint)
if err != nil {
return fmt.Errorf("curve25519: %w", err)
}
if len(p) != 32 {
return fmt.Errorf("curve25519: internal error: X25519 returned %d bytes, expected 32", len(p))
}
copy(kp.pub[:], p)
return nil
}
func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
var kp curve25519KeyPair
if err := kp.generate(rand); err != nil {
return nil, err
}
if err := c.writePacket(Marshal(&kexECDHInitMsg{kp.pub[:]})); err != nil {
return nil, err
}
packet, err := c.readPacket()
if err != nil {
return nil, err
}
var reply kexECDHReplyMsg
if err = Unmarshal(packet, &reply); err != nil {
return nil, err
}
if len(reply.EphemeralPubKey) != 32 {
return nil, errors.New("ssh: peer's curve25519 public value has wrong length")
}
secret, err := curve25519.X25519(kp.priv[:], reply.EphemeralPubKey)
if err != nil {
return nil, fmt.Errorf("ssh: peer's curve25519 public value is not valid: %w", err)
}
h := crypto.SHA256.New()
magics.write(h)
writeString(h, reply.HostKey)
writeString(h, kp.pub[:])
writeString(h, reply.EphemeralPubKey)
ki := new(big.Int).SetBytes(secret[:])
K := make([]byte, intLength(ki))
marshalInt(K, ki)
h.Write(K)
return &kexResult{
H: h.Sum(nil),
K: K,
HostKey: reply.HostKey,
Signature: reply.Signature,
Hash: crypto.SHA256,
}, nil
}
func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
packet, err := c.readPacket()
if err != nil {
return
}
var kexInit kexECDHInitMsg
if err = Unmarshal(packet, &kexInit); err != nil {
return
}
if len(kexInit.ClientPubKey) != 32 {
return nil, errors.New("ssh: peer's curve25519 public value has wrong length")
}
var kp curve25519KeyPair
if err := kp.generate(rand); err != nil {
return nil, err
}
secret, err := curve25519.X25519(kp.priv[:], kexInit.ClientPubKey)
if err != nil {
return nil, fmt.Errorf("ssh: peer's curve25519 public value is not valid: %w", err)
}
hostKeyBytes := priv.PublicKey().Marshal()
h := crypto.SHA256.New()
magics.write(h)
writeString(h, hostKeyBytes)
writeString(h, kexInit.ClientPubKey)
writeString(h, kp.pub[:])
ki := new(big.Int).SetBytes(secret[:])
K := make([]byte, intLength(ki))
marshalInt(K, ki)
h.Write(K)
H := h.Sum(nil)
sig, err := signAndMarshal(priv, rand, H, algo)
if err != nil {
return nil, err
}
reply := kexECDHReplyMsg{
EphemeralPubKey: kp.pub[:],
HostKey: hostKeyBytes,
Signature: sig,
}
if err := c.writePacket(Marshal(&reply)); err != nil {
return nil, err
}
return &kexResult{
H: H,
K: K,
HostKey: hostKeyBytes,
Signature: sig,
Hash: crypto.SHA256,
}, nil
}
// dhGEXSHA implements the diffie-hellman-group-exchange-sha1 and
// diffie-hellman-group-exchange-sha256 key agreement protocols,
// as described in RFC 4419
type dhGEXSHA struct {
hashFunc crypto.Hash
}
const (
dhGroupExchangeMinimumBits = 2048
dhGroupExchangePreferredBits = 2048
dhGroupExchangeMaximumBits = 8192
)
func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
// Send GexRequest
kexDHGexRequest := kexDHGexRequestMsg{
MinBits: dhGroupExchangeMinimumBits,
PreferredBits: dhGroupExchangePreferredBits,
MaxBits: dhGroupExchangeMaximumBits,
}
if err := c.writePacket(Marshal(&kexDHGexRequest)); err != nil {
return nil, err
}
// Receive GexGroup
packet, err := c.readPacket()
if err != nil {
return nil, err
}
var msg kexDHGexGroupMsg
if err = Unmarshal(packet, &msg); err != nil {
return nil, err
}
// reject if p's bit length < dhGroupExchangeMinimumBits or > dhGroupExchangeMaximumBits
if msg.P.BitLen() < dhGroupExchangeMinimumBits || msg.P.BitLen() > dhGroupExchangeMaximumBits {
return nil, fmt.Errorf("ssh: server-generated gex p is out of range (%d bits)", msg.P.BitLen())
}
// Check if g is safe by verifying that 1 < g < p-1
pMinusOne := new(big.Int).Sub(msg.P, bigOne)
if msg.G.Cmp(bigOne) <= 0 || msg.G.Cmp(pMinusOne) >= 0 {
return nil, fmt.Errorf("ssh: server provided gex g is not safe")
}
// Send GexInit
pHalf := new(big.Int).Rsh(msg.P, 1)
x, err := rand.Int(randSource, pHalf)
if err != nil {
return nil, err
}
X := new(big.Int).Exp(msg.G, x, msg.P)
kexDHGexInit := kexDHGexInitMsg{
X: X,
}
if err := c.writePacket(Marshal(&kexDHGexInit)); err != nil {
return nil, err
}
// Receive GexReply
packet, err = c.readPacket()
if err != nil {
return nil, err
}
var kexDHGexReply kexDHGexReplyMsg
if err = Unmarshal(packet, &kexDHGexReply); err != nil {
return nil, err
}
if kexDHGexReply.Y.Cmp(bigOne) <= 0 || kexDHGexReply.Y.Cmp(pMinusOne) >= 0 {
return nil, errors.New("ssh: DH parameter out of bounds")
}
kInt := new(big.Int).Exp(kexDHGexReply.Y, x, msg.P)
// Check if k is safe by verifying that k > 1 and k < p - 1
if kInt.Cmp(bigOne) <= 0 || kInt.Cmp(pMinusOne) >= 0 {
return nil, fmt.Errorf("ssh: derived k is not safe")
}
h := gex.hashFunc.New()
magics.write(h)
writeString(h, kexDHGexReply.HostKey)
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits))
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits))
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits))
writeInt(h, msg.P)
writeInt(h, msg.G)
writeInt(h, X)
writeInt(h, kexDHGexReply.Y)
K := make([]byte, intLength(kInt))
marshalInt(K, kInt)
h.Write(K)
return &kexResult{
H: h.Sum(nil),
K: K,
HostKey: kexDHGexReply.HostKey,
Signature: kexDHGexReply.Signature,
Hash: gex.hashFunc,
}, nil
}
// Server half implementation of the Diffie Hellman Key Exchange with SHA1 and SHA256.
func (gex *dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
// Receive GexRequest
packet, err := c.readPacket()
if err != nil {
return
}
var kexDHGexRequest kexDHGexRequestMsg
if err = Unmarshal(packet, &kexDHGexRequest); err != nil {
return
}
// We check that the request received is valid and that the MaxBits
// requested are at least equal to our supported minimum. This is the same
// check done in OpenSSH:
// https://github.com/openssh/openssh-portable/blob/80a2f64b/kexgexs.c#L94
//
// Furthermore, we also check that the required MinBits are less than or
// equal to 4096 because we can use up to Oakley Group 16.
if kexDHGexRequest.MaxBits < kexDHGexRequest.MinBits || kexDHGexRequest.PreferredBits < kexDHGexRequest.MinBits ||
kexDHGexRequest.MaxBits < kexDHGexRequest.PreferredBits || kexDHGexRequest.MaxBits < dhGroupExchangeMinimumBits ||
kexDHGexRequest.MinBits > 4096 {
return nil, fmt.Errorf("ssh: DH GEX request out of range, min: %d, max: %d, preferred: %d", kexDHGexRequest.MinBits,
kexDHGexRequest.MaxBits, kexDHGexRequest.PreferredBits)
}
var p *big.Int
// We hardcode sending Oakley Group 14 (2048 bits), Oakley Group 15 (3072
// bits) or Oakley Group 16 (4096 bits), based on the requested max size.
if kexDHGexRequest.MaxBits < 3072 {
p, _ = new(big.Int).SetString(oakleyGroup14, 16)
} else if kexDHGexRequest.MaxBits < 4096 {
p, _ = new(big.Int).SetString(oakleyGroup15, 16)
} else {
p, _ = new(big.Int).SetString(oakleyGroup16, 16)
}
g := big.NewInt(2)
msg := &kexDHGexGroupMsg{
P: p,
G: g,
}
if err := c.writePacket(Marshal(msg)); err != nil {
return nil, err
}
// Receive GexInit
packet, err = c.readPacket()
if err != nil {
return
}
var kexDHGexInit kexDHGexInitMsg
if err = Unmarshal(packet, &kexDHGexInit); err != nil {
return
}
pHalf := new(big.Int).Rsh(p, 1)
y, err := rand.Int(randSource, pHalf)
if err != nil {
return
}
Y := new(big.Int).Exp(g, y, p)
pMinusOne := new(big.Int).Sub(p, bigOne)
if kexDHGexInit.X.Cmp(bigOne) <= 0 || kexDHGexInit.X.Cmp(pMinusOne) >= 0 {
return nil, errors.New("ssh: DH parameter out of bounds")
}
kInt := new(big.Int).Exp(kexDHGexInit.X, y, p)
hostKeyBytes := priv.PublicKey().Marshal()
h := gex.hashFunc.New()
magics.write(h)
writeString(h, hostKeyBytes)
binary.Write(h, binary.BigEndian, kexDHGexRequest.MinBits)
binary.Write(h, binary.BigEndian, kexDHGexRequest.PreferredBits)
binary.Write(h, binary.BigEndian, kexDHGexRequest.MaxBits)
writeInt(h, p)
writeInt(h, g)
writeInt(h, kexDHGexInit.X)
writeInt(h, Y)
K := make([]byte, intLength(kInt))
marshalInt(K, kInt)
h.Write(K)
H := h.Sum(nil)
// H is already a hash, but the hostkey signing will apply its
// own key-specific hash algorithm.
sig, err := signAndMarshal(priv, randSource, H, algo)
if err != nil {
return nil, err
}
kexDHGexReply := kexDHGexReplyMsg{
HostKey: hostKeyBytes,
Y: Y,
Signature: sig,
}
packet = Marshal(&kexDHGexReply)
err = c.writePacket(packet)
return &kexResult{
H: H,
K: K,
HostKey: hostKeyBytes,
Signature: sig,
Hash: gex.hashFunc,
}, err
}
// 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.
package ssh
import (
"bytes"
"crypto"
"crypto/aes"
"crypto/cipher"
"crypto/dsa"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/md5"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/asn1"
"encoding/base64"
"encoding/binary"
"encoding/hex"
"encoding/pem"
"errors"
"fmt"
"io"
"math/big"
"slices"
"strings"
"golang.org/x/crypto/ssh/internal/bcrypt_pbkdf"
)
// Public key algorithms names. These values can appear in PublicKey.Type,
// ClientConfig.HostKeyAlgorithms, Signature.Format, or as AlgorithmSigner
// arguments.
const (
KeyAlgoRSA = "ssh-rsa"
// Deprecated: DSA is only supported at insecure key sizes, and was removed
// from major implementations.
KeyAlgoDSA = InsecureKeyAlgoDSA
// Deprecated: DSA is only supported at insecure key sizes, and was removed
// from major implementations.
InsecureKeyAlgoDSA = "ssh-dss"
KeyAlgoECDSA256 = "ecdsa-sha2-nistp256"
KeyAlgoSKECDSA256 = "sk-ecdsa-sha2-nistp256@openssh.com"
KeyAlgoECDSA384 = "ecdsa-sha2-nistp384"
KeyAlgoECDSA521 = "ecdsa-sha2-nistp521"
KeyAlgoED25519 = "ssh-ed25519"
KeyAlgoSKED25519 = "sk-ssh-ed25519@openssh.com"
// KeyAlgoRSASHA256 and KeyAlgoRSASHA512 are only public key algorithms, not
// public key formats, so they can't appear as a PublicKey.Type. The
// corresponding PublicKey.Type is KeyAlgoRSA. See RFC 8332, Section 2.
KeyAlgoRSASHA256 = "rsa-sha2-256"
KeyAlgoRSASHA512 = "rsa-sha2-512"
)
const (
// Deprecated: use KeyAlgoRSA.
SigAlgoRSA = KeyAlgoRSA
// Deprecated: use KeyAlgoRSASHA256.
SigAlgoRSASHA2256 = KeyAlgoRSASHA256
// Deprecated: use KeyAlgoRSASHA512.
SigAlgoRSASHA2512 = KeyAlgoRSASHA512
)
// parsePubKey parses a public key of the given algorithm.
// Use ParsePublicKey for keys with prepended algorithm.
func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err error) {
switch algo {
case KeyAlgoRSA:
return parseRSA(in)
case InsecureKeyAlgoDSA:
return parseDSA(in)
case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521:
return parseECDSA(in)
case KeyAlgoSKECDSA256:
return parseSKECDSA(in)
case KeyAlgoED25519:
return parseED25519(in)
case KeyAlgoSKED25519:
return parseSKEd25519(in)
case CertAlgoRSAv01, InsecureCertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01:
cert, err := parseCert(in, certKeyAlgoNames[algo])
if err != nil {
return nil, nil, err
}
return cert, nil, nil
}
if keyFormat := keyFormatForAlgorithm(algo); keyFormat != "" {
return nil, nil, fmt.Errorf("ssh: signature algorithm %q isn't a key format; key is malformed and should be re-encoded with type %q",
algo, keyFormat)
}
return nil, nil, fmt.Errorf("ssh: unknown key algorithm: %v", algo)
}
// parseAuthorizedKey parses a public key in OpenSSH authorized_keys format
// (see sshd(8) manual page) once the options and key type fields have been
// removed.
func parseAuthorizedKey(in []byte) (out PublicKey, comment string, err error) {
in = bytes.TrimSpace(in)
i := bytes.IndexAny(in, " \t")
if i == -1 {
i = len(in)
}
base64Key := in[:i]
key := make([]byte, base64.StdEncoding.DecodedLen(len(base64Key)))
n, err := base64.StdEncoding.Decode(key, base64Key)
if err != nil {
return nil, "", err
}
key = key[:n]
out, err = ParsePublicKey(key)
if err != nil {
return nil, "", err
}
comment = string(bytes.TrimSpace(in[i:]))
return out, comment, nil
}
// ParseKnownHosts parses an entry in the format of the known_hosts file.
//
// The known_hosts format is documented in the sshd(8) manual page. This
// function will parse a single entry from in. On successful return, marker
// will contain the optional marker value (i.e. "cert-authority" or "revoked")
// or else be empty, hosts will contain the hosts that this entry matches,
// pubKey will contain the public key and comment will contain any trailing
// comment at the end of the line. See the sshd(8) manual page for the various
// forms that a host string can take.
//
// The unparsed remainder of the input will be returned in rest. This function
// can be called repeatedly to parse multiple entries.
//
// If no entries were found in the input then err will be io.EOF. Otherwise a
// non-nil err value indicates a parse error.
func ParseKnownHosts(in []byte) (marker string, hosts []string, pubKey PublicKey, comment string, rest []byte, err error) {
for len(in) > 0 {
end := bytes.IndexByte(in, '\n')
if end != -1 {
rest = in[end+1:]
in = in[:end]
} else {
rest = nil
}
end = bytes.IndexByte(in, '\r')
if end != -1 {
in = in[:end]
}
in = bytes.TrimSpace(in)
if len(in) == 0 || in[0] == '#' {
in = rest
continue
}
i := bytes.IndexAny(in, " \t")
if i == -1 {
in = rest
continue
}
// Strip out the beginning of the known_host key.
// This is either an optional marker or a (set of) hostname(s).
keyFields := bytes.Fields(in)
if len(keyFields) < 3 || len(keyFields) > 5 {
return "", nil, nil, "", nil, errors.New("ssh: invalid entry in known_hosts data")
}
// keyFields[0] is either "@cert-authority", "@revoked" or a comma separated
// list of hosts
marker := ""
if keyFields[0][0] == '@' {
marker = string(keyFields[0][1:])
keyFields = keyFields[1:]
}
hosts := string(keyFields[0])
// keyFields[1] contains the key type (e.g. “ssh-rsa”).
// However, that information is duplicated inside the
// base64-encoded key and so is ignored here.
key := bytes.Join(keyFields[2:], []byte(" "))
if pubKey, comment, err = parseAuthorizedKey(key); err != nil {
return "", nil, nil, "", nil, err
}
return marker, strings.Split(hosts, ","), pubKey, comment, rest, nil
}
return "", nil, nil, "", nil, io.EOF
}
// ParseAuthorizedKey parses a public key from an authorized_keys file used in
// OpenSSH according to the sshd(8) manual page. Invalid lines are ignored.
func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []string, rest []byte, err error) {
var lastErr error
for len(in) > 0 {
end := bytes.IndexByte(in, '\n')
if end != -1 {
rest = in[end+1:]
in = in[:end]
} else {
rest = nil
}
end = bytes.IndexByte(in, '\r')
if end != -1 {
in = in[:end]
}
in = bytes.TrimSpace(in)
if len(in) == 0 || in[0] == '#' {
in = rest
continue
}
i := bytes.IndexAny(in, " \t")
if i == -1 {
in = rest
continue
}
if out, comment, err = parseAuthorizedKey(in[i:]); err == nil {
return out, comment, options, rest, nil
} else {
lastErr = err
}
// No key type recognised. Maybe there's an options field at
// the beginning.
var b byte
inQuote := false
var candidateOptions []string
optionStart := 0
for i, b = range in {
isEnd := !inQuote && (b == ' ' || b == '\t')
if (b == ',' && !inQuote) || isEnd {
if i-optionStart > 0 {
candidateOptions = append(candidateOptions, string(in[optionStart:i]))
}
optionStart = i + 1
}
if isEnd {
break
}
if b == '"' && (i == 0 || (i > 0 && in[i-1] != '\\')) {
inQuote = !inQuote
}
}
for i < len(in) && (in[i] == ' ' || in[i] == '\t') {
i++
}
if i == len(in) {
// Invalid line: unmatched quote
in = rest
continue
}
in = in[i:]
i = bytes.IndexAny(in, " \t")
if i == -1 {
in = rest
continue
}
if out, comment, err = parseAuthorizedKey(in[i:]); err == nil {
options = candidateOptions
return out, comment, options, rest, nil
} else {
lastErr = err
}
in = rest
continue
}
if lastErr != nil {
return nil, "", nil, nil, fmt.Errorf("ssh: no key found; last parsing error for ignored line: %w", lastErr)
}
return nil, "", nil, nil, errors.New("ssh: no key found")
}
// ParsePublicKey parses an SSH public key or certificate formatted for use in
// the SSH wire protocol according to RFC 4253, section 6.6.
func ParsePublicKey(in []byte) (out PublicKey, err error) {
algo, in, ok := parseString(in)
if !ok {
return nil, errShortRead
}
var rest []byte
out, rest, err = parsePubKey(in, string(algo))
if len(rest) > 0 {
return nil, errors.New("ssh: trailing junk in public key")
}
return out, err
}
// MarshalAuthorizedKey serializes key for inclusion in an OpenSSH
// authorized_keys file. The return value ends with newline.
func MarshalAuthorizedKey(key PublicKey) []byte {
b := &bytes.Buffer{}
b.WriteString(key.Type())
b.WriteByte(' ')
e := base64.NewEncoder(base64.StdEncoding, b)
e.Write(key.Marshal())
e.Close()
b.WriteByte('\n')
return b.Bytes()
}
// MarshalPrivateKey returns a PEM block with the private key serialized in the
// OpenSSH format.
func MarshalPrivateKey(key crypto.PrivateKey, comment string) (*pem.Block, error) {
return marshalOpenSSHPrivateKey(key, comment, unencryptedOpenSSHMarshaler)
}
// MarshalPrivateKeyWithPassphrase returns a PEM block holding the encrypted
// private key serialized in the OpenSSH format.
func MarshalPrivateKeyWithPassphrase(key crypto.PrivateKey, comment string, passphrase []byte) (*pem.Block, error) {
return marshalOpenSSHPrivateKey(key, comment, passphraseProtectedOpenSSHMarshaler(passphrase))
}
// PublicKey represents a public key using an unspecified algorithm.
//
// Some PublicKeys provided by this package also implement CryptoPublicKey.
type PublicKey interface {
// Type returns the key format name, e.g. "ssh-rsa".
Type() string
// Marshal returns the serialized key data in SSH wire format, with the name
// prefix. To unmarshal the returned data, use the ParsePublicKey function.
Marshal() []byte
// Verify that sig is a signature on the given data using this key. This
// method will hash the data appropriately first. sig.Format is allowed to
// be any signature algorithm compatible with the key type, the caller
// should check if it has more stringent requirements.
Verify(data []byte, sig *Signature) error
}
// CryptoPublicKey, if implemented by a PublicKey,
// returns the underlying crypto.PublicKey form of the key.
type CryptoPublicKey interface {
CryptoPublicKey() crypto.PublicKey
}
// A Signer can create signatures that verify against a public key.
//
// Some Signers provided by this package also implement MultiAlgorithmSigner.
type Signer interface {
// PublicKey returns the associated PublicKey.
PublicKey() PublicKey
// Sign returns a signature for the given data. This method will hash the
// data appropriately first. The signature algorithm is expected to match
// the key format returned by the PublicKey.Type method (and not to be any
// alternative algorithm supported by the key format).
Sign(rand io.Reader, data []byte) (*Signature, error)
}
// An AlgorithmSigner is a Signer that also supports specifying an algorithm to
// use for signing.
//
// An AlgorithmSigner can't advertise the algorithms it supports, unless it also
// implements MultiAlgorithmSigner, so it should be prepared to be invoked with
// every algorithm supported by the public key format.
type AlgorithmSigner interface {
Signer
// SignWithAlgorithm is like Signer.Sign, but allows specifying a desired
// signing algorithm. Callers may pass an empty string for the algorithm in
// which case the AlgorithmSigner will use a default algorithm. This default
// doesn't currently control any behavior in this package.
SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error)
}
// MultiAlgorithmSigner is an AlgorithmSigner that also reports the algorithms
// supported by that signer.
type MultiAlgorithmSigner interface {
AlgorithmSigner
// Algorithms returns the available algorithms in preference order. The list
// must not be empty, and it must not include certificate types.
Algorithms() []string
}
// NewSignerWithAlgorithms returns a signer restricted to the specified
// algorithms. The algorithms must be set in preference order. The list must not
// be empty, and it must not include certificate types. An error is returned if
// the specified algorithms are incompatible with the public key type.
func NewSignerWithAlgorithms(signer AlgorithmSigner, algorithms []string) (MultiAlgorithmSigner, error) {
if len(algorithms) == 0 {
return nil, errors.New("ssh: please specify at least one valid signing algorithm")
}
var signerAlgos []string
supportedAlgos := algorithmsForKeyFormat(underlyingAlgo(signer.PublicKey().Type()))
if s, ok := signer.(*multiAlgorithmSigner); ok {
signerAlgos = s.Algorithms()
} else {
signerAlgos = supportedAlgos
}
for _, algo := range algorithms {
if !slices.Contains(supportedAlgos, algo) {
return nil, fmt.Errorf("ssh: algorithm %q is not supported for key type %q",
algo, signer.PublicKey().Type())
}
if !slices.Contains(signerAlgos, algo) {
return nil, fmt.Errorf("ssh: algorithm %q is restricted for the provided signer", algo)
}
}
return &multiAlgorithmSigner{
AlgorithmSigner: signer,
supportedAlgorithms: algorithms,
}, nil
}
type multiAlgorithmSigner struct {
AlgorithmSigner
supportedAlgorithms []string
}
func (s *multiAlgorithmSigner) Algorithms() []string {
return s.supportedAlgorithms
}
func (s *multiAlgorithmSigner) isAlgorithmSupported(algorithm string) bool {
if algorithm == "" {
algorithm = underlyingAlgo(s.PublicKey().Type())
}
for _, algo := range s.supportedAlgorithms {
if algorithm == algo {
return true
}
}
return false
}
func (s *multiAlgorithmSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
if !s.isAlgorithmSupported(algorithm) {
return nil, fmt.Errorf("ssh: algorithm %q is not supported: %v", algorithm, s.supportedAlgorithms)
}
return s.AlgorithmSigner.SignWithAlgorithm(rand, data, algorithm)
}
type rsaPublicKey rsa.PublicKey
func (r *rsaPublicKey) Type() string {
return "ssh-rsa"
}
// parseRSA parses an RSA key according to RFC 4253, section 6.6.
func parseRSA(in []byte) (out PublicKey, rest []byte, err error) {
var w struct {
E *big.Int
N *big.Int
Rest []byte `ssh:"rest"`
}
if err := Unmarshal(in, &w); err != nil {
return nil, nil, err
}
if w.E.BitLen() > 24 {
return nil, nil, errors.New("ssh: exponent too large")
}
e := w.E.Int64()
if e < 3 || e&1 == 0 {
return nil, nil, errors.New("ssh: incorrect exponent")
}
var key rsa.PublicKey
key.E = int(e)
key.N = w.N
return (*rsaPublicKey)(&key), w.Rest, nil
}
func (r *rsaPublicKey) Marshal() []byte {
e := new(big.Int).SetInt64(int64(r.E))
// RSA publickey struct layout should match the struct used by
// parseRSACert in the x/crypto/ssh/agent package.
wirekey := struct {
Name string
E *big.Int
N *big.Int
}{
KeyAlgoRSA,
e,
r.N,
}
return Marshal(&wirekey)
}
func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error {
supportedAlgos := algorithmsForKeyFormat(r.Type())
if !slices.Contains(supportedAlgos, sig.Format) {
return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type())
}
hash, err := hashFunc(sig.Format)
if err != nil {
return err
}
h := hash.New()
h.Write(data)
digest := h.Sum(nil)
// Signatures in PKCS1v15 must match the key's modulus in
// length. However with SSH, some signers provide RSA
// signatures which are missing the MSB 0's of the bignum
// represented. With ssh-rsa signatures, this is encouraged by
// the spec (even though e.g. OpenSSH will give the full
// length unconditionally). With rsa-sha2-* signatures, the
// verifier is allowed to support these, even though they are
// out of spec. See RFC 4253 Section 6.6 for ssh-rsa and RFC
// 8332 Section 3 for rsa-sha2-* details.
//
// In practice:
// * OpenSSH always allows "short" signatures:
// https://github.com/openssh/openssh-portable/blob/V_9_8_P1/ssh-rsa.c#L526
// but always generates padded signatures:
// https://github.com/openssh/openssh-portable/blob/V_9_8_P1/ssh-rsa.c#L439
//
// * PuTTY versions 0.81 and earlier will generate short
// signatures for all RSA signature variants. Note that
// PuTTY is embedded in other software, such as WinSCP and
// FileZilla. At the time of writing, a patch has been
// applied to PuTTY to generate padded signatures for
// rsa-sha2-*, but not yet released:
// https://git.tartarus.org/?p=simon/putty.git;a=commitdiff;h=a5bcf3d384e1bf15a51a6923c3724cbbee022d8e
//
// * SSH.NET versions 2024.0.0 and earlier will generate short
// signatures for all RSA signature variants, fixed in 2024.1.0:
// https://github.com/sshnet/SSH.NET/releases/tag/2024.1.0
//
// As a result, we pad these up to the key size by inserting
// leading 0's.
//
// Note that support for short signatures with rsa-sha2-* may
// be removed in the future due to such signatures not being
// allowed by the spec.
blob := sig.Blob
keySize := (*rsa.PublicKey)(r).Size()
if len(blob) < keySize {
padded := make([]byte, keySize)
copy(padded[keySize-len(blob):], blob)
blob = padded
}
return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), hash, digest, blob)
}
func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey {
return (*rsa.PublicKey)(r)
}
type dsaPublicKey dsa.PublicKey
func (k *dsaPublicKey) Type() string {
return "ssh-dss"
}
func checkDSAParams(param *dsa.Parameters) error {
// SSH specifies FIPS 186-2, which only provided a single size
// (1024 bits) DSA key. FIPS 186-3 allows for larger key
// sizes, which would confuse SSH.
if l := param.P.BitLen(); l != 1024 {
return fmt.Errorf("ssh: unsupported DSA key size %d", l)
}
return nil
}
// parseDSA parses an DSA key according to RFC 4253, section 6.6.
func parseDSA(in []byte) (out PublicKey, rest []byte, err error) {
var w struct {
P, Q, G, Y *big.Int
Rest []byte `ssh:"rest"`
}
if err := Unmarshal(in, &w); err != nil {
return nil, nil, err
}
param := dsa.Parameters{
P: w.P,
Q: w.Q,
G: w.G,
}
if err := checkDSAParams(¶m); err != nil {
return nil, nil, err
}
key := &dsaPublicKey{
Parameters: param,
Y: w.Y,
}
return key, w.Rest, nil
}
func (k *dsaPublicKey) Marshal() []byte {
// DSA publickey struct layout should match the struct used by
// parseDSACert in the x/crypto/ssh/agent package.
w := struct {
Name string
P, Q, G, Y *big.Int
}{
k.Type(),
k.P,
k.Q,
k.G,
k.Y,
}
return Marshal(&w)
}
func (k *dsaPublicKey) Verify(data []byte, sig *Signature) error {
if sig.Format != k.Type() {
return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
}
hash, err := hashFunc(sig.Format)
if err != nil {
return err
}
h := hash.New()
h.Write(data)
digest := h.Sum(nil)
// Per RFC 4253, section 6.6,
// The value for 'dss_signature_blob' is encoded as a string containing
// r, followed by s (which are 160-bit integers, without lengths or
// padding, unsigned, and in network byte order).
// For DSS purposes, sig.Blob should be exactly 40 bytes in length.
if len(sig.Blob) != 40 {
return errors.New("ssh: DSA signature parse error")
}
r := new(big.Int).SetBytes(sig.Blob[:20])
s := new(big.Int).SetBytes(sig.Blob[20:])
if dsa.Verify((*dsa.PublicKey)(k), digest, r, s) {
return nil
}
return errors.New("ssh: signature did not verify")
}
func (k *dsaPublicKey) CryptoPublicKey() crypto.PublicKey {
return (*dsa.PublicKey)(k)
}
type dsaPrivateKey struct {
*dsa.PrivateKey
}
func (k *dsaPrivateKey) PublicKey() PublicKey {
return (*dsaPublicKey)(&k.PrivateKey.PublicKey)
}
func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) {
return k.SignWithAlgorithm(rand, data, k.PublicKey().Type())
}
func (k *dsaPrivateKey) Algorithms() []string {
return []string{k.PublicKey().Type()}
}
func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
if algorithm != "" && algorithm != k.PublicKey().Type() {
return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm)
}
hash, err := hashFunc(k.PublicKey().Type())
if err != nil {
return nil, err
}
h := hash.New()
h.Write(data)
digest := h.Sum(nil)
r, s, err := dsa.Sign(rand, k.PrivateKey, digest)
if err != nil {
return nil, err
}
sig := make([]byte, 40)
rb := r.Bytes()
sb := s.Bytes()
copy(sig[20-len(rb):20], rb)
copy(sig[40-len(sb):], sb)
return &Signature{
Format: k.PublicKey().Type(),
Blob: sig,
}, nil
}
type ecdsaPublicKey ecdsa.PublicKey
func (k *ecdsaPublicKey) Type() string {
return "ecdsa-sha2-" + k.nistID()
}
func (k *ecdsaPublicKey) nistID() string {
switch k.Params().BitSize {
case 256:
return "nistp256"
case 384:
return "nistp384"
case 521:
return "nistp521"
}
panic("ssh: unsupported ecdsa key size")
}
type ed25519PublicKey ed25519.PublicKey
func (k ed25519PublicKey) Type() string {
return KeyAlgoED25519
}
func parseED25519(in []byte) (out PublicKey, rest []byte, err error) {
var w struct {
KeyBytes []byte
Rest []byte `ssh:"rest"`
}
if err := Unmarshal(in, &w); err != nil {
return nil, nil, err
}
if l := len(w.KeyBytes); l != ed25519.PublicKeySize {
return nil, nil, fmt.Errorf("invalid size %d for Ed25519 public key", l)
}
return ed25519PublicKey(w.KeyBytes), w.Rest, nil
}
func (k ed25519PublicKey) Marshal() []byte {
w := struct {
Name string
KeyBytes []byte
}{
KeyAlgoED25519,
[]byte(k),
}
return Marshal(&w)
}
func (k ed25519PublicKey) Verify(b []byte, sig *Signature) error {
if sig.Format != k.Type() {
return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
}
if l := len(k); l != ed25519.PublicKeySize {
return fmt.Errorf("ssh: invalid size %d for Ed25519 public key", l)
}
if ok := ed25519.Verify(ed25519.PublicKey(k), b, sig.Blob); !ok {
return errors.New("ssh: signature did not verify")
}
return nil
}
func (k ed25519PublicKey) CryptoPublicKey() crypto.PublicKey {
return ed25519.PublicKey(k)
}
func supportedEllipticCurve(curve elliptic.Curve) bool {
return curve == elliptic.P256() || curve == elliptic.P384() || curve == elliptic.P521()
}
// parseECDSA parses an ECDSA key according to RFC 5656, section 3.1.
func parseECDSA(in []byte) (out PublicKey, rest []byte, err error) {
var w struct {
Curve string
KeyBytes []byte
Rest []byte `ssh:"rest"`
}
if err := Unmarshal(in, &w); err != nil {
return nil, nil, err
}
key := new(ecdsa.PublicKey)
switch w.Curve {
case "nistp256":
key.Curve = elliptic.P256()
case "nistp384":
key.Curve = elliptic.P384()
case "nistp521":
key.Curve = elliptic.P521()
default:
return nil, nil, errors.New("ssh: unsupported curve")
}
key.X, key.Y = elliptic.Unmarshal(key.Curve, w.KeyBytes)
if key.X == nil || key.Y == nil {
return nil, nil, errors.New("ssh: invalid curve point")
}
return (*ecdsaPublicKey)(key), w.Rest, nil
}
func (k *ecdsaPublicKey) Marshal() []byte {
// See RFC 5656, section 3.1.
keyBytes := elliptic.Marshal(k.Curve, k.X, k.Y)
// ECDSA publickey struct layout should match the struct used by
// parseECDSACert in the x/crypto/ssh/agent package.
w := struct {
Name string
ID string
Key []byte
}{
k.Type(),
k.nistID(),
keyBytes,
}
return Marshal(&w)
}
func (k *ecdsaPublicKey) Verify(data []byte, sig *Signature) error {
if sig.Format != k.Type() {
return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
}
hash, err := hashFunc(sig.Format)
if err != nil {
return err
}
h := hash.New()
h.Write(data)
digest := h.Sum(nil)
// Per RFC 5656, section 3.1.2,
// The ecdsa_signature_blob value has the following specific encoding:
// mpint r
// mpint s
var ecSig struct {
R *big.Int
S *big.Int
}
if err := Unmarshal(sig.Blob, &ecSig); err != nil {
return err
}
if ecdsa.Verify((*ecdsa.PublicKey)(k), digest, ecSig.R, ecSig.S) {
return nil
}
return errors.New("ssh: signature did not verify")
}
func (k *ecdsaPublicKey) CryptoPublicKey() crypto.PublicKey {
return (*ecdsa.PublicKey)(k)
}
// skFields holds the additional fields present in U2F/FIDO2 signatures.
// See openssh/PROTOCOL.u2f 'SSH U2F Signatures' for details.
type skFields struct {
// Flags contains U2F/FIDO2 flags such as 'user present'
Flags byte
// Counter is a monotonic signature counter which can be
// used to detect concurrent use of a private key, should
// it be extracted from hardware.
Counter uint32
}
type skECDSAPublicKey struct {
// application is a URL-like string, typically "ssh:" for SSH.
// see openssh/PROTOCOL.u2f for details.
application string
ecdsa.PublicKey
}
func (k *skECDSAPublicKey) Type() string {
return KeyAlgoSKECDSA256
}
func (k *skECDSAPublicKey) nistID() string {
return "nistp256"
}
func parseSKECDSA(in []byte) (out PublicKey, rest []byte, err error) {
var w struct {
Curve string
KeyBytes []byte
Application string
Rest []byte `ssh:"rest"`
}
if err := Unmarshal(in, &w); err != nil {
return nil, nil, err
}
key := new(skECDSAPublicKey)
key.application = w.Application
if w.Curve != "nistp256" {
return nil, nil, errors.New("ssh: unsupported curve")
}
key.Curve = elliptic.P256()
key.X, key.Y = elliptic.Unmarshal(key.Curve, w.KeyBytes)
if key.X == nil || key.Y == nil {
return nil, nil, errors.New("ssh: invalid curve point")
}
return key, w.Rest, nil
}
func (k *skECDSAPublicKey) Marshal() []byte {
// See RFC 5656, section 3.1.
keyBytes := elliptic.Marshal(k.Curve, k.X, k.Y)
w := struct {
Name string
ID string
Key []byte
Application string
}{
k.Type(),
k.nistID(),
keyBytes,
k.application,
}
return Marshal(&w)
}
func (k *skECDSAPublicKey) Verify(data []byte, sig *Signature) error {
if sig.Format != k.Type() {
return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
}
hash, err := hashFunc(sig.Format)
if err != nil {
return err
}
h := hash.New()
h.Write([]byte(k.application))
appDigest := h.Sum(nil)
h.Reset()
h.Write(data)
dataDigest := h.Sum(nil)
var ecSig struct {
R *big.Int
S *big.Int
}
if err := Unmarshal(sig.Blob, &ecSig); err != nil {
return err
}
var skf skFields
if err := Unmarshal(sig.Rest, &skf); err != nil {
return err
}
blob := struct {
ApplicationDigest []byte `ssh:"rest"`
Flags byte
Counter uint32
MessageDigest []byte `ssh:"rest"`
}{
appDigest,
skf.Flags,
skf.Counter,
dataDigest,
}
original := Marshal(blob)
h.Reset()
h.Write(original)
digest := h.Sum(nil)
if ecdsa.Verify((*ecdsa.PublicKey)(&k.PublicKey), digest, ecSig.R, ecSig.S) {
return nil
}
return errors.New("ssh: signature did not verify")
}
func (k *skECDSAPublicKey) CryptoPublicKey() crypto.PublicKey {
return &k.PublicKey
}
type skEd25519PublicKey struct {
// application is a URL-like string, typically "ssh:" for SSH.
// see openssh/PROTOCOL.u2f for details.
application string
ed25519.PublicKey
}
func (k *skEd25519PublicKey) Type() string {
return KeyAlgoSKED25519
}
func parseSKEd25519(in []byte) (out PublicKey, rest []byte, err error) {
var w struct {
KeyBytes []byte
Application string
Rest []byte `ssh:"rest"`
}
if err := Unmarshal(in, &w); err != nil {
return nil, nil, err
}
if l := len(w.KeyBytes); l != ed25519.PublicKeySize {
return nil, nil, fmt.Errorf("invalid size %d for Ed25519 public key", l)
}
key := new(skEd25519PublicKey)
key.application = w.Application
key.PublicKey = ed25519.PublicKey(w.KeyBytes)
return key, w.Rest, nil
}
func (k *skEd25519PublicKey) Marshal() []byte {
w := struct {
Name string
KeyBytes []byte
Application string
}{
KeyAlgoSKED25519,
[]byte(k.PublicKey),
k.application,
}
return Marshal(&w)
}
func (k *skEd25519PublicKey) Verify(data []byte, sig *Signature) error {
if sig.Format != k.Type() {
return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
}
if l := len(k.PublicKey); l != ed25519.PublicKeySize {
return fmt.Errorf("invalid size %d for Ed25519 public key", l)
}
hash, err := hashFunc(sig.Format)
if err != nil {
return err
}
h := hash.New()
h.Write([]byte(k.application))
appDigest := h.Sum(nil)
h.Reset()
h.Write(data)
dataDigest := h.Sum(nil)
var edSig struct {
Signature []byte `ssh:"rest"`
}
if err := Unmarshal(sig.Blob, &edSig); err != nil {
return err
}
var skf skFields
if err := Unmarshal(sig.Rest, &skf); err != nil {
return err
}
blob := struct {
ApplicationDigest []byte `ssh:"rest"`
Flags byte
Counter uint32
MessageDigest []byte `ssh:"rest"`
}{
appDigest,
skf.Flags,
skf.Counter,
dataDigest,
}
original := Marshal(blob)
if ok := ed25519.Verify(k.PublicKey, original, edSig.Signature); !ok {
return errors.New("ssh: signature did not verify")
}
return nil
}
func (k *skEd25519PublicKey) CryptoPublicKey() crypto.PublicKey {
return k.PublicKey
}
// NewSignerFromKey takes an *rsa.PrivateKey, *dsa.PrivateKey,
// *ecdsa.PrivateKey or any other crypto.Signer and returns a
// corresponding Signer instance. ECDSA keys must use P-256, P-384 or
// P-521. DSA keys must use parameter size L1024N160.
func NewSignerFromKey(key interface{}) (Signer, error) {
switch key := key.(type) {
case crypto.Signer:
return NewSignerFromSigner(key)
case *dsa.PrivateKey:
return newDSAPrivateKey(key)
default:
return nil, fmt.Errorf("ssh: unsupported key type %T", key)
}
}
func newDSAPrivateKey(key *dsa.PrivateKey) (Signer, error) {
if err := checkDSAParams(&key.PublicKey.Parameters); err != nil {
return nil, err
}
return &dsaPrivateKey{key}, nil
}
type wrappedSigner struct {
signer crypto.Signer
pubKey PublicKey
}
// NewSignerFromSigner takes any crypto.Signer implementation and
// returns a corresponding Signer interface. This can be used, for
// example, with keys kept in hardware modules.
func NewSignerFromSigner(signer crypto.Signer) (Signer, error) {
pubKey, err := NewPublicKey(signer.Public())
if err != nil {
return nil, err
}
return &wrappedSigner{signer, pubKey}, nil
}
func (s *wrappedSigner) PublicKey() PublicKey {
return s.pubKey
}
func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
return s.SignWithAlgorithm(rand, data, s.pubKey.Type())
}
func (s *wrappedSigner) Algorithms() []string {
return algorithmsForKeyFormat(s.pubKey.Type())
}
func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
if algorithm == "" {
algorithm = s.pubKey.Type()
}
if !slices.Contains(s.Algorithms(), algorithm) {
return nil, fmt.Errorf("ssh: unsupported signature algorithm %q for key format %q", algorithm, s.pubKey.Type())
}
hashFunc, err := hashFunc(algorithm)
if err != nil {
return nil, err
}
var digest []byte
if hashFunc != 0 {
h := hashFunc.New()
h.Write(data)
digest = h.Sum(nil)
} else {
digest = data
}
signature, err := s.signer.Sign(rand, digest, hashFunc)
if err != nil {
return nil, err
}
// crypto.Signer.Sign is expected to return an ASN.1-encoded signature
// for ECDSA and DSA, but that's not the encoding expected by SSH, so
// re-encode.
switch s.pubKey.(type) {
case *ecdsaPublicKey, *dsaPublicKey:
type asn1Signature struct {
R, S *big.Int
}
asn1Sig := new(asn1Signature)
_, err := asn1.Unmarshal(signature, asn1Sig)
if err != nil {
return nil, err
}
switch s.pubKey.(type) {
case *ecdsaPublicKey:
signature = Marshal(asn1Sig)
case *dsaPublicKey:
signature = make([]byte, 40)
r := asn1Sig.R.Bytes()
s := asn1Sig.S.Bytes()
copy(signature[20-len(r):20], r)
copy(signature[40-len(s):40], s)
}
}
return &Signature{
Format: algorithm,
Blob: signature,
}, nil
}
// NewPublicKey takes an *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey,
// or ed25519.PublicKey returns a corresponding PublicKey instance.
// ECDSA keys must use P-256, P-384 or P-521.
func NewPublicKey(key interface{}) (PublicKey, error) {
switch key := key.(type) {
case *rsa.PublicKey:
return (*rsaPublicKey)(key), nil
case *ecdsa.PublicKey:
if !supportedEllipticCurve(key.Curve) {
return nil, errors.New("ssh: only P-256, P-384 and P-521 EC keys are supported")
}
return (*ecdsaPublicKey)(key), nil
case *dsa.PublicKey:
return (*dsaPublicKey)(key), nil
case ed25519.PublicKey:
if l := len(key); l != ed25519.PublicKeySize {
return nil, fmt.Errorf("ssh: invalid size %d for Ed25519 public key", l)
}
return ed25519PublicKey(key), nil
default:
return nil, fmt.Errorf("ssh: unsupported key type %T", key)
}
}
// ParsePrivateKey returns a Signer from a PEM encoded private key. It supports
// the same keys as ParseRawPrivateKey. If the private key is encrypted, it
// will return a PassphraseMissingError.
func ParsePrivateKey(pemBytes []byte) (Signer, error) {
key, err := ParseRawPrivateKey(pemBytes)
if err != nil {
return nil, err
}
return NewSignerFromKey(key)
}
// ParsePrivateKeyWithPassphrase returns a Signer from a PEM encoded private
// key and passphrase. It supports the same keys as
// ParseRawPrivateKeyWithPassphrase.
func ParsePrivateKeyWithPassphrase(pemBytes, passphrase []byte) (Signer, error) {
key, err := ParseRawPrivateKeyWithPassphrase(pemBytes, passphrase)
if err != nil {
return nil, err
}
return NewSignerFromKey(key)
}
// encryptedBlock tells whether a private key is
// encrypted by examining its Proc-Type header
// for a mention of ENCRYPTED
// according to RFC 1421 Section 4.6.1.1.
func encryptedBlock(block *pem.Block) bool {
return strings.Contains(block.Headers["Proc-Type"], "ENCRYPTED")
}
// A PassphraseMissingError indicates that parsing this private key requires a
// passphrase. Use ParsePrivateKeyWithPassphrase.
type PassphraseMissingError struct {
// PublicKey will be set if the private key format includes an unencrypted
// public key along with the encrypted private key.
PublicKey PublicKey
}
func (*PassphraseMissingError) Error() string {
return "ssh: this private key is passphrase protected"
}
// ParseRawPrivateKey returns a private key from a PEM encoded private key. It supports
// RSA, DSA, ECDSA, and Ed25519 private keys in PKCS#1, PKCS#8, OpenSSL, and OpenSSH
// formats. If the private key is encrypted, it will return a PassphraseMissingError.
func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) {
block, _ := pem.Decode(pemBytes)
if block == nil {
return nil, errors.New("ssh: no key found")
}
if encryptedBlock(block) {
return nil, &PassphraseMissingError{}
}
switch block.Type {
case "RSA PRIVATE KEY":
return x509.ParsePKCS1PrivateKey(block.Bytes)
// RFC5208 - https://tools.ietf.org/html/rfc5208
case "PRIVATE KEY":
return x509.ParsePKCS8PrivateKey(block.Bytes)
case "EC PRIVATE KEY":
return x509.ParseECPrivateKey(block.Bytes)
case "DSA PRIVATE KEY":
return ParseDSAPrivateKey(block.Bytes)
case "OPENSSH PRIVATE KEY":
return parseOpenSSHPrivateKey(block.Bytes, unencryptedOpenSSHKey)
default:
return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type)
}
}
// ParseRawPrivateKeyWithPassphrase returns a private key decrypted with
// passphrase from a PEM encoded private key. If the passphrase is wrong, it
// will return x509.IncorrectPasswordError.
func ParseRawPrivateKeyWithPassphrase(pemBytes, passphrase []byte) (interface{}, error) {
block, _ := pem.Decode(pemBytes)
if block == nil {
return nil, errors.New("ssh: no key found")
}
if block.Type == "OPENSSH PRIVATE KEY" {
return parseOpenSSHPrivateKey(block.Bytes, passphraseProtectedOpenSSHKey(passphrase))
}
if !encryptedBlock(block) || !x509.IsEncryptedPEMBlock(block) {
return nil, errors.New("ssh: not an encrypted key")
}
buf, err := x509.DecryptPEMBlock(block, passphrase)
if err != nil {
if err == x509.IncorrectPasswordError {
return nil, err
}
return nil, fmt.Errorf("ssh: cannot decode encrypted private keys: %v", err)
}
var result interface{}
switch block.Type {
case "RSA PRIVATE KEY":
result, err = x509.ParsePKCS1PrivateKey(buf)
case "EC PRIVATE KEY":
result, err = x509.ParseECPrivateKey(buf)
case "DSA PRIVATE KEY":
result, err = ParseDSAPrivateKey(buf)
default:
err = fmt.Errorf("ssh: unsupported key type %q", block.Type)
}
// Because of deficiencies in the format, DecryptPEMBlock does not always
// detect an incorrect password. In these cases decrypted DER bytes is
// random noise. If the parsing of the key returns an asn1.StructuralError
// we return x509.IncorrectPasswordError.
if _, ok := err.(asn1.StructuralError); ok {
return nil, x509.IncorrectPasswordError
}
return result, err
}
// ParseDSAPrivateKey returns a DSA private key from its ASN.1 DER encoding, as
// specified by the OpenSSL DSA man page.
func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) {
var k struct {
Version int
P *big.Int
Q *big.Int
G *big.Int
Pub *big.Int
Priv *big.Int
}
rest, err := asn1.Unmarshal(der, &k)
if err != nil {
return nil, errors.New("ssh: failed to parse DSA key: " + err.Error())
}
if len(rest) > 0 {
return nil, errors.New("ssh: garbage after DSA key")
}
return &dsa.PrivateKey{
PublicKey: dsa.PublicKey{
Parameters: dsa.Parameters{
P: k.P,
Q: k.Q,
G: k.G,
},
Y: k.Pub,
},
X: k.Priv,
}, nil
}
func unencryptedOpenSSHKey(cipherName, kdfName, kdfOpts string, privKeyBlock []byte) ([]byte, error) {
if kdfName != "none" || cipherName != "none" {
return nil, &PassphraseMissingError{}
}
if kdfOpts != "" {
return nil, errors.New("ssh: invalid openssh private key")
}
return privKeyBlock, nil
}
func passphraseProtectedOpenSSHKey(passphrase []byte) openSSHDecryptFunc {
return func(cipherName, kdfName, kdfOpts string, privKeyBlock []byte) ([]byte, error) {
if kdfName == "none" || cipherName == "none" {
return nil, errors.New("ssh: key is not password protected")
}
if kdfName != "bcrypt" {
return nil, fmt.Errorf("ssh: unknown KDF %q, only supports %q", kdfName, "bcrypt")
}
var opts struct {
Salt string
Rounds uint32
}
if err := Unmarshal([]byte(kdfOpts), &opts); err != nil {
return nil, err
}
k, err := bcrypt_pbkdf.Key(passphrase, []byte(opts.Salt), int(opts.Rounds), 32+16)
if err != nil {
return nil, err
}
key, iv := k[:32], k[32:]
c, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
switch cipherName {
case "aes256-ctr":
ctr := cipher.NewCTR(c, iv)
ctr.XORKeyStream(privKeyBlock, privKeyBlock)
case "aes256-cbc":
if len(privKeyBlock)%c.BlockSize() != 0 {
return nil, fmt.Errorf("ssh: invalid encrypted private key length, not a multiple of the block size")
}
cbc := cipher.NewCBCDecrypter(c, iv)
cbc.CryptBlocks(privKeyBlock, privKeyBlock)
default:
return nil, fmt.Errorf("ssh: unknown cipher %q, only supports %q or %q", cipherName, "aes256-ctr", "aes256-cbc")
}
return privKeyBlock, nil
}
}
func unencryptedOpenSSHMarshaler(privKeyBlock []byte) ([]byte, string, string, string, error) {
key := generateOpenSSHPadding(privKeyBlock, 8)
return key, "none", "none", "", nil
}
func passphraseProtectedOpenSSHMarshaler(passphrase []byte) openSSHEncryptFunc {
return func(privKeyBlock []byte) ([]byte, string, string, string, error) {
salt := make([]byte, 16)
if _, err := rand.Read(salt); err != nil {
return nil, "", "", "", err
}
opts := struct {
Salt []byte
Rounds uint32
}{salt, 16}
// Derive key to encrypt the private key block.
k, err := bcrypt_pbkdf.Key(passphrase, salt, int(opts.Rounds), 32+aes.BlockSize)
if err != nil {
return nil, "", "", "", err
}
// Add padding matching the block size of AES.
keyBlock := generateOpenSSHPadding(privKeyBlock, aes.BlockSize)
// Encrypt the private key using the derived secret.
dst := make([]byte, len(keyBlock))
key, iv := k[:32], k[32:]
block, err := aes.NewCipher(key)
if err != nil {
return nil, "", "", "", err
}
stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(dst, keyBlock)
return dst, "aes256-ctr", "bcrypt", string(Marshal(opts)), nil
}
}
const privateKeyAuthMagic = "openssh-key-v1\x00"
type openSSHDecryptFunc func(CipherName, KdfName, KdfOpts string, PrivKeyBlock []byte) ([]byte, error)
type openSSHEncryptFunc func(PrivKeyBlock []byte) (ProtectedKeyBlock []byte, cipherName, kdfName, kdfOptions string, err error)
type openSSHEncryptedPrivateKey struct {
CipherName string
KdfName string
KdfOpts string
NumKeys uint32
PubKey []byte
PrivKeyBlock []byte
Rest []byte `ssh:"rest"`
}
type openSSHPrivateKey struct {
Check1 uint32
Check2 uint32
Keytype string
Rest []byte `ssh:"rest"`
}
type openSSHRSAPrivateKey struct {
N *big.Int
E *big.Int
D *big.Int
Iqmp *big.Int
P *big.Int
Q *big.Int
Comment string
Pad []byte `ssh:"rest"`
}
type openSSHEd25519PrivateKey struct {
Pub []byte
Priv []byte
Comment string
Pad []byte `ssh:"rest"`
}
type openSSHECDSAPrivateKey struct {
Curve string
Pub []byte
D *big.Int
Comment string
Pad []byte `ssh:"rest"`
}
// parseOpenSSHPrivateKey parses an OpenSSH private key, using the decrypt
// function to unwrap the encrypted portion. unencryptedOpenSSHKey can be used
// as the decrypt function to parse an unencrypted private key. See
// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key.
func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (crypto.PrivateKey, error) {
if len(key) < len(privateKeyAuthMagic) || string(key[:len(privateKeyAuthMagic)]) != privateKeyAuthMagic {
return nil, errors.New("ssh: invalid openssh private key format")
}
remaining := key[len(privateKeyAuthMagic):]
var w openSSHEncryptedPrivateKey
if err := Unmarshal(remaining, &w); err != nil {
return nil, err
}
if w.NumKeys != 1 {
// We only support single key files, and so does OpenSSH.
// https://github.com/openssh/openssh-portable/blob/4103a3ec7/sshkey.c#L4171
return nil, errors.New("ssh: multi-key files are not supported")
}
privKeyBlock, err := decrypt(w.CipherName, w.KdfName, w.KdfOpts, w.PrivKeyBlock)
if err != nil {
if err, ok := err.(*PassphraseMissingError); ok {
pub, errPub := ParsePublicKey(w.PubKey)
if errPub != nil {
return nil, fmt.Errorf("ssh: failed to parse embedded public key: %v", errPub)
}
err.PublicKey = pub
}
return nil, err
}
var pk1 openSSHPrivateKey
if err := Unmarshal(privKeyBlock, &pk1); err != nil || pk1.Check1 != pk1.Check2 {
if w.CipherName != "none" {
return nil, x509.IncorrectPasswordError
}
return nil, errors.New("ssh: malformed OpenSSH key")
}
switch pk1.Keytype {
case KeyAlgoRSA:
var key openSSHRSAPrivateKey
if err := Unmarshal(pk1.Rest, &key); err != nil {
return nil, err
}
if err := checkOpenSSHKeyPadding(key.Pad); err != nil {
return nil, err
}
pk := &rsa.PrivateKey{
PublicKey: rsa.PublicKey{
N: key.N,
E: int(key.E.Int64()),
},
D: key.D,
Primes: []*big.Int{key.P, key.Q},
}
if err := pk.Validate(); err != nil {
return nil, err
}
pk.Precompute()
return pk, nil
case KeyAlgoED25519:
var key openSSHEd25519PrivateKey
if err := Unmarshal(pk1.Rest, &key); err != nil {
return nil, err
}
if len(key.Priv) != ed25519.PrivateKeySize {
return nil, errors.New("ssh: private key unexpected length")
}
if err := checkOpenSSHKeyPadding(key.Pad); err != nil {
return nil, err
}
pk := ed25519.PrivateKey(make([]byte, ed25519.PrivateKeySize))
copy(pk, key.Priv)
return &pk, nil
case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521:
var key openSSHECDSAPrivateKey
if err := Unmarshal(pk1.Rest, &key); err != nil {
return nil, err
}
if err := checkOpenSSHKeyPadding(key.Pad); err != nil {
return nil, err
}
var curve elliptic.Curve
switch key.Curve {
case "nistp256":
curve = elliptic.P256()
case "nistp384":
curve = elliptic.P384()
case "nistp521":
curve = elliptic.P521()
default:
return nil, errors.New("ssh: unhandled elliptic curve: " + key.Curve)
}
X, Y := elliptic.Unmarshal(curve, key.Pub)
if X == nil || Y == nil {
return nil, errors.New("ssh: failed to unmarshal public key")
}
if key.D.Cmp(curve.Params().N) >= 0 {
return nil, errors.New("ssh: scalar is out of range")
}
x, y := curve.ScalarBaseMult(key.D.Bytes())
if x.Cmp(X) != 0 || y.Cmp(Y) != 0 {
return nil, errors.New("ssh: public key does not match private key")
}
return &ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
Curve: curve,
X: X,
Y: Y,
},
D: key.D,
}, nil
default:
return nil, errors.New("ssh: unhandled key type")
}
}
func marshalOpenSSHPrivateKey(key crypto.PrivateKey, comment string, encrypt openSSHEncryptFunc) (*pem.Block, error) {
var w openSSHEncryptedPrivateKey
var pk1 openSSHPrivateKey
// Random check bytes.
var check uint32
if err := binary.Read(rand.Reader, binary.BigEndian, &check); err != nil {
return nil, err
}
pk1.Check1 = check
pk1.Check2 = check
w.NumKeys = 1
// Use a []byte directly on ed25519 keys.
if k, ok := key.(*ed25519.PrivateKey); ok {
key = *k
}
switch k := key.(type) {
case *rsa.PrivateKey:
E := new(big.Int).SetInt64(int64(k.PublicKey.E))
// Marshal public key:
// E and N are in reversed order in the public and private key.
pubKey := struct {
KeyType string
E *big.Int
N *big.Int
}{
KeyAlgoRSA,
E, k.PublicKey.N,
}
w.PubKey = Marshal(pubKey)
// Marshal private key.
key := openSSHRSAPrivateKey{
N: k.PublicKey.N,
E: E,
D: k.D,
Iqmp: k.Precomputed.Qinv,
P: k.Primes[0],
Q: k.Primes[1],
Comment: comment,
}
pk1.Keytype = KeyAlgoRSA
pk1.Rest = Marshal(key)
case ed25519.PrivateKey:
pub := make([]byte, ed25519.PublicKeySize)
priv := make([]byte, ed25519.PrivateKeySize)
copy(pub, k[32:])
copy(priv, k)
// Marshal public key.
pubKey := struct {
KeyType string
Pub []byte
}{
KeyAlgoED25519, pub,
}
w.PubKey = Marshal(pubKey)
// Marshal private key.
key := openSSHEd25519PrivateKey{
Pub: pub,
Priv: priv,
Comment: comment,
}
pk1.Keytype = KeyAlgoED25519
pk1.Rest = Marshal(key)
case *ecdsa.PrivateKey:
var curve, keyType string
switch name := k.Curve.Params().Name; name {
case "P-256":
curve = "nistp256"
keyType = KeyAlgoECDSA256
case "P-384":
curve = "nistp384"
keyType = KeyAlgoECDSA384
case "P-521":
curve = "nistp521"
keyType = KeyAlgoECDSA521
default:
return nil, errors.New("ssh: unhandled elliptic curve " + name)
}
pub := elliptic.Marshal(k.Curve, k.PublicKey.X, k.PublicKey.Y)
// Marshal public key.
pubKey := struct {
KeyType string
Curve string
Pub []byte
}{
keyType, curve, pub,
}
w.PubKey = Marshal(pubKey)
// Marshal private key.
key := openSSHECDSAPrivateKey{
Curve: curve,
Pub: pub,
D: k.D,
Comment: comment,
}
pk1.Keytype = keyType
pk1.Rest = Marshal(key)
default:
return nil, fmt.Errorf("ssh: unsupported key type %T", k)
}
var err error
// Add padding and encrypt the key if necessary.
w.PrivKeyBlock, w.CipherName, w.KdfName, w.KdfOpts, err = encrypt(Marshal(pk1))
if err != nil {
return nil, err
}
b := Marshal(w)
block := &pem.Block{
Type: "OPENSSH PRIVATE KEY",
Bytes: append([]byte(privateKeyAuthMagic), b...),
}
return block, nil
}
func checkOpenSSHKeyPadding(pad []byte) error {
for i, b := range pad {
if int(b) != i+1 {
return errors.New("ssh: padding not as expected")
}
}
return nil
}
func generateOpenSSHPadding(block []byte, blockSize int) []byte {
for i, l := 0, len(block); (l+i)%blockSize != 0; i++ {
block = append(block, byte(i+1))
}
return block
}
// FingerprintLegacyMD5 returns the user presentation of the key's
// fingerprint as described by RFC 4716 section 4.
func FingerprintLegacyMD5(pubKey PublicKey) string {
md5sum := md5.Sum(pubKey.Marshal())
hexarray := make([]string, len(md5sum))
for i, c := range md5sum {
hexarray[i] = hex.EncodeToString([]byte{c})
}
return strings.Join(hexarray, ":")
}
// FingerprintSHA256 returns the user presentation of the key's
// fingerprint as unpadded base64 encoded sha256 hash.
// This format was introduced from OpenSSH 6.8.
// https://www.openssh.com/txt/release-6.8
// https://tools.ietf.org/html/rfc4648#section-3.2 (unpadded base64 encoding)
func FingerprintSHA256(pubKey PublicKey) string {
sha256sum := sha256.Sum256(pubKey.Marshal())
hash := base64.RawStdEncoding.EncodeToString(sha256sum[:])
return "SHA256:" + hash
}
// 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 knownhosts implements a parser for the OpenSSH known_hosts
// host key database, and provides utility functions for writing
// OpenSSH compliant known_hosts files.
package knownhosts
import (
"bufio"
"bytes"
"crypto/hmac"
"crypto/rand"
"crypto/sha1"
"encoding/base64"
"errors"
"fmt"
"io"
"net"
"os"
"strings"
"golang.org/x/crypto/ssh"
)
// See the sshd manpage
// (http://man.openbsd.org/sshd#SSH_KNOWN_HOSTS_FILE_FORMAT) for
// background.
type addr struct{ host, port string }
func (a *addr) String() string {
h := a.host
if strings.Contains(h, ":") {
h = "[" + h + "]"
}
return h + ":" + a.port
}
type matcher interface {
match(addr) bool
}
type hostPattern struct {
negate bool
addr addr
}
func (p *hostPattern) String() string {
n := ""
if p.negate {
n = "!"
}
return n + p.addr.String()
}
type hostPatterns []hostPattern
func (ps hostPatterns) match(a addr) bool {
matched := false
for _, p := range ps {
if !p.match(a) {
continue
}
if p.negate {
return false
}
matched = true
}
return matched
}
// See
// https://android.googlesource.com/platform/external/openssh/+/ab28f5495c85297e7a597c1ba62e996416da7c7e/addrmatch.c
// The matching of * has no regard for separators, unlike filesystem globs
func wildcardMatch(pat []byte, str []byte) bool {
for {
if len(pat) == 0 {
return len(str) == 0
}
if len(str) == 0 {
return false
}
if pat[0] == '*' {
if len(pat) == 1 {
return true
}
for j := range str {
if wildcardMatch(pat[1:], str[j:]) {
return true
}
}
return false
}
if pat[0] == '?' || pat[0] == str[0] {
pat = pat[1:]
str = str[1:]
} else {
return false
}
}
}
func (p *hostPattern) match(a addr) bool {
return wildcardMatch([]byte(p.addr.host), []byte(a.host)) && p.addr.port == a.port
}
type keyDBLine struct {
cert bool
matcher matcher
knownKey KnownKey
}
func serialize(k ssh.PublicKey) string {
return k.Type() + " " + base64.StdEncoding.EncodeToString(k.Marshal())
}
func (l *keyDBLine) match(a addr) bool {
return l.matcher.match(a)
}
type hostKeyDB struct {
// Serialized version of revoked keys
revoked map[string]*KnownKey
lines []keyDBLine
}
func newHostKeyDB() *hostKeyDB {
db := &hostKeyDB{
revoked: make(map[string]*KnownKey),
}
return db
}
func keyEq(a, b ssh.PublicKey) bool {
return bytes.Equal(a.Marshal(), b.Marshal())
}
// IsHostAuthority can be used as a callback in ssh.CertChecker
func (db *hostKeyDB) IsHostAuthority(remote ssh.PublicKey, address string) bool {
h, p, err := net.SplitHostPort(address)
if err != nil {
return false
}
a := addr{host: h, port: p}
for _, l := range db.lines {
if l.cert && keyEq(l.knownKey.Key, remote) && l.match(a) {
return true
}
}
return false
}
// IsRevoked can be used as a callback in ssh.CertChecker
func (db *hostKeyDB) IsRevoked(key *ssh.Certificate) bool {
_, ok := db.revoked[string(key.Marshal())]
return ok
}
const markerCert = "@cert-authority"
const markerRevoked = "@revoked"
func nextWord(line []byte) (string, []byte) {
i := bytes.IndexAny(line, "\t ")
if i == -1 {
return string(line), nil
}
return string(line[:i]), bytes.TrimSpace(line[i:])
}
func parseLine(line []byte) (marker, host string, key ssh.PublicKey, err error) {
if w, next := nextWord(line); w == markerCert || w == markerRevoked {
marker = w
line = next
}
host, line = nextWord(line)
if len(line) == 0 {
return "", "", nil, errors.New("knownhosts: missing host pattern")
}
// ignore the keytype as it's in the key blob anyway.
_, line = nextWord(line)
if len(line) == 0 {
return "", "", nil, errors.New("knownhosts: missing key type pattern")
}
keyBlob, _ := nextWord(line)
keyBytes, err := base64.StdEncoding.DecodeString(keyBlob)
if err != nil {
return "", "", nil, err
}
key, err = ssh.ParsePublicKey(keyBytes)
if err != nil {
return "", "", nil, err
}
return marker, host, key, nil
}
func (db *hostKeyDB) parseLine(line []byte, filename string, linenum int) error {
marker, pattern, key, err := parseLine(line)
if err != nil {
return err
}
if marker == markerRevoked {
db.revoked[string(key.Marshal())] = &KnownKey{
Key: key,
Filename: filename,
Line: linenum,
}
return nil
}
entry := keyDBLine{
cert: marker == markerCert,
knownKey: KnownKey{
Filename: filename,
Line: linenum,
Key: key,
},
}
if pattern[0] == '|' {
entry.matcher, err = newHashedHost(pattern)
} else {
entry.matcher, err = newHostnameMatcher(pattern)
}
if err != nil {
return err
}
db.lines = append(db.lines, entry)
return nil
}
func newHostnameMatcher(pattern string) (matcher, error) {
var hps hostPatterns
for _, p := range strings.Split(pattern, ",") {
if len(p) == 0 {
continue
}
var a addr
var negate bool
if p[0] == '!' {
negate = true
p = p[1:]
}
if len(p) == 0 {
return nil, errors.New("knownhosts: negation without following hostname")
}
var err error
if p[0] == '[' {
a.host, a.port, err = net.SplitHostPort(p)
if err != nil {
return nil, err
}
} else {
a.host, a.port, err = net.SplitHostPort(p)
if err != nil {
a.host = p
a.port = "22"
}
}
hps = append(hps, hostPattern{
negate: negate,
addr: a,
})
}
return hps, nil
}
// KnownKey represents a key declared in a known_hosts file.
type KnownKey struct {
Key ssh.PublicKey
Filename string
Line int
}
func (k *KnownKey) String() string {
return fmt.Sprintf("%s:%d: %s", k.Filename, k.Line, serialize(k.Key))
}
// KeyError is returned if we did not find the key in the host key
// database, or there was a mismatch. Typically, in batch
// applications, this should be interpreted as failure. Interactive
// applications can offer an interactive prompt to the user.
type KeyError struct {
// Want holds the accepted host keys. For each key algorithm,
// there can be multiple hostkeys. If Want is empty, the host
// is unknown. If Want is non-empty, there was a mismatch, which
// can signify a MITM attack.
Want []KnownKey
}
func (u *KeyError) Error() string {
if len(u.Want) == 0 {
return "knownhosts: key is unknown"
}
return "knownhosts: key mismatch"
}
// RevokedError is returned if we found a key that was revoked.
type RevokedError struct {
Revoked KnownKey
}
func (r *RevokedError) Error() string {
return "knownhosts: key is revoked"
}
// check checks a key against the host database. This should not be
// used for verifying certificates.
func (db *hostKeyDB) check(address string, remote net.Addr, remoteKey ssh.PublicKey) error {
if revoked := db.revoked[string(remoteKey.Marshal())]; revoked != nil {
return &RevokedError{Revoked: *revoked}
}
host, port, err := net.SplitHostPort(remote.String())
if err != nil {
return fmt.Errorf("knownhosts: SplitHostPort(%s): %v", remote, err)
}
hostToCheck := addr{host, port}
if address != "" {
// Give preference to the hostname if available.
host, port, err := net.SplitHostPort(address)
if err != nil {
return fmt.Errorf("knownhosts: SplitHostPort(%s): %v", address, err)
}
hostToCheck = addr{host, port}
}
return db.checkAddr(hostToCheck, remoteKey)
}
// checkAddr checks if we can find the given public key for the
// given address. If we only find an entry for the IP address,
// or only the hostname, then this still succeeds.
func (db *hostKeyDB) checkAddr(a addr, remoteKey ssh.PublicKey) error {
// TODO(hanwen): are these the right semantics? What if there
// is just a key for the IP address, but not for the
// hostname?
keyErr := &KeyError{}
for _, l := range db.lines {
if !l.match(a) {
continue
}
keyErr.Want = append(keyErr.Want, l.knownKey)
if keyEq(l.knownKey.Key, remoteKey) {
return nil
}
}
return keyErr
}
// The Read function parses file contents.
func (db *hostKeyDB) Read(r io.Reader, filename string) error {
scanner := bufio.NewScanner(r)
lineNum := 0
for scanner.Scan() {
lineNum++
line := scanner.Bytes()
line = bytes.TrimSpace(line)
if len(line) == 0 || line[0] == '#' {
continue
}
if err := db.parseLine(line, filename, lineNum); err != nil {
return fmt.Errorf("knownhosts: %s:%d: %v", filename, lineNum, err)
}
}
return scanner.Err()
}
// New creates a host key callback from the given OpenSSH host key
// files. The returned callback is for use in
// ssh.ClientConfig.HostKeyCallback. By preference, the key check
// operates on the hostname if available, i.e. if a server changes its
// IP address, the host key check will still succeed, even though a
// record of the new IP address is not available.
func New(files ...string) (ssh.HostKeyCallback, error) {
db := newHostKeyDB()
for _, fn := range files {
f, err := os.Open(fn)
if err != nil {
return nil, err
}
defer f.Close()
if err := db.Read(f, fn); err != nil {
return nil, err
}
}
var certChecker ssh.CertChecker
certChecker.IsHostAuthority = db.IsHostAuthority
certChecker.IsRevoked = db.IsRevoked
certChecker.HostKeyFallback = db.check
return certChecker.CheckHostKey, nil
}
// Normalize normalizes an address into the form used in known_hosts. Supports
// IPv4, hostnames, bracketed IPv6. Any other non-standard formats are returned
// with minimal transformation.
func Normalize(address string) string {
const defaultSSHPort = "22"
host, port, err := net.SplitHostPort(address)
if err != nil {
host = address
port = defaultSSHPort
}
if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
host = host[1 : len(host)-1]
}
if port == defaultSSHPort {
return host
}
return "[" + host + "]:" + port
}
// Line returns a line to add append to the known_hosts files.
func Line(addresses []string, key ssh.PublicKey) string {
var trimmed []string
for _, a := range addresses {
trimmed = append(trimmed, Normalize(a))
}
return strings.Join(trimmed, ",") + " " + serialize(key)
}
// HashHostname hashes the given hostname. The hostname is not
// normalized before hashing.
func HashHostname(hostname string) string {
// TODO(hanwen): check if we can safely normalize this always.
salt := make([]byte, sha1.Size)
_, err := rand.Read(salt)
if err != nil {
panic(fmt.Sprintf("crypto/rand failure %v", err))
}
hash := hashHost(hostname, salt)
return encodeHash(sha1HashType, salt, hash)
}
func decodeHash(encoded string) (hashType string, salt, hash []byte, err error) {
if len(encoded) == 0 || encoded[0] != '|' {
err = errors.New("knownhosts: hashed host must start with '|'")
return
}
components := strings.Split(encoded, "|")
if len(components) != 4 {
err = fmt.Errorf("knownhosts: got %d components, want 3", len(components))
return
}
hashType = components[1]
if salt, err = base64.StdEncoding.DecodeString(components[2]); err != nil {
return
}
if hash, err = base64.StdEncoding.DecodeString(components[3]); err != nil {
return
}
return
}
func encodeHash(typ string, salt []byte, hash []byte) string {
return strings.Join([]string{"",
typ,
base64.StdEncoding.EncodeToString(salt),
base64.StdEncoding.EncodeToString(hash),
}, "|")
}
// See https://android.googlesource.com/platform/external/openssh/+/ab28f5495c85297e7a597c1ba62e996416da7c7e/hostfile.c#120
func hashHost(hostname string, salt []byte) []byte {
mac := hmac.New(sha1.New, salt)
mac.Write([]byte(hostname))
return mac.Sum(nil)
}
type hashedHost struct {
salt []byte
hash []byte
}
const sha1HashType = "1"
func newHashedHost(encoded string) (*hashedHost, error) {
typ, salt, hash, err := decodeHash(encoded)
if err != nil {
return nil, err
}
// The type field seems for future algorithm agility, but it's
// actually hardcoded in openssh currently, see
// https://android.googlesource.com/platform/external/openssh/+/ab28f5495c85297e7a597c1ba62e996416da7c7e/hostfile.c#120
if typ != sha1HashType {
return nil, fmt.Errorf("knownhosts: got hash type %s, must be '1'", typ)
}
return &hashedHost{salt: salt, hash: hash}, nil
}
func (h *hashedHost) match(a addr) bool {
return bytes.Equal(hashHost(Normalize(a.String()), h.salt), h.hash)
}
// 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.
package ssh
// Message authentication support
import (
"crypto/fips140"
"crypto/hmac"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"hash"
"slices"
)
type macMode struct {
keySize int
etm bool
new func(key []byte) hash.Hash
}
// truncatingMAC wraps around a hash.Hash and truncates the output digest to
// a given size.
type truncatingMAC struct {
length int
hmac hash.Hash
}
func (t truncatingMAC) Write(data []byte) (int, error) {
return t.hmac.Write(data)
}
func (t truncatingMAC) Sum(in []byte) []byte {
out := t.hmac.Sum(in)
return out[:len(in)+t.length]
}
func (t truncatingMAC) Reset() {
t.hmac.Reset()
}
func (t truncatingMAC) Size() int {
return t.length
}
func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() }
// macModes defines the supported MACs. MACs not included are not supported
// and will not be negotiated, even if explicitly configured. When FIPS mode is
// enabled, only FIPS-approved algorithms are included.
var macModes = map[string]*macMode{}
func init() {
macModes[HMACSHA512ETM] = &macMode{64, true, func(key []byte) hash.Hash {
return hmac.New(sha512.New, key)
}}
macModes[HMACSHA256ETM] = &macMode{32, true, func(key []byte) hash.Hash {
return hmac.New(sha256.New, key)
}}
macModes[HMACSHA512] = &macMode{64, false, func(key []byte) hash.Hash {
return hmac.New(sha512.New, key)
}}
macModes[HMACSHA256] = &macMode{32, false, func(key []byte) hash.Hash {
return hmac.New(sha256.New, key)
}}
if fips140.Enabled() {
defaultMACs = slices.DeleteFunc(defaultMACs, func(algo string) bool {
_, ok := macModes[algo]
return !ok
})
return
}
macModes[HMACSHA1] = &macMode{20, false, func(key []byte) hash.Hash {
return hmac.New(sha1.New, key)
}}
macModes[InsecureHMACSHA196] = &macMode{20, false, func(key []byte) hash.Hash {
return truncatingMAC{12, hmac.New(sha1.New, key)}
}}
}
// Copyright 2011 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 ssh
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"math/big"
"reflect"
"strconv"
"strings"
)
// These are SSH message type numbers. They are scattered around several
// documents but many were taken from [SSH-PARAMETERS].
const (
msgIgnore = 2
msgUnimplemented = 3
msgDebug = 4
msgNewKeys = 21
)
// SSH messages:
//
// These structures mirror the wire format of the corresponding SSH messages.
// They are marshaled using reflection with the marshal and unmarshal functions
// in this file. The only wrinkle is that a final member of type []byte with a
// ssh tag of "rest" receives the remainder of a packet when unmarshaling.
// See RFC 4253, section 11.1.
const msgDisconnect = 1
// disconnectMsg is the message that signals a disconnect. It is also
// the error type returned from mux.Wait()
type disconnectMsg struct {
Reason uint32 `sshtype:"1"`
Message string
Language string
}
func (d *disconnectMsg) Error() string {
return fmt.Sprintf("ssh: disconnect, reason %d: %s", d.Reason, d.Message)
}
// See RFC 4253, section 7.1.
const msgKexInit = 20
type kexInitMsg struct {
Cookie [16]byte `sshtype:"20"`
KexAlgos []string
ServerHostKeyAlgos []string
CiphersClientServer []string
CiphersServerClient []string
MACsClientServer []string
MACsServerClient []string
CompressionClientServer []string
CompressionServerClient []string
LanguagesClientServer []string
LanguagesServerClient []string
FirstKexFollows bool
Reserved uint32
}
// See RFC 4253, section 8.
// Diffie-Hellman
const msgKexDHInit = 30
type kexDHInitMsg struct {
X *big.Int `sshtype:"30"`
}
const msgKexECDHInit = 30
type kexECDHInitMsg struct {
ClientPubKey []byte `sshtype:"30"`
}
const msgKexECDHReply = 31
type kexECDHReplyMsg struct {
HostKey []byte `sshtype:"31"`
EphemeralPubKey []byte
Signature []byte
}
const msgKexDHReply = 31
type kexDHReplyMsg struct {
HostKey []byte `sshtype:"31"`
Y *big.Int
Signature []byte
}
// See RFC 4419, section 5.
const msgKexDHGexGroup = 31
type kexDHGexGroupMsg struct {
P *big.Int `sshtype:"31"`
G *big.Int
}
const msgKexDHGexInit = 32
type kexDHGexInitMsg struct {
X *big.Int `sshtype:"32"`
}
const msgKexDHGexReply = 33
type kexDHGexReplyMsg struct {
HostKey []byte `sshtype:"33"`
Y *big.Int
Signature []byte
}
const msgKexDHGexRequest = 34
type kexDHGexRequestMsg struct {
MinBits uint32 `sshtype:"34"`
PreferredBits uint32
MaxBits uint32
}
// See RFC 4253, section 10.
const msgServiceRequest = 5
type serviceRequestMsg struct {
Service string `sshtype:"5"`
}
// See RFC 4253, section 10.
const msgServiceAccept = 6
type serviceAcceptMsg struct {
Service string `sshtype:"6"`
}
// See RFC 8308, section 2.3
const msgExtInfo = 7
type extInfoMsg struct {
NumExtensions uint32 `sshtype:"7"`
Payload []byte `ssh:"rest"`
}
// See RFC 4252, section 5.
const msgUserAuthRequest = 50
type userAuthRequestMsg struct {
User string `sshtype:"50"`
Service string
Method string
Payload []byte `ssh:"rest"`
}
// Used for debug printouts of packets.
type userAuthSuccessMsg struct {
}
// See RFC 4252, section 5.1
const msgUserAuthFailure = 51
type userAuthFailureMsg struct {
Methods []string `sshtype:"51"`
PartialSuccess bool
}
// See RFC 4252, section 5.1
const msgUserAuthSuccess = 52
// See RFC 4252, section 5.4
const msgUserAuthBanner = 53
type userAuthBannerMsg struct {
Message string `sshtype:"53"`
// unused, but required to allow message parsing
Language string
}
// See RFC 4256, section 3.2
const msgUserAuthInfoRequest = 60
const msgUserAuthInfoResponse = 61
type userAuthInfoRequestMsg struct {
Name string `sshtype:"60"`
Instruction string
Language string
NumPrompts uint32
Prompts []byte `ssh:"rest"`
}
// See RFC 4254, section 5.1.
const msgChannelOpen = 90
type channelOpenMsg struct {
ChanType string `sshtype:"90"`
PeersID uint32
PeersWindow uint32
MaxPacketSize uint32
TypeSpecificData []byte `ssh:"rest"`
}
const msgChannelExtendedData = 95
const msgChannelData = 94
// Used for debug print outs of packets.
type channelDataMsg struct {
PeersID uint32 `sshtype:"94"`
Length uint32
Rest []byte `ssh:"rest"`
}
// See RFC 4254, section 5.1.
const msgChannelOpenConfirm = 91
type channelOpenConfirmMsg struct {
PeersID uint32 `sshtype:"91"`
MyID uint32
MyWindow uint32
MaxPacketSize uint32
TypeSpecificData []byte `ssh:"rest"`
}
// See RFC 4254, section 5.1.
const msgChannelOpenFailure = 92
type channelOpenFailureMsg struct {
PeersID uint32 `sshtype:"92"`
Reason RejectionReason
Message string
Language string
}
const msgChannelRequest = 98
type channelRequestMsg struct {
PeersID uint32 `sshtype:"98"`
Request string
WantReply bool
RequestSpecificData []byte `ssh:"rest"`
}
// See RFC 4254, section 5.4.
const msgChannelSuccess = 99
type channelRequestSuccessMsg struct {
PeersID uint32 `sshtype:"99"`
}
// See RFC 4254, section 5.4.
const msgChannelFailure = 100
type channelRequestFailureMsg struct {
PeersID uint32 `sshtype:"100"`
}
// See RFC 4254, section 5.3
const msgChannelClose = 97
type channelCloseMsg struct {
PeersID uint32 `sshtype:"97"`
}
// See RFC 4254, section 5.3
const msgChannelEOF = 96
type channelEOFMsg struct {
PeersID uint32 `sshtype:"96"`
}
// See RFC 4254, section 4
const msgGlobalRequest = 80
type globalRequestMsg struct {
Type string `sshtype:"80"`
WantReply bool
Data []byte `ssh:"rest"`
}
// See RFC 4254, section 4
const msgRequestSuccess = 81
type globalRequestSuccessMsg struct {
Data []byte `ssh:"rest" sshtype:"81"`
}
// See RFC 4254, section 4
const msgRequestFailure = 82
type globalRequestFailureMsg struct {
Data []byte `ssh:"rest" sshtype:"82"`
}
// See RFC 4254, section 5.2
const msgChannelWindowAdjust = 93
type windowAdjustMsg struct {
PeersID uint32 `sshtype:"93"`
AdditionalBytes uint32
}
// See RFC 4252, section 7
const msgUserAuthPubKeyOk = 60
type userAuthPubKeyOkMsg struct {
Algo string `sshtype:"60"`
PubKey []byte
}
// See RFC 4462, section 3
const msgUserAuthGSSAPIResponse = 60
type userAuthGSSAPIResponse struct {
SupportMech []byte `sshtype:"60"`
}
const msgUserAuthGSSAPIToken = 61
type userAuthGSSAPIToken struct {
Token []byte `sshtype:"61"`
}
const msgUserAuthGSSAPIMIC = 66
type userAuthGSSAPIMIC struct {
MIC []byte `sshtype:"66"`
}
// See RFC 4462, section 3.9
const msgUserAuthGSSAPIErrTok = 64
type userAuthGSSAPIErrTok struct {
ErrorToken []byte `sshtype:"64"`
}
// See RFC 4462, section 3.8
const msgUserAuthGSSAPIError = 65
type userAuthGSSAPIError struct {
MajorStatus uint32 `sshtype:"65"`
MinorStatus uint32
Message string
LanguageTag string
}
// Transport layer OpenSSH extension. See [PROTOCOL], section 1.9
const msgPing = 192
type pingMsg struct {
Data string `sshtype:"192"`
}
// Transport layer OpenSSH extension. See [PROTOCOL], section 1.9
const msgPong = 193
type pongMsg struct {
Data string `sshtype:"193"`
}
// typeTags returns the possible type bytes for the given reflect.Type, which
// should be a struct. The possible values are separated by a '|' character.
func typeTags(structType reflect.Type) (tags []byte) {
tagStr := structType.Field(0).Tag.Get("sshtype")
for _, tag := range strings.Split(tagStr, "|") {
i, err := strconv.Atoi(tag)
if err == nil {
tags = append(tags, byte(i))
}
}
return tags
}
func fieldError(t reflect.Type, field int, problem string) error {
if problem != "" {
problem = ": " + problem
}
return fmt.Errorf("ssh: unmarshal error for field %s of type %s%s", t.Field(field).Name, t.Name(), problem)
}
var errShortRead = errors.New("ssh: short read")
// Unmarshal parses data in SSH wire format into a structure. The out
// argument should be a pointer to struct. If the first member of the
// struct has the "sshtype" tag set to a '|'-separated set of numbers
// in decimal, the packet must start with one of those numbers. In
// case of error, Unmarshal returns a ParseError or
// UnexpectedMessageError.
func Unmarshal(data []byte, out interface{}) error {
v := reflect.ValueOf(out).Elem()
structType := v.Type()
expectedTypes := typeTags(structType)
var expectedType byte
if len(expectedTypes) > 0 {
expectedType = expectedTypes[0]
}
if len(data) == 0 {
return parseError(expectedType)
}
if len(expectedTypes) > 0 {
goodType := false
for _, e := range expectedTypes {
if e > 0 && data[0] == e {
goodType = true
break
}
}
if !goodType {
return fmt.Errorf("ssh: unexpected message type %d (expected one of %v)", data[0], expectedTypes)
}
data = data[1:]
}
var ok bool
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
t := field.Type()
switch t.Kind() {
case reflect.Bool:
if len(data) < 1 {
return errShortRead
}
field.SetBool(data[0] != 0)
data = data[1:]
case reflect.Array:
if t.Elem().Kind() != reflect.Uint8 {
return fieldError(structType, i, "array of unsupported type")
}
if len(data) < t.Len() {
return errShortRead
}
for j, n := 0, t.Len(); j < n; j++ {
field.Index(j).Set(reflect.ValueOf(data[j]))
}
data = data[t.Len():]
case reflect.Uint64:
var u64 uint64
if u64, data, ok = parseUint64(data); !ok {
return errShortRead
}
field.SetUint(u64)
case reflect.Uint32:
var u32 uint32
if u32, data, ok = parseUint32(data); !ok {
return errShortRead
}
field.SetUint(uint64(u32))
case reflect.Uint8:
if len(data) < 1 {
return errShortRead
}
field.SetUint(uint64(data[0]))
data = data[1:]
case reflect.String:
var s []byte
if s, data, ok = parseString(data); !ok {
return fieldError(structType, i, "")
}
field.SetString(string(s))
case reflect.Slice:
switch t.Elem().Kind() {
case reflect.Uint8:
if structType.Field(i).Tag.Get("ssh") == "rest" {
field.Set(reflect.ValueOf(data))
data = nil
} else {
var s []byte
if s, data, ok = parseString(data); !ok {
return errShortRead
}
field.Set(reflect.ValueOf(s))
}
case reflect.String:
var nl []string
if nl, data, ok = parseNameList(data); !ok {
return errShortRead
}
field.Set(reflect.ValueOf(nl))
default:
return fieldError(structType, i, "slice of unsupported type")
}
case reflect.Ptr:
if t == bigIntType {
var n *big.Int
if n, data, ok = parseInt(data); !ok {
return errShortRead
}
field.Set(reflect.ValueOf(n))
} else {
return fieldError(structType, i, "pointer to unsupported type")
}
default:
return fieldError(structType, i, fmt.Sprintf("unsupported type: %v", t))
}
}
if len(data) != 0 {
return parseError(expectedType)
}
return nil
}
// Marshal serializes the message in msg to SSH wire format. The msg
// argument should be a struct or pointer to struct. If the first
// member has the "sshtype" tag set to a number in decimal, that
// number is prepended to the result. If the last of member has the
// "ssh" tag set to "rest", its contents are appended to the output.
func Marshal(msg interface{}) []byte {
out := make([]byte, 0, 64)
return marshalStruct(out, msg)
}
func marshalStruct(out []byte, msg interface{}) []byte {
v := reflect.Indirect(reflect.ValueOf(msg))
msgTypes := typeTags(v.Type())
if len(msgTypes) > 0 {
out = append(out, msgTypes[0])
}
for i, n := 0, v.NumField(); i < n; i++ {
field := v.Field(i)
switch t := field.Type(); t.Kind() {
case reflect.Bool:
var v uint8
if field.Bool() {
v = 1
}
out = append(out, v)
case reflect.Array:
if t.Elem().Kind() != reflect.Uint8 {
panic(fmt.Sprintf("array of non-uint8 in field %d: %T", i, field.Interface()))
}
for j, l := 0, t.Len(); j < l; j++ {
out = append(out, uint8(field.Index(j).Uint()))
}
case reflect.Uint32:
out = appendU32(out, uint32(field.Uint()))
case reflect.Uint64:
out = appendU64(out, uint64(field.Uint()))
case reflect.Uint8:
out = append(out, uint8(field.Uint()))
case reflect.String:
s := field.String()
out = appendInt(out, len(s))
out = append(out, s...)
case reflect.Slice:
switch t.Elem().Kind() {
case reflect.Uint8:
if v.Type().Field(i).Tag.Get("ssh") != "rest" {
out = appendInt(out, field.Len())
}
out = append(out, field.Bytes()...)
case reflect.String:
offset := len(out)
out = appendU32(out, 0)
if n := field.Len(); n > 0 {
for j := 0; j < n; j++ {
f := field.Index(j)
if j != 0 {
out = append(out, ',')
}
out = append(out, f.String()...)
}
// overwrite length value
binary.BigEndian.PutUint32(out[offset:], uint32(len(out)-offset-4))
}
default:
panic(fmt.Sprintf("slice of unknown type in field %d: %T", i, field.Interface()))
}
case reflect.Ptr:
if t == bigIntType {
var n *big.Int
nValue := reflect.ValueOf(&n)
nValue.Elem().Set(field)
needed := intLength(n)
oldLength := len(out)
if cap(out)-len(out) < needed {
newOut := make([]byte, len(out), 2*(len(out)+needed))
copy(newOut, out)
out = newOut
}
out = out[:oldLength+needed]
marshalInt(out[oldLength:], n)
} else {
panic(fmt.Sprintf("pointer to unknown type in field %d: %T", i, field.Interface()))
}
}
}
return out
}
var bigOne = big.NewInt(1)
func parseString(in []byte) (out, rest []byte, ok bool) {
if len(in) < 4 {
return
}
length := binary.BigEndian.Uint32(in)
in = in[4:]
if uint32(len(in)) < length {
return
}
out = in[:length]
rest = in[length:]
ok = true
return
}
var (
comma = []byte{','}
emptyNameList = []string{}
)
func parseNameList(in []byte) (out []string, rest []byte, ok bool) {
contents, rest, ok := parseString(in)
if !ok {
return
}
if len(contents) == 0 {
out = emptyNameList
return
}
parts := bytes.Split(contents, comma)
out = make([]string, len(parts))
for i, part := range parts {
out[i] = string(part)
}
return
}
func parseInt(in []byte) (out *big.Int, rest []byte, ok bool) {
contents, rest, ok := parseString(in)
if !ok {
return
}
out = new(big.Int)
if len(contents) > 0 && contents[0]&0x80 == 0x80 {
// This is a negative number
notBytes := make([]byte, len(contents))
for i := range notBytes {
notBytes[i] = ^contents[i]
}
out.SetBytes(notBytes)
out.Add(out, bigOne)
out.Neg(out)
} else {
// Positive number
out.SetBytes(contents)
}
ok = true
return
}
func parseUint32(in []byte) (uint32, []byte, bool) {
if len(in) < 4 {
return 0, nil, false
}
return binary.BigEndian.Uint32(in), in[4:], true
}
func parseUint64(in []byte) (uint64, []byte, bool) {
if len(in) < 8 {
return 0, nil, false
}
return binary.BigEndian.Uint64(in), in[8:], true
}
func intLength(n *big.Int) int {
length := 4 /* length bytes */
if n.Sign() < 0 {
nMinus1 := new(big.Int).Neg(n)
nMinus1.Sub(nMinus1, bigOne)
bitLen := nMinus1.BitLen()
if bitLen%8 == 0 {
// The number will need 0xff padding
length++
}
length += (bitLen + 7) / 8
} else if n.Sign() == 0 {
// A zero is the zero length string
} else {
bitLen := n.BitLen()
if bitLen%8 == 0 {
// The number will need 0x00 padding
length++
}
length += (bitLen + 7) / 8
}
return length
}
func marshalUint32(to []byte, n uint32) []byte {
binary.BigEndian.PutUint32(to, n)
return to[4:]
}
func marshalUint64(to []byte, n uint64) []byte {
binary.BigEndian.PutUint64(to, n)
return to[8:]
}
func marshalInt(to []byte, n *big.Int) []byte {
lengthBytes := to
to = to[4:]
length := 0
if n.Sign() < 0 {
// A negative number has to be converted to two's-complement
// form. So we'll subtract 1 and invert. 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 len(bytes) == 0 || bytes[0]&0x80 == 0 {
to[0] = 0xff
to = to[1:]
length++
}
nBytes := copy(to, bytes)
to = to[nBytes:]
length += nBytes
} else if n.Sign() == 0 {
// A zero is the zero length string
} else {
bytes := n.Bytes()
if len(bytes) > 0 && bytes[0]&0x80 != 0 {
// We'll have to pad this with a 0x00 in order to
// stop it looking like a negative number.
to[0] = 0
to = to[1:]
length++
}
nBytes := copy(to, bytes)
to = to[nBytes:]
length += nBytes
}
lengthBytes[0] = byte(length >> 24)
lengthBytes[1] = byte(length >> 16)
lengthBytes[2] = byte(length >> 8)
lengthBytes[3] = byte(length)
return to
}
func writeInt(w io.Writer, n *big.Int) {
length := intLength(n)
buf := make([]byte, length)
marshalInt(buf, n)
w.Write(buf)
}
func writeString(w io.Writer, s []byte) {
var lengthBytes [4]byte
lengthBytes[0] = byte(len(s) >> 24)
lengthBytes[1] = byte(len(s) >> 16)
lengthBytes[2] = byte(len(s) >> 8)
lengthBytes[3] = byte(len(s))
w.Write(lengthBytes[:])
w.Write(s)
}
func stringLength(n int) int {
return 4 + n
}
func marshalString(to []byte, s []byte) []byte {
to[0] = byte(len(s) >> 24)
to[1] = byte(len(s) >> 16)
to[2] = byte(len(s) >> 8)
to[3] = byte(len(s))
to = to[4:]
copy(to, s)
return to[len(s):]
}
var bigIntType = reflect.TypeFor[*big.Int]()
// Decode a packet into its corresponding message.
func decode(packet []byte) (interface{}, error) {
var msg interface{}
switch packet[0] {
case msgDisconnect:
msg = new(disconnectMsg)
case msgServiceRequest:
msg = new(serviceRequestMsg)
case msgServiceAccept:
msg = new(serviceAcceptMsg)
case msgExtInfo:
msg = new(extInfoMsg)
case msgKexInit:
msg = new(kexInitMsg)
case msgKexDHInit:
msg = new(kexDHInitMsg)
case msgKexDHReply:
msg = new(kexDHReplyMsg)
case msgUserAuthRequest:
msg = new(userAuthRequestMsg)
case msgUserAuthSuccess:
return new(userAuthSuccessMsg), nil
case msgUserAuthFailure:
msg = new(userAuthFailureMsg)
case msgUserAuthBanner:
msg = new(userAuthBannerMsg)
case msgUserAuthPubKeyOk:
msg = new(userAuthPubKeyOkMsg)
case msgGlobalRequest:
msg = new(globalRequestMsg)
case msgRequestSuccess:
msg = new(globalRequestSuccessMsg)
case msgRequestFailure:
msg = new(globalRequestFailureMsg)
case msgChannelOpen:
msg = new(channelOpenMsg)
case msgChannelData:
msg = new(channelDataMsg)
case msgChannelOpenConfirm:
msg = new(channelOpenConfirmMsg)
case msgChannelOpenFailure:
msg = new(channelOpenFailureMsg)
case msgChannelWindowAdjust:
msg = new(windowAdjustMsg)
case msgChannelEOF:
msg = new(channelEOFMsg)
case msgChannelClose:
msg = new(channelCloseMsg)
case msgChannelRequest:
msg = new(channelRequestMsg)
case msgChannelSuccess:
msg = new(channelRequestSuccessMsg)
case msgChannelFailure:
msg = new(channelRequestFailureMsg)
case msgUserAuthGSSAPIToken:
msg = new(userAuthGSSAPIToken)
case msgUserAuthGSSAPIMIC:
msg = new(userAuthGSSAPIMIC)
case msgUserAuthGSSAPIErrTok:
msg = new(userAuthGSSAPIErrTok)
case msgUserAuthGSSAPIError:
msg = new(userAuthGSSAPIError)
default:
return nil, unexpectedMessageError(0, packet[0])
}
if err := Unmarshal(packet, msg); err != nil {
return nil, err
}
return msg, nil
}
var packetTypeNames = map[byte]string{
msgDisconnect: "disconnectMsg",
msgServiceRequest: "serviceRequestMsg",
msgServiceAccept: "serviceAcceptMsg",
msgExtInfo: "extInfoMsg",
msgKexInit: "kexInitMsg",
msgKexDHInit: "kexDHInitMsg",
msgKexDHReply: "kexDHReplyMsg",
msgUserAuthRequest: "userAuthRequestMsg",
msgUserAuthSuccess: "userAuthSuccessMsg",
msgUserAuthFailure: "userAuthFailureMsg",
msgUserAuthPubKeyOk: "userAuthPubKeyOkMsg",
msgGlobalRequest: "globalRequestMsg",
msgRequestSuccess: "globalRequestSuccessMsg",
msgRequestFailure: "globalRequestFailureMsg",
msgChannelOpen: "channelOpenMsg",
msgChannelData: "channelDataMsg",
msgChannelOpenConfirm: "channelOpenConfirmMsg",
msgChannelOpenFailure: "channelOpenFailureMsg",
msgChannelWindowAdjust: "windowAdjustMsg",
msgChannelEOF: "channelEOFMsg",
msgChannelClose: "channelCloseMsg",
msgChannelRequest: "channelRequestMsg",
msgChannelSuccess: "channelRequestSuccessMsg",
msgChannelFailure: "channelRequestFailureMsg",
}
// Copyright 2024 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 ssh
import (
"crypto"
"crypto/mlkem"
"crypto/sha256"
"errors"
"fmt"
"io"
"golang.org/x/crypto/curve25519"
)
// mlkem768WithCurve25519sha256 implements the hybrid ML-KEM768 with
// curve25519-sha256 key exchange method, as described by
// draft-kampanakis-curdle-ssh-pq-ke-05 section 2.3.3.
type mlkem768WithCurve25519sha256 struct{}
func (kex *mlkem768WithCurve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
var c25519kp curve25519KeyPair
if err := c25519kp.generate(rand); err != nil {
return nil, err
}
seed := make([]byte, mlkem.SeedSize)
if _, err := io.ReadFull(rand, seed); err != nil {
return nil, err
}
mlkemDk, err := mlkem.NewDecapsulationKey768(seed)
if err != nil {
return nil, err
}
hybridKey := append(mlkemDk.EncapsulationKey().Bytes(), c25519kp.pub[:]...)
if err := c.writePacket(Marshal(&kexECDHInitMsg{hybridKey})); err != nil {
return nil, err
}
packet, err := c.readPacket()
if err != nil {
return nil, err
}
var reply kexECDHReplyMsg
if err = Unmarshal(packet, &reply); err != nil {
return nil, err
}
if len(reply.EphemeralPubKey) != mlkem.CiphertextSize768+32 {
return nil, errors.New("ssh: peer's mlkem768x25519 public value has wrong length")
}
// Perform KEM decapsulate operation to obtain shared key from ML-KEM.
mlkem768Secret, err := mlkemDk.Decapsulate(reply.EphemeralPubKey[:mlkem.CiphertextSize768])
if err != nil {
return nil, err
}
// Complete Curve25519 ECDH to obtain its shared key.
c25519Secret, err := curve25519.X25519(c25519kp.priv[:], reply.EphemeralPubKey[mlkem.CiphertextSize768:])
if err != nil {
return nil, fmt.Errorf("ssh: peer's mlkem768x25519 public value is not valid: %w", err)
}
// Compute actual shared key.
h := sha256.New()
h.Write(mlkem768Secret)
h.Write(c25519Secret)
secret := h.Sum(nil)
h.Reset()
magics.write(h)
writeString(h, reply.HostKey)
writeString(h, hybridKey)
writeString(h, reply.EphemeralPubKey)
K := make([]byte, stringLength(len(secret)))
marshalString(K, secret)
h.Write(K)
return &kexResult{
H: h.Sum(nil),
K: K,
HostKey: reply.HostKey,
Signature: reply.Signature,
Hash: crypto.SHA256,
}, nil
}
func (kex *mlkem768WithCurve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (*kexResult, error) {
packet, err := c.readPacket()
if err != nil {
return nil, err
}
var kexInit kexECDHInitMsg
if err = Unmarshal(packet, &kexInit); err != nil {
return nil, err
}
if len(kexInit.ClientPubKey) != mlkem.EncapsulationKeySize768+32 {
return nil, errors.New("ssh: peer's ML-KEM768/curve25519 public value has wrong length")
}
encapsulationKey, err := mlkem.NewEncapsulationKey768(kexInit.ClientPubKey[:mlkem.EncapsulationKeySize768])
if err != nil {
return nil, fmt.Errorf("ssh: peer's ML-KEM768 encapsulation key is not valid: %w", err)
}
// Perform KEM encapsulate operation to obtain ciphertext and shared key.
mlkem768Secret, mlkem768Ciphertext := encapsulationKey.Encapsulate()
// Perform server side of Curve25519 ECDH to obtain server public value and
// shared key.
var c25519kp curve25519KeyPair
if err := c25519kp.generate(rand); err != nil {
return nil, err
}
c25519Secret, err := curve25519.X25519(c25519kp.priv[:], kexInit.ClientPubKey[mlkem.EncapsulationKeySize768:])
if err != nil {
return nil, fmt.Errorf("ssh: peer's ML-KEM768/curve25519 public value is not valid: %w", err)
}
hybridKey := append(mlkem768Ciphertext, c25519kp.pub[:]...)
// Compute actual shared key.
h := sha256.New()
h.Write(mlkem768Secret)
h.Write(c25519Secret)
secret := h.Sum(nil)
hostKeyBytes := priv.PublicKey().Marshal()
h.Reset()
magics.write(h)
writeString(h, hostKeyBytes)
writeString(h, kexInit.ClientPubKey)
writeString(h, hybridKey)
K := make([]byte, stringLength(len(secret)))
marshalString(K, secret)
h.Write(K)
H := h.Sum(nil)
sig, err := signAndMarshal(priv, rand, H, algo)
if err != nil {
return nil, err
}
reply := kexECDHReplyMsg{
EphemeralPubKey: hybridKey,
HostKey: hostKeyBytes,
Signature: sig,
}
if err := c.writePacket(Marshal(&reply)); err != nil {
return nil, err
}
return &kexResult{
H: H,
K: K,
HostKey: hostKeyBytes,
Signature: sig,
Hash: crypto.SHA256,
}, nil
}
// Copyright 2013 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 ssh
import (
"encoding/binary"
"fmt"
"io"
"log"
"sync"
"sync/atomic"
)
// debugMux, if set, causes messages in the connection protocol to be
// logged.
const debugMux = false
// chanList is a thread safe channel list.
type chanList struct {
// protects concurrent access to chans
sync.Mutex
// chans are indexed by the local id of the channel, which the
// other side should send in the PeersId field.
chans []*channel
// This is a debugging aid: it offsets all IDs by this
// amount. This helps distinguish otherwise identical
// server/client muxes
offset uint32
}
// Assigns a channel ID to the given channel.
func (c *chanList) add(ch *channel) uint32 {
c.Lock()
defer c.Unlock()
for i := range c.chans {
if c.chans[i] == nil {
c.chans[i] = ch
return uint32(i) + c.offset
}
}
c.chans = append(c.chans, ch)
return uint32(len(c.chans)-1) + c.offset
}
// getChan returns the channel for the given ID.
func (c *chanList) getChan(id uint32) *channel {
id -= c.offset
c.Lock()
defer c.Unlock()
if id < uint32(len(c.chans)) {
return c.chans[id]
}
return nil
}
func (c *chanList) remove(id uint32) {
id -= c.offset
c.Lock()
if id < uint32(len(c.chans)) {
c.chans[id] = nil
}
c.Unlock()
}
// dropAll forgets all channels it knows, returning them in a slice.
func (c *chanList) dropAll() []*channel {
c.Lock()
defer c.Unlock()
var r []*channel
for _, ch := range c.chans {
if ch == nil {
continue
}
r = append(r, ch)
}
c.chans = nil
return r
}
// mux represents the state for the SSH connection protocol, which
// multiplexes many channels onto a single packet transport.
type mux struct {
conn packetConn
chanList chanList
incomingChannels chan NewChannel
globalSentMu sync.Mutex
globalResponses chan interface{}
incomingRequests chan *Request
errCond *sync.Cond
err error
}
// When debugging, each new chanList instantiation has a different
// offset.
var globalOff uint32
func (m *mux) Wait() error {
m.errCond.L.Lock()
defer m.errCond.L.Unlock()
for m.err == nil {
m.errCond.Wait()
}
return m.err
}
// newMux returns a mux that runs over the given connection.
func newMux(p packetConn) *mux {
m := &mux{
conn: p,
incomingChannels: make(chan NewChannel, chanSize),
globalResponses: make(chan interface{}, 1),
incomingRequests: make(chan *Request, chanSize),
errCond: newCond(),
}
if debugMux {
m.chanList.offset = atomic.AddUint32(&globalOff, 1)
}
go m.loop()
return m
}
func (m *mux) sendMessage(msg interface{}) error {
p := Marshal(msg)
if debugMux {
log.Printf("send global(%d): %#v", m.chanList.offset, msg)
}
return m.conn.writePacket(p)
}
func (m *mux) SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) {
if wantReply {
m.globalSentMu.Lock()
defer m.globalSentMu.Unlock()
}
if err := m.sendMessage(globalRequestMsg{
Type: name,
WantReply: wantReply,
Data: payload,
}); err != nil {
return false, nil, err
}
if !wantReply {
return false, nil, nil
}
msg, ok := <-m.globalResponses
if !ok {
return false, nil, io.EOF
}
switch msg := msg.(type) {
case *globalRequestFailureMsg:
return false, msg.Data, nil
case *globalRequestSuccessMsg:
return true, msg.Data, nil
default:
return false, nil, fmt.Errorf("ssh: unexpected response to request: %#v", msg)
}
}
// ackRequest must be called after processing a global request that
// has WantReply set.
func (m *mux) ackRequest(ok bool, data []byte) error {
if ok {
return m.sendMessage(globalRequestSuccessMsg{Data: data})
}
return m.sendMessage(globalRequestFailureMsg{Data: data})
}
func (m *mux) Close() error {
return m.conn.Close()
}
// loop runs the connection machine. It will process packets until an
// error is encountered. To synchronize on loop exit, use mux.Wait.
func (m *mux) loop() {
var err error
for err == nil {
err = m.onePacket()
}
for _, ch := range m.chanList.dropAll() {
ch.close()
}
close(m.incomingChannels)
close(m.incomingRequests)
close(m.globalResponses)
m.conn.Close()
m.errCond.L.Lock()
m.err = err
m.errCond.Broadcast()
m.errCond.L.Unlock()
if debugMux {
log.Println("loop exit", err)
}
}
// onePacket reads and processes one packet.
func (m *mux) onePacket() error {
packet, err := m.conn.readPacket()
if err != nil {
return err
}
if debugMux {
if packet[0] == msgChannelData || packet[0] == msgChannelExtendedData {
log.Printf("decoding(%d): data packet - %d bytes", m.chanList.offset, len(packet))
} else {
p, _ := decode(packet)
log.Printf("decoding(%d): %d %#v - %d bytes", m.chanList.offset, packet[0], p, len(packet))
}
}
switch packet[0] {
case msgChannelOpen:
return m.handleChannelOpen(packet)
case msgGlobalRequest, msgRequestSuccess, msgRequestFailure:
return m.handleGlobalPacket(packet)
case msgPing:
var msg pingMsg
if err := Unmarshal(packet, &msg); err != nil {
return fmt.Errorf("failed to unmarshal ping@openssh.com message: %w", err)
}
return m.sendMessage(pongMsg(msg))
}
// assume a channel packet.
if len(packet) < 5 {
return parseError(packet[0])
}
id := binary.BigEndian.Uint32(packet[1:])
ch := m.chanList.getChan(id)
if ch == nil {
return m.handleUnknownChannelPacket(id, packet)
}
return ch.handlePacket(packet)
}
func (m *mux) handleGlobalPacket(packet []byte) error {
msg, err := decode(packet)
if err != nil {
return err
}
switch msg := msg.(type) {
case *globalRequestMsg:
m.incomingRequests <- &Request{
Type: msg.Type,
WantReply: msg.WantReply,
Payload: msg.Data,
mux: m,
}
case *globalRequestSuccessMsg, *globalRequestFailureMsg:
m.globalResponses <- msg
default:
panic(fmt.Sprintf("not a global message %#v", msg))
}
return nil
}
// handleChannelOpen schedules a channel to be Accept()ed.
func (m *mux) handleChannelOpen(packet []byte) error {
var msg channelOpenMsg
if err := Unmarshal(packet, &msg); err != nil {
return err
}
if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 {
failMsg := channelOpenFailureMsg{
PeersID: msg.PeersID,
Reason: ConnectionFailed,
Message: "invalid request",
Language: "en_US.UTF-8",
}
return m.sendMessage(failMsg)
}
c := m.newChannel(msg.ChanType, channelInbound, msg.TypeSpecificData)
c.remoteId = msg.PeersID
c.maxRemotePayload = msg.MaxPacketSize
c.remoteWin.add(msg.PeersWindow)
m.incomingChannels <- c
return nil
}
func (m *mux) OpenChannel(chanType string, extra []byte) (Channel, <-chan *Request, error) {
ch, err := m.openChannel(chanType, extra)
if err != nil {
return nil, nil, err
}
return ch, ch.incomingRequests, nil
}
func (m *mux) openChannel(chanType string, extra []byte) (*channel, error) {
ch := m.newChannel(chanType, channelOutbound, extra)
ch.maxIncomingPayload = channelMaxPacket
open := channelOpenMsg{
ChanType: chanType,
PeersWindow: ch.myWindow,
MaxPacketSize: ch.maxIncomingPayload,
TypeSpecificData: extra,
PeersID: ch.localId,
}
if err := m.sendMessage(open); err != nil {
return nil, err
}
switch msg := (<-ch.msg).(type) {
case *channelOpenConfirmMsg:
return ch, nil
case *channelOpenFailureMsg:
return nil, &OpenChannelError{msg.Reason, msg.Message}
default:
return nil, fmt.Errorf("ssh: unexpected packet in response to channel open: %T", msg)
}
}
func (m *mux) handleUnknownChannelPacket(id uint32, packet []byte) error {
msg, err := decode(packet)
if err != nil {
return err
}
switch msg := msg.(type) {
// RFC 4254 section 5.4 says unrecognized channel requests should
// receive a failure response.
case *channelRequestMsg:
if msg.WantReply {
return m.sendMessage(channelRequestFailureMsg{
PeersID: msg.PeersID,
})
}
return nil
default:
return fmt.Errorf("ssh: invalid channel %d", id)
}
}
// Copyright 2011 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 ssh
import (
"bytes"
"errors"
"fmt"
"io"
"net"
"slices"
"strings"
)
// The Permissions type holds fine-grained permissions that are
// specific to a user or a specific authentication method for a user.
// The Permissions value for a successful authentication attempt is
// available in ServerConn, so it can be used to pass information from
// the user-authentication phase to the application layer.
type Permissions struct {
// CriticalOptions indicate restrictions to the default
// permissions, and are typically used in conjunction with
// user certificates. The standard for SSH certificates
// defines "force-command" (only allow the given command to
// execute) and "source-address" (only allow connections from
// the given address). The SSH package currently only enforces
// the "source-address" critical option. It is up to server
// implementations to enforce other critical options, such as
// "force-command", by checking them after the SSH handshake
// is successful. In general, SSH servers should reject
// connections that specify critical options that are unknown
// or not supported.
CriticalOptions map[string]string
// Extensions are extra functionality that the server may
// offer on authenticated connections. Lack of support for an
// extension does not preclude authenticating a user. Common
// extensions are "permit-agent-forwarding",
// "permit-X11-forwarding". The Go SSH library currently does
// not act on any extension, and it is up to server
// implementations to honor them. Extensions can be used to
// pass data from the authentication callbacks to the server
// application layer.
Extensions map[string]string
// ExtraData allows to store user defined data.
ExtraData map[any]any
}
type GSSAPIWithMICConfig struct {
// AllowLogin, must be set, is called when gssapi-with-mic
// authentication is selected (RFC 4462 section 3). The srcName is from the
// results of the GSS-API authentication. The format is username@DOMAIN.
// GSSAPI just guarantees to the server who the user is, but not if they can log in, and with what permissions.
// This callback is called after the user identity is established with GSSAPI to decide if the user can login with
// which permissions. If the user is allowed to login, it should return a nil error.
AllowLogin func(conn ConnMetadata, srcName string) (*Permissions, error)
// Server must be set. It's the implementation
// of the GSSAPIServer interface. See GSSAPIServer interface for details.
Server GSSAPIServer
}
// SendAuthBanner implements [ServerPreAuthConn].
func (s *connection) SendAuthBanner(msg string) error {
return s.transport.writePacket(Marshal(&userAuthBannerMsg{
Message: msg,
}))
}
func (*connection) unexportedMethodForFutureProofing() {}
// ServerPreAuthConn is the interface available on an incoming server
// connection before authentication has completed.
type ServerPreAuthConn interface {
unexportedMethodForFutureProofing() // permits growing ServerPreAuthConn safely later, ala testing.TB
ConnMetadata
// SendAuthBanner sends a banner message to the client.
// It returns an error once the authentication phase has ended.
SendAuthBanner(string) error
}
// ServerConfig holds server specific configuration data.
type ServerConfig struct {
// Config contains configuration shared between client and server.
Config
// PublicKeyAuthAlgorithms specifies the supported client public key
// authentication algorithms. Note that this should not include certificate
// types since those use the underlying algorithm. This list is sent to the
// client if it supports the server-sig-algs extension. Order is irrelevant.
// If unspecified then a default set of algorithms is used.
PublicKeyAuthAlgorithms []string
hostKeys []Signer
// NoClientAuth is true if clients are allowed to connect without
// authenticating.
// To determine NoClientAuth at runtime, set NoClientAuth to true
// and the optional NoClientAuthCallback to a non-nil value.
NoClientAuth bool
// NoClientAuthCallback, if non-nil, is called when a user
// attempts to authenticate with auth method "none".
// NoClientAuth must also be set to true for this be used, or
// this func is unused.
NoClientAuthCallback func(ConnMetadata) (*Permissions, error)
// MaxAuthTries specifies the maximum number of authentication attempts
// permitted per connection. If set to a negative number, the number of
// attempts are unlimited. If set to zero, the number of attempts are limited
// to 6.
MaxAuthTries int
// PasswordCallback, if non-nil, is called when a user
// attempts to authenticate using a password.
PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error)
// PublicKeyCallback, if non-nil, is called when a client
// offers a public key for authentication. It must return a nil error
// if the given public key can be used to authenticate the
// given user. For example, see CertChecker.Authenticate. A
// call to this function does not guarantee that the key
// offered is in fact used to authenticate. To record any data
// depending on the public key, store it inside a
// Permissions.Extensions entry.
PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
// VerifiedPublicKeyCallback, if non-nil, is called after a client
// successfully confirms having control over a key that was previously
// approved by PublicKeyCallback. The permissions object passed to the
// callback is the one returned by PublicKeyCallback for the given public
// key and its ownership is transferred to the callback. The returned
// Permissions object can be the same object, optionally modified, or a
// completely new object. If VerifiedPublicKeyCallback is non-nil,
// PublicKeyCallback is not allowed to return a PartialSuccessError, which
// can instead be returned by VerifiedPublicKeyCallback.
//
// VerifiedPublicKeyCallback does not affect which authentication methods
// are included in the list of methods that can be attempted by the client.
VerifiedPublicKeyCallback func(conn ConnMetadata, key PublicKey, permissions *Permissions,
signatureAlgorithm string) (*Permissions, error)
// KeyboardInteractiveCallback, if non-nil, is called when
// keyboard-interactive authentication is selected (RFC
// 4256). The client object's Challenge function should be
// used to query the user. The callback may offer multiple
// Challenge rounds. To avoid information leaks, the client
// should be presented a challenge even if the user is
// unknown.
KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error)
// AuthLogCallback, if non-nil, is called to log all authentication
// attempts.
AuthLogCallback func(conn ConnMetadata, method string, err error)
// PreAuthConnCallback, if non-nil, is called upon receiving a new connection
// before any authentication has started. The provided ServerPreAuthConn
// can be used at any time before authentication is complete, including
// after this callback has returned.
PreAuthConnCallback func(ServerPreAuthConn)
// ServerVersion is the version identification string to announce in
// the public handshake.
// If empty, a reasonable default is used.
// Note that RFC 4253 section 4.2 requires that this string start with
// "SSH-2.0-".
ServerVersion string
// BannerCallback, if present, is called and the return string is sent to
// the client after key exchange completed but before authentication.
BannerCallback func(conn ConnMetadata) string
// GSSAPIWithMICConfig includes gssapi server and callback, which if both non-nil, is used
// when gssapi-with-mic authentication is selected (RFC 4462 section 3).
GSSAPIWithMICConfig *GSSAPIWithMICConfig
}
// AddHostKey adds a private key as a host key. If an existing host
// key exists with the same public key format, it is replaced. Each server
// config must have at least one host key.
func (s *ServerConfig) AddHostKey(key Signer) {
for i, k := range s.hostKeys {
if k.PublicKey().Type() == key.PublicKey().Type() {
s.hostKeys[i] = key
return
}
}
s.hostKeys = append(s.hostKeys, key)
}
// cachedPubKey contains the results of querying whether a public key is
// acceptable for a user. This is a FIFO cache.
type cachedPubKey struct {
user string
pubKeyData []byte
result error
perms *Permissions
}
// maxCachedPubKeys is the number of cache entries we store.
//
// Due to consistent misuse of the PublicKeyCallback API, we have reduced this
// to 1, such that the only key in the cache is the most recently seen one. This
// forces the behavior that the last call to PublicKeyCallback will always be
// with the key that is used for authentication.
const maxCachedPubKeys = 1
// pubKeyCache caches tests for public keys. Since SSH clients
// will query whether a public key is acceptable before attempting to
// authenticate with it, we end up with duplicate queries for public
// key validity. The cache only applies to a single ServerConn.
type pubKeyCache struct {
keys []cachedPubKey
}
// get returns the result for a given user/algo/key tuple.
func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKey, bool) {
for _, k := range c.keys {
if k.user == user && bytes.Equal(k.pubKeyData, pubKeyData) {
return k, true
}
}
return cachedPubKey{}, false
}
// add adds the given tuple to the cache.
func (c *pubKeyCache) add(candidate cachedPubKey) {
if len(c.keys) >= maxCachedPubKeys {
c.keys = c.keys[1:]
}
c.keys = append(c.keys, candidate)
}
// ServerConn is an authenticated SSH connection, as seen from the
// server
type ServerConn struct {
Conn
// If the succeeding authentication callback returned a
// non-nil Permissions pointer, it is stored here.
Permissions *Permissions
}
// NewServerConn starts a new SSH server with c as the underlying
// transport. It starts with a handshake and, if the handshake is
// unsuccessful, it closes the connection and returns an error. The
// Request and NewChannel channels must be serviced, or the connection
// will hang.
//
// The returned error may be of type *ServerAuthError for
// authentication errors.
func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) {
fullConf := *config
fullConf.SetDefaults()
if fullConf.MaxAuthTries == 0 {
fullConf.MaxAuthTries = 6
}
if len(fullConf.PublicKeyAuthAlgorithms) == 0 {
fullConf.PublicKeyAuthAlgorithms = defaultPubKeyAuthAlgos
} else {
for _, algo := range fullConf.PublicKeyAuthAlgorithms {
if !slices.Contains(SupportedAlgorithms().PublicKeyAuths, algo) && !slices.Contains(InsecureAlgorithms().PublicKeyAuths, algo) {
c.Close()
return nil, nil, nil, fmt.Errorf("ssh: unsupported public key authentication algorithm %s", algo)
}
}
}
s := &connection{
sshConn: sshConn{conn: c},
}
perms, err := s.serverHandshake(&fullConf)
if err != nil {
c.Close()
return nil, nil, nil, err
}
return &ServerConn{s, perms}, s.mux.incomingChannels, s.mux.incomingRequests, nil
}
// signAndMarshal signs the data with the appropriate algorithm,
// and serializes the result in SSH wire format. algo is the negotiate
// algorithm and may be a certificate type.
func signAndMarshal(k AlgorithmSigner, rand io.Reader, data []byte, algo string) ([]byte, error) {
sig, err := k.SignWithAlgorithm(rand, data, underlyingAlgo(algo))
if err != nil {
return nil, err
}
return Marshal(sig), nil
}
// handshake performs key exchange and user authentication.
func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) {
if len(config.hostKeys) == 0 {
return nil, errors.New("ssh: server has no host keys")
}
if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil &&
config.KeyboardInteractiveCallback == nil && (config.GSSAPIWithMICConfig == nil ||
config.GSSAPIWithMICConfig.AllowLogin == nil || config.GSSAPIWithMICConfig.Server == nil) {
return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
}
if config.ServerVersion != "" {
s.serverVersion = []byte(config.ServerVersion)
} else {
s.serverVersion = []byte(packageVersion)
}
var err error
s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion)
if err != nil {
return nil, err
}
tr := newTransport(s.sshConn.conn, config.Rand, false /* not client */)
s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config)
if err := s.transport.waitSession(); err != nil {
return nil, err
}
// We just did the key change, so the session ID is established.
s.sessionID = s.transport.getSessionID()
s.algorithms = s.transport.getAlgorithms()
var packet []byte
if packet, err = s.transport.readPacket(); err != nil {
return nil, err
}
var serviceRequest serviceRequestMsg
if err = Unmarshal(packet, &serviceRequest); err != nil {
return nil, err
}
if serviceRequest.Service != serviceUserAuth {
return nil, errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating")
}
serviceAccept := serviceAcceptMsg{
Service: serviceUserAuth,
}
if err := s.transport.writePacket(Marshal(&serviceAccept)); err != nil {
return nil, err
}
perms, err := s.serverAuthenticate(config)
if err != nil {
return nil, err
}
s.mux = newMux(s.transport)
return perms, err
}
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")
}
tcpAddr, ok := addr.(*net.TCPAddr)
if !ok {
return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr)
}
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
}
}
}
return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr)
}
func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, token []byte, s *connection,
sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) {
gssAPIServer := gssapiConfig.Server
defer gssAPIServer.DeleteSecContext()
var srcName string
for {
var (
outToken []byte
needContinue bool
)
outToken, srcName, needContinue, err = gssAPIServer.AcceptSecContext(token)
if err != nil {
return err, nil, nil
}
if len(outToken) != 0 {
if err := s.transport.writePacket(Marshal(&userAuthGSSAPIToken{
Token: outToken,
})); err != nil {
return nil, nil, err
}
}
if !needContinue {
break
}
packet, err := s.transport.readPacket()
if err != nil {
return nil, nil, err
}
userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
return nil, nil, err
}
token = userAuthGSSAPITokenReq.Token
}
packet, err := s.transport.readPacket()
if err != nil {
return nil, nil, err
}
userAuthGSSAPIMICReq := &userAuthGSSAPIMIC{}
if err := Unmarshal(packet, userAuthGSSAPIMICReq); err != nil {
return nil, nil, err
}
mic := buildMIC(string(sessionID), userAuthReq.User, userAuthReq.Service, userAuthReq.Method)
if err := gssAPIServer.VerifyMIC(mic, userAuthGSSAPIMICReq.MIC); err != nil {
return err, nil, nil
}
perms, authErr = gssapiConfig.AllowLogin(s, srcName)
return authErr, perms, nil
}
// isAlgoCompatible checks if the signature format is compatible with the
// selected algorithm taking into account edge cases that occur with old
// clients.
func isAlgoCompatible(algo, sigFormat string) bool {
// Compatibility for old clients.
//
// For certificate authentication with OpenSSH 7.2-7.7 signature format can
// be rsa-sha2-256 or rsa-sha2-512 for the algorithm
// ssh-rsa-cert-v01@openssh.com.
//
// With gpg-agent < 2.2.6 the algorithm can be rsa-sha2-256 or rsa-sha2-512
// for signature format ssh-rsa.
if isRSA(algo) && isRSA(sigFormat) {
return true
}
// Standard case: the underlying algorithm must match the signature format.
return underlyingAlgo(algo) == sigFormat
}
// ServerAuthError represents server authentication errors and is
// sometimes returned by NewServerConn. It appends any authentication
// errors that may occur, and is returned if all of the authentication
// methods provided by the user failed to authenticate.
type ServerAuthError struct {
// Errors contains authentication errors returned by the authentication
// callback methods. The first entry is typically ErrNoAuth.
Errors []error
}
func (l ServerAuthError) Error() string {
var errs []string
for _, err := range l.Errors {
errs = append(errs, err.Error())
}
return "[" + strings.Join(errs, ", ") + "]"
}
// ServerAuthCallbacks defines server-side authentication callbacks.
type ServerAuthCallbacks struct {
// PasswordCallback behaves like [ServerConfig.PasswordCallback].
PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error)
// PublicKeyCallback behaves like [ServerConfig.PublicKeyCallback].
PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
// KeyboardInteractiveCallback behaves like [ServerConfig.KeyboardInteractiveCallback].
KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error)
// GSSAPIWithMICConfig behaves like [ServerConfig.GSSAPIWithMICConfig].
GSSAPIWithMICConfig *GSSAPIWithMICConfig
}
// PartialSuccessError can be returned by any of the [ServerConfig]
// authentication callbacks to indicate to the client that authentication has
// partially succeeded, but further steps are required.
type PartialSuccessError struct {
// Next defines the authentication callbacks to apply to further steps. The
// available methods communicated to the client are based on the non-nil
// ServerAuthCallbacks fields.
Next ServerAuthCallbacks
}
func (p *PartialSuccessError) Error() string {
return "ssh: authenticated with partial success"
}
// ErrNoAuth is the error value returned if no
// authentication method has been passed yet. This happens as a normal
// part of the authentication loop, since the client first tries
// 'none' authentication to discover available methods.
// It is returned in ServerAuthError.Errors from NewServerConn.
var ErrNoAuth = errors.New("ssh: no auth passed yet")
// BannerError is an error that can be returned by authentication handlers in
// ServerConfig to send a banner message to the client.
type BannerError struct {
Err error
Message string
}
func (b *BannerError) Unwrap() error {
return b.Err
}
func (b *BannerError) Error() string {
if b.Err == nil {
return b.Message
}
return b.Err.Error()
}
func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) {
if config.PreAuthConnCallback != nil {
config.PreAuthConnCallback(s)
}
sessionID := s.transport.getSessionID()
var cache pubKeyCache
var perms *Permissions
authFailures := 0
noneAuthCount := 0
var authErrs []error
var calledBannerCallback bool
partialSuccessReturned := false
// Set the initial authentication callbacks from the config. They can be
// changed if a PartialSuccessError is returned.
authConfig := ServerAuthCallbacks{
PasswordCallback: config.PasswordCallback,
PublicKeyCallback: config.PublicKeyCallback,
KeyboardInteractiveCallback: config.KeyboardInteractiveCallback,
GSSAPIWithMICConfig: config.GSSAPIWithMICConfig,
}
userAuthLoop:
for {
if authFailures >= config.MaxAuthTries && config.MaxAuthTries > 0 {
discMsg := &disconnectMsg{
Reason: 2,
Message: "too many authentication failures",
}
if err := s.transport.writePacket(Marshal(discMsg)); err != nil {
return nil, err
}
authErrs = append(authErrs, discMsg)
return nil, &ServerAuthError{Errors: authErrs}
}
var userAuthReq userAuthRequestMsg
if packet, err := s.transport.readPacket(); err != nil {
if err == io.EOF {
return nil, &ServerAuthError{Errors: authErrs}
}
return nil, err
} else if err = Unmarshal(packet, &userAuthReq); err != nil {
return nil, err
}
if userAuthReq.Service != serviceSSH {
return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service)
}
if s.user != userAuthReq.User && partialSuccessReturned {
return nil, fmt.Errorf("ssh: client changed the user after a partial success authentication, previous user %q, current user %q",
s.user, userAuthReq.User)
}
s.user = userAuthReq.User
if !calledBannerCallback && config.BannerCallback != nil {
calledBannerCallback = true
if msg := config.BannerCallback(s); msg != "" {
if err := s.SendAuthBanner(msg); err != nil {
return nil, err
}
}
}
perms = nil
authErr := ErrNoAuth
switch userAuthReq.Method {
case "none":
noneAuthCount++
// We don't allow none authentication after a partial success
// response.
if config.NoClientAuth && !partialSuccessReturned {
if config.NoClientAuthCallback != nil {
perms, authErr = config.NoClientAuthCallback(s)
} else {
authErr = nil
}
}
case "password":
if authConfig.PasswordCallback == nil {
authErr = errors.New("ssh: password auth not configured")
break
}
payload := userAuthReq.Payload
if len(payload) < 1 || payload[0] != 0 {
return nil, parseError(msgUserAuthRequest)
}
payload = payload[1:]
password, payload, ok := parseString(payload)
if !ok || len(payload) > 0 {
return nil, parseError(msgUserAuthRequest)
}
perms, authErr = authConfig.PasswordCallback(s, password)
case "keyboard-interactive":
if authConfig.KeyboardInteractiveCallback == nil {
authErr = errors.New("ssh: keyboard-interactive auth not configured")
break
}
prompter := &sshClientKeyboardInteractive{s}
perms, authErr = authConfig.KeyboardInteractiveCallback(s, prompter.Challenge)
case "publickey":
if authConfig.PublicKeyCallback == nil {
authErr = errors.New("ssh: publickey auth not configured")
break
}
payload := userAuthReq.Payload
if len(payload) < 1 {
return nil, parseError(msgUserAuthRequest)
}
isQuery := payload[0] == 0
payload = payload[1:]
algoBytes, payload, ok := parseString(payload)
if !ok {
return nil, parseError(msgUserAuthRequest)
}
algo := string(algoBytes)
if !slices.Contains(config.PublicKeyAuthAlgorithms, underlyingAlgo(algo)) {
authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo)
break
}
pubKeyData, payload, ok := parseString(payload)
if !ok {
return nil, parseError(msgUserAuthRequest)
}
pubKey, err := ParsePublicKey(pubKeyData)
if err != nil {
return nil, err
}
candidate, ok := cache.get(s.user, pubKeyData)
if !ok {
candidate.user = s.user
candidate.pubKeyData = pubKeyData
candidate.perms, candidate.result = authConfig.PublicKeyCallback(s, pubKey)
_, isPartialSuccessError := candidate.result.(*PartialSuccessError)
if isPartialSuccessError && config.VerifiedPublicKeyCallback != nil {
return nil, errors.New("ssh: invalid library usage: PublicKeyCallback must not return partial success when VerifiedPublicKeyCallback is defined")
}
if (candidate.result == nil || isPartialSuccessError) &&
candidate.perms != nil &&
candidate.perms.CriticalOptions != nil &&
candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" {
if err := checkSourceAddress(
s.RemoteAddr(),
candidate.perms.CriticalOptions[sourceAddressCriticalOption]); err != nil {
candidate.result = err
}
}
cache.add(candidate)
}
if isQuery {
// The client can query if the given public key
// would be okay.
if len(payload) > 0 {
return nil, parseError(msgUserAuthRequest)
}
_, isPartialSuccessError := candidate.result.(*PartialSuccessError)
if candidate.result == nil || isPartialSuccessError {
okMsg := userAuthPubKeyOkMsg{
Algo: algo,
PubKey: pubKeyData,
}
if err = s.transport.writePacket(Marshal(&okMsg)); err != nil {
return nil, err
}
continue userAuthLoop
}
authErr = candidate.result
} else {
sig, payload, ok := parseSignature(payload)
if !ok || len(payload) > 0 {
return nil, parseError(msgUserAuthRequest)
}
// Ensure the declared public key algo is compatible with the
// decoded one. This check will ensure we don't accept e.g.
// ssh-rsa-cert-v01@openssh.com algorithm with ssh-rsa public
// key type. The algorithm and public key type must be
// consistent: both must be certificate algorithms, or neither.
if !slices.Contains(algorithmsForKeyFormat(pubKey.Type()), algo) {
authErr = fmt.Errorf("ssh: public key type %q not compatible with selected algorithm %q",
pubKey.Type(), algo)
break
}
// Ensure the public key algo and signature algo
// are supported. Compare the private key
// algorithm name that corresponds to algo with
// sig.Format. This is usually the same, but
// for certs, the names differ.
if !slices.Contains(config.PublicKeyAuthAlgorithms, sig.Format) {
authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format)
break
}
if !isAlgoCompatible(algo, sig.Format) {
authErr = fmt.Errorf("ssh: signature %q not compatible with selected algorithm %q", sig.Format, algo)
break
}
signedData := buildDataSignedForAuth(sessionID, userAuthReq, algo, pubKeyData)
if err := pubKey.Verify(signedData, sig); err != nil {
return nil, err
}
authErr = candidate.result
perms = candidate.perms
if authErr == nil && config.VerifiedPublicKeyCallback != nil {
// Only call VerifiedPublicKeyCallback after the key has been accepted
// and successfully verified. If authErr is non-nil, the key is not
// considered verified and the callback must not run.
perms, authErr = config.VerifiedPublicKeyCallback(s, pubKey, perms, algo)
}
}
case "gssapi-with-mic":
if authConfig.GSSAPIWithMICConfig == nil {
authErr = errors.New("ssh: gssapi-with-mic auth not configured")
break
}
gssapiConfig := authConfig.GSSAPIWithMICConfig
userAuthRequestGSSAPI, err := parseGSSAPIPayload(userAuthReq.Payload)
if err != nil {
return nil, parseError(msgUserAuthRequest)
}
// OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication.
if userAuthRequestGSSAPI.N == 0 {
authErr = fmt.Errorf("ssh: Mechanism negotiation is not supported")
break
}
var i uint32
present := false
for i = 0; i < userAuthRequestGSSAPI.N; i++ {
if userAuthRequestGSSAPI.OIDS[i].Equal(krb5Mesh) {
present = true
break
}
}
if !present {
authErr = fmt.Errorf("ssh: GSSAPI authentication must use the Kerberos V5 mechanism")
break
}
// Initial server response, see RFC 4462 section 3.3.
if err := s.transport.writePacket(Marshal(&userAuthGSSAPIResponse{
SupportMech: krb5OID,
})); err != nil {
return nil, err
}
// Exchange token, see RFC 4462 section 3.4.
packet, err := s.transport.readPacket()
if err != nil {
return nil, err
}
userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
return nil, err
}
authErr, perms, err = gssExchangeToken(gssapiConfig, userAuthGSSAPITokenReq.Token, s, sessionID,
userAuthReq)
if err != nil {
return nil, err
}
default:
authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method)
}
authErrs = append(authErrs, authErr)
if config.AuthLogCallback != nil {
config.AuthLogCallback(s, userAuthReq.Method, authErr)
}
var bannerErr *BannerError
if errors.As(authErr, &bannerErr) {
if bannerErr.Message != "" {
if err := s.SendAuthBanner(bannerErr.Message); err != nil {
return nil, err
}
}
}
if authErr == nil {
break userAuthLoop
}
var failureMsg userAuthFailureMsg
if partialSuccess, ok := authErr.(*PartialSuccessError); ok {
// After a partial success error we don't allow changing the user
// name and execute the NoClientAuthCallback.
partialSuccessReturned = true
// In case a partial success is returned, the server may send
// a new set of authentication methods.
authConfig = partialSuccess.Next
// Reset pubkey cache, as the new PublicKeyCallback might
// accept a different set of public keys.
cache = pubKeyCache{}
// Send back a partial success message to the user.
failureMsg.PartialSuccess = true
} else {
// Allow initial attempt of 'none' without penalty.
if authFailures > 0 || userAuthReq.Method != "none" || noneAuthCount != 1 {
authFailures++
}
if config.MaxAuthTries > 0 && authFailures >= config.MaxAuthTries {
// If we have hit the max attempts, don't bother sending the
// final SSH_MSG_USERAUTH_FAILURE message, since there are
// no more authentication methods which can be attempted,
// and this message may cause the client to re-attempt
// authentication while we send the disconnect message.
// Continue, and trigger the disconnect at the start of
// the loop.
//
// The SSH specification is somewhat confusing about this,
// RFC 4252 Section 5.1 requires each authentication failure
// be responded to with a respective SSH_MSG_USERAUTH_FAILURE
// message, but Section 4 says the server should disconnect
// after some number of attempts, but it isn't explicit which
// message should take precedence (i.e. should there be a failure
// message than a disconnect message, or if we are going to
// disconnect, should we only send that message.)
//
// Either way, OpenSSH disconnects immediately after the last
// failed authentication attempt, and given they are typically
// considered the golden implementation it seems reasonable
// to match that behavior.
continue
}
}
if authConfig.PasswordCallback != nil {
failureMsg.Methods = append(failureMsg.Methods, "password")
}
if authConfig.PublicKeyCallback != nil {
failureMsg.Methods = append(failureMsg.Methods, "publickey")
}
if authConfig.KeyboardInteractiveCallback != nil {
failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive")
}
if authConfig.GSSAPIWithMICConfig != nil && authConfig.GSSAPIWithMICConfig.Server != nil &&
authConfig.GSSAPIWithMICConfig.AllowLogin != nil {
failureMsg.Methods = append(failureMsg.Methods, "gssapi-with-mic")
}
if len(failureMsg.Methods) == 0 {
return nil, errors.New("ssh: no authentication methods available")
}
if err := s.transport.writePacket(Marshal(&failureMsg)); err != nil {
return nil, err
}
}
if err := s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil {
return nil, err
}
return perms, nil
}
// sshClientKeyboardInteractive implements a ClientKeyboardInteractive by
// asking the client on the other side of a ServerConn.
type sshClientKeyboardInteractive struct {
*connection
}
func (c *sshClientKeyboardInteractive) Challenge(name, instruction string, questions []string, echos []bool) (answers []string, err error) {
if len(questions) != len(echos) {
return nil, errors.New("ssh: echos and questions must have equal length")
}
var prompts []byte
for i := range questions {
prompts = appendString(prompts, questions[i])
prompts = appendBool(prompts, echos[i])
}
if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{
Name: name,
Instruction: instruction,
NumPrompts: uint32(len(questions)),
Prompts: prompts,
})); err != nil {
return nil, err
}
packet, err := c.transport.readPacket()
if err != nil {
return nil, err
}
if packet[0] != msgUserAuthInfoResponse {
return nil, unexpectedMessageError(msgUserAuthInfoResponse, packet[0])
}
packet = packet[1:]
n, packet, ok := parseUint32(packet)
if !ok || int(n) != len(questions) {
return nil, parseError(msgUserAuthInfoResponse)
}
for i := uint32(0); i < n; i++ {
ans, rest, ok := parseString(packet)
if !ok {
return nil, parseError(msgUserAuthInfoResponse)
}
answers = append(answers, string(ans))
packet = rest
}
if len(packet) != 0 {
return nil, errors.New("ssh: junk at end of message")
}
return answers, nil
}
// Copyright 2011 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 ssh
// Session implements an interactive session described in
// "RFC 4254, section 6".
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"sync"
)
type Signal string
// POSIX signals as listed in RFC 4254 Section 6.10.
const (
SIGABRT Signal = "ABRT"
SIGALRM Signal = "ALRM"
SIGFPE Signal = "FPE"
SIGHUP Signal = "HUP"
SIGILL Signal = "ILL"
SIGINT Signal = "INT"
SIGKILL Signal = "KILL"
SIGPIPE Signal = "PIPE"
SIGQUIT Signal = "QUIT"
SIGSEGV Signal = "SEGV"
SIGTERM Signal = "TERM"
SIGUSR1 Signal = "USR1"
SIGUSR2 Signal = "USR2"
)
var signals = map[Signal]int{
SIGABRT: 6,
SIGALRM: 14,
SIGFPE: 8,
SIGHUP: 1,
SIGILL: 4,
SIGINT: 2,
SIGKILL: 9,
SIGPIPE: 13,
SIGQUIT: 3,
SIGSEGV: 11,
SIGTERM: 15,
}
type TerminalModes map[uint8]uint32
// POSIX terminal mode flags as listed in RFC 4254 Section 8.
const (
tty_OP_END = 0
VINTR = 1
VQUIT = 2
VERASE = 3
VKILL = 4
VEOF = 5
VEOL = 6
VEOL2 = 7
VSTART = 8
VSTOP = 9
VSUSP = 10
VDSUSP = 11
VREPRINT = 12
VWERASE = 13
VLNEXT = 14
VFLUSH = 15
VSWTCH = 16
VSTATUS = 17
VDISCARD = 18
IGNPAR = 30
PARMRK = 31
INPCK = 32
ISTRIP = 33
INLCR = 34
IGNCR = 35
ICRNL = 36
IUCLC = 37
IXON = 38
IXANY = 39
IXOFF = 40
IMAXBEL = 41
IUTF8 = 42 // RFC 8160
ISIG = 50
ICANON = 51
XCASE = 52
ECHO = 53
ECHOE = 54
ECHOK = 55
ECHONL = 56
NOFLSH = 57
TOSTOP = 58
IEXTEN = 59
ECHOCTL = 60
ECHOKE = 61
PENDIN = 62
OPOST = 70
OLCUC = 71
ONLCR = 72
OCRNL = 73
ONOCR = 74
ONLRET = 75
CS7 = 90
CS8 = 91
PARENB = 92
PARODD = 93
TTY_OP_ISPEED = 128
TTY_OP_OSPEED = 129
)
// A Session represents a connection to a remote command or shell.
type Session struct {
// Stdin specifies the remote process's standard input.
// If Stdin is nil, the remote process reads from an empty
// bytes.Buffer.
Stdin io.Reader
// Stdout and Stderr specify the remote process's standard
// output and error.
//
// If either is nil, Run connects the corresponding file
// descriptor to an instance of io.Discard. There is a
// fixed amount of buffering that is shared for the two streams.
// If either blocks it may eventually cause the remote
// command to block.
Stdout io.Writer
Stderr io.Writer
ch Channel // the channel backing this session
started bool // true once Start, Run or Shell is invoked.
copyFuncs []func() error
errors chan error // one send per copyFunc
// true if pipe method is active
stdinpipe, stdoutpipe, stderrpipe bool
// stdinPipeWriter is non-nil if StdinPipe has not been called
// and Stdin was specified by the user; it is the write end of
// a pipe connecting Session.Stdin to the stdin channel.
stdinPipeWriter io.WriteCloser
exitStatus chan error
}
// SendRequest sends an out-of-band channel request on the SSH channel
// underlying the session.
func (s *Session) SendRequest(name string, wantReply bool, payload []byte) (bool, error) {
return s.ch.SendRequest(name, wantReply, payload)
}
func (s *Session) Close() error {
return s.ch.Close()
}
// RFC 4254 Section 6.4.
type setenvRequest struct {
Name string
Value string
}
// Setenv sets an environment variable that will be applied to any
// command executed by Shell or Run.
func (s *Session) Setenv(name, value string) error {
msg := setenvRequest{
Name: name,
Value: value,
}
ok, err := s.ch.SendRequest("env", true, Marshal(&msg))
if err == nil && !ok {
err = errors.New("ssh: setenv failed")
}
return err
}
// RFC 4254 Section 6.2.
type ptyRequestMsg struct {
Term string
Columns uint32
Rows uint32
Width uint32
Height uint32
Modelist string
}
// RequestPty requests the association of a pty with the session on the remote host.
func (s *Session) RequestPty(term string, h, w int, termmodes TerminalModes) error {
var tm []byte
for k, v := range termmodes {
kv := struct {
Key byte
Val uint32
}{k, v}
tm = append(tm, Marshal(&kv)...)
}
tm = append(tm, tty_OP_END)
req := ptyRequestMsg{
Term: term,
Columns: uint32(w),
Rows: uint32(h),
Width: uint32(w * 8),
Height: uint32(h * 8),
Modelist: string(tm),
}
ok, err := s.ch.SendRequest("pty-req", true, Marshal(&req))
if err == nil && !ok {
err = errors.New("ssh: pty-req failed")
}
return err
}
// RFC 4254 Section 6.5.
type subsystemRequestMsg struct {
Subsystem string
}
// RequestSubsystem requests the association of a subsystem with the session on the remote host.
// A subsystem is a predefined command that runs in the background when the ssh session is initiated
func (s *Session) RequestSubsystem(subsystem string) error {
msg := subsystemRequestMsg{
Subsystem: subsystem,
}
ok, err := s.ch.SendRequest("subsystem", true, Marshal(&msg))
if err == nil && !ok {
err = errors.New("ssh: subsystem request failed")
}
return err
}
// RFC 4254 Section 6.7.
type ptyWindowChangeMsg struct {
Columns uint32
Rows uint32
Width uint32
Height uint32
}
// WindowChange informs the remote host about a terminal window dimension change to h rows and w columns.
func (s *Session) WindowChange(h, w int) error {
req := ptyWindowChangeMsg{
Columns: uint32(w),
Rows: uint32(h),
Width: uint32(w * 8),
Height: uint32(h * 8),
}
_, err := s.ch.SendRequest("window-change", false, Marshal(&req))
return err
}
// RFC 4254 Section 6.9.
type signalMsg struct {
Signal string
}
// Signal sends the given signal to the remote process.
// sig is one of the SIG* constants.
func (s *Session) Signal(sig Signal) error {
msg := signalMsg{
Signal: string(sig),
}
_, err := s.ch.SendRequest("signal", false, Marshal(&msg))
return err
}
// RFC 4254 Section 6.5.
type execMsg struct {
Command string
}
// Start runs cmd on the remote host. Typically, the remote
// server passes cmd to the shell for interpretation.
// A Session only accepts one call to Run, Start or Shell.
func (s *Session) Start(cmd string) error {
if s.started {
return errors.New("ssh: session already started")
}
req := execMsg{
Command: cmd,
}
ok, err := s.ch.SendRequest("exec", true, Marshal(&req))
if err == nil && !ok {
err = fmt.Errorf("ssh: command %v failed", cmd)
}
if err != nil {
return err
}
return s.start()
}
// Run runs cmd on the remote host. Typically, the remote
// server passes cmd to the shell for interpretation.
// A Session only accepts one call to Run, Start, Shell, Output,
// or CombinedOutput.
//
// The returned error is nil if the command runs, has no problems
// copying stdin, stdout, and stderr, and exits with a zero exit
// status.
//
// If the remote server does not send an exit status, an error of type
// *ExitMissingError is returned. If the command completes
// unsuccessfully or is interrupted by a signal, the error is of type
// *ExitError. Other error types may be returned for I/O problems.
func (s *Session) Run(cmd string) error {
err := s.Start(cmd)
if err != nil {
return err
}
return s.Wait()
}
// Output runs cmd on the remote host and returns its standard output.
func (s *Session) Output(cmd string) ([]byte, error) {
if s.Stdout != nil {
return nil, errors.New("ssh: Stdout already set")
}
var b bytes.Buffer
s.Stdout = &b
err := s.Run(cmd)
return b.Bytes(), err
}
type singleWriter struct {
b bytes.Buffer
mu sync.Mutex
}
func (w *singleWriter) Write(p []byte) (int, error) {
w.mu.Lock()
defer w.mu.Unlock()
return w.b.Write(p)
}
// CombinedOutput runs cmd on the remote host and returns its combined
// standard output and standard error.
func (s *Session) CombinedOutput(cmd string) ([]byte, error) {
if s.Stdout != nil {
return nil, errors.New("ssh: Stdout already set")
}
if s.Stderr != nil {
return nil, errors.New("ssh: Stderr already set")
}
var b singleWriter
s.Stdout = &b
s.Stderr = &b
err := s.Run(cmd)
return b.b.Bytes(), err
}
// Shell starts a login shell on the remote host. A Session only
// accepts one call to Run, Start, Shell, Output, or CombinedOutput.
func (s *Session) Shell() error {
if s.started {
return errors.New("ssh: session already started")
}
ok, err := s.ch.SendRequest("shell", true, nil)
if err == nil && !ok {
return errors.New("ssh: could not start shell")
}
if err != nil {
return err
}
return s.start()
}
func (s *Session) start() error {
s.started = true
type F func(*Session)
for _, setupFd := range []F{(*Session).stdin, (*Session).stdout, (*Session).stderr} {
setupFd(s)
}
s.errors = make(chan error, len(s.copyFuncs))
for _, fn := range s.copyFuncs {
go func(fn func() error) {
s.errors <- fn()
}(fn)
}
return nil
}
// Wait waits for the remote command to exit.
//
// The returned error is nil if the command runs, has no problems
// copying stdin, stdout, and stderr, and exits with a zero exit
// status.
//
// If the remote server does not send an exit status, an error of type
// *ExitMissingError is returned. If the command completes
// unsuccessfully or is interrupted by a signal, the error is of type
// *ExitError. Other error types may be returned for I/O problems.
func (s *Session) Wait() error {
if !s.started {
return errors.New("ssh: session not started")
}
waitErr := <-s.exitStatus
if s.stdinPipeWriter != nil {
s.stdinPipeWriter.Close()
}
var copyError error
for range s.copyFuncs {
if err := <-s.errors; err != nil && copyError == nil {
copyError = err
}
}
if waitErr != nil {
return waitErr
}
return copyError
}
func (s *Session) wait(reqs <-chan *Request) error {
wm := Waitmsg{status: -1}
// Wait for msg channel to be closed before returning.
for msg := range reqs {
switch msg.Type {
case "exit-status":
wm.status = int(binary.BigEndian.Uint32(msg.Payload))
case "exit-signal":
var sigval struct {
Signal string
CoreDumped bool
Error string
Lang string
}
if err := Unmarshal(msg.Payload, &sigval); err != nil {
return err
}
// Must sanitize strings?
wm.signal = sigval.Signal
wm.msg = sigval.Error
wm.lang = sigval.Lang
default:
// This handles keepalives and matches
// OpenSSH's behaviour.
if msg.WantReply {
msg.Reply(false, nil)
}
}
}
if wm.status == 0 {
return nil
}
if wm.status == -1 {
// exit-status was never sent from server
if wm.signal == "" {
// signal was not sent either. RFC 4254
// section 6.10 recommends against this
// behavior, but it is allowed, so we let
// clients handle it.
return &ExitMissingError{}
}
wm.status = 128
if _, ok := signals[Signal(wm.signal)]; ok {
wm.status += signals[Signal(wm.signal)]
}
}
return &ExitError{wm}
}
// ExitMissingError is returned if a session is torn down cleanly, but
// the server sends no confirmation of the exit status.
type ExitMissingError struct{}
func (e *ExitMissingError) Error() string {
return "wait: remote command exited without exit status or exit signal"
}
func (s *Session) stdin() {
if s.stdinpipe {
return
}
var stdin io.Reader
if s.Stdin == nil {
stdin = new(bytes.Buffer)
} else {
r, w := io.Pipe()
go func() {
_, err := io.Copy(w, s.Stdin)
w.CloseWithError(err)
}()
stdin, s.stdinPipeWriter = r, w
}
s.copyFuncs = append(s.copyFuncs, func() error {
_, err := io.Copy(s.ch, stdin)
if err1 := s.ch.CloseWrite(); err == nil && err1 != io.EOF {
err = err1
}
return err
})
}
func (s *Session) stdout() {
if s.stdoutpipe {
return
}
if s.Stdout == nil {
s.Stdout = io.Discard
}
s.copyFuncs = append(s.copyFuncs, func() error {
_, err := io.Copy(s.Stdout, s.ch)
return err
})
}
func (s *Session) stderr() {
if s.stderrpipe {
return
}
if s.Stderr == nil {
s.Stderr = io.Discard
}
s.copyFuncs = append(s.copyFuncs, func() error {
_, err := io.Copy(s.Stderr, s.ch.Stderr())
return err
})
}
// sessionStdin reroutes Close to CloseWrite.
type sessionStdin struct {
io.Writer
ch Channel
}
func (s *sessionStdin) Close() error {
return s.ch.CloseWrite()
}
// StdinPipe returns a pipe that will be connected to the
// remote command's standard input when the command starts.
func (s *Session) StdinPipe() (io.WriteCloser, error) {
if s.Stdin != nil {
return nil, errors.New("ssh: Stdin already set")
}
if s.started {
return nil, errors.New("ssh: StdinPipe after process started")
}
s.stdinpipe = true
return &sessionStdin{s.ch, s.ch}, nil
}
// StdoutPipe returns a pipe that will be connected to the
// remote command's standard output when the command starts.
// There is a fixed amount of buffering that is shared between
// stdout and stderr streams. If the StdoutPipe reader is
// not serviced fast enough it may eventually cause the
// remote command to block.
func (s *Session) StdoutPipe() (io.Reader, error) {
if s.Stdout != nil {
return nil, errors.New("ssh: Stdout already set")
}
if s.started {
return nil, errors.New("ssh: StdoutPipe after process started")
}
s.stdoutpipe = true
return s.ch, nil
}
// StderrPipe returns a pipe that will be connected to the
// remote command's standard error when the command starts.
// There is a fixed amount of buffering that is shared between
// stdout and stderr streams. If the StderrPipe reader is
// not serviced fast enough it may eventually cause the
// remote command to block.
func (s *Session) StderrPipe() (io.Reader, error) {
if s.Stderr != nil {
return nil, errors.New("ssh: Stderr already set")
}
if s.started {
return nil, errors.New("ssh: StderrPipe after process started")
}
s.stderrpipe = true
return s.ch.Stderr(), nil
}
// newSession returns a new interactive session on the remote host.
func newSession(ch Channel, reqs <-chan *Request) (*Session, error) {
s := &Session{
ch: ch,
}
s.exitStatus = make(chan error, 1)
go func() {
s.exitStatus <- s.wait(reqs)
}()
return s, nil
}
// An ExitError reports unsuccessful completion of a remote command.
type ExitError struct {
Waitmsg
}
func (e *ExitError) Error() string {
return e.Waitmsg.String()
}
// Waitmsg stores the information about an exited remote command
// as reported by Wait.
type Waitmsg struct {
status int
signal string
msg string
lang string
}
// ExitStatus returns the exit status of the remote command.
func (w Waitmsg) ExitStatus() int {
return w.status
}
// Signal returns the exit signal of the remote command if
// it was terminated violently.
func (w Waitmsg) Signal() string {
return w.signal
}
// Msg returns the exit message given by the remote command
func (w Waitmsg) Msg() string {
return w.msg
}
// Lang returns the language tag. See RFC 3066
func (w Waitmsg) Lang() string {
return w.lang
}
func (w Waitmsg) String() string {
str := fmt.Sprintf("Process exited with status %v", w.status)
if w.signal != "" {
str += fmt.Sprintf(" from signal %v", w.signal)
}
if w.msg != "" {
str += fmt.Sprintf(". Reason was: %v", w.msg)
}
return str
}
// Copyright 2011 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 ssh
import (
"encoding/asn1"
"errors"
)
var krb5OID []byte
func init() {
krb5OID, _ = asn1.Marshal(krb5Mesh)
}
// GSSAPIClient provides the API to plug-in GSSAPI authentication for client logins.
type GSSAPIClient interface {
// InitSecContext initiates the establishment of a security context for GSS-API between the
// ssh client and ssh server. Initially the token parameter should be specified as nil.
// The routine may return a outputToken which should be transferred to
// the ssh server, where the ssh server will present it to
// AcceptSecContext. If no token need be sent, InitSecContext will indicate this by setting
// needContinue to false. To complete the context
// establishment, one or more reply tokens may be required from the ssh
// server;if so, InitSecContext will return a needContinue which is true.
// In this case, InitSecContext should be called again when the
// reply token is received from the ssh server, passing the reply
// token to InitSecContext via the token parameters.
// See RFC 2743 section 2.2.1 and RFC 4462 section 3.4.
InitSecContext(target string, token []byte, isGSSDelegCreds bool) (outputToken []byte, needContinue bool, err error)
// GetMIC generates a cryptographic MIC for the SSH2 message, and places
// the MIC in a token for transfer to the ssh server.
// The contents of the MIC field are obtained by calling GSS_GetMIC()
// over the following, using the GSS-API context that was just
// established:
// string session identifier
// byte SSH_MSG_USERAUTH_REQUEST
// string user name
// string service
// string "gssapi-with-mic"
// See RFC 2743 section 2.3.1 and RFC 4462 3.5.
GetMIC(micFiled []byte) ([]byte, error)
// Whenever possible, it should be possible for
// DeleteSecContext() calls to be successfully processed even
// if other calls cannot succeed, thereby enabling context-related
// resources to be released.
// In addition to deleting established security contexts,
// gss_delete_sec_context must also be able to delete "half-built"
// security contexts resulting from an incomplete sequence of
// InitSecContext()/AcceptSecContext() calls.
// See RFC 2743 section 2.2.3.
DeleteSecContext() error
}
// GSSAPIServer provides the API to plug in GSSAPI authentication for server logins.
type GSSAPIServer interface {
// AcceptSecContext allows a remotely initiated security context between the application
// and a remote peer to be established by the ssh client. The routine may return a
// outputToken which should be transferred to the ssh client,
// where the ssh client will present it to InitSecContext.
// If no token need be sent, AcceptSecContext will indicate this
// by setting the needContinue to false. To
// complete the context establishment, one or more reply tokens may be
// required from the ssh client. if so, AcceptSecContext
// will return a needContinue which is true, in which case it
// should be called again when the reply token is received from the ssh
// client, passing the token to AcceptSecContext via the
// token parameters.
// The srcName return value is the authenticated username.
// See RFC 2743 section 2.2.2 and RFC 4462 section 3.4.
AcceptSecContext(token []byte) (outputToken []byte, srcName string, needContinue bool, err error)
// VerifyMIC verifies that a cryptographic MIC, contained in the token parameter,
// fits the supplied message is received from the ssh client.
// See RFC 2743 section 2.3.2.
VerifyMIC(micField []byte, micToken []byte) error
// Whenever possible, it should be possible for
// DeleteSecContext() calls to be successfully processed even
// if other calls cannot succeed, thereby enabling context-related
// resources to be released.
// In addition to deleting established security contexts,
// gss_delete_sec_context must also be able to delete "half-built"
// security contexts resulting from an incomplete sequence of
// InitSecContext()/AcceptSecContext() calls.
// See RFC 2743 section 2.2.3.
DeleteSecContext() error
}
var (
// OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication,
// so we also support the krb5 mechanism only.
// See RFC 1964 section 1.
krb5Mesh = asn1.ObjectIdentifier{1, 2, 840, 113554, 1, 2, 2}
)
// The GSS-API authentication method is initiated when the client sends an SSH_MSG_USERAUTH_REQUEST
// See RFC 4462 section 3.2.
type userAuthRequestGSSAPI struct {
N uint32
OIDS []asn1.ObjectIdentifier
}
func parseGSSAPIPayload(payload []byte) (*userAuthRequestGSSAPI, error) {
n, rest, ok := parseUint32(payload)
if !ok {
return nil, errors.New("parse uint32 failed")
}
s := &userAuthRequestGSSAPI{
N: n,
OIDS: make([]asn1.ObjectIdentifier, n),
}
for i := 0; i < int(n); i++ {
var (
desiredMech []byte
err error
)
desiredMech, rest, ok = parseString(rest)
if !ok {
return nil, errors.New("parse string failed")
}
if rest, err = asn1.Unmarshal(desiredMech, &s.OIDS[i]); err != nil {
return nil, err
}
}
return s, nil
}
// See RFC 4462 section 3.6.
func buildMIC(sessionID string, username string, service string, authMethod string) []byte {
out := make([]byte, 0, 0)
out = appendString(out, sessionID)
out = append(out, msgUserAuthRequest)
out = appendString(out, username)
out = appendString(out, service)
out = appendString(out, authMethod)
return out
}
package ssh
import (
"errors"
"io"
"net"
)
// streamLocalChannelOpenDirectMsg is a struct used for SSH_MSG_CHANNEL_OPEN message
// with "direct-streamlocal@openssh.com" string.
//
// See openssh-portable/PROTOCOL, section 2.4. connection: Unix domain socket forwarding
// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL#L235
type streamLocalChannelOpenDirectMsg struct {
socketPath string
reserved0 string
reserved1 uint32
}
// forwardedStreamLocalPayload is a struct used for SSH_MSG_CHANNEL_OPEN message
// with "forwarded-streamlocal@openssh.com" string.
type forwardedStreamLocalPayload struct {
SocketPath string
Reserved0 string
}
// streamLocalChannelForwardMsg is a struct used for SSH2_MSG_GLOBAL_REQUEST message
// with "streamlocal-forward@openssh.com"/"cancel-streamlocal-forward@openssh.com" string.
type streamLocalChannelForwardMsg struct {
socketPath string
}
// ListenUnix is similar to ListenTCP but uses a Unix domain socket.
func (c *Client) ListenUnix(socketPath string) (net.Listener, error) {
c.handleForwardsOnce.Do(c.handleForwards)
m := streamLocalChannelForwardMsg{
socketPath,
}
// send message
ok, _, err := c.SendRequest("streamlocal-forward@openssh.com", true, Marshal(&m))
if err != nil {
return nil, err
}
if !ok {
return nil, errors.New("ssh: streamlocal-forward@openssh.com request denied by peer")
}
ch := c.forwards.add("unix", socketPath)
return &unixListener{socketPath, c, ch}, nil
}
func (c *Client) dialStreamLocal(socketPath string) (Channel, error) {
msg := streamLocalChannelOpenDirectMsg{
socketPath: socketPath,
}
ch, in, err := c.OpenChannel("direct-streamlocal@openssh.com", Marshal(&msg))
if err != nil {
return nil, err
}
go DiscardRequests(in)
return ch, err
}
type unixListener struct {
socketPath string
conn *Client
in <-chan forward
}
// Accept waits for and returns the next connection to the listener.
func (l *unixListener) Accept() (net.Conn, error) {
s, ok := <-l.in
if !ok {
return nil, io.EOF
}
ch, incoming, err := s.newCh.Accept()
if err != nil {
return nil, err
}
go DiscardRequests(incoming)
return &chanConn{
Channel: ch,
laddr: &net.UnixAddr{
Name: l.socketPath,
Net: "unix",
},
raddr: &net.UnixAddr{
Name: "@",
Net: "unix",
},
}, nil
}
// Close closes the listener.
func (l *unixListener) Close() error {
// this also closes the listener.
l.conn.forwards.remove("unix", l.socketPath)
m := streamLocalChannelForwardMsg{
l.socketPath,
}
ok, _, err := l.conn.SendRequest("cancel-streamlocal-forward@openssh.com", true, Marshal(&m))
if err == nil && !ok {
err = errors.New("ssh: cancel-streamlocal-forward@openssh.com failed")
}
return err
}
// Addr returns the listener's network address.
func (l *unixListener) Addr() net.Addr {
return &net.UnixAddr{
Name: l.socketPath,
Net: "unix",
}
}
// Copyright 2011 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 ssh
import (
"context"
"errors"
"fmt"
"io"
"math/rand"
"net"
"net/netip"
"strconv"
"strings"
"sync"
"time"
)
// Listen requests the remote peer open a listening socket on
// addr. Incoming connections will be available by calling Accept on
// the returned net.Listener. The listener must be serviced, or the
// SSH connection may hang.
// N must be "tcp", "tcp4", "tcp6", or "unix".
//
// If the address is a hostname, it is sent to the remote peer as-is, without
// being resolved locally, and the Listener Addr method will return a zero IP.
func (c *Client) Listen(n, addr string) (net.Listener, error) {
switch n {
case "tcp", "tcp4", "tcp6":
host, portStr, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
}
port, err := strconv.ParseInt(portStr, 10, 32)
if err != nil {
return nil, err
}
return c.listenTCPInternal(host, int(port))
case "unix":
return c.ListenUnix(addr)
default:
return nil, fmt.Errorf("ssh: unsupported protocol: %s", n)
}
}
// Automatic port allocation is broken with OpenSSH before 6.0. See
// also https://bugzilla.mindrot.org/show_bug.cgi?id=2017. In
// particular, OpenSSH 5.9 sends a channelOpenMsg with port number 0,
// rather than the actual port number. This means you can never open
// two different listeners with auto allocated ports. We work around
// this by trying explicit ports until we succeed.
const openSSHPrefix = "OpenSSH_"
var portRandomizer = rand.New(rand.NewSource(time.Now().UnixNano()))
// isBrokenOpenSSHVersion returns true if the given version string
// specifies a version of OpenSSH that is known to have a bug in port
// forwarding.
func isBrokenOpenSSHVersion(versionStr string) bool {
i := strings.Index(versionStr, openSSHPrefix)
if i < 0 {
return false
}
i += len(openSSHPrefix)
j := i
for ; j < len(versionStr); j++ {
if versionStr[j] < '0' || versionStr[j] > '9' {
break
}
}
version, _ := strconv.Atoi(versionStr[i:j])
return version < 6
}
// autoPortListenWorkaround simulates automatic port allocation by
// trying random ports repeatedly.
func (c *Client) autoPortListenWorkaround(laddr *net.TCPAddr) (net.Listener, error) {
var sshListener net.Listener
var err error
const tries = 10
for i := 0; i < tries; i++ {
addr := *laddr
addr.Port = 1024 + portRandomizer.Intn(60000)
sshListener, err = c.ListenTCP(&addr)
if err == nil {
laddr.Port = addr.Port
return sshListener, err
}
}
return nil, fmt.Errorf("ssh: listen on random port failed after %d tries: %v", tries, err)
}
// RFC 4254 7.1
type channelForwardMsg struct {
addr string
rport uint32
}
// handleForwards starts goroutines handling forwarded connections.
// It's called on first use by (*Client).ListenTCP to not launch
// goroutines until needed.
func (c *Client) handleForwards() {
go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-tcpip"))
go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-streamlocal@openssh.com"))
}
// ListenTCP requests the remote peer open a listening socket
// on laddr. Incoming connections will be available by calling
// Accept on the returned net.Listener.
//
// ListenTCP accepts an IP address, to provide a hostname use [Client.Listen]
// with "tcp", "tcp4", or "tcp6" network instead.
func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) {
c.handleForwardsOnce.Do(c.handleForwards)
if laddr.Port == 0 && isBrokenOpenSSHVersion(string(c.ServerVersion())) {
return c.autoPortListenWorkaround(laddr)
}
return c.listenTCPInternal(laddr.IP.String(), laddr.Port)
}
func (c *Client) listenTCPInternal(host string, port int) (net.Listener, error) {
c.handleForwardsOnce.Do(c.handleForwards)
m := channelForwardMsg{
host,
uint32(port),
}
// send message
ok, resp, err := c.SendRequest("tcpip-forward", true, Marshal(&m))
if err != nil {
return nil, err
}
if !ok {
return nil, errors.New("ssh: tcpip-forward request denied by peer")
}
// If the original port was 0, then the remote side will
// supply a real port number in the response.
if port == 0 {
var p struct {
Port uint32
}
if err := Unmarshal(resp, &p); err != nil {
return nil, err
}
port = int(p.Port)
}
// Construct a local address placeholder for the remote listener. If the
// original host is an IP address, preserve it so that Listener.Addr()
// reports the same IP. If the host is a hostname or cannot be parsed as an
// IP, fall back to IPv4zero. The port field is always set, even if the
// original port was 0, because in that case the remote server will assign
// one, allowing callers to determine which port was selected.
ip := net.IPv4zero
if parsed, err := netip.ParseAddr(host); err == nil {
ip = net.IP(parsed.AsSlice())
}
laddr := &net.TCPAddr{
IP: ip,
Port: port,
}
addr := net.JoinHostPort(host, strconv.FormatInt(int64(port), 10))
ch := c.forwards.add("tcp", addr)
return &tcpListener{laddr, addr, c, ch}, nil
}
// forwardList stores a mapping between remote
// forward requests and the tcpListeners.
type forwardList struct {
sync.Mutex
entries []forwardEntry
}
// forwardEntry represents an established mapping of a laddr on a
// remote ssh server to a channel connected to a tcpListener.
type forwardEntry struct {
addr string // host:port or socket path
network string // tcp or unix
c chan forward
}
// forward represents an incoming forwarded tcpip connection. The
// arguments to add/remove/lookup should be address as specified in
// the original forward-request.
type forward struct {
newCh NewChannel // the ssh client channel underlying this forward
raddr net.Addr // the raddr of the incoming connection
}
func (l *forwardList) add(n, addr string) chan forward {
l.Lock()
defer l.Unlock()
f := forwardEntry{
addr: addr,
network: n,
c: make(chan forward, 1),
}
l.entries = append(l.entries, f)
return f.c
}
// See RFC 4254, section 7.2
type forwardedTCPPayload struct {
Addr string
Port uint32
OriginAddr string
OriginPort uint32
}
// parseTCPAddr parses the originating address from the remote into a *net.TCPAddr.
func parseTCPAddr(addr string, port uint32) (*net.TCPAddr, error) {
if port == 0 || port > 65535 {
return nil, fmt.Errorf("ssh: port number out of range: %d", port)
}
ip, err := netip.ParseAddr(addr)
if err != nil {
return nil, fmt.Errorf("ssh: cannot parse IP address %q", addr)
}
return &net.TCPAddr{IP: net.IP(ip.AsSlice()), Port: int(port)}, nil
}
func (l *forwardList) handleChannels(in <-chan NewChannel) {
for ch := range in {
var (
addr string
network string
raddr net.Addr
err error
)
switch channelType := ch.ChannelType(); channelType {
case "forwarded-tcpip":
var payload forwardedTCPPayload
if err = Unmarshal(ch.ExtraData(), &payload); err != nil {
ch.Reject(ConnectionFailed, "could not parse forwarded-tcpip payload: "+err.Error())
continue
}
// RFC 4254 section 7.2 specifies that incoming addresses should
// list the address that was connected, in string format. It is the
// same address used in the tcpip-forward request. The originator
// address is an IP address instead.
addr = net.JoinHostPort(payload.Addr, strconv.FormatUint(uint64(payload.Port), 10))
raddr, err = parseTCPAddr(payload.OriginAddr, payload.OriginPort)
if err != nil {
ch.Reject(ConnectionFailed, err.Error())
continue
}
network = "tcp"
case "forwarded-streamlocal@openssh.com":
var payload forwardedStreamLocalPayload
if err = Unmarshal(ch.ExtraData(), &payload); err != nil {
ch.Reject(ConnectionFailed, "could not parse forwarded-streamlocal@openssh.com payload: "+err.Error())
continue
}
addr = payload.SocketPath
raddr = &net.UnixAddr{
Name: "@",
Net: "unix",
}
network = "unix"
default:
panic(fmt.Errorf("ssh: unknown channel type %s", channelType))
}
if ok := l.forward(network, addr, raddr, ch); !ok {
// Section 7.2, implementations MUST reject spurious incoming
// connections.
ch.Reject(Prohibited, "no forward for address")
continue
}
}
}
// remove removes the forward entry, and the channel feeding its
// listener.
func (l *forwardList) remove(n, addr string) {
l.Lock()
defer l.Unlock()
for i, f := range l.entries {
if n == f.network && addr == f.addr {
l.entries = append(l.entries[:i], l.entries[i+1:]...)
close(f.c)
return
}
}
}
// closeAll closes and clears all forwards.
func (l *forwardList) closeAll() {
l.Lock()
defer l.Unlock()
for _, f := range l.entries {
close(f.c)
}
l.entries = nil
}
func (l *forwardList) forward(n, addr string, raddr net.Addr, ch NewChannel) bool {
l.Lock()
defer l.Unlock()
for _, f := range l.entries {
if n == f.network && addr == f.addr {
f.c <- forward{newCh: ch, raddr: raddr}
return true
}
}
return false
}
type tcpListener struct {
laddr *net.TCPAddr
addr string
conn *Client
in <-chan forward
}
// Accept waits for and returns the next connection to the listener.
func (l *tcpListener) Accept() (net.Conn, error) {
s, ok := <-l.in
if !ok {
return nil, io.EOF
}
ch, incoming, err := s.newCh.Accept()
if err != nil {
return nil, err
}
go DiscardRequests(incoming)
return &chanConn{
Channel: ch,
laddr: l.laddr,
raddr: s.raddr,
}, nil
}
// Close closes the listener.
func (l *tcpListener) Close() error {
host, port, err := net.SplitHostPort(l.addr)
if err != nil {
return err
}
rport, err := strconv.ParseUint(port, 10, 32)
if err != nil {
return err
}
m := channelForwardMsg{
host,
uint32(rport),
}
// this also closes the listener.
l.conn.forwards.remove("tcp", l.addr)
ok, _, err := l.conn.SendRequest("cancel-tcpip-forward", true, Marshal(&m))
if err == nil && !ok {
err = errors.New("ssh: cancel-tcpip-forward failed")
}
return err
}
// Addr returns the listener's network address.
func (l *tcpListener) Addr() net.Addr {
return l.laddr
}
// DialContext initiates a connection to the addr from the remote host.
//
// The provided Context must be non-nil. If the context expires before the
// connection is complete, an error is returned. Once successfully connected,
// any expiration of the context will not affect the connection.
//
// See func Dial for additional information.
func (c *Client) DialContext(ctx context.Context, n, addr string) (net.Conn, error) {
if err := ctx.Err(); err != nil {
return nil, err
}
type connErr struct {
conn net.Conn
err error
}
ch := make(chan connErr)
go func() {
conn, err := c.Dial(n, addr)
select {
case ch <- connErr{conn, err}:
case <-ctx.Done():
if conn != nil {
conn.Close()
}
}
}()
select {
case res := <-ch:
return res.conn, res.err
case <-ctx.Done():
return nil, ctx.Err()
}
}
// Dial initiates a connection to the addr from the remote host.
// The resulting connection has a zero LocalAddr() and RemoteAddr().
func (c *Client) Dial(n, addr string) (net.Conn, error) {
var ch Channel
switch n {
case "tcp", "tcp4", "tcp6":
// Parse the address into host and numeric port.
host, portString, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
}
port, err := strconv.ParseUint(portString, 10, 16)
if err != nil {
return nil, err
}
ch, err = c.dial(net.IPv4zero.String(), 0, host, int(port))
if err != nil {
return nil, err
}
// Use a zero address for local and remote address.
zeroAddr := &net.TCPAddr{
IP: net.IPv4zero,
Port: 0,
}
return &chanConn{
Channel: ch,
laddr: zeroAddr,
raddr: zeroAddr,
}, nil
case "unix":
var err error
ch, err = c.dialStreamLocal(addr)
if err != nil {
return nil, err
}
return &chanConn{
Channel: ch,
laddr: &net.UnixAddr{
Name: "@",
Net: "unix",
},
raddr: &net.UnixAddr{
Name: addr,
Net: "unix",
},
}, nil
default:
return nil, fmt.Errorf("ssh: unsupported protocol: %s", n)
}
}
// DialTCP connects to the remote address raddr on the network net,
// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used
// as the local address for the connection.
func (c *Client) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, error) {
if laddr == nil {
laddr = &net.TCPAddr{
IP: net.IPv4zero,
Port: 0,
}
}
ch, err := c.dial(laddr.IP.String(), laddr.Port, raddr.IP.String(), raddr.Port)
if err != nil {
return nil, err
}
return &chanConn{
Channel: ch,
laddr: laddr,
raddr: raddr,
}, nil
}
// RFC 4254 7.2
type channelOpenDirectMsg struct {
raddr string
rport uint32
laddr string
lport uint32
}
func (c *Client) dial(laddr string, lport int, raddr string, rport int) (Channel, error) {
msg := channelOpenDirectMsg{
raddr: raddr,
rport: uint32(rport),
laddr: laddr,
lport: uint32(lport),
}
ch, in, err := c.OpenChannel("direct-tcpip", Marshal(&msg))
if err != nil {
return nil, err
}
go DiscardRequests(in)
return ch, nil
}
type tcpChan struct {
Channel // the backing channel
}
// chanConn fulfills the net.Conn interface without
// the tcpChan having to hold laddr or raddr directly.
type chanConn struct {
Channel
laddr, raddr net.Addr
}
// LocalAddr returns the local network address.
func (t *chanConn) LocalAddr() net.Addr {
return t.laddr
}
// RemoteAddr returns the remote network address.
func (t *chanConn) RemoteAddr() net.Addr {
return t.raddr
}
// SetDeadline sets the read and write deadlines associated
// with the connection.
func (t *chanConn) SetDeadline(deadline time.Time) error {
if err := t.SetReadDeadline(deadline); err != nil {
return err
}
return t.SetWriteDeadline(deadline)
}
// SetReadDeadline sets the read deadline.
// A zero value for t means Read will not time out.
// After the deadline, the error from Read will implement net.Error
// with Timeout() == true.
func (t *chanConn) SetReadDeadline(deadline time.Time) error {
// for compatibility with previous version,
// the error message contains "tcpChan"
return errors.New("ssh: tcpChan: deadline not supported")
}
// SetWriteDeadline exists to satisfy the net.Conn interface
// but is not implemented by this type. It always returns an error.
func (t *chanConn) SetWriteDeadline(deadline time.Time) error {
return errors.New("ssh: tcpChan: deadline not supported")
}
// Copyright 2011 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 terminal provides support functions for dealing with terminals, as
// commonly found on UNIX systems.
//
// Deprecated: this package moved to golang.org/x/term.
package terminal
import (
"io"
"golang.org/x/term"
)
// EscapeCodes contains escape sequences that can be written to the terminal in
// order to achieve different styles of text.
type EscapeCodes = term.EscapeCodes
// Terminal contains the state for running a VT100 terminal that is capable of
// reading lines of input.
type Terminal = term.Terminal
// NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is
// a local terminal, that terminal must first have been put into raw mode.
// prompt is a string that is written at the start of each input line (i.e.
// "> ").
func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
return term.NewTerminal(c, prompt)
}
// ErrPasteIndicator may be returned from ReadLine as the error, in addition
// to valid line data. It indicates that bracketed paste mode is enabled and
// that the returned line consists only of pasted data. Programs may wish to
// interpret pasted data more literally than typed data.
var ErrPasteIndicator = term.ErrPasteIndicator
// State contains the state of a terminal.
type State = term.State
// IsTerminal returns whether the given file descriptor is a terminal.
func IsTerminal(fd int) bool {
return term.IsTerminal(fd)
}
// ReadPassword reads a line of input from a terminal without local echo. This
// is commonly used for inputting passwords and other sensitive data. The slice
// returned does not include the \n.
func ReadPassword(fd int) ([]byte, error) {
return term.ReadPassword(fd)
}
// MakeRaw puts the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
func MakeRaw(fd int) (*State, error) {
return term.MakeRaw(fd)
}
// Restore restores the terminal connected to the given file descriptor to a
// previous state.
func Restore(fd int, oldState *State) error {
return term.Restore(fd, oldState)
}
// GetState returns the current state of a terminal which may be useful to
// restore the terminal after a signal.
func GetState(fd int) (*State, error) {
return term.GetState(fd)
}
// GetSize returns the dimensions of the given terminal.
func GetSize(fd int) (width, height int, err error) {
return term.GetSize(fd)
}
// Copyright 2011 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 ssh
import (
"bufio"
"bytes"
"errors"
"fmt"
"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
// packetConn represents a transport that implements packet based
// operations.
type packetConn interface {
// Encrypt and send a packet of data to the remote peer.
writePacket(packet []byte) error
// Read a packet from the connection. The read is blocking,
// i.e. if error is nil, then the returned byte slice is
// always non-empty.
readPacket() ([]byte, error)
// Close closes the write-side of the connection.
Close() error
}
// transport is the keyingTransport that implements the SSH packet
// protocol.
type transport struct {
reader connectionState
writer connectionState
bufReader *bufio.Reader
bufWriter *bufio.Writer
rand io.Reader
isClient bool
io.Closer
strictMode bool
initialKEXDone bool
}
// packetCipher represents a combination of SSH encryption/MAC
// protocol. A single instance should be used for one direction only.
type packetCipher interface {
// writeCipherPacket encrypts the packet and writes it to w. The
// contents of the packet are generally scrambled.
writeCipherPacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error
// readCipherPacket reads and decrypts a packet of data. The
// returned packet may be overwritten by future calls of
// readPacket.
readCipherPacket(seqnum uint32, r io.Reader) ([]byte, error)
}
// connectionState represents one side (read or write) of the
// connection. This is necessary because each direction has its own
// keys, and can even have its own algorithms
type connectionState struct {
packetCipher
seqNum uint32
dir direction
pendingKeyChange chan packetCipher
}
func (t *transport) setStrictMode() error {
if t.reader.seqNum != 1 {
return errors.New("ssh: sequence number != 1 when strict KEX mode requested")
}
t.strictMode = true
return nil
}
func (t *transport) setInitialKEXDone() {
t.initialKEXDone = true
}
// prepareKeyChange sets up key material for a keychange. The key changes in
// both directions are triggered by reading and writing a msgNewKey packet
// respectively.
func (t *transport) prepareKeyChange(algs *NegotiatedAlgorithms, kexResult *kexResult) error {
ciph, err := newPacketCipher(t.reader.dir, algs.Read, kexResult)
if err != nil {
return err
}
t.reader.pendingKeyChange <- ciph
ciph, err = newPacketCipher(t.writer.dir, algs.Write, kexResult)
if err != nil {
return err
}
t.writer.pendingKeyChange <- ciph
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 {
p, err = t.reader.readPacket(t.bufReader, t.strictMode)
if err != nil {
break
}
// in strict mode we pass through DEBUG and IGNORE packets only during the initial KEX
if len(p) == 0 || (t.strictMode && !t.initialKEXDone) || (p[0] != msgIgnore && p[0] != msgDebug) {
break
}
}
if debugTransport {
t.printPacket(p, false)
}
return p, err
}
func (s *connectionState) readPacket(r *bufio.Reader, strictMode bool) ([]byte, error) {
packet, err := s.packetCipher.readCipherPacket(s.seqNum, r)
s.seqNum++
if err == nil && len(packet) == 0 {
err = errors.New("ssh: zero length packet")
}
if len(packet) > 0 {
switch packet[0] {
case msgNewKeys:
select {
case cipher := <-s.pendingKeyChange:
s.packetCipher = cipher
if strictMode {
s.seqNum = 0
}
default:
return nil, errors.New("ssh: got bogus newkeys message")
}
case msgDisconnect:
// Transform a disconnect message into an
// error. Since this is lowest level at which
// we interpret message types, doing it here
// ensures that we don't have to handle it
// elsewhere.
var msg disconnectMsg
if err := Unmarshal(packet, &msg); err != nil {
return nil, err
}
return nil, &msg
}
}
// The packet may point to an internal buffer, so copy the
// packet out here.
fresh := make([]byte, len(packet))
copy(fresh, packet)
return fresh, err
}
func (t *transport) writePacket(packet []byte) error {
if debugTransport {
t.printPacket(packet, true)
}
return t.writer.writePacket(t.bufWriter, t.rand, packet, t.strictMode)
}
func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte, strictMode bool) error {
changeKeys := len(packet) > 0 && packet[0] == msgNewKeys
err := s.packetCipher.writeCipherPacket(s.seqNum, w, rand, packet)
if err != nil {
return err
}
if err = w.Flush(); err != nil {
return err
}
s.seqNum++
if changeKeys {
select {
case cipher := <-s.pendingKeyChange:
s.packetCipher = cipher
if strictMode {
s.seqNum = 0
}
default:
panic("ssh: no key material for msgNewKeys")
}
}
return err
}
func newTransport(rwc io.ReadWriteCloser, rand io.Reader, isClient bool) *transport {
t := &transport{
bufReader: bufio.NewReader(rwc),
bufWriter: bufio.NewWriter(rwc),
rand: rand,
reader: connectionState{
packetCipher: &streamPacketCipher{cipher: noneCipher{}},
pendingKeyChange: make(chan packetCipher, 1),
},
writer: connectionState{
packetCipher: &streamPacketCipher{cipher: noneCipher{}},
pendingKeyChange: make(chan packetCipher, 1),
},
Closer: rwc,
}
t.isClient = isClient
if isClient {
t.reader.dir = serverKeys
t.writer.dir = clientKeys
} else {
t.reader.dir = clientKeys
t.writer.dir = serverKeys
}
return t
}
type direction struct {
ivTag []byte
keyTag []byte
macKeyTag []byte
}
var (
serverKeys = direction{[]byte{'B'}, []byte{'D'}, []byte{'F'}}
clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}}
)
// setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as
// described in RFC 4253, section 6.4. direction should either be serverKeys
// (to setup server->client keys) or clientKeys (for client->server keys).
func newPacketCipher(d direction, algs DirectionAlgorithms, kex *kexResult) (packetCipher, error) {
cipherMode := cipherModes[algs.Cipher]
if cipherMode == nil {
return nil, fmt.Errorf("ssh: unsupported cipher %v", algs.Cipher)
}
iv := make([]byte, cipherMode.ivSize)
key := make([]byte, cipherMode.keySize)
generateKeyMaterial(iv, d.ivTag, kex)
generateKeyMaterial(key, d.keyTag, kex)
var macKey []byte
if !aeadCiphers[algs.Cipher] {
macMode := macModes[algs.MAC]
macKey = make([]byte, macMode.keySize)
generateKeyMaterial(macKey, d.macKeyTag, kex)
}
return cipherModes[algs.Cipher].create(key, iv, macKey, algs)
}
// generateKeyMaterial fills out with key material generated from tag, K, H
// and sessionId, as specified in RFC 4253, section 7.2.
func generateKeyMaterial(out, tag []byte, r *kexResult) {
var digestsSoFar []byte
h := r.Hash.New()
for len(out) > 0 {
h.Reset()
h.Write(r.K)
h.Write(r.H)
if len(digestsSoFar) == 0 {
h.Write(tag)
h.Write(r.SessionID)
} else {
h.Write(digestsSoFar)
}
digest := h.Sum(nil)
n := copy(out, digest)
out = out[n:]
if len(out) > 0 {
digestsSoFar = append(digestsSoFar, digest...)
}
}
}
const packageVersion = "SSH-2.0-Go"
// Sends and receives a version line. The versionLine string should
// be US ASCII, start with "SSH-2.0-", and should not include a
// newline. exchangeVersions returns the other side's version line.
func exchangeVersions(rw io.ReadWriter, versionLine []byte) (them []byte, err error) {
// Contrary to the RFC, we do not ignore lines that don't
// start with "SSH-2.0-" to make the library usable with
// nonconforming servers.
for _, c := range versionLine {
// The spec disallows non US-ASCII chars, and
// specifically forbids null chars.
if c < 32 {
return nil, errors.New("ssh: junk character in version line")
}
}
if _, err = rw.Write(append(versionLine, '\r', '\n')); err != nil {
return
}
them, err = readVersion(rw)
return them, err
}
// maxVersionStringBytes is the maximum number of bytes that we'll
// accept as a version string. RFC 4253 section 4.2 limits this at 255
// chars
const maxVersionStringBytes = 255
// Read version string as specified by RFC 4253, section 4.2.
func readVersion(r io.Reader) ([]byte, error) {
versionString := make([]byte, 0, 64)
var ok bool
var buf [1]byte
for length := 0; length < maxVersionStringBytes; length++ {
_, err := io.ReadFull(r, buf[:])
if err != nil {
return nil, err
}
// The RFC says that the version should be terminated with \r\n
// but several SSH servers actually only send a \n.
if buf[0] == '\n' {
if !bytes.HasPrefix(versionString, []byte("SSH-")) {
// RFC 4253 says we need to ignore all version string lines
// except the one containing the SSH version (provided that
// all the lines do not exceed 255 bytes in total).
versionString = versionString[:0]
continue
}
ok = true
break
}
// non ASCII chars are disallowed, but we are lenient,
// since Go doesn't use null-terminated strings.
// The RFC allows a comment after a space, however,
// all of it (version and comments) goes into the
// session hash.
versionString = append(versionString, buf[0])
}
if !ok {
return nil, errors.New("ssh: overflow reading version string")
}
// There might be a '\r' on the end which we should remove.
if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' {
versionString = versionString[:len(versionString)-1]
}
return versionString, nil
}
// 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.
// Package tea implements the TEA algorithm, as defined in Needham and
// Wheeler's 1994 technical report, “TEA, a Tiny Encryption Algorithm”. See
// http://www.cix.co.uk/~klockstone/tea.pdf for details.
//
// TEA is a legacy cipher and its short block size makes it vulnerable to
// birthday bound attacks (see https://sweet32.info). It should only be used
// where compatibility with legacy systems, not security, is the goal.
//
// Deprecated: any new system should use AES (from crypto/aes, if necessary in
// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
// golang.org/x/crypto/chacha20poly1305).
package tea
import (
"crypto/cipher"
"encoding/binary"
"errors"
)
const (
// BlockSize is the size of a TEA block, in bytes.
BlockSize = 8
// KeySize is the size of a TEA key, in bytes.
KeySize = 16
// delta is the TEA key schedule constant.
delta = 0x9e3779b9
// numRounds is the standard number of rounds in TEA.
numRounds = 64
)
// tea is an instance of the TEA cipher with a particular key.
type tea struct {
key [16]byte
rounds int
}
// NewCipher returns an instance of the TEA cipher with the standard number of
// rounds. The key argument must be 16 bytes long.
func NewCipher(key []byte) (cipher.Block, error) {
return NewCipherWithRounds(key, numRounds)
}
// NewCipherWithRounds returns an instance of the TEA cipher with a given
// number of rounds, which must be even. The key argument must be 16 bytes
// long.
func NewCipherWithRounds(key []byte, rounds int) (cipher.Block, error) {
if len(key) != 16 {
return nil, errors.New("tea: incorrect key size")
}
if rounds&1 != 0 {
return nil, errors.New("tea: odd number of rounds specified")
}
c := &tea{
rounds: rounds,
}
copy(c.key[:], key)
return c, nil
}
// BlockSize returns the TEA block size, which is eight bytes. It is necessary
// to satisfy the Block interface in the package "crypto/cipher".
func (*tea) BlockSize() int {
return BlockSize
}
// Encrypt encrypts the 8 byte buffer src using the key in t and stores the
// result in dst. Note that for amounts of data larger than a block, it is not
// safe to just call Encrypt on successive blocks; instead, use an encryption
// mode like CBC (see crypto/cipher/cbc.go).
func (t *tea) Encrypt(dst, src []byte) {
e := binary.BigEndian
v0, v1 := e.Uint32(src), e.Uint32(src[4:])
k0, k1, k2, k3 := e.Uint32(t.key[0:]), e.Uint32(t.key[4:]), e.Uint32(t.key[8:]), e.Uint32(t.key[12:])
sum := uint32(0)
delta := uint32(delta)
for i := 0; i < t.rounds/2; i++ {
sum += delta
v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1)
v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3)
}
e.PutUint32(dst, v0)
e.PutUint32(dst[4:], v1)
}
// Decrypt decrypts the 8 byte buffer src using the key in t and stores the
// result in dst.
func (t *tea) Decrypt(dst, src []byte) {
e := binary.BigEndian
v0, v1 := e.Uint32(src), e.Uint32(src[4:])
k0, k1, k2, k3 := e.Uint32(t.key[0:]), e.Uint32(t.key[4:]), e.Uint32(t.key[8:]), e.Uint32(t.key[12:])
delta := uint32(delta)
sum := delta * uint32(t.rounds/2) // in general, sum = delta * n
for i := 0; i < t.rounds/2; i++ {
v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3)
v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1)
sum -= delta
}
e.PutUint32(dst, v0)
e.PutUint32(dst[4:], v1)
}
// Copyright 2011 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 twofish implements Bruce Schneier's Twofish encryption algorithm.
//
// Deprecated: Twofish is a legacy cipher and should not be used for new
// applications. Also, this package does not and will not provide an optimized
// implementation. Instead, use AES (from crypto/aes, if necessary in an AEAD
// mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
// golang.org/x/crypto/chacha20poly1305).
package twofish
// Twofish is defined in https://www.schneier.com/paper-twofish-paper.pdf [TWOFISH]
// This code is a port of the LibTom C implementation.
// See http://libtom.org/?page=features&newsitems=5&whatfile=crypt.
// LibTomCrypt is free for all purposes under the public domain.
// It was heavily inspired by the go blowfish package.
import (
"math/bits"
"strconv"
)
// BlockSize is the constant block size of Twofish.
const BlockSize = 16
const mdsPolynomial = 0x169 // x^8 + x^6 + x^5 + x^3 + 1, see [TWOFISH] 4.2
const rsPolynomial = 0x14d // x^8 + x^6 + x^3 + x^2 + 1, see [TWOFISH] 4.3
// A Cipher is an instance of Twofish encryption using a particular key.
type Cipher struct {
s [4][256]uint32
k [40]uint32
}
type KeySizeError int
func (k KeySizeError) Error() string {
return "crypto/twofish: invalid key size " + strconv.Itoa(int(k))
}
// NewCipher creates and returns a Cipher.
// The key argument should be the Twofish key, 16, 24 or 32 bytes.
func NewCipher(key []byte) (*Cipher, error) {
keylen := len(key)
if keylen != 16 && keylen != 24 && keylen != 32 {
return nil, KeySizeError(keylen)
}
// k is the number of 64 bit words in key
k := keylen / 8
// Create the S[..] words
var S [4 * 4]byte
for i := 0; i < k; i++ {
// Computes [y0 y1 y2 y3] = rs . [x0 x1 x2 x3 x4 x5 x6 x7]
for j, rsRow := range rs {
for k, rsVal := range rsRow {
S[4*i+j] ^= gfMult(key[8*i+k], rsVal, rsPolynomial)
}
}
}
// Calculate subkeys
c := new(Cipher)
var tmp [4]byte
for i := byte(0); i < 20; i++ {
// A = h(p * 2x, Me)
for j := range tmp {
tmp[j] = 2 * i
}
A := h(tmp[:], key, 0)
// B = rolc(h(p * (2x + 1), Mo), 8)
for j := range tmp {
tmp[j] = 2*i + 1
}
B := h(tmp[:], key, 1)
B = bits.RotateLeft32(B, 8)
c.k[2*i] = A + B
// K[2i+1] = (A + 2B) <<< 9
c.k[2*i+1] = bits.RotateLeft32(2*B+A, 9)
}
// Calculate sboxes
switch k {
case 2:
for i := range c.s[0] {
c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][byte(i)]^S[0]]^S[4]], 0)
c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][byte(i)]^S[1]]^S[5]], 1)
c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][byte(i)]^S[2]]^S[6]], 2)
c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][byte(i)]^S[3]]^S[7]], 3)
}
case 3:
for i := range c.s[0] {
c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][sbox[1][byte(i)]^S[0]]^S[4]]^S[8]], 0)
c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][sbox[1][byte(i)]^S[1]]^S[5]]^S[9]], 1)
c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][sbox[0][byte(i)]^S[2]]^S[6]]^S[10]], 2)
c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][sbox[0][byte(i)]^S[3]]^S[7]]^S[11]], 3)
}
default:
for i := range c.s[0] {
c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][sbox[1][sbox[1][byte(i)]^S[0]]^S[4]]^S[8]]^S[12]], 0)
c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][sbox[1][sbox[0][byte(i)]^S[1]]^S[5]]^S[9]]^S[13]], 1)
c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][sbox[0][sbox[0][byte(i)]^S[2]]^S[6]]^S[10]]^S[14]], 2)
c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][sbox[0][sbox[1][byte(i)]^S[3]]^S[7]]^S[11]]^S[15]], 3)
}
}
return c, nil
}
// BlockSize returns the Twofish block size, 16 bytes.
func (c *Cipher) BlockSize() int { return BlockSize }
// store32l stores src in dst in little-endian form.
func store32l(dst []byte, src uint32) {
dst[0] = byte(src)
dst[1] = byte(src >> 8)
dst[2] = byte(src >> 16)
dst[3] = byte(src >> 24)
return
}
// load32l reads a little-endian uint32 from src.
func load32l(src []byte) uint32 {
return uint32(src[0]) | uint32(src[1])<<8 | uint32(src[2])<<16 | uint32(src[3])<<24
}
// The RS matrix. See [TWOFISH] 4.3
var rs = [4][8]byte{
{0x01, 0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E},
{0xA4, 0x56, 0x82, 0xF3, 0x1E, 0xC6, 0x68, 0xE5},
{0x02, 0xA1, 0xFC, 0xC1, 0x47, 0xAE, 0x3D, 0x19},
{0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E, 0x03},
}
// sbox tables
var sbox = [2][256]byte{
{
0xa9, 0x67, 0xb3, 0xe8, 0x04, 0xfd, 0xa3, 0x76, 0x9a, 0x92, 0x80, 0x78, 0xe4, 0xdd, 0xd1, 0x38,
0x0d, 0xc6, 0x35, 0x98, 0x18, 0xf7, 0xec, 0x6c, 0x43, 0x75, 0x37, 0x26, 0xfa, 0x13, 0x94, 0x48,
0xf2, 0xd0, 0x8b, 0x30, 0x84, 0x54, 0xdf, 0x23, 0x19, 0x5b, 0x3d, 0x59, 0xf3, 0xae, 0xa2, 0x82,
0x63, 0x01, 0x83, 0x2e, 0xd9, 0x51, 0x9b, 0x7c, 0xa6, 0xeb, 0xa5, 0xbe, 0x16, 0x0c, 0xe3, 0x61,
0xc0, 0x8c, 0x3a, 0xf5, 0x73, 0x2c, 0x25, 0x0b, 0xbb, 0x4e, 0x89, 0x6b, 0x53, 0x6a, 0xb4, 0xf1,
0xe1, 0xe6, 0xbd, 0x45, 0xe2, 0xf4, 0xb6, 0x66, 0xcc, 0x95, 0x03, 0x56, 0xd4, 0x1c, 0x1e, 0xd7,
0xfb, 0xc3, 0x8e, 0xb5, 0xe9, 0xcf, 0xbf, 0xba, 0xea, 0x77, 0x39, 0xaf, 0x33, 0xc9, 0x62, 0x71,
0x81, 0x79, 0x09, 0xad, 0x24, 0xcd, 0xf9, 0xd8, 0xe5, 0xc5, 0xb9, 0x4d, 0x44, 0x08, 0x86, 0xe7,
0xa1, 0x1d, 0xaa, 0xed, 0x06, 0x70, 0xb2, 0xd2, 0x41, 0x7b, 0xa0, 0x11, 0x31, 0xc2, 0x27, 0x90,
0x20, 0xf6, 0x60, 0xff, 0x96, 0x5c, 0xb1, 0xab, 0x9e, 0x9c, 0x52, 0x1b, 0x5f, 0x93, 0x0a, 0xef,
0x91, 0x85, 0x49, 0xee, 0x2d, 0x4f, 0x8f, 0x3b, 0x47, 0x87, 0x6d, 0x46, 0xd6, 0x3e, 0x69, 0x64,
0x2a, 0xce, 0xcb, 0x2f, 0xfc, 0x97, 0x05, 0x7a, 0xac, 0x7f, 0xd5, 0x1a, 0x4b, 0x0e, 0xa7, 0x5a,
0x28, 0x14, 0x3f, 0x29, 0x88, 0x3c, 0x4c, 0x02, 0xb8, 0xda, 0xb0, 0x17, 0x55, 0x1f, 0x8a, 0x7d,
0x57, 0xc7, 0x8d, 0x74, 0xb7, 0xc4, 0x9f, 0x72, 0x7e, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
0x6e, 0x50, 0xde, 0x68, 0x65, 0xbc, 0xdb, 0xf8, 0xc8, 0xa8, 0x2b, 0x40, 0xdc, 0xfe, 0x32, 0xa4,
0xca, 0x10, 0x21, 0xf0, 0xd3, 0x5d, 0x0f, 0x00, 0x6f, 0x9d, 0x36, 0x42, 0x4a, 0x5e, 0xc1, 0xe0,
},
{
0x75, 0xf3, 0xc6, 0xf4, 0xdb, 0x7b, 0xfb, 0xc8, 0x4a, 0xd3, 0xe6, 0x6b, 0x45, 0x7d, 0xe8, 0x4b,
0xd6, 0x32, 0xd8, 0xfd, 0x37, 0x71, 0xf1, 0xe1, 0x30, 0x0f, 0xf8, 0x1b, 0x87, 0xfa, 0x06, 0x3f,
0x5e, 0xba, 0xae, 0x5b, 0x8a, 0x00, 0xbc, 0x9d, 0x6d, 0xc1, 0xb1, 0x0e, 0x80, 0x5d, 0xd2, 0xd5,
0xa0, 0x84, 0x07, 0x14, 0xb5, 0x90, 0x2c, 0xa3, 0xb2, 0x73, 0x4c, 0x54, 0x92, 0x74, 0x36, 0x51,
0x38, 0xb0, 0xbd, 0x5a, 0xfc, 0x60, 0x62, 0x96, 0x6c, 0x42, 0xf7, 0x10, 0x7c, 0x28, 0x27, 0x8c,
0x13, 0x95, 0x9c, 0xc7, 0x24, 0x46, 0x3b, 0x70, 0xca, 0xe3, 0x85, 0xcb, 0x11, 0xd0, 0x93, 0xb8,
0xa6, 0x83, 0x20, 0xff, 0x9f, 0x77, 0xc3, 0xcc, 0x03, 0x6f, 0x08, 0xbf, 0x40, 0xe7, 0x2b, 0xe2,
0x79, 0x0c, 0xaa, 0x82, 0x41, 0x3a, 0xea, 0xb9, 0xe4, 0x9a, 0xa4, 0x97, 0x7e, 0xda, 0x7a, 0x17,
0x66, 0x94, 0xa1, 0x1d, 0x3d, 0xf0, 0xde, 0xb3, 0x0b, 0x72, 0xa7, 0x1c, 0xef, 0xd1, 0x53, 0x3e,
0x8f, 0x33, 0x26, 0x5f, 0xec, 0x76, 0x2a, 0x49, 0x81, 0x88, 0xee, 0x21, 0xc4, 0x1a, 0xeb, 0xd9,
0xc5, 0x39, 0x99, 0xcd, 0xad, 0x31, 0x8b, 0x01, 0x18, 0x23, 0xdd, 0x1f, 0x4e, 0x2d, 0xf9, 0x48,
0x4f, 0xf2, 0x65, 0x8e, 0x78, 0x5c, 0x58, 0x19, 0x8d, 0xe5, 0x98, 0x57, 0x67, 0x7f, 0x05, 0x64,
0xaf, 0x63, 0xb6, 0xfe, 0xf5, 0xb7, 0x3c, 0xa5, 0xce, 0xe9, 0x68, 0x44, 0xe0, 0x4d, 0x43, 0x69,
0x29, 0x2e, 0xac, 0x15, 0x59, 0xa8, 0x0a, 0x9e, 0x6e, 0x47, 0xdf, 0x34, 0x35, 0x6a, 0xcf, 0xdc,
0x22, 0xc9, 0xc0, 0x9b, 0x89, 0xd4, 0xed, 0xab, 0x12, 0xa2, 0x0d, 0x52, 0xbb, 0x02, 0x2f, 0xa9,
0xd7, 0x61, 0x1e, 0xb4, 0x50, 0x04, 0xf6, 0xc2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xbe, 0x91,
},
}
// gfMult returns a·b in GF(2^8)/p
func gfMult(a, b byte, p uint32) byte {
B := [2]uint32{0, uint32(b)}
P := [2]uint32{0, p}
var result uint32
// branchless GF multiplier
for i := 0; i < 7; i++ {
result ^= B[a&1]
a >>= 1
B[1] = P[B[1]>>7] ^ (B[1] << 1)
}
result ^= B[a&1]
return byte(result)
}
// mdsColumnMult calculates y{col} where [y0 y1 y2 y3] = MDS · [x0]
func mdsColumnMult(in byte, col int) uint32 {
mul01 := in
mul5B := gfMult(in, 0x5B, mdsPolynomial)
mulEF := gfMult(in, 0xEF, mdsPolynomial)
switch col {
case 0:
return uint32(mul01) | uint32(mul5B)<<8 | uint32(mulEF)<<16 | uint32(mulEF)<<24
case 1:
return uint32(mulEF) | uint32(mulEF)<<8 | uint32(mul5B)<<16 | uint32(mul01)<<24
case 2:
return uint32(mul5B) | uint32(mulEF)<<8 | uint32(mul01)<<16 | uint32(mulEF)<<24
case 3:
return uint32(mul5B) | uint32(mul01)<<8 | uint32(mulEF)<<16 | uint32(mul5B)<<24
}
panic("unreachable")
}
// h implements the S-box generation function. See [TWOFISH] 4.3.5
func h(in, key []byte, offset int) uint32 {
var y [4]byte
for x := range y {
y[x] = in[x]
}
switch len(key) / 8 {
case 4:
y[0] = sbox[1][y[0]] ^ key[4*(6+offset)+0]
y[1] = sbox[0][y[1]] ^ key[4*(6+offset)+1]
y[2] = sbox[0][y[2]] ^ key[4*(6+offset)+2]
y[3] = sbox[1][y[3]] ^ key[4*(6+offset)+3]
fallthrough
case 3:
y[0] = sbox[1][y[0]] ^ key[4*(4+offset)+0]
y[1] = sbox[1][y[1]] ^ key[4*(4+offset)+1]
y[2] = sbox[0][y[2]] ^ key[4*(4+offset)+2]
y[3] = sbox[0][y[3]] ^ key[4*(4+offset)+3]
fallthrough
case 2:
y[0] = sbox[1][sbox[0][sbox[0][y[0]]^key[4*(2+offset)+0]]^key[4*(0+offset)+0]]
y[1] = sbox[0][sbox[0][sbox[1][y[1]]^key[4*(2+offset)+1]]^key[4*(0+offset)+1]]
y[2] = sbox[1][sbox[1][sbox[0][y[2]]^key[4*(2+offset)+2]]^key[4*(0+offset)+2]]
y[3] = sbox[0][sbox[1][sbox[1][y[3]]^key[4*(2+offset)+3]]^key[4*(0+offset)+3]]
}
// [y0 y1 y2 y3] = MDS . [x0 x1 x2 x3]
var mdsMult uint32
for i := range y {
mdsMult ^= mdsColumnMult(y[i], i)
}
return mdsMult
}
// Encrypt encrypts a 16-byte block from src to dst, which may overlap.
// Note that for amounts of data larger than a block,
// it is not safe to just call Encrypt on successive blocks;
// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
func (c *Cipher) Encrypt(dst, src []byte) {
S1 := c.s[0]
S2 := c.s[1]
S3 := c.s[2]
S4 := c.s[3]
// Load input
ia := load32l(src[0:4])
ib := load32l(src[4:8])
ic := load32l(src[8:12])
id := load32l(src[12:16])
// Pre-whitening
ia ^= c.k[0]
ib ^= c.k[1]
ic ^= c.k[2]
id ^= c.k[3]
for i := 0; i < 8; i++ {
k := c.k[8+i*4 : 12+i*4]
t2 := S2[byte(ib)] ^ S3[byte(ib>>8)] ^ S4[byte(ib>>16)] ^ S1[byte(ib>>24)]
t1 := S1[byte(ia)] ^ S2[byte(ia>>8)] ^ S3[byte(ia>>16)] ^ S4[byte(ia>>24)] + t2
ic = bits.RotateLeft32(ic^(t1+k[0]), -1)
id = bits.RotateLeft32(id, 1) ^ (t2 + t1 + k[1])
t2 = S2[byte(id)] ^ S3[byte(id>>8)] ^ S4[byte(id>>16)] ^ S1[byte(id>>24)]
t1 = S1[byte(ic)] ^ S2[byte(ic>>8)] ^ S3[byte(ic>>16)] ^ S4[byte(ic>>24)] + t2
ia = bits.RotateLeft32(ia^(t1+k[2]), -1)
ib = bits.RotateLeft32(ib, 1) ^ (t2 + t1 + k[3])
}
// Output with "undo last swap"
ta := ic ^ c.k[4]
tb := id ^ c.k[5]
tc := ia ^ c.k[6]
td := ib ^ c.k[7]
store32l(dst[0:4], ta)
store32l(dst[4:8], tb)
store32l(dst[8:12], tc)
store32l(dst[12:16], td)
}
// Decrypt decrypts a 16-byte block from src to dst, which may overlap.
func (c *Cipher) Decrypt(dst, src []byte) {
S1 := c.s[0]
S2 := c.s[1]
S3 := c.s[2]
S4 := c.s[3]
// Load input
ta := load32l(src[0:4])
tb := load32l(src[4:8])
tc := load32l(src[8:12])
td := load32l(src[12:16])
// Undo undo final swap
ia := tc ^ c.k[6]
ib := td ^ c.k[7]
ic := ta ^ c.k[4]
id := tb ^ c.k[5]
for i := 8; i > 0; i-- {
k := c.k[4+i*4 : 8+i*4]
t2 := S2[byte(id)] ^ S3[byte(id>>8)] ^ S4[byte(id>>16)] ^ S1[byte(id>>24)]
t1 := S1[byte(ic)] ^ S2[byte(ic>>8)] ^ S3[byte(ic>>16)] ^ S4[byte(ic>>24)] + t2
ia = bits.RotateLeft32(ia, 1) ^ (t1 + k[2])
ib = bits.RotateLeft32(ib^(t2+t1+k[3]), -1)
t2 = S2[byte(ib)] ^ S3[byte(ib>>8)] ^ S4[byte(ib>>16)] ^ S1[byte(ib>>24)]
t1 = S1[byte(ia)] ^ S2[byte(ia>>8)] ^ S3[byte(ia>>16)] ^ S4[byte(ia>>24)] + t2
ic = bits.RotateLeft32(ic, 1) ^ (t1 + k[0])
id = bits.RotateLeft32(id^(t2+t1+k[1]), -1)
}
// Undo pre-whitening
ia ^= c.k[0]
ib ^= c.k[1]
ic ^= c.k[2]
id ^= c.k[3]
store32l(dst[0:4], ia)
store32l(dst[4:8], ib)
store32l(dst[8:12], ic)
store32l(dst[12:16], id)
}
// Copyright 2023 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 nss provides functionality for parsing NSS certdata.txt
// formatted certificate lists and extracting serverAuth roots. Most
// users should not use this package themselves, and should instead
// rely on the golang.org/x/crypto/x509roots/fallback package which
// calls x509.SetFallbackRoots on a pre-parsed set of roots.
package nss
import (
"bufio"
"bytes"
"crypto/sha1"
"crypto/x509"
"errors"
"fmt"
"io"
"strconv"
"strings"
"time"
)
// Constraint is a constraint to be applied to a certificate or
// certificate chain.
type Constraint interface {
Kind() Kind
}
// Kind is the constraint kind, using the NSS enumeration.
type Kind int
const (
CKA_NSS_SERVER_DISTRUST_AFTER Kind = iota
)
// DistrustAfter is a Constraint that indicates a certificate has a
// CKA_NSS_SERVER_DISTRUST_AFTER constraint. This constraint defines a date
// after which any certificate issued which is rooted by the constrained
// certificate should be distrusted.
type DistrustAfter time.Time
func (DistrustAfter) Kind() Kind {
return CKA_NSS_SERVER_DISTRUST_AFTER
}
// A Certificate represents a single trusted serverAuth certificate in the NSS
// certdata.txt list and any constraints that should be applied to chains
// rooted by it.
type Certificate struct {
// Certificate is the parsed certificate
X509 *x509.Certificate
// Constraints contains a list of additional constraints that should be
// applied to any certificates that chain to Certificate. If there are
// any unknown constraints in the slice, Certificate should not be
// trusted.
Constraints []Constraint
}
func parseMulitLineOctal(s *bufio.Scanner) ([]byte, error) {
buf := bytes.NewBuffer(nil)
for s.Scan() {
if s.Text() == "END" {
break
}
b, err := strconv.Unquote(fmt.Sprintf("\"%s\"", s.Text()))
if err != nil {
return nil, err
}
buf.Write([]byte(b))
}
return buf.Bytes(), nil
}
type certObj struct {
c *x509.Certificate
DistrustAfter *time.Time
}
func parseCertClass(s *bufio.Scanner) ([sha1.Size]byte, *certObj, error) {
var h [sha1.Size]byte
co := &certObj{}
for s.Scan() {
l := s.Text()
if l == "" {
// assume an empty newline indicates the end of a block
break
}
if strings.HasPrefix(l, "CKA_VALUE") {
b, err := parseMulitLineOctal(s)
if err != nil {
return h, nil, err
}
co.c, err = x509.ParseCertificate(b)
if err != nil {
return h, nil, err
}
h = sha1.Sum(b)
} else if strings.HasPrefix(l, "CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_FALSE") {
// we don't want it
return h, nil, nil
} else if l == "CKA_NSS_SERVER_DISTRUST_AFTER MULTILINE_OCTAL" {
dateStr, err := parseMulitLineOctal(s)
if err != nil {
return h, nil, err
}
t, err := time.Parse("060102150405Z0700", string(dateStr))
if err != nil {
return h, nil, err
}
co.DistrustAfter = &t
}
}
if co.c == nil {
return h, nil, errors.New("malformed CKO_CERTIFICATE object")
}
return h, co, nil
}
type trustObj struct {
trusted bool
}
func parseTrustClass(s *bufio.Scanner) ([sha1.Size]byte, *trustObj, error) {
var h [sha1.Size]byte
to := &trustObj{trusted: false} // default to untrusted
for s.Scan() {
l := s.Text()
if l == "" {
// assume an empty newline indicates the end of a block
break
}
if l == "CKA_CERT_SHA1_HASH MULTILINE_OCTAL" {
hash, err := parseMulitLineOctal(s)
if err != nil {
return h, nil, err
}
copy(h[:], hash)
} else if l == "CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR" {
// we only care about server auth
to.trusted = true
}
}
return h, to, nil
}
// manualExclusions contains a map of SHA1 fingerprints of roots that we manually exclude
// from the bundle for various reasons.
var manualExclusions = map[string]bool{
// TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1
// We exclude this root because mozilla manually constrains this root to
// issue names under .tr, but this information is only encoded in the CCADB
// IncludedCACertificateReport, in a field the format of which is
// undocumented, and is only used for this particular certificate. Rather
// than adding special parsing for this, we skip it. When code constraint
// support is available, we may also want to simply add a manual constraint,
// rather than a manual exclusion.
"3143649becce27eced3a3f0b8f0de4e891ddeeca": true,
}
// Parse parses a NSS certdata.txt formatted file, returning only
// trusted serverAuth roots, as well as any additional constraints. This parser
// is very opinionated, only returning roots that are currently trusted for
// serverAuth. As such roots returned by this package should only be used for
// making trust decisions about serverAuth certificates, as the trust status for
// other uses is not considered. Using the roots returned by this package for
// trust decisions should be done carefully.
//
// Some roots returned by the parser may include additional constraints
// (currently only DistrustAfter) which need to be considered when verifying
// certificates which chain to them.
//
// Parse is not intended to be a general purpose parser for certdata.txt.
func Parse(r io.Reader) ([]*Certificate, error) {
// certdata.txt is a rather strange format. It is essentially a list of
// textual PKCS#11 objects, delimited by empty lines. There are two main
// types of objects, certificates (CKO_CERTIFICATE) and trust definitions
// (CKO_NSS_TRUST). These objects appear to alternate, but this ordering is
// not defined anywhere, and should probably not be relied on. A single root
// certificate requires both the certificate object and the trust definition
// object in order to be properly understood.
//
// The list contains not just serverAuth certificates, so we need to be
// careful to only extract certificates which have the serverAuth trust bit
// set. Similarly there are a number of trust related bool fields that
// appear to _always_ be CKA_TRUE, but it seems unsafe to assume this is the
// case, so we should always double check.
//
// Since we only really care about a couple of fields, this parser throws
// away a lot of information, essentially just consuming CKA_CLASS objects
// and looking for the individual fields we care about. We could write a
// significantly more complex parser, which handles the entire format, but
// it feels like that would be over engineered for the little information
// that we really care about.
scanner := bufio.NewScanner(r)
type nssEntry struct {
cert *certObj
trust *trustObj
}
entries := map[[sha1.Size]byte]*nssEntry{}
for scanner.Scan() {
// scan until we hit CKA_CLASS
if !strings.HasPrefix(scanner.Text(), "CKA_CLASS") {
continue
}
f := strings.Fields(scanner.Text())
if len(f) != 3 {
return nil, errors.New("malformed CKA_CLASS")
}
switch f[2] {
case "CKO_CERTIFICATE":
h, co, err := parseCertClass(scanner)
if err != nil {
return nil, err
}
if co != nil {
e, ok := entries[h]
if !ok {
e = &nssEntry{}
entries[h] = e
}
e.cert = co
}
case "CKO_NSS_TRUST":
h, to, err := parseTrustClass(scanner)
if err != nil {
return nil, err
}
if to != nil {
e, ok := entries[h]
if !ok {
e = &nssEntry{}
entries[h] = e
}
e.trust = to
}
}
}
if err := scanner.Err(); err != nil {
return nil, err
}
var certs []*Certificate
for h, e := range entries {
if e.cert == nil && e.trust != nil {
// We may skip some certificates which are distrusted due to mozilla
// policy (CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_FALSE), which means
// we might get entries that appear to have a trust object, but no
// certificate. We can just continue on here.
continue
} else if e.cert != nil && e.trust == nil {
return nil, fmt.Errorf("missing trust object for certificate with SHA1 hash: %x", h)
}
if !e.trust.trusted {
continue
}
if manualExclusions[fmt.Sprintf("%x", h)] {
continue
}
nssCert := &Certificate{X509: e.cert.c}
if e.cert.DistrustAfter != nil {
nssCert.Constraints = append(nssCert.Constraints, DistrustAfter(*e.cert.DistrustAfter))
}
certs = append(certs, nssCert)
}
return certs, nil
}
// 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.
/*
Implementation adapted from Needham and Wheeler's paper:
http://www.cix.co.uk/~klockstone/xtea.pdf
A precalculated look up table is used during encryption/decryption for values that are based purely on the key.
*/
package xtea
// XTEA is based on 64 rounds.
const numRounds = 64
// blockToUint32 reads an 8 byte slice into two uint32s.
// The block is treated as big endian.
func blockToUint32(src []byte) (uint32, uint32) {
r0 := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
r1 := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
return r0, r1
}
// uint32ToBlock writes two uint32s into an 8 byte data block.
// Values are written as big endian.
func uint32ToBlock(v0, v1 uint32, dst []byte) {
dst[0] = byte(v0 >> 24)
dst[1] = byte(v0 >> 16)
dst[2] = byte(v0 >> 8)
dst[3] = byte(v0)
dst[4] = byte(v1 >> 24)
dst[5] = byte(v1 >> 16)
dst[6] = byte(v1 >> 8)
dst[7] = byte(v1 >> 0)
}
// encryptBlock encrypts a single 8 byte block using XTEA.
func encryptBlock(c *Cipher, dst, src []byte) {
v0, v1 := blockToUint32(src)
// Two rounds of XTEA applied per loop
for i := 0; i < numRounds; {
v0 += ((v1<<4 ^ v1>>5) + v1) ^ c.table[i]
i++
v1 += ((v0<<4 ^ v0>>5) + v0) ^ c.table[i]
i++
}
uint32ToBlock(v0, v1, dst)
}
// decryptBlock decrypts a single 8 byte block using XTEA.
func decryptBlock(c *Cipher, dst, src []byte) {
v0, v1 := blockToUint32(src)
// Two rounds of XTEA applied per loop
for i := numRounds; i > 0; {
i--
v1 -= ((v0<<4 ^ v0>>5) + v0) ^ c.table[i]
i--
v0 -= ((v1<<4 ^ v1>>5) + v1) ^ c.table[i]
}
uint32ToBlock(v0, v1, dst)
}
// 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 xtea implements XTEA encryption, as defined in Needham and Wheeler's
// 1997 technical report, "Tea extensions."
//
// XTEA is a legacy cipher and its short block size makes it vulnerable to
// birthday bound attacks (see https://sweet32.info). It should only be used
// where compatibility with legacy systems, not security, is the goal.
//
// Deprecated: any new system should use AES (from crypto/aes, if necessary in
// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
// golang.org/x/crypto/chacha20poly1305).
package xtea
// For details, see http://www.cix.co.uk/~klockstone/xtea.pdf
import "strconv"
// The XTEA block size in bytes.
const BlockSize = 8
// A Cipher is an instance of an XTEA cipher using a particular key.
type Cipher struct {
// table contains a series of precalculated values that are used each round.
table [64]uint32
}
type KeySizeError int
func (k KeySizeError) Error() string {
return "crypto/xtea: invalid key size " + strconv.Itoa(int(k))
}
// NewCipher creates and returns a new Cipher.
// The key argument should be the XTEA key.
// XTEA only supports 128 bit (16 byte) keys.
func NewCipher(key []byte) (*Cipher, error) {
k := len(key)
switch k {
default:
return nil, KeySizeError(k)
case 16:
break
}
c := new(Cipher)
initCipher(c, key)
return c, nil
}
// BlockSize returns the XTEA block size, 8 bytes.
// It is necessary to satisfy the Block interface in the
// package "crypto/cipher".
func (c *Cipher) BlockSize() int { return BlockSize }
// Encrypt encrypts the 8 byte buffer src using the key and stores the result in dst.
// Note that for amounts of data larger than a block,
// it is not safe to just call Encrypt on successive blocks;
// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c, dst, src) }
// Decrypt decrypts the 8 byte buffer src using the key and stores the result in dst.
func (c *Cipher) Decrypt(dst, src []byte) { decryptBlock(c, dst, src) }
// initCipher initializes the cipher context by creating a look up table
// of precalculated values that are based on the key.
func initCipher(c *Cipher, key []byte) {
// Load the key into four uint32s
var k [4]uint32
for i := 0; i < len(k); i++ {
j := i << 2 // Multiply by 4
k[i] = uint32(key[j+0])<<24 | uint32(key[j+1])<<16 | uint32(key[j+2])<<8 | uint32(key[j+3])
}
// Precalculate the table
const delta = 0x9E3779B9
var sum uint32
// Two rounds of XTEA applied per loop
for i := 0; i < numRounds; {
c.table[i] = sum + k[sum&3]
i++
sum += delta
c.table[i] = sum + k[(sum>>11)&3]
i++
}
}
// 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.
// Package xts implements the XTS cipher mode as specified in IEEE P1619/D16.
//
// XTS mode is typically used for disk encryption, which presents a number of
// novel problems that make more common modes inapplicable. The disk is
// conceptually an array of sectors and we must be able to encrypt and decrypt
// a sector in isolation. However, an attacker must not be able to transpose
// two sectors of plaintext by transposing their ciphertext.
//
// XTS wraps a block cipher with Rogaway's XEX mode in order to build a
// tweakable block cipher. This allows each sector to have a unique tweak and
// effectively create a unique key for each sector.
//
// XTS does not provide any authentication. An attacker can manipulate the
// ciphertext and randomise a block (16 bytes) of the plaintext. This package
// does not implement ciphertext-stealing so sectors must be a multiple of 16
// bytes.
//
// Note that XTS is usually not appropriate for any use besides disk encryption.
// Most users should use an AEAD mode like GCM (from crypto/cipher.NewGCM) instead.
//
// The xts package is [frozen] and is not accepting new features.
//
// [frozen]: https://go.dev/wiki/Frozen
package xts
import (
"crypto/cipher"
"encoding/binary"
"errors"
"sync"
"golang.org/x/crypto/internal/alias"
)
// Cipher contains an expanded key structure. It is safe for concurrent use if
// the underlying block cipher is safe for concurrent use.
type Cipher struct {
k1, k2 cipher.Block
}
// blockSize is the block size that the underlying cipher must have. XTS is
// only defined for 16-byte ciphers.
const blockSize = 16
var tweakPool = sync.Pool{
New: func() interface{} {
return new([blockSize]byte)
},
}
// NewCipher creates a Cipher given a function for creating the underlying
// block cipher (which must have a block size of 16 bytes). The key must be
// twice the length of the underlying cipher's key.
func NewCipher(cipherFunc func([]byte) (cipher.Block, error), key []byte) (c *Cipher, err error) {
c = new(Cipher)
if c.k1, err = cipherFunc(key[:len(key)/2]); err != nil {
return
}
c.k2, err = cipherFunc(key[len(key)/2:])
if c.k1.BlockSize() != blockSize {
err = errors.New("xts: cipher does not have a block size of 16")
}
return
}
// Encrypt encrypts a sector of plaintext and puts the result into ciphertext.
// Plaintext and ciphertext must overlap entirely or not at all.
// Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
func (c *Cipher) Encrypt(ciphertext, plaintext []byte, sectorNum uint64) {
if len(ciphertext) < len(plaintext) {
panic("xts: ciphertext is smaller than plaintext")
}
if len(plaintext)%blockSize != 0 {
panic("xts: plaintext is not a multiple of the block size")
}
if alias.InexactOverlap(ciphertext[:len(plaintext)], plaintext) {
panic("xts: invalid buffer overlap")
}
tweak := tweakPool.Get().(*[blockSize]byte)
for i := range tweak {
tweak[i] = 0
}
binary.LittleEndian.PutUint64(tweak[:8], sectorNum)
c.k2.Encrypt(tweak[:], tweak[:])
for len(plaintext) > 0 {
for j := range tweak {
ciphertext[j] = plaintext[j] ^ tweak[j]
}
c.k1.Encrypt(ciphertext, ciphertext)
for j := range tweak {
ciphertext[j] ^= tweak[j]
}
plaintext = plaintext[blockSize:]
ciphertext = ciphertext[blockSize:]
mul2(tweak)
}
tweakPool.Put(tweak)
}
// Decrypt decrypts a sector of ciphertext and puts the result into plaintext.
// Plaintext and ciphertext must overlap entirely or not at all.
// Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
func (c *Cipher) Decrypt(plaintext, ciphertext []byte, sectorNum uint64) {
if len(plaintext) < len(ciphertext) {
panic("xts: plaintext is smaller than ciphertext")
}
if len(ciphertext)%blockSize != 0 {
panic("xts: ciphertext is not a multiple of the block size")
}
if alias.InexactOverlap(plaintext[:len(ciphertext)], ciphertext) {
panic("xts: invalid buffer overlap")
}
tweak := tweakPool.Get().(*[blockSize]byte)
for i := range tweak {
tweak[i] = 0
}
binary.LittleEndian.PutUint64(tweak[:8], sectorNum)
c.k2.Encrypt(tweak[:], tweak[:])
for len(ciphertext) > 0 {
for j := range tweak {
plaintext[j] = ciphertext[j] ^ tweak[j]
}
c.k1.Decrypt(plaintext, plaintext)
for j := range tweak {
plaintext[j] ^= tweak[j]
}
plaintext = plaintext[blockSize:]
ciphertext = ciphertext[blockSize:]
mul2(tweak)
}
tweakPool.Put(tweak)
}
// mul2 multiplies tweak by 2 in GF(2¹²⁸) with an irreducible polynomial of
// x¹²⁸ + x⁷ + x² + x + 1.
func mul2(tweak *[blockSize]byte) {
var carryIn byte
for j := range tweak {
carryOut := tweak[j] >> 7
tweak[j] = (tweak[j] << 1) + carryIn
carryIn = carryOut
}
if carryIn != 0 {
// If we have a carry bit then we need to subtract a multiple
// of the irreducible polynomial (x¹²⁸ + x⁷ + x² + x + 1).
// By dropping the carry bit, we're subtracting the x^128 term
// so all that remains is to subtract x⁷ + x² + x + 1.
// Subtraction (and addition) in this representation is just
// XOR.
tweak[0] ^= 1<<7 | 1<<2 | 1<<1 | 1
}
}
// Copyright 2011 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 bmp implements a BMP image decoder and encoder.
//
// The BMP specification is at http://www.digicamsoft.com/bmp/bmp.html.
package bmp // import "golang.org/x/image/bmp"
import (
"errors"
"image"
"image/color"
"io"
)
// ErrUnsupported means that the input BMP image uses a valid but unsupported
// feature.
var ErrUnsupported = errors.New("bmp: unsupported BMP image")
func readUint16(b []byte) uint16 {
return uint16(b[0]) | uint16(b[1])<<8
}
func readUint32(b []byte) uint32 {
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
}
// decodePaletted reads a 1, 2, 4 or 8 bit-per-pixel BMP image from r.
// If topDown is false, the image rows will be read bottom-up.
func decodePaletted(r io.Reader, c image.Config, topDown bool, bpp int) (image.Image, error) {
paletted := image.NewPaletted(image.Rect(0, 0, c.Width, c.Height), c.ColorModel.(color.Palette))
if c.Width == 0 || c.Height == 0 {
return paletted, nil
}
y0, y1, yDelta := c.Height-1, -1, -1
if topDown {
y0, y1, yDelta = 0, c.Height, +1
}
pixelsPerByte := 8 / bpp
// Pad up to ensure each row is 4-bytes aligned.
bytesPerRow := ((c.Width+pixelsPerByte-1)/pixelsPerByte + 3) &^ 3
b := make([]byte, bytesPerRow)
for y := y0; y != y1; y += yDelta {
p := paletted.Pix[y*paletted.Stride : y*paletted.Stride+c.Width]
if _, err := io.ReadFull(r, b); err != nil {
return nil, err
}
byteIndex, bitIndex, mask := 0, 8, byte((1<<bpp)-1)
for pixIndex := 0; pixIndex < c.Width; pixIndex++ {
bitIndex -= bpp
p[pixIndex] = (b[byteIndex]) >> bitIndex & mask
if bitIndex == 0 {
byteIndex++
bitIndex = 8
}
}
}
return paletted, nil
}
// decodeRGB reads a 24 bit-per-pixel BMP image from r.
// If topDown is false, the image rows will be read bottom-up.
func decodeRGB(r io.Reader, c image.Config, topDown bool) (image.Image, error) {
rgba := image.NewRGBA(image.Rect(0, 0, c.Width, c.Height))
if c.Width == 0 || c.Height == 0 {
return rgba, nil
}
// There are 3 bytes per pixel, and each row is 4-byte aligned.
b := make([]byte, (3*c.Width+3)&^3)
y0, y1, yDelta := c.Height-1, -1, -1
if topDown {
y0, y1, yDelta = 0, c.Height, +1
}
for y := y0; y != y1; y += yDelta {
if _, err := io.ReadFull(r, b); err != nil {
return nil, err
}
p := rgba.Pix[y*rgba.Stride : y*rgba.Stride+c.Width*4]
for i, j := 0, 0; i < len(p); i, j = i+4, j+3 {
// BMP images are stored in BGR order rather than RGB order.
p[i+0] = b[j+2]
p[i+1] = b[j+1]
p[i+2] = b[j+0]
p[i+3] = 0xFF
}
}
return rgba, nil
}
// decodeNRGBA reads a 32 bit-per-pixel BMP image from r.
// If topDown is false, the image rows will be read bottom-up.
func decodeNRGBA(r io.Reader, c image.Config, topDown, allowAlpha bool) (image.Image, error) {
rgba := image.NewNRGBA(image.Rect(0, 0, c.Width, c.Height))
if c.Width == 0 || c.Height == 0 {
return rgba, nil
}
y0, y1, yDelta := c.Height-1, -1, -1
if topDown {
y0, y1, yDelta = 0, c.Height, +1
}
for y := y0; y != y1; y += yDelta {
p := rgba.Pix[y*rgba.Stride : y*rgba.Stride+c.Width*4]
if _, err := io.ReadFull(r, p); err != nil {
return nil, err
}
for i := 0; i < len(p); i += 4 {
// BMP images are stored in BGRA order rather than RGBA order.
p[i+0], p[i+2] = p[i+2], p[i+0]
if !allowAlpha {
p[i+3] = 0xFF
}
}
}
return rgba, nil
}
// Decode reads a BMP image from r and returns it as an image.Image.
// Limitation: The file must be 8, 24 or 32 bits per pixel.
func Decode(r io.Reader) (image.Image, error) {
c, bpp, topDown, allowAlpha, err := decodeConfig(r)
if err != nil {
return nil, err
}
switch bpp {
case 1, 2, 4, 8:
return decodePaletted(r, c, topDown, bpp)
case 24:
return decodeRGB(r, c, topDown)
case 32:
return decodeNRGBA(r, c, topDown, allowAlpha)
}
panic("unreachable")
}
// DecodeConfig returns the color model and dimensions of a BMP image without
// decoding the entire image.
// Limitation: The file must be 8, 24 or 32 bits per pixel.
func DecodeConfig(r io.Reader) (image.Config, error) {
config, _, _, _, err := decodeConfig(r)
return config, err
}
func decodeConfig(r io.Reader) (config image.Config, bitsPerPixel int, topDown bool, allowAlpha bool, err error) {
// We only support those BMP images with one of the following DIB headers:
// - BITMAPINFOHEADER (40 bytes)
// - BITMAPV4HEADER (108 bytes)
// - BITMAPV5HEADER (124 bytes)
const (
fileHeaderLen = 14
infoHeaderLen = 40
v4InfoHeaderLen = 108
v5InfoHeaderLen = 124
)
var b [1024]byte
if _, err := io.ReadFull(r, b[:fileHeaderLen+4]); err != nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return image.Config{}, 0, false, false, err
}
if string(b[:2]) != "BM" {
return image.Config{}, 0, false, false, errors.New("bmp: invalid format")
}
offset := readUint32(b[10:14])
infoLen := readUint32(b[14:18])
if infoLen != infoHeaderLen && infoLen != v4InfoHeaderLen && infoLen != v5InfoHeaderLen {
return image.Config{}, 0, false, false, ErrUnsupported
}
if _, err := io.ReadFull(r, b[fileHeaderLen+4:fileHeaderLen+infoLen]); err != nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return image.Config{}, 0, false, false, err
}
width := int(int32(readUint32(b[18:22])))
height := int(int32(readUint32(b[22:26])))
if height < 0 {
height, topDown = -height, true
}
if width < 0 || height < 0 {
return image.Config{}, 0, false, false, ErrUnsupported
}
// We only support 1 plane and 8, 24 or 32 bits per pixel and no
// compression.
planes, bpp, compression := readUint16(b[26:28]), readUint16(b[28:30]), readUint32(b[30:34])
// if compression is set to BI_BITFIELDS, but the bitmask is set to the default bitmask
// that would be used if compression was set to 0, we can continue as if compression was 0
if compression == 3 && infoLen > infoHeaderLen &&
readUint32(b[54:58]) == 0xff0000 && readUint32(b[58:62]) == 0xff00 &&
readUint32(b[62:66]) == 0xff && readUint32(b[66:70]) == 0xff000000 {
compression = 0
}
if planes != 1 || compression != 0 {
return image.Config{}, 0, false, false, ErrUnsupported
}
switch bpp {
case 1, 2, 4, 8:
colorUsed := readUint32(b[46:50])
if colorUsed == 0 {
colorUsed = 1 << bpp
} else if colorUsed > (1 << bpp) {
return image.Config{}, 0, false, false, ErrUnsupported
}
if offset != fileHeaderLen+infoLen+colorUsed*4 {
return image.Config{}, 0, false, false, ErrUnsupported
}
_, err = io.ReadFull(r, b[:colorUsed*4])
if err != nil {
return image.Config{}, 0, false, false, err
}
pcm := make(color.Palette, colorUsed)
for i := range pcm {
// BMP images are stored in BGR order rather than RGB order.
// Every 4th byte is padding.
pcm[i] = color.RGBA{b[4*i+2], b[4*i+1], b[4*i+0], 0xFF}
}
return image.Config{ColorModel: pcm, Width: width, Height: height}, int(bpp), topDown, false, nil
case 24:
if offset != fileHeaderLen+infoLen {
return image.Config{}, 0, false, false, ErrUnsupported
}
return image.Config{ColorModel: color.RGBAModel, Width: width, Height: height}, 24, topDown, false, nil
case 32:
if offset != fileHeaderLen+infoLen {
return image.Config{}, 0, false, false, ErrUnsupported
}
// 32 bits per pixel is possibly RGBX (X is padding) or RGBA (A is
// alpha transparency). However, for BMP images, "Alpha is a
// poorly-documented and inconsistently-used feature" says
// https://source.chromium.org/chromium/chromium/src/+/bc0a792d7ebc587190d1a62ccddba10abeea274b:third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.cc;l=621
//
// That goes on to say "BITMAPV3HEADER+ have an alpha bitmask in the
// info header... so we respect it at all times... [For earlier
// (smaller) headers we] ignore alpha in Windows V3 BMPs except inside
// ICO files".
//
// "Ignore" means to always set alpha to 0xFF (fully opaque):
// https://source.chromium.org/chromium/chromium/src/+/bc0a792d7ebc587190d1a62ccddba10abeea274b:third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.h;l=272
//
// Confusingly, "Windows V3" does not correspond to BITMAPV3HEADER, but
// instead corresponds to the earlier (smaller) BITMAPINFOHEADER:
// https://source.chromium.org/chromium/chromium/src/+/bc0a792d7ebc587190d1a62ccddba10abeea274b:third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.cc;l=258
//
// This Go package does not support ICO files and the (infoLen >
// infoHeaderLen) condition distinguishes BITMAPINFOHEADER (40 bytes)
// vs later (larger) headers.
allowAlpha = infoLen > infoHeaderLen
return image.Config{ColorModel: color.RGBAModel, Width: width, Height: height}, 32, topDown, allowAlpha, nil
}
return image.Config{}, 0, false, false, ErrUnsupported
}
func init() {
image.RegisterFormat("bmp", "BM????\x00\x00\x00\x00", Decode, DecodeConfig)
}
// Copyright 2013 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 bmp
import (
"encoding/binary"
"errors"
"image"
"io"
)
type header struct {
sigBM [2]byte
fileSize uint32
resverved [2]uint16
pixOffset uint32
dibHeaderSize uint32
width uint32
height uint32
colorPlane uint16
bpp uint16
compression uint32
imageSize uint32
xPixelsPerMeter uint32
yPixelsPerMeter uint32
colorUse uint32
colorImportant uint32
}
func encodePaletted(w io.Writer, pix []uint8, dx, dy, stride, step int) error {
var padding []byte
if dx < step {
padding = make([]byte, step-dx)
}
for y := dy - 1; y >= 0; y-- {
min := y*stride + 0
max := y*stride + dx
if _, err := w.Write(pix[min:max]); err != nil {
return err
}
if padding != nil {
if _, err := w.Write(padding); err != nil {
return err
}
}
}
return nil
}
func encodeRGBA(w io.Writer, pix []uint8, dx, dy, stride, step int, opaque bool) error {
buf := make([]byte, step)
if opaque {
for y := dy - 1; y >= 0; y-- {
min := y*stride + 0
max := y*stride + dx*4
off := 0
for i := min; i < max; i += 4 {
buf[off+2] = pix[i+0]
buf[off+1] = pix[i+1]
buf[off+0] = pix[i+2]
off += 3
}
if _, err := w.Write(buf); err != nil {
return err
}
}
} else {
for y := dy - 1; y >= 0; y-- {
min := y*stride + 0
max := y*stride + dx*4
off := 0
for i := min; i < max; i += 4 {
a := uint32(pix[i+3])
if a == 0 {
buf[off+2] = 0
buf[off+1] = 0
buf[off+0] = 0
buf[off+3] = 0
off += 4
continue
} else if a == 0xff {
buf[off+2] = pix[i+0]
buf[off+1] = pix[i+1]
buf[off+0] = pix[i+2]
buf[off+3] = 0xff
off += 4
continue
}
buf[off+2] = uint8(((uint32(pix[i+0]) * 0xffff) / a) >> 8)
buf[off+1] = uint8(((uint32(pix[i+1]) * 0xffff) / a) >> 8)
buf[off+0] = uint8(((uint32(pix[i+2]) * 0xffff) / a) >> 8)
buf[off+3] = uint8(a)
off += 4
}
if _, err := w.Write(buf); err != nil {
return err
}
}
}
return nil
}
func encodeNRGBA(w io.Writer, pix []uint8, dx, dy, stride, step int, opaque bool) error {
buf := make([]byte, step)
if opaque {
for y := dy - 1; y >= 0; y-- {
min := y*stride + 0
max := y*stride + dx*4
off := 0
for i := min; i < max; i += 4 {
buf[off+2] = pix[i+0]
buf[off+1] = pix[i+1]
buf[off+0] = pix[i+2]
off += 3
}
if _, err := w.Write(buf); err != nil {
return err
}
}
} else {
for y := dy - 1; y >= 0; y-- {
min := y*stride + 0
max := y*stride + dx*4
off := 0
for i := min; i < max; i += 4 {
buf[off+2] = pix[i+0]
buf[off+1] = pix[i+1]
buf[off+0] = pix[i+2]
buf[off+3] = pix[i+3]
off += 4
}
if _, err := w.Write(buf); err != nil {
return err
}
}
}
return nil
}
func encode(w io.Writer, m image.Image, step int) error {
b := m.Bounds()
buf := make([]byte, step)
for y := b.Max.Y - 1; y >= b.Min.Y; y-- {
off := 0
for x := b.Min.X; x < b.Max.X; x++ {
r, g, b, _ := m.At(x, y).RGBA()
buf[off+2] = byte(r >> 8)
buf[off+1] = byte(g >> 8)
buf[off+0] = byte(b >> 8)
off += 3
}
if _, err := w.Write(buf); err != nil {
return err
}
}
return nil
}
// Encode writes the image m to w in BMP format.
func Encode(w io.Writer, m image.Image) error {
d := m.Bounds().Size()
if d.X < 0 || d.Y < 0 {
return errors.New("bmp: negative bounds")
}
h := &header{
sigBM: [2]byte{'B', 'M'},
fileSize: 14 + 40,
pixOffset: 14 + 40,
dibHeaderSize: 40,
width: uint32(d.X),
height: uint32(d.Y),
colorPlane: 1,
}
var step int
var palette []byte
var opaque bool
switch m := m.(type) {
case *image.Gray:
step = (d.X + 3) &^ 3
palette = make([]byte, 1024)
for i := 0; i < 256; i++ {
palette[i*4+0] = uint8(i)
palette[i*4+1] = uint8(i)
palette[i*4+2] = uint8(i)
palette[i*4+3] = 0xFF
}
h.imageSize = uint32(d.Y * step)
h.fileSize += uint32(len(palette)) + h.imageSize
h.pixOffset += uint32(len(palette))
h.bpp = 8
case *image.Paletted:
step = (d.X + 3) &^ 3
palette = make([]byte, 1024)
for i := 0; i < len(m.Palette) && i < 256; i++ {
r, g, b, _ := m.Palette[i].RGBA()
palette[i*4+0] = uint8(b >> 8)
palette[i*4+1] = uint8(g >> 8)
palette[i*4+2] = uint8(r >> 8)
palette[i*4+3] = 0xFF
}
h.imageSize = uint32(d.Y * step)
h.fileSize += uint32(len(palette)) + h.imageSize
h.pixOffset += uint32(len(palette))
h.bpp = 8
case *image.RGBA:
opaque = m.Opaque()
if opaque {
step = (3*d.X + 3) &^ 3
h.bpp = 24
} else {
step = 4 * d.X
h.bpp = 32
}
h.imageSize = uint32(d.Y * step)
h.fileSize += h.imageSize
case *image.NRGBA:
opaque = m.Opaque()
if opaque {
step = (3*d.X + 3) &^ 3
h.bpp = 24
} else {
step = 4 * d.X
h.bpp = 32
}
h.imageSize = uint32(d.Y * step)
h.fileSize += h.imageSize
default:
step = (3*d.X + 3) &^ 3
h.imageSize = uint32(d.Y * step)
h.fileSize += h.imageSize
h.bpp = 24
}
if err := binary.Write(w, binary.LittleEndian, h); err != nil {
return err
}
if palette != nil {
if err := binary.Write(w, binary.LittleEndian, palette); err != nil {
return err
}
}
if d.X == 0 || d.Y == 0 {
return nil
}
switch m := m.(type) {
case *image.Gray:
return encodePaletted(w, m.Pix, d.X, d.Y, m.Stride, step)
case *image.Paletted:
return encodePaletted(w, m.Pix, d.X, d.Y, m.Stride, step)
case *image.RGBA:
return encodeRGBA(w, m.Pix, d.X, d.Y, m.Stride, step, opaque)
case *image.NRGBA:
return encodeNRGBA(w, m.Pix, d.X, d.Y, m.Stride, step, opaque)
}
return encode(w, m, step)
}
// Copyright 2019 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.
//go:generate go run gen.go
// Package ccitt implements a CCITT (fax) image decoder.
package ccitt
import (
"encoding/binary"
"errors"
"image"
"io"
"math/bits"
)
var (
errIncompleteCode = errors.New("ccitt: incomplete code")
errInvalidBounds = errors.New("ccitt: invalid bounds")
errInvalidCode = errors.New("ccitt: invalid code")
errInvalidMode = errors.New("ccitt: invalid mode")
errInvalidOffset = errors.New("ccitt: invalid offset")
errMissingEOL = errors.New("ccitt: missing End-of-Line")
errRunLengthOverflowsWidth = errors.New("ccitt: run length overflows width")
errRunLengthTooLong = errors.New("ccitt: run length too long")
errUnsupportedMode = errors.New("ccitt: unsupported mode")
errUnsupportedSubFormat = errors.New("ccitt: unsupported sub-format")
errUnsupportedWidth = errors.New("ccitt: unsupported width")
)
// Order specifies the bit ordering in a CCITT data stream.
type Order uint32
const (
// LSB means Least Significant Bits first.
LSB Order = iota
// MSB means Most Significant Bits first.
MSB
)
// SubFormat represents that the CCITT format consists of a number of
// sub-formats. Decoding or encoding a CCITT data stream requires knowing the
// sub-format context. It is not represented in the data stream per se.
type SubFormat uint32
const (
Group3 SubFormat = iota
Group4
)
// AutoDetectHeight is passed as the height argument to NewReader to indicate
// that the image height (the number of rows) is not known in advance.
const AutoDetectHeight = -1
// Options are optional parameters.
type Options struct {
// Align means that some variable-bit-width codes are byte-aligned.
Align bool
// Invert means that black is the 1 bit or 0xFF byte, and white is 0.
Invert bool
}
// maxWidth is the maximum (inclusive) supported width. This is a limitation of
// this implementation, to guard against integer overflow, and not anything
// inherent to the CCITT format.
const maxWidth = 1 << 20
func invertBytes(b []byte) {
for i, c := range b {
b[i] = ^c
}
}
func reverseBitsWithinBytes(b []byte) {
for i, c := range b {
b[i] = bits.Reverse8(c)
}
}
// highBits writes to dst (1 bit per pixel, most significant bit first) the
// high (0x80) bits from src (1 byte per pixel). It returns the number of bytes
// written and read such that dst[:d] is the packed form of src[:s].
//
// For example, if src starts with the 8 bytes [0x7D, 0x7E, 0x7F, 0x80, 0x81,
// 0x82, 0x00, 0xFF] then 0x1D will be written to dst[0].
//
// If src has (8 * len(dst)) or more bytes then only len(dst) bytes are
// written, (8 * len(dst)) bytes are read, and invert is ignored.
//
// Otherwise, if len(src) is not a multiple of 8 then the final byte written to
// dst is padded with 1 bits (if invert is true) or 0 bits. If inverted, the 1s
// are typically temporary, e.g. they will be flipped back to 0s by an
// invertBytes call in the highBits caller, reader.Read.
func highBits(dst []byte, src []byte, invert bool) (d int, s int) {
// Pack as many complete groups of 8 src bytes as we can.
n := len(src) / 8
if n > len(dst) {
n = len(dst)
}
dstN := dst[:n]
for i := range dstN {
src8 := src[i*8 : i*8+8]
dstN[i] = ((src8[0] & 0x80) >> 0) |
((src8[1] & 0x80) >> 1) |
((src8[2] & 0x80) >> 2) |
((src8[3] & 0x80) >> 3) |
((src8[4] & 0x80) >> 4) |
((src8[5] & 0x80) >> 5) |
((src8[6] & 0x80) >> 6) |
((src8[7] & 0x80) >> 7)
}
d, s = n, 8*n
dst, src = dst[d:], src[s:]
// Pack up to 7 remaining src bytes, if there's room in dst.
if (len(dst) > 0) && (len(src) > 0) {
dstByte := byte(0)
if invert {
dstByte = 0xFF >> uint(len(src))
}
for n, srcByte := range src {
dstByte |= (srcByte & 0x80) >> uint(n)
}
dst[0] = dstByte
d, s = d+1, s+len(src)
}
return d, s
}
type bitReader struct {
r io.Reader
// readErr is the error returned from the most recent r.Read call. As the
// io.Reader documentation says, when r.Read returns (n, err), "always
// process the n > 0 bytes returned before considering the error err".
readErr error
// order is whether to process r's bytes LSB first or MSB first.
order Order
// The high nBits bits of the bits field hold upcoming bits in MSB order.
bits uint64
nBits uint32
// bytes[br:bw] holds bytes read from r but not yet loaded into bits.
br uint32
bw uint32
bytes [1024]uint8
}
func (b *bitReader) alignToByteBoundary() {
n := b.nBits & 7
b.bits <<= n
b.nBits -= n
}
// nextBitMaxNBits is the maximum possible value of bitReader.nBits after a
// bitReader.nextBit call, provided that bitReader.nBits was not more than this
// value before that call.
//
// Note that the decode function can unread bits, which can temporarily set the
// bitReader.nBits value above nextBitMaxNBits.
const nextBitMaxNBits = 31
func (b *bitReader) nextBit() (uint64, error) {
for {
if b.nBits > 0 {
bit := b.bits >> 63
b.bits <<= 1
b.nBits--
return bit, nil
}
if available := b.bw - b.br; available >= 4 {
// Read 32 bits, even though b.bits is a uint64, since the decode
// function may need to unread up to maxCodeLength bits, putting
// them back in the remaining (64 - 32) bits. TestMaxCodeLength
// checks that the generated maxCodeLength constant fits.
//
// If changing the Uint32 call, also change nextBitMaxNBits.
b.bits = uint64(binary.BigEndian.Uint32(b.bytes[b.br:])) << 32
b.br += 4
b.nBits = 32
continue
} else if available > 0 {
b.bits = uint64(b.bytes[b.br]) << (7 * 8)
b.br++
b.nBits = 8
continue
}
if b.readErr != nil {
return 0, b.readErr
}
n, err := b.r.Read(b.bytes[:])
b.br = 0
b.bw = uint32(n)
b.readErr = err
if b.order != MSB {
reverseBitsWithinBytes(b.bytes[:b.bw])
}
}
}
func decode(b *bitReader, decodeTable [][2]int16) (uint32, error) {
nBitsRead, bitsRead, state := uint32(0), uint64(0), int32(1)
for {
bit, err := b.nextBit()
if err != nil {
if err == io.EOF {
err = errIncompleteCode
}
return 0, err
}
bitsRead |= bit << (63 - nBitsRead)
nBitsRead++
// The "&1" is redundant, but can eliminate a bounds check.
state = int32(decodeTable[state][bit&1])
if state < 0 {
return uint32(^state), nil
} else if state == 0 {
// Unread the bits we've read, then return errInvalidCode.
b.bits = (b.bits >> nBitsRead) | bitsRead
b.nBits += nBitsRead
return 0, errInvalidCode
}
}
}
// decodeEOL decodes the 12-bit EOL code 0000_0000_0001.
func decodeEOL(b *bitReader) error {
nBitsRead, bitsRead := uint32(0), uint64(0)
for {
bit, err := b.nextBit()
if err != nil {
if err == io.EOF {
err = errMissingEOL
}
return err
}
bitsRead |= bit << (63 - nBitsRead)
nBitsRead++
if nBitsRead < 12 {
if bit&1 == 0 {
continue
}
} else if bit&1 != 0 {
return nil
}
// Unread the bits we've read, then return errMissingEOL.
b.bits = (b.bits >> nBitsRead) | bitsRead
b.nBits += nBitsRead
return errMissingEOL
}
}
type reader struct {
br bitReader
subFormat SubFormat
// width is the image width in pixels.
width int
// rowsRemaining starts at the image height in pixels, when the reader is
// driven through the io.Reader interface, and decrements to zero as rows
// are decoded. Alternatively, it may be negative if the image height is
// not known in advance at the time of the NewReader call.
//
// When driven through DecodeIntoGray, this field is unused.
rowsRemaining int
// curr and prev hold the current and previous rows. Each element is either
// 0x00 (black) or 0xFF (white).
//
// prev may be nil, when processing the first row.
curr []byte
prev []byte
// ri is the read index. curr[:ri] are those bytes of curr that have been
// passed along via the Read method.
//
// When the reader is driven through DecodeIntoGray, instead of through the
// io.Reader interface, this field is unused.
ri int
// wi is the write index. curr[:wi] are those bytes of curr that have
// already been decoded via the decodeRow method.
//
// What this implementation calls wi is roughly equivalent to what the spec
// calls the a0 index.
wi int
// These fields are copied from the *Options (which may be nil).
align bool
invert bool
// atStartOfRow is whether we have just started the row. Some parts of the
// spec say to treat this situation as if "wi = -1".
atStartOfRow bool
// penColorIsWhite is whether the next run is black or white.
penColorIsWhite bool
// seenStartOfImage is whether we've called the startDecode method.
seenStartOfImage bool
// truncated is whether the input is missing the final 6 consecutive EOL's
// (for Group3) or 2 consecutive EOL's (for Group4). Omitting that trailer
// (but otherwise padding to a byte boundary, with either all 0 bits or all
// 1 bits) is invalid according to the spec, but happens in practice when
// exporting from Adobe Acrobat to TIFF + CCITT. This package silently
// ignores the format error for CCITT input that has been truncated in that
// fashion, returning the full decoded image.
//
// Detecting trailer truncation (just after the final row of pixels)
// requires knowing which row is the final row, and therefore does not
// trigger if the image height is not known in advance.
truncated bool
// readErr is a sticky error for the Read method.
readErr error
}
func (z *reader) Read(p []byte) (int, error) {
if z.readErr != nil {
return 0, z.readErr
}
originalP := p
for len(p) > 0 {
// Allocate buffers (and decode any start-of-image codes), if
// processing the first or second row.
if z.curr == nil {
if !z.seenStartOfImage {
if z.readErr = z.startDecode(); z.readErr != nil {
break
}
z.atStartOfRow = true
}
z.curr = make([]byte, z.width)
}
// Decode the next row, if necessary.
if z.atStartOfRow {
if z.rowsRemaining < 0 {
// We do not know the image height in advance. See if the next
// code is an EOL. If it is, it is consumed. If it isn't, the
// bitReader shouldn't advance along the bit stream, and we
// simply decode another row of pixel data.
//
// For the Group4 subFormat, we may need to align to a byte
// boundary. For the Group3 subFormat, the previous z.decodeRow
// call (or z.startDecode call) has already consumed one of the
// 6 consecutive EOL's. The next EOL is actually the second of
// 6, in the middle, and we shouldn't align at that point.
if z.align && (z.subFormat == Group4) {
z.br.alignToByteBoundary()
}
if err := z.decodeEOL(); err == errMissingEOL {
// No-op. It's another row of pixel data.
} else if err != nil {
z.readErr = err
break
} else {
if z.readErr = z.finishDecode(true); z.readErr != nil {
break
}
z.readErr = io.EOF
break
}
} else if z.rowsRemaining == 0 {
// We do know the image height in advance, and we have already
// decoded exactly that many rows.
if z.readErr = z.finishDecode(false); z.readErr != nil {
break
}
z.readErr = io.EOF
break
} else {
z.rowsRemaining--
}
if z.readErr = z.decodeRow(z.rowsRemaining == 0); z.readErr != nil {
break
}
}
// Pack from z.curr (1 byte per pixel) to p (1 bit per pixel).
packD, packS := highBits(p, z.curr[z.ri:], z.invert)
p = p[packD:]
z.ri += packS
// Prepare to decode the next row, if necessary.
if z.ri == len(z.curr) {
z.ri, z.curr, z.prev = 0, z.prev, z.curr
z.atStartOfRow = true
}
}
n := len(originalP) - len(p)
if z.invert {
invertBytes(originalP[:n])
}
return n, z.readErr
}
func (z *reader) penColor() byte {
if z.penColorIsWhite {
return 0xFF
}
return 0x00
}
func (z *reader) startDecode() error {
switch z.subFormat {
case Group3:
if err := z.decodeEOL(); err != nil {
return err
}
case Group4:
// No-op.
default:
return errUnsupportedSubFormat
}
z.seenStartOfImage = true
return nil
}
func (z *reader) finishDecode(alreadySeenEOL bool) error {
numberOfEOLs := 0
switch z.subFormat {
case Group3:
if z.truncated {
return nil
}
// The stream ends with a RTC (Return To Control) of 6 consecutive
// EOL's, but we should have already just seen an EOL, either in
// z.startDecode (for a zero-height image) or in z.decodeRow.
numberOfEOLs = 5
case Group4:
autoDetectHeight := z.rowsRemaining < 0
if autoDetectHeight {
// Aligning to a byte boundary was already handled by reader.Read.
} else if z.align {
z.br.alignToByteBoundary()
}
// The stream ends with two EOL's. If the first one is missing, and we
// had an explicit image height, we just assume that the trailing two
// EOL's were truncated and return a nil error.
if err := z.decodeEOL(); err != nil {
if (err == errMissingEOL) && !autoDetectHeight {
z.truncated = true
return nil
}
return err
}
numberOfEOLs = 1
default:
return errUnsupportedSubFormat
}
if alreadySeenEOL {
numberOfEOLs--
}
for ; numberOfEOLs > 0; numberOfEOLs-- {
if err := z.decodeEOL(); err != nil {
return err
}
}
return nil
}
func (z *reader) decodeEOL() error {
return decodeEOL(&z.br)
}
func (z *reader) decodeRow(finalRow bool) error {
z.wi = 0
z.atStartOfRow = true
z.penColorIsWhite = true
if z.align {
z.br.alignToByteBoundary()
}
switch z.subFormat {
case Group3:
for ; z.wi < len(z.curr); z.atStartOfRow = false {
if err := z.decodeRun(); err != nil {
return err
}
}
err := z.decodeEOL()
if finalRow && (err == errMissingEOL) {
z.truncated = true
return nil
}
return err
case Group4:
for ; z.wi < len(z.curr); z.atStartOfRow = false {
mode, err := decode(&z.br, modeDecodeTable[:])
if err != nil {
return err
}
rm := readerMode{}
if mode < uint32(len(readerModes)) {
rm = readerModes[mode]
}
if rm.function == nil {
return errInvalidMode
}
if err := rm.function(z, rm.arg); err != nil {
return err
}
}
return nil
}
return errUnsupportedSubFormat
}
func (z *reader) decodeRun() error {
table := blackDecodeTable[:]
if z.penColorIsWhite {
table = whiteDecodeTable[:]
}
total := 0
for {
n, err := decode(&z.br, table)
if err != nil {
return err
}
if n > maxWidth {
panic("unreachable")
}
total += int(n)
if total > maxWidth {
return errRunLengthTooLong
}
// Anything 0x3F or below is a terminal code.
if n <= 0x3F {
break
}
}
if total > (len(z.curr) - z.wi) {
return errRunLengthOverflowsWidth
}
dst := z.curr[z.wi : z.wi+total]
penColor := z.penColor()
for i := range dst {
dst[i] = penColor
}
z.wi += total
z.penColorIsWhite = !z.penColorIsWhite
return nil
}
// The various modes' semantics are based on determining a row of pixels'
// "changing elements": those pixels whose color differs from the one on its
// immediate left.
//
// The row above the first row is implicitly all white. Similarly, the column
// to the left of the first column is implicitly all white.
//
// For example, here's Figure 1 in "ITU-T Recommendation T.6", where the
// current and previous rows contain black (B) and white (w) pixels. The a?
// indexes point into curr, the b? indexes point into prev.
//
// b1 b2
// v v
// prev: BBBBBwwwwwBBBwwwww
// curr: BBBwwwwwBBBBBBwwww
// ^ ^ ^
// a0 a1 a2
//
// a0 is the "reference element" or current decoder position, roughly
// equivalent to what this implementation calls reader.wi.
//
// a1 is the next changing element to the right of a0, on the "coding line"
// (the current row).
//
// a2 is the next changing element to the right of a1, again on curr.
//
// b1 is the first changing element on the "reference line" (the previous row)
// to the right of a0 and of opposite color to a0.
//
// b2 is the next changing element to the right of b1, again on prev.
//
// The various modes calculate a1 (and a2, for modeH):
// - modePass calculates that a1 is at or to the right of b2.
// - modeH calculates a1 and a2 without considering b1 or b2.
// - modeV* calculates a1 to be b1 plus an adjustment (between -3 and +3).
const (
findB1 = false
findB2 = true
)
// findB finds either the b1 or b2 value.
func (z *reader) findB(whichB bool) int {
// The initial row is a special case. The previous row is implicitly all
// white, so that there are no changing pixel elements. We return b1 or b2
// to be at the end of the row.
if len(z.prev) != len(z.curr) {
return len(z.curr)
}
i := z.wi
if z.atStartOfRow {
// a0 is implicitly at -1, on a white pixel. b1 is the first black
// pixel in the previous row. b2 is the first white pixel after that.
for ; (i < len(z.prev)) && (z.prev[i] == 0xFF); i++ {
}
if whichB == findB2 {
for ; (i < len(z.prev)) && (z.prev[i] == 0x00); i++ {
}
}
return i
}
// As per figure 1 above, assume that the current pen color is white.
// First, walk past every contiguous black pixel in prev, starting at a0.
oppositeColor := ^z.penColor()
for ; (i < len(z.prev)) && (z.prev[i] == oppositeColor); i++ {
}
// Then walk past every contiguous white pixel.
penColor := ^oppositeColor
for ; (i < len(z.prev)) && (z.prev[i] == penColor); i++ {
}
// We're now at a black pixel (or at the end of the row). That's b1.
if whichB == findB2 {
// If we're looking for b2, walk past every contiguous black pixel
// again.
oppositeColor := ^penColor
for ; (i < len(z.prev)) && (z.prev[i] == oppositeColor); i++ {
}
}
return i
}
type readerMode struct {
function func(z *reader, arg int) error
arg int
}
var readerModes = [...]readerMode{
modePass: {function: readerModePass},
modeH: {function: readerModeH},
modeV0: {function: readerModeV, arg: +0},
modeVR1: {function: readerModeV, arg: +1},
modeVR2: {function: readerModeV, arg: +2},
modeVR3: {function: readerModeV, arg: +3},
modeVL1: {function: readerModeV, arg: -1},
modeVL2: {function: readerModeV, arg: -2},
modeVL3: {function: readerModeV, arg: -3},
modeExt: {function: readerModeExt},
}
func readerModePass(z *reader, arg int) error {
b2 := z.findB(findB2)
if (b2 < z.wi) || (len(z.curr) < b2) {
return errInvalidOffset
}
dst := z.curr[z.wi:b2]
penColor := z.penColor()
for i := range dst {
dst[i] = penColor
}
z.wi = b2
return nil
}
func readerModeH(z *reader, arg int) error {
// The first iteration finds a1. The second finds a2.
for i := 0; i < 2; i++ {
if err := z.decodeRun(); err != nil {
return err
}
}
return nil
}
func readerModeV(z *reader, arg int) error {
a1 := z.findB(findB1) + arg
if (a1 < z.wi) || (len(z.curr) < a1) {
return errInvalidOffset
}
dst := z.curr[z.wi:a1]
penColor := z.penColor()
for i := range dst {
dst[i] = penColor
}
z.wi = a1
z.penColorIsWhite = !z.penColorIsWhite
return nil
}
func readerModeExt(z *reader, arg int) error {
return errUnsupportedMode
}
// DecodeIntoGray decodes the CCITT-formatted data in r into dst.
//
// It returns an error if dst's width and height don't match the implied width
// and height of CCITT-formatted data.
func DecodeIntoGray(dst *image.Gray, r io.Reader, order Order, sf SubFormat, opts *Options) error {
bounds := dst.Bounds()
if (bounds.Dx() < 0) || (bounds.Dy() < 0) {
return errInvalidBounds
}
if bounds.Dx() > maxWidth {
return errUnsupportedWidth
}
z := reader{
br: bitReader{r: r, order: order},
subFormat: sf,
align: (opts != nil) && opts.Align,
invert: (opts != nil) && opts.Invert,
width: bounds.Dx(),
}
if err := z.startDecode(); err != nil {
return err
}
width := bounds.Dx()
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
p := (y - bounds.Min.Y) * dst.Stride
z.curr = dst.Pix[p : p+width]
if err := z.decodeRow(y+1 == bounds.Max.Y); err != nil {
return err
}
z.curr, z.prev = nil, z.curr
}
if err := z.finishDecode(false); err != nil {
return err
}
if z.invert {
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
p := (y - bounds.Min.Y) * dst.Stride
invertBytes(dst.Pix[p : p+width])
}
}
return nil
}
// NewReader returns an io.Reader that decodes the CCITT-formatted data in r.
// The resultant byte stream is one bit per pixel (MSB first), with 1 meaning
// white and 0 meaning black. Each row in the result is byte-aligned.
//
// A negative height, such as passing AutoDetectHeight, means that the image
// height is not known in advance. A negative width is invalid.
func NewReader(r io.Reader, order Order, sf SubFormat, width int, height int, opts *Options) io.Reader {
readErr := error(nil)
if width < 0 {
readErr = errInvalidBounds
} else if width > maxWidth {
readErr = errUnsupportedWidth
}
return &reader{
br: bitReader{r: r, order: order},
subFormat: sf,
align: (opts != nil) && opts.Align,
invert: (opts != nil) && opts.Invert,
width: width,
rowsRemaining: height,
readErr: readErr,
}
}
// Copyright 2019 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 ccitt
import (
"encoding/binary"
"io"
)
type bitWriter struct {
w io.Writer
// order is whether to process w's bytes LSB first or MSB first.
order Order
// The high nBits bits of the bits field hold encoded bits to be written to w.
bits uint64
nBits uint32
// bytes[:bw] holds encoded bytes not yet written to w.
// Overflow protection is ensured by using a multiple of 8 as bytes length.
bw uint32
bytes [1024]uint8
}
// flushBits copies 64 bits from b.bits to b.bytes. If b.bytes is then full, it
// is written to b.w.
func (b *bitWriter) flushBits() error {
binary.BigEndian.PutUint64(b.bytes[b.bw:], b.bits)
b.bits = 0
b.nBits = 0
b.bw += 8
if b.bw < uint32(len(b.bytes)) {
return nil
}
b.bw = 0
if b.order != MSB {
reverseBitsWithinBytes(b.bytes[:])
}
_, err := b.w.Write(b.bytes[:])
return err
}
// close finalizes a bitcode stream by writing any
// pending bits to bitWriter's underlying io.Writer.
func (b *bitWriter) close() error {
// Write any encoded bits to bytes.
if b.nBits > 0 {
binary.BigEndian.PutUint64(b.bytes[b.bw:], b.bits)
b.bw += (b.nBits + 7) >> 3
}
if b.order != MSB {
reverseBitsWithinBytes(b.bytes[:b.bw])
}
// Write b.bw bytes to b.w.
_, err := b.w.Write(b.bytes[:b.bw])
return err
}
// alignToByteBoundary rounds b.nBits up to a multiple of 8.
// If all 64 bits are used, flush them to bitWriter's bytes.
func (b *bitWriter) alignToByteBoundary() error {
if b.nBits = (b.nBits + 7) &^ 7; b.nBits == 64 {
return b.flushBits()
}
return nil
}
// writeCode writes a variable length bitcode to b's underlying io.Writer.
func (b *bitWriter) writeCode(bs bitString) error {
bits := bs.bits
nBits := bs.nBits
if 64-b.nBits >= nBits {
// b.bits has sufficient room for storing nBits bits.
b.bits |= uint64(bits) << (64 - nBits - b.nBits)
b.nBits += nBits
if b.nBits == 64 {
return b.flushBits()
}
return nil
}
// Number of leading bits that fill b.bits.
i := 64 - b.nBits
// Fill b.bits then flush and write remaining bits.
b.bits |= uint64(bits) >> (nBits - i)
b.nBits = 64
if err := b.flushBits(); err != nil {
return err
}
nBits -= i
b.bits = uint64(bits) << (64 - nBits)
b.nBits = nBits
return nil
}
// 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.
// Package draw provides image composition functions.
//
// See "The Go image/draw package" for an introduction to this package:
// http://golang.org/doc/articles/image_draw.html
//
// This package is a superset of and a drop-in replacement for the image/draw
// 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.
import (
"image"
"image/draw"
)
// Draw calls DrawMask with a nil mask.
func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point, op Op) {
draw.Draw(dst, r, src, sp, draw.Op(op))
}
// DrawMask aligns r.Min in dst with sp in src and mp in mask and then
// replaces the rectangle r in dst with the result of a Porter-Duff
// composition. A nil mask is treated as opaque.
func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
draw.DrawMask(dst, r, src, sp, mask, mp, draw.Op(op))
}
// Drawer contains the Draw method.
type Drawer = draw.Drawer
// FloydSteinberg is a Drawer that is the Src Op with Floyd-Steinberg error
// diffusion.
var FloydSteinberg Drawer = floydSteinberg{}
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 = draw.Image
// RGBA64Image extends both the Image and image.RGBA64Image interfaces with a
// SetRGBA64 method to change a single pixel. SetRGBA64 is equivalent to
// calling Set, but it can avoid allocations from converting concrete color
// types to the color.Color interface type.
type RGBA64Image = draw.RGBA64Image
// 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
// generated by "go run gen.go". DO NOT EDIT.
package draw
import (
"image"
"image/color"
"math"
"golang.org/x/image/math/f64"
)
func (z nnInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
// Try to simplify a Scale to a Copy when DstMask is not specified.
// If DstMask is not nil, Copy will call Scale back with same dr and sr, and cause stack overflow.
if dr.Size() == sr.Size() && (opts == nil || opts.DstMask == nil) {
Copy(dst, dr.Min, src, sr, op, opts)
return
}
var o Options
if opts != nil {
o = *opts
}
// adr is the affected destination pixels.
adr := dst.Bounds().Intersect(dr)
adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
if adr.Empty() || sr.Empty() {
return
}
// Make adr relative to dr.Min.
adr = adr.Sub(dr.Min)
if op == Over && o.SrcMask == nil && opaque(src) {
op = Src
}
// sr is the source pixels. If it extends beyond the src bounds,
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
//
// Similarly, the fast paths assume that the masks are nil.
if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
switch op {
case Over:
z.scale_Image_Image_Over(dst, dr, adr, src, sr, &o)
case Src:
z.scale_Image_Image_Src(dst, dr, adr, src, sr, &o)
}
} else if _, ok := src.(*image.Uniform); ok {
Draw(dst, dr, src, src.Bounds().Min, op)
} else {
switch op {
case Over:
switch dst := dst.(type) {
case *image.RGBA:
switch src := src.(type) {
case *image.NRGBA:
z.scale_RGBA_NRGBA_Over(dst, dr, adr, src, sr, &o)
case *image.RGBA:
z.scale_RGBA_RGBA_Over(dst, dr, adr, src, sr, &o)
case image.RGBA64Image:
z.scale_RGBA_RGBA64Image_Over(dst, dr, adr, src, sr, &o)
default:
z.scale_RGBA_Image_Over(dst, dr, adr, src, sr, &o)
}
case RGBA64Image:
switch src := src.(type) {
case image.RGBA64Image:
z.scale_RGBA64Image_RGBA64Image_Over(dst, dr, adr, src, sr, &o)
}
default:
switch src := src.(type) {
default:
z.scale_Image_Image_Over(dst, dr, adr, src, sr, &o)
}
}
case Src:
switch dst := dst.(type) {
case *image.RGBA:
switch src := src.(type) {
case *image.Gray:
z.scale_RGBA_Gray_Src(dst, dr, adr, src, sr, &o)
case *image.NRGBA:
z.scale_RGBA_NRGBA_Src(dst, dr, adr, src, sr, &o)
case *image.RGBA:
z.scale_RGBA_RGBA_Src(dst, dr, adr, src, sr, &o)
case *image.YCbCr:
switch src.SubsampleRatio {
default:
z.scale_RGBA_Image_Src(dst, dr, adr, src, sr, &o)
case image.YCbCrSubsampleRatio444:
z.scale_RGBA_YCbCr444_Src(dst, dr, adr, src, sr, &o)
case image.YCbCrSubsampleRatio422:
z.scale_RGBA_YCbCr422_Src(dst, dr, adr, src, sr, &o)
case image.YCbCrSubsampleRatio420:
z.scale_RGBA_YCbCr420_Src(dst, dr, adr, src, sr, &o)
case image.YCbCrSubsampleRatio440:
z.scale_RGBA_YCbCr440_Src(dst, dr, adr, src, sr, &o)
}
case image.RGBA64Image:
z.scale_RGBA_RGBA64Image_Src(dst, dr, adr, src, sr, &o)
default:
z.scale_RGBA_Image_Src(dst, dr, adr, src, sr, &o)
}
case RGBA64Image:
switch src := src.(type) {
case image.RGBA64Image:
z.scale_RGBA64Image_RGBA64Image_Src(dst, dr, adr, src, sr, &o)
}
default:
switch src := src.(type) {
default:
z.scale_Image_Image_Src(dst, dr, adr, src, sr, &o)
}
}
}
}
}
func (z nnInterpolator) Transform(dst Image, s2d f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options) {
// Try to simplify a Transform to a Copy.
if s2d[0] == 1 && s2d[1] == 0 && s2d[3] == 0 && s2d[4] == 1 {
dx := int(s2d[2])
dy := int(s2d[5])
if float64(dx) == s2d[2] && float64(dy) == s2d[5] {
Copy(dst, image.Point{X: sr.Min.X + dx, Y: sr.Min.X + dy}, src, sr, op, opts)
return
}
}
var o Options
if opts != nil {
o = *opts
}
dr := transformRect(&s2d, &sr)
// adr is the affected destination pixels.
adr := dst.Bounds().Intersect(dr)
adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
if adr.Empty() || sr.Empty() {
return
}
if op == Over && o.SrcMask == nil && opaque(src) {
op = Src
}
d2s := invert(&s2d)
// bias is a translation of the mapping from dst coordinates to src
// coordinates such that the latter temporarily have non-negative X
// and Y coordinates. This allows us to write int(f) instead of
// int(math.Floor(f)), since "round to zero" and "round down" are
// equivalent when f >= 0, but the former is much cheaper. The X--
// and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
// adjustment.
bias := transformRect(&d2s, &adr).Min
bias.X--
bias.Y--
d2s[2] -= float64(bias.X)
d2s[5] -= float64(bias.Y)
// Make adr relative to dr.Min.
adr = adr.Sub(dr.Min)
// sr is the source pixels. If it extends beyond the src bounds,
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
//
// Similarly, the fast paths assume that the masks are nil.
if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
switch op {
case Over:
z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
case Src:
z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
}
} else if u, ok := src.(*image.Uniform); ok {
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
} else {
switch op {
case Over:
switch dst := dst.(type) {
case *image.RGBA:
switch src := src.(type) {
case *image.NRGBA:
z.transform_RGBA_NRGBA_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
case *image.RGBA:
z.transform_RGBA_RGBA_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
case image.RGBA64Image:
z.transform_RGBA_RGBA64Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
default:
z.transform_RGBA_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
}
case RGBA64Image:
switch src := src.(type) {
case image.RGBA64Image:
z.transform_RGBA64Image_RGBA64Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
}
default:
switch src := src.(type) {
default:
z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
}
}
case Src:
switch dst := dst.(type) {
case *image.RGBA:
switch src := src.(type) {
case *image.Gray:
z.transform_RGBA_Gray_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
case *image.NRGBA:
z.transform_RGBA_NRGBA_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
case *image.RGBA:
z.transform_RGBA_RGBA_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
case *image.YCbCr:
switch src.SubsampleRatio {
default:
z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
case image.YCbCrSubsampleRatio444:
z.transform_RGBA_YCbCr444_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
case image.YCbCrSubsampleRatio422:
z.transform_RGBA_YCbCr422_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
case image.YCbCrSubsampleRatio420:
z.transform_RGBA_YCbCr420_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
case image.YCbCrSubsampleRatio440:
z.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
}
case image.RGBA64Image:
z.transform_RGBA_RGBA64Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
default:
z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
}
case RGBA64Image:
switch src := src.(type) {
case image.RGBA64Image:
z.transform_RGBA64Image_RGBA64Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
}
default:
switch src := src.(type) {
default:
z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
}
}
}
}
}
func (nnInterpolator) scale_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.Gray, sr image.Rectangle, opts *Options) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := (2*uint64(dy) + 1) * sh / dh2
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := (2*uint64(dx) + 1) * sw / dw2
pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx) - src.Rect.Min.X)
pr := uint32(src.Pix[pi]) * 0x101
out := uint8(pr >> 8)
dst.Pix[d+0] = out
dst.Pix[d+1] = out
dst.Pix[d+2] = out
dst.Pix[d+3] = 0xff
}
}
}
func (nnInterpolator) scale_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, src *image.NRGBA, sr image.Rectangle, opts *Options) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := (2*uint64(dy) + 1) * sh / dh2
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := (2*uint64(dx) + 1) * sw / dw2
pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx)-src.Rect.Min.X)*4
pa := uint32(src.Pix[pi+3]) * 0x101
pr := uint32(src.Pix[pi+0]) * pa / 0xff
pg := uint32(src.Pix[pi+1]) * pa / 0xff
pb := uint32(src.Pix[pi+2]) * pa / 0xff
pa1 := (0xffff - pa) * 0x101
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
}
}
}
func (nnInterpolator) scale_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.NRGBA, sr image.Rectangle, opts *Options) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := (2*uint64(dy) + 1) * sh / dh2
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := (2*uint64(dx) + 1) * sw / dw2
pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx)-src.Rect.Min.X)*4
pa := uint32(src.Pix[pi+3]) * 0x101
pr := uint32(src.Pix[pi+0]) * pa / 0xff
pg := uint32(src.Pix[pi+1]) * pa / 0xff
pb := uint32(src.Pix[pi+2]) * pa / 0xff
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = uint8(pa >> 8)
}
}
}
func (nnInterpolator) scale_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, src *image.RGBA, sr image.Rectangle, opts *Options) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := (2*uint64(dy) + 1) * sh / dh2
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := (2*uint64(dx) + 1) * sw / dw2
pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx)-src.Rect.Min.X)*4
pr := uint32(src.Pix[pi+0]) * 0x101
pg := uint32(src.Pix[pi+1]) * 0x101
pb := uint32(src.Pix[pi+2]) * 0x101
pa := uint32(src.Pix[pi+3]) * 0x101
pa1 := (0xffff - pa) * 0x101
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
}
}
}
func (nnInterpolator) scale_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.RGBA, sr image.Rectangle, opts *Options) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := (2*uint64(dy) + 1) * sh / dh2
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := (2*uint64(dx) + 1) * sw / dw2
pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx)-src.Rect.Min.X)*4
pr := uint32(src.Pix[pi+0]) * 0x101
pg := uint32(src.Pix[pi+1]) * 0x101
pb := uint32(src.Pix[pi+2]) * 0x101
pa := uint32(src.Pix[pi+3]) * 0x101
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = uint8(pa >> 8)
}
}
}
func (nnInterpolator) scale_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := (2*uint64(dy) + 1) * sh / dh2
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := (2*uint64(dx) + 1) * sw / dw2
pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
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]) * 0x10101
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pr := (pyy1 + 91881*pcr1) >> 8
pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pb := (pyy1 + 116130*pcb1) >> 8
if pr < 0 {
pr = 0
} else if pr > 0xffff {
pr = 0xffff
}
if pg < 0 {
pg = 0
} else if pg > 0xffff {
pg = 0xffff
}
if pb < 0 {
pb = 0
} else if pb > 0xffff {
pb = 0xffff
}
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = 0xff
}
}
}
func (nnInterpolator) scale_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := (2*uint64(dy) + 1) * sh / dh2
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := (2*uint64(dx) + 1) * sw / dw2
pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
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]) * 0x10101
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pr := (pyy1 + 91881*pcr1) >> 8
pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pb := (pyy1 + 116130*pcb1) >> 8
if pr < 0 {
pr = 0
} else if pr > 0xffff {
pr = 0xffff
}
if pg < 0 {
pg = 0
} else if pg > 0xffff {
pg = 0xffff
}
if pb < 0 {
pb = 0
} else if pb > 0xffff {
pb = 0xffff
}
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = 0xff
}
}
}
func (nnInterpolator) scale_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := (2*uint64(dy) + 1) * sh / dh2
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := (2*uint64(dx) + 1) * sw / dw2
pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
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]) * 0x10101
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pr := (pyy1 + 91881*pcr1) >> 8
pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pb := (pyy1 + 116130*pcb1) >> 8
if pr < 0 {
pr = 0
} else if pr > 0xffff {
pr = 0xffff
}
if pg < 0 {
pg = 0
} else if pg > 0xffff {
pg = 0xffff
}
if pb < 0 {
pb = 0
} else if pb > 0xffff {
pb = 0xffff
}
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = 0xff
}
}
}
func (nnInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := (2*uint64(dy) + 1) * sh / dh2
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := (2*uint64(dx) + 1) * sw / dw2
pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
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]) * 0x10101
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pr := (pyy1 + 91881*pcr1) >> 8
pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pb := (pyy1 + 116130*pcb1) >> 8
if pr < 0 {
pr = 0
} else if pr > 0xffff {
pr = 0xffff
}
if pg < 0 {
pg = 0
} else if pg > 0xffff {
pg = 0xffff
}
if pb < 0 {
pb = 0
} else if pb > 0xffff {
pb = 0xffff
}
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = 0xff
}
}
}
func (nnInterpolator) scale_RGBA_RGBA64Image_Over(dst *image.RGBA, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := (2*uint64(dy) + 1) * sh / dh2
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := (2*uint64(dx) + 1) * sw / dw2
p := src.RGBA64At(sr.Min.X+int(sx), sr.Min.Y+int(sy))
pa1 := (0xffff - uint32(p.A)) * 0x101
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + uint32(p.R)) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + uint32(p.G)) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + uint32(p.B)) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + uint32(p.A)) >> 8)
}
}
}
func (nnInterpolator) scale_RGBA_RGBA64Image_Src(dst *image.RGBA, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := (2*uint64(dy) + 1) * sh / dh2
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := (2*uint64(dx) + 1) * sw / dw2
p := src.RGBA64At(sr.Min.X+int(sx), sr.Min.Y+int(sy))
dst.Pix[d+0] = uint8(p.R >> 8)
dst.Pix[d+1] = uint8(p.G >> 8)
dst.Pix[d+2] = uint8(p.B >> 8)
dst.Pix[d+3] = uint8(p.A >> 8)
}
}
}
func (nnInterpolator) scale_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := (2*uint64(dy) + 1) * sh / dh2
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := (2*uint64(dx) + 1) * sw / dw2
pr, pg, pb, pa := src.At(sr.Min.X+int(sx), sr.Min.Y+int(sy)).RGBA()
pa1 := (0xffff - pa) * 0x101
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
}
}
}
func (nnInterpolator) scale_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := (2*uint64(dy) + 1) * sh / dh2
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := (2*uint64(dx) + 1) * sw / dw2
pr, pg, pb, pa := src.At(sr.Min.X+int(sx), sr.Min.Y+int(sy)).RGBA()
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = uint8(pa >> 8)
}
}
}
func (nnInterpolator) scale_RGBA64Image_RGBA64Image_Over(dst RGBA64Image, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := color.RGBA64{}
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := (2*uint64(dy) + 1) * sh / dh2
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
sx := (2*uint64(dx) + 1) * sw / dw2
p := src.RGBA64At(sr.Min.X+int(sx), sr.Min.Y+int(sy))
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx), smp.Y+sr.Min.Y+int(sy)).RGBA()
p.R = uint16(uint32(p.R) * ma / 0xffff)
p.G = uint16(uint32(p.G) * ma / 0xffff)
p.B = uint16(uint32(p.B) * ma / 0xffff)
p.A = uint16(uint32(p.A) * ma / 0xffff)
}
q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy))
if dstMask != nil {
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
p.R = uint16(uint32(p.R) * ma / 0xffff)
p.G = uint16(uint32(p.G) * ma / 0xffff)
p.B = uint16(uint32(p.B) * ma / 0xffff)
p.A = uint16(uint32(p.A) * ma / 0xffff)
}
pa1 := 0xffff - uint32(p.A)
dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R))
dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G))
dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B))
dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A))
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64)
}
}
}
func (nnInterpolator) scale_RGBA64Image_RGBA64Image_Src(dst RGBA64Image, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := color.RGBA64{}
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := (2*uint64(dy) + 1) * sh / dh2
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
sx := (2*uint64(dx) + 1) * sw / dw2
p := src.RGBA64At(sr.Min.X+int(sx), sr.Min.Y+int(sy))
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx), smp.Y+sr.Min.Y+int(sy)).RGBA()
p.R = uint16(uint32(p.R) * ma / 0xffff)
p.G = uint16(uint32(p.G) * ma / 0xffff)
p.B = uint16(uint32(p.B) * ma / 0xffff)
p.A = uint16(uint32(p.A) * ma / 0xffff)
}
if dstMask != nil {
q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy))
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
p.R = uint16(uint32(p.R) * ma / 0xffff)
p.G = uint16(uint32(p.G) * ma / 0xffff)
p.B = uint16(uint32(p.B) * ma / 0xffff)
p.A = uint16(uint32(p.A) * ma / 0xffff)
pa1 := 0xffff - ma
dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R))
dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G))
dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B))
dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A))
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64)
} else {
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), p)
}
}
}
}
func (nnInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := (2*uint64(dy) + 1) * sh / dh2
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
sx := (2*uint64(dx) + 1) * sw / dw2
pr, pg, pb, pa := src.At(sr.Min.X+int(sx), sr.Min.Y+int(sy)).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx), smp.Y+sr.Min.Y+int(sy)).RGBA()
pr = pr * ma / 0xffff
pg = pg * ma / 0xffff
pb = pb * ma / 0xffff
pa = pa * ma / 0xffff
}
qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
if dstMask != nil {
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
pr = pr * ma / 0xffff
pg = pg * ma / 0xffff
pb = pb * ma / 0xffff
pa = pa * ma / 0xffff
}
pa1 := 0xffff - pa
dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
}
}
}
func (nnInterpolator) scale_Image_Image_Src(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := (2*uint64(dy) + 1) * sh / dh2
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
sx := (2*uint64(dx) + 1) * sw / dw2
pr, pg, pb, pa := src.At(sr.Min.X+int(sx), sr.Min.Y+int(sy)).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx), smp.Y+sr.Min.Y+int(sy)).RGBA()
pr = pr * ma / 0xffff
pg = pg * ma / 0xffff
pb = pb * ma / 0xffff
pa = pa * ma / 0xffff
}
if dstMask != nil {
qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
pr = pr * ma / 0xffff
pg = pg * ma / 0xffff
pb = pb * ma / 0xffff
pa = pa * ma / 0xffff
pa1 := 0xffff - ma
dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
} else {
dstColorRGBA64.R = uint16(pr)
dstColorRGBA64.G = uint16(pg)
dstColorRGBA64.B = uint16(pb)
dstColorRGBA64.A = uint16(pa)
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
}
}
}
}
func (nnInterpolator) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X
sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
pi := (sy0-src.Rect.Min.Y)*src.Stride + (sx0 - src.Rect.Min.X)
pr := uint32(src.Pix[pi]) * 0x101
out := uint8(pr >> 8)
dst.Pix[d+0] = out
dst.Pix[d+1] = out
dst.Pix[d+2] = out
dst.Pix[d+3] = 0xff
}
}
}
func (nnInterpolator) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X
sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
pi := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
pa := uint32(src.Pix[pi+3]) * 0x101
pr := uint32(src.Pix[pi+0]) * pa / 0xff
pg := uint32(src.Pix[pi+1]) * pa / 0xff
pb := uint32(src.Pix[pi+2]) * pa / 0xff
pa1 := (0xffff - pa) * 0x101
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
}
}
}
func (nnInterpolator) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X
sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
pi := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
pa := uint32(src.Pix[pi+3]) * 0x101
pr := uint32(src.Pix[pi+0]) * pa / 0xff
pg := uint32(src.Pix[pi+1]) * pa / 0xff
pb := uint32(src.Pix[pi+2]) * pa / 0xff
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = uint8(pa >> 8)
}
}
}
func (nnInterpolator) transform_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X
sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
pi := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
pr := uint32(src.Pix[pi+0]) * 0x101
pg := uint32(src.Pix[pi+1]) * 0x101
pb := uint32(src.Pix[pi+2]) * 0x101
pa := uint32(src.Pix[pi+3]) * 0x101
pa1 := (0xffff - pa) * 0x101
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
}
}
}
func (nnInterpolator) transform_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X
sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
pi := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
pr := uint32(src.Pix[pi+0]) * 0x101
pg := uint32(src.Pix[pi+1]) * 0x101
pb := uint32(src.Pix[pi+2]) * 0x101
pa := uint32(src.Pix[pi+3]) * 0x101
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = uint8(pa >> 8)
}
}
}
func (nnInterpolator) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X
sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
pi := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
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]) * 0x10101
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pr := (pyy1 + 91881*pcr1) >> 8
pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pb := (pyy1 + 116130*pcb1) >> 8
if pr < 0 {
pr = 0
} else if pr > 0xffff {
pr = 0xffff
}
if pg < 0 {
pg = 0
} else if pg > 0xffff {
pg = 0xffff
}
if pb < 0 {
pb = 0
} else if pb > 0xffff {
pb = 0xffff
}
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = 0xff
}
}
}
func (nnInterpolator) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X
sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
pi := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
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]) * 0x10101
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pr := (pyy1 + 91881*pcr1) >> 8
pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pb := (pyy1 + 116130*pcb1) >> 8
if pr < 0 {
pr = 0
} else if pr > 0xffff {
pr = 0xffff
}
if pg < 0 {
pg = 0
} else if pg > 0xffff {
pg = 0xffff
}
if pb < 0 {
pb = 0
} else if pb > 0xffff {
pb = 0xffff
}
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = 0xff
}
}
}
func (nnInterpolator) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X
sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
pi := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
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]) * 0x10101
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pr := (pyy1 + 91881*pcr1) >> 8
pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pb := (pyy1 + 116130*pcb1) >> 8
if pr < 0 {
pr = 0
} else if pr > 0xffff {
pr = 0xffff
}
if pg < 0 {
pg = 0
} else if pg > 0xffff {
pg = 0xffff
}
if pb < 0 {
pb = 0
} else if pb > 0xffff {
pb = 0xffff
}
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = 0xff
}
}
}
func (nnInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X
sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
pi := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
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]) * 0x10101
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pr := (pyy1 + 91881*pcr1) >> 8
pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pb := (pyy1 + 116130*pcb1) >> 8
if pr < 0 {
pr = 0
} else if pr > 0xffff {
pr = 0xffff
}
if pg < 0 {
pg = 0
} else if pg > 0xffff {
pg = 0xffff
}
if pb < 0 {
pb = 0
} else if pb > 0xffff {
pb = 0xffff
}
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = 0xff
}
}
}
func (nnInterpolator) transform_RGBA_RGBA64Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X
sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
p := src.RGBA64At(sx0, sy0)
pa1 := (0xffff - uint32(p.A)) * 0x101
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + uint32(p.R)) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + uint32(p.G)) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + uint32(p.B)) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + uint32(p.A)) >> 8)
}
}
}
func (nnInterpolator) transform_RGBA_RGBA64Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X
sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
p := src.RGBA64At(sx0, sy0)
dst.Pix[d+0] = uint8(p.R >> 8)
dst.Pix[d+1] = uint8(p.G >> 8)
dst.Pix[d+2] = uint8(p.B >> 8)
dst.Pix[d+3] = uint8(p.A >> 8)
}
}
}
func (nnInterpolator) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X
sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
pr, pg, pb, pa := src.At(sx0, sy0).RGBA()
pa1 := (0xffff - pa) * 0x101
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
}
}
}
func (nnInterpolator) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X
sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
pr, pg, pb, pa := src.At(sx0, sy0).RGBA()
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = uint8(pa >> 8)
}
}
}
func (nnInterpolator) transform_RGBA64Image_RGBA64Image_Over(dst RGBA64Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) {
srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := color.RGBA64{}
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X
sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
p := src.RGBA64At(sx0, sy0)
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA()
p.R = uint16(uint32(p.R) * ma / 0xffff)
p.G = uint16(uint32(p.G) * ma / 0xffff)
p.B = uint16(uint32(p.B) * ma / 0xffff)
p.A = uint16(uint32(p.A) * ma / 0xffff)
}
q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy))
if dstMask != nil {
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
p.R = uint16(uint32(p.R) * ma / 0xffff)
p.G = uint16(uint32(p.G) * ma / 0xffff)
p.B = uint16(uint32(p.B) * ma / 0xffff)
p.A = uint16(uint32(p.A) * ma / 0xffff)
}
pa1 := 0xffff - uint32(p.A)
dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R))
dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G))
dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B))
dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A))
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64)
}
}
}
func (nnInterpolator) transform_RGBA64Image_RGBA64Image_Src(dst RGBA64Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) {
srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := color.RGBA64{}
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X
sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
p := src.RGBA64At(sx0, sy0)
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA()
p.R = uint16(uint32(p.R) * ma / 0xffff)
p.G = uint16(uint32(p.G) * ma / 0xffff)
p.B = uint16(uint32(p.B) * ma / 0xffff)
p.A = uint16(uint32(p.A) * ma / 0xffff)
}
if dstMask != nil {
q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy))
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
p.R = uint16(uint32(p.R) * ma / 0xffff)
p.G = uint16(uint32(p.G) * ma / 0xffff)
p.B = uint16(uint32(p.B) * ma / 0xffff)
p.A = uint16(uint32(p.A) * ma / 0xffff)
pa1 := 0xffff - ma
dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R))
dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G))
dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B))
dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A))
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64)
} else {
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), p)
}
}
}
}
func (nnInterpolator) transform_Image_Image_Over(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X
sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
pr, pg, pb, pa := src.At(sx0, sy0).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA()
pr = pr * ma / 0xffff
pg = pg * ma / 0xffff
pb = pb * ma / 0xffff
pa = pa * ma / 0xffff
}
qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
if dstMask != nil {
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
pr = pr * ma / 0xffff
pg = pg * ma / 0xffff
pb = pb * ma / 0xffff
pa = pa * ma / 0xffff
}
pa1 := 0xffff - pa
dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
}
}
}
func (nnInterpolator) transform_Image_Image_Src(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X
sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
pr, pg, pb, pa := src.At(sx0, sy0).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA()
pr = pr * ma / 0xffff
pg = pg * ma / 0xffff
pb = pb * ma / 0xffff
pa = pa * ma / 0xffff
}
if dstMask != nil {
qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
pr = pr * ma / 0xffff
pg = pg * ma / 0xffff
pb = pb * ma / 0xffff
pa = pa * ma / 0xffff
pa1 := 0xffff - ma
dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
} else {
dstColorRGBA64.R = uint16(pr)
dstColorRGBA64.G = uint16(pg)
dstColorRGBA64.B = uint16(pb)
dstColorRGBA64.A = uint16(pa)
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
}
}
}
}
func (z ablInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
// Try to simplify a Scale to a Copy when DstMask is not specified.
// If DstMask is not nil, Copy will call Scale back with same dr and sr, and cause stack overflow.
if dr.Size() == sr.Size() && (opts == nil || opts.DstMask == nil) {
Copy(dst, dr.Min, src, sr, op, opts)
return
}
var o Options
if opts != nil {
o = *opts
}
// adr is the affected destination pixels.
adr := dst.Bounds().Intersect(dr)
adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
if adr.Empty() || sr.Empty() {
return
}
// Make adr relative to dr.Min.
adr = adr.Sub(dr.Min)
if op == Over && o.SrcMask == nil && opaque(src) {
op = Src
}
// sr is the source pixels. If it extends beyond the src bounds,
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
//
// Similarly, the fast paths assume that the masks are nil.
if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
switch op {
case Over:
z.scale_Image_Image_Over(dst, dr, adr, src, sr, &o)
case Src:
z.scale_Image_Image_Src(dst, dr, adr, src, sr, &o)
}
} else if _, ok := src.(*image.Uniform); ok {
Draw(dst, dr, src, src.Bounds().Min, op)
} else {
switch op {
case Over:
switch dst := dst.(type) {
case *image.RGBA:
switch src := src.(type) {
case *image.NRGBA:
z.scale_RGBA_NRGBA_Over(dst, dr, adr, src, sr, &o)
case *image.RGBA:
z.scale_RGBA_RGBA_Over(dst, dr, adr, src, sr, &o)
case image.RGBA64Image:
z.scale_RGBA_RGBA64Image_Over(dst, dr, adr, src, sr, &o)
default:
z.scale_RGBA_Image_Over(dst, dr, adr, src, sr, &o)
}
case RGBA64Image:
switch src := src.(type) {
case image.RGBA64Image:
z.scale_RGBA64Image_RGBA64Image_Over(dst, dr, adr, src, sr, &o)
}
default:
switch src := src.(type) {
default:
z.scale_Image_Image_Over(dst, dr, adr, src, sr, &o)
}
}
case Src:
switch dst := dst.(type) {
case *image.RGBA:
switch src := src.(type) {
case *image.Gray:
z.scale_RGBA_Gray_Src(dst, dr, adr, src, sr, &o)
case *image.NRGBA:
z.scale_RGBA_NRGBA_Src(dst, dr, adr, src, sr, &o)
case *image.RGBA:
z.scale_RGBA_RGBA_Src(dst, dr, adr, src, sr, &o)
case *image.YCbCr:
switch src.SubsampleRatio {
default:
z.scale_RGBA_Image_Src(dst, dr, adr, src, sr, &o)
case image.YCbCrSubsampleRatio444:
z.scale_RGBA_YCbCr444_Src(dst, dr, adr, src, sr, &o)
case image.YCbCrSubsampleRatio422:
z.scale_RGBA_YCbCr422_Src(dst, dr, adr, src, sr, &o)
case image.YCbCrSubsampleRatio420:
z.scale_RGBA_YCbCr420_Src(dst, dr, adr, src, sr, &o)
case image.YCbCrSubsampleRatio440:
z.scale_RGBA_YCbCr440_Src(dst, dr, adr, src, sr, &o)
}
case image.RGBA64Image:
z.scale_RGBA_RGBA64Image_Src(dst, dr, adr, src, sr, &o)
default:
z.scale_RGBA_Image_Src(dst, dr, adr, src, sr, &o)
}
case RGBA64Image:
switch src := src.(type) {
case image.RGBA64Image:
z.scale_RGBA64Image_RGBA64Image_Src(dst, dr, adr, src, sr, &o)
}
default:
switch src := src.(type) {
default:
z.scale_Image_Image_Src(dst, dr, adr, src, sr, &o)
}
}
}
}
}
func (z ablInterpolator) Transform(dst Image, s2d f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options) {
// Try to simplify a Transform to a Copy.
if s2d[0] == 1 && s2d[1] == 0 && s2d[3] == 0 && s2d[4] == 1 {
dx := int(s2d[2])
dy := int(s2d[5])
if float64(dx) == s2d[2] && float64(dy) == s2d[5] {
Copy(dst, image.Point{X: sr.Min.X + dx, Y: sr.Min.X + dy}, src, sr, op, opts)
return
}
}
var o Options
if opts != nil {
o = *opts
}
dr := transformRect(&s2d, &sr)
// adr is the affected destination pixels.
adr := dst.Bounds().Intersect(dr)
adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
if adr.Empty() || sr.Empty() {
return
}
if op == Over && o.SrcMask == nil && opaque(src) {
op = Src
}
d2s := invert(&s2d)
// bias is a translation of the mapping from dst coordinates to src
// coordinates such that the latter temporarily have non-negative X
// and Y coordinates. This allows us to write int(f) instead of
// int(math.Floor(f)), since "round to zero" and "round down" are
// equivalent when f >= 0, but the former is much cheaper. The X--
// and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
// adjustment.
bias := transformRect(&d2s, &adr).Min
bias.X--
bias.Y--
d2s[2] -= float64(bias.X)
d2s[5] -= float64(bias.Y)
// Make adr relative to dr.Min.
adr = adr.Sub(dr.Min)
// sr is the source pixels. If it extends beyond the src bounds,
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
//
// Similarly, the fast paths assume that the masks are nil.
if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
switch op {
case Over:
z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
case Src:
z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
}
} else if u, ok := src.(*image.Uniform); ok {
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
} else {
switch op {
case Over:
switch dst := dst.(type) {
case *image.RGBA:
switch src := src.(type) {
case *image.NRGBA:
z.transform_RGBA_NRGBA_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
case *image.RGBA:
z.transform_RGBA_RGBA_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
case image.RGBA64Image:
z.transform_RGBA_RGBA64Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
default:
z.transform_RGBA_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
}
case RGBA64Image:
switch src := src.(type) {
case image.RGBA64Image:
z.transform_RGBA64Image_RGBA64Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
}
default:
switch src := src.(type) {
default:
z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
}
}
case Src:
switch dst := dst.(type) {
case *image.RGBA:
switch src := src.(type) {
case *image.Gray:
z.transform_RGBA_Gray_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
case *image.NRGBA:
z.transform_RGBA_NRGBA_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
case *image.RGBA:
z.transform_RGBA_RGBA_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
case *image.YCbCr:
switch src.SubsampleRatio {
default:
z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
case image.YCbCrSubsampleRatio444:
z.transform_RGBA_YCbCr444_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
case image.YCbCrSubsampleRatio422:
z.transform_RGBA_YCbCr422_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
case image.YCbCrSubsampleRatio420:
z.transform_RGBA_YCbCr420_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
case image.YCbCrSubsampleRatio440:
z.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
}
case image.RGBA64Image:
z.transform_RGBA_RGBA64Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
default:
z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
}
case RGBA64Image:
switch src := src.(type) {
case image.RGBA64Image:
z.transform_RGBA64Image_RGBA64Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
}
default:
switch src := src.(type) {
default:
z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
}
}
}
}
}
func (ablInterpolator) scale_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.Gray, sr image.Rectangle, opts *Options) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := float64((float64(dy)+0.5)*yscale) - 0.5
// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
// sx, below.
sy0 := int32(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy1 := sy0 + 1
if sy < 0 {
sy0, sy1 = 0, 0
yFrac0, yFrac1 = 0, 1
} else if sy1 > shMinus1 {
sy0, sy1 = shMinus1, shMinus1
yFrac0, yFrac1 = 1, 0
}
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := float64((float64(dx)+0.5)*xscale) - 0.5
sx0 := int32(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx1 := sx0 + 1
if sx < 0 {
sx0, sx1 = 0, 0
xFrac0, xFrac1 = 0, 1
} else if sx1 > swMinus1 {
sx0, sx1 = swMinus1, swMinus1
xFrac0, xFrac1 = 1, 0
}
s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
s00ru := uint32(src.Pix[s00i]) * 0x101
s00r := float64(s00ru)
s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
s10ru := uint32(src.Pix[s10i]) * 0x101
s10r := float64(s10ru)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
s01ru := uint32(src.Pix[s01i]) * 0x101
s01r := float64(s01ru)
s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
s11ru := uint32(src.Pix[s11i]) * 0x101
s11r := float64(s11ru)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
pr := uint32(s11r)
out := uint8(pr >> 8)
dst.Pix[d+0] = out
dst.Pix[d+1] = out
dst.Pix[d+2] = out
dst.Pix[d+3] = 0xff
}
}
}
func (ablInterpolator) scale_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, src *image.NRGBA, sr image.Rectangle, opts *Options) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := float64((float64(dy)+0.5)*yscale) - 0.5
// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
// sx, below.
sy0 := int32(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy1 := sy0 + 1
if sy < 0 {
sy0, sy1 = 0, 0
yFrac0, yFrac1 = 0, 1
} else if sy1 > shMinus1 {
sy0, sy1 = shMinus1, shMinus1
yFrac0, yFrac1 = 1, 0
}
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := float64((float64(dx)+0.5)*xscale) - 0.5
sx0 := int32(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx1 := sx0 + 1
if sx < 0 {
sx0, sx1 = 0, 0
xFrac0, xFrac1 = 0, 1
} else if sx1 > swMinus1 {
sx0, sx1 = swMinus1, swMinus1
xFrac0, xFrac1 = 1, 0
}
s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
s00au := uint32(src.Pix[s00i+3]) * 0x101
s00ru := uint32(src.Pix[s00i+0]) * s00au / 0xff
s00gu := uint32(src.Pix[s00i+1]) * s00au / 0xff
s00bu := uint32(src.Pix[s00i+2]) * s00au / 0xff
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
s10au := uint32(src.Pix[s10i+3]) * 0x101
s10ru := uint32(src.Pix[s10i+0]) * s10au / 0xff
s10gu := uint32(src.Pix[s10i+1]) * s10au / 0xff
s10bu := uint32(src.Pix[s10i+2]) * s10au / 0xff
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10a := float64(s10au)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
s01au := uint32(src.Pix[s01i+3]) * 0x101
s01ru := uint32(src.Pix[s01i+0]) * s01au / 0xff
s01gu := uint32(src.Pix[s01i+1]) * s01au / 0xff
s01bu := uint32(src.Pix[s01i+2]) * s01au / 0xff
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
s11au := uint32(src.Pix[s11i+3]) * 0x101
s11ru := uint32(src.Pix[s11i+0]) * s11au / 0xff
s11gu := uint32(src.Pix[s11i+1]) * s11au / 0xff
s11bu := uint32(src.Pix[s11i+2]) * s11au / 0xff
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11a := float64(s11au)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
pa := uint32(s11a)
pa1 := (0xffff - pa) * 0x101
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
}
}
}
func (ablInterpolator) scale_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.NRGBA, sr image.Rectangle, opts *Options) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := float64((float64(dy)+0.5)*yscale) - 0.5
// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
// sx, below.
sy0 := int32(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy1 := sy0 + 1
if sy < 0 {
sy0, sy1 = 0, 0
yFrac0, yFrac1 = 0, 1
} else if sy1 > shMinus1 {
sy0, sy1 = shMinus1, shMinus1
yFrac0, yFrac1 = 1, 0
}
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := float64((float64(dx)+0.5)*xscale) - 0.5
sx0 := int32(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx1 := sx0 + 1
if sx < 0 {
sx0, sx1 = 0, 0
xFrac0, xFrac1 = 0, 1
} else if sx1 > swMinus1 {
sx0, sx1 = swMinus1, swMinus1
xFrac0, xFrac1 = 1, 0
}
s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
s00au := uint32(src.Pix[s00i+3]) * 0x101
s00ru := uint32(src.Pix[s00i+0]) * s00au / 0xff
s00gu := uint32(src.Pix[s00i+1]) * s00au / 0xff
s00bu := uint32(src.Pix[s00i+2]) * s00au / 0xff
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
s10au := uint32(src.Pix[s10i+3]) * 0x101
s10ru := uint32(src.Pix[s10i+0]) * s10au / 0xff
s10gu := uint32(src.Pix[s10i+1]) * s10au / 0xff
s10bu := uint32(src.Pix[s10i+2]) * s10au / 0xff
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10a := float64(s10au)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
s01au := uint32(src.Pix[s01i+3]) * 0x101
s01ru := uint32(src.Pix[s01i+0]) * s01au / 0xff
s01gu := uint32(src.Pix[s01i+1]) * s01au / 0xff
s01bu := uint32(src.Pix[s01i+2]) * s01au / 0xff
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
s11au := uint32(src.Pix[s11i+3]) * 0x101
s11ru := uint32(src.Pix[s11i+0]) * s11au / 0xff
s11gu := uint32(src.Pix[s11i+1]) * s11au / 0xff
s11bu := uint32(src.Pix[s11i+2]) * s11au / 0xff
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11a := float64(s11au)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
pa := uint32(s11a)
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = uint8(pa >> 8)
}
}
}
func (ablInterpolator) scale_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, src *image.RGBA, sr image.Rectangle, opts *Options) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := float64((float64(dy)+0.5)*yscale) - 0.5
// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
// sx, below.
sy0 := int32(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy1 := sy0 + 1
if sy < 0 {
sy0, sy1 = 0, 0
yFrac0, yFrac1 = 0, 1
} else if sy1 > shMinus1 {
sy0, sy1 = shMinus1, shMinus1
yFrac0, yFrac1 = 1, 0
}
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := float64((float64(dx)+0.5)*xscale) - 0.5
sx0 := int32(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx1 := sx0 + 1
if sx < 0 {
sx0, sx1 = 0, 0
xFrac0, xFrac1 = 0, 1
} else if sx1 > swMinus1 {
sx0, sx1 = swMinus1, swMinus1
xFrac0, xFrac1 = 1, 0
}
s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
s00ru := uint32(src.Pix[s00i+0]) * 0x101
s00gu := uint32(src.Pix[s00i+1]) * 0x101
s00bu := uint32(src.Pix[s00i+2]) * 0x101
s00au := uint32(src.Pix[s00i+3]) * 0x101
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
s10ru := uint32(src.Pix[s10i+0]) * 0x101
s10gu := uint32(src.Pix[s10i+1]) * 0x101
s10bu := uint32(src.Pix[s10i+2]) * 0x101
s10au := uint32(src.Pix[s10i+3]) * 0x101
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10a := float64(s10au)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
s01ru := uint32(src.Pix[s01i+0]) * 0x101
s01gu := uint32(src.Pix[s01i+1]) * 0x101
s01bu := uint32(src.Pix[s01i+2]) * 0x101
s01au := uint32(src.Pix[s01i+3]) * 0x101
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
s11ru := uint32(src.Pix[s11i+0]) * 0x101
s11gu := uint32(src.Pix[s11i+1]) * 0x101
s11bu := uint32(src.Pix[s11i+2]) * 0x101
s11au := uint32(src.Pix[s11i+3]) * 0x101
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11a := float64(s11au)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
pa := uint32(s11a)
pa1 := (0xffff - pa) * 0x101
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
}
}
}
func (ablInterpolator) scale_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.RGBA, sr image.Rectangle, opts *Options) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := float64((float64(dy)+0.5)*yscale) - 0.5
// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
// sx, below.
sy0 := int32(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy1 := sy0 + 1
if sy < 0 {
sy0, sy1 = 0, 0
yFrac0, yFrac1 = 0, 1
} else if sy1 > shMinus1 {
sy0, sy1 = shMinus1, shMinus1
yFrac0, yFrac1 = 1, 0
}
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := float64((float64(dx)+0.5)*xscale) - 0.5
sx0 := int32(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx1 := sx0 + 1
if sx < 0 {
sx0, sx1 = 0, 0
xFrac0, xFrac1 = 0, 1
} else if sx1 > swMinus1 {
sx0, sx1 = swMinus1, swMinus1
xFrac0, xFrac1 = 1, 0
}
s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
s00ru := uint32(src.Pix[s00i+0]) * 0x101
s00gu := uint32(src.Pix[s00i+1]) * 0x101
s00bu := uint32(src.Pix[s00i+2]) * 0x101
s00au := uint32(src.Pix[s00i+3]) * 0x101
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
s10ru := uint32(src.Pix[s10i+0]) * 0x101
s10gu := uint32(src.Pix[s10i+1]) * 0x101
s10bu := uint32(src.Pix[s10i+2]) * 0x101
s10au := uint32(src.Pix[s10i+3]) * 0x101
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10a := float64(s10au)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
s01ru := uint32(src.Pix[s01i+0]) * 0x101
s01gu := uint32(src.Pix[s01i+1]) * 0x101
s01bu := uint32(src.Pix[s01i+2]) * 0x101
s01au := uint32(src.Pix[s01i+3]) * 0x101
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
s11ru := uint32(src.Pix[s11i+0]) * 0x101
s11gu := uint32(src.Pix[s11i+1]) * 0x101
s11bu := uint32(src.Pix[s11i+2]) * 0x101
s11au := uint32(src.Pix[s11i+3]) * 0x101
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11a := float64(s11au)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
pa := uint32(s11a)
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = uint8(pa >> 8)
}
}
}
func (ablInterpolator) scale_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := float64((float64(dy)+0.5)*yscale) - 0.5
// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
// sx, below.
sy0 := int32(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy1 := sy0 + 1
if sy < 0 {
sy0, sy1 = 0, 0
yFrac0, yFrac1 = 0, 1
} else if sy1 > shMinus1 {
sy0, sy1 = shMinus1, shMinus1
yFrac0, yFrac1 = 1, 0
}
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := float64((float64(dx)+0.5)*xscale) - 0.5
sx0 := int32(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx1 := sx0 + 1
if sx < 0 {
sx0, sx1 = 0, 0
xFrac0, xFrac1 = 0, 1
} else if sx1 > swMinus1 {
sx0, sx1 = swMinus1, swMinus1
xFrac0, xFrac1 = 1, 0
}
s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
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]) * 0x10101
s00cb1 := int(src.Cb[s00j]) - 128
s00cr1 := int(src.Cr[s00j]) - 128
s00ru := (s00yy1 + 91881*s00cr1) >> 8
s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
s00bu := (s00yy1 + 116130*s00cb1) >> 8
if s00ru < 0 {
s00ru = 0
} else if s00ru > 0xffff {
s00ru = 0xffff
}
if s00gu < 0 {
s00gu = 0
} else if s00gu > 0xffff {
s00gu = 0xffff
}
if s00bu < 0 {
s00bu = 0
} else if s00bu > 0xffff {
s00bu = 0xffff
}
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
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]) * 0x10101
s10cb1 := int(src.Cb[s10j]) - 128
s10cr1 := int(src.Cr[s10j]) - 128
s10ru := (s10yy1 + 91881*s10cr1) >> 8
s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
s10bu := (s10yy1 + 116130*s10cb1) >> 8
if s10ru < 0 {
s10ru = 0
} else if s10ru > 0xffff {
s10ru = 0xffff
}
if s10gu < 0 {
s10gu = 0
} else if s10gu > 0xffff {
s10gu = 0xffff
}
if s10bu < 0 {
s10bu = 0
} else if s10bu > 0xffff {
s10bu = 0xffff
}
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
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]) * 0x10101
s01cb1 := int(src.Cb[s01j]) - 128
s01cr1 := int(src.Cr[s01j]) - 128
s01ru := (s01yy1 + 91881*s01cr1) >> 8
s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
s01bu := (s01yy1 + 116130*s01cb1) >> 8
if s01ru < 0 {
s01ru = 0
} else if s01ru > 0xffff {
s01ru = 0xffff
}
if s01gu < 0 {
s01gu = 0
} else if s01gu > 0xffff {
s01gu = 0xffff
}
if s01bu < 0 {
s01bu = 0
} else if s01bu > 0xffff {
s01bu = 0xffff
}
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
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]) * 0x10101
s11cb1 := int(src.Cb[s11j]) - 128
s11cr1 := int(src.Cr[s11j]) - 128
s11ru := (s11yy1 + 91881*s11cr1) >> 8
s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
s11bu := (s11yy1 + 116130*s11cb1) >> 8
if s11ru < 0 {
s11ru = 0
} else if s11ru > 0xffff {
s11ru = 0xffff
}
if s11gu < 0 {
s11gu = 0
} else if s11gu > 0xffff {
s11gu = 0xffff
}
if s11bu < 0 {
s11bu = 0
} else if s11bu > 0xffff {
s11bu = 0xffff
}
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = 0xff
}
}
}
func (ablInterpolator) scale_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := float64((float64(dy)+0.5)*yscale) - 0.5
// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
// sx, below.
sy0 := int32(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy1 := sy0 + 1
if sy < 0 {
sy0, sy1 = 0, 0
yFrac0, yFrac1 = 0, 1
} else if sy1 > shMinus1 {
sy0, sy1 = shMinus1, shMinus1
yFrac0, yFrac1 = 1, 0
}
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := float64((float64(dx)+0.5)*xscale) - 0.5
sx0 := int32(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx1 := sx0 + 1
if sx < 0 {
sx0, sx1 = 0, 0
xFrac0, xFrac1 = 0, 1
} else if sx1 > swMinus1 {
sx0, sx1 = swMinus1, swMinus1
xFrac0, xFrac1 = 1, 0
}
s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
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]) * 0x10101
s00cb1 := int(src.Cb[s00j]) - 128
s00cr1 := int(src.Cr[s00j]) - 128
s00ru := (s00yy1 + 91881*s00cr1) >> 8
s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
s00bu := (s00yy1 + 116130*s00cb1) >> 8
if s00ru < 0 {
s00ru = 0
} else if s00ru > 0xffff {
s00ru = 0xffff
}
if s00gu < 0 {
s00gu = 0
} else if s00gu > 0xffff {
s00gu = 0xffff
}
if s00bu < 0 {
s00bu = 0
} else if s00bu > 0xffff {
s00bu = 0xffff
}
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
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]) * 0x10101
s10cb1 := int(src.Cb[s10j]) - 128
s10cr1 := int(src.Cr[s10j]) - 128
s10ru := (s10yy1 + 91881*s10cr1) >> 8
s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
s10bu := (s10yy1 + 116130*s10cb1) >> 8
if s10ru < 0 {
s10ru = 0
} else if s10ru > 0xffff {
s10ru = 0xffff
}
if s10gu < 0 {
s10gu = 0
} else if s10gu > 0xffff {
s10gu = 0xffff
}
if s10bu < 0 {
s10bu = 0
} else if s10bu > 0xffff {
s10bu = 0xffff
}
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
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]) * 0x10101
s01cb1 := int(src.Cb[s01j]) - 128
s01cr1 := int(src.Cr[s01j]) - 128
s01ru := (s01yy1 + 91881*s01cr1) >> 8
s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
s01bu := (s01yy1 + 116130*s01cb1) >> 8
if s01ru < 0 {
s01ru = 0
} else if s01ru > 0xffff {
s01ru = 0xffff
}
if s01gu < 0 {
s01gu = 0
} else if s01gu > 0xffff {
s01gu = 0xffff
}
if s01bu < 0 {
s01bu = 0
} else if s01bu > 0xffff {
s01bu = 0xffff
}
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
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]) * 0x10101
s11cb1 := int(src.Cb[s11j]) - 128
s11cr1 := int(src.Cr[s11j]) - 128
s11ru := (s11yy1 + 91881*s11cr1) >> 8
s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
s11bu := (s11yy1 + 116130*s11cb1) >> 8
if s11ru < 0 {
s11ru = 0
} else if s11ru > 0xffff {
s11ru = 0xffff
}
if s11gu < 0 {
s11gu = 0
} else if s11gu > 0xffff {
s11gu = 0xffff
}
if s11bu < 0 {
s11bu = 0
} else if s11bu > 0xffff {
s11bu = 0xffff
}
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = 0xff
}
}
}
func (ablInterpolator) scale_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := float64((float64(dy)+0.5)*yscale) - 0.5
// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
// sx, below.
sy0 := int32(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy1 := sy0 + 1
if sy < 0 {
sy0, sy1 = 0, 0
yFrac0, yFrac1 = 0, 1
} else if sy1 > shMinus1 {
sy0, sy1 = shMinus1, shMinus1
yFrac0, yFrac1 = 1, 0
}
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := float64((float64(dx)+0.5)*xscale) - 0.5
sx0 := int32(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx1 := sx0 + 1
if sx < 0 {
sx0, sx1 = 0, 0
xFrac0, xFrac1 = 0, 1
} else if sx1 > swMinus1 {
sx0, sx1 = swMinus1, swMinus1
xFrac0, xFrac1 = 1, 0
}
s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
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]) * 0x10101
s00cb1 := int(src.Cb[s00j]) - 128
s00cr1 := int(src.Cr[s00j]) - 128
s00ru := (s00yy1 + 91881*s00cr1) >> 8
s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
s00bu := (s00yy1 + 116130*s00cb1) >> 8
if s00ru < 0 {
s00ru = 0
} else if s00ru > 0xffff {
s00ru = 0xffff
}
if s00gu < 0 {
s00gu = 0
} else if s00gu > 0xffff {
s00gu = 0xffff
}
if s00bu < 0 {
s00bu = 0
} else if s00bu > 0xffff {
s00bu = 0xffff
}
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
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]) * 0x10101
s10cb1 := int(src.Cb[s10j]) - 128
s10cr1 := int(src.Cr[s10j]) - 128
s10ru := (s10yy1 + 91881*s10cr1) >> 8
s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
s10bu := (s10yy1 + 116130*s10cb1) >> 8
if s10ru < 0 {
s10ru = 0
} else if s10ru > 0xffff {
s10ru = 0xffff
}
if s10gu < 0 {
s10gu = 0
} else if s10gu > 0xffff {
s10gu = 0xffff
}
if s10bu < 0 {
s10bu = 0
} else if s10bu > 0xffff {
s10bu = 0xffff
}
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
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]) * 0x10101
s01cb1 := int(src.Cb[s01j]) - 128
s01cr1 := int(src.Cr[s01j]) - 128
s01ru := (s01yy1 + 91881*s01cr1) >> 8
s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
s01bu := (s01yy1 + 116130*s01cb1) >> 8
if s01ru < 0 {
s01ru = 0
} else if s01ru > 0xffff {
s01ru = 0xffff
}
if s01gu < 0 {
s01gu = 0
} else if s01gu > 0xffff {
s01gu = 0xffff
}
if s01bu < 0 {
s01bu = 0
} else if s01bu > 0xffff {
s01bu = 0xffff
}
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
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]) * 0x10101
s11cb1 := int(src.Cb[s11j]) - 128
s11cr1 := int(src.Cr[s11j]) - 128
s11ru := (s11yy1 + 91881*s11cr1) >> 8
s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
s11bu := (s11yy1 + 116130*s11cb1) >> 8
if s11ru < 0 {
s11ru = 0
} else if s11ru > 0xffff {
s11ru = 0xffff
}
if s11gu < 0 {
s11gu = 0
} else if s11gu > 0xffff {
s11gu = 0xffff
}
if s11bu < 0 {
s11bu = 0
} else if s11bu > 0xffff {
s11bu = 0xffff
}
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = 0xff
}
}
}
func (ablInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := float64((float64(dy)+0.5)*yscale) - 0.5
// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
// sx, below.
sy0 := int32(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy1 := sy0 + 1
if sy < 0 {
sy0, sy1 = 0, 0
yFrac0, yFrac1 = 0, 1
} else if sy1 > shMinus1 {
sy0, sy1 = shMinus1, shMinus1
yFrac0, yFrac1 = 1, 0
}
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := float64((float64(dx)+0.5)*xscale) - 0.5
sx0 := int32(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx1 := sx0 + 1
if sx < 0 {
sx0, sx1 = 0, 0
xFrac0, xFrac1 = 0, 1
} else if sx1 > swMinus1 {
sx0, sx1 = swMinus1, swMinus1
xFrac0, xFrac1 = 1, 0
}
s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
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]) * 0x10101
s00cb1 := int(src.Cb[s00j]) - 128
s00cr1 := int(src.Cr[s00j]) - 128
s00ru := (s00yy1 + 91881*s00cr1) >> 8
s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
s00bu := (s00yy1 + 116130*s00cb1) >> 8
if s00ru < 0 {
s00ru = 0
} else if s00ru > 0xffff {
s00ru = 0xffff
}
if s00gu < 0 {
s00gu = 0
} else if s00gu > 0xffff {
s00gu = 0xffff
}
if s00bu < 0 {
s00bu = 0
} else if s00bu > 0xffff {
s00bu = 0xffff
}
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
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]) * 0x10101
s10cb1 := int(src.Cb[s10j]) - 128
s10cr1 := int(src.Cr[s10j]) - 128
s10ru := (s10yy1 + 91881*s10cr1) >> 8
s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
s10bu := (s10yy1 + 116130*s10cb1) >> 8
if s10ru < 0 {
s10ru = 0
} else if s10ru > 0xffff {
s10ru = 0xffff
}
if s10gu < 0 {
s10gu = 0
} else if s10gu > 0xffff {
s10gu = 0xffff
}
if s10bu < 0 {
s10bu = 0
} else if s10bu > 0xffff {
s10bu = 0xffff
}
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
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]) * 0x10101
s01cb1 := int(src.Cb[s01j]) - 128
s01cr1 := int(src.Cr[s01j]) - 128
s01ru := (s01yy1 + 91881*s01cr1) >> 8
s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
s01bu := (s01yy1 + 116130*s01cb1) >> 8
if s01ru < 0 {
s01ru = 0
} else if s01ru > 0xffff {
s01ru = 0xffff
}
if s01gu < 0 {
s01gu = 0
} else if s01gu > 0xffff {
s01gu = 0xffff
}
if s01bu < 0 {
s01bu = 0
} else if s01bu > 0xffff {
s01bu = 0xffff
}
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
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]) * 0x10101
s11cb1 := int(src.Cb[s11j]) - 128
s11cr1 := int(src.Cr[s11j]) - 128
s11ru := (s11yy1 + 91881*s11cr1) >> 8
s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
s11bu := (s11yy1 + 116130*s11cb1) >> 8
if s11ru < 0 {
s11ru = 0
} else if s11ru > 0xffff {
s11ru = 0xffff
}
if s11gu < 0 {
s11gu = 0
} else if s11gu > 0xffff {
s11gu = 0xffff
}
if s11bu < 0 {
s11bu = 0
} else if s11bu > 0xffff {
s11bu = 0xffff
}
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = 0xff
}
}
}
func (ablInterpolator) scale_RGBA_RGBA64Image_Over(dst *image.RGBA, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := float64((float64(dy)+0.5)*yscale) - 0.5
// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
// sx, below.
sy0 := int32(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy1 := sy0 + 1
if sy < 0 {
sy0, sy1 = 0, 0
yFrac0, yFrac1 = 0, 1
} else if sy1 > shMinus1 {
sy0, sy1 = shMinus1, shMinus1
yFrac0, yFrac1 = 1, 0
}
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := float64((float64(dx)+0.5)*xscale) - 0.5
sx0 := int32(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx1 := sx0 + 1
if sx < 0 {
sx0, sx1 = 0, 0
xFrac0, xFrac1 = 0, 1
} else if sx1 > swMinus1 {
sx0, sx1 = swMinus1, swMinus1
xFrac0, xFrac1 = 1, 0
}
s00u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0))
s00r := float64(s00u.R)
s00g := float64(s00u.G)
s00b := float64(s00u.B)
s00a := float64(s00u.A)
s10u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0))
s10r := float64(s10u.R)
s10g := float64(s10u.G)
s10b := float64(s10u.B)
s10a := float64(s10u.A)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1))
s01r := float64(s01u.R)
s01g := float64(s01u.G)
s01b := float64(s01u.B)
s01a := float64(s01u.A)
s11u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1))
s11r := float64(s11u.R)
s11g := float64(s11u.G)
s11b := float64(s11u.B)
s11a := float64(s11u.A)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)}
pa1 := (0xffff - uint32(p.A)) * 0x101
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + uint32(p.R)) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + uint32(p.G)) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + uint32(p.B)) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + uint32(p.A)) >> 8)
}
}
}
func (ablInterpolator) scale_RGBA_RGBA64Image_Src(dst *image.RGBA, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := float64((float64(dy)+0.5)*yscale) - 0.5
// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
// sx, below.
sy0 := int32(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy1 := sy0 + 1
if sy < 0 {
sy0, sy1 = 0, 0
yFrac0, yFrac1 = 0, 1
} else if sy1 > shMinus1 {
sy0, sy1 = shMinus1, shMinus1
yFrac0, yFrac1 = 1, 0
}
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := float64((float64(dx)+0.5)*xscale) - 0.5
sx0 := int32(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx1 := sx0 + 1
if sx < 0 {
sx0, sx1 = 0, 0
xFrac0, xFrac1 = 0, 1
} else if sx1 > swMinus1 {
sx0, sx1 = swMinus1, swMinus1
xFrac0, xFrac1 = 1, 0
}
s00u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0))
s00r := float64(s00u.R)
s00g := float64(s00u.G)
s00b := float64(s00u.B)
s00a := float64(s00u.A)
s10u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0))
s10r := float64(s10u.R)
s10g := float64(s10u.G)
s10b := float64(s10u.B)
s10a := float64(s10u.A)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1))
s01r := float64(s01u.R)
s01g := float64(s01u.G)
s01b := float64(s01u.B)
s01a := float64(s01u.A)
s11u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1))
s11r := float64(s11u.R)
s11g := float64(s11u.G)
s11b := float64(s11u.B)
s11a := float64(s11u.A)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)}
dst.Pix[d+0] = uint8(p.R >> 8)
dst.Pix[d+1] = uint8(p.G >> 8)
dst.Pix[d+2] = uint8(p.B >> 8)
dst.Pix[d+3] = uint8(p.A >> 8)
}
}
}
func (ablInterpolator) scale_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := float64((float64(dy)+0.5)*yscale) - 0.5
// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
// sx, below.
sy0 := int32(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy1 := sy0 + 1
if sy < 0 {
sy0, sy1 = 0, 0
yFrac0, yFrac1 = 0, 1
} else if sy1 > shMinus1 {
sy0, sy1 = shMinus1, shMinus1
yFrac0, yFrac1 = 1, 0
}
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := float64((float64(dx)+0.5)*xscale) - 0.5
sx0 := int32(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx1 := sx0 + 1
if sx < 0 {
sx0, sx1 = 0, 0
xFrac0, xFrac1 = 0, 1
} else if sx1 > swMinus1 {
sx0, sx1 = swMinus1, swMinus1
xFrac0, xFrac1 = 1, 0
}
s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA()
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA()
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10a := float64(s10au)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA()
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA()
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11a := float64(s11au)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
pa := uint32(s11a)
pa1 := (0xffff - pa) * 0x101
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
}
}
}
func (ablInterpolator) scale_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := float64((float64(dy)+0.5)*yscale) - 0.5
// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
// sx, below.
sy0 := int32(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy1 := sy0 + 1
if sy < 0 {
sy0, sy1 = 0, 0
yFrac0, yFrac1 = 0, 1
} else if sy1 > shMinus1 {
sy0, sy1 = shMinus1, shMinus1
yFrac0, yFrac1 = 1, 0
}
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := float64((float64(dx)+0.5)*xscale) - 0.5
sx0 := int32(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx1 := sx0 + 1
if sx < 0 {
sx0, sx1 = 0, 0
xFrac0, xFrac1 = 0, 1
} else if sx1 > swMinus1 {
sx0, sx1 = swMinus1, swMinus1
xFrac0, xFrac1 = 1, 0
}
s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA()
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA()
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10a := float64(s10au)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA()
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA()
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11a := float64(s11au)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
pa := uint32(s11a)
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = uint8(pa >> 8)
}
}
}
func (ablInterpolator) scale_RGBA64Image_RGBA64Image_Over(dst RGBA64Image, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := color.RGBA64{}
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := float64((float64(dy)+0.5)*yscale) - 0.5
// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
// sx, below.
sy0 := int32(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy1 := sy0 + 1
if sy < 0 {
sy0, sy1 = 0, 0
yFrac0, yFrac1 = 0, 1
} else if sy1 > shMinus1 {
sy0, sy1 = shMinus1, shMinus1
yFrac0, yFrac1 = 1, 0
}
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
sx := float64((float64(dx)+0.5)*xscale) - 0.5
sx0 := int32(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx1 := sx0 + 1
if sx < 0 {
sx0, sx1 = 0, 0
xFrac0, xFrac1 = 0, 1
} else if sx1 > swMinus1 {
sx0, sx1 = swMinus1, swMinus1
xFrac0, xFrac1 = 1, 0
}
s00u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0))
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy0)).RGBA()
s00u.R = uint16(uint32(s00u.R) * ma / 0xffff)
s00u.G = uint16(uint32(s00u.G) * ma / 0xffff)
s00u.B = uint16(uint32(s00u.B) * ma / 0xffff)
s00u.A = uint16(uint32(s00u.A) * ma / 0xffff)
}
s00r := float64(s00u.R)
s00g := float64(s00u.G)
s00b := float64(s00u.B)
s00a := float64(s00u.A)
s10u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0))
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy0)).RGBA()
s10u.R = uint16(uint32(s10u.R) * ma / 0xffff)
s10u.G = uint16(uint32(s10u.G) * ma / 0xffff)
s10u.B = uint16(uint32(s10u.B) * ma / 0xffff)
s10u.A = uint16(uint32(s10u.A) * ma / 0xffff)
}
s10r := float64(s10u.R)
s10g := float64(s10u.G)
s10b := float64(s10u.B)
s10a := float64(s10u.A)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1))
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy1)).RGBA()
s01u.R = uint16(uint32(s01u.R) * ma / 0xffff)
s01u.G = uint16(uint32(s01u.G) * ma / 0xffff)
s01u.B = uint16(uint32(s01u.B) * ma / 0xffff)
s01u.A = uint16(uint32(s01u.A) * ma / 0xffff)
}
s01r := float64(s01u.R)
s01g := float64(s01u.G)
s01b := float64(s01u.B)
s01a := float64(s01u.A)
s11u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1))
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy1)).RGBA()
s11u.R = uint16(uint32(s11u.R) * ma / 0xffff)
s11u.G = uint16(uint32(s11u.G) * ma / 0xffff)
s11u.B = uint16(uint32(s11u.B) * ma / 0xffff)
s11u.A = uint16(uint32(s11u.A) * ma / 0xffff)
}
s11r := float64(s11u.R)
s11g := float64(s11u.G)
s11b := float64(s11u.B)
s11a := float64(s11u.A)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)}
q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy))
if dstMask != nil {
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
p.R = uint16(uint32(p.R) * ma / 0xffff)
p.G = uint16(uint32(p.G) * ma / 0xffff)
p.B = uint16(uint32(p.B) * ma / 0xffff)
p.A = uint16(uint32(p.A) * ma / 0xffff)
}
pa1 := 0xffff - uint32(p.A)
dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R))
dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G))
dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B))
dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A))
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64)
}
}
}
func (ablInterpolator) scale_RGBA64Image_RGBA64Image_Src(dst RGBA64Image, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := color.RGBA64{}
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := float64((float64(dy)+0.5)*yscale) - 0.5
// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
// sx, below.
sy0 := int32(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy1 := sy0 + 1
if sy < 0 {
sy0, sy1 = 0, 0
yFrac0, yFrac1 = 0, 1
} else if sy1 > shMinus1 {
sy0, sy1 = shMinus1, shMinus1
yFrac0, yFrac1 = 1, 0
}
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
sx := float64((float64(dx)+0.5)*xscale) - 0.5
sx0 := int32(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx1 := sx0 + 1
if sx < 0 {
sx0, sx1 = 0, 0
xFrac0, xFrac1 = 0, 1
} else if sx1 > swMinus1 {
sx0, sx1 = swMinus1, swMinus1
xFrac0, xFrac1 = 1, 0
}
s00u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0))
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy0)).RGBA()
s00u.R = uint16(uint32(s00u.R) * ma / 0xffff)
s00u.G = uint16(uint32(s00u.G) * ma / 0xffff)
s00u.B = uint16(uint32(s00u.B) * ma / 0xffff)
s00u.A = uint16(uint32(s00u.A) * ma / 0xffff)
}
s00r := float64(s00u.R)
s00g := float64(s00u.G)
s00b := float64(s00u.B)
s00a := float64(s00u.A)
s10u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0))
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy0)).RGBA()
s10u.R = uint16(uint32(s10u.R) * ma / 0xffff)
s10u.G = uint16(uint32(s10u.G) * ma / 0xffff)
s10u.B = uint16(uint32(s10u.B) * ma / 0xffff)
s10u.A = uint16(uint32(s10u.A) * ma / 0xffff)
}
s10r := float64(s10u.R)
s10g := float64(s10u.G)
s10b := float64(s10u.B)
s10a := float64(s10u.A)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1))
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy1)).RGBA()
s01u.R = uint16(uint32(s01u.R) * ma / 0xffff)
s01u.G = uint16(uint32(s01u.G) * ma / 0xffff)
s01u.B = uint16(uint32(s01u.B) * ma / 0xffff)
s01u.A = uint16(uint32(s01u.A) * ma / 0xffff)
}
s01r := float64(s01u.R)
s01g := float64(s01u.G)
s01b := float64(s01u.B)
s01a := float64(s01u.A)
s11u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1))
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy1)).RGBA()
s11u.R = uint16(uint32(s11u.R) * ma / 0xffff)
s11u.G = uint16(uint32(s11u.G) * ma / 0xffff)
s11u.B = uint16(uint32(s11u.B) * ma / 0xffff)
s11u.A = uint16(uint32(s11u.A) * ma / 0xffff)
}
s11r := float64(s11u.R)
s11g := float64(s11u.G)
s11b := float64(s11u.B)
s11a := float64(s11u.A)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)}
if dstMask != nil {
q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy))
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
p.R = uint16(uint32(p.R) * ma / 0xffff)
p.G = uint16(uint32(p.G) * ma / 0xffff)
p.B = uint16(uint32(p.B) * ma / 0xffff)
p.A = uint16(uint32(p.A) * ma / 0xffff)
pa1 := 0xffff - ma
dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R))
dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G))
dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B))
dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A))
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64)
} else {
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), p)
}
}
}
}
func (ablInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := float64((float64(dy)+0.5)*yscale) - 0.5
// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
// sx, below.
sy0 := int32(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy1 := sy0 + 1
if sy < 0 {
sy0, sy1 = 0, 0
yFrac0, yFrac1 = 0, 1
} else if sy1 > shMinus1 {
sy0, sy1 = shMinus1, shMinus1
yFrac0, yFrac1 = 1, 0
}
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
sx := float64((float64(dx)+0.5)*xscale) - 0.5
sx0 := int32(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx1 := sx0 + 1
if sx < 0 {
sx0, sx1 = 0, 0
xFrac0, xFrac1 = 0, 1
} else if sx1 > swMinus1 {
sx0, sx1 = swMinus1, swMinus1
xFrac0, xFrac1 = 1, 0
}
s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy0)).RGBA()
s00ru = s00ru * ma / 0xffff
s00gu = s00gu * ma / 0xffff
s00bu = s00bu * ma / 0xffff
s00au = s00au * ma / 0xffff
}
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy0)).RGBA()
s10ru = s10ru * ma / 0xffff
s10gu = s10gu * ma / 0xffff
s10bu = s10bu * ma / 0xffff
s10au = s10au * ma / 0xffff
}
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10a := float64(s10au)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy1)).RGBA()
s01ru = s01ru * ma / 0xffff
s01gu = s01gu * ma / 0xffff
s01bu = s01bu * ma / 0xffff
s01au = s01au * ma / 0xffff
}
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy1)).RGBA()
s11ru = s11ru * ma / 0xffff
s11gu = s11gu * ma / 0xffff
s11bu = s11bu * ma / 0xffff
s11au = s11au * ma / 0xffff
}
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11a := float64(s11au)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
pa := uint32(s11a)
qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
if dstMask != nil {
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
pr = pr * ma / 0xffff
pg = pg * ma / 0xffff
pb = pb * ma / 0xffff
pa = pa * ma / 0xffff
}
pa1 := 0xffff - pa
dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
}
}
}
func (ablInterpolator) scale_Image_Image_Src(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := float64((float64(dy)+0.5)*yscale) - 0.5
// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
// sx, below.
sy0 := int32(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy1 := sy0 + 1
if sy < 0 {
sy0, sy1 = 0, 0
yFrac0, yFrac1 = 0, 1
} else if sy1 > shMinus1 {
sy0, sy1 = shMinus1, shMinus1
yFrac0, yFrac1 = 1, 0
}
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
sx := float64((float64(dx)+0.5)*xscale) - 0.5
sx0 := int32(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx1 := sx0 + 1
if sx < 0 {
sx0, sx1 = 0, 0
xFrac0, xFrac1 = 0, 1
} else if sx1 > swMinus1 {
sx0, sx1 = swMinus1, swMinus1
xFrac0, xFrac1 = 1, 0
}
s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy0)).RGBA()
s00ru = s00ru * ma / 0xffff
s00gu = s00gu * ma / 0xffff
s00bu = s00bu * ma / 0xffff
s00au = s00au * ma / 0xffff
}
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy0)).RGBA()
s10ru = s10ru * ma / 0xffff
s10gu = s10gu * ma / 0xffff
s10bu = s10bu * ma / 0xffff
s10au = s10au * ma / 0xffff
}
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10a := float64(s10au)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy1)).RGBA()
s01ru = s01ru * ma / 0xffff
s01gu = s01gu * ma / 0xffff
s01bu = s01bu * ma / 0xffff
s01au = s01au * ma / 0xffff
}
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy1)).RGBA()
s11ru = s11ru * ma / 0xffff
s11gu = s11gu * ma / 0xffff
s11bu = s11bu * ma / 0xffff
s11au = s11au * ma / 0xffff
}
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11a := float64(s11au)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
pa := uint32(s11a)
if dstMask != nil {
qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
pr = pr * ma / 0xffff
pg = pg * ma / 0xffff
pb = pb * ma / 0xffff
pa = pa * ma / 0xffff
pa1 := 0xffff - ma
dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
} else {
dstColorRGBA64.R = uint16(pr)
dstColorRGBA64.G = uint16(pg)
dstColorRGBA64.B = uint16(pb)
dstColorRGBA64.A = uint16(pa)
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
}
}
}
}
func (ablInterpolator) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
sx1 := sx0 + 1
if sx0 < sr.Min.X {
sx0, sx1 = sr.Min.X, sr.Min.X
xFrac0, xFrac1 = 0, 1
} else if sx1 >= sr.Max.X {
sx0, sx1 = sr.Max.X-1, sr.Max.X-1
xFrac0, xFrac1 = 1, 0
}
sy -= 0.5
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
sy1 := sy0 + 1
if sy0 < sr.Min.Y {
sy0, sy1 = sr.Min.Y, sr.Min.Y
yFrac0, yFrac1 = 0, 1
} else if sy1 >= sr.Max.Y {
sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
yFrac0, yFrac1 = 1, 0
}
s00i := (sy0-src.Rect.Min.Y)*src.Stride + (sx0 - src.Rect.Min.X)
s00ru := uint32(src.Pix[s00i]) * 0x101
s00r := float64(s00ru)
s10i := (sy0-src.Rect.Min.Y)*src.Stride + (sx1 - src.Rect.Min.X)
s10ru := uint32(src.Pix[s10i]) * 0x101
s10r := float64(s10ru)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0 - src.Rect.Min.X)
s01ru := uint32(src.Pix[s01i]) * 0x101
s01r := float64(s01ru)
s11i := (sy1-src.Rect.Min.Y)*src.Stride + (sx1 - src.Rect.Min.X)
s11ru := uint32(src.Pix[s11i]) * 0x101
s11r := float64(s11ru)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
pr := uint32(s11r)
out := uint8(pr >> 8)
dst.Pix[d+0] = out
dst.Pix[d+1] = out
dst.Pix[d+2] = out
dst.Pix[d+3] = 0xff
}
}
}
func (ablInterpolator) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
sx1 := sx0 + 1
if sx0 < sr.Min.X {
sx0, sx1 = sr.Min.X, sr.Min.X
xFrac0, xFrac1 = 0, 1
} else if sx1 >= sr.Max.X {
sx0, sx1 = sr.Max.X-1, sr.Max.X-1
xFrac0, xFrac1 = 1, 0
}
sy -= 0.5
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
sy1 := sy0 + 1
if sy0 < sr.Min.Y {
sy0, sy1 = sr.Min.Y, sr.Min.Y
yFrac0, yFrac1 = 0, 1
} else if sy1 >= sr.Max.Y {
sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
yFrac0, yFrac1 = 1, 0
}
s00i := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
s00au := uint32(src.Pix[s00i+3]) * 0x101
s00ru := uint32(src.Pix[s00i+0]) * s00au / 0xff
s00gu := uint32(src.Pix[s00i+1]) * s00au / 0xff
s00bu := uint32(src.Pix[s00i+2]) * s00au / 0xff
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10i := (sy0-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
s10au := uint32(src.Pix[s10i+3]) * 0x101
s10ru := uint32(src.Pix[s10i+0]) * s10au / 0xff
s10gu := uint32(src.Pix[s10i+1]) * s10au / 0xff
s10bu := uint32(src.Pix[s10i+2]) * s10au / 0xff
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10a := float64(s10au)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
s01au := uint32(src.Pix[s01i+3]) * 0x101
s01ru := uint32(src.Pix[s01i+0]) * s01au / 0xff
s01gu := uint32(src.Pix[s01i+1]) * s01au / 0xff
s01bu := uint32(src.Pix[s01i+2]) * s01au / 0xff
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11i := (sy1-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
s11au := uint32(src.Pix[s11i+3]) * 0x101
s11ru := uint32(src.Pix[s11i+0]) * s11au / 0xff
s11gu := uint32(src.Pix[s11i+1]) * s11au / 0xff
s11bu := uint32(src.Pix[s11i+2]) * s11au / 0xff
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11a := float64(s11au)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
pa := uint32(s11a)
pa1 := (0xffff - pa) * 0x101
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
}
}
}
func (ablInterpolator) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
sx1 := sx0 + 1
if sx0 < sr.Min.X {
sx0, sx1 = sr.Min.X, sr.Min.X
xFrac0, xFrac1 = 0, 1
} else if sx1 >= sr.Max.X {
sx0, sx1 = sr.Max.X-1, sr.Max.X-1
xFrac0, xFrac1 = 1, 0
}
sy -= 0.5
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
sy1 := sy0 + 1
if sy0 < sr.Min.Y {
sy0, sy1 = sr.Min.Y, sr.Min.Y
yFrac0, yFrac1 = 0, 1
} else if sy1 >= sr.Max.Y {
sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
yFrac0, yFrac1 = 1, 0
}
s00i := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
s00au := uint32(src.Pix[s00i+3]) * 0x101
s00ru := uint32(src.Pix[s00i+0]) * s00au / 0xff
s00gu := uint32(src.Pix[s00i+1]) * s00au / 0xff
s00bu := uint32(src.Pix[s00i+2]) * s00au / 0xff
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10i := (sy0-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
s10au := uint32(src.Pix[s10i+3]) * 0x101
s10ru := uint32(src.Pix[s10i+0]) * s10au / 0xff
s10gu := uint32(src.Pix[s10i+1]) * s10au / 0xff
s10bu := uint32(src.Pix[s10i+2]) * s10au / 0xff
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10a := float64(s10au)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
s01au := uint32(src.Pix[s01i+3]) * 0x101
s01ru := uint32(src.Pix[s01i+0]) * s01au / 0xff
s01gu := uint32(src.Pix[s01i+1]) * s01au / 0xff
s01bu := uint32(src.Pix[s01i+2]) * s01au / 0xff
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11i := (sy1-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
s11au := uint32(src.Pix[s11i+3]) * 0x101
s11ru := uint32(src.Pix[s11i+0]) * s11au / 0xff
s11gu := uint32(src.Pix[s11i+1]) * s11au / 0xff
s11bu := uint32(src.Pix[s11i+2]) * s11au / 0xff
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11a := float64(s11au)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
pa := uint32(s11a)
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = uint8(pa >> 8)
}
}
}
func (ablInterpolator) transform_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
sx1 := sx0 + 1
if sx0 < sr.Min.X {
sx0, sx1 = sr.Min.X, sr.Min.X
xFrac0, xFrac1 = 0, 1
} else if sx1 >= sr.Max.X {
sx0, sx1 = sr.Max.X-1, sr.Max.X-1
xFrac0, xFrac1 = 1, 0
}
sy -= 0.5
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
sy1 := sy0 + 1
if sy0 < sr.Min.Y {
sy0, sy1 = sr.Min.Y, sr.Min.Y
yFrac0, yFrac1 = 0, 1
} else if sy1 >= sr.Max.Y {
sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
yFrac0, yFrac1 = 1, 0
}
s00i := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
s00ru := uint32(src.Pix[s00i+0]) * 0x101
s00gu := uint32(src.Pix[s00i+1]) * 0x101
s00bu := uint32(src.Pix[s00i+2]) * 0x101
s00au := uint32(src.Pix[s00i+3]) * 0x101
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10i := (sy0-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
s10ru := uint32(src.Pix[s10i+0]) * 0x101
s10gu := uint32(src.Pix[s10i+1]) * 0x101
s10bu := uint32(src.Pix[s10i+2]) * 0x101
s10au := uint32(src.Pix[s10i+3]) * 0x101
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10a := float64(s10au)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
s01ru := uint32(src.Pix[s01i+0]) * 0x101
s01gu := uint32(src.Pix[s01i+1]) * 0x101
s01bu := uint32(src.Pix[s01i+2]) * 0x101
s01au := uint32(src.Pix[s01i+3]) * 0x101
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11i := (sy1-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
s11ru := uint32(src.Pix[s11i+0]) * 0x101
s11gu := uint32(src.Pix[s11i+1]) * 0x101
s11bu := uint32(src.Pix[s11i+2]) * 0x101
s11au := uint32(src.Pix[s11i+3]) * 0x101
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11a := float64(s11au)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
pa := uint32(s11a)
pa1 := (0xffff - pa) * 0x101
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
}
}
}
func (ablInterpolator) transform_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
sx1 := sx0 + 1
if sx0 < sr.Min.X {
sx0, sx1 = sr.Min.X, sr.Min.X
xFrac0, xFrac1 = 0, 1
} else if sx1 >= sr.Max.X {
sx0, sx1 = sr.Max.X-1, sr.Max.X-1
xFrac0, xFrac1 = 1, 0
}
sy -= 0.5
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
sy1 := sy0 + 1
if sy0 < sr.Min.Y {
sy0, sy1 = sr.Min.Y, sr.Min.Y
yFrac0, yFrac1 = 0, 1
} else if sy1 >= sr.Max.Y {
sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
yFrac0, yFrac1 = 1, 0
}
s00i := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
s00ru := uint32(src.Pix[s00i+0]) * 0x101
s00gu := uint32(src.Pix[s00i+1]) * 0x101
s00bu := uint32(src.Pix[s00i+2]) * 0x101
s00au := uint32(src.Pix[s00i+3]) * 0x101
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10i := (sy0-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
s10ru := uint32(src.Pix[s10i+0]) * 0x101
s10gu := uint32(src.Pix[s10i+1]) * 0x101
s10bu := uint32(src.Pix[s10i+2]) * 0x101
s10au := uint32(src.Pix[s10i+3]) * 0x101
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10a := float64(s10au)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
s01ru := uint32(src.Pix[s01i+0]) * 0x101
s01gu := uint32(src.Pix[s01i+1]) * 0x101
s01bu := uint32(src.Pix[s01i+2]) * 0x101
s01au := uint32(src.Pix[s01i+3]) * 0x101
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11i := (sy1-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
s11ru := uint32(src.Pix[s11i+0]) * 0x101
s11gu := uint32(src.Pix[s11i+1]) * 0x101
s11bu := uint32(src.Pix[s11i+2]) * 0x101
s11au := uint32(src.Pix[s11i+3]) * 0x101
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11a := float64(s11au)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
pa := uint32(s11a)
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = uint8(pa >> 8)
}
}
}
func (ablInterpolator) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
sx1 := sx0 + 1
if sx0 < sr.Min.X {
sx0, sx1 = sr.Min.X, sr.Min.X
xFrac0, xFrac1 = 0, 1
} else if sx1 >= sr.Max.X {
sx0, sx1 = sr.Max.X-1, sr.Max.X-1
xFrac0, xFrac1 = 1, 0
}
sy -= 0.5
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
sy1 := sy0 + 1
if sy0 < sr.Min.Y {
sy0, sy1 = sr.Min.Y, sr.Min.Y
yFrac0, yFrac1 = 0, 1
} else if sy1 >= sr.Max.Y {
sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
yFrac0, yFrac1 = 1, 0
}
s00i := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
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]) * 0x10101
s00cb1 := int(src.Cb[s00j]) - 128
s00cr1 := int(src.Cr[s00j]) - 128
s00ru := (s00yy1 + 91881*s00cr1) >> 8
s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
s00bu := (s00yy1 + 116130*s00cb1) >> 8
if s00ru < 0 {
s00ru = 0
} else if s00ru > 0xffff {
s00ru = 0xffff
}
if s00gu < 0 {
s00gu = 0
} else if s00gu > 0xffff {
s00gu = 0xffff
}
if s00bu < 0 {
s00bu = 0
} else if s00bu > 0xffff {
s00bu = 0xffff
}
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s10i := (sy0-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
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]) * 0x10101
s10cb1 := int(src.Cb[s10j]) - 128
s10cr1 := int(src.Cr[s10j]) - 128
s10ru := (s10yy1 + 91881*s10cr1) >> 8
s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
s10bu := (s10yy1 + 116130*s10cb1) >> 8
if s10ru < 0 {
s10ru = 0
} else if s10ru > 0xffff {
s10ru = 0xffff
}
if s10gu < 0 {
s10gu = 0
} else if s10gu > 0xffff {
s10gu = 0xffff
}
if s10bu < 0 {
s10bu = 0
} else if s10bu > 0xffff {
s10bu = 0xffff
}
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s01i := (sy1-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
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]) * 0x10101
s01cb1 := int(src.Cb[s01j]) - 128
s01cr1 := int(src.Cr[s01j]) - 128
s01ru := (s01yy1 + 91881*s01cr1) >> 8
s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
s01bu := (s01yy1 + 116130*s01cb1) >> 8
if s01ru < 0 {
s01ru = 0
} else if s01ru > 0xffff {
s01ru = 0xffff
}
if s01gu < 0 {
s01gu = 0
} else if s01gu > 0xffff {
s01gu = 0xffff
}
if s01bu < 0 {
s01bu = 0
} else if s01bu > 0xffff {
s01bu = 0xffff
}
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s11i := (sy1-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
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]) * 0x10101
s11cb1 := int(src.Cb[s11j]) - 128
s11cr1 := int(src.Cr[s11j]) - 128
s11ru := (s11yy1 + 91881*s11cr1) >> 8
s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
s11bu := (s11yy1 + 116130*s11cb1) >> 8
if s11ru < 0 {
s11ru = 0
} else if s11ru > 0xffff {
s11ru = 0xffff
}
if s11gu < 0 {
s11gu = 0
} else if s11gu > 0xffff {
s11gu = 0xffff
}
if s11bu < 0 {
s11bu = 0
} else if s11bu > 0xffff {
s11bu = 0xffff
}
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = 0xff
}
}
}
func (ablInterpolator) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
sx1 := sx0 + 1
if sx0 < sr.Min.X {
sx0, sx1 = sr.Min.X, sr.Min.X
xFrac0, xFrac1 = 0, 1
} else if sx1 >= sr.Max.X {
sx0, sx1 = sr.Max.X-1, sr.Max.X-1
xFrac0, xFrac1 = 1, 0
}
sy -= 0.5
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
sy1 := sy0 + 1
if sy0 < sr.Min.Y {
sy0, sy1 = sr.Min.Y, sr.Min.Y
yFrac0, yFrac1 = 0, 1
} else if sy1 >= sr.Max.Y {
sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
yFrac0, yFrac1 = 1, 0
}
s00i := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
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]) * 0x10101
s00cb1 := int(src.Cb[s00j]) - 128
s00cr1 := int(src.Cr[s00j]) - 128
s00ru := (s00yy1 + 91881*s00cr1) >> 8
s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
s00bu := (s00yy1 + 116130*s00cb1) >> 8
if s00ru < 0 {
s00ru = 0
} else if s00ru > 0xffff {
s00ru = 0xffff
}
if s00gu < 0 {
s00gu = 0
} else if s00gu > 0xffff {
s00gu = 0xffff
}
if s00bu < 0 {
s00bu = 0
} else if s00bu > 0xffff {
s00bu = 0xffff
}
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s10i := (sy0-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
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]) * 0x10101
s10cb1 := int(src.Cb[s10j]) - 128
s10cr1 := int(src.Cr[s10j]) - 128
s10ru := (s10yy1 + 91881*s10cr1) >> 8
s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
s10bu := (s10yy1 + 116130*s10cb1) >> 8
if s10ru < 0 {
s10ru = 0
} else if s10ru > 0xffff {
s10ru = 0xffff
}
if s10gu < 0 {
s10gu = 0
} else if s10gu > 0xffff {
s10gu = 0xffff
}
if s10bu < 0 {
s10bu = 0
} else if s10bu > 0xffff {
s10bu = 0xffff
}
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s01i := (sy1-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
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]) * 0x10101
s01cb1 := int(src.Cb[s01j]) - 128
s01cr1 := int(src.Cr[s01j]) - 128
s01ru := (s01yy1 + 91881*s01cr1) >> 8
s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
s01bu := (s01yy1 + 116130*s01cb1) >> 8
if s01ru < 0 {
s01ru = 0
} else if s01ru > 0xffff {
s01ru = 0xffff
}
if s01gu < 0 {
s01gu = 0
} else if s01gu > 0xffff {
s01gu = 0xffff
}
if s01bu < 0 {
s01bu = 0
} else if s01bu > 0xffff {
s01bu = 0xffff
}
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s11i := (sy1-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
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]) * 0x10101
s11cb1 := int(src.Cb[s11j]) - 128
s11cr1 := int(src.Cr[s11j]) - 128
s11ru := (s11yy1 + 91881*s11cr1) >> 8
s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
s11bu := (s11yy1 + 116130*s11cb1) >> 8
if s11ru < 0 {
s11ru = 0
} else if s11ru > 0xffff {
s11ru = 0xffff
}
if s11gu < 0 {
s11gu = 0
} else if s11gu > 0xffff {
s11gu = 0xffff
}
if s11bu < 0 {
s11bu = 0
} else if s11bu > 0xffff {
s11bu = 0xffff
}
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = 0xff
}
}
}
func (ablInterpolator) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
sx1 := sx0 + 1
if sx0 < sr.Min.X {
sx0, sx1 = sr.Min.X, sr.Min.X
xFrac0, xFrac1 = 0, 1
} else if sx1 >= sr.Max.X {
sx0, sx1 = sr.Max.X-1, sr.Max.X-1
xFrac0, xFrac1 = 1, 0
}
sy -= 0.5
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
sy1 := sy0 + 1
if sy0 < sr.Min.Y {
sy0, sy1 = sr.Min.Y, sr.Min.Y
yFrac0, yFrac1 = 0, 1
} else if sy1 >= sr.Max.Y {
sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
yFrac0, yFrac1 = 1, 0
}
s00i := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
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]) * 0x10101
s00cb1 := int(src.Cb[s00j]) - 128
s00cr1 := int(src.Cr[s00j]) - 128
s00ru := (s00yy1 + 91881*s00cr1) >> 8
s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
s00bu := (s00yy1 + 116130*s00cb1) >> 8
if s00ru < 0 {
s00ru = 0
} else if s00ru > 0xffff {
s00ru = 0xffff
}
if s00gu < 0 {
s00gu = 0
} else if s00gu > 0xffff {
s00gu = 0xffff
}
if s00bu < 0 {
s00bu = 0
} else if s00bu > 0xffff {
s00bu = 0xffff
}
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s10i := (sy0-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
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]) * 0x10101
s10cb1 := int(src.Cb[s10j]) - 128
s10cr1 := int(src.Cr[s10j]) - 128
s10ru := (s10yy1 + 91881*s10cr1) >> 8
s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
s10bu := (s10yy1 + 116130*s10cb1) >> 8
if s10ru < 0 {
s10ru = 0
} else if s10ru > 0xffff {
s10ru = 0xffff
}
if s10gu < 0 {
s10gu = 0
} else if s10gu > 0xffff {
s10gu = 0xffff
}
if s10bu < 0 {
s10bu = 0
} else if s10bu > 0xffff {
s10bu = 0xffff
}
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s01i := (sy1-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
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]) * 0x10101
s01cb1 := int(src.Cb[s01j]) - 128
s01cr1 := int(src.Cr[s01j]) - 128
s01ru := (s01yy1 + 91881*s01cr1) >> 8
s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
s01bu := (s01yy1 + 116130*s01cb1) >> 8
if s01ru < 0 {
s01ru = 0
} else if s01ru > 0xffff {
s01ru = 0xffff
}
if s01gu < 0 {
s01gu = 0
} else if s01gu > 0xffff {
s01gu = 0xffff
}
if s01bu < 0 {
s01bu = 0
} else if s01bu > 0xffff {
s01bu = 0xffff
}
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s11i := (sy1-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
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]) * 0x10101
s11cb1 := int(src.Cb[s11j]) - 128
s11cr1 := int(src.Cr[s11j]) - 128
s11ru := (s11yy1 + 91881*s11cr1) >> 8
s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
s11bu := (s11yy1 + 116130*s11cb1) >> 8
if s11ru < 0 {
s11ru = 0
} else if s11ru > 0xffff {
s11ru = 0xffff
}
if s11gu < 0 {
s11gu = 0
} else if s11gu > 0xffff {
s11gu = 0xffff
}
if s11bu < 0 {
s11bu = 0
} else if s11bu > 0xffff {
s11bu = 0xffff
}
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = 0xff
}
}
}
func (ablInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
sx1 := sx0 + 1
if sx0 < sr.Min.X {
sx0, sx1 = sr.Min.X, sr.Min.X
xFrac0, xFrac1 = 0, 1
} else if sx1 >= sr.Max.X {
sx0, sx1 = sr.Max.X-1, sr.Max.X-1
xFrac0, xFrac1 = 1, 0
}
sy -= 0.5
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
sy1 := sy0 + 1
if sy0 < sr.Min.Y {
sy0, sy1 = sr.Min.Y, sr.Min.Y
yFrac0, yFrac1 = 0, 1
} else if sy1 >= sr.Max.Y {
sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
yFrac0, yFrac1 = 1, 0
}
s00i := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
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]) * 0x10101
s00cb1 := int(src.Cb[s00j]) - 128
s00cr1 := int(src.Cr[s00j]) - 128
s00ru := (s00yy1 + 91881*s00cr1) >> 8
s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
s00bu := (s00yy1 + 116130*s00cb1) >> 8
if s00ru < 0 {
s00ru = 0
} else if s00ru > 0xffff {
s00ru = 0xffff
}
if s00gu < 0 {
s00gu = 0
} else if s00gu > 0xffff {
s00gu = 0xffff
}
if s00bu < 0 {
s00bu = 0
} else if s00bu > 0xffff {
s00bu = 0xffff
}
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s10i := (sy0-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
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]) * 0x10101
s10cb1 := int(src.Cb[s10j]) - 128
s10cr1 := int(src.Cr[s10j]) - 128
s10ru := (s10yy1 + 91881*s10cr1) >> 8
s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
s10bu := (s10yy1 + 116130*s10cb1) >> 8
if s10ru < 0 {
s10ru = 0
} else if s10ru > 0xffff {
s10ru = 0xffff
}
if s10gu < 0 {
s10gu = 0
} else if s10gu > 0xffff {
s10gu = 0xffff
}
if s10bu < 0 {
s10bu = 0
} else if s10bu > 0xffff {
s10bu = 0xffff
}
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s01i := (sy1-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
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]) * 0x10101
s01cb1 := int(src.Cb[s01j]) - 128
s01cr1 := int(src.Cr[s01j]) - 128
s01ru := (s01yy1 + 91881*s01cr1) >> 8
s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
s01bu := (s01yy1 + 116130*s01cb1) >> 8
if s01ru < 0 {
s01ru = 0
} else if s01ru > 0xffff {
s01ru = 0xffff
}
if s01gu < 0 {
s01gu = 0
} else if s01gu > 0xffff {
s01gu = 0xffff
}
if s01bu < 0 {
s01bu = 0
} else if s01bu > 0xffff {
s01bu = 0xffff
}
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s11i := (sy1-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
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]) * 0x10101
s11cb1 := int(src.Cb[s11j]) - 128
s11cr1 := int(src.Cr[s11j]) - 128
s11ru := (s11yy1 + 91881*s11cr1) >> 8
s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
s11bu := (s11yy1 + 116130*s11cb1) >> 8
if s11ru < 0 {
s11ru = 0
} else if s11ru > 0xffff {
s11ru = 0xffff
}
if s11gu < 0 {
s11gu = 0
} else if s11gu > 0xffff {
s11gu = 0xffff
}
if s11bu < 0 {
s11bu = 0
} else if s11bu > 0xffff {
s11bu = 0xffff
}
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = 0xff
}
}
}
func (ablInterpolator) transform_RGBA_RGBA64Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
sx1 := sx0 + 1
if sx0 < sr.Min.X {
sx0, sx1 = sr.Min.X, sr.Min.X
xFrac0, xFrac1 = 0, 1
} else if sx1 >= sr.Max.X {
sx0, sx1 = sr.Max.X-1, sr.Max.X-1
xFrac0, xFrac1 = 1, 0
}
sy -= 0.5
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
sy1 := sy0 + 1
if sy0 < sr.Min.Y {
sy0, sy1 = sr.Min.Y, sr.Min.Y
yFrac0, yFrac1 = 0, 1
} else if sy1 >= sr.Max.Y {
sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
yFrac0, yFrac1 = 1, 0
}
s00u := src.RGBA64At(sx0, sy0)
s00r := float64(s00u.R)
s00g := float64(s00u.G)
s00b := float64(s00u.B)
s00a := float64(s00u.A)
s10u := src.RGBA64At(sx1, sy0)
s10r := float64(s10u.R)
s10g := float64(s10u.G)
s10b := float64(s10u.B)
s10a := float64(s10u.A)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01u := src.RGBA64At(sx0, sy1)
s01r := float64(s01u.R)
s01g := float64(s01u.G)
s01b := float64(s01u.B)
s01a := float64(s01u.A)
s11u := src.RGBA64At(sx1, sy1)
s11r := float64(s11u.R)
s11g := float64(s11u.G)
s11b := float64(s11u.B)
s11a := float64(s11u.A)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)}
pa1 := (0xffff - uint32(p.A)) * 0x101
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + uint32(p.R)) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + uint32(p.G)) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + uint32(p.B)) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + uint32(p.A)) >> 8)
}
}
}
func (ablInterpolator) transform_RGBA_RGBA64Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
sx1 := sx0 + 1
if sx0 < sr.Min.X {
sx0, sx1 = sr.Min.X, sr.Min.X
xFrac0, xFrac1 = 0, 1
} else if sx1 >= sr.Max.X {
sx0, sx1 = sr.Max.X-1, sr.Max.X-1
xFrac0, xFrac1 = 1, 0
}
sy -= 0.5
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
sy1 := sy0 + 1
if sy0 < sr.Min.Y {
sy0, sy1 = sr.Min.Y, sr.Min.Y
yFrac0, yFrac1 = 0, 1
} else if sy1 >= sr.Max.Y {
sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
yFrac0, yFrac1 = 1, 0
}
s00u := src.RGBA64At(sx0, sy0)
s00r := float64(s00u.R)
s00g := float64(s00u.G)
s00b := float64(s00u.B)
s00a := float64(s00u.A)
s10u := src.RGBA64At(sx1, sy0)
s10r := float64(s10u.R)
s10g := float64(s10u.G)
s10b := float64(s10u.B)
s10a := float64(s10u.A)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01u := src.RGBA64At(sx0, sy1)
s01r := float64(s01u.R)
s01g := float64(s01u.G)
s01b := float64(s01u.B)
s01a := float64(s01u.A)
s11u := src.RGBA64At(sx1, sy1)
s11r := float64(s11u.R)
s11g := float64(s11u.G)
s11b := float64(s11u.B)
s11a := float64(s11u.A)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)}
dst.Pix[d+0] = uint8(p.R >> 8)
dst.Pix[d+1] = uint8(p.G >> 8)
dst.Pix[d+2] = uint8(p.B >> 8)
dst.Pix[d+3] = uint8(p.A >> 8)
}
}
}
func (ablInterpolator) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
sx1 := sx0 + 1
if sx0 < sr.Min.X {
sx0, sx1 = sr.Min.X, sr.Min.X
xFrac0, xFrac1 = 0, 1
} else if sx1 >= sr.Max.X {
sx0, sx1 = sr.Max.X-1, sr.Max.X-1
xFrac0, xFrac1 = 1, 0
}
sy -= 0.5
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
sy1 := sy0 + 1
if sy0 < sr.Min.Y {
sy0, sy1 = sr.Min.Y, sr.Min.Y
yFrac0, yFrac1 = 0, 1
} else if sy1 >= sr.Max.Y {
sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
yFrac0, yFrac1 = 1, 0
}
s00ru, s00gu, s00bu, s00au := src.At(sx0, sy0).RGBA()
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10ru, s10gu, s10bu, s10au := src.At(sx1, sy0).RGBA()
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10a := float64(s10au)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA()
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11ru, s11gu, s11bu, s11au := src.At(sx1, sy1).RGBA()
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11a := float64(s11au)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
pa := uint32(s11a)
pa1 := (0xffff - pa) * 0x101
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
}
}
}
func (ablInterpolator) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
sx1 := sx0 + 1
if sx0 < sr.Min.X {
sx0, sx1 = sr.Min.X, sr.Min.X
xFrac0, xFrac1 = 0, 1
} else if sx1 >= sr.Max.X {
sx0, sx1 = sr.Max.X-1, sr.Max.X-1
xFrac0, xFrac1 = 1, 0
}
sy -= 0.5
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
sy1 := sy0 + 1
if sy0 < sr.Min.Y {
sy0, sy1 = sr.Min.Y, sr.Min.Y
yFrac0, yFrac1 = 0, 1
} else if sy1 >= sr.Max.Y {
sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
yFrac0, yFrac1 = 1, 0
}
s00ru, s00gu, s00bu, s00au := src.At(sx0, sy0).RGBA()
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10ru, s10gu, s10bu, s10au := src.At(sx1, sy0).RGBA()
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10a := float64(s10au)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA()
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11ru, s11gu, s11bu, s11au := src.At(sx1, sy1).RGBA()
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11a := float64(s11au)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
pa := uint32(s11a)
dst.Pix[d+0] = uint8(pr >> 8)
dst.Pix[d+1] = uint8(pg >> 8)
dst.Pix[d+2] = uint8(pb >> 8)
dst.Pix[d+3] = uint8(pa >> 8)
}
}
}
func (ablInterpolator) transform_RGBA64Image_RGBA64Image_Over(dst RGBA64Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) {
srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := color.RGBA64{}
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
sx1 := sx0 + 1
if sx0 < sr.Min.X {
sx0, sx1 = sr.Min.X, sr.Min.X
xFrac0, xFrac1 = 0, 1
} else if sx1 >= sr.Max.X {
sx0, sx1 = sr.Max.X-1, sr.Max.X-1
xFrac0, xFrac1 = 1, 0
}
sy -= 0.5
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
sy1 := sy0 + 1
if sy0 < sr.Min.Y {
sy0, sy1 = sr.Min.Y, sr.Min.Y
yFrac0, yFrac1 = 0, 1
} else if sy1 >= sr.Max.Y {
sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
yFrac0, yFrac1 = 1, 0
}
s00u := src.RGBA64At(sx0, sy0)
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA()
s00u.R = uint16(uint32(s00u.R) * ma / 0xffff)
s00u.G = uint16(uint32(s00u.G) * ma / 0xffff)
s00u.B = uint16(uint32(s00u.B) * ma / 0xffff)
s00u.A = uint16(uint32(s00u.A) * ma / 0xffff)
}
s00r := float64(s00u.R)
s00g := float64(s00u.G)
s00b := float64(s00u.B)
s00a := float64(s00u.A)
s10u := src.RGBA64At(sx1, sy0)
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy0).RGBA()
s10u.R = uint16(uint32(s10u.R) * ma / 0xffff)
s10u.G = uint16(uint32(s10u.G) * ma / 0xffff)
s10u.B = uint16(uint32(s10u.B) * ma / 0xffff)
s10u.A = uint16(uint32(s10u.A) * ma / 0xffff)
}
s10r := float64(s10u.R)
s10g := float64(s10u.G)
s10b := float64(s10u.B)
s10a := float64(s10u.A)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01u := src.RGBA64At(sx0, sy1)
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy1).RGBA()
s01u.R = uint16(uint32(s01u.R) * ma / 0xffff)
s01u.G = uint16(uint32(s01u.G) * ma / 0xffff)
s01u.B = uint16(uint32(s01u.B) * ma / 0xffff)
s01u.A = uint16(uint32(s01u.A) * ma / 0xffff)
}
s01r := float64(s01u.R)
s01g := float64(s01u.G)
s01b := float64(s01u.B)
s01a := float64(s01u.A)
s11u := src.RGBA64At(sx1, sy1)
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy1).RGBA()
s11u.R = uint16(uint32(s11u.R) * ma / 0xffff)
s11u.G = uint16(uint32(s11u.G) * ma / 0xffff)
s11u.B = uint16(uint32(s11u.B) * ma / 0xffff)
s11u.A = uint16(uint32(s11u.A) * ma / 0xffff)
}
s11r := float64(s11u.R)
s11g := float64(s11u.G)
s11b := float64(s11u.B)
s11a := float64(s11u.A)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)}
q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy))
if dstMask != nil {
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
p.R = uint16(uint32(p.R) * ma / 0xffff)
p.G = uint16(uint32(p.G) * ma / 0xffff)
p.B = uint16(uint32(p.B) * ma / 0xffff)
p.A = uint16(uint32(p.A) * ma / 0xffff)
}
pa1 := 0xffff - uint32(p.A)
dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R))
dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G))
dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B))
dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A))
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64)
}
}
}
func (ablInterpolator) transform_RGBA64Image_RGBA64Image_Src(dst RGBA64Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) {
srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := color.RGBA64{}
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
sx1 := sx0 + 1
if sx0 < sr.Min.X {
sx0, sx1 = sr.Min.X, sr.Min.X
xFrac0, xFrac1 = 0, 1
} else if sx1 >= sr.Max.X {
sx0, sx1 = sr.Max.X-1, sr.Max.X-1
xFrac0, xFrac1 = 1, 0
}
sy -= 0.5
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
sy1 := sy0 + 1
if sy0 < sr.Min.Y {
sy0, sy1 = sr.Min.Y, sr.Min.Y
yFrac0, yFrac1 = 0, 1
} else if sy1 >= sr.Max.Y {
sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
yFrac0, yFrac1 = 1, 0
}
s00u := src.RGBA64At(sx0, sy0)
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA()
s00u.R = uint16(uint32(s00u.R) * ma / 0xffff)
s00u.G = uint16(uint32(s00u.G) * ma / 0xffff)
s00u.B = uint16(uint32(s00u.B) * ma / 0xffff)
s00u.A = uint16(uint32(s00u.A) * ma / 0xffff)
}
s00r := float64(s00u.R)
s00g := float64(s00u.G)
s00b := float64(s00u.B)
s00a := float64(s00u.A)
s10u := src.RGBA64At(sx1, sy0)
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy0).RGBA()
s10u.R = uint16(uint32(s10u.R) * ma / 0xffff)
s10u.G = uint16(uint32(s10u.G) * ma / 0xffff)
s10u.B = uint16(uint32(s10u.B) * ma / 0xffff)
s10u.A = uint16(uint32(s10u.A) * ma / 0xffff)
}
s10r := float64(s10u.R)
s10g := float64(s10u.G)
s10b := float64(s10u.B)
s10a := float64(s10u.A)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01u := src.RGBA64At(sx0, sy1)
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy1).RGBA()
s01u.R = uint16(uint32(s01u.R) * ma / 0xffff)
s01u.G = uint16(uint32(s01u.G) * ma / 0xffff)
s01u.B = uint16(uint32(s01u.B) * ma / 0xffff)
s01u.A = uint16(uint32(s01u.A) * ma / 0xffff)
}
s01r := float64(s01u.R)
s01g := float64(s01u.G)
s01b := float64(s01u.B)
s01a := float64(s01u.A)
s11u := src.RGBA64At(sx1, sy1)
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy1).RGBA()
s11u.R = uint16(uint32(s11u.R) * ma / 0xffff)
s11u.G = uint16(uint32(s11u.G) * ma / 0xffff)
s11u.B = uint16(uint32(s11u.B) * ma / 0xffff)
s11u.A = uint16(uint32(s11u.A) * ma / 0xffff)
}
s11r := float64(s11u.R)
s11g := float64(s11u.G)
s11b := float64(s11u.B)
s11a := float64(s11u.A)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)}
if dstMask != nil {
q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy))
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
p.R = uint16(uint32(p.R) * ma / 0xffff)
p.G = uint16(uint32(p.G) * ma / 0xffff)
p.B = uint16(uint32(p.B) * ma / 0xffff)
p.A = uint16(uint32(p.A) * ma / 0xffff)
pa1 := 0xffff - ma
dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R))
dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G))
dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B))
dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A))
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64)
} else {
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), p)
}
}
}
}
func (ablInterpolator) transform_Image_Image_Over(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
sx1 := sx0 + 1
if sx0 < sr.Min.X {
sx0, sx1 = sr.Min.X, sr.Min.X
xFrac0, xFrac1 = 0, 1
} else if sx1 >= sr.Max.X {
sx0, sx1 = sr.Max.X-1, sr.Max.X-1
xFrac0, xFrac1 = 1, 0
}
sy -= 0.5
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
sy1 := sy0 + 1
if sy0 < sr.Min.Y {
sy0, sy1 = sr.Min.Y, sr.Min.Y
yFrac0, yFrac1 = 0, 1
} else if sy1 >= sr.Max.Y {
sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
yFrac0, yFrac1 = 1, 0
}
s00ru, s00gu, s00bu, s00au := src.At(sx0, sy0).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA()
s00ru = s00ru * ma / 0xffff
s00gu = s00gu * ma / 0xffff
s00bu = s00bu * ma / 0xffff
s00au = s00au * ma / 0xffff
}
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10ru, s10gu, s10bu, s10au := src.At(sx1, sy0).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy0).RGBA()
s10ru = s10ru * ma / 0xffff
s10gu = s10gu * ma / 0xffff
s10bu = s10bu * ma / 0xffff
s10au = s10au * ma / 0xffff
}
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10a := float64(s10au)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy1).RGBA()
s01ru = s01ru * ma / 0xffff
s01gu = s01gu * ma / 0xffff
s01bu = s01bu * ma / 0xffff
s01au = s01au * ma / 0xffff
}
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11ru, s11gu, s11bu, s11au := src.At(sx1, sy1).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy1).RGBA()
s11ru = s11ru * ma / 0xffff
s11gu = s11gu * ma / 0xffff
s11bu = s11bu * ma / 0xffff
s11au = s11au * ma / 0xffff
}
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11a := float64(s11au)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
pa := uint32(s11a)
qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
if dstMask != nil {
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
pr = pr * ma / 0xffff
pg = pg * ma / 0xffff
pb = pb * ma / 0xffff
pa = pa * ma / 0xffff
}
pa1 := 0xffff - pa
dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
}
}
}
func (ablInterpolator) transform_Image_Image_Src(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
sx1 := sx0 + 1
if sx0 < sr.Min.X {
sx0, sx1 = sr.Min.X, sr.Min.X
xFrac0, xFrac1 = 0, 1
} else if sx1 >= sr.Max.X {
sx0, sx1 = sr.Max.X-1, sr.Max.X-1
xFrac0, xFrac1 = 1, 0
}
sy -= 0.5
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
sy1 := sy0 + 1
if sy0 < sr.Min.Y {
sy0, sy1 = sr.Min.Y, sr.Min.Y
yFrac0, yFrac1 = 0, 1
} else if sy1 >= sr.Max.Y {
sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
yFrac0, yFrac1 = 1, 0
}
s00ru, s00gu, s00bu, s00au := src.At(sx0, sy0).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA()
s00ru = s00ru * ma / 0xffff
s00gu = s00gu * ma / 0xffff
s00bu = s00bu * ma / 0xffff
s00au = s00au * ma / 0xffff
}
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10ru, s10gu, s10bu, s10au := src.At(sx1, sy0).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy0).RGBA()
s10ru = s10ru * ma / 0xffff
s10gu = s10gu * ma / 0xffff
s10bu = s10bu * ma / 0xffff
s10au = s10au * ma / 0xffff
}
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10a := float64(s10au)
s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r)
s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g)
s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b)
s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a)
s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy1).RGBA()
s01ru = s01ru * ma / 0xffff
s01gu = s01gu * ma / 0xffff
s01bu = s01bu * ma / 0xffff
s01au = s01au * ma / 0xffff
}
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11ru, s11gu, s11bu, s11au := src.At(sx1, sy1).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy1).RGBA()
s11ru = s11ru * ma / 0xffff
s11gu = s11gu * ma / 0xffff
s11bu = s11bu * ma / 0xffff
s11au = s11au * ma / 0xffff
}
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11a := float64(s11au)
s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r)
s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g)
s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b)
s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a)
s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r)
s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g)
s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b)
s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a)
pr := uint32(s11r)
pg := uint32(s11g)
pb := uint32(s11b)
pa := uint32(s11a)
if dstMask != nil {
qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
pr = pr * ma / 0xffff
pg = pg * ma / 0xffff
pb = pb * ma / 0xffff
pa = pa * ma / 0xffff
pa1 := 0xffff - ma
dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
} else {
dstColorRGBA64.R = uint16(pr)
dstColorRGBA64.G = uint16(pg)
dstColorRGBA64.B = uint16(pb)
dstColorRGBA64.A = uint16(pa)
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
}
}
}
}
func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
if z.dw != int32(dr.Dx()) || z.dh != int32(dr.Dy()) || z.sw != int32(sr.Dx()) || z.sh != int32(sr.Dy()) {
z.kernel.Scale(dst, dr, src, sr, op, opts)
return
}
var o Options
if opts != nil {
o = *opts
}
// adr is the affected destination pixels.
adr := dst.Bounds().Intersect(dr)
adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
if adr.Empty() || sr.Empty() {
return
}
// Make adr relative to dr.Min.
adr = adr.Sub(dr.Min)
if op == Over && o.SrcMask == nil && opaque(src) {
op = Src
}
if _, ok := src.(*image.Uniform); ok && o.DstMask == nil && o.SrcMask == nil && sr.In(src.Bounds()) {
Draw(dst, dr, src, src.Bounds().Min, op)
return
}
// Create a temporary buffer:
// scaleX distributes the source image's columns over the temporary image.
// scaleY distributes the temporary image's rows over the destination image.
var tmp [][4]float64
if z.pool.New != nil {
tmpp := z.pool.Get().(*[][4]float64)
defer z.pool.Put(tmpp)
tmp = *tmpp
} else {
tmp = z.makeTmpBuf()
}
// sr is the source pixels. If it extends beyond the src bounds,
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
//
// Similarly, the fast paths assume that the masks are nil.
if o.SrcMask != nil || !sr.In(src.Bounds()) {
z.scaleX_Image(tmp, src, sr, &o)
} else {
switch src := src.(type) {
case *image.Gray:
z.scaleX_Gray(tmp, src, sr, &o)
case *image.NRGBA:
z.scaleX_NRGBA(tmp, src, sr, &o)
case *image.RGBA:
z.scaleX_RGBA(tmp, src, sr, &o)
case *image.YCbCr:
switch src.SubsampleRatio {
default:
z.scaleX_Image(tmp, src, sr, &o)
case image.YCbCrSubsampleRatio444:
z.scaleX_YCbCr444(tmp, src, sr, &o)
case image.YCbCrSubsampleRatio422:
z.scaleX_YCbCr422(tmp, src, sr, &o)
case image.YCbCrSubsampleRatio420:
z.scaleX_YCbCr420(tmp, src, sr, &o)
case image.YCbCrSubsampleRatio440:
z.scaleX_YCbCr440(tmp, src, sr, &o)
}
case image.RGBA64Image:
z.scaleX_RGBA64Image(tmp, src, sr, &o)
default:
z.scaleX_Image(tmp, src, sr, &o)
}
}
if o.DstMask != nil {
switch op {
case Over:
z.scaleY_Image_Over(dst, dr, adr, tmp, &o)
case Src:
z.scaleY_Image_Src(dst, dr, adr, tmp, &o)
}
} else {
switch op {
case Over:
switch dst := dst.(type) {
case *image.RGBA:
z.scaleY_RGBA_Over(dst, dr, adr, tmp, &o)
case RGBA64Image:
z.scaleY_RGBA64Image_Over(dst, dr, adr, tmp, &o)
default:
z.scaleY_Image_Over(dst, dr, adr, tmp, &o)
}
case Src:
switch dst := dst.(type) {
case *image.RGBA:
z.scaleY_RGBA_Src(dst, dr, adr, tmp, &o)
case RGBA64Image:
z.scaleY_RGBA64Image_Src(dst, dr, adr, tmp, &o)
default:
z.scaleY_Image_Src(dst, dr, adr, tmp, &o)
}
}
}
}
func (q *Kernel) Transform(dst Image, s2d f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options) {
var o Options
if opts != nil {
o = *opts
}
dr := transformRect(&s2d, &sr)
// adr is the affected destination pixels.
adr := dst.Bounds().Intersect(dr)
adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
if adr.Empty() || sr.Empty() {
return
}
if op == Over && o.SrcMask == nil && opaque(src) {
op = Src
}
d2s := invert(&s2d)
// bias is a translation of the mapping from dst coordinates to src
// coordinates such that the latter temporarily have non-negative X
// and Y coordinates. This allows us to write int(f) instead of
// int(math.Floor(f)), since "round to zero" and "round down" are
// equivalent when f >= 0, but the former is much cheaper. The X--
// and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
// adjustment.
bias := transformRect(&d2s, &adr).Min
bias.X--
bias.Y--
d2s[2] -= float64(bias.X)
d2s[5] -= float64(bias.Y)
// Make adr relative to dr.Min.
adr = adr.Sub(dr.Min)
if u, ok := src.(*image.Uniform); ok && o.DstMask != nil && o.SrcMask != nil && sr.In(src.Bounds()) {
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
return
}
xscale := abs(d2s[0])
if s := abs(d2s[1]); xscale < s {
xscale = s
}
yscale := abs(d2s[3])
if s := abs(d2s[4]); yscale < s {
yscale = s
}
// sr is the source pixels. If it extends beyond the src bounds,
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
//
// Similarly, the fast paths assume that the masks are nil.
if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
switch op {
case Over:
q.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
case Src:
q.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
}
} else {
switch op {
case Over:
switch dst := dst.(type) {
case *image.RGBA:
switch src := src.(type) {
case *image.NRGBA:
q.transform_RGBA_NRGBA_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
case *image.RGBA:
q.transform_RGBA_RGBA_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
case image.RGBA64Image:
q.transform_RGBA_RGBA64Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
default:
q.transform_RGBA_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
}
case RGBA64Image:
switch src := src.(type) {
case image.RGBA64Image:
q.transform_RGBA64Image_RGBA64Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
}
default:
switch src := src.(type) {
default:
q.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
}
}
case Src:
switch dst := dst.(type) {
case *image.RGBA:
switch src := src.(type) {
case *image.Gray:
q.transform_RGBA_Gray_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
case *image.NRGBA:
q.transform_RGBA_NRGBA_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
case *image.RGBA:
q.transform_RGBA_RGBA_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
case *image.YCbCr:
switch src.SubsampleRatio {
default:
q.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
case image.YCbCrSubsampleRatio444:
q.transform_RGBA_YCbCr444_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
case image.YCbCrSubsampleRatio422:
q.transform_RGBA_YCbCr422_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
case image.YCbCrSubsampleRatio420:
q.transform_RGBA_YCbCr420_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
case image.YCbCrSubsampleRatio440:
q.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
}
case image.RGBA64Image:
q.transform_RGBA_RGBA64Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
default:
q.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
}
case RGBA64Image:
switch src := src.(type) {
case image.RGBA64Image:
q.transform_RGBA64Image_RGBA64Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
}
default:
switch src := src.(type) {
default:
q.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
}
}
}
}
}
func (z *kernelScaler) scaleX_Gray(tmp [][4]float64, src *image.Gray, sr image.Rectangle, opts *Options) {
t := 0
for y := int32(0); y < z.sh; y++ {
for _, s := range z.horizontal.sources {
var pr float64
for _, c := range z.horizontal.contribs[s.i:s.j] {
pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
pru := uint32(src.Pix[pi]) * 0x101
pr += float64(float64(pru) * c.weight)
}
pr *= s.invTotalWeightFFFF
tmp[t] = [4]float64{
pr,
pr,
pr,
1,
}
t++
}
}
}
func (z *kernelScaler) scaleX_NRGBA(tmp [][4]float64, src *image.NRGBA, sr image.Rectangle, opts *Options) {
t := 0
for y := int32(0); y < z.sh; y++ {
for _, s := range z.horizontal.sources {
var pr, pg, pb, pa float64
for _, c := range z.horizontal.contribs[s.i:s.j] {
pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(c.coord)-src.Rect.Min.X)*4
pau := uint32(src.Pix[pi+3]) * 0x101
pru := uint32(src.Pix[pi+0]) * pau / 0xff
pgu := uint32(src.Pix[pi+1]) * pau / 0xff
pbu := uint32(src.Pix[pi+2]) * pau / 0xff
pr += float64(float64(pru) * c.weight)
pg += float64(float64(pgu) * c.weight)
pb += float64(float64(pbu) * c.weight)
pa += float64(float64(pau) * c.weight)
}
tmp[t] = [4]float64{
pr * s.invTotalWeightFFFF,
pg * s.invTotalWeightFFFF,
pb * s.invTotalWeightFFFF,
pa * s.invTotalWeightFFFF,
}
t++
}
}
}
func (z *kernelScaler) scaleX_RGBA(tmp [][4]float64, src *image.RGBA, sr image.Rectangle, opts *Options) {
t := 0
for y := int32(0); y < z.sh; y++ {
for _, s := range z.horizontal.sources {
var pr, pg, pb, pa float64
for _, c := range z.horizontal.contribs[s.i:s.j] {
pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(c.coord)-src.Rect.Min.X)*4
pru := uint32(src.Pix[pi+0]) * 0x101
pgu := uint32(src.Pix[pi+1]) * 0x101
pbu := uint32(src.Pix[pi+2]) * 0x101
pau := uint32(src.Pix[pi+3]) * 0x101
pr += float64(float64(pru) * c.weight)
pg += float64(float64(pgu) * c.weight)
pb += float64(float64(pbu) * c.weight)
pa += float64(float64(pau) * c.weight)
}
tmp[t] = [4]float64{
pr * s.invTotalWeightFFFF,
pg * s.invTotalWeightFFFF,
pb * s.invTotalWeightFFFF,
pa * s.invTotalWeightFFFF,
}
t++
}
}
}
func (z *kernelScaler) scaleX_YCbCr444(tmp [][4]float64, src *image.YCbCr, sr image.Rectangle, opts *Options) {
t := 0
for y := int32(0); y < z.sh; y++ {
for _, s := range z.horizontal.sources {
var pr, pg, pb float64
for _, c := range z.horizontal.contribs[s.i:s.j] {
pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
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]) * 0x10101
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pru := (pyy1 + 91881*pcr1) >> 8
pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pbu := (pyy1 + 116130*pcb1) >> 8
if pru < 0 {
pru = 0
} else if pru > 0xffff {
pru = 0xffff
}
if pgu < 0 {
pgu = 0
} else if pgu > 0xffff {
pgu = 0xffff
}
if pbu < 0 {
pbu = 0
} else if pbu > 0xffff {
pbu = 0xffff
}
pr += float64(float64(pru) * c.weight)
pg += float64(float64(pgu) * c.weight)
pb += float64(float64(pbu) * c.weight)
}
tmp[t] = [4]float64{
pr * s.invTotalWeightFFFF,
pg * s.invTotalWeightFFFF,
pb * s.invTotalWeightFFFF,
1,
}
t++
}
}
}
func (z *kernelScaler) scaleX_YCbCr422(tmp [][4]float64, src *image.YCbCr, sr image.Rectangle, opts *Options) {
t := 0
for y := int32(0); y < z.sh; y++ {
for _, s := range z.horizontal.sources {
var pr, pg, pb float64
for _, c := range z.horizontal.contribs[s.i:s.j] {
pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
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]) * 0x10101
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pru := (pyy1 + 91881*pcr1) >> 8
pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pbu := (pyy1 + 116130*pcb1) >> 8
if pru < 0 {
pru = 0
} else if pru > 0xffff {
pru = 0xffff
}
if pgu < 0 {
pgu = 0
} else if pgu > 0xffff {
pgu = 0xffff
}
if pbu < 0 {
pbu = 0
} else if pbu > 0xffff {
pbu = 0xffff
}
pr += float64(float64(pru) * c.weight)
pg += float64(float64(pgu) * c.weight)
pb += float64(float64(pbu) * c.weight)
}
tmp[t] = [4]float64{
pr * s.invTotalWeightFFFF,
pg * s.invTotalWeightFFFF,
pb * s.invTotalWeightFFFF,
1,
}
t++
}
}
}
func (z *kernelScaler) scaleX_YCbCr420(tmp [][4]float64, src *image.YCbCr, sr image.Rectangle, opts *Options) {
t := 0
for y := int32(0); y < z.sh; y++ {
for _, s := range z.horizontal.sources {
var pr, pg, pb float64
for _, c := range z.horizontal.contribs[s.i:s.j] {
pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
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]) * 0x10101
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pru := (pyy1 + 91881*pcr1) >> 8
pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pbu := (pyy1 + 116130*pcb1) >> 8
if pru < 0 {
pru = 0
} else if pru > 0xffff {
pru = 0xffff
}
if pgu < 0 {
pgu = 0
} else if pgu > 0xffff {
pgu = 0xffff
}
if pbu < 0 {
pbu = 0
} else if pbu > 0xffff {
pbu = 0xffff
}
pr += float64(float64(pru) * c.weight)
pg += float64(float64(pgu) * c.weight)
pb += float64(float64(pbu) * c.weight)
}
tmp[t] = [4]float64{
pr * s.invTotalWeightFFFF,
pg * s.invTotalWeightFFFF,
pb * s.invTotalWeightFFFF,
1,
}
t++
}
}
}
func (z *kernelScaler) scaleX_YCbCr440(tmp [][4]float64, src *image.YCbCr, sr image.Rectangle, opts *Options) {
t := 0
for y := int32(0); y < z.sh; y++ {
for _, s := range z.horizontal.sources {
var pr, pg, pb float64
for _, c := range z.horizontal.contribs[s.i:s.j] {
pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
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]) * 0x10101
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pru := (pyy1 + 91881*pcr1) >> 8
pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pbu := (pyy1 + 116130*pcb1) >> 8
if pru < 0 {
pru = 0
} else if pru > 0xffff {
pru = 0xffff
}
if pgu < 0 {
pgu = 0
} else if pgu > 0xffff {
pgu = 0xffff
}
if pbu < 0 {
pbu = 0
} else if pbu > 0xffff {
pbu = 0xffff
}
pr += float64(float64(pru) * c.weight)
pg += float64(float64(pgu) * c.weight)
pb += float64(float64(pbu) * c.weight)
}
tmp[t] = [4]float64{
pr * s.invTotalWeightFFFF,
pg * s.invTotalWeightFFFF,
pb * s.invTotalWeightFFFF,
1,
}
t++
}
}
}
func (z *kernelScaler) scaleX_RGBA64Image(tmp [][4]float64, src image.RGBA64Image, sr image.Rectangle, opts *Options) {
t := 0
srcMask, smp := opts.SrcMask, opts.SrcMaskP
for y := int32(0); y < z.sh; y++ {
for _, s := range z.horizontal.sources {
var pr, pg, pb, pa float64
for _, c := range z.horizontal.contribs[s.i:s.j] {
pu := src.RGBA64At(sr.Min.X+int(c.coord), sr.Min.Y+int(y))
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(c.coord), smp.Y+sr.Min.Y+int(y)).RGBA()
pu.R = uint16(uint32(pu.R) * ma / 0xffff)
pu.G = uint16(uint32(pu.G) * ma / 0xffff)
pu.B = uint16(uint32(pu.B) * ma / 0xffff)
pu.A = uint16(uint32(pu.A) * ma / 0xffff)
}
pr += float64(float64(pu.R) * c.weight)
pg += float64(float64(pu.G) * c.weight)
pb += float64(float64(pu.B) * c.weight)
pa += float64(float64(pu.A) * c.weight)
}
tmp[t] = [4]float64{
pr * s.invTotalWeightFFFF,
pg * s.invTotalWeightFFFF,
pb * s.invTotalWeightFFFF,
pa * s.invTotalWeightFFFF,
}
t++
}
}
}
func (z *kernelScaler) scaleX_Image(tmp [][4]float64, src image.Image, sr image.Rectangle, opts *Options) {
t := 0
srcMask, smp := opts.SrcMask, opts.SrcMaskP
for y := int32(0); y < z.sh; y++ {
for _, s := range z.horizontal.sources {
var pr, pg, pb, pa float64
for _, c := range z.horizontal.contribs[s.i:s.j] {
pru, pgu, pbu, pau := src.At(sr.Min.X+int(c.coord), sr.Min.Y+int(y)).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(c.coord), smp.Y+sr.Min.Y+int(y)).RGBA()
pru = pru * ma / 0xffff
pgu = pgu * ma / 0xffff
pbu = pbu * ma / 0xffff
pau = pau * ma / 0xffff
}
pr += float64(float64(pru) * c.weight)
pg += float64(float64(pgu) * c.weight)
pb += float64(float64(pbu) * c.weight)
pa += float64(float64(pau) * c.weight)
}
tmp[t] = [4]float64{
pr * s.invTotalWeightFFFF,
pg * s.invTotalWeightFFFF,
pb * s.invTotalWeightFFFF,
pa * s.invTotalWeightFFFF,
}
t++
}
}
}
func (z *kernelScaler) scaleY_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) {
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
d := (dr.Min.Y+adr.Min.Y-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+int(dx)-dst.Rect.Min.X)*4
for _, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] {
var pr, pg, pb, pa float64
for _, c := range z.vertical.contribs[s.i:s.j] {
p := &tmp[c.coord*z.dw+dx]
pr += float64(p[0] * c.weight)
pg += float64(p[1] * c.weight)
pb += float64(p[2] * c.weight)
pa += float64(p[3] * c.weight)
}
if pr > pa {
pr = pa
}
if pg > pa {
pg = pa
}
if pb > pa {
pb = pa
}
pr0 := uint32(ftou(pr * s.invTotalWeight))
pg0 := uint32(ftou(pg * s.invTotalWeight))
pb0 := uint32(ftou(pb * s.invTotalWeight))
pa0 := uint32(ftou(pa * s.invTotalWeight))
pa1 := (0xffff - uint32(pa0)) * 0x101
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8)
d += dst.Stride
}
}
}
func (z *kernelScaler) scaleY_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) {
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
d := (dr.Min.Y+adr.Min.Y-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+int(dx)-dst.Rect.Min.X)*4
for _, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] {
var pr, pg, pb, pa float64
for _, c := range z.vertical.contribs[s.i:s.j] {
p := &tmp[c.coord*z.dw+dx]
pr += float64(p[0] * c.weight)
pg += float64(p[1] * c.weight)
pb += float64(p[2] * c.weight)
pa += float64(p[3] * c.weight)
}
if pr > pa {
pr = pa
}
if pg > pa {
pg = pa
}
if pb > pa {
pb = pa
}
dst.Pix[d+0] = uint8(ftou(pr*s.invTotalWeight) >> 8)
dst.Pix[d+1] = uint8(ftou(pg*s.invTotalWeight) >> 8)
dst.Pix[d+2] = uint8(ftou(pb*s.invTotalWeight) >> 8)
dst.Pix[d+3] = uint8(ftou(pa*s.invTotalWeight) >> 8)
d += dst.Stride
}
}
}
func (z *kernelScaler) scaleY_RGBA64Image_Over(dst RGBA64Image, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) {
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := color.RGBA64{}
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
for dy, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] {
var pr, pg, pb, pa float64
for _, c := range z.vertical.contribs[s.i:s.j] {
p := &tmp[c.coord*z.dw+dx]
pr += float64(p[0] * c.weight)
pg += float64(p[1] * c.weight)
pb += float64(p[2] * c.weight)
pa += float64(p[3] * c.weight)
}
if pr > pa {
pr = pa
}
if pg > pa {
pg = pa
}
if pb > pa {
pb = pa
}
q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy))
pr0 := uint32(ftou(pr * s.invTotalWeight))
pg0 := uint32(ftou(pg * s.invTotalWeight))
pb0 := uint32(ftou(pb * s.invTotalWeight))
pa0 := uint32(ftou(pa * s.invTotalWeight))
if dstMask != nil {
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(adr.Min.Y+dy)).RGBA()
pr0 = pr0 * ma / 0xffff
pg0 = pg0 * ma / 0xffff
pb0 = pb0 * ma / 0xffff
pa0 = pa0 * ma / 0xffff
}
pa1 := 0xffff - pa0
dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + pr0)
dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + pg0)
dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + pb0)
dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + pa0)
dst.SetRGBA64(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColorRGBA64)
}
}
}
func (z *kernelScaler) scaleY_RGBA64Image_Src(dst RGBA64Image, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) {
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := color.RGBA64{}
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
for dy, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] {
var pr, pg, pb, pa float64
for _, c := range z.vertical.contribs[s.i:s.j] {
p := &tmp[c.coord*z.dw+dx]
pr += float64(p[0] * c.weight)
pg += float64(p[1] * c.weight)
pb += float64(p[2] * c.weight)
pa += float64(p[3] * c.weight)
}
if pr > pa {
pr = pa
}
if pg > pa {
pg = pa
}
if pb > pa {
pb = pa
}
if dstMask != nil {
q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy))
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(adr.Min.Y+dy)).RGBA()
pr := uint32(ftou(pr*s.invTotalWeight)) * ma / 0xffff
pg := uint32(ftou(pg*s.invTotalWeight)) * ma / 0xffff
pb := uint32(ftou(pb*s.invTotalWeight)) * ma / 0xffff
pa := uint32(ftou(pa*s.invTotalWeight)) * ma / 0xffff
pa1 := 0xffff - ma
dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + pr)
dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + pg)
dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + pb)
dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + pa)
dst.SetRGBA64(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColorRGBA64)
} else {
dstColorRGBA64.R = ftou(pr * s.invTotalWeight)
dstColorRGBA64.G = ftou(pg * s.invTotalWeight)
dstColorRGBA64.B = ftou(pb * s.invTotalWeight)
dstColorRGBA64.A = ftou(pa * s.invTotalWeight)
dst.SetRGBA64(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColorRGBA64)
}
}
}
}
func (z *kernelScaler) scaleY_Image_Over(dst Image, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) {
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
for dy, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] {
var pr, pg, pb, pa float64
for _, c := range z.vertical.contribs[s.i:s.j] {
p := &tmp[c.coord*z.dw+dx]
pr += float64(p[0] * c.weight)
pg += float64(p[1] * c.weight)
pb += float64(p[2] * c.weight)
pa += float64(p[3] * c.weight)
}
if pr > pa {
pr = pa
}
if pg > pa {
pg = pa
}
if pb > pa {
pb = pa
}
qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy)).RGBA()
pr0 := uint32(ftou(pr * s.invTotalWeight))
pg0 := uint32(ftou(pg * s.invTotalWeight))
pb0 := uint32(ftou(pb * s.invTotalWeight))
pa0 := uint32(ftou(pa * s.invTotalWeight))
if dstMask != nil {
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(adr.Min.Y+dy)).RGBA()
pr0 = pr0 * ma / 0xffff
pg0 = pg0 * ma / 0xffff
pb0 = pb0 * ma / 0xffff
pa0 = pa0 * ma / 0xffff
}
pa1 := 0xffff - pa0
dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr0)
dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg0)
dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb0)
dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa0)
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColor)
}
}
}
func (z *kernelScaler) scaleY_Image_Src(dst Image, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) {
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
for dy, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] {
var pr, pg, pb, pa float64
for _, c := range z.vertical.contribs[s.i:s.j] {
p := &tmp[c.coord*z.dw+dx]
pr += float64(p[0] * c.weight)
pg += float64(p[1] * c.weight)
pb += float64(p[2] * c.weight)
pa += float64(p[3] * c.weight)
}
if pr > pa {
pr = pa
}
if pg > pa {
pg = pa
}
if pb > pa {
pb = pa
}
if dstMask != nil {
qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy)).RGBA()
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(adr.Min.Y+dy)).RGBA()
pr := uint32(ftou(pr*s.invTotalWeight)) * ma / 0xffff
pg := uint32(ftou(pg*s.invTotalWeight)) * ma / 0xffff
pb := uint32(ftou(pb*s.invTotalWeight)) * ma / 0xffff
pa := uint32(ftou(pa*s.invTotalWeight)) * ma / 0xffff
pa1 := 0xffff - ma
dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColor)
} else {
dstColorRGBA64.R = ftou(pr * s.invTotalWeight)
dstColorRGBA64.G = ftou(pg * s.invTotalWeight)
dstColorRGBA64.B = ftou(pb * s.invTotalWeight)
dstColorRGBA64.A = ftou(pa * s.invTotalWeight)
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColor)
}
}
}
}
func (q *Kernel) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
if xscale > 1 {
xHalfWidth *= xscale
xKernelArgScale = 1 / xscale
}
yHalfWidth, yKernelArgScale := q.Support, 1.0
if yscale > 1 {
yHalfWidth *= yscale
yKernelArgScale = 1 / yscale
}
xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
sx -= 0.5
ix := int(math.Floor(sx - xHalfWidth))
if ix < sr.Min.X {
ix = sr.Min.X
}
jx := int(math.Ceil(sx + xHalfWidth))
if jx > sr.Max.X {
jx = sr.Max.X
}
totalXWeight := 0.0
for kx := ix; kx < jx; kx++ {
xWeight := 0.0
if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
xWeight = q.At(t)
}
xWeights[kx-ix] = xWeight
totalXWeight += xWeight
}
for x := range xWeights[:jx-ix] {
xWeights[x] /= totalXWeight
}
sy += float64(bias.Y)
sy -= 0.5
iy := int(math.Floor(sy - yHalfWidth))
if iy < sr.Min.Y {
iy = sr.Min.Y
}
jy := int(math.Ceil(sy + yHalfWidth))
if jy > sr.Max.Y {
jy = sr.Max.Y
}
totalYWeight := 0.0
for ky := iy; ky < jy; ky++ {
yWeight := 0.0
if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
yWeight = q.At(t)
}
yWeights[ky-iy] = yWeight
totalYWeight += yWeight
}
for y := range yWeights[:jy-iy] {
yWeights[y] /= totalYWeight
}
var pr float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pi := (ky-src.Rect.Min.Y)*src.Stride + (kx - src.Rect.Min.X)
pru := uint32(src.Pix[pi]) * 0x101
pr += float64(float64(pru) * w)
}
}
}
}
out := uint8(fffftou(pr) >> 8)
dst.Pix[d+0] = out
dst.Pix[d+1] = out
dst.Pix[d+2] = out
dst.Pix[d+3] = 0xff
}
}
}
func (q *Kernel) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
if xscale > 1 {
xHalfWidth *= xscale
xKernelArgScale = 1 / xscale
}
yHalfWidth, yKernelArgScale := q.Support, 1.0
if yscale > 1 {
yHalfWidth *= yscale
yKernelArgScale = 1 / yscale
}
xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
sx -= 0.5
ix := int(math.Floor(sx - xHalfWidth))
if ix < sr.Min.X {
ix = sr.Min.X
}
jx := int(math.Ceil(sx + xHalfWidth))
if jx > sr.Max.X {
jx = sr.Max.X
}
totalXWeight := 0.0
for kx := ix; kx < jx; kx++ {
xWeight := 0.0
if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
xWeight = q.At(t)
}
xWeights[kx-ix] = xWeight
totalXWeight += xWeight
}
for x := range xWeights[:jx-ix] {
xWeights[x] /= totalXWeight
}
sy += float64(bias.Y)
sy -= 0.5
iy := int(math.Floor(sy - yHalfWidth))
if iy < sr.Min.Y {
iy = sr.Min.Y
}
jy := int(math.Ceil(sy + yHalfWidth))
if jy > sr.Max.Y {
jy = sr.Max.Y
}
totalYWeight := 0.0
for ky := iy; ky < jy; ky++ {
yWeight := 0.0
if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
yWeight = q.At(t)
}
yWeights[ky-iy] = yWeight
totalYWeight += yWeight
}
for y := range yWeights[:jy-iy] {
yWeights[y] /= totalYWeight
}
var pr, pg, pb, pa float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pi := (ky-src.Rect.Min.Y)*src.Stride + (kx-src.Rect.Min.X)*4
pau := uint32(src.Pix[pi+3]) * 0x101
pru := uint32(src.Pix[pi+0]) * pau / 0xff
pgu := uint32(src.Pix[pi+1]) * pau / 0xff
pbu := uint32(src.Pix[pi+2]) * pau / 0xff
pr += float64(float64(pru) * w)
pg += float64(float64(pgu) * w)
pb += float64(float64(pbu) * w)
pa += float64(float64(pau) * w)
}
}
}
}
if pr > pa {
pr = pa
}
if pg > pa {
pg = pa
}
if pb > pa {
pb = pa
}
pr0 := uint32(fffftou(pr))
pg0 := uint32(fffftou(pg))
pb0 := uint32(fffftou(pb))
pa0 := uint32(fffftou(pa))
pa1 := (0xffff - uint32(pa0)) * 0x101
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8)
}
}
}
func (q *Kernel) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
if xscale > 1 {
xHalfWidth *= xscale
xKernelArgScale = 1 / xscale
}
yHalfWidth, yKernelArgScale := q.Support, 1.0
if yscale > 1 {
yHalfWidth *= yscale
yKernelArgScale = 1 / yscale
}
xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
sx -= 0.5
ix := int(math.Floor(sx - xHalfWidth))
if ix < sr.Min.X {
ix = sr.Min.X
}
jx := int(math.Ceil(sx + xHalfWidth))
if jx > sr.Max.X {
jx = sr.Max.X
}
totalXWeight := 0.0
for kx := ix; kx < jx; kx++ {
xWeight := 0.0
if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
xWeight = q.At(t)
}
xWeights[kx-ix] = xWeight
totalXWeight += xWeight
}
for x := range xWeights[:jx-ix] {
xWeights[x] /= totalXWeight
}
sy += float64(bias.Y)
sy -= 0.5
iy := int(math.Floor(sy - yHalfWidth))
if iy < sr.Min.Y {
iy = sr.Min.Y
}
jy := int(math.Ceil(sy + yHalfWidth))
if jy > sr.Max.Y {
jy = sr.Max.Y
}
totalYWeight := 0.0
for ky := iy; ky < jy; ky++ {
yWeight := 0.0
if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
yWeight = q.At(t)
}
yWeights[ky-iy] = yWeight
totalYWeight += yWeight
}
for y := range yWeights[:jy-iy] {
yWeights[y] /= totalYWeight
}
var pr, pg, pb, pa float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pi := (ky-src.Rect.Min.Y)*src.Stride + (kx-src.Rect.Min.X)*4
pau := uint32(src.Pix[pi+3]) * 0x101
pru := uint32(src.Pix[pi+0]) * pau / 0xff
pgu := uint32(src.Pix[pi+1]) * pau / 0xff
pbu := uint32(src.Pix[pi+2]) * pau / 0xff
pr += float64(float64(pru) * w)
pg += float64(float64(pgu) * w)
pb += float64(float64(pbu) * w)
pa += float64(float64(pau) * w)
}
}
}
}
if pr > pa {
pr = pa
}
if pg > pa {
pg = pa
}
if pb > pa {
pb = pa
}
dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
dst.Pix[d+3] = uint8(fffftou(pa) >> 8)
}
}
}
func (q *Kernel) transform_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
if xscale > 1 {
xHalfWidth *= xscale
xKernelArgScale = 1 / xscale
}
yHalfWidth, yKernelArgScale := q.Support, 1.0
if yscale > 1 {
yHalfWidth *= yscale
yKernelArgScale = 1 / yscale
}
xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
sx -= 0.5
ix := int(math.Floor(sx - xHalfWidth))
if ix < sr.Min.X {
ix = sr.Min.X
}
jx := int(math.Ceil(sx + xHalfWidth))
if jx > sr.Max.X {
jx = sr.Max.X
}
totalXWeight := 0.0
for kx := ix; kx < jx; kx++ {
xWeight := 0.0
if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
xWeight = q.At(t)
}
xWeights[kx-ix] = xWeight
totalXWeight += xWeight
}
for x := range xWeights[:jx-ix] {
xWeights[x] /= totalXWeight
}
sy += float64(bias.Y)
sy -= 0.5
iy := int(math.Floor(sy - yHalfWidth))
if iy < sr.Min.Y {
iy = sr.Min.Y
}
jy := int(math.Ceil(sy + yHalfWidth))
if jy > sr.Max.Y {
jy = sr.Max.Y
}
totalYWeight := 0.0
for ky := iy; ky < jy; ky++ {
yWeight := 0.0
if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
yWeight = q.At(t)
}
yWeights[ky-iy] = yWeight
totalYWeight += yWeight
}
for y := range yWeights[:jy-iy] {
yWeights[y] /= totalYWeight
}
var pr, pg, pb, pa float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pi := (ky-src.Rect.Min.Y)*src.Stride + (kx-src.Rect.Min.X)*4
pru := uint32(src.Pix[pi+0]) * 0x101
pgu := uint32(src.Pix[pi+1]) * 0x101
pbu := uint32(src.Pix[pi+2]) * 0x101
pau := uint32(src.Pix[pi+3]) * 0x101
pr += float64(float64(pru) * w)
pg += float64(float64(pgu) * w)
pb += float64(float64(pbu) * w)
pa += float64(float64(pau) * w)
}
}
}
}
if pr > pa {
pr = pa
}
if pg > pa {
pg = pa
}
if pb > pa {
pb = pa
}
pr0 := uint32(fffftou(pr))
pg0 := uint32(fffftou(pg))
pb0 := uint32(fffftou(pb))
pa0 := uint32(fffftou(pa))
pa1 := (0xffff - uint32(pa0)) * 0x101
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8)
}
}
}
func (q *Kernel) transform_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
if xscale > 1 {
xHalfWidth *= xscale
xKernelArgScale = 1 / xscale
}
yHalfWidth, yKernelArgScale := q.Support, 1.0
if yscale > 1 {
yHalfWidth *= yscale
yKernelArgScale = 1 / yscale
}
xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
sx -= 0.5
ix := int(math.Floor(sx - xHalfWidth))
if ix < sr.Min.X {
ix = sr.Min.X
}
jx := int(math.Ceil(sx + xHalfWidth))
if jx > sr.Max.X {
jx = sr.Max.X
}
totalXWeight := 0.0
for kx := ix; kx < jx; kx++ {
xWeight := 0.0
if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
xWeight = q.At(t)
}
xWeights[kx-ix] = xWeight
totalXWeight += xWeight
}
for x := range xWeights[:jx-ix] {
xWeights[x] /= totalXWeight
}
sy += float64(bias.Y)
sy -= 0.5
iy := int(math.Floor(sy - yHalfWidth))
if iy < sr.Min.Y {
iy = sr.Min.Y
}
jy := int(math.Ceil(sy + yHalfWidth))
if jy > sr.Max.Y {
jy = sr.Max.Y
}
totalYWeight := 0.0
for ky := iy; ky < jy; ky++ {
yWeight := 0.0
if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
yWeight = q.At(t)
}
yWeights[ky-iy] = yWeight
totalYWeight += yWeight
}
for y := range yWeights[:jy-iy] {
yWeights[y] /= totalYWeight
}
var pr, pg, pb, pa float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pi := (ky-src.Rect.Min.Y)*src.Stride + (kx-src.Rect.Min.X)*4
pru := uint32(src.Pix[pi+0]) * 0x101
pgu := uint32(src.Pix[pi+1]) * 0x101
pbu := uint32(src.Pix[pi+2]) * 0x101
pau := uint32(src.Pix[pi+3]) * 0x101
pr += float64(float64(pru) * w)
pg += float64(float64(pgu) * w)
pb += float64(float64(pbu) * w)
pa += float64(float64(pau) * w)
}
}
}
}
if pr > pa {
pr = pa
}
if pg > pa {
pg = pa
}
if pb > pa {
pb = pa
}
dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
dst.Pix[d+3] = uint8(fffftou(pa) >> 8)
}
}
}
func (q *Kernel) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
if xscale > 1 {
xHalfWidth *= xscale
xKernelArgScale = 1 / xscale
}
yHalfWidth, yKernelArgScale := q.Support, 1.0
if yscale > 1 {
yHalfWidth *= yscale
yKernelArgScale = 1 / yscale
}
xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
sx -= 0.5
ix := int(math.Floor(sx - xHalfWidth))
if ix < sr.Min.X {
ix = sr.Min.X
}
jx := int(math.Ceil(sx + xHalfWidth))
if jx > sr.Max.X {
jx = sr.Max.X
}
totalXWeight := 0.0
for kx := ix; kx < jx; kx++ {
xWeight := 0.0
if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
xWeight = q.At(t)
}
xWeights[kx-ix] = xWeight
totalXWeight += xWeight
}
for x := range xWeights[:jx-ix] {
xWeights[x] /= totalXWeight
}
sy += float64(bias.Y)
sy -= 0.5
iy := int(math.Floor(sy - yHalfWidth))
if iy < sr.Min.Y {
iy = sr.Min.Y
}
jy := int(math.Ceil(sy + yHalfWidth))
if jy > sr.Max.Y {
jy = sr.Max.Y
}
totalYWeight := 0.0
for ky := iy; ky < jy; ky++ {
yWeight := 0.0
if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
yWeight = q.At(t)
}
yWeights[ky-iy] = yWeight
totalYWeight += yWeight
}
for y := range yWeights[:jy-iy] {
yWeights[y] /= totalYWeight
}
var pr, pg, pb float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X)
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]) * 0x10101
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pru := (pyy1 + 91881*pcr1) >> 8
pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pbu := (pyy1 + 116130*pcb1) >> 8
if pru < 0 {
pru = 0
} else if pru > 0xffff {
pru = 0xffff
}
if pgu < 0 {
pgu = 0
} else if pgu > 0xffff {
pgu = 0xffff
}
if pbu < 0 {
pbu = 0
} else if pbu > 0xffff {
pbu = 0xffff
}
pr += float64(float64(pru) * w)
pg += float64(float64(pgu) * w)
pb += float64(float64(pbu) * w)
}
}
}
}
dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
dst.Pix[d+3] = 0xff
}
}
}
func (q *Kernel) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
if xscale > 1 {
xHalfWidth *= xscale
xKernelArgScale = 1 / xscale
}
yHalfWidth, yKernelArgScale := q.Support, 1.0
if yscale > 1 {
yHalfWidth *= yscale
yKernelArgScale = 1 / yscale
}
xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
sx -= 0.5
ix := int(math.Floor(sx - xHalfWidth))
if ix < sr.Min.X {
ix = sr.Min.X
}
jx := int(math.Ceil(sx + xHalfWidth))
if jx > sr.Max.X {
jx = sr.Max.X
}
totalXWeight := 0.0
for kx := ix; kx < jx; kx++ {
xWeight := 0.0
if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
xWeight = q.At(t)
}
xWeights[kx-ix] = xWeight
totalXWeight += xWeight
}
for x := range xWeights[:jx-ix] {
xWeights[x] /= totalXWeight
}
sy += float64(bias.Y)
sy -= 0.5
iy := int(math.Floor(sy - yHalfWidth))
if iy < sr.Min.Y {
iy = sr.Min.Y
}
jy := int(math.Ceil(sy + yHalfWidth))
if jy > sr.Max.Y {
jy = sr.Max.Y
}
totalYWeight := 0.0
for ky := iy; ky < jy; ky++ {
yWeight := 0.0
if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
yWeight = q.At(t)
}
yWeights[ky-iy] = yWeight
totalYWeight += yWeight
}
for y := range yWeights[:jy-iy] {
yWeights[y] /= totalYWeight
}
var pr, pg, pb float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X)
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]) * 0x10101
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pru := (pyy1 + 91881*pcr1) >> 8
pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pbu := (pyy1 + 116130*pcb1) >> 8
if pru < 0 {
pru = 0
} else if pru > 0xffff {
pru = 0xffff
}
if pgu < 0 {
pgu = 0
} else if pgu > 0xffff {
pgu = 0xffff
}
if pbu < 0 {
pbu = 0
} else if pbu > 0xffff {
pbu = 0xffff
}
pr += float64(float64(pru) * w)
pg += float64(float64(pgu) * w)
pb += float64(float64(pbu) * w)
}
}
}
}
dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
dst.Pix[d+3] = 0xff
}
}
}
func (q *Kernel) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
if xscale > 1 {
xHalfWidth *= xscale
xKernelArgScale = 1 / xscale
}
yHalfWidth, yKernelArgScale := q.Support, 1.0
if yscale > 1 {
yHalfWidth *= yscale
yKernelArgScale = 1 / yscale
}
xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
sx -= 0.5
ix := int(math.Floor(sx - xHalfWidth))
if ix < sr.Min.X {
ix = sr.Min.X
}
jx := int(math.Ceil(sx + xHalfWidth))
if jx > sr.Max.X {
jx = sr.Max.X
}
totalXWeight := 0.0
for kx := ix; kx < jx; kx++ {
xWeight := 0.0
if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
xWeight = q.At(t)
}
xWeights[kx-ix] = xWeight
totalXWeight += xWeight
}
for x := range xWeights[:jx-ix] {
xWeights[x] /= totalXWeight
}
sy += float64(bias.Y)
sy -= 0.5
iy := int(math.Floor(sy - yHalfWidth))
if iy < sr.Min.Y {
iy = sr.Min.Y
}
jy := int(math.Ceil(sy + yHalfWidth))
if jy > sr.Max.Y {
jy = sr.Max.Y
}
totalYWeight := 0.0
for ky := iy; ky < jy; ky++ {
yWeight := 0.0
if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
yWeight = q.At(t)
}
yWeights[ky-iy] = yWeight
totalYWeight += yWeight
}
for y := range yWeights[:jy-iy] {
yWeights[y] /= totalYWeight
}
var pr, pg, pb float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X)
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]) * 0x10101
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pru := (pyy1 + 91881*pcr1) >> 8
pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pbu := (pyy1 + 116130*pcb1) >> 8
if pru < 0 {
pru = 0
} else if pru > 0xffff {
pru = 0xffff
}
if pgu < 0 {
pgu = 0
} else if pgu > 0xffff {
pgu = 0xffff
}
if pbu < 0 {
pbu = 0
} else if pbu > 0xffff {
pbu = 0xffff
}
pr += float64(float64(pru) * w)
pg += float64(float64(pgu) * w)
pb += float64(float64(pbu) * w)
}
}
}
}
dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
dst.Pix[d+3] = 0xff
}
}
}
func (q *Kernel) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
if xscale > 1 {
xHalfWidth *= xscale
xKernelArgScale = 1 / xscale
}
yHalfWidth, yKernelArgScale := q.Support, 1.0
if yscale > 1 {
yHalfWidth *= yscale
yKernelArgScale = 1 / yscale
}
xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
sx -= 0.5
ix := int(math.Floor(sx - xHalfWidth))
if ix < sr.Min.X {
ix = sr.Min.X
}
jx := int(math.Ceil(sx + xHalfWidth))
if jx > sr.Max.X {
jx = sr.Max.X
}
totalXWeight := 0.0
for kx := ix; kx < jx; kx++ {
xWeight := 0.0
if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
xWeight = q.At(t)
}
xWeights[kx-ix] = xWeight
totalXWeight += xWeight
}
for x := range xWeights[:jx-ix] {
xWeights[x] /= totalXWeight
}
sy += float64(bias.Y)
sy -= 0.5
iy := int(math.Floor(sy - yHalfWidth))
if iy < sr.Min.Y {
iy = sr.Min.Y
}
jy := int(math.Ceil(sy + yHalfWidth))
if jy > sr.Max.Y {
jy = sr.Max.Y
}
totalYWeight := 0.0
for ky := iy; ky < jy; ky++ {
yWeight := 0.0
if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
yWeight = q.At(t)
}
yWeights[ky-iy] = yWeight
totalYWeight += yWeight
}
for y := range yWeights[:jy-iy] {
yWeights[y] /= totalYWeight
}
var pr, pg, pb float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X)
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]) * 0x10101
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pru := (pyy1 + 91881*pcr1) >> 8
pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pbu := (pyy1 + 116130*pcb1) >> 8
if pru < 0 {
pru = 0
} else if pru > 0xffff {
pru = 0xffff
}
if pgu < 0 {
pgu = 0
} else if pgu > 0xffff {
pgu = 0xffff
}
if pbu < 0 {
pbu = 0
} else if pbu > 0xffff {
pbu = 0xffff
}
pr += float64(float64(pru) * w)
pg += float64(float64(pgu) * w)
pb += float64(float64(pbu) * w)
}
}
}
}
dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
dst.Pix[d+3] = 0xff
}
}
}
func (q *Kernel) transform_RGBA_RGBA64Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
if xscale > 1 {
xHalfWidth *= xscale
xKernelArgScale = 1 / xscale
}
yHalfWidth, yKernelArgScale := q.Support, 1.0
if yscale > 1 {
yHalfWidth *= yscale
yKernelArgScale = 1 / yscale
}
xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
sx -= 0.5
ix := int(math.Floor(sx - xHalfWidth))
if ix < sr.Min.X {
ix = sr.Min.X
}
jx := int(math.Ceil(sx + xHalfWidth))
if jx > sr.Max.X {
jx = sr.Max.X
}
totalXWeight := 0.0
for kx := ix; kx < jx; kx++ {
xWeight := 0.0
if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
xWeight = q.At(t)
}
xWeights[kx-ix] = xWeight
totalXWeight += xWeight
}
for x := range xWeights[:jx-ix] {
xWeights[x] /= totalXWeight
}
sy += float64(bias.Y)
sy -= 0.5
iy := int(math.Floor(sy - yHalfWidth))
if iy < sr.Min.Y {
iy = sr.Min.Y
}
jy := int(math.Ceil(sy + yHalfWidth))
if jy > sr.Max.Y {
jy = sr.Max.Y
}
totalYWeight := 0.0
for ky := iy; ky < jy; ky++ {
yWeight := 0.0
if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
yWeight = q.At(t)
}
yWeights[ky-iy] = yWeight
totalYWeight += yWeight
}
for y := range yWeights[:jy-iy] {
yWeights[y] /= totalYWeight
}
var pr, pg, pb, pa float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pu := src.RGBA64At(kx, ky)
pr += float64(float64(pu.R) * w)
pg += float64(float64(pu.G) * w)
pb += float64(float64(pu.B) * w)
pa += float64(float64(pu.A) * w)
}
}
}
}
if pr > pa {
pr = pa
}
if pg > pa {
pg = pa
}
if pb > pa {
pb = pa
}
pr0 := uint32(fffftou(pr))
pg0 := uint32(fffftou(pg))
pb0 := uint32(fffftou(pb))
pa0 := uint32(fffftou(pa))
pa1 := (0xffff - uint32(pa0)) * 0x101
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8)
}
}
}
func (q *Kernel) transform_RGBA_RGBA64Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
if xscale > 1 {
xHalfWidth *= xscale
xKernelArgScale = 1 / xscale
}
yHalfWidth, yKernelArgScale := q.Support, 1.0
if yscale > 1 {
yHalfWidth *= yscale
yKernelArgScale = 1 / yscale
}
xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
sx -= 0.5
ix := int(math.Floor(sx - xHalfWidth))
if ix < sr.Min.X {
ix = sr.Min.X
}
jx := int(math.Ceil(sx + xHalfWidth))
if jx > sr.Max.X {
jx = sr.Max.X
}
totalXWeight := 0.0
for kx := ix; kx < jx; kx++ {
xWeight := 0.0
if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
xWeight = q.At(t)
}
xWeights[kx-ix] = xWeight
totalXWeight += xWeight
}
for x := range xWeights[:jx-ix] {
xWeights[x] /= totalXWeight
}
sy += float64(bias.Y)
sy -= 0.5
iy := int(math.Floor(sy - yHalfWidth))
if iy < sr.Min.Y {
iy = sr.Min.Y
}
jy := int(math.Ceil(sy + yHalfWidth))
if jy > sr.Max.Y {
jy = sr.Max.Y
}
totalYWeight := 0.0
for ky := iy; ky < jy; ky++ {
yWeight := 0.0
if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
yWeight = q.At(t)
}
yWeights[ky-iy] = yWeight
totalYWeight += yWeight
}
for y := range yWeights[:jy-iy] {
yWeights[y] /= totalYWeight
}
var pr, pg, pb, pa float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pu := src.RGBA64At(kx, ky)
pr += float64(float64(pu.R) * w)
pg += float64(float64(pu.G) * w)
pb += float64(float64(pu.B) * w)
pa += float64(float64(pu.A) * w)
}
}
}
}
if pr > pa {
pr = pa
}
if pg > pa {
pg = pa
}
if pb > pa {
pb = pa
}
dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
dst.Pix[d+3] = uint8(fffftou(pa) >> 8)
}
}
}
func (q *Kernel) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
if xscale > 1 {
xHalfWidth *= xscale
xKernelArgScale = 1 / xscale
}
yHalfWidth, yKernelArgScale := q.Support, 1.0
if yscale > 1 {
yHalfWidth *= yscale
yKernelArgScale = 1 / yscale
}
xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
sx -= 0.5
ix := int(math.Floor(sx - xHalfWidth))
if ix < sr.Min.X {
ix = sr.Min.X
}
jx := int(math.Ceil(sx + xHalfWidth))
if jx > sr.Max.X {
jx = sr.Max.X
}
totalXWeight := 0.0
for kx := ix; kx < jx; kx++ {
xWeight := 0.0
if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
xWeight = q.At(t)
}
xWeights[kx-ix] = xWeight
totalXWeight += xWeight
}
for x := range xWeights[:jx-ix] {
xWeights[x] /= totalXWeight
}
sy += float64(bias.Y)
sy -= 0.5
iy := int(math.Floor(sy - yHalfWidth))
if iy < sr.Min.Y {
iy = sr.Min.Y
}
jy := int(math.Ceil(sy + yHalfWidth))
if jy > sr.Max.Y {
jy = sr.Max.Y
}
totalYWeight := 0.0
for ky := iy; ky < jy; ky++ {
yWeight := 0.0
if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
yWeight = q.At(t)
}
yWeights[ky-iy] = yWeight
totalYWeight += yWeight
}
for y := range yWeights[:jy-iy] {
yWeights[y] /= totalYWeight
}
var pr, pg, pb, pa float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pru, pgu, pbu, pau := src.At(kx, ky).RGBA()
pr += float64(float64(pru) * w)
pg += float64(float64(pgu) * w)
pb += float64(float64(pbu) * w)
pa += float64(float64(pau) * w)
}
}
}
}
if pr > pa {
pr = pa
}
if pg > pa {
pg = pa
}
if pb > pa {
pb = pa
}
pr0 := uint32(fffftou(pr))
pg0 := uint32(fffftou(pg))
pb0 := uint32(fffftou(pb))
pa0 := uint32(fffftou(pa))
pa1 := (0xffff - uint32(pa0)) * 0x101
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8)
}
}
}
func (q *Kernel) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
if xscale > 1 {
xHalfWidth *= xscale
xKernelArgScale = 1 / xscale
}
yHalfWidth, yKernelArgScale := q.Support, 1.0
if yscale > 1 {
yHalfWidth *= yscale
yKernelArgScale = 1 / yscale
}
xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
sx -= 0.5
ix := int(math.Floor(sx - xHalfWidth))
if ix < sr.Min.X {
ix = sr.Min.X
}
jx := int(math.Ceil(sx + xHalfWidth))
if jx > sr.Max.X {
jx = sr.Max.X
}
totalXWeight := 0.0
for kx := ix; kx < jx; kx++ {
xWeight := 0.0
if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
xWeight = q.At(t)
}
xWeights[kx-ix] = xWeight
totalXWeight += xWeight
}
for x := range xWeights[:jx-ix] {
xWeights[x] /= totalXWeight
}
sy += float64(bias.Y)
sy -= 0.5
iy := int(math.Floor(sy - yHalfWidth))
if iy < sr.Min.Y {
iy = sr.Min.Y
}
jy := int(math.Ceil(sy + yHalfWidth))
if jy > sr.Max.Y {
jy = sr.Max.Y
}
totalYWeight := 0.0
for ky := iy; ky < jy; ky++ {
yWeight := 0.0
if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
yWeight = q.At(t)
}
yWeights[ky-iy] = yWeight
totalYWeight += yWeight
}
for y := range yWeights[:jy-iy] {
yWeights[y] /= totalYWeight
}
var pr, pg, pb, pa float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pru, pgu, pbu, pau := src.At(kx, ky).RGBA()
pr += float64(float64(pru) * w)
pg += float64(float64(pgu) * w)
pb += float64(float64(pbu) * w)
pa += float64(float64(pau) * w)
}
}
}
}
if pr > pa {
pr = pa
}
if pg > pa {
pg = pa
}
if pb > pa {
pb = pa
}
dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
dst.Pix[d+3] = uint8(fffftou(pa) >> 8)
}
}
}
func (q *Kernel) transform_RGBA64Image_RGBA64Image_Over(dst RGBA64Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
if xscale > 1 {
xHalfWidth *= xscale
xKernelArgScale = 1 / xscale
}
yHalfWidth, yKernelArgScale := q.Support, 1.0
if yscale > 1 {
yHalfWidth *= yscale
yKernelArgScale = 1 / yscale
}
xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := color.RGBA64{}
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
sx -= 0.5
ix := int(math.Floor(sx - xHalfWidth))
if ix < sr.Min.X {
ix = sr.Min.X
}
jx := int(math.Ceil(sx + xHalfWidth))
if jx > sr.Max.X {
jx = sr.Max.X
}
totalXWeight := 0.0
for kx := ix; kx < jx; kx++ {
xWeight := 0.0
if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
xWeight = q.At(t)
}
xWeights[kx-ix] = xWeight
totalXWeight += xWeight
}
for x := range xWeights[:jx-ix] {
xWeights[x] /= totalXWeight
}
sy += float64(bias.Y)
sy -= 0.5
iy := int(math.Floor(sy - yHalfWidth))
if iy < sr.Min.Y {
iy = sr.Min.Y
}
jy := int(math.Ceil(sy + yHalfWidth))
if jy > sr.Max.Y {
jy = sr.Max.Y
}
totalYWeight := 0.0
for ky := iy; ky < jy; ky++ {
yWeight := 0.0
if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
yWeight = q.At(t)
}
yWeights[ky-iy] = yWeight
totalYWeight += yWeight
}
for y := range yWeights[:jy-iy] {
yWeights[y] /= totalYWeight
}
var pr, pg, pb, pa float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pu := src.RGBA64At(kx, ky)
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+kx, smp.Y+ky).RGBA()
pu.R = uint16(uint32(pu.R) * ma / 0xffff)
pu.G = uint16(uint32(pu.G) * ma / 0xffff)
pu.B = uint16(uint32(pu.B) * ma / 0xffff)
pu.A = uint16(uint32(pu.A) * ma / 0xffff)
}
pr += float64(float64(pu.R) * w)
pg += float64(float64(pu.G) * w)
pb += float64(float64(pu.B) * w)
pa += float64(float64(pu.A) * w)
}
}
}
}
if pr > pa {
pr = pa
}
if pg > pa {
pg = pa
}
if pb > pa {
pb = pa
}
q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy))
pr0 := uint32(fffftou(pr))
pg0 := uint32(fffftou(pg))
pb0 := uint32(fffftou(pb))
pa0 := uint32(fffftou(pa))
if dstMask != nil {
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
pr0 = pr0 * ma / 0xffff
pg0 = pg0 * ma / 0xffff
pb0 = pb0 * ma / 0xffff
pa0 = pa0 * ma / 0xffff
}
pa1 := 0xffff - pa0
dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + pr0)
dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + pg0)
dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + pb0)
dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + pa0)
dst.SetRGBA64(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64)
}
}
}
func (q *Kernel) transform_RGBA64Image_RGBA64Image_Src(dst RGBA64Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
if xscale > 1 {
xHalfWidth *= xscale
xKernelArgScale = 1 / xscale
}
yHalfWidth, yKernelArgScale := q.Support, 1.0
if yscale > 1 {
yHalfWidth *= yscale
yKernelArgScale = 1 / yscale
}
xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := color.RGBA64{}
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
sx -= 0.5
ix := int(math.Floor(sx - xHalfWidth))
if ix < sr.Min.X {
ix = sr.Min.X
}
jx := int(math.Ceil(sx + xHalfWidth))
if jx > sr.Max.X {
jx = sr.Max.X
}
totalXWeight := 0.0
for kx := ix; kx < jx; kx++ {
xWeight := 0.0
if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
xWeight = q.At(t)
}
xWeights[kx-ix] = xWeight
totalXWeight += xWeight
}
for x := range xWeights[:jx-ix] {
xWeights[x] /= totalXWeight
}
sy += float64(bias.Y)
sy -= 0.5
iy := int(math.Floor(sy - yHalfWidth))
if iy < sr.Min.Y {
iy = sr.Min.Y
}
jy := int(math.Ceil(sy + yHalfWidth))
if jy > sr.Max.Y {
jy = sr.Max.Y
}
totalYWeight := 0.0
for ky := iy; ky < jy; ky++ {
yWeight := 0.0
if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
yWeight = q.At(t)
}
yWeights[ky-iy] = yWeight
totalYWeight += yWeight
}
for y := range yWeights[:jy-iy] {
yWeights[y] /= totalYWeight
}
var pr, pg, pb, pa float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pu := src.RGBA64At(kx, ky)
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+kx, smp.Y+ky).RGBA()
pu.R = uint16(uint32(pu.R) * ma / 0xffff)
pu.G = uint16(uint32(pu.G) * ma / 0xffff)
pu.B = uint16(uint32(pu.B) * ma / 0xffff)
pu.A = uint16(uint32(pu.A) * ma / 0xffff)
}
pr += float64(float64(pu.R) * w)
pg += float64(float64(pu.G) * w)
pb += float64(float64(pu.B) * w)
pa += float64(float64(pu.A) * w)
}
}
}
}
if pr > pa {
pr = pa
}
if pg > pa {
pg = pa
}
if pb > pa {
pb = pa
}
if dstMask != nil {
q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy))
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
pr := uint32(fffftou(pr)) * ma / 0xffff
pg := uint32(fffftou(pg)) * ma / 0xffff
pb := uint32(fffftou(pb)) * ma / 0xffff
pa := uint32(fffftou(pa)) * ma / 0xffff
pa1 := 0xffff - ma
dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + pr)
dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + pg)
dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + pb)
dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + pa)
dst.SetRGBA64(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64)
} else {
dstColorRGBA64.R = fffftou(pr)
dstColorRGBA64.G = fffftou(pg)
dstColorRGBA64.B = fffftou(pb)
dstColorRGBA64.A = fffftou(pa)
dst.SetRGBA64(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64)
}
}
}
}
func (q *Kernel) transform_Image_Image_Over(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
if xscale > 1 {
xHalfWidth *= xscale
xKernelArgScale = 1 / xscale
}
yHalfWidth, yKernelArgScale := q.Support, 1.0
if yscale > 1 {
yHalfWidth *= yscale
yKernelArgScale = 1 / yscale
}
xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
sx -= 0.5
ix := int(math.Floor(sx - xHalfWidth))
if ix < sr.Min.X {
ix = sr.Min.X
}
jx := int(math.Ceil(sx + xHalfWidth))
if jx > sr.Max.X {
jx = sr.Max.X
}
totalXWeight := 0.0
for kx := ix; kx < jx; kx++ {
xWeight := 0.0
if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
xWeight = q.At(t)
}
xWeights[kx-ix] = xWeight
totalXWeight += xWeight
}
for x := range xWeights[:jx-ix] {
xWeights[x] /= totalXWeight
}
sy += float64(bias.Y)
sy -= 0.5
iy := int(math.Floor(sy - yHalfWidth))
if iy < sr.Min.Y {
iy = sr.Min.Y
}
jy := int(math.Ceil(sy + yHalfWidth))
if jy > sr.Max.Y {
jy = sr.Max.Y
}
totalYWeight := 0.0
for ky := iy; ky < jy; ky++ {
yWeight := 0.0
if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
yWeight = q.At(t)
}
yWeights[ky-iy] = yWeight
totalYWeight += yWeight
}
for y := range yWeights[:jy-iy] {
yWeights[y] /= totalYWeight
}
var pr, pg, pb, pa float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pru, pgu, pbu, pau := src.At(kx, ky).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+kx, smp.Y+ky).RGBA()
pru = pru * ma / 0xffff
pgu = pgu * ma / 0xffff
pbu = pbu * ma / 0xffff
pau = pau * ma / 0xffff
}
pr += float64(float64(pru) * w)
pg += float64(float64(pgu) * w)
pb += float64(float64(pbu) * w)
pa += float64(float64(pau) * w)
}
}
}
}
if pr > pa {
pr = pa
}
if pg > pa {
pg = pa
}
if pb > pa {
pb = pa
}
qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
pr0 := uint32(fffftou(pr))
pg0 := uint32(fffftou(pg))
pb0 := uint32(fffftou(pb))
pa0 := uint32(fffftou(pa))
if dstMask != nil {
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
pr0 = pr0 * ma / 0xffff
pg0 = pg0 * ma / 0xffff
pb0 = pb0 * ma / 0xffff
pa0 = pa0 * ma / 0xffff
}
pa1 := 0xffff - pa0
dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr0)
dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg0)
dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb0)
dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa0)
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
}
}
}
func (q *Kernel) transform_Image_Image_Src(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
if xscale > 1 {
xHalfWidth *= xscale
xKernelArgScale = 1 / xscale
}
yHalfWidth, yKernelArgScale := q.Support, 1.0
if yscale > 1 {
yHalfWidth *= yscale
yKernelArgScale = 1 / yscale
}
xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2]
sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
sx -= 0.5
ix := int(math.Floor(sx - xHalfWidth))
if ix < sr.Min.X {
ix = sr.Min.X
}
jx := int(math.Ceil(sx + xHalfWidth))
if jx > sr.Max.X {
jx = sr.Max.X
}
totalXWeight := 0.0
for kx := ix; kx < jx; kx++ {
xWeight := 0.0
if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
xWeight = q.At(t)
}
xWeights[kx-ix] = xWeight
totalXWeight += xWeight
}
for x := range xWeights[:jx-ix] {
xWeights[x] /= totalXWeight
}
sy += float64(bias.Y)
sy -= 0.5
iy := int(math.Floor(sy - yHalfWidth))
if iy < sr.Min.Y {
iy = sr.Min.Y
}
jy := int(math.Ceil(sy + yHalfWidth))
if jy > sr.Max.Y {
jy = sr.Max.Y
}
totalYWeight := 0.0
for ky := iy; ky < jy; ky++ {
yWeight := 0.0
if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
yWeight = q.At(t)
}
yWeights[ky-iy] = yWeight
totalYWeight += yWeight
}
for y := range yWeights[:jy-iy] {
yWeights[y] /= totalYWeight
}
var pr, pg, pb, pa float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pru, pgu, pbu, pau := src.At(kx, ky).RGBA()
if srcMask != nil {
_, _, _, ma := srcMask.At(smp.X+kx, smp.Y+ky).RGBA()
pru = pru * ma / 0xffff
pgu = pgu * ma / 0xffff
pbu = pbu * ma / 0xffff
pau = pau * ma / 0xffff
}
pr += float64(float64(pru) * w)
pg += float64(float64(pgu) * w)
pb += float64(float64(pbu) * w)
pa += float64(float64(pau) * w)
}
}
}
}
if pr > pa {
pr = pa
}
if pg > pa {
pg = pa
}
if pb > pa {
pb = pa
}
if dstMask != nil {
qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
pr := uint32(fffftou(pr)) * ma / 0xffff
pg := uint32(fffftou(pg)) * ma / 0xffff
pb := uint32(fffftou(pb)) * ma / 0xffff
pa := uint32(fffftou(pa)) * ma / 0xffff
pa1 := 0xffff - ma
dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
} else {
dstColorRGBA64.R = fffftou(pr)
dstColorRGBA64.G = fffftou(pg)
dstColorRGBA64.B = fffftou(pb)
dstColorRGBA64.A = fffftou(pa)
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
}
}
}
}
// 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.
//go:generate go run gen.go
package draw
import (
"image"
"image/color"
"math"
"sync"
"golang.org/x/image/math/f64"
)
// Copy copies the part of the source image defined by src and sr and writes
// the result of a Porter-Duff composition to the part of the destination image
// defined by dst and the translation of sr so that sr.Min translates to dp.
func Copy(dst Image, dp image.Point, src image.Image, sr image.Rectangle, op Op, opts *Options) {
var o Options
if opts != nil {
o = *opts
}
dr := sr.Add(dp.Sub(sr.Min))
if o.DstMask == nil {
DrawMask(dst, dr, src, sr.Min, o.SrcMask, o.SrcMaskP.Add(sr.Min), op)
} else {
NearestNeighbor.Scale(dst, dr, src, sr, op, opts)
}
}
// Scaler scales the part of the source image defined by src and sr and writes
// the result of a Porter-Duff composition to the part of the destination image
// defined by dst and dr.
//
// A Scaler is safe to use concurrently.
type Scaler interface {
Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options)
}
// Transformer transforms the part of the source image defined by src and sr
// and writes the result of a Porter-Duff composition to the part of the
// destination image defined by dst and the affine transform m applied to sr.
//
// For example, if m is the matrix
//
// m00 m01 m02
// m10 m11 m12
//
// then the src-space point (sx, sy) maps to the dst-space point
// (m00*sx + m01*sy + m02, m10*sx + m11*sy + m12).
//
// A Transformer is safe to use concurrently.
type Transformer interface {
Transform(dst Image, m f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options)
}
// Options are optional parameters to Copy, Scale and Transform.
//
// A nil *Options means to use the default (zero) values of each field.
type Options struct {
// Masks limit what parts of the dst image are drawn to and what parts of
// the src image are drawn from.
//
// A dst or src mask image having a zero alpha (transparent) pixel value in
// the respective coordinate space means that dst pixel is entirely
// unaffected or that src pixel is considered transparent black. A full
// alpha (opaque) value means that the dst pixel is maximally affected or
// the src pixel contributes maximally. The default values, nil, are
// equivalent to fully opaque, infinitely large mask images.
//
// The DstMask is otherwise known as a clip mask, and its pixels map 1:1 to
// the dst image's pixels. DstMaskP in DstMask space corresponds to
// image.Point{X:0, Y:0} in dst space. For example, when limiting
// repainting to a 'dirty rectangle', use that image.Rectangle and a zero
// image.Point as the DstMask and DstMaskP.
//
// The SrcMask's pixels map 1:1 to the src image's pixels. SrcMaskP in
// SrcMask space corresponds to image.Point{X:0, Y:0} in src space. For
// example, when drawing font glyphs in a uniform color, use an
// *image.Uniform as the src, and use the glyph atlas image and the
// per-glyph offset as SrcMask and SrcMaskP:
// Copy(dst, dp, image.NewUniform(color), image.Rect(0, 0, glyphWidth, glyphHeight), &Options{
// SrcMask: glyphAtlas,
// SrcMaskP: glyphOffset,
// })
DstMask image.Image
DstMaskP image.Point
SrcMask image.Image
SrcMaskP image.Point
// TODO: a smooth vs sharp edges option, for arbitrary rotations?
}
// Interpolator is an interpolation algorithm, when dst and src pixels don't
// have a 1:1 correspondence.
//
// Of the interpolators provided by this package:
// - NearestNeighbor is fast but usually looks worst.
// - CatmullRom is slow but usually looks best.
// - ApproxBiLinear has reasonable speed and quality.
//
// The time taken depends on the size of dr. For kernel interpolators, the
// speed also depends on the size of sr, and so are often slower than
// non-kernel interpolators, especially when scaling down.
type Interpolator interface {
Scaler
Transformer
}
// Kernel is an interpolator that blends source pixels weighted by a symmetric
// kernel function.
type Kernel struct {
// Support is the kernel support and must be >= 0. At(t) is assumed to be
// zero when t >= Support.
Support float64
// At is the kernel function. It will only be called with t in the
// range [0, Support).
At func(t float64) float64
}
// Scale implements the Scaler interface.
func (q *Kernel) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
q.newScaler(dr.Dx(), dr.Dy(), sr.Dx(), sr.Dy(), false).Scale(dst, dr, src, sr, op, opts)
}
// NewScaler returns a Scaler that is optimized for scaling multiple times with
// the same fixed destination and source width and height.
func (q *Kernel) NewScaler(dw, dh, sw, sh int) Scaler {
return q.newScaler(dw, dh, sw, sh, true)
}
func (q *Kernel) newScaler(dw, dh, sw, sh int, usePool bool) Scaler {
z := &kernelScaler{
kernel: q,
dw: int32(dw),
dh: int32(dh),
sw: int32(sw),
sh: int32(sh),
horizontal: newDistrib(q, int32(dw), int32(sw)),
vertical: newDistrib(q, int32(dh), int32(sh)),
}
if usePool {
z.pool.New = func() interface{} {
tmp := z.makeTmpBuf()
return &tmp
}
}
return z
}
var (
// NearestNeighbor is the nearest neighbor interpolator. It is very fast,
// but usually gives very low quality results. When scaling up, the result
// will look 'blocky'.
NearestNeighbor = Interpolator(nnInterpolator{})
// ApproxBiLinear is a mixture of the nearest neighbor and bi-linear
// interpolators. It is fast, but usually gives medium quality results.
//
// It implements bi-linear interpolation when upscaling and a bi-linear
// blend of the 4 nearest neighbor pixels when downscaling. This yields
// nicer quality than nearest neighbor interpolation when upscaling, but
// the time taken is independent of the number of source pixels, unlike the
// bi-linear interpolator. When downscaling a large image, the performance
// difference can be significant.
ApproxBiLinear = Interpolator(ablInterpolator{})
// BiLinear is the tent kernel. It is slow, but usually gives high quality
// results.
BiLinear = &Kernel{1, func(t float64) float64 {
return 1 - t
}}
// CatmullRom is the Catmull-Rom kernel. It is very slow, but usually gives
// very high quality results.
//
// It is an instance of the more general cubic BC-spline kernel with parameters
// B=0 and C=0.5. See Mitchell and Netravali, "Reconstruction Filters in
// Computer Graphics", Computer Graphics, Vol. 22, No. 4, pp. 221-228.
CatmullRom = &Kernel{2, func(t float64) float64 {
if t < 1 {
return float64((float64(1.5*t)-2.5)*t*t) + 1
}
return float64((float64(float64(float64(-0.5*t)+2.5)*t)-4)*t) + 2
}}
// TODO: a Kaiser-Bessel kernel?
)
type nnInterpolator struct{}
type ablInterpolator struct{}
type kernelScaler struct {
kernel *Kernel
dw, dh, sw, sh int32
horizontal, vertical distrib
pool sync.Pool
}
func (z *kernelScaler) makeTmpBuf() [][4]float64 {
return make([][4]float64, z.dw*z.sh)
}
// source is a range of contribs, their inverse total weight, and that ITW
// divided by 0xffff.
type source struct {
i, j int32
invTotalWeight float64
invTotalWeightFFFF float64
}
// contrib is the weight of a column or row.
type contrib struct {
coord int32
weight float64
}
// distrib measures how source pixels are distributed over destination pixels.
type distrib struct {
// sources are what contribs each column or row in the source image owns,
// and the total weight of those contribs.
sources []source
// contribs are the contributions indexed by sources[s].i and sources[s].j.
contribs []contrib
}
// newDistrib returns a distrib that distributes sw source columns (or rows)
// over dw destination columns (or rows).
func newDistrib(q *Kernel, dw, sw int32) distrib {
scale := float64(sw) / float64(dw)
halfWidth, kernelArgScale := q.Support, 1.0
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
if scale > 1 {
halfWidth *= scale
kernelArgScale = 1 / scale
}
// Make the sources slice, one source for each column or row, and temporarily
// appropriate its elements' fields so that invTotalWeight is the scaled
// coordinate of the source column or row, and i and j are the lower and
// upper bounds of the range of destination columns or rows affected by the
// source column or row.
n, sources := int32(0), make([]source, dw)
for x := range sources {
center := float64((float64(x)+0.5)*scale) - 0.5
i := int32(math.Floor(center - halfWidth))
if i < 0 {
i = 0
}
j := int32(math.Ceil(center + halfWidth))
if j > sw {
j = sw
if j < i {
j = i
}
}
sources[x] = source{i: i, j: j, invTotalWeight: center}
n += j - i
}
contribs := make([]contrib, 0, n)
for k, b := range sources {
totalWeight := 0.0
l := int32(len(contribs))
for coord := b.i; coord < b.j; coord++ {
t := abs((b.invTotalWeight - float64(coord)) * kernelArgScale)
if t >= q.Support {
continue
}
weight := q.At(t)
if weight == 0 {
continue
}
totalWeight += weight
contribs = append(contribs, contrib{coord, weight})
}
totalWeight = 1 / totalWeight
sources[k] = source{
i: l,
j: int32(len(contribs)),
invTotalWeight: totalWeight,
invTotalWeightFFFF: totalWeight / 0xffff,
}
}
return distrib{sources, contribs}
}
// abs is like math.Abs, but it doesn't care about negative zero, infinities or
// NaNs.
func abs(f float64) float64 {
if f < 0 {
f = -f
}
return f
}
// ftou converts the range [0.0, 1.0] to [0, 0xffff].
func ftou(f float64) uint16 {
i := int32(float64(0xffff*f) + 0.5)
if i > 0xffff {
return 0xffff
}
if i > 0 {
return uint16(i)
}
return 0
}
// fffftou converts the range [0.0, 65535.0] to [0, 0xffff].
func fffftou(f float64) uint16 {
i := int32(f + 0.5)
if i > 0xffff {
return 0xffff
}
if i > 0 {
return uint16(i)
}
return 0
}
// invert returns the inverse of m.
//
// TODO: move this into the f64 package, once we work out the convention for
// matrix methods in that package: do they modify the receiver, take a dst
// pointer argument, or return a new value?
func invert(m *f64.Aff3) f64.Aff3 {
m00 := +m[3*1+1]
m01 := -m[3*0+1]
m02 := +float64(m[3*1+2]*m[3*0+1]) - float64(m[3*1+1]*m[3*0+2])
m10 := -m[3*1+0]
m11 := +m[3*0+0]
m12 := +float64(m[3*1+0]*m[3*0+2]) - float64(m[3*1+2]*m[3*0+0])
det := float64(m00*m11) - float64(m10*m01)
return f64.Aff3{
m00 / det,
m01 / det,
m02 / det,
m10 / det,
m11 / det,
m12 / det,
}
}
func matMul(p, q *f64.Aff3) f64.Aff3 {
return f64.Aff3{
float64(p[3*0+0]*q[3*0+0]) + float64(p[3*0+1]*q[3*1+0]),
float64(p[3*0+0]*q[3*0+1]) + float64(p[3*0+1]*q[3*1+1]),
float64(p[3*0+0]*q[3*0+2]) + float64(p[3*0+1]*q[3*1+2]) + p[3*0+2],
float64(p[3*1+0]*q[3*0+0]) + float64(p[3*1+1]*q[3*1+0]),
float64(p[3*1+0]*q[3*0+1]) + float64(p[3*1+1]*q[3*1+1]),
float64(p[3*1+0]*q[3*0+2]) + float64(p[3*1+1]*q[3*1+2]) + p[3*1+2],
}
}
// transformRect returns a rectangle dr that contains sr transformed by s2d.
func transformRect(s2d *f64.Aff3, sr *image.Rectangle) (dr image.Rectangle) {
ps := [...]image.Point{
{sr.Min.X, sr.Min.Y},
{sr.Max.X, sr.Min.Y},
{sr.Min.X, sr.Max.Y},
{sr.Max.X, sr.Max.Y},
}
for i, p := range ps {
sxf := float64(p.X)
syf := float64(p.Y)
dx := int(math.Floor(float64(s2d[0]*sxf) + float64(s2d[1]*syf) + s2d[2]))
dy := int(math.Floor(float64(s2d[3]*sxf) + float64(s2d[4]*syf) + s2d[5]))
// The +1 adjustments below are because an image.Rectangle is inclusive
// on the low end but exclusive on the high end.
if i == 0 {
dr = image.Rectangle{
Min: image.Point{dx + 0, dy + 0},
Max: image.Point{dx + 1, dy + 1},
}
continue
}
if dr.Min.X > dx {
dr.Min.X = dx
}
dx++
if dr.Max.X < dx {
dr.Max.X = dx
}
if dr.Min.Y > dy {
dr.Min.Y = dy
}
dy++
if dr.Max.Y < dy {
dr.Max.Y = dy
}
}
return dr
}
func clipAffectedDestRect(adr image.Rectangle, dstMask image.Image, dstMaskP image.Point) (image.Rectangle, image.Image) {
if dstMask == nil {
return adr, nil
}
if r, ok := dstMask.(image.Rectangle); ok {
return adr.Intersect(r.Sub(dstMaskP)), nil
}
// TODO: clip to dstMask.Bounds() if the color model implies that out-of-bounds means 0 alpha?
return adr, dstMask
}
func transform_Uniform(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Uniform, sr image.Rectangle, bias image.Point, op Op) {
switch op {
case Over:
switch dst := dst.(type) {
case *image.RGBA:
pr, pg, pb, pa := src.C.RGBA()
pa1 := (0xffff - pa) * 0x101
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X
sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
}
}
default:
pr, pg, pb, pa := src.C.RGBA()
pa1 := 0xffff - pa
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X
sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
}
}
}
case Src:
switch dst := dst.(type) {
case *image.RGBA:
pr, pg, pb, pa := src.C.RGBA()
pr8 := uint8(pr >> 8)
pg8 := uint8(pg >> 8)
pb8 := uint8(pb >> 8)
pa8 := uint8(pa >> 8)
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X
sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
dst.Pix[d+0] = pr8
dst.Pix[d+1] = pg8
dst.Pix[d+2] = pb8
dst.Pix[d+3] = pa8
}
}
default:
pr, pg, pb, pa := src.C.RGBA()
dstColorRGBA64 := &color.RGBA64{
uint16(pr),
uint16(pg),
uint16(pb),
uint16(pa),
}
dstColor := color.Color(dstColorRGBA64)
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
dxf := float64(dr.Min.X+int(dx)) + 0.5
sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X
sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
}
}
}
}
}
func opaque(m image.Image) bool {
o, ok := m.(interface {
Opaque() bool
})
return ok && o.Opaque()
}
// 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.
// Package font defines an interface for font faces, for drawing text on an
// image.
//
// Other packages provide font face implementations. For example, a truetype
// package would provide one based on .ttf font files.
package font // import "golang.org/x/image/font"
import (
"image"
"image/draw"
"io"
"unicode/utf8"
"golang.org/x/image/math/fixed"
)
// TODO: who is responsible for caches (glyph images, glyph indices, kerns)?
// The Drawer or the Face?
// Face is a font face. Its glyphs are often derived from a font file, such as
// "Comic_Sans_MS.ttf", but a face has a specific size, style, weight and
// hinting. For example, the 12pt and 18pt versions of Comic Sans are two
// different faces, even if derived from the same font file.
//
// A Face is not safe for concurrent use by multiple goroutines, as its methods
// may re-use implementation-specific caches and mask image buffers.
//
// To create a Face, look to other packages that implement specific font file
// formats.
type Face interface {
io.Closer
// Glyph returns the draw.DrawMask parameters (dr, mask, maskp) to draw r's
// glyph at the sub-pixel destination location dot, and that glyph's
// advance width.
//
// It returns !ok if the face does not contain a glyph for r. This includes
// returning !ok for a fallback glyph (such as substituting a U+FFFD glyph
// or OpenType's .notdef glyph), in which case the other return values may
// still be non-zero.
//
// The contents of the mask image returned by one Glyph call may change
// after the next Glyph call. Callers that want to cache the mask must make
// a copy.
Glyph(dot fixed.Point26_6, r rune) (
dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool)
// GlyphBounds returns the bounding box of r's glyph, drawn at a dot equal
// to the origin, and that glyph's advance width.
//
// It returns !ok if the face does not contain a glyph for r. This includes
// returning !ok for a fallback glyph (such as substituting a U+FFFD glyph
// or OpenType's .notdef glyph), in which case the other return values may
// still be non-zero.
//
// The glyph's ascent and descent are equal to -bounds.Min.Y and
// +bounds.Max.Y. The glyph's left-side and right-side bearings are equal
// to bounds.Min.X and advance-bounds.Max.X. A visual depiction of what
// these metrics are is at
// https://developer.apple.com/library/archive/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyphterms_2x.png
GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool)
// GlyphAdvance returns the advance width of r's glyph.
//
// It returns !ok if the face does not contain a glyph for r. This includes
// returning !ok for a fallback glyph (such as substituting a U+FFFD glyph
// or OpenType's .notdef glyph), in which case the other return values may
// still be non-zero.
GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool)
// Kern returns the horizontal adjustment for the kerning pair (r0, r1). A
// positive kern means to move the glyphs further apart.
Kern(r0, r1 rune) fixed.Int26_6
// Metrics returns the metrics for this Face.
Metrics() Metrics
// TODO: ColoredGlyph for various emoji?
// TODO: Ligatures? Shaping?
}
// Metrics holds the metrics for a Face. A visual depiction is at
// https://developer.apple.com/library/mac/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyph_metrics_2x.png
type Metrics struct {
// Height is the recommended amount of vertical space between two lines of
// text.
Height fixed.Int26_6
// Ascent is the distance from the top of a line to its baseline.
Ascent fixed.Int26_6
// Descent is the distance from the bottom of a line to its baseline. The
// value is typically positive, even though a descender goes below the
// baseline.
Descent fixed.Int26_6
// XHeight is the distance from the top of non-ascending lowercase letters
// to the baseline.
XHeight fixed.Int26_6
// CapHeight is the distance from the top of uppercase letters to the
// baseline.
CapHeight fixed.Int26_6
// CaretSlope is the slope of a caret as a vector with the Y axis pointing up.
// The slope {0, 1} is the vertical caret.
CaretSlope image.Point
}
// Drawer draws text on a destination image.
//
// A Drawer is not safe for concurrent use by multiple goroutines, since its
// Face is not.
type Drawer struct {
// Dst is the destination image.
Dst draw.Image
// Src is the source image.
Src image.Image
// Face provides the glyph mask images.
Face Face
// Dot is the baseline location to draw the next glyph. The majority of the
// affected pixels will be above and to the right of the dot, but some may
// be below or to the left. For example, drawing a 'j' in an italic face
// may affect pixels below and to the left of the dot.
Dot fixed.Point26_6
// TODO: Clip image.Image?
// TODO: SrcP image.Point for Src images other than *image.Uniform? How
// does it get updated during DrawString?
}
// TODO: should DrawString return the last rune drawn, so the next DrawString
// call can kern beforehand? Or should that be the responsibility of the caller
// if they really want to do that, since they have to explicitly shift d.Dot
// anyway? What if ligatures span more than two runes? What if grapheme
// clusters span multiple runes?
//
// TODO: do we assume that the input is in any particular Unicode Normalization
// Form?
//
// TODO: have DrawRunes(s []rune)? DrawRuneReader(io.RuneReader)?? If we take
// io.RuneReader, we can't assume that we can rewind the stream.
//
// TODO: how does this work with line breaking: drawing text up until a
// vertical line? Should DrawString return the number of runes drawn?
// DrawBytes draws s at the dot and advances the dot's location.
//
// It is equivalent to DrawString(string(s)) but may be more efficient.
func (d *Drawer) DrawBytes(s []byte) {
prevC := rune(-1)
for len(s) > 0 {
c, size := utf8.DecodeRune(s)
s = s[size:]
if prevC >= 0 {
d.Dot.X += d.Face.Kern(prevC, c)
}
dr, mask, maskp, advance, _ := d.Face.Glyph(d.Dot, c)
if !dr.Empty() {
draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over)
}
d.Dot.X += advance
prevC = c
}
}
// DrawString draws s at the dot and advances the dot's location.
func (d *Drawer) DrawString(s string) {
prevC := rune(-1)
for _, c := range s {
if prevC >= 0 {
d.Dot.X += d.Face.Kern(prevC, c)
}
dr, mask, maskp, advance, _ := d.Face.Glyph(d.Dot, c)
if !dr.Empty() {
draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over)
}
d.Dot.X += advance
prevC = c
}
}
// BoundBytes returns the bounding box of s, drawn at the drawer dot, as well as
// the advance.
//
// It is equivalent to BoundBytes(string(s)) but may be more efficient.
func (d *Drawer) BoundBytes(s []byte) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
bounds, advance = BoundBytes(d.Face, s)
bounds.Min = bounds.Min.Add(d.Dot)
bounds.Max = bounds.Max.Add(d.Dot)
return
}
// BoundString returns the bounding box of s, drawn at the drawer dot, as well
// as the advance.
func (d *Drawer) BoundString(s string) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
bounds, advance = BoundString(d.Face, s)
bounds.Min = bounds.Min.Add(d.Dot)
bounds.Max = bounds.Max.Add(d.Dot)
return
}
// MeasureBytes returns how far dot would advance by drawing s.
//
// It is equivalent to MeasureString(string(s)) but may be more efficient.
func (d *Drawer) MeasureBytes(s []byte) (advance fixed.Int26_6) {
return MeasureBytes(d.Face, s)
}
// MeasureString returns how far dot would advance by drawing s.
func (d *Drawer) MeasureString(s string) (advance fixed.Int26_6) {
return MeasureString(d.Face, s)
}
// BoundBytes returns the bounding box of s with f, drawn at a dot equal to the
// origin, as well as the advance.
//
// It is equivalent to BoundString(string(s)) but may be more efficient.
func BoundBytes(f Face, s []byte) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
prevC := rune(-1)
for len(s) > 0 {
c, size := utf8.DecodeRune(s)
s = s[size:]
if prevC >= 0 {
advance += f.Kern(prevC, c)
}
b, a, _ := f.GlyphBounds(c)
if !b.Empty() {
b.Min.X += advance
b.Max.X += advance
bounds = bounds.Union(b)
}
advance += a
prevC = c
}
return
}
// BoundString returns the bounding box of s with f, drawn at a dot equal to the
// origin, as well as the advance.
func BoundString(f Face, s string) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
prevC := rune(-1)
for _, c := range s {
if prevC >= 0 {
advance += f.Kern(prevC, c)
}
b, a, _ := f.GlyphBounds(c)
if !b.Empty() {
b.Min.X += advance
b.Max.X += advance
bounds = bounds.Union(b)
}
advance += a
prevC = c
}
return
}
// MeasureBytes returns how far dot would advance by drawing s with f.
//
// It is equivalent to MeasureString(string(s)) but may be more efficient.
func MeasureBytes(f Face, s []byte) (advance fixed.Int26_6) {
prevC := rune(-1)
for len(s) > 0 {
c, size := utf8.DecodeRune(s)
s = s[size:]
if prevC >= 0 {
advance += f.Kern(prevC, c)
}
a, _ := f.GlyphAdvance(c)
advance += a
prevC = c
}
return advance
}
// MeasureString returns how far dot would advance by drawing s with f.
func MeasureString(f Face, s string) (advance fixed.Int26_6) {
prevC := rune(-1)
for _, c := range s {
if prevC >= 0 {
advance += f.Kern(prevC, c)
}
a, _ := f.GlyphAdvance(c)
advance += a
prevC = c
}
return advance
}
// Hinting selects how to quantize a vector font's glyph nodes.
//
// Not all fonts support hinting.
type Hinting int
const (
HintingNone Hinting = iota
HintingVertical
HintingFull
)
// Stretch selects a normal, condensed, or expanded face.
//
// Not all fonts support stretches.
type Stretch int
const (
StretchUltraCondensed Stretch = -4
StretchExtraCondensed Stretch = -3
StretchCondensed Stretch = -2
StretchSemiCondensed Stretch = -1
StretchNormal Stretch = +0
StretchSemiExpanded Stretch = +1
StretchExpanded Stretch = +2
StretchExtraExpanded Stretch = +3
StretchUltraExpanded Stretch = +4
)
// Style selects a normal, italic, or oblique face.
//
// Not all fonts support styles.
type Style int
const (
StyleNormal Style = iota
StyleItalic
StyleOblique
)
// Weight selects a normal, light or bold face.
//
// Not all fonts support weights.
//
// The named Weight constants (e.g. WeightBold) correspond to CSS' common
// weight names (e.g. "Bold"), but the numerical values differ, so that in Go,
// the zero value means to use a normal weight. For the CSS names and values,
// see https://developer.mozilla.org/en/docs/Web/CSS/font-weight
type Weight int
const (
WeightThin Weight = -3 // CSS font-weight value 100.
WeightExtraLight Weight = -2 // CSS font-weight value 200.
WeightLight Weight = -1 // CSS font-weight value 300.
WeightNormal Weight = +0 // CSS font-weight value 400.
WeightMedium Weight = +1 // CSS font-weight value 500.
WeightSemiBold Weight = +2 // CSS font-weight value 600.
WeightBold Weight = +3 // CSS font-weight value 700.
WeightExtraBold Weight = +4 // CSS font-weight value 800.
WeightBlack Weight = +5 // CSS font-weight value 900.
)
// 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.
// Package plan9font implements font faces for the Plan 9 font and subfont file
// formats. These formats are described at
// https://9p.io/magic/man2html/6/font
package plan9font // import "golang.org/x/image/font/plan9font"
import (
"bytes"
"errors"
"fmt"
"image"
"image/color"
"log"
"strconv"
"strings"
"golang.org/x/image/font"
"golang.org/x/image/math/fixed"
)
// fontchar describes one character glyph in a subfont.
//
// For more detail, look for "struct Fontchar" in
// https://9p.io/magic/man2html/2/cachechars
type fontchar struct {
x uint32 // X position in the image holding the glyphs.
top uint8 // First non-zero scan line.
bottom uint8 // Last non-zero scan line.
left int8 // Offset of baseline.
width uint8 // Width of baseline.
}
func parseFontchars(p []byte) []fontchar {
fc := make([]fontchar, len(p)/6)
for i := range fc {
fc[i] = fontchar{
x: uint32(p[0]) | uint32(p[1])<<8,
top: uint8(p[2]),
bottom: uint8(p[3]),
left: int8(p[4]),
width: uint8(p[5]),
}
p = p[6:]
}
return fc
}
// subface implements font.Face for a Plan 9 subfont.
type subface struct {
firstRune rune // First rune in the subfont.
n int // Number of characters in the subfont.
height int // Inter-line spacing.
ascent int // Height above the baseline.
fontchars []fontchar // Character descriptions.
img *image.Alpha // Image holding the glyphs.
}
func (f *subface) Close() error { return nil }
func (f *subface) Kern(r0, r1 rune) fixed.Int26_6 { return 0 }
func (f *subface) Metrics() font.Metrics {
// Approximate XHeight with the ascent of lowercase 'x'.
xbounds, _, _ := f.GlyphBounds('x')
// The same applies to CapHeight, using the uppercase 'H'.
hbounds, _, _ := f.GlyphBounds('H')
return font.Metrics{
Height: fixed.I(f.height),
Ascent: fixed.I(f.ascent),
Descent: fixed.I(f.height - f.ascent),
XHeight: -xbounds.Min.Y,
CapHeight: -hbounds.Min.Y,
CaretSlope: image.Point{X: 0, Y: 1},
}
}
func (f *subface) Glyph(dot fixed.Point26_6, r rune) (
dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) {
r -= f.firstRune
if r < 0 || f.n <= int(r) {
return image.Rectangle{}, nil, image.Point{}, 0, false
}
i := &f.fontchars[r+0]
j := &f.fontchars[r+1]
minX := int(dot.X+32)>>6 + int(i.left)
minY := int(dot.Y+32)>>6 + int(i.top) - f.ascent
dr = image.Rectangle{
Min: image.Point{
X: minX,
Y: minY,
},
Max: image.Point{
X: minX + int(j.x-i.x),
Y: minY + int(i.bottom) - int(i.top),
},
}
return dr, f.img, image.Point{int(i.x), int(i.top)}, fixed.Int26_6(i.width) << 6, true
}
func (f *subface) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) {
r -= f.firstRune
if r < 0 || f.n <= int(r) {
return fixed.Rectangle26_6{}, 0, false
}
i := &f.fontchars[r+0]
j := &f.fontchars[r+1]
bounds = fixed.R(
int(i.left),
int(i.top)-f.ascent,
int(i.left)+int(j.x-i.x),
int(i.bottom)-f.ascent,
)
return bounds, fixed.Int26_6(i.width) << 6, true
}
func (f *subface) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
r -= f.firstRune
if r < 0 || f.n <= int(r) {
return 0, false
}
return fixed.Int26_6(f.fontchars[r].width) << 6, true
}
// runeRange maps a single rune range [lo, hi] to a lazily loaded subface. Both
// ends of the range are inclusive.
type runeRange struct {
lo, hi rune
offset rune // subfont index that the lo rune maps to.
relFilename string
subface *subface
bad bool
}
// face implements font.Face for a Plan 9 font.
//
// It maps multiple rune ranges to *subface values. Rune ranges may overlap;
// the first match wins.
type face struct {
height int
ascent int
readFile func(relFilename string) ([]byte, error)
runeRanges []runeRange
}
func (f *face) Close() error { return nil }
func (f *face) Kern(r0, r1 rune) fixed.Int26_6 { return 0 }
func (f *face) Metrics() font.Metrics {
xbounds, _, _ := f.GlyphBounds('x')
hbounds, _, _ := f.GlyphBounds('H')
return font.Metrics{
Height: fixed.I(f.height),
Ascent: fixed.I(f.ascent),
Descent: fixed.I(f.height - f.ascent),
XHeight: -xbounds.Min.Y,
CapHeight: -hbounds.Min.Y,
CaretSlope: image.Point{X: 0, Y: 1},
}
}
func (f *face) Glyph(dot fixed.Point26_6, r rune) (
dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) {
if s, rr := f.subface(r); s != nil {
return s.Glyph(dot, rr)
}
return image.Rectangle{}, nil, image.Point{}, 0, false
}
func (f *face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) {
if s, rr := f.subface(r); s != nil {
return s.GlyphBounds(rr)
}
return fixed.Rectangle26_6{}, 0, false
}
func (f *face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
if s, rr := f.subface(r); s != nil {
return s.GlyphAdvance(rr)
}
return 0, false
}
// For subfont files, if reading the given file name fails, we try appending
// ".n" where n is the log2 of the grayscale depth in bits (so at most 3) and
// then work down to 0. This was done in Plan 9 when antialiased fonts were
// introduced so that the 1-bit displays could keep using the 1-bit forms but
// higher depth displays could use the antialiased forms.
var subfontSuffixes = [...]string{
"",
".3",
".2",
".1",
".0",
}
func (f *face) readSubfontFile(name string) ([]byte, error) {
var firstErr error
for _, suffix := range subfontSuffixes {
if b, err := f.readFile(name + suffix); err == nil {
return b, nil
} else if firstErr == nil {
firstErr = err
}
}
return nil, firstErr
}
func (f *face) subface(r rune) (*subface, rune) {
// Fall back on U+FFFD if we can't find r.
for _, rr := range [2]rune{r, '\ufffd'} {
// We have to do linear, not binary search. plan9port's
// lucsans/unicode.8.font says:
// 0x2591 0x2593 ../luc/Altshades.7.0
// 0x2500 0x25ee ../luc/FormBlock.7.0
// and the rune ranges overlap.
for i := range f.runeRanges {
x := &f.runeRanges[i]
if rr < x.lo || x.hi < rr || x.bad {
continue
}
if x.subface == nil {
data, err := f.readSubfontFile(x.relFilename)
if err != nil {
log.Printf("plan9font: couldn't read subfont %q: %v", x.relFilename, err)
x.bad = true
continue
}
sub, err := ParseSubfont(data, x.lo-x.offset)
if err != nil {
log.Printf("plan9font: couldn't parse subfont %q: %v", x.relFilename, err)
x.bad = true
continue
}
x.subface = sub.(*subface)
}
return x.subface, rr
}
}
return nil, 0
}
// ParseFont parses a Plan 9 font file. data is the contents of that font file,
// which gives relative filenames for subfont files. readFile returns the
// contents of those subfont files. It is similar to io/ioutil's ReadFile
// function, except that it takes a relative filename instead of an absolute
// one.
func ParseFont(data []byte, readFile func(relFilename string) ([]byte, error)) (font.Face, error) {
f := &face{
readFile: readFile,
}
// TODO: don't use strconv, to avoid the conversions from []byte to string?
for first := true; len(data) > 0; first = false {
i := bytes.IndexByte(data, '\n')
if i < 0 {
return nil, errors.New("plan9font: invalid font: no final newline")
}
row := string(data[:i])
data = data[i+1:]
if first {
height, s, ok := nextInt32(row)
if !ok {
return nil, fmt.Errorf("plan9font: invalid font: invalid header %q", row)
}
ascent, s, ok := nextInt32(s)
if !ok {
return nil, fmt.Errorf("plan9font: invalid font: invalid header %q", row)
}
if height < 0 || 0xffff < height || ascent < 0 || 0xffff < ascent {
return nil, fmt.Errorf("plan9font: invalid font: invalid header %q", row)
}
f.height, f.ascent = int(height), int(ascent)
continue
}
lo, s, ok := nextInt32(row)
if !ok {
return nil, fmt.Errorf("plan9font: invalid font: invalid row %q", row)
}
hi, s, ok := nextInt32(s)
if !ok {
return nil, fmt.Errorf("plan9font: invalid font: invalid row %q", row)
}
offset, s, _ := nextInt32(s)
f.runeRanges = append(f.runeRanges, runeRange{
lo: lo,
hi: hi,
offset: offset,
relFilename: s,
})
}
return f, nil
}
func nextInt32(s string) (ret int32, remaining string, ok bool) {
i := 0
for ; i < len(s) && s[i] <= ' '; i++ {
}
j := i
for ; j < len(s) && s[j] > ' '; j++ {
}
n, err := strconv.ParseInt(s[i:j], 0, 32)
if err != nil {
return 0, s, false
}
for ; j < len(s) && s[j] <= ' '; j++ {
}
return int32(n), s[j:], true
}
// ParseSubfont parses a Plan 9 subfont file.
//
// firstRune is the first rune in the subfont file. For example, the
// Phonetic.6.0 subfont, containing glyphs in the range U+0250 to U+02E9, would
// set firstRune to '\u0250'.
func ParseSubfont(data []byte, firstRune rune) (font.Face, error) {
data, m, err := parseImage(data)
if err != nil {
return nil, err
}
if len(data) < 3*12 {
return nil, errors.New("plan9font: invalid subfont: header too short")
}
n := atoi(data[0*12:])
height := atoi(data[1*12:])
ascent := atoi(data[2*12:])
data = data[3*12:]
if n < 0 || height < 0 || ascent < 0 {
return nil, errors.New("plan9font: invalid subfont: dimension too large")
} else if len(data) != 6*(n+1) {
return nil, errors.New("plan9font: invalid subfont: data length mismatch")
}
// Convert from plan9Image to image.Alpha, as the standard library's
// image/draw package works best when glyph masks are of that type.
img := image.NewAlpha(m.Bounds())
for y := img.Rect.Min.Y; y < img.Rect.Max.Y; y++ {
i := img.PixOffset(img.Rect.Min.X, y)
for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
img.Pix[i] = m.at(x, y)
i++
}
}
return &subface{
firstRune: firstRune,
n: n,
height: height,
ascent: ascent,
fontchars: parseFontchars(data),
img: img,
}, nil
}
// plan9Image implements that subset of the Plan 9 image feature set that is
// used by this font file format.
//
// Some features, such as the repl bit and a clip rectangle, are omitted for
// simplicity.
type plan9Image struct {
depth int // Depth of the pixels in bits.
width int // Width in bytes of a single scan line.
rect image.Rectangle // Extent of the image.
pix []byte // Pixel bits.
}
func (m *plan9Image) byteoffset(x, y int) int {
x -= m.rect.Min.X
y -= m.rect.Min.Y
a := y * m.width
if m.depth < 8 {
// We need to always round down, but Go rounds toward zero.
np := 8 / m.depth
if x < 0 {
return a + (x-np+1)/np
}
return a + x/np
}
return a + x*(m.depth/8)
}
func (m *plan9Image) Bounds() image.Rectangle { return m.rect }
func (m *plan9Image) ColorModel() color.Model { return color.AlphaModel }
func (m *plan9Image) At(x, y int) color.Color {
if (image.Point{x, y}).In(m.rect) {
return color.Alpha{m.at(x, y)}
}
return color.Alpha{0x00}
}
func (m *plan9Image) at(x, y int) uint8 {
b := m.pix[m.byteoffset(x, y)]
switch m.depth {
case 1:
// CGrey, 1.
mask := uint8(1 << uint8(7-x&7))
if (b & mask) != 0 {
return 0xff
}
return 0
case 2:
// CGrey, 2.
shift := uint(x&3) << 1
// Place pixel at top of word.
y := b << shift
y &= 0xc0
// Replicate throughout.
y |= y >> 2
y |= y >> 4
return y
}
return 0
}
var compressed = []byte("compressed\n")
func parseImage(data []byte) (remainingData []byte, m *plan9Image, retErr error) {
if !bytes.HasPrefix(data, compressed) {
return nil, nil, errors.New("plan9font: unsupported uncompressed format")
}
data = data[len(compressed):]
const hdrSize = 5 * 12
if len(data) < hdrSize {
return nil, nil, errors.New("plan9font: invalid image: header too short")
}
hdr, data := data[:hdrSize], data[hdrSize:]
// Distinguish new channel descriptor from old ldepth. Channel descriptors
// have letters as well as numbers, while ldepths are a single digit
// formatted as %-11d.
new := false
for m := 0; m < 10; m++ {
if hdr[m] != ' ' {
new = true
break
}
}
if hdr[11] != ' ' {
return nil, nil, errors.New("plan9font: invalid image: bad header")
}
if !new {
return nil, nil, errors.New("plan9font: unsupported ldepth format")
}
depth := 0
switch s := strings.TrimSpace(string(hdr[:1*12])); s {
default:
return nil, nil, fmt.Errorf("plan9font: unsupported pixel format %q", s)
case "k1":
depth = 1
case "k2":
depth = 2
}
r := ator(hdr[1*12:])
if r.Min.X < 0 || r.Max.X < 0 || r.Min.Y < 0 || r.Max.Y < 0 ||
r.Min.X > r.Max.X || r.Min.Y > r.Max.Y {
return nil, nil, errors.New("plan9font: invalid image: bad rectangle")
}
width := bytesPerLine(r, depth)
// These bounds are somewhat arbitrary, but multiplying them together won't
// overflow an int32.
if (width > 0xffff) || (r.Dy() > 0x7fff) {
return nil, nil, errors.New("plan9font: unsupported dimensions")
}
m = &plan9Image{
depth: depth,
width: width,
rect: r,
pix: make([]byte, width*r.Dy()),
}
miny := r.Min.Y
for miny != r.Max.Y {
if len(data) < 2*12 {
return nil, nil, errors.New("plan9font: invalid image: data band too short")
}
maxy := atoi(data[0*12:])
nb := atoi(data[1*12:])
data = data[2*12:]
if maxy < 0 || nb < 0 {
return nil, nil, errors.New("plan9font: invalid image: dimension too large")
} else if len(data) < nb {
return nil, nil, errors.New("plan9font: invalid image: data band length mismatch")
}
buf := data[:nb]
data = data[nb:]
if maxy <= miny || r.Max.Y < maxy {
return nil, nil, fmt.Errorf("plan9font: bad maxy %d", maxy)
}
// An old-format image would flip the bits here, but we don't support
// the old format.
rr := r
rr.Min.Y = miny
rr.Max.Y = maxy
if err := decompress(m, rr, buf); err != nil {
return nil, nil, err
}
miny = maxy
}
return data, m, nil
}
// Compressed data are sequences of byte codes. If the first byte b has the
// 0x80 bit set, the next (b^0x80)+1 bytes are data. Otherwise, these two bytes
// specify a previous string to repeat.
const (
compShortestMatch = 3 // shortest match possible.
compWindowSize = 1024 // window size.
)
var (
errDecompressBufferTooSmall = errors.New("plan9font: decompress: buffer too small")
errDecompressPhaseError = errors.New("plan9font: decompress: phase error")
)
func decompress(m *plan9Image, r image.Rectangle, data []byte) error {
if !r.In(m.rect) {
return errors.New("plan9font: decompress: bad rectangle")
}
bpl := bytesPerLine(r, m.depth)
mem := make([]byte, compWindowSize)
memi := 0
omemi := -1
y := r.Min.Y
linei := m.byteoffset(r.Min.X, y)
eline := linei + bpl
datai := 0
for {
if linei == eline {
y++
if y == r.Max.Y {
break
}
linei = m.byteoffset(r.Min.X, y)
eline = linei + bpl
}
if datai == len(data) {
return errDecompressBufferTooSmall
}
c := data[datai]
datai++
if c >= 128 {
for cnt := c - 128 + 1; cnt != 0; cnt-- {
if datai == len(data) {
return errDecompressBufferTooSmall
}
if linei == eline {
return errDecompressPhaseError
}
m.pix[linei] = data[datai]
linei++
mem[memi] = data[datai]
memi++
datai++
if memi == len(mem) {
memi = 0
}
}
} else {
if datai == len(data) {
return errDecompressBufferTooSmall
}
offs := int(data[datai]) + ((int(c) & 3) << 8) + 1
datai++
if memi < offs {
omemi = memi + (compWindowSize - offs)
} else {
omemi = memi - offs
}
for cnt := (c >> 2) + compShortestMatch; cnt != 0; cnt-- {
if linei == eline {
return errDecompressPhaseError
}
m.pix[linei] = mem[omemi]
linei++
mem[memi] = mem[omemi]
memi++
omemi++
if omemi == len(mem) {
omemi = 0
}
if memi == len(mem) {
memi = 0
}
}
}
}
return nil
}
func ator(b []byte) image.Rectangle {
return image.Rectangle{atop(b), atop(b[2*12:])}
}
func atop(b []byte) image.Point {
return image.Pt(atoi(b), atoi(b[12:]))
}
func atoi(b []byte) int {
i := 0
for ; i < len(b) && b[i] == ' '; i++ {
}
n := 0
for ; i < len(b) && '0' <= b[i] && b[i] <= '9'; i++ {
n = n*10 + int(b[i]) - '0'
if n > 999999 {
return -1
}
}
return n
}
func bytesPerLine(r image.Rectangle, depth int) int {
if depth <= 0 || 32 < depth {
panic("invalid depth")
}
var l int
if r.Min.X >= 0 {
l = (r.Max.X*depth + 7) / 8
l -= (r.Min.X * depth) / 8
} else {
// Make positive before divide.
t := (-r.Min.X*depth + 7) / 8
l = t + (r.Max.X*depth+7)/8
}
return l
}
//go:build gofuzz
package fuzz_ng_x_image_bmp
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/image/bmp"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Decode:
arg1 := bytes.NewReader(a.Decode.R)
cfg, err := bmp.DecodeConfig(arg1)
if err != nil {
return 0
}
if cfg.Width * cfg.Height > 1024*1024 {
continue
}
arg0 := bytes.NewReader(a.Decode.R)
_, r1 := bmp.Decode(arg0)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_DecodeConfig:
arg0 := bytes.NewReader(a.DecodeConfig.R)
_, r1 := bmp.DecodeConfig(arg0)
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Decode:
w.WriteString(fmt.Sprintf("bmp.Decode(bytes.NewReader(%#+v))\n", a.Decode.R))
case *NgoloFuzzOne_DecodeConfig:
w.WriteString(fmt.Sprintf("bmp.DecodeConfig(bytes.NewReader(%#+v))\n", a.DecodeConfig.R))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_image_bmp
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type DecodeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R []byte `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecodeArgs) Reset() {
*x = DecodeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecodeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecodeArgs) ProtoMessage() {}
func (x *DecodeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecodeArgs.ProtoReflect.Descriptor instead.
func (*DecodeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *DecodeArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
type DecodeConfigArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R []byte `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecodeConfigArgs) Reset() {
*x = DecodeConfigArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecodeConfigArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecodeConfigArgs) ProtoMessage() {}
func (x *DecodeConfigArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecodeConfigArgs.ProtoReflect.Descriptor instead.
func (*DecodeConfigArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *DecodeConfigArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_Decode
// *NgoloFuzzOne_DecodeConfig
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetDecode() *DecodeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Decode); ok {
return x.Decode
}
}
return nil
}
func (x *NgoloFuzzOne) GetDecodeConfig() *DecodeConfigArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_DecodeConfig); ok {
return x.DecodeConfig
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_Decode struct {
Decode *DecodeArgs `protobuf:"bytes,1,opt,name=Decode,proto3,oneof"`
}
type NgoloFuzzOne_DecodeConfig struct {
DecodeConfig *DecodeConfigArgs `protobuf:"bytes,2,opt,name=DecodeConfig,proto3,oneof"`
}
func (*NgoloFuzzOne_Decode) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_DecodeConfig) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x1a\n" +
"\n" +
"DecodeArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\fR\x01r\" \n" +
"\x10DecodeConfigArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\fR\x01r\"\x8a\x01\n" +
"\fNgoloFuzzOne\x12/\n" +
"\x06Decode\x18\x01 \x01(\v2\x15.ngolofuzz.DecodeArgsH\x00R\x06Decode\x12A\n" +
"\fDecodeConfig\x18\x02 \x01(\v2\x1b.ngolofuzz.DecodeConfigArgsH\x00R\fDecodeConfigB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x18Z\x16./;fuzz_ng_x_image_bmpb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_ngolofuzz_proto_goTypes = []any{
(*DecodeArgs)(nil), // 0: ngolofuzz.DecodeArgs
(*DecodeConfigArgs)(nil), // 1: ngolofuzz.DecodeConfigArgs
(*NgoloFuzzOne)(nil), // 2: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 3: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 4: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.Decode:type_name -> ngolofuzz.DecodeArgs
1, // 1: ngolofuzz.NgoloFuzzOne.DecodeConfig:type_name -> ngolofuzz.DecodeConfigArgs
2, // 2: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzOne_Decode)(nil),
(*NgoloFuzzOne_DecodeConfig)(nil),
}
file_ngolofuzz_proto_msgTypes[3].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_image_draw
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/image/draw"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func OpNewFromFuzz(p OpEnum) draw.Op{
switch p {
case 1:
return draw.Src
}
return draw.Over
}
func ConvertOpNewFromFuzz(a []OpEnum) []draw.Op{
r := make([]draw.Op, len(a))
for i := range a {
r[i] = OpNewFromFuzz(a[i])
}
return r
}
func KernelNewFromFuzz(p *KernelStruct) *draw.Kernel{
if p == nil {
return nil
}
return &draw.Kernel{
Support: p.Support,
}
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_KernelNgdotNewScaler:
arg0 := KernelNewFromFuzz(a.KernelNgdotNewScaler.Q)
if arg0 == nil {
continue
}
arg1 := int(a.KernelNgdotNewScaler.Dw)
arg2 := int(a.KernelNgdotNewScaler.Dh)
arg3 := int(a.KernelNgdotNewScaler.Sw)
arg4 := int(a.KernelNgdotNewScaler.Sh)
arg0.NewScaler(arg1, arg2, arg3, arg4)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_KernelNgdotNewScaler:
w.WriteString(fmt.Sprintf("KernelNewFromFuzz(%#+v).NewScaler(int(%#+v), int(%#+v), int(%#+v), int(%#+v))\n", a.KernelNgdotNewScaler.Q, a.KernelNgdotNewScaler.Dw, a.KernelNgdotNewScaler.Dh, a.KernelNgdotNewScaler.Sw, a.KernelNgdotNewScaler.Sh))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_image_draw
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type OpEnum int32
const (
OpEnum_Over OpEnum = 0
OpEnum_Src OpEnum = 1
)
// Enum value maps for OpEnum.
var (
OpEnum_name = map[int32]string{
0: "Over",
1: "Src",
}
OpEnum_value = map[string]int32{
"Over": 0,
"Src": 1,
}
)
func (x OpEnum) Enum() *OpEnum {
p := new(OpEnum)
*p = x
return p
}
func (x OpEnum) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (OpEnum) Descriptor() protoreflect.EnumDescriptor {
return file_ngolofuzz_proto_enumTypes[0].Descriptor()
}
func (OpEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[0]
}
func (x OpEnum) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use OpEnum.Descriptor instead.
func (OpEnum) EnumDescriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type KernelStruct struct {
state protoimpl.MessageState `protogen:"open.v1"`
Support float64 `protobuf:"fixed64,1,opt,name=Support,proto3" json:"Support,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *KernelStruct) Reset() {
*x = KernelStruct{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *KernelStruct) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*KernelStruct) ProtoMessage() {}
func (x *KernelStruct) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use KernelStruct.ProtoReflect.Descriptor instead.
func (*KernelStruct) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *KernelStruct) GetSupport() float64 {
if x != nil {
return x.Support
}
return 0
}
type KernelNgdotNewScalerArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Q *KernelStruct `protobuf:"bytes,1,opt,name=q,proto3" json:"q,omitempty"`
Dw int64 `protobuf:"varint,2,opt,name=dw,proto3" json:"dw,omitempty"`
Dh int64 `protobuf:"varint,3,opt,name=dh,proto3" json:"dh,omitempty"`
Sw int64 `protobuf:"varint,4,opt,name=sw,proto3" json:"sw,omitempty"`
Sh int64 `protobuf:"varint,5,opt,name=sh,proto3" json:"sh,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *KernelNgdotNewScalerArgs) Reset() {
*x = KernelNgdotNewScalerArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *KernelNgdotNewScalerArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*KernelNgdotNewScalerArgs) ProtoMessage() {}
func (x *KernelNgdotNewScalerArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use KernelNgdotNewScalerArgs.ProtoReflect.Descriptor instead.
func (*KernelNgdotNewScalerArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *KernelNgdotNewScalerArgs) GetQ() *KernelStruct {
if x != nil {
return x.Q
}
return nil
}
func (x *KernelNgdotNewScalerArgs) GetDw() int64 {
if x != nil {
return x.Dw
}
return 0
}
func (x *KernelNgdotNewScalerArgs) GetDh() int64 {
if x != nil {
return x.Dh
}
return 0
}
func (x *KernelNgdotNewScalerArgs) GetSw() int64 {
if x != nil {
return x.Sw
}
return 0
}
func (x *KernelNgdotNewScalerArgs) GetSh() int64 {
if x != nil {
return x.Sh
}
return 0
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_KernelNgdotNewScaler
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetKernelNgdotNewScaler() *KernelNgdotNewScalerArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_KernelNgdotNewScaler); ok {
return x.KernelNgdotNewScaler
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_KernelNgdotNewScaler struct {
KernelNgdotNewScaler *KernelNgdotNewScalerArgs `protobuf:"bytes,1,opt,name=KernelNgdotNewScaler,proto3,oneof"`
}
func (*NgoloFuzzOne_KernelNgdotNewScaler) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"(\n" +
"\fKernelStruct\x12\x18\n" +
"\aSupport\x18\x01 \x01(\x01R\aSupport\"\x81\x01\n" +
"\x18KernelNgdotNewScalerArgs\x12%\n" +
"\x01q\x18\x01 \x01(\v2\x17.ngolofuzz.KernelStructR\x01q\x12\x0e\n" +
"\x02dw\x18\x02 \x01(\x03R\x02dw\x12\x0e\n" +
"\x02dh\x18\x03 \x01(\x03R\x02dh\x12\x0e\n" +
"\x02sw\x18\x04 \x01(\x03R\x02sw\x12\x0e\n" +
"\x02sh\x18\x05 \x01(\x03R\x02sh\"q\n" +
"\fNgoloFuzzOne\x12Y\n" +
"\x14KernelNgdotNewScaler\x18\x01 \x01(\v2#.ngolofuzz.KernelNgdotNewScalerArgsH\x00R\x14KernelNgdotNewScalerB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04list*\x1b\n" +
"\x06OpEnum\x12\b\n" +
"\x04Over\x10\x00\x12\a\n" +
"\x03Src\x10\x01B\x19Z\x17./;fuzz_ng_x_image_drawb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_ngolofuzz_proto_goTypes = []any{
(OpEnum)(0), // 0: ngolofuzz.OpEnum
(*KernelStruct)(nil), // 1: ngolofuzz.KernelStruct
(*KernelNgdotNewScalerArgs)(nil), // 2: ngolofuzz.KernelNgdotNewScalerArgs
(*NgoloFuzzOne)(nil), // 3: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 4: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 5: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
1, // 0: ngolofuzz.KernelNgdotNewScalerArgs.q:type_name -> ngolofuzz.KernelStruct
2, // 1: ngolofuzz.NgoloFuzzOne.KernelNgdotNewScaler:type_name -> ngolofuzz.KernelNgdotNewScalerArgs
3, // 2: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzOne_KernelNgdotNewScaler)(nil),
}
file_ngolofuzz_proto_msgTypes[3].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 1,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
EnumInfos: file_ngolofuzz_proto_enumTypes,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_image_font_plan9font
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/image/font/plan9font"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_ParseSubfont:
arg1 := GetRune(a.ParseSubfont.FirstRune)
_, r1 := plan9font.ParseSubfont(a.ParseSubfont.Data, arg1)
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_ParseSubfont:
w.WriteString(fmt.Sprintf("plan9font.ParseSubfont(%#+v, GetRune(%#+v))\n", a.ParseSubfont.Data, a.ParseSubfont.FirstRune))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_image_font_plan9font
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ParseSubfontArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
FirstRune string `protobuf:"bytes,2,opt,name=firstRune,proto3" json:"firstRune,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ParseSubfontArgs) Reset() {
*x = ParseSubfontArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ParseSubfontArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ParseSubfontArgs) ProtoMessage() {}
func (x *ParseSubfontArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ParseSubfontArgs.ProtoReflect.Descriptor instead.
func (*ParseSubfontArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *ParseSubfontArgs) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
func (x *ParseSubfontArgs) GetFirstRune() string {
if x != nil {
return x.FirstRune
}
return ""
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_ParseSubfont
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetParseSubfont() *ParseSubfontArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ParseSubfont); ok {
return x.ParseSubfont
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_ParseSubfont struct {
ParseSubfont *ParseSubfontArgs `protobuf:"bytes,1,opt,name=ParseSubfont,proto3,oneof"`
}
func (*NgoloFuzzOne_ParseSubfont) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"D\n" +
"\x10ParseSubfontArgs\x12\x12\n" +
"\x04data\x18\x01 \x01(\fR\x04data\x12\x1c\n" +
"\tfirstRune\x18\x02 \x01(\tR\tfirstRune\"Y\n" +
"\fNgoloFuzzOne\x12A\n" +
"\fParseSubfont\x18\x01 \x01(\v2\x1b.ngolofuzz.ParseSubfontArgsH\x00R\fParseSubfontB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB#Z!./;fuzz_ng_x_image_font_plan9fontb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_ngolofuzz_proto_goTypes = []any{
(*ParseSubfontArgs)(nil), // 0: ngolofuzz.ParseSubfontArgs
(*NgoloFuzzOne)(nil), // 1: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 2: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 3: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.ParseSubfont:type_name -> ngolofuzz.ParseSubfontArgs
1, // 1: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[1].OneofWrappers = []any{
(*NgoloFuzzOne_ParseSubfont)(nil),
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_image_math_fixed
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/image/math/fixed"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var Rectangle52_12Results []*fixed.Rectangle52_12
Rectangle52_12ResultsIndex := 0
var Int26_6Results []*fixed.Int26_6
Int26_6ResultsIndex := 0
var Int52_12Results []*fixed.Int52_12
Int52_12ResultsIndex := 0
var Point26_6Results []*fixed.Point26_6
Point26_6ResultsIndex := 0
var Point52_12Results []*fixed.Point52_12
Point52_12ResultsIndex := 0
var Rectangle26_6Results []*fixed.Rectangle26_6
Rectangle26_6ResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_I:
arg0 := int(a.I.I)
r0 := fixed.I(arg0)
Int26_6Results = append(Int26_6Results, &r0)
case *NgoloFuzzOne_Int26_6NgdotString:
if len(Int26_6Results) == 0 {
continue
}
arg0 := Int26_6Results[Int26_6ResultsIndex]
Int26_6ResultsIndex = (Int26_6ResultsIndex + 1) % len(Int26_6Results)
arg0.String()
case *NgoloFuzzOne_Int26_6NgdotFloor:
if len(Int26_6Results) == 0 {
continue
}
arg0 := Int26_6Results[Int26_6ResultsIndex]
Int26_6ResultsIndex = (Int26_6ResultsIndex + 1) % len(Int26_6Results)
arg0.Floor()
case *NgoloFuzzOne_Int26_6NgdotRound:
if len(Int26_6Results) == 0 {
continue
}
arg0 := Int26_6Results[Int26_6ResultsIndex]
Int26_6ResultsIndex = (Int26_6ResultsIndex + 1) % len(Int26_6Results)
arg0.Round()
case *NgoloFuzzOne_Int26_6NgdotCeil:
if len(Int26_6Results) == 0 {
continue
}
arg0 := Int26_6Results[Int26_6ResultsIndex]
Int26_6ResultsIndex = (Int26_6ResultsIndex + 1) % len(Int26_6Results)
arg0.Ceil()
case *NgoloFuzzOne_Int26_6NgdotMul:
if len(Int26_6Results) == 0 {
continue
}
arg0 := Int26_6Results[Int26_6ResultsIndex]
Int26_6ResultsIndex = (Int26_6ResultsIndex + 1) % len(Int26_6Results)
if len(Int26_6Results) == 0 {
continue
}
arg1 := *Int26_6Results[Int26_6ResultsIndex]
Int26_6ResultsIndex = (Int26_6ResultsIndex + 1) % len(Int26_6Results)
r0 := arg0.Mul(arg1)
Int26_6Results = append(Int26_6Results, &r0)
case *NgoloFuzzOne_Int52_12NgdotString:
if len(Int52_12Results) == 0 {
continue
}
arg0 := Int52_12Results[Int52_12ResultsIndex]
Int52_12ResultsIndex = (Int52_12ResultsIndex + 1) % len(Int52_12Results)
arg0.String()
case *NgoloFuzzOne_Int52_12NgdotFloor:
if len(Int52_12Results) == 0 {
continue
}
arg0 := Int52_12Results[Int52_12ResultsIndex]
Int52_12ResultsIndex = (Int52_12ResultsIndex + 1) % len(Int52_12Results)
arg0.Floor()
case *NgoloFuzzOne_Int52_12NgdotRound:
if len(Int52_12Results) == 0 {
continue
}
arg0 := Int52_12Results[Int52_12ResultsIndex]
Int52_12ResultsIndex = (Int52_12ResultsIndex + 1) % len(Int52_12Results)
arg0.Round()
case *NgoloFuzzOne_Int52_12NgdotCeil:
if len(Int52_12Results) == 0 {
continue
}
arg0 := Int52_12Results[Int52_12ResultsIndex]
Int52_12ResultsIndex = (Int52_12ResultsIndex + 1) % len(Int52_12Results)
arg0.Ceil()
case *NgoloFuzzOne_Int52_12NgdotMul:
if len(Int52_12Results) == 0 {
continue
}
arg0 := Int52_12Results[Int52_12ResultsIndex]
Int52_12ResultsIndex = (Int52_12ResultsIndex + 1) % len(Int52_12Results)
if len(Int52_12Results) == 0 {
continue
}
arg1 := *Int52_12Results[Int52_12ResultsIndex]
Int52_12ResultsIndex = (Int52_12ResultsIndex + 1) % len(Int52_12Results)
r0 := arg0.Mul(arg1)
Int52_12Results = append(Int52_12Results, &r0)
case *NgoloFuzzOne_P:
arg0 := int(a.P.X)
arg1 := int(a.P.Y)
fixed.P(arg0, arg1)
case *NgoloFuzzOne_Point26_6NgdotAdd:
if len(Point26_6Results) == 0 {
continue
}
arg0 := Point26_6Results[Point26_6ResultsIndex]
Point26_6ResultsIndex = (Point26_6ResultsIndex + 1) % len(Point26_6Results)
if len(Point26_6Results) == 0 {
continue
}
arg1 := *Point26_6Results[Point26_6ResultsIndex]
Point26_6ResultsIndex = (Point26_6ResultsIndex + 1) % len(Point26_6Results)
arg0.Add(arg1)
case *NgoloFuzzOne_Point26_6NgdotSub:
if len(Point26_6Results) == 0 {
continue
}
arg0 := Point26_6Results[Point26_6ResultsIndex]
Point26_6ResultsIndex = (Point26_6ResultsIndex + 1) % len(Point26_6Results)
if len(Point26_6Results) == 0 {
continue
}
arg1 := *Point26_6Results[Point26_6ResultsIndex]
Point26_6ResultsIndex = (Point26_6ResultsIndex + 1) % len(Point26_6Results)
arg0.Sub(arg1)
case *NgoloFuzzOne_Point26_6NgdotMul:
if len(Point26_6Results) == 0 {
continue
}
arg0 := Point26_6Results[Point26_6ResultsIndex]
Point26_6ResultsIndex = (Point26_6ResultsIndex + 1) % len(Point26_6Results)
if len(Int26_6Results) == 0 {
continue
}
arg1 := *Int26_6Results[Int26_6ResultsIndex]
Int26_6ResultsIndex = (Int26_6ResultsIndex + 1) % len(Int26_6Results)
arg0.Mul(arg1)
case *NgoloFuzzOne_Point26_6NgdotDiv:
if len(Point26_6Results) == 0 {
continue
}
arg0 := Point26_6Results[Point26_6ResultsIndex]
Point26_6ResultsIndex = (Point26_6ResultsIndex + 1) % len(Point26_6Results)
if len(Int26_6Results) == 0 {
continue
}
arg1 := *Int26_6Results[Int26_6ResultsIndex]
Int26_6ResultsIndex = (Int26_6ResultsIndex + 1) % len(Int26_6Results)
arg0.Div(arg1)
case *NgoloFuzzOne_Point26_6NgdotIn:
if len(Point26_6Results) == 0 {
continue
}
arg0 := Point26_6Results[Point26_6ResultsIndex]
Point26_6ResultsIndex = (Point26_6ResultsIndex + 1) % len(Point26_6Results)
if len(Rectangle26_6Results) == 0 {
continue
}
arg1 := *Rectangle26_6Results[Rectangle26_6ResultsIndex]
Rectangle26_6ResultsIndex = (Rectangle26_6ResultsIndex + 1) % len(Rectangle26_6Results)
arg0.In(arg1)
case *NgoloFuzzOne_Point52_12NgdotAdd:
if len(Point52_12Results) == 0 {
continue
}
arg0 := Point52_12Results[Point52_12ResultsIndex]
Point52_12ResultsIndex = (Point52_12ResultsIndex + 1) % len(Point52_12Results)
if len(Point52_12Results) == 0 {
continue
}
arg1 := *Point52_12Results[Point52_12ResultsIndex]
Point52_12ResultsIndex = (Point52_12ResultsIndex + 1) % len(Point52_12Results)
arg0.Add(arg1)
case *NgoloFuzzOne_Point52_12NgdotSub:
if len(Point52_12Results) == 0 {
continue
}
arg0 := Point52_12Results[Point52_12ResultsIndex]
Point52_12ResultsIndex = (Point52_12ResultsIndex + 1) % len(Point52_12Results)
if len(Point52_12Results) == 0 {
continue
}
arg1 := *Point52_12Results[Point52_12ResultsIndex]
Point52_12ResultsIndex = (Point52_12ResultsIndex + 1) % len(Point52_12Results)
arg0.Sub(arg1)
case *NgoloFuzzOne_Point52_12NgdotMul:
if len(Point52_12Results) == 0 {
continue
}
arg0 := Point52_12Results[Point52_12ResultsIndex]
Point52_12ResultsIndex = (Point52_12ResultsIndex + 1) % len(Point52_12Results)
if len(Int52_12Results) == 0 {
continue
}
arg1 := *Int52_12Results[Int52_12ResultsIndex]
Int52_12ResultsIndex = (Int52_12ResultsIndex + 1) % len(Int52_12Results)
arg0.Mul(arg1)
case *NgoloFuzzOne_Point52_12NgdotDiv:
if len(Point52_12Results) == 0 {
continue
}
arg0 := Point52_12Results[Point52_12ResultsIndex]
Point52_12ResultsIndex = (Point52_12ResultsIndex + 1) % len(Point52_12Results)
if len(Int52_12Results) == 0 {
continue
}
arg1 := *Int52_12Results[Int52_12ResultsIndex]
Int52_12ResultsIndex = (Int52_12ResultsIndex + 1) % len(Int52_12Results)
arg0.Div(arg1)
case *NgoloFuzzOne_Point52_12NgdotIn:
if len(Point52_12Results) == 0 {
continue
}
arg0 := Point52_12Results[Point52_12ResultsIndex]
Point52_12ResultsIndex = (Point52_12ResultsIndex + 1) % len(Point52_12Results)
if len(Rectangle52_12Results) == 0 {
continue
}
arg1 := *Rectangle52_12Results[Rectangle52_12ResultsIndex]
Rectangle52_12ResultsIndex = (Rectangle52_12ResultsIndex + 1) % len(Rectangle52_12Results)
arg0.In(arg1)
case *NgoloFuzzOne_R:
arg0 := int(a.R.MinX)
arg1 := int(a.R.MinY)
arg2 := int(a.R.MaxX)
arg3 := int(a.R.MaxY)
fixed.R(arg0, arg1, arg2, arg3)
case *NgoloFuzzOne_Rectangle26_6NgdotAdd:
if len(Rectangle26_6Results) == 0 {
continue
}
arg0 := Rectangle26_6Results[Rectangle26_6ResultsIndex]
Rectangle26_6ResultsIndex = (Rectangle26_6ResultsIndex + 1) % len(Rectangle26_6Results)
if len(Point26_6Results) == 0 {
continue
}
arg1 := *Point26_6Results[Point26_6ResultsIndex]
Point26_6ResultsIndex = (Point26_6ResultsIndex + 1) % len(Point26_6Results)
arg0.Add(arg1)
case *NgoloFuzzOne_Rectangle26_6NgdotSub:
if len(Rectangle26_6Results) == 0 {
continue
}
arg0 := Rectangle26_6Results[Rectangle26_6ResultsIndex]
Rectangle26_6ResultsIndex = (Rectangle26_6ResultsIndex + 1) % len(Rectangle26_6Results)
if len(Point26_6Results) == 0 {
continue
}
arg1 := *Point26_6Results[Point26_6ResultsIndex]
Point26_6ResultsIndex = (Point26_6ResultsIndex + 1) % len(Point26_6Results)
arg0.Sub(arg1)
case *NgoloFuzzOne_Rectangle26_6NgdotIntersect:
if len(Rectangle26_6Results) == 0 {
continue
}
arg0 := Rectangle26_6Results[Rectangle26_6ResultsIndex]
Rectangle26_6ResultsIndex = (Rectangle26_6ResultsIndex + 1) % len(Rectangle26_6Results)
if len(Rectangle26_6Results) == 0 {
continue
}
arg1 := *Rectangle26_6Results[Rectangle26_6ResultsIndex]
Rectangle26_6ResultsIndex = (Rectangle26_6ResultsIndex + 1) % len(Rectangle26_6Results)
arg0.Intersect(arg1)
case *NgoloFuzzOne_Rectangle26_6NgdotUnion:
if len(Rectangle26_6Results) == 0 {
continue
}
arg0 := Rectangle26_6Results[Rectangle26_6ResultsIndex]
Rectangle26_6ResultsIndex = (Rectangle26_6ResultsIndex + 1) % len(Rectangle26_6Results)
if len(Rectangle26_6Results) == 0 {
continue
}
arg1 := *Rectangle26_6Results[Rectangle26_6ResultsIndex]
Rectangle26_6ResultsIndex = (Rectangle26_6ResultsIndex + 1) % len(Rectangle26_6Results)
arg0.Union(arg1)
case *NgoloFuzzOne_Rectangle26_6NgdotEmpty:
if len(Rectangle26_6Results) == 0 {
continue
}
arg0 := Rectangle26_6Results[Rectangle26_6ResultsIndex]
Rectangle26_6ResultsIndex = (Rectangle26_6ResultsIndex + 1) % len(Rectangle26_6Results)
arg0.Empty()
case *NgoloFuzzOne_Rectangle26_6NgdotIn:
if len(Rectangle26_6Results) == 0 {
continue
}
arg0 := Rectangle26_6Results[Rectangle26_6ResultsIndex]
Rectangle26_6ResultsIndex = (Rectangle26_6ResultsIndex + 1) % len(Rectangle26_6Results)
if len(Rectangle26_6Results) == 0 {
continue
}
arg1 := *Rectangle26_6Results[Rectangle26_6ResultsIndex]
Rectangle26_6ResultsIndex = (Rectangle26_6ResultsIndex + 1) % len(Rectangle26_6Results)
arg0.In(arg1)
case *NgoloFuzzOne_Rectangle52_12NgdotAdd:
if len(Rectangle52_12Results) == 0 {
continue
}
arg0 := Rectangle52_12Results[Rectangle52_12ResultsIndex]
Rectangle52_12ResultsIndex = (Rectangle52_12ResultsIndex + 1) % len(Rectangle52_12Results)
if len(Point52_12Results) == 0 {
continue
}
arg1 := *Point52_12Results[Point52_12ResultsIndex]
Point52_12ResultsIndex = (Point52_12ResultsIndex + 1) % len(Point52_12Results)
arg0.Add(arg1)
case *NgoloFuzzOne_Rectangle52_12NgdotSub:
if len(Rectangle52_12Results) == 0 {
continue
}
arg0 := Rectangle52_12Results[Rectangle52_12ResultsIndex]
Rectangle52_12ResultsIndex = (Rectangle52_12ResultsIndex + 1) % len(Rectangle52_12Results)
if len(Point52_12Results) == 0 {
continue
}
arg1 := *Point52_12Results[Point52_12ResultsIndex]
Point52_12ResultsIndex = (Point52_12ResultsIndex + 1) % len(Point52_12Results)
arg0.Sub(arg1)
case *NgoloFuzzOne_Rectangle52_12NgdotIntersect:
if len(Rectangle52_12Results) == 0 {
continue
}
arg0 := Rectangle52_12Results[Rectangle52_12ResultsIndex]
Rectangle52_12ResultsIndex = (Rectangle52_12ResultsIndex + 1) % len(Rectangle52_12Results)
if len(Rectangle52_12Results) == 0 {
continue
}
arg1 := *Rectangle52_12Results[Rectangle52_12ResultsIndex]
Rectangle52_12ResultsIndex = (Rectangle52_12ResultsIndex + 1) % len(Rectangle52_12Results)
arg0.Intersect(arg1)
case *NgoloFuzzOne_Rectangle52_12NgdotUnion:
if len(Rectangle52_12Results) == 0 {
continue
}
arg0 := Rectangle52_12Results[Rectangle52_12ResultsIndex]
Rectangle52_12ResultsIndex = (Rectangle52_12ResultsIndex + 1) % len(Rectangle52_12Results)
if len(Rectangle52_12Results) == 0 {
continue
}
arg1 := *Rectangle52_12Results[Rectangle52_12ResultsIndex]
Rectangle52_12ResultsIndex = (Rectangle52_12ResultsIndex + 1) % len(Rectangle52_12Results)
arg0.Union(arg1)
case *NgoloFuzzOne_Rectangle52_12NgdotEmpty:
if len(Rectangle52_12Results) == 0 {
continue
}
arg0 := Rectangle52_12Results[Rectangle52_12ResultsIndex]
Rectangle52_12ResultsIndex = (Rectangle52_12ResultsIndex + 1) % len(Rectangle52_12Results)
arg0.Empty()
case *NgoloFuzzOne_Rectangle52_12NgdotIn:
if len(Rectangle52_12Results) == 0 {
continue
}
arg0 := Rectangle52_12Results[Rectangle52_12ResultsIndex]
Rectangle52_12ResultsIndex = (Rectangle52_12ResultsIndex + 1) % len(Rectangle52_12Results)
if len(Rectangle52_12Results) == 0 {
continue
}
arg1 := *Rectangle52_12Results[Rectangle52_12ResultsIndex]
Rectangle52_12ResultsIndex = (Rectangle52_12ResultsIndex + 1) % len(Rectangle52_12Results)
arg0.In(arg1)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
Rectangle52_12Nb := 0
Rectangle52_12ResultsIndex := 0
Int26_6Nb := 0
Int26_6ResultsIndex := 0
Int52_12Nb := 0
Int52_12ResultsIndex := 0
Point26_6Nb := 0
Point26_6ResultsIndex := 0
Point52_12Nb := 0
Point52_12ResultsIndex := 0
Rectangle26_6Nb := 0
Rectangle26_6ResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_I:
w.WriteString(fmt.Sprintf("Int26_6%d := fixed.I(int(%#+v))\n", Int26_6Nb, a.I.I))
Int26_6Nb = Int26_6Nb + 1
case *NgoloFuzzOne_Int26_6NgdotString:
if Int26_6Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Int26_6%d.String()\n", Int26_6ResultsIndex))
Int26_6ResultsIndex = (Int26_6ResultsIndex + 1) % Int26_6Nb
case *NgoloFuzzOne_Int26_6NgdotFloor:
if Int26_6Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Int26_6%d.Floor()\n", Int26_6ResultsIndex))
Int26_6ResultsIndex = (Int26_6ResultsIndex + 1) % Int26_6Nb
case *NgoloFuzzOne_Int26_6NgdotRound:
if Int26_6Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Int26_6%d.Round()\n", Int26_6ResultsIndex))
Int26_6ResultsIndex = (Int26_6ResultsIndex + 1) % Int26_6Nb
case *NgoloFuzzOne_Int26_6NgdotCeil:
if Int26_6Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Int26_6%d.Ceil()\n", Int26_6ResultsIndex))
Int26_6ResultsIndex = (Int26_6ResultsIndex + 1) % Int26_6Nb
case *NgoloFuzzOne_Int26_6NgdotMul:
if Int26_6Nb == 0 {
continue
}
if Int26_6Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Int26_6%d := Int26_6%d.Mul(Int26_6%d)\n", Int26_6Nb, Int26_6ResultsIndex, (Int26_6ResultsIndex + 1) % Int26_6Nb))
Int26_6Nb = Int26_6Nb + 1
Int26_6ResultsIndex = (Int26_6ResultsIndex + 1) % Int26_6Nb
Int26_6ResultsIndex = (Int26_6ResultsIndex + 1) % Int26_6Nb
case *NgoloFuzzOne_Int52_12NgdotString:
if Int52_12Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Int52_12%d.String()\n", Int52_12ResultsIndex))
Int52_12ResultsIndex = (Int52_12ResultsIndex + 1) % Int52_12Nb
case *NgoloFuzzOne_Int52_12NgdotFloor:
if Int52_12Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Int52_12%d.Floor()\n", Int52_12ResultsIndex))
Int52_12ResultsIndex = (Int52_12ResultsIndex + 1) % Int52_12Nb
case *NgoloFuzzOne_Int52_12NgdotRound:
if Int52_12Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Int52_12%d.Round()\n", Int52_12ResultsIndex))
Int52_12ResultsIndex = (Int52_12ResultsIndex + 1) % Int52_12Nb
case *NgoloFuzzOne_Int52_12NgdotCeil:
if Int52_12Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Int52_12%d.Ceil()\n", Int52_12ResultsIndex))
Int52_12ResultsIndex = (Int52_12ResultsIndex + 1) % Int52_12Nb
case *NgoloFuzzOne_Int52_12NgdotMul:
if Int52_12Nb == 0 {
continue
}
if Int52_12Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Int52_12%d := Int52_12%d.Mul(Int52_12%d)\n", Int52_12Nb, Int52_12ResultsIndex, (Int52_12ResultsIndex + 1) % Int52_12Nb))
Int52_12Nb = Int52_12Nb + 1
Int52_12ResultsIndex = (Int52_12ResultsIndex + 1) % Int52_12Nb
Int52_12ResultsIndex = (Int52_12ResultsIndex + 1) % Int52_12Nb
case *NgoloFuzzOne_P:
w.WriteString(fmt.Sprintf("fixed.P(int(%#+v), int(%#+v))\n", a.P.X, a.P.Y))
case *NgoloFuzzOne_Point26_6NgdotAdd:
if Point26_6Nb == 0 {
continue
}
if Point26_6Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Point26_6%d.Add(Point26_6%d)\n", Point26_6ResultsIndex, (Point26_6ResultsIndex + 1) % Point26_6Nb))
Point26_6ResultsIndex = (Point26_6ResultsIndex + 1) % Point26_6Nb
Point26_6ResultsIndex = (Point26_6ResultsIndex + 1) % Point26_6Nb
case *NgoloFuzzOne_Point26_6NgdotSub:
if Point26_6Nb == 0 {
continue
}
if Point26_6Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Point26_6%d.Sub(Point26_6%d)\n", Point26_6ResultsIndex, (Point26_6ResultsIndex + 1) % Point26_6Nb))
Point26_6ResultsIndex = (Point26_6ResultsIndex + 1) % Point26_6Nb
Point26_6ResultsIndex = (Point26_6ResultsIndex + 1) % Point26_6Nb
case *NgoloFuzzOne_Point26_6NgdotMul:
if Point26_6Nb == 0 {
continue
}
if Int26_6Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Point26_6%d.Mul(Int26_6%d)\n", Point26_6ResultsIndex, (Int26_6ResultsIndex + 0) % Int26_6Nb))
Point26_6ResultsIndex = (Point26_6ResultsIndex + 1) % Point26_6Nb
Int26_6ResultsIndex = (Int26_6ResultsIndex + 1) % Int26_6Nb
case *NgoloFuzzOne_Point26_6NgdotDiv:
if Point26_6Nb == 0 {
continue
}
if Int26_6Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Point26_6%d.Div(Int26_6%d)\n", Point26_6ResultsIndex, (Int26_6ResultsIndex + 0) % Int26_6Nb))
Point26_6ResultsIndex = (Point26_6ResultsIndex + 1) % Point26_6Nb
Int26_6ResultsIndex = (Int26_6ResultsIndex + 1) % Int26_6Nb
case *NgoloFuzzOne_Point26_6NgdotIn:
if Point26_6Nb == 0 {
continue
}
if Rectangle26_6Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Point26_6%d.In(Rectangle26_6%d)\n", Point26_6ResultsIndex, (Rectangle26_6ResultsIndex + 0) % Rectangle26_6Nb))
Point26_6ResultsIndex = (Point26_6ResultsIndex + 1) % Point26_6Nb
Rectangle26_6ResultsIndex = (Rectangle26_6ResultsIndex + 1) % Rectangle26_6Nb
case *NgoloFuzzOne_Point52_12NgdotAdd:
if Point52_12Nb == 0 {
continue
}
if Point52_12Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Point52_12%d.Add(Point52_12%d)\n", Point52_12ResultsIndex, (Point52_12ResultsIndex + 1) % Point52_12Nb))
Point52_12ResultsIndex = (Point52_12ResultsIndex + 1) % Point52_12Nb
Point52_12ResultsIndex = (Point52_12ResultsIndex + 1) % Point52_12Nb
case *NgoloFuzzOne_Point52_12NgdotSub:
if Point52_12Nb == 0 {
continue
}
if Point52_12Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Point52_12%d.Sub(Point52_12%d)\n", Point52_12ResultsIndex, (Point52_12ResultsIndex + 1) % Point52_12Nb))
Point52_12ResultsIndex = (Point52_12ResultsIndex + 1) % Point52_12Nb
Point52_12ResultsIndex = (Point52_12ResultsIndex + 1) % Point52_12Nb
case *NgoloFuzzOne_Point52_12NgdotMul:
if Point52_12Nb == 0 {
continue
}
if Int52_12Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Point52_12%d.Mul(Int52_12%d)\n", Point52_12ResultsIndex, (Int52_12ResultsIndex + 0) % Int52_12Nb))
Point52_12ResultsIndex = (Point52_12ResultsIndex + 1) % Point52_12Nb
Int52_12ResultsIndex = (Int52_12ResultsIndex + 1) % Int52_12Nb
case *NgoloFuzzOne_Point52_12NgdotDiv:
if Point52_12Nb == 0 {
continue
}
if Int52_12Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Point52_12%d.Div(Int52_12%d)\n", Point52_12ResultsIndex, (Int52_12ResultsIndex + 0) % Int52_12Nb))
Point52_12ResultsIndex = (Point52_12ResultsIndex + 1) % Point52_12Nb
Int52_12ResultsIndex = (Int52_12ResultsIndex + 1) % Int52_12Nb
case *NgoloFuzzOne_Point52_12NgdotIn:
if Point52_12Nb == 0 {
continue
}
if Rectangle52_12Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Point52_12%d.In(Rectangle52_12%d)\n", Point52_12ResultsIndex, (Rectangle52_12ResultsIndex + 0) % Rectangle52_12Nb))
Point52_12ResultsIndex = (Point52_12ResultsIndex + 1) % Point52_12Nb
Rectangle52_12ResultsIndex = (Rectangle52_12ResultsIndex + 1) % Rectangle52_12Nb
case *NgoloFuzzOne_R:
w.WriteString(fmt.Sprintf("fixed.R(int(%#+v), int(%#+v), int(%#+v), int(%#+v))\n", a.R.MinX, a.R.MinY, a.R.MaxX, a.R.MaxY))
case *NgoloFuzzOne_Rectangle26_6NgdotAdd:
if Rectangle26_6Nb == 0 {
continue
}
if Point26_6Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Rectangle26_6%d.Add(Point26_6%d)\n", Rectangle26_6ResultsIndex, (Point26_6ResultsIndex + 0) % Point26_6Nb))
Rectangle26_6ResultsIndex = (Rectangle26_6ResultsIndex + 1) % Rectangle26_6Nb
Point26_6ResultsIndex = (Point26_6ResultsIndex + 1) % Point26_6Nb
case *NgoloFuzzOne_Rectangle26_6NgdotSub:
if Rectangle26_6Nb == 0 {
continue
}
if Point26_6Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Rectangle26_6%d.Sub(Point26_6%d)\n", Rectangle26_6ResultsIndex, (Point26_6ResultsIndex + 0) % Point26_6Nb))
Rectangle26_6ResultsIndex = (Rectangle26_6ResultsIndex + 1) % Rectangle26_6Nb
Point26_6ResultsIndex = (Point26_6ResultsIndex + 1) % Point26_6Nb
case *NgoloFuzzOne_Rectangle26_6NgdotIntersect:
if Rectangle26_6Nb == 0 {
continue
}
if Rectangle26_6Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Rectangle26_6%d.Intersect(Rectangle26_6%d)\n", Rectangle26_6ResultsIndex, (Rectangle26_6ResultsIndex + 1) % Rectangle26_6Nb))
Rectangle26_6ResultsIndex = (Rectangle26_6ResultsIndex + 1) % Rectangle26_6Nb
Rectangle26_6ResultsIndex = (Rectangle26_6ResultsIndex + 1) % Rectangle26_6Nb
case *NgoloFuzzOne_Rectangle26_6NgdotUnion:
if Rectangle26_6Nb == 0 {
continue
}
if Rectangle26_6Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Rectangle26_6%d.Union(Rectangle26_6%d)\n", Rectangle26_6ResultsIndex, (Rectangle26_6ResultsIndex + 1) % Rectangle26_6Nb))
Rectangle26_6ResultsIndex = (Rectangle26_6ResultsIndex + 1) % Rectangle26_6Nb
Rectangle26_6ResultsIndex = (Rectangle26_6ResultsIndex + 1) % Rectangle26_6Nb
case *NgoloFuzzOne_Rectangle26_6NgdotEmpty:
if Rectangle26_6Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Rectangle26_6%d.Empty()\n", Rectangle26_6ResultsIndex))
Rectangle26_6ResultsIndex = (Rectangle26_6ResultsIndex + 1) % Rectangle26_6Nb
case *NgoloFuzzOne_Rectangle26_6NgdotIn:
if Rectangle26_6Nb == 0 {
continue
}
if Rectangle26_6Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Rectangle26_6%d.In(Rectangle26_6%d)\n", Rectangle26_6ResultsIndex, (Rectangle26_6ResultsIndex + 1) % Rectangle26_6Nb))
Rectangle26_6ResultsIndex = (Rectangle26_6ResultsIndex + 1) % Rectangle26_6Nb
Rectangle26_6ResultsIndex = (Rectangle26_6ResultsIndex + 1) % Rectangle26_6Nb
case *NgoloFuzzOne_Rectangle52_12NgdotAdd:
if Rectangle52_12Nb == 0 {
continue
}
if Point52_12Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Rectangle52_12%d.Add(Point52_12%d)\n", Rectangle52_12ResultsIndex, (Point52_12ResultsIndex + 0) % Point52_12Nb))
Rectangle52_12ResultsIndex = (Rectangle52_12ResultsIndex + 1) % Rectangle52_12Nb
Point52_12ResultsIndex = (Point52_12ResultsIndex + 1) % Point52_12Nb
case *NgoloFuzzOne_Rectangle52_12NgdotSub:
if Rectangle52_12Nb == 0 {
continue
}
if Point52_12Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Rectangle52_12%d.Sub(Point52_12%d)\n", Rectangle52_12ResultsIndex, (Point52_12ResultsIndex + 0) % Point52_12Nb))
Rectangle52_12ResultsIndex = (Rectangle52_12ResultsIndex + 1) % Rectangle52_12Nb
Point52_12ResultsIndex = (Point52_12ResultsIndex + 1) % Point52_12Nb
case *NgoloFuzzOne_Rectangle52_12NgdotIntersect:
if Rectangle52_12Nb == 0 {
continue
}
if Rectangle52_12Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Rectangle52_12%d.Intersect(Rectangle52_12%d)\n", Rectangle52_12ResultsIndex, (Rectangle52_12ResultsIndex + 1) % Rectangle52_12Nb))
Rectangle52_12ResultsIndex = (Rectangle52_12ResultsIndex + 1) % Rectangle52_12Nb
Rectangle52_12ResultsIndex = (Rectangle52_12ResultsIndex + 1) % Rectangle52_12Nb
case *NgoloFuzzOne_Rectangle52_12NgdotUnion:
if Rectangle52_12Nb == 0 {
continue
}
if Rectangle52_12Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Rectangle52_12%d.Union(Rectangle52_12%d)\n", Rectangle52_12ResultsIndex, (Rectangle52_12ResultsIndex + 1) % Rectangle52_12Nb))
Rectangle52_12ResultsIndex = (Rectangle52_12ResultsIndex + 1) % Rectangle52_12Nb
Rectangle52_12ResultsIndex = (Rectangle52_12ResultsIndex + 1) % Rectangle52_12Nb
case *NgoloFuzzOne_Rectangle52_12NgdotEmpty:
if Rectangle52_12Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Rectangle52_12%d.Empty()\n", Rectangle52_12ResultsIndex))
Rectangle52_12ResultsIndex = (Rectangle52_12ResultsIndex + 1) % Rectangle52_12Nb
case *NgoloFuzzOne_Rectangle52_12NgdotIn:
if Rectangle52_12Nb == 0 {
continue
}
if Rectangle52_12Nb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Rectangle52_12%d.In(Rectangle52_12%d)\n", Rectangle52_12ResultsIndex, (Rectangle52_12ResultsIndex + 1) % Rectangle52_12Nb))
Rectangle52_12ResultsIndex = (Rectangle52_12ResultsIndex + 1) % Rectangle52_12Nb
Rectangle52_12ResultsIndex = (Rectangle52_12ResultsIndex + 1) % Rectangle52_12Nb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_image_math_fixed
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type IArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
I int64 `protobuf:"varint,1,opt,name=i,proto3" json:"i,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *IArgs) Reset() {
*x = IArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *IArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*IArgs) ProtoMessage() {}
func (x *IArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use IArgs.ProtoReflect.Descriptor instead.
func (*IArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *IArgs) GetI() int64 {
if x != nil {
return x.I
}
return 0
}
type Int26_6NgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Int26_6NgdotStringArgs) Reset() {
*x = Int26_6NgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Int26_6NgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Int26_6NgdotStringArgs) ProtoMessage() {}
func (x *Int26_6NgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Int26_6NgdotStringArgs.ProtoReflect.Descriptor instead.
func (*Int26_6NgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
type Int26_6NgdotFloorArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Int26_6NgdotFloorArgs) Reset() {
*x = Int26_6NgdotFloorArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Int26_6NgdotFloorArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Int26_6NgdotFloorArgs) ProtoMessage() {}
func (x *Int26_6NgdotFloorArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Int26_6NgdotFloorArgs.ProtoReflect.Descriptor instead.
func (*Int26_6NgdotFloorArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
type Int26_6NgdotRoundArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Int26_6NgdotRoundArgs) Reset() {
*x = Int26_6NgdotRoundArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Int26_6NgdotRoundArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Int26_6NgdotRoundArgs) ProtoMessage() {}
func (x *Int26_6NgdotRoundArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Int26_6NgdotRoundArgs.ProtoReflect.Descriptor instead.
func (*Int26_6NgdotRoundArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
type Int26_6NgdotCeilArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Int26_6NgdotCeilArgs) Reset() {
*x = Int26_6NgdotCeilArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Int26_6NgdotCeilArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Int26_6NgdotCeilArgs) ProtoMessage() {}
func (x *Int26_6NgdotCeilArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Int26_6NgdotCeilArgs.ProtoReflect.Descriptor instead.
func (*Int26_6NgdotCeilArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
type Int26_6NgdotMulArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Int26_6NgdotMulArgs) Reset() {
*x = Int26_6NgdotMulArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Int26_6NgdotMulArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Int26_6NgdotMulArgs) ProtoMessage() {}
func (x *Int26_6NgdotMulArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Int26_6NgdotMulArgs.ProtoReflect.Descriptor instead.
func (*Int26_6NgdotMulArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
type Int52_12NgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Int52_12NgdotStringArgs) Reset() {
*x = Int52_12NgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Int52_12NgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Int52_12NgdotStringArgs) ProtoMessage() {}
func (x *Int52_12NgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Int52_12NgdotStringArgs.ProtoReflect.Descriptor instead.
func (*Int52_12NgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
type Int52_12NgdotFloorArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Int52_12NgdotFloorArgs) Reset() {
*x = Int52_12NgdotFloorArgs{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Int52_12NgdotFloorArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Int52_12NgdotFloorArgs) ProtoMessage() {}
func (x *Int52_12NgdotFloorArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Int52_12NgdotFloorArgs.ProtoReflect.Descriptor instead.
func (*Int52_12NgdotFloorArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
type Int52_12NgdotRoundArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Int52_12NgdotRoundArgs) Reset() {
*x = Int52_12NgdotRoundArgs{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Int52_12NgdotRoundArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Int52_12NgdotRoundArgs) ProtoMessage() {}
func (x *Int52_12NgdotRoundArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Int52_12NgdotRoundArgs.ProtoReflect.Descriptor instead.
func (*Int52_12NgdotRoundArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
type Int52_12NgdotCeilArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Int52_12NgdotCeilArgs) Reset() {
*x = Int52_12NgdotCeilArgs{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Int52_12NgdotCeilArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Int52_12NgdotCeilArgs) ProtoMessage() {}
func (x *Int52_12NgdotCeilArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Int52_12NgdotCeilArgs.ProtoReflect.Descriptor instead.
func (*Int52_12NgdotCeilArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
type Int52_12NgdotMulArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Int52_12NgdotMulArgs) Reset() {
*x = Int52_12NgdotMulArgs{}
mi := &file_ngolofuzz_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Int52_12NgdotMulArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Int52_12NgdotMulArgs) ProtoMessage() {}
func (x *Int52_12NgdotMulArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Int52_12NgdotMulArgs.ProtoReflect.Descriptor instead.
func (*Int52_12NgdotMulArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{10}
}
type PArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
X int64 `protobuf:"varint,1,opt,name=x,proto3" json:"x,omitempty"`
Y int64 `protobuf:"varint,2,opt,name=y,proto3" json:"y,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PArgs) Reset() {
*x = PArgs{}
mi := &file_ngolofuzz_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PArgs) ProtoMessage() {}
func (x *PArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[11]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PArgs.ProtoReflect.Descriptor instead.
func (*PArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{11}
}
func (x *PArgs) GetX() int64 {
if x != nil {
return x.X
}
return 0
}
func (x *PArgs) GetY() int64 {
if x != nil {
return x.Y
}
return 0
}
type Point26_6NgdotAddArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Point26_6NgdotAddArgs) Reset() {
*x = Point26_6NgdotAddArgs{}
mi := &file_ngolofuzz_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Point26_6NgdotAddArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Point26_6NgdotAddArgs) ProtoMessage() {}
func (x *Point26_6NgdotAddArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[12]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Point26_6NgdotAddArgs.ProtoReflect.Descriptor instead.
func (*Point26_6NgdotAddArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{12}
}
type Point26_6NgdotSubArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Point26_6NgdotSubArgs) Reset() {
*x = Point26_6NgdotSubArgs{}
mi := &file_ngolofuzz_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Point26_6NgdotSubArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Point26_6NgdotSubArgs) ProtoMessage() {}
func (x *Point26_6NgdotSubArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[13]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Point26_6NgdotSubArgs.ProtoReflect.Descriptor instead.
func (*Point26_6NgdotSubArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{13}
}
type Point26_6NgdotMulArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Point26_6NgdotMulArgs) Reset() {
*x = Point26_6NgdotMulArgs{}
mi := &file_ngolofuzz_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Point26_6NgdotMulArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Point26_6NgdotMulArgs) ProtoMessage() {}
func (x *Point26_6NgdotMulArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[14]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Point26_6NgdotMulArgs.ProtoReflect.Descriptor instead.
func (*Point26_6NgdotMulArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{14}
}
type Point26_6NgdotDivArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Point26_6NgdotDivArgs) Reset() {
*x = Point26_6NgdotDivArgs{}
mi := &file_ngolofuzz_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Point26_6NgdotDivArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Point26_6NgdotDivArgs) ProtoMessage() {}
func (x *Point26_6NgdotDivArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[15]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Point26_6NgdotDivArgs.ProtoReflect.Descriptor instead.
func (*Point26_6NgdotDivArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{15}
}
type Point26_6NgdotInArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Point26_6NgdotInArgs) Reset() {
*x = Point26_6NgdotInArgs{}
mi := &file_ngolofuzz_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Point26_6NgdotInArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Point26_6NgdotInArgs) ProtoMessage() {}
func (x *Point26_6NgdotInArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[16]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Point26_6NgdotInArgs.ProtoReflect.Descriptor instead.
func (*Point26_6NgdotInArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{16}
}
type Point52_12NgdotAddArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Point52_12NgdotAddArgs) Reset() {
*x = Point52_12NgdotAddArgs{}
mi := &file_ngolofuzz_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Point52_12NgdotAddArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Point52_12NgdotAddArgs) ProtoMessage() {}
func (x *Point52_12NgdotAddArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[17]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Point52_12NgdotAddArgs.ProtoReflect.Descriptor instead.
func (*Point52_12NgdotAddArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{17}
}
type Point52_12NgdotSubArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Point52_12NgdotSubArgs) Reset() {
*x = Point52_12NgdotSubArgs{}
mi := &file_ngolofuzz_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Point52_12NgdotSubArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Point52_12NgdotSubArgs) ProtoMessage() {}
func (x *Point52_12NgdotSubArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[18]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Point52_12NgdotSubArgs.ProtoReflect.Descriptor instead.
func (*Point52_12NgdotSubArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{18}
}
type Point52_12NgdotMulArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Point52_12NgdotMulArgs) Reset() {
*x = Point52_12NgdotMulArgs{}
mi := &file_ngolofuzz_proto_msgTypes[19]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Point52_12NgdotMulArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Point52_12NgdotMulArgs) ProtoMessage() {}
func (x *Point52_12NgdotMulArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[19]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Point52_12NgdotMulArgs.ProtoReflect.Descriptor instead.
func (*Point52_12NgdotMulArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{19}
}
type Point52_12NgdotDivArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Point52_12NgdotDivArgs) Reset() {
*x = Point52_12NgdotDivArgs{}
mi := &file_ngolofuzz_proto_msgTypes[20]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Point52_12NgdotDivArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Point52_12NgdotDivArgs) ProtoMessage() {}
func (x *Point52_12NgdotDivArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[20]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Point52_12NgdotDivArgs.ProtoReflect.Descriptor instead.
func (*Point52_12NgdotDivArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{20}
}
type Point52_12NgdotInArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Point52_12NgdotInArgs) Reset() {
*x = Point52_12NgdotInArgs{}
mi := &file_ngolofuzz_proto_msgTypes[21]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Point52_12NgdotInArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Point52_12NgdotInArgs) ProtoMessage() {}
func (x *Point52_12NgdotInArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[21]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Point52_12NgdotInArgs.ProtoReflect.Descriptor instead.
func (*Point52_12NgdotInArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{21}
}
type RArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
MinX int64 `protobuf:"varint,1,opt,name=minX,proto3" json:"minX,omitempty"`
MinY int64 `protobuf:"varint,2,opt,name=minY,proto3" json:"minY,omitempty"`
MaxX int64 `protobuf:"varint,3,opt,name=maxX,proto3" json:"maxX,omitempty"`
MaxY int64 `protobuf:"varint,4,opt,name=maxY,proto3" json:"maxY,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RArgs) Reset() {
*x = RArgs{}
mi := &file_ngolofuzz_proto_msgTypes[22]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RArgs) ProtoMessage() {}
func (x *RArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[22]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RArgs.ProtoReflect.Descriptor instead.
func (*RArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{22}
}
func (x *RArgs) GetMinX() int64 {
if x != nil {
return x.MinX
}
return 0
}
func (x *RArgs) GetMinY() int64 {
if x != nil {
return x.MinY
}
return 0
}
func (x *RArgs) GetMaxX() int64 {
if x != nil {
return x.MaxX
}
return 0
}
func (x *RArgs) GetMaxY() int64 {
if x != nil {
return x.MaxY
}
return 0
}
type Rectangle26_6NgdotAddArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Rectangle26_6NgdotAddArgs) Reset() {
*x = Rectangle26_6NgdotAddArgs{}
mi := &file_ngolofuzz_proto_msgTypes[23]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Rectangle26_6NgdotAddArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Rectangle26_6NgdotAddArgs) ProtoMessage() {}
func (x *Rectangle26_6NgdotAddArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[23]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Rectangle26_6NgdotAddArgs.ProtoReflect.Descriptor instead.
func (*Rectangle26_6NgdotAddArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{23}
}
type Rectangle26_6NgdotSubArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Rectangle26_6NgdotSubArgs) Reset() {
*x = Rectangle26_6NgdotSubArgs{}
mi := &file_ngolofuzz_proto_msgTypes[24]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Rectangle26_6NgdotSubArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Rectangle26_6NgdotSubArgs) ProtoMessage() {}
func (x *Rectangle26_6NgdotSubArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[24]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Rectangle26_6NgdotSubArgs.ProtoReflect.Descriptor instead.
func (*Rectangle26_6NgdotSubArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{24}
}
type Rectangle26_6NgdotIntersectArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Rectangle26_6NgdotIntersectArgs) Reset() {
*x = Rectangle26_6NgdotIntersectArgs{}
mi := &file_ngolofuzz_proto_msgTypes[25]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Rectangle26_6NgdotIntersectArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Rectangle26_6NgdotIntersectArgs) ProtoMessage() {}
func (x *Rectangle26_6NgdotIntersectArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[25]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Rectangle26_6NgdotIntersectArgs.ProtoReflect.Descriptor instead.
func (*Rectangle26_6NgdotIntersectArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{25}
}
type Rectangle26_6NgdotUnionArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Rectangle26_6NgdotUnionArgs) Reset() {
*x = Rectangle26_6NgdotUnionArgs{}
mi := &file_ngolofuzz_proto_msgTypes[26]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Rectangle26_6NgdotUnionArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Rectangle26_6NgdotUnionArgs) ProtoMessage() {}
func (x *Rectangle26_6NgdotUnionArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[26]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Rectangle26_6NgdotUnionArgs.ProtoReflect.Descriptor instead.
func (*Rectangle26_6NgdotUnionArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{26}
}
type Rectangle26_6NgdotEmptyArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Rectangle26_6NgdotEmptyArgs) Reset() {
*x = Rectangle26_6NgdotEmptyArgs{}
mi := &file_ngolofuzz_proto_msgTypes[27]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Rectangle26_6NgdotEmptyArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Rectangle26_6NgdotEmptyArgs) ProtoMessage() {}
func (x *Rectangle26_6NgdotEmptyArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[27]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Rectangle26_6NgdotEmptyArgs.ProtoReflect.Descriptor instead.
func (*Rectangle26_6NgdotEmptyArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{27}
}
type Rectangle26_6NgdotInArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Rectangle26_6NgdotInArgs) Reset() {
*x = Rectangle26_6NgdotInArgs{}
mi := &file_ngolofuzz_proto_msgTypes[28]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Rectangle26_6NgdotInArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Rectangle26_6NgdotInArgs) ProtoMessage() {}
func (x *Rectangle26_6NgdotInArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[28]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Rectangle26_6NgdotInArgs.ProtoReflect.Descriptor instead.
func (*Rectangle26_6NgdotInArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{28}
}
type Rectangle52_12NgdotAddArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Rectangle52_12NgdotAddArgs) Reset() {
*x = Rectangle52_12NgdotAddArgs{}
mi := &file_ngolofuzz_proto_msgTypes[29]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Rectangle52_12NgdotAddArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Rectangle52_12NgdotAddArgs) ProtoMessage() {}
func (x *Rectangle52_12NgdotAddArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[29]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Rectangle52_12NgdotAddArgs.ProtoReflect.Descriptor instead.
func (*Rectangle52_12NgdotAddArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{29}
}
type Rectangle52_12NgdotSubArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Rectangle52_12NgdotSubArgs) Reset() {
*x = Rectangle52_12NgdotSubArgs{}
mi := &file_ngolofuzz_proto_msgTypes[30]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Rectangle52_12NgdotSubArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Rectangle52_12NgdotSubArgs) ProtoMessage() {}
func (x *Rectangle52_12NgdotSubArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[30]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Rectangle52_12NgdotSubArgs.ProtoReflect.Descriptor instead.
func (*Rectangle52_12NgdotSubArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{30}
}
type Rectangle52_12NgdotIntersectArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Rectangle52_12NgdotIntersectArgs) Reset() {
*x = Rectangle52_12NgdotIntersectArgs{}
mi := &file_ngolofuzz_proto_msgTypes[31]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Rectangle52_12NgdotIntersectArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Rectangle52_12NgdotIntersectArgs) ProtoMessage() {}
func (x *Rectangle52_12NgdotIntersectArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[31]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Rectangle52_12NgdotIntersectArgs.ProtoReflect.Descriptor instead.
func (*Rectangle52_12NgdotIntersectArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{31}
}
type Rectangle52_12NgdotUnionArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Rectangle52_12NgdotUnionArgs) Reset() {
*x = Rectangle52_12NgdotUnionArgs{}
mi := &file_ngolofuzz_proto_msgTypes[32]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Rectangle52_12NgdotUnionArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Rectangle52_12NgdotUnionArgs) ProtoMessage() {}
func (x *Rectangle52_12NgdotUnionArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[32]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Rectangle52_12NgdotUnionArgs.ProtoReflect.Descriptor instead.
func (*Rectangle52_12NgdotUnionArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{32}
}
type Rectangle52_12NgdotEmptyArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Rectangle52_12NgdotEmptyArgs) Reset() {
*x = Rectangle52_12NgdotEmptyArgs{}
mi := &file_ngolofuzz_proto_msgTypes[33]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Rectangle52_12NgdotEmptyArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Rectangle52_12NgdotEmptyArgs) ProtoMessage() {}
func (x *Rectangle52_12NgdotEmptyArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[33]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Rectangle52_12NgdotEmptyArgs.ProtoReflect.Descriptor instead.
func (*Rectangle52_12NgdotEmptyArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{33}
}
type Rectangle52_12NgdotInArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Rectangle52_12NgdotInArgs) Reset() {
*x = Rectangle52_12NgdotInArgs{}
mi := &file_ngolofuzz_proto_msgTypes[34]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Rectangle52_12NgdotInArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Rectangle52_12NgdotInArgs) ProtoMessage() {}
func (x *Rectangle52_12NgdotInArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[34]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Rectangle52_12NgdotInArgs.ProtoReflect.Descriptor instead.
func (*Rectangle52_12NgdotInArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{34}
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_I
// *NgoloFuzzOne_Int26_6NgdotString
// *NgoloFuzzOne_Int26_6NgdotFloor
// *NgoloFuzzOne_Int26_6NgdotRound
// *NgoloFuzzOne_Int26_6NgdotCeil
// *NgoloFuzzOne_Int26_6NgdotMul
// *NgoloFuzzOne_Int52_12NgdotString
// *NgoloFuzzOne_Int52_12NgdotFloor
// *NgoloFuzzOne_Int52_12NgdotRound
// *NgoloFuzzOne_Int52_12NgdotCeil
// *NgoloFuzzOne_Int52_12NgdotMul
// *NgoloFuzzOne_P
// *NgoloFuzzOne_Point26_6NgdotAdd
// *NgoloFuzzOne_Point26_6NgdotSub
// *NgoloFuzzOne_Point26_6NgdotMul
// *NgoloFuzzOne_Point26_6NgdotDiv
// *NgoloFuzzOne_Point26_6NgdotIn
// *NgoloFuzzOne_Point52_12NgdotAdd
// *NgoloFuzzOne_Point52_12NgdotSub
// *NgoloFuzzOne_Point52_12NgdotMul
// *NgoloFuzzOne_Point52_12NgdotDiv
// *NgoloFuzzOne_Point52_12NgdotIn
// *NgoloFuzzOne_R
// *NgoloFuzzOne_Rectangle26_6NgdotAdd
// *NgoloFuzzOne_Rectangle26_6NgdotSub
// *NgoloFuzzOne_Rectangle26_6NgdotIntersect
// *NgoloFuzzOne_Rectangle26_6NgdotUnion
// *NgoloFuzzOne_Rectangle26_6NgdotEmpty
// *NgoloFuzzOne_Rectangle26_6NgdotIn
// *NgoloFuzzOne_Rectangle52_12NgdotAdd
// *NgoloFuzzOne_Rectangle52_12NgdotSub
// *NgoloFuzzOne_Rectangle52_12NgdotIntersect
// *NgoloFuzzOne_Rectangle52_12NgdotUnion
// *NgoloFuzzOne_Rectangle52_12NgdotEmpty
// *NgoloFuzzOne_Rectangle52_12NgdotIn
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[35]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[35]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{35}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetI() *IArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_I); ok {
return x.I
}
}
return nil
}
func (x *NgoloFuzzOne) GetInt26_6NgdotString() *Int26_6NgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Int26_6NgdotString); ok {
return x.Int26_6NgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetInt26_6NgdotFloor() *Int26_6NgdotFloorArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Int26_6NgdotFloor); ok {
return x.Int26_6NgdotFloor
}
}
return nil
}
func (x *NgoloFuzzOne) GetInt26_6NgdotRound() *Int26_6NgdotRoundArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Int26_6NgdotRound); ok {
return x.Int26_6NgdotRound
}
}
return nil
}
func (x *NgoloFuzzOne) GetInt26_6NgdotCeil() *Int26_6NgdotCeilArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Int26_6NgdotCeil); ok {
return x.Int26_6NgdotCeil
}
}
return nil
}
func (x *NgoloFuzzOne) GetInt26_6NgdotMul() *Int26_6NgdotMulArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Int26_6NgdotMul); ok {
return x.Int26_6NgdotMul
}
}
return nil
}
func (x *NgoloFuzzOne) GetInt52_12NgdotString() *Int52_12NgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Int52_12NgdotString); ok {
return x.Int52_12NgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetInt52_12NgdotFloor() *Int52_12NgdotFloorArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Int52_12NgdotFloor); ok {
return x.Int52_12NgdotFloor
}
}
return nil
}
func (x *NgoloFuzzOne) GetInt52_12NgdotRound() *Int52_12NgdotRoundArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Int52_12NgdotRound); ok {
return x.Int52_12NgdotRound
}
}
return nil
}
func (x *NgoloFuzzOne) GetInt52_12NgdotCeil() *Int52_12NgdotCeilArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Int52_12NgdotCeil); ok {
return x.Int52_12NgdotCeil
}
}
return nil
}
func (x *NgoloFuzzOne) GetInt52_12NgdotMul() *Int52_12NgdotMulArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Int52_12NgdotMul); ok {
return x.Int52_12NgdotMul
}
}
return nil
}
func (x *NgoloFuzzOne) GetP() *PArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_P); ok {
return x.P
}
}
return nil
}
func (x *NgoloFuzzOne) GetPoint26_6NgdotAdd() *Point26_6NgdotAddArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Point26_6NgdotAdd); ok {
return x.Point26_6NgdotAdd
}
}
return nil
}
func (x *NgoloFuzzOne) GetPoint26_6NgdotSub() *Point26_6NgdotSubArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Point26_6NgdotSub); ok {
return x.Point26_6NgdotSub
}
}
return nil
}
func (x *NgoloFuzzOne) GetPoint26_6NgdotMul() *Point26_6NgdotMulArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Point26_6NgdotMul); ok {
return x.Point26_6NgdotMul
}
}
return nil
}
func (x *NgoloFuzzOne) GetPoint26_6NgdotDiv() *Point26_6NgdotDivArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Point26_6NgdotDiv); ok {
return x.Point26_6NgdotDiv
}
}
return nil
}
func (x *NgoloFuzzOne) GetPoint26_6NgdotIn() *Point26_6NgdotInArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Point26_6NgdotIn); ok {
return x.Point26_6NgdotIn
}
}
return nil
}
func (x *NgoloFuzzOne) GetPoint52_12NgdotAdd() *Point52_12NgdotAddArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Point52_12NgdotAdd); ok {
return x.Point52_12NgdotAdd
}
}
return nil
}
func (x *NgoloFuzzOne) GetPoint52_12NgdotSub() *Point52_12NgdotSubArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Point52_12NgdotSub); ok {
return x.Point52_12NgdotSub
}
}
return nil
}
func (x *NgoloFuzzOne) GetPoint52_12NgdotMul() *Point52_12NgdotMulArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Point52_12NgdotMul); ok {
return x.Point52_12NgdotMul
}
}
return nil
}
func (x *NgoloFuzzOne) GetPoint52_12NgdotDiv() *Point52_12NgdotDivArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Point52_12NgdotDiv); ok {
return x.Point52_12NgdotDiv
}
}
return nil
}
func (x *NgoloFuzzOne) GetPoint52_12NgdotIn() *Point52_12NgdotInArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Point52_12NgdotIn); ok {
return x.Point52_12NgdotIn
}
}
return nil
}
func (x *NgoloFuzzOne) GetR() *RArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_R); ok {
return x.R
}
}
return nil
}
func (x *NgoloFuzzOne) GetRectangle26_6NgdotAdd() *Rectangle26_6NgdotAddArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Rectangle26_6NgdotAdd); ok {
return x.Rectangle26_6NgdotAdd
}
}
return nil
}
func (x *NgoloFuzzOne) GetRectangle26_6NgdotSub() *Rectangle26_6NgdotSubArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Rectangle26_6NgdotSub); ok {
return x.Rectangle26_6NgdotSub
}
}
return nil
}
func (x *NgoloFuzzOne) GetRectangle26_6NgdotIntersect() *Rectangle26_6NgdotIntersectArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Rectangle26_6NgdotIntersect); ok {
return x.Rectangle26_6NgdotIntersect
}
}
return nil
}
func (x *NgoloFuzzOne) GetRectangle26_6NgdotUnion() *Rectangle26_6NgdotUnionArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Rectangle26_6NgdotUnion); ok {
return x.Rectangle26_6NgdotUnion
}
}
return nil
}
func (x *NgoloFuzzOne) GetRectangle26_6NgdotEmpty() *Rectangle26_6NgdotEmptyArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Rectangle26_6NgdotEmpty); ok {
return x.Rectangle26_6NgdotEmpty
}
}
return nil
}
func (x *NgoloFuzzOne) GetRectangle26_6NgdotIn() *Rectangle26_6NgdotInArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Rectangle26_6NgdotIn); ok {
return x.Rectangle26_6NgdotIn
}
}
return nil
}
func (x *NgoloFuzzOne) GetRectangle52_12NgdotAdd() *Rectangle52_12NgdotAddArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Rectangle52_12NgdotAdd); ok {
return x.Rectangle52_12NgdotAdd
}
}
return nil
}
func (x *NgoloFuzzOne) GetRectangle52_12NgdotSub() *Rectangle52_12NgdotSubArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Rectangle52_12NgdotSub); ok {
return x.Rectangle52_12NgdotSub
}
}
return nil
}
func (x *NgoloFuzzOne) GetRectangle52_12NgdotIntersect() *Rectangle52_12NgdotIntersectArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Rectangle52_12NgdotIntersect); ok {
return x.Rectangle52_12NgdotIntersect
}
}
return nil
}
func (x *NgoloFuzzOne) GetRectangle52_12NgdotUnion() *Rectangle52_12NgdotUnionArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Rectangle52_12NgdotUnion); ok {
return x.Rectangle52_12NgdotUnion
}
}
return nil
}
func (x *NgoloFuzzOne) GetRectangle52_12NgdotEmpty() *Rectangle52_12NgdotEmptyArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Rectangle52_12NgdotEmpty); ok {
return x.Rectangle52_12NgdotEmpty
}
}
return nil
}
func (x *NgoloFuzzOne) GetRectangle52_12NgdotIn() *Rectangle52_12NgdotInArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Rectangle52_12NgdotIn); ok {
return x.Rectangle52_12NgdotIn
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_I struct {
I *IArgs `protobuf:"bytes,1,opt,name=I,proto3,oneof"`
}
type NgoloFuzzOne_Int26_6NgdotString struct {
Int26_6NgdotString *Int26_6NgdotStringArgs `protobuf:"bytes,2,opt,name=Int26_6NgdotString,json=Int266NgdotString,proto3,oneof"`
}
type NgoloFuzzOne_Int26_6NgdotFloor struct {
Int26_6NgdotFloor *Int26_6NgdotFloorArgs `protobuf:"bytes,3,opt,name=Int26_6NgdotFloor,json=Int266NgdotFloor,proto3,oneof"`
}
type NgoloFuzzOne_Int26_6NgdotRound struct {
Int26_6NgdotRound *Int26_6NgdotRoundArgs `protobuf:"bytes,4,opt,name=Int26_6NgdotRound,json=Int266NgdotRound,proto3,oneof"`
}
type NgoloFuzzOne_Int26_6NgdotCeil struct {
Int26_6NgdotCeil *Int26_6NgdotCeilArgs `protobuf:"bytes,5,opt,name=Int26_6NgdotCeil,json=Int266NgdotCeil,proto3,oneof"`
}
type NgoloFuzzOne_Int26_6NgdotMul struct {
Int26_6NgdotMul *Int26_6NgdotMulArgs `protobuf:"bytes,6,opt,name=Int26_6NgdotMul,json=Int266NgdotMul,proto3,oneof"`
}
type NgoloFuzzOne_Int52_12NgdotString struct {
Int52_12NgdotString *Int52_12NgdotStringArgs `protobuf:"bytes,7,opt,name=Int52_12NgdotString,json=Int5212NgdotString,proto3,oneof"`
}
type NgoloFuzzOne_Int52_12NgdotFloor struct {
Int52_12NgdotFloor *Int52_12NgdotFloorArgs `protobuf:"bytes,8,opt,name=Int52_12NgdotFloor,json=Int5212NgdotFloor,proto3,oneof"`
}
type NgoloFuzzOne_Int52_12NgdotRound struct {
Int52_12NgdotRound *Int52_12NgdotRoundArgs `protobuf:"bytes,9,opt,name=Int52_12NgdotRound,json=Int5212NgdotRound,proto3,oneof"`
}
type NgoloFuzzOne_Int52_12NgdotCeil struct {
Int52_12NgdotCeil *Int52_12NgdotCeilArgs `protobuf:"bytes,10,opt,name=Int52_12NgdotCeil,json=Int5212NgdotCeil,proto3,oneof"`
}
type NgoloFuzzOne_Int52_12NgdotMul struct {
Int52_12NgdotMul *Int52_12NgdotMulArgs `protobuf:"bytes,11,opt,name=Int52_12NgdotMul,json=Int5212NgdotMul,proto3,oneof"`
}
type NgoloFuzzOne_P struct {
P *PArgs `protobuf:"bytes,12,opt,name=P,proto3,oneof"`
}
type NgoloFuzzOne_Point26_6NgdotAdd struct {
Point26_6NgdotAdd *Point26_6NgdotAddArgs `protobuf:"bytes,13,opt,name=Point26_6NgdotAdd,json=Point266NgdotAdd,proto3,oneof"`
}
type NgoloFuzzOne_Point26_6NgdotSub struct {
Point26_6NgdotSub *Point26_6NgdotSubArgs `protobuf:"bytes,14,opt,name=Point26_6NgdotSub,json=Point266NgdotSub,proto3,oneof"`
}
type NgoloFuzzOne_Point26_6NgdotMul struct {
Point26_6NgdotMul *Point26_6NgdotMulArgs `protobuf:"bytes,15,opt,name=Point26_6NgdotMul,json=Point266NgdotMul,proto3,oneof"`
}
type NgoloFuzzOne_Point26_6NgdotDiv struct {
Point26_6NgdotDiv *Point26_6NgdotDivArgs `protobuf:"bytes,16,opt,name=Point26_6NgdotDiv,json=Point266NgdotDiv,proto3,oneof"`
}
type NgoloFuzzOne_Point26_6NgdotIn struct {
Point26_6NgdotIn *Point26_6NgdotInArgs `protobuf:"bytes,17,opt,name=Point26_6NgdotIn,json=Point266NgdotIn,proto3,oneof"`
}
type NgoloFuzzOne_Point52_12NgdotAdd struct {
Point52_12NgdotAdd *Point52_12NgdotAddArgs `protobuf:"bytes,18,opt,name=Point52_12NgdotAdd,json=Point5212NgdotAdd,proto3,oneof"`
}
type NgoloFuzzOne_Point52_12NgdotSub struct {
Point52_12NgdotSub *Point52_12NgdotSubArgs `protobuf:"bytes,19,opt,name=Point52_12NgdotSub,json=Point5212NgdotSub,proto3,oneof"`
}
type NgoloFuzzOne_Point52_12NgdotMul struct {
Point52_12NgdotMul *Point52_12NgdotMulArgs `protobuf:"bytes,20,opt,name=Point52_12NgdotMul,json=Point5212NgdotMul,proto3,oneof"`
}
type NgoloFuzzOne_Point52_12NgdotDiv struct {
Point52_12NgdotDiv *Point52_12NgdotDivArgs `protobuf:"bytes,21,opt,name=Point52_12NgdotDiv,json=Point5212NgdotDiv,proto3,oneof"`
}
type NgoloFuzzOne_Point52_12NgdotIn struct {
Point52_12NgdotIn *Point52_12NgdotInArgs `protobuf:"bytes,22,opt,name=Point52_12NgdotIn,json=Point5212NgdotIn,proto3,oneof"`
}
type NgoloFuzzOne_R struct {
R *RArgs `protobuf:"bytes,23,opt,name=R,proto3,oneof"`
}
type NgoloFuzzOne_Rectangle26_6NgdotAdd struct {
Rectangle26_6NgdotAdd *Rectangle26_6NgdotAddArgs `protobuf:"bytes,24,opt,name=Rectangle26_6NgdotAdd,json=Rectangle266NgdotAdd,proto3,oneof"`
}
type NgoloFuzzOne_Rectangle26_6NgdotSub struct {
Rectangle26_6NgdotSub *Rectangle26_6NgdotSubArgs `protobuf:"bytes,25,opt,name=Rectangle26_6NgdotSub,json=Rectangle266NgdotSub,proto3,oneof"`
}
type NgoloFuzzOne_Rectangle26_6NgdotIntersect struct {
Rectangle26_6NgdotIntersect *Rectangle26_6NgdotIntersectArgs `protobuf:"bytes,26,opt,name=Rectangle26_6NgdotIntersect,json=Rectangle266NgdotIntersect,proto3,oneof"`
}
type NgoloFuzzOne_Rectangle26_6NgdotUnion struct {
Rectangle26_6NgdotUnion *Rectangle26_6NgdotUnionArgs `protobuf:"bytes,27,opt,name=Rectangle26_6NgdotUnion,json=Rectangle266NgdotUnion,proto3,oneof"`
}
type NgoloFuzzOne_Rectangle26_6NgdotEmpty struct {
Rectangle26_6NgdotEmpty *Rectangle26_6NgdotEmptyArgs `protobuf:"bytes,28,opt,name=Rectangle26_6NgdotEmpty,json=Rectangle266NgdotEmpty,proto3,oneof"`
}
type NgoloFuzzOne_Rectangle26_6NgdotIn struct {
Rectangle26_6NgdotIn *Rectangle26_6NgdotInArgs `protobuf:"bytes,29,opt,name=Rectangle26_6NgdotIn,json=Rectangle266NgdotIn,proto3,oneof"`
}
type NgoloFuzzOne_Rectangle52_12NgdotAdd struct {
Rectangle52_12NgdotAdd *Rectangle52_12NgdotAddArgs `protobuf:"bytes,30,opt,name=Rectangle52_12NgdotAdd,json=Rectangle5212NgdotAdd,proto3,oneof"`
}
type NgoloFuzzOne_Rectangle52_12NgdotSub struct {
Rectangle52_12NgdotSub *Rectangle52_12NgdotSubArgs `protobuf:"bytes,31,opt,name=Rectangle52_12NgdotSub,json=Rectangle5212NgdotSub,proto3,oneof"`
}
type NgoloFuzzOne_Rectangle52_12NgdotIntersect struct {
Rectangle52_12NgdotIntersect *Rectangle52_12NgdotIntersectArgs `protobuf:"bytes,32,opt,name=Rectangle52_12NgdotIntersect,json=Rectangle5212NgdotIntersect,proto3,oneof"`
}
type NgoloFuzzOne_Rectangle52_12NgdotUnion struct {
Rectangle52_12NgdotUnion *Rectangle52_12NgdotUnionArgs `protobuf:"bytes,33,opt,name=Rectangle52_12NgdotUnion,json=Rectangle5212NgdotUnion,proto3,oneof"`
}
type NgoloFuzzOne_Rectangle52_12NgdotEmpty struct {
Rectangle52_12NgdotEmpty *Rectangle52_12NgdotEmptyArgs `protobuf:"bytes,34,opt,name=Rectangle52_12NgdotEmpty,json=Rectangle5212NgdotEmpty,proto3,oneof"`
}
type NgoloFuzzOne_Rectangle52_12NgdotIn struct {
Rectangle52_12NgdotIn *Rectangle52_12NgdotInArgs `protobuf:"bytes,35,opt,name=Rectangle52_12NgdotIn,json=Rectangle5212NgdotIn,proto3,oneof"`
}
func (*NgoloFuzzOne_I) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Int26_6NgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Int26_6NgdotFloor) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Int26_6NgdotRound) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Int26_6NgdotCeil) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Int26_6NgdotMul) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Int52_12NgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Int52_12NgdotFloor) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Int52_12NgdotRound) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Int52_12NgdotCeil) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Int52_12NgdotMul) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_P) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Point26_6NgdotAdd) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Point26_6NgdotSub) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Point26_6NgdotMul) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Point26_6NgdotDiv) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Point26_6NgdotIn) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Point52_12NgdotAdd) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Point52_12NgdotSub) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Point52_12NgdotMul) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Point52_12NgdotDiv) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Point52_12NgdotIn) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_R) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Rectangle26_6NgdotAdd) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Rectangle26_6NgdotSub) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Rectangle26_6NgdotIntersect) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Rectangle26_6NgdotUnion) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Rectangle26_6NgdotEmpty) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Rectangle26_6NgdotIn) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Rectangle52_12NgdotAdd) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Rectangle52_12NgdotSub) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Rectangle52_12NgdotIntersect) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Rectangle52_12NgdotUnion) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Rectangle52_12NgdotEmpty) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Rectangle52_12NgdotIn) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[36]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[36]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{36}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[37]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[37]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{37}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x15\n" +
"\x05IArgs\x12\f\n" +
"\x01i\x18\x01 \x01(\x03R\x01i\"\x18\n" +
"\x16Int26_6NgdotStringArgs\"\x17\n" +
"\x15Int26_6NgdotFloorArgs\"\x17\n" +
"\x15Int26_6NgdotRoundArgs\"\x16\n" +
"\x14Int26_6NgdotCeilArgs\"\x15\n" +
"\x13Int26_6NgdotMulArgs\"\x19\n" +
"\x17Int52_12NgdotStringArgs\"\x18\n" +
"\x16Int52_12NgdotFloorArgs\"\x18\n" +
"\x16Int52_12NgdotRoundArgs\"\x17\n" +
"\x15Int52_12NgdotCeilArgs\"\x16\n" +
"\x14Int52_12NgdotMulArgs\"#\n" +
"\x05PArgs\x12\f\n" +
"\x01x\x18\x01 \x01(\x03R\x01x\x12\f\n" +
"\x01y\x18\x02 \x01(\x03R\x01y\"\x17\n" +
"\x15Point26_6NgdotAddArgs\"\x17\n" +
"\x15Point26_6NgdotSubArgs\"\x17\n" +
"\x15Point26_6NgdotMulArgs\"\x17\n" +
"\x15Point26_6NgdotDivArgs\"\x16\n" +
"\x14Point26_6NgdotInArgs\"\x18\n" +
"\x16Point52_12NgdotAddArgs\"\x18\n" +
"\x16Point52_12NgdotSubArgs\"\x18\n" +
"\x16Point52_12NgdotMulArgs\"\x18\n" +
"\x16Point52_12NgdotDivArgs\"\x17\n" +
"\x15Point52_12NgdotInArgs\"W\n" +
"\x05RArgs\x12\x12\n" +
"\x04minX\x18\x01 \x01(\x03R\x04minX\x12\x12\n" +
"\x04minY\x18\x02 \x01(\x03R\x04minY\x12\x12\n" +
"\x04maxX\x18\x03 \x01(\x03R\x04maxX\x12\x12\n" +
"\x04maxY\x18\x04 \x01(\x03R\x04maxY\"\x1b\n" +
"\x19Rectangle26_6NgdotAddArgs\"\x1b\n" +
"\x19Rectangle26_6NgdotSubArgs\"!\n" +
"\x1fRectangle26_6NgdotIntersectArgs\"\x1d\n" +
"\x1bRectangle26_6NgdotUnionArgs\"\x1d\n" +
"\x1bRectangle26_6NgdotEmptyArgs\"\x1a\n" +
"\x18Rectangle26_6NgdotInArgs\"\x1c\n" +
"\x1aRectangle52_12NgdotAddArgs\"\x1c\n" +
"\x1aRectangle52_12NgdotSubArgs\"\"\n" +
" Rectangle52_12NgdotIntersectArgs\"\x1e\n" +
"\x1cRectangle52_12NgdotUnionArgs\"\x1e\n" +
"\x1cRectangle52_12NgdotEmptyArgs\"\x1b\n" +
"\x19Rectangle52_12NgdotInArgs\"\x80\x17\n" +
"\fNgoloFuzzOne\x12 \n" +
"\x01I\x18\x01 \x01(\v2\x10.ngolofuzz.IArgsH\x00R\x01I\x12R\n" +
"\x12Int26_6NgdotString\x18\x02 \x01(\v2!.ngolofuzz.Int26_6NgdotStringArgsH\x00R\x11Int266NgdotString\x12O\n" +
"\x11Int26_6NgdotFloor\x18\x03 \x01(\v2 .ngolofuzz.Int26_6NgdotFloorArgsH\x00R\x10Int266NgdotFloor\x12O\n" +
"\x11Int26_6NgdotRound\x18\x04 \x01(\v2 .ngolofuzz.Int26_6NgdotRoundArgsH\x00R\x10Int266NgdotRound\x12L\n" +
"\x10Int26_6NgdotCeil\x18\x05 \x01(\v2\x1f.ngolofuzz.Int26_6NgdotCeilArgsH\x00R\x0fInt266NgdotCeil\x12I\n" +
"\x0fInt26_6NgdotMul\x18\x06 \x01(\v2\x1e.ngolofuzz.Int26_6NgdotMulArgsH\x00R\x0eInt266NgdotMul\x12U\n" +
"\x13Int52_12NgdotString\x18\a \x01(\v2\".ngolofuzz.Int52_12NgdotStringArgsH\x00R\x12Int5212NgdotString\x12R\n" +
"\x12Int52_12NgdotFloor\x18\b \x01(\v2!.ngolofuzz.Int52_12NgdotFloorArgsH\x00R\x11Int5212NgdotFloor\x12R\n" +
"\x12Int52_12NgdotRound\x18\t \x01(\v2!.ngolofuzz.Int52_12NgdotRoundArgsH\x00R\x11Int5212NgdotRound\x12O\n" +
"\x11Int52_12NgdotCeil\x18\n" +
" \x01(\v2 .ngolofuzz.Int52_12NgdotCeilArgsH\x00R\x10Int5212NgdotCeil\x12L\n" +
"\x10Int52_12NgdotMul\x18\v \x01(\v2\x1f.ngolofuzz.Int52_12NgdotMulArgsH\x00R\x0fInt5212NgdotMul\x12 \n" +
"\x01P\x18\f \x01(\v2\x10.ngolofuzz.PArgsH\x00R\x01P\x12O\n" +
"\x11Point26_6NgdotAdd\x18\r \x01(\v2 .ngolofuzz.Point26_6NgdotAddArgsH\x00R\x10Point266NgdotAdd\x12O\n" +
"\x11Point26_6NgdotSub\x18\x0e \x01(\v2 .ngolofuzz.Point26_6NgdotSubArgsH\x00R\x10Point266NgdotSub\x12O\n" +
"\x11Point26_6NgdotMul\x18\x0f \x01(\v2 .ngolofuzz.Point26_6NgdotMulArgsH\x00R\x10Point266NgdotMul\x12O\n" +
"\x11Point26_6NgdotDiv\x18\x10 \x01(\v2 .ngolofuzz.Point26_6NgdotDivArgsH\x00R\x10Point266NgdotDiv\x12L\n" +
"\x10Point26_6NgdotIn\x18\x11 \x01(\v2\x1f.ngolofuzz.Point26_6NgdotInArgsH\x00R\x0fPoint266NgdotIn\x12R\n" +
"\x12Point52_12NgdotAdd\x18\x12 \x01(\v2!.ngolofuzz.Point52_12NgdotAddArgsH\x00R\x11Point5212NgdotAdd\x12R\n" +
"\x12Point52_12NgdotSub\x18\x13 \x01(\v2!.ngolofuzz.Point52_12NgdotSubArgsH\x00R\x11Point5212NgdotSub\x12R\n" +
"\x12Point52_12NgdotMul\x18\x14 \x01(\v2!.ngolofuzz.Point52_12NgdotMulArgsH\x00R\x11Point5212NgdotMul\x12R\n" +
"\x12Point52_12NgdotDiv\x18\x15 \x01(\v2!.ngolofuzz.Point52_12NgdotDivArgsH\x00R\x11Point5212NgdotDiv\x12O\n" +
"\x11Point52_12NgdotIn\x18\x16 \x01(\v2 .ngolofuzz.Point52_12NgdotInArgsH\x00R\x10Point5212NgdotIn\x12 \n" +
"\x01R\x18\x17 \x01(\v2\x10.ngolofuzz.RArgsH\x00R\x01R\x12[\n" +
"\x15Rectangle26_6NgdotAdd\x18\x18 \x01(\v2$.ngolofuzz.Rectangle26_6NgdotAddArgsH\x00R\x14Rectangle266NgdotAdd\x12[\n" +
"\x15Rectangle26_6NgdotSub\x18\x19 \x01(\v2$.ngolofuzz.Rectangle26_6NgdotSubArgsH\x00R\x14Rectangle266NgdotSub\x12m\n" +
"\x1bRectangle26_6NgdotIntersect\x18\x1a \x01(\v2*.ngolofuzz.Rectangle26_6NgdotIntersectArgsH\x00R\x1aRectangle266NgdotIntersect\x12a\n" +
"\x17Rectangle26_6NgdotUnion\x18\x1b \x01(\v2&.ngolofuzz.Rectangle26_6NgdotUnionArgsH\x00R\x16Rectangle266NgdotUnion\x12a\n" +
"\x17Rectangle26_6NgdotEmpty\x18\x1c \x01(\v2&.ngolofuzz.Rectangle26_6NgdotEmptyArgsH\x00R\x16Rectangle266NgdotEmpty\x12X\n" +
"\x14Rectangle26_6NgdotIn\x18\x1d \x01(\v2#.ngolofuzz.Rectangle26_6NgdotInArgsH\x00R\x13Rectangle266NgdotIn\x12^\n" +
"\x16Rectangle52_12NgdotAdd\x18\x1e \x01(\v2%.ngolofuzz.Rectangle52_12NgdotAddArgsH\x00R\x15Rectangle5212NgdotAdd\x12^\n" +
"\x16Rectangle52_12NgdotSub\x18\x1f \x01(\v2%.ngolofuzz.Rectangle52_12NgdotSubArgsH\x00R\x15Rectangle5212NgdotSub\x12p\n" +
"\x1cRectangle52_12NgdotIntersect\x18 \x01(\v2+.ngolofuzz.Rectangle52_12NgdotIntersectArgsH\x00R\x1bRectangle5212NgdotIntersect\x12d\n" +
"\x18Rectangle52_12NgdotUnion\x18! \x01(\v2'.ngolofuzz.Rectangle52_12NgdotUnionArgsH\x00R\x17Rectangle5212NgdotUnion\x12d\n" +
"\x18Rectangle52_12NgdotEmpty\x18\" \x01(\v2'.ngolofuzz.Rectangle52_12NgdotEmptyArgsH\x00R\x17Rectangle5212NgdotEmpty\x12[\n" +
"\x15Rectangle52_12NgdotIn\x18# \x01(\v2$.ngolofuzz.Rectangle52_12NgdotInArgsH\x00R\x14Rectangle5212NgdotInB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1fZ\x1d./;fuzz_ng_x_image_math_fixedb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 38)
var file_ngolofuzz_proto_goTypes = []any{
(*IArgs)(nil), // 0: ngolofuzz.IArgs
(*Int26_6NgdotStringArgs)(nil), // 1: ngolofuzz.Int26_6NgdotStringArgs
(*Int26_6NgdotFloorArgs)(nil), // 2: ngolofuzz.Int26_6NgdotFloorArgs
(*Int26_6NgdotRoundArgs)(nil), // 3: ngolofuzz.Int26_6NgdotRoundArgs
(*Int26_6NgdotCeilArgs)(nil), // 4: ngolofuzz.Int26_6NgdotCeilArgs
(*Int26_6NgdotMulArgs)(nil), // 5: ngolofuzz.Int26_6NgdotMulArgs
(*Int52_12NgdotStringArgs)(nil), // 6: ngolofuzz.Int52_12NgdotStringArgs
(*Int52_12NgdotFloorArgs)(nil), // 7: ngolofuzz.Int52_12NgdotFloorArgs
(*Int52_12NgdotRoundArgs)(nil), // 8: ngolofuzz.Int52_12NgdotRoundArgs
(*Int52_12NgdotCeilArgs)(nil), // 9: ngolofuzz.Int52_12NgdotCeilArgs
(*Int52_12NgdotMulArgs)(nil), // 10: ngolofuzz.Int52_12NgdotMulArgs
(*PArgs)(nil), // 11: ngolofuzz.PArgs
(*Point26_6NgdotAddArgs)(nil), // 12: ngolofuzz.Point26_6NgdotAddArgs
(*Point26_6NgdotSubArgs)(nil), // 13: ngolofuzz.Point26_6NgdotSubArgs
(*Point26_6NgdotMulArgs)(nil), // 14: ngolofuzz.Point26_6NgdotMulArgs
(*Point26_6NgdotDivArgs)(nil), // 15: ngolofuzz.Point26_6NgdotDivArgs
(*Point26_6NgdotInArgs)(nil), // 16: ngolofuzz.Point26_6NgdotInArgs
(*Point52_12NgdotAddArgs)(nil), // 17: ngolofuzz.Point52_12NgdotAddArgs
(*Point52_12NgdotSubArgs)(nil), // 18: ngolofuzz.Point52_12NgdotSubArgs
(*Point52_12NgdotMulArgs)(nil), // 19: ngolofuzz.Point52_12NgdotMulArgs
(*Point52_12NgdotDivArgs)(nil), // 20: ngolofuzz.Point52_12NgdotDivArgs
(*Point52_12NgdotInArgs)(nil), // 21: ngolofuzz.Point52_12NgdotInArgs
(*RArgs)(nil), // 22: ngolofuzz.RArgs
(*Rectangle26_6NgdotAddArgs)(nil), // 23: ngolofuzz.Rectangle26_6NgdotAddArgs
(*Rectangle26_6NgdotSubArgs)(nil), // 24: ngolofuzz.Rectangle26_6NgdotSubArgs
(*Rectangle26_6NgdotIntersectArgs)(nil), // 25: ngolofuzz.Rectangle26_6NgdotIntersectArgs
(*Rectangle26_6NgdotUnionArgs)(nil), // 26: ngolofuzz.Rectangle26_6NgdotUnionArgs
(*Rectangle26_6NgdotEmptyArgs)(nil), // 27: ngolofuzz.Rectangle26_6NgdotEmptyArgs
(*Rectangle26_6NgdotInArgs)(nil), // 28: ngolofuzz.Rectangle26_6NgdotInArgs
(*Rectangle52_12NgdotAddArgs)(nil), // 29: ngolofuzz.Rectangle52_12NgdotAddArgs
(*Rectangle52_12NgdotSubArgs)(nil), // 30: ngolofuzz.Rectangle52_12NgdotSubArgs
(*Rectangle52_12NgdotIntersectArgs)(nil), // 31: ngolofuzz.Rectangle52_12NgdotIntersectArgs
(*Rectangle52_12NgdotUnionArgs)(nil), // 32: ngolofuzz.Rectangle52_12NgdotUnionArgs
(*Rectangle52_12NgdotEmptyArgs)(nil), // 33: ngolofuzz.Rectangle52_12NgdotEmptyArgs
(*Rectangle52_12NgdotInArgs)(nil), // 34: ngolofuzz.Rectangle52_12NgdotInArgs
(*NgoloFuzzOne)(nil), // 35: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 36: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 37: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.I:type_name -> ngolofuzz.IArgs
1, // 1: ngolofuzz.NgoloFuzzOne.Int26_6NgdotString:type_name -> ngolofuzz.Int26_6NgdotStringArgs
2, // 2: ngolofuzz.NgoloFuzzOne.Int26_6NgdotFloor:type_name -> ngolofuzz.Int26_6NgdotFloorArgs
3, // 3: ngolofuzz.NgoloFuzzOne.Int26_6NgdotRound:type_name -> ngolofuzz.Int26_6NgdotRoundArgs
4, // 4: ngolofuzz.NgoloFuzzOne.Int26_6NgdotCeil:type_name -> ngolofuzz.Int26_6NgdotCeilArgs
5, // 5: ngolofuzz.NgoloFuzzOne.Int26_6NgdotMul:type_name -> ngolofuzz.Int26_6NgdotMulArgs
6, // 6: ngolofuzz.NgoloFuzzOne.Int52_12NgdotString:type_name -> ngolofuzz.Int52_12NgdotStringArgs
7, // 7: ngolofuzz.NgoloFuzzOne.Int52_12NgdotFloor:type_name -> ngolofuzz.Int52_12NgdotFloorArgs
8, // 8: ngolofuzz.NgoloFuzzOne.Int52_12NgdotRound:type_name -> ngolofuzz.Int52_12NgdotRoundArgs
9, // 9: ngolofuzz.NgoloFuzzOne.Int52_12NgdotCeil:type_name -> ngolofuzz.Int52_12NgdotCeilArgs
10, // 10: ngolofuzz.NgoloFuzzOne.Int52_12NgdotMul:type_name -> ngolofuzz.Int52_12NgdotMulArgs
11, // 11: ngolofuzz.NgoloFuzzOne.P:type_name -> ngolofuzz.PArgs
12, // 12: ngolofuzz.NgoloFuzzOne.Point26_6NgdotAdd:type_name -> ngolofuzz.Point26_6NgdotAddArgs
13, // 13: ngolofuzz.NgoloFuzzOne.Point26_6NgdotSub:type_name -> ngolofuzz.Point26_6NgdotSubArgs
14, // 14: ngolofuzz.NgoloFuzzOne.Point26_6NgdotMul:type_name -> ngolofuzz.Point26_6NgdotMulArgs
15, // 15: ngolofuzz.NgoloFuzzOne.Point26_6NgdotDiv:type_name -> ngolofuzz.Point26_6NgdotDivArgs
16, // 16: ngolofuzz.NgoloFuzzOne.Point26_6NgdotIn:type_name -> ngolofuzz.Point26_6NgdotInArgs
17, // 17: ngolofuzz.NgoloFuzzOne.Point52_12NgdotAdd:type_name -> ngolofuzz.Point52_12NgdotAddArgs
18, // 18: ngolofuzz.NgoloFuzzOne.Point52_12NgdotSub:type_name -> ngolofuzz.Point52_12NgdotSubArgs
19, // 19: ngolofuzz.NgoloFuzzOne.Point52_12NgdotMul:type_name -> ngolofuzz.Point52_12NgdotMulArgs
20, // 20: ngolofuzz.NgoloFuzzOne.Point52_12NgdotDiv:type_name -> ngolofuzz.Point52_12NgdotDivArgs
21, // 21: ngolofuzz.NgoloFuzzOne.Point52_12NgdotIn:type_name -> ngolofuzz.Point52_12NgdotInArgs
22, // 22: ngolofuzz.NgoloFuzzOne.R:type_name -> ngolofuzz.RArgs
23, // 23: ngolofuzz.NgoloFuzzOne.Rectangle26_6NgdotAdd:type_name -> ngolofuzz.Rectangle26_6NgdotAddArgs
24, // 24: ngolofuzz.NgoloFuzzOne.Rectangle26_6NgdotSub:type_name -> ngolofuzz.Rectangle26_6NgdotSubArgs
25, // 25: ngolofuzz.NgoloFuzzOne.Rectangle26_6NgdotIntersect:type_name -> ngolofuzz.Rectangle26_6NgdotIntersectArgs
26, // 26: ngolofuzz.NgoloFuzzOne.Rectangle26_6NgdotUnion:type_name -> ngolofuzz.Rectangle26_6NgdotUnionArgs
27, // 27: ngolofuzz.NgoloFuzzOne.Rectangle26_6NgdotEmpty:type_name -> ngolofuzz.Rectangle26_6NgdotEmptyArgs
28, // 28: ngolofuzz.NgoloFuzzOne.Rectangle26_6NgdotIn:type_name -> ngolofuzz.Rectangle26_6NgdotInArgs
29, // 29: ngolofuzz.NgoloFuzzOne.Rectangle52_12NgdotAdd:type_name -> ngolofuzz.Rectangle52_12NgdotAddArgs
30, // 30: ngolofuzz.NgoloFuzzOne.Rectangle52_12NgdotSub:type_name -> ngolofuzz.Rectangle52_12NgdotSubArgs
31, // 31: ngolofuzz.NgoloFuzzOne.Rectangle52_12NgdotIntersect:type_name -> ngolofuzz.Rectangle52_12NgdotIntersectArgs
32, // 32: ngolofuzz.NgoloFuzzOne.Rectangle52_12NgdotUnion:type_name -> ngolofuzz.Rectangle52_12NgdotUnionArgs
33, // 33: ngolofuzz.NgoloFuzzOne.Rectangle52_12NgdotEmpty:type_name -> ngolofuzz.Rectangle52_12NgdotEmptyArgs
34, // 34: ngolofuzz.NgoloFuzzOne.Rectangle52_12NgdotIn:type_name -> ngolofuzz.Rectangle52_12NgdotInArgs
35, // 35: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
36, // [36:36] is the sub-list for method output_type
36, // [36:36] is the sub-list for method input_type
36, // [36:36] is the sub-list for extension type_name
36, // [36:36] is the sub-list for extension extendee
0, // [0:36] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[35].OneofWrappers = []any{
(*NgoloFuzzOne_I)(nil),
(*NgoloFuzzOne_Int26_6NgdotString)(nil),
(*NgoloFuzzOne_Int26_6NgdotFloor)(nil),
(*NgoloFuzzOne_Int26_6NgdotRound)(nil),
(*NgoloFuzzOne_Int26_6NgdotCeil)(nil),
(*NgoloFuzzOne_Int26_6NgdotMul)(nil),
(*NgoloFuzzOne_Int52_12NgdotString)(nil),
(*NgoloFuzzOne_Int52_12NgdotFloor)(nil),
(*NgoloFuzzOne_Int52_12NgdotRound)(nil),
(*NgoloFuzzOne_Int52_12NgdotCeil)(nil),
(*NgoloFuzzOne_Int52_12NgdotMul)(nil),
(*NgoloFuzzOne_P)(nil),
(*NgoloFuzzOne_Point26_6NgdotAdd)(nil),
(*NgoloFuzzOne_Point26_6NgdotSub)(nil),
(*NgoloFuzzOne_Point26_6NgdotMul)(nil),
(*NgoloFuzzOne_Point26_6NgdotDiv)(nil),
(*NgoloFuzzOne_Point26_6NgdotIn)(nil),
(*NgoloFuzzOne_Point52_12NgdotAdd)(nil),
(*NgoloFuzzOne_Point52_12NgdotSub)(nil),
(*NgoloFuzzOne_Point52_12NgdotMul)(nil),
(*NgoloFuzzOne_Point52_12NgdotDiv)(nil),
(*NgoloFuzzOne_Point52_12NgdotIn)(nil),
(*NgoloFuzzOne_R)(nil),
(*NgoloFuzzOne_Rectangle26_6NgdotAdd)(nil),
(*NgoloFuzzOne_Rectangle26_6NgdotSub)(nil),
(*NgoloFuzzOne_Rectangle26_6NgdotIntersect)(nil),
(*NgoloFuzzOne_Rectangle26_6NgdotUnion)(nil),
(*NgoloFuzzOne_Rectangle26_6NgdotEmpty)(nil),
(*NgoloFuzzOne_Rectangle26_6NgdotIn)(nil),
(*NgoloFuzzOne_Rectangle52_12NgdotAdd)(nil),
(*NgoloFuzzOne_Rectangle52_12NgdotSub)(nil),
(*NgoloFuzzOne_Rectangle52_12NgdotIntersect)(nil),
(*NgoloFuzzOne_Rectangle52_12NgdotUnion)(nil),
(*NgoloFuzzOne_Rectangle52_12NgdotEmpty)(nil),
(*NgoloFuzzOne_Rectangle52_12NgdotIn)(nil),
}
file_ngolofuzz_proto_msgTypes[36].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 38,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_image_riff
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/image/riff"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var ReaderResults []*riff.Reader
ReaderResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewReader:
arg0 := bytes.NewReader(a.NewReader.R)
_, r1, r2 := riff.NewReader(arg0)
if r1 != nil{
ReaderResults = append(ReaderResults, r1)
}
if r2 != nil{
r2.Error()
return 0
}
case *NgoloFuzzOne_NewListReader:
arg1 := bytes.NewReader(a.NewListReader.ChunkData)
_, r1, r2 := riff.NewListReader(a.NewListReader.ChunkLen, arg1)
if r1 != nil{
ReaderResults = append(ReaderResults, r1)
}
if r2 != nil{
r2.Error()
return 0
}
case *NgoloFuzzOne_ReaderNgdotNext:
if len(ReaderResults) == 0 {
continue
}
arg0 := ReaderResults[ReaderResultsIndex]
ReaderResultsIndex = (ReaderResultsIndex + 1) % len(ReaderResults)
_, _, _, r3 := arg0.Next()
if r3 != nil{
r3.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
ReaderNb := 0
ReaderResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewReader:
w.WriteString(fmt.Sprintf("_, Reader%d, _ := riff.NewReader(bytes.NewReader(%#+v))\n", ReaderNb, a.NewReader.R))
ReaderNb = ReaderNb + 1
case *NgoloFuzzOne_NewListReader:
w.WriteString(fmt.Sprintf("_, Reader%d, _ := riff.NewListReader(%#+v, bytes.NewReader(%#+v))\n", ReaderNb, a.NewListReader.ChunkLen, a.NewListReader.ChunkData))
ReaderNb = ReaderNb + 1
case *NgoloFuzzOne_ReaderNgdotNext:
if ReaderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Reader%d.Next()\n", ReaderResultsIndex))
ReaderResultsIndex = (ReaderResultsIndex + 1) % ReaderNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_image_riff
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type NewReaderArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R []byte `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewReaderArgs) Reset() {
*x = NewReaderArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewReaderArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewReaderArgs) ProtoMessage() {}
func (x *NewReaderArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewReaderArgs.ProtoReflect.Descriptor instead.
func (*NewReaderArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *NewReaderArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
type NewListReaderArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
ChunkLen uint32 `protobuf:"varint,1,opt,name=chunkLen,proto3" json:"chunkLen,omitempty"`
ChunkData []byte `protobuf:"bytes,2,opt,name=chunkData,proto3" json:"chunkData,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewListReaderArgs) Reset() {
*x = NewListReaderArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewListReaderArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewListReaderArgs) ProtoMessage() {}
func (x *NewListReaderArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewListReaderArgs.ProtoReflect.Descriptor instead.
func (*NewListReaderArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *NewListReaderArgs) GetChunkLen() uint32 {
if x != nil {
return x.ChunkLen
}
return 0
}
func (x *NewListReaderArgs) GetChunkData() []byte {
if x != nil {
return x.ChunkData
}
return nil
}
type ReaderNgdotNextArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ReaderNgdotNextArgs) Reset() {
*x = ReaderNgdotNextArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ReaderNgdotNextArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReaderNgdotNextArgs) ProtoMessage() {}
func (x *ReaderNgdotNextArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReaderNgdotNextArgs.ProtoReflect.Descriptor instead.
func (*ReaderNgdotNextArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_NewReader
// *NgoloFuzzOne_NewListReader
// *NgoloFuzzOne_ReaderNgdotNext
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetNewReader() *NewReaderArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewReader); ok {
return x.NewReader
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewListReader() *NewListReaderArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewListReader); ok {
return x.NewListReader
}
}
return nil
}
func (x *NgoloFuzzOne) GetReaderNgdotNext() *ReaderNgdotNextArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ReaderNgdotNext); ok {
return x.ReaderNgdotNext
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_NewReader struct {
NewReader *NewReaderArgs `protobuf:"bytes,1,opt,name=NewReader,proto3,oneof"`
}
type NgoloFuzzOne_NewListReader struct {
NewListReader *NewListReaderArgs `protobuf:"bytes,2,opt,name=NewListReader,proto3,oneof"`
}
type NgoloFuzzOne_ReaderNgdotNext struct {
ReaderNgdotNext *ReaderNgdotNextArgs `protobuf:"bytes,3,opt,name=ReaderNgdotNext,proto3,oneof"`
}
func (*NgoloFuzzOne_NewReader) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewListReader) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ReaderNgdotNext) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x1d\n" +
"\rNewReaderArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\fR\x01r\"M\n" +
"\x11NewListReaderArgs\x12\x1a\n" +
"\bchunkLen\x18\x01 \x01(\rR\bchunkLen\x12\x1c\n" +
"\tchunkData\x18\x02 \x01(\fR\tchunkData\"\x15\n" +
"\x13ReaderNgdotNextArgs\"\xe2\x01\n" +
"\fNgoloFuzzOne\x128\n" +
"\tNewReader\x18\x01 \x01(\v2\x18.ngolofuzz.NewReaderArgsH\x00R\tNewReader\x12D\n" +
"\rNewListReader\x18\x02 \x01(\v2\x1c.ngolofuzz.NewListReaderArgsH\x00R\rNewListReader\x12J\n" +
"\x0fReaderNgdotNext\x18\x03 \x01(\v2\x1e.ngolofuzz.ReaderNgdotNextArgsH\x00R\x0fReaderNgdotNextB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x19Z\x17./;fuzz_ng_x_image_riffb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_ngolofuzz_proto_goTypes = []any{
(*NewReaderArgs)(nil), // 0: ngolofuzz.NewReaderArgs
(*NewListReaderArgs)(nil), // 1: ngolofuzz.NewListReaderArgs
(*ReaderNgdotNextArgs)(nil), // 2: ngolofuzz.ReaderNgdotNextArgs
(*NgoloFuzzOne)(nil), // 3: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 4: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 5: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.NewReader:type_name -> ngolofuzz.NewReaderArgs
1, // 1: ngolofuzz.NgoloFuzzOne.NewListReader:type_name -> ngolofuzz.NewListReaderArgs
2, // 2: ngolofuzz.NgoloFuzzOne.ReaderNgdotNext:type_name -> ngolofuzz.ReaderNgdotNextArgs
3, // 3: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[3].OneofWrappers = []any{
(*NgoloFuzzOne_NewReader)(nil),
(*NgoloFuzzOne_NewListReader)(nil),
(*NgoloFuzzOne_ReaderNgdotNext)(nil),
}
file_ngolofuzz_proto_msgTypes[4].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 6,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_image_tiff
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/image/tiff"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_DecodeConfig:
arg0 := bytes.NewReader(a.DecodeConfig.R)
_, r1 := tiff.DecodeConfig(arg0)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_Decode:
arg1 := bytes.NewReader(a.Decode.R)
cfg, err := tiff.DecodeConfig(arg1)
if err != nil {
return 0
}
if cfg.Width * cfg.Height > 1024*1024 {
continue
}
arg0 := bytes.NewReader(a.Decode.R)
_, r1 := tiff.Decode(arg0)
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_DecodeConfig:
w.WriteString(fmt.Sprintf("tiff.DecodeConfig(bytes.NewReader(%#+v))\n", a.DecodeConfig.R))
case *NgoloFuzzOne_Decode:
w.WriteString(fmt.Sprintf("tiff.Decode(bytes.NewReader(%#+v))\n", a.Decode.R))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_image_tiff
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type DecodeConfigArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R []byte `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecodeConfigArgs) Reset() {
*x = DecodeConfigArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecodeConfigArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecodeConfigArgs) ProtoMessage() {}
func (x *DecodeConfigArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecodeConfigArgs.ProtoReflect.Descriptor instead.
func (*DecodeConfigArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *DecodeConfigArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
type DecodeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R []byte `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecodeArgs) Reset() {
*x = DecodeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecodeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecodeArgs) ProtoMessage() {}
func (x *DecodeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecodeArgs.ProtoReflect.Descriptor instead.
func (*DecodeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *DecodeArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_DecodeConfig
// *NgoloFuzzOne_Decode
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetDecodeConfig() *DecodeConfigArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_DecodeConfig); ok {
return x.DecodeConfig
}
}
return nil
}
func (x *NgoloFuzzOne) GetDecode() *DecodeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Decode); ok {
return x.Decode
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_DecodeConfig struct {
DecodeConfig *DecodeConfigArgs `protobuf:"bytes,1,opt,name=DecodeConfig,proto3,oneof"`
}
type NgoloFuzzOne_Decode struct {
Decode *DecodeArgs `protobuf:"bytes,2,opt,name=Decode,proto3,oneof"`
}
func (*NgoloFuzzOne_DecodeConfig) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Decode) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\" \n" +
"\x10DecodeConfigArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\fR\x01r\"\x1a\n" +
"\n" +
"DecodeArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\fR\x01r\"\x8a\x01\n" +
"\fNgoloFuzzOne\x12A\n" +
"\fDecodeConfig\x18\x01 \x01(\v2\x1b.ngolofuzz.DecodeConfigArgsH\x00R\fDecodeConfig\x12/\n" +
"\x06Decode\x18\x02 \x01(\v2\x15.ngolofuzz.DecodeArgsH\x00R\x06DecodeB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x19Z\x17./;fuzz_ng_x_image_tiffb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_ngolofuzz_proto_goTypes = []any{
(*DecodeConfigArgs)(nil), // 0: ngolofuzz.DecodeConfigArgs
(*DecodeArgs)(nil), // 1: ngolofuzz.DecodeArgs
(*NgoloFuzzOne)(nil), // 2: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 3: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 4: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.DecodeConfig:type_name -> ngolofuzz.DecodeConfigArgs
1, // 1: ngolofuzz.NgoloFuzzOne.Decode:type_name -> ngolofuzz.DecodeArgs
2, // 2: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzOne_DecodeConfig)(nil),
(*NgoloFuzzOne_Decode)(nil),
}
file_ngolofuzz_proto_msgTypes[3].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_image_tiff_lzw
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/image/tiff/lzw"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func OrderNewFromFuzz(p OrderEnum) lzw.Order{
switch p {
case 1:
return lzw.MSB
}
return lzw.LSB
}
func ConvertOrderNewFromFuzz(a []OrderEnum) []lzw.Order{
r := make([]lzw.Order, len(a))
for i := range a {
r[i] = OrderNewFromFuzz(a[i])
}
return r
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewReader:
arg0 := bytes.NewReader(a.NewReader.R)
arg1 := OrderNewFromFuzz(a.NewReader.Order)
arg2 := int(a.NewReader.LitWidth)
lzw.NewReader(arg0, arg1, arg2)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewReader:
w.WriteString(fmt.Sprintf("lzw.NewReader(bytes.NewReader(%#+v), OrderNewFromFuzz(%#+v), int(%#+v))\n", a.NewReader.R, a.NewReader.Order, a.NewReader.LitWidth))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_image_tiff_lzw
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type OrderEnum int32
const (
OrderEnum_LSB OrderEnum = 0
OrderEnum_MSB OrderEnum = 1
)
// Enum value maps for OrderEnum.
var (
OrderEnum_name = map[int32]string{
0: "LSB",
1: "MSB",
}
OrderEnum_value = map[string]int32{
"LSB": 0,
"MSB": 1,
}
)
func (x OrderEnum) Enum() *OrderEnum {
p := new(OrderEnum)
*p = x
return p
}
func (x OrderEnum) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (OrderEnum) Descriptor() protoreflect.EnumDescriptor {
return file_ngolofuzz_proto_enumTypes[0].Descriptor()
}
func (OrderEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[0]
}
func (x OrderEnum) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use OrderEnum.Descriptor instead.
func (OrderEnum) EnumDescriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type NewReaderArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R []byte `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
Order OrderEnum `protobuf:"varint,2,opt,name=order,proto3,enum=ngolofuzz.OrderEnum" json:"order,omitempty"`
LitWidth int64 `protobuf:"varint,3,opt,name=litWidth,proto3" json:"litWidth,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewReaderArgs) Reset() {
*x = NewReaderArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewReaderArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewReaderArgs) ProtoMessage() {}
func (x *NewReaderArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewReaderArgs.ProtoReflect.Descriptor instead.
func (*NewReaderArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *NewReaderArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
func (x *NewReaderArgs) GetOrder() OrderEnum {
if x != nil {
return x.Order
}
return OrderEnum_LSB
}
func (x *NewReaderArgs) GetLitWidth() int64 {
if x != nil {
return x.LitWidth
}
return 0
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_NewReader
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetNewReader() *NewReaderArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewReader); ok {
return x.NewReader
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_NewReader struct {
NewReader *NewReaderArgs `protobuf:"bytes,1,opt,name=NewReader,proto3,oneof"`
}
func (*NgoloFuzzOne_NewReader) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"e\n" +
"\rNewReaderArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\fR\x01r\x12*\n" +
"\x05order\x18\x02 \x01(\x0e2\x14.ngolofuzz.OrderEnumR\x05order\x12\x1a\n" +
"\blitWidth\x18\x03 \x01(\x03R\blitWidth\"P\n" +
"\fNgoloFuzzOne\x128\n" +
"\tNewReader\x18\x01 \x01(\v2\x18.ngolofuzz.NewReaderArgsH\x00R\tNewReaderB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04list*\x1d\n" +
"\tOrderEnum\x12\a\n" +
"\x03LSB\x10\x00\x12\a\n" +
"\x03MSB\x10\x01B\x1dZ\x1b./;fuzz_ng_x_image_tiff_lzwb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_ngolofuzz_proto_goTypes = []any{
(OrderEnum)(0), // 0: ngolofuzz.OrderEnum
(*NewReaderArgs)(nil), // 1: ngolofuzz.NewReaderArgs
(*NgoloFuzzOne)(nil), // 2: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 3: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 4: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NewReaderArgs.order:type_name -> ngolofuzz.OrderEnum
1, // 1: ngolofuzz.NgoloFuzzOne.NewReader:type_name -> ngolofuzz.NewReaderArgs
2, // 2: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[1].OneofWrappers = []any{
(*NgoloFuzzOne_NewReader)(nil),
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 1,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
EnumInfos: file_ngolofuzz_proto_enumTypes,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_image_vector
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/image/vector"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var RasterizerResults []*vector.Rasterizer
RasterizerResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewRasterizer:
arg0 := int(a.NewRasterizer.W)
arg1 := int(a.NewRasterizer.H)
r0 := vector.NewRasterizer(arg0 % 0x10001, arg1 % 0x10001)
if r0 != nil{
RasterizerResults = append(RasterizerResults, r0)
}
case *NgoloFuzzOne_RasterizerNgdotReset:
if len(RasterizerResults) == 0 {
continue
}
arg0 := RasterizerResults[RasterizerResultsIndex]
RasterizerResultsIndex = (RasterizerResultsIndex + 1) % len(RasterizerResults)
arg1 := int(a.RasterizerNgdotReset.W)
arg2 := int(a.RasterizerNgdotReset.H)
arg0.Reset(arg1, arg2)
case *NgoloFuzzOne_RasterizerNgdotSize:
if len(RasterizerResults) == 0 {
continue
}
arg0 := RasterizerResults[RasterizerResultsIndex]
RasterizerResultsIndex = (RasterizerResultsIndex + 1) % len(RasterizerResults)
arg0.Size()
case *NgoloFuzzOne_RasterizerNgdotBounds:
if len(RasterizerResults) == 0 {
continue
}
arg0 := RasterizerResults[RasterizerResultsIndex]
RasterizerResultsIndex = (RasterizerResultsIndex + 1) % len(RasterizerResults)
arg0.Bounds()
case *NgoloFuzzOne_RasterizerNgdotPen:
if len(RasterizerResults) == 0 {
continue
}
arg0 := RasterizerResults[RasterizerResultsIndex]
RasterizerResultsIndex = (RasterizerResultsIndex + 1) % len(RasterizerResults)
arg0.Pen()
case *NgoloFuzzOne_RasterizerNgdotClosePath:
if len(RasterizerResults) == 0 {
continue
}
arg0 := RasterizerResults[RasterizerResultsIndex]
RasterizerResultsIndex = (RasterizerResultsIndex + 1) % len(RasterizerResults)
arg0.ClosePath()
case *NgoloFuzzOne_RasterizerNgdotMoveTo:
if len(RasterizerResults) == 0 {
continue
}
arg0 := RasterizerResults[RasterizerResultsIndex]
RasterizerResultsIndex = (RasterizerResultsIndex + 1) % len(RasterizerResults)
arg0.MoveTo(a.RasterizerNgdotMoveTo.Ax, a.RasterizerNgdotMoveTo.Ay)
case *NgoloFuzzOne_RasterizerNgdotLineTo:
if len(RasterizerResults) == 0 {
continue
}
arg0 := RasterizerResults[RasterizerResultsIndex]
RasterizerResultsIndex = (RasterizerResultsIndex + 1) % len(RasterizerResults)
arg0.LineTo(a.RasterizerNgdotLineTo.Bx, a.RasterizerNgdotLineTo.By)
case *NgoloFuzzOne_RasterizerNgdotQuadTo:
if len(RasterizerResults) == 0 {
continue
}
arg0 := RasterizerResults[RasterizerResultsIndex]
RasterizerResultsIndex = (RasterizerResultsIndex + 1) % len(RasterizerResults)
arg0.QuadTo(a.RasterizerNgdotQuadTo.Bx, a.RasterizerNgdotQuadTo.By, a.RasterizerNgdotQuadTo.Cx, a.RasterizerNgdotQuadTo.Cy)
case *NgoloFuzzOne_RasterizerNgdotCubeTo:
if len(RasterizerResults) == 0 {
continue
}
arg0 := RasterizerResults[RasterizerResultsIndex]
RasterizerResultsIndex = (RasterizerResultsIndex + 1) % len(RasterizerResults)
arg0.CubeTo(a.RasterizerNgdotCubeTo.Bx, a.RasterizerNgdotCubeTo.By, a.RasterizerNgdotCubeTo.Cx, a.RasterizerNgdotCubeTo.Cy, a.RasterizerNgdotCubeTo.Dx, a.RasterizerNgdotCubeTo.Dy)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
RasterizerNb := 0
RasterizerResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewRasterizer:
w.WriteString(fmt.Sprintf("Rasterizer%d := vector.NewRasterizer(int(%#+v) %% 0x10001, int(%#+v) %% 0x10001)\n", RasterizerNb, a.NewRasterizer.W, a.NewRasterizer.H))
RasterizerNb = RasterizerNb + 1
case *NgoloFuzzOne_RasterizerNgdotReset:
if RasterizerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Rasterizer%d.Reset(int(%#+v), int(%#+v))\n", RasterizerResultsIndex, a.RasterizerNgdotReset.W, a.RasterizerNgdotReset.H))
RasterizerResultsIndex = (RasterizerResultsIndex + 1) % RasterizerNb
case *NgoloFuzzOne_RasterizerNgdotSize:
if RasterizerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Rasterizer%d.Size()\n", RasterizerResultsIndex))
RasterizerResultsIndex = (RasterizerResultsIndex + 1) % RasterizerNb
case *NgoloFuzzOne_RasterizerNgdotBounds:
if RasterizerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Rasterizer%d.Bounds()\n", RasterizerResultsIndex))
RasterizerResultsIndex = (RasterizerResultsIndex + 1) % RasterizerNb
case *NgoloFuzzOne_RasterizerNgdotPen:
if RasterizerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Rasterizer%d.Pen()\n", RasterizerResultsIndex))
RasterizerResultsIndex = (RasterizerResultsIndex + 1) % RasterizerNb
case *NgoloFuzzOne_RasterizerNgdotClosePath:
if RasterizerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Rasterizer%d.ClosePath()\n", RasterizerResultsIndex))
RasterizerResultsIndex = (RasterizerResultsIndex + 1) % RasterizerNb
case *NgoloFuzzOne_RasterizerNgdotMoveTo:
if RasterizerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Rasterizer%d.MoveTo(%#+v, %#+v)\n", RasterizerResultsIndex, a.RasterizerNgdotMoveTo.Ax, a.RasterizerNgdotMoveTo.Ay))
RasterizerResultsIndex = (RasterizerResultsIndex + 1) % RasterizerNb
case *NgoloFuzzOne_RasterizerNgdotLineTo:
if RasterizerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Rasterizer%d.LineTo(%#+v, %#+v)\n", RasterizerResultsIndex, a.RasterizerNgdotLineTo.Bx, a.RasterizerNgdotLineTo.By))
RasterizerResultsIndex = (RasterizerResultsIndex + 1) % RasterizerNb
case *NgoloFuzzOne_RasterizerNgdotQuadTo:
if RasterizerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Rasterizer%d.QuadTo(%#+v, %#+v, %#+v, %#+v)\n", RasterizerResultsIndex, a.RasterizerNgdotQuadTo.Bx, a.RasterizerNgdotQuadTo.By, a.RasterizerNgdotQuadTo.Cx, a.RasterizerNgdotQuadTo.Cy))
RasterizerResultsIndex = (RasterizerResultsIndex + 1) % RasterizerNb
case *NgoloFuzzOne_RasterizerNgdotCubeTo:
if RasterizerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Rasterizer%d.CubeTo(%#+v, %#+v, %#+v, %#+v, %#+v, %#+v)\n", RasterizerResultsIndex, a.RasterizerNgdotCubeTo.Bx, a.RasterizerNgdotCubeTo.By, a.RasterizerNgdotCubeTo.Cx, a.RasterizerNgdotCubeTo.Cy, a.RasterizerNgdotCubeTo.Dx, a.RasterizerNgdotCubeTo.Dy))
RasterizerResultsIndex = (RasterizerResultsIndex + 1) % RasterizerNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_image_vector
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type NewRasterizerArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
W int64 `protobuf:"varint,1,opt,name=w,proto3" json:"w,omitempty"`
H int64 `protobuf:"varint,2,opt,name=h,proto3" json:"h,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewRasterizerArgs) Reset() {
*x = NewRasterizerArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewRasterizerArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewRasterizerArgs) ProtoMessage() {}
func (x *NewRasterizerArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewRasterizerArgs.ProtoReflect.Descriptor instead.
func (*NewRasterizerArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *NewRasterizerArgs) GetW() int64 {
if x != nil {
return x.W
}
return 0
}
func (x *NewRasterizerArgs) GetH() int64 {
if x != nil {
return x.H
}
return 0
}
type RasterizerNgdotResetArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
W int64 `protobuf:"varint,1,opt,name=w,proto3" json:"w,omitempty"`
H int64 `protobuf:"varint,2,opt,name=h,proto3" json:"h,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RasterizerNgdotResetArgs) Reset() {
*x = RasterizerNgdotResetArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RasterizerNgdotResetArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RasterizerNgdotResetArgs) ProtoMessage() {}
func (x *RasterizerNgdotResetArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RasterizerNgdotResetArgs.ProtoReflect.Descriptor instead.
func (*RasterizerNgdotResetArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *RasterizerNgdotResetArgs) GetW() int64 {
if x != nil {
return x.W
}
return 0
}
func (x *RasterizerNgdotResetArgs) GetH() int64 {
if x != nil {
return x.H
}
return 0
}
type RasterizerNgdotSizeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RasterizerNgdotSizeArgs) Reset() {
*x = RasterizerNgdotSizeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RasterizerNgdotSizeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RasterizerNgdotSizeArgs) ProtoMessage() {}
func (x *RasterizerNgdotSizeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RasterizerNgdotSizeArgs.ProtoReflect.Descriptor instead.
func (*RasterizerNgdotSizeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
type RasterizerNgdotBoundsArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RasterizerNgdotBoundsArgs) Reset() {
*x = RasterizerNgdotBoundsArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RasterizerNgdotBoundsArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RasterizerNgdotBoundsArgs) ProtoMessage() {}
func (x *RasterizerNgdotBoundsArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RasterizerNgdotBoundsArgs.ProtoReflect.Descriptor instead.
func (*RasterizerNgdotBoundsArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
type RasterizerNgdotPenArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RasterizerNgdotPenArgs) Reset() {
*x = RasterizerNgdotPenArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RasterizerNgdotPenArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RasterizerNgdotPenArgs) ProtoMessage() {}
func (x *RasterizerNgdotPenArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RasterizerNgdotPenArgs.ProtoReflect.Descriptor instead.
func (*RasterizerNgdotPenArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
type RasterizerNgdotClosePathArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RasterizerNgdotClosePathArgs) Reset() {
*x = RasterizerNgdotClosePathArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RasterizerNgdotClosePathArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RasterizerNgdotClosePathArgs) ProtoMessage() {}
func (x *RasterizerNgdotClosePathArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RasterizerNgdotClosePathArgs.ProtoReflect.Descriptor instead.
func (*RasterizerNgdotClosePathArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
type RasterizerNgdotMoveToArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Ax float32 `protobuf:"fixed32,1,opt,name=ax,proto3" json:"ax,omitempty"`
Ay float32 `protobuf:"fixed32,2,opt,name=ay,proto3" json:"ay,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RasterizerNgdotMoveToArgs) Reset() {
*x = RasterizerNgdotMoveToArgs{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RasterizerNgdotMoveToArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RasterizerNgdotMoveToArgs) ProtoMessage() {}
func (x *RasterizerNgdotMoveToArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RasterizerNgdotMoveToArgs.ProtoReflect.Descriptor instead.
func (*RasterizerNgdotMoveToArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *RasterizerNgdotMoveToArgs) GetAx() float32 {
if x != nil {
return x.Ax
}
return 0
}
func (x *RasterizerNgdotMoveToArgs) GetAy() float32 {
if x != nil {
return x.Ay
}
return 0
}
type RasterizerNgdotLineToArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Bx float32 `protobuf:"fixed32,1,opt,name=bx,proto3" json:"bx,omitempty"`
By float32 `protobuf:"fixed32,2,opt,name=by,proto3" json:"by,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RasterizerNgdotLineToArgs) Reset() {
*x = RasterizerNgdotLineToArgs{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RasterizerNgdotLineToArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RasterizerNgdotLineToArgs) ProtoMessage() {}
func (x *RasterizerNgdotLineToArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RasterizerNgdotLineToArgs.ProtoReflect.Descriptor instead.
func (*RasterizerNgdotLineToArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
func (x *RasterizerNgdotLineToArgs) GetBx() float32 {
if x != nil {
return x.Bx
}
return 0
}
func (x *RasterizerNgdotLineToArgs) GetBy() float32 {
if x != nil {
return x.By
}
return 0
}
type RasterizerNgdotQuadToArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Bx float32 `protobuf:"fixed32,1,opt,name=bx,proto3" json:"bx,omitempty"`
By float32 `protobuf:"fixed32,2,opt,name=by,proto3" json:"by,omitempty"`
Cx float32 `protobuf:"fixed32,3,opt,name=cx,proto3" json:"cx,omitempty"`
Cy float32 `protobuf:"fixed32,4,opt,name=cy,proto3" json:"cy,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RasterizerNgdotQuadToArgs) Reset() {
*x = RasterizerNgdotQuadToArgs{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RasterizerNgdotQuadToArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RasterizerNgdotQuadToArgs) ProtoMessage() {}
func (x *RasterizerNgdotQuadToArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RasterizerNgdotQuadToArgs.ProtoReflect.Descriptor instead.
func (*RasterizerNgdotQuadToArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
func (x *RasterizerNgdotQuadToArgs) GetBx() float32 {
if x != nil {
return x.Bx
}
return 0
}
func (x *RasterizerNgdotQuadToArgs) GetBy() float32 {
if x != nil {
return x.By
}
return 0
}
func (x *RasterizerNgdotQuadToArgs) GetCx() float32 {
if x != nil {
return x.Cx
}
return 0
}
func (x *RasterizerNgdotQuadToArgs) GetCy() float32 {
if x != nil {
return x.Cy
}
return 0
}
type RasterizerNgdotCubeToArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Bx float32 `protobuf:"fixed32,1,opt,name=bx,proto3" json:"bx,omitempty"`
By float32 `protobuf:"fixed32,2,opt,name=by,proto3" json:"by,omitempty"`
Cx float32 `protobuf:"fixed32,3,opt,name=cx,proto3" json:"cx,omitempty"`
Cy float32 `protobuf:"fixed32,4,opt,name=cy,proto3" json:"cy,omitempty"`
Dx float32 `protobuf:"fixed32,5,opt,name=dx,proto3" json:"dx,omitempty"`
Dy float32 `protobuf:"fixed32,6,opt,name=dy,proto3" json:"dy,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RasterizerNgdotCubeToArgs) Reset() {
*x = RasterizerNgdotCubeToArgs{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RasterizerNgdotCubeToArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RasterizerNgdotCubeToArgs) ProtoMessage() {}
func (x *RasterizerNgdotCubeToArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RasterizerNgdotCubeToArgs.ProtoReflect.Descriptor instead.
func (*RasterizerNgdotCubeToArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
func (x *RasterizerNgdotCubeToArgs) GetBx() float32 {
if x != nil {
return x.Bx
}
return 0
}
func (x *RasterizerNgdotCubeToArgs) GetBy() float32 {
if x != nil {
return x.By
}
return 0
}
func (x *RasterizerNgdotCubeToArgs) GetCx() float32 {
if x != nil {
return x.Cx
}
return 0
}
func (x *RasterizerNgdotCubeToArgs) GetCy() float32 {
if x != nil {
return x.Cy
}
return 0
}
func (x *RasterizerNgdotCubeToArgs) GetDx() float32 {
if x != nil {
return x.Dx
}
return 0
}
func (x *RasterizerNgdotCubeToArgs) GetDy() float32 {
if x != nil {
return x.Dy
}
return 0
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_NewRasterizer
// *NgoloFuzzOne_RasterizerNgdotReset
// *NgoloFuzzOne_RasterizerNgdotSize
// *NgoloFuzzOne_RasterizerNgdotBounds
// *NgoloFuzzOne_RasterizerNgdotPen
// *NgoloFuzzOne_RasterizerNgdotClosePath
// *NgoloFuzzOne_RasterizerNgdotMoveTo
// *NgoloFuzzOne_RasterizerNgdotLineTo
// *NgoloFuzzOne_RasterizerNgdotQuadTo
// *NgoloFuzzOne_RasterizerNgdotCubeTo
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{10}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetNewRasterizer() *NewRasterizerArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewRasterizer); ok {
return x.NewRasterizer
}
}
return nil
}
func (x *NgoloFuzzOne) GetRasterizerNgdotReset() *RasterizerNgdotResetArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_RasterizerNgdotReset); ok {
return x.RasterizerNgdotReset
}
}
return nil
}
func (x *NgoloFuzzOne) GetRasterizerNgdotSize() *RasterizerNgdotSizeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_RasterizerNgdotSize); ok {
return x.RasterizerNgdotSize
}
}
return nil
}
func (x *NgoloFuzzOne) GetRasterizerNgdotBounds() *RasterizerNgdotBoundsArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_RasterizerNgdotBounds); ok {
return x.RasterizerNgdotBounds
}
}
return nil
}
func (x *NgoloFuzzOne) GetRasterizerNgdotPen() *RasterizerNgdotPenArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_RasterizerNgdotPen); ok {
return x.RasterizerNgdotPen
}
}
return nil
}
func (x *NgoloFuzzOne) GetRasterizerNgdotClosePath() *RasterizerNgdotClosePathArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_RasterizerNgdotClosePath); ok {
return x.RasterizerNgdotClosePath
}
}
return nil
}
func (x *NgoloFuzzOne) GetRasterizerNgdotMoveTo() *RasterizerNgdotMoveToArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_RasterizerNgdotMoveTo); ok {
return x.RasterizerNgdotMoveTo
}
}
return nil
}
func (x *NgoloFuzzOne) GetRasterizerNgdotLineTo() *RasterizerNgdotLineToArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_RasterizerNgdotLineTo); ok {
return x.RasterizerNgdotLineTo
}
}
return nil
}
func (x *NgoloFuzzOne) GetRasterizerNgdotQuadTo() *RasterizerNgdotQuadToArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_RasterizerNgdotQuadTo); ok {
return x.RasterizerNgdotQuadTo
}
}
return nil
}
func (x *NgoloFuzzOne) GetRasterizerNgdotCubeTo() *RasterizerNgdotCubeToArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_RasterizerNgdotCubeTo); ok {
return x.RasterizerNgdotCubeTo
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_NewRasterizer struct {
NewRasterizer *NewRasterizerArgs `protobuf:"bytes,1,opt,name=NewRasterizer,proto3,oneof"`
}
type NgoloFuzzOne_RasterizerNgdotReset struct {
RasterizerNgdotReset *RasterizerNgdotResetArgs `protobuf:"bytes,2,opt,name=RasterizerNgdotReset,proto3,oneof"`
}
type NgoloFuzzOne_RasterizerNgdotSize struct {
RasterizerNgdotSize *RasterizerNgdotSizeArgs `protobuf:"bytes,3,opt,name=RasterizerNgdotSize,proto3,oneof"`
}
type NgoloFuzzOne_RasterizerNgdotBounds struct {
RasterizerNgdotBounds *RasterizerNgdotBoundsArgs `protobuf:"bytes,4,opt,name=RasterizerNgdotBounds,proto3,oneof"`
}
type NgoloFuzzOne_RasterizerNgdotPen struct {
RasterizerNgdotPen *RasterizerNgdotPenArgs `protobuf:"bytes,5,opt,name=RasterizerNgdotPen,proto3,oneof"`
}
type NgoloFuzzOne_RasterizerNgdotClosePath struct {
RasterizerNgdotClosePath *RasterizerNgdotClosePathArgs `protobuf:"bytes,6,opt,name=RasterizerNgdotClosePath,proto3,oneof"`
}
type NgoloFuzzOne_RasterizerNgdotMoveTo struct {
RasterizerNgdotMoveTo *RasterizerNgdotMoveToArgs `protobuf:"bytes,7,opt,name=RasterizerNgdotMoveTo,proto3,oneof"`
}
type NgoloFuzzOne_RasterizerNgdotLineTo struct {
RasterizerNgdotLineTo *RasterizerNgdotLineToArgs `protobuf:"bytes,8,opt,name=RasterizerNgdotLineTo,proto3,oneof"`
}
type NgoloFuzzOne_RasterizerNgdotQuadTo struct {
RasterizerNgdotQuadTo *RasterizerNgdotQuadToArgs `protobuf:"bytes,9,opt,name=RasterizerNgdotQuadTo,proto3,oneof"`
}
type NgoloFuzzOne_RasterizerNgdotCubeTo struct {
RasterizerNgdotCubeTo *RasterizerNgdotCubeToArgs `protobuf:"bytes,10,opt,name=RasterizerNgdotCubeTo,proto3,oneof"`
}
func (*NgoloFuzzOne_NewRasterizer) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_RasterizerNgdotReset) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_RasterizerNgdotSize) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_RasterizerNgdotBounds) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_RasterizerNgdotPen) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_RasterizerNgdotClosePath) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_RasterizerNgdotMoveTo) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_RasterizerNgdotLineTo) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_RasterizerNgdotQuadTo) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_RasterizerNgdotCubeTo) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[11]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{11}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[12]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{12}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"/\n" +
"\x11NewRasterizerArgs\x12\f\n" +
"\x01w\x18\x01 \x01(\x03R\x01w\x12\f\n" +
"\x01h\x18\x02 \x01(\x03R\x01h\"6\n" +
"\x18RasterizerNgdotResetArgs\x12\f\n" +
"\x01w\x18\x01 \x01(\x03R\x01w\x12\f\n" +
"\x01h\x18\x02 \x01(\x03R\x01h\"\x19\n" +
"\x17RasterizerNgdotSizeArgs\"\x1b\n" +
"\x19RasterizerNgdotBoundsArgs\"\x18\n" +
"\x16RasterizerNgdotPenArgs\"\x1e\n" +
"\x1cRasterizerNgdotClosePathArgs\";\n" +
"\x19RasterizerNgdotMoveToArgs\x12\x0e\n" +
"\x02ax\x18\x01 \x01(\x02R\x02ax\x12\x0e\n" +
"\x02ay\x18\x02 \x01(\x02R\x02ay\";\n" +
"\x19RasterizerNgdotLineToArgs\x12\x0e\n" +
"\x02bx\x18\x01 \x01(\x02R\x02bx\x12\x0e\n" +
"\x02by\x18\x02 \x01(\x02R\x02by\"[\n" +
"\x19RasterizerNgdotQuadToArgs\x12\x0e\n" +
"\x02bx\x18\x01 \x01(\x02R\x02bx\x12\x0e\n" +
"\x02by\x18\x02 \x01(\x02R\x02by\x12\x0e\n" +
"\x02cx\x18\x03 \x01(\x02R\x02cx\x12\x0e\n" +
"\x02cy\x18\x04 \x01(\x02R\x02cy\"{\n" +
"\x19RasterizerNgdotCubeToArgs\x12\x0e\n" +
"\x02bx\x18\x01 \x01(\x02R\x02bx\x12\x0e\n" +
"\x02by\x18\x02 \x01(\x02R\x02by\x12\x0e\n" +
"\x02cx\x18\x03 \x01(\x02R\x02cx\x12\x0e\n" +
"\x02cy\x18\x04 \x01(\x02R\x02cy\x12\x0e\n" +
"\x02dx\x18\x05 \x01(\x02R\x02dx\x12\x0e\n" +
"\x02dy\x18\x06 \x01(\x02R\x02dy\"\xa1\a\n" +
"\fNgoloFuzzOne\x12D\n" +
"\rNewRasterizer\x18\x01 \x01(\v2\x1c.ngolofuzz.NewRasterizerArgsH\x00R\rNewRasterizer\x12Y\n" +
"\x14RasterizerNgdotReset\x18\x02 \x01(\v2#.ngolofuzz.RasterizerNgdotResetArgsH\x00R\x14RasterizerNgdotReset\x12V\n" +
"\x13RasterizerNgdotSize\x18\x03 \x01(\v2\".ngolofuzz.RasterizerNgdotSizeArgsH\x00R\x13RasterizerNgdotSize\x12\\\n" +
"\x15RasterizerNgdotBounds\x18\x04 \x01(\v2$.ngolofuzz.RasterizerNgdotBoundsArgsH\x00R\x15RasterizerNgdotBounds\x12S\n" +
"\x12RasterizerNgdotPen\x18\x05 \x01(\v2!.ngolofuzz.RasterizerNgdotPenArgsH\x00R\x12RasterizerNgdotPen\x12e\n" +
"\x18RasterizerNgdotClosePath\x18\x06 \x01(\v2'.ngolofuzz.RasterizerNgdotClosePathArgsH\x00R\x18RasterizerNgdotClosePath\x12\\\n" +
"\x15RasterizerNgdotMoveTo\x18\a \x01(\v2$.ngolofuzz.RasterizerNgdotMoveToArgsH\x00R\x15RasterizerNgdotMoveTo\x12\\\n" +
"\x15RasterizerNgdotLineTo\x18\b \x01(\v2$.ngolofuzz.RasterizerNgdotLineToArgsH\x00R\x15RasterizerNgdotLineTo\x12\\\n" +
"\x15RasterizerNgdotQuadTo\x18\t \x01(\v2$.ngolofuzz.RasterizerNgdotQuadToArgsH\x00R\x15RasterizerNgdotQuadTo\x12\\\n" +
"\x15RasterizerNgdotCubeTo\x18\n" +
" \x01(\v2$.ngolofuzz.RasterizerNgdotCubeToArgsH\x00R\x15RasterizerNgdotCubeToB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1bZ\x19./;fuzz_ng_x_image_vectorb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 13)
var file_ngolofuzz_proto_goTypes = []any{
(*NewRasterizerArgs)(nil), // 0: ngolofuzz.NewRasterizerArgs
(*RasterizerNgdotResetArgs)(nil), // 1: ngolofuzz.RasterizerNgdotResetArgs
(*RasterizerNgdotSizeArgs)(nil), // 2: ngolofuzz.RasterizerNgdotSizeArgs
(*RasterizerNgdotBoundsArgs)(nil), // 3: ngolofuzz.RasterizerNgdotBoundsArgs
(*RasterizerNgdotPenArgs)(nil), // 4: ngolofuzz.RasterizerNgdotPenArgs
(*RasterizerNgdotClosePathArgs)(nil), // 5: ngolofuzz.RasterizerNgdotClosePathArgs
(*RasterizerNgdotMoveToArgs)(nil), // 6: ngolofuzz.RasterizerNgdotMoveToArgs
(*RasterizerNgdotLineToArgs)(nil), // 7: ngolofuzz.RasterizerNgdotLineToArgs
(*RasterizerNgdotQuadToArgs)(nil), // 8: ngolofuzz.RasterizerNgdotQuadToArgs
(*RasterizerNgdotCubeToArgs)(nil), // 9: ngolofuzz.RasterizerNgdotCubeToArgs
(*NgoloFuzzOne)(nil), // 10: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 11: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 12: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.NewRasterizer:type_name -> ngolofuzz.NewRasterizerArgs
1, // 1: ngolofuzz.NgoloFuzzOne.RasterizerNgdotReset:type_name -> ngolofuzz.RasterizerNgdotResetArgs
2, // 2: ngolofuzz.NgoloFuzzOne.RasterizerNgdotSize:type_name -> ngolofuzz.RasterizerNgdotSizeArgs
3, // 3: ngolofuzz.NgoloFuzzOne.RasterizerNgdotBounds:type_name -> ngolofuzz.RasterizerNgdotBoundsArgs
4, // 4: ngolofuzz.NgoloFuzzOne.RasterizerNgdotPen:type_name -> ngolofuzz.RasterizerNgdotPenArgs
5, // 5: ngolofuzz.NgoloFuzzOne.RasterizerNgdotClosePath:type_name -> ngolofuzz.RasterizerNgdotClosePathArgs
6, // 6: ngolofuzz.NgoloFuzzOne.RasterizerNgdotMoveTo:type_name -> ngolofuzz.RasterizerNgdotMoveToArgs
7, // 7: ngolofuzz.NgoloFuzzOne.RasterizerNgdotLineTo:type_name -> ngolofuzz.RasterizerNgdotLineToArgs
8, // 8: ngolofuzz.NgoloFuzzOne.RasterizerNgdotQuadTo:type_name -> ngolofuzz.RasterizerNgdotQuadToArgs
9, // 9: ngolofuzz.NgoloFuzzOne.RasterizerNgdotCubeTo:type_name -> ngolofuzz.RasterizerNgdotCubeToArgs
10, // 10: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
11, // [11:11] is the sub-list for method output_type
11, // [11:11] is the sub-list for method input_type
11, // [11:11] is the sub-list for extension type_name
11, // [11:11] is the sub-list for extension extendee
0, // [0:11] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[10].OneofWrappers = []any{
(*NgoloFuzzOne_NewRasterizer)(nil),
(*NgoloFuzzOne_RasterizerNgdotReset)(nil),
(*NgoloFuzzOne_RasterizerNgdotSize)(nil),
(*NgoloFuzzOne_RasterizerNgdotBounds)(nil),
(*NgoloFuzzOne_RasterizerNgdotPen)(nil),
(*NgoloFuzzOne_RasterizerNgdotClosePath)(nil),
(*NgoloFuzzOne_RasterizerNgdotMoveTo)(nil),
(*NgoloFuzzOne_RasterizerNgdotLineTo)(nil),
(*NgoloFuzzOne_RasterizerNgdotQuadTo)(nil),
(*NgoloFuzzOne_RasterizerNgdotCubeTo)(nil),
}
file_ngolofuzz_proto_msgTypes[11].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 13,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_image_vp8
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/image/vp8"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var DecoderResults []*vp8.Decoder
DecoderResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewDecoder:
r0 := vp8.NewDecoder()
if r0 != nil{
DecoderResults = append(DecoderResults, r0)
}
case *NgoloFuzzOne_DecoderNgdotInit:
if len(DecoderResults) == 0 {
continue
}
arg0 := DecoderResults[DecoderResultsIndex]
DecoderResultsIndex = (DecoderResultsIndex + 1) % len(DecoderResults)
arg1 := bytes.NewReader(a.DecoderNgdotInit.R)
arg2 := int(a.DecoderNgdotInit.N)
arg0.Init(arg1, arg2)
case *NgoloFuzzOne_DecoderNgdotDecodeFrameHeader:
if len(DecoderResults) == 0 {
continue
}
arg0 := DecoderResults[DecoderResultsIndex]
DecoderResultsIndex = (DecoderResultsIndex + 1) % len(DecoderResults)
_, r1 := arg0.DecodeFrameHeader()
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_DecoderNgdotDecodeFrame:
if len(DecoderResults) == 0 {
continue
}
arg0 := DecoderResults[DecoderResultsIndex]
DecoderResultsIndex = (DecoderResultsIndex + 1) % len(DecoderResults)
_, r1 := arg0.DecodeFrame()
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
DecoderNb := 0
DecoderResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewDecoder:
w.WriteString(fmt.Sprintf("Decoder%d := vp8.NewDecoder()\n", DecoderNb))
DecoderNb = DecoderNb + 1
case *NgoloFuzzOne_DecoderNgdotInit:
if DecoderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Decoder%d.Init(bytes.NewReader(%#+v), int(%#+v))\n", DecoderResultsIndex, a.DecoderNgdotInit.R, a.DecoderNgdotInit.N))
DecoderResultsIndex = (DecoderResultsIndex + 1) % DecoderNb
case *NgoloFuzzOne_DecoderNgdotDecodeFrameHeader:
if DecoderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Decoder%d.DecodeFrameHeader()\n", DecoderResultsIndex))
DecoderResultsIndex = (DecoderResultsIndex + 1) % DecoderNb
case *NgoloFuzzOne_DecoderNgdotDecodeFrame:
if DecoderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Decoder%d.DecodeFrame()\n", DecoderResultsIndex))
DecoderResultsIndex = (DecoderResultsIndex + 1) % DecoderNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_image_vp8
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type NewDecoderArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewDecoderArgs) Reset() {
*x = NewDecoderArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewDecoderArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewDecoderArgs) ProtoMessage() {}
func (x *NewDecoderArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewDecoderArgs.ProtoReflect.Descriptor instead.
func (*NewDecoderArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type DecoderNgdotInitArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R []byte `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
N int64 `protobuf:"varint,2,opt,name=n,proto3" json:"n,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecoderNgdotInitArgs) Reset() {
*x = DecoderNgdotInitArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecoderNgdotInitArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecoderNgdotInitArgs) ProtoMessage() {}
func (x *DecoderNgdotInitArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecoderNgdotInitArgs.ProtoReflect.Descriptor instead.
func (*DecoderNgdotInitArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *DecoderNgdotInitArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
func (x *DecoderNgdotInitArgs) GetN() int64 {
if x != nil {
return x.N
}
return 0
}
type DecoderNgdotDecodeFrameHeaderArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecoderNgdotDecodeFrameHeaderArgs) Reset() {
*x = DecoderNgdotDecodeFrameHeaderArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecoderNgdotDecodeFrameHeaderArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecoderNgdotDecodeFrameHeaderArgs) ProtoMessage() {}
func (x *DecoderNgdotDecodeFrameHeaderArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecoderNgdotDecodeFrameHeaderArgs.ProtoReflect.Descriptor instead.
func (*DecoderNgdotDecodeFrameHeaderArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
type DecoderNgdotDecodeFrameArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecoderNgdotDecodeFrameArgs) Reset() {
*x = DecoderNgdotDecodeFrameArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecoderNgdotDecodeFrameArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecoderNgdotDecodeFrameArgs) ProtoMessage() {}
func (x *DecoderNgdotDecodeFrameArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecoderNgdotDecodeFrameArgs.ProtoReflect.Descriptor instead.
func (*DecoderNgdotDecodeFrameArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_NewDecoder
// *NgoloFuzzOne_DecoderNgdotInit
// *NgoloFuzzOne_DecoderNgdotDecodeFrameHeader
// *NgoloFuzzOne_DecoderNgdotDecodeFrame
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetNewDecoder() *NewDecoderArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewDecoder); ok {
return x.NewDecoder
}
}
return nil
}
func (x *NgoloFuzzOne) GetDecoderNgdotInit() *DecoderNgdotInitArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_DecoderNgdotInit); ok {
return x.DecoderNgdotInit
}
}
return nil
}
func (x *NgoloFuzzOne) GetDecoderNgdotDecodeFrameHeader() *DecoderNgdotDecodeFrameHeaderArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_DecoderNgdotDecodeFrameHeader); ok {
return x.DecoderNgdotDecodeFrameHeader
}
}
return nil
}
func (x *NgoloFuzzOne) GetDecoderNgdotDecodeFrame() *DecoderNgdotDecodeFrameArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_DecoderNgdotDecodeFrame); ok {
return x.DecoderNgdotDecodeFrame
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_NewDecoder struct {
NewDecoder *NewDecoderArgs `protobuf:"bytes,1,opt,name=NewDecoder,proto3,oneof"`
}
type NgoloFuzzOne_DecoderNgdotInit struct {
DecoderNgdotInit *DecoderNgdotInitArgs `protobuf:"bytes,2,opt,name=DecoderNgdotInit,proto3,oneof"`
}
type NgoloFuzzOne_DecoderNgdotDecodeFrameHeader struct {
DecoderNgdotDecodeFrameHeader *DecoderNgdotDecodeFrameHeaderArgs `protobuf:"bytes,3,opt,name=DecoderNgdotDecodeFrameHeader,proto3,oneof"`
}
type NgoloFuzzOne_DecoderNgdotDecodeFrame struct {
DecoderNgdotDecodeFrame *DecoderNgdotDecodeFrameArgs `protobuf:"bytes,4,opt,name=DecoderNgdotDecodeFrame,proto3,oneof"`
}
func (*NgoloFuzzOne_NewDecoder) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_DecoderNgdotInit) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_DecoderNgdotDecodeFrameHeader) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_DecoderNgdotDecodeFrame) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x10\n" +
"\x0eNewDecoderArgs\"2\n" +
"\x14DecoderNgdotInitArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\fR\x01r\x12\f\n" +
"\x01n\x18\x02 \x01(\x03R\x01n\"#\n" +
"!DecoderNgdotDecodeFrameHeaderArgs\"\x1d\n" +
"\x1bDecoderNgdotDecodeFrameArgs\"\xfc\x02\n" +
"\fNgoloFuzzOne\x12;\n" +
"\n" +
"NewDecoder\x18\x01 \x01(\v2\x19.ngolofuzz.NewDecoderArgsH\x00R\n" +
"NewDecoder\x12M\n" +
"\x10DecoderNgdotInit\x18\x02 \x01(\v2\x1f.ngolofuzz.DecoderNgdotInitArgsH\x00R\x10DecoderNgdotInit\x12t\n" +
"\x1dDecoderNgdotDecodeFrameHeader\x18\x03 \x01(\v2,.ngolofuzz.DecoderNgdotDecodeFrameHeaderArgsH\x00R\x1dDecoderNgdotDecodeFrameHeader\x12b\n" +
"\x17DecoderNgdotDecodeFrame\x18\x04 \x01(\v2&.ngolofuzz.DecoderNgdotDecodeFrameArgsH\x00R\x17DecoderNgdotDecodeFrameB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x18Z\x16./;fuzz_ng_x_image_vp8b\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_ngolofuzz_proto_goTypes = []any{
(*NewDecoderArgs)(nil), // 0: ngolofuzz.NewDecoderArgs
(*DecoderNgdotInitArgs)(nil), // 1: ngolofuzz.DecoderNgdotInitArgs
(*DecoderNgdotDecodeFrameHeaderArgs)(nil), // 2: ngolofuzz.DecoderNgdotDecodeFrameHeaderArgs
(*DecoderNgdotDecodeFrameArgs)(nil), // 3: ngolofuzz.DecoderNgdotDecodeFrameArgs
(*NgoloFuzzOne)(nil), // 4: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 5: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 6: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.NewDecoder:type_name -> ngolofuzz.NewDecoderArgs
1, // 1: ngolofuzz.NgoloFuzzOne.DecoderNgdotInit:type_name -> ngolofuzz.DecoderNgdotInitArgs
2, // 2: ngolofuzz.NgoloFuzzOne.DecoderNgdotDecodeFrameHeader:type_name -> ngolofuzz.DecoderNgdotDecodeFrameHeaderArgs
3, // 3: ngolofuzz.NgoloFuzzOne.DecoderNgdotDecodeFrame:type_name -> ngolofuzz.DecoderNgdotDecodeFrameArgs
4, // 4: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[4].OneofWrappers = []any{
(*NgoloFuzzOne_NewDecoder)(nil),
(*NgoloFuzzOne_DecoderNgdotInit)(nil),
(*NgoloFuzzOne_DecoderNgdotDecodeFrameHeader)(nil),
(*NgoloFuzzOne_DecoderNgdotDecodeFrame)(nil),
}
file_ngolofuzz_proto_msgTypes[5].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 7,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_image_vp8l
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/image/vp8l"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_DecodeConfig:
arg0 := bytes.NewReader(a.DecodeConfig.R)
_, r1 := vp8l.DecodeConfig(arg0)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_Decode:
arg1 := bytes.NewReader(a.Decode.R)
cfg, err := vp8l.DecodeConfig(arg1)
if err != nil {
return 0
}
if cfg.Width * cfg.Height > 1024*1024 {
continue
}
arg0 := bytes.NewReader(a.Decode.R)
_, r1 := vp8l.Decode(arg0)
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_DecodeConfig:
w.WriteString(fmt.Sprintf("vp8l.DecodeConfig(bytes.NewReader(%#+v))\n", a.DecodeConfig.R))
case *NgoloFuzzOne_Decode:
w.WriteString(fmt.Sprintf("vp8l.Decode(bytes.NewReader(%#+v))\n", a.Decode.R))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_image_vp8l
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type DecodeConfigArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R []byte `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecodeConfigArgs) Reset() {
*x = DecodeConfigArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecodeConfigArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecodeConfigArgs) ProtoMessage() {}
func (x *DecodeConfigArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecodeConfigArgs.ProtoReflect.Descriptor instead.
func (*DecodeConfigArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *DecodeConfigArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
type DecodeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R []byte `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecodeArgs) Reset() {
*x = DecodeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecodeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecodeArgs) ProtoMessage() {}
func (x *DecodeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecodeArgs.ProtoReflect.Descriptor instead.
func (*DecodeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *DecodeArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_DecodeConfig
// *NgoloFuzzOne_Decode
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetDecodeConfig() *DecodeConfigArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_DecodeConfig); ok {
return x.DecodeConfig
}
}
return nil
}
func (x *NgoloFuzzOne) GetDecode() *DecodeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Decode); ok {
return x.Decode
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_DecodeConfig struct {
DecodeConfig *DecodeConfigArgs `protobuf:"bytes,1,opt,name=DecodeConfig,proto3,oneof"`
}
type NgoloFuzzOne_Decode struct {
Decode *DecodeArgs `protobuf:"bytes,2,opt,name=Decode,proto3,oneof"`
}
func (*NgoloFuzzOne_DecodeConfig) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Decode) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\" \n" +
"\x10DecodeConfigArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\fR\x01r\"\x1a\n" +
"\n" +
"DecodeArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\fR\x01r\"\x8a\x01\n" +
"\fNgoloFuzzOne\x12A\n" +
"\fDecodeConfig\x18\x01 \x01(\v2\x1b.ngolofuzz.DecodeConfigArgsH\x00R\fDecodeConfig\x12/\n" +
"\x06Decode\x18\x02 \x01(\v2\x15.ngolofuzz.DecodeArgsH\x00R\x06DecodeB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x19Z\x17./;fuzz_ng_x_image_vp8lb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_ngolofuzz_proto_goTypes = []any{
(*DecodeConfigArgs)(nil), // 0: ngolofuzz.DecodeConfigArgs
(*DecodeArgs)(nil), // 1: ngolofuzz.DecodeArgs
(*NgoloFuzzOne)(nil), // 2: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 3: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 4: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.DecodeConfig:type_name -> ngolofuzz.DecodeConfigArgs
1, // 1: ngolofuzz.NgoloFuzzOne.Decode:type_name -> ngolofuzz.DecodeArgs
2, // 2: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzOne_DecodeConfig)(nil),
(*NgoloFuzzOne_Decode)(nil),
}
file_ngolofuzz_proto_msgTypes[3].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_image_webp
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/image/webp"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Decode:
arg1 := bytes.NewReader(a.Decode.R)
cfg, err := webp.DecodeConfig(arg1)
if err != nil {
return 0
}
if cfg.Width * cfg.Height > 1024*1024 {
continue
}
arg0 := bytes.NewReader(a.Decode.R)
_, r1 := webp.Decode(arg0)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_DecodeConfig:
arg0 := bytes.NewReader(a.DecodeConfig.R)
_, r1 := webp.DecodeConfig(arg0)
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Decode:
w.WriteString(fmt.Sprintf("webp.Decode(bytes.NewReader(%#+v))\n", a.Decode.R))
case *NgoloFuzzOne_DecodeConfig:
w.WriteString(fmt.Sprintf("webp.DecodeConfig(bytes.NewReader(%#+v))\n", a.DecodeConfig.R))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_image_webp
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type DecodeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R []byte `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecodeArgs) Reset() {
*x = DecodeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecodeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecodeArgs) ProtoMessage() {}
func (x *DecodeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecodeArgs.ProtoReflect.Descriptor instead.
func (*DecodeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *DecodeArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
type DecodeConfigArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R []byte `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecodeConfigArgs) Reset() {
*x = DecodeConfigArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecodeConfigArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecodeConfigArgs) ProtoMessage() {}
func (x *DecodeConfigArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecodeConfigArgs.ProtoReflect.Descriptor instead.
func (*DecodeConfigArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *DecodeConfigArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_Decode
// *NgoloFuzzOne_DecodeConfig
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetDecode() *DecodeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Decode); ok {
return x.Decode
}
}
return nil
}
func (x *NgoloFuzzOne) GetDecodeConfig() *DecodeConfigArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_DecodeConfig); ok {
return x.DecodeConfig
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_Decode struct {
Decode *DecodeArgs `protobuf:"bytes,1,opt,name=Decode,proto3,oneof"`
}
type NgoloFuzzOne_DecodeConfig struct {
DecodeConfig *DecodeConfigArgs `protobuf:"bytes,2,opt,name=DecodeConfig,proto3,oneof"`
}
func (*NgoloFuzzOne_Decode) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_DecodeConfig) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x1a\n" +
"\n" +
"DecodeArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\fR\x01r\" \n" +
"\x10DecodeConfigArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\fR\x01r\"\x8a\x01\n" +
"\fNgoloFuzzOne\x12/\n" +
"\x06Decode\x18\x01 \x01(\v2\x15.ngolofuzz.DecodeArgsH\x00R\x06Decode\x12A\n" +
"\fDecodeConfig\x18\x02 \x01(\v2\x1b.ngolofuzz.DecodeConfigArgsH\x00R\fDecodeConfigB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x19Z\x17./;fuzz_ng_x_image_webpb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_ngolofuzz_proto_goTypes = []any{
(*DecodeArgs)(nil), // 0: ngolofuzz.DecodeArgs
(*DecodeConfigArgs)(nil), // 1: ngolofuzz.DecodeConfigArgs
(*NgoloFuzzOne)(nil), // 2: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 3: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 4: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.Decode:type_name -> ngolofuzz.DecodeArgs
1, // 1: ngolofuzz.NgoloFuzzOne.DecodeConfig:type_name -> ngolofuzz.DecodeConfigArgs
2, // 2: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzOne_Decode)(nil),
(*NgoloFuzzOne_DecodeConfig)(nil),
}
file_ngolofuzz_proto_msgTypes[3].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
// 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.
// Package fixed implements fixed-point integer types.
package fixed // import "golang.org/x/image/math/fixed"
import (
"fmt"
)
// TODO: implement fmt.Formatter for %f and %g.
// I returns the integer value i as an Int26_6.
//
// For example, passing the integer value 2 yields Int26_6(128).
func I(i int) Int26_6 {
return Int26_6(i << 6)
}
// Int26_6 is a signed 26.6 fixed-point number.
//
// The integer part ranges from -33554432 to 33554431, inclusive. The
// fractional part has 6 bits of precision.
//
// For example, the number one-and-a-quarter is Int26_6(1<<6 + 1<<4).
type Int26_6 int32
// String returns a human-readable representation of a 26.6 fixed-point number.
//
// For example, the number one-and-a-quarter becomes "1:16".
func (x Int26_6) String() string {
const shift, mask = 6, 1<<6 - 1
if x >= 0 {
return fmt.Sprintf("%d:%02d", int32(x>>shift), int32(x&mask))
}
x = -x
if x >= 0 {
return fmt.Sprintf("-%d:%02d", int32(x>>shift), int32(x&mask))
}
return "-33554432:00" // The minimum value is -(1<<25).
}
// Floor returns the greatest integer value less than or equal to x.
//
// Its return type is int, not Int26_6.
func (x Int26_6) Floor() int { return int((x + 0x00) >> 6) }
// Round returns the nearest integer value to x. Ties are rounded up.
//
// Its return type is int, not Int26_6.
func (x Int26_6) Round() int { return int((x + 0x20) >> 6) }
// Ceil returns the least integer value greater than or equal to x.
//
// Its return type is int, not Int26_6.
func (x Int26_6) Ceil() int { return int((x + 0x3f) >> 6) }
// Mul returns x*y in 26.6 fixed-point arithmetic.
func (x Int26_6) Mul(y Int26_6) Int26_6 {
return Int26_6((int64(x)*int64(y) + 1<<5) >> 6)
}
// Int52_12 is a signed 52.12 fixed-point number.
//
// The integer part ranges from -2251799813685248 to 2251799813685247,
// inclusive. The fractional part has 12 bits of precision.
//
// For example, the number one-and-a-quarter is Int52_12(1<<12 + 1<<10).
type Int52_12 int64
// String returns a human-readable representation of a 52.12 fixed-point
// number.
//
// For example, the number one-and-a-quarter becomes "1:1024".
func (x Int52_12) String() string {
const shift, mask = 12, 1<<12 - 1
if x >= 0 {
return fmt.Sprintf("%d:%04d", int64(x>>shift), int64(x&mask))
}
x = -x
if x >= 0 {
return fmt.Sprintf("-%d:%04d", int64(x>>shift), int64(x&mask))
}
return "-2251799813685248:0000" // The minimum value is -(1<<51).
}
// Floor returns the greatest integer value less than or equal to x.
//
// Its return type is int, not Int52_12.
func (x Int52_12) Floor() int { return int((x + 0x000) >> 12) }
// Round returns the nearest integer value to x. Ties are rounded up.
//
// Its return type is int, not Int52_12.
func (x Int52_12) Round() int { return int((x + 0x800) >> 12) }
// Ceil returns the least integer value greater than or equal to x.
//
// Its return type is int, not Int52_12.
func (x Int52_12) Ceil() int { return int((x + 0xfff) >> 12) }
// Mul returns x*y in 52.12 fixed-point arithmetic.
func (x Int52_12) Mul(y Int52_12) Int52_12 {
const M, N = 52, 12
lo, hi := muli64(int64(x), int64(y))
ret := Int52_12(hi<<M | lo>>N)
ret += Int52_12((lo >> (N - 1)) & 1) // Round to nearest, instead of rounding down.
return ret
}
// muli64 multiplies two int64 values, returning the 128-bit signed integer
// result as two uint64 values.
//
// This implementation is similar to $GOROOT/src/runtime/softfloat64.go's mullu
// function, which is in turn adapted from Hacker's Delight.
func muli64(u, v int64) (lo, hi uint64) {
const (
s = 32
mask = 1<<s - 1
)
u1 := uint64(u >> s)
u0 := uint64(u & mask)
v1 := uint64(v >> s)
v0 := uint64(v & mask)
w0 := u0 * v0
t := u1*v0 + w0>>s
w1 := t & mask
w2 := uint64(int64(t) >> s)
w1 += u0 * v1
return uint64(u) * uint64(v), u1*v1 + w2 + uint64(int64(w1)>>s)
}
// P returns the integer values x and y as a Point26_6.
//
// For example, passing the integer values (2, -3) yields Point26_6{128, -192}.
func P(x, y int) Point26_6 {
return Point26_6{Int26_6(x << 6), Int26_6(y << 6)}
}
// Point26_6 is a 26.6 fixed-point coordinate pair.
//
// It is analogous to the image.Point type in the standard library.
type Point26_6 struct {
X, Y Int26_6
}
// Add returns the vector p+q.
func (p Point26_6) Add(q Point26_6) Point26_6 {
return Point26_6{p.X + q.X, p.Y + q.Y}
}
// Sub returns the vector p-q.
func (p Point26_6) Sub(q Point26_6) Point26_6 {
return Point26_6{p.X - q.X, p.Y - q.Y}
}
// Mul returns the vector p*k.
func (p Point26_6) Mul(k Int26_6) Point26_6 {
return Point26_6{p.X * k / 64, p.Y * k / 64}
}
// Div returns the vector p/k.
func (p Point26_6) Div(k Int26_6) Point26_6 {
return Point26_6{p.X * 64 / k, p.Y * 64 / k}
}
// In returns whether p is in r.
func (p Point26_6) In(r Rectangle26_6) bool {
return r.Min.X <= p.X && p.X < r.Max.X && r.Min.Y <= p.Y && p.Y < r.Max.Y
}
// Point52_12 is a 52.12 fixed-point coordinate pair.
//
// It is analogous to the image.Point type in the standard library.
type Point52_12 struct {
X, Y Int52_12
}
// Add returns the vector p+q.
func (p Point52_12) Add(q Point52_12) Point52_12 {
return Point52_12{p.X + q.X, p.Y + q.Y}
}
// Sub returns the vector p-q.
func (p Point52_12) Sub(q Point52_12) Point52_12 {
return Point52_12{p.X - q.X, p.Y - q.Y}
}
// Mul returns the vector p*k.
func (p Point52_12) Mul(k Int52_12) Point52_12 {
return Point52_12{p.X * k / 4096, p.Y * k / 4096}
}
// Div returns the vector p/k.
func (p Point52_12) Div(k Int52_12) Point52_12 {
return Point52_12{p.X * 4096 / k, p.Y * 4096 / k}
}
// In returns whether p is in r.
func (p Point52_12) In(r Rectangle52_12) bool {
return r.Min.X <= p.X && p.X < r.Max.X && r.Min.Y <= p.Y && p.Y < r.Max.Y
}
// R returns the integer values minX, minY, maxX, maxY as a Rectangle26_6.
//
// For example, passing the integer values (0, 1, 2, 3) yields
// Rectangle26_6{Point26_6{0, 64}, Point26_6{128, 192}}.
//
// Like the image.Rect function in the standard library, the returned rectangle
// has minimum and maximum coordinates swapped if necessary so that it is
// well-formed.
func R(minX, minY, maxX, maxY int) Rectangle26_6 {
if minX > maxX {
minX, maxX = maxX, minX
}
if minY > maxY {
minY, maxY = maxY, minY
}
return Rectangle26_6{
Point26_6{
Int26_6(minX << 6),
Int26_6(minY << 6),
},
Point26_6{
Int26_6(maxX << 6),
Int26_6(maxY << 6),
},
}
}
// Rectangle26_6 is a 26.6 fixed-point coordinate rectangle. The Min bound is
// inclusive and the Max bound is exclusive. It is well-formed if Min.X <=
// Max.X and likewise for Y.
//
// It is analogous to the image.Rectangle type in the standard library.
type Rectangle26_6 struct {
Min, Max Point26_6
}
// Add returns the rectangle r translated by p.
func (r Rectangle26_6) Add(p Point26_6) Rectangle26_6 {
return Rectangle26_6{
Point26_6{r.Min.X + p.X, r.Min.Y + p.Y},
Point26_6{r.Max.X + p.X, r.Max.Y + p.Y},
}
}
// Sub returns the rectangle r translated by -p.
func (r Rectangle26_6) Sub(p Point26_6) Rectangle26_6 {
return Rectangle26_6{
Point26_6{r.Min.X - p.X, r.Min.Y - p.Y},
Point26_6{r.Max.X - p.X, r.Max.Y - p.Y},
}
}
// Intersect returns the largest rectangle contained by both r and s. If the
// two rectangles do not overlap then the zero rectangle will be returned.
func (r Rectangle26_6) Intersect(s Rectangle26_6) Rectangle26_6 {
if r.Min.X < s.Min.X {
r.Min.X = s.Min.X
}
if r.Min.Y < s.Min.Y {
r.Min.Y = s.Min.Y
}
if r.Max.X > s.Max.X {
r.Max.X = s.Max.X
}
if r.Max.Y > s.Max.Y {
r.Max.Y = s.Max.Y
}
// Letting r0 and s0 be the values of r and s at the time that the method
// is called, this next line is equivalent to:
//
// if max(r0.Min.X, s0.Min.X) >= min(r0.Max.X, s0.Max.X) || likewiseForY { etc }
if r.Empty() {
return Rectangle26_6{}
}
return r
}
// Union returns the smallest rectangle that contains both r and s.
func (r Rectangle26_6) Union(s Rectangle26_6) Rectangle26_6 {
if r.Empty() {
return s
}
if s.Empty() {
return r
}
if r.Min.X > s.Min.X {
r.Min.X = s.Min.X
}
if r.Min.Y > s.Min.Y {
r.Min.Y = s.Min.Y
}
if r.Max.X < s.Max.X {
r.Max.X = s.Max.X
}
if r.Max.Y < s.Max.Y {
r.Max.Y = s.Max.Y
}
return r
}
// Empty returns whether the rectangle contains no points.
func (r Rectangle26_6) Empty() bool {
return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y
}
// In returns whether every point in r is in s.
func (r Rectangle26_6) In(s Rectangle26_6) bool {
if r.Empty() {
return true
}
// Note that r.Max is an exclusive bound for r, so that r.In(s)
// does not require that r.Max.In(s).
return s.Min.X <= r.Min.X && r.Max.X <= s.Max.X &&
s.Min.Y <= r.Min.Y && r.Max.Y <= s.Max.Y
}
// Rectangle52_12 is a 52.12 fixed-point coordinate rectangle. The Min bound is
// inclusive and the Max bound is exclusive. It is well-formed if Min.X <=
// Max.X and likewise for Y.
//
// It is analogous to the image.Rectangle type in the standard library.
type Rectangle52_12 struct {
Min, Max Point52_12
}
// Add returns the rectangle r translated by p.
func (r Rectangle52_12) Add(p Point52_12) Rectangle52_12 {
return Rectangle52_12{
Point52_12{r.Min.X + p.X, r.Min.Y + p.Y},
Point52_12{r.Max.X + p.X, r.Max.Y + p.Y},
}
}
// Sub returns the rectangle r translated by -p.
func (r Rectangle52_12) Sub(p Point52_12) Rectangle52_12 {
return Rectangle52_12{
Point52_12{r.Min.X - p.X, r.Min.Y - p.Y},
Point52_12{r.Max.X - p.X, r.Max.Y - p.Y},
}
}
// Intersect returns the largest rectangle contained by both r and s. If the
// two rectangles do not overlap then the zero rectangle will be returned.
func (r Rectangle52_12) Intersect(s Rectangle52_12) Rectangle52_12 {
if r.Min.X < s.Min.X {
r.Min.X = s.Min.X
}
if r.Min.Y < s.Min.Y {
r.Min.Y = s.Min.Y
}
if r.Max.X > s.Max.X {
r.Max.X = s.Max.X
}
if r.Max.Y > s.Max.Y {
r.Max.Y = s.Max.Y
}
// Letting r0 and s0 be the values of r and s at the time that the method
// is called, this next line is equivalent to:
//
// if max(r0.Min.X, s0.Min.X) >= min(r0.Max.X, s0.Max.X) || likewiseForY { etc }
if r.Empty() {
return Rectangle52_12{}
}
return r
}
// Union returns the smallest rectangle that contains both r and s.
func (r Rectangle52_12) Union(s Rectangle52_12) Rectangle52_12 {
if r.Empty() {
return s
}
if s.Empty() {
return r
}
if r.Min.X > s.Min.X {
r.Min.X = s.Min.X
}
if r.Min.Y > s.Min.Y {
r.Min.Y = s.Min.Y
}
if r.Max.X < s.Max.X {
r.Max.X = s.Max.X
}
if r.Max.Y < s.Max.Y {
r.Max.Y = s.Max.Y
}
return r
}
// Empty returns whether the rectangle contains no points.
func (r Rectangle52_12) Empty() bool {
return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y
}
// In returns whether every point in r is in s.
func (r Rectangle52_12) In(s Rectangle52_12) bool {
if r.Empty() {
return true
}
// Note that r.Max is an exclusive bound for r, so that r.In(s)
// does not require that r.Max.In(s).
return s.Min.X <= r.Min.X && r.Max.X <= s.Max.X &&
s.Min.Y <= r.Min.Y && r.Max.Y <= s.Max.Y
}
// 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 riff implements the Resource Interchange File Format, used by media
// formats such as AVI, WAVE and WEBP.
//
// A RIFF stream contains a sequence of chunks. Each chunk consists of an 8-byte
// header (containing a 4-byte chunk type and a 4-byte chunk length), the chunk
// data (presented as an io.Reader), and some padding bytes.
//
// A detailed description of the format is at
// http://www.tactilemedia.com/info/MCI_Control_Info.html
package riff // import "golang.org/x/image/riff"
import (
"errors"
"io"
"io/ioutil"
"math"
)
var (
errMissingPaddingByte = errors.New("riff: missing padding byte")
errMissingRIFFChunkHeader = errors.New("riff: missing RIFF chunk header")
errListSubchunkTooLong = errors.New("riff: list subchunk too long")
errShortChunkData = errors.New("riff: short chunk data")
errShortChunkHeader = errors.New("riff: short chunk header")
errStaleReader = errors.New("riff: stale reader")
)
// u32 decodes the first four bytes of b as a little-endian integer.
func u32(b []byte) uint32 {
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
}
const chunkHeaderSize = 8
// FourCC is a four character code.
type FourCC [4]byte
// LIST is the "LIST" FourCC.
var LIST = FourCC{'L', 'I', 'S', 'T'}
// NewReader returns the RIFF stream's form type, such as "AVI " or "WAVE", and
// its chunks as a *Reader.
func NewReader(r io.Reader) (formType FourCC, data *Reader, err error) {
var buf [chunkHeaderSize]byte
if _, err := io.ReadFull(r, buf[:]); err != nil {
if err == io.EOF || err == io.ErrUnexpectedEOF {
err = errMissingRIFFChunkHeader
}
return FourCC{}, nil, err
}
if buf[0] != 'R' || buf[1] != 'I' || buf[2] != 'F' || buf[3] != 'F' {
return FourCC{}, nil, errMissingRIFFChunkHeader
}
return NewListReader(u32(buf[4:]), r)
}
// NewListReader returns a LIST chunk's list type, such as "movi" or "wavl",
// and its chunks as a *Reader.
func NewListReader(chunkLen uint32, chunkData io.Reader) (listType FourCC, data *Reader, err error) {
if chunkLen < 4 {
return FourCC{}, nil, errShortChunkData
}
z := &Reader{r: chunkData}
if _, err := io.ReadFull(chunkData, z.buf[:4]); err != nil {
if err == io.EOF || err == io.ErrUnexpectedEOF {
err = errShortChunkData
}
return FourCC{}, nil, err
}
z.totalLen = chunkLen - 4
return FourCC{z.buf[0], z.buf[1], z.buf[2], z.buf[3]}, z, nil
}
// Reader reads chunks from an underlying io.Reader.
type Reader struct {
r io.Reader
err error
totalLen uint32
chunkLen uint32
chunkReader *chunkReader
buf [chunkHeaderSize]byte
padded bool
}
// Next returns the next chunk's ID, length and data. It returns io.EOF if there
// are no more chunks. The io.Reader returned becomes stale after the next Next
// call, and should no longer be used.
//
// It is valid to call Next even if all of the previous chunk's data has not
// been read.
func (z *Reader) Next() (chunkID FourCC, chunkLen uint32, chunkData io.Reader, err error) {
if z.err != nil {
return FourCC{}, 0, nil, z.err
}
// Drain the rest of the previous chunk.
if z.chunkLen != 0 {
want := z.chunkLen
var got int64
got, z.err = io.Copy(ioutil.Discard, z.chunkReader)
if z.err == nil && uint32(got) != want {
z.err = errShortChunkData
}
if z.err != nil {
return FourCC{}, 0, nil, z.err
}
}
z.chunkReader = nil
if z.padded {
if z.totalLen == 0 {
z.err = errListSubchunkTooLong
return FourCC{}, 0, nil, z.err
}
z.totalLen--
_, z.err = io.ReadFull(z.r, z.buf[:1])
if z.err != nil {
if z.err == io.EOF {
z.err = errMissingPaddingByte
}
return FourCC{}, 0, nil, z.err
}
}
// We are done if we have no more data.
if z.totalLen == 0 {
z.err = io.EOF
return FourCC{}, 0, nil, z.err
}
// Read the next chunk header.
if z.totalLen < chunkHeaderSize {
z.err = errShortChunkHeader
return FourCC{}, 0, nil, z.err
}
z.totalLen -= chunkHeaderSize
if _, z.err = io.ReadFull(z.r, z.buf[:chunkHeaderSize]); z.err != nil {
if z.err == io.EOF || z.err == io.ErrUnexpectedEOF {
z.err = errShortChunkHeader
}
return FourCC{}, 0, nil, z.err
}
chunkID = FourCC{z.buf[0], z.buf[1], z.buf[2], z.buf[3]}
z.chunkLen = u32(z.buf[4:])
if z.chunkLen > z.totalLen {
z.err = errListSubchunkTooLong
return FourCC{}, 0, nil, z.err
}
z.padded = z.chunkLen&1 == 1
z.chunkReader = &chunkReader{z}
return chunkID, z.chunkLen, z.chunkReader, nil
}
type chunkReader struct {
z *Reader
}
func (c *chunkReader) Read(p []byte) (int, error) {
if c != c.z.chunkReader {
return 0, errStaleReader
}
z := c.z
if z.err != nil {
if z.err == io.EOF {
return 0, errStaleReader
}
return 0, z.err
}
n := int(z.chunkLen)
if n == 0 {
return 0, io.EOF
}
if n < 0 {
// Converting uint32 to int overflowed.
n = math.MaxInt32
}
if n > len(p) {
n = len(p)
}
n, err := z.r.Read(p[:n])
z.totalLen -= uint32(n)
z.chunkLen -= uint32(n)
if err != io.EOF {
z.err = err
}
return n, err
}
// Copyright 2011 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 tiff
import "io"
// buffer buffers an io.Reader to satisfy io.ReaderAt.
type buffer struct {
r io.Reader
buf []byte
}
// fill reads data from b.r until the buffer contains at least end bytes.
func (b *buffer) fill(end int) error {
m := len(b.buf)
if end > m {
if end > cap(b.buf) {
newcap := 1024
for newcap < end {
newcap *= 2
}
newbuf := make([]byte, end, newcap)
copy(newbuf, b.buf)
b.buf = newbuf
} else {
b.buf = b.buf[:end]
}
if n, err := io.ReadFull(b.r, b.buf[m:end]); err != nil {
end = m + n
b.buf = b.buf[:end]
return err
}
}
return nil
}
func (b *buffer) ReadAt(p []byte, off int64) (int, error) {
o := int(off)
end := o + len(p)
if int64(end) != off+int64(len(p)) {
return 0, io.ErrUnexpectedEOF
}
err := b.fill(end)
return copy(p, b.buf[o:end]), err
}
// Slice returns a slice of the underlying buffer. The slice contains
// n bytes starting at offset off.
func (b *buffer) Slice(off, n int) ([]byte, error) {
end := off + n
if err := b.fill(end); err != nil {
return nil, err
}
return b.buf[off:end], nil
}
// newReaderAt converts an io.Reader into an io.ReaderAt.
func newReaderAt(r io.Reader) io.ReaderAt {
if ra, ok := r.(io.ReaderAt); ok {
return ra
}
return &buffer{
r: r,
buf: make([]byte, 0, 1024),
}
}
// Copyright 2011 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 tiff
import (
"bufio"
"io"
)
type byteReader interface {
io.Reader
io.ByteReader
}
// unpackBits decodes the PackBits-compressed data in src and returns the
// uncompressed data.
//
// The PackBits compression format is described in section 9 (p. 42)
// of the TIFF spec.
func unpackBits(r io.Reader) ([]byte, error) {
buf := make([]byte, 128)
dst := make([]byte, 0, 1024)
br, ok := r.(byteReader)
if !ok {
br = bufio.NewReader(r)
}
for {
b, err := br.ReadByte()
if err != nil {
if err == io.EOF {
return dst, nil
}
return nil, err
}
code := int(int8(b))
switch {
case code >= 0:
n, err := io.ReadFull(br, buf[:code+1])
if err != nil {
return nil, err
}
dst = append(dst, buf[:n]...)
case code == -128:
// No-op.
default:
if b, err = br.ReadByte(); err != nil {
return nil, err
}
for j := 0; j < 1-code; j++ {
buf[j] = b
}
dst = append(dst, buf[:1-code]...)
}
}
}
// Copyright 2011 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 tiff
// A tiff image file contains one or more images. The metadata
// of each image is contained in an Image File Directory (IFD),
// which contains entries of 12 bytes each and is described
// on page 14-16 of the specification. An IFD entry consists of
//
// - a tag, which describes the signification of the entry,
// - the data type and length of the entry,
// - the data itself or a pointer to it if it is more than 4 bytes.
//
// The presence of a length means that each IFD is effectively an array.
const (
leHeader = "II\x2A\x00" // Header for little-endian files.
beHeader = "MM\x00\x2A" // Header for big-endian files.
ifdLen = 12 // Length of an IFD entry in bytes.
)
// Data types (p. 14-16 of the spec).
const (
dtByte = 1
dtASCII = 2
dtShort = 3
dtLong = 4
dtRational = 5
)
// The length of one instance of each data type in bytes.
var lengths = [...]uint32{0, 1, 1, 2, 4, 8}
// Tags (see p. 28-41 of the spec).
const (
tImageWidth = 256
tImageLength = 257
tBitsPerSample = 258
tCompression = 259
tPhotometricInterpretation = 262
tFillOrder = 266
tStripOffsets = 273
tSamplesPerPixel = 277
tRowsPerStrip = 278
tStripByteCounts = 279
tT4Options = 292 // CCITT Group 3 options, a set of 32 flag bits.
tT6Options = 293 // CCITT Group 4 options, a set of 32 flag bits.
tTileWidth = 322
tTileLength = 323
tTileOffsets = 324
tTileByteCounts = 325
tXResolution = 282
tYResolution = 283
tResolutionUnit = 296
tPredictor = 317
tColorMap = 320
tExtraSamples = 338
tSampleFormat = 339
)
// Compression types (defined in various places in the spec and supplements).
const (
cNone = 1
cCCITT = 2
cG3 = 3 // Group 3 Fax.
cG4 = 4 // Group 4 Fax.
cLZW = 5
cJPEGOld = 6 // Superseded by cJPEG.
cJPEG = 7
cDeflate = 8 // zlib compression.
cPackBits = 32773
cDeflateOld = 32946 // Superseded by cDeflate.
)
// Photometric interpretation values (see p. 37 of the spec).
const (
pWhiteIsZero = 0
pBlackIsZero = 1
pRGB = 2
pPaletted = 3
pTransMask = 4 // transparency mask
pCMYK = 5
pYCbCr = 6
pCIELab = 8
)
// Values for the tPredictor tag (page 64-65 of the spec).
const (
prNone = 1
prHorizontal = 2
)
// Values for the tResolutionUnit tag (page 18).
const (
resNone = 1
resPerInch = 2 // Dots per inch.
resPerCM = 3 // Dots per centimeter.
)
// imageMode represents the mode of the image.
type imageMode int
const (
mBilevel imageMode = iota
mPaletted
mGray
mGrayInvert
mRGB
mRGBA
mNRGBA
mCMYK
)
// CompressionType describes the type of compression used in Options.
type CompressionType int
// Constants for supported compression types.
const (
Uncompressed CompressionType = iota
Deflate
LZW
CCITTGroup3
CCITTGroup4
)
// specValue returns the compression type constant from the TIFF spec that
// is equivalent to c.
func (c CompressionType) specValue() uint32 {
switch c {
case LZW:
return cLZW
case Deflate:
return cDeflate
case CCITTGroup3:
return cG3
case CCITTGroup4:
return cG4
}
return cNone
}
// Copyright 2019 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.
//go:build gofuzz
package tiff
import "bytes"
func Fuzz(data []byte) int {
cfg, err := DecodeConfig(bytes.NewReader(data))
if err != nil {
return 0
}
if cfg.Width*cfg.Height > 1e6 {
return 0
}
img, err := Decode(bytes.NewReader(data))
if err != nil {
return 0
}
var w bytes.Buffer
err = Encode(&w, img, nil)
if err != nil {
panic(err)
}
return 1
}
// Copyright 2011 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 lzw implements the Lempel-Ziv-Welch compressed data format,
// described in T. A. Welch, “A Technique for High-Performance Data
// Compression”, Computer, 17(6) (June 1984), pp 8-19.
//
// In particular, it implements LZW as used by the TIFF file format, including
// an "off by one" algorithmic difference when compared to standard LZW.
package lzw // import "golang.org/x/image/tiff/lzw"
/*
This file was branched from src/pkg/compress/lzw/reader.go in the
standard library. Differences from the original are marked with "NOTE".
The tif_lzw.c file in the libtiff C library has this comment:
----
The 5.0 spec describes a different algorithm than Aldus
implements. Specifically, Aldus does code length transitions
one code earlier than should be done (for real LZW).
Earlier versions of this library implemented the correct
LZW algorithm, but emitted codes in a bit order opposite
to the TIFF spec. Thus, to maintain compatibility w/ Aldus
we interpret MSB-LSB ordered codes to be images written w/
old versions of this library, but otherwise adhere to the
Aldus "off by one" algorithm.
----
The Go code doesn't read (invalid) TIFF files written by old versions of
libtiff, but the LZW algorithm in this package still differs from the one in
Go's standard package library to accommodate this "off by one" in valid TIFFs.
*/
import (
"bufio"
"errors"
"fmt"
"io"
)
// Order specifies the bit ordering in an LZW data stream.
type Order int
const (
// LSB means Least Significant Bits first, as used in the GIF file format.
LSB Order = iota
// MSB means Most Significant Bits first, as used in the TIFF and PDF
// file formats.
MSB
)
const (
maxWidth = 12
decoderInvalidCode = 0xffff
flushBuffer = 1 << maxWidth
)
// decoder is the state from which the readXxx method converts a byte
// stream into a code stream.
type decoder struct {
r io.ByteReader
bits uint32
nBits uint
width uint
read func(*decoder) (uint16, error) // readLSB or readMSB
litWidth int // width in bits of literal codes
err error
// The first 1<<litWidth codes are literal codes.
// The next two codes mean clear and EOF.
// Other valid codes are in the range [lo, hi] where lo := clear + 2,
// with the upper bound incrementing on each code seen.
// overflow is the code at which hi overflows the code width. NOTE: TIFF's LZW is "off by one".
// last is the most recently seen code, or decoderInvalidCode.
clear, eof, hi, overflow, last uint16
// Each code c in [lo, hi] expands to two or more bytes. For c != hi:
// suffix[c] is the last of these bytes.
// prefix[c] is the code for all but the last byte.
// This code can either be a literal code or another code in [lo, c).
// The c == hi case is a special case.
suffix [1 << maxWidth]uint8
prefix [1 << maxWidth]uint16
// output is the temporary output buffer.
// Literal codes are accumulated from the start of the buffer.
// Non-literal codes decode to a sequence of suffixes that are first
// written right-to-left from the end of the buffer before being copied
// to the start of the buffer.
// It is flushed when it contains >= 1<<maxWidth bytes,
// so that there is always room to decode an entire code.
output [2 * 1 << maxWidth]byte
o int // write index into output
toRead []byte // bytes to return from Read
}
// readLSB returns the next code for "Least Significant Bits first" data.
func (d *decoder) readLSB() (uint16, error) {
for d.nBits < d.width {
x, err := d.r.ReadByte()
if err != nil {
return 0, err
}
d.bits |= uint32(x) << d.nBits
d.nBits += 8
}
code := uint16(d.bits & (1<<d.width - 1))
d.bits >>= d.width
d.nBits -= d.width
return code, nil
}
// readMSB returns the next code for "Most Significant Bits first" data.
func (d *decoder) readMSB() (uint16, error) {
for d.nBits < d.width {
x, err := d.r.ReadByte()
if err != nil {
return 0, err
}
d.bits |= uint32(x) << (24 - d.nBits)
d.nBits += 8
}
code := uint16(d.bits >> (32 - d.width))
d.bits <<= d.width
d.nBits -= d.width
return code, nil
}
func (d *decoder) Read(b []byte) (int, error) {
for {
if len(d.toRead) > 0 {
n := copy(b, d.toRead)
d.toRead = d.toRead[n:]
return n, nil
}
if d.err != nil {
return 0, d.err
}
d.decode()
}
}
// decode decompresses bytes from r and leaves them in d.toRead.
// read specifies how to decode bytes into codes.
// litWidth is the width in bits of literal codes.
func (d *decoder) decode() {
// Loop over the code stream, converting codes into decompressed bytes.
loop:
for {
code, err := d.read(d)
if err != nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
d.err = err
break
}
switch {
case code < d.clear:
// We have a literal code.
d.output[d.o] = uint8(code)
d.o++
if d.last != decoderInvalidCode {
// Save what the hi code expands to.
d.suffix[d.hi] = uint8(code)
d.prefix[d.hi] = d.last
}
case code == d.clear:
d.width = 1 + uint(d.litWidth)
d.hi = d.eof
d.overflow = 1 << d.width
d.last = decoderInvalidCode
continue
case code == d.eof:
d.err = io.EOF
break loop
case code <= d.hi:
c, i := code, len(d.output)-1
if code == d.hi && d.last != decoderInvalidCode {
// code == hi is a special case which expands to the last expansion
// followed by the head of the last expansion. To find the head, we walk
// the prefix chain until we find a literal code.
c = d.last
for c >= d.clear {
c = d.prefix[c]
}
d.output[i] = uint8(c)
i--
c = d.last
}
// Copy the suffix chain into output and then write that to w.
for c >= d.clear {
d.output[i] = d.suffix[c]
i--
c = d.prefix[c]
}
d.output[i] = uint8(c)
d.o += copy(d.output[d.o:], d.output[i:])
if d.last != decoderInvalidCode {
// Save what the hi code expands to.
d.suffix[d.hi] = uint8(c)
d.prefix[d.hi] = d.last
}
default:
d.err = errors.New("lzw: invalid code")
break loop
}
d.last, d.hi = code, d.hi+1
if d.hi+1 >= d.overflow { // NOTE: the "+1" is where TIFF's LZW differs from the standard algorithm.
if d.width == maxWidth {
d.last = decoderInvalidCode
} else {
d.width++
d.overflow <<= 1
}
}
if d.o >= flushBuffer {
break
}
}
// Flush pending output.
d.toRead = d.output[:d.o]
d.o = 0
}
var errClosed = errors.New("lzw: reader/writer is closed")
func (d *decoder) Close() error {
d.err = errClosed // in case any Reads come along
return nil
}
// NewReader creates a new io.ReadCloser.
// Reads from the returned io.ReadCloser read and decompress data from r.
// If r does not also implement io.ByteReader,
// the decompressor may read more data than necessary from r.
// It is the caller's responsibility to call Close on the ReadCloser when
// finished reading.
// The number of bits to use for literal codes, litWidth, must be in the
// range [2,8] and is typically 8. It must equal the litWidth
// used during compression.
func NewReader(r io.Reader, order Order, litWidth int) io.ReadCloser {
d := new(decoder)
switch order {
case LSB:
d.read = (*decoder).readLSB
case MSB:
d.read = (*decoder).readMSB
default:
d.err = errors.New("lzw: unknown order")
return d
}
if litWidth < 2 || 8 < litWidth {
d.err = fmt.Errorf("lzw: litWidth %d out of range", litWidth)
return d
}
if br, ok := r.(io.ByteReader); ok {
d.r = br
} else {
d.r = bufio.NewReader(r)
}
d.litWidth = litWidth
d.width = 1 + uint(litWidth)
d.clear = uint16(1) << uint(litWidth)
d.eof, d.hi = d.clear+1, d.clear+1
d.overflow = uint16(1) << d.width
d.last = decoderInvalidCode
return d
}
// Copyright 2011 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 tiff implements a TIFF image decoder and encoder.
//
// The TIFF specification is at http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf
package tiff // import "golang.org/x/image/tiff"
import (
"bytes"
"compress/zlib"
"encoding/binary"
"fmt"
"image"
"image/color"
"io"
"math"
"golang.org/x/image/ccitt"
"golang.org/x/image/tiff/lzw"
)
// A FormatError reports that the input is not a valid TIFF image.
type FormatError string
func (e FormatError) Error() string {
return "tiff: invalid format: " + string(e)
}
// An UnsupportedError reports that the input uses a valid but
// unimplemented feature.
type UnsupportedError string
func (e UnsupportedError) Error() string {
return "tiff: unsupported feature: " + string(e)
}
var (
errNoPixels = FormatError("not enough pixel data")
errInvalidColorIndex = FormatError("invalid color index")
)
const maxChunkSize = 10 << 20 // 10M
// safeReadAt is a verbatim copy of internal/saferio.ReadDataAt from the
// standard library, which is used to read data from a reader using a length
// provided by untrusted data, without allocating the entire slice ahead of time
// if it is large (>maxChunkSize). This allows us to avoid allocating giant
// slices before learning that we can't actually read that much data from the
// reader.
func safeReadAt(r io.ReaderAt, n uint64, off int64) ([]byte, error) {
if int64(n) < 0 || n != uint64(int(n)) {
// n is too large to fit in int, so we can't allocate
// a buffer large enough. Treat this as a read failure.
return nil, io.ErrUnexpectedEOF
}
if n < maxChunkSize {
buf := make([]byte, n)
_, err := r.ReadAt(buf, off)
if err != nil {
// io.SectionReader can return EOF for n == 0,
// but for our purposes that is a success.
if err != io.EOF || n > 0 {
return nil, err
}
}
return buf, nil
}
var buf []byte
buf1 := make([]byte, maxChunkSize)
for n > 0 {
next := n
if next > maxChunkSize {
next = maxChunkSize
}
_, err := r.ReadAt(buf1[:next], off)
if err != nil {
return nil, err
}
buf = append(buf, buf1[:next]...)
n -= next
off += int64(next)
}
return buf, nil
}
type decoder struct {
r io.ReaderAt
byteOrder binary.ByteOrder
config image.Config
mode imageMode
bpp uint
features map[int][]uint
palette []color.Color
buf []byte
off int // Current offset in buf.
v uint32 // Buffer value for reading with arbitrary bit depths.
nbits uint // Remaining number of bits in v.
}
// firstVal returns the first uint of the features entry with the given tag,
// or 0 if the tag does not exist.
func (d *decoder) firstVal(tag int) uint {
f := d.features[tag]
if len(f) == 0 {
return 0
}
return f[0]
}
// ifdUint decodes the IFD entry in p, which must be of the Byte, Short
// or Long type, and returns the decoded uint values.
func (d *decoder) ifdUint(p []byte) (u []uint, err error) {
var raw []byte
if len(p) < ifdLen {
return nil, FormatError("bad IFD entry")
}
datatype := d.byteOrder.Uint16(p[2:4])
if dt := int(datatype); dt <= 0 || dt >= len(lengths) {
return nil, UnsupportedError("IFD entry datatype")
}
count := d.byteOrder.Uint32(p[4:8])
if count > math.MaxInt32/lengths[datatype] {
return nil, FormatError("IFD data too large")
}
if datalen := lengths[datatype] * count; datalen > 4 {
// The IFD contains a pointer to the real value.
raw, err = safeReadAt(d.r, uint64(datalen), int64(d.byteOrder.Uint32(p[8:12])))
} else {
raw = p[8 : 8+datalen]
}
if err != nil {
return nil, err
}
u = make([]uint, count)
switch datatype {
case dtByte:
for i := uint32(0); i < count; i++ {
u[i] = uint(raw[i])
}
case dtShort:
for i := uint32(0); i < count; i++ {
u[i] = uint(d.byteOrder.Uint16(raw[2*i : 2*(i+1)]))
}
case dtLong:
for i := uint32(0); i < count; i++ {
u[i] = uint(d.byteOrder.Uint32(raw[4*i : 4*(i+1)]))
}
default:
return nil, UnsupportedError("data type")
}
return u, nil
}
// parseIFD decides whether the IFD entry in p is "interesting" and
// stows away the data in the decoder. It returns the tag number of the
// entry and an error, if any.
func (d *decoder) parseIFD(p []byte) (int, error) {
tag := d.byteOrder.Uint16(p[0:2])
switch tag {
case tBitsPerSample,
tExtraSamples,
tPhotometricInterpretation,
tCompression,
tPredictor,
tStripOffsets,
tStripByteCounts,
tRowsPerStrip,
tTileWidth,
tTileLength,
tTileOffsets,
tTileByteCounts,
tImageLength,
tImageWidth,
tFillOrder,
tT4Options,
tT6Options:
val, err := d.ifdUint(p)
if err != nil {
return 0, err
}
d.features[int(tag)] = val
case tColorMap:
val, err := d.ifdUint(p)
if err != nil {
return 0, err
}
numcolors := len(val) / 3
if len(val)%3 != 0 || numcolors <= 0 || numcolors > 256 {
return 0, FormatError("bad ColorMap length")
}
d.palette = make([]color.Color, numcolors)
for i := 0; i < numcolors; i++ {
d.palette[i] = color.RGBA64{
uint16(val[i]),
uint16(val[i+numcolors]),
uint16(val[i+2*numcolors]),
0xffff,
}
}
case tSampleFormat:
// Page 27 of the spec: If the SampleFormat is present and
// the value is not 1 [= unsigned integer data], a Baseline
// TIFF reader that cannot handle the SampleFormat value
// must terminate the import process gracefully.
val, err := d.ifdUint(p)
if err != nil {
return 0, err
}
for _, v := range val {
if v != 1 {
return 0, UnsupportedError("sample format")
}
}
}
return int(tag), nil
}
// readBits reads n bits from the internal buffer starting at the current offset.
func (d *decoder) readBits(n uint) (v uint32, ok bool) {
for d.nbits < n {
d.v <<= 8
if d.off >= len(d.buf) {
return 0, false
}
d.v |= uint32(d.buf[d.off])
d.off++
d.nbits += 8
}
d.nbits -= n
rv := d.v >> d.nbits
d.v &^= rv << d.nbits
return rv, true
}
// flushBits discards the unread bits in the buffer used by readBits.
// It is used at the end of a line.
func (d *decoder) flushBits() {
d.v = 0
d.nbits = 0
}
// minInt returns the smaller of x or y.
func minInt(a, b int) int {
if a <= b {
return a
}
return b
}
// decode decodes the raw data of an image.
// It reads from d.buf and writes the strip or tile into dst.
func (d *decoder) decode(dst image.Image, xmin, ymin, xmax, ymax int) error {
d.off = 0
// Apply horizontal predictor if necessary.
// In this case, p contains the color difference to the preceding pixel.
// See page 64-65 of the spec.
if d.firstVal(tPredictor) == prHorizontal {
switch d.bpp {
case 16:
var off int
n := 2 * len(d.features[tBitsPerSample]) // bytes per sample times samples per pixel
for y := ymin; y < ymax; y++ {
off += n
for x := 0; x < (xmax-xmin-1)*n; x += 2 {
if off+2 > len(d.buf) {
return errNoPixels
}
v0 := d.byteOrder.Uint16(d.buf[off-n : off-n+2])
v1 := d.byteOrder.Uint16(d.buf[off : off+2])
d.byteOrder.PutUint16(d.buf[off:off+2], v1+v0)
off += 2
}
}
case 8:
var off int
n := 1 * len(d.features[tBitsPerSample]) // bytes per sample times samples per pixel
for y := ymin; y < ymax; y++ {
off += n
for x := 0; x < (xmax-xmin-1)*n; x++ {
if off >= len(d.buf) {
return errNoPixels
}
d.buf[off] += d.buf[off-n]
off++
}
}
case 1:
return UnsupportedError("horizontal predictor with 1 BitsPerSample")
}
}
rMaxX := minInt(xmax, dst.Bounds().Max.X)
rMaxY := minInt(ymax, dst.Bounds().Max.Y)
switch d.mode {
case mGray, mGrayInvert:
if d.bpp == 16 {
img := dst.(*image.Gray16)
for y := ymin; y < rMaxY; y++ {
for x := xmin; x < rMaxX; x++ {
if d.off+2 > len(d.buf) {
return errNoPixels
}
v := d.byteOrder.Uint16(d.buf[d.off : d.off+2])
d.off += 2
if d.mode == mGrayInvert {
v = 0xffff - v
}
img.SetGray16(x, y, color.Gray16{v})
}
if rMaxX == img.Bounds().Max.X {
d.off += 2 * (xmax - img.Bounds().Max.X)
}
}
} else {
img := dst.(*image.Gray)
max := uint32((1 << d.bpp) - 1)
for y := ymin; y < rMaxY; y++ {
for x := xmin; x < rMaxX; x++ {
v, ok := d.readBits(d.bpp)
if !ok {
return errNoPixels
}
v = v * 0xff / max
if d.mode == mGrayInvert {
v = 0xff - v
}
img.SetGray(x, y, color.Gray{uint8(v)})
}
d.flushBits()
}
}
case mPaletted:
img := dst.(*image.Paletted)
pLen := len(d.palette)
for y := ymin; y < rMaxY; y++ {
for x := xmin; x < rMaxX; x++ {
v, ok := d.readBits(d.bpp)
if !ok {
return errNoPixels
}
idx := uint8(v)
if int(idx) >= pLen {
return errInvalidColorIndex
}
img.SetColorIndex(x, y, idx)
}
d.flushBits()
}
case mRGB:
if d.bpp == 16 {
img := dst.(*image.RGBA64)
for y := ymin; y < rMaxY; y++ {
for x := xmin; x < rMaxX; x++ {
if d.off+6 > len(d.buf) {
return errNoPixels
}
r := d.byteOrder.Uint16(d.buf[d.off+0 : d.off+2])
g := d.byteOrder.Uint16(d.buf[d.off+2 : d.off+4])
b := d.byteOrder.Uint16(d.buf[d.off+4 : d.off+6])
d.off += 6
img.SetRGBA64(x, y, color.RGBA64{r, g, b, 0xffff})
}
}
} else {
img := dst.(*image.RGBA)
for y := ymin; y < rMaxY; y++ {
min := img.PixOffset(xmin, y)
max := img.PixOffset(rMaxX, y)
off := (y - ymin) * (xmax - xmin) * 3
for i := min; i < max; i += 4 {
if off+3 > len(d.buf) {
return errNoPixels
}
img.Pix[i+0] = d.buf[off+0]
img.Pix[i+1] = d.buf[off+1]
img.Pix[i+2] = d.buf[off+2]
img.Pix[i+3] = 0xff
off += 3
}
}
}
case mNRGBA:
if d.bpp == 16 {
img := dst.(*image.NRGBA64)
for y := ymin; y < rMaxY; y++ {
for x := xmin; x < rMaxX; x++ {
if d.off+8 > len(d.buf) {
return errNoPixels
}
r := d.byteOrder.Uint16(d.buf[d.off+0 : d.off+2])
g := d.byteOrder.Uint16(d.buf[d.off+2 : d.off+4])
b := d.byteOrder.Uint16(d.buf[d.off+4 : d.off+6])
a := d.byteOrder.Uint16(d.buf[d.off+6 : d.off+8])
d.off += 8
img.SetNRGBA64(x, y, color.NRGBA64{r, g, b, a})
}
}
} else {
img := dst.(*image.NRGBA)
for y := ymin; y < rMaxY; y++ {
min := img.PixOffset(xmin, y)
max := img.PixOffset(rMaxX, y)
i0, i1 := (y-ymin)*(xmax-xmin)*4, (y-ymin+1)*(xmax-xmin)*4
if i1 > len(d.buf) {
return errNoPixels
}
copy(img.Pix[min:max], d.buf[i0:i1])
}
}
case mRGBA:
if d.bpp == 16 {
img := dst.(*image.RGBA64)
for y := ymin; y < rMaxY; y++ {
for x := xmin; x < rMaxX; x++ {
if d.off+8 > len(d.buf) {
return errNoPixels
}
r := d.byteOrder.Uint16(d.buf[d.off+0 : d.off+2])
g := d.byteOrder.Uint16(d.buf[d.off+2 : d.off+4])
b := d.byteOrder.Uint16(d.buf[d.off+4 : d.off+6])
a := d.byteOrder.Uint16(d.buf[d.off+6 : d.off+8])
d.off += 8
img.SetRGBA64(x, y, color.RGBA64{r, g, b, a})
}
}
} else {
img := dst.(*image.RGBA)
for y := ymin; y < rMaxY; y++ {
min := img.PixOffset(xmin, y)
max := img.PixOffset(rMaxX, y)
i0, i1 := (y-ymin)*(xmax-xmin)*4, (y-ymin+1)*(xmax-xmin)*4
if i1 > len(d.buf) {
return errNoPixels
}
copy(img.Pix[min:max], d.buf[i0:i1])
}
}
}
return nil
}
func newDecoder(r io.Reader) (*decoder, error) {
d := &decoder{
r: newReaderAt(r),
features: make(map[int][]uint),
}
p := make([]byte, 8)
if _, err := d.r.ReadAt(p, 0); err != nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return nil, err
}
switch string(p[0:4]) {
case leHeader:
d.byteOrder = binary.LittleEndian
case beHeader:
d.byteOrder = binary.BigEndian
default:
return nil, FormatError("malformed header")
}
ifdOffset := int64(d.byteOrder.Uint32(p[4:8]))
// The first two bytes contain the number of entries (12 bytes each).
if _, err := d.r.ReadAt(p[0:2], ifdOffset); err != nil {
return nil, err
}
numItems := int(d.byteOrder.Uint16(p[0:2]))
// All IFD entries are read in one chunk.
var err error
p, err = safeReadAt(d.r, uint64(ifdLen*numItems), ifdOffset+2)
if err != nil {
return nil, err
}
prevTag := -1
for i := 0; i < len(p); i += ifdLen {
tag, err := d.parseIFD(p[i : i+ifdLen])
if err != nil {
return nil, err
}
if tag <= prevTag {
return nil, FormatError("tags are not sorted in ascending order")
}
prevTag = tag
}
d.config.Width = int(d.firstVal(tImageWidth))
d.config.Height = int(d.firstVal(tImageLength))
if _, ok := d.features[tBitsPerSample]; !ok {
// Default is 1 per specification.
d.features[tBitsPerSample] = []uint{1}
}
d.bpp = d.firstVal(tBitsPerSample)
switch d.bpp {
case 0:
return nil, FormatError("BitsPerSample must not be 0")
case 1, 8, 16:
// Nothing to do, these are accepted by this implementation.
default:
return nil, UnsupportedError(fmt.Sprintf("BitsPerSample of %v", d.bpp))
}
// Determine the image mode.
switch d.firstVal(tPhotometricInterpretation) {
case pRGB:
if d.bpp == 16 {
for _, b := range d.features[tBitsPerSample] {
if b != 16 {
return nil, FormatError("wrong number of samples for 16bit RGB")
}
}
} else {
for _, b := range d.features[tBitsPerSample] {
if b != 8 {
return nil, FormatError("wrong number of samples for 8bit RGB")
}
}
}
// RGB images normally have 3 samples per pixel.
// If there are more, ExtraSamples (p. 31-32 of the spec)
// gives their meaning (usually an alpha channel).
//
// This implementation does not support extra samples
// of an unspecified type.
switch len(d.features[tBitsPerSample]) {
case 3:
d.mode = mRGB
if d.bpp == 16 {
d.config.ColorModel = color.RGBA64Model
} else {
d.config.ColorModel = color.RGBAModel
}
case 4:
switch d.firstVal(tExtraSamples) {
case 1:
d.mode = mRGBA
if d.bpp == 16 {
d.config.ColorModel = color.RGBA64Model
} else {
d.config.ColorModel = color.RGBAModel
}
case 2:
d.mode = mNRGBA
if d.bpp == 16 {
d.config.ColorModel = color.NRGBA64Model
} else {
d.config.ColorModel = color.NRGBAModel
}
default:
return nil, FormatError("wrong number of samples for RGB")
}
default:
return nil, FormatError("wrong number of samples for RGB")
}
case pPaletted:
d.mode = mPaletted
d.config.ColorModel = color.Palette(d.palette)
case pWhiteIsZero:
d.mode = mGrayInvert
if d.bpp == 16 {
d.config.ColorModel = color.Gray16Model
} else {
d.config.ColorModel = color.GrayModel
}
case pBlackIsZero:
d.mode = mGray
if d.bpp == 16 {
d.config.ColorModel = color.Gray16Model
} else {
d.config.ColorModel = color.GrayModel
}
default:
return nil, UnsupportedError("color model")
}
if d.firstVal(tPhotometricInterpretation) != pRGB {
if len(d.features[tBitsPerSample]) != 1 {
return nil, UnsupportedError("extra samples")
}
}
return d, nil
}
// DecodeConfig returns the color model and dimensions of a TIFF image without
// decoding the entire image.
func DecodeConfig(r io.Reader) (image.Config, error) {
d, err := newDecoder(r)
if err != nil {
return image.Config{}, err
}
return d.config, nil
}
func ccittFillOrder(tiffFillOrder uint) ccitt.Order {
if tiffFillOrder == 2 {
return ccitt.LSB
}
return ccitt.MSB
}
// Decode reads a TIFF image from r and returns it as an image.Image.
// The type of Image returned depends on the contents of the TIFF.
func Decode(r io.Reader) (img image.Image, err error) {
d, err := newDecoder(r)
if err != nil {
return
}
blockPadding := false
blockWidth := d.config.Width
blockHeight := d.config.Height
blocksAcross := 1
blocksDown := 1
if d.config.Width == 0 {
blocksAcross = 0
}
if d.config.Height == 0 {
blocksDown = 0
}
var blockOffsets, blockCounts []uint
if int(d.firstVal(tTileWidth)) != 0 {
blockPadding = true
blockWidth = int(d.firstVal(tTileWidth))
blockHeight = int(d.firstVal(tTileLength))
// The specification says that tile widths and lengths must be a multiple of 16.
// We currently permit invalid sizes, but reject anything too small to limit the
// amount of work a malicious input can force us to perform.
if blockWidth < 8 || blockHeight < 8 {
return nil, FormatError("tile size is too small")
}
if blockWidth != 0 {
blocksAcross = (d.config.Width + blockWidth - 1) / blockWidth
}
if blockHeight != 0 {
blocksDown = (d.config.Height + blockHeight - 1) / blockHeight
}
blockCounts = d.features[tTileByteCounts]
blockOffsets = d.features[tTileOffsets]
} else {
if int(d.firstVal(tRowsPerStrip)) != 0 {
blockHeight = int(d.firstVal(tRowsPerStrip))
}
if blockHeight != 0 {
blocksDown = (d.config.Height + blockHeight - 1) / blockHeight
}
blockOffsets = d.features[tStripOffsets]
blockCounts = d.features[tStripByteCounts]
}
// Check if we have the right number of strips/tiles, offsets and counts.
if n := blocksAcross * blocksDown; len(blockOffsets) < n || len(blockCounts) < n {
return nil, FormatError("inconsistent header")
}
imgRect := image.Rect(0, 0, d.config.Width, d.config.Height)
switch d.mode {
case mGray, mGrayInvert:
if d.bpp == 16 {
img = image.NewGray16(imgRect)
} else {
img = image.NewGray(imgRect)
}
case mPaletted:
img = image.NewPaletted(imgRect, d.palette)
case mNRGBA:
if d.bpp == 16 {
img = image.NewNRGBA64(imgRect)
} else {
img = image.NewNRGBA(imgRect)
}
case mRGB, mRGBA:
if d.bpp == 16 {
img = image.NewRGBA64(imgRect)
} else {
img = image.NewRGBA(imgRect)
}
}
if blocksAcross == 0 || blocksDown == 0 {
return
}
// Maximum data per pixel is 8 bytes (RGBA64).
blockMaxDataSize := int64(blockWidth) * int64(blockHeight) * 8
for i := 0; i < blocksAcross; i++ {
blkW := blockWidth
if !blockPadding && i == blocksAcross-1 && d.config.Width%blockWidth != 0 {
blkW = d.config.Width % blockWidth
}
for j := 0; j < blocksDown; j++ {
blkH := blockHeight
if !blockPadding && j == blocksDown-1 && d.config.Height%blockHeight != 0 {
blkH = d.config.Height % blockHeight
}
offset := int64(blockOffsets[j*blocksAcross+i])
n := int64(blockCounts[j*blocksAcross+i])
switch d.firstVal(tCompression) {
// According to the spec, Compression does not have a default value,
// but some tools interpret a missing Compression value as none, so we do
// the same.
case cNone, 0:
if b, ok := d.r.(*buffer); ok {
d.buf, err = b.Slice(int(offset), int(n))
} else {
d.buf, err = safeReadAt(d.r, uint64(n), offset)
}
case cG3:
inv := d.firstVal(tPhotometricInterpretation) == pWhiteIsZero
order := ccittFillOrder(d.firstVal(tFillOrder))
r := ccitt.NewReader(io.NewSectionReader(d.r, offset, n), order, ccitt.Group3, blkW, blkH, &ccitt.Options{Invert: inv, Align: false})
d.buf, err = readBuf(r, d.buf, blockMaxDataSize)
case cG4:
inv := d.firstVal(tPhotometricInterpretation) == pWhiteIsZero
order := ccittFillOrder(d.firstVal(tFillOrder))
r := ccitt.NewReader(io.NewSectionReader(d.r, offset, n), order, ccitt.Group4, blkW, blkH, &ccitt.Options{Invert: inv, Align: false})
d.buf, err = readBuf(r, d.buf, blockMaxDataSize)
case cLZW:
r := lzw.NewReader(io.NewSectionReader(d.r, offset, n), lzw.MSB, 8)
d.buf, err = readBuf(r, d.buf, blockMaxDataSize)
r.Close()
case cDeflate, cDeflateOld:
var r io.ReadCloser
r, err = zlib.NewReader(io.NewSectionReader(d.r, offset, n))
if err != nil {
return nil, err
}
d.buf, err = readBuf(r, d.buf, blockMaxDataSize)
r.Close()
case cPackBits:
d.buf, err = unpackBits(io.NewSectionReader(d.r, offset, n))
default:
err = UnsupportedError(fmt.Sprintf("compression value %d", d.firstVal(tCompression)))
}
if err != nil {
return nil, err
}
xmin := i * blockWidth
ymin := j * blockHeight
xmax := xmin + blkW
ymax := ymin + blkH
err = d.decode(img, xmin, ymin, xmax, ymax)
if err != nil {
return nil, err
}
}
}
return
}
func readBuf(r io.Reader, buf []byte, lim int64) ([]byte, error) {
b := bytes.NewBuffer(buf[:0])
_, err := b.ReadFrom(io.LimitReader(r, lim))
return b.Bytes(), err
}
func init() {
image.RegisterFormat("tiff", leHeader, Decode, DecodeConfig)
image.RegisterFormat("tiff", beHeader, Decode, DecodeConfig)
}
// 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.
package tiff
import (
"bytes"
"compress/zlib"
"encoding/binary"
"errors"
"image"
"io"
"sort"
)
// The TIFF format allows to choose the order of the different elements freely.
// The basic structure of a TIFF file written by this package is:
//
// 1. Header (8 bytes).
// 2. Image data.
// 3. Image File Directory (IFD).
// 4. "Pointer area" for larger entries in the IFD.
// We only write little-endian TIFF files.
var enc = binary.LittleEndian
// An ifdEntry is a single entry in an Image File Directory.
// A value of type dtRational is composed of two 32-bit values,
// thus data contains two uints (numerator and denominator) for a single number.
type ifdEntry struct {
tag int
datatype int
data []uint32
}
func (e ifdEntry) putData(p []byte) {
for _, d := range e.data {
switch e.datatype {
case dtByte, dtASCII:
p[0] = byte(d)
p = p[1:]
case dtShort:
enc.PutUint16(p, uint16(d))
p = p[2:]
case dtLong, dtRational:
enc.PutUint32(p, uint32(d))
p = p[4:]
}
}
}
type byTag []ifdEntry
func (d byTag) Len() int { return len(d) }
func (d byTag) Less(i, j int) bool { return d[i].tag < d[j].tag }
func (d byTag) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
func encodeGray(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
if !predictor {
return writePix(w, pix, dy, dx, stride)
}
buf := make([]byte, dx)
for y := 0; y < dy; y++ {
min := y*stride + 0
max := y*stride + dx
off := 0
var v0 uint8
for i := min; i < max; i++ {
v1 := pix[i]
buf[off] = v1 - v0
v0 = v1
off++
}
if _, err := w.Write(buf); err != nil {
return err
}
}
return nil
}
func encodeGray16(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
buf := make([]byte, dx*2)
for y := 0; y < dy; y++ {
min := y*stride + 0
max := y*stride + dx*2
off := 0
var v0 uint16
for i := min; i < max; i += 2 {
// An image.Gray16's Pix is in big-endian order.
v1 := uint16(pix[i])<<8 | uint16(pix[i+1])
if predictor {
v0, v1 = v1, v1-v0
}
// We only write little-endian TIFF files.
buf[off+0] = byte(v1)
buf[off+1] = byte(v1 >> 8)
off += 2
}
if _, err := w.Write(buf); err != nil {
return err
}
}
return nil
}
func encodeRGBA(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
if !predictor {
return writePix(w, pix, dy, dx*4, stride)
}
buf := make([]byte, dx*4)
for y := 0; y < dy; y++ {
min := y*stride + 0
max := y*stride + dx*4
off := 0
var r0, g0, b0, a0 uint8
for i := min; i < max; i += 4 {
r1, g1, b1, a1 := pix[i+0], pix[i+1], pix[i+2], pix[i+3]
buf[off+0] = r1 - r0
buf[off+1] = g1 - g0
buf[off+2] = b1 - b0
buf[off+3] = a1 - a0
off += 4
r0, g0, b0, a0 = r1, g1, b1, a1
}
if _, err := w.Write(buf); err != nil {
return err
}
}
return nil
}
func encodeRGBA64(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
buf := make([]byte, dx*8)
for y := 0; y < dy; y++ {
min := y*stride + 0
max := y*stride + dx*8
off := 0
var r0, g0, b0, a0 uint16
for i := min; i < max; i += 8 {
// An image.RGBA64's Pix is in big-endian order.
r1 := uint16(pix[i+0])<<8 | uint16(pix[i+1])
g1 := uint16(pix[i+2])<<8 | uint16(pix[i+3])
b1 := uint16(pix[i+4])<<8 | uint16(pix[i+5])
a1 := uint16(pix[i+6])<<8 | uint16(pix[i+7])
if predictor {
r0, r1 = r1, r1-r0
g0, g1 = g1, g1-g0
b0, b1 = b1, b1-b0
a0, a1 = a1, a1-a0
}
// We only write little-endian TIFF files.
buf[off+0] = byte(r1)
buf[off+1] = byte(r1 >> 8)
buf[off+2] = byte(g1)
buf[off+3] = byte(g1 >> 8)
buf[off+4] = byte(b1)
buf[off+5] = byte(b1 >> 8)
buf[off+6] = byte(a1)
buf[off+7] = byte(a1 >> 8)
off += 8
}
if _, err := w.Write(buf); err != nil {
return err
}
}
return nil
}
func encode(w io.Writer, m image.Image, predictor bool) error {
bounds := m.Bounds()
buf := make([]byte, 4*bounds.Dx())
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
off := 0
if predictor {
var r0, g0, b0, a0 uint8
for x := bounds.Min.X; x < bounds.Max.X; x++ {
r, g, b, a := m.At(x, y).RGBA()
r1 := uint8(r >> 8)
g1 := uint8(g >> 8)
b1 := uint8(b >> 8)
a1 := uint8(a >> 8)
buf[off+0] = r1 - r0
buf[off+1] = g1 - g0
buf[off+2] = b1 - b0
buf[off+3] = a1 - a0
off += 4
r0, g0, b0, a0 = r1, g1, b1, a1
}
} else {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
r, g, b, a := m.At(x, y).RGBA()
buf[off+0] = uint8(r >> 8)
buf[off+1] = uint8(g >> 8)
buf[off+2] = uint8(b >> 8)
buf[off+3] = uint8(a >> 8)
off += 4
}
}
if _, err := w.Write(buf); err != nil {
return err
}
}
return nil
}
// writePix writes the internal byte array of an image to w. It is less general
// but much faster then encode. writePix is used when pix directly
// corresponds to one of the TIFF image types.
func writePix(w io.Writer, pix []byte, nrows, length, stride int) error {
if length == stride {
_, err := w.Write(pix[:nrows*length])
return err
}
for ; nrows > 0; nrows-- {
if _, err := w.Write(pix[:length]); err != nil {
return err
}
pix = pix[stride:]
}
return nil
}
func writeIFD(w io.Writer, ifdOffset int, d []ifdEntry) error {
var buf [ifdLen]byte
// Make space for "pointer area" containing IFD entry data
// longer than 4 bytes.
parea := make([]byte, 1024)
pstart := ifdOffset + ifdLen*len(d) + 6
var o int // Current offset in parea.
// The IFD has to be written with the tags in ascending order.
sort.Sort(byTag(d))
// Write the number of entries in this IFD.
if err := binary.Write(w, enc, uint16(len(d))); err != nil {
return err
}
for _, ent := range d {
enc.PutUint16(buf[0:2], uint16(ent.tag))
enc.PutUint16(buf[2:4], uint16(ent.datatype))
count := uint32(len(ent.data))
if ent.datatype == dtRational {
count /= 2
}
enc.PutUint32(buf[4:8], count)
datalen := int(count * lengths[ent.datatype])
if datalen <= 4 {
ent.putData(buf[8:12])
} else {
if (o + datalen) > len(parea) {
newlen := len(parea) + 1024
for (o + datalen) > newlen {
newlen += 1024
}
newarea := make([]byte, newlen)
copy(newarea, parea)
parea = newarea
}
ent.putData(parea[o : o+datalen])
enc.PutUint32(buf[8:12], uint32(pstart+o))
o += datalen
}
if _, err := w.Write(buf[:]); err != nil {
return err
}
}
// The IFD ends with the offset of the next IFD in the file,
// or zero if it is the last one (page 14).
if err := binary.Write(w, enc, uint32(0)); err != nil {
return err
}
_, err := w.Write(parea[:o])
return err
}
// Options are the encoding parameters.
type Options struct {
// Compression is the type of compression used.
Compression CompressionType
// Predictor determines whether a differencing predictor is used;
// if true, instead of each pixel's color, the color difference to the
// preceding one is saved. This improves the compression for certain
// types of images and compressors. For example, it works well for
// photos with Deflate compression.
Predictor bool
}
// Encode writes the image m to w. opt determines the options used for
// encoding, such as the compression type. If opt is nil, an uncompressed
// image is written.
func Encode(w io.Writer, m image.Image, opt *Options) error {
d := m.Bounds().Size()
compression := uint32(cNone)
predictor := false
if opt != nil {
compression = opt.Compression.specValue()
// The predictor field is only used with LZW. See page 64 of the spec.
predictor = opt.Predictor && compression == cLZW
}
_, err := io.WriteString(w, leHeader)
if err != nil {
return err
}
// Compressed data is written into a buffer first, so that we
// know the compressed size.
var buf bytes.Buffer
// dst holds the destination for the pixel data of the image --
// either w or a writer to buf.
var dst io.Writer
// imageLen is the length of the pixel data in bytes.
// The offset of the IFD is imageLen + 8 header bytes.
var imageLen int
switch compression {
case cNone:
dst = w
// Write IFD offset before outputting pixel data.
switch m.(type) {
case *image.Paletted:
imageLen = d.X * d.Y * 1
case *image.Gray:
imageLen = d.X * d.Y * 1
case *image.Gray16:
imageLen = d.X * d.Y * 2
case *image.RGBA64:
imageLen = d.X * d.Y * 8
case *image.NRGBA64:
imageLen = d.X * d.Y * 8
default:
imageLen = d.X * d.Y * 4
}
err = binary.Write(w, enc, uint32(imageLen+8))
if err != nil {
return err
}
case cDeflate:
dst = zlib.NewWriter(&buf)
default:
return errors.New("tiff: unsupported compression")
}
pr := uint32(prNone)
photometricInterpretation := uint32(pRGB)
samplesPerPixel := uint32(4)
bitsPerSample := []uint32{8, 8, 8, 8}
extraSamples := uint32(0)
colorMap := []uint32{}
if predictor {
pr = prHorizontal
}
switch m := m.(type) {
case *image.Paletted:
photometricInterpretation = pPaletted
samplesPerPixel = 1
bitsPerSample = []uint32{8}
colorMap = make([]uint32, 256*3)
for i := 0; i < 256 && i < len(m.Palette); i++ {
r, g, b, _ := m.Palette[i].RGBA()
colorMap[i+0*256] = uint32(r)
colorMap[i+1*256] = uint32(g)
colorMap[i+2*256] = uint32(b)
}
err = encodeGray(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
case *image.Gray:
photometricInterpretation = pBlackIsZero
samplesPerPixel = 1
bitsPerSample = []uint32{8}
err = encodeGray(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
case *image.Gray16:
photometricInterpretation = pBlackIsZero
samplesPerPixel = 1
bitsPerSample = []uint32{16}
err = encodeGray16(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
case *image.NRGBA:
extraSamples = 2 // Unassociated alpha.
err = encodeRGBA(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
case *image.NRGBA64:
extraSamples = 2 // Unassociated alpha.
bitsPerSample = []uint32{16, 16, 16, 16}
err = encodeRGBA64(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
case *image.RGBA:
extraSamples = 1 // Associated alpha.
err = encodeRGBA(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
case *image.RGBA64:
extraSamples = 1 // Associated alpha.
bitsPerSample = []uint32{16, 16, 16, 16}
err = encodeRGBA64(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
default:
extraSamples = 1 // Associated alpha.
err = encode(dst, m, predictor)
}
if err != nil {
return err
}
if compression != cNone {
if err = dst.(io.Closer).Close(); err != nil {
return err
}
imageLen = buf.Len()
if err = binary.Write(w, enc, uint32(imageLen+8)); err != nil {
return err
}
if _, err = buf.WriteTo(w); err != nil {
return err
}
}
ifd := []ifdEntry{
{tImageWidth, dtShort, []uint32{uint32(d.X)}},
{tImageLength, dtShort, []uint32{uint32(d.Y)}},
{tBitsPerSample, dtShort, bitsPerSample},
{tCompression, dtShort, []uint32{compression}},
{tPhotometricInterpretation, dtShort, []uint32{photometricInterpretation}},
{tStripOffsets, dtLong, []uint32{8}},
{tSamplesPerPixel, dtShort, []uint32{samplesPerPixel}},
{tRowsPerStrip, dtShort, []uint32{uint32(d.Y)}},
{tStripByteCounts, dtLong, []uint32{uint32(imageLen)}},
// There is currently no support for storing the image
// resolution, so give a bogus value of 72x72 dpi.
{tXResolution, dtRational, []uint32{72, 1}},
{tYResolution, dtRational, []uint32{72, 1}},
{tResolutionUnit, dtShort, []uint32{resPerInch}},
}
if pr != prNone {
ifd = append(ifd, ifdEntry{tPredictor, dtShort, []uint32{pr}})
}
if len(colorMap) != 0 {
ifd = append(ifd, ifdEntry{tColorMap, dtShort, colorMap})
}
if extraSamples > 0 {
ifd = append(ifd, ifdEntry{tExtraSamples, dtShort, []uint32{extraSamples}})
}
return writeIFD(w, imageLen+8, ifd)
}
// 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.
package vector
// This file contains a fixed point math implementation of the vector
// graphics rasterizer.
const (
// ϕ is the number of binary digits after the fixed point.
//
// For example, if ϕ == 10 (and int1ϕ is based on the int32 type) then we
// are using 22.10 fixed point math.
//
// When changing this number, also change the assembly code (search for ϕ
// in the .s files).
ϕ = 9
fxOne int1ϕ = 1 << ϕ
fxOneAndAHalf int1ϕ = 1<<ϕ + 1<<(ϕ-1)
fxOneMinusIota int1ϕ = 1<<ϕ - 1 // Used for rounding up.
)
// int1ϕ is a signed fixed-point number with 1*ϕ binary digits after the fixed
// point.
type int1ϕ int32
// int2ϕ is a signed fixed-point number with 2*ϕ binary digits after the fixed
// point.
//
// The Rasterizer's bufU32 field, nominally of type []uint32 (since that slice
// is also used by other code), can be thought of as a []int2ϕ during the
// fixedLineTo method. Lines of code that are actually like:
//
// buf[i] += uint32(etc) // buf has type []uint32.
//
// can be thought of as
//
// buf[i] += int2ϕ(etc) // buf has type []int2ϕ.
type int2ϕ int32
func fixedFloor(x int1ϕ) int32 { return int32(x >> ϕ) }
func fixedCeil(x int1ϕ) int32 { return int32((x + fxOneMinusIota) >> ϕ) }
func (z *Rasterizer) fixedLineTo(bx, by float32) {
ax, ay := z.penX, z.penY
z.penX, z.penY = bx, by
dir := int1ϕ(1)
if ay > by {
dir, ax, ay, bx, by = -1, bx, by, ax, ay
}
// Horizontal line segments yield no change in coverage. Almost horizontal
// segments would yield some change, in ideal math, but the computation
// further below, involving 1 / (by - ay), is unstable in fixed point math,
// so we treat the segment as if it was perfectly horizontal.
if by-ay <= 0.000001 {
return
}
dxdy := (bx - ax) / (by - ay)
ayϕ := int1ϕ(ay * float32(fxOne))
byϕ := int1ϕ(by * float32(fxOne))
x := int1ϕ(ax * float32(fxOne))
y := fixedFloor(ayϕ)
yMax := fixedCeil(byϕ)
if yMax > int32(z.size.Y) {
yMax = int32(z.size.Y)
}
width := int32(z.size.X)
for ; y < yMax; y++ {
dy := min(int1ϕ(y+1)<<ϕ, byϕ) - max(int1ϕ(y)<<ϕ, ayϕ)
xNext := x + int1ϕ(float32(dy)*dxdy)
if y < 0 {
x = xNext
continue
}
buf := z.bufU32[y*width:]
d := dy * dir // d ranges up to ±1<<(1*ϕ).
x0, x1 := x, xNext
if x > xNext {
x0, x1 = x1, x0
}
x0i := fixedFloor(x0)
x0Floor := int1ϕ(x0i) << ϕ
x1i := fixedCeil(x1)
x1Ceil := int1ϕ(x1i) << ϕ
if x1i <= x0i+1 {
xmf := (x+xNext)>>1 - x0Floor
if i := clamp(x0i+0, width); i < uint(len(buf)) {
buf[i] += uint32(d * (fxOne - xmf))
}
if i := clamp(x0i+1, width); i < uint(len(buf)) {
buf[i] += uint32(d * xmf)
}
} else {
oneOverS := x1 - x0
twoOverS := 2 * oneOverS
x0f := x0 - x0Floor
oneMinusX0f := fxOne - x0f
oneMinusX0fSquared := oneMinusX0f * oneMinusX0f
x1f := x1 - x1Ceil + fxOne
x1fSquared := x1f * x1f
// These next two variables are unused, as rounding errors are
// minimized when we delay the division by oneOverS for as long as
// possible. These lines of code (and the "In ideal math" comments
// below) are commented out instead of deleted in order to aid the
// comparison with the floating point version of the rasterizer.
//
// a0 := ((oneMinusX0f * oneMinusX0f) >> 1) / oneOverS
// am := ((x1f * x1f) >> 1) / oneOverS
if i := clamp(x0i, width); i < uint(len(buf)) {
// In ideal math: buf[i] += uint32(d * a0)
D := oneMinusX0fSquared // D ranges up to ±1<<(2*ϕ).
D *= d // D ranges up to ±1<<(3*ϕ).
D /= twoOverS
buf[i] += uint32(D)
}
if x1i == x0i+2 {
if i := clamp(x0i+1, width); i < uint(len(buf)) {
// In ideal math: buf[i] += uint32(d * (fxOne - a0 - am))
//
// (x1i == x0i+2) and (twoOverS == 2 * (x1 - x0)) implies
// that twoOverS ranges up to +1<<(1*ϕ+2).
D := twoOverS<<ϕ - oneMinusX0fSquared - x1fSquared // D ranges up to ±1<<(2*ϕ+2).
D *= d // D ranges up to ±1<<(3*ϕ+2).
D /= twoOverS
buf[i] += uint32(D)
}
} else {
// This is commented out for the same reason as a0 and am.
//
// a1 := ((fxOneAndAHalf - x0f) << ϕ) / oneOverS
if i := clamp(x0i+1, width); i < uint(len(buf)) {
// In ideal math:
// buf[i] += uint32(d * (a1 - a0))
// or equivalently (but better in non-ideal, integer math,
// with respect to rounding errors),
// buf[i] += uint32(A * d / twoOverS)
// where
// A = (a1 - a0) * twoOverS
// = a1*twoOverS - a0*twoOverS
// Noting that twoOverS/oneOverS equals 2, substituting for
// a0 and then a1, given above, yields:
// A = a1*twoOverS - oneMinusX0fSquared
// = (fxOneAndAHalf-x0f)<<(ϕ+1) - oneMinusX0fSquared
// = fxOneAndAHalf<<(ϕ+1) - x0f<<(ϕ+1) - oneMinusX0fSquared
//
// This is a positive number minus two non-negative
// numbers. For an upper bound on A, the positive number is
// P = fxOneAndAHalf<<(ϕ+1)
// < (2*fxOne)<<(ϕ+1)
// = fxOne<<(ϕ+2)
// = 1<<(2*ϕ+2)
//
// For a lower bound on A, the two non-negative numbers are
// N = x0f<<(ϕ+1) + oneMinusX0fSquared
// ≤ x0f<<(ϕ+1) + fxOne*fxOne
// = x0f<<(ϕ+1) + 1<<(2*ϕ)
// < x0f<<(ϕ+1) + 1<<(2*ϕ+1)
// ≤ fxOne<<(ϕ+1) + 1<<(2*ϕ+1)
// = 1<<(2*ϕ+1) + 1<<(2*ϕ+1)
// = 1<<(2*ϕ+2)
//
// Thus, A ranges up to ±1<<(2*ϕ+2). It is possible to
// derive a tighter bound, but this bound is sufficient to
// reason about overflow.
D := (fxOneAndAHalf-x0f)<<(ϕ+1) - oneMinusX0fSquared // D ranges up to ±1<<(2*ϕ+2).
D *= d // D ranges up to ±1<<(3*ϕ+2).
D /= twoOverS
buf[i] += uint32(D)
}
dTimesS := uint32((d << (2 * ϕ)) / oneOverS)
for xi := x0i + 2; xi < x1i-1; xi++ {
if i := clamp(xi, width); i < uint(len(buf)) {
buf[i] += dTimesS
}
}
// This is commented out for the same reason as a0 and am.
//
// a2 := a1 + (int1ϕ(x1i-x0i-3)<<(2*ϕ))/oneOverS
if i := clamp(x1i-1, width); i < uint(len(buf)) {
// In ideal math:
// buf[i] += uint32(d * (fxOne - a2 - am))
// or equivalently (but better in non-ideal, integer math,
// with respect to rounding errors),
// buf[i] += uint32(A * d / twoOverS)
// where
// A = (fxOne - a2 - am) * twoOverS
// = twoOverS<<ϕ - a2*twoOverS - am*twoOverS
// Noting that twoOverS/oneOverS equals 2, substituting for
// am and then a2, given above, yields:
// A = twoOverS<<ϕ - a2*twoOverS - x1f*x1f
// = twoOverS<<ϕ - a1*twoOverS - (int1ϕ(x1i-x0i-3)<<(2*ϕ))*2 - x1f*x1f
// = twoOverS<<ϕ - a1*twoOverS - int1ϕ(x1i-x0i-3)<<(2*ϕ+1) - x1f*x1f
// Substituting for a1, given above, yields:
// A = twoOverS<<ϕ - ((fxOneAndAHalf-x0f)<<ϕ)*2 - int1ϕ(x1i-x0i-3)<<(2*ϕ+1) - x1f*x1f
// = twoOverS<<ϕ - (fxOneAndAHalf-x0f)<<(ϕ+1) - int1ϕ(x1i-x0i-3)<<(2*ϕ+1) - x1f*x1f
// = B<<ϕ - x1f*x1f
// where
// B = twoOverS - (fxOneAndAHalf-x0f)<<1 - int1ϕ(x1i-x0i-3)<<(ϕ+1)
// = (x1-x0)<<1 - (fxOneAndAHalf-x0f)<<1 - int1ϕ(x1i-x0i-3)<<(ϕ+1)
//
// Re-arranging the defintions given above:
// x0Floor := int1ϕ(x0i) << ϕ
// x0f := x0 - x0Floor
// x1Ceil := int1ϕ(x1i) << ϕ
// x1f := x1 - x1Ceil + fxOne
// combined with fxOne = 1<<ϕ yields:
// x0 = x0f + int1ϕ(x0i)<<ϕ
// x1 = x1f + int1ϕ(x1i-1)<<ϕ
// so that expanding (x1-x0) yields:
// B = (x1f-x0f + int1ϕ(x1i-x0i-1)<<ϕ)<<1 - (fxOneAndAHalf-x0f)<<1 - int1ϕ(x1i-x0i-3)<<(ϕ+1)
// = (x1f-x0f)<<1 + int1ϕ(x1i-x0i-1)<<(ϕ+1) - (fxOneAndAHalf-x0f)<<1 - int1ϕ(x1i-x0i-3)<<(ϕ+1)
// A large part of the second and fourth terms cancel:
// B = (x1f-x0f)<<1 - (fxOneAndAHalf-x0f)<<1 - int1ϕ(-2)<<(ϕ+1)
// = (x1f-x0f)<<1 - (fxOneAndAHalf-x0f)<<1 + 1<<(ϕ+2)
// = (x1f - fxOneAndAHalf)<<1 + 1<<(ϕ+2)
// The first term, (x1f - fxOneAndAHalf)<<1, is a negative
// number, bounded below by -fxOneAndAHalf<<1, which is
// greater than -fxOne<<2, or -1<<(ϕ+2). Thus, B ranges up
// to ±1<<(ϕ+2). One final simplification:
// B = x1f<<1 + (1<<(ϕ+2) - fxOneAndAHalf<<1)
const C = 1<<(ϕ+2) - fxOneAndAHalf<<1
D := x1f<<1 + C // D ranges up to ±1<<(1*ϕ+2).
D <<= ϕ // D ranges up to ±1<<(2*ϕ+2).
D -= x1fSquared // D ranges up to ±1<<(2*ϕ+3).
D *= d // D ranges up to ±1<<(3*ϕ+3).
D /= twoOverS
buf[i] += uint32(D)
}
}
if i := clamp(x1i, width); i < uint(len(buf)) {
// In ideal math: buf[i] += uint32(d * am)
D := x1fSquared // D ranges up to ±1<<(2*ϕ).
D *= d // D ranges up to ±1<<(3*ϕ).
D /= twoOverS
buf[i] += uint32(D)
}
}
x = xNext
}
}
func fixedAccumulateOpOver(dst []uint8, src []uint32) {
// Sanity check that len(dst) >= len(src).
if len(dst) < len(src) {
return
}
acc := int2ϕ(0)
for i, v := range src {
acc += int2ϕ(v)
a := acc
if a < 0 {
a = -a
}
a >>= 2*ϕ - 16
if a > 0xffff {
a = 0xffff
}
// This algorithm comes from the standard library's image/draw package.
dstA := uint32(dst[i]) * 0x101
maskA := uint32(a)
outA := dstA*(0xffff-maskA)/0xffff + maskA
dst[i] = uint8(outA >> 8)
}
}
func fixedAccumulateOpSrc(dst []uint8, src []uint32) {
// Sanity check that len(dst) >= len(src).
if len(dst) < len(src) {
return
}
acc := int2ϕ(0)
for i, v := range src {
acc += int2ϕ(v)
a := acc
if a < 0 {
a = -a
}
a >>= 2*ϕ - 8
if a > 0xff {
a = 0xff
}
dst[i] = uint8(a)
}
}
func fixedAccumulateMask(buf []uint32) {
acc := int2ϕ(0)
for i, v := range buf {
acc += int2ϕ(v)
a := acc
if a < 0 {
a = -a
}
a >>= 2*ϕ - 16
if a > 0xffff {
a = 0xffff
}
buf[i] = uint32(a)
}
}
// 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.
package vector
// This file contains a floating point math implementation of the vector
// graphics rasterizer.
import (
"math"
)
func floatingFloor(x float32) int32 { return int32(math.Floor(float64(x))) }
func floatingCeil(x float32) int32 { return int32(math.Ceil(float64(x))) }
func (z *Rasterizer) floatingLineTo(bx, by float32) {
ax, ay := z.penX, z.penY
z.penX, z.penY = bx, by
dir := float32(1)
if ay > by {
dir, ax, ay, bx, by = -1, bx, by, ax, ay
}
// Horizontal line segments yield no change in coverage. Almost horizontal
// segments would yield some change, in ideal math, but the computation
// further below, involving 1 / (by - ay), is unstable in floating point
// math, so we treat the segment as if it was perfectly horizontal.
if by-ay <= 0.000001 {
return
}
dxdy := (bx - ax) / (by - ay)
x := ax
y := floatingFloor(ay)
yMax := floatingCeil(by)
if yMax > int32(z.size.Y) {
yMax = int32(z.size.Y)
}
width := int32(z.size.X)
for ; y < yMax; y++ {
dy := min(float32(y+1), by) - max(float32(y), ay)
// The "float32" in expressions like "float32(foo*bar)" here and below
// look redundant, since foo and bar already have type float32, but are
// explicit in order to disable the compiler's Fused Multiply Add (FMA)
// instruction selection, which can improve performance but can result
// in different rounding errors in floating point computations.
//
// This package aims to have bit-exact identical results across all
// GOARCHes, and across pure Go code and assembly, so it disables FMA.
//
// See the discussion at
// https://groups.google.com/d/topic/golang-dev/Sti0bl2xUXQ/discussion
xNext := x + float32(dy*dxdy)
if y < 0 {
x = xNext
continue
}
buf := z.bufF32[y*width:]
d := float32(dy * dir)
x0, x1 := x, xNext
if x > xNext {
x0, x1 = x1, x0
}
x0i := floatingFloor(x0)
x0Floor := float32(x0i)
x1i := floatingCeil(x1)
x1Ceil := float32(x1i)
if x1i <= x0i+1 {
xmf := float32(0.5*(x+xNext)) - x0Floor
if i := clamp(x0i+0, width); i < uint(len(buf)) {
buf[i] += d - float32(d*xmf)
}
if i := clamp(x0i+1, width); i < uint(len(buf)) {
buf[i] += float32(d * xmf)
}
} else {
s := 1 / (x1 - x0)
x0f := x0 - x0Floor
oneMinusX0f := 1 - x0f
a0 := float32(0.5 * s * oneMinusX0f * oneMinusX0f)
x1f := x1 - x1Ceil + 1
am := float32(0.5 * s * x1f * x1f)
if i := clamp(x0i, width); i < uint(len(buf)) {
buf[i] += float32(d * a0)
}
if x1i == x0i+2 {
if i := clamp(x0i+1, width); i < uint(len(buf)) {
buf[i] += float32(d * (1 - a0 - am))
}
} else {
a1 := float32(s * (1.5 - x0f))
if i := clamp(x0i+1, width); i < uint(len(buf)) {
buf[i] += float32(d * (a1 - a0))
}
dTimesS := float32(d * s)
for xi := x0i + 2; xi < x1i-1; xi++ {
if i := clamp(xi, width); i < uint(len(buf)) {
buf[i] += dTimesS
}
}
a2 := a1 + float32(s*float32(x1i-x0i-3))
if i := clamp(x1i-1, width); i < uint(len(buf)) {
buf[i] += float32(d * (1 - a2 - am))
}
}
if i := clamp(x1i, width); i < uint(len(buf)) {
buf[i] += float32(d * am)
}
}
x = xNext
}
}
const (
// almost256 scales a floating point value in the range [0, 1] to a uint8
// value in the range [0x00, 0xff].
//
// 255 is too small. Floating point math accumulates rounding errors, so a
// fully covered src value that would in ideal math be float32(1) might be
// float32(1-ε), and uint8(255 * (1-ε)) would be 0xfe instead of 0xff. The
// uint8 conversion rounds to zero, not to nearest.
//
// 256 is too big. If we multiplied by 256, below, then a fully covered src
// value of float32(1) would translate to uint8(256 * 1), which can be 0x00
// instead of the maximal value 0xff.
//
// math.Float32bits(almost256) is 0x437fffff.
almost256 = 255.99998
// almost65536 scales a floating point value in the range [0, 1] to a
// uint16 value in the range [0x0000, 0xffff].
//
// math.Float32bits(almost65536) is 0x477fffff.
almost65536 = almost256 * 256
)
func floatingAccumulateOpOver(dst []uint8, src []float32) {
// Sanity check that len(dst) >= len(src).
if len(dst) < len(src) {
return
}
acc := float32(0)
for i, v := range src {
acc += v
a := acc
if a < 0 {
a = -a
}
if a > 1 {
a = 1
}
// This algorithm comes from the standard library's image/draw package.
dstA := uint32(dst[i]) * 0x101
maskA := uint32(almost65536 * a)
outA := dstA*(0xffff-maskA)/0xffff + maskA
dst[i] = uint8(outA >> 8)
}
}
func floatingAccumulateOpSrc(dst []uint8, src []float32) {
// Sanity check that len(dst) >= len(src).
if len(dst) < len(src) {
return
}
acc := float32(0)
for i, v := range src {
acc += v
a := acc
if a < 0 {
a = -a
}
if a > 1 {
a = 1
}
dst[i] = uint8(almost256 * a)
}
}
func floatingAccumulateMask(dst []uint32, src []float32) {
// Sanity check that len(dst) >= len(src).
if len(dst) < len(src) {
return
}
acc := float32(0)
for i, v := range src {
acc += v
a := acc
if a < 0 {
a = -a
}
if a > 1 {
a = 1
}
dst[i] = uint32(almost65536 * a)
}
}
// 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.
//go:generate go run gen.go
//go:generate asmfmt -w acc_amd64.s
// asmfmt is https://github.com/klauspost/asmfmt
// Package vector provides a rasterizer for 2-D vector graphics.
package vector // import "golang.org/x/image/vector"
// The rasterizer's design follows
// https://medium.com/@raphlinus/inside-the-fastest-font-renderer-in-the-world-75ae5270c445
//
// Proof of concept code is in
// https://github.com/google/font-go
//
// See also:
// http://nothings.org/gamedev/rasterize/
// http://projects.tuxee.net/cl-vectors/section-the-cl-aa-algorithm
// https://people.gnome.org/~mathieu/libart/internals.html#INTERNALS-SCANLINE
import (
"image"
"image/color"
"image/draw"
"math"
)
// floatingPointMathThreshold is the width or height above which the rasterizer
// chooses to used floating point math instead of fixed point math.
//
// Both implementations of line segmentation rasterization (see raster_fixed.go
// and raster_floating.go) implement the same algorithm (in ideal, infinite
// precision math) but they perform differently in practice. The fixed point
// math version is roughly 1.25x faster (on GOARCH=amd64) on the benchmarks,
// but at sufficiently large scales, the computations will overflow and hence
// show rendering artifacts. The floating point math version has more
// consistent quality over larger scales, but it is significantly slower.
//
// This constant determines when to use the faster implementation and when to
// use the better quality implementation.
//
// The rationale for this particular value is that TestRasterizePolygon in
// vector_test.go checks the rendering quality of polygon edges at various
// angles, inscribed in a circle of diameter 512. It may be that a higher value
// would still produce acceptable quality, but 512 seems to work.
const floatingPointMathThreshold = 512
func lerp(t, px, py, qx, qy float32) (x, y float32) {
return px + t*(qx-px), py + t*(qy-py)
}
func clamp(i, width int32) uint {
if i < 0 {
return 0
}
if i < width {
return uint(i)
}
return uint(width)
}
// NewRasterizer returns a new Rasterizer whose rendered mask image is bounded
// by the given width and height.
func NewRasterizer(w, h int) *Rasterizer {
z := &Rasterizer{}
z.Reset(w, h)
return z
}
// Raster is a 2-D vector graphics rasterizer.
//
// The zero value is usable, in that it is a Rasterizer whose rendered mask
// image has zero width and zero height. Call Reset to change its bounds.
type Rasterizer struct {
// bufXxx are buffers of float32 or uint32 values, holding either the
// individual or cumulative area values.
//
// We don't actually need both values at any given time, and to conserve
// memory, the integration of the individual to the cumulative could modify
// the buffer in place. In other words, we could use a single buffer, say
// of type []uint32, and add some math.Float32bits and math.Float32frombits
// calls to satisfy the compiler's type checking. As of Go 1.7, though,
// there is a performance penalty between:
// bufF32[i] += x
// and
// bufU32[i] = math.Float32bits(x + math.Float32frombits(bufU32[i]))
//
// See golang.org/issue/17220 for some discussion.
bufF32 []float32
bufU32 []uint32
useFloatingPointMath bool
size image.Point
firstX float32
firstY float32
penX float32
penY float32
// DrawOp is the operator used for the Draw method.
//
// The zero value is draw.Over.
DrawOp draw.Op
// TODO: an exported field equivalent to the mask point in the
// draw.DrawMask function in the stdlib image/draw package?
}
// Reset resets a Rasterizer as if it was just returned by NewRasterizer.
//
// This includes setting z.DrawOp to draw.Over.
func (z *Rasterizer) Reset(w, h int) {
z.size = image.Point{w, h}
z.firstX = 0
z.firstY = 0
z.penX = 0
z.penY = 0
z.DrawOp = draw.Over
z.setUseFloatingPointMath(w > floatingPointMathThreshold || h > floatingPointMathThreshold)
}
func (z *Rasterizer) setUseFloatingPointMath(b bool) {
z.useFloatingPointMath = b
// Make z.bufF32 or z.bufU32 large enough to hold width * height samples.
if z.useFloatingPointMath {
if n := z.size.X * z.size.Y; n > cap(z.bufF32) {
z.bufF32 = make([]float32, n)
} else {
z.bufF32 = z.bufF32[:n]
for i := range z.bufF32 {
z.bufF32[i] = 0
}
}
} else {
if n := z.size.X * z.size.Y; n > cap(z.bufU32) {
z.bufU32 = make([]uint32, n)
} else {
z.bufU32 = z.bufU32[:n]
for i := range z.bufU32 {
z.bufU32[i] = 0
}
}
}
}
// Size returns the width and height passed to NewRasterizer or Reset.
func (z *Rasterizer) Size() image.Point {
return z.size
}
// Bounds returns the rectangle from (0, 0) to the width and height passed to
// NewRasterizer or Reset.
func (z *Rasterizer) Bounds() image.Rectangle {
return image.Rectangle{Max: z.size}
}
// Pen returns the location of the path-drawing pen: the last argument to the
// most recent XxxTo call.
func (z *Rasterizer) Pen() (x, y float32) {
return z.penX, z.penY
}
// ClosePath closes the current path.
func (z *Rasterizer) ClosePath() {
z.LineTo(z.firstX, z.firstY)
}
// MoveTo starts a new path and moves the pen to (ax, ay).
//
// The coordinates are allowed to be out of the Rasterizer's bounds.
func (z *Rasterizer) MoveTo(ax, ay float32) {
z.firstX = ax
z.firstY = ay
z.penX = ax
z.penY = ay
}
// LineTo adds a line segment, from the pen to (bx, by), and moves the pen to
// (bx, by).
//
// The coordinates are allowed to be out of the Rasterizer's bounds.
func (z *Rasterizer) LineTo(bx, by float32) {
if z.useFloatingPointMath {
z.floatingLineTo(bx, by)
} else {
z.fixedLineTo(bx, by)
}
}
// QuadTo adds a quadratic Bézier segment, from the pen via (bx, by) to (cx,
// cy), and moves the pen to (cx, cy).
//
// The coordinates are allowed to be out of the Rasterizer's bounds.
func (z *Rasterizer) QuadTo(bx, by, cx, cy float32) {
ax, ay := z.penX, z.penY
devsq := devSquared(ax, ay, bx, by, cx, cy)
if devsq >= 0.333 {
const tol = 3
n := 1 + int(math.Sqrt(math.Sqrt(tol*float64(devsq))))
t, nInv := float32(0), 1/float32(n)
for i := 0; i < n-1; i++ {
t += nInv
abx, aby := lerp(t, ax, ay, bx, by)
bcx, bcy := lerp(t, bx, by, cx, cy)
z.LineTo(lerp(t, abx, aby, bcx, bcy))
}
}
z.LineTo(cx, cy)
}
// CubeTo adds a cubic Bézier segment, from the pen via (bx, by) and (cx, cy)
// to (dx, dy), and moves the pen to (dx, dy).
//
// The coordinates are allowed to be out of the Rasterizer's bounds.
func (z *Rasterizer) CubeTo(bx, by, cx, cy, dx, dy float32) {
ax, ay := z.penX, z.penY
devsq := devSquared(ax, ay, bx, by, dx, dy)
if devsqAlt := devSquared(ax, ay, cx, cy, dx, dy); devsq < devsqAlt {
devsq = devsqAlt
}
if devsq >= 0.333 {
const tol = 3
n := 1 + int(math.Sqrt(math.Sqrt(tol*float64(devsq))))
t, nInv := float32(0), 1/float32(n)
for i := 0; i < n-1; i++ {
t += nInv
abx, aby := lerp(t, ax, ay, bx, by)
bcx, bcy := lerp(t, bx, by, cx, cy)
cdx, cdy := lerp(t, cx, cy, dx, dy)
abcx, abcy := lerp(t, abx, aby, bcx, bcy)
bcdx, bcdy := lerp(t, bcx, bcy, cdx, cdy)
z.LineTo(lerp(t, abcx, abcy, bcdx, bcdy))
}
}
z.LineTo(dx, dy)
}
// devSquared returns a measure of how curvy the sequence (ax, ay) to (bx, by)
// to (cx, cy) is. It determines how many line segments will approximate a
// Bézier curve segment.
//
// http://lists.nongnu.org/archive/html/freetype-devel/2016-08/msg00080.html
// gives the rationale for this evenly spaced heuristic instead of a recursive
// de Casteljau approach:
//
// The reason for the subdivision by n is that I expect the "flatness"
// computation to be semi-expensive (it's done once rather than on each
// potential subdivision) and also because you'll often get fewer subdivisions.
// Taking a circular arc as a simplifying assumption (i.e., a spherical cow),
// where I get n, a recursive approach would get 2^⌈lg n⌉, which, if I haven't
// made any horrible mistakes, is expected to be 33% more in the limit.
func devSquared(ax, ay, bx, by, cx, cy float32) float32 {
devx := ax - 2*bx + cx
devy := ay - 2*by + cy
return devx*devx + devy*devy
}
// Draw implements the Drawer interface from the standard library's image/draw
// package.
//
// The vector paths previously added via the XxxTo calls become the mask for
// drawing src onto dst.
func (z *Rasterizer) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
// TODO: adjust r and sp (and mp?) if src.Bounds() doesn't contain
// r.Add(sp.Sub(r.Min)).
if src, ok := src.(*image.Uniform); ok {
srcR, srcG, srcB, srcA := src.RGBA()
switch dst := dst.(type) {
case *image.Alpha:
// Fast path for glyph rendering.
if srcA == 0xffff {
if z.DrawOp == draw.Over {
z.rasterizeDstAlphaSrcOpaqueOpOver(dst, r)
} else {
z.rasterizeDstAlphaSrcOpaqueOpSrc(dst, r)
}
return
}
case *image.RGBA:
if z.DrawOp == draw.Over {
z.rasterizeDstRGBASrcUniformOpOver(dst, r, srcR, srcG, srcB, srcA)
} else {
z.rasterizeDstRGBASrcUniformOpSrc(dst, r, srcR, srcG, srcB, srcA)
}
return
}
}
if z.DrawOp == draw.Over {
z.rasterizeOpOver(dst, r, src, sp)
} else {
z.rasterizeOpSrc(dst, r, src, sp)
}
}
func (z *Rasterizer) accumulateMask() {
if z.useFloatingPointMath {
if n := z.size.X * z.size.Y; n > cap(z.bufU32) {
z.bufU32 = make([]uint32, n)
} else {
z.bufU32 = z.bufU32[:n]
}
if haveAccumulateSIMD {
floatingAccumulateMaskSIMD(z.bufU32, z.bufF32)
} else {
floatingAccumulateMask(z.bufU32, z.bufF32)
}
} else {
if haveAccumulateSIMD {
fixedAccumulateMaskSIMD(z.bufU32)
} else {
fixedAccumulateMask(z.bufU32)
}
}
}
func (z *Rasterizer) rasterizeDstAlphaSrcOpaqueOpOver(dst *image.Alpha, r image.Rectangle) {
// TODO: non-zero vs even-odd winding?
if r == dst.Bounds() && r == z.Bounds() {
// We bypass the z.accumulateMask step and convert straight from
// z.bufF32 or z.bufU32 to dst.Pix.
if z.useFloatingPointMath {
if haveAccumulateSIMD {
floatingAccumulateOpOverSIMD(dst.Pix, z.bufF32)
} else {
floatingAccumulateOpOver(dst.Pix, z.bufF32)
}
} else {
if haveAccumulateSIMD {
fixedAccumulateOpOverSIMD(dst.Pix, z.bufU32)
} else {
fixedAccumulateOpOver(dst.Pix, z.bufU32)
}
}
return
}
z.accumulateMask()
pix := dst.Pix[dst.PixOffset(r.Min.X, r.Min.Y):]
for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
ma := z.bufU32[y*z.size.X+x]
i := y*dst.Stride + x
// This formula is like rasterizeOpOver's, simplified for the
// concrete dst type and opaque src assumption.
a := 0xffff - ma
pix[i] = uint8((uint32(pix[i])*0x101*a/0xffff + ma) >> 8)
}
}
}
func (z *Rasterizer) rasterizeDstAlphaSrcOpaqueOpSrc(dst *image.Alpha, r image.Rectangle) {
// TODO: non-zero vs even-odd winding?
if r == dst.Bounds() && r == z.Bounds() {
// We bypass the z.accumulateMask step and convert straight from
// z.bufF32 or z.bufU32 to dst.Pix.
if z.useFloatingPointMath {
if haveAccumulateSIMD {
floatingAccumulateOpSrcSIMD(dst.Pix, z.bufF32)
} else {
floatingAccumulateOpSrc(dst.Pix, z.bufF32)
}
} else {
if haveAccumulateSIMD {
fixedAccumulateOpSrcSIMD(dst.Pix, z.bufU32)
} else {
fixedAccumulateOpSrc(dst.Pix, z.bufU32)
}
}
return
}
z.accumulateMask()
pix := dst.Pix[dst.PixOffset(r.Min.X, r.Min.Y):]
for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
ma := z.bufU32[y*z.size.X+x]
// This formula is like rasterizeOpSrc's, simplified for the
// concrete dst type and opaque src assumption.
pix[y*dst.Stride+x] = uint8(ma >> 8)
}
}
}
func (z *Rasterizer) rasterizeDstRGBASrcUniformOpOver(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) {
z.accumulateMask()
pix := dst.Pix[dst.PixOffset(r.Min.X, r.Min.Y):]
for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
ma := z.bufU32[y*z.size.X+x]
// This formula is like rasterizeOpOver's, simplified for the
// concrete dst type and uniform src assumption.
a := 0xffff - (sa * ma / 0xffff)
i := y*dst.Stride + 4*x
pix[i+0] = uint8(((uint32(pix[i+0])*0x101*a + sr*ma) / 0xffff) >> 8)
pix[i+1] = uint8(((uint32(pix[i+1])*0x101*a + sg*ma) / 0xffff) >> 8)
pix[i+2] = uint8(((uint32(pix[i+2])*0x101*a + sb*ma) / 0xffff) >> 8)
pix[i+3] = uint8(((uint32(pix[i+3])*0x101*a + sa*ma) / 0xffff) >> 8)
}
}
}
func (z *Rasterizer) rasterizeDstRGBASrcUniformOpSrc(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) {
z.accumulateMask()
pix := dst.Pix[dst.PixOffset(r.Min.X, r.Min.Y):]
for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
ma := z.bufU32[y*z.size.X+x]
// This formula is like rasterizeOpSrc's, simplified for the
// concrete dst type and uniform src assumption.
i := y*dst.Stride + 4*x
pix[i+0] = uint8((sr * ma / 0xffff) >> 8)
pix[i+1] = uint8((sg * ma / 0xffff) >> 8)
pix[i+2] = uint8((sb * ma / 0xffff) >> 8)
pix[i+3] = uint8((sa * ma / 0xffff) >> 8)
}
}
}
func (z *Rasterizer) rasterizeOpOver(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
z.accumulateMask()
out := color.RGBA64{}
outc := color.Color(&out)
for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
sr, sg, sb, sa := src.At(sp.X+x, sp.Y+y).RGBA()
ma := z.bufU32[y*z.size.X+x]
// This algorithm comes from the standard library's image/draw
// package.
dr, dg, db, da := dst.At(r.Min.X+x, r.Min.Y+y).RGBA()
a := 0xffff - (sa * ma / 0xffff)
out.R = uint16((dr*a + sr*ma) / 0xffff)
out.G = uint16((dg*a + sg*ma) / 0xffff)
out.B = uint16((db*a + sb*ma) / 0xffff)
out.A = uint16((da*a + sa*ma) / 0xffff)
dst.Set(r.Min.X+x, r.Min.Y+y, outc)
}
}
}
func (z *Rasterizer) rasterizeOpSrc(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
z.accumulateMask()
out := color.RGBA64{}
outc := color.Color(&out)
for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
sr, sg, sb, sa := src.At(sp.X+x, sp.Y+y).RGBA()
ma := z.bufU32[y*z.size.X+x]
// This algorithm comes from the standard library's image/draw
// package.
out.R = uint16(sr * ma / 0xffff)
out.G = uint16(sg * ma / 0xffff)
out.B = uint16(sb * ma / 0xffff)
out.A = uint16(sa * ma / 0xffff)
dst.Set(r.Min.X+x, r.Min.Y+y, outc)
}
}
}
// Copyright 2011 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 vp8 implements a decoder for the VP8 lossy image format.
//
// The VP8 specification is RFC 6386.
package vp8 // import "golang.org/x/image/vp8"
// This file implements the top-level decoding algorithm.
import (
"errors"
"image"
"io"
)
// limitReader wraps an io.Reader to read at most n bytes from it.
type limitReader struct {
r io.Reader
n int
}
// ReadFull reads exactly len(p) bytes into p.
func (r *limitReader) ReadFull(p []byte) error {
if len(p) > r.n {
return io.ErrUnexpectedEOF
}
n, err := io.ReadFull(r.r, p)
r.n -= n
return err
}
// FrameHeader is a frame header, as specified in section 9.1.
type FrameHeader struct {
KeyFrame bool
VersionNumber uint8
ShowFrame bool
FirstPartitionLen uint32
Width int
Height int
XScale uint8
YScale uint8
}
const (
nSegment = 4
nSegmentProb = 3
)
// segmentHeader holds segment-related header information.
type segmentHeader struct {
useSegment bool
updateMap bool
relativeDelta bool
quantizer [nSegment]int8
filterStrength [nSegment]int8
prob [nSegmentProb]uint8
}
const (
nRefLFDelta = 4
nModeLFDelta = 4
)
// filterHeader holds filter-related header information.
type filterHeader struct {
simple bool
level int8
sharpness uint8
useLFDelta bool
refLFDelta [nRefLFDelta]int8
modeLFDelta [nModeLFDelta]int8
perSegmentLevel [nSegment]int8
}
// mb is the per-macroblock decode state. A decoder maintains mbw+1 of these
// as it is decoding macroblocks left-to-right and top-to-bottom: mbw for the
// macroblocks in the row above, and one for the macroblock to the left.
type mb struct {
// pred is the predictor mode for the 4 bottom or right 4x4 luma regions.
pred [4]uint8
// nzMask is a mask of 8 bits: 4 for the bottom or right 4x4 luma regions,
// and 2 + 2 for the bottom or right 4x4 chroma regions. A 1 bit indicates
// that region has non-zero coefficients.
nzMask uint8
// nzY16 is a 0/1 value that is 1 if the macroblock used Y16 prediction and
// had non-zero coefficients.
nzY16 uint8
}
// Decoder decodes VP8 bitstreams into frames. Decoding one frame consists of
// calling Init, DecodeFrameHeader and then DecodeFrame in that order.
// A Decoder can be re-used to decode multiple frames.
type Decoder struct {
// r is the input bitsream.
r limitReader
// scratch is a scratch buffer.
scratch [8]byte
// img is the YCbCr image to decode into.
img *image.YCbCr
// mbw and mbh are the number of 16x16 macroblocks wide and high the image is.
mbw, mbh int
// frameHeader is the frame header. When decoding multiple frames,
// frames that aren't key frames will inherit the Width, Height,
// XScale and YScale of the most recent key frame.
frameHeader FrameHeader
// Other headers.
segmentHeader segmentHeader
filterHeader filterHeader
// The image data is divided into a number of independent partitions.
// There is 1 "first partition" and between 1 and 8 "other partitions"
// for coefficient data.
fp partition
op [8]partition
nOP int
// Quantization factors.
quant [nSegment]quant
// DCT/WHT coefficient decoding probabilities.
tokenProb [nPlane][nBand][nContext][nProb]uint8
useSkipProb bool
skipProb uint8
// Loop filter parameters.
filterParams [nSegment][2]filterParam
perMBFilterParams []filterParam
// The eight fields below relate to the current macroblock being decoded.
//
// Segment-based adjustments.
segment int
// Per-macroblock state for the macroblock immediately left of and those
// macroblocks immediately above the current macroblock.
leftMB mb
upMB []mb
// Bitmasks for which 4x4 regions of coeff contain non-zero coefficients.
nzDCMask, nzACMask uint32
// Predictor modes.
usePredY16 bool // The libwebp C code calls this !is_i4x4_.
predY16 uint8
predC8 uint8
predY4 [4][4]uint8
// The two fields below form a workspace for reconstructing a macroblock.
// Their specific sizes are documented in reconstruct.go.
coeff [1*16*16 + 2*8*8 + 1*4*4]int16
ybr [1 + 16 + 1 + 8][32]uint8
}
// NewDecoder returns a new Decoder.
func NewDecoder() *Decoder {
return &Decoder{}
}
// Init initializes the decoder to read at most n bytes from r.
func (d *Decoder) Init(r io.Reader, n int) {
d.r = limitReader{r, n}
}
// DecodeFrameHeader decodes the frame header.
func (d *Decoder) DecodeFrameHeader() (fh FrameHeader, err error) {
// All frame headers are at least 3 bytes long.
b := d.scratch[:3]
if err = d.r.ReadFull(b); err != nil {
return
}
d.frameHeader.KeyFrame = (b[0] & 1) == 0
d.frameHeader.VersionNumber = (b[0] >> 1) & 7
d.frameHeader.ShowFrame = (b[0]>>4)&1 == 1
d.frameHeader.FirstPartitionLen = uint32(b[0])>>5 | uint32(b[1])<<3 | uint32(b[2])<<11
if !d.frameHeader.KeyFrame {
return d.frameHeader, nil
}
// Frame headers for key frames are an additional 7 bytes long.
b = d.scratch[:7]
if err = d.r.ReadFull(b); err != nil {
return
}
// Check the magic sync code.
if b[0] != 0x9d || b[1] != 0x01 || b[2] != 0x2a {
err = errors.New("vp8: invalid format")
return
}
d.frameHeader.Width = int(b[4]&0x3f)<<8 | int(b[3])
d.frameHeader.Height = int(b[6]&0x3f)<<8 | int(b[5])
d.frameHeader.XScale = b[4] >> 6
d.frameHeader.YScale = b[6] >> 6
d.mbw = (d.frameHeader.Width + 0x0f) >> 4
d.mbh = (d.frameHeader.Height + 0x0f) >> 4
d.segmentHeader = segmentHeader{
prob: [3]uint8{0xff, 0xff, 0xff},
}
d.tokenProb = defaultTokenProb
d.segment = 0
return d.frameHeader, nil
}
// ensureImg ensures that d.img is large enough to hold the decoded frame.
func (d *Decoder) ensureImg() {
if d.img != nil {
p0, p1 := d.img.Rect.Min, d.img.Rect.Max
if p0.X == 0 && p0.Y == 0 && p1.X >= 16*d.mbw && p1.Y >= 16*d.mbh {
return
}
}
m := image.NewYCbCr(image.Rect(0, 0, 16*d.mbw, 16*d.mbh), image.YCbCrSubsampleRatio420)
d.img = m.SubImage(image.Rect(0, 0, d.frameHeader.Width, d.frameHeader.Height)).(*image.YCbCr)
d.perMBFilterParams = make([]filterParam, d.mbw*d.mbh)
d.upMB = make([]mb, d.mbw)
}
// parseSegmentHeader parses the segment header, as specified in section 9.3.
func (d *Decoder) parseSegmentHeader() {
d.segmentHeader.useSegment = d.fp.readBit(uniformProb)
if !d.segmentHeader.useSegment {
d.segmentHeader.updateMap = false
return
}
d.segmentHeader.updateMap = d.fp.readBit(uniformProb)
if d.fp.readBit(uniformProb) {
d.segmentHeader.relativeDelta = !d.fp.readBit(uniformProb)
for i := range d.segmentHeader.quantizer {
d.segmentHeader.quantizer[i] = int8(d.fp.readOptionalInt(uniformProb, 7))
}
for i := range d.segmentHeader.filterStrength {
d.segmentHeader.filterStrength[i] = int8(d.fp.readOptionalInt(uniformProb, 6))
}
}
if !d.segmentHeader.updateMap {
return
}
for i := range d.segmentHeader.prob {
if d.fp.readBit(uniformProb) {
d.segmentHeader.prob[i] = uint8(d.fp.readUint(uniformProb, 8))
} else {
d.segmentHeader.prob[i] = 0xff
}
}
}
// parseFilterHeader parses the filter header, as specified in section 9.4.
func (d *Decoder) parseFilterHeader() {
d.filterHeader.simple = d.fp.readBit(uniformProb)
d.filterHeader.level = int8(d.fp.readUint(uniformProb, 6))
d.filterHeader.sharpness = uint8(d.fp.readUint(uniformProb, 3))
d.filterHeader.useLFDelta = d.fp.readBit(uniformProb)
if d.filterHeader.useLFDelta && d.fp.readBit(uniformProb) {
for i := range d.filterHeader.refLFDelta {
d.filterHeader.refLFDelta[i] = int8(d.fp.readOptionalInt(uniformProb, 6))
}
for i := range d.filterHeader.modeLFDelta {
d.filterHeader.modeLFDelta[i] = int8(d.fp.readOptionalInt(uniformProb, 6))
}
}
if d.filterHeader.level == 0 {
return
}
if d.segmentHeader.useSegment {
for i := range d.filterHeader.perSegmentLevel {
strength := d.segmentHeader.filterStrength[i]
if d.segmentHeader.relativeDelta {
strength += d.filterHeader.level
}
d.filterHeader.perSegmentLevel[i] = strength
}
} else {
d.filterHeader.perSegmentLevel[0] = d.filterHeader.level
}
d.computeFilterParams()
}
// parseOtherPartitions parses the other partitions, as specified in section 9.5.
func (d *Decoder) parseOtherPartitions() error {
const maxNOP = 1 << 3
var partLens [maxNOP]int
d.nOP = 1 << d.fp.readUint(uniformProb, 2)
// The final partition length is implied by the remaining chunk data
// (d.r.n) and the other d.nOP-1 partition lengths. Those d.nOP-1 partition
// lengths are stored as 24-bit uints, i.e. up to 16 MiB per partition.
n := 3 * (d.nOP - 1)
partLens[d.nOP-1] = d.r.n - n
if partLens[d.nOP-1] < 0 {
return io.ErrUnexpectedEOF
}
if n > 0 {
buf := make([]byte, n)
if err := d.r.ReadFull(buf); err != nil {
return err
}
for i := 0; i < d.nOP-1; i++ {
pl := int(buf[3*i+0]) | int(buf[3*i+1])<<8 | int(buf[3*i+2])<<16
if pl > partLens[d.nOP-1] {
return io.ErrUnexpectedEOF
}
partLens[i] = pl
partLens[d.nOP-1] -= pl
}
}
// We check if the final partition length can also fit into a 24-bit uint.
// Strictly speaking, this isn't part of the spec, but it guards against a
// malicious WEBP image that is too large to ReadFull the encoded DCT
// coefficients into memory, whether that's because the actual WEBP file is
// too large, or whether its RIFF metadata lists too large a chunk.
if 1<<24 <= partLens[d.nOP-1] {
return errors.New("vp8: too much data to decode")
}
buf := make([]byte, d.r.n)
if err := d.r.ReadFull(buf); err != nil {
return err
}
for i, pl := range partLens {
if i == d.nOP {
break
}
d.op[i].init(buf[:pl])
buf = buf[pl:]
}
return nil
}
// parseOtherHeaders parses header information other than the frame header.
func (d *Decoder) parseOtherHeaders() error {
// Initialize and parse the first partition.
firstPartition := make([]byte, d.frameHeader.FirstPartitionLen)
if err := d.r.ReadFull(firstPartition); err != nil {
return err
}
d.fp.init(firstPartition)
if d.frameHeader.KeyFrame {
// Read and ignore the color space and pixel clamp values. They are
// specified in section 9.2, but are unimplemented.
d.fp.readBit(uniformProb)
d.fp.readBit(uniformProb)
}
d.parseSegmentHeader()
d.parseFilterHeader()
if err := d.parseOtherPartitions(); err != nil {
return err
}
d.parseQuant()
if !d.frameHeader.KeyFrame {
// Golden and AltRef frames are specified in section 9.7.
// TODO(nigeltao): implement. Note that they are only used for video, not still images.
return errors.New("vp8: Golden / AltRef frames are not implemented")
}
// Read and ignore the refreshLastFrameBuffer bit, specified in section 9.8.
// It applies only to video, and not still images.
d.fp.readBit(uniformProb)
d.parseTokenProb()
d.useSkipProb = d.fp.readBit(uniformProb)
if d.useSkipProb {
d.skipProb = uint8(d.fp.readUint(uniformProb, 8))
}
if d.fp.unexpectedEOF {
return io.ErrUnexpectedEOF
}
return nil
}
// DecodeFrame decodes the frame and returns it as an YCbCr image.
// The image's contents are valid up until the next call to Decoder.Init.
func (d *Decoder) DecodeFrame() (*image.YCbCr, error) {
d.ensureImg()
if err := d.parseOtherHeaders(); err != nil {
return nil, err
}
// Reconstruct the rows.
for mbx := 0; mbx < d.mbw; mbx++ {
d.upMB[mbx] = mb{}
}
for mby := 0; mby < d.mbh; mby++ {
d.leftMB = mb{}
for mbx := 0; mbx < d.mbw; mbx++ {
skip := d.reconstruct(mbx, mby)
fs := d.filterParams[d.segment][btou(!d.usePredY16)]
fs.inner = fs.inner || !skip
d.perMBFilterParams[d.mbw*mby+mbx] = fs
}
}
if d.fp.unexpectedEOF {
return nil, io.ErrUnexpectedEOF
}
for i := 0; i < d.nOP; i++ {
if d.op[i].unexpectedEOF {
return nil, io.ErrUnexpectedEOF
}
}
// Apply the loop filter.
//
// Even if we are using per-segment levels, section 15 says that "loop
// filtering must be skipped entirely if loop_filter_level at either the
// frame header level or macroblock override level is 0".
if d.filterHeader.level != 0 {
if d.filterHeader.simple {
d.simpleFilter()
} else {
d.normalFilter()
}
}
return d.img, nil
}
// 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 vp8
// filter2 modifies a 2-pixel wide or 2-pixel high band along an edge.
func filter2(pix []byte, level, index, iStep, jStep int) {
for n := 16; n > 0; n, index = n-1, index+iStep {
p1 := int(pix[index-2*jStep])
p0 := int(pix[index-1*jStep])
q0 := int(pix[index+0*jStep])
q1 := int(pix[index+1*jStep])
if abs(p0-q0)<<1+abs(p1-q1)>>1 > level {
continue
}
a := 3*(q0-p0) + clamp127(p1-q1)
a1 := clamp15((a + 4) >> 3)
a2 := clamp15((a + 3) >> 3)
pix[index-1*jStep] = clamp255(p0 + a2)
pix[index+0*jStep] = clamp255(q0 - a1)
}
}
// filter246 modifies a 2-, 4- or 6-pixel wide or high band along an edge.
func filter246(pix []byte, n, level, ilevel, hlevel, index, iStep, jStep int, fourNotSix bool) {
for ; n > 0; n, index = n-1, index+iStep {
p3 := int(pix[index-4*jStep])
p2 := int(pix[index-3*jStep])
p1 := int(pix[index-2*jStep])
p0 := int(pix[index-1*jStep])
q0 := int(pix[index+0*jStep])
q1 := int(pix[index+1*jStep])
q2 := int(pix[index+2*jStep])
q3 := int(pix[index+3*jStep])
if abs(p0-q0)<<1+abs(p1-q1)>>1 > level {
continue
}
if abs(p3-p2) > ilevel ||
abs(p2-p1) > ilevel ||
abs(p1-p0) > ilevel ||
abs(q1-q0) > ilevel ||
abs(q2-q1) > ilevel ||
abs(q3-q2) > ilevel {
continue
}
if abs(p1-p0) > hlevel || abs(q1-q0) > hlevel {
// Filter 2 pixels.
a := 3*(q0-p0) + clamp127(p1-q1)
a1 := clamp15((a + 4) >> 3)
a2 := clamp15((a + 3) >> 3)
pix[index-1*jStep] = clamp255(p0 + a2)
pix[index+0*jStep] = clamp255(q0 - a1)
} else if fourNotSix {
// Filter 4 pixels.
a := 3 * (q0 - p0)
a1 := clamp15((a + 4) >> 3)
a2 := clamp15((a + 3) >> 3)
a3 := (a1 + 1) >> 1
pix[index-2*jStep] = clamp255(p1 + a3)
pix[index-1*jStep] = clamp255(p0 + a2)
pix[index+0*jStep] = clamp255(q0 - a1)
pix[index+1*jStep] = clamp255(q1 - a3)
} else {
// Filter 6 pixels.
a := clamp127(3*(q0-p0) + clamp127(p1-q1))
a1 := (27*a + 63) >> 7
a2 := (18*a + 63) >> 7
a3 := (9*a + 63) >> 7
pix[index-3*jStep] = clamp255(p2 + a3)
pix[index-2*jStep] = clamp255(p1 + a2)
pix[index-1*jStep] = clamp255(p0 + a1)
pix[index+0*jStep] = clamp255(q0 - a1)
pix[index+1*jStep] = clamp255(q1 - a2)
pix[index+2*jStep] = clamp255(q2 - a3)
}
}
}
// simpleFilter implements the simple filter, as specified in section 15.2.
func (d *Decoder) simpleFilter() {
for mby := 0; mby < d.mbh; mby++ {
for mbx := 0; mbx < d.mbw; mbx++ {
f := d.perMBFilterParams[d.mbw*mby+mbx]
if f.level == 0 {
continue
}
l := int(f.level)
yIndex := (mby*d.img.YStride + mbx) * 16
if mbx > 0 {
filter2(d.img.Y, l+4, yIndex, d.img.YStride, 1)
}
if f.inner {
filter2(d.img.Y, l, yIndex+0x4, d.img.YStride, 1)
filter2(d.img.Y, l, yIndex+0x8, d.img.YStride, 1)
filter2(d.img.Y, l, yIndex+0xc, d.img.YStride, 1)
}
if mby > 0 {
filter2(d.img.Y, l+4, yIndex, 1, d.img.YStride)
}
if f.inner {
filter2(d.img.Y, l, yIndex+d.img.YStride*0x4, 1, d.img.YStride)
filter2(d.img.Y, l, yIndex+d.img.YStride*0x8, 1, d.img.YStride)
filter2(d.img.Y, l, yIndex+d.img.YStride*0xc, 1, d.img.YStride)
}
}
}
}
// normalFilter implements the normal filter, as specified in section 15.3.
func (d *Decoder) normalFilter() {
for mby := 0; mby < d.mbh; mby++ {
for mbx := 0; mbx < d.mbw; mbx++ {
f := d.perMBFilterParams[d.mbw*mby+mbx]
if f.level == 0 {
continue
}
l, il, hl := int(f.level), int(f.ilevel), int(f.hlevel)
yIndex := (mby*d.img.YStride + mbx) * 16
cIndex := (mby*d.img.CStride + mbx) * 8
if mbx > 0 {
filter246(d.img.Y, 16, l+4, il, hl, yIndex, d.img.YStride, 1, false)
filter246(d.img.Cb, 8, l+4, il, hl, cIndex, d.img.CStride, 1, false)
filter246(d.img.Cr, 8, l+4, il, hl, cIndex, d.img.CStride, 1, false)
}
if f.inner {
filter246(d.img.Y, 16, l, il, hl, yIndex+0x4, d.img.YStride, 1, true)
filter246(d.img.Y, 16, l, il, hl, yIndex+0x8, d.img.YStride, 1, true)
filter246(d.img.Y, 16, l, il, hl, yIndex+0xc, d.img.YStride, 1, true)
filter246(d.img.Cb, 8, l, il, hl, cIndex+0x4, d.img.CStride, 1, true)
filter246(d.img.Cr, 8, l, il, hl, cIndex+0x4, d.img.CStride, 1, true)
}
if mby > 0 {
filter246(d.img.Y, 16, l+4, il, hl, yIndex, 1, d.img.YStride, false)
filter246(d.img.Cb, 8, l+4, il, hl, cIndex, 1, d.img.CStride, false)
filter246(d.img.Cr, 8, l+4, il, hl, cIndex, 1, d.img.CStride, false)
}
if f.inner {
filter246(d.img.Y, 16, l, il, hl, yIndex+d.img.YStride*0x4, 1, d.img.YStride, true)
filter246(d.img.Y, 16, l, il, hl, yIndex+d.img.YStride*0x8, 1, d.img.YStride, true)
filter246(d.img.Y, 16, l, il, hl, yIndex+d.img.YStride*0xc, 1, d.img.YStride, true)
filter246(d.img.Cb, 8, l, il, hl, cIndex+d.img.CStride*0x4, 1, d.img.CStride, true)
filter246(d.img.Cr, 8, l, il, hl, cIndex+d.img.CStride*0x4, 1, d.img.CStride, true)
}
}
}
}
// filterParam holds the loop filter parameters for a macroblock.
type filterParam struct {
// The first three fields are thresholds used by the loop filter to smooth
// over the edges and interior of a macroblock. level is used by both the
// simple and normal filters. The inner level and high edge variance level
// are only used by the normal filter.
level, ilevel, hlevel uint8
// inner is whether the inner loop filter cannot be optimized out as a
// no-op for this particular macroblock.
inner bool
}
// computeFilterParams computes the loop filter parameters, as specified in
// section 15.4.
func (d *Decoder) computeFilterParams() {
for i := range d.filterParams {
baseLevel := d.filterHeader.level
if d.segmentHeader.useSegment {
baseLevel = d.segmentHeader.filterStrength[i]
if d.segmentHeader.relativeDelta {
baseLevel += d.filterHeader.level
}
}
for j := range d.filterParams[i] {
p := &d.filterParams[i][j]
p.inner = j != 0
level := baseLevel
if d.filterHeader.useLFDelta {
// The libwebp C code has a "TODO: only CURRENT is handled for now."
level += d.filterHeader.refLFDelta[0]
if j != 0 {
level += d.filterHeader.modeLFDelta[0]
}
}
if level <= 0 {
p.level = 0
continue
}
if level > 63 {
level = 63
}
ilevel := level
if d.filterHeader.sharpness > 0 {
if d.filterHeader.sharpness > 4 {
ilevel >>= 2
} else {
ilevel >>= 1
}
if x := int8(9 - d.filterHeader.sharpness); ilevel > x {
ilevel = x
}
}
if ilevel < 1 {
ilevel = 1
}
p.ilevel = uint8(ilevel)
p.level = uint8(2*level + ilevel)
if d.frameHeader.KeyFrame {
if level < 15 {
p.hlevel = 0
} else if level < 40 {
p.hlevel = 1
} else {
p.hlevel = 2
}
} else {
if level < 15 {
p.hlevel = 0
} else if level < 20 {
p.hlevel = 1
} else if level < 40 {
p.hlevel = 2
} else {
p.hlevel = 3
}
}
}
}
}
// intSize is either 32 or 64.
const intSize = 32 << (^uint(0) >> 63)
func abs(x int) int {
// m := -1 if x < 0. m := 0 otherwise.
m := x >> (intSize - 1)
// In two's complement representation, the negative number
// of any number (except the smallest one) can be computed
// by flipping all the bits and add 1. This is faster than
// code with a branch.
// See Hacker's Delight, section 2-4.
return (x ^ m) - m
}
func clamp15(x int) int {
if x < -16 {
return -16
}
if x > 15 {
return 15
}
return x
}
func clamp127(x int) int {
if x < -128 {
return -128
}
if x > 127 {
return 127
}
return x
}
func clamp255(x int) uint8 {
if x < 0 {
return 0
}
if x > 255 {
return 255
}
return uint8(x)
}
// Copyright 2011 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 vp8
// This file implements the inverse Discrete Cosine Transform and the inverse
// Walsh Hadamard Transform (WHT), as specified in sections 14.3 and 14.4.
func clip8(i int32) uint8 {
if i < 0 {
return 0
}
if i > 255 {
return 255
}
return uint8(i)
}
func (z *Decoder) inverseDCT4(y, x, coeffBase int) {
const (
c1 = 85627 // 65536 * cos(pi/8) * sqrt(2).
c2 = 35468 // 65536 * sin(pi/8) * sqrt(2).
)
var m [4][4]int32
for i := 0; i < 4; i++ {
a := int32(z.coeff[coeffBase+0]) + int32(z.coeff[coeffBase+8])
b := int32(z.coeff[coeffBase+0]) - int32(z.coeff[coeffBase+8])
c := (int32(z.coeff[coeffBase+4])*c2)>>16 - (int32(z.coeff[coeffBase+12])*c1)>>16
d := (int32(z.coeff[coeffBase+4])*c1)>>16 + (int32(z.coeff[coeffBase+12])*c2)>>16
m[i][0] = a + d
m[i][1] = b + c
m[i][2] = b - c
m[i][3] = a - d
coeffBase++
}
for j := 0; j < 4; j++ {
dc := m[0][j] + 4
a := dc + m[2][j]
b := dc - m[2][j]
c := (m[1][j]*c2)>>16 - (m[3][j]*c1)>>16
d := (m[1][j]*c1)>>16 + (m[3][j]*c2)>>16
z.ybr[y+j][x+0] = clip8(int32(z.ybr[y+j][x+0]) + (a+d)>>3)
z.ybr[y+j][x+1] = clip8(int32(z.ybr[y+j][x+1]) + (b+c)>>3)
z.ybr[y+j][x+2] = clip8(int32(z.ybr[y+j][x+2]) + (b-c)>>3)
z.ybr[y+j][x+3] = clip8(int32(z.ybr[y+j][x+3]) + (a-d)>>3)
}
}
func (z *Decoder) inverseDCT4DCOnly(y, x, coeffBase int) {
dc := (int32(z.coeff[coeffBase+0]) + 4) >> 3
for j := 0; j < 4; j++ {
for i := 0; i < 4; i++ {
z.ybr[y+j][x+i] = clip8(int32(z.ybr[y+j][x+i]) + dc)
}
}
}
func (z *Decoder) inverseDCT8(y, x, coeffBase int) {
z.inverseDCT4(y+0, x+0, coeffBase+0*16)
z.inverseDCT4(y+0, x+4, coeffBase+1*16)
z.inverseDCT4(y+4, x+0, coeffBase+2*16)
z.inverseDCT4(y+4, x+4, coeffBase+3*16)
}
func (z *Decoder) inverseDCT8DCOnly(y, x, coeffBase int) {
z.inverseDCT4DCOnly(y+0, x+0, coeffBase+0*16)
z.inverseDCT4DCOnly(y+0, x+4, coeffBase+1*16)
z.inverseDCT4DCOnly(y+4, x+0, coeffBase+2*16)
z.inverseDCT4DCOnly(y+4, x+4, coeffBase+3*16)
}
func (d *Decoder) inverseWHT16() {
var m [16]int32
for i := 0; i < 4; i++ {
a0 := int32(d.coeff[384+0+i]) + int32(d.coeff[384+12+i])
a1 := int32(d.coeff[384+4+i]) + int32(d.coeff[384+8+i])
a2 := int32(d.coeff[384+4+i]) - int32(d.coeff[384+8+i])
a3 := int32(d.coeff[384+0+i]) - int32(d.coeff[384+12+i])
m[0+i] = a0 + a1
m[8+i] = a0 - a1
m[4+i] = a3 + a2
m[12+i] = a3 - a2
}
out := 0
for i := 0; i < 4; i++ {
dc := m[0+i*4] + 3
a0 := dc + m[3+i*4]
a1 := m[1+i*4] + m[2+i*4]
a2 := m[1+i*4] - m[2+i*4]
a3 := dc - m[3+i*4]
d.coeff[out+0] = int16((a0 + a1) >> 3)
d.coeff[out+16] = int16((a3 + a2) >> 3)
d.coeff[out+32] = int16((a0 - a1) >> 3)
d.coeff[out+48] = int16((a3 - a2) >> 3)
out += 64
}
}
// Copyright 2011 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 vp8
// Each VP8 frame consists of between 2 and 9 bitstream partitions.
// Each partition is byte-aligned and is independently arithmetic-encoded.
//
// This file implements decoding a partition's bitstream, as specified in
// chapter 7. The implementation follows libwebp's approach instead of the
// specification's reference C implementation. For example, we use a look-up
// table instead of a for loop to recalibrate the encoded range.
var (
lutShift = [127]uint8{
7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
}
lutRangeM1 = [127]uint8{
127,
127, 191,
127, 159, 191, 223,
127, 143, 159, 175, 191, 207, 223, 239,
127, 135, 143, 151, 159, 167, 175, 183, 191, 199, 207, 215, 223, 231, 239, 247,
127, 131, 135, 139, 143, 147, 151, 155, 159, 163, 167, 171, 175, 179, 183, 187,
191, 195, 199, 203, 207, 211, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251,
127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157,
159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189,
191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221,
223, 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253,
}
)
// uniformProb represents a 50% probability that the next bit is 0.
const uniformProb = 128
// partition holds arithmetic-coded bits.
type partition struct {
// buf is the input bytes.
buf []byte
// r is how many of buf's bytes have been consumed.
r int
// rangeM1 is range minus 1, where range is in the arithmetic coding sense,
// not the Go language sense.
rangeM1 uint32
// bits and nBits hold those bits shifted out of buf but not yet consumed.
bits uint32
nBits uint8
// unexpectedEOF tells whether we tried to read past buf.
unexpectedEOF bool
}
// init initializes the partition.
func (p *partition) init(buf []byte) {
p.buf = buf
p.r = 0
p.rangeM1 = 254
p.bits = 0
p.nBits = 0
p.unexpectedEOF = false
}
// readBit returns the next bit.
func (p *partition) readBit(prob uint8) bool {
if p.nBits < 8 {
if p.r >= len(p.buf) {
p.unexpectedEOF = true
return false
}
// Expression split for 386 compiler.
x := uint32(p.buf[p.r])
p.bits |= x << (8 - p.nBits)
p.r++
p.nBits += 8
}
split := (p.rangeM1*uint32(prob))>>8 + 1
bit := p.bits >= split<<8
if bit {
p.rangeM1 -= split
p.bits -= split << 8
} else {
p.rangeM1 = split - 1
}
if p.rangeM1 < 127 {
shift := lutShift[p.rangeM1]
p.rangeM1 = uint32(lutRangeM1[p.rangeM1])
p.bits <<= shift
p.nBits -= shift
}
return bit
}
// readUint returns the next n-bit unsigned integer.
func (p *partition) readUint(prob, n uint8) uint32 {
var u uint32
for n > 0 {
n--
if p.readBit(prob) {
u |= 1 << n
}
}
return u
}
// readInt returns the next n-bit signed integer.
func (p *partition) readInt(prob, n uint8) int32 {
u := p.readUint(prob, n)
b := p.readBit(prob)
if b {
return -int32(u)
}
return int32(u)
}
// readOptionalInt returns the next n-bit signed integer in an encoding
// where the likely result is zero.
func (p *partition) readOptionalInt(prob, n uint8) int32 {
if !p.readBit(prob) {
return 0
}
return p.readInt(prob, n)
}
// Copyright 2011 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 vp8
// This file implements parsing the predictor modes, as specified in chapter
// 11.
func (d *Decoder) parsePredModeY16(mbx int) {
var p uint8
if !d.fp.readBit(156) {
if !d.fp.readBit(163) {
p = predDC
} else {
p = predVE
}
} else if !d.fp.readBit(128) {
p = predHE
} else {
p = predTM
}
for i := 0; i < 4; i++ {
d.upMB[mbx].pred[i] = p
d.leftMB.pred[i] = p
}
d.predY16 = p
}
func (d *Decoder) parsePredModeC8() {
if !d.fp.readBit(142) {
d.predC8 = predDC
} else if !d.fp.readBit(114) {
d.predC8 = predVE
} else if !d.fp.readBit(183) {
d.predC8 = predHE
} else {
d.predC8 = predTM
}
}
func (d *Decoder) parsePredModeY4(mbx int) {
for j := 0; j < 4; j++ {
p := d.leftMB.pred[j]
for i := 0; i < 4; i++ {
prob := &predProb[d.upMB[mbx].pred[i]][p]
if !d.fp.readBit(prob[0]) {
p = predDC
} else if !d.fp.readBit(prob[1]) {
p = predTM
} else if !d.fp.readBit(prob[2]) {
p = predVE
} else if !d.fp.readBit(prob[3]) {
if !d.fp.readBit(prob[4]) {
p = predHE
} else if !d.fp.readBit(prob[5]) {
p = predRD
} else {
p = predVR
}
} else if !d.fp.readBit(prob[6]) {
p = predLD
} else if !d.fp.readBit(prob[7]) {
p = predVL
} else if !d.fp.readBit(prob[8]) {
p = predHD
} else {
p = predHU
}
d.predY4[j][i] = p
d.upMB[mbx].pred[i] = p
}
d.leftMB.pred[j] = p
}
}
// predProb are the probabilities to decode a 4x4 region's predictor mode given
// the predictor modes of the regions above and left of it.
// These values are specified in section 11.5.
var predProb = [nPred][nPred][9]uint8{
{
{231, 120, 48, 89, 115, 113, 120, 152, 112},
{152, 179, 64, 126, 170, 118, 46, 70, 95},
{175, 69, 143, 80, 85, 82, 72, 155, 103},
{56, 58, 10, 171, 218, 189, 17, 13, 152},
{114, 26, 17, 163, 44, 195, 21, 10, 173},
{121, 24, 80, 195, 26, 62, 44, 64, 85},
{144, 71, 10, 38, 171, 213, 144, 34, 26},
{170, 46, 55, 19, 136, 160, 33, 206, 71},
{63, 20, 8, 114, 114, 208, 12, 9, 226},
{81, 40, 11, 96, 182, 84, 29, 16, 36},
},
{
{134, 183, 89, 137, 98, 101, 106, 165, 148},
{72, 187, 100, 130, 157, 111, 32, 75, 80},
{66, 102, 167, 99, 74, 62, 40, 234, 128},
{41, 53, 9, 178, 241, 141, 26, 8, 107},
{74, 43, 26, 146, 73, 166, 49, 23, 157},
{65, 38, 105, 160, 51, 52, 31, 115, 128},
{104, 79, 12, 27, 217, 255, 87, 17, 7},
{87, 68, 71, 44, 114, 51, 15, 186, 23},
{47, 41, 14, 110, 182, 183, 21, 17, 194},
{66, 45, 25, 102, 197, 189, 23, 18, 22},
},
{
{88, 88, 147, 150, 42, 46, 45, 196, 205},
{43, 97, 183, 117, 85, 38, 35, 179, 61},
{39, 53, 200, 87, 26, 21, 43, 232, 171},
{56, 34, 51, 104, 114, 102, 29, 93, 77},
{39, 28, 85, 171, 58, 165, 90, 98, 64},
{34, 22, 116, 206, 23, 34, 43, 166, 73},
{107, 54, 32, 26, 51, 1, 81, 43, 31},
{68, 25, 106, 22, 64, 171, 36, 225, 114},
{34, 19, 21, 102, 132, 188, 16, 76, 124},
{62, 18, 78, 95, 85, 57, 50, 48, 51},
},
{
{193, 101, 35, 159, 215, 111, 89, 46, 111},
{60, 148, 31, 172, 219, 228, 21, 18, 111},
{112, 113, 77, 85, 179, 255, 38, 120, 114},
{40, 42, 1, 196, 245, 209, 10, 25, 109},
{88, 43, 29, 140, 166, 213, 37, 43, 154},
{61, 63, 30, 155, 67, 45, 68, 1, 209},
{100, 80, 8, 43, 154, 1, 51, 26, 71},
{142, 78, 78, 16, 255, 128, 34, 197, 171},
{41, 40, 5, 102, 211, 183, 4, 1, 221},
{51, 50, 17, 168, 209, 192, 23, 25, 82},
},
{
{138, 31, 36, 171, 27, 166, 38, 44, 229},
{67, 87, 58, 169, 82, 115, 26, 59, 179},
{63, 59, 90, 180, 59, 166, 93, 73, 154},
{40, 40, 21, 116, 143, 209, 34, 39, 175},
{47, 15, 16, 183, 34, 223, 49, 45, 183},
{46, 17, 33, 183, 6, 98, 15, 32, 183},
{57, 46, 22, 24, 128, 1, 54, 17, 37},
{65, 32, 73, 115, 28, 128, 23, 128, 205},
{40, 3, 9, 115, 51, 192, 18, 6, 223},
{87, 37, 9, 115, 59, 77, 64, 21, 47},
},
{
{104, 55, 44, 218, 9, 54, 53, 130, 226},
{64, 90, 70, 205, 40, 41, 23, 26, 57},
{54, 57, 112, 184, 5, 41, 38, 166, 213},
{30, 34, 26, 133, 152, 116, 10, 32, 134},
{39, 19, 53, 221, 26, 114, 32, 73, 255},
{31, 9, 65, 234, 2, 15, 1, 118, 73},
{75, 32, 12, 51, 192, 255, 160, 43, 51},
{88, 31, 35, 67, 102, 85, 55, 186, 85},
{56, 21, 23, 111, 59, 205, 45, 37, 192},
{55, 38, 70, 124, 73, 102, 1, 34, 98},
},
{
{125, 98, 42, 88, 104, 85, 117, 175, 82},
{95, 84, 53, 89, 128, 100, 113, 101, 45},
{75, 79, 123, 47, 51, 128, 81, 171, 1},
{57, 17, 5, 71, 102, 57, 53, 41, 49},
{38, 33, 13, 121, 57, 73, 26, 1, 85},
{41, 10, 67, 138, 77, 110, 90, 47, 114},
{115, 21, 2, 10, 102, 255, 166, 23, 6},
{101, 29, 16, 10, 85, 128, 101, 196, 26},
{57, 18, 10, 102, 102, 213, 34, 20, 43},
{117, 20, 15, 36, 163, 128, 68, 1, 26},
},
{
{102, 61, 71, 37, 34, 53, 31, 243, 192},
{69, 60, 71, 38, 73, 119, 28, 222, 37},
{68, 45, 128, 34, 1, 47, 11, 245, 171},
{62, 17, 19, 70, 146, 85, 55, 62, 70},
{37, 43, 37, 154, 100, 163, 85, 160, 1},
{63, 9, 92, 136, 28, 64, 32, 201, 85},
{75, 15, 9, 9, 64, 255, 184, 119, 16},
{86, 6, 28, 5, 64, 255, 25, 248, 1},
{56, 8, 17, 132, 137, 255, 55, 116, 128},
{58, 15, 20, 82, 135, 57, 26, 121, 40},
},
{
{164, 50, 31, 137, 154, 133, 25, 35, 218},
{51, 103, 44, 131, 131, 123, 31, 6, 158},
{86, 40, 64, 135, 148, 224, 45, 183, 128},
{22, 26, 17, 131, 240, 154, 14, 1, 209},
{45, 16, 21, 91, 64, 222, 7, 1, 197},
{56, 21, 39, 155, 60, 138, 23, 102, 213},
{83, 12, 13, 54, 192, 255, 68, 47, 28},
{85, 26, 85, 85, 128, 128, 32, 146, 171},
{18, 11, 7, 63, 144, 171, 4, 4, 246},
{35, 27, 10, 146, 174, 171, 12, 26, 128},
},
{
{190, 80, 35, 99, 180, 80, 126, 54, 45},
{85, 126, 47, 87, 176, 51, 41, 20, 32},
{101, 75, 128, 139, 118, 146, 116, 128, 85},
{56, 41, 15, 176, 236, 85, 37, 9, 62},
{71, 30, 17, 119, 118, 255, 17, 18, 138},
{101, 38, 60, 138, 55, 70, 43, 26, 142},
{146, 36, 19, 30, 171, 255, 97, 27, 20},
{138, 45, 61, 62, 219, 1, 81, 188, 64},
{32, 41, 20, 117, 151, 142, 20, 21, 163},
{112, 19, 12, 61, 195, 128, 48, 4, 24},
},
}
// Copyright 2011 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 vp8
// This file implements the prediction functions, as specified in chapter 12.
//
// For each macroblock (of 1x16x16 luma and 2x8x8 chroma coefficients), the
// luma values are either predicted as one large 16x16 region or 16 separate
// 4x4 regions. The chroma values are always predicted as one 8x8 region.
//
// For 4x4 regions, the target block's predicted values (Xs) are a function of
// its previously-decoded top and left border values, as well as a number of
// pixels from the top-right:
//
// a b c d e f g h
// p X X X X
// q X X X X
// r X X X X
// s X X X X
//
// The predictor modes are:
// - DC: all Xs = (b + c + d + e + p + q + r + s + 4) / 8.
// - TM: the first X = (b + p - a), the second X = (c + p - a), and so on.
// - VE: each X = the weighted average of its column's top value and that
// value's neighbors, i.e. averages of abc, bcd, cde or def.
// - HE: similar to VE except rows instead of columns, and the final row is
// an average of r, s and s.
// - RD, VR, LD, VL, HD, HU: these diagonal modes ("Right Down", "Vertical
// Right", etc) are more complicated and are described in section 12.3.
// All Xs are clipped to the range [0, 255].
//
// For 8x8 and 16x16 regions, the target block's predicted values are a
// function of the top and left border values without the top-right overhang,
// i.e. without the 8x8 or 16x16 equivalent of f, g and h. Furthermore:
// - There are no diagonal predictor modes, only DC, TM, VE and HE.
// - The DC mode has variants for macroblocks in the top row and/or left
// column, i.e. for macroblocks with mby == 0 || mbx == 0.
// - The VE and HE modes take only the column top or row left values; they do
// not smooth that top/left value with its neighbors.
// nPred is the number of predictor modes, not including the Top/Left versions
// of the DC predictor mode.
const nPred = 10
const (
predDC = iota
predTM
predVE
predHE
predRD
predVR
predLD
predVL
predHD
predHU
predDCTop
predDCLeft
predDCTopLeft
)
func checkTopLeftPred(mbx, mby int, p uint8) uint8 {
if p != predDC {
return p
}
if mbx == 0 {
if mby == 0 {
return predDCTopLeft
}
return predDCLeft
}
if mby == 0 {
return predDCTop
}
return predDC
}
var predFunc4 = [...]func(*Decoder, int, int){
predFunc4DC,
predFunc4TM,
predFunc4VE,
predFunc4HE,
predFunc4RD,
predFunc4VR,
predFunc4LD,
predFunc4VL,
predFunc4HD,
predFunc4HU,
nil,
nil,
nil,
}
var predFunc8 = [...]func(*Decoder, int, int){
predFunc8DC,
predFunc8TM,
predFunc8VE,
predFunc8HE,
nil,
nil,
nil,
nil,
nil,
nil,
predFunc8DCTop,
predFunc8DCLeft,
predFunc8DCTopLeft,
}
var predFunc16 = [...]func(*Decoder, int, int){
predFunc16DC,
predFunc16TM,
predFunc16VE,
predFunc16HE,
nil,
nil,
nil,
nil,
nil,
nil,
predFunc16DCTop,
predFunc16DCLeft,
predFunc16DCTopLeft,
}
func predFunc4DC(z *Decoder, y, x int) {
sum := uint32(4)
for i := 0; i < 4; i++ {
sum += uint32(z.ybr[y-1][x+i])
}
for j := 0; j < 4; j++ {
sum += uint32(z.ybr[y+j][x-1])
}
avg := uint8(sum / 8)
for j := 0; j < 4; j++ {
for i := 0; i < 4; i++ {
z.ybr[y+j][x+i] = avg
}
}
}
func predFunc4TM(z *Decoder, y, x int) {
delta0 := -int32(z.ybr[y-1][x-1])
for j := 0; j < 4; j++ {
delta1 := delta0 + int32(z.ybr[y+j][x-1])
for i := 0; i < 4; i++ {
delta2 := delta1 + int32(z.ybr[y-1][x+i])
z.ybr[y+j][x+i] = uint8(clip(delta2, 0, 255))
}
}
}
func predFunc4VE(z *Decoder, y, x int) {
a := int32(z.ybr[y-1][x-1])
b := int32(z.ybr[y-1][x+0])
c := int32(z.ybr[y-1][x+1])
d := int32(z.ybr[y-1][x+2])
e := int32(z.ybr[y-1][x+3])
f := int32(z.ybr[y-1][x+4])
abc := uint8((a + 2*b + c + 2) / 4)
bcd := uint8((b + 2*c + d + 2) / 4)
cde := uint8((c + 2*d + e + 2) / 4)
def := uint8((d + 2*e + f + 2) / 4)
for j := 0; j < 4; j++ {
z.ybr[y+j][x+0] = abc
z.ybr[y+j][x+1] = bcd
z.ybr[y+j][x+2] = cde
z.ybr[y+j][x+3] = def
}
}
func predFunc4HE(z *Decoder, y, x int) {
s := int32(z.ybr[y+3][x-1])
r := int32(z.ybr[y+2][x-1])
q := int32(z.ybr[y+1][x-1])
p := int32(z.ybr[y+0][x-1])
a := int32(z.ybr[y-1][x-1])
ssr := uint8((s + 2*s + r + 2) / 4)
srq := uint8((s + 2*r + q + 2) / 4)
rqp := uint8((r + 2*q + p + 2) / 4)
apq := uint8((a + 2*p + q + 2) / 4)
for i := 0; i < 4; i++ {
z.ybr[y+0][x+i] = apq
z.ybr[y+1][x+i] = rqp
z.ybr[y+2][x+i] = srq
z.ybr[y+3][x+i] = ssr
}
}
func predFunc4RD(z *Decoder, y, x int) {
s := int32(z.ybr[y+3][x-1])
r := int32(z.ybr[y+2][x-1])
q := int32(z.ybr[y+1][x-1])
p := int32(z.ybr[y+0][x-1])
a := int32(z.ybr[y-1][x-1])
b := int32(z.ybr[y-1][x+0])
c := int32(z.ybr[y-1][x+1])
d := int32(z.ybr[y-1][x+2])
e := int32(z.ybr[y-1][x+3])
srq := uint8((s + 2*r + q + 2) / 4)
rqp := uint8((r + 2*q + p + 2) / 4)
qpa := uint8((q + 2*p + a + 2) / 4)
pab := uint8((p + 2*a + b + 2) / 4)
abc := uint8((a + 2*b + c + 2) / 4)
bcd := uint8((b + 2*c + d + 2) / 4)
cde := uint8((c + 2*d + e + 2) / 4)
z.ybr[y+0][x+0] = pab
z.ybr[y+0][x+1] = abc
z.ybr[y+0][x+2] = bcd
z.ybr[y+0][x+3] = cde
z.ybr[y+1][x+0] = qpa
z.ybr[y+1][x+1] = pab
z.ybr[y+1][x+2] = abc
z.ybr[y+1][x+3] = bcd
z.ybr[y+2][x+0] = rqp
z.ybr[y+2][x+1] = qpa
z.ybr[y+2][x+2] = pab
z.ybr[y+2][x+3] = abc
z.ybr[y+3][x+0] = srq
z.ybr[y+3][x+1] = rqp
z.ybr[y+3][x+2] = qpa
z.ybr[y+3][x+3] = pab
}
func predFunc4VR(z *Decoder, y, x int) {
r := int32(z.ybr[y+2][x-1])
q := int32(z.ybr[y+1][x-1])
p := int32(z.ybr[y+0][x-1])
a := int32(z.ybr[y-1][x-1])
b := int32(z.ybr[y-1][x+0])
c := int32(z.ybr[y-1][x+1])
d := int32(z.ybr[y-1][x+2])
e := int32(z.ybr[y-1][x+3])
ab := uint8((a + b + 1) / 2)
bc := uint8((b + c + 1) / 2)
cd := uint8((c + d + 1) / 2)
de := uint8((d + e + 1) / 2)
rqp := uint8((r + 2*q + p + 2) / 4)
qpa := uint8((q + 2*p + a + 2) / 4)
pab := uint8((p + 2*a + b + 2) / 4)
abc := uint8((a + 2*b + c + 2) / 4)
bcd := uint8((b + 2*c + d + 2) / 4)
cde := uint8((c + 2*d + e + 2) / 4)
z.ybr[y+0][x+0] = ab
z.ybr[y+0][x+1] = bc
z.ybr[y+0][x+2] = cd
z.ybr[y+0][x+3] = de
z.ybr[y+1][x+0] = pab
z.ybr[y+1][x+1] = abc
z.ybr[y+1][x+2] = bcd
z.ybr[y+1][x+3] = cde
z.ybr[y+2][x+0] = qpa
z.ybr[y+2][x+1] = ab
z.ybr[y+2][x+2] = bc
z.ybr[y+2][x+3] = cd
z.ybr[y+3][x+0] = rqp
z.ybr[y+3][x+1] = pab
z.ybr[y+3][x+2] = abc
z.ybr[y+3][x+3] = bcd
}
func predFunc4LD(z *Decoder, y, x int) {
a := int32(z.ybr[y-1][x+0])
b := int32(z.ybr[y-1][x+1])
c := int32(z.ybr[y-1][x+2])
d := int32(z.ybr[y-1][x+3])
e := int32(z.ybr[y-1][x+4])
f := int32(z.ybr[y-1][x+5])
g := int32(z.ybr[y-1][x+6])
h := int32(z.ybr[y-1][x+7])
abc := uint8((a + 2*b + c + 2) / 4)
bcd := uint8((b + 2*c + d + 2) / 4)
cde := uint8((c + 2*d + e + 2) / 4)
def := uint8((d + 2*e + f + 2) / 4)
efg := uint8((e + 2*f + g + 2) / 4)
fgh := uint8((f + 2*g + h + 2) / 4)
ghh := uint8((g + 2*h + h + 2) / 4)
z.ybr[y+0][x+0] = abc
z.ybr[y+0][x+1] = bcd
z.ybr[y+0][x+2] = cde
z.ybr[y+0][x+3] = def
z.ybr[y+1][x+0] = bcd
z.ybr[y+1][x+1] = cde
z.ybr[y+1][x+2] = def
z.ybr[y+1][x+3] = efg
z.ybr[y+2][x+0] = cde
z.ybr[y+2][x+1] = def
z.ybr[y+2][x+2] = efg
z.ybr[y+2][x+3] = fgh
z.ybr[y+3][x+0] = def
z.ybr[y+3][x+1] = efg
z.ybr[y+3][x+2] = fgh
z.ybr[y+3][x+3] = ghh
}
func predFunc4VL(z *Decoder, y, x int) {
a := int32(z.ybr[y-1][x+0])
b := int32(z.ybr[y-1][x+1])
c := int32(z.ybr[y-1][x+2])
d := int32(z.ybr[y-1][x+3])
e := int32(z.ybr[y-1][x+4])
f := int32(z.ybr[y-1][x+5])
g := int32(z.ybr[y-1][x+6])
h := int32(z.ybr[y-1][x+7])
ab := uint8((a + b + 1) / 2)
bc := uint8((b + c + 1) / 2)
cd := uint8((c + d + 1) / 2)
de := uint8((d + e + 1) / 2)
abc := uint8((a + 2*b + c + 2) / 4)
bcd := uint8((b + 2*c + d + 2) / 4)
cde := uint8((c + 2*d + e + 2) / 4)
def := uint8((d + 2*e + f + 2) / 4)
efg := uint8((e + 2*f + g + 2) / 4)
fgh := uint8((f + 2*g + h + 2) / 4)
z.ybr[y+0][x+0] = ab
z.ybr[y+0][x+1] = bc
z.ybr[y+0][x+2] = cd
z.ybr[y+0][x+3] = de
z.ybr[y+1][x+0] = abc
z.ybr[y+1][x+1] = bcd
z.ybr[y+1][x+2] = cde
z.ybr[y+1][x+3] = def
z.ybr[y+2][x+0] = bc
z.ybr[y+2][x+1] = cd
z.ybr[y+2][x+2] = de
z.ybr[y+2][x+3] = efg
z.ybr[y+3][x+0] = bcd
z.ybr[y+3][x+1] = cde
z.ybr[y+3][x+2] = def
z.ybr[y+3][x+3] = fgh
}
func predFunc4HD(z *Decoder, y, x int) {
s := int32(z.ybr[y+3][x-1])
r := int32(z.ybr[y+2][x-1])
q := int32(z.ybr[y+1][x-1])
p := int32(z.ybr[y+0][x-1])
a := int32(z.ybr[y-1][x-1])
b := int32(z.ybr[y-1][x+0])
c := int32(z.ybr[y-1][x+1])
d := int32(z.ybr[y-1][x+2])
sr := uint8((s + r + 1) / 2)
rq := uint8((r + q + 1) / 2)
qp := uint8((q + p + 1) / 2)
pa := uint8((p + a + 1) / 2)
srq := uint8((s + 2*r + q + 2) / 4)
rqp := uint8((r + 2*q + p + 2) / 4)
qpa := uint8((q + 2*p + a + 2) / 4)
pab := uint8((p + 2*a + b + 2) / 4)
abc := uint8((a + 2*b + c + 2) / 4)
bcd := uint8((b + 2*c + d + 2) / 4)
z.ybr[y+0][x+0] = pa
z.ybr[y+0][x+1] = pab
z.ybr[y+0][x+2] = abc
z.ybr[y+0][x+3] = bcd
z.ybr[y+1][x+0] = qp
z.ybr[y+1][x+1] = qpa
z.ybr[y+1][x+2] = pa
z.ybr[y+1][x+3] = pab
z.ybr[y+2][x+0] = rq
z.ybr[y+2][x+1] = rqp
z.ybr[y+2][x+2] = qp
z.ybr[y+2][x+3] = qpa
z.ybr[y+3][x+0] = sr
z.ybr[y+3][x+1] = srq
z.ybr[y+3][x+2] = rq
z.ybr[y+3][x+3] = rqp
}
func predFunc4HU(z *Decoder, y, x int) {
s := int32(z.ybr[y+3][x-1])
r := int32(z.ybr[y+2][x-1])
q := int32(z.ybr[y+1][x-1])
p := int32(z.ybr[y+0][x-1])
pq := uint8((p + q + 1) / 2)
qr := uint8((q + r + 1) / 2)
rs := uint8((r + s + 1) / 2)
pqr := uint8((p + 2*q + r + 2) / 4)
qrs := uint8((q + 2*r + s + 2) / 4)
rss := uint8((r + 2*s + s + 2) / 4)
sss := uint8(s)
z.ybr[y+0][x+0] = pq
z.ybr[y+0][x+1] = pqr
z.ybr[y+0][x+2] = qr
z.ybr[y+0][x+3] = qrs
z.ybr[y+1][x+0] = qr
z.ybr[y+1][x+1] = qrs
z.ybr[y+1][x+2] = rs
z.ybr[y+1][x+3] = rss
z.ybr[y+2][x+0] = rs
z.ybr[y+2][x+1] = rss
z.ybr[y+2][x+2] = sss
z.ybr[y+2][x+3] = sss
z.ybr[y+3][x+0] = sss
z.ybr[y+3][x+1] = sss
z.ybr[y+3][x+2] = sss
z.ybr[y+3][x+3] = sss
}
func predFunc8DC(z *Decoder, y, x int) {
sum := uint32(8)
for i := 0; i < 8; i++ {
sum += uint32(z.ybr[y-1][x+i])
}
for j := 0; j < 8; j++ {
sum += uint32(z.ybr[y+j][x-1])
}
avg := uint8(sum / 16)
for j := 0; j < 8; j++ {
for i := 0; i < 8; i++ {
z.ybr[y+j][x+i] = avg
}
}
}
func predFunc8TM(z *Decoder, y, x int) {
delta0 := -int32(z.ybr[y-1][x-1])
for j := 0; j < 8; j++ {
delta1 := delta0 + int32(z.ybr[y+j][x-1])
for i := 0; i < 8; i++ {
delta2 := delta1 + int32(z.ybr[y-1][x+i])
z.ybr[y+j][x+i] = uint8(clip(delta2, 0, 255))
}
}
}
func predFunc8VE(z *Decoder, y, x int) {
for j := 0; j < 8; j++ {
for i := 0; i < 8; i++ {
z.ybr[y+j][x+i] = z.ybr[y-1][x+i]
}
}
}
func predFunc8HE(z *Decoder, y, x int) {
for j := 0; j < 8; j++ {
for i := 0; i < 8; i++ {
z.ybr[y+j][x+i] = z.ybr[y+j][x-1]
}
}
}
func predFunc8DCTop(z *Decoder, y, x int) {
sum := uint32(4)
for j := 0; j < 8; j++ {
sum += uint32(z.ybr[y+j][x-1])
}
avg := uint8(sum / 8)
for j := 0; j < 8; j++ {
for i := 0; i < 8; i++ {
z.ybr[y+j][x+i] = avg
}
}
}
func predFunc8DCLeft(z *Decoder, y, x int) {
sum := uint32(4)
for i := 0; i < 8; i++ {
sum += uint32(z.ybr[y-1][x+i])
}
avg := uint8(sum / 8)
for j := 0; j < 8; j++ {
for i := 0; i < 8; i++ {
z.ybr[y+j][x+i] = avg
}
}
}
func predFunc8DCTopLeft(z *Decoder, y, x int) {
for j := 0; j < 8; j++ {
for i := 0; i < 8; i++ {
z.ybr[y+j][x+i] = 0x80
}
}
}
func predFunc16DC(z *Decoder, y, x int) {
sum := uint32(16)
for i := 0; i < 16; i++ {
sum += uint32(z.ybr[y-1][x+i])
}
for j := 0; j < 16; j++ {
sum += uint32(z.ybr[y+j][x-1])
}
avg := uint8(sum / 32)
for j := 0; j < 16; j++ {
for i := 0; i < 16; i++ {
z.ybr[y+j][x+i] = avg
}
}
}
func predFunc16TM(z *Decoder, y, x int) {
delta0 := -int32(z.ybr[y-1][x-1])
for j := 0; j < 16; j++ {
delta1 := delta0 + int32(z.ybr[y+j][x-1])
for i := 0; i < 16; i++ {
delta2 := delta1 + int32(z.ybr[y-1][x+i])
z.ybr[y+j][x+i] = uint8(clip(delta2, 0, 255))
}
}
}
func predFunc16VE(z *Decoder, y, x int) {
for j := 0; j < 16; j++ {
for i := 0; i < 16; i++ {
z.ybr[y+j][x+i] = z.ybr[y-1][x+i]
}
}
}
func predFunc16HE(z *Decoder, y, x int) {
for j := 0; j < 16; j++ {
for i := 0; i < 16; i++ {
z.ybr[y+j][x+i] = z.ybr[y+j][x-1]
}
}
}
func predFunc16DCTop(z *Decoder, y, x int) {
sum := uint32(8)
for j := 0; j < 16; j++ {
sum += uint32(z.ybr[y+j][x-1])
}
avg := uint8(sum / 16)
for j := 0; j < 16; j++ {
for i := 0; i < 16; i++ {
z.ybr[y+j][x+i] = avg
}
}
}
func predFunc16DCLeft(z *Decoder, y, x int) {
sum := uint32(8)
for i := 0; i < 16; i++ {
sum += uint32(z.ybr[y-1][x+i])
}
avg := uint8(sum / 16)
for j := 0; j < 16; j++ {
for i := 0; i < 16; i++ {
z.ybr[y+j][x+i] = avg
}
}
}
func predFunc16DCTopLeft(z *Decoder, y, x int) {
for j := 0; j < 16; j++ {
for i := 0; i < 16; i++ {
z.ybr[y+j][x+i] = 0x80
}
}
}
// Copyright 2011 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 vp8
// This file implements parsing the quantization factors.
// quant are DC/AC quantization factors.
type quant struct {
y1 [2]uint16
y2 [2]uint16
uv [2]uint16
}
// clip clips x to the range [min, max] inclusive.
func clip(x, min, max int32) int32 {
if x < min {
return min
}
if x > max {
return max
}
return x
}
// parseQuant parses the quantization factors, as specified in section 9.6.
func (d *Decoder) parseQuant() {
baseQ0 := d.fp.readUint(uniformProb, 7)
dqy1DC := d.fp.readOptionalInt(uniformProb, 4)
const dqy1AC = 0
dqy2DC := d.fp.readOptionalInt(uniformProb, 4)
dqy2AC := d.fp.readOptionalInt(uniformProb, 4)
dquvDC := d.fp.readOptionalInt(uniformProb, 4)
dquvAC := d.fp.readOptionalInt(uniformProb, 4)
for i := 0; i < nSegment; i++ {
q := int32(baseQ0)
if d.segmentHeader.useSegment {
if d.segmentHeader.relativeDelta {
q += int32(d.segmentHeader.quantizer[i])
} else {
q = int32(d.segmentHeader.quantizer[i])
}
}
d.quant[i].y1[0] = dequantTableDC[clip(q+dqy1DC, 0, 127)]
d.quant[i].y1[1] = dequantTableAC[clip(q+dqy1AC, 0, 127)]
d.quant[i].y2[0] = dequantTableDC[clip(q+dqy2DC, 0, 127)] * 2
d.quant[i].y2[1] = dequantTableAC[clip(q+dqy2AC, 0, 127)] * 155 / 100
if d.quant[i].y2[1] < 8 {
d.quant[i].y2[1] = 8
}
// The 117 is not a typo. The dequant_init function in the spec's Reference
// Decoder Source Code (http://tools.ietf.org/html/rfc6386#section-9.6 Page 145)
// says to clamp the LHS value at 132, which is equal to dequantTableDC[117].
d.quant[i].uv[0] = dequantTableDC[clip(q+dquvDC, 0, 117)]
d.quant[i].uv[1] = dequantTableAC[clip(q+dquvAC, 0, 127)]
}
}
// The dequantization tables are specified in section 14.1.
var (
dequantTableDC = [128]uint16{
4, 5, 6, 7, 8, 9, 10, 10,
11, 12, 13, 14, 15, 16, 17, 17,
18, 19, 20, 20, 21, 21, 22, 22,
23, 23, 24, 25, 25, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36,
37, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, 62, 63, 64, 65, 66,
67, 68, 69, 70, 71, 72, 73, 74,
75, 76, 76, 77, 78, 79, 80, 81,
82, 83, 84, 85, 86, 87, 88, 89,
91, 93, 95, 96, 98, 100, 101, 102,
104, 106, 108, 110, 112, 114, 116, 118,
122, 124, 126, 128, 130, 132, 134, 136,
138, 140, 143, 145, 148, 151, 154, 157,
}
dequantTableAC = [128]uint16{
4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 49, 50, 51,
52, 53, 54, 55, 56, 57, 58, 60,
62, 64, 66, 68, 70, 72, 74, 76,
78, 80, 82, 84, 86, 88, 90, 92,
94, 96, 98, 100, 102, 104, 106, 108,
110, 112, 114, 116, 119, 122, 125, 128,
131, 134, 137, 140, 143, 146, 149, 152,
155, 158, 161, 164, 167, 170, 173, 177,
181, 185, 189, 193, 197, 201, 205, 209,
213, 217, 221, 225, 229, 234, 239, 245,
249, 254, 259, 264, 269, 274, 279, 284,
}
)
// Copyright 2011 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 vp8
// This file implements decoding DCT/WHT residual coefficients and
// reconstructing YCbCr data equal to predicted values plus residuals.
//
// There are 1*16*16 + 2*8*8 + 1*4*4 coefficients per macroblock:
// - 1*16*16 luma DCT coefficients,
// - 2*8*8 chroma DCT coefficients, and
// - 1*4*4 luma WHT coefficients.
// Coefficients are read in lots of 16, and the later coefficients in each lot
// are often zero.
//
// The YCbCr data consists of 1*16*16 luma values and 2*8*8 chroma values,
// plus previously decoded values along the top and left borders. The combined
// values are laid out as a [1+16+1+8][32]uint8 so that vertically adjacent
// samples are 32 bytes apart. In detail, the layout is:
//
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// . . . . . . . a b b b b b b b b b b b b b b b b c c c c . . . . 0
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 1
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 2
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 3
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y c c c c . . . . 4
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 5
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 6
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 7
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y c c c c . . . . 8
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 9
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 10
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 11
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y c c c c . . . . 12
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 13
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 14
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 15
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 16
// . . . . . . . e f f f f f f f f . . . . . . . g h h h h h h h h 17
// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 18
// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 19
// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 20
// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 21
// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 22
// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 23
// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 24
// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 25
//
// Y, B and R are the reconstructed luma (Y) and chroma (B, R) values.
// The Y values are predicted (either as one 16x16 region or 16 4x4 regions)
// based on the row above's Y values (some combination of {abc} or {dYC}) and
// the column left's Y values (either {ad} or {bY}). Similarly, B and R values
// are predicted on the row above and column left of their respective 8x8
// region: {efi} for B, {ghj} for R.
//
// For uppermost macroblocks (i.e. those with mby == 0), the {abcefgh} values
// are initialized to 0x81. Otherwise, they are copied from the bottom row of
// the macroblock above. The {c} values are then duplicated from row 0 to rows
// 4, 8 and 12 of the ybr workspace.
// Similarly, for leftmost macroblocks (i.e. those with mbx == 0), the {adeigj}
// values are initialized to 0x7f. Otherwise, they are copied from the right
// column of the macroblock to the left.
// For the top-left macroblock (with mby == 0 && mbx == 0), {aeg} is 0x81.
//
// When moving from one macroblock to the next horizontally, the {adeigj}
// values can simply be copied from the workspace to itself, shifted by 8 or
// 16 columns. When moving from one macroblock to the next vertically,
// filtering can occur and hence the row values have to be copied from the
// post-filtered image instead of the pre-filtered workspace.
const (
bCoeffBase = 1*16*16 + 0*8*8
rCoeffBase = 1*16*16 + 1*8*8
whtCoeffBase = 1*16*16 + 2*8*8
)
const (
ybrYX = 8
ybrYY = 1
ybrBX = 8
ybrBY = 18
ybrRX = 24
ybrRY = 18
)
// prepareYBR prepares the {abcdefghij} elements of ybr.
func (d *Decoder) prepareYBR(mbx, mby int) {
if mbx == 0 {
for y := 0; y < 17; y++ {
d.ybr[y][7] = 0x81
}
for y := 17; y < 26; y++ {
d.ybr[y][7] = 0x81
d.ybr[y][23] = 0x81
}
} else {
for y := 0; y < 17; y++ {
d.ybr[y][7] = d.ybr[y][7+16]
}
for y := 17; y < 26; y++ {
d.ybr[y][7] = d.ybr[y][15]
d.ybr[y][23] = d.ybr[y][31]
}
}
if mby == 0 {
for x := 7; x < 28; x++ {
d.ybr[0][x] = 0x7f
}
for x := 7; x < 16; x++ {
d.ybr[17][x] = 0x7f
}
for x := 23; x < 32; x++ {
d.ybr[17][x] = 0x7f
}
} else {
for i := 0; i < 16; i++ {
d.ybr[0][8+i] = d.img.Y[(16*mby-1)*d.img.YStride+16*mbx+i]
}
for i := 0; i < 8; i++ {
d.ybr[17][8+i] = d.img.Cb[(8*mby-1)*d.img.CStride+8*mbx+i]
}
for i := 0; i < 8; i++ {
d.ybr[17][24+i] = d.img.Cr[(8*mby-1)*d.img.CStride+8*mbx+i]
}
if mbx == d.mbw-1 {
for i := 16; i < 20; i++ {
d.ybr[0][8+i] = d.img.Y[(16*mby-1)*d.img.YStride+16*mbx+15]
}
} else {
for i := 16; i < 20; i++ {
d.ybr[0][8+i] = d.img.Y[(16*mby-1)*d.img.YStride+16*mbx+i]
}
}
}
for y := 4; y < 16; y += 4 {
d.ybr[y][24] = d.ybr[0][24]
d.ybr[y][25] = d.ybr[0][25]
d.ybr[y][26] = d.ybr[0][26]
d.ybr[y][27] = d.ybr[0][27]
}
}
// btou converts a bool to a 0/1 value.
func btou(b bool) uint8 {
if b {
return 1
}
return 0
}
// pack packs four 0/1 values into four bits of a uint32.
func pack(x [4]uint8, shift int) uint32 {
u := uint32(x[0])<<0 | uint32(x[1])<<1 | uint32(x[2])<<2 | uint32(x[3])<<3
return u << uint(shift)
}
// unpack unpacks four 0/1 values from a four-bit value.
var unpack = [16][4]uint8{
{0, 0, 0, 0},
{1, 0, 0, 0},
{0, 1, 0, 0},
{1, 1, 0, 0},
{0, 0, 1, 0},
{1, 0, 1, 0},
{0, 1, 1, 0},
{1, 1, 1, 0},
{0, 0, 0, 1},
{1, 0, 0, 1},
{0, 1, 0, 1},
{1, 1, 0, 1},
{0, 0, 1, 1},
{1, 0, 1, 1},
{0, 1, 1, 1},
{1, 1, 1, 1},
}
var (
// The mapping from 4x4 region position to band is specified in section 13.3.
bands = [17]uint8{0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 0}
// Category probabilities are specified in section 13.2.
// Decoding categories 1 and 2 are done inline.
cat3456 = [4][12]uint8{
{173, 148, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{176, 155, 140, 135, 0, 0, 0, 0, 0, 0, 0, 0},
{180, 157, 141, 134, 130, 0, 0, 0, 0, 0, 0, 0},
{254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129, 0},
}
// The zigzag order is:
// 0 1 5 6
// 2 4 7 12
// 3 8 11 13
// 9 10 14 15
zigzag = [16]uint8{0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15}
)
// parseResiduals4 parses a 4x4 region of residual coefficients, as specified
// in section 13.3, and returns a 0/1 value indicating whether there was at
// least one non-zero coefficient.
// r is the partition to read bits from.
// plane and context describe which token probability table to use. context is
// either 0, 1 or 2, and equals how many of the macroblock left and macroblock
// above have non-zero coefficients.
// quant are the DC/AC quantization factors.
// skipFirstCoeff is whether the DC coefficient has already been parsed.
// coeffBase is the base index of d.coeff to write to.
func (d *Decoder) parseResiduals4(r *partition, plane int, context uint8, quant [2]uint16, skipFirstCoeff bool, coeffBase int) uint8 {
prob, n := &d.tokenProb[plane], 0
if skipFirstCoeff {
n = 1
}
p := prob[bands[n]][context]
if !r.readBit(p[0]) {
return 0
}
for n != 16 {
n++
if !r.readBit(p[1]) {
p = prob[bands[n]][0]
continue
}
var v uint32
if !r.readBit(p[2]) {
v = 1
p = prob[bands[n]][1]
} else {
if !r.readBit(p[3]) {
if !r.readBit(p[4]) {
v = 2
} else {
v = 3 + r.readUint(p[5], 1)
}
} else if !r.readBit(p[6]) {
if !r.readBit(p[7]) {
// Category 1.
v = 5 + r.readUint(159, 1)
} else {
// Category 2.
v = 7 + 2*r.readUint(165, 1) + r.readUint(145, 1)
}
} else {
// Categories 3, 4, 5 or 6.
b1 := r.readUint(p[8], 1)
b0 := r.readUint(p[9+b1], 1)
cat := 2*b1 + b0
tab := &cat3456[cat]
v = 0
for i := 0; tab[i] != 0; i++ {
v *= 2
v += r.readUint(tab[i], 1)
}
v += 3 + (8 << cat)
}
p = prob[bands[n]][2]
}
z := zigzag[n-1]
c := int32(v) * int32(quant[btou(z > 0)])
if r.readBit(uniformProb) {
c = -c
}
d.coeff[coeffBase+int(z)] = int16(c)
if n == 16 || !r.readBit(p[0]) {
return 1
}
}
return 1
}
// parseResiduals parses the residuals and returns whether inner loop filtering
// should be skipped for this macroblock.
func (d *Decoder) parseResiduals(mbx, mby int) (skip bool) {
partition := &d.op[mby&(d.nOP-1)]
plane := planeY1SansY2
quant := &d.quant[d.segment]
// Parse the DC coefficient of each 4x4 luma region.
if d.usePredY16 {
nz := d.parseResiduals4(partition, planeY2, d.leftMB.nzY16+d.upMB[mbx].nzY16, quant.y2, false, whtCoeffBase)
d.leftMB.nzY16 = nz
d.upMB[mbx].nzY16 = nz
d.inverseWHT16()
plane = planeY1WithY2
}
var (
nzDC, nzAC [4]uint8
nzDCMask, nzACMask uint32
coeffBase int
)
// Parse the luma coefficients.
lnz := unpack[d.leftMB.nzMask&0x0f]
unz := unpack[d.upMB[mbx].nzMask&0x0f]
for y := 0; y < 4; y++ {
nz := lnz[y]
for x := 0; x < 4; x++ {
nz = d.parseResiduals4(partition, plane, nz+unz[x], quant.y1, d.usePredY16, coeffBase)
unz[x] = nz
nzAC[x] = nz
nzDC[x] = btou(d.coeff[coeffBase] != 0)
coeffBase += 16
}
lnz[y] = nz
nzDCMask |= pack(nzDC, y*4)
nzACMask |= pack(nzAC, y*4)
}
lnzMask := pack(lnz, 0)
unzMask := pack(unz, 0)
// Parse the chroma coefficients.
lnz = unpack[d.leftMB.nzMask>>4]
unz = unpack[d.upMB[mbx].nzMask>>4]
for c := 0; c < 4; c += 2 {
for y := 0; y < 2; y++ {
nz := lnz[y+c]
for x := 0; x < 2; x++ {
nz = d.parseResiduals4(partition, planeUV, nz+unz[x+c], quant.uv, false, coeffBase)
unz[x+c] = nz
nzAC[y*2+x] = nz
nzDC[y*2+x] = btou(d.coeff[coeffBase] != 0)
coeffBase += 16
}
lnz[y+c] = nz
}
nzDCMask |= pack(nzDC, 16+c*2)
nzACMask |= pack(nzAC, 16+c*2)
}
lnzMask |= pack(lnz, 4)
unzMask |= pack(unz, 4)
// Save decoder state.
d.leftMB.nzMask = uint8(lnzMask)
d.upMB[mbx].nzMask = uint8(unzMask)
d.nzDCMask = nzDCMask
d.nzACMask = nzACMask
// Section 15.1 of the spec says that "Steps 2 and 4 [of the loop filter]
// are skipped... [if] there is no DCT coefficient coded for the whole
// macroblock."
return nzDCMask == 0 && nzACMask == 0
}
// reconstructMacroblock applies the predictor functions and adds the inverse-
// DCT transformed residuals to recover the YCbCr data.
func (d *Decoder) reconstructMacroblock(mbx, mby int) {
if d.usePredY16 {
p := checkTopLeftPred(mbx, mby, d.predY16)
predFunc16[p](d, 1, 8)
for j := 0; j < 4; j++ {
for i := 0; i < 4; i++ {
n := 4*j + i
y := 4*j + 1
x := 4*i + 8
mask := uint32(1) << uint(n)
if d.nzACMask&mask != 0 {
d.inverseDCT4(y, x, 16*n)
} else if d.nzDCMask&mask != 0 {
d.inverseDCT4DCOnly(y, x, 16*n)
}
}
}
} else {
for j := 0; j < 4; j++ {
for i := 0; i < 4; i++ {
n := 4*j + i
y := 4*j + 1
x := 4*i + 8
predFunc4[d.predY4[j][i]](d, y, x)
mask := uint32(1) << uint(n)
if d.nzACMask&mask != 0 {
d.inverseDCT4(y, x, 16*n)
} else if d.nzDCMask&mask != 0 {
d.inverseDCT4DCOnly(y, x, 16*n)
}
}
}
}
p := checkTopLeftPred(mbx, mby, d.predC8)
predFunc8[p](d, ybrBY, ybrBX)
if d.nzACMask&0x0f0000 != 0 {
d.inverseDCT8(ybrBY, ybrBX, bCoeffBase)
} else if d.nzDCMask&0x0f0000 != 0 {
d.inverseDCT8DCOnly(ybrBY, ybrBX, bCoeffBase)
}
predFunc8[p](d, ybrRY, ybrRX)
if d.nzACMask&0xf00000 != 0 {
d.inverseDCT8(ybrRY, ybrRX, rCoeffBase)
} else if d.nzDCMask&0xf00000 != 0 {
d.inverseDCT8DCOnly(ybrRY, ybrRX, rCoeffBase)
}
}
// reconstruct reconstructs one macroblock and returns whether inner loop
// filtering should be skipped for it.
func (d *Decoder) reconstruct(mbx, mby int) (skip bool) {
if d.segmentHeader.updateMap {
if !d.fp.readBit(d.segmentHeader.prob[0]) {
d.segment = int(d.fp.readUint(d.segmentHeader.prob[1], 1))
} else {
d.segment = int(d.fp.readUint(d.segmentHeader.prob[2], 1)) + 2
}
}
if d.useSkipProb {
skip = d.fp.readBit(d.skipProb)
}
// Prepare the workspace.
for i := range d.coeff {
d.coeff[i] = 0
}
d.prepareYBR(mbx, mby)
// Parse the predictor modes.
d.usePredY16 = d.fp.readBit(145)
if d.usePredY16 {
d.parsePredModeY16(mbx)
} else {
d.parsePredModeY4(mbx)
}
d.parsePredModeC8()
// Parse the residuals.
if !skip {
skip = d.parseResiduals(mbx, mby)
} else {
if d.usePredY16 {
d.leftMB.nzY16 = 0
d.upMB[mbx].nzY16 = 0
}
d.leftMB.nzMask = 0
d.upMB[mbx].nzMask = 0
d.nzDCMask = 0
d.nzACMask = 0
}
// Reconstruct the YCbCr data and copy it to the image.
d.reconstructMacroblock(mbx, mby)
for i, y := (mby*d.img.YStride+mbx)*16, 0; y < 16; i, y = i+d.img.YStride, y+1 {
copy(d.img.Y[i:i+16], d.ybr[ybrYY+y][ybrYX:ybrYX+16])
}
for i, y := (mby*d.img.CStride+mbx)*8, 0; y < 8; i, y = i+d.img.CStride, y+1 {
copy(d.img.Cb[i:i+8], d.ybr[ybrBY+y][ybrBX:ybrBX+8])
copy(d.img.Cr[i:i+8], d.ybr[ybrRY+y][ybrRX:ybrRX+8])
}
return skip
}
// Copyright 2011 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 vp8
// This file contains token probabilities for decoding DCT/WHT coefficients, as
// specified in chapter 13.
func (d *Decoder) parseTokenProb() {
for i := range d.tokenProb {
for j := range d.tokenProb[i] {
for k := range d.tokenProb[i][j] {
for l := range d.tokenProb[i][j][k] {
if d.fp.readBit(tokenProbUpdateProb[i][j][k][l]) {
d.tokenProb[i][j][k][l] = uint8(d.fp.readUint(uniformProb, 8))
}
}
}
}
}
}
// The plane enumeration is specified in section 13.3.
const (
planeY1WithY2 = iota
planeY2
planeUV
planeY1SansY2
nPlane
)
const (
nBand = 8
nContext = 3
nProb = 11
)
// Token probability update probabilities are specified in section 13.4.
var tokenProbUpdateProb = [nPlane][nBand][nContext][nProb]uint8{
{
{
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
},
{
{176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255},
{249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255},
{234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
{253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255},
{239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
{254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255},
{251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
{251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
{254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255},
{250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255},
{254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
},
},
{
{
{217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255},
{234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255},
},
{
{255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
{238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255},
{249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
{252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
{253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255},
{250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
},
},
{
{
{186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255},
{234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255},
{251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255},
},
{
{255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
{236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
{251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255},
},
{
{255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
{254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
},
},
{
{
{248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255},
{248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255},
{246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255},
{252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255},
},
{
{255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255},
{248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255},
{253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255},
{245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255},
{253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255},
{252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255},
{250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
},
{
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
},
},
}
// Default token probabilities are specified in section 13.5.
var defaultTokenProb = [nPlane][nBand][nContext][nProb]uint8{
{
{
{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
},
{
{253, 136, 254, 255, 228, 219, 128, 128, 128, 128, 128},
{189, 129, 242, 255, 227, 213, 255, 219, 128, 128, 128},
{106, 126, 227, 252, 214, 209, 255, 255, 128, 128, 128},
},
{
{1, 98, 248, 255, 236, 226, 255, 255, 128, 128, 128},
{181, 133, 238, 254, 221, 234, 255, 154, 128, 128, 128},
{78, 134, 202, 247, 198, 180, 255, 219, 128, 128, 128},
},
{
{1, 185, 249, 255, 243, 255, 128, 128, 128, 128, 128},
{184, 150, 247, 255, 236, 224, 128, 128, 128, 128, 128},
{77, 110, 216, 255, 236, 230, 128, 128, 128, 128, 128},
},
{
{1, 101, 251, 255, 241, 255, 128, 128, 128, 128, 128},
{170, 139, 241, 252, 236, 209, 255, 255, 128, 128, 128},
{37, 116, 196, 243, 228, 255, 255, 255, 128, 128, 128},
},
{
{1, 204, 254, 255, 245, 255, 128, 128, 128, 128, 128},
{207, 160, 250, 255, 238, 128, 128, 128, 128, 128, 128},
{102, 103, 231, 255, 211, 171, 128, 128, 128, 128, 128},
},
{
{1, 152, 252, 255, 240, 255, 128, 128, 128, 128, 128},
{177, 135, 243, 255, 234, 225, 128, 128, 128, 128, 128},
{80, 129, 211, 255, 194, 224, 128, 128, 128, 128, 128},
},
{
{1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
{246, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
{255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
},
},
{
{
{198, 35, 237, 223, 193, 187, 162, 160, 145, 155, 62},
{131, 45, 198, 221, 172, 176, 220, 157, 252, 221, 1},
{68, 47, 146, 208, 149, 167, 221, 162, 255, 223, 128},
},
{
{1, 149, 241, 255, 221, 224, 255, 255, 128, 128, 128},
{184, 141, 234, 253, 222, 220, 255, 199, 128, 128, 128},
{81, 99, 181, 242, 176, 190, 249, 202, 255, 255, 128},
},
{
{1, 129, 232, 253, 214, 197, 242, 196, 255, 255, 128},
{99, 121, 210, 250, 201, 198, 255, 202, 128, 128, 128},
{23, 91, 163, 242, 170, 187, 247, 210, 255, 255, 128},
},
{
{1, 200, 246, 255, 234, 255, 128, 128, 128, 128, 128},
{109, 178, 241, 255, 231, 245, 255, 255, 128, 128, 128},
{44, 130, 201, 253, 205, 192, 255, 255, 128, 128, 128},
},
{
{1, 132, 239, 251, 219, 209, 255, 165, 128, 128, 128},
{94, 136, 225, 251, 218, 190, 255, 255, 128, 128, 128},
{22, 100, 174, 245, 186, 161, 255, 199, 128, 128, 128},
},
{
{1, 182, 249, 255, 232, 235, 128, 128, 128, 128, 128},
{124, 143, 241, 255, 227, 234, 128, 128, 128, 128, 128},
{35, 77, 181, 251, 193, 211, 255, 205, 128, 128, 128},
},
{
{1, 157, 247, 255, 236, 231, 255, 255, 128, 128, 128},
{121, 141, 235, 255, 225, 227, 255, 255, 128, 128, 128},
{45, 99, 188, 251, 195, 217, 255, 224, 128, 128, 128},
},
{
{1, 1, 251, 255, 213, 255, 128, 128, 128, 128, 128},
{203, 1, 248, 255, 255, 128, 128, 128, 128, 128, 128},
{137, 1, 177, 255, 224, 255, 128, 128, 128, 128, 128},
},
},
{
{
{253, 9, 248, 251, 207, 208, 255, 192, 128, 128, 128},
{175, 13, 224, 243, 193, 185, 249, 198, 255, 255, 128},
{73, 17, 171, 221, 161, 179, 236, 167, 255, 234, 128},
},
{
{1, 95, 247, 253, 212, 183, 255, 255, 128, 128, 128},
{239, 90, 244, 250, 211, 209, 255, 255, 128, 128, 128},
{155, 77, 195, 248, 188, 195, 255, 255, 128, 128, 128},
},
{
{1, 24, 239, 251, 218, 219, 255, 205, 128, 128, 128},
{201, 51, 219, 255, 196, 186, 128, 128, 128, 128, 128},
{69, 46, 190, 239, 201, 218, 255, 228, 128, 128, 128},
},
{
{1, 191, 251, 255, 255, 128, 128, 128, 128, 128, 128},
{223, 165, 249, 255, 213, 255, 128, 128, 128, 128, 128},
{141, 124, 248, 255, 255, 128, 128, 128, 128, 128, 128},
},
{
{1, 16, 248, 255, 255, 128, 128, 128, 128, 128, 128},
{190, 36, 230, 255, 236, 255, 128, 128, 128, 128, 128},
{149, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
},
{
{1, 226, 255, 128, 128, 128, 128, 128, 128, 128, 128},
{247, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128},
{240, 128, 255, 128, 128, 128, 128, 128, 128, 128, 128},
},
{
{1, 134, 252, 255, 255, 128, 128, 128, 128, 128, 128},
{213, 62, 250, 255, 255, 128, 128, 128, 128, 128, 128},
{55, 93, 255, 128, 128, 128, 128, 128, 128, 128, 128},
},
{
{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
},
},
{
{
{202, 24, 213, 235, 186, 191, 220, 160, 240, 175, 255},
{126, 38, 182, 232, 169, 184, 228, 174, 255, 187, 128},
{61, 46, 138, 219, 151, 178, 240, 170, 255, 216, 128},
},
{
{1, 112, 230, 250, 199, 191, 247, 159, 255, 255, 128},
{166, 109, 228, 252, 211, 215, 255, 174, 128, 128, 128},
{39, 77, 162, 232, 172, 180, 245, 178, 255, 255, 128},
},
{
{1, 52, 220, 246, 198, 199, 249, 220, 255, 255, 128},
{124, 74, 191, 243, 183, 193, 250, 221, 255, 255, 128},
{24, 71, 130, 219, 154, 170, 243, 182, 255, 255, 128},
},
{
{1, 182, 225, 249, 219, 240, 255, 224, 128, 128, 128},
{149, 150, 226, 252, 216, 205, 255, 171, 128, 128, 128},
{28, 108, 170, 242, 183, 194, 254, 223, 255, 255, 128},
},
{
{1, 81, 230, 252, 204, 203, 255, 192, 128, 128, 128},
{123, 102, 209, 247, 188, 196, 255, 233, 128, 128, 128},
{20, 95, 153, 243, 164, 173, 255, 203, 128, 128, 128},
},
{
{1, 222, 248, 255, 216, 213, 128, 128, 128, 128, 128},
{168, 175, 246, 252, 235, 205, 255, 255, 128, 128, 128},
{47, 116, 215, 255, 211, 212, 255, 255, 128, 128, 128},
},
{
{1, 121, 236, 253, 212, 214, 255, 255, 128, 128, 128},
{141, 84, 213, 252, 201, 202, 255, 219, 128, 128, 128},
{42, 80, 160, 240, 162, 185, 255, 205, 128, 128, 128},
},
{
{1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
{244, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
{238, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
},
},
}
// 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 vp8l implements a decoder for the VP8L lossless image format.
//
// The VP8L specification is at:
// https://developers.google.com/speed/webp/docs/riff_container
package vp8l // import "golang.org/x/image/vp8l"
import (
"bufio"
"errors"
"image"
"image/color"
"io"
)
var (
errInvalidCodeLengths = errors.New("vp8l: invalid code lengths")
errInvalidHuffmanTree = errors.New("vp8l: invalid Huffman tree")
)
// colorCacheMultiplier is the multiplier used for the color cache hash
// function, specified in section 4.2.3.
const colorCacheMultiplier = 0x1e35a7bd
// distanceMapTable is the look-up table for distanceMap.
var distanceMapTable = [120]uint8{
0x18, 0x07, 0x17, 0x19, 0x28, 0x06, 0x27, 0x29, 0x16, 0x1a,
0x26, 0x2a, 0x38, 0x05, 0x37, 0x39, 0x15, 0x1b, 0x36, 0x3a,
0x25, 0x2b, 0x48, 0x04, 0x47, 0x49, 0x14, 0x1c, 0x35, 0x3b,
0x46, 0x4a, 0x24, 0x2c, 0x58, 0x45, 0x4b, 0x34, 0x3c, 0x03,
0x57, 0x59, 0x13, 0x1d, 0x56, 0x5a, 0x23, 0x2d, 0x44, 0x4c,
0x55, 0x5b, 0x33, 0x3d, 0x68, 0x02, 0x67, 0x69, 0x12, 0x1e,
0x66, 0x6a, 0x22, 0x2e, 0x54, 0x5c, 0x43, 0x4d, 0x65, 0x6b,
0x32, 0x3e, 0x78, 0x01, 0x77, 0x79, 0x53, 0x5d, 0x11, 0x1f,
0x64, 0x6c, 0x42, 0x4e, 0x76, 0x7a, 0x21, 0x2f, 0x75, 0x7b,
0x31, 0x3f, 0x63, 0x6d, 0x52, 0x5e, 0x00, 0x74, 0x7c, 0x41,
0x4f, 0x10, 0x20, 0x62, 0x6e, 0x30, 0x73, 0x7d, 0x51, 0x5f,
0x40, 0x72, 0x7e, 0x61, 0x6f, 0x50, 0x71, 0x7f, 0x60, 0x70,
}
// distanceMap maps a LZ77 backwards reference distance to a two-dimensional
// pixel offset, specified in section 4.2.2.
func distanceMap(w int32, code uint32) int32 {
if int32(code) > int32(len(distanceMapTable)) {
return int32(code) - int32(len(distanceMapTable))
}
distCode := int32(distanceMapTable[code-1])
yOffset := distCode >> 4
xOffset := 8 - distCode&0xf
if d := yOffset*w + xOffset; d >= 1 {
return d
}
return 1
}
// decoder holds the bit-stream for a VP8L image.
type decoder struct {
r io.ByteReader
bits uint32
nBits uint32
}
// read reads the next n bits from the decoder's bit-stream.
func (d *decoder) read(n uint32) (uint32, error) {
for d.nBits < n {
c, err := d.r.ReadByte()
if err != nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return 0, err
}
d.bits |= uint32(c) << d.nBits
d.nBits += 8
}
u := d.bits & (1<<n - 1)
d.bits >>= n
d.nBits -= n
return u, nil
}
// decodeTransform decodes the next transform and the width of the image after
// transformation (or equivalently, before inverse transformation), specified
// in section 3.
func (d *decoder) decodeTransform(w int32, h int32) (t transform, newWidth int32, err error) {
t.oldWidth = w
t.transformType, err = d.read(2)
if err != nil {
return transform{}, 0, err
}
switch t.transformType {
case transformTypePredictor, transformTypeCrossColor:
t.bits, err = d.read(3)
if err != nil {
return transform{}, 0, err
}
t.bits += 2
t.pix, err = d.decodePix(nTiles(w, t.bits), nTiles(h, t.bits), 0, false)
if err != nil {
return transform{}, 0, err
}
case transformTypeSubtractGreen:
// No-op.
case transformTypeColorIndexing:
nColors, err := d.read(8)
if err != nil {
return transform{}, 0, err
}
nColors++
t.bits = 0
switch {
case nColors <= 2:
t.bits = 3
case nColors <= 4:
t.bits = 2
case nColors <= 16:
t.bits = 1
}
w = nTiles(w, t.bits)
pix, err := d.decodePix(int32(nColors), 1, 4*256, false)
if err != nil {
return transform{}, 0, err
}
for p := 4; p < len(pix); p += 4 {
pix[p+0] += pix[p-4]
pix[p+1] += pix[p-3]
pix[p+2] += pix[p-2]
pix[p+3] += pix[p-1]
}
// The spec says that "if the index is equal or larger than color_table_size,
// the argb color value should be set to 0x00000000 (transparent black)."
// We re-slice up to 256 4-byte pixels.
t.pix = pix[:4*256]
}
return t, w, nil
}
// repeatsCodeLength is the minimum code length for repeated codes.
const repeatsCodeLength = 16
// These magic numbers are specified at the end of section 5.2.2.
// The 3-length arrays apply to code lengths >= repeatsCodeLength.
var (
codeLengthCodeOrder = [19]uint8{
17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
}
repeatBits = [3]uint8{2, 3, 7}
repeatOffsets = [3]uint8{3, 3, 11}
)
// decodeCodeLengths decodes a Huffman tree's code lengths which are themselves
// encoded via a Huffman tree, specified in section 5.2.2.
func (d *decoder) decodeCodeLengths(dst []uint32, codeLengthCodeLengths []uint32) error {
h := hTree{}
if err := h.build(codeLengthCodeLengths); err != nil {
return err
}
maxSymbol := len(dst)
useLength, err := d.read(1)
if err != nil {
return err
}
if useLength != 0 {
n, err := d.read(3)
if err != nil {
return err
}
n = 2 + 2*n
ms, err := d.read(n)
if err != nil {
return err
}
maxSymbol = int(ms) + 2
if maxSymbol > len(dst) {
return errInvalidCodeLengths
}
}
// The spec says that "if code 16 [meaning repeat] is used before
// a non-zero value has been emitted, a value of 8 is repeated."
prevCodeLength := uint32(8)
for symbol := 0; symbol < len(dst); {
if maxSymbol == 0 {
break
}
maxSymbol--
codeLength, err := h.next(d)
if err != nil {
return err
}
if codeLength < repeatsCodeLength {
dst[symbol] = codeLength
symbol++
if codeLength != 0 {
prevCodeLength = codeLength
}
continue
}
repeat, err := d.read(uint32(repeatBits[codeLength-repeatsCodeLength]))
if err != nil {
return err
}
repeat += uint32(repeatOffsets[codeLength-repeatsCodeLength])
if symbol+int(repeat) > len(dst) {
return errInvalidCodeLengths
}
// A code length of 16 repeats the previous non-zero code.
// A code length of 17 or 18 repeats zeroes.
cl := uint32(0)
if codeLength == 16 {
cl = prevCodeLength
}
for ; repeat > 0; repeat-- {
dst[symbol] = cl
symbol++
}
}
return nil
}
// decodeHuffmanTree decodes a Huffman tree into h.
func (d *decoder) decodeHuffmanTree(h *hTree, alphabetSize uint32) error {
useSimple, err := d.read(1)
if err != nil {
return err
}
if useSimple != 0 {
nSymbols, err := d.read(1)
if err != nil {
return err
}
nSymbols++
firstSymbolLengthCode, err := d.read(1)
if err != nil {
return err
}
firstSymbolLengthCode = 7*firstSymbolLengthCode + 1
var symbols [2]uint32
symbols[0], err = d.read(firstSymbolLengthCode)
if err != nil {
return err
}
if nSymbols == 2 {
symbols[1], err = d.read(8)
if err != nil {
return err
}
}
return h.buildSimple(nSymbols, symbols, alphabetSize)
}
nCodes, err := d.read(4)
if err != nil {
return err
}
nCodes += 4
if int(nCodes) > len(codeLengthCodeOrder) {
return errInvalidHuffmanTree
}
codeLengthCodeLengths := [len(codeLengthCodeOrder)]uint32{}
for i := uint32(0); i < nCodes; i++ {
codeLengthCodeLengths[codeLengthCodeOrder[i]], err = d.read(3)
if err != nil {
return err
}
}
codeLengths := make([]uint32, alphabetSize)
if err = d.decodeCodeLengths(codeLengths, codeLengthCodeLengths[:]); err != nil {
return err
}
return h.build(codeLengths)
}
const (
huffGreen = 0
huffRed = 1
huffBlue = 2
huffAlpha = 3
huffDistance = 4
nHuff = 5
)
// hGroup is an array of 5 Huffman trees.
type hGroup [nHuff]hTree
// decodeHuffmanGroups decodes the one or more hGroups used to decode the pixel
// data. If one hGroup is used for the entire image, then hPix and hBits will
// be zero. If more than one hGroup is used, then hPix contains the meta-image
// that maps tiles to hGroup index, and hBits contains the log-2 tile size.
func (d *decoder) decodeHuffmanGroups(w int32, h int32, topLevel bool, ccBits uint32) (
hGroups []hGroup, hPix []byte, hBits uint32, err error) {
maxHGroupIndex := 0
if topLevel {
useMeta, err := d.read(1)
if err != nil {
return nil, nil, 0, err
}
if useMeta != 0 {
hBits, err = d.read(3)
if err != nil {
return nil, nil, 0, err
}
hBits += 2
hPix, err = d.decodePix(nTiles(w, hBits), nTiles(h, hBits), 0, false)
if err != nil {
return nil, nil, 0, err
}
for p := 0; p < len(hPix); p += 4 {
i := int(hPix[p])<<8 | int(hPix[p+1])
if maxHGroupIndex < i {
maxHGroupIndex = i
}
}
}
}
hGroups = make([]hGroup, maxHGroupIndex+1)
for i := range hGroups {
for j, alphabetSize := range alphabetSizes {
if j == 0 && ccBits > 0 {
alphabetSize += 1 << ccBits
}
if err := d.decodeHuffmanTree(&hGroups[i][j], alphabetSize); err != nil {
return nil, nil, 0, err
}
}
}
return hGroups, hPix, hBits, nil
}
const (
nLiteralCodes = 256
nLengthCodes = 24
nDistanceCodes = 40
)
var alphabetSizes = [nHuff]uint32{
nLiteralCodes + nLengthCodes,
nLiteralCodes,
nLiteralCodes,
nLiteralCodes,
nDistanceCodes,
}
// decodePix decodes pixel data, specified in section 5.2.2.
func (d *decoder) decodePix(w int32, h int32, minCap int32, topLevel bool) ([]byte, error) {
// Decode the color cache parameters.
ccBits, ccShift, ccEntries := uint32(0), uint32(0), ([]uint32)(nil)
useColorCache, err := d.read(1)
if err != nil {
return nil, err
}
if useColorCache != 0 {
ccBits, err = d.read(4)
if err != nil {
return nil, err
}
if ccBits < 1 || 11 < ccBits {
return nil, errors.New("vp8l: invalid color cache parameters")
}
ccShift = 32 - ccBits
ccEntries = make([]uint32, 1<<ccBits)
}
// Decode the Huffman groups.
hGroups, hPix, hBits, err := d.decodeHuffmanGroups(w, h, topLevel, ccBits)
if err != nil {
return nil, err
}
hMask, tilesPerRow := int32(0), int32(0)
if hBits != 0 {
hMask, tilesPerRow = 1<<hBits-1, nTiles(w, hBits)
}
// Decode the pixels.
if minCap < 4*w*h {
minCap = 4 * w * h
}
pix := make([]byte, 4*w*h, minCap)
p, cachedP := 0, 0
x, y := int32(0), int32(0)
hg, lookupHG := &hGroups[0], hMask != 0
for p < len(pix) {
if lookupHG {
i := 4 * (tilesPerRow*(y>>hBits) + (x >> hBits))
hg = &hGroups[uint32(hPix[i])<<8|uint32(hPix[i+1])]
}
green, err := hg[huffGreen].next(d)
if err != nil {
return nil, err
}
switch {
case green < nLiteralCodes:
// We have a literal pixel.
red, err := hg[huffRed].next(d)
if err != nil {
return nil, err
}
blue, err := hg[huffBlue].next(d)
if err != nil {
return nil, err
}
alpha, err := hg[huffAlpha].next(d)
if err != nil {
return nil, err
}
pix[p+0] = uint8(red)
pix[p+1] = uint8(green)
pix[p+2] = uint8(blue)
pix[p+3] = uint8(alpha)
p += 4
x++
if x == w {
x, y = 0, y+1
}
lookupHG = hMask != 0 && x&hMask == 0
case green < nLiteralCodes+nLengthCodes:
// We have a LZ77 backwards reference.
length, err := d.lz77Param(green - nLiteralCodes)
if err != nil {
return nil, err
}
distSym, err := hg[huffDistance].next(d)
if err != nil {
return nil, err
}
distCode, err := d.lz77Param(distSym)
if err != nil {
return nil, err
}
dist := distanceMap(w, distCode)
pEnd := p + 4*int(length)
q := p - 4*int(dist)
qEnd := pEnd - 4*int(dist)
if p < 0 || len(pix) < pEnd || q < 0 || len(pix) < qEnd {
return nil, errors.New("vp8l: invalid LZ77 parameters")
}
for ; p < pEnd; p, q = p+1, q+1 {
pix[p] = pix[q]
}
x += int32(length)
for x >= w {
x, y = x-w, y+1
}
lookupHG = hMask != 0
default:
// We have a color cache lookup. First, insert previous pixels
// into the cache. Note that VP8L assumes ARGB order, but the
// Go image.RGBA type is in RGBA order.
for ; cachedP < p; cachedP += 4 {
argb := uint32(pix[cachedP+0])<<16 |
uint32(pix[cachedP+1])<<8 |
uint32(pix[cachedP+2])<<0 |
uint32(pix[cachedP+3])<<24
ccEntries[(argb*colorCacheMultiplier)>>ccShift] = argb
}
green -= nLiteralCodes + nLengthCodes
if int(green) >= len(ccEntries) {
return nil, errors.New("vp8l: invalid color cache index")
}
argb := ccEntries[green]
pix[p+0] = uint8(argb >> 16)
pix[p+1] = uint8(argb >> 8)
pix[p+2] = uint8(argb >> 0)
pix[p+3] = uint8(argb >> 24)
p += 4
x++
if x == w {
x, y = 0, y+1
}
lookupHG = hMask != 0 && x&hMask == 0
}
}
return pix, nil
}
// lz77Param returns the next LZ77 parameter: a length or a distance, specified
// in section 4.2.2.
func (d *decoder) lz77Param(symbol uint32) (uint32, error) {
if symbol < 4 {
return symbol + 1, nil
}
extraBits := (symbol - 2) >> 1
offset := (2 + symbol&1) << extraBits
n, err := d.read(extraBits)
if err != nil {
return 0, err
}
return offset + n + 1, nil
}
// decodeHeader decodes the VP8L header from r.
func decodeHeader(r io.Reader) (d *decoder, w int32, h int32, err error) {
rr, ok := r.(io.ByteReader)
if !ok {
rr = bufio.NewReader(r)
}
d = &decoder{r: rr}
magic, err := d.read(8)
if err != nil {
return nil, 0, 0, err
}
if magic != 0x2f {
return nil, 0, 0, errors.New("vp8l: invalid header")
}
width, err := d.read(14)
if err != nil {
return nil, 0, 0, err
}
width++
height, err := d.read(14)
if err != nil {
return nil, 0, 0, err
}
height++
_, err = d.read(1) // Read and ignore the hasAlpha hint.
if err != nil {
return nil, 0, 0, err
}
version, err := d.read(3)
if err != nil {
return nil, 0, 0, err
}
if version != 0 {
return nil, 0, 0, errors.New("vp8l: invalid version")
}
return d, int32(width), int32(height), nil
}
// DecodeConfig decodes the color model and dimensions of a VP8L image from r.
func DecodeConfig(r io.Reader) (image.Config, error) {
_, w, h, err := decodeHeader(r)
if err != nil {
return image.Config{}, err
}
return image.Config{
ColorModel: color.NRGBAModel,
Width: int(w),
Height: int(h),
}, nil
}
// Decode decodes a VP8L image from r.
func Decode(r io.Reader) (image.Image, error) {
d, w, h, err := decodeHeader(r)
if err != nil {
return nil, err
}
// Decode the transforms.
var (
nTransforms int
transforms [nTransformTypes]transform
transformsSeen [nTransformTypes]bool
originalW = w
)
for {
more, err := d.read(1)
if err != nil {
return nil, err
}
if more == 0 {
break
}
var t transform
t, w, err = d.decodeTransform(w, h)
if err != nil {
return nil, err
}
if transformsSeen[t.transformType] {
return nil, errors.New("vp8l: repeated transform")
}
transformsSeen[t.transformType] = true
transforms[nTransforms] = t
nTransforms++
}
// Decode the transformed pixels.
pix, err := d.decodePix(w, h, 0, true)
if err != nil {
return nil, err
}
// Apply the inverse transformations.
for i := nTransforms - 1; i >= 0; i-- {
t := &transforms[i]
pix = inverseTransforms[t.transformType](t, pix, h)
}
return &image.NRGBA{
Pix: pix,
Stride: 4 * int(originalW),
Rect: image.Rect(0, 0, int(originalW), int(h)),
}, nil
}
// 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 vp8l
import (
"io"
)
// reverseBits reverses the bits in a byte.
var reverseBits = [256]uint8{
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
}
// hNode is a node in a Huffman tree.
type hNode struct {
// symbol is the symbol held by this node.
symbol uint32
// children, if positive, is the hTree.nodes index of the first of
// this node's two children. Zero means an uninitialized node,
// and -1 means a leaf node.
children int32
}
const leafNode = -1
// lutSize is the log-2 size of an hTree's look-up table.
const lutSize, lutMask = 7, 1<<7 - 1
// hTree is a Huffman tree.
type hTree struct {
// nodes are the nodes of the Huffman tree. During construction,
// len(nodes) grows from 1 up to cap(nodes) by steps of two.
// After construction, len(nodes) == cap(nodes), and both equal
// 2*theNumberOfSymbols - 1.
nodes []hNode
// lut is a look-up table for walking the nodes. The x in lut[x] is
// the next lutSize bits in the bit-stream. The low 8 bits of lut[x]
// equals 1 plus the number of bits in the next code, or 0 if the
// next code requires more than lutSize bits. The high 24 bits are:
// - the symbol, if the code requires lutSize or fewer bits, or
// - the hTree.nodes index to start the tree traversal from, if
// the next code requires more than lutSize bits.
lut [1 << lutSize]uint32
}
// insert inserts into the hTree a symbol whose encoding is the least
// significant codeLength bits of code.
func (h *hTree) insert(symbol uint32, code uint32, codeLength uint32) error {
if symbol > 0xffff || codeLength > 0xfe {
return errInvalidHuffmanTree
}
baseCode := uint32(0)
if codeLength > lutSize {
baseCode = uint32(reverseBits[(code>>(codeLength-lutSize))&0xff]) >> (8 - lutSize)
} else {
baseCode = uint32(reverseBits[code&0xff]) >> (8 - codeLength)
for i := 0; i < 1<<(lutSize-codeLength); i++ {
h.lut[baseCode|uint32(i)<<codeLength] = symbol<<8 | (codeLength + 1)
}
}
n := uint32(0)
for jump := lutSize; codeLength > 0; {
codeLength--
if int(n) > len(h.nodes) {
return errInvalidHuffmanTree
}
switch h.nodes[n].children {
case leafNode:
return errInvalidHuffmanTree
case 0:
if len(h.nodes) == cap(h.nodes) {
return errInvalidHuffmanTree
}
// Create two empty child nodes.
h.nodes[n].children = int32(len(h.nodes))
h.nodes = h.nodes[:len(h.nodes)+2]
}
n = uint32(h.nodes[n].children) + 1&(code>>codeLength)
jump--
if jump == 0 && h.lut[baseCode] == 0 {
h.lut[baseCode] = n << 8
}
}
switch h.nodes[n].children {
case leafNode:
// No-op.
case 0:
// Turn the uninitialized node into a leaf.
h.nodes[n].children = leafNode
default:
return errInvalidHuffmanTree
}
h.nodes[n].symbol = symbol
return nil
}
// codeLengthsToCodes returns the canonical Huffman codes implied by the
// sequence of code lengths.
func codeLengthsToCodes(codeLengths []uint32) ([]uint32, error) {
maxCodeLength := uint32(0)
for _, cl := range codeLengths {
if maxCodeLength < cl {
maxCodeLength = cl
}
}
const maxAllowedCodeLength = 15
if len(codeLengths) == 0 || maxCodeLength > maxAllowedCodeLength {
return nil, errInvalidHuffmanTree
}
histogram := [maxAllowedCodeLength + 1]uint32{}
for _, cl := range codeLengths {
histogram[cl]++
}
currCode, nextCodes := uint32(0), [maxAllowedCodeLength + 1]uint32{}
for cl := 1; cl < len(nextCodes); cl++ {
currCode = (currCode + histogram[cl-1]) << 1
nextCodes[cl] = currCode
}
codes := make([]uint32, len(codeLengths))
for symbol, cl := range codeLengths {
if cl > 0 {
codes[symbol] = nextCodes[cl]
nextCodes[cl]++
}
}
return codes, nil
}
// build builds a canonical Huffman tree from the given code lengths.
func (h *hTree) build(codeLengths []uint32) error {
// Calculate the number of symbols.
var nSymbols, lastSymbol uint32
for symbol, cl := range codeLengths {
if cl != 0 {
nSymbols++
lastSymbol = uint32(symbol)
}
}
if nSymbols == 0 {
return errInvalidHuffmanTree
}
h.nodes = make([]hNode, 1, 2*nSymbols-1)
// Handle the trivial case.
if nSymbols == 1 {
if len(codeLengths) <= int(lastSymbol) {
return errInvalidHuffmanTree
}
return h.insert(lastSymbol, 0, 0)
}
// Handle the non-trivial case.
codes, err := codeLengthsToCodes(codeLengths)
if err != nil {
return err
}
for symbol, cl := range codeLengths {
if cl > 0 {
if err := h.insert(uint32(symbol), codes[symbol], cl); err != nil {
return err
}
}
}
return nil
}
// buildSimple builds a Huffman tree with 1 or 2 symbols.
func (h *hTree) buildSimple(nSymbols uint32, symbols [2]uint32, alphabetSize uint32) error {
h.nodes = make([]hNode, 1, 2*nSymbols-1)
for i := uint32(0); i < nSymbols; i++ {
if symbols[i] >= alphabetSize {
return errInvalidHuffmanTree
}
if err := h.insert(symbols[i], i, nSymbols-1); err != nil {
return err
}
}
return nil
}
// next returns the next Huffman-encoded symbol from the bit-stream d.
func (h *hTree) next(d *decoder) (uint32, error) {
var n uint32
// Read enough bits so that we can use the look-up table.
if d.nBits < lutSize {
c, err := d.r.ReadByte()
if err != nil {
if err == io.EOF {
// There are no more bytes of data, but we may still be able
// to read the next symbol out of the previously read bits.
goto slowPath
}
return 0, err
}
d.bits |= uint32(c) << d.nBits
d.nBits += 8
}
// Use the look-up table.
n = h.lut[d.bits&lutMask]
if b := n & 0xff; b != 0 {
b--
d.bits >>= b
d.nBits -= b
return n >> 8, nil
}
n >>= 8
d.bits >>= lutSize
d.nBits -= lutSize
slowPath:
for h.nodes[n].children != leafNode {
if d.nBits == 0 {
c, err := d.r.ReadByte()
if err != nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return 0, err
}
d.bits = uint32(c)
d.nBits = 8
}
n = uint32(h.nodes[n].children) + 1&d.bits
d.bits >>= 1
d.nBits--
}
return h.nodes[n].symbol, nil
}
// 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 vp8l
// This file deals with image transforms, specified in section 3.
// nTiles returns the number of tiles needed to cover size pixels, where each
// tile's side is 1<<bits pixels long.
func nTiles(size int32, bits uint32) int32 {
return (size + 1<<bits - 1) >> bits
}
const (
transformTypePredictor = 0
transformTypeCrossColor = 1
transformTypeSubtractGreen = 2
transformTypeColorIndexing = 3
nTransformTypes = 4
)
// transform holds the parameters for an invertible transform.
type transform struct {
// transformType is the type of the transform.
transformType uint32
// oldWidth is the width of the image before transformation (or
// equivalently, after inverse transformation). The color-indexing
// transform can reduce the width. For example, a 50-pixel-wide
// image that only needs 4 bits (half a byte) per color index can
// be transformed into a 25-pixel-wide image.
oldWidth int32
// bits is the log-2 size of the transform's tiles, for the predictor
// and cross-color transforms. 8>>bits is the number of bits per
// color index, for the color-index transform.
bits uint32
// pix is the tile values, for the predictor and cross-color
// transforms, and the color palette, for the color-index transform.
pix []byte
}
var inverseTransforms = [nTransformTypes]func(*transform, []byte, int32) []byte{
transformTypePredictor: inversePredictor,
transformTypeCrossColor: inverseCrossColor,
transformTypeSubtractGreen: inverseSubtractGreen,
transformTypeColorIndexing: inverseColorIndexing,
}
func inversePredictor(t *transform, pix []byte, h int32) []byte {
if t.oldWidth == 0 || h == 0 {
return pix
}
// The first pixel's predictor is mode 0 (opaque black).
pix[3] += 0xff
p, mask := int32(4), int32(1)<<t.bits-1
for x := int32(1); x < t.oldWidth; x++ {
// The rest of the first row's predictor is mode 1 (L).
pix[p+0] += pix[p-4]
pix[p+1] += pix[p-3]
pix[p+2] += pix[p-2]
pix[p+3] += pix[p-1]
p += 4
}
top, tilesPerRow := 0, nTiles(t.oldWidth, t.bits)
for y := int32(1); y < h; y++ {
// The first column's predictor is mode 2 (T).
pix[p+0] += pix[top+0]
pix[p+1] += pix[top+1]
pix[p+2] += pix[top+2]
pix[p+3] += pix[top+3]
p, top = p+4, top+4
q := 4 * (y >> t.bits) * tilesPerRow
predictorMode := t.pix[q+1] & 0x0f
q += 4
for x := int32(1); x < t.oldWidth; x++ {
if x&mask == 0 {
predictorMode = t.pix[q+1] & 0x0f
q += 4
}
switch predictorMode {
case 0: // Opaque black.
pix[p+3] += 0xff
case 1: // L.
pix[p+0] += pix[p-4]
pix[p+1] += pix[p-3]
pix[p+2] += pix[p-2]
pix[p+3] += pix[p-1]
case 2: // T.
pix[p+0] += pix[top+0]
pix[p+1] += pix[top+1]
pix[p+2] += pix[top+2]
pix[p+3] += pix[top+3]
case 3: // TR.
pix[p+0] += pix[top+4]
pix[p+1] += pix[top+5]
pix[p+2] += pix[top+6]
pix[p+3] += pix[top+7]
case 4: // TL.
pix[p+0] += pix[top-4]
pix[p+1] += pix[top-3]
pix[p+2] += pix[top-2]
pix[p+3] += pix[top-1]
case 5: // Average2(Average2(L, TR), T).
pix[p+0] += avg2(avg2(pix[p-4], pix[top+4]), pix[top+0])
pix[p+1] += avg2(avg2(pix[p-3], pix[top+5]), pix[top+1])
pix[p+2] += avg2(avg2(pix[p-2], pix[top+6]), pix[top+2])
pix[p+3] += avg2(avg2(pix[p-1], pix[top+7]), pix[top+3])
case 6: // Average2(L, TL).
pix[p+0] += avg2(pix[p-4], pix[top-4])
pix[p+1] += avg2(pix[p-3], pix[top-3])
pix[p+2] += avg2(pix[p-2], pix[top-2])
pix[p+3] += avg2(pix[p-1], pix[top-1])
case 7: // Average2(L, T).
pix[p+0] += avg2(pix[p-4], pix[top+0])
pix[p+1] += avg2(pix[p-3], pix[top+1])
pix[p+2] += avg2(pix[p-2], pix[top+2])
pix[p+3] += avg2(pix[p-1], pix[top+3])
case 8: // Average2(TL, T).
pix[p+0] += avg2(pix[top-4], pix[top+0])
pix[p+1] += avg2(pix[top-3], pix[top+1])
pix[p+2] += avg2(pix[top-2], pix[top+2])
pix[p+3] += avg2(pix[top-1], pix[top+3])
case 9: // Average2(T, TR).
pix[p+0] += avg2(pix[top+0], pix[top+4])
pix[p+1] += avg2(pix[top+1], pix[top+5])
pix[p+2] += avg2(pix[top+2], pix[top+6])
pix[p+3] += avg2(pix[top+3], pix[top+7])
case 10: // Average2(Average2(L, TL), Average2(T, TR)).
pix[p+0] += avg2(avg2(pix[p-4], pix[top-4]), avg2(pix[top+0], pix[top+4]))
pix[p+1] += avg2(avg2(pix[p-3], pix[top-3]), avg2(pix[top+1], pix[top+5]))
pix[p+2] += avg2(avg2(pix[p-2], pix[top-2]), avg2(pix[top+2], pix[top+6]))
pix[p+3] += avg2(avg2(pix[p-1], pix[top-1]), avg2(pix[top+3], pix[top+7]))
case 11: // Select(L, T, TL).
l0 := int32(pix[p-4])
l1 := int32(pix[p-3])
l2 := int32(pix[p-2])
l3 := int32(pix[p-1])
c0 := int32(pix[top-4])
c1 := int32(pix[top-3])
c2 := int32(pix[top-2])
c3 := int32(pix[top-1])
t0 := int32(pix[top+0])
t1 := int32(pix[top+1])
t2 := int32(pix[top+2])
t3 := int32(pix[top+3])
l := abs(c0-t0) + abs(c1-t1) + abs(c2-t2) + abs(c3-t3)
t := abs(c0-l0) + abs(c1-l1) + abs(c2-l2) + abs(c3-l3)
if l < t {
pix[p+0] += uint8(l0)
pix[p+1] += uint8(l1)
pix[p+2] += uint8(l2)
pix[p+3] += uint8(l3)
} else {
pix[p+0] += uint8(t0)
pix[p+1] += uint8(t1)
pix[p+2] += uint8(t2)
pix[p+3] += uint8(t3)
}
case 12: // ClampAddSubtractFull(L, T, TL).
pix[p+0] += clampAddSubtractFull(pix[p-4], pix[top+0], pix[top-4])
pix[p+1] += clampAddSubtractFull(pix[p-3], pix[top+1], pix[top-3])
pix[p+2] += clampAddSubtractFull(pix[p-2], pix[top+2], pix[top-2])
pix[p+3] += clampAddSubtractFull(pix[p-1], pix[top+3], pix[top-1])
case 13: // ClampAddSubtractHalf(Average2(L, T), TL).
pix[p+0] += clampAddSubtractHalf(avg2(pix[p-4], pix[top+0]), pix[top-4])
pix[p+1] += clampAddSubtractHalf(avg2(pix[p-3], pix[top+1]), pix[top-3])
pix[p+2] += clampAddSubtractHalf(avg2(pix[p-2], pix[top+2]), pix[top-2])
pix[p+3] += clampAddSubtractHalf(avg2(pix[p-1], pix[top+3]), pix[top-1])
}
p, top = p+4, top+4
}
}
return pix
}
func inverseCrossColor(t *transform, pix []byte, h int32) []byte {
var greenToRed, greenToBlue, redToBlue int32
p, mask, tilesPerRow := int32(0), int32(1)<<t.bits-1, nTiles(t.oldWidth, t.bits)
for y := int32(0); y < h; y++ {
q := 4 * (y >> t.bits) * tilesPerRow
for x := int32(0); x < t.oldWidth; x++ {
if x&mask == 0 {
redToBlue = int32(int8(t.pix[q+0]))
greenToBlue = int32(int8(t.pix[q+1]))
greenToRed = int32(int8(t.pix[q+2]))
q += 4
}
red := pix[p+0]
green := pix[p+1]
blue := pix[p+2]
red += uint8(uint32(greenToRed*int32(int8(green))) >> 5)
blue += uint8(uint32(greenToBlue*int32(int8(green))) >> 5)
blue += uint8(uint32(redToBlue*int32(int8(red))) >> 5)
pix[p+0] = red
pix[p+2] = blue
p += 4
}
}
return pix
}
func inverseSubtractGreen(t *transform, pix []byte, h int32) []byte {
for p := 0; p < len(pix); p += 4 {
green := pix[p+1]
pix[p+0] += green
pix[p+2] += green
}
return pix
}
func inverseColorIndexing(t *transform, pix []byte, h int32) []byte {
if t.bits == 0 {
for p := 0; p < len(pix); p += 4 {
i := 4 * uint32(pix[p+1])
pix[p+0] = t.pix[i+0]
pix[p+1] = t.pix[i+1]
pix[p+2] = t.pix[i+2]
pix[p+3] = t.pix[i+3]
}
return pix
}
vMask, xMask, bitsPerPixel := uint32(0), int32(0), uint32(8>>t.bits)
switch t.bits {
case 1:
vMask, xMask = 0x0f, 0x01
case 2:
vMask, xMask = 0x03, 0x03
case 3:
vMask, xMask = 0x01, 0x07
}
d, p, v, dst := 0, 0, uint32(0), make([]byte, 4*t.oldWidth*h)
for y := int32(0); y < h; y++ {
for x := int32(0); x < t.oldWidth; x++ {
if x&xMask == 0 {
v = uint32(pix[p+1])
p += 4
}
i := 4 * (v & vMask)
dst[d+0] = t.pix[i+0]
dst[d+1] = t.pix[i+1]
dst[d+2] = t.pix[i+2]
dst[d+3] = t.pix[i+3]
d += 4
v >>= bitsPerPixel
}
}
return dst
}
func abs(x int32) int32 {
if x < 0 {
return -x
}
return x
}
func avg2(a, b uint8) uint8 {
return uint8((int32(a) + int32(b)) / 2)
}
func clampAddSubtractFull(a, b, c uint8) uint8 {
x := int32(a) + int32(b) - int32(c)
if x < 0 {
return 0
}
if x > 255 {
return 255
}
return uint8(x)
}
func clampAddSubtractHalf(a, b uint8) uint8 {
x := int32(a) + (int32(a)-int32(b))/2
if x < 0 {
return 0
}
if x > 255 {
return 255
}
return uint8(x)
}
// Copyright 2011 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 webp
import (
"bytes"
"errors"
"image"
"image/color"
"io"
"golang.org/x/image/riff"
"golang.org/x/image/vp8"
"golang.org/x/image/vp8l"
)
var errInvalidFormat = errors.New("webp: invalid format")
var (
fccALPH = riff.FourCC{'A', 'L', 'P', 'H'}
fccVP8 = riff.FourCC{'V', 'P', '8', ' '}
fccVP8L = riff.FourCC{'V', 'P', '8', 'L'}
fccVP8X = riff.FourCC{'V', 'P', '8', 'X'}
fccWEBP = riff.FourCC{'W', 'E', 'B', 'P'}
)
func decode(r io.Reader, configOnly bool) (image.Image, image.Config, error) {
formType, riffReader, err := riff.NewReader(r)
if err != nil {
return nil, image.Config{}, err
}
if formType != fccWEBP {
return nil, image.Config{}, errInvalidFormat
}
var (
alpha []byte
alphaStride int
wantAlpha bool
seenVP8X bool
widthMinusOne uint32
heightMinusOne uint32
buf [10]byte
)
for {
chunkID, chunkLen, chunkData, err := riffReader.Next()
if err == io.EOF {
err = errInvalidFormat
}
if err != nil {
return nil, image.Config{}, err
}
switch chunkID {
case fccALPH:
if !wantAlpha {
return nil, image.Config{}, errInvalidFormat
}
wantAlpha = false
// Read the Pre-processing | Filter | Compression byte.
if _, err := io.ReadFull(chunkData, buf[:1]); err != nil {
if err == io.EOF {
err = errInvalidFormat
}
return nil, image.Config{}, err
}
alpha, alphaStride, err = readAlpha(chunkData, widthMinusOne, heightMinusOne, buf[0]&0x03)
if err != nil {
return nil, image.Config{}, err
}
unfilterAlpha(alpha, alphaStride, (buf[0]>>2)&0x03)
case fccVP8:
if wantAlpha || int32(chunkLen) < 0 {
return nil, image.Config{}, errInvalidFormat
}
d := vp8.NewDecoder()
d.Init(chunkData, int(chunkLen))
fh, err := d.DecodeFrameHeader()
if err != nil {
return nil, image.Config{}, err
}
if configOnly {
return nil, image.Config{
ColorModel: color.YCbCrModel,
Width: fh.Width,
Height: fh.Height,
}, nil
}
m, err := d.DecodeFrame()
if err != nil {
return nil, image.Config{}, err
}
if alpha != nil {
return &image.NYCbCrA{
YCbCr: *m,
A: alpha,
AStride: alphaStride,
}, image.Config{}, nil
}
return m, image.Config{}, nil
case fccVP8L:
if wantAlpha || alpha != nil {
return nil, image.Config{}, errInvalidFormat
}
if configOnly {
c, err := vp8l.DecodeConfig(chunkData)
return nil, c, err
}
m, err := vp8l.Decode(chunkData)
return m, image.Config{}, err
case fccVP8X:
if seenVP8X {
return nil, image.Config{}, errInvalidFormat
}
seenVP8X = true
if chunkLen != 10 {
return nil, image.Config{}, errInvalidFormat
}
if _, err := io.ReadFull(chunkData, buf[:10]); err != nil {
return nil, image.Config{}, err
}
const (
animationBit = 1 << 1
xmpMetadataBit = 1 << 2
exifMetadataBit = 1 << 3
alphaBit = 1 << 4
iccProfileBit = 1 << 5
)
wantAlpha = (buf[0] & alphaBit) != 0
widthMinusOne = uint32(buf[4]) | uint32(buf[5])<<8 | uint32(buf[6])<<16
heightMinusOne = uint32(buf[7]) | uint32(buf[8])<<8 | uint32(buf[9])<<16
if configOnly {
if wantAlpha {
return nil, image.Config{
ColorModel: color.NYCbCrAModel,
Width: int(widthMinusOne) + 1,
Height: int(heightMinusOne) + 1,
}, nil
}
return nil, image.Config{
ColorModel: color.YCbCrModel,
Width: int(widthMinusOne) + 1,
Height: int(heightMinusOne) + 1,
}, nil
}
}
}
}
func readAlpha(chunkData io.Reader, widthMinusOne, heightMinusOne uint32, compression byte) (
alpha []byte, alphaStride int, err error) {
switch compression {
case 0:
w := int(widthMinusOne) + 1
h := int(heightMinusOne) + 1
alpha = make([]byte, w*h)
if _, err := io.ReadFull(chunkData, alpha); err != nil {
return nil, 0, err
}
return alpha, w, nil
case 1:
// Read the VP8L-compressed alpha values. First, synthesize a 5-byte VP8L header:
// a 1-byte magic number, a 14-bit widthMinusOne, a 14-bit heightMinusOne,
// a 1-bit (ignored, zero) alphaIsUsed and a 3-bit (zero) version.
// TODO(nigeltao): be more efficient than decoding an *image.NRGBA just to
// extract the green values to a separately allocated []byte. Fixing this
// will require changes to the vp8l package's API.
if widthMinusOne > 0x3fff || heightMinusOne > 0x3fff {
return nil, 0, errors.New("webp: invalid format")
}
alphaImage, err := vp8l.Decode(io.MultiReader(
bytes.NewReader([]byte{
0x2f, // VP8L magic number.
uint8(widthMinusOne),
uint8(widthMinusOne>>8) | uint8(heightMinusOne<<6),
uint8(heightMinusOne >> 2),
uint8(heightMinusOne >> 10),
}),
chunkData,
))
if err != nil {
return nil, 0, err
}
// The green values of the inner NRGBA image are the alpha values of the
// outer NYCbCrA image.
pix := alphaImage.(*image.NRGBA).Pix
alpha = make([]byte, len(pix)/4)
for i := range alpha {
alpha[i] = pix[4*i+1]
}
return alpha, int(widthMinusOne) + 1, nil
}
return nil, 0, errInvalidFormat
}
func unfilterAlpha(alpha []byte, alphaStride int, filter byte) {
if len(alpha) == 0 || alphaStride == 0 {
return
}
switch filter {
case 1: // Horizontal filter.
for i := 1; i < alphaStride; i++ {
alpha[i] += alpha[i-1]
}
for i := alphaStride; i < len(alpha); i += alphaStride {
// The first column is equivalent to the vertical filter.
alpha[i] += alpha[i-alphaStride]
for j := 1; j < alphaStride; j++ {
alpha[i+j] += alpha[i+j-1]
}
}
case 2: // Vertical filter.
// The first row is equivalent to the horizontal filter.
for i := 1; i < alphaStride; i++ {
alpha[i] += alpha[i-1]
}
for i := alphaStride; i < len(alpha); i++ {
alpha[i] += alpha[i-alphaStride]
}
case 3: // Gradient filter.
// The first row is equivalent to the horizontal filter.
for i := 1; i < alphaStride; i++ {
alpha[i] += alpha[i-1]
}
for i := alphaStride; i < len(alpha); i += alphaStride {
// The first column is equivalent to the vertical filter.
alpha[i] += alpha[i-alphaStride]
// The interior is predicted on the three top/left pixels.
for j := 1; j < alphaStride; j++ {
c := int(alpha[i+j-alphaStride-1])
b := int(alpha[i+j-alphaStride])
a := int(alpha[i+j-1])
x := a + b - c
if x < 0 {
x = 0
} else if x > 255 {
x = 255
}
alpha[i+j] += uint8(x)
}
}
}
}
// Decode reads a WEBP image from r and returns it as an image.Image.
func Decode(r io.Reader) (image.Image, error) {
m, _, err := decode(r, false)
if err != nil {
return nil, err
}
return m, nil
}
// DecodeConfig returns the color model and dimensions of a WEBP image without
// decoding the entire image.
func DecodeConfig(r io.Reader) (image.Config, error) {
_, c, err := decode(r, true)
return c, err
}
func init() {
image.RegisterFormat("webp", "RIFF????WEBPVP8", Decode, DecodeConfig)
}
// 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.
package bpf
import "fmt"
// Assemble converts insts into raw instructions suitable for loading
// into a BPF virtual machine.
//
// Currently, no optimization is attempted, the assembled program flow
// is exactly as provided.
func Assemble(insts []Instruction) ([]RawInstruction, error) {
ret := make([]RawInstruction, len(insts))
var err error
for i, inst := range insts {
ret[i], err = inst.Assemble()
if err != nil {
return nil, fmt.Errorf("assembling instruction %d: %s", i+1, err)
}
}
return ret, nil
}
// Disassemble attempts to parse raw back into
// Instructions. Unrecognized RawInstructions are assumed to be an
// extension not implemented by this package, and are passed through
// unchanged to the output. The allDecoded value reports whether insts
// contains no RawInstructions.
func Disassemble(raw []RawInstruction) (insts []Instruction, allDecoded bool) {
insts = make([]Instruction, len(raw))
allDecoded = true
for i, r := range raw {
insts[i] = r.Disassemble()
if _, ok := insts[i].(RawInstruction); ok {
allDecoded = false
}
}
return insts, allDecoded
}
// 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.
package bpf
import "fmt"
// An Instruction is one instruction executed by the BPF virtual
// machine.
type Instruction interface {
// Assemble assembles the Instruction into a RawInstruction.
Assemble() (RawInstruction, error)
}
// A RawInstruction is a raw BPF virtual machine instruction.
type RawInstruction struct {
// Operation to execute.
Op uint16
// For conditional jump instructions, the number of instructions
// to skip if the condition is true/false.
Jt uint8
Jf uint8
// Constant parameter. The meaning depends on the Op.
K uint32
}
// Assemble implements the Instruction Assemble method.
func (ri RawInstruction) Assemble() (RawInstruction, error) { return ri, nil }
// Disassemble parses ri into an Instruction and returns it. If ri is
// not recognized by this package, ri itself is returned.
func (ri RawInstruction) Disassemble() Instruction {
switch ri.Op & opMaskCls {
case opClsLoadA, opClsLoadX:
reg := Register(ri.Op & opMaskLoadDest)
sz := 0
switch ri.Op & opMaskLoadWidth {
case opLoadWidth4:
sz = 4
case opLoadWidth2:
sz = 2
case opLoadWidth1:
sz = 1
default:
return ri
}
switch ri.Op & opMaskLoadMode {
case opAddrModeImmediate:
if sz != 4 {
return ri
}
return LoadConstant{Dst: reg, Val: ri.K}
case opAddrModeScratch:
if sz != 4 || ri.K > 15 {
return ri
}
return LoadScratch{Dst: reg, N: int(ri.K)}
case opAddrModeAbsolute:
if ri.K > extOffset+0xffffffff {
return LoadExtension{Num: Extension(-extOffset + ri.K)}
}
return LoadAbsolute{Size: sz, Off: ri.K}
case opAddrModeIndirect:
return LoadIndirect{Size: sz, Off: ri.K}
case opAddrModePacketLen:
if sz != 4 {
return ri
}
return LoadExtension{Num: ExtLen}
case opAddrModeMemShift:
return LoadMemShift{Off: ri.K}
default:
return ri
}
case opClsStoreA:
if ri.Op != opClsStoreA || ri.K > 15 {
return ri
}
return StoreScratch{Src: RegA, N: int(ri.K)}
case opClsStoreX:
if ri.Op != opClsStoreX || ri.K > 15 {
return ri
}
return StoreScratch{Src: RegX, N: int(ri.K)}
case opClsALU:
switch op := ALUOp(ri.Op & opMaskOperator); op {
case ALUOpAdd, ALUOpSub, ALUOpMul, ALUOpDiv, ALUOpOr, ALUOpAnd, ALUOpShiftLeft, ALUOpShiftRight, ALUOpMod, ALUOpXor:
switch operand := opOperand(ri.Op & opMaskOperand); operand {
case opOperandX:
return ALUOpX{Op: op}
case opOperandConstant:
return ALUOpConstant{Op: op, Val: ri.K}
default:
return ri
}
case aluOpNeg:
return NegateA{}
default:
return ri
}
case opClsJump:
switch op := jumpOp(ri.Op & opMaskOperator); op {
case opJumpAlways:
return Jump{Skip: ri.K}
case opJumpEqual, opJumpGT, opJumpGE, opJumpSet:
cond, skipTrue, skipFalse := jumpOpToTest(op, ri.Jt, ri.Jf)
switch operand := opOperand(ri.Op & opMaskOperand); operand {
case opOperandX:
return JumpIfX{Cond: cond, SkipTrue: skipTrue, SkipFalse: skipFalse}
case opOperandConstant:
return JumpIf{Cond: cond, Val: ri.K, SkipTrue: skipTrue, SkipFalse: skipFalse}
default:
return ri
}
default:
return ri
}
case opClsReturn:
switch ri.Op {
case opClsReturn | opRetSrcA:
return RetA{}
case opClsReturn | opRetSrcConstant:
return RetConstant{Val: ri.K}
default:
return ri
}
case opClsMisc:
switch ri.Op {
case opClsMisc | opMiscTAX:
return TAX{}
case opClsMisc | opMiscTXA:
return TXA{}
default:
return ri
}
default:
panic("unreachable") // switch is exhaustive on the bit pattern
}
}
func jumpOpToTest(op jumpOp, skipTrue uint8, skipFalse uint8) (JumpTest, uint8, uint8) {
var test JumpTest
// Decode "fake" jump conditions that don't appear in machine code
// Ensures the Assemble -> Disassemble stage recreates the same instructions
// See https://github.com/golang/go/issues/18470
if skipTrue == 0 {
switch op {
case opJumpEqual:
test = JumpNotEqual
case opJumpGT:
test = JumpLessOrEqual
case opJumpGE:
test = JumpLessThan
case opJumpSet:
test = JumpBitsNotSet
}
return test, skipFalse, 0
}
switch op {
case opJumpEqual:
test = JumpEqual
case opJumpGT:
test = JumpGreaterThan
case opJumpGE:
test = JumpGreaterOrEqual
case opJumpSet:
test = JumpBitsSet
}
return test, skipTrue, skipFalse
}
// LoadConstant loads Val into register Dst.
type LoadConstant struct {
Dst Register
Val uint32
}
// Assemble implements the Instruction Assemble method.
func (a LoadConstant) Assemble() (RawInstruction, error) {
return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val)
}
// String returns the instruction in assembler notation.
func (a LoadConstant) String() string {
switch a.Dst {
case RegA:
return fmt.Sprintf("ld #%d", a.Val)
case RegX:
return fmt.Sprintf("ldx #%d", a.Val)
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// LoadScratch loads scratch[N] into register Dst.
type LoadScratch struct {
Dst Register
N int // 0-15
}
// Assemble implements the Instruction Assemble method.
func (a LoadScratch) Assemble() (RawInstruction, error) {
if a.N < 0 || a.N > 15 {
return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
}
return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N))
}
// String returns the instruction in assembler notation.
func (a LoadScratch) String() string {
switch a.Dst {
case RegA:
return fmt.Sprintf("ld M[%d]", a.N)
case RegX:
return fmt.Sprintf("ldx M[%d]", a.N)
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// LoadAbsolute loads packet[Off:Off+Size] as an integer value into
// register A.
type LoadAbsolute struct {
Off uint32
Size int // 1, 2 or 4
}
// Assemble implements the Instruction Assemble method.
func (a LoadAbsolute) Assemble() (RawInstruction, error) {
return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off)
}
// String returns the instruction in assembler notation.
func (a LoadAbsolute) String() string {
switch a.Size {
case 1: // byte
return fmt.Sprintf("ldb [%d]", a.Off)
case 2: // half word
return fmt.Sprintf("ldh [%d]", a.Off)
case 4: // word
if a.Off > extOffset+0xffffffff {
return LoadExtension{Num: Extension(a.Off + 0x1000)}.String()
}
return fmt.Sprintf("ld [%d]", a.Off)
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// LoadIndirect loads packet[X+Off:X+Off+Size] as an integer value
// into register A.
type LoadIndirect struct {
Off uint32
Size int // 1, 2 or 4
}
// Assemble implements the Instruction Assemble method.
func (a LoadIndirect) Assemble() (RawInstruction, error) {
return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off)
}
// String returns the instruction in assembler notation.
func (a LoadIndirect) String() string {
switch a.Size {
case 1: // byte
return fmt.Sprintf("ldb [x + %d]", a.Off)
case 2: // half word
return fmt.Sprintf("ldh [x + %d]", a.Off)
case 4: // word
return fmt.Sprintf("ld [x + %d]", a.Off)
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// LoadMemShift multiplies the first 4 bits of the byte at packet[Off]
// by 4 and stores the result in register X.
//
// This instruction is mainly useful to load into X the length of an
// IPv4 packet header in a single instruction, rather than have to do
// the arithmetic on the header's first byte by hand.
type LoadMemShift struct {
Off uint32
}
// Assemble implements the Instruction Assemble method.
func (a LoadMemShift) Assemble() (RawInstruction, error) {
return assembleLoad(RegX, 1, opAddrModeMemShift, a.Off)
}
// String returns the instruction in assembler notation.
func (a LoadMemShift) String() string {
return fmt.Sprintf("ldx 4*([%d]&0xf)", a.Off)
}
// LoadExtension invokes a linux-specific extension and stores the
// result in register A.
type LoadExtension struct {
Num Extension
}
// Assemble implements the Instruction Assemble method.
func (a LoadExtension) Assemble() (RawInstruction, error) {
if a.Num == ExtLen {
return assembleLoad(RegA, 4, opAddrModePacketLen, 0)
}
return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(extOffset+a.Num))
}
// String returns the instruction in assembler notation.
func (a LoadExtension) String() string {
switch a.Num {
case ExtLen:
return "ld #len"
case ExtProto:
return "ld #proto"
case ExtType:
return "ld #type"
case ExtPayloadOffset:
return "ld #poff"
case ExtInterfaceIndex:
return "ld #ifidx"
case ExtNetlinkAttr:
return "ld #nla"
case ExtNetlinkAttrNested:
return "ld #nlan"
case ExtMark:
return "ld #mark"
case ExtQueue:
return "ld #queue"
case ExtLinkLayerType:
return "ld #hatype"
case ExtRXHash:
return "ld #rxhash"
case ExtCPUID:
return "ld #cpu"
case ExtVLANTag:
return "ld #vlan_tci"
case ExtVLANTagPresent:
return "ld #vlan_avail"
case ExtVLANProto:
return "ld #vlan_tpid"
case ExtRand:
return "ld #rand"
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// StoreScratch stores register Src into scratch[N].
type StoreScratch struct {
Src Register
N int // 0-15
}
// Assemble implements the Instruction Assemble method.
func (a StoreScratch) Assemble() (RawInstruction, error) {
if a.N < 0 || a.N > 15 {
return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
}
var op uint16
switch a.Src {
case RegA:
op = opClsStoreA
case RegX:
op = opClsStoreX
default:
return RawInstruction{}, fmt.Errorf("invalid source register %v", a.Src)
}
return RawInstruction{
Op: op,
K: uint32(a.N),
}, nil
}
// String returns the instruction in assembler notation.
func (a StoreScratch) String() string {
switch a.Src {
case RegA:
return fmt.Sprintf("st M[%d]", a.N)
case RegX:
return fmt.Sprintf("stx M[%d]", a.N)
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// ALUOpConstant executes A = A <Op> Val.
type ALUOpConstant struct {
Op ALUOp
Val uint32
}
// Assemble implements the Instruction Assemble method.
func (a ALUOpConstant) Assemble() (RawInstruction, error) {
return RawInstruction{
Op: opClsALU | uint16(opOperandConstant) | uint16(a.Op),
K: a.Val,
}, nil
}
// String returns the instruction in assembler notation.
func (a ALUOpConstant) String() string {
switch a.Op {
case ALUOpAdd:
return fmt.Sprintf("add #%d", a.Val)
case ALUOpSub:
return fmt.Sprintf("sub #%d", a.Val)
case ALUOpMul:
return fmt.Sprintf("mul #%d", a.Val)
case ALUOpDiv:
return fmt.Sprintf("div #%d", a.Val)
case ALUOpMod:
return fmt.Sprintf("mod #%d", a.Val)
case ALUOpAnd:
return fmt.Sprintf("and #%d", a.Val)
case ALUOpOr:
return fmt.Sprintf("or #%d", a.Val)
case ALUOpXor:
return fmt.Sprintf("xor #%d", a.Val)
case ALUOpShiftLeft:
return fmt.Sprintf("lsh #%d", a.Val)
case ALUOpShiftRight:
return fmt.Sprintf("rsh #%d", a.Val)
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// ALUOpX executes A = A <Op> X
type ALUOpX struct {
Op ALUOp
}
// Assemble implements the Instruction Assemble method.
func (a ALUOpX) Assemble() (RawInstruction, error) {
return RawInstruction{
Op: opClsALU | uint16(opOperandX) | uint16(a.Op),
}, nil
}
// String returns the instruction in assembler notation.
func (a ALUOpX) String() string {
switch a.Op {
case ALUOpAdd:
return "add x"
case ALUOpSub:
return "sub x"
case ALUOpMul:
return "mul x"
case ALUOpDiv:
return "div x"
case ALUOpMod:
return "mod x"
case ALUOpAnd:
return "and x"
case ALUOpOr:
return "or x"
case ALUOpXor:
return "xor x"
case ALUOpShiftLeft:
return "lsh x"
case ALUOpShiftRight:
return "rsh x"
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// NegateA executes A = -A.
type NegateA struct{}
// Assemble implements the Instruction Assemble method.
func (a NegateA) Assemble() (RawInstruction, error) {
return RawInstruction{
Op: opClsALU | uint16(aluOpNeg),
}, nil
}
// String returns the instruction in assembler notation.
func (a NegateA) String() string {
return fmt.Sprintf("neg")
}
// Jump skips the following Skip instructions in the program.
type Jump struct {
Skip uint32
}
// Assemble implements the Instruction Assemble method.
func (a Jump) Assemble() (RawInstruction, error) {
return RawInstruction{
Op: opClsJump | uint16(opJumpAlways),
K: a.Skip,
}, nil
}
// String returns the instruction in assembler notation.
func (a Jump) String() string {
return fmt.Sprintf("ja %d", a.Skip)
}
// JumpIf skips the following Skip instructions in the program if A
// <Cond> Val is true.
type JumpIf struct {
Cond JumpTest
Val uint32
SkipTrue uint8
SkipFalse uint8
}
// Assemble implements the Instruction Assemble method.
func (a JumpIf) Assemble() (RawInstruction, error) {
return jumpToRaw(a.Cond, opOperandConstant, a.Val, a.SkipTrue, a.SkipFalse)
}
// String returns the instruction in assembler notation.
func (a JumpIf) String() string {
return jumpToString(a.Cond, fmt.Sprintf("#%d", a.Val), a.SkipTrue, a.SkipFalse)
}
// JumpIfX skips the following Skip instructions in the program if A
// <Cond> X is true.
type JumpIfX struct {
Cond JumpTest
SkipTrue uint8
SkipFalse uint8
}
// Assemble implements the Instruction Assemble method.
func (a JumpIfX) Assemble() (RawInstruction, error) {
return jumpToRaw(a.Cond, opOperandX, 0, a.SkipTrue, a.SkipFalse)
}
// String returns the instruction in assembler notation.
func (a JumpIfX) String() string {
return jumpToString(a.Cond, "x", a.SkipTrue, a.SkipFalse)
}
// jumpToRaw assembles a jump instruction into a RawInstruction
func jumpToRaw(test JumpTest, operand opOperand, k uint32, skipTrue, skipFalse uint8) (RawInstruction, error) {
var (
cond jumpOp
flip bool
)
switch test {
case JumpEqual:
cond = opJumpEqual
case JumpNotEqual:
cond, flip = opJumpEqual, true
case JumpGreaterThan:
cond = opJumpGT
case JumpLessThan:
cond, flip = opJumpGE, true
case JumpGreaterOrEqual:
cond = opJumpGE
case JumpLessOrEqual:
cond, flip = opJumpGT, true
case JumpBitsSet:
cond = opJumpSet
case JumpBitsNotSet:
cond, flip = opJumpSet, true
default:
return RawInstruction{}, fmt.Errorf("unknown JumpTest %v", test)
}
jt, jf := skipTrue, skipFalse
if flip {
jt, jf = jf, jt
}
return RawInstruction{
Op: opClsJump | uint16(cond) | uint16(operand),
Jt: jt,
Jf: jf,
K: k,
}, nil
}
// jumpToString converts a jump instruction to assembler notation
func jumpToString(cond JumpTest, operand string, skipTrue, skipFalse uint8) string {
switch cond {
// K == A
case JumpEqual:
return conditionalJump(operand, skipTrue, skipFalse, "jeq", "jneq")
// K != A
case JumpNotEqual:
return fmt.Sprintf("jneq %s,%d", operand, skipTrue)
// K > A
case JumpGreaterThan:
return conditionalJump(operand, skipTrue, skipFalse, "jgt", "jle")
// K < A
case JumpLessThan:
return fmt.Sprintf("jlt %s,%d", operand, skipTrue)
// K >= A
case JumpGreaterOrEqual:
return conditionalJump(operand, skipTrue, skipFalse, "jge", "jlt")
// K <= A
case JumpLessOrEqual:
return fmt.Sprintf("jle %s,%d", operand, skipTrue)
// K & A != 0
case JumpBitsSet:
if skipFalse > 0 {
return fmt.Sprintf("jset %s,%d,%d", operand, skipTrue, skipFalse)
}
return fmt.Sprintf("jset %s,%d", operand, skipTrue)
// K & A == 0, there is no assembler instruction for JumpBitNotSet, use JumpBitSet and invert skips
case JumpBitsNotSet:
return jumpToString(JumpBitsSet, operand, skipFalse, skipTrue)
default:
return fmt.Sprintf("unknown JumpTest %#v", cond)
}
}
func conditionalJump(operand string, skipTrue, skipFalse uint8, positiveJump, negativeJump string) string {
if skipTrue > 0 {
if skipFalse > 0 {
return fmt.Sprintf("%s %s,%d,%d", positiveJump, operand, skipTrue, skipFalse)
}
return fmt.Sprintf("%s %s,%d", positiveJump, operand, skipTrue)
}
return fmt.Sprintf("%s %s,%d", negativeJump, operand, skipFalse)
}
// RetA exits the BPF program, returning the value of register A.
type RetA struct{}
// Assemble implements the Instruction Assemble method.
func (a RetA) Assemble() (RawInstruction, error) {
return RawInstruction{
Op: opClsReturn | opRetSrcA,
}, nil
}
// String returns the instruction in assembler notation.
func (a RetA) String() string {
return fmt.Sprintf("ret a")
}
// RetConstant exits the BPF program, returning a constant value.
type RetConstant struct {
Val uint32
}
// Assemble implements the Instruction Assemble method.
func (a RetConstant) Assemble() (RawInstruction, error) {
return RawInstruction{
Op: opClsReturn | opRetSrcConstant,
K: a.Val,
}, nil
}
// String returns the instruction in assembler notation.
func (a RetConstant) String() string {
return fmt.Sprintf("ret #%d", a.Val)
}
// TXA copies the value of register X to register A.
type TXA struct{}
// Assemble implements the Instruction Assemble method.
func (a TXA) Assemble() (RawInstruction, error) {
return RawInstruction{
Op: opClsMisc | opMiscTXA,
}, nil
}
// String returns the instruction in assembler notation.
func (a TXA) String() string {
return fmt.Sprintf("txa")
}
// TAX copies the value of register A to register X.
type TAX struct{}
// Assemble implements the Instruction Assemble method.
func (a TAX) Assemble() (RawInstruction, error) {
return RawInstruction{
Op: opClsMisc | opMiscTAX,
}, nil
}
// String returns the instruction in assembler notation.
func (a TAX) String() string {
return fmt.Sprintf("tax")
}
func assembleLoad(dst Register, loadSize int, mode uint16, k uint32) (RawInstruction, error) {
var (
cls uint16
sz uint16
)
switch dst {
case RegA:
cls = opClsLoadA
case RegX:
cls = opClsLoadX
default:
return RawInstruction{}, fmt.Errorf("invalid target register %v", dst)
}
switch loadSize {
case 1:
sz = opLoadWidth1
case 2:
sz = opLoadWidth2
case 4:
sz = opLoadWidth4
default:
return RawInstruction{}, fmt.Errorf("invalid load byte length %d", sz)
}
return RawInstruction{
Op: cls | sz | mode,
K: k,
}, nil
}
// 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.
package bpf
import (
"errors"
"fmt"
)
// A VM is an emulated BPF virtual machine.
type VM struct {
filter []Instruction
}
// NewVM returns a new VM using the input BPF program.
func NewVM(filter []Instruction) (*VM, error) {
if len(filter) == 0 {
return nil, errors.New("one or more Instructions must be specified")
}
for i, ins := range filter {
check := len(filter) - (i + 1)
switch ins := ins.(type) {
// Check for out-of-bounds jumps in instructions
case Jump:
if check <= int(ins.Skip) {
return nil, fmt.Errorf("cannot jump %d instructions; jumping past program bounds", ins.Skip)
}
case JumpIf:
if check <= int(ins.SkipTrue) {
return nil, fmt.Errorf("cannot jump %d instructions in true case; jumping past program bounds", ins.SkipTrue)
}
if check <= int(ins.SkipFalse) {
return nil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse)
}
case JumpIfX:
if check <= int(ins.SkipTrue) {
return nil, fmt.Errorf("cannot jump %d instructions in true case; jumping past program bounds", ins.SkipTrue)
}
if check <= int(ins.SkipFalse) {
return nil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse)
}
// Check for division or modulus by zero
case ALUOpConstant:
if ins.Val != 0 {
break
}
switch ins.Op {
case ALUOpDiv, ALUOpMod:
return nil, errors.New("cannot divide by zero using ALUOpConstant")
}
// Check for unknown extensions
case LoadExtension:
switch ins.Num {
case ExtLen:
default:
return nil, fmt.Errorf("extension %d not implemented", ins.Num)
}
}
}
// Make sure last instruction is a return instruction
switch filter[len(filter)-1].(type) {
case RetA, RetConstant:
default:
return nil, errors.New("BPF program must end with RetA or RetConstant")
}
// Though our VM works using disassembled instructions, we
// attempt to assemble the input filter anyway to ensure it is compatible
// with an operating system VM.
_, err := Assemble(filter)
return &VM{
filter: filter,
}, err
}
// Run runs the VM's BPF program against the input bytes.
// Run returns the number of bytes accepted by the BPF program, and any errors
// which occurred while processing the program.
func (v *VM) Run(in []byte) (int, error) {
var (
// Registers of the virtual machine
regA uint32
regX uint32
regScratch [16]uint32
// OK is true if the program should continue processing the next
// instruction, or false if not, causing the loop to break
ok = true
)
// TODO(mdlayher): implement:
// - NegateA:
// - would require a change from uint32 registers to int32
// registers
// TODO(mdlayher): add interop tests that check signedness of ALU
// operations against kernel implementation, and make sure Go
// implementation matches behavior
for i := 0; i < len(v.filter) && ok; i++ {
ins := v.filter[i]
switch ins := ins.(type) {
case ALUOpConstant:
regA = aluOpConstant(ins, regA)
case ALUOpX:
regA, ok = aluOpX(ins, regA, regX)
case Jump:
i += int(ins.Skip)
case JumpIf:
jump := jumpIf(ins, regA)
i += jump
case JumpIfX:
jump := jumpIfX(ins, regA, regX)
i += jump
case LoadAbsolute:
regA, ok = loadAbsolute(ins, in)
case LoadConstant:
regA, regX = loadConstant(ins, regA, regX)
case LoadExtension:
regA = loadExtension(ins, in)
case LoadIndirect:
regA, ok = loadIndirect(ins, in, regX)
case LoadMemShift:
regX, ok = loadMemShift(ins, in)
case LoadScratch:
regA, regX = loadScratch(ins, regScratch, regA, regX)
case RetA:
return int(regA), nil
case RetConstant:
return int(ins.Val), nil
case StoreScratch:
regScratch = storeScratch(ins, regScratch, regA, regX)
case TAX:
regX = regA
case TXA:
regA = regX
default:
return 0, fmt.Errorf("unknown Instruction at index %d: %T", i, ins)
}
}
return 0, nil
}
// 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.
package bpf
import (
"encoding/binary"
"fmt"
)
func aluOpConstant(ins ALUOpConstant, regA uint32) uint32 {
return aluOpCommon(ins.Op, regA, ins.Val)
}
func aluOpX(ins ALUOpX, regA uint32, regX uint32) (uint32, bool) {
// Guard against division or modulus by zero by terminating
// the program, as the OS BPF VM does
if regX == 0 {
switch ins.Op {
case ALUOpDiv, ALUOpMod:
return 0, false
}
}
return aluOpCommon(ins.Op, regA, regX), true
}
func aluOpCommon(op ALUOp, regA uint32, value uint32) uint32 {
switch op {
case ALUOpAdd:
return regA + value
case ALUOpSub:
return regA - value
case ALUOpMul:
return regA * value
case ALUOpDiv:
// Division by zero not permitted by NewVM and aluOpX checks
return regA / value
case ALUOpOr:
return regA | value
case ALUOpAnd:
return regA & value
case ALUOpShiftLeft:
return regA << value
case ALUOpShiftRight:
return regA >> value
case ALUOpMod:
// Modulus by zero not permitted by NewVM and aluOpX checks
return regA % value
case ALUOpXor:
return regA ^ value
default:
return regA
}
}
func jumpIf(ins JumpIf, regA uint32) int {
return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, ins.Val)
}
func jumpIfX(ins JumpIfX, regA uint32, regX uint32) int {
return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, regX)
}
func jumpIfCommon(cond JumpTest, skipTrue, skipFalse uint8, regA uint32, value uint32) int {
var ok bool
switch cond {
case JumpEqual:
ok = regA == value
case JumpNotEqual:
ok = regA != value
case JumpGreaterThan:
ok = regA > value
case JumpLessThan:
ok = regA < value
case JumpGreaterOrEqual:
ok = regA >= value
case JumpLessOrEqual:
ok = regA <= value
case JumpBitsSet:
ok = (regA & value) != 0
case JumpBitsNotSet:
ok = (regA & value) == 0
}
if ok {
return int(skipTrue)
}
return int(skipFalse)
}
func loadAbsolute(ins LoadAbsolute, in []byte) (uint32, bool) {
offset := int(ins.Off)
size := ins.Size
return loadCommon(in, offset, size)
}
func loadConstant(ins LoadConstant, regA uint32, regX uint32) (uint32, uint32) {
switch ins.Dst {
case RegA:
regA = ins.Val
case RegX:
regX = ins.Val
}
return regA, regX
}
func loadExtension(ins LoadExtension, in []byte) uint32 {
switch ins.Num {
case ExtLen:
return uint32(len(in))
default:
panic(fmt.Sprintf("unimplemented extension: %d", ins.Num))
}
}
func loadIndirect(ins LoadIndirect, in []byte, regX uint32) (uint32, bool) {
offset := int(ins.Off) + int(regX)
size := ins.Size
return loadCommon(in, offset, size)
}
func loadMemShift(ins LoadMemShift, in []byte) (uint32, bool) {
offset := int(ins.Off)
// Size of LoadMemShift is always 1 byte
if !inBounds(len(in), offset, 1) {
return 0, false
}
// Mask off high 4 bits and multiply low 4 bits by 4
return uint32(in[offset]&0x0f) * 4, true
}
func inBounds(inLen int, offset int, size int) bool {
return offset+size <= inLen
}
func loadCommon(in []byte, offset int, size int) (uint32, bool) {
if !inBounds(len(in), offset, size) {
return 0, false
}
switch size {
case 1:
return uint32(in[offset]), true
case 2:
return uint32(binary.BigEndian.Uint16(in[offset : offset+size])), true
case 4:
return uint32(binary.BigEndian.Uint32(in[offset : offset+size])), true
default:
panic(fmt.Sprintf("invalid load size: %d", size))
}
}
func loadScratch(ins LoadScratch, regScratch [16]uint32, regA uint32, regX uint32) (uint32, uint32) {
switch ins.Dst {
case RegA:
regA = regScratch[ins.N]
case RegX:
regX = regScratch[ins.N]
}
return regA, regX
}
func storeScratch(ins StoreScratch, regScratch [16]uint32, regA uint32, regX uint32) [16]uint32 {
switch ins.Src {
case RegA:
regScratch[ins.N] = regA
case RegX:
regScratch[ins.N] = regX
}
return regScratch
}
// 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 context has been superseded by the standard library [context] package.
//
// Deprecated: Use the standard library context package instead.
package context
import (
"context" // standard library's context, as of Go 1.7
"time"
)
// A Context carries a deadline, a cancellation signal, and other values across
// API boundaries.
//
// Context's methods may be called by multiple goroutines simultaneously.
//
//go:fix inline
type Context = context.Context
// Canceled is the error returned by [Context.Err] when the context is canceled
// for some reason other than its deadline passing.
//
//go:fix inline
var Canceled = context.Canceled
// DeadlineExceeded is the error returned by [Context.Err] when the context is canceled
// due to its deadline passing.
//
//go:fix inline
var DeadlineExceeded = context.DeadlineExceeded
// 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,
// initialization, and tests, and as the top-level Context for incoming
// requests.
//
//go:fix inline
func Background() Context { return context.Background() }
// 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).
//
//go:fix inline
func TODO() Context { return context.TODO() }
// A CancelFunc tells an operation to abandon its work.
// A CancelFunc does not wait for the work to stop.
// A CancelFunc may be called by multiple goroutines simultaneously.
// After the first call, subsequent calls to a CancelFunc do nothing.
type CancelFunc = context.CancelFunc
// WithCancel returns a derived context that points to the parent context
// but has a new Done channel. The returned context's Done channel is closed
// when the returned cancel function is called or when the parent context's
// Done channel is closed, whichever happens first.
//
// Canceling this context releases resources associated with it, so code should
// call cancel as soon as the operations running in this [Context] complete.
//
//go:fix inline
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
return context.WithCancel(parent)
}
// WithDeadline returns a derived context that points to the parent context
// but has 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 [Context.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.
//
// Canceling this context releases resources associated with it, so code should
// call cancel as soon as the operations running in this [Context] complete.
//
//go:fix inline
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) {
return context.WithDeadline(parent, d)
}
// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
//
// Canceling this context releases resources associated with it, so code should
// call cancel as soon as the operations running in this [Context] complete:
//
// func slowOperationWithTimeout(ctx context.Context) (Result, error) {
// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
// defer cancel() // releases resources if slowOperation completes before timeout elapses
// return slowOperation(ctx)
// }
//
//go:fix inline
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
return context.WithTimeout(parent, timeout)
}
// WithValue returns a derived context that points to the parent Context.
// In the derived context, the value associated with key is val.
//
// Use context Values only for request-scoped data that transits processes and
// APIs, not for passing optional parameters to functions.
//
// The provided key must be comparable and should not be of type
// string or any other built-in type to avoid collisions between
// packages using context. Users of WithValue should define their own
// types for keys. To avoid allocating when assigning to an
// interface{}, context keys often have concrete type
// struct{}. Alternatively, exported context key variables' static
// type should be a pointer or interface.
//
//go:fix inline
func WithValue(parent Context, key, val interface{}) Context {
return context.WithValue(parent, key, val)
}
// 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 provides a mostly RFC 1035 compliant implementation of
// DNS message packing and unpacking.
//
// The package also supports messages with Extension Mechanisms for DNS
// (EDNS(0)) as defined in RFC 6891.
//
// This implementation is designed to minimize heap allocations and avoid
// unnecessary packing and unpacking as much as possible.
package dnsmessage
import (
"errors"
)
// Message formats
//
// To add a new Resource Record type:
// 1. Create Resource Record types
// 1.1. Add a Type constant named "Type<name>"
// 1.2. Add the corresponding entry to the typeNames map
// 1.3. Add a [ResourceBody] implementation named "<name>Resource"
// 2. Implement packing
// 2.1. Implement Builder.<name>Resource()
// 3. Implement unpacking
// 3.1. Add the unpacking code to unpackResourceBody()
// 3.2. Implement Parser.<name>Resource()
// A Type is the type of a DNS Resource Record, as defined in the [IANA registry].
//
// [IANA registry]: https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4
type Type uint16
const (
// ResourceHeader.Type and Question.Type
TypeA Type = 1
TypeNS Type = 2
TypeCNAME Type = 5
TypeSOA Type = 6
TypePTR Type = 12
TypeMX Type = 15
TypeTXT Type = 16
TypeAAAA Type = 28
TypeSRV Type = 33
TypeOPT Type = 41
TypeSVCB Type = 64
TypeHTTPS Type = 65
// Question.Type
TypeWKS Type = 11
TypeHINFO Type = 13
TypeMINFO Type = 14
TypeAXFR Type = 252
TypeALL Type = 255
)
var typeNames = map[Type]string{
TypeA: "TypeA",
TypeNS: "TypeNS",
TypeCNAME: "TypeCNAME",
TypeSOA: "TypeSOA",
TypePTR: "TypePTR",
TypeMX: "TypeMX",
TypeTXT: "TypeTXT",
TypeAAAA: "TypeAAAA",
TypeSRV: "TypeSRV",
TypeOPT: "TypeOPT",
TypeSVCB: "TypeSVCB",
TypeHTTPS: "TypeHTTPS",
TypeWKS: "TypeWKS",
TypeHINFO: "TypeHINFO",
TypeMINFO: "TypeMINFO",
TypeAXFR: "TypeAXFR",
TypeALL: "TypeALL",
}
// String implements fmt.Stringer.String.
func (t Type) String() string {
if n, ok := typeNames[t]; ok {
return n
}
return printUint16(uint16(t))
}
// GoString implements fmt.GoStringer.GoString.
func (t Type) GoString() string {
if n, ok := typeNames[t]; ok {
return "dnsmessage." + n
}
return printUint16(uint16(t))
}
// A Class is a type of network.
type Class uint16
const (
// ResourceHeader.Class and Question.Class
ClassINET Class = 1
ClassCSNET Class = 2
ClassCHAOS Class = 3
ClassHESIOD Class = 4
// Question.Class
ClassANY Class = 255
)
var classNames = map[Class]string{
ClassINET: "ClassINET",
ClassCSNET: "ClassCSNET",
ClassCHAOS: "ClassCHAOS",
ClassHESIOD: "ClassHESIOD",
ClassANY: "ClassANY",
}
// String implements fmt.Stringer.String.
func (c Class) String() string {
if n, ok := classNames[c]; ok {
return n
}
return printUint16(uint16(c))
}
// GoString implements fmt.GoStringer.GoString.
func (c Class) GoString() string {
if n, ok := classNames[c]; ok {
return "dnsmessage." + n
}
return printUint16(uint16(c))
}
// An OpCode is a DNS operation code.
type OpCode uint16
// GoString implements fmt.GoStringer.GoString.
func (o OpCode) GoString() string {
return printUint16(uint16(o))
}
// An RCode is a DNS response status code.
type RCode uint16
// Header.RCode values.
const (
RCodeSuccess RCode = 0 // NoError
RCodeFormatError RCode = 1 // FormErr
RCodeServerFailure RCode = 2 // ServFail
RCodeNameError RCode = 3 // NXDomain
RCodeNotImplemented RCode = 4 // NotImp
RCodeRefused RCode = 5 // Refused
)
var rCodeNames = map[RCode]string{
RCodeSuccess: "RCodeSuccess",
RCodeFormatError: "RCodeFormatError",
RCodeServerFailure: "RCodeServerFailure",
RCodeNameError: "RCodeNameError",
RCodeNotImplemented: "RCodeNotImplemented",
RCodeRefused: "RCodeRefused",
}
// String implements fmt.Stringer.String.
func (r RCode) String() string {
if n, ok := rCodeNames[r]; ok {
return n
}
return printUint16(uint16(r))
}
// GoString implements fmt.GoStringer.GoString.
func (r RCode) GoString() string {
if n, ok := rCodeNames[r]; ok {
return "dnsmessage." + n
}
return printUint16(uint16(r))
}
func printPaddedUint8(i uint8) string {
b := byte(i)
return string([]byte{
b/100 + '0',
b/10%10 + '0',
b%10 + '0',
})
}
func printUint8Bytes(buf []byte, i uint8) []byte {
b := byte(i)
if i >= 100 {
buf = append(buf, b/100+'0')
}
if i >= 10 {
buf = append(buf, b/10%10+'0')
}
return append(buf, b%10+'0')
}
func printByteSlice(b []byte) string {
if len(b) == 0 {
return ""
}
buf := make([]byte, 0, 5*len(b))
buf = printUint8Bytes(buf, uint8(b[0]))
for _, n := range b[1:] {
buf = append(buf, ',', ' ')
buf = printUint8Bytes(buf, uint8(n))
}
return string(buf)
}
const hexDigits = "0123456789abcdef"
func printString(str []byte) string {
buf := make([]byte, 0, len(str))
for i := 0; i < len(str); i++ {
c := str[i]
if c == '.' || c == '-' || c == ' ' ||
'A' <= c && c <= 'Z' ||
'a' <= c && c <= 'z' ||
'0' <= c && c <= '9' {
buf = append(buf, c)
continue
}
upper := c >> 4
lower := (c << 4) >> 4
buf = append(
buf,
'\\',
'x',
hexDigits[upper],
hexDigits[lower],
)
}
return string(buf)
}
func printUint16(i uint16) string {
return printUint32(uint32(i))
}
func printUint32(i uint32) string {
// Max value is 4294967295.
buf := make([]byte, 10)
for b, d := buf, uint32(1000000000); d > 0; d /= 10 {
b[0] = byte(i/d%10 + '0')
if b[0] == '0' && len(b) == len(buf) && len(buf) > 1 {
buf = buf[1:]
}
b = b[1:]
i %= d
}
return string(buf)
}
func printBool(b bool) string {
if b {
return "true"
}
return "false"
}
var (
// ErrNotStarted indicates that the prerequisite information isn't
// available yet because the previous records haven't been appropriately
// parsed, skipped or finished.
ErrNotStarted = errors.New("parsing/packing of this type isn't available yet")
// ErrSectionDone indicated that all records in the section have been
// parsed or finished.
ErrSectionDone = errors.New("parsing/packing of this section has completed")
errBaseLen = errors.New("insufficient data for base length type")
errCalcLen = errors.New("insufficient data for calculated length type")
errReserved = errors.New("segment prefix is reserved")
errTooManyPtr = errors.New("too many pointers (>10)")
errInvalidPtr = errors.New("invalid pointer")
errInvalidName = errors.New("invalid dns name")
errNilResouceBody = errors.New("nil resource body")
errResourceLen = errors.New("insufficient data for resource body length")
errSegTooLong = errors.New("segment length too long")
errNameTooLong = errors.New("name too long")
errZeroSegLen = errors.New("zero length segment")
errResTooLong = errors.New("resource length too long")
errTooManyQuestions = errors.New("too many Questions to pack (>65535)")
errTooManyAnswers = errors.New("too many Answers to pack (>65535)")
errTooManyAuthorities = errors.New("too many Authorities to pack (>65535)")
errTooManyAdditionals = errors.New("too many Additionals to pack (>65535)")
errNonCanonicalName = errors.New("name is not in canonical format (it must end with a .)")
errStringTooLong = errors.New("character string exceeds maximum length (255)")
errParamOutOfOrder = errors.New("parameter out of order")
errTooLongSVCBValue = errors.New("value too long (>65535 bytes)")
)
// Internal constants.
const (
// packStartingCap is the default initial buffer size allocated during
// packing.
//
// The starting capacity doesn't matter too much, but most DNS responses
// Will be <= 512 bytes as it is the limit for DNS over UDP.
packStartingCap = 512
// uint16Len is the length (in bytes) of a uint16.
uint16Len = 2
// uint32Len is the length (in bytes) of a uint32.
uint32Len = 4
// headerLen is the length (in bytes) of a DNS header.
//
// A header is comprised of 6 uint16s and no padding.
headerLen = 6 * uint16Len
)
type nestedError struct {
// s is the current level's error message.
s string
// err is the nested error.
err error
}
// nestedError implements error.Error.
func (e *nestedError) Error() string {
return e.s + ": " + e.err.Error()
}
// Header is a representation of a DNS message header.
type Header struct {
ID uint16
Response bool
OpCode OpCode
Authoritative bool
Truncated bool
RecursionDesired bool
RecursionAvailable bool
AuthenticData bool
CheckingDisabled bool
RCode RCode
}
func (m *Header) pack() (id uint16, bits uint16) {
id = m.ID
bits = uint16(m.OpCode)<<11 | uint16(m.RCode)
if m.RecursionAvailable {
bits |= headerBitRA
}
if m.RecursionDesired {
bits |= headerBitRD
}
if m.Truncated {
bits |= headerBitTC
}
if m.Authoritative {
bits |= headerBitAA
}
if m.Response {
bits |= headerBitQR
}
if m.AuthenticData {
bits |= headerBitAD
}
if m.CheckingDisabled {
bits |= headerBitCD
}
return
}
// GoString implements fmt.GoStringer.GoString.
func (m *Header) GoString() string {
return "dnsmessage.Header{" +
"ID: " + printUint16(m.ID) + ", " +
"Response: " + printBool(m.Response) + ", " +
"OpCode: " + m.OpCode.GoString() + ", " +
"Authoritative: " + printBool(m.Authoritative) + ", " +
"Truncated: " + printBool(m.Truncated) + ", " +
"RecursionDesired: " + printBool(m.RecursionDesired) + ", " +
"RecursionAvailable: " + printBool(m.RecursionAvailable) + ", " +
"AuthenticData: " + printBool(m.AuthenticData) + ", " +
"CheckingDisabled: " + printBool(m.CheckingDisabled) + ", " +
"RCode: " + m.RCode.GoString() + "}"
}
// Message is a representation of a DNS message.
type Message struct {
Header
Questions []Question
Answers []Resource
Authorities []Resource
Additionals []Resource
}
type section uint8
const (
sectionNotStarted section = iota
sectionHeader
sectionQuestions
sectionAnswers
sectionAuthorities
sectionAdditionals
sectionDone
headerBitQR = 1 << 15 // query/response (response=1)
headerBitAA = 1 << 10 // authoritative
headerBitTC = 1 << 9 // truncated
headerBitRD = 1 << 8 // recursion desired
headerBitRA = 1 << 7 // recursion available
headerBitAD = 1 << 5 // authentic data
headerBitCD = 1 << 4 // checking disabled
)
var sectionNames = map[section]string{
sectionHeader: "header",
sectionQuestions: "Question",
sectionAnswers: "Answer",
sectionAuthorities: "Authority",
sectionAdditionals: "Additional",
}
// header is the wire format for a DNS message header.
type header struct {
id uint16
bits uint16
questions uint16
answers uint16
authorities uint16
additionals uint16
}
func (h *header) count(sec section) uint16 {
switch sec {
case sectionQuestions:
return h.questions
case sectionAnswers:
return h.answers
case sectionAuthorities:
return h.authorities
case sectionAdditionals:
return h.additionals
}
return 0
}
// pack appends the wire format of the header to msg.
func (h *header) pack(msg []byte) []byte {
msg = packUint16(msg, h.id)
msg = packUint16(msg, h.bits)
msg = packUint16(msg, h.questions)
msg = packUint16(msg, h.answers)
msg = packUint16(msg, h.authorities)
return packUint16(msg, h.additionals)
}
func (h *header) unpack(msg []byte, off int) (int, error) {
newOff := off
var err error
if h.id, newOff, err = unpackUint16(msg, newOff); err != nil {
return off, &nestedError{"id", err}
}
if h.bits, newOff, err = unpackUint16(msg, newOff); err != nil {
return off, &nestedError{"bits", err}
}
if h.questions, newOff, err = unpackUint16(msg, newOff); err != nil {
return off, &nestedError{"questions", err}
}
if h.answers, newOff, err = unpackUint16(msg, newOff); err != nil {
return off, &nestedError{"answers", err}
}
if h.authorities, newOff, err = unpackUint16(msg, newOff); err != nil {
return off, &nestedError{"authorities", err}
}
if h.additionals, newOff, err = unpackUint16(msg, newOff); err != nil {
return off, &nestedError{"additionals", err}
}
return newOff, nil
}
func (h *header) header() Header {
return Header{
ID: h.id,
Response: (h.bits & headerBitQR) != 0,
OpCode: OpCode(h.bits>>11) & 0xF,
Authoritative: (h.bits & headerBitAA) != 0,
Truncated: (h.bits & headerBitTC) != 0,
RecursionDesired: (h.bits & headerBitRD) != 0,
RecursionAvailable: (h.bits & headerBitRA) != 0,
AuthenticData: (h.bits & headerBitAD) != 0,
CheckingDisabled: (h.bits & headerBitCD) != 0,
RCode: RCode(h.bits & 0xF),
}
}
// A Resource is a DNS resource record.
type Resource struct {
Header ResourceHeader
Body ResourceBody
}
func (r *Resource) GoString() string {
return "dnsmessage.Resource{" +
"Header: " + r.Header.GoString() +
", Body: &" + r.Body.GoString() +
"}"
}
// A ResourceBody is a DNS resource record minus the header.
type ResourceBody interface {
// pack packs a Resource except for its header.
pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error)
// realType returns the actual type of the Resource. This is used to
// fill in the header Type field.
realType() Type
// GoString implements fmt.GoStringer.GoString.
GoString() string
}
// pack appends the wire format of the Resource to msg.
func (r *Resource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) {
if r.Body == nil {
return msg, errNilResouceBody
}
oldMsg := msg
r.Header.Type = r.Body.realType()
msg, lenOff, err := r.Header.pack(msg, compression, compressionOff)
if err != nil {
return msg, &nestedError{"ResourceHeader", err}
}
preLen := len(msg)
msg, err = r.Body.pack(msg, compression, compressionOff)
if err != nil {
return msg, &nestedError{"content", err}
}
if err := r.Header.fixLen(msg, lenOff, preLen); err != nil {
return oldMsg, err
}
return msg, nil
}
// A Parser allows incrementally parsing a DNS message.
//
// When parsing is started, the Header is parsed. Next, each Question can be
// either parsed or skipped. Alternatively, all Questions can be skipped at
// once. When all Questions have been parsed, attempting to parse Questions
// will return the [ErrSectionDone] error.
// After all Questions have been either parsed or skipped, all
// Answers, Authorities and Additionals can be either parsed or skipped in the
// same way, and each type of Resource must be fully parsed or skipped before
// proceeding to the next type of Resource.
//
// Parser is safe to copy to preserve the parsing state.
//
// Note that there is no requirement to fully skip or parse the message.
type Parser struct {
msg []byte
header header
section section
off int
index int
resHeaderValid bool
resHeaderOffset int
resHeaderType Type
resHeaderLength uint16
}
// Start parses the header and enables the parsing of Questions.
func (p *Parser) Start(msg []byte) (Header, error) {
if p.msg != nil {
*p = Parser{}
}
p.msg = msg
var err error
if p.off, err = p.header.unpack(msg, 0); err != nil {
return Header{}, &nestedError{"unpacking header", err}
}
p.section = sectionQuestions
return p.header.header(), nil
}
func (p *Parser) checkAdvance(sec section) error {
if p.section < sec {
return ErrNotStarted
}
if p.section > sec {
return ErrSectionDone
}
p.resHeaderValid = false
if p.index == int(p.header.count(sec)) {
p.index = 0
p.section++
return ErrSectionDone
}
return nil
}
func (p *Parser) resource(sec section) (Resource, error) {
var r Resource
var err error
r.Header, err = p.resourceHeader(sec)
if err != nil {
return r, err
}
p.resHeaderValid = false
r.Body, p.off, err = unpackResourceBody(p.msg, p.off, r.Header)
if err != nil {
return Resource{}, &nestedError{"unpacking " + sectionNames[sec], err}
}
p.index++
return r, nil
}
func (p *Parser) resourceHeader(sec section) (ResourceHeader, error) {
if p.resHeaderValid {
p.off = p.resHeaderOffset
}
if err := p.checkAdvance(sec); err != nil {
return ResourceHeader{}, err
}
var hdr ResourceHeader
off, err := hdr.unpack(p.msg, p.off)
if err != nil {
return ResourceHeader{}, err
}
p.resHeaderValid = true
p.resHeaderOffset = p.off
p.resHeaderType = hdr.Type
p.resHeaderLength = hdr.Length
p.off = off
return hdr, nil
}
func (p *Parser) skipResource(sec section) error {
if p.resHeaderValid && p.section == sec {
newOff := p.off + int(p.resHeaderLength)
if newOff > len(p.msg) {
return errResourceLen
}
p.off = newOff
p.resHeaderValid = false
p.index++
return nil
}
if err := p.checkAdvance(sec); err != nil {
return err
}
var err error
p.off, err = skipResource(p.msg, p.off)
if err != nil {
return &nestedError{"skipping: " + sectionNames[sec], err}
}
p.index++
return nil
}
// Question parses a single Question.
func (p *Parser) Question() (Question, error) {
if err := p.checkAdvance(sectionQuestions); err != nil {
return Question{}, err
}
var name Name
off, err := name.unpack(p.msg, p.off)
if err != nil {
return Question{}, &nestedError{"unpacking Question.Name", err}
}
typ, off, err := unpackType(p.msg, off)
if err != nil {
return Question{}, &nestedError{"unpacking Question.Type", err}
}
class, off, err := unpackClass(p.msg, off)
if err != nil {
return Question{}, &nestedError{"unpacking Question.Class", err}
}
p.off = off
p.index++
return Question{name, typ, class}, nil
}
// AllQuestions parses all Questions.
func (p *Parser) AllQuestions() ([]Question, error) {
// Multiple questions are valid according to the spec,
// but servers don't actually support them. There will
// be at most one question here.
//
// Do not pre-allocate based on info in p.header, since
// the data is untrusted.
qs := []Question{}
for {
q, err := p.Question()
if err == ErrSectionDone {
return qs, nil
}
if err != nil {
return nil, err
}
qs = append(qs, q)
}
}
// SkipQuestion skips a single Question.
func (p *Parser) SkipQuestion() error {
if err := p.checkAdvance(sectionQuestions); err != nil {
return err
}
off, err := skipName(p.msg, p.off)
if err != nil {
return &nestedError{"skipping Question Name", err}
}
if off, err = skipType(p.msg, off); err != nil {
return &nestedError{"skipping Question Type", err}
}
if off, err = skipClass(p.msg, off); err != nil {
return &nestedError{"skipping Question Class", err}
}
p.off = off
p.index++
return nil
}
// SkipAllQuestions skips all Questions.
func (p *Parser) SkipAllQuestions() error {
for {
if err := p.SkipQuestion(); err == ErrSectionDone {
return nil
} else if err != nil {
return err
}
}
}
// AnswerHeader parses a single Answer ResourceHeader.
func (p *Parser) AnswerHeader() (ResourceHeader, error) {
return p.resourceHeader(sectionAnswers)
}
// Answer parses a single Answer Resource.
func (p *Parser) Answer() (Resource, error) {
return p.resource(sectionAnswers)
}
// AllAnswers parses all Answer Resources.
func (p *Parser) AllAnswers() ([]Resource, error) {
// The most common query is for A/AAAA, which usually returns
// a handful of IPs.
//
// Pre-allocate up to a certain limit, since p.header is
// untrusted data.
n := int(p.header.answers)
if n > 20 {
n = 20
}
as := make([]Resource, 0, n)
for {
a, err := p.Answer()
if err == ErrSectionDone {
return as, nil
}
if err != nil {
return nil, err
}
as = append(as, a)
}
}
// SkipAnswer skips a single Answer Resource.
//
// It does not perform a complete validation of the resource header, which means
// it may return a nil error when the [AnswerHeader] would actually return an error.
func (p *Parser) SkipAnswer() error {
return p.skipResource(sectionAnswers)
}
// SkipAllAnswers skips all Answer Resources.
func (p *Parser) SkipAllAnswers() error {
for {
if err := p.SkipAnswer(); err == ErrSectionDone {
return nil
} else if err != nil {
return err
}
}
}
// AuthorityHeader parses a single Authority ResourceHeader.
func (p *Parser) AuthorityHeader() (ResourceHeader, error) {
return p.resourceHeader(sectionAuthorities)
}
// Authority parses a single Authority Resource.
func (p *Parser) Authority() (Resource, error) {
return p.resource(sectionAuthorities)
}
// AllAuthorities parses all Authority Resources.
func (p *Parser) AllAuthorities() ([]Resource, error) {
// Authorities contains SOA in case of NXDOMAIN and friends,
// otherwise it is empty.
//
// Pre-allocate up to a certain limit, since p.header is
// untrusted data.
n := int(p.header.authorities)
if n > 10 {
n = 10
}
as := make([]Resource, 0, n)
for {
a, err := p.Authority()
if err == ErrSectionDone {
return as, nil
}
if err != nil {
return nil, err
}
as = append(as, a)
}
}
// SkipAuthority skips a single Authority Resource.
//
// It does not perform a complete validation of the resource header, which means
// it may return a nil error when the [AuthorityHeader] would actually return an error.
func (p *Parser) SkipAuthority() error {
return p.skipResource(sectionAuthorities)
}
// SkipAllAuthorities skips all Authority Resources.
func (p *Parser) SkipAllAuthorities() error {
for {
if err := p.SkipAuthority(); err == ErrSectionDone {
return nil
} else if err != nil {
return err
}
}
}
// AdditionalHeader parses a single Additional ResourceHeader.
func (p *Parser) AdditionalHeader() (ResourceHeader, error) {
return p.resourceHeader(sectionAdditionals)
}
// Additional parses a single Additional Resource.
func (p *Parser) Additional() (Resource, error) {
return p.resource(sectionAdditionals)
}
// AllAdditionals parses all Additional Resources.
func (p *Parser) AllAdditionals() ([]Resource, error) {
// Additionals usually contain OPT, and sometimes A/AAAA
// glue records.
//
// Pre-allocate up to a certain limit, since p.header is
// untrusted data.
n := int(p.header.additionals)
if n > 10 {
n = 10
}
as := make([]Resource, 0, n)
for {
a, err := p.Additional()
if err == ErrSectionDone {
return as, nil
}
if err != nil {
return nil, err
}
as = append(as, a)
}
}
// SkipAdditional skips a single Additional Resource.
//
// It does not perform a complete validation of the resource header, which means
// it may return a nil error when the [AdditionalHeader] would actually return an error.
func (p *Parser) SkipAdditional() error {
return p.skipResource(sectionAdditionals)
}
// SkipAllAdditionals skips all Additional Resources.
func (p *Parser) SkipAllAdditionals() error {
for {
if err := p.SkipAdditional(); err == ErrSectionDone {
return nil
} else if err != nil {
return err
}
}
}
// CNAMEResource parses a single CNAMEResource.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) CNAMEResource() (CNAMEResource, error) {
if !p.resHeaderValid || p.resHeaderType != TypeCNAME {
return CNAMEResource{}, ErrNotStarted
}
r, err := unpackCNAMEResource(p.msg, p.off)
if err != nil {
return CNAMEResource{}, err
}
p.off += int(p.resHeaderLength)
p.resHeaderValid = false
p.index++
return r, nil
}
// MXResource parses a single MXResource.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) MXResource() (MXResource, error) {
if !p.resHeaderValid || p.resHeaderType != TypeMX {
return MXResource{}, ErrNotStarted
}
r, err := unpackMXResource(p.msg, p.off)
if err != nil {
return MXResource{}, err
}
p.off += int(p.resHeaderLength)
p.resHeaderValid = false
p.index++
return r, nil
}
// NSResource parses a single NSResource.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) NSResource() (NSResource, error) {
if !p.resHeaderValid || p.resHeaderType != TypeNS {
return NSResource{}, ErrNotStarted
}
r, err := unpackNSResource(p.msg, p.off)
if err != nil {
return NSResource{}, err
}
p.off += int(p.resHeaderLength)
p.resHeaderValid = false
p.index++
return r, nil
}
// PTRResource parses a single PTRResource.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) PTRResource() (PTRResource, error) {
if !p.resHeaderValid || p.resHeaderType != TypePTR {
return PTRResource{}, ErrNotStarted
}
r, err := unpackPTRResource(p.msg, p.off)
if err != nil {
return PTRResource{}, err
}
p.off += int(p.resHeaderLength)
p.resHeaderValid = false
p.index++
return r, nil
}
// SOAResource parses a single SOAResource.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) SOAResource() (SOAResource, error) {
if !p.resHeaderValid || p.resHeaderType != TypeSOA {
return SOAResource{}, ErrNotStarted
}
r, err := unpackSOAResource(p.msg, p.off)
if err != nil {
return SOAResource{}, err
}
p.off += int(p.resHeaderLength)
p.resHeaderValid = false
p.index++
return r, nil
}
// TXTResource parses a single TXTResource.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) TXTResource() (TXTResource, error) {
if !p.resHeaderValid || p.resHeaderType != TypeTXT {
return TXTResource{}, ErrNotStarted
}
r, err := unpackTXTResource(p.msg, p.off, p.resHeaderLength)
if err != nil {
return TXTResource{}, err
}
p.off += int(p.resHeaderLength)
p.resHeaderValid = false
p.index++
return r, nil
}
// SRVResource parses a single SRVResource.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) SRVResource() (SRVResource, error) {
if !p.resHeaderValid || p.resHeaderType != TypeSRV {
return SRVResource{}, ErrNotStarted
}
r, err := unpackSRVResource(p.msg, p.off)
if err != nil {
return SRVResource{}, err
}
p.off += int(p.resHeaderLength)
p.resHeaderValid = false
p.index++
return r, nil
}
// AResource parses a single AResource.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) AResource() (AResource, error) {
if !p.resHeaderValid || p.resHeaderType != TypeA {
return AResource{}, ErrNotStarted
}
r, err := unpackAResource(p.msg, p.off)
if err != nil {
return AResource{}, err
}
p.off += int(p.resHeaderLength)
p.resHeaderValid = false
p.index++
return r, nil
}
// AAAAResource parses a single AAAAResource.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) AAAAResource() (AAAAResource, error) {
if !p.resHeaderValid || p.resHeaderType != TypeAAAA {
return AAAAResource{}, ErrNotStarted
}
r, err := unpackAAAAResource(p.msg, p.off)
if err != nil {
return AAAAResource{}, err
}
p.off += int(p.resHeaderLength)
p.resHeaderValid = false
p.index++
return r, nil
}
// OPTResource parses a single OPTResource.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) OPTResource() (OPTResource, error) {
if !p.resHeaderValid || p.resHeaderType != TypeOPT {
return OPTResource{}, ErrNotStarted
}
r, err := unpackOPTResource(p.msg, p.off, p.resHeaderLength)
if err != nil {
return OPTResource{}, err
}
p.off += int(p.resHeaderLength)
p.resHeaderValid = false
p.index++
return r, nil
}
// UnknownResource parses a single UnknownResource.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) UnknownResource() (UnknownResource, error) {
if !p.resHeaderValid {
return UnknownResource{}, ErrNotStarted
}
r, err := unpackUnknownResource(p.resHeaderType, p.msg, p.off, p.resHeaderLength)
if err != nil {
return UnknownResource{}, err
}
p.off += int(p.resHeaderLength)
p.resHeaderValid = false
p.index++
return r, nil
}
// Unpack parses a full Message.
func (m *Message) Unpack(msg []byte) error {
var p Parser
var err error
if m.Header, err = p.Start(msg); err != nil {
return err
}
if m.Questions, err = p.AllQuestions(); err != nil {
return err
}
if m.Answers, err = p.AllAnswers(); err != nil {
return err
}
if m.Authorities, err = p.AllAuthorities(); err != nil {
return err
}
if m.Additionals, err = p.AllAdditionals(); err != nil {
return err
}
return nil
}
// Pack packs a full Message.
func (m *Message) Pack() ([]byte, error) {
return m.AppendPack(make([]byte, 0, packStartingCap))
}
// AppendPack is like Pack but appends the full Message to b and returns the
// extended buffer.
func (m *Message) AppendPack(b []byte) ([]byte, error) {
// Validate the lengths. It is very unlikely that anyone will try to
// pack more than 65535 of any particular type, but it is possible and
// we should fail gracefully.
if len(m.Questions) > int(^uint16(0)) {
return nil, errTooManyQuestions
}
if len(m.Answers) > int(^uint16(0)) {
return nil, errTooManyAnswers
}
if len(m.Authorities) > int(^uint16(0)) {
return nil, errTooManyAuthorities
}
if len(m.Additionals) > int(^uint16(0)) {
return nil, errTooManyAdditionals
}
var h header
h.id, h.bits = m.Header.pack()
h.questions = uint16(len(m.Questions))
h.answers = uint16(len(m.Answers))
h.authorities = uint16(len(m.Authorities))
h.additionals = uint16(len(m.Additionals))
compressionOff := len(b)
msg := h.pack(b)
// RFC 1035 allows (but does not require) compression for packing. RFC
// 1035 requires unpacking implementations to support compression, so
// unconditionally enabling it is fine.
//
// DNS lookups are typically done over UDP, and RFC 1035 states that UDP
// DNS messages can be a maximum of 512 bytes long. Without compression,
// many DNS response messages are over this limit, so enabling
// compression will help ensure compliance.
compression := map[string]uint16{}
for i := range m.Questions {
var err error
if msg, err = m.Questions[i].pack(msg, compression, compressionOff); err != nil {
return nil, &nestedError{"packing Question", err}
}
}
for i := range m.Answers {
var err error
if msg, err = m.Answers[i].pack(msg, compression, compressionOff); err != nil {
return nil, &nestedError{"packing Answer", err}
}
}
for i := range m.Authorities {
var err error
if msg, err = m.Authorities[i].pack(msg, compression, compressionOff); err != nil {
return nil, &nestedError{"packing Authority", err}
}
}
for i := range m.Additionals {
var err error
if msg, err = m.Additionals[i].pack(msg, compression, compressionOff); err != nil {
return nil, &nestedError{"packing Additional", err}
}
}
return msg, nil
}
// GoString implements fmt.GoStringer.GoString.
func (m *Message) GoString() string {
s := "dnsmessage.Message{Header: " + m.Header.GoString() + ", " +
"Questions: []dnsmessage.Question{"
if len(m.Questions) > 0 {
s += m.Questions[0].GoString()
for _, q := range m.Questions[1:] {
s += ", " + q.GoString()
}
}
s += "}, Answers: []dnsmessage.Resource{"
if len(m.Answers) > 0 {
s += m.Answers[0].GoString()
for _, a := range m.Answers[1:] {
s += ", " + a.GoString()
}
}
s += "}, Authorities: []dnsmessage.Resource{"
if len(m.Authorities) > 0 {
s += m.Authorities[0].GoString()
for _, a := range m.Authorities[1:] {
s += ", " + a.GoString()
}
}
s += "}, Additionals: []dnsmessage.Resource{"
if len(m.Additionals) > 0 {
s += m.Additionals[0].GoString()
for _, a := range m.Additionals[1:] {
s += ", " + a.GoString()
}
}
return s + "}}"
}
// A Builder allows incrementally packing a DNS message.
//
// Example usage:
//
// buf := make([]byte, 2, 514)
// b := NewBuilder(buf, Header{...})
// b.EnableCompression()
// // Optionally start a section and add things to that section.
// // Repeat adding sections as necessary.
// buf, err := b.Finish()
// // If err is nil, buf[2:] will contain the built bytes.
type Builder struct {
// msg is the storage for the message being built.
msg []byte
// section keeps track of the current section being built.
section section
// header keeps track of what should go in the header when Finish is
// called.
header header
// start is the starting index of the bytes allocated in msg for header.
start int
// compression is a mapping from name suffixes to their starting index
// in msg.
compression map[string]uint16
}
// NewBuilder creates a new builder with compression disabled.
//
// Note: Most users will want to immediately enable compression with the
// EnableCompression method. See that method's comment for why you may or may
// not want to enable compression.
//
// The DNS message is appended to the provided initial buffer buf (which may be
// nil) as it is built. The final message is returned by the (*Builder).Finish
// method, which includes buf[:len(buf)] and may return the same underlying
// array if there was sufficient capacity in the slice.
func NewBuilder(buf []byte, h Header) Builder {
if buf == nil {
buf = make([]byte, 0, packStartingCap)
}
b := Builder{msg: buf, start: len(buf)}
b.header.id, b.header.bits = h.pack()
var hb [headerLen]byte
b.msg = append(b.msg, hb[:]...)
b.section = sectionHeader
return b
}
// EnableCompression enables compression in the Builder.
//
// Leaving compression disabled avoids compression related allocations, but can
// result in larger message sizes. Be careful with this mode as it can cause
// messages to exceed the UDP size limit.
//
// According to RFC 1035, section 4.1.4, the use of compression is optional, but
// all implementations must accept both compressed and uncompressed DNS
// messages.
//
// Compression should be enabled before any sections are added for best results.
func (b *Builder) EnableCompression() {
b.compression = map[string]uint16{}
}
func (b *Builder) startCheck(s section) error {
if b.section <= sectionNotStarted {
return ErrNotStarted
}
if b.section > s {
return ErrSectionDone
}
return nil
}
// StartQuestions prepares the builder for packing Questions.
func (b *Builder) StartQuestions() error {
if err := b.startCheck(sectionQuestions); err != nil {
return err
}
b.section = sectionQuestions
return nil
}
// StartAnswers prepares the builder for packing Answers.
func (b *Builder) StartAnswers() error {
if err := b.startCheck(sectionAnswers); err != nil {
return err
}
b.section = sectionAnswers
return nil
}
// StartAuthorities prepares the builder for packing Authorities.
func (b *Builder) StartAuthorities() error {
if err := b.startCheck(sectionAuthorities); err != nil {
return err
}
b.section = sectionAuthorities
return nil
}
// StartAdditionals prepares the builder for packing Additionals.
func (b *Builder) StartAdditionals() error {
if err := b.startCheck(sectionAdditionals); err != nil {
return err
}
b.section = sectionAdditionals
return nil
}
func (b *Builder) incrementSectionCount() error {
var count *uint16
var err error
switch b.section {
case sectionQuestions:
count = &b.header.questions
err = errTooManyQuestions
case sectionAnswers:
count = &b.header.answers
err = errTooManyAnswers
case sectionAuthorities:
count = &b.header.authorities
err = errTooManyAuthorities
case sectionAdditionals:
count = &b.header.additionals
err = errTooManyAdditionals
}
if *count == ^uint16(0) {
return err
}
*count++
return nil
}
// Question adds a single Question.
func (b *Builder) Question(q Question) error {
if b.section < sectionQuestions {
return ErrNotStarted
}
if b.section > sectionQuestions {
return ErrSectionDone
}
msg, err := q.pack(b.msg, b.compression, b.start)
if err != nil {
return err
}
if err := b.incrementSectionCount(); err != nil {
return err
}
b.msg = msg
return nil
}
func (b *Builder) checkResourceSection() error {
if b.section < sectionAnswers {
return ErrNotStarted
}
if b.section > sectionAdditionals {
return ErrSectionDone
}
return nil
}
// CNAMEResource adds a single CNAMEResource.
func (b *Builder) CNAMEResource(h ResourceHeader, r CNAMEResource) error {
if err := b.checkResourceSection(); err != nil {
return err
}
h.Type = r.realType()
msg, lenOff, err := h.pack(b.msg, b.compression, b.start)
if err != nil {
return &nestedError{"ResourceHeader", err}
}
preLen := len(msg)
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
return &nestedError{"CNAMEResource body", err}
}
if err := h.fixLen(msg, lenOff, preLen); err != nil {
return err
}
if err := b.incrementSectionCount(); err != nil {
return err
}
b.msg = msg
return nil
}
// MXResource adds a single MXResource.
func (b *Builder) MXResource(h ResourceHeader, r MXResource) error {
if err := b.checkResourceSection(); err != nil {
return err
}
h.Type = r.realType()
msg, lenOff, err := h.pack(b.msg, b.compression, b.start)
if err != nil {
return &nestedError{"ResourceHeader", err}
}
preLen := len(msg)
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
return &nestedError{"MXResource body", err}
}
if err := h.fixLen(msg, lenOff, preLen); err != nil {
return err
}
if err := b.incrementSectionCount(); err != nil {
return err
}
b.msg = msg
return nil
}
// NSResource adds a single NSResource.
func (b *Builder) NSResource(h ResourceHeader, r NSResource) error {
if err := b.checkResourceSection(); err != nil {
return err
}
h.Type = r.realType()
msg, lenOff, err := h.pack(b.msg, b.compression, b.start)
if err != nil {
return &nestedError{"ResourceHeader", err}
}
preLen := len(msg)
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
return &nestedError{"NSResource body", err}
}
if err := h.fixLen(msg, lenOff, preLen); err != nil {
return err
}
if err := b.incrementSectionCount(); err != nil {
return err
}
b.msg = msg
return nil
}
// PTRResource adds a single PTRResource.
func (b *Builder) PTRResource(h ResourceHeader, r PTRResource) error {
if err := b.checkResourceSection(); err != nil {
return err
}
h.Type = r.realType()
msg, lenOff, err := h.pack(b.msg, b.compression, b.start)
if err != nil {
return &nestedError{"ResourceHeader", err}
}
preLen := len(msg)
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
return &nestedError{"PTRResource body", err}
}
if err := h.fixLen(msg, lenOff, preLen); err != nil {
return err
}
if err := b.incrementSectionCount(); err != nil {
return err
}
b.msg = msg
return nil
}
// SOAResource adds a single SOAResource.
func (b *Builder) SOAResource(h ResourceHeader, r SOAResource) error {
if err := b.checkResourceSection(); err != nil {
return err
}
h.Type = r.realType()
msg, lenOff, err := h.pack(b.msg, b.compression, b.start)
if err != nil {
return &nestedError{"ResourceHeader", err}
}
preLen := len(msg)
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
return &nestedError{"SOAResource body", err}
}
if err := h.fixLen(msg, lenOff, preLen); err != nil {
return err
}
if err := b.incrementSectionCount(); err != nil {
return err
}
b.msg = msg
return nil
}
// TXTResource adds a single TXTResource.
func (b *Builder) TXTResource(h ResourceHeader, r TXTResource) error {
if err := b.checkResourceSection(); err != nil {
return err
}
h.Type = r.realType()
msg, lenOff, err := h.pack(b.msg, b.compression, b.start)
if err != nil {
return &nestedError{"ResourceHeader", err}
}
preLen := len(msg)
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
return &nestedError{"TXTResource body", err}
}
if err := h.fixLen(msg, lenOff, preLen); err != nil {
return err
}
if err := b.incrementSectionCount(); err != nil {
return err
}
b.msg = msg
return nil
}
// SRVResource adds a single SRVResource.
func (b *Builder) SRVResource(h ResourceHeader, r SRVResource) error {
if err := b.checkResourceSection(); err != nil {
return err
}
h.Type = r.realType()
msg, lenOff, err := h.pack(b.msg, b.compression, b.start)
if err != nil {
return &nestedError{"ResourceHeader", err}
}
preLen := len(msg)
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
return &nestedError{"SRVResource body", err}
}
if err := h.fixLen(msg, lenOff, preLen); err != nil {
return err
}
if err := b.incrementSectionCount(); err != nil {
return err
}
b.msg = msg
return nil
}
// AResource adds a single AResource.
func (b *Builder) AResource(h ResourceHeader, r AResource) error {
if err := b.checkResourceSection(); err != nil {
return err
}
h.Type = r.realType()
msg, lenOff, err := h.pack(b.msg, b.compression, b.start)
if err != nil {
return &nestedError{"ResourceHeader", err}
}
preLen := len(msg)
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
return &nestedError{"AResource body", err}
}
if err := h.fixLen(msg, lenOff, preLen); err != nil {
return err
}
if err := b.incrementSectionCount(); err != nil {
return err
}
b.msg = msg
return nil
}
// AAAAResource adds a single AAAAResource.
func (b *Builder) AAAAResource(h ResourceHeader, r AAAAResource) error {
if err := b.checkResourceSection(); err != nil {
return err
}
h.Type = r.realType()
msg, lenOff, err := h.pack(b.msg, b.compression, b.start)
if err != nil {
return &nestedError{"ResourceHeader", err}
}
preLen := len(msg)
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
return &nestedError{"AAAAResource body", err}
}
if err := h.fixLen(msg, lenOff, preLen); err != nil {
return err
}
if err := b.incrementSectionCount(); err != nil {
return err
}
b.msg = msg
return nil
}
// OPTResource adds a single OPTResource.
func (b *Builder) OPTResource(h ResourceHeader, r OPTResource) error {
if err := b.checkResourceSection(); err != nil {
return err
}
h.Type = r.realType()
msg, lenOff, err := h.pack(b.msg, b.compression, b.start)
if err != nil {
return &nestedError{"ResourceHeader", err}
}
preLen := len(msg)
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
return &nestedError{"OPTResource body", err}
}
if err := h.fixLen(msg, lenOff, preLen); err != nil {
return err
}
if err := b.incrementSectionCount(); err != nil {
return err
}
b.msg = msg
return nil
}
// UnknownResource adds a single UnknownResource.
func (b *Builder) UnknownResource(h ResourceHeader, r UnknownResource) error {
if err := b.checkResourceSection(); err != nil {
return err
}
h.Type = r.realType()
msg, lenOff, err := h.pack(b.msg, b.compression, b.start)
if err != nil {
return &nestedError{"ResourceHeader", err}
}
preLen := len(msg)
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
return &nestedError{"UnknownResource body", err}
}
if err := h.fixLen(msg, lenOff, preLen); err != nil {
return err
}
if err := b.incrementSectionCount(); err != nil {
return err
}
b.msg = msg
return nil
}
// Finish ends message building and generates a binary message.
func (b *Builder) Finish() ([]byte, error) {
if b.section < sectionHeader {
return nil, ErrNotStarted
}
b.section = sectionDone
// Space for the header was allocated in NewBuilder.
b.header.pack(b.msg[b.start:b.start])
return b.msg, nil
}
// A ResourceHeader is the header of a DNS resource record. There are
// many types of DNS resource records, but they all share the same header.
type ResourceHeader struct {
// Name is the domain name for which this resource record pertains.
Name Name
// Type is the type of DNS resource record.
//
// This field will be set automatically during packing.
Type Type
// Class is the class of network to which this DNS resource record
// pertains.
Class Class
// TTL is the length of time (measured in seconds) which this resource
// record is valid for (time to live). All Resources in a set should
// have the same TTL (RFC 2181 Section 5.2).
TTL uint32
// Length is the length of data in the resource record after the header.
//
// This field will be set automatically during packing.
Length uint16
}
// GoString implements fmt.GoStringer.GoString.
func (h *ResourceHeader) GoString() string {
return "dnsmessage.ResourceHeader{" +
"Name: " + h.Name.GoString() + ", " +
"Type: " + h.Type.GoString() + ", " +
"Class: " + h.Class.GoString() + ", " +
"TTL: " + printUint32(h.TTL) + ", " +
"Length: " + printUint16(h.Length) + "}"
}
// pack appends the wire format of the ResourceHeader to oldMsg.
//
// lenOff is the offset in msg where the Length field was packed.
func (h *ResourceHeader) pack(oldMsg []byte, compression map[string]uint16, compressionOff int) (msg []byte, lenOff int, err error) {
msg = oldMsg
if msg, err = h.Name.pack(msg, compression, compressionOff); err != nil {
return oldMsg, 0, &nestedError{"Name", err}
}
msg = packType(msg, h.Type)
msg = packClass(msg, h.Class)
msg = packUint32(msg, h.TTL)
lenOff = len(msg)
msg = packUint16(msg, h.Length)
return msg, lenOff, nil
}
func (h *ResourceHeader) unpack(msg []byte, off int) (int, error) {
newOff := off
var err error
if newOff, err = h.Name.unpack(msg, newOff); err != nil {
return off, &nestedError{"Name", err}
}
if h.Type, newOff, err = unpackType(msg, newOff); err != nil {
return off, &nestedError{"Type", err}
}
if h.Class, newOff, err = unpackClass(msg, newOff); err != nil {
return off, &nestedError{"Class", err}
}
if h.TTL, newOff, err = unpackUint32(msg, newOff); err != nil {
return off, &nestedError{"TTL", err}
}
if h.Length, newOff, err = unpackUint16(msg, newOff); err != nil {
return off, &nestedError{"Length", err}
}
return newOff, nil
}
// fixLen updates a packed ResourceHeader to include the length of the
// ResourceBody.
//
// lenOff is the offset of the ResourceHeader.Length field in msg.
//
// preLen is the length that msg was before the ResourceBody was packed.
func (h *ResourceHeader) fixLen(msg []byte, lenOff int, preLen int) error {
conLen := len(msg) - preLen
if conLen > int(^uint16(0)) {
return errResTooLong
}
// Fill in the length now that we know how long the content is.
packUint16(msg[lenOff:lenOff], uint16(conLen))
h.Length = uint16(conLen)
return nil
}
// EDNS(0) wire constants.
const (
edns0Version = 0
edns0DNSSECOK = 0x00008000
ednsVersionMask = 0x00ff0000
edns0DNSSECOKMask = 0x00ff8000
)
// SetEDNS0 configures h for EDNS(0).
//
// The provided extRCode must be an extended RCode.
func (h *ResourceHeader) SetEDNS0(udpPayloadLen int, extRCode RCode, dnssecOK bool) error {
h.Name = Name{Data: [255]byte{'.'}, Length: 1} // RFC 6891 section 6.1.2
h.Type = TypeOPT
h.Class = Class(udpPayloadLen)
h.TTL = uint32(extRCode) >> 4 << 24
if dnssecOK {
h.TTL |= edns0DNSSECOK
}
return nil
}
// DNSSECAllowed reports whether the DNSSEC OK bit is set.
func (h *ResourceHeader) DNSSECAllowed() bool {
return h.TTL&edns0DNSSECOKMask == edns0DNSSECOK // RFC 6891 section 6.1.3
}
// ExtendedRCode returns an extended RCode.
//
// The provided rcode must be the RCode in DNS message header.
func (h *ResourceHeader) ExtendedRCode(rcode RCode) RCode {
if h.TTL&ednsVersionMask == edns0Version { // RFC 6891 section 6.1.3
return RCode(h.TTL>>24<<4) | rcode
}
return rcode
}
func skipResource(msg []byte, off int) (int, error) {
newOff, err := skipName(msg, off)
if err != nil {
return off, &nestedError{"Name", err}
}
if newOff, err = skipType(msg, newOff); err != nil {
return off, &nestedError{"Type", err}
}
if newOff, err = skipClass(msg, newOff); err != nil {
return off, &nestedError{"Class", err}
}
if newOff, err = skipUint32(msg, newOff); err != nil {
return off, &nestedError{"TTL", err}
}
length, newOff, err := unpackUint16(msg, newOff)
if err != nil {
return off, &nestedError{"Length", err}
}
if newOff += int(length); newOff > len(msg) {
return off, errResourceLen
}
return newOff, nil
}
// packUint16 appends the wire format of field to msg.
func packUint16(msg []byte, field uint16) []byte {
return append(msg, byte(field>>8), byte(field))
}
func unpackUint16(msg []byte, off int) (uint16, int, error) {
if off+uint16Len > len(msg) {
return 0, off, errBaseLen
}
return uint16(msg[off])<<8 | uint16(msg[off+1]), off + uint16Len, nil
}
func skipUint16(msg []byte, off int) (int, error) {
if off+uint16Len > len(msg) {
return off, errBaseLen
}
return off + uint16Len, nil
}
// packType appends the wire format of field to msg.
func packType(msg []byte, field Type) []byte {
return packUint16(msg, uint16(field))
}
func unpackType(msg []byte, off int) (Type, int, error) {
t, o, err := unpackUint16(msg, off)
return Type(t), o, err
}
func skipType(msg []byte, off int) (int, error) {
return skipUint16(msg, off)
}
// packClass appends the wire format of field to msg.
func packClass(msg []byte, field Class) []byte {
return packUint16(msg, uint16(field))
}
func unpackClass(msg []byte, off int) (Class, int, error) {
c, o, err := unpackUint16(msg, off)
return Class(c), o, err
}
func skipClass(msg []byte, off int) (int, error) {
return skipUint16(msg, off)
}
// packUint32 appends the wire format of field to msg.
func packUint32(msg []byte, field uint32) []byte {
return append(
msg,
byte(field>>24),
byte(field>>16),
byte(field>>8),
byte(field),
)
}
func unpackUint32(msg []byte, off int) (uint32, int, error) {
if off+uint32Len > len(msg) {
return 0, off, errBaseLen
}
v := uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3])
return v, off + uint32Len, nil
}
func skipUint32(msg []byte, off int) (int, error) {
if off+uint32Len > len(msg) {
return off, errBaseLen
}
return off + uint32Len, nil
}
// packText appends the wire format of field to msg.
func packText(msg []byte, field string) ([]byte, error) {
l := len(field)
if l > 255 {
return nil, errStringTooLong
}
msg = append(msg, byte(l))
msg = append(msg, field...)
return msg, nil
}
func unpackText(msg []byte, off int) (string, int, error) {
if off >= len(msg) {
return "", off, errBaseLen
}
beginOff := off + 1
endOff := beginOff + int(msg[off])
if endOff > len(msg) {
return "", off, errCalcLen
}
return string(msg[beginOff:endOff]), endOff, nil
}
// packBytes appends the wire format of field to msg.
func packBytes(msg []byte, field []byte) []byte {
return append(msg, field...)
}
func unpackBytes(msg []byte, off int, field []byte) (int, error) {
newOff := off + len(field)
if newOff > len(msg) {
return off, errBaseLen
}
copy(field, msg[off:newOff])
return newOff, nil
}
const nonEncodedNameMax = 254
// A Name is a non-encoded and non-escaped domain name. It is used instead of strings to avoid
// allocations.
type Name struct {
Data [255]byte
Length uint8
}
// NewName creates a new Name from a string.
func NewName(name string) (Name, error) {
n := Name{Length: uint8(len(name))}
if len(name) > len(n.Data) {
return Name{}, errCalcLen
}
copy(n.Data[:], name)
return n, nil
}
// MustNewName creates a new Name from a string and panics on error.
func MustNewName(name string) Name {
n, err := NewName(name)
if err != nil {
panic("creating name: " + err.Error())
}
return n
}
// String implements fmt.Stringer.String.
//
// Note: characters inside the labels are not escaped in any way.
func (n Name) String() string {
return string(n.Data[:n.Length])
}
// GoString implements fmt.GoStringer.GoString.
func (n *Name) GoString() string {
return `dnsmessage.MustNewName("` + printString(n.Data[:n.Length]) + `")`
}
// pack appends the wire format of the Name to msg.
//
// Domain names are a sequence of counted strings split at the dots. They end
// with a zero-length string. Compression can be used to reuse domain suffixes.
//
// The compression map will be updated with new domain suffixes. If compression
// is nil, compression will not be used.
func (n *Name) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) {
oldMsg := msg
if n.Length > nonEncodedNameMax {
return nil, errNameTooLong
}
// Add a trailing dot to canonicalize name.
if n.Length == 0 || n.Data[n.Length-1] != '.' {
return oldMsg, errNonCanonicalName
}
// Allow root domain.
if n.Data[0] == '.' && n.Length == 1 {
return append(msg, 0), nil
}
var nameAsStr string
// Emit sequence of counted strings, chopping at dots.
for i, begin := 0, 0; i < int(n.Length); i++ {
// Check for the end of the segment.
if n.Data[i] == '.' {
// The two most significant bits have special meaning.
// It isn't allowed for segments to be long enough to
// need them.
if i-begin >= 1<<6 {
return oldMsg, errSegTooLong
}
// Segments must have a non-zero length.
if i-begin == 0 {
return oldMsg, errZeroSegLen
}
msg = append(msg, byte(i-begin))
for j := begin; j < i; j++ {
msg = append(msg, n.Data[j])
}
begin = i + 1
continue
}
// We can only compress domain suffixes starting with a new
// segment. A pointer is two bytes with the two most significant
// bits set to 1 to indicate that it is a pointer.
if (i == 0 || n.Data[i-1] == '.') && compression != nil {
if ptr, ok := compression[string(n.Data[i:n.Length])]; ok {
// Hit. Emit a pointer instead of the rest of
// the domain.
return append(msg, byte(ptr>>8|0xC0), byte(ptr)), nil
}
// Miss. Add the suffix to the compression table if the
// offset can be stored in the available 14 bits.
newPtr := len(msg) - compressionOff
if newPtr <= int(^uint16(0)>>2) {
if nameAsStr == "" {
// allocate n.Data on the heap once, to avoid allocating it
// multiple times (for next labels).
nameAsStr = string(n.Data[:n.Length])
}
compression[nameAsStr[i:]] = uint16(newPtr)
}
}
}
return append(msg, 0), nil
}
// unpack unpacks a domain name.
func (n *Name) unpack(msg []byte, off int) (int, error) {
// currOff is the current working offset.
currOff := off
// newOff is the offset where the next record will start. Pointers lead
// to data that belongs to other names and thus doesn't count towards to
// the usage of this name.
newOff := off
// ptr is the number of pointers followed.
var ptr int
// Name is a slice representation of the name data.
name := n.Data[:0]
Loop:
for {
if currOff >= len(msg) {
return off, errBaseLen
}
c := int(msg[currOff])
currOff++
switch c & 0xC0 {
case 0x00: // String segment
if c == 0x00 {
// A zero length signals the end of the name.
break Loop
}
endOff := currOff + c
if endOff > len(msg) {
return off, errCalcLen
}
// Reject names containing dots.
// See issue golang/go#56246
for _, v := range msg[currOff:endOff] {
if v == '.' {
return off, errInvalidName
}
}
name = append(name, msg[currOff:endOff]...)
name = append(name, '.')
currOff = endOff
case 0xC0: // Pointer
if currOff >= len(msg) {
return off, errInvalidPtr
}
c1 := msg[currOff]
currOff++
if ptr == 0 {
newOff = currOff
}
// Don't follow too many pointers, maybe there's a loop.
if ptr++; ptr > 10 {
return off, errTooManyPtr
}
currOff = (c^0xC0)<<8 | int(c1)
default:
// Prefixes 0x80 and 0x40 are reserved.
return off, errReserved
}
}
if len(name) == 0 {
name = append(name, '.')
}
if len(name) > nonEncodedNameMax {
return off, errNameTooLong
}
n.Length = uint8(len(name))
if ptr == 0 {
newOff = currOff
}
return newOff, nil
}
func skipName(msg []byte, off int) (int, error) {
// newOff is the offset where the next record will start. Pointers lead
// to data that belongs to other names and thus doesn't count towards to
// the usage of this name.
newOff := off
Loop:
for {
if newOff >= len(msg) {
return off, errBaseLen
}
c := int(msg[newOff])
newOff++
switch c & 0xC0 {
case 0x00:
if c == 0x00 {
// A zero length signals the end of the name.
break Loop
}
// literal string
newOff += c
if newOff > len(msg) {
return off, errCalcLen
}
case 0xC0:
// Pointer to somewhere else in msg.
// Pointers are two bytes.
newOff++
// Don't follow the pointer as the data here has ended.
break Loop
default:
// Prefixes 0x80 and 0x40 are reserved.
return off, errReserved
}
}
return newOff, nil
}
// A Question is a DNS query.
type Question struct {
Name Name
Type Type
Class Class
}
// pack appends the wire format of the Question to msg.
func (q *Question) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) {
msg, err := q.Name.pack(msg, compression, compressionOff)
if err != nil {
return msg, &nestedError{"Name", err}
}
msg = packType(msg, q.Type)
return packClass(msg, q.Class), nil
}
// GoString implements fmt.GoStringer.GoString.
func (q *Question) GoString() string {
return "dnsmessage.Question{" +
"Name: " + q.Name.GoString() + ", " +
"Type: " + q.Type.GoString() + ", " +
"Class: " + q.Class.GoString() + "}"
}
func unpackResourceBody(msg []byte, off int, hdr ResourceHeader) (ResourceBody, int, error) {
var (
r ResourceBody
err error
name string
)
switch hdr.Type {
case TypeA:
var rb AResource
rb, err = unpackAResource(msg, off)
r = &rb
name = "A"
case TypeNS:
var rb NSResource
rb, err = unpackNSResource(msg, off)
r = &rb
name = "NS"
case TypeCNAME:
var rb CNAMEResource
rb, err = unpackCNAMEResource(msg, off)
r = &rb
name = "CNAME"
case TypeSOA:
var rb SOAResource
rb, err = unpackSOAResource(msg, off)
r = &rb
name = "SOA"
case TypePTR:
var rb PTRResource
rb, err = unpackPTRResource(msg, off)
r = &rb
name = "PTR"
case TypeMX:
var rb MXResource
rb, err = unpackMXResource(msg, off)
r = &rb
name = "MX"
case TypeTXT:
var rb TXTResource
rb, err = unpackTXTResource(msg, off, hdr.Length)
r = &rb
name = "TXT"
case TypeAAAA:
var rb AAAAResource
rb, err = unpackAAAAResource(msg, off)
r = &rb
name = "AAAA"
case TypeSRV:
var rb SRVResource
rb, err = unpackSRVResource(msg, off)
r = &rb
name = "SRV"
case TypeSVCB:
var rb SVCBResource
rb, err = unpackSVCBResource(msg, off, hdr.Length)
r = &rb
name = "SVCB"
case TypeHTTPS:
var rb HTTPSResource
rb.SVCBResource, err = unpackSVCBResource(msg, off, hdr.Length)
r = &rb
name = "HTTPS"
case TypeOPT:
var rb OPTResource
rb, err = unpackOPTResource(msg, off, hdr.Length)
r = &rb
name = "OPT"
default:
var rb UnknownResource
rb, err = unpackUnknownResource(hdr.Type, msg, off, hdr.Length)
r = &rb
name = "Unknown"
}
if err != nil {
return nil, off, &nestedError{name + " record", err}
}
return r, off + int(hdr.Length), nil
}
// A CNAMEResource is a CNAME Resource record.
type CNAMEResource struct {
CNAME Name
}
func (r *CNAMEResource) realType() Type {
return TypeCNAME
}
// pack appends the wire format of the CNAMEResource to msg.
func (r *CNAMEResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) {
return r.CNAME.pack(msg, compression, compressionOff)
}
// GoString implements fmt.GoStringer.GoString.
func (r *CNAMEResource) GoString() string {
return "dnsmessage.CNAMEResource{CNAME: " + r.CNAME.GoString() + "}"
}
func unpackCNAMEResource(msg []byte, off int) (CNAMEResource, error) {
var cname Name
if _, err := cname.unpack(msg, off); err != nil {
return CNAMEResource{}, err
}
return CNAMEResource{cname}, nil
}
// An MXResource is an MX Resource record.
type MXResource struct {
Pref uint16
MX Name
}
func (r *MXResource) realType() Type {
return TypeMX
}
// pack appends the wire format of the MXResource to msg.
func (r *MXResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) {
oldMsg := msg
msg = packUint16(msg, r.Pref)
msg, err := r.MX.pack(msg, compression, compressionOff)
if err != nil {
return oldMsg, &nestedError{"MXResource.MX", err}
}
return msg, nil
}
// GoString implements fmt.GoStringer.GoString.
func (r *MXResource) GoString() string {
return "dnsmessage.MXResource{" +
"Pref: " + printUint16(r.Pref) + ", " +
"MX: " + r.MX.GoString() + "}"
}
func unpackMXResource(msg []byte, off int) (MXResource, error) {
pref, off, err := unpackUint16(msg, off)
if err != nil {
return MXResource{}, &nestedError{"Pref", err}
}
var mx Name
if _, err := mx.unpack(msg, off); err != nil {
return MXResource{}, &nestedError{"MX", err}
}
return MXResource{pref, mx}, nil
}
// An NSResource is an NS Resource record.
type NSResource struct {
NS Name
}
func (r *NSResource) realType() Type {
return TypeNS
}
// pack appends the wire format of the NSResource to msg.
func (r *NSResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) {
return r.NS.pack(msg, compression, compressionOff)
}
// GoString implements fmt.GoStringer.GoString.
func (r *NSResource) GoString() string {
return "dnsmessage.NSResource{NS: " + r.NS.GoString() + "}"
}
func unpackNSResource(msg []byte, off int) (NSResource, error) {
var ns Name
if _, err := ns.unpack(msg, off); err != nil {
return NSResource{}, err
}
return NSResource{ns}, nil
}
// A PTRResource is a PTR Resource record.
type PTRResource struct {
PTR Name
}
func (r *PTRResource) realType() Type {
return TypePTR
}
// pack appends the wire format of the PTRResource to msg.
func (r *PTRResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) {
return r.PTR.pack(msg, compression, compressionOff)
}
// GoString implements fmt.GoStringer.GoString.
func (r *PTRResource) GoString() string {
return "dnsmessage.PTRResource{PTR: " + r.PTR.GoString() + "}"
}
func unpackPTRResource(msg []byte, off int) (PTRResource, error) {
var ptr Name
if _, err := ptr.unpack(msg, off); err != nil {
return PTRResource{}, err
}
return PTRResource{ptr}, nil
}
// An SOAResource is an SOA Resource record.
type SOAResource struct {
NS Name
MBox Name
Serial uint32
Refresh uint32
Retry uint32
Expire uint32
// MinTTL the is the default TTL of Resources records which did not
// contain a TTL value and the TTL of negative responses. (RFC 2308
// Section 4)
MinTTL uint32
}
func (r *SOAResource) realType() Type {
return TypeSOA
}
// pack appends the wire format of the SOAResource to msg.
func (r *SOAResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) {
oldMsg := msg
msg, err := r.NS.pack(msg, compression, compressionOff)
if err != nil {
return oldMsg, &nestedError{"SOAResource.NS", err}
}
msg, err = r.MBox.pack(msg, compression, compressionOff)
if err != nil {
return oldMsg, &nestedError{"SOAResource.MBox", err}
}
msg = packUint32(msg, r.Serial)
msg = packUint32(msg, r.Refresh)
msg = packUint32(msg, r.Retry)
msg = packUint32(msg, r.Expire)
return packUint32(msg, r.MinTTL), nil
}
// GoString implements fmt.GoStringer.GoString.
func (r *SOAResource) GoString() string {
return "dnsmessage.SOAResource{" +
"NS: " + r.NS.GoString() + ", " +
"MBox: " + r.MBox.GoString() + ", " +
"Serial: " + printUint32(r.Serial) + ", " +
"Refresh: " + printUint32(r.Refresh) + ", " +
"Retry: " + printUint32(r.Retry) + ", " +
"Expire: " + printUint32(r.Expire) + ", " +
"MinTTL: " + printUint32(r.MinTTL) + "}"
}
func unpackSOAResource(msg []byte, off int) (SOAResource, error) {
var ns Name
off, err := ns.unpack(msg, off)
if err != nil {
return SOAResource{}, &nestedError{"NS", err}
}
var mbox Name
if off, err = mbox.unpack(msg, off); err != nil {
return SOAResource{}, &nestedError{"MBox", err}
}
serial, off, err := unpackUint32(msg, off)
if err != nil {
return SOAResource{}, &nestedError{"Serial", err}
}
refresh, off, err := unpackUint32(msg, off)
if err != nil {
return SOAResource{}, &nestedError{"Refresh", err}
}
retry, off, err := unpackUint32(msg, off)
if err != nil {
return SOAResource{}, &nestedError{"Retry", err}
}
expire, off, err := unpackUint32(msg, off)
if err != nil {
return SOAResource{}, &nestedError{"Expire", err}
}
minTTL, _, err := unpackUint32(msg, off)
if err != nil {
return SOAResource{}, &nestedError{"MinTTL", err}
}
return SOAResource{ns, mbox, serial, refresh, retry, expire, minTTL}, nil
}
// A TXTResource is a TXT Resource record.
type TXTResource struct {
TXT []string
}
func (r *TXTResource) realType() Type {
return TypeTXT
}
// pack appends the wire format of the TXTResource to msg.
func (r *TXTResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) {
oldMsg := msg
for _, s := range r.TXT {
var err error
msg, err = packText(msg, s)
if err != nil {
return oldMsg, err
}
}
return msg, nil
}
// GoString implements fmt.GoStringer.GoString.
func (r *TXTResource) GoString() string {
s := "dnsmessage.TXTResource{TXT: []string{"
if len(r.TXT) == 0 {
return s + "}}"
}
s += `"` + printString([]byte(r.TXT[0]))
for _, t := range r.TXT[1:] {
s += `", "` + printString([]byte(t))
}
return s + `"}}`
}
func unpackTXTResource(msg []byte, off int, length uint16) (TXTResource, error) {
txts := make([]string, 0, 1)
for n := uint16(0); n < length; {
var t string
var err error
if t, off, err = unpackText(msg, off); err != nil {
return TXTResource{}, &nestedError{"text", err}
}
// Check if we got too many bytes.
if length-n < uint16(len(t))+1 {
return TXTResource{}, errCalcLen
}
n += uint16(len(t)) + 1
txts = append(txts, t)
}
return TXTResource{txts}, nil
}
// An SRVResource is an SRV Resource record.
type SRVResource struct {
Priority uint16
Weight uint16
Port uint16
Target Name // Not compressed as per RFC 2782.
}
func (r *SRVResource) realType() Type {
return TypeSRV
}
// pack appends the wire format of the SRVResource to msg.
func (r *SRVResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) {
oldMsg := msg
msg = packUint16(msg, r.Priority)
msg = packUint16(msg, r.Weight)
msg = packUint16(msg, r.Port)
msg, err := r.Target.pack(msg, nil, compressionOff)
if err != nil {
return oldMsg, &nestedError{"SRVResource.Target", err}
}
return msg, nil
}
// GoString implements fmt.GoStringer.GoString.
func (r *SRVResource) GoString() string {
return "dnsmessage.SRVResource{" +
"Priority: " + printUint16(r.Priority) + ", " +
"Weight: " + printUint16(r.Weight) + ", " +
"Port: " + printUint16(r.Port) + ", " +
"Target: " + r.Target.GoString() + "}"
}
func unpackSRVResource(msg []byte, off int) (SRVResource, error) {
priority, off, err := unpackUint16(msg, off)
if err != nil {
return SRVResource{}, &nestedError{"Priority", err}
}
weight, off, err := unpackUint16(msg, off)
if err != nil {
return SRVResource{}, &nestedError{"Weight", err}
}
port, off, err := unpackUint16(msg, off)
if err != nil {
return SRVResource{}, &nestedError{"Port", err}
}
var target Name
if _, err := target.unpack(msg, off); err != nil {
return SRVResource{}, &nestedError{"Target", err}
}
return SRVResource{priority, weight, port, target}, nil
}
// An AResource is an A Resource record.
type AResource struct {
A [4]byte
}
func (r *AResource) realType() Type {
return TypeA
}
// pack appends the wire format of the AResource to msg.
func (r *AResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) {
return packBytes(msg, r.A[:]), nil
}
// GoString implements fmt.GoStringer.GoString.
func (r *AResource) GoString() string {
return "dnsmessage.AResource{" +
"A: [4]byte{" + printByteSlice(r.A[:]) + "}}"
}
func unpackAResource(msg []byte, off int) (AResource, error) {
var a [4]byte
if _, err := unpackBytes(msg, off, a[:]); err != nil {
return AResource{}, err
}
return AResource{a}, nil
}
// An AAAAResource is an AAAA Resource record.
type AAAAResource struct {
AAAA [16]byte
}
func (r *AAAAResource) realType() Type {
return TypeAAAA
}
// GoString implements fmt.GoStringer.GoString.
func (r *AAAAResource) GoString() string {
return "dnsmessage.AAAAResource{" +
"AAAA: [16]byte{" + printByteSlice(r.AAAA[:]) + "}}"
}
// pack appends the wire format of the AAAAResource to msg.
func (r *AAAAResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) {
return packBytes(msg, r.AAAA[:]), nil
}
func unpackAAAAResource(msg []byte, off int) (AAAAResource, error) {
var aaaa [16]byte
if _, err := unpackBytes(msg, off, aaaa[:]); err != nil {
return AAAAResource{}, err
}
return AAAAResource{aaaa}, nil
}
// An OPTResource is an OPT pseudo Resource record.
//
// The pseudo resource record is part of the extension mechanisms for DNS
// as defined in RFC 6891.
type OPTResource struct {
Options []Option
}
// An Option represents a DNS message option within OPTResource.
//
// The message option is part of the extension mechanisms for DNS as
// defined in RFC 6891.
type Option struct {
Code uint16 // option code
Data []byte
}
// GoString implements fmt.GoStringer.GoString.
func (o *Option) GoString() string {
return "dnsmessage.Option{" +
"Code: " + printUint16(o.Code) + ", " +
"Data: []byte{" + printByteSlice(o.Data) + "}}"
}
func (r *OPTResource) realType() Type {
return TypeOPT
}
func (r *OPTResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) {
for _, opt := range r.Options {
msg = packUint16(msg, opt.Code)
l := uint16(len(opt.Data))
msg = packUint16(msg, l)
msg = packBytes(msg, opt.Data)
}
return msg, nil
}
// GoString implements fmt.GoStringer.GoString.
func (r *OPTResource) GoString() string {
s := "dnsmessage.OPTResource{Options: []dnsmessage.Option{"
if len(r.Options) == 0 {
return s + "}}"
}
s += r.Options[0].GoString()
for _, o := range r.Options[1:] {
s += ", " + o.GoString()
}
return s + "}}"
}
func unpackOPTResource(msg []byte, off int, length uint16) (OPTResource, error) {
var opts []Option
for oldOff := off; off < oldOff+int(length); {
var err error
var o Option
o.Code, off, err = unpackUint16(msg, off)
if err != nil {
return OPTResource{}, &nestedError{"Code", err}
}
var l uint16
l, off, err = unpackUint16(msg, off)
if err != nil {
return OPTResource{}, &nestedError{"Data", err}
}
o.Data = make([]byte, l)
if copy(o.Data, msg[off:]) != int(l) {
return OPTResource{}, &nestedError{"Data", errCalcLen}
}
off += int(l)
opts = append(opts, o)
}
return OPTResource{opts}, nil
}
// An UnknownResource is a catch-all container for unknown record types.
type UnknownResource struct {
Type Type
Data []byte
}
func (r *UnknownResource) realType() Type {
return r.Type
}
// pack appends the wire format of the UnknownResource to msg.
func (r *UnknownResource) pack(msg []byte, compression map[string]uint16, compressionOff int) ([]byte, error) {
return packBytes(msg, r.Data[:]), nil
}
// GoString implements fmt.GoStringer.GoString.
func (r *UnknownResource) GoString() string {
return "dnsmessage.UnknownResource{" +
"Type: " + r.Type.GoString() + ", " +
"Data: []byte{" + printByteSlice(r.Data) + "}}"
}
func unpackUnknownResource(recordType Type, msg []byte, off int, length uint16) (UnknownResource, error) {
parsed := UnknownResource{
Type: recordType,
Data: make([]byte, length),
}
if _, err := unpackBytes(msg, off, parsed.Data); err != nil {
return UnknownResource{}, err
}
return parsed, nil
}
// Copyright 2025 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 (
"math"
"slices"
"strings"
)
// An SVCBResource is an SVCB Resource record.
type SVCBResource struct {
Priority uint16
Target Name
Params []SVCParam // Must be in strict increasing order by Key.
}
func (r *SVCBResource) realType() Type {
return TypeSVCB
}
// GoString implements fmt.GoStringer.GoString.
func (r *SVCBResource) GoString() string {
var b strings.Builder
b.WriteString("dnsmessage.SVCBResource{")
b.WriteString("Priority: " + printUint16(r.Priority) + ", ")
b.WriteString("Target: " + r.Target.GoString() + ", ")
b.WriteString("Params: []dnsmessage.SVCParam{")
if len(r.Params) > 0 {
b.WriteString(r.Params[0].GoString())
for _, p := range r.Params[1:] {
b.WriteString(", " + p.GoString())
}
}
b.WriteString("}}")
return b.String()
}
// An HTTPSResource is an HTTPS Resource record.
// It has the same format as the SVCB record.
type HTTPSResource struct {
// Alias for SVCB resource record.
SVCBResource
}
func (r *HTTPSResource) realType() Type {
return TypeHTTPS
}
// GoString implements fmt.GoStringer.GoString.
func (r *HTTPSResource) GoString() string {
return "dnsmessage.HTTPSResource{SVCBResource: " + r.SVCBResource.GoString() + "}"
}
// GetParam returns a parameter value by key.
func (r *SVCBResource) GetParam(key SVCParamKey) (value []byte, ok bool) {
for i := range r.Params {
if r.Params[i].Key == key {
return r.Params[i].Value, true
}
if r.Params[i].Key > key {
break
}
}
return nil, false
}
// SetParam sets a parameter value by key.
// The Params list is kept sorted by key.
func (r *SVCBResource) SetParam(key SVCParamKey, value []byte) {
i := 0
for i < len(r.Params) {
if r.Params[i].Key >= key {
break
}
i++
}
if i < len(r.Params) && r.Params[i].Key == key {
r.Params[i].Value = value
return
}
r.Params = slices.Insert(r.Params, i, SVCParam{Key: key, Value: value})
}
// DeleteParam deletes a parameter by key.
// It returns true if the parameter was present.
func (r *SVCBResource) DeleteParam(key SVCParamKey) bool {
for i := range r.Params {
if r.Params[i].Key == key {
r.Params = slices.Delete(r.Params, i, i+1)
return true
}
if r.Params[i].Key > key {
break
}
}
return false
}
// A SVCParam is a service parameter.
type SVCParam struct {
Key SVCParamKey
Value []byte
}
// GoString implements fmt.GoStringer.GoString.
func (p SVCParam) GoString() string {
return "dnsmessage.SVCParam{" +
"Key: " + p.Key.GoString() + ", " +
"Value: []byte{" + printByteSlice(p.Value) + "}}"
}
// A SVCParamKey is a key for a service parameter.
type SVCParamKey uint16
// Values defined at https://www.iana.org/assignments/dns-svcb/dns-svcb.xhtml#dns-svcparamkeys.
const (
SVCParamMandatory SVCParamKey = 0
SVCParamALPN SVCParamKey = 1
SVCParamNoDefaultALPN SVCParamKey = 2
SVCParamPort SVCParamKey = 3
SVCParamIPv4Hint SVCParamKey = 4
SVCParamECH SVCParamKey = 5
SVCParamIPv6Hint SVCParamKey = 6
SVCParamDOHPath SVCParamKey = 7
SVCParamOHTTP SVCParamKey = 8
SVCParamTLSSupportedGroups SVCParamKey = 9
)
var svcParamKeyNames = map[SVCParamKey]string{
SVCParamMandatory: "Mandatory",
SVCParamALPN: "ALPN",
SVCParamNoDefaultALPN: "NoDefaultALPN",
SVCParamPort: "Port",
SVCParamIPv4Hint: "IPv4Hint",
SVCParamECH: "ECH",
SVCParamIPv6Hint: "IPv6Hint",
SVCParamDOHPath: "DOHPath",
SVCParamOHTTP: "OHTTP",
SVCParamTLSSupportedGroups: "TLSSupportedGroups",
}
// String implements fmt.Stringer.String.
func (k SVCParamKey) String() string {
if n, ok := svcParamKeyNames[k]; ok {
return n
}
return printUint16(uint16(k))
}
// GoString implements fmt.GoStringer.GoString.
func (k SVCParamKey) GoString() string {
if n, ok := svcParamKeyNames[k]; ok {
return "dnsmessage.SVCParam" + n
}
return printUint16(uint16(k))
}
func (r *SVCBResource) pack(msg []byte, _ map[string]uint16, _ int) ([]byte, error) {
oldMsg := msg
msg = packUint16(msg, r.Priority)
// https://datatracker.ietf.org/doc/html/rfc3597#section-4 prohibits name
// compression for RR types that are not "well-known".
// https://datatracker.ietf.org/doc/html/rfc9460#section-2.2 explicitly states that
// compression of the Target is prohibited, following RFC 3597.
msg, err := r.Target.pack(msg, nil, 0)
if err != nil {
return oldMsg, &nestedError{"SVCBResource.Target", err}
}
var previousKey SVCParamKey
for i, param := range r.Params {
if i > 0 && param.Key <= previousKey {
return oldMsg, &nestedError{"SVCBResource.Params", errParamOutOfOrder}
}
if len(param.Value) > math.MaxUint16 {
return oldMsg, &nestedError{"SVCBResource.Params", errTooLongSVCBValue}
}
msg = packUint16(msg, uint16(param.Key))
msg = packUint16(msg, uint16(len(param.Value)))
msg = append(msg, param.Value...)
}
return msg, nil
}
func unpackSVCBResource(msg []byte, off int, length uint16) (SVCBResource, error) {
// Wire format reference: https://www.rfc-editor.org/rfc/rfc9460.html#section-2.2.
r := SVCBResource{}
paramsOff := off
bodyEnd := off + int(length)
var err error
if r.Priority, paramsOff, err = unpackUint16(msg, paramsOff); err != nil {
return SVCBResource{}, &nestedError{"Priority", err}
}
if paramsOff, err = r.Target.unpack(msg, paramsOff); err != nil {
return SVCBResource{}, &nestedError{"Target", err}
}
// Two-pass parsing to avoid allocations.
// First, count the number of params.
n := 0
var totalValueLen uint16
off = paramsOff
var previousKey uint16
for off < bodyEnd {
var key, len uint16
if key, off, err = unpackUint16(msg, off); err != nil {
return SVCBResource{}, &nestedError{"Params key", err}
}
if n > 0 && key <= previousKey {
// As per https://www.rfc-editor.org/rfc/rfc9460.html#section-2.2, clients MUST
// consider the RR malformed if the SvcParamKeys are not in strictly increasing numeric order
return SVCBResource{}, &nestedError{"Params", errParamOutOfOrder}
}
if len, off, err = unpackUint16(msg, off); err != nil {
return SVCBResource{}, &nestedError{"Params value length", err}
}
if off+int(len) > bodyEnd {
return SVCBResource{}, errResourceLen
}
totalValueLen += len
off += int(len)
n++
}
if off != bodyEnd {
return SVCBResource{}, errResourceLen
}
// Second, fill in the params.
r.Params = make([]SVCParam, n)
// valuesBuf is used to hold all param values to reduce allocations.
// Each param's Value slice will point into this buffer.
valuesBuf := make([]byte, totalValueLen)
off = paramsOff
for i := 0; i < n; i++ {
p := &r.Params[i]
var key, len uint16
if key, off, err = unpackUint16(msg, off); err != nil {
return SVCBResource{}, &nestedError{"param key", err}
}
p.Key = SVCParamKey(key)
if len, off, err = unpackUint16(msg, off); err != nil {
return SVCBResource{}, &nestedError{"param length", err}
}
if copy(valuesBuf, msg[off:off+int(len)]) != int(len) {
return SVCBResource{}, &nestedError{"param value", errCalcLen}
}
p.Value = valuesBuf[:len:len]
valuesBuf = valuesBuf[len:]
off += int(len)
}
return r, nil
}
// genericSVCBResource parses a single Resource Record compatible with SVCB.
func (p *Parser) genericSVCBResource(svcbType Type) (SVCBResource, error) {
if !p.resHeaderValid || p.resHeaderType != svcbType {
return SVCBResource{}, ErrNotStarted
}
r, err := unpackSVCBResource(p.msg, p.off, p.resHeaderLength)
if err != nil {
return SVCBResource{}, err
}
p.off += int(p.resHeaderLength)
p.resHeaderValid = false
p.index++
return r, nil
}
// SVCBResource parses a single SVCBResource.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) SVCBResource() (SVCBResource, error) {
return p.genericSVCBResource(TypeSVCB)
}
// HTTPSResource parses a single HTTPSResource.
//
// One of the XXXHeader methods must have been called before calling this
// method.
func (p *Parser) HTTPSResource() (HTTPSResource, error) {
svcb, err := p.genericSVCBResource(TypeHTTPS)
if err != nil {
return HTTPSResource{}, err
}
return HTTPSResource{svcb}, nil
}
// genericSVCBResource is the generic implementation for adding SVCB-like resources.
func (b *Builder) genericSVCBResource(h ResourceHeader, r SVCBResource) error {
if err := b.checkResourceSection(); err != nil {
return err
}
msg, lenOff, err := h.pack(b.msg, b.compression, b.start)
if err != nil {
return &nestedError{"ResourceHeader", err}
}
preLen := len(msg)
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
return &nestedError{"ResourceBody", err}
}
if err := h.fixLen(msg, lenOff, preLen); err != nil {
return err
}
if err := b.incrementSectionCount(); err != nil {
return err
}
b.msg = msg
return nil
}
// SVCBResource adds a single SVCBResource.
func (b *Builder) SVCBResource(h ResourceHeader, r SVCBResource) error {
h.Type = r.realType()
return b.genericSVCBResource(h, r)
}
// HTTPSResource adds a single HTTPSResource.
func (b *Builder) HTTPSResource(h ResourceHeader, r HTTPSResource) error {
h.Type = r.realType()
return b.genericSVCBResource(h, r.SVCBResource)
}
//go:build gofuzz
package fuzz_ng_x_net_context
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/net/context"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var ContextResults []*context.Context
ContextResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Background:
r0 := context.Background()
ContextResults = append(ContextResults, &r0)
case *NgoloFuzzOne_TODO:
r0 := context.TODO()
ContextResults = append(ContextResults, &r0)
case *NgoloFuzzOne_WithCancel:
if len(ContextResults) == 0 {
continue
}
arg0 := *ContextResults[ContextResultsIndex]
ContextResultsIndex = (ContextResultsIndex + 1) % len(ContextResults)
r0, _ := context.WithCancel(arg0)
ContextResults = append(ContextResults, &r0)
case *NgoloFuzzOne_WithValue:
if len(ContextResults) == 0 {
continue
}
arg0 := *ContextResults[ContextResultsIndex]
ContextResultsIndex = (ContextResultsIndex + 1) % len(ContextResults)
r0 := context.WithValue(arg0, a.WithValue.Key, a.WithValue.Val)
ContextResults = append(ContextResults, &r0)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
ContextNb := 0
ContextResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Background:
w.WriteString(fmt.Sprintf("Context%d := context.Background()\n", ContextNb))
ContextNb = ContextNb + 1
case *NgoloFuzzOne_TODO:
w.WriteString(fmt.Sprintf("Context%d := context.TODO()\n", ContextNb))
ContextNb = ContextNb + 1
case *NgoloFuzzOne_WithCancel:
if ContextNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Context%d, _ := context.WithCancel(Context%d)\n", ContextNb, (ContextResultsIndex + 0) % ContextNb))
ContextNb = ContextNb + 1
ContextResultsIndex = (ContextResultsIndex + 1) % ContextNb
case *NgoloFuzzOne_WithValue:
if ContextNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Context%d := context.WithValue(Context%d, %#+v, %#+v)\n", ContextNb, (ContextResultsIndex + 0) % ContextNb, a.WithValue.Key, a.WithValue.Val))
ContextNb = ContextNb + 1
ContextResultsIndex = (ContextResultsIndex + 1) % ContextNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_net_context
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type BackgroundArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BackgroundArgs) Reset() {
*x = BackgroundArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BackgroundArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BackgroundArgs) ProtoMessage() {}
func (x *BackgroundArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BackgroundArgs.ProtoReflect.Descriptor instead.
func (*BackgroundArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type TODOArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TODOArgs) Reset() {
*x = TODOArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TODOArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TODOArgs) ProtoMessage() {}
func (x *TODOArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TODOArgs.ProtoReflect.Descriptor instead.
func (*TODOArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
type WithCancelArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *WithCancelArgs) Reset() {
*x = WithCancelArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *WithCancelArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*WithCancelArgs) ProtoMessage() {}
func (x *WithCancelArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use WithCancelArgs.ProtoReflect.Descriptor instead.
func (*WithCancelArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
type WithValueArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key *NgoloFuzzAny `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Val *NgoloFuzzAny `protobuf:"bytes,2,opt,name=val,proto3" json:"val,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *WithValueArgs) Reset() {
*x = WithValueArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *WithValueArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*WithValueArgs) ProtoMessage() {}
func (x *WithValueArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use WithValueArgs.ProtoReflect.Descriptor instead.
func (*WithValueArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *WithValueArgs) GetKey() *NgoloFuzzAny {
if x != nil {
return x.Key
}
return nil
}
func (x *WithValueArgs) GetVal() *NgoloFuzzAny {
if x != nil {
return x.Val
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_Background
// *NgoloFuzzOne_TODO
// *NgoloFuzzOne_WithCancel
// *NgoloFuzzOne_WithValue
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetBackground() *BackgroundArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Background); ok {
return x.Background
}
}
return nil
}
func (x *NgoloFuzzOne) GetTODO() *TODOArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TODO); ok {
return x.TODO
}
}
return nil
}
func (x *NgoloFuzzOne) GetWithCancel() *WithCancelArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_WithCancel); ok {
return x.WithCancel
}
}
return nil
}
func (x *NgoloFuzzOne) GetWithValue() *WithValueArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_WithValue); ok {
return x.WithValue
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_Background struct {
Background *BackgroundArgs `protobuf:"bytes,1,opt,name=Background,proto3,oneof"`
}
type NgoloFuzzOne_TODO struct {
TODO *TODOArgs `protobuf:"bytes,2,opt,name=TODO,proto3,oneof"`
}
type NgoloFuzzOne_WithCancel struct {
WithCancel *WithCancelArgs `protobuf:"bytes,3,opt,name=WithCancel,proto3,oneof"`
}
type NgoloFuzzOne_WithValue struct {
WithValue *WithValueArgs `protobuf:"bytes,4,opt,name=WithValue,proto3,oneof"`
}
func (*NgoloFuzzOne_Background) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TODO) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_WithCancel) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_WithValue) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x10\n" +
"\x0eBackgroundArgs\"\n" +
"\n" +
"\bTODOArgs\"\x10\n" +
"\x0eWithCancelArgs\"e\n" +
"\rWithValueArgs\x12)\n" +
"\x03key\x18\x01 \x01(\v2\x17.ngolofuzz.NgoloFuzzAnyR\x03key\x12)\n" +
"\x03val\x18\x02 \x01(\v2\x17.ngolofuzz.NgoloFuzzAnyR\x03val\"\xf5\x01\n" +
"\fNgoloFuzzOne\x12;\n" +
"\n" +
"Background\x18\x01 \x01(\v2\x19.ngolofuzz.BackgroundArgsH\x00R\n" +
"Background\x12)\n" +
"\x04TODO\x18\x02 \x01(\v2\x13.ngolofuzz.TODOArgsH\x00R\x04TODO\x12;\n" +
"\n" +
"WithCancel\x18\x03 \x01(\v2\x19.ngolofuzz.WithCancelArgsH\x00R\n" +
"WithCancel\x128\n" +
"\tWithValue\x18\x04 \x01(\v2\x18.ngolofuzz.WithValueArgsH\x00R\tWithValueB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1aZ\x18./;fuzz_ng_x_net_contextb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_ngolofuzz_proto_goTypes = []any{
(*BackgroundArgs)(nil), // 0: ngolofuzz.BackgroundArgs
(*TODOArgs)(nil), // 1: ngolofuzz.TODOArgs
(*WithCancelArgs)(nil), // 2: ngolofuzz.WithCancelArgs
(*WithValueArgs)(nil), // 3: ngolofuzz.WithValueArgs
(*NgoloFuzzOne)(nil), // 4: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 5: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 6: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
5, // 0: ngolofuzz.WithValueArgs.key:type_name -> ngolofuzz.NgoloFuzzAny
5, // 1: ngolofuzz.WithValueArgs.val:type_name -> ngolofuzz.NgoloFuzzAny
0, // 2: ngolofuzz.NgoloFuzzOne.Background:type_name -> ngolofuzz.BackgroundArgs
1, // 3: ngolofuzz.NgoloFuzzOne.TODO:type_name -> ngolofuzz.TODOArgs
2, // 4: ngolofuzz.NgoloFuzzOne.WithCancel:type_name -> ngolofuzz.WithCancelArgs
3, // 5: ngolofuzz.NgoloFuzzOne.WithValue:type_name -> ngolofuzz.WithValueArgs
4, // 6: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
7, // [7:7] is the sub-list for method output_type
7, // [7:7] is the sub-list for method input_type
7, // [7:7] is the sub-list for extension type_name
7, // [7:7] is the sub-list for extension extendee
0, // [0:7] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[4].OneofWrappers = []any{
(*NgoloFuzzOne_Background)(nil),
(*NgoloFuzzOne_TODO)(nil),
(*NgoloFuzzOne_WithCancel)(nil),
(*NgoloFuzzOne_WithValue)(nil),
}
file_ngolofuzz_proto_msgTypes[5].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 7,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_net_dns_dnsmessage
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/net/dns/dnsmessage"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func SVCParamKeyNewFromFuzz(p SVCParamKeyEnum) dnsmessage.SVCParamKey{
switch p {
case 1:
return dnsmessage.SVCParamALPN
case 2:
return dnsmessage.SVCParamNoDefaultALPN
case 3:
return dnsmessage.SVCParamPort
case 4:
return dnsmessage.SVCParamIPv4Hint
case 5:
return dnsmessage.SVCParamECH
case 6:
return dnsmessage.SVCParamIPv6Hint
case 7:
return dnsmessage.SVCParamDOHPath
case 8:
return dnsmessage.SVCParamOHTTP
case 9:
return dnsmessage.SVCParamTLSSupportedGroups
}
return dnsmessage.SVCParamMandatory
}
func ConvertSVCParamKeyNewFromFuzz(a []SVCParamKeyEnum) []dnsmessage.SVCParamKey{
r := make([]dnsmessage.SVCParamKey, len(a))
for i := range a {
r[i] = SVCParamKeyNewFromFuzz(a[i])
}
return r
}
func ClassNewFromFuzz(p ClassEnum) dnsmessage.Class{
switch p {
case 1:
return dnsmessage.ClassCSNET
case 2:
return dnsmessage.ClassCHAOS
case 3:
return dnsmessage.ClassHESIOD
case 4:
return dnsmessage.ClassANY
}
return dnsmessage.ClassINET
}
func ConvertClassNewFromFuzz(a []ClassEnum) []dnsmessage.Class{
r := make([]dnsmessage.Class, len(a))
for i := range a {
r[i] = ClassNewFromFuzz(a[i])
}
return r
}
func TypeNewFromFuzz(p TypeEnum) dnsmessage.Type{
switch p {
case 1:
return dnsmessage.TypeNS
case 2:
return dnsmessage.TypeCNAME
case 3:
return dnsmessage.TypeSOA
case 4:
return dnsmessage.TypePTR
case 5:
return dnsmessage.TypeMX
case 6:
return dnsmessage.TypeTXT
case 7:
return dnsmessage.TypeAAAA
case 8:
return dnsmessage.TypeSRV
case 9:
return dnsmessage.TypeOPT
case 10:
return dnsmessage.TypeSVCB
case 11:
return dnsmessage.TypeHTTPS
case 12:
return dnsmessage.TypeWKS
case 13:
return dnsmessage.TypeHINFO
case 14:
return dnsmessage.TypeMINFO
case 15:
return dnsmessage.TypeAXFR
case 16:
return dnsmessage.TypeALL
}
return dnsmessage.TypeA
}
func ConvertTypeNewFromFuzz(a []TypeEnum) []dnsmessage.Type{
r := make([]dnsmessage.Type, len(a))
for i := range a {
r[i] = TypeNewFromFuzz(a[i])
}
return r
}
func SVCParamNewFromFuzz(p *SVCParamStruct) *dnsmessage.SVCParam{
if p == nil {
return nil
}
return &dnsmessage.SVCParam{
Key: SVCParamKeyNewFromFuzz(p.Key),
Value: p.Value,
}
}
func OptionNewFromFuzz(p *OptionStruct) *dnsmessage.Option{
if p == nil {
return nil
}
return &dnsmessage.Option{
Code: uint16(p.Code),
Data: p.Data,
}
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var SVCBResourceResults []*dnsmessage.SVCBResource
SVCBResourceResultsIndex := 0
var PTRResourceResults []*dnsmessage.PTRResource
PTRResourceResultsIndex := 0
var OPTResourceResults []*dnsmessage.OPTResource
OPTResourceResultsIndex := 0
var HeaderResults []*dnsmessage.Header
HeaderResultsIndex := 0
var SOAResourceResults []*dnsmessage.SOAResource
SOAResourceResultsIndex := 0
var TXTResourceResults []*dnsmessage.TXTResource
TXTResourceResultsIndex := 0
var UnknownResourceResults []*dnsmessage.UnknownResource
UnknownResourceResultsIndex := 0
var HTTPSResourceResults []*dnsmessage.HTTPSResource
HTTPSResourceResultsIndex := 0
var BuilderResults []*dnsmessage.Builder
BuilderResultsIndex := 0
var NameResults []*dnsmessage.Name
NameResultsIndex := 0
var MXResourceResults []*dnsmessage.MXResource
MXResourceResultsIndex := 0
var CNAMEResourceResults []*dnsmessage.CNAMEResource
CNAMEResourceResultsIndex := 0
var ResourceResults []*dnsmessage.Resource
ResourceResultsIndex := 0
var ResourceHeaderResults []*dnsmessage.ResourceHeader
ResourceHeaderResultsIndex := 0
var SRVResourceResults []*dnsmessage.SRVResource
SRVResourceResultsIndex := 0
var AResourceResults []*dnsmessage.AResource
AResourceResultsIndex := 0
var RCodeResults []*dnsmessage.RCode
RCodeResultsIndex := 0
var QuestionResults []*dnsmessage.Question
QuestionResultsIndex := 0
var NSResourceResults []*dnsmessage.NSResource
NSResourceResultsIndex := 0
var AAAAResourceResults []*dnsmessage.AAAAResource
AAAAResourceResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_TypeNgdotString:
arg0 := TypeNewFromFuzz(a.TypeNgdotString.T)
arg0.String()
case *NgoloFuzzOne_TypeNgdotGoString:
arg0 := TypeNewFromFuzz(a.TypeNgdotGoString.T)
arg0.GoString()
case *NgoloFuzzOne_ClassNgdotString:
arg0 := ClassNewFromFuzz(a.ClassNgdotString.C)
arg0.String()
case *NgoloFuzzOne_ClassNgdotGoString:
arg0 := ClassNewFromFuzz(a.ClassNgdotGoString.C)
arg0.GoString()
case *NgoloFuzzOne_RCodeNgdotString:
if len(RCodeResults) == 0 {
continue
}
arg0 := RCodeResults[RCodeResultsIndex]
RCodeResultsIndex = (RCodeResultsIndex + 1) % len(RCodeResults)
arg0.String()
case *NgoloFuzzOne_RCodeNgdotGoString:
if len(RCodeResults) == 0 {
continue
}
arg0 := RCodeResults[RCodeResultsIndex]
RCodeResultsIndex = (RCodeResultsIndex + 1) % len(RCodeResults)
arg0.GoString()
case *NgoloFuzzOne_HeaderNgdotGoString:
if len(HeaderResults) == 0 {
continue
}
arg0 := HeaderResults[HeaderResultsIndex]
HeaderResultsIndex = (HeaderResultsIndex + 1) % len(HeaderResults)
arg0.GoString()
case *NgoloFuzzOne_ResourceNgdotGoString:
if len(ResourceResults) == 0 {
continue
}
arg0 := ResourceResults[ResourceResultsIndex]
ResourceResultsIndex = (ResourceResultsIndex + 1) % len(ResourceResults)
arg0.GoString()
case *NgoloFuzzOne_NewBuilder:
if len(HeaderResults) == 0 {
continue
}
arg1 := *HeaderResults[HeaderResultsIndex]
HeaderResultsIndex = (HeaderResultsIndex + 1) % len(HeaderResults)
r0 := dnsmessage.NewBuilder(a.NewBuilder.Buf, arg1)
BuilderResults = append(BuilderResults, &r0)
case *NgoloFuzzOne_BuilderNgdotEnableCompression:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
arg0.EnableCompression()
case *NgoloFuzzOne_BuilderNgdotStartQuestions:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
r0 := arg0.StartQuestions()
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_BuilderNgdotStartAnswers:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
r0 := arg0.StartAnswers()
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_BuilderNgdotStartAuthorities:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
r0 := arg0.StartAuthorities()
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_BuilderNgdotStartAdditionals:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
r0 := arg0.StartAdditionals()
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_BuilderNgdotQuestion:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
if len(QuestionResults) == 0 {
continue
}
arg1 := *QuestionResults[QuestionResultsIndex]
QuestionResultsIndex = (QuestionResultsIndex + 1) % len(QuestionResults)
r0 := arg0.Question(arg1)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_BuilderNgdotCNAMEResource:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
if len(ResourceHeaderResults) == 0 {
continue
}
arg1 := *ResourceHeaderResults[ResourceHeaderResultsIndex]
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % len(ResourceHeaderResults)
if len(CNAMEResourceResults) == 0 {
continue
}
arg2 := *CNAMEResourceResults[CNAMEResourceResultsIndex]
CNAMEResourceResultsIndex = (CNAMEResourceResultsIndex + 1) % len(CNAMEResourceResults)
r0 := arg0.CNAMEResource(arg1, arg2)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_BuilderNgdotMXResource:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
if len(ResourceHeaderResults) == 0 {
continue
}
arg1 := *ResourceHeaderResults[ResourceHeaderResultsIndex]
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % len(ResourceHeaderResults)
if len(MXResourceResults) == 0 {
continue
}
arg2 := *MXResourceResults[MXResourceResultsIndex]
MXResourceResultsIndex = (MXResourceResultsIndex + 1) % len(MXResourceResults)
r0 := arg0.MXResource(arg1, arg2)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_BuilderNgdotNSResource:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
if len(ResourceHeaderResults) == 0 {
continue
}
arg1 := *ResourceHeaderResults[ResourceHeaderResultsIndex]
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % len(ResourceHeaderResults)
if len(NSResourceResults) == 0 {
continue
}
arg2 := *NSResourceResults[NSResourceResultsIndex]
NSResourceResultsIndex = (NSResourceResultsIndex + 1) % len(NSResourceResults)
r0 := arg0.NSResource(arg1, arg2)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_BuilderNgdotPTRResource:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
if len(ResourceHeaderResults) == 0 {
continue
}
arg1 := *ResourceHeaderResults[ResourceHeaderResultsIndex]
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % len(ResourceHeaderResults)
if len(PTRResourceResults) == 0 {
continue
}
arg2 := *PTRResourceResults[PTRResourceResultsIndex]
PTRResourceResultsIndex = (PTRResourceResultsIndex + 1) % len(PTRResourceResults)
r0 := arg0.PTRResource(arg1, arg2)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_BuilderNgdotSOAResource:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
if len(ResourceHeaderResults) == 0 {
continue
}
arg1 := *ResourceHeaderResults[ResourceHeaderResultsIndex]
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % len(ResourceHeaderResults)
if len(SOAResourceResults) == 0 {
continue
}
arg2 := *SOAResourceResults[SOAResourceResultsIndex]
SOAResourceResultsIndex = (SOAResourceResultsIndex + 1) % len(SOAResourceResults)
r0 := arg0.SOAResource(arg1, arg2)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_BuilderNgdotTXTResource:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
if len(ResourceHeaderResults) == 0 {
continue
}
arg1 := *ResourceHeaderResults[ResourceHeaderResultsIndex]
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % len(ResourceHeaderResults)
if len(TXTResourceResults) == 0 {
continue
}
arg2 := *TXTResourceResults[TXTResourceResultsIndex]
TXTResourceResultsIndex = (TXTResourceResultsIndex + 1) % len(TXTResourceResults)
r0 := arg0.TXTResource(arg1, arg2)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_BuilderNgdotSRVResource:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
if len(ResourceHeaderResults) == 0 {
continue
}
arg1 := *ResourceHeaderResults[ResourceHeaderResultsIndex]
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % len(ResourceHeaderResults)
if len(SRVResourceResults) == 0 {
continue
}
arg2 := *SRVResourceResults[SRVResourceResultsIndex]
SRVResourceResultsIndex = (SRVResourceResultsIndex + 1) % len(SRVResourceResults)
r0 := arg0.SRVResource(arg1, arg2)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_BuilderNgdotAResource:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
if len(ResourceHeaderResults) == 0 {
continue
}
arg1 := *ResourceHeaderResults[ResourceHeaderResultsIndex]
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % len(ResourceHeaderResults)
if len(AResourceResults) == 0 {
continue
}
arg2 := *AResourceResults[AResourceResultsIndex]
AResourceResultsIndex = (AResourceResultsIndex + 1) % len(AResourceResults)
r0 := arg0.AResource(arg1, arg2)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_BuilderNgdotAAAAResource:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
if len(ResourceHeaderResults) == 0 {
continue
}
arg1 := *ResourceHeaderResults[ResourceHeaderResultsIndex]
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % len(ResourceHeaderResults)
if len(AAAAResourceResults) == 0 {
continue
}
arg2 := *AAAAResourceResults[AAAAResourceResultsIndex]
AAAAResourceResultsIndex = (AAAAResourceResultsIndex + 1) % len(AAAAResourceResults)
r0 := arg0.AAAAResource(arg1, arg2)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_BuilderNgdotOPTResource:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
if len(ResourceHeaderResults) == 0 {
continue
}
arg1 := *ResourceHeaderResults[ResourceHeaderResultsIndex]
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % len(ResourceHeaderResults)
if len(OPTResourceResults) == 0 {
continue
}
arg2 := *OPTResourceResults[OPTResourceResultsIndex]
OPTResourceResultsIndex = (OPTResourceResultsIndex + 1) % len(OPTResourceResults)
r0 := arg0.OPTResource(arg1, arg2)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_BuilderNgdotUnknownResource:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
if len(ResourceHeaderResults) == 0 {
continue
}
arg1 := *ResourceHeaderResults[ResourceHeaderResultsIndex]
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % len(ResourceHeaderResults)
if len(UnknownResourceResults) == 0 {
continue
}
arg2 := *UnknownResourceResults[UnknownResourceResultsIndex]
UnknownResourceResultsIndex = (UnknownResourceResultsIndex + 1) % len(UnknownResourceResults)
r0 := arg0.UnknownResource(arg1, arg2)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_BuilderNgdotFinish:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
_, r1 := arg0.Finish()
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_ResourceHeaderNgdotGoString:
if len(ResourceHeaderResults) == 0 {
continue
}
arg0 := ResourceHeaderResults[ResourceHeaderResultsIndex]
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % len(ResourceHeaderResults)
arg0.GoString()
case *NgoloFuzzOne_ResourceHeaderNgdotSetEDNS0:
if len(ResourceHeaderResults) == 0 {
continue
}
arg0 := ResourceHeaderResults[ResourceHeaderResultsIndex]
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % len(ResourceHeaderResults)
arg1 := int(a.ResourceHeaderNgdotSetEDNS0.UdpPayloadLen)
if len(RCodeResults) == 0 {
continue
}
arg2 := *RCodeResults[RCodeResultsIndex]
RCodeResultsIndex = (RCodeResultsIndex + 1) % len(RCodeResults)
r0 := arg0.SetEDNS0(arg1, arg2, a.ResourceHeaderNgdotSetEDNS0.DnssecOK)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_ResourceHeaderNgdotDNSSECAllowed:
if len(ResourceHeaderResults) == 0 {
continue
}
arg0 := ResourceHeaderResults[ResourceHeaderResultsIndex]
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % len(ResourceHeaderResults)
arg0.DNSSECAllowed()
case *NgoloFuzzOne_ResourceHeaderNgdotExtendedRCode:
if len(ResourceHeaderResults) == 0 {
continue
}
arg0 := ResourceHeaderResults[ResourceHeaderResultsIndex]
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % len(ResourceHeaderResults)
if len(RCodeResults) == 0 {
continue
}
arg1 := *RCodeResults[RCodeResultsIndex]
RCodeResultsIndex = (RCodeResultsIndex + 1) % len(RCodeResults)
r0 := arg0.ExtendedRCode(arg1)
RCodeResults = append(RCodeResults, &r0)
case *NgoloFuzzOne_NewName:
_, r1 := dnsmessage.NewName(a.NewName.Name)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_MustNewName:
dnsmessage.MustNewName(a.MustNewName.Name)
case *NgoloFuzzOne_NameNgdotString:
if len(NameResults) == 0 {
continue
}
arg0 := NameResults[NameResultsIndex]
NameResultsIndex = (NameResultsIndex + 1) % len(NameResults)
arg0.String()
case *NgoloFuzzOne_NameNgdotGoString:
if len(NameResults) == 0 {
continue
}
arg0 := NameResults[NameResultsIndex]
NameResultsIndex = (NameResultsIndex + 1) % len(NameResults)
arg0.GoString()
case *NgoloFuzzOne_QuestionNgdotGoString:
if len(QuestionResults) == 0 {
continue
}
arg0 := QuestionResults[QuestionResultsIndex]
QuestionResultsIndex = (QuestionResultsIndex + 1) % len(QuestionResults)
arg0.GoString()
case *NgoloFuzzOne_CNAMEResourceNgdotGoString:
if len(CNAMEResourceResults) == 0 {
continue
}
arg0 := CNAMEResourceResults[CNAMEResourceResultsIndex]
CNAMEResourceResultsIndex = (CNAMEResourceResultsIndex + 1) % len(CNAMEResourceResults)
arg0.GoString()
case *NgoloFuzzOne_MXResourceNgdotGoString:
if len(MXResourceResults) == 0 {
continue
}
arg0 := MXResourceResults[MXResourceResultsIndex]
MXResourceResultsIndex = (MXResourceResultsIndex + 1) % len(MXResourceResults)
arg0.GoString()
case *NgoloFuzzOne_NSResourceNgdotGoString:
if len(NSResourceResults) == 0 {
continue
}
arg0 := NSResourceResults[NSResourceResultsIndex]
NSResourceResultsIndex = (NSResourceResultsIndex + 1) % len(NSResourceResults)
arg0.GoString()
case *NgoloFuzzOne_PTRResourceNgdotGoString:
if len(PTRResourceResults) == 0 {
continue
}
arg0 := PTRResourceResults[PTRResourceResultsIndex]
PTRResourceResultsIndex = (PTRResourceResultsIndex + 1) % len(PTRResourceResults)
arg0.GoString()
case *NgoloFuzzOne_SOAResourceNgdotGoString:
if len(SOAResourceResults) == 0 {
continue
}
arg0 := SOAResourceResults[SOAResourceResultsIndex]
SOAResourceResultsIndex = (SOAResourceResultsIndex + 1) % len(SOAResourceResults)
arg0.GoString()
case *NgoloFuzzOne_TXTResourceNgdotGoString:
if len(TXTResourceResults) == 0 {
continue
}
arg0 := TXTResourceResults[TXTResourceResultsIndex]
TXTResourceResultsIndex = (TXTResourceResultsIndex + 1) % len(TXTResourceResults)
arg0.GoString()
case *NgoloFuzzOne_SRVResourceNgdotGoString:
if len(SRVResourceResults) == 0 {
continue
}
arg0 := SRVResourceResults[SRVResourceResultsIndex]
SRVResourceResultsIndex = (SRVResourceResultsIndex + 1) % len(SRVResourceResults)
arg0.GoString()
case *NgoloFuzzOne_AResourceNgdotGoString:
if len(AResourceResults) == 0 {
continue
}
arg0 := AResourceResults[AResourceResultsIndex]
AResourceResultsIndex = (AResourceResultsIndex + 1) % len(AResourceResults)
arg0.GoString()
case *NgoloFuzzOne_AAAAResourceNgdotGoString:
if len(AAAAResourceResults) == 0 {
continue
}
arg0 := AAAAResourceResults[AAAAResourceResultsIndex]
AAAAResourceResultsIndex = (AAAAResourceResultsIndex + 1) % len(AAAAResourceResults)
arg0.GoString()
case *NgoloFuzzOne_OptionNgdotGoString:
arg0 := OptionNewFromFuzz(a.OptionNgdotGoString.O)
if arg0 == nil {
continue
}
arg0.GoString()
case *NgoloFuzzOne_OPTResourceNgdotGoString:
if len(OPTResourceResults) == 0 {
continue
}
arg0 := OPTResourceResults[OPTResourceResultsIndex]
OPTResourceResultsIndex = (OPTResourceResultsIndex + 1) % len(OPTResourceResults)
arg0.GoString()
case *NgoloFuzzOne_UnknownResourceNgdotGoString:
if len(UnknownResourceResults) == 0 {
continue
}
arg0 := UnknownResourceResults[UnknownResourceResultsIndex]
UnknownResourceResultsIndex = (UnknownResourceResultsIndex + 1) % len(UnknownResourceResults)
arg0.GoString()
case *NgoloFuzzOne_SVCBResourceNgdotGoString:
if len(SVCBResourceResults) == 0 {
continue
}
arg0 := SVCBResourceResults[SVCBResourceResultsIndex]
SVCBResourceResultsIndex = (SVCBResourceResultsIndex + 1) % len(SVCBResourceResults)
arg0.GoString()
case *NgoloFuzzOne_HTTPSResourceNgdotGoString:
if len(HTTPSResourceResults) == 0 {
continue
}
arg0 := HTTPSResourceResults[HTTPSResourceResultsIndex]
HTTPSResourceResultsIndex = (HTTPSResourceResultsIndex + 1) % len(HTTPSResourceResults)
arg0.GoString()
case *NgoloFuzzOne_SVCBResourceNgdotGetParam:
if len(SVCBResourceResults) == 0 {
continue
}
arg0 := SVCBResourceResults[SVCBResourceResultsIndex]
SVCBResourceResultsIndex = (SVCBResourceResultsIndex + 1) % len(SVCBResourceResults)
arg1 := SVCParamKeyNewFromFuzz(a.SVCBResourceNgdotGetParam.Key)
arg0.GetParam(arg1)
case *NgoloFuzzOne_SVCBResourceNgdotSetParam:
if len(SVCBResourceResults) == 0 {
continue
}
arg0 := SVCBResourceResults[SVCBResourceResultsIndex]
SVCBResourceResultsIndex = (SVCBResourceResultsIndex + 1) % len(SVCBResourceResults)
arg1 := SVCParamKeyNewFromFuzz(a.SVCBResourceNgdotSetParam.Key)
arg0.SetParam(arg1, a.SVCBResourceNgdotSetParam.Value)
case *NgoloFuzzOne_SVCBResourceNgdotDeleteParam:
if len(SVCBResourceResults) == 0 {
continue
}
arg0 := SVCBResourceResults[SVCBResourceResultsIndex]
SVCBResourceResultsIndex = (SVCBResourceResultsIndex + 1) % len(SVCBResourceResults)
arg1 := SVCParamKeyNewFromFuzz(a.SVCBResourceNgdotDeleteParam.Key)
arg0.DeleteParam(arg1)
case *NgoloFuzzOne_SVCParamNgdotGoString:
arg0 := SVCParamNewFromFuzz(a.SVCParamNgdotGoString.P)
if arg0 == nil {
continue
}
arg0.GoString()
case *NgoloFuzzOne_SVCParamKeyNgdotString:
arg0 := SVCParamKeyNewFromFuzz(a.SVCParamKeyNgdotString.K)
arg0.String()
case *NgoloFuzzOne_SVCParamKeyNgdotGoString:
arg0 := SVCParamKeyNewFromFuzz(a.SVCParamKeyNgdotGoString.K)
arg0.GoString()
case *NgoloFuzzOne_BuilderNgdotSVCBResource:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
if len(ResourceHeaderResults) == 0 {
continue
}
arg1 := *ResourceHeaderResults[ResourceHeaderResultsIndex]
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % len(ResourceHeaderResults)
if len(SVCBResourceResults) == 0 {
continue
}
arg2 := *SVCBResourceResults[SVCBResourceResultsIndex]
SVCBResourceResultsIndex = (SVCBResourceResultsIndex + 1) % len(SVCBResourceResults)
r0 := arg0.SVCBResource(arg1, arg2)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_BuilderNgdotHTTPSResource:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
if len(ResourceHeaderResults) == 0 {
continue
}
arg1 := *ResourceHeaderResults[ResourceHeaderResultsIndex]
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % len(ResourceHeaderResults)
if len(HTTPSResourceResults) == 0 {
continue
}
arg2 := *HTTPSResourceResults[HTTPSResourceResultsIndex]
HTTPSResourceResultsIndex = (HTTPSResourceResultsIndex + 1) % len(HTTPSResourceResults)
r0 := arg0.HTTPSResource(arg1, arg2)
if r0 != nil{
r0.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
SVCBResourceNb := 0
SVCBResourceResultsIndex := 0
PTRResourceNb := 0
PTRResourceResultsIndex := 0
OPTResourceNb := 0
OPTResourceResultsIndex := 0
HeaderNb := 0
HeaderResultsIndex := 0
SOAResourceNb := 0
SOAResourceResultsIndex := 0
TXTResourceNb := 0
TXTResourceResultsIndex := 0
UnknownResourceNb := 0
UnknownResourceResultsIndex := 0
HTTPSResourceNb := 0
HTTPSResourceResultsIndex := 0
BuilderNb := 0
BuilderResultsIndex := 0
NameNb := 0
NameResultsIndex := 0
MXResourceNb := 0
MXResourceResultsIndex := 0
CNAMEResourceNb := 0
CNAMEResourceResultsIndex := 0
ResourceNb := 0
ResourceResultsIndex := 0
ResourceHeaderNb := 0
ResourceHeaderResultsIndex := 0
SRVResourceNb := 0
SRVResourceResultsIndex := 0
AResourceNb := 0
AResourceResultsIndex := 0
RCodeNb := 0
RCodeResultsIndex := 0
QuestionNb := 0
QuestionResultsIndex := 0
NSResourceNb := 0
NSResourceResultsIndex := 0
AAAAResourceNb := 0
AAAAResourceResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_TypeNgdotString:
w.WriteString(fmt.Sprintf("TypeNewFromFuzz(%#+v).String()\n", a.TypeNgdotString.T))
case *NgoloFuzzOne_TypeNgdotGoString:
w.WriteString(fmt.Sprintf("TypeNewFromFuzz(%#+v).GoString()\n", a.TypeNgdotGoString.T))
case *NgoloFuzzOne_ClassNgdotString:
w.WriteString(fmt.Sprintf("ClassNewFromFuzz(%#+v).String()\n", a.ClassNgdotString.C))
case *NgoloFuzzOne_ClassNgdotGoString:
w.WriteString(fmt.Sprintf("ClassNewFromFuzz(%#+v).GoString()\n", a.ClassNgdotGoString.C))
case *NgoloFuzzOne_RCodeNgdotString:
if RCodeNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("RCode%d.String()\n", RCodeResultsIndex))
RCodeResultsIndex = (RCodeResultsIndex + 1) % RCodeNb
case *NgoloFuzzOne_RCodeNgdotGoString:
if RCodeNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("RCode%d.GoString()\n", RCodeResultsIndex))
RCodeResultsIndex = (RCodeResultsIndex + 1) % RCodeNb
case *NgoloFuzzOne_HeaderNgdotGoString:
if HeaderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Header%d.GoString()\n", HeaderResultsIndex))
HeaderResultsIndex = (HeaderResultsIndex + 1) % HeaderNb
case *NgoloFuzzOne_ResourceNgdotGoString:
if ResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Resource%d.GoString()\n", ResourceResultsIndex))
ResourceResultsIndex = (ResourceResultsIndex + 1) % ResourceNb
case *NgoloFuzzOne_NewBuilder:
if HeaderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d := dnsmessage.NewBuilder(%#+v, Header%d)\n", BuilderNb, a.NewBuilder.Buf, (HeaderResultsIndex + 0) % HeaderNb))
BuilderNb = BuilderNb + 1
HeaderResultsIndex = (HeaderResultsIndex + 1) % HeaderNb
case *NgoloFuzzOne_BuilderNgdotEnableCompression:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.EnableCompression()\n", BuilderResultsIndex))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotStartQuestions:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.StartQuestions()\n", BuilderResultsIndex))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotStartAnswers:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.StartAnswers()\n", BuilderResultsIndex))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotStartAuthorities:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.StartAuthorities()\n", BuilderResultsIndex))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotStartAdditionals:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.StartAdditionals()\n", BuilderResultsIndex))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_BuilderNgdotQuestion:
if BuilderNb == 0 {
continue
}
if QuestionNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.Question(Question%d)\n", BuilderResultsIndex, (QuestionResultsIndex + 0) % QuestionNb))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
QuestionResultsIndex = (QuestionResultsIndex + 1) % QuestionNb
case *NgoloFuzzOne_BuilderNgdotCNAMEResource:
if BuilderNb == 0 {
continue
}
if ResourceHeaderNb == 0 {
continue
}
if CNAMEResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.CNAMEResource(ResourceHeader%d, CNAMEResource%d)\n", BuilderResultsIndex, (ResourceHeaderResultsIndex + 0) % ResourceHeaderNb, (CNAMEResourceResultsIndex + 0) % CNAMEResourceNb))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % ResourceHeaderNb
CNAMEResourceResultsIndex = (CNAMEResourceResultsIndex + 1) % CNAMEResourceNb
case *NgoloFuzzOne_BuilderNgdotMXResource:
if BuilderNb == 0 {
continue
}
if ResourceHeaderNb == 0 {
continue
}
if MXResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.MXResource(ResourceHeader%d, MXResource%d)\n", BuilderResultsIndex, (ResourceHeaderResultsIndex + 0) % ResourceHeaderNb, (MXResourceResultsIndex + 0) % MXResourceNb))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % ResourceHeaderNb
MXResourceResultsIndex = (MXResourceResultsIndex + 1) % MXResourceNb
case *NgoloFuzzOne_BuilderNgdotNSResource:
if BuilderNb == 0 {
continue
}
if ResourceHeaderNb == 0 {
continue
}
if NSResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.NSResource(ResourceHeader%d, NSResource%d)\n", BuilderResultsIndex, (ResourceHeaderResultsIndex + 0) % ResourceHeaderNb, (NSResourceResultsIndex + 0) % NSResourceNb))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % ResourceHeaderNb
NSResourceResultsIndex = (NSResourceResultsIndex + 1) % NSResourceNb
case *NgoloFuzzOne_BuilderNgdotPTRResource:
if BuilderNb == 0 {
continue
}
if ResourceHeaderNb == 0 {
continue
}
if PTRResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.PTRResource(ResourceHeader%d, PTRResource%d)\n", BuilderResultsIndex, (ResourceHeaderResultsIndex + 0) % ResourceHeaderNb, (PTRResourceResultsIndex + 0) % PTRResourceNb))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % ResourceHeaderNb
PTRResourceResultsIndex = (PTRResourceResultsIndex + 1) % PTRResourceNb
case *NgoloFuzzOne_BuilderNgdotSOAResource:
if BuilderNb == 0 {
continue
}
if ResourceHeaderNb == 0 {
continue
}
if SOAResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.SOAResource(ResourceHeader%d, SOAResource%d)\n", BuilderResultsIndex, (ResourceHeaderResultsIndex + 0) % ResourceHeaderNb, (SOAResourceResultsIndex + 0) % SOAResourceNb))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % ResourceHeaderNb
SOAResourceResultsIndex = (SOAResourceResultsIndex + 1) % SOAResourceNb
case *NgoloFuzzOne_BuilderNgdotTXTResource:
if BuilderNb == 0 {
continue
}
if ResourceHeaderNb == 0 {
continue
}
if TXTResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.TXTResource(ResourceHeader%d, TXTResource%d)\n", BuilderResultsIndex, (ResourceHeaderResultsIndex + 0) % ResourceHeaderNb, (TXTResourceResultsIndex + 0) % TXTResourceNb))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % ResourceHeaderNb
TXTResourceResultsIndex = (TXTResourceResultsIndex + 1) % TXTResourceNb
case *NgoloFuzzOne_BuilderNgdotSRVResource:
if BuilderNb == 0 {
continue
}
if ResourceHeaderNb == 0 {
continue
}
if SRVResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.SRVResource(ResourceHeader%d, SRVResource%d)\n", BuilderResultsIndex, (ResourceHeaderResultsIndex + 0) % ResourceHeaderNb, (SRVResourceResultsIndex + 0) % SRVResourceNb))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % ResourceHeaderNb
SRVResourceResultsIndex = (SRVResourceResultsIndex + 1) % SRVResourceNb
case *NgoloFuzzOne_BuilderNgdotAResource:
if BuilderNb == 0 {
continue
}
if ResourceHeaderNb == 0 {
continue
}
if AResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.AResource(ResourceHeader%d, AResource%d)\n", BuilderResultsIndex, (ResourceHeaderResultsIndex + 0) % ResourceHeaderNb, (AResourceResultsIndex + 0) % AResourceNb))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % ResourceHeaderNb
AResourceResultsIndex = (AResourceResultsIndex + 1) % AResourceNb
case *NgoloFuzzOne_BuilderNgdotAAAAResource:
if BuilderNb == 0 {
continue
}
if ResourceHeaderNb == 0 {
continue
}
if AAAAResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.AAAAResource(ResourceHeader%d, AAAAResource%d)\n", BuilderResultsIndex, (ResourceHeaderResultsIndex + 0) % ResourceHeaderNb, (AAAAResourceResultsIndex + 0) % AAAAResourceNb))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % ResourceHeaderNb
AAAAResourceResultsIndex = (AAAAResourceResultsIndex + 1) % AAAAResourceNb
case *NgoloFuzzOne_BuilderNgdotOPTResource:
if BuilderNb == 0 {
continue
}
if ResourceHeaderNb == 0 {
continue
}
if OPTResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.OPTResource(ResourceHeader%d, OPTResource%d)\n", BuilderResultsIndex, (ResourceHeaderResultsIndex + 0) % ResourceHeaderNb, (OPTResourceResultsIndex + 0) % OPTResourceNb))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % ResourceHeaderNb
OPTResourceResultsIndex = (OPTResourceResultsIndex + 1) % OPTResourceNb
case *NgoloFuzzOne_BuilderNgdotUnknownResource:
if BuilderNb == 0 {
continue
}
if ResourceHeaderNb == 0 {
continue
}
if UnknownResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.UnknownResource(ResourceHeader%d, UnknownResource%d)\n", BuilderResultsIndex, (ResourceHeaderResultsIndex + 0) % ResourceHeaderNb, (UnknownResourceResultsIndex + 0) % UnknownResourceNb))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % ResourceHeaderNb
UnknownResourceResultsIndex = (UnknownResourceResultsIndex + 1) % UnknownResourceNb
case *NgoloFuzzOne_BuilderNgdotFinish:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.Finish()\n", BuilderResultsIndex))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_ResourceHeaderNgdotGoString:
if ResourceHeaderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("ResourceHeader%d.GoString()\n", ResourceHeaderResultsIndex))
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % ResourceHeaderNb
case *NgoloFuzzOne_ResourceHeaderNgdotSetEDNS0:
if ResourceHeaderNb == 0 {
continue
}
if RCodeNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("ResourceHeader%d.SetEDNS0(int(%#+v), RCode%d, %#+v)\n", ResourceHeaderResultsIndex, a.ResourceHeaderNgdotSetEDNS0.UdpPayloadLen, (RCodeResultsIndex + 0) % RCodeNb, a.ResourceHeaderNgdotSetEDNS0.DnssecOK))
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % ResourceHeaderNb
RCodeResultsIndex = (RCodeResultsIndex + 1) % RCodeNb
case *NgoloFuzzOne_ResourceHeaderNgdotDNSSECAllowed:
if ResourceHeaderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("ResourceHeader%d.DNSSECAllowed()\n", ResourceHeaderResultsIndex))
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % ResourceHeaderNb
case *NgoloFuzzOne_ResourceHeaderNgdotExtendedRCode:
if ResourceHeaderNb == 0 {
continue
}
if RCodeNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("RCode%d := ResourceHeader%d.ExtendedRCode(RCode%d)\n", RCodeNb, ResourceHeaderResultsIndex, (RCodeResultsIndex + 0) % RCodeNb))
RCodeNb = RCodeNb + 1
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % ResourceHeaderNb
RCodeResultsIndex = (RCodeResultsIndex + 1) % RCodeNb
case *NgoloFuzzOne_NewName:
w.WriteString(fmt.Sprintf("dnsmessage.NewName(%#+v)\n", a.NewName.Name))
case *NgoloFuzzOne_MustNewName:
w.WriteString(fmt.Sprintf("dnsmessage.MustNewName(%#+v)\n", a.MustNewName.Name))
case *NgoloFuzzOne_NameNgdotString:
if NameNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Name%d.String()\n", NameResultsIndex))
NameResultsIndex = (NameResultsIndex + 1) % NameNb
case *NgoloFuzzOne_NameNgdotGoString:
if NameNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Name%d.GoString()\n", NameResultsIndex))
NameResultsIndex = (NameResultsIndex + 1) % NameNb
case *NgoloFuzzOne_QuestionNgdotGoString:
if QuestionNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Question%d.GoString()\n", QuestionResultsIndex))
QuestionResultsIndex = (QuestionResultsIndex + 1) % QuestionNb
case *NgoloFuzzOne_CNAMEResourceNgdotGoString:
if CNAMEResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("CNAMEResource%d.GoString()\n", CNAMEResourceResultsIndex))
CNAMEResourceResultsIndex = (CNAMEResourceResultsIndex + 1) % CNAMEResourceNb
case *NgoloFuzzOne_MXResourceNgdotGoString:
if MXResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("MXResource%d.GoString()\n", MXResourceResultsIndex))
MXResourceResultsIndex = (MXResourceResultsIndex + 1) % MXResourceNb
case *NgoloFuzzOne_NSResourceNgdotGoString:
if NSResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("NSResource%d.GoString()\n", NSResourceResultsIndex))
NSResourceResultsIndex = (NSResourceResultsIndex + 1) % NSResourceNb
case *NgoloFuzzOne_PTRResourceNgdotGoString:
if PTRResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("PTRResource%d.GoString()\n", PTRResourceResultsIndex))
PTRResourceResultsIndex = (PTRResourceResultsIndex + 1) % PTRResourceNb
case *NgoloFuzzOne_SOAResourceNgdotGoString:
if SOAResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("SOAResource%d.GoString()\n", SOAResourceResultsIndex))
SOAResourceResultsIndex = (SOAResourceResultsIndex + 1) % SOAResourceNb
case *NgoloFuzzOne_TXTResourceNgdotGoString:
if TXTResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("TXTResource%d.GoString()\n", TXTResourceResultsIndex))
TXTResourceResultsIndex = (TXTResourceResultsIndex + 1) % TXTResourceNb
case *NgoloFuzzOne_SRVResourceNgdotGoString:
if SRVResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("SRVResource%d.GoString()\n", SRVResourceResultsIndex))
SRVResourceResultsIndex = (SRVResourceResultsIndex + 1) % SRVResourceNb
case *NgoloFuzzOne_AResourceNgdotGoString:
if AResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("AResource%d.GoString()\n", AResourceResultsIndex))
AResourceResultsIndex = (AResourceResultsIndex + 1) % AResourceNb
case *NgoloFuzzOne_AAAAResourceNgdotGoString:
if AAAAResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("AAAAResource%d.GoString()\n", AAAAResourceResultsIndex))
AAAAResourceResultsIndex = (AAAAResourceResultsIndex + 1) % AAAAResourceNb
case *NgoloFuzzOne_OptionNgdotGoString:
w.WriteString(fmt.Sprintf("OptionNewFromFuzz(%#+v).GoString()\n", a.OptionNgdotGoString.O))
case *NgoloFuzzOne_OPTResourceNgdotGoString:
if OPTResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("OPTResource%d.GoString()\n", OPTResourceResultsIndex))
OPTResourceResultsIndex = (OPTResourceResultsIndex + 1) % OPTResourceNb
case *NgoloFuzzOne_UnknownResourceNgdotGoString:
if UnknownResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("UnknownResource%d.GoString()\n", UnknownResourceResultsIndex))
UnknownResourceResultsIndex = (UnknownResourceResultsIndex + 1) % UnknownResourceNb
case *NgoloFuzzOne_SVCBResourceNgdotGoString:
if SVCBResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("SVCBResource%d.GoString()\n", SVCBResourceResultsIndex))
SVCBResourceResultsIndex = (SVCBResourceResultsIndex + 1) % SVCBResourceNb
case *NgoloFuzzOne_HTTPSResourceNgdotGoString:
if HTTPSResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("HTTPSResource%d.GoString()\n", HTTPSResourceResultsIndex))
HTTPSResourceResultsIndex = (HTTPSResourceResultsIndex + 1) % HTTPSResourceNb
case *NgoloFuzzOne_SVCBResourceNgdotGetParam:
if SVCBResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("SVCBResource%d.GetParam(SVCParamKeyNewFromFuzz(%#+v))\n", SVCBResourceResultsIndex, a.SVCBResourceNgdotGetParam.Key))
SVCBResourceResultsIndex = (SVCBResourceResultsIndex + 1) % SVCBResourceNb
case *NgoloFuzzOne_SVCBResourceNgdotSetParam:
if SVCBResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("SVCBResource%d.SetParam(SVCParamKeyNewFromFuzz(%#+v), %#+v)\n", SVCBResourceResultsIndex, a.SVCBResourceNgdotSetParam.Key, a.SVCBResourceNgdotSetParam.Value))
SVCBResourceResultsIndex = (SVCBResourceResultsIndex + 1) % SVCBResourceNb
case *NgoloFuzzOne_SVCBResourceNgdotDeleteParam:
if SVCBResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("SVCBResource%d.DeleteParam(SVCParamKeyNewFromFuzz(%#+v))\n", SVCBResourceResultsIndex, a.SVCBResourceNgdotDeleteParam.Key))
SVCBResourceResultsIndex = (SVCBResourceResultsIndex + 1) % SVCBResourceNb
case *NgoloFuzzOne_SVCParamNgdotGoString:
w.WriteString(fmt.Sprintf("SVCParamNewFromFuzz(%#+v).GoString()\n", a.SVCParamNgdotGoString.P))
case *NgoloFuzzOne_SVCParamKeyNgdotString:
w.WriteString(fmt.Sprintf("SVCParamKeyNewFromFuzz(%#+v).String()\n", a.SVCParamKeyNgdotString.K))
case *NgoloFuzzOne_SVCParamKeyNgdotGoString:
w.WriteString(fmt.Sprintf("SVCParamKeyNewFromFuzz(%#+v).GoString()\n", a.SVCParamKeyNgdotGoString.K))
case *NgoloFuzzOne_BuilderNgdotSVCBResource:
if BuilderNb == 0 {
continue
}
if ResourceHeaderNb == 0 {
continue
}
if SVCBResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.SVCBResource(ResourceHeader%d, SVCBResource%d)\n", BuilderResultsIndex, (ResourceHeaderResultsIndex + 0) % ResourceHeaderNb, (SVCBResourceResultsIndex + 0) % SVCBResourceNb))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % ResourceHeaderNb
SVCBResourceResultsIndex = (SVCBResourceResultsIndex + 1) % SVCBResourceNb
case *NgoloFuzzOne_BuilderNgdotHTTPSResource:
if BuilderNb == 0 {
continue
}
if ResourceHeaderNb == 0 {
continue
}
if HTTPSResourceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.HTTPSResource(ResourceHeader%d, HTTPSResource%d)\n", BuilderResultsIndex, (ResourceHeaderResultsIndex + 0) % ResourceHeaderNb, (HTTPSResourceResultsIndex + 0) % HTTPSResourceNb))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
ResourceHeaderResultsIndex = (ResourceHeaderResultsIndex + 1) % ResourceHeaderNb
HTTPSResourceResultsIndex = (HTTPSResourceResultsIndex + 1) % HTTPSResourceNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_net_dns_dnsmessage
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type SVCParamKeyEnum int32
const (
SVCParamKeyEnum_SVCParamMandatory SVCParamKeyEnum = 0
SVCParamKeyEnum_SVCParamALPN SVCParamKeyEnum = 1
SVCParamKeyEnum_SVCParamNoDefaultALPN SVCParamKeyEnum = 2
SVCParamKeyEnum_SVCParamPort SVCParamKeyEnum = 3
SVCParamKeyEnum_SVCParamIPv4Hint SVCParamKeyEnum = 4
SVCParamKeyEnum_SVCParamECH SVCParamKeyEnum = 5
SVCParamKeyEnum_SVCParamIPv6Hint SVCParamKeyEnum = 6
SVCParamKeyEnum_SVCParamDOHPath SVCParamKeyEnum = 7
SVCParamKeyEnum_SVCParamOHTTP SVCParamKeyEnum = 8
SVCParamKeyEnum_SVCParamTLSSupportedGroups SVCParamKeyEnum = 9
)
// Enum value maps for SVCParamKeyEnum.
var (
SVCParamKeyEnum_name = map[int32]string{
0: "SVCParamMandatory",
1: "SVCParamALPN",
2: "SVCParamNoDefaultALPN",
3: "SVCParamPort",
4: "SVCParamIPv4Hint",
5: "SVCParamECH",
6: "SVCParamIPv6Hint",
7: "SVCParamDOHPath",
8: "SVCParamOHTTP",
9: "SVCParamTLSSupportedGroups",
}
SVCParamKeyEnum_value = map[string]int32{
"SVCParamMandatory": 0,
"SVCParamALPN": 1,
"SVCParamNoDefaultALPN": 2,
"SVCParamPort": 3,
"SVCParamIPv4Hint": 4,
"SVCParamECH": 5,
"SVCParamIPv6Hint": 6,
"SVCParamDOHPath": 7,
"SVCParamOHTTP": 8,
"SVCParamTLSSupportedGroups": 9,
}
)
func (x SVCParamKeyEnum) Enum() *SVCParamKeyEnum {
p := new(SVCParamKeyEnum)
*p = x
return p
}
func (x SVCParamKeyEnum) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (SVCParamKeyEnum) Descriptor() protoreflect.EnumDescriptor {
return file_ngolofuzz_proto_enumTypes[0].Descriptor()
}
func (SVCParamKeyEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[0]
}
func (x SVCParamKeyEnum) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use SVCParamKeyEnum.Descriptor instead.
func (SVCParamKeyEnum) EnumDescriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type ClassEnum int32
const (
ClassEnum_ClassINET ClassEnum = 0
ClassEnum_ClassCSNET ClassEnum = 1
ClassEnum_ClassCHAOS ClassEnum = 2
ClassEnum_ClassHESIOD ClassEnum = 3
ClassEnum_ClassANY ClassEnum = 4
)
// Enum value maps for ClassEnum.
var (
ClassEnum_name = map[int32]string{
0: "ClassINET",
1: "ClassCSNET",
2: "ClassCHAOS",
3: "ClassHESIOD",
4: "ClassANY",
}
ClassEnum_value = map[string]int32{
"ClassINET": 0,
"ClassCSNET": 1,
"ClassCHAOS": 2,
"ClassHESIOD": 3,
"ClassANY": 4,
}
)
func (x ClassEnum) Enum() *ClassEnum {
p := new(ClassEnum)
*p = x
return p
}
func (x ClassEnum) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (ClassEnum) Descriptor() protoreflect.EnumDescriptor {
return file_ngolofuzz_proto_enumTypes[1].Descriptor()
}
func (ClassEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[1]
}
func (x ClassEnum) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use ClassEnum.Descriptor instead.
func (ClassEnum) EnumDescriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
type TypeEnum int32
const (
TypeEnum_TypeA TypeEnum = 0
TypeEnum_TypeNS TypeEnum = 1
TypeEnum_TypeCNAME TypeEnum = 2
TypeEnum_TypeSOA TypeEnum = 3
TypeEnum_TypePTR TypeEnum = 4
TypeEnum_TypeMX TypeEnum = 5
TypeEnum_TypeTXT TypeEnum = 6
TypeEnum_TypeAAAA TypeEnum = 7
TypeEnum_TypeSRV TypeEnum = 8
TypeEnum_TypeOPT TypeEnum = 9
TypeEnum_TypeSVCB TypeEnum = 10
TypeEnum_TypeHTTPS TypeEnum = 11
TypeEnum_TypeWKS TypeEnum = 12
TypeEnum_TypeHINFO TypeEnum = 13
TypeEnum_TypeMINFO TypeEnum = 14
TypeEnum_TypeAXFR TypeEnum = 15
TypeEnum_TypeALL TypeEnum = 16
)
// Enum value maps for TypeEnum.
var (
TypeEnum_name = map[int32]string{
0: "TypeA",
1: "TypeNS",
2: "TypeCNAME",
3: "TypeSOA",
4: "TypePTR",
5: "TypeMX",
6: "TypeTXT",
7: "TypeAAAA",
8: "TypeSRV",
9: "TypeOPT",
10: "TypeSVCB",
11: "TypeHTTPS",
12: "TypeWKS",
13: "TypeHINFO",
14: "TypeMINFO",
15: "TypeAXFR",
16: "TypeALL",
}
TypeEnum_value = map[string]int32{
"TypeA": 0,
"TypeNS": 1,
"TypeCNAME": 2,
"TypeSOA": 3,
"TypePTR": 4,
"TypeMX": 5,
"TypeTXT": 6,
"TypeAAAA": 7,
"TypeSRV": 8,
"TypeOPT": 9,
"TypeSVCB": 10,
"TypeHTTPS": 11,
"TypeWKS": 12,
"TypeHINFO": 13,
"TypeMINFO": 14,
"TypeAXFR": 15,
"TypeALL": 16,
}
)
func (x TypeEnum) Enum() *TypeEnum {
p := new(TypeEnum)
*p = x
return p
}
func (x TypeEnum) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (TypeEnum) Descriptor() protoreflect.EnumDescriptor {
return file_ngolofuzz_proto_enumTypes[2].Descriptor()
}
func (TypeEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[2]
}
func (x TypeEnum) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use TypeEnum.Descriptor instead.
func (TypeEnum) EnumDescriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
type SVCParamStruct struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key SVCParamKeyEnum `protobuf:"varint,1,opt,name=Key,proto3,enum=ngolofuzz.SVCParamKeyEnum" json:"Key,omitempty"`
Value []byte `protobuf:"bytes,2,opt,name=Value,proto3" json:"Value,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SVCParamStruct) Reset() {
*x = SVCParamStruct{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SVCParamStruct) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SVCParamStruct) ProtoMessage() {}
func (x *SVCParamStruct) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SVCParamStruct.ProtoReflect.Descriptor instead.
func (*SVCParamStruct) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *SVCParamStruct) GetKey() SVCParamKeyEnum {
if x != nil {
return x.Key
}
return SVCParamKeyEnum_SVCParamMandatory
}
func (x *SVCParamStruct) GetValue() []byte {
if x != nil {
return x.Value
}
return nil
}
type OptionStruct struct {
state protoimpl.MessageState `protogen:"open.v1"`
Code uint32 `protobuf:"varint,1,opt,name=Code,proto3" json:"Code,omitempty"`
Data []byte `protobuf:"bytes,2,opt,name=Data,proto3" json:"Data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *OptionStruct) Reset() {
*x = OptionStruct{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *OptionStruct) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*OptionStruct) ProtoMessage() {}
func (x *OptionStruct) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use OptionStruct.ProtoReflect.Descriptor instead.
func (*OptionStruct) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *OptionStruct) GetCode() uint32 {
if x != nil {
return x.Code
}
return 0
}
func (x *OptionStruct) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
type TypeNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
T TypeEnum `protobuf:"varint,1,opt,name=t,proto3,enum=ngolofuzz.TypeEnum" json:"t,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TypeNgdotStringArgs) Reset() {
*x = TypeNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TypeNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TypeNgdotStringArgs) ProtoMessage() {}
func (x *TypeNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TypeNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*TypeNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *TypeNgdotStringArgs) GetT() TypeEnum {
if x != nil {
return x.T
}
return TypeEnum_TypeA
}
type TypeNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
T TypeEnum `protobuf:"varint,1,opt,name=t,proto3,enum=ngolofuzz.TypeEnum" json:"t,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TypeNgdotGoStringArgs) Reset() {
*x = TypeNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TypeNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TypeNgdotGoStringArgs) ProtoMessage() {}
func (x *TypeNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TypeNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*TypeNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *TypeNgdotGoStringArgs) GetT() TypeEnum {
if x != nil {
return x.T
}
return TypeEnum_TypeA
}
type ClassNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
C ClassEnum `protobuf:"varint,1,opt,name=c,proto3,enum=ngolofuzz.ClassEnum" json:"c,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ClassNgdotStringArgs) Reset() {
*x = ClassNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ClassNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ClassNgdotStringArgs) ProtoMessage() {}
func (x *ClassNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ClassNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*ClassNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *ClassNgdotStringArgs) GetC() ClassEnum {
if x != nil {
return x.C
}
return ClassEnum_ClassINET
}
type ClassNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
C ClassEnum `protobuf:"varint,1,opt,name=c,proto3,enum=ngolofuzz.ClassEnum" json:"c,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ClassNgdotGoStringArgs) Reset() {
*x = ClassNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ClassNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ClassNgdotGoStringArgs) ProtoMessage() {}
func (x *ClassNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ClassNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*ClassNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *ClassNgdotGoStringArgs) GetC() ClassEnum {
if x != nil {
return x.C
}
return ClassEnum_ClassINET
}
type RCodeNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RCodeNgdotStringArgs) Reset() {
*x = RCodeNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RCodeNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RCodeNgdotStringArgs) ProtoMessage() {}
func (x *RCodeNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RCodeNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*RCodeNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
type RCodeNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RCodeNgdotGoStringArgs) Reset() {
*x = RCodeNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RCodeNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RCodeNgdotGoStringArgs) ProtoMessage() {}
func (x *RCodeNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RCodeNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*RCodeNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
type HeaderNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HeaderNgdotGoStringArgs) Reset() {
*x = HeaderNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HeaderNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HeaderNgdotGoStringArgs) ProtoMessage() {}
func (x *HeaderNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HeaderNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*HeaderNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
type ResourceNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ResourceNgdotGoStringArgs) Reset() {
*x = ResourceNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ResourceNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ResourceNgdotGoStringArgs) ProtoMessage() {}
func (x *ResourceNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ResourceNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*ResourceNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
type NewBuilderArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Buf []byte `protobuf:"bytes,1,opt,name=buf,proto3" json:"buf,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewBuilderArgs) Reset() {
*x = NewBuilderArgs{}
mi := &file_ngolofuzz_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewBuilderArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewBuilderArgs) ProtoMessage() {}
func (x *NewBuilderArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewBuilderArgs.ProtoReflect.Descriptor instead.
func (*NewBuilderArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{10}
}
func (x *NewBuilderArgs) GetBuf() []byte {
if x != nil {
return x.Buf
}
return nil
}
type BuilderNgdotEnableCompressionArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotEnableCompressionArgs) Reset() {
*x = BuilderNgdotEnableCompressionArgs{}
mi := &file_ngolofuzz_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotEnableCompressionArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotEnableCompressionArgs) ProtoMessage() {}
func (x *BuilderNgdotEnableCompressionArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[11]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotEnableCompressionArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotEnableCompressionArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{11}
}
type BuilderNgdotStartQuestionsArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotStartQuestionsArgs) Reset() {
*x = BuilderNgdotStartQuestionsArgs{}
mi := &file_ngolofuzz_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotStartQuestionsArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotStartQuestionsArgs) ProtoMessage() {}
func (x *BuilderNgdotStartQuestionsArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[12]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotStartQuestionsArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotStartQuestionsArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{12}
}
type BuilderNgdotStartAnswersArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotStartAnswersArgs) Reset() {
*x = BuilderNgdotStartAnswersArgs{}
mi := &file_ngolofuzz_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotStartAnswersArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotStartAnswersArgs) ProtoMessage() {}
func (x *BuilderNgdotStartAnswersArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[13]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotStartAnswersArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotStartAnswersArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{13}
}
type BuilderNgdotStartAuthoritiesArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotStartAuthoritiesArgs) Reset() {
*x = BuilderNgdotStartAuthoritiesArgs{}
mi := &file_ngolofuzz_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotStartAuthoritiesArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotStartAuthoritiesArgs) ProtoMessage() {}
func (x *BuilderNgdotStartAuthoritiesArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[14]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotStartAuthoritiesArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotStartAuthoritiesArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{14}
}
type BuilderNgdotStartAdditionalsArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotStartAdditionalsArgs) Reset() {
*x = BuilderNgdotStartAdditionalsArgs{}
mi := &file_ngolofuzz_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotStartAdditionalsArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotStartAdditionalsArgs) ProtoMessage() {}
func (x *BuilderNgdotStartAdditionalsArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[15]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotStartAdditionalsArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotStartAdditionalsArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{15}
}
type BuilderNgdotQuestionArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotQuestionArgs) Reset() {
*x = BuilderNgdotQuestionArgs{}
mi := &file_ngolofuzz_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotQuestionArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotQuestionArgs) ProtoMessage() {}
func (x *BuilderNgdotQuestionArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[16]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotQuestionArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotQuestionArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{16}
}
type BuilderNgdotCNAMEResourceArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotCNAMEResourceArgs) Reset() {
*x = BuilderNgdotCNAMEResourceArgs{}
mi := &file_ngolofuzz_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotCNAMEResourceArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotCNAMEResourceArgs) ProtoMessage() {}
func (x *BuilderNgdotCNAMEResourceArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[17]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotCNAMEResourceArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotCNAMEResourceArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{17}
}
type BuilderNgdotMXResourceArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotMXResourceArgs) Reset() {
*x = BuilderNgdotMXResourceArgs{}
mi := &file_ngolofuzz_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotMXResourceArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotMXResourceArgs) ProtoMessage() {}
func (x *BuilderNgdotMXResourceArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[18]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotMXResourceArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotMXResourceArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{18}
}
type BuilderNgdotNSResourceArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotNSResourceArgs) Reset() {
*x = BuilderNgdotNSResourceArgs{}
mi := &file_ngolofuzz_proto_msgTypes[19]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotNSResourceArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotNSResourceArgs) ProtoMessage() {}
func (x *BuilderNgdotNSResourceArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[19]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotNSResourceArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotNSResourceArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{19}
}
type BuilderNgdotPTRResourceArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotPTRResourceArgs) Reset() {
*x = BuilderNgdotPTRResourceArgs{}
mi := &file_ngolofuzz_proto_msgTypes[20]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotPTRResourceArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotPTRResourceArgs) ProtoMessage() {}
func (x *BuilderNgdotPTRResourceArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[20]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotPTRResourceArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotPTRResourceArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{20}
}
type BuilderNgdotSOAResourceArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotSOAResourceArgs) Reset() {
*x = BuilderNgdotSOAResourceArgs{}
mi := &file_ngolofuzz_proto_msgTypes[21]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotSOAResourceArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotSOAResourceArgs) ProtoMessage() {}
func (x *BuilderNgdotSOAResourceArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[21]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotSOAResourceArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotSOAResourceArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{21}
}
type BuilderNgdotTXTResourceArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotTXTResourceArgs) Reset() {
*x = BuilderNgdotTXTResourceArgs{}
mi := &file_ngolofuzz_proto_msgTypes[22]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotTXTResourceArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotTXTResourceArgs) ProtoMessage() {}
func (x *BuilderNgdotTXTResourceArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[22]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotTXTResourceArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotTXTResourceArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{22}
}
type BuilderNgdotSRVResourceArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotSRVResourceArgs) Reset() {
*x = BuilderNgdotSRVResourceArgs{}
mi := &file_ngolofuzz_proto_msgTypes[23]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotSRVResourceArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotSRVResourceArgs) ProtoMessage() {}
func (x *BuilderNgdotSRVResourceArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[23]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotSRVResourceArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotSRVResourceArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{23}
}
type BuilderNgdotAResourceArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotAResourceArgs) Reset() {
*x = BuilderNgdotAResourceArgs{}
mi := &file_ngolofuzz_proto_msgTypes[24]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotAResourceArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotAResourceArgs) ProtoMessage() {}
func (x *BuilderNgdotAResourceArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[24]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotAResourceArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotAResourceArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{24}
}
type BuilderNgdotAAAAResourceArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotAAAAResourceArgs) Reset() {
*x = BuilderNgdotAAAAResourceArgs{}
mi := &file_ngolofuzz_proto_msgTypes[25]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotAAAAResourceArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotAAAAResourceArgs) ProtoMessage() {}
func (x *BuilderNgdotAAAAResourceArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[25]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotAAAAResourceArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotAAAAResourceArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{25}
}
type BuilderNgdotOPTResourceArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotOPTResourceArgs) Reset() {
*x = BuilderNgdotOPTResourceArgs{}
mi := &file_ngolofuzz_proto_msgTypes[26]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotOPTResourceArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotOPTResourceArgs) ProtoMessage() {}
func (x *BuilderNgdotOPTResourceArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[26]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotOPTResourceArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotOPTResourceArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{26}
}
type BuilderNgdotUnknownResourceArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotUnknownResourceArgs) Reset() {
*x = BuilderNgdotUnknownResourceArgs{}
mi := &file_ngolofuzz_proto_msgTypes[27]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotUnknownResourceArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotUnknownResourceArgs) ProtoMessage() {}
func (x *BuilderNgdotUnknownResourceArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[27]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotUnknownResourceArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotUnknownResourceArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{27}
}
type BuilderNgdotFinishArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotFinishArgs) Reset() {
*x = BuilderNgdotFinishArgs{}
mi := &file_ngolofuzz_proto_msgTypes[28]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotFinishArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotFinishArgs) ProtoMessage() {}
func (x *BuilderNgdotFinishArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[28]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotFinishArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotFinishArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{28}
}
type ResourceHeaderNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ResourceHeaderNgdotGoStringArgs) Reset() {
*x = ResourceHeaderNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[29]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ResourceHeaderNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ResourceHeaderNgdotGoStringArgs) ProtoMessage() {}
func (x *ResourceHeaderNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[29]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ResourceHeaderNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*ResourceHeaderNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{29}
}
type ResourceHeaderNgdotSetEDNS0Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
UdpPayloadLen int64 `protobuf:"varint,1,opt,name=udpPayloadLen,proto3" json:"udpPayloadLen,omitempty"`
DnssecOK bool `protobuf:"varint,2,opt,name=dnssecOK,proto3" json:"dnssecOK,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ResourceHeaderNgdotSetEDNS0Args) Reset() {
*x = ResourceHeaderNgdotSetEDNS0Args{}
mi := &file_ngolofuzz_proto_msgTypes[30]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ResourceHeaderNgdotSetEDNS0Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ResourceHeaderNgdotSetEDNS0Args) ProtoMessage() {}
func (x *ResourceHeaderNgdotSetEDNS0Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[30]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ResourceHeaderNgdotSetEDNS0Args.ProtoReflect.Descriptor instead.
func (*ResourceHeaderNgdotSetEDNS0Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{30}
}
func (x *ResourceHeaderNgdotSetEDNS0Args) GetUdpPayloadLen() int64 {
if x != nil {
return x.UdpPayloadLen
}
return 0
}
func (x *ResourceHeaderNgdotSetEDNS0Args) GetDnssecOK() bool {
if x != nil {
return x.DnssecOK
}
return false
}
type ResourceHeaderNgdotDNSSECAllowedArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ResourceHeaderNgdotDNSSECAllowedArgs) Reset() {
*x = ResourceHeaderNgdotDNSSECAllowedArgs{}
mi := &file_ngolofuzz_proto_msgTypes[31]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ResourceHeaderNgdotDNSSECAllowedArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ResourceHeaderNgdotDNSSECAllowedArgs) ProtoMessage() {}
func (x *ResourceHeaderNgdotDNSSECAllowedArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[31]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ResourceHeaderNgdotDNSSECAllowedArgs.ProtoReflect.Descriptor instead.
func (*ResourceHeaderNgdotDNSSECAllowedArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{31}
}
type ResourceHeaderNgdotExtendedRCodeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ResourceHeaderNgdotExtendedRCodeArgs) Reset() {
*x = ResourceHeaderNgdotExtendedRCodeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[32]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ResourceHeaderNgdotExtendedRCodeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ResourceHeaderNgdotExtendedRCodeArgs) ProtoMessage() {}
func (x *ResourceHeaderNgdotExtendedRCodeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[32]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ResourceHeaderNgdotExtendedRCodeArgs.ProtoReflect.Descriptor instead.
func (*ResourceHeaderNgdotExtendedRCodeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{32}
}
type NewNameArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewNameArgs) Reset() {
*x = NewNameArgs{}
mi := &file_ngolofuzz_proto_msgTypes[33]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewNameArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewNameArgs) ProtoMessage() {}
func (x *NewNameArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[33]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewNameArgs.ProtoReflect.Descriptor instead.
func (*NewNameArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{33}
}
func (x *NewNameArgs) GetName() string {
if x != nil {
return x.Name
}
return ""
}
type MustNewNameArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *MustNewNameArgs) Reset() {
*x = MustNewNameArgs{}
mi := &file_ngolofuzz_proto_msgTypes[34]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *MustNewNameArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MustNewNameArgs) ProtoMessage() {}
func (x *MustNewNameArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[34]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MustNewNameArgs.ProtoReflect.Descriptor instead.
func (*MustNewNameArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{34}
}
func (x *MustNewNameArgs) GetName() string {
if x != nil {
return x.Name
}
return ""
}
type NameNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NameNgdotStringArgs) Reset() {
*x = NameNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[35]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NameNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NameNgdotStringArgs) ProtoMessage() {}
func (x *NameNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[35]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NameNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*NameNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{35}
}
type NameNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NameNgdotGoStringArgs) Reset() {
*x = NameNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[36]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NameNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NameNgdotGoStringArgs) ProtoMessage() {}
func (x *NameNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[36]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NameNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*NameNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{36}
}
type QuestionNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *QuestionNgdotGoStringArgs) Reset() {
*x = QuestionNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[37]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *QuestionNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*QuestionNgdotGoStringArgs) ProtoMessage() {}
func (x *QuestionNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[37]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use QuestionNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*QuestionNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{37}
}
type CNAMEResourceNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CNAMEResourceNgdotGoStringArgs) Reset() {
*x = CNAMEResourceNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[38]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CNAMEResourceNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CNAMEResourceNgdotGoStringArgs) ProtoMessage() {}
func (x *CNAMEResourceNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[38]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CNAMEResourceNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*CNAMEResourceNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{38}
}
type MXResourceNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *MXResourceNgdotGoStringArgs) Reset() {
*x = MXResourceNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[39]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *MXResourceNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MXResourceNgdotGoStringArgs) ProtoMessage() {}
func (x *MXResourceNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[39]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MXResourceNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*MXResourceNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{39}
}
type NSResourceNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NSResourceNgdotGoStringArgs) Reset() {
*x = NSResourceNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[40]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NSResourceNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NSResourceNgdotGoStringArgs) ProtoMessage() {}
func (x *NSResourceNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[40]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NSResourceNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*NSResourceNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{40}
}
type PTRResourceNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PTRResourceNgdotGoStringArgs) Reset() {
*x = PTRResourceNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[41]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PTRResourceNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PTRResourceNgdotGoStringArgs) ProtoMessage() {}
func (x *PTRResourceNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[41]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PTRResourceNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*PTRResourceNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{41}
}
type SOAResourceNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SOAResourceNgdotGoStringArgs) Reset() {
*x = SOAResourceNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[42]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SOAResourceNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SOAResourceNgdotGoStringArgs) ProtoMessage() {}
func (x *SOAResourceNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[42]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SOAResourceNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*SOAResourceNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{42}
}
type TXTResourceNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TXTResourceNgdotGoStringArgs) Reset() {
*x = TXTResourceNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[43]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TXTResourceNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TXTResourceNgdotGoStringArgs) ProtoMessage() {}
func (x *TXTResourceNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[43]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TXTResourceNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*TXTResourceNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{43}
}
type SRVResourceNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SRVResourceNgdotGoStringArgs) Reset() {
*x = SRVResourceNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[44]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SRVResourceNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SRVResourceNgdotGoStringArgs) ProtoMessage() {}
func (x *SRVResourceNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[44]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SRVResourceNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*SRVResourceNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{44}
}
type AResourceNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *AResourceNgdotGoStringArgs) Reset() {
*x = AResourceNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[45]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AResourceNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AResourceNgdotGoStringArgs) ProtoMessage() {}
func (x *AResourceNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[45]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AResourceNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*AResourceNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{45}
}
type AAAAResourceNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *AAAAResourceNgdotGoStringArgs) Reset() {
*x = AAAAResourceNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[46]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AAAAResourceNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AAAAResourceNgdotGoStringArgs) ProtoMessage() {}
func (x *AAAAResourceNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[46]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AAAAResourceNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*AAAAResourceNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{46}
}
type OptionNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
O *OptionStruct `protobuf:"bytes,1,opt,name=o,proto3" json:"o,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *OptionNgdotGoStringArgs) Reset() {
*x = OptionNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[47]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *OptionNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*OptionNgdotGoStringArgs) ProtoMessage() {}
func (x *OptionNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[47]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use OptionNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*OptionNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{47}
}
func (x *OptionNgdotGoStringArgs) GetO() *OptionStruct {
if x != nil {
return x.O
}
return nil
}
type OPTResourceNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *OPTResourceNgdotGoStringArgs) Reset() {
*x = OPTResourceNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[48]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *OPTResourceNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*OPTResourceNgdotGoStringArgs) ProtoMessage() {}
func (x *OPTResourceNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[48]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use OPTResourceNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*OPTResourceNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{48}
}
type UnknownResourceNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *UnknownResourceNgdotGoStringArgs) Reset() {
*x = UnknownResourceNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[49]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *UnknownResourceNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*UnknownResourceNgdotGoStringArgs) ProtoMessage() {}
func (x *UnknownResourceNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[49]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use UnknownResourceNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*UnknownResourceNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{49}
}
type SVCBResourceNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SVCBResourceNgdotGoStringArgs) Reset() {
*x = SVCBResourceNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[50]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SVCBResourceNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SVCBResourceNgdotGoStringArgs) ProtoMessage() {}
func (x *SVCBResourceNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[50]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SVCBResourceNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*SVCBResourceNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{50}
}
type HTTPSResourceNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HTTPSResourceNgdotGoStringArgs) Reset() {
*x = HTTPSResourceNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[51]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HTTPSResourceNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HTTPSResourceNgdotGoStringArgs) ProtoMessage() {}
func (x *HTTPSResourceNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[51]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HTTPSResourceNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*HTTPSResourceNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{51}
}
type SVCBResourceNgdotGetParamArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key SVCParamKeyEnum `protobuf:"varint,1,opt,name=key,proto3,enum=ngolofuzz.SVCParamKeyEnum" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SVCBResourceNgdotGetParamArgs) Reset() {
*x = SVCBResourceNgdotGetParamArgs{}
mi := &file_ngolofuzz_proto_msgTypes[52]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SVCBResourceNgdotGetParamArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SVCBResourceNgdotGetParamArgs) ProtoMessage() {}
func (x *SVCBResourceNgdotGetParamArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[52]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SVCBResourceNgdotGetParamArgs.ProtoReflect.Descriptor instead.
func (*SVCBResourceNgdotGetParamArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{52}
}
func (x *SVCBResourceNgdotGetParamArgs) GetKey() SVCParamKeyEnum {
if x != nil {
return x.Key
}
return SVCParamKeyEnum_SVCParamMandatory
}
type SVCBResourceNgdotSetParamArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key SVCParamKeyEnum `protobuf:"varint,1,opt,name=key,proto3,enum=ngolofuzz.SVCParamKeyEnum" json:"key,omitempty"`
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SVCBResourceNgdotSetParamArgs) Reset() {
*x = SVCBResourceNgdotSetParamArgs{}
mi := &file_ngolofuzz_proto_msgTypes[53]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SVCBResourceNgdotSetParamArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SVCBResourceNgdotSetParamArgs) ProtoMessage() {}
func (x *SVCBResourceNgdotSetParamArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[53]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SVCBResourceNgdotSetParamArgs.ProtoReflect.Descriptor instead.
func (*SVCBResourceNgdotSetParamArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{53}
}
func (x *SVCBResourceNgdotSetParamArgs) GetKey() SVCParamKeyEnum {
if x != nil {
return x.Key
}
return SVCParamKeyEnum_SVCParamMandatory
}
func (x *SVCBResourceNgdotSetParamArgs) GetValue() []byte {
if x != nil {
return x.Value
}
return nil
}
type SVCBResourceNgdotDeleteParamArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key SVCParamKeyEnum `protobuf:"varint,1,opt,name=key,proto3,enum=ngolofuzz.SVCParamKeyEnum" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SVCBResourceNgdotDeleteParamArgs) Reset() {
*x = SVCBResourceNgdotDeleteParamArgs{}
mi := &file_ngolofuzz_proto_msgTypes[54]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SVCBResourceNgdotDeleteParamArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SVCBResourceNgdotDeleteParamArgs) ProtoMessage() {}
func (x *SVCBResourceNgdotDeleteParamArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[54]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SVCBResourceNgdotDeleteParamArgs.ProtoReflect.Descriptor instead.
func (*SVCBResourceNgdotDeleteParamArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{54}
}
func (x *SVCBResourceNgdotDeleteParamArgs) GetKey() SVCParamKeyEnum {
if x != nil {
return x.Key
}
return SVCParamKeyEnum_SVCParamMandatory
}
type SVCParamNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
P *SVCParamStruct `protobuf:"bytes,1,opt,name=p,proto3" json:"p,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SVCParamNgdotGoStringArgs) Reset() {
*x = SVCParamNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[55]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SVCParamNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SVCParamNgdotGoStringArgs) ProtoMessage() {}
func (x *SVCParamNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[55]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SVCParamNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*SVCParamNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{55}
}
func (x *SVCParamNgdotGoStringArgs) GetP() *SVCParamStruct {
if x != nil {
return x.P
}
return nil
}
type SVCParamKeyNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
K SVCParamKeyEnum `protobuf:"varint,1,opt,name=k,proto3,enum=ngolofuzz.SVCParamKeyEnum" json:"k,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SVCParamKeyNgdotStringArgs) Reset() {
*x = SVCParamKeyNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[56]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SVCParamKeyNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SVCParamKeyNgdotStringArgs) ProtoMessage() {}
func (x *SVCParamKeyNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[56]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SVCParamKeyNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*SVCParamKeyNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{56}
}
func (x *SVCParamKeyNgdotStringArgs) GetK() SVCParamKeyEnum {
if x != nil {
return x.K
}
return SVCParamKeyEnum_SVCParamMandatory
}
type SVCParamKeyNgdotGoStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
K SVCParamKeyEnum `protobuf:"varint,1,opt,name=k,proto3,enum=ngolofuzz.SVCParamKeyEnum" json:"k,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SVCParamKeyNgdotGoStringArgs) Reset() {
*x = SVCParamKeyNgdotGoStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[57]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SVCParamKeyNgdotGoStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SVCParamKeyNgdotGoStringArgs) ProtoMessage() {}
func (x *SVCParamKeyNgdotGoStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[57]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SVCParamKeyNgdotGoStringArgs.ProtoReflect.Descriptor instead.
func (*SVCParamKeyNgdotGoStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{57}
}
func (x *SVCParamKeyNgdotGoStringArgs) GetK() SVCParamKeyEnum {
if x != nil {
return x.K
}
return SVCParamKeyEnum_SVCParamMandatory
}
type BuilderNgdotSVCBResourceArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotSVCBResourceArgs) Reset() {
*x = BuilderNgdotSVCBResourceArgs{}
mi := &file_ngolofuzz_proto_msgTypes[58]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotSVCBResourceArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotSVCBResourceArgs) ProtoMessage() {}
func (x *BuilderNgdotSVCBResourceArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[58]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotSVCBResourceArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotSVCBResourceArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{58}
}
type BuilderNgdotHTTPSResourceArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotHTTPSResourceArgs) Reset() {
*x = BuilderNgdotHTTPSResourceArgs{}
mi := &file_ngolofuzz_proto_msgTypes[59]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotHTTPSResourceArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotHTTPSResourceArgs) ProtoMessage() {}
func (x *BuilderNgdotHTTPSResourceArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[59]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotHTTPSResourceArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotHTTPSResourceArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{59}
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_TypeNgdotString
// *NgoloFuzzOne_TypeNgdotGoString
// *NgoloFuzzOne_ClassNgdotString
// *NgoloFuzzOne_ClassNgdotGoString
// *NgoloFuzzOne_RCodeNgdotString
// *NgoloFuzzOne_RCodeNgdotGoString
// *NgoloFuzzOne_HeaderNgdotGoString
// *NgoloFuzzOne_ResourceNgdotGoString
// *NgoloFuzzOne_NewBuilder
// *NgoloFuzzOne_BuilderNgdotEnableCompression
// *NgoloFuzzOne_BuilderNgdotStartQuestions
// *NgoloFuzzOne_BuilderNgdotStartAnswers
// *NgoloFuzzOne_BuilderNgdotStartAuthorities
// *NgoloFuzzOne_BuilderNgdotStartAdditionals
// *NgoloFuzzOne_BuilderNgdotQuestion
// *NgoloFuzzOne_BuilderNgdotCNAMEResource
// *NgoloFuzzOne_BuilderNgdotMXResource
// *NgoloFuzzOne_BuilderNgdotNSResource
// *NgoloFuzzOne_BuilderNgdotPTRResource
// *NgoloFuzzOne_BuilderNgdotSOAResource
// *NgoloFuzzOne_BuilderNgdotTXTResource
// *NgoloFuzzOne_BuilderNgdotSRVResource
// *NgoloFuzzOne_BuilderNgdotAResource
// *NgoloFuzzOne_BuilderNgdotAAAAResource
// *NgoloFuzzOne_BuilderNgdotOPTResource
// *NgoloFuzzOne_BuilderNgdotUnknownResource
// *NgoloFuzzOne_BuilderNgdotFinish
// *NgoloFuzzOne_ResourceHeaderNgdotGoString
// *NgoloFuzzOne_ResourceHeaderNgdotSetEDNS0
// *NgoloFuzzOne_ResourceHeaderNgdotDNSSECAllowed
// *NgoloFuzzOne_ResourceHeaderNgdotExtendedRCode
// *NgoloFuzzOne_NewName
// *NgoloFuzzOne_MustNewName
// *NgoloFuzzOne_NameNgdotString
// *NgoloFuzzOne_NameNgdotGoString
// *NgoloFuzzOne_QuestionNgdotGoString
// *NgoloFuzzOne_CNAMEResourceNgdotGoString
// *NgoloFuzzOne_MXResourceNgdotGoString
// *NgoloFuzzOne_NSResourceNgdotGoString
// *NgoloFuzzOne_PTRResourceNgdotGoString
// *NgoloFuzzOne_SOAResourceNgdotGoString
// *NgoloFuzzOne_TXTResourceNgdotGoString
// *NgoloFuzzOne_SRVResourceNgdotGoString
// *NgoloFuzzOne_AResourceNgdotGoString
// *NgoloFuzzOne_AAAAResourceNgdotGoString
// *NgoloFuzzOne_OptionNgdotGoString
// *NgoloFuzzOne_OPTResourceNgdotGoString
// *NgoloFuzzOne_UnknownResourceNgdotGoString
// *NgoloFuzzOne_SVCBResourceNgdotGoString
// *NgoloFuzzOne_HTTPSResourceNgdotGoString
// *NgoloFuzzOne_SVCBResourceNgdotGetParam
// *NgoloFuzzOne_SVCBResourceNgdotSetParam
// *NgoloFuzzOne_SVCBResourceNgdotDeleteParam
// *NgoloFuzzOne_SVCParamNgdotGoString
// *NgoloFuzzOne_SVCParamKeyNgdotString
// *NgoloFuzzOne_SVCParamKeyNgdotGoString
// *NgoloFuzzOne_BuilderNgdotSVCBResource
// *NgoloFuzzOne_BuilderNgdotHTTPSResource
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[60]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[60]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{60}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetTypeNgdotString() *TypeNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TypeNgdotString); ok {
return x.TypeNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetTypeNgdotGoString() *TypeNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TypeNgdotGoString); ok {
return x.TypeNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetClassNgdotString() *ClassNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ClassNgdotString); ok {
return x.ClassNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetClassNgdotGoString() *ClassNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ClassNgdotGoString); ok {
return x.ClassNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetRCodeNgdotString() *RCodeNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_RCodeNgdotString); ok {
return x.RCodeNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetRCodeNgdotGoString() *RCodeNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_RCodeNgdotGoString); ok {
return x.RCodeNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetHeaderNgdotGoString() *HeaderNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_HeaderNgdotGoString); ok {
return x.HeaderNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetResourceNgdotGoString() *ResourceNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ResourceNgdotGoString); ok {
return x.ResourceNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewBuilder() *NewBuilderArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewBuilder); ok {
return x.NewBuilder
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotEnableCompression() *BuilderNgdotEnableCompressionArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotEnableCompression); ok {
return x.BuilderNgdotEnableCompression
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotStartQuestions() *BuilderNgdotStartQuestionsArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotStartQuestions); ok {
return x.BuilderNgdotStartQuestions
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotStartAnswers() *BuilderNgdotStartAnswersArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotStartAnswers); ok {
return x.BuilderNgdotStartAnswers
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotStartAuthorities() *BuilderNgdotStartAuthoritiesArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotStartAuthorities); ok {
return x.BuilderNgdotStartAuthorities
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotStartAdditionals() *BuilderNgdotStartAdditionalsArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotStartAdditionals); ok {
return x.BuilderNgdotStartAdditionals
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotQuestion() *BuilderNgdotQuestionArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotQuestion); ok {
return x.BuilderNgdotQuestion
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotCNAMEResource() *BuilderNgdotCNAMEResourceArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotCNAMEResource); ok {
return x.BuilderNgdotCNAMEResource
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotMXResource() *BuilderNgdotMXResourceArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotMXResource); ok {
return x.BuilderNgdotMXResource
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotNSResource() *BuilderNgdotNSResourceArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotNSResource); ok {
return x.BuilderNgdotNSResource
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotPTRResource() *BuilderNgdotPTRResourceArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotPTRResource); ok {
return x.BuilderNgdotPTRResource
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotSOAResource() *BuilderNgdotSOAResourceArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotSOAResource); ok {
return x.BuilderNgdotSOAResource
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotTXTResource() *BuilderNgdotTXTResourceArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotTXTResource); ok {
return x.BuilderNgdotTXTResource
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotSRVResource() *BuilderNgdotSRVResourceArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotSRVResource); ok {
return x.BuilderNgdotSRVResource
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotAResource() *BuilderNgdotAResourceArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotAResource); ok {
return x.BuilderNgdotAResource
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotAAAAResource() *BuilderNgdotAAAAResourceArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotAAAAResource); ok {
return x.BuilderNgdotAAAAResource
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotOPTResource() *BuilderNgdotOPTResourceArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotOPTResource); ok {
return x.BuilderNgdotOPTResource
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotUnknownResource() *BuilderNgdotUnknownResourceArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotUnknownResource); ok {
return x.BuilderNgdotUnknownResource
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotFinish() *BuilderNgdotFinishArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotFinish); ok {
return x.BuilderNgdotFinish
}
}
return nil
}
func (x *NgoloFuzzOne) GetResourceHeaderNgdotGoString() *ResourceHeaderNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ResourceHeaderNgdotGoString); ok {
return x.ResourceHeaderNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetResourceHeaderNgdotSetEDNS0() *ResourceHeaderNgdotSetEDNS0Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ResourceHeaderNgdotSetEDNS0); ok {
return x.ResourceHeaderNgdotSetEDNS0
}
}
return nil
}
func (x *NgoloFuzzOne) GetResourceHeaderNgdotDNSSECAllowed() *ResourceHeaderNgdotDNSSECAllowedArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ResourceHeaderNgdotDNSSECAllowed); ok {
return x.ResourceHeaderNgdotDNSSECAllowed
}
}
return nil
}
func (x *NgoloFuzzOne) GetResourceHeaderNgdotExtendedRCode() *ResourceHeaderNgdotExtendedRCodeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ResourceHeaderNgdotExtendedRCode); ok {
return x.ResourceHeaderNgdotExtendedRCode
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewName() *NewNameArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewName); ok {
return x.NewName
}
}
return nil
}
func (x *NgoloFuzzOne) GetMustNewName() *MustNewNameArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_MustNewName); ok {
return x.MustNewName
}
}
return nil
}
func (x *NgoloFuzzOne) GetNameNgdotString() *NameNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NameNgdotString); ok {
return x.NameNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetNameNgdotGoString() *NameNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NameNgdotGoString); ok {
return x.NameNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetQuestionNgdotGoString() *QuestionNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_QuestionNgdotGoString); ok {
return x.QuestionNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetCNAMEResourceNgdotGoString() *CNAMEResourceNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CNAMEResourceNgdotGoString); ok {
return x.CNAMEResourceNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetMXResourceNgdotGoString() *MXResourceNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_MXResourceNgdotGoString); ok {
return x.MXResourceNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetNSResourceNgdotGoString() *NSResourceNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NSResourceNgdotGoString); ok {
return x.NSResourceNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetPTRResourceNgdotGoString() *PTRResourceNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_PTRResourceNgdotGoString); ok {
return x.PTRResourceNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetSOAResourceNgdotGoString() *SOAResourceNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_SOAResourceNgdotGoString); ok {
return x.SOAResourceNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetTXTResourceNgdotGoString() *TXTResourceNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TXTResourceNgdotGoString); ok {
return x.TXTResourceNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetSRVResourceNgdotGoString() *SRVResourceNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_SRVResourceNgdotGoString); ok {
return x.SRVResourceNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetAResourceNgdotGoString() *AResourceNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_AResourceNgdotGoString); ok {
return x.AResourceNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetAAAAResourceNgdotGoString() *AAAAResourceNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_AAAAResourceNgdotGoString); ok {
return x.AAAAResourceNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetOptionNgdotGoString() *OptionNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_OptionNgdotGoString); ok {
return x.OptionNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetOPTResourceNgdotGoString() *OPTResourceNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_OPTResourceNgdotGoString); ok {
return x.OPTResourceNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetUnknownResourceNgdotGoString() *UnknownResourceNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_UnknownResourceNgdotGoString); ok {
return x.UnknownResourceNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetSVCBResourceNgdotGoString() *SVCBResourceNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_SVCBResourceNgdotGoString); ok {
return x.SVCBResourceNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetHTTPSResourceNgdotGoString() *HTTPSResourceNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_HTTPSResourceNgdotGoString); ok {
return x.HTTPSResourceNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetSVCBResourceNgdotGetParam() *SVCBResourceNgdotGetParamArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_SVCBResourceNgdotGetParam); ok {
return x.SVCBResourceNgdotGetParam
}
}
return nil
}
func (x *NgoloFuzzOne) GetSVCBResourceNgdotSetParam() *SVCBResourceNgdotSetParamArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_SVCBResourceNgdotSetParam); ok {
return x.SVCBResourceNgdotSetParam
}
}
return nil
}
func (x *NgoloFuzzOne) GetSVCBResourceNgdotDeleteParam() *SVCBResourceNgdotDeleteParamArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_SVCBResourceNgdotDeleteParam); ok {
return x.SVCBResourceNgdotDeleteParam
}
}
return nil
}
func (x *NgoloFuzzOne) GetSVCParamNgdotGoString() *SVCParamNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_SVCParamNgdotGoString); ok {
return x.SVCParamNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetSVCParamKeyNgdotString() *SVCParamKeyNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_SVCParamKeyNgdotString); ok {
return x.SVCParamKeyNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetSVCParamKeyNgdotGoString() *SVCParamKeyNgdotGoStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_SVCParamKeyNgdotGoString); ok {
return x.SVCParamKeyNgdotGoString
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotSVCBResource() *BuilderNgdotSVCBResourceArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotSVCBResource); ok {
return x.BuilderNgdotSVCBResource
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotHTTPSResource() *BuilderNgdotHTTPSResourceArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotHTTPSResource); ok {
return x.BuilderNgdotHTTPSResource
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_TypeNgdotString struct {
TypeNgdotString *TypeNgdotStringArgs `protobuf:"bytes,1,opt,name=TypeNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_TypeNgdotGoString struct {
TypeNgdotGoString *TypeNgdotGoStringArgs `protobuf:"bytes,2,opt,name=TypeNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_ClassNgdotString struct {
ClassNgdotString *ClassNgdotStringArgs `protobuf:"bytes,3,opt,name=ClassNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_ClassNgdotGoString struct {
ClassNgdotGoString *ClassNgdotGoStringArgs `protobuf:"bytes,4,opt,name=ClassNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_RCodeNgdotString struct {
RCodeNgdotString *RCodeNgdotStringArgs `protobuf:"bytes,5,opt,name=RCodeNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_RCodeNgdotGoString struct {
RCodeNgdotGoString *RCodeNgdotGoStringArgs `protobuf:"bytes,6,opt,name=RCodeNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_HeaderNgdotGoString struct {
HeaderNgdotGoString *HeaderNgdotGoStringArgs `protobuf:"bytes,7,opt,name=HeaderNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_ResourceNgdotGoString struct {
ResourceNgdotGoString *ResourceNgdotGoStringArgs `protobuf:"bytes,8,opt,name=ResourceNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_NewBuilder struct {
NewBuilder *NewBuilderArgs `protobuf:"bytes,9,opt,name=NewBuilder,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotEnableCompression struct {
BuilderNgdotEnableCompression *BuilderNgdotEnableCompressionArgs `protobuf:"bytes,10,opt,name=BuilderNgdotEnableCompression,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotStartQuestions struct {
BuilderNgdotStartQuestions *BuilderNgdotStartQuestionsArgs `protobuf:"bytes,11,opt,name=BuilderNgdotStartQuestions,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotStartAnswers struct {
BuilderNgdotStartAnswers *BuilderNgdotStartAnswersArgs `protobuf:"bytes,12,opt,name=BuilderNgdotStartAnswers,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotStartAuthorities struct {
BuilderNgdotStartAuthorities *BuilderNgdotStartAuthoritiesArgs `protobuf:"bytes,13,opt,name=BuilderNgdotStartAuthorities,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotStartAdditionals struct {
BuilderNgdotStartAdditionals *BuilderNgdotStartAdditionalsArgs `protobuf:"bytes,14,opt,name=BuilderNgdotStartAdditionals,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotQuestion struct {
BuilderNgdotQuestion *BuilderNgdotQuestionArgs `protobuf:"bytes,15,opt,name=BuilderNgdotQuestion,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotCNAMEResource struct {
BuilderNgdotCNAMEResource *BuilderNgdotCNAMEResourceArgs `protobuf:"bytes,16,opt,name=BuilderNgdotCNAMEResource,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotMXResource struct {
BuilderNgdotMXResource *BuilderNgdotMXResourceArgs `protobuf:"bytes,17,opt,name=BuilderNgdotMXResource,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotNSResource struct {
BuilderNgdotNSResource *BuilderNgdotNSResourceArgs `protobuf:"bytes,18,opt,name=BuilderNgdotNSResource,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotPTRResource struct {
BuilderNgdotPTRResource *BuilderNgdotPTRResourceArgs `protobuf:"bytes,19,opt,name=BuilderNgdotPTRResource,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotSOAResource struct {
BuilderNgdotSOAResource *BuilderNgdotSOAResourceArgs `protobuf:"bytes,20,opt,name=BuilderNgdotSOAResource,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotTXTResource struct {
BuilderNgdotTXTResource *BuilderNgdotTXTResourceArgs `protobuf:"bytes,21,opt,name=BuilderNgdotTXTResource,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotSRVResource struct {
BuilderNgdotSRVResource *BuilderNgdotSRVResourceArgs `protobuf:"bytes,22,opt,name=BuilderNgdotSRVResource,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotAResource struct {
BuilderNgdotAResource *BuilderNgdotAResourceArgs `protobuf:"bytes,23,opt,name=BuilderNgdotAResource,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotAAAAResource struct {
BuilderNgdotAAAAResource *BuilderNgdotAAAAResourceArgs `protobuf:"bytes,24,opt,name=BuilderNgdotAAAAResource,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotOPTResource struct {
BuilderNgdotOPTResource *BuilderNgdotOPTResourceArgs `protobuf:"bytes,25,opt,name=BuilderNgdotOPTResource,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotUnknownResource struct {
BuilderNgdotUnknownResource *BuilderNgdotUnknownResourceArgs `protobuf:"bytes,26,opt,name=BuilderNgdotUnknownResource,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotFinish struct {
BuilderNgdotFinish *BuilderNgdotFinishArgs `protobuf:"bytes,27,opt,name=BuilderNgdotFinish,proto3,oneof"`
}
type NgoloFuzzOne_ResourceHeaderNgdotGoString struct {
ResourceHeaderNgdotGoString *ResourceHeaderNgdotGoStringArgs `protobuf:"bytes,28,opt,name=ResourceHeaderNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_ResourceHeaderNgdotSetEDNS0 struct {
ResourceHeaderNgdotSetEDNS0 *ResourceHeaderNgdotSetEDNS0Args `protobuf:"bytes,29,opt,name=ResourceHeaderNgdotSetEDNS0,proto3,oneof"`
}
type NgoloFuzzOne_ResourceHeaderNgdotDNSSECAllowed struct {
ResourceHeaderNgdotDNSSECAllowed *ResourceHeaderNgdotDNSSECAllowedArgs `protobuf:"bytes,30,opt,name=ResourceHeaderNgdotDNSSECAllowed,proto3,oneof"`
}
type NgoloFuzzOne_ResourceHeaderNgdotExtendedRCode struct {
ResourceHeaderNgdotExtendedRCode *ResourceHeaderNgdotExtendedRCodeArgs `protobuf:"bytes,31,opt,name=ResourceHeaderNgdotExtendedRCode,proto3,oneof"`
}
type NgoloFuzzOne_NewName struct {
NewName *NewNameArgs `protobuf:"bytes,32,opt,name=NewName,proto3,oneof"`
}
type NgoloFuzzOne_MustNewName struct {
MustNewName *MustNewNameArgs `protobuf:"bytes,33,opt,name=MustNewName,proto3,oneof"`
}
type NgoloFuzzOne_NameNgdotString struct {
NameNgdotString *NameNgdotStringArgs `protobuf:"bytes,34,opt,name=NameNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_NameNgdotGoString struct {
NameNgdotGoString *NameNgdotGoStringArgs `protobuf:"bytes,35,opt,name=NameNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_QuestionNgdotGoString struct {
QuestionNgdotGoString *QuestionNgdotGoStringArgs `protobuf:"bytes,36,opt,name=QuestionNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_CNAMEResourceNgdotGoString struct {
CNAMEResourceNgdotGoString *CNAMEResourceNgdotGoStringArgs `protobuf:"bytes,37,opt,name=CNAMEResourceNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_MXResourceNgdotGoString struct {
MXResourceNgdotGoString *MXResourceNgdotGoStringArgs `protobuf:"bytes,38,opt,name=MXResourceNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_NSResourceNgdotGoString struct {
NSResourceNgdotGoString *NSResourceNgdotGoStringArgs `protobuf:"bytes,39,opt,name=NSResourceNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_PTRResourceNgdotGoString struct {
PTRResourceNgdotGoString *PTRResourceNgdotGoStringArgs `protobuf:"bytes,40,opt,name=PTRResourceNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_SOAResourceNgdotGoString struct {
SOAResourceNgdotGoString *SOAResourceNgdotGoStringArgs `protobuf:"bytes,41,opt,name=SOAResourceNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_TXTResourceNgdotGoString struct {
TXTResourceNgdotGoString *TXTResourceNgdotGoStringArgs `protobuf:"bytes,42,opt,name=TXTResourceNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_SRVResourceNgdotGoString struct {
SRVResourceNgdotGoString *SRVResourceNgdotGoStringArgs `protobuf:"bytes,43,opt,name=SRVResourceNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_AResourceNgdotGoString struct {
AResourceNgdotGoString *AResourceNgdotGoStringArgs `protobuf:"bytes,44,opt,name=AResourceNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_AAAAResourceNgdotGoString struct {
AAAAResourceNgdotGoString *AAAAResourceNgdotGoStringArgs `protobuf:"bytes,45,opt,name=AAAAResourceNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_OptionNgdotGoString struct {
OptionNgdotGoString *OptionNgdotGoStringArgs `protobuf:"bytes,46,opt,name=OptionNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_OPTResourceNgdotGoString struct {
OPTResourceNgdotGoString *OPTResourceNgdotGoStringArgs `protobuf:"bytes,47,opt,name=OPTResourceNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_UnknownResourceNgdotGoString struct {
UnknownResourceNgdotGoString *UnknownResourceNgdotGoStringArgs `protobuf:"bytes,48,opt,name=UnknownResourceNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_SVCBResourceNgdotGoString struct {
SVCBResourceNgdotGoString *SVCBResourceNgdotGoStringArgs `protobuf:"bytes,49,opt,name=SVCBResourceNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_HTTPSResourceNgdotGoString struct {
HTTPSResourceNgdotGoString *HTTPSResourceNgdotGoStringArgs `protobuf:"bytes,50,opt,name=HTTPSResourceNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_SVCBResourceNgdotGetParam struct {
SVCBResourceNgdotGetParam *SVCBResourceNgdotGetParamArgs `protobuf:"bytes,51,opt,name=SVCBResourceNgdotGetParam,proto3,oneof"`
}
type NgoloFuzzOne_SVCBResourceNgdotSetParam struct {
SVCBResourceNgdotSetParam *SVCBResourceNgdotSetParamArgs `protobuf:"bytes,52,opt,name=SVCBResourceNgdotSetParam,proto3,oneof"`
}
type NgoloFuzzOne_SVCBResourceNgdotDeleteParam struct {
SVCBResourceNgdotDeleteParam *SVCBResourceNgdotDeleteParamArgs `protobuf:"bytes,53,opt,name=SVCBResourceNgdotDeleteParam,proto3,oneof"`
}
type NgoloFuzzOne_SVCParamNgdotGoString struct {
SVCParamNgdotGoString *SVCParamNgdotGoStringArgs `protobuf:"bytes,54,opt,name=SVCParamNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_SVCParamKeyNgdotString struct {
SVCParamKeyNgdotString *SVCParamKeyNgdotStringArgs `protobuf:"bytes,55,opt,name=SVCParamKeyNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_SVCParamKeyNgdotGoString struct {
SVCParamKeyNgdotGoString *SVCParamKeyNgdotGoStringArgs `protobuf:"bytes,56,opt,name=SVCParamKeyNgdotGoString,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotSVCBResource struct {
BuilderNgdotSVCBResource *BuilderNgdotSVCBResourceArgs `protobuf:"bytes,57,opt,name=BuilderNgdotSVCBResource,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotHTTPSResource struct {
BuilderNgdotHTTPSResource *BuilderNgdotHTTPSResourceArgs `protobuf:"bytes,58,opt,name=BuilderNgdotHTTPSResource,proto3,oneof"`
}
func (*NgoloFuzzOne_TypeNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TypeNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ClassNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ClassNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_RCodeNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_RCodeNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_HeaderNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ResourceNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewBuilder) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotEnableCompression) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotStartQuestions) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotStartAnswers) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotStartAuthorities) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotStartAdditionals) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotQuestion) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotCNAMEResource) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotMXResource) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotNSResource) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotPTRResource) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotSOAResource) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotTXTResource) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotSRVResource) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotAResource) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotAAAAResource) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotOPTResource) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotUnknownResource) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotFinish) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ResourceHeaderNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ResourceHeaderNgdotSetEDNS0) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ResourceHeaderNgdotDNSSECAllowed) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ResourceHeaderNgdotExtendedRCode) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewName) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_MustNewName) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NameNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NameNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_QuestionNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CNAMEResourceNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_MXResourceNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NSResourceNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_PTRResourceNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_SOAResourceNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TXTResourceNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_SRVResourceNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_AResourceNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_AAAAResourceNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_OptionNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_OPTResourceNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_UnknownResourceNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_SVCBResourceNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_HTTPSResourceNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_SVCBResourceNgdotGetParam) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_SVCBResourceNgdotSetParam) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_SVCBResourceNgdotDeleteParam) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_SVCParamNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_SVCParamKeyNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_SVCParamKeyNgdotGoString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotSVCBResource) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotHTTPSResource) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[61]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[61]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{61}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[62]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[62]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{62}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"T\n" +
"\x0eSVCParamStruct\x12,\n" +
"\x03Key\x18\x01 \x01(\x0e2\x1a.ngolofuzz.SVCParamKeyEnumR\x03Key\x12\x14\n" +
"\x05Value\x18\x02 \x01(\fR\x05Value\"6\n" +
"\fOptionStruct\x12\x12\n" +
"\x04Code\x18\x01 \x01(\rR\x04Code\x12\x12\n" +
"\x04Data\x18\x02 \x01(\fR\x04Data\"8\n" +
"\x13TypeNgdotStringArgs\x12!\n" +
"\x01t\x18\x01 \x01(\x0e2\x13.ngolofuzz.TypeEnumR\x01t\":\n" +
"\x15TypeNgdotGoStringArgs\x12!\n" +
"\x01t\x18\x01 \x01(\x0e2\x13.ngolofuzz.TypeEnumR\x01t\":\n" +
"\x14ClassNgdotStringArgs\x12\"\n" +
"\x01c\x18\x01 \x01(\x0e2\x14.ngolofuzz.ClassEnumR\x01c\"<\n" +
"\x16ClassNgdotGoStringArgs\x12\"\n" +
"\x01c\x18\x01 \x01(\x0e2\x14.ngolofuzz.ClassEnumR\x01c\"\x16\n" +
"\x14RCodeNgdotStringArgs\"\x18\n" +
"\x16RCodeNgdotGoStringArgs\"\x19\n" +
"\x17HeaderNgdotGoStringArgs\"\x1b\n" +
"\x19ResourceNgdotGoStringArgs\"\"\n" +
"\x0eNewBuilderArgs\x12\x10\n" +
"\x03buf\x18\x01 \x01(\fR\x03buf\"#\n" +
"!BuilderNgdotEnableCompressionArgs\" \n" +
"\x1eBuilderNgdotStartQuestionsArgs\"\x1e\n" +
"\x1cBuilderNgdotStartAnswersArgs\"\"\n" +
" BuilderNgdotStartAuthoritiesArgs\"\"\n" +
" BuilderNgdotStartAdditionalsArgs\"\x1a\n" +
"\x18BuilderNgdotQuestionArgs\"\x1f\n" +
"\x1dBuilderNgdotCNAMEResourceArgs\"\x1c\n" +
"\x1aBuilderNgdotMXResourceArgs\"\x1c\n" +
"\x1aBuilderNgdotNSResourceArgs\"\x1d\n" +
"\x1bBuilderNgdotPTRResourceArgs\"\x1d\n" +
"\x1bBuilderNgdotSOAResourceArgs\"\x1d\n" +
"\x1bBuilderNgdotTXTResourceArgs\"\x1d\n" +
"\x1bBuilderNgdotSRVResourceArgs\"\x1b\n" +
"\x19BuilderNgdotAResourceArgs\"\x1e\n" +
"\x1cBuilderNgdotAAAAResourceArgs\"\x1d\n" +
"\x1bBuilderNgdotOPTResourceArgs\"!\n" +
"\x1fBuilderNgdotUnknownResourceArgs\"\x18\n" +
"\x16BuilderNgdotFinishArgs\"!\n" +
"\x1fResourceHeaderNgdotGoStringArgs\"c\n" +
"\x1fResourceHeaderNgdotSetEDNS0Args\x12$\n" +
"\rudpPayloadLen\x18\x01 \x01(\x03R\rudpPayloadLen\x12\x1a\n" +
"\bdnssecOK\x18\x02 \x01(\bR\bdnssecOK\"&\n" +
"$ResourceHeaderNgdotDNSSECAllowedArgs\"&\n" +
"$ResourceHeaderNgdotExtendedRCodeArgs\"!\n" +
"\vNewNameArgs\x12\x12\n" +
"\x04name\x18\x01 \x01(\tR\x04name\"%\n" +
"\x0fMustNewNameArgs\x12\x12\n" +
"\x04name\x18\x01 \x01(\tR\x04name\"\x15\n" +
"\x13NameNgdotStringArgs\"\x17\n" +
"\x15NameNgdotGoStringArgs\"\x1b\n" +
"\x19QuestionNgdotGoStringArgs\" \n" +
"\x1eCNAMEResourceNgdotGoStringArgs\"\x1d\n" +
"\x1bMXResourceNgdotGoStringArgs\"\x1d\n" +
"\x1bNSResourceNgdotGoStringArgs\"\x1e\n" +
"\x1cPTRResourceNgdotGoStringArgs\"\x1e\n" +
"\x1cSOAResourceNgdotGoStringArgs\"\x1e\n" +
"\x1cTXTResourceNgdotGoStringArgs\"\x1e\n" +
"\x1cSRVResourceNgdotGoStringArgs\"\x1c\n" +
"\x1aAResourceNgdotGoStringArgs\"\x1f\n" +
"\x1dAAAAResourceNgdotGoStringArgs\"@\n" +
"\x17OptionNgdotGoStringArgs\x12%\n" +
"\x01o\x18\x01 \x01(\v2\x17.ngolofuzz.OptionStructR\x01o\"\x1e\n" +
"\x1cOPTResourceNgdotGoStringArgs\"\"\n" +
" UnknownResourceNgdotGoStringArgs\"\x1f\n" +
"\x1dSVCBResourceNgdotGoStringArgs\" \n" +
"\x1eHTTPSResourceNgdotGoStringArgs\"M\n" +
"\x1dSVCBResourceNgdotGetParamArgs\x12,\n" +
"\x03key\x18\x01 \x01(\x0e2\x1a.ngolofuzz.SVCParamKeyEnumR\x03key\"c\n" +
"\x1dSVCBResourceNgdotSetParamArgs\x12,\n" +
"\x03key\x18\x01 \x01(\x0e2\x1a.ngolofuzz.SVCParamKeyEnumR\x03key\x12\x14\n" +
"\x05value\x18\x02 \x01(\fR\x05value\"P\n" +
" SVCBResourceNgdotDeleteParamArgs\x12,\n" +
"\x03key\x18\x01 \x01(\x0e2\x1a.ngolofuzz.SVCParamKeyEnumR\x03key\"D\n" +
"\x19SVCParamNgdotGoStringArgs\x12'\n" +
"\x01p\x18\x01 \x01(\v2\x19.ngolofuzz.SVCParamStructR\x01p\"F\n" +
"\x1aSVCParamKeyNgdotStringArgs\x12(\n" +
"\x01k\x18\x01 \x01(\x0e2\x1a.ngolofuzz.SVCParamKeyEnumR\x01k\"H\n" +
"\x1cSVCParamKeyNgdotGoStringArgs\x12(\n" +
"\x01k\x18\x01 \x01(\x0e2\x1a.ngolofuzz.SVCParamKeyEnumR\x01k\"\x1e\n" +
"\x1cBuilderNgdotSVCBResourceArgs\"\x1f\n" +
"\x1dBuilderNgdotHTTPSResourceArgs\"\xd5,\n" +
"\fNgoloFuzzOne\x12J\n" +
"\x0fTypeNgdotString\x18\x01 \x01(\v2\x1e.ngolofuzz.TypeNgdotStringArgsH\x00R\x0fTypeNgdotString\x12P\n" +
"\x11TypeNgdotGoString\x18\x02 \x01(\v2 .ngolofuzz.TypeNgdotGoStringArgsH\x00R\x11TypeNgdotGoString\x12M\n" +
"\x10ClassNgdotString\x18\x03 \x01(\v2\x1f.ngolofuzz.ClassNgdotStringArgsH\x00R\x10ClassNgdotString\x12S\n" +
"\x12ClassNgdotGoString\x18\x04 \x01(\v2!.ngolofuzz.ClassNgdotGoStringArgsH\x00R\x12ClassNgdotGoString\x12M\n" +
"\x10RCodeNgdotString\x18\x05 \x01(\v2\x1f.ngolofuzz.RCodeNgdotStringArgsH\x00R\x10RCodeNgdotString\x12S\n" +
"\x12RCodeNgdotGoString\x18\x06 \x01(\v2!.ngolofuzz.RCodeNgdotGoStringArgsH\x00R\x12RCodeNgdotGoString\x12V\n" +
"\x13HeaderNgdotGoString\x18\a \x01(\v2\".ngolofuzz.HeaderNgdotGoStringArgsH\x00R\x13HeaderNgdotGoString\x12\\\n" +
"\x15ResourceNgdotGoString\x18\b \x01(\v2$.ngolofuzz.ResourceNgdotGoStringArgsH\x00R\x15ResourceNgdotGoString\x12;\n" +
"\n" +
"NewBuilder\x18\t \x01(\v2\x19.ngolofuzz.NewBuilderArgsH\x00R\n" +
"NewBuilder\x12t\n" +
"\x1dBuilderNgdotEnableCompression\x18\n" +
" \x01(\v2,.ngolofuzz.BuilderNgdotEnableCompressionArgsH\x00R\x1dBuilderNgdotEnableCompression\x12k\n" +
"\x1aBuilderNgdotStartQuestions\x18\v \x01(\v2).ngolofuzz.BuilderNgdotStartQuestionsArgsH\x00R\x1aBuilderNgdotStartQuestions\x12e\n" +
"\x18BuilderNgdotStartAnswers\x18\f \x01(\v2'.ngolofuzz.BuilderNgdotStartAnswersArgsH\x00R\x18BuilderNgdotStartAnswers\x12q\n" +
"\x1cBuilderNgdotStartAuthorities\x18\r \x01(\v2+.ngolofuzz.BuilderNgdotStartAuthoritiesArgsH\x00R\x1cBuilderNgdotStartAuthorities\x12q\n" +
"\x1cBuilderNgdotStartAdditionals\x18\x0e \x01(\v2+.ngolofuzz.BuilderNgdotStartAdditionalsArgsH\x00R\x1cBuilderNgdotStartAdditionals\x12Y\n" +
"\x14BuilderNgdotQuestion\x18\x0f \x01(\v2#.ngolofuzz.BuilderNgdotQuestionArgsH\x00R\x14BuilderNgdotQuestion\x12h\n" +
"\x19BuilderNgdotCNAMEResource\x18\x10 \x01(\v2(.ngolofuzz.BuilderNgdotCNAMEResourceArgsH\x00R\x19BuilderNgdotCNAMEResource\x12_\n" +
"\x16BuilderNgdotMXResource\x18\x11 \x01(\v2%.ngolofuzz.BuilderNgdotMXResourceArgsH\x00R\x16BuilderNgdotMXResource\x12_\n" +
"\x16BuilderNgdotNSResource\x18\x12 \x01(\v2%.ngolofuzz.BuilderNgdotNSResourceArgsH\x00R\x16BuilderNgdotNSResource\x12b\n" +
"\x17BuilderNgdotPTRResource\x18\x13 \x01(\v2&.ngolofuzz.BuilderNgdotPTRResourceArgsH\x00R\x17BuilderNgdotPTRResource\x12b\n" +
"\x17BuilderNgdotSOAResource\x18\x14 \x01(\v2&.ngolofuzz.BuilderNgdotSOAResourceArgsH\x00R\x17BuilderNgdotSOAResource\x12b\n" +
"\x17BuilderNgdotTXTResource\x18\x15 \x01(\v2&.ngolofuzz.BuilderNgdotTXTResourceArgsH\x00R\x17BuilderNgdotTXTResource\x12b\n" +
"\x17BuilderNgdotSRVResource\x18\x16 \x01(\v2&.ngolofuzz.BuilderNgdotSRVResourceArgsH\x00R\x17BuilderNgdotSRVResource\x12\\\n" +
"\x15BuilderNgdotAResource\x18\x17 \x01(\v2$.ngolofuzz.BuilderNgdotAResourceArgsH\x00R\x15BuilderNgdotAResource\x12e\n" +
"\x18BuilderNgdotAAAAResource\x18\x18 \x01(\v2'.ngolofuzz.BuilderNgdotAAAAResourceArgsH\x00R\x18BuilderNgdotAAAAResource\x12b\n" +
"\x17BuilderNgdotOPTResource\x18\x19 \x01(\v2&.ngolofuzz.BuilderNgdotOPTResourceArgsH\x00R\x17BuilderNgdotOPTResource\x12n\n" +
"\x1bBuilderNgdotUnknownResource\x18\x1a \x01(\v2*.ngolofuzz.BuilderNgdotUnknownResourceArgsH\x00R\x1bBuilderNgdotUnknownResource\x12S\n" +
"\x12BuilderNgdotFinish\x18\x1b \x01(\v2!.ngolofuzz.BuilderNgdotFinishArgsH\x00R\x12BuilderNgdotFinish\x12n\n" +
"\x1bResourceHeaderNgdotGoString\x18\x1c \x01(\v2*.ngolofuzz.ResourceHeaderNgdotGoStringArgsH\x00R\x1bResourceHeaderNgdotGoString\x12n\n" +
"\x1bResourceHeaderNgdotSetEDNS0\x18\x1d \x01(\v2*.ngolofuzz.ResourceHeaderNgdotSetEDNS0ArgsH\x00R\x1bResourceHeaderNgdotSetEDNS0\x12}\n" +
" ResourceHeaderNgdotDNSSECAllowed\x18\x1e \x01(\v2/.ngolofuzz.ResourceHeaderNgdotDNSSECAllowedArgsH\x00R ResourceHeaderNgdotDNSSECAllowed\x12}\n" +
" ResourceHeaderNgdotExtendedRCode\x18\x1f \x01(\v2/.ngolofuzz.ResourceHeaderNgdotExtendedRCodeArgsH\x00R ResourceHeaderNgdotExtendedRCode\x122\n" +
"\aNewName\x18 \x01(\v2\x16.ngolofuzz.NewNameArgsH\x00R\aNewName\x12>\n" +
"\vMustNewName\x18! \x01(\v2\x1a.ngolofuzz.MustNewNameArgsH\x00R\vMustNewName\x12J\n" +
"\x0fNameNgdotString\x18\" \x01(\v2\x1e.ngolofuzz.NameNgdotStringArgsH\x00R\x0fNameNgdotString\x12P\n" +
"\x11NameNgdotGoString\x18# \x01(\v2 .ngolofuzz.NameNgdotGoStringArgsH\x00R\x11NameNgdotGoString\x12\\\n" +
"\x15QuestionNgdotGoString\x18$ \x01(\v2$.ngolofuzz.QuestionNgdotGoStringArgsH\x00R\x15QuestionNgdotGoString\x12k\n" +
"\x1aCNAMEResourceNgdotGoString\x18% \x01(\v2).ngolofuzz.CNAMEResourceNgdotGoStringArgsH\x00R\x1aCNAMEResourceNgdotGoString\x12b\n" +
"\x17MXResourceNgdotGoString\x18& \x01(\v2&.ngolofuzz.MXResourceNgdotGoStringArgsH\x00R\x17MXResourceNgdotGoString\x12b\n" +
"\x17NSResourceNgdotGoString\x18' \x01(\v2&.ngolofuzz.NSResourceNgdotGoStringArgsH\x00R\x17NSResourceNgdotGoString\x12e\n" +
"\x18PTRResourceNgdotGoString\x18( \x01(\v2'.ngolofuzz.PTRResourceNgdotGoStringArgsH\x00R\x18PTRResourceNgdotGoString\x12e\n" +
"\x18SOAResourceNgdotGoString\x18) \x01(\v2'.ngolofuzz.SOAResourceNgdotGoStringArgsH\x00R\x18SOAResourceNgdotGoString\x12e\n" +
"\x18TXTResourceNgdotGoString\x18* \x01(\v2'.ngolofuzz.TXTResourceNgdotGoStringArgsH\x00R\x18TXTResourceNgdotGoString\x12e\n" +
"\x18SRVResourceNgdotGoString\x18+ \x01(\v2'.ngolofuzz.SRVResourceNgdotGoStringArgsH\x00R\x18SRVResourceNgdotGoString\x12_\n" +
"\x16AResourceNgdotGoString\x18, \x01(\v2%.ngolofuzz.AResourceNgdotGoStringArgsH\x00R\x16AResourceNgdotGoString\x12h\n" +
"\x19AAAAResourceNgdotGoString\x18- \x01(\v2(.ngolofuzz.AAAAResourceNgdotGoStringArgsH\x00R\x19AAAAResourceNgdotGoString\x12V\n" +
"\x13OptionNgdotGoString\x18. \x01(\v2\".ngolofuzz.OptionNgdotGoStringArgsH\x00R\x13OptionNgdotGoString\x12e\n" +
"\x18OPTResourceNgdotGoString\x18/ \x01(\v2'.ngolofuzz.OPTResourceNgdotGoStringArgsH\x00R\x18OPTResourceNgdotGoString\x12q\n" +
"\x1cUnknownResourceNgdotGoString\x180 \x01(\v2+.ngolofuzz.UnknownResourceNgdotGoStringArgsH\x00R\x1cUnknownResourceNgdotGoString\x12h\n" +
"\x19SVCBResourceNgdotGoString\x181 \x01(\v2(.ngolofuzz.SVCBResourceNgdotGoStringArgsH\x00R\x19SVCBResourceNgdotGoString\x12k\n" +
"\x1aHTTPSResourceNgdotGoString\x182 \x01(\v2).ngolofuzz.HTTPSResourceNgdotGoStringArgsH\x00R\x1aHTTPSResourceNgdotGoString\x12h\n" +
"\x19SVCBResourceNgdotGetParam\x183 \x01(\v2(.ngolofuzz.SVCBResourceNgdotGetParamArgsH\x00R\x19SVCBResourceNgdotGetParam\x12h\n" +
"\x19SVCBResourceNgdotSetParam\x184 \x01(\v2(.ngolofuzz.SVCBResourceNgdotSetParamArgsH\x00R\x19SVCBResourceNgdotSetParam\x12q\n" +
"\x1cSVCBResourceNgdotDeleteParam\x185 \x01(\v2+.ngolofuzz.SVCBResourceNgdotDeleteParamArgsH\x00R\x1cSVCBResourceNgdotDeleteParam\x12\\\n" +
"\x15SVCParamNgdotGoString\x186 \x01(\v2$.ngolofuzz.SVCParamNgdotGoStringArgsH\x00R\x15SVCParamNgdotGoString\x12_\n" +
"\x16SVCParamKeyNgdotString\x187 \x01(\v2%.ngolofuzz.SVCParamKeyNgdotStringArgsH\x00R\x16SVCParamKeyNgdotString\x12e\n" +
"\x18SVCParamKeyNgdotGoString\x188 \x01(\v2'.ngolofuzz.SVCParamKeyNgdotGoStringArgsH\x00R\x18SVCParamKeyNgdotGoString\x12e\n" +
"\x18BuilderNgdotSVCBResource\x189 \x01(\v2'.ngolofuzz.BuilderNgdotSVCBResourceArgsH\x00R\x18BuilderNgdotSVCBResource\x12h\n" +
"\x19BuilderNgdotHTTPSResource\x18: \x01(\v2(.ngolofuzz.BuilderNgdotHTTPSResourceArgsH\x00R\x19BuilderNgdotHTTPSResourceB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04list*\xec\x01\n" +
"\x0fSVCParamKeyEnum\x12\x15\n" +
"\x11SVCParamMandatory\x10\x00\x12\x10\n" +
"\fSVCParamALPN\x10\x01\x12\x19\n" +
"\x15SVCParamNoDefaultALPN\x10\x02\x12\x10\n" +
"\fSVCParamPort\x10\x03\x12\x14\n" +
"\x10SVCParamIPv4Hint\x10\x04\x12\x0f\n" +
"\vSVCParamECH\x10\x05\x12\x14\n" +
"\x10SVCParamIPv6Hint\x10\x06\x12\x13\n" +
"\x0fSVCParamDOHPath\x10\a\x12\x11\n" +
"\rSVCParamOHTTP\x10\b\x12\x1e\n" +
"\x1aSVCParamTLSSupportedGroups\x10\t*Y\n" +
"\tClassEnum\x12\r\n" +
"\tClassINET\x10\x00\x12\x0e\n" +
"\n" +
"ClassCSNET\x10\x01\x12\x0e\n" +
"\n" +
"ClassCHAOS\x10\x02\x12\x0f\n" +
"\vClassHESIOD\x10\x03\x12\f\n" +
"\bClassANY\x10\x04*\xee\x01\n" +
"\bTypeEnum\x12\t\n" +
"\x05TypeA\x10\x00\x12\n" +
"\n" +
"\x06TypeNS\x10\x01\x12\r\n" +
"\tTypeCNAME\x10\x02\x12\v\n" +
"\aTypeSOA\x10\x03\x12\v\n" +
"\aTypePTR\x10\x04\x12\n" +
"\n" +
"\x06TypeMX\x10\x05\x12\v\n" +
"\aTypeTXT\x10\x06\x12\f\n" +
"\bTypeAAAA\x10\a\x12\v\n" +
"\aTypeSRV\x10\b\x12\v\n" +
"\aTypeOPT\x10\t\x12\f\n" +
"\bTypeSVCB\x10\n" +
"\x12\r\n" +
"\tTypeHTTPS\x10\v\x12\v\n" +
"\aTypeWKS\x10\f\x12\r\n" +
"\tTypeHINFO\x10\r\x12\r\n" +
"\tTypeMINFO\x10\x0e\x12\f\n" +
"\bTypeAXFR\x10\x0f\x12\v\n" +
"\aTypeALL\x10\x10B!Z\x1f./;fuzz_ng_x_net_dns_dnsmessageb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 63)
var file_ngolofuzz_proto_goTypes = []any{
(SVCParamKeyEnum)(0), // 0: ngolofuzz.SVCParamKeyEnum
(ClassEnum)(0), // 1: ngolofuzz.ClassEnum
(TypeEnum)(0), // 2: ngolofuzz.TypeEnum
(*SVCParamStruct)(nil), // 3: ngolofuzz.SVCParamStruct
(*OptionStruct)(nil), // 4: ngolofuzz.OptionStruct
(*TypeNgdotStringArgs)(nil), // 5: ngolofuzz.TypeNgdotStringArgs
(*TypeNgdotGoStringArgs)(nil), // 6: ngolofuzz.TypeNgdotGoStringArgs
(*ClassNgdotStringArgs)(nil), // 7: ngolofuzz.ClassNgdotStringArgs
(*ClassNgdotGoStringArgs)(nil), // 8: ngolofuzz.ClassNgdotGoStringArgs
(*RCodeNgdotStringArgs)(nil), // 9: ngolofuzz.RCodeNgdotStringArgs
(*RCodeNgdotGoStringArgs)(nil), // 10: ngolofuzz.RCodeNgdotGoStringArgs
(*HeaderNgdotGoStringArgs)(nil), // 11: ngolofuzz.HeaderNgdotGoStringArgs
(*ResourceNgdotGoStringArgs)(nil), // 12: ngolofuzz.ResourceNgdotGoStringArgs
(*NewBuilderArgs)(nil), // 13: ngolofuzz.NewBuilderArgs
(*BuilderNgdotEnableCompressionArgs)(nil), // 14: ngolofuzz.BuilderNgdotEnableCompressionArgs
(*BuilderNgdotStartQuestionsArgs)(nil), // 15: ngolofuzz.BuilderNgdotStartQuestionsArgs
(*BuilderNgdotStartAnswersArgs)(nil), // 16: ngolofuzz.BuilderNgdotStartAnswersArgs
(*BuilderNgdotStartAuthoritiesArgs)(nil), // 17: ngolofuzz.BuilderNgdotStartAuthoritiesArgs
(*BuilderNgdotStartAdditionalsArgs)(nil), // 18: ngolofuzz.BuilderNgdotStartAdditionalsArgs
(*BuilderNgdotQuestionArgs)(nil), // 19: ngolofuzz.BuilderNgdotQuestionArgs
(*BuilderNgdotCNAMEResourceArgs)(nil), // 20: ngolofuzz.BuilderNgdotCNAMEResourceArgs
(*BuilderNgdotMXResourceArgs)(nil), // 21: ngolofuzz.BuilderNgdotMXResourceArgs
(*BuilderNgdotNSResourceArgs)(nil), // 22: ngolofuzz.BuilderNgdotNSResourceArgs
(*BuilderNgdotPTRResourceArgs)(nil), // 23: ngolofuzz.BuilderNgdotPTRResourceArgs
(*BuilderNgdotSOAResourceArgs)(nil), // 24: ngolofuzz.BuilderNgdotSOAResourceArgs
(*BuilderNgdotTXTResourceArgs)(nil), // 25: ngolofuzz.BuilderNgdotTXTResourceArgs
(*BuilderNgdotSRVResourceArgs)(nil), // 26: ngolofuzz.BuilderNgdotSRVResourceArgs
(*BuilderNgdotAResourceArgs)(nil), // 27: ngolofuzz.BuilderNgdotAResourceArgs
(*BuilderNgdotAAAAResourceArgs)(nil), // 28: ngolofuzz.BuilderNgdotAAAAResourceArgs
(*BuilderNgdotOPTResourceArgs)(nil), // 29: ngolofuzz.BuilderNgdotOPTResourceArgs
(*BuilderNgdotUnknownResourceArgs)(nil), // 30: ngolofuzz.BuilderNgdotUnknownResourceArgs
(*BuilderNgdotFinishArgs)(nil), // 31: ngolofuzz.BuilderNgdotFinishArgs
(*ResourceHeaderNgdotGoStringArgs)(nil), // 32: ngolofuzz.ResourceHeaderNgdotGoStringArgs
(*ResourceHeaderNgdotSetEDNS0Args)(nil), // 33: ngolofuzz.ResourceHeaderNgdotSetEDNS0Args
(*ResourceHeaderNgdotDNSSECAllowedArgs)(nil), // 34: ngolofuzz.ResourceHeaderNgdotDNSSECAllowedArgs
(*ResourceHeaderNgdotExtendedRCodeArgs)(nil), // 35: ngolofuzz.ResourceHeaderNgdotExtendedRCodeArgs
(*NewNameArgs)(nil), // 36: ngolofuzz.NewNameArgs
(*MustNewNameArgs)(nil), // 37: ngolofuzz.MustNewNameArgs
(*NameNgdotStringArgs)(nil), // 38: ngolofuzz.NameNgdotStringArgs
(*NameNgdotGoStringArgs)(nil), // 39: ngolofuzz.NameNgdotGoStringArgs
(*QuestionNgdotGoStringArgs)(nil), // 40: ngolofuzz.QuestionNgdotGoStringArgs
(*CNAMEResourceNgdotGoStringArgs)(nil), // 41: ngolofuzz.CNAMEResourceNgdotGoStringArgs
(*MXResourceNgdotGoStringArgs)(nil), // 42: ngolofuzz.MXResourceNgdotGoStringArgs
(*NSResourceNgdotGoStringArgs)(nil), // 43: ngolofuzz.NSResourceNgdotGoStringArgs
(*PTRResourceNgdotGoStringArgs)(nil), // 44: ngolofuzz.PTRResourceNgdotGoStringArgs
(*SOAResourceNgdotGoStringArgs)(nil), // 45: ngolofuzz.SOAResourceNgdotGoStringArgs
(*TXTResourceNgdotGoStringArgs)(nil), // 46: ngolofuzz.TXTResourceNgdotGoStringArgs
(*SRVResourceNgdotGoStringArgs)(nil), // 47: ngolofuzz.SRVResourceNgdotGoStringArgs
(*AResourceNgdotGoStringArgs)(nil), // 48: ngolofuzz.AResourceNgdotGoStringArgs
(*AAAAResourceNgdotGoStringArgs)(nil), // 49: ngolofuzz.AAAAResourceNgdotGoStringArgs
(*OptionNgdotGoStringArgs)(nil), // 50: ngolofuzz.OptionNgdotGoStringArgs
(*OPTResourceNgdotGoStringArgs)(nil), // 51: ngolofuzz.OPTResourceNgdotGoStringArgs
(*UnknownResourceNgdotGoStringArgs)(nil), // 52: ngolofuzz.UnknownResourceNgdotGoStringArgs
(*SVCBResourceNgdotGoStringArgs)(nil), // 53: ngolofuzz.SVCBResourceNgdotGoStringArgs
(*HTTPSResourceNgdotGoStringArgs)(nil), // 54: ngolofuzz.HTTPSResourceNgdotGoStringArgs
(*SVCBResourceNgdotGetParamArgs)(nil), // 55: ngolofuzz.SVCBResourceNgdotGetParamArgs
(*SVCBResourceNgdotSetParamArgs)(nil), // 56: ngolofuzz.SVCBResourceNgdotSetParamArgs
(*SVCBResourceNgdotDeleteParamArgs)(nil), // 57: ngolofuzz.SVCBResourceNgdotDeleteParamArgs
(*SVCParamNgdotGoStringArgs)(nil), // 58: ngolofuzz.SVCParamNgdotGoStringArgs
(*SVCParamKeyNgdotStringArgs)(nil), // 59: ngolofuzz.SVCParamKeyNgdotStringArgs
(*SVCParamKeyNgdotGoStringArgs)(nil), // 60: ngolofuzz.SVCParamKeyNgdotGoStringArgs
(*BuilderNgdotSVCBResourceArgs)(nil), // 61: ngolofuzz.BuilderNgdotSVCBResourceArgs
(*BuilderNgdotHTTPSResourceArgs)(nil), // 62: ngolofuzz.BuilderNgdotHTTPSResourceArgs
(*NgoloFuzzOne)(nil), // 63: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 64: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 65: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.SVCParamStruct.Key:type_name -> ngolofuzz.SVCParamKeyEnum
2, // 1: ngolofuzz.TypeNgdotStringArgs.t:type_name -> ngolofuzz.TypeEnum
2, // 2: ngolofuzz.TypeNgdotGoStringArgs.t:type_name -> ngolofuzz.TypeEnum
1, // 3: ngolofuzz.ClassNgdotStringArgs.c:type_name -> ngolofuzz.ClassEnum
1, // 4: ngolofuzz.ClassNgdotGoStringArgs.c:type_name -> ngolofuzz.ClassEnum
4, // 5: ngolofuzz.OptionNgdotGoStringArgs.o:type_name -> ngolofuzz.OptionStruct
0, // 6: ngolofuzz.SVCBResourceNgdotGetParamArgs.key:type_name -> ngolofuzz.SVCParamKeyEnum
0, // 7: ngolofuzz.SVCBResourceNgdotSetParamArgs.key:type_name -> ngolofuzz.SVCParamKeyEnum
0, // 8: ngolofuzz.SVCBResourceNgdotDeleteParamArgs.key:type_name -> ngolofuzz.SVCParamKeyEnum
3, // 9: ngolofuzz.SVCParamNgdotGoStringArgs.p:type_name -> ngolofuzz.SVCParamStruct
0, // 10: ngolofuzz.SVCParamKeyNgdotStringArgs.k:type_name -> ngolofuzz.SVCParamKeyEnum
0, // 11: ngolofuzz.SVCParamKeyNgdotGoStringArgs.k:type_name -> ngolofuzz.SVCParamKeyEnum
5, // 12: ngolofuzz.NgoloFuzzOne.TypeNgdotString:type_name -> ngolofuzz.TypeNgdotStringArgs
6, // 13: ngolofuzz.NgoloFuzzOne.TypeNgdotGoString:type_name -> ngolofuzz.TypeNgdotGoStringArgs
7, // 14: ngolofuzz.NgoloFuzzOne.ClassNgdotString:type_name -> ngolofuzz.ClassNgdotStringArgs
8, // 15: ngolofuzz.NgoloFuzzOne.ClassNgdotGoString:type_name -> ngolofuzz.ClassNgdotGoStringArgs
9, // 16: ngolofuzz.NgoloFuzzOne.RCodeNgdotString:type_name -> ngolofuzz.RCodeNgdotStringArgs
10, // 17: ngolofuzz.NgoloFuzzOne.RCodeNgdotGoString:type_name -> ngolofuzz.RCodeNgdotGoStringArgs
11, // 18: ngolofuzz.NgoloFuzzOne.HeaderNgdotGoString:type_name -> ngolofuzz.HeaderNgdotGoStringArgs
12, // 19: ngolofuzz.NgoloFuzzOne.ResourceNgdotGoString:type_name -> ngolofuzz.ResourceNgdotGoStringArgs
13, // 20: ngolofuzz.NgoloFuzzOne.NewBuilder:type_name -> ngolofuzz.NewBuilderArgs
14, // 21: ngolofuzz.NgoloFuzzOne.BuilderNgdotEnableCompression:type_name -> ngolofuzz.BuilderNgdotEnableCompressionArgs
15, // 22: ngolofuzz.NgoloFuzzOne.BuilderNgdotStartQuestions:type_name -> ngolofuzz.BuilderNgdotStartQuestionsArgs
16, // 23: ngolofuzz.NgoloFuzzOne.BuilderNgdotStartAnswers:type_name -> ngolofuzz.BuilderNgdotStartAnswersArgs
17, // 24: ngolofuzz.NgoloFuzzOne.BuilderNgdotStartAuthorities:type_name -> ngolofuzz.BuilderNgdotStartAuthoritiesArgs
18, // 25: ngolofuzz.NgoloFuzzOne.BuilderNgdotStartAdditionals:type_name -> ngolofuzz.BuilderNgdotStartAdditionalsArgs
19, // 26: ngolofuzz.NgoloFuzzOne.BuilderNgdotQuestion:type_name -> ngolofuzz.BuilderNgdotQuestionArgs
20, // 27: ngolofuzz.NgoloFuzzOne.BuilderNgdotCNAMEResource:type_name -> ngolofuzz.BuilderNgdotCNAMEResourceArgs
21, // 28: ngolofuzz.NgoloFuzzOne.BuilderNgdotMXResource:type_name -> ngolofuzz.BuilderNgdotMXResourceArgs
22, // 29: ngolofuzz.NgoloFuzzOne.BuilderNgdotNSResource:type_name -> ngolofuzz.BuilderNgdotNSResourceArgs
23, // 30: ngolofuzz.NgoloFuzzOne.BuilderNgdotPTRResource:type_name -> ngolofuzz.BuilderNgdotPTRResourceArgs
24, // 31: ngolofuzz.NgoloFuzzOne.BuilderNgdotSOAResource:type_name -> ngolofuzz.BuilderNgdotSOAResourceArgs
25, // 32: ngolofuzz.NgoloFuzzOne.BuilderNgdotTXTResource:type_name -> ngolofuzz.BuilderNgdotTXTResourceArgs
26, // 33: ngolofuzz.NgoloFuzzOne.BuilderNgdotSRVResource:type_name -> ngolofuzz.BuilderNgdotSRVResourceArgs
27, // 34: ngolofuzz.NgoloFuzzOne.BuilderNgdotAResource:type_name -> ngolofuzz.BuilderNgdotAResourceArgs
28, // 35: ngolofuzz.NgoloFuzzOne.BuilderNgdotAAAAResource:type_name -> ngolofuzz.BuilderNgdotAAAAResourceArgs
29, // 36: ngolofuzz.NgoloFuzzOne.BuilderNgdotOPTResource:type_name -> ngolofuzz.BuilderNgdotOPTResourceArgs
30, // 37: ngolofuzz.NgoloFuzzOne.BuilderNgdotUnknownResource:type_name -> ngolofuzz.BuilderNgdotUnknownResourceArgs
31, // 38: ngolofuzz.NgoloFuzzOne.BuilderNgdotFinish:type_name -> ngolofuzz.BuilderNgdotFinishArgs
32, // 39: ngolofuzz.NgoloFuzzOne.ResourceHeaderNgdotGoString:type_name -> ngolofuzz.ResourceHeaderNgdotGoStringArgs
33, // 40: ngolofuzz.NgoloFuzzOne.ResourceHeaderNgdotSetEDNS0:type_name -> ngolofuzz.ResourceHeaderNgdotSetEDNS0Args
34, // 41: ngolofuzz.NgoloFuzzOne.ResourceHeaderNgdotDNSSECAllowed:type_name -> ngolofuzz.ResourceHeaderNgdotDNSSECAllowedArgs
35, // 42: ngolofuzz.NgoloFuzzOne.ResourceHeaderNgdotExtendedRCode:type_name -> ngolofuzz.ResourceHeaderNgdotExtendedRCodeArgs
36, // 43: ngolofuzz.NgoloFuzzOne.NewName:type_name -> ngolofuzz.NewNameArgs
37, // 44: ngolofuzz.NgoloFuzzOne.MustNewName:type_name -> ngolofuzz.MustNewNameArgs
38, // 45: ngolofuzz.NgoloFuzzOne.NameNgdotString:type_name -> ngolofuzz.NameNgdotStringArgs
39, // 46: ngolofuzz.NgoloFuzzOne.NameNgdotGoString:type_name -> ngolofuzz.NameNgdotGoStringArgs
40, // 47: ngolofuzz.NgoloFuzzOne.QuestionNgdotGoString:type_name -> ngolofuzz.QuestionNgdotGoStringArgs
41, // 48: ngolofuzz.NgoloFuzzOne.CNAMEResourceNgdotGoString:type_name -> ngolofuzz.CNAMEResourceNgdotGoStringArgs
42, // 49: ngolofuzz.NgoloFuzzOne.MXResourceNgdotGoString:type_name -> ngolofuzz.MXResourceNgdotGoStringArgs
43, // 50: ngolofuzz.NgoloFuzzOne.NSResourceNgdotGoString:type_name -> ngolofuzz.NSResourceNgdotGoStringArgs
44, // 51: ngolofuzz.NgoloFuzzOne.PTRResourceNgdotGoString:type_name -> ngolofuzz.PTRResourceNgdotGoStringArgs
45, // 52: ngolofuzz.NgoloFuzzOne.SOAResourceNgdotGoString:type_name -> ngolofuzz.SOAResourceNgdotGoStringArgs
46, // 53: ngolofuzz.NgoloFuzzOne.TXTResourceNgdotGoString:type_name -> ngolofuzz.TXTResourceNgdotGoStringArgs
47, // 54: ngolofuzz.NgoloFuzzOne.SRVResourceNgdotGoString:type_name -> ngolofuzz.SRVResourceNgdotGoStringArgs
48, // 55: ngolofuzz.NgoloFuzzOne.AResourceNgdotGoString:type_name -> ngolofuzz.AResourceNgdotGoStringArgs
49, // 56: ngolofuzz.NgoloFuzzOne.AAAAResourceNgdotGoString:type_name -> ngolofuzz.AAAAResourceNgdotGoStringArgs
50, // 57: ngolofuzz.NgoloFuzzOne.OptionNgdotGoString:type_name -> ngolofuzz.OptionNgdotGoStringArgs
51, // 58: ngolofuzz.NgoloFuzzOne.OPTResourceNgdotGoString:type_name -> ngolofuzz.OPTResourceNgdotGoStringArgs
52, // 59: ngolofuzz.NgoloFuzzOne.UnknownResourceNgdotGoString:type_name -> ngolofuzz.UnknownResourceNgdotGoStringArgs
53, // 60: ngolofuzz.NgoloFuzzOne.SVCBResourceNgdotGoString:type_name -> ngolofuzz.SVCBResourceNgdotGoStringArgs
54, // 61: ngolofuzz.NgoloFuzzOne.HTTPSResourceNgdotGoString:type_name -> ngolofuzz.HTTPSResourceNgdotGoStringArgs
55, // 62: ngolofuzz.NgoloFuzzOne.SVCBResourceNgdotGetParam:type_name -> ngolofuzz.SVCBResourceNgdotGetParamArgs
56, // 63: ngolofuzz.NgoloFuzzOne.SVCBResourceNgdotSetParam:type_name -> ngolofuzz.SVCBResourceNgdotSetParamArgs
57, // 64: ngolofuzz.NgoloFuzzOne.SVCBResourceNgdotDeleteParam:type_name -> ngolofuzz.SVCBResourceNgdotDeleteParamArgs
58, // 65: ngolofuzz.NgoloFuzzOne.SVCParamNgdotGoString:type_name -> ngolofuzz.SVCParamNgdotGoStringArgs
59, // 66: ngolofuzz.NgoloFuzzOne.SVCParamKeyNgdotString:type_name -> ngolofuzz.SVCParamKeyNgdotStringArgs
60, // 67: ngolofuzz.NgoloFuzzOne.SVCParamKeyNgdotGoString:type_name -> ngolofuzz.SVCParamKeyNgdotGoStringArgs
61, // 68: ngolofuzz.NgoloFuzzOne.BuilderNgdotSVCBResource:type_name -> ngolofuzz.BuilderNgdotSVCBResourceArgs
62, // 69: ngolofuzz.NgoloFuzzOne.BuilderNgdotHTTPSResource:type_name -> ngolofuzz.BuilderNgdotHTTPSResourceArgs
63, // 70: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
71, // [71:71] is the sub-list for method output_type
71, // [71:71] is the sub-list for method input_type
71, // [71:71] is the sub-list for extension type_name
71, // [71:71] is the sub-list for extension extendee
0, // [0:71] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[60].OneofWrappers = []any{
(*NgoloFuzzOne_TypeNgdotString)(nil),
(*NgoloFuzzOne_TypeNgdotGoString)(nil),
(*NgoloFuzzOne_ClassNgdotString)(nil),
(*NgoloFuzzOne_ClassNgdotGoString)(nil),
(*NgoloFuzzOne_RCodeNgdotString)(nil),
(*NgoloFuzzOne_RCodeNgdotGoString)(nil),
(*NgoloFuzzOne_HeaderNgdotGoString)(nil),
(*NgoloFuzzOne_ResourceNgdotGoString)(nil),
(*NgoloFuzzOne_NewBuilder)(nil),
(*NgoloFuzzOne_BuilderNgdotEnableCompression)(nil),
(*NgoloFuzzOne_BuilderNgdotStartQuestions)(nil),
(*NgoloFuzzOne_BuilderNgdotStartAnswers)(nil),
(*NgoloFuzzOne_BuilderNgdotStartAuthorities)(nil),
(*NgoloFuzzOne_BuilderNgdotStartAdditionals)(nil),
(*NgoloFuzzOne_BuilderNgdotQuestion)(nil),
(*NgoloFuzzOne_BuilderNgdotCNAMEResource)(nil),
(*NgoloFuzzOne_BuilderNgdotMXResource)(nil),
(*NgoloFuzzOne_BuilderNgdotNSResource)(nil),
(*NgoloFuzzOne_BuilderNgdotPTRResource)(nil),
(*NgoloFuzzOne_BuilderNgdotSOAResource)(nil),
(*NgoloFuzzOne_BuilderNgdotTXTResource)(nil),
(*NgoloFuzzOne_BuilderNgdotSRVResource)(nil),
(*NgoloFuzzOne_BuilderNgdotAResource)(nil),
(*NgoloFuzzOne_BuilderNgdotAAAAResource)(nil),
(*NgoloFuzzOne_BuilderNgdotOPTResource)(nil),
(*NgoloFuzzOne_BuilderNgdotUnknownResource)(nil),
(*NgoloFuzzOne_BuilderNgdotFinish)(nil),
(*NgoloFuzzOne_ResourceHeaderNgdotGoString)(nil),
(*NgoloFuzzOne_ResourceHeaderNgdotSetEDNS0)(nil),
(*NgoloFuzzOne_ResourceHeaderNgdotDNSSECAllowed)(nil),
(*NgoloFuzzOne_ResourceHeaderNgdotExtendedRCode)(nil),
(*NgoloFuzzOne_NewName)(nil),
(*NgoloFuzzOne_MustNewName)(nil),
(*NgoloFuzzOne_NameNgdotString)(nil),
(*NgoloFuzzOne_NameNgdotGoString)(nil),
(*NgoloFuzzOne_QuestionNgdotGoString)(nil),
(*NgoloFuzzOne_CNAMEResourceNgdotGoString)(nil),
(*NgoloFuzzOne_MXResourceNgdotGoString)(nil),
(*NgoloFuzzOne_NSResourceNgdotGoString)(nil),
(*NgoloFuzzOne_PTRResourceNgdotGoString)(nil),
(*NgoloFuzzOne_SOAResourceNgdotGoString)(nil),
(*NgoloFuzzOne_TXTResourceNgdotGoString)(nil),
(*NgoloFuzzOne_SRVResourceNgdotGoString)(nil),
(*NgoloFuzzOne_AResourceNgdotGoString)(nil),
(*NgoloFuzzOne_AAAAResourceNgdotGoString)(nil),
(*NgoloFuzzOne_OptionNgdotGoString)(nil),
(*NgoloFuzzOne_OPTResourceNgdotGoString)(nil),
(*NgoloFuzzOne_UnknownResourceNgdotGoString)(nil),
(*NgoloFuzzOne_SVCBResourceNgdotGoString)(nil),
(*NgoloFuzzOne_HTTPSResourceNgdotGoString)(nil),
(*NgoloFuzzOne_SVCBResourceNgdotGetParam)(nil),
(*NgoloFuzzOne_SVCBResourceNgdotSetParam)(nil),
(*NgoloFuzzOne_SVCBResourceNgdotDeleteParam)(nil),
(*NgoloFuzzOne_SVCParamNgdotGoString)(nil),
(*NgoloFuzzOne_SVCParamKeyNgdotString)(nil),
(*NgoloFuzzOne_SVCParamKeyNgdotGoString)(nil),
(*NgoloFuzzOne_BuilderNgdotSVCBResource)(nil),
(*NgoloFuzzOne_BuilderNgdotHTTPSResource)(nil),
}
file_ngolofuzz_proto_msgTypes[61].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 3,
NumMessages: 63,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
EnumInfos: file_ngolofuzz_proto_enumTypes,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_net_html
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/net/html"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var NodeResults []*html.Node
NodeResultsIndex := 0
var TokenTypeResults []*html.TokenType
TokenTypeResultsIndex := 0
var TokenResults []*html.Token
TokenResultsIndex := 0
var TokenizerResults []*html.Tokenizer
TokenizerResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_EscapeString:
html.EscapeString(a.EscapeString.S)
case *NgoloFuzzOne_UnescapeString:
html.UnescapeString(a.UnescapeString.S)
case *NgoloFuzzOne_NodeNgdotAncestors:
if len(NodeResults) == 0 {
continue
}
arg0 := NodeResults[NodeResultsIndex]
NodeResultsIndex = (NodeResultsIndex + 1) % len(NodeResults)
arg0.Ancestors()
case *NgoloFuzzOne_NodeNgdotChildNodes:
if len(NodeResults) == 0 {
continue
}
arg0 := NodeResults[NodeResultsIndex]
NodeResultsIndex = (NodeResultsIndex + 1) % len(NodeResults)
arg0.ChildNodes()
case *NgoloFuzzOne_NodeNgdotDescendants:
if len(NodeResults) == 0 {
continue
}
arg0 := NodeResults[NodeResultsIndex]
NodeResultsIndex = (NodeResultsIndex + 1) % len(NodeResults)
arg0.Descendants()
case *NgoloFuzzOne_NodeNgdotInsertBefore:
if len(NodeResults) == 0 {
continue
}
arg0 := NodeResults[NodeResultsIndex]
NodeResultsIndex = (NodeResultsIndex + 1) % len(NodeResults)
if len(NodeResults) == 0 {
continue
}
arg1 := NodeResults[NodeResultsIndex]
NodeResultsIndex = (NodeResultsIndex + 1) % len(NodeResults)
if len(NodeResults) == 0 {
continue
}
arg2 := NodeResults[NodeResultsIndex]
NodeResultsIndex = (NodeResultsIndex + 1) % len(NodeResults)
arg0.InsertBefore(arg1, arg2)
case *NgoloFuzzOne_NodeNgdotAppendChild:
if len(NodeResults) == 0 {
continue
}
arg0 := NodeResults[NodeResultsIndex]
NodeResultsIndex = (NodeResultsIndex + 1) % len(NodeResults)
if len(NodeResults) == 0 {
continue
}
arg1 := NodeResults[NodeResultsIndex]
NodeResultsIndex = (NodeResultsIndex + 1) % len(NodeResults)
arg0.AppendChild(arg1)
case *NgoloFuzzOne_NodeNgdotRemoveChild:
if len(NodeResults) == 0 {
continue
}
arg0 := NodeResults[NodeResultsIndex]
NodeResultsIndex = (NodeResultsIndex + 1) % len(NodeResults)
if len(NodeResults) == 0 {
continue
}
arg1 := NodeResults[NodeResultsIndex]
NodeResultsIndex = (NodeResultsIndex + 1) % len(NodeResults)
arg0.RemoveChild(arg1)
case *NgoloFuzzOne_Parse:
arg0 := bytes.NewReader(a.Parse.R)
_, r1 := html.Parse(arg0)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_ParseFragment:
arg0 := bytes.NewReader(a.ParseFragment.R)
if len(NodeResults) == 0 {
continue
}
arg1 := NodeResults[NodeResultsIndex]
NodeResultsIndex = (NodeResultsIndex + 1) % len(NodeResults)
_, r1 := html.ParseFragment(arg0, arg1)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_ParseOptionEnableScripting:
html.ParseOptionEnableScripting(a.ParseOptionEnableScripting.Enable)
case *NgoloFuzzOne_Render:
arg0 := bytes.NewBuffer(a.Render.W)
if len(NodeResults) == 0 {
continue
}
arg1 := NodeResults[NodeResultsIndex]
NodeResultsIndex = (NodeResultsIndex + 1) % len(NodeResults)
r0 := html.Render(arg0, arg1)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_TokenTypeNgdotString:
if len(TokenTypeResults) == 0 {
continue
}
arg0 := TokenTypeResults[TokenTypeResultsIndex]
TokenTypeResultsIndex = (TokenTypeResultsIndex + 1) % len(TokenTypeResults)
arg0.String()
case *NgoloFuzzOne_TokenNgdotString:
if len(TokenResults) == 0 {
continue
}
arg0 := TokenResults[TokenResultsIndex]
TokenResultsIndex = (TokenResultsIndex + 1) % len(TokenResults)
arg0.String()
case *NgoloFuzzOne_TokenizerNgdotAllowCDATA:
if len(TokenizerResults) == 0 {
continue
}
arg0 := TokenizerResults[TokenizerResultsIndex]
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % len(TokenizerResults)
arg0.AllowCDATA(a.TokenizerNgdotAllowCDATA.AllowCDATA)
case *NgoloFuzzOne_TokenizerNgdotNextIsNotRawText:
if len(TokenizerResults) == 0 {
continue
}
arg0 := TokenizerResults[TokenizerResultsIndex]
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % len(TokenizerResults)
arg0.NextIsNotRawText()
case *NgoloFuzzOne_TokenizerNgdotErr:
if len(TokenizerResults) == 0 {
continue
}
arg0 := TokenizerResults[TokenizerResultsIndex]
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % len(TokenizerResults)
r0 := arg0.Err()
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_TokenizerNgdotBuffered:
if len(TokenizerResults) == 0 {
continue
}
arg0 := TokenizerResults[TokenizerResultsIndex]
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % len(TokenizerResults)
arg0.Buffered()
case *NgoloFuzzOne_TokenizerNgdotNext:
if len(TokenizerResults) == 0 {
continue
}
arg0 := TokenizerResults[TokenizerResultsIndex]
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % len(TokenizerResults)
r0 := arg0.Next()
TokenTypeResults = append(TokenTypeResults, &r0)
case *NgoloFuzzOne_TokenizerNgdotRaw:
if len(TokenizerResults) == 0 {
continue
}
arg0 := TokenizerResults[TokenizerResultsIndex]
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % len(TokenizerResults)
arg0.Raw()
case *NgoloFuzzOne_TokenizerNgdotText:
if len(TokenizerResults) == 0 {
continue
}
arg0 := TokenizerResults[TokenizerResultsIndex]
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % len(TokenizerResults)
arg0.Text()
case *NgoloFuzzOne_TokenizerNgdotTagName:
if len(TokenizerResults) == 0 {
continue
}
arg0 := TokenizerResults[TokenizerResultsIndex]
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % len(TokenizerResults)
arg0.TagName()
case *NgoloFuzzOne_TokenizerNgdotTagAttr:
if len(TokenizerResults) == 0 {
continue
}
arg0 := TokenizerResults[TokenizerResultsIndex]
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % len(TokenizerResults)
arg0.TagAttr()
case *NgoloFuzzOne_TokenizerNgdotToken:
if len(TokenizerResults) == 0 {
continue
}
arg0 := TokenizerResults[TokenizerResultsIndex]
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % len(TokenizerResults)
arg0.Token()
case *NgoloFuzzOne_TokenizerNgdotSetMaxBuf:
if len(TokenizerResults) == 0 {
continue
}
arg0 := TokenizerResults[TokenizerResultsIndex]
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % len(TokenizerResults)
arg1 := int(a.TokenizerNgdotSetMaxBuf.N)
arg0.SetMaxBuf(arg1)
case *NgoloFuzzOne_NewTokenizer:
arg0 := bytes.NewReader(a.NewTokenizer.R)
r0 := html.NewTokenizer(arg0)
if r0 != nil{
TokenizerResults = append(TokenizerResults, r0)
}
case *NgoloFuzzOne_NewTokenizerFragment:
arg0 := bytes.NewReader(a.NewTokenizerFragment.R)
r0 := html.NewTokenizerFragment(arg0, a.NewTokenizerFragment.ContextTag)
if r0 != nil{
TokenizerResults = append(TokenizerResults, r0)
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
NodeNb := 0
NodeResultsIndex := 0
TokenTypeNb := 0
TokenTypeResultsIndex := 0
TokenNb := 0
TokenResultsIndex := 0
TokenizerNb := 0
TokenizerResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_EscapeString:
w.WriteString(fmt.Sprintf("html.EscapeString(%#+v)\n", a.EscapeString.S))
case *NgoloFuzzOne_UnescapeString:
w.WriteString(fmt.Sprintf("html.UnescapeString(%#+v)\n", a.UnescapeString.S))
case *NgoloFuzzOne_NodeNgdotAncestors:
if NodeNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Node%d.Ancestors()\n", NodeResultsIndex))
NodeResultsIndex = (NodeResultsIndex + 1) % NodeNb
case *NgoloFuzzOne_NodeNgdotChildNodes:
if NodeNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Node%d.ChildNodes()\n", NodeResultsIndex))
NodeResultsIndex = (NodeResultsIndex + 1) % NodeNb
case *NgoloFuzzOne_NodeNgdotDescendants:
if NodeNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Node%d.Descendants()\n", NodeResultsIndex))
NodeResultsIndex = (NodeResultsIndex + 1) % NodeNb
case *NgoloFuzzOne_NodeNgdotInsertBefore:
if NodeNb == 0 {
continue
}
if NodeNb == 0 {
continue
}
if NodeNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Node%d.InsertBefore(Node%d, Node%d)\n", NodeResultsIndex, (NodeResultsIndex + 1) % NodeNb, (NodeResultsIndex + 2) % NodeNb))
NodeResultsIndex = (NodeResultsIndex + 1) % NodeNb
NodeResultsIndex = (NodeResultsIndex + 1) % NodeNb
NodeResultsIndex = (NodeResultsIndex + 1) % NodeNb
case *NgoloFuzzOne_NodeNgdotAppendChild:
if NodeNb == 0 {
continue
}
if NodeNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Node%d.AppendChild(Node%d)\n", NodeResultsIndex, (NodeResultsIndex + 1) % NodeNb))
NodeResultsIndex = (NodeResultsIndex + 1) % NodeNb
NodeResultsIndex = (NodeResultsIndex + 1) % NodeNb
case *NgoloFuzzOne_NodeNgdotRemoveChild:
if NodeNb == 0 {
continue
}
if NodeNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Node%d.RemoveChild(Node%d)\n", NodeResultsIndex, (NodeResultsIndex + 1) % NodeNb))
NodeResultsIndex = (NodeResultsIndex + 1) % NodeNb
NodeResultsIndex = (NodeResultsIndex + 1) % NodeNb
case *NgoloFuzzOne_Parse:
w.WriteString(fmt.Sprintf("html.Parse(bytes.NewReader(%#+v))\n", a.Parse.R))
case *NgoloFuzzOne_ParseFragment:
if NodeNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("html.ParseFragment(bytes.NewReader(%#+v), Node%d)\n", a.ParseFragment.R, (NodeResultsIndex + 0) % NodeNb))
NodeResultsIndex = (NodeResultsIndex + 1) % NodeNb
case *NgoloFuzzOne_ParseOptionEnableScripting:
w.WriteString(fmt.Sprintf("html.ParseOptionEnableScripting(%#+v)\n", a.ParseOptionEnableScripting.Enable))
case *NgoloFuzzOne_Render:
if NodeNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("html.Render(bytes.NewBuffer(%#+v), Node%d)\n", a.Render.W, (NodeResultsIndex + 0) % NodeNb))
NodeResultsIndex = (NodeResultsIndex + 1) % NodeNb
case *NgoloFuzzOne_TokenTypeNgdotString:
if TokenTypeNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("TokenType%d.String()\n", TokenTypeResultsIndex))
TokenTypeResultsIndex = (TokenTypeResultsIndex + 1) % TokenTypeNb
case *NgoloFuzzOne_TokenNgdotString:
if TokenNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Token%d.String()\n", TokenResultsIndex))
TokenResultsIndex = (TokenResultsIndex + 1) % TokenNb
case *NgoloFuzzOne_TokenizerNgdotAllowCDATA:
if TokenizerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Tokenizer%d.AllowCDATA(%#+v)\n", TokenizerResultsIndex, a.TokenizerNgdotAllowCDATA.AllowCDATA))
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % TokenizerNb
case *NgoloFuzzOne_TokenizerNgdotNextIsNotRawText:
if TokenizerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Tokenizer%d.NextIsNotRawText()\n", TokenizerResultsIndex))
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % TokenizerNb
case *NgoloFuzzOne_TokenizerNgdotErr:
if TokenizerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Tokenizer%d.Err()\n", TokenizerResultsIndex))
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % TokenizerNb
case *NgoloFuzzOne_TokenizerNgdotBuffered:
if TokenizerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Tokenizer%d.Buffered()\n", TokenizerResultsIndex))
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % TokenizerNb
case *NgoloFuzzOne_TokenizerNgdotNext:
if TokenizerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("TokenType%d := Tokenizer%d.Next()\n", TokenTypeNb, TokenizerResultsIndex))
TokenTypeNb = TokenTypeNb + 1
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % TokenizerNb
case *NgoloFuzzOne_TokenizerNgdotRaw:
if TokenizerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Tokenizer%d.Raw()\n", TokenizerResultsIndex))
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % TokenizerNb
case *NgoloFuzzOne_TokenizerNgdotText:
if TokenizerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Tokenizer%d.Text()\n", TokenizerResultsIndex))
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % TokenizerNb
case *NgoloFuzzOne_TokenizerNgdotTagName:
if TokenizerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Tokenizer%d.TagName()\n", TokenizerResultsIndex))
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % TokenizerNb
case *NgoloFuzzOne_TokenizerNgdotTagAttr:
if TokenizerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Tokenizer%d.TagAttr()\n", TokenizerResultsIndex))
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % TokenizerNb
case *NgoloFuzzOne_TokenizerNgdotToken:
if TokenizerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Tokenizer%d.Token()\n", TokenizerResultsIndex))
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % TokenizerNb
case *NgoloFuzzOne_TokenizerNgdotSetMaxBuf:
if TokenizerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Tokenizer%d.SetMaxBuf(int(%#+v))\n", TokenizerResultsIndex, a.TokenizerNgdotSetMaxBuf.N))
TokenizerResultsIndex = (TokenizerResultsIndex + 1) % TokenizerNb
case *NgoloFuzzOne_NewTokenizer:
w.WriteString(fmt.Sprintf("Tokenizer%d := html.NewTokenizer(bytes.NewReader(%#+v))\n", TokenizerNb, a.NewTokenizer.R))
TokenizerNb = TokenizerNb + 1
case *NgoloFuzzOne_NewTokenizerFragment:
w.WriteString(fmt.Sprintf("Tokenizer%d := html.NewTokenizerFragment(bytes.NewReader(%#+v), %#+v)\n", TokenizerNb, a.NewTokenizerFragment.R, a.NewTokenizerFragment.ContextTag))
TokenizerNb = TokenizerNb + 1
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_net_html
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type EscapeStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S string `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *EscapeStringArgs) Reset() {
*x = EscapeStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *EscapeStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EscapeStringArgs) ProtoMessage() {}
func (x *EscapeStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EscapeStringArgs.ProtoReflect.Descriptor instead.
func (*EscapeStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *EscapeStringArgs) GetS() string {
if x != nil {
return x.S
}
return ""
}
type UnescapeStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S string `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *UnescapeStringArgs) Reset() {
*x = UnescapeStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *UnescapeStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*UnescapeStringArgs) ProtoMessage() {}
func (x *UnescapeStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use UnescapeStringArgs.ProtoReflect.Descriptor instead.
func (*UnescapeStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *UnescapeStringArgs) GetS() string {
if x != nil {
return x.S
}
return ""
}
type NodeNgdotAncestorsArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NodeNgdotAncestorsArgs) Reset() {
*x = NodeNgdotAncestorsArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NodeNgdotAncestorsArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NodeNgdotAncestorsArgs) ProtoMessage() {}
func (x *NodeNgdotAncestorsArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NodeNgdotAncestorsArgs.ProtoReflect.Descriptor instead.
func (*NodeNgdotAncestorsArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
type NodeNgdotChildNodesArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NodeNgdotChildNodesArgs) Reset() {
*x = NodeNgdotChildNodesArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NodeNgdotChildNodesArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NodeNgdotChildNodesArgs) ProtoMessage() {}
func (x *NodeNgdotChildNodesArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NodeNgdotChildNodesArgs.ProtoReflect.Descriptor instead.
func (*NodeNgdotChildNodesArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
type NodeNgdotDescendantsArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NodeNgdotDescendantsArgs) Reset() {
*x = NodeNgdotDescendantsArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NodeNgdotDescendantsArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NodeNgdotDescendantsArgs) ProtoMessage() {}
func (x *NodeNgdotDescendantsArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NodeNgdotDescendantsArgs.ProtoReflect.Descriptor instead.
func (*NodeNgdotDescendantsArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
type NodeNgdotInsertBeforeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NodeNgdotInsertBeforeArgs) Reset() {
*x = NodeNgdotInsertBeforeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NodeNgdotInsertBeforeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NodeNgdotInsertBeforeArgs) ProtoMessage() {}
func (x *NodeNgdotInsertBeforeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NodeNgdotInsertBeforeArgs.ProtoReflect.Descriptor instead.
func (*NodeNgdotInsertBeforeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
type NodeNgdotAppendChildArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NodeNgdotAppendChildArgs) Reset() {
*x = NodeNgdotAppendChildArgs{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NodeNgdotAppendChildArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NodeNgdotAppendChildArgs) ProtoMessage() {}
func (x *NodeNgdotAppendChildArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NodeNgdotAppendChildArgs.ProtoReflect.Descriptor instead.
func (*NodeNgdotAppendChildArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
type NodeNgdotRemoveChildArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NodeNgdotRemoveChildArgs) Reset() {
*x = NodeNgdotRemoveChildArgs{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NodeNgdotRemoveChildArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NodeNgdotRemoveChildArgs) ProtoMessage() {}
func (x *NodeNgdotRemoveChildArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NodeNgdotRemoveChildArgs.ProtoReflect.Descriptor instead.
func (*NodeNgdotRemoveChildArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
type ParseArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R []byte `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ParseArgs) Reset() {
*x = ParseArgs{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ParseArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ParseArgs) ProtoMessage() {}
func (x *ParseArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ParseArgs.ProtoReflect.Descriptor instead.
func (*ParseArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
func (x *ParseArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
type ParseFragmentArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R []byte `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ParseFragmentArgs) Reset() {
*x = ParseFragmentArgs{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ParseFragmentArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ParseFragmentArgs) ProtoMessage() {}
func (x *ParseFragmentArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ParseFragmentArgs.ProtoReflect.Descriptor instead.
func (*ParseFragmentArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
func (x *ParseFragmentArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
type ParseOptionEnableScriptingArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Enable bool `protobuf:"varint,1,opt,name=enable,proto3" json:"enable,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ParseOptionEnableScriptingArgs) Reset() {
*x = ParseOptionEnableScriptingArgs{}
mi := &file_ngolofuzz_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ParseOptionEnableScriptingArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ParseOptionEnableScriptingArgs) ProtoMessage() {}
func (x *ParseOptionEnableScriptingArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ParseOptionEnableScriptingArgs.ProtoReflect.Descriptor instead.
func (*ParseOptionEnableScriptingArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{10}
}
func (x *ParseOptionEnableScriptingArgs) GetEnable() bool {
if x != nil {
return x.Enable
}
return false
}
type RenderArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
W []byte `protobuf:"bytes,1,opt,name=w,proto3" json:"w,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RenderArgs) Reset() {
*x = RenderArgs{}
mi := &file_ngolofuzz_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RenderArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RenderArgs) ProtoMessage() {}
func (x *RenderArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[11]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RenderArgs.ProtoReflect.Descriptor instead.
func (*RenderArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{11}
}
func (x *RenderArgs) GetW() []byte {
if x != nil {
return x.W
}
return nil
}
type TokenTypeNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TokenTypeNgdotStringArgs) Reset() {
*x = TokenTypeNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TokenTypeNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TokenTypeNgdotStringArgs) ProtoMessage() {}
func (x *TokenTypeNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[12]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TokenTypeNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*TokenTypeNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{12}
}
type TokenNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TokenNgdotStringArgs) Reset() {
*x = TokenNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TokenNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TokenNgdotStringArgs) ProtoMessage() {}
func (x *TokenNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[13]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TokenNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*TokenNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{13}
}
type TokenizerNgdotAllowCDATAArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
AllowCDATA bool `protobuf:"varint,1,opt,name=allowCDATA,proto3" json:"allowCDATA,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TokenizerNgdotAllowCDATAArgs) Reset() {
*x = TokenizerNgdotAllowCDATAArgs{}
mi := &file_ngolofuzz_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TokenizerNgdotAllowCDATAArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TokenizerNgdotAllowCDATAArgs) ProtoMessage() {}
func (x *TokenizerNgdotAllowCDATAArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[14]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TokenizerNgdotAllowCDATAArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotAllowCDATAArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{14}
}
func (x *TokenizerNgdotAllowCDATAArgs) GetAllowCDATA() bool {
if x != nil {
return x.AllowCDATA
}
return false
}
type TokenizerNgdotNextIsNotRawTextArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TokenizerNgdotNextIsNotRawTextArgs) Reset() {
*x = TokenizerNgdotNextIsNotRawTextArgs{}
mi := &file_ngolofuzz_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TokenizerNgdotNextIsNotRawTextArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TokenizerNgdotNextIsNotRawTextArgs) ProtoMessage() {}
func (x *TokenizerNgdotNextIsNotRawTextArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[15]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TokenizerNgdotNextIsNotRawTextArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotNextIsNotRawTextArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{15}
}
type TokenizerNgdotErrArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TokenizerNgdotErrArgs) Reset() {
*x = TokenizerNgdotErrArgs{}
mi := &file_ngolofuzz_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TokenizerNgdotErrArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TokenizerNgdotErrArgs) ProtoMessage() {}
func (x *TokenizerNgdotErrArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[16]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TokenizerNgdotErrArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotErrArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{16}
}
type TokenizerNgdotBufferedArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TokenizerNgdotBufferedArgs) Reset() {
*x = TokenizerNgdotBufferedArgs{}
mi := &file_ngolofuzz_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TokenizerNgdotBufferedArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TokenizerNgdotBufferedArgs) ProtoMessage() {}
func (x *TokenizerNgdotBufferedArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[17]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TokenizerNgdotBufferedArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotBufferedArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{17}
}
type TokenizerNgdotNextArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TokenizerNgdotNextArgs) Reset() {
*x = TokenizerNgdotNextArgs{}
mi := &file_ngolofuzz_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TokenizerNgdotNextArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TokenizerNgdotNextArgs) ProtoMessage() {}
func (x *TokenizerNgdotNextArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[18]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TokenizerNgdotNextArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotNextArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{18}
}
type TokenizerNgdotRawArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TokenizerNgdotRawArgs) Reset() {
*x = TokenizerNgdotRawArgs{}
mi := &file_ngolofuzz_proto_msgTypes[19]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TokenizerNgdotRawArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TokenizerNgdotRawArgs) ProtoMessage() {}
func (x *TokenizerNgdotRawArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[19]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TokenizerNgdotRawArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotRawArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{19}
}
type TokenizerNgdotTextArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TokenizerNgdotTextArgs) Reset() {
*x = TokenizerNgdotTextArgs{}
mi := &file_ngolofuzz_proto_msgTypes[20]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TokenizerNgdotTextArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TokenizerNgdotTextArgs) ProtoMessage() {}
func (x *TokenizerNgdotTextArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[20]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TokenizerNgdotTextArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotTextArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{20}
}
type TokenizerNgdotTagNameArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TokenizerNgdotTagNameArgs) Reset() {
*x = TokenizerNgdotTagNameArgs{}
mi := &file_ngolofuzz_proto_msgTypes[21]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TokenizerNgdotTagNameArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TokenizerNgdotTagNameArgs) ProtoMessage() {}
func (x *TokenizerNgdotTagNameArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[21]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TokenizerNgdotTagNameArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotTagNameArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{21}
}
type TokenizerNgdotTagAttrArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TokenizerNgdotTagAttrArgs) Reset() {
*x = TokenizerNgdotTagAttrArgs{}
mi := &file_ngolofuzz_proto_msgTypes[22]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TokenizerNgdotTagAttrArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TokenizerNgdotTagAttrArgs) ProtoMessage() {}
func (x *TokenizerNgdotTagAttrArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[22]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TokenizerNgdotTagAttrArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotTagAttrArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{22}
}
type TokenizerNgdotTokenArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TokenizerNgdotTokenArgs) Reset() {
*x = TokenizerNgdotTokenArgs{}
mi := &file_ngolofuzz_proto_msgTypes[23]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TokenizerNgdotTokenArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TokenizerNgdotTokenArgs) ProtoMessage() {}
func (x *TokenizerNgdotTokenArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[23]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TokenizerNgdotTokenArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotTokenArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{23}
}
type TokenizerNgdotSetMaxBufArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
N int64 `protobuf:"varint,1,opt,name=n,proto3" json:"n,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TokenizerNgdotSetMaxBufArgs) Reset() {
*x = TokenizerNgdotSetMaxBufArgs{}
mi := &file_ngolofuzz_proto_msgTypes[24]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TokenizerNgdotSetMaxBufArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TokenizerNgdotSetMaxBufArgs) ProtoMessage() {}
func (x *TokenizerNgdotSetMaxBufArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[24]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TokenizerNgdotSetMaxBufArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotSetMaxBufArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{24}
}
func (x *TokenizerNgdotSetMaxBufArgs) GetN() int64 {
if x != nil {
return x.N
}
return 0
}
type NewTokenizerArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R []byte `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewTokenizerArgs) Reset() {
*x = NewTokenizerArgs{}
mi := &file_ngolofuzz_proto_msgTypes[25]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewTokenizerArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewTokenizerArgs) ProtoMessage() {}
func (x *NewTokenizerArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[25]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewTokenizerArgs.ProtoReflect.Descriptor instead.
func (*NewTokenizerArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{25}
}
func (x *NewTokenizerArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
type NewTokenizerFragmentArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R []byte `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
ContextTag string `protobuf:"bytes,2,opt,name=contextTag,proto3" json:"contextTag,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewTokenizerFragmentArgs) Reset() {
*x = NewTokenizerFragmentArgs{}
mi := &file_ngolofuzz_proto_msgTypes[26]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewTokenizerFragmentArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewTokenizerFragmentArgs) ProtoMessage() {}
func (x *NewTokenizerFragmentArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[26]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewTokenizerFragmentArgs.ProtoReflect.Descriptor instead.
func (*NewTokenizerFragmentArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{26}
}
func (x *NewTokenizerFragmentArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
func (x *NewTokenizerFragmentArgs) GetContextTag() string {
if x != nil {
return x.ContextTag
}
return ""
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_EscapeString
// *NgoloFuzzOne_UnescapeString
// *NgoloFuzzOne_NodeNgdotAncestors
// *NgoloFuzzOne_NodeNgdotChildNodes
// *NgoloFuzzOne_NodeNgdotDescendants
// *NgoloFuzzOne_NodeNgdotInsertBefore
// *NgoloFuzzOne_NodeNgdotAppendChild
// *NgoloFuzzOne_NodeNgdotRemoveChild
// *NgoloFuzzOne_Parse
// *NgoloFuzzOne_ParseFragment
// *NgoloFuzzOne_ParseOptionEnableScripting
// *NgoloFuzzOne_Render
// *NgoloFuzzOne_TokenTypeNgdotString
// *NgoloFuzzOne_TokenNgdotString
// *NgoloFuzzOne_TokenizerNgdotAllowCDATA
// *NgoloFuzzOne_TokenizerNgdotNextIsNotRawText
// *NgoloFuzzOne_TokenizerNgdotErr
// *NgoloFuzzOne_TokenizerNgdotBuffered
// *NgoloFuzzOne_TokenizerNgdotNext
// *NgoloFuzzOne_TokenizerNgdotRaw
// *NgoloFuzzOne_TokenizerNgdotText
// *NgoloFuzzOne_TokenizerNgdotTagName
// *NgoloFuzzOne_TokenizerNgdotTagAttr
// *NgoloFuzzOne_TokenizerNgdotToken
// *NgoloFuzzOne_TokenizerNgdotSetMaxBuf
// *NgoloFuzzOne_NewTokenizer
// *NgoloFuzzOne_NewTokenizerFragment
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[27]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[27]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{27}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetEscapeString() *EscapeStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_EscapeString); ok {
return x.EscapeString
}
}
return nil
}
func (x *NgoloFuzzOne) GetUnescapeString() *UnescapeStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_UnescapeString); ok {
return x.UnescapeString
}
}
return nil
}
func (x *NgoloFuzzOne) GetNodeNgdotAncestors() *NodeNgdotAncestorsArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NodeNgdotAncestors); ok {
return x.NodeNgdotAncestors
}
}
return nil
}
func (x *NgoloFuzzOne) GetNodeNgdotChildNodes() *NodeNgdotChildNodesArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NodeNgdotChildNodes); ok {
return x.NodeNgdotChildNodes
}
}
return nil
}
func (x *NgoloFuzzOne) GetNodeNgdotDescendants() *NodeNgdotDescendantsArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NodeNgdotDescendants); ok {
return x.NodeNgdotDescendants
}
}
return nil
}
func (x *NgoloFuzzOne) GetNodeNgdotInsertBefore() *NodeNgdotInsertBeforeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NodeNgdotInsertBefore); ok {
return x.NodeNgdotInsertBefore
}
}
return nil
}
func (x *NgoloFuzzOne) GetNodeNgdotAppendChild() *NodeNgdotAppendChildArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NodeNgdotAppendChild); ok {
return x.NodeNgdotAppendChild
}
}
return nil
}
func (x *NgoloFuzzOne) GetNodeNgdotRemoveChild() *NodeNgdotRemoveChildArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NodeNgdotRemoveChild); ok {
return x.NodeNgdotRemoveChild
}
}
return nil
}
func (x *NgoloFuzzOne) GetParse() *ParseArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Parse); ok {
return x.Parse
}
}
return nil
}
func (x *NgoloFuzzOne) GetParseFragment() *ParseFragmentArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ParseFragment); ok {
return x.ParseFragment
}
}
return nil
}
func (x *NgoloFuzzOne) GetParseOptionEnableScripting() *ParseOptionEnableScriptingArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ParseOptionEnableScripting); ok {
return x.ParseOptionEnableScripting
}
}
return nil
}
func (x *NgoloFuzzOne) GetRender() *RenderArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Render); ok {
return x.Render
}
}
return nil
}
func (x *NgoloFuzzOne) GetTokenTypeNgdotString() *TokenTypeNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TokenTypeNgdotString); ok {
return x.TokenTypeNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetTokenNgdotString() *TokenNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TokenNgdotString); ok {
return x.TokenNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetTokenizerNgdotAllowCDATA() *TokenizerNgdotAllowCDATAArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TokenizerNgdotAllowCDATA); ok {
return x.TokenizerNgdotAllowCDATA
}
}
return nil
}
func (x *NgoloFuzzOne) GetTokenizerNgdotNextIsNotRawText() *TokenizerNgdotNextIsNotRawTextArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TokenizerNgdotNextIsNotRawText); ok {
return x.TokenizerNgdotNextIsNotRawText
}
}
return nil
}
func (x *NgoloFuzzOne) GetTokenizerNgdotErr() *TokenizerNgdotErrArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TokenizerNgdotErr); ok {
return x.TokenizerNgdotErr
}
}
return nil
}
func (x *NgoloFuzzOne) GetTokenizerNgdotBuffered() *TokenizerNgdotBufferedArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TokenizerNgdotBuffered); ok {
return x.TokenizerNgdotBuffered
}
}
return nil
}
func (x *NgoloFuzzOne) GetTokenizerNgdotNext() *TokenizerNgdotNextArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TokenizerNgdotNext); ok {
return x.TokenizerNgdotNext
}
}
return nil
}
func (x *NgoloFuzzOne) GetTokenizerNgdotRaw() *TokenizerNgdotRawArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TokenizerNgdotRaw); ok {
return x.TokenizerNgdotRaw
}
}
return nil
}
func (x *NgoloFuzzOne) GetTokenizerNgdotText() *TokenizerNgdotTextArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TokenizerNgdotText); ok {
return x.TokenizerNgdotText
}
}
return nil
}
func (x *NgoloFuzzOne) GetTokenizerNgdotTagName() *TokenizerNgdotTagNameArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TokenizerNgdotTagName); ok {
return x.TokenizerNgdotTagName
}
}
return nil
}
func (x *NgoloFuzzOne) GetTokenizerNgdotTagAttr() *TokenizerNgdotTagAttrArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TokenizerNgdotTagAttr); ok {
return x.TokenizerNgdotTagAttr
}
}
return nil
}
func (x *NgoloFuzzOne) GetTokenizerNgdotToken() *TokenizerNgdotTokenArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TokenizerNgdotToken); ok {
return x.TokenizerNgdotToken
}
}
return nil
}
func (x *NgoloFuzzOne) GetTokenizerNgdotSetMaxBuf() *TokenizerNgdotSetMaxBufArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TokenizerNgdotSetMaxBuf); ok {
return x.TokenizerNgdotSetMaxBuf
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewTokenizer() *NewTokenizerArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewTokenizer); ok {
return x.NewTokenizer
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewTokenizerFragment() *NewTokenizerFragmentArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewTokenizerFragment); ok {
return x.NewTokenizerFragment
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_EscapeString struct {
EscapeString *EscapeStringArgs `protobuf:"bytes,1,opt,name=EscapeString,proto3,oneof"`
}
type NgoloFuzzOne_UnescapeString struct {
UnescapeString *UnescapeStringArgs `protobuf:"bytes,2,opt,name=UnescapeString,proto3,oneof"`
}
type NgoloFuzzOne_NodeNgdotAncestors struct {
NodeNgdotAncestors *NodeNgdotAncestorsArgs `protobuf:"bytes,3,opt,name=NodeNgdotAncestors,proto3,oneof"`
}
type NgoloFuzzOne_NodeNgdotChildNodes struct {
NodeNgdotChildNodes *NodeNgdotChildNodesArgs `protobuf:"bytes,4,opt,name=NodeNgdotChildNodes,proto3,oneof"`
}
type NgoloFuzzOne_NodeNgdotDescendants struct {
NodeNgdotDescendants *NodeNgdotDescendantsArgs `protobuf:"bytes,5,opt,name=NodeNgdotDescendants,proto3,oneof"`
}
type NgoloFuzzOne_NodeNgdotInsertBefore struct {
NodeNgdotInsertBefore *NodeNgdotInsertBeforeArgs `protobuf:"bytes,6,opt,name=NodeNgdotInsertBefore,proto3,oneof"`
}
type NgoloFuzzOne_NodeNgdotAppendChild struct {
NodeNgdotAppendChild *NodeNgdotAppendChildArgs `protobuf:"bytes,7,opt,name=NodeNgdotAppendChild,proto3,oneof"`
}
type NgoloFuzzOne_NodeNgdotRemoveChild struct {
NodeNgdotRemoveChild *NodeNgdotRemoveChildArgs `protobuf:"bytes,8,opt,name=NodeNgdotRemoveChild,proto3,oneof"`
}
type NgoloFuzzOne_Parse struct {
Parse *ParseArgs `protobuf:"bytes,9,opt,name=Parse,proto3,oneof"`
}
type NgoloFuzzOne_ParseFragment struct {
ParseFragment *ParseFragmentArgs `protobuf:"bytes,10,opt,name=ParseFragment,proto3,oneof"`
}
type NgoloFuzzOne_ParseOptionEnableScripting struct {
ParseOptionEnableScripting *ParseOptionEnableScriptingArgs `protobuf:"bytes,11,opt,name=ParseOptionEnableScripting,proto3,oneof"`
}
type NgoloFuzzOne_Render struct {
Render *RenderArgs `protobuf:"bytes,12,opt,name=Render,proto3,oneof"`
}
type NgoloFuzzOne_TokenTypeNgdotString struct {
TokenTypeNgdotString *TokenTypeNgdotStringArgs `protobuf:"bytes,13,opt,name=TokenTypeNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_TokenNgdotString struct {
TokenNgdotString *TokenNgdotStringArgs `protobuf:"bytes,14,opt,name=TokenNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotAllowCDATA struct {
TokenizerNgdotAllowCDATA *TokenizerNgdotAllowCDATAArgs `protobuf:"bytes,15,opt,name=TokenizerNgdotAllowCDATA,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotNextIsNotRawText struct {
TokenizerNgdotNextIsNotRawText *TokenizerNgdotNextIsNotRawTextArgs `protobuf:"bytes,16,opt,name=TokenizerNgdotNextIsNotRawText,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotErr struct {
TokenizerNgdotErr *TokenizerNgdotErrArgs `protobuf:"bytes,17,opt,name=TokenizerNgdotErr,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotBuffered struct {
TokenizerNgdotBuffered *TokenizerNgdotBufferedArgs `protobuf:"bytes,18,opt,name=TokenizerNgdotBuffered,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotNext struct {
TokenizerNgdotNext *TokenizerNgdotNextArgs `protobuf:"bytes,19,opt,name=TokenizerNgdotNext,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotRaw struct {
TokenizerNgdotRaw *TokenizerNgdotRawArgs `protobuf:"bytes,20,opt,name=TokenizerNgdotRaw,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotText struct {
TokenizerNgdotText *TokenizerNgdotTextArgs `protobuf:"bytes,21,opt,name=TokenizerNgdotText,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotTagName struct {
TokenizerNgdotTagName *TokenizerNgdotTagNameArgs `protobuf:"bytes,22,opt,name=TokenizerNgdotTagName,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotTagAttr struct {
TokenizerNgdotTagAttr *TokenizerNgdotTagAttrArgs `protobuf:"bytes,23,opt,name=TokenizerNgdotTagAttr,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotToken struct {
TokenizerNgdotToken *TokenizerNgdotTokenArgs `protobuf:"bytes,24,opt,name=TokenizerNgdotToken,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotSetMaxBuf struct {
TokenizerNgdotSetMaxBuf *TokenizerNgdotSetMaxBufArgs `protobuf:"bytes,25,opt,name=TokenizerNgdotSetMaxBuf,proto3,oneof"`
}
type NgoloFuzzOne_NewTokenizer struct {
NewTokenizer *NewTokenizerArgs `protobuf:"bytes,26,opt,name=NewTokenizer,proto3,oneof"`
}
type NgoloFuzzOne_NewTokenizerFragment struct {
NewTokenizerFragment *NewTokenizerFragmentArgs `protobuf:"bytes,27,opt,name=NewTokenizerFragment,proto3,oneof"`
}
func (*NgoloFuzzOne_EscapeString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_UnescapeString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NodeNgdotAncestors) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NodeNgdotChildNodes) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NodeNgdotDescendants) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NodeNgdotInsertBefore) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NodeNgdotAppendChild) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NodeNgdotRemoveChild) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Parse) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ParseFragment) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ParseOptionEnableScripting) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Render) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TokenTypeNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TokenNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TokenizerNgdotAllowCDATA) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TokenizerNgdotNextIsNotRawText) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TokenizerNgdotErr) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TokenizerNgdotBuffered) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TokenizerNgdotNext) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TokenizerNgdotRaw) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TokenizerNgdotText) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TokenizerNgdotTagName) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TokenizerNgdotTagAttr) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TokenizerNgdotToken) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TokenizerNgdotSetMaxBuf) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewTokenizer) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewTokenizerFragment) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[28]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[28]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{28}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[29]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[29]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{29}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\" \n" +
"\x10EscapeStringArgs\x12\f\n" +
"\x01s\x18\x01 \x01(\tR\x01s\"\"\n" +
"\x12UnescapeStringArgs\x12\f\n" +
"\x01s\x18\x01 \x01(\tR\x01s\"\x18\n" +
"\x16NodeNgdotAncestorsArgs\"\x19\n" +
"\x17NodeNgdotChildNodesArgs\"\x1a\n" +
"\x18NodeNgdotDescendantsArgs\"\x1b\n" +
"\x19NodeNgdotInsertBeforeArgs\"\x1a\n" +
"\x18NodeNgdotAppendChildArgs\"\x1a\n" +
"\x18NodeNgdotRemoveChildArgs\"\x19\n" +
"\tParseArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\fR\x01r\"!\n" +
"\x11ParseFragmentArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\fR\x01r\"8\n" +
"\x1eParseOptionEnableScriptingArgs\x12\x16\n" +
"\x06enable\x18\x01 \x01(\bR\x06enable\"\x1a\n" +
"\n" +
"RenderArgs\x12\f\n" +
"\x01w\x18\x01 \x01(\fR\x01w\"\x1a\n" +
"\x18TokenTypeNgdotStringArgs\"\x16\n" +
"\x14TokenNgdotStringArgs\">\n" +
"\x1cTokenizerNgdotAllowCDATAArgs\x12\x1e\n" +
"\n" +
"allowCDATA\x18\x01 \x01(\bR\n" +
"allowCDATA\"$\n" +
"\"TokenizerNgdotNextIsNotRawTextArgs\"\x17\n" +
"\x15TokenizerNgdotErrArgs\"\x1c\n" +
"\x1aTokenizerNgdotBufferedArgs\"\x18\n" +
"\x16TokenizerNgdotNextArgs\"\x17\n" +
"\x15TokenizerNgdotRawArgs\"\x18\n" +
"\x16TokenizerNgdotTextArgs\"\x1b\n" +
"\x19TokenizerNgdotTagNameArgs\"\x1b\n" +
"\x19TokenizerNgdotTagAttrArgs\"\x19\n" +
"\x17TokenizerNgdotTokenArgs\"+\n" +
"\x1bTokenizerNgdotSetMaxBufArgs\x12\f\n" +
"\x01n\x18\x01 \x01(\x03R\x01n\" \n" +
"\x10NewTokenizerArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\fR\x01r\"H\n" +
"\x18NewTokenizerFragmentArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\fR\x01r\x12\x1e\n" +
"\n" +
"contextTag\x18\x02 \x01(\tR\n" +
"contextTag\"\x9f\x12\n" +
"\fNgoloFuzzOne\x12A\n" +
"\fEscapeString\x18\x01 \x01(\v2\x1b.ngolofuzz.EscapeStringArgsH\x00R\fEscapeString\x12G\n" +
"\x0eUnescapeString\x18\x02 \x01(\v2\x1d.ngolofuzz.UnescapeStringArgsH\x00R\x0eUnescapeString\x12S\n" +
"\x12NodeNgdotAncestors\x18\x03 \x01(\v2!.ngolofuzz.NodeNgdotAncestorsArgsH\x00R\x12NodeNgdotAncestors\x12V\n" +
"\x13NodeNgdotChildNodes\x18\x04 \x01(\v2\".ngolofuzz.NodeNgdotChildNodesArgsH\x00R\x13NodeNgdotChildNodes\x12Y\n" +
"\x14NodeNgdotDescendants\x18\x05 \x01(\v2#.ngolofuzz.NodeNgdotDescendantsArgsH\x00R\x14NodeNgdotDescendants\x12\\\n" +
"\x15NodeNgdotInsertBefore\x18\x06 \x01(\v2$.ngolofuzz.NodeNgdotInsertBeforeArgsH\x00R\x15NodeNgdotInsertBefore\x12Y\n" +
"\x14NodeNgdotAppendChild\x18\a \x01(\v2#.ngolofuzz.NodeNgdotAppendChildArgsH\x00R\x14NodeNgdotAppendChild\x12Y\n" +
"\x14NodeNgdotRemoveChild\x18\b \x01(\v2#.ngolofuzz.NodeNgdotRemoveChildArgsH\x00R\x14NodeNgdotRemoveChild\x12,\n" +
"\x05Parse\x18\t \x01(\v2\x14.ngolofuzz.ParseArgsH\x00R\x05Parse\x12D\n" +
"\rParseFragment\x18\n" +
" \x01(\v2\x1c.ngolofuzz.ParseFragmentArgsH\x00R\rParseFragment\x12k\n" +
"\x1aParseOptionEnableScripting\x18\v \x01(\v2).ngolofuzz.ParseOptionEnableScriptingArgsH\x00R\x1aParseOptionEnableScripting\x12/\n" +
"\x06Render\x18\f \x01(\v2\x15.ngolofuzz.RenderArgsH\x00R\x06Render\x12Y\n" +
"\x14TokenTypeNgdotString\x18\r \x01(\v2#.ngolofuzz.TokenTypeNgdotStringArgsH\x00R\x14TokenTypeNgdotString\x12M\n" +
"\x10TokenNgdotString\x18\x0e \x01(\v2\x1f.ngolofuzz.TokenNgdotStringArgsH\x00R\x10TokenNgdotString\x12e\n" +
"\x18TokenizerNgdotAllowCDATA\x18\x0f \x01(\v2'.ngolofuzz.TokenizerNgdotAllowCDATAArgsH\x00R\x18TokenizerNgdotAllowCDATA\x12w\n" +
"\x1eTokenizerNgdotNextIsNotRawText\x18\x10 \x01(\v2-.ngolofuzz.TokenizerNgdotNextIsNotRawTextArgsH\x00R\x1eTokenizerNgdotNextIsNotRawText\x12P\n" +
"\x11TokenizerNgdotErr\x18\x11 \x01(\v2 .ngolofuzz.TokenizerNgdotErrArgsH\x00R\x11TokenizerNgdotErr\x12_\n" +
"\x16TokenizerNgdotBuffered\x18\x12 \x01(\v2%.ngolofuzz.TokenizerNgdotBufferedArgsH\x00R\x16TokenizerNgdotBuffered\x12S\n" +
"\x12TokenizerNgdotNext\x18\x13 \x01(\v2!.ngolofuzz.TokenizerNgdotNextArgsH\x00R\x12TokenizerNgdotNext\x12P\n" +
"\x11TokenizerNgdotRaw\x18\x14 \x01(\v2 .ngolofuzz.TokenizerNgdotRawArgsH\x00R\x11TokenizerNgdotRaw\x12S\n" +
"\x12TokenizerNgdotText\x18\x15 \x01(\v2!.ngolofuzz.TokenizerNgdotTextArgsH\x00R\x12TokenizerNgdotText\x12\\\n" +
"\x15TokenizerNgdotTagName\x18\x16 \x01(\v2$.ngolofuzz.TokenizerNgdotTagNameArgsH\x00R\x15TokenizerNgdotTagName\x12\\\n" +
"\x15TokenizerNgdotTagAttr\x18\x17 \x01(\v2$.ngolofuzz.TokenizerNgdotTagAttrArgsH\x00R\x15TokenizerNgdotTagAttr\x12V\n" +
"\x13TokenizerNgdotToken\x18\x18 \x01(\v2\".ngolofuzz.TokenizerNgdotTokenArgsH\x00R\x13TokenizerNgdotToken\x12b\n" +
"\x17TokenizerNgdotSetMaxBuf\x18\x19 \x01(\v2&.ngolofuzz.TokenizerNgdotSetMaxBufArgsH\x00R\x17TokenizerNgdotSetMaxBuf\x12A\n" +
"\fNewTokenizer\x18\x1a \x01(\v2\x1b.ngolofuzz.NewTokenizerArgsH\x00R\fNewTokenizer\x12Y\n" +
"\x14NewTokenizerFragment\x18\x1b \x01(\v2#.ngolofuzz.NewTokenizerFragmentArgsH\x00R\x14NewTokenizerFragmentB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x17Z\x15./;fuzz_ng_x_net_htmlb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 30)
var file_ngolofuzz_proto_goTypes = []any{
(*EscapeStringArgs)(nil), // 0: ngolofuzz.EscapeStringArgs
(*UnescapeStringArgs)(nil), // 1: ngolofuzz.UnescapeStringArgs
(*NodeNgdotAncestorsArgs)(nil), // 2: ngolofuzz.NodeNgdotAncestorsArgs
(*NodeNgdotChildNodesArgs)(nil), // 3: ngolofuzz.NodeNgdotChildNodesArgs
(*NodeNgdotDescendantsArgs)(nil), // 4: ngolofuzz.NodeNgdotDescendantsArgs
(*NodeNgdotInsertBeforeArgs)(nil), // 5: ngolofuzz.NodeNgdotInsertBeforeArgs
(*NodeNgdotAppendChildArgs)(nil), // 6: ngolofuzz.NodeNgdotAppendChildArgs
(*NodeNgdotRemoveChildArgs)(nil), // 7: ngolofuzz.NodeNgdotRemoveChildArgs
(*ParseArgs)(nil), // 8: ngolofuzz.ParseArgs
(*ParseFragmentArgs)(nil), // 9: ngolofuzz.ParseFragmentArgs
(*ParseOptionEnableScriptingArgs)(nil), // 10: ngolofuzz.ParseOptionEnableScriptingArgs
(*RenderArgs)(nil), // 11: ngolofuzz.RenderArgs
(*TokenTypeNgdotStringArgs)(nil), // 12: ngolofuzz.TokenTypeNgdotStringArgs
(*TokenNgdotStringArgs)(nil), // 13: ngolofuzz.TokenNgdotStringArgs
(*TokenizerNgdotAllowCDATAArgs)(nil), // 14: ngolofuzz.TokenizerNgdotAllowCDATAArgs
(*TokenizerNgdotNextIsNotRawTextArgs)(nil), // 15: ngolofuzz.TokenizerNgdotNextIsNotRawTextArgs
(*TokenizerNgdotErrArgs)(nil), // 16: ngolofuzz.TokenizerNgdotErrArgs
(*TokenizerNgdotBufferedArgs)(nil), // 17: ngolofuzz.TokenizerNgdotBufferedArgs
(*TokenizerNgdotNextArgs)(nil), // 18: ngolofuzz.TokenizerNgdotNextArgs
(*TokenizerNgdotRawArgs)(nil), // 19: ngolofuzz.TokenizerNgdotRawArgs
(*TokenizerNgdotTextArgs)(nil), // 20: ngolofuzz.TokenizerNgdotTextArgs
(*TokenizerNgdotTagNameArgs)(nil), // 21: ngolofuzz.TokenizerNgdotTagNameArgs
(*TokenizerNgdotTagAttrArgs)(nil), // 22: ngolofuzz.TokenizerNgdotTagAttrArgs
(*TokenizerNgdotTokenArgs)(nil), // 23: ngolofuzz.TokenizerNgdotTokenArgs
(*TokenizerNgdotSetMaxBufArgs)(nil), // 24: ngolofuzz.TokenizerNgdotSetMaxBufArgs
(*NewTokenizerArgs)(nil), // 25: ngolofuzz.NewTokenizerArgs
(*NewTokenizerFragmentArgs)(nil), // 26: ngolofuzz.NewTokenizerFragmentArgs
(*NgoloFuzzOne)(nil), // 27: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 28: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 29: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.EscapeString:type_name -> ngolofuzz.EscapeStringArgs
1, // 1: ngolofuzz.NgoloFuzzOne.UnescapeString:type_name -> ngolofuzz.UnescapeStringArgs
2, // 2: ngolofuzz.NgoloFuzzOne.NodeNgdotAncestors:type_name -> ngolofuzz.NodeNgdotAncestorsArgs
3, // 3: ngolofuzz.NgoloFuzzOne.NodeNgdotChildNodes:type_name -> ngolofuzz.NodeNgdotChildNodesArgs
4, // 4: ngolofuzz.NgoloFuzzOne.NodeNgdotDescendants:type_name -> ngolofuzz.NodeNgdotDescendantsArgs
5, // 5: ngolofuzz.NgoloFuzzOne.NodeNgdotInsertBefore:type_name -> ngolofuzz.NodeNgdotInsertBeforeArgs
6, // 6: ngolofuzz.NgoloFuzzOne.NodeNgdotAppendChild:type_name -> ngolofuzz.NodeNgdotAppendChildArgs
7, // 7: ngolofuzz.NgoloFuzzOne.NodeNgdotRemoveChild:type_name -> ngolofuzz.NodeNgdotRemoveChildArgs
8, // 8: ngolofuzz.NgoloFuzzOne.Parse:type_name -> ngolofuzz.ParseArgs
9, // 9: ngolofuzz.NgoloFuzzOne.ParseFragment:type_name -> ngolofuzz.ParseFragmentArgs
10, // 10: ngolofuzz.NgoloFuzzOne.ParseOptionEnableScripting:type_name -> ngolofuzz.ParseOptionEnableScriptingArgs
11, // 11: ngolofuzz.NgoloFuzzOne.Render:type_name -> ngolofuzz.RenderArgs
12, // 12: ngolofuzz.NgoloFuzzOne.TokenTypeNgdotString:type_name -> ngolofuzz.TokenTypeNgdotStringArgs
13, // 13: ngolofuzz.NgoloFuzzOne.TokenNgdotString:type_name -> ngolofuzz.TokenNgdotStringArgs
14, // 14: ngolofuzz.NgoloFuzzOne.TokenizerNgdotAllowCDATA:type_name -> ngolofuzz.TokenizerNgdotAllowCDATAArgs
15, // 15: ngolofuzz.NgoloFuzzOne.TokenizerNgdotNextIsNotRawText:type_name -> ngolofuzz.TokenizerNgdotNextIsNotRawTextArgs
16, // 16: ngolofuzz.NgoloFuzzOne.TokenizerNgdotErr:type_name -> ngolofuzz.TokenizerNgdotErrArgs
17, // 17: ngolofuzz.NgoloFuzzOne.TokenizerNgdotBuffered:type_name -> ngolofuzz.TokenizerNgdotBufferedArgs
18, // 18: ngolofuzz.NgoloFuzzOne.TokenizerNgdotNext:type_name -> ngolofuzz.TokenizerNgdotNextArgs
19, // 19: ngolofuzz.NgoloFuzzOne.TokenizerNgdotRaw:type_name -> ngolofuzz.TokenizerNgdotRawArgs
20, // 20: ngolofuzz.NgoloFuzzOne.TokenizerNgdotText:type_name -> ngolofuzz.TokenizerNgdotTextArgs
21, // 21: ngolofuzz.NgoloFuzzOne.TokenizerNgdotTagName:type_name -> ngolofuzz.TokenizerNgdotTagNameArgs
22, // 22: ngolofuzz.NgoloFuzzOne.TokenizerNgdotTagAttr:type_name -> ngolofuzz.TokenizerNgdotTagAttrArgs
23, // 23: ngolofuzz.NgoloFuzzOne.TokenizerNgdotToken:type_name -> ngolofuzz.TokenizerNgdotTokenArgs
24, // 24: ngolofuzz.NgoloFuzzOne.TokenizerNgdotSetMaxBuf:type_name -> ngolofuzz.TokenizerNgdotSetMaxBufArgs
25, // 25: ngolofuzz.NgoloFuzzOne.NewTokenizer:type_name -> ngolofuzz.NewTokenizerArgs
26, // 26: ngolofuzz.NgoloFuzzOne.NewTokenizerFragment:type_name -> ngolofuzz.NewTokenizerFragmentArgs
27, // 27: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
28, // [28:28] is the sub-list for method output_type
28, // [28:28] is the sub-list for method input_type
28, // [28:28] is the sub-list for extension type_name
28, // [28:28] is the sub-list for extension extendee
0, // [0:28] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[27].OneofWrappers = []any{
(*NgoloFuzzOne_EscapeString)(nil),
(*NgoloFuzzOne_UnescapeString)(nil),
(*NgoloFuzzOne_NodeNgdotAncestors)(nil),
(*NgoloFuzzOne_NodeNgdotChildNodes)(nil),
(*NgoloFuzzOne_NodeNgdotDescendants)(nil),
(*NgoloFuzzOne_NodeNgdotInsertBefore)(nil),
(*NgoloFuzzOne_NodeNgdotAppendChild)(nil),
(*NgoloFuzzOne_NodeNgdotRemoveChild)(nil),
(*NgoloFuzzOne_Parse)(nil),
(*NgoloFuzzOne_ParseFragment)(nil),
(*NgoloFuzzOne_ParseOptionEnableScripting)(nil),
(*NgoloFuzzOne_Render)(nil),
(*NgoloFuzzOne_TokenTypeNgdotString)(nil),
(*NgoloFuzzOne_TokenNgdotString)(nil),
(*NgoloFuzzOne_TokenizerNgdotAllowCDATA)(nil),
(*NgoloFuzzOne_TokenizerNgdotNextIsNotRawText)(nil),
(*NgoloFuzzOne_TokenizerNgdotErr)(nil),
(*NgoloFuzzOne_TokenizerNgdotBuffered)(nil),
(*NgoloFuzzOne_TokenizerNgdotNext)(nil),
(*NgoloFuzzOne_TokenizerNgdotRaw)(nil),
(*NgoloFuzzOne_TokenizerNgdotText)(nil),
(*NgoloFuzzOne_TokenizerNgdotTagName)(nil),
(*NgoloFuzzOne_TokenizerNgdotTagAttr)(nil),
(*NgoloFuzzOne_TokenizerNgdotToken)(nil),
(*NgoloFuzzOne_TokenizerNgdotSetMaxBuf)(nil),
(*NgoloFuzzOne_NewTokenizer)(nil),
(*NgoloFuzzOne_NewTokenizerFragment)(nil),
}
file_ngolofuzz_proto_msgTypes[28].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 30,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_net_html_charset
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/net/html/charset"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Lookup:
charset.Lookup(a.Lookup.Label)
case *NgoloFuzzOne_DetermineEncoding:
charset.DetermineEncoding(a.DetermineEncoding.Content, a.DetermineEncoding.ContentType)
case *NgoloFuzzOne_NewReader:
arg0 := bytes.NewReader(a.NewReader.R)
_, r1 := charset.NewReader(arg0, a.NewReader.ContentType)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_NewReaderLabel:
arg1 := bytes.NewReader(a.NewReaderLabel.Input)
_, r1 := charset.NewReaderLabel(a.NewReaderLabel.Label, arg1)
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Lookup:
w.WriteString(fmt.Sprintf("charset.Lookup(%#+v)\n", a.Lookup.Label))
case *NgoloFuzzOne_DetermineEncoding:
w.WriteString(fmt.Sprintf("charset.DetermineEncoding(%#+v, %#+v)\n", a.DetermineEncoding.Content, a.DetermineEncoding.ContentType))
case *NgoloFuzzOne_NewReader:
w.WriteString(fmt.Sprintf("charset.NewReader(bytes.NewReader(%#+v), %#+v)\n", a.NewReader.R, a.NewReader.ContentType))
case *NgoloFuzzOne_NewReaderLabel:
w.WriteString(fmt.Sprintf("charset.NewReaderLabel(%#+v, bytes.NewReader(%#+v))\n", a.NewReaderLabel.Label, a.NewReaderLabel.Input))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_net_html_charset
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type LookupArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Label string `protobuf:"bytes,1,opt,name=label,proto3" json:"label,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *LookupArgs) Reset() {
*x = LookupArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *LookupArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*LookupArgs) ProtoMessage() {}
func (x *LookupArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use LookupArgs.ProtoReflect.Descriptor instead.
func (*LookupArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *LookupArgs) GetLabel() string {
if x != nil {
return x.Label
}
return ""
}
type DetermineEncodingArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Content []byte `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"`
ContentType string `protobuf:"bytes,2,opt,name=contentType,proto3" json:"contentType,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DetermineEncodingArgs) Reset() {
*x = DetermineEncodingArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DetermineEncodingArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DetermineEncodingArgs) ProtoMessage() {}
func (x *DetermineEncodingArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DetermineEncodingArgs.ProtoReflect.Descriptor instead.
func (*DetermineEncodingArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *DetermineEncodingArgs) GetContent() []byte {
if x != nil {
return x.Content
}
return nil
}
func (x *DetermineEncodingArgs) GetContentType() string {
if x != nil {
return x.ContentType
}
return ""
}
type NewReaderArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R []byte `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
ContentType string `protobuf:"bytes,2,opt,name=contentType,proto3" json:"contentType,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewReaderArgs) Reset() {
*x = NewReaderArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewReaderArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewReaderArgs) ProtoMessage() {}
func (x *NewReaderArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewReaderArgs.ProtoReflect.Descriptor instead.
func (*NewReaderArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NewReaderArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
func (x *NewReaderArgs) GetContentType() string {
if x != nil {
return x.ContentType
}
return ""
}
type NewReaderLabelArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Label string `protobuf:"bytes,1,opt,name=label,proto3" json:"label,omitempty"`
Input []byte `protobuf:"bytes,2,opt,name=input,proto3" json:"input,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewReaderLabelArgs) Reset() {
*x = NewReaderLabelArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewReaderLabelArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewReaderLabelArgs) ProtoMessage() {}
func (x *NewReaderLabelArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewReaderLabelArgs.ProtoReflect.Descriptor instead.
func (*NewReaderLabelArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NewReaderLabelArgs) GetLabel() string {
if x != nil {
return x.Label
}
return ""
}
func (x *NewReaderLabelArgs) GetInput() []byte {
if x != nil {
return x.Input
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_Lookup
// *NgoloFuzzOne_DetermineEncoding
// *NgoloFuzzOne_NewReader
// *NgoloFuzzOne_NewReaderLabel
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetLookup() *LookupArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Lookup); ok {
return x.Lookup
}
}
return nil
}
func (x *NgoloFuzzOne) GetDetermineEncoding() *DetermineEncodingArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_DetermineEncoding); ok {
return x.DetermineEncoding
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewReader() *NewReaderArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewReader); ok {
return x.NewReader
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewReaderLabel() *NewReaderLabelArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewReaderLabel); ok {
return x.NewReaderLabel
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_Lookup struct {
Lookup *LookupArgs `protobuf:"bytes,1,opt,name=Lookup,proto3,oneof"`
}
type NgoloFuzzOne_DetermineEncoding struct {
DetermineEncoding *DetermineEncodingArgs `protobuf:"bytes,2,opt,name=DetermineEncoding,proto3,oneof"`
}
type NgoloFuzzOne_NewReader struct {
NewReader *NewReaderArgs `protobuf:"bytes,3,opt,name=NewReader,proto3,oneof"`
}
type NgoloFuzzOne_NewReaderLabel struct {
NewReaderLabel *NewReaderLabelArgs `protobuf:"bytes,4,opt,name=NewReaderLabel,proto3,oneof"`
}
func (*NgoloFuzzOne_Lookup) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_DetermineEncoding) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewReader) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewReaderLabel) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\"\n" +
"\n" +
"LookupArgs\x12\x14\n" +
"\x05label\x18\x01 \x01(\tR\x05label\"S\n" +
"\x15DetermineEncodingArgs\x12\x18\n" +
"\acontent\x18\x01 \x01(\fR\acontent\x12 \n" +
"\vcontentType\x18\x02 \x01(\tR\vcontentType\"?\n" +
"\rNewReaderArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\fR\x01r\x12 \n" +
"\vcontentType\x18\x02 \x01(\tR\vcontentType\"@\n" +
"\x12NewReaderLabelArgs\x12\x14\n" +
"\x05label\x18\x01 \x01(\tR\x05label\x12\x14\n" +
"\x05input\x18\x02 \x01(\fR\x05input\"\x9c\x02\n" +
"\fNgoloFuzzOne\x12/\n" +
"\x06Lookup\x18\x01 \x01(\v2\x15.ngolofuzz.LookupArgsH\x00R\x06Lookup\x12P\n" +
"\x11DetermineEncoding\x18\x02 \x01(\v2 .ngolofuzz.DetermineEncodingArgsH\x00R\x11DetermineEncoding\x128\n" +
"\tNewReader\x18\x03 \x01(\v2\x18.ngolofuzz.NewReaderArgsH\x00R\tNewReader\x12G\n" +
"\x0eNewReaderLabel\x18\x04 \x01(\v2\x1d.ngolofuzz.NewReaderLabelArgsH\x00R\x0eNewReaderLabelB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1fZ\x1d./;fuzz_ng_x_net_html_charsetb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_ngolofuzz_proto_goTypes = []any{
(*LookupArgs)(nil), // 0: ngolofuzz.LookupArgs
(*DetermineEncodingArgs)(nil), // 1: ngolofuzz.DetermineEncodingArgs
(*NewReaderArgs)(nil), // 2: ngolofuzz.NewReaderArgs
(*NewReaderLabelArgs)(nil), // 3: ngolofuzz.NewReaderLabelArgs
(*NgoloFuzzOne)(nil), // 4: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 5: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 6: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.Lookup:type_name -> ngolofuzz.LookupArgs
1, // 1: ngolofuzz.NgoloFuzzOne.DetermineEncoding:type_name -> ngolofuzz.DetermineEncodingArgs
2, // 2: ngolofuzz.NgoloFuzzOne.NewReader:type_name -> ngolofuzz.NewReaderArgs
3, // 3: ngolofuzz.NgoloFuzzOne.NewReaderLabel:type_name -> ngolofuzz.NewReaderLabelArgs
4, // 4: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[4].OneofWrappers = []any{
(*NgoloFuzzOne_Lookup)(nil),
(*NgoloFuzzOne_DetermineEncoding)(nil),
(*NgoloFuzzOne_NewReader)(nil),
(*NgoloFuzzOne_NewReaderLabel)(nil),
}
file_ngolofuzz_proto_msgTypes[5].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 7,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_net_http2
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/net/http2"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func SettingIDNewFromFuzz(p SettingIDEnum) http2.SettingID{
switch p {
case 1:
return http2.SettingEnablePush
case 2:
return http2.SettingMaxConcurrentStreams
case 3:
return http2.SettingInitialWindowSize
case 4:
return http2.SettingMaxFrameSize
case 5:
return http2.SettingMaxHeaderListSize
case 6:
return http2.SettingEnableConnectProtocol
}
return http2.SettingHeaderTableSize
}
func ConvertSettingIDNewFromFuzz(a []SettingIDEnum) []http2.SettingID{
r := make([]http2.SettingID, len(a))
for i := range a {
r[i] = SettingIDNewFromFuzz(a[i])
}
return r
}
func FrameTypeNewFromFuzz(p FrameTypeEnum) http2.FrameType{
switch p {
case 1:
return http2.FrameHeaders
case 2:
return http2.FramePriority
case 3:
return http2.FrameRSTStream
case 4:
return http2.FrameSettings
case 5:
return http2.FramePushPromise
case 6:
return http2.FramePing
case 7:
return http2.FrameGoAway
case 8:
return http2.FrameWindowUpdate
case 9:
return http2.FrameContinuation
}
return http2.FrameData
}
func ConvertFrameTypeNewFromFuzz(a []FrameTypeEnum) []http2.FrameType{
r := make([]http2.FrameType, len(a))
for i := range a {
r[i] = FrameTypeNewFromFuzz(a[i])
}
return r
}
func FlagsNewFromFuzz(p FlagsEnum) http2.Flags{
switch p {
case 1:
return http2.FlagDataPadded
case 2:
return http2.FlagHeadersEndStream
case 3:
return http2.FlagHeadersEndHeaders
case 4:
return http2.FlagHeadersPadded
case 5:
return http2.FlagHeadersPriority
case 6:
return http2.FlagSettingsAck
case 7:
return http2.FlagPingAck
case 8:
return http2.FlagContinuationEndHeaders
case 9:
return http2.FlagPushPromiseEndHeaders
case 10:
return http2.FlagPushPromisePadded
}
return http2.FlagDataEndStream
}
func ConvertFlagsNewFromFuzz(a []FlagsEnum) []http2.Flags{
r := make([]http2.Flags, len(a))
for i := range a {
r[i] = FlagsNewFromFuzz(a[i])
}
return r
}
func ErrCodeNewFromFuzz(p ErrCodeEnum) http2.ErrCode{
switch p {
case 1:
return http2.ErrCodeProtocol
case 2:
return http2.ErrCodeInternal
case 3:
return http2.ErrCodeFlowControl
case 4:
return http2.ErrCodeSettingsTimeout
case 5:
return http2.ErrCodeStreamClosed
case 6:
return http2.ErrCodeFrameSize
case 7:
return http2.ErrCodeRefusedStream
case 8:
return http2.ErrCodeCancel
case 9:
return http2.ErrCodeCompression
case 10:
return http2.ErrCodeConnect
case 11:
return http2.ErrCodeEnhanceYourCalm
case 12:
return http2.ErrCodeInadequateSecurity
case 13:
return http2.ErrCodeHTTP11Required
}
return http2.ErrCodeNo
}
func ConvertErrCodeNewFromFuzz(a []ErrCodeEnum) []http2.ErrCode{
r := make([]http2.ErrCode, len(a))
for i := range a {
r[i] = ErrCodeNewFromFuzz(a[i])
}
return r
}
func PriorityParamNewFromFuzz(p *PriorityParamStruct) *http2.PriorityParam{
if p == nil {
return nil
}
return &http2.PriorityParam{
StreamDep: p.StreamDep,
Exclusive: p.Exclusive,
Weight: uint8(p.Weight),
}
}
func PriorityWriteSchedulerConfigNewFromFuzz(p *PriorityWriteSchedulerConfigStruct) *http2.PriorityWriteSchedulerConfig{
if p == nil {
return nil
}
return &http2.PriorityWriteSchedulerConfig{
MaxClosedNodesInTree: int(p.MaxClosedNodesInTree),
MaxIdleNodesInTree: int(p.MaxIdleNodesInTree),
ThrottleOutOfOrderWrites: p.ThrottleOutOfOrderWrites,
}
}
func GoAwayFrameNewFromFuzz(p *GoAwayFrameStruct) *http2.GoAwayFrame{
if p == nil {
return nil
}
return &http2.GoAwayFrame{
LastStreamID: p.LastStreamID,
ErrCode: ErrCodeNewFromFuzz(p.ErrCode),
}
}
func PushPromiseParamNewFromFuzz(p *PushPromiseParamStruct) *http2.PushPromiseParam{
if p == nil {
return nil
}
return &http2.PushPromiseParam{
StreamID: p.StreamID,
PromiseID: p.PromiseID,
BlockFragment: p.BlockFragment,
EndHeaders: p.EndHeaders,
PadLength: uint8(p.PadLength),
}
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var FrameHeaderResults []*http2.FrameHeader
FrameHeaderResultsIndex := 0
var FrameWriteRequestResults []*http2.FrameWriteRequest
FrameWriteRequestResultsIndex := 0
var SettingResults []*http2.Setting
SettingResultsIndex := 0
var ClientConnResults []*http2.ClientConn
ClientConnResultsIndex := 0
var TransportResults []*http2.Transport
TransportResultsIndex := 0
var FramerResults []*http2.Framer
FramerResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_ErrCodeNgdotString:
arg0 := ErrCodeNewFromFuzz(a.ErrCodeNgdotString.E)
arg0.String()
case *NgoloFuzzOne_FrameTypeNgdotString:
arg0 := FrameTypeNewFromFuzz(a.FrameTypeNgdotString.T)
arg0.String()
case *NgoloFuzzOne_FlagsNgdotHas:
arg0 := FlagsNewFromFuzz(a.FlagsNgdotHas.F)
arg1 := FlagsNewFromFuzz(a.FlagsNgdotHas.V)
arg0.Has(arg1)
case *NgoloFuzzOne_FrameHeaderNgdotHeader:
if len(FrameHeaderResults) == 0 {
continue
}
arg0 := FrameHeaderResults[FrameHeaderResultsIndex]
FrameHeaderResultsIndex = (FrameHeaderResultsIndex + 1) % len(FrameHeaderResults)
arg0.Header()
case *NgoloFuzzOne_FrameHeaderNgdotString:
if len(FrameHeaderResults) == 0 {
continue
}
arg0 := FrameHeaderResults[FrameHeaderResultsIndex]
FrameHeaderResultsIndex = (FrameHeaderResultsIndex + 1) % len(FrameHeaderResults)
arg0.String()
case *NgoloFuzzOne_ReadFrameHeader:
arg0 := bytes.NewReader(a.ReadFrameHeader.R)
_, r1 := http2.ReadFrameHeader(arg0)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_FramerNgdotSetReuseFrames:
if len(FramerResults) == 0 {
continue
}
arg0 := FramerResults[FramerResultsIndex]
FramerResultsIndex = (FramerResultsIndex + 1) % len(FramerResults)
arg0.SetReuseFrames()
case *NgoloFuzzOne_NewFramer:
arg0 := bytes.NewBuffer(a.NewFramer.W)
arg1 := bytes.NewReader(a.NewFramer.R)
r0 := http2.NewFramer(arg0, arg1)
if r0 != nil{
FramerResults = append(FramerResults, r0)
}
case *NgoloFuzzOne_FramerNgdotSetMaxReadFrameSize:
if len(FramerResults) == 0 {
continue
}
arg0 := FramerResults[FramerResultsIndex]
FramerResultsIndex = (FramerResultsIndex + 1) % len(FramerResults)
arg0.SetMaxReadFrameSize(a.FramerNgdotSetMaxReadFrameSize.V)
case *NgoloFuzzOne_FramerNgdotErrorDetail:
if len(FramerResults) == 0 {
continue
}
arg0 := FramerResults[FramerResultsIndex]
FramerResultsIndex = (FramerResultsIndex + 1) % len(FramerResults)
r0 := arg0.ErrorDetail()
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_FramerNgdotReadFrameHeader:
if len(FramerResults) == 0 {
continue
}
arg0 := FramerResults[FramerResultsIndex]
FramerResultsIndex = (FramerResultsIndex + 1) % len(FramerResults)
_, r1 := arg0.ReadFrameHeader()
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_FramerNgdotReadFrameForHeader:
if len(FramerResults) == 0 {
continue
}
arg0 := FramerResults[FramerResultsIndex]
FramerResultsIndex = (FramerResultsIndex + 1) % len(FramerResults)
if len(FrameHeaderResults) == 0 {
continue
}
arg1 := *FrameHeaderResults[FrameHeaderResultsIndex]
FrameHeaderResultsIndex = (FrameHeaderResultsIndex + 1) % len(FrameHeaderResults)
_, r1 := arg0.ReadFrameForHeader(arg1)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_FramerNgdotReadFrame:
if len(FramerResults) == 0 {
continue
}
arg0 := FramerResults[FramerResultsIndex]
FramerResultsIndex = (FramerResultsIndex + 1) % len(FramerResults)
_, r1 := arg0.ReadFrame()
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_FramerNgdotWriteData:
if len(FramerResults) == 0 {
continue
}
arg0 := FramerResults[FramerResultsIndex]
FramerResultsIndex = (FramerResultsIndex + 1) % len(FramerResults)
r0 := arg0.WriteData(a.FramerNgdotWriteData.StreamID, a.FramerNgdotWriteData.EndStream, a.FramerNgdotWriteData.Data)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_FramerNgdotWriteDataPadded:
if len(FramerResults) == 0 {
continue
}
arg0 := FramerResults[FramerResultsIndex]
FramerResultsIndex = (FramerResultsIndex + 1) % len(FramerResults)
r0 := arg0.WriteDataPadded(a.FramerNgdotWriteDataPadded.StreamID, a.FramerNgdotWriteDataPadded.EndStream, a.FramerNgdotWriteDataPadded.Data, a.FramerNgdotWriteDataPadded.Pad)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_FramerNgdotWriteSettingsAck:
if len(FramerResults) == 0 {
continue
}
arg0 := FramerResults[FramerResultsIndex]
FramerResultsIndex = (FramerResultsIndex + 1) % len(FramerResults)
r0 := arg0.WriteSettingsAck()
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_GoAwayFrameNgdotDebugData:
arg0 := GoAwayFrameNewFromFuzz(a.GoAwayFrameNgdotDebugData.F)
if arg0 == nil {
continue
}
arg0.DebugData()
case *NgoloFuzzOne_FramerNgdotWriteGoAway:
if len(FramerResults) == 0 {
continue
}
arg0 := FramerResults[FramerResultsIndex]
FramerResultsIndex = (FramerResultsIndex + 1) % len(FramerResults)
arg2 := ErrCodeNewFromFuzz(a.FramerNgdotWriteGoAway.Code)
r0 := arg0.WriteGoAway(a.FramerNgdotWriteGoAway.MaxStreamID, arg2, a.FramerNgdotWriteGoAway.DebugData)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_FramerNgdotWriteWindowUpdate:
if len(FramerResults) == 0 {
continue
}
arg0 := FramerResults[FramerResultsIndex]
FramerResultsIndex = (FramerResultsIndex + 1) % len(FramerResults)
r0 := arg0.WriteWindowUpdate(a.FramerNgdotWriteWindowUpdate.StreamID, a.FramerNgdotWriteWindowUpdate.Incr)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_PriorityParamNgdotIsZero:
arg0 := PriorityParamNewFromFuzz(a.PriorityParamNgdotIsZero.P)
if arg0 == nil {
continue
}
arg0.IsZero()
case *NgoloFuzzOne_FramerNgdotWriteRSTStream:
if len(FramerResults) == 0 {
continue
}
arg0 := FramerResults[FramerResultsIndex]
FramerResultsIndex = (FramerResultsIndex + 1) % len(FramerResults)
arg2 := ErrCodeNewFromFuzz(a.FramerNgdotWriteRSTStream.Code)
r0 := arg0.WriteRSTStream(a.FramerNgdotWriteRSTStream.StreamID, arg2)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_FramerNgdotWriteContinuation:
if len(FramerResults) == 0 {
continue
}
arg0 := FramerResults[FramerResultsIndex]
FramerResultsIndex = (FramerResultsIndex + 1) % len(FramerResults)
r0 := arg0.WriteContinuation(a.FramerNgdotWriteContinuation.StreamID, a.FramerNgdotWriteContinuation.EndHeaders, a.FramerNgdotWriteContinuation.HeaderBlockFragment)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_FramerNgdotWriteRawFrame:
if len(FramerResults) == 0 {
continue
}
arg0 := FramerResults[FramerResultsIndex]
FramerResultsIndex = (FramerResultsIndex + 1) % len(FramerResults)
arg1 := FrameTypeNewFromFuzz(a.FramerNgdotWriteRawFrame.T)
arg2 := FlagsNewFromFuzz(a.FramerNgdotWriteRawFrame.Flags)
r0 := arg0.WriteRawFrame(arg1, arg2, a.FramerNgdotWriteRawFrame.StreamID, a.FramerNgdotWriteRawFrame.Payload)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_SettingNgdotString:
if len(SettingResults) == 0 {
continue
}
arg0 := SettingResults[SettingResultsIndex]
SettingResultsIndex = (SettingResultsIndex + 1) % len(SettingResults)
arg0.String()
case *NgoloFuzzOne_SettingNgdotValid:
if len(SettingResults) == 0 {
continue
}
arg0 := SettingResults[SettingResultsIndex]
SettingResultsIndex = (SettingResultsIndex + 1) % len(SettingResults)
r0 := arg0.Valid()
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_SettingIDNgdotString:
arg0 := SettingIDNewFromFuzz(a.SettingIDNgdotString.S)
arg0.String()
case *NgoloFuzzOne_TransportNgdotCloseIdleConnections:
if len(TransportResults) == 0 {
continue
}
arg0 := TransportResults[TransportResultsIndex]
TransportResultsIndex = (TransportResultsIndex + 1) % len(TransportResults)
arg0.CloseIdleConnections()
case *NgoloFuzzOne_TransportNgdotNewClientConn:
if len(TransportResults) == 0 {
continue
}
arg0 := TransportResults[TransportResultsIndex]
TransportResultsIndex = (TransportResultsIndex + 1) % len(TransportResults)
arg1 := CreateFuzzingConn(a.TransportNgdotNewClientConn.C)
r0, r1 := arg0.NewClientConn(arg1)
if r0 != nil{
ClientConnResults = append(ClientConnResults, r0)
}
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_ClientConnNgdotSetDoNotReuse:
if len(ClientConnResults) == 0 {
continue
}
arg0 := ClientConnResults[ClientConnResultsIndex]
ClientConnResultsIndex = (ClientConnResultsIndex + 1) % len(ClientConnResults)
arg0.SetDoNotReuse()
case *NgoloFuzzOne_ClientConnNgdotCanTakeNewRequest:
if len(ClientConnResults) == 0 {
continue
}
arg0 := ClientConnResults[ClientConnResultsIndex]
ClientConnResultsIndex = (ClientConnResultsIndex + 1) % len(ClientConnResults)
arg0.CanTakeNewRequest()
case *NgoloFuzzOne_ClientConnNgdotReserveNewRequest:
if len(ClientConnResults) == 0 {
continue
}
arg0 := ClientConnResults[ClientConnResultsIndex]
ClientConnResultsIndex = (ClientConnResultsIndex + 1) % len(ClientConnResults)
arg0.ReserveNewRequest()
case *NgoloFuzzOne_ClientConnNgdotState:
if len(ClientConnResults) == 0 {
continue
}
arg0 := ClientConnResults[ClientConnResultsIndex]
ClientConnResultsIndex = (ClientConnResultsIndex + 1) % len(ClientConnResults)
arg0.State()
case *NgoloFuzzOne_ClientConnNgdotClose:
if len(ClientConnResults) == 0 {
continue
}
arg0 := ClientConnResults[ClientConnResultsIndex]
ClientConnResultsIndex = (ClientConnResultsIndex + 1) % len(ClientConnResults)
r0 := arg0.Close()
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_FrameWriteRequestNgdotStreamID:
if len(FrameWriteRequestResults) == 0 {
continue
}
arg0 := FrameWriteRequestResults[FrameWriteRequestResultsIndex]
FrameWriteRequestResultsIndex = (FrameWriteRequestResultsIndex + 1) % len(FrameWriteRequestResults)
arg0.StreamID()
case *NgoloFuzzOne_FrameWriteRequestNgdotDataSize:
if len(FrameWriteRequestResults) == 0 {
continue
}
arg0 := FrameWriteRequestResults[FrameWriteRequestResultsIndex]
FrameWriteRequestResultsIndex = (FrameWriteRequestResultsIndex + 1) % len(FrameWriteRequestResults)
arg0.DataSize()
case *NgoloFuzzOne_FrameWriteRequestNgdotConsume:
if len(FrameWriteRequestResults) == 0 {
continue
}
arg0 := FrameWriteRequestResults[FrameWriteRequestResultsIndex]
FrameWriteRequestResultsIndex = (FrameWriteRequestResultsIndex + 1) % len(FrameWriteRequestResults)
r0, r1, _ := arg0.Consume(a.FrameWriteRequestNgdotConsume.N)
FrameWriteRequestResults = append(FrameWriteRequestResults, &r0)
FrameWriteRequestResults = append(FrameWriteRequestResults, &r1)
case *NgoloFuzzOne_FrameWriteRequestNgdotString:
if len(FrameWriteRequestResults) == 0 {
continue
}
arg0 := FrameWriteRequestResults[FrameWriteRequestResultsIndex]
FrameWriteRequestResultsIndex = (FrameWriteRequestResultsIndex + 1) % len(FrameWriteRequestResults)
arg0.String()
case *NgoloFuzzOne_NewRandomWriteScheduler:
http2.NewRandomWriteScheduler()
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
FrameHeaderNb := 0
FrameHeaderResultsIndex := 0
FrameWriteRequestNb := 0
FrameWriteRequestResultsIndex := 0
SettingNb := 0
SettingResultsIndex := 0
ClientConnNb := 0
ClientConnResultsIndex := 0
TransportNb := 0
TransportResultsIndex := 0
FramerNb := 0
FramerResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_ErrCodeNgdotString:
w.WriteString(fmt.Sprintf("ErrCodeNewFromFuzz(%#+v).String()\n", a.ErrCodeNgdotString.E))
case *NgoloFuzzOne_FrameTypeNgdotString:
w.WriteString(fmt.Sprintf("FrameTypeNewFromFuzz(%#+v).String()\n", a.FrameTypeNgdotString.T))
case *NgoloFuzzOne_FlagsNgdotHas:
w.WriteString(fmt.Sprintf("FlagsNewFromFuzz(%#+v).Has(FlagsNewFromFuzz(%#+v))\n", a.FlagsNgdotHas.F, a.FlagsNgdotHas.V))
case *NgoloFuzzOne_FrameHeaderNgdotHeader:
if FrameHeaderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("FrameHeader%d.Header()\n", FrameHeaderResultsIndex))
FrameHeaderResultsIndex = (FrameHeaderResultsIndex + 1) % FrameHeaderNb
case *NgoloFuzzOne_FrameHeaderNgdotString:
if FrameHeaderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("FrameHeader%d.String()\n", FrameHeaderResultsIndex))
FrameHeaderResultsIndex = (FrameHeaderResultsIndex + 1) % FrameHeaderNb
case *NgoloFuzzOne_ReadFrameHeader:
w.WriteString(fmt.Sprintf("http2.ReadFrameHeader(bytes.NewReader(%#+v))\n", a.ReadFrameHeader.R))
case *NgoloFuzzOne_FramerNgdotSetReuseFrames:
if FramerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Framer%d.SetReuseFrames()\n", FramerResultsIndex))
FramerResultsIndex = (FramerResultsIndex + 1) % FramerNb
case *NgoloFuzzOne_NewFramer:
w.WriteString(fmt.Sprintf("Framer%d := http2.NewFramer(bytes.NewBuffer(%#+v), bytes.NewReader(%#+v))\n", FramerNb, a.NewFramer.W, a.NewFramer.R))
FramerNb = FramerNb + 1
case *NgoloFuzzOne_FramerNgdotSetMaxReadFrameSize:
if FramerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Framer%d.SetMaxReadFrameSize(%#+v)\n", FramerResultsIndex, a.FramerNgdotSetMaxReadFrameSize.V))
FramerResultsIndex = (FramerResultsIndex + 1) % FramerNb
case *NgoloFuzzOne_FramerNgdotErrorDetail:
if FramerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Framer%d.ErrorDetail()\n", FramerResultsIndex))
FramerResultsIndex = (FramerResultsIndex + 1) % FramerNb
case *NgoloFuzzOne_FramerNgdotReadFrameHeader:
if FramerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Framer%d.ReadFrameHeader()\n", FramerResultsIndex))
FramerResultsIndex = (FramerResultsIndex + 1) % FramerNb
case *NgoloFuzzOne_FramerNgdotReadFrameForHeader:
if FramerNb == 0 {
continue
}
if FrameHeaderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Framer%d.ReadFrameForHeader(FrameHeader%d)\n", FramerResultsIndex, (FrameHeaderResultsIndex + 0) % FrameHeaderNb))
FramerResultsIndex = (FramerResultsIndex + 1) % FramerNb
FrameHeaderResultsIndex = (FrameHeaderResultsIndex + 1) % FrameHeaderNb
case *NgoloFuzzOne_FramerNgdotReadFrame:
if FramerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Framer%d.ReadFrame()\n", FramerResultsIndex))
FramerResultsIndex = (FramerResultsIndex + 1) % FramerNb
case *NgoloFuzzOne_FramerNgdotWriteData:
if FramerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Framer%d.WriteData(%#+v, %#+v, %#+v)\n", FramerResultsIndex, a.FramerNgdotWriteData.StreamID, a.FramerNgdotWriteData.EndStream, a.FramerNgdotWriteData.Data))
FramerResultsIndex = (FramerResultsIndex + 1) % FramerNb
case *NgoloFuzzOne_FramerNgdotWriteDataPadded:
if FramerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Framer%d.WriteDataPadded(%#+v, %#+v, %#+v, %#+v)\n", FramerResultsIndex, a.FramerNgdotWriteDataPadded.StreamID, a.FramerNgdotWriteDataPadded.EndStream, a.FramerNgdotWriteDataPadded.Data, a.FramerNgdotWriteDataPadded.Pad))
FramerResultsIndex = (FramerResultsIndex + 1) % FramerNb
case *NgoloFuzzOne_FramerNgdotWriteSettingsAck:
if FramerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Framer%d.WriteSettingsAck()\n", FramerResultsIndex))
FramerResultsIndex = (FramerResultsIndex + 1) % FramerNb
case *NgoloFuzzOne_GoAwayFrameNgdotDebugData:
w.WriteString(fmt.Sprintf("GoAwayFrameNewFromFuzz(%#+v).DebugData()\n", a.GoAwayFrameNgdotDebugData.F))
case *NgoloFuzzOne_FramerNgdotWriteGoAway:
if FramerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Framer%d.WriteGoAway(%#+v, ErrCodeNewFromFuzz(%#+v), %#+v)\n", FramerResultsIndex, a.FramerNgdotWriteGoAway.MaxStreamID, a.FramerNgdotWriteGoAway.Code, a.FramerNgdotWriteGoAway.DebugData))
FramerResultsIndex = (FramerResultsIndex + 1) % FramerNb
case *NgoloFuzzOne_FramerNgdotWriteWindowUpdate:
if FramerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Framer%d.WriteWindowUpdate(%#+v, %#+v)\n", FramerResultsIndex, a.FramerNgdotWriteWindowUpdate.StreamID, a.FramerNgdotWriteWindowUpdate.Incr))
FramerResultsIndex = (FramerResultsIndex + 1) % FramerNb
case *NgoloFuzzOne_PriorityParamNgdotIsZero:
w.WriteString(fmt.Sprintf("PriorityParamNewFromFuzz(%#+v).IsZero()\n", a.PriorityParamNgdotIsZero.P))
case *NgoloFuzzOne_FramerNgdotWriteRSTStream:
if FramerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Framer%d.WriteRSTStream(%#+v, ErrCodeNewFromFuzz(%#+v))\n", FramerResultsIndex, a.FramerNgdotWriteRSTStream.StreamID, a.FramerNgdotWriteRSTStream.Code))
FramerResultsIndex = (FramerResultsIndex + 1) % FramerNb
case *NgoloFuzzOne_FramerNgdotWriteContinuation:
if FramerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Framer%d.WriteContinuation(%#+v, %#+v, %#+v)\n", FramerResultsIndex, a.FramerNgdotWriteContinuation.StreamID, a.FramerNgdotWriteContinuation.EndHeaders, a.FramerNgdotWriteContinuation.HeaderBlockFragment))
FramerResultsIndex = (FramerResultsIndex + 1) % FramerNb
case *NgoloFuzzOne_FramerNgdotWriteRawFrame:
if FramerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Framer%d.WriteRawFrame(FrameTypeNewFromFuzz(%#+v), FlagsNewFromFuzz(%#+v), %#+v, %#+v)\n", FramerResultsIndex, a.FramerNgdotWriteRawFrame.T, a.FramerNgdotWriteRawFrame.Flags, a.FramerNgdotWriteRawFrame.StreamID, a.FramerNgdotWriteRawFrame.Payload))
FramerResultsIndex = (FramerResultsIndex + 1) % FramerNb
case *NgoloFuzzOne_SettingNgdotString:
if SettingNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Setting%d.String()\n", SettingResultsIndex))
SettingResultsIndex = (SettingResultsIndex + 1) % SettingNb
case *NgoloFuzzOne_SettingNgdotValid:
if SettingNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Setting%d.Valid()\n", SettingResultsIndex))
SettingResultsIndex = (SettingResultsIndex + 1) % SettingNb
case *NgoloFuzzOne_SettingIDNgdotString:
w.WriteString(fmt.Sprintf("SettingIDNewFromFuzz(%#+v).String()\n", a.SettingIDNgdotString.S))
case *NgoloFuzzOne_TransportNgdotCloseIdleConnections:
if TransportNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Transport%d.CloseIdleConnections()\n", TransportResultsIndex))
TransportResultsIndex = (TransportResultsIndex + 1) % TransportNb
case *NgoloFuzzOne_TransportNgdotNewClientConn:
if TransportNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("ClientConn%d, _ := Transport%d.NewClientConn(CreateFuzzingConn(%#+v))\n", ClientConnNb, TransportResultsIndex, a.TransportNgdotNewClientConn.C))
ClientConnNb = ClientConnNb + 1
TransportResultsIndex = (TransportResultsIndex + 1) % TransportNb
case *NgoloFuzzOne_ClientConnNgdotSetDoNotReuse:
if ClientConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("ClientConn%d.SetDoNotReuse()\n", ClientConnResultsIndex))
ClientConnResultsIndex = (ClientConnResultsIndex + 1) % ClientConnNb
case *NgoloFuzzOne_ClientConnNgdotCanTakeNewRequest:
if ClientConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("ClientConn%d.CanTakeNewRequest()\n", ClientConnResultsIndex))
ClientConnResultsIndex = (ClientConnResultsIndex + 1) % ClientConnNb
case *NgoloFuzzOne_ClientConnNgdotReserveNewRequest:
if ClientConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("ClientConn%d.ReserveNewRequest()\n", ClientConnResultsIndex))
ClientConnResultsIndex = (ClientConnResultsIndex + 1) % ClientConnNb
case *NgoloFuzzOne_ClientConnNgdotState:
if ClientConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("ClientConn%d.State()\n", ClientConnResultsIndex))
ClientConnResultsIndex = (ClientConnResultsIndex + 1) % ClientConnNb
case *NgoloFuzzOne_ClientConnNgdotClose:
if ClientConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("ClientConn%d.Close()\n", ClientConnResultsIndex))
ClientConnResultsIndex = (ClientConnResultsIndex + 1) % ClientConnNb
case *NgoloFuzzOne_FrameWriteRequestNgdotStreamID:
if FrameWriteRequestNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("FrameWriteRequest%d.StreamID()\n", FrameWriteRequestResultsIndex))
FrameWriteRequestResultsIndex = (FrameWriteRequestResultsIndex + 1) % FrameWriteRequestNb
case *NgoloFuzzOne_FrameWriteRequestNgdotDataSize:
if FrameWriteRequestNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("FrameWriteRequest%d.DataSize()\n", FrameWriteRequestResultsIndex))
FrameWriteRequestResultsIndex = (FrameWriteRequestResultsIndex + 1) % FrameWriteRequestNb
case *NgoloFuzzOne_FrameWriteRequestNgdotConsume:
if FrameWriteRequestNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("FrameWriteRequest%d, FrameWriteRequest%d, _ := FrameWriteRequest%d.Consume(%#+v)\n", FrameWriteRequestNb, FrameWriteRequestNb, FrameWriteRequestResultsIndex, a.FrameWriteRequestNgdotConsume.N))
FrameWriteRequestNb = FrameWriteRequestNb + 1
FrameWriteRequestNb = FrameWriteRequestNb + 1
FrameWriteRequestResultsIndex = (FrameWriteRequestResultsIndex + 1) % FrameWriteRequestNb
case *NgoloFuzzOne_FrameWriteRequestNgdotString:
if FrameWriteRequestNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("FrameWriteRequest%d.String()\n", FrameWriteRequestResultsIndex))
FrameWriteRequestResultsIndex = (FrameWriteRequestResultsIndex + 1) % FrameWriteRequestNb
case *NgoloFuzzOne_NewRandomWriteScheduler:
w.WriteString(fmt.Sprintf("http2.NewRandomWriteScheduler()\n"))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_net_http2
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type SettingIDEnum int32
const (
SettingIDEnum_SettingHeaderTableSize SettingIDEnum = 0
SettingIDEnum_SettingEnablePush SettingIDEnum = 1
SettingIDEnum_SettingMaxConcurrentStreams SettingIDEnum = 2
SettingIDEnum_SettingInitialWindowSize SettingIDEnum = 3
SettingIDEnum_SettingMaxFrameSize SettingIDEnum = 4
SettingIDEnum_SettingMaxHeaderListSize SettingIDEnum = 5
SettingIDEnum_SettingEnableConnectProtocol SettingIDEnum = 6
)
// Enum value maps for SettingIDEnum.
var (
SettingIDEnum_name = map[int32]string{
0: "SettingHeaderTableSize",
1: "SettingEnablePush",
2: "SettingMaxConcurrentStreams",
3: "SettingInitialWindowSize",
4: "SettingMaxFrameSize",
5: "SettingMaxHeaderListSize",
6: "SettingEnableConnectProtocol",
}
SettingIDEnum_value = map[string]int32{
"SettingHeaderTableSize": 0,
"SettingEnablePush": 1,
"SettingMaxConcurrentStreams": 2,
"SettingInitialWindowSize": 3,
"SettingMaxFrameSize": 4,
"SettingMaxHeaderListSize": 5,
"SettingEnableConnectProtocol": 6,
}
)
func (x SettingIDEnum) Enum() *SettingIDEnum {
p := new(SettingIDEnum)
*p = x
return p
}
func (x SettingIDEnum) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (SettingIDEnum) Descriptor() protoreflect.EnumDescriptor {
return file_ngolofuzz_proto_enumTypes[0].Descriptor()
}
func (SettingIDEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[0]
}
func (x SettingIDEnum) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use SettingIDEnum.Descriptor instead.
func (SettingIDEnum) EnumDescriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type FrameTypeEnum int32
const (
FrameTypeEnum_FrameData FrameTypeEnum = 0
FrameTypeEnum_FrameHeaders FrameTypeEnum = 1
FrameTypeEnum_FramePriority FrameTypeEnum = 2
FrameTypeEnum_FrameRSTStream FrameTypeEnum = 3
FrameTypeEnum_FrameSettings FrameTypeEnum = 4
FrameTypeEnum_FramePushPromise FrameTypeEnum = 5
FrameTypeEnum_FramePing FrameTypeEnum = 6
FrameTypeEnum_FrameGoAway FrameTypeEnum = 7
FrameTypeEnum_FrameWindowUpdate FrameTypeEnum = 8
FrameTypeEnum_FrameContinuation FrameTypeEnum = 9
)
// Enum value maps for FrameTypeEnum.
var (
FrameTypeEnum_name = map[int32]string{
0: "FrameData",
1: "FrameHeaders",
2: "FramePriority",
3: "FrameRSTStream",
4: "FrameSettings",
5: "FramePushPromise",
6: "FramePing",
7: "FrameGoAway",
8: "FrameWindowUpdate",
9: "FrameContinuation",
}
FrameTypeEnum_value = map[string]int32{
"FrameData": 0,
"FrameHeaders": 1,
"FramePriority": 2,
"FrameRSTStream": 3,
"FrameSettings": 4,
"FramePushPromise": 5,
"FramePing": 6,
"FrameGoAway": 7,
"FrameWindowUpdate": 8,
"FrameContinuation": 9,
}
)
func (x FrameTypeEnum) Enum() *FrameTypeEnum {
p := new(FrameTypeEnum)
*p = x
return p
}
func (x FrameTypeEnum) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (FrameTypeEnum) Descriptor() protoreflect.EnumDescriptor {
return file_ngolofuzz_proto_enumTypes[1].Descriptor()
}
func (FrameTypeEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[1]
}
func (x FrameTypeEnum) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use FrameTypeEnum.Descriptor instead.
func (FrameTypeEnum) EnumDescriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
type FlagsEnum int32
const (
FlagsEnum_FlagDataEndStream FlagsEnum = 0
FlagsEnum_FlagDataPadded FlagsEnum = 1
FlagsEnum_FlagHeadersEndStream FlagsEnum = 2
FlagsEnum_FlagHeadersEndHeaders FlagsEnum = 3
FlagsEnum_FlagHeadersPadded FlagsEnum = 4
FlagsEnum_FlagHeadersPriority FlagsEnum = 5
FlagsEnum_FlagSettingsAck FlagsEnum = 6
FlagsEnum_FlagPingAck FlagsEnum = 7
FlagsEnum_FlagContinuationEndHeaders FlagsEnum = 8
FlagsEnum_FlagPushPromiseEndHeaders FlagsEnum = 9
FlagsEnum_FlagPushPromisePadded FlagsEnum = 10
)
// Enum value maps for FlagsEnum.
var (
FlagsEnum_name = map[int32]string{
0: "FlagDataEndStream",
1: "FlagDataPadded",
2: "FlagHeadersEndStream",
3: "FlagHeadersEndHeaders",
4: "FlagHeadersPadded",
5: "FlagHeadersPriority",
6: "FlagSettingsAck",
7: "FlagPingAck",
8: "FlagContinuationEndHeaders",
9: "FlagPushPromiseEndHeaders",
10: "FlagPushPromisePadded",
}
FlagsEnum_value = map[string]int32{
"FlagDataEndStream": 0,
"FlagDataPadded": 1,
"FlagHeadersEndStream": 2,
"FlagHeadersEndHeaders": 3,
"FlagHeadersPadded": 4,
"FlagHeadersPriority": 5,
"FlagSettingsAck": 6,
"FlagPingAck": 7,
"FlagContinuationEndHeaders": 8,
"FlagPushPromiseEndHeaders": 9,
"FlagPushPromisePadded": 10,
}
)
func (x FlagsEnum) Enum() *FlagsEnum {
p := new(FlagsEnum)
*p = x
return p
}
func (x FlagsEnum) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (FlagsEnum) Descriptor() protoreflect.EnumDescriptor {
return file_ngolofuzz_proto_enumTypes[2].Descriptor()
}
func (FlagsEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[2]
}
func (x FlagsEnum) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use FlagsEnum.Descriptor instead.
func (FlagsEnum) EnumDescriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
type ErrCodeEnum int32
const (
ErrCodeEnum_ErrCodeNo ErrCodeEnum = 0
ErrCodeEnum_ErrCodeProtocol ErrCodeEnum = 1
ErrCodeEnum_ErrCodeInternal ErrCodeEnum = 2
ErrCodeEnum_ErrCodeFlowControl ErrCodeEnum = 3
ErrCodeEnum_ErrCodeSettingsTimeout ErrCodeEnum = 4
ErrCodeEnum_ErrCodeStreamClosed ErrCodeEnum = 5
ErrCodeEnum_ErrCodeFrameSize ErrCodeEnum = 6
ErrCodeEnum_ErrCodeRefusedStream ErrCodeEnum = 7
ErrCodeEnum_ErrCodeCancel ErrCodeEnum = 8
ErrCodeEnum_ErrCodeCompression ErrCodeEnum = 9
ErrCodeEnum_ErrCodeConnect ErrCodeEnum = 10
ErrCodeEnum_ErrCodeEnhanceYourCalm ErrCodeEnum = 11
ErrCodeEnum_ErrCodeInadequateSecurity ErrCodeEnum = 12
ErrCodeEnum_ErrCodeHTTP11Required ErrCodeEnum = 13
)
// Enum value maps for ErrCodeEnum.
var (
ErrCodeEnum_name = map[int32]string{
0: "ErrCodeNo",
1: "ErrCodeProtocol",
2: "ErrCodeInternal",
3: "ErrCodeFlowControl",
4: "ErrCodeSettingsTimeout",
5: "ErrCodeStreamClosed",
6: "ErrCodeFrameSize",
7: "ErrCodeRefusedStream",
8: "ErrCodeCancel",
9: "ErrCodeCompression",
10: "ErrCodeConnect",
11: "ErrCodeEnhanceYourCalm",
12: "ErrCodeInadequateSecurity",
13: "ErrCodeHTTP11Required",
}
ErrCodeEnum_value = map[string]int32{
"ErrCodeNo": 0,
"ErrCodeProtocol": 1,
"ErrCodeInternal": 2,
"ErrCodeFlowControl": 3,
"ErrCodeSettingsTimeout": 4,
"ErrCodeStreamClosed": 5,
"ErrCodeFrameSize": 6,
"ErrCodeRefusedStream": 7,
"ErrCodeCancel": 8,
"ErrCodeCompression": 9,
"ErrCodeConnect": 10,
"ErrCodeEnhanceYourCalm": 11,
"ErrCodeInadequateSecurity": 12,
"ErrCodeHTTP11Required": 13,
}
)
func (x ErrCodeEnum) Enum() *ErrCodeEnum {
p := new(ErrCodeEnum)
*p = x
return p
}
func (x ErrCodeEnum) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (ErrCodeEnum) Descriptor() protoreflect.EnumDescriptor {
return file_ngolofuzz_proto_enumTypes[3].Descriptor()
}
func (ErrCodeEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[3]
}
func (x ErrCodeEnum) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use ErrCodeEnum.Descriptor instead.
func (ErrCodeEnum) EnumDescriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
type PriorityParamStruct struct {
state protoimpl.MessageState `protogen:"open.v1"`
StreamDep uint32 `protobuf:"varint,1,opt,name=StreamDep,proto3" json:"StreamDep,omitempty"`
Exclusive bool `protobuf:"varint,2,opt,name=Exclusive,proto3" json:"Exclusive,omitempty"`
Weight uint32 `protobuf:"varint,3,opt,name=Weight,proto3" json:"Weight,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PriorityParamStruct) Reset() {
*x = PriorityParamStruct{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PriorityParamStruct) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PriorityParamStruct) ProtoMessage() {}
func (x *PriorityParamStruct) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PriorityParamStruct.ProtoReflect.Descriptor instead.
func (*PriorityParamStruct) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *PriorityParamStruct) GetStreamDep() uint32 {
if x != nil {
return x.StreamDep
}
return 0
}
func (x *PriorityParamStruct) GetExclusive() bool {
if x != nil {
return x.Exclusive
}
return false
}
func (x *PriorityParamStruct) GetWeight() uint32 {
if x != nil {
return x.Weight
}
return 0
}
type PriorityWriteSchedulerConfigStruct struct {
state protoimpl.MessageState `protogen:"open.v1"`
MaxClosedNodesInTree int64 `protobuf:"varint,1,opt,name=MaxClosedNodesInTree,proto3" json:"MaxClosedNodesInTree,omitempty"`
MaxIdleNodesInTree int64 `protobuf:"varint,2,opt,name=MaxIdleNodesInTree,proto3" json:"MaxIdleNodesInTree,omitempty"`
ThrottleOutOfOrderWrites bool `protobuf:"varint,3,opt,name=ThrottleOutOfOrderWrites,proto3" json:"ThrottleOutOfOrderWrites,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PriorityWriteSchedulerConfigStruct) Reset() {
*x = PriorityWriteSchedulerConfigStruct{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PriorityWriteSchedulerConfigStruct) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PriorityWriteSchedulerConfigStruct) ProtoMessage() {}
func (x *PriorityWriteSchedulerConfigStruct) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PriorityWriteSchedulerConfigStruct.ProtoReflect.Descriptor instead.
func (*PriorityWriteSchedulerConfigStruct) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *PriorityWriteSchedulerConfigStruct) GetMaxClosedNodesInTree() int64 {
if x != nil {
return x.MaxClosedNodesInTree
}
return 0
}
func (x *PriorityWriteSchedulerConfigStruct) GetMaxIdleNodesInTree() int64 {
if x != nil {
return x.MaxIdleNodesInTree
}
return 0
}
func (x *PriorityWriteSchedulerConfigStruct) GetThrottleOutOfOrderWrites() bool {
if x != nil {
return x.ThrottleOutOfOrderWrites
}
return false
}
type GoAwayFrameStruct struct {
state protoimpl.MessageState `protogen:"open.v1"`
LastStreamID uint32 `protobuf:"varint,1,opt,name=LastStreamID,proto3" json:"LastStreamID,omitempty"`
ErrCode ErrCodeEnum `protobuf:"varint,2,opt,name=ErrCode,proto3,enum=ngolofuzz.ErrCodeEnum" json:"ErrCode,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GoAwayFrameStruct) Reset() {
*x = GoAwayFrameStruct{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GoAwayFrameStruct) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GoAwayFrameStruct) ProtoMessage() {}
func (x *GoAwayFrameStruct) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GoAwayFrameStruct.ProtoReflect.Descriptor instead.
func (*GoAwayFrameStruct) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *GoAwayFrameStruct) GetLastStreamID() uint32 {
if x != nil {
return x.LastStreamID
}
return 0
}
func (x *GoAwayFrameStruct) GetErrCode() ErrCodeEnum {
if x != nil {
return x.ErrCode
}
return ErrCodeEnum_ErrCodeNo
}
type PushPromiseParamStruct struct {
state protoimpl.MessageState `protogen:"open.v1"`
StreamID uint32 `protobuf:"varint,1,opt,name=StreamID,proto3" json:"StreamID,omitempty"`
PromiseID uint32 `protobuf:"varint,2,opt,name=PromiseID,proto3" json:"PromiseID,omitempty"`
BlockFragment []byte `protobuf:"bytes,3,opt,name=BlockFragment,proto3" json:"BlockFragment,omitempty"`
EndHeaders bool `protobuf:"varint,4,opt,name=EndHeaders,proto3" json:"EndHeaders,omitempty"`
PadLength uint32 `protobuf:"varint,5,opt,name=PadLength,proto3" json:"PadLength,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PushPromiseParamStruct) Reset() {
*x = PushPromiseParamStruct{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PushPromiseParamStruct) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PushPromiseParamStruct) ProtoMessage() {}
func (x *PushPromiseParamStruct) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PushPromiseParamStruct.ProtoReflect.Descriptor instead.
func (*PushPromiseParamStruct) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *PushPromiseParamStruct) GetStreamID() uint32 {
if x != nil {
return x.StreamID
}
return 0
}
func (x *PushPromiseParamStruct) GetPromiseID() uint32 {
if x != nil {
return x.PromiseID
}
return 0
}
func (x *PushPromiseParamStruct) GetBlockFragment() []byte {
if x != nil {
return x.BlockFragment
}
return nil
}
func (x *PushPromiseParamStruct) GetEndHeaders() bool {
if x != nil {
return x.EndHeaders
}
return false
}
func (x *PushPromiseParamStruct) GetPadLength() uint32 {
if x != nil {
return x.PadLength
}
return 0
}
type ErrCodeNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
E ErrCodeEnum `protobuf:"varint,1,opt,name=e,proto3,enum=ngolofuzz.ErrCodeEnum" json:"e,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ErrCodeNgdotStringArgs) Reset() {
*x = ErrCodeNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ErrCodeNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ErrCodeNgdotStringArgs) ProtoMessage() {}
func (x *ErrCodeNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ErrCodeNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*ErrCodeNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *ErrCodeNgdotStringArgs) GetE() ErrCodeEnum {
if x != nil {
return x.E
}
return ErrCodeEnum_ErrCodeNo
}
type FrameTypeNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
T FrameTypeEnum `protobuf:"varint,1,opt,name=t,proto3,enum=ngolofuzz.FrameTypeEnum" json:"t,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FrameTypeNgdotStringArgs) Reset() {
*x = FrameTypeNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FrameTypeNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FrameTypeNgdotStringArgs) ProtoMessage() {}
func (x *FrameTypeNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FrameTypeNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*FrameTypeNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *FrameTypeNgdotStringArgs) GetT() FrameTypeEnum {
if x != nil {
return x.T
}
return FrameTypeEnum_FrameData
}
type FlagsNgdotHasArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
F FlagsEnum `protobuf:"varint,1,opt,name=f,proto3,enum=ngolofuzz.FlagsEnum" json:"f,omitempty"`
V FlagsEnum `protobuf:"varint,2,opt,name=v,proto3,enum=ngolofuzz.FlagsEnum" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FlagsNgdotHasArgs) Reset() {
*x = FlagsNgdotHasArgs{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FlagsNgdotHasArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FlagsNgdotHasArgs) ProtoMessage() {}
func (x *FlagsNgdotHasArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FlagsNgdotHasArgs.ProtoReflect.Descriptor instead.
func (*FlagsNgdotHasArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *FlagsNgdotHasArgs) GetF() FlagsEnum {
if x != nil {
return x.F
}
return FlagsEnum_FlagDataEndStream
}
func (x *FlagsNgdotHasArgs) GetV() FlagsEnum {
if x != nil {
return x.V
}
return FlagsEnum_FlagDataEndStream
}
type FrameHeaderNgdotHeaderArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FrameHeaderNgdotHeaderArgs) Reset() {
*x = FrameHeaderNgdotHeaderArgs{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FrameHeaderNgdotHeaderArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FrameHeaderNgdotHeaderArgs) ProtoMessage() {}
func (x *FrameHeaderNgdotHeaderArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FrameHeaderNgdotHeaderArgs.ProtoReflect.Descriptor instead.
func (*FrameHeaderNgdotHeaderArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
type FrameHeaderNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FrameHeaderNgdotStringArgs) Reset() {
*x = FrameHeaderNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FrameHeaderNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FrameHeaderNgdotStringArgs) ProtoMessage() {}
func (x *FrameHeaderNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FrameHeaderNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*FrameHeaderNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
type ReadFrameHeaderArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R []byte `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ReadFrameHeaderArgs) Reset() {
*x = ReadFrameHeaderArgs{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ReadFrameHeaderArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReadFrameHeaderArgs) ProtoMessage() {}
func (x *ReadFrameHeaderArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReadFrameHeaderArgs.ProtoReflect.Descriptor instead.
func (*ReadFrameHeaderArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
func (x *ReadFrameHeaderArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
type FramerNgdotSetReuseFramesArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FramerNgdotSetReuseFramesArgs) Reset() {
*x = FramerNgdotSetReuseFramesArgs{}
mi := &file_ngolofuzz_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FramerNgdotSetReuseFramesArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FramerNgdotSetReuseFramesArgs) ProtoMessage() {}
func (x *FramerNgdotSetReuseFramesArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FramerNgdotSetReuseFramesArgs.ProtoReflect.Descriptor instead.
func (*FramerNgdotSetReuseFramesArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{10}
}
type NewFramerArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
W []byte `protobuf:"bytes,1,opt,name=w,proto3" json:"w,omitempty"`
R []byte `protobuf:"bytes,2,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewFramerArgs) Reset() {
*x = NewFramerArgs{}
mi := &file_ngolofuzz_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewFramerArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewFramerArgs) ProtoMessage() {}
func (x *NewFramerArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[11]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewFramerArgs.ProtoReflect.Descriptor instead.
func (*NewFramerArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{11}
}
func (x *NewFramerArgs) GetW() []byte {
if x != nil {
return x.W
}
return nil
}
func (x *NewFramerArgs) GetR() []byte {
if x != nil {
return x.R
}
return nil
}
type FramerNgdotSetMaxReadFrameSizeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
V uint32 `protobuf:"varint,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FramerNgdotSetMaxReadFrameSizeArgs) Reset() {
*x = FramerNgdotSetMaxReadFrameSizeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FramerNgdotSetMaxReadFrameSizeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FramerNgdotSetMaxReadFrameSizeArgs) ProtoMessage() {}
func (x *FramerNgdotSetMaxReadFrameSizeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[12]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FramerNgdotSetMaxReadFrameSizeArgs.ProtoReflect.Descriptor instead.
func (*FramerNgdotSetMaxReadFrameSizeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{12}
}
func (x *FramerNgdotSetMaxReadFrameSizeArgs) GetV() uint32 {
if x != nil {
return x.V
}
return 0
}
type FramerNgdotErrorDetailArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FramerNgdotErrorDetailArgs) Reset() {
*x = FramerNgdotErrorDetailArgs{}
mi := &file_ngolofuzz_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FramerNgdotErrorDetailArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FramerNgdotErrorDetailArgs) ProtoMessage() {}
func (x *FramerNgdotErrorDetailArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[13]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FramerNgdotErrorDetailArgs.ProtoReflect.Descriptor instead.
func (*FramerNgdotErrorDetailArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{13}
}
type FramerNgdotReadFrameHeaderArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FramerNgdotReadFrameHeaderArgs) Reset() {
*x = FramerNgdotReadFrameHeaderArgs{}
mi := &file_ngolofuzz_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FramerNgdotReadFrameHeaderArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FramerNgdotReadFrameHeaderArgs) ProtoMessage() {}
func (x *FramerNgdotReadFrameHeaderArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[14]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FramerNgdotReadFrameHeaderArgs.ProtoReflect.Descriptor instead.
func (*FramerNgdotReadFrameHeaderArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{14}
}
type FramerNgdotReadFrameForHeaderArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FramerNgdotReadFrameForHeaderArgs) Reset() {
*x = FramerNgdotReadFrameForHeaderArgs{}
mi := &file_ngolofuzz_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FramerNgdotReadFrameForHeaderArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FramerNgdotReadFrameForHeaderArgs) ProtoMessage() {}
func (x *FramerNgdotReadFrameForHeaderArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[15]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FramerNgdotReadFrameForHeaderArgs.ProtoReflect.Descriptor instead.
func (*FramerNgdotReadFrameForHeaderArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{15}
}
type FramerNgdotReadFrameArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FramerNgdotReadFrameArgs) Reset() {
*x = FramerNgdotReadFrameArgs{}
mi := &file_ngolofuzz_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FramerNgdotReadFrameArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FramerNgdotReadFrameArgs) ProtoMessage() {}
func (x *FramerNgdotReadFrameArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[16]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FramerNgdotReadFrameArgs.ProtoReflect.Descriptor instead.
func (*FramerNgdotReadFrameArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{16}
}
type FramerNgdotWriteDataArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
StreamID uint32 `protobuf:"varint,1,opt,name=streamID,proto3" json:"streamID,omitempty"`
EndStream bool `protobuf:"varint,2,opt,name=endStream,proto3" json:"endStream,omitempty"`
Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FramerNgdotWriteDataArgs) Reset() {
*x = FramerNgdotWriteDataArgs{}
mi := &file_ngolofuzz_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FramerNgdotWriteDataArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FramerNgdotWriteDataArgs) ProtoMessage() {}
func (x *FramerNgdotWriteDataArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[17]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FramerNgdotWriteDataArgs.ProtoReflect.Descriptor instead.
func (*FramerNgdotWriteDataArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{17}
}
func (x *FramerNgdotWriteDataArgs) GetStreamID() uint32 {
if x != nil {
return x.StreamID
}
return 0
}
func (x *FramerNgdotWriteDataArgs) GetEndStream() bool {
if x != nil {
return x.EndStream
}
return false
}
func (x *FramerNgdotWriteDataArgs) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
type FramerNgdotWriteDataPaddedArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
StreamID uint32 `protobuf:"varint,1,opt,name=streamID,proto3" json:"streamID,omitempty"`
EndStream bool `protobuf:"varint,2,opt,name=endStream,proto3" json:"endStream,omitempty"`
Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
Pad []byte `protobuf:"bytes,4,opt,name=pad,proto3" json:"pad,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FramerNgdotWriteDataPaddedArgs) Reset() {
*x = FramerNgdotWriteDataPaddedArgs{}
mi := &file_ngolofuzz_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FramerNgdotWriteDataPaddedArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FramerNgdotWriteDataPaddedArgs) ProtoMessage() {}
func (x *FramerNgdotWriteDataPaddedArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[18]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FramerNgdotWriteDataPaddedArgs.ProtoReflect.Descriptor instead.
func (*FramerNgdotWriteDataPaddedArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{18}
}
func (x *FramerNgdotWriteDataPaddedArgs) GetStreamID() uint32 {
if x != nil {
return x.StreamID
}
return 0
}
func (x *FramerNgdotWriteDataPaddedArgs) GetEndStream() bool {
if x != nil {
return x.EndStream
}
return false
}
func (x *FramerNgdotWriteDataPaddedArgs) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
func (x *FramerNgdotWriteDataPaddedArgs) GetPad() []byte {
if x != nil {
return x.Pad
}
return nil
}
type FramerNgdotWriteSettingsAckArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FramerNgdotWriteSettingsAckArgs) Reset() {
*x = FramerNgdotWriteSettingsAckArgs{}
mi := &file_ngolofuzz_proto_msgTypes[19]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FramerNgdotWriteSettingsAckArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FramerNgdotWriteSettingsAckArgs) ProtoMessage() {}
func (x *FramerNgdotWriteSettingsAckArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[19]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FramerNgdotWriteSettingsAckArgs.ProtoReflect.Descriptor instead.
func (*FramerNgdotWriteSettingsAckArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{19}
}
type GoAwayFrameNgdotDebugDataArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
F *GoAwayFrameStruct `protobuf:"bytes,1,opt,name=f,proto3" json:"f,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GoAwayFrameNgdotDebugDataArgs) Reset() {
*x = GoAwayFrameNgdotDebugDataArgs{}
mi := &file_ngolofuzz_proto_msgTypes[20]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GoAwayFrameNgdotDebugDataArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GoAwayFrameNgdotDebugDataArgs) ProtoMessage() {}
func (x *GoAwayFrameNgdotDebugDataArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[20]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GoAwayFrameNgdotDebugDataArgs.ProtoReflect.Descriptor instead.
func (*GoAwayFrameNgdotDebugDataArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{20}
}
func (x *GoAwayFrameNgdotDebugDataArgs) GetF() *GoAwayFrameStruct {
if x != nil {
return x.F
}
return nil
}
type FramerNgdotWriteGoAwayArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
MaxStreamID uint32 `protobuf:"varint,1,opt,name=maxStreamID,proto3" json:"maxStreamID,omitempty"`
Code ErrCodeEnum `protobuf:"varint,2,opt,name=code,proto3,enum=ngolofuzz.ErrCodeEnum" json:"code,omitempty"`
DebugData []byte `protobuf:"bytes,3,opt,name=debugData,proto3" json:"debugData,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FramerNgdotWriteGoAwayArgs) Reset() {
*x = FramerNgdotWriteGoAwayArgs{}
mi := &file_ngolofuzz_proto_msgTypes[21]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FramerNgdotWriteGoAwayArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FramerNgdotWriteGoAwayArgs) ProtoMessage() {}
func (x *FramerNgdotWriteGoAwayArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[21]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FramerNgdotWriteGoAwayArgs.ProtoReflect.Descriptor instead.
func (*FramerNgdotWriteGoAwayArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{21}
}
func (x *FramerNgdotWriteGoAwayArgs) GetMaxStreamID() uint32 {
if x != nil {
return x.MaxStreamID
}
return 0
}
func (x *FramerNgdotWriteGoAwayArgs) GetCode() ErrCodeEnum {
if x != nil {
return x.Code
}
return ErrCodeEnum_ErrCodeNo
}
func (x *FramerNgdotWriteGoAwayArgs) GetDebugData() []byte {
if x != nil {
return x.DebugData
}
return nil
}
type FramerNgdotWriteWindowUpdateArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
StreamID uint32 `protobuf:"varint,1,opt,name=streamID,proto3" json:"streamID,omitempty"`
Incr uint32 `protobuf:"varint,2,opt,name=incr,proto3" json:"incr,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FramerNgdotWriteWindowUpdateArgs) Reset() {
*x = FramerNgdotWriteWindowUpdateArgs{}
mi := &file_ngolofuzz_proto_msgTypes[22]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FramerNgdotWriteWindowUpdateArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FramerNgdotWriteWindowUpdateArgs) ProtoMessage() {}
func (x *FramerNgdotWriteWindowUpdateArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[22]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FramerNgdotWriteWindowUpdateArgs.ProtoReflect.Descriptor instead.
func (*FramerNgdotWriteWindowUpdateArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{22}
}
func (x *FramerNgdotWriteWindowUpdateArgs) GetStreamID() uint32 {
if x != nil {
return x.StreamID
}
return 0
}
func (x *FramerNgdotWriteWindowUpdateArgs) GetIncr() uint32 {
if x != nil {
return x.Incr
}
return 0
}
type PriorityParamNgdotIsZeroArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
P *PriorityParamStruct `protobuf:"bytes,1,opt,name=p,proto3" json:"p,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PriorityParamNgdotIsZeroArgs) Reset() {
*x = PriorityParamNgdotIsZeroArgs{}
mi := &file_ngolofuzz_proto_msgTypes[23]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PriorityParamNgdotIsZeroArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PriorityParamNgdotIsZeroArgs) ProtoMessage() {}
func (x *PriorityParamNgdotIsZeroArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[23]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PriorityParamNgdotIsZeroArgs.ProtoReflect.Descriptor instead.
func (*PriorityParamNgdotIsZeroArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{23}
}
func (x *PriorityParamNgdotIsZeroArgs) GetP() *PriorityParamStruct {
if x != nil {
return x.P
}
return nil
}
type FramerNgdotWriteRSTStreamArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
StreamID uint32 `protobuf:"varint,1,opt,name=streamID,proto3" json:"streamID,omitempty"`
Code ErrCodeEnum `protobuf:"varint,2,opt,name=code,proto3,enum=ngolofuzz.ErrCodeEnum" json:"code,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FramerNgdotWriteRSTStreamArgs) Reset() {
*x = FramerNgdotWriteRSTStreamArgs{}
mi := &file_ngolofuzz_proto_msgTypes[24]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FramerNgdotWriteRSTStreamArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FramerNgdotWriteRSTStreamArgs) ProtoMessage() {}
func (x *FramerNgdotWriteRSTStreamArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[24]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FramerNgdotWriteRSTStreamArgs.ProtoReflect.Descriptor instead.
func (*FramerNgdotWriteRSTStreamArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{24}
}
func (x *FramerNgdotWriteRSTStreamArgs) GetStreamID() uint32 {
if x != nil {
return x.StreamID
}
return 0
}
func (x *FramerNgdotWriteRSTStreamArgs) GetCode() ErrCodeEnum {
if x != nil {
return x.Code
}
return ErrCodeEnum_ErrCodeNo
}
type FramerNgdotWriteContinuationArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
StreamID uint32 `protobuf:"varint,1,opt,name=streamID,proto3" json:"streamID,omitempty"`
EndHeaders bool `protobuf:"varint,2,opt,name=endHeaders,proto3" json:"endHeaders,omitempty"`
HeaderBlockFragment []byte `protobuf:"bytes,3,opt,name=headerBlockFragment,proto3" json:"headerBlockFragment,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FramerNgdotWriteContinuationArgs) Reset() {
*x = FramerNgdotWriteContinuationArgs{}
mi := &file_ngolofuzz_proto_msgTypes[25]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FramerNgdotWriteContinuationArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FramerNgdotWriteContinuationArgs) ProtoMessage() {}
func (x *FramerNgdotWriteContinuationArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[25]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FramerNgdotWriteContinuationArgs.ProtoReflect.Descriptor instead.
func (*FramerNgdotWriteContinuationArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{25}
}
func (x *FramerNgdotWriteContinuationArgs) GetStreamID() uint32 {
if x != nil {
return x.StreamID
}
return 0
}
func (x *FramerNgdotWriteContinuationArgs) GetEndHeaders() bool {
if x != nil {
return x.EndHeaders
}
return false
}
func (x *FramerNgdotWriteContinuationArgs) GetHeaderBlockFragment() []byte {
if x != nil {
return x.HeaderBlockFragment
}
return nil
}
type FramerNgdotWriteRawFrameArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
T FrameTypeEnum `protobuf:"varint,1,opt,name=t,proto3,enum=ngolofuzz.FrameTypeEnum" json:"t,omitempty"`
Flags FlagsEnum `protobuf:"varint,2,opt,name=flags,proto3,enum=ngolofuzz.FlagsEnum" json:"flags,omitempty"`
StreamID uint32 `protobuf:"varint,3,opt,name=streamID,proto3" json:"streamID,omitempty"`
Payload []byte `protobuf:"bytes,4,opt,name=payload,proto3" json:"payload,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FramerNgdotWriteRawFrameArgs) Reset() {
*x = FramerNgdotWriteRawFrameArgs{}
mi := &file_ngolofuzz_proto_msgTypes[26]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FramerNgdotWriteRawFrameArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FramerNgdotWriteRawFrameArgs) ProtoMessage() {}
func (x *FramerNgdotWriteRawFrameArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[26]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FramerNgdotWriteRawFrameArgs.ProtoReflect.Descriptor instead.
func (*FramerNgdotWriteRawFrameArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{26}
}
func (x *FramerNgdotWriteRawFrameArgs) GetT() FrameTypeEnum {
if x != nil {
return x.T
}
return FrameTypeEnum_FrameData
}
func (x *FramerNgdotWriteRawFrameArgs) GetFlags() FlagsEnum {
if x != nil {
return x.Flags
}
return FlagsEnum_FlagDataEndStream
}
func (x *FramerNgdotWriteRawFrameArgs) GetStreamID() uint32 {
if x != nil {
return x.StreamID
}
return 0
}
func (x *FramerNgdotWriteRawFrameArgs) GetPayload() []byte {
if x != nil {
return x.Payload
}
return nil
}
type SettingNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SettingNgdotStringArgs) Reset() {
*x = SettingNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[27]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SettingNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SettingNgdotStringArgs) ProtoMessage() {}
func (x *SettingNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[27]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SettingNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*SettingNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{27}
}
type SettingNgdotValidArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SettingNgdotValidArgs) Reset() {
*x = SettingNgdotValidArgs{}
mi := &file_ngolofuzz_proto_msgTypes[28]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SettingNgdotValidArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SettingNgdotValidArgs) ProtoMessage() {}
func (x *SettingNgdotValidArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[28]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SettingNgdotValidArgs.ProtoReflect.Descriptor instead.
func (*SettingNgdotValidArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{28}
}
type SettingIDNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S SettingIDEnum `protobuf:"varint,1,opt,name=s,proto3,enum=ngolofuzz.SettingIDEnum" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SettingIDNgdotStringArgs) Reset() {
*x = SettingIDNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[29]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SettingIDNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SettingIDNgdotStringArgs) ProtoMessage() {}
func (x *SettingIDNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[29]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SettingIDNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*SettingIDNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{29}
}
func (x *SettingIDNgdotStringArgs) GetS() SettingIDEnum {
if x != nil {
return x.S
}
return SettingIDEnum_SettingHeaderTableSize
}
type TransportNgdotCloseIdleConnectionsArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TransportNgdotCloseIdleConnectionsArgs) Reset() {
*x = TransportNgdotCloseIdleConnectionsArgs{}
mi := &file_ngolofuzz_proto_msgTypes[30]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TransportNgdotCloseIdleConnectionsArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TransportNgdotCloseIdleConnectionsArgs) ProtoMessage() {}
func (x *TransportNgdotCloseIdleConnectionsArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[30]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TransportNgdotCloseIdleConnectionsArgs.ProtoReflect.Descriptor instead.
func (*TransportNgdotCloseIdleConnectionsArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{30}
}
type TransportNgdotNewClientConnArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
C []byte `protobuf:"bytes,1,opt,name=c,proto3" json:"c,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TransportNgdotNewClientConnArgs) Reset() {
*x = TransportNgdotNewClientConnArgs{}
mi := &file_ngolofuzz_proto_msgTypes[31]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TransportNgdotNewClientConnArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TransportNgdotNewClientConnArgs) ProtoMessage() {}
func (x *TransportNgdotNewClientConnArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[31]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TransportNgdotNewClientConnArgs.ProtoReflect.Descriptor instead.
func (*TransportNgdotNewClientConnArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{31}
}
func (x *TransportNgdotNewClientConnArgs) GetC() []byte {
if x != nil {
return x.C
}
return nil
}
type ClientConnNgdotSetDoNotReuseArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ClientConnNgdotSetDoNotReuseArgs) Reset() {
*x = ClientConnNgdotSetDoNotReuseArgs{}
mi := &file_ngolofuzz_proto_msgTypes[32]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ClientConnNgdotSetDoNotReuseArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ClientConnNgdotSetDoNotReuseArgs) ProtoMessage() {}
func (x *ClientConnNgdotSetDoNotReuseArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[32]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ClientConnNgdotSetDoNotReuseArgs.ProtoReflect.Descriptor instead.
func (*ClientConnNgdotSetDoNotReuseArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{32}
}
type ClientConnNgdotCanTakeNewRequestArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ClientConnNgdotCanTakeNewRequestArgs) Reset() {
*x = ClientConnNgdotCanTakeNewRequestArgs{}
mi := &file_ngolofuzz_proto_msgTypes[33]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ClientConnNgdotCanTakeNewRequestArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ClientConnNgdotCanTakeNewRequestArgs) ProtoMessage() {}
func (x *ClientConnNgdotCanTakeNewRequestArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[33]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ClientConnNgdotCanTakeNewRequestArgs.ProtoReflect.Descriptor instead.
func (*ClientConnNgdotCanTakeNewRequestArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{33}
}
type ClientConnNgdotReserveNewRequestArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ClientConnNgdotReserveNewRequestArgs) Reset() {
*x = ClientConnNgdotReserveNewRequestArgs{}
mi := &file_ngolofuzz_proto_msgTypes[34]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ClientConnNgdotReserveNewRequestArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ClientConnNgdotReserveNewRequestArgs) ProtoMessage() {}
func (x *ClientConnNgdotReserveNewRequestArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[34]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ClientConnNgdotReserveNewRequestArgs.ProtoReflect.Descriptor instead.
func (*ClientConnNgdotReserveNewRequestArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{34}
}
type ClientConnNgdotStateArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ClientConnNgdotStateArgs) Reset() {
*x = ClientConnNgdotStateArgs{}
mi := &file_ngolofuzz_proto_msgTypes[35]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ClientConnNgdotStateArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ClientConnNgdotStateArgs) ProtoMessage() {}
func (x *ClientConnNgdotStateArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[35]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ClientConnNgdotStateArgs.ProtoReflect.Descriptor instead.
func (*ClientConnNgdotStateArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{35}
}
type ClientConnNgdotCloseArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ClientConnNgdotCloseArgs) Reset() {
*x = ClientConnNgdotCloseArgs{}
mi := &file_ngolofuzz_proto_msgTypes[36]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ClientConnNgdotCloseArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ClientConnNgdotCloseArgs) ProtoMessage() {}
func (x *ClientConnNgdotCloseArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[36]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ClientConnNgdotCloseArgs.ProtoReflect.Descriptor instead.
func (*ClientConnNgdotCloseArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{36}
}
type FrameWriteRequestNgdotStreamIDArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FrameWriteRequestNgdotStreamIDArgs) Reset() {
*x = FrameWriteRequestNgdotStreamIDArgs{}
mi := &file_ngolofuzz_proto_msgTypes[37]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FrameWriteRequestNgdotStreamIDArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FrameWriteRequestNgdotStreamIDArgs) ProtoMessage() {}
func (x *FrameWriteRequestNgdotStreamIDArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[37]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FrameWriteRequestNgdotStreamIDArgs.ProtoReflect.Descriptor instead.
func (*FrameWriteRequestNgdotStreamIDArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{37}
}
type FrameWriteRequestNgdotDataSizeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FrameWriteRequestNgdotDataSizeArgs) Reset() {
*x = FrameWriteRequestNgdotDataSizeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[38]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FrameWriteRequestNgdotDataSizeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FrameWriteRequestNgdotDataSizeArgs) ProtoMessage() {}
func (x *FrameWriteRequestNgdotDataSizeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[38]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FrameWriteRequestNgdotDataSizeArgs.ProtoReflect.Descriptor instead.
func (*FrameWriteRequestNgdotDataSizeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{38}
}
type FrameWriteRequestNgdotConsumeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
N int32 `protobuf:"varint,1,opt,name=n,proto3" json:"n,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FrameWriteRequestNgdotConsumeArgs) Reset() {
*x = FrameWriteRequestNgdotConsumeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[39]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FrameWriteRequestNgdotConsumeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FrameWriteRequestNgdotConsumeArgs) ProtoMessage() {}
func (x *FrameWriteRequestNgdotConsumeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[39]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FrameWriteRequestNgdotConsumeArgs.ProtoReflect.Descriptor instead.
func (*FrameWriteRequestNgdotConsumeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{39}
}
func (x *FrameWriteRequestNgdotConsumeArgs) GetN() int32 {
if x != nil {
return x.N
}
return 0
}
type FrameWriteRequestNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FrameWriteRequestNgdotStringArgs) Reset() {
*x = FrameWriteRequestNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[40]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FrameWriteRequestNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FrameWriteRequestNgdotStringArgs) ProtoMessage() {}
func (x *FrameWriteRequestNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[40]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FrameWriteRequestNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*FrameWriteRequestNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{40}
}
type NewRandomWriteSchedulerArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewRandomWriteSchedulerArgs) Reset() {
*x = NewRandomWriteSchedulerArgs{}
mi := &file_ngolofuzz_proto_msgTypes[41]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewRandomWriteSchedulerArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewRandomWriteSchedulerArgs) ProtoMessage() {}
func (x *NewRandomWriteSchedulerArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[41]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewRandomWriteSchedulerArgs.ProtoReflect.Descriptor instead.
func (*NewRandomWriteSchedulerArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{41}
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_ErrCodeNgdotString
// *NgoloFuzzOne_FrameTypeNgdotString
// *NgoloFuzzOne_FlagsNgdotHas
// *NgoloFuzzOne_FrameHeaderNgdotHeader
// *NgoloFuzzOne_FrameHeaderNgdotString
// *NgoloFuzzOne_ReadFrameHeader
// *NgoloFuzzOne_FramerNgdotSetReuseFrames
// *NgoloFuzzOne_NewFramer
// *NgoloFuzzOne_FramerNgdotSetMaxReadFrameSize
// *NgoloFuzzOne_FramerNgdotErrorDetail
// *NgoloFuzzOne_FramerNgdotReadFrameHeader
// *NgoloFuzzOne_FramerNgdotReadFrameForHeader
// *NgoloFuzzOne_FramerNgdotReadFrame
// *NgoloFuzzOne_FramerNgdotWriteData
// *NgoloFuzzOne_FramerNgdotWriteDataPadded
// *NgoloFuzzOne_FramerNgdotWriteSettingsAck
// *NgoloFuzzOne_GoAwayFrameNgdotDebugData
// *NgoloFuzzOne_FramerNgdotWriteGoAway
// *NgoloFuzzOne_FramerNgdotWriteWindowUpdate
// *NgoloFuzzOne_PriorityParamNgdotIsZero
// *NgoloFuzzOne_FramerNgdotWriteRSTStream
// *NgoloFuzzOne_FramerNgdotWriteContinuation
// *NgoloFuzzOne_FramerNgdotWriteRawFrame
// *NgoloFuzzOne_SettingNgdotString
// *NgoloFuzzOne_SettingNgdotValid
// *NgoloFuzzOne_SettingIDNgdotString
// *NgoloFuzzOne_TransportNgdotCloseIdleConnections
// *NgoloFuzzOne_TransportNgdotNewClientConn
// *NgoloFuzzOne_ClientConnNgdotSetDoNotReuse
// *NgoloFuzzOne_ClientConnNgdotCanTakeNewRequest
// *NgoloFuzzOne_ClientConnNgdotReserveNewRequest
// *NgoloFuzzOne_ClientConnNgdotState
// *NgoloFuzzOne_ClientConnNgdotClose
// *NgoloFuzzOne_FrameWriteRequestNgdotStreamID
// *NgoloFuzzOne_FrameWriteRequestNgdotDataSize
// *NgoloFuzzOne_FrameWriteRequestNgdotConsume
// *NgoloFuzzOne_FrameWriteRequestNgdotString
// *NgoloFuzzOne_NewRandomWriteScheduler
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[42]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[42]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{42}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetErrCodeNgdotString() *ErrCodeNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ErrCodeNgdotString); ok {
return x.ErrCodeNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetFrameTypeNgdotString() *FrameTypeNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FrameTypeNgdotString); ok {
return x.FrameTypeNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetFlagsNgdotHas() *FlagsNgdotHasArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FlagsNgdotHas); ok {
return x.FlagsNgdotHas
}
}
return nil
}
func (x *NgoloFuzzOne) GetFrameHeaderNgdotHeader() *FrameHeaderNgdotHeaderArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FrameHeaderNgdotHeader); ok {
return x.FrameHeaderNgdotHeader
}
}
return nil
}
func (x *NgoloFuzzOne) GetFrameHeaderNgdotString() *FrameHeaderNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FrameHeaderNgdotString); ok {
return x.FrameHeaderNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetReadFrameHeader() *ReadFrameHeaderArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ReadFrameHeader); ok {
return x.ReadFrameHeader
}
}
return nil
}
func (x *NgoloFuzzOne) GetFramerNgdotSetReuseFrames() *FramerNgdotSetReuseFramesArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FramerNgdotSetReuseFrames); ok {
return x.FramerNgdotSetReuseFrames
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewFramer() *NewFramerArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewFramer); ok {
return x.NewFramer
}
}
return nil
}
func (x *NgoloFuzzOne) GetFramerNgdotSetMaxReadFrameSize() *FramerNgdotSetMaxReadFrameSizeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FramerNgdotSetMaxReadFrameSize); ok {
return x.FramerNgdotSetMaxReadFrameSize
}
}
return nil
}
func (x *NgoloFuzzOne) GetFramerNgdotErrorDetail() *FramerNgdotErrorDetailArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FramerNgdotErrorDetail); ok {
return x.FramerNgdotErrorDetail
}
}
return nil
}
func (x *NgoloFuzzOne) GetFramerNgdotReadFrameHeader() *FramerNgdotReadFrameHeaderArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FramerNgdotReadFrameHeader); ok {
return x.FramerNgdotReadFrameHeader
}
}
return nil
}
func (x *NgoloFuzzOne) GetFramerNgdotReadFrameForHeader() *FramerNgdotReadFrameForHeaderArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FramerNgdotReadFrameForHeader); ok {
return x.FramerNgdotReadFrameForHeader
}
}
return nil
}
func (x *NgoloFuzzOne) GetFramerNgdotReadFrame() *FramerNgdotReadFrameArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FramerNgdotReadFrame); ok {
return x.FramerNgdotReadFrame
}
}
return nil
}
func (x *NgoloFuzzOne) GetFramerNgdotWriteData() *FramerNgdotWriteDataArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FramerNgdotWriteData); ok {
return x.FramerNgdotWriteData
}
}
return nil
}
func (x *NgoloFuzzOne) GetFramerNgdotWriteDataPadded() *FramerNgdotWriteDataPaddedArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FramerNgdotWriteDataPadded); ok {
return x.FramerNgdotWriteDataPadded
}
}
return nil
}
func (x *NgoloFuzzOne) GetFramerNgdotWriteSettingsAck() *FramerNgdotWriteSettingsAckArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FramerNgdotWriteSettingsAck); ok {
return x.FramerNgdotWriteSettingsAck
}
}
return nil
}
func (x *NgoloFuzzOne) GetGoAwayFrameNgdotDebugData() *GoAwayFrameNgdotDebugDataArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_GoAwayFrameNgdotDebugData); ok {
return x.GoAwayFrameNgdotDebugData
}
}
return nil
}
func (x *NgoloFuzzOne) GetFramerNgdotWriteGoAway() *FramerNgdotWriteGoAwayArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FramerNgdotWriteGoAway); ok {
return x.FramerNgdotWriteGoAway
}
}
return nil
}
func (x *NgoloFuzzOne) GetFramerNgdotWriteWindowUpdate() *FramerNgdotWriteWindowUpdateArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FramerNgdotWriteWindowUpdate); ok {
return x.FramerNgdotWriteWindowUpdate
}
}
return nil
}
func (x *NgoloFuzzOne) GetPriorityParamNgdotIsZero() *PriorityParamNgdotIsZeroArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_PriorityParamNgdotIsZero); ok {
return x.PriorityParamNgdotIsZero
}
}
return nil
}
func (x *NgoloFuzzOne) GetFramerNgdotWriteRSTStream() *FramerNgdotWriteRSTStreamArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FramerNgdotWriteRSTStream); ok {
return x.FramerNgdotWriteRSTStream
}
}
return nil
}
func (x *NgoloFuzzOne) GetFramerNgdotWriteContinuation() *FramerNgdotWriteContinuationArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FramerNgdotWriteContinuation); ok {
return x.FramerNgdotWriteContinuation
}
}
return nil
}
func (x *NgoloFuzzOne) GetFramerNgdotWriteRawFrame() *FramerNgdotWriteRawFrameArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FramerNgdotWriteRawFrame); ok {
return x.FramerNgdotWriteRawFrame
}
}
return nil
}
func (x *NgoloFuzzOne) GetSettingNgdotString() *SettingNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_SettingNgdotString); ok {
return x.SettingNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetSettingNgdotValid() *SettingNgdotValidArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_SettingNgdotValid); ok {
return x.SettingNgdotValid
}
}
return nil
}
func (x *NgoloFuzzOne) GetSettingIDNgdotString() *SettingIDNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_SettingIDNgdotString); ok {
return x.SettingIDNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetTransportNgdotCloseIdleConnections() *TransportNgdotCloseIdleConnectionsArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TransportNgdotCloseIdleConnections); ok {
return x.TransportNgdotCloseIdleConnections
}
}
return nil
}
func (x *NgoloFuzzOne) GetTransportNgdotNewClientConn() *TransportNgdotNewClientConnArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TransportNgdotNewClientConn); ok {
return x.TransportNgdotNewClientConn
}
}
return nil
}
func (x *NgoloFuzzOne) GetClientConnNgdotSetDoNotReuse() *ClientConnNgdotSetDoNotReuseArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ClientConnNgdotSetDoNotReuse); ok {
return x.ClientConnNgdotSetDoNotReuse
}
}
return nil
}
func (x *NgoloFuzzOne) GetClientConnNgdotCanTakeNewRequest() *ClientConnNgdotCanTakeNewRequestArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ClientConnNgdotCanTakeNewRequest); ok {
return x.ClientConnNgdotCanTakeNewRequest
}
}
return nil
}
func (x *NgoloFuzzOne) GetClientConnNgdotReserveNewRequest() *ClientConnNgdotReserveNewRequestArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ClientConnNgdotReserveNewRequest); ok {
return x.ClientConnNgdotReserveNewRequest
}
}
return nil
}
func (x *NgoloFuzzOne) GetClientConnNgdotState() *ClientConnNgdotStateArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ClientConnNgdotState); ok {
return x.ClientConnNgdotState
}
}
return nil
}
func (x *NgoloFuzzOne) GetClientConnNgdotClose() *ClientConnNgdotCloseArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ClientConnNgdotClose); ok {
return x.ClientConnNgdotClose
}
}
return nil
}
func (x *NgoloFuzzOne) GetFrameWriteRequestNgdotStreamID() *FrameWriteRequestNgdotStreamIDArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FrameWriteRequestNgdotStreamID); ok {
return x.FrameWriteRequestNgdotStreamID
}
}
return nil
}
func (x *NgoloFuzzOne) GetFrameWriteRequestNgdotDataSize() *FrameWriteRequestNgdotDataSizeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FrameWriteRequestNgdotDataSize); ok {
return x.FrameWriteRequestNgdotDataSize
}
}
return nil
}
func (x *NgoloFuzzOne) GetFrameWriteRequestNgdotConsume() *FrameWriteRequestNgdotConsumeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FrameWriteRequestNgdotConsume); ok {
return x.FrameWriteRequestNgdotConsume
}
}
return nil
}
func (x *NgoloFuzzOne) GetFrameWriteRequestNgdotString() *FrameWriteRequestNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FrameWriteRequestNgdotString); ok {
return x.FrameWriteRequestNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewRandomWriteScheduler() *NewRandomWriteSchedulerArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewRandomWriteScheduler); ok {
return x.NewRandomWriteScheduler
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_ErrCodeNgdotString struct {
ErrCodeNgdotString *ErrCodeNgdotStringArgs `protobuf:"bytes,1,opt,name=ErrCodeNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_FrameTypeNgdotString struct {
FrameTypeNgdotString *FrameTypeNgdotStringArgs `protobuf:"bytes,2,opt,name=FrameTypeNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_FlagsNgdotHas struct {
FlagsNgdotHas *FlagsNgdotHasArgs `protobuf:"bytes,3,opt,name=FlagsNgdotHas,proto3,oneof"`
}
type NgoloFuzzOne_FrameHeaderNgdotHeader struct {
FrameHeaderNgdotHeader *FrameHeaderNgdotHeaderArgs `protobuf:"bytes,4,opt,name=FrameHeaderNgdotHeader,proto3,oneof"`
}
type NgoloFuzzOne_FrameHeaderNgdotString struct {
FrameHeaderNgdotString *FrameHeaderNgdotStringArgs `protobuf:"bytes,5,opt,name=FrameHeaderNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_ReadFrameHeader struct {
ReadFrameHeader *ReadFrameHeaderArgs `protobuf:"bytes,6,opt,name=ReadFrameHeader,proto3,oneof"`
}
type NgoloFuzzOne_FramerNgdotSetReuseFrames struct {
FramerNgdotSetReuseFrames *FramerNgdotSetReuseFramesArgs `protobuf:"bytes,7,opt,name=FramerNgdotSetReuseFrames,proto3,oneof"`
}
type NgoloFuzzOne_NewFramer struct {
NewFramer *NewFramerArgs `protobuf:"bytes,8,opt,name=NewFramer,proto3,oneof"`
}
type NgoloFuzzOne_FramerNgdotSetMaxReadFrameSize struct {
FramerNgdotSetMaxReadFrameSize *FramerNgdotSetMaxReadFrameSizeArgs `protobuf:"bytes,9,opt,name=FramerNgdotSetMaxReadFrameSize,proto3,oneof"`
}
type NgoloFuzzOne_FramerNgdotErrorDetail struct {
FramerNgdotErrorDetail *FramerNgdotErrorDetailArgs `protobuf:"bytes,10,opt,name=FramerNgdotErrorDetail,proto3,oneof"`
}
type NgoloFuzzOne_FramerNgdotReadFrameHeader struct {
FramerNgdotReadFrameHeader *FramerNgdotReadFrameHeaderArgs `protobuf:"bytes,11,opt,name=FramerNgdotReadFrameHeader,proto3,oneof"`
}
type NgoloFuzzOne_FramerNgdotReadFrameForHeader struct {
FramerNgdotReadFrameForHeader *FramerNgdotReadFrameForHeaderArgs `protobuf:"bytes,12,opt,name=FramerNgdotReadFrameForHeader,proto3,oneof"`
}
type NgoloFuzzOne_FramerNgdotReadFrame struct {
FramerNgdotReadFrame *FramerNgdotReadFrameArgs `protobuf:"bytes,13,opt,name=FramerNgdotReadFrame,proto3,oneof"`
}
type NgoloFuzzOne_FramerNgdotWriteData struct {
FramerNgdotWriteData *FramerNgdotWriteDataArgs `protobuf:"bytes,14,opt,name=FramerNgdotWriteData,proto3,oneof"`
}
type NgoloFuzzOne_FramerNgdotWriteDataPadded struct {
FramerNgdotWriteDataPadded *FramerNgdotWriteDataPaddedArgs `protobuf:"bytes,15,opt,name=FramerNgdotWriteDataPadded,proto3,oneof"`
}
type NgoloFuzzOne_FramerNgdotWriteSettingsAck struct {
FramerNgdotWriteSettingsAck *FramerNgdotWriteSettingsAckArgs `protobuf:"bytes,16,opt,name=FramerNgdotWriteSettingsAck,proto3,oneof"`
}
type NgoloFuzzOne_GoAwayFrameNgdotDebugData struct {
GoAwayFrameNgdotDebugData *GoAwayFrameNgdotDebugDataArgs `protobuf:"bytes,17,opt,name=GoAwayFrameNgdotDebugData,proto3,oneof"`
}
type NgoloFuzzOne_FramerNgdotWriteGoAway struct {
FramerNgdotWriteGoAway *FramerNgdotWriteGoAwayArgs `protobuf:"bytes,18,opt,name=FramerNgdotWriteGoAway,proto3,oneof"`
}
type NgoloFuzzOne_FramerNgdotWriteWindowUpdate struct {
FramerNgdotWriteWindowUpdate *FramerNgdotWriteWindowUpdateArgs `protobuf:"bytes,19,opt,name=FramerNgdotWriteWindowUpdate,proto3,oneof"`
}
type NgoloFuzzOne_PriorityParamNgdotIsZero struct {
PriorityParamNgdotIsZero *PriorityParamNgdotIsZeroArgs `protobuf:"bytes,20,opt,name=PriorityParamNgdotIsZero,proto3,oneof"`
}
type NgoloFuzzOne_FramerNgdotWriteRSTStream struct {
FramerNgdotWriteRSTStream *FramerNgdotWriteRSTStreamArgs `protobuf:"bytes,21,opt,name=FramerNgdotWriteRSTStream,proto3,oneof"`
}
type NgoloFuzzOne_FramerNgdotWriteContinuation struct {
FramerNgdotWriteContinuation *FramerNgdotWriteContinuationArgs `protobuf:"bytes,22,opt,name=FramerNgdotWriteContinuation,proto3,oneof"`
}
type NgoloFuzzOne_FramerNgdotWriteRawFrame struct {
FramerNgdotWriteRawFrame *FramerNgdotWriteRawFrameArgs `protobuf:"bytes,23,opt,name=FramerNgdotWriteRawFrame,proto3,oneof"`
}
type NgoloFuzzOne_SettingNgdotString struct {
SettingNgdotString *SettingNgdotStringArgs `protobuf:"bytes,24,opt,name=SettingNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_SettingNgdotValid struct {
SettingNgdotValid *SettingNgdotValidArgs `protobuf:"bytes,25,opt,name=SettingNgdotValid,proto3,oneof"`
}
type NgoloFuzzOne_SettingIDNgdotString struct {
SettingIDNgdotString *SettingIDNgdotStringArgs `protobuf:"bytes,26,opt,name=SettingIDNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_TransportNgdotCloseIdleConnections struct {
TransportNgdotCloseIdleConnections *TransportNgdotCloseIdleConnectionsArgs `protobuf:"bytes,27,opt,name=TransportNgdotCloseIdleConnections,proto3,oneof"`
}
type NgoloFuzzOne_TransportNgdotNewClientConn struct {
TransportNgdotNewClientConn *TransportNgdotNewClientConnArgs `protobuf:"bytes,28,opt,name=TransportNgdotNewClientConn,proto3,oneof"`
}
type NgoloFuzzOne_ClientConnNgdotSetDoNotReuse struct {
ClientConnNgdotSetDoNotReuse *ClientConnNgdotSetDoNotReuseArgs `protobuf:"bytes,29,opt,name=ClientConnNgdotSetDoNotReuse,proto3,oneof"`
}
type NgoloFuzzOne_ClientConnNgdotCanTakeNewRequest struct {
ClientConnNgdotCanTakeNewRequest *ClientConnNgdotCanTakeNewRequestArgs `protobuf:"bytes,30,opt,name=ClientConnNgdotCanTakeNewRequest,proto3,oneof"`
}
type NgoloFuzzOne_ClientConnNgdotReserveNewRequest struct {
ClientConnNgdotReserveNewRequest *ClientConnNgdotReserveNewRequestArgs `protobuf:"bytes,31,opt,name=ClientConnNgdotReserveNewRequest,proto3,oneof"`
}
type NgoloFuzzOne_ClientConnNgdotState struct {
ClientConnNgdotState *ClientConnNgdotStateArgs `protobuf:"bytes,32,opt,name=ClientConnNgdotState,proto3,oneof"`
}
type NgoloFuzzOne_ClientConnNgdotClose struct {
ClientConnNgdotClose *ClientConnNgdotCloseArgs `protobuf:"bytes,33,opt,name=ClientConnNgdotClose,proto3,oneof"`
}
type NgoloFuzzOne_FrameWriteRequestNgdotStreamID struct {
FrameWriteRequestNgdotStreamID *FrameWriteRequestNgdotStreamIDArgs `protobuf:"bytes,34,opt,name=FrameWriteRequestNgdotStreamID,proto3,oneof"`
}
type NgoloFuzzOne_FrameWriteRequestNgdotDataSize struct {
FrameWriteRequestNgdotDataSize *FrameWriteRequestNgdotDataSizeArgs `protobuf:"bytes,35,opt,name=FrameWriteRequestNgdotDataSize,proto3,oneof"`
}
type NgoloFuzzOne_FrameWriteRequestNgdotConsume struct {
FrameWriteRequestNgdotConsume *FrameWriteRequestNgdotConsumeArgs `protobuf:"bytes,36,opt,name=FrameWriteRequestNgdotConsume,proto3,oneof"`
}
type NgoloFuzzOne_FrameWriteRequestNgdotString struct {
FrameWriteRequestNgdotString *FrameWriteRequestNgdotStringArgs `protobuf:"bytes,37,opt,name=FrameWriteRequestNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_NewRandomWriteScheduler struct {
NewRandomWriteScheduler *NewRandomWriteSchedulerArgs `protobuf:"bytes,38,opt,name=NewRandomWriteScheduler,proto3,oneof"`
}
func (*NgoloFuzzOne_ErrCodeNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FrameTypeNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FlagsNgdotHas) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FrameHeaderNgdotHeader) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FrameHeaderNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ReadFrameHeader) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FramerNgdotSetReuseFrames) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewFramer) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FramerNgdotSetMaxReadFrameSize) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FramerNgdotErrorDetail) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FramerNgdotReadFrameHeader) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FramerNgdotReadFrameForHeader) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FramerNgdotReadFrame) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FramerNgdotWriteData) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FramerNgdotWriteDataPadded) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FramerNgdotWriteSettingsAck) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_GoAwayFrameNgdotDebugData) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FramerNgdotWriteGoAway) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FramerNgdotWriteWindowUpdate) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_PriorityParamNgdotIsZero) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FramerNgdotWriteRSTStream) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FramerNgdotWriteContinuation) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FramerNgdotWriteRawFrame) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_SettingNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_SettingNgdotValid) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_SettingIDNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TransportNgdotCloseIdleConnections) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TransportNgdotNewClientConn) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ClientConnNgdotSetDoNotReuse) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ClientConnNgdotCanTakeNewRequest) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ClientConnNgdotReserveNewRequest) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ClientConnNgdotState) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ClientConnNgdotClose) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FrameWriteRequestNgdotStreamID) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FrameWriteRequestNgdotDataSize) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FrameWriteRequestNgdotConsume) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FrameWriteRequestNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewRandomWriteScheduler) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[43]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[43]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{43}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[44]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[44]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{44}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"i\n" +
"\x13PriorityParamStruct\x12\x1c\n" +
"\tStreamDep\x18\x01 \x01(\rR\tStreamDep\x12\x1c\n" +
"\tExclusive\x18\x02 \x01(\bR\tExclusive\x12\x16\n" +
"\x06Weight\x18\x03 \x01(\rR\x06Weight\"\xc4\x01\n" +
"\"PriorityWriteSchedulerConfigStruct\x122\n" +
"\x14MaxClosedNodesInTree\x18\x01 \x01(\x03R\x14MaxClosedNodesInTree\x12.\n" +
"\x12MaxIdleNodesInTree\x18\x02 \x01(\x03R\x12MaxIdleNodesInTree\x12:\n" +
"\x18ThrottleOutOfOrderWrites\x18\x03 \x01(\bR\x18ThrottleOutOfOrderWrites\"i\n" +
"\x11GoAwayFrameStruct\x12\"\n" +
"\fLastStreamID\x18\x01 \x01(\rR\fLastStreamID\x120\n" +
"\aErrCode\x18\x02 \x01(\x0e2\x16.ngolofuzz.ErrCodeEnumR\aErrCode\"\xb6\x01\n" +
"\x16PushPromiseParamStruct\x12\x1a\n" +
"\bStreamID\x18\x01 \x01(\rR\bStreamID\x12\x1c\n" +
"\tPromiseID\x18\x02 \x01(\rR\tPromiseID\x12$\n" +
"\rBlockFragment\x18\x03 \x01(\fR\rBlockFragment\x12\x1e\n" +
"\n" +
"EndHeaders\x18\x04 \x01(\bR\n" +
"EndHeaders\x12\x1c\n" +
"\tPadLength\x18\x05 \x01(\rR\tPadLength\">\n" +
"\x16ErrCodeNgdotStringArgs\x12$\n" +
"\x01e\x18\x01 \x01(\x0e2\x16.ngolofuzz.ErrCodeEnumR\x01e\"B\n" +
"\x18FrameTypeNgdotStringArgs\x12&\n" +
"\x01t\x18\x01 \x01(\x0e2\x18.ngolofuzz.FrameTypeEnumR\x01t\"[\n" +
"\x11FlagsNgdotHasArgs\x12\"\n" +
"\x01f\x18\x01 \x01(\x0e2\x14.ngolofuzz.FlagsEnumR\x01f\x12\"\n" +
"\x01v\x18\x02 \x01(\x0e2\x14.ngolofuzz.FlagsEnumR\x01v\"\x1c\n" +
"\x1aFrameHeaderNgdotHeaderArgs\"\x1c\n" +
"\x1aFrameHeaderNgdotStringArgs\"#\n" +
"\x13ReadFrameHeaderArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\fR\x01r\"\x1f\n" +
"\x1dFramerNgdotSetReuseFramesArgs\"+\n" +
"\rNewFramerArgs\x12\f\n" +
"\x01w\x18\x01 \x01(\fR\x01w\x12\f\n" +
"\x01r\x18\x02 \x01(\fR\x01r\"2\n" +
"\"FramerNgdotSetMaxReadFrameSizeArgs\x12\f\n" +
"\x01v\x18\x01 \x01(\rR\x01v\"\x1c\n" +
"\x1aFramerNgdotErrorDetailArgs\" \n" +
"\x1eFramerNgdotReadFrameHeaderArgs\"#\n" +
"!FramerNgdotReadFrameForHeaderArgs\"\x1a\n" +
"\x18FramerNgdotReadFrameArgs\"h\n" +
"\x18FramerNgdotWriteDataArgs\x12\x1a\n" +
"\bstreamID\x18\x01 \x01(\rR\bstreamID\x12\x1c\n" +
"\tendStream\x18\x02 \x01(\bR\tendStream\x12\x12\n" +
"\x04data\x18\x03 \x01(\fR\x04data\"\x80\x01\n" +
"\x1eFramerNgdotWriteDataPaddedArgs\x12\x1a\n" +
"\bstreamID\x18\x01 \x01(\rR\bstreamID\x12\x1c\n" +
"\tendStream\x18\x02 \x01(\bR\tendStream\x12\x12\n" +
"\x04data\x18\x03 \x01(\fR\x04data\x12\x10\n" +
"\x03pad\x18\x04 \x01(\fR\x03pad\"!\n" +
"\x1fFramerNgdotWriteSettingsAckArgs\"K\n" +
"\x1dGoAwayFrameNgdotDebugDataArgs\x12*\n" +
"\x01f\x18\x01 \x01(\v2\x1c.ngolofuzz.GoAwayFrameStructR\x01f\"\x88\x01\n" +
"\x1aFramerNgdotWriteGoAwayArgs\x12 \n" +
"\vmaxStreamID\x18\x01 \x01(\rR\vmaxStreamID\x12*\n" +
"\x04code\x18\x02 \x01(\x0e2\x16.ngolofuzz.ErrCodeEnumR\x04code\x12\x1c\n" +
"\tdebugData\x18\x03 \x01(\fR\tdebugData\"R\n" +
" FramerNgdotWriteWindowUpdateArgs\x12\x1a\n" +
"\bstreamID\x18\x01 \x01(\rR\bstreamID\x12\x12\n" +
"\x04incr\x18\x02 \x01(\rR\x04incr\"L\n" +
"\x1cPriorityParamNgdotIsZeroArgs\x12,\n" +
"\x01p\x18\x01 \x01(\v2\x1e.ngolofuzz.PriorityParamStructR\x01p\"g\n" +
"\x1dFramerNgdotWriteRSTStreamArgs\x12\x1a\n" +
"\bstreamID\x18\x01 \x01(\rR\bstreamID\x12*\n" +
"\x04code\x18\x02 \x01(\x0e2\x16.ngolofuzz.ErrCodeEnumR\x04code\"\x90\x01\n" +
" FramerNgdotWriteContinuationArgs\x12\x1a\n" +
"\bstreamID\x18\x01 \x01(\rR\bstreamID\x12\x1e\n" +
"\n" +
"endHeaders\x18\x02 \x01(\bR\n" +
"endHeaders\x120\n" +
"\x13headerBlockFragment\x18\x03 \x01(\fR\x13headerBlockFragment\"\xa8\x01\n" +
"\x1cFramerNgdotWriteRawFrameArgs\x12&\n" +
"\x01t\x18\x01 \x01(\x0e2\x18.ngolofuzz.FrameTypeEnumR\x01t\x12*\n" +
"\x05flags\x18\x02 \x01(\x0e2\x14.ngolofuzz.FlagsEnumR\x05flags\x12\x1a\n" +
"\bstreamID\x18\x03 \x01(\rR\bstreamID\x12\x18\n" +
"\apayload\x18\x04 \x01(\fR\apayload\"\x18\n" +
"\x16SettingNgdotStringArgs\"\x17\n" +
"\x15SettingNgdotValidArgs\"B\n" +
"\x18SettingIDNgdotStringArgs\x12&\n" +
"\x01s\x18\x01 \x01(\x0e2\x18.ngolofuzz.SettingIDEnumR\x01s\"(\n" +
"&TransportNgdotCloseIdleConnectionsArgs\"/\n" +
"\x1fTransportNgdotNewClientConnArgs\x12\f\n" +
"\x01c\x18\x01 \x01(\fR\x01c\"\"\n" +
" ClientConnNgdotSetDoNotReuseArgs\"&\n" +
"$ClientConnNgdotCanTakeNewRequestArgs\"&\n" +
"$ClientConnNgdotReserveNewRequestArgs\"\x1a\n" +
"\x18ClientConnNgdotStateArgs\"\x1a\n" +
"\x18ClientConnNgdotCloseArgs\"$\n" +
"\"FrameWriteRequestNgdotStreamIDArgs\"$\n" +
"\"FrameWriteRequestNgdotDataSizeArgs\"1\n" +
"!FrameWriteRequestNgdotConsumeArgs\x12\f\n" +
"\x01n\x18\x01 \x01(\x05R\x01n\"\"\n" +
" FrameWriteRequestNgdotStringArgs\"\x1d\n" +
"\x1bNewRandomWriteSchedulerArgs\"\xd5\x1e\n" +
"\fNgoloFuzzOne\x12S\n" +
"\x12ErrCodeNgdotString\x18\x01 \x01(\v2!.ngolofuzz.ErrCodeNgdotStringArgsH\x00R\x12ErrCodeNgdotString\x12Y\n" +
"\x14FrameTypeNgdotString\x18\x02 \x01(\v2#.ngolofuzz.FrameTypeNgdotStringArgsH\x00R\x14FrameTypeNgdotString\x12D\n" +
"\rFlagsNgdotHas\x18\x03 \x01(\v2\x1c.ngolofuzz.FlagsNgdotHasArgsH\x00R\rFlagsNgdotHas\x12_\n" +
"\x16FrameHeaderNgdotHeader\x18\x04 \x01(\v2%.ngolofuzz.FrameHeaderNgdotHeaderArgsH\x00R\x16FrameHeaderNgdotHeader\x12_\n" +
"\x16FrameHeaderNgdotString\x18\x05 \x01(\v2%.ngolofuzz.FrameHeaderNgdotStringArgsH\x00R\x16FrameHeaderNgdotString\x12J\n" +
"\x0fReadFrameHeader\x18\x06 \x01(\v2\x1e.ngolofuzz.ReadFrameHeaderArgsH\x00R\x0fReadFrameHeader\x12h\n" +
"\x19FramerNgdotSetReuseFrames\x18\a \x01(\v2(.ngolofuzz.FramerNgdotSetReuseFramesArgsH\x00R\x19FramerNgdotSetReuseFrames\x128\n" +
"\tNewFramer\x18\b \x01(\v2\x18.ngolofuzz.NewFramerArgsH\x00R\tNewFramer\x12w\n" +
"\x1eFramerNgdotSetMaxReadFrameSize\x18\t \x01(\v2-.ngolofuzz.FramerNgdotSetMaxReadFrameSizeArgsH\x00R\x1eFramerNgdotSetMaxReadFrameSize\x12_\n" +
"\x16FramerNgdotErrorDetail\x18\n" +
" \x01(\v2%.ngolofuzz.FramerNgdotErrorDetailArgsH\x00R\x16FramerNgdotErrorDetail\x12k\n" +
"\x1aFramerNgdotReadFrameHeader\x18\v \x01(\v2).ngolofuzz.FramerNgdotReadFrameHeaderArgsH\x00R\x1aFramerNgdotReadFrameHeader\x12t\n" +
"\x1dFramerNgdotReadFrameForHeader\x18\f \x01(\v2,.ngolofuzz.FramerNgdotReadFrameForHeaderArgsH\x00R\x1dFramerNgdotReadFrameForHeader\x12Y\n" +
"\x14FramerNgdotReadFrame\x18\r \x01(\v2#.ngolofuzz.FramerNgdotReadFrameArgsH\x00R\x14FramerNgdotReadFrame\x12Y\n" +
"\x14FramerNgdotWriteData\x18\x0e \x01(\v2#.ngolofuzz.FramerNgdotWriteDataArgsH\x00R\x14FramerNgdotWriteData\x12k\n" +
"\x1aFramerNgdotWriteDataPadded\x18\x0f \x01(\v2).ngolofuzz.FramerNgdotWriteDataPaddedArgsH\x00R\x1aFramerNgdotWriteDataPadded\x12n\n" +
"\x1bFramerNgdotWriteSettingsAck\x18\x10 \x01(\v2*.ngolofuzz.FramerNgdotWriteSettingsAckArgsH\x00R\x1bFramerNgdotWriteSettingsAck\x12h\n" +
"\x19GoAwayFrameNgdotDebugData\x18\x11 \x01(\v2(.ngolofuzz.GoAwayFrameNgdotDebugDataArgsH\x00R\x19GoAwayFrameNgdotDebugData\x12_\n" +
"\x16FramerNgdotWriteGoAway\x18\x12 \x01(\v2%.ngolofuzz.FramerNgdotWriteGoAwayArgsH\x00R\x16FramerNgdotWriteGoAway\x12q\n" +
"\x1cFramerNgdotWriteWindowUpdate\x18\x13 \x01(\v2+.ngolofuzz.FramerNgdotWriteWindowUpdateArgsH\x00R\x1cFramerNgdotWriteWindowUpdate\x12e\n" +
"\x18PriorityParamNgdotIsZero\x18\x14 \x01(\v2'.ngolofuzz.PriorityParamNgdotIsZeroArgsH\x00R\x18PriorityParamNgdotIsZero\x12h\n" +
"\x19FramerNgdotWriteRSTStream\x18\x15 \x01(\v2(.ngolofuzz.FramerNgdotWriteRSTStreamArgsH\x00R\x19FramerNgdotWriteRSTStream\x12q\n" +
"\x1cFramerNgdotWriteContinuation\x18\x16 \x01(\v2+.ngolofuzz.FramerNgdotWriteContinuationArgsH\x00R\x1cFramerNgdotWriteContinuation\x12e\n" +
"\x18FramerNgdotWriteRawFrame\x18\x17 \x01(\v2'.ngolofuzz.FramerNgdotWriteRawFrameArgsH\x00R\x18FramerNgdotWriteRawFrame\x12S\n" +
"\x12SettingNgdotString\x18\x18 \x01(\v2!.ngolofuzz.SettingNgdotStringArgsH\x00R\x12SettingNgdotString\x12P\n" +
"\x11SettingNgdotValid\x18\x19 \x01(\v2 .ngolofuzz.SettingNgdotValidArgsH\x00R\x11SettingNgdotValid\x12Y\n" +
"\x14SettingIDNgdotString\x18\x1a \x01(\v2#.ngolofuzz.SettingIDNgdotStringArgsH\x00R\x14SettingIDNgdotString\x12\x83\x01\n" +
"\"TransportNgdotCloseIdleConnections\x18\x1b \x01(\v21.ngolofuzz.TransportNgdotCloseIdleConnectionsArgsH\x00R\"TransportNgdotCloseIdleConnections\x12n\n" +
"\x1bTransportNgdotNewClientConn\x18\x1c \x01(\v2*.ngolofuzz.TransportNgdotNewClientConnArgsH\x00R\x1bTransportNgdotNewClientConn\x12q\n" +
"\x1cClientConnNgdotSetDoNotReuse\x18\x1d \x01(\v2+.ngolofuzz.ClientConnNgdotSetDoNotReuseArgsH\x00R\x1cClientConnNgdotSetDoNotReuse\x12}\n" +
" ClientConnNgdotCanTakeNewRequest\x18\x1e \x01(\v2/.ngolofuzz.ClientConnNgdotCanTakeNewRequestArgsH\x00R ClientConnNgdotCanTakeNewRequest\x12}\n" +
" ClientConnNgdotReserveNewRequest\x18\x1f \x01(\v2/.ngolofuzz.ClientConnNgdotReserveNewRequestArgsH\x00R ClientConnNgdotReserveNewRequest\x12Y\n" +
"\x14ClientConnNgdotState\x18 \x01(\v2#.ngolofuzz.ClientConnNgdotStateArgsH\x00R\x14ClientConnNgdotState\x12Y\n" +
"\x14ClientConnNgdotClose\x18! \x01(\v2#.ngolofuzz.ClientConnNgdotCloseArgsH\x00R\x14ClientConnNgdotClose\x12w\n" +
"\x1eFrameWriteRequestNgdotStreamID\x18\" \x01(\v2-.ngolofuzz.FrameWriteRequestNgdotStreamIDArgsH\x00R\x1eFrameWriteRequestNgdotStreamID\x12w\n" +
"\x1eFrameWriteRequestNgdotDataSize\x18# \x01(\v2-.ngolofuzz.FrameWriteRequestNgdotDataSizeArgsH\x00R\x1eFrameWriteRequestNgdotDataSize\x12t\n" +
"\x1dFrameWriteRequestNgdotConsume\x18$ \x01(\v2,.ngolofuzz.FrameWriteRequestNgdotConsumeArgsH\x00R\x1dFrameWriteRequestNgdotConsume\x12q\n" +
"\x1cFrameWriteRequestNgdotString\x18% \x01(\v2+.ngolofuzz.FrameWriteRequestNgdotStringArgsH\x00R\x1cFrameWriteRequestNgdotString\x12b\n" +
"\x17NewRandomWriteScheduler\x18& \x01(\v2&.ngolofuzz.NewRandomWriteSchedulerArgsH\x00R\x17NewRandomWriteSchedulerB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04list*\xda\x01\n" +
"\rSettingIDEnum\x12\x1a\n" +
"\x16SettingHeaderTableSize\x10\x00\x12\x15\n" +
"\x11SettingEnablePush\x10\x01\x12\x1f\n" +
"\x1bSettingMaxConcurrentStreams\x10\x02\x12\x1c\n" +
"\x18SettingInitialWindowSize\x10\x03\x12\x17\n" +
"\x13SettingMaxFrameSize\x10\x04\x12\x1c\n" +
"\x18SettingMaxHeaderListSize\x10\x05\x12 \n" +
"\x1cSettingEnableConnectProtocol\x10\x06*\xce\x01\n" +
"\rFrameTypeEnum\x12\r\n" +
"\tFrameData\x10\x00\x12\x10\n" +
"\fFrameHeaders\x10\x01\x12\x11\n" +
"\rFramePriority\x10\x02\x12\x12\n" +
"\x0eFrameRSTStream\x10\x03\x12\x11\n" +
"\rFrameSettings\x10\x04\x12\x14\n" +
"\x10FramePushPromise\x10\x05\x12\r\n" +
"\tFramePing\x10\x06\x12\x0f\n" +
"\vFrameGoAway\x10\a\x12\x15\n" +
"\x11FrameWindowUpdate\x10\b\x12\x15\n" +
"\x11FrameContinuation\x10\t*\x9b\x02\n" +
"\tFlagsEnum\x12\x15\n" +
"\x11FlagDataEndStream\x10\x00\x12\x12\n" +
"\x0eFlagDataPadded\x10\x01\x12\x18\n" +
"\x14FlagHeadersEndStream\x10\x02\x12\x19\n" +
"\x15FlagHeadersEndHeaders\x10\x03\x12\x15\n" +
"\x11FlagHeadersPadded\x10\x04\x12\x17\n" +
"\x13FlagHeadersPriority\x10\x05\x12\x13\n" +
"\x0fFlagSettingsAck\x10\x06\x12\x0f\n" +
"\vFlagPingAck\x10\a\x12\x1e\n" +
"\x1aFlagContinuationEndHeaders\x10\b\x12\x1d\n" +
"\x19FlagPushPromiseEndHeaders\x10\t\x12\x19\n" +
"\x15FlagPushPromisePadded\x10\n" +
"*\xd8\x02\n" +
"\vErrCodeEnum\x12\r\n" +
"\tErrCodeNo\x10\x00\x12\x13\n" +
"\x0fErrCodeProtocol\x10\x01\x12\x13\n" +
"\x0fErrCodeInternal\x10\x02\x12\x16\n" +
"\x12ErrCodeFlowControl\x10\x03\x12\x1a\n" +
"\x16ErrCodeSettingsTimeout\x10\x04\x12\x17\n" +
"\x13ErrCodeStreamClosed\x10\x05\x12\x14\n" +
"\x10ErrCodeFrameSize\x10\x06\x12\x18\n" +
"\x14ErrCodeRefusedStream\x10\a\x12\x11\n" +
"\rErrCodeCancel\x10\b\x12\x16\n" +
"\x12ErrCodeCompression\x10\t\x12\x12\n" +
"\x0eErrCodeConnect\x10\n" +
"\x12\x1a\n" +
"\x16ErrCodeEnhanceYourCalm\x10\v\x12\x1d\n" +
"\x19ErrCodeInadequateSecurity\x10\f\x12\x19\n" +
"\x15ErrCodeHTTP11Required\x10\rB\x18Z\x16./;fuzz_ng_x_net_http2b\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_enumTypes = make([]protoimpl.EnumInfo, 4)
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 45)
var file_ngolofuzz_proto_goTypes = []any{
(SettingIDEnum)(0), // 0: ngolofuzz.SettingIDEnum
(FrameTypeEnum)(0), // 1: ngolofuzz.FrameTypeEnum
(FlagsEnum)(0), // 2: ngolofuzz.FlagsEnum
(ErrCodeEnum)(0), // 3: ngolofuzz.ErrCodeEnum
(*PriorityParamStruct)(nil), // 4: ngolofuzz.PriorityParamStruct
(*PriorityWriteSchedulerConfigStruct)(nil), // 5: ngolofuzz.PriorityWriteSchedulerConfigStruct
(*GoAwayFrameStruct)(nil), // 6: ngolofuzz.GoAwayFrameStruct
(*PushPromiseParamStruct)(nil), // 7: ngolofuzz.PushPromiseParamStruct
(*ErrCodeNgdotStringArgs)(nil), // 8: ngolofuzz.ErrCodeNgdotStringArgs
(*FrameTypeNgdotStringArgs)(nil), // 9: ngolofuzz.FrameTypeNgdotStringArgs
(*FlagsNgdotHasArgs)(nil), // 10: ngolofuzz.FlagsNgdotHasArgs
(*FrameHeaderNgdotHeaderArgs)(nil), // 11: ngolofuzz.FrameHeaderNgdotHeaderArgs
(*FrameHeaderNgdotStringArgs)(nil), // 12: ngolofuzz.FrameHeaderNgdotStringArgs
(*ReadFrameHeaderArgs)(nil), // 13: ngolofuzz.ReadFrameHeaderArgs
(*FramerNgdotSetReuseFramesArgs)(nil), // 14: ngolofuzz.FramerNgdotSetReuseFramesArgs
(*NewFramerArgs)(nil), // 15: ngolofuzz.NewFramerArgs
(*FramerNgdotSetMaxReadFrameSizeArgs)(nil), // 16: ngolofuzz.FramerNgdotSetMaxReadFrameSizeArgs
(*FramerNgdotErrorDetailArgs)(nil), // 17: ngolofuzz.FramerNgdotErrorDetailArgs
(*FramerNgdotReadFrameHeaderArgs)(nil), // 18: ngolofuzz.FramerNgdotReadFrameHeaderArgs
(*FramerNgdotReadFrameForHeaderArgs)(nil), // 19: ngolofuzz.FramerNgdotReadFrameForHeaderArgs
(*FramerNgdotReadFrameArgs)(nil), // 20: ngolofuzz.FramerNgdotReadFrameArgs
(*FramerNgdotWriteDataArgs)(nil), // 21: ngolofuzz.FramerNgdotWriteDataArgs
(*FramerNgdotWriteDataPaddedArgs)(nil), // 22: ngolofuzz.FramerNgdotWriteDataPaddedArgs
(*FramerNgdotWriteSettingsAckArgs)(nil), // 23: ngolofuzz.FramerNgdotWriteSettingsAckArgs
(*GoAwayFrameNgdotDebugDataArgs)(nil), // 24: ngolofuzz.GoAwayFrameNgdotDebugDataArgs
(*FramerNgdotWriteGoAwayArgs)(nil), // 25: ngolofuzz.FramerNgdotWriteGoAwayArgs
(*FramerNgdotWriteWindowUpdateArgs)(nil), // 26: ngolofuzz.FramerNgdotWriteWindowUpdateArgs
(*PriorityParamNgdotIsZeroArgs)(nil), // 27: ngolofuzz.PriorityParamNgdotIsZeroArgs
(*FramerNgdotWriteRSTStreamArgs)(nil), // 28: ngolofuzz.FramerNgdotWriteRSTStreamArgs
(*FramerNgdotWriteContinuationArgs)(nil), // 29: ngolofuzz.FramerNgdotWriteContinuationArgs
(*FramerNgdotWriteRawFrameArgs)(nil), // 30: ngolofuzz.FramerNgdotWriteRawFrameArgs
(*SettingNgdotStringArgs)(nil), // 31: ngolofuzz.SettingNgdotStringArgs
(*SettingNgdotValidArgs)(nil), // 32: ngolofuzz.SettingNgdotValidArgs
(*SettingIDNgdotStringArgs)(nil), // 33: ngolofuzz.SettingIDNgdotStringArgs
(*TransportNgdotCloseIdleConnectionsArgs)(nil), // 34: ngolofuzz.TransportNgdotCloseIdleConnectionsArgs
(*TransportNgdotNewClientConnArgs)(nil), // 35: ngolofuzz.TransportNgdotNewClientConnArgs
(*ClientConnNgdotSetDoNotReuseArgs)(nil), // 36: ngolofuzz.ClientConnNgdotSetDoNotReuseArgs
(*ClientConnNgdotCanTakeNewRequestArgs)(nil), // 37: ngolofuzz.ClientConnNgdotCanTakeNewRequestArgs
(*ClientConnNgdotReserveNewRequestArgs)(nil), // 38: ngolofuzz.ClientConnNgdotReserveNewRequestArgs
(*ClientConnNgdotStateArgs)(nil), // 39: ngolofuzz.ClientConnNgdotStateArgs
(*ClientConnNgdotCloseArgs)(nil), // 40: ngolofuzz.ClientConnNgdotCloseArgs
(*FrameWriteRequestNgdotStreamIDArgs)(nil), // 41: ngolofuzz.FrameWriteRequestNgdotStreamIDArgs
(*FrameWriteRequestNgdotDataSizeArgs)(nil), // 42: ngolofuzz.FrameWriteRequestNgdotDataSizeArgs
(*FrameWriteRequestNgdotConsumeArgs)(nil), // 43: ngolofuzz.FrameWriteRequestNgdotConsumeArgs
(*FrameWriteRequestNgdotStringArgs)(nil), // 44: ngolofuzz.FrameWriteRequestNgdotStringArgs
(*NewRandomWriteSchedulerArgs)(nil), // 45: ngolofuzz.NewRandomWriteSchedulerArgs
(*NgoloFuzzOne)(nil), // 46: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 47: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 48: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
3, // 0: ngolofuzz.GoAwayFrameStruct.ErrCode:type_name -> ngolofuzz.ErrCodeEnum
3, // 1: ngolofuzz.ErrCodeNgdotStringArgs.e:type_name -> ngolofuzz.ErrCodeEnum
1, // 2: ngolofuzz.FrameTypeNgdotStringArgs.t:type_name -> ngolofuzz.FrameTypeEnum
2, // 3: ngolofuzz.FlagsNgdotHasArgs.f:type_name -> ngolofuzz.FlagsEnum
2, // 4: ngolofuzz.FlagsNgdotHasArgs.v:type_name -> ngolofuzz.FlagsEnum
6, // 5: ngolofuzz.GoAwayFrameNgdotDebugDataArgs.f:type_name -> ngolofuzz.GoAwayFrameStruct
3, // 6: ngolofuzz.FramerNgdotWriteGoAwayArgs.code:type_name -> ngolofuzz.ErrCodeEnum
4, // 7: ngolofuzz.PriorityParamNgdotIsZeroArgs.p:type_name -> ngolofuzz.PriorityParamStruct
3, // 8: ngolofuzz.FramerNgdotWriteRSTStreamArgs.code:type_name -> ngolofuzz.ErrCodeEnum
1, // 9: ngolofuzz.FramerNgdotWriteRawFrameArgs.t:type_name -> ngolofuzz.FrameTypeEnum
2, // 10: ngolofuzz.FramerNgdotWriteRawFrameArgs.flags:type_name -> ngolofuzz.FlagsEnum
0, // 11: ngolofuzz.SettingIDNgdotStringArgs.s:type_name -> ngolofuzz.SettingIDEnum
8, // 12: ngolofuzz.NgoloFuzzOne.ErrCodeNgdotString:type_name -> ngolofuzz.ErrCodeNgdotStringArgs
9, // 13: ngolofuzz.NgoloFuzzOne.FrameTypeNgdotString:type_name -> ngolofuzz.FrameTypeNgdotStringArgs
10, // 14: ngolofuzz.NgoloFuzzOne.FlagsNgdotHas:type_name -> ngolofuzz.FlagsNgdotHasArgs
11, // 15: ngolofuzz.NgoloFuzzOne.FrameHeaderNgdotHeader:type_name -> ngolofuzz.FrameHeaderNgdotHeaderArgs
12, // 16: ngolofuzz.NgoloFuzzOne.FrameHeaderNgdotString:type_name -> ngolofuzz.FrameHeaderNgdotStringArgs
13, // 17: ngolofuzz.NgoloFuzzOne.ReadFrameHeader:type_name -> ngolofuzz.ReadFrameHeaderArgs
14, // 18: ngolofuzz.NgoloFuzzOne.FramerNgdotSetReuseFrames:type_name -> ngolofuzz.FramerNgdotSetReuseFramesArgs
15, // 19: ngolofuzz.NgoloFuzzOne.NewFramer:type_name -> ngolofuzz.NewFramerArgs
16, // 20: ngolofuzz.NgoloFuzzOne.FramerNgdotSetMaxReadFrameSize:type_name -> ngolofuzz.FramerNgdotSetMaxReadFrameSizeArgs
17, // 21: ngolofuzz.NgoloFuzzOne.FramerNgdotErrorDetail:type_name -> ngolofuzz.FramerNgdotErrorDetailArgs
18, // 22: ngolofuzz.NgoloFuzzOne.FramerNgdotReadFrameHeader:type_name -> ngolofuzz.FramerNgdotReadFrameHeaderArgs
19, // 23: ngolofuzz.NgoloFuzzOne.FramerNgdotReadFrameForHeader:type_name -> ngolofuzz.FramerNgdotReadFrameForHeaderArgs
20, // 24: ngolofuzz.NgoloFuzzOne.FramerNgdotReadFrame:type_name -> ngolofuzz.FramerNgdotReadFrameArgs
21, // 25: ngolofuzz.NgoloFuzzOne.FramerNgdotWriteData:type_name -> ngolofuzz.FramerNgdotWriteDataArgs
22, // 26: ngolofuzz.NgoloFuzzOne.FramerNgdotWriteDataPadded:type_name -> ngolofuzz.FramerNgdotWriteDataPaddedArgs
23, // 27: ngolofuzz.NgoloFuzzOne.FramerNgdotWriteSettingsAck:type_name -> ngolofuzz.FramerNgdotWriteSettingsAckArgs
24, // 28: ngolofuzz.NgoloFuzzOne.GoAwayFrameNgdotDebugData:type_name -> ngolofuzz.GoAwayFrameNgdotDebugDataArgs
25, // 29: ngolofuzz.NgoloFuzzOne.FramerNgdotWriteGoAway:type_name -> ngolofuzz.FramerNgdotWriteGoAwayArgs
26, // 30: ngolofuzz.NgoloFuzzOne.FramerNgdotWriteWindowUpdate:type_name -> ngolofuzz.FramerNgdotWriteWindowUpdateArgs
27, // 31: ngolofuzz.NgoloFuzzOne.PriorityParamNgdotIsZero:type_name -> ngolofuzz.PriorityParamNgdotIsZeroArgs
28, // 32: ngolofuzz.NgoloFuzzOne.FramerNgdotWriteRSTStream:type_name -> ngolofuzz.FramerNgdotWriteRSTStreamArgs
29, // 33: ngolofuzz.NgoloFuzzOne.FramerNgdotWriteContinuation:type_name -> ngolofuzz.FramerNgdotWriteContinuationArgs
30, // 34: ngolofuzz.NgoloFuzzOne.FramerNgdotWriteRawFrame:type_name -> ngolofuzz.FramerNgdotWriteRawFrameArgs
31, // 35: ngolofuzz.NgoloFuzzOne.SettingNgdotString:type_name -> ngolofuzz.SettingNgdotStringArgs
32, // 36: ngolofuzz.NgoloFuzzOne.SettingNgdotValid:type_name -> ngolofuzz.SettingNgdotValidArgs
33, // 37: ngolofuzz.NgoloFuzzOne.SettingIDNgdotString:type_name -> ngolofuzz.SettingIDNgdotStringArgs
34, // 38: ngolofuzz.NgoloFuzzOne.TransportNgdotCloseIdleConnections:type_name -> ngolofuzz.TransportNgdotCloseIdleConnectionsArgs
35, // 39: ngolofuzz.NgoloFuzzOne.TransportNgdotNewClientConn:type_name -> ngolofuzz.TransportNgdotNewClientConnArgs
36, // 40: ngolofuzz.NgoloFuzzOne.ClientConnNgdotSetDoNotReuse:type_name -> ngolofuzz.ClientConnNgdotSetDoNotReuseArgs
37, // 41: ngolofuzz.NgoloFuzzOne.ClientConnNgdotCanTakeNewRequest:type_name -> ngolofuzz.ClientConnNgdotCanTakeNewRequestArgs
38, // 42: ngolofuzz.NgoloFuzzOne.ClientConnNgdotReserveNewRequest:type_name -> ngolofuzz.ClientConnNgdotReserveNewRequestArgs
39, // 43: ngolofuzz.NgoloFuzzOne.ClientConnNgdotState:type_name -> ngolofuzz.ClientConnNgdotStateArgs
40, // 44: ngolofuzz.NgoloFuzzOne.ClientConnNgdotClose:type_name -> ngolofuzz.ClientConnNgdotCloseArgs
41, // 45: ngolofuzz.NgoloFuzzOne.FrameWriteRequestNgdotStreamID:type_name -> ngolofuzz.FrameWriteRequestNgdotStreamIDArgs
42, // 46: ngolofuzz.NgoloFuzzOne.FrameWriteRequestNgdotDataSize:type_name -> ngolofuzz.FrameWriteRequestNgdotDataSizeArgs
43, // 47: ngolofuzz.NgoloFuzzOne.FrameWriteRequestNgdotConsume:type_name -> ngolofuzz.FrameWriteRequestNgdotConsumeArgs
44, // 48: ngolofuzz.NgoloFuzzOne.FrameWriteRequestNgdotString:type_name -> ngolofuzz.FrameWriteRequestNgdotStringArgs
45, // 49: ngolofuzz.NgoloFuzzOne.NewRandomWriteScheduler:type_name -> ngolofuzz.NewRandomWriteSchedulerArgs
46, // 50: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
51, // [51:51] is the sub-list for method output_type
51, // [51:51] is the sub-list for method input_type
51, // [51:51] is the sub-list for extension type_name
51, // [51:51] is the sub-list for extension extendee
0, // [0:51] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[42].OneofWrappers = []any{
(*NgoloFuzzOne_ErrCodeNgdotString)(nil),
(*NgoloFuzzOne_FrameTypeNgdotString)(nil),
(*NgoloFuzzOne_FlagsNgdotHas)(nil),
(*NgoloFuzzOne_FrameHeaderNgdotHeader)(nil),
(*NgoloFuzzOne_FrameHeaderNgdotString)(nil),
(*NgoloFuzzOne_ReadFrameHeader)(nil),
(*NgoloFuzzOne_FramerNgdotSetReuseFrames)(nil),
(*NgoloFuzzOne_NewFramer)(nil),
(*NgoloFuzzOne_FramerNgdotSetMaxReadFrameSize)(nil),
(*NgoloFuzzOne_FramerNgdotErrorDetail)(nil),
(*NgoloFuzzOne_FramerNgdotReadFrameHeader)(nil),
(*NgoloFuzzOne_FramerNgdotReadFrameForHeader)(nil),
(*NgoloFuzzOne_FramerNgdotReadFrame)(nil),
(*NgoloFuzzOne_FramerNgdotWriteData)(nil),
(*NgoloFuzzOne_FramerNgdotWriteDataPadded)(nil),
(*NgoloFuzzOne_FramerNgdotWriteSettingsAck)(nil),
(*NgoloFuzzOne_GoAwayFrameNgdotDebugData)(nil),
(*NgoloFuzzOne_FramerNgdotWriteGoAway)(nil),
(*NgoloFuzzOne_FramerNgdotWriteWindowUpdate)(nil),
(*NgoloFuzzOne_PriorityParamNgdotIsZero)(nil),
(*NgoloFuzzOne_FramerNgdotWriteRSTStream)(nil),
(*NgoloFuzzOne_FramerNgdotWriteContinuation)(nil),
(*NgoloFuzzOne_FramerNgdotWriteRawFrame)(nil),
(*NgoloFuzzOne_SettingNgdotString)(nil),
(*NgoloFuzzOne_SettingNgdotValid)(nil),
(*NgoloFuzzOne_SettingIDNgdotString)(nil),
(*NgoloFuzzOne_TransportNgdotCloseIdleConnections)(nil),
(*NgoloFuzzOne_TransportNgdotNewClientConn)(nil),
(*NgoloFuzzOne_ClientConnNgdotSetDoNotReuse)(nil),
(*NgoloFuzzOne_ClientConnNgdotCanTakeNewRequest)(nil),
(*NgoloFuzzOne_ClientConnNgdotReserveNewRequest)(nil),
(*NgoloFuzzOne_ClientConnNgdotState)(nil),
(*NgoloFuzzOne_ClientConnNgdotClose)(nil),
(*NgoloFuzzOne_FrameWriteRequestNgdotStreamID)(nil),
(*NgoloFuzzOne_FrameWriteRequestNgdotDataSize)(nil),
(*NgoloFuzzOne_FrameWriteRequestNgdotConsume)(nil),
(*NgoloFuzzOne_FrameWriteRequestNgdotString)(nil),
(*NgoloFuzzOne_NewRandomWriteScheduler)(nil),
}
file_ngolofuzz_proto_msgTypes[43].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 4,
NumMessages: 45,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
EnumInfos: file_ngolofuzz_proto_enumTypes,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_net_http2_hpack
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/net/http2/hpack"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func HeaderFieldNewFromFuzz(p *HeaderFieldStruct) *hpack.HeaderField{
if p == nil {
return nil
}
return &hpack.HeaderField{
Name: p.Name,
Value: p.Value,
Sensitive: p.Sensitive,
}
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var EncoderResults []*hpack.Encoder
EncoderResultsIndex := 0
var DecoderResults []*hpack.Decoder
DecoderResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewEncoder:
arg0 := bytes.NewBuffer(a.NewEncoder.W)
r0 := hpack.NewEncoder(arg0)
if r0 != nil{
EncoderResults = append(EncoderResults, r0)
}
case *NgoloFuzzOne_EncoderNgdotSetMaxDynamicTableSize:
if len(EncoderResults) == 0 {
continue
}
arg0 := EncoderResults[EncoderResultsIndex]
EncoderResultsIndex = (EncoderResultsIndex + 1) % len(EncoderResults)
arg0.SetMaxDynamicTableSize(a.EncoderNgdotSetMaxDynamicTableSize.V)
case *NgoloFuzzOne_EncoderNgdotMaxDynamicTableSize:
if len(EncoderResults) == 0 {
continue
}
arg0 := EncoderResults[EncoderResultsIndex]
EncoderResultsIndex = (EncoderResultsIndex + 1) % len(EncoderResults)
arg0.MaxDynamicTableSize()
case *NgoloFuzzOne_EncoderNgdotSetMaxDynamicTableSizeLimit:
if len(EncoderResults) == 0 {
continue
}
arg0 := EncoderResults[EncoderResultsIndex]
EncoderResultsIndex = (EncoderResultsIndex + 1) % len(EncoderResults)
arg0.SetMaxDynamicTableSizeLimit(a.EncoderNgdotSetMaxDynamicTableSizeLimit.V)
case *NgoloFuzzOne_HeaderFieldNgdotIsPseudo:
arg0 := HeaderFieldNewFromFuzz(a.HeaderFieldNgdotIsPseudo.Hf)
if arg0 == nil {
continue
}
arg0.IsPseudo()
case *NgoloFuzzOne_HeaderFieldNgdotString:
arg0 := HeaderFieldNewFromFuzz(a.HeaderFieldNgdotString.Hf)
if arg0 == nil {
continue
}
arg0.String()
case *NgoloFuzzOne_HeaderFieldNgdotSize:
arg0 := HeaderFieldNewFromFuzz(a.HeaderFieldNgdotSize.Hf)
if arg0 == nil {
continue
}
arg0.Size()
case *NgoloFuzzOne_DecoderNgdotSetMaxStringLength:
if len(DecoderResults) == 0 {
continue
}
arg0 := DecoderResults[DecoderResultsIndex]
DecoderResultsIndex = (DecoderResultsIndex + 1) % len(DecoderResults)
arg1 := int(a.DecoderNgdotSetMaxStringLength.N)
arg0.SetMaxStringLength(arg1)
case *NgoloFuzzOne_DecoderNgdotSetEmitEnabled:
if len(DecoderResults) == 0 {
continue
}
arg0 := DecoderResults[DecoderResultsIndex]
DecoderResultsIndex = (DecoderResultsIndex + 1) % len(DecoderResults)
arg0.SetEmitEnabled(a.DecoderNgdotSetEmitEnabled.V)
case *NgoloFuzzOne_DecoderNgdotEmitEnabled:
if len(DecoderResults) == 0 {
continue
}
arg0 := DecoderResults[DecoderResultsIndex]
DecoderResultsIndex = (DecoderResultsIndex + 1) % len(DecoderResults)
arg0.EmitEnabled()
case *NgoloFuzzOne_DecoderNgdotSetMaxDynamicTableSize:
if len(DecoderResults) == 0 {
continue
}
arg0 := DecoderResults[DecoderResultsIndex]
DecoderResultsIndex = (DecoderResultsIndex + 1) % len(DecoderResults)
arg0.SetMaxDynamicTableSize(a.DecoderNgdotSetMaxDynamicTableSize.V)
case *NgoloFuzzOne_DecoderNgdotSetAllowedMaxDynamicTableSize:
if len(DecoderResults) == 0 {
continue
}
arg0 := DecoderResults[DecoderResultsIndex]
DecoderResultsIndex = (DecoderResultsIndex + 1) % len(DecoderResults)
arg0.SetAllowedMaxDynamicTableSize(a.DecoderNgdotSetAllowedMaxDynamicTableSize.V)
case *NgoloFuzzOne_DecoderNgdotDecodeFull:
if len(DecoderResults) == 0 {
continue
}
arg0 := DecoderResults[DecoderResultsIndex]
DecoderResultsIndex = (DecoderResultsIndex + 1) % len(DecoderResults)
_, r1 := arg0.DecodeFull(a.DecoderNgdotDecodeFull.P)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_DecoderNgdotClose:
if len(DecoderResults) == 0 {
continue
}
arg0 := DecoderResults[DecoderResultsIndex]
DecoderResultsIndex = (DecoderResultsIndex + 1) % len(DecoderResults)
r0 := arg0.Close()
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_DecoderNgdotWrite:
if len(DecoderResults) == 0 {
continue
}
arg0 := DecoderResults[DecoderResultsIndex]
DecoderResultsIndex = (DecoderResultsIndex + 1) % len(DecoderResults)
_, r1 := arg0.Write(a.DecoderNgdotWrite.P)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_HuffmanDecode:
arg0 := bytes.NewBuffer(a.HuffmanDecode.W)
_, r1 := hpack.HuffmanDecode(arg0, a.HuffmanDecode.V)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_HuffmanDecodeToString:
_, r1 := hpack.HuffmanDecodeToString(a.HuffmanDecodeToString.V)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_AppendHuffmanString:
hpack.AppendHuffmanString(a.AppendHuffmanString.Dst, a.AppendHuffmanString.S)
case *NgoloFuzzOne_HuffmanEncodeLength:
hpack.HuffmanEncodeLength(a.HuffmanEncodeLength.S)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
EncoderNb := 0
EncoderResultsIndex := 0
DecoderNb := 0
DecoderResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewEncoder:
w.WriteString(fmt.Sprintf("Encoder%d := hpack.NewEncoder(bytes.NewBuffer(%#+v))\n", EncoderNb, a.NewEncoder.W))
EncoderNb = EncoderNb + 1
case *NgoloFuzzOne_EncoderNgdotSetMaxDynamicTableSize:
if EncoderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Encoder%d.SetMaxDynamicTableSize(%#+v)\n", EncoderResultsIndex, a.EncoderNgdotSetMaxDynamicTableSize.V))
EncoderResultsIndex = (EncoderResultsIndex + 1) % EncoderNb
case *NgoloFuzzOne_EncoderNgdotMaxDynamicTableSize:
if EncoderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Encoder%d.MaxDynamicTableSize()\n", EncoderResultsIndex))
EncoderResultsIndex = (EncoderResultsIndex + 1) % EncoderNb
case *NgoloFuzzOne_EncoderNgdotSetMaxDynamicTableSizeLimit:
if EncoderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Encoder%d.SetMaxDynamicTableSizeLimit(%#+v)\n", EncoderResultsIndex, a.EncoderNgdotSetMaxDynamicTableSizeLimit.V))
EncoderResultsIndex = (EncoderResultsIndex + 1) % EncoderNb
case *NgoloFuzzOne_HeaderFieldNgdotIsPseudo:
w.WriteString(fmt.Sprintf("HeaderFieldNewFromFuzz(%#+v).IsPseudo()\n", a.HeaderFieldNgdotIsPseudo.Hf))
case *NgoloFuzzOne_HeaderFieldNgdotString:
w.WriteString(fmt.Sprintf("HeaderFieldNewFromFuzz(%#+v).String()\n", a.HeaderFieldNgdotString.Hf))
case *NgoloFuzzOne_HeaderFieldNgdotSize:
w.WriteString(fmt.Sprintf("HeaderFieldNewFromFuzz(%#+v).Size()\n", a.HeaderFieldNgdotSize.Hf))
case *NgoloFuzzOne_DecoderNgdotSetMaxStringLength:
if DecoderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Decoder%d.SetMaxStringLength(int(%#+v))\n", DecoderResultsIndex, a.DecoderNgdotSetMaxStringLength.N))
DecoderResultsIndex = (DecoderResultsIndex + 1) % DecoderNb
case *NgoloFuzzOne_DecoderNgdotSetEmitEnabled:
if DecoderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Decoder%d.SetEmitEnabled(%#+v)\n", DecoderResultsIndex, a.DecoderNgdotSetEmitEnabled.V))
DecoderResultsIndex = (DecoderResultsIndex + 1) % DecoderNb
case *NgoloFuzzOne_DecoderNgdotEmitEnabled:
if DecoderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Decoder%d.EmitEnabled()\n", DecoderResultsIndex))
DecoderResultsIndex = (DecoderResultsIndex + 1) % DecoderNb
case *NgoloFuzzOne_DecoderNgdotSetMaxDynamicTableSize:
if DecoderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Decoder%d.SetMaxDynamicTableSize(%#+v)\n", DecoderResultsIndex, a.DecoderNgdotSetMaxDynamicTableSize.V))
DecoderResultsIndex = (DecoderResultsIndex + 1) % DecoderNb
case *NgoloFuzzOne_DecoderNgdotSetAllowedMaxDynamicTableSize:
if DecoderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Decoder%d.SetAllowedMaxDynamicTableSize(%#+v)\n", DecoderResultsIndex, a.DecoderNgdotSetAllowedMaxDynamicTableSize.V))
DecoderResultsIndex = (DecoderResultsIndex + 1) % DecoderNb
case *NgoloFuzzOne_DecoderNgdotDecodeFull:
if DecoderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Decoder%d.DecodeFull(%#+v)\n", DecoderResultsIndex, a.DecoderNgdotDecodeFull.P))
DecoderResultsIndex = (DecoderResultsIndex + 1) % DecoderNb
case *NgoloFuzzOne_DecoderNgdotClose:
if DecoderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Decoder%d.Close()\n", DecoderResultsIndex))
DecoderResultsIndex = (DecoderResultsIndex + 1) % DecoderNb
case *NgoloFuzzOne_DecoderNgdotWrite:
if DecoderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Decoder%d.Write(%#+v)\n", DecoderResultsIndex, a.DecoderNgdotWrite.P))
DecoderResultsIndex = (DecoderResultsIndex + 1) % DecoderNb
case *NgoloFuzzOne_HuffmanDecode:
w.WriteString(fmt.Sprintf("hpack.HuffmanDecode(bytes.NewBuffer(%#+v), %#+v)\n", a.HuffmanDecode.W, a.HuffmanDecode.V))
case *NgoloFuzzOne_HuffmanDecodeToString:
w.WriteString(fmt.Sprintf("hpack.HuffmanDecodeToString(%#+v)\n", a.HuffmanDecodeToString.V))
case *NgoloFuzzOne_AppendHuffmanString:
w.WriteString(fmt.Sprintf("hpack.AppendHuffmanString(%#+v, %#+v)\n", a.AppendHuffmanString.Dst, a.AppendHuffmanString.S))
case *NgoloFuzzOne_HuffmanEncodeLength:
w.WriteString(fmt.Sprintf("hpack.HuffmanEncodeLength(%#+v)\n", a.HuffmanEncodeLength.S))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_net_http2_hpack
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type HeaderFieldStruct struct {
state protoimpl.MessageState `protogen:"open.v1"`
Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"`
Value string `protobuf:"bytes,2,opt,name=Value,proto3" json:"Value,omitempty"`
Sensitive bool `protobuf:"varint,3,opt,name=Sensitive,proto3" json:"Sensitive,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HeaderFieldStruct) Reset() {
*x = HeaderFieldStruct{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HeaderFieldStruct) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HeaderFieldStruct) ProtoMessage() {}
func (x *HeaderFieldStruct) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HeaderFieldStruct.ProtoReflect.Descriptor instead.
func (*HeaderFieldStruct) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *HeaderFieldStruct) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *HeaderFieldStruct) GetValue() string {
if x != nil {
return x.Value
}
return ""
}
func (x *HeaderFieldStruct) GetSensitive() bool {
if x != nil {
return x.Sensitive
}
return false
}
type NewEncoderArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
W []byte `protobuf:"bytes,1,opt,name=w,proto3" json:"w,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewEncoderArgs) Reset() {
*x = NewEncoderArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewEncoderArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewEncoderArgs) ProtoMessage() {}
func (x *NewEncoderArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewEncoderArgs.ProtoReflect.Descriptor instead.
func (*NewEncoderArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *NewEncoderArgs) GetW() []byte {
if x != nil {
return x.W
}
return nil
}
type EncoderNgdotSetMaxDynamicTableSizeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
V uint32 `protobuf:"varint,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *EncoderNgdotSetMaxDynamicTableSizeArgs) Reset() {
*x = EncoderNgdotSetMaxDynamicTableSizeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *EncoderNgdotSetMaxDynamicTableSizeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EncoderNgdotSetMaxDynamicTableSizeArgs) ProtoMessage() {}
func (x *EncoderNgdotSetMaxDynamicTableSizeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EncoderNgdotSetMaxDynamicTableSizeArgs.ProtoReflect.Descriptor instead.
func (*EncoderNgdotSetMaxDynamicTableSizeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *EncoderNgdotSetMaxDynamicTableSizeArgs) GetV() uint32 {
if x != nil {
return x.V
}
return 0
}
type EncoderNgdotMaxDynamicTableSizeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *EncoderNgdotMaxDynamicTableSizeArgs) Reset() {
*x = EncoderNgdotMaxDynamicTableSizeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *EncoderNgdotMaxDynamicTableSizeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EncoderNgdotMaxDynamicTableSizeArgs) ProtoMessage() {}
func (x *EncoderNgdotMaxDynamicTableSizeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EncoderNgdotMaxDynamicTableSizeArgs.ProtoReflect.Descriptor instead.
func (*EncoderNgdotMaxDynamicTableSizeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
type EncoderNgdotSetMaxDynamicTableSizeLimitArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
V uint32 `protobuf:"varint,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *EncoderNgdotSetMaxDynamicTableSizeLimitArgs) Reset() {
*x = EncoderNgdotSetMaxDynamicTableSizeLimitArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *EncoderNgdotSetMaxDynamicTableSizeLimitArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EncoderNgdotSetMaxDynamicTableSizeLimitArgs) ProtoMessage() {}
func (x *EncoderNgdotSetMaxDynamicTableSizeLimitArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EncoderNgdotSetMaxDynamicTableSizeLimitArgs.ProtoReflect.Descriptor instead.
func (*EncoderNgdotSetMaxDynamicTableSizeLimitArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *EncoderNgdotSetMaxDynamicTableSizeLimitArgs) GetV() uint32 {
if x != nil {
return x.V
}
return 0
}
type HeaderFieldNgdotIsPseudoArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Hf *HeaderFieldStruct `protobuf:"bytes,1,opt,name=hf,proto3" json:"hf,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HeaderFieldNgdotIsPseudoArgs) Reset() {
*x = HeaderFieldNgdotIsPseudoArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HeaderFieldNgdotIsPseudoArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HeaderFieldNgdotIsPseudoArgs) ProtoMessage() {}
func (x *HeaderFieldNgdotIsPseudoArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HeaderFieldNgdotIsPseudoArgs.ProtoReflect.Descriptor instead.
func (*HeaderFieldNgdotIsPseudoArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *HeaderFieldNgdotIsPseudoArgs) GetHf() *HeaderFieldStruct {
if x != nil {
return x.Hf
}
return nil
}
type HeaderFieldNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Hf *HeaderFieldStruct `protobuf:"bytes,1,opt,name=hf,proto3" json:"hf,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HeaderFieldNgdotStringArgs) Reset() {
*x = HeaderFieldNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HeaderFieldNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HeaderFieldNgdotStringArgs) ProtoMessage() {}
func (x *HeaderFieldNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HeaderFieldNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*HeaderFieldNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *HeaderFieldNgdotStringArgs) GetHf() *HeaderFieldStruct {
if x != nil {
return x.Hf
}
return nil
}
type HeaderFieldNgdotSizeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Hf *HeaderFieldStruct `protobuf:"bytes,1,opt,name=hf,proto3" json:"hf,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HeaderFieldNgdotSizeArgs) Reset() {
*x = HeaderFieldNgdotSizeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HeaderFieldNgdotSizeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HeaderFieldNgdotSizeArgs) ProtoMessage() {}
func (x *HeaderFieldNgdotSizeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HeaderFieldNgdotSizeArgs.ProtoReflect.Descriptor instead.
func (*HeaderFieldNgdotSizeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
func (x *HeaderFieldNgdotSizeArgs) GetHf() *HeaderFieldStruct {
if x != nil {
return x.Hf
}
return nil
}
type DecoderNgdotSetMaxStringLengthArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
N int64 `protobuf:"varint,1,opt,name=n,proto3" json:"n,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecoderNgdotSetMaxStringLengthArgs) Reset() {
*x = DecoderNgdotSetMaxStringLengthArgs{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecoderNgdotSetMaxStringLengthArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecoderNgdotSetMaxStringLengthArgs) ProtoMessage() {}
func (x *DecoderNgdotSetMaxStringLengthArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecoderNgdotSetMaxStringLengthArgs.ProtoReflect.Descriptor instead.
func (*DecoderNgdotSetMaxStringLengthArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
func (x *DecoderNgdotSetMaxStringLengthArgs) GetN() int64 {
if x != nil {
return x.N
}
return 0
}
type DecoderNgdotSetEmitEnabledArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
V bool `protobuf:"varint,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecoderNgdotSetEmitEnabledArgs) Reset() {
*x = DecoderNgdotSetEmitEnabledArgs{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecoderNgdotSetEmitEnabledArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecoderNgdotSetEmitEnabledArgs) ProtoMessage() {}
func (x *DecoderNgdotSetEmitEnabledArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecoderNgdotSetEmitEnabledArgs.ProtoReflect.Descriptor instead.
func (*DecoderNgdotSetEmitEnabledArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
func (x *DecoderNgdotSetEmitEnabledArgs) GetV() bool {
if x != nil {
return x.V
}
return false
}
type DecoderNgdotEmitEnabledArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecoderNgdotEmitEnabledArgs) Reset() {
*x = DecoderNgdotEmitEnabledArgs{}
mi := &file_ngolofuzz_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecoderNgdotEmitEnabledArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecoderNgdotEmitEnabledArgs) ProtoMessage() {}
func (x *DecoderNgdotEmitEnabledArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecoderNgdotEmitEnabledArgs.ProtoReflect.Descriptor instead.
func (*DecoderNgdotEmitEnabledArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{10}
}
type DecoderNgdotSetMaxDynamicTableSizeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
V uint32 `protobuf:"varint,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecoderNgdotSetMaxDynamicTableSizeArgs) Reset() {
*x = DecoderNgdotSetMaxDynamicTableSizeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecoderNgdotSetMaxDynamicTableSizeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecoderNgdotSetMaxDynamicTableSizeArgs) ProtoMessage() {}
func (x *DecoderNgdotSetMaxDynamicTableSizeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[11]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecoderNgdotSetMaxDynamicTableSizeArgs.ProtoReflect.Descriptor instead.
func (*DecoderNgdotSetMaxDynamicTableSizeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{11}
}
func (x *DecoderNgdotSetMaxDynamicTableSizeArgs) GetV() uint32 {
if x != nil {
return x.V
}
return 0
}
type DecoderNgdotSetAllowedMaxDynamicTableSizeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
V uint32 `protobuf:"varint,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecoderNgdotSetAllowedMaxDynamicTableSizeArgs) Reset() {
*x = DecoderNgdotSetAllowedMaxDynamicTableSizeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecoderNgdotSetAllowedMaxDynamicTableSizeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecoderNgdotSetAllowedMaxDynamicTableSizeArgs) ProtoMessage() {}
func (x *DecoderNgdotSetAllowedMaxDynamicTableSizeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[12]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecoderNgdotSetAllowedMaxDynamicTableSizeArgs.ProtoReflect.Descriptor instead.
func (*DecoderNgdotSetAllowedMaxDynamicTableSizeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{12}
}
func (x *DecoderNgdotSetAllowedMaxDynamicTableSizeArgs) GetV() uint32 {
if x != nil {
return x.V
}
return 0
}
type DecoderNgdotDecodeFullArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
P []byte `protobuf:"bytes,1,opt,name=p,proto3" json:"p,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecoderNgdotDecodeFullArgs) Reset() {
*x = DecoderNgdotDecodeFullArgs{}
mi := &file_ngolofuzz_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecoderNgdotDecodeFullArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecoderNgdotDecodeFullArgs) ProtoMessage() {}
func (x *DecoderNgdotDecodeFullArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[13]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecoderNgdotDecodeFullArgs.ProtoReflect.Descriptor instead.
func (*DecoderNgdotDecodeFullArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{13}
}
func (x *DecoderNgdotDecodeFullArgs) GetP() []byte {
if x != nil {
return x.P
}
return nil
}
type DecoderNgdotCloseArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecoderNgdotCloseArgs) Reset() {
*x = DecoderNgdotCloseArgs{}
mi := &file_ngolofuzz_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecoderNgdotCloseArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecoderNgdotCloseArgs) ProtoMessage() {}
func (x *DecoderNgdotCloseArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[14]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecoderNgdotCloseArgs.ProtoReflect.Descriptor instead.
func (*DecoderNgdotCloseArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{14}
}
type DecoderNgdotWriteArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
P []byte `protobuf:"bytes,1,opt,name=p,proto3" json:"p,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DecoderNgdotWriteArgs) Reset() {
*x = DecoderNgdotWriteArgs{}
mi := &file_ngolofuzz_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DecoderNgdotWriteArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecoderNgdotWriteArgs) ProtoMessage() {}
func (x *DecoderNgdotWriteArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[15]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecoderNgdotWriteArgs.ProtoReflect.Descriptor instead.
func (*DecoderNgdotWriteArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{15}
}
func (x *DecoderNgdotWriteArgs) GetP() []byte {
if x != nil {
return x.P
}
return nil
}
type HuffmanDecodeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
W []byte `protobuf:"bytes,1,opt,name=w,proto3" json:"w,omitempty"`
V []byte `protobuf:"bytes,2,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HuffmanDecodeArgs) Reset() {
*x = HuffmanDecodeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HuffmanDecodeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HuffmanDecodeArgs) ProtoMessage() {}
func (x *HuffmanDecodeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[16]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HuffmanDecodeArgs.ProtoReflect.Descriptor instead.
func (*HuffmanDecodeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{16}
}
func (x *HuffmanDecodeArgs) GetW() []byte {
if x != nil {
return x.W
}
return nil
}
func (x *HuffmanDecodeArgs) GetV() []byte {
if x != nil {
return x.V
}
return nil
}
type HuffmanDecodeToStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
V []byte `protobuf:"bytes,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HuffmanDecodeToStringArgs) Reset() {
*x = HuffmanDecodeToStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HuffmanDecodeToStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HuffmanDecodeToStringArgs) ProtoMessage() {}
func (x *HuffmanDecodeToStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[17]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HuffmanDecodeToStringArgs.ProtoReflect.Descriptor instead.
func (*HuffmanDecodeToStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{17}
}
func (x *HuffmanDecodeToStringArgs) GetV() []byte {
if x != nil {
return x.V
}
return nil
}
type AppendHuffmanStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Dst []byte `protobuf:"bytes,1,opt,name=dst,proto3" json:"dst,omitempty"`
S string `protobuf:"bytes,2,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *AppendHuffmanStringArgs) Reset() {
*x = AppendHuffmanStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AppendHuffmanStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AppendHuffmanStringArgs) ProtoMessage() {}
func (x *AppendHuffmanStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[18]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AppendHuffmanStringArgs.ProtoReflect.Descriptor instead.
func (*AppendHuffmanStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{18}
}
func (x *AppendHuffmanStringArgs) GetDst() []byte {
if x != nil {
return x.Dst
}
return nil
}
func (x *AppendHuffmanStringArgs) GetS() string {
if x != nil {
return x.S
}
return ""
}
type HuffmanEncodeLengthArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S string `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HuffmanEncodeLengthArgs) Reset() {
*x = HuffmanEncodeLengthArgs{}
mi := &file_ngolofuzz_proto_msgTypes[19]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HuffmanEncodeLengthArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HuffmanEncodeLengthArgs) ProtoMessage() {}
func (x *HuffmanEncodeLengthArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[19]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HuffmanEncodeLengthArgs.ProtoReflect.Descriptor instead.
func (*HuffmanEncodeLengthArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{19}
}
func (x *HuffmanEncodeLengthArgs) GetS() string {
if x != nil {
return x.S
}
return ""
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_NewEncoder
// *NgoloFuzzOne_EncoderNgdotSetMaxDynamicTableSize
// *NgoloFuzzOne_EncoderNgdotMaxDynamicTableSize
// *NgoloFuzzOne_EncoderNgdotSetMaxDynamicTableSizeLimit
// *NgoloFuzzOne_HeaderFieldNgdotIsPseudo
// *NgoloFuzzOne_HeaderFieldNgdotString
// *NgoloFuzzOne_HeaderFieldNgdotSize
// *NgoloFuzzOne_DecoderNgdotSetMaxStringLength
// *NgoloFuzzOne_DecoderNgdotSetEmitEnabled
// *NgoloFuzzOne_DecoderNgdotEmitEnabled
// *NgoloFuzzOne_DecoderNgdotSetMaxDynamicTableSize
// *NgoloFuzzOne_DecoderNgdotSetAllowedMaxDynamicTableSize
// *NgoloFuzzOne_DecoderNgdotDecodeFull
// *NgoloFuzzOne_DecoderNgdotClose
// *NgoloFuzzOne_DecoderNgdotWrite
// *NgoloFuzzOne_HuffmanDecode
// *NgoloFuzzOne_HuffmanDecodeToString
// *NgoloFuzzOne_AppendHuffmanString
// *NgoloFuzzOne_HuffmanEncodeLength
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[20]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[20]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{20}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetNewEncoder() *NewEncoderArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewEncoder); ok {
return x.NewEncoder
}
}
return nil
}
func (x *NgoloFuzzOne) GetEncoderNgdotSetMaxDynamicTableSize() *EncoderNgdotSetMaxDynamicTableSizeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_EncoderNgdotSetMaxDynamicTableSize); ok {
return x.EncoderNgdotSetMaxDynamicTableSize
}
}
return nil
}
func (x *NgoloFuzzOne) GetEncoderNgdotMaxDynamicTableSize() *EncoderNgdotMaxDynamicTableSizeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_EncoderNgdotMaxDynamicTableSize); ok {
return x.EncoderNgdotMaxDynamicTableSize
}
}
return nil
}
func (x *NgoloFuzzOne) GetEncoderNgdotSetMaxDynamicTableSizeLimit() *EncoderNgdotSetMaxDynamicTableSizeLimitArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_EncoderNgdotSetMaxDynamicTableSizeLimit); ok {
return x.EncoderNgdotSetMaxDynamicTableSizeLimit
}
}
return nil
}
func (x *NgoloFuzzOne) GetHeaderFieldNgdotIsPseudo() *HeaderFieldNgdotIsPseudoArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_HeaderFieldNgdotIsPseudo); ok {
return x.HeaderFieldNgdotIsPseudo
}
}
return nil
}
func (x *NgoloFuzzOne) GetHeaderFieldNgdotString() *HeaderFieldNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_HeaderFieldNgdotString); ok {
return x.HeaderFieldNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetHeaderFieldNgdotSize() *HeaderFieldNgdotSizeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_HeaderFieldNgdotSize); ok {
return x.HeaderFieldNgdotSize
}
}
return nil
}
func (x *NgoloFuzzOne) GetDecoderNgdotSetMaxStringLength() *DecoderNgdotSetMaxStringLengthArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_DecoderNgdotSetMaxStringLength); ok {
return x.DecoderNgdotSetMaxStringLength
}
}
return nil
}
func (x *NgoloFuzzOne) GetDecoderNgdotSetEmitEnabled() *DecoderNgdotSetEmitEnabledArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_DecoderNgdotSetEmitEnabled); ok {
return x.DecoderNgdotSetEmitEnabled
}
}
return nil
}
func (x *NgoloFuzzOne) GetDecoderNgdotEmitEnabled() *DecoderNgdotEmitEnabledArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_DecoderNgdotEmitEnabled); ok {
return x.DecoderNgdotEmitEnabled
}
}
return nil
}
func (x *NgoloFuzzOne) GetDecoderNgdotSetMaxDynamicTableSize() *DecoderNgdotSetMaxDynamicTableSizeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_DecoderNgdotSetMaxDynamicTableSize); ok {
return x.DecoderNgdotSetMaxDynamicTableSize
}
}
return nil
}
func (x *NgoloFuzzOne) GetDecoderNgdotSetAllowedMaxDynamicTableSize() *DecoderNgdotSetAllowedMaxDynamicTableSizeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_DecoderNgdotSetAllowedMaxDynamicTableSize); ok {
return x.DecoderNgdotSetAllowedMaxDynamicTableSize
}
}
return nil
}
func (x *NgoloFuzzOne) GetDecoderNgdotDecodeFull() *DecoderNgdotDecodeFullArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_DecoderNgdotDecodeFull); ok {
return x.DecoderNgdotDecodeFull
}
}
return nil
}
func (x *NgoloFuzzOne) GetDecoderNgdotClose() *DecoderNgdotCloseArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_DecoderNgdotClose); ok {
return x.DecoderNgdotClose
}
}
return nil
}
func (x *NgoloFuzzOne) GetDecoderNgdotWrite() *DecoderNgdotWriteArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_DecoderNgdotWrite); ok {
return x.DecoderNgdotWrite
}
}
return nil
}
func (x *NgoloFuzzOne) GetHuffmanDecode() *HuffmanDecodeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_HuffmanDecode); ok {
return x.HuffmanDecode
}
}
return nil
}
func (x *NgoloFuzzOne) GetHuffmanDecodeToString() *HuffmanDecodeToStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_HuffmanDecodeToString); ok {
return x.HuffmanDecodeToString
}
}
return nil
}
func (x *NgoloFuzzOne) GetAppendHuffmanString() *AppendHuffmanStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_AppendHuffmanString); ok {
return x.AppendHuffmanString
}
}
return nil
}
func (x *NgoloFuzzOne) GetHuffmanEncodeLength() *HuffmanEncodeLengthArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_HuffmanEncodeLength); ok {
return x.HuffmanEncodeLength
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_NewEncoder struct {
NewEncoder *NewEncoderArgs `protobuf:"bytes,1,opt,name=NewEncoder,proto3,oneof"`
}
type NgoloFuzzOne_EncoderNgdotSetMaxDynamicTableSize struct {
EncoderNgdotSetMaxDynamicTableSize *EncoderNgdotSetMaxDynamicTableSizeArgs `protobuf:"bytes,2,opt,name=EncoderNgdotSetMaxDynamicTableSize,proto3,oneof"`
}
type NgoloFuzzOne_EncoderNgdotMaxDynamicTableSize struct {
EncoderNgdotMaxDynamicTableSize *EncoderNgdotMaxDynamicTableSizeArgs `protobuf:"bytes,3,opt,name=EncoderNgdotMaxDynamicTableSize,proto3,oneof"`
}
type NgoloFuzzOne_EncoderNgdotSetMaxDynamicTableSizeLimit struct {
EncoderNgdotSetMaxDynamicTableSizeLimit *EncoderNgdotSetMaxDynamicTableSizeLimitArgs `protobuf:"bytes,4,opt,name=EncoderNgdotSetMaxDynamicTableSizeLimit,proto3,oneof"`
}
type NgoloFuzzOne_HeaderFieldNgdotIsPseudo struct {
HeaderFieldNgdotIsPseudo *HeaderFieldNgdotIsPseudoArgs `protobuf:"bytes,5,opt,name=HeaderFieldNgdotIsPseudo,proto3,oneof"`
}
type NgoloFuzzOne_HeaderFieldNgdotString struct {
HeaderFieldNgdotString *HeaderFieldNgdotStringArgs `protobuf:"bytes,6,opt,name=HeaderFieldNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_HeaderFieldNgdotSize struct {
HeaderFieldNgdotSize *HeaderFieldNgdotSizeArgs `protobuf:"bytes,7,opt,name=HeaderFieldNgdotSize,proto3,oneof"`
}
type NgoloFuzzOne_DecoderNgdotSetMaxStringLength struct {
DecoderNgdotSetMaxStringLength *DecoderNgdotSetMaxStringLengthArgs `protobuf:"bytes,8,opt,name=DecoderNgdotSetMaxStringLength,proto3,oneof"`
}
type NgoloFuzzOne_DecoderNgdotSetEmitEnabled struct {
DecoderNgdotSetEmitEnabled *DecoderNgdotSetEmitEnabledArgs `protobuf:"bytes,9,opt,name=DecoderNgdotSetEmitEnabled,proto3,oneof"`
}
type NgoloFuzzOne_DecoderNgdotEmitEnabled struct {
DecoderNgdotEmitEnabled *DecoderNgdotEmitEnabledArgs `protobuf:"bytes,10,opt,name=DecoderNgdotEmitEnabled,proto3,oneof"`
}
type NgoloFuzzOne_DecoderNgdotSetMaxDynamicTableSize struct {
DecoderNgdotSetMaxDynamicTableSize *DecoderNgdotSetMaxDynamicTableSizeArgs `protobuf:"bytes,11,opt,name=DecoderNgdotSetMaxDynamicTableSize,proto3,oneof"`
}
type NgoloFuzzOne_DecoderNgdotSetAllowedMaxDynamicTableSize struct {
DecoderNgdotSetAllowedMaxDynamicTableSize *DecoderNgdotSetAllowedMaxDynamicTableSizeArgs `protobuf:"bytes,12,opt,name=DecoderNgdotSetAllowedMaxDynamicTableSize,proto3,oneof"`
}
type NgoloFuzzOne_DecoderNgdotDecodeFull struct {
DecoderNgdotDecodeFull *DecoderNgdotDecodeFullArgs `protobuf:"bytes,13,opt,name=DecoderNgdotDecodeFull,proto3,oneof"`
}
type NgoloFuzzOne_DecoderNgdotClose struct {
DecoderNgdotClose *DecoderNgdotCloseArgs `protobuf:"bytes,14,opt,name=DecoderNgdotClose,proto3,oneof"`
}
type NgoloFuzzOne_DecoderNgdotWrite struct {
DecoderNgdotWrite *DecoderNgdotWriteArgs `protobuf:"bytes,15,opt,name=DecoderNgdotWrite,proto3,oneof"`
}
type NgoloFuzzOne_HuffmanDecode struct {
HuffmanDecode *HuffmanDecodeArgs `protobuf:"bytes,16,opt,name=HuffmanDecode,proto3,oneof"`
}
type NgoloFuzzOne_HuffmanDecodeToString struct {
HuffmanDecodeToString *HuffmanDecodeToStringArgs `protobuf:"bytes,17,opt,name=HuffmanDecodeToString,proto3,oneof"`
}
type NgoloFuzzOne_AppendHuffmanString struct {
AppendHuffmanString *AppendHuffmanStringArgs `protobuf:"bytes,18,opt,name=AppendHuffmanString,proto3,oneof"`
}
type NgoloFuzzOne_HuffmanEncodeLength struct {
HuffmanEncodeLength *HuffmanEncodeLengthArgs `protobuf:"bytes,19,opt,name=HuffmanEncodeLength,proto3,oneof"`
}
func (*NgoloFuzzOne_NewEncoder) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_EncoderNgdotSetMaxDynamicTableSize) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_EncoderNgdotMaxDynamicTableSize) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_EncoderNgdotSetMaxDynamicTableSizeLimit) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_HeaderFieldNgdotIsPseudo) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_HeaderFieldNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_HeaderFieldNgdotSize) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_DecoderNgdotSetMaxStringLength) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_DecoderNgdotSetEmitEnabled) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_DecoderNgdotEmitEnabled) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_DecoderNgdotSetMaxDynamicTableSize) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_DecoderNgdotSetAllowedMaxDynamicTableSize) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_DecoderNgdotDecodeFull) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_DecoderNgdotClose) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_DecoderNgdotWrite) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_HuffmanDecode) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_HuffmanDecodeToString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_AppendHuffmanString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_HuffmanEncodeLength) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[21]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[21]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{21}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[22]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[22]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{22}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"[\n" +
"\x11HeaderFieldStruct\x12\x12\n" +
"\x04Name\x18\x01 \x01(\tR\x04Name\x12\x14\n" +
"\x05Value\x18\x02 \x01(\tR\x05Value\x12\x1c\n" +
"\tSensitive\x18\x03 \x01(\bR\tSensitive\"\x1e\n" +
"\x0eNewEncoderArgs\x12\f\n" +
"\x01w\x18\x01 \x01(\fR\x01w\"6\n" +
"&EncoderNgdotSetMaxDynamicTableSizeArgs\x12\f\n" +
"\x01v\x18\x01 \x01(\rR\x01v\"%\n" +
"#EncoderNgdotMaxDynamicTableSizeArgs\";\n" +
"+EncoderNgdotSetMaxDynamicTableSizeLimitArgs\x12\f\n" +
"\x01v\x18\x01 \x01(\rR\x01v\"L\n" +
"\x1cHeaderFieldNgdotIsPseudoArgs\x12,\n" +
"\x02hf\x18\x01 \x01(\v2\x1c.ngolofuzz.HeaderFieldStructR\x02hf\"J\n" +
"\x1aHeaderFieldNgdotStringArgs\x12,\n" +
"\x02hf\x18\x01 \x01(\v2\x1c.ngolofuzz.HeaderFieldStructR\x02hf\"H\n" +
"\x18HeaderFieldNgdotSizeArgs\x12,\n" +
"\x02hf\x18\x01 \x01(\v2\x1c.ngolofuzz.HeaderFieldStructR\x02hf\"2\n" +
"\"DecoderNgdotSetMaxStringLengthArgs\x12\f\n" +
"\x01n\x18\x01 \x01(\x03R\x01n\".\n" +
"\x1eDecoderNgdotSetEmitEnabledArgs\x12\f\n" +
"\x01v\x18\x01 \x01(\bR\x01v\"\x1d\n" +
"\x1bDecoderNgdotEmitEnabledArgs\"6\n" +
"&DecoderNgdotSetMaxDynamicTableSizeArgs\x12\f\n" +
"\x01v\x18\x01 \x01(\rR\x01v\"=\n" +
"-DecoderNgdotSetAllowedMaxDynamicTableSizeArgs\x12\f\n" +
"\x01v\x18\x01 \x01(\rR\x01v\"*\n" +
"\x1aDecoderNgdotDecodeFullArgs\x12\f\n" +
"\x01p\x18\x01 \x01(\fR\x01p\"\x17\n" +
"\x15DecoderNgdotCloseArgs\"%\n" +
"\x15DecoderNgdotWriteArgs\x12\f\n" +
"\x01p\x18\x01 \x01(\fR\x01p\"/\n" +
"\x11HuffmanDecodeArgs\x12\f\n" +
"\x01w\x18\x01 \x01(\fR\x01w\x12\f\n" +
"\x01v\x18\x02 \x01(\fR\x01v\")\n" +
"\x19HuffmanDecodeToStringArgs\x12\f\n" +
"\x01v\x18\x01 \x01(\fR\x01v\"9\n" +
"\x17AppendHuffmanStringArgs\x12\x10\n" +
"\x03dst\x18\x01 \x01(\fR\x03dst\x12\f\n" +
"\x01s\x18\x02 \x01(\tR\x01s\"'\n" +
"\x17HuffmanEncodeLengthArgs\x12\f\n" +
"\x01s\x18\x01 \x01(\tR\x01s\"\xd1\x0f\n" +
"\fNgoloFuzzOne\x12;\n" +
"\n" +
"NewEncoder\x18\x01 \x01(\v2\x19.ngolofuzz.NewEncoderArgsH\x00R\n" +
"NewEncoder\x12\x83\x01\n" +
"\"EncoderNgdotSetMaxDynamicTableSize\x18\x02 \x01(\v21.ngolofuzz.EncoderNgdotSetMaxDynamicTableSizeArgsH\x00R\"EncoderNgdotSetMaxDynamicTableSize\x12z\n" +
"\x1fEncoderNgdotMaxDynamicTableSize\x18\x03 \x01(\v2..ngolofuzz.EncoderNgdotMaxDynamicTableSizeArgsH\x00R\x1fEncoderNgdotMaxDynamicTableSize\x12\x92\x01\n" +
"'EncoderNgdotSetMaxDynamicTableSizeLimit\x18\x04 \x01(\v26.ngolofuzz.EncoderNgdotSetMaxDynamicTableSizeLimitArgsH\x00R'EncoderNgdotSetMaxDynamicTableSizeLimit\x12e\n" +
"\x18HeaderFieldNgdotIsPseudo\x18\x05 \x01(\v2'.ngolofuzz.HeaderFieldNgdotIsPseudoArgsH\x00R\x18HeaderFieldNgdotIsPseudo\x12_\n" +
"\x16HeaderFieldNgdotString\x18\x06 \x01(\v2%.ngolofuzz.HeaderFieldNgdotStringArgsH\x00R\x16HeaderFieldNgdotString\x12Y\n" +
"\x14HeaderFieldNgdotSize\x18\a \x01(\v2#.ngolofuzz.HeaderFieldNgdotSizeArgsH\x00R\x14HeaderFieldNgdotSize\x12w\n" +
"\x1eDecoderNgdotSetMaxStringLength\x18\b \x01(\v2-.ngolofuzz.DecoderNgdotSetMaxStringLengthArgsH\x00R\x1eDecoderNgdotSetMaxStringLength\x12k\n" +
"\x1aDecoderNgdotSetEmitEnabled\x18\t \x01(\v2).ngolofuzz.DecoderNgdotSetEmitEnabledArgsH\x00R\x1aDecoderNgdotSetEmitEnabled\x12b\n" +
"\x17DecoderNgdotEmitEnabled\x18\n" +
" \x01(\v2&.ngolofuzz.DecoderNgdotEmitEnabledArgsH\x00R\x17DecoderNgdotEmitEnabled\x12\x83\x01\n" +
"\"DecoderNgdotSetMaxDynamicTableSize\x18\v \x01(\v21.ngolofuzz.DecoderNgdotSetMaxDynamicTableSizeArgsH\x00R\"DecoderNgdotSetMaxDynamicTableSize\x12\x98\x01\n" +
")DecoderNgdotSetAllowedMaxDynamicTableSize\x18\f \x01(\v28.ngolofuzz.DecoderNgdotSetAllowedMaxDynamicTableSizeArgsH\x00R)DecoderNgdotSetAllowedMaxDynamicTableSize\x12_\n" +
"\x16DecoderNgdotDecodeFull\x18\r \x01(\v2%.ngolofuzz.DecoderNgdotDecodeFullArgsH\x00R\x16DecoderNgdotDecodeFull\x12P\n" +
"\x11DecoderNgdotClose\x18\x0e \x01(\v2 .ngolofuzz.DecoderNgdotCloseArgsH\x00R\x11DecoderNgdotClose\x12P\n" +
"\x11DecoderNgdotWrite\x18\x0f \x01(\v2 .ngolofuzz.DecoderNgdotWriteArgsH\x00R\x11DecoderNgdotWrite\x12D\n" +
"\rHuffmanDecode\x18\x10 \x01(\v2\x1c.ngolofuzz.HuffmanDecodeArgsH\x00R\rHuffmanDecode\x12\\\n" +
"\x15HuffmanDecodeToString\x18\x11 \x01(\v2$.ngolofuzz.HuffmanDecodeToStringArgsH\x00R\x15HuffmanDecodeToString\x12V\n" +
"\x13AppendHuffmanString\x18\x12 \x01(\v2\".ngolofuzz.AppendHuffmanStringArgsH\x00R\x13AppendHuffmanString\x12V\n" +
"\x13HuffmanEncodeLength\x18\x13 \x01(\v2\".ngolofuzz.HuffmanEncodeLengthArgsH\x00R\x13HuffmanEncodeLengthB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1eZ\x1c./;fuzz_ng_x_net_http2_hpackb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 23)
var file_ngolofuzz_proto_goTypes = []any{
(*HeaderFieldStruct)(nil), // 0: ngolofuzz.HeaderFieldStruct
(*NewEncoderArgs)(nil), // 1: ngolofuzz.NewEncoderArgs
(*EncoderNgdotSetMaxDynamicTableSizeArgs)(nil), // 2: ngolofuzz.EncoderNgdotSetMaxDynamicTableSizeArgs
(*EncoderNgdotMaxDynamicTableSizeArgs)(nil), // 3: ngolofuzz.EncoderNgdotMaxDynamicTableSizeArgs
(*EncoderNgdotSetMaxDynamicTableSizeLimitArgs)(nil), // 4: ngolofuzz.EncoderNgdotSetMaxDynamicTableSizeLimitArgs
(*HeaderFieldNgdotIsPseudoArgs)(nil), // 5: ngolofuzz.HeaderFieldNgdotIsPseudoArgs
(*HeaderFieldNgdotStringArgs)(nil), // 6: ngolofuzz.HeaderFieldNgdotStringArgs
(*HeaderFieldNgdotSizeArgs)(nil), // 7: ngolofuzz.HeaderFieldNgdotSizeArgs
(*DecoderNgdotSetMaxStringLengthArgs)(nil), // 8: ngolofuzz.DecoderNgdotSetMaxStringLengthArgs
(*DecoderNgdotSetEmitEnabledArgs)(nil), // 9: ngolofuzz.DecoderNgdotSetEmitEnabledArgs
(*DecoderNgdotEmitEnabledArgs)(nil), // 10: ngolofuzz.DecoderNgdotEmitEnabledArgs
(*DecoderNgdotSetMaxDynamicTableSizeArgs)(nil), // 11: ngolofuzz.DecoderNgdotSetMaxDynamicTableSizeArgs
(*DecoderNgdotSetAllowedMaxDynamicTableSizeArgs)(nil), // 12: ngolofuzz.DecoderNgdotSetAllowedMaxDynamicTableSizeArgs
(*DecoderNgdotDecodeFullArgs)(nil), // 13: ngolofuzz.DecoderNgdotDecodeFullArgs
(*DecoderNgdotCloseArgs)(nil), // 14: ngolofuzz.DecoderNgdotCloseArgs
(*DecoderNgdotWriteArgs)(nil), // 15: ngolofuzz.DecoderNgdotWriteArgs
(*HuffmanDecodeArgs)(nil), // 16: ngolofuzz.HuffmanDecodeArgs
(*HuffmanDecodeToStringArgs)(nil), // 17: ngolofuzz.HuffmanDecodeToStringArgs
(*AppendHuffmanStringArgs)(nil), // 18: ngolofuzz.AppendHuffmanStringArgs
(*HuffmanEncodeLengthArgs)(nil), // 19: ngolofuzz.HuffmanEncodeLengthArgs
(*NgoloFuzzOne)(nil), // 20: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 21: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 22: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.HeaderFieldNgdotIsPseudoArgs.hf:type_name -> ngolofuzz.HeaderFieldStruct
0, // 1: ngolofuzz.HeaderFieldNgdotStringArgs.hf:type_name -> ngolofuzz.HeaderFieldStruct
0, // 2: ngolofuzz.HeaderFieldNgdotSizeArgs.hf:type_name -> ngolofuzz.HeaderFieldStruct
1, // 3: ngolofuzz.NgoloFuzzOne.NewEncoder:type_name -> ngolofuzz.NewEncoderArgs
2, // 4: ngolofuzz.NgoloFuzzOne.EncoderNgdotSetMaxDynamicTableSize:type_name -> ngolofuzz.EncoderNgdotSetMaxDynamicTableSizeArgs
3, // 5: ngolofuzz.NgoloFuzzOne.EncoderNgdotMaxDynamicTableSize:type_name -> ngolofuzz.EncoderNgdotMaxDynamicTableSizeArgs
4, // 6: ngolofuzz.NgoloFuzzOne.EncoderNgdotSetMaxDynamicTableSizeLimit:type_name -> ngolofuzz.EncoderNgdotSetMaxDynamicTableSizeLimitArgs
5, // 7: ngolofuzz.NgoloFuzzOne.HeaderFieldNgdotIsPseudo:type_name -> ngolofuzz.HeaderFieldNgdotIsPseudoArgs
6, // 8: ngolofuzz.NgoloFuzzOne.HeaderFieldNgdotString:type_name -> ngolofuzz.HeaderFieldNgdotStringArgs
7, // 9: ngolofuzz.NgoloFuzzOne.HeaderFieldNgdotSize:type_name -> ngolofuzz.HeaderFieldNgdotSizeArgs
8, // 10: ngolofuzz.NgoloFuzzOne.DecoderNgdotSetMaxStringLength:type_name -> ngolofuzz.DecoderNgdotSetMaxStringLengthArgs
9, // 11: ngolofuzz.NgoloFuzzOne.DecoderNgdotSetEmitEnabled:type_name -> ngolofuzz.DecoderNgdotSetEmitEnabledArgs
10, // 12: ngolofuzz.NgoloFuzzOne.DecoderNgdotEmitEnabled:type_name -> ngolofuzz.DecoderNgdotEmitEnabledArgs
11, // 13: ngolofuzz.NgoloFuzzOne.DecoderNgdotSetMaxDynamicTableSize:type_name -> ngolofuzz.DecoderNgdotSetMaxDynamicTableSizeArgs
12, // 14: ngolofuzz.NgoloFuzzOne.DecoderNgdotSetAllowedMaxDynamicTableSize:type_name -> ngolofuzz.DecoderNgdotSetAllowedMaxDynamicTableSizeArgs
13, // 15: ngolofuzz.NgoloFuzzOne.DecoderNgdotDecodeFull:type_name -> ngolofuzz.DecoderNgdotDecodeFullArgs
14, // 16: ngolofuzz.NgoloFuzzOne.DecoderNgdotClose:type_name -> ngolofuzz.DecoderNgdotCloseArgs
15, // 17: ngolofuzz.NgoloFuzzOne.DecoderNgdotWrite:type_name -> ngolofuzz.DecoderNgdotWriteArgs
16, // 18: ngolofuzz.NgoloFuzzOne.HuffmanDecode:type_name -> ngolofuzz.HuffmanDecodeArgs
17, // 19: ngolofuzz.NgoloFuzzOne.HuffmanDecodeToString:type_name -> ngolofuzz.HuffmanDecodeToStringArgs
18, // 20: ngolofuzz.NgoloFuzzOne.AppendHuffmanString:type_name -> ngolofuzz.AppendHuffmanStringArgs
19, // 21: ngolofuzz.NgoloFuzzOne.HuffmanEncodeLength:type_name -> ngolofuzz.HuffmanEncodeLengthArgs
20, // 22: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
23, // [23:23] is the sub-list for method output_type
23, // [23:23] is the sub-list for method input_type
23, // [23:23] is the sub-list for extension type_name
23, // [23:23] is the sub-list for extension extendee
0, // [0:23] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[20].OneofWrappers = []any{
(*NgoloFuzzOne_NewEncoder)(nil),
(*NgoloFuzzOne_EncoderNgdotSetMaxDynamicTableSize)(nil),
(*NgoloFuzzOne_EncoderNgdotMaxDynamicTableSize)(nil),
(*NgoloFuzzOne_EncoderNgdotSetMaxDynamicTableSizeLimit)(nil),
(*NgoloFuzzOne_HeaderFieldNgdotIsPseudo)(nil),
(*NgoloFuzzOne_HeaderFieldNgdotString)(nil),
(*NgoloFuzzOne_HeaderFieldNgdotSize)(nil),
(*NgoloFuzzOne_DecoderNgdotSetMaxStringLength)(nil),
(*NgoloFuzzOne_DecoderNgdotSetEmitEnabled)(nil),
(*NgoloFuzzOne_DecoderNgdotEmitEnabled)(nil),
(*NgoloFuzzOne_DecoderNgdotSetMaxDynamicTableSize)(nil),
(*NgoloFuzzOne_DecoderNgdotSetAllowedMaxDynamicTableSize)(nil),
(*NgoloFuzzOne_DecoderNgdotDecodeFull)(nil),
(*NgoloFuzzOne_DecoderNgdotClose)(nil),
(*NgoloFuzzOne_DecoderNgdotWrite)(nil),
(*NgoloFuzzOne_HuffmanDecode)(nil),
(*NgoloFuzzOne_HuffmanDecodeToString)(nil),
(*NgoloFuzzOne_AppendHuffmanString)(nil),
(*NgoloFuzzOne_HuffmanEncodeLength)(nil),
}
file_ngolofuzz_proto_msgTypes[21].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 23,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_net_http_httpguts
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/net/http/httpguts"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_ValidTrailerHeader:
httpguts.ValidTrailerHeader(a.ValidTrailerHeader.Name)
case *NgoloFuzzOne_IsTokenRune:
arg0 := GetRune(a.IsTokenRune.R)
httpguts.IsTokenRune(arg0)
case *NgoloFuzzOne_HeaderValuesContainsToken:
httpguts.HeaderValuesContainsToken(a.HeaderValuesContainsToken.Values, a.HeaderValuesContainsToken.Token)
case *NgoloFuzzOne_ValidHeaderFieldName:
httpguts.ValidHeaderFieldName(a.ValidHeaderFieldName.V)
case *NgoloFuzzOne_ValidHostHeader:
httpguts.ValidHostHeader(a.ValidHostHeader.H)
case *NgoloFuzzOne_ValidHeaderFieldValue:
httpguts.ValidHeaderFieldValue(a.ValidHeaderFieldValue.V)
case *NgoloFuzzOne_PunycodeHostPort:
_, r1 := httpguts.PunycodeHostPort(a.PunycodeHostPort.V)
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_ValidTrailerHeader:
w.WriteString(fmt.Sprintf("httpguts.ValidTrailerHeader(%#+v)\n", a.ValidTrailerHeader.Name))
case *NgoloFuzzOne_IsTokenRune:
w.WriteString(fmt.Sprintf("httpguts.IsTokenRune(GetRune(%#+v))\n", a.IsTokenRune.R))
case *NgoloFuzzOne_HeaderValuesContainsToken:
w.WriteString(fmt.Sprintf("httpguts.HeaderValuesContainsToken(%#+v, %#+v)\n", a.HeaderValuesContainsToken.Values, a.HeaderValuesContainsToken.Token))
case *NgoloFuzzOne_ValidHeaderFieldName:
w.WriteString(fmt.Sprintf("httpguts.ValidHeaderFieldName(%#+v)\n", a.ValidHeaderFieldName.V))
case *NgoloFuzzOne_ValidHostHeader:
w.WriteString(fmt.Sprintf("httpguts.ValidHostHeader(%#+v)\n", a.ValidHostHeader.H))
case *NgoloFuzzOne_ValidHeaderFieldValue:
w.WriteString(fmt.Sprintf("httpguts.ValidHeaderFieldValue(%#+v)\n", a.ValidHeaderFieldValue.V))
case *NgoloFuzzOne_PunycodeHostPort:
w.WriteString(fmt.Sprintf("httpguts.PunycodeHostPort(%#+v)\n", a.PunycodeHostPort.V))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_net_http_httpguts
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ValidTrailerHeaderArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ValidTrailerHeaderArgs) Reset() {
*x = ValidTrailerHeaderArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ValidTrailerHeaderArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ValidTrailerHeaderArgs) ProtoMessage() {}
func (x *ValidTrailerHeaderArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ValidTrailerHeaderArgs.ProtoReflect.Descriptor instead.
func (*ValidTrailerHeaderArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *ValidTrailerHeaderArgs) GetName() string {
if x != nil {
return x.Name
}
return ""
}
type IsTokenRuneArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R string `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *IsTokenRuneArgs) Reset() {
*x = IsTokenRuneArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *IsTokenRuneArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*IsTokenRuneArgs) ProtoMessage() {}
func (x *IsTokenRuneArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use IsTokenRuneArgs.ProtoReflect.Descriptor instead.
func (*IsTokenRuneArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *IsTokenRuneArgs) GetR() string {
if x != nil {
return x.R
}
return ""
}
type HeaderValuesContainsTokenArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Values []string `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"`
Token string `protobuf:"bytes,2,opt,name=token,proto3" json:"token,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HeaderValuesContainsTokenArgs) Reset() {
*x = HeaderValuesContainsTokenArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HeaderValuesContainsTokenArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HeaderValuesContainsTokenArgs) ProtoMessage() {}
func (x *HeaderValuesContainsTokenArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HeaderValuesContainsTokenArgs.ProtoReflect.Descriptor instead.
func (*HeaderValuesContainsTokenArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *HeaderValuesContainsTokenArgs) GetValues() []string {
if x != nil {
return x.Values
}
return nil
}
func (x *HeaderValuesContainsTokenArgs) GetToken() string {
if x != nil {
return x.Token
}
return ""
}
type ValidHeaderFieldNameArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
V string `protobuf:"bytes,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ValidHeaderFieldNameArgs) Reset() {
*x = ValidHeaderFieldNameArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ValidHeaderFieldNameArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ValidHeaderFieldNameArgs) ProtoMessage() {}
func (x *ValidHeaderFieldNameArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ValidHeaderFieldNameArgs.ProtoReflect.Descriptor instead.
func (*ValidHeaderFieldNameArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *ValidHeaderFieldNameArgs) GetV() string {
if x != nil {
return x.V
}
return ""
}
type ValidHostHeaderArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
H string `protobuf:"bytes,1,opt,name=h,proto3" json:"h,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ValidHostHeaderArgs) Reset() {
*x = ValidHostHeaderArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ValidHostHeaderArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ValidHostHeaderArgs) ProtoMessage() {}
func (x *ValidHostHeaderArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ValidHostHeaderArgs.ProtoReflect.Descriptor instead.
func (*ValidHostHeaderArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *ValidHostHeaderArgs) GetH() string {
if x != nil {
return x.H
}
return ""
}
type ValidHeaderFieldValueArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
V string `protobuf:"bytes,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ValidHeaderFieldValueArgs) Reset() {
*x = ValidHeaderFieldValueArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ValidHeaderFieldValueArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ValidHeaderFieldValueArgs) ProtoMessage() {}
func (x *ValidHeaderFieldValueArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ValidHeaderFieldValueArgs.ProtoReflect.Descriptor instead.
func (*ValidHeaderFieldValueArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *ValidHeaderFieldValueArgs) GetV() string {
if x != nil {
return x.V
}
return ""
}
type PunycodeHostPortArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
V string `protobuf:"bytes,1,opt,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PunycodeHostPortArgs) Reset() {
*x = PunycodeHostPortArgs{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PunycodeHostPortArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PunycodeHostPortArgs) ProtoMessage() {}
func (x *PunycodeHostPortArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PunycodeHostPortArgs.ProtoReflect.Descriptor instead.
func (*PunycodeHostPortArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *PunycodeHostPortArgs) GetV() string {
if x != nil {
return x.V
}
return ""
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_ValidTrailerHeader
// *NgoloFuzzOne_IsTokenRune
// *NgoloFuzzOne_HeaderValuesContainsToken
// *NgoloFuzzOne_ValidHeaderFieldName
// *NgoloFuzzOne_ValidHostHeader
// *NgoloFuzzOne_ValidHeaderFieldValue
// *NgoloFuzzOne_PunycodeHostPort
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetValidTrailerHeader() *ValidTrailerHeaderArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ValidTrailerHeader); ok {
return x.ValidTrailerHeader
}
}
return nil
}
func (x *NgoloFuzzOne) GetIsTokenRune() *IsTokenRuneArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_IsTokenRune); ok {
return x.IsTokenRune
}
}
return nil
}
func (x *NgoloFuzzOne) GetHeaderValuesContainsToken() *HeaderValuesContainsTokenArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_HeaderValuesContainsToken); ok {
return x.HeaderValuesContainsToken
}
}
return nil
}
func (x *NgoloFuzzOne) GetValidHeaderFieldName() *ValidHeaderFieldNameArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ValidHeaderFieldName); ok {
return x.ValidHeaderFieldName
}
}
return nil
}
func (x *NgoloFuzzOne) GetValidHostHeader() *ValidHostHeaderArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ValidHostHeader); ok {
return x.ValidHostHeader
}
}
return nil
}
func (x *NgoloFuzzOne) GetValidHeaderFieldValue() *ValidHeaderFieldValueArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ValidHeaderFieldValue); ok {
return x.ValidHeaderFieldValue
}
}
return nil
}
func (x *NgoloFuzzOne) GetPunycodeHostPort() *PunycodeHostPortArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_PunycodeHostPort); ok {
return x.PunycodeHostPort
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_ValidTrailerHeader struct {
ValidTrailerHeader *ValidTrailerHeaderArgs `protobuf:"bytes,1,opt,name=ValidTrailerHeader,proto3,oneof"`
}
type NgoloFuzzOne_IsTokenRune struct {
IsTokenRune *IsTokenRuneArgs `protobuf:"bytes,2,opt,name=IsTokenRune,proto3,oneof"`
}
type NgoloFuzzOne_HeaderValuesContainsToken struct {
HeaderValuesContainsToken *HeaderValuesContainsTokenArgs `protobuf:"bytes,3,opt,name=HeaderValuesContainsToken,proto3,oneof"`
}
type NgoloFuzzOne_ValidHeaderFieldName struct {
ValidHeaderFieldName *ValidHeaderFieldNameArgs `protobuf:"bytes,4,opt,name=ValidHeaderFieldName,proto3,oneof"`
}
type NgoloFuzzOne_ValidHostHeader struct {
ValidHostHeader *ValidHostHeaderArgs `protobuf:"bytes,5,opt,name=ValidHostHeader,proto3,oneof"`
}
type NgoloFuzzOne_ValidHeaderFieldValue struct {
ValidHeaderFieldValue *ValidHeaderFieldValueArgs `protobuf:"bytes,6,opt,name=ValidHeaderFieldValue,proto3,oneof"`
}
type NgoloFuzzOne_PunycodeHostPort struct {
PunycodeHostPort *PunycodeHostPortArgs `protobuf:"bytes,7,opt,name=PunycodeHostPort,proto3,oneof"`
}
func (*NgoloFuzzOne_ValidTrailerHeader) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_IsTokenRune) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_HeaderValuesContainsToken) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ValidHeaderFieldName) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ValidHostHeader) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ValidHeaderFieldValue) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_PunycodeHostPort) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\",\n" +
"\x16ValidTrailerHeaderArgs\x12\x12\n" +
"\x04name\x18\x01 \x01(\tR\x04name\"\x1f\n" +
"\x0fIsTokenRuneArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\tR\x01r\"M\n" +
"\x1dHeaderValuesContainsTokenArgs\x12\x16\n" +
"\x06values\x18\x01 \x03(\tR\x06values\x12\x14\n" +
"\x05token\x18\x02 \x01(\tR\x05token\"(\n" +
"\x18ValidHeaderFieldNameArgs\x12\f\n" +
"\x01v\x18\x01 \x01(\tR\x01v\"#\n" +
"\x13ValidHostHeaderArgs\x12\f\n" +
"\x01h\x18\x01 \x01(\tR\x01h\")\n" +
"\x19ValidHeaderFieldValueArgs\x12\f\n" +
"\x01v\x18\x01 \x01(\tR\x01v\"$\n" +
"\x14PunycodeHostPortArgs\x12\f\n" +
"\x01v\x18\x01 \x01(\tR\x01v\"\xe9\x04\n" +
"\fNgoloFuzzOne\x12S\n" +
"\x12ValidTrailerHeader\x18\x01 \x01(\v2!.ngolofuzz.ValidTrailerHeaderArgsH\x00R\x12ValidTrailerHeader\x12>\n" +
"\vIsTokenRune\x18\x02 \x01(\v2\x1a.ngolofuzz.IsTokenRuneArgsH\x00R\vIsTokenRune\x12h\n" +
"\x19HeaderValuesContainsToken\x18\x03 \x01(\v2(.ngolofuzz.HeaderValuesContainsTokenArgsH\x00R\x19HeaderValuesContainsToken\x12Y\n" +
"\x14ValidHeaderFieldName\x18\x04 \x01(\v2#.ngolofuzz.ValidHeaderFieldNameArgsH\x00R\x14ValidHeaderFieldName\x12J\n" +
"\x0fValidHostHeader\x18\x05 \x01(\v2\x1e.ngolofuzz.ValidHostHeaderArgsH\x00R\x0fValidHostHeader\x12\\\n" +
"\x15ValidHeaderFieldValue\x18\x06 \x01(\v2$.ngolofuzz.ValidHeaderFieldValueArgsH\x00R\x15ValidHeaderFieldValue\x12M\n" +
"\x10PunycodeHostPort\x18\a \x01(\v2\x1f.ngolofuzz.PunycodeHostPortArgsH\x00R\x10PunycodeHostPortB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB Z\x1e./;fuzz_ng_x_net_http_httpgutsb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
var file_ngolofuzz_proto_goTypes = []any{
(*ValidTrailerHeaderArgs)(nil), // 0: ngolofuzz.ValidTrailerHeaderArgs
(*IsTokenRuneArgs)(nil), // 1: ngolofuzz.IsTokenRuneArgs
(*HeaderValuesContainsTokenArgs)(nil), // 2: ngolofuzz.HeaderValuesContainsTokenArgs
(*ValidHeaderFieldNameArgs)(nil), // 3: ngolofuzz.ValidHeaderFieldNameArgs
(*ValidHostHeaderArgs)(nil), // 4: ngolofuzz.ValidHostHeaderArgs
(*ValidHeaderFieldValueArgs)(nil), // 5: ngolofuzz.ValidHeaderFieldValueArgs
(*PunycodeHostPortArgs)(nil), // 6: ngolofuzz.PunycodeHostPortArgs
(*NgoloFuzzOne)(nil), // 7: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 8: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 9: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.ValidTrailerHeader:type_name -> ngolofuzz.ValidTrailerHeaderArgs
1, // 1: ngolofuzz.NgoloFuzzOne.IsTokenRune:type_name -> ngolofuzz.IsTokenRuneArgs
2, // 2: ngolofuzz.NgoloFuzzOne.HeaderValuesContainsToken:type_name -> ngolofuzz.HeaderValuesContainsTokenArgs
3, // 3: ngolofuzz.NgoloFuzzOne.ValidHeaderFieldName:type_name -> ngolofuzz.ValidHeaderFieldNameArgs
4, // 4: ngolofuzz.NgoloFuzzOne.ValidHostHeader:type_name -> ngolofuzz.ValidHostHeaderArgs
5, // 5: ngolofuzz.NgoloFuzzOne.ValidHeaderFieldValue:type_name -> ngolofuzz.ValidHeaderFieldValueArgs
6, // 6: ngolofuzz.NgoloFuzzOne.PunycodeHostPort:type_name -> ngolofuzz.PunycodeHostPortArgs
7, // 7: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
8, // [8:8] is the sub-list for method output_type
8, // [8:8] is the sub-list for method input_type
8, // [8:8] is the sub-list for extension type_name
8, // [8:8] is the sub-list for extension extendee
0, // [0:8] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[7].OneofWrappers = []any{
(*NgoloFuzzOne_ValidTrailerHeader)(nil),
(*NgoloFuzzOne_IsTokenRune)(nil),
(*NgoloFuzzOne_HeaderValuesContainsToken)(nil),
(*NgoloFuzzOne_ValidHeaderFieldName)(nil),
(*NgoloFuzzOne_ValidHostHeader)(nil),
(*NgoloFuzzOne_ValidHeaderFieldValue)(nil),
(*NgoloFuzzOne_PunycodeHostPort)(nil),
}
file_ngolofuzz_proto_msgTypes[8].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 10,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_net_idna
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/net/idna"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var ProfileResults []*idna.Profile
ProfileResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_ToASCII:
_, r1 := idna.ToASCII(a.ToASCII.S)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_ToUnicode:
_, r1 := idna.ToUnicode(a.ToUnicode.S)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_Transitional:
idna.Transitional(a.Transitional.Transitional)
case *NgoloFuzzOne_VerifyDNSLength:
idna.VerifyDNSLength(a.VerifyDNSLength.Verify)
case *NgoloFuzzOne_RemoveLeadingDots:
idna.RemoveLeadingDots(a.RemoveLeadingDots.Remove)
case *NgoloFuzzOne_ValidateLabels:
idna.ValidateLabels(a.ValidateLabels.Enable)
case *NgoloFuzzOne_CheckHyphens:
idna.CheckHyphens(a.CheckHyphens.Enable)
case *NgoloFuzzOne_CheckJoiners:
idna.CheckJoiners(a.CheckJoiners.Enable)
case *NgoloFuzzOne_StrictDomainName:
idna.StrictDomainName(a.StrictDomainName.Use)
case *NgoloFuzzOne_BidiRule:
idna.BidiRule()
case *NgoloFuzzOne_ValidateForRegistration:
idna.ValidateForRegistration()
case *NgoloFuzzOne_MapForLookup:
idna.MapForLookup()
case *NgoloFuzzOne_ProfileNgdotToASCII:
if len(ProfileResults) == 0 {
continue
}
arg0 := ProfileResults[ProfileResultsIndex]
ProfileResultsIndex = (ProfileResultsIndex + 1) % len(ProfileResults)
_, r1 := arg0.ToASCII(a.ProfileNgdotToASCII.S)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_ProfileNgdotToUnicode:
if len(ProfileResults) == 0 {
continue
}
arg0 := ProfileResults[ProfileResultsIndex]
ProfileResultsIndex = (ProfileResultsIndex + 1) % len(ProfileResults)
_, r1 := arg0.ToUnicode(a.ProfileNgdotToUnicode.S)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_ProfileNgdotString:
if len(ProfileResults) == 0 {
continue
}
arg0 := ProfileResults[ProfileResultsIndex]
ProfileResultsIndex = (ProfileResultsIndex + 1) % len(ProfileResults)
arg0.String()
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
ProfileNb := 0
ProfileResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_ToASCII:
w.WriteString(fmt.Sprintf("idna.ToASCII(%#+v)\n", a.ToASCII.S))
case *NgoloFuzzOne_ToUnicode:
w.WriteString(fmt.Sprintf("idna.ToUnicode(%#+v)\n", a.ToUnicode.S))
case *NgoloFuzzOne_Transitional:
w.WriteString(fmt.Sprintf("idna.Transitional(%#+v)\n", a.Transitional.Transitional))
case *NgoloFuzzOne_VerifyDNSLength:
w.WriteString(fmt.Sprintf("idna.VerifyDNSLength(%#+v)\n", a.VerifyDNSLength.Verify))
case *NgoloFuzzOne_RemoveLeadingDots:
w.WriteString(fmt.Sprintf("idna.RemoveLeadingDots(%#+v)\n", a.RemoveLeadingDots.Remove))
case *NgoloFuzzOne_ValidateLabels:
w.WriteString(fmt.Sprintf("idna.ValidateLabels(%#+v)\n", a.ValidateLabels.Enable))
case *NgoloFuzzOne_CheckHyphens:
w.WriteString(fmt.Sprintf("idna.CheckHyphens(%#+v)\n", a.CheckHyphens.Enable))
case *NgoloFuzzOne_CheckJoiners:
w.WriteString(fmt.Sprintf("idna.CheckJoiners(%#+v)\n", a.CheckJoiners.Enable))
case *NgoloFuzzOne_StrictDomainName:
w.WriteString(fmt.Sprintf("idna.StrictDomainName(%#+v)\n", a.StrictDomainName.Use))
case *NgoloFuzzOne_BidiRule:
w.WriteString(fmt.Sprintf("idna.BidiRule()\n"))
case *NgoloFuzzOne_ValidateForRegistration:
w.WriteString(fmt.Sprintf("idna.ValidateForRegistration()\n"))
case *NgoloFuzzOne_MapForLookup:
w.WriteString(fmt.Sprintf("idna.MapForLookup()\n"))
case *NgoloFuzzOne_ProfileNgdotToASCII:
if ProfileNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Profile%d.ToASCII(%#+v)\n", ProfileResultsIndex, a.ProfileNgdotToASCII.S))
ProfileResultsIndex = (ProfileResultsIndex + 1) % ProfileNb
case *NgoloFuzzOne_ProfileNgdotToUnicode:
if ProfileNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Profile%d.ToUnicode(%#+v)\n", ProfileResultsIndex, a.ProfileNgdotToUnicode.S))
ProfileResultsIndex = (ProfileResultsIndex + 1) % ProfileNb
case *NgoloFuzzOne_ProfileNgdotString:
if ProfileNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Profile%d.String()\n", ProfileResultsIndex))
ProfileResultsIndex = (ProfileResultsIndex + 1) % ProfileNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_net_idna
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ToASCIIArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S string `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ToASCIIArgs) Reset() {
*x = ToASCIIArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ToASCIIArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ToASCIIArgs) ProtoMessage() {}
func (x *ToASCIIArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ToASCIIArgs.ProtoReflect.Descriptor instead.
func (*ToASCIIArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *ToASCIIArgs) GetS() string {
if x != nil {
return x.S
}
return ""
}
type ToUnicodeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S string `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ToUnicodeArgs) Reset() {
*x = ToUnicodeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ToUnicodeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ToUnicodeArgs) ProtoMessage() {}
func (x *ToUnicodeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ToUnicodeArgs.ProtoReflect.Descriptor instead.
func (*ToUnicodeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *ToUnicodeArgs) GetS() string {
if x != nil {
return x.S
}
return ""
}
type TransitionalArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Transitional bool `protobuf:"varint,1,opt,name=transitional,proto3" json:"transitional,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TransitionalArgs) Reset() {
*x = TransitionalArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TransitionalArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TransitionalArgs) ProtoMessage() {}
func (x *TransitionalArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TransitionalArgs.ProtoReflect.Descriptor instead.
func (*TransitionalArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *TransitionalArgs) GetTransitional() bool {
if x != nil {
return x.Transitional
}
return false
}
type VerifyDNSLengthArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Verify bool `protobuf:"varint,1,opt,name=verify,proto3" json:"verify,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *VerifyDNSLengthArgs) Reset() {
*x = VerifyDNSLengthArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *VerifyDNSLengthArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*VerifyDNSLengthArgs) ProtoMessage() {}
func (x *VerifyDNSLengthArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use VerifyDNSLengthArgs.ProtoReflect.Descriptor instead.
func (*VerifyDNSLengthArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *VerifyDNSLengthArgs) GetVerify() bool {
if x != nil {
return x.Verify
}
return false
}
type RemoveLeadingDotsArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Remove bool `protobuf:"varint,1,opt,name=remove,proto3" json:"remove,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RemoveLeadingDotsArgs) Reset() {
*x = RemoveLeadingDotsArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RemoveLeadingDotsArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RemoveLeadingDotsArgs) ProtoMessage() {}
func (x *RemoveLeadingDotsArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RemoveLeadingDotsArgs.ProtoReflect.Descriptor instead.
func (*RemoveLeadingDotsArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *RemoveLeadingDotsArgs) GetRemove() bool {
if x != nil {
return x.Remove
}
return false
}
type ValidateLabelsArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Enable bool `protobuf:"varint,1,opt,name=enable,proto3" json:"enable,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ValidateLabelsArgs) Reset() {
*x = ValidateLabelsArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ValidateLabelsArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ValidateLabelsArgs) ProtoMessage() {}
func (x *ValidateLabelsArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ValidateLabelsArgs.ProtoReflect.Descriptor instead.
func (*ValidateLabelsArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *ValidateLabelsArgs) GetEnable() bool {
if x != nil {
return x.Enable
}
return false
}
type CheckHyphensArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Enable bool `protobuf:"varint,1,opt,name=enable,proto3" json:"enable,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CheckHyphensArgs) Reset() {
*x = CheckHyphensArgs{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CheckHyphensArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CheckHyphensArgs) ProtoMessage() {}
func (x *CheckHyphensArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CheckHyphensArgs.ProtoReflect.Descriptor instead.
func (*CheckHyphensArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *CheckHyphensArgs) GetEnable() bool {
if x != nil {
return x.Enable
}
return false
}
type CheckJoinersArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Enable bool `protobuf:"varint,1,opt,name=enable,proto3" json:"enable,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CheckJoinersArgs) Reset() {
*x = CheckJoinersArgs{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CheckJoinersArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CheckJoinersArgs) ProtoMessage() {}
func (x *CheckJoinersArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CheckJoinersArgs.ProtoReflect.Descriptor instead.
func (*CheckJoinersArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
func (x *CheckJoinersArgs) GetEnable() bool {
if x != nil {
return x.Enable
}
return false
}
type StrictDomainNameArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Use bool `protobuf:"varint,1,opt,name=use,proto3" json:"use,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *StrictDomainNameArgs) Reset() {
*x = StrictDomainNameArgs{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *StrictDomainNameArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StrictDomainNameArgs) ProtoMessage() {}
func (x *StrictDomainNameArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StrictDomainNameArgs.ProtoReflect.Descriptor instead.
func (*StrictDomainNameArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
func (x *StrictDomainNameArgs) GetUse() bool {
if x != nil {
return x.Use
}
return false
}
type BidiRuleArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BidiRuleArgs) Reset() {
*x = BidiRuleArgs{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BidiRuleArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BidiRuleArgs) ProtoMessage() {}
func (x *BidiRuleArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BidiRuleArgs.ProtoReflect.Descriptor instead.
func (*BidiRuleArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
type ValidateForRegistrationArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ValidateForRegistrationArgs) Reset() {
*x = ValidateForRegistrationArgs{}
mi := &file_ngolofuzz_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ValidateForRegistrationArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ValidateForRegistrationArgs) ProtoMessage() {}
func (x *ValidateForRegistrationArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ValidateForRegistrationArgs.ProtoReflect.Descriptor instead.
func (*ValidateForRegistrationArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{10}
}
type MapForLookupArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *MapForLookupArgs) Reset() {
*x = MapForLookupArgs{}
mi := &file_ngolofuzz_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *MapForLookupArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MapForLookupArgs) ProtoMessage() {}
func (x *MapForLookupArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[11]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MapForLookupArgs.ProtoReflect.Descriptor instead.
func (*MapForLookupArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{11}
}
type ProfileNgdotToASCIIArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S string `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProfileNgdotToASCIIArgs) Reset() {
*x = ProfileNgdotToASCIIArgs{}
mi := &file_ngolofuzz_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProfileNgdotToASCIIArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProfileNgdotToASCIIArgs) ProtoMessage() {}
func (x *ProfileNgdotToASCIIArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[12]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProfileNgdotToASCIIArgs.ProtoReflect.Descriptor instead.
func (*ProfileNgdotToASCIIArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{12}
}
func (x *ProfileNgdotToASCIIArgs) GetS() string {
if x != nil {
return x.S
}
return ""
}
type ProfileNgdotToUnicodeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S string `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProfileNgdotToUnicodeArgs) Reset() {
*x = ProfileNgdotToUnicodeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProfileNgdotToUnicodeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProfileNgdotToUnicodeArgs) ProtoMessage() {}
func (x *ProfileNgdotToUnicodeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[13]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProfileNgdotToUnicodeArgs.ProtoReflect.Descriptor instead.
func (*ProfileNgdotToUnicodeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{13}
}
func (x *ProfileNgdotToUnicodeArgs) GetS() string {
if x != nil {
return x.S
}
return ""
}
type ProfileNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProfileNgdotStringArgs) Reset() {
*x = ProfileNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProfileNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProfileNgdotStringArgs) ProtoMessage() {}
func (x *ProfileNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[14]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProfileNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*ProfileNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{14}
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_ToASCII
// *NgoloFuzzOne_ToUnicode
// *NgoloFuzzOne_Transitional
// *NgoloFuzzOne_VerifyDNSLength
// *NgoloFuzzOne_RemoveLeadingDots
// *NgoloFuzzOne_ValidateLabels
// *NgoloFuzzOne_CheckHyphens
// *NgoloFuzzOne_CheckJoiners
// *NgoloFuzzOne_StrictDomainName
// *NgoloFuzzOne_BidiRule
// *NgoloFuzzOne_ValidateForRegistration
// *NgoloFuzzOne_MapForLookup
// *NgoloFuzzOne_ProfileNgdotToASCII
// *NgoloFuzzOne_ProfileNgdotToUnicode
// *NgoloFuzzOne_ProfileNgdotString
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[15]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{15}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetToASCII() *ToASCIIArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ToASCII); ok {
return x.ToASCII
}
}
return nil
}
func (x *NgoloFuzzOne) GetToUnicode() *ToUnicodeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ToUnicode); ok {
return x.ToUnicode
}
}
return nil
}
func (x *NgoloFuzzOne) GetTransitional() *TransitionalArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Transitional); ok {
return x.Transitional
}
}
return nil
}
func (x *NgoloFuzzOne) GetVerifyDNSLength() *VerifyDNSLengthArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_VerifyDNSLength); ok {
return x.VerifyDNSLength
}
}
return nil
}
func (x *NgoloFuzzOne) GetRemoveLeadingDots() *RemoveLeadingDotsArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_RemoveLeadingDots); ok {
return x.RemoveLeadingDots
}
}
return nil
}
func (x *NgoloFuzzOne) GetValidateLabels() *ValidateLabelsArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ValidateLabels); ok {
return x.ValidateLabels
}
}
return nil
}
func (x *NgoloFuzzOne) GetCheckHyphens() *CheckHyphensArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CheckHyphens); ok {
return x.CheckHyphens
}
}
return nil
}
func (x *NgoloFuzzOne) GetCheckJoiners() *CheckJoinersArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CheckJoiners); ok {
return x.CheckJoiners
}
}
return nil
}
func (x *NgoloFuzzOne) GetStrictDomainName() *StrictDomainNameArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_StrictDomainName); ok {
return x.StrictDomainName
}
}
return nil
}
func (x *NgoloFuzzOne) GetBidiRule() *BidiRuleArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BidiRule); ok {
return x.BidiRule
}
}
return nil
}
func (x *NgoloFuzzOne) GetValidateForRegistration() *ValidateForRegistrationArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ValidateForRegistration); ok {
return x.ValidateForRegistration
}
}
return nil
}
func (x *NgoloFuzzOne) GetMapForLookup() *MapForLookupArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_MapForLookup); ok {
return x.MapForLookup
}
}
return nil
}
func (x *NgoloFuzzOne) GetProfileNgdotToASCII() *ProfileNgdotToASCIIArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ProfileNgdotToASCII); ok {
return x.ProfileNgdotToASCII
}
}
return nil
}
func (x *NgoloFuzzOne) GetProfileNgdotToUnicode() *ProfileNgdotToUnicodeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ProfileNgdotToUnicode); ok {
return x.ProfileNgdotToUnicode
}
}
return nil
}
func (x *NgoloFuzzOne) GetProfileNgdotString() *ProfileNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ProfileNgdotString); ok {
return x.ProfileNgdotString
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_ToASCII struct {
ToASCII *ToASCIIArgs `protobuf:"bytes,1,opt,name=ToASCII,proto3,oneof"`
}
type NgoloFuzzOne_ToUnicode struct {
ToUnicode *ToUnicodeArgs `protobuf:"bytes,2,opt,name=ToUnicode,proto3,oneof"`
}
type NgoloFuzzOne_Transitional struct {
Transitional *TransitionalArgs `protobuf:"bytes,3,opt,name=Transitional,proto3,oneof"`
}
type NgoloFuzzOne_VerifyDNSLength struct {
VerifyDNSLength *VerifyDNSLengthArgs `protobuf:"bytes,4,opt,name=VerifyDNSLength,proto3,oneof"`
}
type NgoloFuzzOne_RemoveLeadingDots struct {
RemoveLeadingDots *RemoveLeadingDotsArgs `protobuf:"bytes,5,opt,name=RemoveLeadingDots,proto3,oneof"`
}
type NgoloFuzzOne_ValidateLabels struct {
ValidateLabels *ValidateLabelsArgs `protobuf:"bytes,6,opt,name=ValidateLabels,proto3,oneof"`
}
type NgoloFuzzOne_CheckHyphens struct {
CheckHyphens *CheckHyphensArgs `protobuf:"bytes,7,opt,name=CheckHyphens,proto3,oneof"`
}
type NgoloFuzzOne_CheckJoiners struct {
CheckJoiners *CheckJoinersArgs `protobuf:"bytes,8,opt,name=CheckJoiners,proto3,oneof"`
}
type NgoloFuzzOne_StrictDomainName struct {
StrictDomainName *StrictDomainNameArgs `protobuf:"bytes,9,opt,name=StrictDomainName,proto3,oneof"`
}
type NgoloFuzzOne_BidiRule struct {
BidiRule *BidiRuleArgs `protobuf:"bytes,10,opt,name=BidiRule,proto3,oneof"`
}
type NgoloFuzzOne_ValidateForRegistration struct {
ValidateForRegistration *ValidateForRegistrationArgs `protobuf:"bytes,11,opt,name=ValidateForRegistration,proto3,oneof"`
}
type NgoloFuzzOne_MapForLookup struct {
MapForLookup *MapForLookupArgs `protobuf:"bytes,12,opt,name=MapForLookup,proto3,oneof"`
}
type NgoloFuzzOne_ProfileNgdotToASCII struct {
ProfileNgdotToASCII *ProfileNgdotToASCIIArgs `protobuf:"bytes,13,opt,name=ProfileNgdotToASCII,proto3,oneof"`
}
type NgoloFuzzOne_ProfileNgdotToUnicode struct {
ProfileNgdotToUnicode *ProfileNgdotToUnicodeArgs `protobuf:"bytes,14,opt,name=ProfileNgdotToUnicode,proto3,oneof"`
}
type NgoloFuzzOne_ProfileNgdotString struct {
ProfileNgdotString *ProfileNgdotStringArgs `protobuf:"bytes,15,opt,name=ProfileNgdotString,proto3,oneof"`
}
func (*NgoloFuzzOne_ToASCII) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ToUnicode) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Transitional) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_VerifyDNSLength) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_RemoveLeadingDots) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ValidateLabels) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CheckHyphens) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CheckJoiners) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_StrictDomainName) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BidiRule) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ValidateForRegistration) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_MapForLookup) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ProfileNgdotToASCII) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ProfileNgdotToUnicode) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ProfileNgdotString) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[16]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{16}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[17]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{17}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x1b\n" +
"\vToASCIIArgs\x12\f\n" +
"\x01s\x18\x01 \x01(\tR\x01s\"\x1d\n" +
"\rToUnicodeArgs\x12\f\n" +
"\x01s\x18\x01 \x01(\tR\x01s\"6\n" +
"\x10TransitionalArgs\x12\"\n" +
"\ftransitional\x18\x01 \x01(\bR\ftransitional\"-\n" +
"\x13VerifyDNSLengthArgs\x12\x16\n" +
"\x06verify\x18\x01 \x01(\bR\x06verify\"/\n" +
"\x15RemoveLeadingDotsArgs\x12\x16\n" +
"\x06remove\x18\x01 \x01(\bR\x06remove\",\n" +
"\x12ValidateLabelsArgs\x12\x16\n" +
"\x06enable\x18\x01 \x01(\bR\x06enable\"*\n" +
"\x10CheckHyphensArgs\x12\x16\n" +
"\x06enable\x18\x01 \x01(\bR\x06enable\"*\n" +
"\x10CheckJoinersArgs\x12\x16\n" +
"\x06enable\x18\x01 \x01(\bR\x06enable\"(\n" +
"\x14StrictDomainNameArgs\x12\x10\n" +
"\x03use\x18\x01 \x01(\bR\x03use\"\x0e\n" +
"\fBidiRuleArgs\"\x1d\n" +
"\x1bValidateForRegistrationArgs\"\x12\n" +
"\x10MapForLookupArgs\"'\n" +
"\x17ProfileNgdotToASCIIArgs\x12\f\n" +
"\x01s\x18\x01 \x01(\tR\x01s\")\n" +
"\x19ProfileNgdotToUnicodeArgs\x12\f\n" +
"\x01s\x18\x01 \x01(\tR\x01s\"\x18\n" +
"\x16ProfileNgdotStringArgs\"\xec\b\n" +
"\fNgoloFuzzOne\x122\n" +
"\aToASCII\x18\x01 \x01(\v2\x16.ngolofuzz.ToASCIIArgsH\x00R\aToASCII\x128\n" +
"\tToUnicode\x18\x02 \x01(\v2\x18.ngolofuzz.ToUnicodeArgsH\x00R\tToUnicode\x12A\n" +
"\fTransitional\x18\x03 \x01(\v2\x1b.ngolofuzz.TransitionalArgsH\x00R\fTransitional\x12J\n" +
"\x0fVerifyDNSLength\x18\x04 \x01(\v2\x1e.ngolofuzz.VerifyDNSLengthArgsH\x00R\x0fVerifyDNSLength\x12P\n" +
"\x11RemoveLeadingDots\x18\x05 \x01(\v2 .ngolofuzz.RemoveLeadingDotsArgsH\x00R\x11RemoveLeadingDots\x12G\n" +
"\x0eValidateLabels\x18\x06 \x01(\v2\x1d.ngolofuzz.ValidateLabelsArgsH\x00R\x0eValidateLabels\x12A\n" +
"\fCheckHyphens\x18\a \x01(\v2\x1b.ngolofuzz.CheckHyphensArgsH\x00R\fCheckHyphens\x12A\n" +
"\fCheckJoiners\x18\b \x01(\v2\x1b.ngolofuzz.CheckJoinersArgsH\x00R\fCheckJoiners\x12M\n" +
"\x10StrictDomainName\x18\t \x01(\v2\x1f.ngolofuzz.StrictDomainNameArgsH\x00R\x10StrictDomainName\x125\n" +
"\bBidiRule\x18\n" +
" \x01(\v2\x17.ngolofuzz.BidiRuleArgsH\x00R\bBidiRule\x12b\n" +
"\x17ValidateForRegistration\x18\v \x01(\v2&.ngolofuzz.ValidateForRegistrationArgsH\x00R\x17ValidateForRegistration\x12A\n" +
"\fMapForLookup\x18\f \x01(\v2\x1b.ngolofuzz.MapForLookupArgsH\x00R\fMapForLookup\x12V\n" +
"\x13ProfileNgdotToASCII\x18\r \x01(\v2\".ngolofuzz.ProfileNgdotToASCIIArgsH\x00R\x13ProfileNgdotToASCII\x12\\\n" +
"\x15ProfileNgdotToUnicode\x18\x0e \x01(\v2$.ngolofuzz.ProfileNgdotToUnicodeArgsH\x00R\x15ProfileNgdotToUnicode\x12S\n" +
"\x12ProfileNgdotString\x18\x0f \x01(\v2!.ngolofuzz.ProfileNgdotStringArgsH\x00R\x12ProfileNgdotStringB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x17Z\x15./;fuzz_ng_x_net_idnab\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 18)
var file_ngolofuzz_proto_goTypes = []any{
(*ToASCIIArgs)(nil), // 0: ngolofuzz.ToASCIIArgs
(*ToUnicodeArgs)(nil), // 1: ngolofuzz.ToUnicodeArgs
(*TransitionalArgs)(nil), // 2: ngolofuzz.TransitionalArgs
(*VerifyDNSLengthArgs)(nil), // 3: ngolofuzz.VerifyDNSLengthArgs
(*RemoveLeadingDotsArgs)(nil), // 4: ngolofuzz.RemoveLeadingDotsArgs
(*ValidateLabelsArgs)(nil), // 5: ngolofuzz.ValidateLabelsArgs
(*CheckHyphensArgs)(nil), // 6: ngolofuzz.CheckHyphensArgs
(*CheckJoinersArgs)(nil), // 7: ngolofuzz.CheckJoinersArgs
(*StrictDomainNameArgs)(nil), // 8: ngolofuzz.StrictDomainNameArgs
(*BidiRuleArgs)(nil), // 9: ngolofuzz.BidiRuleArgs
(*ValidateForRegistrationArgs)(nil), // 10: ngolofuzz.ValidateForRegistrationArgs
(*MapForLookupArgs)(nil), // 11: ngolofuzz.MapForLookupArgs
(*ProfileNgdotToASCIIArgs)(nil), // 12: ngolofuzz.ProfileNgdotToASCIIArgs
(*ProfileNgdotToUnicodeArgs)(nil), // 13: ngolofuzz.ProfileNgdotToUnicodeArgs
(*ProfileNgdotStringArgs)(nil), // 14: ngolofuzz.ProfileNgdotStringArgs
(*NgoloFuzzOne)(nil), // 15: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 16: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 17: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.ToASCII:type_name -> ngolofuzz.ToASCIIArgs
1, // 1: ngolofuzz.NgoloFuzzOne.ToUnicode:type_name -> ngolofuzz.ToUnicodeArgs
2, // 2: ngolofuzz.NgoloFuzzOne.Transitional:type_name -> ngolofuzz.TransitionalArgs
3, // 3: ngolofuzz.NgoloFuzzOne.VerifyDNSLength:type_name -> ngolofuzz.VerifyDNSLengthArgs
4, // 4: ngolofuzz.NgoloFuzzOne.RemoveLeadingDots:type_name -> ngolofuzz.RemoveLeadingDotsArgs
5, // 5: ngolofuzz.NgoloFuzzOne.ValidateLabels:type_name -> ngolofuzz.ValidateLabelsArgs
6, // 6: ngolofuzz.NgoloFuzzOne.CheckHyphens:type_name -> ngolofuzz.CheckHyphensArgs
7, // 7: ngolofuzz.NgoloFuzzOne.CheckJoiners:type_name -> ngolofuzz.CheckJoinersArgs
8, // 8: ngolofuzz.NgoloFuzzOne.StrictDomainName:type_name -> ngolofuzz.StrictDomainNameArgs
9, // 9: ngolofuzz.NgoloFuzzOne.BidiRule:type_name -> ngolofuzz.BidiRuleArgs
10, // 10: ngolofuzz.NgoloFuzzOne.ValidateForRegistration:type_name -> ngolofuzz.ValidateForRegistrationArgs
11, // 11: ngolofuzz.NgoloFuzzOne.MapForLookup:type_name -> ngolofuzz.MapForLookupArgs
12, // 12: ngolofuzz.NgoloFuzzOne.ProfileNgdotToASCII:type_name -> ngolofuzz.ProfileNgdotToASCIIArgs
13, // 13: ngolofuzz.NgoloFuzzOne.ProfileNgdotToUnicode:type_name -> ngolofuzz.ProfileNgdotToUnicodeArgs
14, // 14: ngolofuzz.NgoloFuzzOne.ProfileNgdotString:type_name -> ngolofuzz.ProfileNgdotStringArgs
15, // 15: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
16, // [16:16] is the sub-list for method output_type
16, // [16:16] is the sub-list for method input_type
16, // [16:16] is the sub-list for extension type_name
16, // [16:16] is the sub-list for extension extendee
0, // [0:16] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[15].OneofWrappers = []any{
(*NgoloFuzzOne_ToASCII)(nil),
(*NgoloFuzzOne_ToUnicode)(nil),
(*NgoloFuzzOne_Transitional)(nil),
(*NgoloFuzzOne_VerifyDNSLength)(nil),
(*NgoloFuzzOne_RemoveLeadingDots)(nil),
(*NgoloFuzzOne_ValidateLabels)(nil),
(*NgoloFuzzOne_CheckHyphens)(nil),
(*NgoloFuzzOne_CheckJoiners)(nil),
(*NgoloFuzzOne_StrictDomainName)(nil),
(*NgoloFuzzOne_BidiRule)(nil),
(*NgoloFuzzOne_ValidateForRegistration)(nil),
(*NgoloFuzzOne_MapForLookup)(nil),
(*NgoloFuzzOne_ProfileNgdotToASCII)(nil),
(*NgoloFuzzOne_ProfileNgdotToUnicode)(nil),
(*NgoloFuzzOne_ProfileNgdotString)(nil),
}
file_ngolofuzz_proto_msgTypes[16].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 18,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_net_ipv6
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/net/ipv6"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func ControlFlagsNewFromFuzz(p ControlFlagsEnum) ipv6.ControlFlags{
switch p {
case 1:
return ipv6.FlagHopLimit
case 2:
return ipv6.FlagSrc
case 3:
return ipv6.FlagDst
case 4:
return ipv6.FlagInterface
case 5:
return ipv6.FlagPathMTU
}
return ipv6.FlagTrafficClass
}
func ConvertControlFlagsNewFromFuzz(a []ControlFlagsEnum) []ipv6.ControlFlags{
r := make([]ipv6.ControlFlags, len(a))
for i := range a {
r[i] = ControlFlagsNewFromFuzz(a[i])
}
return r
}
func ICMPTypeNewFromFuzz(p ICMPTypeEnum) ipv6.ICMPType{
switch p {
case 1:
return ipv6.ICMPTypePacketTooBig
case 2:
return ipv6.ICMPTypeTimeExceeded
case 3:
return ipv6.ICMPTypeParameterProblem
case 4:
return ipv6.ICMPTypeEchoRequest
case 5:
return ipv6.ICMPTypeEchoReply
case 6:
return ipv6.ICMPTypeMulticastListenerQuery
case 7:
return ipv6.ICMPTypeMulticastListenerReport
case 8:
return ipv6.ICMPTypeMulticastListenerDone
case 9:
return ipv6.ICMPTypeRouterSolicitation
case 10:
return ipv6.ICMPTypeRouterAdvertisement
case 11:
return ipv6.ICMPTypeNeighborSolicitation
case 12:
return ipv6.ICMPTypeNeighborAdvertisement
case 13:
return ipv6.ICMPTypeRedirect
case 14:
return ipv6.ICMPTypeRouterRenumbering
case 15:
return ipv6.ICMPTypeNodeInformationQuery
case 16:
return ipv6.ICMPTypeNodeInformationResponse
case 17:
return ipv6.ICMPTypeInverseNeighborDiscoverySolicitation
case 18:
return ipv6.ICMPTypeInverseNeighborDiscoveryAdvertisement
case 19:
return ipv6.ICMPTypeVersion2MulticastListenerReport
case 20:
return ipv6.ICMPTypeHomeAgentAddressDiscoveryRequest
case 21:
return ipv6.ICMPTypeHomeAgentAddressDiscoveryReply
case 22:
return ipv6.ICMPTypeMobilePrefixSolicitation
case 23:
return ipv6.ICMPTypeMobilePrefixAdvertisement
case 24:
return ipv6.ICMPTypeCertificationPathSolicitation
case 25:
return ipv6.ICMPTypeCertificationPathAdvertisement
case 26:
return ipv6.ICMPTypeMulticastRouterAdvertisement
case 27:
return ipv6.ICMPTypeMulticastRouterSolicitation
case 28:
return ipv6.ICMPTypeMulticastRouterTermination
case 29:
return ipv6.ICMPTypeFMIPv6
case 30:
return ipv6.ICMPTypeRPLControl
case 31:
return ipv6.ICMPTypeILNPv6LocatorUpdate
case 32:
return ipv6.ICMPTypeDuplicateAddressRequest
case 33:
return ipv6.ICMPTypeDuplicateAddressConfirmation
case 34:
return ipv6.ICMPTypeMPLControl
case 35:
return ipv6.ICMPTypeExtendedEchoRequest
case 36:
return ipv6.ICMPTypeExtendedEchoReply
}
return ipv6.ICMPTypeDestinationUnreachable
}
func ConvertICMPTypeNewFromFuzz(a []ICMPTypeEnum) []ipv6.ICMPType{
r := make([]ipv6.ICMPType, len(a))
for i := range a {
r[i] = ICMPTypeNewFromFuzz(a[i])
}
return r
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var PacketConnResults []*ipv6.PacketConn
PacketConnResultsIndex := 0
var ConnResults []*ipv6.Conn
ConnResultsIndex := 0
var HeaderResults []*ipv6.Header
HeaderResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewControlMessage:
arg0 := ControlFlagsNewFromFuzz(a.NewControlMessage.Cf)
ipv6.NewControlMessage(arg0)
case *NgoloFuzzOne_ConnNgdotPathMTU:
if len(ConnResults) == 0 {
continue
}
arg0 := ConnResults[ConnResultsIndex]
ConnResultsIndex = (ConnResultsIndex + 1) % len(ConnResults)
_, r1 := arg0.PathMTU()
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_NewConn:
arg0 := CreateFuzzingConn(a.NewConn.C)
r0 := ipv6.NewConn(arg0)
if r0 != nil{
ConnResults = append(ConnResults, r0)
}
case *NgoloFuzzOne_PacketConnNgdotSetControlMessage:
if len(PacketConnResults) == 0 {
continue
}
arg0 := PacketConnResults[PacketConnResultsIndex]
PacketConnResultsIndex = (PacketConnResultsIndex + 1) % len(PacketConnResults)
arg1 := ControlFlagsNewFromFuzz(a.PacketConnNgdotSetControlMessage.Cf)
r0 := arg0.SetControlMessage(arg1, a.PacketConnNgdotSetControlMessage.On)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_PacketConnNgdotClose:
if len(PacketConnResults) == 0 {
continue
}
arg0 := PacketConnResults[PacketConnResultsIndex]
PacketConnResultsIndex = (PacketConnResultsIndex + 1) % len(PacketConnResults)
r0 := arg0.Close()
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_HeaderNgdotString:
if len(HeaderResults) == 0 {
continue
}
arg0 := HeaderResults[HeaderResultsIndex]
HeaderResultsIndex = (HeaderResultsIndex + 1) % len(HeaderResults)
arg0.String()
case *NgoloFuzzOne_ParseHeader:
_, r1 := ipv6.ParseHeader(a.ParseHeader.B)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_ICMPTypeNgdotString:
arg0 := ICMPTypeNewFromFuzz(a.ICMPTypeNgdotString.Typ)
arg0.String()
case *NgoloFuzzOne_ICMPTypeNgdotProtocol:
arg0 := ICMPTypeNewFromFuzz(a.ICMPTypeNgdotProtocol.Typ)
arg0.Protocol()
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
PacketConnNb := 0
PacketConnResultsIndex := 0
ConnNb := 0
ConnResultsIndex := 0
HeaderNb := 0
HeaderResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewControlMessage:
w.WriteString(fmt.Sprintf("ipv6.NewControlMessage(ControlFlagsNewFromFuzz(%#+v))\n", a.NewControlMessage.Cf))
case *NgoloFuzzOne_ConnNgdotPathMTU:
if ConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Conn%d.PathMTU()\n", ConnResultsIndex))
ConnResultsIndex = (ConnResultsIndex + 1) % ConnNb
case *NgoloFuzzOne_NewConn:
w.WriteString(fmt.Sprintf("Conn%d := ipv6.NewConn(CreateFuzzingConn(%#+v))\n", ConnNb, a.NewConn.C))
ConnNb = ConnNb + 1
case *NgoloFuzzOne_PacketConnNgdotSetControlMessage:
if PacketConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("PacketConn%d.SetControlMessage(ControlFlagsNewFromFuzz(%#+v), %#+v)\n", PacketConnResultsIndex, a.PacketConnNgdotSetControlMessage.Cf, a.PacketConnNgdotSetControlMessage.On))
PacketConnResultsIndex = (PacketConnResultsIndex + 1) % PacketConnNb
case *NgoloFuzzOne_PacketConnNgdotClose:
if PacketConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("PacketConn%d.Close()\n", PacketConnResultsIndex))
PacketConnResultsIndex = (PacketConnResultsIndex + 1) % PacketConnNb
case *NgoloFuzzOne_HeaderNgdotString:
if HeaderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Header%d.String()\n", HeaderResultsIndex))
HeaderResultsIndex = (HeaderResultsIndex + 1) % HeaderNb
case *NgoloFuzzOne_ParseHeader:
w.WriteString(fmt.Sprintf("ipv6.ParseHeader(%#+v)\n", a.ParseHeader.B))
case *NgoloFuzzOne_ICMPTypeNgdotString:
w.WriteString(fmt.Sprintf("ICMPTypeNewFromFuzz(%#+v).String()\n", a.ICMPTypeNgdotString.Typ))
case *NgoloFuzzOne_ICMPTypeNgdotProtocol:
w.WriteString(fmt.Sprintf("ICMPTypeNewFromFuzz(%#+v).Protocol()\n", a.ICMPTypeNgdotProtocol.Typ))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_net_ipv6
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ControlFlagsEnum int32
const (
ControlFlagsEnum_FlagTrafficClass ControlFlagsEnum = 0
ControlFlagsEnum_FlagHopLimit ControlFlagsEnum = 1
ControlFlagsEnum_FlagSrc ControlFlagsEnum = 2
ControlFlagsEnum_FlagDst ControlFlagsEnum = 3
ControlFlagsEnum_FlagInterface ControlFlagsEnum = 4
ControlFlagsEnum_FlagPathMTU ControlFlagsEnum = 5
)
// Enum value maps for ControlFlagsEnum.
var (
ControlFlagsEnum_name = map[int32]string{
0: "FlagTrafficClass",
1: "FlagHopLimit",
2: "FlagSrc",
3: "FlagDst",
4: "FlagInterface",
5: "FlagPathMTU",
}
ControlFlagsEnum_value = map[string]int32{
"FlagTrafficClass": 0,
"FlagHopLimit": 1,
"FlagSrc": 2,
"FlagDst": 3,
"FlagInterface": 4,
"FlagPathMTU": 5,
}
)
func (x ControlFlagsEnum) Enum() *ControlFlagsEnum {
p := new(ControlFlagsEnum)
*p = x
return p
}
func (x ControlFlagsEnum) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (ControlFlagsEnum) Descriptor() protoreflect.EnumDescriptor {
return file_ngolofuzz_proto_enumTypes[0].Descriptor()
}
func (ControlFlagsEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[0]
}
func (x ControlFlagsEnum) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use ControlFlagsEnum.Descriptor instead.
func (ControlFlagsEnum) EnumDescriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type ICMPTypeEnum int32
const (
ICMPTypeEnum_ICMPTypeDestinationUnreachable ICMPTypeEnum = 0
ICMPTypeEnum_ICMPTypePacketTooBig ICMPTypeEnum = 1
ICMPTypeEnum_ICMPTypeTimeExceeded ICMPTypeEnum = 2
ICMPTypeEnum_ICMPTypeParameterProblem ICMPTypeEnum = 3
ICMPTypeEnum_ICMPTypeEchoRequest ICMPTypeEnum = 4
ICMPTypeEnum_ICMPTypeEchoReply ICMPTypeEnum = 5
ICMPTypeEnum_ICMPTypeMulticastListenerQuery ICMPTypeEnum = 6
ICMPTypeEnum_ICMPTypeMulticastListenerReport ICMPTypeEnum = 7
ICMPTypeEnum_ICMPTypeMulticastListenerDone ICMPTypeEnum = 8
ICMPTypeEnum_ICMPTypeRouterSolicitation ICMPTypeEnum = 9
ICMPTypeEnum_ICMPTypeRouterAdvertisement ICMPTypeEnum = 10
ICMPTypeEnum_ICMPTypeNeighborSolicitation ICMPTypeEnum = 11
ICMPTypeEnum_ICMPTypeNeighborAdvertisement ICMPTypeEnum = 12
ICMPTypeEnum_ICMPTypeRedirect ICMPTypeEnum = 13
ICMPTypeEnum_ICMPTypeRouterRenumbering ICMPTypeEnum = 14
ICMPTypeEnum_ICMPTypeNodeInformationQuery ICMPTypeEnum = 15
ICMPTypeEnum_ICMPTypeNodeInformationResponse ICMPTypeEnum = 16
ICMPTypeEnum_ICMPTypeInverseNeighborDiscoverySolicitation ICMPTypeEnum = 17
ICMPTypeEnum_ICMPTypeInverseNeighborDiscoveryAdvertisement ICMPTypeEnum = 18
ICMPTypeEnum_ICMPTypeVersion2MulticastListenerReport ICMPTypeEnum = 19
ICMPTypeEnum_ICMPTypeHomeAgentAddressDiscoveryRequest ICMPTypeEnum = 20
ICMPTypeEnum_ICMPTypeHomeAgentAddressDiscoveryReply ICMPTypeEnum = 21
ICMPTypeEnum_ICMPTypeMobilePrefixSolicitation ICMPTypeEnum = 22
ICMPTypeEnum_ICMPTypeMobilePrefixAdvertisement ICMPTypeEnum = 23
ICMPTypeEnum_ICMPTypeCertificationPathSolicitation ICMPTypeEnum = 24
ICMPTypeEnum_ICMPTypeCertificationPathAdvertisement ICMPTypeEnum = 25
ICMPTypeEnum_ICMPTypeMulticastRouterAdvertisement ICMPTypeEnum = 26
ICMPTypeEnum_ICMPTypeMulticastRouterSolicitation ICMPTypeEnum = 27
ICMPTypeEnum_ICMPTypeMulticastRouterTermination ICMPTypeEnum = 28
ICMPTypeEnum_ICMPTypeFMIPv6 ICMPTypeEnum = 29
ICMPTypeEnum_ICMPTypeRPLControl ICMPTypeEnum = 30
ICMPTypeEnum_ICMPTypeILNPv6LocatorUpdate ICMPTypeEnum = 31
ICMPTypeEnum_ICMPTypeDuplicateAddressRequest ICMPTypeEnum = 32
ICMPTypeEnum_ICMPTypeDuplicateAddressConfirmation ICMPTypeEnum = 33
ICMPTypeEnum_ICMPTypeMPLControl ICMPTypeEnum = 34
ICMPTypeEnum_ICMPTypeExtendedEchoRequest ICMPTypeEnum = 35
ICMPTypeEnum_ICMPTypeExtendedEchoReply ICMPTypeEnum = 36
)
// Enum value maps for ICMPTypeEnum.
var (
ICMPTypeEnum_name = map[int32]string{
0: "ICMPTypeDestinationUnreachable",
1: "ICMPTypePacketTooBig",
2: "ICMPTypeTimeExceeded",
3: "ICMPTypeParameterProblem",
4: "ICMPTypeEchoRequest",
5: "ICMPTypeEchoReply",
6: "ICMPTypeMulticastListenerQuery",
7: "ICMPTypeMulticastListenerReport",
8: "ICMPTypeMulticastListenerDone",
9: "ICMPTypeRouterSolicitation",
10: "ICMPTypeRouterAdvertisement",
11: "ICMPTypeNeighborSolicitation",
12: "ICMPTypeNeighborAdvertisement",
13: "ICMPTypeRedirect",
14: "ICMPTypeRouterRenumbering",
15: "ICMPTypeNodeInformationQuery",
16: "ICMPTypeNodeInformationResponse",
17: "ICMPTypeInverseNeighborDiscoverySolicitation",
18: "ICMPTypeInverseNeighborDiscoveryAdvertisement",
19: "ICMPTypeVersion2MulticastListenerReport",
20: "ICMPTypeHomeAgentAddressDiscoveryRequest",
21: "ICMPTypeHomeAgentAddressDiscoveryReply",
22: "ICMPTypeMobilePrefixSolicitation",
23: "ICMPTypeMobilePrefixAdvertisement",
24: "ICMPTypeCertificationPathSolicitation",
25: "ICMPTypeCertificationPathAdvertisement",
26: "ICMPTypeMulticastRouterAdvertisement",
27: "ICMPTypeMulticastRouterSolicitation",
28: "ICMPTypeMulticastRouterTermination",
29: "ICMPTypeFMIPv6",
30: "ICMPTypeRPLControl",
31: "ICMPTypeILNPv6LocatorUpdate",
32: "ICMPTypeDuplicateAddressRequest",
33: "ICMPTypeDuplicateAddressConfirmation",
34: "ICMPTypeMPLControl",
35: "ICMPTypeExtendedEchoRequest",
36: "ICMPTypeExtendedEchoReply",
}
ICMPTypeEnum_value = map[string]int32{
"ICMPTypeDestinationUnreachable": 0,
"ICMPTypePacketTooBig": 1,
"ICMPTypeTimeExceeded": 2,
"ICMPTypeParameterProblem": 3,
"ICMPTypeEchoRequest": 4,
"ICMPTypeEchoReply": 5,
"ICMPTypeMulticastListenerQuery": 6,
"ICMPTypeMulticastListenerReport": 7,
"ICMPTypeMulticastListenerDone": 8,
"ICMPTypeRouterSolicitation": 9,
"ICMPTypeRouterAdvertisement": 10,
"ICMPTypeNeighborSolicitation": 11,
"ICMPTypeNeighborAdvertisement": 12,
"ICMPTypeRedirect": 13,
"ICMPTypeRouterRenumbering": 14,
"ICMPTypeNodeInformationQuery": 15,
"ICMPTypeNodeInformationResponse": 16,
"ICMPTypeInverseNeighborDiscoverySolicitation": 17,
"ICMPTypeInverseNeighborDiscoveryAdvertisement": 18,
"ICMPTypeVersion2MulticastListenerReport": 19,
"ICMPTypeHomeAgentAddressDiscoveryRequest": 20,
"ICMPTypeHomeAgentAddressDiscoveryReply": 21,
"ICMPTypeMobilePrefixSolicitation": 22,
"ICMPTypeMobilePrefixAdvertisement": 23,
"ICMPTypeCertificationPathSolicitation": 24,
"ICMPTypeCertificationPathAdvertisement": 25,
"ICMPTypeMulticastRouterAdvertisement": 26,
"ICMPTypeMulticastRouterSolicitation": 27,
"ICMPTypeMulticastRouterTermination": 28,
"ICMPTypeFMIPv6": 29,
"ICMPTypeRPLControl": 30,
"ICMPTypeILNPv6LocatorUpdate": 31,
"ICMPTypeDuplicateAddressRequest": 32,
"ICMPTypeDuplicateAddressConfirmation": 33,
"ICMPTypeMPLControl": 34,
"ICMPTypeExtendedEchoRequest": 35,
"ICMPTypeExtendedEchoReply": 36,
}
)
func (x ICMPTypeEnum) Enum() *ICMPTypeEnum {
p := new(ICMPTypeEnum)
*p = x
return p
}
func (x ICMPTypeEnum) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (ICMPTypeEnum) Descriptor() protoreflect.EnumDescriptor {
return file_ngolofuzz_proto_enumTypes[1].Descriptor()
}
func (ICMPTypeEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[1]
}
func (x ICMPTypeEnum) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use ICMPTypeEnum.Descriptor instead.
func (ICMPTypeEnum) EnumDescriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
type NewControlMessageArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Cf ControlFlagsEnum `protobuf:"varint,1,opt,name=cf,proto3,enum=ngolofuzz.ControlFlagsEnum" json:"cf,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewControlMessageArgs) Reset() {
*x = NewControlMessageArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewControlMessageArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewControlMessageArgs) ProtoMessage() {}
func (x *NewControlMessageArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewControlMessageArgs.ProtoReflect.Descriptor instead.
func (*NewControlMessageArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *NewControlMessageArgs) GetCf() ControlFlagsEnum {
if x != nil {
return x.Cf
}
return ControlFlagsEnum_FlagTrafficClass
}
type ConnNgdotPathMTUArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ConnNgdotPathMTUArgs) Reset() {
*x = ConnNgdotPathMTUArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ConnNgdotPathMTUArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConnNgdotPathMTUArgs) ProtoMessage() {}
func (x *ConnNgdotPathMTUArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ConnNgdotPathMTUArgs.ProtoReflect.Descriptor instead.
func (*ConnNgdotPathMTUArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
type NewConnArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
C []byte `protobuf:"bytes,1,opt,name=c,proto3" json:"c,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewConnArgs) Reset() {
*x = NewConnArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewConnArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewConnArgs) ProtoMessage() {}
func (x *NewConnArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewConnArgs.ProtoReflect.Descriptor instead.
func (*NewConnArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NewConnArgs) GetC() []byte {
if x != nil {
return x.C
}
return nil
}
type PacketConnNgdotSetControlMessageArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Cf ControlFlagsEnum `protobuf:"varint,1,opt,name=cf,proto3,enum=ngolofuzz.ControlFlagsEnum" json:"cf,omitempty"`
On bool `protobuf:"varint,2,opt,name=on,proto3" json:"on,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PacketConnNgdotSetControlMessageArgs) Reset() {
*x = PacketConnNgdotSetControlMessageArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PacketConnNgdotSetControlMessageArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PacketConnNgdotSetControlMessageArgs) ProtoMessage() {}
func (x *PacketConnNgdotSetControlMessageArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PacketConnNgdotSetControlMessageArgs.ProtoReflect.Descriptor instead.
func (*PacketConnNgdotSetControlMessageArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *PacketConnNgdotSetControlMessageArgs) GetCf() ControlFlagsEnum {
if x != nil {
return x.Cf
}
return ControlFlagsEnum_FlagTrafficClass
}
func (x *PacketConnNgdotSetControlMessageArgs) GetOn() bool {
if x != nil {
return x.On
}
return false
}
type PacketConnNgdotCloseArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PacketConnNgdotCloseArgs) Reset() {
*x = PacketConnNgdotCloseArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PacketConnNgdotCloseArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PacketConnNgdotCloseArgs) ProtoMessage() {}
func (x *PacketConnNgdotCloseArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PacketConnNgdotCloseArgs.ProtoReflect.Descriptor instead.
func (*PacketConnNgdotCloseArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
type HeaderNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HeaderNgdotStringArgs) Reset() {
*x = HeaderNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HeaderNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HeaderNgdotStringArgs) ProtoMessage() {}
func (x *HeaderNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HeaderNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*HeaderNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
type ParseHeaderArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
B []byte `protobuf:"bytes,1,opt,name=b,proto3" json:"b,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ParseHeaderArgs) Reset() {
*x = ParseHeaderArgs{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ParseHeaderArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ParseHeaderArgs) ProtoMessage() {}
func (x *ParseHeaderArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ParseHeaderArgs.ProtoReflect.Descriptor instead.
func (*ParseHeaderArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *ParseHeaderArgs) GetB() []byte {
if x != nil {
return x.B
}
return nil
}
type ICMPTypeNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Typ ICMPTypeEnum `protobuf:"varint,1,opt,name=typ,proto3,enum=ngolofuzz.ICMPTypeEnum" json:"typ,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ICMPTypeNgdotStringArgs) Reset() {
*x = ICMPTypeNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ICMPTypeNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ICMPTypeNgdotStringArgs) ProtoMessage() {}
func (x *ICMPTypeNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ICMPTypeNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*ICMPTypeNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
func (x *ICMPTypeNgdotStringArgs) GetTyp() ICMPTypeEnum {
if x != nil {
return x.Typ
}
return ICMPTypeEnum_ICMPTypeDestinationUnreachable
}
type ICMPTypeNgdotProtocolArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Typ ICMPTypeEnum `protobuf:"varint,1,opt,name=typ,proto3,enum=ngolofuzz.ICMPTypeEnum" json:"typ,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ICMPTypeNgdotProtocolArgs) Reset() {
*x = ICMPTypeNgdotProtocolArgs{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ICMPTypeNgdotProtocolArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ICMPTypeNgdotProtocolArgs) ProtoMessage() {}
func (x *ICMPTypeNgdotProtocolArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ICMPTypeNgdotProtocolArgs.ProtoReflect.Descriptor instead.
func (*ICMPTypeNgdotProtocolArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
func (x *ICMPTypeNgdotProtocolArgs) GetTyp() ICMPTypeEnum {
if x != nil {
return x.Typ
}
return ICMPTypeEnum_ICMPTypeDestinationUnreachable
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_NewControlMessage
// *NgoloFuzzOne_ConnNgdotPathMTU
// *NgoloFuzzOne_NewConn
// *NgoloFuzzOne_PacketConnNgdotSetControlMessage
// *NgoloFuzzOne_PacketConnNgdotClose
// *NgoloFuzzOne_HeaderNgdotString
// *NgoloFuzzOne_ParseHeader
// *NgoloFuzzOne_ICMPTypeNgdotString
// *NgoloFuzzOne_ICMPTypeNgdotProtocol
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetNewControlMessage() *NewControlMessageArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewControlMessage); ok {
return x.NewControlMessage
}
}
return nil
}
func (x *NgoloFuzzOne) GetConnNgdotPathMTU() *ConnNgdotPathMTUArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ConnNgdotPathMTU); ok {
return x.ConnNgdotPathMTU
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewConn() *NewConnArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewConn); ok {
return x.NewConn
}
}
return nil
}
func (x *NgoloFuzzOne) GetPacketConnNgdotSetControlMessage() *PacketConnNgdotSetControlMessageArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_PacketConnNgdotSetControlMessage); ok {
return x.PacketConnNgdotSetControlMessage
}
}
return nil
}
func (x *NgoloFuzzOne) GetPacketConnNgdotClose() *PacketConnNgdotCloseArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_PacketConnNgdotClose); ok {
return x.PacketConnNgdotClose
}
}
return nil
}
func (x *NgoloFuzzOne) GetHeaderNgdotString() *HeaderNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_HeaderNgdotString); ok {
return x.HeaderNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetParseHeader() *ParseHeaderArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ParseHeader); ok {
return x.ParseHeader
}
}
return nil
}
func (x *NgoloFuzzOne) GetICMPTypeNgdotString() *ICMPTypeNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ICMPTypeNgdotString); ok {
return x.ICMPTypeNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetICMPTypeNgdotProtocol() *ICMPTypeNgdotProtocolArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ICMPTypeNgdotProtocol); ok {
return x.ICMPTypeNgdotProtocol
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_NewControlMessage struct {
NewControlMessage *NewControlMessageArgs `protobuf:"bytes,1,opt,name=NewControlMessage,proto3,oneof"`
}
type NgoloFuzzOne_ConnNgdotPathMTU struct {
ConnNgdotPathMTU *ConnNgdotPathMTUArgs `protobuf:"bytes,2,opt,name=ConnNgdotPathMTU,proto3,oneof"`
}
type NgoloFuzzOne_NewConn struct {
NewConn *NewConnArgs `protobuf:"bytes,3,opt,name=NewConn,proto3,oneof"`
}
type NgoloFuzzOne_PacketConnNgdotSetControlMessage struct {
PacketConnNgdotSetControlMessage *PacketConnNgdotSetControlMessageArgs `protobuf:"bytes,4,opt,name=PacketConnNgdotSetControlMessage,proto3,oneof"`
}
type NgoloFuzzOne_PacketConnNgdotClose struct {
PacketConnNgdotClose *PacketConnNgdotCloseArgs `protobuf:"bytes,5,opt,name=PacketConnNgdotClose,proto3,oneof"`
}
type NgoloFuzzOne_HeaderNgdotString struct {
HeaderNgdotString *HeaderNgdotStringArgs `protobuf:"bytes,6,opt,name=HeaderNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_ParseHeader struct {
ParseHeader *ParseHeaderArgs `protobuf:"bytes,7,opt,name=ParseHeader,proto3,oneof"`
}
type NgoloFuzzOne_ICMPTypeNgdotString struct {
ICMPTypeNgdotString *ICMPTypeNgdotStringArgs `protobuf:"bytes,8,opt,name=ICMPTypeNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_ICMPTypeNgdotProtocol struct {
ICMPTypeNgdotProtocol *ICMPTypeNgdotProtocolArgs `protobuf:"bytes,9,opt,name=ICMPTypeNgdotProtocol,proto3,oneof"`
}
func (*NgoloFuzzOne_NewControlMessage) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ConnNgdotPathMTU) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewConn) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_PacketConnNgdotSetControlMessage) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_PacketConnNgdotClose) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_HeaderNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ParseHeader) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ICMPTypeNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ICMPTypeNgdotProtocol) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{10}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[11]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{11}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"D\n" +
"\x15NewControlMessageArgs\x12+\n" +
"\x02cf\x18\x01 \x01(\x0e2\x1b.ngolofuzz.ControlFlagsEnumR\x02cf\"\x16\n" +
"\x14ConnNgdotPathMTUArgs\"\x1b\n" +
"\vNewConnArgs\x12\f\n" +
"\x01c\x18\x01 \x01(\fR\x01c\"c\n" +
"$PacketConnNgdotSetControlMessageArgs\x12+\n" +
"\x02cf\x18\x01 \x01(\x0e2\x1b.ngolofuzz.ControlFlagsEnumR\x02cf\x12\x0e\n" +
"\x02on\x18\x02 \x01(\bR\x02on\"\x1a\n" +
"\x18PacketConnNgdotCloseArgs\"\x17\n" +
"\x15HeaderNgdotStringArgs\"\x1f\n" +
"\x0fParseHeaderArgs\x12\f\n" +
"\x01b\x18\x01 \x01(\fR\x01b\"D\n" +
"\x17ICMPTypeNgdotStringArgs\x12)\n" +
"\x03typ\x18\x01 \x01(\x0e2\x17.ngolofuzz.ICMPTypeEnumR\x03typ\"F\n" +
"\x19ICMPTypeNgdotProtocolArgs\x12)\n" +
"\x03typ\x18\x01 \x01(\x0e2\x17.ngolofuzz.ICMPTypeEnumR\x03typ\"\x8d\x06\n" +
"\fNgoloFuzzOne\x12P\n" +
"\x11NewControlMessage\x18\x01 \x01(\v2 .ngolofuzz.NewControlMessageArgsH\x00R\x11NewControlMessage\x12M\n" +
"\x10ConnNgdotPathMTU\x18\x02 \x01(\v2\x1f.ngolofuzz.ConnNgdotPathMTUArgsH\x00R\x10ConnNgdotPathMTU\x122\n" +
"\aNewConn\x18\x03 \x01(\v2\x16.ngolofuzz.NewConnArgsH\x00R\aNewConn\x12}\n" +
" PacketConnNgdotSetControlMessage\x18\x04 \x01(\v2/.ngolofuzz.PacketConnNgdotSetControlMessageArgsH\x00R PacketConnNgdotSetControlMessage\x12Y\n" +
"\x14PacketConnNgdotClose\x18\x05 \x01(\v2#.ngolofuzz.PacketConnNgdotCloseArgsH\x00R\x14PacketConnNgdotClose\x12P\n" +
"\x11HeaderNgdotString\x18\x06 \x01(\v2 .ngolofuzz.HeaderNgdotStringArgsH\x00R\x11HeaderNgdotString\x12>\n" +
"\vParseHeader\x18\a \x01(\v2\x1a.ngolofuzz.ParseHeaderArgsH\x00R\vParseHeader\x12V\n" +
"\x13ICMPTypeNgdotString\x18\b \x01(\v2\".ngolofuzz.ICMPTypeNgdotStringArgsH\x00R\x13ICMPTypeNgdotString\x12\\\n" +
"\x15ICMPTypeNgdotProtocol\x18\t \x01(\v2$.ngolofuzz.ICMPTypeNgdotProtocolArgsH\x00R\x15ICMPTypeNgdotProtocolB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04list*x\n" +
"\x10ControlFlagsEnum\x12\x14\n" +
"\x10FlagTrafficClass\x10\x00\x12\x10\n" +
"\fFlagHopLimit\x10\x01\x12\v\n" +
"\aFlagSrc\x10\x02\x12\v\n" +
"\aFlagDst\x10\x03\x12\x11\n" +
"\rFlagInterface\x10\x04\x12\x0f\n" +
"\vFlagPathMTU\x10\x05*\xa1\n" +
"\n" +
"\fICMPTypeEnum\x12\"\n" +
"\x1eICMPTypeDestinationUnreachable\x10\x00\x12\x18\n" +
"\x14ICMPTypePacketTooBig\x10\x01\x12\x18\n" +
"\x14ICMPTypeTimeExceeded\x10\x02\x12\x1c\n" +
"\x18ICMPTypeParameterProblem\x10\x03\x12\x17\n" +
"\x13ICMPTypeEchoRequest\x10\x04\x12\x15\n" +
"\x11ICMPTypeEchoReply\x10\x05\x12\"\n" +
"\x1eICMPTypeMulticastListenerQuery\x10\x06\x12#\n" +
"\x1fICMPTypeMulticastListenerReport\x10\a\x12!\n" +
"\x1dICMPTypeMulticastListenerDone\x10\b\x12\x1e\n" +
"\x1aICMPTypeRouterSolicitation\x10\t\x12\x1f\n" +
"\x1bICMPTypeRouterAdvertisement\x10\n" +
"\x12 \n" +
"\x1cICMPTypeNeighborSolicitation\x10\v\x12!\n" +
"\x1dICMPTypeNeighborAdvertisement\x10\f\x12\x14\n" +
"\x10ICMPTypeRedirect\x10\r\x12\x1d\n" +
"\x19ICMPTypeRouterRenumbering\x10\x0e\x12 \n" +
"\x1cICMPTypeNodeInformationQuery\x10\x0f\x12#\n" +
"\x1fICMPTypeNodeInformationResponse\x10\x10\x120\n" +
",ICMPTypeInverseNeighborDiscoverySolicitation\x10\x11\x121\n" +
"-ICMPTypeInverseNeighborDiscoveryAdvertisement\x10\x12\x12+\n" +
"'ICMPTypeVersion2MulticastListenerReport\x10\x13\x12,\n" +
"(ICMPTypeHomeAgentAddressDiscoveryRequest\x10\x14\x12*\n" +
"&ICMPTypeHomeAgentAddressDiscoveryReply\x10\x15\x12$\n" +
" ICMPTypeMobilePrefixSolicitation\x10\x16\x12%\n" +
"!ICMPTypeMobilePrefixAdvertisement\x10\x17\x12)\n" +
"%ICMPTypeCertificationPathSolicitation\x10\x18\x12*\n" +
"&ICMPTypeCertificationPathAdvertisement\x10\x19\x12(\n" +
"$ICMPTypeMulticastRouterAdvertisement\x10\x1a\x12'\n" +
"#ICMPTypeMulticastRouterSolicitation\x10\x1b\x12&\n" +
"\"ICMPTypeMulticastRouterTermination\x10\x1c\x12\x12\n" +
"\x0eICMPTypeFMIPv6\x10\x1d\x12\x16\n" +
"\x12ICMPTypeRPLControl\x10\x1e\x12\x1f\n" +
"\x1bICMPTypeILNPv6LocatorUpdate\x10\x1f\x12#\n" +
"\x1fICMPTypeDuplicateAddressRequest\x10 \x12(\n" +
"$ICMPTypeDuplicateAddressConfirmation\x10!\x12\x16\n" +
"\x12ICMPTypeMPLControl\x10\"\x12\x1f\n" +
"\x1bICMPTypeExtendedEchoRequest\x10#\x12\x1d\n" +
"\x19ICMPTypeExtendedEchoReply\x10$B\x17Z\x15./;fuzz_ng_x_net_ipv6b\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
var file_ngolofuzz_proto_goTypes = []any{
(ControlFlagsEnum)(0), // 0: ngolofuzz.ControlFlagsEnum
(ICMPTypeEnum)(0), // 1: ngolofuzz.ICMPTypeEnum
(*NewControlMessageArgs)(nil), // 2: ngolofuzz.NewControlMessageArgs
(*ConnNgdotPathMTUArgs)(nil), // 3: ngolofuzz.ConnNgdotPathMTUArgs
(*NewConnArgs)(nil), // 4: ngolofuzz.NewConnArgs
(*PacketConnNgdotSetControlMessageArgs)(nil), // 5: ngolofuzz.PacketConnNgdotSetControlMessageArgs
(*PacketConnNgdotCloseArgs)(nil), // 6: ngolofuzz.PacketConnNgdotCloseArgs
(*HeaderNgdotStringArgs)(nil), // 7: ngolofuzz.HeaderNgdotStringArgs
(*ParseHeaderArgs)(nil), // 8: ngolofuzz.ParseHeaderArgs
(*ICMPTypeNgdotStringArgs)(nil), // 9: ngolofuzz.ICMPTypeNgdotStringArgs
(*ICMPTypeNgdotProtocolArgs)(nil), // 10: ngolofuzz.ICMPTypeNgdotProtocolArgs
(*NgoloFuzzOne)(nil), // 11: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 12: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 13: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NewControlMessageArgs.cf:type_name -> ngolofuzz.ControlFlagsEnum
0, // 1: ngolofuzz.PacketConnNgdotSetControlMessageArgs.cf:type_name -> ngolofuzz.ControlFlagsEnum
1, // 2: ngolofuzz.ICMPTypeNgdotStringArgs.typ:type_name -> ngolofuzz.ICMPTypeEnum
1, // 3: ngolofuzz.ICMPTypeNgdotProtocolArgs.typ:type_name -> ngolofuzz.ICMPTypeEnum
2, // 4: ngolofuzz.NgoloFuzzOne.NewControlMessage:type_name -> ngolofuzz.NewControlMessageArgs
3, // 5: ngolofuzz.NgoloFuzzOne.ConnNgdotPathMTU:type_name -> ngolofuzz.ConnNgdotPathMTUArgs
4, // 6: ngolofuzz.NgoloFuzzOne.NewConn:type_name -> ngolofuzz.NewConnArgs
5, // 7: ngolofuzz.NgoloFuzzOne.PacketConnNgdotSetControlMessage:type_name -> ngolofuzz.PacketConnNgdotSetControlMessageArgs
6, // 8: ngolofuzz.NgoloFuzzOne.PacketConnNgdotClose:type_name -> ngolofuzz.PacketConnNgdotCloseArgs
7, // 9: ngolofuzz.NgoloFuzzOne.HeaderNgdotString:type_name -> ngolofuzz.HeaderNgdotStringArgs
8, // 10: ngolofuzz.NgoloFuzzOne.ParseHeader:type_name -> ngolofuzz.ParseHeaderArgs
9, // 11: ngolofuzz.NgoloFuzzOne.ICMPTypeNgdotString:type_name -> ngolofuzz.ICMPTypeNgdotStringArgs
10, // 12: ngolofuzz.NgoloFuzzOne.ICMPTypeNgdotProtocol:type_name -> ngolofuzz.ICMPTypeNgdotProtocolArgs
11, // 13: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
14, // [14:14] is the sub-list for method output_type
14, // [14:14] is the sub-list for method input_type
14, // [14:14] is the sub-list for extension type_name
14, // [14:14] is the sub-list for extension extendee
0, // [0:14] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[9].OneofWrappers = []any{
(*NgoloFuzzOne_NewControlMessage)(nil),
(*NgoloFuzzOne_ConnNgdotPathMTU)(nil),
(*NgoloFuzzOne_NewConn)(nil),
(*NgoloFuzzOne_PacketConnNgdotSetControlMessage)(nil),
(*NgoloFuzzOne_PacketConnNgdotClose)(nil),
(*NgoloFuzzOne_HeaderNgdotString)(nil),
(*NgoloFuzzOne_ParseHeader)(nil),
(*NgoloFuzzOne_ICMPTypeNgdotString)(nil),
(*NgoloFuzzOne_ICMPTypeNgdotProtocol)(nil),
}
file_ngolofuzz_proto_msgTypes[10].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 2,
NumMessages: 12,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
EnumInfos: file_ngolofuzz_proto_enumTypes,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_net_nettest
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/net/nettest"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_SupportsIPv4:
nettest.SupportsIPv4()
case *NgoloFuzzOne_SupportsIPv6:
nettest.SupportsIPv6()
case *NgoloFuzzOne_SupportsRawSocket:
nettest.SupportsRawSocket()
case *NgoloFuzzOne_TestableNetwork:
nettest.TestableNetwork(a.TestableNetwork.Network)
case *NgoloFuzzOne_TestableAddress:
nettest.TestableAddress(a.TestableAddress.Network, a.TestableAddress.Address)
case *NgoloFuzzOne_NewLocalListener:
_, r1 := nettest.NewLocalListener(a.NewLocalListener.Network)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_NewLocalPacketListener:
_, r1 := nettest.NewLocalPacketListener(a.NewLocalPacketListener.Network)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_LocalPath:
_, r1 := nettest.LocalPath()
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_LoopbackInterface:
_, r1 := nettest.LoopbackInterface()
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_SupportsIPv4:
w.WriteString(fmt.Sprintf("nettest.SupportsIPv4()\n"))
case *NgoloFuzzOne_SupportsIPv6:
w.WriteString(fmt.Sprintf("nettest.SupportsIPv6()\n"))
case *NgoloFuzzOne_SupportsRawSocket:
w.WriteString(fmt.Sprintf("nettest.SupportsRawSocket()\n"))
case *NgoloFuzzOne_TestableNetwork:
w.WriteString(fmt.Sprintf("nettest.TestableNetwork(%#+v)\n", a.TestableNetwork.Network))
case *NgoloFuzzOne_TestableAddress:
w.WriteString(fmt.Sprintf("nettest.TestableAddress(%#+v, %#+v)\n", a.TestableAddress.Network, a.TestableAddress.Address))
case *NgoloFuzzOne_NewLocalListener:
w.WriteString(fmt.Sprintf("nettest.NewLocalListener(%#+v)\n", a.NewLocalListener.Network))
case *NgoloFuzzOne_NewLocalPacketListener:
w.WriteString(fmt.Sprintf("nettest.NewLocalPacketListener(%#+v)\n", a.NewLocalPacketListener.Network))
case *NgoloFuzzOne_LocalPath:
w.WriteString(fmt.Sprintf("nettest.LocalPath()\n"))
case *NgoloFuzzOne_LoopbackInterface:
w.WriteString(fmt.Sprintf("nettest.LoopbackInterface()\n"))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_net_nettest
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type SupportsIPv4Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SupportsIPv4Args) Reset() {
*x = SupportsIPv4Args{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SupportsIPv4Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SupportsIPv4Args) ProtoMessage() {}
func (x *SupportsIPv4Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SupportsIPv4Args.ProtoReflect.Descriptor instead.
func (*SupportsIPv4Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type SupportsIPv6Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SupportsIPv6Args) Reset() {
*x = SupportsIPv6Args{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SupportsIPv6Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SupportsIPv6Args) ProtoMessage() {}
func (x *SupportsIPv6Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SupportsIPv6Args.ProtoReflect.Descriptor instead.
func (*SupportsIPv6Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
type SupportsRawSocketArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SupportsRawSocketArgs) Reset() {
*x = SupportsRawSocketArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SupportsRawSocketArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SupportsRawSocketArgs) ProtoMessage() {}
func (x *SupportsRawSocketArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SupportsRawSocketArgs.ProtoReflect.Descriptor instead.
func (*SupportsRawSocketArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
type TestableNetworkArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Network string `protobuf:"bytes,1,opt,name=network,proto3" json:"network,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TestableNetworkArgs) Reset() {
*x = TestableNetworkArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TestableNetworkArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TestableNetworkArgs) ProtoMessage() {}
func (x *TestableNetworkArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TestableNetworkArgs.ProtoReflect.Descriptor instead.
func (*TestableNetworkArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *TestableNetworkArgs) GetNetwork() string {
if x != nil {
return x.Network
}
return ""
}
type TestableAddressArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Network string `protobuf:"bytes,1,opt,name=network,proto3" json:"network,omitempty"`
Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TestableAddressArgs) Reset() {
*x = TestableAddressArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TestableAddressArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TestableAddressArgs) ProtoMessage() {}
func (x *TestableAddressArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TestableAddressArgs.ProtoReflect.Descriptor instead.
func (*TestableAddressArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *TestableAddressArgs) GetNetwork() string {
if x != nil {
return x.Network
}
return ""
}
func (x *TestableAddressArgs) GetAddress() string {
if x != nil {
return x.Address
}
return ""
}
type NewLocalListenerArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Network string `protobuf:"bytes,1,opt,name=network,proto3" json:"network,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewLocalListenerArgs) Reset() {
*x = NewLocalListenerArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewLocalListenerArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewLocalListenerArgs) ProtoMessage() {}
func (x *NewLocalListenerArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewLocalListenerArgs.ProtoReflect.Descriptor instead.
func (*NewLocalListenerArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *NewLocalListenerArgs) GetNetwork() string {
if x != nil {
return x.Network
}
return ""
}
type NewLocalPacketListenerArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Network string `protobuf:"bytes,1,opt,name=network,proto3" json:"network,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewLocalPacketListenerArgs) Reset() {
*x = NewLocalPacketListenerArgs{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewLocalPacketListenerArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewLocalPacketListenerArgs) ProtoMessage() {}
func (x *NewLocalPacketListenerArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewLocalPacketListenerArgs.ProtoReflect.Descriptor instead.
func (*NewLocalPacketListenerArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *NewLocalPacketListenerArgs) GetNetwork() string {
if x != nil {
return x.Network
}
return ""
}
type LocalPathArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *LocalPathArgs) Reset() {
*x = LocalPathArgs{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *LocalPathArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*LocalPathArgs) ProtoMessage() {}
func (x *LocalPathArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use LocalPathArgs.ProtoReflect.Descriptor instead.
func (*LocalPathArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
type LoopbackInterfaceArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *LoopbackInterfaceArgs) Reset() {
*x = LoopbackInterfaceArgs{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *LoopbackInterfaceArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*LoopbackInterfaceArgs) ProtoMessage() {}
func (x *LoopbackInterfaceArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use LoopbackInterfaceArgs.ProtoReflect.Descriptor instead.
func (*LoopbackInterfaceArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_SupportsIPv4
// *NgoloFuzzOne_SupportsIPv6
// *NgoloFuzzOne_SupportsRawSocket
// *NgoloFuzzOne_TestableNetwork
// *NgoloFuzzOne_TestableAddress
// *NgoloFuzzOne_NewLocalListener
// *NgoloFuzzOne_NewLocalPacketListener
// *NgoloFuzzOne_LocalPath
// *NgoloFuzzOne_LoopbackInterface
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetSupportsIPv4() *SupportsIPv4Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_SupportsIPv4); ok {
return x.SupportsIPv4
}
}
return nil
}
func (x *NgoloFuzzOne) GetSupportsIPv6() *SupportsIPv6Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_SupportsIPv6); ok {
return x.SupportsIPv6
}
}
return nil
}
func (x *NgoloFuzzOne) GetSupportsRawSocket() *SupportsRawSocketArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_SupportsRawSocket); ok {
return x.SupportsRawSocket
}
}
return nil
}
func (x *NgoloFuzzOne) GetTestableNetwork() *TestableNetworkArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TestableNetwork); ok {
return x.TestableNetwork
}
}
return nil
}
func (x *NgoloFuzzOne) GetTestableAddress() *TestableAddressArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TestableAddress); ok {
return x.TestableAddress
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewLocalListener() *NewLocalListenerArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewLocalListener); ok {
return x.NewLocalListener
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewLocalPacketListener() *NewLocalPacketListenerArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewLocalPacketListener); ok {
return x.NewLocalPacketListener
}
}
return nil
}
func (x *NgoloFuzzOne) GetLocalPath() *LocalPathArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_LocalPath); ok {
return x.LocalPath
}
}
return nil
}
func (x *NgoloFuzzOne) GetLoopbackInterface() *LoopbackInterfaceArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_LoopbackInterface); ok {
return x.LoopbackInterface
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_SupportsIPv4 struct {
SupportsIPv4 *SupportsIPv4Args `protobuf:"bytes,1,opt,name=SupportsIPv4,proto3,oneof"`
}
type NgoloFuzzOne_SupportsIPv6 struct {
SupportsIPv6 *SupportsIPv6Args `protobuf:"bytes,2,opt,name=SupportsIPv6,proto3,oneof"`
}
type NgoloFuzzOne_SupportsRawSocket struct {
SupportsRawSocket *SupportsRawSocketArgs `protobuf:"bytes,3,opt,name=SupportsRawSocket,proto3,oneof"`
}
type NgoloFuzzOne_TestableNetwork struct {
TestableNetwork *TestableNetworkArgs `protobuf:"bytes,4,opt,name=TestableNetwork,proto3,oneof"`
}
type NgoloFuzzOne_TestableAddress struct {
TestableAddress *TestableAddressArgs `protobuf:"bytes,5,opt,name=TestableAddress,proto3,oneof"`
}
type NgoloFuzzOne_NewLocalListener struct {
NewLocalListener *NewLocalListenerArgs `protobuf:"bytes,6,opt,name=NewLocalListener,proto3,oneof"`
}
type NgoloFuzzOne_NewLocalPacketListener struct {
NewLocalPacketListener *NewLocalPacketListenerArgs `protobuf:"bytes,7,opt,name=NewLocalPacketListener,proto3,oneof"`
}
type NgoloFuzzOne_LocalPath struct {
LocalPath *LocalPathArgs `protobuf:"bytes,8,opt,name=LocalPath,proto3,oneof"`
}
type NgoloFuzzOne_LoopbackInterface struct {
LoopbackInterface *LoopbackInterfaceArgs `protobuf:"bytes,9,opt,name=LoopbackInterface,proto3,oneof"`
}
func (*NgoloFuzzOne_SupportsIPv4) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_SupportsIPv6) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_SupportsRawSocket) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TestableNetwork) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TestableAddress) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewLocalListener) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewLocalPacketListener) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_LocalPath) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_LoopbackInterface) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{10}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[11]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{11}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x12\n" +
"\x10SupportsIPv4Args\"\x12\n" +
"\x10SupportsIPv6Args\"\x17\n" +
"\x15SupportsRawSocketArgs\"/\n" +
"\x13TestableNetworkArgs\x12\x18\n" +
"\anetwork\x18\x01 \x01(\tR\anetwork\"I\n" +
"\x13TestableAddressArgs\x12\x18\n" +
"\anetwork\x18\x01 \x01(\tR\anetwork\x12\x18\n" +
"\aaddress\x18\x02 \x01(\tR\aaddress\"0\n" +
"\x14NewLocalListenerArgs\x12\x18\n" +
"\anetwork\x18\x01 \x01(\tR\anetwork\"6\n" +
"\x1aNewLocalPacketListenerArgs\x12\x18\n" +
"\anetwork\x18\x01 \x01(\tR\anetwork\"\x0f\n" +
"\rLocalPathArgs\"\x17\n" +
"\x15LoopbackInterfaceArgs\"\xc2\x05\n" +
"\fNgoloFuzzOne\x12A\n" +
"\fSupportsIPv4\x18\x01 \x01(\v2\x1b.ngolofuzz.SupportsIPv4ArgsH\x00R\fSupportsIPv4\x12A\n" +
"\fSupportsIPv6\x18\x02 \x01(\v2\x1b.ngolofuzz.SupportsIPv6ArgsH\x00R\fSupportsIPv6\x12P\n" +
"\x11SupportsRawSocket\x18\x03 \x01(\v2 .ngolofuzz.SupportsRawSocketArgsH\x00R\x11SupportsRawSocket\x12J\n" +
"\x0fTestableNetwork\x18\x04 \x01(\v2\x1e.ngolofuzz.TestableNetworkArgsH\x00R\x0fTestableNetwork\x12J\n" +
"\x0fTestableAddress\x18\x05 \x01(\v2\x1e.ngolofuzz.TestableAddressArgsH\x00R\x0fTestableAddress\x12M\n" +
"\x10NewLocalListener\x18\x06 \x01(\v2\x1f.ngolofuzz.NewLocalListenerArgsH\x00R\x10NewLocalListener\x12_\n" +
"\x16NewLocalPacketListener\x18\a \x01(\v2%.ngolofuzz.NewLocalPacketListenerArgsH\x00R\x16NewLocalPacketListener\x128\n" +
"\tLocalPath\x18\b \x01(\v2\x18.ngolofuzz.LocalPathArgsH\x00R\tLocalPath\x12P\n" +
"\x11LoopbackInterface\x18\t \x01(\v2 .ngolofuzz.LoopbackInterfaceArgsH\x00R\x11LoopbackInterfaceB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1aZ\x18./;fuzz_ng_x_net_nettestb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
var file_ngolofuzz_proto_goTypes = []any{
(*SupportsIPv4Args)(nil), // 0: ngolofuzz.SupportsIPv4Args
(*SupportsIPv6Args)(nil), // 1: ngolofuzz.SupportsIPv6Args
(*SupportsRawSocketArgs)(nil), // 2: ngolofuzz.SupportsRawSocketArgs
(*TestableNetworkArgs)(nil), // 3: ngolofuzz.TestableNetworkArgs
(*TestableAddressArgs)(nil), // 4: ngolofuzz.TestableAddressArgs
(*NewLocalListenerArgs)(nil), // 5: ngolofuzz.NewLocalListenerArgs
(*NewLocalPacketListenerArgs)(nil), // 6: ngolofuzz.NewLocalPacketListenerArgs
(*LocalPathArgs)(nil), // 7: ngolofuzz.LocalPathArgs
(*LoopbackInterfaceArgs)(nil), // 8: ngolofuzz.LoopbackInterfaceArgs
(*NgoloFuzzOne)(nil), // 9: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 10: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 11: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.SupportsIPv4:type_name -> ngolofuzz.SupportsIPv4Args
1, // 1: ngolofuzz.NgoloFuzzOne.SupportsIPv6:type_name -> ngolofuzz.SupportsIPv6Args
2, // 2: ngolofuzz.NgoloFuzzOne.SupportsRawSocket:type_name -> ngolofuzz.SupportsRawSocketArgs
3, // 3: ngolofuzz.NgoloFuzzOne.TestableNetwork:type_name -> ngolofuzz.TestableNetworkArgs
4, // 4: ngolofuzz.NgoloFuzzOne.TestableAddress:type_name -> ngolofuzz.TestableAddressArgs
5, // 5: ngolofuzz.NgoloFuzzOne.NewLocalListener:type_name -> ngolofuzz.NewLocalListenerArgs
6, // 6: ngolofuzz.NgoloFuzzOne.NewLocalPacketListener:type_name -> ngolofuzz.NewLocalPacketListenerArgs
7, // 7: ngolofuzz.NgoloFuzzOne.LocalPath:type_name -> ngolofuzz.LocalPathArgs
8, // 8: ngolofuzz.NgoloFuzzOne.LoopbackInterface:type_name -> ngolofuzz.LoopbackInterfaceArgs
9, // 9: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
10, // [10:10] is the sub-list for method output_type
10, // [10:10] is the sub-list for method input_type
10, // [10:10] is the sub-list for extension type_name
10, // [10:10] is the sub-list for extension extendee
0, // [0:10] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[9].OneofWrappers = []any{
(*NgoloFuzzOne_SupportsIPv4)(nil),
(*NgoloFuzzOne_SupportsIPv6)(nil),
(*NgoloFuzzOne_SupportsRawSocket)(nil),
(*NgoloFuzzOne_TestableNetwork)(nil),
(*NgoloFuzzOne_TestableAddress)(nil),
(*NgoloFuzzOne_NewLocalListener)(nil),
(*NgoloFuzzOne_NewLocalPacketListener)(nil),
(*NgoloFuzzOne_LocalPath)(nil),
(*NgoloFuzzOne_LoopbackInterface)(nil),
}
file_ngolofuzz_proto_msgTypes[10].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 12,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_net_proxy
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/net/proxy"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func AuthNewFromFuzz(p *AuthStruct) *proxy.Auth{
if p == nil {
return nil
}
return &proxy.Auth{
User: p.User,
Password: p.Password,
}
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var PerHostResults []*proxy.PerHost
PerHostResultsIndex := 0
var DialerResults []*proxy.Dialer
DialerResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewPerHost:
if len(DialerResults) == 0 {
continue
}
arg0 := *DialerResults[DialerResultsIndex]
DialerResultsIndex = (DialerResultsIndex + 1) % len(DialerResults)
if len(DialerResults) == 0 {
continue
}
arg1 := *DialerResults[DialerResultsIndex]
DialerResultsIndex = (DialerResultsIndex + 1) % len(DialerResults)
r0 := proxy.NewPerHost(arg0, arg1)
if r0 != nil{
PerHostResults = append(PerHostResults, r0)
}
case *NgoloFuzzOne_PerHostNgdotDial:
if len(PerHostResults) == 0 {
continue
}
arg0 := PerHostResults[PerHostResultsIndex]
PerHostResultsIndex = (PerHostResultsIndex + 1) % len(PerHostResults)
_, r1 := arg0.Dial(a.PerHostNgdotDial.Network, a.PerHostNgdotDial.Addr)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_PerHostNgdotAddFromString:
if len(PerHostResults) == 0 {
continue
}
arg0 := PerHostResults[PerHostResultsIndex]
PerHostResultsIndex = (PerHostResultsIndex + 1) % len(PerHostResults)
arg0.AddFromString(a.PerHostNgdotAddFromString.S)
case *NgoloFuzzOne_PerHostNgdotAddZone:
if len(PerHostResults) == 0 {
continue
}
arg0 := PerHostResults[PerHostResultsIndex]
PerHostResultsIndex = (PerHostResultsIndex + 1) % len(PerHostResults)
arg0.AddZone(a.PerHostNgdotAddZone.Zone)
case *NgoloFuzzOne_PerHostNgdotAddHost:
if len(PerHostResults) == 0 {
continue
}
arg0 := PerHostResults[PerHostResultsIndex]
PerHostResultsIndex = (PerHostResultsIndex + 1) % len(PerHostResults)
arg0.AddHost(a.PerHostNgdotAddHost.Host)
case *NgoloFuzzOne_FromEnvironment:
r0 := proxy.FromEnvironment()
DialerResults = append(DialerResults, &r0)
case *NgoloFuzzOne_FromEnvironmentUsing:
if len(DialerResults) == 0 {
continue
}
arg0 := *DialerResults[DialerResultsIndex]
DialerResultsIndex = (DialerResultsIndex + 1) % len(DialerResults)
r0 := proxy.FromEnvironmentUsing(arg0)
DialerResults = append(DialerResults, &r0)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
PerHostNb := 0
PerHostResultsIndex := 0
DialerNb := 0
DialerResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewPerHost:
if DialerNb == 0 {
continue
}
if DialerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("PerHost%d := proxy.NewPerHost(Dialer%d, Dialer%d)\n", PerHostNb, (DialerResultsIndex + 0) % DialerNb, (DialerResultsIndex + 1) % DialerNb))
PerHostNb = PerHostNb + 1
DialerResultsIndex = (DialerResultsIndex + 1) % DialerNb
DialerResultsIndex = (DialerResultsIndex + 1) % DialerNb
case *NgoloFuzzOne_PerHostNgdotDial:
if PerHostNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("PerHost%d.Dial(%#+v, %#+v)\n", PerHostResultsIndex, a.PerHostNgdotDial.Network, a.PerHostNgdotDial.Addr))
PerHostResultsIndex = (PerHostResultsIndex + 1) % PerHostNb
case *NgoloFuzzOne_PerHostNgdotAddFromString:
if PerHostNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("PerHost%d.AddFromString(%#+v)\n", PerHostResultsIndex, a.PerHostNgdotAddFromString.S))
PerHostResultsIndex = (PerHostResultsIndex + 1) % PerHostNb
case *NgoloFuzzOne_PerHostNgdotAddZone:
if PerHostNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("PerHost%d.AddZone(%#+v)\n", PerHostResultsIndex, a.PerHostNgdotAddZone.Zone))
PerHostResultsIndex = (PerHostResultsIndex + 1) % PerHostNb
case *NgoloFuzzOne_PerHostNgdotAddHost:
if PerHostNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("PerHost%d.AddHost(%#+v)\n", PerHostResultsIndex, a.PerHostNgdotAddHost.Host))
PerHostResultsIndex = (PerHostResultsIndex + 1) % PerHostNb
case *NgoloFuzzOne_FromEnvironment:
w.WriteString(fmt.Sprintf("Dialer%d := proxy.FromEnvironment()\n", DialerNb))
DialerNb = DialerNb + 1
case *NgoloFuzzOne_FromEnvironmentUsing:
if DialerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Dialer%d := proxy.FromEnvironmentUsing(Dialer%d)\n", DialerNb, (DialerResultsIndex + 0) % DialerNb))
DialerNb = DialerNb + 1
DialerResultsIndex = (DialerResultsIndex + 1) % DialerNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_net_proxy
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type AuthStruct struct {
state protoimpl.MessageState `protogen:"open.v1"`
User string `protobuf:"bytes,1,opt,name=User,proto3" json:"User,omitempty"`
Password string `protobuf:"bytes,2,opt,name=Password,proto3" json:"Password,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *AuthStruct) Reset() {
*x = AuthStruct{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AuthStruct) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AuthStruct) ProtoMessage() {}
func (x *AuthStruct) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AuthStruct.ProtoReflect.Descriptor instead.
func (*AuthStruct) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *AuthStruct) GetUser() string {
if x != nil {
return x.User
}
return ""
}
func (x *AuthStruct) GetPassword() string {
if x != nil {
return x.Password
}
return ""
}
type NewPerHostArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewPerHostArgs) Reset() {
*x = NewPerHostArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewPerHostArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewPerHostArgs) ProtoMessage() {}
func (x *NewPerHostArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewPerHostArgs.ProtoReflect.Descriptor instead.
func (*NewPerHostArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
type PerHostNgdotDialArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Network string `protobuf:"bytes,1,opt,name=network,proto3" json:"network,omitempty"`
Addr string `protobuf:"bytes,2,opt,name=addr,proto3" json:"addr,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PerHostNgdotDialArgs) Reset() {
*x = PerHostNgdotDialArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PerHostNgdotDialArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PerHostNgdotDialArgs) ProtoMessage() {}
func (x *PerHostNgdotDialArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PerHostNgdotDialArgs.ProtoReflect.Descriptor instead.
func (*PerHostNgdotDialArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *PerHostNgdotDialArgs) GetNetwork() string {
if x != nil {
return x.Network
}
return ""
}
func (x *PerHostNgdotDialArgs) GetAddr() string {
if x != nil {
return x.Addr
}
return ""
}
type PerHostNgdotAddFromStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S string `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PerHostNgdotAddFromStringArgs) Reset() {
*x = PerHostNgdotAddFromStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PerHostNgdotAddFromStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PerHostNgdotAddFromStringArgs) ProtoMessage() {}
func (x *PerHostNgdotAddFromStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PerHostNgdotAddFromStringArgs.ProtoReflect.Descriptor instead.
func (*PerHostNgdotAddFromStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *PerHostNgdotAddFromStringArgs) GetS() string {
if x != nil {
return x.S
}
return ""
}
type PerHostNgdotAddZoneArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Zone string `protobuf:"bytes,1,opt,name=zone,proto3" json:"zone,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PerHostNgdotAddZoneArgs) Reset() {
*x = PerHostNgdotAddZoneArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PerHostNgdotAddZoneArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PerHostNgdotAddZoneArgs) ProtoMessage() {}
func (x *PerHostNgdotAddZoneArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PerHostNgdotAddZoneArgs.ProtoReflect.Descriptor instead.
func (*PerHostNgdotAddZoneArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *PerHostNgdotAddZoneArgs) GetZone() string {
if x != nil {
return x.Zone
}
return ""
}
type PerHostNgdotAddHostArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Host string `protobuf:"bytes,1,opt,name=host,proto3" json:"host,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PerHostNgdotAddHostArgs) Reset() {
*x = PerHostNgdotAddHostArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PerHostNgdotAddHostArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PerHostNgdotAddHostArgs) ProtoMessage() {}
func (x *PerHostNgdotAddHostArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PerHostNgdotAddHostArgs.ProtoReflect.Descriptor instead.
func (*PerHostNgdotAddHostArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *PerHostNgdotAddHostArgs) GetHost() string {
if x != nil {
return x.Host
}
return ""
}
type FromEnvironmentArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FromEnvironmentArgs) Reset() {
*x = FromEnvironmentArgs{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FromEnvironmentArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FromEnvironmentArgs) ProtoMessage() {}
func (x *FromEnvironmentArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FromEnvironmentArgs.ProtoReflect.Descriptor instead.
func (*FromEnvironmentArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
type FromEnvironmentUsingArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FromEnvironmentUsingArgs) Reset() {
*x = FromEnvironmentUsingArgs{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FromEnvironmentUsingArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FromEnvironmentUsingArgs) ProtoMessage() {}
func (x *FromEnvironmentUsingArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FromEnvironmentUsingArgs.ProtoReflect.Descriptor instead.
func (*FromEnvironmentUsingArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_NewPerHost
// *NgoloFuzzOne_PerHostNgdotDial
// *NgoloFuzzOne_PerHostNgdotAddFromString
// *NgoloFuzzOne_PerHostNgdotAddZone
// *NgoloFuzzOne_PerHostNgdotAddHost
// *NgoloFuzzOne_FromEnvironment
// *NgoloFuzzOne_FromEnvironmentUsing
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetNewPerHost() *NewPerHostArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewPerHost); ok {
return x.NewPerHost
}
}
return nil
}
func (x *NgoloFuzzOne) GetPerHostNgdotDial() *PerHostNgdotDialArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_PerHostNgdotDial); ok {
return x.PerHostNgdotDial
}
}
return nil
}
func (x *NgoloFuzzOne) GetPerHostNgdotAddFromString() *PerHostNgdotAddFromStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_PerHostNgdotAddFromString); ok {
return x.PerHostNgdotAddFromString
}
}
return nil
}
func (x *NgoloFuzzOne) GetPerHostNgdotAddZone() *PerHostNgdotAddZoneArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_PerHostNgdotAddZone); ok {
return x.PerHostNgdotAddZone
}
}
return nil
}
func (x *NgoloFuzzOne) GetPerHostNgdotAddHost() *PerHostNgdotAddHostArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_PerHostNgdotAddHost); ok {
return x.PerHostNgdotAddHost
}
}
return nil
}
func (x *NgoloFuzzOne) GetFromEnvironment() *FromEnvironmentArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FromEnvironment); ok {
return x.FromEnvironment
}
}
return nil
}
func (x *NgoloFuzzOne) GetFromEnvironmentUsing() *FromEnvironmentUsingArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FromEnvironmentUsing); ok {
return x.FromEnvironmentUsing
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_NewPerHost struct {
NewPerHost *NewPerHostArgs `protobuf:"bytes,1,opt,name=NewPerHost,proto3,oneof"`
}
type NgoloFuzzOne_PerHostNgdotDial struct {
PerHostNgdotDial *PerHostNgdotDialArgs `protobuf:"bytes,2,opt,name=PerHostNgdotDial,proto3,oneof"`
}
type NgoloFuzzOne_PerHostNgdotAddFromString struct {
PerHostNgdotAddFromString *PerHostNgdotAddFromStringArgs `protobuf:"bytes,3,opt,name=PerHostNgdotAddFromString,proto3,oneof"`
}
type NgoloFuzzOne_PerHostNgdotAddZone struct {
PerHostNgdotAddZone *PerHostNgdotAddZoneArgs `protobuf:"bytes,4,opt,name=PerHostNgdotAddZone,proto3,oneof"`
}
type NgoloFuzzOne_PerHostNgdotAddHost struct {
PerHostNgdotAddHost *PerHostNgdotAddHostArgs `protobuf:"bytes,5,opt,name=PerHostNgdotAddHost,proto3,oneof"`
}
type NgoloFuzzOne_FromEnvironment struct {
FromEnvironment *FromEnvironmentArgs `protobuf:"bytes,6,opt,name=FromEnvironment,proto3,oneof"`
}
type NgoloFuzzOne_FromEnvironmentUsing struct {
FromEnvironmentUsing *FromEnvironmentUsingArgs `protobuf:"bytes,7,opt,name=FromEnvironmentUsing,proto3,oneof"`
}
func (*NgoloFuzzOne_NewPerHost) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_PerHostNgdotDial) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_PerHostNgdotAddFromString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_PerHostNgdotAddZone) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_PerHostNgdotAddHost) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FromEnvironment) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FromEnvironmentUsing) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{10}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"<\n" +
"\n" +
"AuthStruct\x12\x12\n" +
"\x04User\x18\x01 \x01(\tR\x04User\x12\x1a\n" +
"\bPassword\x18\x02 \x01(\tR\bPassword\"\x10\n" +
"\x0eNewPerHostArgs\"D\n" +
"\x14PerHostNgdotDialArgs\x12\x18\n" +
"\anetwork\x18\x01 \x01(\tR\anetwork\x12\x12\n" +
"\x04addr\x18\x02 \x01(\tR\x04addr\"-\n" +
"\x1dPerHostNgdotAddFromStringArgs\x12\f\n" +
"\x01s\x18\x01 \x01(\tR\x01s\"-\n" +
"\x17PerHostNgdotAddZoneArgs\x12\x12\n" +
"\x04zone\x18\x01 \x01(\tR\x04zone\"-\n" +
"\x17PerHostNgdotAddHostArgs\x12\x12\n" +
"\x04host\x18\x01 \x01(\tR\x04host\"\x15\n" +
"\x13FromEnvironmentArgs\"\x1a\n" +
"\x18FromEnvironmentUsingArgs\"\xe3\x04\n" +
"\fNgoloFuzzOne\x12;\n" +
"\n" +
"NewPerHost\x18\x01 \x01(\v2\x19.ngolofuzz.NewPerHostArgsH\x00R\n" +
"NewPerHost\x12M\n" +
"\x10PerHostNgdotDial\x18\x02 \x01(\v2\x1f.ngolofuzz.PerHostNgdotDialArgsH\x00R\x10PerHostNgdotDial\x12h\n" +
"\x19PerHostNgdotAddFromString\x18\x03 \x01(\v2(.ngolofuzz.PerHostNgdotAddFromStringArgsH\x00R\x19PerHostNgdotAddFromString\x12V\n" +
"\x13PerHostNgdotAddZone\x18\x04 \x01(\v2\".ngolofuzz.PerHostNgdotAddZoneArgsH\x00R\x13PerHostNgdotAddZone\x12V\n" +
"\x13PerHostNgdotAddHost\x18\x05 \x01(\v2\".ngolofuzz.PerHostNgdotAddHostArgsH\x00R\x13PerHostNgdotAddHost\x12J\n" +
"\x0fFromEnvironment\x18\x06 \x01(\v2\x1e.ngolofuzz.FromEnvironmentArgsH\x00R\x0fFromEnvironment\x12Y\n" +
"\x14FromEnvironmentUsing\x18\a \x01(\v2#.ngolofuzz.FromEnvironmentUsingArgsH\x00R\x14FromEnvironmentUsingB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x18Z\x16./;fuzz_ng_x_net_proxyb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
var file_ngolofuzz_proto_goTypes = []any{
(*AuthStruct)(nil), // 0: ngolofuzz.AuthStruct
(*NewPerHostArgs)(nil), // 1: ngolofuzz.NewPerHostArgs
(*PerHostNgdotDialArgs)(nil), // 2: ngolofuzz.PerHostNgdotDialArgs
(*PerHostNgdotAddFromStringArgs)(nil), // 3: ngolofuzz.PerHostNgdotAddFromStringArgs
(*PerHostNgdotAddZoneArgs)(nil), // 4: ngolofuzz.PerHostNgdotAddZoneArgs
(*PerHostNgdotAddHostArgs)(nil), // 5: ngolofuzz.PerHostNgdotAddHostArgs
(*FromEnvironmentArgs)(nil), // 6: ngolofuzz.FromEnvironmentArgs
(*FromEnvironmentUsingArgs)(nil), // 7: ngolofuzz.FromEnvironmentUsingArgs
(*NgoloFuzzOne)(nil), // 8: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 9: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 10: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
1, // 0: ngolofuzz.NgoloFuzzOne.NewPerHost:type_name -> ngolofuzz.NewPerHostArgs
2, // 1: ngolofuzz.NgoloFuzzOne.PerHostNgdotDial:type_name -> ngolofuzz.PerHostNgdotDialArgs
3, // 2: ngolofuzz.NgoloFuzzOne.PerHostNgdotAddFromString:type_name -> ngolofuzz.PerHostNgdotAddFromStringArgs
4, // 3: ngolofuzz.NgoloFuzzOne.PerHostNgdotAddZone:type_name -> ngolofuzz.PerHostNgdotAddZoneArgs
5, // 4: ngolofuzz.NgoloFuzzOne.PerHostNgdotAddHost:type_name -> ngolofuzz.PerHostNgdotAddHostArgs
6, // 5: ngolofuzz.NgoloFuzzOne.FromEnvironment:type_name -> ngolofuzz.FromEnvironmentArgs
7, // 6: ngolofuzz.NgoloFuzzOne.FromEnvironmentUsing:type_name -> ngolofuzz.FromEnvironmentUsingArgs
8, // 7: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
8, // [8:8] is the sub-list for method output_type
8, // [8:8] is the sub-list for method input_type
8, // [8:8] is the sub-list for extension type_name
8, // [8:8] is the sub-list for extension extendee
0, // [0:8] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[8].OneofWrappers = []any{
(*NgoloFuzzOne_NewPerHost)(nil),
(*NgoloFuzzOne_PerHostNgdotDial)(nil),
(*NgoloFuzzOne_PerHostNgdotAddFromString)(nil),
(*NgoloFuzzOne_PerHostNgdotAddZone)(nil),
(*NgoloFuzzOne_PerHostNgdotAddHost)(nil),
(*NgoloFuzzOne_FromEnvironment)(nil),
(*NgoloFuzzOne_FromEnvironmentUsing)(nil),
}
file_ngolofuzz_proto_msgTypes[9].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 11,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_net_publicsuffix
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/net/publicsuffix"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_PublicSuffix:
publicsuffix.PublicSuffix(a.PublicSuffix.Domain)
case *NgoloFuzzOne_EffectiveTLDPlusOne:
_, r1 := publicsuffix.EffectiveTLDPlusOne(a.EffectiveTLDPlusOne.Domain)
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_PublicSuffix:
w.WriteString(fmt.Sprintf("publicsuffix.PublicSuffix(%#+v)\n", a.PublicSuffix.Domain))
case *NgoloFuzzOne_EffectiveTLDPlusOne:
w.WriteString(fmt.Sprintf("publicsuffix.EffectiveTLDPlusOne(%#+v)\n", a.EffectiveTLDPlusOne.Domain))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_net_publicsuffix
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type PublicSuffixArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Domain string `protobuf:"bytes,1,opt,name=domain,proto3" json:"domain,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PublicSuffixArgs) Reset() {
*x = PublicSuffixArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PublicSuffixArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PublicSuffixArgs) ProtoMessage() {}
func (x *PublicSuffixArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PublicSuffixArgs.ProtoReflect.Descriptor instead.
func (*PublicSuffixArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *PublicSuffixArgs) GetDomain() string {
if x != nil {
return x.Domain
}
return ""
}
type EffectiveTLDPlusOneArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Domain string `protobuf:"bytes,1,opt,name=domain,proto3" json:"domain,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *EffectiveTLDPlusOneArgs) Reset() {
*x = EffectiveTLDPlusOneArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *EffectiveTLDPlusOneArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EffectiveTLDPlusOneArgs) ProtoMessage() {}
func (x *EffectiveTLDPlusOneArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EffectiveTLDPlusOneArgs.ProtoReflect.Descriptor instead.
func (*EffectiveTLDPlusOneArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *EffectiveTLDPlusOneArgs) GetDomain() string {
if x != nil {
return x.Domain
}
return ""
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_PublicSuffix
// *NgoloFuzzOne_EffectiveTLDPlusOne
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetPublicSuffix() *PublicSuffixArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_PublicSuffix); ok {
return x.PublicSuffix
}
}
return nil
}
func (x *NgoloFuzzOne) GetEffectiveTLDPlusOne() *EffectiveTLDPlusOneArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_EffectiveTLDPlusOne); ok {
return x.EffectiveTLDPlusOne
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_PublicSuffix struct {
PublicSuffix *PublicSuffixArgs `protobuf:"bytes,1,opt,name=PublicSuffix,proto3,oneof"`
}
type NgoloFuzzOne_EffectiveTLDPlusOne struct {
EffectiveTLDPlusOne *EffectiveTLDPlusOneArgs `protobuf:"bytes,2,opt,name=EffectiveTLDPlusOne,proto3,oneof"`
}
func (*NgoloFuzzOne_PublicSuffix) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_EffectiveTLDPlusOne) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"*\n" +
"\x10PublicSuffixArgs\x12\x16\n" +
"\x06domain\x18\x01 \x01(\tR\x06domain\"1\n" +
"\x17EffectiveTLDPlusOneArgs\x12\x16\n" +
"\x06domain\x18\x01 \x01(\tR\x06domain\"\xb1\x01\n" +
"\fNgoloFuzzOne\x12A\n" +
"\fPublicSuffix\x18\x01 \x01(\v2\x1b.ngolofuzz.PublicSuffixArgsH\x00R\fPublicSuffix\x12V\n" +
"\x13EffectiveTLDPlusOne\x18\x02 \x01(\v2\".ngolofuzz.EffectiveTLDPlusOneArgsH\x00R\x13EffectiveTLDPlusOneB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1fZ\x1d./;fuzz_ng_x_net_publicsuffixb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_ngolofuzz_proto_goTypes = []any{
(*PublicSuffixArgs)(nil), // 0: ngolofuzz.PublicSuffixArgs
(*EffectiveTLDPlusOneArgs)(nil), // 1: ngolofuzz.EffectiveTLDPlusOneArgs
(*NgoloFuzzOne)(nil), // 2: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 3: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 4: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.PublicSuffix:type_name -> ngolofuzz.PublicSuffixArgs
1, // 1: ngolofuzz.NgoloFuzzOne.EffectiveTLDPlusOne:type_name -> ngolofuzz.EffectiveTLDPlusOneArgs
2, // 2: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzOne_PublicSuffix)(nil),
(*NgoloFuzzOne_EffectiveTLDPlusOne)(nil),
}
file_ngolofuzz_proto_msgTypes[3].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_net_quic
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/net/quic"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var EndpointResults []*quic.Endpoint
EndpointResultsIndex := 0
var StreamResults []*quic.Stream
StreamResultsIndex := 0
var ConfigResults []*quic.Config
ConfigResultsIndex := 0
var ConnResults []*quic.Conn
ConnResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_ConfigNgdotClone:
if len(ConfigResults) == 0 {
continue
}
arg0 := ConfigResults[ConfigResultsIndex]
ConfigResultsIndex = (ConfigResultsIndex + 1) % len(ConfigResults)
arg0.Clone()
case *NgoloFuzzOne_ConnNgdotString:
if len(ConnResults) == 0 {
continue
}
arg0 := ConnResults[ConnResultsIndex]
ConnResultsIndex = (ConnResultsIndex + 1) % len(ConnResults)
arg0.String()
case *NgoloFuzzOne_ConnNgdotLocalAddr:
if len(ConnResults) == 0 {
continue
}
arg0 := ConnResults[ConnResultsIndex]
ConnResultsIndex = (ConnResultsIndex + 1) % len(ConnResults)
arg0.LocalAddr()
case *NgoloFuzzOne_ConnNgdotRemoteAddr:
if len(ConnResults) == 0 {
continue
}
arg0 := ConnResults[ConnResultsIndex]
ConnResultsIndex = (ConnResultsIndex + 1) % len(ConnResults)
arg0.RemoteAddr()
case *NgoloFuzzOne_ConnNgdotConnectionState:
if len(ConnResults) == 0 {
continue
}
arg0 := ConnResults[ConnResultsIndex]
ConnResultsIndex = (ConnResultsIndex + 1) % len(ConnResults)
arg0.ConnectionState()
case *NgoloFuzzOne_ConnNgdotClose:
if len(ConnResults) == 0 {
continue
}
arg0 := ConnResults[ConnResultsIndex]
ConnResultsIndex = (ConnResultsIndex + 1) % len(ConnResults)
r0 := arg0.Close()
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_Listen:
if len(ConfigResults) == 0 {
continue
}
arg2 := ConfigResults[ConfigResultsIndex]
ConfigResultsIndex = (ConfigResultsIndex + 1) % len(ConfigResults)
r0, r1 := quic.Listen(a.Listen.Network, a.Listen.Address, arg2)
if r0 != nil{
EndpointResults = append(EndpointResults, r0)
}
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_EndpointNgdotLocalAddr:
if len(EndpointResults) == 0 {
continue
}
arg0 := EndpointResults[EndpointResultsIndex]
EndpointResultsIndex = (EndpointResultsIndex + 1) % len(EndpointResults)
arg0.LocalAddr()
case *NgoloFuzzOne_StreamNgdotIsReadOnly:
if len(StreamResults) == 0 {
continue
}
arg0 := StreamResults[StreamResultsIndex]
StreamResultsIndex = (StreamResultsIndex + 1) % len(StreamResults)
arg0.IsReadOnly()
case *NgoloFuzzOne_StreamNgdotIsWriteOnly:
if len(StreamResults) == 0 {
continue
}
arg0 := StreamResults[StreamResultsIndex]
StreamResultsIndex = (StreamResultsIndex + 1) % len(StreamResults)
arg0.IsWriteOnly()
case *NgoloFuzzOne_StreamNgdotRead:
if len(StreamResults) == 0 {
continue
}
arg0 := StreamResults[StreamResultsIndex]
StreamResultsIndex = (StreamResultsIndex + 1) % len(StreamResults)
_, r1 := arg0.Read(a.StreamNgdotRead.B)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_StreamNgdotReadByte:
if len(StreamResults) == 0 {
continue
}
arg0 := StreamResults[StreamResultsIndex]
StreamResultsIndex = (StreamResultsIndex + 1) % len(StreamResults)
_, r1 := arg0.ReadByte()
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_StreamNgdotWrite:
if len(StreamResults) == 0 {
continue
}
arg0 := StreamResults[StreamResultsIndex]
StreamResultsIndex = (StreamResultsIndex + 1) % len(StreamResults)
_, r1 := arg0.Write(a.StreamNgdotWrite.B)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_StreamNgdotWriteByte:
if len(StreamResults) == 0 {
continue
}
arg0 := StreamResults[StreamResultsIndex]
StreamResultsIndex = (StreamResultsIndex + 1) % len(StreamResults)
arg1 := byte(a.StreamNgdotWriteByte.C)
r0 := arg0.WriteByte(arg1)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_StreamNgdotFlush:
if len(StreamResults) == 0 {
continue
}
arg0 := StreamResults[StreamResultsIndex]
StreamResultsIndex = (StreamResultsIndex + 1) % len(StreamResults)
r0 := arg0.Flush()
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_StreamNgdotClose:
if len(StreamResults) == 0 {
continue
}
arg0 := StreamResults[StreamResultsIndex]
StreamResultsIndex = (StreamResultsIndex + 1) % len(StreamResults)
r0 := arg0.Close()
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_StreamNgdotCloseRead:
if len(StreamResults) == 0 {
continue
}
arg0 := StreamResults[StreamResultsIndex]
StreamResultsIndex = (StreamResultsIndex + 1) % len(StreamResults)
arg0.CloseRead()
case *NgoloFuzzOne_StreamNgdotCloseWrite:
if len(StreamResults) == 0 {
continue
}
arg0 := StreamResults[StreamResultsIndex]
StreamResultsIndex = (StreamResultsIndex + 1) % len(StreamResults)
arg0.CloseWrite()
case *NgoloFuzzOne_StreamNgdotReset:
if len(StreamResults) == 0 {
continue
}
arg0 := StreamResults[StreamResultsIndex]
StreamResultsIndex = (StreamResultsIndex + 1) % len(StreamResults)
arg0.Reset(a.StreamNgdotReset.Code)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
EndpointNb := 0
EndpointResultsIndex := 0
StreamNb := 0
StreamResultsIndex := 0
ConfigNb := 0
ConfigResultsIndex := 0
ConnNb := 0
ConnResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_ConfigNgdotClone:
if ConfigNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Config%d.Clone()\n", ConfigResultsIndex))
ConfigResultsIndex = (ConfigResultsIndex + 1) % ConfigNb
case *NgoloFuzzOne_ConnNgdotString:
if ConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Conn%d.String()\n", ConnResultsIndex))
ConnResultsIndex = (ConnResultsIndex + 1) % ConnNb
case *NgoloFuzzOne_ConnNgdotLocalAddr:
if ConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Conn%d.LocalAddr()\n", ConnResultsIndex))
ConnResultsIndex = (ConnResultsIndex + 1) % ConnNb
case *NgoloFuzzOne_ConnNgdotRemoteAddr:
if ConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Conn%d.RemoteAddr()\n", ConnResultsIndex))
ConnResultsIndex = (ConnResultsIndex + 1) % ConnNb
case *NgoloFuzzOne_ConnNgdotConnectionState:
if ConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Conn%d.ConnectionState()\n", ConnResultsIndex))
ConnResultsIndex = (ConnResultsIndex + 1) % ConnNb
case *NgoloFuzzOne_ConnNgdotClose:
if ConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Conn%d.Close()\n", ConnResultsIndex))
ConnResultsIndex = (ConnResultsIndex + 1) % ConnNb
case *NgoloFuzzOne_Listen:
if ConfigNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Endpoint%d, _ := quic.Listen(%#+v, %#+v, Config%d)\n", EndpointNb, a.Listen.Network, a.Listen.Address, (ConfigResultsIndex + 0) % ConfigNb))
EndpointNb = EndpointNb + 1
ConfigResultsIndex = (ConfigResultsIndex + 1) % ConfigNb
case *NgoloFuzzOne_EndpointNgdotLocalAddr:
if EndpointNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Endpoint%d.LocalAddr()\n", EndpointResultsIndex))
EndpointResultsIndex = (EndpointResultsIndex + 1) % EndpointNb
case *NgoloFuzzOne_StreamNgdotIsReadOnly:
if StreamNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Stream%d.IsReadOnly()\n", StreamResultsIndex))
StreamResultsIndex = (StreamResultsIndex + 1) % StreamNb
case *NgoloFuzzOne_StreamNgdotIsWriteOnly:
if StreamNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Stream%d.IsWriteOnly()\n", StreamResultsIndex))
StreamResultsIndex = (StreamResultsIndex + 1) % StreamNb
case *NgoloFuzzOne_StreamNgdotRead:
if StreamNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Stream%d.Read(%#+v)\n", StreamResultsIndex, a.StreamNgdotRead.B))
StreamResultsIndex = (StreamResultsIndex + 1) % StreamNb
case *NgoloFuzzOne_StreamNgdotReadByte:
if StreamNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Stream%d.ReadByte()\n", StreamResultsIndex))
StreamResultsIndex = (StreamResultsIndex + 1) % StreamNb
case *NgoloFuzzOne_StreamNgdotWrite:
if StreamNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Stream%d.Write(%#+v)\n", StreamResultsIndex, a.StreamNgdotWrite.B))
StreamResultsIndex = (StreamResultsIndex + 1) % StreamNb
case *NgoloFuzzOne_StreamNgdotWriteByte:
if StreamNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Stream%d.WriteByte(byte(%#+v))\n", StreamResultsIndex, a.StreamNgdotWriteByte.C))
StreamResultsIndex = (StreamResultsIndex + 1) % StreamNb
case *NgoloFuzzOne_StreamNgdotFlush:
if StreamNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Stream%d.Flush()\n", StreamResultsIndex))
StreamResultsIndex = (StreamResultsIndex + 1) % StreamNb
case *NgoloFuzzOne_StreamNgdotClose:
if StreamNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Stream%d.Close()\n", StreamResultsIndex))
StreamResultsIndex = (StreamResultsIndex + 1) % StreamNb
case *NgoloFuzzOne_StreamNgdotCloseRead:
if StreamNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Stream%d.CloseRead()\n", StreamResultsIndex))
StreamResultsIndex = (StreamResultsIndex + 1) % StreamNb
case *NgoloFuzzOne_StreamNgdotCloseWrite:
if StreamNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Stream%d.CloseWrite()\n", StreamResultsIndex))
StreamResultsIndex = (StreamResultsIndex + 1) % StreamNb
case *NgoloFuzzOne_StreamNgdotReset:
if StreamNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Stream%d.Reset(%#+v)\n", StreamResultsIndex, a.StreamNgdotReset.Code))
StreamResultsIndex = (StreamResultsIndex + 1) % StreamNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_net_quic
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ConfigNgdotCloneArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ConfigNgdotCloneArgs) Reset() {
*x = ConfigNgdotCloneArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ConfigNgdotCloneArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConfigNgdotCloneArgs) ProtoMessage() {}
func (x *ConfigNgdotCloneArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ConfigNgdotCloneArgs.ProtoReflect.Descriptor instead.
func (*ConfigNgdotCloneArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type ConnNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ConnNgdotStringArgs) Reset() {
*x = ConnNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ConnNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConnNgdotStringArgs) ProtoMessage() {}
func (x *ConnNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ConnNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*ConnNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
type ConnNgdotLocalAddrArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ConnNgdotLocalAddrArgs) Reset() {
*x = ConnNgdotLocalAddrArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ConnNgdotLocalAddrArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConnNgdotLocalAddrArgs) ProtoMessage() {}
func (x *ConnNgdotLocalAddrArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ConnNgdotLocalAddrArgs.ProtoReflect.Descriptor instead.
func (*ConnNgdotLocalAddrArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
type ConnNgdotRemoteAddrArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ConnNgdotRemoteAddrArgs) Reset() {
*x = ConnNgdotRemoteAddrArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ConnNgdotRemoteAddrArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConnNgdotRemoteAddrArgs) ProtoMessage() {}
func (x *ConnNgdotRemoteAddrArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ConnNgdotRemoteAddrArgs.ProtoReflect.Descriptor instead.
func (*ConnNgdotRemoteAddrArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
type ConnNgdotConnectionStateArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ConnNgdotConnectionStateArgs) Reset() {
*x = ConnNgdotConnectionStateArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ConnNgdotConnectionStateArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConnNgdotConnectionStateArgs) ProtoMessage() {}
func (x *ConnNgdotConnectionStateArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ConnNgdotConnectionStateArgs.ProtoReflect.Descriptor instead.
func (*ConnNgdotConnectionStateArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
type ConnNgdotCloseArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ConnNgdotCloseArgs) Reset() {
*x = ConnNgdotCloseArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ConnNgdotCloseArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConnNgdotCloseArgs) ProtoMessage() {}
func (x *ConnNgdotCloseArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ConnNgdotCloseArgs.ProtoReflect.Descriptor instead.
func (*ConnNgdotCloseArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
type ListenArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Network string `protobuf:"bytes,1,opt,name=network,proto3" json:"network,omitempty"`
Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ListenArgs) Reset() {
*x = ListenArgs{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ListenArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListenArgs) ProtoMessage() {}
func (x *ListenArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ListenArgs.ProtoReflect.Descriptor instead.
func (*ListenArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *ListenArgs) GetNetwork() string {
if x != nil {
return x.Network
}
return ""
}
func (x *ListenArgs) GetAddress() string {
if x != nil {
return x.Address
}
return ""
}
type EndpointNgdotLocalAddrArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *EndpointNgdotLocalAddrArgs) Reset() {
*x = EndpointNgdotLocalAddrArgs{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *EndpointNgdotLocalAddrArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EndpointNgdotLocalAddrArgs) ProtoMessage() {}
func (x *EndpointNgdotLocalAddrArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EndpointNgdotLocalAddrArgs.ProtoReflect.Descriptor instead.
func (*EndpointNgdotLocalAddrArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
type StreamNgdotIsReadOnlyArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *StreamNgdotIsReadOnlyArgs) Reset() {
*x = StreamNgdotIsReadOnlyArgs{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *StreamNgdotIsReadOnlyArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StreamNgdotIsReadOnlyArgs) ProtoMessage() {}
func (x *StreamNgdotIsReadOnlyArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StreamNgdotIsReadOnlyArgs.ProtoReflect.Descriptor instead.
func (*StreamNgdotIsReadOnlyArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
type StreamNgdotIsWriteOnlyArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *StreamNgdotIsWriteOnlyArgs) Reset() {
*x = StreamNgdotIsWriteOnlyArgs{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *StreamNgdotIsWriteOnlyArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StreamNgdotIsWriteOnlyArgs) ProtoMessage() {}
func (x *StreamNgdotIsWriteOnlyArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StreamNgdotIsWriteOnlyArgs.ProtoReflect.Descriptor instead.
func (*StreamNgdotIsWriteOnlyArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
type StreamNgdotReadArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
B []byte `protobuf:"bytes,1,opt,name=b,proto3" json:"b,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *StreamNgdotReadArgs) Reset() {
*x = StreamNgdotReadArgs{}
mi := &file_ngolofuzz_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *StreamNgdotReadArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StreamNgdotReadArgs) ProtoMessage() {}
func (x *StreamNgdotReadArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StreamNgdotReadArgs.ProtoReflect.Descriptor instead.
func (*StreamNgdotReadArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{10}
}
func (x *StreamNgdotReadArgs) GetB() []byte {
if x != nil {
return x.B
}
return nil
}
type StreamNgdotReadByteArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *StreamNgdotReadByteArgs) Reset() {
*x = StreamNgdotReadByteArgs{}
mi := &file_ngolofuzz_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *StreamNgdotReadByteArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StreamNgdotReadByteArgs) ProtoMessage() {}
func (x *StreamNgdotReadByteArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[11]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StreamNgdotReadByteArgs.ProtoReflect.Descriptor instead.
func (*StreamNgdotReadByteArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{11}
}
type StreamNgdotWriteArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
B []byte `protobuf:"bytes,1,opt,name=b,proto3" json:"b,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *StreamNgdotWriteArgs) Reset() {
*x = StreamNgdotWriteArgs{}
mi := &file_ngolofuzz_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *StreamNgdotWriteArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StreamNgdotWriteArgs) ProtoMessage() {}
func (x *StreamNgdotWriteArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[12]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StreamNgdotWriteArgs.ProtoReflect.Descriptor instead.
func (*StreamNgdotWriteArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{12}
}
func (x *StreamNgdotWriteArgs) GetB() []byte {
if x != nil {
return x.B
}
return nil
}
type StreamNgdotWriteByteArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
C uint32 `protobuf:"varint,1,opt,name=c,proto3" json:"c,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *StreamNgdotWriteByteArgs) Reset() {
*x = StreamNgdotWriteByteArgs{}
mi := &file_ngolofuzz_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *StreamNgdotWriteByteArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StreamNgdotWriteByteArgs) ProtoMessage() {}
func (x *StreamNgdotWriteByteArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[13]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StreamNgdotWriteByteArgs.ProtoReflect.Descriptor instead.
func (*StreamNgdotWriteByteArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{13}
}
func (x *StreamNgdotWriteByteArgs) GetC() uint32 {
if x != nil {
return x.C
}
return 0
}
type StreamNgdotFlushArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *StreamNgdotFlushArgs) Reset() {
*x = StreamNgdotFlushArgs{}
mi := &file_ngolofuzz_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *StreamNgdotFlushArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StreamNgdotFlushArgs) ProtoMessage() {}
func (x *StreamNgdotFlushArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[14]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StreamNgdotFlushArgs.ProtoReflect.Descriptor instead.
func (*StreamNgdotFlushArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{14}
}
type StreamNgdotCloseArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *StreamNgdotCloseArgs) Reset() {
*x = StreamNgdotCloseArgs{}
mi := &file_ngolofuzz_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *StreamNgdotCloseArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StreamNgdotCloseArgs) ProtoMessage() {}
func (x *StreamNgdotCloseArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[15]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StreamNgdotCloseArgs.ProtoReflect.Descriptor instead.
func (*StreamNgdotCloseArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{15}
}
type StreamNgdotCloseReadArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *StreamNgdotCloseReadArgs) Reset() {
*x = StreamNgdotCloseReadArgs{}
mi := &file_ngolofuzz_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *StreamNgdotCloseReadArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StreamNgdotCloseReadArgs) ProtoMessage() {}
func (x *StreamNgdotCloseReadArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[16]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StreamNgdotCloseReadArgs.ProtoReflect.Descriptor instead.
func (*StreamNgdotCloseReadArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{16}
}
type StreamNgdotCloseWriteArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *StreamNgdotCloseWriteArgs) Reset() {
*x = StreamNgdotCloseWriteArgs{}
mi := &file_ngolofuzz_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *StreamNgdotCloseWriteArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StreamNgdotCloseWriteArgs) ProtoMessage() {}
func (x *StreamNgdotCloseWriteArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[17]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StreamNgdotCloseWriteArgs.ProtoReflect.Descriptor instead.
func (*StreamNgdotCloseWriteArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{17}
}
type StreamNgdotResetArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Code uint64 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *StreamNgdotResetArgs) Reset() {
*x = StreamNgdotResetArgs{}
mi := &file_ngolofuzz_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *StreamNgdotResetArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StreamNgdotResetArgs) ProtoMessage() {}
func (x *StreamNgdotResetArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[18]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StreamNgdotResetArgs.ProtoReflect.Descriptor instead.
func (*StreamNgdotResetArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{18}
}
func (x *StreamNgdotResetArgs) GetCode() uint64 {
if x != nil {
return x.Code
}
return 0
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_ConfigNgdotClone
// *NgoloFuzzOne_ConnNgdotString
// *NgoloFuzzOne_ConnNgdotLocalAddr
// *NgoloFuzzOne_ConnNgdotRemoteAddr
// *NgoloFuzzOne_ConnNgdotConnectionState
// *NgoloFuzzOne_ConnNgdotClose
// *NgoloFuzzOne_Listen
// *NgoloFuzzOne_EndpointNgdotLocalAddr
// *NgoloFuzzOne_StreamNgdotIsReadOnly
// *NgoloFuzzOne_StreamNgdotIsWriteOnly
// *NgoloFuzzOne_StreamNgdotRead
// *NgoloFuzzOne_StreamNgdotReadByte
// *NgoloFuzzOne_StreamNgdotWrite
// *NgoloFuzzOne_StreamNgdotWriteByte
// *NgoloFuzzOne_StreamNgdotFlush
// *NgoloFuzzOne_StreamNgdotClose
// *NgoloFuzzOne_StreamNgdotCloseRead
// *NgoloFuzzOne_StreamNgdotCloseWrite
// *NgoloFuzzOne_StreamNgdotReset
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[19]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[19]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{19}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetConfigNgdotClone() *ConfigNgdotCloneArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ConfigNgdotClone); ok {
return x.ConfigNgdotClone
}
}
return nil
}
func (x *NgoloFuzzOne) GetConnNgdotString() *ConnNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ConnNgdotString); ok {
return x.ConnNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetConnNgdotLocalAddr() *ConnNgdotLocalAddrArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ConnNgdotLocalAddr); ok {
return x.ConnNgdotLocalAddr
}
}
return nil
}
func (x *NgoloFuzzOne) GetConnNgdotRemoteAddr() *ConnNgdotRemoteAddrArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ConnNgdotRemoteAddr); ok {
return x.ConnNgdotRemoteAddr
}
}
return nil
}
func (x *NgoloFuzzOne) GetConnNgdotConnectionState() *ConnNgdotConnectionStateArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ConnNgdotConnectionState); ok {
return x.ConnNgdotConnectionState
}
}
return nil
}
func (x *NgoloFuzzOne) GetConnNgdotClose() *ConnNgdotCloseArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ConnNgdotClose); ok {
return x.ConnNgdotClose
}
}
return nil
}
func (x *NgoloFuzzOne) GetListen() *ListenArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Listen); ok {
return x.Listen
}
}
return nil
}
func (x *NgoloFuzzOne) GetEndpointNgdotLocalAddr() *EndpointNgdotLocalAddrArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_EndpointNgdotLocalAddr); ok {
return x.EndpointNgdotLocalAddr
}
}
return nil
}
func (x *NgoloFuzzOne) GetStreamNgdotIsReadOnly() *StreamNgdotIsReadOnlyArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_StreamNgdotIsReadOnly); ok {
return x.StreamNgdotIsReadOnly
}
}
return nil
}
func (x *NgoloFuzzOne) GetStreamNgdotIsWriteOnly() *StreamNgdotIsWriteOnlyArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_StreamNgdotIsWriteOnly); ok {
return x.StreamNgdotIsWriteOnly
}
}
return nil
}
func (x *NgoloFuzzOne) GetStreamNgdotRead() *StreamNgdotReadArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_StreamNgdotRead); ok {
return x.StreamNgdotRead
}
}
return nil
}
func (x *NgoloFuzzOne) GetStreamNgdotReadByte() *StreamNgdotReadByteArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_StreamNgdotReadByte); ok {
return x.StreamNgdotReadByte
}
}
return nil
}
func (x *NgoloFuzzOne) GetStreamNgdotWrite() *StreamNgdotWriteArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_StreamNgdotWrite); ok {
return x.StreamNgdotWrite
}
}
return nil
}
func (x *NgoloFuzzOne) GetStreamNgdotWriteByte() *StreamNgdotWriteByteArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_StreamNgdotWriteByte); ok {
return x.StreamNgdotWriteByte
}
}
return nil
}
func (x *NgoloFuzzOne) GetStreamNgdotFlush() *StreamNgdotFlushArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_StreamNgdotFlush); ok {
return x.StreamNgdotFlush
}
}
return nil
}
func (x *NgoloFuzzOne) GetStreamNgdotClose() *StreamNgdotCloseArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_StreamNgdotClose); ok {
return x.StreamNgdotClose
}
}
return nil
}
func (x *NgoloFuzzOne) GetStreamNgdotCloseRead() *StreamNgdotCloseReadArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_StreamNgdotCloseRead); ok {
return x.StreamNgdotCloseRead
}
}
return nil
}
func (x *NgoloFuzzOne) GetStreamNgdotCloseWrite() *StreamNgdotCloseWriteArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_StreamNgdotCloseWrite); ok {
return x.StreamNgdotCloseWrite
}
}
return nil
}
func (x *NgoloFuzzOne) GetStreamNgdotReset() *StreamNgdotResetArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_StreamNgdotReset); ok {
return x.StreamNgdotReset
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_ConfigNgdotClone struct {
ConfigNgdotClone *ConfigNgdotCloneArgs `protobuf:"bytes,1,opt,name=ConfigNgdotClone,proto3,oneof"`
}
type NgoloFuzzOne_ConnNgdotString struct {
ConnNgdotString *ConnNgdotStringArgs `protobuf:"bytes,2,opt,name=ConnNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_ConnNgdotLocalAddr struct {
ConnNgdotLocalAddr *ConnNgdotLocalAddrArgs `protobuf:"bytes,3,opt,name=ConnNgdotLocalAddr,proto3,oneof"`
}
type NgoloFuzzOne_ConnNgdotRemoteAddr struct {
ConnNgdotRemoteAddr *ConnNgdotRemoteAddrArgs `protobuf:"bytes,4,opt,name=ConnNgdotRemoteAddr,proto3,oneof"`
}
type NgoloFuzzOne_ConnNgdotConnectionState struct {
ConnNgdotConnectionState *ConnNgdotConnectionStateArgs `protobuf:"bytes,5,opt,name=ConnNgdotConnectionState,proto3,oneof"`
}
type NgoloFuzzOne_ConnNgdotClose struct {
ConnNgdotClose *ConnNgdotCloseArgs `protobuf:"bytes,6,opt,name=ConnNgdotClose,proto3,oneof"`
}
type NgoloFuzzOne_Listen struct {
Listen *ListenArgs `protobuf:"bytes,7,opt,name=Listen,proto3,oneof"`
}
type NgoloFuzzOne_EndpointNgdotLocalAddr struct {
EndpointNgdotLocalAddr *EndpointNgdotLocalAddrArgs `protobuf:"bytes,8,opt,name=EndpointNgdotLocalAddr,proto3,oneof"`
}
type NgoloFuzzOne_StreamNgdotIsReadOnly struct {
StreamNgdotIsReadOnly *StreamNgdotIsReadOnlyArgs `protobuf:"bytes,9,opt,name=StreamNgdotIsReadOnly,proto3,oneof"`
}
type NgoloFuzzOne_StreamNgdotIsWriteOnly struct {
StreamNgdotIsWriteOnly *StreamNgdotIsWriteOnlyArgs `protobuf:"bytes,10,opt,name=StreamNgdotIsWriteOnly,proto3,oneof"`
}
type NgoloFuzzOne_StreamNgdotRead struct {
StreamNgdotRead *StreamNgdotReadArgs `protobuf:"bytes,11,opt,name=StreamNgdotRead,proto3,oneof"`
}
type NgoloFuzzOne_StreamNgdotReadByte struct {
StreamNgdotReadByte *StreamNgdotReadByteArgs `protobuf:"bytes,12,opt,name=StreamNgdotReadByte,proto3,oneof"`
}
type NgoloFuzzOne_StreamNgdotWrite struct {
StreamNgdotWrite *StreamNgdotWriteArgs `protobuf:"bytes,13,opt,name=StreamNgdotWrite,proto3,oneof"`
}
type NgoloFuzzOne_StreamNgdotWriteByte struct {
StreamNgdotWriteByte *StreamNgdotWriteByteArgs `protobuf:"bytes,14,opt,name=StreamNgdotWriteByte,proto3,oneof"`
}
type NgoloFuzzOne_StreamNgdotFlush struct {
StreamNgdotFlush *StreamNgdotFlushArgs `protobuf:"bytes,15,opt,name=StreamNgdotFlush,proto3,oneof"`
}
type NgoloFuzzOne_StreamNgdotClose struct {
StreamNgdotClose *StreamNgdotCloseArgs `protobuf:"bytes,16,opt,name=StreamNgdotClose,proto3,oneof"`
}
type NgoloFuzzOne_StreamNgdotCloseRead struct {
StreamNgdotCloseRead *StreamNgdotCloseReadArgs `protobuf:"bytes,17,opt,name=StreamNgdotCloseRead,proto3,oneof"`
}
type NgoloFuzzOne_StreamNgdotCloseWrite struct {
StreamNgdotCloseWrite *StreamNgdotCloseWriteArgs `protobuf:"bytes,18,opt,name=StreamNgdotCloseWrite,proto3,oneof"`
}
type NgoloFuzzOne_StreamNgdotReset struct {
StreamNgdotReset *StreamNgdotResetArgs `protobuf:"bytes,19,opt,name=StreamNgdotReset,proto3,oneof"`
}
func (*NgoloFuzzOne_ConfigNgdotClone) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ConnNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ConnNgdotLocalAddr) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ConnNgdotRemoteAddr) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ConnNgdotConnectionState) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ConnNgdotClose) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Listen) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_EndpointNgdotLocalAddr) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_StreamNgdotIsReadOnly) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_StreamNgdotIsWriteOnly) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_StreamNgdotRead) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_StreamNgdotReadByte) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_StreamNgdotWrite) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_StreamNgdotWriteByte) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_StreamNgdotFlush) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_StreamNgdotClose) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_StreamNgdotCloseRead) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_StreamNgdotCloseWrite) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_StreamNgdotReset) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[20]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[20]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{20}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[21]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[21]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{21}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x16\n" +
"\x14ConfigNgdotCloneArgs\"\x15\n" +
"\x13ConnNgdotStringArgs\"\x18\n" +
"\x16ConnNgdotLocalAddrArgs\"\x19\n" +
"\x17ConnNgdotRemoteAddrArgs\"\x1e\n" +
"\x1cConnNgdotConnectionStateArgs\"\x14\n" +
"\x12ConnNgdotCloseArgs\"@\n" +
"\n" +
"ListenArgs\x12\x18\n" +
"\anetwork\x18\x01 \x01(\tR\anetwork\x12\x18\n" +
"\aaddress\x18\x02 \x01(\tR\aaddress\"\x1c\n" +
"\x1aEndpointNgdotLocalAddrArgs\"\x1b\n" +
"\x19StreamNgdotIsReadOnlyArgs\"\x1c\n" +
"\x1aStreamNgdotIsWriteOnlyArgs\"#\n" +
"\x13StreamNgdotReadArgs\x12\f\n" +
"\x01b\x18\x01 \x01(\fR\x01b\"\x19\n" +
"\x17StreamNgdotReadByteArgs\"$\n" +
"\x14StreamNgdotWriteArgs\x12\f\n" +
"\x01b\x18\x01 \x01(\fR\x01b\"(\n" +
"\x18StreamNgdotWriteByteArgs\x12\f\n" +
"\x01c\x18\x01 \x01(\rR\x01c\"\x16\n" +
"\x14StreamNgdotFlushArgs\"\x16\n" +
"\x14StreamNgdotCloseArgs\"\x1a\n" +
"\x18StreamNgdotCloseReadArgs\"\x1b\n" +
"\x19StreamNgdotCloseWriteArgs\"*\n" +
"\x14StreamNgdotResetArgs\x12\x12\n" +
"\x04code\x18\x01 \x01(\x04R\x04code\"\xd3\f\n" +
"\fNgoloFuzzOne\x12M\n" +
"\x10ConfigNgdotClone\x18\x01 \x01(\v2\x1f.ngolofuzz.ConfigNgdotCloneArgsH\x00R\x10ConfigNgdotClone\x12J\n" +
"\x0fConnNgdotString\x18\x02 \x01(\v2\x1e.ngolofuzz.ConnNgdotStringArgsH\x00R\x0fConnNgdotString\x12S\n" +
"\x12ConnNgdotLocalAddr\x18\x03 \x01(\v2!.ngolofuzz.ConnNgdotLocalAddrArgsH\x00R\x12ConnNgdotLocalAddr\x12V\n" +
"\x13ConnNgdotRemoteAddr\x18\x04 \x01(\v2\".ngolofuzz.ConnNgdotRemoteAddrArgsH\x00R\x13ConnNgdotRemoteAddr\x12e\n" +
"\x18ConnNgdotConnectionState\x18\x05 \x01(\v2'.ngolofuzz.ConnNgdotConnectionStateArgsH\x00R\x18ConnNgdotConnectionState\x12G\n" +
"\x0eConnNgdotClose\x18\x06 \x01(\v2\x1d.ngolofuzz.ConnNgdotCloseArgsH\x00R\x0eConnNgdotClose\x12/\n" +
"\x06Listen\x18\a \x01(\v2\x15.ngolofuzz.ListenArgsH\x00R\x06Listen\x12_\n" +
"\x16EndpointNgdotLocalAddr\x18\b \x01(\v2%.ngolofuzz.EndpointNgdotLocalAddrArgsH\x00R\x16EndpointNgdotLocalAddr\x12\\\n" +
"\x15StreamNgdotIsReadOnly\x18\t \x01(\v2$.ngolofuzz.StreamNgdotIsReadOnlyArgsH\x00R\x15StreamNgdotIsReadOnly\x12_\n" +
"\x16StreamNgdotIsWriteOnly\x18\n" +
" \x01(\v2%.ngolofuzz.StreamNgdotIsWriteOnlyArgsH\x00R\x16StreamNgdotIsWriteOnly\x12J\n" +
"\x0fStreamNgdotRead\x18\v \x01(\v2\x1e.ngolofuzz.StreamNgdotReadArgsH\x00R\x0fStreamNgdotRead\x12V\n" +
"\x13StreamNgdotReadByte\x18\f \x01(\v2\".ngolofuzz.StreamNgdotReadByteArgsH\x00R\x13StreamNgdotReadByte\x12M\n" +
"\x10StreamNgdotWrite\x18\r \x01(\v2\x1f.ngolofuzz.StreamNgdotWriteArgsH\x00R\x10StreamNgdotWrite\x12Y\n" +
"\x14StreamNgdotWriteByte\x18\x0e \x01(\v2#.ngolofuzz.StreamNgdotWriteByteArgsH\x00R\x14StreamNgdotWriteByte\x12M\n" +
"\x10StreamNgdotFlush\x18\x0f \x01(\v2\x1f.ngolofuzz.StreamNgdotFlushArgsH\x00R\x10StreamNgdotFlush\x12M\n" +
"\x10StreamNgdotClose\x18\x10 \x01(\v2\x1f.ngolofuzz.StreamNgdotCloseArgsH\x00R\x10StreamNgdotClose\x12Y\n" +
"\x14StreamNgdotCloseRead\x18\x11 \x01(\v2#.ngolofuzz.StreamNgdotCloseReadArgsH\x00R\x14StreamNgdotCloseRead\x12\\\n" +
"\x15StreamNgdotCloseWrite\x18\x12 \x01(\v2$.ngolofuzz.StreamNgdotCloseWriteArgsH\x00R\x15StreamNgdotCloseWrite\x12M\n" +
"\x10StreamNgdotReset\x18\x13 \x01(\v2\x1f.ngolofuzz.StreamNgdotResetArgsH\x00R\x10StreamNgdotResetB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x17Z\x15./;fuzz_ng_x_net_quicb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 22)
var file_ngolofuzz_proto_goTypes = []any{
(*ConfigNgdotCloneArgs)(nil), // 0: ngolofuzz.ConfigNgdotCloneArgs
(*ConnNgdotStringArgs)(nil), // 1: ngolofuzz.ConnNgdotStringArgs
(*ConnNgdotLocalAddrArgs)(nil), // 2: ngolofuzz.ConnNgdotLocalAddrArgs
(*ConnNgdotRemoteAddrArgs)(nil), // 3: ngolofuzz.ConnNgdotRemoteAddrArgs
(*ConnNgdotConnectionStateArgs)(nil), // 4: ngolofuzz.ConnNgdotConnectionStateArgs
(*ConnNgdotCloseArgs)(nil), // 5: ngolofuzz.ConnNgdotCloseArgs
(*ListenArgs)(nil), // 6: ngolofuzz.ListenArgs
(*EndpointNgdotLocalAddrArgs)(nil), // 7: ngolofuzz.EndpointNgdotLocalAddrArgs
(*StreamNgdotIsReadOnlyArgs)(nil), // 8: ngolofuzz.StreamNgdotIsReadOnlyArgs
(*StreamNgdotIsWriteOnlyArgs)(nil), // 9: ngolofuzz.StreamNgdotIsWriteOnlyArgs
(*StreamNgdotReadArgs)(nil), // 10: ngolofuzz.StreamNgdotReadArgs
(*StreamNgdotReadByteArgs)(nil), // 11: ngolofuzz.StreamNgdotReadByteArgs
(*StreamNgdotWriteArgs)(nil), // 12: ngolofuzz.StreamNgdotWriteArgs
(*StreamNgdotWriteByteArgs)(nil), // 13: ngolofuzz.StreamNgdotWriteByteArgs
(*StreamNgdotFlushArgs)(nil), // 14: ngolofuzz.StreamNgdotFlushArgs
(*StreamNgdotCloseArgs)(nil), // 15: ngolofuzz.StreamNgdotCloseArgs
(*StreamNgdotCloseReadArgs)(nil), // 16: ngolofuzz.StreamNgdotCloseReadArgs
(*StreamNgdotCloseWriteArgs)(nil), // 17: ngolofuzz.StreamNgdotCloseWriteArgs
(*StreamNgdotResetArgs)(nil), // 18: ngolofuzz.StreamNgdotResetArgs
(*NgoloFuzzOne)(nil), // 19: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 20: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 21: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.ConfigNgdotClone:type_name -> ngolofuzz.ConfigNgdotCloneArgs
1, // 1: ngolofuzz.NgoloFuzzOne.ConnNgdotString:type_name -> ngolofuzz.ConnNgdotStringArgs
2, // 2: ngolofuzz.NgoloFuzzOne.ConnNgdotLocalAddr:type_name -> ngolofuzz.ConnNgdotLocalAddrArgs
3, // 3: ngolofuzz.NgoloFuzzOne.ConnNgdotRemoteAddr:type_name -> ngolofuzz.ConnNgdotRemoteAddrArgs
4, // 4: ngolofuzz.NgoloFuzzOne.ConnNgdotConnectionState:type_name -> ngolofuzz.ConnNgdotConnectionStateArgs
5, // 5: ngolofuzz.NgoloFuzzOne.ConnNgdotClose:type_name -> ngolofuzz.ConnNgdotCloseArgs
6, // 6: ngolofuzz.NgoloFuzzOne.Listen:type_name -> ngolofuzz.ListenArgs
7, // 7: ngolofuzz.NgoloFuzzOne.EndpointNgdotLocalAddr:type_name -> ngolofuzz.EndpointNgdotLocalAddrArgs
8, // 8: ngolofuzz.NgoloFuzzOne.StreamNgdotIsReadOnly:type_name -> ngolofuzz.StreamNgdotIsReadOnlyArgs
9, // 9: ngolofuzz.NgoloFuzzOne.StreamNgdotIsWriteOnly:type_name -> ngolofuzz.StreamNgdotIsWriteOnlyArgs
10, // 10: ngolofuzz.NgoloFuzzOne.StreamNgdotRead:type_name -> ngolofuzz.StreamNgdotReadArgs
11, // 11: ngolofuzz.NgoloFuzzOne.StreamNgdotReadByte:type_name -> ngolofuzz.StreamNgdotReadByteArgs
12, // 12: ngolofuzz.NgoloFuzzOne.StreamNgdotWrite:type_name -> ngolofuzz.StreamNgdotWriteArgs
13, // 13: ngolofuzz.NgoloFuzzOne.StreamNgdotWriteByte:type_name -> ngolofuzz.StreamNgdotWriteByteArgs
14, // 14: ngolofuzz.NgoloFuzzOne.StreamNgdotFlush:type_name -> ngolofuzz.StreamNgdotFlushArgs
15, // 15: ngolofuzz.NgoloFuzzOne.StreamNgdotClose:type_name -> ngolofuzz.StreamNgdotCloseArgs
16, // 16: ngolofuzz.NgoloFuzzOne.StreamNgdotCloseRead:type_name -> ngolofuzz.StreamNgdotCloseReadArgs
17, // 17: ngolofuzz.NgoloFuzzOne.StreamNgdotCloseWrite:type_name -> ngolofuzz.StreamNgdotCloseWriteArgs
18, // 18: ngolofuzz.NgoloFuzzOne.StreamNgdotReset:type_name -> ngolofuzz.StreamNgdotResetArgs
19, // 19: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
20, // [20:20] is the sub-list for method output_type
20, // [20:20] is the sub-list for method input_type
20, // [20:20] is the sub-list for extension type_name
20, // [20:20] is the sub-list for extension extendee
0, // [0:20] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[19].OneofWrappers = []any{
(*NgoloFuzzOne_ConfigNgdotClone)(nil),
(*NgoloFuzzOne_ConnNgdotString)(nil),
(*NgoloFuzzOne_ConnNgdotLocalAddr)(nil),
(*NgoloFuzzOne_ConnNgdotRemoteAddr)(nil),
(*NgoloFuzzOne_ConnNgdotConnectionState)(nil),
(*NgoloFuzzOne_ConnNgdotClose)(nil),
(*NgoloFuzzOne_Listen)(nil),
(*NgoloFuzzOne_EndpointNgdotLocalAddr)(nil),
(*NgoloFuzzOne_StreamNgdotIsReadOnly)(nil),
(*NgoloFuzzOne_StreamNgdotIsWriteOnly)(nil),
(*NgoloFuzzOne_StreamNgdotRead)(nil),
(*NgoloFuzzOne_StreamNgdotReadByte)(nil),
(*NgoloFuzzOne_StreamNgdotWrite)(nil),
(*NgoloFuzzOne_StreamNgdotWriteByte)(nil),
(*NgoloFuzzOne_StreamNgdotFlush)(nil),
(*NgoloFuzzOne_StreamNgdotClose)(nil),
(*NgoloFuzzOne_StreamNgdotCloseRead)(nil),
(*NgoloFuzzOne_StreamNgdotCloseWrite)(nil),
(*NgoloFuzzOne_StreamNgdotReset)(nil),
}
file_ngolofuzz_proto_msgTypes[20].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 22,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_net_webdav
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/net/webdav"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewMemFS:
webdav.NewMemFS()
case *NgoloFuzzOne_NewMemLS:
webdav.NewMemLS()
case *NgoloFuzzOne_StatusText:
arg0 := int(a.StatusText.Code)
webdav.StatusText(arg0)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewMemFS:
w.WriteString(fmt.Sprintf("webdav.NewMemFS()\n"))
case *NgoloFuzzOne_NewMemLS:
w.WriteString(fmt.Sprintf("webdav.NewMemLS()\n"))
case *NgoloFuzzOne_StatusText:
w.WriteString(fmt.Sprintf("webdav.StatusText(int(%#+v))\n", a.StatusText.Code))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_net_webdav
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type NewMemFSArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewMemFSArgs) Reset() {
*x = NewMemFSArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewMemFSArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewMemFSArgs) ProtoMessage() {}
func (x *NewMemFSArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewMemFSArgs.ProtoReflect.Descriptor instead.
func (*NewMemFSArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type NewMemLSArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewMemLSArgs) Reset() {
*x = NewMemLSArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewMemLSArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewMemLSArgs) ProtoMessage() {}
func (x *NewMemLSArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewMemLSArgs.ProtoReflect.Descriptor instead.
func (*NewMemLSArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
type StatusTextArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Code int64 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *StatusTextArgs) Reset() {
*x = StatusTextArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *StatusTextArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StatusTextArgs) ProtoMessage() {}
func (x *StatusTextArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StatusTextArgs.ProtoReflect.Descriptor instead.
func (*StatusTextArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *StatusTextArgs) GetCode() int64 {
if x != nil {
return x.Code
}
return 0
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_NewMemFS
// *NgoloFuzzOne_NewMemLS
// *NgoloFuzzOne_StatusText
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetNewMemFS() *NewMemFSArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewMemFS); ok {
return x.NewMemFS
}
}
return nil
}
func (x *NgoloFuzzOne) GetNewMemLS() *NewMemLSArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewMemLS); ok {
return x.NewMemLS
}
}
return nil
}
func (x *NgoloFuzzOne) GetStatusText() *StatusTextArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_StatusText); ok {
return x.StatusText
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_NewMemFS struct {
NewMemFS *NewMemFSArgs `protobuf:"bytes,1,opt,name=NewMemFS,proto3,oneof"`
}
type NgoloFuzzOne_NewMemLS struct {
NewMemLS *NewMemLSArgs `protobuf:"bytes,2,opt,name=NewMemLS,proto3,oneof"`
}
type NgoloFuzzOne_StatusText struct {
StatusText *StatusTextArgs `protobuf:"bytes,3,opt,name=StatusText,proto3,oneof"`
}
func (*NgoloFuzzOne_NewMemFS) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_NewMemLS) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_StatusText) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x0e\n" +
"\fNewMemFSArgs\"\x0e\n" +
"\fNewMemLSArgs\"$\n" +
"\x0eStatusTextArgs\x12\x12\n" +
"\x04code\x18\x01 \x01(\x03R\x04code\"\xc1\x01\n" +
"\fNgoloFuzzOne\x125\n" +
"\bNewMemFS\x18\x01 \x01(\v2\x17.ngolofuzz.NewMemFSArgsH\x00R\bNewMemFS\x125\n" +
"\bNewMemLS\x18\x02 \x01(\v2\x17.ngolofuzz.NewMemLSArgsH\x00R\bNewMemLS\x12;\n" +
"\n" +
"StatusText\x18\x03 \x01(\v2\x19.ngolofuzz.StatusTextArgsH\x00R\n" +
"StatusTextB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x19Z\x17./;fuzz_ng_x_net_webdavb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_ngolofuzz_proto_goTypes = []any{
(*NewMemFSArgs)(nil), // 0: ngolofuzz.NewMemFSArgs
(*NewMemLSArgs)(nil), // 1: ngolofuzz.NewMemLSArgs
(*StatusTextArgs)(nil), // 2: ngolofuzz.StatusTextArgs
(*NgoloFuzzOne)(nil), // 3: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 4: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 5: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.NewMemFS:type_name -> ngolofuzz.NewMemFSArgs
1, // 1: ngolofuzz.NgoloFuzzOne.NewMemLS:type_name -> ngolofuzz.NewMemLSArgs
2, // 2: ngolofuzz.NgoloFuzzOne.StatusText:type_name -> ngolofuzz.StatusTextArgs
3, // 3: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[3].OneofWrappers = []any{
(*NgoloFuzzOne_NewMemFS)(nil),
(*NgoloFuzzOne_NewMemLS)(nil),
(*NgoloFuzzOne_StatusText)(nil),
}
file_ngolofuzz_proto_msgTypes[4].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 6,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_net_websocket
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/net/websocket"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var ConfigResults []*websocket.Config
ConfigResultsIndex := 0
var ConnResults []*websocket.Conn
ConnResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewConfig:
_, r1 := websocket.NewConfig(a.NewConfig.Server, a.NewConfig.Origin)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_Dial:
r0, r1 := websocket.Dial(a.Dial.Url_, a.Dial.Protocol, a.Dial.Origin)
if r0 != nil{
ConnResults = append(ConnResults, r0)
}
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_DialConfig:
if len(ConfigResults) == 0 {
continue
}
arg0 := ConfigResults[ConfigResultsIndex]
ConfigResultsIndex = (ConfigResultsIndex + 1) % len(ConfigResults)
r0, r1 := websocket.DialConfig(arg0)
if r0 != nil{
ConnResults = append(ConnResults, r0)
}
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_ConnNgdotRead:
if len(ConnResults) == 0 {
continue
}
arg0 := ConnResults[ConnResultsIndex]
ConnResultsIndex = (ConnResultsIndex + 1) % len(ConnResults)
_, r1 := arg0.Read(a.ConnNgdotRead.Msg)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_ConnNgdotWrite:
if len(ConnResults) == 0 {
continue
}
arg0 := ConnResults[ConnResultsIndex]
ConnResultsIndex = (ConnResultsIndex + 1) % len(ConnResults)
_, r1 := arg0.Write(a.ConnNgdotWrite.Msg)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_ConnNgdotClose:
if len(ConnResults) == 0 {
continue
}
arg0 := ConnResults[ConnResultsIndex]
ConnResultsIndex = (ConnResultsIndex + 1) % len(ConnResults)
r0 := arg0.Close()
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_ConnNgdotIsClientConn:
if len(ConnResults) == 0 {
continue
}
arg0 := ConnResults[ConnResultsIndex]
ConnResultsIndex = (ConnResultsIndex + 1) % len(ConnResults)
arg0.IsClientConn()
case *NgoloFuzzOne_ConnNgdotIsServerConn:
if len(ConnResults) == 0 {
continue
}
arg0 := ConnResults[ConnResultsIndex]
ConnResultsIndex = (ConnResultsIndex + 1) % len(ConnResults)
arg0.IsServerConn()
case *NgoloFuzzOne_ConnNgdotLocalAddr:
if len(ConnResults) == 0 {
continue
}
arg0 := ConnResults[ConnResultsIndex]
ConnResultsIndex = (ConnResultsIndex + 1) % len(ConnResults)
arg0.LocalAddr()
case *NgoloFuzzOne_ConnNgdotRemoteAddr:
if len(ConnResults) == 0 {
continue
}
arg0 := ConnResults[ConnResultsIndex]
ConnResultsIndex = (ConnResultsIndex + 1) % len(ConnResults)
arg0.RemoteAddr()
case *NgoloFuzzOne_ConnNgdotConfig:
if len(ConnResults) == 0 {
continue
}
arg0 := ConnResults[ConnResultsIndex]
ConnResultsIndex = (ConnResultsIndex + 1) % len(ConnResults)
arg0.Config()
case *NgoloFuzzOne_ConnNgdotRequest:
if len(ConnResults) == 0 {
continue
}
arg0 := ConnResults[ConnResultsIndex]
ConnResultsIndex = (ConnResultsIndex + 1) % len(ConnResults)
arg0.Request()
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
ConfigNb := 0
ConfigResultsIndex := 0
ConnNb := 0
ConnResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewConfig:
w.WriteString(fmt.Sprintf("websocket.NewConfig(%#+v, %#+v)\n", a.NewConfig.Server, a.NewConfig.Origin))
case *NgoloFuzzOne_Dial:
w.WriteString(fmt.Sprintf("Conn%d, _ := websocket.Dial(%#+v, %#+v, %#+v)\n", ConnNb, a.Dial.Url_, a.Dial.Protocol, a.Dial.Origin))
ConnNb = ConnNb + 1
case *NgoloFuzzOne_DialConfig:
if ConfigNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Conn%d, _ := websocket.DialConfig(Config%d)\n", ConnNb, (ConfigResultsIndex + 0) % ConfigNb))
ConnNb = ConnNb + 1
ConfigResultsIndex = (ConfigResultsIndex + 1) % ConfigNb
case *NgoloFuzzOne_ConnNgdotRead:
if ConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Conn%d.Read(%#+v)\n", ConnResultsIndex, a.ConnNgdotRead.Msg))
ConnResultsIndex = (ConnResultsIndex + 1) % ConnNb
case *NgoloFuzzOne_ConnNgdotWrite:
if ConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Conn%d.Write(%#+v)\n", ConnResultsIndex, a.ConnNgdotWrite.Msg))
ConnResultsIndex = (ConnResultsIndex + 1) % ConnNb
case *NgoloFuzzOne_ConnNgdotClose:
if ConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Conn%d.Close()\n", ConnResultsIndex))
ConnResultsIndex = (ConnResultsIndex + 1) % ConnNb
case *NgoloFuzzOne_ConnNgdotIsClientConn:
if ConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Conn%d.IsClientConn()\n", ConnResultsIndex))
ConnResultsIndex = (ConnResultsIndex + 1) % ConnNb
case *NgoloFuzzOne_ConnNgdotIsServerConn:
if ConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Conn%d.IsServerConn()\n", ConnResultsIndex))
ConnResultsIndex = (ConnResultsIndex + 1) % ConnNb
case *NgoloFuzzOne_ConnNgdotLocalAddr:
if ConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Conn%d.LocalAddr()\n", ConnResultsIndex))
ConnResultsIndex = (ConnResultsIndex + 1) % ConnNb
case *NgoloFuzzOne_ConnNgdotRemoteAddr:
if ConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Conn%d.RemoteAddr()\n", ConnResultsIndex))
ConnResultsIndex = (ConnResultsIndex + 1) % ConnNb
case *NgoloFuzzOne_ConnNgdotConfig:
if ConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Conn%d.Config()\n", ConnResultsIndex))
ConnResultsIndex = (ConnResultsIndex + 1) % ConnNb
case *NgoloFuzzOne_ConnNgdotRequest:
if ConnNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Conn%d.Request()\n", ConnResultsIndex))
ConnResultsIndex = (ConnResultsIndex + 1) % ConnNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_net_websocket
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type NewConfigArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Server string `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"`
Origin string `protobuf:"bytes,2,opt,name=origin,proto3" json:"origin,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewConfigArgs) Reset() {
*x = NewConfigArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewConfigArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewConfigArgs) ProtoMessage() {}
func (x *NewConfigArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewConfigArgs.ProtoReflect.Descriptor instead.
func (*NewConfigArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *NewConfigArgs) GetServer() string {
if x != nil {
return x.Server
}
return ""
}
func (x *NewConfigArgs) GetOrigin() string {
if x != nil {
return x.Origin
}
return ""
}
type DialArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Url_ string `protobuf:"bytes,1,opt,name=url_,json=url,proto3" json:"url_,omitempty"`
Protocol string `protobuf:"bytes,2,opt,name=protocol,proto3" json:"protocol,omitempty"`
Origin string `protobuf:"bytes,3,opt,name=origin,proto3" json:"origin,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DialArgs) Reset() {
*x = DialArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DialArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DialArgs) ProtoMessage() {}
func (x *DialArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DialArgs.ProtoReflect.Descriptor instead.
func (*DialArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *DialArgs) GetUrl_() string {
if x != nil {
return x.Url_
}
return ""
}
func (x *DialArgs) GetProtocol() string {
if x != nil {
return x.Protocol
}
return ""
}
func (x *DialArgs) GetOrigin() string {
if x != nil {
return x.Origin
}
return ""
}
type DialConfigArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DialConfigArgs) Reset() {
*x = DialConfigArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DialConfigArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DialConfigArgs) ProtoMessage() {}
func (x *DialConfigArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DialConfigArgs.ProtoReflect.Descriptor instead.
func (*DialConfigArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
type ConnNgdotReadArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Msg []byte `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ConnNgdotReadArgs) Reset() {
*x = ConnNgdotReadArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ConnNgdotReadArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConnNgdotReadArgs) ProtoMessage() {}
func (x *ConnNgdotReadArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ConnNgdotReadArgs.ProtoReflect.Descriptor instead.
func (*ConnNgdotReadArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *ConnNgdotReadArgs) GetMsg() []byte {
if x != nil {
return x.Msg
}
return nil
}
type ConnNgdotWriteArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Msg []byte `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ConnNgdotWriteArgs) Reset() {
*x = ConnNgdotWriteArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ConnNgdotWriteArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConnNgdotWriteArgs) ProtoMessage() {}
func (x *ConnNgdotWriteArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ConnNgdotWriteArgs.ProtoReflect.Descriptor instead.
func (*ConnNgdotWriteArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *ConnNgdotWriteArgs) GetMsg() []byte {
if x != nil {
return x.Msg
}
return nil
}
type ConnNgdotCloseArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ConnNgdotCloseArgs) Reset() {
*x = ConnNgdotCloseArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ConnNgdotCloseArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConnNgdotCloseArgs) ProtoMessage() {}
func (x *ConnNgdotCloseArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ConnNgdotCloseArgs.ProtoReflect.Descriptor instead.
func (*ConnNgdotCloseArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
type ConnNgdotIsClientConnArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ConnNgdotIsClientConnArgs) Reset() {
*x = ConnNgdotIsClientConnArgs{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ConnNgdotIsClientConnArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConnNgdotIsClientConnArgs) ProtoMessage() {}
func (x *ConnNgdotIsClientConnArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ConnNgdotIsClientConnArgs.ProtoReflect.Descriptor instead.
func (*ConnNgdotIsClientConnArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
type ConnNgdotIsServerConnArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ConnNgdotIsServerConnArgs) Reset() {
*x = ConnNgdotIsServerConnArgs{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ConnNgdotIsServerConnArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConnNgdotIsServerConnArgs) ProtoMessage() {}
func (x *ConnNgdotIsServerConnArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ConnNgdotIsServerConnArgs.ProtoReflect.Descriptor instead.
func (*ConnNgdotIsServerConnArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
type ConnNgdotLocalAddrArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ConnNgdotLocalAddrArgs) Reset() {
*x = ConnNgdotLocalAddrArgs{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ConnNgdotLocalAddrArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConnNgdotLocalAddrArgs) ProtoMessage() {}
func (x *ConnNgdotLocalAddrArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ConnNgdotLocalAddrArgs.ProtoReflect.Descriptor instead.
func (*ConnNgdotLocalAddrArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
type ConnNgdotRemoteAddrArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ConnNgdotRemoteAddrArgs) Reset() {
*x = ConnNgdotRemoteAddrArgs{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ConnNgdotRemoteAddrArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConnNgdotRemoteAddrArgs) ProtoMessage() {}
func (x *ConnNgdotRemoteAddrArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ConnNgdotRemoteAddrArgs.ProtoReflect.Descriptor instead.
func (*ConnNgdotRemoteAddrArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
type ConnNgdotConfigArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ConnNgdotConfigArgs) Reset() {
*x = ConnNgdotConfigArgs{}
mi := &file_ngolofuzz_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ConnNgdotConfigArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConnNgdotConfigArgs) ProtoMessage() {}
func (x *ConnNgdotConfigArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ConnNgdotConfigArgs.ProtoReflect.Descriptor instead.
func (*ConnNgdotConfigArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{10}
}
type ConnNgdotRequestArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ConnNgdotRequestArgs) Reset() {
*x = ConnNgdotRequestArgs{}
mi := &file_ngolofuzz_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ConnNgdotRequestArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConnNgdotRequestArgs) ProtoMessage() {}
func (x *ConnNgdotRequestArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[11]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ConnNgdotRequestArgs.ProtoReflect.Descriptor instead.
func (*ConnNgdotRequestArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{11}
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_NewConfig
// *NgoloFuzzOne_Dial
// *NgoloFuzzOne_DialConfig
// *NgoloFuzzOne_ConnNgdotRead
// *NgoloFuzzOne_ConnNgdotWrite
// *NgoloFuzzOne_ConnNgdotClose
// *NgoloFuzzOne_ConnNgdotIsClientConn
// *NgoloFuzzOne_ConnNgdotIsServerConn
// *NgoloFuzzOne_ConnNgdotLocalAddr
// *NgoloFuzzOne_ConnNgdotRemoteAddr
// *NgoloFuzzOne_ConnNgdotConfig
// *NgoloFuzzOne_ConnNgdotRequest
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[12]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{12}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetNewConfig() *NewConfigArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewConfig); ok {
return x.NewConfig
}
}
return nil
}
func (x *NgoloFuzzOne) GetDial() *DialArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Dial); ok {
return x.Dial
}
}
return nil
}
func (x *NgoloFuzzOne) GetDialConfig() *DialConfigArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_DialConfig); ok {
return x.DialConfig
}
}
return nil
}
func (x *NgoloFuzzOne) GetConnNgdotRead() *ConnNgdotReadArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ConnNgdotRead); ok {
return x.ConnNgdotRead
}
}
return nil
}
func (x *NgoloFuzzOne) GetConnNgdotWrite() *ConnNgdotWriteArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ConnNgdotWrite); ok {
return x.ConnNgdotWrite
}
}
return nil
}
func (x *NgoloFuzzOne) GetConnNgdotClose() *ConnNgdotCloseArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ConnNgdotClose); ok {
return x.ConnNgdotClose
}
}
return nil
}
func (x *NgoloFuzzOne) GetConnNgdotIsClientConn() *ConnNgdotIsClientConnArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ConnNgdotIsClientConn); ok {
return x.ConnNgdotIsClientConn
}
}
return nil
}
func (x *NgoloFuzzOne) GetConnNgdotIsServerConn() *ConnNgdotIsServerConnArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ConnNgdotIsServerConn); ok {
return x.ConnNgdotIsServerConn
}
}
return nil
}
func (x *NgoloFuzzOne) GetConnNgdotLocalAddr() *ConnNgdotLocalAddrArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ConnNgdotLocalAddr); ok {
return x.ConnNgdotLocalAddr
}
}
return nil
}
func (x *NgoloFuzzOne) GetConnNgdotRemoteAddr() *ConnNgdotRemoteAddrArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ConnNgdotRemoteAddr); ok {
return x.ConnNgdotRemoteAddr
}
}
return nil
}
func (x *NgoloFuzzOne) GetConnNgdotConfig() *ConnNgdotConfigArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ConnNgdotConfig); ok {
return x.ConnNgdotConfig
}
}
return nil
}
func (x *NgoloFuzzOne) GetConnNgdotRequest() *ConnNgdotRequestArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ConnNgdotRequest); ok {
return x.ConnNgdotRequest
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_NewConfig struct {
NewConfig *NewConfigArgs `protobuf:"bytes,1,opt,name=NewConfig,proto3,oneof"`
}
type NgoloFuzzOne_Dial struct {
Dial *DialArgs `protobuf:"bytes,2,opt,name=Dial,proto3,oneof"`
}
type NgoloFuzzOne_DialConfig struct {
DialConfig *DialConfigArgs `protobuf:"bytes,3,opt,name=DialConfig,proto3,oneof"`
}
type NgoloFuzzOne_ConnNgdotRead struct {
ConnNgdotRead *ConnNgdotReadArgs `protobuf:"bytes,4,opt,name=ConnNgdotRead,proto3,oneof"`
}
type NgoloFuzzOne_ConnNgdotWrite struct {
ConnNgdotWrite *ConnNgdotWriteArgs `protobuf:"bytes,5,opt,name=ConnNgdotWrite,proto3,oneof"`
}
type NgoloFuzzOne_ConnNgdotClose struct {
ConnNgdotClose *ConnNgdotCloseArgs `protobuf:"bytes,6,opt,name=ConnNgdotClose,proto3,oneof"`
}
type NgoloFuzzOne_ConnNgdotIsClientConn struct {
ConnNgdotIsClientConn *ConnNgdotIsClientConnArgs `protobuf:"bytes,7,opt,name=ConnNgdotIsClientConn,proto3,oneof"`
}
type NgoloFuzzOne_ConnNgdotIsServerConn struct {
ConnNgdotIsServerConn *ConnNgdotIsServerConnArgs `protobuf:"bytes,8,opt,name=ConnNgdotIsServerConn,proto3,oneof"`
}
type NgoloFuzzOne_ConnNgdotLocalAddr struct {
ConnNgdotLocalAddr *ConnNgdotLocalAddrArgs `protobuf:"bytes,9,opt,name=ConnNgdotLocalAddr,proto3,oneof"`
}
type NgoloFuzzOne_ConnNgdotRemoteAddr struct {
ConnNgdotRemoteAddr *ConnNgdotRemoteAddrArgs `protobuf:"bytes,10,opt,name=ConnNgdotRemoteAddr,proto3,oneof"`
}
type NgoloFuzzOne_ConnNgdotConfig struct {
ConnNgdotConfig *ConnNgdotConfigArgs `protobuf:"bytes,11,opt,name=ConnNgdotConfig,proto3,oneof"`
}
type NgoloFuzzOne_ConnNgdotRequest struct {
ConnNgdotRequest *ConnNgdotRequestArgs `protobuf:"bytes,12,opt,name=ConnNgdotRequest,proto3,oneof"`
}
func (*NgoloFuzzOne_NewConfig) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Dial) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_DialConfig) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ConnNgdotRead) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ConnNgdotWrite) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ConnNgdotClose) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ConnNgdotIsClientConn) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ConnNgdotIsServerConn) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ConnNgdotLocalAddr) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ConnNgdotRemoteAddr) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ConnNgdotConfig) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ConnNgdotRequest) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[13]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{13}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[14]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{14}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"?\n" +
"\rNewConfigArgs\x12\x16\n" +
"\x06server\x18\x01 \x01(\tR\x06server\x12\x16\n" +
"\x06origin\x18\x02 \x01(\tR\x06origin\"Q\n" +
"\bDialArgs\x12\x11\n" +
"\x04url_\x18\x01 \x01(\tR\x03url\x12\x1a\n" +
"\bprotocol\x18\x02 \x01(\tR\bprotocol\x12\x16\n" +
"\x06origin\x18\x03 \x01(\tR\x06origin\"\x10\n" +
"\x0eDialConfigArgs\"%\n" +
"\x11ConnNgdotReadArgs\x12\x10\n" +
"\x03msg\x18\x01 \x01(\fR\x03msg\"&\n" +
"\x12ConnNgdotWriteArgs\x12\x10\n" +
"\x03msg\x18\x01 \x01(\fR\x03msg\"\x14\n" +
"\x12ConnNgdotCloseArgs\"\x1b\n" +
"\x19ConnNgdotIsClientConnArgs\"\x1b\n" +
"\x19ConnNgdotIsServerConnArgs\"\x18\n" +
"\x16ConnNgdotLocalAddrArgs\"\x19\n" +
"\x17ConnNgdotRemoteAddrArgs\"\x15\n" +
"\x13ConnNgdotConfigArgs\"\x16\n" +
"\x14ConnNgdotRequestArgs\"\x94\a\n" +
"\fNgoloFuzzOne\x128\n" +
"\tNewConfig\x18\x01 \x01(\v2\x18.ngolofuzz.NewConfigArgsH\x00R\tNewConfig\x12)\n" +
"\x04Dial\x18\x02 \x01(\v2\x13.ngolofuzz.DialArgsH\x00R\x04Dial\x12;\n" +
"\n" +
"DialConfig\x18\x03 \x01(\v2\x19.ngolofuzz.DialConfigArgsH\x00R\n" +
"DialConfig\x12D\n" +
"\rConnNgdotRead\x18\x04 \x01(\v2\x1c.ngolofuzz.ConnNgdotReadArgsH\x00R\rConnNgdotRead\x12G\n" +
"\x0eConnNgdotWrite\x18\x05 \x01(\v2\x1d.ngolofuzz.ConnNgdotWriteArgsH\x00R\x0eConnNgdotWrite\x12G\n" +
"\x0eConnNgdotClose\x18\x06 \x01(\v2\x1d.ngolofuzz.ConnNgdotCloseArgsH\x00R\x0eConnNgdotClose\x12\\\n" +
"\x15ConnNgdotIsClientConn\x18\a \x01(\v2$.ngolofuzz.ConnNgdotIsClientConnArgsH\x00R\x15ConnNgdotIsClientConn\x12\\\n" +
"\x15ConnNgdotIsServerConn\x18\b \x01(\v2$.ngolofuzz.ConnNgdotIsServerConnArgsH\x00R\x15ConnNgdotIsServerConn\x12S\n" +
"\x12ConnNgdotLocalAddr\x18\t \x01(\v2!.ngolofuzz.ConnNgdotLocalAddrArgsH\x00R\x12ConnNgdotLocalAddr\x12V\n" +
"\x13ConnNgdotRemoteAddr\x18\n" +
" \x01(\v2\".ngolofuzz.ConnNgdotRemoteAddrArgsH\x00R\x13ConnNgdotRemoteAddr\x12J\n" +
"\x0fConnNgdotConfig\x18\v \x01(\v2\x1e.ngolofuzz.ConnNgdotConfigArgsH\x00R\x0fConnNgdotConfig\x12M\n" +
"\x10ConnNgdotRequest\x18\f \x01(\v2\x1f.ngolofuzz.ConnNgdotRequestArgsH\x00R\x10ConnNgdotRequestB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1cZ\x1a./;fuzz_ng_x_net_websocketb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 15)
var file_ngolofuzz_proto_goTypes = []any{
(*NewConfigArgs)(nil), // 0: ngolofuzz.NewConfigArgs
(*DialArgs)(nil), // 1: ngolofuzz.DialArgs
(*DialConfigArgs)(nil), // 2: ngolofuzz.DialConfigArgs
(*ConnNgdotReadArgs)(nil), // 3: ngolofuzz.ConnNgdotReadArgs
(*ConnNgdotWriteArgs)(nil), // 4: ngolofuzz.ConnNgdotWriteArgs
(*ConnNgdotCloseArgs)(nil), // 5: ngolofuzz.ConnNgdotCloseArgs
(*ConnNgdotIsClientConnArgs)(nil), // 6: ngolofuzz.ConnNgdotIsClientConnArgs
(*ConnNgdotIsServerConnArgs)(nil), // 7: ngolofuzz.ConnNgdotIsServerConnArgs
(*ConnNgdotLocalAddrArgs)(nil), // 8: ngolofuzz.ConnNgdotLocalAddrArgs
(*ConnNgdotRemoteAddrArgs)(nil), // 9: ngolofuzz.ConnNgdotRemoteAddrArgs
(*ConnNgdotConfigArgs)(nil), // 10: ngolofuzz.ConnNgdotConfigArgs
(*ConnNgdotRequestArgs)(nil), // 11: ngolofuzz.ConnNgdotRequestArgs
(*NgoloFuzzOne)(nil), // 12: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 13: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 14: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.NewConfig:type_name -> ngolofuzz.NewConfigArgs
1, // 1: ngolofuzz.NgoloFuzzOne.Dial:type_name -> ngolofuzz.DialArgs
2, // 2: ngolofuzz.NgoloFuzzOne.DialConfig:type_name -> ngolofuzz.DialConfigArgs
3, // 3: ngolofuzz.NgoloFuzzOne.ConnNgdotRead:type_name -> ngolofuzz.ConnNgdotReadArgs
4, // 4: ngolofuzz.NgoloFuzzOne.ConnNgdotWrite:type_name -> ngolofuzz.ConnNgdotWriteArgs
5, // 5: ngolofuzz.NgoloFuzzOne.ConnNgdotClose:type_name -> ngolofuzz.ConnNgdotCloseArgs
6, // 6: ngolofuzz.NgoloFuzzOne.ConnNgdotIsClientConn:type_name -> ngolofuzz.ConnNgdotIsClientConnArgs
7, // 7: ngolofuzz.NgoloFuzzOne.ConnNgdotIsServerConn:type_name -> ngolofuzz.ConnNgdotIsServerConnArgs
8, // 8: ngolofuzz.NgoloFuzzOne.ConnNgdotLocalAddr:type_name -> ngolofuzz.ConnNgdotLocalAddrArgs
9, // 9: ngolofuzz.NgoloFuzzOne.ConnNgdotRemoteAddr:type_name -> ngolofuzz.ConnNgdotRemoteAddrArgs
10, // 10: ngolofuzz.NgoloFuzzOne.ConnNgdotConfig:type_name -> ngolofuzz.ConnNgdotConfigArgs
11, // 11: ngolofuzz.NgoloFuzzOne.ConnNgdotRequest:type_name -> ngolofuzz.ConnNgdotRequestArgs
12, // 12: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
13, // [13:13] is the sub-list for method output_type
13, // [13:13] is the sub-list for method input_type
13, // [13:13] is the sub-list for extension type_name
13, // [13:13] is the sub-list for extension extendee
0, // [0:13] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[12].OneofWrappers = []any{
(*NgoloFuzzOne_NewConfig)(nil),
(*NgoloFuzzOne_Dial)(nil),
(*NgoloFuzzOne_DialConfig)(nil),
(*NgoloFuzzOne_ConnNgdotRead)(nil),
(*NgoloFuzzOne_ConnNgdotWrite)(nil),
(*NgoloFuzzOne_ConnNgdotClose)(nil),
(*NgoloFuzzOne_ConnNgdotIsClientConn)(nil),
(*NgoloFuzzOne_ConnNgdotIsServerConn)(nil),
(*NgoloFuzzOne_ConnNgdotLocalAddr)(nil),
(*NgoloFuzzOne_ConnNgdotRemoteAddr)(nil),
(*NgoloFuzzOne_ConnNgdotConfig)(nil),
(*NgoloFuzzOne_ConnNgdotRequest)(nil),
}
file_ngolofuzz_proto_msgTypes[13].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 15,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_net_xsrftoken
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/net/xsrftoken"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Generate:
xsrftoken.Generate(a.Generate.Key, a.Generate.UserID, a.Generate.ActionID)
case *NgoloFuzzOne_Valid:
xsrftoken.Valid(a.Valid.Token, a.Valid.Key, a.Valid.UserID, a.Valid.ActionID)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Generate:
w.WriteString(fmt.Sprintf("xsrftoken.Generate(%#+v, %#+v, %#+v)\n", a.Generate.Key, a.Generate.UserID, a.Generate.ActionID))
case *NgoloFuzzOne_Valid:
w.WriteString(fmt.Sprintf("xsrftoken.Valid(%#+v, %#+v, %#+v, %#+v)\n", a.Valid.Token, a.Valid.Key, a.Valid.UserID, a.Valid.ActionID))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_net_xsrftoken
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type GenerateArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
UserID string `protobuf:"bytes,2,opt,name=userID,proto3" json:"userID,omitempty"`
ActionID string `protobuf:"bytes,3,opt,name=actionID,proto3" json:"actionID,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GenerateArgs) Reset() {
*x = GenerateArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GenerateArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GenerateArgs) ProtoMessage() {}
func (x *GenerateArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GenerateArgs.ProtoReflect.Descriptor instead.
func (*GenerateArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *GenerateArgs) GetKey() string {
if x != nil {
return x.Key
}
return ""
}
func (x *GenerateArgs) GetUserID() string {
if x != nil {
return x.UserID
}
return ""
}
func (x *GenerateArgs) GetActionID() string {
if x != nil {
return x.ActionID
}
return ""
}
type ValidArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
UserID string `protobuf:"bytes,3,opt,name=userID,proto3" json:"userID,omitempty"`
ActionID string `protobuf:"bytes,4,opt,name=actionID,proto3" json:"actionID,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ValidArgs) Reset() {
*x = ValidArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ValidArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ValidArgs) ProtoMessage() {}
func (x *ValidArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ValidArgs.ProtoReflect.Descriptor instead.
func (*ValidArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *ValidArgs) GetToken() string {
if x != nil {
return x.Token
}
return ""
}
func (x *ValidArgs) GetKey() string {
if x != nil {
return x.Key
}
return ""
}
func (x *ValidArgs) GetUserID() string {
if x != nil {
return x.UserID
}
return ""
}
func (x *ValidArgs) GetActionID() string {
if x != nil {
return x.ActionID
}
return ""
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_Generate
// *NgoloFuzzOne_Valid
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetGenerate() *GenerateArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Generate); ok {
return x.Generate
}
}
return nil
}
func (x *NgoloFuzzOne) GetValid() *ValidArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Valid); ok {
return x.Valid
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_Generate struct {
Generate *GenerateArgs `protobuf:"bytes,1,opt,name=Generate,proto3,oneof"`
}
type NgoloFuzzOne_Valid struct {
Valid *ValidArgs `protobuf:"bytes,2,opt,name=Valid,proto3,oneof"`
}
func (*NgoloFuzzOne_Generate) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Valid) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"T\n" +
"\fGenerateArgs\x12\x10\n" +
"\x03key\x18\x01 \x01(\tR\x03key\x12\x16\n" +
"\x06userID\x18\x02 \x01(\tR\x06userID\x12\x1a\n" +
"\bactionID\x18\x03 \x01(\tR\bactionID\"g\n" +
"\tValidArgs\x12\x14\n" +
"\x05token\x18\x01 \x01(\tR\x05token\x12\x10\n" +
"\x03key\x18\x02 \x01(\tR\x03key\x12\x16\n" +
"\x06userID\x18\x03 \x01(\tR\x06userID\x12\x1a\n" +
"\bactionID\x18\x04 \x01(\tR\bactionID\"{\n" +
"\fNgoloFuzzOne\x125\n" +
"\bGenerate\x18\x01 \x01(\v2\x17.ngolofuzz.GenerateArgsH\x00R\bGenerate\x12,\n" +
"\x05Valid\x18\x02 \x01(\v2\x14.ngolofuzz.ValidArgsH\x00R\x05ValidB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1cZ\x1a./;fuzz_ng_x_net_xsrftokenb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_ngolofuzz_proto_goTypes = []any{
(*GenerateArgs)(nil), // 0: ngolofuzz.GenerateArgs
(*ValidArgs)(nil), // 1: ngolofuzz.ValidArgs
(*NgoloFuzzOne)(nil), // 2: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 3: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 4: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.Generate:type_name -> ngolofuzz.GenerateArgs
1, // 1: ngolofuzz.NgoloFuzzOne.Valid:type_name -> ngolofuzz.ValidArgs
2, // 2: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzOne_Generate)(nil),
(*NgoloFuzzOne_Valid)(nil),
}
file_ngolofuzz_proto_msgTypes[3].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
// 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.
// Package atom provides integer codes (also known as atoms) for a fixed set of
// frequently occurring HTML strings: tag names and attribute keys such as "p"
// and "id".
//
// Sharing an atom's name between all elements with the same tag can result in
// fewer string allocations when tokenizing and parsing HTML. Integer
// comparisons are also generally faster than string comparisons.
//
// The value of an atom's particular code is not guaranteed to stay the same
// between versions of this package. Neither is any ordering guaranteed:
// whether atom.H1 < atom.H2 may also change. The codes are not guaranteed to
// be dense. The only guarantees are that e.g. looking up "div" will yield
// atom.Div, calling atom.Div.String will return "div", and atom.Div != 0.
package atom // import "golang.org/x/net/html/atom"
// Atom is an integer code for a string. The zero value maps to "".
type Atom uint32
// String returns the atom's name.
func (a Atom) String() string {
start := uint32(a >> 8)
n := uint32(a & 0xff)
if start+n > uint32(len(atomText)) {
return ""
}
return atomText[start : start+n]
}
func (a Atom) string() string {
return atomText[a>>8 : a>>8+a&0xff]
}
// fnv computes the FNV hash with an arbitrary starting value h.
func fnv(h uint32, s []byte) uint32 {
for i := range s {
h ^= uint32(s[i])
h *= 16777619
}
return h
}
func match(s string, t []byte) bool {
for i, c := range t {
if s[i] != c {
return false
}
}
return true
}
// Lookup returns the atom whose name is s. It returns zero if there is no
// such atom. The lookup is case sensitive.
func Lookup(s []byte) Atom {
if len(s) == 0 || len(s) > maxAtomLen {
return 0
}
h := fnv(hash0, s)
if a := table[h&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) {
return a
}
if a := table[(h>>16)&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) {
return a
}
return 0
}
// String returns a string whose contents are equal to s. In that sense, it is
// equivalent to string(s) but may be more efficient.
func String(s []byte) string {
if a := Lookup(s); a != 0 {
return a.String()
}
return string(s)
}
// Copyright 2013 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 charset provides common text encodings for HTML documents.
//
// The mapping from encoding labels to encodings is defined at
// https://encoding.spec.whatwg.org/.
package charset // import "golang.org/x/net/html/charset"
import (
"bytes"
"fmt"
"io"
"mime"
"strings"
"unicode/utf8"
"golang.org/x/net/html"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/charmap"
"golang.org/x/text/encoding/htmlindex"
"golang.org/x/text/transform"
)
// Lookup returns the encoding with the specified label, and its canonical
// name. It returns nil and the empty string if label is not one of the
// standard encodings for HTML. Matching is case-insensitive and ignores
// leading and trailing whitespace. Encoders will use HTML escape sequences for
// runes that are not supported by the character set.
func Lookup(label string) (e encoding.Encoding, name string) {
e, err := htmlindex.Get(label)
if err != nil {
return nil, ""
}
name, _ = htmlindex.Name(e)
return &htmlEncoding{e}, name
}
type htmlEncoding struct{ encoding.Encoding }
func (h *htmlEncoding) NewEncoder() *encoding.Encoder {
// HTML requires a non-terminating legacy encoder. We use HTML escapes to
// substitute unsupported code points.
return encoding.HTMLEscapeUnsupported(h.Encoding.NewEncoder())
}
// DetermineEncoding determines the encoding of an HTML document by examining
// up to the first 1024 bytes of content and the declared Content-Type.
//
// See http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#determining-the-character-encoding
func DetermineEncoding(content []byte, contentType string) (e encoding.Encoding, name string, certain bool) {
if len(content) > 1024 {
content = content[:1024]
}
for _, b := range boms {
if bytes.HasPrefix(content, b.bom) {
e, name = Lookup(b.enc)
return e, name, true
}
}
if _, params, err := mime.ParseMediaType(contentType); err == nil {
if cs, ok := params["charset"]; ok {
if e, name = Lookup(cs); e != nil {
return e, name, true
}
}
}
if len(content) > 0 {
e, name = prescan(content)
if e != nil {
return e, name, false
}
}
// Try to detect UTF-8.
// First eliminate any partial rune at the end.
for i := len(content) - 1; i >= 0 && i > len(content)-4; i-- {
b := content[i]
if b < 0x80 {
break
}
if utf8.RuneStart(b) {
content = content[:i]
break
}
}
hasHighBit := false
for _, c := range content {
if c >= 0x80 {
hasHighBit = true
break
}
}
if hasHighBit && utf8.Valid(content) {
return encoding.Nop, "utf-8", false
}
// TODO: change default depending on user's locale?
return charmap.Windows1252, "windows-1252", false
}
// NewReader returns an io.Reader that converts the content of r to UTF-8.
// It calls DetermineEncoding to find out what r's encoding is.
func NewReader(r io.Reader, contentType string) (io.Reader, error) {
preview := make([]byte, 1024)
n, err := io.ReadFull(r, preview)
switch {
case err == io.ErrUnexpectedEOF:
preview = preview[:n]
r = bytes.NewReader(preview)
case err != nil:
return nil, err
default:
r = io.MultiReader(bytes.NewReader(preview), r)
}
if e, _, _ := DetermineEncoding(preview, contentType); e != encoding.Nop {
r = transform.NewReader(r, e.NewDecoder())
}
return r, nil
}
// NewReaderLabel returns a reader that converts from the specified charset to
// UTF-8. It uses Lookup to find the encoding that corresponds to label, and
// returns an error if Lookup returns nil. It is suitable for use as
// encoding/xml.Decoder's CharsetReader function.
func NewReaderLabel(label string, input io.Reader) (io.Reader, error) {
e, _ := Lookup(label)
if e == nil {
return nil, fmt.Errorf("unsupported charset: %q", label)
}
return transform.NewReader(input, e.NewDecoder()), nil
}
func prescan(content []byte) (e encoding.Encoding, name string) {
z := html.NewTokenizer(bytes.NewReader(content))
for {
switch z.Next() {
case html.ErrorToken:
return nil, ""
case html.StartTagToken, html.SelfClosingTagToken:
tagName, hasAttr := z.TagName()
if !bytes.Equal(tagName, []byte("meta")) {
continue
}
attrList := make(map[string]bool)
gotPragma := false
const (
dontKnow = iota
doNeedPragma
doNotNeedPragma
)
needPragma := dontKnow
name = ""
e = nil
for hasAttr {
var key, val []byte
key, val, hasAttr = z.TagAttr()
ks := string(key)
if attrList[ks] {
continue
}
attrList[ks] = true
for i, c := range val {
if 'A' <= c && c <= 'Z' {
val[i] = c + 0x20
}
}
switch ks {
case "http-equiv":
if bytes.Equal(val, []byte("content-type")) {
gotPragma = true
}
case "content":
if e == nil {
name = fromMetaElement(string(val))
if name != "" {
e, name = Lookup(name)
if e != nil {
needPragma = doNeedPragma
}
}
}
case "charset":
e, name = Lookup(string(val))
needPragma = doNotNeedPragma
}
}
if needPragma == dontKnow || needPragma == doNeedPragma && !gotPragma {
continue
}
if strings.HasPrefix(name, "utf-16") {
name = "utf-8"
e = encoding.Nop
}
if e != nil {
return e, name
}
}
}
}
func fromMetaElement(s string) string {
for s != "" {
csLoc := strings.Index(s, "charset")
if csLoc == -1 {
return ""
}
s = s[csLoc+len("charset"):]
s = strings.TrimLeft(s, " \t\n\f\r")
if !strings.HasPrefix(s, "=") {
continue
}
s = s[1:]
s = strings.TrimLeft(s, " \t\n\f\r")
if s == "" {
return ""
}
if q := s[0]; q == '"' || q == '\'' {
s = s[1:]
closeQuote := strings.IndexRune(s, rune(q))
if closeQuote == -1 {
return ""
}
return s[:closeQuote]
}
end := strings.IndexAny(s, "; \t\n\f\r")
if end == -1 {
end = len(s)
}
return s[:end]
}
return ""
}
var boms = []struct {
bom []byte
enc string
}{
{[]byte{0xfe, 0xff}, "utf-16be"},
{[]byte{0xff, 0xfe}, "utf-16le"},
{[]byte{0xef, 0xbb, 0xbf}, "utf-8"},
}
// Copyright 2011 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 html
// Section 12.2.4.2 of the HTML5 specification says "The following elements
// have varying levels of special parsing rules".
// https://html.spec.whatwg.org/multipage/syntax.html#the-stack-of-open-elements
var isSpecialElementMap = map[string]bool{
"address": true,
"applet": true,
"area": true,
"article": true,
"aside": true,
"base": true,
"basefont": true,
"bgsound": true,
"blockquote": true,
"body": true,
"br": true,
"button": true,
"caption": true,
"center": true,
"col": true,
"colgroup": true,
"dd": true,
"details": true,
"dir": true,
"div": true,
"dl": true,
"dt": true,
"embed": true,
"fieldset": true,
"figcaption": true,
"figure": true,
"footer": true,
"form": true,
"frame": true,
"frameset": true,
"h1": true,
"h2": true,
"h3": true,
"h4": true,
"h5": true,
"h6": true,
"head": true,
"header": true,
"hgroup": true,
"hr": true,
"html": true,
"iframe": true,
"img": true,
"input": true,
"keygen": true, // "keygen" has been removed from the spec, but are kept here for backwards compatibility.
"li": true,
"link": true,
"listing": true,
"main": true,
"marquee": true,
"menu": true,
"meta": true,
"nav": true,
"noembed": true,
"noframes": true,
"noscript": true,
"object": true,
"ol": true,
"p": true,
"param": true,
"plaintext": true,
"pre": true,
"script": true,
"section": true,
"select": true,
"source": true,
"style": true,
"summary": true,
"table": true,
"tbody": true,
"td": true,
"template": true,
"textarea": true,
"tfoot": true,
"th": true,
"thead": true,
"title": true,
"tr": true,
"track": true,
"ul": true,
"wbr": true,
"xmp": true,
}
func isSpecialElement(element *Node) bool {
switch element.Namespace {
case "", "html":
return isSpecialElementMap[element.Data]
case "math":
switch element.Data {
case "mi", "mo", "mn", "ms", "mtext", "annotation-xml":
return true
}
case "svg":
switch element.Data {
case "foreignObject", "desc", "title":
return true
}
}
return false
}
// Copyright 2011 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 html
import (
"strings"
)
// parseDoctype parses the data from a DoctypeToken into a name,
// public identifier, and system identifier. It returns a Node whose Type
// is DoctypeNode, whose Data is the name, and which has attributes
// named "system" and "public" for the two identifiers if they were present.
// quirks is whether the document should be parsed in "quirks mode".
func parseDoctype(s string) (n *Node, quirks bool) {
n = &Node{Type: DoctypeNode}
// Find the name.
space := strings.IndexAny(s, whitespace)
if space == -1 {
space = len(s)
}
n.Data = s[:space]
// The comparison to "html" is case-sensitive.
if n.Data != "html" {
quirks = true
}
n.Data = strings.ToLower(n.Data)
s = strings.TrimLeft(s[space:], whitespace)
if len(s) < 6 {
// It can't start with "PUBLIC" or "SYSTEM".
// Ignore the rest of the string.
return n, quirks || s != ""
}
key := strings.ToLower(s[:6])
s = s[6:]
for key == "public" || key == "system" {
s = strings.TrimLeft(s, whitespace)
if s == "" {
break
}
quote := s[0]
if quote != '"' && quote != '\'' {
break
}
s = s[1:]
q := strings.IndexRune(s, rune(quote))
var id string
if q == -1 {
id = s
s = ""
} else {
id = s[:q]
s = s[q+1:]
}
n.Attr = append(n.Attr, Attribute{Key: key, Val: id})
if key == "public" {
key = "system"
} else {
key = ""
}
}
if key != "" || s != "" {
quirks = true
} else if len(n.Attr) > 0 {
if n.Attr[0].Key == "public" {
public := strings.ToLower(n.Attr[0].Val)
switch public {
case "-//w3o//dtd w3 html strict 3.0//en//", "-/w3d/dtd html 4.0 transitional/en", "html":
quirks = true
default:
for _, q := range quirkyIDs {
if strings.HasPrefix(public, q) {
quirks = true
break
}
}
}
// The following two public IDs only cause quirks mode if there is no system ID.
if len(n.Attr) == 1 && (strings.HasPrefix(public, "-//w3c//dtd html 4.01 frameset//") ||
strings.HasPrefix(public, "-//w3c//dtd html 4.01 transitional//")) {
quirks = true
}
}
if lastAttr := n.Attr[len(n.Attr)-1]; lastAttr.Key == "system" &&
strings.EqualFold(lastAttr.Val, "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd") {
quirks = true
}
}
return n, quirks
}
// quirkyIDs is a list of public doctype identifiers that cause a document
// to be interpreted in quirks mode. The identifiers should be in lower case.
var quirkyIDs = []string{
"+//silmaril//dtd html pro v0r11 19970101//",
"-//advasoft ltd//dtd html 3.0 aswedit + extensions//",
"-//as//dtd html 3.0 aswedit + extensions//",
"-//ietf//dtd html 2.0 level 1//",
"-//ietf//dtd html 2.0 level 2//",
"-//ietf//dtd html 2.0 strict level 1//",
"-//ietf//dtd html 2.0 strict level 2//",
"-//ietf//dtd html 2.0 strict//",
"-//ietf//dtd html 2.0//",
"-//ietf//dtd html 2.1e//",
"-//ietf//dtd html 3.0//",
"-//ietf//dtd html 3.2 final//",
"-//ietf//dtd html 3.2//",
"-//ietf//dtd html 3//",
"-//ietf//dtd html level 0//",
"-//ietf//dtd html level 1//",
"-//ietf//dtd html level 2//",
"-//ietf//dtd html level 3//",
"-//ietf//dtd html strict level 0//",
"-//ietf//dtd html strict level 1//",
"-//ietf//dtd html strict level 2//",
"-//ietf//dtd html strict level 3//",
"-//ietf//dtd html strict//",
"-//ietf//dtd html//",
"-//metrius//dtd metrius presentational//",
"-//microsoft//dtd internet explorer 2.0 html strict//",
"-//microsoft//dtd internet explorer 2.0 html//",
"-//microsoft//dtd internet explorer 2.0 tables//",
"-//microsoft//dtd internet explorer 3.0 html strict//",
"-//microsoft//dtd internet explorer 3.0 html//",
"-//microsoft//dtd internet explorer 3.0 tables//",
"-//netscape comm. corp.//dtd html//",
"-//netscape comm. corp.//dtd strict html//",
"-//o'reilly and associates//dtd html 2.0//",
"-//o'reilly and associates//dtd html extended 1.0//",
"-//o'reilly and associates//dtd html extended relaxed 1.0//",
"-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//",
"-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//",
"-//spyglass//dtd html 2.0 extended//",
"-//sq//dtd html 2.0 hotmetal + extensions//",
"-//sun microsystems corp.//dtd hotjava html//",
"-//sun microsystems corp.//dtd hotjava strict html//",
"-//w3c//dtd html 3 1995-03-24//",
"-//w3c//dtd html 3.2 draft//",
"-//w3c//dtd html 3.2 final//",
"-//w3c//dtd html 3.2//",
"-//w3c//dtd html 3.2s draft//",
"-//w3c//dtd html 4.0 frameset//",
"-//w3c//dtd html 4.0 transitional//",
"-//w3c//dtd html experimental 19960712//",
"-//w3c//dtd html experimental 970421//",
"-//w3c//dtd w3 html//",
"-//w3o//dtd w3 html 3.0//",
"-//webtechs//dtd mozilla html 2.0//",
"-//webtechs//dtd mozilla html//",
}
// Copyright 2010 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 html
import (
"bytes"
"strings"
"unicode/utf8"
)
// These replacements permit compatibility with old numeric entities that
// assumed Windows-1252 encoding.
// https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference
var replacementTable = [...]rune{
'\u20AC', // First entry is what 0x80 should be replaced with.
'\u0081',
'\u201A',
'\u0192',
'\u201E',
'\u2026',
'\u2020',
'\u2021',
'\u02C6',
'\u2030',
'\u0160',
'\u2039',
'\u0152',
'\u008D',
'\u017D',
'\u008F',
'\u0090',
'\u2018',
'\u2019',
'\u201C',
'\u201D',
'\u2022',
'\u2013',
'\u2014',
'\u02DC',
'\u2122',
'\u0161',
'\u203A',
'\u0153',
'\u009D',
'\u017E',
'\u0178', // Last entry is 0x9F.
// 0x00->'\uFFFD' is handled programmatically.
// 0x0D->'\u000D' is a no-op.
}
// unescapeEntity reads an entity like "<" from b[src:] and writes the
// corresponding "<" to b[dst:], returning the incremented dst and src cursors.
// Precondition: b[src] == '&' && dst <= src.
// attribute should be true if parsing an attribute value.
func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
// https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference
// i starts at 1 because we already know that s[0] == '&'.
i, s := 1, b[src:]
if len(s) <= 1 {
b[dst] = b[src]
return dst + 1, src + 1
}
if s[i] == '#' {
if len(s) <= 3 { // We need to have at least "&#.".
b[dst] = b[src]
return dst + 1, src + 1
}
i++
c := s[i]
hex := false
if c == 'x' || c == 'X' {
hex = true
i++
}
x := '\x00'
for i < len(s) {
c = s[i]
i++
if hex {
if '0' <= c && c <= '9' {
x = 16*x + rune(c) - '0'
continue
} else if 'a' <= c && c <= 'f' {
x = 16*x + rune(c) - 'a' + 10
continue
} else if 'A' <= c && c <= 'F' {
x = 16*x + rune(c) - 'A' + 10
continue
}
} else if '0' <= c && c <= '9' {
x = 10*x + rune(c) - '0'
continue
}
if c != ';' {
i--
}
break
}
if i <= 3 { // No characters matched.
b[dst] = b[src]
return dst + 1, src + 1
}
if 0x80 <= x && x <= 0x9F {
// Replace characters from Windows-1252 with UTF-8 equivalents.
x = replacementTable[x-0x80]
} else if x == 0 || (0xD800 <= x && x <= 0xDFFF) || x > 0x10FFFF {
// Replace invalid characters with the replacement character.
x = '\uFFFD'
}
return dst + utf8.EncodeRune(b[dst:], x), src + i
}
// Consume the maximum number of characters possible, with the
// consumed characters matching one of the named references.
for i < len(s) {
c := s[i]
i++
// Lower-cased characters are more common in entities, so we check for them first.
if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
continue
}
if c != ';' {
i--
}
break
}
entityName := string(s[1:i])
if entityName == "" {
// No-op.
} else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' {
// No-op.
} else if x := entity[entityName]; x != 0 {
return dst + utf8.EncodeRune(b[dst:], x), src + i
} else if x := entity2[entityName]; x[0] != 0 {
dst1 := dst + utf8.EncodeRune(b[dst:], x[0])
return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i
} else if !attribute {
maxLen := len(entityName) - 1
if maxLen > longestEntityWithoutSemicolon {
maxLen = longestEntityWithoutSemicolon
}
for j := maxLen; j > 1; j-- {
if x := entity[entityName[:j]]; x != 0 {
return dst + utf8.EncodeRune(b[dst:], x), src + j + 1
}
}
}
dst1, src1 = dst+i, src+i
copy(b[dst:dst1], b[src:src1])
return dst1, src1
}
// unescape unescapes b's entities in-place, so that "a<b" becomes "a<b".
// attribute should be true if parsing an attribute value.
func unescape(b []byte, attribute bool) []byte {
for i, c := range b {
if c == '&' {
dst, src := unescapeEntity(b, i, i, attribute)
for src < len(b) {
c := b[src]
if c == '&' {
dst, src = unescapeEntity(b, dst, src, attribute)
} else {
b[dst] = c
dst, src = dst+1, src+1
}
}
return b[0:dst]
}
}
return b
}
// lower lower-cases the A-Z bytes in b in-place, so that "aBc" becomes "abc".
func lower(b []byte) []byte {
for i, c := range b {
if 'A' <= c && c <= 'Z' {
b[i] = c + 'a' - 'A'
}
}
return b
}
// escapeComment is like func escape but escapes its input bytes less often.
// Per https://github.com/golang/go/issues/58246 some HTML comments are (1)
// meaningful and (2) contain angle brackets that we'd like to avoid escaping
// unless we have to.
//
// "We have to" includes the '&' byte, since that introduces other escapes.
//
// It also includes those bytes (not including EOF) that would otherwise end
// the comment. Per the summary table at the bottom of comment_test.go, this is
// the '>' byte that, per above, we'd like to avoid escaping unless we have to.
//
// Studying the summary table (and T actions in its '>' column) closely, we
// only need to escape in states 43, 44, 49, 51 and 52. State 43 is at the
// start of the comment data. State 52 is after a '!'. The other three states
// are after a '-'.
//
// Our algorithm is thus to escape every '&' and to escape '>' if and only if:
// - The '>' is after a '!' or '-' (in the unescaped data) or
// - The '>' is at the start of the comment data (after the opening "<!--").
func escapeComment(w writer, s string) error {
// When modifying this function, consider manually increasing the
// maxSuffixLen constant in func TestComments, from 6 to e.g. 9 or more.
// That increase should only be temporary, not committed, as it
// exponentially affects the test running time.
if len(s) == 0 {
return nil
}
// Loop:
// - Grow j such that s[i:j] does not need escaping.
// - If s[j] does need escaping, output s[i:j] and an escaped s[j],
// resetting i and j to point past that s[j] byte.
i := 0
for j := 0; j < len(s); j++ {
escaped := ""
switch s[j] {
case '&':
escaped = "&"
case '>':
if j > 0 {
if prev := s[j-1]; (prev != '!') && (prev != '-') {
continue
}
}
escaped = ">"
default:
continue
}
if i < j {
if _, err := w.WriteString(s[i:j]); err != nil {
return err
}
}
if _, err := w.WriteString(escaped); err != nil {
return err
}
i = j + 1
}
if i < len(s) {
if _, err := w.WriteString(s[i:]); err != nil {
return err
}
}
return nil
}
// escapeCommentString is to EscapeString as escapeComment is to escape.
func escapeCommentString(s string) string {
if strings.IndexAny(s, "&>") == -1 {
return s
}
var buf bytes.Buffer
escapeComment(&buf, s)
return buf.String()
}
const escapedChars = "&'<>\"\r"
func escape(w writer, s string) error {
i := strings.IndexAny(s, escapedChars)
for i != -1 {
if _, err := w.WriteString(s[:i]); err != nil {
return err
}
var esc string
switch s[i] {
case '&':
esc = "&"
case '\'':
// "'" is shorter than "'" and apos was not in HTML until HTML5.
esc = "'"
case '<':
esc = "<"
case '>':
esc = ">"
case '"':
// """ is shorter than """.
esc = """
case '\r':
esc = " "
default:
panic("html: unrecognized escape character")
}
s = s[i+1:]
if _, err := w.WriteString(esc); err != nil {
return err
}
i = strings.IndexAny(s, escapedChars)
}
_, err := w.WriteString(s)
return err
}
// EscapeString escapes special characters like "<" to become "<". It
// escapes only five such characters: <, >, &, ' and ".
// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
// always true.
func EscapeString(s string) string {
if strings.IndexAny(s, escapedChars) == -1 {
return s
}
var buf bytes.Buffer
escape(&buf, s)
return buf.String()
}
// UnescapeString unescapes entities like "<" to become "<". It unescapes a
// larger range of entities than EscapeString escapes. For example, "á"
// unescapes to "á", as does "á" and "&xE1;".
// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
// always true.
func UnescapeString(s string) string {
for _, c := range s {
if c == '&' {
return string(unescape([]byte(s), false))
}
}
return s
}
// Copyright 2011 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 html
import (
"strings"
)
func adjustAttributeNames(aa []Attribute, nameMap map[string]string) {
for i := range aa {
if newName, ok := nameMap[aa[i].Key]; ok {
aa[i].Key = newName
}
}
}
func adjustForeignAttributes(aa []Attribute) {
for i, a := range aa {
if a.Key == "" || a.Key[0] != 'x' {
continue
}
switch a.Key {
case "xlink:actuate", "xlink:arcrole", "xlink:href", "xlink:role", "xlink:show",
"xlink:title", "xlink:type", "xml:base", "xml:lang", "xml:space", "xmlns:xlink":
j := strings.Index(a.Key, ":")
aa[i].Namespace = a.Key[:j]
aa[i].Key = a.Key[j+1:]
}
}
}
func htmlIntegrationPoint(n *Node) bool {
if n.Type != ElementNode {
return false
}
switch n.Namespace {
case "math":
if n.Data == "annotation-xml" {
for _, a := range n.Attr {
if a.Key == "encoding" {
if strings.EqualFold(a.Val, "text/html") || strings.EqualFold(a.Val, "application/xhtml+xml") {
return true
}
}
}
}
case "svg":
switch n.Data {
case "desc", "foreignObject", "title":
return true
}
}
return false
}
func mathMLTextIntegrationPoint(n *Node) bool {
if n.Namespace != "math" {
return false
}
switch n.Data {
case "mi", "mo", "mn", "ms", "mtext":
return true
}
return false
}
// Section 12.2.6.5.
var breakout = map[string]bool{
"b": true,
"big": true,
"blockquote": true,
"body": true,
"br": true,
"center": true,
"code": true,
"dd": true,
"div": true,
"dl": true,
"dt": true,
"em": true,
"embed": true,
"h1": true,
"h2": true,
"h3": true,
"h4": true,
"h5": true,
"h6": true,
"head": true,
"hr": true,
"i": true,
"img": true,
"li": true,
"listing": true,
"menu": true,
"meta": true,
"nobr": true,
"ol": true,
"p": true,
"pre": true,
"ruby": true,
"s": true,
"small": true,
"span": true,
"strong": true,
"strike": true,
"sub": true,
"sup": true,
"table": true,
"tt": true,
"u": true,
"ul": true,
"var": true,
}
// Section 12.2.6.5.
var svgTagNameAdjustments = map[string]string{
"altglyph": "altGlyph",
"altglyphdef": "altGlyphDef",
"altglyphitem": "altGlyphItem",
"animatecolor": "animateColor",
"animatemotion": "animateMotion",
"animatetransform": "animateTransform",
"clippath": "clipPath",
"feblend": "feBlend",
"fecolormatrix": "feColorMatrix",
"fecomponenttransfer": "feComponentTransfer",
"fecomposite": "feComposite",
"feconvolvematrix": "feConvolveMatrix",
"fediffuselighting": "feDiffuseLighting",
"fedisplacementmap": "feDisplacementMap",
"fedistantlight": "feDistantLight",
"feflood": "feFlood",
"fefunca": "feFuncA",
"fefuncb": "feFuncB",
"fefuncg": "feFuncG",
"fefuncr": "feFuncR",
"fegaussianblur": "feGaussianBlur",
"feimage": "feImage",
"femerge": "feMerge",
"femergenode": "feMergeNode",
"femorphology": "feMorphology",
"feoffset": "feOffset",
"fepointlight": "fePointLight",
"fespecularlighting": "feSpecularLighting",
"fespotlight": "feSpotLight",
"fetile": "feTile",
"feturbulence": "feTurbulence",
"foreignobject": "foreignObject",
"glyphref": "glyphRef",
"lineargradient": "linearGradient",
"radialgradient": "radialGradient",
"textpath": "textPath",
}
// Section 12.2.6.1
var mathMLAttributeAdjustments = map[string]string{
"definitionurl": "definitionURL",
}
var svgAttributeAdjustments = map[string]string{
"attributename": "attributeName",
"attributetype": "attributeType",
"basefrequency": "baseFrequency",
"baseprofile": "baseProfile",
"calcmode": "calcMode",
"clippathunits": "clipPathUnits",
"diffuseconstant": "diffuseConstant",
"edgemode": "edgeMode",
"filterunits": "filterUnits",
"glyphref": "glyphRef",
"gradienttransform": "gradientTransform",
"gradientunits": "gradientUnits",
"kernelmatrix": "kernelMatrix",
"kernelunitlength": "kernelUnitLength",
"keypoints": "keyPoints",
"keysplines": "keySplines",
"keytimes": "keyTimes",
"lengthadjust": "lengthAdjust",
"limitingconeangle": "limitingConeAngle",
"markerheight": "markerHeight",
"markerunits": "markerUnits",
"markerwidth": "markerWidth",
"maskcontentunits": "maskContentUnits",
"maskunits": "maskUnits",
"numoctaves": "numOctaves",
"pathlength": "pathLength",
"patterncontentunits": "patternContentUnits",
"patterntransform": "patternTransform",
"patternunits": "patternUnits",
"pointsatx": "pointsAtX",
"pointsaty": "pointsAtY",
"pointsatz": "pointsAtZ",
"preservealpha": "preserveAlpha",
"preserveaspectratio": "preserveAspectRatio",
"primitiveunits": "primitiveUnits",
"refx": "refX",
"refy": "refY",
"repeatcount": "repeatCount",
"repeatdur": "repeatDur",
"requiredextensions": "requiredExtensions",
"requiredfeatures": "requiredFeatures",
"specularconstant": "specularConstant",
"specularexponent": "specularExponent",
"spreadmethod": "spreadMethod",
"startoffset": "startOffset",
"stddeviation": "stdDeviation",
"stitchtiles": "stitchTiles",
"surfacescale": "surfaceScale",
"systemlanguage": "systemLanguage",
"tablevalues": "tableValues",
"targetx": "targetX",
"targety": "targetY",
"textlength": "textLength",
"viewbox": "viewBox",
"viewtarget": "viewTarget",
"xchannelselector": "xChannelSelector",
"ychannelselector": "yChannelSelector",
"zoomandpan": "zoomAndPan",
}
// Copyright 2024 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.
//go:build go1.23
package html
import "iter"
// Ancestors returns an iterator over the ancestors of n, starting with n.Parent.
//
// Mutating a Node or its parents while iterating may have unexpected results.
func (n *Node) Ancestors() iter.Seq[*Node] {
_ = n.Parent // eager nil check
return func(yield func(*Node) bool) {
for p := n.Parent; p != nil && yield(p); p = p.Parent {
}
}
}
// ChildNodes returns an iterator over the immediate children of n,
// starting with n.FirstChild.
//
// Mutating a Node or its children while iterating may have unexpected results.
func (n *Node) ChildNodes() iter.Seq[*Node] {
_ = n.FirstChild // eager nil check
return func(yield func(*Node) bool) {
for c := n.FirstChild; c != nil && yield(c); c = c.NextSibling {
}
}
}
// Descendants returns an iterator over all nodes recursively beneath
// n, excluding n itself. Nodes are visited in depth-first preorder.
//
// Mutating a Node or its descendants while iterating may have unexpected results.
func (n *Node) Descendants() iter.Seq[*Node] {
_ = n.FirstChild // eager nil check
return func(yield func(*Node) bool) {
n.descendants(yield)
}
}
func (n *Node) descendants(yield func(*Node) bool) bool {
for c := range n.ChildNodes() {
if !yield(c) || !c.descendants(yield) {
return false
}
}
return true
}
// Copyright 2011 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 html
import (
"golang.org/x/net/html/atom"
)
// A NodeType is the type of a Node.
type NodeType uint32
const (
ErrorNode NodeType = iota
TextNode
DocumentNode
ElementNode
CommentNode
DoctypeNode
// RawNode nodes are not returned by the parser, but can be part of the
// Node tree passed to func Render to insert raw HTML (without escaping).
// If so, this package makes no guarantee that the rendered HTML is secure
// (from e.g. Cross Site Scripting attacks) or well-formed.
RawNode
scopeMarkerNode
)
// Section 12.2.4.3 says "The markers are inserted when entering applet,
// object, marquee, template, td, th, and caption elements, and are used
// to prevent formatting from "leaking" into applet, object, marquee,
// template, td, th, and caption elements".
var scopeMarker = Node{Type: scopeMarkerNode}
// A Node consists of a NodeType and some Data (tag name for element nodes,
// content for text) and are part of a tree of Nodes. Element nodes may also
// have a Namespace and contain a slice of Attributes. Data is unescaped, so
// that it looks like "a<b" rather than "a<b". For element nodes, DataAtom
// is the atom for Data, or zero if Data is not a known tag name.
//
// Node trees may be navigated using the link fields (Parent,
// FirstChild, and so on) or a range loop over iterators such as
// [Node.Descendants].
//
// An empty Namespace implies a "http://www.w3.org/1999/xhtml" namespace.
// Similarly, "math" is short for "http://www.w3.org/1998/Math/MathML", and
// "svg" is short for "http://www.w3.org/2000/svg".
type Node struct {
Parent, FirstChild, LastChild, PrevSibling, NextSibling *Node
Type NodeType
DataAtom atom.Atom
Data string
Namespace string
Attr []Attribute
}
// InsertBefore inserts newChild as a child of n, immediately before oldChild
// in the sequence of n's children. oldChild may be nil, in which case newChild
// is appended to the end of n's children.
//
// It will panic if newChild already has a parent or siblings.
func (n *Node) InsertBefore(newChild, oldChild *Node) {
if newChild.Parent != nil || newChild.PrevSibling != nil || newChild.NextSibling != nil {
panic("html: InsertBefore called for an attached child Node")
}
var prev, next *Node
if oldChild != nil {
prev, next = oldChild.PrevSibling, oldChild
} else {
prev = n.LastChild
}
if prev != nil {
prev.NextSibling = newChild
} else {
n.FirstChild = newChild
}
if next != nil {
next.PrevSibling = newChild
} else {
n.LastChild = newChild
}
newChild.Parent = n
newChild.PrevSibling = prev
newChild.NextSibling = next
}
// AppendChild adds a node c as a child of n.
//
// It will panic if c already has a parent or siblings.
func (n *Node) AppendChild(c *Node) {
if c.Parent != nil || c.PrevSibling != nil || c.NextSibling != nil {
panic("html: AppendChild called for an attached child Node")
}
last := n.LastChild
if last != nil {
last.NextSibling = c
} else {
n.FirstChild = c
}
n.LastChild = c
c.Parent = n
c.PrevSibling = last
}
// RemoveChild removes a node c that is a child of n. Afterwards, c will have
// no parent and no siblings.
//
// It will panic if c's parent is not n.
func (n *Node) RemoveChild(c *Node) {
if c.Parent != n {
panic("html: RemoveChild called for a non-child Node")
}
if n.FirstChild == c {
n.FirstChild = c.NextSibling
}
if c.NextSibling != nil {
c.NextSibling.PrevSibling = c.PrevSibling
}
if n.LastChild == c {
n.LastChild = c.PrevSibling
}
if c.PrevSibling != nil {
c.PrevSibling.NextSibling = c.NextSibling
}
c.Parent = nil
c.PrevSibling = nil
c.NextSibling = nil
}
// reparentChildren reparents all of src's child nodes to dst.
func reparentChildren(dst, src *Node) {
for {
child := src.FirstChild
if child == nil {
break
}
src.RemoveChild(child)
dst.AppendChild(child)
}
}
// clone returns a new node with the same type, data and attributes.
// The clone has no parent, no siblings and no children.
func (n *Node) clone() *Node {
m := &Node{
Type: n.Type,
DataAtom: n.DataAtom,
Data: n.Data,
Attr: make([]Attribute, len(n.Attr)),
}
copy(m.Attr, n.Attr)
return m
}
// nodeStack is a stack of nodes.
type nodeStack []*Node
// pop pops the stack. It will panic if s is empty.
func (s *nodeStack) pop() *Node {
i := len(*s)
n := (*s)[i-1]
*s = (*s)[:i-1]
return n
}
// top returns the most recently pushed node, or nil if s is empty.
func (s *nodeStack) top() *Node {
if i := len(*s); i > 0 {
return (*s)[i-1]
}
return nil
}
// index returns the index of the top-most occurrence of n in the stack, or -1
// if n is not present.
func (s *nodeStack) index(n *Node) int {
for i := len(*s) - 1; i >= 0; i-- {
if (*s)[i] == n {
return i
}
}
return -1
}
// contains returns whether a is within s.
func (s *nodeStack) contains(a atom.Atom) bool {
for _, n := range *s {
if n.DataAtom == a && n.Namespace == "" {
return true
}
}
return false
}
// insert inserts a node at the given index.
func (s *nodeStack) insert(i int, n *Node) {
(*s) = append(*s, nil)
copy((*s)[i+1:], (*s)[i:])
(*s)[i] = n
}
// remove removes a node from the stack. It is a no-op if n is not present.
func (s *nodeStack) remove(n *Node) {
i := s.index(n)
if i == -1 {
return
}
copy((*s)[i:], (*s)[i+1:])
j := len(*s) - 1
(*s)[j] = nil
*s = (*s)[:j]
}
type insertionModeStack []insertionMode
func (s *insertionModeStack) pop() (im insertionMode) {
i := len(*s)
im = (*s)[i-1]
*s = (*s)[:i-1]
return im
}
func (s *insertionModeStack) top() insertionMode {
if i := len(*s); i > 0 {
return (*s)[i-1]
}
return nil
}
// Copyright 2010 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 html
import (
"errors"
"fmt"
"io"
"strings"
a "golang.org/x/net/html/atom"
)
// A parser implements the HTML5 parsing algorithm:
// https://html.spec.whatwg.org/multipage/syntax.html#tree-construction
type parser struct {
// tokenizer provides the tokens for the parser.
tokenizer *Tokenizer
// tok is the most recently read token.
tok Token
// Self-closing tags like <hr/> are treated as start tags, except that
// hasSelfClosingToken is set while they are being processed.
hasSelfClosingToken bool
// doc is the document root element.
doc *Node
// The stack of open elements (section 12.2.4.2) and active formatting
// elements (section 12.2.4.3).
oe, afe nodeStack
// Element pointers (section 12.2.4.4).
head, form *Node
// Other parsing state flags (section 12.2.4.5).
scripting, framesetOK bool
// The stack of template insertion modes
templateStack insertionModeStack
// im is the current insertion mode.
im insertionMode
// originalIM is the insertion mode to go back to after completing a text
// or inTableText insertion mode.
originalIM insertionMode
// fosterParenting is whether new elements should be inserted according to
// the foster parenting rules (section 12.2.6.1).
fosterParenting bool
// quirks is whether the parser is operating in "quirks mode."
quirks bool
// fragment is whether the parser is parsing an HTML fragment.
fragment bool
// context is the context element when parsing an HTML fragment
// (section 12.4).
context *Node
}
func (p *parser) top() *Node {
if n := p.oe.top(); n != nil {
return n
}
return p.doc
}
// Stop tags for use in popUntil. These come from section 12.2.4.2.
var (
defaultScopeStopTags = map[string][]a.Atom{
"": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template},
"math": {a.AnnotationXml, a.Mi, a.Mn, a.Mo, a.Ms, a.Mtext},
"svg": {a.Desc, a.ForeignObject, a.Title},
}
)
type scope int
const (
defaultScope scope = iota
listItemScope
buttonScope
tableScope
tableRowScope
tableBodyScope
selectScope
)
// popUntil pops the stack of open elements at the highest element whose tag
// is in matchTags, provided there is no higher element in the scope's stop
// tags (as defined in section 12.2.4.2). It returns whether or not there was
// such an element. If there was not, popUntil leaves the stack unchanged.
//
// For example, the set of stop tags for table scope is: "html", "table". If
// the stack was:
// ["html", "body", "font", "table", "b", "i", "u"]
// then popUntil(tableScope, "font") would return false, but
// popUntil(tableScope, "i") would return true and the stack would become:
// ["html", "body", "font", "table", "b"]
//
// If an element's tag is in both the stop tags and matchTags, then the stack
// will be popped and the function returns true (provided, of course, there was
// no higher element in the stack that was also in the stop tags). For example,
// popUntil(tableScope, "table") returns true and leaves:
// ["html", "body", "font"]
func (p *parser) popUntil(s scope, matchTags ...a.Atom) bool {
if i := p.indexOfElementInScope(s, matchTags...); i != -1 {
p.oe = p.oe[:i]
return true
}
return false
}
// indexOfElementInScope returns the index in p.oe of the highest element whose
// tag is in matchTags that is in scope. If no matching element is in scope, it
// returns -1.
func (p *parser) indexOfElementInScope(s scope, matchTags ...a.Atom) int {
for i := len(p.oe) - 1; i >= 0; i-- {
tagAtom := p.oe[i].DataAtom
if p.oe[i].Namespace == "" {
for _, t := range matchTags {
if t == tagAtom {
return i
}
}
switch s {
case defaultScope:
// No-op.
case listItemScope:
if tagAtom == a.Ol || tagAtom == a.Ul {
return -1
}
case buttonScope:
if tagAtom == a.Button {
return -1
}
case tableScope:
if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template {
return -1
}
case selectScope:
if tagAtom != a.Optgroup && tagAtom != a.Option {
return -1
}
default:
panic(fmt.Sprintf("html: internal error: indexOfElementInScope unknown scope: %d", s))
}
}
switch s {
case defaultScope, listItemScope, buttonScope:
for _, t := range defaultScopeStopTags[p.oe[i].Namespace] {
if t == tagAtom {
return -1
}
}
}
}
return -1
}
// elementInScope is like popUntil, except that it doesn't modify the stack of
// open elements.
func (p *parser) elementInScope(s scope, matchTags ...a.Atom) bool {
return p.indexOfElementInScope(s, matchTags...) != -1
}
// clearStackToContext pops elements off the stack of open elements until a
// scope-defined element is found.
func (p *parser) clearStackToContext(s scope) {
for i := len(p.oe) - 1; i >= 0; i-- {
tagAtom := p.oe[i].DataAtom
switch s {
case tableScope:
if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template {
p.oe = p.oe[:i+1]
return
}
case tableRowScope:
if tagAtom == a.Html || tagAtom == a.Tr || tagAtom == a.Template {
p.oe = p.oe[:i+1]
return
}
case tableBodyScope:
if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead || tagAtom == a.Template {
p.oe = p.oe[:i+1]
return
}
default:
panic(fmt.Sprintf("html: internal error: clearStackToContext unknown scope: %d", s))
}
}
}
// parseGenericRawTextElement implements the generic raw text element parsing
// algorithm defined in 12.2.6.2.
// https://html.spec.whatwg.org/multipage/parsing.html#parsing-elements-that-contain-only-text
// TODO: Since both RAWTEXT and RCDATA states are treated as tokenizer's part
// officially, need to make tokenizer consider both states.
func (p *parser) parseGenericRawTextElement() {
p.addElement()
p.originalIM = p.im
p.im = textIM
}
// generateImpliedEndTags pops nodes off the stack of open elements as long as
// the top node has a tag name of dd, dt, li, optgroup, option, p, rb, rp, rt or rtc.
// If exceptions are specified, nodes with that name will not be popped off.
func (p *parser) generateImpliedEndTags(exceptions ...string) {
var i int
loop:
for i = len(p.oe) - 1; i >= 0; i-- {
n := p.oe[i]
if n.Type != ElementNode {
break
}
switch n.DataAtom {
case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb, a.Rp, a.Rt, a.Rtc:
for _, except := range exceptions {
if n.Data == except {
break loop
}
}
continue
}
break
}
p.oe = p.oe[:i+1]
}
// addChild adds a child node n to the top element, and pushes n onto the stack
// of open elements if it is an element node.
func (p *parser) addChild(n *Node) {
if p.shouldFosterParent() {
p.fosterParent(n)
} else {
p.top().AppendChild(n)
}
if n.Type == ElementNode {
p.insertOpenElement(n)
}
}
func (p *parser) insertOpenElement(n *Node) {
p.oe = append(p.oe, n)
if len(p.oe) > 512 {
panic("html: open stack of elements exceeds 512 nodes")
}
}
// shouldFosterParent returns whether the next node to be added should be
// foster parented.
func (p *parser) shouldFosterParent() bool {
if p.fosterParenting {
switch p.top().DataAtom {
case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
return true
}
}
return false
}
// fosterParent adds a child node according to the foster parenting rules.
// Section 12.2.6.1, "foster parenting".
func (p *parser) fosterParent(n *Node) {
var table, parent, prev, template *Node
var i int
for i = len(p.oe) - 1; i >= 0; i-- {
if p.oe[i].DataAtom == a.Table {
table = p.oe[i]
break
}
}
var j int
for j = len(p.oe) - 1; j >= 0; j-- {
if p.oe[j].DataAtom == a.Template {
template = p.oe[j]
break
}
}
if template != nil && (table == nil || j > i) {
template.AppendChild(n)
return
}
if table == nil {
// The foster parent is the html element.
parent = p.oe[0]
} else {
parent = table.Parent
}
if parent == nil {
parent = p.oe[i-1]
}
if table != nil {
prev = table.PrevSibling
} else {
prev = parent.LastChild
}
if prev != nil && prev.Type == TextNode && n.Type == TextNode {
prev.Data += n.Data
return
}
parent.InsertBefore(n, table)
}
// addText adds text to the preceding node if it is a text node, or else it
// calls addChild with a new text node.
func (p *parser) addText(text string) {
if text == "" {
return
}
if p.shouldFosterParent() {
p.fosterParent(&Node{
Type: TextNode,
Data: text,
})
return
}
t := p.top()
if n := t.LastChild; n != nil && n.Type == TextNode {
n.Data += text
return
}
p.addChild(&Node{
Type: TextNode,
Data: text,
})
}
// addElement adds a child element based on the current token.
func (p *parser) addElement() {
p.addChild(&Node{
Type: ElementNode,
DataAtom: p.tok.DataAtom,
Data: p.tok.Data,
Attr: p.tok.Attr,
})
}
// Section 12.2.4.3.
func (p *parser) addFormattingElement() {
tagAtom, attr := p.tok.DataAtom, p.tok.Attr
p.addElement()
// Implement the Noah's Ark clause, but with three per family instead of two.
identicalElements := 0
findIdenticalElements:
for i := len(p.afe) - 1; i >= 0; i-- {
n := p.afe[i]
if n.Type == scopeMarkerNode {
break
}
if n.Type != ElementNode {
continue
}
if n.Namespace != "" {
continue
}
if n.DataAtom != tagAtom {
continue
}
if len(n.Attr) != len(attr) {
continue
}
compareAttributes:
for _, t0 := range n.Attr {
for _, t1 := range attr {
if t0.Key == t1.Key && t0.Namespace == t1.Namespace && t0.Val == t1.Val {
// Found a match for this attribute, continue with the next attribute.
continue compareAttributes
}
}
// If we get here, there is no attribute that matches a.
// Therefore the element is not identical to the new one.
continue findIdenticalElements
}
identicalElements++
if identicalElements >= 3 {
p.afe.remove(n)
}
}
p.afe = append(p.afe, p.top())
}
// Section 12.2.4.3.
func (p *parser) clearActiveFormattingElements() {
for {
if n := p.afe.pop(); len(p.afe) == 0 || n.Type == scopeMarkerNode {
return
}
}
}
// Section 12.2.4.3.
func (p *parser) reconstructActiveFormattingElements() {
n := p.afe.top()
if n == nil {
return
}
if n.Type == scopeMarkerNode || p.oe.index(n) != -1 {
return
}
i := len(p.afe) - 1
for n.Type != scopeMarkerNode && p.oe.index(n) == -1 {
if i == 0 {
i = -1
break
}
i--
n = p.afe[i]
}
for {
i++
clone := p.afe[i].clone()
p.addChild(clone)
p.afe[i] = clone
if i == len(p.afe)-1 {
break
}
}
}
// Section 12.2.5.
func (p *parser) acknowledgeSelfClosingTag() {
p.hasSelfClosingToken = false
}
// An insertion mode (section 12.2.4.1) is the state transition function from
// a particular state in the HTML5 parser's state machine. It updates the
// parser's fields depending on parser.tok (where ErrorToken means EOF).
// It returns whether the token was consumed.
type insertionMode func(*parser) bool
// setOriginalIM sets the insertion mode to return to after completing a text or
// inTableText insertion mode.
// Section 12.2.4.1, "using the rules for".
func (p *parser) setOriginalIM() {
if p.originalIM != nil {
panic("html: bad parser state: originalIM was set twice")
}
p.originalIM = p.im
}
// Section 12.2.4.1, "reset the insertion mode".
func (p *parser) resetInsertionMode() {
for i := len(p.oe) - 1; i >= 0; i-- {
n := p.oe[i]
last := i == 0
if last && p.context != nil {
n = p.context
}
switch n.DataAtom {
case a.Select:
if !last {
for ancestor, first := n, p.oe[0]; ancestor != first; {
ancestor = p.oe[p.oe.index(ancestor)-1]
switch ancestor.DataAtom {
case a.Template:
p.im = inSelectIM
return
case a.Table:
p.im = inSelectInTableIM
return
}
}
}
p.im = inSelectIM
case a.Td, a.Th:
// TODO: remove this divergence from the HTML5 spec.
//
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
p.im = inCellIM
case a.Tr:
p.im = inRowIM
case a.Tbody, a.Thead, a.Tfoot:
p.im = inTableBodyIM
case a.Caption:
p.im = inCaptionIM
case a.Colgroup:
p.im = inColumnGroupIM
case a.Table:
p.im = inTableIM
case a.Template:
// TODO: remove this divergence from the HTML5 spec.
if n.Namespace != "" {
continue
}
p.im = p.templateStack.top()
case a.Head:
// TODO: remove this divergence from the HTML5 spec.
//
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
p.im = inHeadIM
case a.Body:
p.im = inBodyIM
case a.Frameset:
p.im = inFramesetIM
case a.Html:
if p.head == nil {
p.im = beforeHeadIM
} else {
p.im = afterHeadIM
}
default:
if last {
p.im = inBodyIM
return
}
continue
}
return
}
}
const whitespace = " \t\r\n\f"
// Section 12.2.6.4.1.
func initialIM(p *parser) bool {
switch p.tok.Type {
case TextToken:
p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace)
if len(p.tok.Data) == 0 {
// It was all whitespace, so ignore it.
return true
}
case CommentToken:
p.doc.AppendChild(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
return true
case DoctypeToken:
n, quirks := parseDoctype(p.tok.Data)
p.doc.AppendChild(n)
p.quirks = quirks
p.im = beforeHTMLIM
return true
}
p.quirks = true
p.im = beforeHTMLIM
return false
}
// Section 12.2.6.4.2.
func beforeHTMLIM(p *parser) bool {
switch p.tok.Type {
case DoctypeToken:
// Ignore the token.
return true
case TextToken:
p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace)
if len(p.tok.Data) == 0 {
// It was all whitespace, so ignore it.
return true
}
case StartTagToken:
if p.tok.DataAtom == a.Html {
p.addElement()
p.im = beforeHeadIM
return true
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Head, a.Body, a.Html, a.Br:
p.parseImpliedToken(StartTagToken, a.Html, a.Html.String())
return false
default:
// Ignore the token.
return true
}
case CommentToken:
p.doc.AppendChild(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
return true
}
p.parseImpliedToken(StartTagToken, a.Html, a.Html.String())
return false
}
// Section 12.2.6.4.3.
func beforeHeadIM(p *parser) bool {
switch p.tok.Type {
case TextToken:
p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace)
if len(p.tok.Data) == 0 {
// It was all whitespace, so ignore it.
return true
}
case StartTagToken:
switch p.tok.DataAtom {
case a.Head:
p.addElement()
p.head = p.top()
p.im = inHeadIM
return true
case a.Html:
return inBodyIM(p)
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Head, a.Body, a.Html, a.Br:
p.parseImpliedToken(StartTagToken, a.Head, a.Head.String())
return false
default:
// Ignore the token.
return true
}
case CommentToken:
p.addChild(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
return true
case DoctypeToken:
// Ignore the token.
return true
}
p.parseImpliedToken(StartTagToken, a.Head, a.Head.String())
return false
}
// Section 12.2.6.4.4.
func inHeadIM(p *parser) bool {
switch p.tok.Type {
case TextToken:
s := strings.TrimLeft(p.tok.Data, whitespace)
if len(s) < len(p.tok.Data) {
// Add the initial whitespace to the current node.
p.addText(p.tok.Data[:len(p.tok.Data)-len(s)])
if s == "" {
return true
}
p.tok.Data = s
}
case StartTagToken:
switch p.tok.DataAtom {
case a.Html:
return inBodyIM(p)
case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta:
p.addElement()
p.oe.pop()
p.acknowledgeSelfClosingTag()
return true
case a.Noscript:
if p.scripting {
p.parseGenericRawTextElement()
return true
}
p.addElement()
p.im = inHeadNoscriptIM
// Don't let the tokenizer go into raw text mode when scripting is disabled.
p.tokenizer.NextIsNotRawText()
return true
case a.Script, a.Title:
p.addElement()
p.setOriginalIM()
p.im = textIM
return true
case a.Noframes, a.Style:
p.parseGenericRawTextElement()
return true
case a.Head:
// Ignore the token.
return true
case a.Template:
// TODO: remove this divergence from the HTML5 spec.
//
// We don't handle all of the corner cases when mixing foreign
// content (i.e. <math> or <svg>) with <template>. Without this
// early return, we can get into an infinite loop, possibly because
// of the "TODO... further divergence" a little below.
//
// As a workaround, if we are mixing foreign content and templates,
// just ignore the rest of the HTML. Foreign content is rare and a
// relatively old HTML feature. Templates are also rare and a
// relatively new HTML feature. Their combination is very rare.
for _, e := range p.oe {
if e.Namespace != "" {
p.im = ignoreTheRemainingTokens
return true
}
}
p.addElement()
p.afe = append(p.afe, &scopeMarker)
p.framesetOK = false
p.im = inTemplateIM
p.templateStack = append(p.templateStack, inTemplateIM)
return true
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Head:
p.oe.pop()
p.im = afterHeadIM
return true
case a.Body, a.Html, a.Br:
p.parseImpliedToken(EndTagToken, a.Head, a.Head.String())
return false
case a.Template:
if !p.oe.contains(a.Template) {
return true
}
// TODO: remove this further divergence from the HTML5 spec.
//
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
p.generateImpliedEndTags()
for i := len(p.oe) - 1; i >= 0; i-- {
if n := p.oe[i]; n.Namespace == "" && n.DataAtom == a.Template {
p.oe = p.oe[:i]
break
}
}
p.clearActiveFormattingElements()
p.templateStack.pop()
p.resetInsertionMode()
return true
default:
// Ignore the token.
return true
}
case CommentToken:
p.addChild(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
return true
case DoctypeToken:
// Ignore the token.
return true
}
p.parseImpliedToken(EndTagToken, a.Head, a.Head.String())
return false
}
// Section 12.2.6.4.5.
func inHeadNoscriptIM(p *parser) bool {
switch p.tok.Type {
case DoctypeToken:
// Ignore the token.
return true
case StartTagToken:
switch p.tok.DataAtom {
case a.Html:
return inBodyIM(p)
case a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Style:
return inHeadIM(p)
case a.Head:
// Ignore the token.
return true
case a.Noscript:
// Don't let the tokenizer go into raw text mode even when a <noscript>
// tag is in "in head noscript" insertion mode.
p.tokenizer.NextIsNotRawText()
// Ignore the token.
return true
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Noscript, a.Br:
default:
// Ignore the token.
return true
}
case TextToken:
s := strings.TrimLeft(p.tok.Data, whitespace)
if len(s) == 0 {
// It was all whitespace.
return inHeadIM(p)
}
case CommentToken:
return inHeadIM(p)
}
p.oe.pop()
if p.top().DataAtom != a.Head {
panic("html: the new current node will be a head element.")
}
p.im = inHeadIM
if p.tok.DataAtom == a.Noscript {
return true
}
return false
}
// Section 12.2.6.4.6.
func afterHeadIM(p *parser) bool {
switch p.tok.Type {
case TextToken:
s := strings.TrimLeft(p.tok.Data, whitespace)
if len(s) < len(p.tok.Data) {
// Add the initial whitespace to the current node.
p.addText(p.tok.Data[:len(p.tok.Data)-len(s)])
if s == "" {
return true
}
p.tok.Data = s
}
case StartTagToken:
switch p.tok.DataAtom {
case a.Html:
return inBodyIM(p)
case a.Body:
p.addElement()
p.framesetOK = false
p.im = inBodyIM
return true
case a.Frameset:
p.addElement()
p.im = inFramesetIM
return true
case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
p.insertOpenElement(p.head)
defer p.oe.remove(p.head)
return inHeadIM(p)
case a.Head:
// Ignore the token.
return true
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Body, a.Html, a.Br:
// Drop down to creating an implied <body> tag.
case a.Template:
return inHeadIM(p)
default:
// Ignore the token.
return true
}
case CommentToken:
p.addChild(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
return true
case DoctypeToken:
// Ignore the token.
return true
}
p.parseImpliedToken(StartTagToken, a.Body, a.Body.String())
p.framesetOK = true
if p.tok.Type == ErrorToken {
// Stop parsing.
return true
}
return false
}
// copyAttributes copies attributes of src not found on dst to dst.
func copyAttributes(dst *Node, src Token) {
if len(src.Attr) == 0 {
return
}
attr := map[string]string{}
for _, t := range dst.Attr {
attr[t.Key] = t.Val
}
for _, t := range src.Attr {
if _, ok := attr[t.Key]; !ok {
dst.Attr = append(dst.Attr, t)
attr[t.Key] = t.Val
}
}
}
// Section 12.2.6.4.7.
func inBodyIM(p *parser) bool {
switch p.tok.Type {
case TextToken:
d := p.tok.Data
switch n := p.oe.top(); n.DataAtom {
case a.Pre, a.Listing:
if n.FirstChild == nil {
// Ignore a newline at the start of a <pre> block.
if d != "" && d[0] == '\r' {
d = d[1:]
}
if d != "" && d[0] == '\n' {
d = d[1:]
}
}
}
d = strings.Replace(d, "\x00", "", -1)
if d == "" {
return true
}
p.reconstructActiveFormattingElements()
p.addText(d)
if p.framesetOK && strings.TrimLeft(d, whitespace) != "" {
// There were non-whitespace characters inserted.
p.framesetOK = false
}
case StartTagToken:
switch p.tok.DataAtom {
case a.Html:
if p.oe.contains(a.Template) {
return true
}
copyAttributes(p.oe[0], p.tok)
case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
return inHeadIM(p)
case a.Body:
if p.oe.contains(a.Template) {
return true
}
if len(p.oe) >= 2 {
body := p.oe[1]
if body.Type == ElementNode && body.DataAtom == a.Body {
p.framesetOK = false
copyAttributes(body, p.tok)
}
}
case a.Frameset:
if !p.framesetOK || len(p.oe) < 2 || p.oe[1].DataAtom != a.Body {
// Ignore the token.
return true
}
body := p.oe[1]
if body.Parent != nil {
body.Parent.RemoveChild(body)
}
p.oe = p.oe[:1]
p.addElement()
p.im = inFramesetIM
return true
case a.Address, a.Article, a.Aside, a.Blockquote, a.Center, a.Details, a.Dialog, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Main, a.Menu, a.Nav, a.Ol, a.P, a.Search, a.Section, a.Summary, a.Ul:
p.popUntil(buttonScope, a.P)
p.addElement()
case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
p.popUntil(buttonScope, a.P)
switch n := p.top(); n.DataAtom {
case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
p.oe.pop()
}
p.addElement()
case a.Pre, a.Listing:
p.popUntil(buttonScope, a.P)
p.addElement()
// The newline, if any, will be dealt with by the TextToken case.
p.framesetOK = false
case a.Form:
if p.form != nil && !p.oe.contains(a.Template) {
// Ignore the token
return true
}
p.popUntil(buttonScope, a.P)
p.addElement()
if !p.oe.contains(a.Template) {
p.form = p.top()
}
case a.Li:
p.framesetOK = false
for i := len(p.oe) - 1; i >= 0; i-- {
node := p.oe[i]
switch node.DataAtom {
case a.Li:
p.oe = p.oe[:i]
case a.Address, a.Div, a.P:
continue
default:
if !isSpecialElement(node) {
continue
}
}
break
}
p.popUntil(buttonScope, a.P)
p.addElement()
case a.Dd, a.Dt:
p.framesetOK = false
for i := len(p.oe) - 1; i >= 0; i-- {
node := p.oe[i]
switch node.DataAtom {
case a.Dd, a.Dt:
p.oe = p.oe[:i]
case a.Address, a.Div, a.P:
continue
default:
if !isSpecialElement(node) {
continue
}
}
break
}
p.popUntil(buttonScope, a.P)
p.addElement()
case a.Plaintext:
p.popUntil(buttonScope, a.P)
p.addElement()
case a.Button:
p.popUntil(defaultScope, a.Button)
p.reconstructActiveFormattingElements()
p.addElement()
p.framesetOK = false
case a.A:
for i := len(p.afe) - 1; i >= 0 && p.afe[i].Type != scopeMarkerNode; i-- {
if n := p.afe[i]; n.Type == ElementNode && n.DataAtom == a.A {
p.inBodyEndTagFormatting(a.A, "a")
p.oe.remove(n)
p.afe.remove(n)
break
}
}
p.reconstructActiveFormattingElements()
p.addFormattingElement()
case a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
p.reconstructActiveFormattingElements()
p.addFormattingElement()
case a.Nobr:
p.reconstructActiveFormattingElements()
if p.elementInScope(defaultScope, a.Nobr) {
p.inBodyEndTagFormatting(a.Nobr, "nobr")
p.reconstructActiveFormattingElements()
}
p.addFormattingElement()
case a.Applet, a.Marquee, a.Object:
p.reconstructActiveFormattingElements()
p.addElement()
p.afe = append(p.afe, &scopeMarker)
p.framesetOK = false
case a.Table:
if !p.quirks {
p.popUntil(buttonScope, a.P)
}
p.addElement()
p.framesetOK = false
p.im = inTableIM
return true
case a.Area, a.Br, a.Embed, a.Img, a.Input, a.Keygen, a.Wbr:
p.reconstructActiveFormattingElements()
p.addElement()
p.oe.pop()
p.acknowledgeSelfClosingTag()
if p.tok.DataAtom == a.Input {
for _, t := range p.tok.Attr {
if t.Key == "type" {
if strings.EqualFold(t.Val, "hidden") {
// Skip setting framesetOK = false
return true
}
}
}
}
p.framesetOK = false
case a.Param, a.Source, a.Track:
p.addElement()
p.oe.pop()
p.acknowledgeSelfClosingTag()
case a.Hr:
p.popUntil(buttonScope, a.P)
p.addElement()
p.oe.pop()
p.acknowledgeSelfClosingTag()
p.framesetOK = false
case a.Image:
p.tok.DataAtom = a.Img
p.tok.Data = a.Img.String()
return false
case a.Textarea:
p.addElement()
p.setOriginalIM()
p.framesetOK = false
p.im = textIM
case a.Xmp:
p.popUntil(buttonScope, a.P)
p.reconstructActiveFormattingElements()
p.framesetOK = false
p.parseGenericRawTextElement()
case a.Iframe:
p.framesetOK = false
p.parseGenericRawTextElement()
case a.Noembed:
p.parseGenericRawTextElement()
case a.Noscript:
if p.scripting {
p.parseGenericRawTextElement()
return true
}
p.reconstructActiveFormattingElements()
p.addElement()
// Don't let the tokenizer go into raw text mode when scripting is disabled.
p.tokenizer.NextIsNotRawText()
case a.Select:
p.reconstructActiveFormattingElements()
p.addElement()
p.framesetOK = false
p.im = inSelectIM
return true
case a.Optgroup, a.Option:
if p.top().DataAtom == a.Option {
p.oe.pop()
}
p.reconstructActiveFormattingElements()
p.addElement()
case a.Rb, a.Rtc:
if p.elementInScope(defaultScope, a.Ruby) {
p.generateImpliedEndTags()
}
p.addElement()
case a.Rp, a.Rt:
if p.elementInScope(defaultScope, a.Ruby) {
p.generateImpliedEndTags("rtc")
}
p.addElement()
case a.Math, a.Svg:
p.reconstructActiveFormattingElements()
if p.tok.DataAtom == a.Math {
adjustAttributeNames(p.tok.Attr, mathMLAttributeAdjustments)
} else {
adjustAttributeNames(p.tok.Attr, svgAttributeAdjustments)
}
adjustForeignAttributes(p.tok.Attr)
p.addElement()
p.top().Namespace = p.tok.Data
if p.hasSelfClosingToken {
p.oe.pop()
p.acknowledgeSelfClosingTag()
}
return true
case a.Caption, a.Col, a.Colgroup, a.Frame, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
// Ignore the token.
default:
p.reconstructActiveFormattingElements()
p.addElement()
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Body:
if p.elementInScope(defaultScope, a.Body) {
p.im = afterBodyIM
}
case a.Html:
if p.elementInScope(defaultScope, a.Body) {
p.parseImpliedToken(EndTagToken, a.Body, a.Body.String())
return false
}
return true
case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dialog, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Main, a.Menu, a.Nav, a.Ol, a.Pre, a.Search, a.Section, a.Summary, a.Ul:
p.popUntil(defaultScope, p.tok.DataAtom)
case a.Form:
if p.oe.contains(a.Template) {
i := p.indexOfElementInScope(defaultScope, a.Form)
if i == -1 {
// Ignore the token.
return true
}
p.generateImpliedEndTags()
if p.oe[i].DataAtom != a.Form {
// Ignore the token.
return true
}
p.popUntil(defaultScope, a.Form)
} else {
node := p.form
p.form = nil
i := p.indexOfElementInScope(defaultScope, a.Form)
if node == nil || i == -1 || p.oe[i] != node {
// Ignore the token.
return true
}
p.generateImpliedEndTags()
p.oe.remove(node)
}
case a.P:
if !p.elementInScope(buttonScope, a.P) {
p.parseImpliedToken(StartTagToken, a.P, a.P.String())
}
p.popUntil(buttonScope, a.P)
case a.Li:
p.popUntil(listItemScope, a.Li)
case a.Dd, a.Dt:
p.popUntil(defaultScope, p.tok.DataAtom)
case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
p.popUntil(defaultScope, a.H1, a.H2, a.H3, a.H4, a.H5, a.H6)
case a.A, a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.Nobr, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
p.inBodyEndTagFormatting(p.tok.DataAtom, p.tok.Data)
case a.Applet, a.Marquee, a.Object:
if p.popUntil(defaultScope, p.tok.DataAtom) {
p.clearActiveFormattingElements()
}
case a.Br:
p.tok.Type = StartTagToken
return false
case a.Template:
return inHeadIM(p)
default:
p.inBodyEndTagOther(p.tok.DataAtom, p.tok.Data)
}
case CommentToken:
p.addChild(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
case ErrorToken:
// TODO: remove this divergence from the HTML5 spec.
if len(p.templateStack) > 0 {
p.im = inTemplateIM
return false
}
for _, e := range p.oe {
switch e.DataAtom {
case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb, a.Rp, a.Rt, a.Rtc, a.Tbody, a.Td, a.Tfoot, a.Th,
a.Thead, a.Tr, a.Body, a.Html:
default:
return true
}
}
}
return true
}
func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom, tagName string) {
// This is the "adoption agency" algorithm, described at
// https://html.spec.whatwg.org/multipage/syntax.html#adoptionAgency
// TODO: this is a fairly literal line-by-line translation of that algorithm.
// Once the code successfully parses the comprehensive test suite, we should
// refactor this code to be more idiomatic.
// Steps 1-2
if current := p.oe.top(); current.Data == tagName && p.afe.index(current) == -1 {
p.oe.pop()
return
}
// Steps 3-5. The outer loop.
for i := 0; i < 8; i++ {
// Step 6. Find the formatting element.
var formattingElement *Node
for j := len(p.afe) - 1; j >= 0; j-- {
if p.afe[j].Type == scopeMarkerNode {
break
}
if p.afe[j].DataAtom == tagAtom {
formattingElement = p.afe[j]
break
}
}
if formattingElement == nil {
p.inBodyEndTagOther(tagAtom, tagName)
return
}
// Step 7. Ignore the tag if formatting element is not in the stack of open elements.
feIndex := p.oe.index(formattingElement)
if feIndex == -1 {
p.afe.remove(formattingElement)
return
}
// Step 8. Ignore the tag if formatting element is not in the scope.
if !p.elementInScope(defaultScope, tagAtom) {
// Ignore the tag.
return
}
// Step 9. This step is omitted because it's just a parse error but no need to return.
// Steps 10-11. Find the furthest block.
var furthestBlock *Node
for _, e := range p.oe[feIndex:] {
if isSpecialElement(e) {
furthestBlock = e
break
}
}
if furthestBlock == nil {
e := p.oe.pop()
for e != formattingElement {
e = p.oe.pop()
}
p.afe.remove(e)
return
}
// Steps 12-13. Find the common ancestor and bookmark node.
commonAncestor := p.oe[feIndex-1]
bookmark := p.afe.index(formattingElement)
// Step 14. The inner loop. Find the lastNode to reparent.
lastNode := furthestBlock
node := furthestBlock
x := p.oe.index(node)
// Step 14.1.
j := 0
for {
// Step 14.2.
j++
// Step. 14.3.
x--
node = p.oe[x]
// Step 14.4. Go to the next step if node is formatting element.
if node == formattingElement {
break
}
// Step 14.5. Remove node from the list of active formatting elements if
// inner loop counter is greater than three and node is in the list of
// active formatting elements.
if ni := p.afe.index(node); j > 3 && ni > -1 {
p.afe.remove(node)
// If any element of the list of active formatting elements is removed,
// we need to take care whether bookmark should be decremented or not.
// This is because the value of bookmark may exceed the size of the
// list by removing elements from the list.
if ni <= bookmark {
bookmark--
}
continue
}
// Step 14.6. Continue the next inner loop if node is not in the list of
// active formatting elements.
if p.afe.index(node) == -1 {
p.oe.remove(node)
continue
}
// Step 14.7.
clone := node.clone()
p.afe[p.afe.index(node)] = clone
p.oe[p.oe.index(node)] = clone
node = clone
// Step 14.8.
if lastNode == furthestBlock {
bookmark = p.afe.index(node) + 1
}
// Step 14.9.
if lastNode.Parent != nil {
lastNode.Parent.RemoveChild(lastNode)
}
node.AppendChild(lastNode)
// Step 14.10.
lastNode = node
}
// Step 15. Reparent lastNode to the common ancestor,
// or for misnested table nodes, to the foster parent.
if lastNode.Parent != nil {
lastNode.Parent.RemoveChild(lastNode)
}
switch commonAncestor.DataAtom {
case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
p.fosterParent(lastNode)
default:
commonAncestor.AppendChild(lastNode)
}
// Steps 16-18. Reparent nodes from the furthest block's children
// to a clone of the formatting element.
clone := formattingElement.clone()
reparentChildren(clone, furthestBlock)
furthestBlock.AppendChild(clone)
// Step 19. Fix up the list of active formatting elements.
if oldLoc := p.afe.index(formattingElement); oldLoc != -1 && oldLoc < bookmark {
// Move the bookmark with the rest of the list.
bookmark--
}
p.afe.remove(formattingElement)
p.afe.insert(bookmark, clone)
// Step 20. Fix up the stack of open elements.
p.oe.remove(formattingElement)
p.oe.insert(p.oe.index(furthestBlock)+1, clone)
}
}
// inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM.
// "Any other end tag" handling from 12.2.6.5 The rules for parsing tokens in foreign content
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign
func (p *parser) inBodyEndTagOther(tagAtom a.Atom, tagName string) {
for i := len(p.oe) - 1; i >= 0; i-- {
// Two element nodes have the same tag if they have the same Data (a
// string-typed field). As an optimization, for common HTML tags, each
// Data string is assigned a unique, non-zero DataAtom (a uint32-typed
// field), since integer comparison is faster than string comparison.
// Uncommon (custom) tags get a zero DataAtom.
//
// The if condition here is equivalent to (p.oe[i].Data == tagName).
if (p.oe[i].DataAtom == tagAtom) &&
((tagAtom != 0) || (p.oe[i].Data == tagName)) {
p.oe = p.oe[:i]
break
}
if isSpecialElement(p.oe[i]) {
break
}
}
}
// Section 12.2.6.4.8.
func textIM(p *parser) bool {
switch p.tok.Type {
case ErrorToken:
p.oe.pop()
case TextToken:
d := p.tok.Data
if n := p.oe.top(); n.DataAtom == a.Textarea && n.FirstChild == nil {
// Ignore a newline at the start of a <textarea> block.
if d != "" && d[0] == '\r' {
d = d[1:]
}
if d != "" && d[0] == '\n' {
d = d[1:]
}
}
if d == "" {
return true
}
p.addText(d)
return true
case EndTagToken:
p.oe.pop()
}
p.im = p.originalIM
p.originalIM = nil
return p.tok.Type == EndTagToken
}
// Section 12.2.6.4.9.
func inTableIM(p *parser) bool {
switch p.tok.Type {
case TextToken:
p.tok.Data = strings.Replace(p.tok.Data, "\x00", "", -1)
switch p.oe.top().DataAtom {
case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
if strings.Trim(p.tok.Data, whitespace) == "" {
p.addText(p.tok.Data)
return true
}
}
case StartTagToken:
switch p.tok.DataAtom {
case a.Caption:
p.clearStackToContext(tableScope)
p.afe = append(p.afe, &scopeMarker)
p.addElement()
p.im = inCaptionIM
return true
case a.Colgroup:
p.clearStackToContext(tableScope)
p.addElement()
p.im = inColumnGroupIM
return true
case a.Col:
p.parseImpliedToken(StartTagToken, a.Colgroup, a.Colgroup.String())
return false
case a.Tbody, a.Tfoot, a.Thead:
p.clearStackToContext(tableScope)
p.addElement()
p.im = inTableBodyIM
return true
case a.Td, a.Th, a.Tr:
p.parseImpliedToken(StartTagToken, a.Tbody, a.Tbody.String())
return false
case a.Table:
if p.popUntil(tableScope, a.Table) {
p.resetInsertionMode()
return false
}
// Ignore the token.
return true
case a.Style, a.Script, a.Template:
return inHeadIM(p)
case a.Input:
for _, t := range p.tok.Attr {
if t.Key == "type" && strings.EqualFold(t.Val, "hidden") {
p.addElement()
p.oe.pop()
return true
}
}
// Otherwise drop down to the default action.
case a.Form:
if p.oe.contains(a.Template) || p.form != nil {
// Ignore the token.
return true
}
p.addElement()
p.form = p.oe.pop()
case a.Select:
p.reconstructActiveFormattingElements()
switch p.top().DataAtom {
case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
p.fosterParenting = true
}
p.addElement()
p.fosterParenting = false
p.framesetOK = false
p.im = inSelectInTableIM
return true
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Table:
if p.popUntil(tableScope, a.Table) {
p.resetInsertionMode()
return true
}
// Ignore the token.
return true
case a.Body, a.Caption, a.Col, a.Colgroup, a.Html, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
// Ignore the token.
return true
case a.Template:
return inHeadIM(p)
}
case CommentToken:
p.addChild(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
return true
case DoctypeToken:
// Ignore the token.
return true
case ErrorToken:
return inBodyIM(p)
}
p.fosterParenting = true
defer func() { p.fosterParenting = false }()
return inBodyIM(p)
}
// Section 12.2.6.4.11.
func inCaptionIM(p *parser) bool {
switch p.tok.Type {
case StartTagToken:
switch p.tok.DataAtom {
case a.Caption, a.Col, a.Colgroup, a.Tbody, a.Td, a.Tfoot, a.Thead, a.Tr:
if !p.popUntil(tableScope, a.Caption) {
// Ignore the token.
return true
}
p.clearActiveFormattingElements()
p.im = inTableIM
return false
case a.Select:
p.reconstructActiveFormattingElements()
p.addElement()
p.framesetOK = false
p.im = inSelectInTableIM
return true
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Caption:
if p.popUntil(tableScope, a.Caption) {
p.clearActiveFormattingElements()
p.im = inTableIM
}
return true
case a.Table:
if !p.popUntil(tableScope, a.Caption) {
// Ignore the token.
return true
}
p.clearActiveFormattingElements()
p.im = inTableIM
return false
case a.Body, a.Col, a.Colgroup, a.Html, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
// Ignore the token.
return true
}
}
return inBodyIM(p)
}
// Section 12.2.6.4.12.
func inColumnGroupIM(p *parser) bool {
switch p.tok.Type {
case TextToken:
s := strings.TrimLeft(p.tok.Data, whitespace)
if len(s) < len(p.tok.Data) {
// Add the initial whitespace to the current node.
p.addText(p.tok.Data[:len(p.tok.Data)-len(s)])
if s == "" {
return true
}
p.tok.Data = s
}
case CommentToken:
p.addChild(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
return true
case DoctypeToken:
// Ignore the token.
return true
case StartTagToken:
switch p.tok.DataAtom {
case a.Html:
return inBodyIM(p)
case a.Col:
p.addElement()
p.oe.pop()
p.acknowledgeSelfClosingTag()
return true
case a.Template:
return inHeadIM(p)
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Colgroup:
if p.oe.top().DataAtom == a.Colgroup {
p.oe.pop()
p.im = inTableIM
}
return true
case a.Col:
// Ignore the token.
return true
case a.Template:
return inHeadIM(p)
}
case ErrorToken:
return inBodyIM(p)
}
if p.oe.top().DataAtom != a.Colgroup {
return true
}
p.oe.pop()
p.im = inTableIM
return false
}
// Section 12.2.6.4.13.
func inTableBodyIM(p *parser) bool {
switch p.tok.Type {
case StartTagToken:
switch p.tok.DataAtom {
case a.Tr:
p.clearStackToContext(tableBodyScope)
p.addElement()
p.im = inRowIM
return true
case a.Td, a.Th:
p.parseImpliedToken(StartTagToken, a.Tr, a.Tr.String())
return false
case a.Caption, a.Col, a.Colgroup, a.Tbody, a.Tfoot, a.Thead:
if p.popUntil(tableScope, a.Tbody, a.Thead, a.Tfoot) {
p.im = inTableIM
return false
}
// Ignore the token.
return true
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Tbody, a.Tfoot, a.Thead:
if p.elementInScope(tableScope, p.tok.DataAtom) {
p.clearStackToContext(tableBodyScope)
p.oe.pop()
p.im = inTableIM
}
return true
case a.Table:
if p.popUntil(tableScope, a.Tbody, a.Thead, a.Tfoot) {
p.im = inTableIM
return false
}
// Ignore the token.
return true
case a.Body, a.Caption, a.Col, a.Colgroup, a.Html, a.Td, a.Th, a.Tr:
// Ignore the token.
return true
}
case CommentToken:
p.addChild(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
return true
}
return inTableIM(p)
}
// Section 13.2.6.4.14.
func inRowIM(p *parser) bool {
switch p.tok.Type {
case StartTagToken:
switch p.tok.DataAtom {
case a.Td, a.Th:
p.clearStackToContext(tableRowScope)
p.addElement()
p.afe = append(p.afe, &scopeMarker)
p.im = inCellIM
return true
case a.Caption, a.Col, a.Colgroup, a.Tbody, a.Tfoot, a.Thead, a.Tr:
if p.elementInScope(tableScope, a.Tr) {
p.clearStackToContext(tableRowScope)
p.oe.pop()
p.im = inTableBodyIM
return false
}
// Ignore the token.
return true
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Tr:
if p.elementInScope(tableScope, a.Tr) {
p.clearStackToContext(tableRowScope)
p.oe.pop()
p.im = inTableBodyIM
return true
}
// Ignore the token.
return true
case a.Table:
if p.elementInScope(tableScope, a.Tr) {
p.clearStackToContext(tableRowScope)
p.oe.pop()
p.im = inTableBodyIM
return false
}
// Ignore the token.
return true
case a.Tbody, a.Tfoot, a.Thead:
if p.elementInScope(tableScope, p.tok.DataAtom) && p.elementInScope(tableScope, a.Tr) {
p.clearStackToContext(tableRowScope)
p.oe.pop()
p.im = inTableBodyIM
return false
}
// Ignore the token.
return true
case a.Body, a.Caption, a.Col, a.Colgroup, a.Html, a.Td, a.Th:
// Ignore the token.
return true
}
}
return inTableIM(p)
}
// Section 12.2.6.4.15.
func inCellIM(p *parser) bool {
switch p.tok.Type {
case StartTagToken:
switch p.tok.DataAtom {
case a.Caption, a.Col, a.Colgroup, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
if p.popUntil(tableScope, a.Td, a.Th) {
// Close the cell and reprocess.
p.clearActiveFormattingElements()
p.im = inRowIM
return false
}
// Ignore the token.
return true
case a.Select:
p.reconstructActiveFormattingElements()
p.addElement()
p.framesetOK = false
p.im = inSelectInTableIM
return true
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Td, a.Th:
if !p.popUntil(tableScope, p.tok.DataAtom) {
// Ignore the token.
return true
}
p.clearActiveFormattingElements()
p.im = inRowIM
return true
case a.Body, a.Caption, a.Col, a.Colgroup, a.Html:
// Ignore the token.
return true
case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
if !p.elementInScope(tableScope, p.tok.DataAtom) {
// Ignore the token.
return true
}
// Close the cell and reprocess.
if p.popUntil(tableScope, a.Td, a.Th) {
p.clearActiveFormattingElements()
}
p.im = inRowIM
return false
}
}
return inBodyIM(p)
}
// Section 12.2.6.4.16.
func inSelectIM(p *parser) bool {
switch p.tok.Type {
case TextToken:
p.addText(strings.Replace(p.tok.Data, "\x00", "", -1))
case StartTagToken:
switch p.tok.DataAtom {
case a.Html:
return inBodyIM(p)
case a.Option:
if p.top().DataAtom == a.Option {
p.oe.pop()
}
p.addElement()
case a.Optgroup:
if p.top().DataAtom == a.Option {
p.oe.pop()
}
if p.top().DataAtom == a.Optgroup {
p.oe.pop()
}
p.addElement()
case a.Select:
if !p.popUntil(selectScope, a.Select) {
// Ignore the token.
return true
}
p.resetInsertionMode()
case a.Input, a.Keygen, a.Textarea:
if p.elementInScope(selectScope, a.Select) {
p.parseImpliedToken(EndTagToken, a.Select, a.Select.String())
return false
}
// In order to properly ignore <textarea>, we need to change the tokenizer mode.
p.tokenizer.NextIsNotRawText()
// Ignore the token.
return true
case a.Script, a.Template:
return inHeadIM(p)
case a.Iframe, a.Noembed, a.Noframes, a.Noscript, a.Plaintext, a.Style, a.Title, a.Xmp:
// Don't let the tokenizer go into raw text mode when there are raw tags
// to be ignored. These tags should be ignored from the tokenizer
// properly.
p.tokenizer.NextIsNotRawText()
// Ignore the token.
return true
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Option:
if p.top().DataAtom == a.Option {
p.oe.pop()
}
case a.Optgroup:
i := len(p.oe) - 1
if p.oe[i].DataAtom == a.Option {
i--
}
if p.oe[i].DataAtom == a.Optgroup {
p.oe = p.oe[:i]
}
case a.Select:
if !p.popUntil(selectScope, a.Select) {
// Ignore the token.
return true
}
p.resetInsertionMode()
case a.Template:
return inHeadIM(p)
}
case CommentToken:
p.addChild(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
case DoctypeToken:
// Ignore the token.
return true
case ErrorToken:
return inBodyIM(p)
}
return true
}
// Section 12.2.6.4.17.
func inSelectInTableIM(p *parser) bool {
switch p.tok.Type {
case StartTagToken, EndTagToken:
switch p.tok.DataAtom {
case a.Caption, a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr, a.Td, a.Th:
if p.tok.Type == EndTagToken && !p.elementInScope(tableScope, p.tok.DataAtom) {
// Ignore the token.
return true
}
// This is like p.popUntil(selectScope, a.Select), but it also
// matches <math select>, not just <select>. Matching the MathML
// tag is arguably incorrect (conceptually), but it mimics what
// Chromium does.
for i := len(p.oe) - 1; i >= 0; i-- {
if n := p.oe[i]; n.DataAtom == a.Select {
p.oe = p.oe[:i]
break
}
}
p.resetInsertionMode()
return false
}
}
return inSelectIM(p)
}
// Section 12.2.6.4.18.
func inTemplateIM(p *parser) bool {
switch p.tok.Type {
case TextToken, CommentToken, DoctypeToken:
return inBodyIM(p)
case StartTagToken:
switch p.tok.DataAtom {
case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
return inHeadIM(p)
case a.Caption, a.Colgroup, a.Tbody, a.Tfoot, a.Thead:
p.templateStack.pop()
p.templateStack = append(p.templateStack, inTableIM)
p.im = inTableIM
return false
case a.Col:
p.templateStack.pop()
p.templateStack = append(p.templateStack, inColumnGroupIM)
p.im = inColumnGroupIM
return false
case a.Tr:
p.templateStack.pop()
p.templateStack = append(p.templateStack, inTableBodyIM)
p.im = inTableBodyIM
return false
case a.Td, a.Th:
p.templateStack.pop()
p.templateStack = append(p.templateStack, inRowIM)
p.im = inRowIM
return false
default:
p.templateStack.pop()
p.templateStack = append(p.templateStack, inBodyIM)
p.im = inBodyIM
return false
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Template:
return inHeadIM(p)
default:
// Ignore the token.
return true
}
case ErrorToken:
if !p.oe.contains(a.Template) {
// Ignore the token.
return true
}
// TODO: remove this divergence from the HTML5 spec.
//
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
p.generateImpliedEndTags()
for i := len(p.oe) - 1; i >= 0; i-- {
if n := p.oe[i]; n.Namespace == "" && n.DataAtom == a.Template {
p.oe = p.oe[:i]
break
}
}
p.clearActiveFormattingElements()
p.templateStack.pop()
p.resetInsertionMode()
return false
}
return false
}
// Section 12.2.6.4.19.
func afterBodyIM(p *parser) bool {
switch p.tok.Type {
case ErrorToken:
// Stop parsing.
return true
case TextToken:
s := strings.TrimLeft(p.tok.Data, whitespace)
if len(s) == 0 {
// It was all whitespace.
return inBodyIM(p)
}
case StartTagToken:
if p.tok.DataAtom == a.Html {
return inBodyIM(p)
}
case EndTagToken:
if p.tok.DataAtom == a.Html {
if !p.fragment {
p.im = afterAfterBodyIM
}
return true
}
case CommentToken:
// The comment is attached to the <html> element.
if len(p.oe) < 1 || p.oe[0].DataAtom != a.Html {
panic("html: bad parser state: <html> element not found, in the after-body insertion mode")
}
p.oe[0].AppendChild(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
return true
}
p.im = inBodyIM
return false
}
// Section 12.2.6.4.20.
func inFramesetIM(p *parser) bool {
switch p.tok.Type {
case CommentToken:
p.addChild(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
case TextToken:
// Ignore all text but whitespace.
s := strings.Map(func(c rune) rune {
switch c {
case ' ', '\t', '\n', '\f', '\r':
return c
}
return -1
}, p.tok.Data)
if s != "" {
p.addText(s)
}
case StartTagToken:
switch p.tok.DataAtom {
case a.Html:
return inBodyIM(p)
case a.Frameset:
p.addElement()
case a.Frame:
p.addElement()
p.oe.pop()
p.acknowledgeSelfClosingTag()
case a.Noframes:
return inHeadIM(p)
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Frameset:
if p.oe.top().DataAtom != a.Html {
p.oe.pop()
if p.oe.top().DataAtom != a.Frameset {
p.im = afterFramesetIM
return true
}
}
}
default:
// Ignore the token.
}
return true
}
// Section 12.2.6.4.21.
func afterFramesetIM(p *parser) bool {
switch p.tok.Type {
case CommentToken:
p.addChild(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
case TextToken:
// Ignore all text but whitespace.
s := strings.Map(func(c rune) rune {
switch c {
case ' ', '\t', '\n', '\f', '\r':
return c
}
return -1
}, p.tok.Data)
if s != "" {
p.addText(s)
}
case StartTagToken:
switch p.tok.DataAtom {
case a.Html:
return inBodyIM(p)
case a.Noframes:
return inHeadIM(p)
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Html:
p.im = afterAfterFramesetIM
return true
}
default:
// Ignore the token.
}
return true
}
// Section 12.2.6.4.22.
func afterAfterBodyIM(p *parser) bool {
switch p.tok.Type {
case ErrorToken:
// Stop parsing.
return true
case TextToken:
s := strings.TrimLeft(p.tok.Data, whitespace)
if len(s) == 0 {
// It was all whitespace.
return inBodyIM(p)
}
case StartTagToken:
if p.tok.DataAtom == a.Html {
return inBodyIM(p)
}
case CommentToken:
p.doc.AppendChild(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
return true
case DoctypeToken:
return inBodyIM(p)
}
p.im = inBodyIM
return false
}
// Section 12.2.6.4.23.
func afterAfterFramesetIM(p *parser) bool {
switch p.tok.Type {
case CommentToken:
p.doc.AppendChild(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
case TextToken:
// Ignore all text but whitespace.
s := strings.Map(func(c rune) rune {
switch c {
case ' ', '\t', '\n', '\f', '\r':
return c
}
return -1
}, p.tok.Data)
if s != "" {
p.tok.Data = s
return inBodyIM(p)
}
case StartTagToken:
switch p.tok.DataAtom {
case a.Html:
return inBodyIM(p)
case a.Noframes:
return inHeadIM(p)
}
case DoctypeToken:
return inBodyIM(p)
default:
// Ignore the token.
}
return true
}
func ignoreTheRemainingTokens(p *parser) bool {
return true
}
const whitespaceOrNUL = whitespace + "\x00"
// Section 12.2.6.5
func parseForeignContent(p *parser) bool {
switch p.tok.Type {
case TextToken:
if p.framesetOK {
p.framesetOK = strings.TrimLeft(p.tok.Data, whitespaceOrNUL) == ""
}
p.tok.Data = strings.Replace(p.tok.Data, "\x00", "\ufffd", -1)
p.addText(p.tok.Data)
case CommentToken:
p.addChild(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
case StartTagToken:
if !p.fragment {
b := breakout[p.tok.Data]
if p.tok.DataAtom == a.Font {
loop:
for _, attr := range p.tok.Attr {
switch attr.Key {
case "color", "face", "size":
b = true
break loop
}
}
}
if b {
for i := len(p.oe) - 1; i >= 0; i-- {
n := p.oe[i]
if n.Namespace == "" || htmlIntegrationPoint(n) || mathMLTextIntegrationPoint(n) {
p.oe = p.oe[:i+1]
break
}
}
return false
}
}
current := p.adjustedCurrentNode()
switch current.Namespace {
case "math":
adjustAttributeNames(p.tok.Attr, mathMLAttributeAdjustments)
case "svg":
// Adjust SVG tag names. The tokenizer lower-cases tag names, but
// SVG wants e.g. "foreignObject" with a capital second "O".
if x := svgTagNameAdjustments[p.tok.Data]; x != "" {
p.tok.DataAtom = a.Lookup([]byte(x))
p.tok.Data = x
}
adjustAttributeNames(p.tok.Attr, svgAttributeAdjustments)
default:
panic("html: bad parser state: unexpected namespace")
}
adjustForeignAttributes(p.tok.Attr)
namespace := current.Namespace
p.addElement()
p.top().Namespace = namespace
if namespace != "" {
// Don't let the tokenizer go into raw text mode in foreign content
// (e.g. in an SVG <title> tag).
p.tokenizer.NextIsNotRawText()
}
if p.hasSelfClosingToken {
p.oe.pop()
p.acknowledgeSelfClosingTag()
}
case EndTagToken:
if strings.EqualFold(p.oe[len(p.oe)-1].Data, p.tok.Data) {
p.oe = p.oe[:len(p.oe)-1]
return true
}
for i := len(p.oe) - 1; i >= 0; i-- {
if strings.EqualFold(p.oe[i].Data, p.tok.Data) {
p.oe = p.oe[:i]
return true
}
if i > 0 && p.oe[i-1].Namespace == "" {
break
}
}
return p.im(p)
default:
// Ignore the token.
}
return true
}
// Section 12.2.4.2.
func (p *parser) adjustedCurrentNode() *Node {
if len(p.oe) == 1 && p.fragment && p.context != nil {
return p.context
}
return p.oe.top()
}
// Section 12.2.6.
func (p *parser) inForeignContent() bool {
if len(p.oe) == 0 {
return false
}
n := p.adjustedCurrentNode()
if n.Namespace == "" {
return false
}
if mathMLTextIntegrationPoint(n) {
if p.tok.Type == StartTagToken && p.tok.DataAtom != a.Mglyph && p.tok.DataAtom != a.Malignmark {
return false
}
if p.tok.Type == TextToken {
return false
}
}
if n.Namespace == "math" && n.DataAtom == a.AnnotationXml && p.tok.Type == StartTagToken && p.tok.DataAtom == a.Svg {
return false
}
if htmlIntegrationPoint(n) && (p.tok.Type == StartTagToken || p.tok.Type == TextToken) {
return false
}
if p.tok.Type == ErrorToken {
return false
}
return true
}
// parseImpliedToken parses a token as though it had appeared in the parser's
// input.
func (p *parser) parseImpliedToken(t TokenType, dataAtom a.Atom, data string) {
realToken, selfClosing := p.tok, p.hasSelfClosingToken
p.tok = Token{
Type: t,
DataAtom: dataAtom,
Data: data,
}
p.hasSelfClosingToken = false
p.parseCurrentToken()
p.tok, p.hasSelfClosingToken = realToken, selfClosing
}
// parseCurrentToken runs the current token through the parsing routines
// until it is consumed.
func (p *parser) parseCurrentToken() {
if p.tok.Type == SelfClosingTagToken {
p.hasSelfClosingToken = true
p.tok.Type = StartTagToken
}
consumed := false
for !consumed {
if p.inForeignContent() {
consumed = parseForeignContent(p)
} else {
consumed = p.im(p)
}
}
if p.hasSelfClosingToken {
// This is a parse error, but ignore it.
p.hasSelfClosingToken = false
}
}
func (p *parser) parse() (err error) {
defer func() {
if panicErr := recover(); panicErr != nil {
err = fmt.Errorf("%s", panicErr)
}
}()
// Iterate until EOF. Any other error will cause an early return.
for err != io.EOF {
// CDATA sections are allowed only in foreign content.
n := p.oe.top()
p.tokenizer.AllowCDATA(n != nil && n.Namespace != "")
// Read and parse the next token.
p.tokenizer.Next()
p.tok = p.tokenizer.Token()
if p.tok.Type == ErrorToken {
err = p.tokenizer.Err()
if err != nil && err != io.EOF {
return err
}
}
p.parseCurrentToken()
}
return nil
}
// Parse returns the parse tree for the HTML from the given Reader.
//
// It implements the HTML5 parsing algorithm
// (https://html.spec.whatwg.org/multipage/syntax.html#tree-construction),
// which is very complicated. The resultant tree can contain implicitly created
// nodes that have no explicit <tag> listed in r's data, and nodes' parents can
// differ from the nesting implied by a naive processing of start and end
// <tag>s. Conversely, explicit <tag>s in r's data can be silently dropped,
// with no corresponding node in the resulting tree.
//
// Parse will reject HTML that is nested deeper than 512 elements.
//
// The input is assumed to be UTF-8 encoded.
func Parse(r io.Reader) (*Node, error) {
return ParseWithOptions(r)
}
// ParseFragment parses a fragment of HTML and returns the nodes that were
// found. If the fragment is the InnerHTML for an existing element, pass that
// element in context.
//
// It has the same intricacies as Parse.
func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
return ParseFragmentWithOptions(r, context)
}
// ParseOption configures a parser.
type ParseOption func(p *parser)
// ParseOptionEnableScripting configures the scripting flag.
// https://html.spec.whatwg.org/multipage/webappapis.html#enabling-and-disabling-scripting
//
// By default, scripting is enabled.
func ParseOptionEnableScripting(enable bool) ParseOption {
return func(p *parser) {
p.scripting = enable
}
}
// ParseWithOptions is like Parse, with options.
func ParseWithOptions(r io.Reader, opts ...ParseOption) (*Node, error) {
p := &parser{
tokenizer: NewTokenizer(r),
doc: &Node{
Type: DocumentNode,
},
scripting: true,
framesetOK: true,
im: initialIM,
}
for _, f := range opts {
f(p)
}
if err := p.parse(); err != nil {
return nil, err
}
return p.doc, nil
}
// ParseFragmentWithOptions is like ParseFragment, with options.
func ParseFragmentWithOptions(r io.Reader, context *Node, opts ...ParseOption) ([]*Node, error) {
contextTag := ""
if context != nil {
if context.Type != ElementNode {
return nil, errors.New("html: ParseFragment of non-element Node")
}
// The next check isn't just context.DataAtom.String() == context.Data because
// it is valid to pass an element whose tag isn't a known atom. For example,
// DataAtom == 0 and Data = "tagfromthefuture" is perfectly consistent.
if context.DataAtom != a.Lookup([]byte(context.Data)) {
return nil, fmt.Errorf("html: inconsistent Node: DataAtom=%q, Data=%q", context.DataAtom, context.Data)
}
contextTag = context.DataAtom.String()
}
p := &parser{
doc: &Node{
Type: DocumentNode,
},
scripting: true,
fragment: true,
context: context,
}
if context != nil && context.Namespace != "" {
p.tokenizer = NewTokenizer(r)
} else {
p.tokenizer = NewTokenizerFragment(r, contextTag)
}
for _, f := range opts {
f(p)
}
root := &Node{
Type: ElementNode,
DataAtom: a.Html,
Data: a.Html.String(),
}
p.doc.AppendChild(root)
p.oe = nodeStack{root}
if context != nil && context.DataAtom == a.Template {
p.templateStack = append(p.templateStack, inTemplateIM)
}
p.resetInsertionMode()
for n := context; n != nil; n = n.Parent {
if n.Type == ElementNode && n.DataAtom == a.Form {
p.form = n
break
}
}
if err := p.parse(); err != nil {
return nil, err
}
parent := p.doc
if context != nil {
parent = root
}
var result []*Node
for c := parent.FirstChild; c != nil; {
next := c.NextSibling
parent.RemoveChild(c)
result = append(result, c)
c = next
}
return result, nil
}
// Copyright 2011 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 html
import (
"bufio"
"errors"
"fmt"
"io"
"strings"
)
type writer interface {
io.Writer
io.ByteWriter
WriteString(string) (int, error)
}
// Render renders the parse tree n to the given writer.
//
// Rendering is done on a 'best effort' basis: calling Parse on the output of
// Render will always result in something similar to the original tree, but it
// is not necessarily an exact clone unless the original tree was 'well-formed'.
// 'Well-formed' is not easily specified; the HTML5 specification is
// complicated.
//
// Calling Parse on arbitrary input typically results in a 'well-formed' parse
// tree. However, it is possible for Parse to yield a 'badly-formed' parse tree.
// For example, in a 'well-formed' parse tree, no <a> element is a child of
// another <a> element: parsing "<a><a>" results in two sibling elements.
// Similarly, in a 'well-formed' parse tree, no <a> element is a child of a
// <table> element: parsing "<p><table><a>" results in a <p> with two sibling
// children; the <a> is reparented to the <table>'s parent. However, calling
// Parse on "<a><table><a>" does not return an error, but the result has an <a>
// element with an <a> child, and is therefore not 'well-formed'.
//
// Programmatically constructed trees are typically also 'well-formed', but it
// is possible to construct a tree that looks innocuous but, when rendered and
// re-parsed, results in a different tree. A simple example is that a solitary
// text node would become a tree containing <html>, <head> and <body> elements.
// Another example is that the programmatic equivalent of "a<head>b</head>c"
// becomes "<html><head><head/><body>abc</body></html>".
func Render(w io.Writer, n *Node) error {
if x, ok := w.(writer); ok {
return render(x, n)
}
buf := bufio.NewWriter(w)
if err := render(buf, n); err != nil {
return err
}
return buf.Flush()
}
// plaintextAbort is returned from render1 when a <plaintext> element
// has been rendered. No more end tags should be rendered after that.
var plaintextAbort = errors.New("html: internal error (plaintext abort)")
func render(w writer, n *Node) error {
err := render1(w, n)
if err == plaintextAbort {
err = nil
}
return err
}
func render1(w writer, n *Node) error {
// Render non-element nodes; these are the easy cases.
switch n.Type {
case ErrorNode:
return errors.New("html: cannot render an ErrorNode node")
case TextNode:
return escape(w, n.Data)
case DocumentNode:
for c := n.FirstChild; c != nil; c = c.NextSibling {
if err := render1(w, c); err != nil {
return err
}
}
return nil
case ElementNode:
// No-op.
case CommentNode:
if _, err := w.WriteString("<!--"); err != nil {
return err
}
if err := escapeComment(w, n.Data); err != nil {
return err
}
if _, err := w.WriteString("-->"); err != nil {
return err
}
return nil
case DoctypeNode:
if _, err := w.WriteString("<!DOCTYPE "); err != nil {
return err
}
if err := escape(w, n.Data); err != nil {
return err
}
if n.Attr != nil {
var p, s string
for _, a := range n.Attr {
switch a.Key {
case "public":
p = a.Val
case "system":
s = a.Val
}
}
if p != "" {
if _, err := w.WriteString(" PUBLIC "); err != nil {
return err
}
if err := writeQuoted(w, p); err != nil {
return err
}
if s != "" {
if err := w.WriteByte(' '); err != nil {
return err
}
if err := writeQuoted(w, s); err != nil {
return err
}
}
} else if s != "" {
if _, err := w.WriteString(" SYSTEM "); err != nil {
return err
}
if err := writeQuoted(w, s); err != nil {
return err
}
}
}
return w.WriteByte('>')
case RawNode:
_, err := w.WriteString(n.Data)
return err
default:
return errors.New("html: unknown node type")
}
// Render the <xxx> opening tag.
if err := w.WriteByte('<'); err != nil {
return err
}
if _, err := w.WriteString(n.Data); err != nil {
return err
}
for _, a := range n.Attr {
if err := w.WriteByte(' '); err != nil {
return err
}
if a.Namespace != "" {
if _, err := w.WriteString(a.Namespace); err != nil {
return err
}
if err := w.WriteByte(':'); err != nil {
return err
}
}
if _, err := w.WriteString(a.Key); err != nil {
return err
}
if _, err := w.WriteString(`="`); err != nil {
return err
}
if err := escape(w, a.Val); err != nil {
return err
}
if err := w.WriteByte('"'); err != nil {
return err
}
}
if voidElements[n.Data] {
if n.FirstChild != nil {
return fmt.Errorf("html: void element <%s> has child nodes", n.Data)
}
_, err := w.WriteString("/>")
return err
}
if err := w.WriteByte('>'); err != nil {
return err
}
// Add initial newline where there is danger of a newline being ignored.
if c := n.FirstChild; c != nil && c.Type == TextNode && strings.HasPrefix(c.Data, "\n") {
switch n.Data {
case "pre", "listing", "textarea":
if err := w.WriteByte('\n'); err != nil {
return err
}
}
}
// Render any child nodes
if childTextNodesAreLiteral(n) {
for c := n.FirstChild; c != nil; c = c.NextSibling {
if c.Type == TextNode {
if _, err := w.WriteString(c.Data); err != nil {
return err
}
} else {
if err := render1(w, c); err != nil {
return err
}
}
}
if n.Data == "plaintext" {
// Don't render anything else. <plaintext> must be the
// last element in the file, with no closing tag.
return plaintextAbort
}
} else {
for c := n.FirstChild; c != nil; c = c.NextSibling {
if err := render1(w, c); err != nil {
return err
}
}
}
// Render the </xxx> closing tag.
if _, err := w.WriteString("</"); err != nil {
return err
}
if _, err := w.WriteString(n.Data); err != nil {
return err
}
return w.WriteByte('>')
}
func childTextNodesAreLiteral(n *Node) bool {
// Per WHATWG HTML 13.3, if the parent of the current node is a style,
// script, xmp, iframe, noembed, noframes, or plaintext element, and the
// current node is a text node, append the value of the node's data
// literally. The specification is not explicit about it, but we only
// enforce this if we are in the HTML namespace (i.e. when the namespace is
// "").
// NOTE: we also always include noscript elements, although the
// specification states that they should only be rendered as such if
// scripting is enabled for the node (which is not something we track).
if n.Namespace != "" {
return false
}
switch n.Data {
case "iframe", "noembed", "noframes", "noscript", "plaintext", "script", "style", "xmp":
return true
default:
return false
}
}
// writeQuoted writes s to w surrounded by quotes. Normally it will use double
// quotes, but if s contains a double quote, it will use single quotes.
// It is used for writing the identifiers in a doctype declaration.
// In valid HTML, they can't contain both types of quotes.
func writeQuoted(w writer, s string) error {
var q byte = '"'
if strings.Contains(s, `"`) {
q = '\''
}
if err := w.WriteByte(q); err != nil {
return err
}
if _, err := w.WriteString(s); err != nil {
return err
}
if err := w.WriteByte(q); err != nil {
return err
}
return nil
}
// Section 12.1.2, "Elements", gives this list of void elements. Void elements
// are those that can't have any contents.
var voidElements = map[string]bool{
"area": true,
"base": true,
"br": true,
"col": true,
"embed": true,
"hr": true,
"img": true,
"input": true,
"keygen": true, // "keygen" has been removed from the spec, but are kept here for backwards compatibility.
"link": true,
"meta": true,
"param": true,
"source": true,
"track": true,
"wbr": true,
}
// Copyright 2010 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 html
import (
"bytes"
"errors"
"io"
"strconv"
"strings"
"golang.org/x/net/html/atom"
)
// A TokenType is the type of a Token.
type TokenType uint32
const (
// ErrorToken means that an error occurred during tokenization.
ErrorToken TokenType = iota
// TextToken means a text node.
TextToken
// A StartTagToken looks like <a>.
StartTagToken
// An EndTagToken looks like </a>.
EndTagToken
// A SelfClosingTagToken tag looks like <br/>.
SelfClosingTagToken
// A CommentToken looks like <!--x-->.
CommentToken
// A DoctypeToken looks like <!DOCTYPE x>
DoctypeToken
)
// ErrBufferExceeded means that the buffering limit was exceeded.
var ErrBufferExceeded = errors.New("max buffer exceeded")
// String returns a string representation of the TokenType.
func (t TokenType) String() string {
switch t {
case ErrorToken:
return "Error"
case TextToken:
return "Text"
case StartTagToken:
return "StartTag"
case EndTagToken:
return "EndTag"
case SelfClosingTagToken:
return "SelfClosingTag"
case CommentToken:
return "Comment"
case DoctypeToken:
return "Doctype"
}
return "Invalid(" + strconv.Itoa(int(t)) + ")"
}
// An Attribute is an attribute namespace-key-value triple. Namespace is
// non-empty for foreign attributes like xlink, Key is alphabetic (and hence
// does not contain escapable characters like '&', '<' or '>'), and Val is
// unescaped (it looks like "a<b" rather than "a<b").
//
// Namespace is only used by the parser, not the tokenizer.
type Attribute struct {
Namespace, Key, Val string
}
// A Token consists of a TokenType and some Data (tag name for start and end
// tags, content for text, comments and doctypes). A tag Token may also contain
// a slice of Attributes. Data is unescaped for all Tokens (it looks like "a<b"
// rather than "a<b"). For tag Tokens, DataAtom is the atom for Data, or
// zero if Data is not a known tag name.
type Token struct {
Type TokenType
DataAtom atom.Atom
Data string
Attr []Attribute
}
// tagString returns a string representation of a tag Token's Data and Attr.
func (t Token) tagString() string {
if len(t.Attr) == 0 {
return t.Data
}
buf := bytes.NewBufferString(t.Data)
for _, a := range t.Attr {
buf.WriteByte(' ')
buf.WriteString(a.Key)
buf.WriteString(`="`)
escape(buf, a.Val)
buf.WriteByte('"')
}
return buf.String()
}
// String returns a string representation of the Token.
func (t Token) String() string {
switch t.Type {
case ErrorToken:
return ""
case TextToken:
return EscapeString(t.Data)
case StartTagToken:
return "<" + t.tagString() + ">"
case EndTagToken:
return "</" + t.tagString() + ">"
case SelfClosingTagToken:
return "<" + t.tagString() + "/>"
case CommentToken:
return "<!--" + escapeCommentString(t.Data) + "-->"
case DoctypeToken:
return "<!DOCTYPE " + EscapeString(t.Data) + ">"
}
return "Invalid(" + strconv.Itoa(int(t.Type)) + ")"
}
// span is a range of bytes in a Tokenizer's buffer. The start is inclusive,
// the end is exclusive.
type span struct {
start, end int
}
// A Tokenizer returns a stream of HTML Tokens.
type Tokenizer struct {
// r is the source of the HTML text.
r io.Reader
// tt is the TokenType of the current token.
tt TokenType
// err is the first error encountered during tokenization. It is possible
// for tt != Error && err != nil to hold: this means that Next returned a
// valid token but the subsequent Next call will return an error token.
// For example, if the HTML text input was just "plain", then the first
// Next call would set z.err to io.EOF but return a TextToken, and all
// subsequent Next calls would return an ErrorToken.
// err is never reset. Once it becomes non-nil, it stays non-nil.
err error
// readErr is the error returned by the io.Reader r. It is separate from
// err because it is valid for an io.Reader to return (n int, err1 error)
// such that n > 0 && err1 != nil, and callers should always process the
// n > 0 bytes before considering the error err1.
readErr error
// buf[raw.start:raw.end] holds the raw bytes of the current token.
// buf[raw.end:] is buffered input that will yield future tokens.
raw span
buf []byte
// maxBuf limits the data buffered in buf. A value of 0 means unlimited.
maxBuf int
// buf[data.start:data.end] holds the raw bytes of the current token's data:
// a text token's text, a tag token's tag name, etc.
data span
// pendingAttr is the attribute key and value currently being tokenized.
// When complete, pendingAttr is pushed onto attr. nAttrReturned is
// incremented on each call to TagAttr.
pendingAttr [2]span
attr [][2]span
nAttrReturned int
// rawTag is the "script" in "</script>" that closes the next token. If
// non-empty, the subsequent call to Next will return a raw or RCDATA text
// token: one that treats "<p>" as text instead of an element.
// rawTag's contents are lower-cased.
rawTag string
// textIsRaw is whether the current text token's data is not escaped.
textIsRaw bool
// convertNUL is whether NUL bytes in the current token's data should
// be converted into \ufffd replacement characters.
convertNUL bool
// allowCDATA is whether CDATA sections are allowed in the current context.
allowCDATA bool
}
// AllowCDATA sets whether or not the tokenizer recognizes <![CDATA[foo]]> as
// the text "foo". The default value is false, which means to recognize it as
// a bogus comment "<!-- [CDATA[foo]] -->" instead.
//
// Strictly speaking, an HTML5 compliant tokenizer should allow CDATA if and
// only if tokenizing foreign content, such as MathML and SVG. However,
// tracking foreign-contentness is difficult to do purely in the tokenizer,
// as opposed to the parser, due to HTML integration points: an <svg> element
// can contain a <foreignObject> that is foreign-to-SVG but not foreign-to-
// HTML. For strict compliance with the HTML5 tokenization algorithm, it is the
// responsibility of the user of a tokenizer to call AllowCDATA as appropriate.
// In practice, if using the tokenizer without caring whether MathML or SVG
// CDATA is text or comments, such as tokenizing HTML to find all the anchor
// text, it is acceptable to ignore this responsibility.
func (z *Tokenizer) AllowCDATA(allowCDATA bool) {
z.allowCDATA = allowCDATA
}
// NextIsNotRawText instructs the tokenizer that the next token should not be
// considered as 'raw text'. Some elements, such as script and title elements,
// normally require the next token after the opening tag to be 'raw text' that
// has no child elements. For example, tokenizing "<title>a<b>c</b>d</title>"
// yields a start tag token for "<title>", a text token for "a<b>c</b>d", and
// an end tag token for "</title>". There are no distinct start tag or end tag
// tokens for the "<b>" and "</b>".
//
// This tokenizer implementation will generally look for raw text at the right
// times. Strictly speaking, an HTML5 compliant tokenizer should not look for
// raw text if in foreign content: <title> generally needs raw text, but a
// <title> inside an <svg> does not. Another example is that a <textarea>
// generally needs raw text, but a <textarea> is not allowed as an immediate
// child of a <select>; in normal parsing, a <textarea> implies </select>, but
// one cannot close the implicit element when parsing a <select>'s InnerHTML.
// Similarly to AllowCDATA, tracking the correct moment to override raw-text-
// ness is difficult to do purely in the tokenizer, as opposed to the parser.
// For strict compliance with the HTML5 tokenization algorithm, it is the
// responsibility of the user of a tokenizer to call NextIsNotRawText as
// appropriate. In practice, like AllowCDATA, it is acceptable to ignore this
// responsibility for basic usage.
//
// Note that this 'raw text' concept is different from the one offered by the
// Tokenizer.Raw method.
func (z *Tokenizer) NextIsNotRawText() {
z.rawTag = ""
}
// Err returns the error associated with the most recent ErrorToken token.
// This is typically io.EOF, meaning the end of tokenization.
func (z *Tokenizer) Err() error {
if z.tt != ErrorToken {
return nil
}
return z.err
}
// readByte returns the next byte from the input stream, doing a buffered read
// from z.r into z.buf if necessary. z.buf[z.raw.start:z.raw.end] remains a contiguous byte
// slice that holds all the bytes read so far for the current token.
// It sets z.err if the underlying reader returns an error.
// Pre-condition: z.err == nil.
func (z *Tokenizer) readByte() byte {
if z.raw.end >= len(z.buf) {
// Our buffer is exhausted and we have to read from z.r. Check if the
// previous read resulted in an error.
if z.readErr != nil {
z.err = z.readErr
return 0
}
// We copy z.buf[z.raw.start:z.raw.end] to the beginning of z.buf. If the length
// z.raw.end - z.raw.start is more than half the capacity of z.buf, then we
// allocate a new buffer before the copy.
c := cap(z.buf)
d := z.raw.end - z.raw.start
var buf1 []byte
if 2*d > c {
buf1 = make([]byte, d, 2*c)
} else {
buf1 = z.buf[:d]
}
copy(buf1, z.buf[z.raw.start:z.raw.end])
if x := z.raw.start; x != 0 {
// Adjust the data/attr spans to refer to the same contents after the copy.
z.data.start -= x
z.data.end -= x
z.pendingAttr[0].start -= x
z.pendingAttr[0].end -= x
z.pendingAttr[1].start -= x
z.pendingAttr[1].end -= x
for i := range z.attr {
z.attr[i][0].start -= x
z.attr[i][0].end -= x
z.attr[i][1].start -= x
z.attr[i][1].end -= x
}
}
z.raw.start, z.raw.end, z.buf = 0, d, buf1[:d]
// Now that we have copied the live bytes to the start of the buffer,
// we read from z.r into the remainder.
var n int
n, z.readErr = readAtLeastOneByte(z.r, buf1[d:cap(buf1)])
if n == 0 {
z.err = z.readErr
return 0
}
z.buf = buf1[:d+n]
}
x := z.buf[z.raw.end]
z.raw.end++
if z.maxBuf > 0 && z.raw.end-z.raw.start >= z.maxBuf {
z.err = ErrBufferExceeded
return 0
}
return x
}
// Buffered returns a slice containing data buffered but not yet tokenized.
func (z *Tokenizer) Buffered() []byte {
return z.buf[z.raw.end:]
}
// readAtLeastOneByte wraps an io.Reader so that reading cannot return (0, nil).
// It returns io.ErrNoProgress if the underlying r.Read method returns (0, nil)
// too many times in succession.
func readAtLeastOneByte(r io.Reader, b []byte) (int, error) {
for i := 0; i < 100; i++ {
if n, err := r.Read(b); n != 0 || err != nil {
return n, err
}
}
return 0, io.ErrNoProgress
}
// skipWhiteSpace skips past any white space.
func (z *Tokenizer) skipWhiteSpace() {
if z.err != nil {
return
}
for {
c := z.readByte()
if z.err != nil {
return
}
switch c {
case ' ', '\n', '\r', '\t', '\f':
// No-op.
default:
z.raw.end--
return
}
}
}
// readRawOrRCDATA reads until the next "</foo>", where "foo" is z.rawTag and
// is typically something like "script" or "textarea".
func (z *Tokenizer) readRawOrRCDATA() {
if z.rawTag == "script" {
z.readScript()
z.textIsRaw = true
z.rawTag = ""
return
}
loop:
for {
c := z.readByte()
if z.err != nil {
break loop
}
if c != '<' {
continue loop
}
c = z.readByte()
if z.err != nil {
break loop
}
if c != '/' {
z.raw.end--
continue loop
}
if z.readRawEndTag() || z.err != nil {
break loop
}
}
z.data.end = z.raw.end
// A textarea's or title's RCDATA can contain escaped entities.
z.textIsRaw = z.rawTag != "textarea" && z.rawTag != "title"
z.rawTag = ""
}
// readRawEndTag attempts to read a tag like "</foo>", where "foo" is z.rawTag.
// If it succeeds, it backs up the input position to reconsume the tag and
// returns true. Otherwise it returns false. The opening "</" has already been
// consumed.
func (z *Tokenizer) readRawEndTag() bool {
for i := 0; i < len(z.rawTag); i++ {
c := z.readByte()
if z.err != nil {
return false
}
if c != z.rawTag[i] && c != z.rawTag[i]-('a'-'A') {
z.raw.end--
return false
}
}
c := z.readByte()
if z.err != nil {
return false
}
switch c {
case ' ', '\n', '\r', '\t', '\f', '/', '>':
// The 3 is 2 for the leading "</" plus 1 for the trailing character c.
z.raw.end -= 3 + len(z.rawTag)
return true
}
z.raw.end--
return false
}
// readScript reads until the next </script> tag, following the byzantine
// rules for escaping/hiding the closing tag.
func (z *Tokenizer) readScript() {
defer func() {
z.data.end = z.raw.end
}()
var c byte
scriptData:
c = z.readByte()
if z.err != nil {
return
}
if c == '<' {
goto scriptDataLessThanSign
}
goto scriptData
scriptDataLessThanSign:
c = z.readByte()
if z.err != nil {
return
}
switch c {
case '/':
goto scriptDataEndTagOpen
case '!':
goto scriptDataEscapeStart
}
z.raw.end--
goto scriptData
scriptDataEndTagOpen:
if z.readRawEndTag() || z.err != nil {
return
}
goto scriptData
scriptDataEscapeStart:
c = z.readByte()
if z.err != nil {
return
}
if c == '-' {
goto scriptDataEscapeStartDash
}
z.raw.end--
goto scriptData
scriptDataEscapeStartDash:
c = z.readByte()
if z.err != nil {
return
}
if c == '-' {
goto scriptDataEscapedDashDash
}
z.raw.end--
goto scriptData
scriptDataEscaped:
c = z.readByte()
if z.err != nil {
return
}
switch c {
case '-':
goto scriptDataEscapedDash
case '<':
goto scriptDataEscapedLessThanSign
}
goto scriptDataEscaped
scriptDataEscapedDash:
c = z.readByte()
if z.err != nil {
return
}
switch c {
case '-':
goto scriptDataEscapedDashDash
case '<':
goto scriptDataEscapedLessThanSign
}
goto scriptDataEscaped
scriptDataEscapedDashDash:
c = z.readByte()
if z.err != nil {
return
}
switch c {
case '-':
goto scriptDataEscapedDashDash
case '<':
goto scriptDataEscapedLessThanSign
case '>':
goto scriptData
}
goto scriptDataEscaped
scriptDataEscapedLessThanSign:
c = z.readByte()
if z.err != nil {
return
}
if c == '/' {
goto scriptDataEscapedEndTagOpen
}
if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' {
goto scriptDataDoubleEscapeStart
}
z.raw.end--
goto scriptData
scriptDataEscapedEndTagOpen:
if z.readRawEndTag() || z.err != nil {
return
}
goto scriptDataEscaped
scriptDataDoubleEscapeStart:
z.raw.end--
for i := 0; i < len("script"); i++ {
c = z.readByte()
if z.err != nil {
return
}
if c != "script"[i] && c != "SCRIPT"[i] {
z.raw.end--
goto scriptDataEscaped
}
}
c = z.readByte()
if z.err != nil {
return
}
switch c {
case ' ', '\n', '\r', '\t', '\f', '/', '>':
goto scriptDataDoubleEscaped
}
z.raw.end--
goto scriptDataEscaped
scriptDataDoubleEscaped:
c = z.readByte()
if z.err != nil {
return
}
switch c {
case '-':
goto scriptDataDoubleEscapedDash
case '<':
goto scriptDataDoubleEscapedLessThanSign
}
goto scriptDataDoubleEscaped
scriptDataDoubleEscapedDash:
c = z.readByte()
if z.err != nil {
return
}
switch c {
case '-':
goto scriptDataDoubleEscapedDashDash
case '<':
goto scriptDataDoubleEscapedLessThanSign
}
goto scriptDataDoubleEscaped
scriptDataDoubleEscapedDashDash:
c = z.readByte()
if z.err != nil {
return
}
switch c {
case '-':
goto scriptDataDoubleEscapedDashDash
case '<':
goto scriptDataDoubleEscapedLessThanSign
case '>':
goto scriptData
}
goto scriptDataDoubleEscaped
scriptDataDoubleEscapedLessThanSign:
c = z.readByte()
if z.err != nil {
return
}
if c == '/' {
goto scriptDataDoubleEscapeEnd
}
z.raw.end--
goto scriptDataDoubleEscaped
scriptDataDoubleEscapeEnd:
if z.readRawEndTag() {
z.raw.end += len("</script>")
goto scriptDataEscaped
}
if z.err != nil {
return
}
goto scriptDataDoubleEscaped
}
// readComment reads the next comment token starting with "<!--". The opening
// "<!--" has already been consumed.
func (z *Tokenizer) readComment() {
// When modifying this function, consider manually increasing the
// maxSuffixLen constant in func TestComments, from 6 to e.g. 9 or more.
// That increase should only be temporary, not committed, as it
// exponentially affects the test running time.
z.data.start = z.raw.end
defer func() {
if z.data.end < z.data.start {
// It's a comment with no data, like <!-->.
z.data.end = z.data.start
}
}()
var dashCount int
beginning := true
for {
c := z.readByte()
if z.err != nil {
z.data.end = z.calculateAbruptCommentDataEnd()
return
}
switch c {
case '-':
dashCount++
continue
case '>':
if dashCount >= 2 || beginning {
z.data.end = z.raw.end - len("-->")
return
}
case '!':
if dashCount >= 2 {
c = z.readByte()
if z.err != nil {
z.data.end = z.calculateAbruptCommentDataEnd()
return
} else if c == '>' {
z.data.end = z.raw.end - len("--!>")
return
} else if c == '-' {
dashCount = 1
beginning = false
continue
}
}
}
dashCount = 0
beginning = false
}
}
func (z *Tokenizer) calculateAbruptCommentDataEnd() int {
raw := z.Raw()
const prefixLen = len("<!--")
if len(raw) >= prefixLen {
raw = raw[prefixLen:]
if hasSuffix(raw, "--!") {
return z.raw.end - 3
} else if hasSuffix(raw, "--") {
return z.raw.end - 2
} else if hasSuffix(raw, "-") {
return z.raw.end - 1
}
}
return z.raw.end
}
func hasSuffix(b []byte, suffix string) bool {
if len(b) < len(suffix) {
return false
}
b = b[len(b)-len(suffix):]
for i := range b {
if b[i] != suffix[i] {
return false
}
}
return true
}
// readUntilCloseAngle reads until the next ">".
func (z *Tokenizer) readUntilCloseAngle() {
z.data.start = z.raw.end
for {
c := z.readByte()
if z.err != nil {
z.data.end = z.raw.end
return
}
if c == '>' {
z.data.end = z.raw.end - len(">")
return
}
}
}
// readMarkupDeclaration reads the next token starting with "<!". It might be
// a "<!--comment-->", a "<!DOCTYPE foo>", a "<![CDATA[section]]>" or
// "<!a bogus comment". The opening "<!" has already been consumed.
func (z *Tokenizer) readMarkupDeclaration() TokenType {
z.data.start = z.raw.end
var c [2]byte
for i := 0; i < 2; i++ {
c[i] = z.readByte()
if z.err != nil {
z.data.end = z.raw.end
return CommentToken
}
}
if c[0] == '-' && c[1] == '-' {
z.readComment()
return CommentToken
}
z.raw.end -= 2
if z.readDoctype() {
return DoctypeToken
}
if z.allowCDATA && z.readCDATA() {
z.convertNUL = true
return TextToken
}
// It's a bogus comment.
z.readUntilCloseAngle()
return CommentToken
}
// readDoctype attempts to read a doctype declaration and returns true if
// successful. The opening "<!" has already been consumed.
func (z *Tokenizer) readDoctype() bool {
const s = "DOCTYPE"
for i := 0; i < len(s); i++ {
c := z.readByte()
if z.err != nil {
z.data.end = z.raw.end
return false
}
if c != s[i] && c != s[i]+('a'-'A') {
// Back up to read the fragment of "DOCTYPE" again.
z.raw.end = z.data.start
return false
}
}
if z.skipWhiteSpace(); z.err != nil {
z.data.start = z.raw.end
z.data.end = z.raw.end
return true
}
z.readUntilCloseAngle()
return true
}
// readCDATA attempts to read a CDATA section and returns true if
// successful. The opening "<!" has already been consumed.
func (z *Tokenizer) readCDATA() bool {
const s = "[CDATA["
for i := 0; i < len(s); i++ {
c := z.readByte()
if z.err != nil {
z.data.end = z.raw.end
return false
}
if c != s[i] {
// Back up to read the fragment of "[CDATA[" again.
z.raw.end = z.data.start
return false
}
}
z.data.start = z.raw.end
brackets := 0
for {
c := z.readByte()
if z.err != nil {
z.data.end = z.raw.end
return true
}
switch c {
case ']':
brackets++
case '>':
if brackets >= 2 {
z.data.end = z.raw.end - len("]]>")
return true
}
brackets = 0
default:
brackets = 0
}
}
}
// startTagIn returns whether the start tag in z.buf[z.data.start:z.data.end]
// case-insensitively matches any element of ss.
func (z *Tokenizer) startTagIn(ss ...string) bool {
loop:
for _, s := range ss {
if z.data.end-z.data.start != len(s) {
continue loop
}
for i := 0; i < len(s); i++ {
c := z.buf[z.data.start+i]
if 'A' <= c && c <= 'Z' {
c += 'a' - 'A'
}
if c != s[i] {
continue loop
}
}
return true
}
return false
}
// readStartTag reads the next start tag token. The opening "<a" has already
// been consumed, where 'a' means anything in [A-Za-z].
func (z *Tokenizer) readStartTag() TokenType {
z.readTag(true)
if z.err != nil {
return ErrorToken
}
// Several tags flag the tokenizer's next token as raw.
c, raw := z.buf[z.data.start], false
if 'A' <= c && c <= 'Z' {
c += 'a' - 'A'
}
switch c {
case 'i':
raw = z.startTagIn("iframe")
case 'n':
raw = z.startTagIn("noembed", "noframes", "noscript")
case 'p':
raw = z.startTagIn("plaintext")
case 's':
raw = z.startTagIn("script", "style")
case 't':
raw = z.startTagIn("textarea", "title")
case 'x':
raw = z.startTagIn("xmp")
}
if raw {
z.rawTag = strings.ToLower(string(z.buf[z.data.start:z.data.end]))
}
// Look for a self-closing token (e.g. <br/>).
//
// Originally, we did this by just checking that the last character of the
// tag (ignoring the closing bracket) was a solidus (/) character, but this
// is not always accurate.
//
// We need to be careful that we don't misinterpret a non-self-closing tag
// as self-closing, as can happen if the tag contains unquoted attribute
// values (i.e. <p a=/>).
//
// To avoid this, we check that the last non-bracket character of the tag
// (z.raw.end-2) isn't the same character as the last non-quote character of
// the last attribute of the tag (z.pendingAttr[1].end-1), if the tag has
// attributes.
nAttrs := len(z.attr)
if z.err == nil && z.buf[z.raw.end-2] == '/' && (nAttrs == 0 || z.raw.end-2 != z.attr[nAttrs-1][1].end-1) {
return SelfClosingTagToken
}
return StartTagToken
}
// readTag reads the next tag token and its attributes. If saveAttr, those
// attributes are saved in z.attr, otherwise z.attr is set to an empty slice.
// The opening "<a" or "</a" has already been consumed, where 'a' means anything
// in [A-Za-z].
func (z *Tokenizer) readTag(saveAttr bool) {
z.attr = z.attr[:0]
z.nAttrReturned = 0
// Read the tag name and attribute key/value pairs.
z.readTagName()
if z.skipWhiteSpace(); z.err != nil {
return
}
for {
c := z.readByte()
if z.err != nil || c == '>' {
break
}
z.raw.end--
z.readTagAttrKey()
z.readTagAttrVal()
// Save pendingAttr if saveAttr and that attribute has a non-empty key.
if saveAttr && z.pendingAttr[0].start != z.pendingAttr[0].end {
z.attr = append(z.attr, z.pendingAttr)
}
if z.skipWhiteSpace(); z.err != nil {
break
}
}
}
// readTagName sets z.data to the "div" in "<div k=v>". The reader (z.raw.end)
// is positioned such that the first byte of the tag name (the "d" in "<div")
// has already been consumed.
func (z *Tokenizer) readTagName() {
z.data.start = z.raw.end - 1
for {
c := z.readByte()
if z.err != nil {
z.data.end = z.raw.end
return
}
switch c {
case ' ', '\n', '\r', '\t', '\f':
z.data.end = z.raw.end - 1
return
case '/', '>':
z.raw.end--
z.data.end = z.raw.end
return
}
}
}
// readTagAttrKey sets z.pendingAttr[0] to the "k" in "<div k=v>".
// Precondition: z.err == nil.
func (z *Tokenizer) readTagAttrKey() {
z.pendingAttr[0].start = z.raw.end
for {
c := z.readByte()
if z.err != nil {
z.pendingAttr[0].end = z.raw.end
return
}
switch c {
case '=':
if z.pendingAttr[0].start+1 == z.raw.end {
// WHATWG 13.2.5.32, if we see an equals sign before the attribute name
// begins, we treat it as a character in the attribute name and continue.
continue
}
fallthrough
case ' ', '\n', '\r', '\t', '\f', '/', '>':
// WHATWG 13.2.5.33 Attribute name state
// We need to reconsume the char in the after attribute name state to support the / character
z.raw.end--
z.pendingAttr[0].end = z.raw.end
return
}
}
}
// readTagAttrVal sets z.pendingAttr[1] to the "v" in "<div k=v>".
func (z *Tokenizer) readTagAttrVal() {
z.pendingAttr[1].start = z.raw.end
z.pendingAttr[1].end = z.raw.end
if z.skipWhiteSpace(); z.err != nil {
return
}
c := z.readByte()
if z.err != nil {
return
}
if c == '/' {
// WHATWG 13.2.5.34 After attribute name state
// U+002F SOLIDUS (/) - Switch to the self-closing start tag state.
return
}
if c != '=' {
z.raw.end--
return
}
if z.skipWhiteSpace(); z.err != nil {
return
}
quote := z.readByte()
if z.err != nil {
return
}
switch quote {
case '>':
z.raw.end--
return
case '\'', '"':
z.pendingAttr[1].start = z.raw.end
for {
c := z.readByte()
if z.err != nil {
z.pendingAttr[1].end = z.raw.end
return
}
if c == quote {
z.pendingAttr[1].end = z.raw.end - 1
return
}
}
default:
z.pendingAttr[1].start = z.raw.end - 1
for {
c := z.readByte()
if z.err != nil {
z.pendingAttr[1].end = z.raw.end
return
}
switch c {
case ' ', '\n', '\r', '\t', '\f':
z.pendingAttr[1].end = z.raw.end - 1
return
case '>':
z.raw.end--
z.pendingAttr[1].end = z.raw.end
return
}
}
}
}
// Next scans the next token and returns its type.
func (z *Tokenizer) Next() TokenType {
z.raw.start = z.raw.end
z.data.start = z.raw.end
z.data.end = z.raw.end
if z.err != nil {
z.tt = ErrorToken
return z.tt
}
if z.rawTag != "" {
if z.rawTag == "plaintext" {
// Read everything up to EOF.
for z.err == nil {
z.readByte()
}
z.data.end = z.raw.end
z.textIsRaw = true
} else {
z.readRawOrRCDATA()
}
if z.data.end > z.data.start {
z.tt = TextToken
z.convertNUL = true
return z.tt
}
}
z.textIsRaw = false
z.convertNUL = false
loop:
for {
c := z.readByte()
if z.err != nil {
break loop
}
if c != '<' {
continue loop
}
// Check if the '<' we have just read is part of a tag, comment
// or doctype. If not, it's part of the accumulated text token.
c = z.readByte()
if z.err != nil {
break loop
}
var tokenType TokenType
switch {
case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
tokenType = StartTagToken
case c == '/':
tokenType = EndTagToken
case c == '!' || c == '?':
// We use CommentToken to mean any of "<!--actual comments-->",
// "<!DOCTYPE declarations>" and "<?xml processing instructions?>".
tokenType = CommentToken
default:
// Reconsume the current character.
z.raw.end--
continue
}
// We have a non-text token, but we might have accumulated some text
// before that. If so, we return the text first, and return the non-
// text token on the subsequent call to Next.
if x := z.raw.end - len("<a"); z.raw.start < x {
z.raw.end = x
z.data.end = x
z.tt = TextToken
return z.tt
}
switch tokenType {
case StartTagToken:
z.tt = z.readStartTag()
return z.tt
case EndTagToken:
c = z.readByte()
if z.err != nil {
break loop
}
if c == '>' {
// "</>" does not generate a token at all. Generate an empty comment
// to allow passthrough clients to pick up the data using Raw.
// Reset the tokenizer state and start again.
z.tt = CommentToken
return z.tt
}
if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' {
z.readTag(false)
if z.err != nil {
z.tt = ErrorToken
} else {
z.tt = EndTagToken
}
return z.tt
}
z.raw.end--
z.readUntilCloseAngle()
z.tt = CommentToken
return z.tt
case CommentToken:
if c == '!' {
z.tt = z.readMarkupDeclaration()
return z.tt
}
z.raw.end--
z.readUntilCloseAngle()
z.tt = CommentToken
return z.tt
}
}
if z.raw.start < z.raw.end {
z.data.end = z.raw.end
z.tt = TextToken
return z.tt
}
z.tt = ErrorToken
return z.tt
}
// Raw returns the unmodified text of the current token. Calling Next, Token,
// Text, TagName or TagAttr may change the contents of the returned slice.
//
// The token stream's raw bytes partition the byte stream (up until an
// ErrorToken). There are no overlaps or gaps between two consecutive token's
// raw bytes. One implication is that the byte offset of the current token is
// the sum of the lengths of all previous tokens' raw bytes.
func (z *Tokenizer) Raw() []byte {
return z.buf[z.raw.start:z.raw.end]
}
// convertNewlines converts "\r" and "\r\n" in s to "\n".
// The conversion happens in place, but the resulting slice may be shorter.
func convertNewlines(s []byte) []byte {
for i, c := range s {
if c != '\r' {
continue
}
src := i + 1
if src >= len(s) || s[src] != '\n' {
s[i] = '\n'
continue
}
dst := i
for src < len(s) {
if s[src] == '\r' {
if src+1 < len(s) && s[src+1] == '\n' {
src++
}
s[dst] = '\n'
} else {
s[dst] = s[src]
}
src++
dst++
}
return s[:dst]
}
return s
}
var (
nul = []byte("\x00")
replacement = []byte("\ufffd")
)
// Text returns the unescaped text of a text, comment or doctype token. The
// contents of the returned slice may change on the next call to Next.
func (z *Tokenizer) Text() []byte {
switch z.tt {
case TextToken, CommentToken, DoctypeToken:
s := z.buf[z.data.start:z.data.end]
z.data.start = z.raw.end
z.data.end = z.raw.end
s = convertNewlines(s)
if (z.convertNUL || z.tt == CommentToken) && bytes.Contains(s, nul) {
s = bytes.Replace(s, nul, replacement, -1)
}
if !z.textIsRaw {
s = unescape(s, false)
}
return s
}
return nil
}
// TagName returns the lower-cased name of a tag token (the `img` out of
// `<IMG SRC="foo">`) and whether the tag has attributes.
// The contents of the returned slice may change on the next call to Next.
func (z *Tokenizer) TagName() (name []byte, hasAttr bool) {
if z.data.start < z.data.end {
switch z.tt {
case StartTagToken, EndTagToken, SelfClosingTagToken:
s := z.buf[z.data.start:z.data.end]
z.data.start = z.raw.end
z.data.end = z.raw.end
return lower(s), z.nAttrReturned < len(z.attr)
}
}
return nil, false
}
// TagAttr returns the lower-cased key and unescaped value of the next unparsed
// attribute for the current tag token and whether there are more attributes.
// The contents of the returned slices may change on the next call to Next.
func (z *Tokenizer) TagAttr() (key, val []byte, moreAttr bool) {
if z.nAttrReturned < len(z.attr) {
switch z.tt {
case StartTagToken, SelfClosingTagToken:
x := z.attr[z.nAttrReturned]
z.nAttrReturned++
key = z.buf[x[0].start:x[0].end]
val = z.buf[x[1].start:x[1].end]
return lower(key), unescape(convertNewlines(val), true), z.nAttrReturned < len(z.attr)
}
}
return nil, nil, false
}
// Token returns the current Token. The result's Data and Attr values remain
// valid after subsequent Next calls.
func (z *Tokenizer) Token() Token {
t := Token{Type: z.tt}
switch z.tt {
case TextToken, CommentToken, DoctypeToken:
t.Data = string(z.Text())
case StartTagToken, SelfClosingTagToken, EndTagToken:
name, moreAttr := z.TagName()
for moreAttr {
var key, val []byte
key, val, moreAttr = z.TagAttr()
t.Attr = append(t.Attr, Attribute{"", atom.String(key), string(val)})
}
if a := atom.Lookup(name); a != 0 {
t.DataAtom, t.Data = a, a.String()
} else {
t.DataAtom, t.Data = 0, string(name)
}
}
return t
}
// SetMaxBuf sets a limit on the amount of data buffered during tokenization.
// A value of 0 means unlimited.
func (z *Tokenizer) SetMaxBuf(n int) {
z.maxBuf = n
}
// NewTokenizer returns a new HTML Tokenizer for the given Reader.
// The input is assumed to be UTF-8 encoded.
func NewTokenizer(r io.Reader) *Tokenizer {
return NewTokenizerFragment(r, "")
}
// NewTokenizerFragment returns a new HTML Tokenizer for the given Reader, for
// tokenizing an existing element's InnerHTML fragment. contextTag is that
// element's tag, such as "div" or "iframe".
//
// For example, how the InnerHTML "a<b" is tokenized depends on whether it is
// for a <p> tag or a <script> tag.
//
// The input is assumed to be UTF-8 encoded.
func NewTokenizerFragment(r io.Reader, contextTag string) *Tokenizer {
z := &Tokenizer{
r: r,
buf: make([]byte, 0, 4096),
}
if contextTag != "" {
switch s := strings.ToLower(contextTag); s {
case "iframe", "noembed", "noframes", "noscript", "plaintext", "script", "style", "title", "textarea", "xmp":
z.rawTag = s
}
}
return z
}
// Copyright 2018 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 httpguts provides functions implementing various details
// of the HTTP specification.
//
// This package is shared by the standard library (which vendors it)
// and x/net/http2. It comes with no API stability promise.
package httpguts
import (
"net/textproto"
"strings"
)
// ValidTrailerHeader reports whether name is a valid header field name to appear
// in trailers.
// See RFC 7230, Section 4.1.2
func ValidTrailerHeader(name string) bool {
name = textproto.CanonicalMIMEHeaderKey(name)
if strings.HasPrefix(name, "If-") || badTrailer[name] {
return false
}
return true
}
var badTrailer = map[string]bool{
"Authorization": true,
"Cache-Control": true,
"Connection": true,
"Content-Encoding": true,
"Content-Length": true,
"Content-Range": true,
"Content-Type": true,
"Expect": true,
"Host": true,
"Keep-Alive": true,
"Max-Forwards": true,
"Pragma": true,
"Proxy-Authenticate": true,
"Proxy-Authorization": true,
"Proxy-Connection": true,
"Range": true,
"Realm": true,
"Te": true,
"Trailer": true,
"Transfer-Encoding": true,
"Www-Authenticate": true,
}
// 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.
package httpguts
import (
"net"
"strings"
"unicode/utf8"
"golang.org/x/net/idna"
)
var isTokenTable = [256]bool{
'!': true,
'#': true,
'$': true,
'%': true,
'&': true,
'\'': true,
'*': true,
'+': true,
'-': true,
'.': true,
'0': true,
'1': true,
'2': true,
'3': true,
'4': true,
'5': true,
'6': true,
'7': true,
'8': true,
'9': true,
'A': true,
'B': true,
'C': true,
'D': true,
'E': true,
'F': true,
'G': true,
'H': true,
'I': true,
'J': true,
'K': true,
'L': true,
'M': true,
'N': true,
'O': true,
'P': true,
'Q': true,
'R': true,
'S': true,
'T': true,
'U': true,
'W': true,
'V': true,
'X': true,
'Y': true,
'Z': true,
'^': true,
'_': true,
'`': true,
'a': true,
'b': true,
'c': true,
'd': true,
'e': true,
'f': true,
'g': true,
'h': true,
'i': true,
'j': true,
'k': true,
'l': true,
'm': true,
'n': true,
'o': true,
'p': true,
'q': true,
'r': true,
's': true,
't': true,
'u': true,
'v': true,
'w': true,
'x': true,
'y': true,
'z': true,
'|': true,
'~': true,
}
func IsTokenRune(r rune) bool {
return r < utf8.RuneSelf && isTokenTable[byte(r)]
}
// HeaderValuesContainsToken reports whether any string in values
// contains the provided token, ASCII case-insensitively.
func HeaderValuesContainsToken(values []string, token string) bool {
for _, v := range values {
if headerValueContainsToken(v, token) {
return true
}
}
return false
}
// isOWS reports whether b is an optional whitespace byte, as defined
// by RFC 7230 section 3.2.3.
func isOWS(b byte) bool { return b == ' ' || b == '\t' }
// trimOWS returns x with all optional whitespace removes from the
// beginning and end.
func trimOWS(x string) string {
// TODO: consider using strings.Trim(x, " \t") instead,
// if and when it's fast enough. See issue 10292.
// But this ASCII-only code will probably always beat UTF-8
// aware code.
for len(x) > 0 && isOWS(x[0]) {
x = x[1:]
}
for len(x) > 0 && isOWS(x[len(x)-1]) {
x = x[:len(x)-1]
}
return x
}
// headerValueContainsToken reports whether v (assumed to be a
// 0#element, in the ABNF extension described in RFC 7230 section 7)
// contains token amongst its comma-separated tokens, ASCII
// case-insensitively.
func headerValueContainsToken(v string, token string) bool {
for comma := strings.IndexByte(v, ','); comma != -1; comma = strings.IndexByte(v, ',') {
if tokenEqual(trimOWS(v[:comma]), token) {
return true
}
v = v[comma+1:]
}
return tokenEqual(trimOWS(v), token)
}
// lowerASCII returns the ASCII lowercase version of b.
func lowerASCII(b byte) byte {
if 'A' <= b && b <= 'Z' {
return b + ('a' - 'A')
}
return b
}
// tokenEqual reports whether t1 and t2 are equal, ASCII case-insensitively.
func tokenEqual(t1, t2 string) bool {
if len(t1) != len(t2) {
return false
}
for i, b := range t1 {
if b >= utf8.RuneSelf {
// No UTF-8 or non-ASCII allowed in tokens.
return false
}
if lowerASCII(byte(b)) != lowerASCII(t2[i]) {
return false
}
}
return true
}
// isLWS reports whether b is linear white space, according
// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
//
// LWS = [CRLF] 1*( SP | HT )
func isLWS(b byte) bool { return b == ' ' || b == '\t' }
// isCTL reports whether b is a control byte, according
// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
//
// CTL = <any US-ASCII control character
// (octets 0 - 31) and DEL (127)>
func isCTL(b byte) bool {
const del = 0x7f // a CTL
return b < ' ' || b == del
}
// ValidHeaderFieldName reports whether v is a valid HTTP/1.x header name.
// HTTP/2 imposes the additional restriction that uppercase ASCII
// letters are not allowed.
//
// RFC 7230 says:
//
// header-field = field-name ":" OWS field-value OWS
// field-name = token
// token = 1*tchar
// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
func ValidHeaderFieldName(v string) bool {
if len(v) == 0 {
return false
}
for i := 0; i < len(v); i++ {
if !isTokenTable[v[i]] {
return false
}
}
return true
}
// ValidHostHeader reports whether h is a valid host header.
func ValidHostHeader(h string) bool {
// The latest spec is actually this:
//
// http://tools.ietf.org/html/rfc7230#section-5.4
// Host = uri-host [ ":" port ]
//
// Where uri-host is:
// http://tools.ietf.org/html/rfc3986#section-3.2.2
//
// But we're going to be much more lenient for now and just
// search for any byte that's not a valid byte in any of those
// expressions.
for i := 0; i < len(h); i++ {
if !validHostByte[h[i]] {
return false
}
}
return true
}
// See the validHostHeader comment.
var validHostByte = [256]bool{
'0': true, '1': true, '2': true, '3': true, '4': true, '5': true, '6': true, '7': true,
'8': true, '9': true,
'a': true, 'b': true, 'c': true, 'd': true, 'e': true, 'f': true, 'g': true, 'h': true,
'i': true, 'j': true, 'k': true, 'l': true, 'm': true, 'n': true, 'o': true, 'p': true,
'q': true, 'r': true, 's': true, 't': true, 'u': true, 'v': true, 'w': true, 'x': true,
'y': true, 'z': true,
'A': true, 'B': true, 'C': true, 'D': true, 'E': true, 'F': true, 'G': true, 'H': true,
'I': true, 'J': true, 'K': true, 'L': true, 'M': true, 'N': true, 'O': true, 'P': true,
'Q': true, 'R': true, 'S': true, 'T': true, 'U': true, 'V': true, 'W': true, 'X': true,
'Y': true, 'Z': true,
'!': true, // sub-delims
'$': true, // sub-delims
'%': true, // pct-encoded (and used in IPv6 zones)
'&': true, // sub-delims
'(': true, // sub-delims
')': true, // sub-delims
'*': true, // sub-delims
'+': true, // sub-delims
',': true, // sub-delims
'-': true, // unreserved
'.': true, // unreserved
':': true, // IPv6address + Host expression's optional port
';': true, // sub-delims
'=': true, // sub-delims
'[': true,
'\'': true, // sub-delims
']': true,
'_': true, // unreserved
'~': true, // unreserved
}
// ValidHeaderFieldValue reports whether v is a valid "field-value" according to
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 :
//
// message-header = field-name ":" [ field-value ]
// field-value = *( field-content | LWS )
// field-content = <the OCTETs making up the field-value
// and consisting of either *TEXT or combinations
// of token, separators, and quoted-string>
//
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 :
//
// TEXT = <any OCTET except CTLs,
// but including LWS>
// LWS = [CRLF] 1*( SP | HT )
// CTL = <any US-ASCII control character
// (octets 0 - 31) and DEL (127)>
//
// RFC 7230 says:
//
// field-value = *( field-content / obs-fold )
// obj-fold = N/A to http2, and deprecated
// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
// field-vchar = VCHAR / obs-text
// obs-text = %x80-FF
// VCHAR = "any visible [USASCII] character"
//
// http2 further says: "Similarly, HTTP/2 allows header field values
// that are not valid. While most of the values that can be encoded
// will not alter header field parsing, carriage return (CR, ASCII
// 0xd), line feed (LF, ASCII 0xa), and the zero character (NUL, ASCII
// 0x0) might be exploited by an attacker if they are translated
// verbatim. Any request or response that contains a character not
// permitted in a header field value MUST be treated as malformed
// (Section 8.1.2.6). Valid characters are defined by the
// field-content ABNF rule in Section 3.2 of [RFC7230]."
//
// This function does not (yet?) properly handle the rejection of
// strings that begin or end with SP or HTAB.
func ValidHeaderFieldValue(v string) bool {
for i := 0; i < len(v); i++ {
b := v[i]
if isCTL(b) && !isLWS(b) {
return false
}
}
return true
}
func isASCII(s string) bool {
for i := 0; i < len(s); i++ {
if s[i] >= utf8.RuneSelf {
return false
}
}
return true
}
// PunycodeHostPort returns the IDNA Punycode version
// of the provided "host" or "host:port" string.
func PunycodeHostPort(v string) (string, error) {
if isASCII(v) {
return v, nil
}
host, port, err := net.SplitHostPort(v)
if err != nil {
// The input 'v' argument was just a "host" argument,
// without a port. This error should not be returned
// to the caller.
host = v
port = ""
}
host, err = idna.ToASCII(host)
if err != nil {
// Non-UTF-8? Not representable in Punycode, in any
// case.
return "", err
}
if port == "" {
return host, nil
}
return net.JoinHostPort(host, port), nil
}
// Copyright 2021 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 "strings"
// The HTTP protocols are defined in terms of ASCII, not Unicode. This file
// contains helper functions which may use Unicode-aware functions which would
// otherwise be unsafe and could introduce vulnerabilities if used improperly.
// asciiEqualFold is strings.EqualFold, ASCII only. It reports whether s and t
// are equal, ASCII-case-insensitively.
func asciiEqualFold(s, t string) bool {
if len(s) != len(t) {
return false
}
for i := 0; i < len(s); i++ {
if lower(s[i]) != lower(t[i]) {
return false
}
}
return true
}
// lower returns the ASCII lowercase version of b.
func lower(b byte) byte {
if 'A' <= b && b <= 'Z' {
return b + ('a' - 'A')
}
return b
}
// isASCIIPrint returns whether s is ASCII and printable according to
// https://tools.ietf.org/html/rfc20#section-4.2.
func isASCIIPrint(s string) bool {
for i := 0; i < len(s); i++ {
if s[i] < ' ' || s[i] > '~' {
return false
}
}
return true
}
// asciiToLower returns the lowercase version of s if s is ASCII and printable,
// and whether or not it was.
func asciiToLower(s string) (lower string, ok bool) {
if !isASCIIPrint(s) {
return "", false
}
return strings.ToLower(s), true
}
// 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
// A list of the possible cipher suite ids. Taken from
// https://www.iana.org/assignments/tls-parameters/tls-parameters.txt
const (
cipher_TLS_NULL_WITH_NULL_NULL uint16 = 0x0000
cipher_TLS_RSA_WITH_NULL_MD5 uint16 = 0x0001
cipher_TLS_RSA_WITH_NULL_SHA uint16 = 0x0002
cipher_TLS_RSA_EXPORT_WITH_RC4_40_MD5 uint16 = 0x0003
cipher_TLS_RSA_WITH_RC4_128_MD5 uint16 = 0x0004
cipher_TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005
cipher_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 uint16 = 0x0006
cipher_TLS_RSA_WITH_IDEA_CBC_SHA uint16 = 0x0007
cipher_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0008
cipher_TLS_RSA_WITH_DES_CBC_SHA uint16 = 0x0009
cipher_TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000A
cipher_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x000B
cipher_TLS_DH_DSS_WITH_DES_CBC_SHA uint16 = 0x000C
cipher_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA uint16 = 0x000D
cipher_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x000E
cipher_TLS_DH_RSA_WITH_DES_CBC_SHA uint16 = 0x000F
cipher_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x0010
cipher_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0011
cipher_TLS_DHE_DSS_WITH_DES_CBC_SHA uint16 = 0x0012
cipher_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA uint16 = 0x0013
cipher_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0014
cipher_TLS_DHE_RSA_WITH_DES_CBC_SHA uint16 = 0x0015
cipher_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x0016
cipher_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 uint16 = 0x0017
cipher_TLS_DH_anon_WITH_RC4_128_MD5 uint16 = 0x0018
cipher_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0019
cipher_TLS_DH_anon_WITH_DES_CBC_SHA uint16 = 0x001A
cipher_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA uint16 = 0x001B
// Reserved uint16 = 0x001C-1D
cipher_TLS_KRB5_WITH_DES_CBC_SHA uint16 = 0x001E
cipher_TLS_KRB5_WITH_3DES_EDE_CBC_SHA uint16 = 0x001F
cipher_TLS_KRB5_WITH_RC4_128_SHA uint16 = 0x0020
cipher_TLS_KRB5_WITH_IDEA_CBC_SHA uint16 = 0x0021
cipher_TLS_KRB5_WITH_DES_CBC_MD5 uint16 = 0x0022
cipher_TLS_KRB5_WITH_3DES_EDE_CBC_MD5 uint16 = 0x0023
cipher_TLS_KRB5_WITH_RC4_128_MD5 uint16 = 0x0024
cipher_TLS_KRB5_WITH_IDEA_CBC_MD5 uint16 = 0x0025
cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA uint16 = 0x0026
cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA uint16 = 0x0027
cipher_TLS_KRB5_EXPORT_WITH_RC4_40_SHA uint16 = 0x0028
cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 uint16 = 0x0029
cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 uint16 = 0x002A
cipher_TLS_KRB5_EXPORT_WITH_RC4_40_MD5 uint16 = 0x002B
cipher_TLS_PSK_WITH_NULL_SHA uint16 = 0x002C
cipher_TLS_DHE_PSK_WITH_NULL_SHA uint16 = 0x002D
cipher_TLS_RSA_PSK_WITH_NULL_SHA uint16 = 0x002E
cipher_TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002F
cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA uint16 = 0x0030
cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA uint16 = 0x0031
cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA uint16 = 0x0032
cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0x0033
cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA uint16 = 0x0034
cipher_TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035
cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA uint16 = 0x0036
cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0037
cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA uint16 = 0x0038
cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0039
cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA uint16 = 0x003A
cipher_TLS_RSA_WITH_NULL_SHA256 uint16 = 0x003B
cipher_TLS_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003C
cipher_TLS_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x003D
cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA256 uint16 = 0x003E
cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003F
cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 uint16 = 0x0040
cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0041
cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0042
cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0043
cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0044
cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0045
cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0046
// Reserved uint16 = 0x0047-4F
// Reserved uint16 = 0x0050-58
// Reserved uint16 = 0x0059-5C
// Unassigned uint16 = 0x005D-5F
// Reserved uint16 = 0x0060-66
cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x0067
cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA256 uint16 = 0x0068
cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x0069
cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 uint16 = 0x006A
cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x006B
cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA256 uint16 = 0x006C
cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA256 uint16 = 0x006D
// Unassigned uint16 = 0x006E-83
cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0084
cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0085
cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0086
cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0087
cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0088
cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0089
cipher_TLS_PSK_WITH_RC4_128_SHA uint16 = 0x008A
cipher_TLS_PSK_WITH_3DES_EDE_CBC_SHA uint16 = 0x008B
cipher_TLS_PSK_WITH_AES_128_CBC_SHA uint16 = 0x008C
cipher_TLS_PSK_WITH_AES_256_CBC_SHA uint16 = 0x008D
cipher_TLS_DHE_PSK_WITH_RC4_128_SHA uint16 = 0x008E
cipher_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA uint16 = 0x008F
cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA uint16 = 0x0090
cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA uint16 = 0x0091
cipher_TLS_RSA_PSK_WITH_RC4_128_SHA uint16 = 0x0092
cipher_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA uint16 = 0x0093
cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA uint16 = 0x0094
cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA uint16 = 0x0095
cipher_TLS_RSA_WITH_SEED_CBC_SHA uint16 = 0x0096
cipher_TLS_DH_DSS_WITH_SEED_CBC_SHA uint16 = 0x0097
cipher_TLS_DH_RSA_WITH_SEED_CBC_SHA uint16 = 0x0098
cipher_TLS_DHE_DSS_WITH_SEED_CBC_SHA uint16 = 0x0099
cipher_TLS_DHE_RSA_WITH_SEED_CBC_SHA uint16 = 0x009A
cipher_TLS_DH_anon_WITH_SEED_CBC_SHA uint16 = 0x009B
cipher_TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009C
cipher_TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009D
cipher_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009E
cipher_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009F
cipher_TLS_DH_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x00A0
cipher_TLS_DH_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x00A1
cipher_TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 uint16 = 0x00A2
cipher_TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 uint16 = 0x00A3
cipher_TLS_DH_DSS_WITH_AES_128_GCM_SHA256 uint16 = 0x00A4
cipher_TLS_DH_DSS_WITH_AES_256_GCM_SHA384 uint16 = 0x00A5
cipher_TLS_DH_anon_WITH_AES_128_GCM_SHA256 uint16 = 0x00A6
cipher_TLS_DH_anon_WITH_AES_256_GCM_SHA384 uint16 = 0x00A7
cipher_TLS_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0x00A8
cipher_TLS_PSK_WITH_AES_256_GCM_SHA384 uint16 = 0x00A9
cipher_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0x00AA
cipher_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 uint16 = 0x00AB
cipher_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0x00AC
cipher_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 uint16 = 0x00AD
cipher_TLS_PSK_WITH_AES_128_CBC_SHA256 uint16 = 0x00AE
cipher_TLS_PSK_WITH_AES_256_CBC_SHA384 uint16 = 0x00AF
cipher_TLS_PSK_WITH_NULL_SHA256 uint16 = 0x00B0
cipher_TLS_PSK_WITH_NULL_SHA384 uint16 = 0x00B1
cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 uint16 = 0x00B2
cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 uint16 = 0x00B3
cipher_TLS_DHE_PSK_WITH_NULL_SHA256 uint16 = 0x00B4
cipher_TLS_DHE_PSK_WITH_NULL_SHA384 uint16 = 0x00B5
cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 uint16 = 0x00B6
cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 uint16 = 0x00B7
cipher_TLS_RSA_PSK_WITH_NULL_SHA256 uint16 = 0x00B8
cipher_TLS_RSA_PSK_WITH_NULL_SHA384 uint16 = 0x00B9
cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BA
cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BB
cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BC
cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BD
cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BE
cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BF
cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C0
cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C1
cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C2
cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C3
cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C4
cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C5
// Unassigned uint16 = 0x00C6-FE
cipher_TLS_EMPTY_RENEGOTIATION_INFO_SCSV uint16 = 0x00FF
// Unassigned uint16 = 0x01-55,*
cipher_TLS_FALLBACK_SCSV uint16 = 0x5600
// Unassigned uint16 = 0x5601 - 0xC000
cipher_TLS_ECDH_ECDSA_WITH_NULL_SHA uint16 = 0xC001
cipher_TLS_ECDH_ECDSA_WITH_RC4_128_SHA uint16 = 0xC002
cipher_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC003
cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xC004
cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xC005
cipher_TLS_ECDHE_ECDSA_WITH_NULL_SHA uint16 = 0xC006
cipher_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA uint16 = 0xC007
cipher_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC008
cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xC009
cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xC00A
cipher_TLS_ECDH_RSA_WITH_NULL_SHA uint16 = 0xC00B
cipher_TLS_ECDH_RSA_WITH_RC4_128_SHA uint16 = 0xC00C
cipher_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC00D
cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA uint16 = 0xC00E
cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA uint16 = 0xC00F
cipher_TLS_ECDHE_RSA_WITH_NULL_SHA uint16 = 0xC010
cipher_TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xC011
cipher_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC012
cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xC013
cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xC014
cipher_TLS_ECDH_anon_WITH_NULL_SHA uint16 = 0xC015
cipher_TLS_ECDH_anon_WITH_RC4_128_SHA uint16 = 0xC016
cipher_TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA uint16 = 0xC017
cipher_TLS_ECDH_anon_WITH_AES_128_CBC_SHA uint16 = 0xC018
cipher_TLS_ECDH_anon_WITH_AES_256_CBC_SHA uint16 = 0xC019
cipher_TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC01A
cipher_TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC01B
cipher_TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA uint16 = 0xC01C
cipher_TLS_SRP_SHA_WITH_AES_128_CBC_SHA uint16 = 0xC01D
cipher_TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA uint16 = 0xC01E
cipher_TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA uint16 = 0xC01F
cipher_TLS_SRP_SHA_WITH_AES_256_CBC_SHA uint16 = 0xC020
cipher_TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA uint16 = 0xC021
cipher_TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA uint16 = 0xC022
cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xC023
cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 uint16 = 0xC024
cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xC025
cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 uint16 = 0xC026
cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xC027
cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 uint16 = 0xC028
cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xC029
cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 uint16 = 0xC02A
cipher_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC02B
cipher_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC02C
cipher_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC02D
cipher_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC02E
cipher_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC02F
cipher_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC030
cipher_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC031
cipher_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC032
cipher_TLS_ECDHE_PSK_WITH_RC4_128_SHA uint16 = 0xC033
cipher_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA uint16 = 0xC034
cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA uint16 = 0xC035
cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA uint16 = 0xC036
cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 uint16 = 0xC037
cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 uint16 = 0xC038
cipher_TLS_ECDHE_PSK_WITH_NULL_SHA uint16 = 0xC039
cipher_TLS_ECDHE_PSK_WITH_NULL_SHA256 uint16 = 0xC03A
cipher_TLS_ECDHE_PSK_WITH_NULL_SHA384 uint16 = 0xC03B
cipher_TLS_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC03C
cipher_TLS_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC03D
cipher_TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC03E
cipher_TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC03F
cipher_TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC040
cipher_TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC041
cipher_TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC042
cipher_TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC043
cipher_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC044
cipher_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC045
cipher_TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC046
cipher_TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC047
cipher_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC048
cipher_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC049
cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC04A
cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC04B
cipher_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC04C
cipher_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC04D
cipher_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC04E
cipher_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC04F
cipher_TLS_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC050
cipher_TLS_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC051
cipher_TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC052
cipher_TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC053
cipher_TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC054
cipher_TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC055
cipher_TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC056
cipher_TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC057
cipher_TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC058
cipher_TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC059
cipher_TLS_DH_anon_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC05A
cipher_TLS_DH_anon_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC05B
cipher_TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC05C
cipher_TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC05D
cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC05E
cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC05F
cipher_TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC060
cipher_TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC061
cipher_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC062
cipher_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC063
cipher_TLS_PSK_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC064
cipher_TLS_PSK_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC065
cipher_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC066
cipher_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC067
cipher_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC068
cipher_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC069
cipher_TLS_PSK_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC06A
cipher_TLS_PSK_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC06B
cipher_TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC06C
cipher_TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC06D
cipher_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC06E
cipher_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC06F
cipher_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC070
cipher_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC071
cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC072
cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC073
cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC074
cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC075
cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC076
cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC077
cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC078
cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC079
cipher_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC07A
cipher_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC07B
cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC07C
cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC07D
cipher_TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC07E
cipher_TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC07F
cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC080
cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC081
cipher_TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC082
cipher_TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC083
cipher_TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC084
cipher_TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC085
cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC086
cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC087
cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC088
cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC089
cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC08A
cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC08B
cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC08C
cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC08D
cipher_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC08E
cipher_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC08F
cipher_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC090
cipher_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC091
cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC092
cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC093
cipher_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC094
cipher_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC095
cipher_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC096
cipher_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC097
cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC098
cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC099
cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC09A
cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC09B
cipher_TLS_RSA_WITH_AES_128_CCM uint16 = 0xC09C
cipher_TLS_RSA_WITH_AES_256_CCM uint16 = 0xC09D
cipher_TLS_DHE_RSA_WITH_AES_128_CCM uint16 = 0xC09E
cipher_TLS_DHE_RSA_WITH_AES_256_CCM uint16 = 0xC09F
cipher_TLS_RSA_WITH_AES_128_CCM_8 uint16 = 0xC0A0
cipher_TLS_RSA_WITH_AES_256_CCM_8 uint16 = 0xC0A1
cipher_TLS_DHE_RSA_WITH_AES_128_CCM_8 uint16 = 0xC0A2
cipher_TLS_DHE_RSA_WITH_AES_256_CCM_8 uint16 = 0xC0A3
cipher_TLS_PSK_WITH_AES_128_CCM uint16 = 0xC0A4
cipher_TLS_PSK_WITH_AES_256_CCM uint16 = 0xC0A5
cipher_TLS_DHE_PSK_WITH_AES_128_CCM uint16 = 0xC0A6
cipher_TLS_DHE_PSK_WITH_AES_256_CCM uint16 = 0xC0A7
cipher_TLS_PSK_WITH_AES_128_CCM_8 uint16 = 0xC0A8
cipher_TLS_PSK_WITH_AES_256_CCM_8 uint16 = 0xC0A9
cipher_TLS_PSK_DHE_WITH_AES_128_CCM_8 uint16 = 0xC0AA
cipher_TLS_PSK_DHE_WITH_AES_256_CCM_8 uint16 = 0xC0AB
cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CCM uint16 = 0xC0AC
cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CCM uint16 = 0xC0AD
cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 uint16 = 0xC0AE
cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 uint16 = 0xC0AF
// Unassigned uint16 = 0xC0B0-FF
// Unassigned uint16 = 0xC1-CB,*
// Unassigned uint16 = 0xCC00-A7
cipher_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCA8
cipher_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCA9
cipher_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCAA
cipher_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCAB
cipher_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCAC
cipher_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCAD
cipher_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCAE
)
// isBadCipher reports whether the cipher is blacklisted by the HTTP/2 spec.
// References:
// https://tools.ietf.org/html/rfc7540#appendix-A
// Reject cipher suites from Appendix A.
// "This list includes those cipher suites that do not
// offer an ephemeral key exchange and those that are
// based on the TLS null, stream or block cipher type"
func isBadCipher(cipher uint16) bool {
switch cipher {
case cipher_TLS_NULL_WITH_NULL_NULL,
cipher_TLS_RSA_WITH_NULL_MD5,
cipher_TLS_RSA_WITH_NULL_SHA,
cipher_TLS_RSA_EXPORT_WITH_RC4_40_MD5,
cipher_TLS_RSA_WITH_RC4_128_MD5,
cipher_TLS_RSA_WITH_RC4_128_SHA,
cipher_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
cipher_TLS_RSA_WITH_IDEA_CBC_SHA,
cipher_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA,
cipher_TLS_RSA_WITH_DES_CBC_SHA,
cipher_TLS_RSA_WITH_3DES_EDE_CBC_SHA,
cipher_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,
cipher_TLS_DH_DSS_WITH_DES_CBC_SHA,
cipher_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA,
cipher_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA,
cipher_TLS_DH_RSA_WITH_DES_CBC_SHA,
cipher_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA,
cipher_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,
cipher_TLS_DHE_DSS_WITH_DES_CBC_SHA,
cipher_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
cipher_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,
cipher_TLS_DHE_RSA_WITH_DES_CBC_SHA,
cipher_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
cipher_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5,
cipher_TLS_DH_anon_WITH_RC4_128_MD5,
cipher_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA,
cipher_TLS_DH_anon_WITH_DES_CBC_SHA,
cipher_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA,
cipher_TLS_KRB5_WITH_DES_CBC_SHA,
cipher_TLS_KRB5_WITH_3DES_EDE_CBC_SHA,
cipher_TLS_KRB5_WITH_RC4_128_SHA,
cipher_TLS_KRB5_WITH_IDEA_CBC_SHA,
cipher_TLS_KRB5_WITH_DES_CBC_MD5,
cipher_TLS_KRB5_WITH_3DES_EDE_CBC_MD5,
cipher_TLS_KRB5_WITH_RC4_128_MD5,
cipher_TLS_KRB5_WITH_IDEA_CBC_MD5,
cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA,
cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA,
cipher_TLS_KRB5_EXPORT_WITH_RC4_40_SHA,
cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5,
cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5,
cipher_TLS_KRB5_EXPORT_WITH_RC4_40_MD5,
cipher_TLS_PSK_WITH_NULL_SHA,
cipher_TLS_DHE_PSK_WITH_NULL_SHA,
cipher_TLS_RSA_PSK_WITH_NULL_SHA,
cipher_TLS_RSA_WITH_AES_128_CBC_SHA,
cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA,
cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA,
cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA,
cipher_TLS_RSA_WITH_AES_256_CBC_SHA,
cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA,
cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA,
cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA,
cipher_TLS_RSA_WITH_NULL_SHA256,
cipher_TLS_RSA_WITH_AES_128_CBC_SHA256,
cipher_TLS_RSA_WITH_AES_256_CBC_SHA256,
cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA256,
cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA256,
cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA,
cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA,
cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA,
cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA,
cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA256,
cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA256,
cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA256,
cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA256,
cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA,
cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA,
cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA,
cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA,
cipher_TLS_PSK_WITH_RC4_128_SHA,
cipher_TLS_PSK_WITH_3DES_EDE_CBC_SHA,
cipher_TLS_PSK_WITH_AES_128_CBC_SHA,
cipher_TLS_PSK_WITH_AES_256_CBC_SHA,
cipher_TLS_DHE_PSK_WITH_RC4_128_SHA,
cipher_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
cipher_TLS_RSA_PSK_WITH_RC4_128_SHA,
cipher_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
cipher_TLS_RSA_WITH_SEED_CBC_SHA,
cipher_TLS_DH_DSS_WITH_SEED_CBC_SHA,
cipher_TLS_DH_RSA_WITH_SEED_CBC_SHA,
cipher_TLS_DHE_DSS_WITH_SEED_CBC_SHA,
cipher_TLS_DHE_RSA_WITH_SEED_CBC_SHA,
cipher_TLS_DH_anon_WITH_SEED_CBC_SHA,
cipher_TLS_RSA_WITH_AES_128_GCM_SHA256,
cipher_TLS_RSA_WITH_AES_256_GCM_SHA384,
cipher_TLS_DH_RSA_WITH_AES_128_GCM_SHA256,
cipher_TLS_DH_RSA_WITH_AES_256_GCM_SHA384,
cipher_TLS_DH_DSS_WITH_AES_128_GCM_SHA256,
cipher_TLS_DH_DSS_WITH_AES_256_GCM_SHA384,
cipher_TLS_DH_anon_WITH_AES_128_GCM_SHA256,
cipher_TLS_DH_anon_WITH_AES_256_GCM_SHA384,
cipher_TLS_PSK_WITH_AES_128_GCM_SHA256,
cipher_TLS_PSK_WITH_AES_256_GCM_SHA384,
cipher_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256,
cipher_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384,
cipher_TLS_PSK_WITH_AES_128_CBC_SHA256,
cipher_TLS_PSK_WITH_AES_256_CBC_SHA384,
cipher_TLS_PSK_WITH_NULL_SHA256,
cipher_TLS_PSK_WITH_NULL_SHA384,
cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,
cipher_TLS_DHE_PSK_WITH_NULL_SHA256,
cipher_TLS_DHE_PSK_WITH_NULL_SHA384,
cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
cipher_TLS_RSA_PSK_WITH_NULL_SHA256,
cipher_TLS_RSA_PSK_WITH_NULL_SHA384,
cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256,
cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256,
cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256,
cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256,
cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256,
cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256,
cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256,
cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256,
cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256,
cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256,
cipher_TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
cipher_TLS_ECDH_ECDSA_WITH_NULL_SHA,
cipher_TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
cipher_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
cipher_TLS_ECDHE_ECDSA_WITH_NULL_SHA,
cipher_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
cipher_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
cipher_TLS_ECDH_RSA_WITH_NULL_SHA,
cipher_TLS_ECDH_RSA_WITH_RC4_128_SHA,
cipher_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
cipher_TLS_ECDHE_RSA_WITH_NULL_SHA,
cipher_TLS_ECDHE_RSA_WITH_RC4_128_SHA,
cipher_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
cipher_TLS_ECDH_anon_WITH_NULL_SHA,
cipher_TLS_ECDH_anon_WITH_RC4_128_SHA,
cipher_TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA,
cipher_TLS_ECDH_anon_WITH_AES_128_CBC_SHA,
cipher_TLS_ECDH_anon_WITH_AES_256_CBC_SHA,
cipher_TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA,
cipher_TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
cipher_TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
cipher_TLS_SRP_SHA_WITH_AES_128_CBC_SHA,
cipher_TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
cipher_TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
cipher_TLS_SRP_SHA_WITH_AES_256_CBC_SHA,
cipher_TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA,
cipher_TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA,
cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
cipher_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
cipher_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
cipher_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
cipher_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
cipher_TLS_ECDHE_PSK_WITH_RC4_128_SHA,
cipher_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA,
cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,
cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA,
cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384,
cipher_TLS_ECDHE_PSK_WITH_NULL_SHA,
cipher_TLS_ECDHE_PSK_WITH_NULL_SHA256,
cipher_TLS_ECDHE_PSK_WITH_NULL_SHA384,
cipher_TLS_RSA_WITH_ARIA_128_CBC_SHA256,
cipher_TLS_RSA_WITH_ARIA_256_CBC_SHA384,
cipher_TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256,
cipher_TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384,
cipher_TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256,
cipher_TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384,
cipher_TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256,
cipher_TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384,
cipher_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256,
cipher_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384,
cipher_TLS_DH_anon_WITH_ARIA_128_CBC_SHA256,
cipher_TLS_DH_anon_WITH_ARIA_256_CBC_SHA384,
cipher_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256,
cipher_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384,
cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256,
cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384,
cipher_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256,
cipher_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384,
cipher_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256,
cipher_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384,
cipher_TLS_RSA_WITH_ARIA_128_GCM_SHA256,
cipher_TLS_RSA_WITH_ARIA_256_GCM_SHA384,
cipher_TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256,
cipher_TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384,
cipher_TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256,
cipher_TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384,
cipher_TLS_DH_anon_WITH_ARIA_128_GCM_SHA256,
cipher_TLS_DH_anon_WITH_ARIA_256_GCM_SHA384,
cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256,
cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384,
cipher_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256,
cipher_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384,
cipher_TLS_PSK_WITH_ARIA_128_CBC_SHA256,
cipher_TLS_PSK_WITH_ARIA_256_CBC_SHA384,
cipher_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256,
cipher_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384,
cipher_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256,
cipher_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384,
cipher_TLS_PSK_WITH_ARIA_128_GCM_SHA256,
cipher_TLS_PSK_WITH_ARIA_256_GCM_SHA384,
cipher_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256,
cipher_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384,
cipher_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256,
cipher_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384,
cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256,
cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256,
cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384,
cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256,
cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384,
cipher_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256,
cipher_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384,
cipher_TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256,
cipher_TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384,
cipher_TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256,
cipher_TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384,
cipher_TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256,
cipher_TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384,
cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256,
cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384,
cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256,
cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384,
cipher_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256,
cipher_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384,
cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256,
cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384,
cipher_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256,
cipher_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384,
cipher_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
cipher_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256,
cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384,
cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
cipher_TLS_RSA_WITH_AES_128_CCM,
cipher_TLS_RSA_WITH_AES_256_CCM,
cipher_TLS_RSA_WITH_AES_128_CCM_8,
cipher_TLS_RSA_WITH_AES_256_CCM_8,
cipher_TLS_PSK_WITH_AES_128_CCM,
cipher_TLS_PSK_WITH_AES_256_CCM,
cipher_TLS_PSK_WITH_AES_128_CCM_8,
cipher_TLS_PSK_WITH_AES_256_CCM_8:
return true
default:
return false
}
}
// 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.
// Transport code's client connection pooling.
package http2
import (
"context"
"errors"
"net"
"net/http"
"sync"
)
// ClientConnPool manages a pool of HTTP/2 client connections.
type ClientConnPool interface {
// GetClientConn returns a specific HTTP/2 connection (usually
// a TLS-TCP connection) to an HTTP/2 server. On success, the
// returned ClientConn accounts for the upcoming RoundTrip
// call, so the caller should not omit it. If the caller needs
// to, ClientConn.RoundTrip can be called with a bogus
// new(http.Request) to release the stream reservation.
GetClientConn(req *http.Request, addr string) (*ClientConn, error)
MarkDead(*ClientConn)
}
// clientConnPoolIdleCloser is the interface implemented by ClientConnPool
// implementations which can close their idle connections.
type clientConnPoolIdleCloser interface {
ClientConnPool
closeIdleConnections()
}
var (
_ clientConnPoolIdleCloser = (*clientConnPool)(nil)
_ clientConnPoolIdleCloser = noDialClientConnPool{}
)
// TODO: use singleflight for dialing and addConnCalls?
type clientConnPool struct {
t *Transport
mu sync.Mutex // TODO: maybe switch to RWMutex
// TODO: add support for sharing conns based on cert names
// (e.g. share conn for googleapis.com and appspot.com)
conns map[string][]*ClientConn // key is host:port
dialing map[string]*dialCall // currently in-flight dials
keys map[*ClientConn][]string
addConnCalls map[string]*addConnCall // in-flight addConnIfNeeded calls
}
func (p *clientConnPool) GetClientConn(req *http.Request, addr string) (*ClientConn, error) {
return p.getClientConn(req, addr, dialOnMiss)
}
const (
dialOnMiss = true
noDialOnMiss = false
)
func (p *clientConnPool) getClientConn(req *http.Request, addr string, dialOnMiss bool) (*ClientConn, error) {
// TODO(dneil): Dial a new connection when t.DisableKeepAlives is set?
if isConnectionCloseRequest(req) && dialOnMiss {
// It gets its own connection.
traceGetConn(req, addr)
const singleUse = true
cc, err := p.t.dialClientConn(req.Context(), addr, singleUse)
if err != nil {
return nil, err
}
return cc, nil
}
for {
p.mu.Lock()
for _, cc := range p.conns[addr] {
if cc.ReserveNewRequest() {
// When a connection is presented to us by the net/http package,
// the GetConn hook has already been called.
// Don't call it a second time here.
if !cc.getConnCalled {
traceGetConn(req, addr)
}
cc.getConnCalled = false
p.mu.Unlock()
return cc, nil
}
}
if !dialOnMiss {
p.mu.Unlock()
return nil, ErrNoCachedConn
}
traceGetConn(req, addr)
call := p.getStartDialLocked(req.Context(), addr)
p.mu.Unlock()
<-call.done
if shouldRetryDial(call, req) {
continue
}
cc, err := call.res, call.err
if err != nil {
return nil, err
}
if cc.ReserveNewRequest() {
return cc, nil
}
}
}
// dialCall is an in-flight Transport dial call to a host.
type dialCall struct {
_ incomparable
p *clientConnPool
// the context associated with the request
// that created this dialCall
ctx context.Context
done chan struct{} // closed when done
res *ClientConn // valid after done is closed
err error // valid after done is closed
}
// requires p.mu is held.
func (p *clientConnPool) getStartDialLocked(ctx context.Context, addr string) *dialCall {
if call, ok := p.dialing[addr]; ok {
// A dial is already in-flight. Don't start another.
return call
}
call := &dialCall{p: p, done: make(chan struct{}), ctx: ctx}
if p.dialing == nil {
p.dialing = make(map[string]*dialCall)
}
p.dialing[addr] = call
go call.dial(call.ctx, addr)
return call
}
// run in its own goroutine.
func (c *dialCall) dial(ctx context.Context, addr string) {
const singleUse = false // shared conn
c.res, c.err = c.p.t.dialClientConn(ctx, addr, singleUse)
c.p.mu.Lock()
delete(c.p.dialing, addr)
if c.err == nil {
c.p.addConnLocked(addr, c.res)
}
c.p.mu.Unlock()
close(c.done)
}
// addConnIfNeeded makes a NewClientConn out of c if a connection for key doesn't
// already exist. It coalesces concurrent calls with the same key.
// This is used by the http1 Transport code when it creates a new connection. Because
// the http1 Transport doesn't de-dup TCP dials to outbound hosts (because it doesn't know
// the protocol), it can get into a situation where it has multiple TLS connections.
// This code decides which ones live or die.
// The return value used is whether c was used.
// c is never closed.
func (p *clientConnPool) addConnIfNeeded(key string, t *Transport, c net.Conn) (used bool, err error) {
p.mu.Lock()
for _, cc := range p.conns[key] {
if cc.CanTakeNewRequest() {
p.mu.Unlock()
return false, nil
}
}
call, dup := p.addConnCalls[key]
if !dup {
if p.addConnCalls == nil {
p.addConnCalls = make(map[string]*addConnCall)
}
call = &addConnCall{
p: p,
done: make(chan struct{}),
}
p.addConnCalls[key] = call
go call.run(t, key, c)
}
p.mu.Unlock()
<-call.done
if call.err != nil {
return false, call.err
}
return !dup, nil
}
type addConnCall struct {
_ incomparable
p *clientConnPool
done chan struct{} // closed when done
err error
}
func (c *addConnCall) run(t *Transport, key string, nc net.Conn) {
cc, err := t.NewClientConn(nc)
p := c.p
p.mu.Lock()
if err != nil {
c.err = err
} else {
cc.getConnCalled = true // already called by the net/http package
p.addConnLocked(key, cc)
}
delete(p.addConnCalls, key)
p.mu.Unlock()
close(c.done)
}
// p.mu must be held
func (p *clientConnPool) addConnLocked(key string, cc *ClientConn) {
for _, v := range p.conns[key] {
if v == cc {
return
}
}
if p.conns == nil {
p.conns = make(map[string][]*ClientConn)
}
if p.keys == nil {
p.keys = make(map[*ClientConn][]string)
}
p.conns[key] = append(p.conns[key], cc)
p.keys[cc] = append(p.keys[cc], key)
}
func (p *clientConnPool) MarkDead(cc *ClientConn) {
p.mu.Lock()
defer p.mu.Unlock()
for _, key := range p.keys[cc] {
vv, ok := p.conns[key]
if !ok {
continue
}
newList := filterOutClientConn(vv, cc)
if len(newList) > 0 {
p.conns[key] = newList
} else {
delete(p.conns, key)
}
}
delete(p.keys, cc)
}
func (p *clientConnPool) closeIdleConnections() {
p.mu.Lock()
defer p.mu.Unlock()
// TODO: don't close a cc if it was just added to the pool
// milliseconds ago and has never been used. There's currently
// a small race window with the HTTP/1 Transport's integration
// where it can add an idle conn just before using it, and
// somebody else can concurrently call CloseIdleConns and
// break some caller's RoundTrip.
for _, vv := range p.conns {
for _, cc := range vv {
cc.closeIfIdle()
}
}
}
func filterOutClientConn(in []*ClientConn, exclude *ClientConn) []*ClientConn {
out := in[:0]
for _, v := range in {
if v != exclude {
out = append(out, v)
}
}
// If we filtered it out, zero out the last item to prevent
// the GC from seeing it.
if len(in) != len(out) {
in[len(in)-1] = nil
}
return out
}
// noDialClientConnPool is an implementation of http2.ClientConnPool
// which never dials. We let the HTTP/1.1 client dial and use its TLS
// connection instead.
type noDialClientConnPool struct{ *clientConnPool }
func (p noDialClientConnPool) GetClientConn(req *http.Request, addr string) (*ClientConn, error) {
return p.getClientConn(req, addr, noDialOnMiss)
}
// shouldRetryDial reports whether the current request should
// retry dialing after the call finished unsuccessfully, for example
// if the dial was canceled because of a context cancellation or
// deadline expiry.
func shouldRetryDial(call *dialCall, req *http.Request) bool {
if call.err == nil {
// No error, no need to retry
return false
}
if call.ctx == req.Context() {
// If the call has the same context as the request, the dial
// should not be retried, since any cancellation will have come
// from this request.
return false
}
if !errors.Is(call.err, context.Canceled) && !errors.Is(call.err, context.DeadlineExceeded) {
// If the call error is not because of a context cancellation or a deadline expiry,
// the dial should not be retried.
return false
}
// Only retry if the error is a context cancellation error or deadline expiry
// and the context associated with the call was canceled or expired.
return call.ctx.Err() != nil
}
// Copyright 2024 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 (
"math"
"net/http"
"time"
)
// http2Config is a package-internal version of net/http.HTTP2Config.
//
// http.HTTP2Config was added in Go 1.24.
// When running with a version of net/http that includes HTTP2Config,
// we merge the configuration with the fields in Transport or Server
// to produce an http2Config.
//
// Zero valued fields in http2Config are interpreted as in the
// net/http.HTTPConfig documentation.
//
// Precedence order for reconciling configurations is:
//
// - Use the net/http.{Server,Transport}.HTTP2Config value, when non-zero.
// - Otherwise use the http2.{Server.Transport} value.
// - If the resulting value is zero or out of range, use a default.
type http2Config struct {
MaxConcurrentStreams uint32
StrictMaxConcurrentRequests bool
MaxDecoderHeaderTableSize uint32
MaxEncoderHeaderTableSize uint32
MaxReadFrameSize uint32
MaxUploadBufferPerConnection int32
MaxUploadBufferPerStream int32
SendPingTimeout time.Duration
PingTimeout time.Duration
WriteByteTimeout time.Duration
PermitProhibitedCipherSuites bool
CountError func(errType string)
}
// configFromServer merges configuration settings from
// net/http.Server.HTTP2Config and http2.Server.
func configFromServer(h1 *http.Server, h2 *Server) http2Config {
conf := http2Config{
MaxConcurrentStreams: h2.MaxConcurrentStreams,
MaxEncoderHeaderTableSize: h2.MaxEncoderHeaderTableSize,
MaxDecoderHeaderTableSize: h2.MaxDecoderHeaderTableSize,
MaxReadFrameSize: h2.MaxReadFrameSize,
MaxUploadBufferPerConnection: h2.MaxUploadBufferPerConnection,
MaxUploadBufferPerStream: h2.MaxUploadBufferPerStream,
SendPingTimeout: h2.ReadIdleTimeout,
PingTimeout: h2.PingTimeout,
WriteByteTimeout: h2.WriteByteTimeout,
PermitProhibitedCipherSuites: h2.PermitProhibitedCipherSuites,
CountError: h2.CountError,
}
fillNetHTTPConfig(&conf, h1.HTTP2)
setConfigDefaults(&conf, true)
return conf
}
// configFromTransport merges configuration settings from h2 and h2.t1.HTTP2
// (the net/http Transport).
func configFromTransport(h2 *Transport) http2Config {
conf := http2Config{
StrictMaxConcurrentRequests: h2.StrictMaxConcurrentStreams,
MaxEncoderHeaderTableSize: h2.MaxEncoderHeaderTableSize,
MaxDecoderHeaderTableSize: h2.MaxDecoderHeaderTableSize,
MaxReadFrameSize: h2.MaxReadFrameSize,
SendPingTimeout: h2.ReadIdleTimeout,
PingTimeout: h2.PingTimeout,
WriteByteTimeout: h2.WriteByteTimeout,
}
// Unlike most config fields, where out-of-range values revert to the default,
// Transport.MaxReadFrameSize clips.
if conf.MaxReadFrameSize < minMaxFrameSize {
conf.MaxReadFrameSize = minMaxFrameSize
} else if conf.MaxReadFrameSize > maxFrameSize {
conf.MaxReadFrameSize = maxFrameSize
}
if h2.t1 != nil {
fillNetHTTPConfig(&conf, h2.t1.HTTP2)
}
setConfigDefaults(&conf, false)
return conf
}
func setDefault[T ~int | ~int32 | ~uint32 | ~int64](v *T, minval, maxval, defval T) {
if *v < minval || *v > maxval {
*v = defval
}
}
func setConfigDefaults(conf *http2Config, server bool) {
setDefault(&conf.MaxConcurrentStreams, 1, math.MaxUint32, defaultMaxStreams)
setDefault(&conf.MaxEncoderHeaderTableSize, 1, math.MaxUint32, initialHeaderTableSize)
setDefault(&conf.MaxDecoderHeaderTableSize, 1, math.MaxUint32, initialHeaderTableSize)
if server {
setDefault(&conf.MaxUploadBufferPerConnection, initialWindowSize, math.MaxInt32, 1<<20)
} else {
setDefault(&conf.MaxUploadBufferPerConnection, initialWindowSize, math.MaxInt32, transportDefaultConnFlow)
}
if server {
setDefault(&conf.MaxUploadBufferPerStream, 1, math.MaxInt32, 1<<20)
} else {
setDefault(&conf.MaxUploadBufferPerStream, 1, math.MaxInt32, transportDefaultStreamFlow)
}
setDefault(&conf.MaxReadFrameSize, minMaxFrameSize, maxFrameSize, defaultMaxReadFrameSize)
setDefault(&conf.PingTimeout, 1, math.MaxInt64, 15*time.Second)
}
// adjustHTTP1MaxHeaderSize converts a limit in bytes on the size of an HTTP/1 header
// to an HTTP/2 MAX_HEADER_LIST_SIZE value.
func adjustHTTP1MaxHeaderSize(n int64) int64 {
// http2's count is in a slightly different unit and includes 32 bytes per pair.
// So, take the net/http.Server value and pad it up a bit, assuming 10 headers.
const perFieldOverhead = 32 // per http2 spec
const typicalHeaders = 10 // conservative
return n + typicalHeaders*perFieldOverhead
}
func fillNetHTTPConfig(conf *http2Config, h2 *http.HTTP2Config) {
if h2 == nil {
return
}
if h2.MaxConcurrentStreams != 0 {
conf.MaxConcurrentStreams = uint32(h2.MaxConcurrentStreams)
}
if http2ConfigStrictMaxConcurrentRequests(h2) {
conf.StrictMaxConcurrentRequests = true
}
if h2.MaxEncoderHeaderTableSize != 0 {
conf.MaxEncoderHeaderTableSize = uint32(h2.MaxEncoderHeaderTableSize)
}
if h2.MaxDecoderHeaderTableSize != 0 {
conf.MaxDecoderHeaderTableSize = uint32(h2.MaxDecoderHeaderTableSize)
}
if h2.MaxConcurrentStreams != 0 {
conf.MaxConcurrentStreams = uint32(h2.MaxConcurrentStreams)
}
if h2.MaxReadFrameSize != 0 {
conf.MaxReadFrameSize = uint32(h2.MaxReadFrameSize)
}
if h2.MaxReceiveBufferPerConnection != 0 {
conf.MaxUploadBufferPerConnection = int32(h2.MaxReceiveBufferPerConnection)
}
if h2.MaxReceiveBufferPerStream != 0 {
conf.MaxUploadBufferPerStream = int32(h2.MaxReceiveBufferPerStream)
}
if h2.SendPingTimeout != 0 {
conf.SendPingTimeout = h2.SendPingTimeout
}
if h2.PingTimeout != 0 {
conf.PingTimeout = h2.PingTimeout
}
if h2.WriteByteTimeout != 0 {
conf.WriteByteTimeout = h2.WriteByteTimeout
}
if h2.PermitProhibitedCipherSuites {
conf.PermitProhibitedCipherSuites = true
}
if h2.CountError != nil {
conf.CountError = h2.CountError
}
}
// Copyright 2025 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.
//go:build go1.26
package http2
import (
"net/http"
)
func http2ConfigStrictMaxConcurrentRequests(h2 *http.HTTP2Config) bool {
return h2.StrictMaxConcurrentRequests
}
// 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 dataChunkPools = [...]sync.Pool{
{New: func() interface{} { return new([1 << 10]byte) }},
{New: func() interface{} { return new([2 << 10]byte) }},
{New: func() interface{} { return new([4 << 10]byte) }},
{New: func() interface{} { return new([8 << 10]byte) }},
{New: func() interface{} { return new([16 << 10]byte) }},
}
func getDataBufferChunk(size int64) []byte {
switch {
case size <= 1<<10:
return dataChunkPools[0].Get().(*[1 << 10]byte)[:]
case size <= 2<<10:
return dataChunkPools[1].Get().(*[2 << 10]byte)[:]
case size <= 4<<10:
return dataChunkPools[2].Get().(*[4 << 10]byte)[:]
case size <= 8<<10:
return dataChunkPools[3].Get().(*[8 << 10]byte)[:]
default:
return dataChunkPools[4].Get().(*[16 << 10]byte)[:]
}
}
func putDataBufferChunk(p []byte) {
switch len(p) {
case 1 << 10:
dataChunkPools[0].Put((*[1 << 10]byte)(p))
case 2 << 10:
dataChunkPools[1].Put((*[2 << 10]byte)(p))
case 4 << 10:
dataChunkPools[2].Put((*[4 << 10]byte)(p))
case 8 << 10:
dataChunkPools[3].Put((*[8 << 10]byte)(p))
case 16 << 10:
dataChunkPools[4].Put((*[16 << 10]byte)(p))
default:
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
}
// 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"
)
// An ErrCode is an unsigned 32-bit error code as defined in the HTTP/2 spec.
type ErrCode uint32
const (
ErrCodeNo ErrCode = 0x0
ErrCodeProtocol ErrCode = 0x1
ErrCodeInternal ErrCode = 0x2
ErrCodeFlowControl ErrCode = 0x3
ErrCodeSettingsTimeout ErrCode = 0x4
ErrCodeStreamClosed ErrCode = 0x5
ErrCodeFrameSize ErrCode = 0x6
ErrCodeRefusedStream ErrCode = 0x7
ErrCodeCancel ErrCode = 0x8
ErrCodeCompression ErrCode = 0x9
ErrCodeConnect ErrCode = 0xa
ErrCodeEnhanceYourCalm ErrCode = 0xb
ErrCodeInadequateSecurity ErrCode = 0xc
ErrCodeHTTP11Required ErrCode = 0xd
)
var errCodeName = map[ErrCode]string{
ErrCodeNo: "NO_ERROR",
ErrCodeProtocol: "PROTOCOL_ERROR",
ErrCodeInternal: "INTERNAL_ERROR",
ErrCodeFlowControl: "FLOW_CONTROL_ERROR",
ErrCodeSettingsTimeout: "SETTINGS_TIMEOUT",
ErrCodeStreamClosed: "STREAM_CLOSED",
ErrCodeFrameSize: "FRAME_SIZE_ERROR",
ErrCodeRefusedStream: "REFUSED_STREAM",
ErrCodeCancel: "CANCEL",
ErrCodeCompression: "COMPRESSION_ERROR",
ErrCodeConnect: "CONNECT_ERROR",
ErrCodeEnhanceYourCalm: "ENHANCE_YOUR_CALM",
ErrCodeInadequateSecurity: "INADEQUATE_SECURITY",
ErrCodeHTTP11Required: "HTTP_1_1_REQUIRED",
}
func (e ErrCode) String() string {
if s, ok := errCodeName[e]; ok {
return s
}
return fmt.Sprintf("unknown error code 0x%x", uint32(e))
}
func (e ErrCode) stringToken() string {
if s, ok := errCodeName[e]; ok {
return s
}
return fmt.Sprintf("ERR_UNKNOWN_%d", uint32(e))
}
// ConnectionError is an error that results in the termination of the
// entire connection.
type ConnectionError ErrCode
func (e ConnectionError) Error() string { return fmt.Sprintf("connection error: %s", ErrCode(e)) }
// StreamError is an error that only affects one stream within an
// HTTP/2 connection.
type StreamError struct {
StreamID uint32
Code ErrCode
Cause error // optional additional detail
}
// errFromPeer is a sentinel error value for StreamError.Cause to
// indicate that the StreamError was sent from the peer over the wire
// and wasn't locally generated in the Transport.
var errFromPeer = errors.New("received from peer")
func streamError(id uint32, code ErrCode) StreamError {
return StreamError{StreamID: id, Code: code}
}
func (e StreamError) Error() string {
if e.Cause != nil {
return fmt.Sprintf("stream error: stream ID %d; %v; %v", e.StreamID, e.Code, e.Cause)
}
return fmt.Sprintf("stream error: stream ID %d; %v", e.StreamID, e.Code)
}
// 6.9.1 The Flow Control Window
// "If a sender receives a WINDOW_UPDATE that causes a flow control
// window to exceed this maximum it MUST terminate either the stream
// or the connection, as appropriate. For streams, [...]; for the
// connection, a GOAWAY frame with a FLOW_CONTROL_ERROR code."
type goAwayFlowError struct{}
func (goAwayFlowError) Error() string { return "connection exceeded flow control window size" }
// connError represents an HTTP/2 ConnectionError error code, along
// with a string (for debugging) explaining why.
//
// Errors of this type are only returned by the frame parser functions
// and converted into ConnectionError(Code), after stashing away
// the Reason into the Framer's errDetail field, accessible via
// the (*Framer).ErrorDetail method.
type connError struct {
Code ErrCode // the ConnectionError error code
Reason string // additional reason
}
func (e connError) Error() string {
return fmt.Sprintf("http2: connection error: %v: %v", e.Code, e.Reason)
}
type pseudoHeaderError string
func (e pseudoHeaderError) Error() string {
return fmt.Sprintf("invalid pseudo-header %q", string(e))
}
type duplicatePseudoHeaderError string
func (e duplicatePseudoHeaderError) Error() string {
return fmt.Sprintf("duplicate pseudo-header %q", string(e))
}
type headerFieldNameError string
func (e headerFieldNameError) Error() string {
return fmt.Sprintf("invalid header field name %q", string(e))
}
type headerFieldValueError string
func (e headerFieldValueError) Error() string {
return fmt.Sprintf("invalid header field value for %q", string(e))
}
var (
errMixPseudoHeaderTypes = errors.New("mix of request and response pseudo headers")
errPseudoAfterRegular = errors.New("pseudo header field after regular")
)
// 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.
// Flow control
package http2
// inflowMinRefresh is the minimum number of bytes we'll send for a
// flow control window update.
const inflowMinRefresh = 4 << 10
// inflow accounts for an inbound flow control window.
// It tracks both the latest window sent to the peer (used for enforcement)
// and the accumulated unsent window.
type inflow struct {
avail int32
unsent int32
}
// init sets the initial window.
func (f *inflow) init(n int32) {
f.avail = n
}
// add adds n bytes to the window, with a maximum window size of max,
// indicating that the peer can now send us more data.
// For example, the user read from a {Request,Response} body and consumed
// some of the buffered data, so the peer can now send more.
// It returns the number of bytes to send in a WINDOW_UPDATE frame to the peer.
// Window updates are accumulated and sent when the unsent capacity
// is at least inflowMinRefresh or will at least double the peer's available window.
func (f *inflow) add(n int) (connAdd int32) {
if n < 0 {
panic("negative update")
}
unsent := int64(f.unsent) + int64(n)
// "A sender MUST NOT allow a flow-control window to exceed 2^31-1 octets."
// RFC 7540 Section 6.9.1.
const maxWindow = 1<<31 - 1
if unsent+int64(f.avail) > maxWindow {
panic("flow control update exceeds maximum window size")
}
f.unsent = int32(unsent)
if f.unsent < inflowMinRefresh && f.unsent < f.avail {
// If there aren't at least inflowMinRefresh bytes of window to send,
// and this update won't at least double the window, buffer the update for later.
return 0
}
f.avail += f.unsent
f.unsent = 0
return int32(unsent)
}
// take attempts to take n bytes from the peer's flow control window.
// It reports whether the window has available capacity.
func (f *inflow) take(n uint32) bool {
if n > uint32(f.avail) {
return false
}
f.avail -= int32(n)
return true
}
// takeInflows attempts to take n bytes from two inflows,
// typically connection-level and stream-level flows.
// It reports whether both windows have available capacity.
func takeInflows(f1, f2 *inflow, n uint32) bool {
if n > uint32(f1.avail) || n > uint32(f2.avail) {
return false
}
f1.avail -= int32(n)
f2.avail -= int32(n)
return true
}
// outflow is the outbound flow control window's size.
type outflow struct {
_ incomparable
// n is the number of DATA bytes we're allowed to send.
// An outflow is kept both on a conn and a per-stream.
n int32
// conn points to the shared connection-level outflow that is
// shared by all streams on that conn. It is nil for the outflow
// that's on the conn directly.
conn *outflow
}
func (f *outflow) setConnFlow(cf *outflow) { f.conn = cf }
func (f *outflow) available() int32 {
n := f.n
if f.conn != nil && f.conn.n < n {
n = f.conn.n
}
return n
}
func (f *outflow) take(n int32) {
if n > f.available() {
panic("internal error: took too much")
}
f.n -= n
if f.conn != nil {
f.conn.n -= n
}
}
// add adds n bytes (positive or negative) to the flow control window.
// It returns false if the sum would exceed 2^31-1.
func (f *outflow) add(n int32) bool {
sum := f.n + n
if (sum > n) == (f.n > 0) {
f.n = sum
return true
}
return false
}
// 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 (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"log"
"strings"
"sync"
"golang.org/x/net/http/httpguts"
"golang.org/x/net/http2/hpack"
)
const frameHeaderLen = 9
var padZeros = make([]byte, 255) // zeros for padding
// A FrameType is a registered frame type as defined in
// https://httpwg.org/specs/rfc7540.html#rfc.section.11.2
type FrameType uint8
const (
FrameData FrameType = 0x0
FrameHeaders FrameType = 0x1
FramePriority FrameType = 0x2
FrameRSTStream FrameType = 0x3
FrameSettings FrameType = 0x4
FramePushPromise FrameType = 0x5
FramePing FrameType = 0x6
FrameGoAway FrameType = 0x7
FrameWindowUpdate FrameType = 0x8
FrameContinuation FrameType = 0x9
)
var frameNames = [...]string{
FrameData: "DATA",
FrameHeaders: "HEADERS",
FramePriority: "PRIORITY",
FrameRSTStream: "RST_STREAM",
FrameSettings: "SETTINGS",
FramePushPromise: "PUSH_PROMISE",
FramePing: "PING",
FrameGoAway: "GOAWAY",
FrameWindowUpdate: "WINDOW_UPDATE",
FrameContinuation: "CONTINUATION",
}
func (t FrameType) String() string {
if int(t) < len(frameNames) {
return frameNames[t]
}
return fmt.Sprintf("UNKNOWN_FRAME_TYPE_%d", t)
}
// Flags is a bitmask of HTTP/2 flags.
// The meaning of flags varies depending on the frame type.
type Flags uint8
// Has reports whether f contains all (0 or more) flags in v.
func (f Flags) Has(v Flags) bool {
return (f & v) == v
}
// Frame-specific FrameHeader flag bits.
const (
// Data Frame
FlagDataEndStream Flags = 0x1
FlagDataPadded Flags = 0x8
// Headers Frame
FlagHeadersEndStream Flags = 0x1
FlagHeadersEndHeaders Flags = 0x4
FlagHeadersPadded Flags = 0x8
FlagHeadersPriority Flags = 0x20
// Settings Frame
FlagSettingsAck Flags = 0x1
// Ping Frame
FlagPingAck Flags = 0x1
// Continuation Frame
FlagContinuationEndHeaders Flags = 0x4
FlagPushPromiseEndHeaders Flags = 0x4
FlagPushPromisePadded Flags = 0x8
)
var flagName = map[FrameType]map[Flags]string{
FrameData: {
FlagDataEndStream: "END_STREAM",
FlagDataPadded: "PADDED",
},
FrameHeaders: {
FlagHeadersEndStream: "END_STREAM",
FlagHeadersEndHeaders: "END_HEADERS",
FlagHeadersPadded: "PADDED",
FlagHeadersPriority: "PRIORITY",
},
FrameSettings: {
FlagSettingsAck: "ACK",
},
FramePing: {
FlagPingAck: "ACK",
},
FrameContinuation: {
FlagContinuationEndHeaders: "END_HEADERS",
},
FramePushPromise: {
FlagPushPromiseEndHeaders: "END_HEADERS",
FlagPushPromisePadded: "PADDED",
},
}
// 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(fc *frameCache, fh FrameHeader, countError func(string), payload []byte) (Frame, error)
var frameParsers = [...]frameParser{
FrameData: parseDataFrame,
FrameHeaders: parseHeadersFrame,
FramePriority: parsePriorityFrame,
FrameRSTStream: parseRSTStreamFrame,
FrameSettings: parseSettingsFrame,
FramePushPromise: parsePushPromise,
FramePing: parsePingFrame,
FrameGoAway: parseGoAwayFrame,
FrameWindowUpdate: parseWindowUpdateFrame,
FrameContinuation: parseContinuationFrame,
}
func typeFrameParser(t FrameType) frameParser {
if int(t) < len(frameParsers) {
return frameParsers[t]
}
return parseUnknownFrame
}
// A FrameHeader is the 9 byte header of all HTTP/2 frames.
//
// See https://httpwg.org/specs/rfc7540.html#FrameHeader
type FrameHeader struct {
valid bool // caller can access []byte fields in the Frame
// Type is the 1 byte frame type. There are ten standard frame
// types, but extension frame types may be written by WriteRawFrame
// and will be returned by ReadFrame (as UnknownFrame).
Type FrameType
// Flags are the 1 byte of 8 potential bit flags per frame.
// They are specific to the frame type.
Flags Flags
// Length is the length of the frame, not including the 9 byte header.
// The maximum size is one byte less than 16MB (uint24), but only
// frames up to 16KB are allowed without peer agreement.
Length uint32
// StreamID is which stream this frame is for. Certain frames
// are not stream-specific, in which case this field is 0.
StreamID uint32
}
// Header returns h. It exists so FrameHeaders can be embedded in other
// specific frame types and implement the Frame interface.
func (h FrameHeader) Header() FrameHeader { return h }
func (h FrameHeader) String() string {
var buf bytes.Buffer
buf.WriteString("[FrameHeader ")
h.writeDebug(&buf)
buf.WriteByte(']')
return buf.String()
}
func (h FrameHeader) writeDebug(buf *bytes.Buffer) {
buf.WriteString(h.Type.String())
if h.Flags != 0 {
buf.WriteString(" flags=")
set := 0
for i := uint8(0); i < 8; i++ {
if h.Flags&(1<<i) == 0 {
continue
}
set++
if set > 1 {
buf.WriteByte('|')
}
name := flagName[h.Type][Flags(1<<i)]
if name != "" {
buf.WriteString(name)
} else {
fmt.Fprintf(buf, "0x%x", 1<<i)
}
}
}
if h.StreamID != 0 {
fmt.Fprintf(buf, " stream=%d", h.StreamID)
}
fmt.Fprintf(buf, " len=%d", h.Length)
}
func (h *FrameHeader) checkValid() {
if !h.valid {
panic("Frame accessor called on non-owned Frame")
}
}
func (h *FrameHeader) invalidate() { h.valid = false }
// frame header bytes.
// Used only by ReadFrameHeader.
var fhBytes = sync.Pool{
New: func() interface{} {
buf := make([]byte, frameHeaderLen)
return &buf
},
}
func invalidHTTP1LookingFrameHeader() FrameHeader {
fh, _ := readFrameHeader(make([]byte, frameHeaderLen), strings.NewReader("HTTP/1.1 "))
return fh
}
// ReadFrameHeader reads 9 bytes from r and returns a FrameHeader.
// Most users should use Framer.ReadFrame instead.
func ReadFrameHeader(r io.Reader) (FrameHeader, error) {
bufp := fhBytes.Get().(*[]byte)
defer fhBytes.Put(bufp)
return readFrameHeader(*bufp, r)
}
func readFrameHeader(buf []byte, r io.Reader) (FrameHeader, error) {
_, err := io.ReadFull(r, buf[:frameHeaderLen])
if err != nil {
return FrameHeader{}, err
}
return FrameHeader{
Length: (uint32(buf[0])<<16 | uint32(buf[1])<<8 | uint32(buf[2])),
Type: FrameType(buf[3]),
Flags: Flags(buf[4]),
StreamID: binary.BigEndian.Uint32(buf[5:]) & (1<<31 - 1),
valid: true,
}, nil
}
// A Frame is the base interface implemented by all frame types.
// Callers will generally type-assert the specific frame type:
// *HeadersFrame, *SettingsFrame, *WindowUpdateFrame, etc.
//
// Frames are only valid until the next call to Framer.ReadFrame.
type Frame interface {
Header() FrameHeader
// invalidate is called by Framer.ReadFrame to make this
// frame's buffers as being invalid, since the subsequent
// frame will reuse them.
invalidate()
}
// A Framer reads and writes Frames.
type Framer struct {
r io.Reader
lastFrame Frame
errDetail error
// countError is a non-nil func that's called on a frame parse
// error with some unique error path token. It's initialized
// from Transport.CountError or Server.CountError.
countError func(errToken string)
// lastHeaderStream is non-zero if the last frame was an
// unfinished HEADERS/CONTINUATION.
lastHeaderStream uint32
// lastFrameType holds the type of the last frame for verifying frame order.
lastFrameType FrameType
maxReadSize uint32
headerBuf [frameHeaderLen]byte
// TODO: let getReadBuf be configurable, and use a less memory-pinning
// allocator in server.go to minimize memory pinned for many idle conns.
// Will probably also need to make frame invalidation have a hook too.
getReadBuf func(size uint32) []byte
readBuf []byte // cache for default getReadBuf
maxWriteSize uint32 // zero means unlimited; TODO: implement
w io.Writer
wbuf []byte
// AllowIllegalWrites permits the Framer's Write methods to
// write frames that do not conform to the HTTP/2 spec. This
// permits using the Framer to test other HTTP/2
// implementations' conformance to the spec.
// If false, the Write methods will prefer to return an error
// rather than comply.
AllowIllegalWrites bool
// AllowIllegalReads permits the Framer's ReadFrame method
// to return non-compliant frames or frame orders.
// This is for testing and permits using the Framer to test
// other HTTP/2 implementations' conformance to the spec.
// It is not compatible with ReadMetaHeaders.
AllowIllegalReads bool
// ReadMetaHeaders if non-nil causes ReadFrame to merge
// HEADERS and CONTINUATION frames together and return
// MetaHeadersFrame instead.
ReadMetaHeaders *hpack.Decoder
// MaxHeaderListSize is the http2 MAX_HEADER_LIST_SIZE.
// It's used only if ReadMetaHeaders is set; 0 means a sane default
// (currently 16MB)
// If the limit is hit, MetaHeadersFrame.Truncated is set true.
MaxHeaderListSize uint32
// TODO: track which type of frame & with which flags was sent
// 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.
logReads, logWrites bool
debugFramer *Framer // only use for logging written writes
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 {
if fr.MaxHeaderListSize == 0 {
return 16 << 20 // sane default, per docs
}
return fr.MaxHeaderListSize
}
func (f *Framer) startWrite(ftype FrameType, flags Flags, streamID uint32) {
// Write the FrameHeader.
f.wbuf = append(f.wbuf[:0],
0, // 3 bytes of length, filled in endWrite
0,
0,
byte(ftype),
byte(flags),
byte(streamID>>24),
byte(streamID>>16),
byte(streamID>>8),
byte(streamID))
}
func (f *Framer) endWrite() error {
// Now that we know the final size, fill in the FrameHeader in
// the space previously reserved for it. Abuse append.
length := len(f.wbuf) - frameHeaderLen
if length >= (1 << 24) {
return ErrFrameTooLarge
}
_ = append(f.wbuf[:0],
byte(length>>16),
byte(length>>8),
byte(length))
if f.logWrites {
f.logWrite()
}
n, err := f.w.Write(f.wbuf)
if err == nil && n != len(f.wbuf) {
err = io.ErrShortWrite
}
return err
}
func (f *Framer) logWrite() {
if f.debugFramer == nil {
f.debugFramerBuf = new(bytes.Buffer)
f.debugFramer = NewFramer(nil, f.debugFramerBuf)
f.debugFramer.logReads = false // we log it ourselves, saying "wrote" below
// Let us read anything, even if we accidentally wrote it
// in the wrong order:
f.debugFramer.AllowIllegalReads = true
}
f.debugFramerBuf.Write(f.wbuf)
fr, err := f.debugFramer.ReadFrame()
if err != nil {
f.debugWriteLoggerf("http2: Framer %p: failed to decode just-written frame", f)
return
}
f.debugWriteLoggerf("http2: Framer %p: wrote %v", f, summarizeFrame(fr))
}
func (f *Framer) writeByte(v byte) { f.wbuf = append(f.wbuf, v) }
func (f *Framer) writeBytes(v []byte) { f.wbuf = append(f.wbuf, v...) }
func (f *Framer) writeUint16(v uint16) { f.wbuf = append(f.wbuf, byte(v>>8), byte(v)) }
func (f *Framer) writeUint32(v uint32) {
f.wbuf = append(f.wbuf, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
}
const (
minMaxFrameSize = 1 << 14
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{
w: w,
r: r,
countError: func(string) {},
logReads: logFrameReads,
logWrites: logFrameWrites,
debugReadLoggerf: log.Printf,
debugWriteLoggerf: log.Printf,
}
fr.getReadBuf = func(size uint32) []byte {
if cap(fr.readBuf) >= int(size) {
return fr.readBuf[:size]
}
fr.readBuf = make([]byte, size)
return fr.readBuf
}
fr.SetMaxReadFrameSize(maxFrameSize)
return fr
}
// SetMaxReadFrameSize sets the maximum size of a frame
// that will be read by a subsequent call to ReadFrame.
// It is the caller's responsibility to advertise this
// limit with a SETTINGS frame.
func (fr *Framer) SetMaxReadFrameSize(v uint32) {
if v > maxFrameSize {
v = maxFrameSize
}
fr.maxReadSize = v
}
// ErrorDetail returns a more detailed error of the last error
// returned by Framer.ReadFrame. For instance, if ReadFrame
// returns a StreamError with code PROTOCOL_ERROR, ErrorDetail
// will say exactly what was invalid. ErrorDetail is not guaranteed
// to return a non-nil value and like the rest of the http2 package,
// its return value is not protected by an API compatibility promise.
// ErrorDetail is reset after the next call to ReadFrame.
func (fr *Framer) ErrorDetail() error {
return fr.errDetail
}
// ErrFrameTooLarge is returned from Framer.ReadFrame when the peer
// sends a frame that is larger than declared with SetMaxReadFrameSize.
var ErrFrameTooLarge = errors.New("http2: frame too large")
// terminalReadFrameError reports whether err is an unrecoverable
// error from ReadFrame and no other frames should be read.
func terminalReadFrameError(err error) bool {
if _, ok := err.(StreamError); ok {
return false
}
return err != nil
}
// ReadFrameHeader reads the header of the next frame.
// It reads the 9-byte fixed frame header, and does not read any portion of the
// frame payload. The caller is responsible for consuming the payload, either
// with ReadFrameForHeader or directly from the Framer's io.Reader.
//
// If the frame is larger than previously set with SetMaxReadFrameSize, it
// returns the frame header and ErrFrameTooLarge.
//
// If the returned FrameHeader.StreamID is non-zero, it indicates the stream
// responsible for the error.
func (fr *Framer) ReadFrameHeader() (FrameHeader, error) {
fr.errDetail = nil
fh, err := readFrameHeader(fr.headerBuf[:], fr.r)
if err != nil {
return fh, err
}
if fh.Length > fr.maxReadSize {
if fh == invalidHTTP1LookingFrameHeader() {
return fh, fmt.Errorf("http2: failed reading the frame payload: %w, note that the frame header looked like an HTTP/1.1 header", ErrFrameTooLarge)
}
return fh, ErrFrameTooLarge
}
if err := fr.checkFrameOrder(fh); err != nil {
return fh, err
}
return fh, nil
}
// ReadFrameForHeader reads the payload for the frame with the given FrameHeader.
//
// It behaves identically to ReadFrame, other than not checking the maximum
// frame size.
func (fr *Framer) ReadFrameForHeader(fh FrameHeader) (Frame, error) {
if fr.lastFrame != nil {
fr.lastFrame.invalidate()
}
payload := fr.getReadBuf(fh.Length)
if _, err := io.ReadFull(fr.r, payload); err != nil {
if fh == invalidHTTP1LookingFrameHeader() {
return nil, fmt.Errorf("http2: failed reading the frame payload: %w, note that the frame header looked like an HTTP/1.1 header", err)
}
return nil, err
}
f, err := typeFrameParser(fh.Type)(fr.frameCache, fh, fr.countError, payload)
if err != nil {
if ce, ok := err.(connError); ok {
return nil, fr.connError(ce.Code, ce.Reason)
}
return nil, err
}
fr.lastFrame = f
if fr.logReads {
fr.debugReadLoggerf("http2: Framer %p: read %v", fr, summarizeFrame(f))
}
if fh.Type == FrameHeaders && fr.ReadMetaHeaders != nil {
return fr.readMetaFrame(f.(*HeadersFrame))
}
return f, nil
}
// ReadFrame reads a single frame. The returned Frame is only valid
// until the next call to ReadFrame or ReadFrameBodyForHeader.
//
// If the frame is larger than previously set with SetMaxReadFrameSize, the
// returned error is ErrFrameTooLarge. Other errors may be of type
// ConnectionError, StreamError, or anything else from the underlying
// reader.
//
// If ReadFrame returns an error and a non-nil Frame, the Frame's StreamID
// indicates the stream responsible for the error.
func (fr *Framer) ReadFrame() (Frame, error) {
fh, err := fr.ReadFrameHeader()
if err != nil {
return nil, err
}
return fr.ReadFrameForHeader(fh)
}
// connError returns ConnectionError(code) but first
// stashes away a public reason to the caller can optionally relay it
// to the peer before hanging up on them. This might help others debug
// their implementations.
func (fr *Framer) connError(code ErrCode, reason string) error {
fr.errDetail = errors.New(reason)
return ConnectionError(code)
}
// checkFrameOrder reports an error if f is an invalid frame to return
// next from ReadFrame. Mostly it checks whether HEADERS and
// CONTINUATION frames are contiguous.
func (fr *Framer) checkFrameOrder(fh FrameHeader) error {
lastType := fr.lastFrameType
fr.lastFrameType = fh.Type
if fr.AllowIllegalReads {
return nil
}
if fr.lastHeaderStream != 0 {
if fh.Type != FrameContinuation {
return fr.connError(ErrCodeProtocol,
fmt.Sprintf("got %s for stream %d; expected CONTINUATION following %s for stream %d",
fh.Type, fh.StreamID,
lastType, fr.lastHeaderStream))
}
if fh.StreamID != fr.lastHeaderStream {
return fr.connError(ErrCodeProtocol,
fmt.Sprintf("got CONTINUATION for stream %d; expected stream %d",
fh.StreamID, fr.lastHeaderStream))
}
} else if fh.Type == FrameContinuation {
return fr.connError(ErrCodeProtocol, fmt.Sprintf("unexpected CONTINUATION for stream %d", fh.StreamID))
}
switch fh.Type {
case FrameHeaders, FrameContinuation:
if fh.Flags.Has(FlagHeadersEndHeaders) {
fr.lastHeaderStream = 0
} else {
fr.lastHeaderStream = fh.StreamID
}
}
return nil
}
// A DataFrame conveys arbitrary, variable-length sequences of octets
// associated with a stream.
// See https://httpwg.org/specs/rfc7540.html#rfc.section.6.1
type DataFrame struct {
FrameHeader
data []byte
}
func (f *DataFrame) StreamEnded() bool {
return f.FrameHeader.Flags.Has(FlagDataEndStream)
}
// Data returns the frame's data octets, not including any padding
// size byte or padding suffix bytes.
// The caller must not retain the returned memory past the next
// call to ReadFrame.
func (f *DataFrame) Data() []byte {
f.checkValid()
return f.data
}
func parseDataFrame(fc *frameCache, fh FrameHeader, countError func(string), 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
// field is 0x0, the recipient MUST respond with a
// connection error (Section 5.4.1) of type
// PROTOCOL_ERROR.
countError("frame_data_stream_0")
return nil, connError{ErrCodeProtocol, "DATA frame with stream ID 0"}
}
f := fc.getDataFrame()
f.FrameHeader = fh
var padSize byte
if fh.Flags.Has(FlagDataPadded) {
var err error
payload, padSize, err = readByte(payload)
if err != nil {
countError("frame_data_pad_byte_short")
return nil, err
}
}
if int(padSize) > len(payload) {
// If the length of the padding is greater than the
// length of the frame payload, the recipient MUST
// treat this as a connection error.
// Filed: https://github.com/http2/http2-spec/issues/610
countError("frame_data_pad_too_big")
return nil, connError{ErrCodeProtocol, "pad size larger than data payload"}
}
f.data = payload[:len(payload)-int(padSize)]
return f, nil
}
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 {
return streamID&(1<<31) == 0
}
func validStreamID(streamID uint32) bool {
return streamID != 0 && streamID&(1<<31) == 0
}
// WriteData writes a DATA frame.
//
// It will perform exactly one Write to the underlying Writer.
// It is the caller's responsibility not to violate the maximum frame size
// and to not call other Write methods concurrently.
func (f *Framer) WriteData(streamID uint32, endStream bool, data []byte) error {
return f.WriteDataPadded(streamID, endStream, data, nil)
}
// WriteDataPadded writes a DATA frame with optional padding.
//
// 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
// and to not call other Write methods concurrently.
func (f *Framer) WriteDataPadded(streamID uint32, endStream bool, data, pad []byte) error {
if err := f.startWriteDataPadded(streamID, endStream, data, pad); err != nil {
return err
}
return f.endWrite()
}
// startWriteDataPadded is WriteDataPadded, but only writes the frame to the Framer's internal buffer.
// The caller should call endWrite to flush the frame to the underlying writer.
func (f *Framer) startWriteDataPadded(streamID uint32, endStream bool, data, pad []byte) error {
if !validStreamID(streamID) && !f.AllowIllegalWrites {
return errStreamID
}
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 {
flags |= FlagDataEndStream
}
if pad != nil {
flags |= FlagDataPadded
}
f.startWrite(FrameData, flags, streamID)
if pad != nil {
f.wbuf = append(f.wbuf, byte(len(pad)))
}
f.wbuf = append(f.wbuf, data...)
f.wbuf = append(f.wbuf, pad...)
return nil
}
// A SettingsFrame conveys configuration parameters that affect how
// endpoints communicate, such as preferences and constraints on peer
// behavior.
//
// See https://httpwg.org/specs/rfc7540.html#SETTINGS
type SettingsFrame struct {
FrameHeader
p []byte
}
func parseSettingsFrame(_ *frameCache, fh FrameHeader, countError func(string), 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 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
// FRAME_SIZE_ERROR.
countError("frame_settings_ack_with_length")
return nil, ConnectionError(ErrCodeFrameSize)
}
if fh.StreamID != 0 {
// SETTINGS frames always apply to a connection,
// 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
// respond with a connection error (Section 5.4.1) of
// type PROTOCOL_ERROR.
countError("frame_settings_has_stream")
return nil, ConnectionError(ErrCodeProtocol)
}
if len(p)%6 != 0 {
countError("frame_settings_mod_6")
// Expecting even number of 6 byte settings.
return nil, ConnectionError(ErrCodeFrameSize)
}
f := &SettingsFrame{FrameHeader: fh, p: p}
if v, ok := f.Value(SettingInitialWindowSize); ok && v > (1<<31)-1 {
countError("frame_settings_window_size_too_big")
// Values above the maximum flow control window size of 2^31 - 1 MUST
// be treated as a connection error (Section 5.4.1) of type
// FLOW_CONTROL_ERROR.
return nil, ConnectionError(ErrCodeFlowControl)
}
return f, nil
}
func (f *SettingsFrame) IsAck() bool {
return f.FrameHeader.Flags.Has(FlagSettingsAck)
}
func (f *SettingsFrame) Value(id SettingID) (v uint32, ok bool) {
f.checkValid()
for i := 0; i < f.NumSettings(); i++ {
if s := f.Setting(i); s.ID == id {
return s.Val, true
}
}
return 0, false
}
// Setting returns the setting from the frame at the given 0-based index.
// The index must be >= 0 and less than f.NumSettings().
func (f *SettingsFrame) Setting(i int) Setting {
buf := f.p
return Setting{
ID: SettingID(binary.BigEndian.Uint16(buf[i*6 : i*6+2])),
Val: binary.BigEndian.Uint32(buf[i*6+2 : i*6+6]),
}
}
func (f *SettingsFrame) NumSettings() int { return len(f.p) / 6 }
// HasDuplicates reports whether f contains any duplicate setting IDs.
func (f *SettingsFrame) HasDuplicates() bool {
num := f.NumSettings()
if num == 0 {
return false
}
// If it's small enough (the common case), just do the n^2
// thing and avoid a map allocation.
if num < 10 {
for i := 0; i < num; i++ {
idi := f.Setting(i).ID
for j := i + 1; j < num; j++ {
idj := f.Setting(j).ID
if idi == idj {
return true
}
}
}
return false
}
seen := map[SettingID]bool{}
for i := 0; i < num; i++ {
id := f.Setting(i).ID
if seen[id] {
return true
}
seen[id] = true
}
return false
}
// ForeachSetting runs fn for each setting.
// It stops and returns the first error.
func (f *SettingsFrame) ForeachSetting(fn func(Setting) error) error {
f.checkValid()
for i := 0; i < f.NumSettings(); i++ {
if err := fn(f.Setting(i)); err != nil {
return err
}
}
return nil
}
// WriteSettings writes a SETTINGS frame with zero or more settings
// specified and the ACK bit not set.
//
// It will perform exactly one Write to the underlying Writer.
// It is the caller's responsibility to not call other Write methods concurrently.
func (f *Framer) WriteSettings(settings ...Setting) error {
f.startWrite(FrameSettings, 0, 0)
for _, s := range settings {
f.writeUint16(uint16(s.ID))
f.writeUint32(s.Val)
}
return f.endWrite()
}
// WriteSettingsAck writes an empty SETTINGS frame with the ACK bit set.
//
// It will perform exactly one Write to the underlying Writer.
// It is the caller's responsibility to not call other Write methods concurrently.
func (f *Framer) WriteSettingsAck() error {
f.startWrite(FrameSettings, FlagSettingsAck, 0)
return f.endWrite()
}
// A PingFrame is a mechanism for measuring a minimal round trip time
// from the sender, as well as determining whether an idle connection
// is still functional.
// See https://httpwg.org/specs/rfc7540.html#rfc.section.6.7
type PingFrame struct {
FrameHeader
Data [8]byte
}
func (f *PingFrame) IsAck() bool { return f.Flags.Has(FlagPingAck) }
func parsePingFrame(_ *frameCache, fh FrameHeader, countError func(string), payload []byte) (Frame, error) {
if len(payload) != 8 {
countError("frame_ping_length")
return nil, ConnectionError(ErrCodeFrameSize)
}
if fh.StreamID != 0 {
countError("frame_ping_has_stream")
return nil, ConnectionError(ErrCodeProtocol)
}
f := &PingFrame{FrameHeader: fh}
copy(f.Data[:], payload)
return f, nil
}
func (f *Framer) WritePing(ack bool, data [8]byte) error {
var flags Flags
if ack {
flags = FlagPingAck
}
f.startWrite(FramePing, flags, 0)
f.writeBytes(data[:])
return f.endWrite()
}
// A GoAwayFrame informs the remote peer to stop creating streams on this connection.
// See https://httpwg.org/specs/rfc7540.html#rfc.section.6.8
type GoAwayFrame struct {
FrameHeader
LastStreamID uint32
ErrCode ErrCode
debugData []byte
}
// DebugData returns any debug data in the GOAWAY frame. Its contents
// are not defined.
// The caller must not retain the returned memory past the next
// call to ReadFrame.
func (f *GoAwayFrame) DebugData() []byte {
f.checkValid()
return f.debugData
}
func parseGoAwayFrame(_ *frameCache, fh FrameHeader, countError func(string), p []byte) (Frame, error) {
if fh.StreamID != 0 {
countError("frame_goaway_has_stream")
return nil, ConnectionError(ErrCodeProtocol)
}
if len(p) < 8 {
countError("frame_goaway_short")
return nil, ConnectionError(ErrCodeFrameSize)
}
return &GoAwayFrame{
FrameHeader: fh,
LastStreamID: binary.BigEndian.Uint32(p[:4]) & (1<<31 - 1),
ErrCode: ErrCode(binary.BigEndian.Uint32(p[4:8])),
debugData: p[8:],
}, nil
}
func (f *Framer) WriteGoAway(maxStreamID uint32, code ErrCode, debugData []byte) error {
f.startWrite(FrameGoAway, 0, 0)
f.writeUint32(maxStreamID & (1<<31 - 1))
f.writeUint32(uint32(code))
f.writeBytes(debugData)
return f.endWrite()
}
// An UnknownFrame is the frame type returned when the frame type is unknown
// or no specific frame type parser exists.
type UnknownFrame struct {
FrameHeader
p []byte
}
// Payload returns the frame's payload (after the header). It is not
// valid to call this method after a subsequent call to
// Framer.ReadFrame, nor is it valid to retain the returned slice.
// The memory is owned by the Framer and is invalidated when the next
// frame is read.
func (f *UnknownFrame) Payload() []byte {
f.checkValid()
return f.p
}
func parseUnknownFrame(_ *frameCache, fh FrameHeader, countError func(string), p []byte) (Frame, error) {
return &UnknownFrame{fh, p}, nil
}
// A WindowUpdateFrame is used to implement flow control.
// See https://httpwg.org/specs/rfc7540.html#rfc.section.6.9
type WindowUpdateFrame struct {
FrameHeader
Increment uint32 // never read with high bit set
}
func parseWindowUpdateFrame(_ *frameCache, fh FrameHeader, countError func(string), p []byte) (Frame, error) {
if len(p) != 4 {
countError("frame_windowupdate_bad_len")
return nil, ConnectionError(ErrCodeFrameSize)
}
inc := binary.BigEndian.Uint32(p[:4]) & 0x7fffffff // mask off high reserved bit
if inc == 0 {
// A receiver MUST treat the receipt of a
// WINDOW_UPDATE frame with an flow control window
// increment of 0 as a stream error (Section 5.4.2) of
// type PROTOCOL_ERROR; errors on the connection flow
// control window MUST be treated as a connection
// error (Section 5.4.1).
if fh.StreamID == 0 {
countError("frame_windowupdate_zero_inc_conn")
return nil, ConnectionError(ErrCodeProtocol)
}
countError("frame_windowupdate_zero_inc_stream")
return nil, streamError(fh.StreamID, ErrCodeProtocol)
}
return &WindowUpdateFrame{
FrameHeader: fh,
Increment: inc,
}, nil
}
// WriteWindowUpdate writes a WINDOW_UPDATE frame.
// The increment value must be between 1 and 2,147,483,647, inclusive.
// If the Stream ID is zero, the window update applies to the
// connection as a whole.
func (f *Framer) WriteWindowUpdate(streamID, incr uint32) error {
// "The legal range for the increment to the flow control window is 1 to 2^31-1 (2,147,483,647) octets."
if (incr < 1 || incr > 2147483647) && !f.AllowIllegalWrites {
return errors.New("illegal window increment value")
}
f.startWrite(FrameWindowUpdate, 0, streamID)
f.writeUint32(incr)
return f.endWrite()
}
// A HeadersFrame is used to open a stream and additionally carries a
// header block fragment.
type HeadersFrame struct {
FrameHeader
// Priority is set if FlagHeadersPriority is set in the FrameHeader.
Priority PriorityParam
headerFragBuf []byte // not owned
}
func (f *HeadersFrame) HeaderBlockFragment() []byte {
f.checkValid()
return f.headerFragBuf
}
func (f *HeadersFrame) HeadersEnded() bool {
return f.FrameHeader.Flags.Has(FlagHeadersEndHeaders)
}
func (f *HeadersFrame) StreamEnded() bool {
return f.FrameHeader.Flags.Has(FlagHeadersEndStream)
}
func (f *HeadersFrame) HasPriority() bool {
return f.FrameHeader.Flags.Has(FlagHeadersPriority)
}
func parseHeadersFrame(_ *frameCache, fh FrameHeader, countError func(string), 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
// is received whose stream identifier field is 0x0, the recipient MUST
// respond with a connection error (Section 5.4.1) of type
// PROTOCOL_ERROR.
countError("frame_headers_zero_stream")
return nil, connError{ErrCodeProtocol, "HEADERS frame with stream ID 0"}
}
var padLength uint8
if fh.Flags.Has(FlagHeadersPadded) {
if p, padLength, err = readByte(p); err != nil {
countError("frame_headers_pad_short")
return
}
}
if fh.Flags.Has(FlagHeadersPriority) {
var v uint32
p, v, err = readUint32(p)
if err != nil {
countError("frame_headers_prio_short")
return nil, err
}
hf.Priority.StreamDep = v & 0x7fffffff
hf.Priority.Exclusive = (v != hf.Priority.StreamDep) // high bit was set
p, hf.Priority.Weight, err = readByte(p)
if err != nil {
countError("frame_headers_prio_weight_short")
return nil, err
}
}
if len(p)-int(padLength) < 0 {
countError("frame_headers_pad_too_big")
return nil, streamError(fh.StreamID, ErrCodeProtocol)
}
hf.headerFragBuf = p[:len(p)-int(padLength)]
return hf, nil
}
// HeadersFrameParam are the parameters for writing a HEADERS frame.
type HeadersFrameParam struct {
// StreamID is the required Stream ID to initiate.
StreamID uint32
// BlockFragment is part (or all) of a Header Block.
BlockFragment []byte
// EndStream indicates that the header block is the last that
// the endpoint will send for the identified stream. Setting
// this flag causes the stream to enter one of "half closed"
// states.
EndStream bool
// EndHeaders indicates that this frame contains an entire
// header block and is not followed by any
// CONTINUATION frames.
EndHeaders bool
// PadLength is the optional number of bytes of zeros to add
// to this frame.
PadLength uint8
// Priority, if non-zero, includes stream priority information
// in the HEADER frame.
Priority PriorityParam
}
// WriteHeaders writes a single HEADERS frame.
//
// This is a low-level header writing method. Encoding headers and
// splitting them into any necessary CONTINUATION frames is handled
// elsewhere.
//
// It will perform exactly one Write to the underlying Writer.
// It is the caller's responsibility to not call other Write methods concurrently.
func (f *Framer) WriteHeaders(p HeadersFrameParam) error {
if !validStreamID(p.StreamID) && !f.AllowIllegalWrites {
return errStreamID
}
var flags Flags
if p.PadLength != 0 {
flags |= FlagHeadersPadded
}
if p.EndStream {
flags |= FlagHeadersEndStream
}
if p.EndHeaders {
flags |= FlagHeadersEndHeaders
}
if !p.Priority.IsZero() {
flags |= FlagHeadersPriority
}
f.startWrite(FrameHeaders, flags, p.StreamID)
if p.PadLength != 0 {
f.writeByte(p.PadLength)
}
if !p.Priority.IsZero() {
v := p.Priority.StreamDep
if !validStreamIDOrZero(v) && !f.AllowIllegalWrites {
return errDepStreamID
}
if p.Priority.Exclusive {
v |= 1 << 31
}
f.writeUint32(v)
f.writeByte(p.Priority.Weight)
}
f.wbuf = append(f.wbuf, p.BlockFragment...)
f.wbuf = append(f.wbuf, padZeros[:p.PadLength]...)
return f.endWrite()
}
// A PriorityFrame specifies the sender-advised priority of a stream.
// See https://httpwg.org/specs/rfc7540.html#rfc.section.6.3
type PriorityFrame struct {
FrameHeader
PriorityParam
}
var defaultRFC9218Priority = PriorityParam{
incremental: 0,
urgency: 3,
}
// Note that HTTP/2 has had two different prioritization schemes, and
// PriorityParam struct below is a superset of both schemes. The exported
// symbols are from RFC 7540 and the non-exported ones are from RFC 9218.
// PriorityParam are the stream prioritization parameters.
type PriorityParam struct {
// StreamDep is a 31-bit stream identifier for the
// stream that this stream depends on. Zero means no
// dependency.
StreamDep uint32
// Exclusive is whether the dependency is exclusive.
Exclusive bool
// Weight is the stream's zero-indexed weight. It should be
// 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
// "The urgency (u) parameter value is Integer (see Section 3.3.1 of
// [STRUCTURED-FIELDS]), between 0 and 7 inclusive, in descending order of
// priority. The default is 3."
urgency uint8
// "The incremental (i) parameter value is Boolean (see Section 3.3.6 of
// [STRUCTURED-FIELDS]). It indicates if an HTTP response can be processed
// incrementally, i.e., provide some meaningful output as chunks of the
// response arrive."
//
// We use uint8 (i.e. 0 is false, 1 is true) instead of bool so we can
// avoid unnecessary type conversions and because either type takes 1 byte.
incremental uint8
}
func (p PriorityParam) IsZero() bool {
return p == PriorityParam{}
}
func parsePriorityFrame(_ *frameCache, fh FrameHeader, countError func(string), payload []byte) (Frame, error) {
if fh.StreamID == 0 {
countError("frame_priority_zero_stream")
return nil, connError{ErrCodeProtocol, "PRIORITY frame with stream ID 0"}
}
if len(payload) != 5 {
countError("frame_priority_bad_length")
return nil, connError{ErrCodeFrameSize, fmt.Sprintf("PRIORITY frame payload size was %d; want 5", len(payload))}
}
v := binary.BigEndian.Uint32(payload[:4])
streamID := v & 0x7fffffff // mask off high bit
return &PriorityFrame{
FrameHeader: fh,
PriorityParam: PriorityParam{
Weight: payload[4],
StreamDep: streamID,
Exclusive: streamID != v, // was high bit set?
},
}, nil
}
// WritePriority writes a PRIORITY frame.
//
// It will perform exactly one Write to the underlying Writer.
// It is the caller's responsibility to not call other Write methods concurrently.
func (f *Framer) WritePriority(streamID uint32, p PriorityParam) error {
if !validStreamID(streamID) && !f.AllowIllegalWrites {
return errStreamID
}
if !validStreamIDOrZero(p.StreamDep) {
return errDepStreamID
}
f.startWrite(FramePriority, 0, streamID)
v := p.StreamDep
if p.Exclusive {
v |= 1 << 31
}
f.writeUint32(v)
f.writeByte(p.Weight)
return f.endWrite()
}
// A RSTStreamFrame allows for abnormal termination of a stream.
// See https://httpwg.org/specs/rfc7540.html#rfc.section.6.4
type RSTStreamFrame struct {
FrameHeader
ErrCode ErrCode
}
func parseRSTStreamFrame(_ *frameCache, fh FrameHeader, countError func(string), p []byte) (Frame, error) {
if len(p) != 4 {
countError("frame_rststream_bad_len")
return nil, ConnectionError(ErrCodeFrameSize)
}
if fh.StreamID == 0 {
countError("frame_rststream_zero_stream")
return nil, ConnectionError(ErrCodeProtocol)
}
return &RSTStreamFrame{fh, ErrCode(binary.BigEndian.Uint32(p[:4]))}, nil
}
// WriteRSTStream writes a RST_STREAM frame.
//
// It will perform exactly one Write to the underlying Writer.
// It is the caller's responsibility to not call other Write methods concurrently.
func (f *Framer) WriteRSTStream(streamID uint32, code ErrCode) error {
if !validStreamID(streamID) && !f.AllowIllegalWrites {
return errStreamID
}
f.startWrite(FrameRSTStream, 0, streamID)
f.writeUint32(uint32(code))
return f.endWrite()
}
// A ContinuationFrame is used to continue a sequence of header block fragments.
// See https://httpwg.org/specs/rfc7540.html#rfc.section.6.10
type ContinuationFrame struct {
FrameHeader
headerFragBuf []byte
}
func parseContinuationFrame(_ *frameCache, fh FrameHeader, countError func(string), p []byte) (Frame, error) {
if fh.StreamID == 0 {
countError("frame_continuation_zero_stream")
return nil, connError{ErrCodeProtocol, "CONTINUATION frame with stream ID 0"}
}
return &ContinuationFrame{fh, p}, nil
}
func (f *ContinuationFrame) HeaderBlockFragment() []byte {
f.checkValid()
return f.headerFragBuf
}
func (f *ContinuationFrame) HeadersEnded() bool {
return f.FrameHeader.Flags.Has(FlagContinuationEndHeaders)
}
// WriteContinuation writes a CONTINUATION frame.
//
// It will perform exactly one Write to the underlying Writer.
// It is the caller's responsibility to not call other Write methods concurrently.
func (f *Framer) WriteContinuation(streamID uint32, endHeaders bool, headerBlockFragment []byte) error {
if !validStreamID(streamID) && !f.AllowIllegalWrites {
return errStreamID
}
var flags Flags
if endHeaders {
flags |= FlagContinuationEndHeaders
}
f.startWrite(FrameContinuation, flags, streamID)
f.wbuf = append(f.wbuf, headerBlockFragment...)
return f.endWrite()
}
// A PushPromiseFrame is used to initiate a server stream.
// See https://httpwg.org/specs/rfc7540.html#rfc.section.6.6
type PushPromiseFrame struct {
FrameHeader
PromiseID uint32
headerFragBuf []byte // not owned
}
func (f *PushPromiseFrame) HeaderBlockFragment() []byte {
f.checkValid()
return f.headerFragBuf
}
func (f *PushPromiseFrame) HeadersEnded() bool {
return f.FrameHeader.Flags.Has(FlagPushPromiseEndHeaders)
}
func parsePushPromise(_ *frameCache, fh FrameHeader, countError func(string), p []byte) (_ Frame, err error) {
pp := &PushPromiseFrame{
FrameHeader: fh,
}
if pp.StreamID == 0 {
// PUSH_PROMISE frames MUST be associated with an existing,
// peer-initiated stream. The stream identifier of a
// PUSH_PROMISE frame indicates the stream it is associated
// with. If the stream identifier field specifies the value
// 0x0, a recipient MUST respond with a connection error
// (Section 5.4.1) of type PROTOCOL_ERROR.
countError("frame_pushpromise_zero_stream")
return nil, ConnectionError(ErrCodeProtocol)
}
// The PUSH_PROMISE frame includes optional padding.
// Padding fields and flags are identical to those defined for DATA frames
var padLength uint8
if fh.Flags.Has(FlagPushPromisePadded) {
if p, padLength, err = readByte(p); err != nil {
countError("frame_pushpromise_pad_short")
return
}
}
p, pp.PromiseID, err = readUint32(p)
if err != nil {
countError("frame_pushpromise_promiseid_short")
return
}
pp.PromiseID = pp.PromiseID & (1<<31 - 1)
if int(padLength) > len(p) {
// like the DATA frame, error out if padding is longer than the body.
countError("frame_pushpromise_pad_too_big")
return nil, ConnectionError(ErrCodeProtocol)
}
pp.headerFragBuf = p[:len(p)-int(padLength)]
return pp, nil
}
// PushPromiseParam are the parameters for writing a PUSH_PROMISE frame.
type PushPromiseParam struct {
// StreamID is the required Stream ID to initiate.
StreamID uint32
// PromiseID is the required Stream ID which this
// Push Promises
PromiseID uint32
// BlockFragment is part (or all) of a Header Block.
BlockFragment []byte
// EndHeaders indicates that this frame contains an entire
// header block and is not followed by any
// CONTINUATION frames.
EndHeaders bool
// PadLength is the optional number of bytes of zeros to add
// to this frame.
PadLength uint8
}
// WritePushPromise writes a single PushPromise Frame.
//
// As with Header Frames, This is the low level call for writing
// individual frames. Continuation frames are handled elsewhere.
//
// It will perform exactly one Write to the underlying Writer.
// It is the caller's responsibility to not call other Write methods concurrently.
func (f *Framer) WritePushPromise(p PushPromiseParam) error {
if !validStreamID(p.StreamID) && !f.AllowIllegalWrites {
return errStreamID
}
var flags Flags
if p.PadLength != 0 {
flags |= FlagPushPromisePadded
}
if p.EndHeaders {
flags |= FlagPushPromiseEndHeaders
}
f.startWrite(FramePushPromise, flags, p.StreamID)
if p.PadLength != 0 {
f.writeByte(p.PadLength)
}
if !validStreamID(p.PromiseID) && !f.AllowIllegalWrites {
return errStreamID
}
f.writeUint32(p.PromiseID)
f.wbuf = append(f.wbuf, p.BlockFragment...)
f.wbuf = append(f.wbuf, padZeros[:p.PadLength]...)
return f.endWrite()
}
// WriteRawFrame writes a raw frame. This can be used to write
// extension frames unknown to this package.
func (f *Framer) WriteRawFrame(t FrameType, flags Flags, streamID uint32, payload []byte) error {
f.startWrite(t, flags, streamID)
f.writeBytes(payload)
return f.endWrite()
}
func readByte(p []byte) (remain []byte, b byte, err error) {
if len(p) == 0 {
return nil, 0, io.ErrUnexpectedEOF
}
return p[1:], p[0], nil
}
func readUint32(p []byte) (remain []byte, v uint32, err error) {
if len(p) < 4 {
return nil, 0, io.ErrUnexpectedEOF
}
return p[4:], binary.BigEndian.Uint32(p[:4]), nil
}
type streamEnder interface {
StreamEnded() bool
}
type headersEnder interface {
HeadersEnded() bool
}
type headersOrContinuation interface {
headersEnder
HeaderBlockFragment() []byte
}
// A MetaHeadersFrame is the representation of one HEADERS frame and
// zero or more contiguous CONTINUATION frames and the decoding of
// their HPACK-encoded contents.
//
// This type of frame does not appear on the wire and is only returned
// by the Framer when Framer.ReadMetaHeaders is set.
type MetaHeadersFrame struct {
*HeadersFrame
// Fields are the fields contained in the HEADERS and
// CONTINUATION frames. The underlying slice is owned by the
// Framer and must not be retained after the next call to
// ReadFrame.
//
// Fields are guaranteed to be in the correct http2 order and
// not have unknown pseudo header fields or invalid header
// field names or values. Required pseudo header fields may be
// missing, however. Use the MetaHeadersFrame.Pseudo accessor
// method access pseudo headers.
Fields []hpack.HeaderField
// Truncated is whether the max header list size limit was hit
// and Fields is incomplete. The hpack decoder state is still
// valid, however.
Truncated bool
}
// PseudoValue returns the given pseudo header field's value.
// The provided pseudo field should not contain the leading colon.
func (mh *MetaHeadersFrame) PseudoValue(pseudo string) string {
for _, hf := range mh.Fields {
if !hf.IsPseudo() {
return ""
}
if hf.Name[1:] == pseudo {
return hf.Value
}
}
return ""
}
// RegularFields returns the regular (non-pseudo) header fields of mh.
// The caller does not own the returned slice.
func (mh *MetaHeadersFrame) RegularFields() []hpack.HeaderField {
for i, hf := range mh.Fields {
if !hf.IsPseudo() {
return mh.Fields[i:]
}
}
return nil
}
// PseudoFields returns the pseudo header fields of mh.
// The caller does not own the returned slice.
func (mh *MetaHeadersFrame) PseudoFields() []hpack.HeaderField {
for i, hf := range mh.Fields {
if !hf.IsPseudo() {
return mh.Fields[:i]
}
}
return mh.Fields
}
func (mh *MetaHeadersFrame) checkPseudos() error {
var isRequest, isResponse bool
pf := mh.PseudoFields()
for i, hf := range pf {
switch hf.Name {
case ":method", ":path", ":scheme", ":authority", ":protocol":
isRequest = true
case ":status":
isResponse = true
default:
return pseudoHeaderError(hf.Name)
}
// Check for duplicates.
// This would be a bad algorithm, but N is 5.
// And this doesn't allocate.
for _, hf2 := range pf[:i] {
if hf.Name == hf2.Name {
return duplicatePseudoHeaderError(hf.Name)
}
}
}
if isRequest && isResponse {
return errMixPseudoHeaderTypes
}
return nil
}
func (fr *Framer) maxHeaderStringLen() int {
v := int(fr.maxHeaderListSize())
if v < 0 {
// If maxHeaderListSize overflows an int, use no limit (0).
return 0
}
return v
}
// readMetaFrame returns 0 or more CONTINUATION frames from fr and
// merge them into the provided hf and returns a MetaHeadersFrame
// with the decoded hpack values.
func (fr *Framer) readMetaFrame(hf *HeadersFrame) (Frame, error) {
if fr.AllowIllegalReads {
return nil, errors.New("illegal use of AllowIllegalReads with ReadMetaHeaders")
}
mh := &MetaHeadersFrame{
HeadersFrame: hf,
}
var remainSize = fr.maxHeaderListSize()
var sawRegular bool
var invalid error // pseudo header field errors
hdec := fr.ReadMetaHeaders
hdec.SetEmitEnabled(true)
hdec.SetMaxStringLength(fr.maxHeaderStringLen())
hdec.SetEmitFunc(func(hf hpack.HeaderField) {
if VerboseLogs && fr.logReads {
fr.debugReadLoggerf("http2: decoded hpack field %+v", hf)
}
if !httpguts.ValidHeaderFieldValue(hf.Value) {
// Don't include the value in the error, because it may be sensitive.
invalid = headerFieldValueError(hf.Name)
}
isPseudo := strings.HasPrefix(hf.Name, ":")
if isPseudo {
if sawRegular {
invalid = errPseudoAfterRegular
}
} else {
sawRegular = true
if !validWireHeaderFieldName(hf.Name) {
invalid = headerFieldNameError(hf.Name)
}
}
if invalid != nil {
hdec.SetEmitEnabled(false)
return
}
size := hf.Size()
if size > remainSize {
hdec.SetEmitEnabled(false)
mh.Truncated = true
remainSize = 0
return
}
remainSize -= size
mh.Fields = append(mh.Fields, hf)
})
// Lose reference to MetaHeadersFrame:
defer hdec.SetEmitFunc(func(hf hpack.HeaderField) {})
var hc headersOrContinuation = hf
for {
frag := hc.HeaderBlockFragment()
// Avoid parsing large amounts of headers that we will then discard.
// If the sender exceeds the max header list size by too much,
// skip parsing the fragment and close the connection.
//
// "Too much" is either any CONTINUATION frame after we've already
// exceeded the max header list size (in which case remainSize is 0),
// or a frame whose encoded size is more than twice the remaining
// header list bytes we're willing to accept.
if int64(len(frag)) > int64(2*remainSize) {
if VerboseLogs {
log.Printf("http2: header list too large")
}
// It would be nice to send a RST_STREAM before sending the GOAWAY,
// but the structure of the server's frame writer makes this difficult.
return mh, ConnectionError(ErrCodeProtocol)
}
// Also close the connection after any CONTINUATION frame following an
// invalid header, since we stop tracking the size of the headers after
// an invalid one.
if invalid != nil {
if VerboseLogs {
log.Printf("http2: invalid header: %v", invalid)
}
// It would be nice to send a RST_STREAM before sending the GOAWAY,
// but the structure of the server's frame writer makes this difficult.
return mh, ConnectionError(ErrCodeProtocol)
}
if _, err := hdec.Write(frag); err != nil {
return mh, ConnectionError(ErrCodeCompression)
}
if hc.HeadersEnded() {
break
}
if f, err := fr.ReadFrame(); err != nil {
return nil, err
} else {
hc = f.(*ContinuationFrame) // guaranteed by checkFrameOrder
}
}
mh.HeadersFrame.headerFragBuf = nil
mh.HeadersFrame.invalidate()
if err := hdec.Close(); err != nil {
return mh, ConnectionError(ErrCodeCompression)
}
if invalid != nil {
fr.errDetail = invalid
if VerboseLogs {
log.Printf("http2: invalid header: %v", invalid)
}
return nil, StreamError{mh.StreamID, ErrCodeProtocol, invalid}
}
if err := mh.checkPseudos(); err != nil {
fr.errDetail = err
if VerboseLogs {
log.Printf("http2: invalid pseudo headers: %v", err)
}
return nil, StreamError{mh.StreamID, ErrCodeProtocol, err}
}
return mh, nil
}
func summarizeFrame(f Frame) string {
var buf bytes.Buffer
f.Header().writeDebug(&buf)
switch f := f.(type) {
case *SettingsFrame:
n := 0
f.ForeachSetting(func(s Setting) error {
n++
if n == 1 {
buf.WriteString(", settings:")
}
fmt.Fprintf(&buf, " %v=%v,", s.ID, s.Val)
return nil
})
if n > 0 {
buf.Truncate(buf.Len() - 1) // remove trailing comma
}
case *DataFrame:
data := f.Data()
const max = 256
if len(data) > max {
data = data[:max]
}
fmt.Fprintf(&buf, " data=%q", data)
if len(f.Data()) > max {
fmt.Fprintf(&buf, " (%d bytes omitted)", len(f.Data())-max)
}
case *WindowUpdateFrame:
if f.StreamID == 0 {
buf.WriteString(" (conn)")
}
fmt.Fprintf(&buf, " incr=%v", f.Increment)
case *PingFrame:
fmt.Fprintf(&buf, " ping=%q", f.Data[:])
case *GoAwayFrame:
fmt.Fprintf(&buf, " LastStreamID=%v ErrCode=%v Debug=%q",
f.LastStreamID, f.ErrCode, f.debugData)
case *RSTStreamFrame:
fmt.Fprintf(&buf, " ErrCode=%v", f.ErrCode)
}
return buf.String()
}
// 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.
// Defensive debug-only utility to track that functions run on the
// goroutine that they're supposed to.
package http2
import (
"bytes"
"errors"
"fmt"
"os"
"runtime"
"strconv"
"sync"
"sync/atomic"
)
var DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1"
// Setting DebugGoroutines to false during a test to disable goroutine debugging
// results in race detector complaints when a test leaves goroutines running before
// returning. Tests shouldn't do this, of course, but when they do it generally shows
// up as infrequent, hard-to-debug flakes. (See #66519.)
//
// Disable goroutine debugging during individual tests with an atomic bool.
// (Note that it's safe to enable/disable debugging mid-test, so the actual race condition
// here is harmless.)
var disableDebugGoroutines atomic.Bool
type goroutineLock uint64
func newGoroutineLock() goroutineLock {
if !DebugGoroutines || disableDebugGoroutines.Load() {
return 0
}
return goroutineLock(curGoroutineID())
}
func (g goroutineLock) check() {
if !DebugGoroutines || disableDebugGoroutines.Load() {
return
}
if curGoroutineID() != uint64(g) {
panic("running on the wrong goroutine")
}
}
func (g goroutineLock) checkNotOn() {
if !DebugGoroutines || disableDebugGoroutines.Load() {
return
}
if curGoroutineID() == uint64(g) {
panic("running on the wrong goroutine")
}
}
var goroutineSpace = []byte("goroutine ")
func curGoroutineID() uint64 {
bp := littleBuf.Get().(*[]byte)
defer littleBuf.Put(bp)
b := *bp
b = b[:runtime.Stack(b, false)]
// Parse the 4707 out of "goroutine 4707 ["
b = bytes.TrimPrefix(b, goroutineSpace)
i := bytes.IndexByte(b, ' ')
if i < 0 {
panic(fmt.Sprintf("No space found in %q", b))
}
b = b[:i]
n, err := parseUintBytes(b, 10, 64)
if err != nil {
panic(fmt.Sprintf("Failed to parse goroutine ID out of %q: %v", b, err))
}
return n
}
var littleBuf = sync.Pool{
New: func() interface{} {
buf := make([]byte, 64)
return &buf
},
}
// parseUintBytes is like strconv.ParseUint, but using a []byte.
func parseUintBytes(s []byte, base int, bitSize int) (n uint64, err error) {
var cutoff, maxVal uint64
if bitSize == 0 {
bitSize = int(strconv.IntSize)
}
s0 := s
switch {
case len(s) < 1:
err = strconv.ErrSyntax
goto Error
case 2 <= base && base <= 36:
// valid base; nothing to do
case base == 0:
// Look for octal, hex prefix.
switch {
case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
base = 16
s = s[2:]
if len(s) < 1 {
err = strconv.ErrSyntax
goto Error
}
case s[0] == '0':
base = 8
default:
base = 10
}
default:
err = errors.New("invalid base " + strconv.Itoa(base))
goto Error
}
n = 0
cutoff = cutoff64(base)
maxVal = 1<<uint(bitSize) - 1
for i := 0; i < len(s); i++ {
var v byte
d := s[i]
switch {
case '0' <= d && d <= '9':
v = d - '0'
case 'a' <= d && d <= 'z':
v = d - 'a' + 10
case 'A' <= d && d <= 'Z':
v = d - 'A' + 10
default:
n = 0
err = strconv.ErrSyntax
goto Error
}
if int(v) >= base {
n = 0
err = strconv.ErrSyntax
goto Error
}
if n >= cutoff {
// n*base overflows
n = 1<<64 - 1
err = strconv.ErrRange
goto Error
}
n *= uint64(base)
n1 := n + uint64(v)
if n1 < n || n1 > maxVal {
// n+v overflows
n = 1<<64 - 1
err = strconv.ErrRange
goto Error
}
n = n1
}
return n, nil
Error:
return n, &strconv.NumError{Func: "ParseUint", Num: string(s0), Err: err}
}
// Return the first number n such that n*base >= 1<<64.
func cutoff64(base int) uint64 {
if base < 2 {
return 0
}
return (1<<64-1)/uint64(base) + 1
}
// 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 hpack
import (
"io"
)
const (
uint32Max = ^uint32(0)
initialHeaderTableSize = 4096
)
type Encoder struct {
dynTab dynamicTable
// minSize is the minimum table size set by
// SetMaxDynamicTableSize after the previous Header Table Size
// Update.
minSize uint32
// maxSizeLimit is the maximum table size this encoder
// supports. This will protect the encoder from too large
// size.
maxSizeLimit uint32
// tableSizeUpdate indicates whether "Header Table Size
// Update" is required.
tableSizeUpdate bool
w io.Writer
buf []byte
}
// NewEncoder returns a new Encoder which performs HPACK encoding. An
// encoded data is written to w.
func NewEncoder(w io.Writer) *Encoder {
e := &Encoder{
minSize: uint32Max,
maxSizeLimit: initialHeaderTableSize,
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.
func (e *Encoder) WriteField(f HeaderField) error {
e.buf = e.buf[:0]
if e.tableSizeUpdate {
e.tableSizeUpdate = false
if e.minSize < e.dynTab.maxSize {
e.buf = appendTableSize(e.buf, e.minSize)
}
e.minSize = uint32Max
e.buf = appendTableSize(e.buf, e.dynTab.maxSize)
}
idx, nameValueMatch := e.searchTable(f)
if nameValueMatch {
e.buf = appendIndexed(e.buf, idx)
} else {
indexing := e.shouldIndex(f)
if indexing {
e.dynTab.add(f)
}
if idx == 0 {
e.buf = appendNewName(e.buf, f, indexing)
} else {
e.buf = appendIndexedName(e.buf, f, idx, indexing)
}
}
n, err := e.w.Write(e.buf)
if err == nil && n != len(e.buf) {
err = io.ErrShortWrite
}
return err
}
// searchTable searches f in both stable and dynamic header tables.
// The static header table is searched first. Only when there is no
// exact match for both name and value, the dynamic header table is
// then searched. 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.
func (e *Encoder) searchTable(f HeaderField) (i uint64, nameValueMatch bool) {
i, nameValueMatch = staticTable.search(f)
if nameValueMatch {
return i, true
}
j, nameValueMatch := e.dynTab.table.search(f)
if nameValueMatch || (i == 0 && j != 0) {
return j + uint64(staticTable.len()), nameValueMatch
}
return i, false
}
// SetMaxDynamicTableSize changes the dynamic header table size to v.
// The actual size is bounded by the value passed to
// SetMaxDynamicTableSizeLimit.
func (e *Encoder) SetMaxDynamicTableSize(v uint32) {
if v > e.maxSizeLimit {
v = e.maxSizeLimit
}
if v < e.minSize {
e.minSize = v
}
e.tableSizeUpdate = true
e.dynTab.setMaxSize(v)
}
// MaxDynamicTableSize returns the current dynamic header table size.
func (e *Encoder) MaxDynamicTableSize() (v uint32) {
return e.dynTab.maxSize
}
// SetMaxDynamicTableSizeLimit changes the maximum value that can be
// specified in SetMaxDynamicTableSize to v. By default, it is set to
// 4096, which is the same size of the default dynamic header table
// size described in HPACK specification. If the current maximum
// dynamic header table size is strictly greater than v, "Header Table
// Size Update" will be done in the next WriteField call and the
// maximum dynamic header table size is truncated to v.
func (e *Encoder) SetMaxDynamicTableSizeLimit(v uint32) {
e.maxSizeLimit = v
if e.dynTab.maxSize > v {
e.tableSizeUpdate = true
e.dynTab.setMaxSize(v)
}
}
// shouldIndex reports whether f should be indexed.
func (e *Encoder) shouldIndex(f HeaderField) bool {
return !f.Sensitive && f.Size() <= e.dynTab.maxSize
}
// appendIndexed appends index i, as encoded in "Indexed Header Field"
// representation, to dst and returns the extended buffer.
func appendIndexed(dst []byte, i uint64) []byte {
first := len(dst)
dst = appendVarInt(dst, 7, i)
dst[first] |= 0x80
return dst
}
// appendNewName appends f, as encoded in one of "Literal Header field
// - New Name" representation variants, to dst and returns the
// extended buffer.
//
// If f.Sensitive is true, "Never Indexed" representation is used. If
// f.Sensitive is false and indexing is true, "Incremental Indexing"
// representation is used.
func appendNewName(dst []byte, f HeaderField, indexing bool) []byte {
dst = append(dst, encodeTypeByte(indexing, f.Sensitive))
dst = appendHpackString(dst, f.Name)
return appendHpackString(dst, f.Value)
}
// appendIndexedName appends f and index i referring indexed name
// entry, as encoded in one of "Literal Header field - Indexed Name"
// representation variants, to dst and returns the extended buffer.
//
// If f.Sensitive is true, "Never Indexed" representation is used. If
// f.Sensitive is false and indexing is true, "Incremental Indexing"
// representation is used.
func appendIndexedName(dst []byte, f HeaderField, i uint64, indexing bool) []byte {
first := len(dst)
var n byte
if indexing {
n = 6
} else {
n = 4
}
dst = appendVarInt(dst, n, i)
dst[first] |= encodeTypeByte(indexing, f.Sensitive)
return appendHpackString(dst, f.Value)
}
// appendTableSize appends v, as encoded in "Header Table Size Update"
// representation, to dst and returns the extended buffer.
func appendTableSize(dst []byte, v uint32) []byte {
first := len(dst)
dst = appendVarInt(dst, 5, uint64(v))
dst[first] |= 0x20
return dst
}
// appendVarInt appends i, as encoded in variable integer form using n
// bit prefix, to dst and returns the extended buffer.
//
// See
// https://httpwg.org/specs/rfc7541.html#integer.representation
func appendVarInt(dst []byte, n byte, i uint64) []byte {
k := uint64((1 << n) - 1)
if i < k {
return append(dst, byte(i))
}
dst = append(dst, byte(k))
i -= k
for ; i >= 128; i >>= 7 {
dst = append(dst, byte(0x80|(i&0x7f)))
}
return append(dst, byte(i))
}
// appendHpackString appends s, as encoded in "String Literal"
// representation, to dst and returns the extended buffer.
//
// s will be encoded in Huffman codes only when it produces strictly
// shorter byte string.
func appendHpackString(dst []byte, s string) []byte {
huffmanLength := HuffmanEncodeLength(s)
if huffmanLength < uint64(len(s)) {
first := len(dst)
dst = appendVarInt(dst, 7, huffmanLength)
dst = AppendHuffmanString(dst, s)
dst[first] |= 0x80
} else {
dst = appendVarInt(dst, 7, uint64(len(s)))
dst = append(dst, s...)
}
return dst
}
// encodeTypeByte returns type byte. If sensitive is true, type byte
// for "Never Indexed" representation is returned. If sensitive is
// false and indexing is true, type byte for "Incremental Indexing"
// representation is returned. Otherwise, type byte for "Without
// Indexing" is returned.
func encodeTypeByte(indexing, sensitive bool) byte {
if sensitive {
return 0x10
}
if indexing {
return 0x40
}
return 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 hpack implements HPACK, a compression format for
// efficiently representing HTTP header fields in the context of HTTP/2.
//
// See http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09
package hpack
import (
"bytes"
"errors"
"fmt"
)
// A DecodingError is something the spec defines as a decoding error.
type DecodingError struct {
Err error
}
func (de DecodingError) Error() string {
return fmt.Sprintf("decoding error: %v", de.Err)
}
// An InvalidIndexError is returned when an encoder references a table
// entry before the static table or after the end of the dynamic table.
type InvalidIndexError int
func (e InvalidIndexError) Error() string {
return fmt.Sprintf("invalid indexed representation index %d", int(e))
}
// A HeaderField is a name-value pair. Both the name and value are
// treated as opaque sequences of octets.
type HeaderField struct {
Name, Value string
// Sensitive means that this header field should never be
// indexed.
Sensitive bool
}
// IsPseudo reports whether the header field is an http2 pseudo header.
// That is, it reports whether it starts with a colon.
// It is not otherwise guaranteed to be a valid pseudo header field,
// though.
func (hf HeaderField) IsPseudo() bool {
return len(hf.Name) != 0 && hf.Name[0] == ':'
}
func (hf HeaderField) String() string {
var suffix string
if hf.Sensitive {
suffix = " (sensitive)"
}
return fmt.Sprintf("header field %q = %q%s", hf.Name, hf.Value, suffix)
}
// Size returns the size of an entry per RFC 7541 section 4.1.
func (hf HeaderField) Size() uint32 {
// https://httpwg.org/specs/rfc7541.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
// 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
// value without any Huffman encoding applied."
// This can overflow if somebody makes a large HeaderField
// Name and/or Value by hand, but we don't care, because that
// won't happen on the wire because the encoding doesn't allow
// it.
return uint32(len(hf.Name) + len(hf.Value) + 32)
}
// A Decoder is the decoding context for incremental processing of
// header blocks.
type Decoder struct {
dynTab dynamicTable
emit func(f HeaderField)
emitEnabled bool // whether calls to emit are enabled
maxStrLen int // 0 means unlimited
// buf is the unparsed buffer. It's only written to
// saveBuf if it was truncated in the middle of a header
// block. Because it's usually not owned, we can only
// process it under Write.
buf []byte // not owned; only valid during Write
// saveBuf is previous data passed to Write which we weren't able
// to fully parse before. Unlike buf, we own this data.
saveBuf bytes.Buffer
firstField bool // processing the first field of the header block
}
// NewDecoder returns a new decoder with the provided maximum dynamic
// table size. The emitFunc will be called for each valid field
// parsed, in the same goroutine as calls to Write, before Write returns.
func NewDecoder(maxDynamicTableSize uint32, emitFunc func(f HeaderField)) *Decoder {
d := &Decoder{
emit: emitFunc,
emitEnabled: true,
firstField: true,
}
d.dynTab.table.init()
d.dynTab.allowedMaxSize = maxDynamicTableSize
d.dynTab.setMaxSize(maxDynamicTableSize)
return d
}
// ErrStringLength is returned by Decoder.Write when the max string length
// (as configured by Decoder.SetMaxStringLength) would be violated.
var ErrStringLength = errors.New("hpack: string too long")
// SetMaxStringLength sets the maximum size of a HeaderField name or
// value string. If a string exceeds this length (even after any
// decompression), Write will return ErrStringLength.
// A value of 0 means unlimited and is the default from NewDecoder.
func (d *Decoder) SetMaxStringLength(n int) {
d.maxStrLen = n
}
// SetEmitFunc changes the callback used when new header fields
// are decoded.
// It must be non-nil. It does not affect EmitEnabled.
func (d *Decoder) SetEmitFunc(emitFunc func(f HeaderField)) {
d.emit = emitFunc
}
// SetEmitEnabled controls whether the emitFunc provided to NewDecoder
// should be called. The default is true.
//
// This facility exists to let servers enforce MAX_HEADER_LIST_SIZE
// while still decoding and keeping in-sync with decoder state, but
// without doing unnecessary decompression or generating unnecessary
// garbage for header fields past the limit.
func (d *Decoder) SetEmitEnabled(v bool) { d.emitEnabled = v }
// EmitEnabled reports whether calls to the emitFunc provided to NewDecoder
// are currently enabled. The default is true.
func (d *Decoder) EmitEnabled() bool { return d.emitEnabled }
// TODO: add method *Decoder.Reset(maxSize, emitFunc) to let callers re-use Decoders and their
// underlying buffers for garbage reasons.
func (d *Decoder) SetMaxDynamicTableSize(v uint32) {
d.dynTab.setMaxSize(v)
}
// SetAllowedMaxDynamicTableSize sets the upper bound that the encoded
// stream (via dynamic table size updates) may set the maximum size
// to.
func (d *Decoder) SetAllowedMaxDynamicTableSize(v uint32) {
d.dynTab.allowedMaxSize = v
}
type dynamicTable struct {
// https://httpwg.org/specs/rfc7541.html#rfc.section.2.3.2
table headerFieldTable
size uint32 // in bytes
maxSize uint32 // current maxSize
allowedMaxSize uint32 // maxSize may go up to this, inclusive
}
func (dt *dynamicTable) setMaxSize(v uint32) {
dt.maxSize = v
dt.evict()
}
func (dt *dynamicTable) add(f HeaderField) {
dt.table.addEntry(f)
dt.size += f.Size()
dt.evict()
}
// If we're too big, evict old stuff.
func (dt *dynamicTable) evict() {
var n int
for dt.size > dt.maxSize && n < dt.table.len() {
dt.size -= dt.table.ents[n].Size()
n++
}
dt.table.evictOldest(n)
}
func (d *Decoder) maxTableIndex() int {
// 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) {
// 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
}
// 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
}
// DecodeFull decodes an entire block.
//
// TODO: remove this method and make it incremental later? This is
// easier for debugging now.
func (d *Decoder) DecodeFull(p []byte) ([]HeaderField, error) {
var hf []HeaderField
saveFunc := d.emit
defer func() { d.emit = saveFunc }()
d.emit = func(f HeaderField) { hf = append(hf, f) }
if _, err := d.Write(p); err != nil {
return nil, err
}
if err := d.Close(); err != nil {
return nil, err
}
return hf, nil
}
// Close declares that the decoding is complete and resets the Decoder
// to be reused again for a new header block. If there is any remaining
// data in the decoder's buffer, Close returns an error.
func (d *Decoder) Close() error {
if d.saveBuf.Len() > 0 {
d.saveBuf.Reset()
return DecodingError{errors.New("truncated headers")}
}
d.firstField = true
return nil
}
func (d *Decoder) Write(p []byte) (n int, err error) {
if len(p) == 0 {
// Prevent state machine CPU attacks (making us redo
// work up to the point of finding out we don't have
// enough data)
return
}
// Only copy the data if we have to. Optimistically assume
// that p will contain a complete header block.
if d.saveBuf.Len() == 0 {
d.buf = p
} else {
d.saveBuf.Write(p)
d.buf = d.saveBuf.Bytes()
d.saveBuf.Reset()
}
for len(d.buf) > 0 {
err = d.parseHeaderFieldRepr()
if err == errNeedMore {
// Extra paranoia, making sure saveBuf won't
// 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.
const varIntOverhead = 8 // conservative
if d.maxStrLen != 0 && int64(len(d.buf)) > 2*(int64(d.maxStrLen)+varIntOverhead) {
return 0, ErrStringLength
}
d.saveBuf.Write(d.buf)
return len(p), nil
}
d.firstField = false
if err != nil {
break
}
}
return len(p), err
}
// errNeedMore is an internal sentinel error value that means the
// buffer is truncated and we need to read more data before we can
// continue parsing.
var errNeedMore = errors.New("need more data")
type indexType int
const (
indexedTrue indexType = iota
indexedFalse
indexedNever
)
func (v indexType) indexed() bool { return v == indexedTrue }
func (v indexType) sensitive() bool { return v == indexedNever }
// returns errNeedMore if there isn't enough data available.
// any other error is fatal.
// consumes d.buf iff it returns nil.
// precondition: must be called with len(d.buf) > 0
func (d *Decoder) parseHeaderFieldRepr() error {
b := d.buf[0]
switch {
case b&128 != 0:
// Indexed representation.
// High bit set?
// https://httpwg.org/specs/rfc7541.html#rfc.section.6.1
return d.parseFieldIndexed()
case b&192 == 64:
// 6.2.1 Literal Header Field with Incremental Indexing
// 0b10xxxxxx: top two bits are 10
// https://httpwg.org/specs/rfc7541.html#rfc.section.6.2.1
return d.parseFieldLiteral(6, indexedTrue)
case b&240 == 0:
// 6.2.2 Literal Header Field without Indexing
// 0b0000xxxx: top four bits are 0000
// https://httpwg.org/specs/rfc7541.html#rfc.section.6.2.2
return d.parseFieldLiteral(4, indexedFalse)
case b&240 == 16:
// 6.2.3 Literal Header Field never Indexed
// 0b0001xxxx: top four bits are 0001
// https://httpwg.org/specs/rfc7541.html#rfc.section.6.2.3
return d.parseFieldLiteral(4, indexedNever)
case b&224 == 32:
// 6.3 Dynamic Table Size Update
// Top three bits are '001'.
// https://httpwg.org/specs/rfc7541.html#rfc.section.6.3
return d.parseDynamicTableSizeUpdate()
}
return DecodingError{errors.New("invalid encoding")}
}
// (same invariants and behavior as parseHeaderFieldRepr)
func (d *Decoder) parseFieldIndexed() error {
buf := d.buf
idx, buf, err := readVarInt(7, buf)
if err != nil {
return err
}
hf, ok := d.at(idx)
if !ok {
return DecodingError{InvalidIndexError(idx)}
}
d.buf = buf
return d.callEmit(HeaderField{Name: hf.Name, Value: hf.Value})
}
// (same invariants and behavior as parseHeaderFieldRepr)
func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error {
buf := d.buf
nameIdx, buf, err := readVarInt(n, buf)
if err != nil {
return err
}
var hf HeaderField
wantStr := d.emitEnabled || it.indexed()
var undecodedName undecodedString
if nameIdx > 0 {
ihf, ok := d.at(nameIdx)
if !ok {
return DecodingError{InvalidIndexError(nameIdx)}
}
hf.Name = ihf.Name
} else {
undecodedName, buf, err = d.readString(buf)
if err != nil {
return err
}
}
undecodedValue, buf, err := d.readString(buf)
if err != nil {
return err
}
if wantStr {
if nameIdx <= 0 {
hf.Name, err = d.decodeString(undecodedName)
if err != nil {
return err
}
}
hf.Value, err = d.decodeString(undecodedValue)
if err != nil {
return err
}
}
d.buf = buf
if it.indexed() {
d.dynTab.add(hf)
}
hf.Sensitive = it.sensitive()
return d.callEmit(hf)
}
func (d *Decoder) callEmit(hf HeaderField) error {
if d.maxStrLen != 0 {
if len(hf.Name) > d.maxStrLen || len(hf.Value) > d.maxStrLen {
return ErrStringLength
}
}
if d.emitEnabled {
d.emit(hf)
}
return nil
}
// (same invariants and behavior as parseHeaderFieldRepr)
func (d *Decoder) parseDynamicTableSizeUpdate() error {
// RFC 7541, sec 4.2: This dynamic table size update MUST occur at the
// beginning of the first header block following the change to the dynamic table size.
if !d.firstField && d.dynTab.size > 0 {
return DecodingError{errors.New("dynamic table size update MUST occur at the beginning of a header block")}
}
buf := d.buf
size, buf, err := readVarInt(5, buf)
if err != nil {
return err
}
if size > uint64(d.dynTab.allowedMaxSize) {
return DecodingError{errors.New("dynamic table size update too large")}
}
d.dynTab.setMaxSize(uint32(size))
d.buf = buf
return nil
}
var errVarintOverflow = DecodingError{errors.New("varint integer overflow")}
// readVarInt reads an unsigned variable length integer off the
// beginning of p. n is the parameter as described in
// https://httpwg.org/specs/rfc7541.html#rfc.section.5.1.
//
// n must always be between 1 and 8.
//
// The returned remain buffer is either a smaller suffix of p, or err != nil.
// The error is errNeedMore if p doesn't contain a complete integer.
func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error) {
if n < 1 || n > 8 {
panic("bad n")
}
if len(p) == 0 {
return 0, p, errNeedMore
}
i = uint64(p[0])
if n < 8 {
i &= (1 << uint64(n)) - 1
}
if i < (1<<uint64(n))-1 {
return i, p[1:], nil
}
origP := p
p = p[1:]
var m uint64
for len(p) > 0 {
b := p[0]
p = p[1:]
i += uint64(b&127) << m
if b&128 == 0 {
return i, p, nil
}
m += 7
if m >= 63 { // TODO: proper overflow check. making this up.
return 0, origP, errVarintOverflow
}
}
return 0, origP, errNeedMore
}
// readString reads an hpack string from p.
//
// It returns a reference to the encoded string data to permit deferring decode costs
// until after the caller verifies all data is present.
func (d *Decoder) readString(p []byte) (u undecodedString, remain []byte, err error) {
if len(p) == 0 {
return u, p, errNeedMore
}
isHuff := p[0]&128 != 0
strLen, p, err := readVarInt(7, p)
if err != nil {
return u, p, err
}
if d.maxStrLen != 0 && strLen > uint64(d.maxStrLen) {
// Returning an error here means Huffman decoding errors
// for non-indexed strings past the maximum string length
// are ignored, but the server is returning an error anyway
// and because the string is not indexed the error will not
// affect the decoding state.
return u, nil, ErrStringLength
}
if uint64(len(p)) < strLen {
return u, p, errNeedMore
}
u.isHuff = isHuff
u.b = p[:strLen]
return u, p[strLen:], nil
}
type undecodedString struct {
isHuff bool
b []byte
}
func (d *Decoder) decodeString(u undecodedString) (string, error) {
if !u.isHuff {
return string(u.b), nil
}
buf := bufPool.Get().(*bytes.Buffer)
buf.Reset() // don't trust others
var s string
err := huffmanDecode(buf, d.maxStrLen, u.b)
if err == nil {
s = buf.String()
}
buf.Reset() // be nice to GC
bufPool.Put(buf)
return s, err
}
// 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 hpack
import (
"bytes"
"errors"
"io"
"sync"
)
var bufPool = sync.Pool{
New: func() interface{} { return new(bytes.Buffer) },
}
// HuffmanDecode decodes the string in v and writes the expanded
// result to w, returning the number of bytes written to w and the
// Write call's return value. At most one Write call is made.
func HuffmanDecode(w io.Writer, v []byte) (int, error) {
buf := bufPool.Get().(*bytes.Buffer)
buf.Reset()
defer bufPool.Put(buf)
if err := huffmanDecode(buf, 0, v); err != nil {
return 0, err
}
return w.Write(buf.Bytes())
}
// HuffmanDecodeToString decodes the string in v.
func HuffmanDecodeToString(v []byte) (string, error) {
buf := bufPool.Get().(*bytes.Buffer)
buf.Reset()
defer bufPool.Put(buf)
if err := huffmanDecode(buf, 0, v); err != nil {
return "", err
}
return buf.String(), nil
}
// ErrInvalidHuffman is returned for errors found decoding
// Huffman-encoded strings.
var ErrInvalidHuffman = errors.New("hpack: invalid Huffman-encoded data")
// huffmanDecode decodes v to buf.
// If maxLen is greater than 0, attempts to write more to buf than
// maxLen bytes will return ErrStringLength.
func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error {
rootHuffmanNode := getRootHuffmanNode()
n := rootHuffmanNode
// cur is the bit buffer that has not been fed into n.
// cbits is the number of low order bits in cur that are valid.
// sbits is the number of bits of the symbol prefix being decoded.
cur, cbits, sbits := uint(0), uint8(0), uint8(0)
for _, b := range v {
cur = cur<<8 | uint(b)
cbits += 8
sbits += 8
for cbits >= 8 {
idx := byte(cur >> (cbits - 8))
n = n.children[idx]
if n == nil {
return ErrInvalidHuffman
}
if n.children == nil {
if maxLen != 0 && buf.Len() == maxLen {
return ErrStringLength
}
buf.WriteByte(n.sym)
cbits -= n.codeLen
n = rootHuffmanNode
sbits = cbits
} else {
cbits -= 8
}
}
}
for cbits > 0 {
n = n.children[byte(cur<<(8-cbits))]
if n == nil {
return ErrInvalidHuffman
}
if n.children != nil || n.codeLen > cbits {
break
}
if maxLen != 0 && buf.Len() == maxLen {
return ErrStringLength
}
buf.WriteByte(n.sym)
cbits -= n.codeLen
n = rootHuffmanNode
sbits = cbits
}
if sbits > 7 {
// Either there was an incomplete symbol, or overlong padding.
// Both are decoding errors per RFC 7541 section 5.2.
return ErrInvalidHuffman
}
if mask := uint(1<<cbits - 1); cur&mask != mask {
// Trailing bits must be a prefix of EOS per RFC 7541 section 5.2.
return ErrInvalidHuffman
}
return nil
}
// incomparable is a zero-width, non-comparable type. Adding it to a struct
// makes that struct also non-comparable, and generally doesn't add
// any size (as long as it's first).
type incomparable [0]func()
type node struct {
_ incomparable
// children is non-nil for internal nodes
children *[256]*node
// The following are only valid if children is nil:
codeLen uint8 // number of bits that led to the output of sym
sym byte // output symbol
}
func newInternalNode() *node {
return &node{children: new([256]*node)}
}
var (
buildRootOnce sync.Once
lazyRootHuffmanNode *node
)
func getRootHuffmanNode() *node {
buildRootOnce.Do(buildRootHuffmanNode)
return lazyRootHuffmanNode
}
func buildRootHuffmanNode() {
if len(huffmanCodes) != 256 {
panic("unexpected size")
}
lazyRootHuffmanNode = newInternalNode()
// allocate a leaf node for each of the 256 symbols
leaves := new([256]node)
for sym, code := range huffmanCodes {
codeLen := huffmanCodeLen[sym]
cur := lazyRootHuffmanNode
for codeLen > 8 {
codeLen -= 8
i := uint8(code >> codeLen)
if cur.children[i] == nil {
cur.children[i] = newInternalNode()
}
cur = cur.children[i]
}
shift := 8 - codeLen
start, end := int(uint8(code<<shift)), int(1<<shift)
leaves[sym].sym = byte(sym)
leaves[sym].codeLen = codeLen
for i := start; i < start+end; i++ {
cur.children[i] = &leaves[sym]
}
}
}
// AppendHuffmanString appends s, as encoded in Huffman codes, to dst
// and returns the extended buffer.
func AppendHuffmanString(dst []byte, s string) []byte {
// This relies on the maximum huffman code length being 30 (See tables.go huffmanCodeLen array)
// So if a uint64 buffer has less than 32 valid bits can always accommodate another huffmanCode.
var (
x uint64 // buffer
n uint // number valid of bits present in x
)
for i := 0; i < len(s); i++ {
c := s[i]
n += uint(huffmanCodeLen[c])
x <<= huffmanCodeLen[c] % 64
x |= uint64(huffmanCodes[c])
if n >= 32 {
n %= 32 // Normally would be -= 32 but %= 32 informs compiler 0 <= n <= 31 for upcoming shift
y := uint32(x >> n) // Compiler doesn't combine memory writes if y isn't uint32
dst = append(dst, byte(y>>24), byte(y>>16), byte(y>>8), byte(y))
}
}
// Add padding bits if necessary
if over := n % 8; over > 0 {
const (
eosCode = 0x3fffffff
eosNBits = 30
eosPadByte = eosCode >> (eosNBits - 8)
)
pad := 8 - over
x = (x << pad) | (eosPadByte >> over)
n += pad // 8 now divides into n exactly
}
// n in (0, 8, 16, 24, 32)
switch n / 8 {
case 0:
return dst
case 1:
return append(dst, byte(x))
case 2:
y := uint16(x)
return append(dst, byte(y>>8), byte(y))
case 3:
y := uint16(x >> 8)
return append(dst, byte(y>>8), byte(y), byte(x))
}
// case 4:
y := uint32(x)
return append(dst, byte(y>>24), byte(y>>16), byte(y>>8), byte(y))
}
// HuffmanEncodeLength returns the number of bytes required to encode
// s in Huffman codes. The result is round up to byte boundary.
func HuffmanEncodeLength(s string) uint64 {
n := uint64(0)
for i := 0; i < len(s); i++ {
n += uint64(huffmanCodeLen[s[i]])
}
return (n + 7) / 8
}
// 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 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 {
delete(t.byName, f.Name)
}
if p := (pairNameValue{f.Name, f.Value}); t.byNameValue[p] == id {
delete(t.byNameValue, p)
}
}
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.
//
// 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
}
var huffmanCodes = [256]uint32{
0x1ff8,
0x7fffd8,
0xfffffe2,
0xfffffe3,
0xfffffe4,
0xfffffe5,
0xfffffe6,
0xfffffe7,
0xfffffe8,
0xffffea,
0x3ffffffc,
0xfffffe9,
0xfffffea,
0x3ffffffd,
0xfffffeb,
0xfffffec,
0xfffffed,
0xfffffee,
0xfffffef,
0xffffff0,
0xffffff1,
0xffffff2,
0x3ffffffe,
0xffffff3,
0xffffff4,
0xffffff5,
0xffffff6,
0xffffff7,
0xffffff8,
0xffffff9,
0xffffffa,
0xffffffb,
0x14,
0x3f8,
0x3f9,
0xffa,
0x1ff9,
0x15,
0xf8,
0x7fa,
0x3fa,
0x3fb,
0xf9,
0x7fb,
0xfa,
0x16,
0x17,
0x18,
0x0,
0x1,
0x2,
0x19,
0x1a,
0x1b,
0x1c,
0x1d,
0x1e,
0x1f,
0x5c,
0xfb,
0x7ffc,
0x20,
0xffb,
0x3fc,
0x1ffa,
0x21,
0x5d,
0x5e,
0x5f,
0x60,
0x61,
0x62,
0x63,
0x64,
0x65,
0x66,
0x67,
0x68,
0x69,
0x6a,
0x6b,
0x6c,
0x6d,
0x6e,
0x6f,
0x70,
0x71,
0x72,
0xfc,
0x73,
0xfd,
0x1ffb,
0x7fff0,
0x1ffc,
0x3ffc,
0x22,
0x7ffd,
0x3,
0x23,
0x4,
0x24,
0x5,
0x25,
0x26,
0x27,
0x6,
0x74,
0x75,
0x28,
0x29,
0x2a,
0x7,
0x2b,
0x76,
0x2c,
0x8,
0x9,
0x2d,
0x77,
0x78,
0x79,
0x7a,
0x7b,
0x7ffe,
0x7fc,
0x3ffd,
0x1ffd,
0xffffffc,
0xfffe6,
0x3fffd2,
0xfffe7,
0xfffe8,
0x3fffd3,
0x3fffd4,
0x3fffd5,
0x7fffd9,
0x3fffd6,
0x7fffda,
0x7fffdb,
0x7fffdc,
0x7fffdd,
0x7fffde,
0xffffeb,
0x7fffdf,
0xffffec,
0xffffed,
0x3fffd7,
0x7fffe0,
0xffffee,
0x7fffe1,
0x7fffe2,
0x7fffe3,
0x7fffe4,
0x1fffdc,
0x3fffd8,
0x7fffe5,
0x3fffd9,
0x7fffe6,
0x7fffe7,
0xffffef,
0x3fffda,
0x1fffdd,
0xfffe9,
0x3fffdb,
0x3fffdc,
0x7fffe8,
0x7fffe9,
0x1fffde,
0x7fffea,
0x3fffdd,
0x3fffde,
0xfffff0,
0x1fffdf,
0x3fffdf,
0x7fffeb,
0x7fffec,
0x1fffe0,
0x1fffe1,
0x3fffe0,
0x1fffe2,
0x7fffed,
0x3fffe1,
0x7fffee,
0x7fffef,
0xfffea,
0x3fffe2,
0x3fffe3,
0x3fffe4,
0x7ffff0,
0x3fffe5,
0x3fffe6,
0x7ffff1,
0x3ffffe0,
0x3ffffe1,
0xfffeb,
0x7fff1,
0x3fffe7,
0x7ffff2,
0x3fffe8,
0x1ffffec,
0x3ffffe2,
0x3ffffe3,
0x3ffffe4,
0x7ffffde,
0x7ffffdf,
0x3ffffe5,
0xfffff1,
0x1ffffed,
0x7fff2,
0x1fffe3,
0x3ffffe6,
0x7ffffe0,
0x7ffffe1,
0x3ffffe7,
0x7ffffe2,
0xfffff2,
0x1fffe4,
0x1fffe5,
0x3ffffe8,
0x3ffffe9,
0xffffffd,
0x7ffffe3,
0x7ffffe4,
0x7ffffe5,
0xfffec,
0xfffff3,
0xfffed,
0x1fffe6,
0x3fffe9,
0x1fffe7,
0x1fffe8,
0x7ffff3,
0x3fffea,
0x3fffeb,
0x1ffffee,
0x1ffffef,
0xfffff4,
0xfffff5,
0x3ffffea,
0x7ffff4,
0x3ffffeb,
0x7ffffe6,
0x3ffffec,
0x3ffffed,
0x7ffffe7,
0x7ffffe8,
0x7ffffe9,
0x7ffffea,
0x7ffffeb,
0xffffffe,
0x7ffffec,
0x7ffffed,
0x7ffffee,
0x7ffffef,
0x7fffff0,
0x3ffffee,
}
var huffmanCodeLen = [256]uint8{
13, 23, 28, 28, 28, 28, 28, 28, 28, 24, 30, 28, 28, 30, 28, 28,
28, 28, 28, 28, 28, 28, 30, 28, 28, 28, 28, 28, 28, 28, 28, 28,
6, 10, 10, 12, 13, 6, 8, 11, 10, 10, 8, 11, 8, 6, 6, 6,
5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 8, 15, 6, 12, 10,
13, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 13, 19, 13, 14, 6,
15, 5, 6, 5, 6, 5, 6, 6, 6, 5, 7, 7, 6, 6, 6, 5,
6, 7, 6, 5, 5, 6, 7, 7, 7, 7, 7, 15, 11, 14, 13, 28,
20, 22, 20, 20, 22, 22, 22, 23, 22, 23, 23, 23, 23, 23, 24, 23,
24, 24, 22, 23, 24, 23, 23, 23, 23, 21, 22, 23, 22, 23, 23, 24,
22, 21, 20, 22, 22, 23, 23, 21, 23, 22, 22, 24, 21, 22, 23, 23,
21, 21, 22, 21, 23, 22, 23, 23, 20, 22, 22, 22, 23, 22, 22, 23,
26, 26, 20, 19, 22, 23, 22, 25, 26, 26, 26, 27, 27, 26, 24, 25,
19, 21, 26, 27, 27, 26, 27, 24, 21, 21, 26, 26, 28, 27, 27, 27,
20, 24, 20, 21, 22, 21, 21, 23, 22, 22, 25, 25, 24, 24, 26, 23,
26, 27, 26, 26, 27, 27, 27, 27, 27, 28, 27, 27, 27, 27, 27, 26,
}
// 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 implements the HTTP/2 protocol.
//
// This package is low-level and intended to be used directly by very
// few people. Most users will use it indirectly through the automatic
// use by the net/http package (from Go 1.6 and later).
// For use in earlier Go versions see ConfigureServer. (Transport support
// requires Go 1.6 or later)
//
// See https://http2.github.io/ for more information on HTTP/2.
package http2 // import "golang.org/x/net/http2"
import (
"bufio"
"crypto/tls"
"errors"
"fmt"
"net"
"net/http"
"os"
"sort"
"strconv"
"strings"
"sync"
"time"
"golang.org/x/net/http/httpguts"
)
var (
VerboseLogs bool
logFrameWrites bool
logFrameReads bool
// Enabling extended CONNECT by causes browsers to attempt to use
// WebSockets-over-HTTP/2. This results in problems when the server's websocket
// package doesn't support extended CONNECT.
//
// Disable extended CONNECT by default for now.
//
// Issue #71128.
disableExtendedConnectProtocol = true
)
func init() {
e := os.Getenv("GODEBUG")
if strings.Contains(e, "http2debug=1") {
VerboseLogs = true
}
if strings.Contains(e, "http2debug=2") {
VerboseLogs = true
logFrameWrites = true
logFrameReads = true
}
if strings.Contains(e, "http2xconnect=1") {
disableExtendedConnectProtocol = false
}
}
const (
// ClientPreface is the string that must be sent by new
// connections from clients.
ClientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
// SETTINGS_MAX_FRAME_SIZE default
// https://httpwg.org/specs/rfc7540.html#rfc.section.6.5.2
initialMaxFrameSize = 16384
// NextProtoTLS is the NPN/ALPN protocol negotiated during
// HTTP/2's TLS setup.
NextProtoTLS = "h2"
// https://httpwg.org/specs/rfc7540.html#SettingValues
initialHeaderTableSize = 4096
initialWindowSize = 65535 // 6.9.2 Initial Flow Control Window Size
defaultMaxReadFrameSize = 1 << 20
)
var (
clientPreface = []byte(ClientPreface)
)
type streamState int
// HTTP/2 stream states.
//
// See http://tools.ietf.org/html/rfc7540#section-5.1.
//
// For simplicity, the server code merges "reserved (local)" into
// "half-closed (remote)". This is one less state transition to track.
// The only downside is that we send PUSH_PROMISEs slightly less
// liberally than allowable. More discussion here:
// https://lists.w3.org/Archives/Public/ietf-http-wg/2016JulSep/0599.html
//
// "reserved (remote)" is omitted since the client code does not
// support server push.
const (
stateIdle streamState = iota
stateOpen
stateHalfClosedLocal
stateHalfClosedRemote
stateClosed
)
var stateName = [...]string{
stateIdle: "Idle",
stateOpen: "Open",
stateHalfClosedLocal: "HalfClosedLocal",
stateHalfClosedRemote: "HalfClosedRemote",
stateClosed: "Closed",
}
func (st streamState) String() string {
return stateName[st]
}
// Setting is a setting parameter: which setting it is, and its value.
type Setting struct {
// ID is which setting is being set.
// See https://httpwg.org/specs/rfc7540.html#SettingFormat
ID SettingID
// Val is the value.
Val uint32
}
func (s Setting) String() string {
return fmt.Sprintf("[%v = %d]", s.ID, s.Val)
}
// Valid reports whether the setting is valid.
func (s Setting) Valid() error {
// Limits and error codes from 6.5.2 Defined SETTINGS Parameters
switch s.ID {
case SettingEnablePush:
if s.Val != 1 && s.Val != 0 {
return ConnectionError(ErrCodeProtocol)
}
case SettingInitialWindowSize:
if s.Val > 1<<31-1 {
return ConnectionError(ErrCodeFlowControl)
}
case SettingMaxFrameSize:
if s.Val < 16384 || s.Val > 1<<24-1 {
return ConnectionError(ErrCodeProtocol)
}
case SettingEnableConnectProtocol:
if s.Val != 1 && s.Val != 0 {
return ConnectionError(ErrCodeProtocol)
}
}
return nil
}
// A SettingID is an HTTP/2 setting as defined in
// https://httpwg.org/specs/rfc7540.html#iana-settings
type SettingID uint16
const (
SettingHeaderTableSize SettingID = 0x1
SettingEnablePush SettingID = 0x2
SettingMaxConcurrentStreams SettingID = 0x3
SettingInitialWindowSize SettingID = 0x4
SettingMaxFrameSize SettingID = 0x5
SettingMaxHeaderListSize SettingID = 0x6
SettingEnableConnectProtocol SettingID = 0x8
)
var settingName = map[SettingID]string{
SettingHeaderTableSize: "HEADER_TABLE_SIZE",
SettingEnablePush: "ENABLE_PUSH",
SettingMaxConcurrentStreams: "MAX_CONCURRENT_STREAMS",
SettingInitialWindowSize: "INITIAL_WINDOW_SIZE",
SettingMaxFrameSize: "MAX_FRAME_SIZE",
SettingMaxHeaderListSize: "MAX_HEADER_LIST_SIZE",
SettingEnableConnectProtocol: "ENABLE_CONNECT_PROTOCOL",
}
func (s SettingID) String() string {
if v, ok := settingName[s]; ok {
return v
}
return fmt.Sprintf("UNKNOWN_SETTING_%d", uint16(s))
}
// validWireHeaderFieldName reports whether v is a valid header field
// name (key). See httpguts.ValidHeaderName for the base rules.
//
// Further, http2 says:
//
// "Just as in HTTP/1.x, header field names are strings of ASCII
// characters that are compared in a case-insensitive
// fashion. However, header field names MUST be converted to
// lowercase prior to their encoding in HTTP/2. "
func validWireHeaderFieldName(v string) bool {
if len(v) == 0 {
return false
}
for _, r := range v {
if !httpguts.IsTokenRune(r) {
return false
}
if 'A' <= r && r <= 'Z' {
return false
}
}
return true
}
func httpCodeString(code int) string {
switch code {
case 200:
return "200"
case 404:
return "404"
}
return strconv.Itoa(code)
}
// from pkg io
type stringWriter interface {
WriteString(s string) (n int, err error)
}
// A closeWaiter is like a sync.WaitGroup but only goes 1 to 0 (open to closed).
type closeWaiter chan struct{}
// Init makes a closeWaiter usable.
// It exists because so a closeWaiter value can be placed inside a
// larger struct and have the Mutex and Cond's memory in the same
// allocation.
func (cw *closeWaiter) Init() {
*cw = make(chan struct{})
}
// Close marks the closeWaiter as closed and unblocks any waiters.
func (cw closeWaiter) Close() {
close(cw)
}
// Wait waits for the closeWaiter to become closed.
func (cw closeWaiter) Wait() {
<-cw
}
// bufferedWriter is a buffered writer that writes to w.
// Its buffered writer is lazily allocated as needed, to minimize
// idle memory usage with many connections.
type bufferedWriter struct {
_ incomparable
conn net.Conn // immutable
bw *bufio.Writer // non-nil when data is buffered
byteTimeout time.Duration // immutable, WriteByteTimeout
}
func newBufferedWriter(conn net.Conn, timeout time.Duration) *bufferedWriter {
return &bufferedWriter{
conn: conn,
byteTimeout: timeout,
}
}
// bufWriterPoolBufferSize is the size of bufio.Writer's
// buffers created using bufWriterPool.
//
// TODO: pick a less arbitrary value? this is a bit under
// (3 x typical 1500 byte MTU) at least. Other than that,
// not much thought went into it.
const bufWriterPoolBufferSize = 4 << 10
var bufWriterPool = sync.Pool{
New: func() interface{} {
return bufio.NewWriterSize(nil, bufWriterPoolBufferSize)
},
}
func (w *bufferedWriter) Available() int {
if w.bw == nil {
return bufWriterPoolBufferSize
}
return w.bw.Available()
}
func (w *bufferedWriter) Write(p []byte) (n int, err error) {
if w.bw == nil {
bw := bufWriterPool.Get().(*bufio.Writer)
bw.Reset((*bufferedWriterTimeoutWriter)(w))
w.bw = bw
}
return w.bw.Write(p)
}
func (w *bufferedWriter) Flush() error {
bw := w.bw
if bw == nil {
return nil
}
err := bw.Flush()
bw.Reset(nil)
bufWriterPool.Put(bw)
w.bw = nil
return err
}
type bufferedWriterTimeoutWriter bufferedWriter
func (w *bufferedWriterTimeoutWriter) Write(p []byte) (n int, err error) {
return writeWithByteTimeout(w.conn, w.byteTimeout, p)
}
// writeWithByteTimeout writes to conn.
// If more than timeout passes without any bytes being written to the connection,
// the write fails.
func writeWithByteTimeout(conn net.Conn, timeout time.Duration, p []byte) (n int, err error) {
if timeout <= 0 {
return conn.Write(p)
}
for {
conn.SetWriteDeadline(time.Now().Add(timeout))
nn, err := conn.Write(p[n:])
n += nn
if n == len(p) || nn == 0 || !errors.Is(err, os.ErrDeadlineExceeded) {
// Either we finished the write, made no progress, or hit the deadline.
// Whichever it is, we're done now.
conn.SetWriteDeadline(time.Time{})
return n, err
}
}
}
func mustUint31(v int32) uint32 {
if v < 0 || v > 2147483647 {
panic("out of range")
}
return uint32(v)
}
// bodyAllowedForStatus reports whether a given response status code
// permits a body. See RFC 7230, section 3.3.
func bodyAllowedForStatus(status int) bool {
switch {
case status >= 100 && status <= 199:
return false
case status == 204:
return false
case status == 304:
return false
}
return true
}
type httpError struct {
_ incomparable
msg string
timeout bool
}
func (e *httpError) Error() string { return e.msg }
func (e *httpError) Timeout() bool { return e.timeout }
func (e *httpError) Temporary() bool { return true }
var errTimeout error = &httpError{msg: "http2: timeout awaiting response headers", timeout: true}
type connectionStater interface {
ConnectionState() tls.ConnectionState
}
var sorterPool = sync.Pool{New: func() interface{} { return new(sorter) }}
type sorter struct {
v []string // owned by sorter
}
func (s *sorter) Len() int { return len(s.v) }
func (s *sorter) Swap(i, j int) { s.v[i], s.v[j] = s.v[j], s.v[i] }
func (s *sorter) Less(i, j int) bool { return s.v[i] < s.v[j] }
// Keys returns the sorted keys of h.
//
// The returned slice is only valid until s used again or returned to
// its pool.
func (s *sorter) Keys(h http.Header) []string {
keys := s.v[:0]
for k := range h {
keys = append(keys, k)
}
s.v = keys
sort.Sort(s)
return keys
}
func (s *sorter) SortStrings(ss []string) {
// Our sorter works on s.v, which sorter owns, so
// stash it away while we sort the user's buffer.
save := s.v
s.v = ss
sort.Sort(s)
s.v = save
}
// incomparable is a zero-width, non-comparable type. Adding it to a struct
// makes that struct also non-comparable, and generally doesn't add
// any size (as long as it's first).
type incomparable [0]func()
// 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"
"io"
"sync"
)
// 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 {
mu sync.Mutex
c sync.Cond // c.L lazily initialized to &p.mu
b pipeBuffer // nil when done reading
unread int // bytes unread when done
err error // read error once empty. non-nil means closed.
breakErr error // immediate read error (caller doesn't see rest of b)
donec chan struct{} // closed on error
readFn func() // optional code to run in Read before error
}
type pipeBuffer interface {
Len() int
io.Writer
io.Reader
}
// setBuffer initializes the pipe buffer.
// It has no effect if the pipe is already closed.
func (p *pipe) setBuffer(b pipeBuffer) {
p.mu.Lock()
defer p.mu.Unlock()
if p.err != nil || p.breakErr != nil {
return
}
p.b = b
}
func (p *pipe) Len() int {
p.mu.Lock()
defer p.mu.Unlock()
if p.b == nil {
return p.unread
}
return p.b.Len()
}
// Read waits until data is available and copies bytes
// from the buffer into p.
func (p *pipe) Read(d []byte) (n int, err error) {
p.mu.Lock()
defer p.mu.Unlock()
if p.c.L == nil {
p.c.L = &p.mu
}
for {
if p.breakErr != nil {
return 0, p.breakErr
}
if p.b != nil && p.b.Len() > 0 {
return p.b.Read(d)
}
if p.err != nil {
if p.readFn != nil {
p.readFn() // e.g. copy trailers
p.readFn = nil // not sticky like p.err
}
p.b = nil
return 0, p.err
}
p.c.Wait()
}
}
var (
errClosedPipeWrite = errors.New("write on closed buffer")
errUninitializedPipeWrite = errors.New("write on uninitialized buffer")
)
// Write copies bytes from p into the buffer and wakes a reader.
// It is an error to write more data than the buffer can hold.
func (p *pipe) Write(d []byte) (n int, err error) {
p.mu.Lock()
defer p.mu.Unlock()
if p.c.L == nil {
p.c.L = &p.mu
}
defer p.c.Signal()
if p.err != nil || p.breakErr != nil {
return 0, errClosedPipeWrite
}
// pipe.setBuffer is never invoked, leaving the buffer uninitialized.
// We shouldn't try to write to an uninitialized pipe,
// but returning an error is better than panicking.
if p.b == nil {
return 0, errUninitializedPipeWrite
}
return p.b.Write(d)
}
// CloseWithError causes the next Read (waking up a current blocked
// Read if needed) to return the provided err after all data has been
// read.
//
// The error must be non-nil.
func (p *pipe) CloseWithError(err error) { p.closeWithError(&p.err, err, nil) }
// BreakWithError causes the next Read (waking up a current blocked
// Read if needed) to return the provided err immediately, without
// waiting for unread data.
func (p *pipe) BreakWithError(err error) { p.closeWithError(&p.breakErr, err, nil) }
// closeWithErrorAndCode is like CloseWithError but also sets some code to run
// in the caller's goroutine before returning the error.
func (p *pipe) closeWithErrorAndCode(err error, fn func()) { p.closeWithError(&p.err, err, fn) }
func (p *pipe) closeWithError(dst *error, err error, fn func()) {
if err == nil {
panic("err must be non-nil")
}
p.mu.Lock()
defer p.mu.Unlock()
if p.c.L == nil {
p.c.L = &p.mu
}
defer p.c.Signal()
if *dst != nil {
// Already been done.
return
}
p.readFn = fn
if dst == &p.breakErr {
if p.b != nil {
p.unread += p.b.Len()
}
p.b = nil
}
*dst = err
p.closeDoneLocked()
}
// requires p.mu be held.
func (p *pipe) closeDoneLocked() {
if p.donec == nil {
return
}
// Close if unclosed. This isn't racy since we always
// hold p.mu while closing.
select {
case <-p.donec:
default:
close(p.donec)
}
}
// Err returns the error (if any) first set by BreakWithError or CloseWithError.
func (p *pipe) Err() error {
p.mu.Lock()
defer p.mu.Unlock()
if p.breakErr != nil {
return p.breakErr
}
return p.err
}
// Done returns a channel which is closed if and when this pipe is closed
// with CloseWithError.
func (p *pipe) Done() <-chan struct{} {
p.mu.Lock()
defer p.mu.Unlock()
if p.donec == nil {
p.donec = make(chan struct{})
if p.err != nil || p.breakErr != nil {
// Already hit an error.
p.closeDoneLocked()
}
}
return p.donec
}
// 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.
// TODO: turn off the serve goroutine when idle, so
// an idle conn only has the readFrames goroutine active. (which could
// also be optimized probably to pin less memory in crypto/tls). This
// would involve tracking when the serve goroutine is active (atomic
// int32 read/CAS probably?) and starting it up when frames arrive,
// and shutting it down when all handlers exit. the occasional PING
// packets could use time.AfterFunc to call sc.wakeStartServeLoop()
// (which is a no-op if already running) and then queue the PING write
// as normal. The serve loop would then exit in most cases (if no
// Handlers running) and not be woken up again until the PING packet
// returns.
// TODO (maybe): add a mechanism for Handlers to going into
// half-closed-local mode (rw.(io.Closer) test?) but not exit their
// handler, and continue to be able to read from the
// Request.Body. This would be a somewhat semantic change from HTTP/1
// (or at least what we expose in net/http), so I'd probably want to
// add it there too. For now, this package says that returning from
// the Handler ServeHTTP function means you're both done reading and
// done writing, without a way to stop just one or the other.
package http2
import (
"bufio"
"bytes"
"context"
"crypto/rand"
"crypto/tls"
"errors"
"fmt"
"io"
"log"
"math"
"net"
"net/http"
"net/textproto"
"net/url"
"os"
"reflect"
"runtime"
"strconv"
"strings"
"sync"
"time"
"golang.org/x/net/http/httpguts"
"golang.org/x/net/http2/hpack"
"golang.org/x/net/internal/httpcommon"
)
const (
prefaceTimeout = 10 * time.Second
firstSettingsTimeout = 2 * time.Second // should be in-flight with preface anyway
handlerChunkWriteSize = 4 << 10
defaultMaxStreams = 250 // TODO: make this 100 as the GFE seems to?
// maxQueuedControlFrames is the maximum number of control frames like
// SETTINGS, PING and RST_STREAM that will be queued for writing before
// the connection is closed to prevent memory exhaustion attacks.
maxQueuedControlFrames = 10000
)
var (
errClientDisconnected = errors.New("client disconnected")
errClosedBody = errors.New("body closed by handler")
errHandlerComplete = errors.New("http2: request body closed due to handler exiting")
errStreamClosed = errors.New("http2: stream closed")
)
var responseWriterStatePool = sync.Pool{
New: func() interface{} {
rws := &responseWriterState{}
rws.bw = bufio.NewWriterSize(chunkWriter{rws}, handlerChunkWriteSize)
return rws
},
}
// Test hooks.
var (
testHookOnConn func()
testHookGetServerConn func(*serverConn)
testHookOnPanicMu *sync.Mutex // nil except in tests
testHookOnPanic func(sc *serverConn, panicVal interface{}) (rePanic bool)
)
// Server is an HTTP/2 server.
type Server struct {
// MaxHandlers limits the number of http.Handler ServeHTTP goroutines
// which may run at a time over all connections.
// Negative or zero no limit.
// TODO: implement
MaxHandlers int
// MaxConcurrentStreams optionally specifies the number of
// concurrent streams that each client may have open at a
// time. This is unrelated to the number of http.Handler goroutines
// which may be active globally, which is MaxHandlers.
// If zero, MaxConcurrentStreams defaults to at least 100, per
// the HTTP/2 spec's recommendations.
MaxConcurrentStreams uint32
// MaxDecoderHeaderTableSize optionally specifies the http2
// SETTINGS_HEADER_TABLE_SIZE to send in the initial settings frame. It
// informs the remote endpoint of the maximum size of the header compression
// table used to decode header blocks, in octets. If zero, the default value
// of 4096 is used.
MaxDecoderHeaderTableSize uint32
// MaxEncoderHeaderTableSize optionally specifies an upper limit for the
// header compression table used for encoding request headers. Received
// SETTINGS_HEADER_TABLE_SIZE settings are capped at this limit. If zero,
// the default value of 4096 is used.
MaxEncoderHeaderTableSize uint32
// MaxReadFrameSize optionally specifies the largest frame
// this server is willing to read. A valid value is between
// 16k and 16M, inclusive. If zero or otherwise invalid, a
// default value is used.
MaxReadFrameSize uint32
// PermitProhibitedCipherSuites, if true, permits the use of
// cipher suites prohibited by the HTTP/2 spec.
PermitProhibitedCipherSuites bool
// IdleTimeout specifies how long until idle clients should be
// closed with a GOAWAY frame. PING frames are not considered
// activity for the purposes of IdleTimeout.
// If zero or negative, there is no timeout.
IdleTimeout time.Duration
// ReadIdleTimeout is the timeout after which a health check using a ping
// frame will be carried out if no frame is received on the connection.
// If zero, no health check is performed.
ReadIdleTimeout time.Duration
// PingTimeout is the timeout after which the connection will be closed
// if a response to a ping is not received.
// If zero, a default of 15 seconds is used.
PingTimeout time.Duration
// WriteByteTimeout is the timeout after which a connection will be
// closed if no data can be written to it. The timeout begins when data is
// available to write, and is extended whenever any bytes are written.
// If zero or negative, there is no timeout.
WriteByteTimeout 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
// CountError, if non-nil, is called on HTTP/2 server errors.
// It's intended to increment a metric for monitoring, such
// as an expvar or Prometheus metric.
// The errType consists of only ASCII word characters.
CountError func(errType string)
// Internal state. This is a pointer (rather than embedded directly)
// so that we don't embed a Mutex in this struct, which will make the
// struct non-copyable, which might break some callers.
state *serverInternalState
}
type serverInternalState struct {
mu sync.Mutex
activeConns map[*serverConn]struct{}
// Pool of error channels. This is per-Server rather than global
// because channels can't be reused across synctest bubbles.
errChanPool sync.Pool
}
func (s *serverInternalState) registerConn(sc *serverConn) {
if s == nil {
return // if the Server was used without calling ConfigureServer
}
s.mu.Lock()
s.activeConns[sc] = struct{}{}
s.mu.Unlock()
}
func (s *serverInternalState) unregisterConn(sc *serverConn) {
if s == nil {
return // if the Server was used without calling ConfigureServer
}
s.mu.Lock()
delete(s.activeConns, sc)
s.mu.Unlock()
}
func (s *serverInternalState) startGracefulShutdown() {
if s == nil {
return // if the Server was used without calling ConfigureServer
}
s.mu.Lock()
for sc := range s.activeConns {
sc.startGracefulShutdown()
}
s.mu.Unlock()
}
// Global error channel pool used for uninitialized Servers.
// We use a per-Server pool when possible to avoid using channels across synctest bubbles.
var errChanPool = sync.Pool{
New: func() any { return make(chan error, 1) },
}
func (s *serverInternalState) getErrChan() chan error {
if s == nil {
return errChanPool.Get().(chan error) // Server used without calling ConfigureServer
}
return s.errChanPool.Get().(chan error)
}
func (s *serverInternalState) putErrChan(ch chan error) {
if s == nil {
errChanPool.Put(ch) // Server used without calling ConfigureServer
return
}
s.errChanPool.Put(ch)
}
// ConfigureServer adds HTTP/2 support to a net/http Server.
//
// The configuration conf may be nil.
//
// ConfigureServer must be called before s begins serving.
func ConfigureServer(s *http.Server, conf *Server) error {
if s == nil {
panic("nil *http.Server")
}
if conf == nil {
conf = new(Server)
}
conf.state = &serverInternalState{
activeConns: make(map[*serverConn]struct{}),
errChanPool: sync.Pool{New: func() any { return make(chan error, 1) }},
}
if h1, h2 := s, conf; h2.IdleTimeout == 0 {
if h1.IdleTimeout != 0 {
h2.IdleTimeout = h1.IdleTimeout
} else {
h2.IdleTimeout = h1.ReadTimeout
}
}
s.RegisterOnShutdown(conf.state.startGracefulShutdown)
if s.TLSConfig == nil {
s.TLSConfig = new(tls.Config)
} else if s.TLSConfig.CipherSuites != nil && s.TLSConfig.MinVersion < tls.VersionTLS13 {
// If they already provided a TLS 1.0–1.2 CipherSuite list, return an
// error if it is missing ECDHE_RSA_WITH_AES_128_GCM_SHA256 or
// ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.
haveRequired := false
for _, cs := range s.TLSConfig.CipherSuites {
switch cs {
case tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
// Alternative MTI cipher to not discourage ECDSA-only servers.
// See http://golang.org/cl/30721 for further information.
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
haveRequired = true
}
}
if !haveRequired {
return fmt.Errorf("http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher (need at least one of TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 or TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)")
}
}
// Note: not setting MinVersion to tls.VersionTLS12,
// as we don't want to interfere with HTTP/1.1 traffic
// on the user's server. We enforce TLS 1.2 later once
// we accept a connection. Ideally this should be done
// during next-proto selection, but using TLS <1.2 with
// HTTP/2 is still the client's bug.
s.TLSConfig.PreferServerCipherSuites = true
if !strSliceContains(s.TLSConfig.NextProtos, NextProtoTLS) {
s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, NextProtoTLS)
}
if !strSliceContains(s.TLSConfig.NextProtos, "http/1.1") {
s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, "http/1.1")
}
if s.TLSNextProto == nil {
s.TLSNextProto = map[string]func(*http.Server, *tls.Conn, http.Handler){}
}
protoHandler := func(hs *http.Server, c net.Conn, h http.Handler, sawClientPreface bool) {
if testHookOnConn != nil {
testHookOnConn()
}
// The TLSNextProto interface predates contexts, so
// the net/http package passes down its per-connection
// base context via an exported but unadvertised
// method on the Handler. This is for internal
// net/http<=>http2 use only.
var ctx context.Context
type baseContexter interface {
BaseContext() context.Context
}
if bc, ok := h.(baseContexter); ok {
ctx = bc.BaseContext()
}
conf.ServeConn(c, &ServeConnOpts{
Context: ctx,
Handler: h,
BaseConfig: hs,
SawClientPreface: sawClientPreface,
})
}
s.TLSNextProto[NextProtoTLS] = func(hs *http.Server, c *tls.Conn, h http.Handler) {
protoHandler(hs, c, h, false)
}
// The "unencrypted_http2" TLSNextProto key is used to pass off non-TLS HTTP/2 conns.
//
// A connection passed in this method has already had the HTTP/2 preface read from it.
s.TLSNextProto[nextProtoUnencryptedHTTP2] = func(hs *http.Server, c *tls.Conn, h http.Handler) {
nc, err := unencryptedNetConnFromTLSConn(c)
if err != nil {
if lg := hs.ErrorLog; lg != nil {
lg.Print(err)
} else {
log.Print(err)
}
go c.Close()
return
}
protoHandler(hs, nc, h, true)
}
return nil
}
// ServeConnOpts are options for the Server.ServeConn method.
type ServeConnOpts struct {
// Context is the base context to use.
// If nil, context.Background is used.
Context context.Context
// BaseConfig optionally sets the base configuration
// for values. If nil, defaults are used.
BaseConfig *http.Server
// Handler specifies which handler to use for processing
// requests. If nil, BaseConfig.Handler is used. If BaseConfig
// or BaseConfig.Handler is nil, http.DefaultServeMux is used.
Handler http.Handler
// UpgradeRequest is an initial request received on a connection
// undergoing an h2c upgrade. The request body must have been
// completely read from the connection before calling ServeConn,
// and the 101 Switching Protocols response written.
UpgradeRequest *http.Request
// Settings is the decoded contents of the HTTP2-Settings header
// in an h2c upgrade request.
Settings []byte
// SawClientPreface is set if the HTTP/2 connection preface
// has already been read from the connection.
SawClientPreface bool
}
func (o *ServeConnOpts) context() context.Context {
if o != nil && o.Context != nil {
return o.Context
}
return context.Background()
}
func (o *ServeConnOpts) baseConfig() *http.Server {
if o != nil && o.BaseConfig != nil {
return o.BaseConfig
}
return new(http.Server)
}
func (o *ServeConnOpts) handler() http.Handler {
if o != nil {
if o.Handler != nil {
return o.Handler
}
if o.BaseConfig != nil && o.BaseConfig.Handler != nil {
return o.BaseConfig.Handler
}
}
return http.DefaultServeMux
}
// ServeConn serves HTTP/2 requests on the provided connection and
// blocks until the connection is no longer readable.
//
// ServeConn starts speaking HTTP/2 assuming that c has not had any
// reads or writes. It writes its initial settings frame and expects
// to be able to read the preface and settings frame from the
// client. If c has a ConnectionState method like a *tls.Conn, the
// ConnectionState is used to verify the TLS ciphersuite and to set
// the Request.TLS field in Handlers.
//
// ServeConn does not support h2c by itself. Any h2c support must be
// implemented in terms of providing a suitably-behaving net.Conn.
//
// The opts parameter is optional. If nil, default values are used.
func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
if opts == nil {
opts = &ServeConnOpts{}
}
s.serveConn(c, opts, nil)
}
func (s *Server) serveConn(c net.Conn, opts *ServeConnOpts, newf func(*serverConn)) {
baseCtx, cancel := serverConnBaseContext(c, opts)
defer cancel()
http1srv := opts.baseConfig()
conf := configFromServer(http1srv, s)
sc := &serverConn{
srv: s,
hs: http1srv,
conn: c,
baseCtx: baseCtx,
remoteAddrStr: c.RemoteAddr().String(),
bw: newBufferedWriter(c, conf.WriteByteTimeout),
handler: opts.handler(),
streams: make(map[uint32]*stream),
readFrameCh: make(chan readFrameResult),
wantWriteFrameCh: make(chan FrameWriteRequest, 8),
serveMsgCh: make(chan interface{}, 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: conf.MaxConcurrentStreams,
initialStreamSendWindowSize: initialWindowSize,
initialStreamRecvWindowSize: conf.MaxUploadBufferPerStream,
maxFrameSize: initialMaxFrameSize,
pingTimeout: conf.PingTimeout,
countErrorFunc: conf.CountError,
serveG: newGoroutineLock(),
pushEnabled: true,
sawClientPreface: opts.SawClientPreface,
}
if newf != nil {
newf(sc)
}
s.state.registerConn(sc)
defer s.state.unregisterConn(sc)
// The net/http package sets the write deadline from the
// http.Server.WriteTimeout during the TLS handshake, but then
// passes the connection off to us with the deadline already set.
// Write deadlines are set per stream in serverConn.newStream.
// Disarm the net.Conn write deadline here.
if sc.hs.WriteTimeout > 0 {
sc.conn.SetWriteDeadline(time.Time{})
}
if s.NewWriteScheduler != nil {
sc.writeSched = s.NewWriteScheduler()
} else {
sc.writeSched = newRoundRobinWriteScheduler()
}
// 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.init(initialWindowSize)
sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf)
sc.hpackEncoder.SetMaxDynamicTableSizeLimit(conf.MaxEncoderHeaderTableSize)
fr := NewFramer(sc.bw, c)
if conf.CountError != nil {
fr.countError = conf.CountError
}
fr.ReadMetaHeaders = hpack.NewDecoder(conf.MaxDecoderHeaderTableSize, nil)
fr.MaxHeaderListSize = sc.maxHeaderListSize()
fr.SetMaxReadFrameSize(conf.MaxReadFrameSize)
sc.framer = fr
if tc, ok := c.(connectionStater); ok {
sc.tlsState = new(tls.ConnectionState)
*sc.tlsState = tc.ConnectionState()
// 9.2 Use of TLS Features
// An implementation of HTTP/2 over TLS MUST use TLS
// 1.2 or higher with the restrictions on feature set
// and cipher suite described in this section. Due to
// implementation limitations, it might not be
// possible to fail TLS negotiation. An endpoint MUST
// immediately terminate an HTTP/2 connection that
// does not meet the TLS requirements described in
// this section with a connection error (Section
// 5.4.1) of type INADEQUATE_SECURITY.
if sc.tlsState.Version < tls.VersionTLS12 {
sc.rejectConn(ErrCodeInadequateSecurity, "TLS version too low")
return
}
if sc.tlsState.ServerName == "" {
// Client must use SNI, but we don't enforce that anymore,
// since it was causing problems when connecting to bare IP
// addresses during development.
//
// TODO: optionally enforce? Or enforce at the time we receive
// a new request, and verify the ServerName matches the :authority?
// But that precludes proxy situations, perhaps.
//
// So for now, do nothing here again.
}
if !conf.PermitProhibitedCipherSuites && isBadCipher(sc.tlsState.CipherSuite) {
// "Endpoints MAY choose to generate a connection error
// (Section 5.4.1) of type INADEQUATE_SECURITY if one of
// the prohibited cipher suites are negotiated."
//
// We choose that. In my opinion, the spec is weak
// here. It also says both parties must support at least
// TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 so there's no
// excuses here. If we really must, we could allow an
// "AllowInsecureWeakCiphers" option on the server later.
// Let's see how it plays out first.
sc.rejectConn(ErrCodeInadequateSecurity, fmt.Sprintf("Prohibited TLS 1.2 Cipher Suite: %x", sc.tlsState.CipherSuite))
return
}
}
if opts.Settings != nil {
fr := &SettingsFrame{
FrameHeader: FrameHeader{valid: true},
p: opts.Settings,
}
if err := fr.ForeachSetting(sc.processSetting); err != nil {
sc.rejectConn(ErrCodeProtocol, "invalid settings")
return
}
opts.Settings = nil
}
if hook := testHookGetServerConn; hook != nil {
hook(sc)
}
if opts.UpgradeRequest != nil {
sc.upgradeRequest(opts.UpgradeRequest)
opts.UpgradeRequest = nil
}
sc.serve(conf)
}
func serverConnBaseContext(c net.Conn, opts *ServeConnOpts) (ctx context.Context, cancel func()) {
ctx, cancel = context.WithCancel(opts.context())
ctx = context.WithValue(ctx, http.LocalAddrContextKey, c.LocalAddr())
if hs := opts.baseConfig(); hs != nil {
ctx = context.WithValue(ctx, http.ServerContextKey, hs)
}
return
}
func (sc *serverConn) rejectConn(err ErrCode, debug string) {
sc.vlogf("http2: server rejecting conn: %v, %s", err, debug)
// ignoring errors. hanging up anyway.
sc.framer.WriteGoAway(0, err, []byte(debug))
sc.bw.Flush()
sc.conn.Close()
}
type serverConn struct {
// Immutable:
srv *Server
hs *http.Server
conn net.Conn
bw *bufferedWriter // writing to conn
handler http.Handler
baseCtx context.Context
framer *Framer
doneServing chan struct{} // closed when serverConn.serve ends
readFrameCh chan readFrameResult // written by serverConn.readFrames
wantWriteFrameCh chan FrameWriteRequest // from handlers -> serve
wroteFrameCh chan frameWriteResult // from writeFrameAsync -> serve, tickles more frame writes
bodyReadCh chan bodyReadMsg // from handlers -> serve
serveMsgCh chan interface{} // misc messages & code to send to / run on the serve loop
flow outflow // conn-wide (not stream-specific) outbound flow control
inflow inflow // conn-wide inbound flow control
tlsState *tls.ConnectionState // shared by all handlers, like net/http
remoteAddrStr string
writeSched WriteScheduler
countErrorFunc func(errType string)
// Everything following is owned by the serve loop; use serveG.check():
serveG goroutineLock // used to verify funcs are on serve()
pushEnabled bool
sawClientPreface bool // preface has already been read, used in h2c upgrade
sawFirstSettings bool // got the initial SETTINGS frame after the preface
needToSendSettingsAck bool
unackedSettings int // how many SETTINGS have we sent without ACKs?
queuedControlFrames int // control frames in the writeSched queue
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
curHandlers uint32 // number of running handler goroutines
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
unstartedHandlers []unstartedHandler
initialStreamSendWindowSize int32
initialStreamRecvWindowSize int32
maxFrameSize int32
peerMaxHeaderListSize uint32 // zero means unknown (default)
canonHeader map[string]string // http2-lower-case -> Go-Canonical-Case
canonHeaderKeysSize int // canonHeader keys size in bytes
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
pingSent bool
sentPingData [8]byte
goAwayCode ErrCode
shutdownTimer *time.Timer // nil until used
idleTimer *time.Timer // nil if unused
readIdleTimeout time.Duration
pingTimeout time.Duration
readIdleTimer *time.Timer // nil if unused
// Owned by the writeFrameAsync goroutine:
headerWriteBuf bytes.Buffer
hpackEncoder *hpack.Encoder
// Used by startGracefulShutdown.
shutdownOnce sync.Once
}
func (sc *serverConn) maxHeaderListSize() uint32 {
n := sc.hs.MaxHeaderBytes
if n <= 0 {
n = http.DefaultMaxHeaderBytes
}
return uint32(adjustHTTP1MaxHeaderSize(int64(n)))
}
func (sc *serverConn) curOpenStreams() uint32 {
sc.serveG.check()
return sc.curClientStreams + sc.curPushedStreams
}
// stream represents a stream. This is the minimal metadata needed by
// the serve goroutine. Most of the actual stream state is owned by
// the http.Handler's goroutine in the responseWriter. Because the
// responseWriter's responseWriterState is recycled at the end of a
// handler, this struct intentionally has no pointer to the
// *responseWriter{,State} itself, as the Handler ending nils out the
// responseWriter's state field.
type stream struct {
// immutable:
sc *serverConn
id uint32
body *pipe // non-nil if expecting DATA frames
cw closeWaiter // closed wait stream transitions to closed state
ctx context.Context
cancelCtx func()
// owned by serverConn's serve loop:
bodyBytes int64 // body bytes seen so far
declBodyBytes int64 // or -1 if undeclared
flow outflow // limits writing from Handler to client
inflow inflow // what the client is allowed to POST/etc to us
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)
readDeadline *time.Timer // nil if unused
writeDeadline *time.Timer // nil if unused
closeErr error // set before cw is closed
trailer http.Header // accumulated trailers
reqTrailer http.Header // handler's Request.Trailer
}
func (sc *serverConn) Framer() *Framer { return sc.framer }
func (sc *serverConn) CloseConn() error { return sc.conn.Close() }
func (sc *serverConn) Flush() error { return sc.bw.Flush() }
func (sc *serverConn) HeaderEncoder() (*hpack.Encoder, *bytes.Buffer) {
return sc.hpackEncoder, &sc.headerWriteBuf
}
func (sc *serverConn) state(streamID uint32) (streamState, *stream) {
sc.serveG.check()
// http://tools.ietf.org/html/rfc7540#section-5.1
if st, ok := sc.streams[streamID]; ok {
return st.state, st
}
// "The first use of a new stream identifier implicitly closes all
// streams in the "idle" state that might have been initiated by
// that peer with a lower-valued stream identifier. For example, if
// a client sends a HEADERS frame on stream 7 without ever sending a
// frame on stream 5, then stream 5 transitions to the "closed"
// state when the first frame for stream 7 is sent or received."
if streamID%2 == 1 {
if streamID <= sc.maxClientStreamID {
return stateClosed, nil
}
} else {
if streamID <= sc.maxPushPromiseID {
return stateClosed, nil
}
}
return stateIdle, nil
}
// setConnState calls the net/http ConnState hook for this connection, if configured.
// Note that the net/http package does StateNew and StateClosed for us.
// There is currently no plan for StateHijacked or hijacking HTTP/2 connections.
func (sc *serverConn) setConnState(state http.ConnState) {
if sc.hs.ConnState != nil {
sc.hs.ConnState(sc.conn, state)
}
}
func (sc *serverConn) vlogf(format string, args ...interface{}) {
if VerboseLogs {
sc.logf(format, args...)
}
}
func (sc *serverConn) logf(format string, args ...interface{}) {
if lg := sc.hs.ErrorLog; lg != nil {
lg.Printf(format, args...)
} else {
log.Printf(format, args...)
}
}
// errno returns v's underlying uintptr, else 0.
//
// TODO: remove this helper function once http2 can use build
// tags. See comment in isClosedConnError.
func errno(v error) uintptr {
if rv := reflect.ValueOf(v); rv.Kind() == reflect.Uintptr {
return uintptr(rv.Uint())
}
return 0
}
// isClosedConnError reports whether err is an error from use of a closed
// network connection.
func isClosedConnError(err error) bool {
if err == nil {
return false
}
if errors.Is(err, net.ErrClosed) {
return true
}
// TODO(bradfitz): x/tools/cmd/bundle doesn't really support
// build tags, so I can't make an http2_windows.go file with
// Windows-specific stuff. Fix that and move this, once we
// have a way to bundle this into std's net/http somehow.
if runtime.GOOS == "windows" {
if oe, ok := err.(*net.OpError); ok && oe.Op == "read" {
if se, ok := oe.Err.(*os.SyscallError); ok && se.Syscall == "wsarecv" {
const WSAECONNABORTED = 10053
const WSAECONNRESET = 10054
if n := errno(se.Err); n == WSAECONNRESET || n == WSAECONNABORTED {
return true
}
}
}
}
return false
}
func (sc *serverConn) condlogf(err error, format string, args ...interface{}) {
if err == nil {
return
}
if err == io.EOF || err == io.ErrUnexpectedEOF || isClosedConnError(err) || err == errPrefaceTimeout {
// Boring, expected errors.
sc.vlogf(format, args...)
} else {
sc.logf(format, args...)
}
}
// maxCachedCanonicalHeadersKeysSize is an arbitrarily-chosen limit on the size
// of the entries in the canonHeader cache.
// This should be larger than the size of unique, uncommon header keys likely to
// be sent by the peer, while not so high as to permit unreasonable memory usage
// if the peer sends an unbounded number of unique header keys.
const maxCachedCanonicalHeadersKeysSize = 2048
func (sc *serverConn) canonicalHeader(v string) string {
sc.serveG.check()
cv, ok := httpcommon.CachedCanonicalHeader(v)
if ok {
return cv
}
cv, ok = sc.canonHeader[v]
if ok {
return cv
}
if sc.canonHeader == nil {
sc.canonHeader = make(map[string]string)
}
cv = http.CanonicalHeaderKey(v)
size := 100 + len(v)*2 // 100 bytes of map overhead + key + value
if sc.canonHeaderKeysSize+size <= maxCachedCanonicalHeadersKeysSize {
sc.canonHeader[v] = cv
sc.canonHeaderKeysSize += size
}
return cv
}
type readFrameResult struct {
f Frame // valid until readMore is called
err error
// readMore should be called once the consumer no longer needs or
// retains f. After readMore, f is invalid and more frames can be
// read.
readMore func()
}
// readFrames is the loop that reads incoming frames.
// It takes care to only read one frame at a time, blocking until the
// consumer is done with the frame.
// It's run on its own goroutine.
func (sc *serverConn) readFrames() {
gate := make(chan struct{})
gateDone := func() { gate <- struct{}{} }
for {
f, err := sc.framer.ReadFrame()
select {
case sc.readFrameCh <- readFrameResult{f, err, gateDone}:
case <-sc.doneServing:
return
}
select {
case <-gate:
case <-sc.doneServing:
return
}
if terminalReadFrameError(err) {
return
}
}
}
// frameWriteResult is the message passed from writeFrameAsync to the serve goroutine.
type frameWriteResult struct {
_ incomparable
wr FrameWriteRequest // what was written (or attempted)
err error // result of the writeFrame call
}
// writeFrameAsync runs in its own goroutine and writes a single frame
// and then reports when it's done.
// At most one goroutine can be running writeFrameAsync at a time per
// serverConn.
func (sc *serverConn) writeFrameAsync(wr FrameWriteRequest, wd *writeData) {
var err error
if wd == nil {
err = wr.write.writeFrame(sc)
} else {
err = sc.framer.endWrite()
}
sc.wroteFrameCh <- frameWriteResult{wr: wr, err: err}
}
func (sc *serverConn) closeAllStreamsOnConnClose() {
sc.serveG.check()
for _, st := range sc.streams {
sc.closeStream(st, errClientDisconnected)
}
}
func (sc *serverConn) stopShutdownTimer() {
sc.serveG.check()
if t := sc.shutdownTimer; t != nil {
t.Stop()
}
}
func (sc *serverConn) notePanic() {
// Note: this is for serverConn.serve panicking, not http.Handler code.
if testHookOnPanicMu != nil {
testHookOnPanicMu.Lock()
defer testHookOnPanicMu.Unlock()
}
if testHookOnPanic != nil {
if e := recover(); e != nil {
if testHookOnPanic(sc, e) {
panic(e)
}
}
}
}
func (sc *serverConn) serve(conf http2Config) {
sc.serveG.check()
defer sc.notePanic()
defer sc.conn.Close()
defer sc.closeAllStreamsOnConnClose()
defer sc.stopShutdownTimer()
defer close(sc.doneServing) // unblocks handlers trying to send
if VerboseLogs {
sc.vlogf("http2: server connection from %v on %p", sc.conn.RemoteAddr(), sc.hs)
}
settings := writeSettings{
{SettingMaxFrameSize, conf.MaxReadFrameSize},
{SettingMaxConcurrentStreams, sc.advMaxStreams},
{SettingMaxHeaderListSize, sc.maxHeaderListSize()},
{SettingHeaderTableSize, conf.MaxDecoderHeaderTableSize},
{SettingInitialWindowSize, uint32(sc.initialStreamRecvWindowSize)},
}
if !disableExtendedConnectProtocol {
settings = append(settings, Setting{SettingEnableConnectProtocol, 1})
}
sc.writeFrame(FrameWriteRequest{
write: settings,
})
sc.unackedSettings++
// Each connection starts with initialWindowSize inflow tokens.
// If a higher value is configured, we add more tokens.
if diff := conf.MaxUploadBufferPerConnection - 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.
// 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)
sc.setConnState(http.StateIdle)
if sc.srv.IdleTimeout > 0 {
sc.idleTimer = time.AfterFunc(sc.srv.IdleTimeout, sc.onIdleTimer)
defer sc.idleTimer.Stop()
}
if conf.SendPingTimeout > 0 {
sc.readIdleTimeout = conf.SendPingTimeout
sc.readIdleTimer = time.AfterFunc(conf.SendPingTimeout, sc.onReadIdleTimer)
defer sc.readIdleTimer.Stop()
}
go sc.readFrames() // closed by defer sc.conn.Close above
settingsTimer := time.AfterFunc(firstSettingsTimeout, sc.onSettingsTimer)
defer settingsTimer.Stop()
lastFrameTime := time.Now()
loopNum := 0
for {
loopNum++
select {
case wr := <-sc.wantWriteFrameCh:
if se, ok := wr.write.(StreamError); ok {
sc.resetStream(se)
break
}
sc.writeFrame(wr)
case res := <-sc.wroteFrameCh:
sc.wroteFrame(res)
case res := <-sc.readFrameCh:
lastFrameTime = time.Now()
// Process any written frames before reading new frames from the client since a
// written frame could have triggered a new stream to be started.
if sc.writingFrameAsync {
select {
case wroteRes := <-sc.wroteFrameCh:
sc.wroteFrame(wroteRes)
default:
}
}
if !sc.processFrameFromReader(res) {
return
}
res.readMore()
if settingsTimer != nil {
settingsTimer.Stop()
settingsTimer = nil
}
case m := <-sc.bodyReadCh:
sc.noteBodyRead(m.st, m.n)
case msg := <-sc.serveMsgCh:
switch v := msg.(type) {
case func(int):
v(loopNum) // for testing
case *serverMessage:
switch v {
case settingsTimerMsg:
sc.logf("timeout waiting for SETTINGS frames from %v", sc.conn.RemoteAddr())
return
case idleTimerMsg:
sc.vlogf("connection is idle")
sc.goAway(ErrCodeNo)
case readIdleTimerMsg:
sc.handlePingTimer(lastFrameTime)
case shutdownTimerMsg:
sc.vlogf("GOAWAY close timer fired; closing conn from %v", sc.conn.RemoteAddr())
return
case gracefulShutdownMsg:
sc.startGracefulShutdownInternal()
case handlerDoneMsg:
sc.handlerDone()
default:
panic("unknown timer")
}
case *startPushRequest:
sc.startPush(v)
case func(*serverConn):
v(sc)
default:
panic(fmt.Sprintf("unexpected type %T", v))
}
}
// If the peer is causing us to generate a lot of control frames,
// but not reading them from us, assume they are trying to make us
// run out of memory.
if sc.queuedControlFrames > maxQueuedControlFrames {
sc.vlogf("http2: too many control frames in send queue, closing connection")
return
}
// Start the shutdown timer after sending a GOAWAY. When sending GOAWAY
// with no error code (graceful shutdown), don't start the timer until
// all open streams have been completed.
sentGoAway := sc.inGoAway && !sc.needToSendGoAway && !sc.writingFrame
gracefulShutdownComplete := sc.goAwayCode == ErrCodeNo && sc.curOpenStreams() == 0
if sentGoAway && sc.shutdownTimer == nil && (sc.goAwayCode != ErrCodeNo || gracefulShutdownComplete) {
sc.shutDownIn(goAwayTimeout)
}
}
}
func (sc *serverConn) handlePingTimer(lastFrameReadTime time.Time) {
if sc.pingSent {
sc.logf("timeout waiting for PING response")
if f := sc.countErrorFunc; f != nil {
f("conn_close_lost_ping")
}
sc.conn.Close()
return
}
pingAt := lastFrameReadTime.Add(sc.readIdleTimeout)
now := time.Now()
if pingAt.After(now) {
// We received frames since arming the ping timer.
// Reset it for the next possible timeout.
sc.readIdleTimer.Reset(pingAt.Sub(now))
return
}
sc.pingSent = true
// Ignore crypto/rand.Read errors: It generally can't fail, and worse case if it does
// is we send a PING frame containing 0s.
_, _ = rand.Read(sc.sentPingData[:])
sc.writeFrame(FrameWriteRequest{
write: &writePing{data: sc.sentPingData},
})
sc.readIdleTimer.Reset(sc.pingTimeout)
}
type serverMessage int
// Message values sent to serveMsgCh.
var (
settingsTimerMsg = new(serverMessage)
idleTimerMsg = new(serverMessage)
readIdleTimerMsg = new(serverMessage)
shutdownTimerMsg = new(serverMessage)
gracefulShutdownMsg = new(serverMessage)
handlerDoneMsg = new(serverMessage)
)
func (sc *serverConn) onSettingsTimer() { sc.sendServeMsg(settingsTimerMsg) }
func (sc *serverConn) onIdleTimer() { sc.sendServeMsg(idleTimerMsg) }
func (sc *serverConn) onReadIdleTimer() { sc.sendServeMsg(readIdleTimerMsg) }
func (sc *serverConn) onShutdownTimer() { sc.sendServeMsg(shutdownTimerMsg) }
func (sc *serverConn) sendServeMsg(msg interface{}) {
sc.serveG.checkNotOn() // NOT
select {
case sc.serveMsgCh <- msg:
case <-sc.doneServing:
}
}
var errPrefaceTimeout = errors.New("timeout waiting for client preface")
// readPreface reads the ClientPreface greeting from the peer or
// returns errPrefaceTimeout on timeout, or an error if the greeting
// is invalid.
func (sc *serverConn) readPreface() error {
if sc.sawClientPreface {
return nil
}
errc := make(chan error, 1)
go func() {
// Read the client preface
buf := make([]byte, len(ClientPreface))
if _, err := io.ReadFull(sc.conn, buf); err != nil {
errc <- err
} else if !bytes.Equal(buf, clientPreface) {
errc <- fmt.Errorf("bogus greeting %q", buf)
} else {
errc <- nil
}
}()
timer := time.NewTimer(prefaceTimeout) // TODO: configurable on *Server?
defer timer.Stop()
select {
case <-timer.C:
return errPrefaceTimeout
case err := <-errc:
if err == nil {
if VerboseLogs {
sc.vlogf("http2: server: client %v said hello", sc.conn.RemoteAddr())
}
}
return err
}
}
var writeDataPool = sync.Pool{
New: func() interface{} { return new(writeData) },
}
// writeDataFromHandler writes DATA response frames from a handler on
// the given stream.
func (sc *serverConn) writeDataFromHandler(stream *stream, data []byte, endStream bool) error {
ch := sc.srv.state.getErrChan()
writeArg := writeDataPool.Get().(*writeData)
*writeArg = writeData{stream.id, data, endStream}
err := sc.writeFrameFromHandler(FrameWriteRequest{
write: writeArg,
stream: stream,
done: ch,
})
if err != nil {
return err
}
var frameWriteDone bool // the frame write is done (successfully or not)
select {
case err = <-ch:
frameWriteDone = true
case <-sc.doneServing:
return errClientDisconnected
case <-stream.cw:
// If both ch and stream.cw were ready (as might
// happen on the final Write after an http.Handler
// ends), prefer the write result. Otherwise this
// might just be us successfully closing the stream.
// The writeFrameAsync and serve goroutines guarantee
// that the ch send will happen before the stream.cw
// close.
select {
case err = <-ch:
frameWriteDone = true
default:
return errStreamClosed
}
}
sc.srv.state.putErrChan(ch)
if frameWriteDone {
writeDataPool.Put(writeArg)
}
return err
}
// writeFrameFromHandler sends wr to sc.wantWriteFrameCh, but aborts
// if the connection has gone away.
//
// This must not be run from the serve goroutine itself, else it might
// deadlock writing to sc.wantWriteFrameCh (which is only mildly
// buffered and is read by serve itself). If you're on the serve
// goroutine, call writeFrame instead.
func (sc *serverConn) writeFrameFromHandler(wr FrameWriteRequest) error {
sc.serveG.checkNotOn() // NOT
select {
case sc.wantWriteFrameCh <- wr:
return nil
case <-sc.doneServing:
// Serve loop is gone.
// Client has closed their connection to the server.
return errClientDisconnected
}
}
// writeFrame schedules a frame to write and sends it if there's nothing
// already being written.
//
// There is no pushback here (the serve goroutine never blocks). It's
// the http.Handlers that block, waiting for their previous frames to
// make it onto the wire
//
// If you're not on the serve goroutine, use writeFrameFromHandler instead.
func (sc *serverConn) writeFrame(wr FrameWriteRequest) {
sc.serveG.check()
// If true, wr will not be written and wr.done will not be signaled.
var ignoreWrite bool
// We are not allowed to write frames on closed streams. RFC 7540 Section
// 5.1.1 says: "An endpoint MUST NOT send frames other than PRIORITY on
// a closed stream." Our server never sends PRIORITY, so that exception
// does not apply.
//
// The serverConn might close an open stream while the stream's handler
// is still running. For example, the server might close a stream when it
// receives bad data from the client. If this happens, the handler might
// attempt to write a frame after the stream has been closed (since the
// handler hasn't yet been notified of the close). In this case, we simply
// ignore the frame. The handler will notice that the stream is closed when
// it waits for the frame to be written.
//
// As an exception to this rule, we allow sending RST_STREAM after close.
// This allows us to immediately reject new streams without tracking any
// state for those streams (except for the queued RST_STREAM frame). This
// may result in duplicate RST_STREAMs in some cases, but the client should
// ignore those.
if wr.StreamID() != 0 {
_, isReset := wr.write.(StreamError)
if state, _ := sc.state(wr.StreamID()); state == stateClosed && !isReset {
ignoreWrite = true
}
}
// Don't send a 100-continue response if we've already sent headers.
// See golang.org/issue/14030.
switch wr.write.(type) {
case *writeResHeaders:
wr.stream.wroteHeaders = true
case write100ContinueHeadersFrame:
if wr.stream.wroteHeaders {
// We do not need to notify wr.done because this frame is
// never written with wr.done != nil.
if wr.done != nil {
panic("wr.done != nil for write100ContinueHeadersFrame")
}
ignoreWrite = true
}
}
if !ignoreWrite {
if wr.isControl() {
sc.queuedControlFrames++
// For extra safety, detect wraparounds, which should not happen,
// and pull the plug.
if sc.queuedControlFrames < 0 {
sc.conn.Close()
}
}
sc.writeSched.Push(wr)
}
sc.scheduleFrameWrite()
}
// startFrameWrite starts a goroutine to write wr (in a separate
// goroutine since that might block on the network), and updates the
// serve goroutine's state about the world, updated from info in wr.
func (sc *serverConn) startFrameWrite(wr FrameWriteRequest) {
sc.serveG.check()
if sc.writingFrame {
panic("internal error: can only be writing one frame at a time")
}
st := wr.stream
if st != nil {
switch st.state {
case stateHalfClosedLocal:
switch wr.write.(type) {
case StreamError, handlerPanicRST, writeWindowUpdate:
// RFC 7540 Section 5.1 allows sending RST_STREAM, PRIORITY, and WINDOW_UPDATE
// in this state. (We never send PRIORITY from the server, so that is not checked.)
default:
panic(fmt.Sprintf("internal error: attempt to send frame on a half-closed-local stream: %v", wr))
}
case stateClosed:
panic(fmt.Sprintf("internal error: attempt to send frame on a closed stream: %v", wr))
}
}
if wpp, ok := wr.write.(*writePushPromise); ok {
var err error
wpp.promisedID, err = wpp.allocatePromisedID()
if err != nil {
sc.writingFrameAsync = false
wr.replyToWriter(err)
return
}
}
sc.writingFrame = true
sc.needsFrameFlush = true
if wr.write.staysWithinBuffer(sc.bw.Available()) {
sc.writingFrameAsync = false
err := wr.write.writeFrame(sc)
sc.wroteFrame(frameWriteResult{wr: wr, err: err})
} else if wd, ok := wr.write.(*writeData); ok {
// Encode the frame in the serve goroutine, to ensure we don't have
// any lingering asynchronous references to data passed to Write.
// See https://go.dev/issue/58446.
sc.framer.startWriteDataPadded(wd.streamID, wd.endStream, wd.p, nil)
sc.writingFrameAsync = true
go sc.writeFrameAsync(wr, wd)
} else {
sc.writingFrameAsync = true
go sc.writeFrameAsync(wr, nil)
}
}
// errHandlerPanicked is the error given to any callers blocked in a read from
// Request.Body when the main goroutine panics. Since most handlers read in the
// main ServeHTTP goroutine, this will show up rarely.
var errHandlerPanicked = errors.New("http2: handler panicked")
// wroteFrame is called on the serve goroutine with the result of
// whatever happened on writeFrameAsync.
func (sc *serverConn) wroteFrame(res frameWriteResult) {
sc.serveG.check()
if !sc.writingFrame {
panic("internal error: expected to be already writing a frame")
}
sc.writingFrame = false
sc.writingFrameAsync = false
if res.err != nil {
sc.conn.Close()
}
wr := res.wr
if writeEndsStream(wr.write) {
st := wr.stream
if st == nil {
panic("internal error: expecting non-nil stream")
}
switch st.state {
case stateOpen:
// Here we would go to stateHalfClosedLocal in
// theory, but since our handler is done and
// the net/http package provides no mechanism
// for closing a ResponseWriter while still
// reading data (see possible TODO at top of
// this file), we go into closed state here
// anyway, after telling the peer we're
// hanging up on them. We'll transition to
// stateClosed after the RST_STREAM frame is
// written.
st.state = stateHalfClosedLocal
// Section 8.1: a server MAY request that the client abort
// transmission of a request without error by sending a
// RST_STREAM with an error code of NO_ERROR after sending
// a complete response.
sc.resetStream(streamError(st.id, ErrCodeNo))
case stateHalfClosedRemote:
sc.closeStream(st, errHandlerComplete)
}
} else {
switch v := wr.write.(type) {
case StreamError:
// st may be unknown if the RST_STREAM was generated to reject bad input.
if st, ok := sc.streams[v.StreamID]; ok {
sc.closeStream(st, v)
}
case handlerPanicRST:
sc.closeStream(wr.stream, errHandlerPanicked)
}
}
// Reply (if requested) to unblock the ServeHTTP goroutine.
wr.replyToWriter(res.err)
sc.scheduleFrameWrite()
}
// scheduleFrameWrite tickles the frame writing scheduler.
//
// If a frame is already being written, nothing happens. This will be called again
// when the frame is done being written.
//
// If a frame isn't being written and we need to send one, the best frame
// to send is selected by writeSched.
//
// If a frame isn't being written and there's nothing else to send, we
// flush the write buffer.
func (sc *serverConn) scheduleFrameWrite() {
sc.serveG.check()
if sc.writingFrame || sc.inFrameScheduleLoop {
return
}
sc.inFrameScheduleLoop = true
for !sc.writingFrameAsync {
if sc.needToSendGoAway {
sc.needToSendGoAway = false
sc.startFrameWrite(FrameWriteRequest{
write: &writeGoAway{
maxStreamID: sc.maxClientStreamID,
code: sc.goAwayCode,
},
})
continue
}
if sc.needToSendSettingsAck {
sc.needToSendSettingsAck = false
sc.startFrameWrite(FrameWriteRequest{write: writeSettingsAck{}})
continue
}
if !sc.inGoAway || sc.goAwayCode == ErrCodeNo {
if wr, ok := sc.writeSched.Pop(); ok {
if wr.isControl() {
sc.queuedControlFrames--
}
sc.startFrameWrite(wr)
continue
}
}
if sc.needsFrameFlush {
sc.startFrameWrite(FrameWriteRequest{write: flushFrameWriter{}})
sc.needsFrameFlush = false // after startFrameWrite, since it sets this true
continue
}
break
}
sc.inFrameScheduleLoop = false
}
// startGracefulShutdown gracefully shuts down a connection. This
// sends GOAWAY with ErrCodeNo to tell the client we're gracefully
// shutting down. The connection isn't closed until all current
// streams are done.
//
// startGracefulShutdown returns immediately; it does not wait until
// the connection has shut down.
func (sc *serverConn) startGracefulShutdown() {
sc.serveG.checkNotOn() // NOT
sc.shutdownOnce.Do(func() { sc.sendServeMsg(gracefulShutdownMsg) })
}
// After sending GOAWAY with an error code (non-graceful shutdown), the
// connection will close after goAwayTimeout.
//
// If we close the connection immediately after sending GOAWAY, there may
// be unsent data in our kernel receive buffer, which will cause the kernel
// to send a TCP RST on close() instead of a FIN. This RST will abort the
// connection immediately, whether or not the client had received the GOAWAY.
//
// Ideally we should delay for at least 1 RTT + epsilon so the client has
// a chance to read the GOAWAY and stop sending messages. Measuring RTT
// is hard, so we approximate with 1 second. See golang.org/issue/18701.
//
// This is a var so it can be shorter in tests, where all requests uses the
// loopback interface making the expected RTT very small.
//
// TODO: configurable?
var goAwayTimeout = 1 * time.Second
func (sc *serverConn) startGracefulShutdownInternal() {
sc.goAway(ErrCodeNo)
}
func (sc *serverConn) goAway(code ErrCode) {
sc.serveG.check()
if sc.inGoAway {
if sc.goAwayCode == ErrCodeNo {
sc.goAwayCode = code
}
return
}
sc.inGoAway = true
sc.needToSendGoAway = true
sc.goAwayCode = code
sc.scheduleFrameWrite()
}
func (sc *serverConn) shutDownIn(d time.Duration) {
sc.serveG.check()
sc.shutdownTimer = time.AfterFunc(d, sc.onShutdownTimer)
}
func (sc *serverConn) resetStream(se StreamError) {
sc.serveG.check()
sc.writeFrame(FrameWriteRequest{write: se})
if st, ok := sc.streams[se.StreamID]; ok {
st.resetQueued = true
}
}
// processFrameFromReader processes the serve loop's read from readFrameCh from the
// frame-reading goroutine.
// processFrameFromReader returns whether the connection should be kept open.
func (sc *serverConn) processFrameFromReader(res readFrameResult) bool {
sc.serveG.check()
err := res.err
if err != nil {
if err == ErrFrameTooLarge {
sc.goAway(ErrCodeFrameSize)
return true // goAway will close the loop
}
clientGone := err == io.EOF || err == io.ErrUnexpectedEOF || isClosedConnError(err)
if clientGone {
// TODO: could we also get into this state if
// the peer does a half close
// (e.g. CloseWrite) because they're done
// sending frames but they're still wanting
// our open replies? Investigate.
// TODO: add CloseWrite to crypto/tls.Conn first
// so we have a way to test this? I suppose
// just for testing we could have a non-TLS mode.
return false
}
} else {
f := res.f
if VerboseLogs {
sc.vlogf("http2: server read frame %v", summarizeFrame(f))
}
err = sc.processFrame(f)
if err == nil {
return true
}
}
switch ev := err.(type) {
case StreamError:
sc.resetStream(ev)
return true
case goAwayFlowError:
sc.goAway(ErrCodeFlowControl)
return true
case ConnectionError:
if res.f != nil {
if id := res.f.Header().StreamID; id > sc.maxClientStreamID {
sc.maxClientStreamID = id
}
}
sc.logf("http2: server connection error from %v: %v", sc.conn.RemoteAddr(), ev)
sc.goAway(ErrCode(ev))
return true // goAway will handle shutdown
default:
if res.err != nil {
sc.vlogf("http2: server closing client connection; error reading frame from client %s: %v", sc.conn.RemoteAddr(), err)
} else {
sc.logf("http2: server closing client connection: %v", err)
}
return false
}
}
func (sc *serverConn) processFrame(f Frame) error {
sc.serveG.check()
// First frame received must be SETTINGS.
if !sc.sawFirstSettings {
if _, ok := f.(*SettingsFrame); !ok {
return sc.countError("first_settings", ConnectionError(ErrCodeProtocol))
}
sc.sawFirstSettings = true
}
// Discard frames for streams initiated after the identified last
// stream sent in a GOAWAY, or all frames after sending an error.
// We still need to return connection-level flow control for DATA frames.
// RFC 9113 Section 6.8.
if sc.inGoAway && (sc.goAwayCode != ErrCodeNo || f.Header().StreamID > sc.maxClientStreamID) {
if f, ok := f.(*DataFrame); ok {
if !sc.inflow.take(f.Length) {
return sc.countError("data_flow", streamError(f.Header().StreamID, ErrCodeFlowControl))
}
sc.sendWindowUpdate(nil, int(f.Length)) // conn-level
}
return nil
}
switch f := f.(type) {
case *SettingsFrame:
return sc.processSettings(f)
case *MetaHeadersFrame:
return sc.processHeaders(f)
case *WindowUpdateFrame:
return sc.processWindowUpdate(f)
case *PingFrame:
return sc.processPing(f)
case *DataFrame:
return sc.processData(f)
case *RSTStreamFrame:
return sc.processResetStream(f)
case *PriorityFrame:
return sc.processPriority(f)
case *GoAwayFrame:
return sc.processGoAway(f)
case *PushPromiseFrame:
// A client cannot push. Thus, servers MUST treat the receipt of a PUSH_PROMISE
// frame as a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
return sc.countError("push_promise", ConnectionError(ErrCodeProtocol))
default:
sc.vlogf("http2: server ignoring frame: %v", f.Header())
return nil
}
}
func (sc *serverConn) processPing(f *PingFrame) error {
sc.serveG.check()
if f.IsAck() {
if sc.pingSent && sc.sentPingData == f.Data {
// This is a response to a PING we sent.
sc.pingSent = false
sc.readIdleTimer.Reset(sc.readIdleTimeout)
}
// 6.7 PING: " An endpoint MUST NOT respond to PING frames
// containing this flag."
return nil
}
if f.StreamID != 0 {
// "PING frames are not associated with any individual
// stream. If a PING frame is received with a stream
// identifier field value other than 0x0, the recipient MUST
// respond with a connection error (Section 5.4.1) of type
// PROTOCOL_ERROR."
return sc.countError("ping_on_stream", ConnectionError(ErrCodeProtocol))
}
sc.writeFrame(FrameWriteRequest{write: writePingAck{f}})
return nil
}
func (sc *serverConn) processWindowUpdate(f *WindowUpdateFrame) error {
sc.serveG.check()
switch {
case f.StreamID != 0: // stream-level flow control
state, st := sc.state(f.StreamID)
if state == stateIdle {
// Section 5.1: "Receiving any frame other than HEADERS
// or PRIORITY on a stream in this state MUST be
// treated as a connection error (Section 5.4.1) of
// type PROTOCOL_ERROR."
return sc.countError("stream_idle", ConnectionError(ErrCodeProtocol))
}
if st == nil {
// "WINDOW_UPDATE can be sent by a peer that has sent a
// frame bearing the END_STREAM flag. This means that a
// receiver could receive a WINDOW_UPDATE frame on a "half
// closed (remote)" or "closed" stream. A receiver MUST
// NOT treat this as an error, see Section 5.1."
return nil
}
if !st.flow.add(int32(f.Increment)) {
return sc.countError("bad_flow", streamError(f.StreamID, ErrCodeFlowControl))
}
default: // connection-level flow control
if !sc.flow.add(int32(f.Increment)) {
return goAwayFlowError{}
}
}
sc.scheduleFrameWrite()
return nil
}
func (sc *serverConn) processResetStream(f *RSTStreamFrame) error {
sc.serveG.check()
state, st := sc.state(f.StreamID)
if state == stateIdle {
// 6.4 "RST_STREAM frames MUST NOT be sent for a
// stream in the "idle" state. If a RST_STREAM frame
// identifying an idle stream is received, the
// recipient MUST treat this as a connection error
// (Section 5.4.1) of type PROTOCOL_ERROR.
return sc.countError("reset_idle_stream", ConnectionError(ErrCodeProtocol))
}
if st != nil {
st.cancelCtx()
sc.closeStream(st, streamError(f.StreamID, f.ErrCode))
}
return nil
}
func (sc *serverConn) closeStream(st *stream, err error) {
sc.serveG.check()
if st.state == stateIdle || st.state == stateClosed {
panic(fmt.Sprintf("invariant; can't close stream in state %v", st.state))
}
st.state = stateClosed
if st.readDeadline != nil {
st.readDeadline.Stop()
}
if st.writeDeadline != nil {
st.writeDeadline.Stop()
}
if st.isPushed() {
sc.curPushedStreams--
} else {
sc.curClientStreams--
}
delete(sc.streams, st.id)
if len(sc.streams) == 0 {
sc.setConnState(http.StateIdle)
if sc.srv.IdleTimeout > 0 && sc.idleTimer != nil {
sc.idleTimer.Reset(sc.srv.IdleTimeout)
}
if h1ServerKeepAlivesDisabled(sc.hs) {
sc.startGracefulShutdownInternal()
}
}
if p := st.body; p != nil {
// Return any buffered unread bytes worth of conn-level flow control.
// See golang.org/issue/16481
sc.sendWindowUpdate(nil, p.Len())
p.CloseWithError(err)
}
if e, ok := err.(StreamError); ok {
if e.Cause != nil {
err = e.Cause
} else {
err = errStreamClosed
}
}
st.closeErr = err
st.cancelCtx()
st.cw.Close() // signals Handler's CloseNotifier, unblocks writes, etc
sc.writeSched.CloseStream(st.id)
}
func (sc *serverConn) processSettings(f *SettingsFrame) error {
sc.serveG.check()
if f.IsAck() {
sc.unackedSettings--
if sc.unackedSettings < 0 {
// Why is the peer ACKing settings we never sent?
// The spec doesn't mention this case, but
// hang up on them anyway.
return sc.countError("ack_mystery", ConnectionError(ErrCodeProtocol))
}
return nil
}
if f.NumSettings() > 100 || f.HasDuplicates() {
// This isn't actually in the spec, but hang up on
// suspiciously large settings frames or those with
// duplicate entries.
return sc.countError("settings_big_or_dups", ConnectionError(ErrCodeProtocol))
}
if err := f.ForeachSetting(sc.processSetting); err != nil {
return err
}
// TODO: judging by RFC 7540, Section 6.5.3 each SETTINGS frame should be
// acknowledged individually, even if multiple are received before the ACK.
sc.needToSendSettingsAck = true
sc.scheduleFrameWrite()
return nil
}
func (sc *serverConn) processSetting(s Setting) error {
sc.serveG.check()
if err := s.Valid(); err != nil {
return err
}
if VerboseLogs {
sc.vlogf("http2: server processing setting %v", s)
}
switch s.ID {
case SettingHeaderTableSize:
sc.hpackEncoder.SetMaxDynamicTableSize(s.Val)
case SettingEnablePush:
sc.pushEnabled = s.Val != 0
case SettingMaxConcurrentStreams:
sc.clientMaxStreams = s.Val
case SettingInitialWindowSize:
return sc.processSettingInitialWindowSize(s.Val)
case SettingMaxFrameSize:
sc.maxFrameSize = int32(s.Val) // the maximum valid s.Val is < 2^31
case SettingMaxHeaderListSize:
sc.peerMaxHeaderListSize = s.Val
case SettingEnableConnectProtocol:
// Receipt of this parameter by a server does not
// have any impact
default:
// Unknown setting: "An endpoint that receives a SETTINGS
// frame with any unknown or unsupported identifier MUST
// ignore that setting."
if VerboseLogs {
sc.vlogf("http2: server ignoring unknown setting %v", s)
}
}
return nil
}
func (sc *serverConn) processSettingInitialWindowSize(val uint32) error {
sc.serveG.check()
// Note: val already validated to be within range by
// processSetting's Valid call.
// "A SETTINGS frame can alter the initial flow control window
// size for all current streams. When the value of
// SETTINGS_INITIAL_WINDOW_SIZE changes, a receiver MUST
// 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.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
// "An endpoint MUST treat a change to
// SETTINGS_INITIAL_WINDOW_SIZE that causes any flow
// control window to exceed the maximum size as a
// connection error (Section 5.4.1) of type
// FLOW_CONTROL_ERROR."
return sc.countError("setting_win_size", ConnectionError(ErrCodeFlowControl))
}
}
return nil
}
func (sc *serverConn) processData(f *DataFrame) error {
sc.serveG.check()
id := f.Header().StreamID
data := f.Data()
state, st := sc.state(id)
if id == 0 || state == stateIdle {
// Section 6.1: "DATA frames MUST be associated with a
// stream. If a DATA 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."
//
// Section 5.1: "Receiving any frame other than HEADERS
// or PRIORITY on a stream in this state MUST be
// treated as a connection error (Section 5.4.1) of
// type PROTOCOL_ERROR."
return sc.countError("data_on_idle", ConnectionError(ErrCodeProtocol))
}
// "If a DATA frame is received whose stream is not in "open"
// or "half closed (local)" state, the recipient MUST respond
// with a stream error (Section 5.4.2) of type STREAM_CLOSED."
if st == nil || state != stateOpen || st.gotTrailerHeader || st.resetQueued {
// This includes sending a RST_STREAM if the stream is
// in stateHalfClosedLocal (which currently means that
// the http.Handler returned, so it's done reading &
// done writing). Try to stop the client from sending
// more DATA.
// But still enforce their connection-level flow control,
// and return any flow control bytes since we're not going
// to consume them.
if !sc.inflow.take(f.Length) {
return sc.countError("data_flow", streamError(id, ErrCodeFlowControl))
}
sc.sendWindowUpdate(nil, int(f.Length)) // conn-level
if st != nil && st.resetQueued {
// Already have a stream error in flight. Don't send another.
return nil
}
return sc.countError("closed", streamError(id, ErrCodeStreamClosed))
}
if st.body == nil {
panic("internal error: should have a body in this state")
}
// Sender sending more than they'd declared?
if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes {
if !sc.inflow.take(f.Length) {
return sc.countError("data_flow", streamError(id, ErrCodeFlowControl))
}
sc.sendWindowUpdate(nil, int(f.Length)) // conn-level
st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))
// RFC 7540, sec 8.1.2.6: A request or response is also malformed if the
// value of a content-length header field does not equal the sum of the
// DATA frame payload lengths that form the body.
return sc.countError("send_too_much", streamError(id, ErrCodeProtocol))
}
if f.Length > 0 {
// Check whether the client has flow control quota.
if !takeInflows(&sc.inflow, &st.inflow, f.Length) {
return sc.countError("flow_on_data_length", streamError(id, ErrCodeFlowControl))
}
if len(data) > 0 {
st.bodyBytes += int64(len(data))
wrote, err := st.body.Write(data)
if err != nil {
// The handler has closed the request body.
// Return the connection-level flow control for the discarded data,
// but not the stream-level flow control.
sc.sendWindowUpdate(nil, int(f.Length)-wrote)
return nil
}
if wrote != len(data) {
panic("internal error: bad Writer")
}
}
// Return any padded flow control now, since we won't
// refund it later on body reads.
// Call sendWindowUpdate even if there is no padding,
// to return buffered flow control credit if the sent
// window has shrunk.
pad := int32(f.Length) - int32(len(data))
sc.sendWindowUpdate32(nil, pad)
sc.sendWindowUpdate32(st, pad)
}
if f.StreamEnded() {
st.endStream()
}
return nil
}
func (sc *serverConn) processGoAway(f *GoAwayFrame) error {
sc.serveG.check()
if f.ErrCode != ErrCodeNo {
sc.logf("http2: received GOAWAY %+v, starting graceful shutdown", f)
} else {
sc.vlogf("http2: received GOAWAY %+v, starting graceful shutdown", f)
}
sc.startGracefulShutdownInternal()
// http://tools.ietf.org/html/rfc7540#section-6.8
// We should not create any new streams, which means we should disable push.
sc.pushEnabled = false
return nil
}
// isPushed reports whether the stream is server-initiated.
func (st *stream) isPushed() bool {
return st.id%2 == 0
}
// endStream closes a Request.Body's pipe. It is called when a DATA
// frame says a request body is over (or after trailers).
func (st *stream) endStream() {
sc := st.sc
sc.serveG.check()
if st.declBodyBytes != -1 && st.declBodyBytes != st.bodyBytes {
st.body.CloseWithError(fmt.Errorf("request declared a Content-Length of %d but only wrote %d bytes",
st.declBodyBytes, st.bodyBytes))
} else {
st.body.closeWithErrorAndCode(io.EOF, st.copyTrailersToHandlerRequest)
st.body.CloseWithError(io.EOF)
}
st.state = stateHalfClosedRemote
}
// copyTrailersToHandlerRequest is run in the Handler's goroutine in
// its Request.Body.Read just before it gets io.EOF.
func (st *stream) copyTrailersToHandlerRequest() {
for k, vv := range st.trailer {
if _, ok := st.reqTrailer[k]; ok {
// Only copy it over it was pre-declared.
st.reqTrailer[k] = vv
}
}
}
// onReadTimeout is run on its own goroutine (from time.AfterFunc)
// when the stream's ReadTimeout has fired.
func (st *stream) onReadTimeout() {
if st.body != nil {
// Wrap the ErrDeadlineExceeded to avoid callers depending on us
// returning the bare error.
st.body.CloseWithError(fmt.Errorf("%w", os.ErrDeadlineExceeded))
}
}
// onWriteTimeout is run on its own goroutine (from time.AfterFunc)
// when the stream's WriteTimeout has fired.
func (st *stream) onWriteTimeout() {
st.sc.writeFrameFromHandler(FrameWriteRequest{write: StreamError{
StreamID: st.id,
Code: ErrCodeInternal,
Cause: os.ErrDeadlineExceeded,
}})
}
func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error {
sc.serveG.check()
id := f.StreamID
// http://tools.ietf.org/html/rfc7540#section-5.1.1
// Streams initiated by a client MUST use odd-numbered stream
// identifiers. [...] An endpoint that receives an unexpected
// stream identifier MUST respond with a connection error
// (Section 5.4.1) of type PROTOCOL_ERROR.
if id%2 != 1 {
return sc.countError("headers_even", ConnectionError(ErrCodeProtocol))
}
// A HEADERS frame can be used to create a new stream or
// send a trailer for an open one. If we already have a stream
// open, let it process its own HEADERS frame (trailers at this
// point, if it's valid).
if st := sc.streams[f.StreamID]; st != nil {
if st.resetQueued {
// We're sending RST_STREAM to close the stream, so don't bother
// processing this frame.
return nil
}
// RFC 7540, sec 5.1: If an endpoint receives additional frames, other than
// WINDOW_UPDATE, PRIORITY, or RST_STREAM, for a stream that is in
// this state, it MUST respond with a stream error (Section 5.4.2) of
// type STREAM_CLOSED.
if st.state == stateHalfClosedRemote {
return sc.countError("headers_half_closed", streamError(id, ErrCodeStreamClosed))
}
return st.processTrailerHeaders(f)
}
// [...] The identifier of a newly established stream MUST be
// numerically greater than all streams that the initiating
// endpoint has opened or reserved. [...] An endpoint that
// receives an unexpected stream identifier MUST respond with
// a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
if id <= sc.maxClientStreamID {
return sc.countError("stream_went_down", ConnectionError(ErrCodeProtocol))
}
sc.maxClientStreamID = id
if sc.idleTimer != nil {
sc.idleTimer.Stop()
}
// http://tools.ietf.org/html/rfc7540#section-5.1.2
// [...] Endpoints MUST NOT exceed the limit set by their peer. An
// endpoint that receives a HEADERS frame that causes their
// advertised concurrent stream limit to be exceeded MUST treat
// this as a stream error (Section 5.4.2) of type PROTOCOL_ERROR
// or REFUSED_STREAM.
if sc.curClientStreams+1 > sc.advMaxStreams {
if sc.unackedSettings == 0 {
// They should know better.
return sc.countError("over_max_streams", streamError(id, ErrCodeProtocol))
}
// Assume it's a network race, where they just haven't
// received our last SETTINGS update. But actually
// this can't happen yet, because we don't yet provide
// a way for users to adjust server parameters at
// runtime.
return sc.countError("over_max_streams_race", streamError(id, ErrCodeRefusedStream))
}
initialState := stateOpen
if f.StreamEnded() {
initialState = stateHalfClosedRemote
}
st := sc.newStream(id, 0, initialState)
if f.HasPriority() {
if err := sc.checkPriority(f.StreamID, f.Priority); err != nil {
return err
}
sc.writeSched.AdjustStream(st.id, f.Priority)
}
rw, req, err := sc.newWriterAndRequest(st, f)
if err != nil {
return err
}
st.reqTrailer = req.Trailer
if st.reqTrailer != nil {
st.trailer = make(http.Header)
}
st.body = req.Body.(*requestBody).pipe // may be nil
st.declBodyBytes = req.ContentLength
handler := sc.handler.ServeHTTP
if f.Truncated {
// Their header list was too long. Send a 431 error.
handler = handleHeaderListTooLong
} else if err := checkValidHTTP2RequestHeaders(req.Header); err != nil {
handler = new400Handler(err)
}
// The net/http package sets the read deadline from the
// http.Server.ReadTimeout during the TLS handshake, but then
// passes the connection off to us with the deadline already
// set. Disarm it here after the request headers are read,
// similar to how the http1 server works. Here it's
// technically more like the http1 Server's ReadHeaderTimeout
// (in Go 1.8), though. That's a more sane option anyway.
if sc.hs.ReadTimeout > 0 {
sc.conn.SetReadDeadline(time.Time{})
st.readDeadline = time.AfterFunc(sc.hs.ReadTimeout, st.onReadTimeout)
}
return sc.scheduleHandler(id, rw, req, handler)
}
func (sc *serverConn) upgradeRequest(req *http.Request) {
sc.serveG.check()
id := uint32(1)
sc.maxClientStreamID = id
st := sc.newStream(id, 0, stateHalfClosedRemote)
st.reqTrailer = req.Trailer
if st.reqTrailer != nil {
st.trailer = make(http.Header)
}
rw := sc.newResponseWriter(st, req)
// Disable any read deadline set by the net/http package
// prior to the upgrade.
if sc.hs.ReadTimeout > 0 {
sc.conn.SetReadDeadline(time.Time{})
}
// This is the first request on the connection,
// so start the handler directly rather than going
// through scheduleHandler.
sc.curHandlers++
go sc.runHandler(rw, req, sc.handler.ServeHTTP)
}
func (st *stream) processTrailerHeaders(f *MetaHeadersFrame) error {
sc := st.sc
sc.serveG.check()
if st.gotTrailerHeader {
return sc.countError("dup_trailers", ConnectionError(ErrCodeProtocol))
}
st.gotTrailerHeader = true
if !f.StreamEnded() {
return sc.countError("trailers_not_ended", streamError(st.id, ErrCodeProtocol))
}
if len(f.PseudoFields()) > 0 {
return sc.countError("trailers_pseudo", streamError(st.id, ErrCodeProtocol))
}
if st.trailer != nil {
for _, hf := range f.RegularFields() {
key := sc.canonicalHeader(hf.Name)
if !httpguts.ValidTrailerHeader(key) {
// TODO: send more details to the peer somehow. But http2 has
// no way to send debug data at a stream level. Discuss with
// HTTP folk.
return sc.countError("trailers_bogus", streamError(st.id, ErrCodeProtocol))
}
st.trailer[key] = append(st.trailer[key], hf.Value)
}
}
st.endStream()
return nil
}
func (sc *serverConn) checkPriority(streamID uint32, p PriorityParam) error {
if streamID == p.StreamDep {
// Section 5.3.1: "A stream cannot depend on itself. An endpoint MUST treat
// this as a stream error (Section 5.4.2) of type PROTOCOL_ERROR."
// Section 5.3.3 says that a stream can depend on one of its dependencies,
// so it's only self-dependencies that are forbidden.
return sc.countError("priority", streamError(streamID, ErrCodeProtocol))
}
return nil
}
func (sc *serverConn) processPriority(f *PriorityFrame) error {
if err := sc.checkPriority(f.StreamID, f.PriorityParam); err != nil {
return err
}
sc.writeSched.AdjustStream(f.StreamID, f.PriorityParam)
return nil
}
func (sc *serverConn) newStream(id, pusherID uint32, state streamState) *stream {
sc.serveG.check()
if id == 0 {
panic("internal error: cannot create stream with id 0")
}
ctx, cancelCtx := context.WithCancel(sc.baseCtx)
st := &stream{
sc: sc,
id: id,
state: state,
ctx: ctx,
cancelCtx: cancelCtx,
}
st.cw.Init()
st.flow.conn = &sc.flow // link to conn-level counter
st.flow.add(sc.initialStreamSendWindowSize)
st.inflow.init(sc.initialStreamRecvWindowSize)
if sc.hs.WriteTimeout > 0 {
st.writeDeadline = time.AfterFunc(sc.hs.WriteTimeout, st.onWriteTimeout)
}
sc.streams[id] = st
sc.writeSched.OpenStream(st.id, OpenStreamOptions{PusherID: pusherID})
if st.isPushed() {
sc.curPushedStreams++
} else {
sc.curClientStreams++
}
if sc.curOpenStreams() == 1 {
sc.setConnState(http.StateActive)
}
return st
}
func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*responseWriter, *http.Request, error) {
sc.serveG.check()
rp := httpcommon.ServerRequestParam{
Method: f.PseudoValue("method"),
Scheme: f.PseudoValue("scheme"),
Authority: f.PseudoValue("authority"),
Path: f.PseudoValue("path"),
Protocol: f.PseudoValue("protocol"),
}
// extended connect is disabled, so we should not see :protocol
if disableExtendedConnectProtocol && rp.Protocol != "" {
return nil, nil, sc.countError("bad_connect", streamError(f.StreamID, ErrCodeProtocol))
}
isConnect := rp.Method == "CONNECT"
if isConnect {
if rp.Protocol == "" && (rp.Path != "" || rp.Scheme != "" || rp.Authority == "") {
return nil, nil, sc.countError("bad_connect", streamError(f.StreamID, ErrCodeProtocol))
}
} else if rp.Method == "" || rp.Path == "" || (rp.Scheme != "https" && rp.Scheme != "http") {
// See 8.1.2.6 Malformed Requests and Responses:
//
// Malformed requests or responses that are detected
// MUST be treated as a stream error (Section 5.4.2)
// of type PROTOCOL_ERROR."
//
// 8.1.2.3 Request Pseudo-Header Fields
// "All HTTP/2 requests MUST include exactly one valid
// value for the :method, :scheme, and :path
// pseudo-header fields"
return nil, nil, sc.countError("bad_path_method", streamError(f.StreamID, ErrCodeProtocol))
}
header := make(http.Header)
rp.Header = header
for _, hf := range f.RegularFields() {
header.Add(sc.canonicalHeader(hf.Name), hf.Value)
}
if rp.Authority == "" {
rp.Authority = header.Get("Host")
}
if rp.Protocol != "" {
header.Set(":protocol", rp.Protocol)
}
rw, req, err := sc.newWriterAndRequestNoBody(st, rp)
if err != nil {
return nil, nil, err
}
bodyOpen := !f.StreamEnded()
if bodyOpen {
if vv, ok := rp.Header["Content-Length"]; ok {
if cl, err := strconv.ParseUint(vv[0], 10, 63); err == nil {
req.ContentLength = int64(cl)
} else {
req.ContentLength = 0
}
} else {
req.ContentLength = -1
}
req.Body.(*requestBody).pipe = &pipe{
b: &dataBuffer{expected: req.ContentLength},
}
}
return rw, req, nil
}
func (sc *serverConn) newWriterAndRequestNoBody(st *stream, rp httpcommon.ServerRequestParam) (*responseWriter, *http.Request, error) {
sc.serveG.check()
var tlsState *tls.ConnectionState // nil if not scheme https
if rp.Scheme == "https" {
tlsState = sc.tlsState
}
res := httpcommon.NewServerRequest(rp)
if res.InvalidReason != "" {
return nil, nil, sc.countError(res.InvalidReason, streamError(st.id, ErrCodeProtocol))
}
body := &requestBody{
conn: sc,
stream: st,
needsContinue: res.NeedsContinue,
}
req := (&http.Request{
Method: rp.Method,
URL: res.URL,
RemoteAddr: sc.remoteAddrStr,
Header: rp.Header,
RequestURI: res.RequestURI,
Proto: "HTTP/2.0",
ProtoMajor: 2,
ProtoMinor: 0,
TLS: tlsState,
Host: rp.Authority,
Body: body,
Trailer: res.Trailer,
}).WithContext(st.ctx)
rw := sc.newResponseWriter(st, req)
return rw, req, nil
}
func (sc *serverConn) newResponseWriter(st *stream, req *http.Request) *responseWriter {
rws := responseWriterStatePool.Get().(*responseWriterState)
bwSave := rws.bw
*rws = responseWriterState{} // zero all the fields
rws.conn = sc
rws.bw = bwSave
rws.bw.Reset(chunkWriter{rws})
rws.stream = st
rws.req = req
return &responseWriter{rws: rws}
}
type unstartedHandler struct {
streamID uint32
rw *responseWriter
req *http.Request
handler func(http.ResponseWriter, *http.Request)
}
// scheduleHandler starts a handler goroutine,
// or schedules one to start as soon as an existing handler finishes.
func (sc *serverConn) scheduleHandler(streamID uint32, rw *responseWriter, req *http.Request, handler func(http.ResponseWriter, *http.Request)) error {
sc.serveG.check()
maxHandlers := sc.advMaxStreams
if sc.curHandlers < maxHandlers {
sc.curHandlers++
go sc.runHandler(rw, req, handler)
return nil
}
if len(sc.unstartedHandlers) > int(4*sc.advMaxStreams) {
return sc.countError("too_many_early_resets", ConnectionError(ErrCodeEnhanceYourCalm))
}
sc.unstartedHandlers = append(sc.unstartedHandlers, unstartedHandler{
streamID: streamID,
rw: rw,
req: req,
handler: handler,
})
return nil
}
func (sc *serverConn) handlerDone() {
sc.serveG.check()
sc.curHandlers--
i := 0
maxHandlers := sc.advMaxStreams
for ; i < len(sc.unstartedHandlers); i++ {
u := sc.unstartedHandlers[i]
if sc.streams[u.streamID] == nil {
// This stream was reset before its goroutine had a chance to start.
continue
}
if sc.curHandlers >= maxHandlers {
break
}
sc.curHandlers++
go sc.runHandler(u.rw, u.req, u.handler)
sc.unstartedHandlers[i] = unstartedHandler{} // don't retain references
}
sc.unstartedHandlers = sc.unstartedHandlers[i:]
if len(sc.unstartedHandlers) == 0 {
sc.unstartedHandlers = nil
}
}
// Run on its own goroutine.
func (sc *serverConn) runHandler(rw *responseWriter, req *http.Request, handler func(http.ResponseWriter, *http.Request)) {
defer sc.sendServeMsg(handlerDoneMsg)
didPanic := true
defer func() {
rw.rws.stream.cancelCtx()
if req.MultipartForm != nil {
req.MultipartForm.RemoveAll()
}
if didPanic {
e := recover()
sc.writeFrameFromHandler(FrameWriteRequest{
write: handlerPanicRST{rw.rws.stream.id},
stream: rw.rws.stream,
})
// Same as net/http:
if e != nil && e != http.ErrAbortHandler {
const size = 64 << 10
buf := make([]byte, size)
buf = buf[:runtime.Stack(buf, false)]
sc.logf("http2: panic serving %v: %v\n%s", sc.conn.RemoteAddr(), e, buf)
}
return
}
rw.handlerDone()
}()
handler(rw, req)
didPanic = false
}
func handleHeaderListTooLong(w http.ResponseWriter, r *http.Request) {
// 10.5.1 Limits on Header Block Size:
// .. "A server that receives a larger header block than it is
// willing to handle can send an HTTP 431 (Request Header Fields Too
// Large) status code"
const statusRequestHeaderFieldsTooLarge = 431 // only in Go 1.6+
w.WriteHeader(statusRequestHeaderFieldsTooLarge)
io.WriteString(w, "<h1>HTTP Error 431</h1><p>Request Header Field(s) Too Large</p>")
}
// called from handler goroutines.
// h may be nil.
func (sc *serverConn) writeHeaders(st *stream, headerData *writeResHeaders) error {
sc.serveG.checkNotOn() // NOT on
var errc chan error
if headerData.h != nil {
// If there's a header map (which we don't own), so we have to block on
// waiting for this frame to be written, so an http.Flush mid-handler
// writes out the correct value of keys, before a handler later potentially
// mutates it.
errc = sc.srv.state.getErrChan()
}
if err := sc.writeFrameFromHandler(FrameWriteRequest{
write: headerData,
stream: st,
done: errc,
}); err != nil {
return err
}
if errc != nil {
select {
case err := <-errc:
sc.srv.state.putErrChan(errc)
return err
case <-sc.doneServing:
return errClientDisconnected
case <-st.cw:
return errStreamClosed
}
}
return nil
}
// called from handler goroutines.
func (sc *serverConn) write100ContinueHeaders(st *stream) {
sc.writeFrameFromHandler(FrameWriteRequest{
write: write100ContinueHeadersFrame{st.id},
stream: st,
})
}
// A bodyReadMsg tells the server loop that the http.Handler read n
// bytes of the DATA from the client on the given stream.
type bodyReadMsg struct {
st *stream
n int
}
// called from handler goroutines.
// Notes that the handler for the given stream ID read n bytes of its body
// and schedules flow control tokens to be sent.
func (sc *serverConn) noteBodyReadFromHandler(st *stream, n int, err error) {
sc.serveG.checkNotOn() // NOT on
if n > 0 {
select {
case sc.bodyReadCh <- bodyReadMsg{st, n}:
case <-sc.doneServing:
}
}
}
func (sc *serverConn) noteBodyRead(st *stream, n int) {
sc.serveG.check()
sc.sendWindowUpdate(nil, n) // conn-level
if st.state != stateHalfClosedRemote && st.state != stateClosed {
// Don't send this WINDOW_UPDATE if the stream is closed
// remotely.
sc.sendWindowUpdate(st, n)
}
}
// st may be nil for conn-level
func (sc *serverConn) sendWindowUpdate32(st *stream, n int32) {
sc.sendWindowUpdate(st, int(n))
}
// st may be nil for conn-level
func (sc *serverConn) sendWindowUpdate(st *stream, n int) {
sc.serveG.check()
var streamID uint32
var send int32
if st == nil {
send = sc.inflow.add(n)
} else {
streamID = st.id
send = st.inflow.add(n)
}
if send == 0 {
return
}
sc.writeFrame(FrameWriteRequest{
write: writeWindowUpdate{streamID: streamID, n: uint32(send)},
stream: st,
})
}
// requestBody is the Handler's Request.Body type.
// Read and Close may be called concurrently.
type requestBody struct {
_ incomparable
stream *stream
conn *serverConn
closeOnce sync.Once // for use by Close only
sawEOF bool // for use by Read only
pipe *pipe // non-nil if we have an HTTP entity message body
needsContinue bool // need to send a 100-continue
}
func (b *requestBody) Close() error {
b.closeOnce.Do(func() {
if b.pipe != nil {
b.pipe.BreakWithError(errClosedBody)
}
})
return nil
}
func (b *requestBody) Read(p []byte) (n int, err error) {
if b.needsContinue {
b.needsContinue = false
b.conn.write100ContinueHeaders(b.stream)
}
if b.pipe == nil || b.sawEOF {
return 0, io.EOF
}
n, err = b.pipe.Read(p)
if err == io.EOF {
b.sawEOF = true
}
if b.conn == nil {
return
}
b.conn.noteBodyReadFromHandler(b.stream, n, err)
return
}
// 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
// and buffers are reused between multiple requests.
type responseWriter struct {
rws *responseWriterState
}
// Optional http.ResponseWriter interfaces implemented.
var (
_ http.CloseNotifier = (*responseWriter)(nil)
_ http.Flusher = (*responseWriter)(nil)
_ stringWriter = (*responseWriter)(nil)
)
type responseWriterState struct {
// immutable within a request:
stream *stream
req *http.Request
conn *serverConn
// TODO: adjust buffer writing sizes based on server config, frame size updates from peer, etc
bw *bufio.Writer // writing to a chunkWriter{this *responseWriterState}
// mutated by http.Handler goroutine:
handlerHeader http.Header // nil until called
snapHeader http.Header // snapshot of handlerHeader at WriteHeader time
trailers []string // set in writeChunk
status int // status code passed to WriteHeader
wroteHeader bool // WriteHeader called (explicitly or implicitly). Not necessarily sent to user yet.
sentHeader bool // have we sent the header frame?
handlerDone bool // handler has finished
sentContentLen int64 // non-zero if handler set a Content-Length header
wroteBytes int64
closeNotifierMu sync.Mutex // guards closeNotifierCh
closeNotifierCh chan bool // nil until first used
}
type chunkWriter struct{ rws *responseWriterState }
func (cw chunkWriter) Write(p []byte) (n int, err error) {
n, err = cw.rws.writeChunk(p)
if err == errStreamClosed {
// If writing failed because the stream has been closed,
// return the reason it was closed.
err = cw.rws.stream.closeErr
}
return n, err
}
func (rws *responseWriterState) hasTrailers() bool { return len(rws.trailers) > 0 }
func (rws *responseWriterState) hasNonemptyTrailers() bool {
for _, trailer := range rws.trailers {
if _, ok := rws.handlerHeader[trailer]; ok {
return true
}
}
return false
}
// declareTrailer is called for each Trailer header when the
// response header is written. It notes that a header will need to be
// written in the trailers at the end of the response.
func (rws *responseWriterState) declareTrailer(k string) {
k = http.CanonicalHeaderKey(k)
if !httpguts.ValidTrailerHeader(k) {
// Forbidden by RFC 7230, section 4.1.2.
rws.conn.logf("ignoring invalid trailer %q", k)
return
}
if !strSliceContains(rws.trailers, k) {
rws.trailers = append(rws.trailers, k)
}
}
// writeChunk writes chunks from the bufio.Writer. But because
// bufio.Writer may bypass its chunking, sometimes p may be
// arbitrarily large.
//
// writeChunk is also responsible (on the first chunk) for sending the
// HEADER response.
func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
if !rws.wroteHeader {
rws.writeHeader(200)
}
if rws.handlerDone {
rws.promoteUndeclaredTrailers()
}
isHeadResp := rws.req.Method == "HEAD"
if !rws.sentHeader {
rws.sentHeader = true
var ctype, clen string
if clen = rws.snapHeader.Get("Content-Length"); clen != "" {
rws.snapHeader.Del("Content-Length")
if cl, err := strconv.ParseUint(clen, 10, 63); err == nil {
rws.sentContentLen = int64(cl)
} else {
clen = ""
}
}
_, hasContentLength := rws.snapHeader["Content-Length"]
if !hasContentLength && clen == "" && rws.handlerDone && bodyAllowedForStatus(rws.status) && (len(p) > 0 || !isHeadResp) {
clen = strconv.Itoa(len(p))
}
_, hasContentType := rws.snapHeader["Content-Type"]
// If the Content-Encoding is non-blank, we shouldn't
// sniff the body. See Issue golang.org/issue/31753.
ce := rws.snapHeader.Get("Content-Encoding")
hasCE := len(ce) > 0
if !hasCE && !hasContentType && bodyAllowedForStatus(rws.status) && len(p) > 0 {
ctype = http.DetectContentType(p)
}
var date string
if _, ok := rws.snapHeader["Date"]; !ok {
// TODO(bradfitz): be faster here, like net/http? measure.
date = time.Now().UTC().Format(http.TimeFormat)
}
for _, v := range rws.snapHeader["Trailer"] {
foreachHeaderElement(v, rws.declareTrailer)
}
// "Connection" headers aren't allowed in HTTP/2 (RFC 7540, 8.1.2.2),
// but respect "Connection" == "close" to mean sending a GOAWAY and tearing
// down the TCP connection when idle, like we do for HTTP/1.
// TODO: remove more Connection-specific header fields here, in addition
// to "Connection".
if _, ok := rws.snapHeader["Connection"]; ok {
v := rws.snapHeader.Get("Connection")
delete(rws.snapHeader, "Connection")
if v == "close" {
rws.conn.startGracefulShutdown()
}
}
endStream := (rws.handlerDone && !rws.hasTrailers() && len(p) == 0) || isHeadResp
err = rws.conn.writeHeaders(rws.stream, &writeResHeaders{
streamID: rws.stream.id,
httpResCode: rws.status,
h: rws.snapHeader,
endStream: endStream,
contentType: ctype,
contentLength: clen,
date: date,
})
if err != nil {
return 0, err
}
if endStream {
return 0, nil
}
}
if isHeadResp {
return len(p), nil
}
if len(p) == 0 && !rws.handlerDone {
return 0, nil
}
// only send trailers if they have actually been defined by the
// server handler.
hasNonemptyTrailers := rws.hasNonemptyTrailers()
endStream := rws.handlerDone && !hasNonemptyTrailers
if len(p) > 0 || endStream {
// only send a 0 byte DATA frame if we're ending the stream.
if err := rws.conn.writeDataFromHandler(rws.stream, p, endStream); err != nil {
return 0, err
}
}
if rws.handlerDone && hasNonemptyTrailers {
err = rws.conn.writeHeaders(rws.stream, &writeResHeaders{
streamID: rws.stream.id,
h: rws.handlerHeader,
trailers: rws.trailers,
endStream: true,
})
return len(p), err
}
return len(p), nil
}
// TrailerPrefix is a magic prefix for ResponseWriter.Header map keys
// that, if present, signals that the map entry is actually for
// the response trailers, and not the response headers. The prefix
// is stripped after the ServeHTTP call finishes and the values are
// sent in the trailers.
//
// This mechanism is intended only for trailers that are not known
// prior to the headers being written. If the set of trailers is fixed
// or known before the header is written, the normal Go trailers mechanism
// is preferred:
//
// https://golang.org/pkg/net/http/#ResponseWriter
// https://golang.org/pkg/net/http/#example_ResponseWriter_trailers
const TrailerPrefix = "Trailer:"
// promoteUndeclaredTrailers permits http.Handlers to set trailers
// after the header has already been flushed. Because the Go
// ResponseWriter interface has no way to set Trailers (only the
// Header), and because we didn't want to expand the ResponseWriter
// interface, and because nobody used trailers, and because RFC 7230
// 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
// 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),
// and gRPC libraries permit setting trailers mid-stream without
// predeclaring them. So: change of plans. We still permit the old
// way, but we also permit this hack: if a Header() key begins with
// "Trailer:", the suffix of that key is a Trailer. Because ':' is an
// invalid token byte anyway, there is no ambiguity. (And it's already
// filtered out) It's mildly hacky, but not terrible.
//
// This method runs after the Handler is done and promotes any Header
// fields to be trailers.
func (rws *responseWriterState) promoteUndeclaredTrailers() {
for k, vv := range rws.handlerHeader {
if !strings.HasPrefix(k, TrailerPrefix) {
continue
}
trailerKey := strings.TrimPrefix(k, TrailerPrefix)
rws.declareTrailer(trailerKey)
rws.handlerHeader[http.CanonicalHeaderKey(trailerKey)] = vv
}
if len(rws.trailers) > 1 {
sorter := sorterPool.Get().(*sorter)
sorter.SortStrings(rws.trailers)
sorterPool.Put(sorter)
}
}
func (w *responseWriter) SetReadDeadline(deadline time.Time) error {
st := w.rws.stream
if !deadline.IsZero() && deadline.Before(time.Now()) {
// If we're setting a deadline in the past, reset the stream immediately
// so writes after SetWriteDeadline returns will fail.
st.onReadTimeout()
return nil
}
w.rws.conn.sendServeMsg(func(sc *serverConn) {
if st.readDeadline != nil {
if !st.readDeadline.Stop() {
// Deadline already exceeded, or stream has been closed.
return
}
}
if deadline.IsZero() {
st.readDeadline = nil
} else if st.readDeadline == nil {
st.readDeadline = time.AfterFunc(deadline.Sub(time.Now()), st.onReadTimeout)
} else {
st.readDeadline.Reset(deadline.Sub(time.Now()))
}
})
return nil
}
func (w *responseWriter) SetWriteDeadline(deadline time.Time) error {
st := w.rws.stream
if !deadline.IsZero() && deadline.Before(time.Now()) {
// If we're setting a deadline in the past, reset the stream immediately
// so writes after SetWriteDeadline returns will fail.
st.onWriteTimeout()
return nil
}
w.rws.conn.sendServeMsg(func(sc *serverConn) {
if st.writeDeadline != nil {
if !st.writeDeadline.Stop() {
// Deadline already exceeded, or stream has been closed.
return
}
}
if deadline.IsZero() {
st.writeDeadline = nil
} else if st.writeDeadline == nil {
st.writeDeadline = time.AfterFunc(deadline.Sub(time.Now()), st.onWriteTimeout)
} else {
st.writeDeadline.Reset(deadline.Sub(time.Now()))
}
})
return nil
}
func (w *responseWriter) EnableFullDuplex() error {
// We always support full duplex responses, so this is a no-op.
return nil
}
func (w *responseWriter) Flush() {
w.FlushError()
}
func (w *responseWriter) FlushError() error {
rws := w.rws
if rws == nil {
panic("Header called after Handler finished")
}
var err error
if rws.bw.Buffered() > 0 {
err = rws.bw.Flush()
} else {
// The bufio.Writer won't call chunkWriter.Write
// (writeChunk with zero bytes), so we have to do it
// ourselves to force the HTTP response header and/or
// final DATA frame (with END_STREAM) to be sent.
_, err = chunkWriter{rws}.Write(nil)
if err == nil {
select {
case <-rws.stream.cw:
err = rws.stream.closeErr
default:
}
}
}
return err
}
func (w *responseWriter) CloseNotify() <-chan bool {
rws := w.rws
if rws == nil {
panic("CloseNotify called after Handler finished")
}
rws.closeNotifierMu.Lock()
ch := rws.closeNotifierCh
if ch == nil {
ch = make(chan bool, 1)
rws.closeNotifierCh = ch
cw := rws.stream.cw
go func() {
cw.Wait() // wait for close
ch <- true
}()
}
rws.closeNotifierMu.Unlock()
return ch
}
func (w *responseWriter) Header() http.Header {
rws := w.rws
if rws == nil {
panic("Header called after Handler finished")
}
if rws.handlerHeader == nil {
rws.handlerHeader = make(http.Header)
}
return rws.handlerHeader
}
// checkWriteHeaderCode is a copy of net/http's checkWriteHeaderCode.
func checkWriteHeaderCode(code int) {
// Issue 22880: require valid WriteHeader status codes.
// For now we only enforce that it's three digits.
// In the future we might block things over 599 (600 and above aren't defined
// at http://httpwg.org/specs/rfc7231.html#status.codes).
// But for now any three digits.
//
// We used to send "HTTP/1.1 000 0" on the wire in responses but there's
// no equivalent bogus thing we can realistically send in HTTP/2,
// so we'll consistently panic instead and help people find their bugs
// early. (We can't return an error from WriteHeader even if we wanted to.)
if code < 100 || code > 999 {
panic(fmt.Sprintf("invalid WriteHeader code %v", code))
}
}
func (w *responseWriter) WriteHeader(code int) {
rws := w.rws
if rws == nil {
panic("WriteHeader called after Handler finished")
}
rws.writeHeader(code)
}
func (rws *responseWriterState) writeHeader(code int) {
if rws.wroteHeader {
return
}
checkWriteHeaderCode(code)
// Handle informational headers
if code >= 100 && code <= 199 {
// Per RFC 8297 we must not clear the current header map
h := rws.handlerHeader
_, cl := h["Content-Length"]
_, te := h["Transfer-Encoding"]
if cl || te {
h = h.Clone()
h.Del("Content-Length")
h.Del("Transfer-Encoding")
}
rws.conn.writeHeaders(rws.stream, &writeResHeaders{
streamID: rws.stream.id,
httpResCode: code,
h: h,
endStream: rws.handlerDone && !rws.hasTrailers(),
})
return
}
rws.wroteHeader = true
rws.status = code
if len(rws.handlerHeader) > 0 {
rws.snapHeader = cloneHeader(rws.handlerHeader)
}
}
func cloneHeader(h http.Header) http.Header {
h2 := make(http.Header, len(h))
for k, vv := range h {
vv2 := make([]string, len(vv))
copy(vv2, vv)
h2[k] = vv2
}
return h2
}
// The Life Of A Write is like this:
//
// * Handler calls w.Write or w.WriteString ->
// * -> rws.bw (*bufio.Writer) ->
// * (Handler might call Flush)
// * -> chunkWriter{rws}
// * -> responseWriterState.writeChunk(p []byte)
// * -> responseWriterState.writeChunk (most of the magic; see comment there)
func (w *responseWriter) Write(p []byte) (n int, err error) {
return w.write(len(p), p, "")
}
func (w *responseWriter) WriteString(s string) (n int, err error) {
return w.write(len(s), nil, s)
}
// either dataB or dataS is non-zero.
func (w *responseWriter) write(lenData int, dataB []byte, dataS string) (n int, err error) {
rws := w.rws
if rws == nil {
panic("Write called after Handler finished")
}
if !rws.wroteHeader {
w.WriteHeader(200)
}
if !bodyAllowedForStatus(rws.status) {
return 0, http.ErrBodyNotAllowed
}
rws.wroteBytes += int64(len(dataB)) + int64(len(dataS)) // only one can be set
if rws.sentContentLen != 0 && rws.wroteBytes > rws.sentContentLen {
// TODO: send a RST_STREAM
return 0, errors.New("http2: handler wrote more than declared Content-Length")
}
if dataB != nil {
return rws.bw.Write(dataB)
} else {
return rws.bw.WriteString(dataS)
}
}
func (w *responseWriter) handlerDone() {
rws := w.rws
rws.handlerDone = true
w.Flush()
w.rws = nil
responseWriterStatePool.Put(rws)
}
// Push errors.
var (
ErrRecursivePush = errors.New("http2: recursive push not allowed")
ErrPushLimitReached = errors.New("http2: push would exceed peer's SETTINGS_MAX_CONCURRENT_STREAMS")
)
var _ http.Pusher = (*responseWriter)(nil)
func (w *responseWriter) Push(target string, opts *http.PushOptions) error {
st := w.rws.stream
sc := st.sc
sc.serveG.checkNotOn()
// No recursive pushes: "PUSH_PROMISE frames MUST only be sent on a peer-initiated stream."
// http://tools.ietf.org/html/rfc7540#section-6.6
if st.isPushed() {
return ErrRecursivePush
}
if opts == nil {
opts = new(http.PushOptions)
}
// Default options.
if opts.Method == "" {
opts.Method = "GET"
}
if opts.Header == nil {
opts.Header = http.Header{}
}
wantScheme := "http"
if w.rws.req.TLS != nil {
wantScheme = "https"
}
// Validate the request.
u, err := url.Parse(target)
if err != nil {
return err
}
if u.Scheme == "" {
if !strings.HasPrefix(target, "/") {
return fmt.Errorf("target must be an absolute URL or an absolute path: %q", target)
}
u.Scheme = wantScheme
u.Host = w.rws.req.Host
} else {
if u.Scheme != wantScheme {
return fmt.Errorf("cannot push URL with scheme %q from request with scheme %q", u.Scheme, wantScheme)
}
if u.Host == "" {
return errors.New("URL must have a host")
}
}
for k := range opts.Header {
if strings.HasPrefix(k, ":") {
return fmt.Errorf("promised request headers cannot include pseudo header %q", k)
}
// These headers are meaningful only if the request has a body,
// but PUSH_PROMISE requests cannot have a body.
// http://tools.ietf.org/html/rfc7540#section-8.2
// Also disallow Host, since the promised URL must be absolute.
if asciiEqualFold(k, "content-length") ||
asciiEqualFold(k, "content-encoding") ||
asciiEqualFold(k, "trailer") ||
asciiEqualFold(k, "te") ||
asciiEqualFold(k, "expect") ||
asciiEqualFold(k, "host") {
return fmt.Errorf("promised request headers cannot include %q", k)
}
}
if err := checkValidHTTP2RequestHeaders(opts.Header); err != nil {
return err
}
// The RFC effectively limits promised requests to GET and HEAD:
// "Promised requests MUST be cacheable [GET, HEAD, or POST], and MUST be safe [GET or HEAD]"
// http://tools.ietf.org/html/rfc7540#section-8.2
if opts.Method != "GET" && opts.Method != "HEAD" {
return fmt.Errorf("method %q must be GET or HEAD", opts.Method)
}
msg := &startPushRequest{
parent: st,
method: opts.Method,
url: u,
header: cloneHeader(opts.Header),
done: sc.srv.state.getErrChan(),
}
select {
case <-sc.doneServing:
return errClientDisconnected
case <-st.cw:
return errStreamClosed
case sc.serveMsgCh <- msg:
}
select {
case <-sc.doneServing:
return errClientDisconnected
case <-st.cw:
return errStreamClosed
case err := <-msg.done:
sc.srv.state.putErrChan(msg.done)
return err
}
}
type startPushRequest struct {
parent *stream
method string
url *url.URL
header http.Header
done chan error
}
func (sc *serverConn) startPush(msg *startPushRequest) {
sc.serveG.check()
// http://tools.ietf.org/html/rfc7540#section-6.6.
// PUSH_PROMISE frames MUST only be sent on a peer-initiated stream that
// is in either the "open" or "half-closed (remote)" state.
if msg.parent.state != stateOpen && msg.parent.state != stateHalfClosedRemote {
// responseWriter.Push checks that the stream is peer-initiated.
msg.done <- errStreamClosed
return
}
// http://tools.ietf.org/html/rfc7540#section-6.6.
if !sc.pushEnabled {
msg.done <- http.ErrNotSupported
return
}
// PUSH_PROMISE frames must be sent in increasing order by stream ID, so
// we allocate an ID for the promised stream lazily, when the PUSH_PROMISE
// is written. Once the ID is allocated, we start the request handler.
allocatePromisedID := func() (uint32, error) {
sc.serveG.check()
// Check this again, just in case. Technically, we might have received
// an updated SETTINGS by the time we got around to writing this frame.
if !sc.pushEnabled {
return 0, http.ErrNotSupported
}
// http://tools.ietf.org/html/rfc7540#section-6.5.2.
if sc.curPushedStreams+1 > sc.clientMaxStreams {
return 0, ErrPushLimitReached
}
// http://tools.ietf.org/html/rfc7540#section-5.1.1.
// Streams initiated by the server MUST use even-numbered identifiers.
// A server that is unable to establish a new stream identifier can send a GOAWAY
// frame so that the client is forced to open a new connection for new streams.
if sc.maxPushPromiseID+2 >= 1<<31 {
sc.startGracefulShutdownInternal()
return 0, ErrPushLimitReached
}
sc.maxPushPromiseID += 2
promisedID := sc.maxPushPromiseID
// http://tools.ietf.org/html/rfc7540#section-8.2.
// Strictly speaking, the new stream should start in "reserved (local)", then
// transition to "half closed (remote)" after sending the initial HEADERS, but
// we start in "half closed (remote)" for simplicity.
// See further comments at the definition of stateHalfClosedRemote.
promised := sc.newStream(promisedID, msg.parent.id, stateHalfClosedRemote)
rw, req, err := sc.newWriterAndRequestNoBody(promised, httpcommon.ServerRequestParam{
Method: msg.method,
Scheme: msg.url.Scheme,
Authority: msg.url.Host,
Path: msg.url.RequestURI(),
Header: cloneHeader(msg.header), // clone since handler runs concurrently with writing the PUSH_PROMISE
})
if err != nil {
// Should not happen, since we've already validated msg.url.
panic(fmt.Sprintf("newWriterAndRequestNoBody(%+v): %v", msg.url, err))
}
sc.curHandlers++
go sc.runHandler(rw, req, sc.handler.ServeHTTP)
return promisedID, nil
}
sc.writeFrame(FrameWriteRequest{
write: &writePushPromise{
streamID: msg.parent.id,
method: msg.method,
url: msg.url,
h: msg.header,
allocatePromisedID: allocatePromisedID,
},
stream: msg.parent,
done: msg.done,
})
}
// foreachHeaderElement splits v according to the "#rule" construction
// in RFC 7230 section 7 and calls fn for each non-empty element.
func foreachHeaderElement(v string, fn func(string)) {
v = textproto.TrimString(v)
if v == "" {
return
}
if !strings.Contains(v, ",") {
fn(v)
return
}
for _, f := range strings.Split(v, ",") {
if f = textproto.TrimString(f); f != "" {
fn(f)
}
}
}
// From http://httpwg.org/specs/rfc7540.html#rfc.section.8.1.2.2
var connHeaders = []string{
"Connection",
"Keep-Alive",
"Proxy-Connection",
"Transfer-Encoding",
"Upgrade",
}
// checkValidHTTP2RequestHeaders checks whether h is a valid HTTP/2 request,
// per RFC 7540 Section 8.1.2.2.
// The returned error is reported to users.
func checkValidHTTP2RequestHeaders(h http.Header) error {
for _, k := range connHeaders {
if _, ok := h[k]; ok {
return fmt.Errorf("request header %q is not valid in HTTP/2", k)
}
}
te := h["Te"]
if len(te) > 0 && (len(te) > 1 || (te[0] != "trailers" && te[0] != "")) {
return errors.New(`request header "TE" may only be "trailers" in HTTP/2`)
}
return nil
}
func new400Handler(err error) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), http.StatusBadRequest)
}
}
// h1ServerKeepAlivesDisabled reports whether hs has its keep-alives
// disabled. See comments on h1ServerShutdownChan above for why
// the code is written this way.
func h1ServerKeepAlivesDisabled(hs *http.Server) bool {
var x interface{} = hs
type I interface {
doKeepAlives() bool
}
if hs, ok := x.(I); ok {
return !hs.doKeepAlives()
}
return false
}
func (sc *serverConn) countError(name string, err error) error {
if sc == nil || sc.srv == nil {
return err
}
f := sc.countErrorFunc
if f == nil {
return err
}
var typ string
var code ErrCode
switch e := err.(type) {
case ConnectionError:
typ = "conn"
code = ErrCode(e)
case StreamError:
typ = "stream"
code = ErrCode(e.Code)
default:
return err
}
codeStr := errCodeName[code]
if codeStr == "" {
codeStr = strconv.Itoa(int(code))
}
f(fmt.Sprintf("%s_%s_%s", typ, codeStr, name))
return err
}
// 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.
// Transport code.
package http2
import (
"bufio"
"bytes"
"compress/flate"
"compress/gzip"
"context"
"crypto/rand"
"crypto/tls"
"errors"
"fmt"
"io"
"io/fs"
"log"
"math"
"math/bits"
mathrand "math/rand"
"net"
"net/http"
"net/http/httptrace"
"net/textproto"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
"golang.org/x/net/http/httpguts"
"golang.org/x/net/http2/hpack"
"golang.org/x/net/idna"
"golang.org/x/net/internal/httpcommon"
)
const (
// transportDefaultConnFlow is how many connection-level flow control
// tokens we give the server at start-up, past the default 64k.
transportDefaultConnFlow = 1 << 30
// transportDefaultStreamFlow is how many stream-level flow
// control tokens we announce to the peer, and how many bytes
// we buffer per stream.
transportDefaultStreamFlow = 4 << 20
defaultUserAgent = "Go-http-client/2.0"
// initialMaxConcurrentStreams is a connections maxConcurrentStreams until
// it's received servers initial SETTINGS frame, which corresponds with the
// spec's minimum recommended value.
initialMaxConcurrentStreams = 100
// defaultMaxConcurrentStreams is a connections default maxConcurrentStreams
// if the server doesn't include one in its initial SETTINGS frame.
defaultMaxConcurrentStreams = 1000
)
// Transport is an HTTP/2 Transport.
//
// A Transport internally caches connections to servers. It is safe
// for concurrent use by multiple goroutines.
type Transport struct {
// DialTLSContext specifies an optional dial function with context for
// creating TLS connections for requests.
//
// If DialTLSContext and DialTLS is nil, tls.Dial is used.
//
// If the returned net.Conn has a ConnectionState method like tls.Conn,
// it will be used to set http.Response.TLS.
DialTLSContext func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error)
// DialTLS specifies an optional dial function for creating
// TLS connections for requests.
//
// If DialTLSContext and DialTLS is nil, tls.Dial is used.
//
// Deprecated: Use DialTLSContext instead, which allows the transport
// to cancel dials as soon as they are no longer needed.
// If both are set, DialTLSContext takes priority.
DialTLS func(network, addr string, cfg *tls.Config) (net.Conn, error)
// TLSClientConfig specifies the TLS configuration to use with
// tls.Client. If nil, the default configuration is used.
TLSClientConfig *tls.Config
// ConnPool optionally specifies an alternate connection pool to use.
// If nil, the default is used.
ConnPool ClientConnPool
// DisableCompression, if true, prevents the Transport from
// requesting compression with an "Accept-Encoding: gzip"
// request header when the Request contains no existing
// Accept-Encoding value. If the Transport requests gzip on
// its own and gets a gzipped response, it's transparently
// decoded in the Response.Body. However, if the user
// explicitly requested gzip it is not automatically
// uncompressed.
DisableCompression bool
// AllowHTTP, if true, permits HTTP/2 requests using the insecure,
// plain-text "http" scheme. Note that this does not enable h2c support.
AllowHTTP bool
// MaxHeaderListSize is the http2 SETTINGS_MAX_HEADER_LIST_SIZE to
// send in the initial settings frame. It is how many bytes
// of response headers are allowed. Unlike the http2 spec, zero here
// means to use a default limit (currently 10MB). If you actually
// want to advertise an unlimited value to the peer, Transport
// interprets the highest possible value here (0xffffffff or 1<<32-1)
// to mean no limit.
MaxHeaderListSize uint32
// MaxReadFrameSize is the http2 SETTINGS_MAX_FRAME_SIZE to send in the
// initial settings frame. It is the size in bytes of the largest frame
// payload that the sender is willing to receive. If 0, no setting is
// sent, and the value is provided by the peer, which should be 16384
// according to the spec:
// https://datatracker.ietf.org/doc/html/rfc7540#section-6.5.2.
// Values are bounded in the range 16k to 16M.
MaxReadFrameSize uint32
// MaxDecoderHeaderTableSize optionally specifies the http2
// SETTINGS_HEADER_TABLE_SIZE to send in the initial settings frame. It
// informs the remote endpoint of the maximum size of the header compression
// table used to decode header blocks, in octets. If zero, the default value
// of 4096 is used.
MaxDecoderHeaderTableSize uint32
// MaxEncoderHeaderTableSize optionally specifies an upper limit for the
// header compression table used for encoding request headers. Received
// SETTINGS_HEADER_TABLE_SIZE settings are capped at this limit. If zero,
// the default value of 4096 is used.
MaxEncoderHeaderTableSize uint32
// StrictMaxConcurrentStreams controls whether the server's
// SETTINGS_MAX_CONCURRENT_STREAMS should be respected
// globally. If false, new TCP connections are created to the
// server as needed to keep each under the per-connection
// SETTINGS_MAX_CONCURRENT_STREAMS limit. If true, the
// server's SETTINGS_MAX_CONCURRENT_STREAMS is interpreted as
// a global limit and callers of RoundTrip block when needed,
// waiting for their turn.
StrictMaxConcurrentStreams bool
// IdleConnTimeout is the maximum amount of time an idle
// (keep-alive) connection will remain idle before closing
// itself.
// Zero means no limit.
IdleConnTimeout time.Duration
// ReadIdleTimeout is the timeout after which a health check using ping
// frame will be carried out if no frame is received on the connection.
// Note that a ping response will is considered a received frame, so if
// there is no other traffic on the connection, the health check will
// be performed every ReadIdleTimeout interval.
// If zero, no health check is performed.
ReadIdleTimeout time.Duration
// PingTimeout is the timeout after which the connection will be closed
// if a response to Ping is not received.
// Defaults to 15s.
PingTimeout time.Duration
// WriteByteTimeout is the timeout after which the connection will be
// closed no data can be written to it. The timeout begins when data is
// available to write, and is extended whenever any bytes are written.
WriteByteTimeout time.Duration
// CountError, if non-nil, is called on HTTP/2 transport errors.
// It's intended to increment a metric for monitoring, such
// as an expvar or Prometheus metric.
// The errType consists of only ASCII word characters.
CountError func(errType string)
// t1, if non-nil, is the standard library Transport using
// this transport. Its settings are used (but not its
// RoundTrip method, etc).
t1 *http.Transport
connPoolOnce sync.Once
connPoolOrDef ClientConnPool // non-nil version of ConnPool
*transportTestHooks
}
// Hook points used for testing.
// Outside of tests, t.transportTestHooks is nil and these all have minimal implementations.
// Inside tests, see the testSyncHooks function docs.
type transportTestHooks struct {
newclientconn func(*ClientConn)
}
func (t *Transport) maxHeaderListSize() uint32 {
n := int64(t.MaxHeaderListSize)
if t.t1 != nil && t.t1.MaxResponseHeaderBytes != 0 {
n = t.t1.MaxResponseHeaderBytes
if n > 0 {
n = adjustHTTP1MaxHeaderSize(n)
}
}
if n <= 0 {
return 10 << 20
}
if n >= 0xffffffff {
return 0
}
return uint32(n)
}
func (t *Transport) disableCompression() bool {
return t.DisableCompression || (t.t1 != nil && t.t1.DisableCompression)
}
// ConfigureTransport configures a net/http HTTP/1 Transport to use HTTP/2.
// It returns an error if t1 has already been HTTP/2-enabled.
//
// Use ConfigureTransports instead to configure the HTTP/2 Transport.
func ConfigureTransport(t1 *http.Transport) error {
_, err := ConfigureTransports(t1)
return err
}
// ConfigureTransports configures a net/http HTTP/1 Transport to use HTTP/2.
// It returns a new HTTP/2 Transport for further configuration.
// It returns an error if t1 has already been HTTP/2-enabled.
func ConfigureTransports(t1 *http.Transport) (*Transport, error) {
return configureTransports(t1)
}
func configureTransports(t1 *http.Transport) (*Transport, error) {
connPool := new(clientConnPool)
t2 := &Transport{
ConnPool: noDialClientConnPool{connPool},
t1: t1,
}
connPool.t = t2
if err := registerHTTPSProtocol(t1, noDialH2RoundTripper{t2}); err != nil {
return nil, err
}
if t1.TLSClientConfig == nil {
t1.TLSClientConfig = new(tls.Config)
}
if !strSliceContains(t1.TLSClientConfig.NextProtos, "h2") {
t1.TLSClientConfig.NextProtos = append([]string{"h2"}, t1.TLSClientConfig.NextProtos...)
}
if !strSliceContains(t1.TLSClientConfig.NextProtos, "http/1.1") {
t1.TLSClientConfig.NextProtos = append(t1.TLSClientConfig.NextProtos, "http/1.1")
}
upgradeFn := func(scheme, authority string, c net.Conn) http.RoundTripper {
addr := authorityAddr(scheme, authority)
if used, err := connPool.addConnIfNeeded(addr, t2, c); err != nil {
go c.Close()
return erringRoundTripper{err}
} else if !used {
// Turns out we don't need this c.
// For example, two goroutines made requests to the same host
// at the same time, both kicking off TCP dials. (since protocol
// was unknown)
go c.Close()
}
if scheme == "http" {
return (*unencryptedTransport)(t2)
}
return t2
}
if t1.TLSNextProto == nil {
t1.TLSNextProto = make(map[string]func(string, *tls.Conn) http.RoundTripper)
}
t1.TLSNextProto[NextProtoTLS] = func(authority string, c *tls.Conn) http.RoundTripper {
return upgradeFn("https", authority, c)
}
// The "unencrypted_http2" TLSNextProto key is used to pass off non-TLS HTTP/2 conns.
t1.TLSNextProto[nextProtoUnencryptedHTTP2] = func(authority string, c *tls.Conn) http.RoundTripper {
nc, err := unencryptedNetConnFromTLSConn(c)
if err != nil {
go c.Close()
return erringRoundTripper{err}
}
return upgradeFn("http", authority, nc)
}
return t2, nil
}
// unencryptedTransport is a Transport with a RoundTrip method that
// always permits http:// URLs.
type unencryptedTransport Transport
func (t *unencryptedTransport) RoundTrip(req *http.Request) (*http.Response, error) {
return (*Transport)(t).RoundTripOpt(req, RoundTripOpt{allowHTTP: true})
}
func (t *Transport) connPool() ClientConnPool {
t.connPoolOnce.Do(t.initConnPool)
return t.connPoolOrDef
}
func (t *Transport) initConnPool() {
if t.ConnPool != nil {
t.connPoolOrDef = t.ConnPool
} else {
t.connPoolOrDef = &clientConnPool{t: t}
}
}
// ClientConn is the state of a single HTTP/2 client connection to an
// HTTP/2 server.
type ClientConn struct {
t *Transport
tconn net.Conn // usually *tls.Conn, except specialized impls
tlsState *tls.ConnectionState // nil only for specialized impls
atomicReused uint32 // whether conn is being reused; atomic
singleUse bool // whether being used for a single http.Request
getConnCalled bool // used by clientConnPool
// readLoop goroutine fields:
readerDone chan struct{} // closed on error
readerErr error // set before readerDone is closed
idleTimeout time.Duration // or 0 for never
idleTimer *time.Timer
mu sync.Mutex // guards following
cond *sync.Cond // hold mu; broadcast on flow/closed changes
flow outflow // our conn-level flow control quota (cs.outflow is per stream)
inflow inflow // peer's conn-level flow control
doNotReuse bool // whether conn is marked to not be reused for any future requests
closing bool
closed bool
closedOnIdle bool // true if conn was closed for idleness
seenSettings bool // true if we've seen a settings frame, false otherwise
seenSettingsChan chan struct{} // closed when seenSettings is true or frame reading fails
wantSettingsAck bool // we sent a SETTINGS frame and haven't heard back
goAway *GoAwayFrame // if non-nil, the GoAwayFrame we received
goAwayDebug string // goAway frame's debug data, retained as a string
streams map[uint32]*clientStream // client-initiated
streamsReserved int // incr by ReserveNewRequest; decr on RoundTrip
nextStreamID uint32
pendingRequests int // requests blocked and waiting to be sent because len(streams) == maxConcurrentStreams
pings map[[8]byte]chan struct{} // in flight ping data to notification channel
br *bufio.Reader
lastActive time.Time
lastIdle time.Time // time last idle
// Settings from peer: (also guarded by wmu)
maxFrameSize uint32
maxConcurrentStreams uint32
peerMaxHeaderListSize uint64
peerMaxHeaderTableSize uint32
initialWindowSize uint32
initialStreamRecvWindowSize int32
readIdleTimeout time.Duration
pingTimeout time.Duration
extendedConnectAllowed bool
strictMaxConcurrentStreams bool
// rstStreamPingsBlocked works around an unfortunate gRPC behavior.
// gRPC strictly limits the number of PING frames that it will receive.
// The default is two pings per two hours, but the limit resets every time
// the gRPC endpoint sends a HEADERS or DATA frame. See golang/go#70575.
//
// rstStreamPingsBlocked is set after receiving a response to a PING frame
// bundled with an RST_STREAM (see pendingResets below), and cleared after
// receiving a HEADERS or DATA frame.
rstStreamPingsBlocked bool
// pendingResets is the number of RST_STREAM frames we have sent to the peer,
// without confirming that the peer has received them. When we send a RST_STREAM,
// we bundle it with a PING frame, unless a PING is already in flight. We count
// the reset stream against the connection's concurrency limit until we get
// a PING response. This limits the number of requests we'll try to send to a
// completely unresponsive connection.
pendingResets int
// reqHeaderMu is a 1-element semaphore channel controlling access to sending new requests.
// Write to reqHeaderMu to lock it, read from it to unlock.
// Lock reqmu BEFORE mu or wmu.
reqHeaderMu chan struct{}
// wmu is held while writing.
// Acquire BEFORE mu when holding both, to avoid blocking mu on network writes.
// Only acquire both at the same time when changing peer settings.
wmu sync.Mutex
bw *bufio.Writer
fr *Framer
werr error // first write error that has occurred
hbuf bytes.Buffer // HPACK encoder writes into this
henc *hpack.Encoder
}
// clientStream is the state for a single HTTP/2 stream. One of these
// is created for each Transport.RoundTrip call.
type clientStream struct {
cc *ClientConn
// Fields of Request that we may access even after the response body is closed.
ctx context.Context
reqCancel <-chan struct{}
trace *httptrace.ClientTrace // or nil
ID uint32
bufPipe pipe // buffered pipe with the flow-controlled response payload
requestedGzip bool
isHead bool
abortOnce sync.Once
abort chan struct{} // closed to signal stream should end immediately
abortErr error // set if abort is closed
peerClosed chan struct{} // closed when the peer sends an END_STREAM flag
donec chan struct{} // closed after the stream is in the closed state
on100 chan struct{} // buffered; written to if a 100 is received
respHeaderRecv chan struct{} // closed when headers are received
res *http.Response // set if respHeaderRecv is closed
flow outflow // guarded by cc.mu
inflow inflow // guarded by cc.mu
bytesRemain int64 // -1 means unknown; owned by transportResponseBody.Read
readErr error // sticky read error; owned by transportResponseBody.Read
reqBody io.ReadCloser
reqBodyContentLength int64 // -1 means unknown
reqBodyClosed chan struct{} // guarded by cc.mu; non-nil on Close, closed when done
// owned by writeRequest:
sentEndStream bool // sent an END_STREAM flag to the peer
sentHeaders bool
// owned by clientConnReadLoop:
firstByte bool // got the first response byte
pastHeaders bool // got first MetaHeadersFrame (actual headers)
pastTrailers bool // got optional second MetaHeadersFrame (trailers)
readClosed bool // peer sent an END_STREAM flag
readAborted bool // read loop reset the stream
totalHeaderSize int64 // total size of 1xx headers seen
trailer http.Header // accumulated trailers
resTrailer *http.Header // client's Response.Trailer
}
var got1xxFuncForTests func(int, textproto.MIMEHeader) error
// get1xxTraceFunc returns the value of request's httptrace.ClientTrace.Got1xxResponse func,
// if any. It returns nil if not set or if the Go version is too old.
func (cs *clientStream) get1xxTraceFunc() func(int, textproto.MIMEHeader) error {
if fn := got1xxFuncForTests; fn != nil {
return fn
}
return traceGot1xxResponseFunc(cs.trace)
}
func (cs *clientStream) abortStream(err error) {
cs.cc.mu.Lock()
defer cs.cc.mu.Unlock()
cs.abortStreamLocked(err)
}
func (cs *clientStream) abortStreamLocked(err error) {
cs.abortOnce.Do(func() {
cs.abortErr = err
close(cs.abort)
})
if cs.reqBody != nil {
cs.closeReqBodyLocked()
}
// TODO(dneil): Clean up tests where cs.cc.cond is nil.
if cs.cc.cond != nil {
// Wake up writeRequestBody if it is waiting on flow control.
cs.cc.cond.Broadcast()
}
}
func (cs *clientStream) abortRequestBodyWrite() {
cc := cs.cc
cc.mu.Lock()
defer cc.mu.Unlock()
if cs.reqBody != nil && cs.reqBodyClosed == nil {
cs.closeReqBodyLocked()
cc.cond.Broadcast()
}
}
func (cs *clientStream) closeReqBodyLocked() {
if cs.reqBodyClosed != nil {
return
}
cs.reqBodyClosed = make(chan struct{})
reqBodyClosed := cs.reqBodyClosed
go func() {
cs.reqBody.Close()
close(reqBodyClosed)
}()
}
type stickyErrWriter struct {
conn net.Conn
timeout time.Duration
err *error
}
func (sew stickyErrWriter) Write(p []byte) (n int, err error) {
if *sew.err != nil {
return 0, *sew.err
}
n, err = writeWithByteTimeout(sew.conn, sew.timeout, p)
*sew.err = err
return n, err
}
// noCachedConnError is the concrete type of ErrNoCachedConn, which
// needs to be detected by net/http regardless of whether it's its
// bundled version (in h2_bundle.go with a rewritten type name) or
// from a user's x/net/http2. As such, as it has a unique method name
// (IsHTTP2NoCachedConnError) that net/http sniffs for via func
// isNoCachedConnError.
type noCachedConnError struct{}
func (noCachedConnError) IsHTTP2NoCachedConnError() {}
func (noCachedConnError) Error() string { return "http2: no cached connection was available" }
// isNoCachedConnError reports whether err is of type noCachedConnError
// or its equivalent renamed type in net/http2's h2_bundle.go. Both types
// may coexist in the same running program.
func isNoCachedConnError(err error) bool {
_, ok := err.(interface{ IsHTTP2NoCachedConnError() })
return ok
}
var ErrNoCachedConn error = noCachedConnError{}
// RoundTripOpt are options for the Transport.RoundTripOpt method.
type RoundTripOpt struct {
// OnlyCachedConn controls whether RoundTripOpt may
// create a new TCP connection. If set true and
// no cached connection is available, RoundTripOpt
// will return ErrNoCachedConn.
OnlyCachedConn bool
allowHTTP bool // allow http:// URLs
}
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
return t.RoundTripOpt(req, RoundTripOpt{})
}
// authorityAddr returns a given authority (a host/IP, or host:port / ip:port)
// and returns a host:port. The port 443 is added if needed.
func authorityAddr(scheme string, authority string) (addr string) {
host, port, err := net.SplitHostPort(authority)
if err != nil { // authority didn't have a port
host = authority
port = ""
}
if port == "" { // authority's port was empty
port = "443"
if scheme == "http" {
port = "80"
}
}
if a, err := idna.ToASCII(host); err == nil {
host = a
}
// IPv6 address literal, without a port:
if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
return host + ":" + port
}
return net.JoinHostPort(host, port)
}
// RoundTripOpt is like RoundTrip, but takes options.
func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Response, error) {
switch req.URL.Scheme {
case "https":
// Always okay.
case "http":
if !t.AllowHTTP && !opt.allowHTTP {
return nil, errors.New("http2: unencrypted HTTP/2 not enabled")
}
default:
return nil, errors.New("http2: unsupported scheme")
}
addr := authorityAddr(req.URL.Scheme, req.URL.Host)
for retry := 0; ; retry++ {
cc, err := t.connPool().GetClientConn(req, addr)
if err != nil {
t.vlogf("http2: Transport failed to get client conn for %s: %v", addr, err)
return nil, err
}
reused := !atomic.CompareAndSwapUint32(&cc.atomicReused, 0, 1)
traceGotConn(req, cc, reused)
res, err := cc.RoundTrip(req)
if err != nil && retry <= 6 {
roundTripErr := err
if req, err = shouldRetryRequest(req, err); err == nil {
// After the first retry, do exponential backoff with 10% jitter.
if retry == 0 {
t.vlogf("RoundTrip retrying after failure: %v", roundTripErr)
continue
}
backoff := float64(uint(1) << (uint(retry) - 1))
backoff += backoff * (0.1 * mathrand.Float64())
d := time.Second * time.Duration(backoff)
tm := time.NewTimer(d)
select {
case <-tm.C:
t.vlogf("RoundTrip retrying after failure: %v", roundTripErr)
continue
case <-req.Context().Done():
tm.Stop()
err = req.Context().Err()
}
}
}
if err == errClientConnNotEstablished {
// This ClientConn was created recently,
// this is the first request to use it,
// and the connection is closed and not usable.
//
// In this state, cc.idleTimer will remove the conn from the pool
// when it fires. Stop the timer and remove it here so future requests
// won't try to use this connection.
//
// If the timer has already fired and we're racing it, the redundant
// call to MarkDead is harmless.
if cc.idleTimer != nil {
cc.idleTimer.Stop()
}
t.connPool().MarkDead(cc)
}
if err != nil {
t.vlogf("RoundTrip failure: %v", err)
return nil, err
}
return res, nil
}
}
// CloseIdleConnections closes any connections which were previously
// connected from previous requests but are now sitting idle.
// It does not interrupt any connections currently in use.
func (t *Transport) CloseIdleConnections() {
if cp, ok := t.connPool().(clientConnPoolIdleCloser); ok {
cp.closeIdleConnections()
}
}
var (
errClientConnClosed = errors.New("http2: client conn is closed")
errClientConnUnusable = errors.New("http2: client conn not usable")
errClientConnNotEstablished = errors.New("http2: client conn could not be established")
errClientConnGotGoAway = errors.New("http2: Transport received Server's graceful shutdown GOAWAY")
errClientConnForceClosed = errors.New("http2: client connection force closed via ClientConn.Close")
)
// shouldRetryRequest is called by RoundTrip when a request fails to get
// response headers. It is always called with a non-nil error.
// It returns either a request to retry (either the same request, or a
// modified clone), or an error if the request can't be replayed.
func shouldRetryRequest(req *http.Request, err error) (*http.Request, error) {
if !canRetryError(err) {
return nil, err
}
// If the Body is nil (or http.NoBody), it's safe to reuse
// this request and its Body.
if req.Body == nil || req.Body == http.NoBody {
return req, nil
}
// If the request body can be reset back to its original
// state via the optional req.GetBody, do that.
if req.GetBody != nil {
body, err := req.GetBody()
if err != nil {
return nil, err
}
newReq := *req
newReq.Body = body
return &newReq, nil
}
// The Request.Body can't reset back to the beginning, but we
// don't seem to have started to read from it yet, so reuse
// the request directly.
if err == errClientConnUnusable {
return req, nil
}
return nil, fmt.Errorf("http2: Transport: cannot retry err [%v] after Request.Body was written; define Request.GetBody to avoid this error", err)
}
func canRetryError(err error) bool {
if err == errClientConnUnusable || err == errClientConnGotGoAway {
return true
}
if se, ok := err.(StreamError); ok {
if se.Code == ErrCodeProtocol && se.Cause == errFromPeer {
// See golang/go#47635, golang/go#42777
return true
}
return se.Code == ErrCodeRefusedStream
}
return false
}
func (t *Transport) dialClientConn(ctx context.Context, addr string, singleUse bool) (*ClientConn, error) {
if t.transportTestHooks != nil {
return t.newClientConn(nil, singleUse)
}
host, _, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
}
tconn, err := t.dialTLS(ctx, "tcp", addr, t.newTLSConfig(host))
if err != nil {
return nil, err
}
return t.newClientConn(tconn, singleUse)
}
func (t *Transport) newTLSConfig(host string) *tls.Config {
cfg := new(tls.Config)
if t.TLSClientConfig != nil {
*cfg = *t.TLSClientConfig.Clone()
}
if !strSliceContains(cfg.NextProtos, NextProtoTLS) {
cfg.NextProtos = append([]string{NextProtoTLS}, cfg.NextProtos...)
}
if cfg.ServerName == "" {
cfg.ServerName = host
}
return cfg
}
func (t *Transport) dialTLS(ctx context.Context, network, addr string, tlsCfg *tls.Config) (net.Conn, error) {
if t.DialTLSContext != nil {
return t.DialTLSContext(ctx, network, addr, tlsCfg)
} else if t.DialTLS != nil {
return t.DialTLS(network, addr, tlsCfg)
}
tlsCn, err := t.dialTLSWithContext(ctx, network, addr, tlsCfg)
if err != nil {
return nil, err
}
state := tlsCn.ConnectionState()
if p := state.NegotiatedProtocol; p != NextProtoTLS {
return nil, fmt.Errorf("http2: unexpected ALPN protocol %q; want %q", p, NextProtoTLS)
}
if !state.NegotiatedProtocolIsMutual {
return nil, errors.New("http2: could not negotiate protocol mutually")
}
return tlsCn, nil
}
// disableKeepAlives reports whether connections should be closed as
// soon as possible after handling the first request.
func (t *Transport) disableKeepAlives() bool {
return t.t1 != nil && t.t1.DisableKeepAlives
}
func (t *Transport) expectContinueTimeout() time.Duration {
if t.t1 == nil {
return 0
}
return t.t1.ExpectContinueTimeout
}
func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {
return t.newClientConn(c, t.disableKeepAlives())
}
func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, error) {
conf := configFromTransport(t)
cc := &ClientConn{
t: t,
tconn: c,
readerDone: make(chan struct{}),
nextStreamID: 1,
maxFrameSize: 16 << 10, // spec default
initialWindowSize: 65535, // spec default
initialStreamRecvWindowSize: conf.MaxUploadBufferPerStream,
maxConcurrentStreams: initialMaxConcurrentStreams, // "infinite", per spec. Use a smaller value until we have received server settings.
strictMaxConcurrentStreams: conf.StrictMaxConcurrentRequests,
peerMaxHeaderListSize: 0xffffffffffffffff, // "infinite", per spec. Use 2^64-1 instead.
streams: make(map[uint32]*clientStream),
singleUse: singleUse,
seenSettingsChan: make(chan struct{}),
wantSettingsAck: true,
readIdleTimeout: conf.SendPingTimeout,
pingTimeout: conf.PingTimeout,
pings: make(map[[8]byte]chan struct{}),
reqHeaderMu: make(chan struct{}, 1),
lastActive: time.Now(),
}
if t.transportTestHooks != nil {
t.transportTestHooks.newclientconn(cc)
c = cc.tconn
}
if VerboseLogs {
t.vlogf("http2: Transport creating client conn %p to %v", cc, c.RemoteAddr())
}
cc.cond = sync.NewCond(&cc.mu)
cc.flow.add(int32(initialWindowSize))
// TODO: adjust this writer size to account for frame size +
// MTU + crypto/tls record padding.
cc.bw = bufio.NewWriter(stickyErrWriter{
conn: c,
timeout: conf.WriteByteTimeout,
err: &cc.werr,
})
cc.br = bufio.NewReader(c)
cc.fr = NewFramer(cc.bw, cc.br)
cc.fr.SetMaxReadFrameSize(conf.MaxReadFrameSize)
if t.CountError != nil {
cc.fr.countError = t.CountError
}
maxHeaderTableSize := conf.MaxDecoderHeaderTableSize
cc.fr.ReadMetaHeaders = hpack.NewDecoder(maxHeaderTableSize, nil)
cc.fr.MaxHeaderListSize = t.maxHeaderListSize()
cc.henc = hpack.NewEncoder(&cc.hbuf)
cc.henc.SetMaxDynamicTableSizeLimit(conf.MaxEncoderHeaderTableSize)
cc.peerMaxHeaderTableSize = initialHeaderTableSize
if cs, ok := c.(connectionStater); ok {
state := cs.ConnectionState()
cc.tlsState = &state
}
initialSettings := []Setting{
{ID: SettingEnablePush, Val: 0},
{ID: SettingInitialWindowSize, Val: uint32(cc.initialStreamRecvWindowSize)},
}
initialSettings = append(initialSettings, Setting{ID: SettingMaxFrameSize, Val: conf.MaxReadFrameSize})
if max := t.maxHeaderListSize(); max != 0 {
initialSettings = append(initialSettings, Setting{ID: SettingMaxHeaderListSize, Val: max})
}
if maxHeaderTableSize != initialHeaderTableSize {
initialSettings = append(initialSettings, Setting{ID: SettingHeaderTableSize, Val: maxHeaderTableSize})
}
cc.bw.Write(clientPreface)
cc.fr.WriteSettings(initialSettings...)
cc.fr.WriteWindowUpdate(0, uint32(conf.MaxUploadBufferPerConnection))
cc.inflow.init(conf.MaxUploadBufferPerConnection + initialWindowSize)
cc.bw.Flush()
if cc.werr != nil {
cc.Close()
return nil, cc.werr
}
// Start the idle timer after the connection is fully initialized.
if d := t.idleConnTimeout(); d != 0 {
cc.idleTimeout = d
cc.idleTimer = time.AfterFunc(d, cc.onIdleTimeout)
}
go cc.readLoop()
return cc, nil
}
func (cc *ClientConn) healthCheck() {
pingTimeout := cc.pingTimeout
// We don't need to periodically ping in the health check, because the readLoop of ClientConn will
// trigger the healthCheck again if there is no frame received.
ctx, cancel := context.WithTimeout(context.Background(), pingTimeout)
defer cancel()
cc.vlogf("http2: Transport sending health check")
err := cc.Ping(ctx)
if err != nil {
cc.vlogf("http2: Transport health check failure: %v", err)
cc.closeForLostPing()
} else {
cc.vlogf("http2: Transport health check success")
}
}
// SetDoNotReuse marks cc as not reusable for future HTTP requests.
func (cc *ClientConn) SetDoNotReuse() {
cc.mu.Lock()
defer cc.mu.Unlock()
cc.doNotReuse = true
}
func (cc *ClientConn) setGoAway(f *GoAwayFrame) {
cc.mu.Lock()
defer cc.mu.Unlock()
old := cc.goAway
cc.goAway = f
// Merge the previous and current GoAway error frames.
if cc.goAwayDebug == "" {
cc.goAwayDebug = string(f.DebugData())
}
if old != nil && old.ErrCode != ErrCodeNo {
cc.goAway.ErrCode = old.ErrCode
}
last := f.LastStreamID
for streamID, cs := range cc.streams {
if streamID <= last {
// The server's GOAWAY indicates that it received this stream.
// It will either finish processing it, or close the connection
// without doing so. Either way, leave the stream alone for now.
continue
}
if streamID == 1 && cc.goAway.ErrCode != ErrCodeNo {
// Don't retry the first stream on a connection if we get a non-NO error.
// If the server is sending an error on a new connection,
// retrying the request on a new one probably isn't going to work.
cs.abortStreamLocked(fmt.Errorf("http2: Transport received GOAWAY from server ErrCode:%v", cc.goAway.ErrCode))
} else {
// Aborting the stream with errClentConnGotGoAway indicates that
// the request should be retried on a new connection.
cs.abortStreamLocked(errClientConnGotGoAway)
}
}
}
// CanTakeNewRequest reports whether the connection can take a new request,
// meaning it has not been closed or received or sent a GOAWAY.
//
// If the caller is going to immediately make a new request on this
// connection, use ReserveNewRequest instead.
func (cc *ClientConn) CanTakeNewRequest() bool {
cc.mu.Lock()
defer cc.mu.Unlock()
return cc.canTakeNewRequestLocked()
}
// ReserveNewRequest is like CanTakeNewRequest but also reserves a
// concurrent stream in cc. The reservation is decremented on the
// next call to RoundTrip.
func (cc *ClientConn) ReserveNewRequest() bool {
cc.mu.Lock()
defer cc.mu.Unlock()
if st := cc.idleStateLocked(); !st.canTakeNewRequest {
return false
}
cc.streamsReserved++
return true
}
// ClientConnState describes the state of a ClientConn.
type ClientConnState struct {
// Closed is whether the connection is closed.
Closed bool
// Closing is whether the connection is in the process of
// closing. It may be closing due to shutdown, being a
// single-use connection, being marked as DoNotReuse, or
// having received a GOAWAY frame.
Closing bool
// StreamsActive is how many streams are active.
StreamsActive int
// StreamsReserved is how many streams have been reserved via
// ClientConn.ReserveNewRequest.
StreamsReserved int
// StreamsPending is how many requests have been sent in excess
// of the peer's advertised MaxConcurrentStreams setting and
// are waiting for other streams to complete.
StreamsPending int
// MaxConcurrentStreams is how many concurrent streams the
// peer advertised as acceptable. Zero means no SETTINGS
// frame has been received yet.
MaxConcurrentStreams uint32
// LastIdle, if non-zero, is when the connection last
// transitioned to idle state.
LastIdle time.Time
}
// State returns a snapshot of cc's state.
func (cc *ClientConn) State() ClientConnState {
cc.wmu.Lock()
maxConcurrent := cc.maxConcurrentStreams
if !cc.seenSettings {
maxConcurrent = 0
}
cc.wmu.Unlock()
cc.mu.Lock()
defer cc.mu.Unlock()
return ClientConnState{
Closed: cc.closed,
Closing: cc.closing || cc.singleUse || cc.doNotReuse || cc.goAway != nil,
StreamsActive: len(cc.streams) + cc.pendingResets,
StreamsReserved: cc.streamsReserved,
StreamsPending: cc.pendingRequests,
LastIdle: cc.lastIdle,
MaxConcurrentStreams: maxConcurrent,
}
}
// clientConnIdleState describes the suitability of a client
// connection to initiate a new RoundTrip request.
type clientConnIdleState struct {
canTakeNewRequest bool
}
func (cc *ClientConn) idleState() clientConnIdleState {
cc.mu.Lock()
defer cc.mu.Unlock()
return cc.idleStateLocked()
}
func (cc *ClientConn) idleStateLocked() (st clientConnIdleState) {
if cc.singleUse && cc.nextStreamID > 1 {
return
}
var maxConcurrentOkay bool
if cc.strictMaxConcurrentStreams {
// We'll tell the caller we can take a new request to
// prevent the caller from dialing a new TCP
// connection, but then we'll block later before
// writing it.
maxConcurrentOkay = true
} else {
// We can take a new request if the total of
// - active streams;
// - reservation slots for new streams; and
// - streams for which we have sent a RST_STREAM and a PING,
// but received no subsequent frame
// is less than the concurrency limit.
maxConcurrentOkay = cc.currentRequestCountLocked() < int(cc.maxConcurrentStreams)
}
st.canTakeNewRequest = cc.goAway == nil && !cc.closed && !cc.closing && maxConcurrentOkay &&
!cc.doNotReuse &&
int64(cc.nextStreamID)+2*int64(cc.pendingRequests) < math.MaxInt32 &&
!cc.tooIdleLocked()
// If this connection has never been used for a request and is closed,
// then let it take a request (which will fail).
// If the conn was closed for idleness, we're racing the idle timer;
// don't try to use the conn. (Issue #70515.)
//
// This avoids a situation where an error early in a connection's lifetime
// goes unreported.
if cc.nextStreamID == 1 && cc.streamsReserved == 0 && cc.closed && !cc.closedOnIdle {
st.canTakeNewRequest = true
}
return
}
// currentRequestCountLocked reports the number of concurrency slots currently in use,
// including active streams, reserved slots, and reset streams waiting for acknowledgement.
func (cc *ClientConn) currentRequestCountLocked() int {
return len(cc.streams) + cc.streamsReserved + cc.pendingResets
}
func (cc *ClientConn) canTakeNewRequestLocked() bool {
st := cc.idleStateLocked()
return st.canTakeNewRequest
}
// tooIdleLocked reports whether this connection has been been sitting idle
// for too much wall time.
func (cc *ClientConn) tooIdleLocked() bool {
// The Round(0) strips the monontonic clock reading so the
// times are compared based on their wall time. We don't want
// to reuse a connection that's been sitting idle during
// VM/laptop suspend if monotonic time was also frozen.
return cc.idleTimeout != 0 && !cc.lastIdle.IsZero() && time.Since(cc.lastIdle.Round(0)) > cc.idleTimeout
}
// 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
// connection. The timer could just call closeIfIdle, but this is more
// clear.
func (cc *ClientConn) onIdleTimeout() {
cc.closeIfIdle()
}
func (cc *ClientConn) closeConn() {
t := time.AfterFunc(250*time.Millisecond, cc.forceCloseConn)
defer t.Stop()
cc.tconn.Close()
}
// A tls.Conn.Close can hang for a long time if the peer is unresponsive.
// Try to shut it down more aggressively.
func (cc *ClientConn) forceCloseConn() {
tc, ok := cc.tconn.(*tls.Conn)
if !ok {
return
}
if nc := tc.NetConn(); nc != nil {
nc.Close()
}
}
func (cc *ClientConn) closeIfIdle() {
cc.mu.Lock()
if len(cc.streams) > 0 || cc.streamsReserved > 0 {
cc.mu.Unlock()
return
}
cc.closed = true
cc.closedOnIdle = true
nextID := cc.nextStreamID
// TODO: do clients send GOAWAY too? maybe? Just Close:
cc.mu.Unlock()
if VerboseLogs {
cc.vlogf("http2: Transport closing idle conn %p (forSingleUse=%v, maxStream=%v)", cc, cc.singleUse, nextID-2)
}
cc.closeConn()
}
func (cc *ClientConn) isDoNotReuseAndIdle() bool {
cc.mu.Lock()
defer cc.mu.Unlock()
return cc.doNotReuse && len(cc.streams) == 0
}
var shutdownEnterWaitStateHook = func() {}
// Shutdown gracefully closes the client connection, waiting for running streams to complete.
func (cc *ClientConn) Shutdown(ctx context.Context) error {
if err := cc.sendGoAway(); err != nil {
return err
}
// Wait for all in-flight streams to complete or connection to close
done := make(chan struct{})
cancelled := false // guarded by cc.mu
go func() {
cc.mu.Lock()
defer cc.mu.Unlock()
for {
if len(cc.streams) == 0 || cc.closed {
cc.closed = true
close(done)
break
}
if cancelled {
break
}
cc.cond.Wait()
}
}()
shutdownEnterWaitStateHook()
select {
case <-done:
cc.closeConn()
return nil
case <-ctx.Done():
cc.mu.Lock()
// Free the goroutine above
cancelled = true
cc.cond.Broadcast()
cc.mu.Unlock()
return ctx.Err()
}
}
func (cc *ClientConn) sendGoAway() error {
cc.mu.Lock()
closing := cc.closing
cc.closing = true
maxStreamID := cc.nextStreamID
cc.mu.Unlock()
if closing {
// GOAWAY sent already
return nil
}
cc.wmu.Lock()
defer cc.wmu.Unlock()
// Send a graceful shutdown frame to server
if err := cc.fr.WriteGoAway(maxStreamID, ErrCodeNo, nil); err != nil {
return err
}
if err := cc.bw.Flush(); err != nil {
return err
}
// Prevent new requests
return nil
}
// closes the client connection immediately. In-flight requests are interrupted.
// err is sent to streams.
func (cc *ClientConn) closeForError(err error) {
cc.mu.Lock()
cc.closed = true
for _, cs := range cc.streams {
cs.abortStreamLocked(err)
}
cc.cond.Broadcast()
cc.mu.Unlock()
cc.closeConn()
}
// Close closes the client connection immediately.
//
// In-flight requests are interrupted. For a graceful shutdown, use Shutdown instead.
func (cc *ClientConn) Close() error {
cc.closeForError(errClientConnForceClosed)
return nil
}
// closes the client connection immediately. In-flight requests are interrupted.
func (cc *ClientConn) closeForLostPing() {
err := errors.New("http2: client connection lost")
if f := cc.t.CountError; f != nil {
f("conn_close_lost_ping")
}
cc.closeForError(err)
}
// errRequestCanceled is a copy of net/http's errRequestCanceled because it's not
// exported. At least they'll be DeepEqual for h1-vs-h2 comparisons tests.
var errRequestCanceled = errors.New("net/http: request canceled")
func (cc *ClientConn) responseHeaderTimeout() time.Duration {
if cc.t.t1 != nil {
return cc.t.t1.ResponseHeaderTimeout
}
// No way to do this (yet?) with just an http2.Transport. Probably
// no need. Request.Cancel this is the new way. We only need to support
// this for compatibility with the old http.Transport fields when
// we're doing transparent http2.
return 0
}
// actualContentLength returns a sanitized version of
// req.ContentLength, where 0 actually means zero (not unknown) and -1
// means unknown.
func actualContentLength(req *http.Request) int64 {
if req.Body == nil || req.Body == http.NoBody {
return 0
}
if req.ContentLength != 0 {
return req.ContentLength
}
return -1
}
func (cc *ClientConn) decrStreamReservations() {
cc.mu.Lock()
defer cc.mu.Unlock()
cc.decrStreamReservationsLocked()
}
func (cc *ClientConn) decrStreamReservationsLocked() {
if cc.streamsReserved > 0 {
cc.streamsReserved--
}
}
func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
return cc.roundTrip(req, nil)
}
func (cc *ClientConn) roundTrip(req *http.Request, streamf func(*clientStream)) (*http.Response, error) {
ctx := req.Context()
cs := &clientStream{
cc: cc,
ctx: ctx,
reqCancel: req.Cancel,
isHead: req.Method == "HEAD",
reqBody: req.Body,
reqBodyContentLength: actualContentLength(req),
trace: httptrace.ContextClientTrace(ctx),
peerClosed: make(chan struct{}),
abort: make(chan struct{}),
respHeaderRecv: make(chan struct{}),
donec: make(chan struct{}),
}
cs.requestedGzip = httpcommon.IsRequestGzip(req.Method, req.Header, cc.t.disableCompression())
go cs.doRequest(req, streamf)
waitDone := func() error {
select {
case <-cs.donec:
return nil
case <-ctx.Done():
return ctx.Err()
case <-cs.reqCancel:
return errRequestCanceled
}
}
handleResponseHeaders := func() (*http.Response, error) {
res := cs.res
if res.StatusCode > 299 {
// On error or status code 3xx, 4xx, 5xx, etc abort any
// ongoing write, assuming that the server doesn't care
// about our request body. If the server replied with 1xx or
// 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
// we can keep it.
cs.abortRequestBodyWrite()
}
res.Request = req
res.TLS = cc.tlsState
if res.Body == noBody && actualContentLength(req) == 0 {
// If there isn't a request or response body still being
// written, then wait for the stream to be closed before
// RoundTrip returns.
if err := waitDone(); err != nil {
return nil, err
}
}
return res, nil
}
cancelRequest := func(cs *clientStream, err error) error {
cs.cc.mu.Lock()
bodyClosed := cs.reqBodyClosed
cs.cc.mu.Unlock()
// Wait for the request body to be closed.
//
// If nothing closed the body before now, abortStreamLocked
// will have started a goroutine to close it.
//
// Closing the body before returning avoids a race condition
// with net/http checking its readTrackingBody to see if the
// body was read from or closed. See golang/go#60041.
//
// The body is closed in a separate goroutine without the
// connection mutex held, but dropping the mutex before waiting
// will keep us from holding it indefinitely if the body
// close is slow for some reason.
if bodyClosed != nil {
<-bodyClosed
}
return err
}
for {
select {
case <-cs.respHeaderRecv:
return handleResponseHeaders()
case <-cs.abort:
select {
case <-cs.respHeaderRecv:
// If both cs.respHeaderRecv and cs.abort are signaling,
// pick respHeaderRecv. The server probably wrote the
// response and immediately reset the stream.
// golang.org/issue/49645
return handleResponseHeaders()
default:
waitDone()
return nil, cs.abortErr
}
case <-ctx.Done():
err := ctx.Err()
cs.abortStream(err)
return nil, cancelRequest(cs, err)
case <-cs.reqCancel:
cs.abortStream(errRequestCanceled)
return nil, cancelRequest(cs, errRequestCanceled)
}
}
}
// doRequest runs for the duration of the request lifetime.
//
// It sends the request and performs post-request cleanup (closing Request.Body, etc.).
func (cs *clientStream) doRequest(req *http.Request, streamf func(*clientStream)) {
err := cs.writeRequest(req, streamf)
cs.cleanupWriteRequest(err)
}
var errExtendedConnectNotSupported = errors.New("net/http: extended connect not supported by peer")
// writeRequest sends a request.
//
// It returns nil after the request is written, the response read,
// and the request stream is half-closed by the peer.
//
// It returns non-nil if the request ends otherwise.
// If the returned error is StreamError, the error Code may be used in resetting the stream.
func (cs *clientStream) writeRequest(req *http.Request, streamf func(*clientStream)) (err error) {
cc := cs.cc
ctx := cs.ctx
// wait for setting frames to be received, a server can change this value later,
// but we just wait for the first settings frame
var isExtendedConnect bool
if req.Method == "CONNECT" && req.Header.Get(":protocol") != "" {
isExtendedConnect = true
}
// Acquire the new-request lock by writing to reqHeaderMu.
// This lock guards the critical section covering allocating a new stream ID
// (requires mu) and creating the stream (requires wmu).
if cc.reqHeaderMu == nil {
panic("RoundTrip on uninitialized ClientConn") // for tests
}
if isExtendedConnect {
select {
case <-cs.reqCancel:
return errRequestCanceled
case <-ctx.Done():
return ctx.Err()
case <-cc.seenSettingsChan:
if !cc.extendedConnectAllowed {
return errExtendedConnectNotSupported
}
}
}
select {
case cc.reqHeaderMu <- struct{}{}:
case <-cs.reqCancel:
return errRequestCanceled
case <-ctx.Done():
return ctx.Err()
}
cc.mu.Lock()
if cc.idleTimer != nil {
cc.idleTimer.Stop()
}
cc.decrStreamReservationsLocked()
if err := cc.awaitOpenSlotForStreamLocked(cs); err != nil {
cc.mu.Unlock()
<-cc.reqHeaderMu
return err
}
cc.addStreamLocked(cs) // assigns stream ID
if isConnectionCloseRequest(req) {
cc.doNotReuse = true
}
cc.mu.Unlock()
if streamf != nil {
streamf(cs)
}
continueTimeout := cc.t.expectContinueTimeout()
if continueTimeout != 0 {
if !httpguts.HeaderValuesContainsToken(req.Header["Expect"], "100-continue") {
continueTimeout = 0
} else {
cs.on100 = make(chan struct{}, 1)
}
}
// Past this point (where we send request headers), it is possible for
// RoundTrip to return successfully. Since the RoundTrip contract permits
// the caller to "mutate or reuse" the Request after closing the Response's Body,
// we must take care when referencing the Request from here on.
err = cs.encodeAndWriteHeaders(req)
<-cc.reqHeaderMu
if err != nil {
return err
}
hasBody := cs.reqBodyContentLength != 0
if !hasBody {
cs.sentEndStream = true
} else {
if continueTimeout != 0 {
traceWait100Continue(cs.trace)
timer := time.NewTimer(continueTimeout)
select {
case <-timer.C:
err = nil
case <-cs.on100:
err = nil
case <-cs.abort:
err = cs.abortErr
case <-ctx.Done():
err = ctx.Err()
case <-cs.reqCancel:
err = errRequestCanceled
}
timer.Stop()
if err != nil {
traceWroteRequest(cs.trace, err)
return err
}
}
if err = cs.writeRequestBody(req); err != nil {
if err != errStopReqBodyWrite {
traceWroteRequest(cs.trace, err)
return err
}
} else {
cs.sentEndStream = true
}
}
traceWroteRequest(cs.trace, err)
var respHeaderTimer <-chan time.Time
var respHeaderRecv chan struct{}
if d := cc.responseHeaderTimeout(); d != 0 {
timer := time.NewTimer(d)
defer timer.Stop()
respHeaderTimer = timer.C
respHeaderRecv = cs.respHeaderRecv
}
// Wait until the peer half-closes its end of the stream,
// or until the request is aborted (via context, error, or otherwise),
// whichever comes first.
for {
select {
case <-cs.peerClosed:
return nil
case <-respHeaderTimer:
return errTimeout
case <-respHeaderRecv:
respHeaderRecv = nil
respHeaderTimer = nil // keep waiting for END_STREAM
case <-cs.abort:
return cs.abortErr
case <-ctx.Done():
return ctx.Err()
case <-cs.reqCancel:
return errRequestCanceled
}
}
}
func (cs *clientStream) encodeAndWriteHeaders(req *http.Request) error {
cc := cs.cc
ctx := cs.ctx
cc.wmu.Lock()
defer cc.wmu.Unlock()
// If the request was canceled while waiting for cc.mu, just quit.
select {
case <-cs.abort:
return cs.abortErr
case <-ctx.Done():
return ctx.Err()
case <-cs.reqCancel:
return errRequestCanceled
default:
}
// Encode headers.
//
// we send: HEADERS{1}, CONTINUATION{0,} + DATA{0,} (DATA is
// sent by writeRequestBody below, along with any Trailers,
// again in form HEADERS{1}, CONTINUATION{0,})
cc.hbuf.Reset()
res, err := encodeRequestHeaders(req, cs.requestedGzip, cc.peerMaxHeaderListSize, func(name, value string) {
cc.writeHeader(name, value)
})
if err != nil {
return fmt.Errorf("http2: %w", err)
}
hdrs := cc.hbuf.Bytes()
// Write the request.
endStream := !res.HasBody && !res.HasTrailers
cs.sentHeaders = true
err = cc.writeHeaders(cs.ID, endStream, int(cc.maxFrameSize), hdrs)
traceWroteHeaders(cs.trace)
return err
}
func encodeRequestHeaders(req *http.Request, addGzipHeader bool, peerMaxHeaderListSize uint64, headerf func(name, value string)) (httpcommon.EncodeHeadersResult, error) {
return httpcommon.EncodeHeaders(req.Context(), httpcommon.EncodeHeadersParam{
Request: httpcommon.Request{
Header: req.Header,
Trailer: req.Trailer,
URL: req.URL,
Host: req.Host,
Method: req.Method,
ActualContentLength: actualContentLength(req),
},
AddGzipHeader: addGzipHeader,
PeerMaxHeaderListSize: peerMaxHeaderListSize,
DefaultUserAgent: defaultUserAgent,
}, headerf)
}
// cleanupWriteRequest performs post-request tasks.
//
// If err (the result of writeRequest) is non-nil and the stream is not closed,
// cleanupWriteRequest will send a reset to the peer.
func (cs *clientStream) cleanupWriteRequest(err error) {
cc := cs.cc
if cs.ID == 0 {
// We were canceled before creating the stream, so return our reservation.
cc.decrStreamReservations()
}
// TODO: write h12Compare test showing whether
// Request.Body is closed by the Transport,
// and in multiple cases: server replies <=299 and >299
// while still writing request body
cc.mu.Lock()
mustCloseBody := false
if cs.reqBody != nil && cs.reqBodyClosed == nil {
mustCloseBody = true
cs.reqBodyClosed = make(chan struct{})
}
bodyClosed := cs.reqBodyClosed
closeOnIdle := cc.singleUse || cc.doNotReuse || cc.t.disableKeepAlives() || cc.goAway != nil
cc.mu.Unlock()
if mustCloseBody {
cs.reqBody.Close()
close(bodyClosed)
}
if bodyClosed != nil {
<-bodyClosed
}
if err != nil && cs.sentEndStream {
// If the connection is closed immediately after the response is read,
// we may be aborted before finishing up here. If the stream was closed
// cleanly on both sides, there is no error.
select {
case <-cs.peerClosed:
err = nil
default:
}
}
if err != nil {
cs.abortStream(err) // possibly redundant, but harmless
if cs.sentHeaders {
if se, ok := err.(StreamError); ok {
if se.Cause != errFromPeer {
cc.writeStreamReset(cs.ID, se.Code, false, err)
}
} else {
// We're cancelling an in-flight request.
//
// This could be due to the server becoming unresponsive.
// To avoid sending too many requests on a dead connection,
// we let the request continue to consume a concurrency slot
// until we can confirm the server is still responding.
// We do this by sending a PING frame along with the RST_STREAM
// (unless a ping is already in flight).
//
// For simplicity, we don't bother tracking the PING payload:
// We reset cc.pendingResets any time we receive a PING ACK.
//
// We skip this if the conn is going to be closed on idle,
// because it's short lived and will probably be closed before
// we get the ping response.
ping := false
if !closeOnIdle {
cc.mu.Lock()
// rstStreamPingsBlocked works around a gRPC behavior:
// see comment on the field for details.
if !cc.rstStreamPingsBlocked {
if cc.pendingResets == 0 {
ping = true
}
cc.pendingResets++
}
cc.mu.Unlock()
}
cc.writeStreamReset(cs.ID, ErrCodeCancel, ping, err)
}
}
cs.bufPipe.CloseWithError(err) // no-op if already closed
} else {
if cs.sentHeaders && !cs.sentEndStream {
cc.writeStreamReset(cs.ID, ErrCodeNo, false, nil)
}
cs.bufPipe.CloseWithError(errRequestCanceled)
}
if cs.ID != 0 {
cc.forgetStreamID(cs.ID)
}
cc.wmu.Lock()
werr := cc.werr
cc.wmu.Unlock()
if werr != nil {
cc.Close()
}
close(cs.donec)
}
// awaitOpenSlotForStreamLocked waits until len(streams) < maxConcurrentStreams.
// Must hold cc.mu.
func (cc *ClientConn) awaitOpenSlotForStreamLocked(cs *clientStream) error {
for {
if cc.closed && cc.nextStreamID == 1 && cc.streamsReserved == 0 {
// This is the very first request sent to this connection.
// Return a fatal error which aborts the retry loop.
return errClientConnNotEstablished
}
cc.lastActive = time.Now()
if cc.closed || !cc.canTakeNewRequestLocked() {
return errClientConnUnusable
}
cc.lastIdle = time.Time{}
if cc.currentRequestCountLocked() < int(cc.maxConcurrentStreams) {
return nil
}
cc.pendingRequests++
cc.cond.Wait()
cc.pendingRequests--
select {
case <-cs.abort:
return cs.abortErr
default:
}
}
}
// requires cc.wmu be held
func (cc *ClientConn) writeHeaders(streamID uint32, endStream bool, maxFrameSize int, hdrs []byte) error {
first := true // first frame written (HEADERS is first, then CONTINUATION)
for len(hdrs) > 0 && cc.werr == nil {
chunk := hdrs
if len(chunk) > maxFrameSize {
chunk = chunk[:maxFrameSize]
}
hdrs = hdrs[len(chunk):]
endHeaders := len(hdrs) == 0
if first {
cc.fr.WriteHeaders(HeadersFrameParam{
StreamID: streamID,
BlockFragment: chunk,
EndStream: endStream,
EndHeaders: endHeaders,
})
first = false
} else {
cc.fr.WriteContinuation(streamID, endHeaders, chunk)
}
}
cc.bw.Flush()
return cc.werr
}
// internal error values; they don't escape to callers
var (
// abort request body write; don't send cancel
errStopReqBodyWrite = errors.New("http2: aborting request body write")
// abort request body write, but send stream reset of cancel.
errStopReqBodyWriteAndCancel = errors.New("http2: canceling request")
errReqBodyTooLong = errors.New("http2: request body larger than specified content length")
)
// frameScratchBufferLen returns the length of a buffer to use for
// outgoing request bodies to read/write to/from.
//
// It returns max(1, min(peer's advertised max frame size,
// Request.ContentLength+1, 512KB)).
func (cs *clientStream) frameScratchBufferLen(maxFrameSize int) int {
const max = 512 << 10
n := int64(maxFrameSize)
if n > max {
n = max
}
if cl := cs.reqBodyContentLength; cl != -1 && cl+1 < n {
// Add an extra byte past the declared content-length to
// give the caller's Request.Body io.Reader a chance to
// give us more bytes than they declared, so we can catch it
// early.
n = cl + 1
}
if n < 1 {
return 1
}
return int(n) // doesn't truncate; max is 512K
}
// Seven bufPools manage different frame sizes. This helps to avoid scenarios where long-running
// streaming requests using small frame sizes occupy large buffers initially allocated for prior
// requests needing big buffers. The size ranges are as follows:
// {0 KB, 16 KB], {16 KB, 32 KB], {32 KB, 64 KB], {64 KB, 128 KB], {128 KB, 256 KB],
// {256 KB, 512 KB], {512 KB, infinity}
// In practice, the maximum scratch buffer size should not exceed 512 KB due to
// frameScratchBufferLen(maxFrameSize), thus the "infinity pool" should never be used.
// It exists mainly as a safety measure, for potential future increases in max buffer size.
var bufPools [7]sync.Pool // of *[]byte
func bufPoolIndex(size int) int {
if size <= 16384 {
return 0
}
size -= 1
bits := bits.Len(uint(size))
index := bits - 14
if index >= len(bufPools) {
return len(bufPools) - 1
}
return index
}
func (cs *clientStream) writeRequestBody(req *http.Request) (err error) {
cc := cs.cc
body := cs.reqBody
sentEnd := false // whether we sent the final DATA frame w/ END_STREAM
hasTrailers := req.Trailer != nil
remainLen := cs.reqBodyContentLength
hasContentLen := remainLen != -1
cc.mu.Lock()
maxFrameSize := int(cc.maxFrameSize)
cc.mu.Unlock()
// Scratch buffer for reading into & writing from.
scratchLen := cs.frameScratchBufferLen(maxFrameSize)
var buf []byte
index := bufPoolIndex(scratchLen)
if bp, ok := bufPools[index].Get().(*[]byte); ok && len(*bp) >= scratchLen {
defer bufPools[index].Put(bp)
buf = *bp
} else {
buf = make([]byte, scratchLen)
defer bufPools[index].Put(&buf)
}
var sawEOF bool
for !sawEOF {
n, err := body.Read(buf)
if hasContentLen {
remainLen -= int64(n)
if remainLen == 0 && err == nil {
// The request body's Content-Length was predeclared and
// we just finished reading it all, but the underlying io.Reader
// returned the final chunk with a nil error (which is one of
// the two valid things a Reader can do at EOF). Because we'd prefer
// to send the END_STREAM bit early, double-check that we're actually
// at EOF. Subsequent reads should return (0, EOF) at this point.
// If either value is different, we return an error in one of two ways below.
var scratch [1]byte
var n1 int
n1, err = body.Read(scratch[:])
remainLen -= int64(n1)
}
if remainLen < 0 {
err = errReqBodyTooLong
return err
}
}
if err != nil {
cc.mu.Lock()
bodyClosed := cs.reqBodyClosed != nil
cc.mu.Unlock()
switch {
case bodyClosed:
return errStopReqBodyWrite
case err == io.EOF:
sawEOF = true
err = nil
default:
return err
}
}
remain := buf[:n]
for len(remain) > 0 && err == nil {
var allowed int32
allowed, err = cs.awaitFlowControl(len(remain))
if err != nil {
return err
}
cc.wmu.Lock()
data := remain[:allowed]
remain = remain[allowed:]
sentEnd = sawEOF && len(remain) == 0 && !hasTrailers
err = cc.fr.WriteData(cs.ID, sentEnd, data)
if err == nil {
// TODO(bradfitz): this flush is for latency, not bandwidth.
// Most requests won't need this. Make this opt-in or
// opt-out? Use some heuristic on the body type? Nagel-like
// timers? Based on 'n'? Only last chunk of this for loop,
// unless flow control tokens are low? For now, always.
// If we change this, see comment below.
err = cc.bw.Flush()
}
cc.wmu.Unlock()
}
if err != nil {
return err
}
}
if sentEnd {
// Already sent END_STREAM (which implies we have no
// trailers) and flushed, because currently all
// WriteData frames above get a flush. So we're done.
return nil
}
// Since the RoundTrip contract permits the caller to "mutate or reuse"
// a request after the Response's Body is closed, verify that this hasn't
// happened before accessing the trailers.
cc.mu.Lock()
trailer := req.Trailer
err = cs.abortErr
cc.mu.Unlock()
if err != nil {
return err
}
cc.wmu.Lock()
defer cc.wmu.Unlock()
var trls []byte
if len(trailer) > 0 {
trls, err = cc.encodeTrailers(trailer)
if err != nil {
return err
}
}
// Two ways to send END_STREAM: either with trailers, or
// with an empty DATA frame.
if len(trls) > 0 {
err = cc.writeHeaders(cs.ID, true, maxFrameSize, trls)
} else {
err = cc.fr.WriteData(cs.ID, true, nil)
}
if ferr := cc.bw.Flush(); ferr != nil && err == nil {
err = ferr
}
return err
}
// awaitFlowControl waits for [1, min(maxBytes, cc.cs.maxFrameSize)] flow
// control tokens from the server.
// It returns either the non-zero number of tokens taken or an error
// if the stream is dead.
func (cs *clientStream) awaitFlowControl(maxBytes int) (taken int32, err error) {
cc := cs.cc
ctx := cs.ctx
cc.mu.Lock()
defer cc.mu.Unlock()
for {
if cc.closed {
return 0, errClientConnClosed
}
if cs.reqBodyClosed != nil {
return 0, errStopReqBodyWrite
}
select {
case <-cs.abort:
return 0, cs.abortErr
case <-ctx.Done():
return 0, ctx.Err()
case <-cs.reqCancel:
return 0, errRequestCanceled
default:
}
if a := cs.flow.available(); a > 0 {
take := a
if int(take) > maxBytes {
take = int32(maxBytes) // can't truncate int; take is int32
}
if take > int32(cc.maxFrameSize) {
take = int32(cc.maxFrameSize)
}
cs.flow.take(take)
return take, nil
}
cc.cond.Wait()
}
}
// requires cc.wmu be held.
func (cc *ClientConn) encodeTrailers(trailer http.Header) ([]byte, error) {
cc.hbuf.Reset()
hlSize := uint64(0)
for k, vv := range trailer {
for _, v := range vv {
hf := hpack.HeaderField{Name: k, Value: v}
hlSize += uint64(hf.Size())
}
}
if hlSize > cc.peerMaxHeaderListSize {
return nil, errRequestHeaderListSize
}
for k, vv := range trailer {
lowKey, ascii := httpcommon.LowerHeader(k)
if !ascii {
// Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header
// field names have to be ASCII characters (just as in HTTP/1.x).
continue
}
// Transfer-Encoding, etc.. have already been filtered at the
// start of RoundTrip
for _, v := range vv {
cc.writeHeader(lowKey, v)
}
}
return cc.hbuf.Bytes(), nil
}
func (cc *ClientConn) writeHeader(name, value string) {
if VerboseLogs {
log.Printf("http2: Transport encoding header %q = %q", name, value)
}
cc.henc.WriteField(hpack.HeaderField{Name: name, Value: value})
}
type resAndError struct {
_ incomparable
res *http.Response
err error
}
// requires cc.mu be held.
func (cc *ClientConn) addStreamLocked(cs *clientStream) {
cs.flow.add(int32(cc.initialWindowSize))
cs.flow.setConnFlow(&cc.flow)
cs.inflow.init(cc.initialStreamRecvWindowSize)
cs.ID = cc.nextStreamID
cc.nextStreamID += 2
cc.streams[cs.ID] = cs
if cs.ID == 0 {
panic("assigned stream ID 0")
}
}
func (cc *ClientConn) forgetStreamID(id uint32) {
cc.mu.Lock()
slen := len(cc.streams)
delete(cc.streams, id)
if len(cc.streams) != slen-1 {
panic("forgetting unknown stream id")
}
cc.lastActive = time.Now()
if len(cc.streams) == 0 && cc.idleTimer != nil {
cc.idleTimer.Reset(cc.idleTimeout)
cc.lastIdle = time.Now()
}
// Wake up writeRequestBody via clientStream.awaitFlowControl and
// wake up RoundTrip if there is a pending request.
cc.cond.Broadcast()
closeOnIdle := cc.singleUse || cc.doNotReuse || cc.t.disableKeepAlives() || cc.goAway != nil
if closeOnIdle && cc.streamsReserved == 0 && len(cc.streams) == 0 {
if VerboseLogs {
cc.vlogf("http2: Transport closing idle conn %p (forSingleUse=%v, maxStream=%v)", cc, cc.singleUse, cc.nextStreamID-2)
}
cc.closed = true
defer cc.closeConn()
}
cc.mu.Unlock()
}
// clientConnReadLoop is the state owned by the clientConn's frame-reading readLoop.
type clientConnReadLoop struct {
_ incomparable
cc *ClientConn
}
// readLoop runs in its own goroutine and reads and dispatches frames.
func (cc *ClientConn) readLoop() {
rl := &clientConnReadLoop{cc: cc}
defer rl.cleanup()
cc.readerErr = rl.run()
if ce, ok := cc.readerErr.(ConnectionError); ok {
cc.wmu.Lock()
cc.fr.WriteGoAway(0, ErrCode(ce), nil)
cc.wmu.Unlock()
}
}
// GoAwayError is returned by the Transport when the server closes the
// TCP connection after sending a GOAWAY frame.
type GoAwayError struct {
LastStreamID uint32
ErrCode ErrCode
DebugData string
}
func (e GoAwayError) Error() string {
return fmt.Sprintf("http2: server sent GOAWAY and closed the connection; LastStreamID=%v, ErrCode=%v, debug=%q",
e.LastStreamID, e.ErrCode, e.DebugData)
}
func isEOFOrNetReadError(err error) bool {
if err == io.EOF {
return true
}
ne, ok := err.(*net.OpError)
return ok && ne.Op == "read"
}
func (rl *clientConnReadLoop) cleanup() {
cc := rl.cc
defer cc.closeConn()
defer close(cc.readerDone)
if cc.idleTimer != nil {
cc.idleTimer.Stop()
}
// Close any response bodies if the server closes prematurely.
// TODO: also do this if we've written the headers but not
// gotten a response yet.
err := cc.readerErr
cc.mu.Lock()
if cc.goAway != nil && isEOFOrNetReadError(err) {
err = GoAwayError{
LastStreamID: cc.goAway.LastStreamID,
ErrCode: cc.goAway.ErrCode,
DebugData: cc.goAwayDebug,
}
} else if err == io.EOF {
err = io.ErrUnexpectedEOF
}
cc.closed = true
// If the connection has never been used, and has been open for only a short time,
// leave it in the connection pool for a little while.
//
// This avoids a situation where new connections are constantly created,
// added to the pool, fail, and are removed from the pool, without any error
// being surfaced to the user.
unusedWaitTime := 5 * time.Second
if cc.idleTimeout > 0 && unusedWaitTime > cc.idleTimeout {
unusedWaitTime = cc.idleTimeout
}
idleTime := time.Now().Sub(cc.lastActive)
if atomic.LoadUint32(&cc.atomicReused) == 0 && idleTime < unusedWaitTime && !cc.closedOnIdle {
cc.idleTimer = time.AfterFunc(unusedWaitTime-idleTime, func() {
cc.t.connPool().MarkDead(cc)
})
} else {
cc.mu.Unlock() // avoid any deadlocks in MarkDead
cc.t.connPool().MarkDead(cc)
cc.mu.Lock()
}
for _, cs := range cc.streams {
select {
case <-cs.peerClosed:
// The server closed the stream before closing the conn,
// so no need to interrupt it.
default:
cs.abortStreamLocked(err)
}
}
cc.cond.Broadcast()
cc.mu.Unlock()
if !cc.seenSettings {
// If we have a pending request that wants extended CONNECT,
// let it continue and fail with the connection error.
cc.extendedConnectAllowed = true
close(cc.seenSettingsChan)
}
}
// countReadFrameError calls Transport.CountError with a string
// representing err.
func (cc *ClientConn) countReadFrameError(err error) {
f := cc.t.CountError
if f == nil || err == nil {
return
}
if ce, ok := err.(ConnectionError); ok {
errCode := ErrCode(ce)
f(fmt.Sprintf("read_frame_conn_error_%s", errCode.stringToken()))
return
}
if errors.Is(err, io.EOF) {
f("read_frame_eof")
return
}
if errors.Is(err, io.ErrUnexpectedEOF) {
f("read_frame_unexpected_eof")
return
}
if errors.Is(err, ErrFrameTooLarge) {
f("read_frame_too_large")
return
}
f("read_frame_other")
}
func (rl *clientConnReadLoop) run() error {
cc := rl.cc
gotSettings := false
readIdleTimeout := cc.readIdleTimeout
var t *time.Timer
if readIdleTimeout != 0 {
t = time.AfterFunc(readIdleTimeout, cc.healthCheck)
}
for {
f, err := cc.fr.ReadFrame()
if t != nil {
t.Reset(readIdleTimeout)
}
if err != nil {
cc.vlogf("http2: Transport readFrame error on conn %p: (%T) %v", cc, err, err)
}
if se, ok := err.(StreamError); ok {
if cs := rl.streamByID(se.StreamID, notHeaderOrDataFrame); cs != nil {
if se.Cause == nil {
se.Cause = cc.fr.errDetail
}
rl.endStreamError(cs, se)
}
continue
} else if err != nil {
cc.countReadFrameError(err)
return err
}
if VerboseLogs {
cc.vlogf("http2: Transport received %s", summarizeFrame(f))
}
if !gotSettings {
if _, ok := f.(*SettingsFrame); !ok {
cc.logf("protocol error: received %T before a SETTINGS frame", f)
return ConnectionError(ErrCodeProtocol)
}
gotSettings = true
}
switch f := f.(type) {
case *MetaHeadersFrame:
err = rl.processHeaders(f)
case *DataFrame:
err = rl.processData(f)
case *GoAwayFrame:
err = rl.processGoAway(f)
case *RSTStreamFrame:
err = rl.processResetStream(f)
case *SettingsFrame:
err = rl.processSettings(f)
case *PushPromiseFrame:
err = rl.processPushPromise(f)
case *WindowUpdateFrame:
err = rl.processWindowUpdate(f)
case *PingFrame:
err = rl.processPing(f)
default:
cc.logf("Transport: unhandled response frame type %T", f)
}
if err != nil {
if VerboseLogs {
cc.vlogf("http2: Transport conn %p received error from processing frame %v: %v", cc, summarizeFrame(f), err)
}
return err
}
}
}
func (rl *clientConnReadLoop) processHeaders(f *MetaHeadersFrame) error {
cs := rl.streamByID(f.StreamID, headerOrDataFrame)
if cs == nil {
// We'd get here if we canceled a request while the
// server had its response still in flight. So if this
// was just something we canceled, ignore it.
return nil
}
if cs.readClosed {
rl.endStreamError(cs, StreamError{
StreamID: f.StreamID,
Code: ErrCodeProtocol,
Cause: errors.New("protocol error: headers after END_STREAM"),
})
return nil
}
if !cs.firstByte {
if cs.trace != nil {
// TODO(bradfitz): move first response byte earlier,
// when we first read the 9 byte header, not waiting
// until all the HEADERS+CONTINUATION frames have been
// merged. This works for now.
traceFirstResponseByte(cs.trace)
}
cs.firstByte = true
}
if !cs.pastHeaders {
cs.pastHeaders = true
} else {
return rl.processTrailers(cs, f)
}
res, err := rl.handleResponse(cs, f)
if err != nil {
if _, ok := err.(ConnectionError); ok {
return err
}
// Any other error type is a stream error.
rl.endStreamError(cs, StreamError{
StreamID: f.StreamID,
Code: ErrCodeProtocol,
Cause: err,
})
return nil // return nil from process* funcs to keep conn alive
}
if res == nil {
// (nil, nil) special case. See handleResponse docs.
return nil
}
cs.resTrailer = &res.Trailer
cs.res = res
close(cs.respHeaderRecv)
if f.StreamEnded() {
rl.endStream(cs)
}
return nil
}
// may return error types nil, or ConnectionError. Any other error value
// is a StreamError of type ErrCodeProtocol. The returned error in that case
// is the detail.
//
// As a special case, handleResponse may return (nil, nil) to skip the
// frame (currently only used for 1xx responses).
func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFrame) (*http.Response, error) {
if f.Truncated {
return nil, errResponseHeaderListSize
}
status := f.PseudoValue("status")
if status == "" {
return nil, errors.New("malformed response from server: missing status pseudo header")
}
statusCode, err := strconv.Atoi(status)
if err != nil {
return nil, errors.New("malformed response from server: malformed non-numeric status pseudo header")
}
regularFields := f.RegularFields()
strs := make([]string, len(regularFields))
header := make(http.Header, len(regularFields))
res := &http.Response{
Proto: "HTTP/2.0",
ProtoMajor: 2,
Header: header,
StatusCode: statusCode,
Status: status + " " + http.StatusText(statusCode),
}
for _, hf := range regularFields {
key := httpcommon.CanonicalHeader(hf.Name)
if key == "Trailer" {
t := res.Trailer
if t == nil {
t = make(http.Header)
res.Trailer = t
}
foreachHeaderElement(hf.Value, func(v string) {
t[httpcommon.CanonicalHeader(v)] = nil
})
} else {
vv := header[key]
if vv == nil && len(strs) > 0 {
// More than likely this will be a single-element key.
// Most headers aren't multi-valued.
// Set the capacity on strs[0] to 1, so any future append
// won't extend the slice into the other strings.
vv, strs = strs[:1:1], strs[1:]
vv[0] = hf.Value
header[key] = vv
} else {
header[key] = append(vv, hf.Value)
}
}
}
if statusCode >= 100 && statusCode <= 199 {
if f.StreamEnded() {
return nil, errors.New("1xx informational response with END_STREAM flag")
}
if fn := cs.get1xxTraceFunc(); fn != nil {
// If the 1xx response is being delivered to the user,
// then they're responsible for limiting the number
// of responses.
if err := fn(statusCode, textproto.MIMEHeader(header)); err != nil {
return nil, err
}
} else {
// If the user didn't examine the 1xx response, then we
// limit the size of all 1xx headers.
//
// This differs a bit from the HTTP/1 implementation, which
// limits the size of all 1xx headers plus the final response.
// Use the larger limit of MaxHeaderListSize and
// net/http.Transport.MaxResponseHeaderBytes.
limit := int64(cs.cc.t.maxHeaderListSize())
if t1 := cs.cc.t.t1; t1 != nil && t1.MaxResponseHeaderBytes > limit {
limit = t1.MaxResponseHeaderBytes
}
for _, h := range f.Fields {
cs.totalHeaderSize += int64(h.Size())
}
if cs.totalHeaderSize > limit {
if VerboseLogs {
log.Printf("http2: 1xx informational responses too large")
}
return nil, errors.New("header list too large")
}
}
if statusCode == 100 {
traceGot100Continue(cs.trace)
select {
case cs.on100 <- struct{}{}:
default:
}
}
cs.pastHeaders = false // do it all again
return nil, nil
}
res.ContentLength = -1
if clens := res.Header["Content-Length"]; len(clens) == 1 {
if cl, err := strconv.ParseUint(clens[0], 10, 63); err == nil {
res.ContentLength = int64(cl)
} else {
// TODO: care? unlike http/1, it won't mess up our framing, so it's
// more safe smuggling-wise to ignore.
}
} else if len(clens) > 1 {
// TODO: care? unlike http/1, it won't mess up our framing, so it's
// more safe smuggling-wise to ignore.
} else if f.StreamEnded() && !cs.isHead {
res.ContentLength = 0
}
if cs.isHead {
res.Body = noBody
return res, nil
}
if f.StreamEnded() {
if res.ContentLength > 0 {
res.Body = missingBody{}
} else {
res.Body = noBody
}
return res, nil
}
cs.bufPipe.setBuffer(&dataBuffer{expected: res.ContentLength})
cs.bytesRemain = res.ContentLength
res.Body = transportResponseBody{cs}
if cs.requestedGzip && asciiEqualFold(res.Header.Get("Content-Encoding"), "gzip") {
res.Header.Del("Content-Encoding")
res.Header.Del("Content-Length")
res.ContentLength = -1
res.Body = &gzipReader{body: res.Body}
res.Uncompressed = true
}
return res, nil
}
func (rl *clientConnReadLoop) processTrailers(cs *clientStream, f *MetaHeadersFrame) error {
if cs.pastTrailers {
// Too many HEADERS frames for this stream.
return ConnectionError(ErrCodeProtocol)
}
cs.pastTrailers = true
if !f.StreamEnded() {
// We expect that any headers for trailers also
// has END_STREAM.
return ConnectionError(ErrCodeProtocol)
}
if len(f.PseudoFields()) > 0 {
// No pseudo header fields are defined for trailers.
// TODO: ConnectionError might be overly harsh? Check.
return ConnectionError(ErrCodeProtocol)
}
trailer := make(http.Header)
for _, hf := range f.RegularFields() {
key := httpcommon.CanonicalHeader(hf.Name)
trailer[key] = append(trailer[key], hf.Value)
}
cs.trailer = trailer
rl.endStream(cs)
return nil
}
// transportResponseBody is the concrete type of Transport.RoundTrip's
// Response.Body. It is an io.ReadCloser.
type transportResponseBody struct {
cs *clientStream
}
func (b transportResponseBody) Read(p []byte) (n int, err error) {
cs := b.cs
cc := cs.cc
if cs.readErr != nil {
return 0, cs.readErr
}
n, err = b.cs.bufPipe.Read(p)
if cs.bytesRemain != -1 {
if int64(n) > cs.bytesRemain {
n = int(cs.bytesRemain)
if err == nil {
err = errors.New("net/http: server replied with more than declared Content-Length; truncated")
cs.abortStream(err)
}
cs.readErr = err
return int(cs.bytesRemain), err
}
cs.bytesRemain -= int64(n)
if err == io.EOF && cs.bytesRemain > 0 {
err = io.ErrUnexpectedEOF
cs.readErr = err
return n, err
}
}
if n == 0 {
// No flow control tokens to send back.
return
}
cc.mu.Lock()
connAdd := cc.inflow.add(n)
var streamAdd int32
if err == nil { // No need to refresh if the stream is over or failed.
streamAdd = cs.inflow.add(n)
}
cc.mu.Unlock()
if connAdd != 0 || streamAdd != 0 {
cc.wmu.Lock()
defer cc.wmu.Unlock()
if connAdd != 0 {
cc.fr.WriteWindowUpdate(0, mustUint31(connAdd))
}
if streamAdd != 0 {
cc.fr.WriteWindowUpdate(cs.ID, mustUint31(streamAdd))
}
cc.bw.Flush()
}
return
}
var errClosedResponseBody = errors.New("http2: response body closed")
func (b transportResponseBody) Close() error {
cs := b.cs
cc := cs.cc
cs.bufPipe.BreakWithError(errClosedResponseBody)
cs.abortStream(errClosedResponseBody)
unread := cs.bufPipe.Len()
if unread > 0 {
cc.mu.Lock()
// Return connection-level flow control.
connAdd := cc.inflow.add(unread)
cc.mu.Unlock()
// TODO(dneil): Acquiring this mutex can block indefinitely.
// Move flow control return to a goroutine?
cc.wmu.Lock()
// Return connection-level flow control.
if connAdd > 0 {
cc.fr.WriteWindowUpdate(0, uint32(connAdd))
}
cc.bw.Flush()
cc.wmu.Unlock()
}
select {
case <-cs.donec:
case <-cs.ctx.Done():
// See golang/go#49366: The net/http package can cancel the
// request context after the response body is fully read.
// Don't treat this as an error.
return nil
case <-cs.reqCancel:
return errRequestCanceled
}
return nil
}
func (rl *clientConnReadLoop) processData(f *DataFrame) error {
cc := rl.cc
cs := rl.streamByID(f.StreamID, headerOrDataFrame)
data := f.Data()
if cs == nil {
cc.mu.Lock()
neverSent := cc.nextStreamID
cc.mu.Unlock()
if f.StreamID >= neverSent {
// We never asked for this.
cc.logf("http2: Transport received unsolicited DATA frame; closing connection")
return ConnectionError(ErrCodeProtocol)
}
// We probably did ask for this, but canceled. Just ignore it.
// TODO: be stricter here? only silently ignore things which
// we canceled, but not things which were closed normally
// by the peer? Tough without accumulating too much state.
// But at least return their flow control:
if f.Length > 0 {
cc.mu.Lock()
ok := cc.inflow.take(f.Length)
connAdd := cc.inflow.add(int(f.Length))
cc.mu.Unlock()
if !ok {
return ConnectionError(ErrCodeFlowControl)
}
if connAdd > 0 {
cc.wmu.Lock()
cc.fr.WriteWindowUpdate(0, uint32(connAdd))
cc.bw.Flush()
cc.wmu.Unlock()
}
}
return nil
}
if cs.readClosed {
cc.logf("protocol error: received DATA after END_STREAM")
rl.endStreamError(cs, StreamError{
StreamID: f.StreamID,
Code: ErrCodeProtocol,
})
return nil
}
if !cs.pastHeaders {
cc.logf("protocol error: received DATA before a HEADERS frame")
rl.endStreamError(cs, StreamError{
StreamID: f.StreamID,
Code: ErrCodeProtocol,
})
return nil
}
if f.Length > 0 {
if cs.isHead && len(data) > 0 {
cc.logf("protocol error: received DATA on a HEAD request")
rl.endStreamError(cs, StreamError{
StreamID: f.StreamID,
Code: ErrCodeProtocol,
})
return nil
}
// Check connection-level flow control.
cc.mu.Lock()
if !takeInflows(&cc.inflow, &cs.inflow, f.Length) {
cc.mu.Unlock()
return ConnectionError(ErrCodeFlowControl)
}
// Return any padded flow control now, since we won't
// refund it later on body reads.
var refund int
if pad := int(f.Length) - len(data); pad > 0 {
refund += pad
}
didReset := false
var err error
if len(data) > 0 {
if _, err = cs.bufPipe.Write(data); err != nil {
// Return len(data) now if the stream is already closed,
// since data will never be read.
didReset = true
refund += len(data)
}
}
sendConn := cc.inflow.add(refund)
var sendStream int32
if !didReset {
sendStream = cs.inflow.add(refund)
}
cc.mu.Unlock()
if sendConn > 0 || sendStream > 0 {
cc.wmu.Lock()
if sendConn > 0 {
cc.fr.WriteWindowUpdate(0, uint32(sendConn))
}
if sendStream > 0 {
cc.fr.WriteWindowUpdate(cs.ID, uint32(sendStream))
}
cc.bw.Flush()
cc.wmu.Unlock()
}
if err != nil {
rl.endStreamError(cs, err)
return nil
}
}
if f.StreamEnded() {
rl.endStream(cs)
}
return nil
}
func (rl *clientConnReadLoop) endStream(cs *clientStream) {
// TODO: check that any declared content-length matches, like
// server.go's (*stream).endStream method.
if !cs.readClosed {
cs.readClosed = true
// Close cs.bufPipe and cs.peerClosed with cc.mu held to avoid a
// race condition: The caller can read io.EOF from Response.Body
// and close the body before we close cs.peerClosed, causing
// cleanupWriteRequest to send a RST_STREAM.
rl.cc.mu.Lock()
defer rl.cc.mu.Unlock()
cs.bufPipe.closeWithErrorAndCode(io.EOF, cs.copyTrailers)
close(cs.peerClosed)
}
}
func (rl *clientConnReadLoop) endStreamError(cs *clientStream, err error) {
cs.readAborted = true
cs.abortStream(err)
}
// Constants passed to streamByID for documentation purposes.
const (
headerOrDataFrame = true
notHeaderOrDataFrame = false
)
// streamByID returns the stream with the given id, or nil if no stream has that id.
// If headerOrData is true, it clears rst.StreamPingsBlocked.
func (rl *clientConnReadLoop) streamByID(id uint32, headerOrData bool) *clientStream {
rl.cc.mu.Lock()
defer rl.cc.mu.Unlock()
if headerOrData {
// Work around an unfortunate gRPC behavior.
// See comment on ClientConn.rstStreamPingsBlocked for details.
rl.cc.rstStreamPingsBlocked = false
}
cs := rl.cc.streams[id]
if cs != nil && !cs.readAborted {
return cs
}
return nil
}
func (cs *clientStream) copyTrailers() {
for k, vv := range cs.trailer {
t := cs.resTrailer
if *t == nil {
*t = make(http.Header)
}
(*t)[k] = vv
}
}
func (rl *clientConnReadLoop) processGoAway(f *GoAwayFrame) error {
cc := rl.cc
cc.t.connPool().MarkDead(cc)
if f.ErrCode != 0 {
// TODO: deal with GOAWAY more. particularly the error code
cc.vlogf("transport got GOAWAY with error code = %v", f.ErrCode)
if fn := cc.t.CountError; fn != nil {
fn("recv_goaway_" + f.ErrCode.stringToken())
}
}
cc.setGoAway(f)
return nil
}
func (rl *clientConnReadLoop) processSettings(f *SettingsFrame) error {
cc := rl.cc
// Locking both mu and wmu here allows frame encoding to read settings with only wmu held.
// Acquiring wmu when f.IsAck() is unnecessary, but convenient and mostly harmless.
cc.wmu.Lock()
defer cc.wmu.Unlock()
if err := rl.processSettingsNoWrite(f); err != nil {
return err
}
if !f.IsAck() {
cc.fr.WriteSettingsAck()
cc.bw.Flush()
}
return nil
}
func (rl *clientConnReadLoop) processSettingsNoWrite(f *SettingsFrame) error {
cc := rl.cc
cc.mu.Lock()
defer cc.mu.Unlock()
if f.IsAck() {
if cc.wantSettingsAck {
cc.wantSettingsAck = false
return nil
}
return ConnectionError(ErrCodeProtocol)
}
var seenMaxConcurrentStreams bool
err := f.ForeachSetting(func(s Setting) error {
switch s.ID {
case SettingMaxFrameSize:
cc.maxFrameSize = s.Val
case SettingMaxConcurrentStreams:
cc.maxConcurrentStreams = s.Val
seenMaxConcurrentStreams = true
case SettingMaxHeaderListSize:
cc.peerMaxHeaderListSize = uint64(s.Val)
case SettingInitialWindowSize:
// Values above the maximum flow-control
// window size of 2^31-1 MUST be treated as a
// connection error (Section 5.4.1) of type
// FLOW_CONTROL_ERROR.
if s.Val > math.MaxInt32 {
return ConnectionError(ErrCodeFlowControl)
}
// Adjust flow control of currently-open
// frames by the difference of the old initial
// window size and this one.
delta := int32(s.Val) - int32(cc.initialWindowSize)
for _, cs := range cc.streams {
cs.flow.add(delta)
}
cc.cond.Broadcast()
cc.initialWindowSize = s.Val
case SettingHeaderTableSize:
cc.henc.SetMaxDynamicTableSize(s.Val)
cc.peerMaxHeaderTableSize = s.Val
case SettingEnableConnectProtocol:
if err := s.Valid(); err != nil {
return err
}
// If the peer wants to send us SETTINGS_ENABLE_CONNECT_PROTOCOL,
// we require that it do so in the first SETTINGS frame.
//
// When we attempt to use extended CONNECT, we wait for the first
// SETTINGS frame to see if the server supports it. If we let the
// server enable the feature with a later SETTINGS frame, then
// users will see inconsistent results depending on whether we've
// seen that frame or not.
if !cc.seenSettings {
cc.extendedConnectAllowed = s.Val == 1
}
default:
cc.vlogf("Unhandled Setting: %v", s)
}
return nil
})
if err != nil {
return err
}
if !cc.seenSettings {
if !seenMaxConcurrentStreams {
// This was the servers initial SETTINGS frame and it
// didn't contain a MAX_CONCURRENT_STREAMS field so
// increase the number of concurrent streams this
// connection can establish to our default.
cc.maxConcurrentStreams = defaultMaxConcurrentStreams
}
close(cc.seenSettingsChan)
cc.seenSettings = true
}
return nil
}
func (rl *clientConnReadLoop) processWindowUpdate(f *WindowUpdateFrame) error {
cc := rl.cc
cs := rl.streamByID(f.StreamID, notHeaderOrDataFrame)
if f.StreamID != 0 && cs == nil {
return nil
}
cc.mu.Lock()
defer cc.mu.Unlock()
fl := &cc.flow
if cs != nil {
fl = &cs.flow
}
if !fl.add(int32(f.Increment)) {
// For stream, the sender sends RST_STREAM with an error code of FLOW_CONTROL_ERROR
if cs != nil {
rl.endStreamError(cs, StreamError{
StreamID: f.StreamID,
Code: ErrCodeFlowControl,
})
return nil
}
return ConnectionError(ErrCodeFlowControl)
}
cc.cond.Broadcast()
return nil
}
func (rl *clientConnReadLoop) processResetStream(f *RSTStreamFrame) error {
cs := rl.streamByID(f.StreamID, notHeaderOrDataFrame)
if cs == nil {
// TODO: return error if server tries to RST_STREAM an idle stream
return nil
}
serr := streamError(cs.ID, f.ErrCode)
serr.Cause = errFromPeer
if f.ErrCode == ErrCodeProtocol {
rl.cc.SetDoNotReuse()
}
if fn := cs.cc.t.CountError; fn != nil {
fn("recv_rststream_" + f.ErrCode.stringToken())
}
cs.abortStream(serr)
cs.bufPipe.CloseWithError(serr)
return nil
}
// Ping sends a PING frame to the server and waits for the ack.
func (cc *ClientConn) Ping(ctx context.Context) error {
c := make(chan struct{})
// Generate a random payload
var p [8]byte
for {
if _, err := rand.Read(p[:]); err != nil {
return err
}
cc.mu.Lock()
// check for dup before insert
if _, found := cc.pings[p]; !found {
cc.pings[p] = c
cc.mu.Unlock()
break
}
cc.mu.Unlock()
}
var pingError error
errc := make(chan struct{})
go func() {
cc.wmu.Lock()
defer cc.wmu.Unlock()
if pingError = cc.fr.WritePing(false, p); pingError != nil {
close(errc)
return
}
if pingError = cc.bw.Flush(); pingError != nil {
close(errc)
return
}
}()
select {
case <-c:
return nil
case <-errc:
return pingError
case <-ctx.Done():
return ctx.Err()
case <-cc.readerDone:
// connection closed
return cc.readerErr
}
}
func (rl *clientConnReadLoop) processPing(f *PingFrame) error {
if f.IsAck() {
cc := rl.cc
cc.mu.Lock()
defer cc.mu.Unlock()
// If ack, notify listener if any
if c, ok := cc.pings[f.Data]; ok {
close(c)
delete(cc.pings, f.Data)
}
if cc.pendingResets > 0 {
// See clientStream.cleanupWriteRequest.
cc.pendingResets = 0
cc.rstStreamPingsBlocked = true
cc.cond.Broadcast()
}
return nil
}
cc := rl.cc
cc.wmu.Lock()
defer cc.wmu.Unlock()
if err := cc.fr.WritePing(true, f.Data); err != nil {
return err
}
return cc.bw.Flush()
}
func (rl *clientConnReadLoop) processPushPromise(f *PushPromiseFrame) error {
// We told the peer we don't want them.
// Spec says:
// "PUSH_PROMISE MUST NOT be sent if the SETTINGS_ENABLE_PUSH
// setting of the peer endpoint is set to 0. An endpoint that
// has set this setting and has received acknowledgement MUST
// treat the receipt of a PUSH_PROMISE frame as a connection
// error (Section 5.4.1) of type PROTOCOL_ERROR."
return ConnectionError(ErrCodeProtocol)
}
// writeStreamReset sends a RST_STREAM frame.
// When ping is true, it also sends a PING frame with a random payload.
func (cc *ClientConn) writeStreamReset(streamID uint32, code ErrCode, ping bool, err error) {
// TODO: map err to more interesting error codes, once the
// HTTP community comes up with some. But currently for
// RST_STREAM there's no equivalent to GOAWAY frame's debug
// data, and the error codes are all pretty vague ("cancel").
cc.wmu.Lock()
cc.fr.WriteRSTStream(streamID, code)
if ping {
var payload [8]byte
rand.Read(payload[:])
cc.fr.WritePing(false, payload)
}
cc.bw.Flush()
cc.wmu.Unlock()
}
var (
errResponseHeaderListSize = errors.New("http2: response header list larger than advertised limit")
errRequestHeaderListSize = httpcommon.ErrRequestHeaderListSize
)
func (cc *ClientConn) logf(format string, args ...interface{}) {
cc.t.logf(format, args...)
}
func (cc *ClientConn) vlogf(format string, args ...interface{}) {
cc.t.vlogf(format, args...)
}
func (t *Transport) vlogf(format string, args ...interface{}) {
if VerboseLogs {
t.logf(format, args...)
}
}
func (t *Transport) logf(format string, args ...interface{}) {
log.Printf(format, args...)
}
var noBody io.ReadCloser = noBodyReader{}
type noBodyReader struct{}
func (noBodyReader) Close() error { return nil }
func (noBodyReader) Read([]byte) (int, error) { return 0, io.EOF }
type missingBody struct{}
func (missingBody) Close() error { return nil }
func (missingBody) Read([]byte) (int, error) { return 0, io.ErrUnexpectedEOF }
func strSliceContains(ss []string, s string) bool {
for _, v := range ss {
if v == s {
return true
}
}
return false
}
type erringRoundTripper struct{ err error }
func (rt erringRoundTripper) RoundTripErr() error { return rt.err }
func (rt erringRoundTripper) RoundTrip(*http.Request) (*http.Response, error) { return nil, rt.err }
var errConcurrentReadOnResBody = errors.New("http2: concurrent read on response body")
// gzipReader wraps a response body so it can lazily
// get gzip.Reader from the pool on the first call to Read.
// After Close is called it puts gzip.Reader to the pool immediately
// if there is no Read in progress or later when Read completes.
type gzipReader struct {
_ incomparable
body io.ReadCloser // underlying Response.Body
mu sync.Mutex // guards zr and zerr
zr *gzip.Reader // stores gzip reader from the pool between reads
zerr error // sticky gzip reader init error or sentinel value to detect concurrent read and read after close
}
type eofReader struct{}
func (eofReader) Read([]byte) (int, error) { return 0, io.EOF }
func (eofReader) ReadByte() (byte, error) { return 0, io.EOF }
var gzipPool = sync.Pool{New: func() any { return new(gzip.Reader) }}
// gzipPoolGet gets a gzip.Reader from the pool and resets it to read from r.
func gzipPoolGet(r io.Reader) (*gzip.Reader, error) {
zr := gzipPool.Get().(*gzip.Reader)
if err := zr.Reset(r); err != nil {
gzipPoolPut(zr)
return nil, err
}
return zr, nil
}
// gzipPoolPut puts a gzip.Reader back into the pool.
func gzipPoolPut(zr *gzip.Reader) {
// Reset will allocate bufio.Reader if we pass it anything
// other than a flate.Reader, so ensure that it's getting one.
var r flate.Reader = eofReader{}
zr.Reset(r)
gzipPool.Put(zr)
}
// acquire returns a gzip.Reader for reading response body.
// The reader must be released after use.
func (gz *gzipReader) acquire() (*gzip.Reader, error) {
gz.mu.Lock()
defer gz.mu.Unlock()
if gz.zerr != nil {
return nil, gz.zerr
}
if gz.zr == nil {
gz.zr, gz.zerr = gzipPoolGet(gz.body)
if gz.zerr != nil {
return nil, gz.zerr
}
}
ret := gz.zr
gz.zr, gz.zerr = nil, errConcurrentReadOnResBody
return ret, nil
}
// release returns the gzip.Reader to the pool if Close was called during Read.
func (gz *gzipReader) release(zr *gzip.Reader) {
gz.mu.Lock()
defer gz.mu.Unlock()
if gz.zerr == errConcurrentReadOnResBody {
gz.zr, gz.zerr = zr, nil
} else { // fs.ErrClosed
gzipPoolPut(zr)
}
}
// close returns the gzip.Reader to the pool immediately or
// signals release to do so after Read completes.
func (gz *gzipReader) close() {
gz.mu.Lock()
defer gz.mu.Unlock()
if gz.zerr == nil && gz.zr != nil {
gzipPoolPut(gz.zr)
gz.zr = nil
}
gz.zerr = fs.ErrClosed
}
func (gz *gzipReader) Read(p []byte) (n int, err error) {
zr, err := gz.acquire()
if err != nil {
return 0, err
}
defer gz.release(zr)
return zr.Read(p)
}
func (gz *gzipReader) Close() error {
gz.close()
return gz.body.Close()
}
type errorReader struct{ err error }
func (r errorReader) Read(p []byte) (int, error) { return 0, r.err }
// isConnectionCloseRequest reports whether req should use its own
// connection for a single request and then close the connection.
func isConnectionCloseRequest(req *http.Request) bool {
return req.Close || httpguts.HeaderValuesContainsToken(req.Header["Connection"], "close")
}
// registerHTTPSProtocol calls Transport.RegisterProtocol but
// converting panics into errors.
func registerHTTPSProtocol(t *http.Transport, rt noDialH2RoundTripper) (err error) {
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("%v", e)
}
}()
t.RegisterProtocol("https", rt)
return nil
}
// noDialH2RoundTripper is a RoundTripper which only tries to complete the request
// if there's already has a cached connection to the host.
// (The field is exported so it can be accessed via reflect from net/http; tested
// by TestNoDialH2RoundTripperType)
type noDialH2RoundTripper struct{ *Transport }
func (rt noDialH2RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
res, err := rt.Transport.RoundTrip(req)
if isNoCachedConnError(err) {
return nil, http.ErrSkipAltProtocol
}
return res, err
}
func (t *Transport) idleConnTimeout() time.Duration {
// to keep things backwards compatible, we use non-zero values of
// IdleConnTimeout, followed by using the IdleConnTimeout on the underlying
// http1 transport, followed by 0
if t.IdleConnTimeout != 0 {
return t.IdleConnTimeout
}
if t.t1 != nil {
return t.t1.IdleConnTimeout
}
return 0
}
func traceGetConn(req *http.Request, hostPort string) {
trace := httptrace.ContextClientTrace(req.Context())
if trace == nil || trace.GetConn == nil {
return
}
trace.GetConn(hostPort)
}
func traceGotConn(req *http.Request, cc *ClientConn, reused bool) {
trace := httptrace.ContextClientTrace(req.Context())
if trace == nil || trace.GotConn == nil {
return
}
ci := httptrace.GotConnInfo{Conn: cc.tconn}
ci.Reused = reused
cc.mu.Lock()
ci.WasIdle = len(cc.streams) == 0 && reused
if ci.WasIdle && !cc.lastActive.IsZero() {
ci.IdleTime = time.Since(cc.lastActive)
}
cc.mu.Unlock()
trace.GotConn(ci)
}
func traceWroteHeaders(trace *httptrace.ClientTrace) {
if trace != nil && trace.WroteHeaders != nil {
trace.WroteHeaders()
}
}
func traceGot100Continue(trace *httptrace.ClientTrace) {
if trace != nil && trace.Got100Continue != nil {
trace.Got100Continue()
}
}
func traceWait100Continue(trace *httptrace.ClientTrace) {
if trace != nil && trace.Wait100Continue != nil {
trace.Wait100Continue()
}
}
func traceWroteRequest(trace *httptrace.ClientTrace, err error) {
if trace != nil && trace.WroteRequest != nil {
trace.WroteRequest(httptrace.WroteRequestInfo{Err: err})
}
}
func traceFirstResponseByte(trace *httptrace.ClientTrace) {
if trace != nil && trace.GotFirstResponseByte != nil {
trace.GotFirstResponseByte()
}
}
func traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error {
if trace != nil {
return trace.Got1xxResponse
}
return nil
}
// dialTLSWithContext uses tls.Dialer, added in Go 1.15, to open a TLS
// connection.
func (t *Transport) dialTLSWithContext(ctx context.Context, network, addr string, cfg *tls.Config) (*tls.Conn, error) {
dialer := &tls.Dialer{
Config: cfg,
}
cn, err := dialer.DialContext(ctx, network, addr)
if err != nil {
return nil, err
}
tlsCn := cn.(*tls.Conn) // DialContext comment promises this will always succeed
return tlsCn, nil
}
// Copyright 2024 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 (
"crypto/tls"
"errors"
"net"
)
const nextProtoUnencryptedHTTP2 = "unencrypted_http2"
// unencryptedNetConnFromTLSConn retrieves a net.Conn wrapped in a *tls.Conn.
//
// TLSNextProto functions accept a *tls.Conn.
//
// When passing an unencrypted HTTP/2 connection to a TLSNextProto function,
// we pass a *tls.Conn with an underlying net.Conn containing the unencrypted connection.
// To be extra careful about mistakes (accidentally dropping TLS encryption in a place
// where we want it), the tls.Conn contains a net.Conn with an UnencryptedNetConn method
// that returns the actual connection we want to use.
func unencryptedNetConnFromTLSConn(tc *tls.Conn) (net.Conn, error) {
conner, ok := tc.NetConn().(interface {
UnencryptedNetConn() net.Conn
})
if !ok {
return nil, errors.New("http2: TLS conn unexpectedly found in unencrypted handoff")
}
return conner.UnencryptedNetConn(), nil
}
// 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 (
"bytes"
"fmt"
"log"
"net/http"
"net/url"
"golang.org/x/net/http/httpguts"
"golang.org/x/net/http2/hpack"
"golang.org/x/net/internal/httpcommon"
)
// writeFramer is implemented by any type that is used to write frames.
type writeFramer interface {
writeFrame(writeContext) error
// staysWithinBuffer reports whether this writer promises that
// it will only write less than or equal to size bytes, and it
// won't Flush the write context.
staysWithinBuffer(size int) bool
}
// writeContext is the interface needed by the various frame writer
// types below. All the writeFrame methods below are scheduled via the
// frame writing scheduler (see writeScheduler in writesched.go).
//
// This interface is implemented by *serverConn.
//
// TODO: decide whether to a) use this in the client code (which didn't
// end up using this yet, because it has a simpler design, not
// currently implementing priorities), or b) delete this and
// make the server code a bit more concrete.
type writeContext interface {
Framer() *Framer
Flush() error
CloseConn() error
// HeaderEncoder returns an HPACK encoder that writes to the
// returned buffer.
HeaderEncoder() (*hpack.Encoder, *bytes.Buffer)
}
// writeEndsStream reports whether w writes a frame that will transition
// the stream to a half-closed local state. This returns false for RST_STREAM,
// which closes the entire stream (not just the local half).
func writeEndsStream(w writeFramer) bool {
switch v := w.(type) {
case *writeData:
return v.endStream
case *writeResHeaders:
return v.endStream
case nil:
// This can only happen if the caller reuses w after it's
// been intentionally nil'ed out to prevent use. Keep this
// here to catch future refactoring breaking it.
panic("writeEndsStream called on nil writeFramer")
}
return false
}
type flushFrameWriter struct{}
func (flushFrameWriter) writeFrame(ctx writeContext) error {
return ctx.Flush()
}
func (flushFrameWriter) staysWithinBuffer(max int) bool { return false }
type writeSettings []Setting
func (s writeSettings) staysWithinBuffer(max int) bool {
const settingSize = 6 // uint16 + uint32
return frameHeaderLen+settingSize*len(s) <= max
}
func (s writeSettings) writeFrame(ctx writeContext) error {
return ctx.Framer().WriteSettings([]Setting(s)...)
}
type writeGoAway struct {
maxStreamID uint32
code ErrCode
}
func (p *writeGoAway) writeFrame(ctx writeContext) error {
err := ctx.Framer().WriteGoAway(p.maxStreamID, p.code, nil)
ctx.Flush() // ignore error: we're hanging up on them anyway
return err
}
func (*writeGoAway) staysWithinBuffer(max int) bool { return false } // flushes
type writeData struct {
streamID uint32
p []byte
endStream bool
}
func (w *writeData) String() string {
return fmt.Sprintf("writeData(stream=%d, p=%d, endStream=%v)", w.streamID, len(w.p), w.endStream)
}
func (w *writeData) writeFrame(ctx writeContext) error {
return ctx.Framer().WriteData(w.streamID, w.endStream, w.p)
}
func (w *writeData) staysWithinBuffer(max int) bool {
return frameHeaderLen+len(w.p) <= max
}
// handlerPanicRST is the message sent from handler goroutines when
// the handler panics.
type handlerPanicRST struct {
StreamID uint32
}
func (hp handlerPanicRST) writeFrame(ctx writeContext) error {
return ctx.Framer().WriteRSTStream(hp.StreamID, ErrCodeInternal)
}
func (hp handlerPanicRST) staysWithinBuffer(max int) bool { return frameHeaderLen+4 <= max }
func (se StreamError) writeFrame(ctx writeContext) error {
return ctx.Framer().WriteRSTStream(se.StreamID, se.Code)
}
func (se StreamError) staysWithinBuffer(max int) bool { return frameHeaderLen+4 <= max }
type writePing struct {
data [8]byte
}
func (w writePing) writeFrame(ctx writeContext) error {
return ctx.Framer().WritePing(false, w.data)
}
func (w writePing) staysWithinBuffer(max int) bool { return frameHeaderLen+len(w.data) <= max }
type writePingAck struct{ pf *PingFrame }
func (w writePingAck) writeFrame(ctx writeContext) error {
return ctx.Framer().WritePing(true, w.pf.Data)
}
func (w writePingAck) staysWithinBuffer(max int) bool { return frameHeaderLen+len(w.pf.Data) <= max }
type writeSettingsAck struct{}
func (writeSettingsAck) writeFrame(ctx writeContext) error {
return ctx.Framer().WriteSettingsAck()
}
func (writeSettingsAck) staysWithinBuffer(max int) bool { return frameHeaderLen <= max }
// splitHeaderBlock splits headerBlock into fragments so that each fragment fits
// in a single frame, then calls fn for each fragment. firstFrag/lastFrag are true
// for the first/last fragment, respectively.
func splitHeaderBlock(ctx writeContext, headerBlock []byte, fn func(ctx writeContext, frag []byte, firstFrag, lastFrag bool) error) error {
// For now we're lazy and just pick the minimum MAX_FRAME_SIZE
// that all peers must support (16KB). Later we could care
// more and send larger frames if the peer advertised it, but
// there's little point. Most headers are small anyway (so we
// generally won't have CONTINUATION frames), and extra frames
// only waste 9 bytes anyway.
const maxFrameSize = 16384
first := true
for len(headerBlock) > 0 {
frag := headerBlock
if len(frag) > maxFrameSize {
frag = frag[:maxFrameSize]
}
headerBlock = headerBlock[len(frag):]
if err := fn(ctx, frag, first, len(headerBlock) == 0); err != nil {
return err
}
first = false
}
return nil
}
// writeResHeaders is a request to write a HEADERS and 0+ CONTINUATION frames
// for HTTP response headers or trailers from a server handler.
type writeResHeaders struct {
streamID uint32
httpResCode int // 0 means no ":status" line
h http.Header // may be nil
trailers []string // if non-nil, which keys of h to write. nil means all.
endStream bool
date string
contentType string
contentLength string
}
func encKV(enc *hpack.Encoder, k, v string) {
if VerboseLogs {
log.Printf("http2: server encoding header %q = %q", k, v)
}
enc.WriteField(hpack.HeaderField{Name: k, Value: v})
}
func (w *writeResHeaders) staysWithinBuffer(max int) bool {
// TODO: this is a common one. It'd be nice to return true
// here and get into the fast path if we could be clever and
// calculate the size fast enough, or at least a conservative
// upper bound that usually fires. (Maybe if w.h and
// w.trailers are nil, so we don't need to enumerate it.)
// Otherwise I'm afraid that just calculating the length to
// answer this question would be slower than the ~2µs benefit.
return false
}
func (w *writeResHeaders) writeFrame(ctx writeContext) error {
enc, buf := ctx.HeaderEncoder()
buf.Reset()
if w.httpResCode != 0 {
encKV(enc, ":status", httpCodeString(w.httpResCode))
}
encodeHeaders(enc, w.h, w.trailers)
if w.contentType != "" {
encKV(enc, "content-type", w.contentType)
}
if w.contentLength != "" {
encKV(enc, "content-length", w.contentLength)
}
if w.date != "" {
encKV(enc, "date", w.date)
}
headerBlock := buf.Bytes()
if len(headerBlock) == 0 && w.trailers == nil {
panic("unexpected empty hpack")
}
return splitHeaderBlock(ctx, headerBlock, w.writeHeaderBlock)
}
func (w *writeResHeaders) writeHeaderBlock(ctx writeContext, frag []byte, firstFrag, lastFrag bool) error {
if firstFrag {
return ctx.Framer().WriteHeaders(HeadersFrameParam{
StreamID: w.streamID,
BlockFragment: frag,
EndStream: w.endStream,
EndHeaders: lastFrag,
})
} else {
return ctx.Framer().WriteContinuation(w.streamID, lastFrag, frag)
}
}
// writePushPromise is a request to write a PUSH_PROMISE and 0+ CONTINUATION frames.
type writePushPromise struct {
streamID uint32 // pusher stream
method string // for :method
url *url.URL // for :scheme, :authority, :path
h http.Header
// Creates an ID for a pushed stream. This runs on serveG just before
// the frame is written. The returned ID is copied to promisedID.
allocatePromisedID func() (uint32, error)
promisedID uint32
}
func (w *writePushPromise) staysWithinBuffer(max int) bool {
// TODO: see writeResHeaders.staysWithinBuffer
return false
}
func (w *writePushPromise) writeFrame(ctx writeContext) error {
enc, buf := ctx.HeaderEncoder()
buf.Reset()
encKV(enc, ":method", w.method)
encKV(enc, ":scheme", w.url.Scheme)
encKV(enc, ":authority", w.url.Host)
encKV(enc, ":path", w.url.RequestURI())
encodeHeaders(enc, w.h, nil)
headerBlock := buf.Bytes()
if len(headerBlock) == 0 {
panic("unexpected empty hpack")
}
return splitHeaderBlock(ctx, headerBlock, w.writeHeaderBlock)
}
func (w *writePushPromise) writeHeaderBlock(ctx writeContext, frag []byte, firstFrag, lastFrag bool) error {
if firstFrag {
return ctx.Framer().WritePushPromise(PushPromiseParam{
StreamID: w.streamID,
PromiseID: w.promisedID,
BlockFragment: frag,
EndHeaders: lastFrag,
})
} else {
return ctx.Framer().WriteContinuation(w.streamID, lastFrag, frag)
}
}
type write100ContinueHeadersFrame struct {
streamID uint32
}
func (w write100ContinueHeadersFrame) writeFrame(ctx writeContext) error {
enc, buf := ctx.HeaderEncoder()
buf.Reset()
encKV(enc, ":status", "100")
return ctx.Framer().WriteHeaders(HeadersFrameParam{
StreamID: w.streamID,
BlockFragment: buf.Bytes(),
EndStream: false,
EndHeaders: true,
})
}
func (w write100ContinueHeadersFrame) staysWithinBuffer(max int) bool {
// Sloppy but conservative:
return 9+2*(len(":status")+len("100")) <= max
}
type writeWindowUpdate struct {
streamID uint32 // or 0 for conn-level
n uint32
}
func (wu writeWindowUpdate) staysWithinBuffer(max int) bool { return frameHeaderLen+4 <= max }
func (wu writeWindowUpdate) writeFrame(ctx writeContext) error {
return ctx.Framer().WriteWindowUpdate(wu.streamID, wu.n)
}
// encodeHeaders encodes an http.Header. If keys is not nil, then (k, h[k])
// is encoded only if k is in keys.
func encodeHeaders(enc *hpack.Encoder, h http.Header, keys []string) {
if keys == nil {
sorter := sorterPool.Get().(*sorter)
// Using defer here, since the returned keys from the
// sorter.Keys method is only valid until the sorter
// is returned:
defer sorterPool.Put(sorter)
keys = sorter.Keys(h)
}
for _, k := range keys {
vv := h[k]
k, ascii := httpcommon.LowerHeader(k)
if !ascii {
// Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header
// field names have to be ASCII characters (just as in HTTP/1.x).
continue
}
if !validWireHeaderFieldName(k) {
// Skip it as backup paranoia. Per
// golang.org/issue/14048, these should
// already be rejected at a higher level.
continue
}
isTE := k == "transfer-encoding"
for _, v := range vv {
if !httpguts.ValidHeaderFieldValue(v) {
// TODO: return an error? golang.org/issue/14048
// For now just omit it.
continue
}
// TODO: more of "8.1.2.2 Connection-Specific Header Fields"
if isTE && v != "trailers" {
continue
}
encKV(enc, k, v)
}
}
}
// 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 "fmt"
// WriteScheduler is the interface implemented by HTTP/2 write schedulers.
// Methods are never called concurrently.
type WriteScheduler interface {
// OpenStream opens a new stream in the write scheduler.
// It is illegal to call this with streamID=0 or with a streamID that is
// already open -- the call may panic.
OpenStream(streamID uint32, options OpenStreamOptions)
// CloseStream closes a stream in the write scheduler. Any frames queued on
// this stream should be discarded. It is illegal to call this on a stream
// that is not open -- the call may panic.
CloseStream(streamID uint32)
// AdjustStream adjusts the priority of the given stream. This may be called
// on a stream that has not yet been opened or has been closed. Note that
// RFC 7540 allows PRIORITY frames to be sent on streams in any state. See:
// https://tools.ietf.org/html/rfc7540#section-5.1
AdjustStream(streamID uint32, priority PriorityParam)
// Push queues a frame in the scheduler. In most cases, this will not be
// called with wr.StreamID()!=0 unless that stream is currently open. The one
// exception is RST_STREAM frames, which may be sent on idle or closed streams.
Push(wr FrameWriteRequest)
// Pop dequeues the next frame to write. Returns false if no frames can
// be written. Frames with a given wr.StreamID() are Pop'd in the same
// order they are Push'd, except RST_STREAM frames. No frames should be
// discarded except by CloseStream.
Pop() (wr FrameWriteRequest, ok bool)
}
// OpenStreamOptions specifies extra options for WriteScheduler.OpenStream.
type OpenStreamOptions struct {
// PusherID is zero if the stream was initiated by the client. Otherwise,
// PusherID names the stream that pushed the newly opened stream.
PusherID uint32
// priority is used to set the priority of the newly opened stream.
priority PriorityParam
}
// FrameWriteRequest is a request to write a frame.
type FrameWriteRequest struct {
// write is the interface value that does the writing, once the
// WriteScheduler has selected this frame to write. The write
// functions are all defined in write.go.
write writeFramer
// stream is the stream on which this frame will be written.
// nil for non-stream frames like PING and SETTINGS.
// nil for RST_STREAM streams, which use the StreamError.StreamID field instead.
stream *stream
// done, if non-nil, must be a buffered channel with space for
// 1 message and is sent the return value from write (or an
// earlier error) when the frame has been written.
done chan error
}
// StreamID returns the id of the stream this frame will be written to.
// 0 is used for non-stream frames such as PING and SETTINGS.
func (wr FrameWriteRequest) StreamID() uint32 {
if wr.stream == nil {
if se, ok := wr.write.(StreamError); ok {
// (*serverConn).resetStream doesn't set
// stream because it doesn't necessarily have
// one. So special case this type of write
// message.
return se.StreamID
}
return 0
}
return wr.stream.id
}
// isControl reports whether wr is a control frame for MaxQueuedControlFrames
// purposes. That includes non-stream frames and RST_STREAM frames.
func (wr FrameWriteRequest) isControl() bool {
return wr.stream == nil
}
// DataSize returns the number of flow control bytes that must be consumed
// to write this entire frame. This is 0 for non-DATA frames.
func (wr FrameWriteRequest) DataSize() int {
if wd, ok := wr.write.(*writeData); ok {
return len(wd.p)
}
return 0
}
// Consume consumes min(n, available) bytes from this frame, where available
// is the number of flow control bytes available on the stream. Consume returns
// 0, 1, or 2 frames, where the integer return value gives the number of frames
// returned.
//
// If flow control prevents consuming any bytes, this returns (_, _, 0). If
// the entire frame was consumed, this returns (wr, _, 1). Otherwise, this
// returns (consumed, rest, 2), where 'consumed' contains the consumed bytes and
// 'rest' contains the remaining bytes. The consumed bytes are deducted from the
// underlying stream's flow control budget.
func (wr FrameWriteRequest) Consume(n int32) (FrameWriteRequest, FrameWriteRequest, int) {
var empty FrameWriteRequest
// Non-DATA frames are always consumed whole.
wd, ok := wr.write.(*writeData)
if !ok || len(wd.p) == 0 {
return wr, empty, 1
}
// Might need to split after applying limits.
allowed := wr.stream.flow.available()
if n < allowed {
allowed = n
}
if wr.stream.sc.maxFrameSize < allowed {
allowed = wr.stream.sc.maxFrameSize
}
if allowed <= 0 {
return empty, empty, 0
}
if len(wd.p) > int(allowed) {
wr.stream.flow.take(allowed)
consumed := FrameWriteRequest{
stream: wr.stream,
write: &writeData{
streamID: wd.streamID,
p: wd.p[:allowed],
// Even if the original had endStream set, there
// are bytes remaining because len(wd.p) > allowed,
// so we know endStream is false.
endStream: false,
},
// Our caller is blocking on the final DATA frame, not
// this intermediate frame, so no need to wait.
done: nil,
}
rest := FrameWriteRequest{
stream: wr.stream,
write: &writeData{
streamID: wd.streamID,
p: wd.p[allowed:],
endStream: wd.endStream,
},
done: wr.done,
}
return consumed, rest, 2
}
// The frame is consumed whole.
// NB: This cast cannot overflow because allowed is <= math.MaxInt32.
wr.stream.flow.take(int32(len(wd.p)))
return wr, empty, 1
}
// String is for debugging only.
func (wr FrameWriteRequest) String() string {
var des string
if s, ok := wr.write.(fmt.Stringer); ok {
des = s.String()
} else {
des = fmt.Sprintf("%T", wr.write)
}
return fmt.Sprintf("[FrameWriteRequest stream=%d, ch=%v, writer=%v]", wr.StreamID(), wr.done != nil, des)
}
// replyToWriter sends err to wr.done and panics if the send must block
// This does nothing if wr.done is nil.
func (wr *FrameWriteRequest) replyToWriter(err error) {
if wr.done == nil {
return
}
select {
case wr.done <- err:
default:
panic(fmt.Sprintf("unbuffered done channel passed in for type %T", wr.write))
}
wr.write = nil // prevent use (assume it's tainted after wr.done send)
}
// writeQueue is used by implementations of WriteScheduler.
//
// Each writeQueue contains a queue of FrameWriteRequests, meant to store all
// FrameWriteRequests associated with a given stream. This is implemented as a
// two-stage queue: currQueue[currPos:] and nextQueue. Removing an item is done
// by incrementing currPos of currQueue. Adding an item is done by appending it
// to the nextQueue. If currQueue is empty when trying to remove an item, we
// can swap currQueue and nextQueue to remedy the situation.
// This two-stage queue is analogous to the use of two lists in Okasaki's
// purely functional queue but without the overhead of reversing the list when
// swapping stages.
//
// writeQueue also contains prev and next, this can be used by implementations
// of WriteScheduler to construct data structures that represent the order of
// writing between different streams (e.g. circular linked list).
type writeQueue struct {
currQueue []FrameWriteRequest
nextQueue []FrameWriteRequest
currPos int
prev, next *writeQueue
}
func (q *writeQueue) empty() bool {
return (len(q.currQueue) - q.currPos + len(q.nextQueue)) == 0
}
func (q *writeQueue) push(wr FrameWriteRequest) {
q.nextQueue = append(q.nextQueue, wr)
}
func (q *writeQueue) shift() FrameWriteRequest {
if q.empty() {
panic("invalid use of queue")
}
if q.currPos >= len(q.currQueue) {
q.currQueue, q.currPos, q.nextQueue = q.nextQueue, 0, q.currQueue[:0]
}
wr := q.currQueue[q.currPos]
q.currQueue[q.currPos] = FrameWriteRequest{}
q.currPos++
return wr
}
func (q *writeQueue) peek() *FrameWriteRequest {
if q.currPos < len(q.currQueue) {
return &q.currQueue[q.currPos]
}
if len(q.nextQueue) > 0 {
return &q.nextQueue[0]
}
return nil
}
// consume consumes up to n bytes from q.s[0]. If the frame is
// entirely consumed, it is removed from the queue. If the frame
// is partially consumed, the frame is kept with the consumed
// bytes removed. Returns true iff any bytes were consumed.
func (q *writeQueue) consume(n int32) (FrameWriteRequest, bool) {
if q.empty() {
return FrameWriteRequest{}, false
}
consumed, rest, numresult := q.peek().Consume(n)
switch numresult {
case 0:
return FrameWriteRequest{}, false
case 1:
q.shift()
case 2:
*q.peek() = rest
}
return consumed, true
}
type writeQueuePool []*writeQueue
// put inserts an unused writeQueue into the pool.
func (p *writeQueuePool) put(q *writeQueue) {
for i := range q.currQueue {
q.currQueue[i] = FrameWriteRequest{}
}
for i := range q.nextQueue {
q.nextQueue[i] = FrameWriteRequest{}
}
q.currQueue = q.currQueue[:0]
q.nextQueue = q.nextQueue[:0]
q.currPos = 0
*p = append(*p, q)
}
// get returns an empty writeQueue.
func (p *writeQueuePool) get() *writeQueue {
ln := len(*p)
if ln == 0 {
return new(writeQueue)
}
x := ln - 1
q := (*p)[x]
(*p)[x] = nil
*p = (*p)[:x]
return q
}
// 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.
package http2
import (
"fmt"
"math"
"sort"
)
// RFC 7540, Section 5.3.5: the default weight is 16.
const priorityDefaultWeightRFC7540 = 15 // 16 = 15 + 1
// PriorityWriteSchedulerConfig configures a priorityWriteScheduler.
type PriorityWriteSchedulerConfig struct {
// MaxClosedNodesInTree controls the maximum number of closed streams to
// retain in the priority tree. Setting this to zero saves a small amount
// of memory at the cost of performance.
//
// See RFC 7540, Section 5.3.4:
// "It is possible for a stream to become closed while prioritization
// information ... is in transit. ... This potentially creates suboptimal
// prioritization, since the stream could be given a priority that is
// different from what is intended. To avoid these problems, an endpoint
// SHOULD retain stream prioritization state for a period after streams
// become closed. The longer state is retained, the lower the chance that
// streams are assigned incorrect or default priority values."
MaxClosedNodesInTree int
// MaxIdleNodesInTree controls the maximum number of idle streams to
// retain in the priority tree. Setting this to zero saves a small amount
// of memory at the cost of performance.
//
// See RFC 7540, Section 5.3.4:
// Similarly, streams that are in the "idle" state can be assigned
// priority or become a parent of other streams. This allows for the
// creation of a grouping node in the dependency tree, which enables
// more flexible expressions of priority. Idle streams begin with a
// default priority (Section 5.3.5).
MaxIdleNodesInTree int
// ThrottleOutOfOrderWrites enables write throttling to help ensure that
// data is delivered in priority order. This works around a race where
// stream B depends on stream A and both streams are about to call Write
// to queue DATA frames. If B wins the race, a naive scheduler would eagerly
// write as much data from B as possible, but this is suboptimal because A
// is a higher-priority stream. With throttling enabled, we write a small
// amount of data from B to minimize the amount of bandwidth that B can
// steal from A.
ThrottleOutOfOrderWrites bool
}
// NewPriorityWriteScheduler constructs a WriteScheduler that schedules
// frames by following HTTP/2 priorities as described in RFC 7540 Section 5.3.
// If cfg is nil, default options are used.
func NewPriorityWriteScheduler(cfg *PriorityWriteSchedulerConfig) WriteScheduler {
if cfg == nil {
// For justification of these defaults, see:
// https://docs.google.com/document/d/1oLhNg1skaWD4_DtaoCxdSRN5erEXrH-KnLrMwEpOtFY
cfg = &PriorityWriteSchedulerConfig{
MaxClosedNodesInTree: 10,
MaxIdleNodesInTree: 10,
ThrottleOutOfOrderWrites: false,
}
}
ws := &priorityWriteSchedulerRFC7540{
nodes: make(map[uint32]*priorityNodeRFC7540),
maxClosedNodesInTree: cfg.MaxClosedNodesInTree,
maxIdleNodesInTree: cfg.MaxIdleNodesInTree,
enableWriteThrottle: cfg.ThrottleOutOfOrderWrites,
}
ws.nodes[0] = &ws.root
if cfg.ThrottleOutOfOrderWrites {
ws.writeThrottleLimit = 1024
} else {
ws.writeThrottleLimit = math.MaxInt32
}
return ws
}
type priorityNodeStateRFC7540 int
const (
priorityNodeOpenRFC7540 priorityNodeStateRFC7540 = iota
priorityNodeClosedRFC7540
priorityNodeIdleRFC7540
)
// priorityNodeRFC7540 is a node in an HTTP/2 priority tree.
// Each node is associated with a single stream ID.
// See RFC 7540, Section 5.3.
type priorityNodeRFC7540 struct {
q writeQueue // queue of pending frames to write
id uint32 // id of the stream, or 0 for the root of the tree
weight uint8 // the actual weight is weight+1, so the value is in [1,256]
state priorityNodeStateRFC7540 // open | closed | idle
bytes int64 // number of bytes written by this node, or 0 if closed
subtreeBytes int64 // sum(node.bytes) of all nodes in this subtree
// These links form the priority tree.
parent *priorityNodeRFC7540
kids *priorityNodeRFC7540 // start of the kids list
prev, next *priorityNodeRFC7540 // doubly-linked list of siblings
}
func (n *priorityNodeRFC7540) setParent(parent *priorityNodeRFC7540) {
if n == parent {
panic("setParent to self")
}
if n.parent == parent {
return
}
// Unlink from current parent.
if parent := n.parent; parent != nil {
if n.prev == nil {
parent.kids = n.next
} else {
n.prev.next = n.next
}
if n.next != nil {
n.next.prev = n.prev
}
}
// Link to new parent.
// If parent=nil, remove n from the tree.
// Always insert at the head of parent.kids (this is assumed by walkReadyInOrder).
n.parent = parent
if parent == nil {
n.next = nil
n.prev = nil
} else {
n.next = parent.kids
n.prev = nil
if n.next != nil {
n.next.prev = n
}
parent.kids = n
}
}
func (n *priorityNodeRFC7540) addBytes(b int64) {
n.bytes += b
for ; n != nil; n = n.parent {
n.subtreeBytes += b
}
}
// walkReadyInOrder iterates over the tree in priority order, calling f for each node
// with a non-empty write queue. When f returns true, this function returns true and the
// walk halts. tmp is used as scratch space for sorting.
//
// f(n, openParent) takes two arguments: the node to visit, n, and a bool that is true
// if any ancestor p of n is still open (ignoring the root node).
func (n *priorityNodeRFC7540) walkReadyInOrder(openParent bool, tmp *[]*priorityNodeRFC7540, f func(*priorityNodeRFC7540, bool) bool) bool {
if !n.q.empty() && f(n, openParent) {
return true
}
if n.kids == nil {
return false
}
// Don't consider the root "open" when updating openParent since
// we can't send data frames on the root stream (only control frames).
if n.id != 0 {
openParent = openParent || (n.state == priorityNodeOpenRFC7540)
}
// Common case: only one kid or all kids have the same weight.
// Some clients don't use weights; other clients (like web browsers)
// use mostly-linear priority trees.
w := n.kids.weight
needSort := false
for k := n.kids.next; k != nil; k = k.next {
if k.weight != w {
needSort = true
break
}
}
if !needSort {
for k := n.kids; k != nil; k = k.next {
if k.walkReadyInOrder(openParent, tmp, f) {
return true
}
}
return false
}
// Uncommon case: sort the child nodes. We remove the kids from the parent,
// then re-insert after sorting so we can reuse tmp for future sort calls.
*tmp = (*tmp)[:0]
for n.kids != nil {
*tmp = append(*tmp, n.kids)
n.kids.setParent(nil)
}
sort.Sort(sortPriorityNodeSiblingsRFC7540(*tmp))
for i := len(*tmp) - 1; i >= 0; i-- {
(*tmp)[i].setParent(n) // setParent inserts at the head of n.kids
}
for k := n.kids; k != nil; k = k.next {
if k.walkReadyInOrder(openParent, tmp, f) {
return true
}
}
return false
}
type sortPriorityNodeSiblingsRFC7540 []*priorityNodeRFC7540
func (z sortPriorityNodeSiblingsRFC7540) Len() int { return len(z) }
func (z sortPriorityNodeSiblingsRFC7540) Swap(i, k int) { z[i], z[k] = z[k], z[i] }
func (z sortPriorityNodeSiblingsRFC7540) Less(i, k int) bool {
// Prefer the subtree that has sent fewer bytes relative to its weight.
// See sections 5.3.2 and 5.3.4.
wi, bi := float64(z[i].weight)+1, float64(z[i].subtreeBytes)
wk, bk := float64(z[k].weight)+1, float64(z[k].subtreeBytes)
if bi == 0 && bk == 0 {
return wi >= wk
}
if bk == 0 {
return false
}
return bi/bk <= wi/wk
}
type priorityWriteSchedulerRFC7540 struct {
// root is the root of the priority tree, where root.id = 0.
// The root queues control frames that are not associated with any stream.
root priorityNodeRFC7540
// nodes maps stream ids to priority tree nodes.
nodes map[uint32]*priorityNodeRFC7540
// maxID is the maximum stream id in nodes.
maxID uint32
// lists of nodes that have been closed or are idle, but are kept in
// the tree for improved prioritization. When the lengths exceed either
// maxClosedNodesInTree or maxIdleNodesInTree, old nodes are discarded.
closedNodes, idleNodes []*priorityNodeRFC7540
// From the config.
maxClosedNodesInTree int
maxIdleNodesInTree int
writeThrottleLimit int32
enableWriteThrottle bool
// tmp is scratch space for priorityNode.walkReadyInOrder to reduce allocations.
tmp []*priorityNodeRFC7540
// pool of empty queues for reuse.
queuePool writeQueuePool
}
func (ws *priorityWriteSchedulerRFC7540) OpenStream(streamID uint32, options OpenStreamOptions) {
// The stream may be currently idle but cannot be opened or closed.
if curr := ws.nodes[streamID]; curr != nil {
if curr.state != priorityNodeIdleRFC7540 {
panic(fmt.Sprintf("stream %d already opened", streamID))
}
curr.state = priorityNodeOpenRFC7540
return
}
// RFC 7540, Section 5.3.5:
// "All streams are initially assigned a non-exclusive dependency on stream 0x0.
// Pushed streams initially depend on their associated stream. In both cases,
// streams are assigned a default weight of 16."
parent := ws.nodes[options.PusherID]
if parent == nil {
parent = &ws.root
}
n := &priorityNodeRFC7540{
q: *ws.queuePool.get(),
id: streamID,
weight: priorityDefaultWeightRFC7540,
state: priorityNodeOpenRFC7540,
}
n.setParent(parent)
ws.nodes[streamID] = n
if streamID > ws.maxID {
ws.maxID = streamID
}
}
func (ws *priorityWriteSchedulerRFC7540) CloseStream(streamID uint32) {
if streamID == 0 {
panic("violation of WriteScheduler interface: cannot close stream 0")
}
if ws.nodes[streamID] == nil {
panic(fmt.Sprintf("violation of WriteScheduler interface: unknown stream %d", streamID))
}
if ws.nodes[streamID].state != priorityNodeOpenRFC7540 {
panic(fmt.Sprintf("violation of WriteScheduler interface: stream %d already closed", streamID))
}
n := ws.nodes[streamID]
n.state = priorityNodeClosedRFC7540
n.addBytes(-n.bytes)
q := n.q
ws.queuePool.put(&q)
if ws.maxClosedNodesInTree > 0 {
ws.addClosedOrIdleNode(&ws.closedNodes, ws.maxClosedNodesInTree, n)
} else {
ws.removeNode(n)
}
}
func (ws *priorityWriteSchedulerRFC7540) AdjustStream(streamID uint32, priority PriorityParam) {
if streamID == 0 {
panic("adjustPriority on root")
}
// If streamID does not exist, there are two cases:
// - A closed stream that has been removed (this will have ID <= maxID)
// - An idle stream that is being used for "grouping" (this will have ID > maxID)
n := ws.nodes[streamID]
if n == nil {
if streamID <= ws.maxID || ws.maxIdleNodesInTree == 0 {
return
}
ws.maxID = streamID
n = &priorityNodeRFC7540{
q: *ws.queuePool.get(),
id: streamID,
weight: priorityDefaultWeightRFC7540,
state: priorityNodeIdleRFC7540,
}
n.setParent(&ws.root)
ws.nodes[streamID] = n
ws.addClosedOrIdleNode(&ws.idleNodes, ws.maxIdleNodesInTree, n)
}
// Section 5.3.1: A dependency on a stream that is not currently in the tree
// results in that stream being given a default priority (Section 5.3.5).
parent := ws.nodes[priority.StreamDep]
if parent == nil {
n.setParent(&ws.root)
n.weight = priorityDefaultWeightRFC7540
return
}
// Ignore if the client tries to make a node its own parent.
if n == parent {
return
}
// Section 5.3.3:
// "If a stream is made dependent on one of its own dependencies, the
// formerly dependent stream is first moved to be dependent on the
// reprioritized stream's previous parent. The moved dependency retains
// its weight."
//
// That is: if parent depends on n, move parent to depend on n.parent.
for x := parent.parent; x != nil; x = x.parent {
if x == n {
parent.setParent(n.parent)
break
}
}
// Section 5.3.3: The exclusive flag causes the stream to become the sole
// dependency of its parent stream, causing other dependencies to become
// dependent on the exclusive stream.
if priority.Exclusive {
k := parent.kids
for k != nil {
next := k.next
if k != n {
k.setParent(n)
}
k = next
}
}
n.setParent(parent)
n.weight = priority.Weight
}
func (ws *priorityWriteSchedulerRFC7540) Push(wr FrameWriteRequest) {
var n *priorityNodeRFC7540
if wr.isControl() {
n = &ws.root
} else {
id := wr.StreamID()
n = ws.nodes[id]
if n == nil {
// id is an idle or closed stream. wr should not be a HEADERS or
// DATA frame. In other case, we push wr onto the root, rather
// than creating a new priorityNode.
if wr.DataSize() > 0 {
panic("add DATA on non-open stream")
}
n = &ws.root
}
}
n.q.push(wr)
}
func (ws *priorityWriteSchedulerRFC7540) Pop() (wr FrameWriteRequest, ok bool) {
ws.root.walkReadyInOrder(false, &ws.tmp, func(n *priorityNodeRFC7540, openParent bool) bool {
limit := int32(math.MaxInt32)
if openParent {
limit = ws.writeThrottleLimit
}
wr, ok = n.q.consume(limit)
if !ok {
return false
}
n.addBytes(int64(wr.DataSize()))
// If B depends on A and B continuously has data available but A
// does not, gradually increase the throttling limit to allow B to
// steal more and more bandwidth from A.
if openParent {
ws.writeThrottleLimit += 1024
if ws.writeThrottleLimit < 0 {
ws.writeThrottleLimit = math.MaxInt32
}
} else if ws.enableWriteThrottle {
ws.writeThrottleLimit = 1024
}
return true
})
return wr, ok
}
func (ws *priorityWriteSchedulerRFC7540) addClosedOrIdleNode(list *[]*priorityNodeRFC7540, maxSize int, n *priorityNodeRFC7540) {
if maxSize == 0 {
return
}
if len(*list) == maxSize {
// Remove the oldest node, then shift left.
ws.removeNode((*list)[0])
x := (*list)[1:]
copy(*list, x)
*list = (*list)[:len(x)]
}
*list = append(*list, n)
}
func (ws *priorityWriteSchedulerRFC7540) removeNode(n *priorityNodeRFC7540) {
for n.kids != nil {
n.kids.setParent(n.parent)
}
n.setParent(nil)
delete(ws.nodes, n.id)
}
// Copyright 2025 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 (
"fmt"
"math"
)
type streamMetadata struct {
location *writeQueue
priority PriorityParam
}
type priorityWriteSchedulerRFC9218 struct {
// control contains control frames (SETTINGS, PING, etc.).
control writeQueue
// heads contain the head of a circular list of streams.
// We put these heads within a nested array that represents urgency and
// incremental, as defined in
// https://www.rfc-editor.org/rfc/rfc9218.html#name-priority-parameters.
// 8 represents u=0 up to u=7, and 2 represents i=false and i=true.
heads [8][2]*writeQueue
// streams contains a mapping between each stream ID and their metadata, so
// we can quickly locate them when needing to, for example, adjust their
// priority.
streams map[uint32]streamMetadata
// queuePool are empty queues for reuse.
queuePool writeQueuePool
// prioritizeIncremental is used to determine whether we should prioritize
// incremental streams or not, when urgency is the same in a given Pop()
// call.
prioritizeIncremental bool
}
func newPriorityWriteSchedulerRFC9218() WriteScheduler {
ws := &priorityWriteSchedulerRFC9218{
streams: make(map[uint32]streamMetadata),
}
return ws
}
func (ws *priorityWriteSchedulerRFC9218) OpenStream(streamID uint32, opt OpenStreamOptions) {
if ws.streams[streamID].location != nil {
panic(fmt.Errorf("stream %d already opened", streamID))
}
q := ws.queuePool.get()
ws.streams[streamID] = streamMetadata{
location: q,
priority: opt.priority,
}
u, i := opt.priority.urgency, opt.priority.incremental
if ws.heads[u][i] == nil {
ws.heads[u][i] = q
q.next = q
q.prev = q
} else {
// Queues are stored in a ring.
// Insert the new stream before ws.head, putting it at the end of the list.
q.prev = ws.heads[u][i].prev
q.next = ws.heads[u][i]
q.prev.next = q
q.next.prev = q
}
}
func (ws *priorityWriteSchedulerRFC9218) CloseStream(streamID uint32) {
metadata := ws.streams[streamID]
q, u, i := metadata.location, metadata.priority.urgency, metadata.priority.incremental
if q == nil {
return
}
if q.next == q {
// This was the only open stream.
ws.heads[u][i] = nil
} else {
q.prev.next = q.next
q.next.prev = q.prev
if ws.heads[u][i] == q {
ws.heads[u][i] = q.next
}
}
delete(ws.streams, streamID)
ws.queuePool.put(q)
}
func (ws *priorityWriteSchedulerRFC9218) AdjustStream(streamID uint32, priority PriorityParam) {
metadata := ws.streams[streamID]
q, u, i := metadata.location, metadata.priority.urgency, metadata.priority.incremental
if q == nil {
return
}
// Remove stream from current location.
if q.next == q {
// This was the only open stream.
ws.heads[u][i] = nil
} else {
q.prev.next = q.next
q.next.prev = q.prev
if ws.heads[u][i] == q {
ws.heads[u][i] = q.next
}
}
// Insert stream to the new queue.
u, i = priority.urgency, priority.incremental
if ws.heads[u][i] == nil {
ws.heads[u][i] = q
q.next = q
q.prev = q
} else {
// Queues are stored in a ring.
// Insert the new stream before ws.head, putting it at the end of the list.
q.prev = ws.heads[u][i].prev
q.next = ws.heads[u][i]
q.prev.next = q
q.next.prev = q
}
// Update the metadata.
ws.streams[streamID] = streamMetadata{
location: q,
priority: priority,
}
}
func (ws *priorityWriteSchedulerRFC9218) Push(wr FrameWriteRequest) {
if wr.isControl() {
ws.control.push(wr)
return
}
q := ws.streams[wr.StreamID()].location
if q == nil {
// This is a closed stream.
// wr should not be a HEADERS or DATA frame.
// We push the request onto the control queue.
if wr.DataSize() > 0 {
panic("add DATA on non-open stream")
}
ws.control.push(wr)
return
}
q.push(wr)
}
func (ws *priorityWriteSchedulerRFC9218) Pop() (FrameWriteRequest, bool) {
// Control and RST_STREAM frames first.
if !ws.control.empty() {
return ws.control.shift(), true
}
// On the next Pop(), we want to prioritize incremental if we prioritized
// non-incremental request of the same urgency this time. Vice-versa.
// i.e. when there are incremental and non-incremental requests at the same
// priority, we give 50% of our bandwidth to the incremental ones in
// aggregate and 50% to the first non-incremental one (since
// non-incremental streams do not use round-robin writes).
ws.prioritizeIncremental = !ws.prioritizeIncremental
// Always prioritize lowest u (i.e. highest urgency level).
for u := range ws.heads {
for i := range ws.heads[u] {
// When we want to prioritize incremental, we try to pop i=true
// first before i=false when u is the same.
if ws.prioritizeIncremental {
i = (i + 1) % 2
}
q := ws.heads[u][i]
if q == nil {
continue
}
for {
if wr, ok := q.consume(math.MaxInt32); ok {
if i == 1 {
// For incremental streams, we update head to q.next so
// we can round-robin between multiple streams that can
// immediately benefit from partial writes.
ws.heads[u][i] = q.next
} else {
// For non-incremental streams, we try to finish one to
// completion rather than doing round-robin. However,
// we update head here so that if q.consume() is !ok
// (e.g. the stream has no more frame to consume), head
// is updated to the next q that has frames to consume
// on future iterations. This way, we do not prioritize
// writing to unavailable stream on next Pop() calls,
// preventing head-of-line blocking.
ws.heads[u][i] = q
}
return wr, true
}
q = q.next
if q == ws.heads[u][i] {
break
}
}
}
}
return FrameWriteRequest{}, false
}
// 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 "math"
// NewRandomWriteScheduler constructs a WriteScheduler that ignores HTTP/2
// priorities. Control frames like SETTINGS and PING are written before DATA
// frames, but if no control frames are queued and multiple streams have queued
// HEADERS or DATA frames, Pop selects a ready stream arbitrarily.
func NewRandomWriteScheduler() WriteScheduler {
return &randomWriteScheduler{sq: make(map[uint32]*writeQueue)}
}
type randomWriteScheduler struct {
// zero are frames not associated with a specific stream.
zero writeQueue
// sq contains the stream-specific queues, keyed by stream ID.
// When a stream is idle, closed, or emptied, it's deleted
// from the map.
sq map[uint32]*writeQueue
// pool of empty queues for reuse.
queuePool writeQueuePool
}
func (ws *randomWriteScheduler) OpenStream(streamID uint32, options OpenStreamOptions) {
// no-op: idle streams are not tracked
}
func (ws *randomWriteScheduler) CloseStream(streamID uint32) {
q, ok := ws.sq[streamID]
if !ok {
return
}
delete(ws.sq, streamID)
ws.queuePool.put(q)
}
func (ws *randomWriteScheduler) AdjustStream(streamID uint32, priority PriorityParam) {
// no-op: priorities are ignored
}
func (ws *randomWriteScheduler) Push(wr FrameWriteRequest) {
if wr.isControl() {
ws.zero.push(wr)
return
}
id := wr.StreamID()
q, ok := ws.sq[id]
if !ok {
q = ws.queuePool.get()
ws.sq[id] = q
}
q.push(wr)
}
func (ws *randomWriteScheduler) Pop() (FrameWriteRequest, bool) {
// Control and RST_STREAM frames first.
if !ws.zero.empty() {
return ws.zero.shift(), true
}
// Iterate over all non-idle streams until finding one that can be consumed.
for streamID, q := range ws.sq {
if wr, ok := q.consume(math.MaxInt32); ok {
if q.empty() {
delete(ws.sq, streamID)
ws.queuePool.put(q)
}
return wr, true
}
}
return FrameWriteRequest{}, false
}
// Copyright 2023 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 (
"fmt"
"math"
)
type roundRobinWriteScheduler struct {
// control contains control frames (SETTINGS, PING, etc.).
control writeQueue
// streams maps stream ID to a queue.
streams map[uint32]*writeQueue
// stream queues are stored in a circular linked list.
// head is the next stream to write, or nil if there are no streams open.
head *writeQueue
// pool of empty queues for reuse.
queuePool writeQueuePool
}
// newRoundRobinWriteScheduler constructs a new write scheduler.
// The round robin scheduler prioritizes control frames
// like SETTINGS and PING over DATA frames.
// When there are no control frames to send, it performs a round-robin
// selection from the ready streams.
func newRoundRobinWriteScheduler() WriteScheduler {
ws := &roundRobinWriteScheduler{
streams: make(map[uint32]*writeQueue),
}
return ws
}
func (ws *roundRobinWriteScheduler) OpenStream(streamID uint32, options OpenStreamOptions) {
if ws.streams[streamID] != nil {
panic(fmt.Errorf("stream %d already opened", streamID))
}
q := ws.queuePool.get()
ws.streams[streamID] = q
if ws.head == nil {
ws.head = q
q.next = q
q.prev = q
} else {
// Queues are stored in a ring.
// Insert the new stream before ws.head, putting it at the end of the list.
q.prev = ws.head.prev
q.next = ws.head
q.prev.next = q
q.next.prev = q
}
}
func (ws *roundRobinWriteScheduler) CloseStream(streamID uint32) {
q := ws.streams[streamID]
if q == nil {
return
}
if q.next == q {
// This was the only open stream.
ws.head = nil
} else {
q.prev.next = q.next
q.next.prev = q.prev
if ws.head == q {
ws.head = q.next
}
}
delete(ws.streams, streamID)
ws.queuePool.put(q)
}
func (ws *roundRobinWriteScheduler) AdjustStream(streamID uint32, priority PriorityParam) {}
func (ws *roundRobinWriteScheduler) Push(wr FrameWriteRequest) {
if wr.isControl() {
ws.control.push(wr)
return
}
q := ws.streams[wr.StreamID()]
if q == nil {
// This is a closed stream.
// wr should not be a HEADERS or DATA frame.
// We push the request onto the control queue.
if wr.DataSize() > 0 {
panic("add DATA on non-open stream")
}
ws.control.push(wr)
return
}
q.push(wr)
}
func (ws *roundRobinWriteScheduler) Pop() (FrameWriteRequest, bool) {
// Control and RST_STREAM frames first.
if !ws.control.empty() {
return ws.control.shift(), true
}
if ws.head == nil {
return FrameWriteRequest{}, false
}
q := ws.head
for {
if wr, ok := q.consume(math.MaxInt32); ok {
ws.head = q.next
return wr, true
}
q = q.next
if q == ws.head {
break
}
}
return FrameWriteRequest{}, false
}
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
// 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.
//go:build go1.10
// Package idna implements IDNA2008 using the compatibility processing
// defined by UTS (Unicode Technical Standard) #46, which defines a standard to
// deal with the transition from IDNA2003.
//
// IDNA2008 (Internationalized Domain Names for Applications), is defined in RFC
// 5890, RFC 5891, RFC 5892, RFC 5893 and RFC 5894.
// UTS #46 is defined in https://www.unicode.org/reports/tr46.
// See https://unicode.org/cldr/utility/idna.jsp for a visualization of the
// differences between these two standards.
package idna // import "golang.org/x/net/idna"
import (
"fmt"
"strings"
"unicode/utf8"
"golang.org/x/text/secure/bidirule"
"golang.org/x/text/unicode/bidi"
"golang.org/x/text/unicode/norm"
)
// NOTE: Unlike common practice in Go APIs, the functions will return a
// sanitized domain name in case of errors. Browsers sometimes use a partially
// evaluated string as lookup.
// TODO: the current error handling is, in my opinion, the least opinionated.
// Other strategies are also viable, though:
// Option 1) Return an empty string in case of error, but allow the user to
// specify explicitly which errors to ignore.
// Option 2) Return the partially evaluated string if it is itself a valid
// string, otherwise return the empty string in case of error.
// Option 3) Option 1 and 2.
// Option 4) Always return an empty string for now and implement Option 1 as
// needed, and document that the return string may not be empty in case of
// error in the future.
// I think Option 1 is best, but it is quite opinionated.
// ToASCII is a wrapper for Punycode.ToASCII.
func ToASCII(s string) (string, error) {
return Punycode.process(s, true)
}
// ToUnicode is a wrapper for Punycode.ToUnicode.
func ToUnicode(s string) (string, error) {
return Punycode.process(s, false)
}
// An Option configures a Profile at creation time.
type Option func(*options)
// Transitional sets a Profile to use the Transitional mapping as defined in UTS
// #46. This will cause, for example, "ß" to be mapped to "ss". Using the
// transitional mapping provides a compromise between IDNA2003 and IDNA2008
// compatibility. It is used by some browsers when resolving domain names. This
// option is only meaningful if combined with MapForLookup.
func Transitional(transitional bool) Option {
return func(o *options) { o.transitional = transitional }
}
// VerifyDNSLength sets whether a Profile should fail if any of the IDN parts
// are longer than allowed by the RFC.
//
// This option corresponds to the VerifyDnsLength flag in UTS #46.
func VerifyDNSLength(verify bool) Option {
return func(o *options) { o.verifyDNSLength = verify }
}
// RemoveLeadingDots removes leading label separators. Leading runes that map to
// dots, such as U+3002 IDEOGRAPHIC FULL STOP, are removed as well.
func RemoveLeadingDots(remove bool) Option {
return func(o *options) { o.removeLeadingDots = remove }
}
// ValidateLabels sets whether to check the mandatory label validation criteria
// as defined in Section 5.4 of RFC 5891. This includes testing for correct use
// of hyphens ('-'), normalization, validity of runes, and the context rules.
// In particular, ValidateLabels also sets the CheckHyphens and CheckJoiners flags
// in UTS #46.
func ValidateLabels(enable bool) Option {
return func(o *options) {
// Don't override existing mappings, but set one that at least checks
// normalization if it is not set.
if o.mapping == nil && enable {
o.mapping = normalize
}
o.trie = trie
o.checkJoiners = enable
o.checkHyphens = enable
if enable {
o.fromPuny = validateFromPunycode
} else {
o.fromPuny = nil
}
}
}
// CheckHyphens sets whether to check for correct use of hyphens ('-') in
// labels. Most web browsers do not have this option set, since labels such as
// "r3---sn-apo3qvuoxuxbt-j5pe" are in common use.
//
// This option corresponds to the CheckHyphens flag in UTS #46.
func CheckHyphens(enable bool) Option {
return func(o *options) { o.checkHyphens = enable }
}
// CheckJoiners sets whether to check the ContextJ rules as defined in Appendix
// A of RFC 5892, concerning the use of joiner runes.
//
// This option corresponds to the CheckJoiners flag in UTS #46.
func CheckJoiners(enable bool) Option {
return func(o *options) {
o.trie = trie
o.checkJoiners = enable
}
}
// StrictDomainName limits the set of permissible ASCII characters to those
// allowed in domain names as defined in RFC 1034 (A-Z, a-z, 0-9 and the
// hyphen). This is set by default for MapForLookup and ValidateForRegistration,
// but is only useful if ValidateLabels is set.
//
// This option is useful, for instance, for browsers that allow characters
// outside this range, for example a '_' (U+005F LOW LINE). See
// http://www.rfc-editor.org/std/std3.txt for more details.
//
// This option corresponds to the UseSTD3ASCIIRules flag in UTS #46.
func StrictDomainName(use bool) Option {
return func(o *options) { o.useSTD3Rules = use }
}
// NOTE: the following options pull in tables. The tables should not be linked
// in as long as the options are not used.
// BidiRule enables the Bidi rule as defined in RFC 5893. Any application
// that relies on proper validation of labels should include this rule.
//
// This option corresponds to the CheckBidi flag in UTS #46.
func BidiRule() Option {
return func(o *options) { o.bidirule = bidirule.ValidString }
}
// ValidateForRegistration sets validation options to verify that a given IDN is
// properly formatted for registration as defined by Section 4 of RFC 5891.
func ValidateForRegistration() Option {
return func(o *options) {
o.mapping = validateRegistration
StrictDomainName(true)(o)
ValidateLabels(true)(o)
VerifyDNSLength(true)(o)
BidiRule()(o)
}
}
// MapForLookup sets validation and mapping options such that a given IDN is
// transformed for domain name lookup according to the requirements set out in
// Section 5 of RFC 5891. The mappings follow the recommendations of RFC 5894,
// RFC 5895 and UTS 46. It does not add the Bidi Rule. Use the BidiRule option
// to add this check.
//
// The mappings include normalization and mapping case, width and other
// compatibility mappings.
func MapForLookup() Option {
return func(o *options) {
o.mapping = validateAndMap
StrictDomainName(true)(o)
ValidateLabels(true)(o)
}
}
type options struct {
transitional bool
useSTD3Rules bool
checkHyphens bool
checkJoiners bool
verifyDNSLength bool
removeLeadingDots bool
trie *idnaTrie
// fromPuny calls validation rules when converting A-labels to U-labels.
fromPuny func(p *Profile, s string) error
// mapping implements a validation and mapping step as defined in RFC 5895
// or UTS 46, tailored to, for example, domain registration or lookup.
mapping func(p *Profile, s string) (mapped string, isBidi bool, err error)
// bidirule, if specified, checks whether s conforms to the Bidi Rule
// defined in RFC 5893.
bidirule func(s string) bool
}
// A Profile defines the configuration of an IDNA mapper.
type Profile struct {
options
}
func apply(o *options, opts []Option) {
for _, f := range opts {
f(o)
}
}
// New creates a new Profile.
//
// With no options, the returned Profile is the most permissive and equals the
// Punycode Profile. Options can be passed to further restrict the Profile. The
// MapForLookup and ValidateForRegistration options set a collection of options,
// for lookup and registration purposes respectively, which can be tailored by
// adding more fine-grained options, where later options override earlier
// options.
func New(o ...Option) *Profile {
p := &Profile{}
apply(&p.options, o)
return p
}
// ToASCII converts a domain or domain label to its ASCII form. For example,
// ToASCII("bücher.example.com") is "xn--bcher-kva.example.com", and
// ToASCII("golang") is "golang". If an error is encountered it will return
// an error and a (partially) processed result.
func (p *Profile) ToASCII(s string) (string, error) {
return p.process(s, true)
}
// ToUnicode converts a domain or domain label to its Unicode form. For example,
// ToUnicode("xn--bcher-kva.example.com") is "bücher.example.com", and
// ToUnicode("golang") is "golang". If an error is encountered it will return
// an error and a (partially) processed result.
func (p *Profile) ToUnicode(s string) (string, error) {
pp := *p
pp.transitional = false
return pp.process(s, false)
}
// String reports a string with a description of the profile for debugging
// purposes. The string format may change with different versions.
func (p *Profile) String() string {
s := ""
if p.transitional {
s = "Transitional"
} else {
s = "NonTransitional"
}
if p.useSTD3Rules {
s += ":UseSTD3Rules"
}
if p.checkHyphens {
s += ":CheckHyphens"
}
if p.checkJoiners {
s += ":CheckJoiners"
}
if p.verifyDNSLength {
s += ":VerifyDNSLength"
}
return s
}
var (
// Punycode is a Profile that does raw punycode processing with a minimum
// of validation.
Punycode *Profile = punycode
// Lookup is the recommended profile for looking up domain names, according
// to Section 5 of RFC 5891. The exact configuration of this profile may
// change over time.
Lookup *Profile = lookup
// Display is the recommended profile for displaying domain names.
// The configuration of this profile may change over time.
Display *Profile = display
// Registration is the recommended profile for checking whether a given
// IDN is valid for registration, according to Section 4 of RFC 5891.
Registration *Profile = registration
punycode = &Profile{}
lookup = &Profile{options{
transitional: transitionalLookup,
useSTD3Rules: true,
checkHyphens: true,
checkJoiners: true,
trie: trie,
fromPuny: validateFromPunycode,
mapping: validateAndMap,
bidirule: bidirule.ValidString,
}}
display = &Profile{options{
useSTD3Rules: true,
checkHyphens: true,
checkJoiners: true,
trie: trie,
fromPuny: validateFromPunycode,
mapping: validateAndMap,
bidirule: bidirule.ValidString,
}}
registration = &Profile{options{
useSTD3Rules: true,
verifyDNSLength: true,
checkHyphens: true,
checkJoiners: true,
trie: trie,
fromPuny: validateFromPunycode,
mapping: validateRegistration,
bidirule: bidirule.ValidString,
}}
// TODO: profiles
// Register: recommended for approving domain names: don't do any mappings
// but rather reject on invalid input. Bundle or block deviation characters.
)
type labelError struct{ label, code_ string }
func (e labelError) code() string { return e.code_ }
func (e labelError) Error() string {
return fmt.Sprintf("idna: invalid label %q", e.label)
}
type runeError rune
func (e runeError) code() string { return "P1" }
func (e runeError) Error() string {
return fmt.Sprintf("idna: disallowed rune %U", e)
}
// process implements the algorithm described in section 4 of UTS #46,
// see https://www.unicode.org/reports/tr46.
func (p *Profile) process(s string, toASCII bool) (string, error) {
var err error
var isBidi bool
if p.mapping != nil {
s, isBidi, err = p.mapping(p, s)
}
// Remove leading empty labels.
if p.removeLeadingDots {
for ; len(s) > 0 && s[0] == '.'; s = s[1:] {
}
}
// TODO: allow for a quick check of the tables data.
// It seems like we should only create this error on ToASCII, but the
// UTS 46 conformance tests suggests we should always check this.
if err == nil && p.verifyDNSLength && s == "" {
err = &labelError{s, "A4"}
}
labels := labelIter{orig: s}
for ; !labels.done(); labels.next() {
label := labels.label()
if label == "" {
// Empty labels are not okay. The label iterator skips the last
// label if it is empty.
if err == nil && p.verifyDNSLength {
err = &labelError{s, "A4"}
}
continue
}
if strings.HasPrefix(label, acePrefix) {
u, err2 := decode(label[len(acePrefix):])
if err2 != nil {
if err == nil {
err = err2
}
// Spec says keep the old label.
continue
}
isBidi = isBidi || bidirule.DirectionString(u) != bidi.LeftToRight
labels.set(u)
if err == nil && p.fromPuny != nil {
err = p.fromPuny(p, u)
}
if err == nil {
// This should be called on NonTransitional, according to the
// spec, but that currently does not have any effect. Use the
// original profile to preserve options.
err = p.validateLabel(u)
}
} else if err == nil {
err = p.validateLabel(label)
}
}
if isBidi && p.bidirule != nil && err == nil {
for labels.reset(); !labels.done(); labels.next() {
if !p.bidirule(labels.label()) {
err = &labelError{s, "B"}
break
}
}
}
if toASCII {
for labels.reset(); !labels.done(); labels.next() {
label := labels.label()
if !ascii(label) {
a, err2 := encode(acePrefix, label)
if err == nil {
err = err2
}
label = a
labels.set(a)
}
n := len(label)
if p.verifyDNSLength && err == nil && (n == 0 || n > 63) {
err = &labelError{label, "A4"}
}
}
}
s = labels.result()
if toASCII && p.verifyDNSLength && err == nil {
// Compute the length of the domain name minus the root label and its dot.
n := len(s)
if n > 0 && s[n-1] == '.' {
n--
}
if len(s) < 1 || n > 253 {
err = &labelError{s, "A4"}
}
}
return s, err
}
func normalize(p *Profile, s string) (mapped string, isBidi bool, err error) {
// TODO: consider first doing a quick check to see if any of these checks
// need to be done. This will make it slower in the general case, but
// faster in the common case.
mapped = norm.NFC.String(s)
isBidi = bidirule.DirectionString(mapped) == bidi.RightToLeft
return mapped, isBidi, nil
}
func validateRegistration(p *Profile, s string) (idem string, bidi bool, err error) {
// TODO: filter need for normalization in loop below.
if !norm.NFC.IsNormalString(s) {
return s, false, &labelError{s, "V1"}
}
for i := 0; i < len(s); {
v, sz := trie.lookupString(s[i:])
if sz == 0 {
return s, bidi, runeError(utf8.RuneError)
}
bidi = bidi || info(v).isBidi(s[i:])
// Copy bytes not copied so far.
switch p.simplify(info(v).category()) {
// TODO: handle the NV8 defined in the Unicode idna data set to allow
// for strict conformance to IDNA2008.
case valid, deviation:
case disallowed, mapped, unknown, ignored:
r, _ := utf8.DecodeRuneInString(s[i:])
return s, bidi, runeError(r)
}
i += sz
}
return s, bidi, nil
}
func (c info) isBidi(s string) bool {
if !c.isMapped() {
return c&attributesMask == rtl
}
// TODO: also store bidi info for mapped data. This is possible, but a bit
// cumbersome and not for the common case.
p, _ := bidi.LookupString(s)
switch p.Class() {
case bidi.R, bidi.AL, bidi.AN:
return true
}
return false
}
func validateAndMap(p *Profile, s string) (vm string, bidi bool, err error) {
var (
b []byte
k int
)
// combinedInfoBits contains the or-ed bits of all runes. We use this
// to derive the mayNeedNorm bit later. This may trigger normalization
// overeagerly, but it will not do so in the common case. The end result
// is another 10% saving on BenchmarkProfile for the common case.
var combinedInfoBits info
for i := 0; i < len(s); {
v, sz := trie.lookupString(s[i:])
if sz == 0 {
b = append(b, s[k:i]...)
b = append(b, "\ufffd"...)
k = len(s)
if err == nil {
err = runeError(utf8.RuneError)
}
break
}
combinedInfoBits |= info(v)
bidi = bidi || info(v).isBidi(s[i:])
start := i
i += sz
// Copy bytes not copied so far.
switch p.simplify(info(v).category()) {
case valid:
continue
case disallowed:
if err == nil {
r, _ := utf8.DecodeRuneInString(s[start:])
err = runeError(r)
}
continue
case mapped, deviation:
b = append(b, s[k:start]...)
b = info(v).appendMapping(b, s[start:i])
case ignored:
b = append(b, s[k:start]...)
// drop the rune
case unknown:
b = append(b, s[k:start]...)
b = append(b, "\ufffd"...)
}
k = i
}
if k == 0 {
// No changes so far.
if combinedInfoBits&mayNeedNorm != 0 {
s = norm.NFC.String(s)
}
} else {
b = append(b, s[k:]...)
if norm.NFC.QuickSpan(b) != len(b) {
b = norm.NFC.Bytes(b)
}
// TODO: the punycode converters require strings as input.
s = string(b)
}
return s, bidi, err
}
// A labelIter allows iterating over domain name labels.
type labelIter struct {
orig string
slice []string
curStart int
curEnd int
i int
}
func (l *labelIter) reset() {
l.curStart = 0
l.curEnd = 0
l.i = 0
}
func (l *labelIter) done() bool {
return l.curStart >= len(l.orig)
}
func (l *labelIter) result() string {
if l.slice != nil {
return strings.Join(l.slice, ".")
}
return l.orig
}
func (l *labelIter) label() string {
if l.slice != nil {
return l.slice[l.i]
}
p := strings.IndexByte(l.orig[l.curStart:], '.')
l.curEnd = l.curStart + p
if p == -1 {
l.curEnd = len(l.orig)
}
return l.orig[l.curStart:l.curEnd]
}
// next sets the value to the next label. It skips the last label if it is empty.
func (l *labelIter) next() {
l.i++
if l.slice != nil {
if l.i >= len(l.slice) || l.i == len(l.slice)-1 && l.slice[l.i] == "" {
l.curStart = len(l.orig)
}
} else {
l.curStart = l.curEnd + 1
if l.curStart == len(l.orig)-1 && l.orig[l.curStart] == '.' {
l.curStart = len(l.orig)
}
}
}
func (l *labelIter) set(s string) {
if l.slice == nil {
l.slice = strings.Split(l.orig, ".")
}
l.slice[l.i] = s
}
// acePrefix is the ASCII Compatible Encoding prefix.
const acePrefix = "xn--"
func (p *Profile) simplify(cat category) category {
switch cat {
case disallowedSTD3Mapped:
if p.useSTD3Rules {
cat = disallowed
} else {
cat = mapped
}
case disallowedSTD3Valid:
if p.useSTD3Rules {
cat = disallowed
} else {
cat = valid
}
case deviation:
if !p.transitional {
cat = valid
}
case validNV8, validXV8:
// TODO: handle V2008
cat = valid
}
return cat
}
func validateFromPunycode(p *Profile, s string) error {
if !norm.NFC.IsNormalString(s) {
return &labelError{s, "V1"}
}
// TODO: detect whether string may have to be normalized in the following
// loop.
for i := 0; i < len(s); {
v, sz := trie.lookupString(s[i:])
if sz == 0 {
return runeError(utf8.RuneError)
}
if c := p.simplify(info(v).category()); c != valid && c != deviation {
return &labelError{s, "V6"}
}
i += sz
}
return nil
}
const (
zwnj = "\u200c"
zwj = "\u200d"
)
type joinState int8
const (
stateStart joinState = iota
stateVirama
stateBefore
stateBeforeVirama
stateAfter
stateFAIL
)
var joinStates = [][numJoinTypes]joinState{
stateStart: {
joiningL: stateBefore,
joiningD: stateBefore,
joinZWNJ: stateFAIL,
joinZWJ: stateFAIL,
joinVirama: stateVirama,
},
stateVirama: {
joiningL: stateBefore,
joiningD: stateBefore,
},
stateBefore: {
joiningL: stateBefore,
joiningD: stateBefore,
joiningT: stateBefore,
joinZWNJ: stateAfter,
joinZWJ: stateFAIL,
joinVirama: stateBeforeVirama,
},
stateBeforeVirama: {
joiningL: stateBefore,
joiningD: stateBefore,
joiningT: stateBefore,
},
stateAfter: {
joiningL: stateFAIL,
joiningD: stateBefore,
joiningT: stateAfter,
joiningR: stateStart,
joinZWNJ: stateFAIL,
joinZWJ: stateFAIL,
joinVirama: stateAfter, // no-op as we can't accept joiners here
},
stateFAIL: {
0: stateFAIL,
joiningL: stateFAIL,
joiningD: stateFAIL,
joiningT: stateFAIL,
joiningR: stateFAIL,
joinZWNJ: stateFAIL,
joinZWJ: stateFAIL,
joinVirama: stateFAIL,
},
}
// validateLabel validates the criteria from Section 4.1. Item 1, 4, and 6 are
// already implicitly satisfied by the overall implementation.
func (p *Profile) validateLabel(s string) (err error) {
if s == "" {
if p.verifyDNSLength {
return &labelError{s, "A4"}
}
return nil
}
if p.checkHyphens {
if len(s) > 4 && s[2] == '-' && s[3] == '-' {
return &labelError{s, "V2"}
}
if s[0] == '-' || s[len(s)-1] == '-' {
return &labelError{s, "V3"}
}
}
if !p.checkJoiners {
return nil
}
trie := p.trie // p.checkJoiners is only set if trie is set.
// TODO: merge the use of this in the trie.
v, sz := trie.lookupString(s)
x := info(v)
if x.isModifier() {
return &labelError{s, "V5"}
}
// Quickly return in the absence of zero-width (non) joiners.
if strings.Index(s, zwj) == -1 && strings.Index(s, zwnj) == -1 {
return nil
}
st := stateStart
for i := 0; ; {
jt := x.joinType()
if s[i:i+sz] == zwj {
jt = joinZWJ
} else if s[i:i+sz] == zwnj {
jt = joinZWNJ
}
st = joinStates[st][jt]
if x.isViramaModifier() {
st = joinStates[st][joinVirama]
}
if i += sz; i == len(s) {
break
}
v, sz = trie.lookupString(s[i:])
x = info(v)
}
if st == stateFAIL || st == stateAfter {
return &labelError{s, "C"}
}
return nil
}
func ascii(s string) bool {
for i := 0; i < len(s); i++ {
if s[i] >= utf8.RuneSelf {
return false
}
}
return true
}
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
// 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.
package idna
// This file implements the Punycode algorithm from RFC 3492.
import (
"math"
"strings"
"unicode/utf8"
)
// These parameter values are specified in section 5.
//
// All computation is done with int32s, so that overflow behavior is identical
// regardless of whether int is 32-bit or 64-bit.
const (
base int32 = 36
damp int32 = 700
initialBias int32 = 72
initialN int32 = 128
skew int32 = 38
tmax int32 = 26
tmin int32 = 1
)
func punyError(s string) error { return &labelError{s, "A3"} }
// decode decodes a string as specified in section 6.2.
func decode(encoded string) (string, error) {
if encoded == "" {
return "", nil
}
pos := 1 + strings.LastIndex(encoded, "-")
if pos == 1 {
return "", punyError(encoded)
}
if pos == len(encoded) {
return encoded[:len(encoded)-1], nil
}
output := make([]rune, 0, len(encoded))
if pos != 0 {
for _, r := range encoded[:pos-1] {
output = append(output, r)
}
}
i, n, bias := int32(0), initialN, initialBias
overflow := false
for pos < len(encoded) {
oldI, w := i, int32(1)
for k := base; ; k += base {
if pos == len(encoded) {
return "", punyError(encoded)
}
digit, ok := decodeDigit(encoded[pos])
if !ok {
return "", punyError(encoded)
}
pos++
i, overflow = madd(i, digit, w)
if overflow {
return "", punyError(encoded)
}
t := k - bias
if k <= bias {
t = tmin
} else if k >= bias+tmax {
t = tmax
}
if digit < t {
break
}
w, overflow = madd(0, w, base-t)
if overflow {
return "", punyError(encoded)
}
}
if len(output) >= 1024 {
return "", punyError(encoded)
}
x := int32(len(output) + 1)
bias = adapt(i-oldI, x, oldI == 0)
n += i / x
i %= x
if n < 0 || n > utf8.MaxRune {
return "", punyError(encoded)
}
output = append(output, 0)
copy(output[i+1:], output[i:])
output[i] = n
i++
}
return string(output), nil
}
// encode encodes a string as specified in section 6.3 and prepends prefix to
// the result.
//
// The "while h < length(input)" line in the specification becomes "for
// remaining != 0" in the Go code, because len(s) in Go is in bytes, not runes.
func encode(prefix, s string) (string, error) {
output := make([]byte, len(prefix), len(prefix)+1+2*len(s))
copy(output, prefix)
delta, n, bias := int32(0), initialN, initialBias
b, remaining := int32(0), int32(0)
for _, r := range s {
if r < 0x80 {
b++
output = append(output, byte(r))
} else {
remaining++
}
}
h := b
if b > 0 {
output = append(output, '-')
}
overflow := false
for remaining != 0 {
m := int32(0x7fffffff)
for _, r := range s {
if m > r && r >= n {
m = r
}
}
delta, overflow = madd(delta, m-n, h+1)
if overflow {
return "", punyError(s)
}
n = m
for _, r := range s {
if r < n {
delta++
if delta < 0 {
return "", punyError(s)
}
continue
}
if r > n {
continue
}
q := delta
for k := base; ; k += base {
t := k - bias
if k <= bias {
t = tmin
} else if k >= bias+tmax {
t = tmax
}
if q < t {
break
}
output = append(output, encodeDigit(t+(q-t)%(base-t)))
q = (q - t) / (base - t)
}
output = append(output, encodeDigit(q))
bias = adapt(delta, h+1, h == b)
delta = 0
h++
remaining--
}
delta++
n++
}
return string(output), nil
}
// madd computes a + (b * c), detecting overflow.
func madd(a, b, c int32) (next int32, overflow bool) {
p := int64(b) * int64(c)
if p > math.MaxInt32-int64(a) {
return 0, true
}
return a + int32(p), false
}
func decodeDigit(x byte) (digit int32, ok bool) {
switch {
case '0' <= x && x <= '9':
return int32(x - ('0' - 26)), true
case 'A' <= x && x <= 'Z':
return int32(x - 'A'), true
case 'a' <= x && x <= 'z':
return int32(x - 'a'), true
}
return 0, false
}
func encodeDigit(digit int32) byte {
switch {
case 0 <= digit && digit < 26:
return byte(digit + 'a')
case 26 <= digit && digit < 36:
return byte(digit + ('0' - 26))
}
panic("idna: internal error in punycode encoding")
}
// adapt is the bias adaptation function specified in section 6.1.
func adapt(delta, numPoints int32, firstTime bool) int32 {
if firstTime {
delta /= damp
} else {
delta /= 2
}
delta += delta / numPoints
k := int32(0)
for delta > ((base-tmin)*tmax)/2 {
delta /= base - tmin
k += base
}
return k + (base-tmin+1)*delta/(delta+skew)
}
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.21
package idna
// UnicodeVersion is the Unicode version from which the tables in this package are derived.
const UnicodeVersion = "15.0.0"
var mappings string = "" + // Size: 6704 bytes
" ̈a ̄23 ́ ̧1o1⁄41⁄23⁄4i̇l·ʼnsdžⱥⱦhjrwy ̆ ̇ ̊ ̨ ̃ ̋lẍ́ ι; ̈́եւاٴوٴۇٴيٴक" +
"़ख़ग़ज़ड़ढ़फ़य़ড়ঢ়য়ਲ਼ਸ਼ਖ਼ਗ਼ਜ਼ਫ਼ଡ଼ଢ଼ําໍາຫນຫມགྷཌྷདྷབྷཛྷཀྵཱཱིུྲྀྲཱྀླྀླཱ" +
"ཱྀྀྒྷྜྷྡྷྦྷྫྷྐྵвдостъѣæbdeǝgikmnȣptuɐɑəɛɜŋɔɯvβγδφχρнɒcɕðfɟɡɥɨɩɪʝɭʟɱɰɲɳ" +
"ɴɵɸʂʃƫʉʊʋʌzʐʑʒθssάέήίόύώἀιἁιἂιἃιἄιἅιἆιἇιἠιἡιἢιἣιἤιἥιἦιἧιὠιὡιὢιὣιὤιὥιὦιὧ" +
"ιὰιαιάιᾶιι ̈͂ὴιηιήιῆι ̓̀ ̓́ ̓͂ΐ ̔̀ ̔́ ̔͂ΰ ̈̀`ὼιωιώιῶι′′′′′‵‵‵‵‵!!???!!?" +
"′′′′0456789+=()rsħnoqsmtmωåאבגדπ1⁄71⁄91⁄101⁄32⁄31⁄52⁄53⁄54⁄51⁄65⁄61⁄83" +
"⁄85⁄87⁄81⁄iiivviviiiixxi0⁄3∫∫∫∫∫∮∮∮∮∮1011121314151617181920(10)(11)(12" +
")(13)(14)(15)(16)(17)(18)(19)(20)∫∫∫∫==⫝̸ɫɽȿɀ. ゙ ゚よりコト(ᄀ)(ᄂ)(ᄃ)(ᄅ)(ᄆ)(ᄇ)" +
"(ᄉ)(ᄋ)(ᄌ)(ᄎ)(ᄏ)(ᄐ)(ᄑ)(ᄒ)(가)(나)(다)(라)(마)(바)(사)(아)(자)(차)(카)(타)(파)(하)(주)(오전" +
")(오후)(一)(二)(三)(四)(五)(六)(七)(八)(九)(十)(月)(火)(水)(木)(金)(土)(日)(株)(有)(社)(名)(特)(" +
"財)(祝)(労)(代)(呼)(学)(監)(企)(資)(協)(祭)(休)(自)(至)21222324252627282930313233343" +
"5참고주의3637383940414243444546474849501月2月3月4月5月6月7月8月9月10月11月12月hgev令和アパート" +
"アルファアンペアアールイニングインチウォンエスクードエーカーオンスオームカイリカラットカロリーガロンガンマギガギニーキュリーギルダーキロキロ" +
"グラムキロメートルキロワットグラムグラムトンクルゼイロクローネケースコルナコーポサイクルサンチームシリングセンチセントダースデシドルトンナノ" +
"ノットハイツパーセントパーツバーレルピアストルピクルピコビルファラッドフィートブッシェルフランヘクタールペソペニヒヘルツペンスページベータポ" +
"イントボルトホンポンドホールホーンマイクロマイルマッハマルクマンションミクロンミリミリバールメガメガトンメートルヤードヤールユアンリットルリ" +
"ラルピールーブルレムレントゲンワット0点1点2点3点4点5点6点7点8点9点10点11点12点13点14点15点16点17点18点19点20" +
"点21点22点23点24点daauovpcdmiu平成昭和大正明治株式会社panamakakbmbgbkcalpfnfmgkghzmldlk" +
"lfmnmmmcmkmm2m3m∕sm∕s2rad∕srad∕s2psnsmspvnvmvkvpwnwmwkwbqcccdc∕kgdbgyhah" +
"pinkkktlmlnlxphprsrsvwbv∕ma∕m1日2日3日4日5日6日7日8日9日10日11日12日13日14日15日16日17日1" +
"8日19日20日21日22日23日24日25日26日27日28日29日30日31日ьɦɬʞʇœʍ𤋮𢡊𢡄𣏕𥉉𥳐𧻓fffiflstմնմեմիվնմ" +
"խיִײַעהכלםרתשׁשׂשּׁשּׂאַאָאּבּגּדּהּוּזּטּיּךּכּלּמּנּסּףּפּצּקּרּשּתּו" +
"ֹבֿכֿפֿאלٱٻپڀٺٿٹڤڦڄڃچڇڍڌڎڈژڑکگڳڱںڻۀہھےۓڭۇۆۈۋۅۉېىئائەئوئۇئۆئۈئېئىیئجئحئم" +
"ئيبجبحبخبمبىبيتجتحتختمتىتيثجثمثىثيجحجمحجحمخجخحخمسجسحسخسمصحصمضجضحضخضمطحط" +
"مظمعجعمغجغمفجفحفخفمفىفيقحقمقىقيكاكجكحكخكلكمكىكيلجلحلخلملىليمجمحمخمممىمي" +
"نجنحنخنمنىنيهجهمهىهييجيحيخيميىييذٰرٰىٰ ٌّ ٍّ َّ ُّ ِّ ّٰئرئزئنبربزبنترت" +
"زتنثرثزثنمانرنزننيريزينئخئهبهتهصخلهنههٰيهثهسهشمشهـَّـُّـِّطىطيعىعيغىغيس" +
"ىسيشىشيحىحيجىجيخىخيصىصيضىضيشجشحشخشرسرصرضراًتجمتحجتحمتخمتمجتمحتمخجمححميح" +
"مىسحجسجحسجىسمحسمجسممصححصممشحمشجيشمخشممضحىضخمطمحطممطميعجمعممعمىغممغميغمى" +
"فخمقمحقمملحملحيلحىلججلخملمحمحجمحممحيمجحمجممخجمخممجخهمجهممنحمنحىنجمنجىنم" +
"ينمىيممبخيتجيتجىتخيتخىتميتمىجميجحىجمىسخىصحيشحيضحيلجيلمييحييجييميمميقمين" +
"حيعميكمينجحمخيلجمكممجحيحجيمجيفميبحيسخينجيصلےقلےاللهاكبرمحمدصلعمرسولعليه" +
"وسلمصلىصلى الله عليه وسلمجل جلالهریال,:!?_{}[]#&*-<>\\$%@ـًـَـُـِـّـْءآ" +
"أؤإئابةتثجحخدذرزسشصضطظعغفقكلمنهويلآلألإلا\x22'/^|~¢£¬¦¥ːˑʙɓʣꭦʥʤɖɗᶑɘɞʩɤɢ" +
"ɠʛʜɧʄʪʫꞎɮʎøɶɷɺɾʀʨʦꭧʧʈⱱʏʡʢʘǀǁǂ𝅗𝅥𝅘𝅥𝅘𝅥𝅮𝅘𝅥𝅯𝅘𝅥𝅰𝅘𝅥𝅱𝅘𝅥𝅲𝆹𝅥𝆺𝅥𝆹𝅥𝅮𝆺𝅥𝅮𝆹𝅥𝅯𝆺𝅥𝅯ıȷαεζηκ" +
"λμνξοστυψ∇∂ϝабгежзиклмпруфхцчшыэюꚉәіјөүӏґѕџҫꙑұٮڡٯ0,1,2,3,4,5,6,7,8,9,(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)〔s〕wzhvsdppvwcmcmdmrdjほかココサ手字双デ二多解天交映無料前後再新初終生販声吹演投捕一三遊左中右指走打禁空合満有月申" +
"割営配〔本〕〔三〕〔二〕〔安〕〔点〕〔打〕〔盗〕〔勝〕〔敗〕得可丽丸乁你侮侻倂偺備僧像㒞免兔兤具㒹內冗冤仌冬况凵刃㓟刻剆剷㔕勇勉勤勺包匆北卉" +
"卑博即卽卿灰及叟叫叱吆咞吸呈周咢哶唐啓啣善喙喫喳嗂圖嘆圗噑噴切壮城埴堍型堲報墬売壷夆夢奢姬娛娧姘婦㛮嬈嬾寃寘寧寳寿将尢㞁屠屮峀岍嵃嵮嵫嵼巡巢" +
"㠯巽帨帽幩㡢㡼庰庳庶廊廾舁弢㣇形彫㣣徚忍志忹悁㤺㤜悔惇慈慌慎慺憎憲憤憯懞懲懶成戛扝抱拔捐挽拼捨掃揤搢揅掩㨮摩摾撝摷㩬敏敬旣書晉㬙暑㬈㫤冒冕最" +
"暜肭䏙朗望朡杞杓㭉柺枅桒梅梎栟椔㮝楂榣槪檨櫛㰘次歔㱎歲殟殺殻汎沿泍汧洖派海流浩浸涅洴港湮㴳滋滇淹潮濆瀹瀞瀛㶖灊災灷炭煅熜爨爵牐犀犕獺王㺬玥㺸" +
"瑇瑜瑱璅瓊㼛甤甾異瘐㿼䀈直眞真睊䀹瞋䁆䂖硎碌磌䃣祖福秫䄯穀穊穏䈂篆築䈧糒䊠糨糣紀絣䌁緇縂繅䌴䍙罺羕翺者聠聰䏕育脃䐋脾媵舄辞䑫芑芋芝劳花芳芽苦" +
"若茝荣莭茣莽菧著荓菊菌菜䔫蓱蓳蔖蕤䕝䕡䕫虐虜虧虩蚩蚈蜎蛢蝹蜨蝫螆蟡蠁䗹衠衣裗裞䘵裺㒻䚾䛇誠諭變豕貫賁贛起跋趼跰軔輸邔郱鄑鄛鈸鋗鋘鉼鏹鐕開䦕閷" +
"䧦雃嶲霣䩮䩶韠䪲頋頩飢䬳餩馧駂駾䯎鬒鱀鳽䳎䳭鵧䳸麻䵖黹黾鼅鼏鼖鼻"
var mappingIndex = []uint16{ // 1729 elements
// Entry 0 - 3F
0x0000, 0x0000, 0x0001, 0x0004, 0x0005, 0x0008, 0x0009, 0x000a,
0x000d, 0x0010, 0x0011, 0x0012, 0x0017, 0x001c, 0x0021, 0x0024,
0x0027, 0x002a, 0x002b, 0x002e, 0x0031, 0x0034, 0x0035, 0x0036,
0x0037, 0x0038, 0x0039, 0x003c, 0x003f, 0x0042, 0x0045, 0x0048,
0x004b, 0x004c, 0x004d, 0x0051, 0x0054, 0x0055, 0x005a, 0x005e,
0x0062, 0x0066, 0x006a, 0x006e, 0x0074, 0x007a, 0x0080, 0x0086,
0x008c, 0x0092, 0x0098, 0x009e, 0x00a4, 0x00aa, 0x00b0, 0x00b6,
0x00bc, 0x00c2, 0x00c8, 0x00ce, 0x00d4, 0x00da, 0x00e0, 0x00e6,
// Entry 40 - 7F
0x00ec, 0x00f2, 0x00f8, 0x00fe, 0x0104, 0x010a, 0x0110, 0x0116,
0x011c, 0x0122, 0x0128, 0x012e, 0x0137, 0x013d, 0x0146, 0x014c,
0x0152, 0x0158, 0x015e, 0x0164, 0x016a, 0x0170, 0x0172, 0x0174,
0x0176, 0x0178, 0x017a, 0x017c, 0x017e, 0x0180, 0x0181, 0x0182,
0x0183, 0x0185, 0x0186, 0x0187, 0x0188, 0x0189, 0x018a, 0x018c,
0x018d, 0x018e, 0x018f, 0x0191, 0x0193, 0x0195, 0x0197, 0x0199,
0x019b, 0x019d, 0x019f, 0x01a0, 0x01a2, 0x01a4, 0x01a6, 0x01a8,
0x01aa, 0x01ac, 0x01ae, 0x01b0, 0x01b1, 0x01b3, 0x01b5, 0x01b6,
// Entry 80 - BF
0x01b8, 0x01ba, 0x01bc, 0x01be, 0x01c0, 0x01c2, 0x01c4, 0x01c6,
0x01c8, 0x01ca, 0x01cc, 0x01ce, 0x01d0, 0x01d2, 0x01d4, 0x01d6,
0x01d8, 0x01da, 0x01dc, 0x01de, 0x01e0, 0x01e2, 0x01e4, 0x01e5,
0x01e7, 0x01e9, 0x01eb, 0x01ed, 0x01ef, 0x01f1, 0x01f3, 0x01f5,
0x01f7, 0x01f9, 0x01fb, 0x01fd, 0x0202, 0x0207, 0x020c, 0x0211,
0x0216, 0x021b, 0x0220, 0x0225, 0x022a, 0x022f, 0x0234, 0x0239,
0x023e, 0x0243, 0x0248, 0x024d, 0x0252, 0x0257, 0x025c, 0x0261,
0x0266, 0x026b, 0x0270, 0x0275, 0x027a, 0x027e, 0x0282, 0x0287,
// Entry C0 - FF
0x0289, 0x028e, 0x0293, 0x0297, 0x029b, 0x02a0, 0x02a5, 0x02aa,
0x02af, 0x02b1, 0x02b6, 0x02bb, 0x02c0, 0x02c2, 0x02c7, 0x02c8,
0x02cd, 0x02d1, 0x02d5, 0x02da, 0x02e0, 0x02e9, 0x02ef, 0x02f8,
0x02fa, 0x02fc, 0x02fe, 0x0300, 0x030c, 0x030d, 0x030e, 0x030f,
0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317,
0x0319, 0x031b, 0x031d, 0x031e, 0x0320, 0x0322, 0x0324, 0x0326,
0x0328, 0x032a, 0x032c, 0x032e, 0x0330, 0x0335, 0x033a, 0x0340,
0x0345, 0x034a, 0x034f, 0x0354, 0x0359, 0x035e, 0x0363, 0x0368,
// Entry 100 - 13F
0x036d, 0x0372, 0x0377, 0x037c, 0x0380, 0x0382, 0x0384, 0x0386,
0x038a, 0x038c, 0x038e, 0x0393, 0x0399, 0x03a2, 0x03a8, 0x03b1,
0x03b3, 0x03b5, 0x03b7, 0x03b9, 0x03bb, 0x03bd, 0x03bf, 0x03c1,
0x03c3, 0x03c5, 0x03c7, 0x03cb, 0x03cf, 0x03d3, 0x03d7, 0x03db,
0x03df, 0x03e3, 0x03e7, 0x03eb, 0x03ef, 0x03f3, 0x03ff, 0x0401,
0x0406, 0x0408, 0x040a, 0x040c, 0x040e, 0x040f, 0x0413, 0x0417,
0x041d, 0x0423, 0x0428, 0x042d, 0x0432, 0x0437, 0x043c, 0x0441,
0x0446, 0x044b, 0x0450, 0x0455, 0x045a, 0x045f, 0x0464, 0x0469,
// Entry 140 - 17F
0x046e, 0x0473, 0x0478, 0x047d, 0x0482, 0x0487, 0x048c, 0x0491,
0x0496, 0x049b, 0x04a0, 0x04a5, 0x04aa, 0x04af, 0x04b4, 0x04bc,
0x04c4, 0x04c9, 0x04ce, 0x04d3, 0x04d8, 0x04dd, 0x04e2, 0x04e7,
0x04ec, 0x04f1, 0x04f6, 0x04fb, 0x0500, 0x0505, 0x050a, 0x050f,
0x0514, 0x0519, 0x051e, 0x0523, 0x0528, 0x052d, 0x0532, 0x0537,
0x053c, 0x0541, 0x0546, 0x054b, 0x0550, 0x0555, 0x055a, 0x055f,
0x0564, 0x0569, 0x056e, 0x0573, 0x0578, 0x057a, 0x057c, 0x057e,
0x0580, 0x0582, 0x0584, 0x0586, 0x0588, 0x058a, 0x058c, 0x058e,
// Entry 180 - 1BF
0x0590, 0x0592, 0x0594, 0x0596, 0x059c, 0x05a2, 0x05a4, 0x05a6,
0x05a8, 0x05aa, 0x05ac, 0x05ae, 0x05b0, 0x05b2, 0x05b4, 0x05b6,
0x05b8, 0x05ba, 0x05bc, 0x05be, 0x05c0, 0x05c4, 0x05c8, 0x05cc,
0x05d0, 0x05d4, 0x05d8, 0x05dc, 0x05e0, 0x05e4, 0x05e9, 0x05ee,
0x05f3, 0x05f5, 0x05f7, 0x05fd, 0x0609, 0x0615, 0x0621, 0x062a,
0x0636, 0x063f, 0x0648, 0x0657, 0x0663, 0x066c, 0x0675, 0x067e,
0x068a, 0x0696, 0x069f, 0x06a8, 0x06ae, 0x06b7, 0x06c3, 0x06cf,
0x06d5, 0x06e4, 0x06f6, 0x0705, 0x070e, 0x071d, 0x072c, 0x0738,
// Entry 1C0 - 1FF
0x0741, 0x074a, 0x0753, 0x075f, 0x076e, 0x077a, 0x0783, 0x078c,
0x0795, 0x079b, 0x07a1, 0x07a7, 0x07ad, 0x07b6, 0x07bf, 0x07ce,
0x07d7, 0x07e3, 0x07f2, 0x07fb, 0x0801, 0x0807, 0x0816, 0x0822,
0x0831, 0x083a, 0x0849, 0x084f, 0x0858, 0x0861, 0x086a, 0x0873,
0x087c, 0x0888, 0x0891, 0x0897, 0x08a0, 0x08a9, 0x08b2, 0x08be,
0x08c7, 0x08d0, 0x08d9, 0x08e8, 0x08f4, 0x08fa, 0x0909, 0x090f,
0x091b, 0x0927, 0x0930, 0x0939, 0x0942, 0x094e, 0x0954, 0x095d,
0x0969, 0x096f, 0x097e, 0x0987, 0x098b, 0x098f, 0x0993, 0x0997,
// Entry 200 - 23F
0x099b, 0x099f, 0x09a3, 0x09a7, 0x09ab, 0x09af, 0x09b4, 0x09b9,
0x09be, 0x09c3, 0x09c8, 0x09cd, 0x09d2, 0x09d7, 0x09dc, 0x09e1,
0x09e6, 0x09eb, 0x09f0, 0x09f5, 0x09fa, 0x09fc, 0x09fe, 0x0a00,
0x0a02, 0x0a04, 0x0a06, 0x0a0c, 0x0a12, 0x0a18, 0x0a1e, 0x0a2a,
0x0a2c, 0x0a2e, 0x0a30, 0x0a32, 0x0a34, 0x0a36, 0x0a38, 0x0a3c,
0x0a3e, 0x0a40, 0x0a42, 0x0a44, 0x0a46, 0x0a48, 0x0a4a, 0x0a4c,
0x0a4e, 0x0a50, 0x0a52, 0x0a54, 0x0a56, 0x0a58, 0x0a5a, 0x0a5f,
0x0a65, 0x0a6c, 0x0a74, 0x0a76, 0x0a78, 0x0a7a, 0x0a7c, 0x0a7e,
// Entry 240 - 27F
0x0a80, 0x0a82, 0x0a84, 0x0a86, 0x0a88, 0x0a8a, 0x0a8c, 0x0a8e,
0x0a90, 0x0a96, 0x0a98, 0x0a9a, 0x0a9c, 0x0a9e, 0x0aa0, 0x0aa2,
0x0aa4, 0x0aa6, 0x0aa8, 0x0aaa, 0x0aac, 0x0aae, 0x0ab0, 0x0ab2,
0x0ab4, 0x0ab9, 0x0abe, 0x0ac2, 0x0ac6, 0x0aca, 0x0ace, 0x0ad2,
0x0ad6, 0x0ada, 0x0ade, 0x0ae2, 0x0ae7, 0x0aec, 0x0af1, 0x0af6,
0x0afb, 0x0b00, 0x0b05, 0x0b0a, 0x0b0f, 0x0b14, 0x0b19, 0x0b1e,
0x0b23, 0x0b28, 0x0b2d, 0x0b32, 0x0b37, 0x0b3c, 0x0b41, 0x0b46,
0x0b4b, 0x0b50, 0x0b52, 0x0b54, 0x0b56, 0x0b58, 0x0b5a, 0x0b5c,
// Entry 280 - 2BF
0x0b5e, 0x0b62, 0x0b66, 0x0b6a, 0x0b6e, 0x0b72, 0x0b76, 0x0b7a,
0x0b7c, 0x0b7e, 0x0b80, 0x0b82, 0x0b86, 0x0b8a, 0x0b8e, 0x0b92,
0x0b96, 0x0b9a, 0x0b9e, 0x0ba0, 0x0ba2, 0x0ba4, 0x0ba6, 0x0ba8,
0x0baa, 0x0bac, 0x0bb0, 0x0bb4, 0x0bba, 0x0bc0, 0x0bc4, 0x0bc8,
0x0bcc, 0x0bd0, 0x0bd4, 0x0bd8, 0x0bdc, 0x0be0, 0x0be4, 0x0be8,
0x0bec, 0x0bf0, 0x0bf4, 0x0bf8, 0x0bfc, 0x0c00, 0x0c04, 0x0c08,
0x0c0c, 0x0c10, 0x0c14, 0x0c18, 0x0c1c, 0x0c20, 0x0c24, 0x0c28,
0x0c2c, 0x0c30, 0x0c34, 0x0c36, 0x0c38, 0x0c3a, 0x0c3c, 0x0c3e,
// Entry 2C0 - 2FF
0x0c40, 0x0c42, 0x0c44, 0x0c46, 0x0c48, 0x0c4a, 0x0c4c, 0x0c4e,
0x0c50, 0x0c52, 0x0c54, 0x0c56, 0x0c58, 0x0c5a, 0x0c5c, 0x0c5e,
0x0c60, 0x0c62, 0x0c64, 0x0c66, 0x0c68, 0x0c6a, 0x0c6c, 0x0c6e,
0x0c70, 0x0c72, 0x0c74, 0x0c76, 0x0c78, 0x0c7a, 0x0c7c, 0x0c7e,
0x0c80, 0x0c82, 0x0c86, 0x0c8a, 0x0c8e, 0x0c92, 0x0c96, 0x0c9a,
0x0c9e, 0x0ca2, 0x0ca4, 0x0ca8, 0x0cac, 0x0cb0, 0x0cb4, 0x0cb8,
0x0cbc, 0x0cc0, 0x0cc4, 0x0cc8, 0x0ccc, 0x0cd0, 0x0cd4, 0x0cd8,
0x0cdc, 0x0ce0, 0x0ce4, 0x0ce8, 0x0cec, 0x0cf0, 0x0cf4, 0x0cf8,
// Entry 300 - 33F
0x0cfc, 0x0d00, 0x0d04, 0x0d08, 0x0d0c, 0x0d10, 0x0d14, 0x0d18,
0x0d1c, 0x0d20, 0x0d24, 0x0d28, 0x0d2c, 0x0d30, 0x0d34, 0x0d38,
0x0d3c, 0x0d40, 0x0d44, 0x0d48, 0x0d4c, 0x0d50, 0x0d54, 0x0d58,
0x0d5c, 0x0d60, 0x0d64, 0x0d68, 0x0d6c, 0x0d70, 0x0d74, 0x0d78,
0x0d7c, 0x0d80, 0x0d84, 0x0d88, 0x0d8c, 0x0d90, 0x0d94, 0x0d98,
0x0d9c, 0x0da0, 0x0da4, 0x0da8, 0x0dac, 0x0db0, 0x0db4, 0x0db8,
0x0dbc, 0x0dc0, 0x0dc4, 0x0dc8, 0x0dcc, 0x0dd0, 0x0dd4, 0x0dd8,
0x0ddc, 0x0de0, 0x0de4, 0x0de8, 0x0dec, 0x0df0, 0x0df4, 0x0df8,
// Entry 340 - 37F
0x0dfc, 0x0e00, 0x0e04, 0x0e08, 0x0e0c, 0x0e10, 0x0e14, 0x0e18,
0x0e1d, 0x0e22, 0x0e27, 0x0e2c, 0x0e31, 0x0e36, 0x0e3a, 0x0e3e,
0x0e42, 0x0e46, 0x0e4a, 0x0e4e, 0x0e52, 0x0e56, 0x0e5a, 0x0e5e,
0x0e62, 0x0e66, 0x0e6a, 0x0e6e, 0x0e72, 0x0e76, 0x0e7a, 0x0e7e,
0x0e82, 0x0e86, 0x0e8a, 0x0e8e, 0x0e92, 0x0e96, 0x0e9a, 0x0e9e,
0x0ea2, 0x0ea6, 0x0eaa, 0x0eae, 0x0eb2, 0x0eb6, 0x0ebc, 0x0ec2,
0x0ec8, 0x0ecc, 0x0ed0, 0x0ed4, 0x0ed8, 0x0edc, 0x0ee0, 0x0ee4,
0x0ee8, 0x0eec, 0x0ef0, 0x0ef4, 0x0ef8, 0x0efc, 0x0f00, 0x0f04,
// Entry 380 - 3BF
0x0f08, 0x0f0c, 0x0f10, 0x0f14, 0x0f18, 0x0f1c, 0x0f20, 0x0f24,
0x0f28, 0x0f2c, 0x0f30, 0x0f34, 0x0f38, 0x0f3e, 0x0f44, 0x0f4a,
0x0f50, 0x0f56, 0x0f5c, 0x0f62, 0x0f68, 0x0f6e, 0x0f74, 0x0f7a,
0x0f80, 0x0f86, 0x0f8c, 0x0f92, 0x0f98, 0x0f9e, 0x0fa4, 0x0faa,
0x0fb0, 0x0fb6, 0x0fbc, 0x0fc2, 0x0fc8, 0x0fce, 0x0fd4, 0x0fda,
0x0fe0, 0x0fe6, 0x0fec, 0x0ff2, 0x0ff8, 0x0ffe, 0x1004, 0x100a,
0x1010, 0x1016, 0x101c, 0x1022, 0x1028, 0x102e, 0x1034, 0x103a,
0x1040, 0x1046, 0x104c, 0x1052, 0x1058, 0x105e, 0x1064, 0x106a,
// Entry 3C0 - 3FF
0x1070, 0x1076, 0x107c, 0x1082, 0x1088, 0x108e, 0x1094, 0x109a,
0x10a0, 0x10a6, 0x10ac, 0x10b2, 0x10b8, 0x10be, 0x10c4, 0x10ca,
0x10d0, 0x10d6, 0x10dc, 0x10e2, 0x10e8, 0x10ee, 0x10f4, 0x10fa,
0x1100, 0x1106, 0x110c, 0x1112, 0x1118, 0x111e, 0x1124, 0x112a,
0x1130, 0x1136, 0x113c, 0x1142, 0x1148, 0x114e, 0x1154, 0x115a,
0x1160, 0x1166, 0x116c, 0x1172, 0x1178, 0x1180, 0x1188, 0x1190,
0x1198, 0x11a0, 0x11a8, 0x11b0, 0x11b6, 0x11d7, 0x11e6, 0x11ee,
0x11ef, 0x11f0, 0x11f1, 0x11f2, 0x11f3, 0x11f4, 0x11f5, 0x11f6,
// Entry 400 - 43F
0x11f7, 0x11f8, 0x11f9, 0x11fa, 0x11fb, 0x11fc, 0x11fd, 0x11fe,
0x11ff, 0x1200, 0x1201, 0x1205, 0x1209, 0x120d, 0x1211, 0x1215,
0x1219, 0x121b, 0x121d, 0x121f, 0x1221, 0x1223, 0x1225, 0x1227,
0x1229, 0x122b, 0x122d, 0x122f, 0x1231, 0x1233, 0x1235, 0x1237,
0x1239, 0x123b, 0x123d, 0x123f, 0x1241, 0x1243, 0x1245, 0x1247,
0x1249, 0x124b, 0x124d, 0x124f, 0x1251, 0x1253, 0x1255, 0x1257,
0x1259, 0x125b, 0x125d, 0x125f, 0x1263, 0x1267, 0x126b, 0x126f,
0x1270, 0x1271, 0x1272, 0x1273, 0x1274, 0x1275, 0x1277, 0x1279,
// Entry 440 - 47F
0x127b, 0x127d, 0x127f, 0x1281, 0x1283, 0x1285, 0x1287, 0x1289,
0x128c, 0x128e, 0x1290, 0x1292, 0x1294, 0x1297, 0x1299, 0x129b,
0x129d, 0x129f, 0x12a1, 0x12a3, 0x12a5, 0x12a7, 0x12a9, 0x12ab,
0x12ad, 0x12af, 0x12b2, 0x12b4, 0x12b6, 0x12b8, 0x12ba, 0x12bc,
0x12be, 0x12c0, 0x12c2, 0x12c4, 0x12c6, 0x12c9, 0x12cb, 0x12cd,
0x12d0, 0x12d2, 0x12d4, 0x12d6, 0x12d8, 0x12da, 0x12dc, 0x12de,
0x12e6, 0x12ee, 0x12fa, 0x1306, 0x1312, 0x131e, 0x132a, 0x1332,
0x133a, 0x1346, 0x1352, 0x135e, 0x136a, 0x136c, 0x136e, 0x1370,
// Entry 480 - 4BF
0x1372, 0x1374, 0x1376, 0x1378, 0x137a, 0x137c, 0x137e, 0x1380,
0x1382, 0x1384, 0x1386, 0x1388, 0x138a, 0x138d, 0x1390, 0x1392,
0x1394, 0x1396, 0x1398, 0x139a, 0x139c, 0x139e, 0x13a0, 0x13a2,
0x13a4, 0x13a6, 0x13a8, 0x13aa, 0x13ac, 0x13ae, 0x13b0, 0x13b2,
0x13b4, 0x13b6, 0x13b8, 0x13ba, 0x13bc, 0x13bf, 0x13c1, 0x13c3,
0x13c5, 0x13c7, 0x13c9, 0x13cb, 0x13cd, 0x13cf, 0x13d1, 0x13d3,
0x13d6, 0x13d8, 0x13da, 0x13dc, 0x13de, 0x13e0, 0x13e2, 0x13e4,
0x13e6, 0x13e8, 0x13ea, 0x13ec, 0x13ee, 0x13f0, 0x13f2, 0x13f5,
// Entry 4C0 - 4FF
0x13f8, 0x13fb, 0x13fe, 0x1401, 0x1404, 0x1407, 0x140a, 0x140d,
0x1410, 0x1413, 0x1416, 0x1419, 0x141c, 0x141f, 0x1422, 0x1425,
0x1428, 0x142b, 0x142e, 0x1431, 0x1434, 0x1437, 0x143a, 0x143d,
0x1440, 0x1447, 0x1449, 0x144b, 0x144d, 0x1450, 0x1452, 0x1454,
0x1456, 0x1458, 0x145a, 0x1460, 0x1466, 0x1469, 0x146c, 0x146f,
0x1472, 0x1475, 0x1478, 0x147b, 0x147e, 0x1481, 0x1484, 0x1487,
0x148a, 0x148d, 0x1490, 0x1493, 0x1496, 0x1499, 0x149c, 0x149f,
0x14a2, 0x14a5, 0x14a8, 0x14ab, 0x14ae, 0x14b1, 0x14b4, 0x14b7,
// Entry 500 - 53F
0x14ba, 0x14bd, 0x14c0, 0x14c3, 0x14c6, 0x14c9, 0x14cc, 0x14cf,
0x14d2, 0x14d5, 0x14d8, 0x14db, 0x14de, 0x14e1, 0x14e4, 0x14e7,
0x14ea, 0x14ed, 0x14f6, 0x14ff, 0x1508, 0x1511, 0x151a, 0x1523,
0x152c, 0x1535, 0x153e, 0x1541, 0x1544, 0x1547, 0x154a, 0x154d,
0x1550, 0x1553, 0x1556, 0x1559, 0x155c, 0x155f, 0x1562, 0x1565,
0x1568, 0x156b, 0x156e, 0x1571, 0x1574, 0x1577, 0x157a, 0x157d,
0x1580, 0x1583, 0x1586, 0x1589, 0x158c, 0x158f, 0x1592, 0x1595,
0x1598, 0x159b, 0x159e, 0x15a1, 0x15a4, 0x15a7, 0x15aa, 0x15ad,
// Entry 540 - 57F
0x15b0, 0x15b3, 0x15b6, 0x15b9, 0x15bc, 0x15bf, 0x15c2, 0x15c5,
0x15c8, 0x15cb, 0x15ce, 0x15d1, 0x15d4, 0x15d7, 0x15da, 0x15dd,
0x15e0, 0x15e3, 0x15e6, 0x15e9, 0x15ec, 0x15ef, 0x15f2, 0x15f5,
0x15f8, 0x15fb, 0x15fe, 0x1601, 0x1604, 0x1607, 0x160a, 0x160d,
0x1610, 0x1613, 0x1616, 0x1619, 0x161c, 0x161f, 0x1622, 0x1625,
0x1628, 0x162b, 0x162e, 0x1631, 0x1634, 0x1637, 0x163a, 0x163d,
0x1640, 0x1643, 0x1646, 0x1649, 0x164c, 0x164f, 0x1652, 0x1655,
0x1658, 0x165b, 0x165e, 0x1661, 0x1664, 0x1667, 0x166a, 0x166d,
// Entry 580 - 5BF
0x1670, 0x1673, 0x1676, 0x1679, 0x167c, 0x167f, 0x1682, 0x1685,
0x1688, 0x168b, 0x168e, 0x1691, 0x1694, 0x1697, 0x169a, 0x169d,
0x16a0, 0x16a3, 0x16a6, 0x16a9, 0x16ac, 0x16af, 0x16b2, 0x16b5,
0x16b8, 0x16bb, 0x16be, 0x16c1, 0x16c4, 0x16c7, 0x16ca, 0x16cd,
0x16d0, 0x16d3, 0x16d6, 0x16d9, 0x16dc, 0x16df, 0x16e2, 0x16e5,
0x16e8, 0x16eb, 0x16ee, 0x16f1, 0x16f4, 0x16f7, 0x16fa, 0x16fd,
0x1700, 0x1703, 0x1706, 0x1709, 0x170c, 0x170f, 0x1712, 0x1715,
0x1718, 0x171b, 0x171e, 0x1721, 0x1724, 0x1727, 0x172a, 0x172d,
// Entry 5C0 - 5FF
0x1730, 0x1733, 0x1736, 0x1739, 0x173c, 0x173f, 0x1742, 0x1745,
0x1748, 0x174b, 0x174e, 0x1751, 0x1754, 0x1757, 0x175a, 0x175d,
0x1760, 0x1763, 0x1766, 0x1769, 0x176c, 0x176f, 0x1772, 0x1775,
0x1778, 0x177b, 0x177e, 0x1781, 0x1784, 0x1787, 0x178a, 0x178d,
0x1790, 0x1793, 0x1796, 0x1799, 0x179c, 0x179f, 0x17a2, 0x17a5,
0x17a8, 0x17ab, 0x17ae, 0x17b1, 0x17b4, 0x17b7, 0x17ba, 0x17bd,
0x17c0, 0x17c3, 0x17c6, 0x17c9, 0x17cc, 0x17cf, 0x17d2, 0x17d5,
0x17d8, 0x17db, 0x17de, 0x17e1, 0x17e4, 0x17e7, 0x17ea, 0x17ed,
// Entry 600 - 63F
0x17f0, 0x17f3, 0x17f6, 0x17f9, 0x17fc, 0x17ff, 0x1802, 0x1805,
0x1808, 0x180b, 0x180e, 0x1811, 0x1814, 0x1817, 0x181a, 0x181d,
0x1820, 0x1823, 0x1826, 0x1829, 0x182c, 0x182f, 0x1832, 0x1835,
0x1838, 0x183b, 0x183e, 0x1841, 0x1844, 0x1847, 0x184a, 0x184d,
0x1850, 0x1853, 0x1856, 0x1859, 0x185c, 0x185f, 0x1862, 0x1865,
0x1868, 0x186b, 0x186e, 0x1871, 0x1874, 0x1877, 0x187a, 0x187d,
0x1880, 0x1883, 0x1886, 0x1889, 0x188c, 0x188f, 0x1892, 0x1895,
0x1898, 0x189b, 0x189e, 0x18a1, 0x18a4, 0x18a7, 0x18aa, 0x18ad,
// Entry 640 - 67F
0x18b0, 0x18b3, 0x18b6, 0x18b9, 0x18bc, 0x18bf, 0x18c2, 0x18c5,
0x18c8, 0x18cb, 0x18ce, 0x18d1, 0x18d4, 0x18d7, 0x18da, 0x18dd,
0x18e0, 0x18e3, 0x18e6, 0x18e9, 0x18ec, 0x18ef, 0x18f2, 0x18f5,
0x18f8, 0x18fb, 0x18fe, 0x1901, 0x1904, 0x1907, 0x190a, 0x190d,
0x1910, 0x1913, 0x1916, 0x1919, 0x191c, 0x191f, 0x1922, 0x1925,
0x1928, 0x192b, 0x192e, 0x1931, 0x1934, 0x1937, 0x193a, 0x193d,
0x1940, 0x1943, 0x1946, 0x1949, 0x194c, 0x194f, 0x1952, 0x1955,
0x1958, 0x195b, 0x195e, 0x1961, 0x1964, 0x1967, 0x196a, 0x196d,
// Entry 680 - 6BF
0x1970, 0x1973, 0x1976, 0x1979, 0x197c, 0x197f, 0x1982, 0x1985,
0x1988, 0x198b, 0x198e, 0x1991, 0x1994, 0x1997, 0x199a, 0x199d,
0x19a0, 0x19a3, 0x19a6, 0x19a9, 0x19ac, 0x19af, 0x19b2, 0x19b5,
0x19b8, 0x19bb, 0x19be, 0x19c1, 0x19c4, 0x19c7, 0x19ca, 0x19cd,
0x19d0, 0x19d3, 0x19d6, 0x19d9, 0x19dc, 0x19df, 0x19e2, 0x19e5,
0x19e8, 0x19eb, 0x19ee, 0x19f1, 0x19f4, 0x19f7, 0x19fa, 0x19fd,
0x1a00, 0x1a03, 0x1a06, 0x1a09, 0x1a0c, 0x1a0f, 0x1a12, 0x1a15,
0x1a18, 0x1a1b, 0x1a1e, 0x1a21, 0x1a24, 0x1a27, 0x1a2a, 0x1a2d,
// Entry 6C0 - 6FF
0x1a30,
} // Size: 3482 bytes
var xorData string = "" + // Size: 4907 bytes
"\x02\x0c\x09\x02\xb0\xec\x02\xad\xd8\x02\xad\xd9\x02\x06\x07\x02\x0f\x12" +
"\x02\x0f\x1f\x02\x0f\x1d\x02\x01\x13\x02\x0f\x16\x02\x0f\x0b\x02\x0f3" +
"\x02\x0f7\x02\x0f?\x02\x0f/\x02\x0f*\x02\x0c&\x02\x0c*\x02\x0c;\x02\x0c9" +
"\x02\x0c%\x02\xab\xed\x02\xab\xe2\x02\xab\xe3\x02\xa9\xe0\x02\xa9\xe1" +
"\x02\xa9\xe6\x02\xa3\xcb\x02\xa3\xc8\x02\xa3\xc9\x02\x01#\x02\x01\x08" +
"\x02\x0e>\x02\x0e'\x02\x0f\x03\x02\x03\x0d\x02\x03\x09\x02\x03\x17\x02" +
"\x03\x0e\x02\x02\x03\x02\x011\x02\x01\x00\x02\x01\x10\x02\x03<\x02\x07" +
"\x0d\x02\x02\x0c\x02\x0c0\x02\x01\x03\x02\x01\x01\x02\x01 \x02\x01\x22" +
"\x02\x01)\x02\x01\x0a\x02\x01\x0c\x02\x02\x06\x02\x02\x02\x02\x03\x10" +
"\x03\x037 \x03\x0b+\x03\x021\x00\x02\x01\x04\x02\x01\x02\x02\x019\x02" +
"\x03\x1c\x02\x02$\x03\x80p$\x02\x03:\x02\x03\x0a\x03\xc1r.\x03\xc1r,\x03" +
"\xc1r\x02\x02\x02:\x02\x02>\x02\x02,\x02\x02\x10\x02\x02\x00\x03\xc1s<" +
"\x03\xc1s*\x03\xc2L$\x03\xc2L;\x02\x09)\x02\x0a\x19\x03\x83\xab\xe3\x03" +
"\x83\xab\xf2\x03 4\xe0\x03\x81\xab\xea\x03\x81\xab\xf3\x03 4\xef\x03\x96" +
"\xe1\xcd\x03\x84\xe5\xc3\x02\x0d\x11\x03\x8b\xec\xcb\x03\x94\xec\xcf\x03" +
"\x9a\xec\xc2\x03\x8b\xec\xdb\x03\x94\xec\xdf\x03\x9a\xec\xd2\x03\x01\x0c" +
"!\x03\x01\x0c#\x03ʠ\x9d\x03ʣ\x9c\x03ʢ\x9f\x03ʥ\x9e\x03ʤ\x91\x03ʧ\x90\x03" +
"ʦ\x93\x03ʩ\x92\x03ʨ\x95\x03\xca\xf3\xb5\x03\xca\xf0\xb4\x03\xca\xf1\xb7" +
"\x03\xca\xf6\xb6\x03\xca\xf7\x89\x03\xca\xf4\x88\x03\xca\xf5\x8b\x03\xca" +
"\xfa\x8a\x03\xca\xfb\x8d\x03\xca\xf8\x8c\x03\xca\xf9\x8f\x03\xca\xfe\x8e" +
"\x03\xca\xff\x81\x03\xca\xfc\x80\x03\xca\xfd\x83\x03\xca\xe2\x82\x03\xca" +
"\xe3\x85\x03\xca\xe0\x84\x03\xca\xe1\x87\x03\xca\xe6\x86\x03\xca\xe7\x99" +
"\x03\xca\xe4\x98\x03\xca\xe5\x9b\x03\xca\xea\x9a\x03\xca\xeb\x9d\x03\xca" +
"\xe8\x9c\x03ؓ\x89\x03ߔ\x8b\x02\x010\x03\x03\x04\x1e\x03\x04\x15\x12\x03" +
"\x0b\x05,\x03\x06\x04\x00\x03\x06\x04)\x03\x06\x044\x03\x06\x04<\x03\x06" +
"\x05\x1d\x03\x06\x06\x00\x03\x06\x06\x0a\x03\x06\x06'\x03\x06\x062\x03" +
"\x0786\x03\x079/\x03\x079 \x03\x07:\x0e\x03\x07:\x1b\x03\x07:%\x03\x07;/" +
"\x03\x07;%\x03\x074\x11\x03\x076\x09\x03\x077*\x03\x070\x01\x03\x070\x0f" +
"\x03\x070.\x03\x071\x16\x03\x071\x04\x03\x0710\x03\x072\x18\x03\x072-" +
"\x03\x073\x14\x03\x073>\x03\x07'\x09\x03\x07 \x00\x03\x07\x1f\x0b\x03" +
"\x07\x18#\x03\x07\x18(\x03\x07\x186\x03\x07\x18\x03\x03\x07\x19\x16\x03" +
"\x07\x116\x03\x07\x12'\x03\x07\x13\x10\x03\x07\x0c&\x03\x07\x0c\x08\x03" +
"\x07\x0c\x13\x03\x07\x0d\x02\x03\x07\x0d\x1c\x03\x07\x0b5\x03\x07\x0b" +
"\x0a\x03\x07\x0b\x01\x03\x07\x0b\x0f\x03\x07\x05\x00\x03\x07\x05\x09\x03" +
"\x07\x05\x0b\x03\x07\x07\x01\x03\x07\x07\x08\x03\x07\x00<\x03\x07\x00+" +
"\x03\x07\x01)\x03\x07\x01\x1b\x03\x07\x01\x08\x03\x07\x03?\x03\x0445\x03" +
"\x044\x08\x03\x0454\x03\x04)/\x03\x04)5\x03\x04+\x05\x03\x04+\x14\x03" +
"\x04+ \x03\x04+<\x03\x04*&\x03\x04*\x22\x03\x04&8\x03\x04!\x01\x03\x04!" +
"\x22\x03\x04\x11+\x03\x04\x10.\x03\x04\x104\x03\x04\x13=\x03\x04\x12\x04" +
"\x03\x04\x12\x0a\x03\x04\x0d\x1d\x03\x04\x0d\x07\x03\x04\x0d \x03\x05<>" +
"\x03\x055<\x03\x055!\x03\x055#\x03\x055&\x03\x054\x1d\x03\x054\x02\x03" +
"\x054\x07\x03\x0571\x03\x053\x1a\x03\x053\x16\x03\x05.<\x03\x05.\x07\x03" +
"\x05):\x03\x05)<\x03\x05)\x0c\x03\x05)\x15\x03\x05+-\x03\x05+5\x03\x05$" +
"\x1e\x03\x05$\x14\x03\x05'\x04\x03\x05'\x14\x03\x05&\x02\x03\x05\x226" +
"\x03\x05\x22\x0c\x03\x05\x22\x1c\x03\x05\x19\x0a\x03\x05\x1b\x09\x03\x05" +
"\x1b\x0c\x03\x05\x14\x07\x03\x05\x16?\x03\x05\x16\x0c\x03\x05\x0c\x05" +
"\x03\x05\x0e\x0f\x03\x05\x01\x0e\x03\x05\x00(\x03\x05\x030\x03\x05\x03" +
"\x06\x03\x0a==\x03\x0a=1\x03\x0a=,\x03\x0a=\x0c\x03\x0a??\x03\x0a<\x08" +
"\x03\x0a9!\x03\x0a9)\x03\x0a97\x03\x0a99\x03\x0a6\x0a\x03\x0a6\x1c\x03" +
"\x0a6\x17\x03\x0a7'\x03\x0a78\x03\x0a73\x03\x0a'\x01\x03\x0a'&\x03\x0a" +
"\x1f\x0e\x03\x0a\x1f\x03\x03\x0a\x1f3\x03\x0a\x1b/\x03\x0a\x18\x19\x03" +
"\x0a\x19\x01\x03\x0a\x16\x14\x03\x0a\x0e\x22\x03\x0a\x0f\x10\x03\x0a\x0f" +
"\x02\x03\x0a\x0f \x03\x0a\x0c\x04\x03\x0a\x0b>\x03\x0a\x0b+\x03\x0a\x08/" +
"\x03\x0a\x046\x03\x0a\x05\x14\x03\x0a\x00\x04\x03\x0a\x00\x10\x03\x0a" +
"\x00\x14\x03\x0b<3\x03\x0b;*\x03\x0b9\x22\x03\x0b9)\x03\x0b97\x03\x0b+" +
"\x10\x03\x0b((\x03\x0b&5\x03\x0b$\x1c\x03\x0b$\x12\x03\x0b%\x04\x03\x0b#" +
"<\x03\x0b#0\x03\x0b#\x0d\x03\x0b#\x19\x03\x0b!:\x03\x0b!\x1f\x03\x0b!" +
"\x00\x03\x0b\x1e5\x03\x0b\x1c\x1d\x03\x0b\x1d-\x03\x0b\x1d(\x03\x0b\x18." +
"\x03\x0b\x18 \x03\x0b\x18\x16\x03\x0b\x14\x13\x03\x0b\x15$\x03\x0b\x15" +
"\x22\x03\x0b\x12\x1b\x03\x0b\x12\x10\x03\x0b\x132\x03\x0b\x13=\x03\x0b" +
"\x12\x18\x03\x0b\x0c&\x03\x0b\x061\x03\x0b\x06:\x03\x0b\x05#\x03\x0b\x05" +
"<\x03\x0b\x04\x0b\x03\x0b\x04\x04\x03\x0b\x04\x1b\x03\x0b\x042\x03\x0b" +
"\x041\x03\x0b\x03\x03\x03\x0b\x03\x1d\x03\x0b\x03/\x03\x0b\x03+\x03\x0b" +
"\x02\x1b\x03\x0b\x02\x00\x03\x0b\x01\x1e\x03\x0b\x01\x08\x03\x0b\x015" +
"\x03\x06\x0d9\x03\x06\x0d=\x03\x06\x0d?\x03\x02\x001\x03\x02\x003\x03" +
"\x02\x02\x19\x03\x02\x006\x03\x02\x02\x1b\x03\x02\x004\x03\x02\x00<\x03" +
"\x02\x02\x0a\x03\x02\x02\x0e\x03\x02\x01\x1a\x03\x02\x01\x07\x03\x02\x01" +
"\x05\x03\x02\x01\x0b\x03\x02\x01%\x03\x02\x01\x0c\x03\x02\x01\x04\x03" +
"\x02\x01\x1c\x03\x02\x00.\x03\x02\x002\x03\x02\x00>\x03\x02\x00\x12\x03" +
"\x02\x00\x16\x03\x02\x011\x03\x02\x013\x03\x02\x02 \x03\x02\x02%\x03\x02" +
"\x02$\x03\x02\x028\x03\x02\x02;\x03\x02\x024\x03\x02\x012\x03\x02\x022" +
"\x03\x02\x02/\x03\x02\x01,\x03\x02\x01\x13\x03\x02\x01\x16\x03\x02\x01" +
"\x11\x03\x02\x01\x1e\x03\x02\x01\x15\x03\x02\x01\x17\x03\x02\x01\x0f\x03" +
"\x02\x01\x08\x03\x02\x00?\x03\x02\x03\x07\x03\x02\x03\x0d\x03\x02\x03" +
"\x13\x03\x02\x03\x1d\x03\x02\x03\x1f\x03\x02\x00\x03\x03\x02\x00\x0d\x03" +
"\x02\x00\x01\x03\x02\x00\x1b\x03\x02\x00\x19\x03\x02\x00\x18\x03\x02\x00" +
"\x13\x03\x02\x00/\x03\x07>\x12\x03\x07<\x1f\x03\x07>\x1d\x03\x06\x1d\x0e" +
"\x03\x07>\x1c\x03\x07>:\x03\x07>\x13\x03\x04\x12+\x03\x07?\x03\x03\x07>" +
"\x02\x03\x06\x224\x03\x06\x1a.\x03\x07<%\x03\x06\x1c\x0b\x03\x0609\x03" +
"\x05\x1f\x01\x03\x04'\x08\x03\x93\xfd\xf5\x03\x02\x0d \x03\x02\x0d#\x03" +
"\x02\x0d!\x03\x02\x0d&\x03\x02\x0d\x22\x03\x02\x0d/\x03\x02\x0d,\x03\x02" +
"\x0d$\x03\x02\x0d'\x03\x02\x0d%\x03\x02\x0d;\x03\x02\x0d=\x03\x02\x0d?" +
"\x03\x099.\x03\x08\x0b7\x03\x08\x02\x14\x03\x08\x14\x0d\x03\x08.:\x03" +
"\x089'\x03\x0f\x0b\x18\x03\x0f\x1c1\x03\x0f\x17&\x03\x0f9\x1f\x03\x0f0" +
"\x0c\x03\x0e\x0a9\x03\x0e\x056\x03\x0e\x1c#\x03\x0f\x13\x0e\x03\x072\x00" +
"\x03\x070\x0d\x03\x072\x0b\x03\x06\x11\x18\x03\x070\x10\x03\x06\x0f(\x03" +
"\x072\x05\x03\x06\x0f,\x03\x073\x15\x03\x06\x07\x08\x03\x05\x16\x02\x03" +
"\x04\x0b \x03\x05:8\x03\x05\x16%\x03\x0a\x0d\x1f\x03\x06\x16\x10\x03\x05" +
"\x1d5\x03\x05*;\x03\x05\x16\x1b\x03\x04.-\x03\x06\x1a\x19\x03\x04\x03," +
"\x03\x0b87\x03\x04/\x0a\x03\x06\x00,\x03\x04-\x01\x03\x04\x1e-\x03\x06/(" +
"\x03\x0a\x0b5\x03\x06\x0e7\x03\x06\x07.\x03\x0597\x03\x0a*%\x03\x0760" +
"\x03\x06\x0c;\x03\x05'\x00\x03\x072.\x03\x072\x08\x03\x06=\x01\x03\x06" +
"\x05\x1b\x03\x06\x06\x12\x03\x06$=\x03\x06'\x0d\x03\x04\x11\x0f\x03\x076" +
",\x03\x06\x07;\x03\x06.,\x03\x86\xf9\xea\x03\x8f\xff\xeb\x02\x092\x02" +
"\x095\x02\x094\x02\x09;\x02\x09>\x02\x098\x02\x09*\x02\x09/\x02\x09,\x02" +
"\x09%\x02\x09&\x02\x09#\x02\x09 \x02\x08!\x02\x08%\x02\x08$\x02\x08+\x02" +
"\x08.\x02\x08*\x02\x08&\x02\x088\x02\x08>\x02\x084\x02\x086\x02\x080\x02" +
"\x08\x10\x02\x08\x17\x02\x08\x12\x02\x08\x1d\x02\x08\x1f\x02\x08\x13\x02" +
"\x08\x15\x02\x08\x14\x02\x08\x0c\x03\x8b\xfd\xd0\x03\x81\xec\xc6\x03\x87" +
"\xe0\x8a\x03-2\xe3\x03\x80\xef\xe4\x03-2\xea\x03\x88\xe6\xeb\x03\x8e\xe6" +
"\xe8\x03\x84\xe6\xe9\x03\x97\xe6\xee\x03-2\xf9\x03-2\xf6\x03\x8e\xe3\xad" +
"\x03\x80\xe3\x92\x03\x88\xe3\x90\x03\x8e\xe3\x90\x03\x80\xe3\x97\x03\x88" +
"\xe3\x95\x03\x88\xfe\xcb\x03\x8e\xfe\xca\x03\x84\xfe\xcd\x03\x91\xef\xc9" +
"\x03-2\xc1\x03-2\xc0\x03-2\xcb\x03\x88@\x09\x03\x8e@\x08\x03\x8f\xe0\xf5" +
"\x03\x8e\xe6\xf9\x03\x8e\xe0\xfa\x03\x93\xff\xf4\x03\x84\xee\xd3\x03\x0b" +
"(\x04\x023 \x03\x0b)\x08\x021;\x02\x01*\x03\x0b#\x10\x03\x0b 0\x03\x0b!" +
"\x10\x03\x0b!0\x03\x07\x15\x08\x03\x09?5\x03\x07\x1f\x08\x03\x07\x17\x0b" +
"\x03\x09\x1f\x15\x03\x0b\x1c7\x03\x0a+#\x03\x06\x1a\x1b\x03\x06\x1a\x14" +
"\x03\x0a\x01\x18\x03\x06#\x1b\x03\x0a2\x0c\x03\x0a\x01\x04\x03\x09#;\x03" +
"\x08='\x03\x08\x1a\x0a\x03\x07</\x03\x07:+\x03\x07\x07*\x03\x06&\x1c\x03" +
"\x09\x0c\x16\x03\x09\x10\x0e\x03\x08'\x0f\x03\x08+\x09\x03\x074%\x03\x06" +
"!3\x03\x06\x03+\x03\x0b\x1e\x19\x03\x0a))\x03\x09\x08\x19\x03\x08,\x05" +
"\x03\x07<2\x03\x06\x1c>\x03\x0a\x111\x03\x09\x1b\x09\x03\x073.\x03\x07" +
"\x01\x00\x03\x09/,\x03\x07#>\x03\x07\x048\x03\x0a\x1f\x22\x03\x098>\x03" +
"\x09\x11\x00\x03\x08/\x17\x03\x06'\x22\x03\x0b\x1a+\x03\x0a\x22\x19\x03" +
"\x0a/1\x03\x0974\x03\x09\x0f\x22\x03\x08,\x22\x03\x08?\x14\x03\x07$5\x03" +
"\x07<3\x03\x07=*\x03\x07\x13\x18\x03\x068\x0a\x03\x06\x09\x16\x03\x06" +
"\x13\x00\x03\x08\x067\x03\x08\x01\x03\x03\x08\x12\x1d\x03\x07+7\x03\x06(" +
";\x03\x06\x1c?\x03\x07\x0e\x17\x03\x0a\x06\x1d\x03\x0a\x19\x07\x03\x08" +
"\x14$\x03\x07$;\x03\x08,$\x03\x08\x06\x0d\x03\x07\x16\x0a\x03\x06>>\x03" +
"\x0a\x06\x12\x03\x0a\x14)\x03\x09\x0d\x1f\x03\x09\x12\x17\x03\x09\x19" +
"\x01\x03\x08\x11 \x03\x08\x1d'\x03\x06<\x1a\x03\x0a.\x00\x03\x07'\x18" +
"\x03\x0a\x22\x08\x03\x08\x0d\x0a\x03\x08\x13)\x03\x07*)\x03\x06<,\x03" +
"\x07\x0b\x1a\x03\x09.\x14\x03\x09\x0d\x1e\x03\x07\x0e#\x03\x0b\x1d'\x03" +
"\x0a\x0a8\x03\x09%2\x03\x08+&\x03\x080\x12\x03\x0a)4\x03\x08\x06\x1f\x03" +
"\x0b\x1b\x1a\x03\x0a\x1b\x0f\x03\x0b\x1d*\x03\x09\x16$\x03\x090\x11\x03" +
"\x08\x11\x08\x03\x0a*(\x03\x0a\x042\x03\x089,\x03\x074'\x03\x07\x0f\x05" +
"\x03\x09\x0b\x0a\x03\x07\x1b\x01\x03\x09\x17:\x03\x09.\x0d\x03\x07.\x11" +
"\x03\x09+\x15\x03\x080\x13\x03\x0b\x1f\x19\x03\x0a \x11\x03\x0a\x220\x03" +
"\x09\x07;\x03\x08\x16\x1c\x03\x07,\x13\x03\x07\x0e/\x03\x06\x221\x03\x0a" +
".\x0a\x03\x0a7\x02\x03\x0a\x032\x03\x0a\x1d.\x03\x091\x06\x03\x09\x19:" +
"\x03\x08\x02/\x03\x060+\x03\x06\x0f-\x03\x06\x1c\x1f\x03\x06\x1d\x07\x03" +
"\x0a,\x11\x03\x09=\x0d\x03\x09\x0b;\x03\x07\x1b/\x03\x0a\x1f:\x03\x09 " +
"\x1f\x03\x09.\x10\x03\x094\x0b\x03\x09\x1a1\x03\x08#\x1a\x03\x084\x1d" +
"\x03\x08\x01\x1f\x03\x08\x11\x22\x03\x07'8\x03\x07\x1a>\x03\x0757\x03" +
"\x06&9\x03\x06+\x11\x03\x0a.\x0b\x03\x0a,>\x03\x0a4#\x03\x08%\x17\x03" +
"\x07\x05\x22\x03\x07\x0c\x0b\x03\x0a\x1d+\x03\x0a\x19\x16\x03\x09+\x1f" +
"\x03\x09\x08\x0b\x03\x08\x16\x18\x03\x08+\x12\x03\x0b\x1d\x0c\x03\x0a=" +
"\x10\x03\x0a\x09\x0d\x03\x0a\x10\x11\x03\x09&0\x03\x08(\x1f\x03\x087\x07" +
"\x03\x08\x185\x03\x07'6\x03\x06.\x05\x03\x06=\x04\x03\x06;;\x03\x06\x06," +
"\x03\x0b\x18>\x03\x08\x00\x18\x03\x06 \x03\x03\x06<\x00\x03\x09%\x18\x03" +
"\x0b\x1c<\x03\x0a%!\x03\x0a\x09\x12\x03\x0a\x16\x02\x03\x090'\x03\x09" +
"\x0e=\x03\x08 \x0e\x03\x08>\x03\x03\x074>\x03\x06&?\x03\x06\x19\x09\x03" +
"\x06?(\x03\x0a-\x0e\x03\x09:3\x03\x098:\x03\x09\x12\x0b\x03\x09\x1d\x17" +
"\x03\x087\x05\x03\x082\x14\x03\x08\x06%\x03\x08\x13\x1f\x03\x06\x06\x0e" +
"\x03\x0a\x22<\x03\x09/<\x03\x06>+\x03\x0a'?\x03\x0a\x13\x0c\x03\x09\x10<" +
"\x03\x07\x1b=\x03\x0a\x19\x13\x03\x09\x22\x1d\x03\x09\x07\x0d\x03\x08)" +
"\x1c\x03\x06=\x1a\x03\x0a/4\x03\x0a7\x11\x03\x0a\x16:\x03\x09?3\x03\x09:" +
"/\x03\x09\x05\x0a\x03\x09\x14\x06\x03\x087\x22\x03\x080\x07\x03\x08\x1a" +
"\x1f\x03\x07\x04(\x03\x07\x04\x09\x03\x06 %\x03\x06<\x08\x03\x0a+\x14" +
"\x03\x09\x1d\x16\x03\x0a70\x03\x08 >\x03\x0857\x03\x070\x0a\x03\x06=\x12" +
"\x03\x06\x16%\x03\x06\x1d,\x03\x099#\x03\x09\x10>\x03\x07 \x1e\x03\x08" +
"\x0c<\x03\x08\x0b\x18\x03\x08\x15+\x03\x08,:\x03\x08%\x22\x03\x07\x0a$" +
"\x03\x0b\x1c=\x03\x07+\x08\x03\x0a/\x05\x03\x0a \x07\x03\x0a\x12'\x03" +
"\x09#\x11\x03\x08\x1b\x15\x03\x0a\x06\x01\x03\x09\x1c\x1b\x03\x0922\x03" +
"\x07\x14<\x03\x07\x09\x04\x03\x061\x04\x03\x07\x0e\x01\x03\x0a\x13\x18" +
"\x03\x0a-\x0c\x03\x0a?\x0d\x03\x0a\x09\x0a\x03\x091&\x03\x0a/\x0b\x03" +
"\x08$<\x03\x083\x1d\x03\x08\x0c$\x03\x08\x0d\x07\x03\x08\x0d?\x03\x08" +
"\x0e\x14\x03\x065\x0a\x03\x08\x1a#\x03\x08\x16#\x03\x0702\x03\x07\x03" +
"\x1a\x03\x06(\x1d\x03\x06+\x1b\x03\x06\x0b\x05\x03\x06\x0b\x17\x03\x06" +
"\x0c\x04\x03\x06\x1e\x19\x03\x06+0\x03\x062\x18\x03\x0b\x16\x1e\x03\x0a+" +
"\x16\x03\x0a-?\x03\x0a#:\x03\x0a#\x10\x03\x0a%$\x03\x0a>+\x03\x0a01\x03" +
"\x0a1\x10\x03\x0a\x099\x03\x0a\x0a\x12\x03\x0a\x19\x1f\x03\x0a\x19\x12" +
"\x03\x09*)\x03\x09-\x16\x03\x09.1\x03\x09.2\x03\x09<\x0e\x03\x09> \x03" +
"\x093\x12\x03\x09\x0b\x01\x03\x09\x1c2\x03\x09\x11\x1c\x03\x09\x15%\x03" +
"\x08,&\x03\x08!\x22\x03\x089(\x03\x08\x0b\x1a\x03\x08\x0d2\x03\x08\x0c" +
"\x04\x03\x08\x0c\x06\x03\x08\x0c\x1f\x03\x08\x0c\x0c\x03\x08\x0f\x1f\x03" +
"\x08\x0f\x1d\x03\x08\x00\x14\x03\x08\x03\x14\x03\x08\x06\x16\x03\x08\x1e" +
"#\x03\x08\x11\x11\x03\x08\x10\x18\x03\x08\x14(\x03\x07)\x1e\x03\x07.1" +
"\x03\x07 $\x03\x07 '\x03\x078\x08\x03\x07\x0d0\x03\x07\x0f7\x03\x07\x05#" +
"\x03\x07\x05\x1a\x03\x07\x1a7\x03\x07\x1d-\x03\x07\x17\x10\x03\x06)\x1f" +
"\x03\x062\x0b\x03\x066\x16\x03\x06\x09\x11\x03\x09(\x1e\x03\x07!5\x03" +
"\x0b\x11\x16\x03\x0a/\x04\x03\x0a,\x1a\x03\x0b\x173\x03\x0a,1\x03\x0a/5" +
"\x03\x0a\x221\x03\x0a\x22\x0d\x03\x0a?%\x03\x0a<,\x03\x0a?#\x03\x0a>\x19" +
"\x03\x0a\x08&\x03\x0a\x0b\x0e\x03\x0a\x0c:\x03\x0a\x0c+\x03\x0a\x03\x22" +
"\x03\x0a\x06)\x03\x0a\x11\x10\x03\x0a\x11\x1a\x03\x0a\x17-\x03\x0a\x14(" +
"\x03\x09)\x1e\x03\x09/\x09\x03\x09.\x00\x03\x09,\x07\x03\x09/*\x03\x09-9" +
"\x03\x09\x228\x03\x09%\x09\x03\x09:\x12\x03\x09;\x1d\x03\x09?\x06\x03" +
"\x093%\x03\x096\x05\x03\x096\x08\x03\x097\x02\x03\x09\x07,\x03\x09\x04," +
"\x03\x09\x1f\x16\x03\x09\x11\x03\x03\x09\x11\x12\x03\x09\x168\x03\x08*" +
"\x05\x03\x08/2\x03\x084:\x03\x08\x22+\x03\x08 0\x03\x08&\x0a\x03\x08;" +
"\x10\x03\x08>$\x03\x08>\x18\x03\x0829\x03\x082:\x03\x081,\x03\x081<\x03" +
"\x081\x1c\x03\x087#\x03\x087*\x03\x08\x09'\x03\x08\x00\x1d\x03\x08\x05-" +
"\x03\x08\x1f4\x03\x08\x1d\x04\x03\x08\x16\x0f\x03\x07*7\x03\x07'!\x03" +
"\x07%\x1b\x03\x077\x0c\x03\x07\x0c1\x03\x07\x0c.\x03\x07\x00\x06\x03\x07" +
"\x01\x02\x03\x07\x010\x03\x07\x06=\x03\x07\x01\x03\x03\x07\x01\x13\x03" +
"\x07\x06\x06\x03\x07\x05\x0a\x03\x07\x1f\x09\x03\x07\x17:\x03\x06*1\x03" +
"\x06-\x1d\x03\x06\x223\x03\x062:\x03\x060$\x03\x066\x1e\x03\x064\x12\x03" +
"\x0645\x03\x06\x0b\x00\x03\x06\x0b7\x03\x06\x07\x1f\x03\x06\x15\x12\x03" +
"\x0c\x05\x0f\x03\x0b+\x0b\x03\x0b+-\x03\x06\x16\x1b\x03\x06\x15\x17\x03" +
"\x89\xca\xea\x03\x89\xca\xe8\x03\x0c8\x10\x03\x0c8\x01\x03\x0c8\x0f\x03" +
"\x0d8%\x03\x0d8!\x03\x0c8-\x03\x0c8/\x03\x0c8+\x03\x0c87\x03\x0c85\x03" +
"\x0c9\x09\x03\x0c9\x0d\x03\x0c9\x0f\x03\x0c9\x0b\x03\xcfu\x0c\x03\xcfu" +
"\x0f\x03\xcfu\x0e\x03\xcfu\x09\x03\x0c9\x10\x03\x0d9\x0c\x03\xcf`;\x03" +
"\xcf`>\x03\xcf`9\x03\xcf`8\x03\xcf`7\x03\xcf`*\x03\xcf`-\x03\xcf`,\x03" +
"\x0d\x1b\x1a\x03\x0d\x1b&\x03\x0c=.\x03\x0c=%\x03\x0c>\x1e\x03\x0c>\x14" +
"\x03\x0c?\x06\x03\x0c?\x0b\x03\x0c?\x0c\x03\x0c?\x0d\x03\x0c?\x02\x03" +
"\x0c>\x0f\x03\x0c>\x08\x03\x0c>\x09\x03\x0c>,\x03\x0c>\x0c\x03\x0c?\x13" +
"\x03\x0c?\x16\x03\x0c?\x15\x03\x0c?\x1c\x03\x0c?\x1f\x03\x0c?\x1d\x03" +
"\x0c?\x1a\x03\x0c?\x17\x03\x0c?\x08\x03\x0c?\x09\x03\x0c?\x0e\x03\x0c?" +
"\x04\x03\x0c?\x05\x03\x0c<?\x03\x0c=\x00\x03\x0c=\x06\x03\x0c=\x05\x03" +
"\x0c=\x0c\x03\x0c=\x0f\x03\x0c=\x0d\x03\x0c=\x0b\x03\x0c=\x07\x03\x0c=" +
"\x19\x03\x0c=\x15\x03\x0c=\x11\x03\x0c=1\x03\x0c=3\x03\x0c=0\x03\x0c=>" +
"\x03\x0c=2\x03\x0c=6\x03\x0c<\x07\x03\x0c<\x05\x03\x0e:!\x03\x0e:#\x03" +
"\x0e8\x09\x03\x0e:&\x03\x0e8\x0b\x03\x0e:$\x03\x0e:,\x03\x0e8\x1a\x03" +
"\x0e8\x1e\x03\x0e:*\x03\x0e:7\x03\x0e:5\x03\x0e:;\x03\x0e:\x15\x03\x0e:<" +
"\x03\x0e:4\x03\x0e:'\x03\x0e:-\x03\x0e:%\x03\x0e:?\x03\x0e:=\x03\x0e:)" +
"\x03\x0e:/\x03\xcfs'\x03\x0d=\x0f\x03\x0d+*\x03\x0d99\x03\x0d9;\x03\x0d9" +
"?\x03\x0d)\x0d\x03\x0d(%\x02\x01\x18\x02\x01(\x02\x03'\x02\x03)\x02\x03+" +
"\x02\x03/\x02\x03\x19\x02\x03\x1b\x02\x03\x1f\x03\x0d\x22\x18\x03\x0d" +
"\x22\x1a\x03\x0d\x22'\x03\x0d\x22/\x03\x0d\x223\x03\x0d\x22$\x02\x01\x1e" +
"\x03\x0f$!\x03\x0f87\x03\x0f4\x0e\x03\x0f5\x1d\x03\x06'\x03\x03\x0f\x08" +
"\x18\x03\x0f\x0d\x1b\x03\x0e2=\x03\x0e;\x08\x03\x0e:\x0b\x03\x0e\x06$" +
"\x03\x0e\x0d)\x03\x0e\x16\x1f\x03\x0e\x16\x1b\x03\x0d$\x0a\x03\x05,\x1d" +
"\x03\x0d. \x03\x0d.#\x03\x0c(/\x03\x09%\x02\x03\x0d90\x03\x0d\x0e4\x03" +
"\x0d\x0d\x0f\x03\x0c#\x00\x03\x0c,\x1e\x03\x0c2\x0e\x03\x0c\x01\x17\x03" +
"\x0c\x09:\x03\x0e\x173\x03\x0c\x08\x03\x03\x0c\x11\x07\x03\x0c\x10\x18" +
"\x03\x0c\x1f\x1c\x03\x0c\x19\x0e\x03\x0c\x1a\x1f\x03\x0f0>\x03\x0b->\x03" +
"\x0b<+\x03\x0b8\x13\x03\x0b\x043\x03\x0b\x14\x03\x03\x0b\x16%\x03\x0d" +
"\x22&\x03\x0b\x1a\x1a\x03\x0b\x1a\x04\x03\x0a%9\x03\x0a&2\x03\x0a&0\x03" +
"\x0a!\x1a\x03\x0a!7\x03\x0a5\x10\x03\x0a=4\x03\x0a?\x0e\x03\x0a>\x10\x03" +
"\x0a\x00 \x03\x0a\x0f:\x03\x0a\x0f9\x03\x0a\x0b\x0a\x03\x0a\x17%\x03\x0a" +
"\x1b-\x03\x09-\x1a\x03\x09,4\x03\x09.,\x03\x09)\x09\x03\x096!\x03\x091" +
"\x1f\x03\x093\x16\x03\x0c+\x1f\x03\x098 \x03\x098=\x03\x0c(\x1a\x03\x0c(" +
"\x16\x03\x09\x0a+\x03\x09\x16\x12\x03\x09\x13\x0e\x03\x09\x153\x03\x08)!" +
"\x03\x09\x1a\x01\x03\x09\x18\x01\x03\x08%#\x03\x08>\x22\x03\x08\x05%\x03" +
"\x08\x02*\x03\x08\x15;\x03\x08\x1b7\x03\x0f\x07\x1d\x03\x0f\x04\x03\x03" +
"\x070\x0c\x03\x07;\x0b\x03\x07\x08\x17\x03\x07\x12\x06\x03\x06/-\x03\x06" +
"71\x03\x065+\x03\x06>7\x03\x06\x049\x03\x05+\x1e\x03\x05,\x17\x03\x05 " +
"\x1d\x03\x05\x22\x05\x03\x050\x1d"
// lookup returns the trie value for the first UTF-8 encoding in s and
// the width in bytes of this encoding. The size will be 0 if s does not
// hold enough bytes to complete the encoding. len(s) must be greater than 0.
func (t *idnaTrie) lookup(s []byte) (v uint16, sz int) {
c0 := s[0]
switch {
case c0 < 0x80: // is ASCII
return idnaValues[c0], 1
case c0 < 0xC2:
return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
case c0 < 0xE0: // 2-byte UTF-8
if len(s) < 2 {
return 0, 0
}
i := idnaIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c1), 2
case c0 < 0xF0: // 3-byte UTF-8
if len(s) < 3 {
return 0, 0
}
i := idnaIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = idnaIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c2), 3
case c0 < 0xF8: // 4-byte UTF-8
if len(s) < 4 {
return 0, 0
}
i := idnaIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = idnaIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
o = uint32(i)<<6 + uint32(c2)
i = idnaIndex[o]
c3 := s[3]
if c3 < 0x80 || 0xC0 <= c3 {
return 0, 3 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c3), 4
}
// Illegal rune
return 0, 1
}
// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
// s must start with a full and valid UTF-8 encoded rune.
func (t *idnaTrie) lookupUnsafe(s []byte) uint16 {
c0 := s[0]
if c0 < 0x80 { // is ASCII
return idnaValues[c0]
}
i := idnaIndex[c0]
if c0 < 0xE0 { // 2-byte UTF-8
return t.lookupValue(uint32(i), s[1])
}
i = idnaIndex[uint32(i)<<6+uint32(s[1])]
if c0 < 0xF0 { // 3-byte UTF-8
return t.lookupValue(uint32(i), s[2])
}
i = idnaIndex[uint32(i)<<6+uint32(s[2])]
if c0 < 0xF8 { // 4-byte UTF-8
return t.lookupValue(uint32(i), s[3])
}
return 0
}
// lookupString returns the trie value for the first UTF-8 encoding in s and
// the width in bytes of this encoding. The size will be 0 if s does not
// hold enough bytes to complete the encoding. len(s) must be greater than 0.
func (t *idnaTrie) lookupString(s string) (v uint16, sz int) {
c0 := s[0]
switch {
case c0 < 0x80: // is ASCII
return idnaValues[c0], 1
case c0 < 0xC2:
return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
case c0 < 0xE0: // 2-byte UTF-8
if len(s) < 2 {
return 0, 0
}
i := idnaIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c1), 2
case c0 < 0xF0: // 3-byte UTF-8
if len(s) < 3 {
return 0, 0
}
i := idnaIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = idnaIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c2), 3
case c0 < 0xF8: // 4-byte UTF-8
if len(s) < 4 {
return 0, 0
}
i := idnaIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = idnaIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
o = uint32(i)<<6 + uint32(c2)
i = idnaIndex[o]
c3 := s[3]
if c3 < 0x80 || 0xC0 <= c3 {
return 0, 3 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c3), 4
}
// Illegal rune
return 0, 1
}
// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
// s must start with a full and valid UTF-8 encoded rune.
func (t *idnaTrie) lookupStringUnsafe(s string) uint16 {
c0 := s[0]
if c0 < 0x80 { // is ASCII
return idnaValues[c0]
}
i := idnaIndex[c0]
if c0 < 0xE0 { // 2-byte UTF-8
return t.lookupValue(uint32(i), s[1])
}
i = idnaIndex[uint32(i)<<6+uint32(s[1])]
if c0 < 0xF0 { // 3-byte UTF-8
return t.lookupValue(uint32(i), s[2])
}
i = idnaIndex[uint32(i)<<6+uint32(s[2])]
if c0 < 0xF8 { // 4-byte UTF-8
return t.lookupValue(uint32(i), s[3])
}
return 0
}
// idnaTrie. Total size: 31598 bytes (30.86 KiB). Checksum: d3118eda0d6b5360.
type idnaTrie struct{}
func newIdnaTrie(i int) *idnaTrie {
return &idnaTrie{}
}
// lookupValue determines the type of block n and looks up the value for b.
func (t *idnaTrie) lookupValue(n uint32, b byte) uint16 {
switch {
case n < 133:
return uint16(idnaValues[n<<6+uint32(b)])
default:
n -= 133
return uint16(idnaSparse.lookup(n, b))
}
}
// idnaValues: 135 blocks, 8640 entries, 17280 bytes
// The third block is the zero block.
var idnaValues = [8640]uint16{
// Block 0x0, offset 0x0
0x00: 0x0080, 0x01: 0x0080, 0x02: 0x0080, 0x03: 0x0080, 0x04: 0x0080, 0x05: 0x0080,
0x06: 0x0080, 0x07: 0x0080, 0x08: 0x0080, 0x09: 0x0080, 0x0a: 0x0080, 0x0b: 0x0080,
0x0c: 0x0080, 0x0d: 0x0080, 0x0e: 0x0080, 0x0f: 0x0080, 0x10: 0x0080, 0x11: 0x0080,
0x12: 0x0080, 0x13: 0x0080, 0x14: 0x0080, 0x15: 0x0080, 0x16: 0x0080, 0x17: 0x0080,
0x18: 0x0080, 0x19: 0x0080, 0x1a: 0x0080, 0x1b: 0x0080, 0x1c: 0x0080, 0x1d: 0x0080,
0x1e: 0x0080, 0x1f: 0x0080, 0x20: 0x0080, 0x21: 0x0080, 0x22: 0x0080, 0x23: 0x0080,
0x24: 0x0080, 0x25: 0x0080, 0x26: 0x0080, 0x27: 0x0080, 0x28: 0x0080, 0x29: 0x0080,
0x2a: 0x0080, 0x2b: 0x0080, 0x2c: 0x0080, 0x2d: 0x0008, 0x2e: 0x0008, 0x2f: 0x0080,
0x30: 0x0008, 0x31: 0x0008, 0x32: 0x0008, 0x33: 0x0008, 0x34: 0x0008, 0x35: 0x0008,
0x36: 0x0008, 0x37: 0x0008, 0x38: 0x0008, 0x39: 0x0008, 0x3a: 0x0080, 0x3b: 0x0080,
0x3c: 0x0080, 0x3d: 0x0080, 0x3e: 0x0080, 0x3f: 0x0080,
// Block 0x1, offset 0x40
0x40: 0x0080, 0x41: 0xe105, 0x42: 0xe105, 0x43: 0xe105, 0x44: 0xe105, 0x45: 0xe105,
0x46: 0xe105, 0x47: 0xe105, 0x48: 0xe105, 0x49: 0xe105, 0x4a: 0xe105, 0x4b: 0xe105,
0x4c: 0xe105, 0x4d: 0xe105, 0x4e: 0xe105, 0x4f: 0xe105, 0x50: 0xe105, 0x51: 0xe105,
0x52: 0xe105, 0x53: 0xe105, 0x54: 0xe105, 0x55: 0xe105, 0x56: 0xe105, 0x57: 0xe105,
0x58: 0xe105, 0x59: 0xe105, 0x5a: 0xe105, 0x5b: 0x0080, 0x5c: 0x0080, 0x5d: 0x0080,
0x5e: 0x0080, 0x5f: 0x0080, 0x60: 0x0080, 0x61: 0x0008, 0x62: 0x0008, 0x63: 0x0008,
0x64: 0x0008, 0x65: 0x0008, 0x66: 0x0008, 0x67: 0x0008, 0x68: 0x0008, 0x69: 0x0008,
0x6a: 0x0008, 0x6b: 0x0008, 0x6c: 0x0008, 0x6d: 0x0008, 0x6e: 0x0008, 0x6f: 0x0008,
0x70: 0x0008, 0x71: 0x0008, 0x72: 0x0008, 0x73: 0x0008, 0x74: 0x0008, 0x75: 0x0008,
0x76: 0x0008, 0x77: 0x0008, 0x78: 0x0008, 0x79: 0x0008, 0x7a: 0x0008, 0x7b: 0x0080,
0x7c: 0x0080, 0x7d: 0x0080, 0x7e: 0x0080, 0x7f: 0x0080,
// Block 0x2, offset 0x80
// Block 0x3, offset 0xc0
0xc0: 0x0040, 0xc1: 0x0040, 0xc2: 0x0040, 0xc3: 0x0040, 0xc4: 0x0040, 0xc5: 0x0040,
0xc6: 0x0040, 0xc7: 0x0040, 0xc8: 0x0040, 0xc9: 0x0040, 0xca: 0x0040, 0xcb: 0x0040,
0xcc: 0x0040, 0xcd: 0x0040, 0xce: 0x0040, 0xcf: 0x0040, 0xd0: 0x0040, 0xd1: 0x0040,
0xd2: 0x0040, 0xd3: 0x0040, 0xd4: 0x0040, 0xd5: 0x0040, 0xd6: 0x0040, 0xd7: 0x0040,
0xd8: 0x0040, 0xd9: 0x0040, 0xda: 0x0040, 0xdb: 0x0040, 0xdc: 0x0040, 0xdd: 0x0040,
0xde: 0x0040, 0xdf: 0x0040, 0xe0: 0x000a, 0xe1: 0x0018, 0xe2: 0x0018, 0xe3: 0x0018,
0xe4: 0x0018, 0xe5: 0x0018, 0xe6: 0x0018, 0xe7: 0x0018, 0xe8: 0x0012, 0xe9: 0x0018,
0xea: 0x0019, 0xeb: 0x0018, 0xec: 0x0018, 0xed: 0x03c0, 0xee: 0x0018, 0xef: 0x0022,
0xf0: 0x0018, 0xf1: 0x0018, 0xf2: 0x0029, 0xf3: 0x0031, 0xf4: 0x003a, 0xf5: 0x0005,
0xf6: 0x0018, 0xf7: 0x0008, 0xf8: 0x0042, 0xf9: 0x0049, 0xfa: 0x0051, 0xfb: 0x0018,
0xfc: 0x0059, 0xfd: 0x0061, 0xfe: 0x0069, 0xff: 0x0018,
// Block 0x4, offset 0x100
0x100: 0xe00d, 0x101: 0x0008, 0x102: 0xe00d, 0x103: 0x0008, 0x104: 0xe00d, 0x105: 0x0008,
0x106: 0xe00d, 0x107: 0x0008, 0x108: 0xe00d, 0x109: 0x0008, 0x10a: 0xe00d, 0x10b: 0x0008,
0x10c: 0xe00d, 0x10d: 0x0008, 0x10e: 0xe00d, 0x10f: 0x0008, 0x110: 0xe00d, 0x111: 0x0008,
0x112: 0xe00d, 0x113: 0x0008, 0x114: 0xe00d, 0x115: 0x0008, 0x116: 0xe00d, 0x117: 0x0008,
0x118: 0xe00d, 0x119: 0x0008, 0x11a: 0xe00d, 0x11b: 0x0008, 0x11c: 0xe00d, 0x11d: 0x0008,
0x11e: 0xe00d, 0x11f: 0x0008, 0x120: 0xe00d, 0x121: 0x0008, 0x122: 0xe00d, 0x123: 0x0008,
0x124: 0xe00d, 0x125: 0x0008, 0x126: 0xe00d, 0x127: 0x0008, 0x128: 0xe00d, 0x129: 0x0008,
0x12a: 0xe00d, 0x12b: 0x0008, 0x12c: 0xe00d, 0x12d: 0x0008, 0x12e: 0xe00d, 0x12f: 0x0008,
0x130: 0x0071, 0x131: 0x0008, 0x132: 0x0035, 0x133: 0x004d, 0x134: 0xe00d, 0x135: 0x0008,
0x136: 0xe00d, 0x137: 0x0008, 0x138: 0x0008, 0x139: 0xe01d, 0x13a: 0x0008, 0x13b: 0xe03d,
0x13c: 0x0008, 0x13d: 0xe01d, 0x13e: 0x0008, 0x13f: 0x0079,
// Block 0x5, offset 0x140
0x140: 0x0079, 0x141: 0xe01d, 0x142: 0x0008, 0x143: 0xe03d, 0x144: 0x0008, 0x145: 0xe01d,
0x146: 0x0008, 0x147: 0xe07d, 0x148: 0x0008, 0x149: 0x0081, 0x14a: 0xe00d, 0x14b: 0x0008,
0x14c: 0xe00d, 0x14d: 0x0008, 0x14e: 0xe00d, 0x14f: 0x0008, 0x150: 0xe00d, 0x151: 0x0008,
0x152: 0xe00d, 0x153: 0x0008, 0x154: 0xe00d, 0x155: 0x0008, 0x156: 0xe00d, 0x157: 0x0008,
0x158: 0xe00d, 0x159: 0x0008, 0x15a: 0xe00d, 0x15b: 0x0008, 0x15c: 0xe00d, 0x15d: 0x0008,
0x15e: 0xe00d, 0x15f: 0x0008, 0x160: 0xe00d, 0x161: 0x0008, 0x162: 0xe00d, 0x163: 0x0008,
0x164: 0xe00d, 0x165: 0x0008, 0x166: 0xe00d, 0x167: 0x0008, 0x168: 0xe00d, 0x169: 0x0008,
0x16a: 0xe00d, 0x16b: 0x0008, 0x16c: 0xe00d, 0x16d: 0x0008, 0x16e: 0xe00d, 0x16f: 0x0008,
0x170: 0xe00d, 0x171: 0x0008, 0x172: 0xe00d, 0x173: 0x0008, 0x174: 0xe00d, 0x175: 0x0008,
0x176: 0xe00d, 0x177: 0x0008, 0x178: 0x0065, 0x179: 0xe01d, 0x17a: 0x0008, 0x17b: 0xe03d,
0x17c: 0x0008, 0x17d: 0xe01d, 0x17e: 0x0008, 0x17f: 0x0089,
// Block 0x6, offset 0x180
0x180: 0x0008, 0x181: 0x007d, 0x182: 0xe00d, 0x183: 0x0008, 0x184: 0xe00d, 0x185: 0x0008,
0x186: 0x007d, 0x187: 0xe07d, 0x188: 0x0008, 0x189: 0x0095, 0x18a: 0x00ad, 0x18b: 0xe03d,
0x18c: 0x0008, 0x18d: 0x0008, 0x18e: 0x00c5, 0x18f: 0x00dd, 0x190: 0x00f5, 0x191: 0xe01d,
0x192: 0x0008, 0x193: 0x010d, 0x194: 0x0125, 0x195: 0x0008, 0x196: 0x013d, 0x197: 0x013d,
0x198: 0xe00d, 0x199: 0x0008, 0x19a: 0x0008, 0x19b: 0x0008, 0x19c: 0x010d, 0x19d: 0x0155,
0x19e: 0x0008, 0x19f: 0x016d, 0x1a0: 0xe00d, 0x1a1: 0x0008, 0x1a2: 0xe00d, 0x1a3: 0x0008,
0x1a4: 0xe00d, 0x1a5: 0x0008, 0x1a6: 0x0185, 0x1a7: 0xe07d, 0x1a8: 0x0008, 0x1a9: 0x019d,
0x1aa: 0x0008, 0x1ab: 0x0008, 0x1ac: 0xe00d, 0x1ad: 0x0008, 0x1ae: 0x0185, 0x1af: 0xe0fd,
0x1b0: 0x0008, 0x1b1: 0x01b5, 0x1b2: 0x01cd, 0x1b3: 0xe03d, 0x1b4: 0x0008, 0x1b5: 0xe01d,
0x1b6: 0x0008, 0x1b7: 0x01e5, 0x1b8: 0xe00d, 0x1b9: 0x0008, 0x1ba: 0x0008, 0x1bb: 0x0008,
0x1bc: 0xe00d, 0x1bd: 0x0008, 0x1be: 0x0008, 0x1bf: 0x0008,
// Block 0x7, offset 0x1c0
0x1c0: 0x0008, 0x1c1: 0x0008, 0x1c2: 0x0008, 0x1c3: 0x0008, 0x1c4: 0x0091, 0x1c5: 0x0091,
0x1c6: 0x0091, 0x1c7: 0x01fd, 0x1c8: 0x0215, 0x1c9: 0x022d, 0x1ca: 0x0245, 0x1cb: 0x025d,
0x1cc: 0x0275, 0x1cd: 0xe01d, 0x1ce: 0x0008, 0x1cf: 0xe0fd, 0x1d0: 0x0008, 0x1d1: 0xe01d,
0x1d2: 0x0008, 0x1d3: 0xe03d, 0x1d4: 0x0008, 0x1d5: 0xe01d, 0x1d6: 0x0008, 0x1d7: 0xe07d,
0x1d8: 0x0008, 0x1d9: 0xe01d, 0x1da: 0x0008, 0x1db: 0xe03d, 0x1dc: 0x0008, 0x1dd: 0x0008,
0x1de: 0xe00d, 0x1df: 0x0008, 0x1e0: 0xe00d, 0x1e1: 0x0008, 0x1e2: 0xe00d, 0x1e3: 0x0008,
0x1e4: 0xe00d, 0x1e5: 0x0008, 0x1e6: 0xe00d, 0x1e7: 0x0008, 0x1e8: 0xe00d, 0x1e9: 0x0008,
0x1ea: 0xe00d, 0x1eb: 0x0008, 0x1ec: 0xe00d, 0x1ed: 0x0008, 0x1ee: 0xe00d, 0x1ef: 0x0008,
0x1f0: 0x0008, 0x1f1: 0x028d, 0x1f2: 0x02a5, 0x1f3: 0x02bd, 0x1f4: 0xe00d, 0x1f5: 0x0008,
0x1f6: 0x02d5, 0x1f7: 0x02ed, 0x1f8: 0xe00d, 0x1f9: 0x0008, 0x1fa: 0xe00d, 0x1fb: 0x0008,
0x1fc: 0xe00d, 0x1fd: 0x0008, 0x1fe: 0xe00d, 0x1ff: 0x0008,
// Block 0x8, offset 0x200
0x200: 0xe00d, 0x201: 0x0008, 0x202: 0xe00d, 0x203: 0x0008, 0x204: 0xe00d, 0x205: 0x0008,
0x206: 0xe00d, 0x207: 0x0008, 0x208: 0xe00d, 0x209: 0x0008, 0x20a: 0xe00d, 0x20b: 0x0008,
0x20c: 0xe00d, 0x20d: 0x0008, 0x20e: 0xe00d, 0x20f: 0x0008, 0x210: 0xe00d, 0x211: 0x0008,
0x212: 0xe00d, 0x213: 0x0008, 0x214: 0xe00d, 0x215: 0x0008, 0x216: 0xe00d, 0x217: 0x0008,
0x218: 0xe00d, 0x219: 0x0008, 0x21a: 0xe00d, 0x21b: 0x0008, 0x21c: 0xe00d, 0x21d: 0x0008,
0x21e: 0xe00d, 0x21f: 0x0008, 0x220: 0x0305, 0x221: 0x0008, 0x222: 0xe00d, 0x223: 0x0008,
0x224: 0xe00d, 0x225: 0x0008, 0x226: 0xe00d, 0x227: 0x0008, 0x228: 0xe00d, 0x229: 0x0008,
0x22a: 0xe00d, 0x22b: 0x0008, 0x22c: 0xe00d, 0x22d: 0x0008, 0x22e: 0xe00d, 0x22f: 0x0008,
0x230: 0xe00d, 0x231: 0x0008, 0x232: 0xe00d, 0x233: 0x0008, 0x234: 0x0008, 0x235: 0x0008,
0x236: 0x0008, 0x237: 0x0008, 0x238: 0x0008, 0x239: 0x0008, 0x23a: 0x0099, 0x23b: 0xe03d,
0x23c: 0x0008, 0x23d: 0x031d, 0x23e: 0x00a1, 0x23f: 0x0008,
// Block 0x9, offset 0x240
0x240: 0x0008, 0x241: 0x0008, 0x242: 0x0018, 0x243: 0x0018, 0x244: 0x0018, 0x245: 0x0018,
0x246: 0x0008, 0x247: 0x0008, 0x248: 0x0008, 0x249: 0x0008, 0x24a: 0x0008, 0x24b: 0x0008,
0x24c: 0x0008, 0x24d: 0x0008, 0x24e: 0x0008, 0x24f: 0x0008, 0x250: 0x0008, 0x251: 0x0008,
0x252: 0x0018, 0x253: 0x0018, 0x254: 0x0018, 0x255: 0x0018, 0x256: 0x0018, 0x257: 0x0018,
0x258: 0x00d2, 0x259: 0x00da, 0x25a: 0x00e2, 0x25b: 0x00ea, 0x25c: 0x00f2, 0x25d: 0x00fa,
0x25e: 0x0018, 0x25f: 0x0018, 0x260: 0x03ad, 0x261: 0x0101, 0x262: 0x0089, 0x263: 0x0109,
0x264: 0x03c5, 0x265: 0x0018, 0x266: 0x0018, 0x267: 0x0018, 0x268: 0x0018, 0x269: 0x0018,
0x26a: 0x0018, 0x26b: 0x0018, 0x26c: 0x0008, 0x26d: 0x0018, 0x26e: 0x0008, 0x26f: 0x0018,
0x270: 0x0018, 0x271: 0x0018, 0x272: 0x0018, 0x273: 0x0018, 0x274: 0x0018, 0x275: 0x0018,
0x276: 0x0018, 0x277: 0x0018, 0x278: 0x0018, 0x279: 0x0018, 0x27a: 0x0018, 0x27b: 0x0018,
0x27c: 0x0018, 0x27d: 0x0018, 0x27e: 0x0018, 0x27f: 0x0018,
// Block 0xa, offset 0x280
0x280: 0x03dd, 0x281: 0x03dd, 0x282: 0x3308, 0x283: 0x03f5, 0x284: 0x0111, 0x285: 0x040d,
0x286: 0x3308, 0x287: 0x3308, 0x288: 0x3308, 0x289: 0x3308, 0x28a: 0x3308, 0x28b: 0x3308,
0x28c: 0x3308, 0x28d: 0x3308, 0x28e: 0x3308, 0x28f: 0x33c0, 0x290: 0x3308, 0x291: 0x3308,
0x292: 0x3308, 0x293: 0x3308, 0x294: 0x3308, 0x295: 0x3308, 0x296: 0x3308, 0x297: 0x3308,
0x298: 0x3308, 0x299: 0x3308, 0x29a: 0x3308, 0x29b: 0x3308, 0x29c: 0x3308, 0x29d: 0x3308,
0x29e: 0x3308, 0x29f: 0x3308, 0x2a0: 0x3308, 0x2a1: 0x3308, 0x2a2: 0x3308, 0x2a3: 0x3308,
0x2a4: 0x3308, 0x2a5: 0x3308, 0x2a6: 0x3308, 0x2a7: 0x3308, 0x2a8: 0x3308, 0x2a9: 0x3308,
0x2aa: 0x3308, 0x2ab: 0x3308, 0x2ac: 0x3308, 0x2ad: 0x3308, 0x2ae: 0x3308, 0x2af: 0x3308,
0x2b0: 0xe00d, 0x2b1: 0x0008, 0x2b2: 0xe00d, 0x2b3: 0x0008, 0x2b4: 0x0425, 0x2b5: 0x0008,
0x2b6: 0xe00d, 0x2b7: 0x0008, 0x2b8: 0x0040, 0x2b9: 0x0040, 0x2ba: 0x011a, 0x2bb: 0x0008,
0x2bc: 0x0008, 0x2bd: 0x0008, 0x2be: 0x0122, 0x2bf: 0x043d,
// Block 0xb, offset 0x2c0
0x2c0: 0x0040, 0x2c1: 0x0040, 0x2c2: 0x0040, 0x2c3: 0x0040, 0x2c4: 0x003a, 0x2c5: 0x012a,
0x2c6: 0xe155, 0x2c7: 0x0455, 0x2c8: 0xe12d, 0x2c9: 0xe13d, 0x2ca: 0xe12d, 0x2cb: 0x0040,
0x2cc: 0x03dd, 0x2cd: 0x0040, 0x2ce: 0x046d, 0x2cf: 0x0485, 0x2d0: 0x0008, 0x2d1: 0xe105,
0x2d2: 0xe105, 0x2d3: 0xe105, 0x2d4: 0xe105, 0x2d5: 0xe105, 0x2d6: 0xe105, 0x2d7: 0xe105,
0x2d8: 0xe105, 0x2d9: 0xe105, 0x2da: 0xe105, 0x2db: 0xe105, 0x2dc: 0xe105, 0x2dd: 0xe105,
0x2de: 0xe105, 0x2df: 0xe105, 0x2e0: 0x049d, 0x2e1: 0x049d, 0x2e2: 0x0040, 0x2e3: 0x049d,
0x2e4: 0x049d, 0x2e5: 0x049d, 0x2e6: 0x049d, 0x2e7: 0x049d, 0x2e8: 0x049d, 0x2e9: 0x049d,
0x2ea: 0x049d, 0x2eb: 0x049d, 0x2ec: 0x0008, 0x2ed: 0x0008, 0x2ee: 0x0008, 0x2ef: 0x0008,
0x2f0: 0x0008, 0x2f1: 0x0008, 0x2f2: 0x0008, 0x2f3: 0x0008, 0x2f4: 0x0008, 0x2f5: 0x0008,
0x2f6: 0x0008, 0x2f7: 0x0008, 0x2f8: 0x0008, 0x2f9: 0x0008, 0x2fa: 0x0008, 0x2fb: 0x0008,
0x2fc: 0x0008, 0x2fd: 0x0008, 0x2fe: 0x0008, 0x2ff: 0x0008,
// Block 0xc, offset 0x300
0x300: 0x0008, 0x301: 0x0008, 0x302: 0xe00f, 0x303: 0x0008, 0x304: 0x0008, 0x305: 0x0008,
0x306: 0x0008, 0x307: 0x0008, 0x308: 0x0008, 0x309: 0x0008, 0x30a: 0x0008, 0x30b: 0x0008,
0x30c: 0x0008, 0x30d: 0x0008, 0x30e: 0x0008, 0x30f: 0xe0c5, 0x310: 0x04b5, 0x311: 0x04cd,
0x312: 0xe0bd, 0x313: 0xe0f5, 0x314: 0xe0fd, 0x315: 0xe09d, 0x316: 0xe0b5, 0x317: 0x0008,
0x318: 0xe00d, 0x319: 0x0008, 0x31a: 0xe00d, 0x31b: 0x0008, 0x31c: 0xe00d, 0x31d: 0x0008,
0x31e: 0xe00d, 0x31f: 0x0008, 0x320: 0xe00d, 0x321: 0x0008, 0x322: 0xe00d, 0x323: 0x0008,
0x324: 0xe00d, 0x325: 0x0008, 0x326: 0xe00d, 0x327: 0x0008, 0x328: 0xe00d, 0x329: 0x0008,
0x32a: 0xe00d, 0x32b: 0x0008, 0x32c: 0xe00d, 0x32d: 0x0008, 0x32e: 0xe00d, 0x32f: 0x0008,
0x330: 0x04e5, 0x331: 0xe185, 0x332: 0xe18d, 0x333: 0x0008, 0x334: 0x04fd, 0x335: 0x03dd,
0x336: 0x0018, 0x337: 0xe07d, 0x338: 0x0008, 0x339: 0xe1d5, 0x33a: 0xe00d, 0x33b: 0x0008,
0x33c: 0x0008, 0x33d: 0x0515, 0x33e: 0x052d, 0x33f: 0x052d,
// Block 0xd, offset 0x340
0x340: 0x0008, 0x341: 0x0008, 0x342: 0x0008, 0x343: 0x0008, 0x344: 0x0008, 0x345: 0x0008,
0x346: 0x0008, 0x347: 0x0008, 0x348: 0x0008, 0x349: 0x0008, 0x34a: 0x0008, 0x34b: 0x0008,
0x34c: 0x0008, 0x34d: 0x0008, 0x34e: 0x0008, 0x34f: 0x0008, 0x350: 0x0008, 0x351: 0x0008,
0x352: 0x0008, 0x353: 0x0008, 0x354: 0x0008, 0x355: 0x0008, 0x356: 0x0008, 0x357: 0x0008,
0x358: 0x0008, 0x359: 0x0008, 0x35a: 0x0008, 0x35b: 0x0008, 0x35c: 0x0008, 0x35d: 0x0008,
0x35e: 0x0008, 0x35f: 0x0008, 0x360: 0xe00d, 0x361: 0x0008, 0x362: 0xe00d, 0x363: 0x0008,
0x364: 0xe00d, 0x365: 0x0008, 0x366: 0xe00d, 0x367: 0x0008, 0x368: 0xe00d, 0x369: 0x0008,
0x36a: 0xe00d, 0x36b: 0x0008, 0x36c: 0xe00d, 0x36d: 0x0008, 0x36e: 0xe00d, 0x36f: 0x0008,
0x370: 0xe00d, 0x371: 0x0008, 0x372: 0xe00d, 0x373: 0x0008, 0x374: 0xe00d, 0x375: 0x0008,
0x376: 0xe00d, 0x377: 0x0008, 0x378: 0xe00d, 0x379: 0x0008, 0x37a: 0xe00d, 0x37b: 0x0008,
0x37c: 0xe00d, 0x37d: 0x0008, 0x37e: 0xe00d, 0x37f: 0x0008,
// Block 0xe, offset 0x380
0x380: 0xe00d, 0x381: 0x0008, 0x382: 0x0018, 0x383: 0x3308, 0x384: 0x3308, 0x385: 0x3308,
0x386: 0x3308, 0x387: 0x3308, 0x388: 0x3318, 0x389: 0x3318, 0x38a: 0xe00d, 0x38b: 0x0008,
0x38c: 0xe00d, 0x38d: 0x0008, 0x38e: 0xe00d, 0x38f: 0x0008, 0x390: 0xe00d, 0x391: 0x0008,
0x392: 0xe00d, 0x393: 0x0008, 0x394: 0xe00d, 0x395: 0x0008, 0x396: 0xe00d, 0x397: 0x0008,
0x398: 0xe00d, 0x399: 0x0008, 0x39a: 0xe00d, 0x39b: 0x0008, 0x39c: 0xe00d, 0x39d: 0x0008,
0x39e: 0xe00d, 0x39f: 0x0008, 0x3a0: 0xe00d, 0x3a1: 0x0008, 0x3a2: 0xe00d, 0x3a3: 0x0008,
0x3a4: 0xe00d, 0x3a5: 0x0008, 0x3a6: 0xe00d, 0x3a7: 0x0008, 0x3a8: 0xe00d, 0x3a9: 0x0008,
0x3aa: 0xe00d, 0x3ab: 0x0008, 0x3ac: 0xe00d, 0x3ad: 0x0008, 0x3ae: 0xe00d, 0x3af: 0x0008,
0x3b0: 0xe00d, 0x3b1: 0x0008, 0x3b2: 0xe00d, 0x3b3: 0x0008, 0x3b4: 0xe00d, 0x3b5: 0x0008,
0x3b6: 0xe00d, 0x3b7: 0x0008, 0x3b8: 0xe00d, 0x3b9: 0x0008, 0x3ba: 0xe00d, 0x3bb: 0x0008,
0x3bc: 0xe00d, 0x3bd: 0x0008, 0x3be: 0xe00d, 0x3bf: 0x0008,
// Block 0xf, offset 0x3c0
0x3c0: 0x0040, 0x3c1: 0xe01d, 0x3c2: 0x0008, 0x3c3: 0xe03d, 0x3c4: 0x0008, 0x3c5: 0xe01d,
0x3c6: 0x0008, 0x3c7: 0xe07d, 0x3c8: 0x0008, 0x3c9: 0xe01d, 0x3ca: 0x0008, 0x3cb: 0xe03d,
0x3cc: 0x0008, 0x3cd: 0xe01d, 0x3ce: 0x0008, 0x3cf: 0x0008, 0x3d0: 0xe00d, 0x3d1: 0x0008,
0x3d2: 0xe00d, 0x3d3: 0x0008, 0x3d4: 0xe00d, 0x3d5: 0x0008, 0x3d6: 0xe00d, 0x3d7: 0x0008,
0x3d8: 0xe00d, 0x3d9: 0x0008, 0x3da: 0xe00d, 0x3db: 0x0008, 0x3dc: 0xe00d, 0x3dd: 0x0008,
0x3de: 0xe00d, 0x3df: 0x0008, 0x3e0: 0xe00d, 0x3e1: 0x0008, 0x3e2: 0xe00d, 0x3e3: 0x0008,
0x3e4: 0xe00d, 0x3e5: 0x0008, 0x3e6: 0xe00d, 0x3e7: 0x0008, 0x3e8: 0xe00d, 0x3e9: 0x0008,
0x3ea: 0xe00d, 0x3eb: 0x0008, 0x3ec: 0xe00d, 0x3ed: 0x0008, 0x3ee: 0xe00d, 0x3ef: 0x0008,
0x3f0: 0xe00d, 0x3f1: 0x0008, 0x3f2: 0xe00d, 0x3f3: 0x0008, 0x3f4: 0xe00d, 0x3f5: 0x0008,
0x3f6: 0xe00d, 0x3f7: 0x0008, 0x3f8: 0xe00d, 0x3f9: 0x0008, 0x3fa: 0xe00d, 0x3fb: 0x0008,
0x3fc: 0xe00d, 0x3fd: 0x0008, 0x3fe: 0xe00d, 0x3ff: 0x0008,
// Block 0x10, offset 0x400
0x400: 0xe00d, 0x401: 0x0008, 0x402: 0xe00d, 0x403: 0x0008, 0x404: 0xe00d, 0x405: 0x0008,
0x406: 0xe00d, 0x407: 0x0008, 0x408: 0xe00d, 0x409: 0x0008, 0x40a: 0xe00d, 0x40b: 0x0008,
0x40c: 0xe00d, 0x40d: 0x0008, 0x40e: 0xe00d, 0x40f: 0x0008, 0x410: 0xe00d, 0x411: 0x0008,
0x412: 0xe00d, 0x413: 0x0008, 0x414: 0xe00d, 0x415: 0x0008, 0x416: 0xe00d, 0x417: 0x0008,
0x418: 0xe00d, 0x419: 0x0008, 0x41a: 0xe00d, 0x41b: 0x0008, 0x41c: 0xe00d, 0x41d: 0x0008,
0x41e: 0xe00d, 0x41f: 0x0008, 0x420: 0xe00d, 0x421: 0x0008, 0x422: 0xe00d, 0x423: 0x0008,
0x424: 0xe00d, 0x425: 0x0008, 0x426: 0xe00d, 0x427: 0x0008, 0x428: 0xe00d, 0x429: 0x0008,
0x42a: 0xe00d, 0x42b: 0x0008, 0x42c: 0xe00d, 0x42d: 0x0008, 0x42e: 0xe00d, 0x42f: 0x0008,
0x430: 0x0040, 0x431: 0x03f5, 0x432: 0x03f5, 0x433: 0x03f5, 0x434: 0x03f5, 0x435: 0x03f5,
0x436: 0x03f5, 0x437: 0x03f5, 0x438: 0x03f5, 0x439: 0x03f5, 0x43a: 0x03f5, 0x43b: 0x03f5,
0x43c: 0x03f5, 0x43d: 0x03f5, 0x43e: 0x03f5, 0x43f: 0x03f5,
// Block 0x11, offset 0x440
0x440: 0x0840, 0x441: 0x0840, 0x442: 0x0840, 0x443: 0x0840, 0x444: 0x0840, 0x445: 0x0840,
0x446: 0x0018, 0x447: 0x0018, 0x448: 0x0818, 0x449: 0x0018, 0x44a: 0x0018, 0x44b: 0x0818,
0x44c: 0x0018, 0x44d: 0x0818, 0x44e: 0x0018, 0x44f: 0x0018, 0x450: 0x3308, 0x451: 0x3308,
0x452: 0x3308, 0x453: 0x3308, 0x454: 0x3308, 0x455: 0x3308, 0x456: 0x3308, 0x457: 0x3308,
0x458: 0x3308, 0x459: 0x3308, 0x45a: 0x3308, 0x45b: 0x0818, 0x45c: 0x0b40, 0x45d: 0x0818,
0x45e: 0x0818, 0x45f: 0x0818, 0x460: 0x0a08, 0x461: 0x0808, 0x462: 0x0c08, 0x463: 0x0c08,
0x464: 0x0c08, 0x465: 0x0c08, 0x466: 0x0a08, 0x467: 0x0c08, 0x468: 0x0a08, 0x469: 0x0c08,
0x46a: 0x0a08, 0x46b: 0x0a08, 0x46c: 0x0a08, 0x46d: 0x0a08, 0x46e: 0x0a08, 0x46f: 0x0c08,
0x470: 0x0c08, 0x471: 0x0c08, 0x472: 0x0c08, 0x473: 0x0a08, 0x474: 0x0a08, 0x475: 0x0a08,
0x476: 0x0a08, 0x477: 0x0a08, 0x478: 0x0a08, 0x479: 0x0a08, 0x47a: 0x0a08, 0x47b: 0x0a08,
0x47c: 0x0a08, 0x47d: 0x0a08, 0x47e: 0x0a08, 0x47f: 0x0a08,
// Block 0x12, offset 0x480
0x480: 0x0818, 0x481: 0x0a08, 0x482: 0x0a08, 0x483: 0x0a08, 0x484: 0x0a08, 0x485: 0x0a08,
0x486: 0x0a08, 0x487: 0x0a08, 0x488: 0x0c08, 0x489: 0x0a08, 0x48a: 0x0a08, 0x48b: 0x3308,
0x48c: 0x3308, 0x48d: 0x3308, 0x48e: 0x3308, 0x48f: 0x3308, 0x490: 0x3308, 0x491: 0x3308,
0x492: 0x3308, 0x493: 0x3308, 0x494: 0x3308, 0x495: 0x3308, 0x496: 0x3308, 0x497: 0x3308,
0x498: 0x3308, 0x499: 0x3308, 0x49a: 0x3308, 0x49b: 0x3308, 0x49c: 0x3308, 0x49d: 0x3308,
0x49e: 0x3308, 0x49f: 0x3308, 0x4a0: 0x0808, 0x4a1: 0x0808, 0x4a2: 0x0808, 0x4a3: 0x0808,
0x4a4: 0x0808, 0x4a5: 0x0808, 0x4a6: 0x0808, 0x4a7: 0x0808, 0x4a8: 0x0808, 0x4a9: 0x0808,
0x4aa: 0x0018, 0x4ab: 0x0818, 0x4ac: 0x0818, 0x4ad: 0x0818, 0x4ae: 0x0a08, 0x4af: 0x0a08,
0x4b0: 0x3308, 0x4b1: 0x0c08, 0x4b2: 0x0c08, 0x4b3: 0x0c08, 0x4b4: 0x0808, 0x4b5: 0x0139,
0x4b6: 0x0141, 0x4b7: 0x0149, 0x4b8: 0x0151, 0x4b9: 0x0a08, 0x4ba: 0x0a08, 0x4bb: 0x0a08,
0x4bc: 0x0a08, 0x4bd: 0x0a08, 0x4be: 0x0a08, 0x4bf: 0x0a08,
// Block 0x13, offset 0x4c0
0x4c0: 0x0c08, 0x4c1: 0x0a08, 0x4c2: 0x0a08, 0x4c3: 0x0c08, 0x4c4: 0x0c08, 0x4c5: 0x0c08,
0x4c6: 0x0c08, 0x4c7: 0x0c08, 0x4c8: 0x0c08, 0x4c9: 0x0c08, 0x4ca: 0x0c08, 0x4cb: 0x0c08,
0x4cc: 0x0a08, 0x4cd: 0x0c08, 0x4ce: 0x0a08, 0x4cf: 0x0c08, 0x4d0: 0x0a08, 0x4d1: 0x0a08,
0x4d2: 0x0c08, 0x4d3: 0x0c08, 0x4d4: 0x0818, 0x4d5: 0x0c08, 0x4d6: 0x3308, 0x4d7: 0x3308,
0x4d8: 0x3308, 0x4d9: 0x3308, 0x4da: 0x3308, 0x4db: 0x3308, 0x4dc: 0x3308, 0x4dd: 0x0840,
0x4de: 0x0018, 0x4df: 0x3308, 0x4e0: 0x3308, 0x4e1: 0x3308, 0x4e2: 0x3308, 0x4e3: 0x3308,
0x4e4: 0x3308, 0x4e5: 0x0808, 0x4e6: 0x0808, 0x4e7: 0x3308, 0x4e8: 0x3308, 0x4e9: 0x0018,
0x4ea: 0x3308, 0x4eb: 0x3308, 0x4ec: 0x3308, 0x4ed: 0x3308, 0x4ee: 0x0c08, 0x4ef: 0x0c08,
0x4f0: 0x0008, 0x4f1: 0x0008, 0x4f2: 0x0008, 0x4f3: 0x0008, 0x4f4: 0x0008, 0x4f5: 0x0008,
0x4f6: 0x0008, 0x4f7: 0x0008, 0x4f8: 0x0008, 0x4f9: 0x0008, 0x4fa: 0x0a08, 0x4fb: 0x0a08,
0x4fc: 0x0a08, 0x4fd: 0x0808, 0x4fe: 0x0808, 0x4ff: 0x0a08,
// Block 0x14, offset 0x500
0x500: 0x0818, 0x501: 0x0818, 0x502: 0x0818, 0x503: 0x0818, 0x504: 0x0818, 0x505: 0x0818,
0x506: 0x0818, 0x507: 0x0818, 0x508: 0x0818, 0x509: 0x0818, 0x50a: 0x0818, 0x50b: 0x0818,
0x50c: 0x0818, 0x50d: 0x0818, 0x50e: 0x0040, 0x50f: 0x0b40, 0x510: 0x0c08, 0x511: 0x3308,
0x512: 0x0a08, 0x513: 0x0a08, 0x514: 0x0a08, 0x515: 0x0c08, 0x516: 0x0c08, 0x517: 0x0c08,
0x518: 0x0c08, 0x519: 0x0c08, 0x51a: 0x0a08, 0x51b: 0x0a08, 0x51c: 0x0a08, 0x51d: 0x0a08,
0x51e: 0x0c08, 0x51f: 0x0a08, 0x520: 0x0a08, 0x521: 0x0a08, 0x522: 0x0a08, 0x523: 0x0a08,
0x524: 0x0a08, 0x525: 0x0a08, 0x526: 0x0a08, 0x527: 0x0a08, 0x528: 0x0c08, 0x529: 0x0a08,
0x52a: 0x0c08, 0x52b: 0x0a08, 0x52c: 0x0c08, 0x52d: 0x0a08, 0x52e: 0x0a08, 0x52f: 0x0c08,
0x530: 0x3308, 0x531: 0x3308, 0x532: 0x3308, 0x533: 0x3308, 0x534: 0x3308, 0x535: 0x3308,
0x536: 0x3308, 0x537: 0x3308, 0x538: 0x3308, 0x539: 0x3308, 0x53a: 0x3308, 0x53b: 0x3308,
0x53c: 0x3308, 0x53d: 0x3308, 0x53e: 0x3308, 0x53f: 0x3308,
// Block 0x15, offset 0x540
0x540: 0x0c08, 0x541: 0x0a08, 0x542: 0x0a08, 0x543: 0x0a08, 0x544: 0x0a08, 0x545: 0x0a08,
0x546: 0x0c08, 0x547: 0x0c08, 0x548: 0x0a08, 0x549: 0x0c08, 0x54a: 0x0a08, 0x54b: 0x0a08,
0x54c: 0x0a08, 0x54d: 0x0a08, 0x54e: 0x0a08, 0x54f: 0x0a08, 0x550: 0x0a08, 0x551: 0x0a08,
0x552: 0x0a08, 0x553: 0x0a08, 0x554: 0x0c08, 0x555: 0x0a08, 0x556: 0x0c08, 0x557: 0x0c08,
0x558: 0x0c08, 0x559: 0x3308, 0x55a: 0x3308, 0x55b: 0x3308, 0x55c: 0x0040, 0x55d: 0x0040,
0x55e: 0x0818, 0x55f: 0x0040, 0x560: 0x0a08, 0x561: 0x0808, 0x562: 0x0a08, 0x563: 0x0a08,
0x564: 0x0a08, 0x565: 0x0a08, 0x566: 0x0808, 0x567: 0x0c08, 0x568: 0x0a08, 0x569: 0x0c08,
0x56a: 0x0c08, 0x56b: 0x0040, 0x56c: 0x0040, 0x56d: 0x0040, 0x56e: 0x0040, 0x56f: 0x0040,
0x570: 0x0c08, 0x571: 0x0c08, 0x572: 0x0c08, 0x573: 0x0c08, 0x574: 0x0c08, 0x575: 0x0c08,
0x576: 0x0c08, 0x577: 0x0c08, 0x578: 0x0c08, 0x579: 0x0c08, 0x57a: 0x0c08, 0x57b: 0x0c08,
0x57c: 0x0c08, 0x57d: 0x0c08, 0x57e: 0x0c08, 0x57f: 0x0c08,
// Block 0x16, offset 0x580
0x580: 0x0c08, 0x581: 0x0c08, 0x582: 0x0c08, 0x583: 0x0808, 0x584: 0x0808, 0x585: 0x0808,
0x586: 0x0a08, 0x587: 0x0808, 0x588: 0x0818, 0x589: 0x0a08, 0x58a: 0x0a08, 0x58b: 0x0a08,
0x58c: 0x0a08, 0x58d: 0x0a08, 0x58e: 0x0c08, 0x58f: 0x0040, 0x590: 0x0840, 0x591: 0x0840,
0x592: 0x0040, 0x593: 0x0040, 0x594: 0x0040, 0x595: 0x0040, 0x596: 0x0040, 0x597: 0x0040,
0x598: 0x3308, 0x599: 0x3308, 0x59a: 0x3308, 0x59b: 0x3308, 0x59c: 0x3308, 0x59d: 0x3308,
0x59e: 0x3308, 0x59f: 0x3308, 0x5a0: 0x0a08, 0x5a1: 0x0a08, 0x5a2: 0x0a08, 0x5a3: 0x0a08,
0x5a4: 0x0a08, 0x5a5: 0x0a08, 0x5a6: 0x0a08, 0x5a7: 0x0a08, 0x5a8: 0x0a08, 0x5a9: 0x0a08,
0x5aa: 0x0c08, 0x5ab: 0x0c08, 0x5ac: 0x0c08, 0x5ad: 0x0808, 0x5ae: 0x0c08, 0x5af: 0x0a08,
0x5b0: 0x0a08, 0x5b1: 0x0c08, 0x5b2: 0x0c08, 0x5b3: 0x0a08, 0x5b4: 0x0a08, 0x5b5: 0x0a08,
0x5b6: 0x0a08, 0x5b7: 0x0a08, 0x5b8: 0x0a08, 0x5b9: 0x0c08, 0x5ba: 0x0a08, 0x5bb: 0x0a08,
0x5bc: 0x0a08, 0x5bd: 0x0a08, 0x5be: 0x0a08, 0x5bf: 0x0a08,
// Block 0x17, offset 0x5c0
0x5c0: 0x3008, 0x5c1: 0x3308, 0x5c2: 0x3308, 0x5c3: 0x3308, 0x5c4: 0x3308, 0x5c5: 0x3308,
0x5c6: 0x3308, 0x5c7: 0x3308, 0x5c8: 0x3308, 0x5c9: 0x3008, 0x5ca: 0x3008, 0x5cb: 0x3008,
0x5cc: 0x3008, 0x5cd: 0x3b08, 0x5ce: 0x3008, 0x5cf: 0x3008, 0x5d0: 0x0008, 0x5d1: 0x3308,
0x5d2: 0x3308, 0x5d3: 0x3308, 0x5d4: 0x3308, 0x5d5: 0x3308, 0x5d6: 0x3308, 0x5d7: 0x3308,
0x5d8: 0x0159, 0x5d9: 0x0161, 0x5da: 0x0169, 0x5db: 0x0171, 0x5dc: 0x0179, 0x5dd: 0x0181,
0x5de: 0x0189, 0x5df: 0x0191, 0x5e0: 0x0008, 0x5e1: 0x0008, 0x5e2: 0x3308, 0x5e3: 0x3308,
0x5e4: 0x0018, 0x5e5: 0x0018, 0x5e6: 0x0008, 0x5e7: 0x0008, 0x5e8: 0x0008, 0x5e9: 0x0008,
0x5ea: 0x0008, 0x5eb: 0x0008, 0x5ec: 0x0008, 0x5ed: 0x0008, 0x5ee: 0x0008, 0x5ef: 0x0008,
0x5f0: 0x0018, 0x5f1: 0x0008, 0x5f2: 0x0008, 0x5f3: 0x0008, 0x5f4: 0x0008, 0x5f5: 0x0008,
0x5f6: 0x0008, 0x5f7: 0x0008, 0x5f8: 0x0008, 0x5f9: 0x0008, 0x5fa: 0x0008, 0x5fb: 0x0008,
0x5fc: 0x0008, 0x5fd: 0x0008, 0x5fe: 0x0008, 0x5ff: 0x0008,
// Block 0x18, offset 0x600
0x600: 0x0008, 0x601: 0x3308, 0x602: 0x3008, 0x603: 0x3008, 0x604: 0x0040, 0x605: 0x0008,
0x606: 0x0008, 0x607: 0x0008, 0x608: 0x0008, 0x609: 0x0008, 0x60a: 0x0008, 0x60b: 0x0008,
0x60c: 0x0008, 0x60d: 0x0040, 0x60e: 0x0040, 0x60f: 0x0008, 0x610: 0x0008, 0x611: 0x0040,
0x612: 0x0040, 0x613: 0x0008, 0x614: 0x0008, 0x615: 0x0008, 0x616: 0x0008, 0x617: 0x0008,
0x618: 0x0008, 0x619: 0x0008, 0x61a: 0x0008, 0x61b: 0x0008, 0x61c: 0x0008, 0x61d: 0x0008,
0x61e: 0x0008, 0x61f: 0x0008, 0x620: 0x0008, 0x621: 0x0008, 0x622: 0x0008, 0x623: 0x0008,
0x624: 0x0008, 0x625: 0x0008, 0x626: 0x0008, 0x627: 0x0008, 0x628: 0x0008, 0x629: 0x0040,
0x62a: 0x0008, 0x62b: 0x0008, 0x62c: 0x0008, 0x62d: 0x0008, 0x62e: 0x0008, 0x62f: 0x0008,
0x630: 0x0008, 0x631: 0x0040, 0x632: 0x0008, 0x633: 0x0040, 0x634: 0x0040, 0x635: 0x0040,
0x636: 0x0008, 0x637: 0x0008, 0x638: 0x0008, 0x639: 0x0008, 0x63a: 0x0040, 0x63b: 0x0040,
0x63c: 0x3308, 0x63d: 0x0008, 0x63e: 0x3008, 0x63f: 0x3008,
// Block 0x19, offset 0x640
0x640: 0x3008, 0x641: 0x3308, 0x642: 0x3308, 0x643: 0x3308, 0x644: 0x3308, 0x645: 0x0040,
0x646: 0x0040, 0x647: 0x3008, 0x648: 0x3008, 0x649: 0x0040, 0x64a: 0x0040, 0x64b: 0x3008,
0x64c: 0x3008, 0x64d: 0x3b08, 0x64e: 0x0008, 0x64f: 0x0040, 0x650: 0x0040, 0x651: 0x0040,
0x652: 0x0040, 0x653: 0x0040, 0x654: 0x0040, 0x655: 0x0040, 0x656: 0x0040, 0x657: 0x3008,
0x658: 0x0040, 0x659: 0x0040, 0x65a: 0x0040, 0x65b: 0x0040, 0x65c: 0x0199, 0x65d: 0x01a1,
0x65e: 0x0040, 0x65f: 0x01a9, 0x660: 0x0008, 0x661: 0x0008, 0x662: 0x3308, 0x663: 0x3308,
0x664: 0x0040, 0x665: 0x0040, 0x666: 0x0008, 0x667: 0x0008, 0x668: 0x0008, 0x669: 0x0008,
0x66a: 0x0008, 0x66b: 0x0008, 0x66c: 0x0008, 0x66d: 0x0008, 0x66e: 0x0008, 0x66f: 0x0008,
0x670: 0x0008, 0x671: 0x0008, 0x672: 0x0018, 0x673: 0x0018, 0x674: 0x0018, 0x675: 0x0018,
0x676: 0x0018, 0x677: 0x0018, 0x678: 0x0018, 0x679: 0x0018, 0x67a: 0x0018, 0x67b: 0x0018,
0x67c: 0x0008, 0x67d: 0x0018, 0x67e: 0x3308, 0x67f: 0x0040,
// Block 0x1a, offset 0x680
0x680: 0x0040, 0x681: 0x3308, 0x682: 0x3308, 0x683: 0x3008, 0x684: 0x0040, 0x685: 0x0008,
0x686: 0x0008, 0x687: 0x0008, 0x688: 0x0008, 0x689: 0x0008, 0x68a: 0x0008, 0x68b: 0x0040,
0x68c: 0x0040, 0x68d: 0x0040, 0x68e: 0x0040, 0x68f: 0x0008, 0x690: 0x0008, 0x691: 0x0040,
0x692: 0x0040, 0x693: 0x0008, 0x694: 0x0008, 0x695: 0x0008, 0x696: 0x0008, 0x697: 0x0008,
0x698: 0x0008, 0x699: 0x0008, 0x69a: 0x0008, 0x69b: 0x0008, 0x69c: 0x0008, 0x69d: 0x0008,
0x69e: 0x0008, 0x69f: 0x0008, 0x6a0: 0x0008, 0x6a1: 0x0008, 0x6a2: 0x0008, 0x6a3: 0x0008,
0x6a4: 0x0008, 0x6a5: 0x0008, 0x6a6: 0x0008, 0x6a7: 0x0008, 0x6a8: 0x0008, 0x6a9: 0x0040,
0x6aa: 0x0008, 0x6ab: 0x0008, 0x6ac: 0x0008, 0x6ad: 0x0008, 0x6ae: 0x0008, 0x6af: 0x0008,
0x6b0: 0x0008, 0x6b1: 0x0040, 0x6b2: 0x0008, 0x6b3: 0x01b1, 0x6b4: 0x0040, 0x6b5: 0x0008,
0x6b6: 0x01b9, 0x6b7: 0x0040, 0x6b8: 0x0008, 0x6b9: 0x0008, 0x6ba: 0x0040, 0x6bb: 0x0040,
0x6bc: 0x3308, 0x6bd: 0x0040, 0x6be: 0x3008, 0x6bf: 0x3008,
// Block 0x1b, offset 0x6c0
0x6c0: 0x3008, 0x6c1: 0x3308, 0x6c2: 0x3308, 0x6c3: 0x0040, 0x6c4: 0x0040, 0x6c5: 0x0040,
0x6c6: 0x0040, 0x6c7: 0x3308, 0x6c8: 0x3308, 0x6c9: 0x0040, 0x6ca: 0x0040, 0x6cb: 0x3308,
0x6cc: 0x3308, 0x6cd: 0x3b08, 0x6ce: 0x0040, 0x6cf: 0x0040, 0x6d0: 0x0040, 0x6d1: 0x3308,
0x6d2: 0x0040, 0x6d3: 0x0040, 0x6d4: 0x0040, 0x6d5: 0x0040, 0x6d6: 0x0040, 0x6d7: 0x0040,
0x6d8: 0x0040, 0x6d9: 0x01c1, 0x6da: 0x01c9, 0x6db: 0x01d1, 0x6dc: 0x0008, 0x6dd: 0x0040,
0x6de: 0x01d9, 0x6df: 0x0040, 0x6e0: 0x0040, 0x6e1: 0x0040, 0x6e2: 0x0040, 0x6e3: 0x0040,
0x6e4: 0x0040, 0x6e5: 0x0040, 0x6e6: 0x0008, 0x6e7: 0x0008, 0x6e8: 0x0008, 0x6e9: 0x0008,
0x6ea: 0x0008, 0x6eb: 0x0008, 0x6ec: 0x0008, 0x6ed: 0x0008, 0x6ee: 0x0008, 0x6ef: 0x0008,
0x6f0: 0x3308, 0x6f1: 0x3308, 0x6f2: 0x0008, 0x6f3: 0x0008, 0x6f4: 0x0008, 0x6f5: 0x3308,
0x6f6: 0x0018, 0x6f7: 0x0040, 0x6f8: 0x0040, 0x6f9: 0x0040, 0x6fa: 0x0040, 0x6fb: 0x0040,
0x6fc: 0x0040, 0x6fd: 0x0040, 0x6fe: 0x0040, 0x6ff: 0x0040,
// Block 0x1c, offset 0x700
0x700: 0x0040, 0x701: 0x3308, 0x702: 0x3308, 0x703: 0x3008, 0x704: 0x0040, 0x705: 0x0008,
0x706: 0x0008, 0x707: 0x0008, 0x708: 0x0008, 0x709: 0x0008, 0x70a: 0x0008, 0x70b: 0x0008,
0x70c: 0x0008, 0x70d: 0x0008, 0x70e: 0x0040, 0x70f: 0x0008, 0x710: 0x0008, 0x711: 0x0008,
0x712: 0x0040, 0x713: 0x0008, 0x714: 0x0008, 0x715: 0x0008, 0x716: 0x0008, 0x717: 0x0008,
0x718: 0x0008, 0x719: 0x0008, 0x71a: 0x0008, 0x71b: 0x0008, 0x71c: 0x0008, 0x71d: 0x0008,
0x71e: 0x0008, 0x71f: 0x0008, 0x720: 0x0008, 0x721: 0x0008, 0x722: 0x0008, 0x723: 0x0008,
0x724: 0x0008, 0x725: 0x0008, 0x726: 0x0008, 0x727: 0x0008, 0x728: 0x0008, 0x729: 0x0040,
0x72a: 0x0008, 0x72b: 0x0008, 0x72c: 0x0008, 0x72d: 0x0008, 0x72e: 0x0008, 0x72f: 0x0008,
0x730: 0x0008, 0x731: 0x0040, 0x732: 0x0008, 0x733: 0x0008, 0x734: 0x0040, 0x735: 0x0008,
0x736: 0x0008, 0x737: 0x0008, 0x738: 0x0008, 0x739: 0x0008, 0x73a: 0x0040, 0x73b: 0x0040,
0x73c: 0x3308, 0x73d: 0x0008, 0x73e: 0x3008, 0x73f: 0x3008,
// Block 0x1d, offset 0x740
0x740: 0x3008, 0x741: 0x3308, 0x742: 0x3308, 0x743: 0x3308, 0x744: 0x3308, 0x745: 0x3308,
0x746: 0x0040, 0x747: 0x3308, 0x748: 0x3308, 0x749: 0x3008, 0x74a: 0x0040, 0x74b: 0x3008,
0x74c: 0x3008, 0x74d: 0x3b08, 0x74e: 0x0040, 0x74f: 0x0040, 0x750: 0x0008, 0x751: 0x0040,
0x752: 0x0040, 0x753: 0x0040, 0x754: 0x0040, 0x755: 0x0040, 0x756: 0x0040, 0x757: 0x0040,
0x758: 0x0040, 0x759: 0x0040, 0x75a: 0x0040, 0x75b: 0x0040, 0x75c: 0x0040, 0x75d: 0x0040,
0x75e: 0x0040, 0x75f: 0x0040, 0x760: 0x0008, 0x761: 0x0008, 0x762: 0x3308, 0x763: 0x3308,
0x764: 0x0040, 0x765: 0x0040, 0x766: 0x0008, 0x767: 0x0008, 0x768: 0x0008, 0x769: 0x0008,
0x76a: 0x0008, 0x76b: 0x0008, 0x76c: 0x0008, 0x76d: 0x0008, 0x76e: 0x0008, 0x76f: 0x0008,
0x770: 0x0018, 0x771: 0x0018, 0x772: 0x0040, 0x773: 0x0040, 0x774: 0x0040, 0x775: 0x0040,
0x776: 0x0040, 0x777: 0x0040, 0x778: 0x0040, 0x779: 0x0008, 0x77a: 0x3308, 0x77b: 0x3308,
0x77c: 0x3308, 0x77d: 0x3308, 0x77e: 0x3308, 0x77f: 0x3308,
// Block 0x1e, offset 0x780
0x780: 0x0040, 0x781: 0x3308, 0x782: 0x3008, 0x783: 0x3008, 0x784: 0x0040, 0x785: 0x0008,
0x786: 0x0008, 0x787: 0x0008, 0x788: 0x0008, 0x789: 0x0008, 0x78a: 0x0008, 0x78b: 0x0008,
0x78c: 0x0008, 0x78d: 0x0040, 0x78e: 0x0040, 0x78f: 0x0008, 0x790: 0x0008, 0x791: 0x0040,
0x792: 0x0040, 0x793: 0x0008, 0x794: 0x0008, 0x795: 0x0008, 0x796: 0x0008, 0x797: 0x0008,
0x798: 0x0008, 0x799: 0x0008, 0x79a: 0x0008, 0x79b: 0x0008, 0x79c: 0x0008, 0x79d: 0x0008,
0x79e: 0x0008, 0x79f: 0x0008, 0x7a0: 0x0008, 0x7a1: 0x0008, 0x7a2: 0x0008, 0x7a3: 0x0008,
0x7a4: 0x0008, 0x7a5: 0x0008, 0x7a6: 0x0008, 0x7a7: 0x0008, 0x7a8: 0x0008, 0x7a9: 0x0040,
0x7aa: 0x0008, 0x7ab: 0x0008, 0x7ac: 0x0008, 0x7ad: 0x0008, 0x7ae: 0x0008, 0x7af: 0x0008,
0x7b0: 0x0008, 0x7b1: 0x0040, 0x7b2: 0x0008, 0x7b3: 0x0008, 0x7b4: 0x0040, 0x7b5: 0x0008,
0x7b6: 0x0008, 0x7b7: 0x0008, 0x7b8: 0x0008, 0x7b9: 0x0008, 0x7ba: 0x0040, 0x7bb: 0x0040,
0x7bc: 0x3308, 0x7bd: 0x0008, 0x7be: 0x3008, 0x7bf: 0x3308,
// Block 0x1f, offset 0x7c0
0x7c0: 0x3008, 0x7c1: 0x3308, 0x7c2: 0x3308, 0x7c3: 0x3308, 0x7c4: 0x3308, 0x7c5: 0x0040,
0x7c6: 0x0040, 0x7c7: 0x3008, 0x7c8: 0x3008, 0x7c9: 0x0040, 0x7ca: 0x0040, 0x7cb: 0x3008,
0x7cc: 0x3008, 0x7cd: 0x3b08, 0x7ce: 0x0040, 0x7cf: 0x0040, 0x7d0: 0x0040, 0x7d1: 0x0040,
0x7d2: 0x0040, 0x7d3: 0x0040, 0x7d4: 0x0040, 0x7d5: 0x3308, 0x7d6: 0x3308, 0x7d7: 0x3008,
0x7d8: 0x0040, 0x7d9: 0x0040, 0x7da: 0x0040, 0x7db: 0x0040, 0x7dc: 0x01e1, 0x7dd: 0x01e9,
0x7de: 0x0040, 0x7df: 0x0008, 0x7e0: 0x0008, 0x7e1: 0x0008, 0x7e2: 0x3308, 0x7e3: 0x3308,
0x7e4: 0x0040, 0x7e5: 0x0040, 0x7e6: 0x0008, 0x7e7: 0x0008, 0x7e8: 0x0008, 0x7e9: 0x0008,
0x7ea: 0x0008, 0x7eb: 0x0008, 0x7ec: 0x0008, 0x7ed: 0x0008, 0x7ee: 0x0008, 0x7ef: 0x0008,
0x7f0: 0x0018, 0x7f1: 0x0008, 0x7f2: 0x0018, 0x7f3: 0x0018, 0x7f4: 0x0018, 0x7f5: 0x0018,
0x7f6: 0x0018, 0x7f7: 0x0018, 0x7f8: 0x0040, 0x7f9: 0x0040, 0x7fa: 0x0040, 0x7fb: 0x0040,
0x7fc: 0x0040, 0x7fd: 0x0040, 0x7fe: 0x0040, 0x7ff: 0x0040,
// Block 0x20, offset 0x800
0x800: 0x0040, 0x801: 0x0040, 0x802: 0x3308, 0x803: 0x0008, 0x804: 0x0040, 0x805: 0x0008,
0x806: 0x0008, 0x807: 0x0008, 0x808: 0x0008, 0x809: 0x0008, 0x80a: 0x0008, 0x80b: 0x0040,
0x80c: 0x0040, 0x80d: 0x0040, 0x80e: 0x0008, 0x80f: 0x0008, 0x810: 0x0008, 0x811: 0x0040,
0x812: 0x0008, 0x813: 0x0008, 0x814: 0x0008, 0x815: 0x0008, 0x816: 0x0040, 0x817: 0x0040,
0x818: 0x0040, 0x819: 0x0008, 0x81a: 0x0008, 0x81b: 0x0040, 0x81c: 0x0008, 0x81d: 0x0040,
0x81e: 0x0008, 0x81f: 0x0008, 0x820: 0x0040, 0x821: 0x0040, 0x822: 0x0040, 0x823: 0x0008,
0x824: 0x0008, 0x825: 0x0040, 0x826: 0x0040, 0x827: 0x0040, 0x828: 0x0008, 0x829: 0x0008,
0x82a: 0x0008, 0x82b: 0x0040, 0x82c: 0x0040, 0x82d: 0x0040, 0x82e: 0x0008, 0x82f: 0x0008,
0x830: 0x0008, 0x831: 0x0008, 0x832: 0x0008, 0x833: 0x0008, 0x834: 0x0008, 0x835: 0x0008,
0x836: 0x0008, 0x837: 0x0008, 0x838: 0x0008, 0x839: 0x0008, 0x83a: 0x0040, 0x83b: 0x0040,
0x83c: 0x0040, 0x83d: 0x0040, 0x83e: 0x3008, 0x83f: 0x3008,
// Block 0x21, offset 0x840
0x840: 0x3308, 0x841: 0x3008, 0x842: 0x3008, 0x843: 0x3008, 0x844: 0x3008, 0x845: 0x0040,
0x846: 0x3308, 0x847: 0x3308, 0x848: 0x3308, 0x849: 0x0040, 0x84a: 0x3308, 0x84b: 0x3308,
0x84c: 0x3308, 0x84d: 0x3b08, 0x84e: 0x0040, 0x84f: 0x0040, 0x850: 0x0040, 0x851: 0x0040,
0x852: 0x0040, 0x853: 0x0040, 0x854: 0x0040, 0x855: 0x3308, 0x856: 0x3308, 0x857: 0x0040,
0x858: 0x0008, 0x859: 0x0008, 0x85a: 0x0008, 0x85b: 0x0040, 0x85c: 0x0040, 0x85d: 0x0008,
0x85e: 0x0040, 0x85f: 0x0040, 0x860: 0x0008, 0x861: 0x0008, 0x862: 0x3308, 0x863: 0x3308,
0x864: 0x0040, 0x865: 0x0040, 0x866: 0x0008, 0x867: 0x0008, 0x868: 0x0008, 0x869: 0x0008,
0x86a: 0x0008, 0x86b: 0x0008, 0x86c: 0x0008, 0x86d: 0x0008, 0x86e: 0x0008, 0x86f: 0x0008,
0x870: 0x0040, 0x871: 0x0040, 0x872: 0x0040, 0x873: 0x0040, 0x874: 0x0040, 0x875: 0x0040,
0x876: 0x0040, 0x877: 0x0018, 0x878: 0x0018, 0x879: 0x0018, 0x87a: 0x0018, 0x87b: 0x0018,
0x87c: 0x0018, 0x87d: 0x0018, 0x87e: 0x0018, 0x87f: 0x0018,
// Block 0x22, offset 0x880
0x880: 0x0008, 0x881: 0x3308, 0x882: 0x3008, 0x883: 0x3008, 0x884: 0x0018, 0x885: 0x0008,
0x886: 0x0008, 0x887: 0x0008, 0x888: 0x0008, 0x889: 0x0008, 0x88a: 0x0008, 0x88b: 0x0008,
0x88c: 0x0008, 0x88d: 0x0040, 0x88e: 0x0008, 0x88f: 0x0008, 0x890: 0x0008, 0x891: 0x0040,
0x892: 0x0008, 0x893: 0x0008, 0x894: 0x0008, 0x895: 0x0008, 0x896: 0x0008, 0x897: 0x0008,
0x898: 0x0008, 0x899: 0x0008, 0x89a: 0x0008, 0x89b: 0x0008, 0x89c: 0x0008, 0x89d: 0x0008,
0x89e: 0x0008, 0x89f: 0x0008, 0x8a0: 0x0008, 0x8a1: 0x0008, 0x8a2: 0x0008, 0x8a3: 0x0008,
0x8a4: 0x0008, 0x8a5: 0x0008, 0x8a6: 0x0008, 0x8a7: 0x0008, 0x8a8: 0x0008, 0x8a9: 0x0040,
0x8aa: 0x0008, 0x8ab: 0x0008, 0x8ac: 0x0008, 0x8ad: 0x0008, 0x8ae: 0x0008, 0x8af: 0x0008,
0x8b0: 0x0008, 0x8b1: 0x0008, 0x8b2: 0x0008, 0x8b3: 0x0008, 0x8b4: 0x0040, 0x8b5: 0x0008,
0x8b6: 0x0008, 0x8b7: 0x0008, 0x8b8: 0x0008, 0x8b9: 0x0008, 0x8ba: 0x0040, 0x8bb: 0x0040,
0x8bc: 0x3308, 0x8bd: 0x0008, 0x8be: 0x3008, 0x8bf: 0x3308,
// Block 0x23, offset 0x8c0
0x8c0: 0x3008, 0x8c1: 0x3008, 0x8c2: 0x3008, 0x8c3: 0x3008, 0x8c4: 0x3008, 0x8c5: 0x0040,
0x8c6: 0x3308, 0x8c7: 0x3008, 0x8c8: 0x3008, 0x8c9: 0x0040, 0x8ca: 0x3008, 0x8cb: 0x3008,
0x8cc: 0x3308, 0x8cd: 0x3b08, 0x8ce: 0x0040, 0x8cf: 0x0040, 0x8d0: 0x0040, 0x8d1: 0x0040,
0x8d2: 0x0040, 0x8d3: 0x0040, 0x8d4: 0x0040, 0x8d5: 0x3008, 0x8d6: 0x3008, 0x8d7: 0x0040,
0x8d8: 0x0040, 0x8d9: 0x0040, 0x8da: 0x0040, 0x8db: 0x0040, 0x8dc: 0x0040, 0x8dd: 0x0008,
0x8de: 0x0008, 0x8df: 0x0040, 0x8e0: 0x0008, 0x8e1: 0x0008, 0x8e2: 0x3308, 0x8e3: 0x3308,
0x8e4: 0x0040, 0x8e5: 0x0040, 0x8e6: 0x0008, 0x8e7: 0x0008, 0x8e8: 0x0008, 0x8e9: 0x0008,
0x8ea: 0x0008, 0x8eb: 0x0008, 0x8ec: 0x0008, 0x8ed: 0x0008, 0x8ee: 0x0008, 0x8ef: 0x0008,
0x8f0: 0x0040, 0x8f1: 0x0008, 0x8f2: 0x0008, 0x8f3: 0x3008, 0x8f4: 0x0040, 0x8f5: 0x0040,
0x8f6: 0x0040, 0x8f7: 0x0040, 0x8f8: 0x0040, 0x8f9: 0x0040, 0x8fa: 0x0040, 0x8fb: 0x0040,
0x8fc: 0x0040, 0x8fd: 0x0040, 0x8fe: 0x0040, 0x8ff: 0x0040,
// Block 0x24, offset 0x900
0x900: 0x3008, 0x901: 0x3308, 0x902: 0x3308, 0x903: 0x3308, 0x904: 0x3308, 0x905: 0x0040,
0x906: 0x3008, 0x907: 0x3008, 0x908: 0x3008, 0x909: 0x0040, 0x90a: 0x3008, 0x90b: 0x3008,
0x90c: 0x3008, 0x90d: 0x3b08, 0x90e: 0x0008, 0x90f: 0x0018, 0x910: 0x0040, 0x911: 0x0040,
0x912: 0x0040, 0x913: 0x0040, 0x914: 0x0008, 0x915: 0x0008, 0x916: 0x0008, 0x917: 0x3008,
0x918: 0x0018, 0x919: 0x0018, 0x91a: 0x0018, 0x91b: 0x0018, 0x91c: 0x0018, 0x91d: 0x0018,
0x91e: 0x0018, 0x91f: 0x0008, 0x920: 0x0008, 0x921: 0x0008, 0x922: 0x3308, 0x923: 0x3308,
0x924: 0x0040, 0x925: 0x0040, 0x926: 0x0008, 0x927: 0x0008, 0x928: 0x0008, 0x929: 0x0008,
0x92a: 0x0008, 0x92b: 0x0008, 0x92c: 0x0008, 0x92d: 0x0008, 0x92e: 0x0008, 0x92f: 0x0008,
0x930: 0x0018, 0x931: 0x0018, 0x932: 0x0018, 0x933: 0x0018, 0x934: 0x0018, 0x935: 0x0018,
0x936: 0x0018, 0x937: 0x0018, 0x938: 0x0018, 0x939: 0x0018, 0x93a: 0x0008, 0x93b: 0x0008,
0x93c: 0x0008, 0x93d: 0x0008, 0x93e: 0x0008, 0x93f: 0x0008,
// Block 0x25, offset 0x940
0x940: 0x0040, 0x941: 0x0008, 0x942: 0x0008, 0x943: 0x0040, 0x944: 0x0008, 0x945: 0x0040,
0x946: 0x0008, 0x947: 0x0008, 0x948: 0x0008, 0x949: 0x0008, 0x94a: 0x0008, 0x94b: 0x0040,
0x94c: 0x0008, 0x94d: 0x0008, 0x94e: 0x0008, 0x94f: 0x0008, 0x950: 0x0008, 0x951: 0x0008,
0x952: 0x0008, 0x953: 0x0008, 0x954: 0x0008, 0x955: 0x0008, 0x956: 0x0008, 0x957: 0x0008,
0x958: 0x0008, 0x959: 0x0008, 0x95a: 0x0008, 0x95b: 0x0008, 0x95c: 0x0008, 0x95d: 0x0008,
0x95e: 0x0008, 0x95f: 0x0008, 0x960: 0x0008, 0x961: 0x0008, 0x962: 0x0008, 0x963: 0x0008,
0x964: 0x0040, 0x965: 0x0008, 0x966: 0x0040, 0x967: 0x0008, 0x968: 0x0008, 0x969: 0x0008,
0x96a: 0x0008, 0x96b: 0x0008, 0x96c: 0x0008, 0x96d: 0x0008, 0x96e: 0x0008, 0x96f: 0x0008,
0x970: 0x0008, 0x971: 0x3308, 0x972: 0x0008, 0x973: 0x01f9, 0x974: 0x3308, 0x975: 0x3308,
0x976: 0x3308, 0x977: 0x3308, 0x978: 0x3308, 0x979: 0x3308, 0x97a: 0x3b08, 0x97b: 0x3308,
0x97c: 0x3308, 0x97d: 0x0008, 0x97e: 0x0040, 0x97f: 0x0040,
// Block 0x26, offset 0x980
0x980: 0x0008, 0x981: 0x0008, 0x982: 0x0008, 0x983: 0x0211, 0x984: 0x0008, 0x985: 0x0008,
0x986: 0x0008, 0x987: 0x0008, 0x988: 0x0040, 0x989: 0x0008, 0x98a: 0x0008, 0x98b: 0x0008,
0x98c: 0x0008, 0x98d: 0x0219, 0x98e: 0x0008, 0x98f: 0x0008, 0x990: 0x0008, 0x991: 0x0008,
0x992: 0x0221, 0x993: 0x0008, 0x994: 0x0008, 0x995: 0x0008, 0x996: 0x0008, 0x997: 0x0229,
0x998: 0x0008, 0x999: 0x0008, 0x99a: 0x0008, 0x99b: 0x0008, 0x99c: 0x0231, 0x99d: 0x0008,
0x99e: 0x0008, 0x99f: 0x0008, 0x9a0: 0x0008, 0x9a1: 0x0008, 0x9a2: 0x0008, 0x9a3: 0x0008,
0x9a4: 0x0008, 0x9a5: 0x0008, 0x9a6: 0x0008, 0x9a7: 0x0008, 0x9a8: 0x0008, 0x9a9: 0x0239,
0x9aa: 0x0008, 0x9ab: 0x0008, 0x9ac: 0x0008, 0x9ad: 0x0040, 0x9ae: 0x0040, 0x9af: 0x0040,
0x9b0: 0x0040, 0x9b1: 0x3308, 0x9b2: 0x3308, 0x9b3: 0x0241, 0x9b4: 0x3308, 0x9b5: 0x0249,
0x9b6: 0x0251, 0x9b7: 0x0259, 0x9b8: 0x0261, 0x9b9: 0x0269, 0x9ba: 0x3308, 0x9bb: 0x3308,
0x9bc: 0x3308, 0x9bd: 0x3308, 0x9be: 0x3308, 0x9bf: 0x3008,
// Block 0x27, offset 0x9c0
0x9c0: 0x3308, 0x9c1: 0x0271, 0x9c2: 0x3308, 0x9c3: 0x3308, 0x9c4: 0x3b08, 0x9c5: 0x0018,
0x9c6: 0x3308, 0x9c7: 0x3308, 0x9c8: 0x0008, 0x9c9: 0x0008, 0x9ca: 0x0008, 0x9cb: 0x0008,
0x9cc: 0x0008, 0x9cd: 0x3308, 0x9ce: 0x3308, 0x9cf: 0x3308, 0x9d0: 0x3308, 0x9d1: 0x3308,
0x9d2: 0x3308, 0x9d3: 0x0279, 0x9d4: 0x3308, 0x9d5: 0x3308, 0x9d6: 0x3308, 0x9d7: 0x3308,
0x9d8: 0x0040, 0x9d9: 0x3308, 0x9da: 0x3308, 0x9db: 0x3308, 0x9dc: 0x3308, 0x9dd: 0x0281,
0x9de: 0x3308, 0x9df: 0x3308, 0x9e0: 0x3308, 0x9e1: 0x3308, 0x9e2: 0x0289, 0x9e3: 0x3308,
0x9e4: 0x3308, 0x9e5: 0x3308, 0x9e6: 0x3308, 0x9e7: 0x0291, 0x9e8: 0x3308, 0x9e9: 0x3308,
0x9ea: 0x3308, 0x9eb: 0x3308, 0x9ec: 0x0299, 0x9ed: 0x3308, 0x9ee: 0x3308, 0x9ef: 0x3308,
0x9f0: 0x3308, 0x9f1: 0x3308, 0x9f2: 0x3308, 0x9f3: 0x3308, 0x9f4: 0x3308, 0x9f5: 0x3308,
0x9f6: 0x3308, 0x9f7: 0x3308, 0x9f8: 0x3308, 0x9f9: 0x02a1, 0x9fa: 0x3308, 0x9fb: 0x3308,
0x9fc: 0x3308, 0x9fd: 0x0040, 0x9fe: 0x0018, 0x9ff: 0x0018,
// Block 0x28, offset 0xa00
0xa00: 0x0008, 0xa01: 0x0008, 0xa02: 0x0008, 0xa03: 0x0008, 0xa04: 0x0008, 0xa05: 0x0008,
0xa06: 0x0008, 0xa07: 0x0008, 0xa08: 0x0008, 0xa09: 0x0008, 0xa0a: 0x0008, 0xa0b: 0x0008,
0xa0c: 0x0008, 0xa0d: 0x0008, 0xa0e: 0x0008, 0xa0f: 0x0008, 0xa10: 0x0008, 0xa11: 0x0008,
0xa12: 0x0008, 0xa13: 0x0008, 0xa14: 0x0008, 0xa15: 0x0008, 0xa16: 0x0008, 0xa17: 0x0008,
0xa18: 0x0008, 0xa19: 0x0008, 0xa1a: 0x0008, 0xa1b: 0x0008, 0xa1c: 0x0008, 0xa1d: 0x0008,
0xa1e: 0x0008, 0xa1f: 0x0008, 0xa20: 0x0008, 0xa21: 0x0008, 0xa22: 0x0008, 0xa23: 0x0008,
0xa24: 0x0008, 0xa25: 0x0008, 0xa26: 0x0008, 0xa27: 0x0008, 0xa28: 0x0008, 0xa29: 0x0008,
0xa2a: 0x0008, 0xa2b: 0x0008, 0xa2c: 0x0019, 0xa2d: 0x02e1, 0xa2e: 0x02e9, 0xa2f: 0x0008,
0xa30: 0x02f1, 0xa31: 0x02f9, 0xa32: 0x0301, 0xa33: 0x0309, 0xa34: 0x00a9, 0xa35: 0x0311,
0xa36: 0x00b1, 0xa37: 0x0319, 0xa38: 0x0101, 0xa39: 0x0321, 0xa3a: 0x0329, 0xa3b: 0x0008,
0xa3c: 0x0051, 0xa3d: 0x0331, 0xa3e: 0x0339, 0xa3f: 0x00b9,
// Block 0x29, offset 0xa40
0xa40: 0x0341, 0xa41: 0x0349, 0xa42: 0x00c1, 0xa43: 0x0019, 0xa44: 0x0351, 0xa45: 0x0359,
0xa46: 0x05b5, 0xa47: 0x02e9, 0xa48: 0x02f1, 0xa49: 0x02f9, 0xa4a: 0x0361, 0xa4b: 0x0369,
0xa4c: 0x0371, 0xa4d: 0x0309, 0xa4e: 0x0008, 0xa4f: 0x0319, 0xa50: 0x0321, 0xa51: 0x0379,
0xa52: 0x0051, 0xa53: 0x0381, 0xa54: 0x05cd, 0xa55: 0x05cd, 0xa56: 0x0339, 0xa57: 0x0341,
0xa58: 0x0349, 0xa59: 0x05b5, 0xa5a: 0x0389, 0xa5b: 0x0391, 0xa5c: 0x05e5, 0xa5d: 0x0399,
0xa5e: 0x03a1, 0xa5f: 0x03a9, 0xa60: 0x03b1, 0xa61: 0x03b9, 0xa62: 0x0311, 0xa63: 0x00b9,
0xa64: 0x0349, 0xa65: 0x0391, 0xa66: 0x0399, 0xa67: 0x03a1, 0xa68: 0x03c1, 0xa69: 0x03b1,
0xa6a: 0x03b9, 0xa6b: 0x0008, 0xa6c: 0x0008, 0xa6d: 0x0008, 0xa6e: 0x0008, 0xa6f: 0x0008,
0xa70: 0x0008, 0xa71: 0x0008, 0xa72: 0x0008, 0xa73: 0x0008, 0xa74: 0x0008, 0xa75: 0x0008,
0xa76: 0x0008, 0xa77: 0x0008, 0xa78: 0x03c9, 0xa79: 0x0008, 0xa7a: 0x0008, 0xa7b: 0x0008,
0xa7c: 0x0008, 0xa7d: 0x0008, 0xa7e: 0x0008, 0xa7f: 0x0008,
// Block 0x2a, offset 0xa80
0xa80: 0x0008, 0xa81: 0x0008, 0xa82: 0x0008, 0xa83: 0x0008, 0xa84: 0x0008, 0xa85: 0x0008,
0xa86: 0x0008, 0xa87: 0x0008, 0xa88: 0x0008, 0xa89: 0x0008, 0xa8a: 0x0008, 0xa8b: 0x0008,
0xa8c: 0x0008, 0xa8d: 0x0008, 0xa8e: 0x0008, 0xa8f: 0x0008, 0xa90: 0x0008, 0xa91: 0x0008,
0xa92: 0x0008, 0xa93: 0x0008, 0xa94: 0x0008, 0xa95: 0x0008, 0xa96: 0x0008, 0xa97: 0x0008,
0xa98: 0x0008, 0xa99: 0x0008, 0xa9a: 0x0008, 0xa9b: 0x03d1, 0xa9c: 0x03d9, 0xa9d: 0x03e1,
0xa9e: 0x03e9, 0xa9f: 0x0371, 0xaa0: 0x03f1, 0xaa1: 0x03f9, 0xaa2: 0x0401, 0xaa3: 0x0409,
0xaa4: 0x0411, 0xaa5: 0x0419, 0xaa6: 0x0421, 0xaa7: 0x05fd, 0xaa8: 0x0429, 0xaa9: 0x0431,
0xaaa: 0xe17d, 0xaab: 0x0439, 0xaac: 0x0441, 0xaad: 0x0449, 0xaae: 0x0451, 0xaaf: 0x0459,
0xab0: 0x0461, 0xab1: 0x0469, 0xab2: 0x0471, 0xab3: 0x0479, 0xab4: 0x0481, 0xab5: 0x0489,
0xab6: 0x0491, 0xab7: 0x0499, 0xab8: 0x0615, 0xab9: 0x04a1, 0xaba: 0x04a9, 0xabb: 0x04b1,
0xabc: 0x04b9, 0xabd: 0x04c1, 0xabe: 0x04c9, 0xabf: 0x04d1,
// Block 0x2b, offset 0xac0
0xac0: 0xe00d, 0xac1: 0x0008, 0xac2: 0xe00d, 0xac3: 0x0008, 0xac4: 0xe00d, 0xac5: 0x0008,
0xac6: 0xe00d, 0xac7: 0x0008, 0xac8: 0xe00d, 0xac9: 0x0008, 0xaca: 0xe00d, 0xacb: 0x0008,
0xacc: 0xe00d, 0xacd: 0x0008, 0xace: 0xe00d, 0xacf: 0x0008, 0xad0: 0xe00d, 0xad1: 0x0008,
0xad2: 0xe00d, 0xad3: 0x0008, 0xad4: 0xe00d, 0xad5: 0x0008, 0xad6: 0xe00d, 0xad7: 0x0008,
0xad8: 0xe00d, 0xad9: 0x0008, 0xada: 0xe00d, 0xadb: 0x0008, 0xadc: 0xe00d, 0xadd: 0x0008,
0xade: 0xe00d, 0xadf: 0x0008, 0xae0: 0xe00d, 0xae1: 0x0008, 0xae2: 0xe00d, 0xae3: 0x0008,
0xae4: 0xe00d, 0xae5: 0x0008, 0xae6: 0xe00d, 0xae7: 0x0008, 0xae8: 0xe00d, 0xae9: 0x0008,
0xaea: 0xe00d, 0xaeb: 0x0008, 0xaec: 0xe00d, 0xaed: 0x0008, 0xaee: 0xe00d, 0xaef: 0x0008,
0xaf0: 0xe00d, 0xaf1: 0x0008, 0xaf2: 0xe00d, 0xaf3: 0x0008, 0xaf4: 0xe00d, 0xaf5: 0x0008,
0xaf6: 0xe00d, 0xaf7: 0x0008, 0xaf8: 0xe00d, 0xaf9: 0x0008, 0xafa: 0xe00d, 0xafb: 0x0008,
0xafc: 0xe00d, 0xafd: 0x0008, 0xafe: 0xe00d, 0xaff: 0x0008,
// Block 0x2c, offset 0xb00
0xb00: 0xe00d, 0xb01: 0x0008, 0xb02: 0xe00d, 0xb03: 0x0008, 0xb04: 0xe00d, 0xb05: 0x0008,
0xb06: 0xe00d, 0xb07: 0x0008, 0xb08: 0xe00d, 0xb09: 0x0008, 0xb0a: 0xe00d, 0xb0b: 0x0008,
0xb0c: 0xe00d, 0xb0d: 0x0008, 0xb0e: 0xe00d, 0xb0f: 0x0008, 0xb10: 0xe00d, 0xb11: 0x0008,
0xb12: 0xe00d, 0xb13: 0x0008, 0xb14: 0xe00d, 0xb15: 0x0008, 0xb16: 0x0008, 0xb17: 0x0008,
0xb18: 0x0008, 0xb19: 0x0008, 0xb1a: 0x062d, 0xb1b: 0x064d, 0xb1c: 0x0008, 0xb1d: 0x0008,
0xb1e: 0x04d9, 0xb1f: 0x0008, 0xb20: 0xe00d, 0xb21: 0x0008, 0xb22: 0xe00d, 0xb23: 0x0008,
0xb24: 0xe00d, 0xb25: 0x0008, 0xb26: 0xe00d, 0xb27: 0x0008, 0xb28: 0xe00d, 0xb29: 0x0008,
0xb2a: 0xe00d, 0xb2b: 0x0008, 0xb2c: 0xe00d, 0xb2d: 0x0008, 0xb2e: 0xe00d, 0xb2f: 0x0008,
0xb30: 0xe00d, 0xb31: 0x0008, 0xb32: 0xe00d, 0xb33: 0x0008, 0xb34: 0xe00d, 0xb35: 0x0008,
0xb36: 0xe00d, 0xb37: 0x0008, 0xb38: 0xe00d, 0xb39: 0x0008, 0xb3a: 0xe00d, 0xb3b: 0x0008,
0xb3c: 0xe00d, 0xb3d: 0x0008, 0xb3e: 0xe00d, 0xb3f: 0x0008,
// Block 0x2d, offset 0xb40
0xb40: 0x0008, 0xb41: 0x0008, 0xb42: 0x0008, 0xb43: 0x0008, 0xb44: 0x0008, 0xb45: 0x0008,
0xb46: 0x0040, 0xb47: 0x0040, 0xb48: 0xe045, 0xb49: 0xe045, 0xb4a: 0xe045, 0xb4b: 0xe045,
0xb4c: 0xe045, 0xb4d: 0xe045, 0xb4e: 0x0040, 0xb4f: 0x0040, 0xb50: 0x0008, 0xb51: 0x0008,
0xb52: 0x0008, 0xb53: 0x0008, 0xb54: 0x0008, 0xb55: 0x0008, 0xb56: 0x0008, 0xb57: 0x0008,
0xb58: 0x0040, 0xb59: 0xe045, 0xb5a: 0x0040, 0xb5b: 0xe045, 0xb5c: 0x0040, 0xb5d: 0xe045,
0xb5e: 0x0040, 0xb5f: 0xe045, 0xb60: 0x0008, 0xb61: 0x0008, 0xb62: 0x0008, 0xb63: 0x0008,
0xb64: 0x0008, 0xb65: 0x0008, 0xb66: 0x0008, 0xb67: 0x0008, 0xb68: 0xe045, 0xb69: 0xe045,
0xb6a: 0xe045, 0xb6b: 0xe045, 0xb6c: 0xe045, 0xb6d: 0xe045, 0xb6e: 0xe045, 0xb6f: 0xe045,
0xb70: 0x0008, 0xb71: 0x04e1, 0xb72: 0x0008, 0xb73: 0x04e9, 0xb74: 0x0008, 0xb75: 0x04f1,
0xb76: 0x0008, 0xb77: 0x04f9, 0xb78: 0x0008, 0xb79: 0x0501, 0xb7a: 0x0008, 0xb7b: 0x0509,
0xb7c: 0x0008, 0xb7d: 0x0511, 0xb7e: 0x0040, 0xb7f: 0x0040,
// Block 0x2e, offset 0xb80
0xb80: 0x0519, 0xb81: 0x0521, 0xb82: 0x0529, 0xb83: 0x0531, 0xb84: 0x0539, 0xb85: 0x0541,
0xb86: 0x0549, 0xb87: 0x0551, 0xb88: 0x0519, 0xb89: 0x0521, 0xb8a: 0x0529, 0xb8b: 0x0531,
0xb8c: 0x0539, 0xb8d: 0x0541, 0xb8e: 0x0549, 0xb8f: 0x0551, 0xb90: 0x0559, 0xb91: 0x0561,
0xb92: 0x0569, 0xb93: 0x0571, 0xb94: 0x0579, 0xb95: 0x0581, 0xb96: 0x0589, 0xb97: 0x0591,
0xb98: 0x0559, 0xb99: 0x0561, 0xb9a: 0x0569, 0xb9b: 0x0571, 0xb9c: 0x0579, 0xb9d: 0x0581,
0xb9e: 0x0589, 0xb9f: 0x0591, 0xba0: 0x0599, 0xba1: 0x05a1, 0xba2: 0x05a9, 0xba3: 0x05b1,
0xba4: 0x05b9, 0xba5: 0x05c1, 0xba6: 0x05c9, 0xba7: 0x05d1, 0xba8: 0x0599, 0xba9: 0x05a1,
0xbaa: 0x05a9, 0xbab: 0x05b1, 0xbac: 0x05b9, 0xbad: 0x05c1, 0xbae: 0x05c9, 0xbaf: 0x05d1,
0xbb0: 0x0008, 0xbb1: 0x0008, 0xbb2: 0x05d9, 0xbb3: 0x05e1, 0xbb4: 0x05e9, 0xbb5: 0x0040,
0xbb6: 0x0008, 0xbb7: 0x05f1, 0xbb8: 0xe045, 0xbb9: 0xe045, 0xbba: 0x0665, 0xbbb: 0x04e1,
0xbbc: 0x05e1, 0xbbd: 0x067e, 0xbbe: 0x05f9, 0xbbf: 0x069e,
// Block 0x2f, offset 0xbc0
0xbc0: 0x06be, 0xbc1: 0x0602, 0xbc2: 0x0609, 0xbc3: 0x0611, 0xbc4: 0x0619, 0xbc5: 0x0040,
0xbc6: 0x0008, 0xbc7: 0x0621, 0xbc8: 0x06dd, 0xbc9: 0x04e9, 0xbca: 0x06f5, 0xbcb: 0x04f1,
0xbcc: 0x0611, 0xbcd: 0x062a, 0xbce: 0x0632, 0xbcf: 0x063a, 0xbd0: 0x0008, 0xbd1: 0x0008,
0xbd2: 0x0008, 0xbd3: 0x0641, 0xbd4: 0x0040, 0xbd5: 0x0040, 0xbd6: 0x0008, 0xbd7: 0x0008,
0xbd8: 0xe045, 0xbd9: 0xe045, 0xbda: 0x070d, 0xbdb: 0x04f9, 0xbdc: 0x0040, 0xbdd: 0x064a,
0xbde: 0x0652, 0xbdf: 0x065a, 0xbe0: 0x0008, 0xbe1: 0x0008, 0xbe2: 0x0008, 0xbe3: 0x0661,
0xbe4: 0x0008, 0xbe5: 0x0008, 0xbe6: 0x0008, 0xbe7: 0x0008, 0xbe8: 0xe045, 0xbe9: 0xe045,
0xbea: 0x0725, 0xbeb: 0x0509, 0xbec: 0xe04d, 0xbed: 0x066a, 0xbee: 0x012a, 0xbef: 0x0672,
0xbf0: 0x0040, 0xbf1: 0x0040, 0xbf2: 0x0679, 0xbf3: 0x0681, 0xbf4: 0x0689, 0xbf5: 0x0040,
0xbf6: 0x0008, 0xbf7: 0x0691, 0xbf8: 0x073d, 0xbf9: 0x0501, 0xbfa: 0x0515, 0xbfb: 0x0511,
0xbfc: 0x0681, 0xbfd: 0x0756, 0xbfe: 0x0776, 0xbff: 0x0040,
// Block 0x30, offset 0xc00
0xc00: 0x000a, 0xc01: 0x000a, 0xc02: 0x000a, 0xc03: 0x000a, 0xc04: 0x000a, 0xc05: 0x000a,
0xc06: 0x000a, 0xc07: 0x000a, 0xc08: 0x000a, 0xc09: 0x000a, 0xc0a: 0x000a, 0xc0b: 0x03c0,
0xc0c: 0x0003, 0xc0d: 0x0003, 0xc0e: 0x0340, 0xc0f: 0x0b40, 0xc10: 0x0018, 0xc11: 0xe00d,
0xc12: 0x0018, 0xc13: 0x0018, 0xc14: 0x0018, 0xc15: 0x0018, 0xc16: 0x0018, 0xc17: 0x0796,
0xc18: 0x0018, 0xc19: 0x0018, 0xc1a: 0x0018, 0xc1b: 0x0018, 0xc1c: 0x0018, 0xc1d: 0x0018,
0xc1e: 0x0018, 0xc1f: 0x0018, 0xc20: 0x0018, 0xc21: 0x0018, 0xc22: 0x0018, 0xc23: 0x0018,
0xc24: 0x0040, 0xc25: 0x0040, 0xc26: 0x0040, 0xc27: 0x0018, 0xc28: 0x0040, 0xc29: 0x0040,
0xc2a: 0x0340, 0xc2b: 0x0340, 0xc2c: 0x0340, 0xc2d: 0x0340, 0xc2e: 0x0340, 0xc2f: 0x000a,
0xc30: 0x0018, 0xc31: 0x0018, 0xc32: 0x0018, 0xc33: 0x0699, 0xc34: 0x06a1, 0xc35: 0x0018,
0xc36: 0x06a9, 0xc37: 0x06b1, 0xc38: 0x0018, 0xc39: 0x0018, 0xc3a: 0x0018, 0xc3b: 0x0018,
0xc3c: 0x06ba, 0xc3d: 0x0018, 0xc3e: 0x07b6, 0xc3f: 0x0018,
// Block 0x31, offset 0xc40
0xc40: 0x0018, 0xc41: 0x0018, 0xc42: 0x0018, 0xc43: 0x0018, 0xc44: 0x0018, 0xc45: 0x0018,
0xc46: 0x0018, 0xc47: 0x06c2, 0xc48: 0x06ca, 0xc49: 0x06d2, 0xc4a: 0x0018, 0xc4b: 0x0018,
0xc4c: 0x0018, 0xc4d: 0x0018, 0xc4e: 0x0018, 0xc4f: 0x0018, 0xc50: 0x0018, 0xc51: 0x0018,
0xc52: 0x0018, 0xc53: 0x0018, 0xc54: 0x0018, 0xc55: 0x0018, 0xc56: 0x0018, 0xc57: 0x06d9,
0xc58: 0x0018, 0xc59: 0x0018, 0xc5a: 0x0018, 0xc5b: 0x0018, 0xc5c: 0x0018, 0xc5d: 0x0018,
0xc5e: 0x0018, 0xc5f: 0x000a, 0xc60: 0x03c0, 0xc61: 0x0340, 0xc62: 0x0340, 0xc63: 0x0340,
0xc64: 0x03c0, 0xc65: 0x0040, 0xc66: 0x0040, 0xc67: 0x0040, 0xc68: 0x0040, 0xc69: 0x0040,
0xc6a: 0x0340, 0xc6b: 0x0340, 0xc6c: 0x0340, 0xc6d: 0x0340, 0xc6e: 0x0340, 0xc6f: 0x0340,
0xc70: 0x06e1, 0xc71: 0x0311, 0xc72: 0x0040, 0xc73: 0x0040, 0xc74: 0x06e9, 0xc75: 0x06f1,
0xc76: 0x06f9, 0xc77: 0x0701, 0xc78: 0x0709, 0xc79: 0x0711, 0xc7a: 0x071a, 0xc7b: 0x07d5,
0xc7c: 0x0722, 0xc7d: 0x072a, 0xc7e: 0x0732, 0xc7f: 0x0329,
// Block 0x32, offset 0xc80
0xc80: 0x06e1, 0xc81: 0x0049, 0xc82: 0x0029, 0xc83: 0x0031, 0xc84: 0x06e9, 0xc85: 0x06f1,
0xc86: 0x06f9, 0xc87: 0x0701, 0xc88: 0x0709, 0xc89: 0x0711, 0xc8a: 0x071a, 0xc8b: 0x07ed,
0xc8c: 0x0722, 0xc8d: 0x072a, 0xc8e: 0x0732, 0xc8f: 0x0040, 0xc90: 0x0019, 0xc91: 0x02f9,
0xc92: 0x0051, 0xc93: 0x0109, 0xc94: 0x0361, 0xc95: 0x00a9, 0xc96: 0x0319, 0xc97: 0x0101,
0xc98: 0x0321, 0xc99: 0x0329, 0xc9a: 0x0339, 0xc9b: 0x0089, 0xc9c: 0x0341, 0xc9d: 0x0040,
0xc9e: 0x0040, 0xc9f: 0x0040, 0xca0: 0x0018, 0xca1: 0x0018, 0xca2: 0x0018, 0xca3: 0x0018,
0xca4: 0x0018, 0xca5: 0x0018, 0xca6: 0x0018, 0xca7: 0x0018, 0xca8: 0x0739, 0xca9: 0x0018,
0xcaa: 0x0018, 0xcab: 0x0018, 0xcac: 0x0018, 0xcad: 0x0018, 0xcae: 0x0018, 0xcaf: 0x0018,
0xcb0: 0x0018, 0xcb1: 0x0018, 0xcb2: 0x0018, 0xcb3: 0x0018, 0xcb4: 0x0018, 0xcb5: 0x0018,
0xcb6: 0x0018, 0xcb7: 0x0018, 0xcb8: 0x0018, 0xcb9: 0x0018, 0xcba: 0x0018, 0xcbb: 0x0018,
0xcbc: 0x0018, 0xcbd: 0x0018, 0xcbe: 0x0018, 0xcbf: 0x0018,
// Block 0x33, offset 0xcc0
0xcc0: 0x0806, 0xcc1: 0x0826, 0xcc2: 0x03d9, 0xcc3: 0x0845, 0xcc4: 0x0018, 0xcc5: 0x0866,
0xcc6: 0x0886, 0xcc7: 0x0369, 0xcc8: 0x0018, 0xcc9: 0x08a5, 0xcca: 0x0309, 0xccb: 0x00a9,
0xccc: 0x00a9, 0xccd: 0x00a9, 0xcce: 0x00a9, 0xccf: 0x0741, 0xcd0: 0x0311, 0xcd1: 0x0311,
0xcd2: 0x0101, 0xcd3: 0x0101, 0xcd4: 0x0018, 0xcd5: 0x0329, 0xcd6: 0x0749, 0xcd7: 0x0018,
0xcd8: 0x0018, 0xcd9: 0x0339, 0xcda: 0x0751, 0xcdb: 0x00b9, 0xcdc: 0x00b9, 0xcdd: 0x00b9,
0xcde: 0x0018, 0xcdf: 0x0018, 0xce0: 0x0759, 0xce1: 0x08c5, 0xce2: 0x0761, 0xce3: 0x0018,
0xce4: 0x04b1, 0xce5: 0x0018, 0xce6: 0x0769, 0xce7: 0x0018, 0xce8: 0x04b1, 0xce9: 0x0018,
0xcea: 0x0319, 0xceb: 0x0771, 0xcec: 0x02e9, 0xced: 0x03d9, 0xcee: 0x0018, 0xcef: 0x02f9,
0xcf0: 0x02f9, 0xcf1: 0x03f1, 0xcf2: 0x0040, 0xcf3: 0x0321, 0xcf4: 0x0051, 0xcf5: 0x0779,
0xcf6: 0x0781, 0xcf7: 0x0789, 0xcf8: 0x0791, 0xcf9: 0x0311, 0xcfa: 0x0018, 0xcfb: 0x08e5,
0xcfc: 0x0799, 0xcfd: 0x03a1, 0xcfe: 0x03a1, 0xcff: 0x0799,
// Block 0x34, offset 0xd00
0xd00: 0x0905, 0xd01: 0x0018, 0xd02: 0x0018, 0xd03: 0x0018, 0xd04: 0x0018, 0xd05: 0x02f1,
0xd06: 0x02f1, 0xd07: 0x02f9, 0xd08: 0x0311, 0xd09: 0x00b1, 0xd0a: 0x0018, 0xd0b: 0x0018,
0xd0c: 0x0018, 0xd0d: 0x0018, 0xd0e: 0x0008, 0xd0f: 0x0018, 0xd10: 0x07a1, 0xd11: 0x07a9,
0xd12: 0x07b1, 0xd13: 0x07b9, 0xd14: 0x07c1, 0xd15: 0x07c9, 0xd16: 0x07d1, 0xd17: 0x07d9,
0xd18: 0x07e1, 0xd19: 0x07e9, 0xd1a: 0x07f1, 0xd1b: 0x07f9, 0xd1c: 0x0801, 0xd1d: 0x0809,
0xd1e: 0x0811, 0xd1f: 0x0819, 0xd20: 0x0311, 0xd21: 0x0821, 0xd22: 0x091d, 0xd23: 0x0829,
0xd24: 0x0391, 0xd25: 0x0831, 0xd26: 0x093d, 0xd27: 0x0839, 0xd28: 0x0841, 0xd29: 0x0109,
0xd2a: 0x0849, 0xd2b: 0x095d, 0xd2c: 0x0101, 0xd2d: 0x03d9, 0xd2e: 0x02f1, 0xd2f: 0x0321,
0xd30: 0x0311, 0xd31: 0x0821, 0xd32: 0x097d, 0xd33: 0x0829, 0xd34: 0x0391, 0xd35: 0x0831,
0xd36: 0x099d, 0xd37: 0x0839, 0xd38: 0x0841, 0xd39: 0x0109, 0xd3a: 0x0849, 0xd3b: 0x09bd,
0xd3c: 0x0101, 0xd3d: 0x03d9, 0xd3e: 0x02f1, 0xd3f: 0x0321,
// Block 0x35, offset 0xd40
0xd40: 0x0018, 0xd41: 0x0018, 0xd42: 0x0018, 0xd43: 0x0018, 0xd44: 0x0018, 0xd45: 0x0018,
0xd46: 0x0018, 0xd47: 0x0018, 0xd48: 0x0018, 0xd49: 0x0018, 0xd4a: 0x0018, 0xd4b: 0x0040,
0xd4c: 0x0040, 0xd4d: 0x0040, 0xd4e: 0x0040, 0xd4f: 0x0040, 0xd50: 0x0040, 0xd51: 0x0040,
0xd52: 0x0040, 0xd53: 0x0040, 0xd54: 0x0040, 0xd55: 0x0040, 0xd56: 0x0040, 0xd57: 0x0040,
0xd58: 0x0040, 0xd59: 0x0040, 0xd5a: 0x0040, 0xd5b: 0x0040, 0xd5c: 0x0040, 0xd5d: 0x0040,
0xd5e: 0x0040, 0xd5f: 0x0040, 0xd60: 0x0049, 0xd61: 0x0029, 0xd62: 0x0031, 0xd63: 0x06e9,
0xd64: 0x06f1, 0xd65: 0x06f9, 0xd66: 0x0701, 0xd67: 0x0709, 0xd68: 0x0711, 0xd69: 0x0879,
0xd6a: 0x0881, 0xd6b: 0x0889, 0xd6c: 0x0891, 0xd6d: 0x0899, 0xd6e: 0x08a1, 0xd6f: 0x08a9,
0xd70: 0x08b1, 0xd71: 0x08b9, 0xd72: 0x08c1, 0xd73: 0x08c9, 0xd74: 0x0a1e, 0xd75: 0x0a3e,
0xd76: 0x0a5e, 0xd77: 0x0a7e, 0xd78: 0x0a9e, 0xd79: 0x0abe, 0xd7a: 0x0ade, 0xd7b: 0x0afe,
0xd7c: 0x0b1e, 0xd7d: 0x08d2, 0xd7e: 0x08da, 0xd7f: 0x08e2,
// Block 0x36, offset 0xd80
0xd80: 0x08ea, 0xd81: 0x08f2, 0xd82: 0x08fa, 0xd83: 0x0902, 0xd84: 0x090a, 0xd85: 0x0912,
0xd86: 0x091a, 0xd87: 0x0922, 0xd88: 0x0040, 0xd89: 0x0040, 0xd8a: 0x0040, 0xd8b: 0x0040,
0xd8c: 0x0040, 0xd8d: 0x0040, 0xd8e: 0x0040, 0xd8f: 0x0040, 0xd90: 0x0040, 0xd91: 0x0040,
0xd92: 0x0040, 0xd93: 0x0040, 0xd94: 0x0040, 0xd95: 0x0040, 0xd96: 0x0040, 0xd97: 0x0040,
0xd98: 0x0040, 0xd99: 0x0040, 0xd9a: 0x0040, 0xd9b: 0x0040, 0xd9c: 0x0b3e, 0xd9d: 0x0b5e,
0xd9e: 0x0b7e, 0xd9f: 0x0b9e, 0xda0: 0x0bbe, 0xda1: 0x0bde, 0xda2: 0x0bfe, 0xda3: 0x0c1e,
0xda4: 0x0c3e, 0xda5: 0x0c5e, 0xda6: 0x0c7e, 0xda7: 0x0c9e, 0xda8: 0x0cbe, 0xda9: 0x0cde,
0xdaa: 0x0cfe, 0xdab: 0x0d1e, 0xdac: 0x0d3e, 0xdad: 0x0d5e, 0xdae: 0x0d7e, 0xdaf: 0x0d9e,
0xdb0: 0x0dbe, 0xdb1: 0x0dde, 0xdb2: 0x0dfe, 0xdb3: 0x0e1e, 0xdb4: 0x0e3e, 0xdb5: 0x0e5e,
0xdb6: 0x0019, 0xdb7: 0x02e9, 0xdb8: 0x03d9, 0xdb9: 0x02f1, 0xdba: 0x02f9, 0xdbb: 0x03f1,
0xdbc: 0x0309, 0xdbd: 0x00a9, 0xdbe: 0x0311, 0xdbf: 0x00b1,
// Block 0x37, offset 0xdc0
0xdc0: 0x0319, 0xdc1: 0x0101, 0xdc2: 0x0321, 0xdc3: 0x0329, 0xdc4: 0x0051, 0xdc5: 0x0339,
0xdc6: 0x0751, 0xdc7: 0x00b9, 0xdc8: 0x0089, 0xdc9: 0x0341, 0xdca: 0x0349, 0xdcb: 0x0391,
0xdcc: 0x00c1, 0xdcd: 0x0109, 0xdce: 0x00c9, 0xdcf: 0x04b1, 0xdd0: 0x0019, 0xdd1: 0x02e9,
0xdd2: 0x03d9, 0xdd3: 0x02f1, 0xdd4: 0x02f9, 0xdd5: 0x03f1, 0xdd6: 0x0309, 0xdd7: 0x00a9,
0xdd8: 0x0311, 0xdd9: 0x00b1, 0xdda: 0x0319, 0xddb: 0x0101, 0xddc: 0x0321, 0xddd: 0x0329,
0xdde: 0x0051, 0xddf: 0x0339, 0xde0: 0x0751, 0xde1: 0x00b9, 0xde2: 0x0089, 0xde3: 0x0341,
0xde4: 0x0349, 0xde5: 0x0391, 0xde6: 0x00c1, 0xde7: 0x0109, 0xde8: 0x00c9, 0xde9: 0x04b1,
0xdea: 0x06e1, 0xdeb: 0x0018, 0xdec: 0x0018, 0xded: 0x0018, 0xdee: 0x0018, 0xdef: 0x0018,
0xdf0: 0x0018, 0xdf1: 0x0018, 0xdf2: 0x0018, 0xdf3: 0x0018, 0xdf4: 0x0018, 0xdf5: 0x0018,
0xdf6: 0x0018, 0xdf7: 0x0018, 0xdf8: 0x0018, 0xdf9: 0x0018, 0xdfa: 0x0018, 0xdfb: 0x0018,
0xdfc: 0x0018, 0xdfd: 0x0018, 0xdfe: 0x0018, 0xdff: 0x0018,
// Block 0x38, offset 0xe00
0xe00: 0x0008, 0xe01: 0x0008, 0xe02: 0x0008, 0xe03: 0x0008, 0xe04: 0x0008, 0xe05: 0x0008,
0xe06: 0x0008, 0xe07: 0x0008, 0xe08: 0x0008, 0xe09: 0x0008, 0xe0a: 0x0008, 0xe0b: 0x0008,
0xe0c: 0x0008, 0xe0d: 0x0008, 0xe0e: 0x0008, 0xe0f: 0x0008, 0xe10: 0x0008, 0xe11: 0x0008,
0xe12: 0x0008, 0xe13: 0x0008, 0xe14: 0x0008, 0xe15: 0x0008, 0xe16: 0x0008, 0xe17: 0x0008,
0xe18: 0x0008, 0xe19: 0x0008, 0xe1a: 0x0008, 0xe1b: 0x0008, 0xe1c: 0x0008, 0xe1d: 0x0008,
0xe1e: 0x0008, 0xe1f: 0x0008, 0xe20: 0xe00d, 0xe21: 0x0008, 0xe22: 0x0941, 0xe23: 0x0ed5,
0xe24: 0x0949, 0xe25: 0x0008, 0xe26: 0x0008, 0xe27: 0xe07d, 0xe28: 0x0008, 0xe29: 0xe01d,
0xe2a: 0x0008, 0xe2b: 0xe03d, 0xe2c: 0x0008, 0xe2d: 0x0359, 0xe2e: 0x0441, 0xe2f: 0x0351,
0xe30: 0x03d1, 0xe31: 0x0008, 0xe32: 0xe00d, 0xe33: 0x0008, 0xe34: 0x0008, 0xe35: 0xe01d,
0xe36: 0x0008, 0xe37: 0x0008, 0xe38: 0x0008, 0xe39: 0x0008, 0xe3a: 0x0008, 0xe3b: 0x0008,
0xe3c: 0x00b1, 0xe3d: 0x0391, 0xe3e: 0x0951, 0xe3f: 0x0959,
// Block 0x39, offset 0xe40
0xe40: 0xe00d, 0xe41: 0x0008, 0xe42: 0xe00d, 0xe43: 0x0008, 0xe44: 0xe00d, 0xe45: 0x0008,
0xe46: 0xe00d, 0xe47: 0x0008, 0xe48: 0xe00d, 0xe49: 0x0008, 0xe4a: 0xe00d, 0xe4b: 0x0008,
0xe4c: 0xe00d, 0xe4d: 0x0008, 0xe4e: 0xe00d, 0xe4f: 0x0008, 0xe50: 0xe00d, 0xe51: 0x0008,
0xe52: 0xe00d, 0xe53: 0x0008, 0xe54: 0xe00d, 0xe55: 0x0008, 0xe56: 0xe00d, 0xe57: 0x0008,
0xe58: 0xe00d, 0xe59: 0x0008, 0xe5a: 0xe00d, 0xe5b: 0x0008, 0xe5c: 0xe00d, 0xe5d: 0x0008,
0xe5e: 0xe00d, 0xe5f: 0x0008, 0xe60: 0xe00d, 0xe61: 0x0008, 0xe62: 0xe00d, 0xe63: 0x0008,
0xe64: 0x0008, 0xe65: 0x0018, 0xe66: 0x0018, 0xe67: 0x0018, 0xe68: 0x0018, 0xe69: 0x0018,
0xe6a: 0x0018, 0xe6b: 0xe03d, 0xe6c: 0x0008, 0xe6d: 0xe01d, 0xe6e: 0x0008, 0xe6f: 0x3308,
0xe70: 0x3308, 0xe71: 0x3308, 0xe72: 0xe00d, 0xe73: 0x0008, 0xe74: 0x0040, 0xe75: 0x0040,
0xe76: 0x0040, 0xe77: 0x0040, 0xe78: 0x0040, 0xe79: 0x0018, 0xe7a: 0x0018, 0xe7b: 0x0018,
0xe7c: 0x0018, 0xe7d: 0x0018, 0xe7e: 0x0018, 0xe7f: 0x0018,
// Block 0x3a, offset 0xe80
0xe80: 0x2715, 0xe81: 0x2735, 0xe82: 0x2755, 0xe83: 0x2775, 0xe84: 0x2795, 0xe85: 0x27b5,
0xe86: 0x27d5, 0xe87: 0x27f5, 0xe88: 0x2815, 0xe89: 0x2835, 0xe8a: 0x2855, 0xe8b: 0x2875,
0xe8c: 0x2895, 0xe8d: 0x28b5, 0xe8e: 0x28d5, 0xe8f: 0x28f5, 0xe90: 0x2915, 0xe91: 0x2935,
0xe92: 0x2955, 0xe93: 0x2975, 0xe94: 0x2995, 0xe95: 0x29b5, 0xe96: 0x0040, 0xe97: 0x0040,
0xe98: 0x0040, 0xe99: 0x0040, 0xe9a: 0x0040, 0xe9b: 0x0040, 0xe9c: 0x0040, 0xe9d: 0x0040,
0xe9e: 0x0040, 0xe9f: 0x0040, 0xea0: 0x0040, 0xea1: 0x0040, 0xea2: 0x0040, 0xea3: 0x0040,
0xea4: 0x0040, 0xea5: 0x0040, 0xea6: 0x0040, 0xea7: 0x0040, 0xea8: 0x0040, 0xea9: 0x0040,
0xeaa: 0x0040, 0xeab: 0x0040, 0xeac: 0x0040, 0xead: 0x0040, 0xeae: 0x0040, 0xeaf: 0x0040,
0xeb0: 0x0040, 0xeb1: 0x0040, 0xeb2: 0x0040, 0xeb3: 0x0040, 0xeb4: 0x0040, 0xeb5: 0x0040,
0xeb6: 0x0040, 0xeb7: 0x0040, 0xeb8: 0x0040, 0xeb9: 0x0040, 0xeba: 0x0040, 0xebb: 0x0040,
0xebc: 0x0040, 0xebd: 0x0040, 0xebe: 0x0040, 0xebf: 0x0040,
// Block 0x3b, offset 0xec0
0xec0: 0x000a, 0xec1: 0x0018, 0xec2: 0x0961, 0xec3: 0x0018, 0xec4: 0x0018, 0xec5: 0x0008,
0xec6: 0x0008, 0xec7: 0x0008, 0xec8: 0x0018, 0xec9: 0x0018, 0xeca: 0x0018, 0xecb: 0x0018,
0xecc: 0x0018, 0xecd: 0x0018, 0xece: 0x0018, 0xecf: 0x0018, 0xed0: 0x0018, 0xed1: 0x0018,
0xed2: 0x0018, 0xed3: 0x0018, 0xed4: 0x0018, 0xed5: 0x0018, 0xed6: 0x0018, 0xed7: 0x0018,
0xed8: 0x0018, 0xed9: 0x0018, 0xeda: 0x0018, 0xedb: 0x0018, 0xedc: 0x0018, 0xedd: 0x0018,
0xede: 0x0018, 0xedf: 0x0018, 0xee0: 0x0018, 0xee1: 0x0018, 0xee2: 0x0018, 0xee3: 0x0018,
0xee4: 0x0018, 0xee5: 0x0018, 0xee6: 0x0018, 0xee7: 0x0018, 0xee8: 0x0018, 0xee9: 0x0018,
0xeea: 0x3308, 0xeeb: 0x3308, 0xeec: 0x3308, 0xeed: 0x3308, 0xeee: 0x3018, 0xeef: 0x3018,
0xef0: 0x0018, 0xef1: 0x0018, 0xef2: 0x0018, 0xef3: 0x0018, 0xef4: 0x0018, 0xef5: 0x0018,
0xef6: 0xe125, 0xef7: 0x0018, 0xef8: 0x29d5, 0xef9: 0x29f5, 0xefa: 0x2a15, 0xefb: 0x0018,
0xefc: 0x0008, 0xefd: 0x0018, 0xefe: 0x0018, 0xeff: 0x0018,
// Block 0x3c, offset 0xf00
0xf00: 0x2b55, 0xf01: 0x2b75, 0xf02: 0x2b95, 0xf03: 0x2bb5, 0xf04: 0x2bd5, 0xf05: 0x2bf5,
0xf06: 0x2bf5, 0xf07: 0x2bf5, 0xf08: 0x2c15, 0xf09: 0x2c15, 0xf0a: 0x2c15, 0xf0b: 0x2c15,
0xf0c: 0x2c35, 0xf0d: 0x2c35, 0xf0e: 0x2c35, 0xf0f: 0x2c55, 0xf10: 0x2c75, 0xf11: 0x2c75,
0xf12: 0x2a95, 0xf13: 0x2a95, 0xf14: 0x2c75, 0xf15: 0x2c75, 0xf16: 0x2c95, 0xf17: 0x2c95,
0xf18: 0x2c75, 0xf19: 0x2c75, 0xf1a: 0x2a95, 0xf1b: 0x2a95, 0xf1c: 0x2c75, 0xf1d: 0x2c75,
0xf1e: 0x2c55, 0xf1f: 0x2c55, 0xf20: 0x2cb5, 0xf21: 0x2cb5, 0xf22: 0x2cd5, 0xf23: 0x2cd5,
0xf24: 0x0040, 0xf25: 0x2cf5, 0xf26: 0x2d15, 0xf27: 0x2d35, 0xf28: 0x2d35, 0xf29: 0x2d55,
0xf2a: 0x2d75, 0xf2b: 0x2d95, 0xf2c: 0x2db5, 0xf2d: 0x2dd5, 0xf2e: 0x2df5, 0xf2f: 0x2e15,
0xf30: 0x2e35, 0xf31: 0x2e55, 0xf32: 0x2e55, 0xf33: 0x2e75, 0xf34: 0x2e95, 0xf35: 0x2e95,
0xf36: 0x2eb5, 0xf37: 0x2ed5, 0xf38: 0x2e75, 0xf39: 0x2ef5, 0xf3a: 0x2f15, 0xf3b: 0x2ef5,
0xf3c: 0x2e75, 0xf3d: 0x2f35, 0xf3e: 0x2f55, 0xf3f: 0x2f75,
// Block 0x3d, offset 0xf40
0xf40: 0x2f95, 0xf41: 0x2fb5, 0xf42: 0x2d15, 0xf43: 0x2cf5, 0xf44: 0x2fd5, 0xf45: 0x2ff5,
0xf46: 0x3015, 0xf47: 0x3035, 0xf48: 0x3055, 0xf49: 0x3075, 0xf4a: 0x3095, 0xf4b: 0x30b5,
0xf4c: 0x30d5, 0xf4d: 0x30f5, 0xf4e: 0x3115, 0xf4f: 0x0040, 0xf50: 0x0018, 0xf51: 0x0018,
0xf52: 0x3135, 0xf53: 0x3155, 0xf54: 0x3175, 0xf55: 0x3195, 0xf56: 0x31b5, 0xf57: 0x31d5,
0xf58: 0x31f5, 0xf59: 0x3215, 0xf5a: 0x3235, 0xf5b: 0x3255, 0xf5c: 0x3175, 0xf5d: 0x3275,
0xf5e: 0x3295, 0xf5f: 0x32b5, 0xf60: 0x0008, 0xf61: 0x0008, 0xf62: 0x0008, 0xf63: 0x0008,
0xf64: 0x0008, 0xf65: 0x0008, 0xf66: 0x0008, 0xf67: 0x0008, 0xf68: 0x0008, 0xf69: 0x0008,
0xf6a: 0x0008, 0xf6b: 0x0008, 0xf6c: 0x0008, 0xf6d: 0x0008, 0xf6e: 0x0008, 0xf6f: 0x0008,
0xf70: 0x0008, 0xf71: 0x0008, 0xf72: 0x0008, 0xf73: 0x0008, 0xf74: 0x0008, 0xf75: 0x0008,
0xf76: 0x0008, 0xf77: 0x0008, 0xf78: 0x0008, 0xf79: 0x0008, 0xf7a: 0x0008, 0xf7b: 0x0008,
0xf7c: 0x0008, 0xf7d: 0x0008, 0xf7e: 0x0008, 0xf7f: 0x0008,
// Block 0x3e, offset 0xf80
0xf80: 0x0b82, 0xf81: 0x0b8a, 0xf82: 0x0b92, 0xf83: 0x0b9a, 0xf84: 0x32d5, 0xf85: 0x32f5,
0xf86: 0x3315, 0xf87: 0x3335, 0xf88: 0x0018, 0xf89: 0x0018, 0xf8a: 0x0018, 0xf8b: 0x0018,
0xf8c: 0x0018, 0xf8d: 0x0018, 0xf8e: 0x0018, 0xf8f: 0x0018, 0xf90: 0x3355, 0xf91: 0x0ba1,
0xf92: 0x0ba9, 0xf93: 0x0bb1, 0xf94: 0x0bb9, 0xf95: 0x0bc1, 0xf96: 0x0bc9, 0xf97: 0x0bd1,
0xf98: 0x0bd9, 0xf99: 0x0be1, 0xf9a: 0x0be9, 0xf9b: 0x0bf1, 0xf9c: 0x0bf9, 0xf9d: 0x0c01,
0xf9e: 0x0c09, 0xf9f: 0x0c11, 0xfa0: 0x3375, 0xfa1: 0x3395, 0xfa2: 0x33b5, 0xfa3: 0x33d5,
0xfa4: 0x33f5, 0xfa5: 0x33f5, 0xfa6: 0x3415, 0xfa7: 0x3435, 0xfa8: 0x3455, 0xfa9: 0x3475,
0xfaa: 0x3495, 0xfab: 0x34b5, 0xfac: 0x34d5, 0xfad: 0x34f5, 0xfae: 0x3515, 0xfaf: 0x3535,
0xfb0: 0x3555, 0xfb1: 0x3575, 0xfb2: 0x3595, 0xfb3: 0x35b5, 0xfb4: 0x35d5, 0xfb5: 0x35f5,
0xfb6: 0x3615, 0xfb7: 0x3635, 0xfb8: 0x3655, 0xfb9: 0x3675, 0xfba: 0x3695, 0xfbb: 0x36b5,
0xfbc: 0x0c19, 0xfbd: 0x0c21, 0xfbe: 0x36d5, 0xfbf: 0x0018,
// Block 0x3f, offset 0xfc0
0xfc0: 0x36f5, 0xfc1: 0x3715, 0xfc2: 0x3735, 0xfc3: 0x3755, 0xfc4: 0x3775, 0xfc5: 0x3795,
0xfc6: 0x37b5, 0xfc7: 0x37d5, 0xfc8: 0x37f5, 0xfc9: 0x3815, 0xfca: 0x3835, 0xfcb: 0x3855,
0xfcc: 0x3875, 0xfcd: 0x3895, 0xfce: 0x38b5, 0xfcf: 0x38d5, 0xfd0: 0x38f5, 0xfd1: 0x3915,
0xfd2: 0x3935, 0xfd3: 0x3955, 0xfd4: 0x3975, 0xfd5: 0x3995, 0xfd6: 0x39b5, 0xfd7: 0x39d5,
0xfd8: 0x39f5, 0xfd9: 0x3a15, 0xfda: 0x3a35, 0xfdb: 0x3a55, 0xfdc: 0x3a75, 0xfdd: 0x3a95,
0xfde: 0x3ab5, 0xfdf: 0x3ad5, 0xfe0: 0x3af5, 0xfe1: 0x3b15, 0xfe2: 0x3b35, 0xfe3: 0x3b55,
0xfe4: 0x3b75, 0xfe5: 0x3b95, 0xfe6: 0x1295, 0xfe7: 0x3bb5, 0xfe8: 0x3bd5, 0xfe9: 0x3bf5,
0xfea: 0x3c15, 0xfeb: 0x3c35, 0xfec: 0x3c55, 0xfed: 0x3c75, 0xfee: 0x23b5, 0xfef: 0x3c95,
0xff0: 0x3cb5, 0xff1: 0x0c29, 0xff2: 0x0c31, 0xff3: 0x0c39, 0xff4: 0x0c41, 0xff5: 0x0c49,
0xff6: 0x0c51, 0xff7: 0x0c59, 0xff8: 0x0c61, 0xff9: 0x0c69, 0xffa: 0x0c71, 0xffb: 0x0c79,
0xffc: 0x0c81, 0xffd: 0x0c89, 0xffe: 0x0c91, 0xfff: 0x0c99,
// Block 0x40, offset 0x1000
0x1000: 0x0ca1, 0x1001: 0x0ca9, 0x1002: 0x0cb1, 0x1003: 0x0cb9, 0x1004: 0x0cc1, 0x1005: 0x0cc9,
0x1006: 0x0cd1, 0x1007: 0x0cd9, 0x1008: 0x0ce1, 0x1009: 0x0ce9, 0x100a: 0x0cf1, 0x100b: 0x0cf9,
0x100c: 0x0d01, 0x100d: 0x3cd5, 0x100e: 0x0d09, 0x100f: 0x3cf5, 0x1010: 0x3d15, 0x1011: 0x3d2d,
0x1012: 0x3d45, 0x1013: 0x3d5d, 0x1014: 0x3d75, 0x1015: 0x3d75, 0x1016: 0x3d5d, 0x1017: 0x3d8d,
0x1018: 0x07d5, 0x1019: 0x3da5, 0x101a: 0x3dbd, 0x101b: 0x3dd5, 0x101c: 0x3ded, 0x101d: 0x3e05,
0x101e: 0x3e1d, 0x101f: 0x3e35, 0x1020: 0x3e4d, 0x1021: 0x3e65, 0x1022: 0x3e7d, 0x1023: 0x3e95,
0x1024: 0x3ead, 0x1025: 0x3ead, 0x1026: 0x3ec5, 0x1027: 0x3ec5, 0x1028: 0x3edd, 0x1029: 0x3edd,
0x102a: 0x3ef5, 0x102b: 0x3f0d, 0x102c: 0x3f25, 0x102d: 0x3f3d, 0x102e: 0x3f55, 0x102f: 0x3f55,
0x1030: 0x3f6d, 0x1031: 0x3f6d, 0x1032: 0x3f6d, 0x1033: 0x3f85, 0x1034: 0x3f9d, 0x1035: 0x3fb5,
0x1036: 0x3fcd, 0x1037: 0x3fb5, 0x1038: 0x3fe5, 0x1039: 0x3ffd, 0x103a: 0x3f85, 0x103b: 0x4015,
0x103c: 0x402d, 0x103d: 0x402d, 0x103e: 0x402d, 0x103f: 0x0d11,
// Block 0x41, offset 0x1040
0x1040: 0x10f9, 0x1041: 0x1101, 0x1042: 0x40a5, 0x1043: 0x1109, 0x1044: 0x1111, 0x1045: 0x1119,
0x1046: 0x1121, 0x1047: 0x1129, 0x1048: 0x40c5, 0x1049: 0x1131, 0x104a: 0x1139, 0x104b: 0x1141,
0x104c: 0x40e5, 0x104d: 0x40e5, 0x104e: 0x1149, 0x104f: 0x1151, 0x1050: 0x1159, 0x1051: 0x4105,
0x1052: 0x4125, 0x1053: 0x4145, 0x1054: 0x4165, 0x1055: 0x4185, 0x1056: 0x1161, 0x1057: 0x1169,
0x1058: 0x1171, 0x1059: 0x1179, 0x105a: 0x1181, 0x105b: 0x41a5, 0x105c: 0x1189, 0x105d: 0x1191,
0x105e: 0x1199, 0x105f: 0x41c5, 0x1060: 0x41e5, 0x1061: 0x11a1, 0x1062: 0x4205, 0x1063: 0x4225,
0x1064: 0x4245, 0x1065: 0x11a9, 0x1066: 0x4265, 0x1067: 0x11b1, 0x1068: 0x11b9, 0x1069: 0x10f9,
0x106a: 0x4285, 0x106b: 0x42a5, 0x106c: 0x42c5, 0x106d: 0x42e5, 0x106e: 0x11c1, 0x106f: 0x11c9,
0x1070: 0x11d1, 0x1071: 0x11d9, 0x1072: 0x4305, 0x1073: 0x11e1, 0x1074: 0x11e9, 0x1075: 0x11f1,
0x1076: 0x4325, 0x1077: 0x11f9, 0x1078: 0x1201, 0x1079: 0x11f9, 0x107a: 0x1209, 0x107b: 0x1211,
0x107c: 0x4345, 0x107d: 0x1219, 0x107e: 0x1221, 0x107f: 0x1219,
// Block 0x42, offset 0x1080
0x1080: 0x4365, 0x1081: 0x4385, 0x1082: 0x0040, 0x1083: 0x1229, 0x1084: 0x1231, 0x1085: 0x1239,
0x1086: 0x1241, 0x1087: 0x0040, 0x1088: 0x1249, 0x1089: 0x1251, 0x108a: 0x1259, 0x108b: 0x1261,
0x108c: 0x1269, 0x108d: 0x1271, 0x108e: 0x1199, 0x108f: 0x1279, 0x1090: 0x1281, 0x1091: 0x1289,
0x1092: 0x43a5, 0x1093: 0x1291, 0x1094: 0x1121, 0x1095: 0x43c5, 0x1096: 0x43e5, 0x1097: 0x1299,
0x1098: 0x0040, 0x1099: 0x4405, 0x109a: 0x12a1, 0x109b: 0x12a9, 0x109c: 0x12b1, 0x109d: 0x12b9,
0x109e: 0x12c1, 0x109f: 0x12c9, 0x10a0: 0x12d1, 0x10a1: 0x12d9, 0x10a2: 0x12e1, 0x10a3: 0x12e9,
0x10a4: 0x12f1, 0x10a5: 0x12f9, 0x10a6: 0x1301, 0x10a7: 0x1309, 0x10a8: 0x1311, 0x10a9: 0x1319,
0x10aa: 0x1321, 0x10ab: 0x1329, 0x10ac: 0x1331, 0x10ad: 0x1339, 0x10ae: 0x1341, 0x10af: 0x1349,
0x10b0: 0x1351, 0x10b1: 0x1359, 0x10b2: 0x1361, 0x10b3: 0x1369, 0x10b4: 0x1371, 0x10b5: 0x1379,
0x10b6: 0x1381, 0x10b7: 0x1389, 0x10b8: 0x1391, 0x10b9: 0x1399, 0x10ba: 0x13a1, 0x10bb: 0x13a9,
0x10bc: 0x13b1, 0x10bd: 0x13b9, 0x10be: 0x13c1, 0x10bf: 0x4425,
// Block 0x43, offset 0x10c0
0x10c0: 0xe00d, 0x10c1: 0x0008, 0x10c2: 0xe00d, 0x10c3: 0x0008, 0x10c4: 0xe00d, 0x10c5: 0x0008,
0x10c6: 0xe00d, 0x10c7: 0x0008, 0x10c8: 0xe00d, 0x10c9: 0x0008, 0x10ca: 0xe00d, 0x10cb: 0x0008,
0x10cc: 0xe00d, 0x10cd: 0x0008, 0x10ce: 0xe00d, 0x10cf: 0x0008, 0x10d0: 0xe00d, 0x10d1: 0x0008,
0x10d2: 0xe00d, 0x10d3: 0x0008, 0x10d4: 0xe00d, 0x10d5: 0x0008, 0x10d6: 0xe00d, 0x10d7: 0x0008,
0x10d8: 0xe00d, 0x10d9: 0x0008, 0x10da: 0xe00d, 0x10db: 0x0008, 0x10dc: 0xe00d, 0x10dd: 0x0008,
0x10de: 0xe00d, 0x10df: 0x0008, 0x10e0: 0xe00d, 0x10e1: 0x0008, 0x10e2: 0xe00d, 0x10e3: 0x0008,
0x10e4: 0xe00d, 0x10e5: 0x0008, 0x10e6: 0xe00d, 0x10e7: 0x0008, 0x10e8: 0xe00d, 0x10e9: 0x0008,
0x10ea: 0xe00d, 0x10eb: 0x0008, 0x10ec: 0xe00d, 0x10ed: 0x0008, 0x10ee: 0x0008, 0x10ef: 0x3308,
0x10f0: 0x3318, 0x10f1: 0x3318, 0x10f2: 0x3318, 0x10f3: 0x0018, 0x10f4: 0x3308, 0x10f5: 0x3308,
0x10f6: 0x3308, 0x10f7: 0x3308, 0x10f8: 0x3308, 0x10f9: 0x3308, 0x10fa: 0x3308, 0x10fb: 0x3308,
0x10fc: 0x3308, 0x10fd: 0x3308, 0x10fe: 0x0018, 0x10ff: 0x0008,
// Block 0x44, offset 0x1100
0x1100: 0xe00d, 0x1101: 0x0008, 0x1102: 0xe00d, 0x1103: 0x0008, 0x1104: 0xe00d, 0x1105: 0x0008,
0x1106: 0xe00d, 0x1107: 0x0008, 0x1108: 0xe00d, 0x1109: 0x0008, 0x110a: 0xe00d, 0x110b: 0x0008,
0x110c: 0xe00d, 0x110d: 0x0008, 0x110e: 0xe00d, 0x110f: 0x0008, 0x1110: 0xe00d, 0x1111: 0x0008,
0x1112: 0xe00d, 0x1113: 0x0008, 0x1114: 0xe00d, 0x1115: 0x0008, 0x1116: 0xe00d, 0x1117: 0x0008,
0x1118: 0xe00d, 0x1119: 0x0008, 0x111a: 0xe00d, 0x111b: 0x0008, 0x111c: 0x02d1, 0x111d: 0x13c9,
0x111e: 0x3308, 0x111f: 0x3308, 0x1120: 0x0008, 0x1121: 0x0008, 0x1122: 0x0008, 0x1123: 0x0008,
0x1124: 0x0008, 0x1125: 0x0008, 0x1126: 0x0008, 0x1127: 0x0008, 0x1128: 0x0008, 0x1129: 0x0008,
0x112a: 0x0008, 0x112b: 0x0008, 0x112c: 0x0008, 0x112d: 0x0008, 0x112e: 0x0008, 0x112f: 0x0008,
0x1130: 0x0008, 0x1131: 0x0008, 0x1132: 0x0008, 0x1133: 0x0008, 0x1134: 0x0008, 0x1135: 0x0008,
0x1136: 0x0008, 0x1137: 0x0008, 0x1138: 0x0008, 0x1139: 0x0008, 0x113a: 0x0008, 0x113b: 0x0008,
0x113c: 0x0008, 0x113d: 0x0008, 0x113e: 0x0008, 0x113f: 0x0008,
// Block 0x45, offset 0x1140
0x1140: 0x0018, 0x1141: 0x0018, 0x1142: 0x0018, 0x1143: 0x0018, 0x1144: 0x0018, 0x1145: 0x0018,
0x1146: 0x0018, 0x1147: 0x0018, 0x1148: 0x0018, 0x1149: 0x0018, 0x114a: 0x0018, 0x114b: 0x0018,
0x114c: 0x0018, 0x114d: 0x0018, 0x114e: 0x0018, 0x114f: 0x0018, 0x1150: 0x0018, 0x1151: 0x0018,
0x1152: 0x0018, 0x1153: 0x0018, 0x1154: 0x0018, 0x1155: 0x0018, 0x1156: 0x0018, 0x1157: 0x0008,
0x1158: 0x0008, 0x1159: 0x0008, 0x115a: 0x0008, 0x115b: 0x0008, 0x115c: 0x0008, 0x115d: 0x0008,
0x115e: 0x0008, 0x115f: 0x0008, 0x1160: 0x0018, 0x1161: 0x0018, 0x1162: 0xe00d, 0x1163: 0x0008,
0x1164: 0xe00d, 0x1165: 0x0008, 0x1166: 0xe00d, 0x1167: 0x0008, 0x1168: 0xe00d, 0x1169: 0x0008,
0x116a: 0xe00d, 0x116b: 0x0008, 0x116c: 0xe00d, 0x116d: 0x0008, 0x116e: 0xe00d, 0x116f: 0x0008,
0x1170: 0x0008, 0x1171: 0x0008, 0x1172: 0xe00d, 0x1173: 0x0008, 0x1174: 0xe00d, 0x1175: 0x0008,
0x1176: 0xe00d, 0x1177: 0x0008, 0x1178: 0xe00d, 0x1179: 0x0008, 0x117a: 0xe00d, 0x117b: 0x0008,
0x117c: 0xe00d, 0x117d: 0x0008, 0x117e: 0xe00d, 0x117f: 0x0008,
// Block 0x46, offset 0x1180
0x1180: 0xe00d, 0x1181: 0x0008, 0x1182: 0xe00d, 0x1183: 0x0008, 0x1184: 0xe00d, 0x1185: 0x0008,
0x1186: 0xe00d, 0x1187: 0x0008, 0x1188: 0xe00d, 0x1189: 0x0008, 0x118a: 0xe00d, 0x118b: 0x0008,
0x118c: 0xe00d, 0x118d: 0x0008, 0x118e: 0xe00d, 0x118f: 0x0008, 0x1190: 0xe00d, 0x1191: 0x0008,
0x1192: 0xe00d, 0x1193: 0x0008, 0x1194: 0xe00d, 0x1195: 0x0008, 0x1196: 0xe00d, 0x1197: 0x0008,
0x1198: 0xe00d, 0x1199: 0x0008, 0x119a: 0xe00d, 0x119b: 0x0008, 0x119c: 0xe00d, 0x119d: 0x0008,
0x119e: 0xe00d, 0x119f: 0x0008, 0x11a0: 0xe00d, 0x11a1: 0x0008, 0x11a2: 0xe00d, 0x11a3: 0x0008,
0x11a4: 0xe00d, 0x11a5: 0x0008, 0x11a6: 0xe00d, 0x11a7: 0x0008, 0x11a8: 0xe00d, 0x11a9: 0x0008,
0x11aa: 0xe00d, 0x11ab: 0x0008, 0x11ac: 0xe00d, 0x11ad: 0x0008, 0x11ae: 0xe00d, 0x11af: 0x0008,
0x11b0: 0xe0fd, 0x11b1: 0x0008, 0x11b2: 0x0008, 0x11b3: 0x0008, 0x11b4: 0x0008, 0x11b5: 0x0008,
0x11b6: 0x0008, 0x11b7: 0x0008, 0x11b8: 0x0008, 0x11b9: 0xe01d, 0x11ba: 0x0008, 0x11bb: 0xe03d,
0x11bc: 0x0008, 0x11bd: 0x4445, 0x11be: 0xe00d, 0x11bf: 0x0008,
// Block 0x47, offset 0x11c0
0x11c0: 0xe00d, 0x11c1: 0x0008, 0x11c2: 0xe00d, 0x11c3: 0x0008, 0x11c4: 0xe00d, 0x11c5: 0x0008,
0x11c6: 0xe00d, 0x11c7: 0x0008, 0x11c8: 0x0008, 0x11c9: 0x0018, 0x11ca: 0x0018, 0x11cb: 0xe03d,
0x11cc: 0x0008, 0x11cd: 0x0409, 0x11ce: 0x0008, 0x11cf: 0x0008, 0x11d0: 0xe00d, 0x11d1: 0x0008,
0x11d2: 0xe00d, 0x11d3: 0x0008, 0x11d4: 0x0008, 0x11d5: 0x0008, 0x11d6: 0xe00d, 0x11d7: 0x0008,
0x11d8: 0xe00d, 0x11d9: 0x0008, 0x11da: 0xe00d, 0x11db: 0x0008, 0x11dc: 0xe00d, 0x11dd: 0x0008,
0x11de: 0xe00d, 0x11df: 0x0008, 0x11e0: 0xe00d, 0x11e1: 0x0008, 0x11e2: 0xe00d, 0x11e3: 0x0008,
0x11e4: 0xe00d, 0x11e5: 0x0008, 0x11e6: 0xe00d, 0x11e7: 0x0008, 0x11e8: 0xe00d, 0x11e9: 0x0008,
0x11ea: 0x13d1, 0x11eb: 0x0371, 0x11ec: 0x0401, 0x11ed: 0x13d9, 0x11ee: 0x0421, 0x11ef: 0x0008,
0x11f0: 0x13e1, 0x11f1: 0x13e9, 0x11f2: 0x0429, 0x11f3: 0x4465, 0x11f4: 0xe00d, 0x11f5: 0x0008,
0x11f6: 0xe00d, 0x11f7: 0x0008, 0x11f8: 0xe00d, 0x11f9: 0x0008, 0x11fa: 0xe00d, 0x11fb: 0x0008,
0x11fc: 0xe00d, 0x11fd: 0x0008, 0x11fe: 0xe00d, 0x11ff: 0x0008,
// Block 0x48, offset 0x1200
0x1200: 0xe00d, 0x1201: 0x0008, 0x1202: 0xe00d, 0x1203: 0x0008, 0x1204: 0x03f5, 0x1205: 0x0479,
0x1206: 0x447d, 0x1207: 0xe07d, 0x1208: 0x0008, 0x1209: 0xe01d, 0x120a: 0x0008, 0x120b: 0x0040,
0x120c: 0x0040, 0x120d: 0x0040, 0x120e: 0x0040, 0x120f: 0x0040, 0x1210: 0xe00d, 0x1211: 0x0008,
0x1212: 0x0040, 0x1213: 0x0008, 0x1214: 0x0040, 0x1215: 0x0008, 0x1216: 0xe00d, 0x1217: 0x0008,
0x1218: 0xe00d, 0x1219: 0x0008, 0x121a: 0x0040, 0x121b: 0x0040, 0x121c: 0x0040, 0x121d: 0x0040,
0x121e: 0x0040, 0x121f: 0x0040, 0x1220: 0x0040, 0x1221: 0x0040, 0x1222: 0x0040, 0x1223: 0x0040,
0x1224: 0x0040, 0x1225: 0x0040, 0x1226: 0x0040, 0x1227: 0x0040, 0x1228: 0x0040, 0x1229: 0x0040,
0x122a: 0x0040, 0x122b: 0x0040, 0x122c: 0x0040, 0x122d: 0x0040, 0x122e: 0x0040, 0x122f: 0x0040,
0x1230: 0x0040, 0x1231: 0x0040, 0x1232: 0x03d9, 0x1233: 0x03f1, 0x1234: 0x0751, 0x1235: 0xe01d,
0x1236: 0x0008, 0x1237: 0x0008, 0x1238: 0x0741, 0x1239: 0x13f1, 0x123a: 0x0008, 0x123b: 0x0008,
0x123c: 0x0008, 0x123d: 0x0008, 0x123e: 0x0008, 0x123f: 0x0008,
// Block 0x49, offset 0x1240
0x1240: 0x650d, 0x1241: 0x652d, 0x1242: 0x654d, 0x1243: 0x656d, 0x1244: 0x658d, 0x1245: 0x65ad,
0x1246: 0x65cd, 0x1247: 0x65ed, 0x1248: 0x660d, 0x1249: 0x662d, 0x124a: 0x664d, 0x124b: 0x666d,
0x124c: 0x668d, 0x124d: 0x66ad, 0x124e: 0x0008, 0x124f: 0x0008, 0x1250: 0x66cd, 0x1251: 0x0008,
0x1252: 0x66ed, 0x1253: 0x0008, 0x1254: 0x0008, 0x1255: 0x670d, 0x1256: 0x672d, 0x1257: 0x674d,
0x1258: 0x676d, 0x1259: 0x678d, 0x125a: 0x67ad, 0x125b: 0x67cd, 0x125c: 0x67ed, 0x125d: 0x680d,
0x125e: 0x682d, 0x125f: 0x0008, 0x1260: 0x684d, 0x1261: 0x0008, 0x1262: 0x686d, 0x1263: 0x0008,
0x1264: 0x0008, 0x1265: 0x688d, 0x1266: 0x68ad, 0x1267: 0x0008, 0x1268: 0x0008, 0x1269: 0x0008,
0x126a: 0x68cd, 0x126b: 0x68ed, 0x126c: 0x690d, 0x126d: 0x692d, 0x126e: 0x694d, 0x126f: 0x696d,
0x1270: 0x698d, 0x1271: 0x69ad, 0x1272: 0x69cd, 0x1273: 0x69ed, 0x1274: 0x6a0d, 0x1275: 0x6a2d,
0x1276: 0x6a4d, 0x1277: 0x6a6d, 0x1278: 0x6a8d, 0x1279: 0x6aad, 0x127a: 0x6acd, 0x127b: 0x6aed,
0x127c: 0x6b0d, 0x127d: 0x6b2d, 0x127e: 0x6b4d, 0x127f: 0x6b6d,
// Block 0x4a, offset 0x1280
0x1280: 0x7acd, 0x1281: 0x7aed, 0x1282: 0x7b0d, 0x1283: 0x7b2d, 0x1284: 0x7b4d, 0x1285: 0x7b6d,
0x1286: 0x7b8d, 0x1287: 0x7bad, 0x1288: 0x7bcd, 0x1289: 0x7bed, 0x128a: 0x7c0d, 0x128b: 0x7c2d,
0x128c: 0x7c4d, 0x128d: 0x7c6d, 0x128e: 0x7c8d, 0x128f: 0x1409, 0x1290: 0x1411, 0x1291: 0x1419,
0x1292: 0x7cad, 0x1293: 0x7ccd, 0x1294: 0x7ced, 0x1295: 0x1421, 0x1296: 0x1429, 0x1297: 0x1431,
0x1298: 0x7d0d, 0x1299: 0x7d2d, 0x129a: 0x0040, 0x129b: 0x0040, 0x129c: 0x0040, 0x129d: 0x0040,
0x129e: 0x0040, 0x129f: 0x0040, 0x12a0: 0x0040, 0x12a1: 0x0040, 0x12a2: 0x0040, 0x12a3: 0x0040,
0x12a4: 0x0040, 0x12a5: 0x0040, 0x12a6: 0x0040, 0x12a7: 0x0040, 0x12a8: 0x0040, 0x12a9: 0x0040,
0x12aa: 0x0040, 0x12ab: 0x0040, 0x12ac: 0x0040, 0x12ad: 0x0040, 0x12ae: 0x0040, 0x12af: 0x0040,
0x12b0: 0x0040, 0x12b1: 0x0040, 0x12b2: 0x0040, 0x12b3: 0x0040, 0x12b4: 0x0040, 0x12b5: 0x0040,
0x12b6: 0x0040, 0x12b7: 0x0040, 0x12b8: 0x0040, 0x12b9: 0x0040, 0x12ba: 0x0040, 0x12bb: 0x0040,
0x12bc: 0x0040, 0x12bd: 0x0040, 0x12be: 0x0040, 0x12bf: 0x0040,
// Block 0x4b, offset 0x12c0
0x12c0: 0x1439, 0x12c1: 0x1441, 0x12c2: 0x1449, 0x12c3: 0x7d4d, 0x12c4: 0x7d6d, 0x12c5: 0x1451,
0x12c6: 0x1451, 0x12c7: 0x0040, 0x12c8: 0x0040, 0x12c9: 0x0040, 0x12ca: 0x0040, 0x12cb: 0x0040,
0x12cc: 0x0040, 0x12cd: 0x0040, 0x12ce: 0x0040, 0x12cf: 0x0040, 0x12d0: 0x0040, 0x12d1: 0x0040,
0x12d2: 0x0040, 0x12d3: 0x1459, 0x12d4: 0x1461, 0x12d5: 0x1469, 0x12d6: 0x1471, 0x12d7: 0x1479,
0x12d8: 0x0040, 0x12d9: 0x0040, 0x12da: 0x0040, 0x12db: 0x0040, 0x12dc: 0x0040, 0x12dd: 0x1481,
0x12de: 0x3308, 0x12df: 0x1489, 0x12e0: 0x1491, 0x12e1: 0x0779, 0x12e2: 0x0791, 0x12e3: 0x1499,
0x12e4: 0x14a1, 0x12e5: 0x14a9, 0x12e6: 0x14b1, 0x12e7: 0x14b9, 0x12e8: 0x14c1, 0x12e9: 0x071a,
0x12ea: 0x14c9, 0x12eb: 0x14d1, 0x12ec: 0x14d9, 0x12ed: 0x14e1, 0x12ee: 0x14e9, 0x12ef: 0x14f1,
0x12f0: 0x14f9, 0x12f1: 0x1501, 0x12f2: 0x1509, 0x12f3: 0x1511, 0x12f4: 0x1519, 0x12f5: 0x1521,
0x12f6: 0x1529, 0x12f7: 0x0040, 0x12f8: 0x1531, 0x12f9: 0x1539, 0x12fa: 0x1541, 0x12fb: 0x1549,
0x12fc: 0x1551, 0x12fd: 0x0040, 0x12fe: 0x1559, 0x12ff: 0x0040,
// Block 0x4c, offset 0x1300
0x1300: 0x1561, 0x1301: 0x1569, 0x1302: 0x0040, 0x1303: 0x1571, 0x1304: 0x1579, 0x1305: 0x0040,
0x1306: 0x1581, 0x1307: 0x1589, 0x1308: 0x1591, 0x1309: 0x1599, 0x130a: 0x15a1, 0x130b: 0x15a9,
0x130c: 0x15b1, 0x130d: 0x15b9, 0x130e: 0x15c1, 0x130f: 0x15c9, 0x1310: 0x15d1, 0x1311: 0x15d1,
0x1312: 0x15d9, 0x1313: 0x15d9, 0x1314: 0x15d9, 0x1315: 0x15d9, 0x1316: 0x15e1, 0x1317: 0x15e1,
0x1318: 0x15e1, 0x1319: 0x15e1, 0x131a: 0x15e9, 0x131b: 0x15e9, 0x131c: 0x15e9, 0x131d: 0x15e9,
0x131e: 0x15f1, 0x131f: 0x15f1, 0x1320: 0x15f1, 0x1321: 0x15f1, 0x1322: 0x15f9, 0x1323: 0x15f9,
0x1324: 0x15f9, 0x1325: 0x15f9, 0x1326: 0x1601, 0x1327: 0x1601, 0x1328: 0x1601, 0x1329: 0x1601,
0x132a: 0x1609, 0x132b: 0x1609, 0x132c: 0x1609, 0x132d: 0x1609, 0x132e: 0x1611, 0x132f: 0x1611,
0x1330: 0x1611, 0x1331: 0x1611, 0x1332: 0x1619, 0x1333: 0x1619, 0x1334: 0x1619, 0x1335: 0x1619,
0x1336: 0x1621, 0x1337: 0x1621, 0x1338: 0x1621, 0x1339: 0x1621, 0x133a: 0x1629, 0x133b: 0x1629,
0x133c: 0x1629, 0x133d: 0x1629, 0x133e: 0x1631, 0x133f: 0x1631,
// Block 0x4d, offset 0x1340
0x1340: 0x1631, 0x1341: 0x1631, 0x1342: 0x1639, 0x1343: 0x1639, 0x1344: 0x1641, 0x1345: 0x1641,
0x1346: 0x1649, 0x1347: 0x1649, 0x1348: 0x1651, 0x1349: 0x1651, 0x134a: 0x1659, 0x134b: 0x1659,
0x134c: 0x1661, 0x134d: 0x1661, 0x134e: 0x1669, 0x134f: 0x1669, 0x1350: 0x1669, 0x1351: 0x1669,
0x1352: 0x1671, 0x1353: 0x1671, 0x1354: 0x1671, 0x1355: 0x1671, 0x1356: 0x1679, 0x1357: 0x1679,
0x1358: 0x1679, 0x1359: 0x1679, 0x135a: 0x1681, 0x135b: 0x1681, 0x135c: 0x1681, 0x135d: 0x1681,
0x135e: 0x1689, 0x135f: 0x1689, 0x1360: 0x1691, 0x1361: 0x1691, 0x1362: 0x1691, 0x1363: 0x1691,
0x1364: 0x1699, 0x1365: 0x1699, 0x1366: 0x16a1, 0x1367: 0x16a1, 0x1368: 0x16a1, 0x1369: 0x16a1,
0x136a: 0x16a9, 0x136b: 0x16a9, 0x136c: 0x16a9, 0x136d: 0x16a9, 0x136e: 0x16b1, 0x136f: 0x16b1,
0x1370: 0x16b9, 0x1371: 0x16b9, 0x1372: 0x0818, 0x1373: 0x0818, 0x1374: 0x0818, 0x1375: 0x0818,
0x1376: 0x0818, 0x1377: 0x0818, 0x1378: 0x0818, 0x1379: 0x0818, 0x137a: 0x0818, 0x137b: 0x0818,
0x137c: 0x0818, 0x137d: 0x0818, 0x137e: 0x0818, 0x137f: 0x0818,
// Block 0x4e, offset 0x1380
0x1380: 0x0818, 0x1381: 0x0818, 0x1382: 0x0818, 0x1383: 0x0040, 0x1384: 0x0040, 0x1385: 0x0040,
0x1386: 0x0040, 0x1387: 0x0040, 0x1388: 0x0040, 0x1389: 0x0040, 0x138a: 0x0040, 0x138b: 0x0040,
0x138c: 0x0040, 0x138d: 0x0040, 0x138e: 0x0040, 0x138f: 0x0040, 0x1390: 0x0040, 0x1391: 0x0040,
0x1392: 0x0040, 0x1393: 0x16c1, 0x1394: 0x16c1, 0x1395: 0x16c1, 0x1396: 0x16c1, 0x1397: 0x16c9,
0x1398: 0x16c9, 0x1399: 0x16d1, 0x139a: 0x16d1, 0x139b: 0x16d9, 0x139c: 0x16d9, 0x139d: 0x0149,
0x139e: 0x16e1, 0x139f: 0x16e1, 0x13a0: 0x16e9, 0x13a1: 0x16e9, 0x13a2: 0x16f1, 0x13a3: 0x16f1,
0x13a4: 0x16f9, 0x13a5: 0x16f9, 0x13a6: 0x16f9, 0x13a7: 0x16f9, 0x13a8: 0x1701, 0x13a9: 0x1701,
0x13aa: 0x1709, 0x13ab: 0x1709, 0x13ac: 0x1711, 0x13ad: 0x1711, 0x13ae: 0x1719, 0x13af: 0x1719,
0x13b0: 0x1721, 0x13b1: 0x1721, 0x13b2: 0x1729, 0x13b3: 0x1729, 0x13b4: 0x1731, 0x13b5: 0x1731,
0x13b6: 0x1739, 0x13b7: 0x1739, 0x13b8: 0x1739, 0x13b9: 0x1741, 0x13ba: 0x1741, 0x13bb: 0x1741,
0x13bc: 0x1749, 0x13bd: 0x1749, 0x13be: 0x1749, 0x13bf: 0x1749,
// Block 0x4f, offset 0x13c0
0x13c0: 0x1949, 0x13c1: 0x1951, 0x13c2: 0x1959, 0x13c3: 0x1961, 0x13c4: 0x1969, 0x13c5: 0x1971,
0x13c6: 0x1979, 0x13c7: 0x1981, 0x13c8: 0x1989, 0x13c9: 0x1991, 0x13ca: 0x1999, 0x13cb: 0x19a1,
0x13cc: 0x19a9, 0x13cd: 0x19b1, 0x13ce: 0x19b9, 0x13cf: 0x19c1, 0x13d0: 0x19c9, 0x13d1: 0x19d1,
0x13d2: 0x19d9, 0x13d3: 0x19e1, 0x13d4: 0x19e9, 0x13d5: 0x19f1, 0x13d6: 0x19f9, 0x13d7: 0x1a01,
0x13d8: 0x1a09, 0x13d9: 0x1a11, 0x13da: 0x1a19, 0x13db: 0x1a21, 0x13dc: 0x1a29, 0x13dd: 0x1a31,
0x13de: 0x1a3a, 0x13df: 0x1a42, 0x13e0: 0x1a4a, 0x13e1: 0x1a52, 0x13e2: 0x1a5a, 0x13e3: 0x1a62,
0x13e4: 0x1a69, 0x13e5: 0x1a71, 0x13e6: 0x1761, 0x13e7: 0x1a79, 0x13e8: 0x1741, 0x13e9: 0x1769,
0x13ea: 0x1a81, 0x13eb: 0x1a89, 0x13ec: 0x1789, 0x13ed: 0x1a91, 0x13ee: 0x1791, 0x13ef: 0x1799,
0x13f0: 0x1a99, 0x13f1: 0x1aa1, 0x13f2: 0x17b9, 0x13f3: 0x1aa9, 0x13f4: 0x17c1, 0x13f5: 0x17c9,
0x13f6: 0x1ab1, 0x13f7: 0x1ab9, 0x13f8: 0x17d9, 0x13f9: 0x1ac1, 0x13fa: 0x17e1, 0x13fb: 0x17e9,
0x13fc: 0x18d1, 0x13fd: 0x18d9, 0x13fe: 0x18f1, 0x13ff: 0x18f9,
// Block 0x50, offset 0x1400
0x1400: 0x1901, 0x1401: 0x1921, 0x1402: 0x1929, 0x1403: 0x1931, 0x1404: 0x1939, 0x1405: 0x1959,
0x1406: 0x1961, 0x1407: 0x1969, 0x1408: 0x1ac9, 0x1409: 0x1989, 0x140a: 0x1ad1, 0x140b: 0x1ad9,
0x140c: 0x19b9, 0x140d: 0x1ae1, 0x140e: 0x19c1, 0x140f: 0x19c9, 0x1410: 0x1a31, 0x1411: 0x1ae9,
0x1412: 0x1af1, 0x1413: 0x1a09, 0x1414: 0x1af9, 0x1415: 0x1a11, 0x1416: 0x1a19, 0x1417: 0x1751,
0x1418: 0x1759, 0x1419: 0x1b01, 0x141a: 0x1761, 0x141b: 0x1b09, 0x141c: 0x1771, 0x141d: 0x1779,
0x141e: 0x1781, 0x141f: 0x1789, 0x1420: 0x1b11, 0x1421: 0x17a1, 0x1422: 0x17a9, 0x1423: 0x17b1,
0x1424: 0x17b9, 0x1425: 0x1b19, 0x1426: 0x17d9, 0x1427: 0x17f1, 0x1428: 0x17f9, 0x1429: 0x1801,
0x142a: 0x1809, 0x142b: 0x1811, 0x142c: 0x1821, 0x142d: 0x1829, 0x142e: 0x1831, 0x142f: 0x1839,
0x1430: 0x1841, 0x1431: 0x1849, 0x1432: 0x1b21, 0x1433: 0x1851, 0x1434: 0x1859, 0x1435: 0x1861,
0x1436: 0x1869, 0x1437: 0x1871, 0x1438: 0x1879, 0x1439: 0x1889, 0x143a: 0x1891, 0x143b: 0x1899,
0x143c: 0x18a1, 0x143d: 0x18a9, 0x143e: 0x18b1, 0x143f: 0x18b9,
// Block 0x51, offset 0x1440
0x1440: 0x18c1, 0x1441: 0x18c9, 0x1442: 0x18e1, 0x1443: 0x18e9, 0x1444: 0x1909, 0x1445: 0x1911,
0x1446: 0x1919, 0x1447: 0x1921, 0x1448: 0x1929, 0x1449: 0x1941, 0x144a: 0x1949, 0x144b: 0x1951,
0x144c: 0x1959, 0x144d: 0x1b29, 0x144e: 0x1971, 0x144f: 0x1979, 0x1450: 0x1981, 0x1451: 0x1989,
0x1452: 0x19a1, 0x1453: 0x19a9, 0x1454: 0x19b1, 0x1455: 0x19b9, 0x1456: 0x1b31, 0x1457: 0x19d1,
0x1458: 0x19d9, 0x1459: 0x1b39, 0x145a: 0x19f1, 0x145b: 0x19f9, 0x145c: 0x1a01, 0x145d: 0x1a09,
0x145e: 0x1b41, 0x145f: 0x1761, 0x1460: 0x1b09, 0x1461: 0x1789, 0x1462: 0x1b11, 0x1463: 0x17b9,
0x1464: 0x1b19, 0x1465: 0x17d9, 0x1466: 0x1b49, 0x1467: 0x1841, 0x1468: 0x1b51, 0x1469: 0x1b59,
0x146a: 0x1b61, 0x146b: 0x1921, 0x146c: 0x1929, 0x146d: 0x1959, 0x146e: 0x19b9, 0x146f: 0x1b31,
0x1470: 0x1a09, 0x1471: 0x1b41, 0x1472: 0x1b69, 0x1473: 0x1b71, 0x1474: 0x1b79, 0x1475: 0x1b81,
0x1476: 0x1b89, 0x1477: 0x1b91, 0x1478: 0x1b99, 0x1479: 0x1ba1, 0x147a: 0x1ba9, 0x147b: 0x1bb1,
0x147c: 0x1bb9, 0x147d: 0x1bc1, 0x147e: 0x1bc9, 0x147f: 0x1bd1,
// Block 0x52, offset 0x1480
0x1480: 0x1bd9, 0x1481: 0x1be1, 0x1482: 0x1be9, 0x1483: 0x1bf1, 0x1484: 0x1bf9, 0x1485: 0x1c01,
0x1486: 0x1c09, 0x1487: 0x1c11, 0x1488: 0x1c19, 0x1489: 0x1c21, 0x148a: 0x1c29, 0x148b: 0x1c31,
0x148c: 0x1b59, 0x148d: 0x1c39, 0x148e: 0x1c41, 0x148f: 0x1c49, 0x1490: 0x1c51, 0x1491: 0x1b81,
0x1492: 0x1b89, 0x1493: 0x1b91, 0x1494: 0x1b99, 0x1495: 0x1ba1, 0x1496: 0x1ba9, 0x1497: 0x1bb1,
0x1498: 0x1bb9, 0x1499: 0x1bc1, 0x149a: 0x1bc9, 0x149b: 0x1bd1, 0x149c: 0x1bd9, 0x149d: 0x1be1,
0x149e: 0x1be9, 0x149f: 0x1bf1, 0x14a0: 0x1bf9, 0x14a1: 0x1c01, 0x14a2: 0x1c09, 0x14a3: 0x1c11,
0x14a4: 0x1c19, 0x14a5: 0x1c21, 0x14a6: 0x1c29, 0x14a7: 0x1c31, 0x14a8: 0x1b59, 0x14a9: 0x1c39,
0x14aa: 0x1c41, 0x14ab: 0x1c49, 0x14ac: 0x1c51, 0x14ad: 0x1c21, 0x14ae: 0x1c29, 0x14af: 0x1c31,
0x14b0: 0x1b59, 0x14b1: 0x1b51, 0x14b2: 0x1b61, 0x14b3: 0x1881, 0x14b4: 0x1829, 0x14b5: 0x1831,
0x14b6: 0x1839, 0x14b7: 0x1c21, 0x14b8: 0x1c29, 0x14b9: 0x1c31, 0x14ba: 0x1881, 0x14bb: 0x1889,
0x14bc: 0x1c59, 0x14bd: 0x1c59, 0x14be: 0x0018, 0x14bf: 0x0018,
// Block 0x53, offset 0x14c0
0x14c0: 0x0018, 0x14c1: 0x0018, 0x14c2: 0x0018, 0x14c3: 0x0018, 0x14c4: 0x0018, 0x14c5: 0x0018,
0x14c6: 0x0018, 0x14c7: 0x0018, 0x14c8: 0x0018, 0x14c9: 0x0018, 0x14ca: 0x0018, 0x14cb: 0x0018,
0x14cc: 0x0018, 0x14cd: 0x0018, 0x14ce: 0x0018, 0x14cf: 0x0018, 0x14d0: 0x1c61, 0x14d1: 0x1c69,
0x14d2: 0x1c69, 0x14d3: 0x1c71, 0x14d4: 0x1c79, 0x14d5: 0x1c81, 0x14d6: 0x1c89, 0x14d7: 0x1c91,
0x14d8: 0x1c99, 0x14d9: 0x1c99, 0x14da: 0x1ca1, 0x14db: 0x1ca9, 0x14dc: 0x1cb1, 0x14dd: 0x1cb9,
0x14de: 0x1cc1, 0x14df: 0x1cc9, 0x14e0: 0x1cc9, 0x14e1: 0x1cd1, 0x14e2: 0x1cd9, 0x14e3: 0x1cd9,
0x14e4: 0x1ce1, 0x14e5: 0x1ce1, 0x14e6: 0x1ce9, 0x14e7: 0x1cf1, 0x14e8: 0x1cf1, 0x14e9: 0x1cf9,
0x14ea: 0x1d01, 0x14eb: 0x1d01, 0x14ec: 0x1d09, 0x14ed: 0x1d09, 0x14ee: 0x1d11, 0x14ef: 0x1d19,
0x14f0: 0x1d19, 0x14f1: 0x1d21, 0x14f2: 0x1d21, 0x14f3: 0x1d29, 0x14f4: 0x1d31, 0x14f5: 0x1d39,
0x14f6: 0x1d41, 0x14f7: 0x1d41, 0x14f8: 0x1d49, 0x14f9: 0x1d51, 0x14fa: 0x1d59, 0x14fb: 0x1d61,
0x14fc: 0x1d69, 0x14fd: 0x1d69, 0x14fe: 0x1d71, 0x14ff: 0x1d79,
// Block 0x54, offset 0x1500
0x1500: 0x1f29, 0x1501: 0x1f31, 0x1502: 0x1f39, 0x1503: 0x1f11, 0x1504: 0x1d39, 0x1505: 0x1ce9,
0x1506: 0x1f41, 0x1507: 0x1f49, 0x1508: 0x0040, 0x1509: 0x0040, 0x150a: 0x0040, 0x150b: 0x0040,
0x150c: 0x0040, 0x150d: 0x0040, 0x150e: 0x0040, 0x150f: 0x0018, 0x1510: 0x0040, 0x1511: 0x0040,
0x1512: 0x0040, 0x1513: 0x0040, 0x1514: 0x0040, 0x1515: 0x0040, 0x1516: 0x0040, 0x1517: 0x0040,
0x1518: 0x0040, 0x1519: 0x0040, 0x151a: 0x0040, 0x151b: 0x0040, 0x151c: 0x0040, 0x151d: 0x0040,
0x151e: 0x0040, 0x151f: 0x0040, 0x1520: 0x0040, 0x1521: 0x0040, 0x1522: 0x0040, 0x1523: 0x0040,
0x1524: 0x0040, 0x1525: 0x0040, 0x1526: 0x0040, 0x1527: 0x0040, 0x1528: 0x0040, 0x1529: 0x0040,
0x152a: 0x0040, 0x152b: 0x0040, 0x152c: 0x0040, 0x152d: 0x0040, 0x152e: 0x0040, 0x152f: 0x0040,
0x1530: 0x1f51, 0x1531: 0x1f59, 0x1532: 0x1f61, 0x1533: 0x1f69, 0x1534: 0x1f71, 0x1535: 0x1f79,
0x1536: 0x1f81, 0x1537: 0x1f89, 0x1538: 0x1f91, 0x1539: 0x1f99, 0x153a: 0x1fa2, 0x153b: 0x1faa,
0x153c: 0x1fb1, 0x153d: 0x0018, 0x153e: 0x0018, 0x153f: 0x0018,
// Block 0x55, offset 0x1540
0x1540: 0x33c0, 0x1541: 0x33c0, 0x1542: 0x33c0, 0x1543: 0x33c0, 0x1544: 0x33c0, 0x1545: 0x33c0,
0x1546: 0x33c0, 0x1547: 0x33c0, 0x1548: 0x33c0, 0x1549: 0x33c0, 0x154a: 0x33c0, 0x154b: 0x33c0,
0x154c: 0x33c0, 0x154d: 0x33c0, 0x154e: 0x33c0, 0x154f: 0x33c0, 0x1550: 0x1fba, 0x1551: 0x7d8d,
0x1552: 0x0040, 0x1553: 0x1fc2, 0x1554: 0x0122, 0x1555: 0x1fca, 0x1556: 0x1fd2, 0x1557: 0x7dad,
0x1558: 0x7dcd, 0x1559: 0x0040, 0x155a: 0x0040, 0x155b: 0x0040, 0x155c: 0x0040, 0x155d: 0x0040,
0x155e: 0x0040, 0x155f: 0x0040, 0x1560: 0x3308, 0x1561: 0x3308, 0x1562: 0x3308, 0x1563: 0x3308,
0x1564: 0x3308, 0x1565: 0x3308, 0x1566: 0x3308, 0x1567: 0x3308, 0x1568: 0x3308, 0x1569: 0x3308,
0x156a: 0x3308, 0x156b: 0x3308, 0x156c: 0x3308, 0x156d: 0x3308, 0x156e: 0x3308, 0x156f: 0x3308,
0x1570: 0x0040, 0x1571: 0x7ded, 0x1572: 0x7e0d, 0x1573: 0x1fda, 0x1574: 0x1fda, 0x1575: 0x072a,
0x1576: 0x0732, 0x1577: 0x1fe2, 0x1578: 0x1fea, 0x1579: 0x7e2d, 0x157a: 0x7e4d, 0x157b: 0x7e6d,
0x157c: 0x7e2d, 0x157d: 0x7e8d, 0x157e: 0x7ead, 0x157f: 0x7e8d,
// Block 0x56, offset 0x1580
0x1580: 0x7ecd, 0x1581: 0x7eed, 0x1582: 0x7f0d, 0x1583: 0x7eed, 0x1584: 0x7f2d, 0x1585: 0x0018,
0x1586: 0x0018, 0x1587: 0x1ff2, 0x1588: 0x1ffa, 0x1589: 0x7f4e, 0x158a: 0x7f6e, 0x158b: 0x7f8e,
0x158c: 0x7fae, 0x158d: 0x1fda, 0x158e: 0x1fda, 0x158f: 0x1fda, 0x1590: 0x1fba, 0x1591: 0x7fcd,
0x1592: 0x0040, 0x1593: 0x0040, 0x1594: 0x0122, 0x1595: 0x1fc2, 0x1596: 0x1fd2, 0x1597: 0x1fca,
0x1598: 0x7fed, 0x1599: 0x072a, 0x159a: 0x0732, 0x159b: 0x1fe2, 0x159c: 0x1fea, 0x159d: 0x7ecd,
0x159e: 0x7f2d, 0x159f: 0x2002, 0x15a0: 0x200a, 0x15a1: 0x2012, 0x15a2: 0x071a, 0x15a3: 0x2019,
0x15a4: 0x2022, 0x15a5: 0x202a, 0x15a6: 0x0722, 0x15a7: 0x0040, 0x15a8: 0x2032, 0x15a9: 0x203a,
0x15aa: 0x2042, 0x15ab: 0x204a, 0x15ac: 0x0040, 0x15ad: 0x0040, 0x15ae: 0x0040, 0x15af: 0x0040,
0x15b0: 0x800e, 0x15b1: 0x2051, 0x15b2: 0x802e, 0x15b3: 0x0808, 0x15b4: 0x804e, 0x15b5: 0x0040,
0x15b6: 0x806e, 0x15b7: 0x2059, 0x15b8: 0x808e, 0x15b9: 0x2061, 0x15ba: 0x80ae, 0x15bb: 0x2069,
0x15bc: 0x80ce, 0x15bd: 0x2071, 0x15be: 0x80ee, 0x15bf: 0x2079,
// Block 0x57, offset 0x15c0
0x15c0: 0x2081, 0x15c1: 0x2089, 0x15c2: 0x2089, 0x15c3: 0x2091, 0x15c4: 0x2091, 0x15c5: 0x2099,
0x15c6: 0x2099, 0x15c7: 0x20a1, 0x15c8: 0x20a1, 0x15c9: 0x20a9, 0x15ca: 0x20a9, 0x15cb: 0x20a9,
0x15cc: 0x20a9, 0x15cd: 0x20b1, 0x15ce: 0x20b1, 0x15cf: 0x20b9, 0x15d0: 0x20b9, 0x15d1: 0x20b9,
0x15d2: 0x20b9, 0x15d3: 0x20c1, 0x15d4: 0x20c1, 0x15d5: 0x20c9, 0x15d6: 0x20c9, 0x15d7: 0x20c9,
0x15d8: 0x20c9, 0x15d9: 0x20d1, 0x15da: 0x20d1, 0x15db: 0x20d1, 0x15dc: 0x20d1, 0x15dd: 0x20d9,
0x15de: 0x20d9, 0x15df: 0x20d9, 0x15e0: 0x20d9, 0x15e1: 0x20e1, 0x15e2: 0x20e1, 0x15e3: 0x20e1,
0x15e4: 0x20e1, 0x15e5: 0x20e9, 0x15e6: 0x20e9, 0x15e7: 0x20e9, 0x15e8: 0x20e9, 0x15e9: 0x20f1,
0x15ea: 0x20f1, 0x15eb: 0x20f9, 0x15ec: 0x20f9, 0x15ed: 0x2101, 0x15ee: 0x2101, 0x15ef: 0x2109,
0x15f0: 0x2109, 0x15f1: 0x2111, 0x15f2: 0x2111, 0x15f3: 0x2111, 0x15f4: 0x2111, 0x15f5: 0x2119,
0x15f6: 0x2119, 0x15f7: 0x2119, 0x15f8: 0x2119, 0x15f9: 0x2121, 0x15fa: 0x2121, 0x15fb: 0x2121,
0x15fc: 0x2121, 0x15fd: 0x2129, 0x15fe: 0x2129, 0x15ff: 0x2129,
// Block 0x58, offset 0x1600
0x1600: 0x2129, 0x1601: 0x2131, 0x1602: 0x2131, 0x1603: 0x2131, 0x1604: 0x2131, 0x1605: 0x2139,
0x1606: 0x2139, 0x1607: 0x2139, 0x1608: 0x2139, 0x1609: 0x2141, 0x160a: 0x2141, 0x160b: 0x2141,
0x160c: 0x2141, 0x160d: 0x2149, 0x160e: 0x2149, 0x160f: 0x2149, 0x1610: 0x2149, 0x1611: 0x2151,
0x1612: 0x2151, 0x1613: 0x2151, 0x1614: 0x2151, 0x1615: 0x2159, 0x1616: 0x2159, 0x1617: 0x2159,
0x1618: 0x2159, 0x1619: 0x2161, 0x161a: 0x2161, 0x161b: 0x2161, 0x161c: 0x2161, 0x161d: 0x2169,
0x161e: 0x2169, 0x161f: 0x2169, 0x1620: 0x2169, 0x1621: 0x2171, 0x1622: 0x2171, 0x1623: 0x2171,
0x1624: 0x2171, 0x1625: 0x2179, 0x1626: 0x2179, 0x1627: 0x2179, 0x1628: 0x2179, 0x1629: 0x2181,
0x162a: 0x2181, 0x162b: 0x2181, 0x162c: 0x2181, 0x162d: 0x2189, 0x162e: 0x2189, 0x162f: 0x1701,
0x1630: 0x1701, 0x1631: 0x2191, 0x1632: 0x2191, 0x1633: 0x2191, 0x1634: 0x2191, 0x1635: 0x2199,
0x1636: 0x2199, 0x1637: 0x21a1, 0x1638: 0x21a1, 0x1639: 0x21a9, 0x163a: 0x21a9, 0x163b: 0x21b1,
0x163c: 0x21b1, 0x163d: 0x0040, 0x163e: 0x0040, 0x163f: 0x03c0,
// Block 0x59, offset 0x1640
0x1640: 0x0040, 0x1641: 0x1fca, 0x1642: 0x21ba, 0x1643: 0x2002, 0x1644: 0x203a, 0x1645: 0x2042,
0x1646: 0x200a, 0x1647: 0x21c2, 0x1648: 0x072a, 0x1649: 0x0732, 0x164a: 0x2012, 0x164b: 0x071a,
0x164c: 0x1fba, 0x164d: 0x2019, 0x164e: 0x0961, 0x164f: 0x21ca, 0x1650: 0x06e1, 0x1651: 0x0049,
0x1652: 0x0029, 0x1653: 0x0031, 0x1654: 0x06e9, 0x1655: 0x06f1, 0x1656: 0x06f9, 0x1657: 0x0701,
0x1658: 0x0709, 0x1659: 0x0711, 0x165a: 0x1fc2, 0x165b: 0x0122, 0x165c: 0x2022, 0x165d: 0x0722,
0x165e: 0x202a, 0x165f: 0x1fd2, 0x1660: 0x204a, 0x1661: 0x0019, 0x1662: 0x02e9, 0x1663: 0x03d9,
0x1664: 0x02f1, 0x1665: 0x02f9, 0x1666: 0x03f1, 0x1667: 0x0309, 0x1668: 0x00a9, 0x1669: 0x0311,
0x166a: 0x00b1, 0x166b: 0x0319, 0x166c: 0x0101, 0x166d: 0x0321, 0x166e: 0x0329, 0x166f: 0x0051,
0x1670: 0x0339, 0x1671: 0x0751, 0x1672: 0x00b9, 0x1673: 0x0089, 0x1674: 0x0341, 0x1675: 0x0349,
0x1676: 0x0391, 0x1677: 0x00c1, 0x1678: 0x0109, 0x1679: 0x00c9, 0x167a: 0x04b1, 0x167b: 0x1ff2,
0x167c: 0x2032, 0x167d: 0x1ffa, 0x167e: 0x21d2, 0x167f: 0x1fda,
// Block 0x5a, offset 0x1680
0x1680: 0x0672, 0x1681: 0x0019, 0x1682: 0x02e9, 0x1683: 0x03d9, 0x1684: 0x02f1, 0x1685: 0x02f9,
0x1686: 0x03f1, 0x1687: 0x0309, 0x1688: 0x00a9, 0x1689: 0x0311, 0x168a: 0x00b1, 0x168b: 0x0319,
0x168c: 0x0101, 0x168d: 0x0321, 0x168e: 0x0329, 0x168f: 0x0051, 0x1690: 0x0339, 0x1691: 0x0751,
0x1692: 0x00b9, 0x1693: 0x0089, 0x1694: 0x0341, 0x1695: 0x0349, 0x1696: 0x0391, 0x1697: 0x00c1,
0x1698: 0x0109, 0x1699: 0x00c9, 0x169a: 0x04b1, 0x169b: 0x1fe2, 0x169c: 0x21da, 0x169d: 0x1fea,
0x169e: 0x21e2, 0x169f: 0x810d, 0x16a0: 0x812d, 0x16a1: 0x0961, 0x16a2: 0x814d, 0x16a3: 0x814d,
0x16a4: 0x816d, 0x16a5: 0x818d, 0x16a6: 0x81ad, 0x16a7: 0x81cd, 0x16a8: 0x81ed, 0x16a9: 0x820d,
0x16aa: 0x822d, 0x16ab: 0x824d, 0x16ac: 0x826d, 0x16ad: 0x828d, 0x16ae: 0x82ad, 0x16af: 0x82cd,
0x16b0: 0x82ed, 0x16b1: 0x830d, 0x16b2: 0x832d, 0x16b3: 0x834d, 0x16b4: 0x836d, 0x16b5: 0x838d,
0x16b6: 0x83ad, 0x16b7: 0x83cd, 0x16b8: 0x83ed, 0x16b9: 0x840d, 0x16ba: 0x842d, 0x16bb: 0x844d,
0x16bc: 0x81ed, 0x16bd: 0x846d, 0x16be: 0x848d, 0x16bf: 0x824d,
// Block 0x5b, offset 0x16c0
0x16c0: 0x84ad, 0x16c1: 0x84cd, 0x16c2: 0x84ed, 0x16c3: 0x850d, 0x16c4: 0x852d, 0x16c5: 0x854d,
0x16c6: 0x856d, 0x16c7: 0x858d, 0x16c8: 0x850d, 0x16c9: 0x85ad, 0x16ca: 0x850d, 0x16cb: 0x85cd,
0x16cc: 0x85cd, 0x16cd: 0x85ed, 0x16ce: 0x85ed, 0x16cf: 0x860d, 0x16d0: 0x854d, 0x16d1: 0x862d,
0x16d2: 0x864d, 0x16d3: 0x862d, 0x16d4: 0x866d, 0x16d5: 0x864d, 0x16d6: 0x868d, 0x16d7: 0x868d,
0x16d8: 0x86ad, 0x16d9: 0x86ad, 0x16da: 0x86cd, 0x16db: 0x86cd, 0x16dc: 0x864d, 0x16dd: 0x814d,
0x16de: 0x86ed, 0x16df: 0x870d, 0x16e0: 0x0040, 0x16e1: 0x872d, 0x16e2: 0x874d, 0x16e3: 0x876d,
0x16e4: 0x878d, 0x16e5: 0x876d, 0x16e6: 0x87ad, 0x16e7: 0x87cd, 0x16e8: 0x87ed, 0x16e9: 0x87ed,
0x16ea: 0x880d, 0x16eb: 0x880d, 0x16ec: 0x882d, 0x16ed: 0x882d, 0x16ee: 0x880d, 0x16ef: 0x880d,
0x16f0: 0x884d, 0x16f1: 0x886d, 0x16f2: 0x888d, 0x16f3: 0x88ad, 0x16f4: 0x88cd, 0x16f5: 0x88ed,
0x16f6: 0x88ed, 0x16f7: 0x88ed, 0x16f8: 0x890d, 0x16f9: 0x890d, 0x16fa: 0x890d, 0x16fb: 0x890d,
0x16fc: 0x87ed, 0x16fd: 0x87ed, 0x16fe: 0x87ed, 0x16ff: 0x0040,
// Block 0x5c, offset 0x1700
0x1700: 0x0040, 0x1701: 0x0040, 0x1702: 0x874d, 0x1703: 0x872d, 0x1704: 0x892d, 0x1705: 0x872d,
0x1706: 0x874d, 0x1707: 0x872d, 0x1708: 0x0040, 0x1709: 0x0040, 0x170a: 0x894d, 0x170b: 0x874d,
0x170c: 0x896d, 0x170d: 0x892d, 0x170e: 0x896d, 0x170f: 0x874d, 0x1710: 0x0040, 0x1711: 0x0040,
0x1712: 0x898d, 0x1713: 0x89ad, 0x1714: 0x88ad, 0x1715: 0x896d, 0x1716: 0x892d, 0x1717: 0x896d,
0x1718: 0x0040, 0x1719: 0x0040, 0x171a: 0x89cd, 0x171b: 0x89ed, 0x171c: 0x89cd, 0x171d: 0x0040,
0x171e: 0x0040, 0x171f: 0x0040, 0x1720: 0x21e9, 0x1721: 0x21f1, 0x1722: 0x21f9, 0x1723: 0x8a0e,
0x1724: 0x2201, 0x1725: 0x2209, 0x1726: 0x8a2d, 0x1727: 0x0040, 0x1728: 0x8a4d, 0x1729: 0x8a6d,
0x172a: 0x8a8d, 0x172b: 0x8a6d, 0x172c: 0x8aad, 0x172d: 0x8acd, 0x172e: 0x8aed, 0x172f: 0x0040,
0x1730: 0x0040, 0x1731: 0x0040, 0x1732: 0x0040, 0x1733: 0x0040, 0x1734: 0x0040, 0x1735: 0x0040,
0x1736: 0x0040, 0x1737: 0x0040, 0x1738: 0x0040, 0x1739: 0x0340, 0x173a: 0x0340, 0x173b: 0x0340,
0x173c: 0x0040, 0x173d: 0x0040, 0x173e: 0x0040, 0x173f: 0x0040,
// Block 0x5d, offset 0x1740
0x1740: 0x0008, 0x1741: 0x0008, 0x1742: 0x0008, 0x1743: 0x0008, 0x1744: 0x0008, 0x1745: 0x0008,
0x1746: 0x0008, 0x1747: 0x0008, 0x1748: 0x0008, 0x1749: 0x0008, 0x174a: 0x0008, 0x174b: 0x0008,
0x174c: 0x0008, 0x174d: 0x0008, 0x174e: 0x0008, 0x174f: 0x0008, 0x1750: 0x0008, 0x1751: 0x0008,
0x1752: 0x0008, 0x1753: 0x0008, 0x1754: 0x0008, 0x1755: 0x0008, 0x1756: 0x0008, 0x1757: 0x0008,
0x1758: 0x0008, 0x1759: 0x0008, 0x175a: 0x0008, 0x175b: 0x0008, 0x175c: 0x0008, 0x175d: 0x0008,
0x175e: 0x0008, 0x175f: 0x0008, 0x1760: 0x0008, 0x1761: 0x0008, 0x1762: 0x0008, 0x1763: 0x0008,
0x1764: 0x0040, 0x1765: 0x0040, 0x1766: 0x0040, 0x1767: 0x0040, 0x1768: 0x0040, 0x1769: 0x0040,
0x176a: 0x0040, 0x176b: 0x0040, 0x176c: 0x0040, 0x176d: 0x0040, 0x176e: 0x0040, 0x176f: 0x0018,
0x1770: 0x8b3d, 0x1771: 0x8b55, 0x1772: 0x8b6d, 0x1773: 0x8b55, 0x1774: 0x8b85, 0x1775: 0x8b55,
0x1776: 0x8b6d, 0x1777: 0x8b55, 0x1778: 0x8b3d, 0x1779: 0x8b9d, 0x177a: 0x8bb5, 0x177b: 0x0040,
0x177c: 0x8bcd, 0x177d: 0x8b9d, 0x177e: 0x8bb5, 0x177f: 0x8b9d,
// Block 0x5e, offset 0x1780
0x1780: 0xe13d, 0x1781: 0xe14d, 0x1782: 0xe15d, 0x1783: 0xe14d, 0x1784: 0xe17d, 0x1785: 0xe14d,
0x1786: 0xe15d, 0x1787: 0xe14d, 0x1788: 0xe13d, 0x1789: 0xe1cd, 0x178a: 0xe1dd, 0x178b: 0x0040,
0x178c: 0xe1fd, 0x178d: 0xe1cd, 0x178e: 0xe1dd, 0x178f: 0xe1cd, 0x1790: 0xe13d, 0x1791: 0xe14d,
0x1792: 0xe15d, 0x1793: 0x0040, 0x1794: 0xe17d, 0x1795: 0xe14d, 0x1796: 0x0040, 0x1797: 0x0008,
0x1798: 0x0008, 0x1799: 0x0008, 0x179a: 0x0008, 0x179b: 0x0008, 0x179c: 0x0008, 0x179d: 0x0008,
0x179e: 0x0008, 0x179f: 0x0008, 0x17a0: 0x0008, 0x17a1: 0x0008, 0x17a2: 0x0040, 0x17a3: 0x0008,
0x17a4: 0x0008, 0x17a5: 0x0008, 0x17a6: 0x0008, 0x17a7: 0x0008, 0x17a8: 0x0008, 0x17a9: 0x0008,
0x17aa: 0x0008, 0x17ab: 0x0008, 0x17ac: 0x0008, 0x17ad: 0x0008, 0x17ae: 0x0008, 0x17af: 0x0008,
0x17b0: 0x0008, 0x17b1: 0x0008, 0x17b2: 0x0040, 0x17b3: 0x0008, 0x17b4: 0x0008, 0x17b5: 0x0008,
0x17b6: 0x0008, 0x17b7: 0x0008, 0x17b8: 0x0008, 0x17b9: 0x0008, 0x17ba: 0x0040, 0x17bb: 0x0008,
0x17bc: 0x0008, 0x17bd: 0x0040, 0x17be: 0x0040, 0x17bf: 0x0040,
// Block 0x5f, offset 0x17c0
0x17c0: 0x0008, 0x17c1: 0x2211, 0x17c2: 0x2219, 0x17c3: 0x02e1, 0x17c4: 0x2221, 0x17c5: 0x2229,
0x17c6: 0x0040, 0x17c7: 0x2231, 0x17c8: 0x2239, 0x17c9: 0x2241, 0x17ca: 0x2249, 0x17cb: 0x2251,
0x17cc: 0x2259, 0x17cd: 0x2261, 0x17ce: 0x2269, 0x17cf: 0x2271, 0x17d0: 0x2279, 0x17d1: 0x2281,
0x17d2: 0x2289, 0x17d3: 0x2291, 0x17d4: 0x2299, 0x17d5: 0x0741, 0x17d6: 0x22a1, 0x17d7: 0x22a9,
0x17d8: 0x22b1, 0x17d9: 0x22b9, 0x17da: 0x22c1, 0x17db: 0x13d9, 0x17dc: 0x8be5, 0x17dd: 0x22c9,
0x17de: 0x22d1, 0x17df: 0x8c05, 0x17e0: 0x22d9, 0x17e1: 0x8c25, 0x17e2: 0x22e1, 0x17e3: 0x22e9,
0x17e4: 0x22f1, 0x17e5: 0x0751, 0x17e6: 0x22f9, 0x17e7: 0x8c45, 0x17e8: 0x0949, 0x17e9: 0x2301,
0x17ea: 0x2309, 0x17eb: 0x2311, 0x17ec: 0x2319, 0x17ed: 0x2321, 0x17ee: 0x2329, 0x17ef: 0x2331,
0x17f0: 0x2339, 0x17f1: 0x0040, 0x17f2: 0x2341, 0x17f3: 0x2349, 0x17f4: 0x2351, 0x17f5: 0x2359,
0x17f6: 0x2361, 0x17f7: 0x2369, 0x17f8: 0x2371, 0x17f9: 0x8c65, 0x17fa: 0x8c85, 0x17fb: 0x0040,
0x17fc: 0x0040, 0x17fd: 0x0040, 0x17fe: 0x0040, 0x17ff: 0x0040,
// Block 0x60, offset 0x1800
0x1800: 0x0a08, 0x1801: 0x0a08, 0x1802: 0x0a08, 0x1803: 0x0a08, 0x1804: 0x0a08, 0x1805: 0x0c08,
0x1806: 0x0808, 0x1807: 0x0c08, 0x1808: 0x0818, 0x1809: 0x0c08, 0x180a: 0x0c08, 0x180b: 0x0808,
0x180c: 0x0808, 0x180d: 0x0908, 0x180e: 0x0c08, 0x180f: 0x0c08, 0x1810: 0x0c08, 0x1811: 0x0c08,
0x1812: 0x0c08, 0x1813: 0x0a08, 0x1814: 0x0a08, 0x1815: 0x0a08, 0x1816: 0x0a08, 0x1817: 0x0908,
0x1818: 0x0a08, 0x1819: 0x0a08, 0x181a: 0x0a08, 0x181b: 0x0a08, 0x181c: 0x0a08, 0x181d: 0x0c08,
0x181e: 0x0a08, 0x181f: 0x0a08, 0x1820: 0x0a08, 0x1821: 0x0c08, 0x1822: 0x0808, 0x1823: 0x0808,
0x1824: 0x0c08, 0x1825: 0x3308, 0x1826: 0x3308, 0x1827: 0x0040, 0x1828: 0x0040, 0x1829: 0x0040,
0x182a: 0x0040, 0x182b: 0x0a18, 0x182c: 0x0a18, 0x182d: 0x0a18, 0x182e: 0x0a18, 0x182f: 0x0c18,
0x1830: 0x0818, 0x1831: 0x0818, 0x1832: 0x0818, 0x1833: 0x0818, 0x1834: 0x0818, 0x1835: 0x0818,
0x1836: 0x0818, 0x1837: 0x0040, 0x1838: 0x0040, 0x1839: 0x0040, 0x183a: 0x0040, 0x183b: 0x0040,
0x183c: 0x0040, 0x183d: 0x0040, 0x183e: 0x0040, 0x183f: 0x0040,
// Block 0x61, offset 0x1840
0x1840: 0x0a08, 0x1841: 0x0c08, 0x1842: 0x0a08, 0x1843: 0x0c08, 0x1844: 0x0c08, 0x1845: 0x0c08,
0x1846: 0x0a08, 0x1847: 0x0a08, 0x1848: 0x0a08, 0x1849: 0x0c08, 0x184a: 0x0a08, 0x184b: 0x0a08,
0x184c: 0x0c08, 0x184d: 0x0a08, 0x184e: 0x0c08, 0x184f: 0x0c08, 0x1850: 0x0a08, 0x1851: 0x0c08,
0x1852: 0x0040, 0x1853: 0x0040, 0x1854: 0x0040, 0x1855: 0x0040, 0x1856: 0x0040, 0x1857: 0x0040,
0x1858: 0x0040, 0x1859: 0x0818, 0x185a: 0x0818, 0x185b: 0x0818, 0x185c: 0x0818, 0x185d: 0x0040,
0x185e: 0x0040, 0x185f: 0x0040, 0x1860: 0x0040, 0x1861: 0x0040, 0x1862: 0x0040, 0x1863: 0x0040,
0x1864: 0x0040, 0x1865: 0x0040, 0x1866: 0x0040, 0x1867: 0x0040, 0x1868: 0x0040, 0x1869: 0x0c18,
0x186a: 0x0c18, 0x186b: 0x0c18, 0x186c: 0x0c18, 0x186d: 0x0a18, 0x186e: 0x0a18, 0x186f: 0x0818,
0x1870: 0x0040, 0x1871: 0x0040, 0x1872: 0x0040, 0x1873: 0x0040, 0x1874: 0x0040, 0x1875: 0x0040,
0x1876: 0x0040, 0x1877: 0x0040, 0x1878: 0x0040, 0x1879: 0x0040, 0x187a: 0x0040, 0x187b: 0x0040,
0x187c: 0x0040, 0x187d: 0x0040, 0x187e: 0x0040, 0x187f: 0x0040,
// Block 0x62, offset 0x1880
0x1880: 0x3308, 0x1881: 0x3308, 0x1882: 0x3008, 0x1883: 0x3008, 0x1884: 0x0040, 0x1885: 0x0008,
0x1886: 0x0008, 0x1887: 0x0008, 0x1888: 0x0008, 0x1889: 0x0008, 0x188a: 0x0008, 0x188b: 0x0008,
0x188c: 0x0008, 0x188d: 0x0040, 0x188e: 0x0040, 0x188f: 0x0008, 0x1890: 0x0008, 0x1891: 0x0040,
0x1892: 0x0040, 0x1893: 0x0008, 0x1894: 0x0008, 0x1895: 0x0008, 0x1896: 0x0008, 0x1897: 0x0008,
0x1898: 0x0008, 0x1899: 0x0008, 0x189a: 0x0008, 0x189b: 0x0008, 0x189c: 0x0008, 0x189d: 0x0008,
0x189e: 0x0008, 0x189f: 0x0008, 0x18a0: 0x0008, 0x18a1: 0x0008, 0x18a2: 0x0008, 0x18a3: 0x0008,
0x18a4: 0x0008, 0x18a5: 0x0008, 0x18a6: 0x0008, 0x18a7: 0x0008, 0x18a8: 0x0008, 0x18a9: 0x0040,
0x18aa: 0x0008, 0x18ab: 0x0008, 0x18ac: 0x0008, 0x18ad: 0x0008, 0x18ae: 0x0008, 0x18af: 0x0008,
0x18b0: 0x0008, 0x18b1: 0x0040, 0x18b2: 0x0008, 0x18b3: 0x0008, 0x18b4: 0x0040, 0x18b5: 0x0008,
0x18b6: 0x0008, 0x18b7: 0x0008, 0x18b8: 0x0008, 0x18b9: 0x0008, 0x18ba: 0x0040, 0x18bb: 0x3308,
0x18bc: 0x3308, 0x18bd: 0x0008, 0x18be: 0x3008, 0x18bf: 0x3008,
// Block 0x63, offset 0x18c0
0x18c0: 0x3308, 0x18c1: 0x3008, 0x18c2: 0x3008, 0x18c3: 0x3008, 0x18c4: 0x3008, 0x18c5: 0x0040,
0x18c6: 0x0040, 0x18c7: 0x3008, 0x18c8: 0x3008, 0x18c9: 0x0040, 0x18ca: 0x0040, 0x18cb: 0x3008,
0x18cc: 0x3008, 0x18cd: 0x3808, 0x18ce: 0x0040, 0x18cf: 0x0040, 0x18d0: 0x0008, 0x18d1: 0x0040,
0x18d2: 0x0040, 0x18d3: 0x0040, 0x18d4: 0x0040, 0x18d5: 0x0040, 0x18d6: 0x0040, 0x18d7: 0x3008,
0x18d8: 0x0040, 0x18d9: 0x0040, 0x18da: 0x0040, 0x18db: 0x0040, 0x18dc: 0x0040, 0x18dd: 0x0008,
0x18de: 0x0008, 0x18df: 0x0008, 0x18e0: 0x0008, 0x18e1: 0x0008, 0x18e2: 0x3008, 0x18e3: 0x3008,
0x18e4: 0x0040, 0x18e5: 0x0040, 0x18e6: 0x3308, 0x18e7: 0x3308, 0x18e8: 0x3308, 0x18e9: 0x3308,
0x18ea: 0x3308, 0x18eb: 0x3308, 0x18ec: 0x3308, 0x18ed: 0x0040, 0x18ee: 0x0040, 0x18ef: 0x0040,
0x18f0: 0x3308, 0x18f1: 0x3308, 0x18f2: 0x3308, 0x18f3: 0x3308, 0x18f4: 0x3308, 0x18f5: 0x0040,
0x18f6: 0x0040, 0x18f7: 0x0040, 0x18f8: 0x0040, 0x18f9: 0x0040, 0x18fa: 0x0040, 0x18fb: 0x0040,
0x18fc: 0x0040, 0x18fd: 0x0040, 0x18fe: 0x0040, 0x18ff: 0x0040,
// Block 0x64, offset 0x1900
0x1900: 0x0008, 0x1901: 0x0008, 0x1902: 0x0008, 0x1903: 0x0008, 0x1904: 0x0008, 0x1905: 0x0008,
0x1906: 0x0008, 0x1907: 0x0040, 0x1908: 0x0040, 0x1909: 0x0008, 0x190a: 0x0040, 0x190b: 0x0040,
0x190c: 0x0008, 0x190d: 0x0008, 0x190e: 0x0008, 0x190f: 0x0008, 0x1910: 0x0008, 0x1911: 0x0008,
0x1912: 0x0008, 0x1913: 0x0008, 0x1914: 0x0040, 0x1915: 0x0008, 0x1916: 0x0008, 0x1917: 0x0040,
0x1918: 0x0008, 0x1919: 0x0008, 0x191a: 0x0008, 0x191b: 0x0008, 0x191c: 0x0008, 0x191d: 0x0008,
0x191e: 0x0008, 0x191f: 0x0008, 0x1920: 0x0008, 0x1921: 0x0008, 0x1922: 0x0008, 0x1923: 0x0008,
0x1924: 0x0008, 0x1925: 0x0008, 0x1926: 0x0008, 0x1927: 0x0008, 0x1928: 0x0008, 0x1929: 0x0008,
0x192a: 0x0008, 0x192b: 0x0008, 0x192c: 0x0008, 0x192d: 0x0008, 0x192e: 0x0008, 0x192f: 0x0008,
0x1930: 0x3008, 0x1931: 0x3008, 0x1932: 0x3008, 0x1933: 0x3008, 0x1934: 0x3008, 0x1935: 0x3008,
0x1936: 0x0040, 0x1937: 0x3008, 0x1938: 0x3008, 0x1939: 0x0040, 0x193a: 0x0040, 0x193b: 0x3308,
0x193c: 0x3308, 0x193d: 0x3808, 0x193e: 0x3b08, 0x193f: 0x0008,
// Block 0x65, offset 0x1940
0x1940: 0x0019, 0x1941: 0x02e9, 0x1942: 0x03d9, 0x1943: 0x02f1, 0x1944: 0x02f9, 0x1945: 0x03f1,
0x1946: 0x0309, 0x1947: 0x00a9, 0x1948: 0x0311, 0x1949: 0x00b1, 0x194a: 0x0319, 0x194b: 0x0101,
0x194c: 0x0321, 0x194d: 0x0329, 0x194e: 0x0051, 0x194f: 0x0339, 0x1950: 0x0751, 0x1951: 0x00b9,
0x1952: 0x0089, 0x1953: 0x0341, 0x1954: 0x0349, 0x1955: 0x0391, 0x1956: 0x00c1, 0x1957: 0x0109,
0x1958: 0x00c9, 0x1959: 0x04b1, 0x195a: 0x0019, 0x195b: 0x02e9, 0x195c: 0x03d9, 0x195d: 0x02f1,
0x195e: 0x02f9, 0x195f: 0x03f1, 0x1960: 0x0309, 0x1961: 0x00a9, 0x1962: 0x0311, 0x1963: 0x00b1,
0x1964: 0x0319, 0x1965: 0x0101, 0x1966: 0x0321, 0x1967: 0x0329, 0x1968: 0x0051, 0x1969: 0x0339,
0x196a: 0x0751, 0x196b: 0x00b9, 0x196c: 0x0089, 0x196d: 0x0341, 0x196e: 0x0349, 0x196f: 0x0391,
0x1970: 0x00c1, 0x1971: 0x0109, 0x1972: 0x00c9, 0x1973: 0x04b1, 0x1974: 0x0019, 0x1975: 0x02e9,
0x1976: 0x03d9, 0x1977: 0x02f1, 0x1978: 0x02f9, 0x1979: 0x03f1, 0x197a: 0x0309, 0x197b: 0x00a9,
0x197c: 0x0311, 0x197d: 0x00b1, 0x197e: 0x0319, 0x197f: 0x0101,
// Block 0x66, offset 0x1980
0x1980: 0x0321, 0x1981: 0x0329, 0x1982: 0x0051, 0x1983: 0x0339, 0x1984: 0x0751, 0x1985: 0x00b9,
0x1986: 0x0089, 0x1987: 0x0341, 0x1988: 0x0349, 0x1989: 0x0391, 0x198a: 0x00c1, 0x198b: 0x0109,
0x198c: 0x00c9, 0x198d: 0x04b1, 0x198e: 0x0019, 0x198f: 0x02e9, 0x1990: 0x03d9, 0x1991: 0x02f1,
0x1992: 0x02f9, 0x1993: 0x03f1, 0x1994: 0x0309, 0x1995: 0x0040, 0x1996: 0x0311, 0x1997: 0x00b1,
0x1998: 0x0319, 0x1999: 0x0101, 0x199a: 0x0321, 0x199b: 0x0329, 0x199c: 0x0051, 0x199d: 0x0339,
0x199e: 0x0751, 0x199f: 0x00b9, 0x19a0: 0x0089, 0x19a1: 0x0341, 0x19a2: 0x0349, 0x19a3: 0x0391,
0x19a4: 0x00c1, 0x19a5: 0x0109, 0x19a6: 0x00c9, 0x19a7: 0x04b1, 0x19a8: 0x0019, 0x19a9: 0x02e9,
0x19aa: 0x03d9, 0x19ab: 0x02f1, 0x19ac: 0x02f9, 0x19ad: 0x03f1, 0x19ae: 0x0309, 0x19af: 0x00a9,
0x19b0: 0x0311, 0x19b1: 0x00b1, 0x19b2: 0x0319, 0x19b3: 0x0101, 0x19b4: 0x0321, 0x19b5: 0x0329,
0x19b6: 0x0051, 0x19b7: 0x0339, 0x19b8: 0x0751, 0x19b9: 0x00b9, 0x19ba: 0x0089, 0x19bb: 0x0341,
0x19bc: 0x0349, 0x19bd: 0x0391, 0x19be: 0x00c1, 0x19bf: 0x0109,
// Block 0x67, offset 0x19c0
0x19c0: 0x00c9, 0x19c1: 0x04b1, 0x19c2: 0x0019, 0x19c3: 0x02e9, 0x19c4: 0x03d9, 0x19c5: 0x02f1,
0x19c6: 0x02f9, 0x19c7: 0x03f1, 0x19c8: 0x0309, 0x19c9: 0x00a9, 0x19ca: 0x0311, 0x19cb: 0x00b1,
0x19cc: 0x0319, 0x19cd: 0x0101, 0x19ce: 0x0321, 0x19cf: 0x0329, 0x19d0: 0x0051, 0x19d1: 0x0339,
0x19d2: 0x0751, 0x19d3: 0x00b9, 0x19d4: 0x0089, 0x19d5: 0x0341, 0x19d6: 0x0349, 0x19d7: 0x0391,
0x19d8: 0x00c1, 0x19d9: 0x0109, 0x19da: 0x00c9, 0x19db: 0x04b1, 0x19dc: 0x0019, 0x19dd: 0x0040,
0x19de: 0x03d9, 0x19df: 0x02f1, 0x19e0: 0x0040, 0x19e1: 0x0040, 0x19e2: 0x0309, 0x19e3: 0x0040,
0x19e4: 0x0040, 0x19e5: 0x00b1, 0x19e6: 0x0319, 0x19e7: 0x0040, 0x19e8: 0x0040, 0x19e9: 0x0329,
0x19ea: 0x0051, 0x19eb: 0x0339, 0x19ec: 0x0751, 0x19ed: 0x0040, 0x19ee: 0x0089, 0x19ef: 0x0341,
0x19f0: 0x0349, 0x19f1: 0x0391, 0x19f2: 0x00c1, 0x19f3: 0x0109, 0x19f4: 0x00c9, 0x19f5: 0x04b1,
0x19f6: 0x0019, 0x19f7: 0x02e9, 0x19f8: 0x03d9, 0x19f9: 0x02f1, 0x19fa: 0x0040, 0x19fb: 0x03f1,
0x19fc: 0x0040, 0x19fd: 0x00a9, 0x19fe: 0x0311, 0x19ff: 0x00b1,
// Block 0x68, offset 0x1a00
0x1a00: 0x0319, 0x1a01: 0x0101, 0x1a02: 0x0321, 0x1a03: 0x0329, 0x1a04: 0x0040, 0x1a05: 0x0339,
0x1a06: 0x0751, 0x1a07: 0x00b9, 0x1a08: 0x0089, 0x1a09: 0x0341, 0x1a0a: 0x0349, 0x1a0b: 0x0391,
0x1a0c: 0x00c1, 0x1a0d: 0x0109, 0x1a0e: 0x00c9, 0x1a0f: 0x04b1, 0x1a10: 0x0019, 0x1a11: 0x02e9,
0x1a12: 0x03d9, 0x1a13: 0x02f1, 0x1a14: 0x02f9, 0x1a15: 0x03f1, 0x1a16: 0x0309, 0x1a17: 0x00a9,
0x1a18: 0x0311, 0x1a19: 0x00b1, 0x1a1a: 0x0319, 0x1a1b: 0x0101, 0x1a1c: 0x0321, 0x1a1d: 0x0329,
0x1a1e: 0x0051, 0x1a1f: 0x0339, 0x1a20: 0x0751, 0x1a21: 0x00b9, 0x1a22: 0x0089, 0x1a23: 0x0341,
0x1a24: 0x0349, 0x1a25: 0x0391, 0x1a26: 0x00c1, 0x1a27: 0x0109, 0x1a28: 0x00c9, 0x1a29: 0x04b1,
0x1a2a: 0x0019, 0x1a2b: 0x02e9, 0x1a2c: 0x03d9, 0x1a2d: 0x02f1, 0x1a2e: 0x02f9, 0x1a2f: 0x03f1,
0x1a30: 0x0309, 0x1a31: 0x00a9, 0x1a32: 0x0311, 0x1a33: 0x00b1, 0x1a34: 0x0319, 0x1a35: 0x0101,
0x1a36: 0x0321, 0x1a37: 0x0329, 0x1a38: 0x0051, 0x1a39: 0x0339, 0x1a3a: 0x0751, 0x1a3b: 0x00b9,
0x1a3c: 0x0089, 0x1a3d: 0x0341, 0x1a3e: 0x0349, 0x1a3f: 0x0391,
// Block 0x69, offset 0x1a40
0x1a40: 0x00c1, 0x1a41: 0x0109, 0x1a42: 0x00c9, 0x1a43: 0x04b1, 0x1a44: 0x0019, 0x1a45: 0x02e9,
0x1a46: 0x0040, 0x1a47: 0x02f1, 0x1a48: 0x02f9, 0x1a49: 0x03f1, 0x1a4a: 0x0309, 0x1a4b: 0x0040,
0x1a4c: 0x0040, 0x1a4d: 0x00b1, 0x1a4e: 0x0319, 0x1a4f: 0x0101, 0x1a50: 0x0321, 0x1a51: 0x0329,
0x1a52: 0x0051, 0x1a53: 0x0339, 0x1a54: 0x0751, 0x1a55: 0x0040, 0x1a56: 0x0089, 0x1a57: 0x0341,
0x1a58: 0x0349, 0x1a59: 0x0391, 0x1a5a: 0x00c1, 0x1a5b: 0x0109, 0x1a5c: 0x00c9, 0x1a5d: 0x0040,
0x1a5e: 0x0019, 0x1a5f: 0x02e9, 0x1a60: 0x03d9, 0x1a61: 0x02f1, 0x1a62: 0x02f9, 0x1a63: 0x03f1,
0x1a64: 0x0309, 0x1a65: 0x00a9, 0x1a66: 0x0311, 0x1a67: 0x00b1, 0x1a68: 0x0319, 0x1a69: 0x0101,
0x1a6a: 0x0321, 0x1a6b: 0x0329, 0x1a6c: 0x0051, 0x1a6d: 0x0339, 0x1a6e: 0x0751, 0x1a6f: 0x00b9,
0x1a70: 0x0089, 0x1a71: 0x0341, 0x1a72: 0x0349, 0x1a73: 0x0391, 0x1a74: 0x00c1, 0x1a75: 0x0109,
0x1a76: 0x00c9, 0x1a77: 0x04b1, 0x1a78: 0x0019, 0x1a79: 0x02e9, 0x1a7a: 0x0040, 0x1a7b: 0x02f1,
0x1a7c: 0x02f9, 0x1a7d: 0x03f1, 0x1a7e: 0x0309, 0x1a7f: 0x0040,
// Block 0x6a, offset 0x1a80
0x1a80: 0x0311, 0x1a81: 0x00b1, 0x1a82: 0x0319, 0x1a83: 0x0101, 0x1a84: 0x0321, 0x1a85: 0x0040,
0x1a86: 0x0051, 0x1a87: 0x0040, 0x1a88: 0x0040, 0x1a89: 0x0040, 0x1a8a: 0x0089, 0x1a8b: 0x0341,
0x1a8c: 0x0349, 0x1a8d: 0x0391, 0x1a8e: 0x00c1, 0x1a8f: 0x0109, 0x1a90: 0x00c9, 0x1a91: 0x0040,
0x1a92: 0x0019, 0x1a93: 0x02e9, 0x1a94: 0x03d9, 0x1a95: 0x02f1, 0x1a96: 0x02f9, 0x1a97: 0x03f1,
0x1a98: 0x0309, 0x1a99: 0x00a9, 0x1a9a: 0x0311, 0x1a9b: 0x00b1, 0x1a9c: 0x0319, 0x1a9d: 0x0101,
0x1a9e: 0x0321, 0x1a9f: 0x0329, 0x1aa0: 0x0051, 0x1aa1: 0x0339, 0x1aa2: 0x0751, 0x1aa3: 0x00b9,
0x1aa4: 0x0089, 0x1aa5: 0x0341, 0x1aa6: 0x0349, 0x1aa7: 0x0391, 0x1aa8: 0x00c1, 0x1aa9: 0x0109,
0x1aaa: 0x00c9, 0x1aab: 0x04b1, 0x1aac: 0x0019, 0x1aad: 0x02e9, 0x1aae: 0x03d9, 0x1aaf: 0x02f1,
0x1ab0: 0x02f9, 0x1ab1: 0x03f1, 0x1ab2: 0x0309, 0x1ab3: 0x00a9, 0x1ab4: 0x0311, 0x1ab5: 0x00b1,
0x1ab6: 0x0319, 0x1ab7: 0x0101, 0x1ab8: 0x0321, 0x1ab9: 0x0329, 0x1aba: 0x0051, 0x1abb: 0x0339,
0x1abc: 0x0751, 0x1abd: 0x00b9, 0x1abe: 0x0089, 0x1abf: 0x0341,
// Block 0x6b, offset 0x1ac0
0x1ac0: 0x0349, 0x1ac1: 0x0391, 0x1ac2: 0x00c1, 0x1ac3: 0x0109, 0x1ac4: 0x00c9, 0x1ac5: 0x04b1,
0x1ac6: 0x0019, 0x1ac7: 0x02e9, 0x1ac8: 0x03d9, 0x1ac9: 0x02f1, 0x1aca: 0x02f9, 0x1acb: 0x03f1,
0x1acc: 0x0309, 0x1acd: 0x00a9, 0x1ace: 0x0311, 0x1acf: 0x00b1, 0x1ad0: 0x0319, 0x1ad1: 0x0101,
0x1ad2: 0x0321, 0x1ad3: 0x0329, 0x1ad4: 0x0051, 0x1ad5: 0x0339, 0x1ad6: 0x0751, 0x1ad7: 0x00b9,
0x1ad8: 0x0089, 0x1ad9: 0x0341, 0x1ada: 0x0349, 0x1adb: 0x0391, 0x1adc: 0x00c1, 0x1add: 0x0109,
0x1ade: 0x00c9, 0x1adf: 0x04b1, 0x1ae0: 0x0019, 0x1ae1: 0x02e9, 0x1ae2: 0x03d9, 0x1ae3: 0x02f1,
0x1ae4: 0x02f9, 0x1ae5: 0x03f1, 0x1ae6: 0x0309, 0x1ae7: 0x00a9, 0x1ae8: 0x0311, 0x1ae9: 0x00b1,
0x1aea: 0x0319, 0x1aeb: 0x0101, 0x1aec: 0x0321, 0x1aed: 0x0329, 0x1aee: 0x0051, 0x1aef: 0x0339,
0x1af0: 0x0751, 0x1af1: 0x00b9, 0x1af2: 0x0089, 0x1af3: 0x0341, 0x1af4: 0x0349, 0x1af5: 0x0391,
0x1af6: 0x00c1, 0x1af7: 0x0109, 0x1af8: 0x00c9, 0x1af9: 0x04b1, 0x1afa: 0x0019, 0x1afb: 0x02e9,
0x1afc: 0x03d9, 0x1afd: 0x02f1, 0x1afe: 0x02f9, 0x1aff: 0x03f1,
// Block 0x6c, offset 0x1b00
0x1b00: 0x0309, 0x1b01: 0x00a9, 0x1b02: 0x0311, 0x1b03: 0x00b1, 0x1b04: 0x0319, 0x1b05: 0x0101,
0x1b06: 0x0321, 0x1b07: 0x0329, 0x1b08: 0x0051, 0x1b09: 0x0339, 0x1b0a: 0x0751, 0x1b0b: 0x00b9,
0x1b0c: 0x0089, 0x1b0d: 0x0341, 0x1b0e: 0x0349, 0x1b0f: 0x0391, 0x1b10: 0x00c1, 0x1b11: 0x0109,
0x1b12: 0x00c9, 0x1b13: 0x04b1, 0x1b14: 0x0019, 0x1b15: 0x02e9, 0x1b16: 0x03d9, 0x1b17: 0x02f1,
0x1b18: 0x02f9, 0x1b19: 0x03f1, 0x1b1a: 0x0309, 0x1b1b: 0x00a9, 0x1b1c: 0x0311, 0x1b1d: 0x00b1,
0x1b1e: 0x0319, 0x1b1f: 0x0101, 0x1b20: 0x0321, 0x1b21: 0x0329, 0x1b22: 0x0051, 0x1b23: 0x0339,
0x1b24: 0x0751, 0x1b25: 0x00b9, 0x1b26: 0x0089, 0x1b27: 0x0341, 0x1b28: 0x0349, 0x1b29: 0x0391,
0x1b2a: 0x00c1, 0x1b2b: 0x0109, 0x1b2c: 0x00c9, 0x1b2d: 0x04b1, 0x1b2e: 0x0019, 0x1b2f: 0x02e9,
0x1b30: 0x03d9, 0x1b31: 0x02f1, 0x1b32: 0x02f9, 0x1b33: 0x03f1, 0x1b34: 0x0309, 0x1b35: 0x00a9,
0x1b36: 0x0311, 0x1b37: 0x00b1, 0x1b38: 0x0319, 0x1b39: 0x0101, 0x1b3a: 0x0321, 0x1b3b: 0x0329,
0x1b3c: 0x0051, 0x1b3d: 0x0339, 0x1b3e: 0x0751, 0x1b3f: 0x00b9,
// Block 0x6d, offset 0x1b40
0x1b40: 0x0089, 0x1b41: 0x0341, 0x1b42: 0x0349, 0x1b43: 0x0391, 0x1b44: 0x00c1, 0x1b45: 0x0109,
0x1b46: 0x00c9, 0x1b47: 0x04b1, 0x1b48: 0x0019, 0x1b49: 0x02e9, 0x1b4a: 0x03d9, 0x1b4b: 0x02f1,
0x1b4c: 0x02f9, 0x1b4d: 0x03f1, 0x1b4e: 0x0309, 0x1b4f: 0x00a9, 0x1b50: 0x0311, 0x1b51: 0x00b1,
0x1b52: 0x0319, 0x1b53: 0x0101, 0x1b54: 0x0321, 0x1b55: 0x0329, 0x1b56: 0x0051, 0x1b57: 0x0339,
0x1b58: 0x0751, 0x1b59: 0x00b9, 0x1b5a: 0x0089, 0x1b5b: 0x0341, 0x1b5c: 0x0349, 0x1b5d: 0x0391,
0x1b5e: 0x00c1, 0x1b5f: 0x0109, 0x1b60: 0x00c9, 0x1b61: 0x04b1, 0x1b62: 0x0019, 0x1b63: 0x02e9,
0x1b64: 0x03d9, 0x1b65: 0x02f1, 0x1b66: 0x02f9, 0x1b67: 0x03f1, 0x1b68: 0x0309, 0x1b69: 0x00a9,
0x1b6a: 0x0311, 0x1b6b: 0x00b1, 0x1b6c: 0x0319, 0x1b6d: 0x0101, 0x1b6e: 0x0321, 0x1b6f: 0x0329,
0x1b70: 0x0051, 0x1b71: 0x0339, 0x1b72: 0x0751, 0x1b73: 0x00b9, 0x1b74: 0x0089, 0x1b75: 0x0341,
0x1b76: 0x0349, 0x1b77: 0x0391, 0x1b78: 0x00c1, 0x1b79: 0x0109, 0x1b7a: 0x00c9, 0x1b7b: 0x04b1,
0x1b7c: 0x0019, 0x1b7d: 0x02e9, 0x1b7e: 0x03d9, 0x1b7f: 0x02f1,
// Block 0x6e, offset 0x1b80
0x1b80: 0x02f9, 0x1b81: 0x03f1, 0x1b82: 0x0309, 0x1b83: 0x00a9, 0x1b84: 0x0311, 0x1b85: 0x00b1,
0x1b86: 0x0319, 0x1b87: 0x0101, 0x1b88: 0x0321, 0x1b89: 0x0329, 0x1b8a: 0x0051, 0x1b8b: 0x0339,
0x1b8c: 0x0751, 0x1b8d: 0x00b9, 0x1b8e: 0x0089, 0x1b8f: 0x0341, 0x1b90: 0x0349, 0x1b91: 0x0391,
0x1b92: 0x00c1, 0x1b93: 0x0109, 0x1b94: 0x00c9, 0x1b95: 0x04b1, 0x1b96: 0x0019, 0x1b97: 0x02e9,
0x1b98: 0x03d9, 0x1b99: 0x02f1, 0x1b9a: 0x02f9, 0x1b9b: 0x03f1, 0x1b9c: 0x0309, 0x1b9d: 0x00a9,
0x1b9e: 0x0311, 0x1b9f: 0x00b1, 0x1ba0: 0x0319, 0x1ba1: 0x0101, 0x1ba2: 0x0321, 0x1ba3: 0x0329,
0x1ba4: 0x0051, 0x1ba5: 0x0339, 0x1ba6: 0x0751, 0x1ba7: 0x00b9, 0x1ba8: 0x0089, 0x1ba9: 0x0341,
0x1baa: 0x0349, 0x1bab: 0x0391, 0x1bac: 0x00c1, 0x1bad: 0x0109, 0x1bae: 0x00c9, 0x1baf: 0x04b1,
0x1bb0: 0x0019, 0x1bb1: 0x02e9, 0x1bb2: 0x03d9, 0x1bb3: 0x02f1, 0x1bb4: 0x02f9, 0x1bb5: 0x03f1,
0x1bb6: 0x0309, 0x1bb7: 0x00a9, 0x1bb8: 0x0311, 0x1bb9: 0x00b1, 0x1bba: 0x0319, 0x1bbb: 0x0101,
0x1bbc: 0x0321, 0x1bbd: 0x0329, 0x1bbe: 0x0051, 0x1bbf: 0x0339,
// Block 0x6f, offset 0x1bc0
0x1bc0: 0x0751, 0x1bc1: 0x00b9, 0x1bc2: 0x0089, 0x1bc3: 0x0341, 0x1bc4: 0x0349, 0x1bc5: 0x0391,
0x1bc6: 0x00c1, 0x1bc7: 0x0109, 0x1bc8: 0x00c9, 0x1bc9: 0x04b1, 0x1bca: 0x0019, 0x1bcb: 0x02e9,
0x1bcc: 0x03d9, 0x1bcd: 0x02f1, 0x1bce: 0x02f9, 0x1bcf: 0x03f1, 0x1bd0: 0x0309, 0x1bd1: 0x00a9,
0x1bd2: 0x0311, 0x1bd3: 0x00b1, 0x1bd4: 0x0319, 0x1bd5: 0x0101, 0x1bd6: 0x0321, 0x1bd7: 0x0329,
0x1bd8: 0x0051, 0x1bd9: 0x0339, 0x1bda: 0x0751, 0x1bdb: 0x00b9, 0x1bdc: 0x0089, 0x1bdd: 0x0341,
0x1bde: 0x0349, 0x1bdf: 0x0391, 0x1be0: 0x00c1, 0x1be1: 0x0109, 0x1be2: 0x00c9, 0x1be3: 0x04b1,
0x1be4: 0x23e1, 0x1be5: 0x23e9, 0x1be6: 0x0040, 0x1be7: 0x0040, 0x1be8: 0x23f1, 0x1be9: 0x0399,
0x1bea: 0x03a1, 0x1beb: 0x03a9, 0x1bec: 0x23f9, 0x1bed: 0x2401, 0x1bee: 0x2409, 0x1bef: 0x04d1,
0x1bf0: 0x05f9, 0x1bf1: 0x2411, 0x1bf2: 0x2419, 0x1bf3: 0x2421, 0x1bf4: 0x2429, 0x1bf5: 0x2431,
0x1bf6: 0x2439, 0x1bf7: 0x0799, 0x1bf8: 0x03c1, 0x1bf9: 0x04d1, 0x1bfa: 0x2441, 0x1bfb: 0x2449,
0x1bfc: 0x2451, 0x1bfd: 0x03b1, 0x1bfe: 0x03b9, 0x1bff: 0x2459,
// Block 0x70, offset 0x1c00
0x1c00: 0x0769, 0x1c01: 0x2461, 0x1c02: 0x23f1, 0x1c03: 0x0399, 0x1c04: 0x03a1, 0x1c05: 0x03a9,
0x1c06: 0x23f9, 0x1c07: 0x2401, 0x1c08: 0x2409, 0x1c09: 0x04d1, 0x1c0a: 0x05f9, 0x1c0b: 0x2411,
0x1c0c: 0x2419, 0x1c0d: 0x2421, 0x1c0e: 0x2429, 0x1c0f: 0x2431, 0x1c10: 0x2439, 0x1c11: 0x0799,
0x1c12: 0x03c1, 0x1c13: 0x2441, 0x1c14: 0x2441, 0x1c15: 0x2449, 0x1c16: 0x2451, 0x1c17: 0x03b1,
0x1c18: 0x03b9, 0x1c19: 0x2459, 0x1c1a: 0x0769, 0x1c1b: 0x2469, 0x1c1c: 0x23f9, 0x1c1d: 0x04d1,
0x1c1e: 0x2411, 0x1c1f: 0x03b1, 0x1c20: 0x03c1, 0x1c21: 0x0799, 0x1c22: 0x23f1, 0x1c23: 0x0399,
0x1c24: 0x03a1, 0x1c25: 0x03a9, 0x1c26: 0x23f9, 0x1c27: 0x2401, 0x1c28: 0x2409, 0x1c29: 0x04d1,
0x1c2a: 0x05f9, 0x1c2b: 0x2411, 0x1c2c: 0x2419, 0x1c2d: 0x2421, 0x1c2e: 0x2429, 0x1c2f: 0x2431,
0x1c30: 0x2439, 0x1c31: 0x0799, 0x1c32: 0x03c1, 0x1c33: 0x04d1, 0x1c34: 0x2441, 0x1c35: 0x2449,
0x1c36: 0x2451, 0x1c37: 0x03b1, 0x1c38: 0x03b9, 0x1c39: 0x2459, 0x1c3a: 0x0769, 0x1c3b: 0x2461,
0x1c3c: 0x23f1, 0x1c3d: 0x0399, 0x1c3e: 0x03a1, 0x1c3f: 0x03a9,
// Block 0x71, offset 0x1c40
0x1c40: 0x23f9, 0x1c41: 0x2401, 0x1c42: 0x2409, 0x1c43: 0x04d1, 0x1c44: 0x05f9, 0x1c45: 0x2411,
0x1c46: 0x2419, 0x1c47: 0x2421, 0x1c48: 0x2429, 0x1c49: 0x2431, 0x1c4a: 0x2439, 0x1c4b: 0x0799,
0x1c4c: 0x03c1, 0x1c4d: 0x2441, 0x1c4e: 0x2441, 0x1c4f: 0x2449, 0x1c50: 0x2451, 0x1c51: 0x03b1,
0x1c52: 0x03b9, 0x1c53: 0x2459, 0x1c54: 0x0769, 0x1c55: 0x2469, 0x1c56: 0x23f9, 0x1c57: 0x04d1,
0x1c58: 0x2411, 0x1c59: 0x03b1, 0x1c5a: 0x03c1, 0x1c5b: 0x0799, 0x1c5c: 0x23f1, 0x1c5d: 0x0399,
0x1c5e: 0x03a1, 0x1c5f: 0x03a9, 0x1c60: 0x23f9, 0x1c61: 0x2401, 0x1c62: 0x2409, 0x1c63: 0x04d1,
0x1c64: 0x05f9, 0x1c65: 0x2411, 0x1c66: 0x2419, 0x1c67: 0x2421, 0x1c68: 0x2429, 0x1c69: 0x2431,
0x1c6a: 0x2439, 0x1c6b: 0x0799, 0x1c6c: 0x03c1, 0x1c6d: 0x04d1, 0x1c6e: 0x2441, 0x1c6f: 0x2449,
0x1c70: 0x2451, 0x1c71: 0x03b1, 0x1c72: 0x03b9, 0x1c73: 0x2459, 0x1c74: 0x0769, 0x1c75: 0x2461,
0x1c76: 0x23f1, 0x1c77: 0x0399, 0x1c78: 0x03a1, 0x1c79: 0x03a9, 0x1c7a: 0x23f9, 0x1c7b: 0x2401,
0x1c7c: 0x2409, 0x1c7d: 0x04d1, 0x1c7e: 0x05f9, 0x1c7f: 0x2411,
// Block 0x72, offset 0x1c80
0x1c80: 0x2419, 0x1c81: 0x2421, 0x1c82: 0x2429, 0x1c83: 0x2431, 0x1c84: 0x2439, 0x1c85: 0x0799,
0x1c86: 0x03c1, 0x1c87: 0x2441, 0x1c88: 0x2441, 0x1c89: 0x2449, 0x1c8a: 0x2451, 0x1c8b: 0x03b1,
0x1c8c: 0x03b9, 0x1c8d: 0x2459, 0x1c8e: 0x0769, 0x1c8f: 0x2469, 0x1c90: 0x23f9, 0x1c91: 0x04d1,
0x1c92: 0x2411, 0x1c93: 0x03b1, 0x1c94: 0x03c1, 0x1c95: 0x0799, 0x1c96: 0x23f1, 0x1c97: 0x0399,
0x1c98: 0x03a1, 0x1c99: 0x03a9, 0x1c9a: 0x23f9, 0x1c9b: 0x2401, 0x1c9c: 0x2409, 0x1c9d: 0x04d1,
0x1c9e: 0x05f9, 0x1c9f: 0x2411, 0x1ca0: 0x2419, 0x1ca1: 0x2421, 0x1ca2: 0x2429, 0x1ca3: 0x2431,
0x1ca4: 0x2439, 0x1ca5: 0x0799, 0x1ca6: 0x03c1, 0x1ca7: 0x04d1, 0x1ca8: 0x2441, 0x1ca9: 0x2449,
0x1caa: 0x2451, 0x1cab: 0x03b1, 0x1cac: 0x03b9, 0x1cad: 0x2459, 0x1cae: 0x0769, 0x1caf: 0x2461,
0x1cb0: 0x23f1, 0x1cb1: 0x0399, 0x1cb2: 0x03a1, 0x1cb3: 0x03a9, 0x1cb4: 0x23f9, 0x1cb5: 0x2401,
0x1cb6: 0x2409, 0x1cb7: 0x04d1, 0x1cb8: 0x05f9, 0x1cb9: 0x2411, 0x1cba: 0x2419, 0x1cbb: 0x2421,
0x1cbc: 0x2429, 0x1cbd: 0x2431, 0x1cbe: 0x2439, 0x1cbf: 0x0799,
// Block 0x73, offset 0x1cc0
0x1cc0: 0x03c1, 0x1cc1: 0x2441, 0x1cc2: 0x2441, 0x1cc3: 0x2449, 0x1cc4: 0x2451, 0x1cc5: 0x03b1,
0x1cc6: 0x03b9, 0x1cc7: 0x2459, 0x1cc8: 0x0769, 0x1cc9: 0x2469, 0x1cca: 0x23f9, 0x1ccb: 0x04d1,
0x1ccc: 0x2411, 0x1ccd: 0x03b1, 0x1cce: 0x03c1, 0x1ccf: 0x0799, 0x1cd0: 0x23f1, 0x1cd1: 0x0399,
0x1cd2: 0x03a1, 0x1cd3: 0x03a9, 0x1cd4: 0x23f9, 0x1cd5: 0x2401, 0x1cd6: 0x2409, 0x1cd7: 0x04d1,
0x1cd8: 0x05f9, 0x1cd9: 0x2411, 0x1cda: 0x2419, 0x1cdb: 0x2421, 0x1cdc: 0x2429, 0x1cdd: 0x2431,
0x1cde: 0x2439, 0x1cdf: 0x0799, 0x1ce0: 0x03c1, 0x1ce1: 0x04d1, 0x1ce2: 0x2441, 0x1ce3: 0x2449,
0x1ce4: 0x2451, 0x1ce5: 0x03b1, 0x1ce6: 0x03b9, 0x1ce7: 0x2459, 0x1ce8: 0x0769, 0x1ce9: 0x2461,
0x1cea: 0x23f1, 0x1ceb: 0x0399, 0x1cec: 0x03a1, 0x1ced: 0x03a9, 0x1cee: 0x23f9, 0x1cef: 0x2401,
0x1cf0: 0x2409, 0x1cf1: 0x04d1, 0x1cf2: 0x05f9, 0x1cf3: 0x2411, 0x1cf4: 0x2419, 0x1cf5: 0x2421,
0x1cf6: 0x2429, 0x1cf7: 0x2431, 0x1cf8: 0x2439, 0x1cf9: 0x0799, 0x1cfa: 0x03c1, 0x1cfb: 0x2441,
0x1cfc: 0x2441, 0x1cfd: 0x2449, 0x1cfe: 0x2451, 0x1cff: 0x03b1,
// Block 0x74, offset 0x1d00
0x1d00: 0x03b9, 0x1d01: 0x2459, 0x1d02: 0x0769, 0x1d03: 0x2469, 0x1d04: 0x23f9, 0x1d05: 0x04d1,
0x1d06: 0x2411, 0x1d07: 0x03b1, 0x1d08: 0x03c1, 0x1d09: 0x0799, 0x1d0a: 0x2471, 0x1d0b: 0x2471,
0x1d0c: 0x0040, 0x1d0d: 0x0040, 0x1d0e: 0x06e1, 0x1d0f: 0x0049, 0x1d10: 0x0029, 0x1d11: 0x0031,
0x1d12: 0x06e9, 0x1d13: 0x06f1, 0x1d14: 0x06f9, 0x1d15: 0x0701, 0x1d16: 0x0709, 0x1d17: 0x0711,
0x1d18: 0x06e1, 0x1d19: 0x0049, 0x1d1a: 0x0029, 0x1d1b: 0x0031, 0x1d1c: 0x06e9, 0x1d1d: 0x06f1,
0x1d1e: 0x06f9, 0x1d1f: 0x0701, 0x1d20: 0x0709, 0x1d21: 0x0711, 0x1d22: 0x06e1, 0x1d23: 0x0049,
0x1d24: 0x0029, 0x1d25: 0x0031, 0x1d26: 0x06e9, 0x1d27: 0x06f1, 0x1d28: 0x06f9, 0x1d29: 0x0701,
0x1d2a: 0x0709, 0x1d2b: 0x0711, 0x1d2c: 0x06e1, 0x1d2d: 0x0049, 0x1d2e: 0x0029, 0x1d2f: 0x0031,
0x1d30: 0x06e9, 0x1d31: 0x06f1, 0x1d32: 0x06f9, 0x1d33: 0x0701, 0x1d34: 0x0709, 0x1d35: 0x0711,
0x1d36: 0x06e1, 0x1d37: 0x0049, 0x1d38: 0x0029, 0x1d39: 0x0031, 0x1d3a: 0x06e9, 0x1d3b: 0x06f1,
0x1d3c: 0x06f9, 0x1d3d: 0x0701, 0x1d3e: 0x0709, 0x1d3f: 0x0711,
// Block 0x75, offset 0x1d40
0x1d40: 0x3308, 0x1d41: 0x3308, 0x1d42: 0x3308, 0x1d43: 0x3308, 0x1d44: 0x3308, 0x1d45: 0x3308,
0x1d46: 0x3308, 0x1d47: 0x0040, 0x1d48: 0x3308, 0x1d49: 0x3308, 0x1d4a: 0x3308, 0x1d4b: 0x3308,
0x1d4c: 0x3308, 0x1d4d: 0x3308, 0x1d4e: 0x3308, 0x1d4f: 0x3308, 0x1d50: 0x3308, 0x1d51: 0x3308,
0x1d52: 0x3308, 0x1d53: 0x3308, 0x1d54: 0x3308, 0x1d55: 0x3308, 0x1d56: 0x3308, 0x1d57: 0x3308,
0x1d58: 0x3308, 0x1d59: 0x0040, 0x1d5a: 0x0040, 0x1d5b: 0x3308, 0x1d5c: 0x3308, 0x1d5d: 0x3308,
0x1d5e: 0x3308, 0x1d5f: 0x3308, 0x1d60: 0x3308, 0x1d61: 0x3308, 0x1d62: 0x0040, 0x1d63: 0x3308,
0x1d64: 0x3308, 0x1d65: 0x0040, 0x1d66: 0x3308, 0x1d67: 0x3308, 0x1d68: 0x3308, 0x1d69: 0x3308,
0x1d6a: 0x3308, 0x1d6b: 0x0040, 0x1d6c: 0x0040, 0x1d6d: 0x0040, 0x1d6e: 0x0040, 0x1d6f: 0x0040,
0x1d70: 0x2479, 0x1d71: 0x2481, 0x1d72: 0x02a9, 0x1d73: 0x2489, 0x1d74: 0x02b1, 0x1d75: 0x2491,
0x1d76: 0x2499, 0x1d77: 0x24a1, 0x1d78: 0x24a9, 0x1d79: 0x24b1, 0x1d7a: 0x24b9, 0x1d7b: 0x24c1,
0x1d7c: 0x02b9, 0x1d7d: 0x24c9, 0x1d7e: 0x24d1, 0x1d7f: 0x02c1,
// Block 0x76, offset 0x1d80
0x1d80: 0x02c9, 0x1d81: 0x24d9, 0x1d82: 0x24e1, 0x1d83: 0x24e9, 0x1d84: 0x24f1, 0x1d85: 0x24f9,
0x1d86: 0x2501, 0x1d87: 0x2509, 0x1d88: 0x2511, 0x1d89: 0x2519, 0x1d8a: 0x2521, 0x1d8b: 0x2529,
0x1d8c: 0x2531, 0x1d8d: 0x2539, 0x1d8e: 0x2541, 0x1d8f: 0x2549, 0x1d90: 0x2551, 0x1d91: 0x2479,
0x1d92: 0x2481, 0x1d93: 0x02a9, 0x1d94: 0x2489, 0x1d95: 0x02b1, 0x1d96: 0x2491, 0x1d97: 0x2499,
0x1d98: 0x24a1, 0x1d99: 0x24a9, 0x1d9a: 0x24b1, 0x1d9b: 0x24b9, 0x1d9c: 0x02b9, 0x1d9d: 0x24c9,
0x1d9e: 0x02c1, 0x1d9f: 0x24d9, 0x1da0: 0x24e1, 0x1da1: 0x24e9, 0x1da2: 0x24f1, 0x1da3: 0x24f9,
0x1da4: 0x2501, 0x1da5: 0x02d1, 0x1da6: 0x2509, 0x1da7: 0x2559, 0x1da8: 0x2531, 0x1da9: 0x2561,
0x1daa: 0x2569, 0x1dab: 0x2571, 0x1dac: 0x2579, 0x1dad: 0x2581, 0x1dae: 0x0040, 0x1daf: 0x0040,
0x1db0: 0x0040, 0x1db1: 0x0040, 0x1db2: 0x0040, 0x1db3: 0x0040, 0x1db4: 0x0040, 0x1db5: 0x0040,
0x1db6: 0x0040, 0x1db7: 0x0040, 0x1db8: 0x0040, 0x1db9: 0x0040, 0x1dba: 0x0040, 0x1dbb: 0x0040,
0x1dbc: 0x0040, 0x1dbd: 0x0040, 0x1dbe: 0x0040, 0x1dbf: 0x0040,
// Block 0x77, offset 0x1dc0
0x1dc0: 0xe115, 0x1dc1: 0xe115, 0x1dc2: 0xe135, 0x1dc3: 0xe135, 0x1dc4: 0xe115, 0x1dc5: 0xe115,
0x1dc6: 0xe175, 0x1dc7: 0xe175, 0x1dc8: 0xe115, 0x1dc9: 0xe115, 0x1dca: 0xe135, 0x1dcb: 0xe135,
0x1dcc: 0xe115, 0x1dcd: 0xe115, 0x1dce: 0xe1f5, 0x1dcf: 0xe1f5, 0x1dd0: 0xe115, 0x1dd1: 0xe115,
0x1dd2: 0xe135, 0x1dd3: 0xe135, 0x1dd4: 0xe115, 0x1dd5: 0xe115, 0x1dd6: 0xe175, 0x1dd7: 0xe175,
0x1dd8: 0xe115, 0x1dd9: 0xe115, 0x1dda: 0xe135, 0x1ddb: 0xe135, 0x1ddc: 0xe115, 0x1ddd: 0xe115,
0x1dde: 0x8ca5, 0x1ddf: 0x8ca5, 0x1de0: 0x04b5, 0x1de1: 0x04b5, 0x1de2: 0x0a08, 0x1de3: 0x0a08,
0x1de4: 0x0a08, 0x1de5: 0x0a08, 0x1de6: 0x0a08, 0x1de7: 0x0a08, 0x1de8: 0x0a08, 0x1de9: 0x0a08,
0x1dea: 0x0a08, 0x1deb: 0x0a08, 0x1dec: 0x0a08, 0x1ded: 0x0a08, 0x1dee: 0x0a08, 0x1def: 0x0a08,
0x1df0: 0x0a08, 0x1df1: 0x0a08, 0x1df2: 0x0a08, 0x1df3: 0x0a08, 0x1df4: 0x0a08, 0x1df5: 0x0a08,
0x1df6: 0x0a08, 0x1df7: 0x0a08, 0x1df8: 0x0a08, 0x1df9: 0x0a08, 0x1dfa: 0x0a08, 0x1dfb: 0x0a08,
0x1dfc: 0x0a08, 0x1dfd: 0x0a08, 0x1dfe: 0x0a08, 0x1dff: 0x0a08,
// Block 0x78, offset 0x1e00
0x1e00: 0x20b1, 0x1e01: 0x20b9, 0x1e02: 0x20d9, 0x1e03: 0x20f1, 0x1e04: 0x0040, 0x1e05: 0x2189,
0x1e06: 0x2109, 0x1e07: 0x20e1, 0x1e08: 0x2131, 0x1e09: 0x2191, 0x1e0a: 0x2161, 0x1e0b: 0x2169,
0x1e0c: 0x2171, 0x1e0d: 0x2179, 0x1e0e: 0x2111, 0x1e0f: 0x2141, 0x1e10: 0x2151, 0x1e11: 0x2121,
0x1e12: 0x2159, 0x1e13: 0x2101, 0x1e14: 0x2119, 0x1e15: 0x20c9, 0x1e16: 0x20d1, 0x1e17: 0x20e9,
0x1e18: 0x20f9, 0x1e19: 0x2129, 0x1e1a: 0x2139, 0x1e1b: 0x2149, 0x1e1c: 0x2589, 0x1e1d: 0x1689,
0x1e1e: 0x2591, 0x1e1f: 0x2599, 0x1e20: 0x0040, 0x1e21: 0x20b9, 0x1e22: 0x20d9, 0x1e23: 0x0040,
0x1e24: 0x2181, 0x1e25: 0x0040, 0x1e26: 0x0040, 0x1e27: 0x20e1, 0x1e28: 0x0040, 0x1e29: 0x2191,
0x1e2a: 0x2161, 0x1e2b: 0x2169, 0x1e2c: 0x2171, 0x1e2d: 0x2179, 0x1e2e: 0x2111, 0x1e2f: 0x2141,
0x1e30: 0x2151, 0x1e31: 0x2121, 0x1e32: 0x2159, 0x1e33: 0x0040, 0x1e34: 0x2119, 0x1e35: 0x20c9,
0x1e36: 0x20d1, 0x1e37: 0x20e9, 0x1e38: 0x0040, 0x1e39: 0x2129, 0x1e3a: 0x0040, 0x1e3b: 0x2149,
0x1e3c: 0x0040, 0x1e3d: 0x0040, 0x1e3e: 0x0040, 0x1e3f: 0x0040,
// Block 0x79, offset 0x1e40
0x1e40: 0x0040, 0x1e41: 0x0040, 0x1e42: 0x20d9, 0x1e43: 0x0040, 0x1e44: 0x0040, 0x1e45: 0x0040,
0x1e46: 0x0040, 0x1e47: 0x20e1, 0x1e48: 0x0040, 0x1e49: 0x2191, 0x1e4a: 0x0040, 0x1e4b: 0x2169,
0x1e4c: 0x0040, 0x1e4d: 0x2179, 0x1e4e: 0x2111, 0x1e4f: 0x2141, 0x1e50: 0x0040, 0x1e51: 0x2121,
0x1e52: 0x2159, 0x1e53: 0x0040, 0x1e54: 0x2119, 0x1e55: 0x0040, 0x1e56: 0x0040, 0x1e57: 0x20e9,
0x1e58: 0x0040, 0x1e59: 0x2129, 0x1e5a: 0x0040, 0x1e5b: 0x2149, 0x1e5c: 0x0040, 0x1e5d: 0x1689,
0x1e5e: 0x0040, 0x1e5f: 0x2599, 0x1e60: 0x0040, 0x1e61: 0x20b9, 0x1e62: 0x20d9, 0x1e63: 0x0040,
0x1e64: 0x2181, 0x1e65: 0x0040, 0x1e66: 0x0040, 0x1e67: 0x20e1, 0x1e68: 0x2131, 0x1e69: 0x2191,
0x1e6a: 0x2161, 0x1e6b: 0x0040, 0x1e6c: 0x2171, 0x1e6d: 0x2179, 0x1e6e: 0x2111, 0x1e6f: 0x2141,
0x1e70: 0x2151, 0x1e71: 0x2121, 0x1e72: 0x2159, 0x1e73: 0x0040, 0x1e74: 0x2119, 0x1e75: 0x20c9,
0x1e76: 0x20d1, 0x1e77: 0x20e9, 0x1e78: 0x0040, 0x1e79: 0x2129, 0x1e7a: 0x2139, 0x1e7b: 0x2149,
0x1e7c: 0x2589, 0x1e7d: 0x0040, 0x1e7e: 0x2591, 0x1e7f: 0x0040,
// Block 0x7a, offset 0x1e80
0x1e80: 0x20b1, 0x1e81: 0x20b9, 0x1e82: 0x20d9, 0x1e83: 0x20f1, 0x1e84: 0x2181, 0x1e85: 0x2189,
0x1e86: 0x2109, 0x1e87: 0x20e1, 0x1e88: 0x2131, 0x1e89: 0x2191, 0x1e8a: 0x0040, 0x1e8b: 0x2169,
0x1e8c: 0x2171, 0x1e8d: 0x2179, 0x1e8e: 0x2111, 0x1e8f: 0x2141, 0x1e90: 0x2151, 0x1e91: 0x2121,
0x1e92: 0x2159, 0x1e93: 0x2101, 0x1e94: 0x2119, 0x1e95: 0x20c9, 0x1e96: 0x20d1, 0x1e97: 0x20e9,
0x1e98: 0x20f9, 0x1e99: 0x2129, 0x1e9a: 0x2139, 0x1e9b: 0x2149, 0x1e9c: 0x0040, 0x1e9d: 0x0040,
0x1e9e: 0x0040, 0x1e9f: 0x0040, 0x1ea0: 0x0040, 0x1ea1: 0x20b9, 0x1ea2: 0x20d9, 0x1ea3: 0x20f1,
0x1ea4: 0x0040, 0x1ea5: 0x2189, 0x1ea6: 0x2109, 0x1ea7: 0x20e1, 0x1ea8: 0x2131, 0x1ea9: 0x2191,
0x1eaa: 0x0040, 0x1eab: 0x2169, 0x1eac: 0x2171, 0x1ead: 0x2179, 0x1eae: 0x2111, 0x1eaf: 0x2141,
0x1eb0: 0x2151, 0x1eb1: 0x2121, 0x1eb2: 0x2159, 0x1eb3: 0x2101, 0x1eb4: 0x2119, 0x1eb5: 0x20c9,
0x1eb6: 0x20d1, 0x1eb7: 0x20e9, 0x1eb8: 0x20f9, 0x1eb9: 0x2129, 0x1eba: 0x2139, 0x1ebb: 0x2149,
0x1ebc: 0x0040, 0x1ebd: 0x0040, 0x1ebe: 0x0040, 0x1ebf: 0x0040,
// Block 0x7b, offset 0x1ec0
0x1ec0: 0x0040, 0x1ec1: 0x25a2, 0x1ec2: 0x25aa, 0x1ec3: 0x25b2, 0x1ec4: 0x25ba, 0x1ec5: 0x25c2,
0x1ec6: 0x25ca, 0x1ec7: 0x25d2, 0x1ec8: 0x25da, 0x1ec9: 0x25e2, 0x1eca: 0x25ea, 0x1ecb: 0x0018,
0x1ecc: 0x0018, 0x1ecd: 0x0018, 0x1ece: 0x0018, 0x1ecf: 0x0018, 0x1ed0: 0x25f2, 0x1ed1: 0x25fa,
0x1ed2: 0x2602, 0x1ed3: 0x260a, 0x1ed4: 0x2612, 0x1ed5: 0x261a, 0x1ed6: 0x2622, 0x1ed7: 0x262a,
0x1ed8: 0x2632, 0x1ed9: 0x263a, 0x1eda: 0x2642, 0x1edb: 0x264a, 0x1edc: 0x2652, 0x1edd: 0x265a,
0x1ede: 0x2662, 0x1edf: 0x266a, 0x1ee0: 0x2672, 0x1ee1: 0x267a, 0x1ee2: 0x2682, 0x1ee3: 0x268a,
0x1ee4: 0x2692, 0x1ee5: 0x269a, 0x1ee6: 0x26a2, 0x1ee7: 0x26aa, 0x1ee8: 0x26b2, 0x1ee9: 0x26ba,
0x1eea: 0x26c1, 0x1eeb: 0x03d9, 0x1eec: 0x00b9, 0x1eed: 0x1239, 0x1eee: 0x26c9, 0x1eef: 0x0018,
0x1ef0: 0x0019, 0x1ef1: 0x02e9, 0x1ef2: 0x03d9, 0x1ef3: 0x02f1, 0x1ef4: 0x02f9, 0x1ef5: 0x03f1,
0x1ef6: 0x0309, 0x1ef7: 0x00a9, 0x1ef8: 0x0311, 0x1ef9: 0x00b1, 0x1efa: 0x0319, 0x1efb: 0x0101,
0x1efc: 0x0321, 0x1efd: 0x0329, 0x1efe: 0x0051, 0x1eff: 0x0339,
// Block 0x7c, offset 0x1f00
0x1f00: 0x0751, 0x1f01: 0x00b9, 0x1f02: 0x0089, 0x1f03: 0x0341, 0x1f04: 0x0349, 0x1f05: 0x0391,
0x1f06: 0x00c1, 0x1f07: 0x0109, 0x1f08: 0x00c9, 0x1f09: 0x04b1, 0x1f0a: 0x26d1, 0x1f0b: 0x11f9,
0x1f0c: 0x26d9, 0x1f0d: 0x04d9, 0x1f0e: 0x26e1, 0x1f0f: 0x26e9, 0x1f10: 0x0018, 0x1f11: 0x0018,
0x1f12: 0x0018, 0x1f13: 0x0018, 0x1f14: 0x0018, 0x1f15: 0x0018, 0x1f16: 0x0018, 0x1f17: 0x0018,
0x1f18: 0x0018, 0x1f19: 0x0018, 0x1f1a: 0x0018, 0x1f1b: 0x0018, 0x1f1c: 0x0018, 0x1f1d: 0x0018,
0x1f1e: 0x0018, 0x1f1f: 0x0018, 0x1f20: 0x0018, 0x1f21: 0x0018, 0x1f22: 0x0018, 0x1f23: 0x0018,
0x1f24: 0x0018, 0x1f25: 0x0018, 0x1f26: 0x0018, 0x1f27: 0x0018, 0x1f28: 0x0018, 0x1f29: 0x0018,
0x1f2a: 0x26f1, 0x1f2b: 0x26f9, 0x1f2c: 0x2701, 0x1f2d: 0x0018, 0x1f2e: 0x0018, 0x1f2f: 0x0018,
0x1f30: 0x0018, 0x1f31: 0x0018, 0x1f32: 0x0018, 0x1f33: 0x0018, 0x1f34: 0x0018, 0x1f35: 0x0018,
0x1f36: 0x0018, 0x1f37: 0x0018, 0x1f38: 0x0018, 0x1f39: 0x0018, 0x1f3a: 0x0018, 0x1f3b: 0x0018,
0x1f3c: 0x0018, 0x1f3d: 0x0018, 0x1f3e: 0x0018, 0x1f3f: 0x0018,
// Block 0x7d, offset 0x1f40
0x1f40: 0x2711, 0x1f41: 0x2719, 0x1f42: 0x2721, 0x1f43: 0x0040, 0x1f44: 0x0040, 0x1f45: 0x0040,
0x1f46: 0x0040, 0x1f47: 0x0040, 0x1f48: 0x0040, 0x1f49: 0x0040, 0x1f4a: 0x0040, 0x1f4b: 0x0040,
0x1f4c: 0x0040, 0x1f4d: 0x0040, 0x1f4e: 0x0040, 0x1f4f: 0x0040, 0x1f50: 0x2729, 0x1f51: 0x2731,
0x1f52: 0x2739, 0x1f53: 0x2741, 0x1f54: 0x2749, 0x1f55: 0x2751, 0x1f56: 0x2759, 0x1f57: 0x2761,
0x1f58: 0x2769, 0x1f59: 0x2771, 0x1f5a: 0x2779, 0x1f5b: 0x2781, 0x1f5c: 0x2789, 0x1f5d: 0x2791,
0x1f5e: 0x2799, 0x1f5f: 0x27a1, 0x1f60: 0x27a9, 0x1f61: 0x27b1, 0x1f62: 0x27b9, 0x1f63: 0x27c1,
0x1f64: 0x27c9, 0x1f65: 0x27d1, 0x1f66: 0x27d9, 0x1f67: 0x27e1, 0x1f68: 0x27e9, 0x1f69: 0x27f1,
0x1f6a: 0x27f9, 0x1f6b: 0x2801, 0x1f6c: 0x2809, 0x1f6d: 0x2811, 0x1f6e: 0x2819, 0x1f6f: 0x2821,
0x1f70: 0x2829, 0x1f71: 0x2831, 0x1f72: 0x2839, 0x1f73: 0x2841, 0x1f74: 0x2849, 0x1f75: 0x2851,
0x1f76: 0x2859, 0x1f77: 0x2861, 0x1f78: 0x2869, 0x1f79: 0x2871, 0x1f7a: 0x2879, 0x1f7b: 0x2881,
0x1f7c: 0x0040, 0x1f7d: 0x0040, 0x1f7e: 0x0040, 0x1f7f: 0x0040,
// Block 0x7e, offset 0x1f80
0x1f80: 0x28e1, 0x1f81: 0x28e9, 0x1f82: 0x28f1, 0x1f83: 0x8cbd, 0x1f84: 0x28f9, 0x1f85: 0x2901,
0x1f86: 0x2909, 0x1f87: 0x2911, 0x1f88: 0x2919, 0x1f89: 0x2921, 0x1f8a: 0x2929, 0x1f8b: 0x2931,
0x1f8c: 0x2939, 0x1f8d: 0x8cdd, 0x1f8e: 0x2941, 0x1f8f: 0x2949, 0x1f90: 0x2951, 0x1f91: 0x2959,
0x1f92: 0x8cfd, 0x1f93: 0x2961, 0x1f94: 0x2969, 0x1f95: 0x2799, 0x1f96: 0x8d1d, 0x1f97: 0x2971,
0x1f98: 0x2979, 0x1f99: 0x2981, 0x1f9a: 0x2989, 0x1f9b: 0x2991, 0x1f9c: 0x8d3d, 0x1f9d: 0x2999,
0x1f9e: 0x29a1, 0x1f9f: 0x29a9, 0x1fa0: 0x29b1, 0x1fa1: 0x29b9, 0x1fa2: 0x2871, 0x1fa3: 0x29c1,
0x1fa4: 0x29c9, 0x1fa5: 0x29d1, 0x1fa6: 0x29d9, 0x1fa7: 0x29e1, 0x1fa8: 0x29e9, 0x1fa9: 0x29f1,
0x1faa: 0x29f9, 0x1fab: 0x2a01, 0x1fac: 0x2a09, 0x1fad: 0x2a11, 0x1fae: 0x2a19, 0x1faf: 0x2a21,
0x1fb0: 0x2a29, 0x1fb1: 0x2a31, 0x1fb2: 0x2a31, 0x1fb3: 0x2a31, 0x1fb4: 0x8d5d, 0x1fb5: 0x2a39,
0x1fb6: 0x2a41, 0x1fb7: 0x2a49, 0x1fb8: 0x8d7d, 0x1fb9: 0x2a51, 0x1fba: 0x2a59, 0x1fbb: 0x2a61,
0x1fbc: 0x2a69, 0x1fbd: 0x2a71, 0x1fbe: 0x2a79, 0x1fbf: 0x2a81,
// Block 0x7f, offset 0x1fc0
0x1fc0: 0x2a89, 0x1fc1: 0x2a91, 0x1fc2: 0x2a99, 0x1fc3: 0x2aa1, 0x1fc4: 0x2aa9, 0x1fc5: 0x2ab1,
0x1fc6: 0x2ab1, 0x1fc7: 0x2ab9, 0x1fc8: 0x2ac1, 0x1fc9: 0x2ac9, 0x1fca: 0x2ad1, 0x1fcb: 0x2ad9,
0x1fcc: 0x2ae1, 0x1fcd: 0x2ae9, 0x1fce: 0x2af1, 0x1fcf: 0x2af9, 0x1fd0: 0x2b01, 0x1fd1: 0x2b09,
0x1fd2: 0x2b11, 0x1fd3: 0x2b19, 0x1fd4: 0x2b21, 0x1fd5: 0x2b29, 0x1fd6: 0x2b31, 0x1fd7: 0x2b39,
0x1fd8: 0x2b41, 0x1fd9: 0x8d9d, 0x1fda: 0x2b49, 0x1fdb: 0x2b51, 0x1fdc: 0x2b59, 0x1fdd: 0x2751,
0x1fde: 0x2b61, 0x1fdf: 0x2b69, 0x1fe0: 0x8dbd, 0x1fe1: 0x8ddd, 0x1fe2: 0x2b71, 0x1fe3: 0x2b79,
0x1fe4: 0x2b81, 0x1fe5: 0x2b89, 0x1fe6: 0x2b91, 0x1fe7: 0x2b99, 0x1fe8: 0x2040, 0x1fe9: 0x2ba1,
0x1fea: 0x2ba9, 0x1feb: 0x2ba9, 0x1fec: 0x8dfd, 0x1fed: 0x2bb1, 0x1fee: 0x2bb9, 0x1fef: 0x2bc1,
0x1ff0: 0x2bc9, 0x1ff1: 0x8e1d, 0x1ff2: 0x2bd1, 0x1ff3: 0x2bd9, 0x1ff4: 0x2040, 0x1ff5: 0x2be1,
0x1ff6: 0x2be9, 0x1ff7: 0x2bf1, 0x1ff8: 0x2bf9, 0x1ff9: 0x2c01, 0x1ffa: 0x2c09, 0x1ffb: 0x8e3d,
0x1ffc: 0x2c11, 0x1ffd: 0x8e5d, 0x1ffe: 0x2c19, 0x1fff: 0x2c21,
// Block 0x80, offset 0x2000
0x2000: 0x2c29, 0x2001: 0x2c31, 0x2002: 0x2c39, 0x2003: 0x2c41, 0x2004: 0x2c49, 0x2005: 0x2c51,
0x2006: 0x2c59, 0x2007: 0x2c61, 0x2008: 0x2c69, 0x2009: 0x8e7d, 0x200a: 0x2c71, 0x200b: 0x2c79,
0x200c: 0x2c81, 0x200d: 0x2c89, 0x200e: 0x2c91, 0x200f: 0x8e9d, 0x2010: 0x2c99, 0x2011: 0x8ebd,
0x2012: 0x8edd, 0x2013: 0x2ca1, 0x2014: 0x2ca9, 0x2015: 0x2ca9, 0x2016: 0x2cb1, 0x2017: 0x8efd,
0x2018: 0x8f1d, 0x2019: 0x2cb9, 0x201a: 0x2cc1, 0x201b: 0x2cc9, 0x201c: 0x2cd1, 0x201d: 0x2cd9,
0x201e: 0x2ce1, 0x201f: 0x2ce9, 0x2020: 0x2cf1, 0x2021: 0x2cf9, 0x2022: 0x2d01, 0x2023: 0x2d09,
0x2024: 0x8f3d, 0x2025: 0x2d11, 0x2026: 0x2d19, 0x2027: 0x2d21, 0x2028: 0x2d29, 0x2029: 0x2d21,
0x202a: 0x2d31, 0x202b: 0x2d39, 0x202c: 0x2d41, 0x202d: 0x2d49, 0x202e: 0x2d51, 0x202f: 0x2d59,
0x2030: 0x2d61, 0x2031: 0x2d69, 0x2032: 0x2d71, 0x2033: 0x2d79, 0x2034: 0x2d81, 0x2035: 0x2d89,
0x2036: 0x2d91, 0x2037: 0x2d99, 0x2038: 0x8f5d, 0x2039: 0x2da1, 0x203a: 0x2da9, 0x203b: 0x2db1,
0x203c: 0x2db9, 0x203d: 0x2dc1, 0x203e: 0x8f7d, 0x203f: 0x2dc9,
// Block 0x81, offset 0x2040
0x2040: 0x2dd1, 0x2041: 0x2dd9, 0x2042: 0x2de1, 0x2043: 0x2de9, 0x2044: 0x2df1, 0x2045: 0x2df9,
0x2046: 0x2e01, 0x2047: 0x2e09, 0x2048: 0x2e11, 0x2049: 0x2e19, 0x204a: 0x8f9d, 0x204b: 0x2e21,
0x204c: 0x2e29, 0x204d: 0x2e31, 0x204e: 0x2e39, 0x204f: 0x2e41, 0x2050: 0x2e49, 0x2051: 0x2e51,
0x2052: 0x2e59, 0x2053: 0x2e61, 0x2054: 0x2e69, 0x2055: 0x2e71, 0x2056: 0x2e79, 0x2057: 0x2e81,
0x2058: 0x2e89, 0x2059: 0x2e91, 0x205a: 0x2e99, 0x205b: 0x2ea1, 0x205c: 0x2ea9, 0x205d: 0x8fbd,
0x205e: 0x2eb1, 0x205f: 0x2eb9, 0x2060: 0x2ec1, 0x2061: 0x2ec9, 0x2062: 0x2ed1, 0x2063: 0x8fdd,
0x2064: 0x2ed9, 0x2065: 0x2ee1, 0x2066: 0x2ee9, 0x2067: 0x2ef1, 0x2068: 0x2ef9, 0x2069: 0x2f01,
0x206a: 0x2f09, 0x206b: 0x2f11, 0x206c: 0x7f0d, 0x206d: 0x2f19, 0x206e: 0x2f21, 0x206f: 0x2f29,
0x2070: 0x8ffd, 0x2071: 0x2f31, 0x2072: 0x2f39, 0x2073: 0x2f41, 0x2074: 0x2f49, 0x2075: 0x2f51,
0x2076: 0x2f59, 0x2077: 0x901d, 0x2078: 0x903d, 0x2079: 0x905d, 0x207a: 0x2f61, 0x207b: 0x907d,
0x207c: 0x2f69, 0x207d: 0x2f71, 0x207e: 0x2f79, 0x207f: 0x2f81,
// Block 0x82, offset 0x2080
0x2080: 0x2f89, 0x2081: 0x2f91, 0x2082: 0x2f99, 0x2083: 0x2fa1, 0x2084: 0x2fa9, 0x2085: 0x2fb1,
0x2086: 0x909d, 0x2087: 0x2fb9, 0x2088: 0x2fc1, 0x2089: 0x2fc9, 0x208a: 0x2fd1, 0x208b: 0x2fd9,
0x208c: 0x2fe1, 0x208d: 0x90bd, 0x208e: 0x2fe9, 0x208f: 0x2ff1, 0x2090: 0x90dd, 0x2091: 0x90fd,
0x2092: 0x2ff9, 0x2093: 0x3001, 0x2094: 0x3009, 0x2095: 0x3011, 0x2096: 0x3019, 0x2097: 0x3021,
0x2098: 0x3029, 0x2099: 0x3031, 0x209a: 0x3039, 0x209b: 0x911d, 0x209c: 0x3041, 0x209d: 0x913d,
0x209e: 0x3049, 0x209f: 0x2040, 0x20a0: 0x3051, 0x20a1: 0x3059, 0x20a2: 0x3061, 0x20a3: 0x915d,
0x20a4: 0x3069, 0x20a5: 0x3071, 0x20a6: 0x917d, 0x20a7: 0x919d, 0x20a8: 0x3079, 0x20a9: 0x3081,
0x20aa: 0x3089, 0x20ab: 0x3091, 0x20ac: 0x3099, 0x20ad: 0x3099, 0x20ae: 0x30a1, 0x20af: 0x30a9,
0x20b0: 0x30b1, 0x20b1: 0x30b9, 0x20b2: 0x30c1, 0x20b3: 0x30c9, 0x20b4: 0x30d1, 0x20b5: 0x91bd,
0x20b6: 0x30d9, 0x20b7: 0x91dd, 0x20b8: 0x30e1, 0x20b9: 0x91fd, 0x20ba: 0x30e9, 0x20bb: 0x921d,
0x20bc: 0x923d, 0x20bd: 0x925d, 0x20be: 0x30f1, 0x20bf: 0x30f9,
// Block 0x83, offset 0x20c0
0x20c0: 0x3101, 0x20c1: 0x927d, 0x20c2: 0x929d, 0x20c3: 0x92bd, 0x20c4: 0x92dd, 0x20c5: 0x3109,
0x20c6: 0x3111, 0x20c7: 0x3111, 0x20c8: 0x3119, 0x20c9: 0x3121, 0x20ca: 0x3129, 0x20cb: 0x3131,
0x20cc: 0x3139, 0x20cd: 0x92fd, 0x20ce: 0x3141, 0x20cf: 0x3149, 0x20d0: 0x3151, 0x20d1: 0x3159,
0x20d2: 0x931d, 0x20d3: 0x3161, 0x20d4: 0x933d, 0x20d5: 0x935d, 0x20d6: 0x3169, 0x20d7: 0x3171,
0x20d8: 0x3179, 0x20d9: 0x3181, 0x20da: 0x3189, 0x20db: 0x3191, 0x20dc: 0x937d, 0x20dd: 0x939d,
0x20de: 0x93bd, 0x20df: 0x2040, 0x20e0: 0x3199, 0x20e1: 0x93dd, 0x20e2: 0x31a1, 0x20e3: 0x31a9,
0x20e4: 0x31b1, 0x20e5: 0x93fd, 0x20e6: 0x31b9, 0x20e7: 0x31c1, 0x20e8: 0x31c9, 0x20e9: 0x31d1,
0x20ea: 0x31d9, 0x20eb: 0x941d, 0x20ec: 0x31e1, 0x20ed: 0x31e9, 0x20ee: 0x31f1, 0x20ef: 0x31f9,
0x20f0: 0x3201, 0x20f1: 0x3209, 0x20f2: 0x943d, 0x20f3: 0x945d, 0x20f4: 0x3211, 0x20f5: 0x947d,
0x20f6: 0x3219, 0x20f7: 0x949d, 0x20f8: 0x3221, 0x20f9: 0x3229, 0x20fa: 0x3231, 0x20fb: 0x94bd,
0x20fc: 0x94dd, 0x20fd: 0x3239, 0x20fe: 0x94fd, 0x20ff: 0x3241,
// Block 0x84, offset 0x2100
0x2100: 0x951d, 0x2101: 0x3249, 0x2102: 0x3251, 0x2103: 0x3259, 0x2104: 0x3261, 0x2105: 0x3269,
0x2106: 0x3271, 0x2107: 0x953d, 0x2108: 0x955d, 0x2109: 0x957d, 0x210a: 0x959d, 0x210b: 0x2ca1,
0x210c: 0x3279, 0x210d: 0x3281, 0x210e: 0x3289, 0x210f: 0x3291, 0x2110: 0x3299, 0x2111: 0x32a1,
0x2112: 0x32a9, 0x2113: 0x32b1, 0x2114: 0x32b9, 0x2115: 0x32c1, 0x2116: 0x32c9, 0x2117: 0x95bd,
0x2118: 0x32d1, 0x2119: 0x32d9, 0x211a: 0x32e1, 0x211b: 0x32e9, 0x211c: 0x32f1, 0x211d: 0x32f9,
0x211e: 0x3301, 0x211f: 0x3309, 0x2120: 0x3311, 0x2121: 0x3319, 0x2122: 0x3321, 0x2123: 0x3329,
0x2124: 0x95dd, 0x2125: 0x95fd, 0x2126: 0x961d, 0x2127: 0x3331, 0x2128: 0x3339, 0x2129: 0x3341,
0x212a: 0x3349, 0x212b: 0x963d, 0x212c: 0x3351, 0x212d: 0x965d, 0x212e: 0x3359, 0x212f: 0x3361,
0x2130: 0x967d, 0x2131: 0x969d, 0x2132: 0x3369, 0x2133: 0x3371, 0x2134: 0x3379, 0x2135: 0x3381,
0x2136: 0x3389, 0x2137: 0x3391, 0x2138: 0x3399, 0x2139: 0x33a1, 0x213a: 0x33a9, 0x213b: 0x33b1,
0x213c: 0x33b9, 0x213d: 0x33c1, 0x213e: 0x33c9, 0x213f: 0x2040,
// Block 0x85, offset 0x2140
0x2140: 0x33d1, 0x2141: 0x33d9, 0x2142: 0x33e1, 0x2143: 0x33e9, 0x2144: 0x33f1, 0x2145: 0x96bd,
0x2146: 0x33f9, 0x2147: 0x3401, 0x2148: 0x3409, 0x2149: 0x3411, 0x214a: 0x3419, 0x214b: 0x96dd,
0x214c: 0x96fd, 0x214d: 0x3421, 0x214e: 0x3429, 0x214f: 0x3431, 0x2150: 0x3439, 0x2151: 0x3441,
0x2152: 0x3449, 0x2153: 0x971d, 0x2154: 0x3451, 0x2155: 0x3459, 0x2156: 0x3461, 0x2157: 0x3469,
0x2158: 0x973d, 0x2159: 0x975d, 0x215a: 0x3471, 0x215b: 0x3479, 0x215c: 0x3481, 0x215d: 0x977d,
0x215e: 0x3489, 0x215f: 0x3491, 0x2160: 0x684d, 0x2161: 0x979d, 0x2162: 0x3499, 0x2163: 0x34a1,
0x2164: 0x34a9, 0x2165: 0x97bd, 0x2166: 0x34b1, 0x2167: 0x34b9, 0x2168: 0x34c1, 0x2169: 0x34c9,
0x216a: 0x34d1, 0x216b: 0x34d9, 0x216c: 0x34e1, 0x216d: 0x97dd, 0x216e: 0x34e9, 0x216f: 0x34f1,
0x2170: 0x34f9, 0x2171: 0x97fd, 0x2172: 0x3501, 0x2173: 0x3509, 0x2174: 0x3511, 0x2175: 0x3519,
0x2176: 0x7b6d, 0x2177: 0x981d, 0x2178: 0x3521, 0x2179: 0x3529, 0x217a: 0x3531, 0x217b: 0x983d,
0x217c: 0x3539, 0x217d: 0x985d, 0x217e: 0x3541, 0x217f: 0x3541,
// Block 0x86, offset 0x2180
0x2180: 0x3549, 0x2181: 0x987d, 0x2182: 0x3551, 0x2183: 0x3559, 0x2184: 0x3561, 0x2185: 0x3569,
0x2186: 0x3571, 0x2187: 0x3579, 0x2188: 0x3581, 0x2189: 0x989d, 0x218a: 0x3589, 0x218b: 0x3591,
0x218c: 0x3599, 0x218d: 0x35a1, 0x218e: 0x35a9, 0x218f: 0x35b1, 0x2190: 0x98bd, 0x2191: 0x35b9,
0x2192: 0x98dd, 0x2193: 0x98fd, 0x2194: 0x991d, 0x2195: 0x35c1, 0x2196: 0x35c9, 0x2197: 0x35d1,
0x2198: 0x35d9, 0x2199: 0x35e1, 0x219a: 0x35e9, 0x219b: 0x35f1, 0x219c: 0x35f9, 0x219d: 0x993d,
0x219e: 0x0040, 0x219f: 0x0040, 0x21a0: 0x0040, 0x21a1: 0x0040, 0x21a2: 0x0040, 0x21a3: 0x0040,
0x21a4: 0x0040, 0x21a5: 0x0040, 0x21a6: 0x0040, 0x21a7: 0x0040, 0x21a8: 0x0040, 0x21a9: 0x0040,
0x21aa: 0x0040, 0x21ab: 0x0040, 0x21ac: 0x0040, 0x21ad: 0x0040, 0x21ae: 0x0040, 0x21af: 0x0040,
0x21b0: 0x0040, 0x21b1: 0x0040, 0x21b2: 0x0040, 0x21b3: 0x0040, 0x21b4: 0x0040, 0x21b5: 0x0040,
0x21b6: 0x0040, 0x21b7: 0x0040, 0x21b8: 0x0040, 0x21b9: 0x0040, 0x21ba: 0x0040, 0x21bb: 0x0040,
0x21bc: 0x0040, 0x21bd: 0x0040, 0x21be: 0x0040, 0x21bf: 0x0040,
}
// idnaIndex: 39 blocks, 2496 entries, 4992 bytes
// Block 0 is the zero block.
var idnaIndex = [2496]uint16{
// Block 0x0, offset 0x0
// Block 0x1, offset 0x40
// Block 0x2, offset 0x80
// Block 0x3, offset 0xc0
0xc2: 0x01, 0xc3: 0x85, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x04, 0xc7: 0x05,
0xc8: 0x06, 0xc9: 0x86, 0xca: 0x87, 0xcb: 0x07, 0xcc: 0x88, 0xcd: 0x08, 0xce: 0x09, 0xcf: 0x0a,
0xd0: 0x89, 0xd1: 0x0b, 0xd2: 0x0c, 0xd3: 0x0d, 0xd4: 0x0e, 0xd5: 0x8a, 0xd6: 0x8b, 0xd7: 0x8c,
0xd8: 0x0f, 0xd9: 0x10, 0xda: 0x8d, 0xdb: 0x11, 0xdc: 0x12, 0xdd: 0x8e, 0xde: 0x8f, 0xdf: 0x90,
0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, 0xe4: 0x06, 0xe5: 0x07, 0xe6: 0x07, 0xe7: 0x07,
0xe8: 0x07, 0xe9: 0x07, 0xea: 0x08, 0xeb: 0x07, 0xec: 0x07, 0xed: 0x09, 0xee: 0x0a, 0xef: 0x0b,
0xf0: 0x20, 0xf1: 0x21, 0xf2: 0x21, 0xf3: 0x23, 0xf4: 0x24,
// Block 0x4, offset 0x100
0x120: 0x91, 0x121: 0x13, 0x122: 0x14, 0x123: 0x92, 0x124: 0x93, 0x125: 0x15, 0x126: 0x16, 0x127: 0x17,
0x128: 0x18, 0x129: 0x19, 0x12a: 0x1a, 0x12b: 0x1b, 0x12c: 0x1c, 0x12d: 0x1d, 0x12e: 0x1e, 0x12f: 0x94,
0x130: 0x95, 0x131: 0x1f, 0x132: 0x20, 0x133: 0x21, 0x134: 0x96, 0x135: 0x22, 0x136: 0x97, 0x137: 0x98,
0x138: 0x99, 0x139: 0x9a, 0x13a: 0x23, 0x13b: 0x9b, 0x13c: 0x9c, 0x13d: 0x24, 0x13e: 0x25, 0x13f: 0x9d,
// Block 0x5, offset 0x140
0x140: 0x9e, 0x141: 0x9f, 0x142: 0xa0, 0x143: 0xa1, 0x144: 0xa2, 0x145: 0xa3, 0x146: 0xa4, 0x147: 0xa5,
0x148: 0xa6, 0x149: 0xa7, 0x14a: 0xa8, 0x14b: 0xa9, 0x14c: 0xaa, 0x14d: 0xab, 0x14e: 0xac, 0x14f: 0xad,
0x150: 0xae, 0x151: 0xa6, 0x152: 0xa6, 0x153: 0xa6, 0x154: 0xa6, 0x155: 0xa6, 0x156: 0xa6, 0x157: 0xa6,
0x158: 0xa6, 0x159: 0xaf, 0x15a: 0xb0, 0x15b: 0xb1, 0x15c: 0xb2, 0x15d: 0xb3, 0x15e: 0xb4, 0x15f: 0xb5,
0x160: 0xb6, 0x161: 0xb7, 0x162: 0xb8, 0x163: 0xb9, 0x164: 0xba, 0x165: 0xbb, 0x166: 0xbc, 0x167: 0xbd,
0x168: 0xbe, 0x169: 0xbf, 0x16a: 0xc0, 0x16b: 0xc1, 0x16c: 0xc2, 0x16d: 0xc3, 0x16e: 0xc4, 0x16f: 0xc5,
0x170: 0xc6, 0x171: 0xc7, 0x172: 0xc8, 0x173: 0xc9, 0x174: 0x26, 0x175: 0x27, 0x176: 0x28, 0x177: 0x88,
0x178: 0x29, 0x179: 0x29, 0x17a: 0x2a, 0x17b: 0x29, 0x17c: 0xca, 0x17d: 0x2b, 0x17e: 0x2c, 0x17f: 0x2d,
// Block 0x6, offset 0x180
0x180: 0x2e, 0x181: 0x2f, 0x182: 0x30, 0x183: 0xcb, 0x184: 0x31, 0x185: 0x32, 0x186: 0xcc, 0x187: 0xa2,
0x188: 0xcd, 0x189: 0xce, 0x18a: 0xa2, 0x18b: 0xa2, 0x18c: 0xcf, 0x18d: 0xa2, 0x18e: 0xa2, 0x18f: 0xa2,
0x190: 0xd0, 0x191: 0x33, 0x192: 0x34, 0x193: 0x35, 0x194: 0xa2, 0x195: 0xa2, 0x196: 0xa2, 0x197: 0xa2,
0x198: 0xa2, 0x199: 0xa2, 0x19a: 0xa2, 0x19b: 0xa2, 0x19c: 0xa2, 0x19d: 0xa2, 0x19e: 0xa2, 0x19f: 0xa2,
0x1a0: 0xa2, 0x1a1: 0xa2, 0x1a2: 0xa2, 0x1a3: 0xa2, 0x1a4: 0xa2, 0x1a5: 0xa2, 0x1a6: 0xa2, 0x1a7: 0xa2,
0x1a8: 0xd1, 0x1a9: 0xd2, 0x1aa: 0xa2, 0x1ab: 0xd3, 0x1ac: 0xa2, 0x1ad: 0xd4, 0x1ae: 0xd5, 0x1af: 0xa2,
0x1b0: 0xd6, 0x1b1: 0x36, 0x1b2: 0x29, 0x1b3: 0x37, 0x1b4: 0xd7, 0x1b5: 0xd8, 0x1b6: 0xd9, 0x1b7: 0xda,
0x1b8: 0xdb, 0x1b9: 0xdc, 0x1ba: 0xdd, 0x1bb: 0xde, 0x1bc: 0xdf, 0x1bd: 0xe0, 0x1be: 0xe1, 0x1bf: 0x38,
// Block 0x7, offset 0x1c0
0x1c0: 0x39, 0x1c1: 0xe2, 0x1c2: 0xe3, 0x1c3: 0xe4, 0x1c4: 0xe5, 0x1c5: 0x3a, 0x1c6: 0x3b, 0x1c7: 0xe6,
0x1c8: 0xe7, 0x1c9: 0x3c, 0x1ca: 0x3d, 0x1cb: 0x3e, 0x1cc: 0xe8, 0x1cd: 0xe9, 0x1ce: 0x3f, 0x1cf: 0x40,
0x1d0: 0xa6, 0x1d1: 0xa6, 0x1d2: 0xa6, 0x1d3: 0xa6, 0x1d4: 0xa6, 0x1d5: 0xa6, 0x1d6: 0xa6, 0x1d7: 0xa6,
0x1d8: 0xa6, 0x1d9: 0xa6, 0x1da: 0xa6, 0x1db: 0xa6, 0x1dc: 0xa6, 0x1dd: 0xa6, 0x1de: 0xa6, 0x1df: 0xa6,
0x1e0: 0xa6, 0x1e1: 0xa6, 0x1e2: 0xa6, 0x1e3: 0xa6, 0x1e4: 0xa6, 0x1e5: 0xa6, 0x1e6: 0xa6, 0x1e7: 0xa6,
0x1e8: 0xa6, 0x1e9: 0xa6, 0x1ea: 0xa6, 0x1eb: 0xa6, 0x1ec: 0xa6, 0x1ed: 0xa6, 0x1ee: 0xa6, 0x1ef: 0xa6,
0x1f0: 0xa6, 0x1f1: 0xa6, 0x1f2: 0xa6, 0x1f3: 0xa6, 0x1f4: 0xa6, 0x1f5: 0xa6, 0x1f6: 0xa6, 0x1f7: 0xa6,
0x1f8: 0xa6, 0x1f9: 0xa6, 0x1fa: 0xa6, 0x1fb: 0xa6, 0x1fc: 0xa6, 0x1fd: 0xa6, 0x1fe: 0xa6, 0x1ff: 0xa6,
// Block 0x8, offset 0x200
0x200: 0xa6, 0x201: 0xa6, 0x202: 0xa6, 0x203: 0xa6, 0x204: 0xa6, 0x205: 0xa6, 0x206: 0xa6, 0x207: 0xa6,
0x208: 0xa6, 0x209: 0xa6, 0x20a: 0xa6, 0x20b: 0xa6, 0x20c: 0xa6, 0x20d: 0xa6, 0x20e: 0xa6, 0x20f: 0xa6,
0x210: 0xa6, 0x211: 0xa6, 0x212: 0xa6, 0x213: 0xa6, 0x214: 0xa6, 0x215: 0xa6, 0x216: 0xa6, 0x217: 0xa6,
0x218: 0xa6, 0x219: 0xa6, 0x21a: 0xa6, 0x21b: 0xa6, 0x21c: 0xa6, 0x21d: 0xa6, 0x21e: 0xa6, 0x21f: 0xa6,
0x220: 0xa6, 0x221: 0xa6, 0x222: 0xa6, 0x223: 0xa6, 0x224: 0xa6, 0x225: 0xa6, 0x226: 0xa6, 0x227: 0xa6,
0x228: 0xa6, 0x229: 0xa6, 0x22a: 0xa6, 0x22b: 0xa6, 0x22c: 0xa6, 0x22d: 0xa6, 0x22e: 0xa6, 0x22f: 0xa6,
0x230: 0xa6, 0x231: 0xa6, 0x232: 0xa6, 0x233: 0xa6, 0x234: 0xa6, 0x235: 0xa6, 0x236: 0xa6, 0x237: 0xa2,
0x238: 0xa6, 0x239: 0xa6, 0x23a: 0xa6, 0x23b: 0xa6, 0x23c: 0xa6, 0x23d: 0xa6, 0x23e: 0xa6, 0x23f: 0xa6,
// Block 0x9, offset 0x240
0x240: 0xa6, 0x241: 0xa6, 0x242: 0xa6, 0x243: 0xa6, 0x244: 0xa6, 0x245: 0xa6, 0x246: 0xa6, 0x247: 0xa6,
0x248: 0xa6, 0x249: 0xa6, 0x24a: 0xa6, 0x24b: 0xa6, 0x24c: 0xa6, 0x24d: 0xa6, 0x24e: 0xa6, 0x24f: 0xa6,
0x250: 0xa6, 0x251: 0xa6, 0x252: 0xa6, 0x253: 0xa6, 0x254: 0xa6, 0x255: 0xa6, 0x256: 0xa6, 0x257: 0xa6,
0x258: 0xa6, 0x259: 0xa6, 0x25a: 0xa6, 0x25b: 0xa6, 0x25c: 0xa6, 0x25d: 0xa6, 0x25e: 0xa6, 0x25f: 0xa6,
0x260: 0xa6, 0x261: 0xa6, 0x262: 0xa6, 0x263: 0xa6, 0x264: 0xa6, 0x265: 0xa6, 0x266: 0xa6, 0x267: 0xa6,
0x268: 0xa6, 0x269: 0xa6, 0x26a: 0xa6, 0x26b: 0xa6, 0x26c: 0xa6, 0x26d: 0xa6, 0x26e: 0xa6, 0x26f: 0xa6,
0x270: 0xa6, 0x271: 0xa6, 0x272: 0xa6, 0x273: 0xa6, 0x274: 0xa6, 0x275: 0xa6, 0x276: 0xa6, 0x277: 0xa6,
0x278: 0xa6, 0x279: 0xa6, 0x27a: 0xa6, 0x27b: 0xa6, 0x27c: 0xa6, 0x27d: 0xa6, 0x27e: 0xa6, 0x27f: 0xa6,
// Block 0xa, offset 0x280
0x280: 0xa6, 0x281: 0xa6, 0x282: 0xa6, 0x283: 0xa6, 0x284: 0xa6, 0x285: 0xa6, 0x286: 0xa6, 0x287: 0xa6,
0x288: 0xa6, 0x289: 0xa6, 0x28a: 0xa6, 0x28b: 0xa6, 0x28c: 0xa6, 0x28d: 0xa6, 0x28e: 0xa6, 0x28f: 0xa6,
0x290: 0xa6, 0x291: 0xa6, 0x292: 0xea, 0x293: 0xeb, 0x294: 0xa6, 0x295: 0xa6, 0x296: 0xa6, 0x297: 0xa6,
0x298: 0xec, 0x299: 0x41, 0x29a: 0x42, 0x29b: 0xed, 0x29c: 0x43, 0x29d: 0x44, 0x29e: 0x45, 0x29f: 0x46,
0x2a0: 0xee, 0x2a1: 0xef, 0x2a2: 0xf0, 0x2a3: 0xf1, 0x2a4: 0xf2, 0x2a5: 0xf3, 0x2a6: 0xf4, 0x2a7: 0xf5,
0x2a8: 0xf6, 0x2a9: 0xf7, 0x2aa: 0xf8, 0x2ab: 0xf9, 0x2ac: 0xfa, 0x2ad: 0xfb, 0x2ae: 0xfc, 0x2af: 0xfd,
0x2b0: 0xa6, 0x2b1: 0xa6, 0x2b2: 0xa6, 0x2b3: 0xa6, 0x2b4: 0xa6, 0x2b5: 0xa6, 0x2b6: 0xa6, 0x2b7: 0xa6,
0x2b8: 0xa6, 0x2b9: 0xa6, 0x2ba: 0xa6, 0x2bb: 0xa6, 0x2bc: 0xa6, 0x2bd: 0xa6, 0x2be: 0xa6, 0x2bf: 0xa6,
// Block 0xb, offset 0x2c0
0x2c0: 0xa6, 0x2c1: 0xa6, 0x2c2: 0xa6, 0x2c3: 0xa6, 0x2c4: 0xa6, 0x2c5: 0xa6, 0x2c6: 0xa6, 0x2c7: 0xa6,
0x2c8: 0xa6, 0x2c9: 0xa6, 0x2ca: 0xa6, 0x2cb: 0xa6, 0x2cc: 0xa6, 0x2cd: 0xa6, 0x2ce: 0xa6, 0x2cf: 0xa6,
0x2d0: 0xa6, 0x2d1: 0xa6, 0x2d2: 0xa6, 0x2d3: 0xa6, 0x2d4: 0xa6, 0x2d5: 0xa6, 0x2d6: 0xa6, 0x2d7: 0xa6,
0x2d8: 0xa6, 0x2d9: 0xa6, 0x2da: 0xa6, 0x2db: 0xa6, 0x2dc: 0xa6, 0x2dd: 0xa6, 0x2de: 0xfe, 0x2df: 0xff,
// Block 0xc, offset 0x300
0x300: 0x100, 0x301: 0x100, 0x302: 0x100, 0x303: 0x100, 0x304: 0x100, 0x305: 0x100, 0x306: 0x100, 0x307: 0x100,
0x308: 0x100, 0x309: 0x100, 0x30a: 0x100, 0x30b: 0x100, 0x30c: 0x100, 0x30d: 0x100, 0x30e: 0x100, 0x30f: 0x100,
0x310: 0x100, 0x311: 0x100, 0x312: 0x100, 0x313: 0x100, 0x314: 0x100, 0x315: 0x100, 0x316: 0x100, 0x317: 0x100,
0x318: 0x100, 0x319: 0x100, 0x31a: 0x100, 0x31b: 0x100, 0x31c: 0x100, 0x31d: 0x100, 0x31e: 0x100, 0x31f: 0x100,
0x320: 0x100, 0x321: 0x100, 0x322: 0x100, 0x323: 0x100, 0x324: 0x100, 0x325: 0x100, 0x326: 0x100, 0x327: 0x100,
0x328: 0x100, 0x329: 0x100, 0x32a: 0x100, 0x32b: 0x100, 0x32c: 0x100, 0x32d: 0x100, 0x32e: 0x100, 0x32f: 0x100,
0x330: 0x100, 0x331: 0x100, 0x332: 0x100, 0x333: 0x100, 0x334: 0x100, 0x335: 0x100, 0x336: 0x100, 0x337: 0x100,
0x338: 0x100, 0x339: 0x100, 0x33a: 0x100, 0x33b: 0x100, 0x33c: 0x100, 0x33d: 0x100, 0x33e: 0x100, 0x33f: 0x100,
// Block 0xd, offset 0x340
0x340: 0x100, 0x341: 0x100, 0x342: 0x100, 0x343: 0x100, 0x344: 0x100, 0x345: 0x100, 0x346: 0x100, 0x347: 0x100,
0x348: 0x100, 0x349: 0x100, 0x34a: 0x100, 0x34b: 0x100, 0x34c: 0x100, 0x34d: 0x100, 0x34e: 0x100, 0x34f: 0x100,
0x350: 0x100, 0x351: 0x100, 0x352: 0x100, 0x353: 0x100, 0x354: 0x100, 0x355: 0x100, 0x356: 0x100, 0x357: 0x100,
0x358: 0x100, 0x359: 0x100, 0x35a: 0x100, 0x35b: 0x100, 0x35c: 0x100, 0x35d: 0x100, 0x35e: 0x100, 0x35f: 0x100,
0x360: 0x100, 0x361: 0x100, 0x362: 0x100, 0x363: 0x100, 0x364: 0x101, 0x365: 0x102, 0x366: 0x103, 0x367: 0x104,
0x368: 0x47, 0x369: 0x105, 0x36a: 0x106, 0x36b: 0x48, 0x36c: 0x49, 0x36d: 0x4a, 0x36e: 0x4b, 0x36f: 0x4c,
0x370: 0x107, 0x371: 0x4d, 0x372: 0x4e, 0x373: 0x4f, 0x374: 0x50, 0x375: 0x51, 0x376: 0x108, 0x377: 0x52,
0x378: 0x53, 0x379: 0x54, 0x37a: 0x55, 0x37b: 0x56, 0x37c: 0x57, 0x37d: 0x58, 0x37e: 0x59, 0x37f: 0x5a,
// Block 0xe, offset 0x380
0x380: 0x109, 0x381: 0x10a, 0x382: 0xa6, 0x383: 0x10b, 0x384: 0x10c, 0x385: 0xa2, 0x386: 0x10d, 0x387: 0x10e,
0x388: 0x100, 0x389: 0x100, 0x38a: 0x10f, 0x38b: 0x110, 0x38c: 0x111, 0x38d: 0x112, 0x38e: 0x113, 0x38f: 0x114,
0x390: 0x115, 0x391: 0xa6, 0x392: 0x116, 0x393: 0x117, 0x394: 0x118, 0x395: 0x5b, 0x396: 0x5c, 0x397: 0x100,
0x398: 0xa6, 0x399: 0xa6, 0x39a: 0xa6, 0x39b: 0xa6, 0x39c: 0x119, 0x39d: 0x11a, 0x39e: 0x5d, 0x39f: 0x100,
0x3a0: 0x11b, 0x3a1: 0x11c, 0x3a2: 0x11d, 0x3a3: 0x11e, 0x3a4: 0x11f, 0x3a5: 0x100, 0x3a6: 0x120, 0x3a7: 0x121,
0x3a8: 0x122, 0x3a9: 0x123, 0x3aa: 0x124, 0x3ab: 0x5e, 0x3ac: 0x125, 0x3ad: 0x126, 0x3ae: 0x5f, 0x3af: 0x100,
0x3b0: 0x127, 0x3b1: 0x128, 0x3b2: 0x129, 0x3b3: 0x12a, 0x3b4: 0x12b, 0x3b5: 0x100, 0x3b6: 0x100, 0x3b7: 0x100,
0x3b8: 0x100, 0x3b9: 0x12c, 0x3ba: 0x12d, 0x3bb: 0x12e, 0x3bc: 0x12f, 0x3bd: 0x130, 0x3be: 0x131, 0x3bf: 0x132,
// Block 0xf, offset 0x3c0
0x3c0: 0x133, 0x3c1: 0x134, 0x3c2: 0x135, 0x3c3: 0x136, 0x3c4: 0x137, 0x3c5: 0x138, 0x3c6: 0x139, 0x3c7: 0x13a,
0x3c8: 0x13b, 0x3c9: 0x13c, 0x3ca: 0x13d, 0x3cb: 0x13e, 0x3cc: 0x60, 0x3cd: 0x61, 0x3ce: 0x100, 0x3cf: 0x100,
0x3d0: 0x13f, 0x3d1: 0x140, 0x3d2: 0x141, 0x3d3: 0x142, 0x3d4: 0x100, 0x3d5: 0x100, 0x3d6: 0x143, 0x3d7: 0x144,
0x3d8: 0x145, 0x3d9: 0x146, 0x3da: 0x147, 0x3db: 0x148, 0x3dc: 0x149, 0x3dd: 0x14a, 0x3de: 0x100, 0x3df: 0x100,
0x3e0: 0x14b, 0x3e1: 0x100, 0x3e2: 0x14c, 0x3e3: 0x14d, 0x3e4: 0x62, 0x3e5: 0x14e, 0x3e6: 0x14f, 0x3e7: 0x150,
0x3e8: 0x151, 0x3e9: 0x152, 0x3ea: 0x153, 0x3eb: 0x154, 0x3ec: 0x155, 0x3ed: 0x100, 0x3ee: 0x100, 0x3ef: 0x100,
0x3f0: 0x156, 0x3f1: 0x157, 0x3f2: 0x158, 0x3f3: 0x100, 0x3f4: 0x159, 0x3f5: 0x15a, 0x3f6: 0x15b, 0x3f7: 0x100,
0x3f8: 0x100, 0x3f9: 0x100, 0x3fa: 0x100, 0x3fb: 0x15c, 0x3fc: 0x15d, 0x3fd: 0x15e, 0x3fe: 0x15f, 0x3ff: 0x160,
// Block 0x10, offset 0x400
0x400: 0xa6, 0x401: 0xa6, 0x402: 0xa6, 0x403: 0xa6, 0x404: 0xa6, 0x405: 0xa6, 0x406: 0xa6, 0x407: 0xa6,
0x408: 0xa6, 0x409: 0xa6, 0x40a: 0xa6, 0x40b: 0xa6, 0x40c: 0xa6, 0x40d: 0xa6, 0x40e: 0x161, 0x40f: 0x100,
0x410: 0xa2, 0x411: 0x162, 0x412: 0xa6, 0x413: 0xa6, 0x414: 0xa6, 0x415: 0x163, 0x416: 0x100, 0x417: 0x100,
0x418: 0x100, 0x419: 0x100, 0x41a: 0x100, 0x41b: 0x100, 0x41c: 0x100, 0x41d: 0x100, 0x41e: 0x100, 0x41f: 0x100,
0x420: 0x100, 0x421: 0x100, 0x422: 0x100, 0x423: 0x100, 0x424: 0x100, 0x425: 0x100, 0x426: 0x100, 0x427: 0x100,
0x428: 0x100, 0x429: 0x100, 0x42a: 0x100, 0x42b: 0x100, 0x42c: 0x100, 0x42d: 0x100, 0x42e: 0x100, 0x42f: 0x100,
0x430: 0x100, 0x431: 0x100, 0x432: 0x100, 0x433: 0x100, 0x434: 0x100, 0x435: 0x100, 0x436: 0x100, 0x437: 0x100,
0x438: 0x100, 0x439: 0x100, 0x43a: 0x100, 0x43b: 0x100, 0x43c: 0x100, 0x43d: 0x100, 0x43e: 0x164, 0x43f: 0x165,
// Block 0x11, offset 0x440
0x440: 0xa6, 0x441: 0xa6, 0x442: 0xa6, 0x443: 0xa6, 0x444: 0xa6, 0x445: 0xa6, 0x446: 0xa6, 0x447: 0xa6,
0x448: 0xa6, 0x449: 0xa6, 0x44a: 0xa6, 0x44b: 0xa6, 0x44c: 0xa6, 0x44d: 0xa6, 0x44e: 0xa6, 0x44f: 0xa6,
0x450: 0x166, 0x451: 0x167, 0x452: 0x100, 0x453: 0x100, 0x454: 0x100, 0x455: 0x100, 0x456: 0x100, 0x457: 0x100,
0x458: 0x100, 0x459: 0x100, 0x45a: 0x100, 0x45b: 0x100, 0x45c: 0x100, 0x45d: 0x100, 0x45e: 0x100, 0x45f: 0x100,
0x460: 0x100, 0x461: 0x100, 0x462: 0x100, 0x463: 0x100, 0x464: 0x100, 0x465: 0x100, 0x466: 0x100, 0x467: 0x100,
0x468: 0x100, 0x469: 0x100, 0x46a: 0x100, 0x46b: 0x100, 0x46c: 0x100, 0x46d: 0x100, 0x46e: 0x100, 0x46f: 0x100,
0x470: 0x100, 0x471: 0x100, 0x472: 0x100, 0x473: 0x100, 0x474: 0x100, 0x475: 0x100, 0x476: 0x100, 0x477: 0x100,
0x478: 0x100, 0x479: 0x100, 0x47a: 0x100, 0x47b: 0x100, 0x47c: 0x100, 0x47d: 0x100, 0x47e: 0x100, 0x47f: 0x100,
// Block 0x12, offset 0x480
0x480: 0x100, 0x481: 0x100, 0x482: 0x100, 0x483: 0x100, 0x484: 0x100, 0x485: 0x100, 0x486: 0x100, 0x487: 0x100,
0x488: 0x100, 0x489: 0x100, 0x48a: 0x100, 0x48b: 0x100, 0x48c: 0x100, 0x48d: 0x100, 0x48e: 0x100, 0x48f: 0x100,
0x490: 0xa6, 0x491: 0xa6, 0x492: 0xa6, 0x493: 0xa6, 0x494: 0xa6, 0x495: 0xa6, 0x496: 0xa6, 0x497: 0xa6,
0x498: 0xa6, 0x499: 0x14a, 0x49a: 0x100, 0x49b: 0x100, 0x49c: 0x100, 0x49d: 0x100, 0x49e: 0x100, 0x49f: 0x100,
0x4a0: 0x100, 0x4a1: 0x100, 0x4a2: 0x100, 0x4a3: 0x100, 0x4a4: 0x100, 0x4a5: 0x100, 0x4a6: 0x100, 0x4a7: 0x100,
0x4a8: 0x100, 0x4a9: 0x100, 0x4aa: 0x100, 0x4ab: 0x100, 0x4ac: 0x100, 0x4ad: 0x100, 0x4ae: 0x100, 0x4af: 0x100,
0x4b0: 0x100, 0x4b1: 0x100, 0x4b2: 0x100, 0x4b3: 0x100, 0x4b4: 0x100, 0x4b5: 0x100, 0x4b6: 0x100, 0x4b7: 0x100,
0x4b8: 0x100, 0x4b9: 0x100, 0x4ba: 0x100, 0x4bb: 0x100, 0x4bc: 0x100, 0x4bd: 0x100, 0x4be: 0x100, 0x4bf: 0x100,
// Block 0x13, offset 0x4c0
0x4c0: 0x100, 0x4c1: 0x100, 0x4c2: 0x100, 0x4c3: 0x100, 0x4c4: 0x100, 0x4c5: 0x100, 0x4c6: 0x100, 0x4c7: 0x100,
0x4c8: 0x100, 0x4c9: 0x100, 0x4ca: 0x100, 0x4cb: 0x100, 0x4cc: 0x100, 0x4cd: 0x100, 0x4ce: 0x100, 0x4cf: 0x100,
0x4d0: 0x100, 0x4d1: 0x100, 0x4d2: 0x100, 0x4d3: 0x100, 0x4d4: 0x100, 0x4d5: 0x100, 0x4d6: 0x100, 0x4d7: 0x100,
0x4d8: 0x100, 0x4d9: 0x100, 0x4da: 0x100, 0x4db: 0x100, 0x4dc: 0x100, 0x4dd: 0x100, 0x4de: 0x100, 0x4df: 0x100,
0x4e0: 0xa6, 0x4e1: 0xa6, 0x4e2: 0xa6, 0x4e3: 0xa6, 0x4e4: 0xa6, 0x4e5: 0xa6, 0x4e6: 0xa6, 0x4e7: 0xa6,
0x4e8: 0x154, 0x4e9: 0x168, 0x4ea: 0x169, 0x4eb: 0x16a, 0x4ec: 0x16b, 0x4ed: 0x16c, 0x4ee: 0x16d, 0x4ef: 0x100,
0x4f0: 0x100, 0x4f1: 0x100, 0x4f2: 0x100, 0x4f3: 0x100, 0x4f4: 0x100, 0x4f5: 0x100, 0x4f6: 0x100, 0x4f7: 0x100,
0x4f8: 0x100, 0x4f9: 0x16e, 0x4fa: 0x16f, 0x4fb: 0x100, 0x4fc: 0xa6, 0x4fd: 0x170, 0x4fe: 0x171, 0x4ff: 0x172,
// Block 0x14, offset 0x500
0x500: 0xa6, 0x501: 0xa6, 0x502: 0xa6, 0x503: 0xa6, 0x504: 0xa6, 0x505: 0xa6, 0x506: 0xa6, 0x507: 0xa6,
0x508: 0xa6, 0x509: 0xa6, 0x50a: 0xa6, 0x50b: 0xa6, 0x50c: 0xa6, 0x50d: 0xa6, 0x50e: 0xa6, 0x50f: 0xa6,
0x510: 0xa6, 0x511: 0xa6, 0x512: 0xa6, 0x513: 0xa6, 0x514: 0xa6, 0x515: 0xa6, 0x516: 0xa6, 0x517: 0xa6,
0x518: 0xa6, 0x519: 0xa6, 0x51a: 0xa6, 0x51b: 0xa6, 0x51c: 0xa6, 0x51d: 0xa6, 0x51e: 0xa6, 0x51f: 0x173,
0x520: 0xa6, 0x521: 0xa6, 0x522: 0xa6, 0x523: 0xa6, 0x524: 0xa6, 0x525: 0xa6, 0x526: 0xa6, 0x527: 0xa6,
0x528: 0xa6, 0x529: 0xa6, 0x52a: 0xa6, 0x52b: 0xa6, 0x52c: 0xa6, 0x52d: 0xa6, 0x52e: 0xa6, 0x52f: 0xa6,
0x530: 0xa6, 0x531: 0xa6, 0x532: 0xa6, 0x533: 0x174, 0x534: 0x175, 0x535: 0x100, 0x536: 0x100, 0x537: 0x100,
0x538: 0x100, 0x539: 0x100, 0x53a: 0x100, 0x53b: 0x100, 0x53c: 0x100, 0x53d: 0x100, 0x53e: 0x100, 0x53f: 0x100,
// Block 0x15, offset 0x540
0x540: 0x100, 0x541: 0x100, 0x542: 0x100, 0x543: 0x100, 0x544: 0x100, 0x545: 0x100, 0x546: 0x100, 0x547: 0x100,
0x548: 0x100, 0x549: 0x100, 0x54a: 0x100, 0x54b: 0x100, 0x54c: 0x100, 0x54d: 0x100, 0x54e: 0x100, 0x54f: 0x100,
0x550: 0x100, 0x551: 0x100, 0x552: 0x100, 0x553: 0x100, 0x554: 0x100, 0x555: 0x100, 0x556: 0x100, 0x557: 0x100,
0x558: 0x100, 0x559: 0x100, 0x55a: 0x100, 0x55b: 0x100, 0x55c: 0x100, 0x55d: 0x100, 0x55e: 0x100, 0x55f: 0x100,
0x560: 0x100, 0x561: 0x100, 0x562: 0x100, 0x563: 0x100, 0x564: 0x100, 0x565: 0x100, 0x566: 0x100, 0x567: 0x100,
0x568: 0x100, 0x569: 0x100, 0x56a: 0x100, 0x56b: 0x100, 0x56c: 0x100, 0x56d: 0x100, 0x56e: 0x100, 0x56f: 0x100,
0x570: 0x100, 0x571: 0x100, 0x572: 0x100, 0x573: 0x100, 0x574: 0x100, 0x575: 0x100, 0x576: 0x100, 0x577: 0x100,
0x578: 0x100, 0x579: 0x100, 0x57a: 0x100, 0x57b: 0x100, 0x57c: 0x100, 0x57d: 0x100, 0x57e: 0x100, 0x57f: 0x176,
// Block 0x16, offset 0x580
0x580: 0xa6, 0x581: 0xa6, 0x582: 0xa6, 0x583: 0xa6, 0x584: 0x177, 0x585: 0x178, 0x586: 0xa6, 0x587: 0xa6,
0x588: 0xa6, 0x589: 0xa6, 0x58a: 0xa6, 0x58b: 0x179, 0x58c: 0x100, 0x58d: 0x100, 0x58e: 0x100, 0x58f: 0x100,
0x590: 0x100, 0x591: 0x100, 0x592: 0x100, 0x593: 0x100, 0x594: 0x100, 0x595: 0x100, 0x596: 0x100, 0x597: 0x100,
0x598: 0x100, 0x599: 0x100, 0x59a: 0x100, 0x59b: 0x100, 0x59c: 0x100, 0x59d: 0x100, 0x59e: 0x100, 0x59f: 0x100,
0x5a0: 0x100, 0x5a1: 0x100, 0x5a2: 0x100, 0x5a3: 0x100, 0x5a4: 0x100, 0x5a5: 0x100, 0x5a6: 0x100, 0x5a7: 0x100,
0x5a8: 0x100, 0x5a9: 0x100, 0x5aa: 0x100, 0x5ab: 0x100, 0x5ac: 0x100, 0x5ad: 0x100, 0x5ae: 0x100, 0x5af: 0x100,
0x5b0: 0xa6, 0x5b1: 0x17a, 0x5b2: 0x17b, 0x5b3: 0x100, 0x5b4: 0x100, 0x5b5: 0x100, 0x5b6: 0x100, 0x5b7: 0x100,
0x5b8: 0x100, 0x5b9: 0x100, 0x5ba: 0x100, 0x5bb: 0x100, 0x5bc: 0x100, 0x5bd: 0x100, 0x5be: 0x100, 0x5bf: 0x100,
// Block 0x17, offset 0x5c0
0x5c0: 0x100, 0x5c1: 0x100, 0x5c2: 0x100, 0x5c3: 0x100, 0x5c4: 0x100, 0x5c5: 0x100, 0x5c6: 0x100, 0x5c7: 0x100,
0x5c8: 0x100, 0x5c9: 0x100, 0x5ca: 0x100, 0x5cb: 0x100, 0x5cc: 0x100, 0x5cd: 0x100, 0x5ce: 0x100, 0x5cf: 0x100,
0x5d0: 0x100, 0x5d1: 0x100, 0x5d2: 0x100, 0x5d3: 0x100, 0x5d4: 0x100, 0x5d5: 0x100, 0x5d6: 0x100, 0x5d7: 0x100,
0x5d8: 0x100, 0x5d9: 0x100, 0x5da: 0x100, 0x5db: 0x100, 0x5dc: 0x100, 0x5dd: 0x100, 0x5de: 0x100, 0x5df: 0x100,
0x5e0: 0x100, 0x5e1: 0x100, 0x5e2: 0x100, 0x5e3: 0x100, 0x5e4: 0x100, 0x5e5: 0x100, 0x5e6: 0x100, 0x5e7: 0x100,
0x5e8: 0x100, 0x5e9: 0x100, 0x5ea: 0x100, 0x5eb: 0x100, 0x5ec: 0x100, 0x5ed: 0x100, 0x5ee: 0x100, 0x5ef: 0x100,
0x5f0: 0x100, 0x5f1: 0x100, 0x5f2: 0x100, 0x5f3: 0x100, 0x5f4: 0x100, 0x5f5: 0x100, 0x5f6: 0x100, 0x5f7: 0x100,
0x5f8: 0x100, 0x5f9: 0x100, 0x5fa: 0x100, 0x5fb: 0x100, 0x5fc: 0x17c, 0x5fd: 0x17d, 0x5fe: 0xa2, 0x5ff: 0x17e,
// Block 0x18, offset 0x600
0x600: 0xa2, 0x601: 0xa2, 0x602: 0xa2, 0x603: 0x17f, 0x604: 0x180, 0x605: 0x181, 0x606: 0x182, 0x607: 0x183,
0x608: 0xa2, 0x609: 0x184, 0x60a: 0x100, 0x60b: 0x185, 0x60c: 0xa2, 0x60d: 0x186, 0x60e: 0x100, 0x60f: 0x100,
0x610: 0x63, 0x611: 0x64, 0x612: 0x65, 0x613: 0x66, 0x614: 0x67, 0x615: 0x68, 0x616: 0x69, 0x617: 0x6a,
0x618: 0x6b, 0x619: 0x6c, 0x61a: 0x6d, 0x61b: 0x6e, 0x61c: 0x6f, 0x61d: 0x70, 0x61e: 0x71, 0x61f: 0x72,
0x620: 0xa2, 0x621: 0xa2, 0x622: 0xa2, 0x623: 0xa2, 0x624: 0xa2, 0x625: 0xa2, 0x626: 0xa2, 0x627: 0xa2,
0x628: 0x187, 0x629: 0x188, 0x62a: 0x189, 0x62b: 0x100, 0x62c: 0x100, 0x62d: 0x100, 0x62e: 0x100, 0x62f: 0x100,
0x630: 0x100, 0x631: 0x100, 0x632: 0x100, 0x633: 0x100, 0x634: 0x100, 0x635: 0x100, 0x636: 0x100, 0x637: 0x100,
0x638: 0x100, 0x639: 0x100, 0x63a: 0x100, 0x63b: 0x100, 0x63c: 0x18a, 0x63d: 0x100, 0x63e: 0x100, 0x63f: 0x100,
// Block 0x19, offset 0x640
0x640: 0x73, 0x641: 0x74, 0x642: 0x18b, 0x643: 0x100, 0x644: 0x18c, 0x645: 0x18d, 0x646: 0x100, 0x647: 0x100,
0x648: 0x100, 0x649: 0x100, 0x64a: 0x18e, 0x64b: 0x18f, 0x64c: 0x100, 0x64d: 0x100, 0x64e: 0x100, 0x64f: 0x100,
0x650: 0x100, 0x651: 0x100, 0x652: 0x100, 0x653: 0x190, 0x654: 0x100, 0x655: 0x100, 0x656: 0x100, 0x657: 0x100,
0x658: 0x100, 0x659: 0x100, 0x65a: 0x100, 0x65b: 0x100, 0x65c: 0x100, 0x65d: 0x100, 0x65e: 0x100, 0x65f: 0x191,
0x660: 0x127, 0x661: 0x127, 0x662: 0x127, 0x663: 0x192, 0x664: 0x75, 0x665: 0x193, 0x666: 0x100, 0x667: 0x100,
0x668: 0x100, 0x669: 0x100, 0x66a: 0x100, 0x66b: 0x100, 0x66c: 0x100, 0x66d: 0x100, 0x66e: 0x100, 0x66f: 0x100,
0x670: 0x100, 0x671: 0x194, 0x672: 0x195, 0x673: 0x100, 0x674: 0x196, 0x675: 0x100, 0x676: 0x100, 0x677: 0x100,
0x678: 0x76, 0x679: 0x77, 0x67a: 0x78, 0x67b: 0x197, 0x67c: 0x100, 0x67d: 0x100, 0x67e: 0x100, 0x67f: 0x100,
// Block 0x1a, offset 0x680
0x680: 0x198, 0x681: 0xa2, 0x682: 0x199, 0x683: 0x19a, 0x684: 0x79, 0x685: 0x7a, 0x686: 0x19b, 0x687: 0x19c,
0x688: 0x7b, 0x689: 0x19d, 0x68a: 0x100, 0x68b: 0x100, 0x68c: 0xa2, 0x68d: 0xa2, 0x68e: 0xa2, 0x68f: 0xa2,
0x690: 0xa2, 0x691: 0xa2, 0x692: 0xa2, 0x693: 0xa2, 0x694: 0xa2, 0x695: 0xa2, 0x696: 0xa2, 0x697: 0xa2,
0x698: 0xa2, 0x699: 0xa2, 0x69a: 0xa2, 0x69b: 0x19e, 0x69c: 0xa2, 0x69d: 0x19f, 0x69e: 0xa2, 0x69f: 0x1a0,
0x6a0: 0x1a1, 0x6a1: 0x1a2, 0x6a2: 0x1a3, 0x6a3: 0x100, 0x6a4: 0xa2, 0x6a5: 0xa2, 0x6a6: 0xa2, 0x6a7: 0xa2,
0x6a8: 0xa2, 0x6a9: 0x1a4, 0x6aa: 0x1a5, 0x6ab: 0x1a6, 0x6ac: 0xa2, 0x6ad: 0xa2, 0x6ae: 0x1a7, 0x6af: 0x1a8,
0x6b0: 0x100, 0x6b1: 0x100, 0x6b2: 0x100, 0x6b3: 0x100, 0x6b4: 0x100, 0x6b5: 0x100, 0x6b6: 0x100, 0x6b7: 0x100,
0x6b8: 0x100, 0x6b9: 0x100, 0x6ba: 0x100, 0x6bb: 0x100, 0x6bc: 0x100, 0x6bd: 0x100, 0x6be: 0x100, 0x6bf: 0x100,
// Block 0x1b, offset 0x6c0
0x6c0: 0xa6, 0x6c1: 0xa6, 0x6c2: 0xa6, 0x6c3: 0xa6, 0x6c4: 0xa6, 0x6c5: 0xa6, 0x6c6: 0xa6, 0x6c7: 0xa6,
0x6c8: 0xa6, 0x6c9: 0xa6, 0x6ca: 0xa6, 0x6cb: 0xa6, 0x6cc: 0xa6, 0x6cd: 0xa6, 0x6ce: 0xa6, 0x6cf: 0xa6,
0x6d0: 0xa6, 0x6d1: 0xa6, 0x6d2: 0xa6, 0x6d3: 0xa6, 0x6d4: 0xa6, 0x6d5: 0xa6, 0x6d6: 0xa6, 0x6d7: 0xa6,
0x6d8: 0xa6, 0x6d9: 0xa6, 0x6da: 0xa6, 0x6db: 0x1a9, 0x6dc: 0xa6, 0x6dd: 0xa6, 0x6de: 0xa6, 0x6df: 0xa6,
0x6e0: 0xa6, 0x6e1: 0xa6, 0x6e2: 0xa6, 0x6e3: 0xa6, 0x6e4: 0xa6, 0x6e5: 0xa6, 0x6e6: 0xa6, 0x6e7: 0xa6,
0x6e8: 0xa6, 0x6e9: 0xa6, 0x6ea: 0xa6, 0x6eb: 0xa6, 0x6ec: 0xa6, 0x6ed: 0xa6, 0x6ee: 0xa6, 0x6ef: 0xa6,
0x6f0: 0xa6, 0x6f1: 0xa6, 0x6f2: 0xa6, 0x6f3: 0xa6, 0x6f4: 0xa6, 0x6f5: 0xa6, 0x6f6: 0xa6, 0x6f7: 0xa6,
0x6f8: 0xa6, 0x6f9: 0xa6, 0x6fa: 0xa6, 0x6fb: 0xa6, 0x6fc: 0xa6, 0x6fd: 0xa6, 0x6fe: 0xa6, 0x6ff: 0xa6,
// Block 0x1c, offset 0x700
0x700: 0xa6, 0x701: 0xa6, 0x702: 0xa6, 0x703: 0xa6, 0x704: 0xa6, 0x705: 0xa6, 0x706: 0xa6, 0x707: 0xa6,
0x708: 0xa6, 0x709: 0xa6, 0x70a: 0xa6, 0x70b: 0xa6, 0x70c: 0xa6, 0x70d: 0xa6, 0x70e: 0xa6, 0x70f: 0xa6,
0x710: 0xa6, 0x711: 0xa6, 0x712: 0xa6, 0x713: 0xa6, 0x714: 0xa6, 0x715: 0xa6, 0x716: 0xa6, 0x717: 0xa6,
0x718: 0xa6, 0x719: 0xa6, 0x71a: 0xa6, 0x71b: 0xa6, 0x71c: 0x1aa, 0x71d: 0xa6, 0x71e: 0xa6, 0x71f: 0xa6,
0x720: 0x1ab, 0x721: 0xa6, 0x722: 0xa6, 0x723: 0xa6, 0x724: 0xa6, 0x725: 0xa6, 0x726: 0xa6, 0x727: 0xa6,
0x728: 0xa6, 0x729: 0xa6, 0x72a: 0xa6, 0x72b: 0xa6, 0x72c: 0xa6, 0x72d: 0xa6, 0x72e: 0xa6, 0x72f: 0xa6,
0x730: 0xa6, 0x731: 0xa6, 0x732: 0xa6, 0x733: 0xa6, 0x734: 0xa6, 0x735: 0xa6, 0x736: 0xa6, 0x737: 0xa6,
0x738: 0xa6, 0x739: 0xa6, 0x73a: 0xa6, 0x73b: 0xa6, 0x73c: 0xa6, 0x73d: 0xa6, 0x73e: 0xa6, 0x73f: 0xa6,
// Block 0x1d, offset 0x740
0x740: 0xa6, 0x741: 0xa6, 0x742: 0xa6, 0x743: 0xa6, 0x744: 0xa6, 0x745: 0xa6, 0x746: 0xa6, 0x747: 0xa6,
0x748: 0xa6, 0x749: 0xa6, 0x74a: 0xa6, 0x74b: 0xa6, 0x74c: 0xa6, 0x74d: 0xa6, 0x74e: 0xa6, 0x74f: 0xa6,
0x750: 0xa6, 0x751: 0xa6, 0x752: 0xa6, 0x753: 0xa6, 0x754: 0xa6, 0x755: 0xa6, 0x756: 0xa6, 0x757: 0xa6,
0x758: 0xa6, 0x759: 0xa6, 0x75a: 0xa6, 0x75b: 0xa6, 0x75c: 0xa6, 0x75d: 0xa6, 0x75e: 0xa6, 0x75f: 0xa6,
0x760: 0xa6, 0x761: 0xa6, 0x762: 0xa6, 0x763: 0xa6, 0x764: 0xa6, 0x765: 0xa6, 0x766: 0xa6, 0x767: 0xa6,
0x768: 0xa6, 0x769: 0xa6, 0x76a: 0xa6, 0x76b: 0xa6, 0x76c: 0xa6, 0x76d: 0xa6, 0x76e: 0xa6, 0x76f: 0xa6,
0x770: 0xa6, 0x771: 0xa6, 0x772: 0xa6, 0x773: 0xa6, 0x774: 0xa6, 0x775: 0xa6, 0x776: 0xa6, 0x777: 0xa6,
0x778: 0xa6, 0x779: 0xa6, 0x77a: 0x1ac, 0x77b: 0xa6, 0x77c: 0xa6, 0x77d: 0xa6, 0x77e: 0xa6, 0x77f: 0xa6,
// Block 0x1e, offset 0x780
0x780: 0xa6, 0x781: 0xa6, 0x782: 0xa6, 0x783: 0xa6, 0x784: 0xa6, 0x785: 0xa6, 0x786: 0xa6, 0x787: 0xa6,
0x788: 0xa6, 0x789: 0xa6, 0x78a: 0xa6, 0x78b: 0xa6, 0x78c: 0xa6, 0x78d: 0xa6, 0x78e: 0xa6, 0x78f: 0xa6,
0x790: 0xa6, 0x791: 0xa6, 0x792: 0xa6, 0x793: 0xa6, 0x794: 0xa6, 0x795: 0xa6, 0x796: 0xa6, 0x797: 0xa6,
0x798: 0xa6, 0x799: 0xa6, 0x79a: 0xa6, 0x79b: 0xa6, 0x79c: 0xa6, 0x79d: 0xa6, 0x79e: 0xa6, 0x79f: 0xa6,
0x7a0: 0xa6, 0x7a1: 0xa6, 0x7a2: 0xa6, 0x7a3: 0xa6, 0x7a4: 0xa6, 0x7a5: 0xa6, 0x7a6: 0xa6, 0x7a7: 0xa6,
0x7a8: 0xa6, 0x7a9: 0xa6, 0x7aa: 0xa6, 0x7ab: 0xa6, 0x7ac: 0xa6, 0x7ad: 0xa6, 0x7ae: 0xa6, 0x7af: 0x1ad,
0x7b0: 0x100, 0x7b1: 0x100, 0x7b2: 0x100, 0x7b3: 0x100, 0x7b4: 0x100, 0x7b5: 0x100, 0x7b6: 0x100, 0x7b7: 0x100,
0x7b8: 0x100, 0x7b9: 0x100, 0x7ba: 0x100, 0x7bb: 0x100, 0x7bc: 0x100, 0x7bd: 0x100, 0x7be: 0x100, 0x7bf: 0x100,
// Block 0x1f, offset 0x7c0
0x7c0: 0x100, 0x7c1: 0x100, 0x7c2: 0x100, 0x7c3: 0x100, 0x7c4: 0x100, 0x7c5: 0x100, 0x7c6: 0x100, 0x7c7: 0x100,
0x7c8: 0x100, 0x7c9: 0x100, 0x7ca: 0x100, 0x7cb: 0x100, 0x7cc: 0x100, 0x7cd: 0x100, 0x7ce: 0x100, 0x7cf: 0x100,
0x7d0: 0x100, 0x7d1: 0x100, 0x7d2: 0x100, 0x7d3: 0x100, 0x7d4: 0x100, 0x7d5: 0x100, 0x7d6: 0x100, 0x7d7: 0x100,
0x7d8: 0x100, 0x7d9: 0x100, 0x7da: 0x100, 0x7db: 0x100, 0x7dc: 0x100, 0x7dd: 0x100, 0x7de: 0x100, 0x7df: 0x100,
0x7e0: 0x7c, 0x7e1: 0x7d, 0x7e2: 0x7e, 0x7e3: 0x7f, 0x7e4: 0x80, 0x7e5: 0x81, 0x7e6: 0x82, 0x7e7: 0x83,
0x7e8: 0x84, 0x7e9: 0x100, 0x7ea: 0x100, 0x7eb: 0x100, 0x7ec: 0x100, 0x7ed: 0x100, 0x7ee: 0x100, 0x7ef: 0x100,
0x7f0: 0x100, 0x7f1: 0x100, 0x7f2: 0x100, 0x7f3: 0x100, 0x7f4: 0x100, 0x7f5: 0x100, 0x7f6: 0x100, 0x7f7: 0x100,
0x7f8: 0x100, 0x7f9: 0x100, 0x7fa: 0x100, 0x7fb: 0x100, 0x7fc: 0x100, 0x7fd: 0x100, 0x7fe: 0x100, 0x7ff: 0x100,
// Block 0x20, offset 0x800
0x800: 0xa6, 0x801: 0xa6, 0x802: 0xa6, 0x803: 0xa6, 0x804: 0xa6, 0x805: 0xa6, 0x806: 0xa6, 0x807: 0xa6,
0x808: 0xa6, 0x809: 0xa6, 0x80a: 0xa6, 0x80b: 0xa6, 0x80c: 0xa6, 0x80d: 0x1ae, 0x80e: 0xa6, 0x80f: 0xa6,
0x810: 0xa6, 0x811: 0xa6, 0x812: 0xa6, 0x813: 0xa6, 0x814: 0xa6, 0x815: 0xa6, 0x816: 0xa6, 0x817: 0xa6,
0x818: 0xa6, 0x819: 0xa6, 0x81a: 0xa6, 0x81b: 0xa6, 0x81c: 0xa6, 0x81d: 0xa6, 0x81e: 0xa6, 0x81f: 0xa6,
0x820: 0xa6, 0x821: 0xa6, 0x822: 0xa6, 0x823: 0xa6, 0x824: 0xa6, 0x825: 0xa6, 0x826: 0xa6, 0x827: 0xa6,
0x828: 0xa6, 0x829: 0xa6, 0x82a: 0xa6, 0x82b: 0xa6, 0x82c: 0xa6, 0x82d: 0xa6, 0x82e: 0xa6, 0x82f: 0xa6,
0x830: 0xa6, 0x831: 0xa6, 0x832: 0xa6, 0x833: 0xa6, 0x834: 0xa6, 0x835: 0xa6, 0x836: 0xa6, 0x837: 0xa6,
0x838: 0xa6, 0x839: 0xa6, 0x83a: 0xa6, 0x83b: 0xa6, 0x83c: 0xa6, 0x83d: 0xa6, 0x83e: 0xa6, 0x83f: 0xa6,
// Block 0x21, offset 0x840
0x840: 0xa6, 0x841: 0xa6, 0x842: 0xa6, 0x843: 0xa6, 0x844: 0xa6, 0x845: 0xa6, 0x846: 0xa6, 0x847: 0xa6,
0x848: 0xa6, 0x849: 0xa6, 0x84a: 0xa6, 0x84b: 0xa6, 0x84c: 0xa6, 0x84d: 0xa6, 0x84e: 0x1af, 0x84f: 0x100,
0x850: 0x100, 0x851: 0x100, 0x852: 0x100, 0x853: 0x100, 0x854: 0x100, 0x855: 0x100, 0x856: 0x100, 0x857: 0x100,
0x858: 0x100, 0x859: 0x100, 0x85a: 0x100, 0x85b: 0x100, 0x85c: 0x100, 0x85d: 0x100, 0x85e: 0x100, 0x85f: 0x100,
0x860: 0x100, 0x861: 0x100, 0x862: 0x100, 0x863: 0x100, 0x864: 0x100, 0x865: 0x100, 0x866: 0x100, 0x867: 0x100,
0x868: 0x100, 0x869: 0x100, 0x86a: 0x100, 0x86b: 0x100, 0x86c: 0x100, 0x86d: 0x100, 0x86e: 0x100, 0x86f: 0x100,
0x870: 0x100, 0x871: 0x100, 0x872: 0x100, 0x873: 0x100, 0x874: 0x100, 0x875: 0x100, 0x876: 0x100, 0x877: 0x100,
0x878: 0x100, 0x879: 0x100, 0x87a: 0x100, 0x87b: 0x100, 0x87c: 0x100, 0x87d: 0x100, 0x87e: 0x100, 0x87f: 0x100,
// Block 0x22, offset 0x880
0x890: 0x0c, 0x891: 0x0d, 0x892: 0x0e, 0x893: 0x0f, 0x894: 0x10, 0x895: 0x0a, 0x896: 0x11, 0x897: 0x07,
0x898: 0x12, 0x899: 0x0a, 0x89a: 0x13, 0x89b: 0x14, 0x89c: 0x15, 0x89d: 0x16, 0x89e: 0x17, 0x89f: 0x18,
0x8a0: 0x07, 0x8a1: 0x07, 0x8a2: 0x07, 0x8a3: 0x07, 0x8a4: 0x07, 0x8a5: 0x07, 0x8a6: 0x07, 0x8a7: 0x07,
0x8a8: 0x07, 0x8a9: 0x07, 0x8aa: 0x19, 0x8ab: 0x1a, 0x8ac: 0x1b, 0x8ad: 0x07, 0x8ae: 0x1c, 0x8af: 0x1d,
0x8b0: 0x07, 0x8b1: 0x1e, 0x8b2: 0x1f, 0x8b3: 0x0a, 0x8b4: 0x0a, 0x8b5: 0x0a, 0x8b6: 0x0a, 0x8b7: 0x0a,
0x8b8: 0x0a, 0x8b9: 0x0a, 0x8ba: 0x0a, 0x8bb: 0x0a, 0x8bc: 0x0a, 0x8bd: 0x0a, 0x8be: 0x0a, 0x8bf: 0x0a,
// Block 0x23, offset 0x8c0
0x8c0: 0x0a, 0x8c1: 0x0a, 0x8c2: 0x0a, 0x8c3: 0x0a, 0x8c4: 0x0a, 0x8c5: 0x0a, 0x8c6: 0x0a, 0x8c7: 0x0a,
0x8c8: 0x0a, 0x8c9: 0x0a, 0x8ca: 0x0a, 0x8cb: 0x0a, 0x8cc: 0x0a, 0x8cd: 0x0a, 0x8ce: 0x0a, 0x8cf: 0x0a,
0x8d0: 0x0a, 0x8d1: 0x0a, 0x8d2: 0x0a, 0x8d3: 0x0a, 0x8d4: 0x0a, 0x8d5: 0x0a, 0x8d6: 0x0a, 0x8d7: 0x0a,
0x8d8: 0x0a, 0x8d9: 0x0a, 0x8da: 0x0a, 0x8db: 0x0a, 0x8dc: 0x0a, 0x8dd: 0x0a, 0x8de: 0x0a, 0x8df: 0x0a,
0x8e0: 0x0a, 0x8e1: 0x0a, 0x8e2: 0x0a, 0x8e3: 0x0a, 0x8e4: 0x0a, 0x8e5: 0x0a, 0x8e6: 0x0a, 0x8e7: 0x0a,
0x8e8: 0x0a, 0x8e9: 0x0a, 0x8ea: 0x0a, 0x8eb: 0x0a, 0x8ec: 0x0a, 0x8ed: 0x0a, 0x8ee: 0x0a, 0x8ef: 0x0a,
0x8f0: 0x0a, 0x8f1: 0x0a, 0x8f2: 0x0a, 0x8f3: 0x0a, 0x8f4: 0x0a, 0x8f5: 0x0a, 0x8f6: 0x0a, 0x8f7: 0x0a,
0x8f8: 0x0a, 0x8f9: 0x0a, 0x8fa: 0x0a, 0x8fb: 0x0a, 0x8fc: 0x0a, 0x8fd: 0x0a, 0x8fe: 0x0a, 0x8ff: 0x0a,
// Block 0x24, offset 0x900
0x900: 0x1b0, 0x901: 0x1b1, 0x902: 0x100, 0x903: 0x100, 0x904: 0x1b2, 0x905: 0x1b2, 0x906: 0x1b2, 0x907: 0x1b3,
0x908: 0x100, 0x909: 0x100, 0x90a: 0x100, 0x90b: 0x100, 0x90c: 0x100, 0x90d: 0x100, 0x90e: 0x100, 0x90f: 0x100,
0x910: 0x100, 0x911: 0x100, 0x912: 0x100, 0x913: 0x100, 0x914: 0x100, 0x915: 0x100, 0x916: 0x100, 0x917: 0x100,
0x918: 0x100, 0x919: 0x100, 0x91a: 0x100, 0x91b: 0x100, 0x91c: 0x100, 0x91d: 0x100, 0x91e: 0x100, 0x91f: 0x100,
0x920: 0x100, 0x921: 0x100, 0x922: 0x100, 0x923: 0x100, 0x924: 0x100, 0x925: 0x100, 0x926: 0x100, 0x927: 0x100,
0x928: 0x100, 0x929: 0x100, 0x92a: 0x100, 0x92b: 0x100, 0x92c: 0x100, 0x92d: 0x100, 0x92e: 0x100, 0x92f: 0x100,
0x930: 0x100, 0x931: 0x100, 0x932: 0x100, 0x933: 0x100, 0x934: 0x100, 0x935: 0x100, 0x936: 0x100, 0x937: 0x100,
0x938: 0x100, 0x939: 0x100, 0x93a: 0x100, 0x93b: 0x100, 0x93c: 0x100, 0x93d: 0x100, 0x93e: 0x100, 0x93f: 0x100,
// Block 0x25, offset 0x940
0x940: 0x0a, 0x941: 0x0a, 0x942: 0x0a, 0x943: 0x0a, 0x944: 0x0a, 0x945: 0x0a, 0x946: 0x0a, 0x947: 0x0a,
0x948: 0x0a, 0x949: 0x0a, 0x94a: 0x0a, 0x94b: 0x0a, 0x94c: 0x0a, 0x94d: 0x0a, 0x94e: 0x0a, 0x94f: 0x0a,
0x950: 0x0a, 0x951: 0x0a, 0x952: 0x0a, 0x953: 0x0a, 0x954: 0x0a, 0x955: 0x0a, 0x956: 0x0a, 0x957: 0x0a,
0x958: 0x0a, 0x959: 0x0a, 0x95a: 0x0a, 0x95b: 0x0a, 0x95c: 0x0a, 0x95d: 0x0a, 0x95e: 0x0a, 0x95f: 0x0a,
0x960: 0x22, 0x961: 0x0a, 0x962: 0x0a, 0x963: 0x0a, 0x964: 0x0a, 0x965: 0x0a, 0x966: 0x0a, 0x967: 0x0a,
0x968: 0x0a, 0x969: 0x0a, 0x96a: 0x0a, 0x96b: 0x0a, 0x96c: 0x0a, 0x96d: 0x0a, 0x96e: 0x0a, 0x96f: 0x0a,
0x970: 0x0a, 0x971: 0x0a, 0x972: 0x0a, 0x973: 0x0a, 0x974: 0x0a, 0x975: 0x0a, 0x976: 0x0a, 0x977: 0x0a,
0x978: 0x0a, 0x979: 0x0a, 0x97a: 0x0a, 0x97b: 0x0a, 0x97c: 0x0a, 0x97d: 0x0a, 0x97e: 0x0a, 0x97f: 0x0a,
// Block 0x26, offset 0x980
0x980: 0x0a, 0x981: 0x0a, 0x982: 0x0a, 0x983: 0x0a, 0x984: 0x0a, 0x985: 0x0a, 0x986: 0x0a, 0x987: 0x0a,
0x988: 0x0a, 0x989: 0x0a, 0x98a: 0x0a, 0x98b: 0x0a, 0x98c: 0x0a, 0x98d: 0x0a, 0x98e: 0x0a, 0x98f: 0x0a,
}
// idnaSparseOffset: 303 entries, 606 bytes
var idnaSparseOffset = []uint16{0x0, 0x8, 0x19, 0x25, 0x27, 0x2c, 0x33, 0x3e, 0x4a, 0x4e, 0x5d, 0x62, 0x6c, 0x78, 0x7e, 0x87, 0x97, 0xa6, 0xb1, 0xbe, 0xcf, 0xd9, 0xe0, 0xed, 0xfe, 0x105, 0x110, 0x11f, 0x12d, 0x137, 0x139, 0x13e, 0x141, 0x144, 0x146, 0x152, 0x15d, 0x165, 0x16b, 0x171, 0x176, 0x17b, 0x17e, 0x182, 0x188, 0x18d, 0x198, 0x1a2, 0x1a8, 0x1b9, 0x1c4, 0x1c7, 0x1cf, 0x1d2, 0x1df, 0x1e7, 0x1eb, 0x1f2, 0x1fa, 0x20a, 0x216, 0x219, 0x223, 0x22f, 0x23b, 0x247, 0x24f, 0x254, 0x261, 0x272, 0x27d, 0x282, 0x28b, 0x293, 0x299, 0x29e, 0x2a1, 0x2a5, 0x2ab, 0x2af, 0x2b3, 0x2b7, 0x2bc, 0x2c4, 0x2cb, 0x2d6, 0x2e0, 0x2e4, 0x2e7, 0x2ed, 0x2f1, 0x2f3, 0x2f6, 0x2f8, 0x2fb, 0x305, 0x308, 0x317, 0x31b, 0x31f, 0x321, 0x32a, 0x32e, 0x333, 0x338, 0x33e, 0x34e, 0x354, 0x358, 0x367, 0x36c, 0x374, 0x37e, 0x389, 0x391, 0x3a2, 0x3ab, 0x3bb, 0x3c8, 0x3d4, 0x3d9, 0x3e6, 0x3ea, 0x3ef, 0x3f1, 0x3f3, 0x3f7, 0x3f9, 0x3fd, 0x406, 0x40c, 0x410, 0x420, 0x42a, 0x42f, 0x432, 0x438, 0x43f, 0x444, 0x448, 0x44e, 0x453, 0x45c, 0x461, 0x467, 0x46e, 0x475, 0x47c, 0x480, 0x483, 0x488, 0x494, 0x49a, 0x49f, 0x4a6, 0x4ae, 0x4b3, 0x4b7, 0x4c7, 0x4ce, 0x4d2, 0x4d6, 0x4dd, 0x4df, 0x4e2, 0x4e5, 0x4e9, 0x4f2, 0x4f6, 0x4fe, 0x501, 0x509, 0x514, 0x523, 0x52f, 0x535, 0x542, 0x54e, 0x556, 0x55f, 0x56a, 0x571, 0x580, 0x58d, 0x591, 0x59e, 0x5a7, 0x5ab, 0x5ba, 0x5c2, 0x5cd, 0x5d6, 0x5dc, 0x5e4, 0x5ed, 0x5f9, 0x5fc, 0x608, 0x60b, 0x614, 0x617, 0x61c, 0x625, 0x62a, 0x637, 0x642, 0x64b, 0x656, 0x659, 0x65c, 0x666, 0x66f, 0x67b, 0x688, 0x695, 0x6a3, 0x6aa, 0x6b5, 0x6bc, 0x6c0, 0x6c4, 0x6c7, 0x6cc, 0x6cf, 0x6d2, 0x6d6, 0x6d9, 0x6de, 0x6e5, 0x6e8, 0x6f0, 0x6f4, 0x6ff, 0x702, 0x705, 0x708, 0x70e, 0x714, 0x71d, 0x720, 0x723, 0x726, 0x72e, 0x733, 0x73c, 0x73f, 0x744, 0x74e, 0x752, 0x756, 0x759, 0x75c, 0x760, 0x76f, 0x77b, 0x77f, 0x784, 0x789, 0x78e, 0x792, 0x797, 0x7a0, 0x7a5, 0x7a9, 0x7af, 0x7b5, 0x7ba, 0x7c0, 0x7c6, 0x7d0, 0x7d6, 0x7df, 0x7e2, 0x7e5, 0x7e9, 0x7ed, 0x7f1, 0x7f7, 0x7fd, 0x802, 0x805, 0x815, 0x81c, 0x820, 0x827, 0x82b, 0x831, 0x838, 0x83f, 0x845, 0x84e, 0x852, 0x860, 0x863, 0x866, 0x86a, 0x86e, 0x871, 0x875, 0x878, 0x87d, 0x87f, 0x881}
// idnaSparseValues: 2180 entries, 8720 bytes
var idnaSparseValues = [2180]valueRange{
// Block 0x0, offset 0x0
{value: 0x0000, lo: 0x07},
{value: 0xe105, lo: 0x80, hi: 0x96},
{value: 0x0018, lo: 0x97, hi: 0x97},
{value: 0xe105, lo: 0x98, hi: 0x9e},
{value: 0x001f, lo: 0x9f, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xb6},
{value: 0x0018, lo: 0xb7, hi: 0xb7},
{value: 0x0008, lo: 0xb8, hi: 0xbf},
// Block 0x1, offset 0x8
{value: 0x0000, lo: 0x10},
{value: 0x0008, lo: 0x80, hi: 0x80},
{value: 0xe01d, lo: 0x81, hi: 0x81},
{value: 0x0008, lo: 0x82, hi: 0x82},
{value: 0x0335, lo: 0x83, hi: 0x83},
{value: 0x034d, lo: 0x84, hi: 0x84},
{value: 0x0365, lo: 0x85, hi: 0x85},
{value: 0xe00d, lo: 0x86, hi: 0x86},
{value: 0x0008, lo: 0x87, hi: 0x87},
{value: 0xe00d, lo: 0x88, hi: 0x88},
{value: 0x0008, lo: 0x89, hi: 0x89},
{value: 0xe00d, lo: 0x8a, hi: 0x8a},
{value: 0x0008, lo: 0x8b, hi: 0x8b},
{value: 0xe00d, lo: 0x8c, hi: 0x8c},
{value: 0x0008, lo: 0x8d, hi: 0x8d},
{value: 0xe00d, lo: 0x8e, hi: 0x8e},
{value: 0x0008, lo: 0x8f, hi: 0xbf},
// Block 0x2, offset 0x19
{value: 0x0000, lo: 0x0b},
{value: 0x0008, lo: 0x80, hi: 0xaf},
{value: 0x00a9, lo: 0xb0, hi: 0xb0},
{value: 0x037d, lo: 0xb1, hi: 0xb1},
{value: 0x00b1, lo: 0xb2, hi: 0xb2},
{value: 0x00b9, lo: 0xb3, hi: 0xb3},
{value: 0x034d, lo: 0xb4, hi: 0xb4},
{value: 0x0395, lo: 0xb5, hi: 0xb5},
{value: 0xe1bd, lo: 0xb6, hi: 0xb6},
{value: 0x00c1, lo: 0xb7, hi: 0xb7},
{value: 0x00c9, lo: 0xb8, hi: 0xb8},
{value: 0x0008, lo: 0xb9, hi: 0xbf},
// Block 0x3, offset 0x25
{value: 0x0000, lo: 0x01},
{value: 0x3308, lo: 0x80, hi: 0xbf},
// Block 0x4, offset 0x27
{value: 0x0000, lo: 0x04},
{value: 0x03f5, lo: 0x80, hi: 0x8f},
{value: 0xe105, lo: 0x90, hi: 0x9f},
{value: 0x049d, lo: 0xa0, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xbf},
// Block 0x5, offset 0x2c
{value: 0x0000, lo: 0x06},
{value: 0xe185, lo: 0x80, hi: 0x8f},
{value: 0x0545, lo: 0x90, hi: 0x96},
{value: 0x0040, lo: 0x97, hi: 0x98},
{value: 0x0008, lo: 0x99, hi: 0x99},
{value: 0x0018, lo: 0x9a, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xbf},
// Block 0x6, offset 0x33
{value: 0x0000, lo: 0x0a},
{value: 0x0008, lo: 0x80, hi: 0x86},
{value: 0x0131, lo: 0x87, hi: 0x87},
{value: 0x0008, lo: 0x88, hi: 0x88},
{value: 0x0018, lo: 0x89, hi: 0x8a},
{value: 0x0040, lo: 0x8b, hi: 0x8c},
{value: 0x0018, lo: 0x8d, hi: 0x8f},
{value: 0x0040, lo: 0x90, hi: 0x90},
{value: 0x3308, lo: 0x91, hi: 0xbd},
{value: 0x0818, lo: 0xbe, hi: 0xbe},
{value: 0x3308, lo: 0xbf, hi: 0xbf},
// Block 0x7, offset 0x3e
{value: 0x0000, lo: 0x0b},
{value: 0x0818, lo: 0x80, hi: 0x80},
{value: 0x3308, lo: 0x81, hi: 0x82},
{value: 0x0818, lo: 0x83, hi: 0x83},
{value: 0x3308, lo: 0x84, hi: 0x85},
{value: 0x0818, lo: 0x86, hi: 0x86},
{value: 0x3308, lo: 0x87, hi: 0x87},
{value: 0x0040, lo: 0x88, hi: 0x8f},
{value: 0x0808, lo: 0x90, hi: 0xaa},
{value: 0x0040, lo: 0xab, hi: 0xae},
{value: 0x0808, lo: 0xaf, hi: 0xb4},
{value: 0x0040, lo: 0xb5, hi: 0xbf},
// Block 0x8, offset 0x4a
{value: 0x0000, lo: 0x03},
{value: 0x0a08, lo: 0x80, hi: 0x87},
{value: 0x0c08, lo: 0x88, hi: 0x99},
{value: 0x0a08, lo: 0x9a, hi: 0xbf},
// Block 0x9, offset 0x4e
{value: 0x0000, lo: 0x0e},
{value: 0x3308, lo: 0x80, hi: 0x8a},
{value: 0x0040, lo: 0x8b, hi: 0x8c},
{value: 0x0c08, lo: 0x8d, hi: 0x8d},
{value: 0x0a08, lo: 0x8e, hi: 0x98},
{value: 0x0c08, lo: 0x99, hi: 0x9b},
{value: 0x0a08, lo: 0x9c, hi: 0xaa},
{value: 0x0c08, lo: 0xab, hi: 0xac},
{value: 0x0a08, lo: 0xad, hi: 0xb0},
{value: 0x0c08, lo: 0xb1, hi: 0xb1},
{value: 0x0a08, lo: 0xb2, hi: 0xb2},
{value: 0x0c08, lo: 0xb3, hi: 0xb4},
{value: 0x0a08, lo: 0xb5, hi: 0xb7},
{value: 0x0c08, lo: 0xb8, hi: 0xb9},
{value: 0x0a08, lo: 0xba, hi: 0xbf},
// Block 0xa, offset 0x5d
{value: 0x0000, lo: 0x04},
{value: 0x0808, lo: 0x80, hi: 0xa5},
{value: 0x3308, lo: 0xa6, hi: 0xb0},
{value: 0x0808, lo: 0xb1, hi: 0xb1},
{value: 0x0040, lo: 0xb2, hi: 0xbf},
// Block 0xb, offset 0x62
{value: 0x0000, lo: 0x09},
{value: 0x0808, lo: 0x80, hi: 0x89},
{value: 0x0a08, lo: 0x8a, hi: 0xaa},
{value: 0x3308, lo: 0xab, hi: 0xb3},
{value: 0x0808, lo: 0xb4, hi: 0xb5},
{value: 0x0018, lo: 0xb6, hi: 0xb9},
{value: 0x0818, lo: 0xba, hi: 0xba},
{value: 0x0040, lo: 0xbb, hi: 0xbc},
{value: 0x3308, lo: 0xbd, hi: 0xbd},
{value: 0x0818, lo: 0xbe, hi: 0xbf},
// Block 0xc, offset 0x6c
{value: 0x0000, lo: 0x0b},
{value: 0x0808, lo: 0x80, hi: 0x95},
{value: 0x3308, lo: 0x96, hi: 0x99},
{value: 0x0808, lo: 0x9a, hi: 0x9a},
{value: 0x3308, lo: 0x9b, hi: 0xa3},
{value: 0x0808, lo: 0xa4, hi: 0xa4},
{value: 0x3308, lo: 0xa5, hi: 0xa7},
{value: 0x0808, lo: 0xa8, hi: 0xa8},
{value: 0x3308, lo: 0xa9, hi: 0xad},
{value: 0x0040, lo: 0xae, hi: 0xaf},
{value: 0x0818, lo: 0xb0, hi: 0xbe},
{value: 0x0040, lo: 0xbf, hi: 0xbf},
// Block 0xd, offset 0x78
{value: 0x0000, lo: 0x05},
{value: 0x0a08, lo: 0x80, hi: 0x88},
{value: 0x0808, lo: 0x89, hi: 0x89},
{value: 0x3308, lo: 0x8a, hi: 0xa1},
{value: 0x0840, lo: 0xa2, hi: 0xa2},
{value: 0x3308, lo: 0xa3, hi: 0xbf},
// Block 0xe, offset 0x7e
{value: 0x0000, lo: 0x08},
{value: 0x3308, lo: 0x80, hi: 0x82},
{value: 0x3008, lo: 0x83, hi: 0x83},
{value: 0x0008, lo: 0x84, hi: 0xb9},
{value: 0x3308, lo: 0xba, hi: 0xba},
{value: 0x3008, lo: 0xbb, hi: 0xbb},
{value: 0x3308, lo: 0xbc, hi: 0xbc},
{value: 0x0008, lo: 0xbd, hi: 0xbd},
{value: 0x3008, lo: 0xbe, hi: 0xbf},
// Block 0xf, offset 0x87
{value: 0x0000, lo: 0x0f},
{value: 0x3308, lo: 0x80, hi: 0x80},
{value: 0x3008, lo: 0x81, hi: 0x82},
{value: 0x0040, lo: 0x83, hi: 0x85},
{value: 0x3008, lo: 0x86, hi: 0x88},
{value: 0x0040, lo: 0x89, hi: 0x89},
{value: 0x3008, lo: 0x8a, hi: 0x8c},
{value: 0x3b08, lo: 0x8d, hi: 0x8d},
{value: 0x0040, lo: 0x8e, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x90},
{value: 0x0040, lo: 0x91, hi: 0x96},
{value: 0x3008, lo: 0x97, hi: 0x97},
{value: 0x0040, lo: 0x98, hi: 0xa5},
{value: 0x0008, lo: 0xa6, hi: 0xaf},
{value: 0x0018, lo: 0xb0, hi: 0xba},
{value: 0x0040, lo: 0xbb, hi: 0xbf},
// Block 0x10, offset 0x97
{value: 0x0000, lo: 0x0e},
{value: 0x3308, lo: 0x80, hi: 0x80},
{value: 0x3008, lo: 0x81, hi: 0x83},
{value: 0x3308, lo: 0x84, hi: 0x84},
{value: 0x0008, lo: 0x85, hi: 0x8c},
{value: 0x0040, lo: 0x8d, hi: 0x8d},
{value: 0x0008, lo: 0x8e, hi: 0x90},
{value: 0x0040, lo: 0x91, hi: 0x91},
{value: 0x0008, lo: 0x92, hi: 0xa8},
{value: 0x0040, lo: 0xa9, hi: 0xa9},
{value: 0x0008, lo: 0xaa, hi: 0xb9},
{value: 0x0040, lo: 0xba, hi: 0xbb},
{value: 0x3308, lo: 0xbc, hi: 0xbc},
{value: 0x0008, lo: 0xbd, hi: 0xbd},
{value: 0x3308, lo: 0xbe, hi: 0xbf},
// Block 0x11, offset 0xa6
{value: 0x0000, lo: 0x0a},
{value: 0x3308, lo: 0x80, hi: 0x81},
{value: 0x3008, lo: 0x82, hi: 0x83},
{value: 0x0008, lo: 0x84, hi: 0x8c},
{value: 0x0040, lo: 0x8d, hi: 0x8d},
{value: 0x0008, lo: 0x8e, hi: 0x90},
{value: 0x0040, lo: 0x91, hi: 0x91},
{value: 0x0008, lo: 0x92, hi: 0xba},
{value: 0x3b08, lo: 0xbb, hi: 0xbc},
{value: 0x0008, lo: 0xbd, hi: 0xbd},
{value: 0x3008, lo: 0xbe, hi: 0xbf},
// Block 0x12, offset 0xb1
{value: 0x0000, lo: 0x0c},
{value: 0x0040, lo: 0x80, hi: 0x80},
{value: 0x3308, lo: 0x81, hi: 0x81},
{value: 0x3008, lo: 0x82, hi: 0x83},
{value: 0x0040, lo: 0x84, hi: 0x84},
{value: 0x0008, lo: 0x85, hi: 0x96},
{value: 0x0040, lo: 0x97, hi: 0x99},
{value: 0x0008, lo: 0x9a, hi: 0xb1},
{value: 0x0040, lo: 0xb2, hi: 0xb2},
{value: 0x0008, lo: 0xb3, hi: 0xbb},
{value: 0x0040, lo: 0xbc, hi: 0xbc},
{value: 0x0008, lo: 0xbd, hi: 0xbd},
{value: 0x0040, lo: 0xbe, hi: 0xbf},
// Block 0x13, offset 0xbe
{value: 0x0000, lo: 0x10},
{value: 0x0008, lo: 0x80, hi: 0x86},
{value: 0x0040, lo: 0x87, hi: 0x89},
{value: 0x3b08, lo: 0x8a, hi: 0x8a},
{value: 0x0040, lo: 0x8b, hi: 0x8e},
{value: 0x3008, lo: 0x8f, hi: 0x91},
{value: 0x3308, lo: 0x92, hi: 0x94},
{value: 0x0040, lo: 0x95, hi: 0x95},
{value: 0x3308, lo: 0x96, hi: 0x96},
{value: 0x0040, lo: 0x97, hi: 0x97},
{value: 0x3008, lo: 0x98, hi: 0x9f},
{value: 0x0040, lo: 0xa0, hi: 0xa5},
{value: 0x0008, lo: 0xa6, hi: 0xaf},
{value: 0x0040, lo: 0xb0, hi: 0xb1},
{value: 0x3008, lo: 0xb2, hi: 0xb3},
{value: 0x0018, lo: 0xb4, hi: 0xb4},
{value: 0x0040, lo: 0xb5, hi: 0xbf},
// Block 0x14, offset 0xcf
{value: 0x0000, lo: 0x09},
{value: 0x0040, lo: 0x80, hi: 0x80},
{value: 0x0008, lo: 0x81, hi: 0xb0},
{value: 0x3308, lo: 0xb1, hi: 0xb1},
{value: 0x0008, lo: 0xb2, hi: 0xb2},
{value: 0x01f1, lo: 0xb3, hi: 0xb3},
{value: 0x3308, lo: 0xb4, hi: 0xb9},
{value: 0x3b08, lo: 0xba, hi: 0xba},
{value: 0x0040, lo: 0xbb, hi: 0xbe},
{value: 0x0018, lo: 0xbf, hi: 0xbf},
// Block 0x15, offset 0xd9
{value: 0x0000, lo: 0x06},
{value: 0x0008, lo: 0x80, hi: 0x86},
{value: 0x3308, lo: 0x87, hi: 0x8e},
{value: 0x0018, lo: 0x8f, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x99},
{value: 0x0018, lo: 0x9a, hi: 0x9b},
{value: 0x0040, lo: 0x9c, hi: 0xbf},
// Block 0x16, offset 0xe0
{value: 0x0000, lo: 0x0c},
{value: 0x0008, lo: 0x80, hi: 0x84},
{value: 0x0040, lo: 0x85, hi: 0x85},
{value: 0x0008, lo: 0x86, hi: 0x86},
{value: 0x0040, lo: 0x87, hi: 0x87},
{value: 0x3308, lo: 0x88, hi: 0x8e},
{value: 0x0040, lo: 0x8f, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x99},
{value: 0x0040, lo: 0x9a, hi: 0x9b},
{value: 0x0201, lo: 0x9c, hi: 0x9c},
{value: 0x0209, lo: 0x9d, hi: 0x9d},
{value: 0x0008, lo: 0x9e, hi: 0x9f},
{value: 0x0040, lo: 0xa0, hi: 0xbf},
// Block 0x17, offset 0xed
{value: 0x0000, lo: 0x10},
{value: 0x0008, lo: 0x80, hi: 0x80},
{value: 0x0018, lo: 0x81, hi: 0x8a},
{value: 0x0008, lo: 0x8b, hi: 0x8b},
{value: 0xe03d, lo: 0x8c, hi: 0x8c},
{value: 0x0018, lo: 0x8d, hi: 0x97},
{value: 0x3308, lo: 0x98, hi: 0x99},
{value: 0x0018, lo: 0x9a, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xa9},
{value: 0x0018, lo: 0xaa, hi: 0xb4},
{value: 0x3308, lo: 0xb5, hi: 0xb5},
{value: 0x0018, lo: 0xb6, hi: 0xb6},
{value: 0x3308, lo: 0xb7, hi: 0xb7},
{value: 0x0018, lo: 0xb8, hi: 0xb8},
{value: 0x3308, lo: 0xb9, hi: 0xb9},
{value: 0x0018, lo: 0xba, hi: 0xbd},
{value: 0x3008, lo: 0xbe, hi: 0xbf},
// Block 0x18, offset 0xfe
{value: 0x0000, lo: 0x06},
{value: 0x0018, lo: 0x80, hi: 0x85},
{value: 0x3308, lo: 0x86, hi: 0x86},
{value: 0x0018, lo: 0x87, hi: 0x8c},
{value: 0x0040, lo: 0x8d, hi: 0x8d},
{value: 0x0018, lo: 0x8e, hi: 0x9a},
{value: 0x0040, lo: 0x9b, hi: 0xbf},
// Block 0x19, offset 0x105
{value: 0x0000, lo: 0x0a},
{value: 0x0008, lo: 0x80, hi: 0xaa},
{value: 0x3008, lo: 0xab, hi: 0xac},
{value: 0x3308, lo: 0xad, hi: 0xb0},
{value: 0x3008, lo: 0xb1, hi: 0xb1},
{value: 0x3308, lo: 0xb2, hi: 0xb7},
{value: 0x3008, lo: 0xb8, hi: 0xb8},
{value: 0x3b08, lo: 0xb9, hi: 0xba},
{value: 0x3008, lo: 0xbb, hi: 0xbc},
{value: 0x3308, lo: 0xbd, hi: 0xbe},
{value: 0x0008, lo: 0xbf, hi: 0xbf},
// Block 0x1a, offset 0x110
{value: 0x0000, lo: 0x0e},
{value: 0x0008, lo: 0x80, hi: 0x89},
{value: 0x0018, lo: 0x8a, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x95},
{value: 0x3008, lo: 0x96, hi: 0x97},
{value: 0x3308, lo: 0x98, hi: 0x99},
{value: 0x0008, lo: 0x9a, hi: 0x9d},
{value: 0x3308, lo: 0x9e, hi: 0xa0},
{value: 0x0008, lo: 0xa1, hi: 0xa1},
{value: 0x3008, lo: 0xa2, hi: 0xa4},
{value: 0x0008, lo: 0xa5, hi: 0xa6},
{value: 0x3008, lo: 0xa7, hi: 0xad},
{value: 0x0008, lo: 0xae, hi: 0xb0},
{value: 0x3308, lo: 0xb1, hi: 0xb4},
{value: 0x0008, lo: 0xb5, hi: 0xbf},
// Block 0x1b, offset 0x11f
{value: 0x0000, lo: 0x0d},
{value: 0x0008, lo: 0x80, hi: 0x81},
{value: 0x3308, lo: 0x82, hi: 0x82},
{value: 0x3008, lo: 0x83, hi: 0x84},
{value: 0x3308, lo: 0x85, hi: 0x86},
{value: 0x3008, lo: 0x87, hi: 0x8c},
{value: 0x3308, lo: 0x8d, hi: 0x8d},
{value: 0x0008, lo: 0x8e, hi: 0x8e},
{value: 0x3008, lo: 0x8f, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x99},
{value: 0x3008, lo: 0x9a, hi: 0x9c},
{value: 0x3308, lo: 0x9d, hi: 0x9d},
{value: 0x0018, lo: 0x9e, hi: 0x9f},
{value: 0x0040, lo: 0xa0, hi: 0xbf},
// Block 0x1c, offset 0x12d
{value: 0x0000, lo: 0x09},
{value: 0x0040, lo: 0x80, hi: 0x86},
{value: 0x055d, lo: 0x87, hi: 0x87},
{value: 0x0040, lo: 0x88, hi: 0x8c},
{value: 0x055d, lo: 0x8d, hi: 0x8d},
{value: 0x0040, lo: 0x8e, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0xba},
{value: 0x0018, lo: 0xbb, hi: 0xbb},
{value: 0xe105, lo: 0xbc, hi: 0xbc},
{value: 0x0008, lo: 0xbd, hi: 0xbf},
// Block 0x1d, offset 0x137
{value: 0x0000, lo: 0x01},
{value: 0x0018, lo: 0x80, hi: 0xbf},
// Block 0x1e, offset 0x139
{value: 0x0000, lo: 0x04},
{value: 0x0018, lo: 0x80, hi: 0x9e},
{value: 0x0040, lo: 0x9f, hi: 0xa0},
{value: 0x2018, lo: 0xa1, hi: 0xb5},
{value: 0x0018, lo: 0xb6, hi: 0xbf},
// Block 0x1f, offset 0x13e
{value: 0x0000, lo: 0x02},
{value: 0x0018, lo: 0x80, hi: 0xa7},
{value: 0x2018, lo: 0xa8, hi: 0xbf},
// Block 0x20, offset 0x141
{value: 0x0000, lo: 0x02},
{value: 0x2018, lo: 0x80, hi: 0x82},
{value: 0x0018, lo: 0x83, hi: 0xbf},
// Block 0x21, offset 0x144
{value: 0x0000, lo: 0x01},
{value: 0x0008, lo: 0x80, hi: 0xbf},
// Block 0x22, offset 0x146
{value: 0x0000, lo: 0x0b},
{value: 0x0008, lo: 0x80, hi: 0x88},
{value: 0x0040, lo: 0x89, hi: 0x89},
{value: 0x0008, lo: 0x8a, hi: 0x8d},
{value: 0x0040, lo: 0x8e, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x96},
{value: 0x0040, lo: 0x97, hi: 0x97},
{value: 0x0008, lo: 0x98, hi: 0x98},
{value: 0x0040, lo: 0x99, hi: 0x99},
{value: 0x0008, lo: 0x9a, hi: 0x9d},
{value: 0x0040, lo: 0x9e, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xbf},
// Block 0x23, offset 0x152
{value: 0x0000, lo: 0x0a},
{value: 0x0008, lo: 0x80, hi: 0x88},
{value: 0x0040, lo: 0x89, hi: 0x89},
{value: 0x0008, lo: 0x8a, hi: 0x8d},
{value: 0x0040, lo: 0x8e, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0xb0},
{value: 0x0040, lo: 0xb1, hi: 0xb1},
{value: 0x0008, lo: 0xb2, hi: 0xb5},
{value: 0x0040, lo: 0xb6, hi: 0xb7},
{value: 0x0008, lo: 0xb8, hi: 0xbe},
{value: 0x0040, lo: 0xbf, hi: 0xbf},
// Block 0x24, offset 0x15d
{value: 0x0000, lo: 0x07},
{value: 0x0008, lo: 0x80, hi: 0x80},
{value: 0x0040, lo: 0x81, hi: 0x81},
{value: 0x0008, lo: 0x82, hi: 0x85},
{value: 0x0040, lo: 0x86, hi: 0x87},
{value: 0x0008, lo: 0x88, hi: 0x96},
{value: 0x0040, lo: 0x97, hi: 0x97},
{value: 0x0008, lo: 0x98, hi: 0xbf},
// Block 0x25, offset 0x165
{value: 0x0000, lo: 0x05},
{value: 0x0008, lo: 0x80, hi: 0x90},
{value: 0x0040, lo: 0x91, hi: 0x91},
{value: 0x0008, lo: 0x92, hi: 0x95},
{value: 0x0040, lo: 0x96, hi: 0x97},
{value: 0x0008, lo: 0x98, hi: 0xbf},
// Block 0x26, offset 0x16b
{value: 0x0000, lo: 0x05},
{value: 0x0008, lo: 0x80, hi: 0x9a},
{value: 0x0040, lo: 0x9b, hi: 0x9c},
{value: 0x3308, lo: 0x9d, hi: 0x9f},
{value: 0x0018, lo: 0xa0, hi: 0xbc},
{value: 0x0040, lo: 0xbd, hi: 0xbf},
// Block 0x27, offset 0x171
{value: 0x0000, lo: 0x04},
{value: 0x0008, lo: 0x80, hi: 0x8f},
{value: 0x0018, lo: 0x90, hi: 0x99},
{value: 0x0040, lo: 0x9a, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xbf},
// Block 0x28, offset 0x176
{value: 0x0000, lo: 0x04},
{value: 0x0008, lo: 0x80, hi: 0xb5},
{value: 0x0040, lo: 0xb6, hi: 0xb7},
{value: 0xe045, lo: 0xb8, hi: 0xbd},
{value: 0x0040, lo: 0xbe, hi: 0xbf},
// Block 0x29, offset 0x17b
{value: 0x0000, lo: 0x02},
{value: 0x0018, lo: 0x80, hi: 0x80},
{value: 0x0008, lo: 0x81, hi: 0xbf},
// Block 0x2a, offset 0x17e
{value: 0x0000, lo: 0x03},
{value: 0x0008, lo: 0x80, hi: 0xac},
{value: 0x0018, lo: 0xad, hi: 0xae},
{value: 0x0008, lo: 0xaf, hi: 0xbf},
// Block 0x2b, offset 0x182
{value: 0x0000, lo: 0x05},
{value: 0x0040, lo: 0x80, hi: 0x80},
{value: 0x0008, lo: 0x81, hi: 0x9a},
{value: 0x0018, lo: 0x9b, hi: 0x9c},
{value: 0x0040, lo: 0x9d, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xbf},
// Block 0x2c, offset 0x188
{value: 0x0000, lo: 0x04},
{value: 0x0008, lo: 0x80, hi: 0xaa},
{value: 0x0018, lo: 0xab, hi: 0xb0},
{value: 0x0008, lo: 0xb1, hi: 0xb8},
{value: 0x0040, lo: 0xb9, hi: 0xbf},
// Block 0x2d, offset 0x18d
{value: 0x0000, lo: 0x0a},
{value: 0x0008, lo: 0x80, hi: 0x91},
{value: 0x3308, lo: 0x92, hi: 0x93},
{value: 0x3b08, lo: 0x94, hi: 0x94},
{value: 0x3808, lo: 0x95, hi: 0x95},
{value: 0x0040, lo: 0x96, hi: 0x9e},
{value: 0x0008, lo: 0x9f, hi: 0xb1},
{value: 0x3308, lo: 0xb2, hi: 0xb3},
{value: 0x3808, lo: 0xb4, hi: 0xb4},
{value: 0x0018, lo: 0xb5, hi: 0xb6},
{value: 0x0040, lo: 0xb7, hi: 0xbf},
// Block 0x2e, offset 0x198
{value: 0x0000, lo: 0x09},
{value: 0x0008, lo: 0x80, hi: 0x91},
{value: 0x3308, lo: 0x92, hi: 0x93},
{value: 0x0040, lo: 0x94, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xac},
{value: 0x0040, lo: 0xad, hi: 0xad},
{value: 0x0008, lo: 0xae, hi: 0xb0},
{value: 0x0040, lo: 0xb1, hi: 0xb1},
{value: 0x3308, lo: 0xb2, hi: 0xb3},
{value: 0x0040, lo: 0xb4, hi: 0xbf},
// Block 0x2f, offset 0x1a2
{value: 0x0000, lo: 0x05},
{value: 0x0008, lo: 0x80, hi: 0xb3},
{value: 0x3340, lo: 0xb4, hi: 0xb5},
{value: 0x3008, lo: 0xb6, hi: 0xb6},
{value: 0x3308, lo: 0xb7, hi: 0xbd},
{value: 0x3008, lo: 0xbe, hi: 0xbf},
// Block 0x30, offset 0x1a8
{value: 0x0000, lo: 0x10},
{value: 0x3008, lo: 0x80, hi: 0x85},
{value: 0x3308, lo: 0x86, hi: 0x86},
{value: 0x3008, lo: 0x87, hi: 0x88},
{value: 0x3308, lo: 0x89, hi: 0x91},
{value: 0x3b08, lo: 0x92, hi: 0x92},
{value: 0x3308, lo: 0x93, hi: 0x93},
{value: 0x0018, lo: 0x94, hi: 0x96},
{value: 0x0008, lo: 0x97, hi: 0x97},
{value: 0x0018, lo: 0x98, hi: 0x9b},
{value: 0x0008, lo: 0x9c, hi: 0x9c},
{value: 0x3308, lo: 0x9d, hi: 0x9d},
{value: 0x0040, lo: 0x9e, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xa9},
{value: 0x0040, lo: 0xaa, hi: 0xaf},
{value: 0x0018, lo: 0xb0, hi: 0xb9},
{value: 0x0040, lo: 0xba, hi: 0xbf},
// Block 0x31, offset 0x1b9
{value: 0x0000, lo: 0x0a},
{value: 0x0018, lo: 0x80, hi: 0x85},
{value: 0x0040, lo: 0x86, hi: 0x86},
{value: 0x0218, lo: 0x87, hi: 0x87},
{value: 0x0018, lo: 0x88, hi: 0x8a},
{value: 0x33c0, lo: 0x8b, hi: 0x8d},
{value: 0x0040, lo: 0x8e, hi: 0x8e},
{value: 0x33c0, lo: 0x8f, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x99},
{value: 0x0040, lo: 0x9a, hi: 0x9f},
{value: 0x0208, lo: 0xa0, hi: 0xbf},
// Block 0x32, offset 0x1c4
{value: 0x0000, lo: 0x02},
{value: 0x0208, lo: 0x80, hi: 0xb8},
{value: 0x0040, lo: 0xb9, hi: 0xbf},
// Block 0x33, offset 0x1c7
{value: 0x0000, lo: 0x07},
{value: 0x0008, lo: 0x80, hi: 0x84},
{value: 0x3308, lo: 0x85, hi: 0x86},
{value: 0x0208, lo: 0x87, hi: 0xa8},
{value: 0x3308, lo: 0xa9, hi: 0xa9},
{value: 0x0208, lo: 0xaa, hi: 0xaa},
{value: 0x0040, lo: 0xab, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xbf},
// Block 0x34, offset 0x1cf
{value: 0x0000, lo: 0x02},
{value: 0x0008, lo: 0x80, hi: 0xb5},
{value: 0x0040, lo: 0xb6, hi: 0xbf},
// Block 0x35, offset 0x1d2
{value: 0x0000, lo: 0x0c},
{value: 0x0008, lo: 0x80, hi: 0x9e},
{value: 0x0040, lo: 0x9f, hi: 0x9f},
{value: 0x3308, lo: 0xa0, hi: 0xa2},
{value: 0x3008, lo: 0xa3, hi: 0xa6},
{value: 0x3308, lo: 0xa7, hi: 0xa8},
{value: 0x3008, lo: 0xa9, hi: 0xab},
{value: 0x0040, lo: 0xac, hi: 0xaf},
{value: 0x3008, lo: 0xb0, hi: 0xb1},
{value: 0x3308, lo: 0xb2, hi: 0xb2},
{value: 0x3008, lo: 0xb3, hi: 0xb8},
{value: 0x3308, lo: 0xb9, hi: 0xbb},
{value: 0x0040, lo: 0xbc, hi: 0xbf},
// Block 0x36, offset 0x1df
{value: 0x0000, lo: 0x07},
{value: 0x0018, lo: 0x80, hi: 0x80},
{value: 0x0040, lo: 0x81, hi: 0x83},
{value: 0x0018, lo: 0x84, hi: 0x85},
{value: 0x0008, lo: 0x86, hi: 0xad},
{value: 0x0040, lo: 0xae, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xb4},
{value: 0x0040, lo: 0xb5, hi: 0xbf},
// Block 0x37, offset 0x1e7
{value: 0x0000, lo: 0x03},
{value: 0x0008, lo: 0x80, hi: 0xab},
{value: 0x0040, lo: 0xac, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xbf},
// Block 0x38, offset 0x1eb
{value: 0x0000, lo: 0x06},
{value: 0x0008, lo: 0x80, hi: 0x89},
{value: 0x0040, lo: 0x8a, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x99},
{value: 0x0028, lo: 0x9a, hi: 0x9a},
{value: 0x0040, lo: 0x9b, hi: 0x9d},
{value: 0x0018, lo: 0x9e, hi: 0xbf},
// Block 0x39, offset 0x1f2
{value: 0x0000, lo: 0x07},
{value: 0x0008, lo: 0x80, hi: 0x96},
{value: 0x3308, lo: 0x97, hi: 0x98},
{value: 0x3008, lo: 0x99, hi: 0x9a},
{value: 0x3308, lo: 0x9b, hi: 0x9b},
{value: 0x0040, lo: 0x9c, hi: 0x9d},
{value: 0x0018, lo: 0x9e, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xbf},
// Block 0x3a, offset 0x1fa
{value: 0x0000, lo: 0x0f},
{value: 0x0008, lo: 0x80, hi: 0x94},
{value: 0x3008, lo: 0x95, hi: 0x95},
{value: 0x3308, lo: 0x96, hi: 0x96},
{value: 0x3008, lo: 0x97, hi: 0x97},
{value: 0x3308, lo: 0x98, hi: 0x9e},
{value: 0x0040, lo: 0x9f, hi: 0x9f},
{value: 0x3b08, lo: 0xa0, hi: 0xa0},
{value: 0x3008, lo: 0xa1, hi: 0xa1},
{value: 0x3308, lo: 0xa2, hi: 0xa2},
{value: 0x3008, lo: 0xa3, hi: 0xa4},
{value: 0x3308, lo: 0xa5, hi: 0xac},
{value: 0x3008, lo: 0xad, hi: 0xb2},
{value: 0x3308, lo: 0xb3, hi: 0xbc},
{value: 0x0040, lo: 0xbd, hi: 0xbe},
{value: 0x3308, lo: 0xbf, hi: 0xbf},
// Block 0x3b, offset 0x20a
{value: 0x0000, lo: 0x0b},
{value: 0x0008, lo: 0x80, hi: 0x89},
{value: 0x0040, lo: 0x8a, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x99},
{value: 0x0040, lo: 0x9a, hi: 0x9f},
{value: 0x0018, lo: 0xa0, hi: 0xa6},
{value: 0x0008, lo: 0xa7, hi: 0xa7},
{value: 0x0018, lo: 0xa8, hi: 0xad},
{value: 0x0040, lo: 0xae, hi: 0xaf},
{value: 0x3308, lo: 0xb0, hi: 0xbd},
{value: 0x3318, lo: 0xbe, hi: 0xbe},
{value: 0x3308, lo: 0xbf, hi: 0xbf},
// Block 0x3c, offset 0x216
{value: 0x0000, lo: 0x02},
{value: 0x3308, lo: 0x80, hi: 0x8e},
{value: 0x0040, lo: 0x8f, hi: 0xbf},
// Block 0x3d, offset 0x219
{value: 0x0000, lo: 0x09},
{value: 0x3308, lo: 0x80, hi: 0x83},
{value: 0x3008, lo: 0x84, hi: 0x84},
{value: 0x0008, lo: 0x85, hi: 0xb3},
{value: 0x3308, lo: 0xb4, hi: 0xb4},
{value: 0x3008, lo: 0xb5, hi: 0xb5},
{value: 0x3308, lo: 0xb6, hi: 0xba},
{value: 0x3008, lo: 0xbb, hi: 0xbb},
{value: 0x3308, lo: 0xbc, hi: 0xbc},
{value: 0x3008, lo: 0xbd, hi: 0xbf},
// Block 0x3e, offset 0x223
{value: 0x0000, lo: 0x0b},
{value: 0x3008, lo: 0x80, hi: 0x81},
{value: 0x3308, lo: 0x82, hi: 0x82},
{value: 0x3008, lo: 0x83, hi: 0x83},
{value: 0x3808, lo: 0x84, hi: 0x84},
{value: 0x0008, lo: 0x85, hi: 0x8c},
{value: 0x0040, lo: 0x8d, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x99},
{value: 0x0018, lo: 0x9a, hi: 0xaa},
{value: 0x3308, lo: 0xab, hi: 0xb3},
{value: 0x0018, lo: 0xb4, hi: 0xbe},
{value: 0x0040, lo: 0xbf, hi: 0xbf},
// Block 0x3f, offset 0x22f
{value: 0x0000, lo: 0x0b},
{value: 0x3308, lo: 0x80, hi: 0x81},
{value: 0x3008, lo: 0x82, hi: 0x82},
{value: 0x0008, lo: 0x83, hi: 0xa0},
{value: 0x3008, lo: 0xa1, hi: 0xa1},
{value: 0x3308, lo: 0xa2, hi: 0xa5},
{value: 0x3008, lo: 0xa6, hi: 0xa7},
{value: 0x3308, lo: 0xa8, hi: 0xa9},
{value: 0x3808, lo: 0xaa, hi: 0xaa},
{value: 0x3b08, lo: 0xab, hi: 0xab},
{value: 0x3308, lo: 0xac, hi: 0xad},
{value: 0x0008, lo: 0xae, hi: 0xbf},
// Block 0x40, offset 0x23b
{value: 0x0000, lo: 0x0b},
{value: 0x0008, lo: 0x80, hi: 0xa5},
{value: 0x3308, lo: 0xa6, hi: 0xa6},
{value: 0x3008, lo: 0xa7, hi: 0xa7},
{value: 0x3308, lo: 0xa8, hi: 0xa9},
{value: 0x3008, lo: 0xaa, hi: 0xac},
{value: 0x3308, lo: 0xad, hi: 0xad},
{value: 0x3008, lo: 0xae, hi: 0xae},
{value: 0x3308, lo: 0xaf, hi: 0xb1},
{value: 0x3808, lo: 0xb2, hi: 0xb3},
{value: 0x0040, lo: 0xb4, hi: 0xbb},
{value: 0x0018, lo: 0xbc, hi: 0xbf},
// Block 0x41, offset 0x247
{value: 0x0000, lo: 0x07},
{value: 0x0008, lo: 0x80, hi: 0xa3},
{value: 0x3008, lo: 0xa4, hi: 0xab},
{value: 0x3308, lo: 0xac, hi: 0xb3},
{value: 0x3008, lo: 0xb4, hi: 0xb5},
{value: 0x3308, lo: 0xb6, hi: 0xb7},
{value: 0x0040, lo: 0xb8, hi: 0xba},
{value: 0x0018, lo: 0xbb, hi: 0xbf},
// Block 0x42, offset 0x24f
{value: 0x0000, lo: 0x04},
{value: 0x0008, lo: 0x80, hi: 0x89},
{value: 0x0040, lo: 0x8a, hi: 0x8c},
{value: 0x0008, lo: 0x8d, hi: 0xbd},
{value: 0x0018, lo: 0xbe, hi: 0xbf},
// Block 0x43, offset 0x254
{value: 0x0000, lo: 0x0c},
{value: 0x02a9, lo: 0x80, hi: 0x80},
{value: 0x02b1, lo: 0x81, hi: 0x81},
{value: 0x02b9, lo: 0x82, hi: 0x82},
{value: 0x02c1, lo: 0x83, hi: 0x83},
{value: 0x02c9, lo: 0x84, hi: 0x85},
{value: 0x02d1, lo: 0x86, hi: 0x86},
{value: 0x02d9, lo: 0x87, hi: 0x87},
{value: 0x057d, lo: 0x88, hi: 0x88},
{value: 0x0040, lo: 0x89, hi: 0x8f},
{value: 0x059d, lo: 0x90, hi: 0xba},
{value: 0x0040, lo: 0xbb, hi: 0xbc},
{value: 0x059d, lo: 0xbd, hi: 0xbf},
// Block 0x44, offset 0x261
{value: 0x0000, lo: 0x10},
{value: 0x0018, lo: 0x80, hi: 0x87},
{value: 0x0040, lo: 0x88, hi: 0x8f},
{value: 0x3308, lo: 0x90, hi: 0x92},
{value: 0x0018, lo: 0x93, hi: 0x93},
{value: 0x3308, lo: 0x94, hi: 0xa0},
{value: 0x3008, lo: 0xa1, hi: 0xa1},
{value: 0x3308, lo: 0xa2, hi: 0xa8},
{value: 0x0008, lo: 0xa9, hi: 0xac},
{value: 0x3308, lo: 0xad, hi: 0xad},
{value: 0x0008, lo: 0xae, hi: 0xb3},
{value: 0x3308, lo: 0xb4, hi: 0xb4},
{value: 0x0008, lo: 0xb5, hi: 0xb6},
{value: 0x3008, lo: 0xb7, hi: 0xb7},
{value: 0x3308, lo: 0xb8, hi: 0xb9},
{value: 0x0008, lo: 0xba, hi: 0xba},
{value: 0x0040, lo: 0xbb, hi: 0xbf},
// Block 0x45, offset 0x272
{value: 0x0000, lo: 0x0a},
{value: 0x0008, lo: 0x80, hi: 0x87},
{value: 0xe045, lo: 0x88, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x95},
{value: 0x0040, lo: 0x96, hi: 0x97},
{value: 0xe045, lo: 0x98, hi: 0x9d},
{value: 0x0040, lo: 0x9e, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xa7},
{value: 0xe045, lo: 0xa8, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xb7},
{value: 0xe045, lo: 0xb8, hi: 0xbf},
// Block 0x46, offset 0x27d
{value: 0x0000, lo: 0x04},
{value: 0x0018, lo: 0x80, hi: 0x80},
{value: 0x0040, lo: 0x81, hi: 0x8f},
{value: 0x3318, lo: 0x90, hi: 0xb0},
{value: 0x0040, lo: 0xb1, hi: 0xbf},
// Block 0x47, offset 0x282
{value: 0x0000, lo: 0x08},
{value: 0x0018, lo: 0x80, hi: 0x82},
{value: 0x0040, lo: 0x83, hi: 0x83},
{value: 0x0008, lo: 0x84, hi: 0x84},
{value: 0x0018, lo: 0x85, hi: 0x88},
{value: 0x0851, lo: 0x89, hi: 0x89},
{value: 0x0018, lo: 0x8a, hi: 0x8b},
{value: 0x0040, lo: 0x8c, hi: 0x8f},
{value: 0x0018, lo: 0x90, hi: 0xbf},
// Block 0x48, offset 0x28b
{value: 0x0000, lo: 0x07},
{value: 0x0018, lo: 0x80, hi: 0xab},
{value: 0x0859, lo: 0xac, hi: 0xac},
{value: 0x0861, lo: 0xad, hi: 0xad},
{value: 0x0018, lo: 0xae, hi: 0xae},
{value: 0x0869, lo: 0xaf, hi: 0xaf},
{value: 0x0871, lo: 0xb0, hi: 0xb0},
{value: 0x0018, lo: 0xb1, hi: 0xbf},
// Block 0x49, offset 0x293
{value: 0x0000, lo: 0x05},
{value: 0x0018, lo: 0x80, hi: 0x9f},
{value: 0x0080, lo: 0xa0, hi: 0xa0},
{value: 0x0018, lo: 0xa1, hi: 0xad},
{value: 0x0080, lo: 0xae, hi: 0xaf},
{value: 0x0018, lo: 0xb0, hi: 0xbf},
// Block 0x4a, offset 0x299
{value: 0x0000, lo: 0x04},
{value: 0x0018, lo: 0x80, hi: 0xa8},
{value: 0x09dd, lo: 0xa9, hi: 0xa9},
{value: 0x09fd, lo: 0xaa, hi: 0xaa},
{value: 0x0018, lo: 0xab, hi: 0xbf},
// Block 0x4b, offset 0x29e
{value: 0x0000, lo: 0x02},
{value: 0x0018, lo: 0x80, hi: 0xa6},
{value: 0x0040, lo: 0xa7, hi: 0xbf},
// Block 0x4c, offset 0x2a1
{value: 0x0000, lo: 0x03},
{value: 0x0018, lo: 0x80, hi: 0x8b},
{value: 0x0929, lo: 0x8c, hi: 0x8c},
{value: 0x0018, lo: 0x8d, hi: 0xbf},
// Block 0x4d, offset 0x2a5
{value: 0x0000, lo: 0x05},
{value: 0x0018, lo: 0x80, hi: 0xb3},
{value: 0x0e7e, lo: 0xb4, hi: 0xb4},
{value: 0x0932, lo: 0xb5, hi: 0xb5},
{value: 0x0e9e, lo: 0xb6, hi: 0xb6},
{value: 0x0018, lo: 0xb7, hi: 0xbf},
// Block 0x4e, offset 0x2ab
{value: 0x0000, lo: 0x03},
{value: 0x0018, lo: 0x80, hi: 0x9b},
{value: 0x0939, lo: 0x9c, hi: 0x9c},
{value: 0x0018, lo: 0x9d, hi: 0xbf},
// Block 0x4f, offset 0x2af
{value: 0x0000, lo: 0x03},
{value: 0x0018, lo: 0x80, hi: 0xb3},
{value: 0x0040, lo: 0xb4, hi: 0xb5},
{value: 0x0018, lo: 0xb6, hi: 0xbf},
// Block 0x50, offset 0x2b3
{value: 0x0000, lo: 0x03},
{value: 0x0018, lo: 0x80, hi: 0x95},
{value: 0x0040, lo: 0x96, hi: 0x96},
{value: 0x0018, lo: 0x97, hi: 0xbf},
// Block 0x51, offset 0x2b7
{value: 0x0000, lo: 0x04},
{value: 0xe185, lo: 0x80, hi: 0x8f},
{value: 0x03f5, lo: 0x90, hi: 0x9f},
{value: 0x0ebd, lo: 0xa0, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xbf},
// Block 0x52, offset 0x2bc
{value: 0x0000, lo: 0x07},
{value: 0x0008, lo: 0x80, hi: 0xa5},
{value: 0x0040, lo: 0xa6, hi: 0xa6},
{value: 0x0008, lo: 0xa7, hi: 0xa7},
{value: 0x0040, lo: 0xa8, hi: 0xac},
{value: 0x0008, lo: 0xad, hi: 0xad},
{value: 0x0040, lo: 0xae, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xbf},
// Block 0x53, offset 0x2c4
{value: 0x0000, lo: 0x06},
{value: 0x0008, lo: 0x80, hi: 0xa7},
{value: 0x0040, lo: 0xa8, hi: 0xae},
{value: 0xe075, lo: 0xaf, hi: 0xaf},
{value: 0x0018, lo: 0xb0, hi: 0xb0},
{value: 0x0040, lo: 0xb1, hi: 0xbe},
{value: 0x3b08, lo: 0xbf, hi: 0xbf},
// Block 0x54, offset 0x2cb
{value: 0x0000, lo: 0x0a},
{value: 0x0008, lo: 0x80, hi: 0x96},
{value: 0x0040, lo: 0x97, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xa6},
{value: 0x0040, lo: 0xa7, hi: 0xa7},
{value: 0x0008, lo: 0xa8, hi: 0xae},
{value: 0x0040, lo: 0xaf, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xb6},
{value: 0x0040, lo: 0xb7, hi: 0xb7},
{value: 0x0008, lo: 0xb8, hi: 0xbe},
{value: 0x0040, lo: 0xbf, hi: 0xbf},
// Block 0x55, offset 0x2d6
{value: 0x0000, lo: 0x09},
{value: 0x0008, lo: 0x80, hi: 0x86},
{value: 0x0040, lo: 0x87, hi: 0x87},
{value: 0x0008, lo: 0x88, hi: 0x8e},
{value: 0x0040, lo: 0x8f, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x96},
{value: 0x0040, lo: 0x97, hi: 0x97},
{value: 0x0008, lo: 0x98, hi: 0x9e},
{value: 0x0040, lo: 0x9f, hi: 0x9f},
{value: 0x3308, lo: 0xa0, hi: 0xbf},
// Block 0x56, offset 0x2e0
{value: 0x0000, lo: 0x03},
{value: 0x0018, lo: 0x80, hi: 0xae},
{value: 0x0008, lo: 0xaf, hi: 0xaf},
{value: 0x0018, lo: 0xb0, hi: 0xbf},
// Block 0x57, offset 0x2e4
{value: 0x0000, lo: 0x02},
{value: 0x0018, lo: 0x80, hi: 0x9d},
{value: 0x0040, lo: 0x9e, hi: 0xbf},
// Block 0x58, offset 0x2e7
{value: 0x0000, lo: 0x05},
{value: 0x0018, lo: 0x80, hi: 0x99},
{value: 0x0040, lo: 0x9a, hi: 0x9a},
{value: 0x0018, lo: 0x9b, hi: 0x9e},
{value: 0x0ef5, lo: 0x9f, hi: 0x9f},
{value: 0x0018, lo: 0xa0, hi: 0xbf},
// Block 0x59, offset 0x2ed
{value: 0x0000, lo: 0x03},
{value: 0x0018, lo: 0x80, hi: 0xb2},
{value: 0x0f15, lo: 0xb3, hi: 0xb3},
{value: 0x0040, lo: 0xb4, hi: 0xbf},
// Block 0x5a, offset 0x2f1
{value: 0x0020, lo: 0x01},
{value: 0x0f35, lo: 0x80, hi: 0xbf},
// Block 0x5b, offset 0x2f3
{value: 0x0020, lo: 0x02},
{value: 0x1735, lo: 0x80, hi: 0x8f},
{value: 0x1915, lo: 0x90, hi: 0xbf},
// Block 0x5c, offset 0x2f6
{value: 0x0020, lo: 0x01},
{value: 0x1f15, lo: 0x80, hi: 0xbf},
// Block 0x5d, offset 0x2f8
{value: 0x0000, lo: 0x02},
{value: 0x0040, lo: 0x80, hi: 0x80},
{value: 0x0008, lo: 0x81, hi: 0xbf},
// Block 0x5e, offset 0x2fb
{value: 0x0000, lo: 0x09},
{value: 0x0008, lo: 0x80, hi: 0x96},
{value: 0x0040, lo: 0x97, hi: 0x98},
{value: 0x3308, lo: 0x99, hi: 0x9a},
{value: 0x096a, lo: 0x9b, hi: 0x9b},
{value: 0x0972, lo: 0x9c, hi: 0x9c},
{value: 0x0008, lo: 0x9d, hi: 0x9e},
{value: 0x0979, lo: 0x9f, hi: 0x9f},
{value: 0x0018, lo: 0xa0, hi: 0xa0},
{value: 0x0008, lo: 0xa1, hi: 0xbf},
// Block 0x5f, offset 0x305
{value: 0x0000, lo: 0x02},
{value: 0x0008, lo: 0x80, hi: 0xbe},
{value: 0x0981, lo: 0xbf, hi: 0xbf},
// Block 0x60, offset 0x308
{value: 0x0000, lo: 0x0e},
{value: 0x0040, lo: 0x80, hi: 0x84},
{value: 0x0008, lo: 0x85, hi: 0xaf},
{value: 0x0040, lo: 0xb0, hi: 0xb0},
{value: 0x2a35, lo: 0xb1, hi: 0xb1},
{value: 0x2a55, lo: 0xb2, hi: 0xb2},
{value: 0x2a75, lo: 0xb3, hi: 0xb3},
{value: 0x2a95, lo: 0xb4, hi: 0xb4},
{value: 0x2a75, lo: 0xb5, hi: 0xb5},
{value: 0x2ab5, lo: 0xb6, hi: 0xb6},
{value: 0x2ad5, lo: 0xb7, hi: 0xb7},
{value: 0x2af5, lo: 0xb8, hi: 0xb9},
{value: 0x2b15, lo: 0xba, hi: 0xbb},
{value: 0x2b35, lo: 0xbc, hi: 0xbd},
{value: 0x2b15, lo: 0xbe, hi: 0xbf},
// Block 0x61, offset 0x317
{value: 0x0000, lo: 0x03},
{value: 0x0018, lo: 0x80, hi: 0xa3},
{value: 0x0040, lo: 0xa4, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xbf},
// Block 0x62, offset 0x31b
{value: 0x0008, lo: 0x03},
{value: 0x098a, lo: 0x80, hi: 0x9e},
{value: 0x0040, lo: 0x9f, hi: 0x9f},
{value: 0x0a82, lo: 0xa0, hi: 0xbf},
// Block 0x63, offset 0x31f
{value: 0x0008, lo: 0x01},
{value: 0x0d19, lo: 0x80, hi: 0xbf},
// Block 0x64, offset 0x321
{value: 0x0008, lo: 0x08},
{value: 0x0f19, lo: 0x80, hi: 0xb0},
{value: 0x4045, lo: 0xb1, hi: 0xb1},
{value: 0x10a1, lo: 0xb2, hi: 0xb3},
{value: 0x4065, lo: 0xb4, hi: 0xb4},
{value: 0x10b1, lo: 0xb5, hi: 0xb7},
{value: 0x4085, lo: 0xb8, hi: 0xb8},
{value: 0x4085, lo: 0xb9, hi: 0xb9},
{value: 0x10c9, lo: 0xba, hi: 0xbf},
// Block 0x65, offset 0x32a
{value: 0x0000, lo: 0x03},
{value: 0x0008, lo: 0x80, hi: 0x8c},
{value: 0x0040, lo: 0x8d, hi: 0x8f},
{value: 0x0018, lo: 0x90, hi: 0xbf},
// Block 0x66, offset 0x32e
{value: 0x0000, lo: 0x04},
{value: 0x0018, lo: 0x80, hi: 0x86},
{value: 0x0040, lo: 0x87, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0xbd},
{value: 0x0018, lo: 0xbe, hi: 0xbf},
// Block 0x67, offset 0x333
{value: 0x0000, lo: 0x04},
{value: 0x0008, lo: 0x80, hi: 0x8c},
{value: 0x0018, lo: 0x8d, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0xab},
{value: 0x0040, lo: 0xac, hi: 0xbf},
// Block 0x68, offset 0x338
{value: 0x0000, lo: 0x05},
{value: 0x0008, lo: 0x80, hi: 0xa5},
{value: 0x0018, lo: 0xa6, hi: 0xaf},
{value: 0x3308, lo: 0xb0, hi: 0xb1},
{value: 0x0018, lo: 0xb2, hi: 0xb7},
{value: 0x0040, lo: 0xb8, hi: 0xbf},
// Block 0x69, offset 0x33e
{value: 0x0000, lo: 0x0f},
{value: 0x0008, lo: 0x80, hi: 0x81},
{value: 0x3308, lo: 0x82, hi: 0x82},
{value: 0x0008, lo: 0x83, hi: 0x85},
{value: 0x3b08, lo: 0x86, hi: 0x86},
{value: 0x0008, lo: 0x87, hi: 0x8a},
{value: 0x3308, lo: 0x8b, hi: 0x8b},
{value: 0x0008, lo: 0x8c, hi: 0xa2},
{value: 0x3008, lo: 0xa3, hi: 0xa4},
{value: 0x3308, lo: 0xa5, hi: 0xa6},
{value: 0x3008, lo: 0xa7, hi: 0xa7},
{value: 0x0018, lo: 0xa8, hi: 0xab},
{value: 0x3b08, lo: 0xac, hi: 0xac},
{value: 0x0040, lo: 0xad, hi: 0xaf},
{value: 0x0018, lo: 0xb0, hi: 0xb9},
{value: 0x0040, lo: 0xba, hi: 0xbf},
// Block 0x6a, offset 0x34e
{value: 0x0000, lo: 0x05},
{value: 0x0208, lo: 0x80, hi: 0xb1},
{value: 0x0108, lo: 0xb2, hi: 0xb2},
{value: 0x0008, lo: 0xb3, hi: 0xb3},
{value: 0x0018, lo: 0xb4, hi: 0xb7},
{value: 0x0040, lo: 0xb8, hi: 0xbf},
// Block 0x6b, offset 0x354
{value: 0x0000, lo: 0x03},
{value: 0x3008, lo: 0x80, hi: 0x81},
{value: 0x0008, lo: 0x82, hi: 0xb3},
{value: 0x3008, lo: 0xb4, hi: 0xbf},
// Block 0x6c, offset 0x358
{value: 0x0000, lo: 0x0e},
{value: 0x3008, lo: 0x80, hi: 0x83},
{value: 0x3b08, lo: 0x84, hi: 0x84},
{value: 0x3308, lo: 0x85, hi: 0x85},
{value: 0x0040, lo: 0x86, hi: 0x8d},
{value: 0x0018, lo: 0x8e, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x99},
{value: 0x0040, lo: 0x9a, hi: 0x9f},
{value: 0x3308, lo: 0xa0, hi: 0xb1},
{value: 0x0008, lo: 0xb2, hi: 0xb7},
{value: 0x0018, lo: 0xb8, hi: 0xba},
{value: 0x0008, lo: 0xbb, hi: 0xbb},
{value: 0x0018, lo: 0xbc, hi: 0xbc},
{value: 0x0008, lo: 0xbd, hi: 0xbe},
{value: 0x3308, lo: 0xbf, hi: 0xbf},
// Block 0x6d, offset 0x367
{value: 0x0000, lo: 0x04},
{value: 0x0008, lo: 0x80, hi: 0xa5},
{value: 0x3308, lo: 0xa6, hi: 0xad},
{value: 0x0018, lo: 0xae, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xbf},
// Block 0x6e, offset 0x36c
{value: 0x0000, lo: 0x07},
{value: 0x0008, lo: 0x80, hi: 0x86},
{value: 0x3308, lo: 0x87, hi: 0x91},
{value: 0x3008, lo: 0x92, hi: 0x92},
{value: 0x3808, lo: 0x93, hi: 0x93},
{value: 0x0040, lo: 0x94, hi: 0x9e},
{value: 0x0018, lo: 0x9f, hi: 0xbc},
{value: 0x0040, lo: 0xbd, hi: 0xbf},
// Block 0x6f, offset 0x374
{value: 0x0000, lo: 0x09},
{value: 0x3308, lo: 0x80, hi: 0x82},
{value: 0x3008, lo: 0x83, hi: 0x83},
{value: 0x0008, lo: 0x84, hi: 0xb2},
{value: 0x3308, lo: 0xb3, hi: 0xb3},
{value: 0x3008, lo: 0xb4, hi: 0xb5},
{value: 0x3308, lo: 0xb6, hi: 0xb9},
{value: 0x3008, lo: 0xba, hi: 0xbb},
{value: 0x3308, lo: 0xbc, hi: 0xbd},
{value: 0x3008, lo: 0xbe, hi: 0xbf},
// Block 0x70, offset 0x37e
{value: 0x0000, lo: 0x0a},
{value: 0x3808, lo: 0x80, hi: 0x80},
{value: 0x0018, lo: 0x81, hi: 0x8d},
{value: 0x0040, lo: 0x8e, hi: 0x8e},
{value: 0x0008, lo: 0x8f, hi: 0x99},
{value: 0x0040, lo: 0x9a, hi: 0x9d},
{value: 0x0018, lo: 0x9e, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xa4},
{value: 0x3308, lo: 0xa5, hi: 0xa5},
{value: 0x0008, lo: 0xa6, hi: 0xbe},
{value: 0x0040, lo: 0xbf, hi: 0xbf},
// Block 0x71, offset 0x389
{value: 0x0000, lo: 0x07},
{value: 0x0008, lo: 0x80, hi: 0xa8},
{value: 0x3308, lo: 0xa9, hi: 0xae},
{value: 0x3008, lo: 0xaf, hi: 0xb0},
{value: 0x3308, lo: 0xb1, hi: 0xb2},
{value: 0x3008, lo: 0xb3, hi: 0xb4},
{value: 0x3308, lo: 0xb5, hi: 0xb6},
{value: 0x0040, lo: 0xb7, hi: 0xbf},
// Block 0x72, offset 0x391
{value: 0x0000, lo: 0x10},
{value: 0x0008, lo: 0x80, hi: 0x82},
{value: 0x3308, lo: 0x83, hi: 0x83},
{value: 0x0008, lo: 0x84, hi: 0x8b},
{value: 0x3308, lo: 0x8c, hi: 0x8c},
{value: 0x3008, lo: 0x8d, hi: 0x8d},
{value: 0x0040, lo: 0x8e, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x99},
{value: 0x0040, lo: 0x9a, hi: 0x9b},
{value: 0x0018, lo: 0x9c, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xb6},
{value: 0x0018, lo: 0xb7, hi: 0xb9},
{value: 0x0008, lo: 0xba, hi: 0xba},
{value: 0x3008, lo: 0xbb, hi: 0xbb},
{value: 0x3308, lo: 0xbc, hi: 0xbc},
{value: 0x3008, lo: 0xbd, hi: 0xbd},
{value: 0x0008, lo: 0xbe, hi: 0xbf},
// Block 0x73, offset 0x3a2
{value: 0x0000, lo: 0x08},
{value: 0x0008, lo: 0x80, hi: 0xaf},
{value: 0x3308, lo: 0xb0, hi: 0xb0},
{value: 0x0008, lo: 0xb1, hi: 0xb1},
{value: 0x3308, lo: 0xb2, hi: 0xb4},
{value: 0x0008, lo: 0xb5, hi: 0xb6},
{value: 0x3308, lo: 0xb7, hi: 0xb8},
{value: 0x0008, lo: 0xb9, hi: 0xbd},
{value: 0x3308, lo: 0xbe, hi: 0xbf},
// Block 0x74, offset 0x3ab
{value: 0x0000, lo: 0x0f},
{value: 0x0008, lo: 0x80, hi: 0x80},
{value: 0x3308, lo: 0x81, hi: 0x81},
{value: 0x0008, lo: 0x82, hi: 0x82},
{value: 0x0040, lo: 0x83, hi: 0x9a},
{value: 0x0008, lo: 0x9b, hi: 0x9d},
{value: 0x0018, lo: 0x9e, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xaa},
{value: 0x3008, lo: 0xab, hi: 0xab},
{value: 0x3308, lo: 0xac, hi: 0xad},
{value: 0x3008, lo: 0xae, hi: 0xaf},
{value: 0x0018, lo: 0xb0, hi: 0xb1},
{value: 0x0008, lo: 0xb2, hi: 0xb4},
{value: 0x3008, lo: 0xb5, hi: 0xb5},
{value: 0x3b08, lo: 0xb6, hi: 0xb6},
{value: 0x0040, lo: 0xb7, hi: 0xbf},
// Block 0x75, offset 0x3bb
{value: 0x0000, lo: 0x0c},
{value: 0x0040, lo: 0x80, hi: 0x80},
{value: 0x0008, lo: 0x81, hi: 0x86},
{value: 0x0040, lo: 0x87, hi: 0x88},
{value: 0x0008, lo: 0x89, hi: 0x8e},
{value: 0x0040, lo: 0x8f, hi: 0x90},
{value: 0x0008, lo: 0x91, hi: 0x96},
{value: 0x0040, lo: 0x97, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xa6},
{value: 0x0040, lo: 0xa7, hi: 0xa7},
{value: 0x0008, lo: 0xa8, hi: 0xae},
{value: 0x0040, lo: 0xaf, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xbf},
// Block 0x76, offset 0x3c8
{value: 0x0000, lo: 0x0b},
{value: 0x0008, lo: 0x80, hi: 0x9a},
{value: 0x0018, lo: 0x9b, hi: 0x9b},
{value: 0x449d, lo: 0x9c, hi: 0x9c},
{value: 0x44b5, lo: 0x9d, hi: 0x9d},
{value: 0x0941, lo: 0x9e, hi: 0x9e},
{value: 0xe06d, lo: 0x9f, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xa8},
{value: 0x13f9, lo: 0xa9, hi: 0xa9},
{value: 0x0018, lo: 0xaa, hi: 0xab},
{value: 0x0040, lo: 0xac, hi: 0xaf},
{value: 0x44cd, lo: 0xb0, hi: 0xbf},
// Block 0x77, offset 0x3d4
{value: 0x0000, lo: 0x04},
{value: 0x44ed, lo: 0x80, hi: 0x8f},
{value: 0x450d, lo: 0x90, hi: 0x9f},
{value: 0x452d, lo: 0xa0, hi: 0xaf},
{value: 0x450d, lo: 0xb0, hi: 0xbf},
// Block 0x78, offset 0x3d9
{value: 0x0000, lo: 0x0c},
{value: 0x0008, lo: 0x80, hi: 0xa2},
{value: 0x3008, lo: 0xa3, hi: 0xa4},
{value: 0x3308, lo: 0xa5, hi: 0xa5},
{value: 0x3008, lo: 0xa6, hi: 0xa7},
{value: 0x3308, lo: 0xa8, hi: 0xa8},
{value: 0x3008, lo: 0xa9, hi: 0xaa},
{value: 0x0018, lo: 0xab, hi: 0xab},
{value: 0x3008, lo: 0xac, hi: 0xac},
{value: 0x3b08, lo: 0xad, hi: 0xad},
{value: 0x0040, lo: 0xae, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xb9},
{value: 0x0040, lo: 0xba, hi: 0xbf},
// Block 0x79, offset 0x3e6
{value: 0x0000, lo: 0x03},
{value: 0x0008, lo: 0x80, hi: 0xa3},
{value: 0x0040, lo: 0xa4, hi: 0xaf},
{value: 0x0018, lo: 0xb0, hi: 0xbf},
// Block 0x7a, offset 0x3ea
{value: 0x0000, lo: 0x04},
{value: 0x0018, lo: 0x80, hi: 0x86},
{value: 0x0040, lo: 0x87, hi: 0x8a},
{value: 0x0018, lo: 0x8b, hi: 0xbb},
{value: 0x0040, lo: 0xbc, hi: 0xbf},
// Block 0x7b, offset 0x3ef
{value: 0x0000, lo: 0x01},
{value: 0x0040, lo: 0x80, hi: 0xbf},
// Block 0x7c, offset 0x3f1
{value: 0x0020, lo: 0x01},
{value: 0x454d, lo: 0x80, hi: 0xbf},
// Block 0x7d, offset 0x3f3
{value: 0x0020, lo: 0x03},
{value: 0x4d4d, lo: 0x80, hi: 0x94},
{value: 0x4b0d, lo: 0x95, hi: 0x95},
{value: 0x4fed, lo: 0x96, hi: 0xbf},
// Block 0x7e, offset 0x3f7
{value: 0x0020, lo: 0x01},
{value: 0x552d, lo: 0x80, hi: 0xbf},
// Block 0x7f, offset 0x3f9
{value: 0x0020, lo: 0x03},
{value: 0x5d2d, lo: 0x80, hi: 0x84},
{value: 0x568d, lo: 0x85, hi: 0x85},
{value: 0x5dcd, lo: 0x86, hi: 0xbf},
// Block 0x80, offset 0x3fd
{value: 0x0020, lo: 0x08},
{value: 0x6b8d, lo: 0x80, hi: 0x8f},
{value: 0x6d4d, lo: 0x90, hi: 0x90},
{value: 0x6d8d, lo: 0x91, hi: 0xab},
{value: 0x1401, lo: 0xac, hi: 0xac},
{value: 0x70ed, lo: 0xad, hi: 0xad},
{value: 0x0040, lo: 0xae, hi: 0xae},
{value: 0x0040, lo: 0xaf, hi: 0xaf},
{value: 0x710d, lo: 0xb0, hi: 0xbf},
// Block 0x81, offset 0x406
{value: 0x0020, lo: 0x05},
{value: 0x730d, lo: 0x80, hi: 0xad},
{value: 0x656d, lo: 0xae, hi: 0xae},
{value: 0x78cd, lo: 0xaf, hi: 0xb5},
{value: 0x6f8d, lo: 0xb6, hi: 0xb6},
{value: 0x79ad, lo: 0xb7, hi: 0xbf},
// Block 0x82, offset 0x40c
{value: 0x0008, lo: 0x03},
{value: 0x1751, lo: 0x80, hi: 0x82},
{value: 0x1741, lo: 0x83, hi: 0x83},
{value: 0x1769, lo: 0x84, hi: 0xbf},
// Block 0x83, offset 0x410
{value: 0x0008, lo: 0x0f},
{value: 0x1d81, lo: 0x80, hi: 0x83},
{value: 0x1d99, lo: 0x84, hi: 0x85},
{value: 0x1da1, lo: 0x86, hi: 0x87},
{value: 0x1da9, lo: 0x88, hi: 0x8f},
{value: 0x0040, lo: 0x90, hi: 0x90},
{value: 0x0040, lo: 0x91, hi: 0x91},
{value: 0x1de9, lo: 0x92, hi: 0x97},
{value: 0x1e11, lo: 0x98, hi: 0x9c},
{value: 0x1e31, lo: 0x9d, hi: 0xb3},
{value: 0x1d71, lo: 0xb4, hi: 0xb4},
{value: 0x1d81, lo: 0xb5, hi: 0xb5},
{value: 0x1ee9, lo: 0xb6, hi: 0xbb},
{value: 0x1f09, lo: 0xbc, hi: 0xbc},
{value: 0x1ef9, lo: 0xbd, hi: 0xbd},
{value: 0x1f19, lo: 0xbe, hi: 0xbf},
// Block 0x84, offset 0x420
{value: 0x0000, lo: 0x09},
{value: 0x0008, lo: 0x80, hi: 0x8b},
{value: 0x0040, lo: 0x8c, hi: 0x8c},
{value: 0x0008, lo: 0x8d, hi: 0xa6},
{value: 0x0040, lo: 0xa7, hi: 0xa7},
{value: 0x0008, lo: 0xa8, hi: 0xba},
{value: 0x0040, lo: 0xbb, hi: 0xbb},
{value: 0x0008, lo: 0xbc, hi: 0xbd},
{value: 0x0040, lo: 0xbe, hi: 0xbe},
{value: 0x0008, lo: 0xbf, hi: 0xbf},
// Block 0x85, offset 0x42a
{value: 0x0000, lo: 0x04},
{value: 0x0008, lo: 0x80, hi: 0x8d},
{value: 0x0040, lo: 0x8e, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x9d},
{value: 0x0040, lo: 0x9e, hi: 0xbf},
// Block 0x86, offset 0x42f
{value: 0x0000, lo: 0x02},
{value: 0x0008, lo: 0x80, hi: 0xba},
{value: 0x0040, lo: 0xbb, hi: 0xbf},
// Block 0x87, offset 0x432
{value: 0x0000, lo: 0x05},
{value: 0x0018, lo: 0x80, hi: 0x82},
{value: 0x0040, lo: 0x83, hi: 0x86},
{value: 0x0018, lo: 0x87, hi: 0xb3},
{value: 0x0040, lo: 0xb4, hi: 0xb6},
{value: 0x0018, lo: 0xb7, hi: 0xbf},
// Block 0x88, offset 0x438
{value: 0x0000, lo: 0x06},
{value: 0x0018, lo: 0x80, hi: 0x8e},
{value: 0x0040, lo: 0x8f, hi: 0x8f},
{value: 0x0018, lo: 0x90, hi: 0x9c},
{value: 0x0040, lo: 0x9d, hi: 0x9f},
{value: 0x0018, lo: 0xa0, hi: 0xa0},
{value: 0x0040, lo: 0xa1, hi: 0xbf},
// Block 0x89, offset 0x43f
{value: 0x0000, lo: 0x04},
{value: 0x0040, lo: 0x80, hi: 0x8f},
{value: 0x0018, lo: 0x90, hi: 0xbc},
{value: 0x3308, lo: 0xbd, hi: 0xbd},
{value: 0x0040, lo: 0xbe, hi: 0xbf},
// Block 0x8a, offset 0x444
{value: 0x0000, lo: 0x03},
{value: 0x0008, lo: 0x80, hi: 0x9c},
{value: 0x0040, lo: 0x9d, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xbf},
// Block 0x8b, offset 0x448
{value: 0x0000, lo: 0x05},
{value: 0x0008, lo: 0x80, hi: 0x90},
{value: 0x0040, lo: 0x91, hi: 0x9f},
{value: 0x3308, lo: 0xa0, hi: 0xa0},
{value: 0x0018, lo: 0xa1, hi: 0xbb},
{value: 0x0040, lo: 0xbc, hi: 0xbf},
// Block 0x8c, offset 0x44e
{value: 0x0000, lo: 0x04},
{value: 0x0008, lo: 0x80, hi: 0x9f},
{value: 0x0018, lo: 0xa0, hi: 0xa3},
{value: 0x0040, lo: 0xa4, hi: 0xac},
{value: 0x0008, lo: 0xad, hi: 0xbf},
// Block 0x8d, offset 0x453
{value: 0x0000, lo: 0x08},
{value: 0x0008, lo: 0x80, hi: 0x80},
{value: 0x0018, lo: 0x81, hi: 0x81},
{value: 0x0008, lo: 0x82, hi: 0x89},
{value: 0x0018, lo: 0x8a, hi: 0x8a},
{value: 0x0040, lo: 0x8b, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0xb5},
{value: 0x3308, lo: 0xb6, hi: 0xba},
{value: 0x0040, lo: 0xbb, hi: 0xbf},
// Block 0x8e, offset 0x45c
{value: 0x0000, lo: 0x04},
{value: 0x0008, lo: 0x80, hi: 0x9d},
{value: 0x0040, lo: 0x9e, hi: 0x9e},
{value: 0x0018, lo: 0x9f, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xbf},
// Block 0x8f, offset 0x461
{value: 0x0000, lo: 0x05},
{value: 0x0008, lo: 0x80, hi: 0x83},
{value: 0x0040, lo: 0x84, hi: 0x87},
{value: 0x0008, lo: 0x88, hi: 0x8f},
{value: 0x0018, lo: 0x90, hi: 0x95},
{value: 0x0040, lo: 0x96, hi: 0xbf},
// Block 0x90, offset 0x467
{value: 0x0000, lo: 0x06},
{value: 0xe145, lo: 0x80, hi: 0x87},
{value: 0xe1c5, lo: 0x88, hi: 0x8f},
{value: 0xe145, lo: 0x90, hi: 0x97},
{value: 0x8b0d, lo: 0x98, hi: 0x9f},
{value: 0x8b25, lo: 0xa0, hi: 0xa7},
{value: 0x0008, lo: 0xa8, hi: 0xbf},
// Block 0x91, offset 0x46e
{value: 0x0000, lo: 0x06},
{value: 0x0008, lo: 0x80, hi: 0x9d},
{value: 0x0040, lo: 0x9e, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xa9},
{value: 0x0040, lo: 0xaa, hi: 0xaf},
{value: 0x8b25, lo: 0xb0, hi: 0xb7},
{value: 0x8b0d, lo: 0xb8, hi: 0xbf},
// Block 0x92, offset 0x475
{value: 0x0000, lo: 0x06},
{value: 0xe145, lo: 0x80, hi: 0x87},
{value: 0xe1c5, lo: 0x88, hi: 0x8f},
{value: 0xe145, lo: 0x90, hi: 0x93},
{value: 0x0040, lo: 0x94, hi: 0x97},
{value: 0x0008, lo: 0x98, hi: 0xbb},
{value: 0x0040, lo: 0xbc, hi: 0xbf},
// Block 0x93, offset 0x47c
{value: 0x0000, lo: 0x03},
{value: 0x0008, lo: 0x80, hi: 0xa7},
{value: 0x0040, lo: 0xa8, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xbf},
// Block 0x94, offset 0x480
{value: 0x0000, lo: 0x02},
{value: 0x0008, lo: 0x80, hi: 0xb6},
{value: 0x0040, lo: 0xb7, hi: 0xbf},
// Block 0x95, offset 0x483
{value: 0x0000, lo: 0x04},
{value: 0x0008, lo: 0x80, hi: 0x95},
{value: 0x0040, lo: 0x96, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xa7},
{value: 0x0040, lo: 0xa8, hi: 0xbf},
// Block 0x96, offset 0x488
{value: 0x0000, lo: 0x0b},
{value: 0x0808, lo: 0x80, hi: 0x85},
{value: 0x0040, lo: 0x86, hi: 0x87},
{value: 0x0808, lo: 0x88, hi: 0x88},
{value: 0x0040, lo: 0x89, hi: 0x89},
{value: 0x0808, lo: 0x8a, hi: 0xb5},
{value: 0x0040, lo: 0xb6, hi: 0xb6},
{value: 0x0808, lo: 0xb7, hi: 0xb8},
{value: 0x0040, lo: 0xb9, hi: 0xbb},
{value: 0x0808, lo: 0xbc, hi: 0xbc},
{value: 0x0040, lo: 0xbd, hi: 0xbe},
{value: 0x0808, lo: 0xbf, hi: 0xbf},
// Block 0x97, offset 0x494
{value: 0x0000, lo: 0x05},
{value: 0x0808, lo: 0x80, hi: 0x95},
{value: 0x0040, lo: 0x96, hi: 0x96},
{value: 0x0818, lo: 0x97, hi: 0x9f},
{value: 0x0808, lo: 0xa0, hi: 0xb6},
{value: 0x0818, lo: 0xb7, hi: 0xbf},
// Block 0x98, offset 0x49a
{value: 0x0000, lo: 0x04},
{value: 0x0808, lo: 0x80, hi: 0x9e},
{value: 0x0040, lo: 0x9f, hi: 0xa6},
{value: 0x0818, lo: 0xa7, hi: 0xaf},
{value: 0x0040, lo: 0xb0, hi: 0xbf},
// Block 0x99, offset 0x49f
{value: 0x0000, lo: 0x06},
{value: 0x0040, lo: 0x80, hi: 0x9f},
{value: 0x0808, lo: 0xa0, hi: 0xb2},
{value: 0x0040, lo: 0xb3, hi: 0xb3},
{value: 0x0808, lo: 0xb4, hi: 0xb5},
{value: 0x0040, lo: 0xb6, hi: 0xba},
{value: 0x0818, lo: 0xbb, hi: 0xbf},
// Block 0x9a, offset 0x4a6
{value: 0x0000, lo: 0x07},
{value: 0x0808, lo: 0x80, hi: 0x95},
{value: 0x0818, lo: 0x96, hi: 0x9b},
{value: 0x0040, lo: 0x9c, hi: 0x9e},
{value: 0x0018, lo: 0x9f, hi: 0x9f},
{value: 0x0808, lo: 0xa0, hi: 0xb9},
{value: 0x0040, lo: 0xba, hi: 0xbe},
{value: 0x0818, lo: 0xbf, hi: 0xbf},
// Block 0x9b, offset 0x4ae
{value: 0x0000, lo: 0x04},
{value: 0x0808, lo: 0x80, hi: 0xb7},
{value: 0x0040, lo: 0xb8, hi: 0xbb},
{value: 0x0818, lo: 0xbc, hi: 0xbd},
{value: 0x0808, lo: 0xbe, hi: 0xbf},
// Block 0x9c, offset 0x4b3
{value: 0x0000, lo: 0x03},
{value: 0x0818, lo: 0x80, hi: 0x8f},
{value: 0x0040, lo: 0x90, hi: 0x91},
{value: 0x0818, lo: 0x92, hi: 0xbf},
// Block 0x9d, offset 0x4b7
{value: 0x0000, lo: 0x0f},
{value: 0x0808, lo: 0x80, hi: 0x80},
{value: 0x3308, lo: 0x81, hi: 0x83},
{value: 0x0040, lo: 0x84, hi: 0x84},
{value: 0x3308, lo: 0x85, hi: 0x86},
{value: 0x0040, lo: 0x87, hi: 0x8b},
{value: 0x3308, lo: 0x8c, hi: 0x8f},
{value: 0x0808, lo: 0x90, hi: 0x93},
{value: 0x0040, lo: 0x94, hi: 0x94},
{value: 0x0808, lo: 0x95, hi: 0x97},
{value: 0x0040, lo: 0x98, hi: 0x98},
{value: 0x0808, lo: 0x99, hi: 0xb5},
{value: 0x0040, lo: 0xb6, hi: 0xb7},
{value: 0x3308, lo: 0xb8, hi: 0xba},
{value: 0x0040, lo: 0xbb, hi: 0xbe},
{value: 0x3b08, lo: 0xbf, hi: 0xbf},
// Block 0x9e, offset 0x4c7
{value: 0x0000, lo: 0x06},
{value: 0x0818, lo: 0x80, hi: 0x88},
{value: 0x0040, lo: 0x89, hi: 0x8f},
{value: 0x0818, lo: 0x90, hi: 0x98},
{value: 0x0040, lo: 0x99, hi: 0x9f},
{value: 0x0808, lo: 0xa0, hi: 0xbc},
{value: 0x0818, lo: 0xbd, hi: 0xbf},
// Block 0x9f, offset 0x4ce
{value: 0x0000, lo: 0x03},
{value: 0x0808, lo: 0x80, hi: 0x9c},
{value: 0x0818, lo: 0x9d, hi: 0x9f},
{value: 0x0040, lo: 0xa0, hi: 0xbf},
// Block 0xa0, offset 0x4d2
{value: 0x0000, lo: 0x03},
{value: 0x0808, lo: 0x80, hi: 0xb5},
{value: 0x0040, lo: 0xb6, hi: 0xb8},
{value: 0x0018, lo: 0xb9, hi: 0xbf},
// Block 0xa1, offset 0x4d6
{value: 0x0000, lo: 0x06},
{value: 0x0808, lo: 0x80, hi: 0x95},
{value: 0x0040, lo: 0x96, hi: 0x97},
{value: 0x0818, lo: 0x98, hi: 0x9f},
{value: 0x0808, lo: 0xa0, hi: 0xb2},
{value: 0x0040, lo: 0xb3, hi: 0xb7},
{value: 0x0818, lo: 0xb8, hi: 0xbf},
// Block 0xa2, offset 0x4dd
{value: 0x0000, lo: 0x01},
{value: 0x0808, lo: 0x80, hi: 0xbf},
// Block 0xa3, offset 0x4df
{value: 0x0000, lo: 0x02},
{value: 0x0808, lo: 0x80, hi: 0x88},
{value: 0x0040, lo: 0x89, hi: 0xbf},
// Block 0xa4, offset 0x4e2
{value: 0x0000, lo: 0x02},
{value: 0x03dd, lo: 0x80, hi: 0xb2},
{value: 0x0040, lo: 0xb3, hi: 0xbf},
// Block 0xa5, offset 0x4e5
{value: 0x0000, lo: 0x03},
{value: 0x0808, lo: 0x80, hi: 0xb2},
{value: 0x0040, lo: 0xb3, hi: 0xb9},
{value: 0x0818, lo: 0xba, hi: 0xbf},
// Block 0xa6, offset 0x4e9
{value: 0x0000, lo: 0x08},
{value: 0x0908, lo: 0x80, hi: 0x80},
{value: 0x0a08, lo: 0x81, hi: 0xa1},
{value: 0x0c08, lo: 0xa2, hi: 0xa2},
{value: 0x0a08, lo: 0xa3, hi: 0xa3},
{value: 0x3308, lo: 0xa4, hi: 0xa7},
{value: 0x0040, lo: 0xa8, hi: 0xaf},
{value: 0x0808, lo: 0xb0, hi: 0xb9},
{value: 0x0040, lo: 0xba, hi: 0xbf},
// Block 0xa7, offset 0x4f2
{value: 0x0000, lo: 0x03},
{value: 0x0040, lo: 0x80, hi: 0x9f},
{value: 0x0818, lo: 0xa0, hi: 0xbe},
{value: 0x0040, lo: 0xbf, hi: 0xbf},
// Block 0xa8, offset 0x4f6
{value: 0x0000, lo: 0x07},
{value: 0x0808, lo: 0x80, hi: 0xa9},
{value: 0x0040, lo: 0xaa, hi: 0xaa},
{value: 0x3308, lo: 0xab, hi: 0xac},
{value: 0x0818, lo: 0xad, hi: 0xad},
{value: 0x0040, lo: 0xae, hi: 0xaf},
{value: 0x0808, lo: 0xb0, hi: 0xb1},
{value: 0x0040, lo: 0xb2, hi: 0xbf},
// Block 0xa9, offset 0x4fe
{value: 0x0000, lo: 0x02},
{value: 0x0040, lo: 0x80, hi: 0xbc},
{value: 0x3308, lo: 0xbd, hi: 0xbf},
// Block 0xaa, offset 0x501
{value: 0x0000, lo: 0x07},
{value: 0x0808, lo: 0x80, hi: 0x9c},
{value: 0x0818, lo: 0x9d, hi: 0xa6},
{value: 0x0808, lo: 0xa7, hi: 0xa7},
{value: 0x0040, lo: 0xa8, hi: 0xaf},
{value: 0x0a08, lo: 0xb0, hi: 0xb2},
{value: 0x0c08, lo: 0xb3, hi: 0xb3},
{value: 0x0a08, lo: 0xb4, hi: 0xbf},
// Block 0xab, offset 0x509
{value: 0x0000, lo: 0x0a},
{value: 0x0a08, lo: 0x80, hi: 0x84},
{value: 0x0808, lo: 0x85, hi: 0x85},
{value: 0x3308, lo: 0x86, hi: 0x90},
{value: 0x0a18, lo: 0x91, hi: 0x93},
{value: 0x0c18, lo: 0x94, hi: 0x94},
{value: 0x0818, lo: 0x95, hi: 0x99},
{value: 0x0040, lo: 0x9a, hi: 0xaf},
{value: 0x0a08, lo: 0xb0, hi: 0xb3},
{value: 0x0c08, lo: 0xb4, hi: 0xb5},
{value: 0x0a08, lo: 0xb6, hi: 0xbf},
// Block 0xac, offset 0x514
{value: 0x0000, lo: 0x0e},
{value: 0x0a08, lo: 0x80, hi: 0x81},
{value: 0x3308, lo: 0x82, hi: 0x85},
{value: 0x0818, lo: 0x86, hi: 0x89},
{value: 0x0040, lo: 0x8a, hi: 0xaf},
{value: 0x0a08, lo: 0xb0, hi: 0xb0},
{value: 0x0808, lo: 0xb1, hi: 0xb1},
{value: 0x0a08, lo: 0xb2, hi: 0xb3},
{value: 0x0c08, lo: 0xb4, hi: 0xb6},
{value: 0x0808, lo: 0xb7, hi: 0xb7},
{value: 0x0a08, lo: 0xb8, hi: 0xb8},
{value: 0x0c08, lo: 0xb9, hi: 0xba},
{value: 0x0a08, lo: 0xbb, hi: 0xbc},
{value: 0x0c08, lo: 0xbd, hi: 0xbd},
{value: 0x0a08, lo: 0xbe, hi: 0xbf},
// Block 0xad, offset 0x523
{value: 0x0000, lo: 0x0b},
{value: 0x0808, lo: 0x80, hi: 0x80},
{value: 0x0a08, lo: 0x81, hi: 0x81},
{value: 0x0c08, lo: 0x82, hi: 0x83},
{value: 0x0a08, lo: 0x84, hi: 0x84},
{value: 0x0818, lo: 0x85, hi: 0x88},
{value: 0x0c18, lo: 0x89, hi: 0x89},
{value: 0x0a18, lo: 0x8a, hi: 0x8a},
{value: 0x0918, lo: 0x8b, hi: 0x8b},
{value: 0x0040, lo: 0x8c, hi: 0x9f},
{value: 0x0808, lo: 0xa0, hi: 0xb6},
{value: 0x0040, lo: 0xb7, hi: 0xbf},
// Block 0xae, offset 0x52f
{value: 0x0000, lo: 0x05},
{value: 0x3008, lo: 0x80, hi: 0x80},
{value: 0x3308, lo: 0x81, hi: 0x81},
{value: 0x3008, lo: 0x82, hi: 0x82},
{value: 0x0008, lo: 0x83, hi: 0xb7},
{value: 0x3308, lo: 0xb8, hi: 0xbf},
// Block 0xaf, offset 0x535
{value: 0x0000, lo: 0x0c},
{value: 0x3308, lo: 0x80, hi: 0x85},
{value: 0x3b08, lo: 0x86, hi: 0x86},
{value: 0x0018, lo: 0x87, hi: 0x8d},
{value: 0x0040, lo: 0x8e, hi: 0x91},
{value: 0x0018, lo: 0x92, hi: 0xa5},
{value: 0x0008, lo: 0xa6, hi: 0xaf},
{value: 0x3b08, lo: 0xb0, hi: 0xb0},
{value: 0x0008, lo: 0xb1, hi: 0xb2},
{value: 0x3308, lo: 0xb3, hi: 0xb4},
{value: 0x0008, lo: 0xb5, hi: 0xb5},
{value: 0x0040, lo: 0xb6, hi: 0xbe},
{value: 0x3b08, lo: 0xbf, hi: 0xbf},
// Block 0xb0, offset 0x542
{value: 0x0000, lo: 0x0b},
{value: 0x3308, lo: 0x80, hi: 0x81},
{value: 0x3008, lo: 0x82, hi: 0x82},
{value: 0x0008, lo: 0x83, hi: 0xaf},
{value: 0x3008, lo: 0xb0, hi: 0xb2},
{value: 0x3308, lo: 0xb3, hi: 0xb6},
{value: 0x3008, lo: 0xb7, hi: 0xb8},
{value: 0x3b08, lo: 0xb9, hi: 0xb9},
{value: 0x3308, lo: 0xba, hi: 0xba},
{value: 0x0018, lo: 0xbb, hi: 0xbc},
{value: 0x0040, lo: 0xbd, hi: 0xbd},
{value: 0x0018, lo: 0xbe, hi: 0xbf},
// Block 0xb1, offset 0x54e
{value: 0x0000, lo: 0x07},
{value: 0x0018, lo: 0x80, hi: 0x81},
{value: 0x3308, lo: 0x82, hi: 0x82},
{value: 0x0040, lo: 0x83, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0xa8},
{value: 0x0040, lo: 0xa9, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xb9},
{value: 0x0040, lo: 0xba, hi: 0xbf},
// Block 0xb2, offset 0x556
{value: 0x0000, lo: 0x08},
{value: 0x3308, lo: 0x80, hi: 0x82},
{value: 0x0008, lo: 0x83, hi: 0xa6},
{value: 0x3308, lo: 0xa7, hi: 0xab},
{value: 0x3008, lo: 0xac, hi: 0xac},
{value: 0x3308, lo: 0xad, hi: 0xb2},
{value: 0x3b08, lo: 0xb3, hi: 0xb4},
{value: 0x0040, lo: 0xb5, hi: 0xb5},
{value: 0x0008, lo: 0xb6, hi: 0xbf},
// Block 0xb3, offset 0x55f
{value: 0x0000, lo: 0x0a},
{value: 0x0018, lo: 0x80, hi: 0x83},
{value: 0x0008, lo: 0x84, hi: 0x84},
{value: 0x3008, lo: 0x85, hi: 0x86},
{value: 0x0008, lo: 0x87, hi: 0x87},
{value: 0x0040, lo: 0x88, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0xb2},
{value: 0x3308, lo: 0xb3, hi: 0xb3},
{value: 0x0018, lo: 0xb4, hi: 0xb5},
{value: 0x0008, lo: 0xb6, hi: 0xb6},
{value: 0x0040, lo: 0xb7, hi: 0xbf},
// Block 0xb4, offset 0x56a
{value: 0x0000, lo: 0x06},
{value: 0x3308, lo: 0x80, hi: 0x81},
{value: 0x3008, lo: 0x82, hi: 0x82},
{value: 0x0008, lo: 0x83, hi: 0xb2},
{value: 0x3008, lo: 0xb3, hi: 0xb5},
{value: 0x3308, lo: 0xb6, hi: 0xbe},
{value: 0x3008, lo: 0xbf, hi: 0xbf},
// Block 0xb5, offset 0x571
{value: 0x0000, lo: 0x0e},
{value: 0x3808, lo: 0x80, hi: 0x80},
{value: 0x0008, lo: 0x81, hi: 0x84},
{value: 0x0018, lo: 0x85, hi: 0x88},
{value: 0x3308, lo: 0x89, hi: 0x8c},
{value: 0x0018, lo: 0x8d, hi: 0x8d},
{value: 0x3008, lo: 0x8e, hi: 0x8e},
{value: 0x3308, lo: 0x8f, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x9a},
{value: 0x0018, lo: 0x9b, hi: 0x9b},
{value: 0x0008, lo: 0x9c, hi: 0x9c},
{value: 0x0018, lo: 0x9d, hi: 0x9f},
{value: 0x0040, lo: 0xa0, hi: 0xa0},
{value: 0x0018, lo: 0xa1, hi: 0xb4},
{value: 0x0040, lo: 0xb5, hi: 0xbf},
// Block 0xb6, offset 0x580
{value: 0x0000, lo: 0x0c},
{value: 0x0008, lo: 0x80, hi: 0x91},
{value: 0x0040, lo: 0x92, hi: 0x92},
{value: 0x0008, lo: 0x93, hi: 0xab},
{value: 0x3008, lo: 0xac, hi: 0xae},
{value: 0x3308, lo: 0xaf, hi: 0xb1},
{value: 0x3008, lo: 0xb2, hi: 0xb3},
{value: 0x3308, lo: 0xb4, hi: 0xb4},
{value: 0x3808, lo: 0xb5, hi: 0xb5},
{value: 0x3308, lo: 0xb6, hi: 0xb7},
{value: 0x0018, lo: 0xb8, hi: 0xbd},
{value: 0x3308, lo: 0xbe, hi: 0xbe},
{value: 0x0008, lo: 0xbf, hi: 0xbf},
// Block 0xb7, offset 0x58d
{value: 0x0000, lo: 0x03},
{value: 0x0008, lo: 0x80, hi: 0x80},
{value: 0x3308, lo: 0x81, hi: 0x81},
{value: 0x0040, lo: 0x82, hi: 0xbf},
// Block 0xb8, offset 0x591
{value: 0x0000, lo: 0x0c},
{value: 0x0008, lo: 0x80, hi: 0x86},
{value: 0x0040, lo: 0x87, hi: 0x87},
{value: 0x0008, lo: 0x88, hi: 0x88},
{value: 0x0040, lo: 0x89, hi: 0x89},
{value: 0x0008, lo: 0x8a, hi: 0x8d},
{value: 0x0040, lo: 0x8e, hi: 0x8e},
{value: 0x0008, lo: 0x8f, hi: 0x9d},
{value: 0x0040, lo: 0x9e, hi: 0x9e},
{value: 0x0008, lo: 0x9f, hi: 0xa8},
{value: 0x0018, lo: 0xa9, hi: 0xa9},
{value: 0x0040, lo: 0xaa, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xbf},
// Block 0xb9, offset 0x59e
{value: 0x0000, lo: 0x08},
{value: 0x0008, lo: 0x80, hi: 0x9e},
{value: 0x3308, lo: 0x9f, hi: 0x9f},
{value: 0x3008, lo: 0xa0, hi: 0xa2},
{value: 0x3308, lo: 0xa3, hi: 0xa9},
{value: 0x3b08, lo: 0xaa, hi: 0xaa},
{value: 0x0040, lo: 0xab, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xb9},
{value: 0x0040, lo: 0xba, hi: 0xbf},
// Block 0xba, offset 0x5a7
{value: 0x0000, lo: 0x03},
{value: 0x0008, lo: 0x80, hi: 0xb4},
{value: 0x3008, lo: 0xb5, hi: 0xb7},
{value: 0x3308, lo: 0xb8, hi: 0xbf},
// Block 0xbb, offset 0x5ab
{value: 0x0000, lo: 0x0e},
{value: 0x3008, lo: 0x80, hi: 0x81},
{value: 0x3b08, lo: 0x82, hi: 0x82},
{value: 0x3308, lo: 0x83, hi: 0x84},
{value: 0x3008, lo: 0x85, hi: 0x85},
{value: 0x3308, lo: 0x86, hi: 0x86},
{value: 0x0008, lo: 0x87, hi: 0x8a},
{value: 0x0018, lo: 0x8b, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x99},
{value: 0x0018, lo: 0x9a, hi: 0x9b},
{value: 0x0040, lo: 0x9c, hi: 0x9c},
{value: 0x0018, lo: 0x9d, hi: 0x9d},
{value: 0x3308, lo: 0x9e, hi: 0x9e},
{value: 0x0008, lo: 0x9f, hi: 0xa1},
{value: 0x0040, lo: 0xa2, hi: 0xbf},
// Block 0xbc, offset 0x5ba
{value: 0x0000, lo: 0x07},
{value: 0x0008, lo: 0x80, hi: 0xaf},
{value: 0x3008, lo: 0xb0, hi: 0xb2},
{value: 0x3308, lo: 0xb3, hi: 0xb8},
{value: 0x3008, lo: 0xb9, hi: 0xb9},
{value: 0x3308, lo: 0xba, hi: 0xba},
{value: 0x3008, lo: 0xbb, hi: 0xbe},
{value: 0x3308, lo: 0xbf, hi: 0xbf},
// Block 0xbd, offset 0x5c2
{value: 0x0000, lo: 0x0a},
{value: 0x3308, lo: 0x80, hi: 0x80},
{value: 0x3008, lo: 0x81, hi: 0x81},
{value: 0x3b08, lo: 0x82, hi: 0x82},
{value: 0x3308, lo: 0x83, hi: 0x83},
{value: 0x0008, lo: 0x84, hi: 0x85},
{value: 0x0018, lo: 0x86, hi: 0x86},
{value: 0x0008, lo: 0x87, hi: 0x87},
{value: 0x0040, lo: 0x88, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x99},
{value: 0x0040, lo: 0x9a, hi: 0xbf},
// Block 0xbe, offset 0x5cd
{value: 0x0000, lo: 0x08},
{value: 0x0008, lo: 0x80, hi: 0xae},
{value: 0x3008, lo: 0xaf, hi: 0xb1},
{value: 0x3308, lo: 0xb2, hi: 0xb5},
{value: 0x0040, lo: 0xb6, hi: 0xb7},
{value: 0x3008, lo: 0xb8, hi: 0xbb},
{value: 0x3308, lo: 0xbc, hi: 0xbd},
{value: 0x3008, lo: 0xbe, hi: 0xbe},
{value: 0x3b08, lo: 0xbf, hi: 0xbf},
// Block 0xbf, offset 0x5d6
{value: 0x0000, lo: 0x05},
{value: 0x3308, lo: 0x80, hi: 0x80},
{value: 0x0018, lo: 0x81, hi: 0x97},
{value: 0x0008, lo: 0x98, hi: 0x9b},
{value: 0x3308, lo: 0x9c, hi: 0x9d},
{value: 0x0040, lo: 0x9e, hi: 0xbf},
// Block 0xc0, offset 0x5dc
{value: 0x0000, lo: 0x07},
{value: 0x0008, lo: 0x80, hi: 0xaf},
{value: 0x3008, lo: 0xb0, hi: 0xb2},
{value: 0x3308, lo: 0xb3, hi: 0xba},
{value: 0x3008, lo: 0xbb, hi: 0xbc},
{value: 0x3308, lo: 0xbd, hi: 0xbd},
{value: 0x3008, lo: 0xbe, hi: 0xbe},
{value: 0x3b08, lo: 0xbf, hi: 0xbf},
// Block 0xc1, offset 0x5e4
{value: 0x0000, lo: 0x08},
{value: 0x3308, lo: 0x80, hi: 0x80},
{value: 0x0018, lo: 0x81, hi: 0x83},
{value: 0x0008, lo: 0x84, hi: 0x84},
{value: 0x0040, lo: 0x85, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x99},
{value: 0x0040, lo: 0x9a, hi: 0x9f},
{value: 0x0018, lo: 0xa0, hi: 0xac},
{value: 0x0040, lo: 0xad, hi: 0xbf},
// Block 0xc2, offset 0x5ed
{value: 0x0000, lo: 0x0b},
{value: 0x0008, lo: 0x80, hi: 0xaa},
{value: 0x3308, lo: 0xab, hi: 0xab},
{value: 0x3008, lo: 0xac, hi: 0xac},
{value: 0x3308, lo: 0xad, hi: 0xad},
{value: 0x3008, lo: 0xae, hi: 0xaf},
{value: 0x3308, lo: 0xb0, hi: 0xb5},
{value: 0x3808, lo: 0xb6, hi: 0xb6},
{value: 0x3308, lo: 0xb7, hi: 0xb7},
{value: 0x0008, lo: 0xb8, hi: 0xb8},
{value: 0x0018, lo: 0xb9, hi: 0xb9},
{value: 0x0040, lo: 0xba, hi: 0xbf},
// Block 0xc3, offset 0x5f9
{value: 0x0000, lo: 0x02},
{value: 0x0008, lo: 0x80, hi: 0x89},
{value: 0x0040, lo: 0x8a, hi: 0xbf},
// Block 0xc4, offset 0x5fc
{value: 0x0000, lo: 0x0b},
{value: 0x0008, lo: 0x80, hi: 0x9a},
{value: 0x0040, lo: 0x9b, hi: 0x9c},
{value: 0x3308, lo: 0x9d, hi: 0x9f},
{value: 0x3008, lo: 0xa0, hi: 0xa1},
{value: 0x3308, lo: 0xa2, hi: 0xa5},
{value: 0x3008, lo: 0xa6, hi: 0xa6},
{value: 0x3308, lo: 0xa7, hi: 0xaa},
{value: 0x3b08, lo: 0xab, hi: 0xab},
{value: 0x0040, lo: 0xac, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xb9},
{value: 0x0018, lo: 0xba, hi: 0xbf},
// Block 0xc5, offset 0x608
{value: 0x0000, lo: 0x02},
{value: 0x0008, lo: 0x80, hi: 0x86},
{value: 0x0040, lo: 0x87, hi: 0xbf},
// Block 0xc6, offset 0x60b
{value: 0x0000, lo: 0x08},
{value: 0x0008, lo: 0x80, hi: 0xab},
{value: 0x3008, lo: 0xac, hi: 0xae},
{value: 0x3308, lo: 0xaf, hi: 0xb7},
{value: 0x3008, lo: 0xb8, hi: 0xb8},
{value: 0x3b08, lo: 0xb9, hi: 0xb9},
{value: 0x3308, lo: 0xba, hi: 0xba},
{value: 0x0018, lo: 0xbb, hi: 0xbb},
{value: 0x0040, lo: 0xbc, hi: 0xbf},
// Block 0xc7, offset 0x614
{value: 0x0000, lo: 0x02},
{value: 0x0040, lo: 0x80, hi: 0x9f},
{value: 0x049d, lo: 0xa0, hi: 0xbf},
// Block 0xc8, offset 0x617
{value: 0x0000, lo: 0x04},
{value: 0x0008, lo: 0x80, hi: 0xa9},
{value: 0x0018, lo: 0xaa, hi: 0xb2},
{value: 0x0040, lo: 0xb3, hi: 0xbe},
{value: 0x0008, lo: 0xbf, hi: 0xbf},
// Block 0xc9, offset 0x61c
{value: 0x0000, lo: 0x08},
{value: 0x3008, lo: 0x80, hi: 0x80},
{value: 0x0008, lo: 0x81, hi: 0x81},
{value: 0x3008, lo: 0x82, hi: 0x82},
{value: 0x3308, lo: 0x83, hi: 0x83},
{value: 0x0018, lo: 0x84, hi: 0x86},
{value: 0x0040, lo: 0x87, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x99},
{value: 0x0040, lo: 0x9a, hi: 0xbf},
// Block 0xca, offset 0x625
{value: 0x0000, lo: 0x04},
{value: 0x0040, lo: 0x80, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xa7},
{value: 0x0040, lo: 0xa8, hi: 0xa9},
{value: 0x0008, lo: 0xaa, hi: 0xbf},
// Block 0xcb, offset 0x62a
{value: 0x0000, lo: 0x0c},
{value: 0x0008, lo: 0x80, hi: 0x90},
{value: 0x3008, lo: 0x91, hi: 0x93},
{value: 0x3308, lo: 0x94, hi: 0x97},
{value: 0x0040, lo: 0x98, hi: 0x99},
{value: 0x3308, lo: 0x9a, hi: 0x9b},
{value: 0x3008, lo: 0x9c, hi: 0x9f},
{value: 0x3b08, lo: 0xa0, hi: 0xa0},
{value: 0x0008, lo: 0xa1, hi: 0xa1},
{value: 0x0018, lo: 0xa2, hi: 0xa2},
{value: 0x0008, lo: 0xa3, hi: 0xa3},
{value: 0x3008, lo: 0xa4, hi: 0xa4},
{value: 0x0040, lo: 0xa5, hi: 0xbf},
// Block 0xcc, offset 0x637
{value: 0x0000, lo: 0x0a},
{value: 0x0008, lo: 0x80, hi: 0x80},
{value: 0x3308, lo: 0x81, hi: 0x8a},
{value: 0x0008, lo: 0x8b, hi: 0xb2},
{value: 0x3308, lo: 0xb3, hi: 0xb3},
{value: 0x3b08, lo: 0xb4, hi: 0xb4},
{value: 0x3308, lo: 0xb5, hi: 0xb8},
{value: 0x3008, lo: 0xb9, hi: 0xb9},
{value: 0x0008, lo: 0xba, hi: 0xba},
{value: 0x3308, lo: 0xbb, hi: 0xbe},
{value: 0x0018, lo: 0xbf, hi: 0xbf},
// Block 0xcd, offset 0x642
{value: 0x0000, lo: 0x08},
{value: 0x0018, lo: 0x80, hi: 0x86},
{value: 0x3b08, lo: 0x87, hi: 0x87},
{value: 0x0040, lo: 0x88, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x90},
{value: 0x3308, lo: 0x91, hi: 0x96},
{value: 0x3008, lo: 0x97, hi: 0x98},
{value: 0x3308, lo: 0x99, hi: 0x9b},
{value: 0x0008, lo: 0x9c, hi: 0xbf},
// Block 0xce, offset 0x64b
{value: 0x0000, lo: 0x0a},
{value: 0x0008, lo: 0x80, hi: 0x89},
{value: 0x3308, lo: 0x8a, hi: 0x96},
{value: 0x3008, lo: 0x97, hi: 0x97},
{value: 0x3308, lo: 0x98, hi: 0x98},
{value: 0x3b08, lo: 0x99, hi: 0x99},
{value: 0x0018, lo: 0x9a, hi: 0x9c},
{value: 0x0008, lo: 0x9d, hi: 0x9d},
{value: 0x0018, lo: 0x9e, hi: 0xa2},
{value: 0x0040, lo: 0xa3, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xbf},
// Block 0xcf, offset 0x656
{value: 0x0000, lo: 0x02},
{value: 0x0008, lo: 0x80, hi: 0xb8},
{value: 0x0040, lo: 0xb9, hi: 0xbf},
// Block 0xd0, offset 0x659
{value: 0x0000, lo: 0x02},
{value: 0x0018, lo: 0x80, hi: 0x89},
{value: 0x0040, lo: 0x8a, hi: 0xbf},
// Block 0xd1, offset 0x65c
{value: 0x0000, lo: 0x09},
{value: 0x0008, lo: 0x80, hi: 0x88},
{value: 0x0040, lo: 0x89, hi: 0x89},
{value: 0x0008, lo: 0x8a, hi: 0xae},
{value: 0x3008, lo: 0xaf, hi: 0xaf},
{value: 0x3308, lo: 0xb0, hi: 0xb6},
{value: 0x0040, lo: 0xb7, hi: 0xb7},
{value: 0x3308, lo: 0xb8, hi: 0xbd},
{value: 0x3008, lo: 0xbe, hi: 0xbe},
{value: 0x3b08, lo: 0xbf, hi: 0xbf},
// Block 0xd2, offset 0x666
{value: 0x0000, lo: 0x08},
{value: 0x0008, lo: 0x80, hi: 0x80},
{value: 0x0018, lo: 0x81, hi: 0x85},
{value: 0x0040, lo: 0x86, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x99},
{value: 0x0018, lo: 0x9a, hi: 0xac},
{value: 0x0040, lo: 0xad, hi: 0xaf},
{value: 0x0018, lo: 0xb0, hi: 0xb1},
{value: 0x0008, lo: 0xb2, hi: 0xbf},
// Block 0xd3, offset 0x66f
{value: 0x0000, lo: 0x0b},
{value: 0x0008, lo: 0x80, hi: 0x8f},
{value: 0x0040, lo: 0x90, hi: 0x91},
{value: 0x3308, lo: 0x92, hi: 0xa7},
{value: 0x0040, lo: 0xa8, hi: 0xa8},
{value: 0x3008, lo: 0xa9, hi: 0xa9},
{value: 0x3308, lo: 0xaa, hi: 0xb0},
{value: 0x3008, lo: 0xb1, hi: 0xb1},
{value: 0x3308, lo: 0xb2, hi: 0xb3},
{value: 0x3008, lo: 0xb4, hi: 0xb4},
{value: 0x3308, lo: 0xb5, hi: 0xb6},
{value: 0x0040, lo: 0xb7, hi: 0xbf},
// Block 0xd4, offset 0x67b
{value: 0x0000, lo: 0x0c},
{value: 0x0008, lo: 0x80, hi: 0x86},
{value: 0x0040, lo: 0x87, hi: 0x87},
{value: 0x0008, lo: 0x88, hi: 0x89},
{value: 0x0040, lo: 0x8a, hi: 0x8a},
{value: 0x0008, lo: 0x8b, hi: 0xb0},
{value: 0x3308, lo: 0xb1, hi: 0xb6},
{value: 0x0040, lo: 0xb7, hi: 0xb9},
{value: 0x3308, lo: 0xba, hi: 0xba},
{value: 0x0040, lo: 0xbb, hi: 0xbb},
{value: 0x3308, lo: 0xbc, hi: 0xbd},
{value: 0x0040, lo: 0xbe, hi: 0xbe},
{value: 0x3308, lo: 0xbf, hi: 0xbf},
// Block 0xd5, offset 0x688
{value: 0x0000, lo: 0x0c},
{value: 0x3308, lo: 0x80, hi: 0x83},
{value: 0x3b08, lo: 0x84, hi: 0x85},
{value: 0x0008, lo: 0x86, hi: 0x86},
{value: 0x3308, lo: 0x87, hi: 0x87},
{value: 0x0040, lo: 0x88, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x99},
{value: 0x0040, lo: 0x9a, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xa5},
{value: 0x0040, lo: 0xa6, hi: 0xa6},
{value: 0x0008, lo: 0xa7, hi: 0xa8},
{value: 0x0040, lo: 0xa9, hi: 0xa9},
{value: 0x0008, lo: 0xaa, hi: 0xbf},
// Block 0xd6, offset 0x695
{value: 0x0000, lo: 0x0d},
{value: 0x0008, lo: 0x80, hi: 0x89},
{value: 0x3008, lo: 0x8a, hi: 0x8e},
{value: 0x0040, lo: 0x8f, hi: 0x8f},
{value: 0x3308, lo: 0x90, hi: 0x91},
{value: 0x0040, lo: 0x92, hi: 0x92},
{value: 0x3008, lo: 0x93, hi: 0x94},
{value: 0x3308, lo: 0x95, hi: 0x95},
{value: 0x3008, lo: 0x96, hi: 0x96},
{value: 0x3b08, lo: 0x97, hi: 0x97},
{value: 0x0008, lo: 0x98, hi: 0x98},
{value: 0x0040, lo: 0x99, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xa9},
{value: 0x0040, lo: 0xaa, hi: 0xbf},
// Block 0xd7, offset 0x6a3
{value: 0x0000, lo: 0x06},
{value: 0x0040, lo: 0x80, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xb2},
{value: 0x3308, lo: 0xb3, hi: 0xb4},
{value: 0x3008, lo: 0xb5, hi: 0xb6},
{value: 0x0018, lo: 0xb7, hi: 0xb8},
{value: 0x0040, lo: 0xb9, hi: 0xbf},
// Block 0xd8, offset 0x6aa
{value: 0x0000, lo: 0x0a},
{value: 0x3308, lo: 0x80, hi: 0x81},
{value: 0x0008, lo: 0x82, hi: 0x82},
{value: 0x3008, lo: 0x83, hi: 0x83},
{value: 0x0008, lo: 0x84, hi: 0x90},
{value: 0x0040, lo: 0x91, hi: 0x91},
{value: 0x0008, lo: 0x92, hi: 0xb3},
{value: 0x3008, lo: 0xb4, hi: 0xb5},
{value: 0x3308, lo: 0xb6, hi: 0xba},
{value: 0x0040, lo: 0xbb, hi: 0xbd},
{value: 0x3008, lo: 0xbe, hi: 0xbf},
// Block 0xd9, offset 0x6b5
{value: 0x0000, lo: 0x06},
{value: 0x3308, lo: 0x80, hi: 0x80},
{value: 0x3808, lo: 0x81, hi: 0x81},
{value: 0x3b08, lo: 0x82, hi: 0x82},
{value: 0x0018, lo: 0x83, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x99},
{value: 0x0040, lo: 0x9a, hi: 0xbf},
// Block 0xda, offset 0x6bc
{value: 0x0000, lo: 0x03},
{value: 0x0040, lo: 0x80, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xb0},
{value: 0x0040, lo: 0xb1, hi: 0xbf},
// Block 0xdb, offset 0x6c0
{value: 0x0000, lo: 0x03},
{value: 0x0018, lo: 0x80, hi: 0xb1},
{value: 0x0040, lo: 0xb2, hi: 0xbe},
{value: 0x0018, lo: 0xbf, hi: 0xbf},
// Block 0xdc, offset 0x6c4
{value: 0x0000, lo: 0x02},
{value: 0x0008, lo: 0x80, hi: 0x99},
{value: 0x0040, lo: 0x9a, hi: 0xbf},
// Block 0xdd, offset 0x6c7
{value: 0x0000, lo: 0x04},
{value: 0x0018, lo: 0x80, hi: 0xae},
{value: 0x0040, lo: 0xaf, hi: 0xaf},
{value: 0x0018, lo: 0xb0, hi: 0xb4},
{value: 0x0040, lo: 0xb5, hi: 0xbf},
// Block 0xde, offset 0x6cc
{value: 0x0000, lo: 0x02},
{value: 0x0008, lo: 0x80, hi: 0x83},
{value: 0x0040, lo: 0x84, hi: 0xbf},
// Block 0xdf, offset 0x6cf
{value: 0x0000, lo: 0x02},
{value: 0x0040, lo: 0x80, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0xbf},
// Block 0xe0, offset 0x6d2
{value: 0x0000, lo: 0x03},
{value: 0x0008, lo: 0x80, hi: 0xb0},
{value: 0x0018, lo: 0xb1, hi: 0xb2},
{value: 0x0040, lo: 0xb3, hi: 0xbf},
// Block 0xe1, offset 0x6d6
{value: 0x0000, lo: 0x02},
{value: 0x0008, lo: 0x80, hi: 0xaf},
{value: 0x0340, lo: 0xb0, hi: 0xbf},
// Block 0xe2, offset 0x6d9
{value: 0x0000, lo: 0x04},
{value: 0x3308, lo: 0x80, hi: 0x80},
{value: 0x0008, lo: 0x81, hi: 0x86},
{value: 0x3308, lo: 0x87, hi: 0x95},
{value: 0x0040, lo: 0x96, hi: 0xbf},
// Block 0xe3, offset 0x6de
{value: 0x0000, lo: 0x06},
{value: 0x0008, lo: 0x80, hi: 0x9e},
{value: 0x0040, lo: 0x9f, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xa9},
{value: 0x0040, lo: 0xaa, hi: 0xad},
{value: 0x0018, lo: 0xae, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xbf},
// Block 0xe4, offset 0x6e5
{value: 0x0000, lo: 0x02},
{value: 0x0008, lo: 0x80, hi: 0xbe},
{value: 0x0040, lo: 0xbf, hi: 0xbf},
// Block 0xe5, offset 0x6e8
{value: 0x0000, lo: 0x07},
{value: 0x0008, lo: 0x80, hi: 0x89},
{value: 0x0040, lo: 0x8a, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0xad},
{value: 0x0040, lo: 0xae, hi: 0xaf},
{value: 0x3308, lo: 0xb0, hi: 0xb4},
{value: 0x0018, lo: 0xb5, hi: 0xb5},
{value: 0x0040, lo: 0xb6, hi: 0xbf},
// Block 0xe6, offset 0x6f0
{value: 0x0000, lo: 0x03},
{value: 0x0008, lo: 0x80, hi: 0xaf},
{value: 0x3308, lo: 0xb0, hi: 0xb6},
{value: 0x0018, lo: 0xb7, hi: 0xbf},
// Block 0xe7, offset 0x6f4
{value: 0x0000, lo: 0x0a},
{value: 0x0008, lo: 0x80, hi: 0x83},
{value: 0x0018, lo: 0x84, hi: 0x85},
{value: 0x0040, lo: 0x86, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x99},
{value: 0x0040, lo: 0x9a, hi: 0x9a},
{value: 0x0018, lo: 0x9b, hi: 0xa1},
{value: 0x0040, lo: 0xa2, hi: 0xa2},
{value: 0x0008, lo: 0xa3, hi: 0xb7},
{value: 0x0040, lo: 0xb8, hi: 0xbc},
{value: 0x0008, lo: 0xbd, hi: 0xbf},
// Block 0xe8, offset 0x6ff
{value: 0x0000, lo: 0x02},
{value: 0x0008, lo: 0x80, hi: 0x8f},
{value: 0x0040, lo: 0x90, hi: 0xbf},
// Block 0xe9, offset 0x702
{value: 0x0000, lo: 0x02},
{value: 0xe105, lo: 0x80, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xbf},
// Block 0xea, offset 0x705
{value: 0x0000, lo: 0x02},
{value: 0x0018, lo: 0x80, hi: 0x9a},
{value: 0x0040, lo: 0x9b, hi: 0xbf},
// Block 0xeb, offset 0x708
{value: 0x0000, lo: 0x05},
{value: 0x0008, lo: 0x80, hi: 0x8a},
{value: 0x0040, lo: 0x8b, hi: 0x8e},
{value: 0x3308, lo: 0x8f, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x90},
{value: 0x3008, lo: 0x91, hi: 0xbf},
// Block 0xec, offset 0x70e
{value: 0x0000, lo: 0x05},
{value: 0x3008, lo: 0x80, hi: 0x87},
{value: 0x0040, lo: 0x88, hi: 0x8e},
{value: 0x3308, lo: 0x8f, hi: 0x92},
{value: 0x0008, lo: 0x93, hi: 0x9f},
{value: 0x0040, lo: 0xa0, hi: 0xbf},
// Block 0xed, offset 0x714
{value: 0x0000, lo: 0x08},
{value: 0x0040, lo: 0x80, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xa1},
{value: 0x0018, lo: 0xa2, hi: 0xa2},
{value: 0x0008, lo: 0xa3, hi: 0xa3},
{value: 0x3308, lo: 0xa4, hi: 0xa4},
{value: 0x0040, lo: 0xa5, hi: 0xaf},
{value: 0x3008, lo: 0xb0, hi: 0xb1},
{value: 0x0040, lo: 0xb2, hi: 0xbf},
// Block 0xee, offset 0x71d
{value: 0x0000, lo: 0x02},
{value: 0x0008, lo: 0x80, hi: 0xb7},
{value: 0x0040, lo: 0xb8, hi: 0xbf},
// Block 0xef, offset 0x720
{value: 0x0000, lo: 0x02},
{value: 0x0008, lo: 0x80, hi: 0x95},
{value: 0x0040, lo: 0x96, hi: 0xbf},
// Block 0xf0, offset 0x723
{value: 0x0000, lo: 0x02},
{value: 0x0008, lo: 0x80, hi: 0x88},
{value: 0x0040, lo: 0x89, hi: 0xbf},
// Block 0xf1, offset 0x726
{value: 0x0000, lo: 0x07},
{value: 0x0040, lo: 0x80, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xb3},
{value: 0x0040, lo: 0xb4, hi: 0xb4},
{value: 0x0008, lo: 0xb5, hi: 0xbb},
{value: 0x0040, lo: 0xbc, hi: 0xbc},
{value: 0x0008, lo: 0xbd, hi: 0xbe},
{value: 0x0040, lo: 0xbf, hi: 0xbf},
// Block 0xf2, offset 0x72e
{value: 0x0000, lo: 0x04},
{value: 0x0008, lo: 0x80, hi: 0xa2},
{value: 0x0040, lo: 0xa3, hi: 0xb1},
{value: 0x0008, lo: 0xb2, hi: 0xb2},
{value: 0x0040, lo: 0xb3, hi: 0xbf},
// Block 0xf3, offset 0x733
{value: 0x0000, lo: 0x08},
{value: 0x0040, lo: 0x80, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x92},
{value: 0x0040, lo: 0x93, hi: 0x94},
{value: 0x0008, lo: 0x95, hi: 0x95},
{value: 0x0040, lo: 0x96, hi: 0xa3},
{value: 0x0008, lo: 0xa4, hi: 0xa7},
{value: 0x0040, lo: 0xa8, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xbf},
// Block 0xf4, offset 0x73c
{value: 0x0000, lo: 0x02},
{value: 0x0008, lo: 0x80, hi: 0xbb},
{value: 0x0040, lo: 0xbc, hi: 0xbf},
// Block 0xf5, offset 0x73f
{value: 0x0000, lo: 0x04},
{value: 0x0008, lo: 0x80, hi: 0xaa},
{value: 0x0040, lo: 0xab, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xbc},
{value: 0x0040, lo: 0xbd, hi: 0xbf},
// Block 0xf6, offset 0x744
{value: 0x0000, lo: 0x09},
{value: 0x0008, lo: 0x80, hi: 0x88},
{value: 0x0040, lo: 0x89, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0x99},
{value: 0x0040, lo: 0x9a, hi: 0x9b},
{value: 0x0018, lo: 0x9c, hi: 0x9c},
{value: 0x3308, lo: 0x9d, hi: 0x9e},
{value: 0x0018, lo: 0x9f, hi: 0x9f},
{value: 0x03c0, lo: 0xa0, hi: 0xa3},
{value: 0x0040, lo: 0xa4, hi: 0xbf},
// Block 0xf7, offset 0x74e
{value: 0x0000, lo: 0x03},
{value: 0x3308, lo: 0x80, hi: 0xad},
{value: 0x0040, lo: 0xae, hi: 0xaf},
{value: 0x3308, lo: 0xb0, hi: 0xbf},
// Block 0xf8, offset 0x752
{value: 0x0000, lo: 0x03},
{value: 0x3308, lo: 0x80, hi: 0x86},
{value: 0x0040, lo: 0x87, hi: 0x8f},
{value: 0x0018, lo: 0x90, hi: 0xbf},
// Block 0xf9, offset 0x756
{value: 0x0000, lo: 0x02},
{value: 0x0018, lo: 0x80, hi: 0x83},
{value: 0x0040, lo: 0x84, hi: 0xbf},
// Block 0xfa, offset 0x759
{value: 0x0000, lo: 0x02},
{value: 0x0018, lo: 0x80, hi: 0xb5},
{value: 0x0040, lo: 0xb6, hi: 0xbf},
// Block 0xfb, offset 0x75c
{value: 0x0000, lo: 0x03},
{value: 0x0018, lo: 0x80, hi: 0xa6},
{value: 0x0040, lo: 0xa7, hi: 0xa8},
{value: 0x0018, lo: 0xa9, hi: 0xbf},
// Block 0xfc, offset 0x760
{value: 0x0000, lo: 0x0e},
{value: 0x0018, lo: 0x80, hi: 0x9d},
{value: 0x2379, lo: 0x9e, hi: 0x9e},
{value: 0x2381, lo: 0x9f, hi: 0x9f},
{value: 0x2389, lo: 0xa0, hi: 0xa0},
{value: 0x2391, lo: 0xa1, hi: 0xa1},
{value: 0x2399, lo: 0xa2, hi: 0xa2},
{value: 0x23a1, lo: 0xa3, hi: 0xa3},
{value: 0x23a9, lo: 0xa4, hi: 0xa4},
{value: 0x3018, lo: 0xa5, hi: 0xa6},
{value: 0x3318, lo: 0xa7, hi: 0xa9},
{value: 0x0018, lo: 0xaa, hi: 0xac},
{value: 0x3018, lo: 0xad, hi: 0xb2},
{value: 0x0340, lo: 0xb3, hi: 0xba},
{value: 0x3318, lo: 0xbb, hi: 0xbf},
// Block 0xfd, offset 0x76f
{value: 0x0000, lo: 0x0b},
{value: 0x3318, lo: 0x80, hi: 0x82},
{value: 0x0018, lo: 0x83, hi: 0x84},
{value: 0x3318, lo: 0x85, hi: 0x8b},
{value: 0x0018, lo: 0x8c, hi: 0xa9},
{value: 0x3318, lo: 0xaa, hi: 0xad},
{value: 0x0018, lo: 0xae, hi: 0xba},
{value: 0x23b1, lo: 0xbb, hi: 0xbb},
{value: 0x23b9, lo: 0xbc, hi: 0xbc},
{value: 0x23c1, lo: 0xbd, hi: 0xbd},
{value: 0x23c9, lo: 0xbe, hi: 0xbe},
{value: 0x23d1, lo: 0xbf, hi: 0xbf},
// Block 0xfe, offset 0x77b
{value: 0x0000, lo: 0x03},
{value: 0x23d9, lo: 0x80, hi: 0x80},
{value: 0x0018, lo: 0x81, hi: 0xaa},
{value: 0x0040, lo: 0xab, hi: 0xbf},
// Block 0xff, offset 0x77f
{value: 0x0000, lo: 0x04},
{value: 0x0018, lo: 0x80, hi: 0x81},
{value: 0x3318, lo: 0x82, hi: 0x84},
{value: 0x0018, lo: 0x85, hi: 0x85},
{value: 0x0040, lo: 0x86, hi: 0xbf},
// Block 0x100, offset 0x784
{value: 0x0000, lo: 0x04},
{value: 0x0018, lo: 0x80, hi: 0x93},
{value: 0x0040, lo: 0x94, hi: 0x9f},
{value: 0x0018, lo: 0xa0, hi: 0xb3},
{value: 0x0040, lo: 0xb4, hi: 0xbf},
// Block 0x101, offset 0x789
{value: 0x0000, lo: 0x04},
{value: 0x0018, lo: 0x80, hi: 0x96},
{value: 0x0040, lo: 0x97, hi: 0x9f},
{value: 0x0018, lo: 0xa0, hi: 0xb8},
{value: 0x0040, lo: 0xb9, hi: 0xbf},
// Block 0x102, offset 0x78e
{value: 0x0000, lo: 0x03},
{value: 0x3308, lo: 0x80, hi: 0xb6},
{value: 0x0018, lo: 0xb7, hi: 0xba},
{value: 0x3308, lo: 0xbb, hi: 0xbf},
// Block 0x103, offset 0x792
{value: 0x0000, lo: 0x04},
{value: 0x3308, lo: 0x80, hi: 0xac},
{value: 0x0018, lo: 0xad, hi: 0xb4},
{value: 0x3308, lo: 0xb5, hi: 0xb5},
{value: 0x0018, lo: 0xb6, hi: 0xbf},
// Block 0x104, offset 0x797
{value: 0x0000, lo: 0x08},
{value: 0x0018, lo: 0x80, hi: 0x83},
{value: 0x3308, lo: 0x84, hi: 0x84},
{value: 0x0018, lo: 0x85, hi: 0x8b},
{value: 0x0040, lo: 0x8c, hi: 0x9a},
{value: 0x3308, lo: 0x9b, hi: 0x9f},
{value: 0x0040, lo: 0xa0, hi: 0xa0},
{value: 0x3308, lo: 0xa1, hi: 0xaf},
{value: 0x0040, lo: 0xb0, hi: 0xbf},
// Block 0x105, offset 0x7a0
{value: 0x0000, lo: 0x04},
{value: 0x0008, lo: 0x80, hi: 0x9e},
{value: 0x0040, lo: 0x9f, hi: 0xa4},
{value: 0x0008, lo: 0xa5, hi: 0xaa},
{value: 0x0040, lo: 0xab, hi: 0xbf},
// Block 0x106, offset 0x7a5
{value: 0x0000, lo: 0x03},
{value: 0x0040, lo: 0x80, hi: 0x8e},
{value: 0x3308, lo: 0x8f, hi: 0x8f},
{value: 0x0040, lo: 0x90, hi: 0xbf},
// Block 0x107, offset 0x7a9
{value: 0x0000, lo: 0x05},
{value: 0x0008, lo: 0x80, hi: 0xac},
{value: 0x0040, lo: 0xad, hi: 0xaf},
{value: 0x3308, lo: 0xb0, hi: 0xb6},
{value: 0x0008, lo: 0xb7, hi: 0xbd},
{value: 0x0040, lo: 0xbe, hi: 0xbf},
// Block 0x108, offset 0x7af
{value: 0x0000, lo: 0x05},
{value: 0x0008, lo: 0x80, hi: 0x89},
{value: 0x0040, lo: 0x8a, hi: 0x8d},
{value: 0x0008, lo: 0x8e, hi: 0x8e},
{value: 0x0018, lo: 0x8f, hi: 0x8f},
{value: 0x0040, lo: 0x90, hi: 0xbf},
// Block 0x109, offset 0x7b5
{value: 0x0000, lo: 0x04},
{value: 0x0040, lo: 0x80, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0xad},
{value: 0x3308, lo: 0xae, hi: 0xae},
{value: 0x0040, lo: 0xaf, hi: 0xbf},
// Block 0x10a, offset 0x7ba
{value: 0x0000, lo: 0x05},
{value: 0x0008, lo: 0x80, hi: 0xab},
{value: 0x3308, lo: 0xac, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xb9},
{value: 0x0040, lo: 0xba, hi: 0xbe},
{value: 0x0018, lo: 0xbf, hi: 0xbf},
// Block 0x10b, offset 0x7c0
{value: 0x0000, lo: 0x05},
{value: 0x0040, lo: 0x80, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0xab},
{value: 0x3308, lo: 0xac, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xb9},
{value: 0x0040, lo: 0xba, hi: 0xbf},
// Block 0x10c, offset 0x7c6
{value: 0x0000, lo: 0x09},
{value: 0x0040, lo: 0x80, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xa6},
{value: 0x0040, lo: 0xa7, hi: 0xa7},
{value: 0x0008, lo: 0xa8, hi: 0xab},
{value: 0x0040, lo: 0xac, hi: 0xac},
{value: 0x0008, lo: 0xad, hi: 0xae},
{value: 0x0040, lo: 0xaf, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xbe},
{value: 0x0040, lo: 0xbf, hi: 0xbf},
// Block 0x10d, offset 0x7d0
{value: 0x0000, lo: 0x05},
{value: 0x0808, lo: 0x80, hi: 0x84},
{value: 0x0040, lo: 0x85, hi: 0x86},
{value: 0x0818, lo: 0x87, hi: 0x8f},
{value: 0x3308, lo: 0x90, hi: 0x96},
{value: 0x0040, lo: 0x97, hi: 0xbf},
// Block 0x10e, offset 0x7d6
{value: 0x0000, lo: 0x08},
{value: 0x0a08, lo: 0x80, hi: 0x83},
{value: 0x3308, lo: 0x84, hi: 0x8a},
{value: 0x0b08, lo: 0x8b, hi: 0x8b},
{value: 0x0040, lo: 0x8c, hi: 0x8f},
{value: 0x0808, lo: 0x90, hi: 0x99},
{value: 0x0040, lo: 0x9a, hi: 0x9d},
{value: 0x0818, lo: 0x9e, hi: 0x9f},
{value: 0x0040, lo: 0xa0, hi: 0xbf},
// Block 0x10f, offset 0x7df
{value: 0x0000, lo: 0x02},
{value: 0x0040, lo: 0x80, hi: 0xb0},
{value: 0x0818, lo: 0xb1, hi: 0xbf},
// Block 0x110, offset 0x7e2
{value: 0x0000, lo: 0x02},
{value: 0x0818, lo: 0x80, hi: 0xb4},
{value: 0x0040, lo: 0xb5, hi: 0xbf},
// Block 0x111, offset 0x7e5
{value: 0x0000, lo: 0x03},
{value: 0x0040, lo: 0x80, hi: 0x80},
{value: 0x0818, lo: 0x81, hi: 0xbd},
{value: 0x0040, lo: 0xbe, hi: 0xbf},
// Block 0x112, offset 0x7e9
{value: 0x0000, lo: 0x03},
{value: 0x0040, lo: 0x80, hi: 0xaf},
{value: 0x0018, lo: 0xb0, hi: 0xb1},
{value: 0x0040, lo: 0xb2, hi: 0xbf},
// Block 0x113, offset 0x7ed
{value: 0x0000, lo: 0x03},
{value: 0x0018, lo: 0x80, hi: 0xab},
{value: 0x0040, lo: 0xac, hi: 0xaf},
{value: 0x0018, lo: 0xb0, hi: 0xbf},
// Block 0x114, offset 0x7f1
{value: 0x0000, lo: 0x05},
{value: 0x0018, lo: 0x80, hi: 0x93},
{value: 0x0040, lo: 0x94, hi: 0x9f},
{value: 0x0018, lo: 0xa0, hi: 0xae},
{value: 0x0040, lo: 0xaf, hi: 0xb0},
{value: 0x0018, lo: 0xb1, hi: 0xbf},
// Block 0x115, offset 0x7f7
{value: 0x0000, lo: 0x05},
{value: 0x0040, lo: 0x80, hi: 0x80},
{value: 0x0018, lo: 0x81, hi: 0x8f},
{value: 0x0040, lo: 0x90, hi: 0x90},
{value: 0x0018, lo: 0x91, hi: 0xb5},
{value: 0x0040, lo: 0xb6, hi: 0xbf},
// Block 0x116, offset 0x7fd
{value: 0x0000, lo: 0x04},
{value: 0x0018, lo: 0x80, hi: 0x8f},
{value: 0x2709, lo: 0x90, hi: 0x90},
{value: 0x0018, lo: 0x91, hi: 0xad},
{value: 0x0040, lo: 0xae, hi: 0xbf},
// Block 0x117, offset 0x802
{value: 0x0000, lo: 0x02},
{value: 0x0040, lo: 0x80, hi: 0xa5},
{value: 0x0018, lo: 0xa6, hi: 0xbf},
// Block 0x118, offset 0x805
{value: 0x0000, lo: 0x0f},
{value: 0x2889, lo: 0x80, hi: 0x80},
{value: 0x2891, lo: 0x81, hi: 0x81},
{value: 0x2899, lo: 0x82, hi: 0x82},
{value: 0x28a1, lo: 0x83, hi: 0x83},
{value: 0x28a9, lo: 0x84, hi: 0x84},
{value: 0x28b1, lo: 0x85, hi: 0x85},
{value: 0x28b9, lo: 0x86, hi: 0x86},
{value: 0x28c1, lo: 0x87, hi: 0x87},
{value: 0x28c9, lo: 0x88, hi: 0x88},
{value: 0x0040, lo: 0x89, hi: 0x8f},
{value: 0x28d1, lo: 0x90, hi: 0x90},
{value: 0x28d9, lo: 0x91, hi: 0x91},
{value: 0x0040, lo: 0x92, hi: 0x9f},
{value: 0x0018, lo: 0xa0, hi: 0xa5},
{value: 0x0040, lo: 0xa6, hi: 0xbf},
// Block 0x119, offset 0x815
{value: 0x0000, lo: 0x06},
{value: 0x0018, lo: 0x80, hi: 0x97},
{value: 0x0040, lo: 0x98, hi: 0x9b},
{value: 0x0018, lo: 0x9c, hi: 0xac},
{value: 0x0040, lo: 0xad, hi: 0xaf},
{value: 0x0018, lo: 0xb0, hi: 0xbc},
{value: 0x0040, lo: 0xbd, hi: 0xbf},
// Block 0x11a, offset 0x81c
{value: 0x0000, lo: 0x03},
{value: 0x0018, lo: 0x80, hi: 0xb6},
{value: 0x0040, lo: 0xb7, hi: 0xba},
{value: 0x0018, lo: 0xbb, hi: 0xbf},
// Block 0x11b, offset 0x820
{value: 0x0000, lo: 0x06},
{value: 0x0018, lo: 0x80, hi: 0x99},
{value: 0x0040, lo: 0x9a, hi: 0x9f},
{value: 0x0018, lo: 0xa0, hi: 0xab},
{value: 0x0040, lo: 0xac, hi: 0xaf},
{value: 0x0018, lo: 0xb0, hi: 0xb0},
{value: 0x0040, lo: 0xb1, hi: 0xbf},
// Block 0x11c, offset 0x827
{value: 0x0000, lo: 0x03},
{value: 0x0018, lo: 0x80, hi: 0x8b},
{value: 0x0040, lo: 0x8c, hi: 0x8f},
{value: 0x0018, lo: 0x90, hi: 0xbf},
// Block 0x11d, offset 0x82b
{value: 0x0000, lo: 0x05},
{value: 0x0018, lo: 0x80, hi: 0x87},
{value: 0x0040, lo: 0x88, hi: 0x8f},
{value: 0x0018, lo: 0x90, hi: 0x99},
{value: 0x0040, lo: 0x9a, hi: 0x9f},
{value: 0x0018, lo: 0xa0, hi: 0xbf},
// Block 0x11e, offset 0x831
{value: 0x0000, lo: 0x06},
{value: 0x0018, lo: 0x80, hi: 0x87},
{value: 0x0040, lo: 0x88, hi: 0x8f},
{value: 0x0018, lo: 0x90, hi: 0xad},
{value: 0x0040, lo: 0xae, hi: 0xaf},
{value: 0x0018, lo: 0xb0, hi: 0xb1},
{value: 0x0040, lo: 0xb2, hi: 0xbf},
// Block 0x11f, offset 0x838
{value: 0x0000, lo: 0x06},
{value: 0x0018, lo: 0x80, hi: 0x93},
{value: 0x0040, lo: 0x94, hi: 0x9f},
{value: 0x0018, lo: 0xa0, hi: 0xad},
{value: 0x0040, lo: 0xae, hi: 0xaf},
{value: 0x0018, lo: 0xb0, hi: 0xbc},
{value: 0x0040, lo: 0xbd, hi: 0xbf},
// Block 0x120, offset 0x83f
{value: 0x0000, lo: 0x05},
{value: 0x0018, lo: 0x80, hi: 0x88},
{value: 0x0040, lo: 0x89, hi: 0x8f},
{value: 0x0018, lo: 0x90, hi: 0xbd},
{value: 0x0040, lo: 0xbe, hi: 0xbe},
{value: 0x0018, lo: 0xbf, hi: 0xbf},
// Block 0x121, offset 0x845
{value: 0x0000, lo: 0x08},
{value: 0x0018, lo: 0x80, hi: 0x85},
{value: 0x0040, lo: 0x86, hi: 0x8d},
{value: 0x0018, lo: 0x8e, hi: 0x9b},
{value: 0x0040, lo: 0x9c, hi: 0x9f},
{value: 0x0018, lo: 0xa0, hi: 0xa8},
{value: 0x0040, lo: 0xa9, hi: 0xaf},
{value: 0x0018, lo: 0xb0, hi: 0xb8},
{value: 0x0040, lo: 0xb9, hi: 0xbf},
// Block 0x122, offset 0x84e
{value: 0x0000, lo: 0x03},
{value: 0x0018, lo: 0x80, hi: 0x92},
{value: 0x0040, lo: 0x93, hi: 0x93},
{value: 0x0018, lo: 0x94, hi: 0xbf},
// Block 0x123, offset 0x852
{value: 0x0000, lo: 0x0d},
{value: 0x0018, lo: 0x80, hi: 0x8a},
{value: 0x0040, lo: 0x8b, hi: 0xaf},
{value: 0x06e1, lo: 0xb0, hi: 0xb0},
{value: 0x0049, lo: 0xb1, hi: 0xb1},
{value: 0x0029, lo: 0xb2, hi: 0xb2},
{value: 0x0031, lo: 0xb3, hi: 0xb3},
{value: 0x06e9, lo: 0xb4, hi: 0xb4},
{value: 0x06f1, lo: 0xb5, hi: 0xb5},
{value: 0x06f9, lo: 0xb6, hi: 0xb6},
{value: 0x0701, lo: 0xb7, hi: 0xb7},
{value: 0x0709, lo: 0xb8, hi: 0xb8},
{value: 0x0711, lo: 0xb9, hi: 0xb9},
{value: 0x0040, lo: 0xba, hi: 0xbf},
// Block 0x124, offset 0x860
{value: 0x0000, lo: 0x02},
{value: 0x0008, lo: 0x80, hi: 0x9f},
{value: 0x0040, lo: 0xa0, hi: 0xbf},
// Block 0x125, offset 0x863
{value: 0x0000, lo: 0x02},
{value: 0x0008, lo: 0x80, hi: 0xb9},
{value: 0x0040, lo: 0xba, hi: 0xbf},
// Block 0x126, offset 0x866
{value: 0x0000, lo: 0x03},
{value: 0x0008, lo: 0x80, hi: 0x9d},
{value: 0x0040, lo: 0x9e, hi: 0x9f},
{value: 0x0008, lo: 0xa0, hi: 0xbf},
// Block 0x127, offset 0x86a
{value: 0x0000, lo: 0x03},
{value: 0x0008, lo: 0x80, hi: 0xa1},
{value: 0x0040, lo: 0xa2, hi: 0xaf},
{value: 0x0008, lo: 0xb0, hi: 0xbf},
// Block 0x128, offset 0x86e
{value: 0x0000, lo: 0x02},
{value: 0x0008, lo: 0x80, hi: 0xa0},
{value: 0x0040, lo: 0xa1, hi: 0xbf},
// Block 0x129, offset 0x871
{value: 0x0000, lo: 0x03},
{value: 0x0008, lo: 0x80, hi: 0x8a},
{value: 0x0040, lo: 0x8b, hi: 0x8f},
{value: 0x0008, lo: 0x90, hi: 0xbf},
// Block 0x12a, offset 0x875
{value: 0x0000, lo: 0x02},
{value: 0x0008, lo: 0x80, hi: 0xaf},
{value: 0x0040, lo: 0xb0, hi: 0xbf},
// Block 0x12b, offset 0x878
{value: 0x0000, lo: 0x04},
{value: 0x0040, lo: 0x80, hi: 0x80},
{value: 0x0340, lo: 0x81, hi: 0x81},
{value: 0x0040, lo: 0x82, hi: 0x9f},
{value: 0x0340, lo: 0xa0, hi: 0xbf},
// Block 0x12c, offset 0x87d
{value: 0x0000, lo: 0x01},
{value: 0x0340, lo: 0x80, hi: 0xbf},
// Block 0x12d, offset 0x87f
{value: 0x0000, lo: 0x01},
{value: 0x33c0, lo: 0x80, hi: 0xbf},
// Block 0x12e, offset 0x881
{value: 0x0000, lo: 0x02},
{value: 0x33c0, lo: 0x80, hi: 0xaf},
{value: 0x0040, lo: 0xb0, hi: 0xbf},
}
// Total table size 46723 bytes (45KiB); checksum: 4CF3143A
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
// 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.
package idna
// Sparse block handling code.
type valueRange struct {
value uint16 // header: value:stride
lo, hi byte // header: lo:n
}
type sparseBlocks struct {
values []valueRange
offset []uint16
}
var idnaSparse = sparseBlocks{
values: idnaSparseValues[:],
offset: idnaSparseOffset[:],
}
// Don't use newIdnaTrie to avoid unconditional linking in of the table.
var trie = &idnaTrie{}
// lookup determines the type of block n and looks up the value for b.
// For n < t.cutoff, the block is a simple lookup table. Otherwise, the block
// is a list of ranges with an accompanying value. Given a matching range r,
// the value for b is by r.value + (b - r.lo) * stride.
func (t *sparseBlocks) lookup(n uint32, b byte) uint16 {
offset := t.offset[n]
header := t.values[offset]
lo := offset + 1
hi := lo + uint16(header.lo)
for lo < hi {
m := lo + (hi-lo)/2
r := t.values[m]
if r.lo <= b && b <= r.hi {
return r.value + uint16(b-r.lo)*header.value
}
if b < r.lo {
hi = m
} else {
lo = m + 1
}
}
return 0
}
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
// 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.
//go:build go1.16
package idna
// appendMapping appends the mapping for the respective rune. isMapped must be
// true. A mapping is a categorization of a rune as defined in UTS #46.
func (c info) appendMapping(b []byte, s string) []byte {
index := int(c >> indexShift)
if c&xorBit == 0 {
p := index
return append(b, mappings[mappingIndex[p]:mappingIndex[p+1]]...)
}
b = append(b, s...)
if c&inlineXOR == inlineXOR {
// TODO: support and handle two-byte inline masks
b[len(b)-1] ^= byte(index)
} else {
for p := len(b) - int(xorData[index]); p < len(b); p++ {
index++
b[p] ^= xorData[index]
}
}
return b
}
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
package idna
// This file contains definitions for interpreting the trie value of the idna
// trie generated by "go run gen*.go". It is shared by both the generator
// program and the resultant package. Sharing is achieved by the generator
// copying gen_trieval.go to trieval.go and changing what's above this comment.
// info holds information from the IDNA mapping table for a single rune. It is
// the value returned by a trie lookup. In most cases, all information fits in
// a 16-bit value. For mappings, this value may contain an index into a slice
// with the mapped string. Such mappings can consist of the actual mapped value
// or an XOR pattern to be applied to the bytes of the UTF8 encoding of the
// input rune. This technique is used by the cases packages and reduces the
// table size significantly.
//
// The per-rune values have the following format:
//
// if mapped {
// if inlinedXOR {
// 15..13 inline XOR marker
// 12..11 unused
// 10..3 inline XOR mask
// } else {
// 15..3 index into xor or mapping table
// }
// } else {
// 15..14 unused
// 13 mayNeedNorm
// 12..11 attributes
// 10..8 joining type
// 7..3 category type
// }
// 2 use xor pattern
// 1..0 mapped category
//
// See the definitions below for a more detailed description of the various
// bits.
type info uint16
const (
catSmallMask = 0x3
catBigMask = 0xF8
indexShift = 3
xorBit = 0x4 // interpret the index as an xor pattern
inlineXOR = 0xE000 // These bits are set if the XOR pattern is inlined.
joinShift = 8
joinMask = 0x07
// Attributes
attributesMask = 0x1800
viramaModifier = 0x1800
modifier = 0x1000
rtl = 0x0800
mayNeedNorm = 0x2000
)
// A category corresponds to a category defined in the IDNA mapping table.
type category uint16
const (
unknown category = 0 // not currently defined in unicode.
mapped category = 1
disallowedSTD3Mapped category = 2
deviation category = 3
)
const (
valid category = 0x08
validNV8 category = 0x18
validXV8 category = 0x28
disallowed category = 0x40
disallowedSTD3Valid category = 0x80
ignored category = 0xC0
)
// join types and additional rune information
const (
joiningL = (iota + 1)
joiningD
joiningT
joiningR
//the following types are derived during processing
joinZWJ
joinZWNJ
joinVirama
numJoinTypes
)
func (c info) isMapped() bool {
return c&0x3 != 0
}
func (c info) category() category {
small := c & catSmallMask
if small != 0 {
return category(small)
}
return category(c & catBigMask)
}
func (c info) joinType() info {
if c.isMapped() {
return 0
}
return (c >> joinShift) & joinMask
}
func (c info) isModifier() bool {
return c&(modifier|catSmallMask) == modifier
}
func (c info) isViramaModifier() bool {
return c&(attributesMask|catSmallMask) == viramaModifier
}
// Copyright 2025 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 httpcommon
import "strings"
// The HTTP protocols are defined in terms of ASCII, not Unicode. This file
// contains helper functions which may use Unicode-aware functions which would
// otherwise be unsafe and could introduce vulnerabilities if used improperly.
// asciiEqualFold is strings.EqualFold, ASCII only. It reports whether s and t
// are equal, ASCII-case-insensitively.
func asciiEqualFold(s, t string) bool {
if len(s) != len(t) {
return false
}
for i := 0; i < len(s); i++ {
if lower(s[i]) != lower(t[i]) {
return false
}
}
return true
}
// lower returns the ASCII lowercase version of b.
func lower(b byte) byte {
if 'A' <= b && b <= 'Z' {
return b + ('a' - 'A')
}
return b
}
// isASCIIPrint returns whether s is ASCII and printable according to
// https://tools.ietf.org/html/rfc20#section-4.2.
func isASCIIPrint(s string) bool {
for i := 0; i < len(s); i++ {
if s[i] < ' ' || s[i] > '~' {
return false
}
}
return true
}
// asciiToLower returns the lowercase version of s if s is ASCII and printable,
// and whether or not it was.
func asciiToLower(s string) (lower string, ok bool) {
if !isASCIIPrint(s) {
return "", false
}
return strings.ToLower(s), true
}
// Copyright 2025 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 httpcommon
import (
"net/textproto"
"sync"
)
var (
commonBuildOnce sync.Once
commonLowerHeader map[string]string // Go-Canonical-Case -> lower-case
commonCanonHeader map[string]string // lower-case -> Go-Canonical-Case
)
func buildCommonHeaderMapsOnce() {
commonBuildOnce.Do(buildCommonHeaderMaps)
}
func buildCommonHeaderMaps() {
common := []string{
"accept",
"accept-charset",
"accept-encoding",
"accept-language",
"accept-ranges",
"age",
"access-control-allow-credentials",
"access-control-allow-headers",
"access-control-allow-methods",
"access-control-allow-origin",
"access-control-expose-headers",
"access-control-max-age",
"access-control-request-headers",
"access-control-request-method",
"allow",
"authorization",
"cache-control",
"content-disposition",
"content-encoding",
"content-language",
"content-length",
"content-location",
"content-range",
"content-type",
"cookie",
"date",
"etag",
"expect",
"expires",
"from",
"host",
"if-match",
"if-modified-since",
"if-none-match",
"if-unmodified-since",
"last-modified",
"link",
"location",
"max-forwards",
"origin",
"proxy-authenticate",
"proxy-authorization",
"range",
"referer",
"refresh",
"retry-after",
"server",
"set-cookie",
"strict-transport-security",
"trailer",
"transfer-encoding",
"user-agent",
"vary",
"via",
"www-authenticate",
"x-forwarded-for",
"x-forwarded-proto",
}
commonLowerHeader = make(map[string]string, len(common))
commonCanonHeader = make(map[string]string, len(common))
for _, v := range common {
chk := textproto.CanonicalMIMEHeaderKey(v)
commonLowerHeader[chk] = v
commonCanonHeader[v] = chk
}
}
// LowerHeader returns the lowercase form of a header name,
// used on the wire for HTTP/2 and HTTP/3 requests.
func LowerHeader(v string) (lower string, ascii bool) {
buildCommonHeaderMapsOnce()
if s, ok := commonLowerHeader[v]; ok {
return s, true
}
return asciiToLower(v)
}
// CanonicalHeader canonicalizes a header name. (For example, "host" becomes "Host".)
func CanonicalHeader(v string) string {
buildCommonHeaderMapsOnce()
if s, ok := commonCanonHeader[v]; ok {
return s
}
return textproto.CanonicalMIMEHeaderKey(v)
}
// CachedCanonicalHeader returns the canonical form of a well-known header name.
func CachedCanonicalHeader(v string) (string, bool) {
buildCommonHeaderMapsOnce()
s, ok := commonCanonHeader[v]
return s, ok
}
// Copyright 2025 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 httpcommon
import (
"context"
"errors"
"fmt"
"net/http/httptrace"
"net/textproto"
"net/url"
"sort"
"strconv"
"strings"
"golang.org/x/net/http/httpguts"
"golang.org/x/net/http2/hpack"
)
var (
ErrRequestHeaderListSize = errors.New("request header list larger than peer's advertised limit")
)
// Request is a subset of http.Request.
// It'd be simpler to pass an *http.Request, of course, but we can't depend on net/http
// without creating a dependency cycle.
type Request struct {
URL *url.URL
Method string
Host string
Header map[string][]string
Trailer map[string][]string
ActualContentLength int64 // 0 means 0, -1 means unknown
}
// EncodeHeadersParam is parameters to EncodeHeaders.
type EncodeHeadersParam struct {
Request Request
// AddGzipHeader indicates that an "accept-encoding: gzip" header should be
// added to the request.
AddGzipHeader bool
// PeerMaxHeaderListSize, when non-zero, is the peer's MAX_HEADER_LIST_SIZE setting.
PeerMaxHeaderListSize uint64
// DefaultUserAgent is the User-Agent header to send when the request
// neither contains a User-Agent nor disables it.
DefaultUserAgent string
}
// EncodeHeadersResult is the result of EncodeHeaders.
type EncodeHeadersResult struct {
HasBody bool
HasTrailers bool
}
// EncodeHeaders constructs request headers common to HTTP/2 and HTTP/3.
// It validates a request and calls headerf with each pseudo-header and header
// for the request.
// The headerf function is called with the validated, canonicalized header name.
func EncodeHeaders(ctx context.Context, param EncodeHeadersParam, headerf func(name, value string)) (res EncodeHeadersResult, _ error) {
req := param.Request
// Check for invalid connection-level headers.
if err := checkConnHeaders(req.Header); err != nil {
return res, err
}
if req.URL == nil {
return res, errors.New("Request.URL is nil")
}
host := req.Host
if host == "" {
host = req.URL.Host
}
host, err := httpguts.PunycodeHostPort(host)
if err != nil {
return res, err
}
if !httpguts.ValidHostHeader(host) {
return res, errors.New("invalid Host header")
}
// isNormalConnect is true if this is a non-extended CONNECT request.
isNormalConnect := false
var protocol string
if vv := req.Header[":protocol"]; len(vv) > 0 {
protocol = vv[0]
}
if req.Method == "CONNECT" && protocol == "" {
isNormalConnect = true
} else if protocol != "" && req.Method != "CONNECT" {
return res, errors.New("invalid :protocol header in non-CONNECT request")
}
// Validate the path, except for non-extended CONNECT requests which have no path.
var path string
if !isNormalConnect {
path = req.URL.RequestURI()
if !validPseudoPath(path) {
orig := path
path = strings.TrimPrefix(path, req.URL.Scheme+"://"+host)
if !validPseudoPath(path) {
if req.URL.Opaque != "" {
return res, fmt.Errorf("invalid request :path %q from URL.Opaque = %q", orig, req.URL.Opaque)
} else {
return res, fmt.Errorf("invalid request :path %q", orig)
}
}
}
}
// Check for any invalid headers+trailers and return an error before we
// potentially pollute our hpack state. (We want to be able to
// continue to reuse the hpack encoder for future requests)
if err := validateHeaders(req.Header); err != "" {
return res, fmt.Errorf("invalid HTTP header %s", err)
}
if err := validateHeaders(req.Trailer); err != "" {
return res, fmt.Errorf("invalid HTTP trailer %s", err)
}
trailers, err := commaSeparatedTrailers(req.Trailer)
if err != nil {
return res, err
}
enumerateHeaders := func(f func(name, value string)) {
// 8.1.2.3 Request Pseudo-Header Fields
// The :path pseudo-header field includes the path and query parts of the
// target URI (the path-absolute production and optionally a '?' character
// followed by the query production, see Sections 3.3 and 3.4 of
// [RFC3986]).
f(":authority", host)
m := req.Method
if m == "" {
m = "GET"
}
f(":method", m)
if !isNormalConnect {
f(":path", path)
f(":scheme", req.URL.Scheme)
}
if protocol != "" {
f(":protocol", protocol)
}
if trailers != "" {
f("trailer", trailers)
}
var didUA bool
for k, vv := range req.Header {
if asciiEqualFold(k, "host") || asciiEqualFold(k, "content-length") {
// Host is :authority, already sent.
// Content-Length is automatic, set below.
continue
} else if asciiEqualFold(k, "connection") ||
asciiEqualFold(k, "proxy-connection") ||
asciiEqualFold(k, "transfer-encoding") ||
asciiEqualFold(k, "upgrade") ||
asciiEqualFold(k, "keep-alive") {
// Per 8.1.2.2 Connection-Specific Header
// Fields, don't send connection-specific
// fields. We have already checked if any
// are error-worthy so just ignore the rest.
continue
} else if asciiEqualFold(k, "user-agent") {
// Match Go's http1 behavior: at most one
// User-Agent. If set to nil or empty string,
// then omit it. Otherwise if not mentioned,
// include the default (below).
didUA = true
if len(vv) < 1 {
continue
}
vv = vv[:1]
if vv[0] == "" {
continue
}
} else if asciiEqualFold(k, "cookie") {
// Per 8.1.2.5 To allow for better compression efficiency, the
// Cookie header field MAY be split into separate header fields,
// each with one or more cookie-pairs.
for _, v := range vv {
for {
p := strings.IndexByte(v, ';')
if p < 0 {
break
}
f("cookie", v[:p])
p++
// strip space after semicolon if any.
for p+1 <= len(v) && v[p] == ' ' {
p++
}
v = v[p:]
}
if len(v) > 0 {
f("cookie", v)
}
}
continue
} else if k == ":protocol" {
// :protocol pseudo-header was already sent above.
continue
}
for _, v := range vv {
f(k, v)
}
}
if shouldSendReqContentLength(req.Method, req.ActualContentLength) {
f("content-length", strconv.FormatInt(req.ActualContentLength, 10))
}
if param.AddGzipHeader {
f("accept-encoding", "gzip")
}
if !didUA {
f("user-agent", param.DefaultUserAgent)
}
}
// Do a first pass over the headers counting bytes to ensure
// we don't exceed cc.peerMaxHeaderListSize. This is done as a
// separate pass before encoding the headers to prevent
// modifying the hpack state.
if param.PeerMaxHeaderListSize > 0 {
hlSize := uint64(0)
enumerateHeaders(func(name, value string) {
hf := hpack.HeaderField{Name: name, Value: value}
hlSize += uint64(hf.Size())
})
if hlSize > param.PeerMaxHeaderListSize {
return res, ErrRequestHeaderListSize
}
}
trace := httptrace.ContextClientTrace(ctx)
// Header list size is ok. Write the headers.
enumerateHeaders(func(name, value string) {
name, ascii := LowerHeader(name)
if !ascii {
// Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header
// field names have to be ASCII characters (just as in HTTP/1.x).
return
}
headerf(name, value)
if trace != nil && trace.WroteHeaderField != nil {
trace.WroteHeaderField(name, []string{value})
}
})
res.HasBody = req.ActualContentLength != 0
res.HasTrailers = trailers != ""
return res, nil
}
// IsRequestGzip reports whether we should add an Accept-Encoding: gzip header
// for a request.
func IsRequestGzip(method string, header map[string][]string, disableCompression bool) bool {
// TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere?
if !disableCompression &&
len(header["Accept-Encoding"]) == 0 &&
len(header["Range"]) == 0 &&
method != "HEAD" {
// Request gzip only, not deflate. Deflate is ambiguous and
// not as universally supported anyway.
// See: https://zlib.net/zlib_faq.html#faq39
//
// Note that we don't request this for HEAD requests,
// due to a bug in nginx:
// http://trac.nginx.org/nginx/ticket/358
// https://golang.org/issue/5522
//
// We don't request gzip if the request is for a range, since
// auto-decoding a portion of a gzipped document will just fail
// anyway. See https://golang.org/issue/8923
return true
}
return false
}
// checkConnHeaders checks whether req has any invalid connection-level headers.
//
// https://www.rfc-editor.org/rfc/rfc9114.html#section-4.2-3
// https://www.rfc-editor.org/rfc/rfc9113.html#section-8.2.2-1
//
// Certain headers are special-cased as okay but not transmitted later.
// For example, we allow "Transfer-Encoding: chunked", but drop the header when encoding.
func checkConnHeaders(h map[string][]string) error {
if vv := h["Upgrade"]; len(vv) > 0 && (vv[0] != "" && vv[0] != "chunked") {
return fmt.Errorf("invalid Upgrade request header: %q", vv)
}
if vv := h["Transfer-Encoding"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && vv[0] != "chunked") {
return fmt.Errorf("invalid Transfer-Encoding request header: %q", vv)
}
if vv := h["Connection"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && !asciiEqualFold(vv[0], "close") && !asciiEqualFold(vv[0], "keep-alive")) {
return fmt.Errorf("invalid Connection request header: %q", vv)
}
return nil
}
func commaSeparatedTrailers(trailer map[string][]string) (string, error) {
keys := make([]string, 0, len(trailer))
for k := range trailer {
k = CanonicalHeader(k)
switch k {
case "Transfer-Encoding", "Trailer", "Content-Length":
return "", fmt.Errorf("invalid Trailer key %q", k)
}
keys = append(keys, k)
}
if len(keys) > 0 {
sort.Strings(keys)
return strings.Join(keys, ","), nil
}
return "", nil
}
// validPseudoPath reports whether v is a valid :path pseudo-header
// value. It must be either:
//
// - a non-empty string starting with '/'
// - the string '*', for OPTIONS requests.
//
// For now this is only used a quick check for deciding when to clean
// up Opaque URLs before sending requests from the Transport.
// See golang.org/issue/16847
//
// We used to enforce that the path also didn't start with "//", but
// Google's GFE accepts such paths and Chrome sends them, so ignore
// that part of the spec. See golang.org/issue/19103.
func validPseudoPath(v string) bool {
return (len(v) > 0 && v[0] == '/') || v == "*"
}
func validateHeaders(hdrs map[string][]string) string {
for k, vv := range hdrs {
if !httpguts.ValidHeaderFieldName(k) && k != ":protocol" {
return fmt.Sprintf("name %q", k)
}
for _, v := range vv {
if !httpguts.ValidHeaderFieldValue(v) {
// Don't include the value in the error,
// because it may be sensitive.
return fmt.Sprintf("value for header %q", k)
}
}
}
return ""
}
// shouldSendReqContentLength reports whether we should send
// a "content-length" request header. This logic is basically a copy of the net/http
// transferWriter.shouldSendContentLength.
// The contentLength is the corrected contentLength (so 0 means actually 0, not unknown).
// -1 means unknown.
func shouldSendReqContentLength(method string, contentLength int64) bool {
if contentLength > 0 {
return true
}
if contentLength < 0 {
return false
}
// For zero bodies, whether we send a content-length depends on the method.
// It also kinda doesn't matter for http2 either way, with END_STREAM.
switch method {
case "POST", "PUT", "PATCH":
return true
default:
return false
}
}
// ServerRequestParam is parameters to NewServerRequest.
type ServerRequestParam struct {
Method string
Scheme, Authority, Path string
Protocol string
Header map[string][]string
}
// ServerRequestResult is the result of NewServerRequest.
type ServerRequestResult struct {
// Various http.Request fields.
URL *url.URL
RequestURI string
Trailer map[string][]string
NeedsContinue bool // client provided an "Expect: 100-continue" header
// If the request should be rejected, this is a short string suitable for passing
// to the http2 package's CountError function.
// It might be a bit odd to return errors this way rather than returning an error,
// but this ensures we don't forget to include a CountError reason.
InvalidReason string
}
func NewServerRequest(rp ServerRequestParam) ServerRequestResult {
needsContinue := httpguts.HeaderValuesContainsToken(rp.Header["Expect"], "100-continue")
if needsContinue {
delete(rp.Header, "Expect")
}
// Merge Cookie headers into one "; "-delimited value.
if cookies := rp.Header["Cookie"]; len(cookies) > 1 {
rp.Header["Cookie"] = []string{strings.Join(cookies, "; ")}
}
// Setup Trailers
var trailer map[string][]string
for _, v := range rp.Header["Trailer"] {
for _, key := range strings.Split(v, ",") {
key = textproto.CanonicalMIMEHeaderKey(textproto.TrimString(key))
switch key {
case "Transfer-Encoding", "Trailer", "Content-Length":
// Bogus. (copy of http1 rules)
// Ignore.
default:
if trailer == nil {
trailer = make(map[string][]string)
}
trailer[key] = nil
}
}
}
delete(rp.Header, "Trailer")
// "':authority' MUST NOT include the deprecated userinfo subcomponent
// for "http" or "https" schemed URIs."
// https://www.rfc-editor.org/rfc/rfc9113.html#section-8.3.1-2.3.8
if strings.IndexByte(rp.Authority, '@') != -1 && (rp.Scheme == "http" || rp.Scheme == "https") {
return ServerRequestResult{
InvalidReason: "userinfo_in_authority",
}
}
var url_ *url.URL
var requestURI string
if rp.Method == "CONNECT" && rp.Protocol == "" {
url_ = &url.URL{Host: rp.Authority}
requestURI = rp.Authority // mimic HTTP/1 server behavior
} else {
var err error
url_, err = url.ParseRequestURI(rp.Path)
if err != nil {
return ServerRequestResult{
InvalidReason: "bad_path",
}
}
requestURI = rp.Path
}
return ServerRequestResult{
URL: url_,
NeedsContinue: needsContinue,
RequestURI: requestURI,
Trailer: trailer,
}
}
// Copyright 2023 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.
//go:build go1.21
// Package quicwire encodes and decode QUIC/HTTP3 wire encoding types,
// particularly variable-length integers.
package quicwire
import "encoding/binary"
const (
MaxVarintSize = 8 // encoded size in bytes
MaxVarint = (1 << 62) - 1
)
// ConsumeVarint parses a variable-length integer, reporting its length.
// It returns a negative length upon an error.
//
// https://www.rfc-editor.org/rfc/rfc9000.html#section-16
func ConsumeVarint(b []byte) (v uint64, n int) {
if len(b) < 1 {
return 0, -1
}
b0 := b[0] & 0x3f
switch b[0] >> 6 {
case 0:
return uint64(b0), 1
case 1:
if len(b) < 2 {
return 0, -1
}
return uint64(b0)<<8 | uint64(b[1]), 2
case 2:
if len(b) < 4 {
return 0, -1
}
return uint64(b0)<<24 | uint64(b[1])<<16 | uint64(b[2])<<8 | uint64(b[3]), 4
case 3:
if len(b) < 8 {
return 0, -1
}
return uint64(b0)<<56 | uint64(b[1])<<48 | uint64(b[2])<<40 | uint64(b[3])<<32 | uint64(b[4])<<24 | uint64(b[5])<<16 | uint64(b[6])<<8 | uint64(b[7]), 8
}
return 0, -1
}
// ConsumeVarintInt64 parses a variable-length integer as an int64.
func ConsumeVarintInt64(b []byte) (v int64, n int) {
u, n := ConsumeVarint(b)
// QUIC varints are 62-bits large, so this conversion can never overflow.
return int64(u), n
}
// AppendVarint appends a variable-length integer to b.
//
// https://www.rfc-editor.org/rfc/rfc9000.html#section-16
func AppendVarint(b []byte, v uint64) []byte {
switch {
case v <= 63:
return append(b, byte(v))
case v <= 16383:
return append(b, (1<<6)|byte(v>>8), byte(v))
case v <= 1073741823:
return append(b, (2<<6)|byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
case v <= 4611686018427387903:
return append(b, (3<<6)|byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
default:
panic("varint too large")
}
}
// SizeVarint returns the size of the variable-length integer encoding of f.
func SizeVarint(v uint64) int {
switch {
case v <= 63:
return 1
case v <= 16383:
return 2
case v <= 1073741823:
return 4
case v <= 4611686018427387903:
return 8
default:
panic("varint too large")
}
}
// ConsumeUint32 parses a 32-bit fixed-length, big-endian integer, reporting its length.
// It returns a negative length upon an error.
func ConsumeUint32(b []byte) (uint32, int) {
if len(b) < 4 {
return 0, -1
}
return binary.BigEndian.Uint32(b), 4
}
// ConsumeUint64 parses a 64-bit fixed-length, big-endian integer, reporting its length.
// It returns a negative length upon an error.
func ConsumeUint64(b []byte) (uint64, int) {
if len(b) < 8 {
return 0, -1
}
return binary.BigEndian.Uint64(b), 8
}
// ConsumeUint8Bytes parses a sequence of bytes prefixed with an 8-bit length,
// reporting the total number of bytes consumed.
// It returns a negative length upon an error.
func ConsumeUint8Bytes(b []byte) ([]byte, int) {
if len(b) < 1 {
return nil, -1
}
size := int(b[0])
const n = 1
if size > len(b[n:]) {
return nil, -1
}
return b[n:][:size], size + n
}
// AppendUint8Bytes appends a sequence of bytes prefixed by an 8-bit length.
func AppendUint8Bytes(b, v []byte) []byte {
if len(v) > 0xff {
panic("uint8-prefixed bytes too large")
}
b = append(b, uint8(len(v)))
b = append(b, v...)
return b
}
// ConsumeVarintBytes parses a sequence of bytes preceded by a variable-length integer length,
// reporting the total number of bytes consumed.
// It returns a negative length upon an error.
func ConsumeVarintBytes(b []byte) ([]byte, int) {
size, n := ConsumeVarint(b)
if n < 0 {
return nil, -1
}
if size > uint64(len(b[n:])) {
return nil, -1
}
return b[n:][:size], int(size) + n
}
// AppendVarintBytes appends a sequence of bytes prefixed by a variable-length integer length.
func AppendVarintBytes(b, v []byte) []byte {
b = AppendVarint(b, uint64(len(v)))
b = append(b, v...)
return b
}
// 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.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package socket
func (h *cmsghdr) len() int { return int(h.Len) }
func (h *cmsghdr) lvl() int { return int(h.Level) }
func (h *cmsghdr) typ() int { return int(h.Type) }
// 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.
//go:build (arm64 || amd64 || loong64 || ppc64 || ppc64le || mips64 || mips64le || riscv64 || s390x) && linux
package socket
func (h *cmsghdr) set(l, lvl, typ int) {
h.Len = uint64(l)
h.Level = int32(lvl)
h.Type = int32(typ)
}
// Copyright 2020 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.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package socket
import "golang.org/x/sys/unix"
func controlHeaderLen() int {
return unix.CmsgLen(0)
}
func controlMessageLen(dataLen int) int {
return unix.CmsgLen(dataLen)
}
func controlMessageSpace(dataLen int) int {
return unix.CmsgSpace(dataLen)
}
// Copyright 2021 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.
//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
package socket
import (
"syscall"
)
// ioComplete checks the flags and result of a syscall, to be used as return
// value in a syscall.RawConn.Read or Write callback.
func ioComplete(flags int, operr error) bool {
if flags&syscall.MSG_DONTWAIT != 0 {
// Caller explicitly said don't wait, so always return immediately.
return true
}
if operr == syscall.EAGAIN || operr == syscall.EWOULDBLOCK {
// No data available, block for I/O and try again.
return false
}
return true
}
// 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.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package socket
import "syscall"
var (
errEAGAIN error = syscall.EAGAIN
errEINVAL error = syscall.EINVAL
errENOENT error = syscall.ENOENT
)
// errnoErr returns common boxed Errno values, to prevent allocations
// at runtime.
func errnoErr(errno syscall.Errno) error {
switch errno {
case 0:
return nil
case syscall.EAGAIN:
return errEAGAIN
case syscall.EINVAL:
return errEINVAL
case syscall.ENOENT:
return errENOENT
}
return errno
}
// 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.
//go:build (arm64 || amd64 || loong64 || ppc64 || ppc64le || mips64 || mips64le || riscv64 || s390x) && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || zos)
package socket
import "unsafe"
func (v *iovec) set(b []byte) {
l := len(b)
if l == 0 {
return
}
v.Base = (*byte)(unsafe.Pointer(&b[0]))
v.Len = uint64(l)
}
// 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.
//go:build aix || linux || netbsd
package socket
import (
"net"
"os"
"sync"
"syscall"
)
type mmsghdrs []mmsghdr
func (hs mmsghdrs) unpack(ms []Message, parseFn func([]byte, string) (net.Addr, error), hint string) error {
for i := range hs {
ms[i].N = int(hs[i].Len)
ms[i].NN = hs[i].Hdr.controllen()
ms[i].Flags = hs[i].Hdr.flags()
if parseFn != nil {
var err error
ms[i].Addr, err = parseFn(hs[i].Hdr.name(), hint)
if err != nil {
return err
}
}
}
return nil
}
// mmsghdrsPacker packs Message-slices into mmsghdrs (re-)using pre-allocated buffers.
type mmsghdrsPacker struct {
// hs are the pre-allocated mmsghdrs.
hs mmsghdrs
// sockaddrs is the pre-allocated buffer for the Hdr.Name buffers.
// We use one large buffer for all messages and slice it up.
sockaddrs []byte
// vs are the pre-allocated iovecs.
// We allocate one large buffer for all messages and slice it up. This allows to reuse the buffer
// if the number of buffers per message is distributed differently between calls.
vs []iovec
}
func (p *mmsghdrsPacker) prepare(ms []Message) {
n := len(ms)
if n <= cap(p.hs) {
p.hs = p.hs[:n]
} else {
p.hs = make(mmsghdrs, n)
}
if n*sizeofSockaddrInet6 <= cap(p.sockaddrs) {
p.sockaddrs = p.sockaddrs[:n*sizeofSockaddrInet6]
} else {
p.sockaddrs = make([]byte, n*sizeofSockaddrInet6)
}
nb := 0
for _, m := range ms {
nb += len(m.Buffers)
}
if nb <= cap(p.vs) {
p.vs = p.vs[:nb]
} else {
p.vs = make([]iovec, nb)
}
}
func (p *mmsghdrsPacker) pack(ms []Message, parseFn func([]byte, string) (net.Addr, error), marshalFn func(net.Addr, []byte) int) mmsghdrs {
p.prepare(ms)
hs := p.hs
vsRest := p.vs
saRest := p.sockaddrs
for i := range hs {
nvs := len(ms[i].Buffers)
vs := vsRest[:nvs]
vsRest = vsRest[nvs:]
var sa []byte
if parseFn != nil {
sa = saRest[:sizeofSockaddrInet6]
saRest = saRest[sizeofSockaddrInet6:]
} else if marshalFn != nil {
n := marshalFn(ms[i].Addr, saRest)
if n > 0 {
sa = saRest[:n]
saRest = saRest[n:]
}
}
hs[i].Hdr.pack(vs, ms[i].Buffers, ms[i].OOB, sa)
}
return hs
}
// syscaller is a helper to invoke recvmmsg and sendmmsg via the RawConn.Read/Write interface.
// It is reusable, to amortize the overhead of allocating a closure for the function passed to
// RawConn.Read/Write.
type syscaller struct {
n int
operr error
hs mmsghdrs
flags int
boundRecvmmsgF func(uintptr) bool
boundSendmmsgF func(uintptr) bool
}
func (r *syscaller) init() {
r.boundRecvmmsgF = r.recvmmsgF
r.boundSendmmsgF = r.sendmmsgF
}
func (r *syscaller) recvmmsg(c syscall.RawConn, hs mmsghdrs, flags int) (int, error) {
r.n = 0
r.operr = nil
r.hs = hs
r.flags = flags
if err := c.Read(r.boundRecvmmsgF); err != nil {
return r.n, err
}
if r.operr != nil {
return r.n, os.NewSyscallError("recvmmsg", r.operr)
}
return r.n, nil
}
func (r *syscaller) recvmmsgF(s uintptr) bool {
r.n, r.operr = recvmmsg(s, r.hs, r.flags)
return ioComplete(r.flags, r.operr)
}
func (r *syscaller) sendmmsg(c syscall.RawConn, hs mmsghdrs, flags int) (int, error) {
r.n = 0
r.operr = nil
r.hs = hs
r.flags = flags
if err := c.Write(r.boundSendmmsgF); err != nil {
return r.n, err
}
if r.operr != nil {
return r.n, os.NewSyscallError("sendmmsg", r.operr)
}
return r.n, nil
}
func (r *syscaller) sendmmsgF(s uintptr) bool {
r.n, r.operr = sendmmsg(s, r.hs, r.flags)
return ioComplete(r.flags, r.operr)
}
// mmsgTmps holds reusable temporary helpers for recvmmsg and sendmmsg.
type mmsgTmps struct {
packer mmsghdrsPacker
syscaller syscaller
}
var defaultMmsgTmpsPool = mmsgTmpsPool{
p: sync.Pool{
New: func() interface{} {
tmps := new(mmsgTmps)
tmps.syscaller.init()
return tmps
},
},
}
type mmsgTmpsPool struct {
p sync.Pool
}
func (p *mmsgTmpsPool) Get() *mmsgTmps {
m := p.p.Get().(*mmsgTmps)
// Clear fields up to the len (not the cap) of the slice,
// assuming that the previous caller only used that many elements.
for i := range m.packer.sockaddrs {
m.packer.sockaddrs[i] = 0
}
m.packer.sockaddrs = m.packer.sockaddrs[:0]
for i := range m.packer.vs {
m.packer.vs[i] = iovec{}
}
m.packer.vs = m.packer.vs[:0]
for i := range m.packer.hs {
m.packer.hs[i].Len = 0
m.packer.hs[i].Hdr = msghdr{}
}
m.packer.hs = m.packer.hs[:0]
return m
}
func (p *mmsgTmpsPool) Put(tmps *mmsgTmps) {
p.p.Put(tmps)
}
// 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 socket
import "unsafe"
func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {
for i := range vs {
vs[i].set(bs[i])
}
h.setIov(vs)
if len(oob) > 0 {
h.setControl(oob)
}
if sa != nil {
h.Name = (*byte)(unsafe.Pointer(&sa[0]))
h.Namelen = uint32(len(sa))
}
}
func (h *msghdr) name() []byte {
if h.Name != nil && h.Namelen > 0 {
return (*[sizeofSockaddrInet6]byte)(unsafe.Pointer(h.Name))[:h.Namelen]
}
return nil
}
func (h *msghdr) controllen() int {
return int(h.Controllen)
}
func (h *msghdr) flags() int {
return int(h.Flags)
}
// 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.
//go:build (arm64 || amd64 || loong64 || ppc64 || ppc64le || mips64 || mips64le || riscv64 || s390x) && linux
package socket
import "unsafe"
func (h *msghdr) setIov(vs []iovec) {
l := len(vs)
if l == 0 {
return
}
h.Iov = &vs[0]
h.Iovlen = uint64(l)
}
func (h *msghdr) setControl(b []byte) {
h.Control = (*byte)(unsafe.Pointer(&b[0]))
h.Controllen = uint64(len(b))
}
// Copyright 2019 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.
//go:build !race
package socket
func (m *Message) raceRead() {
}
func (m *Message) raceWrite() {
}
// 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 socket
import (
"errors"
"net"
"os"
"syscall"
)
// A Conn represents a raw connection.
type Conn struct {
network string
c syscall.RawConn
}
// tcpConn is an interface implemented by net.TCPConn.
// It can be used for interface assertions to check if a net.Conn is a TCP connection.
type tcpConn interface {
SyscallConn() (syscall.RawConn, error)
SetLinger(int) error
}
var _ tcpConn = (*net.TCPConn)(nil)
// udpConn is an interface implemented by net.UDPConn.
// It can be used for interface assertions to check if a net.Conn is a UDP connection.
type udpConn interface {
SyscallConn() (syscall.RawConn, error)
ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error)
}
var _ udpConn = (*net.UDPConn)(nil)
// ipConn is an interface implemented by net.IPConn.
// It can be used for interface assertions to check if a net.Conn is an IP connection.
type ipConn interface {
SyscallConn() (syscall.RawConn, error)
ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *net.IPAddr, err error)
}
var _ ipConn = (*net.IPConn)(nil)
// NewConn returns a new raw connection.
func NewConn(c net.Conn) (*Conn, error) {
var err error
var cc Conn
switch c := c.(type) {
case tcpConn:
cc.network = "tcp"
cc.c, err = c.SyscallConn()
case udpConn:
cc.network = "udp"
cc.c, err = c.SyscallConn()
case ipConn:
cc.network = "ip"
cc.c, err = c.SyscallConn()
default:
return nil, errors.New("unknown connection type")
}
if err != nil {
return nil, err
}
return &cc, nil
}
func (o *Option) get(c *Conn, b []byte) (int, error) {
var operr error
var n int
fn := func(s uintptr) {
n, operr = getsockopt(s, o.Level, o.Name, b)
}
if err := c.c.Control(fn); err != nil {
return 0, err
}
return n, os.NewSyscallError("getsockopt", operr)
}
func (o *Option) set(c *Conn, b []byte) error {
var operr error
fn := func(s uintptr) {
operr = setsockopt(s, o.Level, o.Name, b)
}
if err := c.c.Control(fn); err != nil {
return err
}
return os.NewSyscallError("setsockopt", operr)
}
// 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.
//go:build linux
package socket
import (
"net"
)
func (c *Conn) recvMsgs(ms []Message, flags int) (int, error) {
for i := range ms {
ms[i].raceWrite()
}
tmps := defaultMmsgTmpsPool.Get()
defer defaultMmsgTmpsPool.Put(tmps)
var parseFn func([]byte, string) (net.Addr, error)
if c.network != "tcp" {
parseFn = parseInetAddr
}
hs := tmps.packer.pack(ms, parseFn, nil)
n, err := tmps.syscaller.recvmmsg(c.c, hs, flags)
if err != nil {
return n, err
}
if err := hs[:n].unpack(ms[:n], parseFn, c.network); err != nil {
return n, err
}
return n, nil
}
func (c *Conn) sendMsgs(ms []Message, flags int) (int, error) {
for i := range ms {
ms[i].raceRead()
}
tmps := defaultMmsgTmpsPool.Get()
defer defaultMmsgTmpsPool.Put(tmps)
var marshalFn func(net.Addr, []byte) int
if c.network != "tcp" {
marshalFn = marshalInetAddr
}
hs := tmps.packer.pack(ms, nil, marshalFn)
n, err := tmps.syscaller.sendmmsg(c.c, hs, flags)
if err != nil {
return n, err
}
if err := hs[:n].unpack(ms[:n], nil, ""); err != nil {
return n, err
}
return n, nil
}
// 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.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows || zos
package socket
import (
"net"
"os"
)
func (c *Conn) recvMsg(m *Message, flags int) error {
m.raceWrite()
var (
operr error
n int
oobn int
recvflags int
from net.Addr
)
fn := func(s uintptr) bool {
n, oobn, recvflags, from, operr = recvmsg(s, m.Buffers, m.OOB, flags, c.network)
return ioComplete(flags, operr)
}
if err := c.c.Read(fn); err != nil {
return err
}
if operr != nil {
return os.NewSyscallError("recvmsg", operr)
}
m.Addr = from
m.N = n
m.NN = oobn
m.Flags = recvflags
return nil
}
func (c *Conn) sendMsg(m *Message, flags int) error {
m.raceRead()
var (
operr error
n int
)
fn := func(s uintptr) bool {
n, operr = sendmsg(s, m.Buffers, m.OOB, m.Addr, flags)
return ioComplete(flags, operr)
}
if err := c.c.Write(fn); err != nil {
return err
}
if operr != nil {
return os.NewSyscallError("sendmsg", operr)
}
m.N = n
m.NN = len(m.OOB)
return nil
}
// 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 socket provides a portable interface for socket system
// calls.
package socket // import "golang.org/x/net/internal/socket"
import (
"errors"
"net"
"runtime"
"unsafe"
)
var errNotImplemented = errors.New("not implemented on " + runtime.GOOS + "/" + runtime.GOARCH)
// An Option represents a sticky socket option.
type Option struct {
Level int // level
Name int // name; must be equal or greater than 1
Len int // length of value in bytes; must be equal or greater than 1
}
// Get reads a value for the option from the kernel.
// It returns the number of bytes written into b.
func (o *Option) Get(c *Conn, b []byte) (int, error) {
if o.Name < 1 || o.Len < 1 {
return 0, errors.New("invalid option")
}
if len(b) < o.Len {
return 0, errors.New("short buffer")
}
return o.get(c, b)
}
// GetInt returns an integer value for the option.
//
// The Len field of Option must be either 1 or 4.
func (o *Option) GetInt(c *Conn) (int, error) {
if o.Len != 1 && o.Len != 4 {
return 0, errors.New("invalid option")
}
var b []byte
var bb [4]byte
if o.Len == 1 {
b = bb[:1]
} else {
b = bb[:4]
}
n, err := o.get(c, b)
if err != nil {
return 0, err
}
if n != o.Len {
return 0, errors.New("invalid option length")
}
if o.Len == 1 {
return int(b[0]), nil
}
return int(NativeEndian.Uint32(b[:4])), nil
}
// Set writes the option and value to the kernel.
func (o *Option) Set(c *Conn, b []byte) error {
if o.Name < 1 || o.Len < 1 {
return errors.New("invalid option")
}
if len(b) < o.Len {
return errors.New("short buffer")
}
return o.set(c, b)
}
// SetInt writes the option and value to the kernel.
//
// The Len field of Option must be either 1 or 4.
func (o *Option) SetInt(c *Conn, v int) error {
if o.Len != 1 && o.Len != 4 {
return errors.New("invalid option")
}
var b []byte
if o.Len == 1 {
b = []byte{byte(v)}
} else {
var bb [4]byte
NativeEndian.PutUint32(bb[:o.Len], uint32(v))
b = bb[:4]
}
return o.set(c, b)
}
// ControlMessageSpace returns the whole length of control message.
func ControlMessageSpace(dataLen int) int {
return controlMessageSpace(dataLen)
}
// A ControlMessage represents the head message in a stream of control
// messages.
//
// A control message comprises of a header, data and a few padding
// fields to conform to the interface to the kernel.
//
// See RFC 3542 for further information.
type ControlMessage []byte
// Data returns the data field of the control message at the head on
// m.
func (m ControlMessage) Data(dataLen int) []byte {
l := controlHeaderLen()
if len(m) < l || len(m) < l+dataLen {
return nil
}
return m[l : l+dataLen]
}
// Next returns the control message at the next on m.
//
// Next works only for standard control messages.
func (m ControlMessage) Next(dataLen int) ControlMessage {
l := ControlMessageSpace(dataLen)
if len(m) < l {
return nil
}
return m[l:]
}
// MarshalHeader marshals the header fields of the control message at
// the head on m.
func (m ControlMessage) MarshalHeader(lvl, typ, dataLen int) error {
if len(m) < controlHeaderLen() {
return errors.New("short message")
}
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
h.set(controlMessageLen(dataLen), lvl, typ)
return nil
}
// ParseHeader parses and returns the header fields of the control
// message at the head on m.
func (m ControlMessage) ParseHeader() (lvl, typ, dataLen int, err error) {
l := controlHeaderLen()
if len(m) < l {
return 0, 0, 0, errors.New("short message")
}
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
return h.lvl(), h.typ(), int(uint64(h.len()) - uint64(l)), nil
}
// Marshal marshals the control message at the head on m, and returns
// the next control message.
func (m ControlMessage) Marshal(lvl, typ int, data []byte) (ControlMessage, error) {
l := len(data)
if len(m) < ControlMessageSpace(l) {
return nil, errors.New("short message")
}
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
h.set(controlMessageLen(l), lvl, typ)
if l > 0 {
copy(m.Data(l), data)
}
return m.Next(l), nil
}
// Parse parses m as a single or multiple control messages.
//
// Parse works for both standard and compatible messages.
func (m ControlMessage) Parse() ([]ControlMessage, error) {
var ms []ControlMessage
for len(m) >= controlHeaderLen() {
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
l := h.len()
if l <= 0 {
return nil, errors.New("invalid header length")
}
if uint64(l) < uint64(controlHeaderLen()) {
return nil, errors.New("invalid message length")
}
if uint64(l) > uint64(len(m)) {
return nil, errors.New("short buffer")
}
// On message reception:
//
// |<- ControlMessageSpace --------------->|
// |<- controlMessageLen ---------->| |
// |<- controlHeaderLen ->| | |
// +---------------+------+---------+------+
// | Header | PadH | Data | PadD |
// +---------------+------+---------+------+
//
// On compatible message reception:
//
// | ... |<- controlMessageLen ----------->|
// | ... |<- controlHeaderLen ->| |
// +-----+---------------+------+----------+
// | ... | Header | PadH | Data |
// +-----+---------------+------+----------+
ms = append(ms, ControlMessage(m[:l]))
ll := l - controlHeaderLen()
if len(m) >= ControlMessageSpace(ll) {
m = m[ControlMessageSpace(ll):]
} else {
m = m[controlMessageLen(ll):]
}
}
return ms, nil
}
// NewControlMessage returns a new stream of control messages.
func NewControlMessage(dataLen []int) ControlMessage {
var l int
for i := range dataLen {
l += ControlMessageSpace(dataLen[i])
}
return make([]byte, l)
}
// A Message represents an IO message.
type Message struct {
// When writing, the Buffers field must contain at least one
// byte to write.
// When reading, the Buffers field will always contain a byte
// to read.
Buffers [][]byte
// OOB contains protocol-specific control or miscellaneous
// ancillary data known as out-of-band data.
OOB []byte
// Addr specifies a destination address when writing.
// It can be nil when the underlying protocol of the raw
// connection uses connection-oriented communication.
// After a successful read, it may contain the source address
// on the received packet.
Addr net.Addr
N int // # of bytes read or written from/to Buffers
NN int // # of bytes read or written from/to OOB
Flags int // protocol-specific information on the received message
}
// RecvMsg wraps recvmsg system call.
//
// The provided flags is a set of platform-dependent flags, such as
// syscall.MSG_PEEK.
func (c *Conn) RecvMsg(m *Message, flags int) error {
return c.recvMsg(m, flags)
}
// SendMsg wraps sendmsg system call.
//
// The provided flags is a set of platform-dependent flags, such as
// syscall.MSG_DONTROUTE.
func (c *Conn) SendMsg(m *Message, flags int) error {
return c.sendMsg(m, flags)
}
// RecvMsgs wraps recvmmsg system call.
//
// It returns the number of processed messages.
//
// The provided flags is a set of platform-dependent flags, such as
// syscall.MSG_PEEK.
//
// Only Linux supports this.
func (c *Conn) RecvMsgs(ms []Message, flags int) (int, error) {
return c.recvMsgs(ms, flags)
}
// SendMsgs wraps sendmmsg system call.
//
// It returns the number of processed messages.
//
// The provided flags is a set of platform-dependent flags, such as
// syscall.MSG_DONTROUTE.
//
// Only Linux supports this.
func (c *Conn) SendMsgs(ms []Message, flags int) (int, error) {
return c.sendMsgs(ms, flags)
}
// 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 socket
import (
"encoding/binary"
"unsafe"
)
// NativeEndian is the machine native endian implementation of ByteOrder.
var NativeEndian binary.ByteOrder
func init() {
i := uint32(1)
b := (*[4]byte)(unsafe.Pointer(&i))
if b[0] == 1 {
NativeEndian = binary.LittleEndian
} else {
NativeEndian = binary.BigEndian
}
}
// 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.
//go:build linux && !s390x && !386
package socket
import (
"syscall"
"unsafe"
)
func recvmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
n, _, errno := syscall.Syscall6(sysRECVMMSG, s, uintptr(unsafe.Pointer(&hs[0])), uintptr(len(hs)), uintptr(flags), 0, 0)
return int(n), errnoErr(errno)
}
func sendmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
n, _, errno := syscall.Syscall6(sysSENDMMSG, s, uintptr(unsafe.Pointer(&hs[0])), uintptr(len(hs)), uintptr(flags), 0, 0)
return int(n), errnoErr(errno)
}
// 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.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows || zos
package socket
import (
"encoding/binary"
"errors"
"net"
"runtime"
"strconv"
"sync"
"time"
)
// marshalInetAddr writes a in sockaddr format into the buffer b.
// The buffer must be sufficiently large (sizeofSockaddrInet4/6).
// Returns the number of bytes written.
func marshalInetAddr(a net.Addr, b []byte) int {
switch a := a.(type) {
case *net.TCPAddr:
return marshalSockaddr(a.IP, a.Port, a.Zone, b)
case *net.UDPAddr:
return marshalSockaddr(a.IP, a.Port, a.Zone, b)
case *net.IPAddr:
return marshalSockaddr(a.IP, 0, a.Zone, b)
default:
return 0
}
}
func marshalSockaddr(ip net.IP, port int, zone string, b []byte) int {
if ip4 := ip.To4(); ip4 != nil {
switch runtime.GOOS {
case "android", "illumos", "linux", "solaris", "windows":
NativeEndian.PutUint16(b[:2], uint16(sysAF_INET))
default:
b[0] = sizeofSockaddrInet4
b[1] = sysAF_INET
}
binary.BigEndian.PutUint16(b[2:4], uint16(port))
copy(b[4:8], ip4)
return sizeofSockaddrInet4
}
if ip6 := ip.To16(); ip6 != nil && ip.To4() == nil {
switch runtime.GOOS {
case "android", "illumos", "linux", "solaris", "windows":
NativeEndian.PutUint16(b[:2], uint16(sysAF_INET6))
default:
b[0] = sizeofSockaddrInet6
b[1] = sysAF_INET6
}
binary.BigEndian.PutUint16(b[2:4], uint16(port))
copy(b[8:24], ip6)
if zone != "" {
NativeEndian.PutUint32(b[24:28], uint32(zoneCache.index(zone)))
}
return sizeofSockaddrInet6
}
return 0
}
func parseInetAddr(b []byte, network string) (net.Addr, error) {
if len(b) < 2 {
return nil, errors.New("invalid address")
}
var af int
switch runtime.GOOS {
case "android", "illumos", "linux", "solaris", "windows":
af = int(NativeEndian.Uint16(b[:2]))
default:
af = int(b[1])
}
var ip net.IP
var zone string
if af == sysAF_INET {
if len(b) < sizeofSockaddrInet4 {
return nil, errors.New("short address")
}
ip = make(net.IP, net.IPv4len)
copy(ip, b[4:8])
}
if af == sysAF_INET6 {
if len(b) < sizeofSockaddrInet6 {
return nil, errors.New("short address")
}
ip = make(net.IP, net.IPv6len)
copy(ip, b[8:24])
if id := int(NativeEndian.Uint32(b[24:28])); id > 0 {
zone = zoneCache.name(id)
}
}
switch network {
case "tcp", "tcp4", "tcp6":
return &net.TCPAddr{IP: ip, Port: int(binary.BigEndian.Uint16(b[2:4])), Zone: zone}, nil
case "udp", "udp4", "udp6":
return &net.UDPAddr{IP: ip, Port: int(binary.BigEndian.Uint16(b[2:4])), Zone: zone}, nil
default:
return &net.IPAddr{IP: ip, Zone: zone}, nil
}
}
// An ipv6ZoneCache represents a cache holding partial network
// interface information. It is used for reducing the cost of IPv6
// addressing scope zone resolution.
//
// Multiple names sharing the index are managed by first-come
// first-served basis for consistency.
type ipv6ZoneCache struct {
sync.RWMutex // guard the following
lastFetched time.Time // last time routing information was fetched
toIndex map[string]int // interface name to its index
toName map[int]string // interface index to its name
}
var zoneCache = ipv6ZoneCache{
toIndex: make(map[string]int),
toName: make(map[int]string),
}
// update refreshes the network interface information if the cache was last
// updated more than 1 minute ago, or if force is set. It returns whether the
// cache was updated.
func (zc *ipv6ZoneCache) update(ift []net.Interface, force bool) (updated bool) {
zc.Lock()
defer zc.Unlock()
now := time.Now()
if !force && zc.lastFetched.After(now.Add(-60*time.Second)) {
return false
}
zc.lastFetched = now
if len(ift) == 0 {
var err error
if ift, err = net.Interfaces(); err != nil {
return false
}
}
zc.toIndex = make(map[string]int, len(ift))
zc.toName = make(map[int]string, len(ift))
for _, ifi := range ift {
zc.toIndex[ifi.Name] = ifi.Index
if _, ok := zc.toName[ifi.Index]; !ok {
zc.toName[ifi.Index] = ifi.Name
}
}
return true
}
func (zc *ipv6ZoneCache) name(zone int) string {
updated := zoneCache.update(nil, false)
zoneCache.RLock()
name, ok := zoneCache.toName[zone]
zoneCache.RUnlock()
if !ok && !updated {
zoneCache.update(nil, true)
zoneCache.RLock()
name, ok = zoneCache.toName[zone]
zoneCache.RUnlock()
}
if !ok { // last resort
name = strconv.Itoa(zone)
}
return name
}
func (zc *ipv6ZoneCache) index(zone string) int {
updated := zoneCache.update(nil, false)
zoneCache.RLock()
index, ok := zoneCache.toIndex[zone]
zoneCache.RUnlock()
if !ok && !updated {
zoneCache.update(nil, true)
zoneCache.RLock()
index, ok = zoneCache.toIndex[zone]
zoneCache.RUnlock()
}
if !ok { // last resort
index, _ = strconv.Atoi(zone)
}
return index
}
// 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.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
package socket
import (
"net"
"unsafe"
"golang.org/x/sys/unix"
)
//go:linkname syscall_getsockopt syscall.getsockopt
func syscall_getsockopt(s, level, name int, val unsafe.Pointer, vallen *uint32) error
//go:linkname syscall_setsockopt syscall.setsockopt
func syscall_setsockopt(s, level, name int, val unsafe.Pointer, vallen uintptr) error
func getsockopt(s uintptr, level, name int, b []byte) (int, error) {
l := uint32(len(b))
err := syscall_getsockopt(int(s), level, name, unsafe.Pointer(&b[0]), &l)
return int(l), err
}
func setsockopt(s uintptr, level, name int, b []byte) error {
return syscall_setsockopt(int(s), level, name, unsafe.Pointer(&b[0]), uintptr(len(b)))
}
func recvmsg(s uintptr, buffers [][]byte, oob []byte, flags int, network string) (n, oobn int, recvflags int, from net.Addr, err error) {
var unixFrom unix.Sockaddr
n, oobn, recvflags, unixFrom, err = unix.RecvmsgBuffers(int(s), buffers, oob, flags)
if unixFrom != nil {
from = sockaddrToAddr(unixFrom, network)
}
return
}
func sendmsg(s uintptr, buffers [][]byte, oob []byte, to net.Addr, flags int) (int, error) {
var unixTo unix.Sockaddr
if to != nil {
unixTo = addrToSockaddr(to)
}
return unix.SendmsgBuffers(int(s), buffers, oob, unixTo, flags)
}
// addrToSockaddr converts a net.Addr to a unix.Sockaddr.
func addrToSockaddr(a net.Addr) unix.Sockaddr {
var (
ip net.IP
port int
zone string
)
switch a := a.(type) {
case *net.TCPAddr:
ip = a.IP
port = a.Port
zone = a.Zone
case *net.UDPAddr:
ip = a.IP
port = a.Port
zone = a.Zone
case *net.IPAddr:
ip = a.IP
zone = a.Zone
default:
return nil
}
if ip4 := ip.To4(); ip4 != nil {
sa := unix.SockaddrInet4{Port: port}
copy(sa.Addr[:], ip4)
return &sa
}
if ip6 := ip.To16(); ip6 != nil && ip.To4() == nil {
sa := unix.SockaddrInet6{Port: port}
copy(sa.Addr[:], ip6)
if zone != "" {
sa.ZoneId = uint32(zoneCache.index(zone))
}
return &sa
}
return nil
}
// sockaddrToAddr converts a unix.Sockaddr to a net.Addr.
func sockaddrToAddr(sa unix.Sockaddr, network string) net.Addr {
var (
ip net.IP
port int
zone string
)
switch sa := sa.(type) {
case *unix.SockaddrInet4:
ip = make(net.IP, net.IPv4len)
copy(ip, sa.Addr[:])
port = sa.Port
case *unix.SockaddrInet6:
ip = make(net.IP, net.IPv6len)
copy(ip, sa.Addr[:])
port = sa.Port
if sa.ZoneId > 0 {
zone = zoneCache.name(int(sa.ZoneId))
}
default:
return nil
}
switch network {
case "tcp", "tcp4", "tcp6":
return &net.TCPAddr{IP: ip, Port: port, Zone: zone}
case "udp", "udp4", "udp6":
return &net.UDPAddr{IP: ip, Port: port, Zone: zone}
default:
return &net.IPAddr{IP: ip, Zone: zone}
}
}
// Copyright 2018 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 socks
import (
"context"
"errors"
"io"
"net"
"strconv"
"time"
)
var (
noDeadline = time.Time{}
aLongTimeAgo = time.Unix(1, 0)
)
func (d *Dialer) connect(ctx context.Context, c net.Conn, address string) (_ net.Addr, ctxErr error) {
host, port, err := splitHostPort(address)
if err != nil {
return nil, err
}
if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() {
c.SetDeadline(deadline)
defer c.SetDeadline(noDeadline)
}
if ctx != context.Background() {
errCh := make(chan error, 1)
done := make(chan struct{})
defer func() {
close(done)
if ctxErr == nil {
ctxErr = <-errCh
}
}()
go func() {
select {
case <-ctx.Done():
c.SetDeadline(aLongTimeAgo)
errCh <- ctx.Err()
case <-done:
errCh <- nil
}
}()
}
b := make([]byte, 0, 6+len(host)) // the size here is just an estimate
b = append(b, Version5)
if len(d.AuthMethods) == 0 || d.Authenticate == nil {
b = append(b, 1, byte(AuthMethodNotRequired))
} else {
ams := d.AuthMethods
if len(ams) > 255 {
return nil, errors.New("too many authentication methods")
}
b = append(b, byte(len(ams)))
for _, am := range ams {
b = append(b, byte(am))
}
}
if _, ctxErr = c.Write(b); ctxErr != nil {
return
}
if _, ctxErr = io.ReadFull(c, b[:2]); ctxErr != nil {
return
}
if b[0] != Version5 {
return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
}
am := AuthMethod(b[1])
if am == AuthMethodNoAcceptableMethods {
return nil, errors.New("no acceptable authentication methods")
}
if d.Authenticate != nil {
if ctxErr = d.Authenticate(ctx, c, am); ctxErr != nil {
return
}
}
b = b[:0]
b = append(b, Version5, byte(d.cmd), 0)
if ip := net.ParseIP(host); ip != nil {
if ip4 := ip.To4(); ip4 != nil {
b = append(b, AddrTypeIPv4)
b = append(b, ip4...)
} else if ip6 := ip.To16(); ip6 != nil {
b = append(b, AddrTypeIPv6)
b = append(b, ip6...)
} else {
return nil, errors.New("unknown address type")
}
} else {
if len(host) > 255 {
return nil, errors.New("FQDN too long")
}
b = append(b, AddrTypeFQDN)
b = append(b, byte(len(host)))
b = append(b, host...)
}
b = append(b, byte(port>>8), byte(port))
if _, ctxErr = c.Write(b); ctxErr != nil {
return
}
if _, ctxErr = io.ReadFull(c, b[:4]); ctxErr != nil {
return
}
if b[0] != Version5 {
return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
}
if cmdErr := Reply(b[1]); cmdErr != StatusSucceeded {
return nil, errors.New("unknown error " + cmdErr.String())
}
if b[2] != 0 {
return nil, errors.New("non-zero reserved field")
}
l := 2
var a Addr
switch b[3] {
case AddrTypeIPv4:
l += net.IPv4len
a.IP = make(net.IP, net.IPv4len)
case AddrTypeIPv6:
l += net.IPv6len
a.IP = make(net.IP, net.IPv6len)
case AddrTypeFQDN:
if _, err := io.ReadFull(c, b[:1]); err != nil {
return nil, err
}
l += int(b[0])
default:
return nil, errors.New("unknown address type " + strconv.Itoa(int(b[3])))
}
if cap(b) < l {
b = make([]byte, l)
} else {
b = b[:l]
}
if _, ctxErr = io.ReadFull(c, b); ctxErr != nil {
return
}
if a.IP != nil {
copy(a.IP, b)
} else {
a.Name = string(b[:len(b)-2])
}
a.Port = int(b[len(b)-2])<<8 | int(b[len(b)-1])
return &a, nil
}
func splitHostPort(address string) (string, int, error) {
host, port, err := net.SplitHostPort(address)
if err != nil {
return "", 0, err
}
portnum, err := strconv.Atoi(port)
if err != nil {
return "", 0, err
}
if 1 > portnum || portnum > 0xffff {
return "", 0, errors.New("port number out of range " + port)
}
return host, portnum, nil
}
// Copyright 2018 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 socks provides a SOCKS version 5 client implementation.
//
// SOCKS protocol version 5 is defined in RFC 1928.
// Username/Password authentication for SOCKS version 5 is defined in
// RFC 1929.
package socks
import (
"context"
"errors"
"io"
"net"
"strconv"
)
// A Command represents a SOCKS command.
type Command int
func (cmd Command) String() string {
switch cmd {
case CmdConnect:
return "socks connect"
case cmdBind:
return "socks bind"
default:
return "socks " + strconv.Itoa(int(cmd))
}
}
// An AuthMethod represents a SOCKS authentication method.
type AuthMethod int
// A Reply represents a SOCKS command reply code.
type Reply int
func (code Reply) String() string {
switch code {
case StatusSucceeded:
return "succeeded"
case 0x01:
return "general SOCKS server failure"
case 0x02:
return "connection not allowed by ruleset"
case 0x03:
return "network unreachable"
case 0x04:
return "host unreachable"
case 0x05:
return "connection refused"
case 0x06:
return "TTL expired"
case 0x07:
return "command not supported"
case 0x08:
return "address type not supported"
default:
return "unknown code: " + strconv.Itoa(int(code))
}
}
// Wire protocol constants.
const (
Version5 = 0x05
AddrTypeIPv4 = 0x01
AddrTypeFQDN = 0x03
AddrTypeIPv6 = 0x04
CmdConnect Command = 0x01 // establishes an active-open forward proxy connection
cmdBind Command = 0x02 // establishes a passive-open forward proxy connection
AuthMethodNotRequired AuthMethod = 0x00 // no authentication required
AuthMethodUsernamePassword AuthMethod = 0x02 // use username/password
AuthMethodNoAcceptableMethods AuthMethod = 0xff // no acceptable authentication methods
StatusSucceeded Reply = 0x00
)
// An Addr represents a SOCKS-specific address.
// Either Name or IP is used exclusively.
type Addr struct {
Name string // fully-qualified domain name
IP net.IP
Port int
}
func (a *Addr) Network() string { return "socks" }
func (a *Addr) String() string {
if a == nil {
return "<nil>"
}
port := strconv.Itoa(a.Port)
if a.IP == nil {
return net.JoinHostPort(a.Name, port)
}
return net.JoinHostPort(a.IP.String(), port)
}
// A Conn represents a forward proxy connection.
type Conn struct {
net.Conn
boundAddr net.Addr
}
// BoundAddr returns the address assigned by the proxy server for
// connecting to the command target address from the proxy server.
func (c *Conn) BoundAddr() net.Addr {
if c == nil {
return nil
}
return c.boundAddr
}
// A Dialer holds SOCKS-specific options.
type Dialer struct {
cmd Command // either CmdConnect or cmdBind
proxyNetwork string // network between a proxy server and a client
proxyAddress string // proxy server address
// ProxyDial specifies the optional dial function for
// establishing the transport connection.
ProxyDial func(context.Context, string, string) (net.Conn, error)
// AuthMethods specifies the list of request authentication
// methods.
// If empty, SOCKS client requests only AuthMethodNotRequired.
AuthMethods []AuthMethod
// Authenticate specifies the optional authentication
// function. It must be non-nil when AuthMethods is not empty.
// It must return an error when the authentication is failed.
Authenticate func(context.Context, io.ReadWriter, AuthMethod) error
}
// DialContext connects to the provided address on the provided
// network.
//
// The returned error value may be a net.OpError. When the Op field of
// net.OpError contains "socks", the Source field contains a proxy
// server address and the Addr field contains a command target
// address.
//
// See func Dial of the net package of standard library for a
// description of the network and address parameters.
func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
if err := d.validateTarget(network, address); err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
if ctx == nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
}
var err error
var c net.Conn
if d.ProxyDial != nil {
c, err = d.ProxyDial(ctx, d.proxyNetwork, d.proxyAddress)
} else {
var dd net.Dialer
c, err = dd.DialContext(ctx, d.proxyNetwork, d.proxyAddress)
}
if err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
a, err := d.connect(ctx, c, address)
if err != nil {
c.Close()
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
return &Conn{Conn: c, boundAddr: a}, nil
}
// DialWithConn initiates a connection from SOCKS server to the target
// network and address using the connection c that is already
// connected to the SOCKS server.
//
// It returns the connection's local address assigned by the SOCKS
// server.
func (d *Dialer) DialWithConn(ctx context.Context, c net.Conn, network, address string) (net.Addr, error) {
if err := d.validateTarget(network, address); err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
if ctx == nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
}
a, err := d.connect(ctx, c, address)
if err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
return a, nil
}
// Dial connects to the provided address on the provided network.
//
// Unlike DialContext, it returns a raw transport connection instead
// of a forward proxy connection.
//
// Deprecated: Use DialContext or DialWithConn instead.
func (d *Dialer) Dial(network, address string) (net.Conn, error) {
if err := d.validateTarget(network, address); err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
var err error
var c net.Conn
if d.ProxyDial != nil {
c, err = d.ProxyDial(context.Background(), d.proxyNetwork, d.proxyAddress)
} else {
c, err = net.Dial(d.proxyNetwork, d.proxyAddress)
}
if err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
if _, err := d.DialWithConn(context.Background(), c, network, address); err != nil {
c.Close()
return nil, err
}
return c, nil
}
func (d *Dialer) validateTarget(network, address string) error {
switch network {
case "tcp", "tcp6", "tcp4":
default:
return errors.New("network not implemented")
}
switch d.cmd {
case CmdConnect, cmdBind:
default:
return errors.New("command not implemented")
}
return nil
}
func (d *Dialer) pathAddrs(address string) (proxy, dst net.Addr, err error) {
for i, s := range []string{d.proxyAddress, address} {
host, port, err := splitHostPort(s)
if err != nil {
return nil, nil, err
}
a := &Addr{Port: port}
a.IP = net.ParseIP(host)
if a.IP == nil {
a.Name = host
}
if i == 0 {
proxy = a
} else {
dst = a
}
}
return
}
// NewDialer returns a new Dialer that dials through the provided
// proxy server's network and address.
func NewDialer(network, address string) *Dialer {
return &Dialer{proxyNetwork: network, proxyAddress: address, cmd: CmdConnect}
}
const (
authUsernamePasswordVersion = 0x01
authStatusSucceeded = 0x00
)
// UsernamePassword are the credentials for the username/password
// authentication method.
type UsernamePassword struct {
Username string
Password string
}
// Authenticate authenticates a pair of username and password with the
// proxy server.
func (up *UsernamePassword) Authenticate(ctx context.Context, rw io.ReadWriter, auth AuthMethod) error {
switch auth {
case AuthMethodNotRequired:
return nil
case AuthMethodUsernamePassword:
if len(up.Username) == 0 || len(up.Username) > 255 || len(up.Password) > 255 {
return errors.New("invalid username/password")
}
b := []byte{authUsernamePasswordVersion}
b = append(b, byte(len(up.Username)))
b = append(b, up.Username...)
b = append(b, byte(len(up.Password)))
b = append(b, up.Password...)
// TODO(mikio): handle IO deadlines and cancellation if
// necessary
if _, err := rw.Write(b); err != nil {
return err
}
if _, err := io.ReadFull(rw, b[:2]); err != nil {
return err
}
if b[0] != authUsernamePasswordVersion {
return errors.New("invalid username/password version")
}
if b[1] != authStatusSucceeded {
return errors.New("username/password authentication failed")
}
return nil
}
return errors.New("unsupported authentication method " + strconv.Itoa(int(auth)))
}
// 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 ipv6
import (
"net"
"runtime"
"golang.org/x/net/internal/socket"
)
// BUG(mikio): On Windows, the ReadBatch and WriteBatch methods of
// PacketConn are not implemented.
// A Message represents an IO message.
//
// type Message struct {
// Buffers [][]byte
// OOB []byte
// Addr net.Addr
// N int
// NN int
// Flags int
// }
//
// The Buffers fields represents a list of contiguous buffers, which
// can be used for vectored IO, for example, putting a header and a
// payload in each slice.
// When writing, the Buffers field must contain at least one byte to
// write.
// When reading, the Buffers field will always contain a byte to read.
//
// The OOB field contains protocol-specific control or miscellaneous
// ancillary data known as out-of-band data.
// It can be nil when not required.
//
// The Addr field specifies a destination address when writing.
// It can be nil when the underlying protocol of the endpoint uses
// connection-oriented communication.
// After a successful read, it may contain the source address on the
// received packet.
//
// The N field indicates the number of bytes read or written from/to
// Buffers.
//
// The NN field indicates the number of bytes read or written from/to
// OOB.
//
// The Flags field contains protocol-specific information on the
// received message.
type Message = socket.Message
// ReadBatch reads a batch of messages.
//
// The provided flags is a set of platform-dependent flags, such as
// syscall.MSG_PEEK.
//
// On a successful read it returns the number of messages received, up
// to len(ms).
//
// On Linux, a batch read will be optimized.
// On other platforms, this method will read only a single message.
func (c *payloadHandler) ReadBatch(ms []Message, flags int) (int, error) {
if !c.ok() {
return 0, errInvalidConn
}
switch runtime.GOOS {
case "linux":
n, err := c.RecvMsgs([]socket.Message(ms), flags)
if err != nil {
err = &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
}
return n, err
default:
n := 1
err := c.RecvMsg(&ms[0], flags)
if err != nil {
n = 0
err = &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
}
return n, err
}
}
// WriteBatch writes a batch of messages.
//
// The provided flags is a set of platform-dependent flags, such as
// syscall.MSG_DONTROUTE.
//
// It returns the number of messages written on a successful write.
//
// On Linux, a batch write will be optimized.
// On other platforms, this method will write only a single message.
func (c *payloadHandler) WriteBatch(ms []Message, flags int) (int, error) {
if !c.ok() {
return 0, errInvalidConn
}
switch runtime.GOOS {
case "linux":
n, err := c.SendMsgs([]socket.Message(ms), flags)
if err != nil {
err = &net.OpError{Op: "write", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
}
return n, err
default:
n := 1
err := c.SendMsg(&ms[0], flags)
if err != nil {
n = 0
err = &net.OpError{Op: "write", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
}
return n, err
}
}
// Copyright 2013 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 ipv6
import (
"fmt"
"net"
"sync"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
)
// Note that RFC 3542 obsoletes RFC 2292 but OS X Snow Leopard and the
// former still support RFC 2292 only. Please be aware that almost
// all protocol implementations prohibit using a combination of RFC
// 2292 and RFC 3542 for some practical reasons.
type rawOpt struct {
sync.RWMutex
cflags ControlFlags
}
func (c *rawOpt) set(f ControlFlags) { c.cflags |= f }
func (c *rawOpt) clear(f ControlFlags) { c.cflags &^= f }
func (c *rawOpt) isset(f ControlFlags) bool { return c.cflags&f != 0 }
// A ControlFlags represents per packet basis IP-level socket option
// control flags.
type ControlFlags uint
const (
FlagTrafficClass ControlFlags = 1 << iota // pass the traffic class on the received packet
FlagHopLimit // pass the hop limit on the received packet
FlagSrc // pass the source address on the received packet
FlagDst // pass the destination address on the received packet
FlagInterface // pass the interface index on the received packet
FlagPathMTU // pass the path MTU on the received packet path
)
const flagPacketInfo = FlagDst | FlagInterface
// A ControlMessage represents per packet basis IP-level socket
// options.
type ControlMessage struct {
// Receiving socket options: SetControlMessage allows to
// receive the options from the protocol stack using ReadFrom
// method of PacketConn.
//
// Specifying socket options: ControlMessage for WriteTo
// method of PacketConn allows to send the options to the
// protocol stack.
//
TrafficClass int // traffic class, must be 1 <= value <= 255 when specifying
HopLimit int // hop limit, must be 1 <= value <= 255 when specifying
Src net.IP // source address, specifying only
Dst net.IP // destination address, receiving only
IfIndex int // interface index, must be 1 <= value when specifying
NextHop net.IP // next hop address, specifying only
MTU int // path MTU, receiving only
}
func (cm *ControlMessage) String() string {
if cm == nil {
return "<nil>"
}
return fmt.Sprintf("tclass=%#x hoplim=%d src=%v dst=%v ifindex=%d nexthop=%v mtu=%d", cm.TrafficClass, cm.HopLimit, cm.Src, cm.Dst, cm.IfIndex, cm.NextHop, cm.MTU)
}
// Marshal returns the binary encoding of cm.
func (cm *ControlMessage) Marshal() []byte {
if cm == nil {
return nil
}
var l int
tclass := false
if ctlOpts[ctlTrafficClass].name > 0 && cm.TrafficClass > 0 {
tclass = true
l += socket.ControlMessageSpace(ctlOpts[ctlTrafficClass].length)
}
hoplimit := false
if ctlOpts[ctlHopLimit].name > 0 && cm.HopLimit > 0 {
hoplimit = true
l += socket.ControlMessageSpace(ctlOpts[ctlHopLimit].length)
}
pktinfo := false
if ctlOpts[ctlPacketInfo].name > 0 && (cm.Src.To16() != nil && cm.Src.To4() == nil || cm.IfIndex > 0) {
pktinfo = true
l += socket.ControlMessageSpace(ctlOpts[ctlPacketInfo].length)
}
nexthop := false
if ctlOpts[ctlNextHop].name > 0 && cm.NextHop.To16() != nil && cm.NextHop.To4() == nil {
nexthop = true
l += socket.ControlMessageSpace(ctlOpts[ctlNextHop].length)
}
var b []byte
if l > 0 {
b = make([]byte, l)
bb := b
if tclass {
bb = ctlOpts[ctlTrafficClass].marshal(bb, cm)
}
if hoplimit {
bb = ctlOpts[ctlHopLimit].marshal(bb, cm)
}
if pktinfo {
bb = ctlOpts[ctlPacketInfo].marshal(bb, cm)
}
if nexthop {
bb = ctlOpts[ctlNextHop].marshal(bb, cm)
}
}
return b
}
// Parse parses b as a control message and stores the result in cm.
func (cm *ControlMessage) Parse(b []byte) error {
ms, err := socket.ControlMessage(b).Parse()
if err != nil {
return err
}
for _, m := range ms {
lvl, typ, l, err := m.ParseHeader()
if err != nil {
return err
}
if lvl != iana.ProtocolIPv6 {
continue
}
switch {
case typ == ctlOpts[ctlTrafficClass].name && l >= ctlOpts[ctlTrafficClass].length:
ctlOpts[ctlTrafficClass].parse(cm, m.Data(l))
case typ == ctlOpts[ctlHopLimit].name && l >= ctlOpts[ctlHopLimit].length:
ctlOpts[ctlHopLimit].parse(cm, m.Data(l))
case typ == ctlOpts[ctlPacketInfo].name && l >= ctlOpts[ctlPacketInfo].length:
ctlOpts[ctlPacketInfo].parse(cm, m.Data(l))
case typ == ctlOpts[ctlPathMTU].name && l >= ctlOpts[ctlPathMTU].length:
ctlOpts[ctlPathMTU].parse(cm, m.Data(l))
}
}
return nil
}
// NewControlMessage returns a new control message.
//
// The returned message is large enough for options specified by cf.
func NewControlMessage(cf ControlFlags) []byte {
opt := rawOpt{cflags: cf}
var l int
if opt.isset(FlagTrafficClass) && ctlOpts[ctlTrafficClass].name > 0 {
l += socket.ControlMessageSpace(ctlOpts[ctlTrafficClass].length)
}
if opt.isset(FlagHopLimit) && ctlOpts[ctlHopLimit].name > 0 {
l += socket.ControlMessageSpace(ctlOpts[ctlHopLimit].length)
}
if opt.isset(flagPacketInfo) && ctlOpts[ctlPacketInfo].name > 0 {
l += socket.ControlMessageSpace(ctlOpts[ctlPacketInfo].length)
}
if opt.isset(FlagPathMTU) && ctlOpts[ctlPathMTU].name > 0 {
l += socket.ControlMessageSpace(ctlOpts[ctlPathMTU].length)
}
var b []byte
if l > 0 {
b = make([]byte, l)
}
return b
}
// Ancillary data socket options
const (
ctlTrafficClass = iota // header field
ctlHopLimit // header field
ctlPacketInfo // inbound or outbound packet path
ctlNextHop // nexthop
ctlPathMTU // path mtu
ctlMax
)
// A ctlOpt represents a binding for ancillary data socket option.
type ctlOpt struct {
name int // option name, must be equal or greater than 1
length int // option length
marshal func([]byte, *ControlMessage) []byte
parse func(*ControlMessage, []byte)
}
// Copyright 2013 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.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package ipv6
import (
"net"
"unsafe"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
func marshalTrafficClass(b []byte, cm *ControlMessage) []byte {
m := socket.ControlMessage(b)
m.MarshalHeader(iana.ProtocolIPv6, unix.IPV6_TCLASS, 4)
if cm != nil {
socket.NativeEndian.PutUint32(m.Data(4), uint32(cm.TrafficClass))
}
return m.Next(4)
}
func parseTrafficClass(cm *ControlMessage, b []byte) {
cm.TrafficClass = int(socket.NativeEndian.Uint32(b[:4]))
}
func marshalHopLimit(b []byte, cm *ControlMessage) []byte {
m := socket.ControlMessage(b)
m.MarshalHeader(iana.ProtocolIPv6, unix.IPV6_HOPLIMIT, 4)
if cm != nil {
socket.NativeEndian.PutUint32(m.Data(4), uint32(cm.HopLimit))
}
return m.Next(4)
}
func parseHopLimit(cm *ControlMessage, b []byte) {
cm.HopLimit = int(socket.NativeEndian.Uint32(b[:4]))
}
func marshalPacketInfo(b []byte, cm *ControlMessage) []byte {
m := socket.ControlMessage(b)
m.MarshalHeader(iana.ProtocolIPv6, unix.IPV6_PKTINFO, sizeofInet6Pktinfo)
if cm != nil {
pi := (*inet6Pktinfo)(unsafe.Pointer(&m.Data(sizeofInet6Pktinfo)[0]))
if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
copy(pi.Addr[:], ip)
}
if cm.IfIndex > 0 {
pi.setIfindex(cm.IfIndex)
}
}
return m.Next(sizeofInet6Pktinfo)
}
func parsePacketInfo(cm *ControlMessage, b []byte) {
pi := (*inet6Pktinfo)(unsafe.Pointer(&b[0]))
if len(cm.Dst) < net.IPv6len {
cm.Dst = make(net.IP, net.IPv6len)
}
copy(cm.Dst, pi.Addr[:])
cm.IfIndex = int(pi.Ifindex)
}
func marshalNextHop(b []byte, cm *ControlMessage) []byte {
m := socket.ControlMessage(b)
m.MarshalHeader(iana.ProtocolIPv6, unix.IPV6_NEXTHOP, sizeofSockaddrInet6)
if cm != nil {
sa := (*sockaddrInet6)(unsafe.Pointer(&m.Data(sizeofSockaddrInet6)[0]))
sa.setSockaddr(cm.NextHop, cm.IfIndex)
}
return m.Next(sizeofSockaddrInet6)
}
func parseNextHop(cm *ControlMessage, b []byte) {
}
func marshalPathMTU(b []byte, cm *ControlMessage) []byte {
m := socket.ControlMessage(b)
m.MarshalHeader(iana.ProtocolIPv6, unix.IPV6_PATHMTU, sizeofIPv6Mtuinfo)
return m.Next(sizeofIPv6Mtuinfo)
}
func parsePathMTU(cm *ControlMessage, b []byte) {
mi := (*ipv6Mtuinfo)(unsafe.Pointer(&b[0]))
if len(cm.Dst) < net.IPv6len {
cm.Dst = make(net.IP, net.IPv6len)
}
copy(cm.Dst, mi.Addr.Addr[:])
cm.IfIndex = int(mi.Addr.Scope_id)
cm.MTU = int(mi.Mtu)
}
// Copyright 2013 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.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package ipv6
import "golang.org/x/net/internal/socket"
func setControlMessage(c *socket.Conn, opt *rawOpt, cf ControlFlags, on bool) error {
opt.Lock()
defer opt.Unlock()
if so, ok := sockOpts[ssoReceiveTrafficClass]; ok && cf&FlagTrafficClass != 0 {
if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
opt.set(FlagTrafficClass)
} else {
opt.clear(FlagTrafficClass)
}
}
if so, ok := sockOpts[ssoReceiveHopLimit]; ok && cf&FlagHopLimit != 0 {
if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
opt.set(FlagHopLimit)
} else {
opt.clear(FlagHopLimit)
}
}
if so, ok := sockOpts[ssoReceivePacketInfo]; ok && cf&flagPacketInfo != 0 {
if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
opt.set(cf & flagPacketInfo)
} else {
opt.clear(cf & flagPacketInfo)
}
}
if so, ok := sockOpts[ssoReceivePathMTU]; ok && cf&FlagPathMTU != 0 {
if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
opt.set(FlagPathMTU)
} else {
opt.clear(FlagPathMTU)
}
}
return nil
}
// Copyright 2013 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 ipv6
import (
"net"
"golang.org/x/net/bpf"
)
// MulticastHopLimit returns the hop limit field value for outgoing
// multicast packets.
func (c *dgramOpt) MulticastHopLimit() (int, error) {
if !c.ok() {
return 0, errInvalidConn
}
so, ok := sockOpts[ssoMulticastHopLimit]
if !ok {
return 0, errNotImplemented
}
return so.GetInt(c.Conn)
}
// SetMulticastHopLimit sets the hop limit field value for future
// outgoing multicast packets.
func (c *dgramOpt) SetMulticastHopLimit(hoplim int) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoMulticastHopLimit]
if !ok {
return errNotImplemented
}
return so.SetInt(c.Conn, hoplim)
}
// MulticastInterface returns the default interface for multicast
// packet transmissions.
func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
if !c.ok() {
return nil, errInvalidConn
}
so, ok := sockOpts[ssoMulticastInterface]
if !ok {
return nil, errNotImplemented
}
return so.getMulticastInterface(c.Conn)
}
// SetMulticastInterface sets the default interface for future
// multicast packet transmissions.
func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoMulticastInterface]
if !ok {
return errNotImplemented
}
return so.setMulticastInterface(c.Conn, ifi)
}
// MulticastLoopback reports whether transmitted multicast packets
// should be copied and send back to the originator.
func (c *dgramOpt) MulticastLoopback() (bool, error) {
if !c.ok() {
return false, errInvalidConn
}
so, ok := sockOpts[ssoMulticastLoopback]
if !ok {
return false, errNotImplemented
}
on, err := so.GetInt(c.Conn)
if err != nil {
return false, err
}
return on == 1, nil
}
// SetMulticastLoopback sets whether transmitted multicast packets
// should be copied and send back to the originator.
func (c *dgramOpt) SetMulticastLoopback(on bool) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoMulticastLoopback]
if !ok {
return errNotImplemented
}
return so.SetInt(c.Conn, boolint(on))
}
// JoinGroup joins the group address group on the interface ifi.
// By default all sources that can cast data to group are accepted.
// It's possible to mute and unmute data transmission from a specific
// source by using ExcludeSourceSpecificGroup and
// IncludeSourceSpecificGroup.
// JoinGroup uses the system assigned multicast interface when ifi is
// nil, although this is not recommended because the assignment
// depends on platforms and sometimes it might require routing
// configuration.
func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoJoinGroup]
if !ok {
return errNotImplemented
}
grp := netAddrToIP16(group)
if grp == nil {
return errMissingAddress
}
return so.setGroup(c.Conn, ifi, grp)
}
// LeaveGroup leaves the group address group on the interface ifi
// regardless of whether the group is any-source group or
// source-specific group.
func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoLeaveGroup]
if !ok {
return errNotImplemented
}
grp := netAddrToIP16(group)
if grp == nil {
return errMissingAddress
}
return so.setGroup(c.Conn, ifi, grp)
}
// JoinSourceSpecificGroup joins the source-specific group comprising
// group and source on the interface ifi.
// JoinSourceSpecificGroup uses the system assigned multicast
// interface when ifi is nil, although this is not recommended because
// the assignment depends on platforms and sometimes it might require
// routing configuration.
func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoJoinSourceGroup]
if !ok {
return errNotImplemented
}
grp := netAddrToIP16(group)
if grp == nil {
return errMissingAddress
}
src := netAddrToIP16(source)
if src == nil {
return errMissingAddress
}
return so.setSourceGroup(c.Conn, ifi, grp, src)
}
// LeaveSourceSpecificGroup leaves the source-specific group on the
// interface ifi.
func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoLeaveSourceGroup]
if !ok {
return errNotImplemented
}
grp := netAddrToIP16(group)
if grp == nil {
return errMissingAddress
}
src := netAddrToIP16(source)
if src == nil {
return errMissingAddress
}
return so.setSourceGroup(c.Conn, ifi, grp, src)
}
// ExcludeSourceSpecificGroup excludes the source-specific group from
// the already joined any-source groups by JoinGroup on the interface
// ifi.
func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoBlockSourceGroup]
if !ok {
return errNotImplemented
}
grp := netAddrToIP16(group)
if grp == nil {
return errMissingAddress
}
src := netAddrToIP16(source)
if src == nil {
return errMissingAddress
}
return so.setSourceGroup(c.Conn, ifi, grp, src)
}
// IncludeSourceSpecificGroup includes the excluded source-specific
// group by ExcludeSourceSpecificGroup again on the interface ifi.
func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoUnblockSourceGroup]
if !ok {
return errNotImplemented
}
grp := netAddrToIP16(group)
if grp == nil {
return errMissingAddress
}
src := netAddrToIP16(source)
if src == nil {
return errMissingAddress
}
return so.setSourceGroup(c.Conn, ifi, grp, src)
}
// Checksum reports whether the kernel will compute, store or verify a
// checksum for both incoming and outgoing packets. If on is true, it
// returns an offset in bytes into the data of where the checksum
// field is located.
func (c *dgramOpt) Checksum() (on bool, offset int, err error) {
if !c.ok() {
return false, 0, errInvalidConn
}
so, ok := sockOpts[ssoChecksum]
if !ok {
return false, 0, errNotImplemented
}
offset, err = so.GetInt(c.Conn)
if err != nil {
return false, 0, err
}
if offset < 0 {
return false, 0, nil
}
return true, offset, nil
}
// SetChecksum enables the kernel checksum processing. If on is true,
// the offset should be an offset in bytes into the data of where the
// checksum field is located.
func (c *dgramOpt) SetChecksum(on bool, offset int) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoChecksum]
if !ok {
return errNotImplemented
}
if !on {
offset = -1
}
return so.SetInt(c.Conn, offset)
}
// ICMPFilter returns an ICMP filter.
func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
if !c.ok() {
return nil, errInvalidConn
}
so, ok := sockOpts[ssoICMPFilter]
if !ok {
return nil, errNotImplemented
}
return so.getICMPFilter(c.Conn)
}
// SetICMPFilter deploys the ICMP filter.
func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoICMPFilter]
if !ok {
return errNotImplemented
}
return so.setICMPFilter(c.Conn, f)
}
// SetBPF attaches a BPF program to the connection.
//
// Only supported on Linux.
func (c *dgramOpt) SetBPF(filter []bpf.RawInstruction) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoAttachFilter]
if !ok {
return errNotImplemented
}
return so.setBPF(c.Conn, filter)
}
// Copyright 2013 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 ipv6
import (
"net"
"time"
"golang.org/x/net/internal/socket"
)
// BUG(mikio): On Windows, the JoinSourceSpecificGroup,
// LeaveSourceSpecificGroup, ExcludeSourceSpecificGroup and
// IncludeSourceSpecificGroup methods of PacketConn are not
// implemented.
// A Conn represents a network endpoint that uses IPv6 transport.
// It allows to set basic IP-level socket options such as traffic
// class and hop limit.
type Conn struct {
genericOpt
}
type genericOpt struct {
*socket.Conn
}
func (c *genericOpt) ok() bool { return c != nil && c.Conn != nil }
// PathMTU returns a path MTU value for the destination associated
// with the endpoint.
func (c *Conn) PathMTU() (int, error) {
if !c.ok() {
return 0, errInvalidConn
}
so, ok := sockOpts[ssoPathMTU]
if !ok {
return 0, errNotImplemented
}
_, mtu, err := so.getMTUInfo(c.Conn)
if err != nil {
return 0, err
}
return mtu, nil
}
// NewConn returns a new Conn.
func NewConn(c net.Conn) *Conn {
cc, _ := socket.NewConn(c)
return &Conn{
genericOpt: genericOpt{Conn: cc},
}
}
// A PacketConn represents a packet network endpoint that uses IPv6
// transport. It is used to control several IP-level socket options
// including IPv6 header manipulation. It also provides datagram
// based network I/O methods specific to the IPv6 and higher layer
// protocols such as OSPF, GRE, and UDP.
type PacketConn struct {
genericOpt
dgramOpt
payloadHandler
}
type dgramOpt struct {
*socket.Conn
}
func (c *dgramOpt) ok() bool { return c != nil && c.Conn != nil }
// SetControlMessage allows to receive the per packet basis IP-level
// socket options.
func (c *PacketConn) SetControlMessage(cf ControlFlags, on bool) error {
if !c.payloadHandler.ok() {
return errInvalidConn
}
return setControlMessage(c.dgramOpt.Conn, &c.payloadHandler.rawOpt, cf, on)
}
// SetDeadline sets the read and write deadlines associated with the
// endpoint.
func (c *PacketConn) SetDeadline(t time.Time) error {
if !c.payloadHandler.ok() {
return errInvalidConn
}
return c.payloadHandler.SetDeadline(t)
}
// SetReadDeadline sets the read deadline associated with the
// endpoint.
func (c *PacketConn) SetReadDeadline(t time.Time) error {
if !c.payloadHandler.ok() {
return errInvalidConn
}
return c.payloadHandler.SetReadDeadline(t)
}
// SetWriteDeadline sets the write deadline associated with the
// endpoint.
func (c *PacketConn) SetWriteDeadline(t time.Time) error {
if !c.payloadHandler.ok() {
return errInvalidConn
}
return c.payloadHandler.SetWriteDeadline(t)
}
// Close closes the endpoint.
func (c *PacketConn) Close() error {
if !c.payloadHandler.ok() {
return errInvalidConn
}
return c.payloadHandler.Close()
}
// NewPacketConn returns a new PacketConn using c as its underlying
// transport.
func NewPacketConn(c net.PacketConn) *PacketConn {
cc, _ := socket.NewConn(c.(net.Conn))
return &PacketConn{
genericOpt: genericOpt{Conn: cc},
dgramOpt: dgramOpt{Conn: cc},
payloadHandler: payloadHandler{PacketConn: c, Conn: cc},
}
}
// Copyright 2013 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 ipv6
// TrafficClass returns the traffic class field value for outgoing
// packets.
func (c *genericOpt) TrafficClass() (int, error) {
if !c.ok() {
return 0, errInvalidConn
}
so, ok := sockOpts[ssoTrafficClass]
if !ok {
return 0, errNotImplemented
}
return so.GetInt(c.Conn)
}
// SetTrafficClass sets the traffic class field value for future
// outgoing packets.
func (c *genericOpt) SetTrafficClass(tclass int) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoTrafficClass]
if !ok {
return errNotImplemented
}
return so.SetInt(c.Conn, tclass)
}
// HopLimit returns the hop limit field value for outgoing packets.
func (c *genericOpt) HopLimit() (int, error) {
if !c.ok() {
return 0, errInvalidConn
}
so, ok := sockOpts[ssoHopLimit]
if !ok {
return 0, errNotImplemented
}
return so.GetInt(c.Conn)
}
// SetHopLimit sets the hop limit field value for future outgoing
// packets.
func (c *genericOpt) SetHopLimit(hoplim int) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoHopLimit]
if !ok {
return errNotImplemented
}
return so.SetInt(c.Conn, hoplim)
}
// 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 ipv6
import (
"encoding/binary"
"fmt"
"net"
)
const (
Version = 6 // protocol version
HeaderLen = 40 // header length
)
// A Header represents an IPv6 base header.
type Header struct {
Version int // protocol version
TrafficClass int // traffic class
FlowLabel int // flow label
PayloadLen int // payload length
NextHeader int // next header
HopLimit int // hop limit
Src net.IP // source address
Dst net.IP // destination address
}
func (h *Header) String() string {
if h == nil {
return "<nil>"
}
return fmt.Sprintf("ver=%d tclass=%#x flowlbl=%#x payloadlen=%d nxthdr=%d hoplim=%d src=%v dst=%v", h.Version, h.TrafficClass, h.FlowLabel, h.PayloadLen, h.NextHeader, h.HopLimit, h.Src, h.Dst)
}
// ParseHeader parses b as an IPv6 base header.
func ParseHeader(b []byte) (*Header, error) {
if len(b) < HeaderLen {
return nil, errHeaderTooShort
}
h := &Header{
Version: int(b[0]) >> 4,
TrafficClass: int(b[0]&0x0f)<<4 | int(b[1])>>4,
FlowLabel: int(b[1]&0x0f)<<16 | int(b[2])<<8 | int(b[3]),
PayloadLen: int(binary.BigEndian.Uint16(b[4:6])),
NextHeader: int(b[6]),
HopLimit: int(b[7]),
}
h.Src = make(net.IP, net.IPv6len)
copy(h.Src, b[8:24])
h.Dst = make(net.IP, net.IPv6len)
copy(h.Dst, b[24:40])
return h, nil
}
// Copyright 2013 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 ipv6
import (
"errors"
"net"
"runtime"
)
var (
errInvalidConn = errors.New("invalid connection")
errMissingAddress = errors.New("missing address")
errHeaderTooShort = errors.New("header too short")
errInvalidConnType = errors.New("invalid conn type")
errNotImplemented = errors.New("not implemented on " + runtime.GOOS + "/" + runtime.GOARCH)
)
func boolint(b bool) int {
if b {
return 1
}
return 0
}
func netAddrToIP16(a net.Addr) net.IP {
switch v := a.(type) {
case *net.UDPAddr:
if ip := v.IP.To16(); ip != nil && ip.To4() == nil {
return ip
}
case *net.IPAddr:
if ip := v.IP.To16(); ip != nil && ip.To4() == nil {
return ip
}
}
return nil
}
func opAddr(a net.Addr) net.Addr {
switch a.(type) {
case *net.TCPAddr:
if a == nil {
return nil
}
case *net.UDPAddr:
if a == nil {
return nil
}
case *net.IPAddr:
if a == nil {
return nil
}
}
return a
}
// Copyright 2013 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 ipv6
import "golang.org/x/net/internal/iana"
// BUG(mikio): On Windows, methods related to ICMPFilter are not
// implemented.
// An ICMPType represents a type of ICMP message.
type ICMPType int
func (typ ICMPType) String() string {
s, ok := icmpTypes[typ]
if !ok {
return "<nil>"
}
return s
}
// Protocol returns the ICMPv6 protocol number.
func (typ ICMPType) Protocol() int {
return iana.ProtocolIPv6ICMP
}
// An ICMPFilter represents an ICMP message filter for incoming
// packets. The filter belongs to a packet delivery path on a host and
// it cannot interact with forwarding packets or tunnel-outer packets.
//
// Note: RFC 8200 defines a reasonable role model. A node means a
// device that implements IP. A router means a node that forwards IP
// packets not explicitly addressed to itself, and a host means a node
// that is not a router.
type ICMPFilter struct {
icmpv6Filter
}
// Accept accepts incoming ICMP packets including the type field value
// typ.
func (f *ICMPFilter) Accept(typ ICMPType) {
f.accept(typ)
}
// Block blocks incoming ICMP packets including the type field value
// typ.
func (f *ICMPFilter) Block(typ ICMPType) {
f.block(typ)
}
// SetAll sets the filter action to the filter.
func (f *ICMPFilter) SetAll(block bool) {
f.setAll(block)
}
// WillBlock reports whether the ICMP type will be blocked.
func (f *ICMPFilter) WillBlock(typ ICMPType) bool {
return f.willBlock(typ)
}
// Copyright 2013 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 ipv6
func (f *icmpv6Filter) accept(typ ICMPType) {
f.Data[typ>>5] &^= 1 << (uint32(typ) & 31)
}
func (f *icmpv6Filter) block(typ ICMPType) {
f.Data[typ>>5] |= 1 << (uint32(typ) & 31)
}
func (f *icmpv6Filter) setAll(block bool) {
for i := range f.Data {
if block {
f.Data[i] = 1<<32 - 1
} else {
f.Data[i] = 0
}
}
}
func (f *icmpv6Filter) willBlock(typ ICMPType) bool {
return f.Data[typ>>5]&(1<<(uint32(typ)&31)) != 0
}
// Copyright 2013 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 ipv6
import (
"net"
"golang.org/x/net/internal/socket"
)
// BUG(mikio): On Windows, the ControlMessage for ReadFrom and WriteTo
// methods of PacketConn is not implemented.
// A payloadHandler represents the IPv6 datagram payload handler.
type payloadHandler struct {
net.PacketConn
*socket.Conn
rawOpt
}
func (c *payloadHandler) ok() bool { return c != nil && c.PacketConn != nil && c.Conn != nil }
// Copyright 2013 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.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package ipv6
import (
"net"
"golang.org/x/net/internal/socket"
)
// ReadFrom reads a payload of the received IPv6 datagram, from the
// endpoint c, copying the payload into b. It returns the number of
// bytes copied into b, the control message cm and the source address
// src of the received datagram.
func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) {
if !c.ok() {
return 0, nil, nil, errInvalidConn
}
c.rawOpt.RLock()
m := socket.Message{
Buffers: [][]byte{b},
OOB: NewControlMessage(c.rawOpt.cflags),
}
c.rawOpt.RUnlock()
switch c.PacketConn.(type) {
case *net.UDPConn:
if err := c.RecvMsg(&m, 0); err != nil {
return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
}
case *net.IPConn:
if err := c.RecvMsg(&m, 0); err != nil {
return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
}
default:
return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: errInvalidConnType}
}
if m.NN > 0 {
cm = new(ControlMessage)
if err := cm.Parse(m.OOB[:m.NN]); err != nil {
return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
}
cm.Src = netAddrToIP16(m.Addr)
}
return m.N, cm, m.Addr, nil
}
// WriteTo writes a payload of the IPv6 datagram, to the destination
// address dst through the endpoint c, copying the payload from b. It
// returns the number of bytes written. The control message cm allows
// the IPv6 header fields and the datagram path to be specified. The
// cm may be nil if control of the outgoing datagram is not required.
func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) {
if !c.ok() {
return 0, errInvalidConn
}
m := socket.Message{
Buffers: [][]byte{b},
OOB: cm.Marshal(),
Addr: dst,
}
err = c.SendMsg(&m, 0)
if err != nil {
err = &net.OpError{Op: "write", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Addr: opAddr(dst), Err: err}
}
return m.N, err
}
// Copyright 2013 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.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows || zos
package ipv6
import (
"net"
"runtime"
"unsafe"
"golang.org/x/net/bpf"
"golang.org/x/net/internal/socket"
)
func (so *sockOpt) getMulticastInterface(c *socket.Conn) (*net.Interface, error) {
n, err := so.GetInt(c)
if err != nil {
return nil, err
}
return net.InterfaceByIndex(n)
}
func (so *sockOpt) setMulticastInterface(c *socket.Conn, ifi *net.Interface) error {
var n int
if ifi != nil {
n = ifi.Index
}
return so.SetInt(c, n)
}
func (so *sockOpt) getICMPFilter(c *socket.Conn) (*ICMPFilter, error) {
b := make([]byte, so.Len)
n, err := so.Get(c, b)
if err != nil {
return nil, err
}
if n != sizeofICMPv6Filter {
return nil, errNotImplemented
}
return (*ICMPFilter)(unsafe.Pointer(&b[0])), nil
}
func (so *sockOpt) setICMPFilter(c *socket.Conn, f *ICMPFilter) error {
b := (*[sizeofICMPv6Filter]byte)(unsafe.Pointer(f))[:sizeofICMPv6Filter]
return so.Set(c, b)
}
func (so *sockOpt) getMTUInfo(c *socket.Conn) (*net.Interface, int, error) {
b := make([]byte, so.Len)
n, err := so.Get(c, b)
if err != nil {
return nil, 0, err
}
if n != sizeofIPv6Mtuinfo {
return nil, 0, errNotImplemented
}
mi := (*ipv6Mtuinfo)(unsafe.Pointer(&b[0]))
if mi.Addr.Scope_id == 0 || runtime.GOOS == "aix" {
// AIX kernel might return a wrong address.
return nil, int(mi.Mtu), nil
}
ifi, err := net.InterfaceByIndex(int(mi.Addr.Scope_id))
if err != nil {
return nil, 0, err
}
return ifi, int(mi.Mtu), nil
}
func (so *sockOpt) setGroup(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
switch so.typ {
case ssoTypeIPMreq:
return so.setIPMreq(c, ifi, grp)
case ssoTypeGroupReq:
return so.setGroupReq(c, ifi, grp)
default:
return errNotImplemented
}
}
func (so *sockOpt) setSourceGroup(c *socket.Conn, ifi *net.Interface, grp, src net.IP) error {
return so.setGroupSourceReq(c, ifi, grp, src)
}
func (so *sockOpt) setBPF(c *socket.Conn, f []bpf.RawInstruction) error {
return so.setAttachFilter(c, f)
}
// Copyright 2013 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.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows
package ipv6
import (
"net"
"unsafe"
"golang.org/x/net/internal/socket"
)
func (so *sockOpt) setIPMreq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
var mreq ipv6Mreq
copy(mreq.Multiaddr[:], grp)
if ifi != nil {
mreq.setIfindex(ifi.Index)
}
b := (*[sizeofIPv6Mreq]byte)(unsafe.Pointer(&mreq))[:sizeofIPv6Mreq]
return so.Set(c, b)
}
// 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.
//go:build linux
package ipv6
import (
"unsafe"
"golang.org/x/net/bpf"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
func (so *sockOpt) setAttachFilter(c *socket.Conn, f []bpf.RawInstruction) error {
prog := unix.SockFprog{
Len: uint16(len(f)),
Filter: (*unix.SockFilter)(unsafe.Pointer(&f[0])),
}
b := (*[unix.SizeofSockFprog]byte)(unsafe.Pointer(&prog))[:unix.SizeofSockFprog]
return so.Set(c, b)
}
// Copyright 2013 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 ipv6
import (
"net"
"syscall"
"unsafe"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
var (
ctlOpts = [ctlMax]ctlOpt{
ctlTrafficClass: {unix.IPV6_TCLASS, 4, marshalTrafficClass, parseTrafficClass},
ctlHopLimit: {unix.IPV6_HOPLIMIT, 4, marshalHopLimit, parseHopLimit},
ctlPacketInfo: {unix.IPV6_PKTINFO, sizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo},
ctlPathMTU: {unix.IPV6_PATHMTU, sizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU},
}
sockOpts = map[int]*sockOpt{
ssoTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_TCLASS, Len: 4}},
ssoHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_UNICAST_HOPS, Len: 4}},
ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_IF, Len: 4}},
ssoMulticastHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_HOPS, Len: 4}},
ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_LOOP, Len: 4}},
ssoReceiveTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVTCLASS, Len: 4}},
ssoReceiveHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVHOPLIMIT, Len: 4}},
ssoReceivePacketInfo: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVPKTINFO, Len: 4}},
ssoReceivePathMTU: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVPATHMTU, Len: 4}},
ssoPathMTU: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_PATHMTU, Len: sizeofIPv6Mtuinfo}},
ssoChecksum: {Option: socket.Option{Level: iana.ProtocolReserved, Name: unix.IPV6_CHECKSUM, Len: 4}},
ssoICMPFilter: {Option: socket.Option{Level: iana.ProtocolIPv6ICMP, Name: unix.ICMPV6_FILTER, Len: sizeofICMPv6Filter}},
ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoJoinSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoLeaveSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoBlockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoUnblockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoAttachFilter: {Option: socket.Option{Level: unix.SOL_SOCKET, Name: unix.SO_ATTACH_FILTER, Len: unix.SizeofSockFprog}},
}
)
func (sa *sockaddrInet6) setSockaddr(ip net.IP, i int) {
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], ip)
sa.Scope_id = uint32(i)
}
func (pi *inet6Pktinfo) setIfindex(i int) {
pi.Ifindex = int32(i)
}
func (mreq *ipv6Mreq) setIfindex(i int) {
mreq.Ifindex = int32(i)
}
func (gr *groupReq) setGroup(grp net.IP) {
sa := (*sockaddrInet6)(unsafe.Pointer(&gr.Group))
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], grp)
}
func (gsr *groupSourceReq) setSourceGroup(grp, src net.IP) {
sa := (*sockaddrInet6)(unsafe.Pointer(&gsr.Group))
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], grp)
sa = (*sockaddrInet6)(unsafe.Pointer(&gsr.Source))
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], src)
}
// 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.
//go:build aix || darwin || freebsd || linux || solaris || zos
package ipv6
import (
"net"
"unsafe"
"golang.org/x/net/internal/socket"
)
var compatFreeBSD32 bool // 386 emulation on amd64
func (so *sockOpt) setGroupReq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
var gr groupReq
if ifi != nil {
gr.Interface = uint32(ifi.Index)
}
gr.setGroup(grp)
var b []byte
if compatFreeBSD32 {
var d [sizeofGroupReq + 4]byte
s := (*[sizeofGroupReq]byte)(unsafe.Pointer(&gr))
copy(d[:4], s[:4])
copy(d[8:], s[4:])
b = d[:]
} else {
b = (*[sizeofGroupReq]byte)(unsafe.Pointer(&gr))[:sizeofGroupReq]
}
return so.Set(c, b)
}
func (so *sockOpt) setGroupSourceReq(c *socket.Conn, ifi *net.Interface, grp, src net.IP) error {
var gsr groupSourceReq
if ifi != nil {
gsr.Interface = uint32(ifi.Index)
}
gsr.setSourceGroup(grp, src)
var b []byte
if compatFreeBSD32 {
var d [sizeofGroupSourceReq + 4]byte
s := (*[sizeofGroupSourceReq]byte)(unsafe.Pointer(&gsr))
copy(d[:4], s[:4])
copy(d[8:], s[4:])
b = d[:]
} else {
b = (*[sizeofGroupSourceReq]byte)(unsafe.Pointer(&gsr))[:sizeofGroupSourceReq]
}
return so.Set(c, b)
}
// 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.
package nettest
import (
"bytes"
"encoding/binary"
"io"
"math/rand"
"net"
"runtime"
"sync"
"testing"
"time"
)
// MakePipe creates a connection between two endpoints and returns the pair
// as c1 and c2, such that anything written to c1 is read by c2 and vice-versa.
// The stop function closes all resources, including c1, c2, and the underlying
// net.Listener (if there is one), and should not be nil.
type MakePipe func() (c1, c2 net.Conn, stop func(), err error)
// TestConn tests that a net.Conn implementation properly satisfies the interface.
// The tests should not produce any false positives, but may experience
// false negatives. Thus, some issues may only be detected when the test is
// run multiple times. For maximal effectiveness, run the tests under the
// race detector.
func TestConn(t *testing.T, mp MakePipe) {
t.Run("BasicIO", func(t *testing.T) { timeoutWrapper(t, mp, testBasicIO) })
t.Run("PingPong", func(t *testing.T) { timeoutWrapper(t, mp, testPingPong) })
t.Run("RacyRead", func(t *testing.T) { timeoutWrapper(t, mp, testRacyRead) })
t.Run("RacyWrite", func(t *testing.T) { timeoutWrapper(t, mp, testRacyWrite) })
t.Run("ReadTimeout", func(t *testing.T) { timeoutWrapper(t, mp, testReadTimeout) })
t.Run("WriteTimeout", func(t *testing.T) { timeoutWrapper(t, mp, testWriteTimeout) })
t.Run("PastTimeout", func(t *testing.T) { timeoutWrapper(t, mp, testPastTimeout) })
t.Run("PresentTimeout", func(t *testing.T) { timeoutWrapper(t, mp, testPresentTimeout) })
t.Run("FutureTimeout", func(t *testing.T) { timeoutWrapper(t, mp, testFutureTimeout) })
t.Run("CloseTimeout", func(t *testing.T) { timeoutWrapper(t, mp, testCloseTimeout) })
t.Run("ConcurrentMethods", func(t *testing.T) { timeoutWrapper(t, mp, testConcurrentMethods) })
}
type connTester func(t *testing.T, c1, c2 net.Conn)
func timeoutWrapper(t *testing.T, mp MakePipe, f connTester) {
t.Helper()
c1, c2, stop, err := mp()
if err != nil {
t.Fatalf("unable to make pipe: %v", err)
}
var once sync.Once
defer once.Do(func() { stop() })
timer := time.AfterFunc(time.Minute, func() {
once.Do(func() {
t.Error("test timed out; terminating pipe")
stop()
})
})
defer timer.Stop()
f(t, c1, c2)
}
// testBasicIO tests that the data sent on c1 is properly received on c2.
func testBasicIO(t *testing.T, c1, c2 net.Conn) {
want := make([]byte, 1<<20)
rand.New(rand.NewSource(0)).Read(want)
dataCh := make(chan []byte)
go func() {
rd := bytes.NewReader(want)
if err := chunkedCopy(c1, rd); err != nil {
t.Errorf("unexpected c1.Write error: %v", err)
}
if err := c1.Close(); err != nil {
t.Errorf("unexpected c1.Close error: %v", err)
}
}()
go func() {
wr := new(bytes.Buffer)
if err := chunkedCopy(wr, c2); err != nil {
t.Errorf("unexpected c2.Read error: %v", err)
}
if err := c2.Close(); err != nil {
t.Errorf("unexpected c2.Close error: %v", err)
}
dataCh <- wr.Bytes()
}()
if got := <-dataCh; !bytes.Equal(got, want) {
t.Error("transmitted data differs")
}
}
// testPingPong tests that the two endpoints can synchronously send data to
// each other in a typical request-response pattern.
func testPingPong(t *testing.T, c1, c2 net.Conn) {
var wg sync.WaitGroup
defer wg.Wait()
pingPonger := func(c net.Conn) {
defer wg.Done()
buf := make([]byte, 8)
var prev uint64
for {
if _, err := io.ReadFull(c, buf); err != nil {
if err == io.EOF {
break
}
t.Errorf("unexpected Read error: %v", err)
}
v := binary.LittleEndian.Uint64(buf)
binary.LittleEndian.PutUint64(buf, v+1)
if prev != 0 && prev+2 != v {
t.Errorf("mismatching value: got %d, want %d", v, prev+2)
}
prev = v
if v == 1000 {
break
}
if _, err := c.Write(buf); err != nil {
t.Errorf("unexpected Write error: %v", err)
break
}
}
if err := c.Close(); err != nil {
t.Errorf("unexpected Close error: %v", err)
}
}
wg.Add(2)
go pingPonger(c1)
go pingPonger(c2)
// Start off the chain reaction.
if _, err := c1.Write(make([]byte, 8)); err != nil {
t.Errorf("unexpected c1.Write error: %v", err)
}
}
// testRacyRead tests that it is safe to mutate the input Read buffer
// immediately after cancellation has occurred.
func testRacyRead(t *testing.T, c1, c2 net.Conn) {
go chunkedCopy(c2, rand.New(rand.NewSource(0)))
var wg sync.WaitGroup
defer wg.Wait()
c1.SetReadDeadline(time.Now().Add(time.Millisecond))
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
b1 := make([]byte, 1024)
b2 := make([]byte, 1024)
for j := 0; j < 100; j++ {
_, err := c1.Read(b1)
copy(b1, b2) // Mutate b1 to trigger potential race
if err != nil {
checkForTimeoutError(t, err)
c1.SetReadDeadline(time.Now().Add(time.Millisecond))
}
}
}()
}
}
// testRacyWrite tests that it is safe to mutate the input Write buffer
// immediately after cancellation has occurred.
func testRacyWrite(t *testing.T, c1, c2 net.Conn) {
go chunkedCopy(io.Discard, c2)
var wg sync.WaitGroup
defer wg.Wait()
c1.SetWriteDeadline(time.Now().Add(time.Millisecond))
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
b1 := make([]byte, 1024)
b2 := make([]byte, 1024)
for j := 0; j < 100; j++ {
_, err := c1.Write(b1)
copy(b1, b2) // Mutate b1 to trigger potential race
if err != nil {
checkForTimeoutError(t, err)
c1.SetWriteDeadline(time.Now().Add(time.Millisecond))
}
}
}()
}
}
// testReadTimeout tests that Read timeouts do not affect Write.
func testReadTimeout(t *testing.T, c1, c2 net.Conn) {
go chunkedCopy(io.Discard, c2)
c1.SetReadDeadline(aLongTimeAgo)
_, err := c1.Read(make([]byte, 1024))
checkForTimeoutError(t, err)
if _, err := c1.Write(make([]byte, 1024)); err != nil {
t.Errorf("unexpected Write error: %v", err)
}
}
// testWriteTimeout tests that Write timeouts do not affect Read.
func testWriteTimeout(t *testing.T, c1, c2 net.Conn) {
go chunkedCopy(c2, rand.New(rand.NewSource(0)))
c1.SetWriteDeadline(aLongTimeAgo)
_, err := c1.Write(make([]byte, 1024))
checkForTimeoutError(t, err)
if _, err := c1.Read(make([]byte, 1024)); err != nil {
t.Errorf("unexpected Read error: %v", err)
}
}
// testPastTimeout tests that a deadline set in the past immediately times out
// Read and Write requests.
func testPastTimeout(t *testing.T, c1, c2 net.Conn) {
go chunkedCopy(c2, c2)
testRoundtrip(t, c1)
c1.SetDeadline(aLongTimeAgo)
n, err := c1.Write(make([]byte, 1024))
if n != 0 {
t.Errorf("unexpected Write count: got %d, want 0", n)
}
checkForTimeoutError(t, err)
n, err = c1.Read(make([]byte, 1024))
if n != 0 {
t.Errorf("unexpected Read count: got %d, want 0", n)
}
checkForTimeoutError(t, err)
testRoundtrip(t, c1)
}
// testPresentTimeout tests that a past deadline set while there are pending
// Read and Write operations immediately times out those operations.
func testPresentTimeout(t *testing.T, c1, c2 net.Conn) {
var wg sync.WaitGroup
defer wg.Wait()
wg.Add(3)
deadlineSet := make(chan bool, 1)
go func() {
defer wg.Done()
time.Sleep(100 * time.Millisecond)
deadlineSet <- true
c1.SetReadDeadline(aLongTimeAgo)
c1.SetWriteDeadline(aLongTimeAgo)
}()
go func() {
defer wg.Done()
n, err := c1.Read(make([]byte, 1024))
if n != 0 {
t.Errorf("unexpected Read count: got %d, want 0", n)
}
checkForTimeoutError(t, err)
if len(deadlineSet) == 0 {
t.Error("Read timed out before deadline is set")
}
}()
go func() {
defer wg.Done()
var err error
for err == nil {
_, err = c1.Write(make([]byte, 1024))
}
checkForTimeoutError(t, err)
if len(deadlineSet) == 0 {
t.Error("Write timed out before deadline is set")
}
}()
}
// testFutureTimeout tests that a future deadline will eventually time out
// Read and Write operations.
func testFutureTimeout(t *testing.T, c1, c2 net.Conn) {
var wg sync.WaitGroup
wg.Add(2)
c1.SetDeadline(time.Now().Add(100 * time.Millisecond))
go func() {
defer wg.Done()
_, err := c1.Read(make([]byte, 1024))
checkForTimeoutError(t, err)
}()
go func() {
defer wg.Done()
var err error
for err == nil {
_, err = c1.Write(make([]byte, 1024))
}
checkForTimeoutError(t, err)
}()
wg.Wait()
go chunkedCopy(c2, c2)
resyncConn(t, c1)
testRoundtrip(t, c1)
}
// testCloseTimeout tests that calling Close immediately times out pending
// Read and Write operations.
func testCloseTimeout(t *testing.T, c1, c2 net.Conn) {
go chunkedCopy(c2, c2)
var wg sync.WaitGroup
defer wg.Wait()
wg.Add(3)
// Test for cancellation upon connection closure.
c1.SetDeadline(neverTimeout)
go func() {
defer wg.Done()
time.Sleep(100 * time.Millisecond)
c1.Close()
}()
go func() {
defer wg.Done()
var err error
buf := make([]byte, 1024)
for err == nil {
_, err = c1.Read(buf)
}
}()
go func() {
defer wg.Done()
var err error
buf := make([]byte, 1024)
for err == nil {
_, err = c1.Write(buf)
}
}()
}
// testConcurrentMethods tests that the methods of net.Conn can safely
// be called concurrently.
func testConcurrentMethods(t *testing.T, c1, c2 net.Conn) {
if runtime.GOOS == "plan9" {
t.Skip("skipping on plan9; see https://golang.org/issue/20489")
}
go chunkedCopy(c2, c2)
// The results of the calls may be nonsensical, but this should
// not trigger a race detector warning.
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(7)
go func() {
defer wg.Done()
c1.Read(make([]byte, 1024))
}()
go func() {
defer wg.Done()
c1.Write(make([]byte, 1024))
}()
go func() {
defer wg.Done()
c1.SetDeadline(time.Now().Add(10 * time.Millisecond))
}()
go func() {
defer wg.Done()
c1.SetReadDeadline(aLongTimeAgo)
}()
go func() {
defer wg.Done()
c1.SetWriteDeadline(aLongTimeAgo)
}()
go func() {
defer wg.Done()
c1.LocalAddr()
}()
go func() {
defer wg.Done()
c1.RemoteAddr()
}()
}
wg.Wait() // At worst, the deadline is set 10ms into the future
resyncConn(t, c1)
testRoundtrip(t, c1)
}
// checkForTimeoutError checks that the error satisfies the Error interface
// and that Timeout returns true.
func checkForTimeoutError(t *testing.T, err error) {
t.Helper()
if nerr, ok := err.(net.Error); ok {
if !nerr.Timeout() {
if runtime.GOOS == "windows" && runtime.GOARCH == "arm64" && t.Name() == "TestTestConn/TCP/RacyRead" {
t.Logf("ignoring known failure mode on windows/arm64; see https://go.dev/issue/52893")
} else {
t.Errorf("got error: %v, want err.Timeout() = true", nerr)
}
}
} else {
t.Errorf("got %T: %v, want net.Error", err, err)
}
}
// testRoundtrip writes something into c and reads it back.
// It assumes that everything written into c is echoed back to itself.
func testRoundtrip(t *testing.T, c net.Conn) {
t.Helper()
if err := c.SetDeadline(neverTimeout); err != nil {
t.Errorf("roundtrip SetDeadline error: %v", err)
}
const s = "Hello, world!"
buf := []byte(s)
if _, err := c.Write(buf); err != nil {
t.Errorf("roundtrip Write error: %v", err)
}
if _, err := io.ReadFull(c, buf); err != nil {
t.Errorf("roundtrip Read error: %v", err)
}
if string(buf) != s {
t.Errorf("roundtrip data mismatch: got %q, want %q", buf, s)
}
}
// resyncConn resynchronizes the connection into a sane state.
// It assumes that everything written into c is echoed back to itself.
// It assumes that 0xff is not currently on the wire or in the read buffer.
func resyncConn(t *testing.T, c net.Conn) {
t.Helper()
c.SetDeadline(neverTimeout)
errCh := make(chan error)
go func() {
_, err := c.Write([]byte{0xff})
errCh <- err
}()
buf := make([]byte, 1024)
for {
n, err := c.Read(buf)
if n > 0 && bytes.IndexByte(buf[:n], 0xff) == n-1 {
break
}
if err != nil {
t.Errorf("unexpected Read error: %v", err)
break
}
}
if err := <-errCh; err != nil {
t.Errorf("unexpected Write error: %v", err)
}
}
// chunkedCopy copies from r to w in fixed-width chunks to avoid
// causing a Write that exceeds the maximum packet size for packet-based
// connections like "unixpacket".
// We assume that the maximum packet size is at least 1024.
func chunkedCopy(w io.Writer, r io.Reader) error {
b := make([]byte, 1024)
_, err := io.CopyBuffer(struct{ io.Writer }{w}, struct{ io.Reader }{r}, b)
return err
}
// Copyright 2019 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 nettest provides utilities for network testing.
package nettest
import (
"errors"
"fmt"
"net"
"os"
"os/exec"
"runtime"
"strconv"
"strings"
"sync"
"time"
)
var (
stackOnce sync.Once
ipv4Enabled bool
canListenTCP4OnLoopback bool
ipv6Enabled bool
canListenTCP6OnLoopback bool
unStrmDgramEnabled bool
rawSocketSess bool
aLongTimeAgo = time.Unix(233431200, 0)
neverTimeout = time.Time{}
errNoAvailableInterface = errors.New("no available interface")
errNoAvailableAddress = errors.New("no available address")
)
func probeStack() {
if _, err := RoutedInterface("ip4", net.FlagUp); err == nil {
ipv4Enabled = true
}
if ln, err := net.Listen("tcp4", "127.0.0.1:0"); err == nil {
ln.Close()
canListenTCP4OnLoopback = true
}
if _, err := RoutedInterface("ip6", net.FlagUp); err == nil {
ipv6Enabled = true
}
if ln, err := net.Listen("tcp6", "[::1]:0"); err == nil {
ln.Close()
canListenTCP6OnLoopback = true
}
rawSocketSess = supportsRawSocket()
switch runtime.GOOS {
case "aix":
// Unix network isn't properly working on AIX 7.2 with
// Technical Level < 2.
out, _ := exec.Command("oslevel", "-s").Output()
if len(out) >= len("7200-XX-ZZ-YYMM") { // AIX 7.2, Tech Level XX, Service Pack ZZ, date YYMM
ver := string(out[:4])
tl, _ := strconv.Atoi(string(out[5:7]))
unStrmDgramEnabled = ver > "7200" || (ver == "7200" && tl >= 2)
}
default:
unStrmDgramEnabled = true
}
}
func unixStrmDgramEnabled() bool {
stackOnce.Do(probeStack)
return unStrmDgramEnabled
}
// SupportsIPv4 reports whether the platform supports IPv4 networking
// functionality.
func SupportsIPv4() bool {
stackOnce.Do(probeStack)
return ipv4Enabled
}
// SupportsIPv6 reports whether the platform supports IPv6 networking
// functionality.
func SupportsIPv6() bool {
stackOnce.Do(probeStack)
return ipv6Enabled
}
// SupportsRawSocket reports whether the current session is available
// to use raw sockets.
func SupportsRawSocket() bool {
stackOnce.Do(probeStack)
return rawSocketSess
}
// TestableNetwork reports whether network is testable on the current
// platform configuration.
//
// See func Dial of the standard library for the supported networks.
func TestableNetwork(network string) bool {
ss := strings.Split(network, ":")
switch ss[0] {
case "ip+nopriv":
// This is an internal network name for testing on the
// package net of the standard library.
switch runtime.GOOS {
case "android", "fuchsia", "hurd", "ios", "js", "nacl", "plan9", "wasip1", "windows":
return false
}
case "ip", "ip4", "ip6":
switch runtime.GOOS {
case "fuchsia", "hurd", "js", "nacl", "plan9", "wasip1":
return false
default:
if os.Getuid() != 0 {
return false
}
}
case "unix", "unixgram":
switch runtime.GOOS {
case "android", "fuchsia", "hurd", "ios", "js", "nacl", "plan9", "wasip1", "windows":
return false
case "aix":
return unixStrmDgramEnabled()
}
case "unixpacket":
switch runtime.GOOS {
case "aix", "android", "fuchsia", "hurd", "darwin", "ios", "js", "nacl", "plan9", "wasip1", "windows", "zos":
return false
}
}
switch ss[0] {
case "tcp4", "udp4", "ip4":
return SupportsIPv4()
case "tcp6", "udp6", "ip6":
return SupportsIPv6()
}
return true
}
// TestableAddress reports whether address of network is testable on
// the current platform configuration.
func TestableAddress(network, address string) bool {
switch ss := strings.Split(network, ":"); ss[0] {
case "unix", "unixgram", "unixpacket":
// Abstract unix domain sockets, a Linux-ism.
if address[0] == '@' && runtime.GOOS != "linux" {
return false
}
}
return true
}
// NewLocalListener returns a listener which listens to a loopback IP
// address or local file system path.
//
// The provided network must be "tcp", "tcp4", "tcp6", "unix" or
// "unixpacket".
func NewLocalListener(network string) (net.Listener, error) {
stackOnce.Do(probeStack)
switch network {
case "tcp":
if canListenTCP4OnLoopback {
if ln, err := net.Listen("tcp4", "127.0.0.1:0"); err == nil {
return ln, nil
}
}
if canListenTCP6OnLoopback {
return net.Listen("tcp6", "[::1]:0")
}
case "tcp4":
if canListenTCP4OnLoopback {
return net.Listen("tcp4", "127.0.0.1:0")
}
case "tcp6":
if canListenTCP6OnLoopback {
return net.Listen("tcp6", "[::1]:0")
}
case "unix", "unixpacket":
path, err := LocalPath()
if err != nil {
return nil, err
}
return net.Listen(network, path)
}
return nil, fmt.Errorf("%s is not supported on %s/%s", network, runtime.GOOS, runtime.GOARCH)
}
// NewLocalPacketListener returns a packet listener which listens to a
// loopback IP address or local file system path.
//
// The provided network must be "udp", "udp4", "udp6" or "unixgram".
func NewLocalPacketListener(network string) (net.PacketConn, error) {
stackOnce.Do(probeStack)
switch network {
case "udp":
if canListenTCP4OnLoopback {
if c, err := net.ListenPacket("udp4", "127.0.0.1:0"); err == nil {
return c, nil
}
}
if canListenTCP6OnLoopback {
return net.ListenPacket("udp6", "[::1]:0")
}
case "udp4":
if canListenTCP4OnLoopback {
return net.ListenPacket("udp4", "127.0.0.1:0")
}
case "udp6":
if canListenTCP6OnLoopback {
return net.ListenPacket("udp6", "[::1]:0")
}
case "unixgram":
path, err := LocalPath()
if err != nil {
return nil, err
}
return net.ListenPacket(network, path)
}
return nil, fmt.Errorf("%s is not supported on %s/%s", network, runtime.GOOS, runtime.GOARCH)
}
// LocalPath returns a local path that can be used for Unix-domain
// protocol testing.
func LocalPath() (string, error) {
dir := ""
if runtime.GOOS == "darwin" {
dir = "/tmp"
}
f, err := os.CreateTemp(dir, "go-nettest")
if err != nil {
return "", err
}
path := f.Name()
f.Close()
os.Remove(path)
return path, nil
}
// MulticastSource returns a unicast IP address on ifi when ifi is an
// IP multicast-capable network interface.
//
// The provided network must be "ip", "ip4" or "ip6".
func MulticastSource(network string, ifi *net.Interface) (net.IP, error) {
switch network {
case "ip", "ip4", "ip6":
default:
return nil, errNoAvailableAddress
}
if ifi == nil || ifi.Flags&net.FlagUp == 0 || ifi.Flags&net.FlagMulticast == 0 {
return nil, errNoAvailableAddress
}
ip, ok := hasRoutableIP(network, ifi)
if !ok {
return nil, errNoAvailableAddress
}
return ip, nil
}
// LoopbackInterface returns an available logical network interface
// for loopback test.
func LoopbackInterface() (*net.Interface, error) {
ift, err := net.Interfaces()
if err != nil {
return nil, errNoAvailableInterface
}
for _, ifi := range ift {
if ifi.Flags&net.FlagLoopback != 0 && ifi.Flags&net.FlagUp != 0 {
return &ifi, nil
}
}
return nil, errNoAvailableInterface
}
// RoutedInterface returns a network interface that can route IP
// traffic and satisfies flags.
//
// The provided network must be "ip", "ip4" or "ip6".
func RoutedInterface(network string, flags net.Flags) (*net.Interface, error) {
switch network {
case "ip", "ip4", "ip6":
default:
return nil, errNoAvailableInterface
}
ift, err := net.Interfaces()
if err != nil {
return nil, errNoAvailableInterface
}
for _, ifi := range ift {
if ifi.Flags&flags != flags {
continue
}
if _, ok := hasRoutableIP(network, &ifi); !ok {
continue
}
return &ifi, nil
}
return nil, errNoAvailableInterface
}
func hasRoutableIP(network string, ifi *net.Interface) (net.IP, bool) {
ifat, err := ifi.Addrs()
if err != nil {
return nil, false
}
for _, ifa := range ifat {
switch ifa := ifa.(type) {
case *net.IPAddr:
if ip, ok := routableIP(network, ifa.IP); ok {
return ip, true
}
case *net.IPNet:
if ip, ok := routableIP(network, ifa.IP); ok {
return ip, true
}
}
}
return nil, false
}
func routableIP(network string, ip net.IP) (net.IP, bool) {
if !ip.IsLoopback() && !ip.IsLinkLocalUnicast() && !ip.IsGlobalUnicast() {
return nil, false
}
switch network {
case "ip4":
if ip := ip.To4(); ip != nil {
return ip, true
}
case "ip6":
if ip.IsLoopback() { // addressing scope of the loopback address depends on each implementation
return nil, false
}
if ip := ip.To16(); ip != nil && ip.To4() == nil {
return ip, true
}
default:
if ip := ip.To4(); ip != nil {
return ip, true
}
if ip := ip.To16(); ip != nil {
return ip, true
}
}
return nil, false
}
// Copyright 2019 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.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package nettest
import "syscall"
func supportsRawSocket() bool {
for _, af := range []int{syscall.AF_INET, syscall.AF_INET6} {
s, err := syscall.Socket(af, syscall.SOCK_RAW, 0)
if err != nil {
continue
}
syscall.Close(s)
return true
}
return false
}
// Copyright 2019 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 proxy
import (
"context"
"net"
)
// A ContextDialer dials using a context.
type ContextDialer interface {
DialContext(ctx context.Context, network, address string) (net.Conn, error)
}
// Dial works like DialContext on net.Dialer but using a dialer returned by FromEnvironment.
//
// The passed ctx is only used for returning the Conn, not the lifetime of the Conn.
//
// Custom dialers (registered via RegisterDialerType) that do not implement ContextDialer
// can leak a goroutine for as long as it takes the underlying Dialer implementation to timeout.
//
// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed.
func Dial(ctx context.Context, network, address string) (net.Conn, error) {
d := FromEnvironment()
if xd, ok := d.(ContextDialer); ok {
return xd.DialContext(ctx, network, address)
}
return dialContext(ctx, d, network, address)
}
// WARNING: this can leak a goroutine for as long as the underlying Dialer implementation takes to timeout
// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed.
func dialContext(ctx context.Context, d Dialer, network, address string) (net.Conn, error) {
var (
conn net.Conn
done = make(chan struct{}, 1)
err error
)
go func() {
conn, err = d.Dial(network, address)
close(done)
if conn != nil && ctx.Err() != nil {
conn.Close()
}
}()
select {
case <-ctx.Done():
err = ctx.Err()
case <-done:
}
return conn, err
}
// Copyright 2011 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 proxy
import (
"context"
"net"
)
type direct struct{}
// Direct implements Dialer by making network connections directly using net.Dial or net.DialContext.
var Direct = direct{}
var (
_ Dialer = Direct
_ ContextDialer = Direct
)
// Dial directly invokes net.Dial with the supplied parameters.
func (direct) Dial(network, addr string) (net.Conn, error) {
return net.Dial(network, addr)
}
// DialContext instantiates a net.Dialer and invokes its DialContext receiver with the supplied parameters.
func (direct) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
var d net.Dialer
return d.DialContext(ctx, network, addr)
}
// Copyright 2011 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 proxy
import (
"context"
"net"
"net/netip"
"strings"
)
// A PerHost directs connections to a default Dialer unless the host name
// requested matches one of a number of exceptions.
type PerHost struct {
def, bypass Dialer
bypassNetworks []*net.IPNet
bypassIPs []net.IP
bypassZones []string
bypassHosts []string
}
// NewPerHost returns a PerHost Dialer that directs connections to either
// defaultDialer or bypass, depending on whether the connection matches one of
// the configured rules.
func NewPerHost(defaultDialer, bypass Dialer) *PerHost {
return &PerHost{
def: defaultDialer,
bypass: bypass,
}
}
// Dial connects to the address addr on the given network through either
// defaultDialer or bypass.
func (p *PerHost) Dial(network, addr string) (c net.Conn, err error) {
host, _, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
}
return p.dialerForRequest(host).Dial(network, addr)
}
// DialContext connects to the address addr on the given network through either
// defaultDialer or bypass.
func (p *PerHost) DialContext(ctx context.Context, network, addr string) (c net.Conn, err error) {
host, _, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
}
d := p.dialerForRequest(host)
if x, ok := d.(ContextDialer); ok {
return x.DialContext(ctx, network, addr)
}
return dialContext(ctx, d, network, addr)
}
func (p *PerHost) dialerForRequest(host string) Dialer {
if nip, err := netip.ParseAddr(host); err == nil {
ip := net.IP(nip.AsSlice())
for _, net := range p.bypassNetworks {
if net.Contains(ip) {
return p.bypass
}
}
for _, bypassIP := range p.bypassIPs {
if bypassIP.Equal(ip) {
return p.bypass
}
}
return p.def
}
for _, zone := range p.bypassZones {
if strings.HasSuffix(host, zone) {
return p.bypass
}
if host == zone[1:] {
// For a zone ".example.com", we match "example.com"
// too.
return p.bypass
}
}
for _, bypassHost := range p.bypassHosts {
if bypassHost == host {
return p.bypass
}
}
return p.def
}
// AddFromString parses a string that contains comma-separated values
// specifying hosts that should use the bypass proxy. Each value is either an
// IP address, a CIDR range, a zone (*.example.com) or a host name
// (localhost). A best effort is made to parse the string and errors are
// ignored.
func (p *PerHost) AddFromString(s string) {
hosts := strings.Split(s, ",")
for _, host := range hosts {
host = strings.TrimSpace(host)
if len(host) == 0 {
continue
}
if strings.Contains(host, "/") {
// We assume that it's a CIDR address like 127.0.0.0/8
if _, net, err := net.ParseCIDR(host); err == nil {
p.AddNetwork(net)
}
continue
}
if nip, err := netip.ParseAddr(host); err == nil {
p.AddIP(net.IP(nip.AsSlice()))
continue
}
if strings.HasPrefix(host, "*.") {
p.AddZone(host[1:])
continue
}
p.AddHost(host)
}
}
// AddIP specifies an IP address that will use the bypass proxy. Note that
// this will only take effect if a literal IP address is dialed. A connection
// to a named host will never match an IP.
func (p *PerHost) AddIP(ip net.IP) {
p.bypassIPs = append(p.bypassIPs, ip)
}
// AddNetwork specifies an IP range that will use the bypass proxy. Note that
// this will only take effect if a literal IP address is dialed. A connection
// to a named host will never match.
func (p *PerHost) AddNetwork(net *net.IPNet) {
p.bypassNetworks = append(p.bypassNetworks, net)
}
// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of
// "example.com" matches "example.com" and all of its subdomains.
func (p *PerHost) AddZone(zone string) {
zone = strings.TrimSuffix(zone, ".")
if !strings.HasPrefix(zone, ".") {
zone = "." + zone
}
p.bypassZones = append(p.bypassZones, zone)
}
// AddHost specifies a host name that will use the bypass proxy.
func (p *PerHost) AddHost(host string) {
host = strings.TrimSuffix(host, ".")
p.bypassHosts = append(p.bypassHosts, host)
}
// Copyright 2011 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 proxy provides support for a variety of protocols to proxy network
// data.
package proxy // import "golang.org/x/net/proxy"
import (
"errors"
"net"
"net/url"
"os"
"sync"
)
// A Dialer is a means to establish a connection.
// Custom dialers should also implement ContextDialer.
type Dialer interface {
// Dial connects to the given address via the proxy.
Dial(network, addr string) (c net.Conn, err error)
}
// Auth contains authentication parameters that specific Dialers may require.
type Auth struct {
User, Password string
}
// FromEnvironment returns the dialer specified by the proxy-related
// variables in the environment and makes underlying connections
// directly.
func FromEnvironment() Dialer {
return FromEnvironmentUsing(Direct)
}
// FromEnvironmentUsing returns the dialer specify by the proxy-related
// variables in the environment and makes underlying connections
// using the provided forwarding Dialer (for instance, a *net.Dialer
// with desired configuration).
func FromEnvironmentUsing(forward Dialer) Dialer {
allProxy := allProxyEnv.Get()
if len(allProxy) == 0 {
return forward
}
proxyURL, err := url.Parse(allProxy)
if err != nil {
return forward
}
proxy, err := FromURL(proxyURL, forward)
if err != nil {
return forward
}
noProxy := noProxyEnv.Get()
if len(noProxy) == 0 {
return proxy
}
perHost := NewPerHost(proxy, forward)
perHost.AddFromString(noProxy)
return perHost
}
// proxySchemes is a map from URL schemes to a function that creates a Dialer
// from a URL with such a scheme.
var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error)
// RegisterDialerType takes a URL scheme and a function to generate Dialers from
// a URL with that scheme and a forwarding Dialer. Registered schemes are used
// by FromURL.
func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) {
if proxySchemes == nil {
proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error))
}
proxySchemes[scheme] = f
}
// FromURL returns a Dialer given a URL specification and an underlying
// Dialer for it to make network requests.
func FromURL(u *url.URL, forward Dialer) (Dialer, error) {
var auth *Auth
if u.User != nil {
auth = new(Auth)
auth.User = u.User.Username()
if p, ok := u.User.Password(); ok {
auth.Password = p
}
}
switch u.Scheme {
case "socks5", "socks5h":
addr := u.Hostname()
port := u.Port()
if port == "" {
port = "1080"
}
return SOCKS5("tcp", net.JoinHostPort(addr, port), auth, forward)
}
// If the scheme doesn't match any of the built-in schemes, see if it
// was registered by another package.
if proxySchemes != nil {
if f, ok := proxySchemes[u.Scheme]; ok {
return f(u, forward)
}
}
return nil, errors.New("proxy: unknown scheme: " + u.Scheme)
}
var (
allProxyEnv = &envOnce{
names: []string{"ALL_PROXY", "all_proxy"},
}
noProxyEnv = &envOnce{
names: []string{"NO_PROXY", "no_proxy"},
}
)
// envOnce looks up an environment variable (optionally by multiple
// names) once. It mitigates expensive lookups on some platforms
// (e.g. Windows).
// (Borrowed from net/http/transport.go)
type envOnce struct {
names []string
once sync.Once
val string
}
func (e *envOnce) Get() string {
e.once.Do(e.init)
return e.val
}
func (e *envOnce) init() {
for _, n := range e.names {
e.val = os.Getenv(n)
if e.val != "" {
return
}
}
}
// reset is used by tests
func (e *envOnce) reset() {
e.once = sync.Once{}
e.val = ""
}
// Copyright 2011 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 proxy
import (
"context"
"net"
"golang.org/x/net/internal/socks"
)
// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given
// address with an optional username and password.
// See RFC 1928 and RFC 1929.
func SOCKS5(network, address string, auth *Auth, forward Dialer) (Dialer, error) {
d := socks.NewDialer(network, address)
if forward != nil {
if f, ok := forward.(ContextDialer); ok {
d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) {
return f.DialContext(ctx, network, address)
}
} else {
d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) {
return dialContext(ctx, forward, network, address)
}
}
}
if auth != nil {
up := socks.UsernamePassword{
Username: auth.User,
Password: auth.Password,
}
d.AuthMethods = []socks.AuthMethod{
socks.AuthMethodNotRequired,
socks.AuthMethodUsernamePassword,
}
d.Authenticate = up.Authenticate
}
return d, nil
}
// 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.
//go:generate go run gen.go
// Package publicsuffix provides a public suffix list based on data from
// https://publicsuffix.org/
//
// A public suffix is one under which Internet users can directly register
// names. It is related to, but different from, a TLD (top level domain).
//
// "com" is a TLD (top level domain). Top level means it has no dots.
//
// "com" is also a public suffix. Amazon and Google have registered different
// siblings under that domain: "amazon.com" and "google.com".
//
// "au" is another TLD, again because it has no dots. But it's not "amazon.au".
// Instead, it's "amazon.com.au".
//
// "com.au" isn't an actual TLD, because it's not at the top level (it has
// dots). But it is an eTLD (effective TLD), because that's the branching point
// for domain name registrars.
//
// Another name for "an eTLD" is "a public suffix". Often, what's more of
// interest is the eTLD+1, or one more label than the public suffix. For
// example, browsers partition read/write access to HTTP cookies according to
// the eTLD+1. Web pages served from "amazon.com.au" can't read cookies from
// "google.com.au", but web pages served from "maps.google.com" can share
// cookies from "www.google.com", so you don't have to sign into Google Maps
// separately from signing into Google Web Search. Note that all four of those
// domains have 3 labels and 2 dots. The first two domains are each an eTLD+1,
// the last two are not (but share the same eTLD+1: "google.com").
//
// All of these domains have the same eTLD+1:
// - "www.books.amazon.co.uk"
// - "books.amazon.co.uk"
// - "amazon.co.uk"
//
// Specifically, the eTLD+1 is "amazon.co.uk", because the eTLD is "co.uk".
//
// There is no closed form algorithm to calculate the eTLD of a domain.
// Instead, the calculation is data driven. This package provides a
// pre-compiled snapshot of Mozilla's PSL (Public Suffix List) data at
// https://publicsuffix.org/
package publicsuffix // import "golang.org/x/net/publicsuffix"
// TODO: specify case sensitivity and leading/trailing dot behavior for
// func PublicSuffix and func EffectiveTLDPlusOne.
import (
"fmt"
"net/http/cookiejar"
"net/netip"
"strings"
)
// List implements the cookiejar.PublicSuffixList interface by calling the
// PublicSuffix function.
var List cookiejar.PublicSuffixList = list{}
type list struct{}
func (list) PublicSuffix(domain string) string {
ps, _ := PublicSuffix(domain)
return ps
}
func (list) String() string {
return version
}
// PublicSuffix returns the public suffix of the domain using a copy of the
// publicsuffix.org database compiled into the library.
//
// icann is whether the public suffix is managed by the Internet Corporation
// for Assigned Names and Numbers. If not, the public suffix is either a
// privately managed domain (and in practice, not a top level domain) or an
// unmanaged top level domain (and not explicitly mentioned in the
// publicsuffix.org list). For example, "foo.org" and "foo.co.uk" are ICANN
// domains, "foo.dyndns.org" is a private domain and
// "cromulent" is an unmanaged top level domain.
//
// Use cases for distinguishing ICANN domains like "foo.com" from private
// domains like "foo.appspot.com" can be found at
// https://wiki.mozilla.org/Public_Suffix_List/Use_Cases
func PublicSuffix(domain string) (publicSuffix string, icann bool) {
if _, err := netip.ParseAddr(domain); err == nil {
return domain, false
}
lo, hi := uint32(0), uint32(numTLD)
s, suffix, icannNode, wildcard := domain, len(domain), false, false
loop:
for {
dot := strings.LastIndexByte(s, '.')
if wildcard {
icann = icannNode
suffix = 1 + dot
}
if lo == hi {
break
}
f := find(s[1+dot:], lo, hi)
if f == notFound {
break
}
u := uint32(nodes.get(f) >> (nodesBitsTextOffset + nodesBitsTextLength))
icannNode = u&(1<<nodesBitsICANN-1) != 0
u >>= nodesBitsICANN
u = children.get(u & (1<<nodesBitsChildren - 1))
lo = u & (1<<childrenBitsLo - 1)
u >>= childrenBitsLo
hi = u & (1<<childrenBitsHi - 1)
u >>= childrenBitsHi
switch u & (1<<childrenBitsNodeType - 1) {
case nodeTypeNormal:
suffix = 1 + dot
case nodeTypeException:
suffix = 1 + len(s)
break loop
}
u >>= childrenBitsNodeType
wildcard = u&(1<<childrenBitsWildcard-1) != 0
if !wildcard {
icann = icannNode
}
if dot == -1 {
break
}
s = s[:dot]
}
if suffix == len(domain) {
// If no rules match, the prevailing rule is "*".
return domain[1+strings.LastIndexByte(domain, '.'):], icann
}
return domain[suffix:], icann
}
const notFound uint32 = 1<<32 - 1
// find returns the index of the node in the range [lo, hi) whose label equals
// label, or notFound if there is no such node. The range is assumed to be in
// strictly increasing node label order.
func find(label string, lo, hi uint32) uint32 {
for lo < hi {
mid := lo + (hi-lo)/2
s := nodeLabel(mid)
if s < label {
lo = mid + 1
} else if s == label {
return mid
} else {
hi = mid
}
}
return notFound
}
// nodeLabel returns the label for the i'th node.
func nodeLabel(i uint32) string {
x := nodes.get(i)
length := x & (1<<nodesBitsTextLength - 1)
x >>= nodesBitsTextLength
offset := x & (1<<nodesBitsTextOffset - 1)
return text[offset : offset+length]
}
// EffectiveTLDPlusOne returns the effective top level domain plus one more
// label. For example, the eTLD+1 for "foo.bar.golang.org" is "golang.org".
func EffectiveTLDPlusOne(domain string) (string, error) {
if strings.HasPrefix(domain, ".") || strings.HasSuffix(domain, ".") || strings.Contains(domain, "..") {
return "", fmt.Errorf("publicsuffix: empty label in domain %q", domain)
}
suffix, _ := PublicSuffix(domain)
if len(domain) <= len(suffix) {
return "", fmt.Errorf("publicsuffix: cannot derive eTLD+1 for domain %q", domain)
}
i := len(domain) - len(suffix) - 1
if domain[i] != '.' {
return "", fmt.Errorf("publicsuffix: invalid public suffix %q for domain %q", suffix, domain)
}
return domain[1+strings.LastIndexByte(domain[:i], '.'):], nil
}
type uint32String string
func (u uint32String) get(i uint32) uint32 {
off := i * 4
u = u[off:] // help the compiler reduce bounds checks
return uint32(u[3]) |
uint32(u[2])<<8 |
uint32(u[1])<<16 |
uint32(u[0])<<24
}
type uint40String string
func (u uint40String) get(i uint32) uint64 {
off := uint64(i * (nodesBits / 8))
u = u[off:] // help the compiler reduce bounds checks
return uint64(u[4]) |
uint64(u[3])<<8 |
uint64(u[2])<<16 |
uint64(u[1])<<24 |
uint64(u[0])<<32
}
// Copyright 2023 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 quic
import (
"math"
"time"
)
// An unscaledAckDelay is an ACK Delay field value from an ACK packet,
// without the ack_delay_exponent scaling applied.
type unscaledAckDelay int64
func unscaledAckDelayFromDuration(d time.Duration, ackDelayExponent uint8) unscaledAckDelay {
return unscaledAckDelay(d.Microseconds() >> ackDelayExponent)
}
func (d unscaledAckDelay) Duration(ackDelayExponent uint8) time.Duration {
if int64(d) > (math.MaxInt64>>ackDelayExponent)/int64(time.Microsecond) {
// If scaling the delay would overflow, ignore the delay.
return 0
}
return time.Duration(d<<ackDelayExponent) * time.Microsecond
}
// Copyright 2023 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 quic
import (
"time"
)
// ackState tracks packets received from a peer within a number space.
// It handles packet deduplication (don't process the same packet twice) and
// determines the timing and content of ACK frames.
type ackState struct {
seen rangeset[packetNumber]
// The time at which we must send an ACK frame, even if we have no other data to send.
nextAck time.Time
// The time we received the largest-numbered packet in seen.
maxRecvTime time.Time
// The largest-numbered ack-eliciting packet in seen.
maxAckEliciting packetNumber
// The number of ack-eliciting packets in seen that we have not yet acknowledged.
unackedAckEliciting int
// Total ECN counters for this packet number space.
ecn ecnCounts
}
type ecnCounts struct {
t0 int
t1 int
ce int
}
// shouldProcess reports whether a packet should be handled or discarded.
func (acks *ackState) shouldProcess(num packetNumber) bool {
if packetNumber(acks.seen.min()) > num {
// We've discarded the state for this range of packet numbers.
// Discard the packet rather than potentially processing a duplicate.
// https://www.rfc-editor.org/rfc/rfc9000.html#section-13.2.3-5
return false
}
if acks.seen.contains(num) {
// Discard duplicate packets.
return false
}
return true
}
// receive records receipt of a packet.
func (acks *ackState) receive(now time.Time, space numberSpace, num packetNumber, ackEliciting bool, ecn ecnBits) {
if ackEliciting {
acks.unackedAckEliciting++
if acks.mustAckImmediately(space, num, ecn) {
acks.nextAck = now
} else if acks.nextAck.IsZero() {
// This packet does not need to be acknowledged immediately,
// but the ack must not be intentionally delayed by more than
// the max_ack_delay transport parameter we sent to the peer.
//
// We always delay acks by the maximum allowed, less the timer
// granularity. ("[max_ack_delay] SHOULD include the receiver's
// expected delays in alarms firing.")
//
// https://www.rfc-editor.org/rfc/rfc9000#section-18.2-4.28.1
acks.nextAck = now.Add(maxAckDelay - timerGranularity)
}
if num > acks.maxAckEliciting {
acks.maxAckEliciting = num
}
}
acks.seen.add(num, num+1)
if num == acks.seen.max() {
acks.maxRecvTime = now
}
switch ecn {
case ecnECT0:
acks.ecn.t0++
case ecnECT1:
acks.ecn.t1++
case ecnCE:
acks.ecn.ce++
}
// Limit the total number of ACK ranges by dropping older ranges.
//
// Remembering more ranges results in larger ACK frames.
//
// Remembering a large number of ranges could result in ACK frames becoming
// too large to fit in a packet, in which case we will silently drop older
// ranges during packet construction.
//
// Remembering fewer ranges can result in unnecessary retransmissions,
// since we cannot accept packets older than the oldest remembered range.
//
// The limit here is completely arbitrary. If it seems wrong, it probably is.
//
// https://www.rfc-editor.org/rfc/rfc9000#section-13.2.3
const maxAckRanges = 8
if overflow := acks.seen.numRanges() - maxAckRanges; overflow > 0 {
acks.seen.removeranges(0, overflow)
}
}
// mustAckImmediately reports whether an ack-eliciting packet must be acknowledged immediately,
// or whether the ack may be deferred.
func (acks *ackState) mustAckImmediately(space numberSpace, num packetNumber, ecn ecnBits) bool {
// https://www.rfc-editor.org/rfc/rfc9000.html#section-13.2.1
if space != appDataSpace {
// "[...] all ack-eliciting Initial and Handshake packets [...]"
// https://www.rfc-editor.org/rfc/rfc9000.html#section-13.2.1-2
return true
}
if num < acks.maxAckEliciting {
// "[...] when the received packet has a packet number less than another
// ack-eliciting packet that has been received [...]"
// https://www.rfc-editor.org/rfc/rfc9000.html#section-13.2.1-8.1
return true
}
if acks.seen.rangeContaining(acks.maxAckEliciting).end != num {
// "[...] when the packet has a packet number larger than the highest-numbered
// ack-eliciting packet that has been received and there are missing packets
// between that packet and this packet."
// https://www.rfc-editor.org/rfc/rfc9000.html#section-13.2.1-8.2
//
// This case is a bit tricky. Let's say we've received:
// 0, ack-eliciting
// 1, ack-eliciting
// 3, NOT ack eliciting
//
// We have sent ACKs for 0 and 1. If we receive ack-eliciting packet 2,
// we do not need to send an immediate ACK, because there are no missing
// packets between it and the highest-numbered ack-eliciting packet (1).
// If we receive ack-eliciting packet 4, we do need to send an immediate ACK,
// because there's a gap (the missing packet 2).
//
// We check for this by looking up the ACK range which contains the
// highest-numbered ack-eliciting packet: [0, 1) in the above example.
// If the range ends just before the packet we are now processing,
// there are no gaps. If it does not, there must be a gap.
return true
}
// "[...] packets marked with the ECN Congestion Experienced (CE) codepoint
// in the IP header SHOULD be acknowledged immediately [...]"
// https://www.rfc-editor.org/rfc/rfc9000.html#section-13.2.1-9
if ecn == ecnCE {
return true
}
// "[...] SHOULD send an ACK frame after receiving at least two ack-eliciting packets."
// https://www.rfc-editor.org/rfc/rfc9000.html#section-13.2.2
//
// This ack frequency takes a substantial toll on performance, however.
// Follow the behavior of Google QUICHE:
// Ack every other packet for the first 100 packets, and then ack every 10th packet.
// This keeps ack frequency high during the beginning of slow start when CWND is
// increasing rapidly.
packetsBeforeAck := 2
if acks.seen.max() > 100 {
packetsBeforeAck = 10
}
return acks.unackedAckEliciting >= packetsBeforeAck
}
// shouldSendAck reports whether the connection should send an ACK frame at this time,
// in an ACK-only packet if necessary.
func (acks *ackState) shouldSendAck(now time.Time) bool {
return !acks.nextAck.IsZero() && !acks.nextAck.After(now)
}
// acksToSend returns the set of packet numbers to ACK at this time, and the current ack delay.
// It may return acks even if shouldSendAck returns false, when there are unacked
// ack-eliciting packets whose ack is being delayed.
func (acks *ackState) acksToSend(now time.Time) (nums rangeset[packetNumber], ackDelay time.Duration) {
if acks.nextAck.IsZero() && acks.unackedAckEliciting == 0 {
return nil, 0
}
// "[...] the delays intentionally introduced between the time the packet with the
// largest packet number is received and the time an acknowledgement is sent."
// https://www.rfc-editor.org/rfc/rfc9000#section-13.2.5-1
delay := now.Sub(acks.maxRecvTime)
if delay < 0 {
delay = 0
}
return acks.seen, delay
}
// sentAck records that an ACK frame has been sent.
func (acks *ackState) sentAck() {
acks.nextAck = time.Time{}
acks.unackedAckEliciting = 0
}
// handleAck records that an ack has been received for a ACK frame we sent
// containing the given Largest Acknowledged field.
func (acks *ackState) handleAck(largestAcked packetNumber) {
// We can stop acking packets less or equal to largestAcked.
// https://www.rfc-editor.org/rfc/rfc9000.html#section-13.2.4-1
//
// We rely on acks.seen containing the largest packet number that has been successfully
// processed, so we retain the range containing largestAcked and discard previous ones.
acks.seen.sub(0, acks.seen.rangeContaining(largestAcked).start)
}
// largestSeen reports the largest seen packet.
func (acks *ackState) largestSeen() packetNumber {
return acks.seen.max()
}
// Copyright 2023 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 quic
import "sync/atomic"
// atomicBits is an atomic uint32 that supports setting individual bits.
type atomicBits[T ~uint32] struct {
bits atomic.Uint32
}
// set sets the bits in mask to the corresponding bits in v.
// It returns the new value.
func (a *atomicBits[T]) set(v, mask T) T {
if v&^mask != 0 {
panic("BUG: bits in v are not in mask")
}
for {
o := a.bits.Load()
n := (o &^ uint32(mask)) | uint32(v)
if a.bits.CompareAndSwap(o, n) {
return T(n)
}
}
}
func (a *atomicBits[T]) load() T {
return T(a.bits.Load())
}
// Copyright 2023 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 quic
import (
"crypto/tls"
"log/slog"
"math"
"time"
"golang.org/x/net/internal/quic/quicwire"
)
// A Config structure configures a QUIC endpoint.
// A Config must not be modified after it has been passed to a QUIC function.
// A Config may be reused; the quic package will also not modify it.
type Config struct {
// TLSConfig is the endpoint's TLS configuration.
// It must be non-nil and include at least one certificate or else set GetCertificate.
TLSConfig *tls.Config
// MaxBidiRemoteStreams limits the number of simultaneous bidirectional streams
// a peer may open.
// If zero, the default value of 100 is used.
// If negative, the limit is zero.
MaxBidiRemoteStreams int64
// MaxUniRemoteStreams limits the number of simultaneous unidirectional streams
// a peer may open.
// If zero, the default value of 100 is used.
// If negative, the limit is zero.
MaxUniRemoteStreams int64
// MaxStreamReadBufferSize is the maximum amount of data sent by the peer that a
// stream will buffer for reading.
// If zero, the default value of 1MiB is used.
// If negative, the limit is zero.
MaxStreamReadBufferSize int64
// MaxStreamWriteBufferSize is the maximum amount of data a stream will buffer for
// sending to the peer.
// If zero, the default value of 1MiB is used.
// If negative, the limit is zero.
MaxStreamWriteBufferSize int64
// MaxConnReadBufferSize is the maximum amount of data sent by the peer that a
// connection will buffer for reading, across all streams.
// If zero, the default value of 1MiB is used.
// If negative, the limit is zero.
MaxConnReadBufferSize int64
// RequireAddressValidation may be set to true to enable address validation
// of client connections prior to starting the handshake.
//
// Enabling this setting reduces the amount of work packets with spoofed
// source address information can cause a server to perform,
// at the cost of increased handshake latency.
RequireAddressValidation bool
// StatelessResetKey is used to provide stateless reset of connections.
// A restart may leave an endpoint without access to the state of
// existing connections. Stateless reset permits an endpoint to respond
// to a packet for a connection it does not recognize.
//
// This field should be filled with random bytes.
// The contents should remain stable across restarts,
// to permit an endpoint to send a reset for
// connections created before a restart.
//
// The contents of the StatelessResetKey should not be exposed.
// An attacker can use knowledge of this field's value to
// reset existing connections.
//
// If this field is left as zero, stateless reset is disabled.
StatelessResetKey [32]byte
// HandshakeTimeout is the maximum time in which a connection handshake must complete.
// If zero, the default of 10 seconds is used.
// If negative, there is no handshake timeout.
HandshakeTimeout time.Duration
// MaxIdleTimeout is the maximum time after which an idle connection will be closed.
// If zero, the default of 30 seconds is used.
// If negative, idle connections are never closed.
//
// The idle timeout for a connection is the minimum of the maximum idle timeouts
// of the endpoints.
MaxIdleTimeout time.Duration
// KeepAlivePeriod is the time after which a packet will be sent to keep
// an idle connection alive.
// If zero, keep alive packets are not sent.
// If greater than zero, the keep alive period is the smaller of KeepAlivePeriod and
// half the connection idle timeout.
KeepAlivePeriod time.Duration
// QLogLogger receives qlog events.
//
// Events currently correspond to the definitions in draft-ietf-qlog-quic-events-03.
// This is not the latest version of the draft, but is the latest version supported
// by common event log viewers as of the time this paragraph was written.
//
// The qlog package contains a slog.Handler which serializes qlog events
// to a standard JSON representation.
QLogLogger *slog.Logger
}
// Clone returns a shallow clone of c, or nil if c is nil.
// It is safe to clone a [Config] that is being used concurrently by a QUIC endpoint.
func (c *Config) Clone() *Config {
n := *c
return &n
}
func configDefault[T ~int64](v, def, limit T) T {
switch {
case v == 0:
return def
case v < 0:
return 0
default:
return min(v, limit)
}
}
func (c *Config) maxBidiRemoteStreams() int64 {
return configDefault(c.MaxBidiRemoteStreams, 100, maxStreamsLimit)
}
func (c *Config) maxUniRemoteStreams() int64 {
return configDefault(c.MaxUniRemoteStreams, 100, maxStreamsLimit)
}
func (c *Config) maxStreamReadBufferSize() int64 {
return configDefault(c.MaxStreamReadBufferSize, 1<<20, quicwire.MaxVarint)
}
func (c *Config) maxStreamWriteBufferSize() int64 {
return configDefault(c.MaxStreamWriteBufferSize, 1<<20, quicwire.MaxVarint)
}
func (c *Config) maxConnReadBufferSize() int64 {
return configDefault(c.MaxConnReadBufferSize, 1<<20, quicwire.MaxVarint)
}
func (c *Config) handshakeTimeout() time.Duration {
return configDefault(c.HandshakeTimeout, defaultHandshakeTimeout, math.MaxInt64)
}
func (c *Config) maxIdleTimeout() time.Duration {
return configDefault(c.MaxIdleTimeout, defaultMaxIdleTimeout, math.MaxInt64)
}
func (c *Config) keepAlivePeriod() time.Duration {
return configDefault(c.KeepAlivePeriod, defaultKeepAlivePeriod, math.MaxInt64)
}
// Copyright 2023 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 quic
import (
"context"
"log/slog"
"math"
"time"
)
// ccReno is the NewReno-based congestion controller defined in RFC 9002.
// https://www.rfc-editor.org/rfc/rfc9002.html#section-7
type ccReno struct {
maxDatagramSize int
// Maximum number of bytes allowed to be in flight.
congestionWindow int
// Sum of size of all packets that contain at least one ack-eliciting
// or PADDING frame (i.e., any non-ACK frame), and have neither been
// acknowledged nor declared lost.
bytesInFlight int
// When the congestion window is below the slow start threshold,
// the controller is in slow start.
slowStartThreshold int
// The time the current recovery period started, or zero when not
// in a recovery period.
recoveryStartTime time.Time
// Accumulated count of bytes acknowledged in congestion avoidance.
congestionPendingAcks int
// When entering a recovery period, we are allowed to send one packet
// before reducing the congestion window. sendOnePacketInRecovery is
// true if we haven't sent that packet yet.
sendOnePacketInRecovery bool
// inRecovery is set when we are in the recovery state.
inRecovery bool
// underutilized is set if the congestion window is underutilized
// due to insufficient application data, flow control limits, or
// anti-amplification limits.
underutilized bool
// ackLastLoss is the sent time of the newest lost packet processed
// in the current batch.
ackLastLoss time.Time
// Data tracking the duration of the most recently handled sequence of
// contiguous lost packets. If this exceeds the persistent congestion duration,
// persistent congestion is declared.
//
// https://www.rfc-editor.org/rfc/rfc9002#section-7.6
persistentCongestion [numberSpaceCount]struct {
start time.Time // send time of first lost packet
end time.Time // send time of last lost packet
next packetNumber // one plus the number of the last lost packet
}
}
func newReno(maxDatagramSize int) *ccReno {
c := &ccReno{
maxDatagramSize: maxDatagramSize,
}
// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.2-1
c.congestionWindow = min(10*maxDatagramSize, max(14720, c.minimumCongestionWindow()))
// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.3.1-1
c.slowStartThreshold = math.MaxInt
for space := range c.persistentCongestion {
c.persistentCongestion[space].next = -1
}
return c
}
// canSend reports whether the congestion controller permits sending
// a maximum-size datagram at this time.
//
// "An endpoint MUST NOT send a packet if it would cause bytes_in_flight [...]
// to be larger than the congestion window [...]"
// https://www.rfc-editor.org/rfc/rfc9002#section-7-7
//
// For simplicity and efficiency, we don't permit sending undersized datagrams.
func (c *ccReno) canSend() bool {
if c.sendOnePacketInRecovery {
return true
}
return c.bytesInFlight+c.maxDatagramSize <= c.congestionWindow
}
// setUnderutilized indicates that the congestion window is underutilized.
//
// The congestion window is underutilized if bytes in flight is smaller than
// the congestion window and sending is not pacing limited; that is, the
// congestion controller permits sending data, but no data is sent.
//
// https://www.rfc-editor.org/rfc/rfc9002#section-7.8
func (c *ccReno) setUnderutilized(log *slog.Logger, v bool) {
if c.underutilized == v {
return
}
oldState := c.state()
c.underutilized = v
if logEnabled(log, QLogLevelPacket) {
logCongestionStateUpdated(log, oldState, c.state())
}
}
// packetSent indicates that a packet has been sent.
func (c *ccReno) packetSent(now time.Time, log *slog.Logger, space numberSpace, sent *sentPacket) {
if !sent.inFlight {
return
}
c.bytesInFlight += sent.size
if c.sendOnePacketInRecovery {
c.sendOnePacketInRecovery = false
}
}
// Acked and lost packets are processed in batches
// resulting from either a received ACK frame or
// the loss detection timer expiring.
//
// A batch consists of zero or more calls to packetAcked and packetLost,
// followed by a single call to packetBatchEnd.
//
// Acks may be reported in any order, but lost packets must
// be reported in strictly increasing order.
// packetAcked indicates that a packet has been newly acknowledged.
func (c *ccReno) packetAcked(now time.Time, sent *sentPacket) {
if !sent.inFlight {
return
}
c.bytesInFlight -= sent.size
if c.underutilized {
// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.8
return
}
if sent.time.Before(c.recoveryStartTime) {
// In recovery, and this packet was sent before we entered recovery.
// (If this packet was sent after we entered recovery, receiving an ack
// for it moves us out of recovery into congestion avoidance.)
// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.3.2
return
}
c.congestionPendingAcks += sent.size
}
// packetLost indicates that a packet has been newly marked as lost.
// Lost packets must be reported in increasing order.
func (c *ccReno) packetLost(now time.Time, space numberSpace, sent *sentPacket, rtt *rttState) {
// Record state to check for persistent congestion.
// https://www.rfc-editor.org/rfc/rfc9002#section-7.6
//
// Note that this relies on always receiving loss events in increasing order:
// All packets prior to the one we're examining now have either been
// acknowledged or declared lost.
isValidPersistentCongestionSample := (sent.ackEliciting &&
!rtt.firstSampleTime.IsZero() &&
!sent.time.Before(rtt.firstSampleTime))
if isValidPersistentCongestionSample {
// This packet either extends an existing range of lost packets,
// or starts a new one.
if sent.num != c.persistentCongestion[space].next {
c.persistentCongestion[space].start = sent.time
}
c.persistentCongestion[space].end = sent.time
c.persistentCongestion[space].next = sent.num + 1
} else {
// This packet cannot establish persistent congestion on its own.
// However, if we have an existing range of lost packets,
// this does not break it.
if sent.num == c.persistentCongestion[space].next {
c.persistentCongestion[space].next = sent.num + 1
}
}
if !sent.inFlight {
return
}
c.bytesInFlight -= sent.size
if sent.time.After(c.ackLastLoss) {
c.ackLastLoss = sent.time
}
}
// packetBatchEnd is called at the end of processing a batch of acked or lost packets.
func (c *ccReno) packetBatchEnd(now time.Time, log *slog.Logger, space numberSpace, rtt *rttState, maxAckDelay time.Duration) {
if logEnabled(log, QLogLevelPacket) {
oldState := c.state()
defer func() { logCongestionStateUpdated(log, oldState, c.state()) }()
}
if !c.ackLastLoss.IsZero() && !c.ackLastLoss.Before(c.recoveryStartTime) {
// Enter the recovery state.
// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.3.2
c.recoveryStartTime = now
c.slowStartThreshold = c.congestionWindow / 2
c.congestionWindow = max(c.slowStartThreshold, c.minimumCongestionWindow())
c.sendOnePacketInRecovery = true
// Clear congestionPendingAcks to avoid increasing the congestion
// window based on acks in a frame that sends us into recovery.
c.congestionPendingAcks = 0
c.inRecovery = true
} else if c.congestionPendingAcks > 0 {
// We are in slow start or congestion avoidance.
c.inRecovery = false
if c.congestionWindow < c.slowStartThreshold {
// When the congestion window is less than the slow start threshold,
// we are in slow start and increase the window by the number of
// bytes acknowledged.
d := min(c.slowStartThreshold-c.congestionWindow, c.congestionPendingAcks)
c.congestionWindow += d
c.congestionPendingAcks -= d
}
// When the congestion window is at or above the slow start threshold,
// we are in congestion avoidance.
//
// RFC 9002 does not specify an algorithm here. The following is
// the recommended algorithm from RFC 5681, in which we increment
// the window by the maximum datagram size every time the number
// of bytes acknowledged reaches cwnd.
for c.congestionPendingAcks > c.congestionWindow {
c.congestionPendingAcks -= c.congestionWindow
c.congestionWindow += c.maxDatagramSize
}
}
if !c.ackLastLoss.IsZero() {
// Check for persistent congestion.
// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.6
//
// "A sender [...] MAY use state for just the packet number space that
// was acknowledged."
// https://www.rfc-editor.org/rfc/rfc9002#section-7.6.2-5
//
// For simplicity, we consider each number space independently.
const persistentCongestionThreshold = 3
d := (rtt.smoothedRTT + max(4*rtt.rttvar, timerGranularity) + maxAckDelay) *
persistentCongestionThreshold
start := c.persistentCongestion[space].start
end := c.persistentCongestion[space].end
if end.Sub(start) >= d {
c.congestionWindow = c.minimumCongestionWindow()
c.recoveryStartTime = time.Time{}
rtt.establishPersistentCongestion()
}
}
c.ackLastLoss = time.Time{}
}
// packetDiscarded indicates that the keys for a packet's space have been discarded.
func (c *ccReno) packetDiscarded(sent *sentPacket) {
// https://www.rfc-editor.org/rfc/rfc9002#section-6.2.2-3
if sent.inFlight {
c.bytesInFlight -= sent.size
}
}
func (c *ccReno) minimumCongestionWindow() int {
// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.2-4
return 2 * c.maxDatagramSize
}
func logCongestionStateUpdated(log *slog.Logger, oldState, newState congestionState) {
if oldState == newState {
return
}
log.LogAttrs(context.Background(), QLogLevelPacket,
"recovery:congestion_state_updated",
slog.String("old", oldState.String()),
slog.String("new", newState.String()),
)
}
type congestionState string
func (s congestionState) String() string { return string(s) }
const (
congestionSlowStart = congestionState("slow_start")
congestionCongestionAvoidance = congestionState("congestion_avoidance")
congestionApplicationLimited = congestionState("application_limited")
congestionRecovery = congestionState("recovery")
)
func (c *ccReno) state() congestionState {
switch {
case c.inRecovery:
return congestionRecovery
case c.underutilized:
return congestionApplicationLimited
case c.congestionWindow < c.slowStartThreshold:
return congestionSlowStart
default:
return congestionCongestionAvoidance
}
}
// Copyright 2023 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 quic
import (
"context"
cryptorand "crypto/rand"
"crypto/tls"
"errors"
"fmt"
"log/slog"
"math/rand/v2"
"net/netip"
"time"
)
// A Conn is a QUIC connection.
//
// Multiple goroutines may invoke methods on a Conn simultaneously.
type Conn struct {
side connSide
endpoint *Endpoint
config *Config
testHooks connTestHooks
peerAddr netip.AddrPort
localAddr netip.AddrPort
prng *rand.Rand
msgc chan any
donec chan struct{} // closed when conn loop exits
w packetWriter
acks [numberSpaceCount]ackState // indexed by number space
lifetime lifetimeState
idle idleState
connIDState connIDState
loss lossState
streams streamsState
path pathState
skip skipState
// Packet protection keys, CRYPTO streams, and TLS state.
keysInitial fixedKeyPair
keysHandshake fixedKeyPair
keysAppData updatingKeyPair
crypto [numberSpaceCount]cryptoStream
tls *tls.QUICConn
// retryToken is the token provided by the peer in a Retry packet.
retryToken []byte
// handshakeConfirmed is set when the handshake is confirmed.
// For server connections, it tracks sending HANDSHAKE_DONE.
handshakeConfirmed sentVal
peerAckDelayExponent int8 // -1 when unknown
// Tests only: Send a PING in a specific number space.
testSendPingSpace numberSpace
testSendPing sentVal
log *slog.Logger
}
// connTestHooks override conn behavior in tests.
type connTestHooks interface {
// init is called after a conn is created.
init(first bool)
// handleTLSEvent is called with each TLS event.
handleTLSEvent(tls.QUICEvent)
// newConnID is called to generate a new connection ID.
// Permits tests to generate consistent connection IDs rather than random ones.
newConnID(seq int64) ([]byte, error)
}
// newServerConnIDs is connection IDs associated with a new server connection.
type newServerConnIDs struct {
srcConnID []byte // source from client's current Initial
dstConnID []byte // destination from client's current Initial
originalDstConnID []byte // destination from client's first Initial
retrySrcConnID []byte // source from server's Retry
}
func newConn(now time.Time, side connSide, cids newServerConnIDs, peerHostname string, peerAddr netip.AddrPort, config *Config, e *Endpoint) (conn *Conn, _ error) {
c := &Conn{
side: side,
endpoint: e,
config: config,
peerAddr: unmapAddrPort(peerAddr),
donec: make(chan struct{}),
peerAckDelayExponent: -1,
}
defer func() {
// If we hit an error in newConn, close donec so tests don't get stuck waiting for it.
// This is only relevant if we've got a bug, but it makes tracking that bug down
// much easier.
if conn == nil {
close(c.donec)
}
}()
// A one-element buffer allows us to wake a Conn's event loop as a
// non-blocking operation.
c.msgc = make(chan any, 1)
if e.testHooks != nil {
e.testHooks.newConn(c)
}
// initialConnID is the connection ID used to generate Initial packet protection keys.
var initialConnID []byte
if c.side == clientSide {
if err := c.connIDState.initClient(c); err != nil {
return nil, err
}
initialConnID, _ = c.connIDState.dstConnID()
} else {
initialConnID = cids.originalDstConnID
if cids.retrySrcConnID != nil {
initialConnID = cids.retrySrcConnID
}
if err := c.connIDState.initServer(c, cids); err != nil {
return nil, err
}
}
// A per-conn ChaCha8 PRNG is probably more than we need,
// but at least it's fairly small.
var seed [32]byte
if _, err := cryptorand.Read(seed[:]); err != nil {
panic(err)
}
c.prng = rand.New(rand.NewChaCha8(seed))
// TODO: PMTU discovery.
c.logConnectionStarted(cids.originalDstConnID, peerAddr)
c.keysAppData.init()
c.loss.init(c.side, smallestMaxDatagramSize, now)
c.streamsInit()
c.lifetimeInit()
c.restartIdleTimer(now)
c.skip.init(c)
if err := c.startTLS(now, initialConnID, peerHostname, transportParameters{
initialSrcConnID: c.connIDState.srcConnID(),
originalDstConnID: cids.originalDstConnID,
retrySrcConnID: cids.retrySrcConnID,
ackDelayExponent: ackDelayExponent,
maxUDPPayloadSize: maxUDPPayloadSize,
maxAckDelay: maxAckDelay,
disableActiveMigration: true,
initialMaxData: config.maxConnReadBufferSize(),
initialMaxStreamDataBidiLocal: config.maxStreamReadBufferSize(),
initialMaxStreamDataBidiRemote: config.maxStreamReadBufferSize(),
initialMaxStreamDataUni: config.maxStreamReadBufferSize(),
initialMaxStreamsBidi: c.streams.remoteLimit[bidiStream].max,
initialMaxStreamsUni: c.streams.remoteLimit[uniStream].max,
activeConnIDLimit: activeConnIDLimit,
}); err != nil {
return nil, err
}
if c.testHooks != nil {
c.testHooks.init(true)
}
go c.loop(now)
return c, nil
}
func (c *Conn) String() string {
return fmt.Sprintf("quic.Conn(%v,->%v)", c.side, c.peerAddr)
}
// LocalAddr returns the local network address, if known.
func (c *Conn) LocalAddr() netip.AddrPort {
return c.localAddr
}
// RemoteAddr returns the remote network address, if known.
func (c *Conn) RemoteAddr() netip.AddrPort {
return c.peerAddr
}
// ConnectionState returns basic TLS details about the connection.
func (c *Conn) ConnectionState() tls.ConnectionState {
return c.tls.ConnectionState()
}
// confirmHandshake is called when the handshake is confirmed.
// https://www.rfc-editor.org/rfc/rfc9001#section-4.1.2
func (c *Conn) confirmHandshake(now time.Time) {
// If handshakeConfirmed is unset, the handshake is not confirmed.
// If it is unsent, the handshake is confirmed and we need to send a HANDSHAKE_DONE.
// If it is sent, we have sent a HANDSHAKE_DONE.
// If it is received, the handshake is confirmed and we do not need to send anything.
if c.handshakeConfirmed.isSet() {
return // already confirmed
}
if c.side == serverSide {
// When the server confirms the handshake, it sends a HANDSHAKE_DONE.
c.handshakeConfirmed.setUnsent()
c.endpoint.serverConnEstablished(c)
} else {
// The client never sends a HANDSHAKE_DONE, so we set handshakeConfirmed
// to the received state, indicating that the handshake is confirmed and we
// don't need to send anything.
c.handshakeConfirmed.setReceived()
}
c.restartIdleTimer(now)
c.loss.confirmHandshake()
// "An endpoint MUST discard its Handshake keys when the TLS handshake is confirmed"
// https://www.rfc-editor.org/rfc/rfc9001#section-4.9.2-1
c.discardKeys(now, handshakeSpace)
}
// discardKeys discards unused packet protection keys.
// https://www.rfc-editor.org/rfc/rfc9001#section-4.9
func (c *Conn) discardKeys(now time.Time, space numberSpace) {
if err := c.crypto[space].discardKeys(); err != nil {
c.abort(now, err)
}
switch space {
case initialSpace:
c.keysInitial.discard()
case handshakeSpace:
c.keysHandshake.discard()
}
c.loss.discardKeys(now, c.log, space)
}
// receiveTransportParameters applies transport parameters sent by the peer.
func (c *Conn) receiveTransportParameters(p transportParameters) error {
isRetry := c.retryToken != nil
if err := c.connIDState.validateTransportParameters(c, isRetry, p); err != nil {
return err
}
c.streams.outflow.setMaxData(p.initialMaxData)
c.streams.localLimit[bidiStream].setMax(p.initialMaxStreamsBidi)
c.streams.localLimit[uniStream].setMax(p.initialMaxStreamsUni)
c.streams.peerInitialMaxStreamDataBidiLocal = p.initialMaxStreamDataBidiLocal
c.streams.peerInitialMaxStreamDataRemote[bidiStream] = p.initialMaxStreamDataBidiRemote
c.streams.peerInitialMaxStreamDataRemote[uniStream] = p.initialMaxStreamDataUni
c.receivePeerMaxIdleTimeout(p.maxIdleTimeout)
c.peerAckDelayExponent = p.ackDelayExponent
c.loss.setMaxAckDelay(p.maxAckDelay)
if err := c.connIDState.setPeerActiveConnIDLimit(c, p.activeConnIDLimit); err != nil {
return err
}
if p.preferredAddrConnID != nil {
var (
seq int64 = 1 // sequence number of this conn id is 1
retirePriorTo int64 = 0 // retire nothing
resetToken [16]byte
)
copy(resetToken[:], p.preferredAddrResetToken)
if err := c.connIDState.handleNewConnID(c, seq, retirePriorTo, p.preferredAddrConnID, resetToken); err != nil {
return err
}
}
// TODO: stateless_reset_token
// TODO: max_udp_payload_size
// TODO: disable_active_migration
// TODO: preferred_address
return nil
}
type (
timerEvent struct{}
wakeEvent struct{}
)
var errIdleTimeout = errors.New("idle timeout")
// loop is the connection main loop.
//
// Except where otherwise noted, all connection state is owned by the loop goroutine.
//
// The loop processes messages from c.msgc and timer events.
// Other goroutines may examine or modify conn state by sending the loop funcs to execute.
func (c *Conn) loop(now time.Time) {
defer c.cleanup()
// The connection timer sends a message to the connection loop on expiry.
// We need to give it an expiry when creating it, so set the initial timeout to
// an arbitrary large value. The timer will be reset before this expires (and it
// isn't a problem if it does anyway).
var lastTimeout time.Time
timer := time.AfterFunc(1*time.Hour, func() {
c.sendMsg(timerEvent{})
})
defer timer.Stop()
for c.lifetime.state != connStateDone {
sendTimeout := c.maybeSend(now) // try sending
// Note that we only need to consider the ack timer for the App Data space,
// since the Initial and Handshake spaces always ack immediately.
nextTimeout := sendTimeout
nextTimeout = firstTime(nextTimeout, c.idle.nextTimeout)
if c.isAlive() {
nextTimeout = firstTime(nextTimeout, c.loss.timer)
nextTimeout = firstTime(nextTimeout, c.acks[appDataSpace].nextAck)
} else {
nextTimeout = firstTime(nextTimeout, c.lifetime.drainEndTime)
}
var m any
if !nextTimeout.IsZero() && nextTimeout.Before(now) {
// A connection timer has expired.
now = time.Now()
m = timerEvent{}
} else {
// Reschedule the connection timer if necessary
// and wait for the next event.
if !nextTimeout.Equal(lastTimeout) && !nextTimeout.IsZero() {
// Resetting a timer created with time.AfterFunc guarantees
// that the timer will run again. We might generate a spurious
// timer event under some circumstances, but that's okay.
timer.Reset(nextTimeout.Sub(now))
lastTimeout = nextTimeout
}
m = <-c.msgc
now = time.Now()
}
switch m := m.(type) {
case *datagram:
if !c.handleDatagram(now, m) {
if c.logEnabled(QLogLevelPacket) {
c.logPacketDropped(m)
}
}
m.recycle()
case timerEvent:
// A connection timer has expired.
if c.idleAdvance(now) {
// The connection idle timer has expired.
c.abortImmediately(now, errIdleTimeout)
return
}
c.loss.advance(now, c.handleAckOrLoss)
if c.lifetimeAdvance(now) {
// The connection has completed the draining period,
// and may be shut down.
return
}
case wakeEvent:
// We're being woken up to try sending some frames.
case func(time.Time, *Conn):
// Send a func to msgc to run it on the main Conn goroutine
m(now, c)
case func(now, next time.Time, _ *Conn):
// Send a func to msgc to run it on the main Conn goroutine
m(now, nextTimeout, c)
default:
panic(fmt.Sprintf("quic: unrecognized conn message %T", m))
}
}
}
func (c *Conn) cleanup() {
c.logConnectionClosed()
c.endpoint.connDrained(c)
c.tls.Close()
close(c.donec)
}
// sendMsg sends a message to the conn's loop.
// It does not wait for the message to be processed.
// The conn may close before processing the message, in which case it is lost.
func (c *Conn) sendMsg(m any) {
select {
case c.msgc <- m:
case <-c.donec:
}
}
// wake wakes up the conn's loop.
func (c *Conn) wake() {
select {
case c.msgc <- wakeEvent{}:
default:
}
}
// runOnLoop executes a function within the conn's loop goroutine.
func (c *Conn) runOnLoop(ctx context.Context, f func(now time.Time, c *Conn)) error {
donec := make(chan struct{})
msg := func(now time.Time, c *Conn) {
defer close(donec)
f(now, c)
}
c.sendMsg(msg)
select {
case <-donec:
case <-c.donec:
return errors.New("quic: connection closed")
}
return nil
}
func (c *Conn) waitOnDone(ctx context.Context, ch <-chan struct{}) error {
// Check the channel before the context.
// We always prefer to return results when available,
// even when provided with an already-canceled context.
select {
case <-ch:
return nil
default:
}
select {
case <-ch:
case <-ctx.Done():
return ctx.Err()
}
return nil
}
// firstTime returns the earliest non-zero time, or zero if both times are zero.
func firstTime(a, b time.Time) time.Time {
switch {
case a.IsZero():
return b
case b.IsZero():
return a
case a.Before(b):
return a
default:
return b
}
}
// Copyright 2023 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 quic
import (
"context"
"errors"
"time"
)
// connState is the state of a connection.
type connState int
const (
// A connection is alive when it is first created.
connStateAlive = connState(iota)
// The connection has received a CONNECTION_CLOSE frame from the peer,
// and has not yet sent a CONNECTION_CLOSE in response.
//
// We will send a CONNECTION_CLOSE, and then enter the draining state.
connStatePeerClosed
// The connection is in the closing state.
//
// We will send CONNECTION_CLOSE frames to the peer
// (once upon entering the closing state, and possibly again in response to peer packets).
//
// If we receive a CONNECTION_CLOSE from the peer, we will enter the draining state.
// Otherwise, we will eventually time out and move to the done state.
//
// https://www.rfc-editor.org/rfc/rfc9000#section-10.2.1
connStateClosing
// The connection is in the draining state.
//
// We will neither send packets nor process received packets.
// When the drain timer expires, we move to the done state.
//
// https://www.rfc-editor.org/rfc/rfc9000#section-10.2.2
connStateDraining
// The connection is done, and the conn loop will exit.
connStateDone
)
// lifetimeState tracks the state of a connection.
//
// This is fairly coupled to the rest of a Conn, but putting it in a struct of its own helps
// reason about operations that cause state transitions.
type lifetimeState struct {
state connState
readyc chan struct{} // closed when TLS handshake completes
donec chan struct{} // closed when finalErr is set
localErr error // error sent to the peer
finalErr error // error sent by the peer, or transport error; set before closing donec
connCloseSentTime time.Time // send time of last CONNECTION_CLOSE frame
connCloseDelay time.Duration // delay until next CONNECTION_CLOSE frame sent
drainEndTime time.Time // time the connection exits the draining state
}
func (c *Conn) lifetimeInit() {
c.lifetime.readyc = make(chan struct{})
c.lifetime.donec = make(chan struct{})
}
var (
errNoPeerResponse = errors.New("peer did not respond to CONNECTION_CLOSE")
errConnClosed = errors.New("connection closed")
)
// advance is called when time passes.
func (c *Conn) lifetimeAdvance(now time.Time) (done bool) {
if c.lifetime.drainEndTime.IsZero() || c.lifetime.drainEndTime.After(now) {
return false
}
// The connection drain period has ended, and we can shut down.
// https://www.rfc-editor.org/rfc/rfc9000.html#section-10.2-7
c.lifetime.drainEndTime = time.Time{}
if c.lifetime.state != connStateDraining {
// We were in the closing state, waiting for a CONNECTION_CLOSE from the peer.
c.setFinalError(errNoPeerResponse)
}
c.setState(now, connStateDone)
return true
}
// setState sets the conn state.
func (c *Conn) setState(now time.Time, state connState) {
if c.lifetime.state == state {
return
}
c.lifetime.state = state
switch state {
case connStateClosing, connStateDraining:
if c.lifetime.drainEndTime.IsZero() {
c.lifetime.drainEndTime = now.Add(3 * c.loss.ptoBasePeriod())
}
case connStateDone:
c.setFinalError(nil)
}
if state != connStateAlive {
c.streamsCleanup()
}
}
// handshakeDone is called when the TLS handshake completes.
func (c *Conn) handshakeDone() {
close(c.lifetime.readyc)
}
// isDraining reports whether the conn is in the draining state.
//
// The draining state is entered once an endpoint receives a CONNECTION_CLOSE frame.
// The endpoint will no longer send any packets, but we retain knowledge of the connection
// until the end of the drain period to ensure we discard packets for the connection
// rather than treating them as starting a new connection.
//
// https://www.rfc-editor.org/rfc/rfc9000.html#section-10.2.2
func (c *Conn) isDraining() bool {
switch c.lifetime.state {
case connStateDraining, connStateDone:
return true
}
return false
}
// isAlive reports whether the conn is handling packets.
func (c *Conn) isAlive() bool {
return c.lifetime.state == connStateAlive
}
// sendOK reports whether the conn can send frames at this time.
func (c *Conn) sendOK(now time.Time) bool {
switch c.lifetime.state {
case connStateAlive:
return true
case connStatePeerClosed:
if c.lifetime.localErr == nil {
// We're waiting for the user to close the connection, providing us with
// a final status to send to the peer.
return false
}
// We should send a CONNECTION_CLOSE.
return true
case connStateClosing:
if c.lifetime.connCloseSentTime.IsZero() {
return true
}
maxRecvTime := c.acks[initialSpace].maxRecvTime
if t := c.acks[handshakeSpace].maxRecvTime; t.After(maxRecvTime) {
maxRecvTime = t
}
if t := c.acks[appDataSpace].maxRecvTime; t.After(maxRecvTime) {
maxRecvTime = t
}
if maxRecvTime.Before(c.lifetime.connCloseSentTime.Add(c.lifetime.connCloseDelay)) {
// After sending CONNECTION_CLOSE, ignore packets from the peer for
// a delay. On the next packet received after the delay, send another
// CONNECTION_CLOSE.
return false
}
return true
case connStateDraining:
// We are in the draining state, and will send no more packets.
return false
case connStateDone:
return false
default:
panic("BUG: unhandled connection state")
}
}
// sentConnectionClose reports that the conn has sent a CONNECTION_CLOSE to the peer.
func (c *Conn) sentConnectionClose(now time.Time) {
switch c.lifetime.state {
case connStatePeerClosed:
c.enterDraining(now)
}
if c.lifetime.connCloseSentTime.IsZero() {
// Set the initial delay before we will send another CONNECTION_CLOSE.
//
// RFC 9000 states that we should rate limit CONNECTION_CLOSE frames,
// but leaves the implementation of the limit up to us. Here, we start
// with the same delay as the PTO timer (RFC 9002, Section 6.2.1),
// not including max_ack_delay, and double it on every CONNECTION_CLOSE sent.
c.lifetime.connCloseDelay = c.loss.rtt.smoothedRTT + max(4*c.loss.rtt.rttvar, timerGranularity)
} else if !c.lifetime.connCloseSentTime.Equal(now) {
// If connCloseSentTime == now, we're sending two CONNECTION_CLOSE frames
// coalesced into the same datagram. We only want to increase the delay once.
c.lifetime.connCloseDelay *= 2
}
c.lifetime.connCloseSentTime = now
}
// handlePeerConnectionClose handles a CONNECTION_CLOSE from the peer.
func (c *Conn) handlePeerConnectionClose(now time.Time, err error) {
c.setFinalError(err)
switch c.lifetime.state {
case connStateAlive:
c.setState(now, connStatePeerClosed)
case connStatePeerClosed:
// Duplicate CONNECTION_CLOSE, ignore.
case connStateClosing:
if c.lifetime.connCloseSentTime.IsZero() {
c.setState(now, connStatePeerClosed)
} else {
c.setState(now, connStateDraining)
}
case connStateDraining:
case connStateDone:
}
}
// setFinalError records the final connection status we report to the user.
func (c *Conn) setFinalError(err error) {
select {
case <-c.lifetime.donec:
return // already set
default:
}
c.lifetime.finalErr = err
close(c.lifetime.donec)
}
// finalError returns the final connection status reported to the user,
// or nil if a final status has not yet been set.
func (c *Conn) finalError() error {
select {
case <-c.lifetime.donec:
return c.lifetime.finalErr
default:
}
return nil
}
func (c *Conn) waitReady(ctx context.Context) error {
select {
case <-c.lifetime.readyc:
return nil
case <-c.lifetime.donec:
return c.lifetime.finalErr
default:
}
select {
case <-c.lifetime.readyc:
return nil
case <-c.lifetime.donec:
return c.lifetime.finalErr
case <-ctx.Done():
return ctx.Err()
}
}
// Close closes the connection.
//
// Close is equivalent to:
//
// conn.Abort(nil)
// err := conn.Wait(context.Background())
func (c *Conn) Close() error {
c.Abort(nil)
<-c.lifetime.donec
return c.lifetime.finalErr
}
// Wait waits for the peer to close the connection.
//
// If the connection is closed locally and the peer does not close its end of the connection,
// Wait will return with a non-nil error after the drain period expires.
//
// If the peer closes the connection with a NO_ERROR transport error, Wait returns nil.
// If the peer closes the connection with an application error, Wait returns an ApplicationError
// containing the peer's error code and reason.
// If the peer closes the connection with any other status, Wait returns a non-nil error.
func (c *Conn) Wait(ctx context.Context) error {
if err := c.waitOnDone(ctx, c.lifetime.donec); err != nil {
return err
}
return c.lifetime.finalErr
}
// Abort closes the connection and returns immediately.
//
// If err is nil, Abort sends a transport error of NO_ERROR to the peer.
// If err is an ApplicationError, Abort sends its error code and text.
// Otherwise, Abort sends a transport error of APPLICATION_ERROR with the error's text.
func (c *Conn) Abort(err error) {
if err == nil {
err = localTransportError{code: errNo}
}
c.sendMsg(func(now time.Time, c *Conn) {
c.enterClosing(now, err)
})
}
// abort terminates a connection with an error.
func (c *Conn) abort(now time.Time, err error) {
c.setFinalError(err) // this error takes precedence over the peer's CONNECTION_CLOSE
c.enterClosing(now, err)
}
// abortImmediately terminates a connection.
// The connection does not send a CONNECTION_CLOSE, and skips the draining period.
func (c *Conn) abortImmediately(now time.Time, err error) {
c.setFinalError(err)
c.setState(now, connStateDone)
}
// enterClosing starts an immediate close.
// We will send a CONNECTION_CLOSE to the peer and wait for their response.
func (c *Conn) enterClosing(now time.Time, err error) {
switch c.lifetime.state {
case connStateAlive:
c.lifetime.localErr = err
c.setState(now, connStateClosing)
case connStatePeerClosed:
c.lifetime.localErr = err
}
}
// enterDraining moves directly to the draining state, without sending a CONNECTION_CLOSE.
func (c *Conn) enterDraining(now time.Time) {
switch c.lifetime.state {
case connStateAlive, connStatePeerClosed, connStateClosing:
c.setState(now, connStateDraining)
}
}
// exit fully terminates a connection immediately.
func (c *Conn) exit() {
c.sendMsg(func(now time.Time, c *Conn) {
c.abortImmediately(now, errors.New("connection closed"))
})
}
// Copyright 2023 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 quic
import (
"sync/atomic"
"time"
)
// connInflow tracks connection-level flow control for data sent by the peer to us.
//
// There are four byte offsets of significance in the stream of data received from the peer,
// each >= to the previous:
//
// - bytes read by the user
// - bytes received from the peer
// - limit sent to the peer in a MAX_DATA frame
// - potential new limit to sent to the peer
//
// We maintain a flow control window, so as bytes are read by the user
// the potential limit is extended correspondingly.
//
// We keep an atomic counter of bytes read by the user and not yet applied to the
// potential limit (credit). When this count grows large enough, we update the
// new limit to send and mark that we need to send a new MAX_DATA frame.
type connInflow struct {
sent sentVal // set when we need to send a MAX_DATA update to the peer
usedLimit int64 // total bytes sent by the peer, must be less than sentLimit
sentLimit int64 // last MAX_DATA sent to the peer
newLimit int64 // new MAX_DATA to send
credit atomic.Int64 // bytes read but not yet applied to extending the flow-control window
}
func (c *Conn) inflowInit() {
// The initial MAX_DATA limit is sent as a transport parameter.
c.streams.inflow.sentLimit = c.config.maxConnReadBufferSize()
c.streams.inflow.newLimit = c.streams.inflow.sentLimit
}
// handleStreamBytesReadOffLoop records that the user has consumed bytes from a stream.
// We may extend the peer's flow control window.
//
// This is called indirectly by the user, via Read or CloseRead.
func (c *Conn) handleStreamBytesReadOffLoop(n int64) {
if n == 0 {
return
}
if c.shouldUpdateFlowControl(c.streams.inflow.credit.Add(n)) {
// We should send a MAX_DATA update to the peer.
// Record this on the Conn's main loop.
c.sendMsg(func(now time.Time, c *Conn) {
// A MAX_DATA update may have already happened, so check again.
if c.shouldUpdateFlowControl(c.streams.inflow.credit.Load()) {
c.sendMaxDataUpdate()
}
})
}
}
// handleStreamBytesReadOnLoop extends the peer's flow control window after
// data has been discarded due to a RESET_STREAM frame.
//
// This is called on the conn's loop.
func (c *Conn) handleStreamBytesReadOnLoop(n int64) {
if c.shouldUpdateFlowControl(c.streams.inflow.credit.Add(n)) {
c.sendMaxDataUpdate()
}
}
func (c *Conn) sendMaxDataUpdate() {
c.streams.inflow.sent.setUnsent()
// Apply current credit to the limit.
// We don't strictly need to do this here
// since appendMaxDataFrame will do so as well,
// but this avoids redundant trips down this path
// if the MAX_DATA frame doesn't go out right away.
c.streams.inflow.newLimit += c.streams.inflow.credit.Swap(0)
}
func (c *Conn) shouldUpdateFlowControl(credit int64) bool {
return shouldUpdateFlowControl(c.config.maxConnReadBufferSize(), credit)
}
// handleStreamBytesReceived records that the peer has sent us stream data.
func (c *Conn) handleStreamBytesReceived(n int64) error {
c.streams.inflow.usedLimit += n
if c.streams.inflow.usedLimit > c.streams.inflow.sentLimit {
return localTransportError{
code: errFlowControl,
reason: "stream exceeded flow control limit",
}
}
return nil
}
// appendMaxDataFrame appends a MAX_DATA frame to the current packet.
//
// It returns true if no more frames need appending,
// false if it could not fit a frame in the current packet.
func (c *Conn) appendMaxDataFrame(w *packetWriter, pnum packetNumber, pto bool) bool {
if c.streams.inflow.sent.shouldSendPTO(pto) {
// Add any unapplied credit to the new limit now.
c.streams.inflow.newLimit += c.streams.inflow.credit.Swap(0)
if !w.appendMaxDataFrame(c.streams.inflow.newLimit) {
return false
}
c.streams.inflow.sentLimit += c.streams.inflow.newLimit
c.streams.inflow.sent.setSent(pnum)
}
return true
}
// ackOrLossMaxData records the fate of a MAX_DATA frame.
func (c *Conn) ackOrLossMaxData(pnum packetNumber, fate packetFate) {
c.streams.inflow.sent.ackLatestOrLoss(pnum, fate)
}
// connOutflow tracks connection-level flow control for data sent by us to the peer.
type connOutflow struct {
max int64 // largest MAX_DATA received from peer
used int64 // total bytes of STREAM data sent to peer
}
// setMaxData updates the connection-level flow control limit
// with the initial limit conveyed in transport parameters
// or an update from a MAX_DATA frame.
func (f *connOutflow) setMaxData(maxData int64) {
f.max = max(f.max, maxData)
}
// avail returns the number of connection-level flow control bytes available.
func (f *connOutflow) avail() int64 {
return f.max - f.used
}
// consume records consumption of n bytes of flow.
func (f *connOutflow) consume(n int64) {
f.used += n
}
// Copyright 2023 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 quic
import (
"bytes"
"crypto/rand"
"slices"
)
// connIDState is a conn's connection IDs.
type connIDState struct {
// The destination connection IDs of packets we receive are local.
// The destination connection IDs of packets we send are remote.
//
// Local IDs are usually issued by us, and remote IDs by the peer.
// The exception is the transient destination connection ID sent in
// a client's Initial packets, which is chosen by the client.
//
// These are []connID rather than []*connID to minimize allocations.
local []connID
remote []remoteConnID
nextLocalSeq int64
peerActiveConnIDLimit int64 // peer's active_connection_id_limit
// Handling of retirement of remote connection IDs.
// The rangesets track ID sequence numbers.
// IDs in need of retirement are added to remoteRetiring,
// moved to remoteRetiringSent once we send a RETIRE_CONECTION_ID frame,
// and removed from the set once retirement completes.
retireRemotePriorTo int64 // largest Retire Prior To value sent by the peer
remoteRetiring rangeset[int64] // remote IDs in need of retirement
remoteRetiringSent rangeset[int64] // remote IDs waiting for ack of retirement
originalDstConnID []byte // expected original_destination_connection_id param
retrySrcConnID []byte // expected retry_source_connection_id param
needSend bool
}
// A connID is a connection ID and associated metadata.
type connID struct {
// cid is the connection ID itself.
cid []byte
// seq is the connection ID's sequence number:
// https://www.rfc-editor.org/rfc/rfc9000.html#section-5.1.1-1
//
// For the transient destination ID in a client's Initial packet, this is -1.
seq int64
// send is set when the connection ID's state needs to be sent to the peer.
//
// For local IDs, this indicates a new ID that should be sent
// in a NEW_CONNECTION_ID frame.
//
// For remote IDs, this indicates a retired ID that should be sent
// in a RETIRE_CONNECTION_ID frame.
send sentVal
}
// A remoteConnID is a connection ID and stateless reset token.
type remoteConnID struct {
connID
resetToken statelessResetToken
}
func (s *connIDState) initClient(c *Conn) error {
// Client chooses its initial connection ID, and sends it
// in the Source Connection ID field of the first Initial packet.
locid, err := c.newConnID(0)
if err != nil {
return err
}
s.local = append(s.local, connID{
seq: 0,
cid: locid,
})
s.nextLocalSeq = 1
c.endpoint.connsMap.updateConnIDs(func(conns *connsMap) {
conns.addConnID(c, locid)
})
// Client chooses an initial, transient connection ID for the server,
// and sends it in the Destination Connection ID field of the first Initial packet.
remid, err := c.newConnID(-1)
if err != nil {
return err
}
s.remote = append(s.remote, remoteConnID{
connID: connID{
seq: -1,
cid: remid,
},
})
s.originalDstConnID = remid
return nil
}
func (s *connIDState) initServer(c *Conn, cids newServerConnIDs) error {
dstConnID := cloneBytes(cids.dstConnID)
// Client-chosen, transient connection ID received in the first Initial packet.
// The server will not use this as the Source Connection ID of packets it sends,
// but remembers it because it may receive packets sent to this destination.
s.local = append(s.local, connID{
seq: -1,
cid: dstConnID,
})
// Server chooses a connection ID, and sends it in the Source Connection ID of
// the response to the clent.
locid, err := c.newConnID(0)
if err != nil {
return err
}
s.local = append(s.local, connID{
seq: 0,
cid: locid,
})
s.nextLocalSeq = 1
c.endpoint.connsMap.updateConnIDs(func(conns *connsMap) {
conns.addConnID(c, dstConnID)
conns.addConnID(c, locid)
})
// Client chose its own connection ID.
s.remote = append(s.remote, remoteConnID{
connID: connID{
seq: 0,
cid: cloneBytes(cids.srcConnID),
},
})
return nil
}
// srcConnID is the Source Connection ID to use in a sent packet.
func (s *connIDState) srcConnID() []byte {
if s.local[0].seq == -1 && len(s.local) > 1 {
// Don't use the transient connection ID if another is available.
return s.local[1].cid
}
return s.local[0].cid
}
// dstConnID is the Destination Connection ID to use in a sent packet.
func (s *connIDState) dstConnID() (cid []byte, ok bool) {
for i := range s.remote {
return s.remote[i].cid, true
}
return nil, false
}
// isValidStatelessResetToken reports whether the given reset token is
// associated with a non-retired connection ID which we have used.
func (s *connIDState) isValidStatelessResetToken(resetToken statelessResetToken) bool {
if len(s.remote) == 0 {
return false
}
// We currently only use the first available remote connection ID,
// so any other reset token is not valid.
return s.remote[0].resetToken == resetToken
}
// setPeerActiveConnIDLimit sets the active_connection_id_limit
// transport parameter received from the peer.
func (s *connIDState) setPeerActiveConnIDLimit(c *Conn, lim int64) error {
s.peerActiveConnIDLimit = lim
return s.issueLocalIDs(c)
}
func (s *connIDState) issueLocalIDs(c *Conn) error {
toIssue := min(int(s.peerActiveConnIDLimit), maxPeerActiveConnIDLimit)
for i := range s.local {
if s.local[i].seq != -1 {
toIssue--
}
}
var newIDs [][]byte
for toIssue > 0 {
cid, err := c.newConnID(s.nextLocalSeq)
if err != nil {
return err
}
newIDs = append(newIDs, cid)
s.local = append(s.local, connID{
seq: s.nextLocalSeq,
cid: cid,
})
s.local[len(s.local)-1].send.setUnsent()
s.nextLocalSeq++
s.needSend = true
toIssue--
}
c.endpoint.connsMap.updateConnIDs(func(conns *connsMap) {
for _, cid := range newIDs {
conns.addConnID(c, cid)
}
})
return nil
}
// validateTransportParameters verifies the original_destination_connection_id and
// initial_source_connection_id transport parameters match the expected values.
func (s *connIDState) validateTransportParameters(c *Conn, isRetry bool, p transportParameters) error {
// TODO: Consider returning more detailed errors, for debugging.
// Verify original_destination_connection_id matches
// the transient remote connection ID we chose (client)
// or is empty (server).
if !bytes.Equal(s.originalDstConnID, p.originalDstConnID) {
return localTransportError{
code: errTransportParameter,
reason: "original_destination_connection_id mismatch",
}
}
s.originalDstConnID = nil // we have no further need for this
// Verify retry_source_connection_id matches the value from
// the server's Retry packet (when one was sent), or is empty.
if !bytes.Equal(p.retrySrcConnID, s.retrySrcConnID) {
return localTransportError{
code: errTransportParameter,
reason: "retry_source_connection_id mismatch",
}
}
s.retrySrcConnID = nil // we have no further need for this
// Verify initial_source_connection_id matches the first remote connection ID.
if len(s.remote) == 0 || s.remote[0].seq != 0 {
return localTransportError{
code: errInternal,
reason: "remote connection id missing",
}
}
if !bytes.Equal(p.initialSrcConnID, s.remote[0].cid) {
return localTransportError{
code: errTransportParameter,
reason: "initial_source_connection_id mismatch",
}
}
if len(p.statelessResetToken) > 0 {
if c.side == serverSide {
return localTransportError{
code: errTransportParameter,
reason: "client sent stateless_reset_token",
}
}
token := statelessResetToken(p.statelessResetToken)
s.remote[0].resetToken = token
c.endpoint.connsMap.updateConnIDs(func(conns *connsMap) {
conns.addResetToken(c, token)
})
}
return nil
}
// handlePacket updates the connection ID state during the handshake
// (Initial and Handshake packets).
func (s *connIDState) handlePacket(c *Conn, ptype packetType, srcConnID []byte) {
switch {
case ptype == packetTypeInitial && c.side == clientSide:
if len(s.remote) == 1 && s.remote[0].seq == -1 {
// We're a client connection processing the first Initial packet
// from the server. Replace the transient remote connection ID
// with the Source Connection ID from the packet.
s.remote[0] = remoteConnID{
connID: connID{
seq: 0,
cid: cloneBytes(srcConnID),
},
}
}
case ptype == packetTypeHandshake && c.side == serverSide:
if len(s.local) > 0 && s.local[0].seq == -1 {
// We're a server connection processing the first Handshake packet from
// the client. Discard the transient, client-chosen connection ID used
// for Initial packets; the client will never send it again.
cid := s.local[0].cid
c.endpoint.connsMap.updateConnIDs(func(conns *connsMap) {
conns.retireConnID(c, cid)
})
s.local = append(s.local[:0], s.local[1:]...)
}
}
}
func (s *connIDState) handleRetryPacket(srcConnID []byte) {
if len(s.remote) != 1 || s.remote[0].seq != -1 {
panic("BUG: handling retry with non-transient remote conn id")
}
s.retrySrcConnID = cloneBytes(srcConnID)
s.remote[0].cid = s.retrySrcConnID
}
func (s *connIDState) handleNewConnID(c *Conn, seq, retire int64, cid []byte, resetToken statelessResetToken) error {
if len(s.remote[0].cid) == 0 {
// "An endpoint that is sending packets with a zero-length
// Destination Connection ID MUST treat receipt of a NEW_CONNECTION_ID
// frame as a connection error of type PROTOCOL_VIOLATION."
// https://www.rfc-editor.org/rfc/rfc9000.html#section-19.15-6
return localTransportError{
code: errProtocolViolation,
reason: "NEW_CONNECTION_ID from peer with zero-length DCID",
}
}
if seq < s.retireRemotePriorTo {
// This ID was already retired by a previous NEW_CONNECTION_ID frame.
// Nothing to do.
return nil
}
if retire > s.retireRemotePriorTo {
// Add newly-retired connection IDs to the set we need to send
// RETIRE_CONNECTION_ID frames for, and remove them from s.remote.
//
// (This might cause us to send a RETIRE_CONNECTION_ID for an ID we've
// never seen. That's fine.)
s.remoteRetiring.add(s.retireRemotePriorTo, retire)
s.retireRemotePriorTo = retire
s.needSend = true
s.remote = slices.DeleteFunc(s.remote, func(rcid remoteConnID) bool {
return rcid.seq < s.retireRemotePriorTo
})
}
have := false // do we already have this connection ID?
for i := range s.remote {
rcid := &s.remote[i]
if rcid.seq == seq {
if !bytes.Equal(rcid.cid, cid) {
return localTransportError{
code: errProtocolViolation,
reason: "NEW_CONNECTION_ID does not match prior id",
}
}
have = true // yes, we've seen this sequence number
break
}
}
if !have {
// This is a new connection ID that we have not seen before.
//
// We could take steps to keep the list of remote connection IDs
// sorted by sequence number, but there's no particular need
// so we don't bother.
s.remote = append(s.remote, remoteConnID{
connID: connID{
seq: seq,
cid: cloneBytes(cid),
},
resetToken: resetToken,
})
c.endpoint.connsMap.updateConnIDs(func(conns *connsMap) {
conns.addResetToken(c, resetToken)
})
}
if len(s.remote) > activeConnIDLimit {
// Retired connection IDs (including newly-retired ones) do not count
// against the limit.
// https://www.rfc-editor.org/rfc/rfc9000.html#section-5.1.1-5
return localTransportError{
code: errConnectionIDLimit,
reason: "active_connection_id_limit exceeded",
}
}
// "An endpoint SHOULD limit the number of connection IDs it has retired locally
// for which RETIRE_CONNECTION_ID frames have not yet been acknowledged."
// https://www.rfc-editor.org/rfc/rfc9000#section-5.1.2-6
//
// Set a limit of three times the active_connection_id_limit for
// the total number of remote connection IDs we keep retirement state for.
if s.remoteRetiring.size()+s.remoteRetiringSent.size() > 3*activeConnIDLimit {
return localTransportError{
code: errConnectionIDLimit,
reason: "too many unacknowledged retired connection ids",
}
}
return nil
}
func (s *connIDState) handleRetireConnID(c *Conn, seq int64) error {
if seq >= s.nextLocalSeq {
return localTransportError{
code: errProtocolViolation,
reason: "RETIRE_CONNECTION_ID for unissued sequence number",
}
}
for i := range s.local {
if s.local[i].seq == seq {
cid := s.local[i].cid
c.endpoint.connsMap.updateConnIDs(func(conns *connsMap) {
conns.retireConnID(c, cid)
})
s.local = append(s.local[:i], s.local[i+1:]...)
break
}
}
s.issueLocalIDs(c)
return nil
}
func (s *connIDState) ackOrLossNewConnectionID(pnum packetNumber, seq int64, fate packetFate) {
for i := range s.local {
if s.local[i].seq != seq {
continue
}
s.local[i].send.ackOrLoss(pnum, fate)
if fate != packetAcked {
s.needSend = true
}
return
}
}
func (s *connIDState) ackOrLossRetireConnectionID(pnum packetNumber, seq int64, fate packetFate) {
s.remoteRetiringSent.sub(seq, seq+1)
if fate == packetLost {
// RETIRE_CONNECTION_ID frame was lost, mark for retransmission.
s.remoteRetiring.add(seq, seq+1)
s.needSend = true
}
}
// appendFrames appends NEW_CONNECTION_ID and RETIRE_CONNECTION_ID frames
// to the current packet.
//
// It returns true if no more frames need appending,
// false if not everything fit in the current packet.
func (s *connIDState) appendFrames(c *Conn, pnum packetNumber, pto bool) bool {
if !s.needSend && !pto {
// Fast path: We don't need to send anything.
return true
}
retireBefore := int64(0)
if s.local[0].seq != -1 {
retireBefore = s.local[0].seq
}
for i := range s.local {
if !s.local[i].send.shouldSendPTO(pto) {
continue
}
if !c.w.appendNewConnectionIDFrame(
s.local[i].seq,
retireBefore,
s.local[i].cid,
c.endpoint.resetGen.tokenForConnID(s.local[i].cid),
) {
return false
}
s.local[i].send.setSent(pnum)
}
if pto {
for _, r := range s.remoteRetiringSent {
for cid := r.start; cid < r.end; cid++ {
if !c.w.appendRetireConnectionIDFrame(cid) {
return false
}
}
}
}
for s.remoteRetiring.numRanges() > 0 {
cid := s.remoteRetiring.min()
if !c.w.appendRetireConnectionIDFrame(cid) {
return false
}
s.remoteRetiring.sub(cid, cid+1)
s.remoteRetiringSent.add(cid, cid+1)
}
s.needSend = false
return true
}
func cloneBytes(b []byte) []byte {
n := make([]byte, len(b))
copy(n, b)
return n
}
func (c *Conn) newConnID(seq int64) ([]byte, error) {
if c.testHooks != nil {
return c.testHooks.newConnID(seq)
}
return newRandomConnID(seq)
}
func newRandomConnID(_ int64) ([]byte, error) {
// It is not necessary for connection IDs to be cryptographically secure,
// but it doesn't hurt.
id := make([]byte, connIDLen)
if _, err := rand.Read(id); err != nil {
// TODO: Surface this error as a metric or log event or something.
// rand.Read really shouldn't ever fail, but if it does, we should
// have a way to inform the user.
return nil, err
}
return id, nil
}
// Copyright 2023 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 quic
import "fmt"
// handleAckOrLoss deals with the final fate of a packet we sent:
// Either the peer acknowledges it, or we declare it lost.
//
// In order to handle packet loss, we must retain any information sent to the peer
// until the peer has acknowledged it.
//
// When information is acknowledged, we can discard it.
//
// When information is lost, we mark it for retransmission.
// See RFC 9000, Section 13.3 for a complete list of information which is retransmitted on loss.
// https://www.rfc-editor.org/rfc/rfc9000#section-13.3
func (c *Conn) handleAckOrLoss(space numberSpace, sent *sentPacket, fate packetFate) {
if fate == packetLost && c.logEnabled(QLogLevelPacket) {
c.logPacketLost(space, sent)
}
// The list of frames in a sent packet is marshaled into a buffer in the sentPacket
// by the packetWriter. Unmarshal that buffer here. This code must be kept in sync with
// packetWriter.append*.
//
// A sent packet meets its fate (acked or lost) only once, so it's okay to consume
// the sentPacket's buffer here.
for !sent.done() {
switch f := sent.next(); f {
default:
panic(fmt.Sprintf("BUG: unhandled acked/lost frame type %x", f))
case frameTypeAck, frameTypeAckECN:
// Unlike most information, loss of an ACK frame does not trigger
// retransmission. ACKs are sent in response to ack-eliciting packets,
// and always contain the latest information available.
//
// Acknowledgement of an ACK frame may allow us to discard information
// about older packets.
largest := packetNumber(sent.nextInt())
if fate == packetAcked {
c.acks[space].handleAck(largest)
}
case frameTypeCrypto:
start, end := sent.nextRange()
c.crypto[space].ackOrLoss(start, end, fate)
case frameTypeMaxData:
c.ackOrLossMaxData(sent.num, fate)
case frameTypeResetStream,
frameTypeStopSending,
frameTypeMaxStreamData,
frameTypeStreamDataBlocked:
id := streamID(sent.nextInt())
s := c.streamForID(id)
if s == nil {
continue
}
s.ackOrLoss(sent.num, f, fate)
case frameTypeStreamBase,
frameTypeStreamBase | streamFinBit:
id := streamID(sent.nextInt())
start, end := sent.nextRange()
s := c.streamForID(id)
if s == nil {
continue
}
fin := f&streamFinBit != 0
s.ackOrLossData(sent.num, start, end, fin, fate)
case frameTypeMaxStreamsBidi:
c.streams.remoteLimit[bidiStream].sendMax.ackLatestOrLoss(sent.num, fate)
case frameTypeMaxStreamsUni:
c.streams.remoteLimit[uniStream].sendMax.ackLatestOrLoss(sent.num, fate)
case frameTypeNewConnectionID:
seq := int64(sent.nextInt())
c.connIDState.ackOrLossNewConnectionID(sent.num, seq, fate)
case frameTypeRetireConnectionID:
seq := int64(sent.nextInt())
c.connIDState.ackOrLossRetireConnectionID(sent.num, seq, fate)
case frameTypeHandshakeDone:
c.handshakeConfirmed.ackOrLoss(sent.num, fate)
}
}
}
// Copyright 2023 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 quic
import (
"bytes"
"encoding/binary"
"errors"
"time"
)
func (c *Conn) handleDatagram(now time.Time, dgram *datagram) (handled bool) {
if !c.localAddr.IsValid() {
// We don't have any way to tell in the general case what address we're
// sending packets from. Set our address from the destination address of
// the first packet received from the peer.
c.localAddr = dgram.localAddr
}
if dgram.peerAddr.IsValid() && dgram.peerAddr != c.peerAddr {
if c.side == clientSide {
// "If a client receives packets from an unknown server address,
// the client MUST discard these packets."
// https://www.rfc-editor.org/rfc/rfc9000#section-9-6
return false
}
// We currently don't support connection migration,
// so for now the server also drops packets from an unknown address.
return false
}
buf := dgram.b
c.loss.datagramReceived(now, len(buf))
if c.isDraining() {
return false
}
for len(buf) > 0 {
var n int
ptype := getPacketType(buf)
switch ptype {
case packetTypeInitial:
if c.side == serverSide && len(dgram.b) < paddedInitialDatagramSize {
// Discard client-sent Initial packets in too-short datagrams.
// https://www.rfc-editor.org/rfc/rfc9000#section-14.1-4
return false
}
n = c.handleLongHeader(now, dgram, ptype, initialSpace, c.keysInitial.r, buf)
case packetTypeHandshake:
n = c.handleLongHeader(now, dgram, ptype, handshakeSpace, c.keysHandshake.r, buf)
case packetType1RTT:
n = c.handle1RTT(now, dgram, buf)
case packetTypeRetry:
c.handleRetry(now, buf)
return true
case packetTypeVersionNegotiation:
c.handleVersionNegotiation(now, buf)
return true
default:
n = -1
}
if n <= 0 {
// We don't expect to get a stateless reset with a valid
// destination connection ID, since the sender of a stateless
// reset doesn't know what the connection ID is.
//
// We're required to perform this check anyway.
//
// "[...] the comparison MUST be performed when the first packet
// in an incoming datagram [...] cannot be decrypted."
// https://www.rfc-editor.org/rfc/rfc9000#section-10.3.1-2
if len(buf) == len(dgram.b) && len(buf) > statelessResetTokenLen {
var token statelessResetToken
copy(token[:], buf[len(buf)-len(token):])
if c.handleStatelessReset(now, token) {
return true
}
}
// Invalid data at the end of a datagram is ignored.
return false
}
c.idleHandlePacketReceived(now)
buf = buf[n:]
}
return true
}
func (c *Conn) handleLongHeader(now time.Time, dgram *datagram, ptype packetType, space numberSpace, k fixedKeys, buf []byte) int {
if !k.isSet() {
return skipLongHeaderPacket(buf)
}
pnumMax := c.acks[space].largestSeen()
p, n := parseLongHeaderPacket(buf, k, pnumMax)
if n < 0 {
return -1
}
if buf[0]&reservedLongBits != 0 {
// Reserved header bits must be 0.
// https://www.rfc-editor.org/rfc/rfc9000#section-17.2-8.2.1
c.abort(now, localTransportError{
code: errProtocolViolation,
reason: "reserved header bits are not zero",
})
return -1
}
if p.version != quicVersion1 {
// The peer has changed versions on us mid-handshake?
c.abort(now, localTransportError{
code: errProtocolViolation,
reason: "protocol version changed during handshake",
})
return -1
}
if !c.acks[space].shouldProcess(p.num) {
return n
}
if logPackets {
logInboundLongPacket(c, p)
}
if c.logEnabled(QLogLevelPacket) {
c.logLongPacketReceived(p, buf[:n])
}
c.connIDState.handlePacket(c, p.ptype, p.srcConnID)
ackEliciting := c.handleFrames(now, dgram, ptype, space, p.payload)
c.acks[space].receive(now, space, p.num, ackEliciting, dgram.ecn)
if p.ptype == packetTypeHandshake && c.side == serverSide {
c.loss.validateClientAddress()
// "[...] a server MUST discard Initial keys when it first successfully
// processes a Handshake packet [...]"
// https://www.rfc-editor.org/rfc/rfc9001#section-4.9.1-2
c.discardKeys(now, initialSpace)
}
return n
}
func (c *Conn) handle1RTT(now time.Time, dgram *datagram, buf []byte) int {
if !c.keysAppData.canRead() {
// 1-RTT packets extend to the end of the datagram,
// so skip the remainder of the datagram if we can't parse this.
return len(buf)
}
pnumMax := c.acks[appDataSpace].largestSeen()
p, err := parse1RTTPacket(buf, &c.keysAppData, connIDLen, pnumMax)
if err != nil {
// A localTransportError terminates the connection.
// Other errors indicate an unparsable packet, but otherwise may be ignored.
if _, ok := err.(localTransportError); ok {
c.abort(now, err)
}
return -1
}
if buf[0]&reserved1RTTBits != 0 {
// Reserved header bits must be 0.
// https://www.rfc-editor.org/rfc/rfc9000#section-17.3.1-4.8.1
c.abort(now, localTransportError{
code: errProtocolViolation,
reason: "reserved header bits are not zero",
})
return -1
}
if !c.acks[appDataSpace].shouldProcess(p.num) {
return len(buf)
}
if logPackets {
logInboundShortPacket(c, p)
}
if c.logEnabled(QLogLevelPacket) {
c.log1RTTPacketReceived(p, buf)
}
ackEliciting := c.handleFrames(now, dgram, packetType1RTT, appDataSpace, p.payload)
c.acks[appDataSpace].receive(now, appDataSpace, p.num, ackEliciting, dgram.ecn)
return len(buf)
}
func (c *Conn) handleRetry(now time.Time, pkt []byte) {
if c.side != clientSide {
return // clients don't send Retry packets
}
// "After the client has received and processed an Initial or Retry packet
// from the server, it MUST discard any subsequent Retry packets that it receives."
// https://www.rfc-editor.org/rfc/rfc9000#section-17.2.5.2-1
if !c.keysInitial.canRead() {
return // discarded Initial keys, connection is already established
}
if c.acks[initialSpace].seen.numRanges() != 0 {
return // processed at least one packet
}
if c.retryToken != nil {
return // received a Retry already
}
// "Clients MUST discard Retry packets that have a Retry Integrity Tag
// that cannot be validated."
// https://www.rfc-editor.org/rfc/rfc9000#section-17.2.5.2-2
p, ok := parseRetryPacket(pkt, c.connIDState.originalDstConnID)
if !ok {
return
}
// "A client MUST discard a Retry packet with a zero-length Retry Token field."
// https://www.rfc-editor.org/rfc/rfc9000#section-17.2.5.2-2
if len(p.token) == 0 {
return
}
c.retryToken = cloneBytes(p.token)
c.connIDState.handleRetryPacket(p.srcConnID)
c.keysInitial = initialKeys(p.srcConnID, c.side)
// We need to resend any data we've already sent in Initial packets.
// We must not reuse already sent packet numbers.
c.loss.discardPackets(initialSpace, c.log, c.handleAckOrLoss)
// TODO: Discard 0-RTT packets as well, once we support 0-RTT.
if c.testHooks != nil {
c.testHooks.init(false)
}
}
var errVersionNegotiation = errors.New("server does not support QUIC version 1")
func (c *Conn) handleVersionNegotiation(now time.Time, pkt []byte) {
if c.side != clientSide {
return // servers don't handle Version Negotiation packets
}
// "A client MUST discard any Version Negotiation packet if it has
// received and successfully processed any other packet [...]"
// https://www.rfc-editor.org/rfc/rfc9000#section-6.2-2
if !c.keysInitial.canRead() {
return // discarded Initial keys, connection is already established
}
if c.acks[initialSpace].seen.numRanges() != 0 {
return // processed at least one packet
}
_, srcConnID, versions := parseVersionNegotiation(pkt)
if len(c.connIDState.remote) < 1 || !bytes.Equal(c.connIDState.remote[0].cid, srcConnID) {
return // Source Connection ID doesn't match what we sent
}
for len(versions) >= 4 {
ver := binary.BigEndian.Uint32(versions)
if ver == 1 {
// "A client MUST discard a Version Negotiation packet that lists
// the QUIC version selected by the client."
// https://www.rfc-editor.org/rfc/rfc9000#section-6.2-2
return
}
versions = versions[4:]
}
// "A client that supports only this version of QUIC MUST
// abandon the current connection attempt if it receives
// a Version Negotiation packet, [with the two exceptions handled above]."
// https://www.rfc-editor.org/rfc/rfc9000#section-6.2-2
c.abortImmediately(now, errVersionNegotiation)
}
func (c *Conn) handleFrames(now time.Time, dgram *datagram, ptype packetType, space numberSpace, payload []byte) (ackEliciting bool) {
if len(payload) == 0 {
// "An endpoint MUST treat receipt of a packet containing no frames
// as a connection error of type PROTOCOL_VIOLATION."
// https://www.rfc-editor.org/rfc/rfc9000#section-12.4-3
c.abort(now, localTransportError{
code: errProtocolViolation,
reason: "packet contains no frames",
})
return false
}
// frameOK verifies that ptype is one of the packets in mask.
frameOK := func(c *Conn, ptype, mask packetType) (ok bool) {
if ptype&mask == 0 {
// "An endpoint MUST treat receipt of a frame in a packet type
// that is not permitted as a connection error of type
// PROTOCOL_VIOLATION."
// https://www.rfc-editor.org/rfc/rfc9000#section-12.4-3
c.abort(now, localTransportError{
code: errProtocolViolation,
reason: "frame not allowed in packet",
})
return false
}
return true
}
// Packet masks from RFC 9000 Table 3.
// https://www.rfc-editor.org/rfc/rfc9000#table-3
const (
IH_1 = packetTypeInitial | packetTypeHandshake | packetType1RTT
__01 = packetType0RTT | packetType1RTT
___1 = packetType1RTT
)
hasCrypto := false
for len(payload) > 0 {
switch payload[0] {
case frameTypePadding, frameTypeAck, frameTypeAckECN,
frameTypeConnectionCloseTransport, frameTypeConnectionCloseApplication:
default:
ackEliciting = true
}
n := -1
switch payload[0] {
case frameTypePadding:
// PADDING is OK in all spaces.
n = 1
case frameTypePing:
// PING is OK in all spaces.
//
// A PING frame causes us to respond with an ACK by virtue of being
// an ack-eliciting frame, but requires no other action.
n = 1
case frameTypeAck, frameTypeAckECN:
if !frameOK(c, ptype, IH_1) {
return
}
n = c.handleAckFrame(now, space, payload)
case frameTypeResetStream:
if !frameOK(c, ptype, __01) {
return
}
n = c.handleResetStreamFrame(now, space, payload)
case frameTypeStopSending:
if !frameOK(c, ptype, __01) {
return
}
n = c.handleStopSendingFrame(now, space, payload)
case frameTypeCrypto:
if !frameOK(c, ptype, IH_1) {
return
}
hasCrypto = true
n = c.handleCryptoFrame(now, space, payload)
case frameTypeNewToken:
if !frameOK(c, ptype, ___1) {
return
}
_, n = consumeNewTokenFrame(payload)
case 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f: // STREAM
if !frameOK(c, ptype, __01) {
return
}
n = c.handleStreamFrame(now, space, payload)
case frameTypeMaxData:
if !frameOK(c, ptype, __01) {
return
}
n = c.handleMaxDataFrame(now, payload)
case frameTypeMaxStreamData:
if !frameOK(c, ptype, __01) {
return
}
n = c.handleMaxStreamDataFrame(now, payload)
case frameTypeMaxStreamsBidi, frameTypeMaxStreamsUni:
if !frameOK(c, ptype, __01) {
return
}
n = c.handleMaxStreamsFrame(now, payload)
case frameTypeDataBlocked:
if !frameOK(c, ptype, __01) {
return
}
_, n = consumeDataBlockedFrame(payload)
case frameTypeStreamsBlockedBidi, frameTypeStreamsBlockedUni:
if !frameOK(c, ptype, __01) {
return
}
_, _, n = consumeStreamsBlockedFrame(payload)
case frameTypeStreamDataBlocked:
if !frameOK(c, ptype, __01) {
return
}
_, _, n = consumeStreamDataBlockedFrame(payload)
case frameTypeNewConnectionID:
if !frameOK(c, ptype, __01) {
return
}
n = c.handleNewConnectionIDFrame(now, space, payload)
case frameTypeRetireConnectionID:
if !frameOK(c, ptype, __01) {
return
}
n = c.handleRetireConnectionIDFrame(now, space, payload)
case frameTypePathChallenge:
if !frameOK(c, ptype, __01) {
return
}
n = c.handlePathChallengeFrame(now, dgram, space, payload)
case frameTypePathResponse:
if !frameOK(c, ptype, ___1) {
return
}
n = c.handlePathResponseFrame(now, space, payload)
case frameTypeConnectionCloseTransport:
// Transport CONNECTION_CLOSE is OK in all spaces.
n = c.handleConnectionCloseTransportFrame(now, payload)
case frameTypeConnectionCloseApplication:
if !frameOK(c, ptype, __01) {
return
}
n = c.handleConnectionCloseApplicationFrame(now, payload)
case frameTypeHandshakeDone:
if !frameOK(c, ptype, ___1) {
return
}
n = c.handleHandshakeDoneFrame(now, space, payload)
}
if n < 0 {
c.abort(now, localTransportError{
code: errFrameEncoding,
reason: "frame encoding error",
})
return false
}
payload = payload[n:]
}
if hasCrypto {
// Process TLS events after handling all frames in a packet.
// TLS events can cause us to drop state for a number space,
// so do that last, to avoid handling frames differently
// depending on whether they come before or after a CRYPTO frame.
if err := c.handleTLSEvents(now); err != nil {
c.abort(now, err)
}
}
return ackEliciting
}
func (c *Conn) handleAckFrame(now time.Time, space numberSpace, payload []byte) int {
c.loss.receiveAckStart()
largest, ackDelay, ecn, n := consumeAckFrame(payload, func(rangeIndex int, start, end packetNumber) {
if err := c.loss.receiveAckRange(now, space, rangeIndex, start, end, c.handleAckOrLoss); err != nil {
c.abort(now, err)
return
}
})
// TODO: Make use of ECN feedback.
// https://www.rfc-editor.org/rfc/rfc9000.html#section-19.3.2
_ = ecn
// Prior to receiving the peer's transport parameters, we cannot
// interpret the ACK Delay field because we don't know the ack_delay_exponent
// to apply.
//
// For servers, we should always know the ack_delay_exponent because the
// client's transport parameters are carried in its Initial packets and we
// won't send an ack-eliciting Initial packet until after receiving the last
// client Initial packet.
//
// For clients, we won't receive the server's transport parameters until handling
// its Handshake flight, which will probably happen after reading its ACK for our
// Initial packet(s). However, the peer's acknowledgement delay cannot reduce our
// adjusted RTT sample below min_rtt, and min_rtt is generally going to be set
// by the packet containing the ACK for our Initial flight. Therefore, the
// ACK Delay for an ACK in the Initial space is likely to be ignored anyway.
//
// Long story short, setting the delay to 0 prior to reading transport parameters
// is usually going to have no effect, will have only a minor effect in the rare
// cases when it happens, and there aren't any good alternatives anyway since we
// can't interpret the ACK Delay field without knowing the exponent.
var delay time.Duration
if c.peerAckDelayExponent >= 0 {
delay = ackDelay.Duration(uint8(c.peerAckDelayExponent))
}
c.loss.receiveAckEnd(now, c.log, space, delay, c.handleAckOrLoss)
if space == appDataSpace {
c.keysAppData.handleAckFor(largest)
}
return n
}
func (c *Conn) handleMaxDataFrame(now time.Time, payload []byte) int {
maxData, n := consumeMaxDataFrame(payload)
if n < 0 {
return -1
}
c.streams.outflow.setMaxData(maxData)
return n
}
func (c *Conn) handleMaxStreamDataFrame(now time.Time, payload []byte) int {
id, maxStreamData, n := consumeMaxStreamDataFrame(payload)
if n < 0 {
return -1
}
if s := c.streamForFrame(now, id, sendStream); s != nil {
if err := s.handleMaxStreamData(maxStreamData); err != nil {
c.abort(now, err)
return -1
}
}
return n
}
func (c *Conn) handleMaxStreamsFrame(now time.Time, payload []byte) int {
styp, max, n := consumeMaxStreamsFrame(payload)
if n < 0 {
return -1
}
c.streams.localLimit[styp].setMax(max)
return n
}
func (c *Conn) handleResetStreamFrame(now time.Time, space numberSpace, payload []byte) int {
id, code, finalSize, n := consumeResetStreamFrame(payload)
if n < 0 {
return -1
}
if s := c.streamForFrame(now, id, recvStream); s != nil {
if err := s.handleReset(code, finalSize); err != nil {
c.abort(now, err)
}
}
return n
}
func (c *Conn) handleStopSendingFrame(now time.Time, space numberSpace, payload []byte) int {
id, code, n := consumeStopSendingFrame(payload)
if n < 0 {
return -1
}
if s := c.streamForFrame(now, id, sendStream); s != nil {
if err := s.handleStopSending(code); err != nil {
c.abort(now, err)
}
}
return n
}
func (c *Conn) handleCryptoFrame(now time.Time, space numberSpace, payload []byte) int {
off, data, n := consumeCryptoFrame(payload)
err := c.handleCrypto(now, space, off, data)
if err != nil {
c.abort(now, err)
return -1
}
return n
}
func (c *Conn) handleStreamFrame(now time.Time, space numberSpace, payload []byte) int {
id, off, fin, b, n := consumeStreamFrame(payload)
if n < 0 {
return -1
}
if s := c.streamForFrame(now, id, recvStream); s != nil {
if err := s.handleData(off, b, fin); err != nil {
c.abort(now, err)
}
}
return n
}
func (c *Conn) handleNewConnectionIDFrame(now time.Time, space numberSpace, payload []byte) int {
seq, retire, connID, resetToken, n := consumeNewConnectionIDFrame(payload)
if n < 0 {
return -1
}
if err := c.connIDState.handleNewConnID(c, seq, retire, connID, resetToken); err != nil {
c.abort(now, err)
}
return n
}
func (c *Conn) handleRetireConnectionIDFrame(now time.Time, space numberSpace, payload []byte) int {
seq, n := consumeRetireConnectionIDFrame(payload)
if n < 0 {
return -1
}
if err := c.connIDState.handleRetireConnID(c, seq); err != nil {
c.abort(now, err)
}
return n
}
func (c *Conn) handlePathChallengeFrame(now time.Time, dgram *datagram, space numberSpace, payload []byte) int {
data, n := consumePathChallengeFrame(payload)
if n < 0 {
return -1
}
c.handlePathChallenge(now, dgram, data)
return n
}
func (c *Conn) handlePathResponseFrame(now time.Time, space numberSpace, payload []byte) int {
data, n := consumePathResponseFrame(payload)
if n < 0 {
return -1
}
c.handlePathResponse(now, data)
return n
}
func (c *Conn) handleConnectionCloseTransportFrame(now time.Time, payload []byte) int {
code, _, reason, n := consumeConnectionCloseTransportFrame(payload)
if n < 0 {
return -1
}
c.handlePeerConnectionClose(now, peerTransportError{code: code, reason: reason})
return n
}
func (c *Conn) handleConnectionCloseApplicationFrame(now time.Time, payload []byte) int {
code, reason, n := consumeConnectionCloseApplicationFrame(payload)
if n < 0 {
return -1
}
c.handlePeerConnectionClose(now, &ApplicationError{Code: code, Reason: reason})
return n
}
func (c *Conn) handleHandshakeDoneFrame(now time.Time, space numberSpace, payload []byte) int {
if c.side == serverSide {
// Clients should never send HANDSHAKE_DONE.
// https://www.rfc-editor.org/rfc/rfc9000#section-19.20-4
c.abort(now, localTransportError{
code: errProtocolViolation,
reason: "client sent HANDSHAKE_DONE",
})
return -1
}
if c.isAlive() {
c.confirmHandshake(now)
}
return 1
}
var errStatelessReset = errors.New("received stateless reset")
func (c *Conn) handleStatelessReset(now time.Time, resetToken statelessResetToken) (valid bool) {
if !c.connIDState.isValidStatelessResetToken(resetToken) {
return false
}
c.setFinalError(errStatelessReset)
c.enterDraining(now)
return true
}
// Copyright 2023 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 quic
import (
"crypto/tls"
"errors"
"time"
)
// maybeSend sends datagrams, if possible.
//
// If sending is blocked by pacing, it returns the next time
// a datagram may be sent.
//
// If sending is blocked indefinitely, it returns the zero Time.
func (c *Conn) maybeSend(now time.Time) (next time.Time) {
// Assumption: The congestion window is not underutilized.
// If congestion control, pacing, and anti-amplification all permit sending,
// but we have no packet to send, then we will declare the window underutilized.
underutilized := false
defer func() {
c.loss.cc.setUnderutilized(c.log, underutilized)
}()
// Send one datagram on each iteration of this loop,
// until we hit a limit or run out of data to send.
//
// For each number space where we have write keys,
// attempt to construct a packet in that space.
// If the packet contains no frames (we have no data in need of sending),
// abandon the packet.
//
// Speculatively constructing packets means we don't need
// separate code paths for "do we have data to send?" and
// "send the data" that need to be kept in sync.
for {
limit, next := c.loss.sendLimit(now)
if limit == ccBlocked {
// If anti-amplification blocks sending, then no packet can be sent.
return next
}
if !c.sendOK(now) {
return time.Time{}
}
// We may still send ACKs, even if congestion control or pacing limit sending.
// Prepare to write a datagram of at most maxSendSize bytes.
c.w.reset(c.loss.maxSendSize())
dstConnID, ok := c.connIDState.dstConnID()
if !ok {
// It is currently not possible for us to end up without a connection ID,
// but handle the case anyway.
return time.Time{}
}
// Initial packet.
pad := false
var sentInitial *sentPacket
if c.keysInitial.canWrite() {
pnumMaxAcked := c.loss.spaces[initialSpace].maxAcked
pnum := c.loss.nextNumber(initialSpace)
p := longPacket{
ptype: packetTypeInitial,
version: quicVersion1,
num: pnum,
dstConnID: dstConnID,
srcConnID: c.connIDState.srcConnID(),
extra: c.retryToken,
}
c.w.startProtectedLongHeaderPacket(pnumMaxAcked, p)
c.appendFrames(now, initialSpace, pnum, limit)
if logPackets {
logSentPacket(c, packetTypeInitial, pnum, p.srcConnID, p.dstConnID, c.w.payload())
}
if c.logEnabled(QLogLevelPacket) && len(c.w.payload()) > 0 {
c.logPacketSent(packetTypeInitial, pnum, p.srcConnID, p.dstConnID, c.w.packetLen(), c.w.payload())
}
sentInitial = c.w.finishProtectedLongHeaderPacket(pnumMaxAcked, c.keysInitial.w, p)
if sentInitial != nil {
// Client initial packets and ack-eliciting server initial packaets
// need to be sent in a datagram padded to at least 1200 bytes.
// We can't add the padding yet, however, since we may want to
// coalesce additional packets with this one.
if c.side == clientSide || sentInitial.ackEliciting {
pad = true
}
}
}
// Handshake packet.
if c.keysHandshake.canWrite() {
pnumMaxAcked := c.loss.spaces[handshakeSpace].maxAcked
pnum := c.loss.nextNumber(handshakeSpace)
p := longPacket{
ptype: packetTypeHandshake,
version: quicVersion1,
num: pnum,
dstConnID: dstConnID,
srcConnID: c.connIDState.srcConnID(),
}
c.w.startProtectedLongHeaderPacket(pnumMaxAcked, p)
c.appendFrames(now, handshakeSpace, pnum, limit)
if logPackets {
logSentPacket(c, packetTypeHandshake, pnum, p.srcConnID, p.dstConnID, c.w.payload())
}
if c.logEnabled(QLogLevelPacket) && len(c.w.payload()) > 0 {
c.logPacketSent(packetTypeHandshake, pnum, p.srcConnID, p.dstConnID, c.w.packetLen(), c.w.payload())
}
if sent := c.w.finishProtectedLongHeaderPacket(pnumMaxAcked, c.keysHandshake.w, p); sent != nil {
c.packetSent(now, handshakeSpace, sent)
if c.side == clientSide {
// "[...] a client MUST discard Initial keys when it first
// sends a Handshake packet [...]"
// https://www.rfc-editor.org/rfc/rfc9001.html#section-4.9.1-2
c.discardKeys(now, initialSpace)
}
}
}
// 1-RTT packet.
if c.keysAppData.canWrite() {
pnumMaxAcked := c.loss.spaces[appDataSpace].maxAcked
pnum := c.loss.nextNumber(appDataSpace)
c.w.start1RTTPacket(pnum, pnumMaxAcked, dstConnID)
c.appendFrames(now, appDataSpace, pnum, limit)
if pad && len(c.w.payload()) > 0 {
// 1-RTT packets have no length field and extend to the end
// of the datagram, so if we're sending a datagram that needs
// padding we need to add it inside the 1-RTT packet.
c.w.appendPaddingTo(paddedInitialDatagramSize)
pad = false
}
if logPackets {
logSentPacket(c, packetType1RTT, pnum, nil, dstConnID, c.w.payload())
}
if c.logEnabled(QLogLevelPacket) && len(c.w.payload()) > 0 {
c.logPacketSent(packetType1RTT, pnum, nil, dstConnID, c.w.packetLen(), c.w.payload())
}
if sent := c.w.finish1RTTPacket(pnum, pnumMaxAcked, dstConnID, &c.keysAppData); sent != nil {
c.packetSent(now, appDataSpace, sent)
if c.skip.shouldSkip(pnum + 1) {
c.loss.skipNumber(now, appDataSpace)
c.skip.updateNumberSkip(c)
}
}
}
buf := c.w.datagram()
if len(buf) == 0 {
if limit == ccOK {
// We have nothing to send, and congestion control does not
// block sending. The congestion window is underutilized.
underutilized = true
}
return next
}
if sentInitial != nil {
if pad {
// Pad out the datagram with zeros, coalescing the Initial
// packet with invalid packets that will be ignored by the peer.
// https://www.rfc-editor.org/rfc/rfc9000.html#section-14.1-1
for len(buf) < paddedInitialDatagramSize {
buf = append(buf, 0)
// Technically this padding isn't in any packet, but
// account it to the Initial packet in this datagram
// for purposes of flow control and loss recovery.
sentInitial.size++
sentInitial.inFlight = true
}
}
// If we're a client and this Initial packet is coalesced
// with a Handshake packet, then we've discarded Initial keys
// since constructing the packet and shouldn't record it as in-flight.
if c.keysInitial.canWrite() {
c.packetSent(now, initialSpace, sentInitial)
}
}
c.endpoint.sendDatagram(datagram{
b: buf,
peerAddr: c.peerAddr,
})
}
}
func (c *Conn) packetSent(now time.Time, space numberSpace, sent *sentPacket) {
c.idleHandlePacketSent(now, sent)
c.loss.packetSent(now, c.log, space, sent)
}
func (c *Conn) appendFrames(now time.Time, space numberSpace, pnum packetNumber, limit ccLimit) {
if c.lifetime.localErr != nil {
c.appendConnectionCloseFrame(now, space, c.lifetime.localErr)
return
}
shouldSendAck := c.acks[space].shouldSendAck(now)
if limit != ccOK {
// ACKs are not limited by congestion control.
if shouldSendAck && c.appendAckFrame(now, space) {
c.acks[space].sentAck()
}
return
}
// We want to send an ACK frame if the ack controller wants to send a frame now,
// OR if we are sending a packet anyway and have ack-eliciting packets which we
// have not yet acked.
//
// We speculatively add ACK frames here, to put them at the front of the packet
// to avoid truncation.
//
// After adding all frames, if we don't need to send an ACK frame and have not
// added any other frames, we abandon the packet.
if c.appendAckFrame(now, space) {
defer func() {
// All frames other than ACK and PADDING are ack-eliciting,
// so if the packet is ack-eliciting we've added additional
// frames to it.
if !shouldSendAck && !c.w.sent.ackEliciting {
// There's nothing in this packet but ACK frames, and
// we don't want to send an ACK-only packet at this time.
// Abandoning the packet means we wrote an ACK frame for
// nothing, but constructing the frame is cheap.
c.w.abandonPacket()
return
}
// Either we are willing to send an ACK-only packet,
// or we've added additional frames.
c.acks[space].sentAck()
if !c.w.sent.ackEliciting && c.shouldMakePacketAckEliciting() {
c.w.appendPingFrame()
}
}()
}
if limit != ccOK {
return
}
pto := c.loss.ptoExpired
// TODO: Add all the other frames we can send.
// CRYPTO
c.crypto[space].dataToSend(pto, func(off, size int64) int64 {
b, _ := c.w.appendCryptoFrame(off, int(size))
c.crypto[space].sendData(off, b)
return int64(len(b))
})
// Test-only PING frames.
if space == c.testSendPingSpace && c.testSendPing.shouldSendPTO(pto) {
if !c.w.appendPingFrame() {
return
}
c.testSendPing.setSent(pnum)
}
if space == appDataSpace {
// HANDSHAKE_DONE
if c.handshakeConfirmed.shouldSendPTO(pto) {
if !c.w.appendHandshakeDoneFrame() {
return
}
c.handshakeConfirmed.setSent(pnum)
}
// NEW_CONNECTION_ID, RETIRE_CONNECTION_ID
if !c.connIDState.appendFrames(c, pnum, pto) {
return
}
// PATH_RESPONSE
if pad, ok := c.appendPathFrames(); !ok {
return
} else if pad {
defer c.w.appendPaddingTo(smallestMaxDatagramSize)
}
// All stream-related frames. This should come last in the packet,
// so large amounts of STREAM data don't crowd out other frames
// we may need to send.
if !c.appendStreamFrames(&c.w, pnum, pto) {
return
}
if !c.appendKeepAlive(now) {
return
}
}
// If this is a PTO probe and we haven't added an ack-eliciting frame yet,
// add a PING to make this an ack-eliciting probe.
//
// Technically, there are separate PTO timers for each number space.
// When a PTO timer expires, we MUST send an ack-eliciting packet in the
// timer's space. We SHOULD send ack-eliciting packets in every other space
// with in-flight data. (RFC 9002, section 6.2.4)
//
// What we actually do is send a single datagram containing an ack-eliciting packet
// for every space for which we have keys.
//
// We fill the PTO probe packets with new or unacknowledged data. For example,
// a PTO probe sent for the Initial space will generally retransmit previously
// sent but unacknowledged CRYPTO data.
//
// When sending a PTO probe datagram containing multiple packets, it is
// possible that an earlier packet will fill up the datagram, leaving no
// space for the remaining probe packet(s). This is not a problem in practice.
//
// A client discards Initial keys when it first sends a Handshake packet
// (RFC 9001 Section 4.9.1). Handshake keys are discarded when the handshake
// is confirmed (RFC 9001 Section 4.9.2). The PTO timer is not set for the
// Application Data packet number space until the handshake is confirmed
// (RFC 9002 Section 6.2.1). Therefore, the only times a PTO probe can fire
// while data for multiple spaces is in flight are:
//
// - a server's Initial or Handshake timers can fire while Initial and Handshake
// data is in flight; and
//
// - a client's Handshake timer can fire while Handshake and Application Data
// data is in flight.
//
// It is theoretically possible for a server's Initial CRYPTO data to overflow
// the maximum datagram size, but unlikely in practice; this space contains
// only the ServerHello TLS message, which is small. It's also unlikely that
// the Handshake PTO probe will fire while Initial data is in flight (this
// requires not just that the Initial CRYPTO data completely fill a datagram,
// but a quite specific arrangement of lost and retransmitted packets.)
// We don't bother worrying about this case here, since the worst case is
// that we send a PTO probe for the in-flight Initial data and drop the
// Handshake probe.
//
// If a client's Handshake PTO timer fires while Application Data data is in
// flight, it is possible that the resent Handshake CRYPTO data will crowd
// out the probe for the Application Data space. However, since this probe is
// optional (recall that the Application Data PTO timer is never set until
// after Handshake keys have been discarded), dropping it is acceptable.
if pto && !c.w.sent.ackEliciting {
c.w.appendPingFrame()
}
}
// shouldMakePacketAckEliciting is called when sending a packet containing nothing but an ACK frame.
// It reports whether we should add a PING frame to the packet to make it ack-eliciting.
func (c *Conn) shouldMakePacketAckEliciting() bool {
if c.keysAppData.needAckEliciting() {
// The peer has initiated a key update.
// We haven't sent them any packets yet in the new phase.
// Make this an ack-eliciting packet.
// Their ack of this packet will complete the key update.
return true
}
if c.loss.consecutiveNonAckElicitingPackets >= 19 {
// We've sent a run of non-ack-eliciting packets.
// Add in an ack-eliciting one every once in a while so the peer
// lets us know which ones have arrived.
//
// Google QUICHE injects a PING after sending 19 packets. We do the same.
//
// https://www.rfc-editor.org/rfc/rfc9000#section-13.2.4-2
return true
}
// TODO: Consider making every packet sent when in PTO ack-eliciting to speed up recovery.
return false
}
func (c *Conn) appendAckFrame(now time.Time, space numberSpace) bool {
seen, delay := c.acks[space].acksToSend(now)
if len(seen) == 0 {
return false
}
d := unscaledAckDelayFromDuration(delay, ackDelayExponent)
return c.w.appendAckFrame(seen, d, c.acks[space].ecn)
}
func (c *Conn) appendConnectionCloseFrame(now time.Time, space numberSpace, err error) {
c.sentConnectionClose(now)
switch e := err.(type) {
case localTransportError:
c.w.appendConnectionCloseTransportFrame(e.code, 0, e.reason)
case *ApplicationError:
if space != appDataSpace {
// "CONNECTION_CLOSE frames signaling application errors (type 0x1d)
// MUST only appear in the application data packet number space."
// https://www.rfc-editor.org/rfc/rfc9000#section-12.5-2.2
c.w.appendConnectionCloseTransportFrame(errApplicationError, 0, "")
} else {
c.w.appendConnectionCloseApplicationFrame(e.Code, e.Reason)
}
default:
// TLS alerts are sent using error codes [0x0100,0x01ff).
// https://www.rfc-editor.org/rfc/rfc9000#section-20.1-2.36.1
var alert tls.AlertError
switch {
case errors.As(err, &alert):
// tls.AlertError is a uint8, so this can't exceed 0x01ff.
code := errTLSBase + transportError(alert)
c.w.appendConnectionCloseTransportFrame(code, 0, "")
default:
c.w.appendConnectionCloseTransportFrame(errInternal, 0, "")
}
}
}
// Copyright 2023 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 quic
import (
"context"
"sync"
"sync/atomic"
"time"
)
type streamsState struct {
queue queue[*Stream] // new, peer-created streams
// All peer-created streams.
//
// Implicitly created streams are included as an empty entry in the map.
// (For example, if we receive a frame for stream 4, we implicitly create stream 0 and
// insert an empty entry for it to the map.)
//
// The map value is maybeStream rather than *Stream as a reminder that values can be nil.
streams map[streamID]maybeStream
// Limits on the number of streams, indexed by streamType.
localLimit [streamTypeCount]localStreamLimits
remoteLimit [streamTypeCount]remoteStreamLimits
// Peer configuration provided in transport parameters.
peerInitialMaxStreamDataRemote [streamTypeCount]int64 // streams opened by us
peerInitialMaxStreamDataBidiLocal int64 // streams opened by them
// Connection-level flow control.
inflow connInflow
outflow connOutflow
// Streams with frames to send are stored in one of two circular linked lists,
// depending on whether they require connection-level flow control.
needSend atomic.Bool
sendMu sync.Mutex
queueMeta streamRing // streams with any non-flow-controlled frames
queueData streamRing // streams with only flow-controlled frames
}
// maybeStream is a possibly nil *Stream. See streamsState.streams.
type maybeStream struct {
s *Stream
}
func (c *Conn) streamsInit() {
c.streams.streams = make(map[streamID]maybeStream)
c.streams.queue = newQueue[*Stream]()
c.streams.localLimit[bidiStream].init()
c.streams.localLimit[uniStream].init()
c.streams.remoteLimit[bidiStream].init(c.config.maxBidiRemoteStreams())
c.streams.remoteLimit[uniStream].init(c.config.maxUniRemoteStreams())
c.inflowInit()
}
func (c *Conn) streamsCleanup() {
c.streams.queue.close(errConnClosed)
c.streams.localLimit[bidiStream].connHasClosed()
c.streams.localLimit[uniStream].connHasClosed()
for _, s := range c.streams.streams {
if s.s != nil {
s.s.connHasClosed()
}
}
}
// AcceptStream waits for and returns the next stream created by the peer.
func (c *Conn) AcceptStream(ctx context.Context) (*Stream, error) {
return c.streams.queue.get(ctx)
}
// NewStream creates a stream.
//
// If the peer's maximum stream limit for the connection has been reached,
// NewStream blocks until the limit is increased or the context expires.
func (c *Conn) NewStream(ctx context.Context) (*Stream, error) {
return c.newLocalStream(ctx, bidiStream)
}
// NewSendOnlyStream creates a unidirectional, send-only stream.
//
// If the peer's maximum stream limit for the connection has been reached,
// NewSendOnlyStream blocks until the limit is increased or the context expires.
func (c *Conn) NewSendOnlyStream(ctx context.Context) (*Stream, error) {
return c.newLocalStream(ctx, uniStream)
}
func (c *Conn) newLocalStream(ctx context.Context, styp streamType) (*Stream, error) {
num, err := c.streams.localLimit[styp].open(ctx, c)
if err != nil {
return nil, err
}
s := newStream(c, newStreamID(c.side, styp, num))
s.outmaxbuf = c.config.maxStreamWriteBufferSize()
s.outwin = c.streams.peerInitialMaxStreamDataRemote[styp]
if styp == bidiStream {
s.inmaxbuf = c.config.maxStreamReadBufferSize()
s.inwin = c.config.maxStreamReadBufferSize()
}
s.inUnlock()
s.outUnlock()
// Modify c.streams on the conn's loop.
if err := c.runOnLoop(ctx, func(now time.Time, c *Conn) {
c.streams.streams[s.id] = maybeStream{s}
}); err != nil {
return nil, err
}
return s, nil
}
// streamFrameType identifies which direction of a stream,
// from the local perspective, a frame is associated with.
//
// For example, STREAM is a recvStream frame,
// because it carries data from the peer to us.
type streamFrameType uint8
const (
sendStream = streamFrameType(iota) // for example, MAX_DATA
recvStream // for example, STREAM_DATA_BLOCKED
)
// streamForID returns the stream with the given id.
// If the stream does not exist, it returns nil.
func (c *Conn) streamForID(id streamID) *Stream {
return c.streams.streams[id].s
}
// streamForFrame returns the stream with the given id.
// If the stream does not exist, it may be created.
//
// streamForFrame aborts the connection if the stream id, state, and frame type don't align.
// For example, it aborts the connection with a STREAM_STATE error if a MAX_DATA frame
// is received for a receive-only stream, or if the peer attempts to create a stream that
// should be originated locally.
//
// streamForFrame returns nil if the stream no longer exists or if an error occurred.
func (c *Conn) streamForFrame(now time.Time, id streamID, ftype streamFrameType) *Stream {
if id.streamType() == uniStream {
if (id.initiator() == c.side) != (ftype == sendStream) {
// Received an invalid frame for unidirectional stream.
// For example, a RESET_STREAM frame for a send-only stream.
c.abort(now, localTransportError{
code: errStreamState,
reason: "invalid frame for unidirectional stream",
})
return nil
}
}
ms, isOpen := c.streams.streams[id]
if ms.s != nil {
return ms.s
}
num := id.num()
styp := id.streamType()
if id.initiator() == c.side {
if num < c.streams.localLimit[styp].opened {
// This stream was created by us, and has been closed.
return nil
}
// Received a frame for a stream that should be originated by us,
// but which we never created.
c.abort(now, localTransportError{
code: errStreamState,
reason: "received frame for unknown stream",
})
return nil
} else {
// if isOpen, this is a stream that was implicitly opened by a
// previous frame for a larger-numbered stream, but we haven't
// actually created it yet.
if !isOpen && num < c.streams.remoteLimit[styp].opened {
// This stream was created by the peer, and has been closed.
return nil
}
}
prevOpened := c.streams.remoteLimit[styp].opened
if err := c.streams.remoteLimit[styp].open(id); err != nil {
c.abort(now, err)
return nil
}
// Receiving a frame for a stream implicitly creates all streams
// with the same initiator and type and a lower number.
// Add a nil entry to the streams map for each implicitly created stream.
for n := newStreamID(id.initiator(), id.streamType(), prevOpened); n < id; n += 4 {
c.streams.streams[n] = maybeStream{}
}
s := newStream(c, id)
s.inmaxbuf = c.config.maxStreamReadBufferSize()
s.inwin = c.config.maxStreamReadBufferSize()
if id.streamType() == bidiStream {
s.outmaxbuf = c.config.maxStreamWriteBufferSize()
s.outwin = c.streams.peerInitialMaxStreamDataBidiLocal
}
s.inUnlock()
s.outUnlock()
c.streams.streams[id] = maybeStream{s}
c.streams.queue.put(s)
return s
}
// maybeQueueStreamForSend marks a stream as containing frames that need sending.
func (c *Conn) maybeQueueStreamForSend(s *Stream, state streamState) {
if state.wantQueue() == state.inQueue() {
return // already on the right queue
}
c.streams.sendMu.Lock()
defer c.streams.sendMu.Unlock()
state = s.state.load() // may have changed while waiting
c.queueStreamForSendLocked(s, state)
c.streams.needSend.Store(true)
c.wake()
}
// queueStreamForSendLocked moves a stream to the correct send queue,
// or removes it from all queues.
//
// state is the last known stream state.
func (c *Conn) queueStreamForSendLocked(s *Stream, state streamState) {
for {
wantQueue := state.wantQueue()
inQueue := state.inQueue()
if inQueue == wantQueue {
return // already on the right queue
}
switch inQueue {
case metaQueue:
c.streams.queueMeta.remove(s)
case dataQueue:
c.streams.queueData.remove(s)
}
switch wantQueue {
case metaQueue:
c.streams.queueMeta.append(s)
state = s.state.set(streamQueueMeta, streamQueueMeta|streamQueueData)
case dataQueue:
c.streams.queueData.append(s)
state = s.state.set(streamQueueData, streamQueueMeta|streamQueueData)
case noQueue:
state = s.state.set(0, streamQueueMeta|streamQueueData)
}
// If the stream state changed while we were moving the stream,
// we might now be on the wrong queue.
//
// For example:
// - stream has data to send: streamOutSendData|streamQueueData
// - appendStreamFrames sends all the data: streamQueueData
// - concurrently, more data is written: streamOutSendData|streamQueueData
// - appendStreamFrames calls us with the last state it observed
// (streamQueueData).
// - We remove the stream from the queue and observe the updated state:
// streamOutSendData
// - We realize that the stream needs to go back on the data queue.
//
// Go back around the loop to confirm we're on the correct queue.
}
}
// appendStreamFrames writes stream-related frames to the current packet.
//
// It returns true if no more frames need appending,
// false if not everything fit in the current packet.
func (c *Conn) appendStreamFrames(w *packetWriter, pnum packetNumber, pto bool) bool {
// MAX_DATA
if !c.appendMaxDataFrame(w, pnum, pto) {
return false
}
if pto {
return c.appendStreamFramesPTO(w, pnum)
}
if !c.streams.needSend.Load() {
// If queueMeta includes newly-finished streams, we may extend the peer's
// stream limits. When there are no streams to process, add MAX_STREAMS
// frames here. Otherwise, wait until after we've processed queueMeta.
return c.appendMaxStreams(w, pnum, pto)
}
c.streams.sendMu.Lock()
defer c.streams.sendMu.Unlock()
// queueMeta contains streams with non-flow-controlled frames to send.
for c.streams.queueMeta.head != nil {
s := c.streams.queueMeta.head
state := s.state.load()
if state&(streamQueueMeta|streamConnRemoved) != streamQueueMeta {
panic("BUG: queueMeta stream is not streamQueueMeta")
}
if state&streamInSendMeta != 0 {
s.ingate.lock()
ok := s.appendInFramesLocked(w, pnum, pto)
state = s.inUnlockNoQueue()
if !ok {
return false
}
if state&streamInSendMeta != 0 {
panic("BUG: streamInSendMeta set after successfully appending frames")
}
}
if state&streamOutSendMeta != 0 {
s.outgate.lock()
// This might also append flow-controlled frames if we have any
// and available conn-level quota. That's fine.
ok := s.appendOutFramesLocked(w, pnum, pto)
state = s.outUnlockNoQueue()
// We're checking both ok and state, because appendOutFramesLocked
// might have filled up the packet with flow-controlled data.
// If so, we want to move the stream to queueData for any remaining frames.
if !ok && state&streamOutSendMeta != 0 {
return false
}
if state&streamOutSendMeta != 0 {
panic("BUG: streamOutSendMeta set after successfully appending frames")
}
}
// We've sent all frames for this stream, so remove it from the send queue.
c.streams.queueMeta.remove(s)
if state&(streamInDone|streamOutDone) == streamInDone|streamOutDone {
// Stream is finished, remove it from the conn.
state = s.state.set(streamConnRemoved, streamQueueMeta|streamConnRemoved)
delete(c.streams.streams, s.id)
// Record finalization of remote streams, to know when
// to extend the peer's stream limit.
if s.id.initiator() != c.side {
c.streams.remoteLimit[s.id.streamType()].close()
}
} else {
state = s.state.set(0, streamQueueMeta|streamConnRemoved)
}
// The stream may have flow-controlled data to send,
// or something might have added non-flow-controlled frames after we
// unlocked the stream.
// If so, put the stream back on a queue.
c.queueStreamForSendLocked(s, state)
}
// MAX_STREAMS (possibly triggered by finalization of remote streams above).
if !c.appendMaxStreams(w, pnum, pto) {
return false
}
// queueData contains streams with flow-controlled frames.
for c.streams.queueData.head != nil {
avail := c.streams.outflow.avail()
if avail == 0 {
break // no flow control quota available
}
s := c.streams.queueData.head
s.outgate.lock()
ok := s.appendOutFramesLocked(w, pnum, pto)
state := s.outUnlockNoQueue()
if !ok {
// We've sent some data for this stream, but it still has more to send.
// If the stream got a reasonable chance to put data in a packet,
// advance sendHead to the next stream in line, to avoid starvation.
// We'll come back to this stream after going through the others.
//
// If the packet was already mostly out of space, leave sendHead alone
// and come back to this stream again on the next packet.
if avail > 512 {
c.streams.queueData.head = s.next
}
return false
}
if state&streamQueueData == 0 {
panic("BUG: queueData stream is not streamQueueData")
}
if state&streamOutSendData != 0 {
// We must have run out of connection-level flow control:
// appendOutFramesLocked says it wrote all it can, but there's
// still data to send.
//
// Advance sendHead to the next stream in line to avoid starvation.
if c.streams.outflow.avail() != 0 {
panic("BUG: streamOutSendData set and flow control available after send")
}
c.streams.queueData.head = s.next
return true
}
c.streams.queueData.remove(s)
state = s.state.set(0, streamQueueData)
c.queueStreamForSendLocked(s, state)
}
if c.streams.queueMeta.head == nil && c.streams.queueData.head == nil {
c.streams.needSend.Store(false)
}
return true
}
// appendStreamFramesPTO writes stream-related frames to the current packet
// for a PTO probe.
//
// It returns true if no more frames need appending,
// false if not everything fit in the current packet.
func (c *Conn) appendStreamFramesPTO(w *packetWriter, pnum packetNumber) bool {
const pto = true
if !c.appendMaxStreams(w, pnum, pto) {
return false
}
c.streams.sendMu.Lock()
defer c.streams.sendMu.Unlock()
for _, ms := range c.streams.streams {
s := ms.s
if s == nil {
continue
}
const pto = true
s.ingate.lock()
inOK := s.appendInFramesLocked(w, pnum, pto)
s.inUnlockNoQueue()
if !inOK {
return false
}
s.outgate.lock()
outOK := s.appendOutFramesLocked(w, pnum, pto)
s.outUnlockNoQueue()
if !outOK {
return false
}
}
return true
}
func (c *Conn) appendMaxStreams(w *packetWriter, pnum packetNumber, pto bool) bool {
if !c.streams.remoteLimit[uniStream].appendFrame(w, uniStream, pnum, pto) {
return false
}
if !c.streams.remoteLimit[bidiStream].appendFrame(w, bidiStream, pnum, pto) {
return false
}
return true
}
// A streamRing is a circular linked list of streams.
type streamRing struct {
head *Stream
}
// remove removes s from the ring.
// s must be on the ring.
func (r *streamRing) remove(s *Stream) {
if s.next == s {
r.head = nil // s was the last stream in the ring
} else {
s.prev.next = s.next
s.next.prev = s.prev
if r.head == s {
r.head = s.next
}
}
}
// append places s at the last position in the ring.
// s must not be attached to any ring.
func (r *streamRing) append(s *Stream) {
if r.head == nil {
r.head = s
s.next = s
s.prev = s
} else {
s.prev = r.head.prev
s.next = r.head
s.prev.next = s
s.next.prev = s
}
}
// Copyright 2023 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 quic
// "Implementations MUST support buffering at least 4096 bytes of data
// received in out-of-order CRYPTO frames."
// https://www.rfc-editor.org/rfc/rfc9000.html#section-7.5-2
//
// 4096 is too small for real-world cases, however, so we allow more.
const cryptoBufferSize = 1 << 20
// A cryptoStream is the stream of data passed in CRYPTO frames.
// There is one cryptoStream per packet number space.
type cryptoStream struct {
// CRYPTO data received from the peer.
in pipe
inset rangeset[int64] // bytes received
// CRYPTO data queued for transmission to the peer.
out pipe
outunsent rangeset[int64] // bytes in need of sending
outacked rangeset[int64] // bytes acked by peer
}
// handleCrypto processes data received in a CRYPTO frame.
func (s *cryptoStream) handleCrypto(off int64, b []byte, f func([]byte) error) error {
end := off + int64(len(b))
if end-s.inset.min() > cryptoBufferSize {
return localTransportError{
code: errCryptoBufferExceeded,
reason: "crypto buffer exceeded",
}
}
s.inset.add(off, end)
if off == s.in.start {
// Fast path: This is the next chunk of data in the stream,
// so just handle it immediately.
if err := f(b); err != nil {
return err
}
s.in.discardBefore(end)
} else {
// This is either data we've already processed,
// data we can't process yet, or a mix of both.
s.in.writeAt(b, off)
}
// s.in.start is the next byte in sequence.
// If it's in s.inset, we have bytes to provide.
// If it isn't, we don't--we're either out of data,
// or only have data that comes after the next byte.
if !s.inset.contains(s.in.start) {
return nil
}
// size is the size of the first contiguous chunk of bytes
// that have not been processed yet.
size := int(s.inset[0].end - s.in.start)
if size <= 0 {
return nil
}
err := s.in.read(s.in.start, size, f)
s.in.discardBefore(s.inset[0].end)
return err
}
// write queues data for sending to the peer.
// It does not block or limit the amount of buffered data.
// QUIC connections don't communicate the amount of CRYPTO data they are willing to buffer,
// so we send what we have and the peer can close the connection if it is too much.
func (s *cryptoStream) write(b []byte) {
start := s.out.end
s.out.writeAt(b, start)
s.outunsent.add(start, s.out.end)
}
// ackOrLoss reports that an CRYPTO frame sent by us has been acknowledged by the peer, or lost.
func (s *cryptoStream) ackOrLoss(start, end int64, fate packetFate) {
switch fate {
case packetAcked:
s.outacked.add(start, end)
s.outunsent.sub(start, end)
// If this ack is for data at the start of the send buffer, we can now discard it.
if s.outacked.contains(s.out.start) {
s.out.discardBefore(s.outacked[0].end)
}
case packetLost:
// Mark everything lost, but not previously acked, as needing retransmission.
// We do this by adding all the lost bytes to outunsent, and then
// removing everything already acked.
s.outunsent.add(start, end)
for _, a := range s.outacked {
s.outunsent.sub(a.start, a.end)
}
}
}
// dataToSend reports what data should be sent in CRYPTO frames to the peer.
// It calls f with each range of data to send.
// f uses sendData to get the bytes to send, and returns the number of bytes sent.
// dataToSend calls f until no data is left, or f returns 0.
//
// This function is unusually indirect (why not just return a []byte,
// or implement io.Reader?).
//
// Returning a []byte to the caller either requires that we store the
// data to send contiguously (which we don't), allocate a temporary buffer
// and copy into it (inefficient), or return less data than we have available
// (requires complexity to avoid unnecessarily breaking data across frames).
//
// Accepting a []byte from the caller (io.Reader) makes packet construction
// difficult. Since CRYPTO data is encoded with a varint length prefix, the
// location of the data depends on the length of the data. (We could hardcode
// a 2-byte length, of course.)
//
// Instead, we tell the caller how much data is, the caller figures out where
// to put it (and possibly decides that it doesn't have space for this data
// in the packet after all), and the caller then makes a separate call to
// copy the data it wants into position.
func (s *cryptoStream) dataToSend(pto bool, f func(off, size int64) (sent int64)) {
for {
off, size := dataToSend(s.out.start, s.out.end, s.outunsent, s.outacked, pto)
if size == 0 {
return
}
n := f(off, size)
if n == 0 || pto {
return
}
}
}
// sendData fills b with data to send to the peer, starting at off,
// and marks the data as sent. The caller must have already ascertained
// that there is data to send in this region using dataToSend.
func (s *cryptoStream) sendData(off int64, b []byte) {
s.out.copy(off, b)
s.outunsent.sub(off, off+int64(len(b)))
}
// discardKeys is called when the packet protection keys for the stream are dropped.
func (s *cryptoStream) discardKeys() error {
if s.in.end-s.in.start != 0 {
// The peer sent some unprocessed CRYPTO data that we're about to discard.
// Close the connection with a TLS unexpected_message alert.
// https://www.rfc-editor.org/rfc/rfc5246#section-7.2.2
const unexpectedMessage = 10
return localTransportError{
code: errTLSBase + unexpectedMessage,
reason: "excess crypto data",
}
}
// Discard any unacked (but presumably received) data in our output buffer.
s.out.discardBefore(s.out.end)
*s = cryptoStream{}
return nil
}
// Copyright 2023 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 quic
import (
"net/netip"
"sync"
)
type datagram struct {
b []byte
localAddr netip.AddrPort
peerAddr netip.AddrPort
ecn ecnBits
}
// Explicit Congestion Notification bits.
//
// https://www.rfc-editor.org/rfc/rfc3168.html#section-5
type ecnBits byte
const (
ecnMask = 0b000000_11
ecnNotECT = 0b000000_00
ecnECT1 = 0b000000_01
ecnECT0 = 0b000000_10
ecnCE = 0b000000_11
)
var datagramPool = sync.Pool{
New: func() any {
return &datagram{
b: make([]byte, maxUDPPayloadSize),
}
},
}
func newDatagram() *datagram {
m := datagramPool.Get().(*datagram)
*m = datagram{
b: m.b[:cap(m.b)],
}
return m
}
func (m *datagram) recycle() {
if cap(m.b) != maxUDPPayloadSize {
return
}
datagramPool.Put(m)
}
// Copyright 2023 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 quic
import (
"context"
"crypto/rand"
"errors"
"net"
"net/netip"
"sync"
"sync/atomic"
"time"
)
// An Endpoint handles QUIC traffic on a network address.
// It can accept inbound connections or create outbound ones.
//
// Multiple goroutines may invoke methods on an Endpoint simultaneously.
type Endpoint struct {
listenConfig *Config
packetConn packetConn
testHooks endpointTestHooks
resetGen statelessResetTokenGenerator
retry retryState
acceptQueue queue[*Conn] // new inbound connections
connsMap connsMap // only accessed by the listen loop
connsMu sync.Mutex
conns map[*Conn]struct{}
closing bool // set when Close is called
closec chan struct{} // closed when the listen loop exits
}
type endpointTestHooks interface {
newConn(c *Conn)
}
// A packetConn is the interface to sending and receiving UDP packets.
type packetConn interface {
Close() error
LocalAddr() netip.AddrPort
Read(f func(*datagram))
Write(datagram) error
}
// Listen listens on a local network address.
//
// The config is used to for connections accepted by the endpoint.
// If the config is nil, the endpoint will not accept connections.
func Listen(network, address string, listenConfig *Config) (*Endpoint, error) {
if listenConfig != nil && listenConfig.TLSConfig == nil {
return nil, errors.New("TLSConfig is not set")
}
a, err := net.ResolveUDPAddr(network, address)
if err != nil {
return nil, err
}
udpConn, err := net.ListenUDP(network, a)
if err != nil {
return nil, err
}
pc, err := newNetUDPConn(udpConn)
if err != nil {
return nil, err
}
return newEndpoint(pc, listenConfig, nil)
}
// NewEndpoint creates an endpoint using a net.PacketConn as the underlying transport.
//
// If the PacketConn is not a *net.UDPConn, the endpoint may be slower and lack
// access to some features of the network.
func NewEndpoint(conn net.PacketConn, config *Config) (*Endpoint, error) {
var pc packetConn
var err error
switch conn := conn.(type) {
case *net.UDPConn:
pc, err = newNetUDPConn(conn)
default:
pc, err = newNetPacketConn(conn)
}
if err != nil {
return nil, err
}
return newEndpoint(pc, config, nil)
}
func newEndpoint(pc packetConn, config *Config, hooks endpointTestHooks) (*Endpoint, error) {
e := &Endpoint{
listenConfig: config,
packetConn: pc,
testHooks: hooks,
conns: make(map[*Conn]struct{}),
acceptQueue: newQueue[*Conn](),
closec: make(chan struct{}),
}
var statelessResetKey [32]byte
if config != nil {
statelessResetKey = config.StatelessResetKey
}
e.resetGen.init(statelessResetKey)
e.connsMap.init()
if config != nil && config.RequireAddressValidation {
if err := e.retry.init(); err != nil {
return nil, err
}
}
go e.listen()
return e, nil
}
// LocalAddr returns the local network address.
func (e *Endpoint) LocalAddr() netip.AddrPort {
return e.packetConn.LocalAddr()
}
// Close closes the Endpoint.
// Any blocked operations on the Endpoint or associated Conns and Stream will be unblocked
// and return errors.
//
// Close aborts every open connection.
// Data in stream read and write buffers is discarded.
// It waits for the peers of any open connection to acknowledge the connection has been closed.
func (e *Endpoint) Close(ctx context.Context) error {
e.acceptQueue.close(errors.New("endpoint closed"))
// It isn't safe to call Conn.Abort or conn.exit with connsMu held,
// so copy the list of conns.
var conns []*Conn
e.connsMu.Lock()
if !e.closing {
e.closing = true // setting e.closing prevents new conns from being created
for c := range e.conns {
conns = append(conns, c)
}
if len(e.conns) == 0 {
e.packetConn.Close()
}
}
e.connsMu.Unlock()
for _, c := range conns {
c.Abort(localTransportError{code: errNo})
}
select {
case <-e.closec:
case <-ctx.Done():
for _, c := range conns {
c.exit()
}
return ctx.Err()
}
return nil
}
// Accept waits for and returns the next connection.
func (e *Endpoint) Accept(ctx context.Context) (*Conn, error) {
return e.acceptQueue.get(ctx)
}
// Dial creates and returns a connection to a network address.
// The config cannot be nil.
func (e *Endpoint) Dial(ctx context.Context, network, address string, config *Config) (*Conn, error) {
u, err := net.ResolveUDPAddr(network, address)
if err != nil {
return nil, err
}
addr := u.AddrPort()
addr = netip.AddrPortFrom(addr.Addr().Unmap(), addr.Port())
c, err := e.newConn(time.Now(), config, clientSide, newServerConnIDs{}, address, addr)
if err != nil {
return nil, err
}
if err := c.waitReady(ctx); err != nil {
c.Abort(nil)
return nil, err
}
return c, nil
}
func (e *Endpoint) newConn(now time.Time, config *Config, side connSide, cids newServerConnIDs, peerHostname string, peerAddr netip.AddrPort) (*Conn, error) {
e.connsMu.Lock()
defer e.connsMu.Unlock()
if e.closing {
return nil, errors.New("endpoint closed")
}
c, err := newConn(now, side, cids, peerHostname, peerAddr, config, e)
if err != nil {
return nil, err
}
e.conns[c] = struct{}{}
return c, nil
}
// serverConnEstablished is called by a conn when the handshake completes
// for an inbound (serverSide) connection.
func (e *Endpoint) serverConnEstablished(c *Conn) {
e.acceptQueue.put(c)
}
// connDrained is called by a conn when it leaves the draining state,
// either when the peer acknowledges connection closure or the drain timeout expires.
func (e *Endpoint) connDrained(c *Conn) {
var cids [][]byte
for i := range c.connIDState.local {
cids = append(cids, c.connIDState.local[i].cid)
}
var tokens []statelessResetToken
for i := range c.connIDState.remote {
tokens = append(tokens, c.connIDState.remote[i].resetToken)
}
e.connsMap.updateConnIDs(func(conns *connsMap) {
for _, cid := range cids {
conns.retireConnID(c, cid)
}
for _, token := range tokens {
conns.retireResetToken(c, token)
}
})
e.connsMu.Lock()
defer e.connsMu.Unlock()
delete(e.conns, c)
if e.closing && len(e.conns) == 0 {
e.packetConn.Close()
}
}
func (e *Endpoint) listen() {
defer close(e.closec)
e.packetConn.Read(func(m *datagram) {
if e.connsMap.updateNeeded.Load() {
e.connsMap.applyUpdates()
}
e.handleDatagram(m)
})
}
func (e *Endpoint) handleDatagram(m *datagram) {
dstConnID, ok := dstConnIDForDatagram(m.b)
if !ok {
m.recycle()
return
}
c := e.connsMap.byConnID[string(dstConnID)]
if c == nil {
// TODO: Move this branch into a separate goroutine to avoid blocking
// the endpoint while processing packets.
e.handleUnknownDestinationDatagram(m)
return
}
// TODO: This can block the endpoint while waiting for the conn to accept the dgram.
// Think about buffering between the receive loop and the conn.
c.sendMsg(m)
}
func (e *Endpoint) handleUnknownDestinationDatagram(m *datagram) {
defer func() {
if m != nil {
m.recycle()
}
}()
const minimumValidPacketSize = 21
if len(m.b) < minimumValidPacketSize {
return
}
now := time.Now()
// Check to see if this is a stateless reset.
var token statelessResetToken
copy(token[:], m.b[len(m.b)-len(token):])
if c := e.connsMap.byResetToken[token]; c != nil {
c.sendMsg(func(now time.Time, c *Conn) {
c.handleStatelessReset(now, token)
})
return
}
// If this is a 1-RTT packet, there's nothing productive we can do with it.
// Send a stateless reset if possible.
if !isLongHeader(m.b[0]) {
e.maybeSendStatelessReset(m.b, m.peerAddr)
return
}
p, ok := parseGenericLongHeaderPacket(m.b)
if !ok || len(m.b) < paddedInitialDatagramSize {
return
}
switch p.version {
case quicVersion1:
case 0:
// Version Negotiation for an unknown connection.
return
default:
// Unknown version.
e.sendVersionNegotiation(p, m.peerAddr)
return
}
if getPacketType(m.b) != packetTypeInitial {
// This packet isn't trying to create a new connection.
// It might be associated with some connection we've lost state for.
// We are technically permitted to send a stateless reset for
// a long-header packet, but this isn't generally useful. See:
// https://www.rfc-editor.org/rfc/rfc9000#section-10.3-16
return
}
if e.listenConfig == nil {
// We are not configured to accept connections.
return
}
cids := newServerConnIDs{
srcConnID: p.srcConnID,
dstConnID: p.dstConnID,
}
if e.listenConfig.RequireAddressValidation {
var ok bool
cids.retrySrcConnID = p.dstConnID
cids.originalDstConnID, ok = e.validateInitialAddress(now, p, m.peerAddr)
if !ok {
return
}
} else {
cids.originalDstConnID = p.dstConnID
}
var err error
c, err := e.newConn(now, e.listenConfig, serverSide, cids, "", m.peerAddr)
if err != nil {
// The accept queue is probably full.
// We could send a CONNECTION_CLOSE to the peer to reject the connection.
// Currently, we just drop the datagram.
// https://www.rfc-editor.org/rfc/rfc9000.html#section-5.2.2-5
return
}
c.sendMsg(m)
m = nil // don't recycle, sendMsg takes ownership
}
func (e *Endpoint) maybeSendStatelessReset(b []byte, peerAddr netip.AddrPort) {
if !e.resetGen.canReset {
// Config.StatelessResetKey isn't set, so we don't send stateless resets.
return
}
// The smallest possible valid packet a peer can send us is:
// 1 byte of header
// connIDLen bytes of destination connection ID
// 1 byte of packet number
// 1 byte of payload
// 16 bytes AEAD expansion
if len(b) < 1+connIDLen+1+1+16 {
return
}
// TODO: Rate limit stateless resets.
cid := b[1:][:connIDLen]
token := e.resetGen.tokenForConnID(cid)
// We want to generate a stateless reset that is as short as possible,
// but long enough to be difficult to distinguish from a 1-RTT packet.
//
// The minimal 1-RTT packet is:
// 1 byte of header
// 0-20 bytes of destination connection ID
// 1-4 bytes of packet number
// 1 byte of payload
// 16 bytes AEAD expansion
//
// Assuming the maximum possible connection ID and packet number size,
// this gives 1 + 20 + 4 + 1 + 16 = 42 bytes.
//
// We also must generate a stateless reset that is shorter than the datagram
// we are responding to, in order to ensure that reset loops terminate.
//
// See: https://www.rfc-editor.org/rfc/rfc9000#section-10.3
size := min(len(b)-1, 42)
// Reuse the input buffer for generating the stateless reset.
b = b[:size]
rand.Read(b[:len(b)-statelessResetTokenLen])
b[0] &^= headerFormLong // clear long header bit
b[0] |= fixedBit // set fixed bit
copy(b[len(b)-statelessResetTokenLen:], token[:])
e.sendDatagram(datagram{
b: b,
peerAddr: peerAddr,
})
}
func (e *Endpoint) sendVersionNegotiation(p genericLongPacket, peerAddr netip.AddrPort) {
m := newDatagram()
m.b = appendVersionNegotiation(m.b[:0], p.srcConnID, p.dstConnID, quicVersion1)
m.peerAddr = peerAddr
e.sendDatagram(*m)
m.recycle()
}
func (e *Endpoint) sendConnectionClose(in genericLongPacket, peerAddr netip.AddrPort, code transportError) {
keys := initialKeys(in.dstConnID, serverSide)
var w packetWriter
p := longPacket{
ptype: packetTypeInitial,
version: quicVersion1,
num: 0,
dstConnID: in.srcConnID,
srcConnID: in.dstConnID,
}
const pnumMaxAcked = 0
w.reset(paddedInitialDatagramSize)
w.startProtectedLongHeaderPacket(pnumMaxAcked, p)
w.appendConnectionCloseTransportFrame(code, 0, "")
w.finishProtectedLongHeaderPacket(pnumMaxAcked, keys.w, p)
buf := w.datagram()
if len(buf) == 0 {
return
}
e.sendDatagram(datagram{
b: buf,
peerAddr: peerAddr,
})
}
func (e *Endpoint) sendDatagram(dgram datagram) error {
return e.packetConn.Write(dgram)
}
// A connsMap is an endpoint's mapping of conn ids and reset tokens to conns.
type connsMap struct {
byConnID map[string]*Conn
byResetToken map[statelessResetToken]*Conn
updateMu sync.Mutex
updateNeeded atomic.Bool
updates []func(*connsMap)
}
func (m *connsMap) init() {
m.byConnID = map[string]*Conn{}
m.byResetToken = map[statelessResetToken]*Conn{}
}
func (m *connsMap) addConnID(c *Conn, cid []byte) {
m.byConnID[string(cid)] = c
}
func (m *connsMap) retireConnID(c *Conn, cid []byte) {
delete(m.byConnID, string(cid))
}
func (m *connsMap) addResetToken(c *Conn, token statelessResetToken) {
m.byResetToken[token] = c
}
func (m *connsMap) retireResetToken(c *Conn, token statelessResetToken) {
delete(m.byResetToken, token)
}
func (m *connsMap) updateConnIDs(f func(*connsMap)) {
m.updateMu.Lock()
defer m.updateMu.Unlock()
m.updates = append(m.updates, f)
m.updateNeeded.Store(true)
}
// applyUpdates is called by the datagram receive loop to update its connection ID map.
func (m *connsMap) applyUpdates() {
m.updateMu.Lock()
defer m.updateMu.Unlock()
for _, f := range m.updates {
f(m)
}
clear(m.updates)
m.updates = m.updates[:0]
m.updateNeeded.Store(false)
}
// Copyright 2023 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 quic
import (
"fmt"
)
// A transportError is a transport error code from RFC 9000 Section 20.1.
//
// The transportError type doesn't implement the error interface to ensure we always
// distinguish between errors sent to and received from the peer.
// See the localTransportError and peerTransportError types below.
type transportError uint64
// https://www.rfc-editor.org/rfc/rfc9000.html#section-20.1
const (
errNo = transportError(0x00)
errInternal = transportError(0x01)
errConnectionRefused = transportError(0x02)
errFlowControl = transportError(0x03)
errStreamLimit = transportError(0x04)
errStreamState = transportError(0x05)
errFinalSize = transportError(0x06)
errFrameEncoding = transportError(0x07)
errTransportParameter = transportError(0x08)
errConnectionIDLimit = transportError(0x09)
errProtocolViolation = transportError(0x0a)
errInvalidToken = transportError(0x0b)
errApplicationError = transportError(0x0c)
errCryptoBufferExceeded = transportError(0x0d)
errKeyUpdateError = transportError(0x0e)
errAEADLimitReached = transportError(0x0f)
errNoViablePath = transportError(0x10)
errTLSBase = transportError(0x0100) // 0x0100-0x01ff; base + TLS code
)
func (e transportError) String() string {
switch e {
case errNo:
return "NO_ERROR"
case errInternal:
return "INTERNAL_ERROR"
case errConnectionRefused:
return "CONNECTION_REFUSED"
case errFlowControl:
return "FLOW_CONTROL_ERROR"
case errStreamLimit:
return "STREAM_LIMIT_ERROR"
case errStreamState:
return "STREAM_STATE_ERROR"
case errFinalSize:
return "FINAL_SIZE_ERROR"
case errFrameEncoding:
return "FRAME_ENCODING_ERROR"
case errTransportParameter:
return "TRANSPORT_PARAMETER_ERROR"
case errConnectionIDLimit:
return "CONNECTION_ID_LIMIT_ERROR"
case errProtocolViolation:
return "PROTOCOL_VIOLATION"
case errInvalidToken:
return "INVALID_TOKEN"
case errApplicationError:
return "APPLICATION_ERROR"
case errCryptoBufferExceeded:
return "CRYPTO_BUFFER_EXCEEDED"
case errKeyUpdateError:
return "KEY_UPDATE_ERROR"
case errAEADLimitReached:
return "AEAD_LIMIT_REACHED"
case errNoViablePath:
return "NO_VIABLE_PATH"
}
if e >= 0x0100 && e <= 0x01ff {
return fmt.Sprintf("CRYPTO_ERROR(%v)", uint64(e)&0xff)
}
return fmt.Sprintf("ERROR %d", uint64(e))
}
// A localTransportError is an error sent to the peer.
type localTransportError struct {
code transportError
reason string
}
func (e localTransportError) Error() string {
if e.reason == "" {
return fmt.Sprintf("closed connection: %v", e.code)
}
return fmt.Sprintf("closed connection: %v: %q", e.code, e.reason)
}
// A peerTransportError is an error received from the peer.
type peerTransportError struct {
code transportError
reason string
}
func (e peerTransportError) Error() string {
return fmt.Sprintf("peer closed connection: %v: %q", e.code, e.reason)
}
// A StreamErrorCode is an application protocol error code (RFC 9000, Section 20.2)
// indicating whay a stream is being closed.
type StreamErrorCode uint64
func (e StreamErrorCode) Error() string {
return fmt.Sprintf("stream error code %v", uint64(e))
}
// An ApplicationError is an application protocol error code (RFC 9000, Section 20.2).
// Application protocol errors may be sent when terminating a stream or connection.
type ApplicationError struct {
Code uint64
Reason string
}
func (e *ApplicationError) Error() string {
return fmt.Sprintf("peer closed connection: %v: %q", e.Code, e.Reason)
}
// Is reports a match if err is an *ApplicationError with a matching Code.
func (e *ApplicationError) Is(err error) bool {
e2, ok := err.(*ApplicationError)
return ok && e2.Code == e.Code
}
// Copyright 2023 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 quic
import (
"fmt"
"log/slog"
"strconv"
"time"
)
// A debugFrame is a representation of the contents of a QUIC frame,
// used for debug logs and testing but not the primary serving path.
type debugFrame interface {
String() string
write(w *packetWriter) bool
LogValue() slog.Value
}
func parseDebugFrame(b []byte) (f debugFrame, n int) {
if len(b) == 0 {
return nil, -1
}
switch b[0] {
case frameTypePadding:
f, n = parseDebugFramePadding(b)
case frameTypePing:
f, n = parseDebugFramePing(b)
case frameTypeAck, frameTypeAckECN:
f, n = parseDebugFrameAck(b)
case frameTypeResetStream:
f, n = parseDebugFrameResetStream(b)
case frameTypeStopSending:
f, n = parseDebugFrameStopSending(b)
case frameTypeCrypto:
f, n = parseDebugFrameCrypto(b)
case frameTypeNewToken:
f, n = parseDebugFrameNewToken(b)
case frameTypeStreamBase, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f:
f, n = parseDebugFrameStream(b)
case frameTypeMaxData:
f, n = parseDebugFrameMaxData(b)
case frameTypeMaxStreamData:
f, n = parseDebugFrameMaxStreamData(b)
case frameTypeMaxStreamsBidi, frameTypeMaxStreamsUni:
f, n = parseDebugFrameMaxStreams(b)
case frameTypeDataBlocked:
f, n = parseDebugFrameDataBlocked(b)
case frameTypeStreamDataBlocked:
f, n = parseDebugFrameStreamDataBlocked(b)
case frameTypeStreamsBlockedBidi, frameTypeStreamsBlockedUni:
f, n = parseDebugFrameStreamsBlocked(b)
case frameTypeNewConnectionID:
f, n = parseDebugFrameNewConnectionID(b)
case frameTypeRetireConnectionID:
f, n = parseDebugFrameRetireConnectionID(b)
case frameTypePathChallenge:
f, n = parseDebugFramePathChallenge(b)
case frameTypePathResponse:
f, n = parseDebugFramePathResponse(b)
case frameTypeConnectionCloseTransport:
f, n = parseDebugFrameConnectionCloseTransport(b)
case frameTypeConnectionCloseApplication:
f, n = parseDebugFrameConnectionCloseApplication(b)
case frameTypeHandshakeDone:
f, n = parseDebugFrameHandshakeDone(b)
default:
return nil, -1
}
return f, n
}
// debugFramePadding is a sequence of PADDING frames.
type debugFramePadding struct {
size int
to int // alternate for writing packets: pad to
}
func parseDebugFramePadding(b []byte) (f debugFramePadding, n int) {
for n < len(b) && b[n] == frameTypePadding {
n++
}
f.size = n
return f, n
}
func (f debugFramePadding) String() string {
return fmt.Sprintf("PADDING*%v", f.size)
}
func (f debugFramePadding) write(w *packetWriter) bool {
if w.avail() == 0 {
return false
}
if f.to > 0 {
w.appendPaddingTo(f.to)
return true
}
for i := 0; i < f.size && w.avail() > 0; i++ {
w.b = append(w.b, frameTypePadding)
}
return true
}
func (f debugFramePadding) LogValue() slog.Value {
return slog.GroupValue(
slog.String("frame_type", "padding"),
slog.Int("length", f.size),
)
}
// debugFramePing is a PING frame.
type debugFramePing struct{}
func parseDebugFramePing(b []byte) (f debugFramePing, n int) {
return f, 1
}
func (f debugFramePing) String() string {
return "PING"
}
func (f debugFramePing) write(w *packetWriter) bool {
return w.appendPingFrame()
}
func (f debugFramePing) LogValue() slog.Value {
return slog.GroupValue(
slog.String("frame_type", "ping"),
)
}
// debugFrameAck is an ACK frame.
type debugFrameAck struct {
ackDelay unscaledAckDelay
ranges []i64range[packetNumber]
ecn ecnCounts
}
func parseDebugFrameAck(b []byte) (f debugFrameAck, n int) {
f.ranges = nil
_, f.ackDelay, f.ecn, n = consumeAckFrame(b, func(_ int, start, end packetNumber) {
f.ranges = append(f.ranges, i64range[packetNumber]{
start: start,
end: end,
})
})
// Ranges are parsed high to low; reverse ranges slice to order them low to high.
for i := 0; i < len(f.ranges)/2; i++ {
j := len(f.ranges) - 1
f.ranges[i], f.ranges[j] = f.ranges[j], f.ranges[i]
}
return f, n
}
func (f debugFrameAck) String() string {
s := fmt.Sprintf("ACK Delay=%v", f.ackDelay)
for _, r := range f.ranges {
s += fmt.Sprintf(" [%v,%v)", r.start, r.end)
}
if (f.ecn != ecnCounts{}) {
s += fmt.Sprintf(" ECN=[%d,%d,%d]", f.ecn.t0, f.ecn.t1, f.ecn.ce)
}
return s
}
func (f debugFrameAck) write(w *packetWriter) bool {
return w.appendAckFrame(rangeset[packetNumber](f.ranges), f.ackDelay, f.ecn)
}
func (f debugFrameAck) LogValue() slog.Value {
return slog.StringValue("error: debugFrameAck should not appear as a slog Value")
}
// debugFrameScaledAck is an ACK frame with scaled ACK Delay.
//
// This type is used in qlog events, which need access to the delay as a duration.
type debugFrameScaledAck struct {
ackDelay time.Duration
ranges []i64range[packetNumber]
}
func (f debugFrameScaledAck) LogValue() slog.Value {
var ackDelay slog.Attr
if f.ackDelay >= 0 {
ackDelay = slog.Duration("ack_delay", f.ackDelay)
}
return slog.GroupValue(
slog.String("frame_type", "ack"),
// Rather than trying to convert the ack ranges into the slog data model,
// pass a value that can JSON-encode itself.
slog.Any("acked_ranges", debugAckRanges(f.ranges)),
ackDelay,
)
}
type debugAckRanges []i64range[packetNumber]
// AppendJSON appends a JSON encoding of the ack ranges to b, and returns it.
// This is different than the standard json.Marshaler, but more efficient.
// Since we only use this in cooperation with the qlog package,
// encoding/json compatibility is irrelevant.
func (r debugAckRanges) AppendJSON(b []byte) []byte {
b = append(b, '[')
for i, ar := range r {
start, end := ar.start, ar.end-1 // qlog ranges are closed-closed
if i != 0 {
b = append(b, ',')
}
b = append(b, '[')
b = strconv.AppendInt(b, int64(start), 10)
if start != end {
b = append(b, ',')
b = strconv.AppendInt(b, int64(end), 10)
}
b = append(b, ']')
}
b = append(b, ']')
return b
}
func (r debugAckRanges) String() string {
return string(r.AppendJSON(nil))
}
// debugFrameResetStream is a RESET_STREAM frame.
type debugFrameResetStream struct {
id streamID
code uint64
finalSize int64
}
func parseDebugFrameResetStream(b []byte) (f debugFrameResetStream, n int) {
f.id, f.code, f.finalSize, n = consumeResetStreamFrame(b)
return f, n
}
func (f debugFrameResetStream) String() string {
return fmt.Sprintf("RESET_STREAM ID=%v Code=%v FinalSize=%v", f.id, f.code, f.finalSize)
}
func (f debugFrameResetStream) write(w *packetWriter) bool {
return w.appendResetStreamFrame(f.id, f.code, f.finalSize)
}
func (f debugFrameResetStream) LogValue() slog.Value {
return slog.GroupValue(
slog.String("frame_type", "reset_stream"),
slog.Uint64("stream_id", uint64(f.id)),
slog.Uint64("final_size", uint64(f.finalSize)),
)
}
// debugFrameStopSending is a STOP_SENDING frame.
type debugFrameStopSending struct {
id streamID
code uint64
}
func parseDebugFrameStopSending(b []byte) (f debugFrameStopSending, n int) {
f.id, f.code, n = consumeStopSendingFrame(b)
return f, n
}
func (f debugFrameStopSending) String() string {
return fmt.Sprintf("STOP_SENDING ID=%v Code=%v", f.id, f.code)
}
func (f debugFrameStopSending) write(w *packetWriter) bool {
return w.appendStopSendingFrame(f.id, f.code)
}
func (f debugFrameStopSending) LogValue() slog.Value {
return slog.GroupValue(
slog.String("frame_type", "stop_sending"),
slog.Uint64("stream_id", uint64(f.id)),
slog.Uint64("error_code", uint64(f.code)),
)
}
// debugFrameCrypto is a CRYPTO frame.
type debugFrameCrypto struct {
off int64
data []byte
}
func parseDebugFrameCrypto(b []byte) (f debugFrameCrypto, n int) {
f.off, f.data, n = consumeCryptoFrame(b)
return f, n
}
func (f debugFrameCrypto) String() string {
return fmt.Sprintf("CRYPTO Offset=%v Length=%v", f.off, len(f.data))
}
func (f debugFrameCrypto) write(w *packetWriter) bool {
b, added := w.appendCryptoFrame(f.off, len(f.data))
copy(b, f.data)
return added
}
func (f debugFrameCrypto) LogValue() slog.Value {
return slog.GroupValue(
slog.String("frame_type", "crypto"),
slog.Int64("offset", f.off),
slog.Int("length", len(f.data)),
)
}
// debugFrameNewToken is a NEW_TOKEN frame.
type debugFrameNewToken struct {
token []byte
}
func parseDebugFrameNewToken(b []byte) (f debugFrameNewToken, n int) {
f.token, n = consumeNewTokenFrame(b)
return f, n
}
func (f debugFrameNewToken) String() string {
return fmt.Sprintf("NEW_TOKEN Token=%x", f.token)
}
func (f debugFrameNewToken) write(w *packetWriter) bool {
return w.appendNewTokenFrame(f.token)
}
func (f debugFrameNewToken) LogValue() slog.Value {
return slog.GroupValue(
slog.String("frame_type", "new_token"),
slogHexstring("token", f.token),
)
}
// debugFrameStream is a STREAM frame.
type debugFrameStream struct {
id streamID
fin bool
off int64
data []byte
}
func parseDebugFrameStream(b []byte) (f debugFrameStream, n int) {
f.id, f.off, f.fin, f.data, n = consumeStreamFrame(b)
return f, n
}
func (f debugFrameStream) String() string {
fin := ""
if f.fin {
fin = " FIN"
}
return fmt.Sprintf("STREAM ID=%v%v Offset=%v Length=%v", f.id, fin, f.off, len(f.data))
}
func (f debugFrameStream) write(w *packetWriter) bool {
b, added := w.appendStreamFrame(f.id, f.off, len(f.data), f.fin)
copy(b, f.data)
return added
}
func (f debugFrameStream) LogValue() slog.Value {
var fin slog.Attr
if f.fin {
fin = slog.Bool("fin", true)
}
return slog.GroupValue(
slog.String("frame_type", "stream"),
slog.Uint64("stream_id", uint64(f.id)),
slog.Int64("offset", f.off),
slog.Int("length", len(f.data)),
fin,
)
}
// debugFrameMaxData is a MAX_DATA frame.
type debugFrameMaxData struct {
max int64
}
func parseDebugFrameMaxData(b []byte) (f debugFrameMaxData, n int) {
f.max, n = consumeMaxDataFrame(b)
return f, n
}
func (f debugFrameMaxData) String() string {
return fmt.Sprintf("MAX_DATA Max=%v", f.max)
}
func (f debugFrameMaxData) write(w *packetWriter) bool {
return w.appendMaxDataFrame(f.max)
}
func (f debugFrameMaxData) LogValue() slog.Value {
return slog.GroupValue(
slog.String("frame_type", "max_data"),
slog.Int64("maximum", f.max),
)
}
// debugFrameMaxStreamData is a MAX_STREAM_DATA frame.
type debugFrameMaxStreamData struct {
id streamID
max int64
}
func parseDebugFrameMaxStreamData(b []byte) (f debugFrameMaxStreamData, n int) {
f.id, f.max, n = consumeMaxStreamDataFrame(b)
return f, n
}
func (f debugFrameMaxStreamData) String() string {
return fmt.Sprintf("MAX_STREAM_DATA ID=%v Max=%v", f.id, f.max)
}
func (f debugFrameMaxStreamData) write(w *packetWriter) bool {
return w.appendMaxStreamDataFrame(f.id, f.max)
}
func (f debugFrameMaxStreamData) LogValue() slog.Value {
return slog.GroupValue(
slog.String("frame_type", "max_stream_data"),
slog.Uint64("stream_id", uint64(f.id)),
slog.Int64("maximum", f.max),
)
}
// debugFrameMaxStreams is a MAX_STREAMS frame.
type debugFrameMaxStreams struct {
streamType streamType
max int64
}
func parseDebugFrameMaxStreams(b []byte) (f debugFrameMaxStreams, n int) {
f.streamType, f.max, n = consumeMaxStreamsFrame(b)
return f, n
}
func (f debugFrameMaxStreams) String() string {
return fmt.Sprintf("MAX_STREAMS Type=%v Max=%v", f.streamType, f.max)
}
func (f debugFrameMaxStreams) write(w *packetWriter) bool {
return w.appendMaxStreamsFrame(f.streamType, f.max)
}
func (f debugFrameMaxStreams) LogValue() slog.Value {
return slog.GroupValue(
slog.String("frame_type", "max_streams"),
slog.String("stream_type", f.streamType.qlogString()),
slog.Int64("maximum", f.max),
)
}
// debugFrameDataBlocked is a DATA_BLOCKED frame.
type debugFrameDataBlocked struct {
max int64
}
func parseDebugFrameDataBlocked(b []byte) (f debugFrameDataBlocked, n int) {
f.max, n = consumeDataBlockedFrame(b)
return f, n
}
func (f debugFrameDataBlocked) String() string {
return fmt.Sprintf("DATA_BLOCKED Max=%v", f.max)
}
func (f debugFrameDataBlocked) write(w *packetWriter) bool {
return w.appendDataBlockedFrame(f.max)
}
func (f debugFrameDataBlocked) LogValue() slog.Value {
return slog.GroupValue(
slog.String("frame_type", "data_blocked"),
slog.Int64("limit", f.max),
)
}
// debugFrameStreamDataBlocked is a STREAM_DATA_BLOCKED frame.
type debugFrameStreamDataBlocked struct {
id streamID
max int64
}
func parseDebugFrameStreamDataBlocked(b []byte) (f debugFrameStreamDataBlocked, n int) {
f.id, f.max, n = consumeStreamDataBlockedFrame(b)
return f, n
}
func (f debugFrameStreamDataBlocked) String() string {
return fmt.Sprintf("STREAM_DATA_BLOCKED ID=%v Max=%v", f.id, f.max)
}
func (f debugFrameStreamDataBlocked) write(w *packetWriter) bool {
return w.appendStreamDataBlockedFrame(f.id, f.max)
}
func (f debugFrameStreamDataBlocked) LogValue() slog.Value {
return slog.GroupValue(
slog.String("frame_type", "stream_data_blocked"),
slog.Uint64("stream_id", uint64(f.id)),
slog.Int64("limit", f.max),
)
}
// debugFrameStreamsBlocked is a STREAMS_BLOCKED frame.
type debugFrameStreamsBlocked struct {
streamType streamType
max int64
}
func parseDebugFrameStreamsBlocked(b []byte) (f debugFrameStreamsBlocked, n int) {
f.streamType, f.max, n = consumeStreamsBlockedFrame(b)
return f, n
}
func (f debugFrameStreamsBlocked) String() string {
return fmt.Sprintf("STREAMS_BLOCKED Type=%v Max=%v", f.streamType, f.max)
}
func (f debugFrameStreamsBlocked) write(w *packetWriter) bool {
return w.appendStreamsBlockedFrame(f.streamType, f.max)
}
func (f debugFrameStreamsBlocked) LogValue() slog.Value {
return slog.GroupValue(
slog.String("frame_type", "streams_blocked"),
slog.String("stream_type", f.streamType.qlogString()),
slog.Int64("limit", f.max),
)
}
// debugFrameNewConnectionID is a NEW_CONNECTION_ID frame.
type debugFrameNewConnectionID struct {
seq int64
retirePriorTo int64
connID []byte
token statelessResetToken
}
func parseDebugFrameNewConnectionID(b []byte) (f debugFrameNewConnectionID, n int) {
f.seq, f.retirePriorTo, f.connID, f.token, n = consumeNewConnectionIDFrame(b)
return f, n
}
func (f debugFrameNewConnectionID) String() string {
return fmt.Sprintf("NEW_CONNECTION_ID Seq=%v Retire=%v ID=%x Token=%x", f.seq, f.retirePriorTo, f.connID, f.token[:])
}
func (f debugFrameNewConnectionID) write(w *packetWriter) bool {
return w.appendNewConnectionIDFrame(f.seq, f.retirePriorTo, f.connID, f.token)
}
func (f debugFrameNewConnectionID) LogValue() slog.Value {
return slog.GroupValue(
slog.String("frame_type", "new_connection_id"),
slog.Int64("sequence_number", f.seq),
slog.Int64("retire_prior_to", f.retirePriorTo),
slogHexstring("connection_id", f.connID),
slogHexstring("stateless_reset_token", f.token[:]),
)
}
// debugFrameRetireConnectionID is a NEW_CONNECTION_ID frame.
type debugFrameRetireConnectionID struct {
seq int64
}
func parseDebugFrameRetireConnectionID(b []byte) (f debugFrameRetireConnectionID, n int) {
f.seq, n = consumeRetireConnectionIDFrame(b)
return f, n
}
func (f debugFrameRetireConnectionID) String() string {
return fmt.Sprintf("RETIRE_CONNECTION_ID Seq=%v", f.seq)
}
func (f debugFrameRetireConnectionID) write(w *packetWriter) bool {
return w.appendRetireConnectionIDFrame(f.seq)
}
func (f debugFrameRetireConnectionID) LogValue() slog.Value {
return slog.GroupValue(
slog.String("frame_type", "retire_connection_id"),
slog.Int64("sequence_number", f.seq),
)
}
// debugFramePathChallenge is a PATH_CHALLENGE frame.
type debugFramePathChallenge struct {
data pathChallengeData
}
func parseDebugFramePathChallenge(b []byte) (f debugFramePathChallenge, n int) {
f.data, n = consumePathChallengeFrame(b)
return f, n
}
func (f debugFramePathChallenge) String() string {
return fmt.Sprintf("PATH_CHALLENGE Data=%x", f.data)
}
func (f debugFramePathChallenge) write(w *packetWriter) bool {
return w.appendPathChallengeFrame(f.data)
}
func (f debugFramePathChallenge) LogValue() slog.Value {
return slog.GroupValue(
slog.String("frame_type", "path_challenge"),
slog.String("data", fmt.Sprintf("%x", f.data)),
)
}
// debugFramePathResponse is a PATH_RESPONSE frame.
type debugFramePathResponse struct {
data pathChallengeData
}
func parseDebugFramePathResponse(b []byte) (f debugFramePathResponse, n int) {
f.data, n = consumePathResponseFrame(b)
return f, n
}
func (f debugFramePathResponse) String() string {
return fmt.Sprintf("PATH_RESPONSE Data=%x", f.data)
}
func (f debugFramePathResponse) write(w *packetWriter) bool {
return w.appendPathResponseFrame(f.data)
}
func (f debugFramePathResponse) LogValue() slog.Value {
return slog.GroupValue(
slog.String("frame_type", "path_response"),
slog.String("data", fmt.Sprintf("%x", f.data)),
)
}
// debugFrameConnectionCloseTransport is a CONNECTION_CLOSE frame carrying a transport error.
type debugFrameConnectionCloseTransport struct {
code transportError
frameType uint64
reason string
}
func parseDebugFrameConnectionCloseTransport(b []byte) (f debugFrameConnectionCloseTransport, n int) {
f.code, f.frameType, f.reason, n = consumeConnectionCloseTransportFrame(b)
return f, n
}
func (f debugFrameConnectionCloseTransport) String() string {
s := fmt.Sprintf("CONNECTION_CLOSE Code=%v", f.code)
if f.frameType != 0 {
s += fmt.Sprintf(" FrameType=%v", f.frameType)
}
if f.reason != "" {
s += fmt.Sprintf(" Reason=%q", f.reason)
}
return s
}
func (f debugFrameConnectionCloseTransport) write(w *packetWriter) bool {
return w.appendConnectionCloseTransportFrame(f.code, f.frameType, f.reason)
}
func (f debugFrameConnectionCloseTransport) LogValue() slog.Value {
return slog.GroupValue(
slog.String("frame_type", "connection_close"),
slog.String("error_space", "transport"),
slog.Uint64("error_code_value", uint64(f.code)),
slog.String("reason", f.reason),
)
}
// debugFrameConnectionCloseApplication is a CONNECTION_CLOSE frame carrying an application error.
type debugFrameConnectionCloseApplication struct {
code uint64
reason string
}
func parseDebugFrameConnectionCloseApplication(b []byte) (f debugFrameConnectionCloseApplication, n int) {
f.code, f.reason, n = consumeConnectionCloseApplicationFrame(b)
return f, n
}
func (f debugFrameConnectionCloseApplication) String() string {
s := fmt.Sprintf("CONNECTION_CLOSE AppCode=%v", f.code)
if f.reason != "" {
s += fmt.Sprintf(" Reason=%q", f.reason)
}
return s
}
func (f debugFrameConnectionCloseApplication) write(w *packetWriter) bool {
return w.appendConnectionCloseApplicationFrame(f.code, f.reason)
}
func (f debugFrameConnectionCloseApplication) LogValue() slog.Value {
return slog.GroupValue(
slog.String("frame_type", "connection_close"),
slog.String("error_space", "application"),
slog.Uint64("error_code_value", uint64(f.code)),
slog.String("reason", f.reason),
)
}
// debugFrameHandshakeDone is a HANDSHAKE_DONE frame.
type debugFrameHandshakeDone struct{}
func parseDebugFrameHandshakeDone(b []byte) (f debugFrameHandshakeDone, n int) {
return f, 1
}
func (f debugFrameHandshakeDone) String() string {
return "HANDSHAKE_DONE"
}
func (f debugFrameHandshakeDone) write(w *packetWriter) bool {
return w.appendHandshakeDoneFrame()
}
func (f debugFrameHandshakeDone) LogValue() slog.Value {
return slog.GroupValue(
slog.String("frame_type", "handshake_done"),
)
}
// Copyright 2023 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 quic
import "context"
// An gate is a monitor (mutex + condition variable) with one bit of state.
//
// The condition may be either set or unset.
// Lock operations may be unconditional, or wait for the condition to be set.
// Unlock operations record the new state of the condition.
type gate struct {
// When unlocked, exactly one of set or unset contains a value.
// When locked, neither chan contains a value.
set chan struct{}
unset chan struct{}
}
// newGate returns a new, unlocked gate with the condition unset.
func newGate() gate {
g := newLockedGate()
g.unlock(false)
return g
}
// newLockedGate returns a new, locked gate.
func newLockedGate() gate {
return gate{
set: make(chan struct{}, 1),
unset: make(chan struct{}, 1),
}
}
// lock acquires the gate unconditionally.
// It reports whether the condition is set.
func (g *gate) lock() (set bool) {
select {
case <-g.set:
return true
case <-g.unset:
return false
}
}
// waitAndLock waits until the condition is set before acquiring the gate.
// If the context expires, waitAndLock returns an error and does not acquire the gate.
func (g *gate) waitAndLock(ctx context.Context) error {
select {
case <-g.set:
return nil
default:
}
select {
case <-g.set:
return nil
case <-ctx.Done():
return ctx.Err()
}
}
// lockIfSet acquires the gate if and only if the condition is set.
func (g *gate) lockIfSet() (acquired bool) {
select {
case <-g.set:
return true
default:
return false
}
}
// unlock sets the condition and releases the gate.
func (g *gate) unlock(set bool) {
if set {
g.set <- struct{}{}
} else {
g.unset <- struct{}{}
}
}
// unlockFunc sets the condition to the result of f and releases the gate.
// Useful in defers.
func (g *gate) unlockFunc(f func() bool) {
g.unlock(f())
}
// Copyright 2023 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 quic
import (
"time"
)
// idleState tracks connection idle events.
//
// Before the handshake is confirmed, the idle timeout is Config.HandshakeTimeout.
//
// After the handshake is confirmed, the idle timeout is
// the minimum of Config.MaxIdleTimeout and the peer's max_idle_timeout transport parameter.
//
// If KeepAlivePeriod is set, keep-alive pings are sent.
// Keep-alives are only sent after the handshake is confirmed.
//
// https://www.rfc-editor.org/rfc/rfc9000#section-10.1
type idleState struct {
// idleDuration is the negotiated idle timeout for the connection.
idleDuration time.Duration
// idleTimeout is the time at which the connection will be closed due to inactivity.
idleTimeout time.Time
// nextTimeout is the time of the next idle event.
// If nextTimeout == idleTimeout, this is the idle timeout.
// Otherwise, this is the keep-alive timeout.
nextTimeout time.Time
// sentSinceLastReceive is set if we have sent an ack-eliciting packet
// since the last time we received and processed a packet from the peer.
sentSinceLastReceive bool
}
// receivePeerMaxIdleTimeout handles the peer's max_idle_timeout transport parameter.
func (c *Conn) receivePeerMaxIdleTimeout(peerMaxIdleTimeout time.Duration) {
localMaxIdleTimeout := c.config.maxIdleTimeout()
switch {
case localMaxIdleTimeout == 0:
c.idle.idleDuration = peerMaxIdleTimeout
case peerMaxIdleTimeout == 0:
c.idle.idleDuration = localMaxIdleTimeout
default:
c.idle.idleDuration = min(localMaxIdleTimeout, peerMaxIdleTimeout)
}
}
func (c *Conn) idleHandlePacketReceived(now time.Time) {
if !c.handshakeConfirmed.isSet() {
return
}
// "An endpoint restarts its idle timer when a packet from its peer is
// received and processed successfully."
// https://www.rfc-editor.org/rfc/rfc9000#section-10.1-3
c.idle.sentSinceLastReceive = false
c.restartIdleTimer(now)
}
func (c *Conn) idleHandlePacketSent(now time.Time, sent *sentPacket) {
// "An endpoint also restarts its idle timer when sending an ack-eliciting packet
// if no other ack-eliciting packets have been sent since
// last receiving and processing a packet."
// https://www.rfc-editor.org/rfc/rfc9000#section-10.1-3
if c.idle.sentSinceLastReceive || !sent.ackEliciting || !c.handshakeConfirmed.isSet() {
return
}
c.idle.sentSinceLastReceive = true
c.restartIdleTimer(now)
}
func (c *Conn) restartIdleTimer(now time.Time) {
if !c.isAlive() {
// Connection is closing, disable timeouts.
c.idle.idleTimeout = time.Time{}
c.idle.nextTimeout = time.Time{}
return
}
var idleDuration time.Duration
if c.handshakeConfirmed.isSet() {
idleDuration = c.idle.idleDuration
} else {
idleDuration = c.config.handshakeTimeout()
}
if idleDuration == 0 {
c.idle.idleTimeout = time.Time{}
} else {
// "[...] endpoints MUST increase the idle timeout period to be
// at least three times the current Probe Timeout (PTO)."
// https://www.rfc-editor.org/rfc/rfc9000#section-10.1-4
idleDuration = max(idleDuration, 3*c.loss.ptoPeriod())
c.idle.idleTimeout = now.Add(idleDuration)
}
// Set the time of our next event:
// The idle timer if no keep-alive is set, or the keep-alive timer if one is.
c.idle.nextTimeout = c.idle.idleTimeout
keepAlive := c.config.keepAlivePeriod()
switch {
case !c.handshakeConfirmed.isSet():
// We do not send keep-alives before the handshake is complete.
case keepAlive <= 0:
// Keep-alives are not enabled.
case c.idle.sentSinceLastReceive:
// We have sent an ack-eliciting packet to the peer.
// If they don't acknowledge it, loss detection will follow up with PTO probes,
// which will function as keep-alives.
// We don't need to send further pings.
case idleDuration == 0:
// The connection does not have a negotiated idle timeout.
// Send keep-alives anyway, since they may be required to keep middleboxes
// from losing state.
c.idle.nextTimeout = now.Add(keepAlive)
default:
// Schedule our next keep-alive.
// If our configured keep-alive period is greater than half the negotiated
// connection idle timeout, we reduce the keep-alive period to half
// the idle timeout to ensure we have time for the ping to arrive.
c.idle.nextTimeout = now.Add(min(keepAlive, idleDuration/2))
}
}
func (c *Conn) appendKeepAlive(now time.Time) bool {
if c.idle.nextTimeout.IsZero() || c.idle.nextTimeout.After(now) {
return true // timer has not expired
}
if c.idle.nextTimeout.Equal(c.idle.idleTimeout) {
return true // no keepalive timer set, only idle
}
if c.idle.sentSinceLastReceive {
return true // already sent an ack-eliciting packet
}
if c.w.sent.ackEliciting {
return true // this packet is already ack-eliciting
}
// Send an ack-eliciting PING frame to the peer to keep the connection alive.
return c.w.appendPingFrame()
}
var errHandshakeTimeout error = localTransportError{
code: errConnectionRefused,
reason: "handshake timeout",
}
func (c *Conn) idleAdvance(now time.Time) (shouldExit bool) {
if c.idle.idleTimeout.IsZero() || now.Before(c.idle.idleTimeout) {
return false
}
c.idle.idleTimeout = time.Time{}
c.idle.nextTimeout = time.Time{}
if !c.handshakeConfirmed.isSet() {
// Handshake timeout has expired.
// If we're a server, we're refusing the too-slow client.
// If we're a client, we're giving up.
// In either case, we're going to send a CONNECTION_CLOSE frame and
// enter the closing state rather than unceremoniously dropping the connection,
// since the peer might still be trying to complete the handshake.
c.abort(now, errHandshakeTimeout)
return false
}
// Idle timeout has expired.
//
// "[...] the connection is silently closed and its state is discarded [...]"
// https://www.rfc-editor.org/rfc/rfc9000#section-10.1-1
return true
}
// Copyright 2023 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 quic
import (
"fmt"
"os"
"strings"
)
var logPackets bool
// Parse GODEBUG settings.
//
// GODEBUG=quiclogpackets=1 -- log every packet sent and received.
func init() {
s := os.Getenv("GODEBUG")
for len(s) > 0 {
var opt string
opt, s, _ = strings.Cut(s, ",")
switch opt {
case "quiclogpackets=1":
logPackets = true
}
}
}
func logInboundLongPacket(c *Conn, p longPacket) {
if !logPackets {
return
}
prefix := c.String()
fmt.Printf("%v recv %v %v\n", prefix, p.ptype, p.num)
logFrames(prefix+" <- ", p.payload)
}
func logInboundShortPacket(c *Conn, p shortPacket) {
if !logPackets {
return
}
prefix := c.String()
fmt.Printf("%v recv 1-RTT %v\n", prefix, p.num)
logFrames(prefix+" <- ", p.payload)
}
func logSentPacket(c *Conn, ptype packetType, pnum packetNumber, src, dst, payload []byte) {
if !logPackets || len(payload) == 0 {
return
}
prefix := c.String()
fmt.Printf("%v send %v %v\n", prefix, ptype, pnum)
logFrames(prefix+" -> ", payload)
}
func logFrames(prefix string, payload []byte) {
for len(payload) > 0 {
f, n := parseDebugFrame(payload)
if n < 0 {
fmt.Printf("%vBAD DATA\n", prefix)
break
}
payload = payload[n:]
fmt.Printf("%v%v\n", prefix, f)
}
}
// Copyright 2023 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 quic
import (
"context"
"log/slog"
"math"
"time"
)
type lossState struct {
side connSide
// True when the handshake is confirmed.
// https://www.rfc-editor.org/rfc/rfc9001#section-4.1.2
handshakeConfirmed bool
// Peer's max_ack_delay transport parameter.
// https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-4.28.1
maxAckDelay time.Duration
// Time of the next event: PTO expiration (if ptoTimerArmed is true),
// or loss detection.
// The connection must call lossState.advance when the timer expires.
timer time.Time
// True when the PTO timer is set.
ptoTimerArmed bool
// True when the PTO timer has expired and a probe packet has not yet been sent.
ptoExpired bool
// Count of PTO expirations since the lack received acknowledgement.
// https://www.rfc-editor.org/rfc/rfc9002#section-6.2.1-9
ptoBackoffCount int
// Anti-amplification limit: Three times the amount of data received from
// the peer, less the amount of data sent.
//
// Set to antiAmplificationUnlimited (MaxInt) to disable the limit.
// The limit is always disabled for clients, and for servers after the
// peer's address is validated.
//
// Anti-amplification is per-address; this will need to change if/when we
// support address migration.
//
// https://www.rfc-editor.org/rfc/rfc9000#section-8-2
antiAmplificationLimit int
// Count of non-ack-eliciting packets (ACKs) sent since the last ack-eliciting one.
consecutiveNonAckElicitingPackets int
rtt rttState
pacer pacerState
cc *ccReno
// Per-space loss detection state.
spaces [numberSpaceCount]struct {
sentPacketList
maxAcked packetNumber
lastAckEliciting packetNumber
}
// Temporary state used when processing an ACK frame.
ackFrameRTT time.Duration // RTT from latest packet in frame
ackFrameContainsAckEliciting bool // newly acks an ack-eliciting packet?
}
const antiAmplificationUnlimited = math.MaxInt
func (c *lossState) init(side connSide, maxDatagramSize int, now time.Time) {
c.side = side
if side == clientSide {
// Clients don't have an anti-amplification limit.
c.antiAmplificationLimit = antiAmplificationUnlimited
}
c.rtt.init()
c.cc = newReno(maxDatagramSize)
c.pacer.init(now, c.cc.congestionWindow, timerGranularity)
// Peer's assumed max_ack_delay, prior to receiving transport parameters.
// https://www.rfc-editor.org/rfc/rfc9000#section-18.2
c.maxAckDelay = 25 * time.Millisecond
for space := range c.spaces {
c.spaces[space].maxAcked = -1
c.spaces[space].lastAckEliciting = -1
}
}
// setMaxAckDelay sets the max_ack_delay transport parameter received from the peer.
func (c *lossState) setMaxAckDelay(d time.Duration) {
if d >= (1<<14)*time.Millisecond {
// Values of 2^14 or greater are invalid.
// https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-4.28.1
return
}
c.maxAckDelay = d
}
// confirmHandshake indicates the handshake has been confirmed.
func (c *lossState) confirmHandshake() {
c.handshakeConfirmed = true
}
// validateClientAddress disables the anti-amplification limit after
// a server validates a client's address.
func (c *lossState) validateClientAddress() {
c.antiAmplificationLimit = antiAmplificationUnlimited
}
// minDatagramSize is the minimum datagram size permitted by
// anti-amplification protection.
//
// Defining a minimum size avoids the case where, say, anti-amplification
// technically allows us to send a 1-byte datagram, but no such datagram
// can be constructed.
const minPacketSize = 128
type ccLimit int
const (
ccOK = ccLimit(iota) // OK to send
ccBlocked // sending blocked by anti-amplification
ccLimited // sending blocked by congestion control
ccPaced // sending allowed by congestion, but delayed by pacer
)
// sendLimit reports whether sending is possible at this time.
// When sending is pacing limited, it returns the next time a packet may be sent.
func (c *lossState) sendLimit(now time.Time) (limit ccLimit, next time.Time) {
if c.antiAmplificationLimit < minPacketSize {
// When at the anti-amplification limit, we may not send anything.
return ccBlocked, time.Time{}
}
if c.ptoExpired {
// On PTO expiry, send a probe.
return ccOK, time.Time{}
}
if !c.cc.canSend() {
// Congestion control blocks sending.
return ccLimited, time.Time{}
}
if c.cc.bytesInFlight == 0 {
// If no bytes are in flight, send packet unpaced.
return ccOK, time.Time{}
}
canSend, next := c.pacer.canSend(now)
if !canSend {
// Pacer blocks sending.
return ccPaced, next
}
return ccOK, time.Time{}
}
// maxSendSize reports the maximum datagram size that may be sent.
func (c *lossState) maxSendSize() int {
return min(c.antiAmplificationLimit, c.cc.maxDatagramSize)
}
// advance is called when time passes.
// The lossf function is called for each packet newly detected as lost.
func (c *lossState) advance(now time.Time, lossf func(numberSpace, *sentPacket, packetFate)) {
c.pacer.advance(now, c.cc.congestionWindow, c.rtt.smoothedRTT)
if c.ptoTimerArmed && !c.timer.IsZero() && !c.timer.After(now) {
c.ptoExpired = true
c.timer = time.Time{}
c.ptoBackoffCount++
}
c.detectLoss(now, lossf)
}
// nextNumber returns the next packet number to use in a space.
func (c *lossState) nextNumber(space numberSpace) packetNumber {
return c.spaces[space].nextNum
}
// skipNumber skips a packet number as a defense against optimistic ACK attacks.
func (c *lossState) skipNumber(now time.Time, space numberSpace) {
sent := newSentPacket()
sent.num = c.spaces[space].nextNum
sent.time = now
sent.state = sentPacketUnsent
c.spaces[space].add(sent)
}
// packetSent records a sent packet.
func (c *lossState) packetSent(now time.Time, log *slog.Logger, space numberSpace, sent *sentPacket) {
sent.time = now
c.spaces[space].add(sent)
size := sent.size
if c.antiAmplificationLimit != antiAmplificationUnlimited {
c.antiAmplificationLimit = max(0, c.antiAmplificationLimit-size)
}
if sent.inFlight {
c.cc.packetSent(now, log, space, sent)
c.pacer.packetSent(now, size, c.cc.congestionWindow, c.rtt.smoothedRTT)
if sent.ackEliciting {
c.spaces[space].lastAckEliciting = sent.num
c.ptoExpired = false // reset expired PTO timer after sending probe
}
c.scheduleTimer(now)
if logEnabled(log, QLogLevelPacket) {
logBytesInFlight(log, c.cc.bytesInFlight)
}
}
if sent.ackEliciting {
c.consecutiveNonAckElicitingPackets = 0
} else {
c.consecutiveNonAckElicitingPackets++
}
}
// datagramReceived records a datagram (not packet!) received from the peer.
func (c *lossState) datagramReceived(now time.Time, size int) {
if c.antiAmplificationLimit != antiAmplificationUnlimited {
c.antiAmplificationLimit += 3 * size
// Reset the PTO timer, possibly to a point in the past, in which
// case the caller should execute it immediately.
// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.2.1-2
c.scheduleTimer(now)
if c.ptoTimerArmed && !c.timer.IsZero() && !c.timer.After(now) {
c.ptoExpired = true
c.timer = time.Time{}
}
}
}
// receiveAckStart starts processing an ACK frame.
// Call receiveAckRange for each range in the frame.
// Call receiveAckFrameEnd after all ranges are processed.
func (c *lossState) receiveAckStart() {
c.ackFrameContainsAckEliciting = false
c.ackFrameRTT = -1
}
// receiveAckRange processes a range within an ACK frame.
// The ackf function is called for each newly-acknowledged packet.
func (c *lossState) receiveAckRange(now time.Time, space numberSpace, rangeIndex int, start, end packetNumber, ackf func(numberSpace, *sentPacket, packetFate)) error {
// Limit our range to the intersection of the ACK range and
// the in-flight packets we have state for.
if s := c.spaces[space].start(); start < s {
start = s
}
if e := c.spaces[space].end(); end > e {
return localTransportError{
code: errProtocolViolation,
reason: "acknowledgement for unsent packet",
}
}
if start >= end {
return nil
}
if rangeIndex == 0 {
// If the latest packet in the ACK frame is newly-acked,
// record the RTT in c.ackFrameRTT.
sent := c.spaces[space].num(end - 1)
if sent.state == sentPacketSent {
c.ackFrameRTT = max(0, now.Sub(sent.time))
}
}
for pnum := start; pnum < end; pnum++ {
sent := c.spaces[space].num(pnum)
if sent.state == sentPacketUnsent {
return localTransportError{
code: errProtocolViolation,
reason: "acknowledgement for unsent packet",
}
}
if sent.state != sentPacketSent {
continue
}
// This is a newly-acknowledged packet.
if pnum > c.spaces[space].maxAcked {
c.spaces[space].maxAcked = pnum
}
sent.state = sentPacketAcked
c.cc.packetAcked(now, sent)
ackf(space, sent, packetAcked)
if sent.ackEliciting {
c.ackFrameContainsAckEliciting = true
}
}
return nil
}
// receiveAckEnd finishes processing an ack frame.
// The lossf function is called for each packet newly detected as lost.
func (c *lossState) receiveAckEnd(now time.Time, log *slog.Logger, space numberSpace, ackDelay time.Duration, lossf func(numberSpace, *sentPacket, packetFate)) {
c.spaces[space].sentPacketList.clean()
// Update the RTT sample when the largest acknowledged packet in the ACK frame
// is newly acknowledged, and at least one newly acknowledged packet is ack-eliciting.
// https://www.rfc-editor.org/rfc/rfc9002.html#section-5.1-2.2
if c.ackFrameRTT >= 0 && c.ackFrameContainsAckEliciting {
c.rtt.updateSample(now, c.handshakeConfirmed, space, c.ackFrameRTT, ackDelay, c.maxAckDelay)
}
// Reset the PTO backoff.
// Exception: A client does not reset the backoff on acks for Initial packets.
// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1-9
if !(c.side == clientSide && space == initialSpace) {
c.ptoBackoffCount = 0
}
// If the client has set a PTO timer with no packets in flight
// we want to restart that timer now. Clearing c.timer does this.
// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.2.1-3
c.timer = time.Time{}
c.detectLoss(now, lossf)
c.cc.packetBatchEnd(now, log, space, &c.rtt, c.maxAckDelay)
if logEnabled(log, QLogLevelPacket) {
var ssthresh slog.Attr
if c.cc.slowStartThreshold != math.MaxInt {
ssthresh = slog.Int("ssthresh", c.cc.slowStartThreshold)
}
log.LogAttrs(context.Background(), QLogLevelPacket,
"recovery:metrics_updated",
slog.Duration("min_rtt", c.rtt.minRTT),
slog.Duration("smoothed_rtt", c.rtt.smoothedRTT),
slog.Duration("latest_rtt", c.rtt.latestRTT),
slog.Duration("rtt_variance", c.rtt.rttvar),
slog.Int("congestion_window", c.cc.congestionWindow),
slog.Int("bytes_in_flight", c.cc.bytesInFlight),
ssthresh,
)
}
}
// discardPackets declares that packets within a number space will not be delivered
// and that data contained in them should be resent.
// For example, after receiving a Retry packet we discard already-sent Initial packets.
func (c *lossState) discardPackets(space numberSpace, log *slog.Logger, lossf func(numberSpace, *sentPacket, packetFate)) {
for i := 0; i < c.spaces[space].size; i++ {
sent := c.spaces[space].nth(i)
if sent.state != sentPacketSent {
// This should not be possible, since we only discard packets
// in spaces which have never received an ack, but check anyway.
continue
}
sent.state = sentPacketLost
c.cc.packetDiscarded(sent)
lossf(numberSpace(space), sent, packetLost)
}
c.spaces[space].clean()
if logEnabled(log, QLogLevelPacket) {
logBytesInFlight(log, c.cc.bytesInFlight)
}
}
// discardKeys is called when dropping packet protection keys for a number space.
func (c *lossState) discardKeys(now time.Time, log *slog.Logger, space numberSpace) {
// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.4
for i := 0; i < c.spaces[space].size; i++ {
sent := c.spaces[space].nth(i)
if sent.state != sentPacketSent {
continue
}
c.cc.packetDiscarded(sent)
}
c.spaces[space].discard()
c.spaces[space].maxAcked = -1
c.spaces[space].lastAckEliciting = -1
c.scheduleTimer(now)
if logEnabled(log, QLogLevelPacket) {
logBytesInFlight(log, c.cc.bytesInFlight)
}
}
func (c *lossState) lossDuration() time.Duration {
// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.1.2
return max((9*max(c.rtt.smoothedRTT, c.rtt.latestRTT))/8, timerGranularity)
}
func (c *lossState) detectLoss(now time.Time, lossf func(numberSpace, *sentPacket, packetFate)) {
// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.1.1-1
const lossThreshold = 3
lossTime := now.Add(-c.lossDuration())
for space := numberSpace(0); space < numberSpaceCount; space++ {
for i := 0; i < c.spaces[space].size; i++ {
sent := c.spaces[space].nth(i)
if sent.state != sentPacketSent {
continue
}
// RFC 9002 Section 6.1 states that a packet is only declared lost if it
// is "in flight", which excludes packets that contain only ACK frames.
// However, we need some way to determine when to drop state for ACK-only
// packets, and the loss algorithm in Appendix A handles loss detection of
// not-in-flight packets identically to all others, so we do the same here.
switch {
case c.spaces[space].maxAcked-sent.num >= lossThreshold:
// Packet threshold
// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.1.1
fallthrough
case sent.num <= c.spaces[space].maxAcked && !sent.time.After(lossTime):
// Time threshold
// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.1.2
sent.state = sentPacketLost
lossf(space, sent, packetLost)
if sent.inFlight {
c.cc.packetLost(now, space, sent, &c.rtt)
}
}
if sent.state != sentPacketLost {
break
}
}
c.spaces[space].clean()
}
c.scheduleTimer(now)
}
// scheduleTimer sets the loss or PTO timer.
//
// The connection is responsible for arranging for advance to be called after
// the timer expires.
//
// The timer may be set to a point in the past, in which advance should be called
// immediately. We don't do this here, because executing the timer can cause
// packet loss events, and it's simpler for the connection if loss events only
// occur when advancing time.
func (c *lossState) scheduleTimer(now time.Time) {
c.ptoTimerArmed = false
// Loss timer for sent packets.
// The loss timer is only started once a later packet has been acknowledged,
// and takes precedence over the PTO timer.
// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.1.2
var oldestPotentiallyLost time.Time
for space := numberSpace(0); space < numberSpaceCount; space++ {
if c.spaces[space].size > 0 && c.spaces[space].start() <= c.spaces[space].maxAcked {
firstTime := c.spaces[space].nth(0).time
if oldestPotentiallyLost.IsZero() || firstTime.Before(oldestPotentiallyLost) {
oldestPotentiallyLost = firstTime
}
}
}
if !oldestPotentiallyLost.IsZero() {
c.timer = oldestPotentiallyLost.Add(c.lossDuration())
return
}
// PTO timer.
if c.ptoExpired {
// PTO timer has expired, don't restart it until we send a probe.
c.timer = time.Time{}
return
}
if c.antiAmplificationLimit >= 0 && c.antiAmplificationLimit < minPacketSize {
// Server is at its anti-amplification limit and can't send any more data.
// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.2.1-1
c.timer = time.Time{}
return
}
// Timer starts at the most recently sent ack-eliciting packet.
// Prior to confirming the handshake, we consider the Initial and Handshake
// number spaces; after, we consider only Application Data.
var last time.Time
if !c.handshakeConfirmed {
for space := initialSpace; space <= handshakeSpace; space++ {
sent := c.spaces[space].num(c.spaces[space].lastAckEliciting)
if sent == nil {
continue
}
if last.IsZero() || last.After(sent.time) {
last = sent.time
}
}
} else {
sent := c.spaces[appDataSpace].num(c.spaces[appDataSpace].lastAckEliciting)
if sent != nil {
last = sent.time
}
}
if last.IsZero() &&
c.side == clientSide &&
c.spaces[handshakeSpace].maxAcked < 0 &&
!c.handshakeConfirmed {
// The client must always set a PTO timer prior to receiving an ack for a
// handshake packet or the handshake being confirmed.
// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.2.1
if !c.timer.IsZero() {
// If c.timer is non-zero here, we've already set the PTO timer and
// should leave it as-is rather than moving it forward.
c.ptoTimerArmed = true
return
}
last = now
} else if last.IsZero() {
c.timer = time.Time{}
return
}
c.timer = last.Add(c.ptoPeriod())
c.ptoTimerArmed = true
}
func (c *lossState) ptoPeriod() time.Duration {
// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1
return c.ptoBasePeriod() << c.ptoBackoffCount
}
func (c *lossState) ptoBasePeriod() time.Duration {
// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1
pto := c.rtt.smoothedRTT + max(4*c.rtt.rttvar, timerGranularity)
if c.handshakeConfirmed {
// The max_ack_delay is the maximum amount of time the peer might delay sending
// an ack to us. We only take it into account for the Application Data space.
// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1-4
pto += c.maxAckDelay
}
return pto
}
func logBytesInFlight(log *slog.Logger, bytesInFlight int) {
log.LogAttrs(context.Background(), QLogLevelPacket,
"recovery:metrics_updated",
slog.Int("bytes_in_flight", bytesInFlight),
)
}
// Copyright 2023 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 quic
func abs[T ~int | ~int64](a T) T {
if a < 0 {
return -a
}
return a
}
// Copyright 2023 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 quic
import (
"time"
)
// A pacerState controls the rate at which packets are sent using a leaky-bucket rate limiter.
//
// The pacer limits the maximum size of a burst of packets.
// When a burst exceeds this limit, it spreads subsequent packets
// over time.
//
// The bucket is initialized to the maximum burst size (ten packets by default),
// and fills at the rate:
//
// 1.25 * congestion_window / smoothed_rtt
//
// A sender can send one congestion window of packets per RTT,
// since the congestion window consumed by each packet is returned
// one round-trip later by the responding ack.
// The pacer permits sending at slightly faster than this rate to
// avoid underutilizing the congestion window.
//
// The pacer permits the bucket to become negative, and permits
// sending when non-negative. This biases slightly in favor of
// sending packets over limiting them, and permits bursts one
// packet greater than the configured maximum, but permits the pacer
// to be ignorant of the maximum packet size.
//
// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.7
type pacerState struct {
bucket int // measured in bytes
maxBucket int
timerGranularity time.Duration
lastUpdate time.Time
nextSend time.Time
}
func (p *pacerState) init(now time.Time, maxBurst int, timerGranularity time.Duration) {
// Bucket is limited to maximum burst size, which is the initial congestion window.
// https://www.rfc-editor.org/rfc/rfc9002#section-7.7-2
p.maxBucket = maxBurst
p.bucket = p.maxBucket
p.timerGranularity = timerGranularity
p.lastUpdate = now
p.nextSend = now
}
// pacerBytesForInterval returns the number of bytes permitted over an interval.
//
// rate = 1.25 * congestion_window / smoothed_rtt
// bytes = interval * rate
//
// https://www.rfc-editor.org/rfc/rfc9002#section-7.7-6
func pacerBytesForInterval(interval time.Duration, congestionWindow int, rtt time.Duration) int {
bytes := (int64(interval) * int64(congestionWindow)) / int64(rtt)
bytes = (bytes * 5) / 4 // bytes *= 1.25
return int(bytes)
}
// pacerIntervalForBytes returns the amount of time required for a number of bytes.
//
// time_per_byte = (smoothed_rtt / congestion_window) / 1.25
// interval = time_per_byte * bytes
//
// https://www.rfc-editor.org/rfc/rfc9002#section-7.7-8
func pacerIntervalForBytes(bytes int, congestionWindow int, rtt time.Duration) time.Duration {
interval := (int64(rtt) * int64(bytes)) / int64(congestionWindow)
interval = (interval * 4) / 5 // interval /= 1.25
return time.Duration(interval)
}
// advance is called when time passes.
func (p *pacerState) advance(now time.Time, congestionWindow int, rtt time.Duration) {
elapsed := now.Sub(p.lastUpdate)
if elapsed < 0 {
// Time has gone backward?
elapsed = 0
p.nextSend = now // allow a packet through to get back on track
if p.bucket < 0 {
p.bucket = 0
}
}
p.lastUpdate = now
if rtt == 0 {
// Avoid divide by zero in the implausible case that we measure no RTT.
p.bucket = p.maxBucket
return
}
// Refill the bucket.
delta := pacerBytesForInterval(elapsed, congestionWindow, rtt)
p.bucket = min(p.bucket+delta, p.maxBucket)
}
// packetSent is called to record transmission of a packet.
func (p *pacerState) packetSent(now time.Time, size, congestionWindow int, rtt time.Duration) {
p.bucket -= size
if p.bucket < -congestionWindow {
// Never allow the bucket to fall more than one congestion window in arrears.
// We can only fall this far behind if the sender is sending unpaced packets,
// the congestion window has been exceeded, or the RTT is less than the
// timer granularity.
//
// Limiting the minimum bucket size limits the maximum pacer delay
// to RTT/1.25.
p.bucket = -congestionWindow
}
if p.bucket >= 0 {
p.nextSend = now
return
}
// Next send occurs when the bucket has refilled to 0.
delay := pacerIntervalForBytes(-p.bucket, congestionWindow, rtt)
p.nextSend = now.Add(delay)
}
// canSend reports whether a packet can be sent now.
// If it returns false, next is the time when the next packet can be sent.
func (p *pacerState) canSend(now time.Time) (canSend bool, next time.Time) {
// If the next send time is within the timer granularity, send immediately.
if p.nextSend.After(now.Add(p.timerGranularity)) {
return false, p.nextSend
}
return true, time.Time{}
}
// Copyright 2023 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 quic
import (
"encoding/binary"
"fmt"
"golang.org/x/net/internal/quic/quicwire"
)
// packetType is a QUIC packet type.
// https://www.rfc-editor.org/rfc/rfc9000.html#section-17
type packetType byte
const (
packetTypeInvalid = packetType(iota)
packetTypeInitial
packetType0RTT
packetTypeHandshake
packetTypeRetry
packetType1RTT
packetTypeVersionNegotiation
)
func (p packetType) String() string {
switch p {
case packetTypeInitial:
return "Initial"
case packetType0RTT:
return "0-RTT"
case packetTypeHandshake:
return "Handshake"
case packetTypeRetry:
return "Retry"
case packetType1RTT:
return "1-RTT"
}
return fmt.Sprintf("unknown packet type %v", byte(p))
}
func (p packetType) qlogString() string {
switch p {
case packetTypeInitial:
return "initial"
case packetType0RTT:
return "0RTT"
case packetTypeHandshake:
return "handshake"
case packetTypeRetry:
return "retry"
case packetType1RTT:
return "1RTT"
}
return "unknown"
}
// Bits set in the first byte of a packet.
const (
headerFormLong = 0x80 // https://www.rfc-editor.org/rfc/rfc9000.html#section-17.2-3.2.1
headerFormShort = 0x00 // https://www.rfc-editor.org/rfc/rfc9000.html#section-17.3.1-4.2.1
fixedBit = 0x40 // https://www.rfc-editor.org/rfc/rfc9000.html#section-17.2-3.4.1
reservedLongBits = 0x0c // https://www.rfc-editor.org/rfc/rfc9000#section-17.2-8.2.1
reserved1RTTBits = 0x18 // https://www.rfc-editor.org/rfc/rfc9000#section-17.3.1-4.8.1
keyPhaseBit = 0x04 // https://www.rfc-editor.org/rfc/rfc9000#section-17.3.1-4.10.1
)
// Long Packet Type bits.
// https://www.rfc-editor.org/rfc/rfc9000.html#section-17.2-3.6.1
const (
longPacketTypeInitial = 0 << 4
longPacketType0RTT = 1 << 4
longPacketTypeHandshake = 2 << 4
longPacketTypeRetry = 3 << 4
)
// Frame types.
// https://www.rfc-editor.org/rfc/rfc9000.html#section-19
const (
frameTypePadding = 0x00
frameTypePing = 0x01
frameTypeAck = 0x02
frameTypeAckECN = 0x03
frameTypeResetStream = 0x04
frameTypeStopSending = 0x05
frameTypeCrypto = 0x06
frameTypeNewToken = 0x07
frameTypeStreamBase = 0x08 // low three bits carry stream flags
frameTypeMaxData = 0x10
frameTypeMaxStreamData = 0x11
frameTypeMaxStreamsBidi = 0x12
frameTypeMaxStreamsUni = 0x13
frameTypeDataBlocked = 0x14
frameTypeStreamDataBlocked = 0x15
frameTypeStreamsBlockedBidi = 0x16
frameTypeStreamsBlockedUni = 0x17
frameTypeNewConnectionID = 0x18
frameTypeRetireConnectionID = 0x19
frameTypePathChallenge = 0x1a
frameTypePathResponse = 0x1b
frameTypeConnectionCloseTransport = 0x1c
frameTypeConnectionCloseApplication = 0x1d
frameTypeHandshakeDone = 0x1e
)
// The low three bits of STREAM frames.
// https://www.rfc-editor.org/rfc/rfc9000.html#section-19.8
const (
streamOffBit = 0x04
streamLenBit = 0x02
streamFinBit = 0x01
)
// Maximum length of a connection ID.
const maxConnIDLen = 20
// isLongHeader returns true if b is the first byte of a long header.
func isLongHeader(b byte) bool {
return b&headerFormLong == headerFormLong
}
// getPacketType returns the type of a packet.
func getPacketType(b []byte) packetType {
if len(b) == 0 {
return packetTypeInvalid
}
if !isLongHeader(b[0]) {
if b[0]&fixedBit != fixedBit {
return packetTypeInvalid
}
return packetType1RTT
}
if len(b) < 5 {
return packetTypeInvalid
}
if b[1] == 0 && b[2] == 0 && b[3] == 0 && b[4] == 0 {
// Version Negotiation packets don't necessarily set the fixed bit.
return packetTypeVersionNegotiation
}
if b[0]&fixedBit != fixedBit {
return packetTypeInvalid
}
switch b[0] & 0x30 {
case longPacketTypeInitial:
return packetTypeInitial
case longPacketType0RTT:
return packetType0RTT
case longPacketTypeHandshake:
return packetTypeHandshake
case longPacketTypeRetry:
return packetTypeRetry
}
return packetTypeInvalid
}
// dstConnIDForDatagram returns the destination connection ID field of the
// first QUIC packet in a datagram.
func dstConnIDForDatagram(pkt []byte) (id []byte, ok bool) {
if len(pkt) < 1 {
return nil, false
}
var n int
var b []byte
if isLongHeader(pkt[0]) {
if len(pkt) < 6 {
return nil, false
}
n = int(pkt[5])
b = pkt[6:]
} else {
n = connIDLen
b = pkt[1:]
}
if len(b) < n {
return nil, false
}
return b[:n], true
}
// parseVersionNegotiation parses a Version Negotiation packet.
// The returned versions is a slice of big-endian uint32s.
// It returns (nil, nil, nil) for an invalid packet.
func parseVersionNegotiation(pkt []byte) (dstConnID, srcConnID, versions []byte) {
p, ok := parseGenericLongHeaderPacket(pkt)
if !ok {
return nil, nil, nil
}
if len(p.data)%4 != 0 {
return nil, nil, nil
}
return p.dstConnID, p.srcConnID, p.data
}
// appendVersionNegotiation appends a Version Negotiation packet to pkt,
// returning the result.
func appendVersionNegotiation(pkt, dstConnID, srcConnID []byte, versions ...uint32) []byte {
pkt = append(pkt, headerFormLong|fixedBit) // header byte
pkt = append(pkt, 0, 0, 0, 0) // Version (0 for Version Negotiation)
pkt = quicwire.AppendUint8Bytes(pkt, dstConnID) // Destination Connection ID
pkt = quicwire.AppendUint8Bytes(pkt, srcConnID) // Source Connection ID
for _, v := range versions {
pkt = binary.BigEndian.AppendUint32(pkt, v) // Supported Version
}
return pkt
}
// A longPacket is a long header packet.
type longPacket struct {
ptype packetType
version uint32
num packetNumber
dstConnID []byte
srcConnID []byte
payload []byte
// The extra data depends on the packet type:
// Initial: Token.
// Retry: Retry token and integrity tag.
extra []byte
}
// A shortPacket is a short header (1-RTT) packet.
type shortPacket struct {
num packetNumber
payload []byte
}
// A genericLongPacket is a long header packet of an arbitrary QUIC version.
// https://www.rfc-editor.org/rfc/rfc8999#section-5.1
type genericLongPacket struct {
version uint32
dstConnID []byte
srcConnID []byte
data []byte
}
func parseGenericLongHeaderPacket(b []byte) (p genericLongPacket, ok bool) {
if len(b) < 5 || !isLongHeader(b[0]) {
return genericLongPacket{}, false
}
b = b[1:]
// Version (32),
var n int
p.version, n = quicwire.ConsumeUint32(b)
if n < 0 {
return genericLongPacket{}, false
}
b = b[n:]
// Destination Connection ID Length (8),
// Destination Connection ID (0..2048),
p.dstConnID, n = quicwire.ConsumeUint8Bytes(b)
if n < 0 || len(p.dstConnID) > 2048/8 {
return genericLongPacket{}, false
}
b = b[n:]
// Source Connection ID Length (8),
// Source Connection ID (0..2048),
p.srcConnID, n = quicwire.ConsumeUint8Bytes(b)
if n < 0 || len(p.dstConnID) > 2048/8 {
return genericLongPacket{}, false
}
b = b[n:]
p.data = b
return p, true
}
// Copyright 2023 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 quic
// A packetNumber is a QUIC packet number.
// Packet numbers are integers in the range [0, 2^62-1].
//
// https://www.rfc-editor.org/rfc/rfc9000.html#section-12.3
type packetNumber int64
const maxPacketNumber = 1<<62 - 1 // https://www.rfc-editor.org/rfc/rfc9000.html#section-17.1-1
// decodePacketNumber decodes a truncated packet number, given
// the largest acknowledged packet number in this number space,
// the truncated number received in a packet, and the size of the
// number received in bytes.
//
// https://www.rfc-editor.org/rfc/rfc9000.html#section-17.1
// https://www.rfc-editor.org/rfc/rfc9000.html#section-a.3
func decodePacketNumber(largest, truncated packetNumber, numLenInBytes int) packetNumber {
expected := largest + 1
win := packetNumber(1) << (uint(numLenInBytes) * 8)
hwin := win / 2
mask := win - 1
candidate := (expected &^ mask) | truncated
if candidate <= expected-hwin && candidate < (1<<62)-win {
return candidate + win
}
if candidate > expected+hwin && candidate >= win {
return candidate - win
}
return candidate
}
// appendPacketNumber appends an encoded packet number to b.
// The packet number must be larger than the largest acknowledged packet number.
// When no packets have been acknowledged yet, largestAck is -1.
//
// https://www.rfc-editor.org/rfc/rfc9000.html#section-17.1-5
func appendPacketNumber(b []byte, pnum, largestAck packetNumber) []byte {
switch packetNumberLength(pnum, largestAck) {
case 1:
return append(b, byte(pnum))
case 2:
return append(b, byte(pnum>>8), byte(pnum))
case 3:
return append(b, byte(pnum>>16), byte(pnum>>8), byte(pnum))
default:
return append(b, byte(pnum>>24), byte(pnum>>16), byte(pnum>>8), byte(pnum))
}
}
// packetNumberLength returns the minimum length, in bytes, needed to encode
// a packet number given the largest acknowledged packet number.
// The packet number must be larger than the largest acknowledged packet number.
//
// https://www.rfc-editor.org/rfc/rfc9000.html#section-17.1-5
func packetNumberLength(pnum, largestAck packetNumber) int {
d := pnum - largestAck
switch {
case d < 0x80:
return 1
case d < 0x8000:
return 2
case d < 0x800000:
return 3
default:
return 4
}
}
// Copyright 2023 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 quic
import "golang.org/x/net/internal/quic/quicwire"
// parseLongHeaderPacket parses a QUIC long header packet.
//
// It does not parse Version Negotiation packets.
//
// On input, pkt contains a long header packet (possibly followed by more packets),
// k the decryption keys for the packet, and pnumMax the largest packet number seen
// in the number space of this packet.
//
// parseLongHeaderPacket returns the parsed packet with protection removed
// and its length in bytes.
//
// It returns an empty packet and -1 if the packet could not be parsed.
func parseLongHeaderPacket(pkt []byte, k fixedKeys, pnumMax packetNumber) (p longPacket, n int) {
if len(pkt) < 5 || !isLongHeader(pkt[0]) {
return longPacket{}, -1
}
// Header Form (1) = 1,
// Fixed Bit (1) = 1,
// Long Packet Type (2),
// Type-Specific Bits (4),
b := pkt
p.ptype = getPacketType(b)
if p.ptype == packetTypeInvalid {
return longPacket{}, -1
}
b = b[1:]
// Version (32),
p.version, n = quicwire.ConsumeUint32(b)
if n < 0 {
return longPacket{}, -1
}
b = b[n:]
if p.version == 0 {
// Version Negotiation packet; not handled here.
return longPacket{}, -1
}
// Destination Connection ID Length (8),
// Destination Connection ID (0..160),
p.dstConnID, n = quicwire.ConsumeUint8Bytes(b)
if n < 0 || len(p.dstConnID) > maxConnIDLen {
return longPacket{}, -1
}
b = b[n:]
// Source Connection ID Length (8),
// Source Connection ID (0..160),
p.srcConnID, n = quicwire.ConsumeUint8Bytes(b)
if n < 0 || len(p.dstConnID) > maxConnIDLen {
return longPacket{}, -1
}
b = b[n:]
switch p.ptype {
case packetTypeInitial:
// Token Length (i),
// Token (..),
p.extra, n = quicwire.ConsumeVarintBytes(b)
if n < 0 {
return longPacket{}, -1
}
b = b[n:]
case packetTypeRetry:
// Retry Token (..),
// Retry Integrity Tag (128),
p.extra = b
return p, len(pkt)
}
// Length (i),
payLen, n := quicwire.ConsumeVarint(b)
if n < 0 {
return longPacket{}, -1
}
b = b[n:]
if uint64(len(b)) < payLen {
return longPacket{}, -1
}
// Packet Number (8..32),
// Packet Payload (..),
pnumOff := len(pkt) - len(b)
pkt = pkt[:pnumOff+int(payLen)]
if k.isSet() {
var err error
p.payload, p.num, err = k.unprotect(pkt, pnumOff, pnumMax)
if err != nil {
return longPacket{}, -1
}
}
return p, len(pkt)
}
// skipLongHeaderPacket returns the length of the long header packet at the start of pkt,
// or -1 if the buffer does not contain a valid packet.
func skipLongHeaderPacket(pkt []byte) int {
// Header byte, 4 bytes of version.
n := 5
if len(pkt) <= n {
return -1
}
// Destination connection ID length, destination connection ID.
n += 1 + int(pkt[n])
if len(pkt) <= n {
return -1
}
// Source connection ID length, source connection ID.
n += 1 + int(pkt[n])
if len(pkt) <= n {
return -1
}
if getPacketType(pkt) == packetTypeInitial {
// Token length, token.
_, nn := quicwire.ConsumeVarintBytes(pkt[n:])
if nn < 0 {
return -1
}
n += nn
}
// Length, packet number, payload.
_, nn := quicwire.ConsumeVarintBytes(pkt[n:])
if nn < 0 {
return -1
}
n += nn
if len(pkt) < n {
return -1
}
return n
}
// parse1RTTPacket parses a QUIC 1-RTT (short header) packet.
//
// On input, pkt contains a short header packet, k the decryption keys for the packet,
// and pnumMax the largest packet number seen in the number space of this packet.
func parse1RTTPacket(pkt []byte, k *updatingKeyPair, dstConnIDLen int, pnumMax packetNumber) (p shortPacket, err error) {
pay, pnum, err := k.unprotect(pkt, 1+dstConnIDLen, pnumMax)
if err != nil {
return shortPacket{}, err
}
p.num = pnum
p.payload = pay
return p, nil
}
// Consume functions return n=-1 on conditions which result in FRAME_ENCODING_ERROR,
// which includes both general parse failures and specific violations of frame
// constraints.
func consumeAckFrame(frame []byte, f func(rangeIndex int, start, end packetNumber)) (largest packetNumber, ackDelay unscaledAckDelay, ecn ecnCounts, n int) {
b := frame[1:] // type
largestAck, n := quicwire.ConsumeVarint(b)
if n < 0 {
return 0, 0, ecnCounts{}, -1
}
b = b[n:]
v, n := quicwire.ConsumeVarintInt64(b)
if n < 0 {
return 0, 0, ecnCounts{}, -1
}
b = b[n:]
ackDelay = unscaledAckDelay(v)
ackRangeCount, n := quicwire.ConsumeVarint(b)
if n < 0 {
return 0, 0, ecnCounts{}, -1
}
b = b[n:]
rangeMax := packetNumber(largestAck)
for i := uint64(0); ; i++ {
rangeLen, n := quicwire.ConsumeVarint(b)
if n < 0 {
return 0, 0, ecnCounts{}, -1
}
b = b[n:]
rangeMin := rangeMax - packetNumber(rangeLen)
if rangeMin < 0 || rangeMin > rangeMax {
return 0, 0, ecnCounts{}, -1
}
f(int(i), rangeMin, rangeMax+1)
if i == ackRangeCount {
break
}
gap, n := quicwire.ConsumeVarint(b)
if n < 0 {
return 0, 0, ecnCounts{}, -1
}
b = b[n:]
rangeMax = rangeMin - packetNumber(gap) - 2
}
if frame[0] != frameTypeAckECN {
return packetNumber(largestAck), ackDelay, ecnCounts{}, len(frame) - len(b)
}
ect0Count, n := quicwire.ConsumeVarint(b)
if n < 0 {
return 0, 0, ecnCounts{}, -1
}
b = b[n:]
ect1Count, n := quicwire.ConsumeVarint(b)
if n < 0 {
return 0, 0, ecnCounts{}, -1
}
b = b[n:]
ecnCECount, n := quicwire.ConsumeVarint(b)
if n < 0 {
return 0, 0, ecnCounts{}, -1
}
b = b[n:]
ecn.t0 = int(ect0Count)
ecn.t1 = int(ect1Count)
ecn.ce = int(ecnCECount)
return packetNumber(largestAck), ackDelay, ecn, len(frame) - len(b)
}
func consumeResetStreamFrame(b []byte) (id streamID, code uint64, finalSize int64, n int) {
n = 1
idInt, nn := quicwire.ConsumeVarint(b[n:])
if nn < 0 {
return 0, 0, 0, -1
}
n += nn
code, nn = quicwire.ConsumeVarint(b[n:])
if nn < 0 {
return 0, 0, 0, -1
}
n += nn
v, nn := quicwire.ConsumeVarint(b[n:])
if nn < 0 {
return 0, 0, 0, -1
}
n += nn
finalSize = int64(v)
return streamID(idInt), code, finalSize, n
}
func consumeStopSendingFrame(b []byte) (id streamID, code uint64, n int) {
n = 1
idInt, nn := quicwire.ConsumeVarint(b[n:])
if nn < 0 {
return 0, 0, -1
}
n += nn
code, nn = quicwire.ConsumeVarint(b[n:])
if nn < 0 {
return 0, 0, -1
}
n += nn
return streamID(idInt), code, n
}
func consumeCryptoFrame(b []byte) (off int64, data []byte, n int) {
n = 1
v, nn := quicwire.ConsumeVarint(b[n:])
if nn < 0 {
return 0, nil, -1
}
off = int64(v)
n += nn
data, nn = quicwire.ConsumeVarintBytes(b[n:])
if nn < 0 {
return 0, nil, -1
}
n += nn
return off, data, n
}
func consumeNewTokenFrame(b []byte) (token []byte, n int) {
n = 1
data, nn := quicwire.ConsumeVarintBytes(b[n:])
if nn < 0 {
return nil, -1
}
if len(data) == 0 {
return nil, -1
}
n += nn
return data, n
}
func consumeStreamFrame(b []byte) (id streamID, off int64, fin bool, data []byte, n int) {
fin = (b[0] & 0x01) != 0
n = 1
idInt, nn := quicwire.ConsumeVarint(b[n:])
if nn < 0 {
return 0, 0, false, nil, -1
}
n += nn
if b[0]&0x04 != 0 {
v, nn := quicwire.ConsumeVarint(b[n:])
if nn < 0 {
return 0, 0, false, nil, -1
}
n += nn
off = int64(v)
}
if b[0]&0x02 != 0 {
data, nn = quicwire.ConsumeVarintBytes(b[n:])
if nn < 0 {
return 0, 0, false, nil, -1
}
n += nn
} else {
data = b[n:]
n += len(data)
}
if off+int64(len(data)) >= 1<<62 {
return 0, 0, false, nil, -1
}
return streamID(idInt), off, fin, data, n
}
func consumeMaxDataFrame(b []byte) (max int64, n int) {
n = 1
v, nn := quicwire.ConsumeVarint(b[n:])
if nn < 0 {
return 0, -1
}
n += nn
return int64(v), n
}
func consumeMaxStreamDataFrame(b []byte) (id streamID, max int64, n int) {
n = 1
v, nn := quicwire.ConsumeVarint(b[n:])
if nn < 0 {
return 0, 0, -1
}
n += nn
id = streamID(v)
v, nn = quicwire.ConsumeVarint(b[n:])
if nn < 0 {
return 0, 0, -1
}
n += nn
max = int64(v)
return id, max, n
}
func consumeMaxStreamsFrame(b []byte) (typ streamType, max int64, n int) {
switch b[0] {
case frameTypeMaxStreamsBidi:
typ = bidiStream
case frameTypeMaxStreamsUni:
typ = uniStream
default:
return 0, 0, -1
}
n = 1
v, nn := quicwire.ConsumeVarint(b[n:])
if nn < 0 {
return 0, 0, -1
}
n += nn
if v > maxStreamsLimit {
return 0, 0, -1
}
return typ, int64(v), n
}
func consumeStreamDataBlockedFrame(b []byte) (id streamID, max int64, n int) {
n = 1
v, nn := quicwire.ConsumeVarint(b[n:])
if nn < 0 {
return 0, 0, -1
}
n += nn
id = streamID(v)
max, nn = quicwire.ConsumeVarintInt64(b[n:])
if nn < 0 {
return 0, 0, -1
}
n += nn
return id, max, n
}
func consumeDataBlockedFrame(b []byte) (max int64, n int) {
n = 1
max, nn := quicwire.ConsumeVarintInt64(b[n:])
if nn < 0 {
return 0, -1
}
n += nn
return max, n
}
func consumeStreamsBlockedFrame(b []byte) (typ streamType, max int64, n int) {
if b[0] == frameTypeStreamsBlockedBidi {
typ = bidiStream
} else {
typ = uniStream
}
n = 1
max, nn := quicwire.ConsumeVarintInt64(b[n:])
if nn < 0 {
return 0, 0, -1
}
n += nn
return typ, max, n
}
func consumeNewConnectionIDFrame(b []byte) (seq, retire int64, connID []byte, resetToken statelessResetToken, n int) {
n = 1
var nn int
seq, nn = quicwire.ConsumeVarintInt64(b[n:])
if nn < 0 {
return 0, 0, nil, statelessResetToken{}, -1
}
n += nn
retire, nn = quicwire.ConsumeVarintInt64(b[n:])
if nn < 0 {
return 0, 0, nil, statelessResetToken{}, -1
}
n += nn
if seq < retire {
return 0, 0, nil, statelessResetToken{}, -1
}
connID, nn = quicwire.ConsumeVarintBytes(b[n:])
if nn < 0 {
return 0, 0, nil, statelessResetToken{}, -1
}
if len(connID) < 1 || len(connID) > 20 {
return 0, 0, nil, statelessResetToken{}, -1
}
n += nn
if len(b[n:]) < len(resetToken) {
return 0, 0, nil, statelessResetToken{}, -1
}
copy(resetToken[:], b[n:])
n += len(resetToken)
return seq, retire, connID, resetToken, n
}
func consumeRetireConnectionIDFrame(b []byte) (seq int64, n int) {
n = 1
var nn int
seq, nn = quicwire.ConsumeVarintInt64(b[n:])
if nn < 0 {
return 0, -1
}
n += nn
return seq, n
}
func consumePathChallengeFrame(b []byte) (data pathChallengeData, n int) {
n = 1
nn := copy(data[:], b[n:])
if nn != len(data) {
return data, -1
}
n += nn
return data, n
}
func consumePathResponseFrame(b []byte) (data pathChallengeData, n int) {
return consumePathChallengeFrame(b) // identical frame format
}
func consumeConnectionCloseTransportFrame(b []byte) (code transportError, frameType uint64, reason string, n int) {
n = 1
var nn int
var codeInt uint64
codeInt, nn = quicwire.ConsumeVarint(b[n:])
if nn < 0 {
return 0, 0, "", -1
}
code = transportError(codeInt)
n += nn
frameType, nn = quicwire.ConsumeVarint(b[n:])
if nn < 0 {
return 0, 0, "", -1
}
n += nn
reasonb, nn := quicwire.ConsumeVarintBytes(b[n:])
if nn < 0 {
return 0, 0, "", -1
}
n += nn
reason = string(reasonb)
return code, frameType, reason, n
}
func consumeConnectionCloseApplicationFrame(b []byte) (code uint64, reason string, n int) {
n = 1
var nn int
code, nn = quicwire.ConsumeVarint(b[n:])
if nn < 0 {
return 0, "", -1
}
n += nn
reasonb, nn := quicwire.ConsumeVarintBytes(b[n:])
if nn < 0 {
return 0, "", -1
}
n += nn
reason = string(reasonb)
return code, reason, n
}
// Copyright 2023 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 quic
import (
"crypto"
"crypto/aes"
"crypto/cipher"
"crypto/sha256"
"crypto/tls"
"errors"
"hash"
"golang.org/x/crypto/chacha20"
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/cryptobyte"
"golang.org/x/crypto/hkdf"
)
var errInvalidPacket = errors.New("quic: invalid packet")
// headerProtectionSampleSize is the size of the ciphertext sample used for header protection.
// https://www.rfc-editor.org/rfc/rfc9001#section-5.4.2
const headerProtectionSampleSize = 16
// aeadOverhead is the difference in size between the AEAD output and input.
// All cipher suites defined for use with QUIC have 16 bytes of overhead.
const aeadOverhead = 16
// A headerKey applies or removes header protection.
// https://www.rfc-editor.org/rfc/rfc9001#section-5.4
type headerKey struct {
hp headerProtection
}
func (k headerKey) isSet() bool {
return k.hp != nil
}
func (k *headerKey) init(suite uint16, secret []byte) {
h, keySize := hashForSuite(suite)
hpKey := hkdfExpandLabel(h.New, secret, "quic hp", nil, keySize)
switch suite {
case tls.TLS_AES_128_GCM_SHA256, tls.TLS_AES_256_GCM_SHA384:
c, err := aes.NewCipher(hpKey)
if err != nil {
panic(err)
}
k.hp = &aesHeaderProtection{cipher: c}
case tls.TLS_CHACHA20_POLY1305_SHA256:
k.hp = chaCha20HeaderProtection{hpKey}
default:
panic("BUG: unknown cipher suite")
}
}
// protect applies header protection.
// pnumOff is the offset of the packet number in the packet.
func (k headerKey) protect(hdr []byte, pnumOff int) {
// Apply header protection.
pnumSize := int(hdr[0]&0x03) + 1
sample := hdr[pnumOff+4:][:headerProtectionSampleSize]
mask := k.hp.headerProtection(sample)
if isLongHeader(hdr[0]) {
hdr[0] ^= mask[0] & 0x0f
} else {
hdr[0] ^= mask[0] & 0x1f
}
for i := 0; i < pnumSize; i++ {
hdr[pnumOff+i] ^= mask[1+i]
}
}
// unprotect removes header protection.
// pnumOff is the offset of the packet number in the packet.
// pnumMax is the largest packet number seen in the number space of this packet.
func (k headerKey) unprotect(pkt []byte, pnumOff int, pnumMax packetNumber) (hdr, pay []byte, pnum packetNumber, _ error) {
if len(pkt) < pnumOff+4+headerProtectionSampleSize {
return nil, nil, 0, errInvalidPacket
}
numpay := pkt[pnumOff:]
sample := numpay[4:][:headerProtectionSampleSize]
mask := k.hp.headerProtection(sample)
if isLongHeader(pkt[0]) {
pkt[0] ^= mask[0] & 0x0f
} else {
pkt[0] ^= mask[0] & 0x1f
}
pnumLen := int(pkt[0]&0x03) + 1
pnum = packetNumber(0)
for i := 0; i < pnumLen; i++ {
numpay[i] ^= mask[1+i]
pnum = (pnum << 8) | packetNumber(numpay[i])
}
pnum = decodePacketNumber(pnumMax, pnum, pnumLen)
hdr = pkt[:pnumOff+pnumLen]
pay = numpay[pnumLen:]
return hdr, pay, pnum, nil
}
// headerProtection is the header_protection function as defined in:
// https://www.rfc-editor.org/rfc/rfc9001#section-5.4.1
//
// This function takes a sample of the packet ciphertext
// and returns a 5-byte mask which will be applied to the
// protected portions of the packet header.
type headerProtection interface {
headerProtection(sample []byte) (mask [5]byte)
}
// AES-based header protection.
// https://www.rfc-editor.org/rfc/rfc9001#section-5.4.3
type aesHeaderProtection struct {
cipher cipher.Block
scratch [aes.BlockSize]byte
}
func (hp *aesHeaderProtection) headerProtection(sample []byte) (mask [5]byte) {
hp.cipher.Encrypt(hp.scratch[:], sample)
copy(mask[:], hp.scratch[:])
return mask
}
// ChaCha20-based header protection.
// https://www.rfc-editor.org/rfc/rfc9001#section-5.4.4
type chaCha20HeaderProtection struct {
key []byte
}
func (hp chaCha20HeaderProtection) headerProtection(sample []byte) (mask [5]byte) {
counter := uint32(sample[3])<<24 | uint32(sample[2])<<16 | uint32(sample[1])<<8 | uint32(sample[0])
nonce := sample[4:16]
c, err := chacha20.NewUnauthenticatedCipher(hp.key, nonce)
if err != nil {
panic(err)
}
c.SetCounter(counter)
c.XORKeyStream(mask[:], mask[:])
return mask
}
// A packetKey applies or removes packet protection.
// https://www.rfc-editor.org/rfc/rfc9001#section-5.1
type packetKey struct {
aead cipher.AEAD // AEAD function used for packet protection.
iv []byte // IV used to construct the AEAD nonce.
}
func (k *packetKey) init(suite uint16, secret []byte) {
// https://www.rfc-editor.org/rfc/rfc9001#section-5.1
h, keySize := hashForSuite(suite)
key := hkdfExpandLabel(h.New, secret, "quic key", nil, keySize)
switch suite {
case tls.TLS_AES_128_GCM_SHA256, tls.TLS_AES_256_GCM_SHA384:
k.aead = newAESAEAD(key)
case tls.TLS_CHACHA20_POLY1305_SHA256:
k.aead = newChaCha20AEAD(key)
default:
panic("BUG: unknown cipher suite")
}
k.iv = hkdfExpandLabel(h.New, secret, "quic iv", nil, k.aead.NonceSize())
}
func newAESAEAD(key []byte) cipher.AEAD {
c, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
aead, err := cipher.NewGCM(c)
if err != nil {
panic(err)
}
return aead
}
func newChaCha20AEAD(key []byte) cipher.AEAD {
var err error
aead, err := chacha20poly1305.New(key)
if err != nil {
panic(err)
}
return aead
}
func (k packetKey) protect(hdr, pay []byte, pnum packetNumber) []byte {
k.xorIV(pnum)
defer k.xorIV(pnum)
return k.aead.Seal(hdr, k.iv, pay, hdr)
}
func (k packetKey) unprotect(hdr, pay []byte, pnum packetNumber) (dec []byte, err error) {
k.xorIV(pnum)
defer k.xorIV(pnum)
return k.aead.Open(pay[:0], k.iv, pay, hdr)
}
// xorIV xors the packet protection IV with the packet number.
func (k packetKey) xorIV(pnum packetNumber) {
k.iv[len(k.iv)-8] ^= uint8(pnum >> 56)
k.iv[len(k.iv)-7] ^= uint8(pnum >> 48)
k.iv[len(k.iv)-6] ^= uint8(pnum >> 40)
k.iv[len(k.iv)-5] ^= uint8(pnum >> 32)
k.iv[len(k.iv)-4] ^= uint8(pnum >> 24)
k.iv[len(k.iv)-3] ^= uint8(pnum >> 16)
k.iv[len(k.iv)-2] ^= uint8(pnum >> 8)
k.iv[len(k.iv)-1] ^= uint8(pnum)
}
// A fixedKeys is a header protection key and fixed packet protection key.
// The packet protection key is fixed (it does not update).
//
// Fixed keys are used for Initial and Handshake keys, which do not update.
type fixedKeys struct {
hdr headerKey
pkt packetKey
}
func (k *fixedKeys) init(suite uint16, secret []byte) {
k.hdr.init(suite, secret)
k.pkt.init(suite, secret)
}
func (k fixedKeys) isSet() bool {
return k.hdr.hp != nil
}
// protect applies packet protection to a packet.
//
// On input, hdr contains the packet header, pay the unencrypted payload,
// pnumOff the offset of the packet number in the header, and pnum the untruncated
// packet number.
//
// protect returns the result of appending the encrypted payload to hdr and
// applying header protection.
func (k fixedKeys) protect(hdr, pay []byte, pnumOff int, pnum packetNumber) []byte {
pkt := k.pkt.protect(hdr, pay, pnum)
k.hdr.protect(pkt, pnumOff)
return pkt
}
// unprotect removes packet protection from a packet.
//
// On input, pkt contains the full protected packet, pnumOff the offset of
// the packet number in the header, and pnumMax the largest packet number
// seen in the number space of this packet.
//
// unprotect removes header protection from the header in pkt, and returns
// the unprotected payload and packet number.
func (k fixedKeys) unprotect(pkt []byte, pnumOff int, pnumMax packetNumber) (pay []byte, num packetNumber, err error) {
hdr, pay, pnum, err := k.hdr.unprotect(pkt, pnumOff, pnumMax)
if err != nil {
return nil, 0, err
}
pay, err = k.pkt.unprotect(hdr, pay, pnum)
if err != nil {
return nil, 0, err
}
return pay, pnum, nil
}
// A fixedKeyPair is a read/write pair of fixed keys.
type fixedKeyPair struct {
r, w fixedKeys
}
func (k *fixedKeyPair) discard() {
*k = fixedKeyPair{}
}
func (k *fixedKeyPair) canRead() bool {
return k.r.isSet()
}
func (k *fixedKeyPair) canWrite() bool {
return k.w.isSet()
}
// An updatingKeys is a header protection key and updatable packet protection key.
// updatingKeys are used for 1-RTT keys, where the packet protection key changes
// over the lifetime of a connection.
// https://www.rfc-editor.org/rfc/rfc9001#section-6
type updatingKeys struct {
suite uint16
hdr headerKey
pkt [2]packetKey // current, next
nextSecret []byte // secret used to generate pkt[1]
}
func (k *updatingKeys) init(suite uint16, secret []byte) {
k.suite = suite
k.hdr.init(suite, secret)
// Initialize pkt[1] with secret_0, and then call update to generate secret_1.
k.pkt[1].init(suite, secret)
k.nextSecret = secret
k.update()
}
// update performs a key update.
// The current key in pkt[0] is discarded.
// The next key in pkt[1] becomes the current key.
// A new next key is generated in pkt[1].
func (k *updatingKeys) update() {
k.nextSecret = updateSecret(k.suite, k.nextSecret)
k.pkt[0] = k.pkt[1]
k.pkt[1].init(k.suite, k.nextSecret)
}
func updateSecret(suite uint16, secret []byte) (nextSecret []byte) {
h, _ := hashForSuite(suite)
return hkdfExpandLabel(h.New, secret, "quic ku", nil, len(secret))
}
// An updatingKeyPair is a read/write pair of updating keys.
//
// We keep two keys (current and next) in both read and write directions.
// When an incoming packet's phase matches the current phase bit,
// we unprotect it using the current keys; otherwise we use the next keys.
//
// When updating=false, outgoing packets are protected using the current phase.
//
// An update is initiated and updating is set to true when:
// - we decide to initiate a key update; or
// - we successfully unprotect a packet using the next keys,
// indicating the peer has initiated a key update.
//
// When updating=true, outgoing packets are protected using the next phase.
// We do not change the current phase bit or generate new keys yet.
//
// The update concludes when we receive an ACK frame for a packet sent
// with the next keys. At this time, we set updating to false, flip the
// phase bit, and update the keys. This permits us to handle up to 1-RTT
// of reordered packets before discarding the previous phase's keys after
// an update.
type updatingKeyPair struct {
phase uint8 // current key phase (r.pkt[0], w.pkt[0])
updating bool
authFailures int64 // total packet unprotect failures
minSent packetNumber // min packet number sent since entering the updating state
minReceived packetNumber // min packet number received in the next phase
updateAfter packetNumber // packet number after which to initiate key update
r, w updatingKeys
}
func (k *updatingKeyPair) init() {
// 1-RTT packets until the first key update.
//
// We perform the first key update early in the connection so a peer
// which does not support key updates will fail rapidly,
// rather than after the connection has been long established.
//
// The QUIC interop runner "keyupdate" test requires that the client
// initiate a key rotation early in the connection. Increasing this
// value may cause interop test failures; if we do want to increase it,
// we should either skip the keyupdate test or provide a way to override
// the setting in interop tests.
k.updateAfter = 100
}
func (k *updatingKeyPair) canRead() bool {
return k.r.hdr.hp != nil
}
func (k *updatingKeyPair) canWrite() bool {
return k.w.hdr.hp != nil
}
// handleAckFor finishes a key update after receiving an ACK for a packet in the next phase.
func (k *updatingKeyPair) handleAckFor(pnum packetNumber) {
if k.updating && pnum >= k.minSent {
k.updating = false
k.phase ^= keyPhaseBit
k.r.update()
k.w.update()
}
}
// needAckEliciting reports whether we should send an ack-eliciting packet in the next phase.
// The first packet sent in a phase is ack-eliciting, since the peer must acknowledge a
// packet in the new phase for us to finish the update.
func (k *updatingKeyPair) needAckEliciting() bool {
return k.updating && k.minSent == maxPacketNumber
}
// protect applies packet protection to a packet.
// Parameters and returns are as for fixedKeyPair.protect.
func (k *updatingKeyPair) protect(hdr, pay []byte, pnumOff int, pnum packetNumber) []byte {
var pkt []byte
if k.updating {
hdr[0] |= k.phase ^ keyPhaseBit
pkt = k.w.pkt[1].protect(hdr, pay, pnum)
k.minSent = min(pnum, k.minSent)
} else {
hdr[0] |= k.phase
pkt = k.w.pkt[0].protect(hdr, pay, pnum)
if pnum >= k.updateAfter {
// Initiate a key update, starting with the next packet we send.
//
// We do this after protecting the current packet
// to allow Conn.appendFrames to ensure that the first packet sent
// in the new phase is ack-eliciting.
k.updating = true
k.minSent = maxPacketNumber
k.minReceived = maxPacketNumber
// The lowest confidentiality limit for a supported AEAD is 2^23 packets.
// https://www.rfc-editor.org/rfc/rfc9001#section-6.6-5
//
// Schedule our next update for half that.
k.updateAfter += (1 << 22)
}
}
k.w.hdr.protect(pkt, pnumOff)
return pkt
}
// unprotect removes packet protection from a packet.
// Parameters and returns are as for fixedKeyPair.unprotect.
func (k *updatingKeyPair) unprotect(pkt []byte, pnumOff int, pnumMax packetNumber) (pay []byte, pnum packetNumber, err error) {
hdr, pay, pnum, err := k.r.hdr.unprotect(pkt, pnumOff, pnumMax)
if err != nil {
return nil, 0, err
}
// To avoid timing signals that might indicate the key phase bit is invalid,
// we always attempt to unprotect the packet with one key.
//
// If the key phase bit matches and the packet number doesn't come after
// the start of an in-progress update, use the current phase.
// Otherwise, use the next phase.
if hdr[0]&keyPhaseBit == k.phase && (!k.updating || pnum < k.minReceived) {
pay, err = k.r.pkt[0].unprotect(hdr, pay, pnum)
} else {
pay, err = k.r.pkt[1].unprotect(hdr, pay, pnum)
if err == nil {
if !k.updating {
// The peer has initiated a key update.
k.updating = true
k.minSent = maxPacketNumber
k.minReceived = pnum
} else {
k.minReceived = min(pnum, k.minReceived)
}
}
}
if err != nil {
k.authFailures++
if k.authFailures >= aeadIntegrityLimit(k.r.suite) {
return nil, 0, localTransportError{code: errAEADLimitReached}
}
return nil, 0, err
}
return pay, pnum, nil
}
// aeadIntegrityLimit returns the integrity limit for an AEAD:
// The maximum number of received packets that may fail authentication
// before closing the connection.
//
// https://www.rfc-editor.org/rfc/rfc9001#section-6.6-4
func aeadIntegrityLimit(suite uint16) int64 {
switch suite {
case tls.TLS_AES_128_GCM_SHA256, tls.TLS_AES_256_GCM_SHA384:
return 1 << 52
case tls.TLS_CHACHA20_POLY1305_SHA256:
return 1 << 36
default:
panic("BUG: unknown cipher suite")
}
}
// https://www.rfc-editor.org/rfc/rfc9001#section-5.2-2
var initialSalt = []byte{0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a}
// initialKeys returns the keys used to protect Initial packets.
//
// The Initial packet keys are derived from the Destination Connection ID
// field in the client's first Initial packet.
//
// https://www.rfc-editor.org/rfc/rfc9001#section-5.2
func initialKeys(cid []byte, side connSide) fixedKeyPair {
initialSecret := hkdf.Extract(sha256.New, cid, initialSalt)
var clientKeys fixedKeys
clientSecret := hkdfExpandLabel(sha256.New, initialSecret, "client in", nil, sha256.Size)
clientKeys.init(tls.TLS_AES_128_GCM_SHA256, clientSecret)
var serverKeys fixedKeys
serverSecret := hkdfExpandLabel(sha256.New, initialSecret, "server in", nil, sha256.Size)
serverKeys.init(tls.TLS_AES_128_GCM_SHA256, serverSecret)
if side == clientSide {
return fixedKeyPair{r: serverKeys, w: clientKeys}
} else {
return fixedKeyPair{w: serverKeys, r: clientKeys}
}
}
// checkCipherSuite returns an error if suite is not a supported cipher suite.
func checkCipherSuite(suite uint16) error {
switch suite {
case tls.TLS_AES_128_GCM_SHA256:
case tls.TLS_AES_256_GCM_SHA384:
case tls.TLS_CHACHA20_POLY1305_SHA256:
default:
return errors.New("invalid cipher suite")
}
return nil
}
func hashForSuite(suite uint16) (h crypto.Hash, keySize int) {
switch suite {
case tls.TLS_AES_128_GCM_SHA256:
return crypto.SHA256, 128 / 8
case tls.TLS_AES_256_GCM_SHA384:
return crypto.SHA384, 256 / 8
case tls.TLS_CHACHA20_POLY1305_SHA256:
return crypto.SHA256, chacha20.KeySize
default:
panic("BUG: unknown cipher suite")
}
}
// hkdfExpandLabel implements HKDF-Expand-Label from RFC 8446, Section 7.1.
//
// Copied from crypto/tls/key_schedule.go.
func hkdfExpandLabel(hash func() hash.Hash, secret []byte, label string, context []byte, length int) []byte {
var hkdfLabel cryptobyte.Builder
hkdfLabel.AddUint16(uint16(length))
hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
b.AddBytes([]byte("tls13 "))
b.AddBytes([]byte(label))
})
hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
b.AddBytes(context)
})
out := make([]byte, length)
n, err := hkdf.Expand(hash, secret, hkdfLabel.BytesOrPanic()).Read(out)
if err != nil || n != length {
panic("quic: HKDF-Expand-Label invocation failed unexpectedly")
}
return out
}
// Copyright 2023 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 quic
import (
"encoding/binary"
"golang.org/x/net/internal/quic/quicwire"
)
// A packetWriter constructs QUIC datagrams.
//
// A datagram consists of one or more packets.
// A packet consists of a header followed by one or more frames.
//
// Packets are written in three steps:
// - startProtectedLongHeaderPacket or start1RTT packet prepare the packet;
// - append*Frame appends frames to the payload; and
// - finishProtectedLongHeaderPacket or finish1RTT finalize the packet.
//
// The start functions are efficient, so we can start speculatively
// writing a packet before we know whether we have any frames to
// put in it. The finish functions will abandon the packet if the
// payload contains no data.
type packetWriter struct {
dgramLim int // max datagram size
pktLim int // max packet size
pktOff int // offset of the start of the current packet
payOff int // offset of the payload of the current packet
b []byte
sent *sentPacket
}
// reset prepares to write a datagram of at most lim bytes.
func (w *packetWriter) reset(lim int) {
if cap(w.b) < lim {
w.b = make([]byte, 0, lim)
}
w.dgramLim = lim
w.b = w.b[:0]
}
// datagram returns the current datagram.
func (w *packetWriter) datagram() []byte {
return w.b
}
// packetLen returns the size of the current packet.
func (w *packetWriter) packetLen() int {
return len(w.b[w.pktOff:]) + aeadOverhead
}
// payload returns the payload of the current packet.
func (w *packetWriter) payload() []byte {
return w.b[w.payOff:]
}
func (w *packetWriter) abandonPacket() {
w.b = w.b[:w.payOff]
w.sent.reset()
}
// startProtectedLongHeaderPacket starts writing an Initial, 0-RTT, or Handshake packet.
func (w *packetWriter) startProtectedLongHeaderPacket(pnumMaxAcked packetNumber, p longPacket) {
if w.sent == nil {
w.sent = newSentPacket()
}
w.pktOff = len(w.b)
hdrSize := 1 // packet type
hdrSize += 4 // version
hdrSize += 1 + len(p.dstConnID)
hdrSize += 1 + len(p.srcConnID)
switch p.ptype {
case packetTypeInitial:
hdrSize += quicwire.SizeVarint(uint64(len(p.extra))) + len(p.extra)
}
hdrSize += 2 // length, hardcoded to a 2-byte varint
pnumOff := len(w.b) + hdrSize
hdrSize += packetNumberLength(p.num, pnumMaxAcked)
payOff := len(w.b) + hdrSize
// Check if we have enough space to hold the packet, including the header,
// header protection sample (RFC 9001, section 5.4.2), and encryption overhead.
if pnumOff+4+headerProtectionSampleSize+aeadOverhead >= w.dgramLim {
// Set the limit on the packet size to be the current write buffer length,
// ensuring that any writes to the payload fail.
w.payOff = len(w.b)
w.pktLim = len(w.b)
return
}
w.payOff = payOff
w.pktLim = w.dgramLim - aeadOverhead
// We hardcode the payload length field to be 2 bytes, which limits the payload
// (including the packet number) to 16383 bytes (the largest 2-byte QUIC varint).
//
// Most networks don't support datagrams over 1472 bytes, and even Ethernet
// jumbo frames are generally only about 9000 bytes.
if lim := pnumOff + 16383 - aeadOverhead; lim < w.pktLim {
w.pktLim = lim
}
w.b = w.b[:payOff]
}
// finishProtectedLongHeaderPacket finishes writing an Initial, 0-RTT, or Handshake packet,
// canceling the packet if it contains no payload.
// It returns a sentPacket describing the packet, or nil if no packet was written.
func (w *packetWriter) finishProtectedLongHeaderPacket(pnumMaxAcked packetNumber, k fixedKeys, p longPacket) *sentPacket {
if len(w.b) == w.payOff {
// The payload is empty, so just abandon the packet.
w.b = w.b[:w.pktOff]
return nil
}
pnumLen := packetNumberLength(p.num, pnumMaxAcked)
plen := w.padPacketLength(pnumLen)
hdr := w.b[:w.pktOff]
var typeBits byte
switch p.ptype {
case packetTypeInitial:
typeBits = longPacketTypeInitial
case packetType0RTT:
typeBits = longPacketType0RTT
case packetTypeHandshake:
typeBits = longPacketTypeHandshake
case packetTypeRetry:
typeBits = longPacketTypeRetry
}
hdr = append(hdr, headerFormLong|fixedBit|typeBits|byte(pnumLen-1))
hdr = binary.BigEndian.AppendUint32(hdr, p.version)
hdr = quicwire.AppendUint8Bytes(hdr, p.dstConnID)
hdr = quicwire.AppendUint8Bytes(hdr, p.srcConnID)
switch p.ptype {
case packetTypeInitial:
hdr = quicwire.AppendVarintBytes(hdr, p.extra) // token
}
// Packet length, always encoded as a 2-byte varint.
hdr = append(hdr, 0x40|byte(plen>>8), byte(plen))
pnumOff := len(hdr)
hdr = appendPacketNumber(hdr, p.num, pnumMaxAcked)
k.protect(hdr[w.pktOff:], w.b[len(hdr):], pnumOff-w.pktOff, p.num)
return w.finish(p.ptype, p.num)
}
// start1RTTPacket starts writing a 1-RTT (short header) packet.
func (w *packetWriter) start1RTTPacket(pnum, pnumMaxAcked packetNumber, dstConnID []byte) {
if w.sent == nil {
w.sent = newSentPacket()
}
w.pktOff = len(w.b)
hdrSize := 1 // packet type
hdrSize += len(dstConnID)
// Ensure we have enough space to hold the packet, including the header,
// header protection sample (RFC 9001, section 5.4.2), and encryption overhead.
if len(w.b)+hdrSize+4+headerProtectionSampleSize+aeadOverhead >= w.dgramLim {
w.payOff = len(w.b)
w.pktLim = len(w.b)
return
}
hdrSize += packetNumberLength(pnum, pnumMaxAcked)
w.payOff = len(w.b) + hdrSize
w.pktLim = w.dgramLim - aeadOverhead
w.b = w.b[:w.payOff]
}
// finish1RTTPacket finishes writing a 1-RTT packet,
// canceling the packet if it contains no payload.
// It returns a sentPacket describing the packet, or nil if no packet was written.
func (w *packetWriter) finish1RTTPacket(pnum, pnumMaxAcked packetNumber, dstConnID []byte, k *updatingKeyPair) *sentPacket {
if len(w.b) == w.payOff {
// The payload is empty, so just abandon the packet.
w.b = w.b[:w.pktOff]
return nil
}
// TODO: Spin
pnumLen := packetNumberLength(pnum, pnumMaxAcked)
hdr := w.b[:w.pktOff]
hdr = append(hdr, 0x40|byte(pnumLen-1))
hdr = append(hdr, dstConnID...)
pnumOff := len(hdr)
hdr = appendPacketNumber(hdr, pnum, pnumMaxAcked)
w.padPacketLength(pnumLen)
k.protect(hdr[w.pktOff:], w.b[len(hdr):], pnumOff-w.pktOff, pnum)
return w.finish(packetType1RTT, pnum)
}
// padPacketLength pads out the payload of the current packet to the minimum size,
// and returns the combined length of the packet number and payload (used for the Length
// field of long header packets).
func (w *packetWriter) padPacketLength(pnumLen int) int {
plen := len(w.b) - w.payOff + pnumLen + aeadOverhead
// "To ensure that sufficient data is available for sampling, packets are
// padded so that the combined lengths of the encoded packet number and
// protected payload is at least 4 bytes longer than the sample required
// for header protection."
// https://www.rfc-editor.org/rfc/rfc9001.html#section-5.4.2
for plen < 4+headerProtectionSampleSize {
w.b = append(w.b, 0)
plen++
}
return plen
}
// finish finishes the current packet after protection is applied.
func (w *packetWriter) finish(ptype packetType, pnum packetNumber) *sentPacket {
w.b = w.b[:len(w.b)+aeadOverhead]
w.sent.size = len(w.b) - w.pktOff
w.sent.ptype = ptype
w.sent.num = pnum
sent := w.sent
w.sent = nil
return sent
}
// avail reports how many more bytes may be written to the current packet.
func (w *packetWriter) avail() int {
return w.pktLim - len(w.b)
}
// appendPaddingTo appends PADDING frames until the total datagram size
// (including AEAD overhead of the current packet) is n.
func (w *packetWriter) appendPaddingTo(n int) {
n -= aeadOverhead
lim := w.pktLim
if n < lim {
lim = n
}
if len(w.b) >= lim {
return
}
for len(w.b) < lim {
w.b = append(w.b, frameTypePadding)
}
// Packets are considered in flight when they contain a PADDING frame.
// https://www.rfc-editor.org/rfc/rfc9002.html#section-2-3.6.1
w.sent.inFlight = true
}
func (w *packetWriter) appendPingFrame() (added bool) {
if len(w.b) >= w.pktLim {
return false
}
w.b = append(w.b, frameTypePing)
w.sent.markAckEliciting() // no need to record the frame itself
return true
}
// appendAckFrame appends an ACK frame to the payload.
// It includes at least the most recent range in the rangeset
// (the range with the largest packet numbers),
// followed by as many additional ranges as fit within the packet.
//
// We always place ACK frames at the start of packets,
// we limit the number of ack ranges retained, and
// we set a minimum packet payload size.
// As a result, appendAckFrame will rarely if ever drop ranges
// in practice.
//
// In the event that ranges are dropped, the impact is limited
// to the peer potentially failing to receive an acknowledgement
// for an older packet during a period of high packet loss or
// reordering. This may result in unnecessary retransmissions.
func (w *packetWriter) appendAckFrame(seen rangeset[packetNumber], delay unscaledAckDelay, ecn ecnCounts) (added bool) {
if len(seen) == 0 {
return false
}
var (
largest = uint64(seen.max())
firstRange = uint64(seen[len(seen)-1].size() - 1)
)
var ecnLen int
ackType := byte(frameTypeAck)
if (ecn != ecnCounts{}) {
// "Even if an endpoint does not set an ECT field in packets it sends,
// the endpoint MUST provide feedback about ECN markings it receives, if
// these are accessible."
// https://www.rfc-editor.org/rfc/rfc9000.html#section-13.4.1-2
ecnLen = quicwire.SizeVarint(uint64(ecn.ce)) + quicwire.SizeVarint(uint64(ecn.t0)) + quicwire.SizeVarint(uint64(ecn.t1))
ackType = frameTypeAckECN
}
if w.avail() < 1+quicwire.SizeVarint(largest)+quicwire.SizeVarint(uint64(delay))+1+quicwire.SizeVarint(firstRange)+ecnLen {
return false
}
w.b = append(w.b, ackType)
w.b = quicwire.AppendVarint(w.b, largest)
w.b = quicwire.AppendVarint(w.b, uint64(delay))
// The range count is technically a varint, but we'll reserve a single byte for it
// and never add more than 62 ranges (the maximum varint that fits in a byte).
rangeCountOff := len(w.b)
w.b = append(w.b, 0)
w.b = quicwire.AppendVarint(w.b, firstRange)
rangeCount := byte(0)
for i := len(seen) - 2; i >= 0; i-- {
gap := uint64(seen[i+1].start - seen[i].end - 1)
size := uint64(seen[i].size() - 1)
if w.avail() < quicwire.SizeVarint(gap)+quicwire.SizeVarint(size)+ecnLen || rangeCount > 62 {
break
}
w.b = quicwire.AppendVarint(w.b, gap)
w.b = quicwire.AppendVarint(w.b, size)
rangeCount++
}
w.b[rangeCountOff] = rangeCount
if ackType == frameTypeAckECN {
w.b = quicwire.AppendVarint(w.b, uint64(ecn.t0))
w.b = quicwire.AppendVarint(w.b, uint64(ecn.t1))
w.b = quicwire.AppendVarint(w.b, uint64(ecn.ce))
}
w.sent.appendNonAckElicitingFrame(ackType)
w.sent.appendInt(uint64(seen.max()))
return true
}
func (w *packetWriter) appendNewTokenFrame(token []byte) (added bool) {
if w.avail() < 1+quicwire.SizeVarint(uint64(len(token)))+len(token) {
return false
}
w.b = append(w.b, frameTypeNewToken)
w.b = quicwire.AppendVarintBytes(w.b, token)
return true
}
func (w *packetWriter) appendResetStreamFrame(id streamID, code uint64, finalSize int64) (added bool) {
if w.avail() < 1+quicwire.SizeVarint(uint64(id))+quicwire.SizeVarint(code)+quicwire.SizeVarint(uint64(finalSize)) {
return false
}
w.b = append(w.b, frameTypeResetStream)
w.b = quicwire.AppendVarint(w.b, uint64(id))
w.b = quicwire.AppendVarint(w.b, code)
w.b = quicwire.AppendVarint(w.b, uint64(finalSize))
w.sent.appendAckElicitingFrame(frameTypeResetStream)
w.sent.appendInt(uint64(id))
return true
}
func (w *packetWriter) appendStopSendingFrame(id streamID, code uint64) (added bool) {
if w.avail() < 1+quicwire.SizeVarint(uint64(id))+quicwire.SizeVarint(code) {
return false
}
w.b = append(w.b, frameTypeStopSending)
w.b = quicwire.AppendVarint(w.b, uint64(id))
w.b = quicwire.AppendVarint(w.b, code)
w.sent.appendAckElicitingFrame(frameTypeStopSending)
w.sent.appendInt(uint64(id))
return true
}
// appendCryptoFrame appends a CRYPTO frame.
// It returns a []byte into which the data should be written and whether a frame was added.
// The returned []byte may be smaller than size if the packet cannot hold all the data.
func (w *packetWriter) appendCryptoFrame(off int64, size int) (_ []byte, added bool) {
max := w.avail()
max -= 1 // frame type
max -= quicwire.SizeVarint(uint64(off)) // offset
max -= quicwire.SizeVarint(uint64(size)) // maximum length
if max <= 0 {
return nil, false
}
if max < size {
size = max
}
w.b = append(w.b, frameTypeCrypto)
w.b = quicwire.AppendVarint(w.b, uint64(off))
w.b = quicwire.AppendVarint(w.b, uint64(size))
start := len(w.b)
w.b = w.b[:start+size]
w.sent.appendAckElicitingFrame(frameTypeCrypto)
w.sent.appendOffAndSize(off, size)
return w.b[start:][:size], true
}
// appendStreamFrame appends a STREAM frame.
// It returns a []byte into which the data should be written and whether a frame was added.
// The returned []byte may be smaller than size if the packet cannot hold all the data.
func (w *packetWriter) appendStreamFrame(id streamID, off int64, size int, fin bool) (_ []byte, added bool) {
typ := uint8(frameTypeStreamBase | streamLenBit)
max := w.avail()
max -= 1 // frame type
max -= quicwire.SizeVarint(uint64(id))
if off != 0 {
max -= quicwire.SizeVarint(uint64(off))
typ |= streamOffBit
}
max -= quicwire.SizeVarint(uint64(size)) // maximum length
if max < 0 || (max == 0 && size > 0) {
return nil, false
}
if max < size {
size = max
} else if fin {
typ |= streamFinBit
}
w.b = append(w.b, typ)
w.b = quicwire.AppendVarint(w.b, uint64(id))
if off != 0 {
w.b = quicwire.AppendVarint(w.b, uint64(off))
}
w.b = quicwire.AppendVarint(w.b, uint64(size))
start := len(w.b)
w.b = w.b[:start+size]
w.sent.appendAckElicitingFrame(typ & (frameTypeStreamBase | streamFinBit))
w.sent.appendInt(uint64(id))
w.sent.appendOffAndSize(off, size)
return w.b[start:][:size], true
}
func (w *packetWriter) appendMaxDataFrame(max int64) (added bool) {
if w.avail() < 1+quicwire.SizeVarint(uint64(max)) {
return false
}
w.b = append(w.b, frameTypeMaxData)
w.b = quicwire.AppendVarint(w.b, uint64(max))
w.sent.appendAckElicitingFrame(frameTypeMaxData)
return true
}
func (w *packetWriter) appendMaxStreamDataFrame(id streamID, max int64) (added bool) {
if w.avail() < 1+quicwire.SizeVarint(uint64(id))+quicwire.SizeVarint(uint64(max)) {
return false
}
w.b = append(w.b, frameTypeMaxStreamData)
w.b = quicwire.AppendVarint(w.b, uint64(id))
w.b = quicwire.AppendVarint(w.b, uint64(max))
w.sent.appendAckElicitingFrame(frameTypeMaxStreamData)
w.sent.appendInt(uint64(id))
return true
}
func (w *packetWriter) appendMaxStreamsFrame(streamType streamType, max int64) (added bool) {
if w.avail() < 1+quicwire.SizeVarint(uint64(max)) {
return false
}
var typ byte
if streamType == bidiStream {
typ = frameTypeMaxStreamsBidi
} else {
typ = frameTypeMaxStreamsUni
}
w.b = append(w.b, typ)
w.b = quicwire.AppendVarint(w.b, uint64(max))
w.sent.appendAckElicitingFrame(typ)
return true
}
func (w *packetWriter) appendDataBlockedFrame(max int64) (added bool) {
if w.avail() < 1+quicwire.SizeVarint(uint64(max)) {
return false
}
w.b = append(w.b, frameTypeDataBlocked)
w.b = quicwire.AppendVarint(w.b, uint64(max))
w.sent.appendAckElicitingFrame(frameTypeDataBlocked)
return true
}
func (w *packetWriter) appendStreamDataBlockedFrame(id streamID, max int64) (added bool) {
if w.avail() < 1+quicwire.SizeVarint(uint64(id))+quicwire.SizeVarint(uint64(max)) {
return false
}
w.b = append(w.b, frameTypeStreamDataBlocked)
w.b = quicwire.AppendVarint(w.b, uint64(id))
w.b = quicwire.AppendVarint(w.b, uint64(max))
w.sent.appendAckElicitingFrame(frameTypeStreamDataBlocked)
w.sent.appendInt(uint64(id))
return true
}
func (w *packetWriter) appendStreamsBlockedFrame(typ streamType, max int64) (added bool) {
if w.avail() < 1+quicwire.SizeVarint(uint64(max)) {
return false
}
var ftype byte
if typ == bidiStream {
ftype = frameTypeStreamsBlockedBidi
} else {
ftype = frameTypeStreamsBlockedUni
}
w.b = append(w.b, ftype)
w.b = quicwire.AppendVarint(w.b, uint64(max))
w.sent.appendAckElicitingFrame(ftype)
return true
}
func (w *packetWriter) appendNewConnectionIDFrame(seq, retirePriorTo int64, connID []byte, token [16]byte) (added bool) {
if w.avail() < 1+quicwire.SizeVarint(uint64(seq))+quicwire.SizeVarint(uint64(retirePriorTo))+1+len(connID)+len(token) {
return false
}
w.b = append(w.b, frameTypeNewConnectionID)
w.b = quicwire.AppendVarint(w.b, uint64(seq))
w.b = quicwire.AppendVarint(w.b, uint64(retirePriorTo))
w.b = quicwire.AppendUint8Bytes(w.b, connID)
w.b = append(w.b, token[:]...)
w.sent.appendAckElicitingFrame(frameTypeNewConnectionID)
w.sent.appendInt(uint64(seq))
return true
}
func (w *packetWriter) appendRetireConnectionIDFrame(seq int64) (added bool) {
if w.avail() < 1+quicwire.SizeVarint(uint64(seq)) {
return false
}
w.b = append(w.b, frameTypeRetireConnectionID)
w.b = quicwire.AppendVarint(w.b, uint64(seq))
w.sent.appendAckElicitingFrame(frameTypeRetireConnectionID)
w.sent.appendInt(uint64(seq))
return true
}
func (w *packetWriter) appendPathChallengeFrame(data pathChallengeData) (added bool) {
if w.avail() < 1+8 {
return false
}
w.b = append(w.b, frameTypePathChallenge)
w.b = append(w.b, data[:]...)
w.sent.markAckEliciting() // no need to record the frame itself
return true
}
func (w *packetWriter) appendPathResponseFrame(data pathChallengeData) (added bool) {
if w.avail() < 1+8 {
return false
}
w.b = append(w.b, frameTypePathResponse)
w.b = append(w.b, data[:]...)
w.sent.markAckEliciting() // no need to record the frame itself
return true
}
// appendConnectionCloseTransportFrame appends a CONNECTION_CLOSE frame
// carrying a transport error code.
func (w *packetWriter) appendConnectionCloseTransportFrame(code transportError, frameType uint64, reason string) (added bool) {
if w.avail() < 1+quicwire.SizeVarint(uint64(code))+quicwire.SizeVarint(frameType)+quicwire.SizeVarint(uint64(len(reason)))+len(reason) {
return false
}
w.b = append(w.b, frameTypeConnectionCloseTransport)
w.b = quicwire.AppendVarint(w.b, uint64(code))
w.b = quicwire.AppendVarint(w.b, frameType)
w.b = quicwire.AppendVarintBytes(w.b, []byte(reason))
// We don't record CONNECTION_CLOSE frames in w.sent, since they are never acked or
// detected as lost.
return true
}
// appendConnectionCloseApplicationFrame appends a CONNECTION_CLOSE frame
// carrying an application protocol error code.
func (w *packetWriter) appendConnectionCloseApplicationFrame(code uint64, reason string) (added bool) {
if w.avail() < 1+quicwire.SizeVarint(code)+quicwire.SizeVarint(uint64(len(reason)))+len(reason) {
return false
}
w.b = append(w.b, frameTypeConnectionCloseApplication)
w.b = quicwire.AppendVarint(w.b, code)
w.b = quicwire.AppendVarintBytes(w.b, []byte(reason))
// We don't record CONNECTION_CLOSE frames in w.sent, since they are never acked or
// detected as lost.
return true
}
func (w *packetWriter) appendHandshakeDoneFrame() (added bool) {
if w.avail() < 1 {
return false
}
w.b = append(w.b, frameTypeHandshakeDone)
w.sent.appendAckElicitingFrame(frameTypeHandshakeDone)
return true
}
// Copyright 2024 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 quic
import "time"
type pathState struct {
// Response to a peer's PATH_CHALLENGE.
// This is not a sentVal, because we don't resend lost PATH_RESPONSE frames.
// We only track the most recent PATH_CHALLENGE.
// If the peer sends a second PATH_CHALLENGE before we respond to the first,
// we'll drop the first response.
sendPathResponse pathResponseType
data pathChallengeData
}
// pathChallengeData is data carried in a PATH_CHALLENGE or PATH_RESPONSE frame.
type pathChallengeData [64 / 8]byte
type pathResponseType uint8
const (
pathResponseNotNeeded = pathResponseType(iota)
pathResponseSmall // send PATH_RESPONSE, do not expand datagram
pathResponseExpanded // send PATH_RESPONSE, expand datagram to 1200 bytes
)
func (c *Conn) handlePathChallenge(_ time.Time, dgram *datagram, data pathChallengeData) {
// A PATH_RESPONSE is sent in a datagram expanded to 1200 bytes,
// except when this would exceed the anti-amplification limit.
//
// Rather than maintaining anti-amplification state for each path
// we may be sending a PATH_RESPONSE on, follow the following heuristic:
//
// If we receive a PATH_CHALLENGE in an expanded datagram,
// respond with an expanded datagram.
//
// If we receive a PATH_CHALLENGE in a non-expanded datagram,
// then the peer is presumably blocked by its own anti-amplification limit.
// Respond with a non-expanded datagram. Receiving this PATH_RESPONSE
// will validate the path to the peer, remove its anti-amplification limit,
// and permit it to send a followup PATH_CHALLENGE in an expanded datagram.
// https://www.rfc-editor.org/rfc/rfc9000.html#section-8.2.1
if len(dgram.b) >= smallestMaxDatagramSize {
c.path.sendPathResponse = pathResponseExpanded
} else {
c.path.sendPathResponse = pathResponseSmall
}
c.path.data = data
}
func (c *Conn) handlePathResponse(now time.Time, _ pathChallengeData) {
// "If the content of a PATH_RESPONSE frame does not match the content of
// a PATH_CHALLENGE frame previously sent by the endpoint,
// the endpoint MAY generate a connection error of type PROTOCOL_VIOLATION."
// https://www.rfc-editor.org/rfc/rfc9000.html#section-19.18-4
//
// We never send PATH_CHALLENGE frames.
c.abort(now, localTransportError{
code: errProtocolViolation,
reason: "PATH_RESPONSE received when no PATH_CHALLENGE sent",
})
}
// appendPathFrames appends path validation related frames to the current packet.
// If the return value pad is true, then the packet should be padded to 1200 bytes.
func (c *Conn) appendPathFrames() (pad, ok bool) {
if c.path.sendPathResponse == pathResponseNotNeeded {
return pad, true
}
// We're required to send the PATH_RESPONSE on the path where the
// PATH_CHALLENGE was received (RFC 9000, Section 8.2.2).
//
// At the moment, we don't support path migration and reject packets if
// the peer changes its source address, so just sending the PATH_RESPONSE
// in a regular datagram is fine.
if !c.w.appendPathResponseFrame(c.path.data) {
return pad, false
}
if c.path.sendPathResponse == pathResponseExpanded {
pad = true
}
c.path.sendPathResponse = pathResponseNotNeeded
return pad, true
}
// Copyright 2023 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 quic
import "time"
func (c *Conn) ping(space numberSpace) {
c.sendMsg(func(now time.Time, c *Conn) {
c.testSendPing.setUnsent()
c.testSendPingSpace = space
})
}
// Copyright 2023 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 quic
import (
"sync"
)
// A pipe is a byte buffer used in implementing streams.
//
// A pipe contains a window of stream data.
// Random access reads and writes are supported within the window.
// Writing past the end of the window extends it.
// Data may be discarded from the start of the pipe, advancing the window.
type pipe struct {
start int64 // stream position of first stored byte
end int64 // stream position just past the last stored byte
head *pipebuf // if non-nil, then head.off + len(head.b) > start
tail *pipebuf // if non-nil, then tail.off + len(tail.b) == end
}
type pipebuf struct {
off int64 // stream position of b[0]
b []byte
next *pipebuf
}
func (pb *pipebuf) end() int64 {
return pb.off + int64(len(pb.b))
}
var pipebufPool = sync.Pool{
New: func() any {
return &pipebuf{
b: make([]byte, 4096),
}
},
}
func newPipebuf() *pipebuf {
return pipebufPool.Get().(*pipebuf)
}
func (b *pipebuf) recycle() {
b.off = 0
b.next = nil
pipebufPool.Put(b)
}
// writeAt writes len(b) bytes to the pipe at offset off.
//
// Writes to offsets before p.start are discarded.
// Writes to offsets after p.end extend the pipe window.
func (p *pipe) writeAt(b []byte, off int64) {
end := off + int64(len(b))
if end > p.end {
p.end = end
} else if end <= p.start {
return
}
if off < p.start {
// Discard the portion of b which falls before p.start.
trim := p.start - off
b = b[trim:]
off = p.start
}
if p.head == nil {
p.head = newPipebuf()
p.head.off = p.start
p.tail = p.head
}
pb := p.head
if off >= p.tail.off {
// Common case: Writing past the end of the pipe.
pb = p.tail
}
for {
pboff := off - pb.off
if pboff < int64(len(pb.b)) {
n := copy(pb.b[pboff:], b)
if n == len(b) {
return
}
off += int64(n)
b = b[n:]
}
if pb.next == nil {
pb.next = newPipebuf()
pb.next.off = pb.off + int64(len(pb.b))
p.tail = pb.next
}
pb = pb.next
}
}
// copy copies len(b) bytes into b starting from off.
// The pipe must contain [off, off+len(b)).
func (p *pipe) copy(off int64, b []byte) {
dst := b[:0]
p.read(off, len(b), func(c []byte) error {
dst = append(dst, c...)
return nil
})
}
// read calls f with the data in [off, off+n)
// The data may be provided sequentially across multiple calls to f.
// Note that read (unlike an io.Reader) does not consume the read data.
func (p *pipe) read(off int64, n int, f func([]byte) error) error {
if off < p.start {
panic("invalid read range")
}
for pb := p.head; pb != nil && n > 0; pb = pb.next {
if off >= pb.end() {
continue
}
b := pb.b[off-pb.off:]
if len(b) > n {
b = b[:n]
}
off += int64(len(b))
n -= len(b)
if err := f(b); err != nil {
return err
}
}
if n > 0 {
panic("invalid read range")
}
return nil
}
// peek returns a reference to up to n bytes of internal data buffer, starting at p.start.
// The returned slice is valid until the next call to discardBefore.
// The length of the returned slice will be in the range [0,n].
func (p *pipe) peek(n int64) []byte {
pb := p.head
if pb == nil {
return nil
}
b := pb.b[p.start-pb.off:]
return b[:min(int64(len(b)), n)]
}
// availableBuffer returns the available contiguous, allocated buffer space
// following the pipe window.
//
// This is used by the stream write fast path, which makes multiple writes into the pipe buffer
// without a lock, and then adjusts p.end at a later time with a lock held.
func (p *pipe) availableBuffer() []byte {
if p.tail == nil {
return nil
}
return p.tail.b[p.end-p.tail.off:]
}
// discardBefore discards all data prior to off.
func (p *pipe) discardBefore(off int64) {
for p.head != nil && p.head.end() < off {
head := p.head
p.head = p.head.next
head.recycle()
}
if p.head == nil {
p.tail = nil
}
p.start = off
p.end = max(p.end, off)
}
// Copyright 2023 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 quic
import (
"context"
"encoding/hex"
"log/slog"
"net/netip"
"time"
)
// Log levels for qlog events.
const (
// QLogLevelFrame includes per-frame information.
// When this level is enabled, packet_sent and packet_received events will
// contain information on individual frames sent/received.
QLogLevelFrame = slog.Level(-6)
// QLogLevelPacket events occur at most once per packet sent or received.
//
// For example: packet_sent, packet_received.
QLogLevelPacket = slog.Level(-4)
// QLogLevelConn events occur multiple times over a connection's lifetime,
// but less often than the frequency of individual packets.
//
// For example: connection_state_updated.
QLogLevelConn = slog.Level(-2)
// QLogLevelEndpoint events occur at most once per connection.
//
// For example: connection_started, connection_closed.
QLogLevelEndpoint = slog.Level(0)
)
func (c *Conn) logEnabled(level slog.Level) bool {
return logEnabled(c.log, level)
}
func logEnabled(log *slog.Logger, level slog.Level) bool {
return log != nil && log.Enabled(context.Background(), level)
}
// slogHexstring returns a slog.Attr for a value of the hexstring type.
//
// https://www.ietf.org/archive/id/draft-ietf-quic-qlog-main-schema-04.html#section-1.1.1
func slogHexstring(key string, value []byte) slog.Attr {
return slog.String(key, hex.EncodeToString(value))
}
func slogAddr(key string, value netip.Addr) slog.Attr {
return slog.String(key, value.String())
}
func (c *Conn) logConnectionStarted(originalDstConnID []byte, peerAddr netip.AddrPort) {
if c.config.QLogLogger == nil ||
!c.config.QLogLogger.Enabled(context.Background(), QLogLevelEndpoint) {
return
}
var vantage string
if c.side == clientSide {
vantage = "client"
originalDstConnID = c.connIDState.originalDstConnID
} else {
vantage = "server"
}
// A qlog Trace container includes some metadata (title, description, vantage_point)
// and a list of Events. The Trace also includes a common_fields field setting field
// values common to all events in the trace.
//
// Trace = {
// ? title: text
// ? description: text
// ? configuration: Configuration
// ? common_fields: CommonFields
// ? vantage_point: VantagePoint
// events: [* Event]
// }
//
// To map this into slog's data model, we start each per-connection trace with a With
// call that includes both the trace metadata and the common fields.
//
// This means that in slog's model, each trace event will also include
// the Trace metadata fields (vantage_point), which is a divergence from the qlog model.
c.log = c.config.QLogLogger.With(
// The group_id permits associating traces taken from different vantage points
// for the same connection.
//
// We use the original destination connection ID as the group ID.
//
// https://www.ietf.org/archive/id/draft-ietf-quic-qlog-main-schema-04.html#section-3.4.6
slogHexstring("group_id", originalDstConnID),
slog.Group("vantage_point",
slog.String("name", "go quic"),
slog.String("type", vantage),
),
)
localAddr := c.endpoint.LocalAddr()
// https://www.ietf.org/archive/id/draft-ietf-quic-qlog-quic-events-03.html#section-4.2
c.log.LogAttrs(context.Background(), QLogLevelEndpoint,
"connectivity:connection_started",
slogAddr("src_ip", localAddr.Addr()),
slog.Int("src_port", int(localAddr.Port())),
slogHexstring("src_cid", c.connIDState.local[0].cid),
slogAddr("dst_ip", peerAddr.Addr()),
slog.Int("dst_port", int(peerAddr.Port())),
slogHexstring("dst_cid", c.connIDState.remote[0].cid),
)
}
func (c *Conn) logConnectionClosed() {
if !c.logEnabled(QLogLevelEndpoint) {
return
}
err := c.lifetime.finalErr
trigger := "error"
switch e := err.(type) {
case *ApplicationError:
// TODO: Distinguish between peer and locally-initiated close.
trigger = "application"
case localTransportError:
switch err {
case errHandshakeTimeout:
trigger = "handshake_timeout"
default:
if e.code == errNo {
trigger = "clean"
}
}
case peerTransportError:
if e.code == errNo {
trigger = "clean"
}
default:
switch err {
case errIdleTimeout:
trigger = "idle_timeout"
case errStatelessReset:
trigger = "stateless_reset"
}
}
// https://www.ietf.org/archive/id/draft-ietf-quic-qlog-quic-events-03.html#section-4.3
c.log.LogAttrs(context.Background(), QLogLevelEndpoint,
"connectivity:connection_closed",
slog.String("trigger", trigger),
)
}
func (c *Conn) logPacketDropped(dgram *datagram) {
c.log.LogAttrs(context.Background(), QLogLevelPacket,
"connectivity:packet_dropped",
)
}
func (c *Conn) logLongPacketReceived(p longPacket, pkt []byte) {
var frames slog.Attr
if c.logEnabled(QLogLevelFrame) {
frames = c.packetFramesAttr(p.payload)
}
c.log.LogAttrs(context.Background(), QLogLevelPacket,
"transport:packet_received",
slog.Group("header",
slog.String("packet_type", p.ptype.qlogString()),
slog.Uint64("packet_number", uint64(p.num)),
slog.Uint64("flags", uint64(pkt[0])),
slogHexstring("scid", p.srcConnID),
slogHexstring("dcid", p.dstConnID),
),
slog.Group("raw",
slog.Int("length", len(pkt)),
),
frames,
)
}
func (c *Conn) log1RTTPacketReceived(p shortPacket, pkt []byte) {
var frames slog.Attr
if c.logEnabled(QLogLevelFrame) {
frames = c.packetFramesAttr(p.payload)
}
dstConnID, _ := dstConnIDForDatagram(pkt)
c.log.LogAttrs(context.Background(), QLogLevelPacket,
"transport:packet_received",
slog.Group("header",
slog.String("packet_type", packetType1RTT.qlogString()),
slog.Uint64("packet_number", uint64(p.num)),
slog.Uint64("flags", uint64(pkt[0])),
slogHexstring("dcid", dstConnID),
),
slog.Group("raw",
slog.Int("length", len(pkt)),
),
frames,
)
}
func (c *Conn) logPacketSent(ptype packetType, pnum packetNumber, src, dst []byte, pktLen int, payload []byte) {
var frames slog.Attr
if c.logEnabled(QLogLevelFrame) {
frames = c.packetFramesAttr(payload)
}
var scid slog.Attr
if len(src) > 0 {
scid = slogHexstring("scid", src)
}
c.log.LogAttrs(context.Background(), QLogLevelPacket,
"transport:packet_sent",
slog.Group("header",
slog.String("packet_type", ptype.qlogString()),
slog.Uint64("packet_number", uint64(pnum)),
scid,
slogHexstring("dcid", dst),
),
slog.Group("raw",
slog.Int("length", pktLen),
),
frames,
)
}
// packetFramesAttr returns the "frames" attribute containing the frames in a packet.
// We currently pass this as a slog Any containing a []slog.Value,
// where each Value is a debugFrame that implements slog.LogValuer.
//
// This isn't tremendously efficient, but avoids the need to put a JSON encoder
// in the quic package or a frame parser in the qlog package.
func (c *Conn) packetFramesAttr(payload []byte) slog.Attr {
var frames []slog.Value
for len(payload) > 0 {
f, n := parseDebugFrame(payload)
if n < 0 {
break
}
payload = payload[n:]
switch f := f.(type) {
case debugFrameAck:
// The qlog ACK frame contains the ACK Delay field as a duration.
// Interpreting the contents of this field as a duration requires
// knowing the peer's ack_delay_exponent transport parameter,
// and it's possible for us to parse an ACK frame before we've
// received that parameter.
//
// We could plumb connection state down into the frame parser,
// but for now let's minimize the amount of code that needs to
// deal with this and convert the unscaled value into a scaled one here.
ackDelay := time.Duration(-1)
if c.peerAckDelayExponent >= 0 {
ackDelay = f.ackDelay.Duration(uint8(c.peerAckDelayExponent))
}
frames = append(frames, slog.AnyValue(debugFrameScaledAck{
ranges: f.ranges,
ackDelay: ackDelay,
}))
default:
frames = append(frames, slog.AnyValue(f))
}
}
return slog.Any("frames", frames)
}
func (c *Conn) logPacketLost(space numberSpace, sent *sentPacket) {
c.log.LogAttrs(context.Background(), QLogLevelPacket,
"recovery:packet_lost",
slog.Group("header",
slog.String("packet_type", sent.ptype.qlogString()),
slog.Uint64("packet_number", uint64(sent.num)),
),
)
}
// Copyright 2023 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 quic
import "context"
// A queue is an unbounded queue of some item (new connections and streams).
type queue[T any] struct {
// The gate condition is set if the queue is non-empty or closed.
gate gate
err error
q []T
}
func newQueue[T any]() queue[T] {
return queue[T]{gate: newGate()}
}
// close closes the queue, causing pending and future pop operations
// to return immediately with err.
func (q *queue[T]) close(err error) {
q.gate.lock()
defer q.unlock()
if q.err == nil {
q.err = err
}
}
// put appends an item to the queue.
// It returns true if the item was added, false if the queue is closed.
func (q *queue[T]) put(v T) bool {
q.gate.lock()
defer q.unlock()
if q.err != nil {
return false
}
q.q = append(q.q, v)
return true
}
// get removes the first item from the queue, blocking until ctx is done, an item is available,
// or the queue is closed.
func (q *queue[T]) get(ctx context.Context) (T, error) {
var zero T
if err := q.gate.waitAndLock(ctx); err != nil {
return zero, err
}
defer q.unlock()
if q.err != nil {
return zero, q.err
}
v := q.q[0]
copy(q.q[:], q.q[1:])
q.q[len(q.q)-1] = zero
q.q = q.q[:len(q.q)-1]
return v, nil
}
func (q *queue[T]) unlock() {
q.gate.unlock(q.err != nil || len(q.q) > 0)
}
// Copyright 2023 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 quic
import (
"time"
)
// QUIC versions.
// We only support v1 at this time.
const (
quicVersion1 = 1
quicVersion2 = 0x6b3343cf // https://www.rfc-editor.org/rfc/rfc9369
)
// connIDLen is the length in bytes of connection IDs chosen by this package.
// Since 1-RTT packets don't include a connection ID length field,
// we use a consistent length for all our IDs.
// https://www.rfc-editor.org/rfc/rfc9000.html#section-5.1-6
const connIDLen = 8
// Local values of various transport parameters.
// https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2
const (
defaultMaxIdleTimeout = 30 * time.Second // max_idle_timeout
// The max_udp_payload_size transport parameter is the size of our
// network receive buffer.
//
// Set this to the largest UDP packet that can be sent over
// Ethernet without using jumbo frames: 1500 byte Ethernet frame,
// minus 20 byte IPv4 header and 8 byte UDP header.
//
// The maximum possible UDP payload is 65527 bytes. Supporting this
// without wasting memory in unused receive buffers will require some
// care. For now, just limit ourselves to the most common case.
maxUDPPayloadSize = 1472
ackDelayExponent = 3 // ack_delay_exponent
maxAckDelay = 25 * time.Millisecond // max_ack_delay
// The active_conn_id_limit transport parameter is the maximum
// number of connection IDs from the peer we're willing to store.
//
// maxPeerActiveConnIDLimit is the maximum number of connection IDs
// we're willing to send to the peer.
//
// https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-6.2.1
activeConnIDLimit = 2
maxPeerActiveConnIDLimit = 4
)
// Time limit for completing the handshake.
const defaultHandshakeTimeout = 10 * time.Second
// Keep-alive ping frequency.
const defaultKeepAlivePeriod = 0
// Local timer granularity.
// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.1.2-6
const timerGranularity = 1 * time.Millisecond
// The smallest allowed maximum datagram size.
// https://www.rfc-editor.org/rfc/rfc9000#section-14
const smallestMaxDatagramSize = 1200
// Minimum size of a UDP datagram sent by a client carrying an Initial packet,
// or a server containing an ack-eliciting Initial packet.
// https://www.rfc-editor.org/rfc/rfc9000#section-14.1
const paddedInitialDatagramSize = smallestMaxDatagramSize
// Maximum number of streams of a given type which may be created.
// https://www.rfc-editor.org/rfc/rfc9000.html#section-4.6-2
const maxStreamsLimit = 1 << 60
// Maximum number of streams we will allow the peer to create implicitly.
// A stream ID that is used out of order results in all streams of that type
// with lower-numbered IDs also being opened. To limit the amount of work we
// will do in response to a single frame, we cap the peer's stream limit to
// this value.
const implicitStreamLimit = 100
// A connSide distinguishes between the client and server sides of a connection.
type connSide int8
const (
clientSide = connSide(iota)
serverSide
)
func (s connSide) String() string {
switch s {
case clientSide:
return "client"
case serverSide:
return "server"
default:
return "BUG"
}
}
func (s connSide) peer() connSide {
if s == clientSide {
return serverSide
} else {
return clientSide
}
}
// A numberSpace is the context in which a packet number applies.
// https://www.rfc-editor.org/rfc/rfc9000.html#section-12.3-7
type numberSpace byte
const (
initialSpace = numberSpace(iota)
handshakeSpace
appDataSpace
numberSpaceCount
)
func (n numberSpace) String() string {
switch n {
case initialSpace:
return "Initial"
case handshakeSpace:
return "Handshake"
case appDataSpace:
return "AppData"
default:
return "BUG"
}
}
// A streamType is the type of a stream: bidirectional or unidirectional.
type streamType uint8
const (
bidiStream = streamType(iota)
uniStream
streamTypeCount
)
func (s streamType) qlogString() string {
switch s {
case bidiStream:
return "bidirectional"
case uniStream:
return "unidirectional"
default:
return "BUG"
}
}
func (s streamType) String() string {
switch s {
case bidiStream:
return "bidi"
case uniStream:
return "uni"
default:
return "BUG"
}
}
// A streamID is a QUIC stream ID.
// https://www.rfc-editor.org/rfc/rfc9000.html#section-2.1
type streamID uint64
// The two least significant bits of a stream ID indicate the initiator
// and directionality of the stream. The upper bits are the stream number.
// Each of the four possible combinations of initiator and direction
// each has a distinct number space.
const (
clientInitiatedStreamBit = 0x0
serverInitiatedStreamBit = 0x1
initiatorStreamBitMask = 0x1
bidiStreamBit = 0x0
uniStreamBit = 0x2
dirStreamBitMask = 0x2
)
func newStreamID(initiator connSide, typ streamType, num int64) streamID {
id := streamID(num << 2)
if typ == uniStream {
id |= uniStreamBit
}
if initiator == serverSide {
id |= serverInitiatedStreamBit
}
return id
}
func (s streamID) initiator() connSide {
if s&initiatorStreamBitMask == serverInitiatedStreamBit {
return serverSide
}
return clientSide
}
func (s streamID) num() int64 {
return int64(s) >> 2
}
func (s streamID) streamType() streamType {
if s&dirStreamBitMask == uniStreamBit {
return uniStream
}
return bidiStream
}
// packetFate is the fate of a sent packet: Either acknowledged by the peer,
// or declared lost.
type packetFate byte
const (
packetLost = packetFate(iota)
packetAcked
)
// Copyright 2023 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 quic
// A rangeset is a set of int64s, stored as an ordered list of non-overlapping,
// non-empty ranges.
//
// Rangesets are efficient for small numbers of ranges,
// which is expected to be the common case.
type rangeset[T ~int64] []i64range[T]
type i64range[T ~int64] struct {
start, end T // [start, end)
}
// size returns the size of the range.
func (r i64range[T]) size() T {
return r.end - r.start
}
// contains reports whether v is in the range.
func (r i64range[T]) contains(v T) bool {
return r.start <= v && v < r.end
}
// add adds [start, end) to the set, combining it with existing ranges if necessary.
func (s *rangeset[T]) add(start, end T) {
if start == end {
return
}
for i := range *s {
r := &(*s)[i]
if r.start > end {
// The new range comes before range i.
s.insertrange(i, start, end)
return
}
if start > r.end {
// The new range comes after range i.
continue
}
// The new range is adjacent to or overlapping range i.
if start < r.start {
r.start = start
}
if end <= r.end {
return
}
// Possibly coalesce subsequent ranges into range i.
r.end = end
j := i + 1
for ; j < len(*s) && r.end >= (*s)[j].start; j++ {
if e := (*s)[j].end; e > r.end {
// Range j ends after the new range.
r.end = e
}
}
s.removeranges(i+1, j)
return
}
*s = append(*s, i64range[T]{start, end})
}
// sub removes [start, end) from the set.
func (s *rangeset[T]) sub(start, end T) {
removefrom, removeto := -1, -1
for i := range *s {
r := &(*s)[i]
if end < r.start {
break
}
if r.end < start {
continue
}
switch {
case start <= r.start && end >= r.end:
// Remove the entire range.
if removefrom == -1 {
removefrom = i
}
removeto = i + 1
case start <= r.start:
// Remove a prefix.
r.start = end
case end >= r.end:
// Remove a suffix.
r.end = start
default:
// Remove the middle, leaving two new ranges.
rend := r.end
r.end = start
s.insertrange(i+1, end, rend)
return
}
}
if removefrom != -1 {
s.removeranges(removefrom, removeto)
}
}
// contains reports whether s contains v.
func (s rangeset[T]) contains(v T) bool {
for _, r := range s {
if v >= r.end {
continue
}
if r.start <= v {
return true
}
return false
}
return false
}
// rangeContaining returns the range containing v, or the range [0,0) if v is not in s.
func (s rangeset[T]) rangeContaining(v T) i64range[T] {
for _, r := range s {
if v >= r.end {
continue
}
if r.start <= v {
return r
}
break
}
return i64range[T]{0, 0}
}
// min returns the minimum value in the set, or 0 if empty.
func (s rangeset[T]) min() T {
if len(s) == 0 {
return 0
}
return s[0].start
}
// max returns the maximum value in the set, or 0 if empty.
func (s rangeset[T]) max() T {
if len(s) == 0 {
return 0
}
return s[len(s)-1].end - 1
}
// end returns the end of the last range in the set, or 0 if empty.
func (s rangeset[T]) end() T {
if len(s) == 0 {
return 0
}
return s[len(s)-1].end
}
// numRanges returns the number of ranges in the rangeset.
func (s rangeset[T]) numRanges() int {
return len(s)
}
// size returns the size of all ranges in the rangeset.
func (s rangeset[T]) size() (total T) {
for _, r := range s {
total += r.size()
}
return total
}
// isrange reports if the rangeset covers exactly the range [start, end).
func (s rangeset[T]) isrange(start, end T) bool {
switch len(s) {
case 0:
return start == 0 && end == 0
case 1:
return s[0].start == start && s[0].end == end
}
return false
}
// removeranges removes ranges [i,j).
func (s *rangeset[T]) removeranges(i, j int) {
if i == j {
return
}
copy((*s)[i:], (*s)[j:])
*s = (*s)[:len(*s)-(j-i)]
}
// insert adds a new range at index i.
func (s *rangeset[T]) insertrange(i int, start, end T) {
*s = append(*s, i64range[T]{})
copy((*s)[i+1:], (*s)[i:])
(*s)[i] = i64range[T]{start, end}
}
// Copyright 2023 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 quic
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/binary"
"net/netip"
"time"
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/net/internal/quic/quicwire"
)
// AEAD and nonce used to compute the Retry Integrity Tag.
// https://www.rfc-editor.org/rfc/rfc9001#section-5.8
var (
retrySecret = []byte{0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a, 0x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e}
retryNonce = []byte{0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb}
retryAEAD = func() cipher.AEAD {
c, err := aes.NewCipher(retrySecret)
if err != nil {
panic(err)
}
aead, err := cipher.NewGCM(c)
if err != nil {
panic(err)
}
return aead
}()
)
// retryTokenValidityPeriod is how long we accept a Retry packet token after sending it.
const retryTokenValidityPeriod = 5 * time.Second
// retryState generates and validates an endpoint's retry tokens.
type retryState struct {
aead cipher.AEAD
}
func (rs *retryState) init() error {
// Retry tokens are authenticated using a per-server key chosen at start time.
// TODO: Provide a way for the user to set this key.
secret := make([]byte, chacha20poly1305.KeySize)
if _, err := rand.Read(secret); err != nil {
return err
}
aead, err := chacha20poly1305.NewX(secret)
if err != nil {
panic(err)
}
rs.aead = aead
return nil
}
// Retry tokens are encrypted with an AEAD.
// The plaintext contains the time the token was created and
// the original destination connection ID.
// The additional data contains the sender's source address and original source connection ID.
// The token nonce is randomly generated.
// We use the nonce as the Source Connection ID of the Retry packet.
// Since the 24-byte XChaCha20-Poly1305 nonce is too large to fit in a 20-byte connection ID,
// we include the remaining 4 bytes of nonce in the token.
//
// Token {
// Last 4 Bytes of Nonce (32),
// Ciphertext (..),
// }
//
// Plaintext {
// Timestamp (64),
// Original Destination Connection ID,
// }
//
//
// Additional Data {
// Original Source Connection ID Length (8),
// Original Source Connection ID (..),
// IP Address (32..128),
// Port (16),
// }
//
// TODO: Consider using AES-256-GCM-SIV once crypto/tls supports it.
func (rs *retryState) makeToken(now time.Time, srcConnID, origDstConnID []byte, addr netip.AddrPort) (token, newDstConnID []byte, err error) {
nonce := make([]byte, rs.aead.NonceSize())
if _, err := rand.Read(nonce); err != nil {
return nil, nil, err
}
var plaintext []byte
plaintext = binary.BigEndian.AppendUint64(plaintext, uint64(now.Unix()))
plaintext = append(plaintext, origDstConnID...)
token = append(token, nonce[maxConnIDLen:]...)
token = rs.aead.Seal(token, nonce, plaintext, rs.additionalData(srcConnID, addr))
return token, nonce[:maxConnIDLen], nil
}
func (rs *retryState) validateToken(now time.Time, token, srcConnID, dstConnID []byte, addr netip.AddrPort) (origDstConnID []byte, ok bool) {
tokenNonceLen := rs.aead.NonceSize() - maxConnIDLen
if len(token) < tokenNonceLen {
return nil, false
}
nonce := append([]byte{}, dstConnID...)
nonce = append(nonce, token[:tokenNonceLen]...)
ciphertext := token[tokenNonceLen:]
plaintext, err := rs.aead.Open(nil, nonce, ciphertext, rs.additionalData(srcConnID, addr))
if err != nil {
return nil, false
}
if len(plaintext) < 8 {
return nil, false
}
when := time.Unix(int64(binary.BigEndian.Uint64(plaintext)), 0)
origDstConnID = plaintext[8:]
// We allow for tokens created in the future (up to the validity period),
// which likely indicates that the system clock was adjusted backwards.
if d := abs(now.Sub(when)); d > retryTokenValidityPeriod {
return nil, false
}
return origDstConnID, true
}
func (rs *retryState) additionalData(srcConnID []byte, addr netip.AddrPort) []byte {
var additional []byte
additional = quicwire.AppendUint8Bytes(additional, srcConnID)
additional = append(additional, addr.Addr().AsSlice()...)
additional = binary.BigEndian.AppendUint16(additional, addr.Port())
return additional
}
func (e *Endpoint) validateInitialAddress(now time.Time, p genericLongPacket, peerAddr netip.AddrPort) (origDstConnID []byte, ok bool) {
// The retry token is at the start of an Initial packet's data.
token, n := quicwire.ConsumeUint8Bytes(p.data)
if n < 0 {
// We've already validated that the packet is at least 1200 bytes long,
// so there's no way for even a maximum size token to not fit.
// Check anyway.
return nil, false
}
if len(token) == 0 {
// The sender has not provided a token.
// Send a Retry packet to them with one.
e.sendRetry(now, p, peerAddr)
return nil, false
}
origDstConnID, ok = e.retry.validateToken(now, token, p.srcConnID, p.dstConnID, peerAddr)
if !ok {
// This does not seem to be a valid token.
// Close the connection with an INVALID_TOKEN error.
// https://www.rfc-editor.org/rfc/rfc9000#section-8.1.2-5
e.sendConnectionClose(p, peerAddr, errInvalidToken)
return nil, false
}
return origDstConnID, true
}
func (e *Endpoint) sendRetry(now time.Time, p genericLongPacket, peerAddr netip.AddrPort) {
token, srcConnID, err := e.retry.makeToken(now, p.srcConnID, p.dstConnID, peerAddr)
if err != nil {
return
}
b := encodeRetryPacket(p.dstConnID, retryPacket{
dstConnID: p.srcConnID,
srcConnID: srcConnID,
token: token,
})
e.sendDatagram(datagram{
b: b,
peerAddr: peerAddr,
})
}
type retryPacket struct {
dstConnID []byte
srcConnID []byte
token []byte
}
func encodeRetryPacket(originalDstConnID []byte, p retryPacket) []byte {
// Retry packets include an integrity tag, computed by AEAD_AES_128_GCM over
// the original destination connection ID followed by the Retry packet
// (less the integrity tag itself).
// https://www.rfc-editor.org/rfc/rfc9001#section-5.8
//
// Create the pseudo-packet (including the original DCID), append the tag,
// and return the Retry packet.
var b []byte
b = quicwire.AppendUint8Bytes(b, originalDstConnID) // Original Destination Connection ID
start := len(b) // start of the Retry packet
b = append(b, headerFormLong|fixedBit|longPacketTypeRetry)
b = binary.BigEndian.AppendUint32(b, quicVersion1) // Version
b = quicwire.AppendUint8Bytes(b, p.dstConnID) // Destination Connection ID
b = quicwire.AppendUint8Bytes(b, p.srcConnID) // Source Connection ID
b = append(b, p.token...) // Token
b = retryAEAD.Seal(b, retryNonce, nil, b) // Retry Integrity Tag
return b[start:]
}
func parseRetryPacket(b, origDstConnID []byte) (p retryPacket, ok bool) {
const retryIntegrityTagLength = 128 / 8
lp, ok := parseGenericLongHeaderPacket(b)
if !ok {
return retryPacket{}, false
}
if len(lp.data) < retryIntegrityTagLength {
return retryPacket{}, false
}
gotTag := lp.data[len(lp.data)-retryIntegrityTagLength:]
// Create the pseudo-packet consisting of the original destination connection ID
// followed by the Retry packet (less the integrity tag).
// Use this to validate the packet integrity tag.
pseudo := quicwire.AppendUint8Bytes(nil, origDstConnID)
pseudo = append(pseudo, b[:len(b)-retryIntegrityTagLength]...)
wantTag := retryAEAD.Seal(nil, retryNonce, nil, pseudo)
if !bytes.Equal(gotTag, wantTag) {
return retryPacket{}, false
}
token := lp.data[:len(lp.data)-retryIntegrityTagLength]
return retryPacket{
dstConnID: lp.dstConnID,
srcConnID: lp.srcConnID,
token: token,
}, true
}
// Copyright 2023 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 quic
import (
"time"
)
type rttState struct {
minRTT time.Duration
latestRTT time.Duration
smoothedRTT time.Duration
rttvar time.Duration // RTT variation
firstSampleTime time.Time // time of first RTT sample
}
func (r *rttState) init() {
r.minRTT = -1 // -1 indicates the first sample has not been taken yet
// "[...] the initial RTT SHOULD be set to 333 milliseconds."
// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.2-1
const initialRTT = 333 * time.Millisecond
// https://www.rfc-editor.org/rfc/rfc9002.html#section-5.3-12
r.smoothedRTT = initialRTT
r.rttvar = initialRTT / 2
}
func (r *rttState) establishPersistentCongestion() {
// "Endpoints SHOULD set the min_rtt to the newest RTT sample
// after persistent congestion is established."
// https://www.rfc-editor.org/rfc/rfc9002#section-5.2-5
r.minRTT = r.latestRTT
}
// updateSample is called when we generate a new RTT sample.
// https://www.rfc-editor.org/rfc/rfc9002.html#section-5
func (r *rttState) updateSample(now time.Time, handshakeConfirmed bool, spaceID numberSpace, latestRTT, ackDelay, maxAckDelay time.Duration) {
r.latestRTT = latestRTT
if r.minRTT < 0 {
// First RTT sample.
// "min_rtt MUST be set to the latest_rtt on the first RTT sample."
// https://www.rfc-editor.org/rfc/rfc9002.html#section-5.2-2
r.minRTT = latestRTT
// https://www.rfc-editor.org/rfc/rfc9002.html#section-5.3-14
r.smoothedRTT = latestRTT
r.rttvar = latestRTT / 2
r.firstSampleTime = now
return
}
// "min_rtt MUST be set to the lesser of min_rtt and latest_rtt [...]
// on all other samples."
// https://www.rfc-editor.org/rfc/rfc9002.html#section-5.2-2
r.minRTT = min(r.minRTT, latestRTT)
// https://www.rfc-editor.org/rfc/rfc9002.html#section-5.3-16
if handshakeConfirmed {
ackDelay = min(ackDelay, maxAckDelay)
}
adjustedRTT := latestRTT - ackDelay
if adjustedRTT < r.minRTT {
adjustedRTT = latestRTT
}
rttvarSample := abs(r.smoothedRTT - adjustedRTT)
r.rttvar = (3*r.rttvar + rttvarSample) / 4
r.smoothedRTT = ((7 * r.smoothedRTT) + adjustedRTT) / 8
}
// Copyright 2023 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 quic
import (
"sync"
"time"
"golang.org/x/net/internal/quic/quicwire"
)
// A sentPacket tracks state related to an in-flight packet we sent,
// to be committed when the peer acks it or resent if the packet is lost.
type sentPacket struct {
num packetNumber
size int // size in bytes
time time.Time // time sent
ptype packetType
state sentPacketState
ackEliciting bool // https://www.rfc-editor.org/rfc/rfc9002.html#section-2-3.4.1
inFlight bool // https://www.rfc-editor.org/rfc/rfc9002.html#section-2-3.6.1
// Frames sent in the packet.
//
// This is an abbreviated version of the packet payload, containing only the information
// we need to process an ack for or loss of this packet.
// For example, a CRYPTO frame is recorded as the frame type (0x06), offset, and length,
// but does not include the sent data.
//
// This buffer is written by packetWriter.append* and read by Conn.handleAckOrLoss.
b []byte
n int // read offset into b
}
type sentPacketState uint8
const (
sentPacketSent = sentPacketState(iota) // sent but neither acked nor lost
sentPacketAcked // acked
sentPacketLost // declared lost
sentPacketUnsent // never sent
)
var sentPool = sync.Pool{
New: func() any {
return &sentPacket{}
},
}
func newSentPacket() *sentPacket {
sent := sentPool.Get().(*sentPacket)
sent.reset()
return sent
}
// recycle returns a sentPacket to the pool.
func (sent *sentPacket) recycle() {
sentPool.Put(sent)
}
func (sent *sentPacket) reset() {
*sent = sentPacket{
b: sent.b[:0],
}
}
// markAckEliciting marks the packet as containing an ack-eliciting frame.
func (sent *sentPacket) markAckEliciting() {
sent.ackEliciting = true
sent.inFlight = true
}
// The append* methods record information about frames in the packet.
func (sent *sentPacket) appendNonAckElicitingFrame(frameType byte) {
sent.b = append(sent.b, frameType)
}
func (sent *sentPacket) appendAckElicitingFrame(frameType byte) {
sent.ackEliciting = true
sent.inFlight = true
sent.b = append(sent.b, frameType)
}
func (sent *sentPacket) appendInt(v uint64) {
sent.b = quicwire.AppendVarint(sent.b, v)
}
func (sent *sentPacket) appendOffAndSize(start int64, size int) {
sent.b = quicwire.AppendVarint(sent.b, uint64(start))
sent.b = quicwire.AppendVarint(sent.b, uint64(size))
}
// The next* methods read back information about frames in the packet.
func (sent *sentPacket) next() (frameType byte) {
f := sent.b[sent.n]
sent.n++
return f
}
func (sent *sentPacket) nextInt() uint64 {
v, n := quicwire.ConsumeVarint(sent.b[sent.n:])
sent.n += n
return v
}
func (sent *sentPacket) nextRange() (start, end int64) {
start = int64(sent.nextInt())
end = start + int64(sent.nextInt())
return start, end
}
func (sent *sentPacket) done() bool {
return sent.n == len(sent.b)
}
// Copyright 2023 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 quic
// A sentPacketList is a ring buffer of sentPackets.
//
// Processing an ack for a packet causes all older packets past a small threshold
// to be discarded (RFC 9002, Section 6.1.1), so the list of in-flight packets is
// not sparse and will contain at most a few acked/lost packets we no longer
// care about.
type sentPacketList struct {
nextNum packetNumber // next packet number to add to the buffer
off int // offset of first packet in the buffer
size int // number of packets
p []*sentPacket
}
// start is the first packet in the list.
func (s *sentPacketList) start() packetNumber {
return s.nextNum - packetNumber(s.size)
}
// end is one after the last packet in the list.
// If the list is empty, start == end.
func (s *sentPacketList) end() packetNumber {
return s.nextNum
}
// discard clears the list.
func (s *sentPacketList) discard() {
*s = sentPacketList{}
}
// add appends a packet to the list.
func (s *sentPacketList) add(sent *sentPacket) {
if s.nextNum != sent.num {
panic("inserting out-of-order packet")
}
s.nextNum++
if s.size >= len(s.p) {
s.grow()
}
i := (s.off + s.size) % len(s.p)
s.size++
s.p[i] = sent
}
// nth returns a packet by index.
func (s *sentPacketList) nth(n int) *sentPacket {
index := (s.off + n) % len(s.p)
return s.p[index]
}
// num returns a packet by number.
// It returns nil if the packet is not in the list.
func (s *sentPacketList) num(num packetNumber) *sentPacket {
i := int(num - s.start())
if i < 0 || i >= s.size {
return nil
}
return s.nth(i)
}
// clean removes all acked or lost packets from the head of the list.
func (s *sentPacketList) clean() {
for s.size > 0 {
sent := s.p[s.off]
if sent.state == sentPacketSent {
return
}
sent.recycle()
s.p[s.off] = nil
s.off = (s.off + 1) % len(s.p)
s.size--
}
s.off = 0
}
// grow increases the buffer to hold more packaets.
func (s *sentPacketList) grow() {
newSize := len(s.p) * 2
if newSize == 0 {
newSize = 64
}
p := make([]*sentPacket, newSize)
for i := 0; i < s.size; i++ {
p[i] = s.nth(i)
}
s.p = p
s.off = 0
}
// Copyright 2023 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 quic
// A sentVal tracks sending some piece of information to the peer.
// It tracks whether the information has been sent, acked, and
// (when in-flight) the most recent packet to carry it.
//
// For example, a sentVal can track sending of a RESET_STREAM frame.
//
// - unset: stream is active, no need to send RESET_STREAM
// - unsent: we should send a RESET_STREAM, but have not yet
// - sent: we have sent a RESET_STREAM, but have not received an ack
// - received: we have sent a RESET_STREAM, and the peer has acked the packet that contained it
//
// In the "sent" state, a sentVal also tracks the latest packet number to carry
// the information. (QUIC packet numbers are always at most 62 bits in size,
// so the sentVal keeps the number in the low 62 bits and the state in the high 2 bits.)
type sentVal uint64
const (
sentValUnset = 0 // unset
sentValUnsent = 1 << 62 // set, not sent to the peer
sentValSent = 2 << 62 // set, sent to the peer but not yet acked; pnum is set
sentValReceived = 3 << 62 // set, peer acked receipt
sentValStateMask = 3 << 62
)
// isSet reports whether the value is set.
func (s sentVal) isSet() bool { return s != 0 }
// shouldSend reports whether the value is set and has not been sent to the peer.
func (s sentVal) shouldSend() bool { return s.state() == sentValUnsent }
// shouldSendPTO reports whether the value needs to be sent to the peer.
// The value needs to be sent if it is set and has not been sent.
// If pto is true, indicating that we are sending a PTO probe, the value
// should also be sent if it is set and has not been acknowledged.
func (s sentVal) shouldSendPTO(pto bool) bool {
st := s.state()
return st == sentValUnsent || (pto && st == sentValSent)
}
// isReceived reports whether the value has been received by the peer.
func (s sentVal) isReceived() bool { return s == sentValReceived }
// set sets the value and records that it should be sent to the peer.
// If the value has already been sent, it is not resent.
func (s *sentVal) set() {
if *s == 0 {
*s = sentValUnsent
}
}
// reset sets the value to the unsent state.
func (s *sentVal) setUnsent() { *s = sentValUnsent }
// clear sets the value to the unset state.
func (s *sentVal) clear() { *s = sentValUnset }
// setSent sets the value to the send state and records the number of the most recent
// packet containing the value.
func (s *sentVal) setSent(pnum packetNumber) {
*s = sentValSent | sentVal(pnum)
}
// setReceived sets the value to the received state.
func (s *sentVal) setReceived() { *s = sentValReceived }
// ackOrLoss reports that an acknowledgement has been received for the value,
// or that the packet carrying the value has been lost.
func (s *sentVal) ackOrLoss(pnum packetNumber, fate packetFate) {
if fate == packetAcked {
*s = sentValReceived
} else if *s == sentVal(pnum)|sentValSent {
*s = sentValUnsent
}
}
// ackLatestOrLoss reports that an acknowledgement has been received for the value,
// or that the packet carrying the value has been lost.
// The value is set to the acked state only if pnum is the latest packet containing it.
//
// We use this to handle acks for data that varies every time it is sent.
// For example, if we send a MAX_DATA frame followed by an updated MAX_DATA value in a
// second packet, we consider the data sent only upon receiving an ack for the most
// recent value.
func (s *sentVal) ackLatestOrLoss(pnum packetNumber, fate packetFate) {
if fate == packetAcked {
if *s == sentVal(pnum)|sentValSent {
*s = sentValReceived
}
} else {
if *s == sentVal(pnum)|sentValSent {
*s = sentValUnsent
}
}
}
func (s sentVal) state() uint64 { return uint64(s) & sentValStateMask }
// Copyright 2025 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 quic
// skipState is state for optimistic ACK defenses.
//
// An endpoint performs an optimistic ACK attack by sending acknowledgements for packets
// which it has not received, potentially convincing the sender's congestion controller to
// send at rates beyond what the network supports.
//
// We defend against this by periodically skipping packet numbers.
// Receiving an ACK for an unsent packet number is a PROTOCOL_VIOLATION error.
//
// We only skip packet numbers in the Application Data number space.
// The total data sent in the Initial/Handshake spaces should generally fit into
// the initial congestion window.
//
// https://www.rfc-editor.org/rfc/rfc9000.html#section-21.4
type skipState struct {
// skip is the next packet number (in the Application Data space) we should skip.
skip packetNumber
// maxSkip is the maximum number of packets to send before skipping another number.
// Increases over time.
maxSkip int64
}
func (ss *skipState) init(c *Conn) {
ss.maxSkip = 256 // skip our first packet number within this range
ss.updateNumberSkip(c)
}
// shouldSkip returns whether we should skip the given packet number.
func (ss *skipState) shouldSkip(num packetNumber) bool {
return ss.skip == num
}
// updateNumberSkip schedules a packet to be skipped after skipping lastSkipped.
func (ss *skipState) updateNumberSkip(c *Conn) {
// Send at least this many packets before skipping.
// Limits the impact of skipping a little,
// plus allows most tests to ignore skipping.
const minSkip = 64
skip := minSkip + c.prng.Int64N(ss.maxSkip-minSkip)
ss.skip += packetNumber(skip)
// Double the size of the skip each time until we reach 128k.
// The idea here is that an attacker needs to correctly ack ~N packets in order
// to send an optimistic ack for another ~N packets.
// Skipping packet numbers comes with a small cost (it causes the receiver to
// send an immediate ACK rather than the usual delayed ACK), so we increase the
// time between skips as a connection's lifetime grows.
//
// The 128k cap is arbitrary, chosen so that we skip a packet number
// about once a second when sending full-size datagrams at 1Gbps.
if ss.maxSkip < 128*1024 {
ss.maxSkip *= 2
}
}
// Copyright 2023 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 quic
import (
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"hash"
"sync"
)
const statelessResetTokenLen = 128 / 8
// A statelessResetToken is a stateless reset token.
// https://www.rfc-editor.org/rfc/rfc9000#section-10.3
type statelessResetToken [statelessResetTokenLen]byte
type statelessResetTokenGenerator struct {
canReset bool
// The hash.Hash interface is not concurrency safe,
// so we need a mutex here.
//
// There shouldn't be much contention on stateless reset token generation.
// If this proves to be a problem, we could avoid the mutex by using a separate
// generator per Conn, or by using a concurrency-safe generator.
mu sync.Mutex
mac hash.Hash
}
func (g *statelessResetTokenGenerator) init(secret [32]byte) {
zero := true
for _, b := range secret {
if b != 0 {
zero = false
break
}
}
if zero {
// Generate tokens using a random secret, but don't send stateless resets.
rand.Read(secret[:])
g.canReset = false
} else {
g.canReset = true
}
g.mac = hmac.New(sha256.New, secret[:])
}
func (g *statelessResetTokenGenerator) tokenForConnID(cid []byte) (token statelessResetToken) {
g.mu.Lock()
defer g.mu.Unlock()
defer g.mac.Reset()
g.mac.Write(cid)
copy(token[:], g.mac.Sum(nil))
return token
}
// Copyright 2023 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 quic
import (
"context"
"errors"
"fmt"
"io"
"math"
"golang.org/x/net/internal/quic/quicwire"
)
// A Stream is an ordered byte stream.
//
// Streams may be bidirectional, read-only, or write-only.
// Methods inappropriate for a stream's direction
// (for example, [Write] to a read-only stream)
// return errors.
//
// It is not safe to perform concurrent reads from or writes to a stream.
// It is safe, however, to read and write at the same time.
//
// Reads and writes are buffered.
// It is generally not necessary to wrap a stream in a [bufio.ReadWriter]
// or otherwise apply additional buffering.
//
// To cancel reads or writes, use the [SetReadContext] and [SetWriteContext] methods.
type Stream struct {
id streamID
conn *Conn
// Contexts used for read/write operations.
// Intentionally not mutex-guarded, to allow the race detector to catch concurrent access.
inctx context.Context
outctx context.Context
// ingate's lock guards receive-related state.
//
// The gate condition is set if a read from the stream will not block,
// either because the stream has available data or because the read will fail.
ingate gate
in pipe // received data
inwin int64 // last MAX_STREAM_DATA sent to the peer
insendmax sentVal // set when we should send MAX_STREAM_DATA to the peer
inmaxbuf int64 // maximum amount of data we will buffer
insize int64 // stream final size; -1 before this is known
inset rangeset[int64] // received ranges
inclosed sentVal // set by CloseRead
inresetcode int64 // RESET_STREAM code received from the peer; -1 if not reset
// outgate's lock guards send-related state.
//
// The gate condition is set if a write to the stream will not block,
// either because the stream has available flow control or because
// the write will fail.
outgate gate
out pipe // buffered data to send
outflushed int64 // offset of last flush call
outwin int64 // maximum MAX_STREAM_DATA received from the peer
outmaxsent int64 // maximum data offset we've sent to the peer
outmaxbuf int64 // maximum amount of data we will buffer
outunsent rangeset[int64] // ranges buffered but not yet sent (only flushed data)
outacked rangeset[int64] // ranges sent and acknowledged
outopened sentVal // set if we should open the stream
outclosed sentVal // set by CloseWrite
outblocked sentVal // set when a write to the stream is blocked by flow control
outreset sentVal // set by Reset
outresetcode uint64 // reset code to send in RESET_STREAM
outdone chan struct{} // closed when all data sent
// Unsynchronized buffers, used for lock-free fast path.
inbuf []byte // received data
inbufoff int // bytes of inbuf which have been consumed
outbuf []byte // written data
outbufoff int // bytes of outbuf which contain data to write
// Atomic stream state bits.
//
// These bits provide a fast way to coordinate between the
// send and receive sides of the stream, and the conn's loop.
//
// streamIn* bits must be set with ingate held.
// streamOut* bits must be set with outgate held.
// streamConn* bits are set by the conn's loop.
// streamQueue* bits must be set with streamsState.sendMu held.
state atomicBits[streamState]
prev, next *Stream // guarded by streamsState.sendMu
}
type streamState uint32
const (
// streamInSendMeta is set when there are frames to send for the
// inbound side of the stream. For example, MAX_STREAM_DATA.
// Inbound frames are never flow-controlled.
streamInSendMeta = streamState(1 << iota)
// streamOutSendMeta is set when there are non-flow-controlled frames
// to send for the outbound side of the stream. For example, STREAM_DATA_BLOCKED.
// streamOutSendData is set when there are no non-flow-controlled outbound frames
// and the stream has data to send.
//
// At most one of streamOutSendMeta and streamOutSendData is set at any time.
streamOutSendMeta
streamOutSendData
// streamInDone and streamOutDone are set when the inbound or outbound
// sides of the stream are finished. When both are set, the stream
// can be removed from the Conn and forgotten.
streamInDone
streamOutDone
// streamConnRemoved is set when the stream has been removed from the conn.
streamConnRemoved
// streamQueueMeta and streamQueueData indicate which of the streamsState
// send queues the conn is currently on.
streamQueueMeta
streamQueueData
)
type streamQueue int
const (
noQueue = streamQueue(iota)
metaQueue // streamsState.queueMeta
dataQueue // streamsState.queueData
)
// streamResetByConnClose is assigned to Stream.inresetcode to indicate that a stream
// was implicitly reset when the connection closed. It's out of the range of
// possible reset codes the peer can send.
const streamResetByConnClose = math.MaxInt64
// wantQueue returns the send queue the stream should be on.
func (s streamState) wantQueue() streamQueue {
switch {
case s&(streamInSendMeta|streamOutSendMeta) != 0:
return metaQueue
case s&(streamInDone|streamOutDone|streamConnRemoved) == streamInDone|streamOutDone:
return metaQueue
case s&streamOutSendData != 0:
// The stream has no non-flow-controlled frames to send,
// but does have data. Put it on the data queue, which is only
// processed when flow control is available.
return dataQueue
}
return noQueue
}
// inQueue returns the send queue the stream is currently on.
func (s streamState) inQueue() streamQueue {
switch {
case s&streamQueueMeta != 0:
return metaQueue
case s&streamQueueData != 0:
return dataQueue
}
return noQueue
}
// newStream returns a new stream.
//
// The stream's ingate and outgate are locked.
// (We create the stream with locked gates so after the caller
// initializes the flow control window,
// unlocking outgate will set the stream writability state.)
func newStream(c *Conn, id streamID) *Stream {
s := &Stream{
conn: c,
id: id,
insize: -1, // -1 indicates the stream size is unknown
inresetcode: -1, // -1 indicates no RESET_STREAM received
ingate: newLockedGate(),
outgate: newLockedGate(),
inctx: context.Background(),
outctx: context.Background(),
}
if !s.IsReadOnly() {
s.outdone = make(chan struct{})
}
return s
}
// SetReadContext sets the context used for reads from the stream.
//
// It is not safe to call SetReadContext concurrently.
func (s *Stream) SetReadContext(ctx context.Context) {
s.inctx = ctx
}
// SetWriteContext sets the context used for writes to the stream.
// The write context is also used by Close when waiting for writes to be
// received by the peer.
//
// It is not safe to call SetWriteContext concurrently.
func (s *Stream) SetWriteContext(ctx context.Context) {
s.outctx = ctx
}
// IsReadOnly reports whether the stream is read-only
// (a unidirectional stream created by the peer).
func (s *Stream) IsReadOnly() bool {
return s.id.streamType() == uniStream && s.id.initiator() != s.conn.side
}
// IsWriteOnly reports whether the stream is write-only
// (a unidirectional stream created locally).
func (s *Stream) IsWriteOnly() bool {
return s.id.streamType() == uniStream && s.id.initiator() == s.conn.side
}
// Read reads data from the stream.
//
// Read returns as soon as at least one byte of data is available.
//
// If the peer closes the stream cleanly, Read returns io.EOF after
// returning all data sent by the peer.
// If the peer aborts reads on the stream, Read returns
// an error wrapping StreamResetCode.
//
// It is not safe to call Read concurrently.
func (s *Stream) Read(b []byte) (n int, err error) {
if s.IsWriteOnly() {
return 0, errors.New("read from write-only stream")
}
if len(s.inbuf) > s.inbufoff {
// Fast path: If s.inbuf contains unread bytes, return them immediately
// without taking a lock.
n = copy(b, s.inbuf[s.inbufoff:])
s.inbufoff += n
return n, nil
}
if err := s.ingate.waitAndLock(s.inctx); err != nil {
return 0, err
}
if s.inbufoff > 0 {
// Discard bytes consumed by the fast path above.
s.in.discardBefore(s.in.start + int64(s.inbufoff))
s.inbufoff = 0
s.inbuf = nil
}
// bytesRead contains the number of bytes of connection-level flow control to return.
// We return flow control for bytes read by this Read call, as well as bytes moved
// to the fast-path read buffer (s.inbuf).
var bytesRead int64
defer func() {
s.inUnlock()
s.conn.handleStreamBytesReadOffLoop(bytesRead) // must be done with ingate unlocked
}()
if s.inresetcode != -1 {
if s.inresetcode == streamResetByConnClose {
if err := s.conn.finalError(); err != nil {
return 0, err
}
}
return 0, fmt.Errorf("stream reset by peer: %w", StreamErrorCode(s.inresetcode))
}
if s.inclosed.isSet() {
return 0, errors.New("read from closed stream")
}
if s.insize == s.in.start {
return 0, io.EOF
}
// Getting here indicates the stream contains data to be read.
if len(s.inset) < 1 || s.inset[0].start != 0 || s.inset[0].end <= s.in.start {
panic("BUG: inconsistent input stream state")
}
if size := int(s.inset[0].end - s.in.start); size < len(b) {
b = b[:size]
}
bytesRead = int64(len(b))
start := s.in.start
end := start + int64(len(b))
s.in.copy(start, b)
s.in.discardBefore(end)
if end == s.insize {
// We have read up to the end of the stream.
// No need to update stream flow control.
return len(b), io.EOF
}
if len(s.inset) > 0 && s.inset[0].start <= s.in.start && s.inset[0].end > s.in.start {
// If we have more readable bytes available, put the next chunk of data
// in s.inbuf for lock-free reads.
s.inbuf = s.in.peek(s.inset[0].end - s.in.start)
bytesRead += int64(len(s.inbuf))
}
if s.insize == -1 || s.insize > s.inwin {
newWindow := s.in.start + int64(len(s.inbuf)) + s.inmaxbuf
addedWindow := newWindow - s.inwin
if shouldUpdateFlowControl(s.inmaxbuf, addedWindow) {
// Update stream flow control with a STREAM_MAX_DATA frame.
s.insendmax.setUnsent()
}
}
return len(b), nil
}
// ReadByte reads and returns a single byte from the stream.
//
// It is not safe to call ReadByte concurrently.
func (s *Stream) ReadByte() (byte, error) {
if len(s.inbuf) > s.inbufoff {
b := s.inbuf[s.inbufoff]
s.inbufoff++
return b, nil
}
var b [1]byte
n, err := s.Read(b[:])
if n > 0 {
return b[0], nil
}
return 0, err
}
// shouldUpdateFlowControl determines whether to send a flow control window update.
//
// We want to balance keeping the peer well-supplied with flow control with not sending
// many small updates.
func shouldUpdateFlowControl(maxWindow, addedWindow int64) bool {
return addedWindow >= maxWindow/8
}
// Write writes data to the stream.
//
// Write writes data to the stream write buffer.
// Buffered data is only sent when the buffer is sufficiently full.
// Call the Flush method to ensure buffered data is sent.
func (s *Stream) Write(b []byte) (n int, err error) {
if s.IsReadOnly() {
return 0, errors.New("write to read-only stream")
}
if len(b) > 0 && len(s.outbuf)-s.outbufoff >= len(b) {
// Fast path: The data to write fits in s.outbuf.
copy(s.outbuf[s.outbufoff:], b)
s.outbufoff += len(b)
return len(b), nil
}
canWrite := s.outgate.lock()
s.flushFastOutputBuffer()
for {
// The first time through this loop, we may or may not be write blocked.
// We exit the loop after writing all data, so on subsequent passes through
// the loop we are always write blocked.
if len(b) > 0 && !canWrite {
// Our send buffer is full. Wait for the peer to ack some data.
s.outUnlock()
if err := s.outgate.waitAndLock(s.outctx); err != nil {
return n, err
}
// Successfully returning from waitAndLockGate means we are no longer
// write blocked. (Unlike traditional condition variables, gates do not
// have spurious wakeups.)
}
if err := s.writeErrorLocked(); err != nil {
s.outUnlock()
return n, err
}
if len(b) == 0 {
break
}
// Write limit is our send buffer limit.
// This is a stream offset.
lim := s.out.start + s.outmaxbuf
// Amount to write is min(the full buffer, data up to the write limit).
// This is a number of bytes.
nn := min(int64(len(b)), lim-s.out.end)
// Copy the data into the output buffer.
s.out.writeAt(b[:nn], s.out.end)
b = b[nn:]
n += int(nn)
// Possibly flush the output buffer.
// We automatically flush if:
// - We have enough data to consume the send window.
// Sending this data may cause the peer to extend the window.
// - We have buffered as much data as we're willing do.
// We need to send data to clear out buffer space.
// - We have enough data to fill a 1-RTT packet using the smallest
// possible maximum datagram size (1200 bytes, less header byte,
// connection ID, packet number, and AEAD overhead).
const autoFlushSize = smallestMaxDatagramSize - 1 - connIDLen - 1 - aeadOverhead
shouldFlush := s.out.end >= s.outwin || // peer send window is full
s.out.end >= lim || // local send buffer is full
(s.out.end-s.outflushed) >= autoFlushSize // enough data buffered
if shouldFlush {
s.flushLocked()
}
if s.out.end > s.outwin {
// We're blocked by flow control.
// Send a STREAM_DATA_BLOCKED frame to let the peer know.
s.outblocked.set()
}
// If we have bytes left to send, we're blocked.
canWrite = false
}
if lim := s.out.start + s.outmaxbuf - s.out.end - 1; lim > 0 {
// If s.out has space allocated and available to be written into,
// then reference it in s.outbuf for fast-path writes.
//
// It's perhaps a bit pointless to limit s.outbuf to the send buffer limit.
// We've already allocated this buffer so we aren't saving any memory
// by not using it.
// For now, we limit it anyway to make it easier to reason about limits.
//
// We set the limit to one less than the send buffer limit (the -1 above)
// so that a write which completely fills the buffer will overflow
// s.outbuf and trigger a flush.
s.outbuf = s.out.availableBuffer()
if int64(len(s.outbuf)) > lim {
s.outbuf = s.outbuf[:lim]
}
}
s.outUnlock()
return n, nil
}
// WriteByte writes a single byte to the stream.
func (s *Stream) WriteByte(c byte) error {
if s.outbufoff < len(s.outbuf) {
s.outbuf[s.outbufoff] = c
s.outbufoff++
return nil
}
b := [1]byte{c}
_, err := s.Write(b[:])
return err
}
func (s *Stream) flushFastOutputBuffer() {
if s.outbuf == nil {
return
}
// Commit data previously written to s.outbuf.
// s.outbuf is a reference to a buffer in s.out, so we just need to record
// that the output buffer has been extended.
s.out.end += int64(s.outbufoff)
s.outbuf = nil
s.outbufoff = 0
}
// Flush flushes data written to the stream.
// It does not wait for the peer to acknowledge receipt of the data.
// Use Close to wait for the peer's acknowledgement.
func (s *Stream) Flush() error {
if s.IsReadOnly() {
return errors.New("flush of read-only stream")
}
s.outgate.lock()
defer s.outUnlock()
if err := s.writeErrorLocked(); err != nil {
return err
}
s.flushLocked()
return nil
}
// writeErrorLocked returns the error (if any) which should be returned by write operations
// due to the stream being reset or closed.
func (s *Stream) writeErrorLocked() error {
if s.outreset.isSet() {
if s.outresetcode == streamResetByConnClose {
if err := s.conn.finalError(); err != nil {
return err
}
}
return errors.New("write to reset stream")
}
if s.outclosed.isSet() {
return errors.New("write to closed stream")
}
return nil
}
func (s *Stream) flushLocked() {
s.flushFastOutputBuffer()
s.outopened.set()
if s.outflushed < s.outwin {
s.outunsent.add(s.outflushed, min(s.outwin, s.out.end))
}
s.outflushed = s.out.end
}
// Close closes the stream.
// Any blocked stream operations will be unblocked and return errors.
//
// Close flushes any data in the stream write buffer and waits for the peer to
// acknowledge receipt of the data.
// If the stream has been reset, it waits for the peer to acknowledge the reset.
// If the context expires before the peer receives the stream's data,
// Close discards the buffer and returns the context error.
func (s *Stream) Close() error {
s.CloseRead()
if s.IsReadOnly() {
return nil
}
s.CloseWrite()
// TODO: Return code from peer's RESET_STREAM frame?
if err := s.conn.waitOnDone(s.outctx, s.outdone); err != nil {
return err
}
s.outgate.lock()
defer s.outUnlock()
if s.outclosed.isReceived() && s.outacked.isrange(0, s.out.end) {
return nil
}
return errors.New("stream reset")
}
// CloseRead aborts reads on the stream.
// Any blocked reads will be unblocked and return errors.
//
// CloseRead notifies the peer that the stream has been closed for reading.
// It does not wait for the peer to acknowledge the closure.
// Use Close to wait for the peer's acknowledgement.
func (s *Stream) CloseRead() {
if s.IsWriteOnly() {
return
}
s.ingate.lock()
if s.inset.isrange(0, s.insize) || s.inresetcode != -1 {
// We've already received all data from the peer,
// so there's no need to send STOP_SENDING.
// This is the same as saying we sent one and they got it.
s.inclosed.setReceived()
} else {
s.inclosed.set()
}
discarded := s.in.end - s.in.start
s.in.discardBefore(s.in.end)
s.inUnlock()
s.conn.handleStreamBytesReadOffLoop(discarded) // must be done with ingate unlocked
}
// CloseWrite aborts writes on the stream.
// Any blocked writes will be unblocked and return errors.
//
// CloseWrite sends any data in the stream write buffer to the peer.
// It does not wait for the peer to acknowledge receipt of the data.
// Use Close to wait for the peer's acknowledgement.
func (s *Stream) CloseWrite() {
if s.IsReadOnly() {
return
}
s.outgate.lock()
defer s.outUnlock()
s.outclosed.set()
s.flushLocked()
}
// Reset aborts writes on the stream and notifies the peer
// that the stream was terminated abruptly.
// Any blocked writes will be unblocked and return errors.
//
// Reset sends the application protocol error code, which must be
// less than 2^62, to the peer.
// It does not wait for the peer to acknowledge receipt of the error.
// Use Close to wait for the peer's acknowledgement.
//
// Reset does not affect reads.
// Use CloseRead to abort reads on the stream.
func (s *Stream) Reset(code uint64) {
const userClosed = true
s.resetInternal(code, userClosed)
}
// resetInternal resets the send side of the stream.
//
// If userClosed is true, this is s.Reset.
// If userClosed is false, this is a reaction to a STOP_SENDING frame.
func (s *Stream) resetInternal(code uint64, userClosed bool) {
s.outgate.lock()
defer s.outUnlock()
if s.IsReadOnly() {
return
}
if userClosed {
// Mark that the user closed the stream.
s.outclosed.set()
}
if s.outreset.isSet() {
return
}
if code > quicwire.MaxVarint {
code = quicwire.MaxVarint
}
// We could check here to see if the stream is closed and the
// peer has acked all the data and the FIN, but sending an
// extra RESET_STREAM in this case is harmless.
s.outreset.set()
s.outresetcode = code
s.outbuf = nil
s.outbufoff = 0
s.out.discardBefore(s.out.end)
s.outunsent = rangeset[int64]{}
s.outblocked.clear()
}
// connHasClosed indicates the stream's conn has closed.
func (s *Stream) connHasClosed() {
// If we're in the closing state, the user closed the conn.
// Otherwise, we the peer initiated the close.
// This only matters for the error we're going to return from stream operations.
localClose := s.conn.lifetime.state == connStateClosing
s.ingate.lock()
if !s.inset.isrange(0, s.insize) && s.inresetcode == -1 {
if localClose {
s.inclosed.set()
} else {
s.inresetcode = streamResetByConnClose
}
}
s.inUnlock()
s.outgate.lock()
if localClose {
s.outclosed.set()
s.outreset.set()
} else {
s.outresetcode = streamResetByConnClose
s.outreset.setReceived()
}
s.outUnlock()
}
// inUnlock unlocks s.ingate.
// It sets the gate condition if reads from s will not block.
// If s has receive-related frames to write or if both directions
// are done and the stream should be removed, it notifies the Conn.
func (s *Stream) inUnlock() {
state := s.inUnlockNoQueue()
s.conn.maybeQueueStreamForSend(s, state)
}
// inUnlockNoQueue is inUnlock,
// but reports whether s has frames to write rather than notifying the Conn.
func (s *Stream) inUnlockNoQueue() streamState {
nextByte := s.in.start + int64(len(s.inbuf))
canRead := s.inset.contains(nextByte) || // data available to read
s.insize == s.in.start+int64(len(s.inbuf)) || // at EOF
s.inresetcode != -1 || // reset by peer
s.inclosed.isSet() // closed locally
defer s.ingate.unlock(canRead)
var state streamState
switch {
case s.IsWriteOnly():
state = streamInDone
case s.inresetcode != -1: // reset by peer
fallthrough
case s.in.start == s.insize: // all data received and read
// We don't increase MAX_STREAMS until the user calls ReadClose or Close,
// so the receive side is not finished until inclosed is set.
if s.inclosed.isSet() {
state = streamInDone
}
case s.insendmax.shouldSend(): // STREAM_MAX_DATA
state = streamInSendMeta
case s.inclosed.shouldSend(): // STOP_SENDING
state = streamInSendMeta
}
const mask = streamInDone | streamInSendMeta
return s.state.set(state, mask)
}
// outUnlock unlocks s.outgate.
// It sets the gate condition if writes to s will not block.
// If s has send-related frames to write or if both directions
// are done and the stream should be removed, it notifies the Conn.
func (s *Stream) outUnlock() {
state := s.outUnlockNoQueue()
s.conn.maybeQueueStreamForSend(s, state)
}
// outUnlockNoQueue is outUnlock,
// but reports whether s has frames to write rather than notifying the Conn.
func (s *Stream) outUnlockNoQueue() streamState {
isDone := s.outclosed.isReceived() && s.outacked.isrange(0, s.out.end) || // all data acked
s.outreset.isSet() // reset locally
if isDone {
select {
case <-s.outdone:
default:
if !s.IsReadOnly() {
close(s.outdone)
}
}
}
lim := s.out.start + s.outmaxbuf
canWrite := lim > s.out.end || // available send buffer
s.outclosed.isSet() || // closed locally
s.outreset.isSet() // reset locally
defer s.outgate.unlock(canWrite)
var state streamState
switch {
case s.IsReadOnly():
state = streamOutDone
case s.outclosed.isReceived() && s.outacked.isrange(0, s.out.end): // all data sent and acked
fallthrough
case s.outreset.isReceived(): // RESET_STREAM sent and acked
// We don't increase MAX_STREAMS until the user calls WriteClose or Close,
// so the send side is not finished until outclosed is set.
if s.outclosed.isSet() {
state = streamOutDone
}
case s.outreset.shouldSend(): // RESET_STREAM
state = streamOutSendMeta
case s.outreset.isSet(): // RESET_STREAM sent but not acknowledged
case s.outblocked.shouldSend(): // STREAM_DATA_BLOCKED
state = streamOutSendMeta
case len(s.outunsent) > 0: // STREAM frame with data
if s.outunsent.min() < s.outmaxsent {
state = streamOutSendMeta // resent data, will not consume flow control
} else {
state = streamOutSendData // new data, requires flow control
}
case s.outclosed.shouldSend() && s.out.end == s.outmaxsent: // empty STREAM frame with FIN bit
state = streamOutSendMeta
case s.outopened.shouldSend(): // STREAM frame with no data
state = streamOutSendMeta
}
const mask = streamOutDone | streamOutSendMeta | streamOutSendData
return s.state.set(state, mask)
}
// handleData handles data received in a STREAM frame.
func (s *Stream) handleData(off int64, b []byte, fin bool) error {
s.ingate.lock()
defer s.inUnlock()
end := off + int64(len(b))
if err := s.checkStreamBounds(end, fin); err != nil {
return err
}
if s.inclosed.isSet() || s.inresetcode != -1 {
// The user read-closed the stream, or the peer reset it.
// Either way, we can discard this frame.
return nil
}
if s.insize == -1 && end > s.in.end {
added := end - s.in.end
if err := s.conn.handleStreamBytesReceived(added); err != nil {
return err
}
}
s.in.writeAt(b, off)
s.inset.add(off, end)
if fin {
s.insize = end
// The peer has enough flow control window to send the entire stream.
s.insendmax.clear()
}
return nil
}
// handleReset handles a RESET_STREAM frame.
func (s *Stream) handleReset(code uint64, finalSize int64) error {
s.ingate.lock()
defer s.inUnlock()
const fin = true
if err := s.checkStreamBounds(finalSize, fin); err != nil {
return err
}
if s.inresetcode != -1 {
// The stream was already reset.
return nil
}
if s.insize == -1 {
added := finalSize - s.in.end
if err := s.conn.handleStreamBytesReceived(added); err != nil {
return err
}
}
s.conn.handleStreamBytesReadOnLoop(finalSize - s.in.start)
s.in.discardBefore(s.in.end)
s.inresetcode = int64(code)
s.insize = finalSize
return nil
}
// checkStreamBounds validates the stream offset in a STREAM or RESET_STREAM frame.
func (s *Stream) checkStreamBounds(end int64, fin bool) error {
if end > s.inwin {
// The peer sent us data past the maximum flow control window we gave them.
return localTransportError{
code: errFlowControl,
reason: "stream flow control window exceeded",
}
}
if s.insize != -1 && end > s.insize {
// The peer sent us data past the final size of the stream they previously gave us.
return localTransportError{
code: errFinalSize,
reason: "data received past end of stream",
}
}
if fin && s.insize != -1 && end != s.insize {
// The peer changed the final size of the stream.
return localTransportError{
code: errFinalSize,
reason: "final size of stream changed",
}
}
if fin && end < s.in.end {
// The peer has previously sent us data past the final size.
return localTransportError{
code: errFinalSize,
reason: "end of stream occurs before prior data",
}
}
return nil
}
// handleStopSending handles a STOP_SENDING frame.
func (s *Stream) handleStopSending(code uint64) error {
// Peer requests that we reset this stream.
// https://www.rfc-editor.org/rfc/rfc9000#section-3.5-4
const userReset = false
s.resetInternal(code, userReset)
return nil
}
// handleMaxStreamData handles an update received in a MAX_STREAM_DATA frame.
func (s *Stream) handleMaxStreamData(maxStreamData int64) error {
s.outgate.lock()
defer s.outUnlock()
if maxStreamData <= s.outwin {
return nil
}
if s.outflushed > s.outwin {
s.outunsent.add(s.outwin, min(maxStreamData, s.outflushed))
}
s.outwin = maxStreamData
if s.out.end > s.outwin {
// We've still got more data than flow control window.
s.outblocked.setUnsent()
} else {
s.outblocked.clear()
}
return nil
}
// ackOrLoss handles the fate of stream frames other than STREAM.
func (s *Stream) ackOrLoss(pnum packetNumber, ftype byte, fate packetFate) {
// Frames which carry new information each time they are sent
// (MAX_STREAM_DATA, STREAM_DATA_BLOCKED) must only be marked
// as received if the most recent packet carrying this frame is acked.
//
// Frames which are always the same (STOP_SENDING, RESET_STREAM)
// can be marked as received if any packet carrying this frame is acked.
switch ftype {
case frameTypeResetStream:
s.outgate.lock()
s.outreset.ackOrLoss(pnum, fate)
s.outUnlock()
case frameTypeStopSending:
s.ingate.lock()
s.inclosed.ackOrLoss(pnum, fate)
s.inUnlock()
case frameTypeMaxStreamData:
s.ingate.lock()
s.insendmax.ackLatestOrLoss(pnum, fate)
s.inUnlock()
case frameTypeStreamDataBlocked:
s.outgate.lock()
s.outblocked.ackLatestOrLoss(pnum, fate)
s.outUnlock()
default:
panic("unhandled frame type")
}
}
// ackOrLossData handles the fate of a STREAM frame.
func (s *Stream) ackOrLossData(pnum packetNumber, start, end int64, fin bool, fate packetFate) {
s.outgate.lock()
defer s.outUnlock()
s.outopened.ackOrLoss(pnum, fate)
if fin {
s.outclosed.ackOrLoss(pnum, fate)
}
if s.outreset.isSet() {
// If the stream has been reset, we don't care any more.
return
}
switch fate {
case packetAcked:
s.outacked.add(start, end)
s.outunsent.sub(start, end)
// If this ack is for data at the start of the send buffer, we can now discard it.
if s.outacked.contains(s.out.start) {
s.out.discardBefore(s.outacked[0].end)
}
case packetLost:
// Mark everything lost, but not previously acked, as needing retransmission.
// We do this by adding all the lost bytes to outunsent, and then
// removing everything already acked.
s.outunsent.add(start, end)
for _, a := range s.outacked {
s.outunsent.sub(a.start, a.end)
}
}
}
// appendInFramesLocked appends STOP_SENDING and MAX_STREAM_DATA frames
// to the current packet.
//
// It returns true if no more frames need appending,
// false if not everything fit in the current packet.
func (s *Stream) appendInFramesLocked(w *packetWriter, pnum packetNumber, pto bool) bool {
if s.inclosed.shouldSendPTO(pto) {
// We don't currently have an API for setting the error code.
// Just send zero.
code := uint64(0)
if !w.appendStopSendingFrame(s.id, code) {
return false
}
s.inclosed.setSent(pnum)
}
// TODO: STOP_SENDING
if s.insendmax.shouldSendPTO(pto) {
// MAX_STREAM_DATA
maxStreamData := s.in.start + s.inmaxbuf
if !w.appendMaxStreamDataFrame(s.id, maxStreamData) {
return false
}
s.inwin = maxStreamData
s.insendmax.setSent(pnum)
}
return true
}
// appendOutFramesLocked appends RESET_STREAM, STREAM_DATA_BLOCKED, and STREAM frames
// to the current packet.
//
// It returns true if no more frames need appending,
// false if not everything fit in the current packet.
func (s *Stream) appendOutFramesLocked(w *packetWriter, pnum packetNumber, pto bool) bool {
if s.outreset.isSet() {
// RESET_STREAM
if s.outreset.shouldSendPTO(pto) {
if !w.appendResetStreamFrame(s.id, s.outresetcode, min(s.outwin, s.out.end)) {
return false
}
s.outreset.setSent(pnum)
s.frameOpensStream(pnum)
}
return true
}
if s.outblocked.shouldSendPTO(pto) {
// STREAM_DATA_BLOCKED
if !w.appendStreamDataBlockedFrame(s.id, s.outwin) {
return false
}
s.outblocked.setSent(pnum)
s.frameOpensStream(pnum)
}
for {
// STREAM
off, size := dataToSend(min(s.out.start, s.outwin), min(s.outflushed, s.outwin), s.outunsent, s.outacked, pto)
if end := off + size; end > s.outmaxsent {
// This will require connection-level flow control to send.
end = min(end, s.outmaxsent+s.conn.streams.outflow.avail())
end = max(end, off)
size = end - off
}
fin := s.outclosed.isSet() && off+size == s.out.end
shouldSend := size > 0 || // have data to send
s.outopened.shouldSendPTO(pto) || // should open the stream
(fin && s.outclosed.shouldSendPTO(pto)) // should close the stream
if !shouldSend {
return true
}
b, added := w.appendStreamFrame(s.id, off, int(size), fin)
if !added {
return false
}
s.out.copy(off, b)
end := off + int64(len(b))
if end > s.outmaxsent {
s.conn.streams.outflow.consume(end - s.outmaxsent)
s.outmaxsent = end
}
s.outunsent.sub(off, end)
s.frameOpensStream(pnum)
if fin {
s.outclosed.setSent(pnum)
}
if pto {
return true
}
if int64(len(b)) < size {
return false
}
}
}
// frameOpensStream records that we're sending a frame that will open the stream.
//
// If we don't have an acknowledgement from the peer for a previous frame opening the stream,
// record this packet as being the latest one to open it.
func (s *Stream) frameOpensStream(pnum packetNumber) {
if !s.outopened.isReceived() {
s.outopened.setSent(pnum)
}
}
// dataToSend returns the next range of data to send in a STREAM or CRYPTO_STREAM.
func dataToSend(start, end int64, outunsent, outacked rangeset[int64], pto bool) (sendStart, size int64) {
switch {
case pto:
// On PTO, resend unacked data that fits in the probe packet.
// For simplicity, we send the range starting at s.out.start
// (which is definitely unacked, or else we would have discarded it)
// up to the next acked byte (if any).
//
// This may miss unacked data starting after that acked byte,
// but avoids resending data the peer has acked.
for _, r := range outacked {
if r.start > start {
return start, r.start - start
}
}
return start, end - start
case outunsent.numRanges() > 0:
return outunsent.min(), outunsent[0].size()
default:
return end, 0
}
}
// Copyright 2023 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 quic
import (
"context"
)
// Limits on the number of open streams.
// Every connection has separate limits for bidirectional and unidirectional streams.
//
// Note that the MAX_STREAMS limit includes closed as well as open streams.
// Closing a stream doesn't enable an endpoint to open a new one;
// only an increase in the MAX_STREAMS limit does.
// localStreamLimits are limits on the number of open streams created by us.
type localStreamLimits struct {
gate gate
max int64 // peer-provided MAX_STREAMS
opened int64 // number of streams opened by us, -1 when conn is closed
}
func (lim *localStreamLimits) init() {
lim.gate = newGate()
}
// open creates a new local stream, blocking until MAX_STREAMS quota is available.
func (lim *localStreamLimits) open(ctx context.Context, c *Conn) (num int64, err error) {
// TODO: Send a STREAMS_BLOCKED when blocked.
if err := lim.gate.waitAndLock(ctx); err != nil {
return 0, err
}
if lim.opened < 0 {
lim.gate.unlock(true)
return 0, errConnClosed
}
num = lim.opened
lim.opened++
lim.gate.unlock(lim.opened < lim.max)
return num, nil
}
// connHasClosed indicates the connection has been closed, locally or by the peer.
func (lim *localStreamLimits) connHasClosed() {
lim.gate.lock()
lim.opened = -1
lim.gate.unlock(true)
}
// setMax sets the MAX_STREAMS provided by the peer.
func (lim *localStreamLimits) setMax(maxStreams int64) {
lim.gate.lock()
lim.max = max(lim.max, maxStreams)
lim.gate.unlock(lim.opened < lim.max)
}
// remoteStreamLimits are limits on the number of open streams created by the peer.
type remoteStreamLimits struct {
max int64 // last MAX_STREAMS sent to the peer
opened int64 // number of streams opened by the peer (including subsequently closed ones)
closed int64 // number of peer streams in the "closed" state
maxOpen int64 // how many streams we want to let the peer simultaneously open
sendMax sentVal // set when we should send MAX_STREAMS
}
func (lim *remoteStreamLimits) init(maxOpen int64) {
lim.maxOpen = maxOpen
lim.max = min(maxOpen, implicitStreamLimit) // initial limit sent in transport parameters
lim.opened = 0
}
// open handles the peer opening a new stream.
func (lim *remoteStreamLimits) open(id streamID) error {
num := id.num()
if num >= lim.max {
return localTransportError{
code: errStreamLimit,
reason: "stream limit exceeded",
}
}
if num >= lim.opened {
lim.opened = num + 1
lim.maybeUpdateMax()
}
return nil
}
// close handles the peer closing an open stream.
func (lim *remoteStreamLimits) close() {
lim.closed++
lim.maybeUpdateMax()
}
// maybeUpdateMax updates the MAX_STREAMS value we will send to the peer.
func (lim *remoteStreamLimits) maybeUpdateMax() {
newMax := min(
// Max streams the peer can have open at once.
lim.closed+lim.maxOpen,
// Max streams the peer can open with a single frame.
lim.opened+implicitStreamLimit,
)
avail := lim.max - lim.opened
if newMax > lim.max && (avail < 8 || newMax-lim.max >= 2*avail) {
// If the peer has less than 8 streams, or if increasing the peer's
// stream limit would double it, then send a MAX_STREAMS.
lim.max = newMax
lim.sendMax.setUnsent()
}
}
// appendFrame appends a MAX_STREAMS frame to the current packet, if necessary.
//
// It returns true if no more frames need appending,
// false if not everything fit in the current packet.
func (lim *remoteStreamLimits) appendFrame(w *packetWriter, typ streamType, pnum packetNumber, pto bool) bool {
if lim.sendMax.shouldSendPTO(pto) {
if !w.appendMaxStreamsFrame(typ, lim.max) {
return false
}
lim.sendMax.setSent(pnum)
}
return true
}
// Copyright 2023 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 quic
import (
"context"
"crypto/tls"
"errors"
"fmt"
"net"
"time"
)
// startTLS starts the TLS handshake.
func (c *Conn) startTLS(now time.Time, initialConnID []byte, peerHostname string, params transportParameters) error {
tlsConfig := c.config.TLSConfig
if a, _, err := net.SplitHostPort(peerHostname); err == nil {
peerHostname = a
}
if tlsConfig.ServerName == "" && peerHostname != "" {
tlsConfig = tlsConfig.Clone()
tlsConfig.ServerName = peerHostname
}
c.keysInitial = initialKeys(initialConnID, c.side)
qconfig := &tls.QUICConfig{TLSConfig: tlsConfig}
if c.side == clientSide {
c.tls = tls.QUICClient(qconfig)
} else {
c.tls = tls.QUICServer(qconfig)
}
c.tls.SetTransportParameters(marshalTransportParameters(params))
// TODO: We don't need or want a context for cancellation here,
// but users can use a context to plumb values through to hooks defined
// in the tls.Config. Pass through a context.
if err := c.tls.Start(context.TODO()); err != nil {
return err
}
return c.handleTLSEvents(now)
}
func (c *Conn) handleTLSEvents(now time.Time) error {
for {
e := c.tls.NextEvent()
if c.testHooks != nil {
c.testHooks.handleTLSEvent(e)
}
switch e.Kind {
case tls.QUICNoEvent:
return nil
case tls.QUICSetReadSecret:
if err := checkCipherSuite(e.Suite); err != nil {
return err
}
switch e.Level {
case tls.QUICEncryptionLevelHandshake:
c.keysHandshake.r.init(e.Suite, e.Data)
case tls.QUICEncryptionLevelApplication:
c.keysAppData.r.init(e.Suite, e.Data)
}
case tls.QUICSetWriteSecret:
if err := checkCipherSuite(e.Suite); err != nil {
return err
}
switch e.Level {
case tls.QUICEncryptionLevelHandshake:
c.keysHandshake.w.init(e.Suite, e.Data)
case tls.QUICEncryptionLevelApplication:
c.keysAppData.w.init(e.Suite, e.Data)
}
case tls.QUICWriteData:
var space numberSpace
switch e.Level {
case tls.QUICEncryptionLevelInitial:
space = initialSpace
case tls.QUICEncryptionLevelHandshake:
space = handshakeSpace
case tls.QUICEncryptionLevelApplication:
space = appDataSpace
default:
return fmt.Errorf("quic: internal error: write handshake data at level %v", e.Level)
}
c.crypto[space].write(e.Data)
case tls.QUICHandshakeDone:
if c.side == serverSide {
// "[...] the TLS handshake is considered confirmed
// at the server when the handshake completes."
// https://www.rfc-editor.org/rfc/rfc9001#section-4.1.2-1
c.confirmHandshake(now)
}
c.handshakeDone()
case tls.QUICTransportParameters:
params, err := unmarshalTransportParams(e.Data)
if err != nil {
return err
}
if err := c.receiveTransportParameters(params); err != nil {
return err
}
}
}
}
// handleCrypto processes data received in a CRYPTO frame.
func (c *Conn) handleCrypto(now time.Time, space numberSpace, off int64, data []byte) error {
var level tls.QUICEncryptionLevel
switch space {
case initialSpace:
level = tls.QUICEncryptionLevelInitial
case handshakeSpace:
level = tls.QUICEncryptionLevelHandshake
case appDataSpace:
level = tls.QUICEncryptionLevelApplication
default:
return errors.New("quic: internal error: received CRYPTO frame in unexpected number space")
}
return c.crypto[space].handleCrypto(off, data, func(b []byte) error {
return c.tls.HandleData(level, b)
})
}
// Copyright 2023 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 quic
import (
"encoding/binary"
"net/netip"
"time"
"golang.org/x/net/internal/quic/quicwire"
)
// transportParameters transferred in the quic_transport_parameters TLS extension.
// https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2
type transportParameters struct {
originalDstConnID []byte
maxIdleTimeout time.Duration
statelessResetToken []byte
maxUDPPayloadSize int64
initialMaxData int64
initialMaxStreamDataBidiLocal int64
initialMaxStreamDataBidiRemote int64
initialMaxStreamDataUni int64
initialMaxStreamsBidi int64
initialMaxStreamsUni int64
ackDelayExponent int8
maxAckDelay time.Duration
disableActiveMigration bool
preferredAddrV4 netip.AddrPort
preferredAddrV6 netip.AddrPort
preferredAddrConnID []byte
preferredAddrResetToken []byte
activeConnIDLimit int64
initialSrcConnID []byte
retrySrcConnID []byte
}
const (
defaultParamMaxUDPPayloadSize = 65527
defaultParamAckDelayExponent = 3
defaultParamMaxAckDelayMilliseconds = 25
defaultParamActiveConnIDLimit = 2
)
// defaultTransportParameters is initialized to the RFC 9000 default values.
func defaultTransportParameters() transportParameters {
return transportParameters{
maxUDPPayloadSize: defaultParamMaxUDPPayloadSize,
ackDelayExponent: defaultParamAckDelayExponent,
maxAckDelay: defaultParamMaxAckDelayMilliseconds * time.Millisecond,
activeConnIDLimit: defaultParamActiveConnIDLimit,
}
}
const (
paramOriginalDestinationConnectionID = 0x00
paramMaxIdleTimeout = 0x01
paramStatelessResetToken = 0x02
paramMaxUDPPayloadSize = 0x03
paramInitialMaxData = 0x04
paramInitialMaxStreamDataBidiLocal = 0x05
paramInitialMaxStreamDataBidiRemote = 0x06
paramInitialMaxStreamDataUni = 0x07
paramInitialMaxStreamsBidi = 0x08
paramInitialMaxStreamsUni = 0x09
paramAckDelayExponent = 0x0a
paramMaxAckDelay = 0x0b
paramDisableActiveMigration = 0x0c
paramPreferredAddress = 0x0d
paramActiveConnectionIDLimit = 0x0e
paramInitialSourceConnectionID = 0x0f
paramRetrySourceConnectionID = 0x10
)
func marshalTransportParameters(p transportParameters) []byte {
var b []byte
if v := p.originalDstConnID; v != nil {
b = quicwire.AppendVarint(b, paramOriginalDestinationConnectionID)
b = quicwire.AppendVarintBytes(b, v)
}
if v := uint64(p.maxIdleTimeout / time.Millisecond); v != 0 {
b = quicwire.AppendVarint(b, paramMaxIdleTimeout)
b = quicwire.AppendVarint(b, uint64(quicwire.SizeVarint(v)))
b = quicwire.AppendVarint(b, uint64(v))
}
if v := p.statelessResetToken; v != nil {
b = quicwire.AppendVarint(b, paramStatelessResetToken)
b = quicwire.AppendVarintBytes(b, v)
}
if v := p.maxUDPPayloadSize; v != defaultParamMaxUDPPayloadSize {
b = quicwire.AppendVarint(b, paramMaxUDPPayloadSize)
b = quicwire.AppendVarint(b, uint64(quicwire.SizeVarint(uint64(v))))
b = quicwire.AppendVarint(b, uint64(v))
}
if v := p.initialMaxData; v != 0 {
b = quicwire.AppendVarint(b, paramInitialMaxData)
b = quicwire.AppendVarint(b, uint64(quicwire.SizeVarint(uint64(v))))
b = quicwire.AppendVarint(b, uint64(v))
}
if v := p.initialMaxStreamDataBidiLocal; v != 0 {
b = quicwire.AppendVarint(b, paramInitialMaxStreamDataBidiLocal)
b = quicwire.AppendVarint(b, uint64(quicwire.SizeVarint(uint64(v))))
b = quicwire.AppendVarint(b, uint64(v))
}
if v := p.initialMaxStreamDataBidiRemote; v != 0 {
b = quicwire.AppendVarint(b, paramInitialMaxStreamDataBidiRemote)
b = quicwire.AppendVarint(b, uint64(quicwire.SizeVarint(uint64(v))))
b = quicwire.AppendVarint(b, uint64(v))
}
if v := p.initialMaxStreamDataUni; v != 0 {
b = quicwire.AppendVarint(b, paramInitialMaxStreamDataUni)
b = quicwire.AppendVarint(b, uint64(quicwire.SizeVarint(uint64(v))))
b = quicwire.AppendVarint(b, uint64(v))
}
if v := p.initialMaxStreamsBidi; v != 0 {
b = quicwire.AppendVarint(b, paramInitialMaxStreamsBidi)
b = quicwire.AppendVarint(b, uint64(quicwire.SizeVarint(uint64(v))))
b = quicwire.AppendVarint(b, uint64(v))
}
if v := p.initialMaxStreamsUni; v != 0 {
b = quicwire.AppendVarint(b, paramInitialMaxStreamsUni)
b = quicwire.AppendVarint(b, uint64(quicwire.SizeVarint(uint64(v))))
b = quicwire.AppendVarint(b, uint64(v))
}
if v := p.ackDelayExponent; v != defaultParamAckDelayExponent {
b = quicwire.AppendVarint(b, paramAckDelayExponent)
b = quicwire.AppendVarint(b, uint64(quicwire.SizeVarint(uint64(v))))
b = quicwire.AppendVarint(b, uint64(v))
}
if v := uint64(p.maxAckDelay / time.Millisecond); v != defaultParamMaxAckDelayMilliseconds {
b = quicwire.AppendVarint(b, paramMaxAckDelay)
b = quicwire.AppendVarint(b, uint64(quicwire.SizeVarint(v)))
b = quicwire.AppendVarint(b, v)
}
if p.disableActiveMigration {
b = quicwire.AppendVarint(b, paramDisableActiveMigration)
b = append(b, 0) // 0-length value
}
if p.preferredAddrConnID != nil {
b = append(b, paramPreferredAddress)
b = quicwire.AppendVarint(b, uint64(4+2+16+2+1+len(p.preferredAddrConnID)+16))
b = append(b, p.preferredAddrV4.Addr().AsSlice()...) // 4 bytes
b = binary.BigEndian.AppendUint16(b, p.preferredAddrV4.Port()) // 2 bytes
b = append(b, p.preferredAddrV6.Addr().AsSlice()...) // 16 bytes
b = binary.BigEndian.AppendUint16(b, p.preferredAddrV6.Port()) // 2 bytes
b = quicwire.AppendUint8Bytes(b, p.preferredAddrConnID) // 1 byte + len(conn_id)
b = append(b, p.preferredAddrResetToken...) // 16 bytes
}
if v := p.activeConnIDLimit; v != defaultParamActiveConnIDLimit {
b = quicwire.AppendVarint(b, paramActiveConnectionIDLimit)
b = quicwire.AppendVarint(b, uint64(quicwire.SizeVarint(uint64(v))))
b = quicwire.AppendVarint(b, uint64(v))
}
if v := p.initialSrcConnID; v != nil {
b = quicwire.AppendVarint(b, paramInitialSourceConnectionID)
b = quicwire.AppendVarintBytes(b, v)
}
if v := p.retrySrcConnID; v != nil {
b = quicwire.AppendVarint(b, paramRetrySourceConnectionID)
b = quicwire.AppendVarintBytes(b, v)
}
return b
}
func unmarshalTransportParams(params []byte) (transportParameters, error) {
p := defaultTransportParameters()
for len(params) > 0 {
id, n := quicwire.ConsumeVarint(params)
if n < 0 {
return p, localTransportError{code: errTransportParameter}
}
params = params[n:]
val, n := quicwire.ConsumeVarintBytes(params)
if n < 0 {
return p, localTransportError{code: errTransportParameter}
}
params = params[n:]
n = 0
switch id {
case paramOriginalDestinationConnectionID:
p.originalDstConnID = val
n = len(val)
case paramMaxIdleTimeout:
var v uint64
v, n = quicwire.ConsumeVarint(val)
// If this is unreasonably large, consider it as no timeout to avoid
// time.Duration overflows.
if v > 1<<32 {
v = 0
}
p.maxIdleTimeout = time.Duration(v) * time.Millisecond
case paramStatelessResetToken:
if len(val) != 16 {
return p, localTransportError{code: errTransportParameter}
}
p.statelessResetToken = val
n = 16
case paramMaxUDPPayloadSize:
p.maxUDPPayloadSize, n = quicwire.ConsumeVarintInt64(val)
if p.maxUDPPayloadSize < 1200 {
return p, localTransportError{code: errTransportParameter}
}
case paramInitialMaxData:
p.initialMaxData, n = quicwire.ConsumeVarintInt64(val)
case paramInitialMaxStreamDataBidiLocal:
p.initialMaxStreamDataBidiLocal, n = quicwire.ConsumeVarintInt64(val)
case paramInitialMaxStreamDataBidiRemote:
p.initialMaxStreamDataBidiRemote, n = quicwire.ConsumeVarintInt64(val)
case paramInitialMaxStreamDataUni:
p.initialMaxStreamDataUni, n = quicwire.ConsumeVarintInt64(val)
case paramInitialMaxStreamsBidi:
p.initialMaxStreamsBidi, n = quicwire.ConsumeVarintInt64(val)
if p.initialMaxStreamsBidi > maxStreamsLimit {
return p, localTransportError{code: errTransportParameter}
}
case paramInitialMaxStreamsUni:
p.initialMaxStreamsUni, n = quicwire.ConsumeVarintInt64(val)
if p.initialMaxStreamsUni > maxStreamsLimit {
return p, localTransportError{code: errTransportParameter}
}
case paramAckDelayExponent:
var v uint64
v, n = quicwire.ConsumeVarint(val)
if v > 20 {
return p, localTransportError{code: errTransportParameter}
}
p.ackDelayExponent = int8(v)
case paramMaxAckDelay:
var v uint64
v, n = quicwire.ConsumeVarint(val)
if v >= 1<<14 {
return p, localTransportError{code: errTransportParameter}
}
p.maxAckDelay = time.Duration(v) * time.Millisecond
case paramDisableActiveMigration:
p.disableActiveMigration = true
case paramPreferredAddress:
if len(val) < 4+2+16+2+1 {
return p, localTransportError{code: errTransportParameter}
}
p.preferredAddrV4 = netip.AddrPortFrom(
netip.AddrFrom4(*(*[4]byte)(val[:4])),
binary.BigEndian.Uint16(val[4:][:2]),
)
val = val[4+2:]
p.preferredAddrV6 = netip.AddrPortFrom(
netip.AddrFrom16(*(*[16]byte)(val[:16])),
binary.BigEndian.Uint16(val[16:][:2]),
)
val = val[16+2:]
var nn int
p.preferredAddrConnID, nn = quicwire.ConsumeUint8Bytes(val)
if nn < 0 {
return p, localTransportError{code: errTransportParameter}
}
val = val[nn:]
if len(val) != 16 {
return p, localTransportError{code: errTransportParameter}
}
p.preferredAddrResetToken = val
val = nil
case paramActiveConnectionIDLimit:
p.activeConnIDLimit, n = quicwire.ConsumeVarintInt64(val)
if p.activeConnIDLimit < 2 {
return p, localTransportError{code: errTransportParameter}
}
case paramInitialSourceConnectionID:
p.initialSrcConnID = val
n = len(val)
case paramRetrySourceConnectionID:
p.retrySrcConnID = val
n = len(val)
default:
n = len(val)
}
if n != len(val) {
return p, localTransportError{code: errTransportParameter}
}
}
return p, nil
}
// Copyright 2023 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 quic
import "net/netip"
// Per-plaform consts describing support for various features.
//
// const udpECNSupport indicates whether the platform supports setting
// the ECN (Explicit Congestion Notification) IP header bits.
//
// const udpInvalidLocalAddrIsError indicates whether sending a packet
// from an local address not associated with the system is an error.
// For example, assuming 127.0.0.2 is not a local address, does sending
// from it (using IP_PKTINFO or some other such feature) result in an error?
// unmapAddrPort returns a with any IPv4-mapped IPv6 address prefix removed.
func unmapAddrPort(a netip.AddrPort) netip.AddrPort {
if a.Addr().Is4In6() {
return netip.AddrPortFrom(
a.Addr().Unmap(),
a.Port(),
)
}
return a
}
// Copyright 2023 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.
//go:build linux
package quic
import (
"golang.org/x/sys/unix"
)
// See udp.go.
const (
udpECNSupport = true
udpInvalidLocalAddrIsError = false
)
// The IP_TOS socket option is a single byte containing the IP TOS field.
// The low two bits are the ECN field.
func parseIPTOS(b []byte) (ecnBits, bool) {
if len(b) != 1 {
return 0, false
}
return ecnBits(b[0] & ecnMask), true
}
func appendCmsgECNv4(b []byte, ecn ecnBits) []byte {
b, data := appendCmsg(b, unix.IPPROTO_IP, unix.IP_TOS, 1)
data[0] = byte(ecn)
return b
}
// Copyright 2023 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.
//go:build !quicbasicnet && (darwin || linux)
package quic
import (
"encoding/binary"
"net"
"net/netip"
"sync"
"unsafe"
"golang.org/x/sys/unix"
)
// Network interface for platforms using sendmsg/recvmsg with cmsgs.
type netUDPConn struct {
c *net.UDPConn
localAddr netip.AddrPort
}
func newNetUDPConn(uc *net.UDPConn) (*netUDPConn, error) {
a, _ := uc.LocalAddr().(*net.UDPAddr)
localAddr := a.AddrPort()
if localAddr.Addr().IsUnspecified() {
// If the conn is not bound to a specified (non-wildcard) address,
// then set localAddr.Addr to an invalid netip.Addr.
// This better conveys that this is not an address we should be using,
// and is a bit more efficient to test against.
localAddr = netip.AddrPortFrom(netip.Addr{}, localAddr.Port())
}
sc, err := uc.SyscallConn()
if err != nil {
return nil, err
}
sc.Control(func(fd uintptr) {
// Ask for ECN info and (when we aren't bound to a fixed local address)
// destination info.
//
// If any of these calls fail, we won't get the requested information.
// That's fine, we'll gracefully handle the lack.
unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_RECVTOS, 1)
unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_RECVTCLASS, 1)
if !localAddr.IsValid() {
unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_PKTINFO, 1)
unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_RECVPKTINFO, 1)
}
})
return &netUDPConn{
c: uc,
localAddr: localAddr,
}, nil
}
func (c *netUDPConn) Close() error { return c.c.Close() }
func (c *netUDPConn) LocalAddr() netip.AddrPort {
a, _ := c.c.LocalAddr().(*net.UDPAddr)
return a.AddrPort()
}
func (c *netUDPConn) Read(f func(*datagram)) {
// We shouldn't ever see all of these messages at the same time,
// but the total is small so just allocate enough space for everything we use.
const (
inPktinfoSize = 12 // int + in_addr + in_addr
in6PktinfoSize = 20 // in6_addr + int
ipTOSSize = 4
ipv6TclassSize = 4
)
control := make([]byte, 0+
unix.CmsgSpace(inPktinfoSize)+
unix.CmsgSpace(in6PktinfoSize)+
unix.CmsgSpace(ipTOSSize)+
unix.CmsgSpace(ipv6TclassSize))
for {
d := newDatagram()
n, controlLen, _, peerAddr, err := c.c.ReadMsgUDPAddrPort(d.b, control)
if err != nil {
return
}
if n == 0 {
continue
}
d.localAddr = c.localAddr
d.peerAddr = unmapAddrPort(peerAddr)
d.b = d.b[:n]
parseControl(d, control[:controlLen])
f(d)
}
}
var cmsgPool = sync.Pool{
New: func() any {
return new([]byte)
},
}
func (c *netUDPConn) Write(dgram datagram) error {
controlp := cmsgPool.Get().(*[]byte)
control := *controlp
defer func() {
*controlp = control[:0]
cmsgPool.Put(controlp)
}()
localIP := dgram.localAddr.Addr()
if localIP.IsValid() {
if localIP.Is4() {
control = appendCmsgIPSourceAddrV4(control, localIP)
} else {
control = appendCmsgIPSourceAddrV6(control, localIP)
}
}
if dgram.ecn != ecnNotECT {
if dgram.peerAddr.Addr().Is4() {
control = appendCmsgECNv4(control, dgram.ecn)
} else {
control = appendCmsgECNv6(control, dgram.ecn)
}
}
_, _, err := c.c.WriteMsgUDPAddrPort(dgram.b, control, dgram.peerAddr)
return err
}
func parseControl(d *datagram, control []byte) {
for len(control) > 0 {
hdr, data, remainder, err := unix.ParseOneSocketControlMessage(control)
if err != nil {
return
}
control = remainder
switch hdr.Level {
case unix.IPPROTO_IP:
switch hdr.Type {
case unix.IP_TOS, unix.IP_RECVTOS:
// (Linux sets the type to IP_TOS, Darwin to IP_RECVTOS,
// just check for both.)
if ecn, ok := parseIPTOS(data); ok {
d.ecn = ecn
}
case unix.IP_PKTINFO:
if a, ok := parseInPktinfo(data); ok {
d.localAddr = netip.AddrPortFrom(a, d.localAddr.Port())
}
}
case unix.IPPROTO_IPV6:
switch hdr.Type {
case unix.IPV6_TCLASS:
// 32-bit integer containing the traffic class field.
// The low two bits are the ECN field.
if ecn, ok := parseIPv6TCLASS(data); ok {
d.ecn = ecn
}
case unix.IPV6_PKTINFO:
if a, ok := parseIn6Pktinfo(data); ok {
d.localAddr = netip.AddrPortFrom(a, d.localAddr.Port())
}
}
}
}
}
// IPV6_TCLASS is specified by RFC 3542 as an int.
func parseIPv6TCLASS(b []byte) (ecnBits, bool) {
if len(b) != 4 {
return 0, false
}
return ecnBits(binary.NativeEndian.Uint32(b) & ecnMask), true
}
func appendCmsgECNv6(b []byte, ecn ecnBits) []byte {
b, data := appendCmsg(b, unix.IPPROTO_IPV6, unix.IPV6_TCLASS, 4)
binary.NativeEndian.PutUint32(data, uint32(ecn))
return b
}
// struct in_pktinfo {
// unsigned int ipi_ifindex; /* send/recv interface index */
// struct in_addr ipi_spec_dst; /* Local address */
// struct in_addr ipi_addr; /* IP Header dst address */
// };
// parseInPktinfo returns the destination address from an IP_PKTINFO.
func parseInPktinfo(b []byte) (dst netip.Addr, ok bool) {
if len(b) != 12 {
return netip.Addr{}, false
}
return netip.AddrFrom4([4]byte(b[8:][:4])), true
}
// appendCmsgIPSourceAddrV4 appends an IP_PKTINFO setting the source address
// for an outbound datagram.
func appendCmsgIPSourceAddrV4(b []byte, src netip.Addr) []byte {
// struct in_pktinfo {
// unsigned int ipi_ifindex; /* send/recv interface index */
// struct in_addr ipi_spec_dst; /* Local address */
// struct in_addr ipi_addr; /* IP Header dst address */
// };
b, data := appendCmsg(b, unix.IPPROTO_IP, unix.IP_PKTINFO, 12)
ip := src.As4()
copy(data[4:], ip[:])
return b
}
// struct in6_pktinfo {
// struct in6_addr ipi6_addr; /* src/dst IPv6 address */
// unsigned int ipi6_ifindex; /* send/recv interface index */
// };
// parseIn6Pktinfo returns the destination address from an IPV6_PKTINFO.
func parseIn6Pktinfo(b []byte) (netip.Addr, bool) {
if len(b) != 20 {
return netip.Addr{}, false
}
return netip.AddrFrom16([16]byte(b[:16])).Unmap(), true
}
// appendCmsgIPSourceAddrV6 appends an IPV6_PKTINFO setting the source address
// for an outbound datagram.
func appendCmsgIPSourceAddrV6(b []byte, src netip.Addr) []byte {
b, data := appendCmsg(b, unix.IPPROTO_IPV6, unix.IPV6_PKTINFO, 20)
ip := src.As16()
copy(data[0:], ip[:])
return b
}
// appendCmsg appends a cmsg with the given level, type, and size to b.
// It returns the new buffer, and the data section of the cmsg.
func appendCmsg(b []byte, level, typ int32, size int) (_, data []byte) {
off := len(b)
b = append(b, make([]byte, unix.CmsgSpace(size))...)
h := (*unix.Cmsghdr)(unsafe.Pointer(&b[off]))
h.Level = level
h.Type = typ
h.SetLen(unix.CmsgLen(size))
return b, b[off+unix.CmsgSpace(0):][:size]
}
// Copyright 2024 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 quic
import (
"net"
"net/netip"
)
// netPacketConn is a packetConn implementation wrapping a net.PacketConn.
//
// This is mostly useful for tests, since PacketConn doesn't provide access to
// important features such as identifying the local address packets were received on.
type netPacketConn struct {
c net.PacketConn
localAddr netip.AddrPort
}
func newNetPacketConn(pc net.PacketConn) (*netPacketConn, error) {
addr, err := addrPortFromAddr(pc.LocalAddr())
if err != nil {
return nil, err
}
return &netPacketConn{
c: pc,
localAddr: addr,
}, nil
}
func (c *netPacketConn) Close() error {
return c.c.Close()
}
func (c *netPacketConn) LocalAddr() netip.AddrPort {
return c.localAddr
}
func (c *netPacketConn) Read(f func(*datagram)) {
for {
dgram := newDatagram()
n, peerAddr, err := c.c.ReadFrom(dgram.b)
if err != nil {
return
}
dgram.peerAddr, err = addrPortFromAddr(peerAddr)
if err != nil {
continue
}
dgram.b = dgram.b[:n]
f(dgram)
}
}
func (c *netPacketConn) Write(dgram datagram) error {
_, err := c.c.WriteTo(dgram.b, net.UDPAddrFromAddrPort(dgram.peerAddr))
return err
}
func addrPortFromAddr(addr net.Addr) (netip.AddrPort, error) {
switch a := addr.(type) {
case *net.UDPAddr:
return a.AddrPort(), nil
}
return netip.ParseAddrPort(addr.String())
}
// 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 webdav
import (
"context"
"encoding/xml"
"io"
"net/http"
"os"
"path"
"path/filepath"
"runtime"
"strings"
"sync"
"time"
)
// slashClean is equivalent to but slightly more efficient than
// path.Clean("/" + name).
func slashClean(name string) string {
if name == "" || name[0] != '/' {
name = "/" + name
}
return path.Clean(name)
}
// A FileSystem implements access to a collection of named files. The elements
// in a file path are separated by slash ('/', U+002F) characters, regardless
// of host operating system convention.
//
// Each method has the same semantics as the os package's function of the same
// name.
//
// Note that the os.Rename documentation says that "OS-specific restrictions
// might apply". In particular, whether or not renaming a file or directory
// overwriting another existing file or directory is an error is OS-dependent.
type FileSystem interface {
Mkdir(ctx context.Context, name string, perm os.FileMode) error
OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (File, error)
RemoveAll(ctx context.Context, name string) error
Rename(ctx context.Context, oldName, newName string) error
Stat(ctx context.Context, name string) (os.FileInfo, error)
}
// A File is returned by a FileSystem's OpenFile method and can be served by a
// Handler.
//
// A File may optionally implement the DeadPropsHolder interface, if it can
// load and save dead properties.
type File interface {
http.File
io.Writer
}
// A Dir implements FileSystem using the native file system restricted to a
// specific directory tree.
//
// While the FileSystem.OpenFile method takes '/'-separated paths, a Dir's
// string value is a filename on the native file system, not a URL, so it is
// separated by filepath.Separator, which isn't necessarily '/'.
//
// An empty Dir is treated as ".".
type Dir string
func (d Dir) resolve(name string) string {
// This implementation is based on Dir.Open's code in the standard net/http package.
if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 ||
strings.Contains(name, "\x00") {
return ""
}
dir := string(d)
if dir == "" {
dir = "."
}
return filepath.Join(dir, filepath.FromSlash(slashClean(name)))
}
func (d Dir) Mkdir(ctx context.Context, name string, perm os.FileMode) error {
if name = d.resolve(name); name == "" {
return os.ErrNotExist
}
return os.Mkdir(name, perm)
}
func (d Dir) OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (File, error) {
if name = d.resolve(name); name == "" {
return nil, os.ErrNotExist
}
f, err := os.OpenFile(name, flag, perm)
if err != nil {
return nil, err
}
return f, nil
}
func (d Dir) RemoveAll(ctx context.Context, name string) error {
if name = d.resolve(name); name == "" {
return os.ErrNotExist
}
if name == filepath.Clean(string(d)) {
// Prohibit removing the virtual root directory.
return os.ErrInvalid
}
return os.RemoveAll(name)
}
func (d Dir) Rename(ctx context.Context, oldName, newName string) error {
if oldName = d.resolve(oldName); oldName == "" {
return os.ErrNotExist
}
if newName = d.resolve(newName); newName == "" {
return os.ErrNotExist
}
if root := filepath.Clean(string(d)); root == oldName || root == newName {
// Prohibit renaming from or to the virtual root directory.
return os.ErrInvalid
}
return os.Rename(oldName, newName)
}
func (d Dir) Stat(ctx context.Context, name string) (os.FileInfo, error) {
if name = d.resolve(name); name == "" {
return nil, os.ErrNotExist
}
return os.Stat(name)
}
// NewMemFS returns a new in-memory FileSystem implementation.
func NewMemFS() FileSystem {
return &memFS{
root: memFSNode{
children: make(map[string]*memFSNode),
mode: 0660 | os.ModeDir,
modTime: time.Now(),
},
}
}
// A memFS implements FileSystem, storing all metadata and actual file data
// in-memory. No limits on filesystem size are used, so it is not recommended
// this be used where the clients are untrusted.
//
// Concurrent access is permitted. The tree structure is protected by a mutex,
// and each node's contents and metadata are protected by a per-node mutex.
//
// TODO: Enforce file permissions.
type memFS struct {
mu sync.Mutex
root memFSNode
}
// TODO: clean up and rationalize the walk/find code.
// walk walks the directory tree for the fullname, calling f at each step. If f
// returns an error, the walk will be aborted and return that same error.
//
// dir is the directory at that step, frag is the name fragment, and final is
// whether it is the final step. For example, walking "/foo/bar/x" will result
// in 3 calls to f:
// - "/", "foo", false
// - "/foo/", "bar", false
// - "/foo/bar/", "x", true
//
// The frag argument will be empty only if dir is the root node and the walk
// ends at that root node.
func (fs *memFS) walk(op, fullname string, f func(dir *memFSNode, frag string, final bool) error) error {
original := fullname
fullname = slashClean(fullname)
// Strip any leading "/"s to make fullname a relative path, as the walk
// starts at fs.root.
if fullname[0] == '/' {
fullname = fullname[1:]
}
dir := &fs.root
for {
frag, remaining := fullname, ""
i := strings.IndexRune(fullname, '/')
final := i < 0
if !final {
frag, remaining = fullname[:i], fullname[i+1:]
}
if frag == "" && dir != &fs.root {
panic("webdav: empty path fragment for a clean path")
}
if err := f(dir, frag, final); err != nil {
return &os.PathError{
Op: op,
Path: original,
Err: err,
}
}
if final {
break
}
child := dir.children[frag]
if child == nil {
return &os.PathError{
Op: op,
Path: original,
Err: os.ErrNotExist,
}
}
if !child.mode.IsDir() {
return &os.PathError{
Op: op,
Path: original,
Err: os.ErrInvalid,
}
}
dir, fullname = child, remaining
}
return nil
}
// find returns the parent of the named node and the relative name fragment
// from the parent to the child. For example, if finding "/foo/bar/baz" then
// parent will be the node for "/foo/bar" and frag will be "baz".
//
// If the fullname names the root node, then parent, frag and err will be zero.
//
// find returns an error if the parent does not already exist or the parent
// isn't a directory, but it will not return an error per se if the child does
// not already exist. The error returned is either nil or an *os.PathError
// whose Op is op.
func (fs *memFS) find(op, fullname string) (parent *memFSNode, frag string, err error) {
err = fs.walk(op, fullname, func(parent0 *memFSNode, frag0 string, final bool) error {
if !final {
return nil
}
if frag0 != "" {
parent, frag = parent0, frag0
}
return nil
})
return parent, frag, err
}
func (fs *memFS) Mkdir(ctx context.Context, name string, perm os.FileMode) error {
fs.mu.Lock()
defer fs.mu.Unlock()
dir, frag, err := fs.find("mkdir", name)
if err != nil {
return err
}
if dir == nil {
// We can't create the root.
return os.ErrInvalid
}
if _, ok := dir.children[frag]; ok {
return os.ErrExist
}
dir.children[frag] = &memFSNode{
children: make(map[string]*memFSNode),
mode: perm.Perm() | os.ModeDir,
modTime: time.Now(),
}
return nil
}
func (fs *memFS) OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (File, error) {
fs.mu.Lock()
defer fs.mu.Unlock()
dir, frag, err := fs.find("open", name)
if err != nil {
return nil, err
}
var n *memFSNode
if dir == nil {
// We're opening the root.
if runtime.GOOS == "zos" {
if flag&os.O_WRONLY != 0 {
return nil, os.ErrPermission
}
} else {
if flag&(os.O_WRONLY|os.O_RDWR) != 0 {
return nil, os.ErrPermission
}
}
n, frag = &fs.root, "/"
} else {
n = dir.children[frag]
if flag&(os.O_SYNC|os.O_APPEND) != 0 {
// memFile doesn't support these flags yet.
return nil, os.ErrInvalid
}
if flag&os.O_CREATE != 0 {
if flag&os.O_EXCL != 0 && n != nil {
return nil, os.ErrExist
}
if n == nil {
n = &memFSNode{
mode: perm.Perm(),
}
dir.children[frag] = n
}
}
if n == nil {
return nil, os.ErrNotExist
}
if flag&(os.O_WRONLY|os.O_RDWR) != 0 && flag&os.O_TRUNC != 0 {
n.mu.Lock()
n.data = nil
n.mu.Unlock()
}
}
children := make([]os.FileInfo, 0, len(n.children))
for cName, c := range n.children {
children = append(children, c.stat(cName))
}
return &memFile{
n: n,
nameSnapshot: frag,
childrenSnapshot: children,
}, nil
}
func (fs *memFS) RemoveAll(ctx context.Context, name string) error {
fs.mu.Lock()
defer fs.mu.Unlock()
dir, frag, err := fs.find("remove", name)
if err != nil {
return err
}
if dir == nil {
// We can't remove the root.
return os.ErrInvalid
}
delete(dir.children, frag)
return nil
}
func (fs *memFS) Rename(ctx context.Context, oldName, newName string) error {
fs.mu.Lock()
defer fs.mu.Unlock()
oldName = slashClean(oldName)
newName = slashClean(newName)
if oldName == newName {
return nil
}
if strings.HasPrefix(newName, oldName+"/") {
// We can't rename oldName to be a sub-directory of itself.
return os.ErrInvalid
}
oDir, oFrag, err := fs.find("rename", oldName)
if err != nil {
return err
}
if oDir == nil {
// We can't rename from the root.
return os.ErrInvalid
}
nDir, nFrag, err := fs.find("rename", newName)
if err != nil {
return err
}
if nDir == nil {
// We can't rename to the root.
return os.ErrInvalid
}
oNode, ok := oDir.children[oFrag]
if !ok {
return os.ErrNotExist
}
if oNode.children != nil {
if nNode, ok := nDir.children[nFrag]; ok {
if nNode.children == nil {
return errNotADirectory
}
if len(nNode.children) != 0 {
return errDirectoryNotEmpty
}
}
}
delete(oDir.children, oFrag)
nDir.children[nFrag] = oNode
return nil
}
func (fs *memFS) Stat(ctx context.Context, name string) (os.FileInfo, error) {
fs.mu.Lock()
defer fs.mu.Unlock()
dir, frag, err := fs.find("stat", name)
if err != nil {
return nil, err
}
if dir == nil {
// We're stat'ting the root.
return fs.root.stat("/"), nil
}
if n, ok := dir.children[frag]; ok {
return n.stat(path.Base(name)), nil
}
return nil, os.ErrNotExist
}
// A memFSNode represents a single entry in the in-memory filesystem and also
// implements os.FileInfo.
type memFSNode struct {
// children is protected by memFS.mu.
children map[string]*memFSNode
mu sync.Mutex
data []byte
mode os.FileMode
modTime time.Time
deadProps map[xml.Name]Property
}
func (n *memFSNode) stat(name string) *memFileInfo {
n.mu.Lock()
defer n.mu.Unlock()
return &memFileInfo{
name: name,
size: int64(len(n.data)),
mode: n.mode,
modTime: n.modTime,
}
}
func (n *memFSNode) DeadProps() (map[xml.Name]Property, error) {
n.mu.Lock()
defer n.mu.Unlock()
if len(n.deadProps) == 0 {
return nil, nil
}
ret := make(map[xml.Name]Property, len(n.deadProps))
for k, v := range n.deadProps {
ret[k] = v
}
return ret, nil
}
func (n *memFSNode) Patch(patches []Proppatch) ([]Propstat, error) {
n.mu.Lock()
defer n.mu.Unlock()
pstat := Propstat{Status: http.StatusOK}
for _, patch := range patches {
for _, p := range patch.Props {
pstat.Props = append(pstat.Props, Property{XMLName: p.XMLName})
if patch.Remove {
delete(n.deadProps, p.XMLName)
continue
}
if n.deadProps == nil {
n.deadProps = map[xml.Name]Property{}
}
n.deadProps[p.XMLName] = p
}
}
return []Propstat{pstat}, nil
}
type memFileInfo struct {
name string
size int64
mode os.FileMode
modTime time.Time
}
func (f *memFileInfo) Name() string { return f.name }
func (f *memFileInfo) Size() int64 { return f.size }
func (f *memFileInfo) Mode() os.FileMode { return f.mode }
func (f *memFileInfo) ModTime() time.Time { return f.modTime }
func (f *memFileInfo) IsDir() bool { return f.mode.IsDir() }
func (f *memFileInfo) Sys() interface{} { return nil }
// A memFile is a File implementation for a memFSNode. It is a per-file (not
// per-node) read/write position, and a snapshot of the memFS' tree structure
// (a node's name and children) for that node.
type memFile struct {
n *memFSNode
nameSnapshot string
childrenSnapshot []os.FileInfo
// pos is protected by n.mu.
pos int
}
// A *memFile implements the optional DeadPropsHolder interface.
var _ DeadPropsHolder = (*memFile)(nil)
func (f *memFile) DeadProps() (map[xml.Name]Property, error) { return f.n.DeadProps() }
func (f *memFile) Patch(patches []Proppatch) ([]Propstat, error) { return f.n.Patch(patches) }
func (f *memFile) Close() error {
return nil
}
func (f *memFile) Read(p []byte) (int, error) {
f.n.mu.Lock()
defer f.n.mu.Unlock()
if f.n.mode.IsDir() {
return 0, os.ErrInvalid
}
if f.pos >= len(f.n.data) {
return 0, io.EOF
}
n := copy(p, f.n.data[f.pos:])
f.pos += n
return n, nil
}
func (f *memFile) Readdir(count int) ([]os.FileInfo, error) {
f.n.mu.Lock()
defer f.n.mu.Unlock()
if !f.n.mode.IsDir() {
return nil, os.ErrInvalid
}
old := f.pos
if old >= len(f.childrenSnapshot) {
// The os.File Readdir docs say that at the end of a directory,
// the error is io.EOF if count > 0 and nil if count <= 0.
if count > 0 {
return nil, io.EOF
}
return nil, nil
}
if count > 0 {
f.pos += count
if f.pos > len(f.childrenSnapshot) {
f.pos = len(f.childrenSnapshot)
}
} else {
f.pos = len(f.childrenSnapshot)
old = 0
}
return f.childrenSnapshot[old:f.pos], nil
}
func (f *memFile) Seek(offset int64, whence int) (int64, error) {
f.n.mu.Lock()
defer f.n.mu.Unlock()
npos := f.pos
// TODO: How to handle offsets greater than the size of system int?
switch whence {
case io.SeekStart:
npos = int(offset)
case io.SeekCurrent:
npos += int(offset)
case io.SeekEnd:
npos = len(f.n.data) + int(offset)
default:
npos = -1
}
if npos < 0 {
return 0, os.ErrInvalid
}
f.pos = npos
return int64(f.pos), nil
}
func (f *memFile) Stat() (os.FileInfo, error) {
return f.n.stat(f.nameSnapshot), nil
}
func (f *memFile) Write(p []byte) (int, error) {
lenp := len(p)
f.n.mu.Lock()
defer f.n.mu.Unlock()
if f.n.mode.IsDir() {
return 0, os.ErrInvalid
}
if f.pos < len(f.n.data) {
n := copy(f.n.data[f.pos:], p)
f.pos += n
p = p[n:]
} else if f.pos > len(f.n.data) {
// Write permits the creation of holes, if we've seek'ed past the
// existing end of file.
if f.pos <= cap(f.n.data) {
oldLen := len(f.n.data)
f.n.data = f.n.data[:f.pos]
hole := f.n.data[oldLen:]
for i := range hole {
hole[i] = 0
}
} else {
d := make([]byte, f.pos, f.pos+len(p))
copy(d, f.n.data)
f.n.data = d
}
}
if len(p) > 0 {
// We should only get here if f.pos == len(f.n.data).
f.n.data = append(f.n.data, p...)
f.pos = len(f.n.data)
}
f.n.modTime = time.Now()
return lenp, nil
}
// moveFiles moves files and/or directories from src to dst.
//
// See section 9.9.4 for when various HTTP status codes apply.
func moveFiles(ctx context.Context, fs FileSystem, src, dst string, overwrite bool) (status int, err error) {
created := false
if _, err := fs.Stat(ctx, dst); err != nil {
if !os.IsNotExist(err) {
return http.StatusForbidden, err
}
created = true
} else if overwrite {
// Section 9.9.3 says that "If a resource exists at the destination
// and the Overwrite header is "T", then prior to performing the move,
// the server must perform a DELETE with "Depth: infinity" on the
// destination resource.
if err := fs.RemoveAll(ctx, dst); err != nil {
return http.StatusForbidden, err
}
} else {
return http.StatusPreconditionFailed, os.ErrExist
}
if err := fs.Rename(ctx, src, dst); err != nil {
return http.StatusForbidden, err
}
if created {
return http.StatusCreated, nil
}
return http.StatusNoContent, nil
}
func copyProps(dst, src File) error {
d, ok := dst.(DeadPropsHolder)
if !ok {
return nil
}
s, ok := src.(DeadPropsHolder)
if !ok {
return nil
}
m, err := s.DeadProps()
if err != nil {
return err
}
props := make([]Property, 0, len(m))
for _, prop := range m {
props = append(props, prop)
}
_, err = d.Patch([]Proppatch{{Props: props}})
return err
}
// copyFiles copies files and/or directories from src to dst.
//
// See section 9.8.5 for when various HTTP status codes apply.
func copyFiles(ctx context.Context, fs FileSystem, src, dst string, overwrite bool, depth int, recursion int) (status int, err error) {
if recursion == 1000 {
return http.StatusInternalServerError, errRecursionTooDeep
}
recursion++
// TODO: section 9.8.3 says that "Note that an infinite-depth COPY of /A/
// into /A/B/ could lead to infinite recursion if not handled correctly."
srcFile, err := fs.OpenFile(ctx, src, os.O_RDONLY, 0)
if err != nil {
if os.IsNotExist(err) {
return http.StatusNotFound, err
}
return http.StatusInternalServerError, err
}
defer srcFile.Close()
srcStat, err := srcFile.Stat()
if err != nil {
if os.IsNotExist(err) {
return http.StatusNotFound, err
}
return http.StatusInternalServerError, err
}
srcPerm := srcStat.Mode() & os.ModePerm
created := false
if _, err := fs.Stat(ctx, dst); err != nil {
if os.IsNotExist(err) {
created = true
} else {
return http.StatusForbidden, err
}
} else {
if !overwrite {
return http.StatusPreconditionFailed, os.ErrExist
}
if err := fs.RemoveAll(ctx, dst); err != nil && !os.IsNotExist(err) {
return http.StatusForbidden, err
}
}
if srcStat.IsDir() {
if err := fs.Mkdir(ctx, dst, srcPerm); err != nil {
return http.StatusForbidden, err
}
if depth == infiniteDepth {
children, err := srcFile.Readdir(-1)
if err != nil {
return http.StatusForbidden, err
}
for _, c := range children {
name := c.Name()
s := path.Join(src, name)
d := path.Join(dst, name)
cStatus, cErr := copyFiles(ctx, fs, s, d, overwrite, depth, recursion)
if cErr != nil {
// TODO: MultiStatus.
return cStatus, cErr
}
}
}
} else {
dstFile, err := fs.OpenFile(ctx, dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, srcPerm)
if err != nil {
if os.IsNotExist(err) {
return http.StatusConflict, err
}
return http.StatusForbidden, err
}
_, copyErr := io.Copy(dstFile, srcFile)
propsErr := copyProps(dstFile, srcFile)
closeErr := dstFile.Close()
if copyErr != nil {
return http.StatusInternalServerError, copyErr
}
if propsErr != nil {
return http.StatusInternalServerError, propsErr
}
if closeErr != nil {
return http.StatusInternalServerError, closeErr
}
}
if created {
return http.StatusCreated, nil
}
return http.StatusNoContent, nil
}
// walkFS traverses filesystem fs starting at name up to depth levels.
//
// Allowed values for depth are 0, 1 or infiniteDepth. For each visited node,
// walkFS calls walkFn. If a visited file system node is a directory and
// walkFn returns filepath.SkipDir, walkFS will skip traversal of this node.
func walkFS(ctx context.Context, fs FileSystem, depth int, name string, info os.FileInfo, walkFn filepath.WalkFunc) error {
// This implementation is based on Walk's code in the standard path/filepath package.
err := walkFn(name, info, nil)
if err != nil {
if info.IsDir() && err == filepath.SkipDir {
return nil
}
return err
}
if !info.IsDir() || depth == 0 {
return nil
}
if depth == 1 {
depth = 0
}
// Read directory names.
f, err := fs.OpenFile(ctx, name, os.O_RDONLY, 0)
if err != nil {
return walkFn(name, info, err)
}
fileInfos, err := f.Readdir(0)
f.Close()
if err != nil {
return walkFn(name, info, err)
}
for _, fileInfo := range fileInfos {
filename := path.Join(name, fileInfo.Name())
fileInfo, err := fs.Stat(ctx, filename)
if err != nil {
if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
return err
}
} else {
err = walkFS(ctx, fs, depth, filename, fileInfo, walkFn)
if err != nil {
if !fileInfo.IsDir() || err != filepath.SkipDir {
return err
}
}
}
}
return nil
}
// 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 webdav
// The If header is covered by Section 10.4.
// http://www.webdav.org/specs/rfc4918.html#HEADER_If
import (
"strings"
)
// ifHeader is a disjunction (OR) of ifLists.
type ifHeader struct {
lists []ifList
}
// ifList is a conjunction (AND) of Conditions, and an optional resource tag.
type ifList struct {
resourceTag string
conditions []Condition
}
// parseIfHeader parses the "If: foo bar" HTTP header. The httpHeader string
// should omit the "If:" prefix and have any "\r\n"s collapsed to a " ", as is
// returned by req.Header.Get("If") for an http.Request req.
func parseIfHeader(httpHeader string) (h ifHeader, ok bool) {
s := strings.TrimSpace(httpHeader)
switch tokenType, _, _ := lex(s); tokenType {
case '(':
return parseNoTagLists(s)
case angleTokenType:
return parseTaggedLists(s)
default:
return ifHeader{}, false
}
}
func parseNoTagLists(s string) (h ifHeader, ok bool) {
for {
l, remaining, ok := parseList(s)
if !ok {
return ifHeader{}, false
}
h.lists = append(h.lists, l)
if remaining == "" {
return h, true
}
s = remaining
}
}
func parseTaggedLists(s string) (h ifHeader, ok bool) {
resourceTag, n := "", 0
for first := true; ; first = false {
tokenType, tokenStr, remaining := lex(s)
switch tokenType {
case angleTokenType:
if !first && n == 0 {
return ifHeader{}, false
}
resourceTag, n = tokenStr, 0
s = remaining
case '(':
n++
l, remaining, ok := parseList(s)
if !ok {
return ifHeader{}, false
}
l.resourceTag = resourceTag
h.lists = append(h.lists, l)
if remaining == "" {
return h, true
}
s = remaining
default:
return ifHeader{}, false
}
}
}
func parseList(s string) (l ifList, remaining string, ok bool) {
tokenType, _, s := lex(s)
if tokenType != '(' {
return ifList{}, "", false
}
for {
tokenType, _, remaining = lex(s)
if tokenType == ')' {
if len(l.conditions) == 0 {
return ifList{}, "", false
}
return l, remaining, true
}
c, remaining, ok := parseCondition(s)
if !ok {
return ifList{}, "", false
}
l.conditions = append(l.conditions, c)
s = remaining
}
}
func parseCondition(s string) (c Condition, remaining string, ok bool) {
tokenType, tokenStr, s := lex(s)
if tokenType == notTokenType {
c.Not = true
tokenType, tokenStr, s = lex(s)
}
switch tokenType {
case strTokenType, angleTokenType:
c.Token = tokenStr
case squareTokenType:
c.ETag = tokenStr
default:
return Condition{}, "", false
}
return c, s, true
}
// Single-rune tokens like '(' or ')' have a token type equal to their rune.
// All other tokens have a negative token type.
const (
errTokenType = rune(-1)
eofTokenType = rune(-2)
strTokenType = rune(-3)
notTokenType = rune(-4)
angleTokenType = rune(-5)
squareTokenType = rune(-6)
)
func lex(s string) (tokenType rune, tokenStr string, remaining string) {
// The net/textproto Reader that parses the HTTP header will collapse
// Linear White Space that spans multiple "\r\n" lines to a single " ",
// so we don't need to look for '\r' or '\n'.
for len(s) > 0 && (s[0] == '\t' || s[0] == ' ') {
s = s[1:]
}
if len(s) == 0 {
return eofTokenType, "", ""
}
i := 0
loop:
for ; i < len(s); i++ {
switch s[i] {
case '\t', ' ', '(', ')', '<', '>', '[', ']':
break loop
}
}
if i != 0 {
tokenStr, remaining = s[:i], s[i:]
if tokenStr == "Not" {
return notTokenType, "", remaining
}
return strTokenType, tokenStr, remaining
}
j := 0
switch s[0] {
case '<':
j, tokenType = strings.IndexByte(s, '>'), angleTokenType
case '[':
j, tokenType = strings.IndexByte(s, ']'), squareTokenType
default:
return rune(s[0]), "", s[1:]
}
if j < 0 {
return errTokenType, "", ""
}
return tokenType, s[1:j], s[j+1:]
}
// Copyright 2011 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 xml
import (
"bufio"
"bytes"
"encoding"
"fmt"
"io"
"reflect"
"strconv"
"strings"
)
const (
// A generic XML header suitable for use with the output of Marshal.
// This is not automatically added to any output of this package,
// it is provided as a convenience.
Header = `<?xml version="1.0" encoding="UTF-8"?>` + "\n"
)
// Marshal returns the XML encoding of v.
//
// Marshal handles an array or slice by marshalling each of the elements.
// Marshal handles a pointer by marshalling the value it points at or, if the
// pointer is nil, by writing nothing. Marshal handles an interface value by
// marshalling the value it contains or, if the interface value is nil, by
// writing nothing. Marshal handles all other data by writing one or more XML
// elements containing the data.
//
// The name for the XML elements is taken from, in order of preference:
// - the tag on the XMLName field, if the data is a struct
// - the value of the XMLName field of type xml.Name
// - the tag of the struct field used to obtain the data
// - the name of the struct field used to obtain the data
// - the name of the marshalled type
//
// The XML element for a struct contains marshalled elements for each of the
// exported fields of the struct, with these exceptions:
// - the XMLName field, described above, is omitted.
// - a field with tag "-" is omitted.
// - a field with tag "name,attr" becomes an attribute with
// the given name in the XML element.
// - a field with tag ",attr" becomes an attribute with the
// field name in the XML element.
// - a field with tag ",chardata" is written as character data,
// not as an XML element.
// - a field with tag ",innerxml" is written verbatim, not subject
// to the usual marshalling procedure.
// - a field with tag ",comment" is written as an XML comment, not
// subject to the usual marshalling procedure. It must not contain
// the "--" string within it.
// - a field with a tag including the "omitempty" option is omitted
// if the field value is empty. The empty values are false, 0, any
// nil pointer or interface value, and any array, slice, map, or
// string of length zero.
// - an anonymous struct field is handled as if the fields of its
// value were part of the outer struct.
//
// If a field uses a tag "a>b>c", then the element c will be nested inside
// parent elements a and b. Fields that appear next to each other that name
// the same parent will be enclosed in one XML element.
//
// See MarshalIndent for an example.
//
// Marshal will return an error if asked to marshal a channel, function, or map.
func Marshal(v interface{}) ([]byte, error) {
var b bytes.Buffer
if err := NewEncoder(&b).Encode(v); err != nil {
return nil, err
}
return b.Bytes(), nil
}
// Marshaler is the interface implemented by objects that can marshal
// themselves into valid XML elements.
//
// MarshalXML encodes the receiver as zero or more XML elements.
// By convention, arrays or slices are typically encoded as a sequence
// of elements, one per entry.
// Using start as the element tag is not required, but doing so
// will enable Unmarshal to match the XML elements to the correct
// struct field.
// One common implementation strategy is to construct a separate
// value with a layout corresponding to the desired XML and then
// to encode it using e.EncodeElement.
// Another common strategy is to use repeated calls to e.EncodeToken
// to generate the XML output one token at a time.
// The sequence of encoded tokens must make up zero or more valid
// XML elements.
type Marshaler interface {
MarshalXML(e *Encoder, start StartElement) error
}
// MarshalerAttr is the interface implemented by objects that can marshal
// themselves into valid XML attributes.
//
// MarshalXMLAttr returns an XML attribute with the encoded value of the receiver.
// Using name as the attribute name is not required, but doing so
// will enable Unmarshal to match the attribute to the correct
// struct field.
// If MarshalXMLAttr returns the zero attribute Attr{}, no attribute
// will be generated in the output.
// MarshalXMLAttr is used only for struct fields with the
// "attr" option in the field tag.
type MarshalerAttr interface {
MarshalXMLAttr(name Name) (Attr, error)
}
// MarshalIndent works like Marshal, but each XML element begins on a new
// indented line that starts with prefix and is followed by one or more
// copies of indent according to the nesting depth.
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
var b bytes.Buffer
enc := NewEncoder(&b)
enc.Indent(prefix, indent)
if err := enc.Encode(v); err != nil {
return nil, err
}
return b.Bytes(), nil
}
// An Encoder writes XML data to an output stream.
type Encoder struct {
p printer
}
// NewEncoder returns a new encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder {
e := &Encoder{printer{Writer: bufio.NewWriter(w)}}
e.p.encoder = e
return e
}
// Indent sets the encoder to generate XML in which each element
// begins on a new indented line that starts with prefix and is followed by
// one or more copies of indent according to the nesting depth.
func (enc *Encoder) Indent(prefix, indent string) {
enc.p.prefix = prefix
enc.p.indent = indent
}
// Encode writes the XML encoding of v to the stream.
//
// See the documentation for Marshal for details about the conversion
// of Go values to XML.
//
// Encode calls Flush before returning.
func (enc *Encoder) Encode(v interface{}) error {
err := enc.p.marshalValue(reflect.ValueOf(v), nil, nil)
if err != nil {
return err
}
return enc.p.Flush()
}
// EncodeElement writes the XML encoding of v to the stream,
// using start as the outermost tag in the encoding.
//
// See the documentation for Marshal for details about the conversion
// of Go values to XML.
//
// EncodeElement calls Flush before returning.
func (enc *Encoder) EncodeElement(v interface{}, start StartElement) error {
err := enc.p.marshalValue(reflect.ValueOf(v), nil, &start)
if err != nil {
return err
}
return enc.p.Flush()
}
var (
begComment = []byte("<!--")
endComment = []byte("-->")
endProcInst = []byte("?>")
endDirective = []byte(">")
)
// EncodeToken writes the given XML token to the stream.
// It returns an error if StartElement and EndElement tokens are not
// properly matched.
//
// EncodeToken does not call Flush, because usually it is part of a
// larger operation such as Encode or EncodeElement (or a custom
// Marshaler's MarshalXML invoked during those), and those will call
// Flush when finished. Callers that create an Encoder and then invoke
// EncodeToken directly, without using Encode or EncodeElement, need to
// call Flush when finished to ensure that the XML is written to the
// underlying writer.
//
// EncodeToken allows writing a ProcInst with Target set to "xml" only
// as the first token in the stream.
//
// When encoding a StartElement holding an XML namespace prefix
// declaration for a prefix that is not already declared, contained
// elements (including the StartElement itself) will use the declared
// prefix when encoding names with matching namespace URIs.
func (enc *Encoder) EncodeToken(t Token) error {
p := &enc.p
switch t := t.(type) {
case StartElement:
if err := p.writeStart(&t); err != nil {
return err
}
case EndElement:
if err := p.writeEnd(t.Name); err != nil {
return err
}
case CharData:
escapeText(p, t, false)
case Comment:
if bytes.Contains(t, endComment) {
return fmt.Errorf("xml: EncodeToken of Comment containing --> marker")
}
p.WriteString("<!--")
p.Write(t)
p.WriteString("-->")
return p.cachedWriteError()
case ProcInst:
// First token to be encoded which is also a ProcInst with target of xml
// is the xml declaration. The only ProcInst where target of xml is allowed.
if t.Target == "xml" && p.Buffered() != 0 {
return fmt.Errorf("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded")
}
if !isNameString(t.Target) {
return fmt.Errorf("xml: EncodeToken of ProcInst with invalid Target")
}
if bytes.Contains(t.Inst, endProcInst) {
return fmt.Errorf("xml: EncodeToken of ProcInst containing ?> marker")
}
p.WriteString("<?")
p.WriteString(t.Target)
if len(t.Inst) > 0 {
p.WriteByte(' ')
p.Write(t.Inst)
}
p.WriteString("?>")
case Directive:
if !isValidDirective(t) {
return fmt.Errorf("xml: EncodeToken of Directive containing wrong < or > markers")
}
p.WriteString("<!")
p.Write(t)
p.WriteString(">")
default:
return fmt.Errorf("xml: EncodeToken of invalid token type")
}
return p.cachedWriteError()
}
// isValidDirective reports whether dir is a valid directive text,
// meaning angle brackets are matched, ignoring comments and strings.
func isValidDirective(dir Directive) bool {
var (
depth int
inquote uint8
incomment bool
)
for i, c := range dir {
switch {
case incomment:
if c == '>' {
if n := 1 + i - len(endComment); n >= 0 && bytes.Equal(dir[n:i+1], endComment) {
incomment = false
}
}
// Just ignore anything in comment
case inquote != 0:
if c == inquote {
inquote = 0
}
// Just ignore anything within quotes
case c == '\'' || c == '"':
inquote = c
case c == '<':
if i+len(begComment) < len(dir) && bytes.Equal(dir[i:i+len(begComment)], begComment) {
incomment = true
} else {
depth++
}
case c == '>':
if depth == 0 {
return false
}
depth--
}
}
return depth == 0 && inquote == 0 && !incomment
}
// Flush flushes any buffered XML to the underlying writer.
// See the EncodeToken documentation for details about when it is necessary.
func (enc *Encoder) Flush() error {
return enc.p.Flush()
}
type printer struct {
*bufio.Writer
encoder *Encoder
seq int
indent string
prefix string
depth int
indentedIn bool
putNewline bool
defaultNS string
attrNS map[string]string // map prefix -> name space
attrPrefix map[string]string // map name space -> prefix
prefixes []printerPrefix
tags []Name
}
// printerPrefix holds a namespace undo record.
// When an element is popped, the prefix record
// is set back to the recorded URL. The empty
// prefix records the URL for the default name space.
//
// The start of an element is recorded with an element
// that has mark=true.
type printerPrefix struct {
prefix string
url string
mark bool
}
func (p *printer) prefixForNS(url string, isAttr bool) string {
// The "http://www.w3.org/XML/1998/namespace" name space is predefined as "xml"
// and must be referred to that way.
// (The "http://www.w3.org/2000/xmlns/" name space is also predefined as "xmlns",
// but users should not be trying to use that one directly - that's our job.)
if url == xmlURL {
return "xml"
}
if !isAttr && url == p.defaultNS {
// We can use the default name space.
return ""
}
return p.attrPrefix[url]
}
// defineNS pushes any namespace definition found in the given attribute.
// If ignoreNonEmptyDefault is true, an xmlns="nonempty"
// attribute will be ignored.
func (p *printer) defineNS(attr Attr, ignoreNonEmptyDefault bool) error {
var prefix string
if attr.Name.Local == "xmlns" {
if attr.Name.Space != "" && attr.Name.Space != "xml" && attr.Name.Space != xmlURL {
return fmt.Errorf("xml: cannot redefine xmlns attribute prefix")
}
} else if attr.Name.Space == "xmlns" && attr.Name.Local != "" {
prefix = attr.Name.Local
if attr.Value == "" {
// Technically, an empty XML namespace is allowed for an attribute.
// From http://www.w3.org/TR/xml-names11/#scoping-defaulting:
//
// The attribute value in a namespace declaration for a prefix may be
// empty. This has the effect, within the scope of the declaration, of removing
// any association of the prefix with a namespace name.
//
// However our namespace prefixes here are used only as hints. There's
// no need to respect the removal of a namespace prefix, so we ignore it.
return nil
}
} else {
// Ignore: it's not a namespace definition
return nil
}
if prefix == "" {
if attr.Value == p.defaultNS {
// No need for redefinition.
return nil
}
if attr.Value != "" && ignoreNonEmptyDefault {
// We have an xmlns="..." value but
// it can't define a name space in this context,
// probably because the element has an empty
// name space. In this case, we just ignore
// the name space declaration.
return nil
}
} else if _, ok := p.attrPrefix[attr.Value]; ok {
// There's already a prefix for the given name space,
// so use that. This prevents us from
// having two prefixes for the same name space
// so attrNS and attrPrefix can remain bijective.
return nil
}
p.pushPrefix(prefix, attr.Value)
return nil
}
// createNSPrefix creates a name space prefix attribute
// to use for the given name space, defining a new prefix
// if necessary.
// If isAttr is true, the prefix is to be created for an attribute
// prefix, which means that the default name space cannot
// be used.
func (p *printer) createNSPrefix(url string, isAttr bool) {
if _, ok := p.attrPrefix[url]; ok {
// We already have a prefix for the given URL.
return
}
switch {
case !isAttr && url == p.defaultNS:
// We can use the default name space.
return
case url == "":
// The only way we can encode names in the empty
// name space is by using the default name space,
// so we must use that.
if p.defaultNS != "" {
// The default namespace is non-empty, so we
// need to set it to empty.
p.pushPrefix("", "")
}
return
case url == xmlURL:
return
}
// TODO If the URL is an existing prefix, we could
// use it as is. That would enable the
// marshaling of elements that had been unmarshaled
// and with a name space prefix that was not found.
// although technically it would be incorrect.
// Pick a name. We try to use the final element of the path
// but fall back to _.
prefix := strings.TrimRight(url, "/")
if i := strings.LastIndex(prefix, "/"); i >= 0 {
prefix = prefix[i+1:]
}
if prefix == "" || !isName([]byte(prefix)) || strings.Contains(prefix, ":") {
prefix = "_"
}
if strings.HasPrefix(prefix, "xml") {
// xmlanything is reserved.
prefix = "_" + prefix
}
if p.attrNS[prefix] != "" {
// Name is taken. Find a better one.
for p.seq++; ; p.seq++ {
if id := prefix + "_" + strconv.Itoa(p.seq); p.attrNS[id] == "" {
prefix = id
break
}
}
}
p.pushPrefix(prefix, url)
}
// writeNamespaces writes xmlns attributes for all the
// namespace prefixes that have been defined in
// the current element.
func (p *printer) writeNamespaces() {
for i := len(p.prefixes) - 1; i >= 0; i-- {
prefix := p.prefixes[i]
if prefix.mark {
return
}
p.WriteString(" ")
if prefix.prefix == "" {
// Default name space.
p.WriteString(`xmlns="`)
} else {
p.WriteString("xmlns:")
p.WriteString(prefix.prefix)
p.WriteString(`="`)
}
EscapeText(p, []byte(p.nsForPrefix(prefix.prefix)))
p.WriteString(`"`)
}
}
// pushPrefix pushes a new prefix on the prefix stack
// without checking to see if it is already defined.
func (p *printer) pushPrefix(prefix, url string) {
p.prefixes = append(p.prefixes, printerPrefix{
prefix: prefix,
url: p.nsForPrefix(prefix),
})
p.setAttrPrefix(prefix, url)
}
// nsForPrefix returns the name space for the given
// prefix. Note that this is not valid for the
// empty attribute prefix, which always has an empty
// name space.
func (p *printer) nsForPrefix(prefix string) string {
if prefix == "" {
return p.defaultNS
}
return p.attrNS[prefix]
}
// markPrefix marks the start of an element on the prefix
// stack.
func (p *printer) markPrefix() {
p.prefixes = append(p.prefixes, printerPrefix{
mark: true,
})
}
// popPrefix pops all defined prefixes for the current
// element.
func (p *printer) popPrefix() {
for len(p.prefixes) > 0 {
prefix := p.prefixes[len(p.prefixes)-1]
p.prefixes = p.prefixes[:len(p.prefixes)-1]
if prefix.mark {
break
}
p.setAttrPrefix(prefix.prefix, prefix.url)
}
}
// setAttrPrefix sets an attribute name space prefix.
// If url is empty, the attribute is removed.
// If prefix is empty, the default name space is set.
func (p *printer) setAttrPrefix(prefix, url string) {
if prefix == "" {
p.defaultNS = url
return
}
if url == "" {
delete(p.attrPrefix, p.attrNS[prefix])
delete(p.attrNS, prefix)
return
}
if p.attrPrefix == nil {
// Need to define a new name space.
p.attrPrefix = make(map[string]string)
p.attrNS = make(map[string]string)
}
// Remove any old prefix value. This is OK because we maintain a
// strict one-to-one mapping between prefix and URL (see
// defineNS)
delete(p.attrPrefix, p.attrNS[prefix])
p.attrPrefix[url] = prefix
p.attrNS[prefix] = url
}
var (
marshalerType = reflect.TypeFor[Marshaler]()
marshalerAttrType = reflect.TypeFor[MarshalerAttr]()
textMarshalerType = reflect.TypeFor[encoding.TextMarshaler]()
)
// marshalValue writes one or more XML elements representing val.
// If val was obtained from a struct field, finfo must have its details.
func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplate *StartElement) error {
if startTemplate != nil && startTemplate.Name.Local == "" {
return fmt.Errorf("xml: EncodeElement of StartElement with missing name")
}
if !val.IsValid() {
return nil
}
if finfo != nil && finfo.flags&fOmitEmpty != 0 && isEmptyValue(val) {
return nil
}
// Drill into interfaces and pointers.
// This can turn into an infinite loop given a cyclic chain,
// but it matches the Go 1 behavior.
for val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr {
if val.IsNil() {
return nil
}
val = val.Elem()
}
kind := val.Kind()
typ := val.Type()
// Check for marshaler.
if val.CanInterface() && typ.Implements(marshalerType) {
return p.marshalInterface(val.Interface().(Marshaler), p.defaultStart(typ, finfo, startTemplate))
}
if val.CanAddr() {
pv := val.Addr()
if pv.CanInterface() && pv.Type().Implements(marshalerType) {
return p.marshalInterface(pv.Interface().(Marshaler), p.defaultStart(pv.Type(), finfo, startTemplate))
}
}
// Check for text marshaler.
if val.CanInterface() && typ.Implements(textMarshalerType) {
return p.marshalTextInterface(val.Interface().(encoding.TextMarshaler), p.defaultStart(typ, finfo, startTemplate))
}
if val.CanAddr() {
pv := val.Addr()
if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
return p.marshalTextInterface(pv.Interface().(encoding.TextMarshaler), p.defaultStart(pv.Type(), finfo, startTemplate))
}
}
// Slices and arrays iterate over the elements. They do not have an enclosing tag.
if (kind == reflect.Slice || kind == reflect.Array) && typ.Elem().Kind() != reflect.Uint8 {
for i, n := 0, val.Len(); i < n; i++ {
if err := p.marshalValue(val.Index(i), finfo, startTemplate); err != nil {
return err
}
}
return nil
}
tinfo, err := getTypeInfo(typ)
if err != nil {
return err
}
// Create start element.
// Precedence for the XML element name is:
// 0. startTemplate
// 1. XMLName field in underlying struct;
// 2. field name/tag in the struct field; and
// 3. type name
var start StartElement
// explicitNS records whether the element's name space has been
// explicitly set (for example an XMLName field).
explicitNS := false
if startTemplate != nil {
start.Name = startTemplate.Name
explicitNS = true
start.Attr = append(start.Attr, startTemplate.Attr...)
} else if tinfo.xmlname != nil {
xmlname := tinfo.xmlname
if xmlname.name != "" {
start.Name.Space, start.Name.Local = xmlname.xmlns, xmlname.name
} else if v, ok := xmlname.value(val).Interface().(Name); ok && v.Local != "" {
start.Name = v
}
explicitNS = true
}
if start.Name.Local == "" && finfo != nil {
start.Name.Local = finfo.name
if finfo.xmlns != "" {
start.Name.Space = finfo.xmlns
explicitNS = true
}
}
if start.Name.Local == "" {
name := typ.Name()
if name == "" {
return &UnsupportedTypeError{typ}
}
start.Name.Local = name
}
// defaultNS records the default name space as set by a xmlns="..."
// attribute. We don't set p.defaultNS because we want to let
// the attribute writing code (in p.defineNS) be solely responsible
// for maintaining that.
defaultNS := p.defaultNS
// Attributes
for i := range tinfo.fields {
finfo := &tinfo.fields[i]
if finfo.flags&fAttr == 0 {
continue
}
attr, err := p.fieldAttr(finfo, val)
if err != nil {
return err
}
if attr.Name.Local == "" {
continue
}
start.Attr = append(start.Attr, attr)
if attr.Name.Space == "" && attr.Name.Local == "xmlns" {
defaultNS = attr.Value
}
}
if !explicitNS {
// Historic behavior: elements use the default name space
// they are contained in by default.
start.Name.Space = defaultNS
}
// Historic behaviour: an element that's in a namespace sets
// the default namespace for all elements contained within it.
start.setDefaultNamespace()
if err := p.writeStart(&start); err != nil {
return err
}
if val.Kind() == reflect.Struct {
err = p.marshalStruct(tinfo, val)
} else {
s, b, err1 := p.marshalSimple(typ, val)
if err1 != nil {
err = err1
} else if b != nil {
EscapeText(p, b)
} else {
p.EscapeString(s)
}
}
if err != nil {
return err
}
if err := p.writeEnd(start.Name); err != nil {
return err
}
return p.cachedWriteError()
}
// fieldAttr returns the attribute of the given field.
// If the returned attribute has an empty Name.Local,
// it should not be used.
// The given value holds the value containing the field.
func (p *printer) fieldAttr(finfo *fieldInfo, val reflect.Value) (Attr, error) {
fv := finfo.value(val)
name := Name{Space: finfo.xmlns, Local: finfo.name}
if finfo.flags&fOmitEmpty != 0 && isEmptyValue(fv) {
return Attr{}, nil
}
if fv.Kind() == reflect.Interface && fv.IsNil() {
return Attr{}, nil
}
if fv.CanInterface() && fv.Type().Implements(marshalerAttrType) {
attr, err := fv.Interface().(MarshalerAttr).MarshalXMLAttr(name)
return attr, err
}
if fv.CanAddr() {
pv := fv.Addr()
if pv.CanInterface() && pv.Type().Implements(marshalerAttrType) {
attr, err := pv.Interface().(MarshalerAttr).MarshalXMLAttr(name)
return attr, err
}
}
if fv.CanInterface() && fv.Type().Implements(textMarshalerType) {
text, err := fv.Interface().(encoding.TextMarshaler).MarshalText()
if err != nil {
return Attr{}, err
}
return Attr{name, string(text)}, nil
}
if fv.CanAddr() {
pv := fv.Addr()
if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
text, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
if err != nil {
return Attr{}, err
}
return Attr{name, string(text)}, nil
}
}
// Dereference or skip nil pointer, interface values.
switch fv.Kind() {
case reflect.Ptr, reflect.Interface:
if fv.IsNil() {
return Attr{}, nil
}
fv = fv.Elem()
}
s, b, err := p.marshalSimple(fv.Type(), fv)
if err != nil {
return Attr{}, err
}
if b != nil {
s = string(b)
}
return Attr{name, s}, nil
}
// defaultStart returns the default start element to use,
// given the reflect type, field info, and start template.
func (p *printer) defaultStart(typ reflect.Type, finfo *fieldInfo, startTemplate *StartElement) StartElement {
var start StartElement
// Precedence for the XML element name is as above,
// except that we do not look inside structs for the first field.
if startTemplate != nil {
start.Name = startTemplate.Name
start.Attr = append(start.Attr, startTemplate.Attr...)
} else if finfo != nil && finfo.name != "" {
start.Name.Local = finfo.name
start.Name.Space = finfo.xmlns
} else if typ.Name() != "" {
start.Name.Local = typ.Name()
} else {
// Must be a pointer to a named type,
// since it has the Marshaler methods.
start.Name.Local = typ.Elem().Name()
}
// Historic behaviour: elements use the name space of
// the element they are contained in by default.
if start.Name.Space == "" {
start.Name.Space = p.defaultNS
}
start.setDefaultNamespace()
return start
}
// marshalInterface marshals a Marshaler interface value.
func (p *printer) marshalInterface(val Marshaler, start StartElement) error {
// Push a marker onto the tag stack so that MarshalXML
// cannot close the XML tags that it did not open.
p.tags = append(p.tags, Name{})
n := len(p.tags)
err := val.MarshalXML(p.encoder, start)
if err != nil {
return err
}
// Make sure MarshalXML closed all its tags. p.tags[n-1] is the mark.
if len(p.tags) > n {
return fmt.Errorf("xml: %s.MarshalXML wrote invalid XML: <%s> not closed", receiverType(val), p.tags[len(p.tags)-1].Local)
}
p.tags = p.tags[:n-1]
return nil
}
// marshalTextInterface marshals a TextMarshaler interface value.
func (p *printer) marshalTextInterface(val encoding.TextMarshaler, start StartElement) error {
if err := p.writeStart(&start); err != nil {
return err
}
text, err := val.MarshalText()
if err != nil {
return err
}
EscapeText(p, text)
return p.writeEnd(start.Name)
}
// writeStart writes the given start element.
func (p *printer) writeStart(start *StartElement) error {
if start.Name.Local == "" {
return fmt.Errorf("xml: start tag with no name")
}
p.tags = append(p.tags, start.Name)
p.markPrefix()
// Define any name spaces explicitly declared in the attributes.
// We do this as a separate pass so that explicitly declared prefixes
// will take precedence over implicitly declared prefixes
// regardless of the order of the attributes.
ignoreNonEmptyDefault := start.Name.Space == ""
for _, attr := range start.Attr {
if err := p.defineNS(attr, ignoreNonEmptyDefault); err != nil {
return err
}
}
// Define any new name spaces implied by the attributes.
for _, attr := range start.Attr {
name := attr.Name
// From http://www.w3.org/TR/xml-names11/#defaulting
// "Default namespace declarations do not apply directly
// to attribute names; the interpretation of unprefixed
// attributes is determined by the element on which they
// appear."
// This means we don't need to create a new namespace
// when an attribute name space is empty.
if name.Space != "" && !name.isNamespace() {
p.createNSPrefix(name.Space, true)
}
}
p.createNSPrefix(start.Name.Space, false)
p.writeIndent(1)
p.WriteByte('<')
p.writeName(start.Name, false)
p.writeNamespaces()
for _, attr := range start.Attr {
name := attr.Name
if name.Local == "" || name.isNamespace() {
// Namespaces have already been written by writeNamespaces above.
continue
}
p.WriteByte(' ')
p.writeName(name, true)
p.WriteString(`="`)
p.EscapeString(attr.Value)
p.WriteByte('"')
}
p.WriteByte('>')
return nil
}
// writeName writes the given name. It assumes
// that p.createNSPrefix(name) has already been called.
func (p *printer) writeName(name Name, isAttr bool) {
if prefix := p.prefixForNS(name.Space, isAttr); prefix != "" {
p.WriteString(prefix)
p.WriteByte(':')
}
p.WriteString(name.Local)
}
func (p *printer) writeEnd(name Name) error {
if name.Local == "" {
return fmt.Errorf("xml: end tag with no name")
}
if len(p.tags) == 0 || p.tags[len(p.tags)-1].Local == "" {
return fmt.Errorf("xml: end tag </%s> without start tag", name.Local)
}
if top := p.tags[len(p.tags)-1]; top != name {
if top.Local != name.Local {
return fmt.Errorf("xml: end tag </%s> does not match start tag <%s>", name.Local, top.Local)
}
return fmt.Errorf("xml: end tag </%s> in namespace %s does not match start tag <%s> in namespace %s", name.Local, name.Space, top.Local, top.Space)
}
p.tags = p.tags[:len(p.tags)-1]
p.writeIndent(-1)
p.WriteByte('<')
p.WriteByte('/')
p.writeName(name, false)
p.WriteByte('>')
p.popPrefix()
return nil
}
func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) (string, []byte, error) {
switch val.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return strconv.FormatInt(val.Int(), 10), nil, nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return strconv.FormatUint(val.Uint(), 10), nil, nil
case reflect.Float32, reflect.Float64:
return strconv.FormatFloat(val.Float(), 'g', -1, val.Type().Bits()), nil, nil
case reflect.String:
return val.String(), nil, nil
case reflect.Bool:
return strconv.FormatBool(val.Bool()), nil, nil
case reflect.Array:
if typ.Elem().Kind() != reflect.Uint8 {
break
}
// [...]byte
var bytes []byte
if val.CanAddr() {
bytes = val.Slice(0, val.Len()).Bytes()
} else {
bytes = make([]byte, val.Len())
reflect.Copy(reflect.ValueOf(bytes), val)
}
return "", bytes, nil
case reflect.Slice:
if typ.Elem().Kind() != reflect.Uint8 {
break
}
// []byte
return "", val.Bytes(), nil
}
return "", nil, &UnsupportedTypeError{typ}
}
var ddBytes = []byte("--")
func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
s := parentStack{p: p}
for i := range tinfo.fields {
finfo := &tinfo.fields[i]
if finfo.flags&fAttr != 0 {
continue
}
vf := finfo.value(val)
// Dereference or skip nil pointer, interface values.
switch vf.Kind() {
case reflect.Ptr, reflect.Interface:
if !vf.IsNil() {
vf = vf.Elem()
}
}
switch finfo.flags & fMode {
case fCharData:
if err := s.setParents(&noField, reflect.Value{}); err != nil {
return err
}
if vf.CanInterface() && vf.Type().Implements(textMarshalerType) {
data, err := vf.Interface().(encoding.TextMarshaler).MarshalText()
if err != nil {
return err
}
Escape(p, data)
continue
}
if vf.CanAddr() {
pv := vf.Addr()
if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
data, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
if err != nil {
return err
}
Escape(p, data)
continue
}
}
var scratch [64]byte
switch vf.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
Escape(p, strconv.AppendInt(scratch[:0], vf.Int(), 10))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
Escape(p, strconv.AppendUint(scratch[:0], vf.Uint(), 10))
case reflect.Float32, reflect.Float64:
Escape(p, strconv.AppendFloat(scratch[:0], vf.Float(), 'g', -1, vf.Type().Bits()))
case reflect.Bool:
Escape(p, strconv.AppendBool(scratch[:0], vf.Bool()))
case reflect.String:
if err := EscapeText(p, []byte(vf.String())); err != nil {
return err
}
case reflect.Slice:
if elem, ok := vf.Interface().([]byte); ok {
if err := EscapeText(p, elem); err != nil {
return err
}
}
}
continue
case fComment:
if err := s.setParents(&noField, reflect.Value{}); err != nil {
return err
}
k := vf.Kind()
if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) {
return fmt.Errorf("xml: bad type for comment field of %s", val.Type())
}
if vf.Len() == 0 {
continue
}
p.writeIndent(0)
p.WriteString("<!--")
dashDash := false
dashLast := false
switch k {
case reflect.String:
s := vf.String()
dashDash = strings.Index(s, "--") >= 0
dashLast = s[len(s)-1] == '-'
if !dashDash {
p.WriteString(s)
}
case reflect.Slice:
b := vf.Bytes()
dashDash = bytes.Index(b, ddBytes) >= 0
dashLast = b[len(b)-1] == '-'
if !dashDash {
p.Write(b)
}
default:
panic("can't happen")
}
if dashDash {
return fmt.Errorf(`xml: comments must not contain "--"`)
}
if dashLast {
// "--->" is invalid grammar. Make it "- -->"
p.WriteByte(' ')
}
p.WriteString("-->")
continue
case fInnerXml:
iface := vf.Interface()
switch raw := iface.(type) {
case []byte:
p.Write(raw)
continue
case string:
p.WriteString(raw)
continue
}
case fElement, fElement | fAny:
if err := s.setParents(finfo, vf); err != nil {
return err
}
}
if err := p.marshalValue(vf, finfo, nil); err != nil {
return err
}
}
if err := s.setParents(&noField, reflect.Value{}); err != nil {
return err
}
return p.cachedWriteError()
}
var noField fieldInfo
// return the bufio Writer's cached write error
func (p *printer) cachedWriteError() error {
_, err := p.Write(nil)
return err
}
func (p *printer) writeIndent(depthDelta int) {
if len(p.prefix) == 0 && len(p.indent) == 0 {
return
}
if depthDelta < 0 {
p.depth--
if p.indentedIn {
p.indentedIn = false
return
}
p.indentedIn = false
}
if p.putNewline {
p.WriteByte('\n')
} else {
p.putNewline = true
}
if len(p.prefix) > 0 {
p.WriteString(p.prefix)
}
if len(p.indent) > 0 {
for i := 0; i < p.depth; i++ {
p.WriteString(p.indent)
}
}
if depthDelta > 0 {
p.depth++
p.indentedIn = true
}
}
type parentStack struct {
p *printer
xmlns string
parents []string
}
// setParents sets the stack of current parents to those found in finfo.
// It only writes the start elements if vf holds a non-nil value.
// If finfo is &noField, it pops all elements.
func (s *parentStack) setParents(finfo *fieldInfo, vf reflect.Value) error {
xmlns := s.p.defaultNS
if finfo.xmlns != "" {
xmlns = finfo.xmlns
}
commonParents := 0
if xmlns == s.xmlns {
for ; commonParents < len(finfo.parents) && commonParents < len(s.parents); commonParents++ {
if finfo.parents[commonParents] != s.parents[commonParents] {
break
}
}
}
// Pop off any parents that aren't in common with the previous field.
for i := len(s.parents) - 1; i >= commonParents; i-- {
if err := s.p.writeEnd(Name{
Space: s.xmlns,
Local: s.parents[i],
}); err != nil {
return err
}
}
s.parents = finfo.parents
s.xmlns = xmlns
if commonParents >= len(s.parents) {
// No new elements to push.
return nil
}
if (vf.Kind() == reflect.Ptr || vf.Kind() == reflect.Interface) && vf.IsNil() {
// The element is nil, so no need for the start elements.
s.parents = s.parents[:commonParents]
return nil
}
// Push any new parents required.
for _, name := range s.parents[commonParents:] {
start := &StartElement{
Name: Name{
Space: s.xmlns,
Local: name,
},
}
// Set the default name space for parent elements
// to match what we do with other elements.
if s.xmlns != s.p.defaultNS {
start.setDefaultNamespace()
}
if err := s.p.writeStart(start); err != nil {
return err
}
}
return nil
}
// A MarshalXMLError is returned when Marshal encounters a type
// that cannot be converted into XML.
type UnsupportedTypeError struct {
Type reflect.Type
}
func (e *UnsupportedTypeError) Error() string {
return "xml: unsupported type: " + e.Type.String()
}
func isEmptyValue(v reflect.Value) bool {
switch v.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Interface, reflect.Ptr:
return v.IsNil()
}
return false
}
// 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 xml
import (
"bytes"
"encoding"
"errors"
"fmt"
"reflect"
"strconv"
"strings"
)
// BUG(rsc): Mapping between XML elements and data structures is inherently flawed:
// an XML element is an order-dependent collection of anonymous
// values, while a data structure is an order-independent collection
// of named values.
// See package json for a textual representation more suitable
// to data structures.
// Unmarshal parses the XML-encoded data and stores the result in
// the value pointed to by v, which must be an arbitrary struct,
// slice, or string. Well-formed data that does not fit into v is
// discarded.
//
// Because Unmarshal uses the reflect package, it can only assign
// to exported (upper case) fields. Unmarshal uses a case-sensitive
// comparison to match XML element names to tag values and struct
// field names.
//
// Unmarshal maps an XML element to a struct using the following rules.
// In the rules, the tag of a field refers to the value associated with the
// key 'xml' in the struct field's tag (see the example above).
//
// - If the struct has a field of type []byte or string with tag
// ",innerxml", Unmarshal accumulates the raw XML nested inside the
// element in that field. The rest of the rules still apply.
//
// - If the struct has a field named XMLName of type xml.Name,
// Unmarshal records the element name in that field.
//
// - If the XMLName field has an associated tag of the form
// "name" or "namespace-URL name", the XML element must have
// the given name (and, optionally, name space) or else Unmarshal
// returns an error.
//
// - If the XML element has an attribute whose name matches a
// struct field name with an associated tag containing ",attr" or
// the explicit name in a struct field tag of the form "name,attr",
// Unmarshal records the attribute value in that field.
//
// - If the XML element contains character data, that data is
// accumulated in the first struct field that has tag ",chardata".
// The struct field may have type []byte or string.
// If there is no such field, the character data is discarded.
//
// - If the XML element contains comments, they are accumulated in
// the first struct field that has tag ",comment". The struct
// field may have type []byte or string. If there is no such
// field, the comments are discarded.
//
// - If the XML element contains a sub-element whose name matches
// the prefix of a tag formatted as "a" or "a>b>c", unmarshal
// will descend into the XML structure looking for elements with the
// given names, and will map the innermost elements to that struct
// field. A tag starting with ">" is equivalent to one starting
// with the field name followed by ">".
//
// - If the XML element contains a sub-element whose name matches
// a struct field's XMLName tag and the struct field has no
// explicit name tag as per the previous rule, unmarshal maps
// the sub-element to that struct field.
//
// - If the XML element contains a sub-element whose name matches a
// field without any mode flags (",attr", ",chardata", etc), Unmarshal
// maps the sub-element to that struct field.
//
// - If the XML element contains a sub-element that hasn't matched any
// of the above rules and the struct has a field with tag ",any",
// unmarshal maps the sub-element to that struct field.
//
// - An anonymous struct field is handled as if the fields of its
// value were part of the outer struct.
//
// - A struct field with tag "-" is never unmarshalled into.
//
// Unmarshal maps an XML element to a string or []byte by saving the
// concatenation of that element's character data in the string or
// []byte. The saved []byte is never nil.
//
// Unmarshal maps an attribute value to a string or []byte by saving
// the value in the string or slice.
//
// Unmarshal maps an XML element to a slice by extending the length of
// the slice and mapping the element to the newly created value.
//
// Unmarshal maps an XML element or attribute value to a bool by
// setting it to the boolean value represented by the string.
//
// Unmarshal maps an XML element or attribute value to an integer or
// floating-point field by setting the field to the result of
// interpreting the string value in decimal. There is no check for
// overflow.
//
// Unmarshal maps an XML element to an xml.Name by recording the
// element name.
//
// Unmarshal maps an XML element to a pointer by setting the pointer
// to a freshly allocated value and then mapping the element to that value.
func Unmarshal(data []byte, v interface{}) error {
return NewDecoder(bytes.NewReader(data)).Decode(v)
}
// Decode works like xml.Unmarshal, except it reads the decoder
// stream to find the start element.
func (d *Decoder) Decode(v interface{}) error {
return d.DecodeElement(v, nil)
}
// DecodeElement works like xml.Unmarshal except that it takes
// a pointer to the start XML element to decode into v.
// It is useful when a client reads some raw XML tokens itself
// but also wants to defer to Unmarshal for some elements.
func (d *Decoder) DecodeElement(v interface{}, start *StartElement) error {
val := reflect.ValueOf(v)
if val.Kind() != reflect.Ptr {
return errors.New("non-pointer passed to Unmarshal")
}
return d.unmarshal(val.Elem(), start)
}
// An UnmarshalError represents an error in the unmarshalling process.
type UnmarshalError string
func (e UnmarshalError) Error() string { return string(e) }
// Unmarshaler is the interface implemented by objects that can unmarshal
// an XML element description of themselves.
//
// UnmarshalXML decodes a single XML element
// beginning with the given start element.
// If it returns an error, the outer call to Unmarshal stops and
// returns that error.
// UnmarshalXML must consume exactly one XML element.
// One common implementation strategy is to unmarshal into
// a separate value with a layout matching the expected XML
// using d.DecodeElement, and then to copy the data from
// that value into the receiver.
// Another common strategy is to use d.Token to process the
// XML object one token at a time.
// UnmarshalXML may not use d.RawToken.
type Unmarshaler interface {
UnmarshalXML(d *Decoder, start StartElement) error
}
// UnmarshalerAttr is the interface implemented by objects that can unmarshal
// an XML attribute description of themselves.
//
// UnmarshalXMLAttr decodes a single XML attribute.
// If it returns an error, the outer call to Unmarshal stops and
// returns that error.
// UnmarshalXMLAttr is used only for struct fields with the
// "attr" option in the field tag.
type UnmarshalerAttr interface {
UnmarshalXMLAttr(attr Attr) error
}
// receiverType returns the receiver type to use in an expression like "%s.MethodName".
func receiverType(val interface{}) string {
t := reflect.TypeOf(val)
if t.Name() != "" {
return t.String()
}
return "(" + t.String() + ")"
}
// unmarshalInterface unmarshals a single XML element into val.
// start is the opening tag of the element.
func (p *Decoder) unmarshalInterface(val Unmarshaler, start *StartElement) error {
// Record that decoder must stop at end tag corresponding to start.
p.pushEOF()
p.unmarshalDepth++
err := val.UnmarshalXML(p, *start)
p.unmarshalDepth--
if err != nil {
p.popEOF()
return err
}
if !p.popEOF() {
return fmt.Errorf("xml: %s.UnmarshalXML did not consume entire <%s> element", receiverType(val), start.Name.Local)
}
return nil
}
// unmarshalTextInterface unmarshals a single XML element into val.
// The chardata contained in the element (but not its children)
// is passed to the text unmarshaler.
func (p *Decoder) unmarshalTextInterface(val encoding.TextUnmarshaler, start *StartElement) error {
var buf []byte
depth := 1
for depth > 0 {
t, err := p.Token()
if err != nil {
return err
}
switch t := t.(type) {
case CharData:
if depth == 1 {
buf = append(buf, t...)
}
case StartElement:
depth++
case EndElement:
depth--
}
}
return val.UnmarshalText(buf)
}
// unmarshalAttr unmarshals a single XML attribute into val.
func (p *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error {
if val.Kind() == reflect.Ptr {
if val.IsNil() {
val.Set(reflect.New(val.Type().Elem()))
}
val = val.Elem()
}
if val.CanInterface() && val.Type().Implements(unmarshalerAttrType) {
// This is an unmarshaler with a non-pointer receiver,
// so it's likely to be incorrect, but we do what we're told.
return val.Interface().(UnmarshalerAttr).UnmarshalXMLAttr(attr)
}
if val.CanAddr() {
pv := val.Addr()
if pv.CanInterface() && pv.Type().Implements(unmarshalerAttrType) {
return pv.Interface().(UnmarshalerAttr).UnmarshalXMLAttr(attr)
}
}
// Not an UnmarshalerAttr; try encoding.TextUnmarshaler.
if val.CanInterface() && val.Type().Implements(textUnmarshalerType) {
// This is an unmarshaler with a non-pointer receiver,
// so it's likely to be incorrect, but we do what we're told.
return val.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(attr.Value))
}
if val.CanAddr() {
pv := val.Addr()
if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) {
return pv.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(attr.Value))
}
}
copyValue(val, []byte(attr.Value))
return nil
}
var (
unmarshalerType = reflect.TypeFor[Unmarshaler]()
unmarshalerAttrType = reflect.TypeFor[UnmarshalerAttr]()
textUnmarshalerType = reflect.TypeFor[encoding.TextUnmarshaler]()
)
// Unmarshal a single XML element into val.
func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
// Find start element if we need it.
if start == nil {
for {
tok, err := p.Token()
if err != nil {
return err
}
if t, ok := tok.(StartElement); ok {
start = &t
break
}
}
}
// Load value from interface, but only if the result will be
// usefully addressable.
if val.Kind() == reflect.Interface && !val.IsNil() {
e := val.Elem()
if e.Kind() == reflect.Ptr && !e.IsNil() {
val = e
}
}
if val.Kind() == reflect.Ptr {
if val.IsNil() {
val.Set(reflect.New(val.Type().Elem()))
}
val = val.Elem()
}
if val.CanInterface() && val.Type().Implements(unmarshalerType) {
// This is an unmarshaler with a non-pointer receiver,
// so it's likely to be incorrect, but we do what we're told.
return p.unmarshalInterface(val.Interface().(Unmarshaler), start)
}
if val.CanAddr() {
pv := val.Addr()
if pv.CanInterface() && pv.Type().Implements(unmarshalerType) {
return p.unmarshalInterface(pv.Interface().(Unmarshaler), start)
}
}
if val.CanInterface() && val.Type().Implements(textUnmarshalerType) {
return p.unmarshalTextInterface(val.Interface().(encoding.TextUnmarshaler), start)
}
if val.CanAddr() {
pv := val.Addr()
if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) {
return p.unmarshalTextInterface(pv.Interface().(encoding.TextUnmarshaler), start)
}
}
var (
data []byte
saveData reflect.Value
comment []byte
saveComment reflect.Value
saveXML reflect.Value
saveXMLIndex int
saveXMLData []byte
saveAny reflect.Value
sv reflect.Value
tinfo *typeInfo
err error
)
switch v := val; v.Kind() {
default:
return errors.New("unknown type " + v.Type().String())
case reflect.Interface:
// TODO: For now, simply ignore the field. In the near
// future we may choose to unmarshal the start
// element on it, if not nil.
return p.Skip()
case reflect.Slice:
typ := v.Type()
if typ.Elem().Kind() == reflect.Uint8 {
// []byte
saveData = v
break
}
// Slice of element values.
// Grow slice.
n := v.Len()
if n >= v.Cap() {
ncap := 2 * n
if ncap < 4 {
ncap = 4
}
new := reflect.MakeSlice(typ, n, ncap)
reflect.Copy(new, v)
v.Set(new)
}
v.SetLen(n + 1)
// Recur to read element into slice.
if err := p.unmarshal(v.Index(n), start); err != nil {
v.SetLen(n)
return err
}
return nil
case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.String:
saveData = v
case reflect.Struct:
typ := v.Type()
if typ == nameType {
v.Set(reflect.ValueOf(start.Name))
break
}
sv = v
tinfo, err = getTypeInfo(typ)
if err != nil {
return err
}
// Validate and assign element name.
if tinfo.xmlname != nil {
finfo := tinfo.xmlname
if finfo.name != "" && finfo.name != start.Name.Local {
return UnmarshalError("expected element type <" + finfo.name + "> but have <" + start.Name.Local + ">")
}
if finfo.xmlns != "" && finfo.xmlns != start.Name.Space {
e := "expected element <" + finfo.name + "> in name space " + finfo.xmlns + " but have "
if start.Name.Space == "" {
e += "no name space"
} else {
e += start.Name.Space
}
return UnmarshalError(e)
}
fv := finfo.value(sv)
if _, ok := fv.Interface().(Name); ok {
fv.Set(reflect.ValueOf(start.Name))
}
}
// Assign attributes.
// Also, determine whether we need to save character data or comments.
for i := range tinfo.fields {
finfo := &tinfo.fields[i]
switch finfo.flags & fMode {
case fAttr:
strv := finfo.value(sv)
// Look for attribute.
for _, a := range start.Attr {
if a.Name.Local == finfo.name && (finfo.xmlns == "" || finfo.xmlns == a.Name.Space) {
if err := p.unmarshalAttr(strv, a); err != nil {
return err
}
break
}
}
case fCharData:
if !saveData.IsValid() {
saveData = finfo.value(sv)
}
case fComment:
if !saveComment.IsValid() {
saveComment = finfo.value(sv)
}
case fAny, fAny | fElement:
if !saveAny.IsValid() {
saveAny = finfo.value(sv)
}
case fInnerXml:
if !saveXML.IsValid() {
saveXML = finfo.value(sv)
if p.saved == nil {
saveXMLIndex = 0
p.saved = new(bytes.Buffer)
} else {
saveXMLIndex = p.savedOffset()
}
}
}
}
}
// Find end element.
// Process sub-elements along the way.
Loop:
for {
var savedOffset int
if saveXML.IsValid() {
savedOffset = p.savedOffset()
}
tok, err := p.Token()
if err != nil {
return err
}
switch t := tok.(type) {
case StartElement:
consumed := false
if sv.IsValid() {
consumed, err = p.unmarshalPath(tinfo, sv, nil, &t)
if err != nil {
return err
}
if !consumed && saveAny.IsValid() {
consumed = true
if err := p.unmarshal(saveAny, &t); err != nil {
return err
}
}
}
if !consumed {
if err := p.Skip(); err != nil {
return err
}
}
case EndElement:
if saveXML.IsValid() {
saveXMLData = p.saved.Bytes()[saveXMLIndex:savedOffset]
if saveXMLIndex == 0 {
p.saved = nil
}
}
break Loop
case CharData:
if saveData.IsValid() {
data = append(data, t...)
}
case Comment:
if saveComment.IsValid() {
comment = append(comment, t...)
}
}
}
if saveData.IsValid() && saveData.CanInterface() && saveData.Type().Implements(textUnmarshalerType) {
if err := saveData.Interface().(encoding.TextUnmarshaler).UnmarshalText(data); err != nil {
return err
}
saveData = reflect.Value{}
}
if saveData.IsValid() && saveData.CanAddr() {
pv := saveData.Addr()
if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) {
if err := pv.Interface().(encoding.TextUnmarshaler).UnmarshalText(data); err != nil {
return err
}
saveData = reflect.Value{}
}
}
if err := copyValue(saveData, data); err != nil {
return err
}
switch t := saveComment; t.Kind() {
case reflect.String:
t.SetString(string(comment))
case reflect.Slice:
t.Set(reflect.ValueOf(comment))
}
switch t := saveXML; t.Kind() {
case reflect.String:
t.SetString(string(saveXMLData))
case reflect.Slice:
t.Set(reflect.ValueOf(saveXMLData))
}
return nil
}
func copyValue(dst reflect.Value, src []byte) (err error) {
dst0 := dst
if dst.Kind() == reflect.Ptr {
if dst.IsNil() {
dst.Set(reflect.New(dst.Type().Elem()))
}
dst = dst.Elem()
}
// Save accumulated data.
switch dst.Kind() {
case reflect.Invalid:
// Probably a comment.
default:
return errors.New("cannot unmarshal into " + dst0.Type().String())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
itmp, err := strconv.ParseInt(string(src), 10, dst.Type().Bits())
if err != nil {
return err
}
dst.SetInt(itmp)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
utmp, err := strconv.ParseUint(string(src), 10, dst.Type().Bits())
if err != nil {
return err
}
dst.SetUint(utmp)
case reflect.Float32, reflect.Float64:
ftmp, err := strconv.ParseFloat(string(src), dst.Type().Bits())
if err != nil {
return err
}
dst.SetFloat(ftmp)
case reflect.Bool:
value, err := strconv.ParseBool(strings.TrimSpace(string(src)))
if err != nil {
return err
}
dst.SetBool(value)
case reflect.String:
dst.SetString(string(src))
case reflect.Slice:
if len(src) == 0 {
// non-nil to flag presence
src = []byte{}
}
dst.SetBytes(src)
}
return nil
}
// unmarshalPath walks down an XML structure looking for wanted
// paths, and calls unmarshal on them.
// The consumed result tells whether XML elements have been consumed
// from the Decoder until start's matching end element, or if it's
// still untouched because start is uninteresting for sv's fields.
func (p *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []string, start *StartElement) (consumed bool, err error) {
recurse := false
Loop:
for i := range tinfo.fields {
finfo := &tinfo.fields[i]
if finfo.flags&fElement == 0 || len(finfo.parents) < len(parents) || finfo.xmlns != "" && finfo.xmlns != start.Name.Space {
continue
}
for j := range parents {
if parents[j] != finfo.parents[j] {
continue Loop
}
}
if len(finfo.parents) == len(parents) && finfo.name == start.Name.Local {
// It's a perfect match, unmarshal the field.
return true, p.unmarshal(finfo.value(sv), start)
}
if len(finfo.parents) > len(parents) && finfo.parents[len(parents)] == start.Name.Local {
// It's a prefix for the field. Break and recurse
// since it's not ok for one field path to be itself
// the prefix for another field path.
recurse = true
// We can reuse the same slice as long as we
// don't try to append to it.
parents = finfo.parents[:len(parents)+1]
break
}
}
if !recurse {
// We have no business with this element.
return false, nil
}
// The element is not a perfect match for any field, but one
// or more fields have the path to this element as a parent
// prefix. Recurse and attempt to match these.
for {
var tok Token
tok, err = p.Token()
if err != nil {
return true, err
}
switch t := tok.(type) {
case StartElement:
consumed2, err := p.unmarshalPath(tinfo, sv, parents, &t)
if err != nil {
return true, err
}
if !consumed2 {
if err := p.Skip(); err != nil {
return true, err
}
}
case EndElement:
return true, nil
}
}
}
// Skip reads tokens until it has consumed the end element
// matching the most recent start element already consumed.
// It recurs if it encounters a start element, so it can be used to
// skip nested structures.
// It returns nil if it finds an end element matching the start
// element; otherwise it returns an error describing the problem.
func (d *Decoder) Skip() error {
for {
tok, err := d.Token()
if err != nil {
return err
}
switch tok.(type) {
case StartElement:
if err := d.Skip(); err != nil {
return err
}
case EndElement:
return nil
}
}
}
// Copyright 2011 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 xml
import (
"fmt"
"reflect"
"strings"
"sync"
)
// typeInfo holds details for the xml representation of a type.
type typeInfo struct {
xmlname *fieldInfo
fields []fieldInfo
}
// fieldInfo holds details for the xml representation of a single field.
type fieldInfo struct {
idx []int
name string
xmlns string
flags fieldFlags
parents []string
}
type fieldFlags int
const (
fElement fieldFlags = 1 << iota
fAttr
fCharData
fInnerXml
fComment
fAny
fOmitEmpty
fMode = fElement | fAttr | fCharData | fInnerXml | fComment | fAny
)
var tinfoMap = make(map[reflect.Type]*typeInfo)
var tinfoLock sync.RWMutex
var nameType = reflect.TypeFor[Name]()
// getTypeInfo returns the typeInfo structure with details necessary
// for marshalling and unmarshalling typ.
func getTypeInfo(typ reflect.Type) (*typeInfo, error) {
tinfoLock.RLock()
tinfo, ok := tinfoMap[typ]
tinfoLock.RUnlock()
if ok {
return tinfo, nil
}
tinfo = &typeInfo{}
if typ.Kind() == reflect.Struct && typ != nameType {
n := typ.NumField()
for i := 0; i < n; i++ {
f := typ.Field(i)
if f.PkgPath != "" || f.Tag.Get("xml") == "-" {
continue // Private field
}
// For embedded structs, embed its fields.
if f.Anonymous {
t := f.Type
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() == reflect.Struct {
inner, err := getTypeInfo(t)
if err != nil {
return nil, err
}
if tinfo.xmlname == nil {
tinfo.xmlname = inner.xmlname
}
for _, finfo := range inner.fields {
finfo.idx = append([]int{i}, finfo.idx...)
if err := addFieldInfo(typ, tinfo, &finfo); err != nil {
return nil, err
}
}
continue
}
}
finfo, err := structFieldInfo(typ, &f)
if err != nil {
return nil, err
}
if f.Name == "XMLName" {
tinfo.xmlname = finfo
continue
}
// Add the field if it doesn't conflict with other fields.
if err := addFieldInfo(typ, tinfo, finfo); err != nil {
return nil, err
}
}
}
tinfoLock.Lock()
tinfoMap[typ] = tinfo
tinfoLock.Unlock()
return tinfo, nil
}
// structFieldInfo builds and returns a fieldInfo for f.
func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, error) {
finfo := &fieldInfo{idx: f.Index}
// Split the tag from the xml namespace if necessary.
tag := f.Tag.Get("xml")
if i := strings.Index(tag, " "); i >= 0 {
finfo.xmlns, tag = tag[:i], tag[i+1:]
}
// Parse flags.
tokens := strings.Split(tag, ",")
if len(tokens) == 1 {
finfo.flags = fElement
} else {
tag = tokens[0]
for _, flag := range tokens[1:] {
switch flag {
case "attr":
finfo.flags |= fAttr
case "chardata":
finfo.flags |= fCharData
case "innerxml":
finfo.flags |= fInnerXml
case "comment":
finfo.flags |= fComment
case "any":
finfo.flags |= fAny
case "omitempty":
finfo.flags |= fOmitEmpty
}
}
// Validate the flags used.
valid := true
switch mode := finfo.flags & fMode; mode {
case 0:
finfo.flags |= fElement
case fAttr, fCharData, fInnerXml, fComment, fAny:
if f.Name == "XMLName" || tag != "" && mode != fAttr {
valid = false
}
default:
// This will also catch multiple modes in a single field.
valid = false
}
if finfo.flags&fMode == fAny {
finfo.flags |= fElement
}
if finfo.flags&fOmitEmpty != 0 && finfo.flags&(fElement|fAttr) == 0 {
valid = false
}
if !valid {
return nil, fmt.Errorf("xml: invalid tag in field %s of type %s: %q",
f.Name, typ, f.Tag.Get("xml"))
}
}
// Use of xmlns without a name is not allowed.
if finfo.xmlns != "" && tag == "" {
return nil, fmt.Errorf("xml: namespace without name in field %s of type %s: %q",
f.Name, typ, f.Tag.Get("xml"))
}
if f.Name == "XMLName" {
// The XMLName field records the XML element name. Don't
// process it as usual because its name should default to
// empty rather than to the field name.
finfo.name = tag
return finfo, nil
}
if tag == "" {
// If the name part of the tag is completely empty, get
// default from XMLName of underlying struct if feasible,
// or field name otherwise.
if xmlname := lookupXMLName(f.Type); xmlname != nil {
finfo.xmlns, finfo.name = xmlname.xmlns, xmlname.name
} else {
finfo.name = f.Name
}
return finfo, nil
}
if finfo.xmlns == "" && finfo.flags&fAttr == 0 {
// If it's an element no namespace specified, get the default
// from the XMLName of enclosing struct if possible.
if xmlname := lookupXMLName(typ); xmlname != nil {
finfo.xmlns = xmlname.xmlns
}
}
// Prepare field name and parents.
parents := strings.Split(tag, ">")
if parents[0] == "" {
parents[0] = f.Name
}
if parents[len(parents)-1] == "" {
return nil, fmt.Errorf("xml: trailing '>' in field %s of type %s", f.Name, typ)
}
finfo.name = parents[len(parents)-1]
if len(parents) > 1 {
if (finfo.flags & fElement) == 0 {
return nil, fmt.Errorf("xml: %s chain not valid with %s flag", tag, strings.Join(tokens[1:], ","))
}
finfo.parents = parents[:len(parents)-1]
}
// If the field type has an XMLName field, the names must match
// so that the behavior of both marshalling and unmarshalling
// is straightforward and unambiguous.
if finfo.flags&fElement != 0 {
ftyp := f.Type
xmlname := lookupXMLName(ftyp)
if xmlname != nil && xmlname.name != finfo.name {
return nil, fmt.Errorf("xml: name %q in tag of %s.%s conflicts with name %q in %s.XMLName",
finfo.name, typ, f.Name, xmlname.name, ftyp)
}
}
return finfo, nil
}
// lookupXMLName returns the fieldInfo for typ's XMLName field
// in case it exists and has a valid xml field tag, otherwise
// it returns nil.
func lookupXMLName(typ reflect.Type) (xmlname *fieldInfo) {
for typ.Kind() == reflect.Ptr {
typ = typ.Elem()
}
if typ.Kind() != reflect.Struct {
return nil
}
for i, n := 0, typ.NumField(); i < n; i++ {
f := typ.Field(i)
if f.Name != "XMLName" {
continue
}
finfo, err := structFieldInfo(typ, &f)
if finfo.name != "" && err == nil {
return finfo
}
// Also consider errors as a non-existent field tag
// and let getTypeInfo itself report the error.
break
}
return nil
}
// addFieldInfo adds finfo to tinfo.fields if there are no
// conflicts, or if conflicts arise from previous fields that were
// obtained from deeper embedded structures than finfo. In the latter
// case, the conflicting entries are dropped.
// A conflict occurs when the path (parent + name) to a field is
// itself a prefix of another path, or when two paths match exactly.
// It is okay for field paths to share a common, shorter prefix.
func addFieldInfo(typ reflect.Type, tinfo *typeInfo, newf *fieldInfo) error {
var conflicts []int
Loop:
// First, figure all conflicts. Most working code will have none.
for i := range tinfo.fields {
oldf := &tinfo.fields[i]
if oldf.flags&fMode != newf.flags&fMode {
continue
}
if oldf.xmlns != "" && newf.xmlns != "" && oldf.xmlns != newf.xmlns {
continue
}
minl := min(len(newf.parents), len(oldf.parents))
for p := 0; p < minl; p++ {
if oldf.parents[p] != newf.parents[p] {
continue Loop
}
}
if len(oldf.parents) > len(newf.parents) {
if oldf.parents[len(newf.parents)] == newf.name {
conflicts = append(conflicts, i)
}
} else if len(oldf.parents) < len(newf.parents) {
if newf.parents[len(oldf.parents)] == oldf.name {
conflicts = append(conflicts, i)
}
} else {
if newf.name == oldf.name {
conflicts = append(conflicts, i)
}
}
}
// Without conflicts, add the new field and return.
if conflicts == nil {
tinfo.fields = append(tinfo.fields, *newf)
return nil
}
// If any conflict is shallower, ignore the new field.
// This matches the Go field resolution on embedding.
for _, i := range conflicts {
if len(tinfo.fields[i].idx) < len(newf.idx) {
return nil
}
}
// Otherwise, if any of them is at the same depth level, it's an error.
for _, i := range conflicts {
oldf := &tinfo.fields[i]
if len(oldf.idx) == len(newf.idx) {
f1 := typ.FieldByIndex(oldf.idx)
f2 := typ.FieldByIndex(newf.idx)
return &TagPathError{typ, f1.Name, f1.Tag.Get("xml"), f2.Name, f2.Tag.Get("xml")}
}
}
// Otherwise, the new field is shallower, and thus takes precedence,
// so drop the conflicting fields from tinfo and append the new one.
for c := len(conflicts) - 1; c >= 0; c-- {
i := conflicts[c]
copy(tinfo.fields[i:], tinfo.fields[i+1:])
tinfo.fields = tinfo.fields[:len(tinfo.fields)-1]
}
tinfo.fields = append(tinfo.fields, *newf)
return nil
}
// A TagPathError represents an error in the unmarshalling process
// caused by the use of field tags with conflicting paths.
type TagPathError struct {
Struct reflect.Type
Field1, Tag1 string
Field2, Tag2 string
}
func (e *TagPathError) Error() string {
return fmt.Sprintf("%s field %q with tag %q conflicts with field %q with tag %q", e.Struct, e.Field1, e.Tag1, e.Field2, e.Tag2)
}
// value returns v's field value corresponding to finfo.
// It's equivalent to v.FieldByIndex(finfo.idx), but initializes
// and dereferences pointers as necessary.
func (finfo *fieldInfo) value(v reflect.Value) reflect.Value {
for i, x := range finfo.idx {
if i > 0 {
t := v.Type()
if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct {
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))
}
v = v.Elem()
}
}
v = v.Field(x)
}
return v
}
// 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 xml implements a simple XML 1.0 parser that
// understands XML name spaces.
package xml
// References:
// Annotated XML spec: http://www.xml.com/axml/testaxml.htm
// XML name spaces: http://www.w3.org/TR/REC-xml-names/
// TODO(rsc):
// Test error handling.
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"strconv"
"strings"
"unicode"
"unicode/utf8"
)
// A SyntaxError represents a syntax error in the XML input stream.
type SyntaxError struct {
Msg string
Line int
}
func (e *SyntaxError) Error() string {
return "XML syntax error on line " + strconv.Itoa(e.Line) + ": " + e.Msg
}
// A Name represents an XML name (Local) annotated with a name space
// identifier (Space). In tokens returned by Decoder.Token, the Space
// identifier is given as a canonical URL, not the short prefix used in
// the document being parsed.
//
// As a special case, XML namespace declarations will use the literal
// string "xmlns" for the Space field instead of the fully resolved URL.
// See Encoder.EncodeToken for more information on namespace encoding
// behaviour.
type Name struct {
Space, Local string
}
// isNamespace reports whether the name is a namespace-defining name.
func (name Name) isNamespace() bool {
return name.Local == "xmlns" || name.Space == "xmlns"
}
// An Attr represents an attribute in an XML element (Name=Value).
type Attr struct {
Name Name
Value string
}
// A Token is an interface holding one of the token types:
// StartElement, EndElement, CharData, Comment, ProcInst, or Directive.
type Token interface{}
// A StartElement represents an XML start element.
type StartElement struct {
Name Name
Attr []Attr
}
func (e StartElement) Copy() StartElement {
attrs := make([]Attr, len(e.Attr))
copy(attrs, e.Attr)
e.Attr = attrs
return e
}
// End returns the corresponding XML end element.
func (e StartElement) End() EndElement {
return EndElement{e.Name}
}
// setDefaultNamespace sets the namespace of the element
// as the default for all elements contained within it.
func (e *StartElement) setDefaultNamespace() {
if e.Name.Space == "" {
// If there's no namespace on the element, don't
// set the default. Strictly speaking this might be wrong, as
// we can't tell if the element had no namespace set
// or was just using the default namespace.
return
}
// Don't add a default name space if there's already one set.
for _, attr := range e.Attr {
if attr.Name.Space == "" && attr.Name.Local == "xmlns" {
return
}
}
e.Attr = append(e.Attr, Attr{
Name: Name{
Local: "xmlns",
},
Value: e.Name.Space,
})
}
// An EndElement represents an XML end element.
type EndElement struct {
Name Name
}
// A CharData represents XML character data (raw text),
// in which XML escape sequences have been replaced by
// the characters they represent.
type CharData []byte
func makeCopy(b []byte) []byte {
b1 := make([]byte, len(b))
copy(b1, b)
return b1
}
func (c CharData) Copy() CharData { return CharData(makeCopy(c)) }
// A Comment represents an XML comment of the form <!--comment-->.
// The bytes do not include the <!-- and --> comment markers.
type Comment []byte
func (c Comment) Copy() Comment { return Comment(makeCopy(c)) }
// A ProcInst represents an XML processing instruction of the form <?target inst?>
type ProcInst struct {
Target string
Inst []byte
}
func (p ProcInst) Copy() ProcInst {
p.Inst = makeCopy(p.Inst)
return p
}
// A Directive represents an XML directive of the form <!text>.
// The bytes do not include the <! and > markers.
type Directive []byte
func (d Directive) Copy() Directive { return Directive(makeCopy(d)) }
// CopyToken returns a copy of a Token.
func CopyToken(t Token) Token {
switch v := t.(type) {
case CharData:
return v.Copy()
case Comment:
return v.Copy()
case Directive:
return v.Copy()
case ProcInst:
return v.Copy()
case StartElement:
return v.Copy()
}
return t
}
// A Decoder represents an XML parser reading a particular input stream.
// The parser assumes that its input is encoded in UTF-8.
type Decoder struct {
// Strict defaults to true, enforcing the requirements
// of the XML specification.
// If set to false, the parser allows input containing common
// mistakes:
// * If an element is missing an end tag, the parser invents
// end tags as necessary to keep the return values from Token
// properly balanced.
// * In attribute values and character data, unknown or malformed
// character entities (sequences beginning with &) are left alone.
//
// Setting:
//
// d.Strict = false;
// d.AutoClose = HTMLAutoClose;
// d.Entity = HTMLEntity
//
// creates a parser that can handle typical HTML.
//
// Strict mode does not enforce the requirements of the XML name spaces TR.
// In particular it does not reject name space tags using undefined prefixes.
// Such tags are recorded with the unknown prefix as the name space URL.
Strict bool
// When Strict == false, AutoClose indicates a set of elements to
// consider closed immediately after they are opened, regardless
// of whether an end element is present.
AutoClose []string
// Entity can be used to map non-standard entity names to string replacements.
// The parser behaves as if these standard mappings are present in the map,
// regardless of the actual map content:
//
// "lt": "<",
// "gt": ">",
// "amp": "&",
// "apos": "'",
// "quot": `"`,
Entity map[string]string
// CharsetReader, if non-nil, defines a function to generate
// charset-conversion readers, converting from the provided
// non-UTF-8 charset into UTF-8. If CharsetReader is nil or
// returns an error, parsing stops with an error. One of the
// the CharsetReader's result values must be non-nil.
CharsetReader func(charset string, input io.Reader) (io.Reader, error)
// DefaultSpace sets the default name space used for unadorned tags,
// as if the entire XML stream were wrapped in an element containing
// the attribute xmlns="DefaultSpace".
DefaultSpace string
r io.ByteReader
buf bytes.Buffer
saved *bytes.Buffer
stk *stack
free *stack
needClose bool
toClose Name
nextToken Token
nextByte int
ns map[string]string
err error
line int
offset int64
unmarshalDepth int
}
// NewDecoder creates a new XML parser reading from r.
// If r does not implement io.ByteReader, NewDecoder will
// do its own buffering.
func NewDecoder(r io.Reader) *Decoder {
d := &Decoder{
ns: make(map[string]string),
nextByte: -1,
line: 1,
Strict: true,
}
d.switchToReader(r)
return d
}
// Token returns the next XML token in the input stream.
// At the end of the input stream, Token returns nil, io.EOF.
//
// Slices of bytes in the returned token data refer to the
// parser's internal buffer and remain valid only until the next
// call to Token. To acquire a copy of the bytes, call CopyToken
// or the token's Copy method.
//
// Token expands self-closing elements such as <br/>
// into separate start and end elements returned by successive calls.
//
// Token guarantees that the StartElement and EndElement
// tokens it returns are properly nested and matched:
// if Token encounters an unexpected end element,
// it will return an error.
//
// Token implements XML name spaces as described by
// http://www.w3.org/TR/REC-xml-names/. Each of the
// Name structures contained in the Token has the Space
// set to the URL identifying its name space when known.
// If Token encounters an unrecognized name space prefix,
// it uses the prefix as the Space rather than report an error.
func (d *Decoder) Token() (t Token, err error) {
if d.stk != nil && d.stk.kind == stkEOF {
err = io.EOF
return
}
if d.nextToken != nil {
t = d.nextToken
d.nextToken = nil
} else if t, err = d.rawToken(); err != nil {
return
}
if !d.Strict {
if t1, ok := d.autoClose(t); ok {
d.nextToken = t
t = t1
}
}
switch t1 := t.(type) {
case StartElement:
// In XML name spaces, the translations listed in the
// attributes apply to the element name and
// to the other attribute names, so process
// the translations first.
for _, a := range t1.Attr {
if a.Name.Space == "xmlns" {
v, ok := d.ns[a.Name.Local]
d.pushNs(a.Name.Local, v, ok)
d.ns[a.Name.Local] = a.Value
}
if a.Name.Space == "" && a.Name.Local == "xmlns" {
// Default space for untagged names
v, ok := d.ns[""]
d.pushNs("", v, ok)
d.ns[""] = a.Value
}
}
d.translate(&t1.Name, true)
for i := range t1.Attr {
d.translate(&t1.Attr[i].Name, false)
}
d.pushElement(t1.Name)
t = t1
case EndElement:
d.translate(&t1.Name, true)
if !d.popElement(&t1) {
return nil, d.err
}
t = t1
}
return
}
const xmlURL = "http://www.w3.org/XML/1998/namespace"
// Apply name space translation to name n.
// The default name space (for Space=="")
// applies only to element names, not to attribute names.
func (d *Decoder) translate(n *Name, isElementName bool) {
switch {
case n.Space == "xmlns":
return
case n.Space == "" && !isElementName:
return
case n.Space == "xml":
n.Space = xmlURL
case n.Space == "" && n.Local == "xmlns":
return
}
if v, ok := d.ns[n.Space]; ok {
n.Space = v
} else if n.Space == "" {
n.Space = d.DefaultSpace
}
}
func (d *Decoder) switchToReader(r io.Reader) {
// Get efficient byte at a time reader.
// Assume that if reader has its own
// ReadByte, it's efficient enough.
// Otherwise, use bufio.
if rb, ok := r.(io.ByteReader); ok {
d.r = rb
} else {
d.r = bufio.NewReader(r)
}
}
// Parsing state - stack holds old name space translations
// and the current set of open elements. The translations to pop when
// ending a given tag are *below* it on the stack, which is
// more work but forced on us by XML.
type stack struct {
next *stack
kind int
name Name
ok bool
}
const (
stkStart = iota
stkNs
stkEOF
)
func (d *Decoder) push(kind int) *stack {
s := d.free
if s != nil {
d.free = s.next
} else {
s = new(stack)
}
s.next = d.stk
s.kind = kind
d.stk = s
return s
}
func (d *Decoder) pop() *stack {
s := d.stk
if s != nil {
d.stk = s.next
s.next = d.free
d.free = s
}
return s
}
// Record that after the current element is finished
// (that element is already pushed on the stack)
// Token should return EOF until popEOF is called.
func (d *Decoder) pushEOF() {
// Walk down stack to find Start.
// It might not be the top, because there might be stkNs
// entries above it.
start := d.stk
for start.kind != stkStart {
start = start.next
}
// The stkNs entries below a start are associated with that
// element too; skip over them.
for start.next != nil && start.next.kind == stkNs {
start = start.next
}
s := d.free
if s != nil {
d.free = s.next
} else {
s = new(stack)
}
s.kind = stkEOF
s.next = start.next
start.next = s
}
// Undo a pushEOF.
// The element must have been finished, so the EOF should be at the top of the stack.
func (d *Decoder) popEOF() bool {
if d.stk == nil || d.stk.kind != stkEOF {
return false
}
d.pop()
return true
}
// Record that we are starting an element with the given name.
func (d *Decoder) pushElement(name Name) {
s := d.push(stkStart)
s.name = name
}
// Record that we are changing the value of ns[local].
// The old value is url, ok.
func (d *Decoder) pushNs(local string, url string, ok bool) {
s := d.push(stkNs)
s.name.Local = local
s.name.Space = url
s.ok = ok
}
// Creates a SyntaxError with the current line number.
func (d *Decoder) syntaxError(msg string) error {
return &SyntaxError{Msg: msg, Line: d.line}
}
// Record that we are ending an element with the given name.
// The name must match the record at the top of the stack,
// which must be a pushElement record.
// After popping the element, apply any undo records from
// the stack to restore the name translations that existed
// before we saw this element.
func (d *Decoder) popElement(t *EndElement) bool {
s := d.pop()
name := t.Name
switch {
case s == nil || s.kind != stkStart:
d.err = d.syntaxError("unexpected end element </" + name.Local + ">")
return false
case s.name.Local != name.Local:
if !d.Strict {
d.needClose = true
d.toClose = t.Name
t.Name = s.name
return true
}
d.err = d.syntaxError("element <" + s.name.Local + "> closed by </" + name.Local + ">")
return false
case s.name.Space != name.Space:
d.err = d.syntaxError("element <" + s.name.Local + "> in space " + s.name.Space +
"closed by </" + name.Local + "> in space " + name.Space)
return false
}
// Pop stack until a Start or EOF is on the top, undoing the
// translations that were associated with the element we just closed.
for d.stk != nil && d.stk.kind != stkStart && d.stk.kind != stkEOF {
s := d.pop()
if s.ok {
d.ns[s.name.Local] = s.name.Space
} else {
delete(d.ns, s.name.Local)
}
}
return true
}
// If the top element on the stack is autoclosing and
// t is not the end tag, invent the end tag.
func (d *Decoder) autoClose(t Token) (Token, bool) {
if d.stk == nil || d.stk.kind != stkStart {
return nil, false
}
name := strings.ToLower(d.stk.name.Local)
for _, s := range d.AutoClose {
if strings.ToLower(s) == name {
// This one should be auto closed if t doesn't close it.
et, ok := t.(EndElement)
if !ok || et.Name.Local != name {
return EndElement{d.stk.name}, true
}
break
}
}
return nil, false
}
var errRawToken = errors.New("xml: cannot use RawToken from UnmarshalXML method")
// RawToken is like Token but does not verify that
// start and end elements match and does not translate
// name space prefixes to their corresponding URLs.
func (d *Decoder) RawToken() (Token, error) {
if d.unmarshalDepth > 0 {
return nil, errRawToken
}
return d.rawToken()
}
func (d *Decoder) rawToken() (Token, error) {
if d.err != nil {
return nil, d.err
}
if d.needClose {
// The last element we read was self-closing and
// we returned just the StartElement half.
// Return the EndElement half now.
d.needClose = false
return EndElement{d.toClose}, nil
}
b, ok := d.getc()
if !ok {
return nil, d.err
}
if b != '<' {
// Text section.
d.ungetc(b)
data := d.text(-1, false)
if data == nil {
return nil, d.err
}
return CharData(data), nil
}
if b, ok = d.mustgetc(); !ok {
return nil, d.err
}
switch b {
case '/':
// </: End element
var name Name
if name, ok = d.nsname(); !ok {
if d.err == nil {
d.err = d.syntaxError("expected element name after </")
}
return nil, d.err
}
d.space()
if b, ok = d.mustgetc(); !ok {
return nil, d.err
}
if b != '>' {
d.err = d.syntaxError("invalid characters between </" + name.Local + " and >")
return nil, d.err
}
return EndElement{name}, nil
case '?':
// <?: Processing instruction.
var target string
if target, ok = d.name(); !ok {
if d.err == nil {
d.err = d.syntaxError("expected target name after <?")
}
return nil, d.err
}
d.space()
d.buf.Reset()
var b0 byte
for {
if b, ok = d.mustgetc(); !ok {
return nil, d.err
}
d.buf.WriteByte(b)
if b0 == '?' && b == '>' {
break
}
b0 = b
}
data := d.buf.Bytes()
data = data[0 : len(data)-2] // chop ?>
if target == "xml" {
content := string(data)
ver := procInst("version", content)
if ver != "" && ver != "1.0" {
d.err = fmt.Errorf("xml: unsupported version %q; only version 1.0 is supported", ver)
return nil, d.err
}
enc := procInst("encoding", content)
if enc != "" && enc != "utf-8" && enc != "UTF-8" {
if d.CharsetReader == nil {
d.err = fmt.Errorf("xml: encoding %q declared but Decoder.CharsetReader is nil", enc)
return nil, d.err
}
newr, err := d.CharsetReader(enc, d.r.(io.Reader))
if err != nil {
d.err = fmt.Errorf("xml: opening charset %q: %v", enc, err)
return nil, d.err
}
if newr == nil {
panic("CharsetReader returned a nil Reader for charset " + enc)
}
d.switchToReader(newr)
}
}
return ProcInst{target, data}, nil
case '!':
// <!: Maybe comment, maybe CDATA.
if b, ok = d.mustgetc(); !ok {
return nil, d.err
}
switch b {
case '-': // <!-
// Probably <!-- for a comment.
if b, ok = d.mustgetc(); !ok {
return nil, d.err
}
if b != '-' {
d.err = d.syntaxError("invalid sequence <!- not part of <!--")
return nil, d.err
}
// Look for terminator.
d.buf.Reset()
var b0, b1 byte
for {
if b, ok = d.mustgetc(); !ok {
return nil, d.err
}
d.buf.WriteByte(b)
if b0 == '-' && b1 == '-' && b == '>' {
break
}
b0, b1 = b1, b
}
data := d.buf.Bytes()
data = data[0 : len(data)-3] // chop -->
return Comment(data), nil
case '[': // <![
// Probably <![CDATA[.
for i := 0; i < 6; i++ {
if b, ok = d.mustgetc(); !ok {
return nil, d.err
}
if b != "CDATA["[i] {
d.err = d.syntaxError("invalid <![ sequence")
return nil, d.err
}
}
// Have <![CDATA[. Read text until ]]>.
data := d.text(-1, true)
if data == nil {
return nil, d.err
}
return CharData(data), nil
}
// Probably a directive: <!DOCTYPE ...>, <!ENTITY ...>, etc.
// We don't care, but accumulate for caller. Quoted angle
// brackets do not count for nesting.
d.buf.Reset()
d.buf.WriteByte(b)
inquote := uint8(0)
depth := 0
for {
if b, ok = d.mustgetc(); !ok {
return nil, d.err
}
if inquote == 0 && b == '>' && depth == 0 {
break
}
HandleB:
d.buf.WriteByte(b)
switch {
case b == inquote:
inquote = 0
case inquote != 0:
// in quotes, no special action
case b == '\'' || b == '"':
inquote = b
case b == '>' && inquote == 0:
depth--
case b == '<' && inquote == 0:
// Look for <!-- to begin comment.
s := "!--"
for i := 0; i < len(s); i++ {
if b, ok = d.mustgetc(); !ok {
return nil, d.err
}
if b != s[i] {
for j := 0; j < i; j++ {
d.buf.WriteByte(s[j])
}
depth++
goto HandleB
}
}
// Remove < that was written above.
d.buf.Truncate(d.buf.Len() - 1)
// Look for terminator.
var b0, b1 byte
for {
if b, ok = d.mustgetc(); !ok {
return nil, d.err
}
if b0 == '-' && b1 == '-' && b == '>' {
break
}
b0, b1 = b1, b
}
}
}
return Directive(d.buf.Bytes()), nil
}
// Must be an open element like <a href="foo">
d.ungetc(b)
var (
name Name
empty bool
attr []Attr
)
if name, ok = d.nsname(); !ok {
if d.err == nil {
d.err = d.syntaxError("expected element name after <")
}
return nil, d.err
}
attr = []Attr{}
for {
d.space()
if b, ok = d.mustgetc(); !ok {
return nil, d.err
}
if b == '/' {
empty = true
if b, ok = d.mustgetc(); !ok {
return nil, d.err
}
if b != '>' {
d.err = d.syntaxError("expected /> in element")
return nil, d.err
}
break
}
if b == '>' {
break
}
d.ungetc(b)
n := len(attr)
if n >= cap(attr) {
nCap := 2 * cap(attr)
if nCap == 0 {
nCap = 4
}
nattr := make([]Attr, n, nCap)
copy(nattr, attr)
attr = nattr
}
attr = attr[0 : n+1]
a := &attr[n]
if a.Name, ok = d.nsname(); !ok {
if d.err == nil {
d.err = d.syntaxError("expected attribute name in element")
}
return nil, d.err
}
d.space()
if b, ok = d.mustgetc(); !ok {
return nil, d.err
}
if b != '=' {
if d.Strict {
d.err = d.syntaxError("attribute name without = in element")
return nil, d.err
} else {
d.ungetc(b)
a.Value = a.Name.Local
}
} else {
d.space()
data := d.attrval()
if data == nil {
return nil, d.err
}
a.Value = string(data)
}
}
if empty {
d.needClose = true
d.toClose = name
}
return StartElement{name, attr}, nil
}
func (d *Decoder) attrval() []byte {
b, ok := d.mustgetc()
if !ok {
return nil
}
// Handle quoted attribute values
if b == '"' || b == '\'' {
return d.text(int(b), false)
}
// Handle unquoted attribute values for strict parsers
if d.Strict {
d.err = d.syntaxError("unquoted or missing attribute value in element")
return nil
}
// Handle unquoted attribute values for unstrict parsers
d.ungetc(b)
d.buf.Reset()
for {
b, ok = d.mustgetc()
if !ok {
return nil
}
// http://www.w3.org/TR/REC-html40/intro/sgmltut.html#h-3.2.2
if 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z' ||
'0' <= b && b <= '9' || b == '_' || b == ':' || b == '-' {
d.buf.WriteByte(b)
} else {
d.ungetc(b)
break
}
}
return d.buf.Bytes()
}
// Skip spaces if any
func (d *Decoder) space() {
for {
b, ok := d.getc()
if !ok {
return
}
switch b {
case ' ', '\r', '\n', '\t':
default:
d.ungetc(b)
return
}
}
}
// Read a single byte.
// If there is no byte to read, return ok==false
// and leave the error in d.err.
// Maintain line number.
func (d *Decoder) getc() (b byte, ok bool) {
if d.err != nil {
return 0, false
}
if d.nextByte >= 0 {
b = byte(d.nextByte)
d.nextByte = -1
} else {
b, d.err = d.r.ReadByte()
if d.err != nil {
return 0, false
}
if d.saved != nil {
d.saved.WriteByte(b)
}
}
if b == '\n' {
d.line++
}
d.offset++
return b, true
}
// InputOffset returns the input stream byte offset of the current decoder position.
// The offset gives the location of the end of the most recently returned token
// and the beginning of the next token.
func (d *Decoder) InputOffset() int64 {
return d.offset
}
// Return saved offset.
// If we did ungetc (nextByte >= 0), have to back up one.
func (d *Decoder) savedOffset() int {
n := d.saved.Len()
if d.nextByte >= 0 {
n--
}
return n
}
// Must read a single byte.
// If there is no byte to read,
// set d.err to SyntaxError("unexpected EOF")
// and return ok==false
func (d *Decoder) mustgetc() (b byte, ok bool) {
if b, ok = d.getc(); !ok {
if d.err == io.EOF {
d.err = d.syntaxError("unexpected EOF")
}
}
return
}
// Unread a single byte.
func (d *Decoder) ungetc(b byte) {
if b == '\n' {
d.line--
}
d.nextByte = int(b)
d.offset--
}
var entity = map[string]rune{
"lt": '<',
"gt": '>',
"amp": '&',
"apos": '\'',
"quot": '"',
}
// Read plain text section (XML calls it character data).
// If quote >= 0, we are in a quoted string and need to find the matching quote.
// If cdata == true, we are in a <![CDATA[ section and need to find ]]>.
// On failure return nil and leave the error in d.err.
func (d *Decoder) text(quote int, cdata bool) []byte {
var b0, b1 byte
var trunc int
d.buf.Reset()
Input:
for {
b, ok := d.getc()
if !ok {
if cdata {
if d.err == io.EOF {
d.err = d.syntaxError("unexpected EOF in CDATA section")
}
return nil
}
break Input
}
// <![CDATA[ section ends with ]]>.
// It is an error for ]]> to appear in ordinary text.
if b0 == ']' && b1 == ']' && b == '>' {
if cdata {
trunc = 2
break Input
}
d.err = d.syntaxError("unescaped ]]> not in CDATA section")
return nil
}
// Stop reading text if we see a <.
if b == '<' && !cdata {
if quote >= 0 {
d.err = d.syntaxError("unescaped < inside quoted string")
return nil
}
d.ungetc('<')
break Input
}
if quote >= 0 && b == byte(quote) {
break Input
}
if b == '&' && !cdata {
// Read escaped character expression up to semicolon.
// XML in all its glory allows a document to define and use
// its own character names with <!ENTITY ...> directives.
// Parsers are required to recognize lt, gt, amp, apos, and quot
// even if they have not been declared.
before := d.buf.Len()
d.buf.WriteByte('&')
var ok bool
var text string
var haveText bool
if b, ok = d.mustgetc(); !ok {
return nil
}
if b == '#' {
d.buf.WriteByte(b)
if b, ok = d.mustgetc(); !ok {
return nil
}
base := 10
if b == 'x' {
base = 16
d.buf.WriteByte(b)
if b, ok = d.mustgetc(); !ok {
return nil
}
}
start := d.buf.Len()
for '0' <= b && b <= '9' ||
base == 16 && 'a' <= b && b <= 'f' ||
base == 16 && 'A' <= b && b <= 'F' {
d.buf.WriteByte(b)
if b, ok = d.mustgetc(); !ok {
return nil
}
}
if b != ';' {
d.ungetc(b)
} else {
s := string(d.buf.Bytes()[start:])
d.buf.WriteByte(';')
n, err := strconv.ParseUint(s, base, 64)
if err == nil && n <= unicode.MaxRune {
text = string(rune(n))
haveText = true
}
}
} else {
d.ungetc(b)
if !d.readName() {
if d.err != nil {
return nil
}
ok = false
}
if b, ok = d.mustgetc(); !ok {
return nil
}
if b != ';' {
d.ungetc(b)
} else {
name := d.buf.Bytes()[before+1:]
d.buf.WriteByte(';')
if isName(name) {
s := string(name)
if r, ok := entity[s]; ok {
text = string(r)
haveText = true
} else if d.Entity != nil {
text, haveText = d.Entity[s]
}
}
}
}
if haveText {
d.buf.Truncate(before)
d.buf.Write([]byte(text))
b0, b1 = 0, 0
continue Input
}
if !d.Strict {
b0, b1 = 0, 0
continue Input
}
ent := string(d.buf.Bytes()[before:])
if ent[len(ent)-1] != ';' {
ent += " (no semicolon)"
}
d.err = d.syntaxError("invalid character entity " + ent)
return nil
}
// We must rewrite unescaped \r and \r\n into \n.
if b == '\r' {
d.buf.WriteByte('\n')
} else if b1 == '\r' && b == '\n' {
// Skip \r\n--we already wrote \n.
} else {
d.buf.WriteByte(b)
}
b0, b1 = b1, b
}
data := d.buf.Bytes()
data = data[0 : len(data)-trunc]
// Inspect each rune for being a disallowed character.
buf := data
for len(buf) > 0 {
r, size := utf8.DecodeRune(buf)
if r == utf8.RuneError && size == 1 {
d.err = d.syntaxError("invalid UTF-8")
return nil
}
buf = buf[size:]
if !isInCharacterRange(r) {
d.err = d.syntaxError(fmt.Sprintf("illegal character code %U", r))
return nil
}
}
return data
}
// Decide whether the given rune is in the XML Character Range, per
// the Char production of http://www.xml.com/axml/testaxml.htm,
// Section 2.2 Characters.
func isInCharacterRange(r rune) (inrange bool) {
return r == 0x09 ||
r == 0x0A ||
r == 0x0D ||
r >= 0x20 && r <= 0xDF77 ||
r >= 0xE000 && r <= 0xFFFD ||
r >= 0x10000 && r <= 0x10FFFF
}
// Get name space name: name with a : stuck in the middle.
// The part before the : is the name space identifier.
func (d *Decoder) nsname() (name Name, ok bool) {
s, ok := d.name()
if !ok {
return
}
i := strings.Index(s, ":")
if i < 0 {
name.Local = s
} else {
name.Space = s[0:i]
name.Local = s[i+1:]
}
return name, true
}
// Get name: /first(first|second)*/
// Do not set d.err if the name is missing (unless unexpected EOF is received):
// let the caller provide better context.
func (d *Decoder) name() (s string, ok bool) {
d.buf.Reset()
if !d.readName() {
return "", false
}
// Now we check the characters.
b := d.buf.Bytes()
if !isName(b) {
d.err = d.syntaxError("invalid XML name: " + string(b))
return "", false
}
return string(b), true
}
// Read a name and append its bytes to d.buf.
// The name is delimited by any single-byte character not valid in names.
// All multi-byte characters are accepted; the caller must check their validity.
func (d *Decoder) readName() (ok bool) {
var b byte
if b, ok = d.mustgetc(); !ok {
return
}
if b < utf8.RuneSelf && !isNameByte(b) {
d.ungetc(b)
return false
}
d.buf.WriteByte(b)
for {
if b, ok = d.mustgetc(); !ok {
return
}
if b < utf8.RuneSelf && !isNameByte(b) {
d.ungetc(b)
break
}
d.buf.WriteByte(b)
}
return true
}
func isNameByte(c byte) bool {
return 'A' <= c && c <= 'Z' ||
'a' <= c && c <= 'z' ||
'0' <= c && c <= '9' ||
c == '_' || c == ':' || c == '.' || c == '-'
}
func isName(s []byte) bool {
if len(s) == 0 {
return false
}
c, n := utf8.DecodeRune(s)
if c == utf8.RuneError && n == 1 {
return false
}
if !unicode.Is(first, c) {
return false
}
for n < len(s) {
s = s[n:]
c, n = utf8.DecodeRune(s)
if c == utf8.RuneError && n == 1 {
return false
}
if !unicode.Is(first, c) && !unicode.Is(second, c) {
return false
}
}
return true
}
func isNameString(s string) bool {
if len(s) == 0 {
return false
}
c, n := utf8.DecodeRuneInString(s)
if c == utf8.RuneError && n == 1 {
return false
}
if !unicode.Is(first, c) {
return false
}
for n < len(s) {
s = s[n:]
c, n = utf8.DecodeRuneInString(s)
if c == utf8.RuneError && n == 1 {
return false
}
if !unicode.Is(first, c) && !unicode.Is(second, c) {
return false
}
}
return true
}
// These tables were generated by cut and paste from Appendix B of
// the XML spec at http://www.xml.com/axml/testaxml.htm
// and then reformatting. First corresponds to (Letter | '_' | ':')
// and second corresponds to NameChar.
var first = &unicode.RangeTable{
R16: []unicode.Range16{
{0x003A, 0x003A, 1},
{0x0041, 0x005A, 1},
{0x005F, 0x005F, 1},
{0x0061, 0x007A, 1},
{0x00C0, 0x00D6, 1},
{0x00D8, 0x00F6, 1},
{0x00F8, 0x00FF, 1},
{0x0100, 0x0131, 1},
{0x0134, 0x013E, 1},
{0x0141, 0x0148, 1},
{0x014A, 0x017E, 1},
{0x0180, 0x01C3, 1},
{0x01CD, 0x01F0, 1},
{0x01F4, 0x01F5, 1},
{0x01FA, 0x0217, 1},
{0x0250, 0x02A8, 1},
{0x02BB, 0x02C1, 1},
{0x0386, 0x0386, 1},
{0x0388, 0x038A, 1},
{0x038C, 0x038C, 1},
{0x038E, 0x03A1, 1},
{0x03A3, 0x03CE, 1},
{0x03D0, 0x03D6, 1},
{0x03DA, 0x03E0, 2},
{0x03E2, 0x03F3, 1},
{0x0401, 0x040C, 1},
{0x040E, 0x044F, 1},
{0x0451, 0x045C, 1},
{0x045E, 0x0481, 1},
{0x0490, 0x04C4, 1},
{0x04C7, 0x04C8, 1},
{0x04CB, 0x04CC, 1},
{0x04D0, 0x04EB, 1},
{0x04EE, 0x04F5, 1},
{0x04F8, 0x04F9, 1},
{0x0531, 0x0556, 1},
{0x0559, 0x0559, 1},
{0x0561, 0x0586, 1},
{0x05D0, 0x05EA, 1},
{0x05F0, 0x05F2, 1},
{0x0621, 0x063A, 1},
{0x0641, 0x064A, 1},
{0x0671, 0x06B7, 1},
{0x06BA, 0x06BE, 1},
{0x06C0, 0x06CE, 1},
{0x06D0, 0x06D3, 1},
{0x06D5, 0x06D5, 1},
{0x06E5, 0x06E6, 1},
{0x0905, 0x0939, 1},
{0x093D, 0x093D, 1},
{0x0958, 0x0961, 1},
{0x0985, 0x098C, 1},
{0x098F, 0x0990, 1},
{0x0993, 0x09A8, 1},
{0x09AA, 0x09B0, 1},
{0x09B2, 0x09B2, 1},
{0x09B6, 0x09B9, 1},
{0x09DC, 0x09DD, 1},
{0x09DF, 0x09E1, 1},
{0x09F0, 0x09F1, 1},
{0x0A05, 0x0A0A, 1},
{0x0A0F, 0x0A10, 1},
{0x0A13, 0x0A28, 1},
{0x0A2A, 0x0A30, 1},
{0x0A32, 0x0A33, 1},
{0x0A35, 0x0A36, 1},
{0x0A38, 0x0A39, 1},
{0x0A59, 0x0A5C, 1},
{0x0A5E, 0x0A5E, 1},
{0x0A72, 0x0A74, 1},
{0x0A85, 0x0A8B, 1},
{0x0A8D, 0x0A8D, 1},
{0x0A8F, 0x0A91, 1},
{0x0A93, 0x0AA8, 1},
{0x0AAA, 0x0AB0, 1},
{0x0AB2, 0x0AB3, 1},
{0x0AB5, 0x0AB9, 1},
{0x0ABD, 0x0AE0, 0x23},
{0x0B05, 0x0B0C, 1},
{0x0B0F, 0x0B10, 1},
{0x0B13, 0x0B28, 1},
{0x0B2A, 0x0B30, 1},
{0x0B32, 0x0B33, 1},
{0x0B36, 0x0B39, 1},
{0x0B3D, 0x0B3D, 1},
{0x0B5C, 0x0B5D, 1},
{0x0B5F, 0x0B61, 1},
{0x0B85, 0x0B8A, 1},
{0x0B8E, 0x0B90, 1},
{0x0B92, 0x0B95, 1},
{0x0B99, 0x0B9A, 1},
{0x0B9C, 0x0B9C, 1},
{0x0B9E, 0x0B9F, 1},
{0x0BA3, 0x0BA4, 1},
{0x0BA8, 0x0BAA, 1},
{0x0BAE, 0x0BB5, 1},
{0x0BB7, 0x0BB9, 1},
{0x0C05, 0x0C0C, 1},
{0x0C0E, 0x0C10, 1},
{0x0C12, 0x0C28, 1},
{0x0C2A, 0x0C33, 1},
{0x0C35, 0x0C39, 1},
{0x0C60, 0x0C61, 1},
{0x0C85, 0x0C8C, 1},
{0x0C8E, 0x0C90, 1},
{0x0C92, 0x0CA8, 1},
{0x0CAA, 0x0CB3, 1},
{0x0CB5, 0x0CB9, 1},
{0x0CDE, 0x0CDE, 1},
{0x0CE0, 0x0CE1, 1},
{0x0D05, 0x0D0C, 1},
{0x0D0E, 0x0D10, 1},
{0x0D12, 0x0D28, 1},
{0x0D2A, 0x0D39, 1},
{0x0D60, 0x0D61, 1},
{0x0E01, 0x0E2E, 1},
{0x0E30, 0x0E30, 1},
{0x0E32, 0x0E33, 1},
{0x0E40, 0x0E45, 1},
{0x0E81, 0x0E82, 1},
{0x0E84, 0x0E84, 1},
{0x0E87, 0x0E88, 1},
{0x0E8A, 0x0E8D, 3},
{0x0E94, 0x0E97, 1},
{0x0E99, 0x0E9F, 1},
{0x0EA1, 0x0EA3, 1},
{0x0EA5, 0x0EA7, 2},
{0x0EAA, 0x0EAB, 1},
{0x0EAD, 0x0EAE, 1},
{0x0EB0, 0x0EB0, 1},
{0x0EB2, 0x0EB3, 1},
{0x0EBD, 0x0EBD, 1},
{0x0EC0, 0x0EC4, 1},
{0x0F40, 0x0F47, 1},
{0x0F49, 0x0F69, 1},
{0x10A0, 0x10C5, 1},
{0x10D0, 0x10F6, 1},
{0x1100, 0x1100, 1},
{0x1102, 0x1103, 1},
{0x1105, 0x1107, 1},
{0x1109, 0x1109, 1},
{0x110B, 0x110C, 1},
{0x110E, 0x1112, 1},
{0x113C, 0x1140, 2},
{0x114C, 0x1150, 2},
{0x1154, 0x1155, 1},
{0x1159, 0x1159, 1},
{0x115F, 0x1161, 1},
{0x1163, 0x1169, 2},
{0x116D, 0x116E, 1},
{0x1172, 0x1173, 1},
{0x1175, 0x119E, 0x119E - 0x1175},
{0x11A8, 0x11AB, 0x11AB - 0x11A8},
{0x11AE, 0x11AF, 1},
{0x11B7, 0x11B8, 1},
{0x11BA, 0x11BA, 1},
{0x11BC, 0x11C2, 1},
{0x11EB, 0x11F0, 0x11F0 - 0x11EB},
{0x11F9, 0x11F9, 1},
{0x1E00, 0x1E9B, 1},
{0x1EA0, 0x1EF9, 1},
{0x1F00, 0x1F15, 1},
{0x1F18, 0x1F1D, 1},
{0x1F20, 0x1F45, 1},
{0x1F48, 0x1F4D, 1},
{0x1F50, 0x1F57, 1},
{0x1F59, 0x1F5B, 0x1F5B - 0x1F59},
{0x1F5D, 0x1F5D, 1},
{0x1F5F, 0x1F7D, 1},
{0x1F80, 0x1FB4, 1},
{0x1FB6, 0x1FBC, 1},
{0x1FBE, 0x1FBE, 1},
{0x1FC2, 0x1FC4, 1},
{0x1FC6, 0x1FCC, 1},
{0x1FD0, 0x1FD3, 1},
{0x1FD6, 0x1FDB, 1},
{0x1FE0, 0x1FEC, 1},
{0x1FF2, 0x1FF4, 1},
{0x1FF6, 0x1FFC, 1},
{0x2126, 0x2126, 1},
{0x212A, 0x212B, 1},
{0x212E, 0x212E, 1},
{0x2180, 0x2182, 1},
{0x3007, 0x3007, 1},
{0x3021, 0x3029, 1},
{0x3041, 0x3094, 1},
{0x30A1, 0x30FA, 1},
{0x3105, 0x312C, 1},
{0x4E00, 0x9FA5, 1},
{0xAC00, 0xD7A3, 1},
},
}
var second = &unicode.RangeTable{
R16: []unicode.Range16{
{0x002D, 0x002E, 1},
{0x0030, 0x0039, 1},
{0x00B7, 0x00B7, 1},
{0x02D0, 0x02D1, 1},
{0x0300, 0x0345, 1},
{0x0360, 0x0361, 1},
{0x0387, 0x0387, 1},
{0x0483, 0x0486, 1},
{0x0591, 0x05A1, 1},
{0x05A3, 0x05B9, 1},
{0x05BB, 0x05BD, 1},
{0x05BF, 0x05BF, 1},
{0x05C1, 0x05C2, 1},
{0x05C4, 0x0640, 0x0640 - 0x05C4},
{0x064B, 0x0652, 1},
{0x0660, 0x0669, 1},
{0x0670, 0x0670, 1},
{0x06D6, 0x06DC, 1},
{0x06DD, 0x06DF, 1},
{0x06E0, 0x06E4, 1},
{0x06E7, 0x06E8, 1},
{0x06EA, 0x06ED, 1},
{0x06F0, 0x06F9, 1},
{0x0901, 0x0903, 1},
{0x093C, 0x093C, 1},
{0x093E, 0x094C, 1},
{0x094D, 0x094D, 1},
{0x0951, 0x0954, 1},
{0x0962, 0x0963, 1},
{0x0966, 0x096F, 1},
{0x0981, 0x0983, 1},
{0x09BC, 0x09BC, 1},
{0x09BE, 0x09BF, 1},
{0x09C0, 0x09C4, 1},
{0x09C7, 0x09C8, 1},
{0x09CB, 0x09CD, 1},
{0x09D7, 0x09D7, 1},
{0x09E2, 0x09E3, 1},
{0x09E6, 0x09EF, 1},
{0x0A02, 0x0A3C, 0x3A},
{0x0A3E, 0x0A3F, 1},
{0x0A40, 0x0A42, 1},
{0x0A47, 0x0A48, 1},
{0x0A4B, 0x0A4D, 1},
{0x0A66, 0x0A6F, 1},
{0x0A70, 0x0A71, 1},
{0x0A81, 0x0A83, 1},
{0x0ABC, 0x0ABC, 1},
{0x0ABE, 0x0AC5, 1},
{0x0AC7, 0x0AC9, 1},
{0x0ACB, 0x0ACD, 1},
{0x0AE6, 0x0AEF, 1},
{0x0B01, 0x0B03, 1},
{0x0B3C, 0x0B3C, 1},
{0x0B3E, 0x0B43, 1},
{0x0B47, 0x0B48, 1},
{0x0B4B, 0x0B4D, 1},
{0x0B56, 0x0B57, 1},
{0x0B66, 0x0B6F, 1},
{0x0B82, 0x0B83, 1},
{0x0BBE, 0x0BC2, 1},
{0x0BC6, 0x0BC8, 1},
{0x0BCA, 0x0BCD, 1},
{0x0BD7, 0x0BD7, 1},
{0x0BE7, 0x0BEF, 1},
{0x0C01, 0x0C03, 1},
{0x0C3E, 0x0C44, 1},
{0x0C46, 0x0C48, 1},
{0x0C4A, 0x0C4D, 1},
{0x0C55, 0x0C56, 1},
{0x0C66, 0x0C6F, 1},
{0x0C82, 0x0C83, 1},
{0x0CBE, 0x0CC4, 1},
{0x0CC6, 0x0CC8, 1},
{0x0CCA, 0x0CCD, 1},
{0x0CD5, 0x0CD6, 1},
{0x0CE6, 0x0CEF, 1},
{0x0D02, 0x0D03, 1},
{0x0D3E, 0x0D43, 1},
{0x0D46, 0x0D48, 1},
{0x0D4A, 0x0D4D, 1},
{0x0D57, 0x0D57, 1},
{0x0D66, 0x0D6F, 1},
{0x0E31, 0x0E31, 1},
{0x0E34, 0x0E3A, 1},
{0x0E46, 0x0E46, 1},
{0x0E47, 0x0E4E, 1},
{0x0E50, 0x0E59, 1},
{0x0EB1, 0x0EB1, 1},
{0x0EB4, 0x0EB9, 1},
{0x0EBB, 0x0EBC, 1},
{0x0EC6, 0x0EC6, 1},
{0x0EC8, 0x0ECD, 1},
{0x0ED0, 0x0ED9, 1},
{0x0F18, 0x0F19, 1},
{0x0F20, 0x0F29, 1},
{0x0F35, 0x0F39, 2},
{0x0F3E, 0x0F3F, 1},
{0x0F71, 0x0F84, 1},
{0x0F86, 0x0F8B, 1},
{0x0F90, 0x0F95, 1},
{0x0F97, 0x0F97, 1},
{0x0F99, 0x0FAD, 1},
{0x0FB1, 0x0FB7, 1},
{0x0FB9, 0x0FB9, 1},
{0x20D0, 0x20DC, 1},
{0x20E1, 0x3005, 0x3005 - 0x20E1},
{0x302A, 0x302F, 1},
{0x3031, 0x3035, 1},
{0x3099, 0x309A, 1},
{0x309D, 0x309E, 1},
{0x30FC, 0x30FE, 1},
},
}
// HTMLEntity is an entity map containing translations for the
// standard HTML entity characters.
var HTMLEntity = htmlEntity
var htmlEntity = map[string]string{
/*
hget http://www.w3.org/TR/html4/sgml/entities.html |
ssam '
,y /\>/ x/\<(.|\n)+/ s/\n/ /g
,x v/^\<!ENTITY/d
,s/\<!ENTITY ([^ ]+) .*U\+([0-9A-F][0-9A-F][0-9A-F][0-9A-F]) .+/ "\1": "\\u\2",/g
'
*/
"nbsp": "\u00A0",
"iexcl": "\u00A1",
"cent": "\u00A2",
"pound": "\u00A3",
"curren": "\u00A4",
"yen": "\u00A5",
"brvbar": "\u00A6",
"sect": "\u00A7",
"uml": "\u00A8",
"copy": "\u00A9",
"ordf": "\u00AA",
"laquo": "\u00AB",
"not": "\u00AC",
"shy": "\u00AD",
"reg": "\u00AE",
"macr": "\u00AF",
"deg": "\u00B0",
"plusmn": "\u00B1",
"sup2": "\u00B2",
"sup3": "\u00B3",
"acute": "\u00B4",
"micro": "\u00B5",
"para": "\u00B6",
"middot": "\u00B7",
"cedil": "\u00B8",
"sup1": "\u00B9",
"ordm": "\u00BA",
"raquo": "\u00BB",
"frac14": "\u00BC",
"frac12": "\u00BD",
"frac34": "\u00BE",
"iquest": "\u00BF",
"Agrave": "\u00C0",
"Aacute": "\u00C1",
"Acirc": "\u00C2",
"Atilde": "\u00C3",
"Auml": "\u00C4",
"Aring": "\u00C5",
"AElig": "\u00C6",
"Ccedil": "\u00C7",
"Egrave": "\u00C8",
"Eacute": "\u00C9",
"Ecirc": "\u00CA",
"Euml": "\u00CB",
"Igrave": "\u00CC",
"Iacute": "\u00CD",
"Icirc": "\u00CE",
"Iuml": "\u00CF",
"ETH": "\u00D0",
"Ntilde": "\u00D1",
"Ograve": "\u00D2",
"Oacute": "\u00D3",
"Ocirc": "\u00D4",
"Otilde": "\u00D5",
"Ouml": "\u00D6",
"times": "\u00D7",
"Oslash": "\u00D8",
"Ugrave": "\u00D9",
"Uacute": "\u00DA",
"Ucirc": "\u00DB",
"Uuml": "\u00DC",
"Yacute": "\u00DD",
"THORN": "\u00DE",
"szlig": "\u00DF",
"agrave": "\u00E0",
"aacute": "\u00E1",
"acirc": "\u00E2",
"atilde": "\u00E3",
"auml": "\u00E4",
"aring": "\u00E5",
"aelig": "\u00E6",
"ccedil": "\u00E7",
"egrave": "\u00E8",
"eacute": "\u00E9",
"ecirc": "\u00EA",
"euml": "\u00EB",
"igrave": "\u00EC",
"iacute": "\u00ED",
"icirc": "\u00EE",
"iuml": "\u00EF",
"eth": "\u00F0",
"ntilde": "\u00F1",
"ograve": "\u00F2",
"oacute": "\u00F3",
"ocirc": "\u00F4",
"otilde": "\u00F5",
"ouml": "\u00F6",
"divide": "\u00F7",
"oslash": "\u00F8",
"ugrave": "\u00F9",
"uacute": "\u00FA",
"ucirc": "\u00FB",
"uuml": "\u00FC",
"yacute": "\u00FD",
"thorn": "\u00FE",
"yuml": "\u00FF",
"fnof": "\u0192",
"Alpha": "\u0391",
"Beta": "\u0392",
"Gamma": "\u0393",
"Delta": "\u0394",
"Epsilon": "\u0395",
"Zeta": "\u0396",
"Eta": "\u0397",
"Theta": "\u0398",
"Iota": "\u0399",
"Kappa": "\u039A",
"Lambda": "\u039B",
"Mu": "\u039C",
"Nu": "\u039D",
"Xi": "\u039E",
"Omicron": "\u039F",
"Pi": "\u03A0",
"Rho": "\u03A1",
"Sigma": "\u03A3",
"Tau": "\u03A4",
"Upsilon": "\u03A5",
"Phi": "\u03A6",
"Chi": "\u03A7",
"Psi": "\u03A8",
"Omega": "\u03A9",
"alpha": "\u03B1",
"beta": "\u03B2",
"gamma": "\u03B3",
"delta": "\u03B4",
"epsilon": "\u03B5",
"zeta": "\u03B6",
"eta": "\u03B7",
"theta": "\u03B8",
"iota": "\u03B9",
"kappa": "\u03BA",
"lambda": "\u03BB",
"mu": "\u03BC",
"nu": "\u03BD",
"xi": "\u03BE",
"omicron": "\u03BF",
"pi": "\u03C0",
"rho": "\u03C1",
"sigmaf": "\u03C2",
"sigma": "\u03C3",
"tau": "\u03C4",
"upsilon": "\u03C5",
"phi": "\u03C6",
"chi": "\u03C7",
"psi": "\u03C8",
"omega": "\u03C9",
"thetasym": "\u03D1",
"upsih": "\u03D2",
"piv": "\u03D6",
"bull": "\u2022",
"hellip": "\u2026",
"prime": "\u2032",
"Prime": "\u2033",
"oline": "\u203E",
"frasl": "\u2044",
"weierp": "\u2118",
"image": "\u2111",
"real": "\u211C",
"trade": "\u2122",
"alefsym": "\u2135",
"larr": "\u2190",
"uarr": "\u2191",
"rarr": "\u2192",
"darr": "\u2193",
"harr": "\u2194",
"crarr": "\u21B5",
"lArr": "\u21D0",
"uArr": "\u21D1",
"rArr": "\u21D2",
"dArr": "\u21D3",
"hArr": "\u21D4",
"forall": "\u2200",
"part": "\u2202",
"exist": "\u2203",
"empty": "\u2205",
"nabla": "\u2207",
"isin": "\u2208",
"notin": "\u2209",
"ni": "\u220B",
"prod": "\u220F",
"sum": "\u2211",
"minus": "\u2212",
"lowast": "\u2217",
"radic": "\u221A",
"prop": "\u221D",
"infin": "\u221E",
"ang": "\u2220",
"and": "\u2227",
"or": "\u2228",
"cap": "\u2229",
"cup": "\u222A",
"int": "\u222B",
"there4": "\u2234",
"sim": "\u223C",
"cong": "\u2245",
"asymp": "\u2248",
"ne": "\u2260",
"equiv": "\u2261",
"le": "\u2264",
"ge": "\u2265",
"sub": "\u2282",
"sup": "\u2283",
"nsub": "\u2284",
"sube": "\u2286",
"supe": "\u2287",
"oplus": "\u2295",
"otimes": "\u2297",
"perp": "\u22A5",
"sdot": "\u22C5",
"lceil": "\u2308",
"rceil": "\u2309",
"lfloor": "\u230A",
"rfloor": "\u230B",
"lang": "\u2329",
"rang": "\u232A",
"loz": "\u25CA",
"spades": "\u2660",
"clubs": "\u2663",
"hearts": "\u2665",
"diams": "\u2666",
"quot": "\u0022",
"amp": "\u0026",
"lt": "\u003C",
"gt": "\u003E",
"OElig": "\u0152",
"oelig": "\u0153",
"Scaron": "\u0160",
"scaron": "\u0161",
"Yuml": "\u0178",
"circ": "\u02C6",
"tilde": "\u02DC",
"ensp": "\u2002",
"emsp": "\u2003",
"thinsp": "\u2009",
"zwnj": "\u200C",
"zwj": "\u200D",
"lrm": "\u200E",
"rlm": "\u200F",
"ndash": "\u2013",
"mdash": "\u2014",
"lsquo": "\u2018",
"rsquo": "\u2019",
"sbquo": "\u201A",
"ldquo": "\u201C",
"rdquo": "\u201D",
"bdquo": "\u201E",
"dagger": "\u2020",
"Dagger": "\u2021",
"permil": "\u2030",
"lsaquo": "\u2039",
"rsaquo": "\u203A",
"euro": "\u20AC",
}
// HTMLAutoClose is the set of HTML elements that
// should be considered to close automatically.
var HTMLAutoClose = htmlAutoClose
var htmlAutoClose = []string{
/*
hget http://www.w3.org/TR/html4/loose.dtd |
9 sed -n 's/<!ELEMENT ([^ ]*) +- O EMPTY.+/ "\1",/p' | tr A-Z a-z
*/
"basefont",
"br",
"area",
"link",
"img",
"param",
"hr",
"input",
"col",
"frame",
"isindex",
"base",
"meta",
}
var (
esc_quot = []byte(""") // shorter than """
esc_apos = []byte("'") // shorter than "'"
esc_amp = []byte("&")
esc_lt = []byte("<")
esc_gt = []byte(">")
esc_tab = []byte("	")
esc_nl = []byte("
")
esc_cr = []byte("
")
esc_fffd = []byte("\uFFFD") // Unicode replacement character
)
// EscapeText writes to w the properly escaped XML equivalent
// of the plain text data s.
func EscapeText(w io.Writer, s []byte) error {
return escapeText(w, s, true)
}
// escapeText writes to w the properly escaped XML equivalent
// of the plain text data s. If escapeNewline is true, newline
// characters will be escaped.
func escapeText(w io.Writer, s []byte, escapeNewline bool) error {
var esc []byte
last := 0
for i := 0; i < len(s); {
r, width := utf8.DecodeRune(s[i:])
i += width
switch r {
case '"':
esc = esc_quot
case '\'':
esc = esc_apos
case '&':
esc = esc_amp
case '<':
esc = esc_lt
case '>':
esc = esc_gt
case '\t':
esc = esc_tab
case '\n':
if !escapeNewline {
continue
}
esc = esc_nl
case '\r':
esc = esc_cr
default:
if !isInCharacterRange(r) || (r == 0xFFFD && width == 1) {
esc = esc_fffd
break
}
continue
}
if _, err := w.Write(s[last : i-width]); err != nil {
return err
}
if _, err := w.Write(esc); err != nil {
return err
}
last = i
}
if _, err := w.Write(s[last:]); err != nil {
return err
}
return nil
}
// EscapeString writes to p the properly escaped XML equivalent
// of the plain text data s.
func (p *printer) EscapeString(s string) {
var esc []byte
last := 0
for i := 0; i < len(s); {
r, width := utf8.DecodeRuneInString(s[i:])
i += width
switch r {
case '"':
esc = esc_quot
case '\'':
esc = esc_apos
case '&':
esc = esc_amp
case '<':
esc = esc_lt
case '>':
esc = esc_gt
case '\t':
esc = esc_tab
case '\n':
esc = esc_nl
case '\r':
esc = esc_cr
default:
if !isInCharacterRange(r) || (r == 0xFFFD && width == 1) {
esc = esc_fffd
break
}
continue
}
p.WriteString(s[last : i-width])
p.Write(esc)
last = i
}
p.WriteString(s[last:])
}
// Escape is like EscapeText but omits the error return value.
// It is provided for backwards compatibility with Go 1.0.
// Code targeting Go 1.1 or later should use EscapeText.
func Escape(w io.Writer, s []byte) {
EscapeText(w, s)
}
// procInst parses the `param="..."` or `param='...'`
// value out of the provided string, returning "" if not found.
func procInst(param, s string) string {
// TODO: this parsing is somewhat lame and not exact.
// It works for all actual cases, though.
param = param + "="
idx := strings.Index(s, param)
if idx == -1 {
return ""
}
v := s[idx+len(param):]
if v == "" {
return ""
}
if v[0] != '\'' && v[0] != '"' {
return ""
}
idx = strings.IndexRune(v[1:], rune(v[0]))
if idx == -1 {
return ""
}
return v[1 : idx+1]
}
// 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 webdav
import (
"container/heap"
"errors"
"strconv"
"strings"
"sync"
"time"
)
var (
// ErrConfirmationFailed is returned by a LockSystem's Confirm method.
ErrConfirmationFailed = errors.New("webdav: confirmation failed")
// ErrForbidden is returned by a LockSystem's Unlock method.
ErrForbidden = errors.New("webdav: forbidden")
// ErrLocked is returned by a LockSystem's Create, Refresh and Unlock methods.
ErrLocked = errors.New("webdav: locked")
// ErrNoSuchLock is returned by a LockSystem's Refresh and Unlock methods.
ErrNoSuchLock = errors.New("webdav: no such lock")
)
// Condition can match a WebDAV resource, based on a token or ETag.
// Exactly one of Token and ETag should be non-empty.
type Condition struct {
Not bool
Token string
ETag string
}
// LockSystem manages access to a collection of named resources. The elements
// in a lock name are separated by slash ('/', U+002F) characters, regardless
// of host operating system convention.
type LockSystem interface {
// Confirm confirms that the caller can claim all of the locks specified by
// the given conditions, and that holding the union of all of those locks
// gives exclusive access to all of the named resources. Up to two resources
// can be named. Empty names are ignored.
//
// Exactly one of release and err will be non-nil. If release is non-nil,
// all of the requested locks are held until release is called. Calling
// release does not unlock the lock, in the WebDAV UNLOCK sense, but once
// Confirm has confirmed that a lock claim is valid, that lock cannot be
// Confirmed again until it has been released.
//
// If Confirm returns ErrConfirmationFailed then the Handler will continue
// to try any other set of locks presented (a WebDAV HTTP request can
// present more than one set of locks). If it returns any other non-nil
// error, the Handler will write a "500 Internal Server Error" HTTP status.
Confirm(now time.Time, name0, name1 string, conditions ...Condition) (release func(), err error)
// Create creates a lock with the given depth, duration, owner and root
// (name). The depth will either be negative (meaning infinite) or zero.
//
// If Create returns ErrLocked then the Handler will write a "423 Locked"
// HTTP status. If it returns any other non-nil error, the Handler will
// write a "500 Internal Server Error" HTTP status.
//
// See http://www.webdav.org/specs/rfc4918.html#rfc.section.9.10.6 for
// when to use each error.
//
// The token returned identifies the created lock. It should be an absolute
// URI as defined by RFC 3986, Section 4.3. In particular, it should not
// contain whitespace.
Create(now time.Time, details LockDetails) (token string, err error)
// Refresh refreshes the lock with the given token.
//
// If Refresh returns ErrLocked then the Handler will write a "423 Locked"
// HTTP Status. If Refresh returns ErrNoSuchLock then the Handler will write
// a "412 Precondition Failed" HTTP Status. If it returns any other non-nil
// error, the Handler will write a "500 Internal Server Error" HTTP status.
//
// See http://www.webdav.org/specs/rfc4918.html#rfc.section.9.10.6 for
// when to use each error.
Refresh(now time.Time, token string, duration time.Duration) (LockDetails, error)
// Unlock unlocks the lock with the given token.
//
// If Unlock returns ErrForbidden then the Handler will write a "403
// Forbidden" HTTP Status. If Unlock returns ErrLocked then the Handler
// will write a "423 Locked" HTTP status. If Unlock returns ErrNoSuchLock
// then the Handler will write a "409 Conflict" HTTP Status. If it returns
// any other non-nil error, the Handler will write a "500 Internal Server
// Error" HTTP status.
//
// See http://www.webdav.org/specs/rfc4918.html#rfc.section.9.11.1 for
// when to use each error.
Unlock(now time.Time, token string) error
}
// LockDetails are a lock's metadata.
type LockDetails struct {
// Root is the root resource name being locked. For a zero-depth lock, the
// root is the only resource being locked.
Root string
// Duration is the lock timeout. A negative duration means infinite.
Duration time.Duration
// OwnerXML is the verbatim <owner> XML given in a LOCK HTTP request.
//
// TODO: does the "verbatim" nature play well with XML namespaces?
// Does the OwnerXML field need to have more structure? See
// https://codereview.appspot.com/175140043/#msg2
OwnerXML string
// ZeroDepth is whether the lock has zero depth. If it does not have zero
// depth, it has infinite depth.
ZeroDepth bool
}
// NewMemLS returns a new in-memory LockSystem.
func NewMemLS() LockSystem {
return &memLS{
byName: make(map[string]*memLSNode),
byToken: make(map[string]*memLSNode),
gen: uint64(time.Now().Unix()),
}
}
type memLS struct {
mu sync.Mutex
byName map[string]*memLSNode
byToken map[string]*memLSNode
gen uint64
// byExpiry only contains those nodes whose LockDetails have a finite
// Duration and are yet to expire.
byExpiry byExpiry
}
func (m *memLS) nextToken() string {
m.gen++
return strconv.FormatUint(m.gen, 10)
}
func (m *memLS) collectExpiredNodes(now time.Time) {
for len(m.byExpiry) > 0 {
if now.Before(m.byExpiry[0].expiry) {
break
}
m.remove(m.byExpiry[0])
}
}
func (m *memLS) Confirm(now time.Time, name0, name1 string, conditions ...Condition) (func(), error) {
m.mu.Lock()
defer m.mu.Unlock()
m.collectExpiredNodes(now)
var n0, n1 *memLSNode
if name0 != "" {
if n0 = m.lookup(slashClean(name0), conditions...); n0 == nil {
return nil, ErrConfirmationFailed
}
}
if name1 != "" {
if n1 = m.lookup(slashClean(name1), conditions...); n1 == nil {
return nil, ErrConfirmationFailed
}
}
// Don't hold the same node twice.
if n1 == n0 {
n1 = nil
}
if n0 != nil {
m.hold(n0)
}
if n1 != nil {
m.hold(n1)
}
return func() {
m.mu.Lock()
defer m.mu.Unlock()
if n1 != nil {
m.unhold(n1)
}
if n0 != nil {
m.unhold(n0)
}
}, nil
}
// lookup returns the node n that locks the named resource, provided that n
// matches at least one of the given conditions and that lock isn't held by
// another party. Otherwise, it returns nil.
//
// n may be a parent of the named resource, if n is an infinite depth lock.
func (m *memLS) lookup(name string, conditions ...Condition) (n *memLSNode) {
// TODO: support Condition.Not and Condition.ETag.
for _, c := range conditions {
n = m.byToken[c.Token]
if n == nil || n.held {
continue
}
if name == n.details.Root {
return n
}
if n.details.ZeroDepth {
continue
}
if n.details.Root == "/" || strings.HasPrefix(name, n.details.Root+"/") {
return n
}
}
return nil
}
func (m *memLS) hold(n *memLSNode) {
if n.held {
panic("webdav: memLS inconsistent held state")
}
n.held = true
if n.details.Duration >= 0 && n.byExpiryIndex >= 0 {
heap.Remove(&m.byExpiry, n.byExpiryIndex)
}
}
func (m *memLS) unhold(n *memLSNode) {
if !n.held {
panic("webdav: memLS inconsistent held state")
}
n.held = false
if n.details.Duration >= 0 {
heap.Push(&m.byExpiry, n)
}
}
func (m *memLS) Create(now time.Time, details LockDetails) (string, error) {
m.mu.Lock()
defer m.mu.Unlock()
m.collectExpiredNodes(now)
details.Root = slashClean(details.Root)
if !m.canCreate(details.Root, details.ZeroDepth) {
return "", ErrLocked
}
n := m.create(details.Root)
n.token = m.nextToken()
m.byToken[n.token] = n
n.details = details
if n.details.Duration >= 0 {
n.expiry = now.Add(n.details.Duration)
heap.Push(&m.byExpiry, n)
}
return n.token, nil
}
func (m *memLS) Refresh(now time.Time, token string, duration time.Duration) (LockDetails, error) {
m.mu.Lock()
defer m.mu.Unlock()
m.collectExpiredNodes(now)
n := m.byToken[token]
if n == nil {
return LockDetails{}, ErrNoSuchLock
}
if n.held {
return LockDetails{}, ErrLocked
}
if n.byExpiryIndex >= 0 {
heap.Remove(&m.byExpiry, n.byExpiryIndex)
}
n.details.Duration = duration
if n.details.Duration >= 0 {
n.expiry = now.Add(n.details.Duration)
heap.Push(&m.byExpiry, n)
}
return n.details, nil
}
func (m *memLS) Unlock(now time.Time, token string) error {
m.mu.Lock()
defer m.mu.Unlock()
m.collectExpiredNodes(now)
n := m.byToken[token]
if n == nil {
return ErrNoSuchLock
}
if n.held {
return ErrLocked
}
m.remove(n)
return nil
}
func (m *memLS) canCreate(name string, zeroDepth bool) bool {
return walkToRoot(name, func(name0 string, first bool) bool {
n := m.byName[name0]
if n == nil {
return true
}
if first {
if n.token != "" {
// The target node is already locked.
return false
}
if !zeroDepth {
// The requested lock depth is infinite, and the fact that n exists
// (n != nil) means that a descendent of the target node is locked.
return false
}
} else if n.token != "" && !n.details.ZeroDepth {
// An ancestor of the target node is locked with infinite depth.
return false
}
return true
})
}
func (m *memLS) create(name string) (ret *memLSNode) {
walkToRoot(name, func(name0 string, first bool) bool {
n := m.byName[name0]
if n == nil {
n = &memLSNode{
details: LockDetails{
Root: name0,
},
byExpiryIndex: -1,
}
m.byName[name0] = n
}
n.refCount++
if first {
ret = n
}
return true
})
return ret
}
func (m *memLS) remove(n *memLSNode) {
delete(m.byToken, n.token)
n.token = ""
walkToRoot(n.details.Root, func(name0 string, first bool) bool {
x := m.byName[name0]
x.refCount--
if x.refCount == 0 {
delete(m.byName, name0)
}
return true
})
if n.byExpiryIndex >= 0 {
heap.Remove(&m.byExpiry, n.byExpiryIndex)
}
}
func walkToRoot(name string, f func(name0 string, first bool) bool) bool {
for first := true; ; first = false {
if !f(name, first) {
return false
}
if name == "/" {
break
}
name = name[:strings.LastIndex(name, "/")]
if name == "" {
name = "/"
}
}
return true
}
type memLSNode struct {
// details are the lock metadata. Even if this node's name is not explicitly locked,
// details.Root will still equal the node's name.
details LockDetails
// token is the unique identifier for this node's lock. An empty token means that
// this node is not explicitly locked.
token string
// refCount is the number of self-or-descendent nodes that are explicitly locked.
refCount int
// expiry is when this node's lock expires.
expiry time.Time
// byExpiryIndex is the index of this node in memLS.byExpiry. It is -1
// if this node does not expire, or has expired.
byExpiryIndex int
// held is whether this node's lock is actively held by a Confirm call.
held bool
}
type byExpiry []*memLSNode
func (b *byExpiry) Len() int {
return len(*b)
}
func (b *byExpiry) Less(i, j int) bool {
return (*b)[i].expiry.Before((*b)[j].expiry)
}
func (b *byExpiry) Swap(i, j int) {
(*b)[i], (*b)[j] = (*b)[j], (*b)[i]
(*b)[i].byExpiryIndex = i
(*b)[j].byExpiryIndex = j
}
func (b *byExpiry) Push(x interface{}) {
n := x.(*memLSNode)
n.byExpiryIndex = len(*b)
*b = append(*b, n)
}
func (b *byExpiry) Pop() interface{} {
i := len(*b) - 1
n := (*b)[i]
(*b)[i] = nil
n.byExpiryIndex = -1
*b = (*b)[:i]
return n
}
const infiniteTimeout = -1
// parseTimeout parses the Timeout HTTP header, as per section 10.7. If s is
// empty, an infiniteTimeout is returned.
func parseTimeout(s string) (time.Duration, error) {
if s == "" {
return infiniteTimeout, nil
}
if i := strings.IndexByte(s, ','); i >= 0 {
s = s[:i]
}
s = strings.TrimSpace(s)
if s == "Infinite" {
return infiniteTimeout, nil
}
const pre = "Second-"
if !strings.HasPrefix(s, pre) {
return 0, errInvalidTimeout
}
s = s[len(pre):]
if s == "" || s[0] < '0' || '9' < s[0] {
return 0, errInvalidTimeout
}
n, err := strconv.ParseInt(s, 10, 64)
if err != nil || 1<<32-1 < n {
return 0, errInvalidTimeout
}
return time.Duration(n) * time.Second, nil
}
// 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.
package webdav
import (
"bytes"
"context"
"encoding/xml"
"errors"
"fmt"
"io"
"mime"
"net/http"
"os"
"path/filepath"
"strconv"
)
// Proppatch describes a property update instruction as defined in RFC 4918.
// See http://www.webdav.org/specs/rfc4918.html#METHOD_PROPPATCH
type Proppatch struct {
// Remove specifies whether this patch removes properties. If it does not
// remove them, it sets them.
Remove bool
// Props contains the properties to be set or removed.
Props []Property
}
// Propstat describes a XML propstat element as defined in RFC 4918.
// See http://www.webdav.org/specs/rfc4918.html#ELEMENT_propstat
type Propstat struct {
// Props contains the properties for which Status applies.
Props []Property
// Status defines the HTTP status code of the properties in Prop.
// Allowed values include, but are not limited to the WebDAV status
// code extensions for HTTP/1.1.
// http://www.webdav.org/specs/rfc4918.html#status.code.extensions.to.http11
Status int
// XMLError contains the XML representation of the optional error element.
// XML content within this field must not rely on any predefined
// namespace declarations or prefixes. If empty, the XML error element
// is omitted.
XMLError string
// ResponseDescription contains the contents of the optional
// responsedescription field. If empty, the XML element is omitted.
ResponseDescription string
}
// makePropstats returns a slice containing those of x and y whose Props slice
// is non-empty. If both are empty, it returns a slice containing an otherwise
// zero Propstat whose HTTP status code is 200 OK.
func makePropstats(x, y Propstat) []Propstat {
pstats := make([]Propstat, 0, 2)
if len(x.Props) != 0 {
pstats = append(pstats, x)
}
if len(y.Props) != 0 {
pstats = append(pstats, y)
}
if len(pstats) == 0 {
pstats = append(pstats, Propstat{
Status: http.StatusOK,
})
}
return pstats
}
// DeadPropsHolder holds the dead properties of a resource.
//
// Dead properties are those properties that are explicitly defined. In
// comparison, live properties, such as DAV:getcontentlength, are implicitly
// defined by the underlying resource, and cannot be explicitly overridden or
// removed. See the Terminology section of
// http://www.webdav.org/specs/rfc4918.html#rfc.section.3
//
// There is a whitelist of the names of live properties. This package handles
// all live properties, and will only pass non-whitelisted names to the Patch
// method of DeadPropsHolder implementations.
type DeadPropsHolder interface {
// DeadProps returns a copy of the dead properties held.
DeadProps() (map[xml.Name]Property, error)
// Patch patches the dead properties held.
//
// Patching is atomic; either all or no patches succeed. It returns (nil,
// non-nil) if an internal server error occurred, otherwise the Propstats
// collectively contain one Property for each proposed patch Property. If
// all patches succeed, Patch returns a slice of length one and a Propstat
// element with a 200 OK HTTP status code. If none succeed, for reasons
// other than an internal server error, no Propstat has status 200 OK.
//
// For more details on when various HTTP status codes apply, see
// http://www.webdav.org/specs/rfc4918.html#PROPPATCH-status
Patch([]Proppatch) ([]Propstat, error)
}
// liveProps contains all supported, protected DAV: properties.
var liveProps = map[xml.Name]struct {
// findFn implements the propfind function of this property. If nil,
// it indicates a hidden property.
findFn func(context.Context, FileSystem, LockSystem, string, os.FileInfo) (string, error)
// dir is true if the property applies to directories.
dir bool
}{
{Space: "DAV:", Local: "resourcetype"}: {
findFn: findResourceType,
dir: true,
},
{Space: "DAV:", Local: "displayname"}: {
findFn: findDisplayName,
dir: true,
},
{Space: "DAV:", Local: "getcontentlength"}: {
findFn: findContentLength,
dir: false,
},
{Space: "DAV:", Local: "getlastmodified"}: {
findFn: findLastModified,
// http://webdav.org/specs/rfc4918.html#PROPERTY_getlastmodified
// suggests that getlastmodified should only apply to GETable
// resources, and this package does not support GET on directories.
//
// Nonetheless, some WebDAV clients expect child directories to be
// sortable by getlastmodified date, so this value is true, not false.
// See golang.org/issue/15334.
dir: true,
},
{Space: "DAV:", Local: "creationdate"}: {
findFn: nil,
dir: false,
},
{Space: "DAV:", Local: "getcontentlanguage"}: {
findFn: nil,
dir: false,
},
{Space: "DAV:", Local: "getcontenttype"}: {
findFn: findContentType,
dir: false,
},
{Space: "DAV:", Local: "getetag"}: {
findFn: findETag,
// findETag implements ETag as the concatenated hex values of a file's
// modification time and size. This is not a reliable synchronization
// mechanism for directories, so we do not advertise getetag for DAV
// collections.
dir: false,
},
// TODO: The lockdiscovery property requires LockSystem to list the
// active locks on a resource.
{Space: "DAV:", Local: "lockdiscovery"}: {},
{Space: "DAV:", Local: "supportedlock"}: {
findFn: findSupportedLock,
dir: true,
},
}
// TODO(nigeltao) merge props and allprop?
// props returns the status of the properties named pnames for resource name.
//
// Each Propstat has a unique status and each property name will only be part
// of one Propstat element.
func props(ctx context.Context, fs FileSystem, ls LockSystem, name string, pnames []xml.Name) ([]Propstat, error) {
f, err := fs.OpenFile(ctx, name, os.O_RDONLY, 0)
if err != nil {
return nil, err
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
return nil, err
}
isDir := fi.IsDir()
var deadProps map[xml.Name]Property
if dph, ok := f.(DeadPropsHolder); ok {
deadProps, err = dph.DeadProps()
if err != nil {
return nil, err
}
}
pstatOK := Propstat{Status: http.StatusOK}
pstatNotFound := Propstat{Status: http.StatusNotFound}
for _, pn := range pnames {
// If this file has dead properties, check if they contain pn.
if dp, ok := deadProps[pn]; ok {
pstatOK.Props = append(pstatOK.Props, dp)
continue
}
// Otherwise, it must either be a live property or we don't know it.
if prop := liveProps[pn]; prop.findFn != nil && (prop.dir || !isDir) {
innerXML, err := prop.findFn(ctx, fs, ls, name, fi)
if err != nil {
return nil, err
}
pstatOK.Props = append(pstatOK.Props, Property{
XMLName: pn,
InnerXML: []byte(innerXML),
})
} else {
pstatNotFound.Props = append(pstatNotFound.Props, Property{
XMLName: pn,
})
}
}
return makePropstats(pstatOK, pstatNotFound), nil
}
// propnames returns the property names defined for resource name.
func propnames(ctx context.Context, fs FileSystem, ls LockSystem, name string) ([]xml.Name, error) {
f, err := fs.OpenFile(ctx, name, os.O_RDONLY, 0)
if err != nil {
return nil, err
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
return nil, err
}
isDir := fi.IsDir()
var deadProps map[xml.Name]Property
if dph, ok := f.(DeadPropsHolder); ok {
deadProps, err = dph.DeadProps()
if err != nil {
return nil, err
}
}
pnames := make([]xml.Name, 0, len(liveProps)+len(deadProps))
for pn, prop := range liveProps {
if prop.findFn != nil && (prop.dir || !isDir) {
pnames = append(pnames, pn)
}
}
for pn := range deadProps {
pnames = append(pnames, pn)
}
return pnames, nil
}
// allprop returns the properties defined for resource name and the properties
// named in include.
//
// Note that RFC 4918 defines 'allprop' to return the DAV: properties defined
// within the RFC plus dead properties. Other live properties should only be
// returned if they are named in 'include'.
//
// See http://www.webdav.org/specs/rfc4918.html#METHOD_PROPFIND
func allprop(ctx context.Context, fs FileSystem, ls LockSystem, name string, include []xml.Name) ([]Propstat, error) {
pnames, err := propnames(ctx, fs, ls, name)
if err != nil {
return nil, err
}
// Add names from include if they are not already covered in pnames.
nameset := make(map[xml.Name]bool)
for _, pn := range pnames {
nameset[pn] = true
}
for _, pn := range include {
if !nameset[pn] {
pnames = append(pnames, pn)
}
}
return props(ctx, fs, ls, name, pnames)
}
// patch patches the properties of resource name. The return values are
// constrained in the same manner as DeadPropsHolder.Patch.
func patch(ctx context.Context, fs FileSystem, ls LockSystem, name string, patches []Proppatch) ([]Propstat, error) {
conflict := false
loop:
for _, patch := range patches {
for _, p := range patch.Props {
if _, ok := liveProps[p.XMLName]; ok {
conflict = true
break loop
}
}
}
if conflict {
pstatForbidden := Propstat{
Status: http.StatusForbidden,
XMLError: `<D:cannot-modify-protected-property xmlns:D="DAV:"/>`,
}
pstatFailedDep := Propstat{
Status: StatusFailedDependency,
}
for _, patch := range patches {
for _, p := range patch.Props {
if _, ok := liveProps[p.XMLName]; ok {
pstatForbidden.Props = append(pstatForbidden.Props, Property{XMLName: p.XMLName})
} else {
pstatFailedDep.Props = append(pstatFailedDep.Props, Property{XMLName: p.XMLName})
}
}
}
return makePropstats(pstatForbidden, pstatFailedDep), nil
}
f, err := fs.OpenFile(ctx, name, os.O_RDWR, 0)
if err != nil {
return nil, err
}
defer f.Close()
if dph, ok := f.(DeadPropsHolder); ok {
ret, err := dph.Patch(patches)
if err != nil {
return nil, err
}
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_propstat says that
// "The contents of the prop XML element must only list the names of
// properties to which the result in the status element applies."
for _, pstat := range ret {
for i, p := range pstat.Props {
pstat.Props[i] = Property{XMLName: p.XMLName}
}
}
return ret, nil
}
// The file doesn't implement the optional DeadPropsHolder interface, so
// all patches are forbidden.
pstat := Propstat{Status: http.StatusForbidden}
for _, patch := range patches {
for _, p := range patch.Props {
pstat.Props = append(pstat.Props, Property{XMLName: p.XMLName})
}
}
return []Propstat{pstat}, nil
}
func escapeXML(s string) string {
for i := 0; i < len(s); i++ {
// As an optimization, if s contains only ASCII letters, digits or a
// few special characters, the escaped value is s itself and we don't
// need to allocate a buffer and convert between string and []byte.
switch c := s[i]; {
case c == ' ' || c == '_' ||
('+' <= c && c <= '9') || // Digits as well as + , - . and /
('A' <= c && c <= 'Z') ||
('a' <= c && c <= 'z'):
continue
}
// Otherwise, go through the full escaping process.
var buf bytes.Buffer
xml.EscapeText(&buf, []byte(s))
return buf.String()
}
return s
}
func findResourceType(ctx context.Context, fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) {
if fi.IsDir() {
return `<D:collection xmlns:D="DAV:"/>`, nil
}
return "", nil
}
func findDisplayName(ctx context.Context, fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) {
if slashClean(name) == "/" {
// Hide the real name of a possibly prefixed root directory.
return "", nil
}
return escapeXML(fi.Name()), nil
}
func findContentLength(ctx context.Context, fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) {
return strconv.FormatInt(fi.Size(), 10), nil
}
func findLastModified(ctx context.Context, fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) {
return fi.ModTime().UTC().Format(http.TimeFormat), nil
}
// ErrNotImplemented should be returned by optional interfaces if they
// want the original implementation to be used.
var ErrNotImplemented = errors.New("not implemented")
// ContentTyper is an optional interface for the os.FileInfo
// objects returned by the FileSystem.
//
// If this interface is defined then it will be used to read the
// content type from the object.
//
// If this interface is not defined the file will be opened and the
// content type will be guessed from the initial contents of the file.
type ContentTyper interface {
// ContentType returns the content type for the file.
//
// If this returns error ErrNotImplemented then the error will
// be ignored and the base implementation will be used
// instead.
ContentType(ctx context.Context) (string, error)
}
func findContentType(ctx context.Context, fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) {
if do, ok := fi.(ContentTyper); ok {
ctype, err := do.ContentType(ctx)
if err != ErrNotImplemented {
return ctype, err
}
}
f, err := fs.OpenFile(ctx, name, os.O_RDONLY, 0)
if err != nil {
return "", err
}
defer f.Close()
// This implementation is based on serveContent's code in the standard net/http package.
ctype := mime.TypeByExtension(filepath.Ext(name))
if ctype != "" {
return ctype, nil
}
// Read a chunk to decide between utf-8 text and binary.
var buf [512]byte
n, err := io.ReadFull(f, buf[:])
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
return "", err
}
ctype = http.DetectContentType(buf[:n])
// Rewind file.
_, err = f.Seek(0, io.SeekStart)
return ctype, err
}
// ETager is an optional interface for the os.FileInfo objects
// returned by the FileSystem.
//
// If this interface is defined then it will be used to read the ETag
// for the object.
//
// If this interface is not defined an ETag will be computed using the
// ModTime() and the Size() methods of the os.FileInfo object.
type ETager interface {
// ETag returns an ETag for the file. This should be of the
// form "value" or W/"value"
//
// If this returns error ErrNotImplemented then the error will
// be ignored and the base implementation will be used
// instead.
ETag(ctx context.Context) (string, error)
}
func findETag(ctx context.Context, fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) {
if do, ok := fi.(ETager); ok {
etag, err := do.ETag(ctx)
if err != ErrNotImplemented {
return etag, err
}
}
// The Apache http 2.4 web server by default concatenates the
// modification time and size of a file. We replicate the heuristic
// with nanosecond granularity.
return fmt.Sprintf(`"%x%x"`, fi.ModTime().UnixNano(), fi.Size()), nil
}
func findSupportedLock(ctx context.Context, fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) {
return `` +
`<D:lockentry xmlns:D="DAV:">` +
`<D:lockscope><D:exclusive/></D:lockscope>` +
`<D:locktype><D:write/></D:locktype>` +
`</D:lockentry>`, nil
}
// 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 webdav provides a WebDAV server implementation.
package webdav // import "golang.org/x/net/webdav"
import (
"errors"
"fmt"
"io"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
"strings"
"time"
)
type Handler struct {
// Prefix is the URL path prefix to strip from WebDAV resource paths.
Prefix string
// FileSystem is the virtual file system.
FileSystem FileSystem
// LockSystem is the lock management system.
LockSystem LockSystem
// Logger is an optional error logger. If non-nil, it will be called
// for all HTTP requests.
Logger func(*http.Request, error)
}
func (h *Handler) stripPrefix(p string) (string, int, error) {
if h.Prefix == "" {
return p, http.StatusOK, nil
}
if r := strings.TrimPrefix(p, h.Prefix); len(r) < len(p) {
return r, http.StatusOK, nil
}
return p, http.StatusNotFound, errPrefixMismatch
}
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
status, err := http.StatusBadRequest, errUnsupportedMethod
if h.FileSystem == nil {
status, err = http.StatusInternalServerError, errNoFileSystem
} else if h.LockSystem == nil {
status, err = http.StatusInternalServerError, errNoLockSystem
} else {
switch r.Method {
case "OPTIONS":
status, err = h.handleOptions(w, r)
case "GET", "HEAD", "POST":
status, err = h.handleGetHeadPost(w, r)
case "DELETE":
status, err = h.handleDelete(w, r)
case "PUT":
status, err = h.handlePut(w, r)
case "MKCOL":
status, err = h.handleMkcol(w, r)
case "COPY", "MOVE":
status, err = h.handleCopyMove(w, r)
case "LOCK":
status, err = h.handleLock(w, r)
case "UNLOCK":
status, err = h.handleUnlock(w, r)
case "PROPFIND":
status, err = h.handlePropfind(w, r)
case "PROPPATCH":
status, err = h.handleProppatch(w, r)
}
}
if status != 0 {
w.WriteHeader(status)
if status != http.StatusNoContent {
w.Write([]byte(StatusText(status)))
}
}
if h.Logger != nil {
h.Logger(r, err)
}
}
func (h *Handler) lock(now time.Time, root string) (token string, status int, err error) {
token, err = h.LockSystem.Create(now, LockDetails{
Root: root,
Duration: infiniteTimeout,
ZeroDepth: true,
})
if err != nil {
if err == ErrLocked {
return "", StatusLocked, err
}
return "", http.StatusInternalServerError, err
}
return token, 0, nil
}
func (h *Handler) confirmLocks(r *http.Request, src, dst string) (release func(), status int, err error) {
hdr := r.Header.Get("If")
if hdr == "" {
// An empty If header means that the client hasn't previously created locks.
// Even if this client doesn't care about locks, we still need to check that
// the resources aren't locked by another client, so we create temporary
// locks that would conflict with another client's locks. These temporary
// locks are unlocked at the end of the HTTP request.
now, srcToken, dstToken := time.Now(), "", ""
if src != "" {
srcToken, status, err = h.lock(now, src)
if err != nil {
return nil, status, err
}
}
if dst != "" {
dstToken, status, err = h.lock(now, dst)
if err != nil {
if srcToken != "" {
h.LockSystem.Unlock(now, srcToken)
}
return nil, status, err
}
}
return func() {
if dstToken != "" {
h.LockSystem.Unlock(now, dstToken)
}
if srcToken != "" {
h.LockSystem.Unlock(now, srcToken)
}
}, 0, nil
}
ih, ok := parseIfHeader(hdr)
if !ok {
return nil, http.StatusBadRequest, errInvalidIfHeader
}
// ih is a disjunction (OR) of ifLists, so any ifList will do.
for _, l := range ih.lists {
lsrc := l.resourceTag
if lsrc == "" {
lsrc = src
} else {
u, err := url.Parse(lsrc)
if err != nil {
continue
}
if u.Host != r.Host {
continue
}
lsrc, status, err = h.stripPrefix(u.Path)
if err != nil {
return nil, status, err
}
}
release, err = h.LockSystem.Confirm(time.Now(), lsrc, dst, l.conditions...)
if err == ErrConfirmationFailed {
continue
}
if err != nil {
return nil, http.StatusInternalServerError, err
}
return release, 0, nil
}
// Section 10.4.1 says that "If this header is evaluated and all state lists
// fail, then the request must fail with a 412 (Precondition Failed) status."
// We follow the spec even though the cond_put_corrupt_token test case from
// the litmus test warns on seeing a 412 instead of a 423 (Locked).
return nil, http.StatusPreconditionFailed, ErrLocked
}
func (h *Handler) handleOptions(w http.ResponseWriter, r *http.Request) (status int, err error) {
reqPath, status, err := h.stripPrefix(r.URL.Path)
if err != nil {
return status, err
}
ctx := r.Context()
allow := "OPTIONS, LOCK, PUT, MKCOL"
if fi, err := h.FileSystem.Stat(ctx, reqPath); err == nil {
if fi.IsDir() {
allow = "OPTIONS, LOCK, DELETE, PROPPATCH, COPY, MOVE, UNLOCK, PROPFIND"
} else {
allow = "OPTIONS, LOCK, GET, HEAD, POST, DELETE, PROPPATCH, COPY, MOVE, UNLOCK, PROPFIND, PUT"
}
}
w.Header().Set("Allow", allow)
// http://www.webdav.org/specs/rfc4918.html#dav.compliance.classes
w.Header().Set("DAV", "1, 2")
// http://msdn.microsoft.com/en-au/library/cc250217.aspx
w.Header().Set("MS-Author-Via", "DAV")
return 0, nil
}
func (h *Handler) handleGetHeadPost(w http.ResponseWriter, r *http.Request) (status int, err error) {
reqPath, status, err := h.stripPrefix(r.URL.Path)
if err != nil {
return status, err
}
// TODO: check locks for read-only access??
ctx := r.Context()
f, err := h.FileSystem.OpenFile(ctx, reqPath, os.O_RDONLY, 0)
if err != nil {
return http.StatusNotFound, err
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
return http.StatusNotFound, err
}
if fi.IsDir() {
return http.StatusMethodNotAllowed, nil
}
etag, err := findETag(ctx, h.FileSystem, h.LockSystem, reqPath, fi)
if err != nil {
return http.StatusInternalServerError, err
}
w.Header().Set("ETag", etag)
// Let ServeContent determine the Content-Type header.
http.ServeContent(w, r, reqPath, fi.ModTime(), f)
return 0, nil
}
func (h *Handler) handleDelete(w http.ResponseWriter, r *http.Request) (status int, err error) {
reqPath, status, err := h.stripPrefix(r.URL.Path)
if err != nil {
return status, err
}
release, status, err := h.confirmLocks(r, reqPath, "")
if err != nil {
return status, err
}
defer release()
ctx := r.Context()
// TODO: return MultiStatus where appropriate.
// "godoc os RemoveAll" says that "If the path does not exist, RemoveAll
// returns nil (no error)." WebDAV semantics are that it should return a
// "404 Not Found". We therefore have to Stat before we RemoveAll.
if _, err := h.FileSystem.Stat(ctx, reqPath); err != nil {
if os.IsNotExist(err) {
return http.StatusNotFound, err
}
return http.StatusMethodNotAllowed, err
}
if err := h.FileSystem.RemoveAll(ctx, reqPath); err != nil {
return http.StatusMethodNotAllowed, err
}
return http.StatusNoContent, nil
}
func (h *Handler) handlePut(w http.ResponseWriter, r *http.Request) (status int, err error) {
reqPath, status, err := h.stripPrefix(r.URL.Path)
if err != nil {
return status, err
}
release, status, err := h.confirmLocks(r, reqPath, "")
if err != nil {
return status, err
}
defer release()
// TODO(rost): Support the If-Match, If-None-Match headers? See bradfitz'
// comments in http.checkEtag.
ctx := r.Context()
f, err := h.FileSystem.OpenFile(ctx, reqPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
if os.IsNotExist(err) {
return http.StatusConflict, err
}
return http.StatusNotFound, err
}
_, copyErr := io.Copy(f, r.Body)
fi, statErr := f.Stat()
closeErr := f.Close()
// TODO(rost): Returning 405 Method Not Allowed might not be appropriate.
if copyErr != nil {
return http.StatusMethodNotAllowed, copyErr
}
if statErr != nil {
return http.StatusMethodNotAllowed, statErr
}
if closeErr != nil {
return http.StatusMethodNotAllowed, closeErr
}
etag, err := findETag(ctx, h.FileSystem, h.LockSystem, reqPath, fi)
if err != nil {
return http.StatusInternalServerError, err
}
w.Header().Set("ETag", etag)
return http.StatusCreated, nil
}
func (h *Handler) handleMkcol(w http.ResponseWriter, r *http.Request) (status int, err error) {
reqPath, status, err := h.stripPrefix(r.URL.Path)
if err != nil {
return status, err
}
release, status, err := h.confirmLocks(r, reqPath, "")
if err != nil {
return status, err
}
defer release()
ctx := r.Context()
if r.ContentLength > 0 {
return http.StatusUnsupportedMediaType, nil
}
if err := h.FileSystem.Mkdir(ctx, reqPath, 0777); err != nil {
if os.IsNotExist(err) {
return http.StatusConflict, err
}
return http.StatusMethodNotAllowed, err
}
return http.StatusCreated, nil
}
func (h *Handler) handleCopyMove(w http.ResponseWriter, r *http.Request) (status int, err error) {
hdr := r.Header.Get("Destination")
if hdr == "" {
return http.StatusBadRequest, errInvalidDestination
}
u, err := url.Parse(hdr)
if err != nil {
return http.StatusBadRequest, errInvalidDestination
}
if u.Host != "" && u.Host != r.Host {
return http.StatusBadGateway, errInvalidDestination
}
src, status, err := h.stripPrefix(r.URL.Path)
if err != nil {
return status, err
}
dst, status, err := h.stripPrefix(u.Path)
if err != nil {
return status, err
}
if dst == "" {
return http.StatusBadGateway, errInvalidDestination
}
if dst == src {
return http.StatusForbidden, errDestinationEqualsSource
}
ctx := r.Context()
if r.Method == "COPY" {
// Section 7.5.1 says that a COPY only needs to lock the destination,
// not both destination and source. Strictly speaking, this is racy,
// even though a COPY doesn't modify the source, if a concurrent
// operation modifies the source. However, the litmus test explicitly
// checks that COPYing a locked-by-another source is OK.
release, status, err := h.confirmLocks(r, "", dst)
if err != nil {
return status, err
}
defer release()
// Section 9.8.3 says that "The COPY method on a collection without a Depth
// header must act as if a Depth header with value "infinity" was included".
depth := infiniteDepth
if hdr := r.Header.Get("Depth"); hdr != "" {
depth = parseDepth(hdr)
if depth != 0 && depth != infiniteDepth {
// Section 9.8.3 says that "A client may submit a Depth header on a
// COPY on a collection with a value of "0" or "infinity"."
return http.StatusBadRequest, errInvalidDepth
}
}
return copyFiles(ctx, h.FileSystem, src, dst, r.Header.Get("Overwrite") != "F", depth, 0)
}
release, status, err := h.confirmLocks(r, src, dst)
if err != nil {
return status, err
}
defer release()
// Section 9.9.2 says that "The MOVE method on a collection must act as if
// a "Depth: infinity" header was used on it. A client must not submit a
// Depth header on a MOVE on a collection with any value but "infinity"."
if hdr := r.Header.Get("Depth"); hdr != "" {
if parseDepth(hdr) != infiniteDepth {
return http.StatusBadRequest, errInvalidDepth
}
}
return moveFiles(ctx, h.FileSystem, src, dst, r.Header.Get("Overwrite") == "T")
}
func (h *Handler) handleLock(w http.ResponseWriter, r *http.Request) (retStatus int, retErr error) {
duration, err := parseTimeout(r.Header.Get("Timeout"))
if err != nil {
return http.StatusBadRequest, err
}
li, status, err := readLockInfo(r.Body)
if err != nil {
return status, err
}
ctx := r.Context()
token, ld, now, created := "", LockDetails{}, time.Now(), false
if li == (lockInfo{}) {
// An empty lockInfo means to refresh the lock.
ih, ok := parseIfHeader(r.Header.Get("If"))
if !ok {
return http.StatusBadRequest, errInvalidIfHeader
}
if len(ih.lists) == 1 && len(ih.lists[0].conditions) == 1 {
token = ih.lists[0].conditions[0].Token
}
if token == "" {
return http.StatusBadRequest, errInvalidLockToken
}
ld, err = h.LockSystem.Refresh(now, token, duration)
if err != nil {
if err == ErrNoSuchLock {
return http.StatusPreconditionFailed, err
}
return http.StatusInternalServerError, err
}
} else {
// Section 9.10.3 says that "If no Depth header is submitted on a LOCK request,
// then the request MUST act as if a "Depth:infinity" had been submitted."
depth := infiniteDepth
if hdr := r.Header.Get("Depth"); hdr != "" {
depth = parseDepth(hdr)
if depth != 0 && depth != infiniteDepth {
// Section 9.10.3 says that "Values other than 0 or infinity must not be
// used with the Depth header on a LOCK method".
return http.StatusBadRequest, errInvalidDepth
}
}
reqPath, status, err := h.stripPrefix(r.URL.Path)
if err != nil {
return status, err
}
ld = LockDetails{
Root: reqPath,
Duration: duration,
OwnerXML: li.Owner.InnerXML,
ZeroDepth: depth == 0,
}
token, err = h.LockSystem.Create(now, ld)
if err != nil {
if err == ErrLocked {
return StatusLocked, err
}
return http.StatusInternalServerError, err
}
defer func() {
if retErr != nil {
h.LockSystem.Unlock(now, token)
}
}()
// Create the resource if it didn't previously exist.
if _, err := h.FileSystem.Stat(ctx, reqPath); err != nil {
f, err := h.FileSystem.OpenFile(ctx, reqPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
// TODO: detect missing intermediate dirs and return http.StatusConflict?
return http.StatusInternalServerError, err
}
f.Close()
created = true
}
// http://www.webdav.org/specs/rfc4918.html#HEADER_Lock-Token says that the
// Lock-Token value is a Coded-URL. We add angle brackets.
w.Header().Set("Lock-Token", "<"+token+">")
}
w.Header().Set("Content-Type", "application/xml; charset=utf-8")
if created {
// This is "w.WriteHeader(http.StatusCreated)" and not "return
// http.StatusCreated, nil" because we write our own (XML) response to w
// and Handler.ServeHTTP would otherwise write "Created".
w.WriteHeader(http.StatusCreated)
}
writeLockInfo(w, token, ld)
return 0, nil
}
func (h *Handler) handleUnlock(w http.ResponseWriter, r *http.Request) (status int, err error) {
// http://www.webdav.org/specs/rfc4918.html#HEADER_Lock-Token says that the
// Lock-Token value is a Coded-URL. We strip its angle brackets.
t := r.Header.Get("Lock-Token")
if len(t) < 2 || t[0] != '<' || t[len(t)-1] != '>' {
return http.StatusBadRequest, errInvalidLockToken
}
t = t[1 : len(t)-1]
switch err = h.LockSystem.Unlock(time.Now(), t); err {
case nil:
return http.StatusNoContent, err
case ErrForbidden:
return http.StatusForbidden, err
case ErrLocked:
return StatusLocked, err
case ErrNoSuchLock:
return http.StatusConflict, err
default:
return http.StatusInternalServerError, err
}
}
func (h *Handler) handlePropfind(w http.ResponseWriter, r *http.Request) (status int, err error) {
reqPath, status, err := h.stripPrefix(r.URL.Path)
if err != nil {
return status, err
}
ctx := r.Context()
fi, err := h.FileSystem.Stat(ctx, reqPath)
if err != nil {
if os.IsNotExist(err) {
return http.StatusNotFound, err
}
return http.StatusMethodNotAllowed, err
}
depth := infiniteDepth
if hdr := r.Header.Get("Depth"); hdr != "" {
depth = parseDepth(hdr)
if depth == invalidDepth {
return http.StatusBadRequest, errInvalidDepth
}
}
pf, status, err := readPropfind(r.Body)
if err != nil {
return status, err
}
mw := multistatusWriter{w: w}
walkFn := func(reqPath string, info os.FileInfo, err error) error {
if err != nil {
return handlePropfindError(err, info)
}
var pstats []Propstat
if pf.Propname != nil {
pnames, err := propnames(ctx, h.FileSystem, h.LockSystem, reqPath)
if err != nil {
return handlePropfindError(err, info)
}
pstat := Propstat{Status: http.StatusOK}
for _, xmlname := range pnames {
pstat.Props = append(pstat.Props, Property{XMLName: xmlname})
}
pstats = append(pstats, pstat)
} else if pf.Allprop != nil {
pstats, err = allprop(ctx, h.FileSystem, h.LockSystem, reqPath, pf.Prop)
} else {
pstats, err = props(ctx, h.FileSystem, h.LockSystem, reqPath, pf.Prop)
}
if err != nil {
return handlePropfindError(err, info)
}
href := path.Join(h.Prefix, reqPath)
if href != "/" && info.IsDir() {
href += "/"
}
return mw.write(makePropstatResponse(href, pstats))
}
walkErr := walkFS(ctx, h.FileSystem, depth, reqPath, fi, walkFn)
closeErr := mw.close()
if walkErr != nil {
return http.StatusInternalServerError, walkErr
}
if closeErr != nil {
return http.StatusInternalServerError, closeErr
}
return 0, nil
}
func (h *Handler) handleProppatch(w http.ResponseWriter, r *http.Request) (status int, err error) {
reqPath, status, err := h.stripPrefix(r.URL.Path)
if err != nil {
return status, err
}
release, status, err := h.confirmLocks(r, reqPath, "")
if err != nil {
return status, err
}
defer release()
ctx := r.Context()
if _, err := h.FileSystem.Stat(ctx, reqPath); err != nil {
if os.IsNotExist(err) {
return http.StatusNotFound, err
}
return http.StatusMethodNotAllowed, err
}
patches, status, err := readProppatch(r.Body)
if err != nil {
return status, err
}
pstats, err := patch(ctx, h.FileSystem, h.LockSystem, reqPath, patches)
if err != nil {
return http.StatusInternalServerError, err
}
mw := multistatusWriter{w: w}
writeErr := mw.write(makePropstatResponse(r.URL.Path, pstats))
closeErr := mw.close()
if writeErr != nil {
return http.StatusInternalServerError, writeErr
}
if closeErr != nil {
return http.StatusInternalServerError, closeErr
}
return 0, nil
}
func makePropstatResponse(href string, pstats []Propstat) *response {
resp := response{
Href: []string{(&url.URL{Path: href}).EscapedPath()},
Propstat: make([]propstat, 0, len(pstats)),
}
for _, p := range pstats {
var xmlErr *xmlError
if p.XMLError != "" {
xmlErr = &xmlError{InnerXML: []byte(p.XMLError)}
}
resp.Propstat = append(resp.Propstat, propstat{
Status: fmt.Sprintf("HTTP/1.1 %d %s", p.Status, StatusText(p.Status)),
Prop: p.Props,
ResponseDescription: p.ResponseDescription,
Error: xmlErr,
})
}
return &resp
}
func handlePropfindError(err error, info os.FileInfo) error {
var skipResp error = nil
if info != nil && info.IsDir() {
skipResp = filepath.SkipDir
}
if errors.Is(err, os.ErrPermission) {
// If the server cannot recurse into a directory because it is not allowed,
// then there is nothing more to say about it. Just skip sending anything.
return skipResp
}
if _, ok := err.(*os.PathError); ok {
// If the file is just bad, it couldn't be a proper WebDAV resource. Skip it.
return skipResp
}
// We need to be careful with other errors: there is no way to abort the xml stream
// part way through while returning a valid PROPFIND response. Returning only half
// the data would be misleading, but so would be returning results tainted by errors.
// The current behaviour by returning an error here leads to the stream being aborted,
// and the parent http server complaining about writing a spurious header. We should
// consider further enhancing this error handling to more gracefully fail, or perhaps
// buffer the entire response until we've walked the tree.
return err
}
const (
infiniteDepth = -1
invalidDepth = -2
)
// parseDepth maps the strings "0", "1" and "infinity" to 0, 1 and
// infiniteDepth. Parsing any other string returns invalidDepth.
//
// Different WebDAV methods have further constraints on valid depths:
// - PROPFIND has no further restrictions, as per section 9.1.
// - COPY accepts only "0" or "infinity", as per section 9.8.3.
// - MOVE accepts only "infinity", as per section 9.9.2.
// - LOCK accepts only "0" or "infinity", as per section 9.10.3.
//
// These constraints are enforced by the handleXxx methods.
func parseDepth(s string) int {
switch s {
case "0":
return 0
case "1":
return 1
case "infinity":
return infiniteDepth
}
return invalidDepth
}
// http://www.webdav.org/specs/rfc4918.html#status.code.extensions.to.http11
const (
StatusMulti = 207
StatusUnprocessableEntity = 422
StatusLocked = 423
StatusFailedDependency = 424
StatusInsufficientStorage = 507
)
func StatusText(code int) string {
switch code {
case StatusMulti:
return "Multi-Status"
case StatusUnprocessableEntity:
return "Unprocessable Entity"
case StatusLocked:
return "Locked"
case StatusFailedDependency:
return "Failed Dependency"
case StatusInsufficientStorage:
return "Insufficient Storage"
}
return http.StatusText(code)
}
var (
errDestinationEqualsSource = errors.New("webdav: destination equals source")
errDirectoryNotEmpty = errors.New("webdav: directory not empty")
errInvalidDepth = errors.New("webdav: invalid depth")
errInvalidDestination = errors.New("webdav: invalid destination")
errInvalidIfHeader = errors.New("webdav: invalid If header")
errInvalidLockInfo = errors.New("webdav: invalid lock info")
errInvalidLockToken = errors.New("webdav: invalid lock token")
errInvalidPropfind = errors.New("webdav: invalid propfind")
errInvalidProppatch = errors.New("webdav: invalid proppatch")
errInvalidResponse = errors.New("webdav: invalid response")
errInvalidTimeout = errors.New("webdav: invalid timeout")
errNoFileSystem = errors.New("webdav: no file system")
errNoLockSystem = errors.New("webdav: no lock system")
errNotADirectory = errors.New("webdav: not a directory")
errPrefixMismatch = errors.New("webdav: prefix mismatch")
errRecursionTooDeep = errors.New("webdav: recursion too deep")
errUnsupportedLockInfo = errors.New("webdav: unsupported lock info")
errUnsupportedMethod = errors.New("webdav: unsupported method")
)
// 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 webdav
// The XML encoding is covered by Section 14.
// http://www.webdav.org/specs/rfc4918.html#xml.element.definitions
import (
"bytes"
"encoding/xml"
"fmt"
"io"
"net/http"
"time"
// As of https://go-review.googlesource.com/#/c/12772/ which was submitted
// in July 2015, this package uses an internal fork of the standard
// library's encoding/xml package, due to changes in the way namespaces
// were encoded. Such changes were introduced in the Go 1.5 cycle, but were
// rolled back in response to https://github.com/golang/go/issues/11841
//
// However, this package's exported API, specifically the Property and
// DeadPropsHolder types, need to refer to the standard library's version
// of the xml.Name type, as code that imports this package cannot refer to
// the internal version.
//
// This file therefore imports both the internal and external versions, as
// ixml and xml, and converts between them.
//
// In the long term, this package should use the standard library's version
// only, and the internal fork deleted, once
// https://github.com/golang/go/issues/13400 is resolved.
ixml "golang.org/x/net/webdav/internal/xml"
)
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_lockinfo
type lockInfo struct {
XMLName ixml.Name `xml:"lockinfo"`
Exclusive *struct{} `xml:"lockscope>exclusive"`
Shared *struct{} `xml:"lockscope>shared"`
Write *struct{} `xml:"locktype>write"`
Owner owner `xml:"owner"`
}
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_owner
type owner struct {
InnerXML string `xml:",innerxml"`
}
func readLockInfo(r io.Reader) (li lockInfo, status int, err error) {
c := &countingReader{r: r}
if err = ixml.NewDecoder(c).Decode(&li); err != nil {
if err == io.EOF {
if c.n == 0 {
// An empty body means to refresh the lock.
// http://www.webdav.org/specs/rfc4918.html#refreshing-locks
return lockInfo{}, 0, nil
}
err = errInvalidLockInfo
}
return lockInfo{}, http.StatusBadRequest, err
}
// We only support exclusive (non-shared) write locks. In practice, these are
// the only types of locks that seem to matter.
if li.Exclusive == nil || li.Shared != nil || li.Write == nil {
return lockInfo{}, http.StatusNotImplemented, errUnsupportedLockInfo
}
return li, 0, nil
}
type countingReader struct {
n int
r io.Reader
}
func (c *countingReader) Read(p []byte) (int, error) {
n, err := c.r.Read(p)
c.n += n
return n, err
}
func writeLockInfo(w io.Writer, token string, ld LockDetails) (int, error) {
depth := "infinity"
if ld.ZeroDepth {
depth = "0"
}
timeout := ld.Duration / time.Second
return fmt.Fprintf(w, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"+
"<D:prop xmlns:D=\"DAV:\"><D:lockdiscovery><D:activelock>\n"+
" <D:locktype><D:write/></D:locktype>\n"+
" <D:lockscope><D:exclusive/></D:lockscope>\n"+
" <D:depth>%s</D:depth>\n"+
" <D:owner>%s</D:owner>\n"+
" <D:timeout>Second-%d</D:timeout>\n"+
" <D:locktoken><D:href>%s</D:href></D:locktoken>\n"+
" <D:lockroot><D:href>%s</D:href></D:lockroot>\n"+
"</D:activelock></D:lockdiscovery></D:prop>",
depth, ld.OwnerXML, timeout, escape(token), escape(ld.Root),
)
}
func escape(s string) string {
for i := 0; i < len(s); i++ {
switch s[i] {
case '"', '&', '\'', '<', '>':
b := bytes.NewBuffer(nil)
ixml.EscapeText(b, []byte(s))
return b.String()
}
}
return s
}
// next returns the next token, if any, in the XML stream of d.
// RFC 4918 requires to ignore comments, processing instructions
// and directives.
// http://www.webdav.org/specs/rfc4918.html#property_values
// http://www.webdav.org/specs/rfc4918.html#xml-extensibility
func next(d *ixml.Decoder) (ixml.Token, error) {
for {
t, err := d.Token()
if err != nil {
return t, err
}
switch t.(type) {
case ixml.Comment, ixml.Directive, ixml.ProcInst:
continue
default:
return t, nil
}
}
}
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_prop (for propfind)
type propfindProps []xml.Name
// UnmarshalXML appends the property names enclosed within start to pn.
//
// It returns an error if start does not contain any properties or if
// properties contain values. Character data between properties is ignored.
func (pn *propfindProps) UnmarshalXML(d *ixml.Decoder, start ixml.StartElement) error {
for {
t, err := next(d)
if err != nil {
return err
}
switch t.(type) {
case ixml.EndElement:
if len(*pn) == 0 {
return fmt.Errorf("%s must not be empty", start.Name.Local)
}
return nil
case ixml.StartElement:
name := t.(ixml.StartElement).Name
t, err = next(d)
if err != nil {
return err
}
if _, ok := t.(ixml.EndElement); !ok {
return fmt.Errorf("unexpected token %T", t)
}
*pn = append(*pn, xml.Name(name))
}
}
}
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_propfind
type propfind struct {
XMLName ixml.Name `xml:"DAV: propfind"`
Allprop *struct{} `xml:"DAV: allprop"`
Propname *struct{} `xml:"DAV: propname"`
Prop propfindProps `xml:"DAV: prop"`
Include propfindProps `xml:"DAV: include"`
}
func readPropfind(r io.Reader) (pf propfind, status int, err error) {
c := countingReader{r: r}
if err = ixml.NewDecoder(&c).Decode(&pf); err != nil {
if err == io.EOF {
if c.n == 0 {
// An empty body means to propfind allprop.
// http://www.webdav.org/specs/rfc4918.html#METHOD_PROPFIND
return propfind{Allprop: new(struct{})}, 0, nil
}
err = errInvalidPropfind
}
return propfind{}, http.StatusBadRequest, err
}
if pf.Allprop == nil && pf.Include != nil {
return propfind{}, http.StatusBadRequest, errInvalidPropfind
}
if pf.Allprop != nil && (pf.Prop != nil || pf.Propname != nil) {
return propfind{}, http.StatusBadRequest, errInvalidPropfind
}
if pf.Prop != nil && pf.Propname != nil {
return propfind{}, http.StatusBadRequest, errInvalidPropfind
}
if pf.Propname == nil && pf.Allprop == nil && pf.Prop == nil {
return propfind{}, http.StatusBadRequest, errInvalidPropfind
}
return pf, 0, nil
}
// Property represents a single DAV resource property as defined in RFC 4918.
// See http://www.webdav.org/specs/rfc4918.html#data.model.for.resource.properties
type Property struct {
// XMLName is the fully qualified name that identifies this property.
XMLName xml.Name
// Lang is an optional xml:lang attribute.
Lang string `xml:"xml:lang,attr,omitempty"`
// InnerXML contains the XML representation of the property value.
// See http://www.webdav.org/specs/rfc4918.html#property_values
//
// Property values of complex type or mixed-content must have fully
// expanded XML namespaces or be self-contained with according
// XML namespace declarations. They must not rely on any XML
// namespace declarations within the scope of the XML document,
// even including the DAV: namespace.
InnerXML []byte `xml:",innerxml"`
}
// ixmlProperty is the same as the Property type except it holds an ixml.Name
// instead of an xml.Name.
type ixmlProperty struct {
XMLName ixml.Name
Lang string `xml:"xml:lang,attr,omitempty"`
InnerXML []byte `xml:",innerxml"`
}
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_error
// See multistatusWriter for the "D:" namespace prefix.
type xmlError struct {
XMLName ixml.Name `xml:"D:error"`
InnerXML []byte `xml:",innerxml"`
}
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_propstat
// See multistatusWriter for the "D:" namespace prefix.
type propstat struct {
Prop []Property `xml:"D:prop>_ignored_"`
Status string `xml:"D:status"`
Error *xmlError `xml:"D:error"`
ResponseDescription string `xml:"D:responsedescription,omitempty"`
}
// ixmlPropstat is the same as the propstat type except it holds an ixml.Name
// instead of an xml.Name.
type ixmlPropstat struct {
Prop []ixmlProperty `xml:"D:prop>_ignored_"`
Status string `xml:"D:status"`
Error *xmlError `xml:"D:error"`
ResponseDescription string `xml:"D:responsedescription,omitempty"`
}
// MarshalXML prepends the "D:" namespace prefix on properties in the DAV: namespace
// before encoding. See multistatusWriter.
func (ps propstat) MarshalXML(e *ixml.Encoder, start ixml.StartElement) error {
// Convert from a propstat to an ixmlPropstat.
ixmlPs := ixmlPropstat{
Prop: make([]ixmlProperty, len(ps.Prop)),
Status: ps.Status,
Error: ps.Error,
ResponseDescription: ps.ResponseDescription,
}
for k, prop := range ps.Prop {
ixmlPs.Prop[k] = ixmlProperty{
XMLName: ixml.Name(prop.XMLName),
Lang: prop.Lang,
InnerXML: prop.InnerXML,
}
}
for k, prop := range ixmlPs.Prop {
if prop.XMLName.Space == "DAV:" {
prop.XMLName = ixml.Name{Space: "", Local: "D:" + prop.XMLName.Local}
ixmlPs.Prop[k] = prop
}
}
// Distinct type to avoid infinite recursion of MarshalXML.
type newpropstat ixmlPropstat
return e.EncodeElement(newpropstat(ixmlPs), start)
}
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_response
// See multistatusWriter for the "D:" namespace prefix.
type response struct {
XMLName ixml.Name `xml:"D:response"`
Href []string `xml:"D:href"`
Propstat []propstat `xml:"D:propstat"`
Status string `xml:"D:status,omitempty"`
Error *xmlError `xml:"D:error"`
ResponseDescription string `xml:"D:responsedescription,omitempty"`
}
// MultistatusWriter marshals one or more Responses into a XML
// multistatus response.
// See http://www.webdav.org/specs/rfc4918.html#ELEMENT_multistatus
// TODO(rsto, mpl): As a workaround, the "D:" namespace prefix, defined as
// "DAV:" on this element, is prepended on the nested response, as well as on all
// its nested elements. All property names in the DAV: namespace are prefixed as
// well. This is because some versions of Mini-Redirector (on windows 7) ignore
// elements with a default namespace (no prefixed namespace). A less intrusive fix
// should be possible after golang.org/cl/11074. See https://golang.org/issue/11177
type multistatusWriter struct {
// ResponseDescription contains the optional responsedescription
// of the multistatus XML element. Only the latest content before
// close will be emitted. Empty response descriptions are not
// written.
responseDescription string
w http.ResponseWriter
enc *ixml.Encoder
}
// Write validates and emits a DAV response as part of a multistatus response
// element.
//
// It sets the HTTP status code of its underlying http.ResponseWriter to 207
// (Multi-Status) and populates the Content-Type header. If r is the
// first, valid response to be written, Write prepends the XML representation
// of r with a multistatus tag. Callers must call close after the last response
// has been written.
func (w *multistatusWriter) write(r *response) error {
switch len(r.Href) {
case 0:
return errInvalidResponse
case 1:
if len(r.Propstat) > 0 != (r.Status == "") {
return errInvalidResponse
}
default:
if len(r.Propstat) > 0 || r.Status == "" {
return errInvalidResponse
}
}
err := w.writeHeader()
if err != nil {
return err
}
return w.enc.Encode(r)
}
// writeHeader writes a XML multistatus start element on w's underlying
// http.ResponseWriter and returns the result of the write operation.
// After the first write attempt, writeHeader becomes a no-op.
func (w *multistatusWriter) writeHeader() error {
if w.enc != nil {
return nil
}
w.w.Header().Add("Content-Type", "text/xml; charset=utf-8")
w.w.WriteHeader(StatusMulti)
_, err := fmt.Fprintf(w.w, `<?xml version="1.0" encoding="UTF-8"?>`)
if err != nil {
return err
}
w.enc = ixml.NewEncoder(w.w)
return w.enc.EncodeToken(ixml.StartElement{
Name: ixml.Name{
Space: "DAV:",
Local: "multistatus",
},
Attr: []ixml.Attr{{
Name: ixml.Name{Space: "xmlns", Local: "D"},
Value: "DAV:",
}},
})
}
// Close completes the marshalling of the multistatus response. It returns
// an error if the multistatus response could not be completed. If both the
// return value and field enc of w are nil, then no multistatus response has
// been written.
func (w *multistatusWriter) close() error {
if w.enc == nil {
return nil
}
var end []ixml.Token
if w.responseDescription != "" {
name := ixml.Name{Space: "DAV:", Local: "responsedescription"}
end = append(end,
ixml.StartElement{Name: name},
ixml.CharData(w.responseDescription),
ixml.EndElement{Name: name},
)
}
end = append(end, ixml.EndElement{
Name: ixml.Name{Space: "DAV:", Local: "multistatus"},
})
for _, t := range end {
err := w.enc.EncodeToken(t)
if err != nil {
return err
}
}
return w.enc.Flush()
}
var xmlLangName = ixml.Name{Space: "http://www.w3.org/XML/1998/namespace", Local: "lang"}
func xmlLang(s ixml.StartElement, d string) string {
for _, attr := range s.Attr {
if attr.Name == xmlLangName {
return attr.Value
}
}
return d
}
type xmlValue []byte
func (v *xmlValue) UnmarshalXML(d *ixml.Decoder, start ixml.StartElement) error {
// The XML value of a property can be arbitrary, mixed-content XML.
// To make sure that the unmarshalled value contains all required
// namespaces, we encode all the property value XML tokens into a
// buffer. This forces the encoder to redeclare any used namespaces.
var b bytes.Buffer
e := ixml.NewEncoder(&b)
for {
t, err := next(d)
if err != nil {
return err
}
if e, ok := t.(ixml.EndElement); ok && e.Name == start.Name {
break
}
if err = e.EncodeToken(t); err != nil {
return err
}
}
err := e.Flush()
if err != nil {
return err
}
*v = b.Bytes()
return nil
}
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_prop (for proppatch)
type proppatchProps []Property
// UnmarshalXML appends the property names and values enclosed within start
// to ps.
//
// An xml:lang attribute that is defined either on the DAV:prop or property
// name XML element is propagated to the property's Lang field.
//
// UnmarshalXML returns an error if start does not contain any properties or if
// property values contain syntactically incorrect XML.
func (ps *proppatchProps) UnmarshalXML(d *ixml.Decoder, start ixml.StartElement) error {
lang := xmlLang(start, "")
for {
t, err := next(d)
if err != nil {
return err
}
switch elem := t.(type) {
case ixml.EndElement:
if len(*ps) == 0 {
return fmt.Errorf("%s must not be empty", start.Name.Local)
}
return nil
case ixml.StartElement:
p := Property{
XMLName: xml.Name(t.(ixml.StartElement).Name),
Lang: xmlLang(t.(ixml.StartElement), lang),
}
err = d.DecodeElement(((*xmlValue)(&p.InnerXML)), &elem)
if err != nil {
return err
}
*ps = append(*ps, p)
}
}
}
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_set
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_remove
type setRemove struct {
XMLName ixml.Name
Lang string `xml:"xml:lang,attr,omitempty"`
Prop proppatchProps `xml:"DAV: prop"`
}
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_propertyupdate
type propertyupdate struct {
XMLName ixml.Name `xml:"DAV: propertyupdate"`
Lang string `xml:"xml:lang,attr,omitempty"`
SetRemove []setRemove `xml:",any"`
}
func readProppatch(r io.Reader) (patches []Proppatch, status int, err error) {
var pu propertyupdate
if err = ixml.NewDecoder(r).Decode(&pu); err != nil {
return nil, http.StatusBadRequest, err
}
for _, op := range pu.SetRemove {
remove := false
switch op.XMLName {
case ixml.Name{Space: "DAV:", Local: "set"}:
// No-op.
case ixml.Name{Space: "DAV:", Local: "remove"}:
for _, p := range op.Prop {
if len(p.InnerXML) > 0 {
return nil, http.StatusBadRequest, errInvalidProppatch
}
}
remove = true
default:
return nil, http.StatusBadRequest, errInvalidProppatch
}
patches = append(patches, Proppatch{Remove: remove, Props: op.Prop})
}
return patches, 0, nil
}
// 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 websocket
import (
"bufio"
"context"
"io"
"net"
"net/http"
"net/url"
"time"
)
// DialError is an error that occurs while dialling a websocket server.
type DialError struct {
*Config
Err error
}
func (e *DialError) Error() string {
return "websocket.Dial " + e.Config.Location.String() + ": " + e.Err.Error()
}
// NewConfig creates a new WebSocket config for client connection.
func NewConfig(server, origin string) (config *Config, err error) {
config = new(Config)
config.Version = ProtocolVersionHybi13
config.Location, err = url.ParseRequestURI(server)
if err != nil {
return
}
config.Origin, err = url.ParseRequestURI(origin)
if err != nil {
return
}
config.Header = http.Header(make(map[string][]string))
return
}
// NewClient creates a new WebSocket client connection over rwc.
func NewClient(config *Config, rwc io.ReadWriteCloser) (ws *Conn, err error) {
br := bufio.NewReader(rwc)
bw := bufio.NewWriter(rwc)
err = hybiClientHandshake(config, br, bw)
if err != nil {
return
}
buf := bufio.NewReadWriter(br, bw)
ws = newHybiClientConn(config, buf, rwc)
return
}
// Dial opens a new client connection to a WebSocket.
func Dial(url_, protocol, origin string) (ws *Conn, err error) {
config, err := NewConfig(url_, origin)
if err != nil {
return nil, err
}
if protocol != "" {
config.Protocol = []string{protocol}
}
return DialConfig(config)
}
var portMap = map[string]string{
"ws": "80",
"wss": "443",
}
func parseAuthority(location *url.URL) string {
if _, ok := portMap[location.Scheme]; ok {
if _, _, err := net.SplitHostPort(location.Host); err != nil {
return net.JoinHostPort(location.Host, portMap[location.Scheme])
}
}
return location.Host
}
// DialConfig opens a new client connection to a WebSocket with a config.
func DialConfig(config *Config) (ws *Conn, err error) {
return config.DialContext(context.Background())
}
// DialContext opens a new client connection to a WebSocket, with context support for timeouts/cancellation.
func (config *Config) DialContext(ctx context.Context) (*Conn, error) {
if config.Location == nil {
return nil, &DialError{config, ErrBadWebSocketLocation}
}
if config.Origin == nil {
return nil, &DialError{config, ErrBadWebSocketOrigin}
}
dialer := config.Dialer
if dialer == nil {
dialer = &net.Dialer{}
}
client, err := dialWithDialer(ctx, dialer, config)
if err != nil {
return nil, &DialError{config, err}
}
// Cleanup the connection if we fail to create the websocket successfully
success := false
defer func() {
if !success {
_ = client.Close()
}
}()
var ws *Conn
var wsErr error
doneConnecting := make(chan struct{})
go func() {
defer close(doneConnecting)
ws, err = NewClient(config, client)
if err != nil {
wsErr = &DialError{config, err}
}
}()
// The websocket.NewClient() function can block indefinitely, make sure that we
// respect the deadlines specified by the context.
select {
case <-ctx.Done():
// Force the pending operations to fail, terminating the pending connection attempt
_ = client.SetDeadline(time.Now())
<-doneConnecting // Wait for the goroutine that tries to establish the connection to finish
return nil, &DialError{config, ctx.Err()}
case <-doneConnecting:
if wsErr == nil {
success = true // Disarm the deferred connection cleanup
}
return ws, wsErr
}
}
// 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.
package websocket
import (
"context"
"crypto/tls"
"net"
)
func dialWithDialer(ctx context.Context, dialer *net.Dialer, config *Config) (conn net.Conn, err error) {
switch config.Location.Scheme {
case "ws":
conn, err = dialer.DialContext(ctx, "tcp", parseAuthority(config.Location))
case "wss":
tlsDialer := &tls.Dialer{
NetDialer: dialer,
Config: config.TlsConfig,
}
conn, err = tlsDialer.DialContext(ctx, "tcp", parseAuthority(config.Location))
default:
err = ErrBadScheme
}
return
}
// Copyright 2011 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 websocket
// This file implements a protocol of hybi draft.
// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17
import (
"bufio"
"bytes"
"crypto/rand"
"crypto/sha1"
"encoding/base64"
"encoding/binary"
"fmt"
"io"
"net/http"
"net/url"
"strings"
)
const (
websocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
closeStatusNormal = 1000
closeStatusGoingAway = 1001
closeStatusProtocolError = 1002
closeStatusUnsupportedData = 1003
closeStatusFrameTooLarge = 1004
closeStatusNoStatusRcvd = 1005
closeStatusAbnormalClosure = 1006
closeStatusBadMessageData = 1007
closeStatusPolicyViolation = 1008
closeStatusTooBigData = 1009
closeStatusExtensionMismatch = 1010
maxControlFramePayloadLength = 125
)
var (
ErrBadMaskingKey = &ProtocolError{"bad masking key"}
ErrBadPongMessage = &ProtocolError{"bad pong message"}
ErrBadClosingStatus = &ProtocolError{"bad closing status"}
ErrUnsupportedExtensions = &ProtocolError{"unsupported extensions"}
ErrNotImplemented = &ProtocolError{"not implemented"}
handshakeHeader = map[string]bool{
"Host": true,
"Upgrade": true,
"Connection": true,
"Sec-Websocket-Key": true,
"Sec-Websocket-Origin": true,
"Sec-Websocket-Version": true,
"Sec-Websocket-Protocol": true,
"Sec-Websocket-Accept": true,
}
)
// A hybiFrameHeader is a frame header as defined in hybi draft.
type hybiFrameHeader struct {
Fin bool
Rsv [3]bool
OpCode byte
Length int64
MaskingKey []byte
data *bytes.Buffer
}
// A hybiFrameReader is a reader for hybi frame.
type hybiFrameReader struct {
reader io.Reader
header hybiFrameHeader
pos int64
length int
}
func (frame *hybiFrameReader) Read(msg []byte) (n int, err error) {
n, err = frame.reader.Read(msg)
if frame.header.MaskingKey != nil {
for i := 0; i < n; i++ {
msg[i] = msg[i] ^ frame.header.MaskingKey[frame.pos%4]
frame.pos++
}
}
return n, err
}
func (frame *hybiFrameReader) PayloadType() byte { return frame.header.OpCode }
func (frame *hybiFrameReader) HeaderReader() io.Reader {
if frame.header.data == nil {
return nil
}
if frame.header.data.Len() == 0 {
return nil
}
return frame.header.data
}
func (frame *hybiFrameReader) TrailerReader() io.Reader { return nil }
func (frame *hybiFrameReader) Len() (n int) { return frame.length }
// A hybiFrameReaderFactory creates new frame reader based on its frame type.
type hybiFrameReaderFactory struct {
*bufio.Reader
}
// NewFrameReader reads a frame header from the connection, and creates new reader for the frame.
// See Section 5.2 Base Framing protocol for detail.
// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5.2
func (buf hybiFrameReaderFactory) NewFrameReader() (frame frameReader, err error) {
hybiFrame := new(hybiFrameReader)
frame = hybiFrame
var header []byte
var b byte
// First byte. FIN/RSV1/RSV2/RSV3/OpCode(4bits)
b, err = buf.ReadByte()
if err != nil {
return
}
header = append(header, b)
hybiFrame.header.Fin = ((header[0] >> 7) & 1) != 0
for i := 0; i < 3; i++ {
j := uint(6 - i)
hybiFrame.header.Rsv[i] = ((header[0] >> j) & 1) != 0
}
hybiFrame.header.OpCode = header[0] & 0x0f
// Second byte. Mask/Payload len(7bits)
b, err = buf.ReadByte()
if err != nil {
return
}
header = append(header, b)
mask := (b & 0x80) != 0
b &= 0x7f
lengthFields := 0
switch {
case b <= 125: // Payload length 7bits.
hybiFrame.header.Length = int64(b)
case b == 126: // Payload length 7+16bits
lengthFields = 2
case b == 127: // Payload length 7+64bits
lengthFields = 8
}
for i := 0; i < lengthFields; i++ {
b, err = buf.ReadByte()
if err != nil {
return
}
if lengthFields == 8 && i == 0 { // MSB must be zero when 7+64 bits
b &= 0x7f
}
header = append(header, b)
hybiFrame.header.Length = hybiFrame.header.Length*256 + int64(b)
}
if mask {
// Masking key. 4 bytes.
for i := 0; i < 4; i++ {
b, err = buf.ReadByte()
if err != nil {
return
}
header = append(header, b)
hybiFrame.header.MaskingKey = append(hybiFrame.header.MaskingKey, b)
}
}
hybiFrame.reader = io.LimitReader(buf.Reader, hybiFrame.header.Length)
hybiFrame.header.data = bytes.NewBuffer(header)
hybiFrame.length = len(header) + int(hybiFrame.header.Length)
return
}
// A HybiFrameWriter is a writer for hybi frame.
type hybiFrameWriter struct {
writer *bufio.Writer
header *hybiFrameHeader
}
func (frame *hybiFrameWriter) Write(msg []byte) (n int, err error) {
var header []byte
var b byte
if frame.header.Fin {
b |= 0x80
}
for i := 0; i < 3; i++ {
if frame.header.Rsv[i] {
j := uint(6 - i)
b |= 1 << j
}
}
b |= frame.header.OpCode
header = append(header, b)
if frame.header.MaskingKey != nil {
b = 0x80
} else {
b = 0
}
lengthFields := 0
length := len(msg)
switch {
case length <= 125:
b |= byte(length)
case length < 65536:
b |= 126
lengthFields = 2
default:
b |= 127
lengthFields = 8
}
header = append(header, b)
for i := 0; i < lengthFields; i++ {
j := uint((lengthFields - i - 1) * 8)
b = byte((length >> j) & 0xff)
header = append(header, b)
}
if frame.header.MaskingKey != nil {
if len(frame.header.MaskingKey) != 4 {
return 0, ErrBadMaskingKey
}
header = append(header, frame.header.MaskingKey...)
frame.writer.Write(header)
data := make([]byte, length)
for i := range data {
data[i] = msg[i] ^ frame.header.MaskingKey[i%4]
}
frame.writer.Write(data)
err = frame.writer.Flush()
return length, err
}
frame.writer.Write(header)
frame.writer.Write(msg)
err = frame.writer.Flush()
return length, err
}
func (frame *hybiFrameWriter) Close() error { return nil }
type hybiFrameWriterFactory struct {
*bufio.Writer
needMaskingKey bool
}
func (buf hybiFrameWriterFactory) NewFrameWriter(payloadType byte) (frame frameWriter, err error) {
frameHeader := &hybiFrameHeader{Fin: true, OpCode: payloadType}
if buf.needMaskingKey {
frameHeader.MaskingKey, err = generateMaskingKey()
if err != nil {
return nil, err
}
}
return &hybiFrameWriter{writer: buf.Writer, header: frameHeader}, nil
}
type hybiFrameHandler struct {
conn *Conn
payloadType byte
}
func (handler *hybiFrameHandler) HandleFrame(frame frameReader) (frameReader, error) {
if handler.conn.IsServerConn() {
// The client MUST mask all frames sent to the server.
if frame.(*hybiFrameReader).header.MaskingKey == nil {
handler.WriteClose(closeStatusProtocolError)
return nil, io.EOF
}
} else {
// The server MUST NOT mask all frames.
if frame.(*hybiFrameReader).header.MaskingKey != nil {
handler.WriteClose(closeStatusProtocolError)
return nil, io.EOF
}
}
if header := frame.HeaderReader(); header != nil {
io.Copy(io.Discard, header)
}
switch frame.PayloadType() {
case ContinuationFrame:
frame.(*hybiFrameReader).header.OpCode = handler.payloadType
case TextFrame, BinaryFrame:
handler.payloadType = frame.PayloadType()
case CloseFrame:
return nil, io.EOF
case PingFrame, PongFrame:
b := make([]byte, maxControlFramePayloadLength)
n, err := io.ReadFull(frame, b)
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
return nil, err
}
io.Copy(io.Discard, frame)
if frame.PayloadType() == PingFrame {
if _, err := handler.WritePong(b[:n]); err != nil {
return nil, err
}
}
return nil, nil
}
return frame, nil
}
func (handler *hybiFrameHandler) WriteClose(status int) (err error) {
handler.conn.wio.Lock()
defer handler.conn.wio.Unlock()
w, err := handler.conn.frameWriterFactory.NewFrameWriter(CloseFrame)
if err != nil {
return err
}
msg := make([]byte, 2)
binary.BigEndian.PutUint16(msg, uint16(status))
_, err = w.Write(msg)
w.Close()
return err
}
func (handler *hybiFrameHandler) WritePong(msg []byte) (n int, err error) {
handler.conn.wio.Lock()
defer handler.conn.wio.Unlock()
w, err := handler.conn.frameWriterFactory.NewFrameWriter(PongFrame)
if err != nil {
return 0, err
}
n, err = w.Write(msg)
w.Close()
return n, err
}
// newHybiConn creates a new WebSocket connection speaking hybi draft protocol.
func newHybiConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
if buf == nil {
br := bufio.NewReader(rwc)
bw := bufio.NewWriter(rwc)
buf = bufio.NewReadWriter(br, bw)
}
ws := &Conn{config: config, request: request, buf: buf, rwc: rwc,
frameReaderFactory: hybiFrameReaderFactory{buf.Reader},
frameWriterFactory: hybiFrameWriterFactory{
buf.Writer, request == nil},
PayloadType: TextFrame,
defaultCloseStatus: closeStatusNormal}
ws.frameHandler = &hybiFrameHandler{conn: ws}
return ws
}
// generateMaskingKey generates a masking key for a frame.
func generateMaskingKey() (maskingKey []byte, err error) {
maskingKey = make([]byte, 4)
if _, err = io.ReadFull(rand.Reader, maskingKey); err != nil {
return
}
return
}
// generateNonce generates a nonce consisting of a randomly selected 16-byte
// value that has been base64-encoded.
func generateNonce() (nonce []byte) {
key := make([]byte, 16)
if _, err := io.ReadFull(rand.Reader, key); err != nil {
panic(err)
}
nonce = make([]byte, 24)
base64.StdEncoding.Encode(nonce, key)
return
}
// removeZone removes IPv6 zone identifier from host.
// E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080"
func removeZone(host string) string {
if !strings.HasPrefix(host, "[") {
return host
}
i := strings.LastIndex(host, "]")
if i < 0 {
return host
}
j := strings.LastIndex(host[:i], "%")
if j < 0 {
return host
}
return host[:j] + host[i:]
}
// getNonceAccept computes the base64-encoded SHA-1 of the concatenation of
// the nonce ("Sec-WebSocket-Key" value) with the websocket GUID string.
func getNonceAccept(nonce []byte) (expected []byte, err error) {
h := sha1.New()
if _, err = h.Write(nonce); err != nil {
return
}
if _, err = h.Write([]byte(websocketGUID)); err != nil {
return
}
expected = make([]byte, 28)
base64.StdEncoding.Encode(expected, h.Sum(nil))
return
}
// Client handshake described in draft-ietf-hybi-thewebsocket-protocol-17
func hybiClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) {
bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n")
// According to RFC 6874, an HTTP client, proxy, or other
// intermediary must remove any IPv6 zone identifier attached
// to an outgoing URI.
bw.WriteString("Host: " + removeZone(config.Location.Host) + "\r\n")
bw.WriteString("Upgrade: websocket\r\n")
bw.WriteString("Connection: Upgrade\r\n")
nonce := generateNonce()
if config.handshakeData != nil {
nonce = []byte(config.handshakeData["key"])
}
bw.WriteString("Sec-WebSocket-Key: " + string(nonce) + "\r\n")
bw.WriteString("Origin: " + strings.ToLower(config.Origin.String()) + "\r\n")
if config.Version != ProtocolVersionHybi13 {
return ErrBadProtocolVersion
}
bw.WriteString("Sec-WebSocket-Version: " + fmt.Sprintf("%d", config.Version) + "\r\n")
if len(config.Protocol) > 0 {
bw.WriteString("Sec-WebSocket-Protocol: " + strings.Join(config.Protocol, ", ") + "\r\n")
}
// TODO(ukai): send Sec-WebSocket-Extensions.
err = config.Header.WriteSubset(bw, handshakeHeader)
if err != nil {
return err
}
bw.WriteString("\r\n")
if err = bw.Flush(); err != nil {
return err
}
resp, err := http.ReadResponse(br, &http.Request{Method: "GET"})
if err != nil {
return err
}
if resp.StatusCode != 101 {
return ErrBadStatus
}
if strings.ToLower(resp.Header.Get("Upgrade")) != "websocket" ||
strings.ToLower(resp.Header.Get("Connection")) != "upgrade" {
return ErrBadUpgrade
}
expectedAccept, err := getNonceAccept(nonce)
if err != nil {
return err
}
if resp.Header.Get("Sec-WebSocket-Accept") != string(expectedAccept) {
return ErrChallengeResponse
}
if resp.Header.Get("Sec-WebSocket-Extensions") != "" {
return ErrUnsupportedExtensions
}
offeredProtocol := resp.Header.Get("Sec-WebSocket-Protocol")
if offeredProtocol != "" {
protocolMatched := false
for i := 0; i < len(config.Protocol); i++ {
if config.Protocol[i] == offeredProtocol {
protocolMatched = true
break
}
}
if !protocolMatched {
return ErrBadWebSocketProtocol
}
config.Protocol = []string{offeredProtocol}
}
return nil
}
// newHybiClientConn creates a client WebSocket connection after handshake.
func newHybiClientConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn {
return newHybiConn(config, buf, rwc, nil)
}
// A HybiServerHandshaker performs a server handshake using hybi draft protocol.
type hybiServerHandshaker struct {
*Config
accept []byte
}
func (c *hybiServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) {
c.Version = ProtocolVersionHybi13
if req.Method != "GET" {
return http.StatusMethodNotAllowed, ErrBadRequestMethod
}
// HTTP version can be safely ignored.
if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" ||
!strings.Contains(strings.ToLower(req.Header.Get("Connection")), "upgrade") {
return http.StatusBadRequest, ErrNotWebSocket
}
key := req.Header.Get("Sec-Websocket-Key")
if key == "" {
return http.StatusBadRequest, ErrChallengeResponse
}
version := req.Header.Get("Sec-Websocket-Version")
switch version {
case "13":
c.Version = ProtocolVersionHybi13
default:
return http.StatusBadRequest, ErrBadWebSocketVersion
}
var scheme string
if req.TLS != nil {
scheme = "wss"
} else {
scheme = "ws"
}
c.Location, err = url.ParseRequestURI(scheme + "://" + req.Host + req.URL.RequestURI())
if err != nil {
return http.StatusBadRequest, err
}
protocol := strings.TrimSpace(req.Header.Get("Sec-Websocket-Protocol"))
if protocol != "" {
protocols := strings.Split(protocol, ",")
for i := 0; i < len(protocols); i++ {
c.Protocol = append(c.Protocol, strings.TrimSpace(protocols[i]))
}
}
c.accept, err = getNonceAccept([]byte(key))
if err != nil {
return http.StatusInternalServerError, err
}
return http.StatusSwitchingProtocols, nil
}
// Origin parses the Origin header in req.
// If the Origin header is not set, it returns nil and nil.
func Origin(config *Config, req *http.Request) (*url.URL, error) {
var origin string
switch config.Version {
case ProtocolVersionHybi13:
origin = req.Header.Get("Origin")
}
if origin == "" {
return nil, nil
}
return url.ParseRequestURI(origin)
}
func (c *hybiServerHandshaker) AcceptHandshake(buf *bufio.Writer) (err error) {
if len(c.Protocol) > 0 {
if len(c.Protocol) != 1 {
// You need choose a Protocol in Handshake func in Server.
return ErrBadWebSocketProtocol
}
}
buf.WriteString("HTTP/1.1 101 Switching Protocols\r\n")
buf.WriteString("Upgrade: websocket\r\n")
buf.WriteString("Connection: Upgrade\r\n")
buf.WriteString("Sec-WebSocket-Accept: " + string(c.accept) + "\r\n")
if len(c.Protocol) > 0 {
buf.WriteString("Sec-WebSocket-Protocol: " + c.Protocol[0] + "\r\n")
}
// TODO(ukai): send Sec-WebSocket-Extensions.
if c.Header != nil {
err := c.Header.WriteSubset(buf, handshakeHeader)
if err != nil {
return err
}
}
buf.WriteString("\r\n")
return buf.Flush()
}
func (c *hybiServerHandshaker) NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
return newHybiServerConn(c.Config, buf, rwc, request)
}
// newHybiServerConn returns a new WebSocket connection speaking hybi draft protocol.
func newHybiServerConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
return newHybiConn(config, buf, rwc, request)
}
// 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 websocket
import (
"bufio"
"fmt"
"io"
"net/http"
)
func newServerConn(rwc io.ReadWriteCloser, buf *bufio.ReadWriter, req *http.Request, config *Config, handshake func(*Config, *http.Request) error) (conn *Conn, err error) {
var hs serverHandshaker = &hybiServerHandshaker{Config: config}
code, err := hs.ReadHandshake(buf.Reader, req)
if err == ErrBadWebSocketVersion {
fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
fmt.Fprintf(buf, "Sec-WebSocket-Version: %s\r\n", SupportedProtocolVersion)
buf.WriteString("\r\n")
buf.WriteString(err.Error())
buf.Flush()
return
}
if err != nil {
fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
buf.WriteString("\r\n")
buf.WriteString(err.Error())
buf.Flush()
return
}
if handshake != nil {
err = handshake(config, req)
if err != nil {
code = http.StatusForbidden
fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
buf.WriteString("\r\n")
buf.Flush()
return
}
}
err = hs.AcceptHandshake(buf.Writer)
if err != nil {
code = http.StatusBadRequest
fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
buf.WriteString("\r\n")
buf.Flush()
return
}
conn = hs.NewServerConn(buf, rwc, req)
return
}
// Server represents a server of a WebSocket.
type Server struct {
// Config is a WebSocket configuration for new WebSocket connection.
Config
// Handshake is an optional function in WebSocket handshake.
// For example, you can check, or don't check Origin header.
// Another example, you can select config.Protocol.
Handshake func(*Config, *http.Request) error
// Handler handles a WebSocket connection.
Handler
}
// ServeHTTP implements the http.Handler interface for a WebSocket
func (s Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
s.serveWebSocket(w, req)
}
func (s Server) serveWebSocket(w http.ResponseWriter, req *http.Request) {
rwc, buf, err := w.(http.Hijacker).Hijack()
if err != nil {
panic("Hijack failed: " + err.Error())
}
// The server should abort the WebSocket connection if it finds
// the client did not send a handshake that matches with protocol
// specification.
defer rwc.Close()
conn, err := newServerConn(rwc, buf, req, &s.Config, s.Handshake)
if err != nil {
return
}
if conn == nil {
panic("unexpected nil conn")
}
s.Handler(conn)
}
// Handler is a simple interface to a WebSocket browser client.
// It checks if Origin header is valid URL by default.
// You might want to verify websocket.Conn.Config().Origin in the func.
// If you use Server instead of Handler, you could call websocket.Origin and
// check the origin in your Handshake func. So, if you want to accept
// non-browser clients, which do not send an Origin header, set a
// Server.Handshake that does not check the origin.
type Handler func(*Conn)
func checkOrigin(config *Config, req *http.Request) (err error) {
config.Origin, err = Origin(config, req)
if err == nil && config.Origin == nil {
return fmt.Errorf("null origin")
}
return err
}
// ServeHTTP implements the http.Handler interface for a WebSocket
func (h Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
s := Server{Handler: h, Handshake: checkOrigin}
s.serveWebSocket(w, req)
}
// 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 websocket implements a client and server for the WebSocket protocol
// as specified in RFC 6455.
//
// This package currently lacks some features found in an alternative
// and more actively maintained WebSocket packages:
//
// - [github.com/gorilla/websocket]
// - [github.com/coder/websocket]
package websocket // import "golang.org/x/net/websocket"
import (
"bufio"
"crypto/tls"
"encoding/json"
"errors"
"io"
"net"
"net/http"
"net/url"
"sync"
"time"
)
const (
ProtocolVersionHybi13 = 13
ProtocolVersionHybi = ProtocolVersionHybi13
SupportedProtocolVersion = "13"
ContinuationFrame = 0
TextFrame = 1
BinaryFrame = 2
CloseFrame = 8
PingFrame = 9
PongFrame = 10
UnknownFrame = 255
DefaultMaxPayloadBytes = 32 << 20 // 32MB
)
// ProtocolError represents WebSocket protocol errors.
type ProtocolError struct {
ErrorString string
}
func (err *ProtocolError) Error() string { return err.ErrorString }
var (
ErrBadProtocolVersion = &ProtocolError{"bad protocol version"}
ErrBadScheme = &ProtocolError{"bad scheme"}
ErrBadStatus = &ProtocolError{"bad status"}
ErrBadUpgrade = &ProtocolError{"missing or bad upgrade"}
ErrBadWebSocketOrigin = &ProtocolError{"missing or bad WebSocket-Origin"}
ErrBadWebSocketLocation = &ProtocolError{"missing or bad WebSocket-Location"}
ErrBadWebSocketProtocol = &ProtocolError{"missing or bad WebSocket-Protocol"}
ErrBadWebSocketVersion = &ProtocolError{"missing or bad WebSocket Version"}
ErrChallengeResponse = &ProtocolError{"mismatch challenge/response"}
ErrBadFrame = &ProtocolError{"bad frame"}
ErrBadFrameBoundary = &ProtocolError{"not on frame boundary"}
ErrNotWebSocket = &ProtocolError{"not websocket protocol"}
ErrBadRequestMethod = &ProtocolError{"bad method"}
ErrNotSupported = &ProtocolError{"not supported"}
)
// ErrFrameTooLarge is returned by Codec's Receive method if payload size
// exceeds limit set by Conn.MaxPayloadBytes
var ErrFrameTooLarge = errors.New("websocket: frame payload size exceeds limit")
// Addr is an implementation of net.Addr for WebSocket.
type Addr struct {
*url.URL
}
// Network returns the network type for a WebSocket, "websocket".
func (addr *Addr) Network() string { return "websocket" }
// Config is a WebSocket configuration
type Config struct {
// A WebSocket server address.
Location *url.URL
// A Websocket client origin.
Origin *url.URL
// WebSocket subprotocols.
Protocol []string
// WebSocket protocol version.
Version int
// TLS config for secure WebSocket (wss).
TlsConfig *tls.Config
// Additional header fields to be sent in WebSocket opening handshake.
Header http.Header
// Dialer used when opening websocket connections.
Dialer *net.Dialer
handshakeData map[string]string
}
// serverHandshaker is an interface to handle WebSocket server side handshake.
type serverHandshaker interface {
// ReadHandshake reads handshake request message from client.
// Returns http response code and error if any.
ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error)
// AcceptHandshake accepts the client handshake request and sends
// handshake response back to client.
AcceptHandshake(buf *bufio.Writer) (err error)
// NewServerConn creates a new WebSocket connection.
NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) (conn *Conn)
}
// frameReader is an interface to read a WebSocket frame.
type frameReader interface {
// Reader is to read payload of the frame.
io.Reader
// PayloadType returns payload type.
PayloadType() byte
// HeaderReader returns a reader to read header of the frame.
HeaderReader() io.Reader
// TrailerReader returns a reader to read trailer of the frame.
// If it returns nil, there is no trailer in the frame.
TrailerReader() io.Reader
// Len returns total length of the frame, including header and trailer.
Len() int
}
// frameReaderFactory is an interface to creates new frame reader.
type frameReaderFactory interface {
NewFrameReader() (r frameReader, err error)
}
// frameWriter is an interface to write a WebSocket frame.
type frameWriter interface {
// Writer is to write payload of the frame.
io.WriteCloser
}
// frameWriterFactory is an interface to create new frame writer.
type frameWriterFactory interface {
NewFrameWriter(payloadType byte) (w frameWriter, err error)
}
type frameHandler interface {
HandleFrame(frame frameReader) (r frameReader, err error)
WriteClose(status int) (err error)
}
// Conn represents a WebSocket connection.
//
// Multiple goroutines may invoke methods on a Conn simultaneously.
type Conn struct {
config *Config
request *http.Request
buf *bufio.ReadWriter
rwc io.ReadWriteCloser
rio sync.Mutex
frameReaderFactory
frameReader
wio sync.Mutex
frameWriterFactory
frameHandler
PayloadType byte
defaultCloseStatus int
// MaxPayloadBytes limits the size of frame payload received over Conn
// by Codec's Receive method. If zero, DefaultMaxPayloadBytes is used.
MaxPayloadBytes int
}
// Read implements the io.Reader interface:
// it reads data of a frame from the WebSocket connection.
// if msg is not large enough for the frame data, it fills the msg and next Read
// will read the rest of the frame data.
// it reads Text frame or Binary frame.
func (ws *Conn) Read(msg []byte) (n int, err error) {
ws.rio.Lock()
defer ws.rio.Unlock()
again:
if ws.frameReader == nil {
frame, err := ws.frameReaderFactory.NewFrameReader()
if err != nil {
return 0, err
}
ws.frameReader, err = ws.frameHandler.HandleFrame(frame)
if err != nil {
return 0, err
}
if ws.frameReader == nil {
goto again
}
}
n, err = ws.frameReader.Read(msg)
if err == io.EOF {
if trailer := ws.frameReader.TrailerReader(); trailer != nil {
io.Copy(io.Discard, trailer)
}
ws.frameReader = nil
goto again
}
return n, err
}
// Write implements the io.Writer interface:
// it writes data as a frame to the WebSocket connection.
func (ws *Conn) Write(msg []byte) (n int, err error) {
ws.wio.Lock()
defer ws.wio.Unlock()
w, err := ws.frameWriterFactory.NewFrameWriter(ws.PayloadType)
if err != nil {
return 0, err
}
n, err = w.Write(msg)
w.Close()
return n, err
}
// Close implements the io.Closer interface.
func (ws *Conn) Close() error {
err := ws.frameHandler.WriteClose(ws.defaultCloseStatus)
err1 := ws.rwc.Close()
if err != nil {
return err
}
return err1
}
// IsClientConn reports whether ws is a client-side connection.
func (ws *Conn) IsClientConn() bool { return ws.request == nil }
// IsServerConn reports whether ws is a server-side connection.
func (ws *Conn) IsServerConn() bool { return ws.request != nil }
// LocalAddr returns the WebSocket Origin for the connection for client, or
// the WebSocket location for server.
func (ws *Conn) LocalAddr() net.Addr {
if ws.IsClientConn() {
return &Addr{ws.config.Origin}
}
return &Addr{ws.config.Location}
}
// RemoteAddr returns the WebSocket location for the connection for client, or
// the Websocket Origin for server.
func (ws *Conn) RemoteAddr() net.Addr {
if ws.IsClientConn() {
return &Addr{ws.config.Location}
}
return &Addr{ws.config.Origin}
}
var errSetDeadline = errors.New("websocket: cannot set deadline: not using a net.Conn")
// SetDeadline sets the connection's network read & write deadlines.
func (ws *Conn) SetDeadline(t time.Time) error {
if conn, ok := ws.rwc.(net.Conn); ok {
return conn.SetDeadline(t)
}
return errSetDeadline
}
// SetReadDeadline sets the connection's network read deadline.
func (ws *Conn) SetReadDeadline(t time.Time) error {
if conn, ok := ws.rwc.(net.Conn); ok {
return conn.SetReadDeadline(t)
}
return errSetDeadline
}
// SetWriteDeadline sets the connection's network write deadline.
func (ws *Conn) SetWriteDeadline(t time.Time) error {
if conn, ok := ws.rwc.(net.Conn); ok {
return conn.SetWriteDeadline(t)
}
return errSetDeadline
}
// Config returns the WebSocket config.
func (ws *Conn) Config() *Config { return ws.config }
// Request returns the http request upgraded to the WebSocket.
// It is nil for client side.
func (ws *Conn) Request() *http.Request { return ws.request }
// Codec represents a symmetric pair of functions that implement a codec.
type Codec struct {
Marshal func(v interface{}) (data []byte, payloadType byte, err error)
Unmarshal func(data []byte, payloadType byte, v interface{}) (err error)
}
// Send sends v marshaled by cd.Marshal as single frame to ws.
func (cd Codec) Send(ws *Conn, v interface{}) (err error) {
data, payloadType, err := cd.Marshal(v)
if err != nil {
return err
}
ws.wio.Lock()
defer ws.wio.Unlock()
w, err := ws.frameWriterFactory.NewFrameWriter(payloadType)
if err != nil {
return err
}
_, err = w.Write(data)
w.Close()
return err
}
// Receive receives single frame from ws, unmarshaled by cd.Unmarshal and stores
// in v. The whole frame payload is read to an in-memory buffer; max size of
// payload is defined by ws.MaxPayloadBytes. If frame payload size exceeds
// limit, ErrFrameTooLarge is returned; in this case frame is not read off wire
// completely. The next call to Receive would read and discard leftover data of
// previous oversized frame before processing next frame.
func (cd Codec) Receive(ws *Conn, v interface{}) (err error) {
ws.rio.Lock()
defer ws.rio.Unlock()
if ws.frameReader != nil {
_, err = io.Copy(io.Discard, ws.frameReader)
if err != nil {
return err
}
ws.frameReader = nil
}
again:
frame, err := ws.frameReaderFactory.NewFrameReader()
if err != nil {
return err
}
frame, err = ws.frameHandler.HandleFrame(frame)
if err != nil {
return err
}
if frame == nil {
goto again
}
maxPayloadBytes := ws.MaxPayloadBytes
if maxPayloadBytes == 0 {
maxPayloadBytes = DefaultMaxPayloadBytes
}
if hf, ok := frame.(*hybiFrameReader); ok && hf.header.Length > int64(maxPayloadBytes) {
// payload size exceeds limit, no need to call Unmarshal
//
// set frameReader to current oversized frame so that
// the next call to this function can drain leftover
// data before processing the next frame
ws.frameReader = frame
return ErrFrameTooLarge
}
payloadType := frame.PayloadType()
data, err := io.ReadAll(frame)
if err != nil {
return err
}
return cd.Unmarshal(data, payloadType, v)
}
func marshal(v interface{}) (msg []byte, payloadType byte, err error) {
switch data := v.(type) {
case string:
return []byte(data), TextFrame, nil
case []byte:
return data, BinaryFrame, nil
}
return nil, UnknownFrame, ErrNotSupported
}
func unmarshal(msg []byte, payloadType byte, v interface{}) (err error) {
switch data := v.(type) {
case *string:
*data = string(msg)
return nil
case *[]byte:
*data = msg
return nil
}
return ErrNotSupported
}
/*
Message is a codec to send/receive text/binary data in a frame on WebSocket connection.
To send/receive text frame, use string type.
To send/receive binary frame, use []byte type.
Trivial usage:
import "websocket"
// receive text frame
var message string
websocket.Message.Receive(ws, &message)
// send text frame
message = "hello"
websocket.Message.Send(ws, message)
// receive binary frame
var data []byte
websocket.Message.Receive(ws, &data)
// send binary frame
data = []byte{0, 1, 2}
websocket.Message.Send(ws, data)
*/
var Message = Codec{marshal, unmarshal}
func jsonMarshal(v interface{}) (msg []byte, payloadType byte, err error) {
msg, err = json.Marshal(v)
return msg, TextFrame, err
}
func jsonUnmarshal(msg []byte, payloadType byte, v interface{}) (err error) {
return json.Unmarshal(msg, v)
}
/*
JSON is a codec to send/receive JSON data in a frame from a WebSocket connection.
Trivial usage:
import "websocket"
type T struct {
Msg string
Count int
}
// receive JSON type T
var data T
websocket.JSON.Receive(ws, &data)
// send JSON type T
websocket.JSON.Send(ws, data)
*/
var JSON = Codec{jsonMarshal, jsonUnmarshal}
// 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.
// Package xsrftoken provides methods for generating and validating secure XSRF tokens.
package xsrftoken // import "golang.org/x/net/xsrftoken"
import (
"crypto/hmac"
"crypto/sha1"
"crypto/subtle"
"encoding/base64"
"fmt"
"strconv"
"strings"
"time"
)
// Timeout is the duration for which XSRF tokens are valid.
// It is exported so clients may set cookie timeouts that match generated tokens.
const Timeout = 24 * time.Hour
// clean sanitizes a string for inclusion in a token by replacing all ":" with "::".
func clean(s string) string {
return strings.Replace(s, `:`, `::`, -1)
}
// Generate returns a URL-safe secure XSRF token that expires in 24 hours.
//
// key is a secret key for your application; it must be non-empty.
// userID is an optional unique identifier for the user.
// actionID is an optional action the user is taking (e.g. POSTing to a particular path).
func Generate(key, userID, actionID string) string {
return generateTokenAtTime(key, userID, actionID, time.Now())
}
// generateTokenAtTime is like Generate, but returns a token that expires 24 hours from now.
func generateTokenAtTime(key, userID, actionID string, now time.Time) string {
if len(key) == 0 {
panic("zero length xsrf secret key")
}
// Round time up and convert to milliseconds.
milliTime := (now.UnixNano() + 1e6 - 1) / 1e6
h := hmac.New(sha1.New, []byte(key))
fmt.Fprintf(h, "%s:%s:%d", clean(userID), clean(actionID), milliTime)
// Get the no padding base64 string.
tok := string(h.Sum(nil))
tok = base64.RawURLEncoding.EncodeToString([]byte(tok))
return fmt.Sprintf("%s:%d", tok, milliTime)
}
// Valid reports whether a token is a valid, unexpired token returned by Generate.
// The token is considered to be expired and invalid if it is older than the default Timeout.
func Valid(token, key, userID, actionID string) bool {
return validTokenAtTime(token, key, userID, actionID, time.Now(), Timeout)
}
// ValidFor reports whether a token is a valid, unexpired token returned by Generate.
// The token is considered to be expired and invalid if it is older than the timeout duration.
func ValidFor(token, key, userID, actionID string, timeout time.Duration) bool {
return validTokenAtTime(token, key, userID, actionID, time.Now(), timeout)
}
// validTokenAtTime reports whether a token is valid at the given time.
func validTokenAtTime(token, key, userID, actionID string, now time.Time, timeout time.Duration) bool {
if len(key) == 0 {
panic("zero length xsrf secret key")
}
// Extract the issue time of the token.
sep := strings.LastIndex(token, ":")
if sep < 0 {
return false
}
millis, err := strconv.ParseInt(token[sep+1:], 10, 64)
if err != nil {
return false
}
issueTime := time.Unix(0, millis*1e6)
// Check that the token is not expired.
if now.Sub(issueTime) >= timeout {
return false
}
// Check that the token is not from the future.
// Allow 1 minute grace period in case the token is being verified on a
// machine whose clock is behind the machine that issued the token.
if issueTime.After(now.Add(1 * time.Minute)) {
return false
}
expected := generateTokenAtTime(key, userID, actionID, issueTime)
// Check that the token matches the expected value.
// Use constant time comparison to avoid timing attacks.
return subtle.ConstantTimeCompare([]byte(token), []byte(expected)) == 1
}
// 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.
//go:generate go run gen.go gen_trieval.go
// Package cases provides general and language-specific case mappers.
package cases // import "golang.org/x/text/cases"
import (
"golang.org/x/text/language"
"golang.org/x/text/transform"
)
// References:
// - Unicode Reference Manual Chapter 3.13, 4.2, and 5.18.
// - https://www.unicode.org/reports/tr29/
// - https://www.unicode.org/Public/6.3.0/ucd/CaseFolding.txt
// - https://www.unicode.org/Public/6.3.0/ucd/SpecialCasing.txt
// - https://www.unicode.org/Public/6.3.0/ucd/DerivedCoreProperties.txt
// - https://www.unicode.org/Public/6.3.0/ucd/auxiliary/WordBreakProperty.txt
// - https://www.unicode.org/Public/6.3.0/ucd/auxiliary/WordBreakTest.txt
// - http://userguide.icu-project.org/transforms/casemappings
// TODO:
// - Case folding
// - Wide and Narrow?
// - Segmenter option for title casing.
// - ASCII fast paths
// - Encode Soft-Dotted property within trie somehow.
// A Caser transforms given input to a certain case. It implements
// transform.Transformer.
//
// A Caser may be stateful and should therefore not be shared between
// goroutines.
type Caser struct {
t transform.SpanningTransformer
}
// Bytes returns a new byte slice with the result of converting b to the case
// form implemented by c.
func (c Caser) Bytes(b []byte) []byte {
b, _, _ = transform.Bytes(c.t, b)
return b
}
// String returns a string with the result of transforming s to the case form
// implemented by c.
func (c Caser) String(s string) string {
s, _, _ = transform.String(c.t, s)
return s
}
// Reset resets the Caser to be reused for new input after a previous call to
// Transform.
func (c Caser) Reset() { c.t.Reset() }
// Transform implements the transform.Transformer interface and transforms the
// given input to the case form implemented by c.
func (c Caser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
return c.t.Transform(dst, src, atEOF)
}
// Span implements the transform.SpanningTransformer interface.
func (c Caser) Span(src []byte, atEOF bool) (n int, err error) {
return c.t.Span(src, atEOF)
}
// Upper returns a Caser for language-specific uppercasing.
func Upper(t language.Tag, opts ...Option) Caser {
return Caser{makeUpper(t, getOpts(opts...))}
}
// Lower returns a Caser for language-specific lowercasing.
func Lower(t language.Tag, opts ...Option) Caser {
return Caser{makeLower(t, getOpts(opts...))}
}
// Title returns a Caser for language-specific title casing. It uses an
// approximation of the default Unicode Word Break algorithm.
func Title(t language.Tag, opts ...Option) Caser {
return Caser{makeTitle(t, getOpts(opts...))}
}
// Fold returns a Caser that implements Unicode case folding. The returned Caser
// is stateless and safe to use concurrently by multiple goroutines.
//
// Case folding does not normalize the input and may not preserve a normal form.
// Use the collate or search package for more convenient and linguistically
// sound comparisons. Use golang.org/x/text/secure/precis for string comparisons
// where security aspects are a concern.
func Fold(opts ...Option) Caser {
return Caser{makeFold(getOpts(opts...))}
}
// An Option is used to modify the behavior of a Caser.
type Option func(o options) options
// TODO: consider these options to take a boolean as well, like FinalSigma.
// The advantage of using this approach is that other providers of a lower-case
// algorithm could set different defaults by prefixing a user-provided slice
// of options with their own. This is handy, for instance, for the precis
// package which would override the default to not handle the Greek final sigma.
var (
// NoLower disables the lowercasing of non-leading letters for a title
// caser.
NoLower Option = noLower
// Compact omits mappings in case folding for characters that would grow the
// input. (Unimplemented.)
Compact Option = compact
)
// TODO: option to preserve a normal form, if applicable?
type options struct {
noLower bool
simple bool
// TODO: segmenter, max ignorable, alternative versions, etc.
ignoreFinalSigma bool
}
func getOpts(o ...Option) (res options) {
for _, f := range o {
res = f(res)
}
return
}
func noLower(o options) options {
o.noLower = true
return o
}
func compact(o options) options {
o.simple = true
return o
}
// HandleFinalSigma specifies whether the special handling of Greek final sigma
// should be enabled. Unicode prescribes handling the Greek final sigma for all
// locales, but standards like IDNA and PRECIS override this default.
func HandleFinalSigma(enable bool) Option {
if enable {
return handleFinalSigma
}
return ignoreFinalSigma
}
func ignoreFinalSigma(o options) options {
o.ignoreFinalSigma = true
return o
}
func handleFinalSigma(o options) options {
o.ignoreFinalSigma = false
return o
}
// 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 cases
import "golang.org/x/text/transform"
// A context is used for iterating over source bytes, fetching case info and
// writing to a destination buffer.
//
// Casing operations may need more than one rune of context to decide how a rune
// should be cased. Casing implementations should call checkpoint on context
// whenever it is known to be safe to return the runes processed so far.
//
// It is recommended for implementations to not allow for more than 30 case
// ignorables as lookahead (analogous to the limit in norm) and to use state if
// unbounded lookahead is needed for cased runes.
type context struct {
dst, src []byte
atEOF bool
pDst int // pDst points past the last written rune in dst.
pSrc int // pSrc points to the start of the currently scanned rune.
// checkpoints safe to return in Transform, where nDst <= pDst and nSrc <= pSrc.
nDst, nSrc int
err error
sz int // size of current rune
info info // case information of currently scanned rune
// State preserved across calls to Transform.
isMidWord bool // false if next cased letter needs to be title-cased.
}
func (c *context) Reset() {
c.isMidWord = false
}
// ret returns the return values for the Transform method. It checks whether
// there were insufficient bytes in src to complete and introduces an error
// accordingly, if necessary.
func (c *context) ret() (nDst, nSrc int, err error) {
if c.err != nil || c.nSrc == len(c.src) {
return c.nDst, c.nSrc, c.err
}
// This point is only reached by mappers if there was no short destination
// buffer. This means that the source buffer was exhausted and that c.sz was
// set to 0 by next.
if c.atEOF && c.pSrc == len(c.src) {
return c.pDst, c.pSrc, nil
}
return c.nDst, c.nSrc, transform.ErrShortSrc
}
// retSpan returns the return values for the Span method. It checks whether
// there were insufficient bytes in src to complete and introduces an error
// accordingly, if necessary.
func (c *context) retSpan() (n int, err error) {
_, nSrc, err := c.ret()
return nSrc, err
}
// checkpoint sets the return value buffer points for Transform to the current
// positions.
func (c *context) checkpoint() {
if c.err == nil {
c.nDst, c.nSrc = c.pDst, c.pSrc+c.sz
}
}
// unreadRune causes the last rune read by next to be reread on the next
// invocation of next. Only one unreadRune may be called after a call to next.
func (c *context) unreadRune() {
c.sz = 0
}
func (c *context) next() bool {
c.pSrc += c.sz
if c.pSrc == len(c.src) || c.err != nil {
c.info, c.sz = 0, 0
return false
}
v, sz := trie.lookup(c.src[c.pSrc:])
c.info, c.sz = info(v), sz
if c.sz == 0 {
if c.atEOF {
// A zero size means we have an incomplete rune. If we are atEOF,
// this means it is an illegal rune, which we will consume one
// byte at a time.
c.sz = 1
} else {
c.err = transform.ErrShortSrc
return false
}
}
return true
}
// writeBytes adds bytes to dst.
func (c *context) writeBytes(b []byte) bool {
if len(c.dst)-c.pDst < len(b) {
c.err = transform.ErrShortDst
return false
}
// This loop is faster than using copy.
for _, ch := range b {
c.dst[c.pDst] = ch
c.pDst++
}
return true
}
// writeString writes the given string to dst.
func (c *context) writeString(s string) bool {
if len(c.dst)-c.pDst < len(s) {
c.err = transform.ErrShortDst
return false
}
// This loop is faster than using copy.
for i := 0; i < len(s); i++ {
c.dst[c.pDst] = s[i]
c.pDst++
}
return true
}
// copy writes the current rune to dst.
func (c *context) copy() bool {
return c.writeBytes(c.src[c.pSrc : c.pSrc+c.sz])
}
// copyXOR copies the current rune to dst and modifies it by applying the XOR
// pattern of the case info. It is the responsibility of the caller to ensure
// that this is a rune with a XOR pattern defined.
func (c *context) copyXOR() bool {
if !c.copy() {
return false
}
if c.info&xorIndexBit == 0 {
// Fast path for 6-bit XOR pattern, which covers most cases.
c.dst[c.pDst-1] ^= byte(c.info >> xorShift)
} else {
// Interpret XOR bits as an index.
// TODO: test performance for unrolling this loop. Verify that we have
// at least two bytes and at most three.
idx := c.info >> xorShift
for p := c.pDst - 1; ; p-- {
c.dst[p] ^= xorData[idx]
idx--
if xorData[idx] == 0 {
break
}
}
}
return true
}
// hasPrefix returns true if src[pSrc:] starts with the given string.
func (c *context) hasPrefix(s string) bool {
b := c.src[c.pSrc:]
if len(b) < len(s) {
return false
}
for i, c := range b[:len(s)] {
if c != s[i] {
return false
}
}
return true
}
// caseType returns an info with only the case bits, normalized to either
// cLower, cUpper, cTitle or cUncased.
func (c *context) caseType() info {
cm := c.info & 0x7
if cm < 4 {
return cm
}
if cm >= cXORCase {
// xor the last bit of the rune with the case type bits.
b := c.src[c.pSrc+c.sz-1]
return info(b&1) ^ cm&0x3
}
if cm == cIgnorableCased {
return cLower
}
return cUncased
}
// lower writes the lowercase version of the current rune to dst.
func lower(c *context) bool {
ct := c.caseType()
if c.info&hasMappingMask == 0 || ct == cLower {
return c.copy()
}
if c.info&exceptionBit == 0 {
return c.copyXOR()
}
e := exceptions[c.info>>exceptionShift:]
offset := 2 + e[0]&lengthMask // size of header + fold string
if nLower := (e[1] >> lengthBits) & lengthMask; nLower != noChange {
return c.writeString(e[offset : offset+nLower])
}
return c.copy()
}
func isLower(c *context) bool {
ct := c.caseType()
if c.info&hasMappingMask == 0 || ct == cLower {
return true
}
if c.info&exceptionBit == 0 {
c.err = transform.ErrEndOfSpan
return false
}
e := exceptions[c.info>>exceptionShift:]
if nLower := (e[1] >> lengthBits) & lengthMask; nLower != noChange {
c.err = transform.ErrEndOfSpan
return false
}
return true
}
// upper writes the uppercase version of the current rune to dst.
func upper(c *context) bool {
ct := c.caseType()
if c.info&hasMappingMask == 0 || ct == cUpper {
return c.copy()
}
if c.info&exceptionBit == 0 {
return c.copyXOR()
}
e := exceptions[c.info>>exceptionShift:]
offset := 2 + e[0]&lengthMask // size of header + fold string
// Get length of first special case mapping.
n := (e[1] >> lengthBits) & lengthMask
if ct == cTitle {
// The first special case mapping is for lower. Set n to the second.
if n == noChange {
n = 0
}
n, e = e[1]&lengthMask, e[n:]
}
if n != noChange {
return c.writeString(e[offset : offset+n])
}
return c.copy()
}
// isUpper writes the isUppercase version of the current rune to dst.
func isUpper(c *context) bool {
ct := c.caseType()
if c.info&hasMappingMask == 0 || ct == cUpper {
return true
}
if c.info&exceptionBit == 0 {
c.err = transform.ErrEndOfSpan
return false
}
e := exceptions[c.info>>exceptionShift:]
// Get length of first special case mapping.
n := (e[1] >> lengthBits) & lengthMask
if ct == cTitle {
n = e[1] & lengthMask
}
if n != noChange {
c.err = transform.ErrEndOfSpan
return false
}
return true
}
// title writes the title case version of the current rune to dst.
func title(c *context) bool {
ct := c.caseType()
if c.info&hasMappingMask == 0 || ct == cTitle {
return c.copy()
}
if c.info&exceptionBit == 0 {
if ct == cLower {
return c.copyXOR()
}
return c.copy()
}
// Get the exception data.
e := exceptions[c.info>>exceptionShift:]
offset := 2 + e[0]&lengthMask // size of header + fold string
nFirst := (e[1] >> lengthBits) & lengthMask
if nTitle := e[1] & lengthMask; nTitle != noChange {
if nFirst != noChange {
e = e[nFirst:]
}
return c.writeString(e[offset : offset+nTitle])
}
if ct == cLower && nFirst != noChange {
// Use the uppercase version instead.
return c.writeString(e[offset : offset+nFirst])
}
// Already in correct case.
return c.copy()
}
// isTitle reports whether the current rune is in title case.
func isTitle(c *context) bool {
ct := c.caseType()
if c.info&hasMappingMask == 0 || ct == cTitle {
return true
}
if c.info&exceptionBit == 0 {
if ct == cLower {
c.err = transform.ErrEndOfSpan
return false
}
return true
}
// Get the exception data.
e := exceptions[c.info>>exceptionShift:]
if nTitle := e[1] & lengthMask; nTitle != noChange {
c.err = transform.ErrEndOfSpan
return false
}
nFirst := (e[1] >> lengthBits) & lengthMask
if ct == cLower && nFirst != noChange {
c.err = transform.ErrEndOfSpan
return false
}
return true
}
// foldFull writes the foldFull version of the current rune to dst.
func foldFull(c *context) bool {
if c.info&hasMappingMask == 0 {
return c.copy()
}
ct := c.caseType()
if c.info&exceptionBit == 0 {
if ct != cLower || c.info&inverseFoldBit != 0 {
return c.copyXOR()
}
return c.copy()
}
e := exceptions[c.info>>exceptionShift:]
n := e[0] & lengthMask
if n == 0 {
if ct == cLower {
return c.copy()
}
n = (e[1] >> lengthBits) & lengthMask
}
return c.writeString(e[2 : 2+n])
}
// isFoldFull reports whether the current run is mapped to foldFull
func isFoldFull(c *context) bool {
if c.info&hasMappingMask == 0 {
return true
}
ct := c.caseType()
if c.info&exceptionBit == 0 {
if ct != cLower || c.info&inverseFoldBit != 0 {
c.err = transform.ErrEndOfSpan
return false
}
return true
}
e := exceptions[c.info>>exceptionShift:]
n := e[0] & lengthMask
if n == 0 && ct == cLower {
return true
}
c.err = transform.ErrEndOfSpan
return false
}
// 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.
package cases
import "golang.org/x/text/transform"
type caseFolder struct{ transform.NopResetter }
// caseFolder implements the Transformer interface for doing case folding.
func (t *caseFolder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
c := context{dst: dst, src: src, atEOF: atEOF}
for c.next() {
foldFull(&c)
c.checkpoint()
}
return c.ret()
}
func (t *caseFolder) Span(src []byte, atEOF bool) (n int, err error) {
c := context{src: src, atEOF: atEOF}
for c.next() && isFoldFull(&c) {
c.checkpoint()
}
return c.retSpan()
}
func makeFold(o options) transform.SpanningTransformer {
// TODO: Special case folding, through option Language, Special/Turkic, or
// both.
// TODO: Implement Compact options.
return &caseFolder{}
}
// 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.
package cases
func (c info) cccVal() info {
if c&exceptionBit != 0 {
return info(exceptions[c>>exceptionShift]) & cccMask
}
return c & cccMask
}
func (c info) cccType() info {
ccc := c.cccVal()
if ccc <= cccZero {
return cccZero
}
return ccc
}
// TODO: Implement full Unicode breaking algorithm:
// 1) Implement breaking in separate package.
// 2) Use the breaker here.
// 3) Compare table size and performance of using the more generic breaker.
//
// Note that we can extend the current algorithm to be much more accurate. This
// only makes sense, though, if the performance and/or space penalty of using
// the generic breaker is big. Extra data will only be needed for non-cased
// runes, which means there are sufficient bits left in the caseType.
// ICU prohibits breaking in such cases as well.
// For the purpose of title casing we use an approximation of the Unicode Word
// Breaking algorithm defined in Annex #29:
// https://www.unicode.org/reports/tr29/#Default_Grapheme_Cluster_Table.
//
// For our approximation, we group the Word Break types into the following
// categories, with associated rules:
//
// 1) Letter:
// ALetter, Hebrew_Letter, Numeric, ExtendNumLet, Extend, Format_FE, ZWJ.
// Rule: Never break between consecutive runes of this category.
//
// 2) Mid:
// MidLetter, MidNumLet, Single_Quote.
// (Cf. case-ignorable: MidLetter, MidNumLet, Single_Quote or cat is Mn,
// Me, Cf, Lm or Sk).
// Rule: Don't break between Letter and Mid, but break between two Mids.
//
// 3) Break:
// Any other category: NewLine, MidNum, CR, LF, Double_Quote, Katakana, and
// Other.
// These categories should always result in a break between two cased letters.
// Rule: Always break.
//
// Note 1: the Katakana and MidNum categories can, in esoteric cases, result in
// preventing a break between two cased letters. For now we will ignore this
// (e.g. [ALetter] [ExtendNumLet] [Katakana] [ExtendNumLet] [ALetter] and
// [ALetter] [Numeric] [MidNum] [Numeric] [ALetter].)
//
// Note 2: the rule for Mid is very approximate, but works in most cases. To
// improve, we could store the categories in the trie value and use a FA to
// manage breaks. See TODO comment above.
//
// Note 3: according to the spec, it is possible for the Extend category to
// introduce breaks between other categories grouped in Letter. However, this
// is undesirable for our purposes. ICU prevents breaks in such cases as well.
// isBreak returns whether this rune should introduce a break.
func (c info) isBreak() bool {
return c.cccVal() == cccBreak
}
// isLetter returns whether the rune is of break type ALetter, Hebrew_Letter,
// Numeric, ExtendNumLet, or Extend.
func (c info) isLetter() bool {
ccc := c.cccVal()
if ccc == cccZero {
return !c.isCaseIgnorable()
}
return ccc != cccBreak
}
// 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 cases
// This file contains the definitions of case mappings for all supported
// languages. The rules for the language-specific tailorings were taken and
// modified from the CLDR transform definitions in common/transforms.
import (
"strings"
"unicode"
"unicode/utf8"
"golang.org/x/text/internal"
"golang.org/x/text/language"
"golang.org/x/text/transform"
"golang.org/x/text/unicode/norm"
)
// A mapFunc takes a context set to the current rune and writes the mapped
// version to the same context. It may advance the context to the next rune. It
// returns whether a checkpoint is possible: whether the pDst bytes written to
// dst so far won't need changing as we see more source bytes.
type mapFunc func(*context) bool
// A spanFunc takes a context set to the current rune and returns whether this
// rune would be altered when written to the output. It may advance the context
// to the next rune. It returns whether a checkpoint is possible.
type spanFunc func(*context) bool
// maxIgnorable defines the maximum number of ignorables to consider for
// lookahead operations.
const maxIgnorable = 30
// supported lists the language tags for which we have tailorings.
const supported = "und af az el lt nl tr"
func init() {
tags := []language.Tag{}
for _, s := range strings.Split(supported, " ") {
tags = append(tags, language.MustParse(s))
}
matcher = internal.NewInheritanceMatcher(tags)
Supported = language.NewCoverage(tags)
}
var (
matcher *internal.InheritanceMatcher
Supported language.Coverage
// We keep the following lists separate, instead of having a single per-
// language struct, to give the compiler a chance to remove unused code.
// Some uppercase mappers are stateless, so we can precompute the
// Transformers and save a bit on runtime allocations.
upperFunc = []struct {
upper mapFunc
span spanFunc
}{
{nil, nil}, // und
{nil, nil}, // af
{aztrUpper(upper), isUpper}, // az
{elUpper, noSpan}, // el
{ltUpper(upper), noSpan}, // lt
{nil, nil}, // nl
{aztrUpper(upper), isUpper}, // tr
}
undUpper transform.SpanningTransformer = &undUpperCaser{}
undLower transform.SpanningTransformer = &undLowerCaser{}
undLowerIgnoreSigma transform.SpanningTransformer = &undLowerIgnoreSigmaCaser{}
lowerFunc = []mapFunc{
nil, // und
nil, // af
aztrLower, // az
nil, // el
ltLower, // lt
nil, // nl
aztrLower, // tr
}
titleInfos = []struct {
title mapFunc
lower mapFunc
titleSpan spanFunc
rewrite func(*context)
}{
{title, lower, isTitle, nil}, // und
{title, lower, isTitle, afnlRewrite}, // af
{aztrUpper(title), aztrLower, isTitle, nil}, // az
{title, lower, isTitle, nil}, // el
{ltUpper(title), ltLower, noSpan, nil}, // lt
{nlTitle, lower, nlTitleSpan, afnlRewrite}, // nl
{aztrUpper(title), aztrLower, isTitle, nil}, // tr
}
)
func makeUpper(t language.Tag, o options) transform.SpanningTransformer {
_, i, _ := matcher.Match(t)
f := upperFunc[i].upper
if f == nil {
return undUpper
}
return &simpleCaser{f: f, span: upperFunc[i].span}
}
func makeLower(t language.Tag, o options) transform.SpanningTransformer {
_, i, _ := matcher.Match(t)
f := lowerFunc[i]
if f == nil {
if o.ignoreFinalSigma {
return undLowerIgnoreSigma
}
return undLower
}
if o.ignoreFinalSigma {
return &simpleCaser{f: f, span: isLower}
}
return &lowerCaser{
first: f,
midWord: finalSigma(f),
}
}
func makeTitle(t language.Tag, o options) transform.SpanningTransformer {
_, i, _ := matcher.Match(t)
x := &titleInfos[i]
lower := x.lower
if o.noLower {
lower = (*context).copy
} else if !o.ignoreFinalSigma {
lower = finalSigma(lower)
}
return &titleCaser{
title: x.title,
lower: lower,
titleSpan: x.titleSpan,
rewrite: x.rewrite,
}
}
func noSpan(c *context) bool {
c.err = transform.ErrEndOfSpan
return false
}
// TODO: consider a similar special case for the fast majority lower case. This
// is a bit more involved so will require some more precise benchmarking to
// justify it.
type undUpperCaser struct{ transform.NopResetter }
// undUpperCaser implements the Transformer interface for doing an upper case
// mapping for the root locale (und). It eliminates the need for an allocation
// as it prevents escaping by not using function pointers.
func (t undUpperCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
c := context{dst: dst, src: src, atEOF: atEOF}
for c.next() {
upper(&c)
c.checkpoint()
}
return c.ret()
}
func (t undUpperCaser) Span(src []byte, atEOF bool) (n int, err error) {
c := context{src: src, atEOF: atEOF}
for c.next() && isUpper(&c) {
c.checkpoint()
}
return c.retSpan()
}
// undLowerIgnoreSigmaCaser implements the Transformer interface for doing
// a lower case mapping for the root locale (und) ignoring final sigma
// handling. This casing algorithm is used in some performance-critical packages
// like secure/precis and x/net/http/idna, which warrants its special-casing.
type undLowerIgnoreSigmaCaser struct{ transform.NopResetter }
func (t undLowerIgnoreSigmaCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
c := context{dst: dst, src: src, atEOF: atEOF}
for c.next() && lower(&c) {
c.checkpoint()
}
return c.ret()
}
// Span implements a generic lower-casing. This is possible as isLower works
// for all lowercasing variants. All lowercase variants only vary in how they
// transform a non-lowercase letter. They will never change an already lowercase
// letter. In addition, there is no state.
func (t undLowerIgnoreSigmaCaser) Span(src []byte, atEOF bool) (n int, err error) {
c := context{src: src, atEOF: atEOF}
for c.next() && isLower(&c) {
c.checkpoint()
}
return c.retSpan()
}
type simpleCaser struct {
context
f mapFunc
span spanFunc
}
// simpleCaser implements the Transformer interface for doing a case operation
// on a rune-by-rune basis.
func (t *simpleCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
c := context{dst: dst, src: src, atEOF: atEOF}
for c.next() && t.f(&c) {
c.checkpoint()
}
return c.ret()
}
func (t *simpleCaser) Span(src []byte, atEOF bool) (n int, err error) {
c := context{src: src, atEOF: atEOF}
for c.next() && t.span(&c) {
c.checkpoint()
}
return c.retSpan()
}
// undLowerCaser implements the Transformer interface for doing a lower case
// mapping for the root locale (und) ignoring final sigma handling. This casing
// algorithm is used in some performance-critical packages like secure/precis
// and x/net/http/idna, which warrants its special-casing.
type undLowerCaser struct{ transform.NopResetter }
func (t undLowerCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
c := context{dst: dst, src: src, atEOF: atEOF}
for isInterWord := true; c.next(); {
if isInterWord {
if c.info.isCased() {
if !lower(&c) {
break
}
isInterWord = false
} else if !c.copy() {
break
}
} else {
if c.info.isNotCasedAndNotCaseIgnorable() {
if !c.copy() {
break
}
isInterWord = true
} else if !c.hasPrefix("Σ") {
if !lower(&c) {
break
}
} else if !finalSigmaBody(&c) {
break
}
}
c.checkpoint()
}
return c.ret()
}
func (t undLowerCaser) Span(src []byte, atEOF bool) (n int, err error) {
c := context{src: src, atEOF: atEOF}
for c.next() && isLower(&c) {
c.checkpoint()
}
return c.retSpan()
}
// lowerCaser implements the Transformer interface. The default Unicode lower
// casing requires different treatment for the first and subsequent characters
// of a word, most notably to handle the Greek final Sigma.
type lowerCaser struct {
undLowerIgnoreSigmaCaser
context
first, midWord mapFunc
}
func (t *lowerCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
t.context = context{dst: dst, src: src, atEOF: atEOF}
c := &t.context
for isInterWord := true; c.next(); {
if isInterWord {
if c.info.isCased() {
if !t.first(c) {
break
}
isInterWord = false
} else if !c.copy() {
break
}
} else {
if c.info.isNotCasedAndNotCaseIgnorable() {
if !c.copy() {
break
}
isInterWord = true
} else if !t.midWord(c) {
break
}
}
c.checkpoint()
}
return c.ret()
}
// titleCaser implements the Transformer interface. Title casing algorithms
// distinguish between the first letter of a word and subsequent letters of the
// same word. It uses state to avoid requiring a potentially infinite lookahead.
type titleCaser struct {
context
// rune mappings used by the actual casing algorithms.
title mapFunc
lower mapFunc
titleSpan spanFunc
rewrite func(*context)
}
// Transform implements the standard Unicode title case algorithm as defined in
// Chapter 3 of The Unicode Standard:
// toTitlecase(X): Find the word boundaries in X according to Unicode Standard
// Annex #29, "Unicode Text Segmentation." For each word boundary, find the
// first cased character F following the word boundary. If F exists, map F to
// Titlecase_Mapping(F); then map all characters C between F and the following
// word boundary to Lowercase_Mapping(C).
func (t *titleCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
t.context = context{dst: dst, src: src, atEOF: atEOF, isMidWord: t.isMidWord}
c := &t.context
if !c.next() {
return c.ret()
}
for {
p := c.info
if t.rewrite != nil {
t.rewrite(c)
}
wasMid := p.isMid()
// Break out of this loop on failure to ensure we do not modify the
// state incorrectly.
if p.isCased() {
if !c.isMidWord {
if !t.title(c) {
break
}
c.isMidWord = true
} else if !t.lower(c) {
break
}
} else if !c.copy() {
break
} else if p.isBreak() {
c.isMidWord = false
}
// As we save the state of the transformer, it is safe to call
// checkpoint after any successful write.
if !(c.isMidWord && wasMid) {
c.checkpoint()
}
if !c.next() {
break
}
if wasMid && c.info.isMid() {
c.isMidWord = false
}
}
return c.ret()
}
func (t *titleCaser) Span(src []byte, atEOF bool) (n int, err error) {
t.context = context{src: src, atEOF: atEOF, isMidWord: t.isMidWord}
c := &t.context
if !c.next() {
return c.retSpan()
}
for {
p := c.info
if t.rewrite != nil {
t.rewrite(c)
}
wasMid := p.isMid()
// Break out of this loop on failure to ensure we do not modify the
// state incorrectly.
if p.isCased() {
if !c.isMidWord {
if !t.titleSpan(c) {
break
}
c.isMidWord = true
} else if !isLower(c) {
break
}
} else if p.isBreak() {
c.isMidWord = false
}
// As we save the state of the transformer, it is safe to call
// checkpoint after any successful write.
if !(c.isMidWord && wasMid) {
c.checkpoint()
}
if !c.next() {
break
}
if wasMid && c.info.isMid() {
c.isMidWord = false
}
}
return c.retSpan()
}
// finalSigma adds Greek final Sigma handing to another casing function. It
// determines whether a lowercased sigma should be σ or ς, by looking ahead for
// case-ignorables and a cased letters.
func finalSigma(f mapFunc) mapFunc {
return func(c *context) bool {
if !c.hasPrefix("Σ") {
return f(c)
}
return finalSigmaBody(c)
}
}
func finalSigmaBody(c *context) bool {
// Current rune must be ∑.
// ::NFD();
// # 03A3; 03C2; 03A3; 03A3; Final_Sigma; # GREEK CAPITAL LETTER SIGMA
// Σ } [:case-ignorable:]* [:cased:] → σ;
// [:cased:] [:case-ignorable:]* { Σ → ς;
// ::Any-Lower;
// ::NFC();
p := c.pDst
c.writeString("ς")
// TODO: we should do this here, but right now this will never have an
// effect as this is called when the prefix is Sigma, whereas Dutch and
// Afrikaans only test for an apostrophe.
//
// if t.rewrite != nil {
// t.rewrite(c)
// }
// We need to do one more iteration after maxIgnorable, as a cased
// letter is not an ignorable and may modify the result.
wasMid := false
for i := 0; i < maxIgnorable+1; i++ {
if !c.next() {
return false
}
if !c.info.isCaseIgnorable() {
// All Midword runes are also case ignorable, so we are
// guaranteed to have a letter or word break here. As we are
// unreading the run, there is no need to unset c.isMidWord;
// the title caser will handle this.
if c.info.isCased() {
// p+1 is guaranteed to be in bounds: if writing ς was
// successful, p+1 will contain the second byte of ς. If not,
// this function will have returned after c.next returned false.
c.dst[p+1]++ // ς → σ
}
c.unreadRune()
return true
}
// A case ignorable may also introduce a word break, so we may need
// to continue searching even after detecting a break.
isMid := c.info.isMid()
if (wasMid && isMid) || c.info.isBreak() {
c.isMidWord = false
}
wasMid = isMid
c.copy()
}
return true
}
// finalSigmaSpan would be the same as isLower.
// elUpper implements Greek upper casing, which entails removing a predefined
// set of non-blocked modifiers. Note that these accents should not be removed
// for title casing!
// Example: "Οδός" -> "ΟΔΟΣ".
func elUpper(c *context) bool {
// From CLDR:
// [:Greek:] [^[:ccc=Not_Reordered:][:ccc=Above:]]*? { [\u0313\u0314\u0301\u0300\u0306\u0342\u0308\u0304] → ;
// [:Greek:] [^[:ccc=Not_Reordered:][:ccc=Iota_Subscript:]]*? { \u0345 → ;
r, _ := utf8.DecodeRune(c.src[c.pSrc:])
oldPDst := c.pDst
if !upper(c) {
return false
}
if !unicode.Is(unicode.Greek, r) {
return true
}
i := 0
// Take the properties of the uppercased rune that is already written to the
// destination. This saves us the trouble of having to uppercase the
// decomposed rune again.
if b := norm.NFD.Properties(c.dst[oldPDst:]).Decomposition(); b != nil {
// Restore the destination position and process the decomposed rune.
r, sz := utf8.DecodeRune(b)
if r <= 0xFF { // See A.6.1
return true
}
c.pDst = oldPDst
// Insert the first rune and ignore the modifiers. See A.6.2.
c.writeBytes(b[:sz])
i = len(b[sz:]) / 2 // Greek modifiers are always of length 2.
}
for ; i < maxIgnorable && c.next(); i++ {
switch r, _ := utf8.DecodeRune(c.src[c.pSrc:]); r {
// Above and Iota Subscript
case 0x0300, // U+0300 COMBINING GRAVE ACCENT
0x0301, // U+0301 COMBINING ACUTE ACCENT
0x0304, // U+0304 COMBINING MACRON
0x0306, // U+0306 COMBINING BREVE
0x0308, // U+0308 COMBINING DIAERESIS
0x0313, // U+0313 COMBINING COMMA ABOVE
0x0314, // U+0314 COMBINING REVERSED COMMA ABOVE
0x0342, // U+0342 COMBINING GREEK PERISPOMENI
0x0345: // U+0345 COMBINING GREEK YPOGEGRAMMENI
// No-op. Gobble the modifier.
default:
switch v, _ := trie.lookup(c.src[c.pSrc:]); info(v).cccType() {
case cccZero:
c.unreadRune()
return true
// We don't need to test for IotaSubscript as the only rune that
// qualifies (U+0345) was already excluded in the switch statement
// above. See A.4.
case cccAbove:
return c.copy()
default:
// Some other modifier. We're still allowed to gobble Greek
// modifiers after this.
c.copy()
}
}
}
return i == maxIgnorable
}
// TODO: implement elUpperSpan (low-priority: complex and infrequent).
func ltLower(c *context) bool {
// From CLDR:
// # Introduce an explicit dot above when lowercasing capital I's and J's
// # whenever there are more accents above.
// # (of the accents used in Lithuanian: grave, acute, tilde above, and ogonek)
// # 0049; 0069 0307; 0049; 0049; lt More_Above; # LATIN CAPITAL LETTER I
// # 004A; 006A 0307; 004A; 004A; lt More_Above; # LATIN CAPITAL LETTER J
// # 012E; 012F 0307; 012E; 012E; lt More_Above; # LATIN CAPITAL LETTER I WITH OGONEK
// # 00CC; 0069 0307 0300; 00CC; 00CC; lt; # LATIN CAPITAL LETTER I WITH GRAVE
// # 00CD; 0069 0307 0301; 00CD; 00CD; lt; # LATIN CAPITAL LETTER I WITH ACUTE
// # 0128; 0069 0307 0303; 0128; 0128; lt; # LATIN CAPITAL LETTER I WITH TILDE
// ::NFD();
// I } [^[:ccc=Not_Reordered:][:ccc=Above:]]* [:ccc=Above:] → i \u0307;
// J } [^[:ccc=Not_Reordered:][:ccc=Above:]]* [:ccc=Above:] → j \u0307;
// I \u0328 (Į) } [^[:ccc=Not_Reordered:][:ccc=Above:]]* [:ccc=Above:] → i \u0328 \u0307;
// I \u0300 (Ì) → i \u0307 \u0300;
// I \u0301 (Í) → i \u0307 \u0301;
// I \u0303 (Ĩ) → i \u0307 \u0303;
// ::Any-Lower();
// ::NFC();
i := 0
if r := c.src[c.pSrc]; r < utf8.RuneSelf {
lower(c)
if r != 'I' && r != 'J' {
return true
}
} else {
p := norm.NFD.Properties(c.src[c.pSrc:])
if d := p.Decomposition(); len(d) >= 3 && (d[0] == 'I' || d[0] == 'J') {
// UTF-8 optimization: the decomposition will only have an above
// modifier if the last rune of the decomposition is in [U+300-U+311].
// In all other cases, a decomposition starting with I is always
// an I followed by modifiers that are not cased themselves. See A.2.
if d[1] == 0xCC && d[2] <= 0x91 { // A.2.4.
if !c.writeBytes(d[:1]) {
return false
}
c.dst[c.pDst-1] += 'a' - 'A' // lower
// Assumption: modifier never changes on lowercase. See A.1.
// Assumption: all modifiers added have CCC = Above. See A.2.3.
return c.writeString("\u0307") && c.writeBytes(d[1:])
}
// In all other cases the additional modifiers will have a CCC
// that is less than 230 (Above). We will insert the U+0307, if
// needed, after these modifiers so that a string in FCD form
// will remain so. See A.2.2.
lower(c)
i = 1
} else {
return lower(c)
}
}
for ; i < maxIgnorable && c.next(); i++ {
switch c.info.cccType() {
case cccZero:
c.unreadRune()
return true
case cccAbove:
return c.writeString("\u0307") && c.copy() // See A.1.
default:
c.copy() // See A.1.
}
}
return i == maxIgnorable
}
// ltLowerSpan would be the same as isLower.
func ltUpper(f mapFunc) mapFunc {
return func(c *context) bool {
// Unicode:
// 0307; 0307; ; ; lt After_Soft_Dotted; # COMBINING DOT ABOVE
//
// From CLDR:
// # Remove \u0307 following soft-dotteds (i, j, and the like), with possible
// # intervening non-230 marks.
// ::NFD();
// [:Soft_Dotted:] [^[:ccc=Not_Reordered:][:ccc=Above:]]* { \u0307 → ;
// ::Any-Upper();
// ::NFC();
// TODO: See A.5. A soft-dotted rune never has an exception. This would
// allow us to overload the exception bit and encode this property in
// info. Need to measure performance impact of this.
r, _ := utf8.DecodeRune(c.src[c.pSrc:])
oldPDst := c.pDst
if !f(c) {
return false
}
if !unicode.Is(unicode.Soft_Dotted, r) {
return true
}
// We don't need to do an NFD normalization, as a soft-dotted rune never
// contains U+0307. See A.3.
i := 0
for ; i < maxIgnorable && c.next(); i++ {
switch c.info.cccType() {
case cccZero:
c.unreadRune()
return true
case cccAbove:
if c.hasPrefix("\u0307") {
// We don't do a full NFC, but rather combine runes for
// some of the common cases. (Returning NFC or
// preserving normal form is neither a requirement nor
// a possibility anyway).
if !c.next() {
return false
}
if c.dst[oldPDst] == 'I' && c.pDst == oldPDst+1 && c.src[c.pSrc] == 0xcc {
s := ""
switch c.src[c.pSrc+1] {
case 0x80: // U+0300 COMBINING GRAVE ACCENT
s = "\u00cc" // U+00CC LATIN CAPITAL LETTER I WITH GRAVE
case 0x81: // U+0301 COMBINING ACUTE ACCENT
s = "\u00cd" // U+00CD LATIN CAPITAL LETTER I WITH ACUTE
case 0x83: // U+0303 COMBINING TILDE
s = "\u0128" // U+0128 LATIN CAPITAL LETTER I WITH TILDE
case 0x88: // U+0308 COMBINING DIAERESIS
s = "\u00cf" // U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS
default:
}
if s != "" {
c.pDst = oldPDst
return c.writeString(s)
}
}
}
return c.copy()
default:
c.copy()
}
}
return i == maxIgnorable
}
}
// TODO: implement ltUpperSpan (low priority: complex and infrequent).
func aztrUpper(f mapFunc) mapFunc {
return func(c *context) bool {
// i→İ;
if c.src[c.pSrc] == 'i' {
return c.writeString("İ")
}
return f(c)
}
}
func aztrLower(c *context) (done bool) {
// From CLDR:
// # I and i-dotless; I-dot and i are case pairs in Turkish and Azeri
// # 0130; 0069; 0130; 0130; tr; # LATIN CAPITAL LETTER I WITH DOT ABOVE
// İ→i;
// # When lowercasing, remove dot_above in the sequence I + dot_above, which will turn into i.
// # This matches the behavior of the canonically equivalent I-dot_above
// # 0307; ; 0307; 0307; tr After_I; # COMBINING DOT ABOVE
// # When lowercasing, unless an I is before a dot_above, it turns into a dotless i.
// # 0049; 0131; 0049; 0049; tr Not_Before_Dot; # LATIN CAPITAL LETTER I
// I([^[:ccc=Not_Reordered:][:ccc=Above:]]*)\u0307 → i$1 ;
// I→ı ;
// ::Any-Lower();
if c.hasPrefix("\u0130") { // İ
return c.writeString("i")
}
if c.src[c.pSrc] != 'I' {
return lower(c)
}
// We ignore the lower-case I for now, but insert it later when we know
// which form we need.
start := c.pSrc + c.sz
i := 0
Loop:
// We check for up to n ignorables before \u0307. As \u0307 is an
// ignorable as well, n is maxIgnorable-1.
for ; i < maxIgnorable && c.next(); i++ {
switch c.info.cccType() {
case cccAbove:
if c.hasPrefix("\u0307") {
return c.writeString("i") && c.writeBytes(c.src[start:c.pSrc]) // ignore U+0307
}
done = true
break Loop
case cccZero:
c.unreadRune()
done = true
break Loop
default:
// We'll write this rune after we know which starter to use.
}
}
if i == maxIgnorable {
done = true
}
return c.writeString("ı") && c.writeBytes(c.src[start:c.pSrc+c.sz]) && done
}
// aztrLowerSpan would be the same as isLower.
func nlTitle(c *context) bool {
// From CLDR:
// # Special titlecasing for Dutch initial "ij".
// ::Any-Title();
// # Fix up Ij at the beginning of a "word" (per Any-Title, notUAX #29)
// [:^WB=ALetter:] [:WB=Extend:]* [[:WB=MidLetter:][:WB=MidNumLet:]]? { Ij } → IJ ;
if c.src[c.pSrc] != 'I' && c.src[c.pSrc] != 'i' {
return title(c)
}
if !c.writeString("I") || !c.next() {
return false
}
if c.src[c.pSrc] == 'j' || c.src[c.pSrc] == 'J' {
return c.writeString("J")
}
c.unreadRune()
return true
}
func nlTitleSpan(c *context) bool {
// From CLDR:
// # Special titlecasing for Dutch initial "ij".
// ::Any-Title();
// # Fix up Ij at the beginning of a "word" (per Any-Title, notUAX #29)
// [:^WB=ALetter:] [:WB=Extend:]* [[:WB=MidLetter:][:WB=MidNumLet:]]? { Ij } → IJ ;
if c.src[c.pSrc] != 'I' {
return isTitle(c)
}
if !c.next() || c.src[c.pSrc] == 'j' {
return false
}
if c.src[c.pSrc] != 'J' {
c.unreadRune()
}
return true
}
// Not part of CLDR, but see https://unicode.org/cldr/trac/ticket/7078.
func afnlRewrite(c *context) {
if c.hasPrefix("'") || c.hasPrefix("’") {
c.isMidWord = true
}
}
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.21
package cases
// UnicodeVersion is the Unicode version from which the tables in this package are derived.
const UnicodeVersion = "15.0.0"
var xorData string = "" + // Size: 213 bytes
"\x00\x06\x07\x00\x01?\x00\x0f\x03\x00\x0f\x12\x00\x0f\x1f\x00\x0f\x1d" +
"\x00\x01\x13\x00\x0f\x16\x00\x0f\x0b\x00\x0f3\x00\x0f7\x00\x01#\x00\x0f?" +
"\x00\x0e'\x00\x0f/\x00\x0e>\x00\x0f*\x00\x0c&\x00\x0c*\x00\x0c;\x00\x0c9" +
"\x00\x0c%\x00\x01\x08\x00\x03\x0d\x00\x03\x09\x00\x02\x06\x00\x02\x02" +
"\x00\x02\x0c\x00\x01\x00\x00\x01\x03\x00\x01\x01\x00\x01 \x00\x01\x0c" +
"\x00\x01\x10\x00\x03\x10\x00\x036 \x00\x037 \x00\x0b#\x10\x00\x0b 0\x00" +
"\x0b!\x10\x00\x0b!0\x001\x00\x00\x0b(\x04\x00\x03\x04\x1e\x00\x0b)\x08" +
"\x00\x03\x0a\x00\x02:\x00\x02>\x00\x02,\x00\x02\x00\x00\x02\x10\x00\x01<" +
"\x00\x01&\x00\x01*\x00\x01.\x00\x010\x003 \x00\x01\x18\x00\x01(\x00\x03'" +
"\x00\x03)\x00\x03+\x00\x03/\x00\x03\x19\x00\x03\x1b\x00\x03\x1f\x00\x01" +
"\x1e\x00\x01\x22"
var exceptions string = "" + // Size: 2450 bytes
"\x00\x12\x12μΜΜ\x12\x12ssSSSs\x13\x18i̇i̇\x10\x09II\x13\x1bʼnʼNʼN\x11" +
"\x09sSS\x12\x12dždžDž\x12\x12dždžDŽ\x10\x12DŽDž\x12\x12ljljLj\x12\x12ljljLJ\x10\x12LJLj" +
"\x12\x12njnjNj\x12\x12njnjNJ\x10\x12NJNj\x13\x1bǰJ̌J̌\x12\x12dzdzDz\x12\x12dzdzDZ\x10" +
"\x12DZDz\x13\x18ⱥⱥ\x13\x18ⱦⱦ\x10\x1bⱾⱾ\x10\x1bⱿⱿ\x10\x1bⱯⱯ\x10\x1bⱭⱭ\x10" +
"\x1bⱰⱰ\x10\x1bꞫꞫ\x10\x1bꞬꞬ\x10\x1bꞍꞍ\x10\x1bꞪꞪ\x10\x1bꞮꞮ\x10\x1bⱢⱢ\x10" +
"\x1bꞭꞭ\x10\x1bⱮⱮ\x10\x1bⱤⱤ\x10\x1bꟅꟅ\x10\x1bꞱꞱ\x10\x1bꞲꞲ\x10\x1bꞰꞰ2\x12ι" +
"ΙΙ\x166ΐΪ́Ϊ́\x166ΰΫ́Ϋ́\x12\x12σΣΣ\x12\x12βΒΒ\x12\x12θΘΘ\x12\x12" +
"φΦΦ\x12\x12πΠΠ\x12\x12κΚΚ\x12\x12ρΡΡ\x12\x12εΕΕ\x14$եւԵՒԵւ\x10\x1bᲐა" +
"\x10\x1bᲑბ\x10\x1bᲒგ\x10\x1bᲓდ\x10\x1bᲔე\x10\x1bᲕვ\x10\x1bᲖზ\x10\x1bᲗთ" +
"\x10\x1bᲘი\x10\x1bᲙკ\x10\x1bᲚლ\x10\x1bᲛმ\x10\x1bᲜნ\x10\x1bᲝო\x10\x1bᲞპ" +
"\x10\x1bᲟჟ\x10\x1bᲠრ\x10\x1bᲡს\x10\x1bᲢტ\x10\x1bᲣუ\x10\x1bᲤფ\x10\x1bᲥქ" +
"\x10\x1bᲦღ\x10\x1bᲧყ\x10\x1bᲨშ\x10\x1bᲩჩ\x10\x1bᲪც\x10\x1bᲫძ\x10\x1bᲬწ" +
"\x10\x1bᲭჭ\x10\x1bᲮხ\x10\x1bᲯჯ\x10\x1bᲰჰ\x10\x1bᲱჱ\x10\x1bᲲჲ\x10\x1bᲳჳ" +
"\x10\x1bᲴჴ\x10\x1bᲵჵ\x10\x1bᲶჶ\x10\x1bᲷჷ\x10\x1bᲸჸ\x10\x1bᲹჹ\x10\x1bᲺჺ" +
"\x10\x1bᲽჽ\x10\x1bᲾჾ\x10\x1bᲿჿ\x12\x12вВВ\x12\x12дДД\x12\x12оОО\x12\x12с" +
"СС\x12\x12тТТ\x12\x12тТТ\x12\x12ъЪЪ\x12\x12ѣѢѢ\x13\x1bꙋꙊꙊ\x13\x1bẖH̱H̱" +
"\x13\x1bẗT̈T̈\x13\x1bẘW̊W̊\x13\x1bẙY̊Y̊\x13\x1baʾAʾAʾ\x13\x1bṡṠṠ\x12" +
"\x10ssß\x14$ὐΥ̓Υ̓\x166ὒΥ̓̀Υ̓̀\x166ὔΥ̓́Υ̓́\x166ὖΥ̓͂Υ̓͂\x15+ἀιἈΙᾈ" +
"\x15+ἁιἉΙᾉ\x15+ἂιἊΙᾊ\x15+ἃιἋΙᾋ\x15+ἄιἌΙᾌ\x15+ἅιἍΙᾍ\x15+ἆιἎΙᾎ\x15+ἇιἏΙᾏ" +
"\x15\x1dἀιᾀἈΙ\x15\x1dἁιᾁἉΙ\x15\x1dἂιᾂἊΙ\x15\x1dἃιᾃἋΙ\x15\x1dἄιᾄἌΙ\x15" +
"\x1dἅιᾅἍΙ\x15\x1dἆιᾆἎΙ\x15\x1dἇιᾇἏΙ\x15+ἠιἨΙᾘ\x15+ἡιἩΙᾙ\x15+ἢιἪΙᾚ\x15+ἣι" +
"ἫΙᾛ\x15+ἤιἬΙᾜ\x15+ἥιἭΙᾝ\x15+ἦιἮΙᾞ\x15+ἧιἯΙᾟ\x15\x1dἠιᾐἨΙ\x15\x1dἡιᾑἩΙ" +
"\x15\x1dἢιᾒἪΙ\x15\x1dἣιᾓἫΙ\x15\x1dἤιᾔἬΙ\x15\x1dἥιᾕἭΙ\x15\x1dἦιᾖἮΙ\x15" +
"\x1dἧιᾗἯΙ\x15+ὠιὨΙᾨ\x15+ὡιὩΙᾩ\x15+ὢιὪΙᾪ\x15+ὣιὫΙᾫ\x15+ὤιὬΙᾬ\x15+ὥιὭΙᾭ" +
"\x15+ὦιὮΙᾮ\x15+ὧιὯΙᾯ\x15\x1dὠιᾠὨΙ\x15\x1dὡιᾡὩΙ\x15\x1dὢιᾢὪΙ\x15\x1dὣιᾣὫΙ" +
"\x15\x1dὤιᾤὬΙ\x15\x1dὥιᾥὭΙ\x15\x1dὦιᾦὮΙ\x15\x1dὧιᾧὯΙ\x15-ὰιᾺΙᾺͅ\x14#αιΑΙ" +
"ᾼ\x14$άιΆΙΆͅ\x14$ᾶΑ͂Α͂\x166ᾶιΑ͂Ιᾼ͂\x14\x1cαιᾳΑΙ\x12\x12ιΙΙ\x15-ὴιῊΙ" +
"Ὴͅ\x14#ηιΗΙῌ\x14$ήιΉΙΉͅ\x14$ῆΗ͂Η͂\x166ῆιΗ͂Ιῌ͂\x14\x1cηιῃΗΙ\x166ῒΙ" +
"̈̀Ϊ̀\x166ΐΪ́Ϊ́\x14$ῖΙ͂Ι͂\x166ῗΪ͂Ϊ͂\x166ῢΫ̀Ϋ̀\x166ΰΫ́Ϋ" +
"́\x14$ῤΡ̓Ρ̓\x14$ῦΥ͂Υ͂\x166ῧΫ͂Ϋ͂\x15-ὼιῺΙῺͅ\x14#ωιΩΙῼ\x14$ώιΏΙΏͅ" +
"\x14$ῶΩ͂Ω͂\x166ῶιΩ͂Ιῼ͂\x14\x1cωιῳΩΙ\x12\x10ωω\x11\x08kk\x12\x10åå\x12" +
"\x10ɫɫ\x12\x10ɽɽ\x10\x12ȺȺ\x10\x12ȾȾ\x12\x10ɑɑ\x12\x10ɱɱ\x12\x10ɐɐ\x12" +
"\x10ɒɒ\x12\x10ȿȿ\x12\x10ɀɀ\x12\x10ɥɥ\x12\x10ɦɦ\x12\x10ɜɜ\x12\x10ɡɡ\x12" +
"\x10ɬɬ\x12\x10ɪɪ\x12\x10ʞʞ\x12\x10ʇʇ\x12\x10ʝʝ\x12\x10ʂʂ\x12\x12ffFFFf" +
"\x12\x12fiFIFi\x12\x12flFLFl\x13\x1bffiFFIFfi\x13\x1bfflFFLFfl\x12\x12st" +
"STSt\x12\x12stSTSt\x14$մնՄՆՄն\x14$մեՄԵՄե\x14$միՄԻՄի\x14$վնՎՆՎն\x14$մխՄԽՄ" +
"խ"
// lookup returns the trie value for the first UTF-8 encoding in s and
// the width in bytes of this encoding. The size will be 0 if s does not
// hold enough bytes to complete the encoding. len(s) must be greater than 0.
func (t *caseTrie) lookup(s []byte) (v uint16, sz int) {
c0 := s[0]
switch {
case c0 < 0x80: // is ASCII
return caseValues[c0], 1
case c0 < 0xC2:
return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
case c0 < 0xE0: // 2-byte UTF-8
if len(s) < 2 {
return 0, 0
}
i := caseIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c1), 2
case c0 < 0xF0: // 3-byte UTF-8
if len(s) < 3 {
return 0, 0
}
i := caseIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = caseIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c2), 3
case c0 < 0xF8: // 4-byte UTF-8
if len(s) < 4 {
return 0, 0
}
i := caseIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = caseIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
o = uint32(i)<<6 + uint32(c2)
i = caseIndex[o]
c3 := s[3]
if c3 < 0x80 || 0xC0 <= c3 {
return 0, 3 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c3), 4
}
// Illegal rune
return 0, 1
}
// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
// s must start with a full and valid UTF-8 encoded rune.
func (t *caseTrie) lookupUnsafe(s []byte) uint16 {
c0 := s[0]
if c0 < 0x80 { // is ASCII
return caseValues[c0]
}
i := caseIndex[c0]
if c0 < 0xE0 { // 2-byte UTF-8
return t.lookupValue(uint32(i), s[1])
}
i = caseIndex[uint32(i)<<6+uint32(s[1])]
if c0 < 0xF0 { // 3-byte UTF-8
return t.lookupValue(uint32(i), s[2])
}
i = caseIndex[uint32(i)<<6+uint32(s[2])]
if c0 < 0xF8 { // 4-byte UTF-8
return t.lookupValue(uint32(i), s[3])
}
return 0
}
// lookupString returns the trie value for the first UTF-8 encoding in s and
// the width in bytes of this encoding. The size will be 0 if s does not
// hold enough bytes to complete the encoding. len(s) must be greater than 0.
func (t *caseTrie) lookupString(s string) (v uint16, sz int) {
c0 := s[0]
switch {
case c0 < 0x80: // is ASCII
return caseValues[c0], 1
case c0 < 0xC2:
return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
case c0 < 0xE0: // 2-byte UTF-8
if len(s) < 2 {
return 0, 0
}
i := caseIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c1), 2
case c0 < 0xF0: // 3-byte UTF-8
if len(s) < 3 {
return 0, 0
}
i := caseIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = caseIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c2), 3
case c0 < 0xF8: // 4-byte UTF-8
if len(s) < 4 {
return 0, 0
}
i := caseIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = caseIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
o = uint32(i)<<6 + uint32(c2)
i = caseIndex[o]
c3 := s[3]
if c3 < 0x80 || 0xC0 <= c3 {
return 0, 3 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c3), 4
}
// Illegal rune
return 0, 1
}
// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
// s must start with a full and valid UTF-8 encoded rune.
func (t *caseTrie) lookupStringUnsafe(s string) uint16 {
c0 := s[0]
if c0 < 0x80 { // is ASCII
return caseValues[c0]
}
i := caseIndex[c0]
if c0 < 0xE0 { // 2-byte UTF-8
return t.lookupValue(uint32(i), s[1])
}
i = caseIndex[uint32(i)<<6+uint32(s[1])]
if c0 < 0xF0 { // 3-byte UTF-8
return t.lookupValue(uint32(i), s[2])
}
i = caseIndex[uint32(i)<<6+uint32(s[2])]
if c0 < 0xF8 { // 4-byte UTF-8
return t.lookupValue(uint32(i), s[3])
}
return 0
}
// caseTrie. Total size: 13398 bytes (13.08 KiB). Checksum: 544af6e6b1b70931.
type caseTrie struct{}
func newCaseTrie(i int) *caseTrie {
return &caseTrie{}
}
// lookupValue determines the type of block n and looks up the value for b.
func (t *caseTrie) lookupValue(n uint32, b byte) uint16 {
switch {
case n < 22:
return uint16(caseValues[n<<6+uint32(b)])
default:
n -= 22
return uint16(sparse.lookup(n, b))
}
}
// caseValues: 24 blocks, 1536 entries, 3072 bytes
// The third block is the zero block.
var caseValues = [1536]uint16{
// Block 0x0, offset 0x0
0x27: 0x0054,
0x2e: 0x0054,
0x30: 0x0010, 0x31: 0x0010, 0x32: 0x0010, 0x33: 0x0010, 0x34: 0x0010, 0x35: 0x0010,
0x36: 0x0010, 0x37: 0x0010, 0x38: 0x0010, 0x39: 0x0010, 0x3a: 0x0054,
// Block 0x1, offset 0x40
0x41: 0x2013, 0x42: 0x2013, 0x43: 0x2013, 0x44: 0x2013, 0x45: 0x2013,
0x46: 0x2013, 0x47: 0x2013, 0x48: 0x2013, 0x49: 0x2013, 0x4a: 0x2013, 0x4b: 0x2013,
0x4c: 0x2013, 0x4d: 0x2013, 0x4e: 0x2013, 0x4f: 0x2013, 0x50: 0x2013, 0x51: 0x2013,
0x52: 0x2013, 0x53: 0x2013, 0x54: 0x2013, 0x55: 0x2013, 0x56: 0x2013, 0x57: 0x2013,
0x58: 0x2013, 0x59: 0x2013, 0x5a: 0x2013,
0x5e: 0x0004, 0x5f: 0x0010, 0x60: 0x0004, 0x61: 0x2012, 0x62: 0x2012, 0x63: 0x2012,
0x64: 0x2012, 0x65: 0x2012, 0x66: 0x2012, 0x67: 0x2012, 0x68: 0x2012, 0x69: 0x2012,
0x6a: 0x2012, 0x6b: 0x2012, 0x6c: 0x2012, 0x6d: 0x2012, 0x6e: 0x2012, 0x6f: 0x2012,
0x70: 0x2012, 0x71: 0x2012, 0x72: 0x2012, 0x73: 0x2012, 0x74: 0x2012, 0x75: 0x2012,
0x76: 0x2012, 0x77: 0x2012, 0x78: 0x2012, 0x79: 0x2012, 0x7a: 0x2012,
// Block 0x2, offset 0x80
// Block 0x3, offset 0xc0
0xc0: 0x0852, 0xc1: 0x0b53, 0xc2: 0x0113, 0xc3: 0x0112, 0xc4: 0x0113, 0xc5: 0x0112,
0xc6: 0x0b53, 0xc7: 0x0f13, 0xc8: 0x0f12, 0xc9: 0x0e53, 0xca: 0x1153, 0xcb: 0x0713,
0xcc: 0x0712, 0xcd: 0x0012, 0xce: 0x1453, 0xcf: 0x1753, 0xd0: 0x1a53, 0xd1: 0x0313,
0xd2: 0x0312, 0xd3: 0x1d53, 0xd4: 0x2053, 0xd5: 0x2352, 0xd6: 0x2653, 0xd7: 0x2653,
0xd8: 0x0113, 0xd9: 0x0112, 0xda: 0x2952, 0xdb: 0x0012, 0xdc: 0x1d53, 0xdd: 0x2c53,
0xde: 0x2f52, 0xdf: 0x3253, 0xe0: 0x0113, 0xe1: 0x0112, 0xe2: 0x0113, 0xe3: 0x0112,
0xe4: 0x0113, 0xe5: 0x0112, 0xe6: 0x3553, 0xe7: 0x0f13, 0xe8: 0x0f12, 0xe9: 0x3853,
0xea: 0x0012, 0xeb: 0x0012, 0xec: 0x0113, 0xed: 0x0112, 0xee: 0x3553, 0xef: 0x1f13,
0xf0: 0x1f12, 0xf1: 0x3b53, 0xf2: 0x3e53, 0xf3: 0x0713, 0xf4: 0x0712, 0xf5: 0x0313,
0xf6: 0x0312, 0xf7: 0x4153, 0xf8: 0x0113, 0xf9: 0x0112, 0xfa: 0x0012, 0xfb: 0x0010,
0xfc: 0x0113, 0xfd: 0x0112, 0xfe: 0x0012, 0xff: 0x4452,
// Block 0x4, offset 0x100
0x100: 0x0010, 0x101: 0x0010, 0x102: 0x0010, 0x103: 0x0010, 0x104: 0x02db, 0x105: 0x0359,
0x106: 0x03da, 0x107: 0x043b, 0x108: 0x04b9, 0x109: 0x053a, 0x10a: 0x059b, 0x10b: 0x0619,
0x10c: 0x069a, 0x10d: 0x0313, 0x10e: 0x0312, 0x10f: 0x1f13, 0x110: 0x1f12, 0x111: 0x0313,
0x112: 0x0312, 0x113: 0x0713, 0x114: 0x0712, 0x115: 0x0313, 0x116: 0x0312, 0x117: 0x0f13,
0x118: 0x0f12, 0x119: 0x0313, 0x11a: 0x0312, 0x11b: 0x0713, 0x11c: 0x0712, 0x11d: 0x1452,
0x11e: 0x0113, 0x11f: 0x0112, 0x120: 0x0113, 0x121: 0x0112, 0x122: 0x0113, 0x123: 0x0112,
0x124: 0x0113, 0x125: 0x0112, 0x126: 0x0113, 0x127: 0x0112, 0x128: 0x0113, 0x129: 0x0112,
0x12a: 0x0113, 0x12b: 0x0112, 0x12c: 0x0113, 0x12d: 0x0112, 0x12e: 0x0113, 0x12f: 0x0112,
0x130: 0x06fa, 0x131: 0x07ab, 0x132: 0x0829, 0x133: 0x08aa, 0x134: 0x0113, 0x135: 0x0112,
0x136: 0x2353, 0x137: 0x4453, 0x138: 0x0113, 0x139: 0x0112, 0x13a: 0x0113, 0x13b: 0x0112,
0x13c: 0x0113, 0x13d: 0x0112, 0x13e: 0x0113, 0x13f: 0x0112,
// Block 0x5, offset 0x140
0x140: 0x0a8a, 0x141: 0x0313, 0x142: 0x0312, 0x143: 0x0853, 0x144: 0x4753, 0x145: 0x4a53,
0x146: 0x0113, 0x147: 0x0112, 0x148: 0x0113, 0x149: 0x0112, 0x14a: 0x0113, 0x14b: 0x0112,
0x14c: 0x0113, 0x14d: 0x0112, 0x14e: 0x0113, 0x14f: 0x0112, 0x150: 0x0b0a, 0x151: 0x0b8a,
0x152: 0x0c0a, 0x153: 0x0b52, 0x154: 0x0b52, 0x155: 0x0012, 0x156: 0x0e52, 0x157: 0x1152,
0x158: 0x0012, 0x159: 0x1752, 0x15a: 0x0012, 0x15b: 0x1a52, 0x15c: 0x0c8a, 0x15d: 0x0012,
0x15e: 0x0012, 0x15f: 0x0012, 0x160: 0x1d52, 0x161: 0x0d0a, 0x162: 0x0012, 0x163: 0x2052,
0x164: 0x0012, 0x165: 0x0d8a, 0x166: 0x0e0a, 0x167: 0x0012, 0x168: 0x2652, 0x169: 0x2652,
0x16a: 0x0e8a, 0x16b: 0x0f0a, 0x16c: 0x0f8a, 0x16d: 0x0012, 0x16e: 0x0012, 0x16f: 0x1d52,
0x170: 0x0012, 0x171: 0x100a, 0x172: 0x2c52, 0x173: 0x0012, 0x174: 0x0012, 0x175: 0x3252,
0x176: 0x0012, 0x177: 0x0012, 0x178: 0x0012, 0x179: 0x0012, 0x17a: 0x0012, 0x17b: 0x0012,
0x17c: 0x0012, 0x17d: 0x108a, 0x17e: 0x0012, 0x17f: 0x0012,
// Block 0x6, offset 0x180
0x180: 0x3552, 0x181: 0x0012, 0x182: 0x110a, 0x183: 0x3852, 0x184: 0x0012, 0x185: 0x0012,
0x186: 0x0012, 0x187: 0x118a, 0x188: 0x3552, 0x189: 0x4752, 0x18a: 0x3b52, 0x18b: 0x3e52,
0x18c: 0x4a52, 0x18d: 0x0012, 0x18e: 0x0012, 0x18f: 0x0012, 0x190: 0x0012, 0x191: 0x0012,
0x192: 0x4152, 0x193: 0x0012, 0x194: 0x0010, 0x195: 0x0012, 0x196: 0x0012, 0x197: 0x0012,
0x198: 0x0012, 0x199: 0x0012, 0x19a: 0x0012, 0x19b: 0x0012, 0x19c: 0x0012, 0x19d: 0x120a,
0x19e: 0x128a, 0x19f: 0x0012, 0x1a0: 0x0012, 0x1a1: 0x0012, 0x1a2: 0x0012, 0x1a3: 0x0012,
0x1a4: 0x0012, 0x1a5: 0x0012, 0x1a6: 0x0012, 0x1a7: 0x0012, 0x1a8: 0x0012, 0x1a9: 0x0012,
0x1aa: 0x0012, 0x1ab: 0x0012, 0x1ac: 0x0012, 0x1ad: 0x0012, 0x1ae: 0x0012, 0x1af: 0x0012,
0x1b0: 0x0015, 0x1b1: 0x0015, 0x1b2: 0x0015, 0x1b3: 0x0015, 0x1b4: 0x0015, 0x1b5: 0x0015,
0x1b6: 0x0015, 0x1b7: 0x0015, 0x1b8: 0x0015, 0x1b9: 0x0014, 0x1ba: 0x0014, 0x1bb: 0x0014,
0x1bc: 0x0014, 0x1bd: 0x0014, 0x1be: 0x0014, 0x1bf: 0x0014,
// Block 0x7, offset 0x1c0
0x1c0: 0x0024, 0x1c1: 0x0024, 0x1c2: 0x0024, 0x1c3: 0x0024, 0x1c4: 0x0024, 0x1c5: 0x130d,
0x1c6: 0x0024, 0x1c7: 0x0034, 0x1c8: 0x0034, 0x1c9: 0x0034, 0x1ca: 0x0024, 0x1cb: 0x0024,
0x1cc: 0x0024, 0x1cd: 0x0034, 0x1ce: 0x0034, 0x1cf: 0x0014, 0x1d0: 0x0024, 0x1d1: 0x0024,
0x1d2: 0x0024, 0x1d3: 0x0034, 0x1d4: 0x0034, 0x1d5: 0x0034, 0x1d6: 0x0034, 0x1d7: 0x0024,
0x1d8: 0x0034, 0x1d9: 0x0034, 0x1da: 0x0034, 0x1db: 0x0024, 0x1dc: 0x0034, 0x1dd: 0x0034,
0x1de: 0x0034, 0x1df: 0x0034, 0x1e0: 0x0034, 0x1e1: 0x0034, 0x1e2: 0x0034, 0x1e3: 0x0024,
0x1e4: 0x0024, 0x1e5: 0x0024, 0x1e6: 0x0024, 0x1e7: 0x0024, 0x1e8: 0x0024, 0x1e9: 0x0024,
0x1ea: 0x0024, 0x1eb: 0x0024, 0x1ec: 0x0024, 0x1ed: 0x0024, 0x1ee: 0x0024, 0x1ef: 0x0024,
0x1f0: 0x0113, 0x1f1: 0x0112, 0x1f2: 0x0113, 0x1f3: 0x0112, 0x1f4: 0x0014, 0x1f5: 0x0004,
0x1f6: 0x0113, 0x1f7: 0x0112, 0x1fa: 0x0015, 0x1fb: 0x4d52,
0x1fc: 0x5052, 0x1fd: 0x5052, 0x1ff: 0x5353,
// Block 0x8, offset 0x200
0x204: 0x0004, 0x205: 0x0004,
0x206: 0x2a13, 0x207: 0x0054, 0x208: 0x2513, 0x209: 0x2713, 0x20a: 0x2513,
0x20c: 0x5653, 0x20e: 0x5953, 0x20f: 0x5c53, 0x210: 0x138a, 0x211: 0x2013,
0x212: 0x2013, 0x213: 0x2013, 0x214: 0x2013, 0x215: 0x2013, 0x216: 0x2013, 0x217: 0x2013,
0x218: 0x2013, 0x219: 0x2013, 0x21a: 0x2013, 0x21b: 0x2013, 0x21c: 0x2013, 0x21d: 0x2013,
0x21e: 0x2013, 0x21f: 0x2013, 0x220: 0x5f53, 0x221: 0x5f53, 0x223: 0x5f53,
0x224: 0x5f53, 0x225: 0x5f53, 0x226: 0x5f53, 0x227: 0x5f53, 0x228: 0x5f53, 0x229: 0x5f53,
0x22a: 0x5f53, 0x22b: 0x5f53, 0x22c: 0x2a12, 0x22d: 0x2512, 0x22e: 0x2712, 0x22f: 0x2512,
0x230: 0x14ca, 0x231: 0x2012, 0x232: 0x2012, 0x233: 0x2012, 0x234: 0x2012, 0x235: 0x2012,
0x236: 0x2012, 0x237: 0x2012, 0x238: 0x2012, 0x239: 0x2012, 0x23a: 0x2012, 0x23b: 0x2012,
0x23c: 0x2012, 0x23d: 0x2012, 0x23e: 0x2012, 0x23f: 0x2012,
// Block 0x9, offset 0x240
0x240: 0x5f52, 0x241: 0x5f52, 0x242: 0x160a, 0x243: 0x5f52, 0x244: 0x5f52, 0x245: 0x5f52,
0x246: 0x5f52, 0x247: 0x5f52, 0x248: 0x5f52, 0x249: 0x5f52, 0x24a: 0x5f52, 0x24b: 0x5f52,
0x24c: 0x5652, 0x24d: 0x5952, 0x24e: 0x5c52, 0x24f: 0x1813, 0x250: 0x168a, 0x251: 0x170a,
0x252: 0x0013, 0x253: 0x0013, 0x254: 0x0013, 0x255: 0x178a, 0x256: 0x180a, 0x257: 0x1812,
0x258: 0x0113, 0x259: 0x0112, 0x25a: 0x0113, 0x25b: 0x0112, 0x25c: 0x0113, 0x25d: 0x0112,
0x25e: 0x0113, 0x25f: 0x0112, 0x260: 0x0113, 0x261: 0x0112, 0x262: 0x0113, 0x263: 0x0112,
0x264: 0x0113, 0x265: 0x0112, 0x266: 0x0113, 0x267: 0x0112, 0x268: 0x0113, 0x269: 0x0112,
0x26a: 0x0113, 0x26b: 0x0112, 0x26c: 0x0113, 0x26d: 0x0112, 0x26e: 0x0113, 0x26f: 0x0112,
0x270: 0x188a, 0x271: 0x190a, 0x272: 0x0b12, 0x273: 0x5352, 0x274: 0x6253, 0x275: 0x198a,
0x277: 0x0f13, 0x278: 0x0f12, 0x279: 0x0b13, 0x27a: 0x0113, 0x27b: 0x0112,
0x27c: 0x0012, 0x27d: 0x4d53, 0x27e: 0x5053, 0x27f: 0x5053,
// Block 0xa, offset 0x280
0x280: 0x6852, 0x281: 0x6852, 0x282: 0x6852, 0x283: 0x6852, 0x284: 0x6852, 0x285: 0x6852,
0x286: 0x6852, 0x287: 0x1a0a, 0x288: 0x0012, 0x28a: 0x0010,
0x291: 0x0034,
0x292: 0x0024, 0x293: 0x0024, 0x294: 0x0024, 0x295: 0x0024, 0x296: 0x0034, 0x297: 0x0024,
0x298: 0x0024, 0x299: 0x0024, 0x29a: 0x0034, 0x29b: 0x0034, 0x29c: 0x0024, 0x29d: 0x0024,
0x29e: 0x0024, 0x29f: 0x0024, 0x2a0: 0x0024, 0x2a1: 0x0024, 0x2a2: 0x0034, 0x2a3: 0x0034,
0x2a4: 0x0034, 0x2a5: 0x0034, 0x2a6: 0x0034, 0x2a7: 0x0034, 0x2a8: 0x0024, 0x2a9: 0x0024,
0x2aa: 0x0034, 0x2ab: 0x0024, 0x2ac: 0x0024, 0x2ad: 0x0034, 0x2ae: 0x0034, 0x2af: 0x0024,
0x2b0: 0x0034, 0x2b1: 0x0034, 0x2b2: 0x0034, 0x2b3: 0x0034, 0x2b4: 0x0034, 0x2b5: 0x0034,
0x2b6: 0x0034, 0x2b7: 0x0034, 0x2b8: 0x0034, 0x2b9: 0x0034, 0x2ba: 0x0034, 0x2bb: 0x0034,
0x2bc: 0x0034, 0x2bd: 0x0034, 0x2bf: 0x0034,
// Block 0xb, offset 0x2c0
0x2c0: 0x0010, 0x2c1: 0x0010, 0x2c2: 0x0010, 0x2c3: 0x0010, 0x2c4: 0x0010, 0x2c5: 0x0010,
0x2c6: 0x0010, 0x2c7: 0x0010, 0x2c8: 0x0010, 0x2c9: 0x0014, 0x2ca: 0x0024, 0x2cb: 0x0024,
0x2cc: 0x0024, 0x2cd: 0x0024, 0x2ce: 0x0024, 0x2cf: 0x0034, 0x2d0: 0x0034, 0x2d1: 0x0034,
0x2d2: 0x0034, 0x2d3: 0x0034, 0x2d4: 0x0024, 0x2d5: 0x0024, 0x2d6: 0x0024, 0x2d7: 0x0024,
0x2d8: 0x0024, 0x2d9: 0x0024, 0x2da: 0x0024, 0x2db: 0x0024, 0x2dc: 0x0024, 0x2dd: 0x0024,
0x2de: 0x0024, 0x2df: 0x0024, 0x2e0: 0x0024, 0x2e1: 0x0024, 0x2e2: 0x0014, 0x2e3: 0x0034,
0x2e4: 0x0024, 0x2e5: 0x0024, 0x2e6: 0x0034, 0x2e7: 0x0024, 0x2e8: 0x0024, 0x2e9: 0x0034,
0x2ea: 0x0024, 0x2eb: 0x0024, 0x2ec: 0x0024, 0x2ed: 0x0034, 0x2ee: 0x0034, 0x2ef: 0x0034,
0x2f0: 0x0034, 0x2f1: 0x0034, 0x2f2: 0x0034, 0x2f3: 0x0024, 0x2f4: 0x0024, 0x2f5: 0x0024,
0x2f6: 0x0034, 0x2f7: 0x0024, 0x2f8: 0x0024, 0x2f9: 0x0034, 0x2fa: 0x0034, 0x2fb: 0x0024,
0x2fc: 0x0024, 0x2fd: 0x0024, 0x2fe: 0x0024, 0x2ff: 0x0024,
// Block 0xc, offset 0x300
0x300: 0x7053, 0x301: 0x7053, 0x302: 0x7053, 0x303: 0x7053, 0x304: 0x7053, 0x305: 0x7053,
0x307: 0x7053,
0x30d: 0x7053, 0x310: 0x1aea, 0x311: 0x1b6a,
0x312: 0x1bea, 0x313: 0x1c6a, 0x314: 0x1cea, 0x315: 0x1d6a, 0x316: 0x1dea, 0x317: 0x1e6a,
0x318: 0x1eea, 0x319: 0x1f6a, 0x31a: 0x1fea, 0x31b: 0x206a, 0x31c: 0x20ea, 0x31d: 0x216a,
0x31e: 0x21ea, 0x31f: 0x226a, 0x320: 0x22ea, 0x321: 0x236a, 0x322: 0x23ea, 0x323: 0x246a,
0x324: 0x24ea, 0x325: 0x256a, 0x326: 0x25ea, 0x327: 0x266a, 0x328: 0x26ea, 0x329: 0x276a,
0x32a: 0x27ea, 0x32b: 0x286a, 0x32c: 0x28ea, 0x32d: 0x296a, 0x32e: 0x29ea, 0x32f: 0x2a6a,
0x330: 0x2aea, 0x331: 0x2b6a, 0x332: 0x2bea, 0x333: 0x2c6a, 0x334: 0x2cea, 0x335: 0x2d6a,
0x336: 0x2dea, 0x337: 0x2e6a, 0x338: 0x2eea, 0x339: 0x2f6a, 0x33a: 0x2fea,
0x33c: 0x0015, 0x33d: 0x306a, 0x33e: 0x30ea, 0x33f: 0x316a,
// Block 0xd, offset 0x340
0x340: 0x0812, 0x341: 0x0812, 0x342: 0x0812, 0x343: 0x0812, 0x344: 0x0812, 0x345: 0x0812,
0x348: 0x0813, 0x349: 0x0813, 0x34a: 0x0813, 0x34b: 0x0813,
0x34c: 0x0813, 0x34d: 0x0813, 0x350: 0x3b1a, 0x351: 0x0812,
0x352: 0x3bfa, 0x353: 0x0812, 0x354: 0x3d3a, 0x355: 0x0812, 0x356: 0x3e7a, 0x357: 0x0812,
0x359: 0x0813, 0x35b: 0x0813, 0x35d: 0x0813,
0x35f: 0x0813, 0x360: 0x0812, 0x361: 0x0812, 0x362: 0x0812, 0x363: 0x0812,
0x364: 0x0812, 0x365: 0x0812, 0x366: 0x0812, 0x367: 0x0812, 0x368: 0x0813, 0x369: 0x0813,
0x36a: 0x0813, 0x36b: 0x0813, 0x36c: 0x0813, 0x36d: 0x0813, 0x36e: 0x0813, 0x36f: 0x0813,
0x370: 0x9252, 0x371: 0x9252, 0x372: 0x9552, 0x373: 0x9552, 0x374: 0x9852, 0x375: 0x9852,
0x376: 0x9b52, 0x377: 0x9b52, 0x378: 0x9e52, 0x379: 0x9e52, 0x37a: 0xa152, 0x37b: 0xa152,
0x37c: 0x4d52, 0x37d: 0x4d52,
// Block 0xe, offset 0x380
0x380: 0x3fba, 0x381: 0x40aa, 0x382: 0x419a, 0x383: 0x428a, 0x384: 0x437a, 0x385: 0x446a,
0x386: 0x455a, 0x387: 0x464a, 0x388: 0x4739, 0x389: 0x4829, 0x38a: 0x4919, 0x38b: 0x4a09,
0x38c: 0x4af9, 0x38d: 0x4be9, 0x38e: 0x4cd9, 0x38f: 0x4dc9, 0x390: 0x4eba, 0x391: 0x4faa,
0x392: 0x509a, 0x393: 0x518a, 0x394: 0x527a, 0x395: 0x536a, 0x396: 0x545a, 0x397: 0x554a,
0x398: 0x5639, 0x399: 0x5729, 0x39a: 0x5819, 0x39b: 0x5909, 0x39c: 0x59f9, 0x39d: 0x5ae9,
0x39e: 0x5bd9, 0x39f: 0x5cc9, 0x3a0: 0x5dba, 0x3a1: 0x5eaa, 0x3a2: 0x5f9a, 0x3a3: 0x608a,
0x3a4: 0x617a, 0x3a5: 0x626a, 0x3a6: 0x635a, 0x3a7: 0x644a, 0x3a8: 0x6539, 0x3a9: 0x6629,
0x3aa: 0x6719, 0x3ab: 0x6809, 0x3ac: 0x68f9, 0x3ad: 0x69e9, 0x3ae: 0x6ad9, 0x3af: 0x6bc9,
0x3b0: 0x0812, 0x3b1: 0x0812, 0x3b2: 0x6cba, 0x3b3: 0x6dca, 0x3b4: 0x6e9a,
0x3b6: 0x6f7a, 0x3b7: 0x705a, 0x3b8: 0x0813, 0x3b9: 0x0813, 0x3ba: 0x9253, 0x3bb: 0x9253,
0x3bc: 0x7199, 0x3bd: 0x0004, 0x3be: 0x726a, 0x3bf: 0x0004,
// Block 0xf, offset 0x3c0
0x3c0: 0x0004, 0x3c1: 0x0004, 0x3c2: 0x72ea, 0x3c3: 0x73fa, 0x3c4: 0x74ca,
0x3c6: 0x75aa, 0x3c7: 0x768a, 0x3c8: 0x9553, 0x3c9: 0x9553, 0x3ca: 0x9853, 0x3cb: 0x9853,
0x3cc: 0x77c9, 0x3cd: 0x0004, 0x3ce: 0x0004, 0x3cf: 0x0004, 0x3d0: 0x0812, 0x3d1: 0x0812,
0x3d2: 0x789a, 0x3d3: 0x79da, 0x3d6: 0x7b1a, 0x3d7: 0x7bfa,
0x3d8: 0x0813, 0x3d9: 0x0813, 0x3da: 0x9b53, 0x3db: 0x9b53, 0x3dd: 0x0004,
0x3de: 0x0004, 0x3df: 0x0004, 0x3e0: 0x0812, 0x3e1: 0x0812, 0x3e2: 0x7d3a, 0x3e3: 0x7e7a,
0x3e4: 0x7fba, 0x3e5: 0x0912, 0x3e6: 0x809a, 0x3e7: 0x817a, 0x3e8: 0x0813, 0x3e9: 0x0813,
0x3ea: 0xa153, 0x3eb: 0xa153, 0x3ec: 0x0913, 0x3ed: 0x0004, 0x3ee: 0x0004, 0x3ef: 0x0004,
0x3f2: 0x82ba, 0x3f3: 0x83ca, 0x3f4: 0x849a,
0x3f6: 0x857a, 0x3f7: 0x865a, 0x3f8: 0x9e53, 0x3f9: 0x9e53, 0x3fa: 0x4d53, 0x3fb: 0x4d53,
0x3fc: 0x8799, 0x3fd: 0x0004, 0x3fe: 0x0004,
// Block 0x10, offset 0x400
0x402: 0x0013,
0x407: 0x0013, 0x40a: 0x0012, 0x40b: 0x0013,
0x40c: 0x0013, 0x40d: 0x0013, 0x40e: 0x0012, 0x40f: 0x0012, 0x410: 0x0013, 0x411: 0x0013,
0x412: 0x0013, 0x413: 0x0012, 0x415: 0x0013,
0x419: 0x0013, 0x41a: 0x0013, 0x41b: 0x0013, 0x41c: 0x0013, 0x41d: 0x0013,
0x424: 0x0013, 0x426: 0x886b, 0x428: 0x0013,
0x42a: 0x88cb, 0x42b: 0x890b, 0x42c: 0x0013, 0x42d: 0x0013, 0x42f: 0x0012,
0x430: 0x0013, 0x431: 0x0013, 0x432: 0xa453, 0x433: 0x0013, 0x434: 0x0012, 0x435: 0x0010,
0x436: 0x0010, 0x437: 0x0010, 0x438: 0x0010, 0x439: 0x0012,
0x43c: 0x0012, 0x43d: 0x0012, 0x43e: 0x0013, 0x43f: 0x0013,
// Block 0x11, offset 0x440
0x440: 0x1a13, 0x441: 0x1a13, 0x442: 0x1e13, 0x443: 0x1e13, 0x444: 0x1a13, 0x445: 0x1a13,
0x446: 0x2613, 0x447: 0x2613, 0x448: 0x2a13, 0x449: 0x2a13, 0x44a: 0x2e13, 0x44b: 0x2e13,
0x44c: 0x2a13, 0x44d: 0x2a13, 0x44e: 0x2613, 0x44f: 0x2613, 0x450: 0xa752, 0x451: 0xa752,
0x452: 0xaa52, 0x453: 0xaa52, 0x454: 0xad52, 0x455: 0xad52, 0x456: 0xaa52, 0x457: 0xaa52,
0x458: 0xa752, 0x459: 0xa752, 0x45a: 0x1a12, 0x45b: 0x1a12, 0x45c: 0x1e12, 0x45d: 0x1e12,
0x45e: 0x1a12, 0x45f: 0x1a12, 0x460: 0x2612, 0x461: 0x2612, 0x462: 0x2a12, 0x463: 0x2a12,
0x464: 0x2e12, 0x465: 0x2e12, 0x466: 0x2a12, 0x467: 0x2a12, 0x468: 0x2612, 0x469: 0x2612,
// Block 0x12, offset 0x480
0x480: 0x6552, 0x481: 0x6552, 0x482: 0x6552, 0x483: 0x6552, 0x484: 0x6552, 0x485: 0x6552,
0x486: 0x6552, 0x487: 0x6552, 0x488: 0x6552, 0x489: 0x6552, 0x48a: 0x6552, 0x48b: 0x6552,
0x48c: 0x6552, 0x48d: 0x6552, 0x48e: 0x6552, 0x48f: 0x6552, 0x490: 0xb052, 0x491: 0xb052,
0x492: 0xb052, 0x493: 0xb052, 0x494: 0xb052, 0x495: 0xb052, 0x496: 0xb052, 0x497: 0xb052,
0x498: 0xb052, 0x499: 0xb052, 0x49a: 0xb052, 0x49b: 0xb052, 0x49c: 0xb052, 0x49d: 0xb052,
0x49e: 0xb052, 0x49f: 0xb052, 0x4a0: 0x0113, 0x4a1: 0x0112, 0x4a2: 0x896b, 0x4a3: 0x8b53,
0x4a4: 0x89cb, 0x4a5: 0x8a2a, 0x4a6: 0x8a8a, 0x4a7: 0x0f13, 0x4a8: 0x0f12, 0x4a9: 0x0313,
0x4aa: 0x0312, 0x4ab: 0x0713, 0x4ac: 0x0712, 0x4ad: 0x8aeb, 0x4ae: 0x8b4b, 0x4af: 0x8bab,
0x4b0: 0x8c0b, 0x4b1: 0x0012, 0x4b2: 0x0113, 0x4b3: 0x0112, 0x4b4: 0x0012, 0x4b5: 0x0313,
0x4b6: 0x0312, 0x4b7: 0x0012, 0x4b8: 0x0012, 0x4b9: 0x0012, 0x4ba: 0x0012, 0x4bb: 0x0012,
0x4bc: 0x0015, 0x4bd: 0x0015, 0x4be: 0x8c6b, 0x4bf: 0x8ccb,
// Block 0x13, offset 0x4c0
0x4c0: 0x0113, 0x4c1: 0x0112, 0x4c2: 0x0113, 0x4c3: 0x0112, 0x4c4: 0x0113, 0x4c5: 0x0112,
0x4c6: 0x0113, 0x4c7: 0x0112, 0x4c8: 0x0014, 0x4c9: 0x0014, 0x4ca: 0x0014, 0x4cb: 0x0713,
0x4cc: 0x0712, 0x4cd: 0x8d2b, 0x4ce: 0x0012, 0x4cf: 0x0010, 0x4d0: 0x0113, 0x4d1: 0x0112,
0x4d2: 0x0113, 0x4d3: 0x0112, 0x4d4: 0x6552, 0x4d5: 0x0012, 0x4d6: 0x0113, 0x4d7: 0x0112,
0x4d8: 0x0113, 0x4d9: 0x0112, 0x4da: 0x0113, 0x4db: 0x0112, 0x4dc: 0x0113, 0x4dd: 0x0112,
0x4de: 0x0113, 0x4df: 0x0112, 0x4e0: 0x0113, 0x4e1: 0x0112, 0x4e2: 0x0113, 0x4e3: 0x0112,
0x4e4: 0x0113, 0x4e5: 0x0112, 0x4e6: 0x0113, 0x4e7: 0x0112, 0x4e8: 0x0113, 0x4e9: 0x0112,
0x4ea: 0x8d8b, 0x4eb: 0x8deb, 0x4ec: 0x8e4b, 0x4ed: 0x8eab, 0x4ee: 0x8f0b, 0x4ef: 0x0012,
0x4f0: 0x8f6b, 0x4f1: 0x8fcb, 0x4f2: 0x902b, 0x4f3: 0xb353, 0x4f4: 0x0113, 0x4f5: 0x0112,
0x4f6: 0x0113, 0x4f7: 0x0112, 0x4f8: 0x0113, 0x4f9: 0x0112, 0x4fa: 0x0113, 0x4fb: 0x0112,
0x4fc: 0x0113, 0x4fd: 0x0112, 0x4fe: 0x0113, 0x4ff: 0x0112,
// Block 0x14, offset 0x500
0x500: 0x90ea, 0x501: 0x916a, 0x502: 0x91ea, 0x503: 0x926a, 0x504: 0x931a, 0x505: 0x93ca,
0x506: 0x944a,
0x513: 0x94ca, 0x514: 0x95aa, 0x515: 0x968a, 0x516: 0x976a, 0x517: 0x984a,
0x51d: 0x0010,
0x51e: 0x0034, 0x51f: 0x0010, 0x520: 0x0010, 0x521: 0x0010, 0x522: 0x0010, 0x523: 0x0010,
0x524: 0x0010, 0x525: 0x0010, 0x526: 0x0010, 0x527: 0x0010, 0x528: 0x0010,
0x52a: 0x0010, 0x52b: 0x0010, 0x52c: 0x0010, 0x52d: 0x0010, 0x52e: 0x0010, 0x52f: 0x0010,
0x530: 0x0010, 0x531: 0x0010, 0x532: 0x0010, 0x533: 0x0010, 0x534: 0x0010, 0x535: 0x0010,
0x536: 0x0010, 0x538: 0x0010, 0x539: 0x0010, 0x53a: 0x0010, 0x53b: 0x0010,
0x53c: 0x0010, 0x53e: 0x0010,
// Block 0x15, offset 0x540
0x540: 0x2713, 0x541: 0x2913, 0x542: 0x2b13, 0x543: 0x2913, 0x544: 0x2f13, 0x545: 0x2913,
0x546: 0x2b13, 0x547: 0x2913, 0x548: 0x2713, 0x549: 0x3913, 0x54a: 0x3b13,
0x54c: 0x3f13, 0x54d: 0x3913, 0x54e: 0x3b13, 0x54f: 0x3913, 0x550: 0x2713, 0x551: 0x2913,
0x552: 0x2b13, 0x554: 0x2f13, 0x555: 0x2913, 0x557: 0xbc52,
0x558: 0xbf52, 0x559: 0xc252, 0x55a: 0xbf52, 0x55b: 0xc552, 0x55c: 0xbf52, 0x55d: 0xc252,
0x55e: 0xbf52, 0x55f: 0xbc52, 0x560: 0xc852, 0x561: 0xcb52, 0x563: 0xce52,
0x564: 0xc852, 0x565: 0xcb52, 0x566: 0xc852, 0x567: 0x2712, 0x568: 0x2912, 0x569: 0x2b12,
0x56a: 0x2912, 0x56b: 0x2f12, 0x56c: 0x2912, 0x56d: 0x2b12, 0x56e: 0x2912, 0x56f: 0x2712,
0x570: 0x3912, 0x571: 0x3b12, 0x573: 0x3f12, 0x574: 0x3912, 0x575: 0x3b12,
0x576: 0x3912, 0x577: 0x2712, 0x578: 0x2912, 0x579: 0x2b12, 0x57b: 0x2f12,
0x57c: 0x2912,
// Block 0x16, offset 0x580
0x580: 0x2213, 0x581: 0x2213, 0x582: 0x2613, 0x583: 0x2613, 0x584: 0x2213, 0x585: 0x2213,
0x586: 0x2e13, 0x587: 0x2e13, 0x588: 0x2213, 0x589: 0x2213, 0x58a: 0x2613, 0x58b: 0x2613,
0x58c: 0x2213, 0x58d: 0x2213, 0x58e: 0x3e13, 0x58f: 0x3e13, 0x590: 0x2213, 0x591: 0x2213,
0x592: 0x2613, 0x593: 0x2613, 0x594: 0x2213, 0x595: 0x2213, 0x596: 0x2e13, 0x597: 0x2e13,
0x598: 0x2213, 0x599: 0x2213, 0x59a: 0x2613, 0x59b: 0x2613, 0x59c: 0x2213, 0x59d: 0x2213,
0x59e: 0xd153, 0x59f: 0xd153, 0x5a0: 0xd453, 0x5a1: 0xd453, 0x5a2: 0x2212, 0x5a3: 0x2212,
0x5a4: 0x2612, 0x5a5: 0x2612, 0x5a6: 0x2212, 0x5a7: 0x2212, 0x5a8: 0x2e12, 0x5a9: 0x2e12,
0x5aa: 0x2212, 0x5ab: 0x2212, 0x5ac: 0x2612, 0x5ad: 0x2612, 0x5ae: 0x2212, 0x5af: 0x2212,
0x5b0: 0x3e12, 0x5b1: 0x3e12, 0x5b2: 0x2212, 0x5b3: 0x2212, 0x5b4: 0x2612, 0x5b5: 0x2612,
0x5b6: 0x2212, 0x5b7: 0x2212, 0x5b8: 0x2e12, 0x5b9: 0x2e12, 0x5ba: 0x2212, 0x5bb: 0x2212,
0x5bc: 0x2612, 0x5bd: 0x2612, 0x5be: 0x2212, 0x5bf: 0x2212,
// Block 0x17, offset 0x5c0
0x5c2: 0x0010,
0x5c7: 0x0010, 0x5c9: 0x0010, 0x5cb: 0x0010,
0x5cd: 0x0010, 0x5ce: 0x0010, 0x5cf: 0x0010, 0x5d1: 0x0010,
0x5d2: 0x0010, 0x5d4: 0x0010, 0x5d7: 0x0010,
0x5d9: 0x0010, 0x5db: 0x0010, 0x5dd: 0x0010,
0x5df: 0x0010, 0x5e1: 0x0010, 0x5e2: 0x0010,
0x5e4: 0x0010, 0x5e7: 0x0010, 0x5e8: 0x0010, 0x5e9: 0x0010,
0x5ea: 0x0010, 0x5ec: 0x0010, 0x5ed: 0x0010, 0x5ee: 0x0010, 0x5ef: 0x0010,
0x5f0: 0x0010, 0x5f1: 0x0010, 0x5f2: 0x0010, 0x5f4: 0x0010, 0x5f5: 0x0010,
0x5f6: 0x0010, 0x5f7: 0x0010, 0x5f9: 0x0010, 0x5fa: 0x0010, 0x5fb: 0x0010,
0x5fc: 0x0010, 0x5fe: 0x0010,
}
// caseIndex: 27 blocks, 1728 entries, 3456 bytes
// Block 0 is the zero block.
var caseIndex = [1728]uint16{
// Block 0x0, offset 0x0
// Block 0x1, offset 0x40
// Block 0x2, offset 0x80
// Block 0x3, offset 0xc0
0xc2: 0x16, 0xc3: 0x17, 0xc4: 0x18, 0xc5: 0x19, 0xc6: 0x01, 0xc7: 0x02,
0xc8: 0x1a, 0xc9: 0x03, 0xca: 0x04, 0xcb: 0x1b, 0xcc: 0x1c, 0xcd: 0x05, 0xce: 0x06, 0xcf: 0x07,
0xd0: 0x1d, 0xd1: 0x1e, 0xd2: 0x1f, 0xd3: 0x20, 0xd4: 0x21, 0xd5: 0x22, 0xd6: 0x08, 0xd7: 0x23,
0xd8: 0x24, 0xd9: 0x25, 0xda: 0x26, 0xdb: 0x27, 0xdc: 0x28, 0xdd: 0x29, 0xde: 0x2a, 0xdf: 0x2b,
0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05,
0xea: 0x06, 0xeb: 0x07, 0xec: 0x07, 0xed: 0x08, 0xef: 0x09,
0xf0: 0x16, 0xf3: 0x18,
// Block 0x4, offset 0x100
0x120: 0x2c, 0x121: 0x2d, 0x122: 0x2e, 0x123: 0x09, 0x124: 0x2f, 0x125: 0x30, 0x126: 0x31, 0x127: 0x32,
0x128: 0x33, 0x129: 0x34, 0x12a: 0x35, 0x12b: 0x36, 0x12c: 0x37, 0x12d: 0x38, 0x12e: 0x39, 0x12f: 0x3a,
0x130: 0x3b, 0x131: 0x3c, 0x132: 0x3d, 0x133: 0x3e, 0x134: 0x3f, 0x135: 0x40, 0x136: 0x41, 0x137: 0x42,
0x138: 0x43, 0x139: 0x44, 0x13a: 0x45, 0x13b: 0x46, 0x13c: 0x47, 0x13d: 0x48, 0x13e: 0x49, 0x13f: 0x4a,
// Block 0x5, offset 0x140
0x140: 0x4b, 0x141: 0x4c, 0x142: 0x4d, 0x143: 0x0a, 0x144: 0x26, 0x145: 0x26, 0x146: 0x26, 0x147: 0x26,
0x148: 0x26, 0x149: 0x4e, 0x14a: 0x4f, 0x14b: 0x50, 0x14c: 0x51, 0x14d: 0x52, 0x14e: 0x53, 0x14f: 0x54,
0x150: 0x55, 0x151: 0x26, 0x152: 0x26, 0x153: 0x26, 0x154: 0x26, 0x155: 0x26, 0x156: 0x26, 0x157: 0x26,
0x158: 0x26, 0x159: 0x56, 0x15a: 0x57, 0x15b: 0x58, 0x15c: 0x59, 0x15d: 0x5a, 0x15e: 0x5b, 0x15f: 0x5c,
0x160: 0x5d, 0x161: 0x5e, 0x162: 0x5f, 0x163: 0x60, 0x164: 0x61, 0x165: 0x62, 0x167: 0x63,
0x168: 0x64, 0x169: 0x65, 0x16a: 0x66, 0x16b: 0x67, 0x16c: 0x68, 0x16d: 0x69, 0x16e: 0x6a, 0x16f: 0x6b,
0x170: 0x6c, 0x171: 0x6d, 0x172: 0x6e, 0x173: 0x6f, 0x174: 0x70, 0x175: 0x71, 0x176: 0x72, 0x177: 0x73,
0x178: 0x74, 0x179: 0x74, 0x17a: 0x75, 0x17b: 0x74, 0x17c: 0x76, 0x17d: 0x0b, 0x17e: 0x0c, 0x17f: 0x0d,
// Block 0x6, offset 0x180
0x180: 0x77, 0x181: 0x78, 0x182: 0x79, 0x183: 0x7a, 0x184: 0x0e, 0x185: 0x7b, 0x186: 0x7c,
0x192: 0x7d, 0x193: 0x0f,
0x1b0: 0x7e, 0x1b1: 0x10, 0x1b2: 0x74, 0x1b3: 0x7f, 0x1b4: 0x80, 0x1b5: 0x81, 0x1b6: 0x82, 0x1b7: 0x83,
0x1b8: 0x84,
// Block 0x7, offset 0x1c0
0x1c0: 0x85, 0x1c2: 0x86, 0x1c3: 0x87, 0x1c4: 0x88, 0x1c5: 0x26, 0x1c6: 0x89,
// Block 0x8, offset 0x200
0x200: 0x8a, 0x201: 0x26, 0x202: 0x26, 0x203: 0x26, 0x204: 0x26, 0x205: 0x26, 0x206: 0x26, 0x207: 0x26,
0x208: 0x26, 0x209: 0x26, 0x20a: 0x26, 0x20b: 0x26, 0x20c: 0x26, 0x20d: 0x26, 0x20e: 0x26, 0x20f: 0x26,
0x210: 0x26, 0x211: 0x26, 0x212: 0x8b, 0x213: 0x8c, 0x214: 0x26, 0x215: 0x26, 0x216: 0x26, 0x217: 0x26,
0x218: 0x8d, 0x219: 0x8e, 0x21a: 0x8f, 0x21b: 0x90, 0x21c: 0x91, 0x21d: 0x92, 0x21e: 0x11, 0x21f: 0x93,
0x220: 0x94, 0x221: 0x95, 0x222: 0x26, 0x223: 0x96, 0x224: 0x97, 0x225: 0x98, 0x226: 0x99, 0x227: 0x9a,
0x228: 0x9b, 0x229: 0x9c, 0x22a: 0x9d, 0x22b: 0x9e, 0x22c: 0x9f, 0x22d: 0xa0, 0x22e: 0xa1, 0x22f: 0xa2,
0x230: 0x26, 0x231: 0x26, 0x232: 0x26, 0x233: 0x26, 0x234: 0x26, 0x235: 0x26, 0x236: 0x26, 0x237: 0x26,
0x238: 0x26, 0x239: 0x26, 0x23a: 0x26, 0x23b: 0x26, 0x23c: 0x26, 0x23d: 0x26, 0x23e: 0x26, 0x23f: 0x26,
// Block 0x9, offset 0x240
0x240: 0x26, 0x241: 0x26, 0x242: 0x26, 0x243: 0x26, 0x244: 0x26, 0x245: 0x26, 0x246: 0x26, 0x247: 0x26,
0x248: 0x26, 0x249: 0x26, 0x24a: 0x26, 0x24b: 0x26, 0x24c: 0x26, 0x24d: 0x26, 0x24e: 0x26, 0x24f: 0x26,
0x250: 0x26, 0x251: 0x26, 0x252: 0x26, 0x253: 0x26, 0x254: 0x26, 0x255: 0x26, 0x256: 0x26, 0x257: 0x26,
0x258: 0x26, 0x259: 0x26, 0x25a: 0x26, 0x25b: 0x26, 0x25c: 0x26, 0x25d: 0x26, 0x25e: 0x26, 0x25f: 0x26,
0x260: 0x26, 0x261: 0x26, 0x262: 0x26, 0x263: 0x26, 0x264: 0x26, 0x265: 0x26, 0x266: 0x26, 0x267: 0x26,
0x268: 0x26, 0x269: 0x26, 0x26a: 0x26, 0x26b: 0x26, 0x26c: 0x26, 0x26d: 0x26, 0x26e: 0x26, 0x26f: 0x26,
0x270: 0x26, 0x271: 0x26, 0x272: 0x26, 0x273: 0x26, 0x274: 0x26, 0x275: 0x26, 0x276: 0x26, 0x277: 0x26,
0x278: 0x26, 0x279: 0x26, 0x27a: 0x26, 0x27b: 0x26, 0x27c: 0x26, 0x27d: 0x26, 0x27e: 0x26, 0x27f: 0x26,
// Block 0xa, offset 0x280
0x280: 0x26, 0x281: 0x26, 0x282: 0x26, 0x283: 0x26, 0x284: 0x26, 0x285: 0x26, 0x286: 0x26, 0x287: 0x26,
0x288: 0x26, 0x289: 0x26, 0x28a: 0x26, 0x28b: 0x26, 0x28c: 0x26, 0x28d: 0x26, 0x28e: 0x26, 0x28f: 0x26,
0x290: 0x26, 0x291: 0x26, 0x292: 0x26, 0x293: 0x26, 0x294: 0x26, 0x295: 0x26, 0x296: 0x26, 0x297: 0x26,
0x298: 0x26, 0x299: 0x26, 0x29a: 0x26, 0x29b: 0x26, 0x29c: 0x26, 0x29d: 0x26, 0x29e: 0xa3, 0x29f: 0xa4,
// Block 0xb, offset 0x2c0
0x2ec: 0x12, 0x2ed: 0xa5, 0x2ee: 0xa6, 0x2ef: 0xa7,
0x2f0: 0x26, 0x2f1: 0x26, 0x2f2: 0x26, 0x2f3: 0x26, 0x2f4: 0xa8, 0x2f5: 0xa9, 0x2f6: 0xaa, 0x2f7: 0xab,
0x2f8: 0xac, 0x2f9: 0xad, 0x2fa: 0x26, 0x2fb: 0xae, 0x2fc: 0xaf, 0x2fd: 0xb0, 0x2fe: 0xb1, 0x2ff: 0xb2,
// Block 0xc, offset 0x300
0x300: 0xb3, 0x301: 0xb4, 0x302: 0x26, 0x303: 0xb5, 0x305: 0xb6, 0x307: 0xb7,
0x30a: 0xb8, 0x30b: 0xb9, 0x30c: 0xba, 0x30d: 0xbb, 0x30e: 0xbc, 0x30f: 0xbd,
0x310: 0xbe, 0x311: 0xbf, 0x312: 0xc0, 0x313: 0xc1, 0x314: 0xc2, 0x315: 0xc3, 0x316: 0x13,
0x318: 0x26, 0x319: 0x26, 0x31a: 0x26, 0x31b: 0x26, 0x31c: 0xc4, 0x31d: 0xc5, 0x31e: 0xc6,
0x320: 0xc7, 0x321: 0xc8, 0x322: 0xc9, 0x323: 0xca, 0x324: 0xcb, 0x326: 0xcc,
0x328: 0xcd, 0x329: 0xce, 0x32a: 0xcf, 0x32b: 0xd0, 0x32c: 0x60, 0x32d: 0xd1, 0x32e: 0xd2,
0x330: 0x26, 0x331: 0xd3, 0x332: 0xd4, 0x333: 0xd5, 0x334: 0xd6,
0x33a: 0xd7, 0x33b: 0xd8, 0x33c: 0xd9, 0x33d: 0xda, 0x33e: 0xdb, 0x33f: 0xdc,
// Block 0xd, offset 0x340
0x340: 0xdd, 0x341: 0xde, 0x342: 0xdf, 0x343: 0xe0, 0x344: 0xe1, 0x345: 0xe2, 0x346: 0xe3, 0x347: 0xe4,
0x348: 0xe5, 0x349: 0xe6, 0x34a: 0xe7, 0x34b: 0xe8, 0x34c: 0xe9, 0x34d: 0xea,
0x350: 0xeb, 0x351: 0xec, 0x352: 0xed, 0x353: 0xee, 0x356: 0xef, 0x357: 0xf0,
0x358: 0xf1, 0x359: 0xf2, 0x35a: 0xf3, 0x35b: 0xf4, 0x35c: 0xf5,
0x360: 0xf6, 0x362: 0xf7, 0x363: 0xf8, 0x364: 0xf9, 0x365: 0xfa, 0x366: 0xfb, 0x367: 0xfc,
0x368: 0xfd, 0x369: 0xfe, 0x36a: 0xff, 0x36b: 0x100,
0x370: 0x101, 0x371: 0x102, 0x372: 0x103, 0x374: 0x104, 0x375: 0x105, 0x376: 0x106,
0x37b: 0x107, 0x37c: 0x108, 0x37d: 0x109, 0x37e: 0x10a,
// Block 0xe, offset 0x380
0x380: 0x26, 0x381: 0x26, 0x382: 0x26, 0x383: 0x26, 0x384: 0x26, 0x385: 0x26, 0x386: 0x26, 0x387: 0x26,
0x388: 0x26, 0x389: 0x26, 0x38a: 0x26, 0x38b: 0x26, 0x38c: 0x26, 0x38d: 0x26, 0x38e: 0x10b,
0x390: 0x26, 0x391: 0x10c, 0x392: 0x26, 0x393: 0x26, 0x394: 0x26, 0x395: 0x10d,
0x3be: 0xa9, 0x3bf: 0x10e,
// Block 0xf, offset 0x3c0
0x3c0: 0x26, 0x3c1: 0x26, 0x3c2: 0x26, 0x3c3: 0x26, 0x3c4: 0x26, 0x3c5: 0x26, 0x3c6: 0x26, 0x3c7: 0x26,
0x3c8: 0x26, 0x3c9: 0x26, 0x3ca: 0x26, 0x3cb: 0x26, 0x3cc: 0x26, 0x3cd: 0x26, 0x3ce: 0x26, 0x3cf: 0x26,
0x3d0: 0x10f, 0x3d1: 0x110,
// Block 0x10, offset 0x400
0x410: 0x26, 0x411: 0x26, 0x412: 0x26, 0x413: 0x26, 0x414: 0x26, 0x415: 0x26, 0x416: 0x26, 0x417: 0x26,
0x418: 0x26, 0x419: 0x111,
// Block 0x11, offset 0x440
0x460: 0x26, 0x461: 0x26, 0x462: 0x26, 0x463: 0x26, 0x464: 0x26, 0x465: 0x26, 0x466: 0x26, 0x467: 0x26,
0x468: 0x100, 0x469: 0x112, 0x46a: 0x113, 0x46b: 0x114, 0x46c: 0x115, 0x46d: 0x116, 0x46e: 0x117,
0x479: 0x118, 0x47c: 0x26, 0x47d: 0x119, 0x47e: 0x11a, 0x47f: 0x11b,
// Block 0x12, offset 0x480
0x4bf: 0x11c,
// Block 0x13, offset 0x4c0
0x4f0: 0x26, 0x4f1: 0x11d, 0x4f2: 0x11e,
// Block 0x14, offset 0x500
0x53c: 0x11f, 0x53d: 0x120,
// Block 0x15, offset 0x540
0x545: 0x121, 0x546: 0x122,
0x549: 0x123,
0x550: 0x124, 0x551: 0x125, 0x552: 0x126, 0x553: 0x127, 0x554: 0x128, 0x555: 0x129, 0x556: 0x12a, 0x557: 0x12b,
0x558: 0x12c, 0x559: 0x12d, 0x55a: 0x12e, 0x55b: 0x12f, 0x55c: 0x130, 0x55d: 0x131, 0x55e: 0x132, 0x55f: 0x133,
0x568: 0x134, 0x569: 0x135, 0x56a: 0x136,
0x57c: 0x137,
// Block 0x16, offset 0x580
0x580: 0x138, 0x581: 0x139, 0x582: 0x13a, 0x584: 0x13b, 0x585: 0x13c,
0x58a: 0x13d, 0x58b: 0x13e,
0x593: 0x13f,
0x59f: 0x140,
0x5a0: 0x26, 0x5a1: 0x26, 0x5a2: 0x26, 0x5a3: 0x141, 0x5a4: 0x14, 0x5a5: 0x142,
0x5b8: 0x143, 0x5b9: 0x15, 0x5ba: 0x144,
// Block 0x17, offset 0x5c0
0x5c4: 0x145, 0x5c5: 0x146, 0x5c6: 0x147,
0x5cf: 0x148,
0x5ef: 0x149,
// Block 0x18, offset 0x600
0x610: 0x0a, 0x611: 0x0b, 0x612: 0x0c, 0x613: 0x0d, 0x614: 0x0e, 0x616: 0x0f,
0x61a: 0x10, 0x61b: 0x11, 0x61c: 0x12, 0x61d: 0x13, 0x61e: 0x14, 0x61f: 0x15,
// Block 0x19, offset 0x640
0x640: 0x14a, 0x641: 0x14b, 0x644: 0x14b, 0x645: 0x14b, 0x646: 0x14b, 0x647: 0x14c,
// Block 0x1a, offset 0x680
0x6a0: 0x17,
}
// sparseOffsets: 312 entries, 624 bytes
var sparseOffsets = []uint16{0x0, 0x9, 0xf, 0x18, 0x24, 0x2e, 0x34, 0x37, 0x3b, 0x3e, 0x42, 0x4c, 0x4e, 0x57, 0x5e, 0x63, 0x71, 0x72, 0x80, 0x8f, 0x99, 0x9c, 0xa3, 0xab, 0xaf, 0xb7, 0xbd, 0xcb, 0xd6, 0xe3, 0xee, 0xfa, 0x104, 0x110, 0x11b, 0x127, 0x133, 0x13b, 0x145, 0x150, 0x15b, 0x167, 0x16d, 0x178, 0x17e, 0x186, 0x189, 0x18e, 0x192, 0x196, 0x19d, 0x1a6, 0x1ae, 0x1af, 0x1b8, 0x1bf, 0x1c7, 0x1cd, 0x1d2, 0x1d6, 0x1d9, 0x1db, 0x1de, 0x1e3, 0x1e4, 0x1e6, 0x1e8, 0x1ea, 0x1f1, 0x1f6, 0x1fa, 0x203, 0x206, 0x209, 0x20f, 0x210, 0x21b, 0x21c, 0x21d, 0x222, 0x22f, 0x238, 0x23e, 0x246, 0x24f, 0x258, 0x261, 0x266, 0x269, 0x274, 0x282, 0x284, 0x28b, 0x28f, 0x29b, 0x29c, 0x2a7, 0x2af, 0x2b7, 0x2bd, 0x2be, 0x2cc, 0x2d1, 0x2d4, 0x2d9, 0x2dd, 0x2e3, 0x2e8, 0x2eb, 0x2f0, 0x2f5, 0x2f6, 0x2fc, 0x2fe, 0x2ff, 0x301, 0x303, 0x306, 0x307, 0x309, 0x30c, 0x312, 0x316, 0x318, 0x31d, 0x324, 0x334, 0x33e, 0x33f, 0x348, 0x34c, 0x351, 0x359, 0x35f, 0x365, 0x36f, 0x374, 0x37d, 0x383, 0x38c, 0x390, 0x398, 0x39a, 0x39c, 0x39f, 0x3a1, 0x3a3, 0x3a4, 0x3a5, 0x3a7, 0x3a9, 0x3af, 0x3b4, 0x3b6, 0x3bd, 0x3c0, 0x3c2, 0x3c8, 0x3cd, 0x3cf, 0x3d0, 0x3d1, 0x3d2, 0x3d4, 0x3d6, 0x3d8, 0x3db, 0x3dd, 0x3e0, 0x3e8, 0x3eb, 0x3ef, 0x3f7, 0x3f9, 0x409, 0x40a, 0x40c, 0x411, 0x417, 0x419, 0x41a, 0x41c, 0x41e, 0x420, 0x42d, 0x42e, 0x42f, 0x433, 0x435, 0x436, 0x437, 0x438, 0x439, 0x43c, 0x43f, 0x440, 0x443, 0x44a, 0x450, 0x452, 0x456, 0x45e, 0x464, 0x468, 0x46f, 0x473, 0x477, 0x480, 0x48a, 0x48c, 0x492, 0x498, 0x4a2, 0x4ac, 0x4ae, 0x4b7, 0x4bd, 0x4c3, 0x4c9, 0x4cc, 0x4d2, 0x4d5, 0x4de, 0x4df, 0x4e6, 0x4ea, 0x4eb, 0x4ee, 0x4f8, 0x4fb, 0x4fd, 0x504, 0x50c, 0x512, 0x519, 0x51a, 0x520, 0x523, 0x52b, 0x532, 0x53c, 0x544, 0x547, 0x54c, 0x550, 0x551, 0x552, 0x553, 0x554, 0x555, 0x557, 0x55a, 0x55b, 0x55e, 0x55f, 0x562, 0x564, 0x568, 0x569, 0x56b, 0x56e, 0x570, 0x573, 0x576, 0x578, 0x57d, 0x57f, 0x580, 0x585, 0x589, 0x58a, 0x58d, 0x591, 0x59c, 0x5a0, 0x5a8, 0x5ad, 0x5b1, 0x5b4, 0x5b8, 0x5bb, 0x5be, 0x5c3, 0x5c7, 0x5cb, 0x5cf, 0x5d3, 0x5d5, 0x5d7, 0x5da, 0x5de, 0x5e4, 0x5e5, 0x5e6, 0x5e9, 0x5eb, 0x5ed, 0x5f0, 0x5f5, 0x5f9, 0x5fb, 0x601, 0x60a, 0x60f, 0x610, 0x613, 0x614, 0x615, 0x616, 0x618, 0x619, 0x61a}
// sparseValues: 1562 entries, 6248 bytes
var sparseValues = [1562]valueRange{
// Block 0x0, offset 0x0
{value: 0x0004, lo: 0xa8, hi: 0xa8},
{value: 0x0012, lo: 0xaa, hi: 0xaa},
{value: 0x0014, lo: 0xad, hi: 0xad},
{value: 0x0004, lo: 0xaf, hi: 0xaf},
{value: 0x0004, lo: 0xb4, hi: 0xb4},
{value: 0x001a, lo: 0xb5, hi: 0xb5},
{value: 0x0054, lo: 0xb7, hi: 0xb7},
{value: 0x0004, lo: 0xb8, hi: 0xb8},
{value: 0x0012, lo: 0xba, hi: 0xba},
// Block 0x1, offset 0x9
{value: 0x2013, lo: 0x80, hi: 0x96},
{value: 0x2013, lo: 0x98, hi: 0x9e},
{value: 0x009a, lo: 0x9f, hi: 0x9f},
{value: 0x2012, lo: 0xa0, hi: 0xb6},
{value: 0x2012, lo: 0xb8, hi: 0xbe},
{value: 0x0252, lo: 0xbf, hi: 0xbf},
// Block 0x2, offset 0xf
{value: 0x0117, lo: 0x80, hi: 0xaf},
{value: 0x011b, lo: 0xb0, hi: 0xb0},
{value: 0x019a, lo: 0xb1, hi: 0xb1},
{value: 0x0117, lo: 0xb2, hi: 0xb7},
{value: 0x0012, lo: 0xb8, hi: 0xb8},
{value: 0x0316, lo: 0xb9, hi: 0xba},
{value: 0x0716, lo: 0xbb, hi: 0xbc},
{value: 0x0316, lo: 0xbd, hi: 0xbe},
{value: 0x0553, lo: 0xbf, hi: 0xbf},
// Block 0x3, offset 0x18
{value: 0x0552, lo: 0x80, hi: 0x80},
{value: 0x0316, lo: 0x81, hi: 0x82},
{value: 0x0716, lo: 0x83, hi: 0x84},
{value: 0x0316, lo: 0x85, hi: 0x86},
{value: 0x0f16, lo: 0x87, hi: 0x88},
{value: 0x01da, lo: 0x89, hi: 0x89},
{value: 0x0117, lo: 0x8a, hi: 0xb7},
{value: 0x0253, lo: 0xb8, hi: 0xb8},
{value: 0x0316, lo: 0xb9, hi: 0xba},
{value: 0x0716, lo: 0xbb, hi: 0xbc},
{value: 0x0316, lo: 0xbd, hi: 0xbe},
{value: 0x028a, lo: 0xbf, hi: 0xbf},
// Block 0x4, offset 0x24
{value: 0x0117, lo: 0x80, hi: 0x9f},
{value: 0x2f53, lo: 0xa0, hi: 0xa0},
{value: 0x0012, lo: 0xa1, hi: 0xa1},
{value: 0x0117, lo: 0xa2, hi: 0xb3},
{value: 0x0012, lo: 0xb4, hi: 0xb9},
{value: 0x090b, lo: 0xba, hi: 0xba},
{value: 0x0716, lo: 0xbb, hi: 0xbc},
{value: 0x2953, lo: 0xbd, hi: 0xbd},
{value: 0x098b, lo: 0xbe, hi: 0xbe},
{value: 0x0a0a, lo: 0xbf, hi: 0xbf},
// Block 0x5, offset 0x2e
{value: 0x0015, lo: 0x80, hi: 0x81},
{value: 0x0014, lo: 0x82, hi: 0x97},
{value: 0x0004, lo: 0x98, hi: 0x9d},
{value: 0x0014, lo: 0x9e, hi: 0x9f},
{value: 0x0015, lo: 0xa0, hi: 0xa4},
{value: 0x0014, lo: 0xa5, hi: 0xbf},
// Block 0x6, offset 0x34
{value: 0x0024, lo: 0x80, hi: 0x94},
{value: 0x0034, lo: 0x95, hi: 0xbc},
{value: 0x0024, lo: 0xbd, hi: 0xbf},
// Block 0x7, offset 0x37
{value: 0x6553, lo: 0x80, hi: 0x8f},
{value: 0x2013, lo: 0x90, hi: 0x9f},
{value: 0x5f53, lo: 0xa0, hi: 0xaf},
{value: 0x2012, lo: 0xb0, hi: 0xbf},
// Block 0x8, offset 0x3b
{value: 0x5f52, lo: 0x80, hi: 0x8f},
{value: 0x6552, lo: 0x90, hi: 0x9f},
{value: 0x0117, lo: 0xa0, hi: 0xbf},
// Block 0x9, offset 0x3e
{value: 0x0117, lo: 0x80, hi: 0x81},
{value: 0x0024, lo: 0x83, hi: 0x87},
{value: 0x0014, lo: 0x88, hi: 0x89},
{value: 0x0117, lo: 0x8a, hi: 0xbf},
// Block 0xa, offset 0x42
{value: 0x0f13, lo: 0x80, hi: 0x80},
{value: 0x0316, lo: 0x81, hi: 0x82},
{value: 0x0716, lo: 0x83, hi: 0x84},
{value: 0x0316, lo: 0x85, hi: 0x86},
{value: 0x0f16, lo: 0x87, hi: 0x88},
{value: 0x0316, lo: 0x89, hi: 0x8a},
{value: 0x0716, lo: 0x8b, hi: 0x8c},
{value: 0x0316, lo: 0x8d, hi: 0x8e},
{value: 0x0f12, lo: 0x8f, hi: 0x8f},
{value: 0x0117, lo: 0x90, hi: 0xbf},
// Block 0xb, offset 0x4c
{value: 0x0117, lo: 0x80, hi: 0xaf},
{value: 0x6553, lo: 0xb1, hi: 0xbf},
// Block 0xc, offset 0x4e
{value: 0x3013, lo: 0x80, hi: 0x8f},
{value: 0x6853, lo: 0x90, hi: 0x96},
{value: 0x0014, lo: 0x99, hi: 0x99},
{value: 0x0010, lo: 0x9a, hi: 0x9c},
{value: 0x0010, lo: 0x9e, hi: 0x9e},
{value: 0x0054, lo: 0x9f, hi: 0x9f},
{value: 0x0012, lo: 0xa0, hi: 0xa0},
{value: 0x6552, lo: 0xa1, hi: 0xaf},
{value: 0x3012, lo: 0xb0, hi: 0xbf},
// Block 0xd, offset 0x57
{value: 0x0034, lo: 0x81, hi: 0x82},
{value: 0x0024, lo: 0x84, hi: 0x84},
{value: 0x0034, lo: 0x85, hi: 0x85},
{value: 0x0034, lo: 0x87, hi: 0x87},
{value: 0x0010, lo: 0x90, hi: 0xaa},
{value: 0x0010, lo: 0xaf, hi: 0xb3},
{value: 0x0054, lo: 0xb4, hi: 0xb4},
// Block 0xe, offset 0x5e
{value: 0x0014, lo: 0x80, hi: 0x85},
{value: 0x0024, lo: 0x90, hi: 0x97},
{value: 0x0034, lo: 0x98, hi: 0x9a},
{value: 0x0014, lo: 0x9c, hi: 0x9c},
{value: 0x0010, lo: 0xa0, hi: 0xbf},
// Block 0xf, offset 0x63
{value: 0x0014, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x81, hi: 0x8a},
{value: 0x0034, lo: 0x8b, hi: 0x92},
{value: 0x0024, lo: 0x93, hi: 0x94},
{value: 0x0034, lo: 0x95, hi: 0x96},
{value: 0x0024, lo: 0x97, hi: 0x9b},
{value: 0x0034, lo: 0x9c, hi: 0x9c},
{value: 0x0024, lo: 0x9d, hi: 0x9e},
{value: 0x0034, lo: 0x9f, hi: 0x9f},
{value: 0x0010, lo: 0xa0, hi: 0xa9},
{value: 0x0010, lo: 0xab, hi: 0xab},
{value: 0x0010, lo: 0xae, hi: 0xaf},
{value: 0x0034, lo: 0xb0, hi: 0xb0},
{value: 0x0010, lo: 0xb1, hi: 0xbf},
// Block 0x10, offset 0x71
{value: 0x0010, lo: 0x80, hi: 0xbf},
// Block 0x11, offset 0x72
{value: 0x0010, lo: 0x80, hi: 0x93},
{value: 0x0010, lo: 0x95, hi: 0x95},
{value: 0x0024, lo: 0x96, hi: 0x9c},
{value: 0x0014, lo: 0x9d, hi: 0x9d},
{value: 0x0024, lo: 0x9f, hi: 0xa2},
{value: 0x0034, lo: 0xa3, hi: 0xa3},
{value: 0x0024, lo: 0xa4, hi: 0xa4},
{value: 0x0014, lo: 0xa5, hi: 0xa6},
{value: 0x0024, lo: 0xa7, hi: 0xa8},
{value: 0x0034, lo: 0xaa, hi: 0xaa},
{value: 0x0024, lo: 0xab, hi: 0xac},
{value: 0x0034, lo: 0xad, hi: 0xad},
{value: 0x0010, lo: 0xae, hi: 0xbc},
{value: 0x0010, lo: 0xbf, hi: 0xbf},
// Block 0x12, offset 0x80
{value: 0x0014, lo: 0x8f, hi: 0x8f},
{value: 0x0010, lo: 0x90, hi: 0x90},
{value: 0x0034, lo: 0x91, hi: 0x91},
{value: 0x0010, lo: 0x92, hi: 0xaf},
{value: 0x0024, lo: 0xb0, hi: 0xb0},
{value: 0x0034, lo: 0xb1, hi: 0xb1},
{value: 0x0024, lo: 0xb2, hi: 0xb3},
{value: 0x0034, lo: 0xb4, hi: 0xb4},
{value: 0x0024, lo: 0xb5, hi: 0xb6},
{value: 0x0034, lo: 0xb7, hi: 0xb9},
{value: 0x0024, lo: 0xba, hi: 0xba},
{value: 0x0034, lo: 0xbb, hi: 0xbc},
{value: 0x0024, lo: 0xbd, hi: 0xbd},
{value: 0x0034, lo: 0xbe, hi: 0xbe},
{value: 0x0024, lo: 0xbf, hi: 0xbf},
// Block 0x13, offset 0x8f
{value: 0x0024, lo: 0x80, hi: 0x81},
{value: 0x0034, lo: 0x82, hi: 0x82},
{value: 0x0024, lo: 0x83, hi: 0x83},
{value: 0x0034, lo: 0x84, hi: 0x84},
{value: 0x0024, lo: 0x85, hi: 0x85},
{value: 0x0034, lo: 0x86, hi: 0x86},
{value: 0x0024, lo: 0x87, hi: 0x87},
{value: 0x0034, lo: 0x88, hi: 0x88},
{value: 0x0024, lo: 0x89, hi: 0x8a},
{value: 0x0010, lo: 0x8d, hi: 0xbf},
// Block 0x14, offset 0x99
{value: 0x0010, lo: 0x80, hi: 0xa5},
{value: 0x0014, lo: 0xa6, hi: 0xb0},
{value: 0x0010, lo: 0xb1, hi: 0xb1},
// Block 0x15, offset 0x9c
{value: 0x0010, lo: 0x80, hi: 0xaa},
{value: 0x0024, lo: 0xab, hi: 0xb1},
{value: 0x0034, lo: 0xb2, hi: 0xb2},
{value: 0x0024, lo: 0xb3, hi: 0xb3},
{value: 0x0014, lo: 0xb4, hi: 0xb5},
{value: 0x0014, lo: 0xba, hi: 0xba},
{value: 0x0034, lo: 0xbd, hi: 0xbd},
// Block 0x16, offset 0xa3
{value: 0x0010, lo: 0x80, hi: 0x95},
{value: 0x0024, lo: 0x96, hi: 0x99},
{value: 0x0014, lo: 0x9a, hi: 0x9a},
{value: 0x0024, lo: 0x9b, hi: 0xa3},
{value: 0x0014, lo: 0xa4, hi: 0xa4},
{value: 0x0024, lo: 0xa5, hi: 0xa7},
{value: 0x0014, lo: 0xa8, hi: 0xa8},
{value: 0x0024, lo: 0xa9, hi: 0xad},
// Block 0x17, offset 0xab
{value: 0x0010, lo: 0x80, hi: 0x98},
{value: 0x0034, lo: 0x99, hi: 0x9b},
{value: 0x0010, lo: 0xa0, hi: 0xaa},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0x18, offset 0xaf
{value: 0x0010, lo: 0x80, hi: 0x87},
{value: 0x0004, lo: 0x88, hi: 0x88},
{value: 0x0010, lo: 0x89, hi: 0x8e},
{value: 0x0014, lo: 0x90, hi: 0x91},
{value: 0x0024, lo: 0x98, hi: 0x98},
{value: 0x0034, lo: 0x99, hi: 0x9b},
{value: 0x0024, lo: 0x9c, hi: 0x9f},
{value: 0x0010, lo: 0xa0, hi: 0xbf},
// Block 0x19, offset 0xb7
{value: 0x0014, lo: 0x80, hi: 0x82},
{value: 0x0010, lo: 0x83, hi: 0xb9},
{value: 0x0014, lo: 0xba, hi: 0xba},
{value: 0x0010, lo: 0xbb, hi: 0xbb},
{value: 0x0034, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbd, hi: 0xbf},
// Block 0x1a, offset 0xbd
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x88},
{value: 0x0010, lo: 0x89, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0010, lo: 0x8e, hi: 0x90},
{value: 0x0024, lo: 0x91, hi: 0x91},
{value: 0x0034, lo: 0x92, hi: 0x92},
{value: 0x0024, lo: 0x93, hi: 0x94},
{value: 0x0014, lo: 0x95, hi: 0x97},
{value: 0x0010, lo: 0x98, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa3},
{value: 0x0010, lo: 0xa6, hi: 0xaf},
{value: 0x0014, lo: 0xb1, hi: 0xb1},
{value: 0x0010, lo: 0xb2, hi: 0xbf},
// Block 0x1b, offset 0xcb
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x81},
{value: 0x0010, lo: 0x82, hi: 0x83},
{value: 0x0010, lo: 0x85, hi: 0x8c},
{value: 0x0010, lo: 0x8f, hi: 0x90},
{value: 0x0010, lo: 0x93, hi: 0xa8},
{value: 0x0010, lo: 0xaa, hi: 0xb0},
{value: 0x0010, lo: 0xb2, hi: 0xb2},
{value: 0x0010, lo: 0xb6, hi: 0xb9},
{value: 0x0034, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbd, hi: 0xbf},
// Block 0x1c, offset 0xd6
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x84},
{value: 0x0010, lo: 0x87, hi: 0x88},
{value: 0x0010, lo: 0x8b, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0010, lo: 0x8e, hi: 0x8e},
{value: 0x0010, lo: 0x97, hi: 0x97},
{value: 0x0010, lo: 0x9c, hi: 0x9d},
{value: 0x0010, lo: 0x9f, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa3},
{value: 0x0010, lo: 0xa6, hi: 0xb1},
{value: 0x0010, lo: 0xbc, hi: 0xbc},
{value: 0x0024, lo: 0xbe, hi: 0xbe},
// Block 0x1d, offset 0xe3
{value: 0x0014, lo: 0x81, hi: 0x82},
{value: 0x0010, lo: 0x83, hi: 0x83},
{value: 0x0010, lo: 0x85, hi: 0x8a},
{value: 0x0010, lo: 0x8f, hi: 0x90},
{value: 0x0010, lo: 0x93, hi: 0xa8},
{value: 0x0010, lo: 0xaa, hi: 0xb0},
{value: 0x0010, lo: 0xb2, hi: 0xb3},
{value: 0x0010, lo: 0xb5, hi: 0xb6},
{value: 0x0010, lo: 0xb8, hi: 0xb9},
{value: 0x0034, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbe, hi: 0xbf},
// Block 0x1e, offset 0xee
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x82},
{value: 0x0014, lo: 0x87, hi: 0x88},
{value: 0x0014, lo: 0x8b, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0014, lo: 0x91, hi: 0x91},
{value: 0x0010, lo: 0x99, hi: 0x9c},
{value: 0x0010, lo: 0x9e, hi: 0x9e},
{value: 0x0010, lo: 0xa6, hi: 0xaf},
{value: 0x0014, lo: 0xb0, hi: 0xb1},
{value: 0x0010, lo: 0xb2, hi: 0xb4},
{value: 0x0014, lo: 0xb5, hi: 0xb5},
// Block 0x1f, offset 0xfa
{value: 0x0014, lo: 0x81, hi: 0x82},
{value: 0x0010, lo: 0x83, hi: 0x83},
{value: 0x0010, lo: 0x85, hi: 0x8d},
{value: 0x0010, lo: 0x8f, hi: 0x91},
{value: 0x0010, lo: 0x93, hi: 0xa8},
{value: 0x0010, lo: 0xaa, hi: 0xb0},
{value: 0x0010, lo: 0xb2, hi: 0xb3},
{value: 0x0010, lo: 0xb5, hi: 0xb9},
{value: 0x0034, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbd, hi: 0xbf},
// Block 0x20, offset 0x104
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x85},
{value: 0x0014, lo: 0x87, hi: 0x88},
{value: 0x0010, lo: 0x89, hi: 0x89},
{value: 0x0010, lo: 0x8b, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0010, lo: 0x90, hi: 0x90},
{value: 0x0010, lo: 0xa0, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa3},
{value: 0x0010, lo: 0xa6, hi: 0xaf},
{value: 0x0010, lo: 0xb9, hi: 0xb9},
{value: 0x0014, lo: 0xba, hi: 0xbf},
// Block 0x21, offset 0x110
{value: 0x0014, lo: 0x81, hi: 0x81},
{value: 0x0010, lo: 0x82, hi: 0x83},
{value: 0x0010, lo: 0x85, hi: 0x8c},
{value: 0x0010, lo: 0x8f, hi: 0x90},
{value: 0x0010, lo: 0x93, hi: 0xa8},
{value: 0x0010, lo: 0xaa, hi: 0xb0},
{value: 0x0010, lo: 0xb2, hi: 0xb3},
{value: 0x0010, lo: 0xb5, hi: 0xb9},
{value: 0x0034, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbd, hi: 0xbe},
{value: 0x0014, lo: 0xbf, hi: 0xbf},
// Block 0x22, offset 0x11b
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x84},
{value: 0x0010, lo: 0x87, hi: 0x88},
{value: 0x0010, lo: 0x8b, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0014, lo: 0x95, hi: 0x96},
{value: 0x0010, lo: 0x97, hi: 0x97},
{value: 0x0010, lo: 0x9c, hi: 0x9d},
{value: 0x0010, lo: 0x9f, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa3},
{value: 0x0010, lo: 0xa6, hi: 0xaf},
{value: 0x0010, lo: 0xb1, hi: 0xb1},
// Block 0x23, offset 0x127
{value: 0x0014, lo: 0x82, hi: 0x82},
{value: 0x0010, lo: 0x83, hi: 0x83},
{value: 0x0010, lo: 0x85, hi: 0x8a},
{value: 0x0010, lo: 0x8e, hi: 0x90},
{value: 0x0010, lo: 0x92, hi: 0x95},
{value: 0x0010, lo: 0x99, hi: 0x9a},
{value: 0x0010, lo: 0x9c, hi: 0x9c},
{value: 0x0010, lo: 0x9e, hi: 0x9f},
{value: 0x0010, lo: 0xa3, hi: 0xa4},
{value: 0x0010, lo: 0xa8, hi: 0xaa},
{value: 0x0010, lo: 0xae, hi: 0xb9},
{value: 0x0010, lo: 0xbe, hi: 0xbf},
// Block 0x24, offset 0x133
{value: 0x0014, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x81, hi: 0x82},
{value: 0x0010, lo: 0x86, hi: 0x88},
{value: 0x0010, lo: 0x8a, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0010, lo: 0x90, hi: 0x90},
{value: 0x0010, lo: 0x97, hi: 0x97},
{value: 0x0010, lo: 0xa6, hi: 0xaf},
// Block 0x25, offset 0x13b
{value: 0x0014, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x81, hi: 0x83},
{value: 0x0014, lo: 0x84, hi: 0x84},
{value: 0x0010, lo: 0x85, hi: 0x8c},
{value: 0x0010, lo: 0x8e, hi: 0x90},
{value: 0x0010, lo: 0x92, hi: 0xa8},
{value: 0x0010, lo: 0xaa, hi: 0xb9},
{value: 0x0034, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbd, hi: 0xbd},
{value: 0x0014, lo: 0xbe, hi: 0xbf},
// Block 0x26, offset 0x145
{value: 0x0014, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x81, hi: 0x84},
{value: 0x0014, lo: 0x86, hi: 0x88},
{value: 0x0014, lo: 0x8a, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0034, lo: 0x95, hi: 0x96},
{value: 0x0010, lo: 0x98, hi: 0x9a},
{value: 0x0010, lo: 0x9d, hi: 0x9d},
{value: 0x0010, lo: 0xa0, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa3},
{value: 0x0010, lo: 0xa6, hi: 0xaf},
// Block 0x27, offset 0x150
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x81},
{value: 0x0010, lo: 0x82, hi: 0x83},
{value: 0x0010, lo: 0x85, hi: 0x8c},
{value: 0x0010, lo: 0x8e, hi: 0x90},
{value: 0x0010, lo: 0x92, hi: 0xa8},
{value: 0x0010, lo: 0xaa, hi: 0xb3},
{value: 0x0010, lo: 0xb5, hi: 0xb9},
{value: 0x0034, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbd, hi: 0xbe},
{value: 0x0014, lo: 0xbf, hi: 0xbf},
// Block 0x28, offset 0x15b
{value: 0x0010, lo: 0x80, hi: 0x84},
{value: 0x0014, lo: 0x86, hi: 0x86},
{value: 0x0010, lo: 0x87, hi: 0x88},
{value: 0x0010, lo: 0x8a, hi: 0x8b},
{value: 0x0014, lo: 0x8c, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0010, lo: 0x95, hi: 0x96},
{value: 0x0010, lo: 0x9d, hi: 0x9e},
{value: 0x0010, lo: 0xa0, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa3},
{value: 0x0010, lo: 0xa6, hi: 0xaf},
{value: 0x0010, lo: 0xb1, hi: 0xb3},
// Block 0x29, offset 0x167
{value: 0x0014, lo: 0x80, hi: 0x81},
{value: 0x0010, lo: 0x82, hi: 0x8c},
{value: 0x0010, lo: 0x8e, hi: 0x90},
{value: 0x0010, lo: 0x92, hi: 0xba},
{value: 0x0034, lo: 0xbb, hi: 0xbc},
{value: 0x0010, lo: 0xbd, hi: 0xbf},
// Block 0x2a, offset 0x16d
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x84},
{value: 0x0010, lo: 0x86, hi: 0x88},
{value: 0x0010, lo: 0x8a, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0010, lo: 0x8e, hi: 0x8e},
{value: 0x0010, lo: 0x94, hi: 0x97},
{value: 0x0010, lo: 0x9f, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa3},
{value: 0x0010, lo: 0xa6, hi: 0xaf},
{value: 0x0010, lo: 0xba, hi: 0xbf},
// Block 0x2b, offset 0x178
{value: 0x0014, lo: 0x81, hi: 0x81},
{value: 0x0010, lo: 0x82, hi: 0x83},
{value: 0x0010, lo: 0x85, hi: 0x96},
{value: 0x0010, lo: 0x9a, hi: 0xb1},
{value: 0x0010, lo: 0xb3, hi: 0xbb},
{value: 0x0010, lo: 0xbd, hi: 0xbd},
// Block 0x2c, offset 0x17e
{value: 0x0010, lo: 0x80, hi: 0x86},
{value: 0x0034, lo: 0x8a, hi: 0x8a},
{value: 0x0010, lo: 0x8f, hi: 0x91},
{value: 0x0014, lo: 0x92, hi: 0x94},
{value: 0x0014, lo: 0x96, hi: 0x96},
{value: 0x0010, lo: 0x98, hi: 0x9f},
{value: 0x0010, lo: 0xa6, hi: 0xaf},
{value: 0x0010, lo: 0xb2, hi: 0xb3},
// Block 0x2d, offset 0x186
{value: 0x0014, lo: 0xb1, hi: 0xb1},
{value: 0x0014, lo: 0xb4, hi: 0xb7},
{value: 0x0034, lo: 0xb8, hi: 0xba},
// Block 0x2e, offset 0x189
{value: 0x0004, lo: 0x86, hi: 0x86},
{value: 0x0014, lo: 0x87, hi: 0x87},
{value: 0x0034, lo: 0x88, hi: 0x8b},
{value: 0x0014, lo: 0x8c, hi: 0x8e},
{value: 0x0010, lo: 0x90, hi: 0x99},
// Block 0x2f, offset 0x18e
{value: 0x0014, lo: 0xb1, hi: 0xb1},
{value: 0x0014, lo: 0xb4, hi: 0xb7},
{value: 0x0034, lo: 0xb8, hi: 0xba},
{value: 0x0014, lo: 0xbb, hi: 0xbc},
// Block 0x30, offset 0x192
{value: 0x0004, lo: 0x86, hi: 0x86},
{value: 0x0034, lo: 0x88, hi: 0x8b},
{value: 0x0014, lo: 0x8c, hi: 0x8e},
{value: 0x0010, lo: 0x90, hi: 0x99},
// Block 0x31, offset 0x196
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0034, lo: 0x98, hi: 0x99},
{value: 0x0010, lo: 0xa0, hi: 0xa9},
{value: 0x0034, lo: 0xb5, hi: 0xb5},
{value: 0x0034, lo: 0xb7, hi: 0xb7},
{value: 0x0034, lo: 0xb9, hi: 0xb9},
{value: 0x0010, lo: 0xbe, hi: 0xbf},
// Block 0x32, offset 0x19d
{value: 0x0010, lo: 0x80, hi: 0x87},
{value: 0x0010, lo: 0x89, hi: 0xac},
{value: 0x0034, lo: 0xb1, hi: 0xb2},
{value: 0x0014, lo: 0xb3, hi: 0xb3},
{value: 0x0034, lo: 0xb4, hi: 0xb4},
{value: 0x0014, lo: 0xb5, hi: 0xb9},
{value: 0x0034, lo: 0xba, hi: 0xbd},
{value: 0x0014, lo: 0xbe, hi: 0xbe},
{value: 0x0010, lo: 0xbf, hi: 0xbf},
// Block 0x33, offset 0x1a6
{value: 0x0034, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x81},
{value: 0x0024, lo: 0x82, hi: 0x83},
{value: 0x0034, lo: 0x84, hi: 0x84},
{value: 0x0024, lo: 0x86, hi: 0x87},
{value: 0x0010, lo: 0x88, hi: 0x8c},
{value: 0x0014, lo: 0x8d, hi: 0x97},
{value: 0x0014, lo: 0x99, hi: 0xbc},
// Block 0x34, offset 0x1ae
{value: 0x0034, lo: 0x86, hi: 0x86},
// Block 0x35, offset 0x1af
{value: 0x0010, lo: 0xab, hi: 0xac},
{value: 0x0014, lo: 0xad, hi: 0xb0},
{value: 0x0010, lo: 0xb1, hi: 0xb1},
{value: 0x0014, lo: 0xb2, hi: 0xb6},
{value: 0x0034, lo: 0xb7, hi: 0xb7},
{value: 0x0010, lo: 0xb8, hi: 0xb8},
{value: 0x0034, lo: 0xb9, hi: 0xba},
{value: 0x0010, lo: 0xbb, hi: 0xbc},
{value: 0x0014, lo: 0xbd, hi: 0xbe},
// Block 0x36, offset 0x1b8
{value: 0x0010, lo: 0x80, hi: 0x89},
{value: 0x0010, lo: 0x96, hi: 0x97},
{value: 0x0014, lo: 0x98, hi: 0x99},
{value: 0x0014, lo: 0x9e, hi: 0xa0},
{value: 0x0010, lo: 0xa2, hi: 0xa4},
{value: 0x0010, lo: 0xa7, hi: 0xad},
{value: 0x0014, lo: 0xb1, hi: 0xb4},
// Block 0x37, offset 0x1bf
{value: 0x0014, lo: 0x82, hi: 0x82},
{value: 0x0010, lo: 0x83, hi: 0x84},
{value: 0x0014, lo: 0x85, hi: 0x86},
{value: 0x0010, lo: 0x87, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0010, lo: 0x8f, hi: 0x9c},
{value: 0x0014, lo: 0x9d, hi: 0x9d},
{value: 0x6c53, lo: 0xa0, hi: 0xbf},
// Block 0x38, offset 0x1c7
{value: 0x0010, lo: 0x80, hi: 0x88},
{value: 0x0010, lo: 0x8a, hi: 0x8d},
{value: 0x0010, lo: 0x90, hi: 0x96},
{value: 0x0010, lo: 0x98, hi: 0x98},
{value: 0x0010, lo: 0x9a, hi: 0x9d},
{value: 0x0010, lo: 0xa0, hi: 0xbf},
// Block 0x39, offset 0x1cd
{value: 0x0010, lo: 0x80, hi: 0x88},
{value: 0x0010, lo: 0x8a, hi: 0x8d},
{value: 0x0010, lo: 0x90, hi: 0xb0},
{value: 0x0010, lo: 0xb2, hi: 0xb5},
{value: 0x0010, lo: 0xb8, hi: 0xbe},
// Block 0x3a, offset 0x1d2
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x82, hi: 0x85},
{value: 0x0010, lo: 0x88, hi: 0x96},
{value: 0x0010, lo: 0x98, hi: 0xbf},
// Block 0x3b, offset 0x1d6
{value: 0x0010, lo: 0x80, hi: 0x90},
{value: 0x0010, lo: 0x92, hi: 0x95},
{value: 0x0010, lo: 0x98, hi: 0xbf},
// Block 0x3c, offset 0x1d9
{value: 0x0010, lo: 0x80, hi: 0x9a},
{value: 0x0024, lo: 0x9d, hi: 0x9f},
// Block 0x3d, offset 0x1db
{value: 0x0010, lo: 0x80, hi: 0x8f},
{value: 0x7453, lo: 0xa0, hi: 0xaf},
{value: 0x7853, lo: 0xb0, hi: 0xbf},
// Block 0x3e, offset 0x1de
{value: 0x7c53, lo: 0x80, hi: 0x8f},
{value: 0x8053, lo: 0x90, hi: 0x9f},
{value: 0x7c53, lo: 0xa0, hi: 0xaf},
{value: 0x0813, lo: 0xb0, hi: 0xb5},
{value: 0x0892, lo: 0xb8, hi: 0xbd},
// Block 0x3f, offset 0x1e3
{value: 0x0010, lo: 0x81, hi: 0xbf},
// Block 0x40, offset 0x1e4
{value: 0x0010, lo: 0x80, hi: 0xac},
{value: 0x0010, lo: 0xaf, hi: 0xbf},
// Block 0x41, offset 0x1e6
{value: 0x0010, lo: 0x81, hi: 0x9a},
{value: 0x0010, lo: 0xa0, hi: 0xbf},
// Block 0x42, offset 0x1e8
{value: 0x0010, lo: 0x80, hi: 0xaa},
{value: 0x0010, lo: 0xae, hi: 0xb8},
// Block 0x43, offset 0x1ea
{value: 0x0010, lo: 0x80, hi: 0x91},
{value: 0x0014, lo: 0x92, hi: 0x93},
{value: 0x0034, lo: 0x94, hi: 0x94},
{value: 0x0030, lo: 0x95, hi: 0x95},
{value: 0x0010, lo: 0x9f, hi: 0xb1},
{value: 0x0014, lo: 0xb2, hi: 0xb3},
{value: 0x0030, lo: 0xb4, hi: 0xb4},
// Block 0x44, offset 0x1f1
{value: 0x0010, lo: 0x80, hi: 0x91},
{value: 0x0014, lo: 0x92, hi: 0x93},
{value: 0x0010, lo: 0xa0, hi: 0xac},
{value: 0x0010, lo: 0xae, hi: 0xb0},
{value: 0x0014, lo: 0xb2, hi: 0xb3},
// Block 0x45, offset 0x1f6
{value: 0x0014, lo: 0xb4, hi: 0xb5},
{value: 0x0010, lo: 0xb6, hi: 0xb6},
{value: 0x0014, lo: 0xb7, hi: 0xbd},
{value: 0x0010, lo: 0xbe, hi: 0xbf},
// Block 0x46, offset 0x1fa
{value: 0x0010, lo: 0x80, hi: 0x85},
{value: 0x0014, lo: 0x86, hi: 0x86},
{value: 0x0010, lo: 0x87, hi: 0x88},
{value: 0x0014, lo: 0x89, hi: 0x91},
{value: 0x0034, lo: 0x92, hi: 0x92},
{value: 0x0014, lo: 0x93, hi: 0x93},
{value: 0x0004, lo: 0x97, hi: 0x97},
{value: 0x0024, lo: 0x9d, hi: 0x9d},
{value: 0x0010, lo: 0xa0, hi: 0xa9},
// Block 0x47, offset 0x203
{value: 0x0014, lo: 0x8b, hi: 0x8f},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0010, lo: 0xa0, hi: 0xbf},
// Block 0x48, offset 0x206
{value: 0x0010, lo: 0x80, hi: 0x82},
{value: 0x0014, lo: 0x83, hi: 0x83},
{value: 0x0010, lo: 0x84, hi: 0xb8},
// Block 0x49, offset 0x209
{value: 0x0010, lo: 0x80, hi: 0x84},
{value: 0x0014, lo: 0x85, hi: 0x86},
{value: 0x0010, lo: 0x87, hi: 0xa8},
{value: 0x0034, lo: 0xa9, hi: 0xa9},
{value: 0x0010, lo: 0xaa, hi: 0xaa},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0x4a, offset 0x20f
{value: 0x0010, lo: 0x80, hi: 0xb5},
// Block 0x4b, offset 0x210
{value: 0x0010, lo: 0x80, hi: 0x9e},
{value: 0x0014, lo: 0xa0, hi: 0xa2},
{value: 0x0010, lo: 0xa3, hi: 0xa6},
{value: 0x0014, lo: 0xa7, hi: 0xa8},
{value: 0x0010, lo: 0xa9, hi: 0xab},
{value: 0x0010, lo: 0xb0, hi: 0xb1},
{value: 0x0014, lo: 0xb2, hi: 0xb2},
{value: 0x0010, lo: 0xb3, hi: 0xb8},
{value: 0x0034, lo: 0xb9, hi: 0xb9},
{value: 0x0024, lo: 0xba, hi: 0xba},
{value: 0x0034, lo: 0xbb, hi: 0xbb},
// Block 0x4c, offset 0x21b
{value: 0x0010, lo: 0x86, hi: 0x8f},
// Block 0x4d, offset 0x21c
{value: 0x0010, lo: 0x90, hi: 0x99},
// Block 0x4e, offset 0x21d
{value: 0x0010, lo: 0x80, hi: 0x96},
{value: 0x0024, lo: 0x97, hi: 0x97},
{value: 0x0034, lo: 0x98, hi: 0x98},
{value: 0x0010, lo: 0x99, hi: 0x9a},
{value: 0x0014, lo: 0x9b, hi: 0x9b},
// Block 0x4f, offset 0x222
{value: 0x0010, lo: 0x95, hi: 0x95},
{value: 0x0014, lo: 0x96, hi: 0x96},
{value: 0x0010, lo: 0x97, hi: 0x97},
{value: 0x0014, lo: 0x98, hi: 0x9e},
{value: 0x0034, lo: 0xa0, hi: 0xa0},
{value: 0x0010, lo: 0xa1, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa2},
{value: 0x0010, lo: 0xa3, hi: 0xa4},
{value: 0x0014, lo: 0xa5, hi: 0xac},
{value: 0x0010, lo: 0xad, hi: 0xb2},
{value: 0x0014, lo: 0xb3, hi: 0xb4},
{value: 0x0024, lo: 0xb5, hi: 0xbc},
{value: 0x0034, lo: 0xbf, hi: 0xbf},
// Block 0x50, offset 0x22f
{value: 0x0010, lo: 0x80, hi: 0x89},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0004, lo: 0xa7, hi: 0xa7},
{value: 0x0024, lo: 0xb0, hi: 0xb4},
{value: 0x0034, lo: 0xb5, hi: 0xba},
{value: 0x0024, lo: 0xbb, hi: 0xbc},
{value: 0x0034, lo: 0xbd, hi: 0xbd},
{value: 0x0014, lo: 0xbe, hi: 0xbe},
{value: 0x0034, lo: 0xbf, hi: 0xbf},
// Block 0x51, offset 0x238
{value: 0x0034, lo: 0x80, hi: 0x80},
{value: 0x0024, lo: 0x81, hi: 0x82},
{value: 0x0034, lo: 0x83, hi: 0x84},
{value: 0x0024, lo: 0x85, hi: 0x89},
{value: 0x0034, lo: 0x8a, hi: 0x8a},
{value: 0x0024, lo: 0x8b, hi: 0x8e},
// Block 0x52, offset 0x23e
{value: 0x0014, lo: 0x80, hi: 0x83},
{value: 0x0010, lo: 0x84, hi: 0xb3},
{value: 0x0034, lo: 0xb4, hi: 0xb4},
{value: 0x0010, lo: 0xb5, hi: 0xb5},
{value: 0x0014, lo: 0xb6, hi: 0xba},
{value: 0x0010, lo: 0xbb, hi: 0xbb},
{value: 0x0014, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbd, hi: 0xbf},
// Block 0x53, offset 0x246
{value: 0x0010, lo: 0x80, hi: 0x81},
{value: 0x0014, lo: 0x82, hi: 0x82},
{value: 0x0010, lo: 0x83, hi: 0x83},
{value: 0x0030, lo: 0x84, hi: 0x84},
{value: 0x0010, lo: 0x85, hi: 0x8c},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0024, lo: 0xab, hi: 0xab},
{value: 0x0034, lo: 0xac, hi: 0xac},
{value: 0x0024, lo: 0xad, hi: 0xb3},
// Block 0x54, offset 0x24f
{value: 0x0014, lo: 0x80, hi: 0x81},
{value: 0x0010, lo: 0x82, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa5},
{value: 0x0010, lo: 0xa6, hi: 0xa7},
{value: 0x0014, lo: 0xa8, hi: 0xa9},
{value: 0x0030, lo: 0xaa, hi: 0xaa},
{value: 0x0034, lo: 0xab, hi: 0xab},
{value: 0x0014, lo: 0xac, hi: 0xad},
{value: 0x0010, lo: 0xae, hi: 0xbf},
// Block 0x55, offset 0x258
{value: 0x0010, lo: 0x80, hi: 0xa5},
{value: 0x0034, lo: 0xa6, hi: 0xa6},
{value: 0x0010, lo: 0xa7, hi: 0xa7},
{value: 0x0014, lo: 0xa8, hi: 0xa9},
{value: 0x0010, lo: 0xaa, hi: 0xac},
{value: 0x0014, lo: 0xad, hi: 0xad},
{value: 0x0010, lo: 0xae, hi: 0xae},
{value: 0x0014, lo: 0xaf, hi: 0xb1},
{value: 0x0030, lo: 0xb2, hi: 0xb3},
// Block 0x56, offset 0x261
{value: 0x0010, lo: 0x80, hi: 0xab},
{value: 0x0014, lo: 0xac, hi: 0xb3},
{value: 0x0010, lo: 0xb4, hi: 0xb5},
{value: 0x0014, lo: 0xb6, hi: 0xb6},
{value: 0x0034, lo: 0xb7, hi: 0xb7},
// Block 0x57, offset 0x266
{value: 0x0010, lo: 0x80, hi: 0x89},
{value: 0x0010, lo: 0x8d, hi: 0xb7},
{value: 0x0014, lo: 0xb8, hi: 0xbd},
// Block 0x58, offset 0x269
{value: 0x31ea, lo: 0x80, hi: 0x80},
{value: 0x326a, lo: 0x81, hi: 0x81},
{value: 0x32ea, lo: 0x82, hi: 0x82},
{value: 0x336a, lo: 0x83, hi: 0x83},
{value: 0x33ea, lo: 0x84, hi: 0x84},
{value: 0x346a, lo: 0x85, hi: 0x85},
{value: 0x34ea, lo: 0x86, hi: 0x86},
{value: 0x356a, lo: 0x87, hi: 0x87},
{value: 0x35ea, lo: 0x88, hi: 0x88},
{value: 0x8353, lo: 0x90, hi: 0xba},
{value: 0x8353, lo: 0xbd, hi: 0xbf},
// Block 0x59, offset 0x274
{value: 0x0024, lo: 0x90, hi: 0x92},
{value: 0x0034, lo: 0x94, hi: 0x99},
{value: 0x0024, lo: 0x9a, hi: 0x9b},
{value: 0x0034, lo: 0x9c, hi: 0x9f},
{value: 0x0024, lo: 0xa0, hi: 0xa0},
{value: 0x0010, lo: 0xa1, hi: 0xa1},
{value: 0x0034, lo: 0xa2, hi: 0xa8},
{value: 0x0010, lo: 0xa9, hi: 0xac},
{value: 0x0034, lo: 0xad, hi: 0xad},
{value: 0x0010, lo: 0xae, hi: 0xb3},
{value: 0x0024, lo: 0xb4, hi: 0xb4},
{value: 0x0010, lo: 0xb5, hi: 0xb7},
{value: 0x0024, lo: 0xb8, hi: 0xb9},
{value: 0x0010, lo: 0xba, hi: 0xba},
// Block 0x5a, offset 0x282
{value: 0x0012, lo: 0x80, hi: 0xab},
{value: 0x0015, lo: 0xac, hi: 0xbf},
// Block 0x5b, offset 0x284
{value: 0x0015, lo: 0x80, hi: 0xaa},
{value: 0x0012, lo: 0xab, hi: 0xb7},
{value: 0x0015, lo: 0xb8, hi: 0xb8},
{value: 0x8752, lo: 0xb9, hi: 0xb9},
{value: 0x0012, lo: 0xba, hi: 0xbc},
{value: 0x8b52, lo: 0xbd, hi: 0xbd},
{value: 0x0012, lo: 0xbe, hi: 0xbf},
// Block 0x5c, offset 0x28b
{value: 0x0012, lo: 0x80, hi: 0x8d},
{value: 0x8f52, lo: 0x8e, hi: 0x8e},
{value: 0x0012, lo: 0x8f, hi: 0x9a},
{value: 0x0015, lo: 0x9b, hi: 0xbf},
// Block 0x5d, offset 0x28f
{value: 0x0024, lo: 0x80, hi: 0x81},
{value: 0x0034, lo: 0x82, hi: 0x82},
{value: 0x0024, lo: 0x83, hi: 0x89},
{value: 0x0034, lo: 0x8a, hi: 0x8a},
{value: 0x0024, lo: 0x8b, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x90},
{value: 0x0024, lo: 0x91, hi: 0xb5},
{value: 0x0034, lo: 0xb6, hi: 0xba},
{value: 0x0024, lo: 0xbb, hi: 0xbb},
{value: 0x0034, lo: 0xbc, hi: 0xbd},
{value: 0x0024, lo: 0xbe, hi: 0xbe},
{value: 0x0034, lo: 0xbf, hi: 0xbf},
// Block 0x5e, offset 0x29b
{value: 0x0117, lo: 0x80, hi: 0xbf},
// Block 0x5f, offset 0x29c
{value: 0x0117, lo: 0x80, hi: 0x95},
{value: 0x369a, lo: 0x96, hi: 0x96},
{value: 0x374a, lo: 0x97, hi: 0x97},
{value: 0x37fa, lo: 0x98, hi: 0x98},
{value: 0x38aa, lo: 0x99, hi: 0x99},
{value: 0x395a, lo: 0x9a, hi: 0x9a},
{value: 0x3a0a, lo: 0x9b, hi: 0x9b},
{value: 0x0012, lo: 0x9c, hi: 0x9d},
{value: 0x3abb, lo: 0x9e, hi: 0x9e},
{value: 0x0012, lo: 0x9f, hi: 0x9f},
{value: 0x0117, lo: 0xa0, hi: 0xbf},
// Block 0x60, offset 0x2a7
{value: 0x0812, lo: 0x80, hi: 0x87},
{value: 0x0813, lo: 0x88, hi: 0x8f},
{value: 0x0812, lo: 0x90, hi: 0x95},
{value: 0x0813, lo: 0x98, hi: 0x9d},
{value: 0x0812, lo: 0xa0, hi: 0xa7},
{value: 0x0813, lo: 0xa8, hi: 0xaf},
{value: 0x0812, lo: 0xb0, hi: 0xb7},
{value: 0x0813, lo: 0xb8, hi: 0xbf},
// Block 0x61, offset 0x2af
{value: 0x0004, lo: 0x8b, hi: 0x8b},
{value: 0x0014, lo: 0x8c, hi: 0x8f},
{value: 0x0054, lo: 0x98, hi: 0x99},
{value: 0x0054, lo: 0xa4, hi: 0xa4},
{value: 0x0054, lo: 0xa7, hi: 0xa7},
{value: 0x0014, lo: 0xaa, hi: 0xae},
{value: 0x0010, lo: 0xaf, hi: 0xaf},
{value: 0x0010, lo: 0xbf, hi: 0xbf},
// Block 0x62, offset 0x2b7
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x94, hi: 0x94},
{value: 0x0014, lo: 0xa0, hi: 0xa4},
{value: 0x0014, lo: 0xa6, hi: 0xaf},
{value: 0x0015, lo: 0xb1, hi: 0xb1},
{value: 0x0015, lo: 0xbf, hi: 0xbf},
// Block 0x63, offset 0x2bd
{value: 0x0015, lo: 0x90, hi: 0x9c},
// Block 0x64, offset 0x2be
{value: 0x0024, lo: 0x90, hi: 0x91},
{value: 0x0034, lo: 0x92, hi: 0x93},
{value: 0x0024, lo: 0x94, hi: 0x97},
{value: 0x0034, lo: 0x98, hi: 0x9a},
{value: 0x0024, lo: 0x9b, hi: 0x9c},
{value: 0x0014, lo: 0x9d, hi: 0xa0},
{value: 0x0024, lo: 0xa1, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa4},
{value: 0x0034, lo: 0xa5, hi: 0xa6},
{value: 0x0024, lo: 0xa7, hi: 0xa7},
{value: 0x0034, lo: 0xa8, hi: 0xa8},
{value: 0x0024, lo: 0xa9, hi: 0xa9},
{value: 0x0034, lo: 0xaa, hi: 0xaf},
{value: 0x0024, lo: 0xb0, hi: 0xb0},
// Block 0x65, offset 0x2cc
{value: 0x0016, lo: 0x85, hi: 0x86},
{value: 0x0012, lo: 0x87, hi: 0x89},
{value: 0xa452, lo: 0x8e, hi: 0x8e},
{value: 0x1013, lo: 0xa0, hi: 0xaf},
{value: 0x1012, lo: 0xb0, hi: 0xbf},
// Block 0x66, offset 0x2d1
{value: 0x0010, lo: 0x80, hi: 0x82},
{value: 0x0716, lo: 0x83, hi: 0x84},
{value: 0x0010, lo: 0x85, hi: 0x88},
// Block 0x67, offset 0x2d4
{value: 0xa753, lo: 0xb6, hi: 0xb7},
{value: 0xaa53, lo: 0xb8, hi: 0xb9},
{value: 0xad53, lo: 0xba, hi: 0xbb},
{value: 0xaa53, lo: 0xbc, hi: 0xbd},
{value: 0xa753, lo: 0xbe, hi: 0xbf},
// Block 0x68, offset 0x2d9
{value: 0x3013, lo: 0x80, hi: 0x8f},
{value: 0x6553, lo: 0x90, hi: 0x9f},
{value: 0xb053, lo: 0xa0, hi: 0xaf},
{value: 0x3012, lo: 0xb0, hi: 0xbf},
// Block 0x69, offset 0x2dd
{value: 0x0117, lo: 0x80, hi: 0xa3},
{value: 0x0012, lo: 0xa4, hi: 0xa4},
{value: 0x0716, lo: 0xab, hi: 0xac},
{value: 0x0316, lo: 0xad, hi: 0xae},
{value: 0x0024, lo: 0xaf, hi: 0xb1},
{value: 0x0117, lo: 0xb2, hi: 0xb3},
// Block 0x6a, offset 0x2e3
{value: 0x6c52, lo: 0x80, hi: 0x9f},
{value: 0x7052, lo: 0xa0, hi: 0xa5},
{value: 0x7052, lo: 0xa7, hi: 0xa7},
{value: 0x7052, lo: 0xad, hi: 0xad},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0x6b, offset 0x2e8
{value: 0x0010, lo: 0x80, hi: 0xa7},
{value: 0x0014, lo: 0xaf, hi: 0xaf},
{value: 0x0034, lo: 0xbf, hi: 0xbf},
// Block 0x6c, offset 0x2eb
{value: 0x0010, lo: 0x80, hi: 0x96},
{value: 0x0010, lo: 0xa0, hi: 0xa6},
{value: 0x0010, lo: 0xa8, hi: 0xae},
{value: 0x0010, lo: 0xb0, hi: 0xb6},
{value: 0x0010, lo: 0xb8, hi: 0xbe},
// Block 0x6d, offset 0x2f0
{value: 0x0010, lo: 0x80, hi: 0x86},
{value: 0x0010, lo: 0x88, hi: 0x8e},
{value: 0x0010, lo: 0x90, hi: 0x96},
{value: 0x0010, lo: 0x98, hi: 0x9e},
{value: 0x0024, lo: 0xa0, hi: 0xbf},
// Block 0x6e, offset 0x2f5
{value: 0x0014, lo: 0xaf, hi: 0xaf},
// Block 0x6f, offset 0x2f6
{value: 0x0014, lo: 0x85, hi: 0x85},
{value: 0x0034, lo: 0xaa, hi: 0xad},
{value: 0x0030, lo: 0xae, hi: 0xaf},
{value: 0x0004, lo: 0xb1, hi: 0xb5},
{value: 0x0014, lo: 0xbb, hi: 0xbb},
{value: 0x0010, lo: 0xbc, hi: 0xbc},
// Block 0x70, offset 0x2fc
{value: 0x0034, lo: 0x99, hi: 0x9a},
{value: 0x0004, lo: 0x9b, hi: 0x9e},
// Block 0x71, offset 0x2fe
{value: 0x0004, lo: 0xbc, hi: 0xbe},
// Block 0x72, offset 0x2ff
{value: 0x0010, lo: 0x85, hi: 0xaf},
{value: 0x0010, lo: 0xb1, hi: 0xbf},
// Block 0x73, offset 0x301
{value: 0x0010, lo: 0x80, hi: 0x8e},
{value: 0x0010, lo: 0xa0, hi: 0xbf},
// Block 0x74, offset 0x303
{value: 0x0010, lo: 0x80, hi: 0x94},
{value: 0x0014, lo: 0x95, hi: 0x95},
{value: 0x0010, lo: 0x96, hi: 0xbf},
// Block 0x75, offset 0x306
{value: 0x0010, lo: 0x80, hi: 0x8c},
// Block 0x76, offset 0x307
{value: 0x0010, lo: 0x90, hi: 0xb7},
{value: 0x0014, lo: 0xb8, hi: 0xbd},
// Block 0x77, offset 0x309
{value: 0x0010, lo: 0x80, hi: 0x8b},
{value: 0x0014, lo: 0x8c, hi: 0x8c},
{value: 0x0010, lo: 0x90, hi: 0xab},
// Block 0x78, offset 0x30c
{value: 0x0117, lo: 0x80, hi: 0xad},
{value: 0x0010, lo: 0xae, hi: 0xae},
{value: 0x0024, lo: 0xaf, hi: 0xaf},
{value: 0x0014, lo: 0xb0, hi: 0xb2},
{value: 0x0024, lo: 0xb4, hi: 0xbd},
{value: 0x0014, lo: 0xbf, hi: 0xbf},
// Block 0x79, offset 0x312
{value: 0x0117, lo: 0x80, hi: 0x9b},
{value: 0x0015, lo: 0x9c, hi: 0x9d},
{value: 0x0024, lo: 0x9e, hi: 0x9f},
{value: 0x0010, lo: 0xa0, hi: 0xbf},
// Block 0x7a, offset 0x316
{value: 0x0010, lo: 0x80, hi: 0xaf},
{value: 0x0024, lo: 0xb0, hi: 0xb1},
// Block 0x7b, offset 0x318
{value: 0x0004, lo: 0x80, hi: 0x87},
{value: 0x0014, lo: 0x88, hi: 0xa1},
{value: 0x0117, lo: 0xa2, hi: 0xaf},
{value: 0x0012, lo: 0xb0, hi: 0xb1},
{value: 0x0117, lo: 0xb2, hi: 0xbf},
// Block 0x7c, offset 0x31d
{value: 0x0117, lo: 0x80, hi: 0xaf},
{value: 0x0015, lo: 0xb0, hi: 0xb0},
{value: 0x0012, lo: 0xb1, hi: 0xb8},
{value: 0x0316, lo: 0xb9, hi: 0xba},
{value: 0x0716, lo: 0xbb, hi: 0xbc},
{value: 0x8753, lo: 0xbd, hi: 0xbd},
{value: 0x0117, lo: 0xbe, hi: 0xbf},
// Block 0x7d, offset 0x324
{value: 0x0117, lo: 0x80, hi: 0x83},
{value: 0x6553, lo: 0x84, hi: 0x84},
{value: 0x908b, lo: 0x85, hi: 0x85},
{value: 0x8f53, lo: 0x86, hi: 0x86},
{value: 0x0f16, lo: 0x87, hi: 0x88},
{value: 0x0316, lo: 0x89, hi: 0x8a},
{value: 0x0117, lo: 0x90, hi: 0x91},
{value: 0x0012, lo: 0x93, hi: 0x93},
{value: 0x0012, lo: 0x95, hi: 0x95},
{value: 0x0117, lo: 0x96, hi: 0x99},
{value: 0x0015, lo: 0xb2, hi: 0xb4},
{value: 0x0316, lo: 0xb5, hi: 0xb6},
{value: 0x0010, lo: 0xb7, hi: 0xb7},
{value: 0x0015, lo: 0xb8, hi: 0xb9},
{value: 0x0012, lo: 0xba, hi: 0xba},
{value: 0x0010, lo: 0xbb, hi: 0xbf},
// Block 0x7e, offset 0x334
{value: 0x0010, lo: 0x80, hi: 0x81},
{value: 0x0014, lo: 0x82, hi: 0x82},
{value: 0x0010, lo: 0x83, hi: 0x85},
{value: 0x0034, lo: 0x86, hi: 0x86},
{value: 0x0010, lo: 0x87, hi: 0x8a},
{value: 0x0014, lo: 0x8b, hi: 0x8b},
{value: 0x0010, lo: 0x8c, hi: 0xa4},
{value: 0x0014, lo: 0xa5, hi: 0xa6},
{value: 0x0010, lo: 0xa7, hi: 0xa7},
{value: 0x0034, lo: 0xac, hi: 0xac},
// Block 0x7f, offset 0x33e
{value: 0x0010, lo: 0x80, hi: 0xb3},
// Block 0x80, offset 0x33f
{value: 0x0010, lo: 0x80, hi: 0x83},
{value: 0x0034, lo: 0x84, hi: 0x84},
{value: 0x0014, lo: 0x85, hi: 0x85},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0024, lo: 0xa0, hi: 0xb1},
{value: 0x0010, lo: 0xb2, hi: 0xb7},
{value: 0x0010, lo: 0xbb, hi: 0xbb},
{value: 0x0010, lo: 0xbd, hi: 0xbe},
{value: 0x0014, lo: 0xbf, hi: 0xbf},
// Block 0x81, offset 0x348
{value: 0x0010, lo: 0x80, hi: 0xa5},
{value: 0x0014, lo: 0xa6, hi: 0xaa},
{value: 0x0034, lo: 0xab, hi: 0xad},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0x82, offset 0x34c
{value: 0x0010, lo: 0x80, hi: 0x86},
{value: 0x0014, lo: 0x87, hi: 0x91},
{value: 0x0010, lo: 0x92, hi: 0x92},
{value: 0x0030, lo: 0x93, hi: 0x93},
{value: 0x0010, lo: 0xa0, hi: 0xbc},
// Block 0x83, offset 0x351
{value: 0x0014, lo: 0x80, hi: 0x82},
{value: 0x0010, lo: 0x83, hi: 0xb2},
{value: 0x0034, lo: 0xb3, hi: 0xb3},
{value: 0x0010, lo: 0xb4, hi: 0xb5},
{value: 0x0014, lo: 0xb6, hi: 0xb9},
{value: 0x0010, lo: 0xba, hi: 0xbb},
{value: 0x0014, lo: 0xbc, hi: 0xbd},
{value: 0x0010, lo: 0xbe, hi: 0xbf},
// Block 0x84, offset 0x359
{value: 0x0030, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x8f, hi: 0x8f},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0014, lo: 0xa5, hi: 0xa5},
{value: 0x0004, lo: 0xa6, hi: 0xa6},
{value: 0x0010, lo: 0xb0, hi: 0xb9},
// Block 0x85, offset 0x35f
{value: 0x0010, lo: 0x80, hi: 0xa8},
{value: 0x0014, lo: 0xa9, hi: 0xae},
{value: 0x0010, lo: 0xaf, hi: 0xb0},
{value: 0x0014, lo: 0xb1, hi: 0xb2},
{value: 0x0010, lo: 0xb3, hi: 0xb4},
{value: 0x0014, lo: 0xb5, hi: 0xb6},
// Block 0x86, offset 0x365
{value: 0x0010, lo: 0x80, hi: 0x82},
{value: 0x0014, lo: 0x83, hi: 0x83},
{value: 0x0010, lo: 0x84, hi: 0x8b},
{value: 0x0014, lo: 0x8c, hi: 0x8c},
{value: 0x0010, lo: 0x8d, hi: 0x8d},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0004, lo: 0xb0, hi: 0xb0},
{value: 0x0010, lo: 0xbb, hi: 0xbb},
{value: 0x0014, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbd, hi: 0xbd},
// Block 0x87, offset 0x36f
{value: 0x0024, lo: 0xb0, hi: 0xb0},
{value: 0x0024, lo: 0xb2, hi: 0xb3},
{value: 0x0034, lo: 0xb4, hi: 0xb4},
{value: 0x0024, lo: 0xb7, hi: 0xb8},
{value: 0x0024, lo: 0xbe, hi: 0xbf},
// Block 0x88, offset 0x374
{value: 0x0024, lo: 0x81, hi: 0x81},
{value: 0x0004, lo: 0x9d, hi: 0x9d},
{value: 0x0010, lo: 0xa0, hi: 0xab},
{value: 0x0014, lo: 0xac, hi: 0xad},
{value: 0x0010, lo: 0xae, hi: 0xaf},
{value: 0x0010, lo: 0xb2, hi: 0xb2},
{value: 0x0014, lo: 0xb3, hi: 0xb4},
{value: 0x0010, lo: 0xb5, hi: 0xb5},
{value: 0x0034, lo: 0xb6, hi: 0xb6},
// Block 0x89, offset 0x37d
{value: 0x0010, lo: 0x81, hi: 0x86},
{value: 0x0010, lo: 0x89, hi: 0x8e},
{value: 0x0010, lo: 0x91, hi: 0x96},
{value: 0x0010, lo: 0xa0, hi: 0xa6},
{value: 0x0010, lo: 0xa8, hi: 0xae},
{value: 0x0012, lo: 0xb0, hi: 0xbf},
// Block 0x8a, offset 0x383
{value: 0x0012, lo: 0x80, hi: 0x92},
{value: 0xb352, lo: 0x93, hi: 0x93},
{value: 0x0012, lo: 0x94, hi: 0x9a},
{value: 0x0014, lo: 0x9b, hi: 0x9b},
{value: 0x0015, lo: 0x9c, hi: 0x9f},
{value: 0x0012, lo: 0xa0, hi: 0xa8},
{value: 0x0015, lo: 0xa9, hi: 0xa9},
{value: 0x0004, lo: 0xaa, hi: 0xab},
{value: 0x74d2, lo: 0xb0, hi: 0xbf},
// Block 0x8b, offset 0x38c
{value: 0x78d2, lo: 0x80, hi: 0x8f},
{value: 0x7cd2, lo: 0x90, hi: 0x9f},
{value: 0x80d2, lo: 0xa0, hi: 0xaf},
{value: 0x7cd2, lo: 0xb0, hi: 0xbf},
// Block 0x8c, offset 0x390
{value: 0x0010, lo: 0x80, hi: 0xa4},
{value: 0x0014, lo: 0xa5, hi: 0xa5},
{value: 0x0010, lo: 0xa6, hi: 0xa7},
{value: 0x0014, lo: 0xa8, hi: 0xa8},
{value: 0x0010, lo: 0xa9, hi: 0xaa},
{value: 0x0010, lo: 0xac, hi: 0xac},
{value: 0x0034, lo: 0xad, hi: 0xad},
{value: 0x0010, lo: 0xb0, hi: 0xb9},
// Block 0x8d, offset 0x398
{value: 0x0010, lo: 0x80, hi: 0xa3},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0x8e, offset 0x39a
{value: 0x0010, lo: 0x80, hi: 0x86},
{value: 0x0010, lo: 0x8b, hi: 0xbb},
// Block 0x8f, offset 0x39c
{value: 0x0010, lo: 0x80, hi: 0x81},
{value: 0x0010, lo: 0x83, hi: 0x84},
{value: 0x0010, lo: 0x86, hi: 0xbf},
// Block 0x90, offset 0x39f
{value: 0x0010, lo: 0x80, hi: 0xb1},
{value: 0x0004, lo: 0xb2, hi: 0xbf},
// Block 0x91, offset 0x3a1
{value: 0x0004, lo: 0x80, hi: 0x82},
{value: 0x0010, lo: 0x93, hi: 0xbf},
// Block 0x92, offset 0x3a3
{value: 0x0010, lo: 0x80, hi: 0xbd},
// Block 0x93, offset 0x3a4
{value: 0x0010, lo: 0x90, hi: 0xbf},
// Block 0x94, offset 0x3a5
{value: 0x0010, lo: 0x80, hi: 0x8f},
{value: 0x0010, lo: 0x92, hi: 0xbf},
// Block 0x95, offset 0x3a7
{value: 0x0010, lo: 0x80, hi: 0x87},
{value: 0x0010, lo: 0xb0, hi: 0xbb},
// Block 0x96, offset 0x3a9
{value: 0x0014, lo: 0x80, hi: 0x8f},
{value: 0x0054, lo: 0x93, hi: 0x93},
{value: 0x0024, lo: 0xa0, hi: 0xa6},
{value: 0x0034, lo: 0xa7, hi: 0xad},
{value: 0x0024, lo: 0xae, hi: 0xaf},
{value: 0x0010, lo: 0xb3, hi: 0xb4},
// Block 0x97, offset 0x3af
{value: 0x0010, lo: 0x8d, hi: 0x8f},
{value: 0x0054, lo: 0x92, hi: 0x92},
{value: 0x0054, lo: 0x95, hi: 0x95},
{value: 0x0010, lo: 0xb0, hi: 0xb4},
{value: 0x0010, lo: 0xb6, hi: 0xbf},
// Block 0x98, offset 0x3b4
{value: 0x0010, lo: 0x80, hi: 0xbc},
{value: 0x0014, lo: 0xbf, hi: 0xbf},
// Block 0x99, offset 0x3b6
{value: 0x0054, lo: 0x87, hi: 0x87},
{value: 0x0054, lo: 0x8e, hi: 0x8e},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0054, lo: 0x9a, hi: 0x9a},
{value: 0x5f53, lo: 0xa1, hi: 0xba},
{value: 0x0004, lo: 0xbe, hi: 0xbe},
{value: 0x0010, lo: 0xbf, hi: 0xbf},
// Block 0x9a, offset 0x3bd
{value: 0x0004, lo: 0x80, hi: 0x80},
{value: 0x5f52, lo: 0x81, hi: 0x9a},
{value: 0x0004, lo: 0xb0, hi: 0xb0},
// Block 0x9b, offset 0x3c0
{value: 0x0014, lo: 0x9e, hi: 0x9f},
{value: 0x0010, lo: 0xa0, hi: 0xbe},
// Block 0x9c, offset 0x3c2
{value: 0x0010, lo: 0x82, hi: 0x87},
{value: 0x0010, lo: 0x8a, hi: 0x8f},
{value: 0x0010, lo: 0x92, hi: 0x97},
{value: 0x0010, lo: 0x9a, hi: 0x9c},
{value: 0x0004, lo: 0xa3, hi: 0xa3},
{value: 0x0014, lo: 0xb9, hi: 0xbb},
// Block 0x9d, offset 0x3c8
{value: 0x0010, lo: 0x80, hi: 0x8b},
{value: 0x0010, lo: 0x8d, hi: 0xa6},
{value: 0x0010, lo: 0xa8, hi: 0xba},
{value: 0x0010, lo: 0xbc, hi: 0xbd},
{value: 0x0010, lo: 0xbf, hi: 0xbf},
// Block 0x9e, offset 0x3cd
{value: 0x0010, lo: 0x80, hi: 0x8d},
{value: 0x0010, lo: 0x90, hi: 0x9d},
// Block 0x9f, offset 0x3cf
{value: 0x0010, lo: 0x80, hi: 0xba},
// Block 0xa0, offset 0x3d0
{value: 0x0010, lo: 0x80, hi: 0xb4},
// Block 0xa1, offset 0x3d1
{value: 0x0034, lo: 0xbd, hi: 0xbd},
// Block 0xa2, offset 0x3d2
{value: 0x0010, lo: 0x80, hi: 0x9c},
{value: 0x0010, lo: 0xa0, hi: 0xbf},
// Block 0xa3, offset 0x3d4
{value: 0x0010, lo: 0x80, hi: 0x90},
{value: 0x0034, lo: 0xa0, hi: 0xa0},
// Block 0xa4, offset 0x3d6
{value: 0x0010, lo: 0x80, hi: 0x9f},
{value: 0x0010, lo: 0xad, hi: 0xbf},
// Block 0xa5, offset 0x3d8
{value: 0x0010, lo: 0x80, hi: 0x8a},
{value: 0x0010, lo: 0x90, hi: 0xb5},
{value: 0x0024, lo: 0xb6, hi: 0xba},
// Block 0xa6, offset 0x3db
{value: 0x0010, lo: 0x80, hi: 0x9d},
{value: 0x0010, lo: 0xa0, hi: 0xbf},
// Block 0xa7, offset 0x3dd
{value: 0x0010, lo: 0x80, hi: 0x83},
{value: 0x0010, lo: 0x88, hi: 0x8f},
{value: 0x0010, lo: 0x91, hi: 0x95},
// Block 0xa8, offset 0x3e0
{value: 0x2813, lo: 0x80, hi: 0x87},
{value: 0x3813, lo: 0x88, hi: 0x8f},
{value: 0x2813, lo: 0x90, hi: 0x97},
{value: 0xb653, lo: 0x98, hi: 0x9f},
{value: 0xb953, lo: 0xa0, hi: 0xa7},
{value: 0x2812, lo: 0xa8, hi: 0xaf},
{value: 0x3812, lo: 0xb0, hi: 0xb7},
{value: 0x2812, lo: 0xb8, hi: 0xbf},
// Block 0xa9, offset 0x3e8
{value: 0xb652, lo: 0x80, hi: 0x87},
{value: 0xb952, lo: 0x88, hi: 0x8f},
{value: 0x0010, lo: 0x90, hi: 0xbf},
// Block 0xaa, offset 0x3eb
{value: 0x0010, lo: 0x80, hi: 0x9d},
{value: 0x0010, lo: 0xa0, hi: 0xa9},
{value: 0xb953, lo: 0xb0, hi: 0xb7},
{value: 0xb653, lo: 0xb8, hi: 0xbf},
// Block 0xab, offset 0x3ef
{value: 0x2813, lo: 0x80, hi: 0x87},
{value: 0x3813, lo: 0x88, hi: 0x8f},
{value: 0x2813, lo: 0x90, hi: 0x93},
{value: 0xb952, lo: 0x98, hi: 0x9f},
{value: 0xb652, lo: 0xa0, hi: 0xa7},
{value: 0x2812, lo: 0xa8, hi: 0xaf},
{value: 0x3812, lo: 0xb0, hi: 0xb7},
{value: 0x2812, lo: 0xb8, hi: 0xbb},
// Block 0xac, offset 0x3f7
{value: 0x0010, lo: 0x80, hi: 0xa7},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0xad, offset 0x3f9
{value: 0x0010, lo: 0x80, hi: 0xa3},
{value: 0xbc53, lo: 0xb0, hi: 0xb0},
{value: 0xbf53, lo: 0xb1, hi: 0xb1},
{value: 0xc253, lo: 0xb2, hi: 0xb2},
{value: 0xbf53, lo: 0xb3, hi: 0xb3},
{value: 0xc553, lo: 0xb4, hi: 0xb4},
{value: 0xbf53, lo: 0xb5, hi: 0xb5},
{value: 0xc253, lo: 0xb6, hi: 0xb6},
{value: 0xbf53, lo: 0xb7, hi: 0xb7},
{value: 0xbc53, lo: 0xb8, hi: 0xb8},
{value: 0xc853, lo: 0xb9, hi: 0xb9},
{value: 0xcb53, lo: 0xba, hi: 0xba},
{value: 0xce53, lo: 0xbc, hi: 0xbc},
{value: 0xc853, lo: 0xbd, hi: 0xbd},
{value: 0xcb53, lo: 0xbe, hi: 0xbe},
{value: 0xc853, lo: 0xbf, hi: 0xbf},
// Block 0xae, offset 0x409
{value: 0x0010, lo: 0x80, hi: 0xb6},
// Block 0xaf, offset 0x40a
{value: 0x0010, lo: 0x80, hi: 0x95},
{value: 0x0010, lo: 0xa0, hi: 0xa7},
// Block 0xb0, offset 0x40c
{value: 0x0015, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x82},
{value: 0x0015, lo: 0x83, hi: 0x85},
{value: 0x0015, lo: 0x87, hi: 0xb0},
{value: 0x0015, lo: 0xb2, hi: 0xba},
// Block 0xb1, offset 0x411
{value: 0x0010, lo: 0x80, hi: 0x85},
{value: 0x0010, lo: 0x88, hi: 0x88},
{value: 0x0010, lo: 0x8a, hi: 0xb5},
{value: 0x0010, lo: 0xb7, hi: 0xb8},
{value: 0x0010, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbf, hi: 0xbf},
// Block 0xb2, offset 0x417
{value: 0x0010, lo: 0x80, hi: 0x95},
{value: 0x0010, lo: 0xa0, hi: 0xb6},
// Block 0xb3, offset 0x419
{value: 0x0010, lo: 0x80, hi: 0x9e},
// Block 0xb4, offset 0x41a
{value: 0x0010, lo: 0xa0, hi: 0xb2},
{value: 0x0010, lo: 0xb4, hi: 0xb5},
// Block 0xb5, offset 0x41c
{value: 0x0010, lo: 0x80, hi: 0x95},
{value: 0x0010, lo: 0xa0, hi: 0xb9},
// Block 0xb6, offset 0x41e
{value: 0x0010, lo: 0x80, hi: 0xb7},
{value: 0x0010, lo: 0xbe, hi: 0xbf},
// Block 0xb7, offset 0x420
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x83},
{value: 0x0014, lo: 0x85, hi: 0x86},
{value: 0x0014, lo: 0x8c, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0014, lo: 0x8e, hi: 0x8e},
{value: 0x0024, lo: 0x8f, hi: 0x8f},
{value: 0x0010, lo: 0x90, hi: 0x93},
{value: 0x0010, lo: 0x95, hi: 0x97},
{value: 0x0010, lo: 0x99, hi: 0xb5},
{value: 0x0024, lo: 0xb8, hi: 0xb8},
{value: 0x0034, lo: 0xb9, hi: 0xba},
{value: 0x0034, lo: 0xbf, hi: 0xbf},
// Block 0xb8, offset 0x42d
{value: 0x0010, lo: 0xa0, hi: 0xbc},
// Block 0xb9, offset 0x42e
{value: 0x0010, lo: 0x80, hi: 0x9c},
// Block 0xba, offset 0x42f
{value: 0x0010, lo: 0x80, hi: 0x87},
{value: 0x0010, lo: 0x89, hi: 0xa4},
{value: 0x0024, lo: 0xa5, hi: 0xa5},
{value: 0x0034, lo: 0xa6, hi: 0xa6},
// Block 0xbb, offset 0x433
{value: 0x0010, lo: 0x80, hi: 0x95},
{value: 0x0010, lo: 0xa0, hi: 0xb2},
// Block 0xbc, offset 0x435
{value: 0x0010, lo: 0x80, hi: 0x91},
// Block 0xbd, offset 0x436
{value: 0x0010, lo: 0x80, hi: 0x88},
// Block 0xbe, offset 0x437
{value: 0x5653, lo: 0x80, hi: 0xb2},
// Block 0xbf, offset 0x438
{value: 0x5652, lo: 0x80, hi: 0xb2},
// Block 0xc0, offset 0x439
{value: 0x0010, lo: 0x80, hi: 0xa3},
{value: 0x0024, lo: 0xa4, hi: 0xa7},
{value: 0x0010, lo: 0xb0, hi: 0xb9},
// Block 0xc1, offset 0x43c
{value: 0x0010, lo: 0x80, hi: 0xa9},
{value: 0x0024, lo: 0xab, hi: 0xac},
{value: 0x0010, lo: 0xb0, hi: 0xb1},
// Block 0xc2, offset 0x43f
{value: 0x0034, lo: 0xbd, hi: 0xbf},
// Block 0xc3, offset 0x440
{value: 0x0010, lo: 0x80, hi: 0x9c},
{value: 0x0010, lo: 0xa7, hi: 0xa7},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0xc4, offset 0x443
{value: 0x0010, lo: 0x80, hi: 0x85},
{value: 0x0034, lo: 0x86, hi: 0x87},
{value: 0x0024, lo: 0x88, hi: 0x8a},
{value: 0x0034, lo: 0x8b, hi: 0x8b},
{value: 0x0024, lo: 0x8c, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x90},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0xc5, offset 0x44a
{value: 0x0010, lo: 0x80, hi: 0x81},
{value: 0x0024, lo: 0x82, hi: 0x82},
{value: 0x0034, lo: 0x83, hi: 0x83},
{value: 0x0024, lo: 0x84, hi: 0x84},
{value: 0x0034, lo: 0x85, hi: 0x85},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0xc6, offset 0x450
{value: 0x0010, lo: 0x80, hi: 0x84},
{value: 0x0010, lo: 0xa0, hi: 0xb6},
// Block 0xc7, offset 0x452
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x81},
{value: 0x0010, lo: 0x82, hi: 0xb7},
{value: 0x0014, lo: 0xb8, hi: 0xbf},
// Block 0xc8, offset 0x456
{value: 0x0014, lo: 0x80, hi: 0x85},
{value: 0x0034, lo: 0x86, hi: 0x86},
{value: 0x0010, lo: 0xa6, hi: 0xaf},
{value: 0x0034, lo: 0xb0, hi: 0xb0},
{value: 0x0010, lo: 0xb1, hi: 0xb2},
{value: 0x0014, lo: 0xb3, hi: 0xb4},
{value: 0x0010, lo: 0xb5, hi: 0xb5},
{value: 0x0034, lo: 0xbf, hi: 0xbf},
// Block 0xc9, offset 0x45e
{value: 0x0014, lo: 0x80, hi: 0x81},
{value: 0x0010, lo: 0x82, hi: 0xb2},
{value: 0x0014, lo: 0xb3, hi: 0xb6},
{value: 0x0010, lo: 0xb7, hi: 0xb8},
{value: 0x0034, lo: 0xb9, hi: 0xba},
{value: 0x0014, lo: 0xbd, hi: 0xbd},
// Block 0xca, offset 0x464
{value: 0x0014, lo: 0x82, hi: 0x82},
{value: 0x0014, lo: 0x8d, hi: 0x8d},
{value: 0x0010, lo: 0x90, hi: 0xa8},
{value: 0x0010, lo: 0xb0, hi: 0xb9},
// Block 0xcb, offset 0x468
{value: 0x0024, lo: 0x80, hi: 0x82},
{value: 0x0010, lo: 0x83, hi: 0xa6},
{value: 0x0014, lo: 0xa7, hi: 0xab},
{value: 0x0010, lo: 0xac, hi: 0xac},
{value: 0x0014, lo: 0xad, hi: 0xb2},
{value: 0x0034, lo: 0xb3, hi: 0xb4},
{value: 0x0010, lo: 0xb6, hi: 0xbf},
// Block 0xcc, offset 0x46f
{value: 0x0010, lo: 0x84, hi: 0x87},
{value: 0x0010, lo: 0x90, hi: 0xb2},
{value: 0x0034, lo: 0xb3, hi: 0xb3},
{value: 0x0010, lo: 0xb6, hi: 0xb6},
// Block 0xcd, offset 0x473
{value: 0x0014, lo: 0x80, hi: 0x81},
{value: 0x0010, lo: 0x82, hi: 0xb5},
{value: 0x0014, lo: 0xb6, hi: 0xbe},
{value: 0x0010, lo: 0xbf, hi: 0xbf},
// Block 0xce, offset 0x477
{value: 0x0030, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x81, hi: 0x84},
{value: 0x0014, lo: 0x89, hi: 0x89},
{value: 0x0034, lo: 0x8a, hi: 0x8a},
{value: 0x0014, lo: 0x8b, hi: 0x8c},
{value: 0x0010, lo: 0x8e, hi: 0x8e},
{value: 0x0014, lo: 0x8f, hi: 0x8f},
{value: 0x0010, lo: 0x90, hi: 0x9a},
{value: 0x0010, lo: 0x9c, hi: 0x9c},
// Block 0xcf, offset 0x480
{value: 0x0010, lo: 0x80, hi: 0x91},
{value: 0x0010, lo: 0x93, hi: 0xae},
{value: 0x0014, lo: 0xaf, hi: 0xb1},
{value: 0x0010, lo: 0xb2, hi: 0xb3},
{value: 0x0014, lo: 0xb4, hi: 0xb4},
{value: 0x0030, lo: 0xb5, hi: 0xb5},
{value: 0x0034, lo: 0xb6, hi: 0xb6},
{value: 0x0014, lo: 0xb7, hi: 0xb7},
{value: 0x0014, lo: 0xbe, hi: 0xbe},
{value: 0x0010, lo: 0xbf, hi: 0xbf},
// Block 0xd0, offset 0x48a
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x81},
// Block 0xd1, offset 0x48c
{value: 0x0010, lo: 0x80, hi: 0x86},
{value: 0x0010, lo: 0x88, hi: 0x88},
{value: 0x0010, lo: 0x8a, hi: 0x8d},
{value: 0x0010, lo: 0x8f, hi: 0x9d},
{value: 0x0010, lo: 0x9f, hi: 0xa8},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0xd2, offset 0x492
{value: 0x0010, lo: 0x80, hi: 0x9e},
{value: 0x0014, lo: 0x9f, hi: 0x9f},
{value: 0x0010, lo: 0xa0, hi: 0xa2},
{value: 0x0014, lo: 0xa3, hi: 0xa8},
{value: 0x0034, lo: 0xa9, hi: 0xaa},
{value: 0x0010, lo: 0xb0, hi: 0xb9},
// Block 0xd3, offset 0x498
{value: 0x0014, lo: 0x80, hi: 0x81},
{value: 0x0010, lo: 0x82, hi: 0x83},
{value: 0x0010, lo: 0x85, hi: 0x8c},
{value: 0x0010, lo: 0x8f, hi: 0x90},
{value: 0x0010, lo: 0x93, hi: 0xa8},
{value: 0x0010, lo: 0xaa, hi: 0xb0},
{value: 0x0010, lo: 0xb2, hi: 0xb3},
{value: 0x0010, lo: 0xb5, hi: 0xb9},
{value: 0x0034, lo: 0xbb, hi: 0xbc},
{value: 0x0010, lo: 0xbd, hi: 0xbf},
// Block 0xd4, offset 0x4a2
{value: 0x0014, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x81, hi: 0x84},
{value: 0x0010, lo: 0x87, hi: 0x88},
{value: 0x0010, lo: 0x8b, hi: 0x8c},
{value: 0x0030, lo: 0x8d, hi: 0x8d},
{value: 0x0010, lo: 0x90, hi: 0x90},
{value: 0x0010, lo: 0x97, hi: 0x97},
{value: 0x0010, lo: 0x9d, hi: 0xa3},
{value: 0x0024, lo: 0xa6, hi: 0xac},
{value: 0x0024, lo: 0xb0, hi: 0xb4},
// Block 0xd5, offset 0x4ac
{value: 0x0010, lo: 0x80, hi: 0xb7},
{value: 0x0014, lo: 0xb8, hi: 0xbf},
// Block 0xd6, offset 0x4ae
{value: 0x0010, lo: 0x80, hi: 0x81},
{value: 0x0034, lo: 0x82, hi: 0x82},
{value: 0x0014, lo: 0x83, hi: 0x84},
{value: 0x0010, lo: 0x85, hi: 0x85},
{value: 0x0034, lo: 0x86, hi: 0x86},
{value: 0x0010, lo: 0x87, hi: 0x8a},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0024, lo: 0x9e, hi: 0x9e},
{value: 0x0010, lo: 0x9f, hi: 0xa1},
// Block 0xd7, offset 0x4b7
{value: 0x0010, lo: 0x80, hi: 0xb2},
{value: 0x0014, lo: 0xb3, hi: 0xb8},
{value: 0x0010, lo: 0xb9, hi: 0xb9},
{value: 0x0014, lo: 0xba, hi: 0xba},
{value: 0x0010, lo: 0xbb, hi: 0xbe},
{value: 0x0014, lo: 0xbf, hi: 0xbf},
// Block 0xd8, offset 0x4bd
{value: 0x0014, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x81, hi: 0x81},
{value: 0x0034, lo: 0x82, hi: 0x83},
{value: 0x0010, lo: 0x84, hi: 0x85},
{value: 0x0010, lo: 0x87, hi: 0x87},
{value: 0x0010, lo: 0x90, hi: 0x99},
// Block 0xd9, offset 0x4c3
{value: 0x0010, lo: 0x80, hi: 0xb1},
{value: 0x0014, lo: 0xb2, hi: 0xb5},
{value: 0x0010, lo: 0xb8, hi: 0xbb},
{value: 0x0014, lo: 0xbc, hi: 0xbd},
{value: 0x0010, lo: 0xbe, hi: 0xbe},
{value: 0x0034, lo: 0xbf, hi: 0xbf},
// Block 0xda, offset 0x4c9
{value: 0x0034, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x98, hi: 0x9b},
{value: 0x0014, lo: 0x9c, hi: 0x9d},
// Block 0xdb, offset 0x4cc
{value: 0x0010, lo: 0x80, hi: 0xb2},
{value: 0x0014, lo: 0xb3, hi: 0xba},
{value: 0x0010, lo: 0xbb, hi: 0xbc},
{value: 0x0014, lo: 0xbd, hi: 0xbd},
{value: 0x0010, lo: 0xbe, hi: 0xbe},
{value: 0x0034, lo: 0xbf, hi: 0xbf},
// Block 0xdc, offset 0x4d2
{value: 0x0014, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x84, hi: 0x84},
{value: 0x0010, lo: 0x90, hi: 0x99},
// Block 0xdd, offset 0x4d5
{value: 0x0010, lo: 0x80, hi: 0xaa},
{value: 0x0014, lo: 0xab, hi: 0xab},
{value: 0x0010, lo: 0xac, hi: 0xac},
{value: 0x0014, lo: 0xad, hi: 0xad},
{value: 0x0010, lo: 0xae, hi: 0xaf},
{value: 0x0014, lo: 0xb0, hi: 0xb5},
{value: 0x0030, lo: 0xb6, hi: 0xb6},
{value: 0x0034, lo: 0xb7, hi: 0xb7},
{value: 0x0010, lo: 0xb8, hi: 0xb8},
// Block 0xde, offset 0x4de
{value: 0x0010, lo: 0x80, hi: 0x89},
// Block 0xdf, offset 0x4df
{value: 0x0014, lo: 0x9d, hi: 0x9f},
{value: 0x0010, lo: 0xa0, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa5},
{value: 0x0010, lo: 0xa6, hi: 0xa6},
{value: 0x0014, lo: 0xa7, hi: 0xaa},
{value: 0x0034, lo: 0xab, hi: 0xab},
{value: 0x0010, lo: 0xb0, hi: 0xb9},
// Block 0xe0, offset 0x4e6
{value: 0x0010, lo: 0x80, hi: 0xae},
{value: 0x0014, lo: 0xaf, hi: 0xb7},
{value: 0x0010, lo: 0xb8, hi: 0xb8},
{value: 0x0034, lo: 0xb9, hi: 0xba},
// Block 0xe1, offset 0x4ea
{value: 0x5f53, lo: 0xa0, hi: 0xbf},
// Block 0xe2, offset 0x4eb
{value: 0x5f52, lo: 0x80, hi: 0x9f},
{value: 0x0010, lo: 0xa0, hi: 0xa9},
{value: 0x0010, lo: 0xbf, hi: 0xbf},
// Block 0xe3, offset 0x4ee
{value: 0x0010, lo: 0x80, hi: 0x86},
{value: 0x0010, lo: 0x89, hi: 0x89},
{value: 0x0010, lo: 0x8c, hi: 0x93},
{value: 0x0010, lo: 0x95, hi: 0x96},
{value: 0x0010, lo: 0x98, hi: 0xb5},
{value: 0x0010, lo: 0xb7, hi: 0xb8},
{value: 0x0014, lo: 0xbb, hi: 0xbc},
{value: 0x0030, lo: 0xbd, hi: 0xbd},
{value: 0x0034, lo: 0xbe, hi: 0xbe},
{value: 0x0010, lo: 0xbf, hi: 0xbf},
// Block 0xe4, offset 0x4f8
{value: 0x0010, lo: 0x80, hi: 0x82},
{value: 0x0034, lo: 0x83, hi: 0x83},
{value: 0x0010, lo: 0x90, hi: 0x99},
// Block 0xe5, offset 0x4fb
{value: 0x0010, lo: 0xa0, hi: 0xa7},
{value: 0x0010, lo: 0xaa, hi: 0xbf},
// Block 0xe6, offset 0x4fd
{value: 0x0010, lo: 0x80, hi: 0x93},
{value: 0x0014, lo: 0x94, hi: 0x97},
{value: 0x0014, lo: 0x9a, hi: 0x9b},
{value: 0x0010, lo: 0x9c, hi: 0x9f},
{value: 0x0034, lo: 0xa0, hi: 0xa0},
{value: 0x0010, lo: 0xa1, hi: 0xa1},
{value: 0x0010, lo: 0xa3, hi: 0xa4},
// Block 0xe7, offset 0x504
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x8a},
{value: 0x0010, lo: 0x8b, hi: 0xb2},
{value: 0x0014, lo: 0xb3, hi: 0xb3},
{value: 0x0034, lo: 0xb4, hi: 0xb4},
{value: 0x0014, lo: 0xb5, hi: 0xb8},
{value: 0x0010, lo: 0xb9, hi: 0xba},
{value: 0x0014, lo: 0xbb, hi: 0xbe},
// Block 0xe8, offset 0x50c
{value: 0x0034, lo: 0x87, hi: 0x87},
{value: 0x0010, lo: 0x90, hi: 0x90},
{value: 0x0014, lo: 0x91, hi: 0x96},
{value: 0x0010, lo: 0x97, hi: 0x98},
{value: 0x0014, lo: 0x99, hi: 0x9b},
{value: 0x0010, lo: 0x9c, hi: 0xbf},
// Block 0xe9, offset 0x512
{value: 0x0010, lo: 0x80, hi: 0x89},
{value: 0x0014, lo: 0x8a, hi: 0x96},
{value: 0x0010, lo: 0x97, hi: 0x97},
{value: 0x0014, lo: 0x98, hi: 0x98},
{value: 0x0034, lo: 0x99, hi: 0x99},
{value: 0x0010, lo: 0x9d, hi: 0x9d},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0xea, offset 0x519
{value: 0x0010, lo: 0x80, hi: 0xb8},
// Block 0xeb, offset 0x51a
{value: 0x0010, lo: 0x80, hi: 0x88},
{value: 0x0010, lo: 0x8a, hi: 0xaf},
{value: 0x0014, lo: 0xb0, hi: 0xb6},
{value: 0x0014, lo: 0xb8, hi: 0xbd},
{value: 0x0010, lo: 0xbe, hi: 0xbe},
{value: 0x0034, lo: 0xbf, hi: 0xbf},
// Block 0xec, offset 0x520
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0010, lo: 0xb2, hi: 0xbf},
// Block 0xed, offset 0x523
{value: 0x0010, lo: 0x80, hi: 0x8f},
{value: 0x0014, lo: 0x92, hi: 0xa7},
{value: 0x0010, lo: 0xa9, hi: 0xa9},
{value: 0x0014, lo: 0xaa, hi: 0xb0},
{value: 0x0010, lo: 0xb1, hi: 0xb1},
{value: 0x0014, lo: 0xb2, hi: 0xb3},
{value: 0x0010, lo: 0xb4, hi: 0xb4},
{value: 0x0014, lo: 0xb5, hi: 0xb6},
// Block 0xee, offset 0x52b
{value: 0x0010, lo: 0x80, hi: 0x86},
{value: 0x0010, lo: 0x88, hi: 0x89},
{value: 0x0010, lo: 0x8b, hi: 0xb0},
{value: 0x0014, lo: 0xb1, hi: 0xb6},
{value: 0x0014, lo: 0xba, hi: 0xba},
{value: 0x0014, lo: 0xbc, hi: 0xbd},
{value: 0x0014, lo: 0xbf, hi: 0xbf},
// Block 0xef, offset 0x532
{value: 0x0014, lo: 0x80, hi: 0x81},
{value: 0x0034, lo: 0x82, hi: 0x82},
{value: 0x0014, lo: 0x83, hi: 0x83},
{value: 0x0034, lo: 0x84, hi: 0x85},
{value: 0x0010, lo: 0x86, hi: 0x86},
{value: 0x0014, lo: 0x87, hi: 0x87},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0010, lo: 0xa0, hi: 0xa5},
{value: 0x0010, lo: 0xa7, hi: 0xa8},
{value: 0x0010, lo: 0xaa, hi: 0xbf},
// Block 0xf0, offset 0x53c
{value: 0x0010, lo: 0x80, hi: 0x8e},
{value: 0x0014, lo: 0x90, hi: 0x91},
{value: 0x0010, lo: 0x93, hi: 0x94},
{value: 0x0014, lo: 0x95, hi: 0x95},
{value: 0x0010, lo: 0x96, hi: 0x96},
{value: 0x0034, lo: 0x97, hi: 0x97},
{value: 0x0010, lo: 0x98, hi: 0x98},
{value: 0x0010, lo: 0xa0, hi: 0xa9},
// Block 0xf1, offset 0x544
{value: 0x0010, lo: 0xa0, hi: 0xb2},
{value: 0x0014, lo: 0xb3, hi: 0xb4},
{value: 0x0010, lo: 0xb5, hi: 0xb6},
// Block 0xf2, offset 0x547
{value: 0x0014, lo: 0x80, hi: 0x81},
{value: 0x0010, lo: 0x82, hi: 0x90},
{value: 0x0010, lo: 0x92, hi: 0xb5},
{value: 0x0014, lo: 0xb6, hi: 0xba},
{value: 0x0010, lo: 0xbe, hi: 0xbf},
// Block 0xf3, offset 0x54c
{value: 0x0014, lo: 0x80, hi: 0x80},
{value: 0x0030, lo: 0x81, hi: 0x81},
{value: 0x0034, lo: 0x82, hi: 0x82},
{value: 0x0010, lo: 0x90, hi: 0x99},
// Block 0xf4, offset 0x550
{value: 0x0010, lo: 0xb0, hi: 0xb0},
// Block 0xf5, offset 0x551
{value: 0x0010, lo: 0x80, hi: 0x99},
// Block 0xf6, offset 0x552
{value: 0x0010, lo: 0x80, hi: 0xae},
// Block 0xf7, offset 0x553
{value: 0x0010, lo: 0x80, hi: 0x83},
// Block 0xf8, offset 0x554
{value: 0x0010, lo: 0x80, hi: 0xb0},
// Block 0xf9, offset 0x555
{value: 0x0010, lo: 0x80, hi: 0xaf},
{value: 0x0014, lo: 0xb0, hi: 0xbf},
// Block 0xfa, offset 0x557
{value: 0x0014, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x81, hi: 0x86},
{value: 0x0014, lo: 0x87, hi: 0x95},
// Block 0xfb, offset 0x55a
{value: 0x0010, lo: 0x80, hi: 0x86},
// Block 0xfc, offset 0x55b
{value: 0x0010, lo: 0x80, hi: 0x9e},
{value: 0x0010, lo: 0xa0, hi: 0xa9},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0xfd, offset 0x55e
{value: 0x0010, lo: 0x80, hi: 0xbe},
// Block 0xfe, offset 0x55f
{value: 0x0010, lo: 0x80, hi: 0x89},
{value: 0x0010, lo: 0x90, hi: 0xad},
{value: 0x0034, lo: 0xb0, hi: 0xb4},
// Block 0xff, offset 0x562
{value: 0x0010, lo: 0x80, hi: 0xaf},
{value: 0x0024, lo: 0xb0, hi: 0xb6},
// Block 0x100, offset 0x564
{value: 0x0014, lo: 0x80, hi: 0x83},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0010, lo: 0xa3, hi: 0xb7},
{value: 0x0010, lo: 0xbd, hi: 0xbf},
// Block 0x101, offset 0x568
{value: 0x0010, lo: 0x80, hi: 0x8f},
// Block 0x102, offset 0x569
{value: 0x2013, lo: 0x80, hi: 0x9f},
{value: 0x2012, lo: 0xa0, hi: 0xbf},
// Block 0x103, offset 0x56b
{value: 0x0010, lo: 0x80, hi: 0x8a},
{value: 0x0014, lo: 0x8f, hi: 0x8f},
{value: 0x0010, lo: 0x90, hi: 0xbf},
// Block 0x104, offset 0x56e
{value: 0x0010, lo: 0x80, hi: 0x87},
{value: 0x0014, lo: 0x8f, hi: 0x9f},
// Block 0x105, offset 0x570
{value: 0x0014, lo: 0xa0, hi: 0xa1},
{value: 0x0014, lo: 0xa3, hi: 0xa4},
{value: 0x0030, lo: 0xb0, hi: 0xb1},
// Block 0x106, offset 0x573
{value: 0x0004, lo: 0xb0, hi: 0xb3},
{value: 0x0004, lo: 0xb5, hi: 0xbb},
{value: 0x0004, lo: 0xbd, hi: 0xbe},
// Block 0x107, offset 0x576
{value: 0x0010, lo: 0x80, hi: 0xaa},
{value: 0x0010, lo: 0xb0, hi: 0xbc},
// Block 0x108, offset 0x578
{value: 0x0010, lo: 0x80, hi: 0x88},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0014, lo: 0x9d, hi: 0x9d},
{value: 0x0034, lo: 0x9e, hi: 0x9e},
{value: 0x0014, lo: 0xa0, hi: 0xa3},
// Block 0x109, offset 0x57d
{value: 0x0014, lo: 0x80, hi: 0xad},
{value: 0x0014, lo: 0xb0, hi: 0xbf},
// Block 0x10a, offset 0x57f
{value: 0x0014, lo: 0x80, hi: 0x86},
// Block 0x10b, offset 0x580
{value: 0x0030, lo: 0xa5, hi: 0xa6},
{value: 0x0034, lo: 0xa7, hi: 0xa9},
{value: 0x0030, lo: 0xad, hi: 0xb2},
{value: 0x0014, lo: 0xb3, hi: 0xba},
{value: 0x0034, lo: 0xbb, hi: 0xbf},
// Block 0x10c, offset 0x585
{value: 0x0034, lo: 0x80, hi: 0x82},
{value: 0x0024, lo: 0x85, hi: 0x89},
{value: 0x0034, lo: 0x8a, hi: 0x8b},
{value: 0x0024, lo: 0xaa, hi: 0xad},
// Block 0x10d, offset 0x589
{value: 0x0024, lo: 0x82, hi: 0x84},
// Block 0x10e, offset 0x58a
{value: 0x0013, lo: 0x80, hi: 0x99},
{value: 0x0012, lo: 0x9a, hi: 0xb3},
{value: 0x0013, lo: 0xb4, hi: 0xbf},
// Block 0x10f, offset 0x58d
{value: 0x0013, lo: 0x80, hi: 0x8d},
{value: 0x0012, lo: 0x8e, hi: 0x94},
{value: 0x0012, lo: 0x96, hi: 0xa7},
{value: 0x0013, lo: 0xa8, hi: 0xbf},
// Block 0x110, offset 0x591
{value: 0x0013, lo: 0x80, hi: 0x81},
{value: 0x0012, lo: 0x82, hi: 0x9b},
{value: 0x0013, lo: 0x9c, hi: 0x9c},
{value: 0x0013, lo: 0x9e, hi: 0x9f},
{value: 0x0013, lo: 0xa2, hi: 0xa2},
{value: 0x0013, lo: 0xa5, hi: 0xa6},
{value: 0x0013, lo: 0xa9, hi: 0xac},
{value: 0x0013, lo: 0xae, hi: 0xb5},
{value: 0x0012, lo: 0xb6, hi: 0xb9},
{value: 0x0012, lo: 0xbb, hi: 0xbb},
{value: 0x0012, lo: 0xbd, hi: 0xbf},
// Block 0x111, offset 0x59c
{value: 0x0012, lo: 0x80, hi: 0x83},
{value: 0x0012, lo: 0x85, hi: 0x8f},
{value: 0x0013, lo: 0x90, hi: 0xa9},
{value: 0x0012, lo: 0xaa, hi: 0xbf},
// Block 0x112, offset 0x5a0
{value: 0x0012, lo: 0x80, hi: 0x83},
{value: 0x0013, lo: 0x84, hi: 0x85},
{value: 0x0013, lo: 0x87, hi: 0x8a},
{value: 0x0013, lo: 0x8d, hi: 0x94},
{value: 0x0013, lo: 0x96, hi: 0x9c},
{value: 0x0012, lo: 0x9e, hi: 0xb7},
{value: 0x0013, lo: 0xb8, hi: 0xb9},
{value: 0x0013, lo: 0xbb, hi: 0xbe},
// Block 0x113, offset 0x5a8
{value: 0x0013, lo: 0x80, hi: 0x84},
{value: 0x0013, lo: 0x86, hi: 0x86},
{value: 0x0013, lo: 0x8a, hi: 0x90},
{value: 0x0012, lo: 0x92, hi: 0xab},
{value: 0x0013, lo: 0xac, hi: 0xbf},
// Block 0x114, offset 0x5ad
{value: 0x0013, lo: 0x80, hi: 0x85},
{value: 0x0012, lo: 0x86, hi: 0x9f},
{value: 0x0013, lo: 0xa0, hi: 0xb9},
{value: 0x0012, lo: 0xba, hi: 0xbf},
// Block 0x115, offset 0x5b1
{value: 0x0012, lo: 0x80, hi: 0x93},
{value: 0x0013, lo: 0x94, hi: 0xad},
{value: 0x0012, lo: 0xae, hi: 0xbf},
// Block 0x116, offset 0x5b4
{value: 0x0012, lo: 0x80, hi: 0x87},
{value: 0x0013, lo: 0x88, hi: 0xa1},
{value: 0x0012, lo: 0xa2, hi: 0xbb},
{value: 0x0013, lo: 0xbc, hi: 0xbf},
// Block 0x117, offset 0x5b8
{value: 0x0013, lo: 0x80, hi: 0x95},
{value: 0x0012, lo: 0x96, hi: 0xaf},
{value: 0x0013, lo: 0xb0, hi: 0xbf},
// Block 0x118, offset 0x5bb
{value: 0x0013, lo: 0x80, hi: 0x89},
{value: 0x0012, lo: 0x8a, hi: 0xa5},
{value: 0x0013, lo: 0xa8, hi: 0xbf},
// Block 0x119, offset 0x5be
{value: 0x0013, lo: 0x80, hi: 0x80},
{value: 0x0012, lo: 0x82, hi: 0x9a},
{value: 0x0012, lo: 0x9c, hi: 0xa1},
{value: 0x0013, lo: 0xa2, hi: 0xba},
{value: 0x0012, lo: 0xbc, hi: 0xbf},
// Block 0x11a, offset 0x5c3
{value: 0x0012, lo: 0x80, hi: 0x94},
{value: 0x0012, lo: 0x96, hi: 0x9b},
{value: 0x0013, lo: 0x9c, hi: 0xb4},
{value: 0x0012, lo: 0xb6, hi: 0xbf},
// Block 0x11b, offset 0x5c7
{value: 0x0012, lo: 0x80, hi: 0x8e},
{value: 0x0012, lo: 0x90, hi: 0x95},
{value: 0x0013, lo: 0x96, hi: 0xae},
{value: 0x0012, lo: 0xb0, hi: 0xbf},
// Block 0x11c, offset 0x5cb
{value: 0x0012, lo: 0x80, hi: 0x88},
{value: 0x0012, lo: 0x8a, hi: 0x8f},
{value: 0x0013, lo: 0x90, hi: 0xa8},
{value: 0x0012, lo: 0xaa, hi: 0xbf},
// Block 0x11d, offset 0x5cf
{value: 0x0012, lo: 0x80, hi: 0x82},
{value: 0x0012, lo: 0x84, hi: 0x89},
{value: 0x0017, lo: 0x8a, hi: 0x8b},
{value: 0x0010, lo: 0x8e, hi: 0xbf},
// Block 0x11e, offset 0x5d3
{value: 0x0014, lo: 0x80, hi: 0xb6},
{value: 0x0014, lo: 0xbb, hi: 0xbf},
// Block 0x11f, offset 0x5d5
{value: 0x0014, lo: 0x80, hi: 0xac},
{value: 0x0014, lo: 0xb5, hi: 0xb5},
// Block 0x120, offset 0x5d7
{value: 0x0014, lo: 0x84, hi: 0x84},
{value: 0x0014, lo: 0x9b, hi: 0x9f},
{value: 0x0014, lo: 0xa1, hi: 0xaf},
// Block 0x121, offset 0x5da
{value: 0x0012, lo: 0x80, hi: 0x89},
{value: 0x0010, lo: 0x8a, hi: 0x8a},
{value: 0x0012, lo: 0x8b, hi: 0x9e},
{value: 0x0012, lo: 0xa5, hi: 0xaa},
// Block 0x122, offset 0x5de
{value: 0x0024, lo: 0x80, hi: 0x86},
{value: 0x0024, lo: 0x88, hi: 0x98},
{value: 0x0024, lo: 0x9b, hi: 0xa1},
{value: 0x0024, lo: 0xa3, hi: 0xa4},
{value: 0x0024, lo: 0xa6, hi: 0xaa},
{value: 0x0015, lo: 0xb0, hi: 0xbf},
// Block 0x123, offset 0x5e4
{value: 0x0015, lo: 0x80, hi: 0xad},
// Block 0x124, offset 0x5e5
{value: 0x0024, lo: 0x8f, hi: 0x8f},
// Block 0x125, offset 0x5e6
{value: 0x0010, lo: 0x80, hi: 0xac},
{value: 0x0024, lo: 0xb0, hi: 0xb6},
{value: 0x0014, lo: 0xb7, hi: 0xbd},
// Block 0x126, offset 0x5e9
{value: 0x0010, lo: 0x80, hi: 0x89},
{value: 0x0010, lo: 0x8e, hi: 0x8e},
// Block 0x127, offset 0x5eb
{value: 0x0010, lo: 0x90, hi: 0xad},
{value: 0x0024, lo: 0xae, hi: 0xae},
// Block 0x128, offset 0x5ed
{value: 0x0010, lo: 0x80, hi: 0xab},
{value: 0x0024, lo: 0xac, hi: 0xaf},
{value: 0x0010, lo: 0xb0, hi: 0xb9},
// Block 0x129, offset 0x5f0
{value: 0x0010, lo: 0x90, hi: 0xaa},
{value: 0x0014, lo: 0xab, hi: 0xab},
{value: 0x0034, lo: 0xac, hi: 0xae},
{value: 0x0024, lo: 0xaf, hi: 0xaf},
{value: 0x0010, lo: 0xb0, hi: 0xb9},
// Block 0x12a, offset 0x5f5
{value: 0x0010, lo: 0xa0, hi: 0xa6},
{value: 0x0010, lo: 0xa8, hi: 0xab},
{value: 0x0010, lo: 0xad, hi: 0xae},
{value: 0x0010, lo: 0xb0, hi: 0xbe},
// Block 0x12b, offset 0x5f9
{value: 0x0010, lo: 0x80, hi: 0x84},
{value: 0x0034, lo: 0x90, hi: 0x96},
// Block 0x12c, offset 0x5fb
{value: 0xd152, lo: 0x80, hi: 0x81},
{value: 0xd452, lo: 0x82, hi: 0x83},
{value: 0x0024, lo: 0x84, hi: 0x89},
{value: 0x0034, lo: 0x8a, hi: 0x8a},
{value: 0x0014, lo: 0x8b, hi: 0x8b},
{value: 0x0010, lo: 0x90, hi: 0x99},
// Block 0x12d, offset 0x601
{value: 0x0010, lo: 0x80, hi: 0x83},
{value: 0x0010, lo: 0x85, hi: 0x9f},
{value: 0x0010, lo: 0xa1, hi: 0xa2},
{value: 0x0010, lo: 0xa4, hi: 0xa4},
{value: 0x0010, lo: 0xa7, hi: 0xa7},
{value: 0x0010, lo: 0xa9, hi: 0xb2},
{value: 0x0010, lo: 0xb4, hi: 0xb7},
{value: 0x0010, lo: 0xb9, hi: 0xb9},
{value: 0x0010, lo: 0xbb, hi: 0xbb},
// Block 0x12e, offset 0x60a
{value: 0x0010, lo: 0x80, hi: 0x89},
{value: 0x0010, lo: 0x8b, hi: 0x9b},
{value: 0x0010, lo: 0xa1, hi: 0xa3},
{value: 0x0010, lo: 0xa5, hi: 0xa9},
{value: 0x0010, lo: 0xab, hi: 0xbb},
// Block 0x12f, offset 0x60f
{value: 0x0013, lo: 0xb0, hi: 0xbf},
// Block 0x130, offset 0x610
{value: 0x0013, lo: 0x80, hi: 0x89},
{value: 0x0013, lo: 0x90, hi: 0xa9},
{value: 0x0013, lo: 0xb0, hi: 0xbf},
// Block 0x131, offset 0x613
{value: 0x0013, lo: 0x80, hi: 0x89},
// Block 0x132, offset 0x614
{value: 0x0014, lo: 0xbb, hi: 0xbf},
// Block 0x133, offset 0x615
{value: 0x0010, lo: 0xb0, hi: 0xb9},
// Block 0x134, offset 0x616
{value: 0x0014, lo: 0x81, hi: 0x81},
{value: 0x0014, lo: 0xa0, hi: 0xbf},
// Block 0x135, offset 0x618
{value: 0x0014, lo: 0x80, hi: 0xbf},
// Block 0x136, offset 0x619
{value: 0x0014, lo: 0x80, hi: 0xaf},
}
// Total table size 16093 bytes (15KiB); checksum: EE91C452
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
package cases
// This file contains definitions for interpreting the trie value of the case
// trie generated by "go run gen*.go". It is shared by both the generator
// program and the resultant package. Sharing is achieved by the generator
// copying gen_trieval.go to trieval.go and changing what's above this comment.
// info holds case information for a single rune. It is the value returned
// by a trie lookup. Most mapping information can be stored in a single 16-bit
// value. If not, for example when a rune is mapped to multiple runes, the value
// stores some basic case data and an index into an array with additional data.
//
// The per-rune values have the following format:
//
// if (exception) {
// 15..4 unsigned exception index
// } else {
// 15..8 XOR pattern or index to XOR pattern for case mapping
// Only 13..8 are used for XOR patterns.
// 7 inverseFold (fold to upper, not to lower)
// 6 index: interpret the XOR pattern as an index
// or isMid if case mode is cIgnorableUncased.
// 5..4 CCC: zero (normal or break), above or other
// }
// 3 exception: interpret this value as an exception index
// (TODO: is this bit necessary? Probably implied from case mode.)
// 2..0 case mode
//
// For the non-exceptional cases, a rune must be either uncased, lowercase or
// uppercase. If the rune is cased, the XOR pattern maps either a lowercase
// rune to uppercase or an uppercase rune to lowercase (applied to the 10
// least-significant bits of the rune).
//
// See the definitions below for a more detailed description of the various
// bits.
type info uint16
const (
casedMask = 0x0003
fullCasedMask = 0x0007
ignorableMask = 0x0006
ignorableValue = 0x0004
inverseFoldBit = 1 << 7
isMidBit = 1 << 6
exceptionBit = 1 << 3
exceptionShift = 4
numExceptionBits = 12
xorIndexBit = 1 << 6
xorShift = 8
// There is no mapping if all xor bits and the exception bit are zero.
hasMappingMask = 0xff80 | exceptionBit
)
// The case mode bits encodes the case type of a rune. This includes uncased,
// title, upper and lower case and case ignorable. (For a definition of these
// terms see Chapter 3 of The Unicode Standard Core Specification.) In some rare
// cases, a rune can be both cased and case-ignorable. This is encoded by
// cIgnorableCased. A rune of this type is always lower case. Some runes are
// cased while not having a mapping.
//
// A common pattern for scripts in the Unicode standard is for upper and lower
// case runes to alternate for increasing rune values (e.g. the accented Latin
// ranges starting from U+0100 and U+1E00 among others and some Cyrillic
// characters). We use this property by defining a cXORCase mode, where the case
// mode (always upper or lower case) is derived from the rune value. As the XOR
// pattern for case mappings is often identical for successive runes, using
// cXORCase can result in large series of identical trie values. This, in turn,
// allows us to better compress the trie blocks.
const (
cUncased info = iota // 000
cTitle // 001
cLower // 010
cUpper // 011
cIgnorableUncased // 100
cIgnorableCased // 101 // lower case if mappings exist
cXORCase // 11x // case is cLower | ((rune&1) ^ x)
maxCaseMode = cUpper
)
func (c info) isCased() bool {
return c&casedMask != 0
}
func (c info) isCaseIgnorable() bool {
return c&ignorableMask == ignorableValue
}
func (c info) isNotCasedAndNotCaseIgnorable() bool {
return c&fullCasedMask == 0
}
func (c info) isCaseIgnorableAndNotCased() bool {
return c&fullCasedMask == cIgnorableUncased
}
func (c info) isMid() bool {
return c&(fullCasedMask|isMidBit) == isMidBit|cIgnorableUncased
}
// The case mapping implementation will need to know about various Canonical
// Combining Class (CCC) values. We encode two of these in the trie value:
// cccZero (0) and cccAbove (230). If the value is cccOther, it means that
// CCC(r) > 0, but not 230. A value of cccBreak means that CCC(r) == 0 and that
// the rune also has the break category Break (see below).
const (
cccBreak info = iota << 4
cccZero
cccAbove
cccOther
cccMask = cccBreak | cccZero | cccAbove | cccOther
)
const (
starter = 0
above = 230
iotaSubscript = 240
)
// The exceptions slice holds data that does not fit in a normal info entry.
// The entry is pointed to by the exception index in an entry. It has the
// following format:
//
// Header:
//
// byte 0:
// 7..6 unused
// 5..4 CCC type (same bits as entry)
// 3 unused
// 2..0 length of fold
//
// byte 1:
// 7..6 unused
// 5..3 length of 1st mapping of case type
// 2..0 length of 2nd mapping of case type
//
// case 1st 2nd
// lower -> upper, title
// upper -> lower, title
// title -> lower, upper
//
// Lengths with the value 0x7 indicate no value and implies no change.
// A length of 0 indicates a mapping to zero-length string.
//
// Body bytes:
//
// case folding bytes
// lowercase mapping bytes
// uppercase mapping bytes
// titlecase mapping bytes
// closure mapping bytes (for NFKC_Casefold). (TODO)
//
// Fallbacks:
//
// missing fold -> lower
// missing title -> upper
// all missing -> original rune
//
// exceptions starts with a dummy byte to enforce that there is no zero index
// value.
const (
lengthMask = 0x07
lengthBits = 3
noChange = 0
)
// References to generated trie.
var trie = newCaseTrie(0)
var sparse = sparseBlocks{
values: sparseValues[:],
offsets: sparseOffsets[:],
}
// Sparse block lookup code.
// valueRange is an entry in a sparse block.
type valueRange struct {
value uint16
lo, hi byte
}
type sparseBlocks struct {
values []valueRange
offsets []uint16
}
// lookup returns the value from values block n for byte b using binary search.
func (s *sparseBlocks) lookup(n uint32, b byte) uint16 {
lo := s.offsets[n]
hi := s.offsets[n+1]
for lo < hi {
m := lo + (hi-lo)/2
r := s.values[m]
if r.lo <= b && b <= r.hi {
return r.value
}
if b < r.lo {
hi = m
} else {
lo = m + 1
}
}
return 0
}
// lastRuneForTesting is the last rune used for testing. Everything after this
// is boring.
const lastRuneForTesting = rune(0x1FFFF)
// 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.
package build // import "golang.org/x/text/collate/build"
import (
"fmt"
"io"
"log"
"sort"
"strings"
"unicode/utf8"
"golang.org/x/text/internal/colltab"
"golang.org/x/text/language"
"golang.org/x/text/unicode/norm"
)
// TODO: optimizations:
// - expandElem is currently 20K. By putting unique colElems in a separate
// table and having a byte array of indexes into this table, we can reduce
// the total size to about 7K. By also factoring out the length bytes, we
// can reduce this to about 6K.
// - trie valueBlocks are currently 100K. There are a lot of sparse blocks
// and many consecutive values with the same stride. This can be further
// compacted.
// - Compress secondary weights into 8 bits.
// - Some LDML specs specify a context element. Currently we simply concatenate
// those. Context can be implemented using the contraction trie. If Builder
// could analyze and detect when using a context makes sense, there is no
// need to expose this construct in the API.
// A Builder builds a root collation table. The user must specify the
// collation elements for each entry. A common use will be to base the weights
// on those specified in the allkeys* file as provided by the UCA or CLDR.
type Builder struct {
index *trieBuilder
root ordering
locale []*Tailoring
t *table
err error
built bool
minNonVar int // lowest primary recorded for a variable
varTop int // highest primary recorded for a non-variable
// indexes used for reusing expansions and contractions
expIndex map[string]int // positions of expansions keyed by their string representation
ctHandle map[string]ctHandle // contraction handles keyed by a concatenation of the suffixes
ctElem map[string]int // contraction elements keyed by their string representation
}
// A Tailoring builds a collation table based on another collation table.
// The table is defined by specifying tailorings to the underlying table.
// See https://unicode.org/reports/tr35/ for an overview of tailoring
// collation tables. The CLDR contains pre-defined tailorings for a variety
// of languages (See https://www.unicode.org/Public/cldr/<version>/core.zip.)
type Tailoring struct {
id string
builder *Builder
index *ordering
anchor *entry
before bool
}
// NewBuilder returns a new Builder.
func NewBuilder() *Builder {
return &Builder{
index: newTrieBuilder(),
root: makeRootOrdering(),
expIndex: make(map[string]int),
ctHandle: make(map[string]ctHandle),
ctElem: make(map[string]int),
}
}
// Tailoring returns a Tailoring for the given locale. One should
// have completed all calls to Add before calling Tailoring.
func (b *Builder) Tailoring(loc language.Tag) *Tailoring {
t := &Tailoring{
id: loc.String(),
builder: b,
index: b.root.clone(),
}
t.index.id = t.id
b.locale = append(b.locale, t)
return t
}
// Add adds an entry to the collation element table, mapping
// a slice of runes to a sequence of collation elements.
// A collation element is specified as list of weights: []int{primary, secondary, ...}.
// The entries are typically obtained from a collation element table
// as defined in https://www.unicode.org/reports/tr10/#Data_Table_Format.
// Note that the collation elements specified by colelems are only used
// as a guide. The actual weights generated by Builder may differ.
// The argument variables is a list of indices into colelems that should contain
// a value for each colelem that is a variable. (See the reference above.)
func (b *Builder) Add(runes []rune, colelems [][]int, variables []int) error {
str := string(runes)
elems := make([]rawCE, len(colelems))
for i, ce := range colelems {
if len(ce) == 0 {
break
}
elems[i] = makeRawCE(ce, 0)
if len(ce) == 1 {
elems[i].w[1] = defaultSecondary
}
if len(ce) <= 2 {
elems[i].w[2] = defaultTertiary
}
if len(ce) <= 3 {
elems[i].w[3] = ce[0]
}
}
for i, ce := range elems {
p := ce.w[0]
isvar := false
for _, j := range variables {
if i == j {
isvar = true
}
}
if isvar {
if p >= b.minNonVar && b.minNonVar > 0 {
return fmt.Errorf("primary value %X of variable is larger than the smallest non-variable %X", p, b.minNonVar)
}
if p > b.varTop {
b.varTop = p
}
} else if p > 1 { // 1 is a special primary value reserved for FFFE
if p <= b.varTop {
return fmt.Errorf("primary value %X of non-variable is smaller than the highest variable %X", p, b.varTop)
}
if b.minNonVar == 0 || p < b.minNonVar {
b.minNonVar = p
}
}
}
elems, err := convertLargeWeights(elems)
if err != nil {
return err
}
cccs := []uint8{}
nfd := norm.NFD.String(str)
for i := range nfd {
cccs = append(cccs, norm.NFD.PropertiesString(nfd[i:]).CCC())
}
if len(cccs) < len(elems) {
if len(cccs) > 2 {
return fmt.Errorf("number of decomposed characters should be greater or equal to the number of collation elements for len(colelems) > 3 (%d < %d)", len(cccs), len(elems))
}
p := len(elems) - 1
for ; p > 0 && elems[p].w[0] == 0; p-- {
elems[p].ccc = cccs[len(cccs)-1]
}
for ; p >= 0; p-- {
elems[p].ccc = cccs[0]
}
} else {
for i := range elems {
elems[i].ccc = cccs[i]
}
}
// doNorm in collate.go assumes that the following conditions hold.
if len(elems) > 1 && len(cccs) > 1 && cccs[0] != 0 && cccs[0] != cccs[len(cccs)-1] {
return fmt.Errorf("incompatible CCC values for expansion %X (%d)", runes, cccs)
}
b.root.newEntry(str, elems)
return nil
}
func (t *Tailoring) setAnchor(anchor string) error {
anchor = norm.NFC.String(anchor)
a := t.index.find(anchor)
if a == nil {
a = t.index.newEntry(anchor, nil)
a.implicit = true
a.modified = true
for _, r := range []rune(anchor) {
e := t.index.find(string(r))
e.lock = true
}
}
t.anchor = a
return nil
}
// SetAnchor sets the point after which elements passed in subsequent calls to
// Insert will be inserted. It is equivalent to the reset directive in an LDML
// specification. See Insert for an example.
// SetAnchor supports the following logical reset positions:
// <first_tertiary_ignorable/>, <last_teriary_ignorable/>, <first_primary_ignorable/>,
// and <last_non_ignorable/>.
func (t *Tailoring) SetAnchor(anchor string) error {
if err := t.setAnchor(anchor); err != nil {
return err
}
t.before = false
return nil
}
// SetAnchorBefore is similar to SetAnchor, except that subsequent calls to
// Insert will insert entries before the anchor.
func (t *Tailoring) SetAnchorBefore(anchor string) error {
if err := t.setAnchor(anchor); err != nil {
return err
}
t.before = true
return nil
}
// Insert sets the ordering of str relative to the entry set by the previous
// call to SetAnchor or Insert. The argument extend corresponds
// to the extend elements as defined in LDML. A non-empty value for extend
// will cause the collation elements corresponding to extend to be appended
// to the collation elements generated for the entry added by Insert.
// This has the same net effect as sorting str after the string anchor+extend.
// See https://www.unicode.org/reports/tr10/#Tailoring_Example for details
// on parametric tailoring and https://unicode.org/reports/tr35/#Collation_Elements
// for full details on LDML.
//
// Examples: create a tailoring for Swedish, where "ä" is ordered after "z"
// at the primary sorting level:
//
// t := b.Tailoring("se")
// t.SetAnchor("z")
// t.Insert(colltab.Primary, "ä", "")
//
// Order "ü" after "ue" at the secondary sorting level:
//
// t.SetAnchor("ue")
// t.Insert(colltab.Secondary, "ü","")
//
// or
//
// t.SetAnchor("u")
// t.Insert(colltab.Secondary, "ü", "e")
//
// Order "q" after "ab" at the secondary level and "Q" after "q"
// at the tertiary level:
//
// t.SetAnchor("ab")
// t.Insert(colltab.Secondary, "q", "")
// t.Insert(colltab.Tertiary, "Q", "")
//
// Order "b" before "a":
//
// t.SetAnchorBefore("a")
// t.Insert(colltab.Primary, "b", "")
//
// Order "0" after the last primary ignorable:
//
// t.SetAnchor("<last_primary_ignorable/>")
// t.Insert(colltab.Primary, "0", "")
func (t *Tailoring) Insert(level colltab.Level, str, extend string) error {
if t.anchor == nil {
return fmt.Errorf("%s:Insert: no anchor point set for tailoring of %s", t.id, str)
}
str = norm.NFC.String(str)
e := t.index.find(str)
if e == nil {
e = t.index.newEntry(str, nil)
} else if e.logical != noAnchor {
return fmt.Errorf("%s:Insert: cannot reinsert logical reset position %q", t.id, e.str)
}
if e.lock {
return fmt.Errorf("%s:Insert: cannot reinsert element %q", t.id, e.str)
}
a := t.anchor
// Find the first element after the anchor which differs at a level smaller or
// equal to the given level. Then insert at this position.
// See https://unicode.org/reports/tr35/#Collation_Elements, Section 5.14.5 for details.
e.before = t.before
if t.before {
t.before = false
if a.prev == nil {
a.insertBefore(e)
} else {
for a = a.prev; a.level > level; a = a.prev {
}
a.insertAfter(e)
}
e.level = level
} else {
for ; a.level > level; a = a.next {
}
e.level = a.level
if a != e {
a.insertAfter(e)
a.level = level
} else {
// We don't set a to prev itself. This has the effect of the entry
// getting new collation elements that are an increment of itself.
// This is intentional.
a.prev.level = level
}
}
e.extend = norm.NFD.String(extend)
e.exclude = false
e.modified = true
e.elems = nil
t.anchor = e
return nil
}
func (o *ordering) getWeight(e *entry) []rawCE {
if len(e.elems) == 0 && e.logical == noAnchor {
if e.implicit {
for _, r := range e.runes {
e.elems = append(e.elems, o.getWeight(o.find(string(r)))...)
}
} else if e.before {
count := [colltab.Identity + 1]int{}
a := e
for ; a.elems == nil && !a.implicit; a = a.next {
count[a.level]++
}
e.elems = []rawCE{makeRawCE(a.elems[0].w, a.elems[0].ccc)}
for i := colltab.Primary; i < colltab.Quaternary; i++ {
if count[i] != 0 {
e.elems[0].w[i] -= count[i]
break
}
}
if e.prev != nil {
o.verifyWeights(e.prev, e, e.prev.level)
}
} else {
prev := e.prev
e.elems = nextWeight(prev.level, o.getWeight(prev))
o.verifyWeights(e, e.next, e.level)
}
}
return e.elems
}
func (o *ordering) addExtension(e *entry) {
if ex := o.find(e.extend); ex != nil {
e.elems = append(e.elems, ex.elems...)
} else {
for _, r := range []rune(e.extend) {
e.elems = append(e.elems, o.find(string(r)).elems...)
}
}
e.extend = ""
}
func (o *ordering) verifyWeights(a, b *entry, level colltab.Level) error {
if level == colltab.Identity || b == nil || b.elems == nil || a.elems == nil {
return nil
}
for i := colltab.Primary; i < level; i++ {
if a.elems[0].w[i] < b.elems[0].w[i] {
return nil
}
}
if a.elems[0].w[level] >= b.elems[0].w[level] {
err := fmt.Errorf("%s:overflow: collation elements of %q (%X) overflows those of %q (%X) at level %d (%X >= %X)", o.id, a.str, a.runes, b.str, b.runes, level, a.elems, b.elems)
log.Println(err)
// TODO: return the error instead, or better, fix the conflicting entry by making room.
}
return nil
}
func (b *Builder) error(e error) {
if e != nil {
b.err = e
}
}
func (b *Builder) errorID(locale string, e error) {
if e != nil {
b.err = fmt.Errorf("%s:%v", locale, e)
}
}
// patchNorm ensures that NFC and NFD counterparts are consistent.
func (o *ordering) patchNorm() {
// Insert the NFD counterparts, if necessary.
for _, e := range o.ordered {
nfd := norm.NFD.String(e.str)
if nfd != e.str {
if e0 := o.find(nfd); e0 != nil && !e0.modified {
e0.elems = e.elems
} else if e.modified && !equalCEArrays(o.genColElems(nfd), e.elems) {
e := o.newEntry(nfd, e.elems)
e.modified = true
}
}
}
// Update unchanged composed forms if one of their parts changed.
for _, e := range o.ordered {
nfd := norm.NFD.String(e.str)
if e.modified || nfd == e.str {
continue
}
if e0 := o.find(nfd); e0 != nil {
e.elems = e0.elems
} else {
e.elems = o.genColElems(nfd)
if norm.NFD.LastBoundary([]byte(nfd)) == 0 {
r := []rune(nfd)
head := string(r[0])
tail := ""
for i := 1; i < len(r); i++ {
s := norm.NFC.String(head + string(r[i]))
if e0 := o.find(s); e0 != nil && e0.modified {
head = s
} else {
tail += string(r[i])
}
}
e.elems = append(o.genColElems(head), o.genColElems(tail)...)
}
}
}
// Exclude entries for which the individual runes generate the same collation elements.
for _, e := range o.ordered {
if len(e.runes) > 1 && equalCEArrays(o.genColElems(e.str), e.elems) {
e.exclude = true
}
}
}
func (b *Builder) buildOrdering(o *ordering) {
for _, e := range o.ordered {
o.getWeight(e)
}
for _, e := range o.ordered {
o.addExtension(e)
}
o.patchNorm()
o.sort()
simplify(o)
b.processExpansions(o) // requires simplify
b.processContractions(o) // requires simplify
t := newNode()
for e := o.front(); e != nil; e, _ = e.nextIndexed() {
if !e.skip() {
ce, err := e.encode()
b.errorID(o.id, err)
t.insert(e.runes[0], ce)
}
}
o.handle = b.index.addTrie(t)
}
func (b *Builder) build() (*table, error) {
if b.built {
return b.t, b.err
}
b.built = true
b.t = &table{
Table: colltab.Table{
MaxContractLen: utf8.UTFMax,
VariableTop: uint32(b.varTop),
},
}
b.buildOrdering(&b.root)
b.t.root = b.root.handle
for _, t := range b.locale {
b.buildOrdering(t.index)
if b.err != nil {
break
}
}
i, err := b.index.generate()
b.t.trie = *i
b.t.Index = colltab.Trie{
Index: i.index,
Values: i.values,
Index0: i.index[blockSize*b.t.root.lookupStart:],
Values0: i.values[blockSize*b.t.root.valueStart:],
}
b.error(err)
return b.t, b.err
}
// Build builds the root Collator.
func (b *Builder) Build() (colltab.Weighter, error) {
table, err := b.build()
if err != nil {
return nil, err
}
return table, nil
}
// Build builds a Collator for Tailoring t.
func (t *Tailoring) Build() (colltab.Weighter, error) {
// TODO: implement.
return nil, nil
}
// Print prints the tables for b and all its Tailorings as a Go file
// that can be included in the Collate package.
func (b *Builder) Print(w io.Writer) (n int, err error) {
p := func(nn int, e error) {
n += nn
if err == nil {
err = e
}
}
t, err := b.build()
if err != nil {
return 0, err
}
p(fmt.Fprintf(w, `var availableLocales = "und`))
for _, loc := range b.locale {
if loc.id != "und" {
p(fmt.Fprintf(w, ",%s", loc.id))
}
}
p(fmt.Fprint(w, "\"\n\n"))
p(fmt.Fprintf(w, "const varTop = 0x%x\n\n", b.varTop))
p(fmt.Fprintln(w, "var locales = [...]tableIndex{"))
for _, loc := range b.locale {
if loc.id == "und" {
p(t.fprintIndex(w, loc.index.handle, loc.id))
}
}
for _, loc := range b.locale {
if loc.id != "und" {
p(t.fprintIndex(w, loc.index.handle, loc.id))
}
}
p(fmt.Fprint(w, "}\n\n"))
n, _, err = t.fprint(w, "main")
return
}
// reproducibleFromNFKD checks whether the given expansion could be generated
// from an NFKD expansion.
func reproducibleFromNFKD(e *entry, exp, nfkd []rawCE) bool {
// Length must be equal.
if len(exp) != len(nfkd) {
return false
}
for i, ce := range exp {
// Primary and secondary values should be equal.
if ce.w[0] != nfkd[i].w[0] || ce.w[1] != nfkd[i].w[1] {
return false
}
// Tertiary values should be equal to maxTertiary for third element onwards.
// TODO: there seem to be a lot of cases in CLDR (e.g. ㏭ in zh.xml) that can
// simply be dropped. Try this out by dropping the following code.
if i >= 2 && ce.w[2] != maxTertiary {
return false
}
if _, err := makeCE(ce); err != nil {
// Simply return false. The error will be caught elsewhere.
return false
}
}
return true
}
func simplify(o *ordering) {
// Runes that are a starter of a contraction should not be removed.
// (To date, there is only Kannada character 0CCA.)
keep := make(map[rune]bool)
for e := o.front(); e != nil; e, _ = e.nextIndexed() {
if len(e.runes) > 1 {
keep[e.runes[0]] = true
}
}
// Tag entries for which the runes NFKD decompose to identical values.
for e := o.front(); e != nil; e, _ = e.nextIndexed() {
s := e.str
nfkd := norm.NFKD.String(s)
nfd := norm.NFD.String(s)
if e.decompose || len(e.runes) > 1 || len(e.elems) == 1 || keep[e.runes[0]] || nfkd == nfd {
continue
}
if reproducibleFromNFKD(e, e.elems, o.genColElems(nfkd)) {
e.decompose = true
}
}
}
// appendExpansion converts the given collation sequence to
// collation elements and adds them to the expansion table.
// It returns an index to the expansion table.
func (b *Builder) appendExpansion(e *entry) int {
t := b.t
i := len(t.ExpandElem)
ce := uint32(len(e.elems))
t.ExpandElem = append(t.ExpandElem, ce)
for _, w := range e.elems {
ce, err := makeCE(w)
if err != nil {
b.error(err)
return -1
}
t.ExpandElem = append(t.ExpandElem, ce)
}
return i
}
// processExpansions extracts data necessary to generate
// the extraction tables.
func (b *Builder) processExpansions(o *ordering) {
for e := o.front(); e != nil; e, _ = e.nextIndexed() {
if !e.expansion() {
continue
}
key := fmt.Sprintf("%v", e.elems)
i, ok := b.expIndex[key]
if !ok {
i = b.appendExpansion(e)
b.expIndex[key] = i
}
e.expansionIndex = i
}
}
func (b *Builder) processContractions(o *ordering) {
// Collate contractions per starter rune.
starters := []rune{}
cm := make(map[rune][]*entry)
for e := o.front(); e != nil; e, _ = e.nextIndexed() {
if e.contraction() {
if len(e.str) > b.t.MaxContractLen {
b.t.MaxContractLen = len(e.str)
}
r := e.runes[0]
if _, ok := cm[r]; !ok {
starters = append(starters, r)
}
cm[r] = append(cm[r], e)
}
}
// Add entries of single runes that are at a start of a contraction.
for e := o.front(); e != nil; e, _ = e.nextIndexed() {
if !e.contraction() {
r := e.runes[0]
if _, ok := cm[r]; ok {
cm[r] = append(cm[r], e)
}
}
}
// Build the tries for the contractions.
t := b.t
for _, r := range starters {
l := cm[r]
// Compute suffix strings. There are 31 different contraction suffix
// sets for 715 contractions and 82 contraction starter runes as of
// version 6.0.0.
sufx := []string{}
hasSingle := false
for _, e := range l {
if len(e.runes) > 1 {
sufx = append(sufx, string(e.runes[1:]))
} else {
hasSingle = true
}
}
if !hasSingle {
b.error(fmt.Errorf("no single entry for starter rune %U found", r))
continue
}
// Unique the suffix set.
sort.Strings(sufx)
key := strings.Join(sufx, "\n")
handle, ok := b.ctHandle[key]
if !ok {
var err error
handle, err = appendTrie(&t.ContractTries, sufx)
if err != nil {
b.error(err)
}
b.ctHandle[key] = handle
}
// Bucket sort entries in index order.
es := make([]*entry, len(l))
for _, e := range l {
var p, sn int
if len(e.runes) > 1 {
str := []byte(string(e.runes[1:]))
p, sn = lookup(&t.ContractTries, handle, str)
if sn != len(str) {
log.Fatalf("%s: processContractions: unexpected length for '%X'; len=%d; want %d", o.id, e.runes, sn, len(str))
}
}
if es[p] != nil {
log.Fatalf("%s: multiple contractions for position %d for rune %U", o.id, p, e.runes[0])
}
es[p] = e
}
// Create collation elements for contractions.
elems := []uint32{}
for _, e := range es {
ce, err := e.encodeBase()
b.errorID(o.id, err)
elems = append(elems, ce)
}
key = fmt.Sprintf("%v", elems)
i, ok := b.ctElem[key]
if !ok {
i = len(t.ContractElem)
b.ctElem[key] = i
t.ContractElem = append(t.ContractElem, elems...)
}
// Store info in entry for starter rune.
es[0].contractionIndex = i
es[0].contractionHandle = handle
}
}
// 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.
package build
import (
"fmt"
"unicode"
"golang.org/x/text/internal/colltab"
)
const (
defaultSecondary = 0x20
defaultTertiary = 0x2
maxTertiary = 0x1F
)
type rawCE struct {
w []int
ccc uint8
}
func makeRawCE(w []int, ccc uint8) rawCE {
ce := rawCE{w: make([]int, 4), ccc: ccc}
copy(ce.w, w)
return ce
}
// A collation element is represented as an uint32.
// In the typical case, a rune maps to a single collation element. If a rune
// can be the start of a contraction or expands into multiple collation elements,
// then the collation element that is associated with a rune will have a special
// form to represent such m to n mappings. Such special collation elements
// have a value >= 0x80000000.
const (
maxPrimaryBits = 21
maxSecondaryBits = 12
maxTertiaryBits = 8
)
func makeCE(ce rawCE) (uint32, error) {
v, e := colltab.MakeElem(ce.w[0], ce.w[1], ce.w[2], ce.ccc)
return uint32(v), e
}
// For contractions, collation elements are of the form
// 110bbbbb bbbbbbbb iiiiiiii iiiinnnn, where
// - n* is the size of the first node in the contraction trie.
// - i* is the index of the first node in the contraction trie.
// - b* is the offset into the contraction collation element table.
//
// See contract.go for details on the contraction trie.
const (
contractID = 0xC0000000
maxNBits = 4
maxTrieIndexBits = 12
maxContractOffsetBits = 13
)
func makeContractIndex(h ctHandle, offset int) (uint32, error) {
if h.n >= 1<<maxNBits {
return 0, fmt.Errorf("size of contraction trie node too large: %d >= %d", h.n, 1<<maxNBits)
}
if h.index >= 1<<maxTrieIndexBits {
return 0, fmt.Errorf("size of contraction trie offset too large: %d >= %d", h.index, 1<<maxTrieIndexBits)
}
if offset >= 1<<maxContractOffsetBits {
return 0, fmt.Errorf("contraction offset out of bounds: %x >= %x", offset, 1<<maxContractOffsetBits)
}
ce := uint32(contractID)
ce += uint32(offset << (maxNBits + maxTrieIndexBits))
ce += uint32(h.index << maxNBits)
ce += uint32(h.n)
return ce, nil
}
// For expansions, collation elements are of the form
// 11100000 00000000 bbbbbbbb bbbbbbbb,
// where b* is the index into the expansion sequence table.
const (
expandID = 0xE0000000
maxExpandIndexBits = 16
)
func makeExpandIndex(index int) (uint32, error) {
if index >= 1<<maxExpandIndexBits {
return 0, fmt.Errorf("expansion index out of bounds: %x >= %x", index, 1<<maxExpandIndexBits)
}
return expandID + uint32(index), nil
}
// Each list of collation elements corresponding to an expansion starts with
// a header indicating the length of the sequence.
func makeExpansionHeader(n int) (uint32, error) {
return uint32(n), nil
}
// Some runes can be expanded using NFKD decomposition. Instead of storing the full
// sequence of collation elements, we decompose the rune and lookup the collation
// elements for each rune in the decomposition and modify the tertiary weights.
// The collation element, in this case, is of the form
// 11110000 00000000 wwwwwwww vvvvvvvv, where
// - v* is the replacement tertiary weight for the first rune,
// - w* is the replacement tertiary weight for the second rune.
//
// Tertiary weights of subsequent runes should be replaced with maxTertiary.
// See https://www.unicode.org/reports/tr10/#Compatibility_Decompositions for more details.
const (
decompID = 0xF0000000
)
func makeDecompose(t1, t2 int) (uint32, error) {
if t1 >= 256 || t1 < 0 {
return 0, fmt.Errorf("first tertiary weight out of bounds: %d >= 256", t1)
}
if t2 >= 256 || t2 < 0 {
return 0, fmt.Errorf("second tertiary weight out of bounds: %d >= 256", t2)
}
return uint32(t2<<8+t1) + decompID, nil
}
const (
// These constants were taken from https://www.unicode.org/versions/Unicode6.0.0/ch12.pdf.
minUnified rune = 0x4E00
maxUnified = 0x9FFF
minCompatibility = 0xF900
maxCompatibility = 0xFAFF
minRare = 0x3400
maxRare = 0x4DBF
)
const (
commonUnifiedOffset = 0x10000
rareUnifiedOffset = 0x20000 // largest rune in common is U+FAFF
otherOffset = 0x50000 // largest rune in rare is U+2FA1D
illegalOffset = otherOffset + int(unicode.MaxRune)
maxPrimary = illegalOffset + 1
)
// implicitPrimary returns the primary weight for the given rune
// for which there is no entry for the rune in the collation table.
// We take a different approach from the one specified in
// https://unicode.org/reports/tr10/#Implicit_Weights,
// but preserve the resulting relative ordering of the runes.
func implicitPrimary(r rune) int {
if unicode.Is(unicode.Ideographic, r) {
if r >= minUnified && r <= maxUnified {
// The most common case for CJK.
return int(r) + commonUnifiedOffset
}
if r >= minCompatibility && r <= maxCompatibility {
// This will typically not hit. The DUCET explicitly specifies mappings
// for all characters that do not decompose.
return int(r) + commonUnifiedOffset
}
return int(r) + rareUnifiedOffset
}
return int(r) + otherOffset
}
// convertLargeWeights converts collation elements with large
// primaries (either double primaries or for illegal runes)
// to our own representation.
// A CJK character C is represented in the DUCET as
//
// [.FBxx.0020.0002.C][.BBBB.0000.0000.C]
//
// We will rewrite these characters to a single CE.
// We assume the CJK values start at 0x8000.
// See https://unicode.org/reports/tr10/#Implicit_Weights
func convertLargeWeights(elems []rawCE) (res []rawCE, err error) {
const (
cjkPrimaryStart = 0xFB40
rarePrimaryStart = 0xFB80
otherPrimaryStart = 0xFBC0
illegalPrimary = 0xFFFE
highBitsMask = 0x3F
lowBitsMask = 0x7FFF
lowBitsFlag = 0x8000
shiftBits = 15
)
for i := 0; i < len(elems); i++ {
ce := elems[i].w
p := ce[0]
if p < cjkPrimaryStart {
continue
}
if p > 0xFFFF {
return elems, fmt.Errorf("found primary weight %X; should be <= 0xFFFF", p)
}
if p >= illegalPrimary {
ce[0] = illegalOffset + p - illegalPrimary
} else {
if i+1 >= len(elems) {
return elems, fmt.Errorf("second part of double primary weight missing: %v", elems)
}
if elems[i+1].w[0]&lowBitsFlag == 0 {
return elems, fmt.Errorf("malformed second part of double primary weight: %v", elems)
}
np := ((p & highBitsMask) << shiftBits) + elems[i+1].w[0]&lowBitsMask
switch {
case p < rarePrimaryStart:
np += commonUnifiedOffset
case p < otherPrimaryStart:
np += rareUnifiedOffset
default:
p += otherOffset
}
ce[0] = np
for j := i + 1; j+1 < len(elems); j++ {
elems[j] = elems[j+1]
}
elems = elems[:len(elems)-1]
}
}
return elems, nil
}
// nextWeight computes the first possible collation weights following elems
// for the given level.
func nextWeight(level colltab.Level, elems []rawCE) []rawCE {
if level == colltab.Identity {
next := make([]rawCE, len(elems))
copy(next, elems)
return next
}
next := []rawCE{makeRawCE(elems[0].w, elems[0].ccc)}
next[0].w[level]++
if level < colltab.Secondary {
next[0].w[colltab.Secondary] = defaultSecondary
}
if level < colltab.Tertiary {
next[0].w[colltab.Tertiary] = defaultTertiary
}
// Filter entries that cannot influence ordering.
for _, ce := range elems[1:] {
skip := true
for i := colltab.Primary; i < level; i++ {
skip = skip && ce.w[i] == 0
}
if !skip {
next = append(next, ce)
}
}
return next
}
func nextVal(elems []rawCE, i int, level colltab.Level) (index, value int) {
for ; i < len(elems) && elems[i].w[level] == 0; i++ {
}
if i < len(elems) {
return i, elems[i].w[level]
}
return i, 0
}
// compareWeights returns -1 if a < b, 1 if a > b, or 0 otherwise.
// It also returns the collation level at which the difference is found.
func compareWeights(a, b []rawCE) (result int, level colltab.Level) {
for level := colltab.Primary; level < colltab.Identity; level++ {
var va, vb int
for ia, ib := 0, 0; ia < len(a) || ib < len(b); ia, ib = ia+1, ib+1 {
ia, va = nextVal(a, ia, level)
ib, vb = nextVal(b, ib, level)
if va != vb {
if va < vb {
return -1, level
} else {
return 1, level
}
}
}
}
return 0, colltab.Identity
}
func equalCE(a, b rawCE) bool {
for i := 0; i < 3; i++ {
if b.w[i] != a.w[i] {
return false
}
}
return true
}
func equalCEArrays(a, b []rawCE) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if !equalCE(a[i], b[i]) {
return false
}
}
return true
}
// 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.
package build
import (
"fmt"
"io"
"reflect"
"sort"
"strings"
"golang.org/x/text/internal/colltab"
)
// This file contains code for detecting contractions and generating
// the necessary tables.
// Any Unicode Collation Algorithm (UCA) table entry that has more than
// one rune one the left-hand side is called a contraction.
// See https://www.unicode.org/reports/tr10/#Contractions for more details.
//
// We define the following terms:
// initial: a rune that appears as the first rune in a contraction.
// suffix: a sequence of runes succeeding the initial rune
// in a given contraction.
// non-initial: a rune that appears in a suffix.
//
// A rune may be both an initial and a non-initial and may be so in
// many contractions. An initial may typically also appear by itself.
// In case of ambiguities, the UCA requires we match the longest
// contraction.
//
// Many contraction rules share the same set of possible suffixes.
// We store sets of suffixes in a trie that associates an index with
// each suffix in the set. This index can be used to look up a
// collation element associated with the (starter rune, suffix) pair.
//
// The trie is defined on a UTF-8 byte sequence.
// The overall trie is represented as an array of ctEntries. Each node of the trie
// is represented as a subsequence of ctEntries, where each entry corresponds to
// a possible match of a next character in the search string. An entry
// also includes the length and offset to the next sequence of entries
// to check in case of a match.
const (
final = 0
noIndex = 0xFF
)
// ctEntry associates to a matching byte an offset and/or next sequence of
// bytes to check. A ctEntry c is called final if a match means that the
// longest suffix has been found. An entry c is final if c.N == 0.
// A single final entry can match a range of characters to an offset.
// A non-final entry always matches a single byte. Note that a non-final
// entry might still resemble a completed suffix.
// Examples:
// The suffix strings "ab" and "ac" can be represented as:
//
// []ctEntry{
// {'a', 1, 1, noIndex}, // 'a' by itself does not match, so i is 0xFF.
// {'b', 'c', 0, 1}, // "ab" -> 1, "ac" -> 2
// }
//
// The suffix strings "ab", "abc", "abd", and "abcd" can be represented as:
//
// []ctEntry{
// {'a', 1, 1, noIndex}, // 'a' must be followed by 'b'.
// {'b', 1, 2, 1}, // "ab" -> 1, may be followed by 'c' or 'd'.
// {'d', 'd', final, 3}, // "abd" -> 3
// {'c', 4, 1, 2}, // "abc" -> 2, may be followed by 'd'.
// {'d', 'd', final, 4}, // "abcd" -> 4
// }
//
// See genStateTests in contract_test.go for more examples.
type ctEntry struct {
L uint8 // non-final: byte value to match; final: lowest match in range.
H uint8 // non-final: relative index to next block; final: highest match in range.
N uint8 // non-final: length of next block; final: final
I uint8 // result offset. Will be noIndex if more bytes are needed to complete.
}
// contractTrieSet holds a set of contraction tries. The tries are stored
// consecutively in the entry field.
type contractTrieSet []struct{ l, h, n, i uint8 }
// ctHandle is used to identify a trie in the trie set, consisting in an offset
// in the array and the size of the first node.
type ctHandle struct {
index, n int
}
// appendTrie adds a new trie for the given suffixes to the trie set and returns
// a handle to it. The handle will be invalid on error.
func appendTrie(ct *colltab.ContractTrieSet, suffixes []string) (ctHandle, error) {
es := make([]stridx, len(suffixes))
for i, s := range suffixes {
es[i].str = s
}
sort.Sort(offsetSort(es))
for i := range es {
es[i].index = i + 1
}
sort.Sort(genidxSort(es))
i := len(*ct)
n, err := genStates(ct, es)
if err != nil {
*ct = (*ct)[:i]
return ctHandle{}, err
}
return ctHandle{i, n}, nil
}
// genStates generates ctEntries for a given suffix set and returns
// the number of entries for the first node.
func genStates(ct *colltab.ContractTrieSet, sis []stridx) (int, error) {
if len(sis) == 0 {
return 0, fmt.Errorf("genStates: list of suffices must be non-empty")
}
start := len(*ct)
// create entries for differing first bytes.
for _, si := range sis {
s := si.str
if len(s) == 0 {
continue
}
added := false
c := s[0]
if len(s) > 1 {
for j := len(*ct) - 1; j >= start; j-- {
if (*ct)[j].L == c {
added = true
break
}
}
if !added {
*ct = append(*ct, ctEntry{L: c, I: noIndex})
}
} else {
for j := len(*ct) - 1; j >= start; j-- {
// Update the offset for longer suffixes with the same byte.
if (*ct)[j].L == c {
(*ct)[j].I = uint8(si.index)
added = true
}
// Extend range of final ctEntry, if possible.
if (*ct)[j].H+1 == c {
(*ct)[j].H = c
added = true
}
}
if !added {
*ct = append(*ct, ctEntry{L: c, H: c, N: final, I: uint8(si.index)})
}
}
}
n := len(*ct) - start
// Append nodes for the remainder of the suffixes for each ctEntry.
sp := 0
for i, end := start, len(*ct); i < end; i++ {
fe := (*ct)[i]
if fe.H == 0 { // uninitialized non-final
ln := len(*ct) - start - n
if ln > 0xFF {
return 0, fmt.Errorf("genStates: relative block offset too large: %d > 255", ln)
}
fe.H = uint8(ln)
// Find first non-final strings with same byte as current entry.
for ; sis[sp].str[0] != fe.L; sp++ {
}
se := sp + 1
for ; se < len(sis) && len(sis[se].str) > 1 && sis[se].str[0] == fe.L; se++ {
}
sl := sis[sp:se]
sp = se
for i, si := range sl {
sl[i].str = si.str[1:]
}
nn, err := genStates(ct, sl)
if err != nil {
return 0, err
}
fe.N = uint8(nn)
(*ct)[i] = fe
}
}
sort.Sort(entrySort((*ct)[start : start+n]))
return n, nil
}
// There may be both a final and non-final entry for a byte if the byte
// is implied in a range of matches in the final entry.
// We need to ensure that the non-final entry comes first in that case.
type entrySort colltab.ContractTrieSet
func (fe entrySort) Len() int { return len(fe) }
func (fe entrySort) Swap(i, j int) { fe[i], fe[j] = fe[j], fe[i] }
func (fe entrySort) Less(i, j int) bool {
return fe[i].L > fe[j].L
}
// stridx is used for sorting suffixes and their associated offsets.
type stridx struct {
str string
index int
}
// For computing the offsets, we first sort by size, and then by string.
// This ensures that strings that only differ in the last byte by 1
// are sorted consecutively in increasing order such that they can
// be packed as a range in a final ctEntry.
type offsetSort []stridx
func (si offsetSort) Len() int { return len(si) }
func (si offsetSort) Swap(i, j int) { si[i], si[j] = si[j], si[i] }
func (si offsetSort) Less(i, j int) bool {
if len(si[i].str) != len(si[j].str) {
return len(si[i].str) > len(si[j].str)
}
return si[i].str < si[j].str
}
// For indexing, we want to ensure that strings are sorted in string order, where
// for strings with the same prefix, we put longer strings before shorter ones.
type genidxSort []stridx
func (si genidxSort) Len() int { return len(si) }
func (si genidxSort) Swap(i, j int) { si[i], si[j] = si[j], si[i] }
func (si genidxSort) Less(i, j int) bool {
if strings.HasPrefix(si[j].str, si[i].str) {
return false
}
if strings.HasPrefix(si[i].str, si[j].str) {
return true
}
return si[i].str < si[j].str
}
// lookup matches the longest suffix in str and returns the associated offset
// and the number of bytes consumed.
func lookup(ct *colltab.ContractTrieSet, h ctHandle, str []byte) (index, ns int) {
states := (*ct)[h.index:]
p := 0
n := h.n
for i := 0; i < n && p < len(str); {
e := states[i]
c := str[p]
if c >= e.L {
if e.L == c {
p++
if e.I != noIndex {
index, ns = int(e.I), p
}
if e.N != final {
// set to new state
i, states, n = 0, states[int(e.H)+n:], int(e.N)
} else {
return
}
continue
} else if e.N == final && c <= e.H {
p++
return int(c-e.L) + int(e.I), p
}
}
i++
}
return
}
// print writes the contractTrieSet t as compilable Go code to w. It returns
// the total number of bytes written and the size of the resulting data structure in bytes.
func print(t *colltab.ContractTrieSet, w io.Writer, name string) (n, size int, err error) {
update3 := func(nn, sz int, e error) {
n += nn
if err == nil {
err = e
}
size += sz
}
update2 := func(nn int, e error) { update3(nn, 0, e) }
update3(printArray(*t, w, name))
update2(fmt.Fprintf(w, "var %sContractTrieSet = ", name))
update3(printStruct(w, name))
update2(fmt.Fprintln(w))
return
}
func printArray(ct colltab.ContractTrieSet, w io.Writer, name string) (n, size int, err error) {
p := func(f string, a ...interface{}) {
nn, e := fmt.Fprintf(w, f, a...)
n += nn
if err == nil {
err = e
}
}
size = len(ct) * 4
p("// %sCTEntries: %d entries, %d bytes\n", name, len(ct), size)
p("var %sCTEntries = [%d]struct{L,H,N,I uint8}{\n", name, len(ct))
for _, fe := range ct {
p("\t{0x%X, 0x%X, %d, %d},\n", fe.L, fe.H, fe.N, fe.I)
}
p("}\n")
return
}
func printStruct(w io.Writer, name string) (n, size int, err error) {
n, err = fmt.Fprintf(w, "colltab.ContractTrieSet( %sCTEntries[:] )", name)
size = int(reflect.TypeFor[colltab.ContractTrieSet]().Size())
return
}
// 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.
package build
import (
"fmt"
"log"
"sort"
"strings"
"unicode"
"golang.org/x/text/internal/colltab"
"golang.org/x/text/unicode/norm"
)
type logicalAnchor int
const (
firstAnchor logicalAnchor = -1
noAnchor = 0
lastAnchor = 1
)
// entry is used to keep track of a single entry in the collation element table
// during building. Examples of entries can be found in the Default Unicode
// Collation Element Table.
// See https://www.unicode.org/Public/UCA/6.0.0/allkeys.txt.
type entry struct {
str string // same as string(runes)
runes []rune
elems []rawCE // the collation elements
extend string // weights of extend to be appended to elems
before bool // weights relative to next instead of previous.
lock bool // entry is used in extension and can no longer be moved.
// prev, next, and level are used to keep track of tailorings.
prev, next *entry
level colltab.Level // next differs at this level
skipRemove bool // do not unlink when removed
decompose bool // can use NFKD decomposition to generate elems
exclude bool // do not include in table
implicit bool // derived, is not included in the list
modified bool // entry was modified in tailoring
logical logicalAnchor
expansionIndex int // used to store index into expansion table
contractionHandle ctHandle
contractionIndex int // index into contraction elements
}
func (e *entry) String() string {
return fmt.Sprintf("%X (%q) -> %X (ch:%x; ci:%d, ei:%d)",
e.runes, e.str, e.elems, e.contractionHandle, e.contractionIndex, e.expansionIndex)
}
func (e *entry) skip() bool {
return e.contraction()
}
func (e *entry) expansion() bool {
return !e.decompose && len(e.elems) > 1
}
func (e *entry) contraction() bool {
return len(e.runes) > 1
}
func (e *entry) contractionStarter() bool {
return e.contractionHandle.n != 0
}
// nextIndexed gets the next entry that needs to be stored in the table.
// It returns the entry and the collation level at which the next entry differs
// from the current entry.
// Entries that can be explicitly derived and logical reset positions are
// examples of entries that will not be indexed.
func (e *entry) nextIndexed() (*entry, colltab.Level) {
level := e.level
for e = e.next; e != nil && (e.exclude || len(e.elems) == 0); e = e.next {
if e.level < level {
level = e.level
}
}
return e, level
}
// remove unlinks entry e from the sorted chain and clears the collation
// elements. e may not be at the front or end of the list. This should always
// be the case, as the front and end of the list are always logical anchors,
// which may not be removed.
func (e *entry) remove() {
if e.logical != noAnchor {
log.Fatalf("may not remove anchor %q", e.str)
}
// TODO: need to set e.prev.level to e.level if e.level is smaller?
e.elems = nil
if !e.skipRemove {
if e.prev != nil {
e.prev.next = e.next
}
if e.next != nil {
e.next.prev = e.prev
}
}
e.skipRemove = false
}
// insertAfter inserts n after e.
func (e *entry) insertAfter(n *entry) {
if e == n {
panic("e == anchor")
}
if e == nil {
panic("unexpected nil anchor")
}
n.remove()
n.decompose = false // redo decomposition test
n.next = e.next
n.prev = e
if e.next != nil {
e.next.prev = n
}
e.next = n
}
// insertBefore inserts n before e.
func (e *entry) insertBefore(n *entry) {
if e == n {
panic("e == anchor")
}
if e == nil {
panic("unexpected nil anchor")
}
n.remove()
n.decompose = false // redo decomposition test
n.prev = e.prev
n.next = e
if e.prev != nil {
e.prev.next = n
}
e.prev = n
}
func (e *entry) encodeBase() (ce uint32, err error) {
switch {
case e.expansion():
ce, err = makeExpandIndex(e.expansionIndex)
default:
if e.decompose {
log.Fatal("decompose should be handled elsewhere")
}
ce, err = makeCE(e.elems[0])
}
return
}
func (e *entry) encode() (ce uint32, err error) {
if e.skip() {
log.Fatal("cannot build colElem for entry that should be skipped")
}
switch {
case e.decompose:
t1 := e.elems[0].w[2]
t2 := 0
if len(e.elems) > 1 {
t2 = e.elems[1].w[2]
}
ce, err = makeDecompose(t1, t2)
case e.contractionStarter():
ce, err = makeContractIndex(e.contractionHandle, e.contractionIndex)
default:
if len(e.runes) > 1 {
log.Fatal("colElem: contractions are handled in contraction trie")
}
ce, err = e.encodeBase()
}
return
}
// entryLess returns true if a sorts before b and false otherwise.
func entryLess(a, b *entry) bool {
if res, _ := compareWeights(a.elems, b.elems); res != 0 {
return res == -1
}
if a.logical != noAnchor {
return a.logical == firstAnchor
}
if b.logical != noAnchor {
return b.logical == lastAnchor
}
return a.str < b.str
}
type sortedEntries []*entry
func (s sortedEntries) Len() int {
return len(s)
}
func (s sortedEntries) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s sortedEntries) Less(i, j int) bool {
return entryLess(s[i], s[j])
}
type ordering struct {
id string
entryMap map[string]*entry
ordered []*entry
handle *trieHandle
}
// insert inserts e into both entryMap and ordered.
// Note that insert simply appends e to ordered. To reattain a sorted
// order, o.sort() should be called.
func (o *ordering) insert(e *entry) {
if e.logical == noAnchor {
o.entryMap[e.str] = e
} else {
// Use key format as used in UCA rules.
o.entryMap[fmt.Sprintf("[%s]", e.str)] = e
// Also add index entry for XML format.
o.entryMap[fmt.Sprintf("<%s/>", strings.Replace(e.str, " ", "_", -1))] = e
}
o.ordered = append(o.ordered, e)
}
// newEntry creates a new entry for the given info and inserts it into
// the index.
func (o *ordering) newEntry(s string, ces []rawCE) *entry {
e := &entry{
runes: []rune(s),
elems: ces,
str: s,
}
o.insert(e)
return e
}
// find looks up and returns the entry for the given string.
// It returns nil if str is not in the index and if an implicit value
// cannot be derived, that is, if str represents more than one rune.
func (o *ordering) find(str string) *entry {
e := o.entryMap[str]
if e == nil {
r := []rune(str)
if len(r) == 1 {
const (
firstHangul = 0xAC00
lastHangul = 0xD7A3
)
if r[0] >= firstHangul && r[0] <= lastHangul {
ce := []rawCE{}
nfd := norm.NFD.String(str)
for _, r := range nfd {
ce = append(ce, o.find(string(r)).elems...)
}
e = o.newEntry(nfd, ce)
} else {
e = o.newEntry(string(r[0]), []rawCE{
{w: []int{
implicitPrimary(r[0]),
defaultSecondary,
defaultTertiary,
int(r[0]),
},
},
})
e.modified = true
}
e.exclude = true // do not index implicits
}
}
return e
}
// makeRootOrdering returns a newly initialized ordering value and populates
// it with a set of logical reset points that can be used as anchors.
// The anchors first_tertiary_ignorable and __END__ will always sort at
// the beginning and end, respectively. This means that prev and next are non-nil
// for any indexed entry.
func makeRootOrdering() ordering {
const max = unicode.MaxRune
o := ordering{
entryMap: make(map[string]*entry),
}
insert := func(typ logicalAnchor, s string, ce []int) {
e := &entry{
elems: []rawCE{{w: ce}},
str: s,
exclude: true,
logical: typ,
}
o.insert(e)
}
insert(firstAnchor, "first tertiary ignorable", []int{0, 0, 0, 0})
insert(lastAnchor, "last tertiary ignorable", []int{0, 0, 0, max})
insert(lastAnchor, "last primary ignorable", []int{0, defaultSecondary, defaultTertiary, max})
insert(lastAnchor, "last non ignorable", []int{maxPrimary, defaultSecondary, defaultTertiary, max})
insert(lastAnchor, "__END__", []int{1 << maxPrimaryBits, defaultSecondary, defaultTertiary, max})
return o
}
// patchForInsert eliminates entries from the list with more than one collation element.
// The next and prev fields of the eliminated entries still point to appropriate
// values in the newly created list.
// It requires that sort has been called.
func (o *ordering) patchForInsert() {
for i := 0; i < len(o.ordered)-1; {
e := o.ordered[i]
lev := e.level
n := e.next
for ; n != nil && len(n.elems) > 1; n = n.next {
if n.level < lev {
lev = n.level
}
n.skipRemove = true
}
for ; o.ordered[i] != n; i++ {
o.ordered[i].level = lev
o.ordered[i].next = n
o.ordered[i+1].prev = e
}
}
}
// clone copies all ordering of es into a new ordering value.
func (o *ordering) clone() *ordering {
o.sort()
oo := ordering{
entryMap: make(map[string]*entry),
}
for _, e := range o.ordered {
ne := &entry{
runes: e.runes,
elems: e.elems,
str: e.str,
decompose: e.decompose,
exclude: e.exclude,
logical: e.logical,
}
oo.insert(ne)
}
oo.sort() // link all ordering.
oo.patchForInsert()
return &oo
}
// front returns the first entry to be indexed.
// It assumes that sort() has been called.
func (o *ordering) front() *entry {
e := o.ordered[0]
if e.prev != nil {
log.Panicf("unexpected first entry: %v", e)
}
// The first entry is always a logical position, which should not be indexed.
e, _ = e.nextIndexed()
return e
}
// sort sorts all ordering based on their collation elements and initializes
// the prev, next, and level fields accordingly.
func (o *ordering) sort() {
sort.Sort(sortedEntries(o.ordered))
l := o.ordered
for i := 1; i < len(l); i++ {
k := i - 1
l[k].next = l[i]
_, l[k].level = compareWeights(l[k].elems, l[i].elems)
l[i].prev = l[k]
}
}
// genColElems generates a collation element array from the runes in str. This
// assumes that all collation elements have already been added to the Builder.
func (o *ordering) genColElems(str string) []rawCE {
elems := []rawCE{}
for _, r := range []rune(str) {
for _, ce := range o.find(string(r)).elems {
if ce.w[0] != 0 || ce.w[1] != 0 || ce.w[2] != 0 {
elems = append(elems, ce)
}
}
}
return elems
}
// 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.
package build
import (
"fmt"
"io"
"reflect"
"golang.org/x/text/internal/colltab"
)
// table is an intermediate structure that roughly resembles the table in collate.
type table struct {
colltab.Table
trie trie
root *trieHandle
}
// print writes the table as Go compilable code to w. It prefixes the
// variable names with name. It returns the number of bytes written
// and the size of the resulting table.
func (t *table) fprint(w io.Writer, name string) (n, size int, err error) {
update := func(nn, sz int, e error) {
n += nn
if err == nil {
err = e
}
size += sz
}
// Write arrays needed for the structure.
update(printColElems(w, t.ExpandElem, name+"ExpandElem"))
update(printColElems(w, t.ContractElem, name+"ContractElem"))
update(t.trie.printArrays(w, name))
update(printArray(t.ContractTries, w, name))
nn, e := fmt.Fprintf(w, "// Total size of %sTable is %d bytes\n", name, size)
update(nn, 0, e)
return
}
func (t *table) fprintIndex(w io.Writer, h *trieHandle, id string) (n int, err error) {
p := func(f string, a ...interface{}) {
nn, e := fmt.Fprintf(w, f, a...)
n += nn
if err == nil {
err = e
}
}
p("\t{ // %s\n", id)
p("\t\tlookupOffset: 0x%x,\n", h.lookupStart)
p("\t\tvaluesOffset: 0x%x,\n", h.valueStart)
p("\t},\n")
return
}
func printColElems(w io.Writer, a []uint32, name string) (n, sz int, err error) {
p := func(f string, a ...interface{}) {
nn, e := fmt.Fprintf(w, f, a...)
n += nn
if err == nil {
err = e
}
}
sz = len(a) * int(reflect.TypeFor[uint32]().Size())
p("// %s: %d entries, %d bytes\n", name, len(a), sz)
p("var %s = [%d]uint32 {", name, len(a))
for i, c := range a {
switch {
case i%64 == 0:
p("\n\t// Block %d, offset 0x%x\n", i/64, i)
case (i%64)%6 == 0:
p("\n\t")
}
p("0x%.8X, ", c)
}
p("\n}\n\n")
return
}
// 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.
// The trie in this file is used to associate the first full character
// in a UTF-8 string to a collation element.
// All but the last byte in a UTF-8 byte sequence are
// used to look up offsets in the index table to be used for the next byte.
// The last byte is used to index into a table of collation elements.
// This file contains the code for the generation of the trie.
package build
import (
"fmt"
"hash/fnv"
"io"
"reflect"
)
const (
blockSize = 64
blockOffset = 2 // Subtract 2 blocks to compensate for the 0x80 added to continuation bytes.
)
type trieHandle struct {
lookupStart uint16 // offset in table for first byte
valueStart uint16 // offset in table for first byte
}
type trie struct {
index []uint16
values []uint32
}
// trieNode is the intermediate trie structure used for generating a trie.
type trieNode struct {
index []*trieNode
value []uint32
b byte
refValue uint16
refIndex uint16
}
func newNode() *trieNode {
return &trieNode{
index: make([]*trieNode, 64),
value: make([]uint32, 128), // root node size is 128 instead of 64
}
}
func (n *trieNode) isInternal() bool {
return n.value != nil
}
func (n *trieNode) insert(r rune, value uint32) {
const maskx = 0x3F // mask out two most-significant bits
str := string(r)
if len(str) == 1 {
n.value[str[0]] = value
return
}
for i := 0; i < len(str)-1; i++ {
b := str[i] & maskx
if n.index == nil {
n.index = make([]*trieNode, blockSize)
}
nn := n.index[b]
if nn == nil {
nn = &trieNode{}
nn.b = b
n.index[b] = nn
}
n = nn
}
if n.value == nil {
n.value = make([]uint32, blockSize)
}
b := str[len(str)-1] & maskx
n.value[b] = value
}
type trieBuilder struct {
t *trie
roots []*trieHandle
lookupBlocks []*trieNode
valueBlocks []*trieNode
lookupBlockIdx map[uint32]*trieNode
valueBlockIdx map[uint32]*trieNode
}
func newTrieBuilder() *trieBuilder {
index := &trieBuilder{}
index.lookupBlocks = make([]*trieNode, 0)
index.valueBlocks = make([]*trieNode, 0)
index.lookupBlockIdx = make(map[uint32]*trieNode)
index.valueBlockIdx = make(map[uint32]*trieNode)
// The third nil is the default null block. The other two blocks
// are used to guarantee an offset of at least 3 for each block.
index.lookupBlocks = append(index.lookupBlocks, nil, nil, nil)
index.t = &trie{}
return index
}
func (b *trieBuilder) computeOffsets(n *trieNode) *trieNode {
hasher := fnv.New32()
if n.index != nil {
for i, nn := range n.index {
var vi, vv uint16
if nn != nil {
nn = b.computeOffsets(nn)
n.index[i] = nn
vi = nn.refIndex
vv = nn.refValue
}
hasher.Write([]byte{byte(vi >> 8), byte(vi)})
hasher.Write([]byte{byte(vv >> 8), byte(vv)})
}
h := hasher.Sum32()
nn, ok := b.lookupBlockIdx[h]
if !ok {
n.refIndex = uint16(len(b.lookupBlocks)) - blockOffset
b.lookupBlocks = append(b.lookupBlocks, n)
b.lookupBlockIdx[h] = n
} else {
n = nn
}
} else {
for _, v := range n.value {
hasher.Write([]byte{byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)})
}
h := hasher.Sum32()
nn, ok := b.valueBlockIdx[h]
if !ok {
n.refValue = uint16(len(b.valueBlocks)) - blockOffset
n.refIndex = n.refValue
b.valueBlocks = append(b.valueBlocks, n)
b.valueBlockIdx[h] = n
} else {
n = nn
}
}
return n
}
func (b *trieBuilder) addStartValueBlock(n *trieNode) uint16 {
hasher := fnv.New32()
for _, v := range n.value[:2*blockSize] {
hasher.Write([]byte{byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)})
}
h := hasher.Sum32()
nn, ok := b.valueBlockIdx[h]
if !ok {
n.refValue = uint16(len(b.valueBlocks))
n.refIndex = n.refValue
b.valueBlocks = append(b.valueBlocks, n)
// Add a dummy block to accommodate the double block size.
b.valueBlocks = append(b.valueBlocks, nil)
b.valueBlockIdx[h] = n
} else {
n = nn
}
return n.refValue
}
func genValueBlock(t *trie, n *trieNode) {
if n != nil {
for _, v := range n.value {
t.values = append(t.values, v)
}
}
}
func genLookupBlock(t *trie, n *trieNode) {
for _, nn := range n.index {
v := uint16(0)
if nn != nil {
if n.index != nil {
v = nn.refIndex
} else {
v = nn.refValue
}
}
t.index = append(t.index, v)
}
}
func (b *trieBuilder) addTrie(n *trieNode) *trieHandle {
h := &trieHandle{}
b.roots = append(b.roots, h)
h.valueStart = b.addStartValueBlock(n)
if len(b.roots) == 1 {
// We insert a null block after the first start value block.
// This ensures that continuation bytes UTF-8 sequences of length
// greater than 2 will automatically hit a null block if there
// was an undefined entry.
b.valueBlocks = append(b.valueBlocks, nil)
}
n = b.computeOffsets(n)
// Offset by one extra block as the first byte starts at 0xC0 instead of 0x80.
h.lookupStart = n.refIndex - 1
return h
}
// generate generates and returns the trie for n.
func (b *trieBuilder) generate() (t *trie, err error) {
t = b.t
if len(b.valueBlocks) >= 1<<16 {
return nil, fmt.Errorf("maximum number of value blocks exceeded (%d > %d)", len(b.valueBlocks), 1<<16)
}
if len(b.lookupBlocks) >= 1<<16 {
return nil, fmt.Errorf("maximum number of lookup blocks exceeded (%d > %d)", len(b.lookupBlocks), 1<<16)
}
genValueBlock(t, b.valueBlocks[0])
genValueBlock(t, &trieNode{value: make([]uint32, 64)})
for i := 2; i < len(b.valueBlocks); i++ {
genValueBlock(t, b.valueBlocks[i])
}
n := &trieNode{index: make([]*trieNode, 64)}
genLookupBlock(t, n)
genLookupBlock(t, n)
genLookupBlock(t, n)
for i := 3; i < len(b.lookupBlocks); i++ {
genLookupBlock(t, b.lookupBlocks[i])
}
return b.t, nil
}
func (t *trie) printArrays(w io.Writer, name string) (n, size int, err error) {
p := func(f string, a ...interface{}) {
nn, e := fmt.Fprintf(w, f, a...)
n += nn
if err == nil {
err = e
}
}
nv := len(t.values)
p("// %sValues: %d entries, %d bytes\n", name, nv, nv*4)
p("// Block 2 is the null block.\n")
p("var %sValues = [%d]uint32 {", name, nv)
var printnewline bool
for i, v := range t.values {
if i%blockSize == 0 {
p("\n\t// Block %#x, offset %#x", i/blockSize, i)
}
if i%4 == 0 {
printnewline = true
}
if v != 0 {
if printnewline {
p("\n\t")
printnewline = false
}
p("%#04x:%#08x, ", i, v)
}
}
p("\n}\n\n")
ni := len(t.index)
p("// %sLookup: %d entries, %d bytes\n", name, ni, ni*2)
p("// Block 0 is the null block.\n")
p("var %sLookup = [%d]uint16 {", name, ni)
printnewline = false
for i, v := range t.index {
if i%blockSize == 0 {
p("\n\t// Block %#x, offset %#x", i/blockSize, i)
}
if i%8 == 0 {
printnewline = true
}
if v != 0 {
if printnewline {
p("\n\t")
printnewline = false
}
p("%#03x:%#02x, ", i, v)
}
}
p("\n}\n\n")
return n, nv*4 + ni*2, err
}
func (t *trie) printStruct(w io.Writer, handle *trieHandle, name string) (n, sz int, err error) {
const msg = "trie{ %sLookup[%d:], %sValues[%d:], %sLookup[:], %sValues[:]}"
n, err = fmt.Fprintf(w, msg, name, handle.lookupStart*blockSize, name, handle.valueStart*blockSize, name, name)
sz += int(reflect.TypeFor[trie]().Size())
return
}
// 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.
// TODO: remove hard-coded versions when we have implemented fractional weights.
// The current implementation is incompatible with later CLDR versions.
//go:generate go run maketables.go -cldr=23 -unicode=6.2.0
// Package collate contains types for comparing and sorting Unicode strings
// according to a given collation order.
package collate // import "golang.org/x/text/collate"
import (
"bytes"
"strings"
"golang.org/x/text/internal/colltab"
"golang.org/x/text/language"
)
// Collator provides functionality for comparing strings for a given
// collation order.
type Collator struct {
options
sorter sorter
_iter [2]iter
}
func (c *Collator) iter(i int) *iter {
// TODO: evaluate performance for making the second iterator optional.
return &c._iter[i]
}
// Supported returns the list of languages for which collating differs from its parent.
func Supported() []language.Tag {
// TODO: use language.Coverage instead.
t := make([]language.Tag, len(tags))
copy(t, tags)
return t
}
func init() {
ids := strings.Split(availableLocales, ",")
tags = make([]language.Tag, len(ids))
for i, s := range ids {
tags[i] = language.Raw.MustParse(s)
}
}
var tags []language.Tag
// New returns a new Collator initialized for the given locale.
func New(t language.Tag, o ...Option) *Collator {
index := colltab.MatchLang(t, tags)
c := newCollator(getTable(locales[index]))
// Set options from the user-supplied tag.
c.setFromTag(t)
// Set the user-supplied options.
c.setOptions(o)
c.init()
return c
}
// NewFromTable returns a new Collator for the given Weighter.
func NewFromTable(w colltab.Weighter, o ...Option) *Collator {
c := newCollator(w)
c.setOptions(o)
c.init()
return c
}
func (c *Collator) init() {
if c.numeric {
c.t = colltab.NewNumericWeighter(c.t)
}
c._iter[0].init(c)
c._iter[1].init(c)
}
// Buffer holds keys generated by Key and KeyString.
type Buffer struct {
buf [4096]byte
key []byte
}
func (b *Buffer) init() {
if b.key == nil {
b.key = b.buf[:0]
}
}
// Reset clears the buffer from previous results generated by Key and KeyString.
func (b *Buffer) Reset() {
b.key = b.key[:0]
}
// Compare returns an integer comparing the two byte slices.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
func (c *Collator) Compare(a, b []byte) int {
// TODO: skip identical prefixes once we have a fast way to detect if a rune is
// part of a contraction. This would lead to roughly a 10% speedup for the colcmp regtest.
c.iter(0).SetInput(a)
c.iter(1).SetInput(b)
if res := c.compare(); res != 0 {
return res
}
if !c.ignore[colltab.Identity] {
return bytes.Compare(a, b)
}
return 0
}
// CompareString returns an integer comparing the two strings.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
func (c *Collator) CompareString(a, b string) int {
// TODO: skip identical prefixes once we have a fast way to detect if a rune is
// part of a contraction. This would lead to roughly a 10% speedup for the colcmp regtest.
c.iter(0).SetInputString(a)
c.iter(1).SetInputString(b)
if res := c.compare(); res != 0 {
return res
}
if !c.ignore[colltab.Identity] {
if a < b {
return -1
} else if a > b {
return 1
}
}
return 0
}
func compareLevel(f func(i *iter) int, a, b *iter) int {
a.pce = 0
b.pce = 0
for {
va := f(a)
vb := f(b)
if va != vb {
if va < vb {
return -1
}
return 1
} else if va == 0 {
break
}
}
return 0
}
func (c *Collator) compare() int {
ia, ib := c.iter(0), c.iter(1)
// Process primary level
if c.alternate != altShifted {
// TODO: implement script reordering
if res := compareLevel((*iter).nextPrimary, ia, ib); res != 0 {
return res
}
} else {
// TODO: handle shifted
}
if !c.ignore[colltab.Secondary] {
f := (*iter).nextSecondary
if c.backwards {
f = (*iter).prevSecondary
}
if res := compareLevel(f, ia, ib); res != 0 {
return res
}
}
// TODO: special case handling (Danish?)
if !c.ignore[colltab.Tertiary] || c.caseLevel {
if res := compareLevel((*iter).nextTertiary, ia, ib); res != 0 {
return res
}
if !c.ignore[colltab.Quaternary] {
if res := compareLevel((*iter).nextQuaternary, ia, ib); res != 0 {
return res
}
}
}
return 0
}
// Key returns the collation key for str.
// Passing the buffer buf may avoid memory allocations.
// The returned slice will point to an allocation in Buffer and will remain
// valid until the next call to buf.Reset().
func (c *Collator) Key(buf *Buffer, str []byte) []byte {
// See https://www.unicode.org/reports/tr10/#Main_Algorithm for more details.
buf.init()
return c.key(buf, c.getColElems(str))
}
// KeyFromString returns the collation key for str.
// Passing the buffer buf may avoid memory allocations.
// The returned slice will point to an allocation in Buffer and will retain
// valid until the next call to buf.ResetKeys().
func (c *Collator) KeyFromString(buf *Buffer, str string) []byte {
// See https://www.unicode.org/reports/tr10/#Main_Algorithm for more details.
buf.init()
return c.key(buf, c.getColElemsString(str))
}
func (c *Collator) key(buf *Buffer, w []colltab.Elem) []byte {
processWeights(c.alternate, c.t.Top(), w)
kn := len(buf.key)
c.keyFromElems(buf, w)
return buf.key[kn:]
}
func (c *Collator) getColElems(str []byte) []colltab.Elem {
i := c.iter(0)
i.SetInput(str)
for i.Next() {
}
return i.Elems
}
func (c *Collator) getColElemsString(str string) []colltab.Elem {
i := c.iter(0)
i.SetInputString(str)
for i.Next() {
}
return i.Elems
}
type iter struct {
wa [512]colltab.Elem
colltab.Iter
pce int
}
func (i *iter) init(c *Collator) {
i.Weighter = c.t
i.Elems = i.wa[:0]
}
func (i *iter) nextPrimary() int {
for {
for ; i.pce < i.N; i.pce++ {
if v := i.Elems[i.pce].Primary(); v != 0 {
i.pce++
return v
}
}
if !i.Next() {
return 0
}
}
}
func (i *iter) nextSecondary() int {
for ; i.pce < len(i.Elems); i.pce++ {
if v := i.Elems[i.pce].Secondary(); v != 0 {
i.pce++
return v
}
}
return 0
}
func (i *iter) prevSecondary() int {
for ; i.pce < len(i.Elems); i.pce++ {
if v := i.Elems[len(i.Elems)-i.pce-1].Secondary(); v != 0 {
i.pce++
return v
}
}
return 0
}
func (i *iter) nextTertiary() int {
for ; i.pce < len(i.Elems); i.pce++ {
if v := i.Elems[i.pce].Tertiary(); v != 0 {
i.pce++
return int(v)
}
}
return 0
}
func (i *iter) nextQuaternary() int {
for ; i.pce < len(i.Elems); i.pce++ {
if v := i.Elems[i.pce].Quaternary(); v != 0 {
i.pce++
return v
}
}
return 0
}
func appendPrimary(key []byte, p int) []byte {
// Convert to variable length encoding; supports up to 23 bits.
if p <= 0x7FFF {
key = append(key, uint8(p>>8), uint8(p))
} else {
key = append(key, uint8(p>>16)|0x80, uint8(p>>8), uint8(p))
}
return key
}
// keyFromElems converts the weights ws to a compact sequence of bytes.
// The result will be appended to the byte buffer in buf.
func (c *Collator) keyFromElems(buf *Buffer, ws []colltab.Elem) {
for _, v := range ws {
if w := v.Primary(); w > 0 {
buf.key = appendPrimary(buf.key, w)
}
}
if !c.ignore[colltab.Secondary] {
buf.key = append(buf.key, 0, 0)
// TODO: we can use one 0 if we can guarantee that all non-zero weights are > 0xFF.
if !c.backwards {
for _, v := range ws {
if w := v.Secondary(); w > 0 {
buf.key = append(buf.key, uint8(w>>8), uint8(w))
}
}
} else {
for i := len(ws) - 1; i >= 0; i-- {
if w := ws[i].Secondary(); w > 0 {
buf.key = append(buf.key, uint8(w>>8), uint8(w))
}
}
}
} else if c.caseLevel {
buf.key = append(buf.key, 0, 0)
}
if !c.ignore[colltab.Tertiary] || c.caseLevel {
buf.key = append(buf.key, 0, 0)
for _, v := range ws {
if w := v.Tertiary(); w > 0 {
buf.key = append(buf.key, uint8(w))
}
}
// Derive the quaternary weights from the options and other levels.
// Note that we represent MaxQuaternary as 0xFF. The first byte of the
// representation of a primary weight is always smaller than 0xFF,
// so using this single byte value will compare correctly.
if !c.ignore[colltab.Quaternary] && c.alternate >= altShifted {
if c.alternate == altShiftTrimmed {
lastNonFFFF := len(buf.key)
buf.key = append(buf.key, 0)
for _, v := range ws {
if w := v.Quaternary(); w == colltab.MaxQuaternary {
buf.key = append(buf.key, 0xFF)
} else if w > 0 {
buf.key = appendPrimary(buf.key, w)
lastNonFFFF = len(buf.key)
}
}
buf.key = buf.key[:lastNonFFFF]
} else {
buf.key = append(buf.key, 0)
for _, v := range ws {
if w := v.Quaternary(); w == colltab.MaxQuaternary {
buf.key = append(buf.key, 0xFF)
} else if w > 0 {
buf.key = appendPrimary(buf.key, w)
}
}
}
}
}
}
func processWeights(vw alternateHandling, top uint32, wa []colltab.Elem) {
ignore := false
vtop := int(top)
switch vw {
case altShifted, altShiftTrimmed:
for i := range wa {
if p := wa[i].Primary(); p <= vtop && p != 0 {
wa[i] = colltab.MakeQuaternary(p)
ignore = true
} else if p == 0 {
if ignore {
wa[i] = colltab.Ignore
}
} else {
ignore = false
}
}
case altBlanked:
for i := range wa {
if p := wa[i].Primary(); p <= vtop && (ignore || p != 0) {
wa[i] = colltab.Ignore
ignore = true
} else {
ignore = false
}
}
}
}
// Copyright 2013 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 collate
import "golang.org/x/text/internal/colltab"
const blockSize = 64
func getTable(t tableIndex) *colltab.Table {
return &colltab.Table{
Index: colltab.Trie{
Index0: mainLookup[:][blockSize*t.lookupOffset:],
Values0: mainValues[:][blockSize*t.valuesOffset:],
Index: mainLookup[:],
Values: mainValues[:],
},
ExpandElem: mainExpandElem[:],
ContractTries: colltab.ContractTrieSet(mainCTEntries[:]),
ContractElem: mainContractElem[:],
MaxContractLen: 18,
VariableTop: varTop,
}
}
// tableIndex holds information for constructing a table
// for a certain locale based on the main table.
type tableIndex struct {
lookupOffset uint32
valuesOffset uint32
}
// 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 collate
import (
"sort"
"golang.org/x/text/internal/colltab"
"golang.org/x/text/language"
"golang.org/x/text/unicode/norm"
)
// newCollator creates a new collator with default options configured.
func newCollator(t colltab.Weighter) *Collator {
// Initialize a collator with default options.
c := &Collator{
options: options{
ignore: [colltab.NumLevels]bool{
colltab.Quaternary: true,
colltab.Identity: true,
},
f: norm.NFD,
t: t,
},
}
// TODO: store vt in tags or remove.
c.variableTop = t.Top()
return c
}
// An Option is used to change the behavior of a Collator. Options override the
// settings passed through the locale identifier.
type Option struct {
priority int
f func(o *options)
}
type prioritizedOptions []Option
func (p prioritizedOptions) Len() int {
return len(p)
}
func (p prioritizedOptions) Swap(i, j int) {
p[i], p[j] = p[j], p[i]
}
func (p prioritizedOptions) Less(i, j int) bool {
return p[i].priority < p[j].priority
}
type options struct {
// ignore specifies which levels to ignore.
ignore [colltab.NumLevels]bool
// caseLevel is true if there is an additional level of case matching
// between the secondary and tertiary levels.
caseLevel bool
// backwards specifies the order of sorting at the secondary level.
// This option exists predominantly to support reverse sorting of accents in French.
backwards bool
// numeric specifies whether any sequence of decimal digits (category is Nd)
// is sorted at a primary level with its numeric value.
// For example, "A-21" < "A-123".
// This option is set by wrapping the main Weighter with NewNumericWeighter.
numeric bool
// alternate specifies an alternative handling of variables.
alternate alternateHandling
// variableTop is the largest primary value that is considered to be
// variable.
variableTop uint32
t colltab.Weighter
f norm.Form
}
func (o *options) setOptions(opts []Option) {
sort.Sort(prioritizedOptions(opts))
for _, x := range opts {
x.f(o)
}
}
// OptionsFromTag extracts the BCP47 collation options from the tag and
// configures a collator accordingly. These options are set before any other
// option.
func OptionsFromTag(t language.Tag) Option {
return Option{0, func(o *options) {
o.setFromTag(t)
}}
}
func (o *options) setFromTag(t language.Tag) {
o.caseLevel = ldmlBool(t, o.caseLevel, "kc")
o.backwards = ldmlBool(t, o.backwards, "kb")
o.numeric = ldmlBool(t, o.numeric, "kn")
// Extract settings from the BCP47 u extension.
switch t.TypeForKey("ks") { // strength
case "level1":
o.ignore[colltab.Secondary] = true
o.ignore[colltab.Tertiary] = true
case "level2":
o.ignore[colltab.Tertiary] = true
case "level3", "":
// The default.
case "level4":
o.ignore[colltab.Quaternary] = false
case "identic":
o.ignore[colltab.Quaternary] = false
o.ignore[colltab.Identity] = false
}
switch t.TypeForKey("ka") {
case "shifted":
o.alternate = altShifted
// The following two types are not official BCP47, but we support them to
// give access to this otherwise hidden functionality. The name blanked is
// derived from the LDML name blanked and posix reflects the main use of
// the shift-trimmed option.
case "blanked":
o.alternate = altBlanked
case "posix":
o.alternate = altShiftTrimmed
}
// TODO: caseFirst ("kf"), reorder ("kr"), and maybe variableTop ("vt").
// Not used:
// - normalization ("kk", not necessary for this implementation)
// - hiraganaQuatenary ("kh", obsolete)
}
func ldmlBool(t language.Tag, old bool, key string) bool {
switch t.TypeForKey(key) {
case "true":
return true
case "false":
return false
default:
return old
}
}
var (
// IgnoreCase sets case-insensitive comparison.
IgnoreCase Option = ignoreCase
ignoreCase = Option{3, ignoreCaseF}
// IgnoreDiacritics causes diacritical marks to be ignored. ("o" == "ö").
IgnoreDiacritics Option = ignoreDiacritics
ignoreDiacritics = Option{3, ignoreDiacriticsF}
// IgnoreWidth causes full-width characters to match their half-width
// equivalents.
IgnoreWidth Option = ignoreWidth
ignoreWidth = Option{2, ignoreWidthF}
// Loose sets the collator to ignore diacritics, case and width.
Loose Option = loose
loose = Option{4, looseF}
// Force ordering if strings are equivalent but not equal.
Force Option = force
force = Option{5, forceF}
// Numeric specifies that numbers should sort numerically ("2" < "12").
Numeric Option = numeric
numeric = Option{5, numericF}
)
func ignoreWidthF(o *options) {
o.ignore[colltab.Tertiary] = true
o.caseLevel = true
}
func ignoreDiacriticsF(o *options) {
o.ignore[colltab.Secondary] = true
}
func ignoreCaseF(o *options) {
o.ignore[colltab.Tertiary] = true
o.caseLevel = false
}
func looseF(o *options) {
ignoreWidthF(o)
ignoreDiacriticsF(o)
ignoreCaseF(o)
}
func forceF(o *options) {
o.ignore[colltab.Identity] = false
}
func numericF(o *options) { o.numeric = true }
// Reorder overrides the pre-defined ordering of scripts and character sets.
func Reorder(s ...string) Option {
// TODO: need fractional weights to implement this.
panic("TODO: implement")
}
// TODO: consider making these public again. These options cannot be fully
// specified in BCP47, so an API interface seems warranted. Still a higher-level
// interface would be nice (e.g. a POSIX option for enabling altShiftTrimmed)
// alternateHandling identifies the various ways in which variables are handled.
// A rune with a primary weight lower than the variable top is considered a
// variable.
// See https://www.unicode.org/reports/tr10/#Variable_Weighting for details.
type alternateHandling int
const (
// altNonIgnorable turns off special handling of variables.
altNonIgnorable alternateHandling = iota
// altBlanked sets variables and all subsequent primary ignorables to be
// ignorable at all levels. This is identical to removing all variables
// and subsequent primary ignorables from the input.
altBlanked
// altShifted sets variables to be ignorable for levels one through three and
// adds a fourth level based on the values of the ignored levels.
altShifted
// altShiftTrimmed is a slight variant of altShifted that is used to
// emulate POSIX.
altShiftTrimmed
)
// Copyright 2013 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 collate
import (
"bytes"
"sort"
)
const (
maxSortBuffer = 40960
maxSortEntries = 4096
)
type swapper interface {
Swap(i, j int)
}
type sorter struct {
buf *Buffer
keys [][]byte
src swapper
}
func (s *sorter) init(n int) {
if s.buf == nil {
s.buf = &Buffer{}
s.buf.init()
}
if cap(s.keys) < n {
s.keys = make([][]byte, n)
}
s.keys = s.keys[0:n]
}
func (s *sorter) sort(src swapper) {
s.src = src
sort.Sort(s)
}
func (s sorter) Len() int {
return len(s.keys)
}
func (s sorter) Less(i, j int) bool {
return bytes.Compare(s.keys[i], s.keys[j]) == -1
}
func (s sorter) Swap(i, j int) {
s.keys[i], s.keys[j] = s.keys[j], s.keys[i]
s.src.Swap(i, j)
}
// A Lister can be sorted by Collator's Sort method.
type Lister interface {
Len() int
Swap(i, j int)
// Bytes returns the bytes of the text at index i.
Bytes(i int) []byte
}
// Sort uses sort.Sort to sort the strings represented by x using the rules of c.
func (c *Collator) Sort(x Lister) {
n := x.Len()
c.sorter.init(n)
for i := 0; i < n; i++ {
c.sorter.keys[i] = c.Key(c.sorter.buf, x.Bytes(i))
}
c.sorter.sort(x)
}
// SortStrings uses sort.Sort to sort the strings in x using the rules of c.
func (c *Collator) SortStrings(x []string) {
c.sorter.init(len(x))
for i, s := range x {
c.sorter.keys[i] = c.KeyFromString(c.sorter.buf, s)
}
c.sorter.sort(sort.StringSlice(x))
}
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
package currency
import (
"time"
"golang.org/x/text/language"
)
// This file contains code common to gen.go and the package code.
const (
cashShift = 3
roundMask = 0x7
nonTenderBit = 0x8000
)
// currencyInfo contains information about a currency.
// bits 0..2: index into roundings for standard rounding
// bits 3..5: index into roundings for cash rounding
type currencyInfo byte
// roundingType defines the scale (number of fractional decimals) and increments
// in terms of units of size 10^-scale. For example, for scale == 2 and
// increment == 1, the currency is rounded to units of 0.01.
type roundingType struct {
scale, increment uint8
}
// roundings contains rounding data for currencies. This struct is
// created by hand as it is very unlikely to change much.
var roundings = [...]roundingType{
{2, 1}, // default
{0, 1},
{1, 1},
{3, 1},
{4, 1},
{2, 5}, // cash rounding alternative
{2, 50},
}
// regionToCode returns a 16-bit region code. Only two-letter codes are
// supported. (Three-letter codes are not needed.)
func regionToCode(r language.Region) uint16 {
if s := r.String(); len(s) == 2 {
return uint16(s[0])<<8 | uint16(s[1])
}
return 0
}
func toDate(t time.Time) uint32 {
y := t.Year()
if y == 1 {
return 0
}
date := uint32(y) << 4
date |= uint32(t.Month())
date <<= 5
date |= uint32(t.Day())
return date
}
func fromDate(date uint32) time.Time {
return time.Date(int(date>>9), time.Month((date>>5)&0xf), int(date&0x1f), 0, 0, 0, 0, time.UTC)
}
// 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.
//go:generate go run gen.go gen_common.go -output tables.go
// Package currency contains currency-related functionality.
//
// NOTE: the formatting functionality is currently under development and may
// change without notice.
package currency // import "golang.org/x/text/currency"
import (
"errors"
"sort"
"golang.org/x/text/internal/tag"
"golang.org/x/text/language"
)
// TODO:
// - language-specific currency names.
// - currency formatting.
// - currency information per region
// - register currency code (there are no private use area)
// TODO: remove Currency type from package language.
// Kind determines the rounding and rendering properties of a currency value.
type Kind struct {
rounding rounding
// TODO: formatting type: standard, accounting. See CLDR.
}
type rounding byte
const (
standard rounding = iota
cash
)
var (
// Standard defines standard rounding and formatting for currencies.
Standard Kind = Kind{rounding: standard}
// Cash defines rounding and formatting standards for cash transactions.
Cash Kind = Kind{rounding: cash}
// Accounting defines rounding and formatting standards for accounting.
Accounting Kind = Kind{rounding: standard}
)
// Rounding reports the rounding characteristics for the given currency, where
// scale is the number of fractional decimals and increment is the number of
// units in terms of 10^(-scale) to which to round to.
func (k Kind) Rounding(cur Unit) (scale, increment int) {
info := currency.Elem(int(cur.index))[3]
switch k.rounding {
case standard:
info &= roundMask
case cash:
info >>= cashShift
}
return int(roundings[info].scale), int(roundings[info].increment)
}
// Unit is an ISO 4217 currency designator.
type Unit struct {
index uint16
}
// String returns the ISO code of u.
func (u Unit) String() string {
if u.index == 0 {
return "XXX"
}
return currency.Elem(int(u.index))[:3]
}
// Amount creates an Amount for the given currency unit and amount.
func (u Unit) Amount(amount interface{}) Amount {
// TODO: verify amount is a supported number type
return Amount{amount: amount, currency: u}
}
var (
errSyntax = errors.New("currency: tag is not well-formed")
errValue = errors.New("currency: tag is not a recognized currency")
)
// ParseISO parses a 3-letter ISO 4217 currency code. It returns an error if s
// is not well-formed or not a recognized currency code.
func ParseISO(s string) (Unit, error) {
var buf [4]byte // Take one byte more to detect oversize keys.
key := buf[:copy(buf[:], s)]
if !tag.FixCase("XXX", key) {
return Unit{}, errSyntax
}
if i := currency.Index(key); i >= 0 {
if i == xxx {
return Unit{}, nil
}
return Unit{uint16(i)}, nil
}
return Unit{}, errValue
}
// MustParseISO is like ParseISO, but panics if the given currency unit
// cannot be parsed. It simplifies safe initialization of Unit values.
func MustParseISO(s string) Unit {
c, err := ParseISO(s)
if err != nil {
panic(err)
}
return c
}
// FromRegion reports the currency unit that is currently legal tender in the
// given region according to CLDR. It will return false if region currently does
// not have a legal tender.
func FromRegion(r language.Region) (currency Unit, ok bool) {
x := regionToCode(r)
i := sort.Search(len(regionToCurrency), func(i int) bool {
return regionToCurrency[i].region >= x
})
if i < len(regionToCurrency) && regionToCurrency[i].region == x {
return Unit{regionToCurrency[i].code}, true
}
return Unit{}, false
}
// FromTag reports the most likely currency for the given tag. It considers the
// currency defined in the -u extension and infers the region if necessary.
func FromTag(t language.Tag) (Unit, language.Confidence) {
if cur := t.TypeForKey("cu"); len(cur) == 3 {
c, _ := ParseISO(cur)
return c, language.Exact
}
r, conf := t.Region()
if cur, ok := FromRegion(r); ok {
return cur, conf
}
return Unit{}, language.No
}
var (
// Undefined and testing.
XXX Unit = Unit{}
XTS Unit = Unit{xts}
// G10 currencies https://en.wikipedia.org/wiki/G10_currencies.
USD Unit = Unit{usd}
EUR Unit = Unit{eur}
JPY Unit = Unit{jpy}
GBP Unit = Unit{gbp}
CHF Unit = Unit{chf}
AUD Unit = Unit{aud}
NZD Unit = Unit{nzd}
CAD Unit = Unit{cad}
SEK Unit = Unit{sek}
NOK Unit = Unit{nok}
// Additional common currencies as defined by CLDR.
BRL Unit = Unit{brl}
CNY Unit = Unit{cny}
DKK Unit = Unit{dkk}
INR Unit = Unit{inr}
RUB Unit = Unit{rub}
HKD Unit = Unit{hkd}
IDR Unit = Unit{idr}
KRW Unit = Unit{krw}
MXN Unit = Unit{mxn}
PLN Unit = Unit{pln}
SAR Unit = Unit{sar}
THB Unit = Unit{thb}
TRY Unit = Unit{try}
TWD Unit = Unit{twd}
ZAR Unit = Unit{zar}
// Precious metals.
XAG Unit = Unit{xag}
XAU Unit = Unit{xau}
XPT Unit = Unit{xpt}
XPD Unit = Unit{xpd}
)
// 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.
package currency
import (
"fmt"
"sort"
"golang.org/x/text/internal/format"
"golang.org/x/text/internal/language/compact"
"golang.org/x/text/internal/number"
"golang.org/x/text/language"
)
// Amount is an amount-currency unit pair.
type Amount struct {
amount interface{} // Change to decimal(64|128).
currency Unit
}
// Currency reports the currency unit of this amount.
func (a Amount) Currency() Unit { return a.currency }
// TODO: based on decimal type, but may make sense to customize a bit.
// func (a Amount) Decimal()
// func (a Amount) Int() (int64, error)
// func (a Amount) Fraction() (int64, error)
// func (a Amount) Rat() *big.Rat
// func (a Amount) Float() (float64, error)
// func (a Amount) Scale() uint
// func (a Amount) Precision() uint
// func (a Amount) Sign() int
//
// Add/Sub/Div/Mul/Round.
// Format implements fmt.Formatter. It accepts format.State for
// language-specific rendering.
func (a Amount) Format(s fmt.State, verb rune) {
v := formattedValue{
currency: a.currency,
amount: a.amount,
format: defaultFormat,
}
v.Format(s, verb)
}
// formattedValue is currency amount or unit that implements language-sensitive
// formatting.
type formattedValue struct {
currency Unit
amount interface{} // Amount, Unit, or number.
format *options
}
// Format implements fmt.Formatter. It accepts format.State for
// language-specific rendering.
func (v formattedValue) Format(s fmt.State, verb rune) {
var tag language.Tag
var lang compact.ID
if state, ok := s.(format.State); ok {
tag = state.Language()
lang, _ = compact.RegionalID(compact.Tag(tag))
}
// Get the options. Use DefaultFormat if not present.
opt := v.format
if opt == nil {
opt = defaultFormat
}
cur := v.currency
if cur.index == 0 {
cur = opt.currency
}
sym := opt.symbol(lang, cur)
if v.amount != nil {
var f number.Formatter
f.InitDecimal(tag)
scale, increment := opt.kind.Rounding(cur)
f.RoundingContext.SetScale(scale)
f.RoundingContext.Increment = uint32(increment)
f.RoundingContext.IncrementScale = uint8(scale)
f.RoundingContext.Mode = number.ToNearestAway
d := f.Append(nil, v.amount)
fmt.Fprint(s, sym, " ", string(d))
} else {
fmt.Fprint(s, sym)
}
}
// Formatter decorates a given number, Unit or Amount with formatting options.
type Formatter func(amount interface{}) formattedValue
// func (f Formatter) Options(opts ...Option) Formatter
// TODO: call this a Formatter or FormatFunc?
var dummy = USD.Amount(0)
// adjust creates a new Formatter based on the adjustments of fn on f.
func (f Formatter) adjust(fn func(*options)) Formatter {
var o options = *(f(dummy).format)
fn(&o)
return o.format
}
// Default creates a new Formatter that defaults to currency unit c if a numeric
// value is passed that is not associated with a currency.
func (f Formatter) Default(currency Unit) Formatter {
return f.adjust(func(o *options) { o.currency = currency })
}
// Kind sets the kind of the underlying currency unit.
func (f Formatter) Kind(k Kind) Formatter {
return f.adjust(func(o *options) { o.kind = k })
}
var defaultFormat *options = ISO(dummy).format
var (
// Uses Narrow symbols. Overrides Symbol, if present.
NarrowSymbol Formatter = Formatter(formNarrow)
// Use Symbols instead of ISO codes, when available.
Symbol Formatter = Formatter(formSymbol)
// Use ISO code as symbol.
ISO Formatter = Formatter(formISO)
// TODO:
// // Use full name as symbol.
// Name Formatter
)
// options configures rendering and rounding options for an Amount.
type options struct {
currency Unit
kind Kind
symbol func(compactIndex compact.ID, c Unit) string
}
func (o *options) format(amount interface{}) formattedValue {
v := formattedValue{format: o}
switch x := amount.(type) {
case Amount:
v.amount = x.amount
v.currency = x.currency
case *Amount:
v.amount = x.amount
v.currency = x.currency
case Unit:
v.currency = x
case *Unit:
v.currency = *x
default:
if o.currency.index == 0 {
panic("cannot format number without a currency being set")
}
// TODO: Must be a number.
v.amount = x
v.currency = o.currency
}
return v
}
var (
optISO = options{symbol: lookupISO}
optSymbol = options{symbol: lookupSymbol}
optNarrow = options{symbol: lookupNarrow}
)
// These need to be functions, rather than curried methods, as curried methods
// are evaluated at init time, causing tables to be included unconditionally.
func formISO(x interface{}) formattedValue { return optISO.format(x) }
func formSymbol(x interface{}) formattedValue { return optSymbol.format(x) }
func formNarrow(x interface{}) formattedValue { return optNarrow.format(x) }
func lookupISO(x compact.ID, c Unit) string { return c.String() }
func lookupSymbol(x compact.ID, c Unit) string { return normalSymbol.lookup(x, c) }
func lookupNarrow(x compact.ID, c Unit) string { return narrowSymbol.lookup(x, c) }
type symbolIndex struct {
index []uint16 // position corresponds with compact index of language.
data []curToIndex
}
var (
normalSymbol = symbolIndex{normalLangIndex, normalSymIndex}
narrowSymbol = symbolIndex{narrowLangIndex, narrowSymIndex}
)
func (x *symbolIndex) lookup(lang compact.ID, c Unit) string {
for {
index := x.data[x.index[lang]:x.index[lang+1]]
i := sort.Search(len(index), func(i int) bool {
return index[i].cur >= c.index
})
if i < len(index) && index[i].cur == c.index {
x := index[i].idx
start := x + 1
end := start + uint16(symbols[x])
if start == end {
return c.String()
}
return symbols[start:end]
}
if lang == 0 {
break
}
lang = lang.Parent()
}
return c.String()
}
// 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.
package currency
import (
"sort"
"time"
"golang.org/x/text/language"
)
// QueryIter represents a set of Units. The default set includes all Units that
// are currently in use as legal tender in any Region.
type QueryIter interface {
// Next returns true if there is a next element available.
// It must be called before any of the other methods are called.
Next() bool
// Unit returns the unit of the current iteration.
Unit() Unit
// Region returns the Region for the current iteration.
Region() language.Region
// From returns the date from which the unit was used in the region.
// It returns false if this date is unknown.
From() (time.Time, bool)
// To returns the date up till which the unit was used in the region.
// It returns false if this date is unknown or if the unit is still in use.
To() (time.Time, bool)
// IsTender reports whether the unit is a legal tender in the region during
// the specified date range.
IsTender() bool
}
// Query represents a set of Units. The default set includes all Units that are
// currently in use as legal tender in any Region.
func Query(options ...QueryOption) QueryIter {
it := &iter{
end: len(regionData),
date: 0xFFFFFFFF,
}
for _, fn := range options {
fn(it)
}
return it
}
// NonTender returns a new query that also includes matching Units that are not
// legal tender.
var NonTender QueryOption = nonTender
func nonTender(i *iter) {
i.nonTender = true
}
// Historical selects the units for all dates.
var Historical QueryOption = historical
func historical(i *iter) {
i.date = hist
}
// A QueryOption can be used to change the set of unit information returned by
// a query.
type QueryOption func(*iter)
// Date queries the units that were in use at the given point in history.
func Date(t time.Time) QueryOption {
d := toDate(t)
return func(i *iter) {
i.date = d
}
}
// Region limits the query to only return entries for the given region.
func Region(r language.Region) QueryOption {
p, end := len(regionData), len(regionData)
x := regionToCode(r)
i := sort.Search(len(regionData), func(i int) bool {
return regionData[i].region >= x
})
if i < len(regionData) && regionData[i].region == x {
p = i
for i++; i < len(regionData) && regionData[i].region == x; i++ {
}
end = i
}
return func(i *iter) {
i.p, i.end = p, end
}
}
const (
hist = 0x00
now = 0xFFFFFFFF
)
type iter struct {
*regionInfo
p, end int
date uint32
nonTender bool
}
func (i *iter) Next() bool {
for ; i.p < i.end; i.p++ {
i.regionInfo = ®ionData[i.p]
if !i.nonTender && !i.IsTender() {
continue
}
if i.date == hist || (i.from <= i.date && (i.to == 0 || i.date <= i.to)) {
i.p++
return true
}
}
return false
}
func (r *regionInfo) Region() language.Region {
// TODO: this could be much faster.
var buf [2]byte
buf[0] = uint8(r.region >> 8)
buf[1] = uint8(r.region)
return language.MustParseRegion(string(buf[:]))
}
func (r *regionInfo) Unit() Unit {
return Unit{r.code &^ nonTenderBit}
}
func (r *regionInfo) IsTender() bool {
return r.code&nonTenderBit == 0
}
func (r *regionInfo) From() (time.Time, bool) {
if r.from == 0 {
return time.Time{}, false
}
return fromDate(r.from), true
}
func (r *regionInfo) To() (time.Time, bool) {
if r.to == 0 {
return time.Time{}, false
}
return fromDate(r.to), true
}
// Copyright 2013 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.
//go:generate go run maketables.go
// Package charmap provides simple character encodings such as IBM Code Page 437
// and Windows 1252.
package charmap // import "golang.org/x/text/encoding/charmap"
import (
"unicode/utf8"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/internal"
"golang.org/x/text/encoding/internal/identifier"
"golang.org/x/text/transform"
)
// These encodings vary only in the way clients should interpret them. Their
// coded character set is identical and a single implementation can be shared.
var (
// ISO8859_6E is the ISO 8859-6E encoding.
ISO8859_6E encoding.Encoding = &iso8859_6E
// ISO8859_6I is the ISO 8859-6I encoding.
ISO8859_6I encoding.Encoding = &iso8859_6I
// ISO8859_8E is the ISO 8859-8E encoding.
ISO8859_8E encoding.Encoding = &iso8859_8E
// ISO8859_8I is the ISO 8859-8I encoding.
ISO8859_8I encoding.Encoding = &iso8859_8I
iso8859_6E = internal.Encoding{
Encoding: ISO8859_6,
Name: "ISO-8859-6E",
MIB: identifier.ISO88596E,
}
iso8859_6I = internal.Encoding{
Encoding: ISO8859_6,
Name: "ISO-8859-6I",
MIB: identifier.ISO88596I,
}
iso8859_8E = internal.Encoding{
Encoding: ISO8859_8,
Name: "ISO-8859-8E",
MIB: identifier.ISO88598E,
}
iso8859_8I = internal.Encoding{
Encoding: ISO8859_8,
Name: "ISO-8859-8I",
MIB: identifier.ISO88598I,
}
)
// All is a list of all defined encodings in this package.
var All []encoding.Encoding = listAll
// TODO: implement these encodings, in order of importance.
// ASCII, ISO8859_1: Rather common. Close to Windows 1252.
// ISO8859_9: Close to Windows 1254.
// utf8Enc holds a rune's UTF-8 encoding in data[:len].
type utf8Enc struct {
len uint8
data [3]byte
}
// Charmap is an 8-bit character set encoding.
type Charmap struct {
// name is the encoding's name.
name string
// mib is the encoding type of this encoder.
mib identifier.MIB
// asciiSuperset states whether the encoding is a superset of ASCII.
asciiSuperset bool
// low is the lower bound of the encoded byte for a non-ASCII rune. If
// Charmap.asciiSuperset is true then this will be 0x80, otherwise 0x00.
low uint8
// replacement is the encoded replacement character.
replacement byte
// decode is the map from encoded byte to UTF-8.
decode [256]utf8Enc
// encoding is the map from runes to encoded bytes. Each entry is a
// uint32: the high 8 bits are the encoded byte and the low 24 bits are
// the rune. The table entries are sorted by ascending rune.
encode [256]uint32
}
// NewDecoder implements the encoding.Encoding interface.
func (m *Charmap) NewDecoder() *encoding.Decoder {
return &encoding.Decoder{Transformer: charmapDecoder{charmap: m}}
}
// NewEncoder implements the encoding.Encoding interface.
func (m *Charmap) NewEncoder() *encoding.Encoder {
return &encoding.Encoder{Transformer: charmapEncoder{charmap: m}}
}
// String returns the Charmap's name.
func (m *Charmap) String() string {
return m.name
}
// ID implements an internal interface.
func (m *Charmap) ID() (mib identifier.MIB, other string) {
return m.mib, ""
}
// charmapDecoder implements transform.Transformer by decoding to UTF-8.
type charmapDecoder struct {
transform.NopResetter
charmap *Charmap
}
func (m charmapDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
for i, c := range src {
if m.charmap.asciiSuperset && c < utf8.RuneSelf {
if nDst >= len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst] = c
nDst++
nSrc = i + 1
continue
}
decode := &m.charmap.decode[c]
n := int(decode.len)
if nDst+n > len(dst) {
err = transform.ErrShortDst
break
}
// It's 15% faster to avoid calling copy for these tiny slices.
for j := 0; j < n; j++ {
dst[nDst] = decode.data[j]
nDst++
}
nSrc = i + 1
}
return nDst, nSrc, err
}
// DecodeByte returns the Charmap's rune decoding of the byte b.
func (m *Charmap) DecodeByte(b byte) rune {
switch x := &m.decode[b]; x.len {
case 1:
return rune(x.data[0])
case 2:
return rune(x.data[0]&0x1f)<<6 | rune(x.data[1]&0x3f)
default:
return rune(x.data[0]&0x0f)<<12 | rune(x.data[1]&0x3f)<<6 | rune(x.data[2]&0x3f)
}
}
// charmapEncoder implements transform.Transformer by encoding from UTF-8.
type charmapEncoder struct {
transform.NopResetter
charmap *Charmap
}
func (m charmapEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
loop:
for nSrc < len(src) {
if nDst >= len(dst) {
err = transform.ErrShortDst
break
}
r = rune(src[nSrc])
// Decode a 1-byte rune.
if r < utf8.RuneSelf {
if m.charmap.asciiSuperset {
nSrc++
dst[nDst] = uint8(r)
nDst++
continue
}
size = 1
} else {
// Decode a multi-byte rune.
r, size = utf8.DecodeRune(src[nSrc:])
if size == 1 {
// All valid runes of size 1 (those below utf8.RuneSelf) were
// handled above. We have invalid UTF-8 or we haven't seen the
// full character yet.
if !atEOF && !utf8.FullRune(src[nSrc:]) {
err = transform.ErrShortSrc
} else {
err = internal.RepertoireError(m.charmap.replacement)
}
break
}
}
// Binary search in [low, high) for that rune in the m.charmap.encode table.
for low, high := int(m.charmap.low), 0x100; ; {
if low >= high {
err = internal.RepertoireError(m.charmap.replacement)
break loop
}
mid := (low + high) / 2
got := m.charmap.encode[mid]
gotRune := rune(got & (1<<24 - 1))
if gotRune < r {
low = mid + 1
} else if gotRune > r {
high = mid
} else {
dst[nDst] = byte(got >> 24)
nDst++
break
}
}
nSrc += size
}
return nDst, nSrc, err
}
// EncodeRune returns the Charmap's byte encoding of the rune r. ok is whether
// r is in the Charmap's repertoire. If not, b is set to the Charmap's
// replacement byte. This is often the ASCII substitute character '\x1a'.
func (m *Charmap) EncodeRune(r rune) (b byte, ok bool) {
if r < utf8.RuneSelf && m.asciiSuperset {
return byte(r), true
}
for low, high := int(m.low), 0x100; ; {
if low >= high {
return m.replacement, false
}
mid := (low + high) / 2
got := m.encode[mid]
gotRune := rune(got & (1<<24 - 1))
if gotRune < r {
low = mid + 1
} else if gotRune > r {
high = mid
} else {
return byte(got >> 24), true
}
}
}
// Copyright 2013 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 encoding defines an interface for character encodings, such as Shift
// JIS and Windows 1252, that can convert to and from UTF-8.
//
// Encoding implementations are provided in other packages, such as
// golang.org/x/text/encoding/charmap and
// golang.org/x/text/encoding/japanese.
package encoding // import "golang.org/x/text/encoding"
import (
"errors"
"io"
"strconv"
"unicode/utf8"
"golang.org/x/text/encoding/internal/identifier"
"golang.org/x/text/transform"
)
// TODO:
// - There seems to be some inconsistency in when decoders return errors
// and when not. Also documentation seems to suggest they shouldn't return
// errors at all (except for UTF-16).
// - Encoders seem to rely on or at least benefit from the input being in NFC
// normal form. Perhaps add an example how users could prepare their output.
// Encoding is a character set encoding that can be transformed to and from
// UTF-8.
type Encoding interface {
// NewDecoder returns a Decoder.
NewDecoder() *Decoder
// NewEncoder returns an Encoder.
NewEncoder() *Encoder
}
// A Decoder converts bytes to UTF-8. It implements transform.Transformer.
//
// Transforming source bytes that are not of that encoding will not result in an
// error per se. Each byte that cannot be transcoded will be represented in the
// output by the UTF-8 encoding of '\uFFFD', the replacement rune.
type Decoder struct {
transform.Transformer
// This forces external creators of Decoders to use names in struct
// initializers, allowing for future extendibility without having to break
// code.
_ struct{}
}
// Bytes converts the given encoded bytes to UTF-8. It returns the converted
// bytes or nil, err if any error occurred.
func (d *Decoder) Bytes(b []byte) ([]byte, error) {
b, _, err := transform.Bytes(d, b)
if err != nil {
return nil, err
}
return b, nil
}
// String converts the given encoded string to UTF-8. It returns the converted
// string or "", err if any error occurred.
func (d *Decoder) String(s string) (string, error) {
s, _, err := transform.String(d, s)
if err != nil {
return "", err
}
return s, nil
}
// Reader wraps another Reader to decode its bytes.
//
// The Decoder may not be used for any other operation as long as the returned
// Reader is in use.
func (d *Decoder) Reader(r io.Reader) io.Reader {
return transform.NewReader(r, d)
}
// An Encoder converts bytes from UTF-8. It implements transform.Transformer.
//
// Each rune that cannot be transcoded will result in an error. In this case,
// the transform will consume all source byte up to, not including the offending
// rune. Transforming source bytes that are not valid UTF-8 will be replaced by
// `\uFFFD`. To return early with an error instead, use transform.Chain to
// preprocess the data with a UTF8Validator.
type Encoder struct {
transform.Transformer
// This forces external creators of Encoders to use names in struct
// initializers, allowing for future extendibility without having to break
// code.
_ struct{}
}
// Bytes converts bytes from UTF-8. It returns the converted bytes or nil, err if
// any error occurred.
func (e *Encoder) Bytes(b []byte) ([]byte, error) {
b, _, err := transform.Bytes(e, b)
if err != nil {
return nil, err
}
return b, nil
}
// String converts a string from UTF-8. It returns the converted string or
// "", err if any error occurred.
func (e *Encoder) String(s string) (string, error) {
s, _, err := transform.String(e, s)
if err != nil {
return "", err
}
return s, nil
}
// Writer wraps another Writer to encode its UTF-8 output.
//
// The Encoder may not be used for any other operation as long as the returned
// Writer is in use.
func (e *Encoder) Writer(w io.Writer) io.Writer {
return transform.NewWriter(w, e)
}
// ASCIISub is the ASCII substitute character, as recommended by
// https://unicode.org/reports/tr36/#Text_Comparison
const ASCIISub = '\x1a'
// Nop is the nop encoding. Its transformed bytes are the same as the source
// bytes; it does not replace invalid UTF-8 sequences.
var Nop Encoding = nop{}
type nop struct{}
func (nop) NewDecoder() *Decoder {
return &Decoder{Transformer: transform.Nop}
}
func (nop) NewEncoder() *Encoder {
return &Encoder{Transformer: transform.Nop}
}
// Replacement is the replacement encoding. Decoding from the replacement
// encoding yields a single '\uFFFD' replacement rune. Encoding from UTF-8 to
// the replacement encoding yields the same as the source bytes except that
// invalid UTF-8 is converted to '\uFFFD'.
//
// It is defined at http://encoding.spec.whatwg.org/#replacement
var Replacement Encoding = replacement{}
type replacement struct{}
func (replacement) NewDecoder() *Decoder {
return &Decoder{Transformer: replacementDecoder{}}
}
func (replacement) NewEncoder() *Encoder {
return &Encoder{Transformer: replacementEncoder{}}
}
func (replacement) ID() (mib identifier.MIB, other string) {
return identifier.Replacement, ""
}
type replacementDecoder struct{ transform.NopResetter }
func (replacementDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
if len(dst) < 3 {
return 0, 0, transform.ErrShortDst
}
if atEOF {
const fffd = "\ufffd"
dst[0] = fffd[0]
dst[1] = fffd[1]
dst[2] = fffd[2]
nDst = 3
}
return nDst, len(src), nil
}
type replacementEncoder struct{ transform.NopResetter }
func (replacementEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
for ; nSrc < len(src); nSrc += size {
r = rune(src[nSrc])
// Decode a 1-byte rune.
if r < utf8.RuneSelf {
size = 1
} else {
// Decode a multi-byte rune.
r, size = utf8.DecodeRune(src[nSrc:])
if size == 1 {
// All valid runes of size 1 (those below utf8.RuneSelf) were
// handled above. We have invalid UTF-8 or we haven't seen the
// full character yet.
if !atEOF && !utf8.FullRune(src[nSrc:]) {
err = transform.ErrShortSrc
break
}
r = '\ufffd'
}
}
if nDst+utf8.RuneLen(r) > len(dst) {
err = transform.ErrShortDst
break
}
nDst += utf8.EncodeRune(dst[nDst:], r)
}
return nDst, nSrc, err
}
// HTMLEscapeUnsupported wraps encoders to replace source runes outside the
// repertoire of the destination encoding with HTML escape sequences.
//
// This wrapper exists to comply to URL and HTML forms requiring a
// non-terminating legacy encoder. The produced sequences may lead to data
// loss as they are indistinguishable from legitimate input. To avoid this
// issue, use UTF-8 encodings whenever possible.
func HTMLEscapeUnsupported(e *Encoder) *Encoder {
return &Encoder{Transformer: &errorHandler{e, errorToHTML}}
}
// ReplaceUnsupported wraps encoders to replace source runes outside the
// repertoire of the destination encoding with an encoding-specific
// replacement.
//
// This wrapper is only provided for backwards compatibility and legacy
// handling. Its use is strongly discouraged. Use UTF-8 whenever possible.
func ReplaceUnsupported(e *Encoder) *Encoder {
return &Encoder{Transformer: &errorHandler{e, errorToReplacement}}
}
type errorHandler struct {
*Encoder
handler func(dst []byte, r rune, err repertoireError) (n int, ok bool)
}
// TODO: consider making this error public in some form.
type repertoireError interface {
Replacement() byte
}
func (h errorHandler) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
nDst, nSrc, err = h.Transformer.Transform(dst, src, atEOF)
for err != nil {
rerr, ok := err.(repertoireError)
if !ok {
return nDst, nSrc, err
}
r, sz := utf8.DecodeRune(src[nSrc:])
n, ok := h.handler(dst[nDst:], r, rerr)
if !ok {
return nDst, nSrc, transform.ErrShortDst
}
err = nil
nDst += n
if nSrc += sz; nSrc < len(src) {
var dn, sn int
dn, sn, err = h.Transformer.Transform(dst[nDst:], src[nSrc:], atEOF)
nDst += dn
nSrc += sn
}
}
return nDst, nSrc, err
}
func errorToHTML(dst []byte, r rune, err repertoireError) (n int, ok bool) {
buf := [8]byte{}
b := strconv.AppendUint(buf[:0], uint64(r), 10)
if n = len(b) + len("&#;"); n >= len(dst) {
return 0, false
}
dst[0] = '&'
dst[1] = '#'
dst[copy(dst[2:], b)+2] = ';'
return n, true
}
func errorToReplacement(dst []byte, r rune, err repertoireError) (n int, ok bool) {
if len(dst) == 0 {
return 0, false
}
dst[0] = err.Replacement()
return 1, true
}
// ErrInvalidUTF8 means that a transformer encountered invalid UTF-8.
var ErrInvalidUTF8 = errors.New("encoding: invalid UTF-8")
// UTF8Validator is a transformer that returns ErrInvalidUTF8 on the first
// input byte that is not valid UTF-8.
var UTF8Validator transform.Transformer = utf8Validator{}
type utf8Validator struct{ transform.NopResetter }
func (utf8Validator) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
n := len(src)
if n > len(dst) {
n = len(dst)
}
for i := 0; i < n; {
if c := src[i]; c < utf8.RuneSelf {
dst[i] = c
i++
continue
}
_, size := utf8.DecodeRune(src[i:])
if size == 1 {
// All valid runes of size 1 (those below utf8.RuneSelf) were
// handled above. We have invalid UTF-8 or we haven't seen the
// full character yet.
err = ErrInvalidUTF8
if !atEOF && !utf8.FullRune(src[i:]) {
err = transform.ErrShortSrc
}
return i, i, err
}
if i+size > len(dst) {
return i, i, transform.ErrShortDst
}
for ; size > 0; size-- {
dst[i] = src[i]
i++
}
}
if len(src) > len(dst) {
err = transform.ErrShortDst
}
return n, n, err
}
// 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.
//go:generate go run gen.go
// Package htmlindex maps character set encoding names to Encodings as
// recommended by the W3C for use in HTML 5. See http://www.w3.org/TR/encoding.
package htmlindex
// TODO: perhaps have a "bare" version of the index (used by this package) that
// is not pre-loaded with all encodings. Global variables in encodings prevent
// the linker from being able to purge unneeded tables. This means that
// referencing all encodings, as this package does for the default index, links
// in all encodings unconditionally.
//
// This issue can be solved by either solving the linking issue (see
// https://github.com/golang/go/issues/6330) or refactoring the encoding tables
// (e.g. moving the tables to internal packages that do not use global
// variables).
// TODO: allow canonicalizing names
import (
"errors"
"strings"
"sync"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/internal/identifier"
"golang.org/x/text/language"
)
var (
errInvalidName = errors.New("htmlindex: invalid encoding name")
errUnknown = errors.New("htmlindex: unknown Encoding")
errUnsupported = errors.New("htmlindex: this encoding is not supported")
)
var (
matcherOnce sync.Once
matcher language.Matcher
)
// LanguageDefault returns the canonical name of the default encoding for a
// given language.
func LanguageDefault(tag language.Tag) string {
matcherOnce.Do(func() {
tags := []language.Tag{}
for _, t := range strings.Split(locales, " ") {
tags = append(tags, language.MustParse(t))
}
matcher = language.NewMatcher(tags, language.PreferSameScript(true))
})
_, i, _ := matcher.Match(tag)
return canonical[localeMap[i]] // Default is Windows-1252.
}
// Get returns an Encoding for one of the names listed in
// http://www.w3.org/TR/encoding using the Default Index. Matching is case-
// insensitive.
func Get(name string) (encoding.Encoding, error) {
x, ok := nameMap[strings.ToLower(strings.TrimSpace(name))]
if !ok {
return nil, errInvalidName
}
return encodings[x], nil
}
// Name reports the canonical name of the given Encoding. It will return
// an error if e is not associated with a supported encoding scheme.
func Name(e encoding.Encoding) (string, error) {
id, ok := e.(identifier.Interface)
if !ok {
return "", errUnknown
}
mib, _ := id.ID()
if mib == 0 {
return "", errUnknown
}
v, ok := mibMap[mib]
if !ok {
return "", errUnsupported
}
return canonical[v], nil
}
// 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.
// Package internal contains code that is shared among encoding implementations.
package internal
import (
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/internal/identifier"
"golang.org/x/text/transform"
)
// Encoding is an implementation of the Encoding interface that adds the String
// and ID methods to an existing encoding.
type Encoding struct {
encoding.Encoding
Name string
MIB identifier.MIB
}
// _ verifies that Encoding implements identifier.Interface.
var _ identifier.Interface = (*Encoding)(nil)
func (e *Encoding) String() string {
return e.Name
}
func (e *Encoding) ID() (mib identifier.MIB, other string) {
return e.MIB, ""
}
// SimpleEncoding is an Encoding that combines two Transformers.
type SimpleEncoding struct {
Decoder transform.Transformer
Encoder transform.Transformer
}
func (e *SimpleEncoding) NewDecoder() *encoding.Decoder {
return &encoding.Decoder{Transformer: e.Decoder}
}
func (e *SimpleEncoding) NewEncoder() *encoding.Encoder {
return &encoding.Encoder{Transformer: e.Encoder}
}
// FuncEncoding is an Encoding that combines two functions returning a new
// Transformer.
type FuncEncoding struct {
Decoder func() transform.Transformer
Encoder func() transform.Transformer
}
func (e FuncEncoding) NewDecoder() *encoding.Decoder {
return &encoding.Decoder{Transformer: e.Decoder()}
}
func (e FuncEncoding) NewEncoder() *encoding.Encoder {
return &encoding.Encoder{Transformer: e.Encoder()}
}
// A RepertoireError indicates a rune is not in the repertoire of a destination
// encoding. It is associated with an encoding-specific suggested replacement
// byte.
type RepertoireError byte
// Error implements the error interface.
func (r RepertoireError) Error() string {
return "encoding: rune not supported by encoding."
}
// Replacement returns the replacement string associated with this error.
func (r RepertoireError) Replacement() byte { return byte(r) }
var ErrASCIIReplacement = RepertoireError(encoding.ASCIISub)
// Copyright 2013 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 japanese
import (
"unicode/utf8"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/internal"
"golang.org/x/text/encoding/internal/identifier"
"golang.org/x/text/transform"
)
// EUCJP is the EUC-JP encoding.
var EUCJP encoding.Encoding = &eucJP
var eucJP = internal.Encoding{
Encoding: &internal.SimpleEncoding{Decoder: eucJPDecoder{}, Encoder: eucJPEncoder{}},
Name: "EUC-JP",
MIB: identifier.EUCPkdFmtJapanese,
}
type eucJPDecoder struct{ transform.NopResetter }
// See https://encoding.spec.whatwg.org/#euc-jp-decoder.
func (eucJPDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
loop:
for ; nSrc < len(src); nSrc += size {
switch c0 := src[nSrc]; {
case c0 < utf8.RuneSelf:
r, size = rune(c0), 1
case c0 == 0x8e:
if nSrc+1 >= len(src) {
if !atEOF {
err = transform.ErrShortSrc
break loop
}
r, size = utf8.RuneError, 1
break
}
c1 := src[nSrc+1]
switch {
case c1 < 0xa1:
r, size = utf8.RuneError, 1
case c1 > 0xdf:
r, size = utf8.RuneError, 2
if c1 == 0xff {
size = 1
}
default:
r, size = rune(c1)+(0xff61-0xa1), 2
}
case c0 == 0x8f:
if nSrc+2 >= len(src) {
if !atEOF {
err = transform.ErrShortSrc
break loop
}
r, size = utf8.RuneError, 1
if p := nSrc + 1; p < len(src) && 0xa1 <= src[p] && src[p] < 0xfe {
size = 2
}
break
}
c1 := src[nSrc+1]
if c1 < 0xa1 || 0xfe < c1 {
r, size = utf8.RuneError, 1
break
}
c2 := src[nSrc+2]
if c2 < 0xa1 || 0xfe < c2 {
r, size = utf8.RuneError, 2
break
}
r, size = utf8.RuneError, 3
if i := int(c1-0xa1)*94 + int(c2-0xa1); i < len(jis0212Decode) {
r = rune(jis0212Decode[i])
if r == 0 {
r = utf8.RuneError
}
}
case 0xa1 <= c0 && c0 <= 0xfe:
if nSrc+1 >= len(src) {
if !atEOF {
err = transform.ErrShortSrc
break loop
}
r, size = utf8.RuneError, 1
break
}
c1 := src[nSrc+1]
if c1 < 0xa1 || 0xfe < c1 {
r, size = utf8.RuneError, 1
break
}
r, size = utf8.RuneError, 2
if i := int(c0-0xa1)*94 + int(c1-0xa1); i < len(jis0208Decode) {
r = rune(jis0208Decode[i])
if r == 0 {
r = utf8.RuneError
}
}
default:
r, size = utf8.RuneError, 1
}
if nDst+utf8.RuneLen(r) > len(dst) {
err = transform.ErrShortDst
break loop
}
nDst += utf8.EncodeRune(dst[nDst:], r)
}
return nDst, nSrc, err
}
type eucJPEncoder struct{ transform.NopResetter }
func (eucJPEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
for ; nSrc < len(src); nSrc += size {
r = rune(src[nSrc])
// Decode a 1-byte rune.
if r < utf8.RuneSelf {
size = 1
} else {
// Decode a multi-byte rune.
r, size = utf8.DecodeRune(src[nSrc:])
if size == 1 {
// All valid runes of size 1 (those below utf8.RuneSelf) were
// handled above. We have invalid UTF-8 or we haven't seen the
// full character yet.
if !atEOF && !utf8.FullRune(src[nSrc:]) {
err = transform.ErrShortSrc
break
}
}
// func init checks that the switch covers all tables.
switch {
case encode0Low <= r && r < encode0High:
if r = rune(encode0[r-encode0Low]); r != 0 {
goto write2or3
}
case encode1Low <= r && r < encode1High:
if r = rune(encode1[r-encode1Low]); r != 0 {
goto write2or3
}
case encode2Low <= r && r < encode2High:
if r = rune(encode2[r-encode2Low]); r != 0 {
goto write2or3
}
case encode3Low <= r && r < encode3High:
if r = rune(encode3[r-encode3Low]); r != 0 {
goto write2or3
}
case encode4Low <= r && r < encode4High:
if r = rune(encode4[r-encode4Low]); r != 0 {
goto write2or3
}
case encode5Low <= r && r < encode5High:
if 0xff61 <= r && r < 0xffa0 {
goto write2
}
if r = rune(encode5[r-encode5Low]); r != 0 {
goto write2or3
}
}
err = internal.ErrASCIIReplacement
break
}
if nDst >= len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst] = uint8(r)
nDst++
continue
write2or3:
if r>>tableShift == jis0208 {
if nDst+2 > len(dst) {
err = transform.ErrShortDst
break
}
} else {
if nDst+3 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst] = 0x8f
nDst++
}
dst[nDst+0] = 0xa1 + uint8(r>>codeShift)&codeMask
dst[nDst+1] = 0xa1 + uint8(r)&codeMask
nDst += 2
continue
write2:
if nDst+2 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst+0] = 0x8e
dst[nDst+1] = uint8(r - (0xff61 - 0xa1))
nDst += 2
continue
}
return nDst, nSrc, err
}
func init() {
// Check that the hard-coded encode switch covers all tables.
if numEncodeTables != 6 {
panic("bad numEncodeTables")
}
}
// Copyright 2013 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 japanese
import (
"unicode/utf8"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/internal"
"golang.org/x/text/encoding/internal/identifier"
"golang.org/x/text/transform"
)
// ISO2022JP is the ISO-2022-JP encoding.
var ISO2022JP encoding.Encoding = &iso2022JP
var iso2022JP = internal.Encoding{
Encoding: internal.FuncEncoding{Decoder: iso2022JPNewDecoder, Encoder: iso2022JPNewEncoder},
Name: "ISO-2022-JP",
MIB: identifier.ISO2022JP,
}
func iso2022JPNewDecoder() transform.Transformer {
return new(iso2022JPDecoder)
}
func iso2022JPNewEncoder() transform.Transformer {
return new(iso2022JPEncoder)
}
const (
asciiState = iota
katakanaState
jis0208State
jis0212State
)
const asciiEsc = 0x1b
type iso2022JPDecoder int
func (d *iso2022JPDecoder) Reset() {
*d = asciiState
}
func (d *iso2022JPDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
for ; nSrc < len(src); nSrc += size {
c0 := src[nSrc]
if c0 >= utf8.RuneSelf {
r, size = '\ufffd', 1
goto write
}
if c0 == asciiEsc {
if nSrc+2 >= len(src) {
if !atEOF {
return nDst, nSrc, transform.ErrShortSrc
}
// TODO: is it correct to only skip 1??
r, size = '\ufffd', 1
goto write
}
size = 3
c1 := src[nSrc+1]
c2 := src[nSrc+2]
switch {
case c1 == '$' && (c2 == '@' || c2 == 'B'): // 0x24 {0x40, 0x42}
*d = jis0208State
continue
case c1 == '$' && c2 == '(': // 0x24 0x28
if nSrc+3 >= len(src) {
if !atEOF {
return nDst, nSrc, transform.ErrShortSrc
}
r, size = '\ufffd', 1
goto write
}
size = 4
if src[nSrc+3] == 'D' {
*d = jis0212State
continue
}
case c1 == '(' && (c2 == 'B' || c2 == 'J'): // 0x28 {0x42, 0x4A}
*d = asciiState
continue
case c1 == '(' && c2 == 'I': // 0x28 0x49
*d = katakanaState
continue
}
r, size = '\ufffd', 1
goto write
}
switch *d {
case asciiState:
r, size = rune(c0), 1
case katakanaState:
if c0 < 0x21 || 0x60 <= c0 {
r, size = '\ufffd', 1
goto write
}
r, size = rune(c0)+(0xff61-0x21), 1
default:
if c0 == 0x0a {
*d = asciiState
r, size = rune(c0), 1
goto write
}
if nSrc+1 >= len(src) {
if !atEOF {
return nDst, nSrc, transform.ErrShortSrc
}
r, size = '\ufffd', 1
goto write
}
size = 2
c1 := src[nSrc+1]
i := int(c0-0x21)*94 + int(c1-0x21)
if *d == jis0208State && i < len(jis0208Decode) {
r = rune(jis0208Decode[i])
} else if *d == jis0212State && i < len(jis0212Decode) {
r = rune(jis0212Decode[i])
} else {
r = '\ufffd'
goto write
}
if r == 0 {
r = '\ufffd'
}
}
write:
if nDst+utf8.RuneLen(r) > len(dst) {
return nDst, nSrc, transform.ErrShortDst
}
nDst += utf8.EncodeRune(dst[nDst:], r)
}
return nDst, nSrc, err
}
type iso2022JPEncoder int
func (e *iso2022JPEncoder) Reset() {
*e = asciiState
}
func (e *iso2022JPEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
for ; nSrc < len(src); nSrc += size {
r = rune(src[nSrc])
// Decode a 1-byte rune.
if r < utf8.RuneSelf {
size = 1
} else {
// Decode a multi-byte rune.
r, size = utf8.DecodeRune(src[nSrc:])
if size == 1 {
// All valid runes of size 1 (those below utf8.RuneSelf) were
// handled above. We have invalid UTF-8 or we haven't seen the
// full character yet.
if !atEOF && !utf8.FullRune(src[nSrc:]) {
err = transform.ErrShortSrc
break
}
}
// func init checks that the switch covers all tables.
//
// http://encoding.spec.whatwg.org/#iso-2022-jp says that "the index jis0212
// is not used by the iso-2022-jp encoder due to lack of widespread support".
//
// TODO: do we have to special-case U+00A5 and U+203E, as per
// http://encoding.spec.whatwg.org/#iso-2022-jp
// Doing so would mean that "\u00a5" would not be preserved
// after an encode-decode round trip.
switch {
case encode0Low <= r && r < encode0High:
if r = rune(encode0[r-encode0Low]); r>>tableShift == jis0208 {
goto writeJIS
}
case encode1Low <= r && r < encode1High:
if r = rune(encode1[r-encode1Low]); r>>tableShift == jis0208 {
goto writeJIS
}
case encode2Low <= r && r < encode2High:
if r = rune(encode2[r-encode2Low]); r>>tableShift == jis0208 {
goto writeJIS
}
case encode3Low <= r && r < encode3High:
if r = rune(encode3[r-encode3Low]); r>>tableShift == jis0208 {
goto writeJIS
}
case encode4Low <= r && r < encode4High:
if r = rune(encode4[r-encode4Low]); r>>tableShift == jis0208 {
goto writeJIS
}
case encode5Low <= r && r < encode5High:
if 0xff61 <= r && r < 0xffa0 {
goto writeKatakana
}
if r = rune(encode5[r-encode5Low]); r>>tableShift == jis0208 {
goto writeJIS
}
}
// Switch back to ASCII state in case of error so that an ASCII
// replacement character can be written in the correct state.
if *e != asciiState {
if nDst+3 > len(dst) {
err = transform.ErrShortDst
break
}
*e = asciiState
dst[nDst+0] = asciiEsc
dst[nDst+1] = '('
dst[nDst+2] = 'B'
nDst += 3
}
err = internal.ErrASCIIReplacement
break
}
if *e != asciiState {
if nDst+4 > len(dst) {
err = transform.ErrShortDst
break
}
*e = asciiState
dst[nDst+0] = asciiEsc
dst[nDst+1] = '('
dst[nDst+2] = 'B'
nDst += 3
} else if nDst >= len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst] = uint8(r)
nDst++
continue
writeJIS:
if *e != jis0208State {
if nDst+5 > len(dst) {
err = transform.ErrShortDst
break
}
*e = jis0208State
dst[nDst+0] = asciiEsc
dst[nDst+1] = '$'
dst[nDst+2] = 'B'
nDst += 3
} else if nDst+2 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst+0] = 0x21 + uint8(r>>codeShift)&codeMask
dst[nDst+1] = 0x21 + uint8(r)&codeMask
nDst += 2
continue
writeKatakana:
if *e != katakanaState {
if nDst+4 > len(dst) {
err = transform.ErrShortDst
break
}
*e = katakanaState
dst[nDst+0] = asciiEsc
dst[nDst+1] = '('
dst[nDst+2] = 'I'
nDst += 3
} else if nDst >= len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst] = uint8(r - (0xff61 - 0x21))
nDst++
continue
}
if atEOF && err == nil && *e != asciiState {
if nDst+3 > len(dst) {
err = transform.ErrShortDst
} else {
*e = asciiState
dst[nDst+0] = asciiEsc
dst[nDst+1] = '('
dst[nDst+2] = 'B'
nDst += 3
}
}
return nDst, nSrc, err
}
// Copyright 2013 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 japanese
import (
"unicode/utf8"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/internal"
"golang.org/x/text/encoding/internal/identifier"
"golang.org/x/text/transform"
)
// ShiftJIS is the Shift JIS encoding, also known as Code Page 932 and
// Windows-31J.
var ShiftJIS encoding.Encoding = &shiftJIS
var shiftJIS = internal.Encoding{
Encoding: &internal.SimpleEncoding{Decoder: shiftJISDecoder{}, Encoder: shiftJISEncoder{}},
Name: "Shift JIS",
MIB: identifier.ShiftJIS,
}
type shiftJISDecoder struct{ transform.NopResetter }
func (shiftJISDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
loop:
for ; nSrc < len(src); nSrc += size {
switch c0 := src[nSrc]; {
case c0 < utf8.RuneSelf:
r, size = rune(c0), 1
case 0xa1 <= c0 && c0 < 0xe0:
r, size = rune(c0)+(0xff61-0xa1), 1
case (0x81 <= c0 && c0 < 0xa0) || (0xe0 <= c0 && c0 < 0xfd):
if c0 <= 0x9f {
c0 -= 0x70
} else {
c0 -= 0xb0
}
c0 = 2*c0 - 0x21
if nSrc+1 >= len(src) {
if !atEOF {
err = transform.ErrShortSrc
break loop
}
r, size = '\ufffd', 1
goto write
}
c1 := src[nSrc+1]
switch {
case c1 < 0x40:
r, size = '\ufffd', 1 // c1 is ASCII so output on next round
goto write
case c1 < 0x7f:
c0--
c1 -= 0x40
case c1 == 0x7f:
r, size = '\ufffd', 1 // c1 is ASCII so output on next round
goto write
case c1 < 0x9f:
c0--
c1 -= 0x41
case c1 < 0xfd:
c1 -= 0x9f
default:
r, size = '\ufffd', 2
goto write
}
r, size = '\ufffd', 2
if i := int(c0)*94 + int(c1); i < len(jis0208Decode) {
r = rune(jis0208Decode[i])
if r == 0 {
r = '\ufffd'
}
}
case c0 == 0x80:
r, size = 0x80, 1
default:
r, size = '\ufffd', 1
}
write:
if nDst+utf8.RuneLen(r) > len(dst) {
err = transform.ErrShortDst
break loop
}
nDst += utf8.EncodeRune(dst[nDst:], r)
}
return nDst, nSrc, err
}
type shiftJISEncoder struct{ transform.NopResetter }
func (shiftJISEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
loop:
for ; nSrc < len(src); nSrc += size {
r = rune(src[nSrc])
// Decode a 1-byte rune.
if r < utf8.RuneSelf {
size = 1
} else {
// Decode a multi-byte rune.
r, size = utf8.DecodeRune(src[nSrc:])
if size == 1 {
// All valid runes of size 1 (those below utf8.RuneSelf) were
// handled above. We have invalid UTF-8 or we haven't seen the
// full character yet.
if !atEOF && !utf8.FullRune(src[nSrc:]) {
err = transform.ErrShortSrc
break loop
}
}
// func init checks that the switch covers all tables.
switch {
case encode0Low <= r && r < encode0High:
if r = rune(encode0[r-encode0Low]); r>>tableShift == jis0208 {
goto write2
}
case encode1Low <= r && r < encode1High:
if r = rune(encode1[r-encode1Low]); r>>tableShift == jis0208 {
goto write2
}
case encode2Low <= r && r < encode2High:
if r = rune(encode2[r-encode2Low]); r>>tableShift == jis0208 {
goto write2
}
case encode3Low <= r && r < encode3High:
if r = rune(encode3[r-encode3Low]); r>>tableShift == jis0208 {
goto write2
}
case encode4Low <= r && r < encode4High:
if r = rune(encode4[r-encode4Low]); r>>tableShift == jis0208 {
goto write2
}
case encode5Low <= r && r < encode5High:
if 0xff61 <= r && r < 0xffa0 {
r -= 0xff61 - 0xa1
goto write1
}
if r = rune(encode5[r-encode5Low]); r>>tableShift == jis0208 {
goto write2
}
}
err = internal.ErrASCIIReplacement
break
}
write1:
if nDst >= len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst] = uint8(r)
nDst++
continue
write2:
j1 := uint8(r>>codeShift) & codeMask
j2 := uint8(r) & codeMask
if nDst+2 > len(dst) {
err = transform.ErrShortDst
break loop
}
if j1 <= 61 {
dst[nDst+0] = 129 + j1/2
} else {
dst[nDst+0] = 193 + j1/2
}
if j1&1 == 0 {
dst[nDst+1] = j2 + j2/63 + 64
} else {
dst[nDst+1] = j2 + 159
}
nDst += 2
continue
}
return nDst, nSrc, err
}
// Copyright 2013 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 korean
import (
"unicode/utf8"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/internal"
"golang.org/x/text/encoding/internal/identifier"
"golang.org/x/text/transform"
)
// All is a list of all defined encodings in this package.
var All = []encoding.Encoding{EUCKR}
// EUCKR is the EUC-KR encoding, also known as Code Page 949.
var EUCKR encoding.Encoding = &eucKR
var eucKR = internal.Encoding{
Encoding: &internal.SimpleEncoding{Decoder: eucKRDecoder{}, Encoder: eucKREncoder{}},
Name: "EUC-KR",
MIB: identifier.EUCKR,
}
type eucKRDecoder struct{ transform.NopResetter }
func (eucKRDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
loop:
for ; nSrc < len(src); nSrc += size {
switch c0 := src[nSrc]; {
case c0 < utf8.RuneSelf:
r, size = rune(c0), 1
case 0x81 <= c0 && c0 < 0xff:
if nSrc+1 >= len(src) {
if !atEOF {
err = transform.ErrShortSrc
break loop
}
r, size = utf8.RuneError, 1
break
}
c1 := src[nSrc+1]
size = 2
if c0 < 0xc7 {
r = 178 * rune(c0-0x81)
switch {
case 0x41 <= c1 && c1 < 0x5b:
r += rune(c1) - (0x41 - 0*26)
case 0x61 <= c1 && c1 < 0x7b:
r += rune(c1) - (0x61 - 1*26)
case 0x81 <= c1 && c1 < 0xff:
r += rune(c1) - (0x81 - 2*26)
default:
goto decError
}
} else if 0xa1 <= c1 && c1 < 0xff {
r = 178*(0xc7-0x81) + rune(c0-0xc7)*94 + rune(c1-0xa1)
} else {
goto decError
}
if int(r) < len(decode) {
r = rune(decode[r])
if r != 0 {
break
}
}
decError:
r = utf8.RuneError
if c1 < utf8.RuneSelf {
size = 1
}
default:
r, size = utf8.RuneError, 1
break
}
if nDst+utf8.RuneLen(r) > len(dst) {
err = transform.ErrShortDst
break
}
nDst += utf8.EncodeRune(dst[nDst:], r)
}
return nDst, nSrc, err
}
type eucKREncoder struct{ transform.NopResetter }
func (eucKREncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
for ; nSrc < len(src); nSrc += size {
r = rune(src[nSrc])
// Decode a 1-byte rune.
if r < utf8.RuneSelf {
size = 1
if nDst >= len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst] = uint8(r)
nDst++
continue
} else {
// Decode a multi-byte rune.
r, size = utf8.DecodeRune(src[nSrc:])
if size == 1 {
// All valid runes of size 1 (those below utf8.RuneSelf) were
// handled above. We have invalid UTF-8 or we haven't seen the
// full character yet.
if !atEOF && !utf8.FullRune(src[nSrc:]) {
err = transform.ErrShortSrc
break
}
}
// func init checks that the switch covers all tables.
switch {
case encode0Low <= r && r < encode0High:
if r = rune(encode0[r-encode0Low]); r != 0 {
goto write2
}
case encode1Low <= r && r < encode1High:
if r = rune(encode1[r-encode1Low]); r != 0 {
goto write2
}
case encode2Low <= r && r < encode2High:
if r = rune(encode2[r-encode2Low]); r != 0 {
goto write2
}
case encode3Low <= r && r < encode3High:
if r = rune(encode3[r-encode3Low]); r != 0 {
goto write2
}
case encode4Low <= r && r < encode4High:
if r = rune(encode4[r-encode4Low]); r != 0 {
goto write2
}
case encode5Low <= r && r < encode5High:
if r = rune(encode5[r-encode5Low]); r != 0 {
goto write2
}
case encode6Low <= r && r < encode6High:
if r = rune(encode6[r-encode6Low]); r != 0 {
goto write2
}
}
err = internal.ErrASCIIReplacement
break
}
write2:
if nDst+2 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst+0] = uint8(r >> 8)
dst[nDst+1] = uint8(r)
nDst += 2
continue
}
return nDst, nSrc, err
}
func init() {
// Check that the hard-coded encode switch covers all tables.
if numEncodeTables != 7 {
panic("bad numEncodeTables")
}
}
// Copyright 2013 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 simplifiedchinese
import (
"unicode/utf8"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/internal"
"golang.org/x/text/encoding/internal/identifier"
"golang.org/x/text/transform"
)
var (
// GB18030 is the GB18030 encoding.
GB18030 encoding.Encoding = &gbk18030
// GBK is the GBK encoding. It encodes an extension of the GB2312 character set
// and is also known as Code Page 936.
GBK encoding.Encoding = &gbk
)
var gbk = internal.Encoding{
Encoding: &internal.SimpleEncoding{
Decoder: gbkDecoder{gb18030: false},
Encoder: gbkEncoder{gb18030: false},
},
Name: "GBK",
MIB: identifier.GBK,
}
var gbk18030 = internal.Encoding{
Encoding: &internal.SimpleEncoding{
Decoder: gbkDecoder{gb18030: true},
Encoder: gbkEncoder{gb18030: true},
},
Name: "GB18030",
MIB: identifier.GB18030,
}
type gbkDecoder struct {
transform.NopResetter
gb18030 bool
}
func (d gbkDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
loop:
for ; nSrc < len(src); nSrc += size {
switch c0 := src[nSrc]; {
case c0 < utf8.RuneSelf:
r, size = rune(c0), 1
// Microsoft's Code Page 936 extends GBK 1.0 to encode the euro sign U+20AC
// as 0x80. The HTML5 specification at http://encoding.spec.whatwg.org/#gbk
// says to treat "gbk" as Code Page 936.
// GBK’s decoder is gb18030’s decoder. https://encoding.spec.whatwg.org/#gbk-decoder
// If byte is 0x80, return code point U+20AC. https://encoding.spec.whatwg.org/#gb18030-decoder
case c0 == 0x80:
r, size = '€', 1
case c0 < 0xff:
if nSrc+1 >= len(src) {
if !atEOF {
err = transform.ErrShortSrc
break loop
}
r, size = utf8.RuneError, 1
goto write
}
c1 := src[nSrc+1]
switch {
case 0x40 <= c1 && c1 < 0x7f:
c1 -= 0x40
case 0x80 <= c1 && c1 < 0xff:
c1 -= 0x41
case d.gb18030 && 0x30 <= c1 && c1 < 0x40:
if nSrc+3 >= len(src) {
if !atEOF {
err = transform.ErrShortSrc
break loop
}
// The second byte here is always ASCII, so we can set size
// to 1 in all cases.
r, size = utf8.RuneError, 1
goto write
}
c2 := src[nSrc+2]
if c2 < 0x81 || 0xff <= c2 {
r, size = utf8.RuneError, 1
goto write
}
c3 := src[nSrc+3]
if c3 < 0x30 || 0x3a <= c3 {
r, size = utf8.RuneError, 1
goto write
}
size = 4
r = ((rune(c0-0x81)*10+rune(c1-0x30))*126+rune(c2-0x81))*10 + rune(c3-0x30)
if r < 39420 {
i, j := 0, len(gb18030)
for i < j {
h := i + (j-i)/2
if r >= rune(gb18030[h][0]) {
i = h + 1
} else {
j = h
}
}
dec := &gb18030[i-1]
r += rune(dec[1]) - rune(dec[0])
goto write
}
r -= 189000
if 0 <= r && r < 0x100000 {
r += 0x10000
} else {
r, size = utf8.RuneError, 1
}
goto write
default:
r, size = utf8.RuneError, 1
goto write
}
r, size = '\ufffd', 2
if i := int(c0-0x81)*190 + int(c1); i < len(decode) {
r = rune(decode[i])
if r == 0 {
r = '\ufffd'
}
}
default:
r, size = utf8.RuneError, 1
}
write:
if nDst+utf8.RuneLen(r) > len(dst) {
err = transform.ErrShortDst
break loop
}
nDst += utf8.EncodeRune(dst[nDst:], r)
}
return nDst, nSrc, err
}
type gbkEncoder struct {
transform.NopResetter
gb18030 bool
}
func (e gbkEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, r2, size := rune(0), rune(0), 0
for ; nSrc < len(src); nSrc += size {
r = rune(src[nSrc])
// Decode a 1-byte rune.
if r < utf8.RuneSelf {
size = 1
} else {
// Decode a multi-byte rune.
r, size = utf8.DecodeRune(src[nSrc:])
if size == 1 {
// All valid runes of size 1 (those below utf8.RuneSelf) were
// handled above. We have invalid UTF-8 or we haven't seen the
// full character yet.
if !atEOF && !utf8.FullRune(src[nSrc:]) {
err = transform.ErrShortSrc
break
}
}
// func init checks that the switch covers all tables.
switch {
case encode0Low <= r && r < encode0High:
if r2 = rune(encode0[r-encode0Low]); r2 != 0 {
goto write2
}
case encode1Low <= r && r < encode1High:
// Microsoft's Code Page 936 extends GBK 1.0 to encode the euro sign U+20AC
// as 0x80. The HTML5 specification at http://encoding.spec.whatwg.org/#gbk
// says to treat "gbk" as Code Page 936.
// GBK’s encoder is gb18030’s encoder with its _is GBK_ set to true. https://encoding.spec.whatwg.org/#gbk-encoder
// If _is GBK_ is true and code point is U+20AC, return byte 0x80. https://encoding.spec.whatwg.org/#gb18030-encoder
if !e.gb18030 && r == '€' {
r = 0x80
goto write1
}
if r2 = rune(encode1[r-encode1Low]); r2 != 0 {
goto write2
}
case encode2Low <= r && r < encode2High:
if r2 = rune(encode2[r-encode2Low]); r2 != 0 {
goto write2
}
case encode3Low <= r && r < encode3High:
if r2 = rune(encode3[r-encode3Low]); r2 != 0 {
goto write2
}
case encode4Low <= r && r < encode4High:
if r2 = rune(encode4[r-encode4Low]); r2 != 0 {
goto write2
}
}
if e.gb18030 {
if r < 0x10000 {
i, j := 0, len(gb18030)
for i < j {
h := i + (j-i)/2
if r >= rune(gb18030[h][1]) {
i = h + 1
} else {
j = h
}
}
dec := &gb18030[i-1]
r += rune(dec[0]) - rune(dec[1])
goto write4
} else if r < 0x110000 {
r += 189000 - 0x10000
goto write4
}
}
err = internal.ErrASCIIReplacement
break
}
write1:
if nDst >= len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst] = uint8(r)
nDst++
continue
write2:
if nDst+2 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst+0] = uint8(r2 >> 8)
dst[nDst+1] = uint8(r2)
nDst += 2
continue
write4:
if nDst+4 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst+3] = uint8(r%10 + 0x30)
r /= 10
dst[nDst+2] = uint8(r%126 + 0x81)
r /= 126
dst[nDst+1] = uint8(r%10 + 0x30)
r /= 10
dst[nDst+0] = uint8(r + 0x81)
nDst += 4
continue
}
return nDst, nSrc, err
}
func init() {
// Check that the hard-coded encode switch covers all tables.
if numEncodeTables != 5 {
panic("bad numEncodeTables")
}
}
// Copyright 2013 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 simplifiedchinese
import (
"unicode/utf8"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/internal"
"golang.org/x/text/encoding/internal/identifier"
"golang.org/x/text/transform"
)
// HZGB2312 is the HZ-GB2312 encoding.
var HZGB2312 encoding.Encoding = &hzGB2312
var hzGB2312 = internal.Encoding{
Encoding: internal.FuncEncoding{Decoder: hzGB2312NewDecoder, Encoder: hzGB2312NewEncoder},
Name: "HZ-GB2312",
MIB: identifier.HZGB2312,
}
func hzGB2312NewDecoder() transform.Transformer {
return new(hzGB2312Decoder)
}
func hzGB2312NewEncoder() transform.Transformer {
return new(hzGB2312Encoder)
}
const (
asciiState = iota
gbState
)
type hzGB2312Decoder int
func (d *hzGB2312Decoder) Reset() {
*d = asciiState
}
func (d *hzGB2312Decoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
loop:
for ; nSrc < len(src); nSrc += size {
c0 := src[nSrc]
if c0 >= utf8.RuneSelf {
r, size = utf8.RuneError, 1
goto write
}
if c0 == '~' {
if nSrc+1 >= len(src) {
if !atEOF {
err = transform.ErrShortSrc
break loop
}
r, size = utf8.RuneError, 1
goto write
}
size = 2
switch src[nSrc+1] {
case '{':
*d = gbState
continue
case '}':
*d = asciiState
continue
case '~':
if nDst >= len(dst) {
err = transform.ErrShortDst
break loop
}
dst[nDst] = '~'
nDst++
continue
case '\n':
continue
default:
r = utf8.RuneError
goto write
}
}
if *d == asciiState {
r, size = rune(c0), 1
} else {
if nSrc+1 >= len(src) {
if !atEOF {
err = transform.ErrShortSrc
break loop
}
r, size = utf8.RuneError, 1
goto write
}
size = 2
c1 := src[nSrc+1]
if c0 < 0x21 || 0x7e <= c0 || c1 < 0x21 || 0x7f <= c1 {
// error
} else if i := int(c0-0x01)*190 + int(c1+0x3f); i < len(decode) {
r = rune(decode[i])
if r != 0 {
goto write
}
}
if c1 > utf8.RuneSelf {
// Be consistent and always treat non-ASCII as a single error.
size = 1
}
r = utf8.RuneError
}
write:
if nDst+utf8.RuneLen(r) > len(dst) {
err = transform.ErrShortDst
break loop
}
nDst += utf8.EncodeRune(dst[nDst:], r)
}
return nDst, nSrc, err
}
type hzGB2312Encoder int
func (d *hzGB2312Encoder) Reset() {
*d = asciiState
}
func (e *hzGB2312Encoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
for ; nSrc < len(src); nSrc += size {
r = rune(src[nSrc])
// Decode a 1-byte rune.
if r < utf8.RuneSelf {
size = 1
if r == '~' {
if nDst+2 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst+0] = '~'
dst[nDst+1] = '~'
nDst += 2
continue
} else if *e != asciiState {
if nDst+3 > len(dst) {
err = transform.ErrShortDst
break
}
*e = asciiState
dst[nDst+0] = '~'
dst[nDst+1] = '}'
nDst += 2
} else if nDst >= len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst] = uint8(r)
nDst += 1
continue
}
// Decode a multi-byte rune.
r, size = utf8.DecodeRune(src[nSrc:])
if size == 1 {
// All valid runes of size 1 (those below utf8.RuneSelf) were
// handled above. We have invalid UTF-8 or we haven't seen the
// full character yet.
if !atEOF && !utf8.FullRune(src[nSrc:]) {
err = transform.ErrShortSrc
break
}
}
// func init checks that the switch covers all tables.
switch {
case encode0Low <= r && r < encode0High:
if r = rune(encode0[r-encode0Low]); r != 0 {
goto writeGB
}
case encode1Low <= r && r < encode1High:
if r = rune(encode1[r-encode1Low]); r != 0 {
goto writeGB
}
case encode2Low <= r && r < encode2High:
if r = rune(encode2[r-encode2Low]); r != 0 {
goto writeGB
}
case encode3Low <= r && r < encode3High:
if r = rune(encode3[r-encode3Low]); r != 0 {
goto writeGB
}
case encode4Low <= r && r < encode4High:
if r = rune(encode4[r-encode4Low]); r != 0 {
goto writeGB
}
}
terminateInASCIIState:
// Switch back to ASCII state in case of error so that an ASCII
// replacement character can be written in the correct state.
if *e != asciiState {
if nDst+2 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst+0] = '~'
dst[nDst+1] = '}'
nDst += 2
}
err = internal.ErrASCIIReplacement
break
writeGB:
c0 := uint8(r>>8) - 0x80
c1 := uint8(r) - 0x80
if c0 < 0x21 || 0x7e <= c0 || c1 < 0x21 || 0x7f <= c1 {
goto terminateInASCIIState
}
if *e == asciiState {
if nDst+4 > len(dst) {
err = transform.ErrShortDst
break
}
*e = gbState
dst[nDst+0] = '~'
dst[nDst+1] = '{'
nDst += 2
} else if nDst+2 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst+0] = c0
dst[nDst+1] = c1
nDst += 2
continue
}
// TODO: should one always terminate in ASCII state to make it safe to
// concatenate two HZ-GB2312-encoded strings?
return nDst, nSrc, err
}
// Copyright 2013 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 traditionalchinese
import (
"unicode/utf8"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/internal"
"golang.org/x/text/encoding/internal/identifier"
"golang.org/x/text/transform"
)
// All is a list of all defined encodings in this package.
var All = []encoding.Encoding{Big5}
// Big5 is the Big5 encoding, also known as Code Page 950.
var Big5 encoding.Encoding = &big5
var big5 = internal.Encoding{
Encoding: &internal.SimpleEncoding{Decoder: big5Decoder{}, Encoder: big5Encoder{}},
Name: "Big5",
MIB: identifier.Big5,
}
type big5Decoder struct{ transform.NopResetter }
func (big5Decoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size, s := rune(0), 0, ""
loop:
for ; nSrc < len(src); nSrc += size {
switch c0 := src[nSrc]; {
case c0 < utf8.RuneSelf:
r, size = rune(c0), 1
case 0x81 <= c0 && c0 < 0xff:
if nSrc+1 >= len(src) {
if !atEOF {
err = transform.ErrShortSrc
break loop
}
r, size = utf8.RuneError, 1
goto write
}
c1 := src[nSrc+1]
switch {
case 0x40 <= c1 && c1 < 0x7f:
c1 -= 0x40
case 0xa1 <= c1 && c1 < 0xff:
c1 -= 0x62
case c1 < 0x40:
r, size = utf8.RuneError, 1
goto write
default:
r, size = utf8.RuneError, 2
goto write
}
r, size = '\ufffd', 2
if i := int(c0-0x81)*157 + int(c1); i < len(decode) {
if 1133 <= i && i < 1167 {
// The two-rune special cases for LATIN CAPITAL / SMALL E WITH CIRCUMFLEX
// AND MACRON / CARON are from http://encoding.spec.whatwg.org/#big5
switch i {
case 1133:
s = "\u00CA\u0304"
goto writeStr
case 1135:
s = "\u00CA\u030C"
goto writeStr
case 1164:
s = "\u00EA\u0304"
goto writeStr
case 1166:
s = "\u00EA\u030C"
goto writeStr
}
}
r = rune(decode[i])
if r == 0 {
r = '\ufffd'
}
}
default:
r, size = utf8.RuneError, 1
}
write:
if nDst+utf8.RuneLen(r) > len(dst) {
err = transform.ErrShortDst
break loop
}
nDst += utf8.EncodeRune(dst[nDst:], r)
continue loop
writeStr:
if nDst+len(s) > len(dst) {
err = transform.ErrShortDst
break loop
}
nDst += copy(dst[nDst:], s)
continue loop
}
return nDst, nSrc, err
}
type big5Encoder struct{ transform.NopResetter }
func (big5Encoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
for ; nSrc < len(src); nSrc += size {
r = rune(src[nSrc])
// Decode a 1-byte rune.
if r < utf8.RuneSelf {
size = 1
if nDst >= len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst] = uint8(r)
nDst++
continue
} else {
// Decode a multi-byte rune.
r, size = utf8.DecodeRune(src[nSrc:])
if size == 1 {
// All valid runes of size 1 (those below utf8.RuneSelf) were
// handled above. We have invalid UTF-8 or we haven't seen the
// full character yet.
if !atEOF && !utf8.FullRune(src[nSrc:]) {
err = transform.ErrShortSrc
break
}
}
}
if r >= utf8.RuneSelf {
// func init checks that the switch covers all tables.
switch {
case encode0Low <= r && r < encode0High:
if r = rune(encode0[r-encode0Low]); r != 0 {
goto write2
}
case encode1Low <= r && r < encode1High:
if r = rune(encode1[r-encode1Low]); r != 0 {
goto write2
}
case encode2Low <= r && r < encode2High:
if r = rune(encode2[r-encode2Low]); r != 0 {
goto write2
}
case encode3Low <= r && r < encode3High:
if r = rune(encode3[r-encode3Low]); r != 0 {
goto write2
}
case encode4Low <= r && r < encode4High:
if r = rune(encode4[r-encode4Low]); r != 0 {
goto write2
}
case encode5Low <= r && r < encode5High:
if r = rune(encode5[r-encode5Low]); r != 0 {
goto write2
}
case encode6Low <= r && r < encode6High:
if r = rune(encode6[r-encode6Low]); r != 0 {
goto write2
}
case encode7Low <= r && r < encode7High:
if r = rune(encode7[r-encode7Low]); r != 0 {
goto write2
}
}
err = internal.ErrASCIIReplacement
break
}
write2:
if nDst+2 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst+0] = uint8(r >> 8)
dst[nDst+1] = uint8(r)
nDst += 2
continue
}
return nDst, nSrc, err
}
func init() {
// Check that the hard-coded encode switch covers all tables.
if numEncodeTables != 8 {
panic("bad numEncodeTables")
}
}
// 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.
package unicode
import (
"golang.org/x/text/transform"
)
// BOMOverride returns a new decoder transformer that is identical to fallback,
// except that the presence of a Byte Order Mark at the start of the input
// causes it to switch to the corresponding Unicode decoding. It will only
// consider BOMs for UTF-8, UTF-16BE, and UTF-16LE.
//
// This differs from using ExpectBOM by allowing a BOM to switch to UTF-8, not
// just UTF-16 variants, and allowing falling back to any encoding scheme.
//
// This technique is recommended by the W3C for use in HTML 5: "For
// compatibility with deployed content, the byte order mark (also known as BOM)
// is considered more authoritative than anything else."
// http://www.w3.org/TR/encoding/#specification-hooks
//
// Using BOMOverride is mostly intended for use cases where the first characters
// of a fallback encoding are known to not be a BOM, for example, for valid HTML
// and most encodings.
func BOMOverride(fallback transform.Transformer) transform.Transformer {
// TODO: possibly allow a variadic argument of unicode encodings to allow
// specifying details of which fallbacks are supported as well as
// specifying the details of the implementations. This would also allow for
// support for UTF-32, which should not be supported by default.
return &bomOverride{fallback: fallback}
}
type bomOverride struct {
fallback transform.Transformer
current transform.Transformer
}
func (d *bomOverride) Reset() {
d.current = nil
d.fallback.Reset()
}
var (
// TODO: we could use decode functions here, instead of allocating a new
// decoder on every NewDecoder as IgnoreBOM decoders can be stateless.
utf16le = UTF16(LittleEndian, IgnoreBOM)
utf16be = UTF16(BigEndian, IgnoreBOM)
)
const utf8BOM = "\ufeff"
func (d *bomOverride) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
if d.current != nil {
return d.current.Transform(dst, src, atEOF)
}
if len(src) < 3 && !atEOF {
return 0, 0, transform.ErrShortSrc
}
d.current = d.fallback
bomSize := 0
if len(src) >= 2 {
if src[0] == 0xFF && src[1] == 0xFE {
d.current = utf16le.NewDecoder()
bomSize = 2
} else if src[0] == 0xFE && src[1] == 0xFF {
d.current = utf16be.NewDecoder()
bomSize = 2
} else if len(src) >= 3 &&
src[0] == utf8BOM[0] &&
src[1] == utf8BOM[1] &&
src[2] == utf8BOM[2] {
d.current = transform.Nop
bomSize = 3
}
}
if bomSize < len(src) {
nDst, nSrc, err = d.current.Transform(dst, src[bomSize:], atEOF)
}
return nDst, nSrc + bomSize, err
}
// Copyright 2013 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 unicode provides Unicode encodings such as UTF-16.
package unicode // import "golang.org/x/text/encoding/unicode"
import (
"bytes"
"errors"
"unicode/utf16"
"unicode/utf8"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/internal"
"golang.org/x/text/encoding/internal/identifier"
"golang.org/x/text/internal/utf8internal"
"golang.org/x/text/runes"
"golang.org/x/text/transform"
)
// TODO: I think the Transformers really should return errors on unmatched
// surrogate pairs and odd numbers of bytes. This is not required by RFC 2781,
// which leaves it open, but is suggested by WhatWG. It will allow for all error
// modes as defined by WhatWG: fatal, HTML and Replacement. This would require
// the introduction of some kind of error type for conveying the erroneous code
// point.
// UTF8 is the UTF-8 encoding. It neither removes nor adds byte order marks.
var UTF8 encoding.Encoding = utf8enc
// UTF8BOM is an UTF-8 encoding where the decoder strips a leading byte order
// mark while the encoder adds one.
//
// Some editors add a byte order mark as a signature to UTF-8 files. Although
// the byte order mark is not useful for detecting byte order in UTF-8, it is
// sometimes used as a convention to mark UTF-8-encoded files. This relies on
// the observation that the UTF-8 byte order mark is either an illegal or at
// least very unlikely sequence in any other character encoding.
var UTF8BOM encoding.Encoding = utf8bomEncoding{}
type utf8bomEncoding struct{}
func (utf8bomEncoding) String() string {
return "UTF-8-BOM"
}
func (utf8bomEncoding) ID() (identifier.MIB, string) {
return identifier.Unofficial, "x-utf8bom"
}
func (utf8bomEncoding) NewEncoder() *encoding.Encoder {
return &encoding.Encoder{
Transformer: &utf8bomEncoder{t: runes.ReplaceIllFormed()},
}
}
func (utf8bomEncoding) NewDecoder() *encoding.Decoder {
return &encoding.Decoder{Transformer: &utf8bomDecoder{}}
}
var utf8enc = &internal.Encoding{
Encoding: &internal.SimpleEncoding{Decoder: utf8Decoder{}, Encoder: runes.ReplaceIllFormed()},
Name: "UTF-8",
MIB: identifier.UTF8,
}
type utf8bomDecoder struct {
checked bool
}
func (t *utf8bomDecoder) Reset() {
t.checked = false
}
func (t *utf8bomDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
if !t.checked {
if !atEOF && len(src) < len(utf8BOM) {
if len(src) == 0 {
return 0, 0, nil
}
return 0, 0, transform.ErrShortSrc
}
if bytes.HasPrefix(src, []byte(utf8BOM)) {
nSrc += len(utf8BOM)
src = src[len(utf8BOM):]
}
t.checked = true
}
nDst, n, err := utf8Decoder.Transform(utf8Decoder{}, dst[nDst:], src, atEOF)
nSrc += n
return nDst, nSrc, err
}
type utf8bomEncoder struct {
written bool
t transform.Transformer
}
func (t *utf8bomEncoder) Reset() {
t.written = false
t.t.Reset()
}
func (t *utf8bomEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
if !t.written {
if len(dst) < len(utf8BOM) {
return nDst, 0, transform.ErrShortDst
}
nDst = copy(dst, utf8BOM)
t.written = true
}
n, nSrc, err := utf8Decoder.Transform(utf8Decoder{}, dst[nDst:], src, atEOF)
nDst += n
return nDst, nSrc, err
}
type utf8Decoder struct{ transform.NopResetter }
func (utf8Decoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
var pSrc int // point from which to start copy in src
var accept utf8internal.AcceptRange
// The decoder can only make the input larger, not smaller.
n := len(src)
if len(dst) < n {
err = transform.ErrShortDst
n = len(dst)
atEOF = false
}
for nSrc < n {
c := src[nSrc]
if c < utf8.RuneSelf {
nSrc++
continue
}
first := utf8internal.First[c]
size := int(first & utf8internal.SizeMask)
if first == utf8internal.FirstInvalid {
goto handleInvalid // invalid starter byte
}
accept = utf8internal.AcceptRanges[first>>utf8internal.AcceptShift]
if nSrc+size > n {
if !atEOF {
// We may stop earlier than necessary here if the short sequence
// has invalid bytes. Not checking for this simplifies the code
// and may avoid duplicate computations in certain conditions.
if err == nil {
err = transform.ErrShortSrc
}
break
}
// Determine the maximal subpart of an ill-formed subsequence.
switch {
case nSrc+1 >= n || src[nSrc+1] < accept.Lo || accept.Hi < src[nSrc+1]:
size = 1
case nSrc+2 >= n || src[nSrc+2] < utf8internal.LoCB || utf8internal.HiCB < src[nSrc+2]:
size = 2
default:
size = 3 // As we are short, the maximum is 3.
}
goto handleInvalid
}
if c = src[nSrc+1]; c < accept.Lo || accept.Hi < c {
size = 1
goto handleInvalid // invalid continuation byte
} else if size == 2 {
} else if c = src[nSrc+2]; c < utf8internal.LoCB || utf8internal.HiCB < c {
size = 2
goto handleInvalid // invalid continuation byte
} else if size == 3 {
} else if c = src[nSrc+3]; c < utf8internal.LoCB || utf8internal.HiCB < c {
size = 3
goto handleInvalid // invalid continuation byte
}
nSrc += size
continue
handleInvalid:
// Copy the scanned input so far.
nDst += copy(dst[nDst:], src[pSrc:nSrc])
// Append RuneError to the destination.
const runeError = "\ufffd"
if nDst+len(runeError) > len(dst) {
return nDst, nSrc, transform.ErrShortDst
}
nDst += copy(dst[nDst:], runeError)
// Skip the maximal subpart of an ill-formed subsequence according to
// the W3C standard way instead of the Go way. This Transform is
// probably the only place in the text repo where it is warranted.
nSrc += size
pSrc = nSrc
// Recompute the maximum source length.
if sz := len(dst) - nDst; sz < len(src)-nSrc {
err = transform.ErrShortDst
n = nSrc + sz
atEOF = false
}
}
return nDst + copy(dst[nDst:], src[pSrc:nSrc]), nSrc, err
}
// UTF16 returns a UTF-16 Encoding for the given default endianness and byte
// order mark (BOM) policy.
//
// When decoding from UTF-16 to UTF-8, if the BOMPolicy is IgnoreBOM then
// neither BOMs U+FEFF nor noncharacters U+FFFE in the input stream will affect
// the endianness used for decoding, and will instead be output as their
// standard UTF-8 encodings: "\xef\xbb\xbf" and "\xef\xbf\xbe". If the BOMPolicy
// is UseBOM or ExpectBOM a staring BOM is not written to the UTF-8 output.
// Instead, it overrides the default endianness e for the remainder of the
// transformation. Any subsequent BOMs U+FEFF or noncharacters U+FFFE will not
// affect the endianness used, and will instead be output as their standard
// UTF-8 encodings. For UseBOM, if there is no starting BOM, it will proceed
// with the default Endianness. For ExpectBOM, in that case, the transformation
// will return early with an ErrMissingBOM error.
//
// When encoding from UTF-8 to UTF-16, a BOM will be inserted at the start of
// the output if the BOMPolicy is UseBOM or ExpectBOM. Otherwise, a BOM will not
// be inserted. The UTF-8 input does not need to contain a BOM.
//
// There is no concept of a 'native' endianness. If the UTF-16 data is produced
// and consumed in a greater context that implies a certain endianness, use
// IgnoreBOM. Otherwise, use ExpectBOM and always produce and consume a BOM.
//
// In the language of https://www.unicode.org/faq/utf_bom.html#bom10, IgnoreBOM
// corresponds to "Where the precise type of the data stream is known... the
// BOM should not be used" and ExpectBOM corresponds to "A particular
// protocol... may require use of the BOM".
func UTF16(e Endianness, b BOMPolicy) encoding.Encoding {
return utf16Encoding{config{e, b}, mibValue[e][b&bomMask]}
}
// mibValue maps Endianness and BOMPolicy settings to MIB constants. Note that
// some configurations map to the same MIB identifier. RFC 2781 has requirements
// and recommendations. Some of the "configurations" are merely recommendations,
// so multiple configurations could match.
var mibValue = map[Endianness][numBOMValues]identifier.MIB{
BigEndian: [numBOMValues]identifier.MIB{
IgnoreBOM: identifier.UTF16BE,
UseBOM: identifier.UTF16, // BigEnding default is preferred by RFC 2781.
// TODO: acceptBOM | strictBOM would map to UTF16BE as well.
},
LittleEndian: [numBOMValues]identifier.MIB{
IgnoreBOM: identifier.UTF16LE,
UseBOM: identifier.UTF16, // LittleEndian default is allowed and preferred on Windows.
// TODO: acceptBOM | strictBOM would map to UTF16LE as well.
},
// ExpectBOM is not widely used and has no valid MIB identifier.
}
// All lists a configuration for each IANA-defined UTF-16 variant.
var All = []encoding.Encoding{
UTF8,
UTF16(BigEndian, UseBOM),
UTF16(BigEndian, IgnoreBOM),
UTF16(LittleEndian, IgnoreBOM),
}
// BOMPolicy is a UTF-16 encoding's byte order mark policy.
type BOMPolicy uint8
const (
writeBOM BOMPolicy = 0x01
acceptBOM BOMPolicy = 0x02
requireBOM BOMPolicy = 0x04
bomMask BOMPolicy = 0x07
// HACK: numBOMValues == 8 triggers a bug in the 1.4 compiler (cannot have a
// map of an array of length 8 of a type that is also used as a key or value
// in another map). See golang.org/issue/11354.
// TODO: consider changing this value back to 8 if the use of 1.4.* has
// been minimized.
numBOMValues = 8 + 1
// IgnoreBOM means to ignore any byte order marks.
IgnoreBOM BOMPolicy = 0
// Common and RFC 2781-compliant interpretation for UTF-16BE/LE.
// UseBOM means that the UTF-16 form may start with a byte order mark, which
// will be used to override the default encoding.
UseBOM BOMPolicy = writeBOM | acceptBOM
// Common and RFC 2781-compliant interpretation for UTF-16.
// ExpectBOM means that the UTF-16 form must start with a byte order mark,
// which will be used to override the default encoding.
ExpectBOM BOMPolicy = writeBOM | acceptBOM | requireBOM
// Used in Java as Unicode (not to be confused with Java's UTF-16) and
// ICU's UTF-16,version=1. Not compliant with RFC 2781.
// TODO (maybe): strictBOM: BOM must match Endianness. This would allow:
// - UTF-16(B|L)E,version=1: writeBOM | acceptBOM | requireBOM | strictBOM
// (UnicodeBig and UnicodeLittle in Java)
// - RFC 2781-compliant, but less common interpretation for UTF-16(B|L)E:
// acceptBOM | strictBOM (e.g. assigned to CheckBOM).
// This addition would be consistent with supporting ExpectBOM.
)
// Endianness is a UTF-16 encoding's default endianness.
type Endianness bool
const (
// BigEndian is UTF-16BE.
BigEndian Endianness = false
// LittleEndian is UTF-16LE.
LittleEndian Endianness = true
)
// ErrMissingBOM means that decoding UTF-16 input with ExpectBOM did not find a
// starting byte order mark.
var ErrMissingBOM = errors.New("encoding: missing byte order mark")
type utf16Encoding struct {
config
mib identifier.MIB
}
type config struct {
endianness Endianness
bomPolicy BOMPolicy
}
func (u utf16Encoding) NewDecoder() *encoding.Decoder {
return &encoding.Decoder{Transformer: &utf16Decoder{
initial: u.config,
current: u.config,
}}
}
func (u utf16Encoding) NewEncoder() *encoding.Encoder {
return &encoding.Encoder{Transformer: &utf16Encoder{
endianness: u.endianness,
initialBOMPolicy: u.bomPolicy,
currentBOMPolicy: u.bomPolicy,
}}
}
func (u utf16Encoding) ID() (mib identifier.MIB, other string) {
return u.mib, ""
}
func (u utf16Encoding) String() string {
e, b := "B", ""
if u.endianness == LittleEndian {
e = "L"
}
switch u.bomPolicy {
case ExpectBOM:
b = "Expect"
case UseBOM:
b = "Use"
case IgnoreBOM:
b = "Ignore"
}
return "UTF-16" + e + "E (" + b + " BOM)"
}
type utf16Decoder struct {
initial config
current config
}
func (u *utf16Decoder) Reset() {
u.current = u.initial
}
func (u *utf16Decoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
if len(src) < 2 && atEOF && u.current.bomPolicy&requireBOM != 0 {
return 0, 0, ErrMissingBOM
}
if len(src) == 0 {
return 0, 0, nil
}
if len(src) >= 2 && u.current.bomPolicy&acceptBOM != 0 {
switch {
case src[0] == 0xfe && src[1] == 0xff:
u.current.endianness = BigEndian
nSrc = 2
case src[0] == 0xff && src[1] == 0xfe:
u.current.endianness = LittleEndian
nSrc = 2
default:
if u.current.bomPolicy&requireBOM != 0 {
return 0, 0, ErrMissingBOM
}
}
u.current.bomPolicy = IgnoreBOM
}
var r rune
var dSize, sSize int
for nSrc < len(src) {
if nSrc+1 < len(src) {
x := uint16(src[nSrc+0])<<8 | uint16(src[nSrc+1])
if u.current.endianness == LittleEndian {
x = x>>8 | x<<8
}
r, sSize = rune(x), 2
if utf16.IsSurrogate(r) {
if nSrc+3 < len(src) {
x = uint16(src[nSrc+2])<<8 | uint16(src[nSrc+3])
if u.current.endianness == LittleEndian {
x = x>>8 | x<<8
}
// Save for next iteration if it is not a high surrogate.
if isHighSurrogate(rune(x)) {
r, sSize = utf16.DecodeRune(r, rune(x)), 4
}
} else if !atEOF {
err = transform.ErrShortSrc
break
}
}
if dSize = utf8.RuneLen(r); dSize < 0 {
r, dSize = utf8.RuneError, 3
}
} else if atEOF {
// Single trailing byte.
r, dSize, sSize = utf8.RuneError, 3, 1
} else {
err = transform.ErrShortSrc
break
}
if nDst+dSize > len(dst) {
err = transform.ErrShortDst
break
}
nDst += utf8.EncodeRune(dst[nDst:], r)
nSrc += sSize
}
return nDst, nSrc, err
}
func isHighSurrogate(r rune) bool {
return 0xDC00 <= r && r <= 0xDFFF
}
type utf16Encoder struct {
endianness Endianness
initialBOMPolicy BOMPolicy
currentBOMPolicy BOMPolicy
}
func (u *utf16Encoder) Reset() {
u.currentBOMPolicy = u.initialBOMPolicy
}
func (u *utf16Encoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
if u.currentBOMPolicy&writeBOM != 0 {
if len(dst) < 2 {
return 0, 0, transform.ErrShortDst
}
dst[0], dst[1] = 0xfe, 0xff
u.currentBOMPolicy = IgnoreBOM
nDst = 2
}
r, size := rune(0), 0
for nSrc < len(src) {
r = rune(src[nSrc])
// Decode a 1-byte rune.
if r < utf8.RuneSelf {
size = 1
} else {
// Decode a multi-byte rune.
r, size = utf8.DecodeRune(src[nSrc:])
if size == 1 {
// All valid runes of size 1 (those below utf8.RuneSelf) were
// handled above. We have invalid UTF-8 or we haven't seen the
// full character yet.
if !atEOF && !utf8.FullRune(src[nSrc:]) {
err = transform.ErrShortSrc
break
}
}
}
if r <= 0xffff {
if nDst+2 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst+0] = uint8(r >> 8)
dst[nDst+1] = uint8(r)
nDst += 2
} else {
if nDst+4 > len(dst) {
err = transform.ErrShortDst
break
}
r1, r2 := utf16.EncodeRune(r)
dst[nDst+0] = uint8(r1 >> 8)
dst[nDst+1] = uint8(r1)
dst[nDst+2] = uint8(r2 >> 8)
dst[nDst+3] = uint8(r2)
nDst += 4
}
nSrc += size
}
if u.endianness == LittleEndian {
for i := 0; i < nDst; i += 2 {
dst[i], dst[i+1] = dst[i+1], dst[i]
}
}
return nDst, nSrc, err
}
// 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.
// Package utf32 provides the UTF-32 Unicode encoding.
//
// Please note that support for UTF-32 is discouraged as it is a rare and
// inefficient encoding, unfit for use as an interchange format. For use
// on the web, the W3C strongly discourages its use
// (https://www.w3.org/TR/html5/document-metadata.html#charset)
// while WHATWG directly prohibits supporting it
// (https://html.spec.whatwg.org/multipage/syntax.html#character-encodings).
package utf32 // import "golang.org/x/text/encoding/unicode/utf32"
import (
"errors"
"unicode/utf8"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/internal/identifier"
"golang.org/x/text/transform"
)
// All lists a configuration for each IANA-defined UTF-32 variant.
var All = []encoding.Encoding{
UTF32(BigEndian, UseBOM),
UTF32(BigEndian, IgnoreBOM),
UTF32(LittleEndian, IgnoreBOM),
}
// ErrMissingBOM means that decoding UTF-32 input with ExpectBOM did not
// find a starting byte order mark.
var ErrMissingBOM = errors.New("encoding: missing byte order mark")
// UTF32 returns a UTF-32 Encoding for the given default endianness and
// byte order mark (BOM) policy.
//
// When decoding from UTF-32 to UTF-8, if the BOMPolicy is IgnoreBOM then
// neither BOMs U+FEFF nor ill-formed code units 0xFFFE0000 in the input
// stream will affect the endianness used for decoding. Instead BOMs will
// be output as their standard UTF-8 encoding "\xef\xbb\xbf" while
// 0xFFFE0000 code units will be output as "\xef\xbf\xbd", the standard
// UTF-8 encoding for the Unicode replacement character. If the BOMPolicy
// is UseBOM or ExpectBOM a starting BOM is not written to the UTF-8
// output. Instead, it overrides the default endianness e for the remainder
// of the transformation. Any subsequent BOMs U+FEFF or ill-formed code
// units 0xFFFE0000 will not affect the endianness used, and will instead
// be output as their standard UTF-8 (replacement) encodings. For UseBOM,
// if there is no starting BOM, it will proceed with the default
// Endianness. For ExpectBOM, in that case, the transformation will return
// early with an ErrMissingBOM error.
//
// When encoding from UTF-8 to UTF-32, a BOM will be inserted at the start
// of the output if the BOMPolicy is UseBOM or ExpectBOM. Otherwise, a BOM
// will not be inserted. The UTF-8 input does not need to contain a BOM.
//
// There is no concept of a 'native' endianness. If the UTF-32 data is
// produced and consumed in a greater context that implies a certain
// endianness, use IgnoreBOM. Otherwise, use ExpectBOM and always produce
// and consume a BOM.
//
// In the language of https://www.unicode.org/faq/utf_bom.html#bom10,
// IgnoreBOM corresponds to "Where the precise type of the data stream is
// known... the BOM should not be used" and ExpectBOM corresponds to "A
// particular protocol... may require use of the BOM".
func UTF32(e Endianness, b BOMPolicy) encoding.Encoding {
return utf32Encoding{config{e, b}, mibValue[e][b&bomMask]}
}
// mibValue maps Endianness and BOMPolicy settings to MIB constants for UTF-32.
// Note that some configurations map to the same MIB identifier.
var mibValue = map[Endianness][numBOMValues]identifier.MIB{
BigEndian: [numBOMValues]identifier.MIB{
IgnoreBOM: identifier.UTF32BE,
UseBOM: identifier.UTF32,
},
LittleEndian: [numBOMValues]identifier.MIB{
IgnoreBOM: identifier.UTF32LE,
UseBOM: identifier.UTF32,
},
// ExpectBOM is not widely used and has no valid MIB identifier.
}
// BOMPolicy is a UTF-32 encodings's byte order mark policy.
type BOMPolicy uint8
const (
writeBOM BOMPolicy = 0x01
acceptBOM BOMPolicy = 0x02
requireBOM BOMPolicy = 0x04
bomMask BOMPolicy = 0x07
// HACK: numBOMValues == 8 triggers a bug in the 1.4 compiler (cannot have a
// map of an array of length 8 of a type that is also used as a key or value
// in another map). See golang.org/issue/11354.
// TODO: consider changing this value back to 8 if the use of 1.4.* has
// been minimized.
numBOMValues = 8 + 1
// IgnoreBOM means to ignore any byte order marks.
IgnoreBOM BOMPolicy = 0
// Unicode-compliant interpretation for UTF-32BE/LE.
// UseBOM means that the UTF-32 form may start with a byte order mark,
// which will be used to override the default encoding.
UseBOM BOMPolicy = writeBOM | acceptBOM
// Unicode-compliant interpretation for UTF-32.
// ExpectBOM means that the UTF-32 form must start with a byte order mark,
// which will be used to override the default encoding.
ExpectBOM BOMPolicy = writeBOM | acceptBOM | requireBOM
// Consistent with BOMPolicy definition in golang.org/x/text/encoding/unicode
)
// Endianness is a UTF-32 encoding's default endianness.
type Endianness bool
const (
// BigEndian is UTF-32BE.
BigEndian Endianness = false
// LittleEndian is UTF-32LE.
LittleEndian Endianness = true
)
type config struct {
endianness Endianness
bomPolicy BOMPolicy
}
type utf32Encoding struct {
config
mib identifier.MIB
}
func (u utf32Encoding) NewDecoder() *encoding.Decoder {
return &encoding.Decoder{Transformer: &utf32Decoder{
initial: u.config,
current: u.config,
}}
}
func (u utf32Encoding) NewEncoder() *encoding.Encoder {
return &encoding.Encoder{Transformer: &utf32Encoder{
endianness: u.endianness,
initialBOMPolicy: u.bomPolicy,
currentBOMPolicy: u.bomPolicy,
}}
}
func (u utf32Encoding) ID() (mib identifier.MIB, other string) {
return u.mib, ""
}
func (u utf32Encoding) String() string {
e, b := "B", ""
if u.endianness == LittleEndian {
e = "L"
}
switch u.bomPolicy {
case ExpectBOM:
b = "Expect"
case UseBOM:
b = "Use"
case IgnoreBOM:
b = "Ignore"
}
return "UTF-32" + e + "E (" + b + " BOM)"
}
type utf32Decoder struct {
initial config
current config
}
func (u *utf32Decoder) Reset() {
u.current = u.initial
}
func (u *utf32Decoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
if len(src) == 0 {
if atEOF && u.current.bomPolicy&requireBOM != 0 {
return 0, 0, ErrMissingBOM
}
return 0, 0, nil
}
if u.current.bomPolicy&acceptBOM != 0 {
if len(src) < 4 {
return 0, 0, transform.ErrShortSrc
}
switch {
case src[0] == 0x00 && src[1] == 0x00 && src[2] == 0xfe && src[3] == 0xff:
u.current.endianness = BigEndian
nSrc = 4
case src[0] == 0xff && src[1] == 0xfe && src[2] == 0x00 && src[3] == 0x00:
u.current.endianness = LittleEndian
nSrc = 4
default:
if u.current.bomPolicy&requireBOM != 0 {
return 0, 0, ErrMissingBOM
}
}
u.current.bomPolicy = IgnoreBOM
}
var r rune
var dSize, sSize int
for nSrc < len(src) {
if nSrc+3 < len(src) {
x := uint32(src[nSrc+0])<<24 | uint32(src[nSrc+1])<<16 |
uint32(src[nSrc+2])<<8 | uint32(src[nSrc+3])
if u.current.endianness == LittleEndian {
x = x>>24 | (x >> 8 & 0x0000FF00) | (x << 8 & 0x00FF0000) | x<<24
}
r, sSize = rune(x), 4
if dSize = utf8.RuneLen(r); dSize < 0 {
r, dSize = utf8.RuneError, 3
}
} else if atEOF {
// 1..3 trailing bytes.
r, dSize, sSize = utf8.RuneError, 3, len(src)-nSrc
} else {
err = transform.ErrShortSrc
break
}
if nDst+dSize > len(dst) {
err = transform.ErrShortDst
break
}
nDst += utf8.EncodeRune(dst[nDst:], r)
nSrc += sSize
}
return nDst, nSrc, err
}
type utf32Encoder struct {
endianness Endianness
initialBOMPolicy BOMPolicy
currentBOMPolicy BOMPolicy
}
func (u *utf32Encoder) Reset() {
u.currentBOMPolicy = u.initialBOMPolicy
}
func (u *utf32Encoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
if u.currentBOMPolicy&writeBOM != 0 {
if len(dst) < 4 {
return 0, 0, transform.ErrShortDst
}
dst[0], dst[1], dst[2], dst[3] = 0x00, 0x00, 0xfe, 0xff
u.currentBOMPolicy = IgnoreBOM
nDst = 4
}
r, size := rune(0), 0
for nSrc < len(src) {
r = rune(src[nSrc])
// Decode a 1-byte rune.
if r < utf8.RuneSelf {
size = 1
} else {
// Decode a multi-byte rune.
r, size = utf8.DecodeRune(src[nSrc:])
if size == 1 {
// All valid runes of size 1 (those below utf8.RuneSelf) were
// handled above. We have invalid UTF-8 or we haven't seen the
// full character yet.
if !atEOF && !utf8.FullRune(src[nSrc:]) {
err = transform.ErrShortSrc
break
}
}
}
if nDst+4 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst+0] = uint8(r >> 24)
dst[nDst+1] = uint8(r >> 16)
dst[nDst+2] = uint8(r >> 8)
dst[nDst+3] = uint8(r)
nDst += 4
nSrc += size
}
if u.endianness == LittleEndian {
for i := 0; i < nDst; i += 4 {
dst[i], dst[i+1], dst[i+2], dst[i+3] = dst[i+3], dst[i+2], dst[i+1], dst[i]
}
}
return nDst, nSrc, err
}
// 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 plural
import (
"fmt"
"io"
"reflect"
"strconv"
"golang.org/x/text/internal/catmsg"
"golang.org/x/text/internal/number"
"golang.org/x/text/language"
"golang.org/x/text/message/catalog"
)
// TODO: consider deleting this interface. Maybe VisibleDigits is always
// sufficient and practical.
// Interface is used for types that can determine their own plural form.
type Interface interface {
// PluralForm reports the plural form for the given language of the
// underlying value. It also returns the integer value. If the integer value
// is larger than fits in n, PluralForm may return a value modulo
// 10,000,000.
PluralForm(t language.Tag, scale int) (f Form, n int)
}
// Selectf returns the first case for which its selector is a match for the
// arg-th substitution argument to a formatting call, formatting it as indicated
// by format.
//
// The cases argument are pairs of selectors and messages. Selectors are of type
// string or Form. Messages are of type string or catalog.Message. A selector
// matches an argument if:
// - it is "other" or Other
// - it matches the plural form of the argument: "zero", "one", "two", "few",
// or "many", or the equivalent Form
// - it is of the form "=x" where x is an integer that matches the value of
// the argument.
// - it is of the form "<x" where x is an integer that is larger than the
// argument.
//
// The format argument determines the formatting parameters for which to
// determine the plural form. This is especially relevant for non-integer
// values.
//
// The format string may be "", in which case a best-effort attempt is made to
// find a reasonable representation on which to base the plural form. Examples
// of format strings are:
// - %.2f decimal with scale 2
// - %.2e scientific notation with precision 3 (scale + 1)
// - %d integer
func Selectf(arg int, format string, cases ...interface{}) catalog.Message {
var p parser
// Intercept the formatting parameters of format by doing a dummy print.
fmt.Fprintf(io.Discard, format, &p)
m := &message{arg, kindDefault, 0, cases}
switch p.verb {
case 'g':
m.kind = kindPrecision
m.scale = p.scale
case 'f':
m.kind = kindScale
m.scale = p.scale
case 'e':
m.kind = kindScientific
m.scale = p.scale
case 'd':
m.kind = kindScale
m.scale = 0
default:
// TODO: do we need to handle errors?
}
return m
}
type parser struct {
verb rune
scale int
}
func (p *parser) Format(s fmt.State, verb rune) {
p.verb = verb
p.scale = -1
if prec, ok := s.Precision(); ok {
p.scale = prec
}
}
type message struct {
arg int
kind int
scale int
cases []interface{}
}
const (
// Start with non-ASCII to allow skipping values.
kindDefault = 0x80 + iota
kindScale // verb f, number of fraction digits follows
kindScientific // verb e, number of fraction digits follows
kindPrecision // verb g, number of significant digits follows
)
var handle = catmsg.Register("golang.org/x/text/feature/plural:plural", execute)
func (m *message) Compile(e *catmsg.Encoder) error {
e.EncodeMessageType(handle)
e.EncodeUint(uint64(m.arg))
e.EncodeUint(uint64(m.kind))
if m.kind > kindDefault {
e.EncodeUint(uint64(m.scale))
}
forms := validForms(cardinal, e.Language())
for i := 0; i < len(m.cases); {
if err := compileSelector(e, forms, m.cases[i]); err != nil {
return err
}
if i++; i >= len(m.cases) {
return fmt.Errorf("plural: no message defined for selector %v", m.cases[i-1])
}
var msg catalog.Message
switch x := m.cases[i].(type) {
case string:
msg = catalog.String(x)
case catalog.Message:
msg = x
default:
return fmt.Errorf("plural: message of type %T; must be string or catalog.Message", x)
}
if err := e.EncodeMessage(msg); err != nil {
return err
}
i++
}
return nil
}
func compileSelector(e *catmsg.Encoder, valid []Form, selector interface{}) error {
form := Other
switch x := selector.(type) {
case string:
if x == "" {
return fmt.Errorf("plural: empty selector")
}
if c := x[0]; c == '=' || c == '<' {
val, err := strconv.ParseUint(x[1:], 10, 16)
if err != nil {
return fmt.Errorf("plural: invalid number in selector %q: %v", selector, err)
}
e.EncodeUint(uint64(c))
e.EncodeUint(val)
return nil
}
var ok bool
form, ok = countMap[x]
if !ok {
return fmt.Errorf("plural: invalid plural form %q", selector)
}
case Form:
form = x
default:
return fmt.Errorf("plural: selector of type %T; want string or Form", selector)
}
ok := false
for _, f := range valid {
if f == form {
ok = true
break
}
}
if !ok {
return fmt.Errorf("plural: form %q not supported for language %q", selector, e.Language())
}
e.EncodeUint(uint64(form))
return nil
}
func execute(d *catmsg.Decoder) bool {
lang := d.Language()
argN := int(d.DecodeUint())
kind := int(d.DecodeUint())
scale := -1 // default
if kind > kindDefault {
scale = int(d.DecodeUint())
}
form := Other
n := -1
if arg := d.Arg(argN); arg == nil {
// Default to Other.
} else if x, ok := arg.(number.VisibleDigits); ok {
d := x.Digits(nil, lang, scale)
form, n = cardinal.matchDisplayDigits(lang, &d)
} else if x, ok := arg.(Interface); ok {
// This covers lists and formatters from the number package.
form, n = x.PluralForm(lang, scale)
} else {
var f number.Formatter
switch kind {
case kindScale:
f.InitDecimal(lang)
f.SetScale(scale)
case kindScientific:
f.InitScientific(lang)
f.SetScale(scale)
case kindPrecision:
f.InitDecimal(lang)
f.SetPrecision(scale)
case kindDefault:
// sensible default
f.InitDecimal(lang)
if k := reflect.TypeOf(arg).Kind(); reflect.Int <= k && k <= reflect.Uintptr {
f.SetScale(0)
} else {
f.SetScale(2)
}
}
var dec number.Decimal // TODO: buffer in Printer
dec.Convert(f.RoundingContext, arg)
v := number.FormatDigits(&dec, f.RoundingContext)
if !v.NaN && !v.Inf {
form, n = cardinal.matchDisplayDigits(d.Language(), &v)
}
}
for !d.Done() {
f := d.DecodeUint()
if (f == '=' && n == int(d.DecodeUint())) ||
(f == '<' && 0 <= n && n < int(d.DecodeUint())) ||
form == Form(f) ||
Other == Form(f) {
return d.ExecuteMessage()
}
d.SkipMessage()
}
return false
}
// 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.
//go:generate go run gen.go gen_common.go
// Package plural provides utilities for handling linguistic plurals in text.
//
// The definitions in this package are based on the plural rule handling defined
// in CLDR. See
// https://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules for
// details.
package plural
import (
"golang.org/x/text/internal/language/compact"
"golang.org/x/text/internal/number"
"golang.org/x/text/language"
)
// Rules defines the plural rules for all languages for a certain plural type.
//
// This package is UNDER CONSTRUCTION and its API may change.
type Rules struct {
rules []pluralCheck
index []byte
langToIndex []byte
inclusionMasks []uint64
}
var (
// Cardinal defines the plural rules for numbers indicating quantities.
Cardinal *Rules = cardinal
// Ordinal defines the plural rules for numbers indicating position
// (first, second, etc.).
Ordinal *Rules = ordinal
ordinal = &Rules{
ordinalRules,
ordinalIndex,
ordinalLangToIndex,
ordinalInclusionMasks[:],
}
cardinal = &Rules{
cardinalRules,
cardinalIndex,
cardinalLangToIndex,
cardinalInclusionMasks[:],
}
)
// getIntApprox converts the digits in slice digits[start:end] to an integer
// according to the following rules:
// - Let i be asInt(digits[start:end]), where out-of-range digits are assumed
// to be zero.
// - Result n is big if i / 10^nMod > 1.
// - Otherwise the result is i % 10^nMod.
//
// For example, if digits is {1, 2, 3} and start:end is 0:5, then the result
// for various values of nMod is:
// - when nMod == 2, n == big
// - when nMod == 3, n == big
// - when nMod == 4, n == big
// - when nMod == 5, n == 12300
// - when nMod == 6, n == 12300
// - when nMod == 7, n == 12300
func getIntApprox(digits []byte, start, end, nMod, big int) (n int) {
// Leading 0 digits just result in 0.
p := start
if p < 0 {
p = 0
}
// Range only over the part for which we have digits.
mid := end
if mid >= len(digits) {
mid = len(digits)
}
// Check digits more significant that nMod.
if q := end - nMod; q > 0 {
if q > mid {
q = mid
}
for ; p < q; p++ {
if digits[p] != 0 {
return big
}
}
}
for ; p < mid; p++ {
n = 10*n + int(digits[p])
}
// Multiply for trailing zeros.
for ; p < end; p++ {
n *= 10
}
return n
}
// MatchDigits computes the plural form for the given language and the given
// decimal floating point digits. The digits are stored in big-endian order and
// are of value byte(0) - byte(9). The floating point position is indicated by
// exp and the number of visible decimals is scale. All leading and trailing
// zeros may be omitted from digits.
//
// The following table contains examples of possible arguments to represent
// the given numbers.
//
// decimal digits exp scale
// 123 []byte{1, 2, 3} 3 0
// 123.4 []byte{1, 2, 3, 4} 3 1
// 123.40 []byte{1, 2, 3, 4} 3 2
// 100000 []byte{1} 6 0
// 100000.00 []byte{1} 6 3
func (p *Rules) MatchDigits(t language.Tag, digits []byte, exp, scale int) Form {
index := tagToID(t)
// Differentiate up to including mod 1000000 for the integer part.
n := getIntApprox(digits, 0, exp, 6, 1000000)
// Differentiate up to including mod 100 for the fractional part.
f := getIntApprox(digits, exp, exp+scale, 2, 100)
return matchPlural(p, index, n, f, scale)
}
func (p *Rules) matchDisplayDigits(t language.Tag, d *number.Digits) (Form, int) {
n := getIntApprox(d.Digits, 0, int(d.Exp), 6, 1000000)
return p.MatchDigits(t, d.Digits, int(d.Exp), d.NumFracDigits()), n
}
func validForms(p *Rules, t language.Tag) (forms []Form) {
offset := p.langToIndex[tagToID(t)]
rules := p.rules[p.index[offset]:p.index[offset+1]]
forms = append(forms, Other)
last := Other
for _, r := range rules {
if cat := Form(r.cat & formMask); cat != andNext && last != cat {
forms = append(forms, cat)
last = cat
}
}
return forms
}
func (p *Rules) matchComponents(t language.Tag, n, f, scale int) Form {
return matchPlural(p, tagToID(t), n, f, scale)
}
// MatchPlural returns the plural form for the given language and plural
// operands (as defined in
// https://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules):
//
// where
// n absolute value of the source number (integer and decimals)
// input
// i integer digits of n.
// v number of visible fraction digits in n, with trailing zeros.
// w number of visible fraction digits in n, without trailing zeros.
// f visible fractional digits in n, with trailing zeros (f = t * 10^(v-w))
// t visible fractional digits in n, without trailing zeros.
//
// If any of the operand values is too large to fit in an int, it is okay to
// pass the value modulo 10,000,000.
func (p *Rules) MatchPlural(lang language.Tag, i, v, w, f, t int) Form {
return matchPlural(p, tagToID(lang), i, f, v)
}
func matchPlural(p *Rules, index compact.ID, n, f, v int) Form {
nMask := p.inclusionMasks[n%maxMod]
// Compute the fMask inline in the rules below, as it is relatively rare.
// fMask := p.inclusionMasks[f%maxMod]
vMask := p.inclusionMasks[v%maxMod]
// Do the matching
offset := p.langToIndex[index]
rules := p.rules[p.index[offset]:p.index[offset+1]]
for i := 0; i < len(rules); i++ {
rule := rules[i]
setBit := uint64(1 << rule.setID)
var skip bool
switch op := opID(rule.cat >> opShift); op {
case opI: // i = x
skip = n >= numN || nMask&setBit == 0
case opI | opNotEqual: // i != x
skip = n < numN && nMask&setBit != 0
case opI | opMod: // i % m = x
skip = nMask&setBit == 0
case opI | opMod | opNotEqual: // i % m != x
skip = nMask&setBit != 0
case opN: // n = x
skip = f != 0 || n >= numN || nMask&setBit == 0
case opN | opNotEqual: // n != x
skip = f == 0 && n < numN && nMask&setBit != 0
case opN | opMod: // n % m = x
skip = f != 0 || nMask&setBit == 0
case opN | opMod | opNotEqual: // n % m != x
skip = f == 0 && nMask&setBit != 0
case opF: // f = x
skip = f >= numN || p.inclusionMasks[f%maxMod]&setBit == 0
case opF | opNotEqual: // f != x
skip = f < numN && p.inclusionMasks[f%maxMod]&setBit != 0
case opF | opMod: // f % m = x
skip = p.inclusionMasks[f%maxMod]&setBit == 0
case opF | opMod | opNotEqual: // f % m != x
skip = p.inclusionMasks[f%maxMod]&setBit != 0
case opV: // v = x
skip = v < numN && vMask&setBit == 0
case opV | opNotEqual: // v != x
skip = v < numN && vMask&setBit != 0
case opW: // w == 0
skip = f != 0
case opW | opNotEqual: // w != 0
skip = f == 0
// Hard-wired rules that cannot be handled by our algorithm.
case opBretonM:
skip = f != 0 || n == 0 || n%1000000 != 0
case opAzerbaijan00s:
// 100,200,300,400,500,600,700,800,900
skip = n == 0 || n >= 1000 || n%100 != 0
case opItalian800:
skip = (f != 0 || n >= numN || nMask&setBit == 0) && n != 800
}
if skip {
// advance over AND entries.
for ; i < len(rules) && rules[i].cat&formMask == andNext; i++ {
}
continue
}
// return if we have a final entry.
if cat := rule.cat & formMask; cat != andNext {
return Form(cat)
}
}
return Other
}
func tagToID(t language.Tag) compact.ID {
id, _ := compact.RegionalID(compact.Tag(t))
return id
}
//go:build gofuzz
package fuzz_ng_x_text_cases
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/text/cases"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var CaserResults []*cases.Caser
CaserResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_CaserNgdotBytes:
if len(CaserResults) == 0 {
continue
}
arg0 := CaserResults[CaserResultsIndex]
CaserResultsIndex = (CaserResultsIndex + 1) % len(CaserResults)
arg0.Bytes(a.CaserNgdotBytes.B)
case *NgoloFuzzOne_CaserNgdotString:
if len(CaserResults) == 0 {
continue
}
arg0 := CaserResults[CaserResultsIndex]
CaserResultsIndex = (CaserResultsIndex + 1) % len(CaserResults)
arg0.String(a.CaserNgdotString.S)
case *NgoloFuzzOne_CaserNgdotReset:
if len(CaserResults) == 0 {
continue
}
arg0 := CaserResults[CaserResultsIndex]
CaserResultsIndex = (CaserResultsIndex + 1) % len(CaserResults)
arg0.Reset()
case *NgoloFuzzOne_CaserNgdotTransform:
if len(CaserResults) == 0 {
continue
}
arg0 := CaserResults[CaserResultsIndex]
CaserResultsIndex = (CaserResultsIndex + 1) % len(CaserResults)
a.CaserNgdotTransform.Dst = make([]byte, 2*len(a.CaserNgdotTransform.Src))
_, _, r2 := arg0.Transform(a.CaserNgdotTransform.Dst, a.CaserNgdotTransform.Src, a.CaserNgdotTransform.AtEOF)
if r2 != nil{
r2.Error()
return 0
}
case *NgoloFuzzOne_CaserNgdotSpan:
if len(CaserResults) == 0 {
continue
}
arg0 := CaserResults[CaserResultsIndex]
CaserResultsIndex = (CaserResultsIndex + 1) % len(CaserResults)
_, r1 := arg0.Span(a.CaserNgdotSpan.Src, a.CaserNgdotSpan.AtEOF)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_HandleFinalSigma:
cases.HandleFinalSigma(a.HandleFinalSigma.Enable)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
CaserNb := 0
CaserResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_CaserNgdotBytes:
if CaserNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Caser%d.Bytes(%#+v)\n", CaserResultsIndex, a.CaserNgdotBytes.B))
CaserResultsIndex = (CaserResultsIndex + 1) % CaserNb
case *NgoloFuzzOne_CaserNgdotString:
if CaserNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Caser%d.String(%#+v)\n", CaserResultsIndex, a.CaserNgdotString.S))
CaserResultsIndex = (CaserResultsIndex + 1) % CaserNb
case *NgoloFuzzOne_CaserNgdotReset:
if CaserNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Caser%d.Reset()\n", CaserResultsIndex))
CaserResultsIndex = (CaserResultsIndex + 1) % CaserNb
case *NgoloFuzzOne_CaserNgdotTransform:
if CaserNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Caser%d.Transform(%#+v, %#+v, %#+v)\n", CaserResultsIndex, a.CaserNgdotTransform.Dst, a.CaserNgdotTransform.Src, a.CaserNgdotTransform.AtEOF))
CaserResultsIndex = (CaserResultsIndex + 1) % CaserNb
case *NgoloFuzzOne_CaserNgdotSpan:
if CaserNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Caser%d.Span(%#+v, %#+v)\n", CaserResultsIndex, a.CaserNgdotSpan.Src, a.CaserNgdotSpan.AtEOF))
CaserResultsIndex = (CaserResultsIndex + 1) % CaserNb
case *NgoloFuzzOne_HandleFinalSigma:
w.WriteString(fmt.Sprintf("cases.HandleFinalSigma(%#+v)\n", a.HandleFinalSigma.Enable))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_text_cases
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type CaserNgdotBytesArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
B []byte `protobuf:"bytes,1,opt,name=b,proto3" json:"b,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CaserNgdotBytesArgs) Reset() {
*x = CaserNgdotBytesArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CaserNgdotBytesArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CaserNgdotBytesArgs) ProtoMessage() {}
func (x *CaserNgdotBytesArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CaserNgdotBytesArgs.ProtoReflect.Descriptor instead.
func (*CaserNgdotBytesArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *CaserNgdotBytesArgs) GetB() []byte {
if x != nil {
return x.B
}
return nil
}
type CaserNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S string `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CaserNgdotStringArgs) Reset() {
*x = CaserNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CaserNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CaserNgdotStringArgs) ProtoMessage() {}
func (x *CaserNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CaserNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*CaserNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *CaserNgdotStringArgs) GetS() string {
if x != nil {
return x.S
}
return ""
}
type CaserNgdotResetArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CaserNgdotResetArgs) Reset() {
*x = CaserNgdotResetArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CaserNgdotResetArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CaserNgdotResetArgs) ProtoMessage() {}
func (x *CaserNgdotResetArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CaserNgdotResetArgs.ProtoReflect.Descriptor instead.
func (*CaserNgdotResetArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
type CaserNgdotTransformArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Dst []byte `protobuf:"bytes,1,opt,name=dst,proto3" json:"dst,omitempty"`
Src []byte `protobuf:"bytes,2,opt,name=src,proto3" json:"src,omitempty"`
AtEOF bool `protobuf:"varint,3,opt,name=atEOF,proto3" json:"atEOF,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CaserNgdotTransformArgs) Reset() {
*x = CaserNgdotTransformArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CaserNgdotTransformArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CaserNgdotTransformArgs) ProtoMessage() {}
func (x *CaserNgdotTransformArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CaserNgdotTransformArgs.ProtoReflect.Descriptor instead.
func (*CaserNgdotTransformArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *CaserNgdotTransformArgs) GetDst() []byte {
if x != nil {
return x.Dst
}
return nil
}
func (x *CaserNgdotTransformArgs) GetSrc() []byte {
if x != nil {
return x.Src
}
return nil
}
func (x *CaserNgdotTransformArgs) GetAtEOF() bool {
if x != nil {
return x.AtEOF
}
return false
}
type CaserNgdotSpanArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Src []byte `protobuf:"bytes,1,opt,name=src,proto3" json:"src,omitempty"`
AtEOF bool `protobuf:"varint,2,opt,name=atEOF,proto3" json:"atEOF,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CaserNgdotSpanArgs) Reset() {
*x = CaserNgdotSpanArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CaserNgdotSpanArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CaserNgdotSpanArgs) ProtoMessage() {}
func (x *CaserNgdotSpanArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CaserNgdotSpanArgs.ProtoReflect.Descriptor instead.
func (*CaserNgdotSpanArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *CaserNgdotSpanArgs) GetSrc() []byte {
if x != nil {
return x.Src
}
return nil
}
func (x *CaserNgdotSpanArgs) GetAtEOF() bool {
if x != nil {
return x.AtEOF
}
return false
}
type HandleFinalSigmaArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Enable bool `protobuf:"varint,1,opt,name=enable,proto3" json:"enable,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HandleFinalSigmaArgs) Reset() {
*x = HandleFinalSigmaArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HandleFinalSigmaArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HandleFinalSigmaArgs) ProtoMessage() {}
func (x *HandleFinalSigmaArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HandleFinalSigmaArgs.ProtoReflect.Descriptor instead.
func (*HandleFinalSigmaArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *HandleFinalSigmaArgs) GetEnable() bool {
if x != nil {
return x.Enable
}
return false
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_CaserNgdotBytes
// *NgoloFuzzOne_CaserNgdotString
// *NgoloFuzzOne_CaserNgdotReset
// *NgoloFuzzOne_CaserNgdotTransform
// *NgoloFuzzOne_CaserNgdotSpan
// *NgoloFuzzOne_HandleFinalSigma
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetCaserNgdotBytes() *CaserNgdotBytesArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CaserNgdotBytes); ok {
return x.CaserNgdotBytes
}
}
return nil
}
func (x *NgoloFuzzOne) GetCaserNgdotString() *CaserNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CaserNgdotString); ok {
return x.CaserNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetCaserNgdotReset() *CaserNgdotResetArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CaserNgdotReset); ok {
return x.CaserNgdotReset
}
}
return nil
}
func (x *NgoloFuzzOne) GetCaserNgdotTransform() *CaserNgdotTransformArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CaserNgdotTransform); ok {
return x.CaserNgdotTransform
}
}
return nil
}
func (x *NgoloFuzzOne) GetCaserNgdotSpan() *CaserNgdotSpanArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CaserNgdotSpan); ok {
return x.CaserNgdotSpan
}
}
return nil
}
func (x *NgoloFuzzOne) GetHandleFinalSigma() *HandleFinalSigmaArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_HandleFinalSigma); ok {
return x.HandleFinalSigma
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_CaserNgdotBytes struct {
CaserNgdotBytes *CaserNgdotBytesArgs `protobuf:"bytes,1,opt,name=CaserNgdotBytes,proto3,oneof"`
}
type NgoloFuzzOne_CaserNgdotString struct {
CaserNgdotString *CaserNgdotStringArgs `protobuf:"bytes,2,opt,name=CaserNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_CaserNgdotReset struct {
CaserNgdotReset *CaserNgdotResetArgs `protobuf:"bytes,3,opt,name=CaserNgdotReset,proto3,oneof"`
}
type NgoloFuzzOne_CaserNgdotTransform struct {
CaserNgdotTransform *CaserNgdotTransformArgs `protobuf:"bytes,4,opt,name=CaserNgdotTransform,proto3,oneof"`
}
type NgoloFuzzOne_CaserNgdotSpan struct {
CaserNgdotSpan *CaserNgdotSpanArgs `protobuf:"bytes,5,opt,name=CaserNgdotSpan,proto3,oneof"`
}
type NgoloFuzzOne_HandleFinalSigma struct {
HandleFinalSigma *HandleFinalSigmaArgs `protobuf:"bytes,6,opt,name=HandleFinalSigma,proto3,oneof"`
}
func (*NgoloFuzzOne_CaserNgdotBytes) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CaserNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CaserNgdotReset) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CaserNgdotTransform) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CaserNgdotSpan) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_HandleFinalSigma) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"#\n" +
"\x13CaserNgdotBytesArgs\x12\f\n" +
"\x01b\x18\x01 \x01(\fR\x01b\"$\n" +
"\x14CaserNgdotStringArgs\x12\f\n" +
"\x01s\x18\x01 \x01(\tR\x01s\"\x15\n" +
"\x13CaserNgdotResetArgs\"S\n" +
"\x17CaserNgdotTransformArgs\x12\x10\n" +
"\x03dst\x18\x01 \x01(\fR\x03dst\x12\x10\n" +
"\x03src\x18\x02 \x01(\fR\x03src\x12\x14\n" +
"\x05atEOF\x18\x03 \x01(\bR\x05atEOF\"<\n" +
"\x12CaserNgdotSpanArgs\x12\x10\n" +
"\x03src\x18\x01 \x01(\fR\x03src\x12\x14\n" +
"\x05atEOF\x18\x02 \x01(\bR\x05atEOF\".\n" +
"\x14HandleFinalSigmaArgs\x12\x16\n" +
"\x06enable\x18\x01 \x01(\bR\x06enable\"\xed\x03\n" +
"\fNgoloFuzzOne\x12J\n" +
"\x0fCaserNgdotBytes\x18\x01 \x01(\v2\x1e.ngolofuzz.CaserNgdotBytesArgsH\x00R\x0fCaserNgdotBytes\x12M\n" +
"\x10CaserNgdotString\x18\x02 \x01(\v2\x1f.ngolofuzz.CaserNgdotStringArgsH\x00R\x10CaserNgdotString\x12J\n" +
"\x0fCaserNgdotReset\x18\x03 \x01(\v2\x1e.ngolofuzz.CaserNgdotResetArgsH\x00R\x0fCaserNgdotReset\x12V\n" +
"\x13CaserNgdotTransform\x18\x04 \x01(\v2\".ngolofuzz.CaserNgdotTransformArgsH\x00R\x13CaserNgdotTransform\x12G\n" +
"\x0eCaserNgdotSpan\x18\x05 \x01(\v2\x1d.ngolofuzz.CaserNgdotSpanArgsH\x00R\x0eCaserNgdotSpan\x12M\n" +
"\x10HandleFinalSigma\x18\x06 \x01(\v2\x1f.ngolofuzz.HandleFinalSigmaArgsH\x00R\x10HandleFinalSigmaB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x19Z\x17./;fuzz_ng_x_text_casesb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
var file_ngolofuzz_proto_goTypes = []any{
(*CaserNgdotBytesArgs)(nil), // 0: ngolofuzz.CaserNgdotBytesArgs
(*CaserNgdotStringArgs)(nil), // 1: ngolofuzz.CaserNgdotStringArgs
(*CaserNgdotResetArgs)(nil), // 2: ngolofuzz.CaserNgdotResetArgs
(*CaserNgdotTransformArgs)(nil), // 3: ngolofuzz.CaserNgdotTransformArgs
(*CaserNgdotSpanArgs)(nil), // 4: ngolofuzz.CaserNgdotSpanArgs
(*HandleFinalSigmaArgs)(nil), // 5: ngolofuzz.HandleFinalSigmaArgs
(*NgoloFuzzOne)(nil), // 6: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 7: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 8: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.CaserNgdotBytes:type_name -> ngolofuzz.CaserNgdotBytesArgs
1, // 1: ngolofuzz.NgoloFuzzOne.CaserNgdotString:type_name -> ngolofuzz.CaserNgdotStringArgs
2, // 2: ngolofuzz.NgoloFuzzOne.CaserNgdotReset:type_name -> ngolofuzz.CaserNgdotResetArgs
3, // 3: ngolofuzz.NgoloFuzzOne.CaserNgdotTransform:type_name -> ngolofuzz.CaserNgdotTransformArgs
4, // 4: ngolofuzz.NgoloFuzzOne.CaserNgdotSpan:type_name -> ngolofuzz.CaserNgdotSpanArgs
5, // 5: ngolofuzz.NgoloFuzzOne.HandleFinalSigma:type_name -> ngolofuzz.HandleFinalSigmaArgs
6, // 6: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
7, // [7:7] is the sub-list for method output_type
7, // [7:7] is the sub-list for method input_type
7, // [7:7] is the sub-list for extension type_name
7, // [7:7] is the sub-list for extension extendee
0, // [0:7] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[6].OneofWrappers = []any{
(*NgoloFuzzOne_CaserNgdotBytes)(nil),
(*NgoloFuzzOne_CaserNgdotString)(nil),
(*NgoloFuzzOne_CaserNgdotReset)(nil),
(*NgoloFuzzOne_CaserNgdotTransform)(nil),
(*NgoloFuzzOne_CaserNgdotSpan)(nil),
(*NgoloFuzzOne_HandleFinalSigma)(nil),
}
file_ngolofuzz_proto_msgTypes[7].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 9,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_text_collate
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/text/collate"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var CollatorResults []*collate.Collator
CollatorResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Supported:
collate.Supported()
case *NgoloFuzzOne_CollatorNgdotCompare:
if len(CollatorResults) == 0 {
continue
}
arg0 := CollatorResults[CollatorResultsIndex]
CollatorResultsIndex = (CollatorResultsIndex + 1) % len(CollatorResults)
arg0.Compare(a.CollatorNgdotCompare.A, a.CollatorNgdotCompare.B)
case *NgoloFuzzOne_CollatorNgdotCompareString:
if len(CollatorResults) == 0 {
continue
}
arg0 := CollatorResults[CollatorResultsIndex]
CollatorResultsIndex = (CollatorResultsIndex + 1) % len(CollatorResults)
arg0.CompareString(a.CollatorNgdotCompareString.A, a.CollatorNgdotCompareString.B)
case *NgoloFuzzOne_CollatorNgdotSortStrings:
if len(CollatorResults) == 0 {
continue
}
arg0 := CollatorResults[CollatorResultsIndex]
CollatorResultsIndex = (CollatorResultsIndex + 1) % len(CollatorResults)
arg0.SortStrings(a.CollatorNgdotSortStrings.X)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
CollatorNb := 0
CollatorResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Supported:
w.WriteString(fmt.Sprintf("collate.Supported()\n"))
case *NgoloFuzzOne_CollatorNgdotCompare:
if CollatorNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Collator%d.Compare(%#+v, %#+v)\n", CollatorResultsIndex, a.CollatorNgdotCompare.A, a.CollatorNgdotCompare.B))
CollatorResultsIndex = (CollatorResultsIndex + 1) % CollatorNb
case *NgoloFuzzOne_CollatorNgdotCompareString:
if CollatorNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Collator%d.CompareString(%#+v, %#+v)\n", CollatorResultsIndex, a.CollatorNgdotCompareString.A, a.CollatorNgdotCompareString.B))
CollatorResultsIndex = (CollatorResultsIndex + 1) % CollatorNb
case *NgoloFuzzOne_CollatorNgdotSortStrings:
if CollatorNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Collator%d.SortStrings(%#+v)\n", CollatorResultsIndex, a.CollatorNgdotSortStrings.X))
CollatorResultsIndex = (CollatorResultsIndex + 1) % CollatorNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_text_collate
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type SupportedArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SupportedArgs) Reset() {
*x = SupportedArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SupportedArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SupportedArgs) ProtoMessage() {}
func (x *SupportedArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SupportedArgs.ProtoReflect.Descriptor instead.
func (*SupportedArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type CollatorNgdotCompareArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
A []byte `protobuf:"bytes,1,opt,name=a,proto3" json:"a,omitempty"`
B []byte `protobuf:"bytes,2,opt,name=b,proto3" json:"b,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CollatorNgdotCompareArgs) Reset() {
*x = CollatorNgdotCompareArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CollatorNgdotCompareArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CollatorNgdotCompareArgs) ProtoMessage() {}
func (x *CollatorNgdotCompareArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CollatorNgdotCompareArgs.ProtoReflect.Descriptor instead.
func (*CollatorNgdotCompareArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *CollatorNgdotCompareArgs) GetA() []byte {
if x != nil {
return x.A
}
return nil
}
func (x *CollatorNgdotCompareArgs) GetB() []byte {
if x != nil {
return x.B
}
return nil
}
type CollatorNgdotCompareStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
A string `protobuf:"bytes,1,opt,name=a,proto3" json:"a,omitempty"`
B string `protobuf:"bytes,2,opt,name=b,proto3" json:"b,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CollatorNgdotCompareStringArgs) Reset() {
*x = CollatorNgdotCompareStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CollatorNgdotCompareStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CollatorNgdotCompareStringArgs) ProtoMessage() {}
func (x *CollatorNgdotCompareStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CollatorNgdotCompareStringArgs.ProtoReflect.Descriptor instead.
func (*CollatorNgdotCompareStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *CollatorNgdotCompareStringArgs) GetA() string {
if x != nil {
return x.A
}
return ""
}
func (x *CollatorNgdotCompareStringArgs) GetB() string {
if x != nil {
return x.B
}
return ""
}
type CollatorNgdotSortStringsArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
X []string `protobuf:"bytes,1,rep,name=x,proto3" json:"x,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CollatorNgdotSortStringsArgs) Reset() {
*x = CollatorNgdotSortStringsArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CollatorNgdotSortStringsArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CollatorNgdotSortStringsArgs) ProtoMessage() {}
func (x *CollatorNgdotSortStringsArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CollatorNgdotSortStringsArgs.ProtoReflect.Descriptor instead.
func (*CollatorNgdotSortStringsArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *CollatorNgdotSortStringsArgs) GetX() []string {
if x != nil {
return x.X
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_Supported
// *NgoloFuzzOne_CollatorNgdotCompare
// *NgoloFuzzOne_CollatorNgdotCompareString
// *NgoloFuzzOne_CollatorNgdotSortStrings
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetSupported() *SupportedArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Supported); ok {
return x.Supported
}
}
return nil
}
func (x *NgoloFuzzOne) GetCollatorNgdotCompare() *CollatorNgdotCompareArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CollatorNgdotCompare); ok {
return x.CollatorNgdotCompare
}
}
return nil
}
func (x *NgoloFuzzOne) GetCollatorNgdotCompareString() *CollatorNgdotCompareStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CollatorNgdotCompareString); ok {
return x.CollatorNgdotCompareString
}
}
return nil
}
func (x *NgoloFuzzOne) GetCollatorNgdotSortStrings() *CollatorNgdotSortStringsArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CollatorNgdotSortStrings); ok {
return x.CollatorNgdotSortStrings
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_Supported struct {
Supported *SupportedArgs `protobuf:"bytes,1,opt,name=Supported,proto3,oneof"`
}
type NgoloFuzzOne_CollatorNgdotCompare struct {
CollatorNgdotCompare *CollatorNgdotCompareArgs `protobuf:"bytes,2,opt,name=CollatorNgdotCompare,proto3,oneof"`
}
type NgoloFuzzOne_CollatorNgdotCompareString struct {
CollatorNgdotCompareString *CollatorNgdotCompareStringArgs `protobuf:"bytes,3,opt,name=CollatorNgdotCompareString,proto3,oneof"`
}
type NgoloFuzzOne_CollatorNgdotSortStrings struct {
CollatorNgdotSortStrings *CollatorNgdotSortStringsArgs `protobuf:"bytes,4,opt,name=CollatorNgdotSortStrings,proto3,oneof"`
}
func (*NgoloFuzzOne_Supported) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CollatorNgdotCompare) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CollatorNgdotCompareString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CollatorNgdotSortStrings) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x0f\n" +
"\rSupportedArgs\"6\n" +
"\x18CollatorNgdotCompareArgs\x12\f\n" +
"\x01a\x18\x01 \x01(\fR\x01a\x12\f\n" +
"\x01b\x18\x02 \x01(\fR\x01b\"<\n" +
"\x1eCollatorNgdotCompareStringArgs\x12\f\n" +
"\x01a\x18\x01 \x01(\tR\x01a\x12\f\n" +
"\x01b\x18\x02 \x01(\tR\x01b\",\n" +
"\x1cCollatorNgdotSortStringsArgs\x12\f\n" +
"\x01x\x18\x01 \x03(\tR\x01x\"\xff\x02\n" +
"\fNgoloFuzzOne\x128\n" +
"\tSupported\x18\x01 \x01(\v2\x18.ngolofuzz.SupportedArgsH\x00R\tSupported\x12Y\n" +
"\x14CollatorNgdotCompare\x18\x02 \x01(\v2#.ngolofuzz.CollatorNgdotCompareArgsH\x00R\x14CollatorNgdotCompare\x12k\n" +
"\x1aCollatorNgdotCompareString\x18\x03 \x01(\v2).ngolofuzz.CollatorNgdotCompareStringArgsH\x00R\x1aCollatorNgdotCompareString\x12e\n" +
"\x18CollatorNgdotSortStrings\x18\x04 \x01(\v2'.ngolofuzz.CollatorNgdotSortStringsArgsH\x00R\x18CollatorNgdotSortStringsB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1bZ\x19./;fuzz_ng_x_text_collateb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_ngolofuzz_proto_goTypes = []any{
(*SupportedArgs)(nil), // 0: ngolofuzz.SupportedArgs
(*CollatorNgdotCompareArgs)(nil), // 1: ngolofuzz.CollatorNgdotCompareArgs
(*CollatorNgdotCompareStringArgs)(nil), // 2: ngolofuzz.CollatorNgdotCompareStringArgs
(*CollatorNgdotSortStringsArgs)(nil), // 3: ngolofuzz.CollatorNgdotSortStringsArgs
(*NgoloFuzzOne)(nil), // 4: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 5: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 6: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.Supported:type_name -> ngolofuzz.SupportedArgs
1, // 1: ngolofuzz.NgoloFuzzOne.CollatorNgdotCompare:type_name -> ngolofuzz.CollatorNgdotCompareArgs
2, // 2: ngolofuzz.NgoloFuzzOne.CollatorNgdotCompareString:type_name -> ngolofuzz.CollatorNgdotCompareStringArgs
3, // 3: ngolofuzz.NgoloFuzzOne.CollatorNgdotSortStrings:type_name -> ngolofuzz.CollatorNgdotSortStringsArgs
4, // 4: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[4].OneofWrappers = []any{
(*NgoloFuzzOne_Supported)(nil),
(*NgoloFuzzOne_CollatorNgdotCompare)(nil),
(*NgoloFuzzOne_CollatorNgdotCompareString)(nil),
(*NgoloFuzzOne_CollatorNgdotSortStrings)(nil),
}
file_ngolofuzz_proto_msgTypes[5].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 7,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_text_collate_build
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/text/collate/build"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var BuilderResults []*build.Builder
BuilderResultsIndex := 0
var TailoringResults []*build.Tailoring
TailoringResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewBuilder:
r0 := build.NewBuilder()
if r0 != nil{
BuilderResults = append(BuilderResults, r0)
}
case *NgoloFuzzOne_TailoringNgdotSetAnchor:
if len(TailoringResults) == 0 {
continue
}
arg0 := TailoringResults[TailoringResultsIndex]
TailoringResultsIndex = (TailoringResultsIndex + 1) % len(TailoringResults)
r0 := arg0.SetAnchor(a.TailoringNgdotSetAnchor.Anchor)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_TailoringNgdotSetAnchorBefore:
if len(TailoringResults) == 0 {
continue
}
arg0 := TailoringResults[TailoringResultsIndex]
TailoringResultsIndex = (TailoringResultsIndex + 1) % len(TailoringResults)
r0 := arg0.SetAnchorBefore(a.TailoringNgdotSetAnchorBefore.Anchor)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_BuilderNgdotBuild:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
_, r1 := arg0.Build()
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_TailoringNgdotBuild:
if len(TailoringResults) == 0 {
continue
}
arg0 := TailoringResults[TailoringResultsIndex]
TailoringResultsIndex = (TailoringResultsIndex + 1) % len(TailoringResults)
_, r1 := arg0.Build()
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_BuilderNgdotPrint:
if len(BuilderResults) == 0 {
continue
}
arg0 := BuilderResults[BuilderResultsIndex]
BuilderResultsIndex = (BuilderResultsIndex + 1) % len(BuilderResults)
arg1 := bytes.NewBuffer(a.BuilderNgdotPrint.W)
_, r1 := arg0.Print(arg1)
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
BuilderNb := 0
BuilderResultsIndex := 0
TailoringNb := 0
TailoringResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_NewBuilder:
w.WriteString(fmt.Sprintf("Builder%d := build.NewBuilder()\n", BuilderNb))
BuilderNb = BuilderNb + 1
case *NgoloFuzzOne_TailoringNgdotSetAnchor:
if TailoringNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Tailoring%d.SetAnchor(%#+v)\n", TailoringResultsIndex, a.TailoringNgdotSetAnchor.Anchor))
TailoringResultsIndex = (TailoringResultsIndex + 1) % TailoringNb
case *NgoloFuzzOne_TailoringNgdotSetAnchorBefore:
if TailoringNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Tailoring%d.SetAnchorBefore(%#+v)\n", TailoringResultsIndex, a.TailoringNgdotSetAnchorBefore.Anchor))
TailoringResultsIndex = (TailoringResultsIndex + 1) % TailoringNb
case *NgoloFuzzOne_BuilderNgdotBuild:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.Build()\n", BuilderResultsIndex))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
case *NgoloFuzzOne_TailoringNgdotBuild:
if TailoringNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Tailoring%d.Build()\n", TailoringResultsIndex))
TailoringResultsIndex = (TailoringResultsIndex + 1) % TailoringNb
case *NgoloFuzzOne_BuilderNgdotPrint:
if BuilderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Builder%d.Print(bytes.NewBuffer(%#+v))\n", BuilderResultsIndex, a.BuilderNgdotPrint.W))
BuilderResultsIndex = (BuilderResultsIndex + 1) % BuilderNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_text_collate_build
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type NewBuilderArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewBuilderArgs) Reset() {
*x = NewBuilderArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewBuilderArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewBuilderArgs) ProtoMessage() {}
func (x *NewBuilderArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewBuilderArgs.ProtoReflect.Descriptor instead.
func (*NewBuilderArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type TailoringNgdotSetAnchorArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Anchor string `protobuf:"bytes,1,opt,name=anchor,proto3" json:"anchor,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TailoringNgdotSetAnchorArgs) Reset() {
*x = TailoringNgdotSetAnchorArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TailoringNgdotSetAnchorArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TailoringNgdotSetAnchorArgs) ProtoMessage() {}
func (x *TailoringNgdotSetAnchorArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TailoringNgdotSetAnchorArgs.ProtoReflect.Descriptor instead.
func (*TailoringNgdotSetAnchorArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *TailoringNgdotSetAnchorArgs) GetAnchor() string {
if x != nil {
return x.Anchor
}
return ""
}
type TailoringNgdotSetAnchorBeforeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Anchor string `protobuf:"bytes,1,opt,name=anchor,proto3" json:"anchor,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TailoringNgdotSetAnchorBeforeArgs) Reset() {
*x = TailoringNgdotSetAnchorBeforeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TailoringNgdotSetAnchorBeforeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TailoringNgdotSetAnchorBeforeArgs) ProtoMessage() {}
func (x *TailoringNgdotSetAnchorBeforeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TailoringNgdotSetAnchorBeforeArgs.ProtoReflect.Descriptor instead.
func (*TailoringNgdotSetAnchorBeforeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *TailoringNgdotSetAnchorBeforeArgs) GetAnchor() string {
if x != nil {
return x.Anchor
}
return ""
}
type BuilderNgdotBuildArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotBuildArgs) Reset() {
*x = BuilderNgdotBuildArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotBuildArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotBuildArgs) ProtoMessage() {}
func (x *BuilderNgdotBuildArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotBuildArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotBuildArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
type TailoringNgdotBuildArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TailoringNgdotBuildArgs) Reset() {
*x = TailoringNgdotBuildArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TailoringNgdotBuildArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TailoringNgdotBuildArgs) ProtoMessage() {}
func (x *TailoringNgdotBuildArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TailoringNgdotBuildArgs.ProtoReflect.Descriptor instead.
func (*TailoringNgdotBuildArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
type BuilderNgdotPrintArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
W []byte `protobuf:"bytes,1,opt,name=w,proto3" json:"w,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuilderNgdotPrintArgs) Reset() {
*x = BuilderNgdotPrintArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuilderNgdotPrintArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderNgdotPrintArgs) ProtoMessage() {}
func (x *BuilderNgdotPrintArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderNgdotPrintArgs.ProtoReflect.Descriptor instead.
func (*BuilderNgdotPrintArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *BuilderNgdotPrintArgs) GetW() []byte {
if x != nil {
return x.W
}
return nil
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_NewBuilder
// *NgoloFuzzOne_TailoringNgdotSetAnchor
// *NgoloFuzzOne_TailoringNgdotSetAnchorBefore
// *NgoloFuzzOne_BuilderNgdotBuild
// *NgoloFuzzOne_TailoringNgdotBuild
// *NgoloFuzzOne_BuilderNgdotPrint
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetNewBuilder() *NewBuilderArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NewBuilder); ok {
return x.NewBuilder
}
}
return nil
}
func (x *NgoloFuzzOne) GetTailoringNgdotSetAnchor() *TailoringNgdotSetAnchorArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TailoringNgdotSetAnchor); ok {
return x.TailoringNgdotSetAnchor
}
}
return nil
}
func (x *NgoloFuzzOne) GetTailoringNgdotSetAnchorBefore() *TailoringNgdotSetAnchorBeforeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TailoringNgdotSetAnchorBefore); ok {
return x.TailoringNgdotSetAnchorBefore
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotBuild() *BuilderNgdotBuildArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotBuild); ok {
return x.BuilderNgdotBuild
}
}
return nil
}
func (x *NgoloFuzzOne) GetTailoringNgdotBuild() *TailoringNgdotBuildArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TailoringNgdotBuild); ok {
return x.TailoringNgdotBuild
}
}
return nil
}
func (x *NgoloFuzzOne) GetBuilderNgdotPrint() *BuilderNgdotPrintArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_BuilderNgdotPrint); ok {
return x.BuilderNgdotPrint
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_NewBuilder struct {
NewBuilder *NewBuilderArgs `protobuf:"bytes,1,opt,name=NewBuilder,proto3,oneof"`
}
type NgoloFuzzOne_TailoringNgdotSetAnchor struct {
TailoringNgdotSetAnchor *TailoringNgdotSetAnchorArgs `protobuf:"bytes,2,opt,name=TailoringNgdotSetAnchor,proto3,oneof"`
}
type NgoloFuzzOne_TailoringNgdotSetAnchorBefore struct {
TailoringNgdotSetAnchorBefore *TailoringNgdotSetAnchorBeforeArgs `protobuf:"bytes,3,opt,name=TailoringNgdotSetAnchorBefore,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotBuild struct {
BuilderNgdotBuild *BuilderNgdotBuildArgs `protobuf:"bytes,4,opt,name=BuilderNgdotBuild,proto3,oneof"`
}
type NgoloFuzzOne_TailoringNgdotBuild struct {
TailoringNgdotBuild *TailoringNgdotBuildArgs `protobuf:"bytes,5,opt,name=TailoringNgdotBuild,proto3,oneof"`
}
type NgoloFuzzOne_BuilderNgdotPrint struct {
BuilderNgdotPrint *BuilderNgdotPrintArgs `protobuf:"bytes,6,opt,name=BuilderNgdotPrint,proto3,oneof"`
}
func (*NgoloFuzzOne_NewBuilder) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TailoringNgdotSetAnchor) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TailoringNgdotSetAnchorBefore) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotBuild) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TailoringNgdotBuild) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_BuilderNgdotPrint) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x10\n" +
"\x0eNewBuilderArgs\"5\n" +
"\x1bTailoringNgdotSetAnchorArgs\x12\x16\n" +
"\x06anchor\x18\x01 \x01(\tR\x06anchor\";\n" +
"!TailoringNgdotSetAnchorBeforeArgs\x12\x16\n" +
"\x06anchor\x18\x01 \x01(\tR\x06anchor\"\x17\n" +
"\x15BuilderNgdotBuildArgs\"\x19\n" +
"\x17TailoringNgdotBuildArgs\"%\n" +
"\x15BuilderNgdotPrintArgs\x12\f\n" +
"\x01w\x18\x01 \x01(\fR\x01w\"\xa9\x04\n" +
"\fNgoloFuzzOne\x12;\n" +
"\n" +
"NewBuilder\x18\x01 \x01(\v2\x19.ngolofuzz.NewBuilderArgsH\x00R\n" +
"NewBuilder\x12b\n" +
"\x17TailoringNgdotSetAnchor\x18\x02 \x01(\v2&.ngolofuzz.TailoringNgdotSetAnchorArgsH\x00R\x17TailoringNgdotSetAnchor\x12t\n" +
"\x1dTailoringNgdotSetAnchorBefore\x18\x03 \x01(\v2,.ngolofuzz.TailoringNgdotSetAnchorBeforeArgsH\x00R\x1dTailoringNgdotSetAnchorBefore\x12P\n" +
"\x11BuilderNgdotBuild\x18\x04 \x01(\v2 .ngolofuzz.BuilderNgdotBuildArgsH\x00R\x11BuilderNgdotBuild\x12V\n" +
"\x13TailoringNgdotBuild\x18\x05 \x01(\v2\".ngolofuzz.TailoringNgdotBuildArgsH\x00R\x13TailoringNgdotBuild\x12P\n" +
"\x11BuilderNgdotPrint\x18\x06 \x01(\v2 .ngolofuzz.BuilderNgdotPrintArgsH\x00R\x11BuilderNgdotPrintB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB!Z\x1f./;fuzz_ng_x_text_collate_buildb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
var file_ngolofuzz_proto_goTypes = []any{
(*NewBuilderArgs)(nil), // 0: ngolofuzz.NewBuilderArgs
(*TailoringNgdotSetAnchorArgs)(nil), // 1: ngolofuzz.TailoringNgdotSetAnchorArgs
(*TailoringNgdotSetAnchorBeforeArgs)(nil), // 2: ngolofuzz.TailoringNgdotSetAnchorBeforeArgs
(*BuilderNgdotBuildArgs)(nil), // 3: ngolofuzz.BuilderNgdotBuildArgs
(*TailoringNgdotBuildArgs)(nil), // 4: ngolofuzz.TailoringNgdotBuildArgs
(*BuilderNgdotPrintArgs)(nil), // 5: ngolofuzz.BuilderNgdotPrintArgs
(*NgoloFuzzOne)(nil), // 6: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 7: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 8: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.NewBuilder:type_name -> ngolofuzz.NewBuilderArgs
1, // 1: ngolofuzz.NgoloFuzzOne.TailoringNgdotSetAnchor:type_name -> ngolofuzz.TailoringNgdotSetAnchorArgs
2, // 2: ngolofuzz.NgoloFuzzOne.TailoringNgdotSetAnchorBefore:type_name -> ngolofuzz.TailoringNgdotSetAnchorBeforeArgs
3, // 3: ngolofuzz.NgoloFuzzOne.BuilderNgdotBuild:type_name -> ngolofuzz.BuilderNgdotBuildArgs
4, // 4: ngolofuzz.NgoloFuzzOne.TailoringNgdotBuild:type_name -> ngolofuzz.TailoringNgdotBuildArgs
5, // 5: ngolofuzz.NgoloFuzzOne.BuilderNgdotPrint:type_name -> ngolofuzz.BuilderNgdotPrintArgs
6, // 6: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
7, // [7:7] is the sub-list for method output_type
7, // [7:7] is the sub-list for method input_type
7, // [7:7] is the sub-list for extension type_name
7, // [7:7] is the sub-list for extension extendee
0, // [0:7] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[6].OneofWrappers = []any{
(*NgoloFuzzOne_NewBuilder)(nil),
(*NgoloFuzzOne_TailoringNgdotSetAnchor)(nil),
(*NgoloFuzzOne_TailoringNgdotSetAnchorBefore)(nil),
(*NgoloFuzzOne_BuilderNgdotBuild)(nil),
(*NgoloFuzzOne_TailoringNgdotBuild)(nil),
(*NgoloFuzzOne_BuilderNgdotPrint)(nil),
}
file_ngolofuzz_proto_msgTypes[7].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 9,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_text_currency
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/text/currency"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var UnitResults []*currency.Unit
UnitResultsIndex := 0
var AmountResults []*currency.Amount
AmountResultsIndex := 0
var FormatterResults []*currency.Formatter
FormatterResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_UnitNgdotString:
if len(UnitResults) == 0 {
continue
}
arg0 := UnitResults[UnitResultsIndex]
UnitResultsIndex = (UnitResultsIndex + 1) % len(UnitResults)
arg0.String()
case *NgoloFuzzOne_UnitNgdotAmount:
if len(UnitResults) == 0 {
continue
}
arg0 := UnitResults[UnitResultsIndex]
UnitResultsIndex = (UnitResultsIndex + 1) % len(UnitResults)
r0 := arg0.Amount(a.UnitNgdotAmount.Amount)
AmountResults = append(AmountResults, &r0)
case *NgoloFuzzOne_ParseISO:
r0, r1 := currency.ParseISO(a.ParseISO.S)
UnitResults = append(UnitResults, &r0)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_AmountNgdotCurrency:
if len(AmountResults) == 0 {
continue
}
arg0 := AmountResults[AmountResultsIndex]
AmountResultsIndex = (AmountResultsIndex + 1) % len(AmountResults)
r0 := arg0.Currency()
UnitResults = append(UnitResults, &r0)
case *NgoloFuzzOne_FormatterNgdotDefault:
if len(FormatterResults) == 0 {
continue
}
arg0 := FormatterResults[FormatterResultsIndex]
FormatterResultsIndex = (FormatterResultsIndex + 1) % len(FormatterResults)
if len(UnitResults) == 0 {
continue
}
arg1 := *UnitResults[UnitResultsIndex]
UnitResultsIndex = (UnitResultsIndex + 1) % len(UnitResults)
r0 := arg0.Default(arg1)
FormatterResults = append(FormatterResults, &r0)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
UnitNb := 0
UnitResultsIndex := 0
AmountNb := 0
AmountResultsIndex := 0
FormatterNb := 0
FormatterResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_UnitNgdotString:
if UnitNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Unit%d.String()\n", UnitResultsIndex))
UnitResultsIndex = (UnitResultsIndex + 1) % UnitNb
case *NgoloFuzzOne_UnitNgdotAmount:
if UnitNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Amount%d := Unit%d.Amount(%#+v)\n", AmountNb, UnitResultsIndex, a.UnitNgdotAmount.Amount))
AmountNb = AmountNb + 1
UnitResultsIndex = (UnitResultsIndex + 1) % UnitNb
case *NgoloFuzzOne_ParseISO:
w.WriteString(fmt.Sprintf("Unit%d, _ := currency.ParseISO(%#+v)\n", UnitNb, a.ParseISO.S))
UnitNb = UnitNb + 1
case *NgoloFuzzOne_AmountNgdotCurrency:
if AmountNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Unit%d := Amount%d.Currency()\n", UnitNb, AmountResultsIndex))
UnitNb = UnitNb + 1
AmountResultsIndex = (AmountResultsIndex + 1) % AmountNb
case *NgoloFuzzOne_FormatterNgdotDefault:
if FormatterNb == 0 {
continue
}
if UnitNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Formatter%d := Formatter%d.Default(Unit%d)\n", FormatterNb, FormatterResultsIndex, (UnitResultsIndex + 0) % UnitNb))
FormatterNb = FormatterNb + 1
FormatterResultsIndex = (FormatterResultsIndex + 1) % FormatterNb
UnitResultsIndex = (UnitResultsIndex + 1) % UnitNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_text_currency
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type UnitNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *UnitNgdotStringArgs) Reset() {
*x = UnitNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *UnitNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*UnitNgdotStringArgs) ProtoMessage() {}
func (x *UnitNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use UnitNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*UnitNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type UnitNgdotAmountArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Amount *NgoloFuzzAny `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *UnitNgdotAmountArgs) Reset() {
*x = UnitNgdotAmountArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *UnitNgdotAmountArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*UnitNgdotAmountArgs) ProtoMessage() {}
func (x *UnitNgdotAmountArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use UnitNgdotAmountArgs.ProtoReflect.Descriptor instead.
func (*UnitNgdotAmountArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *UnitNgdotAmountArgs) GetAmount() *NgoloFuzzAny {
if x != nil {
return x.Amount
}
return nil
}
type ParseISOArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S string `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ParseISOArgs) Reset() {
*x = ParseISOArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ParseISOArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ParseISOArgs) ProtoMessage() {}
func (x *ParseISOArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ParseISOArgs.ProtoReflect.Descriptor instead.
func (*ParseISOArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *ParseISOArgs) GetS() string {
if x != nil {
return x.S
}
return ""
}
type AmountNgdotCurrencyArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *AmountNgdotCurrencyArgs) Reset() {
*x = AmountNgdotCurrencyArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AmountNgdotCurrencyArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AmountNgdotCurrencyArgs) ProtoMessage() {}
func (x *AmountNgdotCurrencyArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AmountNgdotCurrencyArgs.ProtoReflect.Descriptor instead.
func (*AmountNgdotCurrencyArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
type FormatterNgdotDefaultArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FormatterNgdotDefaultArgs) Reset() {
*x = FormatterNgdotDefaultArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FormatterNgdotDefaultArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FormatterNgdotDefaultArgs) ProtoMessage() {}
func (x *FormatterNgdotDefaultArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FormatterNgdotDefaultArgs.ProtoReflect.Descriptor instead.
func (*FormatterNgdotDefaultArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_UnitNgdotString
// *NgoloFuzzOne_UnitNgdotAmount
// *NgoloFuzzOne_ParseISO
// *NgoloFuzzOne_AmountNgdotCurrency
// *NgoloFuzzOne_FormatterNgdotDefault
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetUnitNgdotString() *UnitNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_UnitNgdotString); ok {
return x.UnitNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetUnitNgdotAmount() *UnitNgdotAmountArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_UnitNgdotAmount); ok {
return x.UnitNgdotAmount
}
}
return nil
}
func (x *NgoloFuzzOne) GetParseISO() *ParseISOArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ParseISO); ok {
return x.ParseISO
}
}
return nil
}
func (x *NgoloFuzzOne) GetAmountNgdotCurrency() *AmountNgdotCurrencyArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_AmountNgdotCurrency); ok {
return x.AmountNgdotCurrency
}
}
return nil
}
func (x *NgoloFuzzOne) GetFormatterNgdotDefault() *FormatterNgdotDefaultArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FormatterNgdotDefault); ok {
return x.FormatterNgdotDefault
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_UnitNgdotString struct {
UnitNgdotString *UnitNgdotStringArgs `protobuf:"bytes,1,opt,name=UnitNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_UnitNgdotAmount struct {
UnitNgdotAmount *UnitNgdotAmountArgs `protobuf:"bytes,2,opt,name=UnitNgdotAmount,proto3,oneof"`
}
type NgoloFuzzOne_ParseISO struct {
ParseISO *ParseISOArgs `protobuf:"bytes,3,opt,name=ParseISO,proto3,oneof"`
}
type NgoloFuzzOne_AmountNgdotCurrency struct {
AmountNgdotCurrency *AmountNgdotCurrencyArgs `protobuf:"bytes,4,opt,name=AmountNgdotCurrency,proto3,oneof"`
}
type NgoloFuzzOne_FormatterNgdotDefault struct {
FormatterNgdotDefault *FormatterNgdotDefaultArgs `protobuf:"bytes,5,opt,name=FormatterNgdotDefault,proto3,oneof"`
}
func (*NgoloFuzzOne_UnitNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_UnitNgdotAmount) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ParseISO) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_AmountNgdotCurrency) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_FormatterNgdotDefault) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x15\n" +
"\x13UnitNgdotStringArgs\"F\n" +
"\x13UnitNgdotAmountArgs\x12/\n" +
"\x06amount\x18\x01 \x01(\v2\x17.ngolofuzz.NgoloFuzzAnyR\x06amount\"\x1c\n" +
"\fParseISOArgs\x12\f\n" +
"\x01s\x18\x01 \x01(\tR\x01s\"\x19\n" +
"\x17AmountNgdotCurrencyArgs\"\x1b\n" +
"\x19FormatterNgdotDefaultArgs\"\x9b\x03\n" +
"\fNgoloFuzzOne\x12J\n" +
"\x0fUnitNgdotString\x18\x01 \x01(\v2\x1e.ngolofuzz.UnitNgdotStringArgsH\x00R\x0fUnitNgdotString\x12J\n" +
"\x0fUnitNgdotAmount\x18\x02 \x01(\v2\x1e.ngolofuzz.UnitNgdotAmountArgsH\x00R\x0fUnitNgdotAmount\x125\n" +
"\bParseISO\x18\x03 \x01(\v2\x17.ngolofuzz.ParseISOArgsH\x00R\bParseISO\x12V\n" +
"\x13AmountNgdotCurrency\x18\x04 \x01(\v2\".ngolofuzz.AmountNgdotCurrencyArgsH\x00R\x13AmountNgdotCurrency\x12\\\n" +
"\x15FormatterNgdotDefault\x18\x05 \x01(\v2$.ngolofuzz.FormatterNgdotDefaultArgsH\x00R\x15FormatterNgdotDefaultB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1cZ\x1a./;fuzz_ng_x_text_currencyb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
var file_ngolofuzz_proto_goTypes = []any{
(*UnitNgdotStringArgs)(nil), // 0: ngolofuzz.UnitNgdotStringArgs
(*UnitNgdotAmountArgs)(nil), // 1: ngolofuzz.UnitNgdotAmountArgs
(*ParseISOArgs)(nil), // 2: ngolofuzz.ParseISOArgs
(*AmountNgdotCurrencyArgs)(nil), // 3: ngolofuzz.AmountNgdotCurrencyArgs
(*FormatterNgdotDefaultArgs)(nil), // 4: ngolofuzz.FormatterNgdotDefaultArgs
(*NgoloFuzzOne)(nil), // 5: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 6: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 7: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
6, // 0: ngolofuzz.UnitNgdotAmountArgs.amount:type_name -> ngolofuzz.NgoloFuzzAny
0, // 1: ngolofuzz.NgoloFuzzOne.UnitNgdotString:type_name -> ngolofuzz.UnitNgdotStringArgs
1, // 2: ngolofuzz.NgoloFuzzOne.UnitNgdotAmount:type_name -> ngolofuzz.UnitNgdotAmountArgs
2, // 3: ngolofuzz.NgoloFuzzOne.ParseISO:type_name -> ngolofuzz.ParseISOArgs
3, // 4: ngolofuzz.NgoloFuzzOne.AmountNgdotCurrency:type_name -> ngolofuzz.AmountNgdotCurrencyArgs
4, // 5: ngolofuzz.NgoloFuzzOne.FormatterNgdotDefault:type_name -> ngolofuzz.FormatterNgdotDefaultArgs
5, // 6: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
7, // [7:7] is the sub-list for method output_type
7, // [7:7] is the sub-list for method input_type
7, // [7:7] is the sub-list for extension type_name
7, // [7:7] is the sub-list for extension extendee
0, // [0:7] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[5].OneofWrappers = []any{
(*NgoloFuzzOne_UnitNgdotString)(nil),
(*NgoloFuzzOne_UnitNgdotAmount)(nil),
(*NgoloFuzzOne_ParseISO)(nil),
(*NgoloFuzzOne_AmountNgdotCurrency)(nil),
(*NgoloFuzzOne_FormatterNgdotDefault)(nil),
}
file_ngolofuzz_proto_msgTypes[6].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 8,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_text_encoding
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/text/encoding"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var EncoderResults []*encoding.Encoder
EncoderResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_EncoderNgdotBytes:
if len(EncoderResults) == 0 {
continue
}
arg0 := EncoderResults[EncoderResultsIndex]
EncoderResultsIndex = (EncoderResultsIndex + 1) % len(EncoderResults)
_, r1 := arg0.Bytes(a.EncoderNgdotBytes.B)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_EncoderNgdotString:
if len(EncoderResults) == 0 {
continue
}
arg0 := EncoderResults[EncoderResultsIndex]
EncoderResultsIndex = (EncoderResultsIndex + 1) % len(EncoderResults)
_, r1 := arg0.String(a.EncoderNgdotString.S)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_EncoderNgdotWriter:
if len(EncoderResults) == 0 {
continue
}
arg0 := EncoderResults[EncoderResultsIndex]
EncoderResultsIndex = (EncoderResultsIndex + 1) % len(EncoderResults)
arg1 := bytes.NewBuffer(a.EncoderNgdotWriter.W)
arg0.Writer(arg1)
case *NgoloFuzzOne_HTMLEscapeUnsupported:
if len(EncoderResults) == 0 {
continue
}
arg0 := EncoderResults[EncoderResultsIndex]
EncoderResultsIndex = (EncoderResultsIndex + 1) % len(EncoderResults)
r0 := encoding.HTMLEscapeUnsupported(arg0)
if r0 != nil{
EncoderResults = append(EncoderResults, r0)
}
case *NgoloFuzzOne_ReplaceUnsupported:
if len(EncoderResults) == 0 {
continue
}
arg0 := EncoderResults[EncoderResultsIndex]
EncoderResultsIndex = (EncoderResultsIndex + 1) % len(EncoderResults)
r0 := encoding.ReplaceUnsupported(arg0)
if r0 != nil{
EncoderResults = append(EncoderResults, r0)
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
EncoderNb := 0
EncoderResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_EncoderNgdotBytes:
if EncoderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Encoder%d.Bytes(%#+v)\n", EncoderResultsIndex, a.EncoderNgdotBytes.B))
EncoderResultsIndex = (EncoderResultsIndex + 1) % EncoderNb
case *NgoloFuzzOne_EncoderNgdotString:
if EncoderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Encoder%d.String(%#+v)\n", EncoderResultsIndex, a.EncoderNgdotString.S))
EncoderResultsIndex = (EncoderResultsIndex + 1) % EncoderNb
case *NgoloFuzzOne_EncoderNgdotWriter:
if EncoderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Encoder%d.Writer(bytes.NewBuffer(%#+v))\n", EncoderResultsIndex, a.EncoderNgdotWriter.W))
EncoderResultsIndex = (EncoderResultsIndex + 1) % EncoderNb
case *NgoloFuzzOne_HTMLEscapeUnsupported:
if EncoderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Encoder%d := encoding.HTMLEscapeUnsupported(Encoder%d)\n", EncoderNb, (EncoderResultsIndex + 0) % EncoderNb))
EncoderNb = EncoderNb + 1
EncoderResultsIndex = (EncoderResultsIndex + 1) % EncoderNb
case *NgoloFuzzOne_ReplaceUnsupported:
if EncoderNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Encoder%d := encoding.ReplaceUnsupported(Encoder%d)\n", EncoderNb, (EncoderResultsIndex + 0) % EncoderNb))
EncoderNb = EncoderNb + 1
EncoderResultsIndex = (EncoderResultsIndex + 1) % EncoderNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_text_encoding
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type EncoderNgdotBytesArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
B []byte `protobuf:"bytes,1,opt,name=b,proto3" json:"b,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *EncoderNgdotBytesArgs) Reset() {
*x = EncoderNgdotBytesArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *EncoderNgdotBytesArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EncoderNgdotBytesArgs) ProtoMessage() {}
func (x *EncoderNgdotBytesArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EncoderNgdotBytesArgs.ProtoReflect.Descriptor instead.
func (*EncoderNgdotBytesArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *EncoderNgdotBytesArgs) GetB() []byte {
if x != nil {
return x.B
}
return nil
}
type EncoderNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S string `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *EncoderNgdotStringArgs) Reset() {
*x = EncoderNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *EncoderNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EncoderNgdotStringArgs) ProtoMessage() {}
func (x *EncoderNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EncoderNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*EncoderNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *EncoderNgdotStringArgs) GetS() string {
if x != nil {
return x.S
}
return ""
}
type EncoderNgdotWriterArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
W []byte `protobuf:"bytes,1,opt,name=w,proto3" json:"w,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *EncoderNgdotWriterArgs) Reset() {
*x = EncoderNgdotWriterArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *EncoderNgdotWriterArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EncoderNgdotWriterArgs) ProtoMessage() {}
func (x *EncoderNgdotWriterArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EncoderNgdotWriterArgs.ProtoReflect.Descriptor instead.
func (*EncoderNgdotWriterArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *EncoderNgdotWriterArgs) GetW() []byte {
if x != nil {
return x.W
}
return nil
}
type HTMLEscapeUnsupportedArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HTMLEscapeUnsupportedArgs) Reset() {
*x = HTMLEscapeUnsupportedArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HTMLEscapeUnsupportedArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HTMLEscapeUnsupportedArgs) ProtoMessage() {}
func (x *HTMLEscapeUnsupportedArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HTMLEscapeUnsupportedArgs.ProtoReflect.Descriptor instead.
func (*HTMLEscapeUnsupportedArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
type ReplaceUnsupportedArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ReplaceUnsupportedArgs) Reset() {
*x = ReplaceUnsupportedArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ReplaceUnsupportedArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReplaceUnsupportedArgs) ProtoMessage() {}
func (x *ReplaceUnsupportedArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReplaceUnsupportedArgs.ProtoReflect.Descriptor instead.
func (*ReplaceUnsupportedArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_EncoderNgdotBytes
// *NgoloFuzzOne_EncoderNgdotString
// *NgoloFuzzOne_EncoderNgdotWriter
// *NgoloFuzzOne_HTMLEscapeUnsupported
// *NgoloFuzzOne_ReplaceUnsupported
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetEncoderNgdotBytes() *EncoderNgdotBytesArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_EncoderNgdotBytes); ok {
return x.EncoderNgdotBytes
}
}
return nil
}
func (x *NgoloFuzzOne) GetEncoderNgdotString() *EncoderNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_EncoderNgdotString); ok {
return x.EncoderNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetEncoderNgdotWriter() *EncoderNgdotWriterArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_EncoderNgdotWriter); ok {
return x.EncoderNgdotWriter
}
}
return nil
}
func (x *NgoloFuzzOne) GetHTMLEscapeUnsupported() *HTMLEscapeUnsupportedArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_HTMLEscapeUnsupported); ok {
return x.HTMLEscapeUnsupported
}
}
return nil
}
func (x *NgoloFuzzOne) GetReplaceUnsupported() *ReplaceUnsupportedArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ReplaceUnsupported); ok {
return x.ReplaceUnsupported
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_EncoderNgdotBytes struct {
EncoderNgdotBytes *EncoderNgdotBytesArgs `protobuf:"bytes,1,opt,name=EncoderNgdotBytes,proto3,oneof"`
}
type NgoloFuzzOne_EncoderNgdotString struct {
EncoderNgdotString *EncoderNgdotStringArgs `protobuf:"bytes,2,opt,name=EncoderNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_EncoderNgdotWriter struct {
EncoderNgdotWriter *EncoderNgdotWriterArgs `protobuf:"bytes,3,opt,name=EncoderNgdotWriter,proto3,oneof"`
}
type NgoloFuzzOne_HTMLEscapeUnsupported struct {
HTMLEscapeUnsupported *HTMLEscapeUnsupportedArgs `protobuf:"bytes,4,opt,name=HTMLEscapeUnsupported,proto3,oneof"`
}
type NgoloFuzzOne_ReplaceUnsupported struct {
ReplaceUnsupported *ReplaceUnsupportedArgs `protobuf:"bytes,5,opt,name=ReplaceUnsupported,proto3,oneof"`
}
func (*NgoloFuzzOne_EncoderNgdotBytes) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_EncoderNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_EncoderNgdotWriter) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_HTMLEscapeUnsupported) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ReplaceUnsupported) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"%\n" +
"\x15EncoderNgdotBytesArgs\x12\f\n" +
"\x01b\x18\x01 \x01(\fR\x01b\"&\n" +
"\x16EncoderNgdotStringArgs\x12\f\n" +
"\x01s\x18\x01 \x01(\tR\x01s\"&\n" +
"\x16EncoderNgdotWriterArgs\x12\f\n" +
"\x01w\x18\x01 \x01(\fR\x01w\"\x1b\n" +
"\x19HTMLEscapeUnsupportedArgs\"\x18\n" +
"\x16ReplaceUnsupportedArgs\"\xc5\x03\n" +
"\fNgoloFuzzOne\x12P\n" +
"\x11EncoderNgdotBytes\x18\x01 \x01(\v2 .ngolofuzz.EncoderNgdotBytesArgsH\x00R\x11EncoderNgdotBytes\x12S\n" +
"\x12EncoderNgdotString\x18\x02 \x01(\v2!.ngolofuzz.EncoderNgdotStringArgsH\x00R\x12EncoderNgdotString\x12S\n" +
"\x12EncoderNgdotWriter\x18\x03 \x01(\v2!.ngolofuzz.EncoderNgdotWriterArgsH\x00R\x12EncoderNgdotWriter\x12\\\n" +
"\x15HTMLEscapeUnsupported\x18\x04 \x01(\v2$.ngolofuzz.HTMLEscapeUnsupportedArgsH\x00R\x15HTMLEscapeUnsupported\x12S\n" +
"\x12ReplaceUnsupported\x18\x05 \x01(\v2!.ngolofuzz.ReplaceUnsupportedArgsH\x00R\x12ReplaceUnsupportedB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x1cZ\x1a./;fuzz_ng_x_text_encodingb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
var file_ngolofuzz_proto_goTypes = []any{
(*EncoderNgdotBytesArgs)(nil), // 0: ngolofuzz.EncoderNgdotBytesArgs
(*EncoderNgdotStringArgs)(nil), // 1: ngolofuzz.EncoderNgdotStringArgs
(*EncoderNgdotWriterArgs)(nil), // 2: ngolofuzz.EncoderNgdotWriterArgs
(*HTMLEscapeUnsupportedArgs)(nil), // 3: ngolofuzz.HTMLEscapeUnsupportedArgs
(*ReplaceUnsupportedArgs)(nil), // 4: ngolofuzz.ReplaceUnsupportedArgs
(*NgoloFuzzOne)(nil), // 5: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 6: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 7: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.EncoderNgdotBytes:type_name -> ngolofuzz.EncoderNgdotBytesArgs
1, // 1: ngolofuzz.NgoloFuzzOne.EncoderNgdotString:type_name -> ngolofuzz.EncoderNgdotStringArgs
2, // 2: ngolofuzz.NgoloFuzzOne.EncoderNgdotWriter:type_name -> ngolofuzz.EncoderNgdotWriterArgs
3, // 3: ngolofuzz.NgoloFuzzOne.HTMLEscapeUnsupported:type_name -> ngolofuzz.HTMLEscapeUnsupportedArgs
4, // 4: ngolofuzz.NgoloFuzzOne.ReplaceUnsupported:type_name -> ngolofuzz.ReplaceUnsupportedArgs
5, // 5: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
6, // [6:6] is the sub-list for method output_type
6, // [6:6] is the sub-list for method input_type
6, // [6:6] is the sub-list for extension type_name
6, // [6:6] is the sub-list for extension extendee
0, // [0:6] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[5].OneofWrappers = []any{
(*NgoloFuzzOne_EncoderNgdotBytes)(nil),
(*NgoloFuzzOne_EncoderNgdotString)(nil),
(*NgoloFuzzOne_EncoderNgdotWriter)(nil),
(*NgoloFuzzOne_HTMLEscapeUnsupported)(nil),
(*NgoloFuzzOne_ReplaceUnsupported)(nil),
}
file_ngolofuzz_proto_msgTypes[6].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 8,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_text_encoding_htmlindex
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/text/encoding/htmlindex"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Get:
_, r1 := htmlindex.Get(a.Get.Name)
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Get:
w.WriteString(fmt.Sprintf("htmlindex.Get(%#+v)\n", a.Get.Name))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_text_encoding_htmlindex
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type GetArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetArgs) Reset() {
*x = GetArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetArgs) ProtoMessage() {}
func (x *GetArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetArgs.ProtoReflect.Descriptor instead.
func (*GetArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *GetArgs) GetName() string {
if x != nil {
return x.Name
}
return ""
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_Get
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetGet() *GetArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Get); ok {
return x.Get
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_Get struct {
Get *GetArgs `protobuf:"bytes,1,opt,name=Get,proto3,oneof"`
}
func (*NgoloFuzzOne_Get) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x1d\n" +
"\aGetArgs\x12\x12\n" +
"\x04name\x18\x01 \x01(\tR\x04name\">\n" +
"\fNgoloFuzzOne\x12&\n" +
"\x03Get\x18\x01 \x01(\v2\x12.ngolofuzz.GetArgsH\x00R\x03GetB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB&Z$./;fuzz_ng_x_text_encoding_htmlindexb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_ngolofuzz_proto_goTypes = []any{
(*GetArgs)(nil), // 0: ngolofuzz.GetArgs
(*NgoloFuzzOne)(nil), // 1: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 2: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 3: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.Get:type_name -> ngolofuzz.GetArgs
1, // 1: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[1].OneofWrappers = []any{
(*NgoloFuzzOne_Get)(nil),
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_text_encoding_unicode
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/text/encoding/unicode"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func BOMPolicyNewFromFuzz(p BOMPolicyEnum) unicode.BOMPolicy{
switch p {
case 1:
return unicode.UseBOM
case 2:
return unicode.ExpectBOM
}
return unicode.IgnoreBOM
}
func ConvertBOMPolicyNewFromFuzz(a []BOMPolicyEnum) []unicode.BOMPolicy{
r := make([]unicode.BOMPolicy, len(a))
for i := range a {
r[i] = BOMPolicyNewFromFuzz(a[i])
}
return r
}
func EndiannessNewFromFuzz(p EndiannessEnum) unicode.Endianness{
switch p {
case 1:
return unicode.LittleEndian
}
return unicode.BigEndian
}
func ConvertEndiannessNewFromFuzz(a []EndiannessEnum) []unicode.Endianness{
r := make([]unicode.Endianness, len(a))
for i := range a {
r[i] = EndiannessNewFromFuzz(a[i])
}
return r
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_UTF16:
arg0 := EndiannessNewFromFuzz(a.UTF16.E)
arg1 := BOMPolicyNewFromFuzz(a.UTF16.B)
unicode.UTF16(arg0, arg1)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_UTF16:
w.WriteString(fmt.Sprintf("unicode.UTF16(EndiannessNewFromFuzz(%#+v), BOMPolicyNewFromFuzz(%#+v))\n", a.UTF16.E, a.UTF16.B))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_text_encoding_unicode
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type BOMPolicyEnum int32
const (
BOMPolicyEnum_IgnoreBOM BOMPolicyEnum = 0
BOMPolicyEnum_UseBOM BOMPolicyEnum = 1
BOMPolicyEnum_ExpectBOM BOMPolicyEnum = 2
)
// Enum value maps for BOMPolicyEnum.
var (
BOMPolicyEnum_name = map[int32]string{
0: "IgnoreBOM",
1: "UseBOM",
2: "ExpectBOM",
}
BOMPolicyEnum_value = map[string]int32{
"IgnoreBOM": 0,
"UseBOM": 1,
"ExpectBOM": 2,
}
)
func (x BOMPolicyEnum) Enum() *BOMPolicyEnum {
p := new(BOMPolicyEnum)
*p = x
return p
}
func (x BOMPolicyEnum) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (BOMPolicyEnum) Descriptor() protoreflect.EnumDescriptor {
return file_ngolofuzz_proto_enumTypes[0].Descriptor()
}
func (BOMPolicyEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[0]
}
func (x BOMPolicyEnum) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use BOMPolicyEnum.Descriptor instead.
func (BOMPolicyEnum) EnumDescriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type EndiannessEnum int32
const (
EndiannessEnum_BigEndian EndiannessEnum = 0
EndiannessEnum_LittleEndian EndiannessEnum = 1
)
// Enum value maps for EndiannessEnum.
var (
EndiannessEnum_name = map[int32]string{
0: "BigEndian",
1: "LittleEndian",
}
EndiannessEnum_value = map[string]int32{
"BigEndian": 0,
"LittleEndian": 1,
}
)
func (x EndiannessEnum) Enum() *EndiannessEnum {
p := new(EndiannessEnum)
*p = x
return p
}
func (x EndiannessEnum) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (EndiannessEnum) Descriptor() protoreflect.EnumDescriptor {
return file_ngolofuzz_proto_enumTypes[1].Descriptor()
}
func (EndiannessEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[1]
}
func (x EndiannessEnum) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use EndiannessEnum.Descriptor instead.
func (EndiannessEnum) EnumDescriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
type UTF16Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
E EndiannessEnum `protobuf:"varint,1,opt,name=e,proto3,enum=ngolofuzz.EndiannessEnum" json:"e,omitempty"`
B BOMPolicyEnum `protobuf:"varint,2,opt,name=b,proto3,enum=ngolofuzz.BOMPolicyEnum" json:"b,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *UTF16Args) Reset() {
*x = UTF16Args{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *UTF16Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*UTF16Args) ProtoMessage() {}
func (x *UTF16Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use UTF16Args.ProtoReflect.Descriptor instead.
func (*UTF16Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *UTF16Args) GetE() EndiannessEnum {
if x != nil {
return x.E
}
return EndiannessEnum_BigEndian
}
func (x *UTF16Args) GetB() BOMPolicyEnum {
if x != nil {
return x.B
}
return BOMPolicyEnum_IgnoreBOM
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_UTF16
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetUTF16() *UTF16Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_UTF16); ok {
return x.UTF16
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_UTF16 struct {
UTF16 *UTF16Args `protobuf:"bytes,1,opt,name=UTF16,proto3,oneof"`
}
func (*NgoloFuzzOne_UTF16) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\\\n" +
"\tUTF16Args\x12'\n" +
"\x01e\x18\x01 \x01(\x0e2\x19.ngolofuzz.EndiannessEnumR\x01e\x12&\n" +
"\x01b\x18\x02 \x01(\x0e2\x18.ngolofuzz.BOMPolicyEnumR\x01b\"D\n" +
"\fNgoloFuzzOne\x12,\n" +
"\x05UTF16\x18\x01 \x01(\v2\x14.ngolofuzz.UTF16ArgsH\x00R\x05UTF16B\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04list*9\n" +
"\rBOMPolicyEnum\x12\r\n" +
"\tIgnoreBOM\x10\x00\x12\n" +
"\n" +
"\x06UseBOM\x10\x01\x12\r\n" +
"\tExpectBOM\x10\x02*1\n" +
"\x0eEndiannessEnum\x12\r\n" +
"\tBigEndian\x10\x00\x12\x10\n" +
"\fLittleEndian\x10\x01B$Z\"./;fuzz_ng_x_text_encoding_unicodeb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_ngolofuzz_proto_goTypes = []any{
(BOMPolicyEnum)(0), // 0: ngolofuzz.BOMPolicyEnum
(EndiannessEnum)(0), // 1: ngolofuzz.EndiannessEnum
(*UTF16Args)(nil), // 2: ngolofuzz.UTF16Args
(*NgoloFuzzOne)(nil), // 3: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 4: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 5: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
1, // 0: ngolofuzz.UTF16Args.e:type_name -> ngolofuzz.EndiannessEnum
0, // 1: ngolofuzz.UTF16Args.b:type_name -> ngolofuzz.BOMPolicyEnum
2, // 2: ngolofuzz.NgoloFuzzOne.UTF16:type_name -> ngolofuzz.UTF16Args
3, // 3: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[1].OneofWrappers = []any{
(*NgoloFuzzOne_UTF16)(nil),
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 2,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
EnumInfos: file_ngolofuzz_proto_enumTypes,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_text_encoding_unicode_utf32
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/text/encoding/unicode/utf32"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func BOMPolicyNewFromFuzz(p BOMPolicyEnum) utf32.BOMPolicy{
switch p {
case 1:
return utf32.UseBOM
case 2:
return utf32.ExpectBOM
}
return utf32.IgnoreBOM
}
func ConvertBOMPolicyNewFromFuzz(a []BOMPolicyEnum) []utf32.BOMPolicy{
r := make([]utf32.BOMPolicy, len(a))
for i := range a {
r[i] = BOMPolicyNewFromFuzz(a[i])
}
return r
}
func EndiannessNewFromFuzz(p EndiannessEnum) utf32.Endianness{
switch p {
case 1:
return utf32.LittleEndian
}
return utf32.BigEndian
}
func ConvertEndiannessNewFromFuzz(a []EndiannessEnum) []utf32.Endianness{
r := make([]utf32.Endianness, len(a))
for i := range a {
r[i] = EndiannessNewFromFuzz(a[i])
}
return r
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_UTF32:
arg0 := EndiannessNewFromFuzz(a.UTF32.E)
arg1 := BOMPolicyNewFromFuzz(a.UTF32.B)
utf32.UTF32(arg0, arg1)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_UTF32:
w.WriteString(fmt.Sprintf("utf32.UTF32(EndiannessNewFromFuzz(%#+v), BOMPolicyNewFromFuzz(%#+v))\n", a.UTF32.E, a.UTF32.B))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_text_encoding_unicode_utf32
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type BOMPolicyEnum int32
const (
BOMPolicyEnum_IgnoreBOM BOMPolicyEnum = 0
BOMPolicyEnum_UseBOM BOMPolicyEnum = 1
BOMPolicyEnum_ExpectBOM BOMPolicyEnum = 2
)
// Enum value maps for BOMPolicyEnum.
var (
BOMPolicyEnum_name = map[int32]string{
0: "IgnoreBOM",
1: "UseBOM",
2: "ExpectBOM",
}
BOMPolicyEnum_value = map[string]int32{
"IgnoreBOM": 0,
"UseBOM": 1,
"ExpectBOM": 2,
}
)
func (x BOMPolicyEnum) Enum() *BOMPolicyEnum {
p := new(BOMPolicyEnum)
*p = x
return p
}
func (x BOMPolicyEnum) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (BOMPolicyEnum) Descriptor() protoreflect.EnumDescriptor {
return file_ngolofuzz_proto_enumTypes[0].Descriptor()
}
func (BOMPolicyEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[0]
}
func (x BOMPolicyEnum) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use BOMPolicyEnum.Descriptor instead.
func (BOMPolicyEnum) EnumDescriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type EndiannessEnum int32
const (
EndiannessEnum_BigEndian EndiannessEnum = 0
EndiannessEnum_LittleEndian EndiannessEnum = 1
)
// Enum value maps for EndiannessEnum.
var (
EndiannessEnum_name = map[int32]string{
0: "BigEndian",
1: "LittleEndian",
}
EndiannessEnum_value = map[string]int32{
"BigEndian": 0,
"LittleEndian": 1,
}
)
func (x EndiannessEnum) Enum() *EndiannessEnum {
p := new(EndiannessEnum)
*p = x
return p
}
func (x EndiannessEnum) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (EndiannessEnum) Descriptor() protoreflect.EnumDescriptor {
return file_ngolofuzz_proto_enumTypes[1].Descriptor()
}
func (EndiannessEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[1]
}
func (x EndiannessEnum) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use EndiannessEnum.Descriptor instead.
func (EndiannessEnum) EnumDescriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
type UTF32Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
E EndiannessEnum `protobuf:"varint,1,opt,name=e,proto3,enum=ngolofuzz.EndiannessEnum" json:"e,omitempty"`
B BOMPolicyEnum `protobuf:"varint,2,opt,name=b,proto3,enum=ngolofuzz.BOMPolicyEnum" json:"b,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *UTF32Args) Reset() {
*x = UTF32Args{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *UTF32Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*UTF32Args) ProtoMessage() {}
func (x *UTF32Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use UTF32Args.ProtoReflect.Descriptor instead.
func (*UTF32Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *UTF32Args) GetE() EndiannessEnum {
if x != nil {
return x.E
}
return EndiannessEnum_BigEndian
}
func (x *UTF32Args) GetB() BOMPolicyEnum {
if x != nil {
return x.B
}
return BOMPolicyEnum_IgnoreBOM
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_UTF32
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetUTF32() *UTF32Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_UTF32); ok {
return x.UTF32
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_UTF32 struct {
UTF32 *UTF32Args `protobuf:"bytes,1,opt,name=UTF32,proto3,oneof"`
}
func (*NgoloFuzzOne_UTF32) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\\\n" +
"\tUTF32Args\x12'\n" +
"\x01e\x18\x01 \x01(\x0e2\x19.ngolofuzz.EndiannessEnumR\x01e\x12&\n" +
"\x01b\x18\x02 \x01(\x0e2\x18.ngolofuzz.BOMPolicyEnumR\x01b\"D\n" +
"\fNgoloFuzzOne\x12,\n" +
"\x05UTF32\x18\x01 \x01(\v2\x14.ngolofuzz.UTF32ArgsH\x00R\x05UTF32B\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04list*9\n" +
"\rBOMPolicyEnum\x12\r\n" +
"\tIgnoreBOM\x10\x00\x12\n" +
"\n" +
"\x06UseBOM\x10\x01\x12\r\n" +
"\tExpectBOM\x10\x02*1\n" +
"\x0eEndiannessEnum\x12\r\n" +
"\tBigEndian\x10\x00\x12\x10\n" +
"\fLittleEndian\x10\x01B*Z(./;fuzz_ng_x_text_encoding_unicode_utf32b\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_ngolofuzz_proto_goTypes = []any{
(BOMPolicyEnum)(0), // 0: ngolofuzz.BOMPolicyEnum
(EndiannessEnum)(0), // 1: ngolofuzz.EndiannessEnum
(*UTF32Args)(nil), // 2: ngolofuzz.UTF32Args
(*NgoloFuzzOne)(nil), // 3: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 4: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 5: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
1, // 0: ngolofuzz.UTF32Args.e:type_name -> ngolofuzz.EndiannessEnum
0, // 1: ngolofuzz.UTF32Args.b:type_name -> ngolofuzz.BOMPolicyEnum
2, // 2: ngolofuzz.NgoloFuzzOne.UTF32:type_name -> ngolofuzz.UTF32Args
3, // 3: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[1].OneofWrappers = []any{
(*NgoloFuzzOne_UTF32)(nil),
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 2,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
EnumInfos: file_ngolofuzz_proto_enumTypes,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_text_message_pipeline
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/text/message/pipeline"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var StateResults []*pipeline.State
StateResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_StateNgdotGenerate:
if len(StateResults) == 0 {
continue
}
arg0 := StateResults[StateResultsIndex]
StateResultsIndex = (StateResultsIndex + 1) % len(StateResults)
r0 := arg0.Generate()
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_StateNgdotWriteGen:
if len(StateResults) == 0 {
continue
}
arg0 := StateResults[StateResultsIndex]
StateResultsIndex = (StateResultsIndex + 1) % len(StateResults)
arg1 := bytes.NewBuffer(a.StateNgdotWriteGen.W)
r0 := arg0.WriteGen(arg1, a.StateNgdotWriteGen.Pkg)
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_StateNgdotImport:
if len(StateResults) == 0 {
continue
}
arg0 := StateResults[StateResultsIndex]
StateResultsIndex = (StateResultsIndex + 1) % len(StateResults)
r0 := arg0.Import()
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_StateNgdotMerge:
if len(StateResults) == 0 {
continue
}
arg0 := StateResults[StateResultsIndex]
StateResultsIndex = (StateResultsIndex + 1) % len(StateResults)
r0 := arg0.Merge()
if r0 != nil{
r0.Error()
return 0
}
case *NgoloFuzzOne_StateNgdotExport:
if len(StateResults) == 0 {
continue
}
arg0 := StateResults[StateResultsIndex]
StateResultsIndex = (StateResultsIndex + 1) % len(StateResults)
r0 := arg0.Export()
if r0 != nil{
r0.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
StateNb := 0
StateResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_StateNgdotGenerate:
if StateNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("State%d.Generate()\n", StateResultsIndex))
StateResultsIndex = (StateResultsIndex + 1) % StateNb
case *NgoloFuzzOne_StateNgdotWriteGen:
if StateNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("State%d.WriteGen(bytes.NewBuffer(%#+v), %#+v)\n", StateResultsIndex, a.StateNgdotWriteGen.W, a.StateNgdotWriteGen.Pkg))
StateResultsIndex = (StateResultsIndex + 1) % StateNb
case *NgoloFuzzOne_StateNgdotImport:
if StateNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("State%d.Import()\n", StateResultsIndex))
StateResultsIndex = (StateResultsIndex + 1) % StateNb
case *NgoloFuzzOne_StateNgdotMerge:
if StateNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("State%d.Merge()\n", StateResultsIndex))
StateResultsIndex = (StateResultsIndex + 1) % StateNb
case *NgoloFuzzOne_StateNgdotExport:
if StateNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("State%d.Export()\n", StateResultsIndex))
StateResultsIndex = (StateResultsIndex + 1) % StateNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_text_message_pipeline
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type StateNgdotGenerateArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *StateNgdotGenerateArgs) Reset() {
*x = StateNgdotGenerateArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *StateNgdotGenerateArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StateNgdotGenerateArgs) ProtoMessage() {}
func (x *StateNgdotGenerateArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StateNgdotGenerateArgs.ProtoReflect.Descriptor instead.
func (*StateNgdotGenerateArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type StateNgdotWriteGenArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
W []byte `protobuf:"bytes,1,opt,name=w,proto3" json:"w,omitempty"`
Pkg string `protobuf:"bytes,2,opt,name=pkg,proto3" json:"pkg,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *StateNgdotWriteGenArgs) Reset() {
*x = StateNgdotWriteGenArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *StateNgdotWriteGenArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StateNgdotWriteGenArgs) ProtoMessage() {}
func (x *StateNgdotWriteGenArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StateNgdotWriteGenArgs.ProtoReflect.Descriptor instead.
func (*StateNgdotWriteGenArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *StateNgdotWriteGenArgs) GetW() []byte {
if x != nil {
return x.W
}
return nil
}
func (x *StateNgdotWriteGenArgs) GetPkg() string {
if x != nil {
return x.Pkg
}
return ""
}
type StateNgdotImportArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *StateNgdotImportArgs) Reset() {
*x = StateNgdotImportArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *StateNgdotImportArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StateNgdotImportArgs) ProtoMessage() {}
func (x *StateNgdotImportArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StateNgdotImportArgs.ProtoReflect.Descriptor instead.
func (*StateNgdotImportArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
type StateNgdotMergeArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *StateNgdotMergeArgs) Reset() {
*x = StateNgdotMergeArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *StateNgdotMergeArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StateNgdotMergeArgs) ProtoMessage() {}
func (x *StateNgdotMergeArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StateNgdotMergeArgs.ProtoReflect.Descriptor instead.
func (*StateNgdotMergeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
type StateNgdotExportArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *StateNgdotExportArgs) Reset() {
*x = StateNgdotExportArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *StateNgdotExportArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StateNgdotExportArgs) ProtoMessage() {}
func (x *StateNgdotExportArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StateNgdotExportArgs.ProtoReflect.Descriptor instead.
func (*StateNgdotExportArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_StateNgdotGenerate
// *NgoloFuzzOne_StateNgdotWriteGen
// *NgoloFuzzOne_StateNgdotImport
// *NgoloFuzzOne_StateNgdotMerge
// *NgoloFuzzOne_StateNgdotExport
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetStateNgdotGenerate() *StateNgdotGenerateArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_StateNgdotGenerate); ok {
return x.StateNgdotGenerate
}
}
return nil
}
func (x *NgoloFuzzOne) GetStateNgdotWriteGen() *StateNgdotWriteGenArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_StateNgdotWriteGen); ok {
return x.StateNgdotWriteGen
}
}
return nil
}
func (x *NgoloFuzzOne) GetStateNgdotImport() *StateNgdotImportArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_StateNgdotImport); ok {
return x.StateNgdotImport
}
}
return nil
}
func (x *NgoloFuzzOne) GetStateNgdotMerge() *StateNgdotMergeArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_StateNgdotMerge); ok {
return x.StateNgdotMerge
}
}
return nil
}
func (x *NgoloFuzzOne) GetStateNgdotExport() *StateNgdotExportArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_StateNgdotExport); ok {
return x.StateNgdotExport
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_StateNgdotGenerate struct {
StateNgdotGenerate *StateNgdotGenerateArgs `protobuf:"bytes,1,opt,name=StateNgdotGenerate,proto3,oneof"`
}
type NgoloFuzzOne_StateNgdotWriteGen struct {
StateNgdotWriteGen *StateNgdotWriteGenArgs `protobuf:"bytes,2,opt,name=StateNgdotWriteGen,proto3,oneof"`
}
type NgoloFuzzOne_StateNgdotImport struct {
StateNgdotImport *StateNgdotImportArgs `protobuf:"bytes,3,opt,name=StateNgdotImport,proto3,oneof"`
}
type NgoloFuzzOne_StateNgdotMerge struct {
StateNgdotMerge *StateNgdotMergeArgs `protobuf:"bytes,4,opt,name=StateNgdotMerge,proto3,oneof"`
}
type NgoloFuzzOne_StateNgdotExport struct {
StateNgdotExport *StateNgdotExportArgs `protobuf:"bytes,5,opt,name=StateNgdotExport,proto3,oneof"`
}
func (*NgoloFuzzOne_StateNgdotGenerate) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_StateNgdotWriteGen) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_StateNgdotImport) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_StateNgdotMerge) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_StateNgdotExport) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x18\n" +
"\x16StateNgdotGenerateArgs\"8\n" +
"\x16StateNgdotWriteGenArgs\x12\f\n" +
"\x01w\x18\x01 \x01(\fR\x01w\x12\x10\n" +
"\x03pkg\x18\x02 \x01(\tR\x03pkg\"\x16\n" +
"\x14StateNgdotImportArgs\"\x15\n" +
"\x13StateNgdotMergeArgs\"\x16\n" +
"\x14StateNgdotExportArgs\"\xaa\x03\n" +
"\fNgoloFuzzOne\x12S\n" +
"\x12StateNgdotGenerate\x18\x01 \x01(\v2!.ngolofuzz.StateNgdotGenerateArgsH\x00R\x12StateNgdotGenerate\x12S\n" +
"\x12StateNgdotWriteGen\x18\x02 \x01(\v2!.ngolofuzz.StateNgdotWriteGenArgsH\x00R\x12StateNgdotWriteGen\x12M\n" +
"\x10StateNgdotImport\x18\x03 \x01(\v2\x1f.ngolofuzz.StateNgdotImportArgsH\x00R\x10StateNgdotImport\x12J\n" +
"\x0fStateNgdotMerge\x18\x04 \x01(\v2\x1e.ngolofuzz.StateNgdotMergeArgsH\x00R\x0fStateNgdotMerge\x12M\n" +
"\x10StateNgdotExport\x18\x05 \x01(\v2\x1f.ngolofuzz.StateNgdotExportArgsH\x00R\x10StateNgdotExportB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB$Z\"./;fuzz_ng_x_text_message_pipelineb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
var file_ngolofuzz_proto_goTypes = []any{
(*StateNgdotGenerateArgs)(nil), // 0: ngolofuzz.StateNgdotGenerateArgs
(*StateNgdotWriteGenArgs)(nil), // 1: ngolofuzz.StateNgdotWriteGenArgs
(*StateNgdotImportArgs)(nil), // 2: ngolofuzz.StateNgdotImportArgs
(*StateNgdotMergeArgs)(nil), // 3: ngolofuzz.StateNgdotMergeArgs
(*StateNgdotExportArgs)(nil), // 4: ngolofuzz.StateNgdotExportArgs
(*NgoloFuzzOne)(nil), // 5: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 6: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 7: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.StateNgdotGenerate:type_name -> ngolofuzz.StateNgdotGenerateArgs
1, // 1: ngolofuzz.NgoloFuzzOne.StateNgdotWriteGen:type_name -> ngolofuzz.StateNgdotWriteGenArgs
2, // 2: ngolofuzz.NgoloFuzzOne.StateNgdotImport:type_name -> ngolofuzz.StateNgdotImportArgs
3, // 3: ngolofuzz.NgoloFuzzOne.StateNgdotMerge:type_name -> ngolofuzz.StateNgdotMergeArgs
4, // 4: ngolofuzz.NgoloFuzzOne.StateNgdotExport:type_name -> ngolofuzz.StateNgdotExportArgs
5, // 5: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
6, // [6:6] is the sub-list for method output_type
6, // [6:6] is the sub-list for method input_type
6, // [6:6] is the sub-list for extension type_name
6, // [6:6] is the sub-list for extension extendee
0, // [0:6] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[5].OneofWrappers = []any{
(*NgoloFuzzOne_StateNgdotGenerate)(nil),
(*NgoloFuzzOne_StateNgdotWriteGen)(nil),
(*NgoloFuzzOne_StateNgdotImport)(nil),
(*NgoloFuzzOne_StateNgdotMerge)(nil),
(*NgoloFuzzOne_StateNgdotExport)(nil),
}
file_ngolofuzz_proto_msgTypes[6].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 8,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_text_runes
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/text/runes"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var SetResults []*runes.Set
SetResultsIndex := 0
var TransformerResults []*runes.Transformer
TransformerResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_TransformerNgdotTransform:
if len(TransformerResults) == 0 {
continue
}
arg0 := TransformerResults[TransformerResultsIndex]
TransformerResultsIndex = (TransformerResultsIndex + 1) % len(TransformerResults)
a.TransformerNgdotTransform.Dst = make([]byte, 2*len(a.TransformerNgdotTransform.Src))
_, _, r2 := arg0.Transform(a.TransformerNgdotTransform.Dst, a.TransformerNgdotTransform.Src, a.TransformerNgdotTransform.AtEOF)
if r2 != nil{
r2.Error()
return 0
}
case *NgoloFuzzOne_TransformerNgdotSpan:
if len(TransformerResults) == 0 {
continue
}
arg0 := TransformerResults[TransformerResultsIndex]
TransformerResultsIndex = (TransformerResultsIndex + 1) % len(TransformerResults)
_, r1 := arg0.Span(a.TransformerNgdotSpan.B, a.TransformerNgdotSpan.AtEOF)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_TransformerNgdotReset:
if len(TransformerResults) == 0 {
continue
}
arg0 := TransformerResults[TransformerResultsIndex]
TransformerResultsIndex = (TransformerResultsIndex + 1) % len(TransformerResults)
arg0.Reset()
case *NgoloFuzzOne_TransformerNgdotBytes:
if len(TransformerResults) == 0 {
continue
}
arg0 := TransformerResults[TransformerResultsIndex]
TransformerResultsIndex = (TransformerResultsIndex + 1) % len(TransformerResults)
arg0.Bytes(a.TransformerNgdotBytes.B)
case *NgoloFuzzOne_TransformerNgdotString:
if len(TransformerResults) == 0 {
continue
}
arg0 := TransformerResults[TransformerResultsIndex]
TransformerResultsIndex = (TransformerResultsIndex + 1) % len(TransformerResults)
arg0.String(a.TransformerNgdotString.S)
case *NgoloFuzzOne_Remove:
if len(SetResults) == 0 {
continue
}
arg0 := *SetResults[SetResultsIndex]
SetResultsIndex = (SetResultsIndex + 1) % len(SetResults)
r0 := runes.Remove(arg0)
TransformerResults = append(TransformerResults, &r0)
case *NgoloFuzzOne_ReplaceIllFormed:
r0 := runes.ReplaceIllFormed()
TransformerResults = append(TransformerResults, &r0)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
SetNb := 0
SetResultsIndex := 0
TransformerNb := 0
TransformerResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_TransformerNgdotTransform:
if TransformerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Transformer%d.Transform(%#+v, %#+v, %#+v)\n", TransformerResultsIndex, a.TransformerNgdotTransform.Dst, a.TransformerNgdotTransform.Src, a.TransformerNgdotTransform.AtEOF))
TransformerResultsIndex = (TransformerResultsIndex + 1) % TransformerNb
case *NgoloFuzzOne_TransformerNgdotSpan:
if TransformerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Transformer%d.Span(%#+v, %#+v)\n", TransformerResultsIndex, a.TransformerNgdotSpan.B, a.TransformerNgdotSpan.AtEOF))
TransformerResultsIndex = (TransformerResultsIndex + 1) % TransformerNb
case *NgoloFuzzOne_TransformerNgdotReset:
if TransformerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Transformer%d.Reset()\n", TransformerResultsIndex))
TransformerResultsIndex = (TransformerResultsIndex + 1) % TransformerNb
case *NgoloFuzzOne_TransformerNgdotBytes:
if TransformerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Transformer%d.Bytes(%#+v)\n", TransformerResultsIndex, a.TransformerNgdotBytes.B))
TransformerResultsIndex = (TransformerResultsIndex + 1) % TransformerNb
case *NgoloFuzzOne_TransformerNgdotString:
if TransformerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Transformer%d.String(%#+v)\n", TransformerResultsIndex, a.TransformerNgdotString.S))
TransformerResultsIndex = (TransformerResultsIndex + 1) % TransformerNb
case *NgoloFuzzOne_Remove:
if SetNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Transformer%d := runes.Remove(Set%d)\n", TransformerNb, (SetResultsIndex + 0) % SetNb))
TransformerNb = TransformerNb + 1
SetResultsIndex = (SetResultsIndex + 1) % SetNb
case *NgoloFuzzOne_ReplaceIllFormed:
w.WriteString(fmt.Sprintf("Transformer%d := runes.ReplaceIllFormed()\n", TransformerNb))
TransformerNb = TransformerNb + 1
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_text_runes
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type TransformerNgdotTransformArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Dst []byte `protobuf:"bytes,1,opt,name=dst,proto3" json:"dst,omitempty"`
Src []byte `protobuf:"bytes,2,opt,name=src,proto3" json:"src,omitempty"`
AtEOF bool `protobuf:"varint,3,opt,name=atEOF,proto3" json:"atEOF,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TransformerNgdotTransformArgs) Reset() {
*x = TransformerNgdotTransformArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TransformerNgdotTransformArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TransformerNgdotTransformArgs) ProtoMessage() {}
func (x *TransformerNgdotTransformArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TransformerNgdotTransformArgs.ProtoReflect.Descriptor instead.
func (*TransformerNgdotTransformArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *TransformerNgdotTransformArgs) GetDst() []byte {
if x != nil {
return x.Dst
}
return nil
}
func (x *TransformerNgdotTransformArgs) GetSrc() []byte {
if x != nil {
return x.Src
}
return nil
}
func (x *TransformerNgdotTransformArgs) GetAtEOF() bool {
if x != nil {
return x.AtEOF
}
return false
}
type TransformerNgdotSpanArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
B []byte `protobuf:"bytes,1,opt,name=b,proto3" json:"b,omitempty"`
AtEOF bool `protobuf:"varint,2,opt,name=atEOF,proto3" json:"atEOF,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TransformerNgdotSpanArgs) Reset() {
*x = TransformerNgdotSpanArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TransformerNgdotSpanArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TransformerNgdotSpanArgs) ProtoMessage() {}
func (x *TransformerNgdotSpanArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TransformerNgdotSpanArgs.ProtoReflect.Descriptor instead.
func (*TransformerNgdotSpanArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *TransformerNgdotSpanArgs) GetB() []byte {
if x != nil {
return x.B
}
return nil
}
func (x *TransformerNgdotSpanArgs) GetAtEOF() bool {
if x != nil {
return x.AtEOF
}
return false
}
type TransformerNgdotResetArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TransformerNgdotResetArgs) Reset() {
*x = TransformerNgdotResetArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TransformerNgdotResetArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TransformerNgdotResetArgs) ProtoMessage() {}
func (x *TransformerNgdotResetArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TransformerNgdotResetArgs.ProtoReflect.Descriptor instead.
func (*TransformerNgdotResetArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
type TransformerNgdotBytesArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
B []byte `protobuf:"bytes,1,opt,name=b,proto3" json:"b,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TransformerNgdotBytesArgs) Reset() {
*x = TransformerNgdotBytesArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TransformerNgdotBytesArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TransformerNgdotBytesArgs) ProtoMessage() {}
func (x *TransformerNgdotBytesArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TransformerNgdotBytesArgs.ProtoReflect.Descriptor instead.
func (*TransformerNgdotBytesArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *TransformerNgdotBytesArgs) GetB() []byte {
if x != nil {
return x.B
}
return nil
}
type TransformerNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S string `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TransformerNgdotStringArgs) Reset() {
*x = TransformerNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TransformerNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TransformerNgdotStringArgs) ProtoMessage() {}
func (x *TransformerNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TransformerNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*TransformerNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *TransformerNgdotStringArgs) GetS() string {
if x != nil {
return x.S
}
return ""
}
type RemoveArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RemoveArgs) Reset() {
*x = RemoveArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RemoveArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RemoveArgs) ProtoMessage() {}
func (x *RemoveArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RemoveArgs.ProtoReflect.Descriptor instead.
func (*RemoveArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
type ReplaceIllFormedArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ReplaceIllFormedArgs) Reset() {
*x = ReplaceIllFormedArgs{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ReplaceIllFormedArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReplaceIllFormedArgs) ProtoMessage() {}
func (x *ReplaceIllFormedArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReplaceIllFormedArgs.ProtoReflect.Descriptor instead.
func (*ReplaceIllFormedArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_TransformerNgdotTransform
// *NgoloFuzzOne_TransformerNgdotSpan
// *NgoloFuzzOne_TransformerNgdotReset
// *NgoloFuzzOne_TransformerNgdotBytes
// *NgoloFuzzOne_TransformerNgdotString
// *NgoloFuzzOne_Remove
// *NgoloFuzzOne_ReplaceIllFormed
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetTransformerNgdotTransform() *TransformerNgdotTransformArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TransformerNgdotTransform); ok {
return x.TransformerNgdotTransform
}
}
return nil
}
func (x *NgoloFuzzOne) GetTransformerNgdotSpan() *TransformerNgdotSpanArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TransformerNgdotSpan); ok {
return x.TransformerNgdotSpan
}
}
return nil
}
func (x *NgoloFuzzOne) GetTransformerNgdotReset() *TransformerNgdotResetArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TransformerNgdotReset); ok {
return x.TransformerNgdotReset
}
}
return nil
}
func (x *NgoloFuzzOne) GetTransformerNgdotBytes() *TransformerNgdotBytesArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TransformerNgdotBytes); ok {
return x.TransformerNgdotBytes
}
}
return nil
}
func (x *NgoloFuzzOne) GetTransformerNgdotString() *TransformerNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TransformerNgdotString); ok {
return x.TransformerNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetRemove() *RemoveArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Remove); ok {
return x.Remove
}
}
return nil
}
func (x *NgoloFuzzOne) GetReplaceIllFormed() *ReplaceIllFormedArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ReplaceIllFormed); ok {
return x.ReplaceIllFormed
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_TransformerNgdotTransform struct {
TransformerNgdotTransform *TransformerNgdotTransformArgs `protobuf:"bytes,1,opt,name=TransformerNgdotTransform,proto3,oneof"`
}
type NgoloFuzzOne_TransformerNgdotSpan struct {
TransformerNgdotSpan *TransformerNgdotSpanArgs `protobuf:"bytes,2,opt,name=TransformerNgdotSpan,proto3,oneof"`
}
type NgoloFuzzOne_TransformerNgdotReset struct {
TransformerNgdotReset *TransformerNgdotResetArgs `protobuf:"bytes,3,opt,name=TransformerNgdotReset,proto3,oneof"`
}
type NgoloFuzzOne_TransformerNgdotBytes struct {
TransformerNgdotBytes *TransformerNgdotBytesArgs `protobuf:"bytes,4,opt,name=TransformerNgdotBytes,proto3,oneof"`
}
type NgoloFuzzOne_TransformerNgdotString struct {
TransformerNgdotString *TransformerNgdotStringArgs `protobuf:"bytes,5,opt,name=TransformerNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_Remove struct {
Remove *RemoveArgs `protobuf:"bytes,6,opt,name=Remove,proto3,oneof"`
}
type NgoloFuzzOne_ReplaceIllFormed struct {
ReplaceIllFormed *ReplaceIllFormedArgs `protobuf:"bytes,7,opt,name=ReplaceIllFormed,proto3,oneof"`
}
func (*NgoloFuzzOne_TransformerNgdotTransform) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TransformerNgdotSpan) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TransformerNgdotReset) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TransformerNgdotBytes) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TransformerNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Remove) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ReplaceIllFormed) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"Y\n" +
"\x1dTransformerNgdotTransformArgs\x12\x10\n" +
"\x03dst\x18\x01 \x01(\fR\x03dst\x12\x10\n" +
"\x03src\x18\x02 \x01(\fR\x03src\x12\x14\n" +
"\x05atEOF\x18\x03 \x01(\bR\x05atEOF\">\n" +
"\x18TransformerNgdotSpanArgs\x12\f\n" +
"\x01b\x18\x01 \x01(\fR\x01b\x12\x14\n" +
"\x05atEOF\x18\x02 \x01(\bR\x05atEOF\"\x1b\n" +
"\x19TransformerNgdotResetArgs\")\n" +
"\x19TransformerNgdotBytesArgs\x12\f\n" +
"\x01b\x18\x01 \x01(\fR\x01b\"*\n" +
"\x1aTransformerNgdotStringArgs\x12\f\n" +
"\x01s\x18\x01 \x01(\tR\x01s\"\f\n" +
"\n" +
"RemoveArgs\"\x16\n" +
"\x14ReplaceIllFormedArgs\"\xf8\x04\n" +
"\fNgoloFuzzOne\x12h\n" +
"\x19TransformerNgdotTransform\x18\x01 \x01(\v2(.ngolofuzz.TransformerNgdotTransformArgsH\x00R\x19TransformerNgdotTransform\x12Y\n" +
"\x14TransformerNgdotSpan\x18\x02 \x01(\v2#.ngolofuzz.TransformerNgdotSpanArgsH\x00R\x14TransformerNgdotSpan\x12\\\n" +
"\x15TransformerNgdotReset\x18\x03 \x01(\v2$.ngolofuzz.TransformerNgdotResetArgsH\x00R\x15TransformerNgdotReset\x12\\\n" +
"\x15TransformerNgdotBytes\x18\x04 \x01(\v2$.ngolofuzz.TransformerNgdotBytesArgsH\x00R\x15TransformerNgdotBytes\x12_\n" +
"\x16TransformerNgdotString\x18\x05 \x01(\v2%.ngolofuzz.TransformerNgdotStringArgsH\x00R\x16TransformerNgdotString\x12/\n" +
"\x06Remove\x18\x06 \x01(\v2\x15.ngolofuzz.RemoveArgsH\x00R\x06Remove\x12M\n" +
"\x10ReplaceIllFormed\x18\a \x01(\v2\x1f.ngolofuzz.ReplaceIllFormedArgsH\x00R\x10ReplaceIllFormedB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x19Z\x17./;fuzz_ng_x_text_runesb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
var file_ngolofuzz_proto_goTypes = []any{
(*TransformerNgdotTransformArgs)(nil), // 0: ngolofuzz.TransformerNgdotTransformArgs
(*TransformerNgdotSpanArgs)(nil), // 1: ngolofuzz.TransformerNgdotSpanArgs
(*TransformerNgdotResetArgs)(nil), // 2: ngolofuzz.TransformerNgdotResetArgs
(*TransformerNgdotBytesArgs)(nil), // 3: ngolofuzz.TransformerNgdotBytesArgs
(*TransformerNgdotStringArgs)(nil), // 4: ngolofuzz.TransformerNgdotStringArgs
(*RemoveArgs)(nil), // 5: ngolofuzz.RemoveArgs
(*ReplaceIllFormedArgs)(nil), // 6: ngolofuzz.ReplaceIllFormedArgs
(*NgoloFuzzOne)(nil), // 7: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 8: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 9: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.TransformerNgdotTransform:type_name -> ngolofuzz.TransformerNgdotTransformArgs
1, // 1: ngolofuzz.NgoloFuzzOne.TransformerNgdotSpan:type_name -> ngolofuzz.TransformerNgdotSpanArgs
2, // 2: ngolofuzz.NgoloFuzzOne.TransformerNgdotReset:type_name -> ngolofuzz.TransformerNgdotResetArgs
3, // 3: ngolofuzz.NgoloFuzzOne.TransformerNgdotBytes:type_name -> ngolofuzz.TransformerNgdotBytesArgs
4, // 4: ngolofuzz.NgoloFuzzOne.TransformerNgdotString:type_name -> ngolofuzz.TransformerNgdotStringArgs
5, // 5: ngolofuzz.NgoloFuzzOne.Remove:type_name -> ngolofuzz.RemoveArgs
6, // 6: ngolofuzz.NgoloFuzzOne.ReplaceIllFormed:type_name -> ngolofuzz.ReplaceIllFormedArgs
7, // 7: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
8, // [8:8] is the sub-list for method output_type
8, // [8:8] is the sub-list for method input_type
8, // [8:8] is the sub-list for extension type_name
8, // [8:8] is the sub-list for extension extendee
0, // [0:8] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[7].OneofWrappers = []any{
(*NgoloFuzzOne_TransformerNgdotTransform)(nil),
(*NgoloFuzzOne_TransformerNgdotSpan)(nil),
(*NgoloFuzzOne_TransformerNgdotReset)(nil),
(*NgoloFuzzOne_TransformerNgdotBytes)(nil),
(*NgoloFuzzOne_TransformerNgdotString)(nil),
(*NgoloFuzzOne_Remove)(nil),
(*NgoloFuzzOne_ReplaceIllFormed)(nil),
}
file_ngolofuzz_proto_msgTypes[8].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 10,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_text_secure_bidirule
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/text/secure/bidirule"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var TransformerResults []*bidirule.Transformer
TransformerResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Direction:
bidirule.Direction(a.Direction.B)
case *NgoloFuzzOne_DirectionString:
bidirule.DirectionString(a.DirectionString.S)
case *NgoloFuzzOne_Valid:
bidirule.Valid(a.Valid.B)
case *NgoloFuzzOne_ValidString:
bidirule.ValidString(a.ValidString.S)
case *NgoloFuzzOne_New:
r0 := bidirule.New()
if r0 != nil{
TransformerResults = append(TransformerResults, r0)
}
case *NgoloFuzzOne_TransformerNgdotReset:
if len(TransformerResults) == 0 {
continue
}
arg0 := TransformerResults[TransformerResultsIndex]
TransformerResultsIndex = (TransformerResultsIndex + 1) % len(TransformerResults)
arg0.Reset()
case *NgoloFuzzOne_TransformerNgdotTransform:
if len(TransformerResults) == 0 {
continue
}
arg0 := TransformerResults[TransformerResultsIndex]
TransformerResultsIndex = (TransformerResultsIndex + 1) % len(TransformerResults)
a.TransformerNgdotTransform.Dst = make([]byte, 2*len(a.TransformerNgdotTransform.Src))
_, _, r2 := arg0.Transform(a.TransformerNgdotTransform.Dst, a.TransformerNgdotTransform.Src, a.TransformerNgdotTransform.AtEOF)
if r2 != nil{
r2.Error()
return 0
}
case *NgoloFuzzOne_TransformerNgdotSpan:
if len(TransformerResults) == 0 {
continue
}
arg0 := TransformerResults[TransformerResultsIndex]
TransformerResultsIndex = (TransformerResultsIndex + 1) % len(TransformerResults)
_, r1 := arg0.Span(a.TransformerNgdotSpan.Src, a.TransformerNgdotSpan.AtEOF)
if r1 != nil{
r1.Error()
return 0
}
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
TransformerNb := 0
TransformerResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Direction:
w.WriteString(fmt.Sprintf("bidirule.Direction(%#+v)\n", a.Direction.B))
case *NgoloFuzzOne_DirectionString:
w.WriteString(fmt.Sprintf("bidirule.DirectionString(%#+v)\n", a.DirectionString.S))
case *NgoloFuzzOne_Valid:
w.WriteString(fmt.Sprintf("bidirule.Valid(%#+v)\n", a.Valid.B))
case *NgoloFuzzOne_ValidString:
w.WriteString(fmt.Sprintf("bidirule.ValidString(%#+v)\n", a.ValidString.S))
case *NgoloFuzzOne_New:
w.WriteString(fmt.Sprintf("Transformer%d := bidirule.New()\n", TransformerNb))
TransformerNb = TransformerNb + 1
case *NgoloFuzzOne_TransformerNgdotReset:
if TransformerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Transformer%d.Reset()\n", TransformerResultsIndex))
TransformerResultsIndex = (TransformerResultsIndex + 1) % TransformerNb
case *NgoloFuzzOne_TransformerNgdotTransform:
if TransformerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Transformer%d.Transform(%#+v, %#+v, %#+v)\n", TransformerResultsIndex, a.TransformerNgdotTransform.Dst, a.TransformerNgdotTransform.Src, a.TransformerNgdotTransform.AtEOF))
TransformerResultsIndex = (TransformerResultsIndex + 1) % TransformerNb
case *NgoloFuzzOne_TransformerNgdotSpan:
if TransformerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Transformer%d.Span(%#+v, %#+v)\n", TransformerResultsIndex, a.TransformerNgdotSpan.Src, a.TransformerNgdotSpan.AtEOF))
TransformerResultsIndex = (TransformerResultsIndex + 1) % TransformerNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_text_secure_bidirule
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type DirectionArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
B []byte `protobuf:"bytes,1,opt,name=b,proto3" json:"b,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DirectionArgs) Reset() {
*x = DirectionArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DirectionArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DirectionArgs) ProtoMessage() {}
func (x *DirectionArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DirectionArgs.ProtoReflect.Descriptor instead.
func (*DirectionArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *DirectionArgs) GetB() []byte {
if x != nil {
return x.B
}
return nil
}
type DirectionStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S string `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DirectionStringArgs) Reset() {
*x = DirectionStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DirectionStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DirectionStringArgs) ProtoMessage() {}
func (x *DirectionStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DirectionStringArgs.ProtoReflect.Descriptor instead.
func (*DirectionStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *DirectionStringArgs) GetS() string {
if x != nil {
return x.S
}
return ""
}
type ValidArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
B []byte `protobuf:"bytes,1,opt,name=b,proto3" json:"b,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ValidArgs) Reset() {
*x = ValidArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ValidArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ValidArgs) ProtoMessage() {}
func (x *ValidArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ValidArgs.ProtoReflect.Descriptor instead.
func (*ValidArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *ValidArgs) GetB() []byte {
if x != nil {
return x.B
}
return nil
}
type ValidStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S string `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ValidStringArgs) Reset() {
*x = ValidStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ValidStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ValidStringArgs) ProtoMessage() {}
func (x *ValidStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ValidStringArgs.ProtoReflect.Descriptor instead.
func (*ValidStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *ValidStringArgs) GetS() string {
if x != nil {
return x.S
}
return ""
}
type NewArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewArgs) Reset() {
*x = NewArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewArgs) ProtoMessage() {}
func (x *NewArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewArgs.ProtoReflect.Descriptor instead.
func (*NewArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
type TransformerNgdotResetArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TransformerNgdotResetArgs) Reset() {
*x = TransformerNgdotResetArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TransformerNgdotResetArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TransformerNgdotResetArgs) ProtoMessage() {}
func (x *TransformerNgdotResetArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TransformerNgdotResetArgs.ProtoReflect.Descriptor instead.
func (*TransformerNgdotResetArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
type TransformerNgdotTransformArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Dst []byte `protobuf:"bytes,1,opt,name=dst,proto3" json:"dst,omitempty"`
Src []byte `protobuf:"bytes,2,opt,name=src,proto3" json:"src,omitempty"`
AtEOF bool `protobuf:"varint,3,opt,name=atEOF,proto3" json:"atEOF,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TransformerNgdotTransformArgs) Reset() {
*x = TransformerNgdotTransformArgs{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TransformerNgdotTransformArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TransformerNgdotTransformArgs) ProtoMessage() {}
func (x *TransformerNgdotTransformArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TransformerNgdotTransformArgs.ProtoReflect.Descriptor instead.
func (*TransformerNgdotTransformArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *TransformerNgdotTransformArgs) GetDst() []byte {
if x != nil {
return x.Dst
}
return nil
}
func (x *TransformerNgdotTransformArgs) GetSrc() []byte {
if x != nil {
return x.Src
}
return nil
}
func (x *TransformerNgdotTransformArgs) GetAtEOF() bool {
if x != nil {
return x.AtEOF
}
return false
}
type TransformerNgdotSpanArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Src []byte `protobuf:"bytes,1,opt,name=src,proto3" json:"src,omitempty"`
AtEOF bool `protobuf:"varint,2,opt,name=atEOF,proto3" json:"atEOF,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TransformerNgdotSpanArgs) Reset() {
*x = TransformerNgdotSpanArgs{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TransformerNgdotSpanArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TransformerNgdotSpanArgs) ProtoMessage() {}
func (x *TransformerNgdotSpanArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TransformerNgdotSpanArgs.ProtoReflect.Descriptor instead.
func (*TransformerNgdotSpanArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
func (x *TransformerNgdotSpanArgs) GetSrc() []byte {
if x != nil {
return x.Src
}
return nil
}
func (x *TransformerNgdotSpanArgs) GetAtEOF() bool {
if x != nil {
return x.AtEOF
}
return false
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_Direction
// *NgoloFuzzOne_DirectionString
// *NgoloFuzzOne_Valid
// *NgoloFuzzOne_ValidString
// *NgoloFuzzOne_New
// *NgoloFuzzOne_TransformerNgdotReset
// *NgoloFuzzOne_TransformerNgdotTransform
// *NgoloFuzzOne_TransformerNgdotSpan
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetDirection() *DirectionArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Direction); ok {
return x.Direction
}
}
return nil
}
func (x *NgoloFuzzOne) GetDirectionString() *DirectionStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_DirectionString); ok {
return x.DirectionString
}
}
return nil
}
func (x *NgoloFuzzOne) GetValid() *ValidArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Valid); ok {
return x.Valid
}
}
return nil
}
func (x *NgoloFuzzOne) GetValidString() *ValidStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ValidString); ok {
return x.ValidString
}
}
return nil
}
func (x *NgoloFuzzOne) GetNew() *NewArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_New); ok {
return x.New
}
}
return nil
}
func (x *NgoloFuzzOne) GetTransformerNgdotReset() *TransformerNgdotResetArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TransformerNgdotReset); ok {
return x.TransformerNgdotReset
}
}
return nil
}
func (x *NgoloFuzzOne) GetTransformerNgdotTransform() *TransformerNgdotTransformArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TransformerNgdotTransform); ok {
return x.TransformerNgdotTransform
}
}
return nil
}
func (x *NgoloFuzzOne) GetTransformerNgdotSpan() *TransformerNgdotSpanArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TransformerNgdotSpan); ok {
return x.TransformerNgdotSpan
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_Direction struct {
Direction *DirectionArgs `protobuf:"bytes,1,opt,name=Direction,proto3,oneof"`
}
type NgoloFuzzOne_DirectionString struct {
DirectionString *DirectionStringArgs `protobuf:"bytes,2,opt,name=DirectionString,proto3,oneof"`
}
type NgoloFuzzOne_Valid struct {
Valid *ValidArgs `protobuf:"bytes,3,opt,name=Valid,proto3,oneof"`
}
type NgoloFuzzOne_ValidString struct {
ValidString *ValidStringArgs `protobuf:"bytes,4,opt,name=ValidString,proto3,oneof"`
}
type NgoloFuzzOne_New struct {
New *NewArgs `protobuf:"bytes,5,opt,name=New,proto3,oneof"`
}
type NgoloFuzzOne_TransformerNgdotReset struct {
TransformerNgdotReset *TransformerNgdotResetArgs `protobuf:"bytes,6,opt,name=TransformerNgdotReset,proto3,oneof"`
}
type NgoloFuzzOne_TransformerNgdotTransform struct {
TransformerNgdotTransform *TransformerNgdotTransformArgs `protobuf:"bytes,7,opt,name=TransformerNgdotTransform,proto3,oneof"`
}
type NgoloFuzzOne_TransformerNgdotSpan struct {
TransformerNgdotSpan *TransformerNgdotSpanArgs `protobuf:"bytes,8,opt,name=TransformerNgdotSpan,proto3,oneof"`
}
func (*NgoloFuzzOne_Direction) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_DirectionString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Valid) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ValidString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_New) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TransformerNgdotReset) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TransformerNgdotTransform) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TransformerNgdotSpan) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{10}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x1d\n" +
"\rDirectionArgs\x12\f\n" +
"\x01b\x18\x01 \x01(\fR\x01b\"#\n" +
"\x13DirectionStringArgs\x12\f\n" +
"\x01s\x18\x01 \x01(\tR\x01s\"\x19\n" +
"\tValidArgs\x12\f\n" +
"\x01b\x18\x01 \x01(\fR\x01b\"\x1f\n" +
"\x0fValidStringArgs\x12\f\n" +
"\x01s\x18\x01 \x01(\tR\x01s\"\t\n" +
"\aNewArgs\"\x1b\n" +
"\x19TransformerNgdotResetArgs\"Y\n" +
"\x1dTransformerNgdotTransformArgs\x12\x10\n" +
"\x03dst\x18\x01 \x01(\fR\x03dst\x12\x10\n" +
"\x03src\x18\x02 \x01(\fR\x03src\x12\x14\n" +
"\x05atEOF\x18\x03 \x01(\bR\x05atEOF\"B\n" +
"\x18TransformerNgdotSpanArgs\x12\x10\n" +
"\x03src\x18\x01 \x01(\fR\x03src\x12\x14\n" +
"\x05atEOF\x18\x02 \x01(\bR\x05atEOF\"\xd5\x04\n" +
"\fNgoloFuzzOne\x128\n" +
"\tDirection\x18\x01 \x01(\v2\x18.ngolofuzz.DirectionArgsH\x00R\tDirection\x12J\n" +
"\x0fDirectionString\x18\x02 \x01(\v2\x1e.ngolofuzz.DirectionStringArgsH\x00R\x0fDirectionString\x12,\n" +
"\x05Valid\x18\x03 \x01(\v2\x14.ngolofuzz.ValidArgsH\x00R\x05Valid\x12>\n" +
"\vValidString\x18\x04 \x01(\v2\x1a.ngolofuzz.ValidStringArgsH\x00R\vValidString\x12&\n" +
"\x03New\x18\x05 \x01(\v2\x12.ngolofuzz.NewArgsH\x00R\x03New\x12\\\n" +
"\x15TransformerNgdotReset\x18\x06 \x01(\v2$.ngolofuzz.TransformerNgdotResetArgsH\x00R\x15TransformerNgdotReset\x12h\n" +
"\x19TransformerNgdotTransform\x18\a \x01(\v2(.ngolofuzz.TransformerNgdotTransformArgsH\x00R\x19TransformerNgdotTransform\x12Y\n" +
"\x14TransformerNgdotSpan\x18\b \x01(\v2#.ngolofuzz.TransformerNgdotSpanArgsH\x00R\x14TransformerNgdotSpanB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB#Z!./;fuzz_ng_x_text_secure_bidiruleb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
var file_ngolofuzz_proto_goTypes = []any{
(*DirectionArgs)(nil), // 0: ngolofuzz.DirectionArgs
(*DirectionStringArgs)(nil), // 1: ngolofuzz.DirectionStringArgs
(*ValidArgs)(nil), // 2: ngolofuzz.ValidArgs
(*ValidStringArgs)(nil), // 3: ngolofuzz.ValidStringArgs
(*NewArgs)(nil), // 4: ngolofuzz.NewArgs
(*TransformerNgdotResetArgs)(nil), // 5: ngolofuzz.TransformerNgdotResetArgs
(*TransformerNgdotTransformArgs)(nil), // 6: ngolofuzz.TransformerNgdotTransformArgs
(*TransformerNgdotSpanArgs)(nil), // 7: ngolofuzz.TransformerNgdotSpanArgs
(*NgoloFuzzOne)(nil), // 8: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 9: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 10: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.Direction:type_name -> ngolofuzz.DirectionArgs
1, // 1: ngolofuzz.NgoloFuzzOne.DirectionString:type_name -> ngolofuzz.DirectionStringArgs
2, // 2: ngolofuzz.NgoloFuzzOne.Valid:type_name -> ngolofuzz.ValidArgs
3, // 3: ngolofuzz.NgoloFuzzOne.ValidString:type_name -> ngolofuzz.ValidStringArgs
4, // 4: ngolofuzz.NgoloFuzzOne.New:type_name -> ngolofuzz.NewArgs
5, // 5: ngolofuzz.NgoloFuzzOne.TransformerNgdotReset:type_name -> ngolofuzz.TransformerNgdotResetArgs
6, // 6: ngolofuzz.NgoloFuzzOne.TransformerNgdotTransform:type_name -> ngolofuzz.TransformerNgdotTransformArgs
7, // 7: ngolofuzz.NgoloFuzzOne.TransformerNgdotSpan:type_name -> ngolofuzz.TransformerNgdotSpanArgs
8, // 8: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
9, // [9:9] is the sub-list for method output_type
9, // [9:9] is the sub-list for method input_type
9, // [9:9] is the sub-list for extension type_name
9, // [9:9] is the sub-list for extension extendee
0, // [0:9] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[8].OneofWrappers = []any{
(*NgoloFuzzOne_Direction)(nil),
(*NgoloFuzzOne_DirectionString)(nil),
(*NgoloFuzzOne_Valid)(nil),
(*NgoloFuzzOne_ValidString)(nil),
(*NgoloFuzzOne_New)(nil),
(*NgoloFuzzOne_TransformerNgdotReset)(nil),
(*NgoloFuzzOne_TransformerNgdotTransform)(nil),
(*NgoloFuzzOne_TransformerNgdotSpan)(nil),
}
file_ngolofuzz_proto_msgTypes[9].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 11,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_text_secure_precis
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/text/secure/precis"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var ProfileResults []*precis.Profile
ProfileResultsIndex := 0
var TransformerResults []*precis.Transformer
TransformerResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_ProfileNgdotNewTransformer:
if len(ProfileResults) == 0 {
continue
}
arg0 := ProfileResults[ProfileResultsIndex]
ProfileResultsIndex = (ProfileResultsIndex + 1) % len(ProfileResults)
r0 := arg0.NewTransformer()
if r0 != nil{
TransformerResults = append(TransformerResults, r0)
}
case *NgoloFuzzOne_ProfileNgdotAppend:
if len(ProfileResults) == 0 {
continue
}
arg0 := ProfileResults[ProfileResultsIndex]
ProfileResultsIndex = (ProfileResultsIndex + 1) % len(ProfileResults)
a.ProfileNgdotAppend.Dst = make([]byte, 2*len(a.ProfileNgdotAppend.Src))
_, r1 := arg0.Append(a.ProfileNgdotAppend.Dst, a.ProfileNgdotAppend.Src)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_ProfileNgdotBytes:
if len(ProfileResults) == 0 {
continue
}
arg0 := ProfileResults[ProfileResultsIndex]
ProfileResultsIndex = (ProfileResultsIndex + 1) % len(ProfileResults)
_, r1 := arg0.Bytes(a.ProfileNgdotBytes.B)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_ProfileNgdotAppendCompareKey:
if len(ProfileResults) == 0 {
continue
}
arg0 := ProfileResults[ProfileResultsIndex]
ProfileResultsIndex = (ProfileResultsIndex + 1) % len(ProfileResults)
a.ProfileNgdotAppendCompareKey.Dst = make([]byte, 2*len(a.ProfileNgdotAppendCompareKey.Src))
_, r1 := arg0.AppendCompareKey(a.ProfileNgdotAppendCompareKey.Dst, a.ProfileNgdotAppendCompareKey.Src)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_ProfileNgdotString:
if len(ProfileResults) == 0 {
continue
}
arg0 := ProfileResults[ProfileResultsIndex]
ProfileResultsIndex = (ProfileResultsIndex + 1) % len(ProfileResults)
_, r1 := arg0.String(a.ProfileNgdotString.S)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_ProfileNgdotCompareKey:
if len(ProfileResults) == 0 {
continue
}
arg0 := ProfileResults[ProfileResultsIndex]
ProfileResultsIndex = (ProfileResultsIndex + 1) % len(ProfileResults)
_, r1 := arg0.CompareKey(a.ProfileNgdotCompareKey.S)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_ProfileNgdotCompare:
if len(ProfileResults) == 0 {
continue
}
arg0 := ProfileResults[ProfileResultsIndex]
ProfileResultsIndex = (ProfileResultsIndex + 1) % len(ProfileResults)
arg0.Compare(a.ProfileNgdotCompare.A, a.ProfileNgdotCompare.B)
case *NgoloFuzzOne_ProfileNgdotAllowed:
if len(ProfileResults) == 0 {
continue
}
arg0 := ProfileResults[ProfileResultsIndex]
ProfileResultsIndex = (ProfileResultsIndex + 1) % len(ProfileResults)
arg0.Allowed()
case *NgoloFuzzOne_TransformerNgdotReset:
if len(TransformerResults) == 0 {
continue
}
arg0 := TransformerResults[TransformerResultsIndex]
TransformerResultsIndex = (TransformerResultsIndex + 1) % len(TransformerResults)
arg0.Reset()
case *NgoloFuzzOne_TransformerNgdotTransform:
if len(TransformerResults) == 0 {
continue
}
arg0 := TransformerResults[TransformerResultsIndex]
TransformerResultsIndex = (TransformerResultsIndex + 1) % len(TransformerResults)
a.TransformerNgdotTransform.Dst = make([]byte, 2*len(a.TransformerNgdotTransform.Src))
_, _, r2 := arg0.Transform(a.TransformerNgdotTransform.Dst, a.TransformerNgdotTransform.Src, a.TransformerNgdotTransform.AtEOF)
if r2 != nil{
r2.Error()
return 0
}
case *NgoloFuzzOne_TransformerNgdotBytes:
if len(TransformerResults) == 0 {
continue
}
arg0 := TransformerResults[TransformerResultsIndex]
TransformerResultsIndex = (TransformerResultsIndex + 1) % len(TransformerResults)
arg0.Bytes(a.TransformerNgdotBytes.B)
case *NgoloFuzzOne_TransformerNgdotString:
if len(TransformerResults) == 0 {
continue
}
arg0 := TransformerResults[TransformerResultsIndex]
TransformerResultsIndex = (TransformerResultsIndex + 1) % len(TransformerResults)
arg0.String(a.TransformerNgdotString.S)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
ProfileNb := 0
ProfileResultsIndex := 0
TransformerNb := 0
TransformerResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_ProfileNgdotNewTransformer:
if ProfileNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Transformer%d := Profile%d.NewTransformer()\n", TransformerNb, ProfileResultsIndex))
TransformerNb = TransformerNb + 1
ProfileResultsIndex = (ProfileResultsIndex + 1) % ProfileNb
case *NgoloFuzzOne_ProfileNgdotAppend:
if ProfileNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Profile%d.Append(%#+v, %#+v)\n", ProfileResultsIndex, a.ProfileNgdotAppend.Dst, a.ProfileNgdotAppend.Src))
ProfileResultsIndex = (ProfileResultsIndex + 1) % ProfileNb
case *NgoloFuzzOne_ProfileNgdotBytes:
if ProfileNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Profile%d.Bytes(%#+v)\n", ProfileResultsIndex, a.ProfileNgdotBytes.B))
ProfileResultsIndex = (ProfileResultsIndex + 1) % ProfileNb
case *NgoloFuzzOne_ProfileNgdotAppendCompareKey:
if ProfileNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Profile%d.AppendCompareKey(%#+v, %#+v)\n", ProfileResultsIndex, a.ProfileNgdotAppendCompareKey.Dst, a.ProfileNgdotAppendCompareKey.Src))
ProfileResultsIndex = (ProfileResultsIndex + 1) % ProfileNb
case *NgoloFuzzOne_ProfileNgdotString:
if ProfileNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Profile%d.String(%#+v)\n", ProfileResultsIndex, a.ProfileNgdotString.S))
ProfileResultsIndex = (ProfileResultsIndex + 1) % ProfileNb
case *NgoloFuzzOne_ProfileNgdotCompareKey:
if ProfileNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Profile%d.CompareKey(%#+v)\n", ProfileResultsIndex, a.ProfileNgdotCompareKey.S))
ProfileResultsIndex = (ProfileResultsIndex + 1) % ProfileNb
case *NgoloFuzzOne_ProfileNgdotCompare:
if ProfileNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Profile%d.Compare(%#+v, %#+v)\n", ProfileResultsIndex, a.ProfileNgdotCompare.A, a.ProfileNgdotCompare.B))
ProfileResultsIndex = (ProfileResultsIndex + 1) % ProfileNb
case *NgoloFuzzOne_ProfileNgdotAllowed:
if ProfileNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Profile%d.Allowed()\n", ProfileResultsIndex))
ProfileResultsIndex = (ProfileResultsIndex + 1) % ProfileNb
case *NgoloFuzzOne_TransformerNgdotReset:
if TransformerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Transformer%d.Reset()\n", TransformerResultsIndex))
TransformerResultsIndex = (TransformerResultsIndex + 1) % TransformerNb
case *NgoloFuzzOne_TransformerNgdotTransform:
if TransformerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Transformer%d.Transform(%#+v, %#+v, %#+v)\n", TransformerResultsIndex, a.TransformerNgdotTransform.Dst, a.TransformerNgdotTransform.Src, a.TransformerNgdotTransform.AtEOF))
TransformerResultsIndex = (TransformerResultsIndex + 1) % TransformerNb
case *NgoloFuzzOne_TransformerNgdotBytes:
if TransformerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Transformer%d.Bytes(%#+v)\n", TransformerResultsIndex, a.TransformerNgdotBytes.B))
TransformerResultsIndex = (TransformerResultsIndex + 1) % TransformerNb
case *NgoloFuzzOne_TransformerNgdotString:
if TransformerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Transformer%d.String(%#+v)\n", TransformerResultsIndex, a.TransformerNgdotString.S))
TransformerResultsIndex = (TransformerResultsIndex + 1) % TransformerNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_text_secure_precis
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ProfileNgdotNewTransformerArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProfileNgdotNewTransformerArgs) Reset() {
*x = ProfileNgdotNewTransformerArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProfileNgdotNewTransformerArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProfileNgdotNewTransformerArgs) ProtoMessage() {}
func (x *ProfileNgdotNewTransformerArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProfileNgdotNewTransformerArgs.ProtoReflect.Descriptor instead.
func (*ProfileNgdotNewTransformerArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type ProfileNgdotAppendArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Dst []byte `protobuf:"bytes,1,opt,name=dst,proto3" json:"dst,omitempty"`
Src []byte `protobuf:"bytes,2,opt,name=src,proto3" json:"src,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProfileNgdotAppendArgs) Reset() {
*x = ProfileNgdotAppendArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProfileNgdotAppendArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProfileNgdotAppendArgs) ProtoMessage() {}
func (x *ProfileNgdotAppendArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProfileNgdotAppendArgs.ProtoReflect.Descriptor instead.
func (*ProfileNgdotAppendArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *ProfileNgdotAppendArgs) GetDst() []byte {
if x != nil {
return x.Dst
}
return nil
}
func (x *ProfileNgdotAppendArgs) GetSrc() []byte {
if x != nil {
return x.Src
}
return nil
}
type ProfileNgdotBytesArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
B []byte `protobuf:"bytes,1,opt,name=b,proto3" json:"b,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProfileNgdotBytesArgs) Reset() {
*x = ProfileNgdotBytesArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProfileNgdotBytesArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProfileNgdotBytesArgs) ProtoMessage() {}
func (x *ProfileNgdotBytesArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProfileNgdotBytesArgs.ProtoReflect.Descriptor instead.
func (*ProfileNgdotBytesArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *ProfileNgdotBytesArgs) GetB() []byte {
if x != nil {
return x.B
}
return nil
}
type ProfileNgdotAppendCompareKeyArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Dst []byte `protobuf:"bytes,1,opt,name=dst,proto3" json:"dst,omitempty"`
Src []byte `protobuf:"bytes,2,opt,name=src,proto3" json:"src,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProfileNgdotAppendCompareKeyArgs) Reset() {
*x = ProfileNgdotAppendCompareKeyArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProfileNgdotAppendCompareKeyArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProfileNgdotAppendCompareKeyArgs) ProtoMessage() {}
func (x *ProfileNgdotAppendCompareKeyArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProfileNgdotAppendCompareKeyArgs.ProtoReflect.Descriptor instead.
func (*ProfileNgdotAppendCompareKeyArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *ProfileNgdotAppendCompareKeyArgs) GetDst() []byte {
if x != nil {
return x.Dst
}
return nil
}
func (x *ProfileNgdotAppendCompareKeyArgs) GetSrc() []byte {
if x != nil {
return x.Src
}
return nil
}
type ProfileNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S string `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProfileNgdotStringArgs) Reset() {
*x = ProfileNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProfileNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProfileNgdotStringArgs) ProtoMessage() {}
func (x *ProfileNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProfileNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*ProfileNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
func (x *ProfileNgdotStringArgs) GetS() string {
if x != nil {
return x.S
}
return ""
}
type ProfileNgdotCompareKeyArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S string `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProfileNgdotCompareKeyArgs) Reset() {
*x = ProfileNgdotCompareKeyArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProfileNgdotCompareKeyArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProfileNgdotCompareKeyArgs) ProtoMessage() {}
func (x *ProfileNgdotCompareKeyArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProfileNgdotCompareKeyArgs.ProtoReflect.Descriptor instead.
func (*ProfileNgdotCompareKeyArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *ProfileNgdotCompareKeyArgs) GetS() string {
if x != nil {
return x.S
}
return ""
}
type ProfileNgdotCompareArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
A string `protobuf:"bytes,1,opt,name=a,proto3" json:"a,omitempty"`
B string `protobuf:"bytes,2,opt,name=b,proto3" json:"b,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProfileNgdotCompareArgs) Reset() {
*x = ProfileNgdotCompareArgs{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProfileNgdotCompareArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProfileNgdotCompareArgs) ProtoMessage() {}
func (x *ProfileNgdotCompareArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProfileNgdotCompareArgs.ProtoReflect.Descriptor instead.
func (*ProfileNgdotCompareArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
func (x *ProfileNgdotCompareArgs) GetA() string {
if x != nil {
return x.A
}
return ""
}
func (x *ProfileNgdotCompareArgs) GetB() string {
if x != nil {
return x.B
}
return ""
}
type ProfileNgdotAllowedArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProfileNgdotAllowedArgs) Reset() {
*x = ProfileNgdotAllowedArgs{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProfileNgdotAllowedArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProfileNgdotAllowedArgs) ProtoMessage() {}
func (x *ProfileNgdotAllowedArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProfileNgdotAllowedArgs.ProtoReflect.Descriptor instead.
func (*ProfileNgdotAllowedArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
type TransformerNgdotResetArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TransformerNgdotResetArgs) Reset() {
*x = TransformerNgdotResetArgs{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TransformerNgdotResetArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TransformerNgdotResetArgs) ProtoMessage() {}
func (x *TransformerNgdotResetArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TransformerNgdotResetArgs.ProtoReflect.Descriptor instead.
func (*TransformerNgdotResetArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
type TransformerNgdotTransformArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Dst []byte `protobuf:"bytes,1,opt,name=dst,proto3" json:"dst,omitempty"`
Src []byte `protobuf:"bytes,2,opt,name=src,proto3" json:"src,omitempty"`
AtEOF bool `protobuf:"varint,3,opt,name=atEOF,proto3" json:"atEOF,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TransformerNgdotTransformArgs) Reset() {
*x = TransformerNgdotTransformArgs{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TransformerNgdotTransformArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TransformerNgdotTransformArgs) ProtoMessage() {}
func (x *TransformerNgdotTransformArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TransformerNgdotTransformArgs.ProtoReflect.Descriptor instead.
func (*TransformerNgdotTransformArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
func (x *TransformerNgdotTransformArgs) GetDst() []byte {
if x != nil {
return x.Dst
}
return nil
}
func (x *TransformerNgdotTransformArgs) GetSrc() []byte {
if x != nil {
return x.Src
}
return nil
}
func (x *TransformerNgdotTransformArgs) GetAtEOF() bool {
if x != nil {
return x.AtEOF
}
return false
}
type TransformerNgdotBytesArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
B []byte `protobuf:"bytes,1,opt,name=b,proto3" json:"b,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TransformerNgdotBytesArgs) Reset() {
*x = TransformerNgdotBytesArgs{}
mi := &file_ngolofuzz_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TransformerNgdotBytesArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TransformerNgdotBytesArgs) ProtoMessage() {}
func (x *TransformerNgdotBytesArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TransformerNgdotBytesArgs.ProtoReflect.Descriptor instead.
func (*TransformerNgdotBytesArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{10}
}
func (x *TransformerNgdotBytesArgs) GetB() []byte {
if x != nil {
return x.B
}
return nil
}
type TransformerNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S string `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TransformerNgdotStringArgs) Reset() {
*x = TransformerNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TransformerNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TransformerNgdotStringArgs) ProtoMessage() {}
func (x *TransformerNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[11]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TransformerNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*TransformerNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{11}
}
func (x *TransformerNgdotStringArgs) GetS() string {
if x != nil {
return x.S
}
return ""
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_ProfileNgdotNewTransformer
// *NgoloFuzzOne_ProfileNgdotAppend
// *NgoloFuzzOne_ProfileNgdotBytes
// *NgoloFuzzOne_ProfileNgdotAppendCompareKey
// *NgoloFuzzOne_ProfileNgdotString
// *NgoloFuzzOne_ProfileNgdotCompareKey
// *NgoloFuzzOne_ProfileNgdotCompare
// *NgoloFuzzOne_ProfileNgdotAllowed
// *NgoloFuzzOne_TransformerNgdotReset
// *NgoloFuzzOne_TransformerNgdotTransform
// *NgoloFuzzOne_TransformerNgdotBytes
// *NgoloFuzzOne_TransformerNgdotString
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[12]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{12}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetProfileNgdotNewTransformer() *ProfileNgdotNewTransformerArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ProfileNgdotNewTransformer); ok {
return x.ProfileNgdotNewTransformer
}
}
return nil
}
func (x *NgoloFuzzOne) GetProfileNgdotAppend() *ProfileNgdotAppendArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ProfileNgdotAppend); ok {
return x.ProfileNgdotAppend
}
}
return nil
}
func (x *NgoloFuzzOne) GetProfileNgdotBytes() *ProfileNgdotBytesArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ProfileNgdotBytes); ok {
return x.ProfileNgdotBytes
}
}
return nil
}
func (x *NgoloFuzzOne) GetProfileNgdotAppendCompareKey() *ProfileNgdotAppendCompareKeyArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ProfileNgdotAppendCompareKey); ok {
return x.ProfileNgdotAppendCompareKey
}
}
return nil
}
func (x *NgoloFuzzOne) GetProfileNgdotString() *ProfileNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ProfileNgdotString); ok {
return x.ProfileNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetProfileNgdotCompareKey() *ProfileNgdotCompareKeyArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ProfileNgdotCompareKey); ok {
return x.ProfileNgdotCompareKey
}
}
return nil
}
func (x *NgoloFuzzOne) GetProfileNgdotCompare() *ProfileNgdotCompareArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ProfileNgdotCompare); ok {
return x.ProfileNgdotCompare
}
}
return nil
}
func (x *NgoloFuzzOne) GetProfileNgdotAllowed() *ProfileNgdotAllowedArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ProfileNgdotAllowed); ok {
return x.ProfileNgdotAllowed
}
}
return nil
}
func (x *NgoloFuzzOne) GetTransformerNgdotReset() *TransformerNgdotResetArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TransformerNgdotReset); ok {
return x.TransformerNgdotReset
}
}
return nil
}
func (x *NgoloFuzzOne) GetTransformerNgdotTransform() *TransformerNgdotTransformArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TransformerNgdotTransform); ok {
return x.TransformerNgdotTransform
}
}
return nil
}
func (x *NgoloFuzzOne) GetTransformerNgdotBytes() *TransformerNgdotBytesArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TransformerNgdotBytes); ok {
return x.TransformerNgdotBytes
}
}
return nil
}
func (x *NgoloFuzzOne) GetTransformerNgdotString() *TransformerNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_TransformerNgdotString); ok {
return x.TransformerNgdotString
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_ProfileNgdotNewTransformer struct {
ProfileNgdotNewTransformer *ProfileNgdotNewTransformerArgs `protobuf:"bytes,1,opt,name=ProfileNgdotNewTransformer,proto3,oneof"`
}
type NgoloFuzzOne_ProfileNgdotAppend struct {
ProfileNgdotAppend *ProfileNgdotAppendArgs `protobuf:"bytes,2,opt,name=ProfileNgdotAppend,proto3,oneof"`
}
type NgoloFuzzOne_ProfileNgdotBytes struct {
ProfileNgdotBytes *ProfileNgdotBytesArgs `protobuf:"bytes,3,opt,name=ProfileNgdotBytes,proto3,oneof"`
}
type NgoloFuzzOne_ProfileNgdotAppendCompareKey struct {
ProfileNgdotAppendCompareKey *ProfileNgdotAppendCompareKeyArgs `protobuf:"bytes,4,opt,name=ProfileNgdotAppendCompareKey,proto3,oneof"`
}
type NgoloFuzzOne_ProfileNgdotString struct {
ProfileNgdotString *ProfileNgdotStringArgs `protobuf:"bytes,5,opt,name=ProfileNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_ProfileNgdotCompareKey struct {
ProfileNgdotCompareKey *ProfileNgdotCompareKeyArgs `protobuf:"bytes,6,opt,name=ProfileNgdotCompareKey,proto3,oneof"`
}
type NgoloFuzzOne_ProfileNgdotCompare struct {
ProfileNgdotCompare *ProfileNgdotCompareArgs `protobuf:"bytes,7,opt,name=ProfileNgdotCompare,proto3,oneof"`
}
type NgoloFuzzOne_ProfileNgdotAllowed struct {
ProfileNgdotAllowed *ProfileNgdotAllowedArgs `protobuf:"bytes,8,opt,name=ProfileNgdotAllowed,proto3,oneof"`
}
type NgoloFuzzOne_TransformerNgdotReset struct {
TransformerNgdotReset *TransformerNgdotResetArgs `protobuf:"bytes,9,opt,name=TransformerNgdotReset,proto3,oneof"`
}
type NgoloFuzzOne_TransformerNgdotTransform struct {
TransformerNgdotTransform *TransformerNgdotTransformArgs `protobuf:"bytes,10,opt,name=TransformerNgdotTransform,proto3,oneof"`
}
type NgoloFuzzOne_TransformerNgdotBytes struct {
TransformerNgdotBytes *TransformerNgdotBytesArgs `protobuf:"bytes,11,opt,name=TransformerNgdotBytes,proto3,oneof"`
}
type NgoloFuzzOne_TransformerNgdotString struct {
TransformerNgdotString *TransformerNgdotStringArgs `protobuf:"bytes,12,opt,name=TransformerNgdotString,proto3,oneof"`
}
func (*NgoloFuzzOne_ProfileNgdotNewTransformer) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ProfileNgdotAppend) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ProfileNgdotBytes) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ProfileNgdotAppendCompareKey) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ProfileNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ProfileNgdotCompareKey) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ProfileNgdotCompare) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ProfileNgdotAllowed) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TransformerNgdotReset) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TransformerNgdotTransform) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TransformerNgdotBytes) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_TransformerNgdotString) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[13]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{13}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[14]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{14}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\" \n" +
"\x1eProfileNgdotNewTransformerArgs\"<\n" +
"\x16ProfileNgdotAppendArgs\x12\x10\n" +
"\x03dst\x18\x01 \x01(\fR\x03dst\x12\x10\n" +
"\x03src\x18\x02 \x01(\fR\x03src\"%\n" +
"\x15ProfileNgdotBytesArgs\x12\f\n" +
"\x01b\x18\x01 \x01(\fR\x01b\"F\n" +
" ProfileNgdotAppendCompareKeyArgs\x12\x10\n" +
"\x03dst\x18\x01 \x01(\fR\x03dst\x12\x10\n" +
"\x03src\x18\x02 \x01(\fR\x03src\"&\n" +
"\x16ProfileNgdotStringArgs\x12\f\n" +
"\x01s\x18\x01 \x01(\tR\x01s\"*\n" +
"\x1aProfileNgdotCompareKeyArgs\x12\f\n" +
"\x01s\x18\x01 \x01(\tR\x01s\"5\n" +
"\x17ProfileNgdotCompareArgs\x12\f\n" +
"\x01a\x18\x01 \x01(\tR\x01a\x12\f\n" +
"\x01b\x18\x02 \x01(\tR\x01b\"\x19\n" +
"\x17ProfileNgdotAllowedArgs\"\x1b\n" +
"\x19TransformerNgdotResetArgs\"Y\n" +
"\x1dTransformerNgdotTransformArgs\x12\x10\n" +
"\x03dst\x18\x01 \x01(\fR\x03dst\x12\x10\n" +
"\x03src\x18\x02 \x01(\fR\x03src\x12\x14\n" +
"\x05atEOF\x18\x03 \x01(\bR\x05atEOF\")\n" +
"\x19TransformerNgdotBytesArgs\x12\f\n" +
"\x01b\x18\x01 \x01(\fR\x01b\"*\n" +
"\x1aTransformerNgdotStringArgs\x12\f\n" +
"\x01s\x18\x01 \x01(\tR\x01s\"\x8a\t\n" +
"\fNgoloFuzzOne\x12k\n" +
"\x1aProfileNgdotNewTransformer\x18\x01 \x01(\v2).ngolofuzz.ProfileNgdotNewTransformerArgsH\x00R\x1aProfileNgdotNewTransformer\x12S\n" +
"\x12ProfileNgdotAppend\x18\x02 \x01(\v2!.ngolofuzz.ProfileNgdotAppendArgsH\x00R\x12ProfileNgdotAppend\x12P\n" +
"\x11ProfileNgdotBytes\x18\x03 \x01(\v2 .ngolofuzz.ProfileNgdotBytesArgsH\x00R\x11ProfileNgdotBytes\x12q\n" +
"\x1cProfileNgdotAppendCompareKey\x18\x04 \x01(\v2+.ngolofuzz.ProfileNgdotAppendCompareKeyArgsH\x00R\x1cProfileNgdotAppendCompareKey\x12S\n" +
"\x12ProfileNgdotString\x18\x05 \x01(\v2!.ngolofuzz.ProfileNgdotStringArgsH\x00R\x12ProfileNgdotString\x12_\n" +
"\x16ProfileNgdotCompareKey\x18\x06 \x01(\v2%.ngolofuzz.ProfileNgdotCompareKeyArgsH\x00R\x16ProfileNgdotCompareKey\x12V\n" +
"\x13ProfileNgdotCompare\x18\a \x01(\v2\".ngolofuzz.ProfileNgdotCompareArgsH\x00R\x13ProfileNgdotCompare\x12V\n" +
"\x13ProfileNgdotAllowed\x18\b \x01(\v2\".ngolofuzz.ProfileNgdotAllowedArgsH\x00R\x13ProfileNgdotAllowed\x12\\\n" +
"\x15TransformerNgdotReset\x18\t \x01(\v2$.ngolofuzz.TransformerNgdotResetArgsH\x00R\x15TransformerNgdotReset\x12h\n" +
"\x19TransformerNgdotTransform\x18\n" +
" \x01(\v2(.ngolofuzz.TransformerNgdotTransformArgsH\x00R\x19TransformerNgdotTransform\x12\\\n" +
"\x15TransformerNgdotBytes\x18\v \x01(\v2$.ngolofuzz.TransformerNgdotBytesArgsH\x00R\x15TransformerNgdotBytes\x12_\n" +
"\x16TransformerNgdotString\x18\f \x01(\v2%.ngolofuzz.TransformerNgdotStringArgsH\x00R\x16TransformerNgdotStringB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB!Z\x1f./;fuzz_ng_x_text_secure_precisb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 15)
var file_ngolofuzz_proto_goTypes = []any{
(*ProfileNgdotNewTransformerArgs)(nil), // 0: ngolofuzz.ProfileNgdotNewTransformerArgs
(*ProfileNgdotAppendArgs)(nil), // 1: ngolofuzz.ProfileNgdotAppendArgs
(*ProfileNgdotBytesArgs)(nil), // 2: ngolofuzz.ProfileNgdotBytesArgs
(*ProfileNgdotAppendCompareKeyArgs)(nil), // 3: ngolofuzz.ProfileNgdotAppendCompareKeyArgs
(*ProfileNgdotStringArgs)(nil), // 4: ngolofuzz.ProfileNgdotStringArgs
(*ProfileNgdotCompareKeyArgs)(nil), // 5: ngolofuzz.ProfileNgdotCompareKeyArgs
(*ProfileNgdotCompareArgs)(nil), // 6: ngolofuzz.ProfileNgdotCompareArgs
(*ProfileNgdotAllowedArgs)(nil), // 7: ngolofuzz.ProfileNgdotAllowedArgs
(*TransformerNgdotResetArgs)(nil), // 8: ngolofuzz.TransformerNgdotResetArgs
(*TransformerNgdotTransformArgs)(nil), // 9: ngolofuzz.TransformerNgdotTransformArgs
(*TransformerNgdotBytesArgs)(nil), // 10: ngolofuzz.TransformerNgdotBytesArgs
(*TransformerNgdotStringArgs)(nil), // 11: ngolofuzz.TransformerNgdotStringArgs
(*NgoloFuzzOne)(nil), // 12: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 13: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 14: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.ProfileNgdotNewTransformer:type_name -> ngolofuzz.ProfileNgdotNewTransformerArgs
1, // 1: ngolofuzz.NgoloFuzzOne.ProfileNgdotAppend:type_name -> ngolofuzz.ProfileNgdotAppendArgs
2, // 2: ngolofuzz.NgoloFuzzOne.ProfileNgdotBytes:type_name -> ngolofuzz.ProfileNgdotBytesArgs
3, // 3: ngolofuzz.NgoloFuzzOne.ProfileNgdotAppendCompareKey:type_name -> ngolofuzz.ProfileNgdotAppendCompareKeyArgs
4, // 4: ngolofuzz.NgoloFuzzOne.ProfileNgdotString:type_name -> ngolofuzz.ProfileNgdotStringArgs
5, // 5: ngolofuzz.NgoloFuzzOne.ProfileNgdotCompareKey:type_name -> ngolofuzz.ProfileNgdotCompareKeyArgs
6, // 6: ngolofuzz.NgoloFuzzOne.ProfileNgdotCompare:type_name -> ngolofuzz.ProfileNgdotCompareArgs
7, // 7: ngolofuzz.NgoloFuzzOne.ProfileNgdotAllowed:type_name -> ngolofuzz.ProfileNgdotAllowedArgs
8, // 8: ngolofuzz.NgoloFuzzOne.TransformerNgdotReset:type_name -> ngolofuzz.TransformerNgdotResetArgs
9, // 9: ngolofuzz.NgoloFuzzOne.TransformerNgdotTransform:type_name -> ngolofuzz.TransformerNgdotTransformArgs
10, // 10: ngolofuzz.NgoloFuzzOne.TransformerNgdotBytes:type_name -> ngolofuzz.TransformerNgdotBytesArgs
11, // 11: ngolofuzz.NgoloFuzzOne.TransformerNgdotString:type_name -> ngolofuzz.TransformerNgdotStringArgs
12, // 12: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
13, // [13:13] is the sub-list for method output_type
13, // [13:13] is the sub-list for method input_type
13, // [13:13] is the sub-list for extension type_name
13, // [13:13] is the sub-list for extension extendee
0, // [0:13] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[12].OneofWrappers = []any{
(*NgoloFuzzOne_ProfileNgdotNewTransformer)(nil),
(*NgoloFuzzOne_ProfileNgdotAppend)(nil),
(*NgoloFuzzOne_ProfileNgdotBytes)(nil),
(*NgoloFuzzOne_ProfileNgdotAppendCompareKey)(nil),
(*NgoloFuzzOne_ProfileNgdotString)(nil),
(*NgoloFuzzOne_ProfileNgdotCompareKey)(nil),
(*NgoloFuzzOne_ProfileNgdotCompare)(nil),
(*NgoloFuzzOne_ProfileNgdotAllowed)(nil),
(*NgoloFuzzOne_TransformerNgdotReset)(nil),
(*NgoloFuzzOne_TransformerNgdotTransform)(nil),
(*NgoloFuzzOne_TransformerNgdotBytes)(nil),
(*NgoloFuzzOne_TransformerNgdotString)(nil),
}
file_ngolofuzz_proto_msgTypes[13].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 15,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_text_unicode_bidi
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/text/unicode/bidi"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var OrderingResults []*bidi.Ordering
OrderingResultsIndex := 0
var RunResults []*bidi.Run
RunResultsIndex := 0
var PropertiesResults []*bidi.Properties
PropertiesResultsIndex := 0
var DirectionResults []*bidi.Direction
DirectionResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_DefaultDirection:
if len(DirectionResults) == 0 {
continue
}
arg0 := *DirectionResults[DirectionResultsIndex]
DirectionResultsIndex = (DirectionResultsIndex + 1) % len(DirectionResults)
bidi.DefaultDirection(arg0)
case *NgoloFuzzOne_OrderingNgdotDirection:
if len(OrderingResults) == 0 {
continue
}
arg0 := OrderingResults[OrderingResultsIndex]
OrderingResultsIndex = (OrderingResultsIndex + 1) % len(OrderingResults)
r0 := arg0.Direction()
DirectionResults = append(DirectionResults, &r0)
case *NgoloFuzzOne_OrderingNgdotNumRuns:
if len(OrderingResults) == 0 {
continue
}
arg0 := OrderingResults[OrderingResultsIndex]
OrderingResultsIndex = (OrderingResultsIndex + 1) % len(OrderingResults)
arg0.NumRuns()
case *NgoloFuzzOne_OrderingNgdotRun:
if len(OrderingResults) == 0 {
continue
}
arg0 := OrderingResults[OrderingResultsIndex]
OrderingResultsIndex = (OrderingResultsIndex + 1) % len(OrderingResults)
arg1 := int(a.OrderingNgdotRun.I)
r0 := arg0.Run(arg1)
RunResults = append(RunResults, &r0)
case *NgoloFuzzOne_RunNgdotString:
if len(RunResults) == 0 {
continue
}
arg0 := RunResults[RunResultsIndex]
RunResultsIndex = (RunResultsIndex + 1) % len(RunResults)
arg0.String()
case *NgoloFuzzOne_RunNgdotBytes:
if len(RunResults) == 0 {
continue
}
arg0 := RunResults[RunResultsIndex]
RunResultsIndex = (RunResultsIndex + 1) % len(RunResults)
arg0.Bytes()
case *NgoloFuzzOne_RunNgdotDirection:
if len(RunResults) == 0 {
continue
}
arg0 := RunResults[RunResultsIndex]
RunResultsIndex = (RunResultsIndex + 1) % len(RunResults)
r0 := arg0.Direction()
DirectionResults = append(DirectionResults, &r0)
case *NgoloFuzzOne_RunNgdotPos:
if len(RunResults) == 0 {
continue
}
arg0 := RunResults[RunResultsIndex]
RunResultsIndex = (RunResultsIndex + 1) % len(RunResults)
arg0.Pos()
case *NgoloFuzzOne_AppendReverse:
bidi.AppendReverse(a.AppendReverse.Out, a.AppendReverse.In)
case *NgoloFuzzOne_ReverseString:
bidi.ReverseString(a.ReverseString.S)
case *NgoloFuzzOne_PropertiesNgdotClass:
if len(PropertiesResults) == 0 {
continue
}
arg0 := PropertiesResults[PropertiesResultsIndex]
PropertiesResultsIndex = (PropertiesResultsIndex + 1) % len(PropertiesResults)
arg0.Class()
case *NgoloFuzzOne_PropertiesNgdotIsBracket:
if len(PropertiesResults) == 0 {
continue
}
arg0 := PropertiesResults[PropertiesResultsIndex]
PropertiesResultsIndex = (PropertiesResultsIndex + 1) % len(PropertiesResults)
arg0.IsBracket()
case *NgoloFuzzOne_PropertiesNgdotIsOpeningBracket:
if len(PropertiesResults) == 0 {
continue
}
arg0 := PropertiesResults[PropertiesResultsIndex]
PropertiesResultsIndex = (PropertiesResultsIndex + 1) % len(PropertiesResults)
arg0.IsOpeningBracket()
case *NgoloFuzzOne_LookupRune:
arg0 := GetRune(a.LookupRune.R)
r0, _ := bidi.LookupRune(arg0)
PropertiesResults = append(PropertiesResults, &r0)
case *NgoloFuzzOne_Lookup:
r0, _ := bidi.Lookup(a.Lookup.S)
PropertiesResults = append(PropertiesResults, &r0)
case *NgoloFuzzOne_LookupString:
r0, _ := bidi.LookupString(a.LookupString.S)
PropertiesResults = append(PropertiesResults, &r0)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
OrderingNb := 0
OrderingResultsIndex := 0
RunNb := 0
RunResultsIndex := 0
PropertiesNb := 0
PropertiesResultsIndex := 0
DirectionNb := 0
DirectionResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_DefaultDirection:
if DirectionNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("bidi.DefaultDirection(Direction%d)\n", (DirectionResultsIndex + 0) % DirectionNb))
DirectionResultsIndex = (DirectionResultsIndex + 1) % DirectionNb
case *NgoloFuzzOne_OrderingNgdotDirection:
if OrderingNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Direction%d := Ordering%d.Direction()\n", DirectionNb, OrderingResultsIndex))
DirectionNb = DirectionNb + 1
OrderingResultsIndex = (OrderingResultsIndex + 1) % OrderingNb
case *NgoloFuzzOne_OrderingNgdotNumRuns:
if OrderingNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Ordering%d.NumRuns()\n", OrderingResultsIndex))
OrderingResultsIndex = (OrderingResultsIndex + 1) % OrderingNb
case *NgoloFuzzOne_OrderingNgdotRun:
if OrderingNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Run%d := Ordering%d.Run(int(%#+v))\n", RunNb, OrderingResultsIndex, a.OrderingNgdotRun.I))
RunNb = RunNb + 1
OrderingResultsIndex = (OrderingResultsIndex + 1) % OrderingNb
case *NgoloFuzzOne_RunNgdotString:
if RunNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Run%d.String()\n", RunResultsIndex))
RunResultsIndex = (RunResultsIndex + 1) % RunNb
case *NgoloFuzzOne_RunNgdotBytes:
if RunNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Run%d.Bytes()\n", RunResultsIndex))
RunResultsIndex = (RunResultsIndex + 1) % RunNb
case *NgoloFuzzOne_RunNgdotDirection:
if RunNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Direction%d := Run%d.Direction()\n", DirectionNb, RunResultsIndex))
DirectionNb = DirectionNb + 1
RunResultsIndex = (RunResultsIndex + 1) % RunNb
case *NgoloFuzzOne_RunNgdotPos:
if RunNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Run%d.Pos()\n", RunResultsIndex))
RunResultsIndex = (RunResultsIndex + 1) % RunNb
case *NgoloFuzzOne_AppendReverse:
w.WriteString(fmt.Sprintf("bidi.AppendReverse(%#+v, %#+v)\n", a.AppendReverse.Out, a.AppendReverse.In))
case *NgoloFuzzOne_ReverseString:
w.WriteString(fmt.Sprintf("bidi.ReverseString(%#+v)\n", a.ReverseString.S))
case *NgoloFuzzOne_PropertiesNgdotClass:
if PropertiesNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Properties%d.Class()\n", PropertiesResultsIndex))
PropertiesResultsIndex = (PropertiesResultsIndex + 1) % PropertiesNb
case *NgoloFuzzOne_PropertiesNgdotIsBracket:
if PropertiesNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Properties%d.IsBracket()\n", PropertiesResultsIndex))
PropertiesResultsIndex = (PropertiesResultsIndex + 1) % PropertiesNb
case *NgoloFuzzOne_PropertiesNgdotIsOpeningBracket:
if PropertiesNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Properties%d.IsOpeningBracket()\n", PropertiesResultsIndex))
PropertiesResultsIndex = (PropertiesResultsIndex + 1) % PropertiesNb
case *NgoloFuzzOne_LookupRune:
w.WriteString(fmt.Sprintf("Properties%d, _ := bidi.LookupRune(GetRune(%#+v))\n", PropertiesNb, a.LookupRune.R))
PropertiesNb = PropertiesNb + 1
case *NgoloFuzzOne_Lookup:
w.WriteString(fmt.Sprintf("Properties%d, _ := bidi.Lookup(%#+v)\n", PropertiesNb, a.Lookup.S))
PropertiesNb = PropertiesNb + 1
case *NgoloFuzzOne_LookupString:
w.WriteString(fmt.Sprintf("Properties%d, _ := bidi.LookupString(%#+v)\n", PropertiesNb, a.LookupString.S))
PropertiesNb = PropertiesNb + 1
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_text_unicode_bidi
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type DefaultDirectionArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DefaultDirectionArgs) Reset() {
*x = DefaultDirectionArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DefaultDirectionArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DefaultDirectionArgs) ProtoMessage() {}
func (x *DefaultDirectionArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DefaultDirectionArgs.ProtoReflect.Descriptor instead.
func (*DefaultDirectionArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type OrderingNgdotDirectionArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *OrderingNgdotDirectionArgs) Reset() {
*x = OrderingNgdotDirectionArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *OrderingNgdotDirectionArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*OrderingNgdotDirectionArgs) ProtoMessage() {}
func (x *OrderingNgdotDirectionArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use OrderingNgdotDirectionArgs.ProtoReflect.Descriptor instead.
func (*OrderingNgdotDirectionArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
type OrderingNgdotNumRunsArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *OrderingNgdotNumRunsArgs) Reset() {
*x = OrderingNgdotNumRunsArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *OrderingNgdotNumRunsArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*OrderingNgdotNumRunsArgs) ProtoMessage() {}
func (x *OrderingNgdotNumRunsArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use OrderingNgdotNumRunsArgs.ProtoReflect.Descriptor instead.
func (*OrderingNgdotNumRunsArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
type OrderingNgdotRunArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
I int64 `protobuf:"varint,1,opt,name=i,proto3" json:"i,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *OrderingNgdotRunArgs) Reset() {
*x = OrderingNgdotRunArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *OrderingNgdotRunArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*OrderingNgdotRunArgs) ProtoMessage() {}
func (x *OrderingNgdotRunArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use OrderingNgdotRunArgs.ProtoReflect.Descriptor instead.
func (*OrderingNgdotRunArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *OrderingNgdotRunArgs) GetI() int64 {
if x != nil {
return x.I
}
return 0
}
type RunNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RunNgdotStringArgs) Reset() {
*x = RunNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RunNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RunNgdotStringArgs) ProtoMessage() {}
func (x *RunNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RunNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*RunNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
type RunNgdotBytesArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RunNgdotBytesArgs) Reset() {
*x = RunNgdotBytesArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RunNgdotBytesArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RunNgdotBytesArgs) ProtoMessage() {}
func (x *RunNgdotBytesArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RunNgdotBytesArgs.ProtoReflect.Descriptor instead.
func (*RunNgdotBytesArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
type RunNgdotDirectionArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RunNgdotDirectionArgs) Reset() {
*x = RunNgdotDirectionArgs{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RunNgdotDirectionArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RunNgdotDirectionArgs) ProtoMessage() {}
func (x *RunNgdotDirectionArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RunNgdotDirectionArgs.ProtoReflect.Descriptor instead.
func (*RunNgdotDirectionArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
type RunNgdotPosArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RunNgdotPosArgs) Reset() {
*x = RunNgdotPosArgs{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RunNgdotPosArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RunNgdotPosArgs) ProtoMessage() {}
func (x *RunNgdotPosArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RunNgdotPosArgs.ProtoReflect.Descriptor instead.
func (*RunNgdotPosArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
type AppendReverseArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Out []byte `protobuf:"bytes,1,opt,name=out,proto3" json:"out,omitempty"`
In []byte `protobuf:"bytes,2,opt,name=in,proto3" json:"in,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *AppendReverseArgs) Reset() {
*x = AppendReverseArgs{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AppendReverseArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AppendReverseArgs) ProtoMessage() {}
func (x *AppendReverseArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AppendReverseArgs.ProtoReflect.Descriptor instead.
func (*AppendReverseArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
func (x *AppendReverseArgs) GetOut() []byte {
if x != nil {
return x.Out
}
return nil
}
func (x *AppendReverseArgs) GetIn() []byte {
if x != nil {
return x.In
}
return nil
}
type ReverseStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S string `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ReverseStringArgs) Reset() {
*x = ReverseStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ReverseStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReverseStringArgs) ProtoMessage() {}
func (x *ReverseStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReverseStringArgs.ProtoReflect.Descriptor instead.
func (*ReverseStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
func (x *ReverseStringArgs) GetS() string {
if x != nil {
return x.S
}
return ""
}
type PropertiesNgdotClassArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PropertiesNgdotClassArgs) Reset() {
*x = PropertiesNgdotClassArgs{}
mi := &file_ngolofuzz_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PropertiesNgdotClassArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PropertiesNgdotClassArgs) ProtoMessage() {}
func (x *PropertiesNgdotClassArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PropertiesNgdotClassArgs.ProtoReflect.Descriptor instead.
func (*PropertiesNgdotClassArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{10}
}
type PropertiesNgdotIsBracketArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PropertiesNgdotIsBracketArgs) Reset() {
*x = PropertiesNgdotIsBracketArgs{}
mi := &file_ngolofuzz_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PropertiesNgdotIsBracketArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PropertiesNgdotIsBracketArgs) ProtoMessage() {}
func (x *PropertiesNgdotIsBracketArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[11]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PropertiesNgdotIsBracketArgs.ProtoReflect.Descriptor instead.
func (*PropertiesNgdotIsBracketArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{11}
}
type PropertiesNgdotIsOpeningBracketArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PropertiesNgdotIsOpeningBracketArgs) Reset() {
*x = PropertiesNgdotIsOpeningBracketArgs{}
mi := &file_ngolofuzz_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PropertiesNgdotIsOpeningBracketArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PropertiesNgdotIsOpeningBracketArgs) ProtoMessage() {}
func (x *PropertiesNgdotIsOpeningBracketArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[12]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PropertiesNgdotIsOpeningBracketArgs.ProtoReflect.Descriptor instead.
func (*PropertiesNgdotIsOpeningBracketArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{12}
}
type LookupRuneArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R string `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *LookupRuneArgs) Reset() {
*x = LookupRuneArgs{}
mi := &file_ngolofuzz_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *LookupRuneArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*LookupRuneArgs) ProtoMessage() {}
func (x *LookupRuneArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[13]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use LookupRuneArgs.ProtoReflect.Descriptor instead.
func (*LookupRuneArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{13}
}
func (x *LookupRuneArgs) GetR() string {
if x != nil {
return x.R
}
return ""
}
type LookupArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S []byte `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *LookupArgs) Reset() {
*x = LookupArgs{}
mi := &file_ngolofuzz_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *LookupArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*LookupArgs) ProtoMessage() {}
func (x *LookupArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[14]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use LookupArgs.ProtoReflect.Descriptor instead.
func (*LookupArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{14}
}
func (x *LookupArgs) GetS() []byte {
if x != nil {
return x.S
}
return nil
}
type LookupStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S string `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *LookupStringArgs) Reset() {
*x = LookupStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *LookupStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*LookupStringArgs) ProtoMessage() {}
func (x *LookupStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[15]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use LookupStringArgs.ProtoReflect.Descriptor instead.
func (*LookupStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{15}
}
func (x *LookupStringArgs) GetS() string {
if x != nil {
return x.S
}
return ""
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_DefaultDirection
// *NgoloFuzzOne_OrderingNgdotDirection
// *NgoloFuzzOne_OrderingNgdotNumRuns
// *NgoloFuzzOne_OrderingNgdotRun
// *NgoloFuzzOne_RunNgdotString
// *NgoloFuzzOne_RunNgdotBytes
// *NgoloFuzzOne_RunNgdotDirection
// *NgoloFuzzOne_RunNgdotPos
// *NgoloFuzzOne_AppendReverse
// *NgoloFuzzOne_ReverseString
// *NgoloFuzzOne_PropertiesNgdotClass
// *NgoloFuzzOne_PropertiesNgdotIsBracket
// *NgoloFuzzOne_PropertiesNgdotIsOpeningBracket
// *NgoloFuzzOne_LookupRune
// *NgoloFuzzOne_Lookup
// *NgoloFuzzOne_LookupString
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[16]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{16}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetDefaultDirection() *DefaultDirectionArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_DefaultDirection); ok {
return x.DefaultDirection
}
}
return nil
}
func (x *NgoloFuzzOne) GetOrderingNgdotDirection() *OrderingNgdotDirectionArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_OrderingNgdotDirection); ok {
return x.OrderingNgdotDirection
}
}
return nil
}
func (x *NgoloFuzzOne) GetOrderingNgdotNumRuns() *OrderingNgdotNumRunsArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_OrderingNgdotNumRuns); ok {
return x.OrderingNgdotNumRuns
}
}
return nil
}
func (x *NgoloFuzzOne) GetOrderingNgdotRun() *OrderingNgdotRunArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_OrderingNgdotRun); ok {
return x.OrderingNgdotRun
}
}
return nil
}
func (x *NgoloFuzzOne) GetRunNgdotString() *RunNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_RunNgdotString); ok {
return x.RunNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetRunNgdotBytes() *RunNgdotBytesArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_RunNgdotBytes); ok {
return x.RunNgdotBytes
}
}
return nil
}
func (x *NgoloFuzzOne) GetRunNgdotDirection() *RunNgdotDirectionArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_RunNgdotDirection); ok {
return x.RunNgdotDirection
}
}
return nil
}
func (x *NgoloFuzzOne) GetRunNgdotPos() *RunNgdotPosArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_RunNgdotPos); ok {
return x.RunNgdotPos
}
}
return nil
}
func (x *NgoloFuzzOne) GetAppendReverse() *AppendReverseArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_AppendReverse); ok {
return x.AppendReverse
}
}
return nil
}
func (x *NgoloFuzzOne) GetReverseString() *ReverseStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ReverseString); ok {
return x.ReverseString
}
}
return nil
}
func (x *NgoloFuzzOne) GetPropertiesNgdotClass() *PropertiesNgdotClassArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_PropertiesNgdotClass); ok {
return x.PropertiesNgdotClass
}
}
return nil
}
func (x *NgoloFuzzOne) GetPropertiesNgdotIsBracket() *PropertiesNgdotIsBracketArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_PropertiesNgdotIsBracket); ok {
return x.PropertiesNgdotIsBracket
}
}
return nil
}
func (x *NgoloFuzzOne) GetPropertiesNgdotIsOpeningBracket() *PropertiesNgdotIsOpeningBracketArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_PropertiesNgdotIsOpeningBracket); ok {
return x.PropertiesNgdotIsOpeningBracket
}
}
return nil
}
func (x *NgoloFuzzOne) GetLookupRune() *LookupRuneArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_LookupRune); ok {
return x.LookupRune
}
}
return nil
}
func (x *NgoloFuzzOne) GetLookup() *LookupArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Lookup); ok {
return x.Lookup
}
}
return nil
}
func (x *NgoloFuzzOne) GetLookupString() *LookupStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_LookupString); ok {
return x.LookupString
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_DefaultDirection struct {
DefaultDirection *DefaultDirectionArgs `protobuf:"bytes,1,opt,name=DefaultDirection,proto3,oneof"`
}
type NgoloFuzzOne_OrderingNgdotDirection struct {
OrderingNgdotDirection *OrderingNgdotDirectionArgs `protobuf:"bytes,2,opt,name=OrderingNgdotDirection,proto3,oneof"`
}
type NgoloFuzzOne_OrderingNgdotNumRuns struct {
OrderingNgdotNumRuns *OrderingNgdotNumRunsArgs `protobuf:"bytes,3,opt,name=OrderingNgdotNumRuns,proto3,oneof"`
}
type NgoloFuzzOne_OrderingNgdotRun struct {
OrderingNgdotRun *OrderingNgdotRunArgs `protobuf:"bytes,4,opt,name=OrderingNgdotRun,proto3,oneof"`
}
type NgoloFuzzOne_RunNgdotString struct {
RunNgdotString *RunNgdotStringArgs `protobuf:"bytes,5,opt,name=RunNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_RunNgdotBytes struct {
RunNgdotBytes *RunNgdotBytesArgs `protobuf:"bytes,6,opt,name=RunNgdotBytes,proto3,oneof"`
}
type NgoloFuzzOne_RunNgdotDirection struct {
RunNgdotDirection *RunNgdotDirectionArgs `protobuf:"bytes,7,opt,name=RunNgdotDirection,proto3,oneof"`
}
type NgoloFuzzOne_RunNgdotPos struct {
RunNgdotPos *RunNgdotPosArgs `protobuf:"bytes,8,opt,name=RunNgdotPos,proto3,oneof"`
}
type NgoloFuzzOne_AppendReverse struct {
AppendReverse *AppendReverseArgs `protobuf:"bytes,9,opt,name=AppendReverse,proto3,oneof"`
}
type NgoloFuzzOne_ReverseString struct {
ReverseString *ReverseStringArgs `protobuf:"bytes,10,opt,name=ReverseString,proto3,oneof"`
}
type NgoloFuzzOne_PropertiesNgdotClass struct {
PropertiesNgdotClass *PropertiesNgdotClassArgs `protobuf:"bytes,11,opt,name=PropertiesNgdotClass,proto3,oneof"`
}
type NgoloFuzzOne_PropertiesNgdotIsBracket struct {
PropertiesNgdotIsBracket *PropertiesNgdotIsBracketArgs `protobuf:"bytes,12,opt,name=PropertiesNgdotIsBracket,proto3,oneof"`
}
type NgoloFuzzOne_PropertiesNgdotIsOpeningBracket struct {
PropertiesNgdotIsOpeningBracket *PropertiesNgdotIsOpeningBracketArgs `protobuf:"bytes,13,opt,name=PropertiesNgdotIsOpeningBracket,proto3,oneof"`
}
type NgoloFuzzOne_LookupRune struct {
LookupRune *LookupRuneArgs `protobuf:"bytes,14,opt,name=LookupRune,proto3,oneof"`
}
type NgoloFuzzOne_Lookup struct {
Lookup *LookupArgs `protobuf:"bytes,15,opt,name=Lookup,proto3,oneof"`
}
type NgoloFuzzOne_LookupString struct {
LookupString *LookupStringArgs `protobuf:"bytes,16,opt,name=LookupString,proto3,oneof"`
}
func (*NgoloFuzzOne_DefaultDirection) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_OrderingNgdotDirection) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_OrderingNgdotNumRuns) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_OrderingNgdotRun) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_RunNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_RunNgdotBytes) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_RunNgdotDirection) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_RunNgdotPos) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_AppendReverse) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ReverseString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_PropertiesNgdotClass) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_PropertiesNgdotIsBracket) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_PropertiesNgdotIsOpeningBracket) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_LookupRune) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Lookup) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_LookupString) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[17]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{17}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[18]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{18}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x16\n" +
"\x14DefaultDirectionArgs\"\x1c\n" +
"\x1aOrderingNgdotDirectionArgs\"\x1a\n" +
"\x18OrderingNgdotNumRunsArgs\"$\n" +
"\x14OrderingNgdotRunArgs\x12\f\n" +
"\x01i\x18\x01 \x01(\x03R\x01i\"\x14\n" +
"\x12RunNgdotStringArgs\"\x13\n" +
"\x11RunNgdotBytesArgs\"\x17\n" +
"\x15RunNgdotDirectionArgs\"\x11\n" +
"\x0fRunNgdotPosArgs\"5\n" +
"\x11AppendReverseArgs\x12\x10\n" +
"\x03out\x18\x01 \x01(\fR\x03out\x12\x0e\n" +
"\x02in\x18\x02 \x01(\fR\x02in\"!\n" +
"\x11ReverseStringArgs\x12\f\n" +
"\x01s\x18\x01 \x01(\tR\x01s\"\x1a\n" +
"\x18PropertiesNgdotClassArgs\"\x1e\n" +
"\x1cPropertiesNgdotIsBracketArgs\"%\n" +
"#PropertiesNgdotIsOpeningBracketArgs\"\x1e\n" +
"\x0eLookupRuneArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\tR\x01r\"\x1a\n" +
"\n" +
"LookupArgs\x12\f\n" +
"\x01s\x18\x01 \x01(\fR\x01s\" \n" +
"\x10LookupStringArgs\x12\f\n" +
"\x01s\x18\x01 \x01(\tR\x01s\"\x8c\n" +
"\n" +
"\fNgoloFuzzOne\x12M\n" +
"\x10DefaultDirection\x18\x01 \x01(\v2\x1f.ngolofuzz.DefaultDirectionArgsH\x00R\x10DefaultDirection\x12_\n" +
"\x16OrderingNgdotDirection\x18\x02 \x01(\v2%.ngolofuzz.OrderingNgdotDirectionArgsH\x00R\x16OrderingNgdotDirection\x12Y\n" +
"\x14OrderingNgdotNumRuns\x18\x03 \x01(\v2#.ngolofuzz.OrderingNgdotNumRunsArgsH\x00R\x14OrderingNgdotNumRuns\x12M\n" +
"\x10OrderingNgdotRun\x18\x04 \x01(\v2\x1f.ngolofuzz.OrderingNgdotRunArgsH\x00R\x10OrderingNgdotRun\x12G\n" +
"\x0eRunNgdotString\x18\x05 \x01(\v2\x1d.ngolofuzz.RunNgdotStringArgsH\x00R\x0eRunNgdotString\x12D\n" +
"\rRunNgdotBytes\x18\x06 \x01(\v2\x1c.ngolofuzz.RunNgdotBytesArgsH\x00R\rRunNgdotBytes\x12P\n" +
"\x11RunNgdotDirection\x18\a \x01(\v2 .ngolofuzz.RunNgdotDirectionArgsH\x00R\x11RunNgdotDirection\x12>\n" +
"\vRunNgdotPos\x18\b \x01(\v2\x1a.ngolofuzz.RunNgdotPosArgsH\x00R\vRunNgdotPos\x12D\n" +
"\rAppendReverse\x18\t \x01(\v2\x1c.ngolofuzz.AppendReverseArgsH\x00R\rAppendReverse\x12D\n" +
"\rReverseString\x18\n" +
" \x01(\v2\x1c.ngolofuzz.ReverseStringArgsH\x00R\rReverseString\x12Y\n" +
"\x14PropertiesNgdotClass\x18\v \x01(\v2#.ngolofuzz.PropertiesNgdotClassArgsH\x00R\x14PropertiesNgdotClass\x12e\n" +
"\x18PropertiesNgdotIsBracket\x18\f \x01(\v2'.ngolofuzz.PropertiesNgdotIsBracketArgsH\x00R\x18PropertiesNgdotIsBracket\x12z\n" +
"\x1fPropertiesNgdotIsOpeningBracket\x18\r \x01(\v2..ngolofuzz.PropertiesNgdotIsOpeningBracketArgsH\x00R\x1fPropertiesNgdotIsOpeningBracket\x12;\n" +
"\n" +
"LookupRune\x18\x0e \x01(\v2\x19.ngolofuzz.LookupRuneArgsH\x00R\n" +
"LookupRune\x12/\n" +
"\x06Lookup\x18\x0f \x01(\v2\x15.ngolofuzz.LookupArgsH\x00R\x06Lookup\x12A\n" +
"\fLookupString\x18\x10 \x01(\v2\x1b.ngolofuzz.LookupStringArgsH\x00R\fLookupStringB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB Z\x1e./;fuzz_ng_x_text_unicode_bidib\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 19)
var file_ngolofuzz_proto_goTypes = []any{
(*DefaultDirectionArgs)(nil), // 0: ngolofuzz.DefaultDirectionArgs
(*OrderingNgdotDirectionArgs)(nil), // 1: ngolofuzz.OrderingNgdotDirectionArgs
(*OrderingNgdotNumRunsArgs)(nil), // 2: ngolofuzz.OrderingNgdotNumRunsArgs
(*OrderingNgdotRunArgs)(nil), // 3: ngolofuzz.OrderingNgdotRunArgs
(*RunNgdotStringArgs)(nil), // 4: ngolofuzz.RunNgdotStringArgs
(*RunNgdotBytesArgs)(nil), // 5: ngolofuzz.RunNgdotBytesArgs
(*RunNgdotDirectionArgs)(nil), // 6: ngolofuzz.RunNgdotDirectionArgs
(*RunNgdotPosArgs)(nil), // 7: ngolofuzz.RunNgdotPosArgs
(*AppendReverseArgs)(nil), // 8: ngolofuzz.AppendReverseArgs
(*ReverseStringArgs)(nil), // 9: ngolofuzz.ReverseStringArgs
(*PropertiesNgdotClassArgs)(nil), // 10: ngolofuzz.PropertiesNgdotClassArgs
(*PropertiesNgdotIsBracketArgs)(nil), // 11: ngolofuzz.PropertiesNgdotIsBracketArgs
(*PropertiesNgdotIsOpeningBracketArgs)(nil), // 12: ngolofuzz.PropertiesNgdotIsOpeningBracketArgs
(*LookupRuneArgs)(nil), // 13: ngolofuzz.LookupRuneArgs
(*LookupArgs)(nil), // 14: ngolofuzz.LookupArgs
(*LookupStringArgs)(nil), // 15: ngolofuzz.LookupStringArgs
(*NgoloFuzzOne)(nil), // 16: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 17: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 18: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.DefaultDirection:type_name -> ngolofuzz.DefaultDirectionArgs
1, // 1: ngolofuzz.NgoloFuzzOne.OrderingNgdotDirection:type_name -> ngolofuzz.OrderingNgdotDirectionArgs
2, // 2: ngolofuzz.NgoloFuzzOne.OrderingNgdotNumRuns:type_name -> ngolofuzz.OrderingNgdotNumRunsArgs
3, // 3: ngolofuzz.NgoloFuzzOne.OrderingNgdotRun:type_name -> ngolofuzz.OrderingNgdotRunArgs
4, // 4: ngolofuzz.NgoloFuzzOne.RunNgdotString:type_name -> ngolofuzz.RunNgdotStringArgs
5, // 5: ngolofuzz.NgoloFuzzOne.RunNgdotBytes:type_name -> ngolofuzz.RunNgdotBytesArgs
6, // 6: ngolofuzz.NgoloFuzzOne.RunNgdotDirection:type_name -> ngolofuzz.RunNgdotDirectionArgs
7, // 7: ngolofuzz.NgoloFuzzOne.RunNgdotPos:type_name -> ngolofuzz.RunNgdotPosArgs
8, // 8: ngolofuzz.NgoloFuzzOne.AppendReverse:type_name -> ngolofuzz.AppendReverseArgs
9, // 9: ngolofuzz.NgoloFuzzOne.ReverseString:type_name -> ngolofuzz.ReverseStringArgs
10, // 10: ngolofuzz.NgoloFuzzOne.PropertiesNgdotClass:type_name -> ngolofuzz.PropertiesNgdotClassArgs
11, // 11: ngolofuzz.NgoloFuzzOne.PropertiesNgdotIsBracket:type_name -> ngolofuzz.PropertiesNgdotIsBracketArgs
12, // 12: ngolofuzz.NgoloFuzzOne.PropertiesNgdotIsOpeningBracket:type_name -> ngolofuzz.PropertiesNgdotIsOpeningBracketArgs
13, // 13: ngolofuzz.NgoloFuzzOne.LookupRune:type_name -> ngolofuzz.LookupRuneArgs
14, // 14: ngolofuzz.NgoloFuzzOne.Lookup:type_name -> ngolofuzz.LookupArgs
15, // 15: ngolofuzz.NgoloFuzzOne.LookupString:type_name -> ngolofuzz.LookupStringArgs
16, // 16: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
17, // [17:17] is the sub-list for method output_type
17, // [17:17] is the sub-list for method input_type
17, // [17:17] is the sub-list for extension type_name
17, // [17:17] is the sub-list for extension extendee
0, // [0:17] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[16].OneofWrappers = []any{
(*NgoloFuzzOne_DefaultDirection)(nil),
(*NgoloFuzzOne_OrderingNgdotDirection)(nil),
(*NgoloFuzzOne_OrderingNgdotNumRuns)(nil),
(*NgoloFuzzOne_OrderingNgdotRun)(nil),
(*NgoloFuzzOne_RunNgdotString)(nil),
(*NgoloFuzzOne_RunNgdotBytes)(nil),
(*NgoloFuzzOne_RunNgdotDirection)(nil),
(*NgoloFuzzOne_RunNgdotPos)(nil),
(*NgoloFuzzOne_AppendReverse)(nil),
(*NgoloFuzzOne_ReverseString)(nil),
(*NgoloFuzzOne_PropertiesNgdotClass)(nil),
(*NgoloFuzzOne_PropertiesNgdotIsBracket)(nil),
(*NgoloFuzzOne_PropertiesNgdotIsOpeningBracket)(nil),
(*NgoloFuzzOne_LookupRune)(nil),
(*NgoloFuzzOne_Lookup)(nil),
(*NgoloFuzzOne_LookupString)(nil),
}
file_ngolofuzz_proto_msgTypes[17].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 19,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_text_unicode_cldr
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/text/unicode/cldr"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var ElemResults []*cldr.Elem
ElemResultsIndex := 0
var CLDRResults []*cldr.CLDR
CLDRResultsIndex := 0
var SliceResults []*cldr.Slice
SliceResultsIndex := 0
var CommonResults []*cldr.Common
CommonResultsIndex := 0
var DraftResults []*cldr.Draft
DraftResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_CommonNgdotDefault:
if len(CommonResults) == 0 {
continue
}
arg0 := CommonResults[CommonResultsIndex]
CommonResultsIndex = (CommonResultsIndex + 1) % len(CommonResults)
arg0.Default()
case *NgoloFuzzOne_CommonNgdotElement:
if len(CommonResults) == 0 {
continue
}
arg0 := CommonResults[CommonResultsIndex]
CommonResultsIndex = (CommonResultsIndex + 1) % len(CommonResults)
arg0.Element()
case *NgoloFuzzOne_CommonNgdotGetCommon:
if len(CommonResults) == 0 {
continue
}
arg0 := CommonResults[CommonResultsIndex]
CommonResultsIndex = (CommonResultsIndex + 1) % len(CommonResults)
arg0.GetCommon()
case *NgoloFuzzOne_CommonNgdotData:
if len(CommonResults) == 0 {
continue
}
arg0 := CommonResults[CommonResultsIndex]
CommonResultsIndex = (CommonResultsIndex + 1) % len(CommonResults)
arg0.Data()
case *NgoloFuzzOne_CLDRNgdotBCP47:
if len(CLDRResults) == 0 {
continue
}
arg0 := CLDRResults[CLDRResultsIndex]
CLDRResultsIndex = (CLDRResultsIndex + 1) % len(CLDRResults)
arg0.BCP47()
case *NgoloFuzzOne_ParseDraft:
r0, r1 := cldr.ParseDraft(a.ParseDraft.Level)
DraftResults = append(DraftResults, &r0)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_DraftNgdotString:
if len(DraftResults) == 0 {
continue
}
arg0 := DraftResults[DraftResultsIndex]
DraftResultsIndex = (DraftResultsIndex + 1) % len(DraftResults)
arg0.String()
case *NgoloFuzzOne_CLDRNgdotSetDraftLevel:
if len(CLDRResults) == 0 {
continue
}
arg0 := CLDRResults[CLDRResultsIndex]
CLDRResultsIndex = (CLDRResultsIndex + 1) % len(CLDRResults)
if len(DraftResults) == 0 {
continue
}
arg1 := *DraftResults[DraftResultsIndex]
DraftResultsIndex = (DraftResultsIndex + 1) % len(DraftResults)
arg0.SetDraftLevel(arg1, a.CLDRNgdotSetDraftLevel.PreferDraft)
case *NgoloFuzzOne_CLDRNgdotRawLDML:
if len(CLDRResults) == 0 {
continue
}
arg0 := CLDRResults[CLDRResultsIndex]
CLDRResultsIndex = (CLDRResultsIndex + 1) % len(CLDRResults)
arg0.RawLDML(a.CLDRNgdotRawLDML.Loc)
case *NgoloFuzzOne_CLDRNgdotLDML:
if len(CLDRResults) == 0 {
continue
}
arg0 := CLDRResults[CLDRResultsIndex]
CLDRResultsIndex = (CLDRResultsIndex + 1) % len(CLDRResults)
_, r1 := arg0.LDML(a.CLDRNgdotLDML.Loc)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_CLDRNgdotSupplemental:
if len(CLDRResults) == 0 {
continue
}
arg0 := CLDRResults[CLDRResultsIndex]
CLDRResultsIndex = (CLDRResultsIndex + 1) % len(CLDRResults)
arg0.Supplemental()
case *NgoloFuzzOne_CLDRNgdotLocales:
if len(CLDRResults) == 0 {
continue
}
arg0 := CLDRResults[CLDRResultsIndex]
CLDRResultsIndex = (CLDRResultsIndex + 1) % len(CLDRResults)
arg0.Locales()
case *NgoloFuzzOne_Get:
if len(ElemResults) == 0 {
continue
}
arg0 := *ElemResults[ElemResultsIndex]
ElemResultsIndex = (ElemResultsIndex + 1) % len(ElemResults)
r0, r1 := cldr.Get(arg0, a.Get.Path)
ElemResults = append(ElemResults, &r0)
if r1 != nil{
r1.Error()
return 0
}
case *NgoloFuzzOne_SliceNgdotValue:
if len(SliceResults) == 0 {
continue
}
arg0 := SliceResults[SliceResultsIndex]
SliceResultsIndex = (SliceResultsIndex + 1) % len(SliceResults)
arg0.Value()
case *NgoloFuzzOne_MakeSlice:
r0 := cldr.MakeSlice(a.MakeSlice.SlicePtr)
SliceResults = append(SliceResults, &r0)
case *NgoloFuzzOne_SliceNgdotSelectOnePerGroup:
if len(SliceResults) == 0 {
continue
}
arg0 := SliceResults[SliceResultsIndex]
SliceResultsIndex = (SliceResultsIndex + 1) % len(SliceResults)
arg0.SelectOnePerGroup(a.SliceNgdotSelectOnePerGroup.A, a.SliceNgdotSelectOnePerGroup.V)
case *NgoloFuzzOne_SliceNgdotSelectDraft:
if len(SliceResults) == 0 {
continue
}
arg0 := SliceResults[SliceResultsIndex]
SliceResultsIndex = (SliceResultsIndex + 1) % len(SliceResults)
if len(DraftResults) == 0 {
continue
}
arg1 := *DraftResults[DraftResultsIndex]
DraftResultsIndex = (DraftResultsIndex + 1) % len(DraftResults)
arg0.SelectDraft(arg1)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
ElemNb := 0
ElemResultsIndex := 0
CLDRNb := 0
CLDRResultsIndex := 0
SliceNb := 0
SliceResultsIndex := 0
CommonNb := 0
CommonResultsIndex := 0
DraftNb := 0
DraftResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_CommonNgdotDefault:
if CommonNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Common%d.Default()\n", CommonResultsIndex))
CommonResultsIndex = (CommonResultsIndex + 1) % CommonNb
case *NgoloFuzzOne_CommonNgdotElement:
if CommonNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Common%d.Element()\n", CommonResultsIndex))
CommonResultsIndex = (CommonResultsIndex + 1) % CommonNb
case *NgoloFuzzOne_CommonNgdotGetCommon:
if CommonNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Common%d.GetCommon()\n", CommonResultsIndex))
CommonResultsIndex = (CommonResultsIndex + 1) % CommonNb
case *NgoloFuzzOne_CommonNgdotData:
if CommonNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Common%d.Data()\n", CommonResultsIndex))
CommonResultsIndex = (CommonResultsIndex + 1) % CommonNb
case *NgoloFuzzOne_CLDRNgdotBCP47:
if CLDRNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("CLDR%d.BCP47()\n", CLDRResultsIndex))
CLDRResultsIndex = (CLDRResultsIndex + 1) % CLDRNb
case *NgoloFuzzOne_ParseDraft:
w.WriteString(fmt.Sprintf("Draft%d, _ := cldr.ParseDraft(%#+v)\n", DraftNb, a.ParseDraft.Level))
DraftNb = DraftNb + 1
case *NgoloFuzzOne_DraftNgdotString:
if DraftNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Draft%d.String()\n", DraftResultsIndex))
DraftResultsIndex = (DraftResultsIndex + 1) % DraftNb
case *NgoloFuzzOne_CLDRNgdotSetDraftLevel:
if CLDRNb == 0 {
continue
}
if DraftNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("CLDR%d.SetDraftLevel(Draft%d, %#+v)\n", CLDRResultsIndex, (DraftResultsIndex + 0) % DraftNb, a.CLDRNgdotSetDraftLevel.PreferDraft))
CLDRResultsIndex = (CLDRResultsIndex + 1) % CLDRNb
DraftResultsIndex = (DraftResultsIndex + 1) % DraftNb
case *NgoloFuzzOne_CLDRNgdotRawLDML:
if CLDRNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("CLDR%d.RawLDML(%#+v)\n", CLDRResultsIndex, a.CLDRNgdotRawLDML.Loc))
CLDRResultsIndex = (CLDRResultsIndex + 1) % CLDRNb
case *NgoloFuzzOne_CLDRNgdotLDML:
if CLDRNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("CLDR%d.LDML(%#+v)\n", CLDRResultsIndex, a.CLDRNgdotLDML.Loc))
CLDRResultsIndex = (CLDRResultsIndex + 1) % CLDRNb
case *NgoloFuzzOne_CLDRNgdotSupplemental:
if CLDRNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("CLDR%d.Supplemental()\n", CLDRResultsIndex))
CLDRResultsIndex = (CLDRResultsIndex + 1) % CLDRNb
case *NgoloFuzzOne_CLDRNgdotLocales:
if CLDRNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("CLDR%d.Locales()\n", CLDRResultsIndex))
CLDRResultsIndex = (CLDRResultsIndex + 1) % CLDRNb
case *NgoloFuzzOne_Get:
if ElemNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Elem%d, _ := cldr.Get(Elem%d, %#+v)\n", ElemNb, (ElemResultsIndex + 0) % ElemNb, a.Get.Path))
ElemNb = ElemNb + 1
ElemResultsIndex = (ElemResultsIndex + 1) % ElemNb
case *NgoloFuzzOne_SliceNgdotValue:
if SliceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Slice%d.Value()\n", SliceResultsIndex))
SliceResultsIndex = (SliceResultsIndex + 1) % SliceNb
case *NgoloFuzzOne_MakeSlice:
w.WriteString(fmt.Sprintf("Slice%d := cldr.MakeSlice(%#+v)\n", SliceNb, a.MakeSlice.SlicePtr))
SliceNb = SliceNb + 1
case *NgoloFuzzOne_SliceNgdotSelectOnePerGroup:
if SliceNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Slice%d.SelectOnePerGroup(%#+v, %#+v)\n", SliceResultsIndex, a.SliceNgdotSelectOnePerGroup.A, a.SliceNgdotSelectOnePerGroup.V))
SliceResultsIndex = (SliceResultsIndex + 1) % SliceNb
case *NgoloFuzzOne_SliceNgdotSelectDraft:
if SliceNb == 0 {
continue
}
if DraftNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Slice%d.SelectDraft(Draft%d)\n", SliceResultsIndex, (DraftResultsIndex + 0) % DraftNb))
SliceResultsIndex = (SliceResultsIndex + 1) % SliceNb
DraftResultsIndex = (DraftResultsIndex + 1) % DraftNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_text_unicode_cldr
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type CommonNgdotDefaultArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CommonNgdotDefaultArgs) Reset() {
*x = CommonNgdotDefaultArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CommonNgdotDefaultArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CommonNgdotDefaultArgs) ProtoMessage() {}
func (x *CommonNgdotDefaultArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CommonNgdotDefaultArgs.ProtoReflect.Descriptor instead.
func (*CommonNgdotDefaultArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type CommonNgdotElementArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CommonNgdotElementArgs) Reset() {
*x = CommonNgdotElementArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CommonNgdotElementArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CommonNgdotElementArgs) ProtoMessage() {}
func (x *CommonNgdotElementArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CommonNgdotElementArgs.ProtoReflect.Descriptor instead.
func (*CommonNgdotElementArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
type CommonNgdotGetCommonArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CommonNgdotGetCommonArgs) Reset() {
*x = CommonNgdotGetCommonArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CommonNgdotGetCommonArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CommonNgdotGetCommonArgs) ProtoMessage() {}
func (x *CommonNgdotGetCommonArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CommonNgdotGetCommonArgs.ProtoReflect.Descriptor instead.
func (*CommonNgdotGetCommonArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
type CommonNgdotDataArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CommonNgdotDataArgs) Reset() {
*x = CommonNgdotDataArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CommonNgdotDataArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CommonNgdotDataArgs) ProtoMessage() {}
func (x *CommonNgdotDataArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CommonNgdotDataArgs.ProtoReflect.Descriptor instead.
func (*CommonNgdotDataArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
type CLDRNgdotBCP47Args struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CLDRNgdotBCP47Args) Reset() {
*x = CLDRNgdotBCP47Args{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CLDRNgdotBCP47Args) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CLDRNgdotBCP47Args) ProtoMessage() {}
func (x *CLDRNgdotBCP47Args) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CLDRNgdotBCP47Args.ProtoReflect.Descriptor instead.
func (*CLDRNgdotBCP47Args) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
type ParseDraftArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Level string `protobuf:"bytes,1,opt,name=level,proto3" json:"level,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ParseDraftArgs) Reset() {
*x = ParseDraftArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ParseDraftArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ParseDraftArgs) ProtoMessage() {}
func (x *ParseDraftArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ParseDraftArgs.ProtoReflect.Descriptor instead.
func (*ParseDraftArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
func (x *ParseDraftArgs) GetLevel() string {
if x != nil {
return x.Level
}
return ""
}
type DraftNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DraftNgdotStringArgs) Reset() {
*x = DraftNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DraftNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DraftNgdotStringArgs) ProtoMessage() {}
func (x *DraftNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DraftNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*DraftNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
type CLDRNgdotSetDraftLevelArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
PreferDraft bool `protobuf:"varint,1,opt,name=preferDraft,proto3" json:"preferDraft,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CLDRNgdotSetDraftLevelArgs) Reset() {
*x = CLDRNgdotSetDraftLevelArgs{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CLDRNgdotSetDraftLevelArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CLDRNgdotSetDraftLevelArgs) ProtoMessage() {}
func (x *CLDRNgdotSetDraftLevelArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CLDRNgdotSetDraftLevelArgs.ProtoReflect.Descriptor instead.
func (*CLDRNgdotSetDraftLevelArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
func (x *CLDRNgdotSetDraftLevelArgs) GetPreferDraft() bool {
if x != nil {
return x.PreferDraft
}
return false
}
type CLDRNgdotRawLDMLArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Loc string `protobuf:"bytes,1,opt,name=loc,proto3" json:"loc,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CLDRNgdotRawLDMLArgs) Reset() {
*x = CLDRNgdotRawLDMLArgs{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CLDRNgdotRawLDMLArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CLDRNgdotRawLDMLArgs) ProtoMessage() {}
func (x *CLDRNgdotRawLDMLArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CLDRNgdotRawLDMLArgs.ProtoReflect.Descriptor instead.
func (*CLDRNgdotRawLDMLArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
func (x *CLDRNgdotRawLDMLArgs) GetLoc() string {
if x != nil {
return x.Loc
}
return ""
}
type CLDRNgdotLDMLArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Loc string `protobuf:"bytes,1,opt,name=loc,proto3" json:"loc,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CLDRNgdotLDMLArgs) Reset() {
*x = CLDRNgdotLDMLArgs{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CLDRNgdotLDMLArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CLDRNgdotLDMLArgs) ProtoMessage() {}
func (x *CLDRNgdotLDMLArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CLDRNgdotLDMLArgs.ProtoReflect.Descriptor instead.
func (*CLDRNgdotLDMLArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
func (x *CLDRNgdotLDMLArgs) GetLoc() string {
if x != nil {
return x.Loc
}
return ""
}
type CLDRNgdotSupplementalArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CLDRNgdotSupplementalArgs) Reset() {
*x = CLDRNgdotSupplementalArgs{}
mi := &file_ngolofuzz_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CLDRNgdotSupplementalArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CLDRNgdotSupplementalArgs) ProtoMessage() {}
func (x *CLDRNgdotSupplementalArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CLDRNgdotSupplementalArgs.ProtoReflect.Descriptor instead.
func (*CLDRNgdotSupplementalArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{10}
}
type CLDRNgdotLocalesArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CLDRNgdotLocalesArgs) Reset() {
*x = CLDRNgdotLocalesArgs{}
mi := &file_ngolofuzz_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CLDRNgdotLocalesArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CLDRNgdotLocalesArgs) ProtoMessage() {}
func (x *CLDRNgdotLocalesArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[11]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CLDRNgdotLocalesArgs.ProtoReflect.Descriptor instead.
func (*CLDRNgdotLocalesArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{11}
}
type GetArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetArgs) Reset() {
*x = GetArgs{}
mi := &file_ngolofuzz_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetArgs) ProtoMessage() {}
func (x *GetArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[12]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetArgs.ProtoReflect.Descriptor instead.
func (*GetArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{12}
}
func (x *GetArgs) GetPath() string {
if x != nil {
return x.Path
}
return ""
}
type SliceNgdotValueArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SliceNgdotValueArgs) Reset() {
*x = SliceNgdotValueArgs{}
mi := &file_ngolofuzz_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SliceNgdotValueArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SliceNgdotValueArgs) ProtoMessage() {}
func (x *SliceNgdotValueArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[13]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SliceNgdotValueArgs.ProtoReflect.Descriptor instead.
func (*SliceNgdotValueArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{13}
}
type MakeSliceArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
SlicePtr *NgoloFuzzAny `protobuf:"bytes,1,opt,name=slicePtr,proto3" json:"slicePtr,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *MakeSliceArgs) Reset() {
*x = MakeSliceArgs{}
mi := &file_ngolofuzz_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *MakeSliceArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MakeSliceArgs) ProtoMessage() {}
func (x *MakeSliceArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[14]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MakeSliceArgs.ProtoReflect.Descriptor instead.
func (*MakeSliceArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{14}
}
func (x *MakeSliceArgs) GetSlicePtr() *NgoloFuzzAny {
if x != nil {
return x.SlicePtr
}
return nil
}
type SliceNgdotSelectOnePerGroupArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
A string `protobuf:"bytes,1,opt,name=a,proto3" json:"a,omitempty"`
V []string `protobuf:"bytes,2,rep,name=v,proto3" json:"v,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SliceNgdotSelectOnePerGroupArgs) Reset() {
*x = SliceNgdotSelectOnePerGroupArgs{}
mi := &file_ngolofuzz_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SliceNgdotSelectOnePerGroupArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SliceNgdotSelectOnePerGroupArgs) ProtoMessage() {}
func (x *SliceNgdotSelectOnePerGroupArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[15]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SliceNgdotSelectOnePerGroupArgs.ProtoReflect.Descriptor instead.
func (*SliceNgdotSelectOnePerGroupArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{15}
}
func (x *SliceNgdotSelectOnePerGroupArgs) GetA() string {
if x != nil {
return x.A
}
return ""
}
func (x *SliceNgdotSelectOnePerGroupArgs) GetV() []string {
if x != nil {
return x.V
}
return nil
}
type SliceNgdotSelectDraftArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SliceNgdotSelectDraftArgs) Reset() {
*x = SliceNgdotSelectDraftArgs{}
mi := &file_ngolofuzz_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SliceNgdotSelectDraftArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SliceNgdotSelectDraftArgs) ProtoMessage() {}
func (x *SliceNgdotSelectDraftArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[16]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SliceNgdotSelectDraftArgs.ProtoReflect.Descriptor instead.
func (*SliceNgdotSelectDraftArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{16}
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_CommonNgdotDefault
// *NgoloFuzzOne_CommonNgdotElement
// *NgoloFuzzOne_CommonNgdotGetCommon
// *NgoloFuzzOne_CommonNgdotData
// *NgoloFuzzOne_CLDRNgdotBCP47
// *NgoloFuzzOne_ParseDraft
// *NgoloFuzzOne_DraftNgdotString
// *NgoloFuzzOne_CLDRNgdotSetDraftLevel
// *NgoloFuzzOne_CLDRNgdotRawLDML
// *NgoloFuzzOne_CLDRNgdotLDML
// *NgoloFuzzOne_CLDRNgdotSupplemental
// *NgoloFuzzOne_CLDRNgdotLocales
// *NgoloFuzzOne_Get
// *NgoloFuzzOne_SliceNgdotValue
// *NgoloFuzzOne_MakeSlice
// *NgoloFuzzOne_SliceNgdotSelectOnePerGroup
// *NgoloFuzzOne_SliceNgdotSelectDraft
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[17]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{17}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetCommonNgdotDefault() *CommonNgdotDefaultArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CommonNgdotDefault); ok {
return x.CommonNgdotDefault
}
}
return nil
}
func (x *NgoloFuzzOne) GetCommonNgdotElement() *CommonNgdotElementArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CommonNgdotElement); ok {
return x.CommonNgdotElement
}
}
return nil
}
func (x *NgoloFuzzOne) GetCommonNgdotGetCommon() *CommonNgdotGetCommonArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CommonNgdotGetCommon); ok {
return x.CommonNgdotGetCommon
}
}
return nil
}
func (x *NgoloFuzzOne) GetCommonNgdotData() *CommonNgdotDataArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CommonNgdotData); ok {
return x.CommonNgdotData
}
}
return nil
}
func (x *NgoloFuzzOne) GetCLDRNgdotBCP47() *CLDRNgdotBCP47Args {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CLDRNgdotBCP47); ok {
return x.CLDRNgdotBCP47
}
}
return nil
}
func (x *NgoloFuzzOne) GetParseDraft() *ParseDraftArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_ParseDraft); ok {
return x.ParseDraft
}
}
return nil
}
func (x *NgoloFuzzOne) GetDraftNgdotString() *DraftNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_DraftNgdotString); ok {
return x.DraftNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetCLDRNgdotSetDraftLevel() *CLDRNgdotSetDraftLevelArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CLDRNgdotSetDraftLevel); ok {
return x.CLDRNgdotSetDraftLevel
}
}
return nil
}
func (x *NgoloFuzzOne) GetCLDRNgdotRawLDML() *CLDRNgdotRawLDMLArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CLDRNgdotRawLDML); ok {
return x.CLDRNgdotRawLDML
}
}
return nil
}
func (x *NgoloFuzzOne) GetCLDRNgdotLDML() *CLDRNgdotLDMLArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CLDRNgdotLDML); ok {
return x.CLDRNgdotLDML
}
}
return nil
}
func (x *NgoloFuzzOne) GetCLDRNgdotSupplemental() *CLDRNgdotSupplementalArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CLDRNgdotSupplemental); ok {
return x.CLDRNgdotSupplemental
}
}
return nil
}
func (x *NgoloFuzzOne) GetCLDRNgdotLocales() *CLDRNgdotLocalesArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_CLDRNgdotLocales); ok {
return x.CLDRNgdotLocales
}
}
return nil
}
func (x *NgoloFuzzOne) GetGet() *GetArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Get); ok {
return x.Get
}
}
return nil
}
func (x *NgoloFuzzOne) GetSliceNgdotValue() *SliceNgdotValueArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_SliceNgdotValue); ok {
return x.SliceNgdotValue
}
}
return nil
}
func (x *NgoloFuzzOne) GetMakeSlice() *MakeSliceArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_MakeSlice); ok {
return x.MakeSlice
}
}
return nil
}
func (x *NgoloFuzzOne) GetSliceNgdotSelectOnePerGroup() *SliceNgdotSelectOnePerGroupArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_SliceNgdotSelectOnePerGroup); ok {
return x.SliceNgdotSelectOnePerGroup
}
}
return nil
}
func (x *NgoloFuzzOne) GetSliceNgdotSelectDraft() *SliceNgdotSelectDraftArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_SliceNgdotSelectDraft); ok {
return x.SliceNgdotSelectDraft
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_CommonNgdotDefault struct {
CommonNgdotDefault *CommonNgdotDefaultArgs `protobuf:"bytes,1,opt,name=CommonNgdotDefault,proto3,oneof"`
}
type NgoloFuzzOne_CommonNgdotElement struct {
CommonNgdotElement *CommonNgdotElementArgs `protobuf:"bytes,2,opt,name=CommonNgdotElement,proto3,oneof"`
}
type NgoloFuzzOne_CommonNgdotGetCommon struct {
CommonNgdotGetCommon *CommonNgdotGetCommonArgs `protobuf:"bytes,3,opt,name=CommonNgdotGetCommon,proto3,oneof"`
}
type NgoloFuzzOne_CommonNgdotData struct {
CommonNgdotData *CommonNgdotDataArgs `protobuf:"bytes,4,opt,name=CommonNgdotData,proto3,oneof"`
}
type NgoloFuzzOne_CLDRNgdotBCP47 struct {
CLDRNgdotBCP47 *CLDRNgdotBCP47Args `protobuf:"bytes,5,opt,name=CLDRNgdotBCP47,proto3,oneof"`
}
type NgoloFuzzOne_ParseDraft struct {
ParseDraft *ParseDraftArgs `protobuf:"bytes,6,opt,name=ParseDraft,proto3,oneof"`
}
type NgoloFuzzOne_DraftNgdotString struct {
DraftNgdotString *DraftNgdotStringArgs `protobuf:"bytes,7,opt,name=DraftNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_CLDRNgdotSetDraftLevel struct {
CLDRNgdotSetDraftLevel *CLDRNgdotSetDraftLevelArgs `protobuf:"bytes,8,opt,name=CLDRNgdotSetDraftLevel,proto3,oneof"`
}
type NgoloFuzzOne_CLDRNgdotRawLDML struct {
CLDRNgdotRawLDML *CLDRNgdotRawLDMLArgs `protobuf:"bytes,9,opt,name=CLDRNgdotRawLDML,proto3,oneof"`
}
type NgoloFuzzOne_CLDRNgdotLDML struct {
CLDRNgdotLDML *CLDRNgdotLDMLArgs `protobuf:"bytes,10,opt,name=CLDRNgdotLDML,proto3,oneof"`
}
type NgoloFuzzOne_CLDRNgdotSupplemental struct {
CLDRNgdotSupplemental *CLDRNgdotSupplementalArgs `protobuf:"bytes,11,opt,name=CLDRNgdotSupplemental,proto3,oneof"`
}
type NgoloFuzzOne_CLDRNgdotLocales struct {
CLDRNgdotLocales *CLDRNgdotLocalesArgs `protobuf:"bytes,12,opt,name=CLDRNgdotLocales,proto3,oneof"`
}
type NgoloFuzzOne_Get struct {
Get *GetArgs `protobuf:"bytes,13,opt,name=Get,proto3,oneof"`
}
type NgoloFuzzOne_SliceNgdotValue struct {
SliceNgdotValue *SliceNgdotValueArgs `protobuf:"bytes,14,opt,name=SliceNgdotValue,proto3,oneof"`
}
type NgoloFuzzOne_MakeSlice struct {
MakeSlice *MakeSliceArgs `protobuf:"bytes,15,opt,name=MakeSlice,proto3,oneof"`
}
type NgoloFuzzOne_SliceNgdotSelectOnePerGroup struct {
SliceNgdotSelectOnePerGroup *SliceNgdotSelectOnePerGroupArgs `protobuf:"bytes,16,opt,name=SliceNgdotSelectOnePerGroup,proto3,oneof"`
}
type NgoloFuzzOne_SliceNgdotSelectDraft struct {
SliceNgdotSelectDraft *SliceNgdotSelectDraftArgs `protobuf:"bytes,17,opt,name=SliceNgdotSelectDraft,proto3,oneof"`
}
func (*NgoloFuzzOne_CommonNgdotDefault) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CommonNgdotElement) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CommonNgdotGetCommon) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CommonNgdotData) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CLDRNgdotBCP47) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_ParseDraft) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_DraftNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CLDRNgdotSetDraftLevel) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CLDRNgdotRawLDML) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CLDRNgdotLDML) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CLDRNgdotSupplemental) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_CLDRNgdotLocales) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Get) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_SliceNgdotValue) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_MakeSlice) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_SliceNgdotSelectOnePerGroup) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_SliceNgdotSelectDraft) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[18]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{18}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[19]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[19]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{19}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x18\n" +
"\x16CommonNgdotDefaultArgs\"\x18\n" +
"\x16CommonNgdotElementArgs\"\x1a\n" +
"\x18CommonNgdotGetCommonArgs\"\x15\n" +
"\x13CommonNgdotDataArgs\"\x14\n" +
"\x12CLDRNgdotBCP47Args\"&\n" +
"\x0eParseDraftArgs\x12\x14\n" +
"\x05level\x18\x01 \x01(\tR\x05level\"\x16\n" +
"\x14DraftNgdotStringArgs\">\n" +
"\x1aCLDRNgdotSetDraftLevelArgs\x12 \n" +
"\vpreferDraft\x18\x01 \x01(\bR\vpreferDraft\"(\n" +
"\x14CLDRNgdotRawLDMLArgs\x12\x10\n" +
"\x03loc\x18\x01 \x01(\tR\x03loc\"%\n" +
"\x11CLDRNgdotLDMLArgs\x12\x10\n" +
"\x03loc\x18\x01 \x01(\tR\x03loc\"\x1b\n" +
"\x19CLDRNgdotSupplementalArgs\"\x16\n" +
"\x14CLDRNgdotLocalesArgs\"\x1d\n" +
"\aGetArgs\x12\x12\n" +
"\x04path\x18\x01 \x01(\tR\x04path\"\x15\n" +
"\x13SliceNgdotValueArgs\"D\n" +
"\rMakeSliceArgs\x123\n" +
"\bslicePtr\x18\x01 \x01(\v2\x17.ngolofuzz.NgoloFuzzAnyR\bslicePtr\"=\n" +
"\x1fSliceNgdotSelectOnePerGroupArgs\x12\f\n" +
"\x01a\x18\x01 \x01(\tR\x01a\x12\f\n" +
"\x01v\x18\x02 \x03(\tR\x01v\"\x1b\n" +
"\x19SliceNgdotSelectDraftArgs\"\xdb\n" +
"\n" +
"\fNgoloFuzzOne\x12S\n" +
"\x12CommonNgdotDefault\x18\x01 \x01(\v2!.ngolofuzz.CommonNgdotDefaultArgsH\x00R\x12CommonNgdotDefault\x12S\n" +
"\x12CommonNgdotElement\x18\x02 \x01(\v2!.ngolofuzz.CommonNgdotElementArgsH\x00R\x12CommonNgdotElement\x12Y\n" +
"\x14CommonNgdotGetCommon\x18\x03 \x01(\v2#.ngolofuzz.CommonNgdotGetCommonArgsH\x00R\x14CommonNgdotGetCommon\x12J\n" +
"\x0fCommonNgdotData\x18\x04 \x01(\v2\x1e.ngolofuzz.CommonNgdotDataArgsH\x00R\x0fCommonNgdotData\x12G\n" +
"\x0eCLDRNgdotBCP47\x18\x05 \x01(\v2\x1d.ngolofuzz.CLDRNgdotBCP47ArgsH\x00R\x0eCLDRNgdotBCP47\x12;\n" +
"\n" +
"ParseDraft\x18\x06 \x01(\v2\x19.ngolofuzz.ParseDraftArgsH\x00R\n" +
"ParseDraft\x12M\n" +
"\x10DraftNgdotString\x18\a \x01(\v2\x1f.ngolofuzz.DraftNgdotStringArgsH\x00R\x10DraftNgdotString\x12_\n" +
"\x16CLDRNgdotSetDraftLevel\x18\b \x01(\v2%.ngolofuzz.CLDRNgdotSetDraftLevelArgsH\x00R\x16CLDRNgdotSetDraftLevel\x12M\n" +
"\x10CLDRNgdotRawLDML\x18\t \x01(\v2\x1f.ngolofuzz.CLDRNgdotRawLDMLArgsH\x00R\x10CLDRNgdotRawLDML\x12D\n" +
"\rCLDRNgdotLDML\x18\n" +
" \x01(\v2\x1c.ngolofuzz.CLDRNgdotLDMLArgsH\x00R\rCLDRNgdotLDML\x12\\\n" +
"\x15CLDRNgdotSupplemental\x18\v \x01(\v2$.ngolofuzz.CLDRNgdotSupplementalArgsH\x00R\x15CLDRNgdotSupplemental\x12M\n" +
"\x10CLDRNgdotLocales\x18\f \x01(\v2\x1f.ngolofuzz.CLDRNgdotLocalesArgsH\x00R\x10CLDRNgdotLocales\x12&\n" +
"\x03Get\x18\r \x01(\v2\x12.ngolofuzz.GetArgsH\x00R\x03Get\x12J\n" +
"\x0fSliceNgdotValue\x18\x0e \x01(\v2\x1e.ngolofuzz.SliceNgdotValueArgsH\x00R\x0fSliceNgdotValue\x128\n" +
"\tMakeSlice\x18\x0f \x01(\v2\x18.ngolofuzz.MakeSliceArgsH\x00R\tMakeSlice\x12n\n" +
"\x1bSliceNgdotSelectOnePerGroup\x18\x10 \x01(\v2*.ngolofuzz.SliceNgdotSelectOnePerGroupArgsH\x00R\x1bSliceNgdotSelectOnePerGroup\x12\\\n" +
"\x15SliceNgdotSelectDraft\x18\x11 \x01(\v2$.ngolofuzz.SliceNgdotSelectDraftArgsH\x00R\x15SliceNgdotSelectDraftB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB Z\x1e./;fuzz_ng_x_text_unicode_cldrb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 20)
var file_ngolofuzz_proto_goTypes = []any{
(*CommonNgdotDefaultArgs)(nil), // 0: ngolofuzz.CommonNgdotDefaultArgs
(*CommonNgdotElementArgs)(nil), // 1: ngolofuzz.CommonNgdotElementArgs
(*CommonNgdotGetCommonArgs)(nil), // 2: ngolofuzz.CommonNgdotGetCommonArgs
(*CommonNgdotDataArgs)(nil), // 3: ngolofuzz.CommonNgdotDataArgs
(*CLDRNgdotBCP47Args)(nil), // 4: ngolofuzz.CLDRNgdotBCP47Args
(*ParseDraftArgs)(nil), // 5: ngolofuzz.ParseDraftArgs
(*DraftNgdotStringArgs)(nil), // 6: ngolofuzz.DraftNgdotStringArgs
(*CLDRNgdotSetDraftLevelArgs)(nil), // 7: ngolofuzz.CLDRNgdotSetDraftLevelArgs
(*CLDRNgdotRawLDMLArgs)(nil), // 8: ngolofuzz.CLDRNgdotRawLDMLArgs
(*CLDRNgdotLDMLArgs)(nil), // 9: ngolofuzz.CLDRNgdotLDMLArgs
(*CLDRNgdotSupplementalArgs)(nil), // 10: ngolofuzz.CLDRNgdotSupplementalArgs
(*CLDRNgdotLocalesArgs)(nil), // 11: ngolofuzz.CLDRNgdotLocalesArgs
(*GetArgs)(nil), // 12: ngolofuzz.GetArgs
(*SliceNgdotValueArgs)(nil), // 13: ngolofuzz.SliceNgdotValueArgs
(*MakeSliceArgs)(nil), // 14: ngolofuzz.MakeSliceArgs
(*SliceNgdotSelectOnePerGroupArgs)(nil), // 15: ngolofuzz.SliceNgdotSelectOnePerGroupArgs
(*SliceNgdotSelectDraftArgs)(nil), // 16: ngolofuzz.SliceNgdotSelectDraftArgs
(*NgoloFuzzOne)(nil), // 17: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 18: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 19: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
18, // 0: ngolofuzz.MakeSliceArgs.slicePtr:type_name -> ngolofuzz.NgoloFuzzAny
0, // 1: ngolofuzz.NgoloFuzzOne.CommonNgdotDefault:type_name -> ngolofuzz.CommonNgdotDefaultArgs
1, // 2: ngolofuzz.NgoloFuzzOne.CommonNgdotElement:type_name -> ngolofuzz.CommonNgdotElementArgs
2, // 3: ngolofuzz.NgoloFuzzOne.CommonNgdotGetCommon:type_name -> ngolofuzz.CommonNgdotGetCommonArgs
3, // 4: ngolofuzz.NgoloFuzzOne.CommonNgdotData:type_name -> ngolofuzz.CommonNgdotDataArgs
4, // 5: ngolofuzz.NgoloFuzzOne.CLDRNgdotBCP47:type_name -> ngolofuzz.CLDRNgdotBCP47Args
5, // 6: ngolofuzz.NgoloFuzzOne.ParseDraft:type_name -> ngolofuzz.ParseDraftArgs
6, // 7: ngolofuzz.NgoloFuzzOne.DraftNgdotString:type_name -> ngolofuzz.DraftNgdotStringArgs
7, // 8: ngolofuzz.NgoloFuzzOne.CLDRNgdotSetDraftLevel:type_name -> ngolofuzz.CLDRNgdotSetDraftLevelArgs
8, // 9: ngolofuzz.NgoloFuzzOne.CLDRNgdotRawLDML:type_name -> ngolofuzz.CLDRNgdotRawLDMLArgs
9, // 10: ngolofuzz.NgoloFuzzOne.CLDRNgdotLDML:type_name -> ngolofuzz.CLDRNgdotLDMLArgs
10, // 11: ngolofuzz.NgoloFuzzOne.CLDRNgdotSupplemental:type_name -> ngolofuzz.CLDRNgdotSupplementalArgs
11, // 12: ngolofuzz.NgoloFuzzOne.CLDRNgdotLocales:type_name -> ngolofuzz.CLDRNgdotLocalesArgs
12, // 13: ngolofuzz.NgoloFuzzOne.Get:type_name -> ngolofuzz.GetArgs
13, // 14: ngolofuzz.NgoloFuzzOne.SliceNgdotValue:type_name -> ngolofuzz.SliceNgdotValueArgs
14, // 15: ngolofuzz.NgoloFuzzOne.MakeSlice:type_name -> ngolofuzz.MakeSliceArgs
15, // 16: ngolofuzz.NgoloFuzzOne.SliceNgdotSelectOnePerGroup:type_name -> ngolofuzz.SliceNgdotSelectOnePerGroupArgs
16, // 17: ngolofuzz.NgoloFuzzOne.SliceNgdotSelectDraft:type_name -> ngolofuzz.SliceNgdotSelectDraftArgs
17, // 18: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
19, // [19:19] is the sub-list for method output_type
19, // [19:19] is the sub-list for method input_type
19, // [19:19] is the sub-list for extension type_name
19, // [19:19] is the sub-list for extension extendee
0, // [0:19] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[17].OneofWrappers = []any{
(*NgoloFuzzOne_CommonNgdotDefault)(nil),
(*NgoloFuzzOne_CommonNgdotElement)(nil),
(*NgoloFuzzOne_CommonNgdotGetCommon)(nil),
(*NgoloFuzzOne_CommonNgdotData)(nil),
(*NgoloFuzzOne_CLDRNgdotBCP47)(nil),
(*NgoloFuzzOne_ParseDraft)(nil),
(*NgoloFuzzOne_DraftNgdotString)(nil),
(*NgoloFuzzOne_CLDRNgdotSetDraftLevel)(nil),
(*NgoloFuzzOne_CLDRNgdotRawLDML)(nil),
(*NgoloFuzzOne_CLDRNgdotLDML)(nil),
(*NgoloFuzzOne_CLDRNgdotSupplemental)(nil),
(*NgoloFuzzOne_CLDRNgdotLocales)(nil),
(*NgoloFuzzOne_Get)(nil),
(*NgoloFuzzOne_SliceNgdotValue)(nil),
(*NgoloFuzzOne_MakeSlice)(nil),
(*NgoloFuzzOne_SliceNgdotSelectOnePerGroup)(nil),
(*NgoloFuzzOne_SliceNgdotSelectDraft)(nil),
}
file_ngolofuzz_proto_msgTypes[18].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 20,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_text_unicode_rangetable
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/text/unicode/rangetable"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Assigned:
rangetable.Assigned(a.Assigned.Version)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Assigned:
w.WriteString(fmt.Sprintf("rangetable.Assigned(%#+v)\n", a.Assigned.Version))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_text_unicode_rangetable
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type AssignedArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *AssignedArgs) Reset() {
*x = AssignedArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AssignedArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AssignedArgs) ProtoMessage() {}
func (x *AssignedArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AssignedArgs.ProtoReflect.Descriptor instead.
func (*AssignedArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *AssignedArgs) GetVersion() string {
if x != nil {
return x.Version
}
return ""
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_Assigned
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetAssigned() *AssignedArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Assigned); ok {
return x.Assigned
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_Assigned struct {
Assigned *AssignedArgs `protobuf:"bytes,1,opt,name=Assigned,proto3,oneof"`
}
func (*NgoloFuzzOne_Assigned) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"(\n" +
"\fAssignedArgs\x12\x18\n" +
"\aversion\x18\x01 \x01(\tR\aversion\"M\n" +
"\fNgoloFuzzOne\x125\n" +
"\bAssigned\x18\x01 \x01(\v2\x17.ngolofuzz.AssignedArgsH\x00R\bAssignedB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB&Z$./;fuzz_ng_x_text_unicode_rangetableb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_ngolofuzz_proto_goTypes = []any{
(*AssignedArgs)(nil), // 0: ngolofuzz.AssignedArgs
(*NgoloFuzzOne)(nil), // 1: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 2: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 3: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.Assigned:type_name -> ngolofuzz.AssignedArgs
1, // 1: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[1].OneofWrappers = []any{
(*NgoloFuzzOne_Assigned)(nil),
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_text_unicode_runenames
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/text/unicode/runenames"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Name:
arg0 := GetRune(a.Name.R)
runenames.Name(arg0)
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_Name:
w.WriteString(fmt.Sprintf("runenames.Name(GetRune(%#+v))\n", a.Name.R))
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_text_unicode_runenames
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type NameArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R string `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NameArgs) Reset() {
*x = NameArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NameArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NameArgs) ProtoMessage() {}
func (x *NameArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NameArgs.ProtoReflect.Descriptor instead.
func (*NameArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
func (x *NameArgs) GetR() string {
if x != nil {
return x.R
}
return ""
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_Name
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetName() *NameArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Name); ok {
return x.Name
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_Name struct {
Name *NameArgs `protobuf:"bytes,1,opt,name=Name,proto3,oneof"`
}
func (*NgoloFuzzOne_Name) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x18\n" +
"\bNameArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\tR\x01r\"A\n" +
"\fNgoloFuzzOne\x12)\n" +
"\x04Name\x18\x01 \x01(\v2\x13.ngolofuzz.NameArgsH\x00R\x04NameB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB%Z#./;fuzz_ng_x_text_unicode_runenamesb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_ngolofuzz_proto_goTypes = []any{
(*NameArgs)(nil), // 0: ngolofuzz.NameArgs
(*NgoloFuzzOne)(nil), // 1: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 2: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 3: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.Name:type_name -> ngolofuzz.NameArgs
1, // 1: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[1].OneofWrappers = []any{
(*NgoloFuzzOne_Name)(nil),
}
file_ngolofuzz_proto_msgTypes[2].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
//go:build gofuzz
package fuzz_ng_x_text_width
import (
"google.golang.org/protobuf/proto"
"bufio"
"bytes"
"fmt"
"golang.org/x/text/width"
"io"
"log"
"math/big"
"net"
"os"
"runtime"
"time"
)
type FuzzingConn struct {
buf []byte
offset int
}
func (c *FuzzingConn) Read(b []byte) (n int, err error) {
if c.offset >= len(c.buf) {
return 0, io.EOF
}
if len(b) < len(c.buf)+c.offset {
copy(b, c.buf[c.offset:])
c.offset += len(b)
return len(b), nil
}
copy(b, c.buf[c.offset:])
r := len(c.buf) - c.offset
c.offset = len(c.buf)
return r, nil
}
func (c *FuzzingConn) Write(b []byte) (n int, err error) {
return len(b), nil
}
func (c *FuzzingConn) Close() error {
c.offset = len(c.buf)
return nil
}
type FuzzingAddr struct{}
func (c *FuzzingAddr) Network() string {
return "fuzz_addr_net"
}
func (c *FuzzingAddr) String() string {
return "fuzz_addr_string"
}
func (c *FuzzingConn) LocalAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) RemoteAddr() net.Addr {
return &FuzzingAddr{}
}
func (c *FuzzingConn) SetDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *FuzzingConn) SetWriteDeadline(t time.Time) error {
return nil
}
func CreateFuzzingConn(a []byte) *FuzzingConn {
r := &FuzzingConn{}
r.buf = a
return r
}
//TODO only add these functions if needed
func CreateBigInt(a []byte) *big.Int {
r := new(big.Int)
r.SetBytes(a)
return r
}
func CreateBufioReader(a []byte) *bufio.Reader {
return bufio.NewReader(bytes.NewBuffer(a))
}
func ConvertIntArray(a []int64) []int {
r := make([]int, len(a))
for i := range a {
r[i] = int(a[i])
}
return r
}
func ConvertUint16Array(a []int64) []uint16 {
r := make([]uint16, len(a))
for i := range a {
r[i] = uint16(a[i])
}
return r
}
func GetRune(s string) rune {
for _, c := range s {
return c
}
return '\x00'
}
func FuzzNG_valid(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
panic("Failed to unmarshal LPM generated variables")
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
// we are unsure the input is a valid protobuf
func FuzzNG_unsure(data []byte) int {
gen := &NgoloFuzzList{}
err := proto.Unmarshal(data, gen)
if err != nil {
return 0
}
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case string:
//do nothing
default:
panic(r)
}
}
}()
runtime.GC()
return FuzzNG_List(gen)
}
var initialized bool
func FuzzNG_List(gen *NgoloFuzzList) int {
if !initialized {
repro := os.Getenv("FUZZ_NG_REPRODUCER")
if len(repro) > 0 {
f, err := os.Create(repro)
if err != nil {
log.Fatalf("Failed to open %s : %s", repro, err)
} else {
PrintNG_List(gen, f)
}
}
initialized = true
}
var KindResults []*width.Kind
KindResultsIndex := 0
var PropertiesResults []*width.Properties
PropertiesResultsIndex := 0
for l := range gen.List {
if l > 4096 {
return 0
}
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_KindNgdotString:
if len(KindResults) == 0 {
continue
}
arg0 := KindResults[KindResultsIndex]
KindResultsIndex = (KindResultsIndex + 1) % len(KindResults)
arg0.String()
case *NgoloFuzzOne_Lookup:
r0, _ := width.Lookup(a.Lookup.B)
PropertiesResults = append(PropertiesResults, &r0)
case *NgoloFuzzOne_LookupString:
r0, _ := width.LookupString(a.LookupString.S)
PropertiesResults = append(PropertiesResults, &r0)
case *NgoloFuzzOne_LookupRune:
arg0 := GetRune(a.LookupRune.R)
r0 := width.LookupRune(arg0)
PropertiesResults = append(PropertiesResults, &r0)
case *NgoloFuzzOne_PropertiesNgdotKind:
if len(PropertiesResults) == 0 {
continue
}
arg0 := PropertiesResults[PropertiesResultsIndex]
PropertiesResultsIndex = (PropertiesResultsIndex + 1) % len(PropertiesResults)
r0 := arg0.Kind()
KindResults = append(KindResults, &r0)
case *NgoloFuzzOne_PropertiesNgdotFolded:
if len(PropertiesResults) == 0 {
continue
}
arg0 := PropertiesResults[PropertiesResultsIndex]
PropertiesResultsIndex = (PropertiesResultsIndex + 1) % len(PropertiesResults)
arg0.Folded()
case *NgoloFuzzOne_PropertiesNgdotNarrow:
if len(PropertiesResults) == 0 {
continue
}
arg0 := PropertiesResults[PropertiesResultsIndex]
PropertiesResultsIndex = (PropertiesResultsIndex + 1) % len(PropertiesResults)
arg0.Narrow()
case *NgoloFuzzOne_PropertiesNgdotWide:
if len(PropertiesResults) == 0 {
continue
}
arg0 := PropertiesResults[PropertiesResultsIndex]
PropertiesResultsIndex = (PropertiesResultsIndex + 1) % len(PropertiesResults)
arg0.Wide()
}
}
return 1
}
func PrintNG_List(gen *NgoloFuzzList, w io.StringWriter) {
KindNb := 0
KindResultsIndex := 0
PropertiesNb := 0
PropertiesResultsIndex := 0
for l := range gen.List {
switch a := gen.List[l].Item.(type) {
case *NgoloFuzzOne_KindNgdotString:
if KindNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Kind%d.String()\n", KindResultsIndex))
KindResultsIndex = (KindResultsIndex + 1) % KindNb
case *NgoloFuzzOne_Lookup:
w.WriteString(fmt.Sprintf("Properties%d, _ := width.Lookup(%#+v)\n", PropertiesNb, a.Lookup.B))
PropertiesNb = PropertiesNb + 1
case *NgoloFuzzOne_LookupString:
w.WriteString(fmt.Sprintf("Properties%d, _ := width.LookupString(%#+v)\n", PropertiesNb, a.LookupString.S))
PropertiesNb = PropertiesNb + 1
case *NgoloFuzzOne_LookupRune:
w.WriteString(fmt.Sprintf("Properties%d := width.LookupRune(GetRune(%#+v))\n", PropertiesNb, a.LookupRune.R))
PropertiesNb = PropertiesNb + 1
case *NgoloFuzzOne_PropertiesNgdotKind:
if PropertiesNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Kind%d := Properties%d.Kind()\n", KindNb, PropertiesResultsIndex))
KindNb = KindNb + 1
PropertiesResultsIndex = (PropertiesResultsIndex + 1) % PropertiesNb
case *NgoloFuzzOne_PropertiesNgdotFolded:
if PropertiesNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Properties%d.Folded()\n", PropertiesResultsIndex))
PropertiesResultsIndex = (PropertiesResultsIndex + 1) % PropertiesNb
case *NgoloFuzzOne_PropertiesNgdotNarrow:
if PropertiesNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Properties%d.Narrow()\n", PropertiesResultsIndex))
PropertiesResultsIndex = (PropertiesResultsIndex + 1) % PropertiesNb
case *NgoloFuzzOne_PropertiesNgdotWide:
if PropertiesNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Properties%d.Wide()\n", PropertiesResultsIndex))
PropertiesResultsIndex = (PropertiesResultsIndex + 1) % PropertiesNb
}
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v5.29.3
// source: ngolofuzz.proto
package fuzz_ng_x_text_width
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type KindNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *KindNgdotStringArgs) Reset() {
*x = KindNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *KindNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*KindNgdotStringArgs) ProtoMessage() {}
func (x *KindNgdotStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use KindNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*KindNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
type LookupArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
B []byte `protobuf:"bytes,1,opt,name=b,proto3" json:"b,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *LookupArgs) Reset() {
*x = LookupArgs{}
mi := &file_ngolofuzz_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *LookupArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*LookupArgs) ProtoMessage() {}
func (x *LookupArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use LookupArgs.ProtoReflect.Descriptor instead.
func (*LookupArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
func (x *LookupArgs) GetB() []byte {
if x != nil {
return x.B
}
return nil
}
type LookupStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
S string `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *LookupStringArgs) Reset() {
*x = LookupStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *LookupStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*LookupStringArgs) ProtoMessage() {}
func (x *LookupStringArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use LookupStringArgs.ProtoReflect.Descriptor instead.
func (*LookupStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
func (x *LookupStringArgs) GetS() string {
if x != nil {
return x.S
}
return ""
}
type LookupRuneArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
R string `protobuf:"bytes,1,opt,name=r,proto3" json:"r,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *LookupRuneArgs) Reset() {
*x = LookupRuneArgs{}
mi := &file_ngolofuzz_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *LookupRuneArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*LookupRuneArgs) ProtoMessage() {}
func (x *LookupRuneArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use LookupRuneArgs.ProtoReflect.Descriptor instead.
func (*LookupRuneArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
func (x *LookupRuneArgs) GetR() string {
if x != nil {
return x.R
}
return ""
}
type PropertiesNgdotKindArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PropertiesNgdotKindArgs) Reset() {
*x = PropertiesNgdotKindArgs{}
mi := &file_ngolofuzz_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PropertiesNgdotKindArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PropertiesNgdotKindArgs) ProtoMessage() {}
func (x *PropertiesNgdotKindArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PropertiesNgdotKindArgs.ProtoReflect.Descriptor instead.
func (*PropertiesNgdotKindArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{4}
}
type PropertiesNgdotFoldedArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PropertiesNgdotFoldedArgs) Reset() {
*x = PropertiesNgdotFoldedArgs{}
mi := &file_ngolofuzz_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PropertiesNgdotFoldedArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PropertiesNgdotFoldedArgs) ProtoMessage() {}
func (x *PropertiesNgdotFoldedArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PropertiesNgdotFoldedArgs.ProtoReflect.Descriptor instead.
func (*PropertiesNgdotFoldedArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{5}
}
type PropertiesNgdotNarrowArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PropertiesNgdotNarrowArgs) Reset() {
*x = PropertiesNgdotNarrowArgs{}
mi := &file_ngolofuzz_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PropertiesNgdotNarrowArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PropertiesNgdotNarrowArgs) ProtoMessage() {}
func (x *PropertiesNgdotNarrowArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PropertiesNgdotNarrowArgs.ProtoReflect.Descriptor instead.
func (*PropertiesNgdotNarrowArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{6}
}
type PropertiesNgdotWideArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PropertiesNgdotWideArgs) Reset() {
*x = PropertiesNgdotWideArgs{}
mi := &file_ngolofuzz_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PropertiesNgdotWideArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PropertiesNgdotWideArgs) ProtoMessage() {}
func (x *PropertiesNgdotWideArgs) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PropertiesNgdotWideArgs.ProtoReflect.Descriptor instead.
func (*PropertiesNgdotWideArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{7}
}
type NgoloFuzzOne struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzOne_KindNgdotString
// *NgoloFuzzOne_Lookup
// *NgoloFuzzOne_LookupString
// *NgoloFuzzOne_LookupRune
// *NgoloFuzzOne_PropertiesNgdotKind
// *NgoloFuzzOne_PropertiesNgdotFolded
// *NgoloFuzzOne_PropertiesNgdotNarrow
// *NgoloFuzzOne_PropertiesNgdotWide
Item isNgoloFuzzOne_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzOne) Reset() {
*x = NgoloFuzzOne{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzOne) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzOne) ProtoMessage() {}
func (x *NgoloFuzzOne) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
func (x *NgoloFuzzOne) GetItem() isNgoloFuzzOne_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzOne) GetKindNgdotString() *KindNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_KindNgdotString); ok {
return x.KindNgdotString
}
}
return nil
}
func (x *NgoloFuzzOne) GetLookup() *LookupArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_Lookup); ok {
return x.Lookup
}
}
return nil
}
func (x *NgoloFuzzOne) GetLookupString() *LookupStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_LookupString); ok {
return x.LookupString
}
}
return nil
}
func (x *NgoloFuzzOne) GetLookupRune() *LookupRuneArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_LookupRune); ok {
return x.LookupRune
}
}
return nil
}
func (x *NgoloFuzzOne) GetPropertiesNgdotKind() *PropertiesNgdotKindArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_PropertiesNgdotKind); ok {
return x.PropertiesNgdotKind
}
}
return nil
}
func (x *NgoloFuzzOne) GetPropertiesNgdotFolded() *PropertiesNgdotFoldedArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_PropertiesNgdotFolded); ok {
return x.PropertiesNgdotFolded
}
}
return nil
}
func (x *NgoloFuzzOne) GetPropertiesNgdotNarrow() *PropertiesNgdotNarrowArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_PropertiesNgdotNarrow); ok {
return x.PropertiesNgdotNarrow
}
}
return nil
}
func (x *NgoloFuzzOne) GetPropertiesNgdotWide() *PropertiesNgdotWideArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_PropertiesNgdotWide); ok {
return x.PropertiesNgdotWide
}
}
return nil
}
type isNgoloFuzzOne_Item interface {
isNgoloFuzzOne_Item()
}
type NgoloFuzzOne_KindNgdotString struct {
KindNgdotString *KindNgdotStringArgs `protobuf:"bytes,1,opt,name=KindNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_Lookup struct {
Lookup *LookupArgs `protobuf:"bytes,2,opt,name=Lookup,proto3,oneof"`
}
type NgoloFuzzOne_LookupString struct {
LookupString *LookupStringArgs `protobuf:"bytes,3,opt,name=LookupString,proto3,oneof"`
}
type NgoloFuzzOne_LookupRune struct {
LookupRune *LookupRuneArgs `protobuf:"bytes,4,opt,name=LookupRune,proto3,oneof"`
}
type NgoloFuzzOne_PropertiesNgdotKind struct {
PropertiesNgdotKind *PropertiesNgdotKindArgs `protobuf:"bytes,5,opt,name=PropertiesNgdotKind,proto3,oneof"`
}
type NgoloFuzzOne_PropertiesNgdotFolded struct {
PropertiesNgdotFolded *PropertiesNgdotFoldedArgs `protobuf:"bytes,6,opt,name=PropertiesNgdotFolded,proto3,oneof"`
}
type NgoloFuzzOne_PropertiesNgdotNarrow struct {
PropertiesNgdotNarrow *PropertiesNgdotNarrowArgs `protobuf:"bytes,7,opt,name=PropertiesNgdotNarrow,proto3,oneof"`
}
type NgoloFuzzOne_PropertiesNgdotWide struct {
PropertiesNgdotWide *PropertiesNgdotWideArgs `protobuf:"bytes,8,opt,name=PropertiesNgdotWide,proto3,oneof"`
}
func (*NgoloFuzzOne_KindNgdotString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_Lookup) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_LookupString) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_LookupRune) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_PropertiesNgdotKind) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_PropertiesNgdotFolded) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_PropertiesNgdotNarrow) isNgoloFuzzOne_Item() {}
func (*NgoloFuzzOne_PropertiesNgdotWide) isNgoloFuzzOne_Item() {}
type NgoloFuzzAny struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Item:
//
// *NgoloFuzzAny_DoubleArgs
// *NgoloFuzzAny_Int64Args
// *NgoloFuzzAny_BoolArgs
// *NgoloFuzzAny_StringArgs
// *NgoloFuzzAny_BytesArgs
Item isNgoloFuzzAny_Item `protobuf_oneof:"item"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzAny) Reset() {
*x = NgoloFuzzAny{}
mi := &file_ngolofuzz_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzAny) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzAny) ProtoMessage() {}
func (x *NgoloFuzzAny) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
func (x *NgoloFuzzAny) GetItem() isNgoloFuzzAny_Item {
if x != nil {
return x.Item
}
return nil
}
func (x *NgoloFuzzAny) GetDoubleArgs() float64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_DoubleArgs); ok {
return x.DoubleArgs
}
}
return 0
}
func (x *NgoloFuzzAny) GetInt64Args() int64 {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_Int64Args); ok {
return x.Int64Args
}
}
return 0
}
func (x *NgoloFuzzAny) GetBoolArgs() bool {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BoolArgs); ok {
return x.BoolArgs
}
}
return false
}
func (x *NgoloFuzzAny) GetStringArgs() string {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_StringArgs); ok {
return x.StringArgs
}
}
return ""
}
func (x *NgoloFuzzAny) GetBytesArgs() []byte {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzAny_BytesArgs); ok {
return x.BytesArgs
}
}
return nil
}
type isNgoloFuzzAny_Item interface {
isNgoloFuzzAny_Item()
}
type NgoloFuzzAny_DoubleArgs struct {
DoubleArgs float64 `protobuf:"fixed64,1,opt,name=DoubleArgs,proto3,oneof"`
}
type NgoloFuzzAny_Int64Args struct {
Int64Args int64 `protobuf:"varint,2,opt,name=Int64Args,proto3,oneof"`
}
type NgoloFuzzAny_BoolArgs struct {
BoolArgs bool `protobuf:"varint,3,opt,name=BoolArgs,proto3,oneof"`
}
type NgoloFuzzAny_StringArgs struct {
StringArgs string `protobuf:"bytes,4,opt,name=StringArgs,proto3,oneof"`
}
type NgoloFuzzAny_BytesArgs struct {
BytesArgs []byte `protobuf:"bytes,5,opt,name=BytesArgs,proto3,oneof"`
}
func (*NgoloFuzzAny_DoubleArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_Int64Args) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BoolArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_StringArgs) isNgoloFuzzAny_Item() {}
func (*NgoloFuzzAny_BytesArgs) isNgoloFuzzAny_Item() {}
type NgoloFuzzList struct {
state protoimpl.MessageState `protogen:"open.v1"`
List []*NgoloFuzzOne `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NgoloFuzzList) Reset() {
*x = NgoloFuzzList{}
mi := &file_ngolofuzz_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NgoloFuzzList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NgoloFuzzList) ProtoMessage() {}
func (x *NgoloFuzzList) ProtoReflect() protoreflect.Message {
mi := &file_ngolofuzz_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{10}
}
func (x *NgoloFuzzList) GetList() []*NgoloFuzzOne {
if x != nil {
return x.List
}
return nil
}
var File_ngolofuzz_proto protoreflect.FileDescriptor
const file_ngolofuzz_proto_rawDesc = "" +
"\n" +
"\x0fngolofuzz.proto\x12\tngolofuzz\"\x15\n" +
"\x13KindNgdotStringArgs\"\x1a\n" +
"\n" +
"LookupArgs\x12\f\n" +
"\x01b\x18\x01 \x01(\fR\x01b\" \n" +
"\x10LookupStringArgs\x12\f\n" +
"\x01s\x18\x01 \x01(\tR\x01s\"\x1e\n" +
"\x0eLookupRuneArgs\x12\f\n" +
"\x01r\x18\x01 \x01(\tR\x01r\"\x19\n" +
"\x17PropertiesNgdotKindArgs\"\x1b\n" +
"\x19PropertiesNgdotFoldedArgs\"\x1b\n" +
"\x19PropertiesNgdotNarrowArgs\"\x19\n" +
"\x17PropertiesNgdotWideArgs\"\xff\x04\n" +
"\fNgoloFuzzOne\x12J\n" +
"\x0fKindNgdotString\x18\x01 \x01(\v2\x1e.ngolofuzz.KindNgdotStringArgsH\x00R\x0fKindNgdotString\x12/\n" +
"\x06Lookup\x18\x02 \x01(\v2\x15.ngolofuzz.LookupArgsH\x00R\x06Lookup\x12A\n" +
"\fLookupString\x18\x03 \x01(\v2\x1b.ngolofuzz.LookupStringArgsH\x00R\fLookupString\x12;\n" +
"\n" +
"LookupRune\x18\x04 \x01(\v2\x19.ngolofuzz.LookupRuneArgsH\x00R\n" +
"LookupRune\x12V\n" +
"\x13PropertiesNgdotKind\x18\x05 \x01(\v2\".ngolofuzz.PropertiesNgdotKindArgsH\x00R\x13PropertiesNgdotKind\x12\\\n" +
"\x15PropertiesNgdotFolded\x18\x06 \x01(\v2$.ngolofuzz.PropertiesNgdotFoldedArgsH\x00R\x15PropertiesNgdotFolded\x12\\\n" +
"\x15PropertiesNgdotNarrow\x18\a \x01(\v2$.ngolofuzz.PropertiesNgdotNarrowArgsH\x00R\x15PropertiesNgdotNarrow\x12V\n" +
"\x13PropertiesNgdotWide\x18\b \x01(\v2\".ngolofuzz.PropertiesNgdotWideArgsH\x00R\x13PropertiesNgdotWideB\x06\n" +
"\x04item\"\xb8\x01\n" +
"\fNgoloFuzzAny\x12 \n" +
"\n" +
"DoubleArgs\x18\x01 \x01(\x01H\x00R\n" +
"DoubleArgs\x12\x1e\n" +
"\tInt64Args\x18\x02 \x01(\x03H\x00R\tInt64Args\x12\x1c\n" +
"\bBoolArgs\x18\x03 \x01(\bH\x00R\bBoolArgs\x12 \n" +
"\n" +
"StringArgs\x18\x04 \x01(\tH\x00R\n" +
"StringArgs\x12\x1e\n" +
"\tBytesArgs\x18\x05 \x01(\fH\x00R\tBytesArgsB\x06\n" +
"\x04item\"<\n" +
"\rNgoloFuzzList\x12+\n" +
"\x04list\x18\x01 \x03(\v2\x17.ngolofuzz.NgoloFuzzOneR\x04listB\x19Z\x17./;fuzz_ng_x_text_widthb\x06proto3"
var (
file_ngolofuzz_proto_rawDescOnce sync.Once
file_ngolofuzz_proto_rawDescData []byte
)
func file_ngolofuzz_proto_rawDescGZIP() []byte {
file_ngolofuzz_proto_rawDescOnce.Do(func() {
file_ngolofuzz_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)))
})
return file_ngolofuzz_proto_rawDescData
}
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
var file_ngolofuzz_proto_goTypes = []any{
(*KindNgdotStringArgs)(nil), // 0: ngolofuzz.KindNgdotStringArgs
(*LookupArgs)(nil), // 1: ngolofuzz.LookupArgs
(*LookupStringArgs)(nil), // 2: ngolofuzz.LookupStringArgs
(*LookupRuneArgs)(nil), // 3: ngolofuzz.LookupRuneArgs
(*PropertiesNgdotKindArgs)(nil), // 4: ngolofuzz.PropertiesNgdotKindArgs
(*PropertiesNgdotFoldedArgs)(nil), // 5: ngolofuzz.PropertiesNgdotFoldedArgs
(*PropertiesNgdotNarrowArgs)(nil), // 6: ngolofuzz.PropertiesNgdotNarrowArgs
(*PropertiesNgdotWideArgs)(nil), // 7: ngolofuzz.PropertiesNgdotWideArgs
(*NgoloFuzzOne)(nil), // 8: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 9: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 10: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NgoloFuzzOne.KindNgdotString:type_name -> ngolofuzz.KindNgdotStringArgs
1, // 1: ngolofuzz.NgoloFuzzOne.Lookup:type_name -> ngolofuzz.LookupArgs
2, // 2: ngolofuzz.NgoloFuzzOne.LookupString:type_name -> ngolofuzz.LookupStringArgs
3, // 3: ngolofuzz.NgoloFuzzOne.LookupRune:type_name -> ngolofuzz.LookupRuneArgs
4, // 4: ngolofuzz.NgoloFuzzOne.PropertiesNgdotKind:type_name -> ngolofuzz.PropertiesNgdotKindArgs
5, // 5: ngolofuzz.NgoloFuzzOne.PropertiesNgdotFolded:type_name -> ngolofuzz.PropertiesNgdotFoldedArgs
6, // 6: ngolofuzz.NgoloFuzzOne.PropertiesNgdotNarrow:type_name -> ngolofuzz.PropertiesNgdotNarrowArgs
7, // 7: ngolofuzz.NgoloFuzzOne.PropertiesNgdotWide:type_name -> ngolofuzz.PropertiesNgdotWideArgs
8, // 8: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
9, // [9:9] is the sub-list for method output_type
9, // [9:9] is the sub-list for method input_type
9, // [9:9] is the sub-list for extension type_name
9, // [9:9] is the sub-list for extension extendee
0, // [0:9] is the sub-list for field type_name
}
func init() { file_ngolofuzz_proto_init() }
func file_ngolofuzz_proto_init() {
if File_ngolofuzz_proto != nil {
return
}
file_ngolofuzz_proto_msgTypes[8].OneofWrappers = []any{
(*NgoloFuzzOne_KindNgdotString)(nil),
(*NgoloFuzzOne_Lookup)(nil),
(*NgoloFuzzOne_LookupString)(nil),
(*NgoloFuzzOne_LookupRune)(nil),
(*NgoloFuzzOne_PropertiesNgdotKind)(nil),
(*NgoloFuzzOne_PropertiesNgdotFolded)(nil),
(*NgoloFuzzOne_PropertiesNgdotNarrow)(nil),
(*NgoloFuzzOne_PropertiesNgdotWide)(nil),
}
file_ngolofuzz_proto_msgTypes[9].OneofWrappers = []any{
(*NgoloFuzzAny_DoubleArgs)(nil),
(*NgoloFuzzAny_Int64Args)(nil),
(*NgoloFuzzAny_BoolArgs)(nil),
(*NgoloFuzzAny_StringArgs)(nil),
(*NgoloFuzzAny_BytesArgs)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ngolofuzz_proto_rawDesc), len(file_ngolofuzz_proto_rawDesc)),
NumEnums: 0,
NumMessages: 11,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ngolofuzz_proto_goTypes,
DependencyIndexes: file_ngolofuzz_proto_depIdxs,
MessageInfos: file_ngolofuzz_proto_msgTypes,
}.Build()
File_ngolofuzz_proto = out.File
file_ngolofuzz_proto_goTypes = nil
file_ngolofuzz_proto_depIdxs = nil
}
// 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 catmsg contains support types for package x/text/message/catalog.
//
// This package contains the low-level implementations of Message used by the
// catalog package and provides primitives for other packages to implement their
// own. For instance, the plural package provides functionality for selecting
// translation strings based on the plural category of substitution arguments.
//
// # Encoding and Decoding
//
// Catalogs store Messages encoded as a single string. Compiling a message into
// a string both results in compacter representation and speeds up evaluation.
//
// A Message must implement a Compile method to convert its arbitrary
// representation to a string. The Compile method takes an Encoder which
// facilitates serializing the message. Encoders also provide more context of
// the messages's creation (such as for which language the message is intended),
// which may not be known at the time of the creation of the message.
//
// Each message type must also have an accompanying decoder registered to decode
// the message. This decoder takes a Decoder argument which provides the
// counterparts for the decoding.
//
// # Renderers
//
// A Decoder must be initialized with a Renderer implementation. These
// implementations must be provided by packages that use Catalogs, typically
// formatting packages such as x/text/message. A typical user will not need to
// worry about this type; it is only relevant to packages that do string
// formatting and want to use the catalog package to handle localized strings.
//
// A package that uses catalogs for selecting strings receives selection results
// as sequence of substrings passed to the Renderer. The following snippet shows
// how to express the above example using the message package.
//
// message.Set(language.English, "You are %d minute(s) late.",
// catalog.Var("minutes", plural.Select(1, "one", "minute")),
// catalog.String("You are %[1]d ${minutes} late."))
//
// p := message.NewPrinter(language.English)
// p.Printf("You are %d minute(s) late.", 5) // always 5 minutes late.
//
// To evaluate the Printf, package message wraps the arguments in a Renderer
// that is passed to the catalog for message decoding. The call sequence that
// results from evaluating the above message, assuming the person is rather
// tardy, is:
//
// Render("You are %[1]d ")
// Arg(1)
// Render("minutes")
// Render(" late.")
//
// The calls to Arg is caused by the plural.Select execution, which evaluates
// the argument to determine whether the singular or plural message form should
// be selected. The calls to Render reports the partial results to the message
// package for further evaluation.
package catmsg
import (
"errors"
"fmt"
"strconv"
"strings"
"sync"
"golang.org/x/text/language"
)
// A Handle refers to a registered message type.
type Handle int
// A Handler decodes and evaluates data compiled by a Message and sends the
// result to the Decoder. The output may depend on the value of the substitution
// arguments, accessible by the Decoder's Arg method. The Handler returns false
// if there is no translation for the given substitution arguments.
type Handler func(d *Decoder) bool
// Register records the existence of a message type and returns a Handle that
// can be used in the Encoder's EncodeMessageType method to create such
// messages. The prefix of the name should be the package path followed by
// an optional disambiguating string.
// Register will panic if a handle for the same name was already registered.
func Register(name string, handler Handler) Handle {
mutex.Lock()
defer mutex.Unlock()
if _, ok := names[name]; ok {
panic(fmt.Errorf("catmsg: handler for %q already exists", name))
}
h := Handle(len(handlers))
names[name] = h
handlers = append(handlers, handler)
return h
}
// These handlers require fixed positions in the handlers slice.
const (
msgVars Handle = iota
msgFirst
msgRaw
msgString
msgAffix
// Leave some arbitrary room for future expansion: 20 should suffice.
numInternal = 20
)
const prefix = "golang.org/x/text/internal/catmsg."
var (
// TODO: find a more stable way to link handles to message types.
mutex sync.Mutex
names = map[string]Handle{
prefix + "Vars": msgVars,
prefix + "First": msgFirst,
prefix + "Raw": msgRaw,
prefix + "String": msgString,
prefix + "Affix": msgAffix,
}
handlers = make([]Handler, numInternal)
)
func init() {
// This handler is a message type wrapper that initializes a decoder
// with a variable block. This message type, if present, is always at the
// start of an encoded message.
handlers[msgVars] = func(d *Decoder) bool {
blockSize := int(d.DecodeUint())
d.vars = d.data[:blockSize]
d.data = d.data[blockSize:]
return d.executeMessage()
}
// First takes the first message in a sequence that results in a match for
// the given substitution arguments.
handlers[msgFirst] = func(d *Decoder) bool {
for !d.Done() {
if d.ExecuteMessage() {
return true
}
}
return false
}
handlers[msgRaw] = func(d *Decoder) bool {
d.Render(d.data)
return true
}
// A String message alternates between a string constant and a variable
// substitution.
handlers[msgString] = func(d *Decoder) bool {
for !d.Done() {
if str := d.DecodeString(); str != "" {
d.Render(str)
}
if d.Done() {
break
}
d.ExecuteSubstitution()
}
return true
}
handlers[msgAffix] = func(d *Decoder) bool {
// TODO: use an alternative method for common cases.
prefix := d.DecodeString()
suffix := d.DecodeString()
if prefix != "" {
d.Render(prefix)
}
ret := d.ExecuteMessage()
if suffix != "" {
d.Render(suffix)
}
return ret
}
}
var (
// ErrIncomplete indicates a compiled message does not define translations
// for all possible argument values. If this message is returned, evaluating
// a message may result in the ErrNoMatch error.
ErrIncomplete = errors.New("catmsg: incomplete message; may not give result for all inputs")
// ErrNoMatch indicates no translation message matched the given input
// parameters when evaluating a message.
ErrNoMatch = errors.New("catmsg: no translation for inputs")
)
// A Message holds a collection of translations for the same phrase that may
// vary based on the values of substitution arguments.
type Message interface {
// Compile encodes the format string(s) of the message as a string for later
// evaluation.
//
// The first call Compile makes on the encoder must be EncodeMessageType.
// The handle passed to this call may either be a handle returned by
// Register to encode a single custom message, or HandleFirst followed by
// a sequence of calls to EncodeMessage.
//
// Compile must return ErrIncomplete if it is possible for evaluation to
// not match any translation for a given set of formatting parameters.
// For example, selecting a translation based on plural form may not yield
// a match if the form "Other" is not one of the selectors.
//
// Compile may return any other application-specific error. For backwards
// compatibility with package like fmt, which often do not do sanity
// checking of format strings ahead of time, Compile should still make an
// effort to have some sensible fallback in case of an error.
Compile(e *Encoder) error
}
// Compile converts a Message to a data string that can be stored in a Catalog.
// The resulting string can subsequently be decoded by passing to the Execute
// method of a Decoder.
func Compile(tag language.Tag, macros Dictionary, m Message) (data string, err error) {
// TODO: pass macros so they can be used for validation.
v := &Encoder{inBody: true} // encoder for variables
v.root = v
e := &Encoder{root: v, parent: v, tag: tag} // encoder for messages
err = m.Compile(e)
// This package serves te message package, which in turn is meant to be a
// drop-in replacement for fmt. With the fmt package, format strings are
// evaluated lazily and errors are handled by substituting strings in the
// result, rather then returning an error. Dealing with multiple languages
// makes it more important to check errors ahead of time. We chose to be
// consistent and compatible and allow graceful degradation in case of
// errors.
buf := e.buf[stripPrefix(e.buf):]
if len(v.buf) > 0 {
// Prepend variable block.
b := make([]byte, 1+maxVarintBytes+len(v.buf)+len(buf))
b[0] = byte(msgVars)
b = b[:1+encodeUint(b[1:], uint64(len(v.buf)))]
b = append(b, v.buf...)
b = append(b, buf...)
buf = b
}
if err == nil {
err = v.err
}
return string(buf), err
}
// FirstOf is a message type that prints the first message in the sequence that
// resolves to a match for the given substitution arguments.
type FirstOf []Message
// Compile implements Message.
func (s FirstOf) Compile(e *Encoder) error {
e.EncodeMessageType(msgFirst)
err := ErrIncomplete
for i, m := range s {
if err == nil {
return fmt.Errorf("catalog: message argument %d is complete and blocks subsequent messages", i-1)
}
err = e.EncodeMessage(m)
}
return err
}
// Var defines a message that can be substituted for a placeholder of the same
// name. If an expression does not result in a string after evaluation, Name is
// used as the substitution. For example:
//
// Var{
// Name: "minutes",
// Message: plural.Select(1, "one", "minute"),
// }
//
// will resolve to minute for singular and minutes for plural forms.
type Var struct {
Name string
Message Message
}
var errIsVar = errors.New("catmsg: variable used as message")
// Compile implements Message.
//
// Note that this method merely registers a variable; it does not create an
// encoded message.
func (v *Var) Compile(e *Encoder) error {
if err := e.addVar(v.Name, v.Message); err != nil {
return err
}
// Using a Var by itself is an error. If it is in a sequence followed by
// other messages referring to it, this error will be ignored.
return errIsVar
}
// Raw is a message consisting of a single format string that is passed as is
// to the Renderer.
//
// Note that a Renderer may still do its own variable substitution.
type Raw string
// Compile implements Message.
func (r Raw) Compile(e *Encoder) (err error) {
e.EncodeMessageType(msgRaw)
// Special case: raw strings don't have a size encoding and so don't use
// EncodeString.
e.buf = append(e.buf, r...)
return nil
}
// String is a message consisting of a single format string which contains
// placeholders that may be substituted with variables.
//
// Variable substitutions are marked with placeholders and a variable name of
// the form ${name}. Any other substitutions such as Go templates or
// printf-style substitutions are left to be done by the Renderer.
//
// When evaluation a string interpolation, a Renderer will receive separate
// calls for each placeholder and interstitial string. For example, for the
// message: "%[1]v ${invites} %[2]v to ${their} party." The sequence of calls
// is:
//
// d.Render("%[1]v ")
// d.Arg(1)
// d.Render(resultOfInvites)
// d.Render(" %[2]v to ")
// d.Arg(2)
// d.Render(resultOfTheir)
// d.Render(" party.")
//
// where the messages for "invites" and "their" both use a plural.Select
// referring to the first argument.
//
// Strings may also invoke macros. Macros are essentially variables that can be
// reused. Macros may, for instance, be used to make selections between
// different conjugations of a verb. See the catalog package description for an
// overview of macros.
type String string
// Compile implements Message. It parses the placeholder formats and returns
// any error.
func (s String) Compile(e *Encoder) (err error) {
msg := string(s)
const subStart = "${"
hasHeader := false
p := 0
b := []byte{}
for {
i := strings.Index(msg[p:], subStart)
if i == -1 {
break
}
b = append(b, msg[p:p+i]...)
p += i + len(subStart)
if i = strings.IndexByte(msg[p:], '}'); i == -1 {
b = append(b, "$!(MISSINGBRACE)"...)
err = fmt.Errorf("catmsg: missing '}'")
p = len(msg)
break
}
name := strings.TrimSpace(msg[p : p+i])
if q := strings.IndexByte(name, '('); q == -1 {
if !hasHeader {
hasHeader = true
e.EncodeMessageType(msgString)
}
e.EncodeString(string(b))
e.EncodeSubstitution(name)
b = b[:0]
} else if j := strings.IndexByte(name[q:], ')'); j == -1 {
// TODO: what should the error be?
b = append(b, "$!(MISSINGPAREN)"...)
err = fmt.Errorf("catmsg: missing ')'")
} else if x, sErr := strconv.ParseUint(strings.TrimSpace(name[q+1:q+j]), 10, 32); sErr != nil {
// TODO: handle more than one argument
b = append(b, "$!(BADNUM)"...)
err = fmt.Errorf("catmsg: invalid number %q", strings.TrimSpace(name[q+1:q+j]))
} else {
if !hasHeader {
hasHeader = true
e.EncodeMessageType(msgString)
}
e.EncodeString(string(b))
e.EncodeSubstitution(name[:q], int(x))
b = b[:0]
}
p += i + 1
}
b = append(b, msg[p:]...)
if !hasHeader {
// Simplify string to a raw string.
Raw(string(b)).Compile(e)
} else if len(b) > 0 {
e.EncodeString(string(b))
}
return err
}
// Affix is a message that adds a prefix and suffix to another message.
// This is mostly used add back whitespace to a translation that was stripped
// before sending it out.
type Affix struct {
Message Message
Prefix string
Suffix string
}
// Compile implements Message.
func (a Affix) Compile(e *Encoder) (err error) {
// TODO: consider adding a special message type that just adds a single
// return. This is probably common enough to handle the majority of cases.
// Get some stats first, though.
e.EncodeMessageType(msgAffix)
e.EncodeString(a.Prefix)
e.EncodeString(a.Suffix)
e.EncodeMessage(a.Message)
return nil
}
// 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 catmsg
import (
"errors"
"fmt"
"golang.org/x/text/language"
)
// A Renderer renders a Message.
type Renderer interface {
// Render renders the given string. The given string may be interpreted as a
// format string, such as the one used by the fmt package or a template.
Render(s string)
// Arg returns the i-th argument passed to format a message. This method
// should return nil if there is no such argument. Messages need access to
// arguments to allow selecting a message based on linguistic features of
// those arguments.
Arg(i int) interface{}
}
// A Dictionary specifies a source of messages, including variables or macros.
type Dictionary interface {
// Lookup returns the message for the given key. It returns false for ok if
// such a message could not be found.
Lookup(key string) (data string, ok bool)
// TODO: consider returning an interface, instead of a string. This will
// allow implementations to do their own message type decoding.
}
// An Encoder serializes a Message to a string.
type Encoder struct {
// The root encoder is used for storing encoded variables.
root *Encoder
// The parent encoder provides the surrounding scopes for resolving variable
// names.
parent *Encoder
tag language.Tag
// buf holds the encoded message so far. After a message completes encoding,
// the contents of buf, prefixed by the encoded length, are flushed to the
// parent buffer.
buf []byte
// vars is the lookup table of variables in the current scope.
vars []keyVal
err error
inBody bool // if false next call must be EncodeMessageType
}
type keyVal struct {
key string
offset int
}
// Language reports the language for which the encoded message will be stored
// in the Catalog.
func (e *Encoder) Language() language.Tag { return e.tag }
func (e *Encoder) setError(err error) {
if e.root.err == nil {
e.root.err = err
}
}
// EncodeUint encodes x.
func (e *Encoder) EncodeUint(x uint64) {
e.checkInBody()
var buf [maxVarintBytes]byte
n := encodeUint(buf[:], x)
e.buf = append(e.buf, buf[:n]...)
}
// EncodeString encodes s.
func (e *Encoder) EncodeString(s string) {
e.checkInBody()
e.EncodeUint(uint64(len(s)))
e.buf = append(e.buf, s...)
}
// EncodeMessageType marks the current message to be of type h.
//
// It must be the first call of a Message's Compile method.
func (e *Encoder) EncodeMessageType(h Handle) {
if e.inBody {
panic("catmsg: EncodeMessageType not the first method called")
}
e.inBody = true
e.EncodeUint(uint64(h))
}
// EncodeMessage serializes the given message inline at the current position.
func (e *Encoder) EncodeMessage(m Message) error {
e = &Encoder{root: e.root, parent: e, tag: e.tag}
err := m.Compile(e)
if _, ok := m.(*Var); !ok {
e.flushTo(e.parent)
}
return err
}
func (e *Encoder) checkInBody() {
if !e.inBody {
panic("catmsg: expected prior call to EncodeMessageType")
}
}
// stripPrefix indicates the number of prefix bytes that must be stripped to
// turn a single-element sequence into a message that is just this single member
// without its size prefix. If the message can be stripped, b[1:n] contains the
// size prefix.
func stripPrefix(b []byte) (n int) {
if len(b) > 0 && Handle(b[0]) == msgFirst {
x, n, _ := decodeUint(b[1:])
if 1+n+int(x) == len(b) {
return 1 + n
}
}
return 0
}
func (e *Encoder) flushTo(dst *Encoder) {
data := e.buf
p := stripPrefix(data)
if p > 0 {
data = data[1:]
} else {
// Prefix the size.
dst.EncodeUint(uint64(len(data)))
}
dst.buf = append(dst.buf, data...)
}
func (e *Encoder) addVar(key string, m Message) error {
for _, v := range e.parent.vars {
if v.key == key {
err := fmt.Errorf("catmsg: duplicate variable %q", key)
e.setError(err)
return err
}
}
scope := e.parent
// If a variable message is Incomplete, and does not evaluate to a message
// during execution, we fall back to the variable name. We encode this by
// appending the variable name if the message reports it's incomplete.
err := m.Compile(e)
if err != ErrIncomplete {
e.setError(err)
}
switch {
case len(e.buf) == 1 && Handle(e.buf[0]) == msgFirst: // empty sequence
e.buf = e.buf[:0]
e.inBody = false
fallthrough
case len(e.buf) == 0:
// Empty message.
if err := String(key).Compile(e); err != nil {
e.setError(err)
}
case err == ErrIncomplete:
if Handle(e.buf[0]) != msgFirst {
seq := &Encoder{root: e.root, parent: e}
seq.EncodeMessageType(msgFirst)
e.flushTo(seq)
e = seq
}
// e contains a sequence; append the fallback string.
e.EncodeMessage(String(key))
}
// Flush result to variable heap.
offset := len(e.root.buf)
e.flushTo(e.root)
e.buf = e.buf[:0]
// Record variable offset in current scope.
scope.vars = append(scope.vars, keyVal{key: key, offset: offset})
return err
}
const (
substituteVar = iota
substituteMacro
substituteError
)
// EncodeSubstitution inserts a resolved reference to a variable or macro.
//
// This call must be matched with a call to ExecuteSubstitution at decoding
// time.
func (e *Encoder) EncodeSubstitution(name string, arguments ...int) {
if arity := len(arguments); arity > 0 {
// TODO: also resolve macros.
e.EncodeUint(substituteMacro)
e.EncodeString(name)
for _, a := range arguments {
e.EncodeUint(uint64(a))
}
return
}
for scope := e; scope != nil; scope = scope.parent {
for _, v := range scope.vars {
if v.key != name {
continue
}
e.EncodeUint(substituteVar) // TODO: support arity > 0
e.EncodeUint(uint64(v.offset))
return
}
}
// TODO: refer to dictionary-wide scoped variables.
e.EncodeUint(substituteError)
e.EncodeString(name)
e.setError(fmt.Errorf("catmsg: unknown var %q", name))
}
// A Decoder deserializes and evaluates messages that are encoded by an encoder.
type Decoder struct {
tag language.Tag
dst Renderer
macros Dictionary
err error
vars string
data string
macroArg int // TODO: allow more than one argument
}
// NewDecoder returns a new Decoder.
//
// Decoders are designed to be reused for multiple invocations of Execute.
// Only one goroutine may call Execute concurrently.
func NewDecoder(tag language.Tag, r Renderer, macros Dictionary) *Decoder {
return &Decoder{
tag: tag,
dst: r,
macros: macros,
}
}
func (d *Decoder) setError(err error) {
if d.err == nil {
d.err = err
}
}
// Language returns the language in which the message is being rendered.
//
// The destination language may be a child language of the language used for
// encoding. For instance, a decoding language of "pt-PT" is consistent with an
// encoding language of "pt".
func (d *Decoder) Language() language.Tag { return d.tag }
// Done reports whether there are more bytes to process in this message.
func (d *Decoder) Done() bool { return len(d.data) == 0 }
// Render implements Renderer.
func (d *Decoder) Render(s string) { d.dst.Render(s) }
// Arg implements Renderer.
//
// During evaluation of macros, the argument positions may be mapped to
// arguments that differ from the original call.
func (d *Decoder) Arg(i int) interface{} {
if d.macroArg != 0 {
if i != 1 {
panic("catmsg: only macros with single argument supported")
}
i = d.macroArg
}
return d.dst.Arg(i)
}
// DecodeUint decodes a number that was encoded with EncodeUint and advances the
// position.
func (d *Decoder) DecodeUint() uint64 {
x, n, err := decodeUintString(d.data)
d.data = d.data[n:]
if err != nil {
d.setError(err)
}
return x
}
// DecodeString decodes a string that was encoded with EncodeString and advances
// the position.
func (d *Decoder) DecodeString() string {
size := d.DecodeUint()
s := d.data[:size]
d.data = d.data[size:]
return s
}
// SkipMessage skips the message at the current location and advances the
// position.
func (d *Decoder) SkipMessage() {
n := int(d.DecodeUint())
d.data = d.data[n:]
}
// Execute decodes and evaluates msg.
//
// Only one goroutine may call execute.
func (d *Decoder) Execute(msg string) error {
d.err = nil
if !d.execute(msg) {
return ErrNoMatch
}
return d.err
}
func (d *Decoder) execute(msg string) bool {
saved := d.data
d.data = msg
ok := d.executeMessage()
d.data = saved
return ok
}
// executeMessageFromData is like execute, but also decodes a leading message
// size and clips the given string accordingly.
//
// It reports the number of bytes consumed and whether a message was selected.
func (d *Decoder) executeMessageFromData(s string) (n int, ok bool) {
saved := d.data
d.data = s
size := int(d.DecodeUint())
n = len(s) - len(d.data)
// Sanitize the setting. This allows skipping a size argument for
// RawString and method Done.
d.data = d.data[:size]
ok = d.executeMessage()
n += size - len(d.data)
d.data = saved
return n, ok
}
var errUnknownHandler = errors.New("catmsg: string contains unsupported handler")
// executeMessage reads the handle id, initializes the decoder and executes the
// message. It is assumed that all of d.data[d.p:] is the single message.
func (d *Decoder) executeMessage() bool {
if d.Done() {
// We interpret no data as a valid empty message.
return true
}
handle := d.DecodeUint()
var fn Handler
mutex.Lock()
if int(handle) < len(handlers) {
fn = handlers[handle]
}
mutex.Unlock()
if fn == nil {
d.setError(errUnknownHandler)
d.execute(fmt.Sprintf("\x02$!(UNKNOWNMSGHANDLER=%#x)", handle))
return true
}
return fn(d)
}
// ExecuteMessage decodes and executes the message at the current position.
func (d *Decoder) ExecuteMessage() bool {
n, ok := d.executeMessageFromData(d.data)
d.data = d.data[n:]
return ok
}
// ExecuteSubstitution executes the message corresponding to the substitution
// as encoded by EncodeSubstitution.
func (d *Decoder) ExecuteSubstitution() {
switch x := d.DecodeUint(); x {
case substituteVar:
offset := d.DecodeUint()
d.executeMessageFromData(d.vars[offset:])
case substituteMacro:
name := d.DecodeString()
data, ok := d.macros.Lookup(name)
old := d.macroArg
// TODO: support macros of arity other than 1.
d.macroArg = int(d.DecodeUint())
switch {
case !ok:
// TODO: detect this at creation time.
d.setError(fmt.Errorf("catmsg: undefined macro %q", name))
fallthrough
case !d.execute(data):
d.dst.Render(name) // fall back to macro name.
}
d.macroArg = old
case substituteError:
d.dst.Render(d.DecodeString())
default:
panic("catmsg: unreachable")
}
}
// 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 catmsg
// This file implements varint encoding analogous to the one in encoding/binary.
// We need a string version of this function, so we add that here and then add
// the rest for consistency.
import "errors"
var (
errIllegalVarint = errors.New("catmsg: illegal varint")
errVarintTooLarge = errors.New("catmsg: varint too large for uint64")
)
const maxVarintBytes = 10 // maximum length of a varint
// encodeUint encodes x as a variable-sized integer into buf and returns the
// number of bytes written. buf must be at least maxVarintBytes long
func encodeUint(buf []byte, x uint64) (n int) {
for ; x > 127; n++ {
buf[n] = 0x80 | uint8(x&0x7F)
x >>= 7
}
buf[n] = uint8(x)
n++
return n
}
func decodeUintString(s string) (x uint64, size int, err error) {
i := 0
for shift := uint(0); shift < 64; shift += 7 {
if i >= len(s) {
return 0, i, errIllegalVarint
}
b := uint64(s[i])
i++
x |= (b & 0x7F) << shift
if b&0x80 == 0 {
return x, i, nil
}
}
return 0, i, errVarintTooLarge
}
func decodeUint(b []byte) (x uint64, size int, err error) {
i := 0
for shift := uint(0); shift < 64; shift += 7 {
if i >= len(b) {
return 0, i, errIllegalVarint
}
c := uint64(b[i])
i++
x |= (c & 0x7F) << shift
if c&0x80 == 0 {
return x, i, nil
}
}
return 0, i, errVarintTooLarge
}
// 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.
package colltab
import (
"fmt"
"unicode"
)
// Level identifies the collation comparison level.
// The primary level corresponds to the basic sorting of text.
// The secondary level corresponds to accents and related linguistic elements.
// The tertiary level corresponds to casing and related concepts.
// The quaternary level is derived from the other levels by the
// various algorithms for handling variable elements.
type Level int
const (
Primary Level = iota
Secondary
Tertiary
Quaternary
Identity
NumLevels
)
const (
defaultSecondary = 0x20
defaultTertiary = 0x2
maxTertiary = 0x1F
MaxQuaternary = 0x1FFFFF // 21 bits.
)
// Elem is a representation of a collation element. This API provides ways to encode
// and decode Elems. Implementations of collation tables may use values greater
// or equal to PrivateUse for their own purposes. However, these should never be
// returned by AppendNext.
type Elem uint32
const (
maxCE Elem = 0xAFFFFFFF
PrivateUse = minContract
minContract = 0xC0000000
maxContract = 0xDFFFFFFF
minExpand = 0xE0000000
maxExpand = 0xEFFFFFFF
minDecomp = 0xF0000000
)
type ceType int
const (
ceNormal ceType = iota // ceNormal includes implicits (ce == 0)
ceContractionIndex // rune can be a start of a contraction
ceExpansionIndex // rune expands into a sequence of collation elements
ceDecompose // rune expands using NFKC decomposition
)
func (ce Elem) ctype() ceType {
if ce <= maxCE {
return ceNormal
}
if ce <= maxContract {
return ceContractionIndex
} else {
if ce <= maxExpand {
return ceExpansionIndex
}
return ceDecompose
}
}
// For normal collation elements, we assume that a collation element either has
// a primary or non-default secondary value, not both.
// Collation elements with a primary value are of the form
//
// 01pppppp pppppppp ppppppp0 ssssssss
// - p* is primary collation value
// - s* is the secondary collation value
// 00pppppp pppppppp ppppppps sssttttt, where
// - p* is primary collation value
// - s* offset of secondary from default value.
// - t* is the tertiary collation value
// 100ttttt cccccccc pppppppp pppppppp
// - t* is the tertiar collation value
// - c* is the canonical combining class
// - p* is the primary collation value
//
// Collation elements with a secondary value are of the form
//
// 1010cccc ccccssss ssssssss tttttttt, where
// - c* is the canonical combining class
// - s* is the secondary collation value
// - t* is the tertiary collation value
// 11qqqqqq qqqqqqqq qqqqqqq0 00000000
// - q* quaternary value
const (
ceTypeMask = 0xC0000000
ceTypeMaskExt = 0xE0000000
ceIgnoreMask = 0xF00FFFFF
ceType1 = 0x40000000
ceType2 = 0x00000000
ceType3or4 = 0x80000000
ceType4 = 0xA0000000
ceTypeQ = 0xC0000000
Ignore = ceType4
firstNonPrimary = 0x80000000
lastSpecialPrimary = 0xA0000000
secondaryMask = 0x80000000
hasTertiaryMask = 0x40000000
primaryValueMask = 0x3FFFFE00
maxPrimaryBits = 21
compactPrimaryBits = 16
maxSecondaryBits = 12
maxTertiaryBits = 8
maxCCCBits = 8
maxSecondaryCompactBits = 8
maxSecondaryDiffBits = 4
maxTertiaryCompactBits = 5
primaryShift = 9
compactSecondaryShift = 5
minCompactSecondary = defaultSecondary - 4
)
func makeImplicitCE(primary int) Elem {
return ceType1 | Elem(primary<<primaryShift) | defaultSecondary
}
// MakeElem returns an Elem for the given values. It will return an error
// if the given combination of values is invalid.
func MakeElem(primary, secondary, tertiary int, ccc uint8) (Elem, error) {
if w := primary; w >= 1<<maxPrimaryBits || w < 0 {
return 0, fmt.Errorf("makeCE: primary weight out of bounds: %x >= %x", w, 1<<maxPrimaryBits)
}
if w := secondary; w >= 1<<maxSecondaryBits || w < 0 {
return 0, fmt.Errorf("makeCE: secondary weight out of bounds: %x >= %x", w, 1<<maxSecondaryBits)
}
if w := tertiary; w >= 1<<maxTertiaryBits || w < 0 {
return 0, fmt.Errorf("makeCE: tertiary weight out of bounds: %x >= %x", w, 1<<maxTertiaryBits)
}
ce := Elem(0)
if primary != 0 {
if ccc != 0 {
if primary >= 1<<compactPrimaryBits {
return 0, fmt.Errorf("makeCE: primary weight with non-zero CCC out of bounds: %x >= %x", primary, 1<<compactPrimaryBits)
}
if secondary != defaultSecondary {
return 0, fmt.Errorf("makeCE: cannot combine non-default secondary value (%x) with non-zero CCC (%x)", secondary, ccc)
}
ce = Elem(tertiary << (compactPrimaryBits + maxCCCBits))
ce |= Elem(ccc) << compactPrimaryBits
ce |= Elem(primary)
ce |= ceType3or4
} else if tertiary == defaultTertiary {
if secondary >= 1<<maxSecondaryCompactBits {
return 0, fmt.Errorf("makeCE: secondary weight with non-zero primary out of bounds: %x >= %x", secondary, 1<<maxSecondaryCompactBits)
}
ce = Elem(primary<<(maxSecondaryCompactBits+1) + secondary)
ce |= ceType1
} else {
d := secondary - defaultSecondary + maxSecondaryDiffBits
if d >= 1<<maxSecondaryDiffBits || d < 0 {
return 0, fmt.Errorf("makeCE: secondary weight diff out of bounds: %x < 0 || %x > %x", d, d, 1<<maxSecondaryDiffBits)
}
if tertiary >= 1<<maxTertiaryCompactBits {
return 0, fmt.Errorf("makeCE: tertiary weight with non-zero primary out of bounds: %x > %x", tertiary, 1<<maxTertiaryCompactBits)
}
ce = Elem(primary<<maxSecondaryDiffBits + d)
ce = ce<<maxTertiaryCompactBits + Elem(tertiary)
}
} else {
ce = Elem(secondary<<maxTertiaryBits + tertiary)
ce += Elem(ccc) << (maxSecondaryBits + maxTertiaryBits)
ce |= ceType4
}
return ce, nil
}
// MakeQuaternary returns an Elem with the given quaternary value.
func MakeQuaternary(v int) Elem {
return ceTypeQ | Elem(v<<primaryShift)
}
// Mask sets weights for any level smaller than l to 0.
// The resulting Elem can be used to test for equality with
// other Elems to which the same mask has been applied.
func (ce Elem) Mask(l Level) uint32 {
return 0
}
// CCC returns the canonical combining class associated with the underlying character,
// if applicable, or 0 otherwise.
func (ce Elem) CCC() uint8 {
if ce&ceType3or4 != 0 {
if ce&ceType4 == ceType3or4 {
return uint8(ce >> 16)
}
return uint8(ce >> 20)
}
return 0
}
// Primary returns the primary collation weight for ce.
func (ce Elem) Primary() int {
if ce >= firstNonPrimary {
if ce > lastSpecialPrimary {
return 0
}
return int(uint16(ce))
}
return int(ce&primaryValueMask) >> primaryShift
}
// Secondary returns the secondary collation weight for ce.
func (ce Elem) Secondary() int {
switch ce & ceTypeMask {
case ceType1:
return int(uint8(ce))
case ceType2:
return minCompactSecondary + int((ce>>compactSecondaryShift)&0xF)
case ceType3or4:
if ce < ceType4 {
return defaultSecondary
}
return int(ce>>8) & 0xFFF
case ceTypeQ:
return 0
}
panic("should not reach here")
}
// Tertiary returns the tertiary collation weight for ce.
func (ce Elem) Tertiary() uint8 {
if ce&hasTertiaryMask == 0 {
if ce&ceType3or4 == 0 {
return uint8(ce & 0x1F)
}
if ce&ceType4 == ceType4 {
return uint8(ce)
}
return uint8(ce>>24) & 0x1F // type 2
} else if ce&ceTypeMask == ceType1 {
return defaultTertiary
}
// ce is a quaternary value.
return 0
}
func (ce Elem) updateTertiary(t uint8) Elem {
if ce&ceTypeMask == ceType1 {
// convert to type 4
nce := ce & primaryValueMask
nce |= Elem(uint8(ce)-minCompactSecondary) << compactSecondaryShift
ce = nce
} else if ce&ceTypeMaskExt == ceType3or4 {
ce &= ^Elem(maxTertiary << 24)
return ce | (Elem(t) << 24)
} else {
// type 2 or 4
ce &= ^Elem(maxTertiary)
}
return ce | Elem(t)
}
// Quaternary returns the quaternary value if explicitly specified,
// 0 if ce == Ignore, or MaxQuaternary otherwise.
// Quaternary values are used only for shifted variants.
func (ce Elem) Quaternary() int {
if ce&ceTypeMask == ceTypeQ {
return int(ce&primaryValueMask) >> primaryShift
} else if ce&ceIgnoreMask == Ignore {
return 0
}
return MaxQuaternary
}
// Weight returns the collation weight for the given level.
func (ce Elem) Weight(l Level) int {
switch l {
case Primary:
return ce.Primary()
case Secondary:
return ce.Secondary()
case Tertiary:
return int(ce.Tertiary())
case Quaternary:
return ce.Quaternary()
}
return 0 // return 0 (ignore) for undefined levels.
}
// For contractions, collation elements are of the form
// 110bbbbb bbbbbbbb iiiiiiii iiiinnnn, where
// - n* is the size of the first node in the contraction trie.
// - i* is the index of the first node in the contraction trie.
// - b* is the offset into the contraction collation element table.
//
// See contract.go for details on the contraction trie.
const (
maxNBits = 4
maxTrieIndexBits = 12
maxContractOffsetBits = 13
)
func splitContractIndex(ce Elem) (index, n, offset int) {
n = int(ce & (1<<maxNBits - 1))
ce >>= maxNBits
index = int(ce & (1<<maxTrieIndexBits - 1))
ce >>= maxTrieIndexBits
offset = int(ce & (1<<maxContractOffsetBits - 1))
return
}
// For expansions, Elems are of the form 11100000 00000000 bbbbbbbb bbbbbbbb,
// where b* is the index into the expansion sequence table.
const maxExpandIndexBits = 16
func splitExpandIndex(ce Elem) (index int) {
return int(uint16(ce))
}
// Some runes can be expanded using NFKD decomposition. Instead of storing the full
// sequence of collation elements, we decompose the rune and lookup the collation
// elements for each rune in the decomposition and modify the tertiary weights.
// The Elem, in this case, is of the form 11110000 00000000 wwwwwwww vvvvvvvv, where
// - v* is the replacement tertiary weight for the first rune,
// - w* is the replacement tertiary weight for the second rune,
//
// Tertiary weights of subsequent runes should be replaced with maxTertiary.
// See https://www.unicode.org/reports/tr10/#Compatibility_Decompositions for more details.
func splitDecompose(ce Elem) (t1, t2 uint8) {
return uint8(ce), uint8(ce >> 8)
}
const (
// These constants were taken from https://www.unicode.org/versions/Unicode6.0.0/ch12.pdf.
minUnified rune = 0x4E00
maxUnified = 0x9FFF
minCompatibility = 0xF900
maxCompatibility = 0xFAFF
minRare = 0x3400
maxRare = 0x4DBF
)
const (
commonUnifiedOffset = 0x10000
rareUnifiedOffset = 0x20000 // largest rune in common is U+FAFF
otherOffset = 0x50000 // largest rune in rare is U+2FA1D
illegalOffset = otherOffset + int(unicode.MaxRune)
maxPrimary = illegalOffset + 1
)
// implicitPrimary returns the primary weight for the given rune
// for which there is no entry for the rune in the collation table.
// We take a different approach from the one specified in
// https://unicode.org/reports/tr10/#Implicit_Weights,
// but preserve the resulting relative ordering of the runes.
func implicitPrimary(r rune) int {
if unicode.Is(unicode.Ideographic, r) {
if r >= minUnified && r <= maxUnified {
// The most common case for CJK.
return int(r) + commonUnifiedOffset
}
if r >= minCompatibility && r <= maxCompatibility {
// This will typically not hit. The DUCET explicitly specifies mappings
// for all characters that do not decompose.
return int(r) + commonUnifiedOffset
}
return int(r) + rareUnifiedOffset
}
return int(r) + otherOffset
}
// 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.
// Package colltab contains functionality related to collation tables.
// It is only to be used by the collate and search packages.
package colltab // import "golang.org/x/text/internal/colltab"
import (
"sort"
"golang.org/x/text/language"
)
// MatchLang finds the index of t in tags, using a matching algorithm used for
// collation and search. tags[0] must be language.Und, the remaining tags should
// be sorted alphabetically.
//
// Language matching for collation and search is different from the matching
// defined by language.Matcher: the (inferred) base language must be an exact
// match for the relevant fields. For example, "gsw" should not match "de".
// Also the parent relation is different, as a parent may have a different
// script. So usually the parent of zh-Hant is und, whereas for MatchLang it is
// zh.
func MatchLang(t language.Tag, tags []language.Tag) int {
// Canonicalize the values, including collapsing macro languages.
t, _ = language.All.Canonicalize(t)
base, conf := t.Base()
// Estimate the base language, but only use high-confidence values.
if conf < language.High {
// The root locale supports "search" and "standard". We assume that any
// implementation will only use one of both.
return 0
}
// Maximize base and script and normalize the tag.
if _, s, r := t.Raw(); (r != language.Region{}) {
p, _ := language.Raw.Compose(base, s, r)
// Taking the parent forces the script to be maximized.
p = p.Parent()
// Add back region and extensions.
t, _ = language.Raw.Compose(p, r, t.Extensions())
} else {
// Set the maximized base language.
t, _ = language.Raw.Compose(base, s, t.Extensions())
}
// Find start index of the language tag.
start := 1 + sort.Search(len(tags)-1, func(i int) bool {
b, _, _ := tags[i+1].Raw()
return base.String() <= b.String()
})
if start < len(tags) {
if b, _, _ := tags[start].Raw(); b != base {
return 0
}
}
// Besides the base language, script and region, only the collation type and
// the custom variant defined in the 'u' extension are used to distinguish a
// locale.
// Strip all variants and extensions and add back the custom variant.
tdef, _ := language.Raw.Compose(t.Raw())
tdef, _ = tdef.SetTypeForKey("va", t.TypeForKey("va"))
// First search for a specialized collation type, if present.
try := []language.Tag{tdef}
if co := t.TypeForKey("co"); co != "" {
tco, _ := tdef.SetTypeForKey("co", co)
try = []language.Tag{tco, tdef}
}
for _, tx := range try {
for ; tx != language.Und; tx = parent(tx) {
for i, t := range tags[start:] {
if b, _, _ := t.Raw(); b != base {
break
}
if tx == t {
return start + i
}
}
}
}
return 0
}
// parent computes the structural parent. This means inheritance may change
// script. So, unlike the CLDR parent, parent(zh-Hant) == zh.
func parent(t language.Tag) language.Tag {
if t.TypeForKey("va") != "" {
t, _ = t.SetTypeForKey("va", "")
return t
}
result := language.Und
if b, s, r := t.Raw(); (r != language.Region{}) {
result, _ = language.Raw.Compose(b, s, t.Extensions())
} else if (s != language.Script{}) {
result, _ = language.Raw.Compose(b, t.Extensions())
} else if (b != language.Base{}) {
result, _ = language.Raw.Compose(t.Extensions())
}
return result
}
// 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.
package colltab
import "unicode/utf8"
// For a description of ContractTrieSet, see text/collate/build/contract.go.
type ContractTrieSet []struct{ L, H, N, I uint8 }
// ctScanner is used to match a trie to an input sequence.
// A contraction may match a non-contiguous sequence of bytes in an input string.
// For example, if there is a contraction for <a, combining_ring>, it should match
// the sequence <a, combining_cedilla, combining_ring>, as combining_cedilla does
// not block combining_ring.
// ctScanner does not automatically skip over non-blocking non-starters, but rather
// retains the state of the last match and leaves it up to the user to continue
// the match at the appropriate points.
type ctScanner struct {
states ContractTrieSet
s []byte
n int
index int
pindex int
done bool
}
type ctScannerString struct {
states ContractTrieSet
s string
n int
index int
pindex int
done bool
}
func (t ContractTrieSet) scanner(index, n int, b []byte) ctScanner {
return ctScanner{s: b, states: t[index:], n: n}
}
func (t ContractTrieSet) scannerString(index, n int, str string) ctScannerString {
return ctScannerString{s: str, states: t[index:], n: n}
}
// result returns the offset i and bytes consumed p so far. If no suffix
// matched, i and p will be 0.
func (s *ctScanner) result() (i, p int) {
return s.index, s.pindex
}
func (s *ctScannerString) result() (i, p int) {
return s.index, s.pindex
}
const (
final = 0
noIndex = 0xFF
)
// scan matches the longest suffix at the current location in the input
// and returns the number of bytes consumed.
func (s *ctScanner) scan(p int) int {
pr := p // the p at the rune start
str := s.s
states, n := s.states, s.n
for i := 0; i < n && p < len(str); {
e := states[i]
c := str[p]
// TODO: a significant number of contractions are of a form that
// cannot match discontiguous UTF-8 in a normalized string. We could let
// a negative value of e.n mean that we can set s.done = true and avoid
// the need for additional matches.
if c >= e.L {
if e.L == c {
p++
if e.I != noIndex {
s.index = int(e.I)
s.pindex = p
}
if e.N != final {
i, states, n = 0, states[int(e.H)+n:], int(e.N)
if p >= len(str) || utf8.RuneStart(str[p]) {
s.states, s.n, pr = states, n, p
}
} else {
s.done = true
return p
}
continue
} else if e.N == final && c <= e.H {
p++
s.done = true
s.index = int(c-e.L) + int(e.I)
s.pindex = p
return p
}
}
i++
}
return pr
}
// scan is a verbatim copy of ctScanner.scan.
func (s *ctScannerString) scan(p int) int {
pr := p // the p at the rune start
str := s.s
states, n := s.states, s.n
for i := 0; i < n && p < len(str); {
e := states[i]
c := str[p]
// TODO: a significant number of contractions are of a form that
// cannot match discontiguous UTF-8 in a normalized string. We could let
// a negative value of e.n mean that we can set s.done = true and avoid
// the need for additional matches.
if c >= e.L {
if e.L == c {
p++
if e.I != noIndex {
s.index = int(e.I)
s.pindex = p
}
if e.N != final {
i, states, n = 0, states[int(e.H)+n:], int(e.N)
if p >= len(str) || utf8.RuneStart(str[p]) {
s.states, s.n, pr = states, n, p
}
} else {
s.done = true
return p
}
continue
} else if e.N == final && c <= e.H {
p++
s.done = true
s.index = int(c-e.L) + int(e.I)
s.pindex = p
return p
}
}
i++
}
return pr
}
// 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.
package colltab
// An Iter incrementally converts chunks of the input text to collation
// elements, while ensuring that the collation elements are in normalized order
// (that is, they are in the order as if the input text were normalized first).
type Iter struct {
Weighter Weighter
Elems []Elem
// N is the number of elements in Elems that will not be reordered on
// subsequent iterations, N <= len(Elems).
N int
bytes []byte
str string
// Because the Elems buffer may contain collation elements that are needed
// for look-ahead, we need two positions in the text (bytes or str): one for
// the end position in the text for the current iteration and one for the
// start of the next call to appendNext.
pEnd int // end position in text corresponding to N.
pNext int // pEnd <= pNext.
}
// Reset sets the position in the current input text to p and discards any
// results obtained so far.
func (i *Iter) Reset(p int) {
i.Elems = i.Elems[:0]
i.N = 0
i.pEnd = p
i.pNext = p
}
// Len returns the length of the input text.
func (i *Iter) Len() int {
if i.bytes != nil {
return len(i.bytes)
}
return len(i.str)
}
// Discard removes the collation elements up to N.
func (i *Iter) Discard() {
// TODO: change this such that only modifiers following starters will have
// to be copied.
i.Elems = i.Elems[:copy(i.Elems, i.Elems[i.N:])]
i.N = 0
}
// End returns the end position of the input text for which Next has returned
// results.
func (i *Iter) End() int {
return i.pEnd
}
// SetInput resets i to input s.
func (i *Iter) SetInput(s []byte) {
i.bytes = s
i.str = ""
i.Reset(0)
}
// SetInputString resets i to input s.
func (i *Iter) SetInputString(s string) {
i.str = s
i.bytes = nil
i.Reset(0)
}
func (i *Iter) done() bool {
return i.pNext >= len(i.str) && i.pNext >= len(i.bytes)
}
func (i *Iter) appendNext() bool {
if i.done() {
return false
}
var sz int
if i.bytes == nil {
i.Elems, sz = i.Weighter.AppendNextString(i.Elems, i.str[i.pNext:])
} else {
i.Elems, sz = i.Weighter.AppendNext(i.Elems, i.bytes[i.pNext:])
}
if sz == 0 {
sz = 1
}
i.pNext += sz
return true
}
// Next appends Elems to the internal array. On each iteration, it will either
// add starters or modifiers. In the majority of cases, an Elem with a primary
// value > 0 will have a CCC of 0. The CCC values of collation elements are also
// used to detect if the input string was not normalized and to adjust the
// result accordingly.
func (i *Iter) Next() bool {
if i.N == len(i.Elems) && !i.appendNext() {
return false
}
// Check if the current segment starts with a starter.
prevCCC := i.Elems[len(i.Elems)-1].CCC()
if prevCCC == 0 {
i.N = len(i.Elems)
i.pEnd = i.pNext
return true
} else if i.Elems[i.N].CCC() == 0 {
// set i.N to only cover part of i.Elems for which prevCCC == 0 and
// use rest for the next call to next.
for i.N++; i.N < len(i.Elems) && i.Elems[i.N].CCC() == 0; i.N++ {
}
i.pEnd = i.pNext
return true
}
// The current (partial) segment starts with modifiers. We need to collect
// all successive modifiers to ensure that they are normalized.
for {
p := len(i.Elems)
i.pEnd = i.pNext
if !i.appendNext() {
break
}
if ccc := i.Elems[p].CCC(); ccc == 0 || len(i.Elems)-i.N > maxCombiningCharacters {
// Leave the starter for the next iteration. This ensures that we
// do not return sequences of collation elements that cross two
// segments.
//
// TODO: handle large number of combining characters by fully
// normalizing the input segment before iteration. This ensures
// results are consistent across the text repo.
i.N = p
return true
} else if ccc < prevCCC {
i.doNorm(p, ccc) // should be rare, never occurs for NFD and FCC.
} else {
prevCCC = ccc
}
}
done := len(i.Elems) != i.N
i.N = len(i.Elems)
return done
}
// nextNoNorm is the same as next, but does not "normalize" the collation
// elements.
func (i *Iter) nextNoNorm() bool {
// TODO: remove this function. Using this instead of next does not seem
// to improve performance in any significant way. We retain this until
// later for evaluation purposes.
if i.done() {
return false
}
i.appendNext()
i.N = len(i.Elems)
return true
}
const maxCombiningCharacters = 30
// doNorm reorders the collation elements in i.Elems.
// It assumes that blocks of collation elements added with appendNext
// either start and end with the same CCC or start with CCC == 0.
// This allows for a single insertion point for the entire block.
// The correctness of this assumption is verified in builder.go.
func (i *Iter) doNorm(p int, ccc uint8) {
n := len(i.Elems)
k := p
for p--; p > i.N && ccc < i.Elems[p-1].CCC(); p-- {
}
i.Elems = append(i.Elems, i.Elems[p:k]...)
copy(i.Elems[p:], i.Elems[k:])
i.Elems = i.Elems[:n]
}
// 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 colltab
import (
"unicode"
"unicode/utf8"
)
// NewNumericWeighter wraps w to replace individual digits to sort based on their
// numeric value.
//
// Weighter w must have a free primary weight after the primary weight for 9.
// If this is not the case, numeric value will sort at the same primary level
// as the first primary sorting after 9.
func NewNumericWeighter(w Weighter) Weighter {
getElem := func(s string) Elem {
elems, _ := w.AppendNextString(nil, s)
return elems[0]
}
nine := getElem("9")
// Numbers should order before zero, but the DUCET has no room for this.
// TODO: move before zero once we use fractional collation elements.
ns, _ := MakeElem(nine.Primary()+1, nine.Secondary(), int(nine.Tertiary()), 0)
return &numericWeighter{
Weighter: w,
// We assume that w sorts digits of different kinds in order of numeric
// value and that the tertiary weight order is preserved.
//
// TODO: evaluate whether it is worth basing the ranges on the Elem
// encoding itself once the move to fractional weights is complete.
zero: getElem("0"),
zeroSpecialLo: getElem("0"), // U+FF10 FULLWIDTH DIGIT ZERO
zeroSpecialHi: getElem("₀"), // U+2080 SUBSCRIPT ZERO
nine: nine,
nineSpecialHi: getElem("₉"), // U+2089 SUBSCRIPT NINE
numberStart: ns,
}
}
// A numericWeighter translates a stream of digits into a stream of weights
// representing the numeric value.
type numericWeighter struct {
Weighter
// The Elems below all demarcate boundaries of specific ranges. With the
// current element encoding digits are in two ranges: normal (default
// tertiary value) and special. For most languages, digits have collation
// elements in the normal range.
//
// Note: the range tests are very specific for the element encoding used by
// this implementation. The tests in collate_test.go are designed to fail
// if this code is not updated when an encoding has changed.
zero Elem // normal digit zero
zeroSpecialLo Elem // special digit zero, low tertiary value
zeroSpecialHi Elem // special digit zero, high tertiary value
nine Elem // normal digit nine
nineSpecialHi Elem // special digit nine
numberStart Elem
}
// AppendNext calls the namesake of the underlying weigher, but replaces single
// digits with weights representing their value.
func (nw *numericWeighter) AppendNext(buf []Elem, s []byte) (ce []Elem, n int) {
ce, n = nw.Weighter.AppendNext(buf, s)
nc := numberConverter{
elems: buf,
w: nw,
b: s,
}
isZero, ok := nc.checkNextDigit(ce)
if !ok {
return ce, n
}
// ce might have been grown already, so take it instead of buf.
nc.init(ce, len(buf), isZero)
for n < len(s) {
ce, sz := nw.Weighter.AppendNext(nc.elems, s[n:])
nc.b = s
n += sz
if !nc.update(ce) {
break
}
}
return nc.result(), n
}
// AppendNextString calls the namesake of the underlying weigher, but replaces
// single digits with weights representing their value.
func (nw *numericWeighter) AppendNextString(buf []Elem, s string) (ce []Elem, n int) {
ce, n = nw.Weighter.AppendNextString(buf, s)
nc := numberConverter{
elems: buf,
w: nw,
s: s,
}
isZero, ok := nc.checkNextDigit(ce)
if !ok {
return ce, n
}
nc.init(ce, len(buf), isZero)
for n < len(s) {
ce, sz := nw.Weighter.AppendNextString(nc.elems, s[n:])
nc.s = s
n += sz
if !nc.update(ce) {
break
}
}
return nc.result(), n
}
type numberConverter struct {
w *numericWeighter
elems []Elem
nDigits int
lenIndex int
s string // set if the input was of type string
b []byte // set if the input was of type []byte
}
// init completes initialization of a numberConverter and prepares it for adding
// more digits. elems is assumed to have a digit starting at oldLen.
func (nc *numberConverter) init(elems []Elem, oldLen int, isZero bool) {
// Insert a marker indicating the start of a number and a placeholder
// for the number of digits.
if isZero {
elems = append(elems[:oldLen], nc.w.numberStart, 0)
} else {
elems = append(elems, 0, 0)
copy(elems[oldLen+2:], elems[oldLen:])
elems[oldLen] = nc.w.numberStart
elems[oldLen+1] = 0
nc.nDigits = 1
}
nc.elems = elems
nc.lenIndex = oldLen + 1
}
// checkNextDigit reports whether bufNew adds a single digit relative to the old
// buffer. If it does, it also reports whether this digit is zero.
func (nc *numberConverter) checkNextDigit(bufNew []Elem) (isZero, ok bool) {
if len(nc.elems) >= len(bufNew) {
return false, false
}
e := bufNew[len(nc.elems)]
if e < nc.w.zeroSpecialLo || nc.w.nine < e {
// Not a number.
return false, false
}
if e < nc.w.zero {
if e > nc.w.nineSpecialHi {
// Not a number.
return false, false
}
if !nc.isDigit() {
return false, false
}
isZero = e <= nc.w.zeroSpecialHi
} else {
// This is the common case if we encounter a digit.
isZero = e == nc.w.zero
}
// Test the remaining added collation elements have a zero primary value.
if n := len(bufNew) - len(nc.elems); n > 1 {
for i := len(nc.elems) + 1; i < len(bufNew); i++ {
if bufNew[i].Primary() != 0 {
return false, false
}
}
// In some rare cases, collation elements will encode runes in
// unicode.No as a digit. For example Ethiopic digits (U+1369 - U+1371)
// are not in Nd. Also some digits that clearly belong in unicode.No,
// like U+0C78 TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR, have
// collation elements indistinguishable from normal digits.
// Unfortunately, this means we need to make this check for nearly all
// non-Latin digits.
//
// TODO: check the performance impact and find something better if it is
// an issue.
if !nc.isDigit() {
return false, false
}
}
return isZero, true
}
func (nc *numberConverter) isDigit() bool {
if nc.b != nil {
r, _ := utf8.DecodeRune(nc.b)
return unicode.In(r, unicode.Nd)
}
r, _ := utf8.DecodeRuneInString(nc.s)
return unicode.In(r, unicode.Nd)
}
// We currently support a maximum of about 2M digits (the number of primary
// values). Such numbers will compare correctly against small numbers, but their
// comparison against other large numbers is undefined.
//
// TODO: define a proper fallback, such as comparing large numbers textually or
// actually allowing numbers of unlimited length.
//
// TODO: cap this to a lower number (like 100) and maybe allow a larger number
// in an option?
const maxDigits = 1<<maxPrimaryBits - 1
func (nc *numberConverter) update(elems []Elem) bool {
isZero, ok := nc.checkNextDigit(elems)
if nc.nDigits == 0 && isZero {
return true
}
nc.elems = elems
if !ok {
return false
}
nc.nDigits++
return nc.nDigits < maxDigits
}
// result fills in the length element for the digit sequence and returns the
// completed collation elements.
func (nc *numberConverter) result() []Elem {
e, _ := MakeElem(nc.nDigits, defaultSecondary, defaultTertiary, 0)
nc.elems[nc.lenIndex] = e
return nc.elems
}
// 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.
package colltab
import (
"unicode/utf8"
"golang.org/x/text/unicode/norm"
)
// Table holds all collation data for a given collation ordering.
type Table struct {
Index Trie // main trie
// expansion info
ExpandElem []uint32
// contraction info
ContractTries ContractTrieSet
ContractElem []uint32
MaxContractLen int
VariableTop uint32
}
func (t *Table) AppendNext(w []Elem, b []byte) (res []Elem, n int) {
return t.appendNext(w, source{bytes: b})
}
func (t *Table) AppendNextString(w []Elem, s string) (res []Elem, n int) {
return t.appendNext(w, source{str: s})
}
func (t *Table) Start(p int, b []byte) int {
// TODO: implement
panic("not implemented")
}
func (t *Table) StartString(p int, s string) int {
// TODO: implement
panic("not implemented")
}
func (t *Table) Domain() []string {
// TODO: implement
panic("not implemented")
}
func (t *Table) Top() uint32 {
return t.VariableTop
}
type source struct {
str string
bytes []byte
}
func (src *source) lookup(t *Table) (ce Elem, sz int) {
if src.bytes == nil {
return t.Index.lookupString(src.str)
}
return t.Index.lookup(src.bytes)
}
func (src *source) tail(sz int) {
if src.bytes == nil {
src.str = src.str[sz:]
} else {
src.bytes = src.bytes[sz:]
}
}
func (src *source) nfd(buf []byte, end int) []byte {
if src.bytes == nil {
return norm.NFD.AppendString(buf[:0], src.str[:end])
}
return norm.NFD.Append(buf[:0], src.bytes[:end]...)
}
func (src *source) rune() (r rune, sz int) {
if src.bytes == nil {
return utf8.DecodeRuneInString(src.str)
}
return utf8.DecodeRune(src.bytes)
}
func (src *source) properties(f norm.Form) norm.Properties {
if src.bytes == nil {
return f.PropertiesString(src.str)
}
return f.Properties(src.bytes)
}
// appendNext appends the weights corresponding to the next rune or
// contraction in s. If a contraction is matched to a discontinuous
// sequence of runes, the weights for the interstitial runes are
// appended as well. It returns a new slice that includes the appended
// weights and the number of bytes consumed from s.
func (t *Table) appendNext(w []Elem, src source) (res []Elem, n int) {
ce, sz := src.lookup(t)
tp := ce.ctype()
if tp == ceNormal {
if ce == 0 {
r, _ := src.rune()
const (
hangulSize = 3
firstHangul = 0xAC00
lastHangul = 0xD7A3
)
if r >= firstHangul && r <= lastHangul {
// TODO: performance can be considerably improved here.
n = sz
var buf [16]byte // Used for decomposing Hangul.
for b := src.nfd(buf[:0], hangulSize); len(b) > 0; b = b[sz:] {
ce, sz = t.Index.lookup(b)
w = append(w, ce)
}
return w, n
}
ce = makeImplicitCE(implicitPrimary(r))
}
w = append(w, ce)
} else if tp == ceExpansionIndex {
w = t.appendExpansion(w, ce)
} else if tp == ceContractionIndex {
n := 0
src.tail(sz)
if src.bytes == nil {
w, n = t.matchContractionString(w, ce, src.str)
} else {
w, n = t.matchContraction(w, ce, src.bytes)
}
sz += n
} else if tp == ceDecompose {
// Decompose using NFKD and replace tertiary weights.
t1, t2 := splitDecompose(ce)
i := len(w)
nfkd := src.properties(norm.NFKD).Decomposition()
for p := 0; len(nfkd) > 0; nfkd = nfkd[p:] {
w, p = t.appendNext(w, source{bytes: nfkd})
}
w[i] = w[i].updateTertiary(t1)
if i++; i < len(w) {
w[i] = w[i].updateTertiary(t2)
for i++; i < len(w); i++ {
w[i] = w[i].updateTertiary(maxTertiary)
}
}
}
return w, sz
}
func (t *Table) appendExpansion(w []Elem, ce Elem) []Elem {
i := splitExpandIndex(ce)
n := int(t.ExpandElem[i])
i++
for _, ce := range t.ExpandElem[i : i+n] {
w = append(w, Elem(ce))
}
return w
}
func (t *Table) matchContraction(w []Elem, ce Elem, suffix []byte) ([]Elem, int) {
index, n, offset := splitContractIndex(ce)
scan := t.ContractTries.scanner(index, n, suffix)
buf := [norm.MaxSegmentSize]byte{}
bufp := 0
p := scan.scan(0)
if !scan.done && p < len(suffix) && suffix[p] >= utf8.RuneSelf {
// By now we should have filtered most cases.
p0 := p
bufn := 0
rune := norm.NFD.Properties(suffix[p:])
p += rune.Size()
if rune.LeadCCC() != 0 {
prevCC := rune.TrailCCC()
// A gap may only occur in the last normalization segment.
// This also ensures that len(scan.s) < norm.MaxSegmentSize.
if end := norm.NFD.FirstBoundary(suffix[p:]); end != -1 {
scan.s = suffix[:p+end]
}
for p < len(suffix) && !scan.done && suffix[p] >= utf8.RuneSelf {
rune = norm.NFD.Properties(suffix[p:])
if ccc := rune.LeadCCC(); ccc == 0 || prevCC >= ccc {
break
}
prevCC = rune.TrailCCC()
if pp := scan.scan(p); pp != p {
// Copy the interstitial runes for later processing.
bufn += copy(buf[bufn:], suffix[p0:p])
if scan.pindex == pp {
bufp = bufn
}
p, p0 = pp, pp
} else {
p += rune.Size()
}
}
}
}
// Append weights for the matched contraction, which may be an expansion.
i, n := scan.result()
ce = Elem(t.ContractElem[i+offset])
if ce.ctype() == ceNormal {
w = append(w, ce)
} else {
w = t.appendExpansion(w, ce)
}
// Append weights for the runes in the segment not part of the contraction.
for b, p := buf[:bufp], 0; len(b) > 0; b = b[p:] {
w, p = t.appendNext(w, source{bytes: b})
}
return w, n
}
// TODO: unify the two implementations. This is best done after first simplifying
// the algorithm taking into account the inclusion of both NFC and NFD forms
// in the table.
func (t *Table) matchContractionString(w []Elem, ce Elem, suffix string) ([]Elem, int) {
index, n, offset := splitContractIndex(ce)
scan := t.ContractTries.scannerString(index, n, suffix)
buf := [norm.MaxSegmentSize]byte{}
bufp := 0
p := scan.scan(0)
if !scan.done && p < len(suffix) && suffix[p] >= utf8.RuneSelf {
// By now we should have filtered most cases.
p0 := p
bufn := 0
rune := norm.NFD.PropertiesString(suffix[p:])
p += rune.Size()
if rune.LeadCCC() != 0 {
prevCC := rune.TrailCCC()
// A gap may only occur in the last normalization segment.
// This also ensures that len(scan.s) < norm.MaxSegmentSize.
if end := norm.NFD.FirstBoundaryInString(suffix[p:]); end != -1 {
scan.s = suffix[:p+end]
}
for p < len(suffix) && !scan.done && suffix[p] >= utf8.RuneSelf {
rune = norm.NFD.PropertiesString(suffix[p:])
if ccc := rune.LeadCCC(); ccc == 0 || prevCC >= ccc {
break
}
prevCC = rune.TrailCCC()
if pp := scan.scan(p); pp != p {
// Copy the interstitial runes for later processing.
bufn += copy(buf[bufn:], suffix[p0:p])
if scan.pindex == pp {
bufp = bufn
}
p, p0 = pp, pp
} else {
p += rune.Size()
}
}
}
}
// Append weights for the matched contraction, which may be an expansion.
i, n := scan.result()
ce = Elem(t.ContractElem[i+offset])
if ce.ctype() == ceNormal {
w = append(w, ce)
} else {
w = t.appendExpansion(w, ce)
}
// Append weights for the runes in the segment not part of the contraction.
for b, p := buf[:bufp], 0; len(b) > 0; b = b[p:] {
w, p = t.appendNext(w, source{bytes: b})
}
return w, n
}
// 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.
// The trie in this file is used to associate the first full character in an
// UTF-8 string to a collation element. All but the last byte in a UTF-8 byte
// sequence are used to lookup offsets in the index table to be used for the
// next byte. The last byte is used to index into a table of collation elements.
// For a full description, see go.text/collate/build/trie.go.
package colltab
const blockSize = 64
type Trie struct {
Index0 []uint16 // index for first byte (0xC0-0xFF)
Values0 []uint32 // index for first byte (0x00-0x7F)
Index []uint16
Values []uint32
}
const (
t1 = 0x00 // 0000 0000
tx = 0x80 // 1000 0000
t2 = 0xC0 // 1100 0000
t3 = 0xE0 // 1110 0000
t4 = 0xF0 // 1111 0000
t5 = 0xF8 // 1111 1000
t6 = 0xFC // 1111 1100
te = 0xFE // 1111 1110
)
func (t *Trie) lookupValue(n uint16, b byte) Elem {
return Elem(t.Values[int(n)<<6+int(b)])
}
// lookup returns the trie value for the first UTF-8 encoding in s and
// the width in bytes of this encoding. The size will be 0 if s does not
// hold enough bytes to complete the encoding. len(s) must be greater than 0.
func (t *Trie) lookup(s []byte) (v Elem, sz int) {
c0 := s[0]
switch {
case c0 < tx:
return Elem(t.Values0[c0]), 1
case c0 < t2:
return 0, 1
case c0 < t3:
if len(s) < 2 {
return 0, 0
}
i := t.Index0[c0]
c1 := s[1]
if c1 < tx || t2 <= c1 {
return 0, 1
}
return t.lookupValue(i, c1), 2
case c0 < t4:
if len(s) < 3 {
return 0, 0
}
i := t.Index0[c0]
c1 := s[1]
if c1 < tx || t2 <= c1 {
return 0, 1
}
o := int(i)<<6 + int(c1)
i = t.Index[o]
c2 := s[2]
if c2 < tx || t2 <= c2 {
return 0, 2
}
return t.lookupValue(i, c2), 3
case c0 < t5:
if len(s) < 4 {
return 0, 0
}
i := t.Index0[c0]
c1 := s[1]
if c1 < tx || t2 <= c1 {
return 0, 1
}
o := int(i)<<6 + int(c1)
i = t.Index[o]
c2 := s[2]
if c2 < tx || t2 <= c2 {
return 0, 2
}
o = int(i)<<6 + int(c2)
i = t.Index[o]
c3 := s[3]
if c3 < tx || t2 <= c3 {
return 0, 3
}
return t.lookupValue(i, c3), 4
}
// Illegal rune
return 0, 1
}
// The body of lookupString is a verbatim copy of that of lookup.
func (t *Trie) lookupString(s string) (v Elem, sz int) {
c0 := s[0]
switch {
case c0 < tx:
return Elem(t.Values0[c0]), 1
case c0 < t2:
return 0, 1
case c0 < t3:
if len(s) < 2 {
return 0, 0
}
i := t.Index0[c0]
c1 := s[1]
if c1 < tx || t2 <= c1 {
return 0, 1
}
return t.lookupValue(i, c1), 2
case c0 < t4:
if len(s) < 3 {
return 0, 0
}
i := t.Index0[c0]
c1 := s[1]
if c1 < tx || t2 <= c1 {
return 0, 1
}
o := int(i)<<6 + int(c1)
i = t.Index[o]
c2 := s[2]
if c2 < tx || t2 <= c2 {
return 0, 2
}
return t.lookupValue(i, c2), 3
case c0 < t5:
if len(s) < 4 {
return 0, 0
}
i := t.Index0[c0]
c1 := s[1]
if c1 < tx || t2 <= c1 {
return 0, 1
}
o := int(i)<<6 + int(c1)
i = t.Index[o]
c2 := s[2]
if c2 < tx || t2 <= c2 {
return 0, 2
}
o = int(i)<<6 + int(c2)
i = t.Index[o]
c3 := s[3]
if c3 < tx || t2 <= c3 {
return 0, 3
}
return t.lookupValue(i, c3), 4
}
// Illegal rune
return 0, 1
}
// 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 format
import (
"reflect"
"unicode/utf8"
)
// A Parser parses a format string. The result from the parse are set in the
// struct fields.
type Parser struct {
Verb rune
WidthPresent bool
PrecPresent bool
Minus bool
Plus bool
Sharp bool
Space bool
Zero bool
// For the formats %+v %#v, we set the plusV/sharpV flags
// and clear the plus/sharp flags since %+v and %#v are in effect
// different, flagless formats set at the top level.
PlusV bool
SharpV bool
HasIndex bool
Width int
Prec int // precision
// retain arguments across calls.
Args []interface{}
// retain current argument number across calls
ArgNum int
// reordered records whether the format string used argument reordering.
Reordered bool
// goodArgNum records whether the most recent reordering directive was valid.
goodArgNum bool
// position info
format string
startPos int
endPos int
Status Status
}
// Reset initializes a parser to scan format strings for the given args.
func (p *Parser) Reset(args []interface{}) {
p.Args = args
p.ArgNum = 0
p.startPos = 0
p.Reordered = false
}
// Text returns the part of the format string that was parsed by the last call
// to Scan. It returns the original substitution clause if the current scan
// parsed a substitution.
func (p *Parser) Text() string { return p.format[p.startPos:p.endPos] }
// SetFormat sets a new format string to parse. It does not reset the argument
// count.
func (p *Parser) SetFormat(format string) {
p.format = format
p.startPos = 0
p.endPos = 0
}
// Status indicates the result type of a call to Scan.
type Status int
const (
StatusText Status = iota
StatusSubstitution
StatusBadWidthSubstitution
StatusBadPrecSubstitution
StatusNoVerb
StatusBadArgNum
StatusMissingArg
)
// ClearFlags reset the parser to default behavior.
func (p *Parser) ClearFlags() {
p.WidthPresent = false
p.PrecPresent = false
p.Minus = false
p.Plus = false
p.Sharp = false
p.Space = false
p.Zero = false
p.PlusV = false
p.SharpV = false
p.HasIndex = false
}
// Scan scans the next part of the format string and sets the status to
// indicate whether it scanned a string literal, substitution or error.
func (p *Parser) Scan() bool {
p.Status = StatusText
format := p.format
end := len(format)
if p.endPos >= end {
return false
}
afterIndex := false // previous item in format was an index like [3].
p.startPos = p.endPos
p.goodArgNum = true
i := p.startPos
for i < end && format[i] != '%' {
i++
}
if i > p.startPos {
p.endPos = i
return true
}
// Process one verb
i++
p.Status = StatusSubstitution
// Do we have flags?
p.ClearFlags()
simpleFormat:
for ; i < end; i++ {
c := p.format[i]
switch c {
case '#':
p.Sharp = true
case '0':
p.Zero = !p.Minus // Only allow zero padding to the left.
case '+':
p.Plus = true
case '-':
p.Minus = true
p.Zero = false // Do not pad with zeros to the right.
case ' ':
p.Space = true
default:
// Fast path for common case of ascii lower case simple verbs
// without precision or width or argument indices.
if 'a' <= c && c <= 'z' && p.ArgNum < len(p.Args) {
if c == 'v' {
// Go syntax
p.SharpV = p.Sharp
p.Sharp = false
// Struct-field syntax
p.PlusV = p.Plus
p.Plus = false
}
p.Verb = rune(c)
p.ArgNum++
p.endPos = i + 1
return true
}
// Format is more complex than simple flags and a verb or is malformed.
break simpleFormat
}
}
// Do we have an explicit argument index?
i, afterIndex = p.updateArgNumber(format, i)
// Do we have width?
if i < end && format[i] == '*' {
i++
p.Width, p.WidthPresent = p.intFromArg()
if !p.WidthPresent {
p.Status = StatusBadWidthSubstitution
}
// We have a negative width, so take its value and ensure
// that the minus flag is set
if p.Width < 0 {
p.Width = -p.Width
p.Minus = true
p.Zero = false // Do not pad with zeros to the right.
}
afterIndex = false
} else {
p.Width, p.WidthPresent, i = parsenum(format, i, end)
if afterIndex && p.WidthPresent { // "%[3]2d"
p.goodArgNum = false
}
}
// Do we have precision?
if i+1 < end && format[i] == '.' {
i++
if afterIndex { // "%[3].2d"
p.goodArgNum = false
}
i, afterIndex = p.updateArgNumber(format, i)
if i < end && format[i] == '*' {
i++
p.Prec, p.PrecPresent = p.intFromArg()
// Negative precision arguments don't make sense
if p.Prec < 0 {
p.Prec = 0
p.PrecPresent = false
}
if !p.PrecPresent {
p.Status = StatusBadPrecSubstitution
}
afterIndex = false
} else {
p.Prec, p.PrecPresent, i = parsenum(format, i, end)
if !p.PrecPresent {
p.Prec = 0
p.PrecPresent = true
}
}
}
if !afterIndex {
i, afterIndex = p.updateArgNumber(format, i)
}
p.HasIndex = afterIndex
if i >= end {
p.endPos = i
p.Status = StatusNoVerb
return true
}
verb, w := utf8.DecodeRuneInString(format[i:])
p.endPos = i + w
p.Verb = verb
switch {
case verb == '%': // Percent does not absorb operands and ignores f.wid and f.prec.
p.startPos = p.endPos - 1
p.Status = StatusText
case !p.goodArgNum:
p.Status = StatusBadArgNum
case p.ArgNum >= len(p.Args): // No argument left over to print for the current verb.
p.Status = StatusMissingArg
p.ArgNum++
case verb == 'v':
// Go syntax
p.SharpV = p.Sharp
p.Sharp = false
// Struct-field syntax
p.PlusV = p.Plus
p.Plus = false
fallthrough
default:
p.ArgNum++
}
return true
}
// intFromArg gets the ArgNumth element of Args. On return, isInt reports
// whether the argument has integer type.
func (p *Parser) intFromArg() (num int, isInt bool) {
if p.ArgNum < len(p.Args) {
arg := p.Args[p.ArgNum]
num, isInt = arg.(int) // Almost always OK.
if !isInt {
// Work harder.
switch v := reflect.ValueOf(arg); v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n := v.Int()
if int64(int(n)) == n {
num = int(n)
isInt = true
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n := v.Uint()
if int64(n) >= 0 && uint64(int(n)) == n {
num = int(n)
isInt = true
}
default:
// Already 0, false.
}
}
p.ArgNum++
if tooLarge(num) {
num = 0
isInt = false
}
}
return
}
// parseArgNumber returns the value of the bracketed number, minus 1
// (explicit argument numbers are one-indexed but we want zero-indexed).
// The opening bracket is known to be present at format[0].
// The returned values are the index, the number of bytes to consume
// up to the closing paren, if present, and whether the number parsed
// ok. The bytes to consume will be 1 if no closing paren is present.
func parseArgNumber(format string) (index int, wid int, ok bool) {
// There must be at least 3 bytes: [n].
if len(format) < 3 {
return 0, 1, false
}
// Find closing bracket.
for i := 1; i < len(format); i++ {
if format[i] == ']' {
width, ok, newi := parsenum(format, 1, i)
if !ok || newi != i {
return 0, i + 1, false
}
return width - 1, i + 1, true // arg numbers are one-indexed and skip paren.
}
}
return 0, 1, false
}
// updateArgNumber returns the next argument to evaluate, which is either the value of the passed-in
// argNum or the value of the bracketed integer that begins format[i:]. It also returns
// the new value of i, that is, the index of the next byte of the format to process.
func (p *Parser) updateArgNumber(format string, i int) (newi int, found bool) {
if len(format) <= i || format[i] != '[' {
return i, false
}
p.Reordered = true
index, wid, ok := parseArgNumber(format[i:])
if ok && 0 <= index && index < len(p.Args) {
p.ArgNum = index
return i + wid, true
}
p.goodArgNum = false
return i + wid, ok
}
// tooLarge reports whether the magnitude of the integer is
// too large to be used as a formatting width or precision.
func tooLarge(x int) bool {
const max int = 1e6
return x > max || x < -max
}
// parsenum converts ASCII to integer. num is 0 (and isnum is false) if no number present.
func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
if start >= end {
return 0, false, end
}
for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ {
if tooLarge(num) {
return 0, false, end // Overflow; crazy long number most likely.
}
num = num*10 + int(s[newi]-'0')
isnum = true
}
return
}
// 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.
package gen
import (
"bytes"
"encoding/gob"
"fmt"
"hash"
"hash/fnv"
"io"
"log"
"os"
"reflect"
"strings"
"unicode"
"unicode/utf8"
)
// This file contains utilities for generating code.
// TODO: other write methods like:
// - slices, maps, types, etc.
// CodeWriter is a utility for writing structured code. It computes the content
// hash and size of written content. It ensures there are newlines between
// written code blocks.
type CodeWriter struct {
buf bytes.Buffer
Size int
Hash hash.Hash32 // content hash
gob *gob.Encoder
// For comments we skip the usual one-line separator if they are followed by
// a code block.
skipSep bool
}
func (w *CodeWriter) Write(p []byte) (n int, err error) {
return w.buf.Write(p)
}
// NewCodeWriter returns a new CodeWriter.
func NewCodeWriter() *CodeWriter {
h := fnv.New32()
return &CodeWriter{Hash: h, gob: gob.NewEncoder(h)}
}
// WriteGoFile appends the buffer with the total size of all created structures
// and writes it as a Go file to the given file with the given package name.
func (w *CodeWriter) WriteGoFile(filename, pkg string) {
f, err := os.Create(filename)
if err != nil {
log.Fatalf("Could not create file %s: %v", filename, err)
}
defer f.Close()
if _, err = w.WriteGo(f, pkg, ""); err != nil {
log.Fatalf("Error writing file %s: %v", filename, err)
}
}
// WriteVersionedGoFile appends the buffer with the total size of all created
// structures and writes it as a Go file to the given file with the given
// package name and build tags for the current Unicode version,
func (w *CodeWriter) WriteVersionedGoFile(filename, pkg string) {
tags := buildTags()
if tags != "" {
pattern := fileToPattern(filename)
updateBuildTags(pattern)
filename = fmt.Sprintf(pattern, UnicodeVersion())
}
f, err := os.Create(filename)
if err != nil {
log.Fatalf("Could not create file %s: %v", filename, err)
}
defer f.Close()
if _, err = w.WriteGo(f, pkg, tags); err != nil {
log.Fatalf("Error writing file %s: %v", filename, err)
}
}
// WriteGo appends the buffer with the total size of all created structures and
// writes it as a Go file to the given writer with the given package name.
func (w *CodeWriter) WriteGo(out io.Writer, pkg, tags string) (n int, err error) {
sz := w.Size
if sz > 0 {
w.WriteComment("Total table size %d bytes (%dKiB); checksum: %X\n", sz, sz/1024, w.Hash.Sum32())
}
defer w.buf.Reset()
return WriteGo(out, pkg, tags, w.buf.Bytes())
}
func (w *CodeWriter) printf(f string, x ...interface{}) {
fmt.Fprintf(w, f, x...)
}
func (w *CodeWriter) insertSep() {
if w.skipSep {
w.skipSep = false
return
}
// Use at least two newlines to ensure a blank space between the previous
// block. WriteGoFile will remove extraneous newlines.
w.printf("\n\n")
}
// WriteComment writes a comment block. All line starts are prefixed with "//".
// Initial empty lines are gobbled. The indentation for the first line is
// stripped from consecutive lines.
func (w *CodeWriter) WriteComment(comment string, args ...interface{}) {
s := fmt.Sprintf(comment, args...)
s = strings.Trim(s, "\n")
// Use at least two newlines to ensure a blank space between the previous
// block. WriteGoFile will remove extraneous newlines.
w.printf("\n\n// ")
w.skipSep = true
// strip first indent level.
sep := "\n"
for ; len(s) > 0 && (s[0] == '\t' || s[0] == ' '); s = s[1:] {
sep += s[:1]
}
strings.NewReplacer(sep, "\n// ", "\n", "\n// ").WriteString(w, s)
w.printf("\n")
}
func (w *CodeWriter) writeSizeInfo(size int) {
w.printf("// Size: %d bytes\n", size)
}
// WriteConst writes a constant of the given name and value.
func (w *CodeWriter) WriteConst(name string, x interface{}) {
w.insertSep()
v := reflect.ValueOf(x)
switch v.Type().Kind() {
case reflect.String:
w.printf("const %s %s = ", name, typeName(x))
w.WriteString(v.String())
w.printf("\n")
default:
w.printf("const %s = %#v\n", name, x)
}
}
// WriteVar writes a variable of the given name and value.
func (w *CodeWriter) WriteVar(name string, x interface{}) {
w.insertSep()
v := reflect.ValueOf(x)
oldSize := w.Size
sz := int(v.Type().Size())
w.Size += sz
switch v.Type().Kind() {
case reflect.String:
w.printf("var %s %s = ", name, typeName(x))
w.WriteString(v.String())
case reflect.Struct:
w.gob.Encode(x)
fallthrough
case reflect.Slice, reflect.Array:
w.printf("var %s = ", name)
w.writeValue(v)
w.writeSizeInfo(w.Size - oldSize)
default:
w.printf("var %s %s = ", name, typeName(x))
w.gob.Encode(x)
w.writeValue(v)
w.writeSizeInfo(w.Size - oldSize)
}
w.printf("\n")
}
func (w *CodeWriter) writeValue(v reflect.Value) {
x := v.Interface()
switch v.Kind() {
case reflect.String:
w.WriteString(v.String())
case reflect.Array:
// Don't double count: callers of WriteArray count on the size being
// added, so we need to discount it here.
w.Size -= int(v.Type().Size())
w.writeSlice(x, true)
case reflect.Slice:
w.writeSlice(x, false)
case reflect.Struct:
w.printf("%s{\n", typeName(v.Interface()))
t := v.Type()
for i := 0; i < v.NumField(); i++ {
w.printf("%s: ", t.Field(i).Name)
w.writeValue(v.Field(i))
w.printf(",\n")
}
w.printf("}")
default:
w.printf("%#v", x)
}
}
// WriteString writes a string literal.
func (w *CodeWriter) WriteString(s string) {
io.WriteString(w.Hash, s) // content hash
w.Size += len(s)
const maxInline = 40
if len(s) <= maxInline {
w.printf("%q", s)
return
}
// We will render the string as a multi-line string.
const maxWidth = 80 - 4 - len(`"`) - len(`" +`)
// When starting on its own line, go fmt indents line 2+ an extra level.
n, max := maxWidth, maxWidth-4
// As per https://golang.org/issue/18078, the compiler has trouble
// compiling the concatenation of many strings, s0 + s1 + s2 + ... + sN,
// for large N. We insert redundant, explicit parentheses to work around
// that, lowering the N at any given step: (s0 + s1 + ... + s63) + (s64 +
// ... + s127) + etc + (etc + ... + sN).
explicitParens, extraComment := len(s) > 128*1024, ""
if explicitParens {
w.printf(`(`)
extraComment = "; the redundant, explicit parens are for https://golang.org/issue/18078"
}
// Print "" +\n, if a string does not start on its own line.
b := w.buf.Bytes()
if p := len(bytes.TrimRight(b, " \t")); p > 0 && b[p-1] != '\n' {
w.printf("\"\" + // Size: %d bytes%s\n", len(s), extraComment)
n, max = maxWidth, maxWidth
}
w.printf(`"`)
for sz, p, nLines := 0, 0, 0; p < len(s); {
var r rune
r, sz = utf8.DecodeRuneInString(s[p:])
out := s[p : p+sz]
chars := 1
if !unicode.IsPrint(r) || r == utf8.RuneError || r == '"' {
switch sz {
case 1:
out = fmt.Sprintf("\\x%02x", s[p])
case 2, 3:
out = fmt.Sprintf("\\u%04x", r)
case 4:
out = fmt.Sprintf("\\U%08x", r)
}
chars = len(out)
} else if r == '\\' {
out = "\\" + string(r)
chars = 2
}
if n -= chars; n < 0 {
nLines++
if explicitParens && nLines&63 == 63 {
w.printf("\") + (\"")
}
w.printf("\" +\n\"")
n = max - len(out)
}
w.printf("%s", out)
p += sz
}
w.printf(`"`)
if explicitParens {
w.printf(`)`)
}
}
// WriteSlice writes a slice value.
func (w *CodeWriter) WriteSlice(x interface{}) {
w.writeSlice(x, false)
}
// WriteArray writes an array value.
func (w *CodeWriter) WriteArray(x interface{}) {
w.writeSlice(x, true)
}
func (w *CodeWriter) writeSlice(x interface{}, isArray bool) {
v := reflect.ValueOf(x)
w.gob.Encode(v.Len())
w.Size += v.Len() * int(v.Type().Elem().Size())
name := typeName(x)
if isArray {
name = fmt.Sprintf("[%d]%s", v.Len(), name[strings.Index(name, "]")+1:])
}
if isArray {
w.printf("%s{\n", name)
} else {
w.printf("%s{ // %d elements\n", name, v.Len())
}
switch kind := v.Type().Elem().Kind(); kind {
case reflect.String:
for _, s := range x.([]string) {
w.WriteString(s)
w.printf(",\n")
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
// nLine and nBlock are the number of elements per line and block.
nLine, nBlock, format := 8, 64, "%d,"
switch kind {
case reflect.Uint8:
format = "%#02x,"
case reflect.Uint16:
format = "%#04x,"
case reflect.Uint32:
nLine, nBlock, format = 4, 32, "%#08x,"
case reflect.Uint, reflect.Uint64:
nLine, nBlock, format = 4, 32, "%#016x,"
case reflect.Int8:
nLine = 16
}
n := nLine
for i := 0; i < v.Len(); i++ {
if i%nBlock == 0 && v.Len() > nBlock {
w.printf("// Entry %X - %X\n", i, i+nBlock-1)
}
x := v.Index(i).Interface()
w.gob.Encode(x)
w.printf(format, x)
if n--; n == 0 {
n = nLine
w.printf("\n")
}
}
w.printf("\n")
case reflect.Struct:
zero := reflect.Zero(v.Type().Elem()).Interface()
for i := 0; i < v.Len(); i++ {
x := v.Index(i).Interface()
w.gob.EncodeValue(v)
if !reflect.DeepEqual(zero, x) {
line := fmt.Sprintf("%#v,\n", x)
line = line[strings.IndexByte(line, '{'):]
w.printf("%d: %s", i, line)
}
}
case reflect.Array:
for i := 0; i < v.Len(); i++ {
w.printf("%d: %#v,\n", i, v.Index(i).Interface())
}
default:
panic("gen: slice elem type not supported")
}
w.printf("}")
}
// WriteType writes a definition of the type of the given value and returns the
// type name.
func (w *CodeWriter) WriteType(x interface{}) string {
t := reflect.TypeOf(x)
w.printf("type %s struct {\n", t.Name())
for i := 0; i < t.NumField(); i++ {
w.printf("\t%s %s\n", t.Field(i).Name, t.Field(i).Type)
}
w.printf("}\n")
return t.Name()
}
// typeName returns the name of the go type of x.
func typeName(x interface{}) string {
t := reflect.ValueOf(x).Type()
return strings.Replace(fmt.Sprint(t), "main.", "", 1)
}
// 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.
// Package gen contains common code for the various code generation tools in the
// text repository. Its usage ensures consistency between tools.
//
// This package defines command line flags that are common to most generation
// tools. The flags allow for specifying specific Unicode and CLDR versions
// in the public Unicode data repository (https://www.unicode.org/Public).
//
// A local Unicode data mirror can be set through the flag -local or the
// environment variable UNICODE_DIR. The former takes precedence. The local
// directory should follow the same structure as the public repository.
//
// IANA data can also optionally be mirrored by putting it in the iana directory
// rooted at the top of the local mirror. Beware, though, that IANA data is not
// versioned. So it is up to the developer to use the right version.
package gen // import "golang.org/x/text/internal/gen"
import (
"bytes"
"flag"
"fmt"
"go/build"
"go/format"
"io"
"log"
"net/http"
"os"
"path"
"path/filepath"
"regexp"
"strings"
"sync"
"unicode"
"golang.org/x/text/unicode/cldr"
)
var (
url = flag.String("url",
"https://www.unicode.org/Public",
"URL of Unicode database directory")
iana = flag.String("iana",
"http://www.iana.org",
"URL of the IANA repository")
unicodeVersion = flag.String("unicode",
getEnv("UNICODE_VERSION", unicode.Version),
"unicode version to use")
cldrVersion = flag.String("cldr",
getEnv("CLDR_VERSION", cldr.Version),
"cldr version to use")
)
func getEnv(name, def string) string {
if v := os.Getenv(name); v != "" {
return v
}
return def
}
// Init performs common initialization for a gen command. It parses the flags
// and sets up the standard logging parameters.
func Init() {
log.SetPrefix("")
log.SetFlags(log.Lshortfile)
flag.Parse()
}
const header = `// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
`
// UnicodeVersion reports the requested Unicode version.
func UnicodeVersion() string {
return *unicodeVersion
}
// CLDRVersion reports the requested CLDR version.
func CLDRVersion() string {
return *cldrVersion
}
var tags = []struct{ version, buildTags string }{
{"9.0.0", "!go1.10"},
{"10.0.0", "go1.10,!go1.13"},
{"11.0.0", "go1.13,!go1.14"},
{"12.0.0", "go1.14,!go1.16"},
{"13.0.0", "go1.16,!go1.21"},
{"15.0.0", "go1.21"},
}
// buildTags reports the build tags used for the current Unicode version.
func buildTags() string {
v := UnicodeVersion()
for _, e := range tags {
if e.version == v {
return e.buildTags
}
}
log.Fatalf("Unknown build tags for Unicode version %q.", v)
return ""
}
// IsLocal reports whether data files are available locally.
func IsLocal() bool {
dir, err := localReadmeFile()
if err != nil {
return false
}
if _, err = os.Stat(dir); err != nil {
return false
}
return true
}
// OpenUCDFile opens the requested UCD file. The file is specified relative to
// the public Unicode root directory. It will call log.Fatal if there are any
// errors.
func OpenUCDFile(file string) io.ReadCloser {
return openUnicode(path.Join(*unicodeVersion, "ucd", file))
}
// OpenCLDRCoreZip opens the CLDR core zip file. It will call log.Fatal if there
// are any errors.
func OpenCLDRCoreZip() io.ReadCloser {
return OpenUnicodeFile("cldr", *cldrVersion, "core.zip")
}
// OpenUnicodeFile opens the requested file of the requested category from the
// root of the Unicode data archive. The file is specified relative to the
// public Unicode root directory. If version is "", it will use the default
// Unicode version. It will call log.Fatal if there are any errors.
func OpenUnicodeFile(category, version, file string) io.ReadCloser {
if version == "" {
version = UnicodeVersion()
}
return openUnicode(path.Join(category, version, file))
}
// OpenIANAFile opens the requested IANA file. The file is specified relative
// to the IANA root, which is typically either http://www.iana.org or the
// iana directory in the local mirror. It will call log.Fatal if there are any
// errors.
func OpenIANAFile(path string) io.ReadCloser {
return Open(*iana, "iana", path)
}
var (
dirMutex sync.Mutex
localDir string
)
const permissions = 0755
func localReadmeFile() (string, error) {
p, err := build.Import("golang.org/x/text", "", build.FindOnly)
if err != nil {
return "", fmt.Errorf("Could not locate package: %v", err)
}
return filepath.Join(p.Dir, "DATA", "README"), nil
}
func getLocalDir() string {
dirMutex.Lock()
defer dirMutex.Unlock()
readme, err := localReadmeFile()
if err != nil {
log.Fatal(err)
}
dir := filepath.Dir(readme)
if _, err := os.Stat(readme); err != nil {
if err := os.MkdirAll(dir, permissions); err != nil {
log.Fatalf("Could not create directory: %v", err)
}
os.WriteFile(readme, []byte(readmeTxt), permissions)
}
return dir
}
const readmeTxt = `Generated by golang.org/x/text/internal/gen. DO NOT EDIT.
This directory contains downloaded files used to generate the various tables
in the golang.org/x/text subrepo.
Note that the language subtag repo (iana/assignments/language-subtag-registry)
and all other times in the iana subdirectory are not versioned and will need
to be periodically manually updated. The easiest way to do this is to remove
the entire iana directory. This is mostly of concern when updating the language
package.
`
// Open opens subdir/path if a local directory is specified and the file exists,
// where subdir is a directory relative to the local root, or fetches it from
// urlRoot/path otherwise. It will call log.Fatal if there are any errors.
func Open(urlRoot, subdir, path string) io.ReadCloser {
file := filepath.Join(getLocalDir(), subdir, filepath.FromSlash(path))
return open(file, urlRoot, path)
}
func openUnicode(path string) io.ReadCloser {
file := filepath.Join(getLocalDir(), filepath.FromSlash(path))
return open(file, *url, path)
}
// TODO: automatically periodically update non-versioned files.
func open(file, urlRoot, path string) io.ReadCloser {
if f, err := os.Open(file); err == nil {
return f
}
r := get(urlRoot, path)
defer r.Close()
b, err := io.ReadAll(r)
if err != nil {
log.Fatalf("Could not download file: %v", err)
}
os.MkdirAll(filepath.Dir(file), permissions)
if err := os.WriteFile(file, b, permissions); err != nil {
log.Fatalf("Could not create file: %v", err)
}
return io.NopCloser(bytes.NewReader(b))
}
func get(root, path string) io.ReadCloser {
url := root + "/" + path
fmt.Printf("Fetching %s...", url)
defer fmt.Println(" done.")
resp, err := http.Get(url)
if err != nil {
log.Fatalf("HTTP GET: %v", err)
}
if resp.StatusCode != 200 {
log.Fatalf("Bad GET status for %q: %q", url, resp.Status)
}
return resp.Body
}
// TODO: use Write*Version in all applicable packages.
// WriteUnicodeVersion writes a constant for the Unicode version from which the
// tables are generated.
func WriteUnicodeVersion(w io.Writer) {
fmt.Fprintf(w, "// UnicodeVersion is the Unicode version from which the tables in this package are derived.\n")
fmt.Fprintf(w, "const UnicodeVersion = %q\n\n", UnicodeVersion())
}
// WriteCLDRVersion writes a constant for the CLDR version from which the
// tables are generated.
func WriteCLDRVersion(w io.Writer) {
fmt.Fprintf(w, "// CLDRVersion is the CLDR version from which the tables in this package are derived.\n")
fmt.Fprintf(w, "const CLDRVersion = %q\n\n", CLDRVersion())
}
// WriteGoFile prepends a standard file comment and package statement to the
// given bytes, applies gofmt, and writes them to a file with the given name.
// It will call log.Fatal if there are any errors.
func WriteGoFile(filename, pkg string, b []byte) {
w, err := os.Create(filename)
if err != nil {
log.Fatalf("Could not create file %s: %v", filename, err)
}
defer w.Close()
if _, err = WriteGo(w, pkg, "", b); err != nil {
log.Fatalf("Error writing file %s: %v", filename, err)
}
}
func fileToPattern(filename string) string {
suffix := ".go"
if strings.HasSuffix(filename, "_test.go") {
suffix = "_test.go"
}
prefix := filename[:len(filename)-len(suffix)]
return fmt.Sprint(prefix, "%s", suffix)
}
// tagLines returns the //go:build lines to add to the file.
func tagLines(tags string) string {
return "//go:build " + strings.ReplaceAll(tags, ",", " && ") + "\n"
}
func updateBuildTags(pattern string) {
for _, t := range tags {
oldFile := fmt.Sprintf(pattern, t.version)
b, err := os.ReadFile(oldFile)
if err != nil {
continue
}
b = regexp.MustCompile(`//go:build.*\n`).ReplaceAll(b, []byte(tagLines(t.buildTags)))
err = os.WriteFile(oldFile, b, 0644)
if err != nil {
log.Fatal(err)
}
}
}
// WriteVersionedGoFile prepends a standard file comment, adds build tags to
// version the file for the current Unicode version, and package statement to
// the given bytes, applies gofmt, and writes them to a file with the given
// name. It will call log.Fatal if there are any errors.
func WriteVersionedGoFile(filename, pkg string, b []byte) {
pattern := fileToPattern(filename)
updateBuildTags(pattern)
filename = fmt.Sprintf(pattern, UnicodeVersion())
w, err := os.Create(filename)
if err != nil {
log.Fatalf("Could not create file %s: %v", filename, err)
}
defer w.Close()
if _, err = WriteGo(w, pkg, buildTags(), b); err != nil {
log.Fatalf("Error writing file %s: %v", filename, err)
}
}
// WriteGo prepends a standard file comment and package statement to the given
// bytes, applies gofmt, and writes them to w.
func WriteGo(w io.Writer, pkg, tags string, b []byte) (n int, err error) {
src := []byte(header)
if tags != "" {
src = append(src, tagLines(tags)...)
src = append(src, '\n')
}
src = append(src, fmt.Sprintf("package %s\n\n", pkg)...)
src = append(src, b...)
formatted, err := format.Source(src)
if err != nil {
// Print the generated code even in case of an error so that the
// returned error can be meaningfully interpreted.
n, _ = w.Write(src)
return n, err
}
return w.Write(formatted)
}
// Repackage rewrites a Go file from belonging to package main to belonging to
// the given package.
func Repackage(inFile, outFile, pkg string) {
src, err := os.ReadFile(inFile)
if err != nil {
log.Fatalf("reading %s: %v", inFile, err)
}
const toDelete = "package main\n\n"
i := bytes.Index(src, []byte(toDelete))
if i < 0 {
log.Fatalf("Could not find %q in %s.", toDelete, inFile)
}
w := &bytes.Buffer{}
w.Write(src[i+len(toDelete):])
WriteGoFile(outFile, pkg, w.Bytes())
}
// 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.
// Package internal contains non-exported functionality that are used by
// packages in the text repository.
package internal // import "golang.org/x/text/internal"
import (
"sort"
"golang.org/x/text/language"
)
// SortTags sorts tags in place.
func SortTags(tags []language.Tag) {
sort.Sort(sorter(tags))
}
type sorter []language.Tag
func (s sorter) Len() int {
return len(s)
}
func (s sorter) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s sorter) Less(i, j int) bool {
return s[i].String() < s[j].String()
}
// UniqueTags sorts and filters duplicate tags in place and returns a slice with
// only unique tags.
func UniqueTags(tags []language.Tag) []language.Tag {
if len(tags) <= 1 {
return tags
}
SortTags(tags)
k := 0
for i := 1; i < len(tags); i++ {
if tags[k].String() < tags[i].String() {
k++
tags[k] = tags[i]
}
}
return tags[:k+1]
}
// Copyright 2018 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 language
// CompactCoreInfo is a compact integer with the three core tags encoded.
type CompactCoreInfo uint32
// GetCompactCore generates a uint32 value that is guaranteed to be unique for
// different language, region, and script values.
func GetCompactCore(t Tag) (cci CompactCoreInfo, ok bool) {
if t.LangID > langNoIndexOffset {
return 0, false
}
cci |= CompactCoreInfo(t.LangID) << (8 + 12)
cci |= CompactCoreInfo(t.ScriptID) << 12
cci |= CompactCoreInfo(t.RegionID)
return cci, true
}
// Tag generates a tag from c.
func (c CompactCoreInfo) Tag() Tag {
return Tag{
LangID: Language(c >> 20),
RegionID: Region(c & 0x3ff),
ScriptID: Script(c>>12) & 0xff,
}
}
// Copyright 2018 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 compact defines a compact representation of language tags.
//
// Common language tags (at least all for which locale information is defined
// in CLDR) are assigned a unique index. Each Tag is associated with such an
// ID for selecting language-related resources (such as translations) as well
// as one for selecting regional defaults (currency, number formatting, etc.)
//
// It may want to export this functionality at some point, but at this point
// this is only available for use within x/text.
package compact // import "golang.org/x/text/internal/language/compact"
import (
"sort"
"strings"
"golang.org/x/text/internal/language"
)
// ID is an integer identifying a single tag.
type ID uint16
func getCoreIndex(t language.Tag) (id ID, ok bool) {
cci, ok := language.GetCompactCore(t)
if !ok {
return 0, false
}
i := sort.Search(len(coreTags), func(i int) bool {
return cci <= coreTags[i]
})
if i == len(coreTags) || coreTags[i] != cci {
return 0, false
}
return ID(i), true
}
// Parent returns the ID of the parent or the root ID if id is already the root.
func (id ID) Parent() ID {
return parents[id]
}
// Tag converts id to an internal language Tag.
func (id ID) Tag() language.Tag {
if int(id) >= len(coreTags) {
return specialTags[int(id)-len(coreTags)]
}
return coreTags[id].Tag()
}
var specialTags []language.Tag
func init() {
tags := strings.Split(specialTagsStr, " ")
specialTags = make([]language.Tag, len(tags))
for i, t := range tags {
specialTags[i] = language.MustParse(t)
}
}
// Copyright 2013 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.
//go:generate go run gen.go gen_index.go -output tables.go
//go:generate go run gen_parents.go
package compact
// TODO: Remove above NOTE after:
// - verifying that tables are dropped correctly (most notably matcher tables).
import (
"strings"
"golang.org/x/text/internal/language"
)
// Tag represents a BCP 47 language tag. It is used to specify an instance of a
// specific language or locale. All language tag values are guaranteed to be
// well-formed.
type Tag struct {
// NOTE: exported tags will become part of the public API.
language ID
locale ID
full fullTag // always a language.Tag for now.
}
const _und = 0
type fullTag interface {
IsRoot() bool
Parent() language.Tag
}
// Make a compact Tag from a fully specified internal language Tag.
func Make(t language.Tag) (tag Tag) {
if region := t.TypeForKey("rg"); len(region) == 6 && region[2:] == "zzzz" {
if r, err := language.ParseRegion(region[:2]); err == nil {
tFull := t
t, _ = t.SetTypeForKey("rg", "")
// TODO: should we not consider "va" for the language tag?
var exact1, exact2 bool
tag.language, exact1 = FromTag(t)
t.RegionID = r
tag.locale, exact2 = FromTag(t)
if !exact1 || !exact2 {
tag.full = tFull
}
return tag
}
}
lang, ok := FromTag(t)
tag.language = lang
tag.locale = lang
if !ok {
tag.full = t
}
return tag
}
// Tag returns an internal language Tag version of this tag.
func (t Tag) Tag() language.Tag {
if t.full != nil {
return t.full.(language.Tag)
}
tag := t.language.Tag()
if t.language != t.locale {
loc := t.locale.Tag()
tag, _ = tag.SetTypeForKey("rg", strings.ToLower(loc.RegionID.String())+"zzzz")
}
return tag
}
// IsCompact reports whether this tag is fully defined in terms of ID.
func (t *Tag) IsCompact() bool {
return t.full == nil
}
// MayHaveVariants reports whether a tag may have variants. If it returns false
// it is guaranteed the tag does not have variants.
func (t Tag) MayHaveVariants() bool {
return t.full != nil || int(t.language) >= len(coreTags)
}
// MayHaveExtensions reports whether a tag may have extensions. If it returns
// false it is guaranteed the tag does not have them.
func (t Tag) MayHaveExtensions() bool {
return t.full != nil ||
int(t.language) >= len(coreTags) ||
t.language != t.locale
}
// IsRoot returns true if t is equal to language "und".
func (t Tag) IsRoot() bool {
if t.full != nil {
return t.full.IsRoot()
}
return t.language == _und
}
// Parent returns the CLDR parent of t. In CLDR, missing fields in data for a
// specific language are substituted with fields from the parent language.
// The parent for a language may change for newer versions of CLDR.
func (t Tag) Parent() Tag {
if t.full != nil {
return Make(t.full.Parent())
}
if t.language != t.locale {
// Simulate stripping -u-rg-xxxxxx
return Tag{language: t.language, locale: t.language}
}
// TODO: use parent lookup table once cycle from internal package is
// removed. Probably by internalizing the table and declaring this fast
// enough.
// lang := compactID(internal.Parent(uint16(t.language)))
lang, _ := FromTag(t.language.Tag().Parent())
return Tag{language: lang, locale: lang}
}
// nextToken returns token t and the rest of the string.
func nextToken(s string) (t, tail string) {
p := strings.Index(s[1:], "-")
if p == -1 {
return s[1:], ""
}
p++
return s[1:p], s[p:]
}
// LanguageID returns an index, where 0 <= index < NumCompactTags, for tags
// for which data exists in the text repository.The index will change over time
// and should not be stored in persistent storage. If t does not match a compact
// index, exact will be false and the compact index will be returned for the
// first match after repeatedly taking the Parent of t.
func LanguageID(t Tag) (id ID, exact bool) {
return t.language, t.full == nil
}
// RegionalID returns the ID for the regional variant of this tag. This index is
// used to indicate region-specific overrides, such as default currency, default
// calendar and week data, default time cycle, and default measurement system
// and unit preferences.
//
// For instance, the tag en-GB-u-rg-uszzzz specifies British English with US
// settings for currency, number formatting, etc. The CompactIndex for this tag
// will be that for en-GB, while the RegionalID will be the one corresponding to
// en-US.
func RegionalID(t Tag) (id ID, exact bool) {
return t.locale, t.full == nil
}
// LanguageTag returns t stripped of regional variant indicators.
//
// At the moment this means it is stripped of a regional and variant subtag "rg"
// and "va" in the "u" extension.
func (t Tag) LanguageTag() Tag {
if t.full == nil {
return Tag{language: t.language, locale: t.language}
}
tt := t.Tag()
tt.SetTypeForKey("rg", "")
tt.SetTypeForKey("va", "")
return Make(tt)
}
// RegionalTag returns the regional variant of the tag.
//
// At the moment this means that the region is set from the regional subtag
// "rg" in the "u" extension.
func (t Tag) RegionalTag() Tag {
rt := Tag{language: t.locale, locale: t.locale}
if t.full == nil {
return rt
}
b := language.Builder{}
tag := t.Tag()
// tag, _ = tag.SetTypeForKey("rg", "")
b.SetTag(t.locale.Tag())
if v := tag.Variants(); v != "" {
for _, v := range strings.Split(v, "-") {
b.AddVariant(v)
}
}
for _, e := range tag.Extensions() {
b.AddExt(e)
}
return t
}
// FromTag reports closest matching ID for an internal language Tag.
func FromTag(t language.Tag) (id ID, exact bool) {
// TODO: perhaps give more frequent tags a lower index.
// TODO: we could make the indexes stable. This will excluded some
// possibilities for optimization, so don't do this quite yet.
exact = true
b, s, r := t.Raw()
if t.HasString() {
if t.IsPrivateUse() {
// We have no entries for user-defined tags.
return 0, false
}
hasExtra := false
if t.HasVariants() {
if t.HasExtensions() {
build := language.Builder{}
build.SetTag(language.Tag{LangID: b, ScriptID: s, RegionID: r})
build.AddVariant(t.Variants())
exact = false
t = build.Make()
}
hasExtra = true
} else if _, ok := t.Extension('u'); ok {
// TODO: va may mean something else. Consider not considering it.
// Strip all but the 'va' entry.
old := t
variant := t.TypeForKey("va")
t = language.Tag{LangID: b, ScriptID: s, RegionID: r}
if variant != "" {
t, _ = t.SetTypeForKey("va", variant)
hasExtra = true
}
exact = old == t
} else {
exact = false
}
if hasExtra {
// We have some variants.
for i, s := range specialTags {
if s == t {
return ID(i + len(coreTags)), exact
}
}
exact = false
}
}
if x, ok := getCoreIndex(t); ok {
return x, exact
}
exact = false
if r != 0 && s == 0 {
// Deal with cases where an extra script is inserted for the region.
t, _ := t.Maximize()
if x, ok := getCoreIndex(t); ok {
return x, exact
}
}
for t = t.Parent(); t != root; t = t.Parent() {
// No variants specified: just compare core components.
// The key has the form lllssrrr, where l, s, and r are nibbles for
// respectively the langID, scriptID, and regionID.
if x, ok := getCoreIndex(t); ok {
return x, exact
}
}
return 0, exact
}
var root = language.Tag{}
// Copyright 2018 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 language
import (
"sort"
"strings"
)
// A Builder allows constructing a Tag from individual components.
// Its main user is Compose in the top-level language package.
type Builder struct {
Tag Tag
private string // the x extension
variants []string
extensions []string
}
// Make returns a new Tag from the current settings.
func (b *Builder) Make() Tag {
t := b.Tag
if len(b.extensions) > 0 || len(b.variants) > 0 {
sort.Sort(sortVariants(b.variants))
sort.Strings(b.extensions)
if b.private != "" {
b.extensions = append(b.extensions, b.private)
}
n := maxCoreSize + tokenLen(b.variants...) + tokenLen(b.extensions...)
buf := make([]byte, n)
p := t.genCoreBytes(buf)
t.pVariant = byte(p)
p += appendTokens(buf[p:], b.variants...)
t.pExt = uint16(p)
p += appendTokens(buf[p:], b.extensions...)
t.str = string(buf[:p])
// We may not always need to remake the string, but when or when not
// to do so is rather tricky.
scan := makeScanner(buf[:p])
t, _ = parse(&scan, "")
return t
} else if b.private != "" {
t.str = b.private
t.RemakeString()
}
return t
}
// SetTag copies all the settings from a given Tag. Any previously set values
// are discarded.
func (b *Builder) SetTag(t Tag) {
b.Tag.LangID = t.LangID
b.Tag.RegionID = t.RegionID
b.Tag.ScriptID = t.ScriptID
// TODO: optimize
b.variants = b.variants[:0]
if variants := t.Variants(); variants != "" {
for _, vr := range strings.Split(variants[1:], "-") {
b.variants = append(b.variants, vr)
}
}
b.extensions, b.private = b.extensions[:0], ""
for _, e := range t.Extensions() {
b.AddExt(e)
}
}
// AddExt adds extension e to the tag. e must be a valid extension as returned
// by Tag.Extension. If the extension already exists, it will be discarded,
// except for a -u extension, where non-existing key-type pairs will added.
func (b *Builder) AddExt(e string) {
if e[0] == 'x' {
if b.private == "" {
b.private = e
}
return
}
for i, s := range b.extensions {
if s[0] == e[0] {
if e[0] == 'u' {
b.extensions[i] += e[1:]
}
return
}
}
b.extensions = append(b.extensions, e)
}
// SetExt sets the extension e to the tag. e must be a valid extension as
// returned by Tag.Extension. If the extension already exists, it will be
// overwritten, except for a -u extension, where the individual key-type pairs
// will be set.
func (b *Builder) SetExt(e string) {
if e[0] == 'x' {
b.private = e
return
}
for i, s := range b.extensions {
if s[0] == e[0] {
if e[0] == 'u' {
b.extensions[i] = e + s[1:]
} else {
b.extensions[i] = e
}
return
}
}
b.extensions = append(b.extensions, e)
}
// AddVariant adds any number of variants.
func (b *Builder) AddVariant(v ...string) {
for _, v := range v {
if v != "" {
b.variants = append(b.variants, v)
}
}
}
// ClearVariants removes any variants previously added, including those
// copied from a Tag in SetTag.
func (b *Builder) ClearVariants() {
b.variants = b.variants[:0]
}
// ClearExtensions removes any extensions previously added, including those
// copied from a Tag in SetTag.
func (b *Builder) ClearExtensions() {
b.private = ""
b.extensions = b.extensions[:0]
}
func tokenLen(token ...string) (n int) {
for _, t := range token {
n += len(t) + 1
}
return
}
func appendTokens(b []byte, token ...string) int {
p := 0
for _, t := range token {
b[p] = '-'
copy(b[p+1:], t)
p += 1 + len(t)
}
return p
}
type sortVariants []string
func (s sortVariants) Len() int {
return len(s)
}
func (s sortVariants) Swap(i, j int) {
s[j], s[i] = s[i], s[j]
}
func (s sortVariants) Less(i, j int) bool {
return variantIndex[s[i]] < variantIndex[s[j]]
}
// 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 language
// BaseLanguages returns the list of all supported base languages. It generates
// the list by traversing the internal structures.
func BaseLanguages() []Language {
base := make([]Language, 0, NumLanguages)
for i := 0; i < langNoIndexOffset; i++ {
// We included "und" already for the value 0.
if i != nonCanonicalUnd {
base = append(base, Language(i))
}
}
i := langNoIndexOffset
for _, v := range langNoIndex {
for k := 0; k < 8; k++ {
if v&1 == 1 {
base = append(base, Language(i))
}
v >>= 1
i++
}
}
return base
}
// Copyright 2013 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.
//go:generate go run gen.go gen_common.go -output tables.go
package language // import "golang.org/x/text/internal/language"
// TODO: Remove above NOTE after:
// - verifying that tables are dropped correctly (most notably matcher tables).
import (
"errors"
"fmt"
"strings"
)
const (
// maxCoreSize is the maximum size of a BCP 47 tag without variants and
// extensions. Equals max lang (3) + script (4) + max reg (3) + 2 dashes.
maxCoreSize = 12
// max99thPercentileSize is a somewhat arbitrary buffer size that presumably
// is large enough to hold at least 99% of the BCP 47 tags.
max99thPercentileSize = 32
// maxSimpleUExtensionSize is the maximum size of a -u extension with one
// key-type pair. Equals len("-u-") + key (2) + dash + max value (8).
maxSimpleUExtensionSize = 14
)
// Tag represents a BCP 47 language tag. It is used to specify an instance of a
// specific language or locale. All language tag values are guaranteed to be
// well-formed. The zero value of Tag is Und.
type Tag struct {
// TODO: the following fields have the form TagTypeID. This name is chosen
// to allow refactoring the public package without conflicting with its
// Base, Script, and Region methods. Once the transition is fully completed
// the ID can be stripped from the name.
LangID Language
RegionID Region
// TODO: we will soon run out of positions for ScriptID. Idea: instead of
// storing lang, region, and ScriptID codes, store only the compact index and
// have a lookup table from this code to its expansion. This greatly speeds
// up table lookup, speed up common variant cases.
// This will also immediately free up 3 extra bytes. Also, the pVariant
// field can now be moved to the lookup table, as the compact index uniquely
// determines the offset of a possible variant.
ScriptID Script
pVariant byte // offset in str, includes preceding '-'
pExt uint16 // offset of first extension, includes preceding '-'
// str is the string representation of the Tag. It will only be used if the
// tag has variants or extensions.
str string
}
// Make is a convenience wrapper for Parse that omits the error.
// In case of an error, a sensible default is returned.
func Make(s string) Tag {
t, _ := Parse(s)
return t
}
// Raw returns the raw base language, script and region, without making an
// attempt to infer their values.
// TODO: consider removing
func (t Tag) Raw() (b Language, s Script, r Region) {
return t.LangID, t.ScriptID, t.RegionID
}
// equalTags compares language, script and region subtags only.
func (t Tag) equalTags(a Tag) bool {
return t.LangID == a.LangID && t.ScriptID == a.ScriptID && t.RegionID == a.RegionID
}
// IsRoot returns true if t is equal to language "und".
func (t Tag) IsRoot() bool {
if int(t.pVariant) < len(t.str) {
return false
}
return t.equalTags(Und)
}
// IsPrivateUse reports whether the Tag consists solely of an IsPrivateUse use
// tag.
func (t Tag) IsPrivateUse() bool {
return t.str != "" && t.pVariant == 0
}
// RemakeString is used to update t.str in case lang, script or region changed.
// It is assumed that pExt and pVariant still point to the start of the
// respective parts.
func (t *Tag) RemakeString() {
if t.str == "" {
return
}
extra := t.str[t.pVariant:]
if t.pVariant > 0 {
extra = extra[1:]
}
if t.equalTags(Und) && strings.HasPrefix(extra, "x-") {
t.str = extra
t.pVariant = 0
t.pExt = 0
return
}
var buf [max99thPercentileSize]byte // avoid extra memory allocation in most cases.
b := buf[:t.genCoreBytes(buf[:])]
if extra != "" {
diff := len(b) - int(t.pVariant)
b = append(b, '-')
b = append(b, extra...)
t.pVariant = uint8(int(t.pVariant) + diff)
t.pExt = uint16(int(t.pExt) + diff)
} else {
t.pVariant = uint8(len(b))
t.pExt = uint16(len(b))
}
t.str = string(b)
}
// genCoreBytes writes a string for the base languages, script and region tags
// to the given buffer and returns the number of bytes written. It will never
// write more than maxCoreSize bytes.
func (t *Tag) genCoreBytes(buf []byte) int {
n := t.LangID.StringToBuf(buf[:])
if t.ScriptID != 0 {
n += copy(buf[n:], "-")
n += copy(buf[n:], t.ScriptID.String())
}
if t.RegionID != 0 {
n += copy(buf[n:], "-")
n += copy(buf[n:], t.RegionID.String())
}
return n
}
// String returns the canonical string representation of the language tag.
func (t Tag) String() string {
if t.str != "" {
return t.str
}
if t.ScriptID == 0 && t.RegionID == 0 {
return t.LangID.String()
}
buf := [maxCoreSize]byte{}
return string(buf[:t.genCoreBytes(buf[:])])
}
// MarshalText implements encoding.TextMarshaler.
func (t Tag) MarshalText() (text []byte, err error) {
if t.str != "" {
text = append(text, t.str...)
} else if t.ScriptID == 0 && t.RegionID == 0 {
text = append(text, t.LangID.String()...)
} else {
buf := [maxCoreSize]byte{}
text = buf[:t.genCoreBytes(buf[:])]
}
return text, nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (t *Tag) UnmarshalText(text []byte) error {
tag, err := Parse(string(text))
*t = tag
return err
}
// Variants returns the part of the tag holding all variants or the empty string
// if there are no variants defined.
func (t Tag) Variants() string {
if t.pVariant == 0 {
return ""
}
return t.str[t.pVariant:t.pExt]
}
// VariantOrPrivateUseTags returns variants or private use tags.
func (t Tag) VariantOrPrivateUseTags() string {
if t.pExt > 0 {
return t.str[t.pVariant:t.pExt]
}
return t.str[t.pVariant:]
}
// HasString reports whether this tag defines more than just the raw
// components.
func (t Tag) HasString() bool {
return t.str != ""
}
// Parent returns the CLDR parent of t. In CLDR, missing fields in data for a
// specific language are substituted with fields from the parent language.
// The parent for a language may change for newer versions of CLDR.
func (t Tag) Parent() Tag {
if t.str != "" {
// Strip the variants and extensions.
b, s, r := t.Raw()
t = Tag{LangID: b, ScriptID: s, RegionID: r}
if t.RegionID == 0 && t.ScriptID != 0 && t.LangID != 0 {
base, _ := addTags(Tag{LangID: t.LangID})
if base.ScriptID == t.ScriptID {
return Tag{LangID: t.LangID}
}
}
return t
}
if t.LangID != 0 {
if t.RegionID != 0 {
maxScript := t.ScriptID
if maxScript == 0 {
max, _ := addTags(t)
maxScript = max.ScriptID
}
for i := range parents {
if Language(parents[i].lang) == t.LangID && Script(parents[i].maxScript) == maxScript {
for _, r := range parents[i].fromRegion {
if Region(r) == t.RegionID {
return Tag{
LangID: t.LangID,
ScriptID: Script(parents[i].script),
RegionID: Region(parents[i].toRegion),
}
}
}
}
}
// Strip the script if it is the default one.
base, _ := addTags(Tag{LangID: t.LangID})
if base.ScriptID != maxScript {
return Tag{LangID: t.LangID, ScriptID: maxScript}
}
return Tag{LangID: t.LangID}
} else if t.ScriptID != 0 {
// The parent for an base-script pair with a non-default script is
// "und" instead of the base language.
base, _ := addTags(Tag{LangID: t.LangID})
if base.ScriptID != t.ScriptID {
return Und
}
return Tag{LangID: t.LangID}
}
}
return Und
}
// ParseExtension parses s as an extension and returns it on success.
func ParseExtension(s string) (ext string, err error) {
defer func() {
if recover() != nil {
ext = ""
err = ErrSyntax
}
}()
scan := makeScannerString(s)
var end int
if n := len(scan.token); n != 1 {
return "", ErrSyntax
}
scan.toLower(0, len(scan.b))
end = parseExtension(&scan)
if end != len(s) {
return "", ErrSyntax
}
return string(scan.b), nil
}
// HasVariants reports whether t has variants.
func (t Tag) HasVariants() bool {
return uint16(t.pVariant) < t.pExt
}
// HasExtensions reports whether t has extensions.
func (t Tag) HasExtensions() bool {
return int(t.pExt) < len(t.str)
}
// Extension returns the extension of type x for tag t. It will return
// false for ok if t does not have the requested extension. The returned
// extension will be invalid in this case.
func (t Tag) Extension(x byte) (ext string, ok bool) {
for i := int(t.pExt); i < len(t.str)-1; {
var ext string
i, ext = getExtension(t.str, i)
if ext[0] == x {
return ext, true
}
}
return "", false
}
// Extensions returns all extensions of t.
func (t Tag) Extensions() []string {
e := []string{}
for i := int(t.pExt); i < len(t.str)-1; {
var ext string
i, ext = getExtension(t.str, i)
e = append(e, ext)
}
return e
}
// TypeForKey returns the type associated with the given key, where key and type
// are of the allowed values defined for the Unicode locale extension ('u') in
// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
// TypeForKey will traverse the inheritance chain to get the correct value.
//
// If there are multiple types associated with a key, only the first will be
// returned. If there is no type associated with a key, it returns the empty
// string.
func (t Tag) TypeForKey(key string) string {
if _, start, end, _ := t.findTypeForKey(key); end != start {
s := t.str[start:end]
if p := strings.IndexByte(s, '-'); p >= 0 {
s = s[:p]
}
return s
}
return ""
}
var (
errPrivateUse = errors.New("cannot set a key on a private use tag")
errInvalidArguments = errors.New("invalid key or type")
)
// SetTypeForKey returns a new Tag with the key set to type, where key and type
// are of the allowed values defined for the Unicode locale extension ('u') in
// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
// An empty value removes an existing pair with the same key.
func (t Tag) SetTypeForKey(key, value string) (Tag, error) {
if t.IsPrivateUse() {
return t, errPrivateUse
}
if len(key) != 2 {
return t, errInvalidArguments
}
// Remove the setting if value is "".
if value == "" {
start, sep, end, _ := t.findTypeForKey(key)
if start != sep {
// Remove a possible empty extension.
switch {
case t.str[start-2] != '-': // has previous elements.
case end == len(t.str), // end of string
end+2 < len(t.str) && t.str[end+2] == '-': // end of extension
start -= 2
}
if start == int(t.pVariant) && end == len(t.str) {
t.str = ""
t.pVariant, t.pExt = 0, 0
} else {
t.str = fmt.Sprintf("%s%s", t.str[:start], t.str[end:])
}
}
return t, nil
}
if len(value) < 3 || len(value) > 8 {
return t, errInvalidArguments
}
var (
buf [maxCoreSize + maxSimpleUExtensionSize]byte
uStart int // start of the -u extension.
)
// Generate the tag string if needed.
if t.str == "" {
uStart = t.genCoreBytes(buf[:])
buf[uStart] = '-'
uStart++
}
// Create new key-type pair and parse it to verify.
b := buf[uStart:]
copy(b, "u-")
copy(b[2:], key)
b[4] = '-'
b = b[:5+copy(b[5:], value)]
scan := makeScanner(b)
if parseExtensions(&scan); scan.err != nil {
return t, scan.err
}
// Assemble the replacement string.
if t.str == "" {
t.pVariant, t.pExt = byte(uStart-1), uint16(uStart-1)
t.str = string(buf[:uStart+len(b)])
} else {
s := t.str
start, sep, end, hasExt := t.findTypeForKey(key)
if start == sep {
if hasExt {
b = b[2:]
}
t.str = fmt.Sprintf("%s-%s%s", s[:sep], b, s[end:])
} else {
t.str = fmt.Sprintf("%s-%s%s", s[:start+3], value, s[end:])
}
}
return t, nil
}
// findTypeForKey returns the start and end position for the type corresponding
// to key or the point at which to insert the key-value pair if the type
// wasn't found. The hasExt return value reports whether an -u extension was present.
// Note: the extensions are typically very small and are likely to contain
// only one key-type pair.
func (t Tag) findTypeForKey(key string) (start, sep, end int, hasExt bool) {
p := int(t.pExt)
if len(key) != 2 || p == len(t.str) || p == 0 {
return p, p, p, false
}
s := t.str
// Find the correct extension.
for p++; s[p] != 'u'; p++ {
if s[p] > 'u' {
p--
return p, p, p, false
}
if p = nextExtension(s, p); p == len(s) {
return len(s), len(s), len(s), false
}
}
// Proceed to the hyphen following the extension name.
p++
// curKey is the key currently being processed.
curKey := ""
// Iterate over keys until we get the end of a section.
for {
end = p
for p++; p < len(s) && s[p] != '-'; p++ {
}
n := p - end - 1
if n <= 2 && curKey == key {
if sep < end {
sep++
}
return start, sep, end, true
}
switch n {
case 0, // invalid string
1: // next extension
return end, end, end, true
case 2:
// next key
curKey = s[end+1 : p]
if curKey > key {
return end, end, end, true
}
start = end
sep = p
}
}
}
// ParseBase parses a 2- or 3-letter ISO 639 code.
// It returns a ValueError if s is a well-formed but unknown language identifier
// or another error if another error occurred.
func ParseBase(s string) (l Language, err error) {
defer func() {
if recover() != nil {
l = 0
err = ErrSyntax
}
}()
if n := len(s); n < 2 || 3 < n {
return 0, ErrSyntax
}
var buf [3]byte
return getLangID(buf[:copy(buf[:], s)])
}
// ParseScript parses a 4-letter ISO 15924 code.
// It returns a ValueError if s is a well-formed but unknown script identifier
// or another error if another error occurred.
func ParseScript(s string) (scr Script, err error) {
defer func() {
if recover() != nil {
scr = 0
err = ErrSyntax
}
}()
if len(s) != 4 {
return 0, ErrSyntax
}
var buf [4]byte
return getScriptID(script, buf[:copy(buf[:], s)])
}
// EncodeM49 returns the Region for the given UN M.49 code.
// It returns an error if r is not a valid code.
func EncodeM49(r int) (Region, error) {
return getRegionM49(r)
}
// ParseRegion parses a 2- or 3-letter ISO 3166-1 or a UN M.49 code.
// It returns a ValueError if s is a well-formed but unknown region identifier
// or another error if another error occurred.
func ParseRegion(s string) (r Region, err error) {
defer func() {
if recover() != nil {
r = 0
err = ErrSyntax
}
}()
if n := len(s); n < 2 || 3 < n {
return 0, ErrSyntax
}
var buf [3]byte
return getRegionID(buf[:copy(buf[:], s)])
}
// IsCountry returns whether this region is a country or autonomous area. This
// includes non-standard definitions from CLDR.
func (r Region) IsCountry() bool {
if r == 0 || r.IsGroup() || r.IsPrivateUse() && r != _XK {
return false
}
return true
}
// IsGroup returns whether this region defines a collection of regions. This
// includes non-standard definitions from CLDR.
func (r Region) IsGroup() bool {
if r == 0 {
return false
}
return int(regionInclusion[r]) < len(regionContainment)
}
// Contains returns whether Region c is contained by Region r. It returns true
// if c == r.
func (r Region) Contains(c Region) bool {
if r == c {
return true
}
g := regionInclusion[r]
if g >= nRegionGroups {
return false
}
m := regionContainment[g]
d := regionInclusion[c]
b := regionInclusionBits[d]
// A contained country may belong to multiple disjoint groups. Matching any
// of these indicates containment. If the contained region is a group, it
// must strictly be a subset.
if d >= nRegionGroups {
return b&m != 0
}
return b&^m == 0
}
var errNoTLD = errors.New("language: region is not a valid ccTLD")
// TLD returns the country code top-level domain (ccTLD). UK is returned for GB.
// In all other cases it returns either the region itself or an error.
//
// This method may return an error for a region for which there exists a
// canonical form with a ccTLD. To get that ccTLD canonicalize r first. The
// region will already be canonicalized it was obtained from a Tag that was
// obtained using any of the default methods.
func (r Region) TLD() (Region, error) {
// See http://en.wikipedia.org/wiki/Country_code_top-level_domain for the
// difference between ISO 3166-1 and IANA ccTLD.
if r == _GB {
r = _UK
}
if (r.typ() & ccTLD) == 0 {
return 0, errNoTLD
}
return r, nil
}
// Canonicalize returns the region or a possible replacement if the region is
// deprecated. It will not return a replacement for deprecated regions that
// are split into multiple regions.
func (r Region) Canonicalize() Region {
if cr := normRegion(r); cr != 0 {
return cr
}
return r
}
// Variant represents a registered variant of a language as defined by BCP 47.
type Variant struct {
ID uint8
str string
}
// ParseVariant parses and returns a Variant. An error is returned if s is not
// a valid variant.
func ParseVariant(s string) (v Variant, err error) {
defer func() {
if recover() != nil {
v = Variant{}
err = ErrSyntax
}
}()
s = strings.ToLower(s)
if id, ok := variantIndex[s]; ok {
return Variant{id, s}, nil
}
return Variant{}, NewValueError([]byte(s))
}
// String returns the string representation of the variant.
func (v Variant) String() string {
return v.str
}
// Copyright 2013 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 language
import (
"bytes"
"fmt"
"sort"
"strconv"
"golang.org/x/text/internal/tag"
)
// findIndex tries to find the given tag in idx and returns a standardized error
// if it could not be found.
func findIndex(idx tag.Index, key []byte, form string) (index int, err error) {
if !tag.FixCase(form, key) {
return 0, ErrSyntax
}
i := idx.Index(key)
if i == -1 {
return 0, NewValueError(key)
}
return i, nil
}
func searchUint(imap []uint16, key uint16) int {
return sort.Search(len(imap), func(i int) bool {
return imap[i] >= key
})
}
type Language uint16
// getLangID returns the langID of s if s is a canonical subtag
// or langUnknown if s is not a canonical subtag.
func getLangID(s []byte) (Language, error) {
if len(s) == 2 {
return getLangISO2(s)
}
return getLangISO3(s)
}
// TODO language normalization as well as the AliasMaps could be moved to the
// higher level package, but it is a bit tricky to separate the generation.
func (id Language) Canonicalize() (Language, AliasType) {
return normLang(id)
}
// normLang returns the mapped langID of id according to mapping m.
func normLang(id Language) (Language, AliasType) {
k := sort.Search(len(AliasMap), func(i int) bool {
return AliasMap[i].From >= uint16(id)
})
if k < len(AliasMap) && AliasMap[k].From == uint16(id) {
return Language(AliasMap[k].To), AliasTypes[k]
}
return id, AliasTypeUnknown
}
// getLangISO2 returns the langID for the given 2-letter ISO language code
// or unknownLang if this does not exist.
func getLangISO2(s []byte) (Language, error) {
if !tag.FixCase("zz", s) {
return 0, ErrSyntax
}
if i := lang.Index(s); i != -1 && lang.Elem(i)[3] != 0 {
return Language(i), nil
}
return 0, NewValueError(s)
}
const base = 'z' - 'a' + 1
func strToInt(s []byte) uint {
v := uint(0)
for i := 0; i < len(s); i++ {
v *= base
v += uint(s[i] - 'a')
}
return v
}
// converts the given integer to the original ASCII string passed to strToInt.
// len(s) must match the number of characters obtained.
func intToStr(v uint, s []byte) {
for i := len(s) - 1; i >= 0; i-- {
s[i] = byte(v%base) + 'a'
v /= base
}
}
// getLangISO3 returns the langID for the given 3-letter ISO language code
// or unknownLang if this does not exist.
func getLangISO3(s []byte) (Language, error) {
if tag.FixCase("und", s) {
// first try to match canonical 3-letter entries
for i := lang.Index(s[:2]); i != -1; i = lang.Next(s[:2], i) {
if e := lang.Elem(i); e[3] == 0 && e[2] == s[2] {
// We treat "und" as special and always translate it to "unspecified".
// Note that ZZ and Zzzz are private use and are not treated as
// unspecified by default.
id := Language(i)
if id == nonCanonicalUnd {
return 0, nil
}
return id, nil
}
}
if i := altLangISO3.Index(s); i != -1 {
return Language(altLangIndex[altLangISO3.Elem(i)[3]]), nil
}
n := strToInt(s)
if langNoIndex[n/8]&(1<<(n%8)) != 0 {
return Language(n) + langNoIndexOffset, nil
}
// Check for non-canonical uses of ISO3.
for i := lang.Index(s[:1]); i != -1; i = lang.Next(s[:1], i) {
if e := lang.Elem(i); e[2] == s[1] && e[3] == s[2] {
return Language(i), nil
}
}
return 0, NewValueError(s)
}
return 0, ErrSyntax
}
// StringToBuf writes the string to b and returns the number of bytes
// written. cap(b) must be >= 3.
func (id Language) StringToBuf(b []byte) int {
if id >= langNoIndexOffset {
intToStr(uint(id)-langNoIndexOffset, b[:3])
return 3
} else if id == 0 {
return copy(b, "und")
}
l := lang[id<<2:]
if l[3] == 0 {
return copy(b, l[:3])
}
return copy(b, l[:2])
}
// String returns the BCP 47 representation of the langID.
// Use b as variable name, instead of id, to ensure the variable
// used is consistent with that of Base in which this type is embedded.
func (b Language) String() string {
if b == 0 {
return "und"
} else if b >= langNoIndexOffset {
b -= langNoIndexOffset
buf := [3]byte{}
intToStr(uint(b), buf[:])
return string(buf[:])
}
l := lang.Elem(int(b))
if l[3] == 0 {
return l[:3]
}
return l[:2]
}
// ISO3 returns the ISO 639-3 language code.
func (b Language) ISO3() string {
if b == 0 || b >= langNoIndexOffset {
return b.String()
}
l := lang.Elem(int(b))
if l[3] == 0 {
return l[:3]
} else if l[2] == 0 {
return altLangISO3.Elem(int(l[3]))[:3]
}
// This allocation will only happen for 3-letter ISO codes
// that are non-canonical BCP 47 language identifiers.
return l[0:1] + l[2:4]
}
// IsPrivateUse reports whether this language code is reserved for private use.
func (b Language) IsPrivateUse() bool {
return langPrivateStart <= b && b <= langPrivateEnd
}
// SuppressScript returns the script marked as SuppressScript in the IANA
// language tag repository, or 0 if there is no such script.
func (b Language) SuppressScript() Script {
if b < langNoIndexOffset {
return Script(suppressScript[b])
}
return 0
}
type Region uint16
// getRegionID returns the region id for s if s is a valid 2-letter region code
// or unknownRegion.
func getRegionID(s []byte) (Region, error) {
if len(s) == 3 {
if isAlpha(s[0]) {
return getRegionISO3(s)
}
if i, err := strconv.ParseUint(string(s), 10, 10); err == nil {
return getRegionM49(int(i))
}
}
return getRegionISO2(s)
}
// getRegionISO2 returns the regionID for the given 2-letter ISO country code
// or unknownRegion if this does not exist.
func getRegionISO2(s []byte) (Region, error) {
i, err := findIndex(regionISO, s, "ZZ")
if err != nil {
return 0, err
}
return Region(i) + isoRegionOffset, nil
}
// getRegionISO3 returns the regionID for the given 3-letter ISO country code
// or unknownRegion if this does not exist.
func getRegionISO3(s []byte) (Region, error) {
if tag.FixCase("ZZZ", s) {
for i := regionISO.Index(s[:1]); i != -1; i = regionISO.Next(s[:1], i) {
if e := regionISO.Elem(i); e[2] == s[1] && e[3] == s[2] {
return Region(i) + isoRegionOffset, nil
}
}
for i := 0; i < len(altRegionISO3); i += 3 {
if tag.Compare(altRegionISO3[i:i+3], s) == 0 {
return Region(altRegionIDs[i/3]), nil
}
}
return 0, NewValueError(s)
}
return 0, ErrSyntax
}
func getRegionM49(n int) (Region, error) {
if 0 < n && n <= 999 {
const (
searchBits = 7
regionBits = 9
regionMask = 1<<regionBits - 1
)
idx := n >> searchBits
buf := fromM49[m49Index[idx]:m49Index[idx+1]]
val := uint16(n) << regionBits // we rely on bits shifting out
i := sort.Search(len(buf), func(i int) bool {
return buf[i] >= val
})
if r := fromM49[int(m49Index[idx])+i]; r&^regionMask == val {
return Region(r & regionMask), nil
}
}
var e ValueError
fmt.Fprint(bytes.NewBuffer([]byte(e.v[:])), n)
return 0, e
}
// normRegion returns a region if r is deprecated or 0 otherwise.
// TODO: consider supporting BYS (-> BLR), CSK (-> 200 or CZ), PHI (-> PHL) and AFI (-> DJ).
// TODO: consider mapping split up regions to new most populous one (like CLDR).
func normRegion(r Region) Region {
m := regionOldMap
k := sort.Search(len(m), func(i int) bool {
return m[i].From >= uint16(r)
})
if k < len(m) && m[k].From == uint16(r) {
return Region(m[k].To)
}
return 0
}
const (
iso3166UserAssigned = 1 << iota
ccTLD
bcp47Region
)
func (r Region) typ() byte {
return regionTypes[r]
}
// String returns the BCP 47 representation for the region.
// It returns "ZZ" for an unspecified region.
func (r Region) String() string {
if r < isoRegionOffset {
if r == 0 {
return "ZZ"
}
return fmt.Sprintf("%03d", r.M49())
}
r -= isoRegionOffset
return regionISO.Elem(int(r))[:2]
}
// ISO3 returns the 3-letter ISO code of r.
// Note that not all regions have a 3-letter ISO code.
// In such cases this method returns "ZZZ".
func (r Region) ISO3() string {
if r < isoRegionOffset {
return "ZZZ"
}
r -= isoRegionOffset
reg := regionISO.Elem(int(r))
switch reg[2] {
case 0:
return altRegionISO3[reg[3]:][:3]
case ' ':
return "ZZZ"
}
return reg[0:1] + reg[2:4]
}
// M49 returns the UN M.49 encoding of r, or 0 if this encoding
// is not defined for r.
func (r Region) M49() int {
return int(m49[r])
}
// IsPrivateUse reports whether r has the ISO 3166 User-assigned status. This
// may include private-use tags that are assigned by CLDR and used in this
// implementation. So IsPrivateUse and IsCountry can be simultaneously true.
func (r Region) IsPrivateUse() bool {
return r.typ()&iso3166UserAssigned != 0
}
type Script uint16
// getScriptID returns the script id for string s. It assumes that s
// is of the format [A-Z][a-z]{3}.
func getScriptID(idx tag.Index, s []byte) (Script, error) {
i, err := findIndex(idx, s, "Zzzz")
return Script(i), err
}
// String returns the script code in title case.
// It returns "Zzzz" for an unspecified script.
func (s Script) String() string {
if s == 0 {
return "Zzzz"
}
return script.Elem(int(s))
}
// IsPrivateUse reports whether this script code is reserved for private use.
func (s Script) IsPrivateUse() bool {
return _Qaaa <= s && s <= _Qabx
}
const (
maxAltTaglen = len("en-US-POSIX")
maxLen = maxAltTaglen
)
var (
// grandfatheredMap holds a mapping from legacy and grandfathered tags to
// their base language or index to more elaborate tag.
grandfatheredMap = map[[maxLen]byte]int16{
[maxLen]byte{'a', 'r', 't', '-', 'l', 'o', 'j', 'b', 'a', 'n'}: _jbo, // art-lojban
[maxLen]byte{'i', '-', 'a', 'm', 'i'}: _ami, // i-ami
[maxLen]byte{'i', '-', 'b', 'n', 'n'}: _bnn, // i-bnn
[maxLen]byte{'i', '-', 'h', 'a', 'k'}: _hak, // i-hak
[maxLen]byte{'i', '-', 'k', 'l', 'i', 'n', 'g', 'o', 'n'}: _tlh, // i-klingon
[maxLen]byte{'i', '-', 'l', 'u', 'x'}: _lb, // i-lux
[maxLen]byte{'i', '-', 'n', 'a', 'v', 'a', 'j', 'o'}: _nv, // i-navajo
[maxLen]byte{'i', '-', 'p', 'w', 'n'}: _pwn, // i-pwn
[maxLen]byte{'i', '-', 't', 'a', 'o'}: _tao, // i-tao
[maxLen]byte{'i', '-', 't', 'a', 'y'}: _tay, // i-tay
[maxLen]byte{'i', '-', 't', 's', 'u'}: _tsu, // i-tsu
[maxLen]byte{'n', 'o', '-', 'b', 'o', 'k'}: _nb, // no-bok
[maxLen]byte{'n', 'o', '-', 'n', 'y', 'n'}: _nn, // no-nyn
[maxLen]byte{'s', 'g', 'n', '-', 'b', 'e', '-', 'f', 'r'}: _sfb, // sgn-BE-FR
[maxLen]byte{'s', 'g', 'n', '-', 'b', 'e', '-', 'n', 'l'}: _vgt, // sgn-BE-NL
[maxLen]byte{'s', 'g', 'n', '-', 'c', 'h', '-', 'd', 'e'}: _sgg, // sgn-CH-DE
[maxLen]byte{'z', 'h', '-', 'g', 'u', 'o', 'y', 'u'}: _cmn, // zh-guoyu
[maxLen]byte{'z', 'h', '-', 'h', 'a', 'k', 'k', 'a'}: _hak, // zh-hakka
[maxLen]byte{'z', 'h', '-', 'm', 'i', 'n', '-', 'n', 'a', 'n'}: _nan, // zh-min-nan
[maxLen]byte{'z', 'h', '-', 'x', 'i', 'a', 'n', 'g'}: _hsn, // zh-xiang
// Grandfathered tags with no modern replacement will be converted as
// follows:
[maxLen]byte{'c', 'e', 'l', '-', 'g', 'a', 'u', 'l', 'i', 's', 'h'}: -1, // cel-gaulish
[maxLen]byte{'e', 'n', '-', 'g', 'b', '-', 'o', 'e', 'd'}: -2, // en-GB-oed
[maxLen]byte{'i', '-', 'd', 'e', 'f', 'a', 'u', 'l', 't'}: -3, // i-default
[maxLen]byte{'i', '-', 'e', 'n', 'o', 'c', 'h', 'i', 'a', 'n'}: -4, // i-enochian
[maxLen]byte{'i', '-', 'm', 'i', 'n', 'g', 'o'}: -5, // i-mingo
[maxLen]byte{'z', 'h', '-', 'm', 'i', 'n'}: -6, // zh-min
// CLDR-specific tag.
[maxLen]byte{'r', 'o', 'o', 't'}: 0, // root
[maxLen]byte{'e', 'n', '-', 'u', 's', '-', 'p', 'o', 's', 'i', 'x'}: -7, // en_US_POSIX"
}
altTagIndex = [...]uint8{0, 17, 31, 45, 61, 74, 86, 102}
altTags = "xtg-x-cel-gaulishen-GB-oxendicten-x-i-defaultund-x-i-enochiansee-x-i-mingonan-x-zh-minen-US-u-va-posix"
)
func grandfathered(s [maxAltTaglen]byte) (t Tag, ok bool) {
if v, ok := grandfatheredMap[s]; ok {
if v < 0 {
return Make(altTags[altTagIndex[-v-1]:altTagIndex[-v]]), true
}
t.LangID = Language(v)
return t, true
}
return t, false
}
// Copyright 2013 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 language
import "errors"
type scriptRegionFlags uint8
const (
isList = 1 << iota
scriptInFrom
regionInFrom
)
func (t *Tag) setUndefinedLang(id Language) {
if t.LangID == 0 {
t.LangID = id
}
}
func (t *Tag) setUndefinedScript(id Script) {
if t.ScriptID == 0 {
t.ScriptID = id
}
}
func (t *Tag) setUndefinedRegion(id Region) {
if t.RegionID == 0 || t.RegionID.Contains(id) {
t.RegionID = id
}
}
// ErrMissingLikelyTagsData indicates no information was available
// to compute likely values of missing tags.
var ErrMissingLikelyTagsData = errors.New("missing likely tags data")
// addLikelySubtags sets subtags to their most likely value, given the locale.
// In most cases this means setting fields for unknown values, but in some
// cases it may alter a value. It returns an ErrMissingLikelyTagsData error
// if the given locale cannot be expanded.
func (t Tag) addLikelySubtags() (Tag, error) {
id, err := addTags(t)
if err != nil {
return t, err
} else if id.equalTags(t) {
return t, nil
}
id.RemakeString()
return id, nil
}
// specializeRegion attempts to specialize a group region.
func specializeRegion(t *Tag) bool {
if i := regionInclusion[t.RegionID]; i < nRegionGroups {
x := likelyRegionGroup[i]
if Language(x.lang) == t.LangID && Script(x.script) == t.ScriptID {
t.RegionID = Region(x.region)
}
return true
}
return false
}
// Maximize returns a new tag with missing tags filled in.
func (t Tag) Maximize() (Tag, error) {
return addTags(t)
}
func addTags(t Tag) (Tag, error) {
// We leave private use identifiers alone.
if t.IsPrivateUse() {
return t, nil
}
if t.ScriptID != 0 && t.RegionID != 0 {
if t.LangID != 0 {
// already fully specified
specializeRegion(&t)
return t, nil
}
// Search matches for und-script-region. Note that for these cases
// region will never be a group so there is no need to check for this.
list := likelyRegion[t.RegionID : t.RegionID+1]
if x := list[0]; x.flags&isList != 0 {
list = likelyRegionList[x.lang : x.lang+uint16(x.script)]
}
for _, x := range list {
// Deviating from the spec. See match_test.go for details.
if Script(x.script) == t.ScriptID {
t.setUndefinedLang(Language(x.lang))
return t, nil
}
}
}
if t.LangID != 0 {
// Search matches for lang-script and lang-region, where lang != und.
if t.LangID < langNoIndexOffset {
x := likelyLang[t.LangID]
if x.flags&isList != 0 {
list := likelyLangList[x.region : x.region+uint16(x.script)]
if t.ScriptID != 0 {
for _, x := range list {
if Script(x.script) == t.ScriptID && x.flags&scriptInFrom != 0 {
t.setUndefinedRegion(Region(x.region))
return t, nil
}
}
} else if t.RegionID != 0 {
count := 0
goodScript := true
tt := t
for _, x := range list {
// We visit all entries for which the script was not
// defined, including the ones where the region was not
// defined. This allows for proper disambiguation within
// regions.
if x.flags&scriptInFrom == 0 && t.RegionID.Contains(Region(x.region)) {
tt.RegionID = Region(x.region)
tt.setUndefinedScript(Script(x.script))
goodScript = goodScript && tt.ScriptID == Script(x.script)
count++
}
}
if count == 1 {
return tt, nil
}
// Even if we fail to find a unique Region, we might have
// an unambiguous script.
if goodScript {
t.ScriptID = tt.ScriptID
}
}
}
}
} else {
// Search matches for und-script.
if t.ScriptID != 0 {
x := likelyScript[t.ScriptID]
if x.region != 0 {
t.setUndefinedRegion(Region(x.region))
t.setUndefinedLang(Language(x.lang))
return t, nil
}
}
// Search matches for und-region. If und-script-region exists, it would
// have been found earlier.
if t.RegionID != 0 {
if i := regionInclusion[t.RegionID]; i < nRegionGroups {
x := likelyRegionGroup[i]
if x.region != 0 {
t.setUndefinedLang(Language(x.lang))
t.setUndefinedScript(Script(x.script))
t.RegionID = Region(x.region)
}
} else {
x := likelyRegion[t.RegionID]
if x.flags&isList != 0 {
x = likelyRegionList[x.lang]
}
if x.script != 0 && x.flags != scriptInFrom {
t.setUndefinedLang(Language(x.lang))
t.setUndefinedScript(Script(x.script))
return t, nil
}
}
}
}
// Search matches for lang.
if t.LangID < langNoIndexOffset {
x := likelyLang[t.LangID]
if x.flags&isList != 0 {
x = likelyLangList[x.region]
}
if x.region != 0 {
t.setUndefinedScript(Script(x.script))
t.setUndefinedRegion(Region(x.region))
}
specializeRegion(&t)
if t.LangID == 0 {
t.LangID = _en // default language
}
return t, nil
}
return t, ErrMissingLikelyTagsData
}
func (t *Tag) setTagsFrom(id Tag) {
t.LangID = id.LangID
t.ScriptID = id.ScriptID
t.RegionID = id.RegionID
}
// minimize removes the region or script subtags from t such that
// t.addLikelySubtags() == t.minimize().addLikelySubtags().
func (t Tag) minimize() (Tag, error) {
t, err := minimizeTags(t)
if err != nil {
return t, err
}
t.RemakeString()
return t, nil
}
// minimizeTags mimics the behavior of the ICU 51 C implementation.
func minimizeTags(t Tag) (Tag, error) {
if t.equalTags(Und) {
return t, nil
}
max, err := addTags(t)
if err != nil {
return t, err
}
for _, id := range [...]Tag{
{LangID: t.LangID},
{LangID: t.LangID, RegionID: t.RegionID},
{LangID: t.LangID, ScriptID: t.ScriptID},
} {
if x, err := addTags(id); err == nil && max.equalTags(x) {
t.setTagsFrom(id)
break
}
}
return t, nil
}
// Copyright 2013 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 language
import (
"bytes"
"errors"
"fmt"
"sort"
"golang.org/x/text/internal/tag"
)
// isAlpha returns true if the byte is not a digit.
// b must be an ASCII letter or digit.
func isAlpha(b byte) bool {
return b > '9'
}
// isAlphaNum returns true if the string contains only ASCII letters or digits.
func isAlphaNum(s []byte) bool {
for _, c := range s {
if !('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9') {
return false
}
}
return true
}
// ErrSyntax is returned by any of the parsing functions when the
// input is not well-formed, according to BCP 47.
// TODO: return the position at which the syntax error occurred?
var ErrSyntax = errors.New("language: tag is not well-formed")
// ErrDuplicateKey is returned when a tag contains the same key twice with
// different values in the -u section.
var ErrDuplicateKey = errors.New("language: different values for same key in -u extension")
// ValueError is returned by any of the parsing functions when the
// input is well-formed but the respective subtag is not recognized
// as a valid value.
type ValueError struct {
v [8]byte
}
// NewValueError creates a new ValueError.
func NewValueError(tag []byte) ValueError {
var e ValueError
copy(e.v[:], tag)
return e
}
func (e ValueError) tag() []byte {
n := bytes.IndexByte(e.v[:], 0)
if n == -1 {
n = 8
}
return e.v[:n]
}
// Error implements the error interface.
func (e ValueError) Error() string {
return fmt.Sprintf("language: subtag %q is well-formed but unknown", e.tag())
}
// Subtag returns the subtag for which the error occurred.
func (e ValueError) Subtag() string {
return string(e.tag())
}
// scanner is used to scan BCP 47 tokens, which are separated by _ or -.
type scanner struct {
b []byte
bytes [max99thPercentileSize]byte
token []byte
start int // start position of the current token
end int // end position of the current token
next int // next point for scan
err error
done bool
}
func makeScannerString(s string) scanner {
scan := scanner{}
if len(s) <= len(scan.bytes) {
scan.b = scan.bytes[:copy(scan.bytes[:], s)]
} else {
scan.b = []byte(s)
}
scan.init()
return scan
}
// makeScanner returns a scanner using b as the input buffer.
// b is not copied and may be modified by the scanner routines.
func makeScanner(b []byte) scanner {
scan := scanner{b: b}
scan.init()
return scan
}
func (s *scanner) init() {
for i, c := range s.b {
if c == '_' {
s.b[i] = '-'
}
}
s.scan()
}
// restToLower converts the string between start and end to lower case.
func (s *scanner) toLower(start, end int) {
for i := start; i < end; i++ {
c := s.b[i]
if 'A' <= c && c <= 'Z' {
s.b[i] += 'a' - 'A'
}
}
}
func (s *scanner) setError(e error) {
if s.err == nil || (e == ErrSyntax && s.err != ErrSyntax) {
s.err = e
}
}
// resizeRange shrinks or grows the array at position oldStart such that
// a new string of size newSize can fit between oldStart and oldEnd.
// Sets the scan point to after the resized range.
func (s *scanner) resizeRange(oldStart, oldEnd, newSize int) {
s.start = oldStart
if end := oldStart + newSize; end != oldEnd {
diff := end - oldEnd
var b []byte
if n := len(s.b) + diff; n > cap(s.b) {
b = make([]byte, n)
copy(b, s.b[:oldStart])
} else {
b = s.b[:n]
}
copy(b[end:], s.b[oldEnd:])
s.b = b
s.next = end + (s.next - s.end)
s.end = end
}
}
// replace replaces the current token with repl.
func (s *scanner) replace(repl string) {
s.resizeRange(s.start, s.end, len(repl))
copy(s.b[s.start:], repl)
}
// gobble removes the current token from the input.
// Caller must call scan after calling gobble.
func (s *scanner) gobble(e error) {
s.setError(e)
if s.start == 0 {
s.b = s.b[:+copy(s.b, s.b[s.next:])]
s.end = 0
} else {
s.b = s.b[:s.start-1+copy(s.b[s.start-1:], s.b[s.end:])]
s.end = s.start - 1
}
s.next = s.start
}
// deleteRange removes the given range from s.b before the current token.
func (s *scanner) deleteRange(start, end int) {
s.b = s.b[:start+copy(s.b[start:], s.b[end:])]
diff := end - start
s.next -= diff
s.start -= diff
s.end -= diff
}
// scan parses the next token of a BCP 47 string. Tokens that are larger
// than 8 characters or include non-alphanumeric characters result in an error
// and are gobbled and removed from the output.
// It returns the end position of the last token consumed.
func (s *scanner) scan() (end int) {
end = s.end
s.token = nil
for s.start = s.next; s.next < len(s.b); {
i := bytes.IndexByte(s.b[s.next:], '-')
if i == -1 {
s.end = len(s.b)
s.next = len(s.b)
i = s.end - s.start
} else {
s.end = s.next + i
s.next = s.end + 1
}
token := s.b[s.start:s.end]
if i < 1 || i > 8 || !isAlphaNum(token) {
s.gobble(ErrSyntax)
continue
}
s.token = token
return end
}
if n := len(s.b); n > 0 && s.b[n-1] == '-' {
s.setError(ErrSyntax)
s.b = s.b[:len(s.b)-1]
}
s.done = true
return end
}
// acceptMinSize parses multiple tokens of the given size or greater.
// It returns the end position of the last token consumed.
func (s *scanner) acceptMinSize(min int) (end int) {
end = s.end
s.scan()
for ; len(s.token) >= min; s.scan() {
end = s.end
}
return end
}
// Parse parses the given BCP 47 string and returns a valid Tag. If parsing
// failed it returns an error and any part of the tag that could be parsed.
// If parsing succeeded but an unknown value was found, it returns
// ValueError. The Tag returned in this case is just stripped of the unknown
// value. All other values are preserved. It accepts tags in the BCP 47 format
// and extensions to this standard defined in
// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
func Parse(s string) (t Tag, err error) {
// TODO: consider supporting old-style locale key-value pairs.
if s == "" {
return Und, ErrSyntax
}
defer func() {
if recover() != nil {
t = Und
err = ErrSyntax
return
}
}()
if len(s) <= maxAltTaglen {
b := [maxAltTaglen]byte{}
for i, c := range s {
// Generating invalid UTF-8 is okay as it won't match.
if 'A' <= c && c <= 'Z' {
c += 'a' - 'A'
} else if c == '_' {
c = '-'
}
b[i] = byte(c)
}
if t, ok := grandfathered(b); ok {
return t, nil
}
}
scan := makeScannerString(s)
return parse(&scan, s)
}
func parse(scan *scanner, s string) (t Tag, err error) {
t = Und
var end int
if n := len(scan.token); n <= 1 {
scan.toLower(0, len(scan.b))
if n == 0 || scan.token[0] != 'x' {
return t, ErrSyntax
}
end = parseExtensions(scan)
} else if n >= 4 {
return Und, ErrSyntax
} else { // the usual case
t, end = parseTag(scan, true)
if n := len(scan.token); n == 1 {
t.pExt = uint16(end)
end = parseExtensions(scan)
} else if end < len(scan.b) {
scan.setError(ErrSyntax)
scan.b = scan.b[:end]
}
}
if int(t.pVariant) < len(scan.b) {
if end < len(s) {
s = s[:end]
}
if len(s) > 0 && tag.Compare(s, scan.b) == 0 {
t.str = s
} else {
t.str = string(scan.b)
}
} else {
t.pVariant, t.pExt = 0, 0
}
return t, scan.err
}
// parseTag parses language, script, region and variants.
// It returns a Tag and the end position in the input that was parsed.
// If doNorm is true, then <lang>-<extlang> will be normalized to <extlang>.
func parseTag(scan *scanner, doNorm bool) (t Tag, end int) {
var e error
// TODO: set an error if an unknown lang, script or region is encountered.
t.LangID, e = getLangID(scan.token)
scan.setError(e)
scan.replace(t.LangID.String())
langStart := scan.start
end = scan.scan()
for len(scan.token) == 3 && isAlpha(scan.token[0]) {
// From http://tools.ietf.org/html/bcp47, <lang>-<extlang> tags are equivalent
// to a tag of the form <extlang>.
if doNorm {
lang, e := getLangID(scan.token)
if lang != 0 {
t.LangID = lang
langStr := lang.String()
copy(scan.b[langStart:], langStr)
scan.b[langStart+len(langStr)] = '-'
scan.start = langStart + len(langStr) + 1
}
scan.gobble(e)
}
end = scan.scan()
}
if len(scan.token) == 4 && isAlpha(scan.token[0]) {
t.ScriptID, e = getScriptID(script, scan.token)
if t.ScriptID == 0 {
scan.gobble(e)
}
end = scan.scan()
}
if n := len(scan.token); n >= 2 && n <= 3 {
t.RegionID, e = getRegionID(scan.token)
if t.RegionID == 0 {
scan.gobble(e)
} else {
scan.replace(t.RegionID.String())
}
end = scan.scan()
}
scan.toLower(scan.start, len(scan.b))
t.pVariant = byte(end)
end = parseVariants(scan, end, t)
t.pExt = uint16(end)
return t, end
}
var separator = []byte{'-'}
// parseVariants scans tokens as long as each token is a valid variant string.
// Duplicate variants are removed.
func parseVariants(scan *scanner, end int, t Tag) int {
start := scan.start
varIDBuf := [4]uint8{}
variantBuf := [4][]byte{}
varID := varIDBuf[:0]
variant := variantBuf[:0]
last := -1
needSort := false
for ; len(scan.token) >= 4; scan.scan() {
// TODO: measure the impact of needing this conversion and redesign
// the data structure if there is an issue.
v, ok := variantIndex[string(scan.token)]
if !ok {
// unknown variant
// TODO: allow user-defined variants?
scan.gobble(NewValueError(scan.token))
continue
}
varID = append(varID, v)
variant = append(variant, scan.token)
if !needSort {
if last < int(v) {
last = int(v)
} else {
needSort = true
// There is no legal combinations of more than 7 variants
// (and this is by no means a useful sequence).
const maxVariants = 8
if len(varID) > maxVariants {
break
}
}
}
end = scan.end
}
if needSort {
sort.Sort(variantsSort{varID, variant})
k, l := 0, -1
for i, v := range varID {
w := int(v)
if l == w {
// Remove duplicates.
continue
}
varID[k] = varID[i]
variant[k] = variant[i]
k++
l = w
}
if str := bytes.Join(variant[:k], separator); len(str) == 0 {
end = start - 1
} else {
scan.resizeRange(start, end, len(str))
copy(scan.b[scan.start:], str)
end = scan.end
}
}
return end
}
type variantsSort struct {
i []uint8
v [][]byte
}
func (s variantsSort) Len() int {
return len(s.i)
}
func (s variantsSort) Swap(i, j int) {
s.i[i], s.i[j] = s.i[j], s.i[i]
s.v[i], s.v[j] = s.v[j], s.v[i]
}
func (s variantsSort) Less(i, j int) bool {
return s.i[i] < s.i[j]
}
type bytesSort struct {
b [][]byte
n int // first n bytes to compare
}
func (b bytesSort) Len() int {
return len(b.b)
}
func (b bytesSort) Swap(i, j int) {
b.b[i], b.b[j] = b.b[j], b.b[i]
}
func (b bytesSort) Less(i, j int) bool {
for k := 0; k < b.n; k++ {
if b.b[i][k] == b.b[j][k] {
continue
}
return b.b[i][k] < b.b[j][k]
}
return false
}
// parseExtensions parses and normalizes the extensions in the buffer.
// It returns the last position of scan.b that is part of any extension.
// It also trims scan.b to remove excess parts accordingly.
func parseExtensions(scan *scanner) int {
start := scan.start
exts := [][]byte{}
private := []byte{}
end := scan.end
for len(scan.token) == 1 {
extStart := scan.start
ext := scan.token[0]
end = parseExtension(scan)
extension := scan.b[extStart:end]
if len(extension) < 3 || (ext != 'x' && len(extension) < 4) {
scan.setError(ErrSyntax)
end = extStart
continue
} else if start == extStart && (ext == 'x' || scan.start == len(scan.b)) {
scan.b = scan.b[:end]
return end
} else if ext == 'x' {
private = extension
break
}
exts = append(exts, extension)
}
sort.Sort(bytesSort{exts, 1})
if len(private) > 0 {
exts = append(exts, private)
}
scan.b = scan.b[:start]
if len(exts) > 0 {
scan.b = append(scan.b, bytes.Join(exts, separator)...)
} else if start > 0 {
// Strip trailing '-'.
scan.b = scan.b[:start-1]
}
return end
}
// parseExtension parses a single extension and returns the position of
// the extension end.
func parseExtension(scan *scanner) int {
start, end := scan.start, scan.end
switch scan.token[0] {
case 'u': // https://www.ietf.org/rfc/rfc6067.txt
attrStart := end
scan.scan()
for last := []byte{}; len(scan.token) > 2; scan.scan() {
if bytes.Compare(scan.token, last) != -1 {
// Attributes are unsorted. Start over from scratch.
p := attrStart + 1
scan.next = p
attrs := [][]byte{}
for scan.scan(); len(scan.token) > 2; scan.scan() {
attrs = append(attrs, scan.token)
end = scan.end
}
sort.Sort(bytesSort{attrs, 3})
copy(scan.b[p:], bytes.Join(attrs, separator))
break
}
last = scan.token
end = scan.end
}
// Scan key-type sequences. A key is of length 2 and may be followed
// by 0 or more "type" subtags from 3 to the maximum of 8 letters.
var last, key []byte
for attrEnd := end; len(scan.token) == 2; last = key {
key = scan.token
end = scan.end
for scan.scan(); end < scan.end && len(scan.token) > 2; scan.scan() {
end = scan.end
}
// TODO: check key value validity
if bytes.Compare(key, last) != 1 || scan.err != nil {
// We have an invalid key or the keys are not sorted.
// Start scanning keys from scratch and reorder.
p := attrEnd + 1
scan.next = p
keys := [][]byte{}
for scan.scan(); len(scan.token) == 2; {
keyStart := scan.start
end = scan.end
for scan.scan(); end < scan.end && len(scan.token) > 2; scan.scan() {
end = scan.end
}
keys = append(keys, scan.b[keyStart:end])
}
sort.Stable(bytesSort{keys, 2})
if n := len(keys); n > 0 {
k := 0
for i := 1; i < n; i++ {
if !bytes.Equal(keys[k][:2], keys[i][:2]) {
k++
keys[k] = keys[i]
} else if !bytes.Equal(keys[k], keys[i]) {
scan.setError(ErrDuplicateKey)
}
}
keys = keys[:k+1]
}
reordered := bytes.Join(keys, separator)
if e := p + len(reordered); e < end {
scan.deleteRange(e, end)
end = e
}
copy(scan.b[p:], reordered)
break
}
}
case 't': // https://www.ietf.org/rfc/rfc6497.txt
scan.scan()
if n := len(scan.token); n >= 2 && n <= 3 && isAlpha(scan.token[1]) {
_, end = parseTag(scan, false)
scan.toLower(start, end)
}
for len(scan.token) == 2 && !isAlpha(scan.token[1]) {
end = scan.acceptMinSize(3)
}
case 'x':
end = scan.acceptMinSize(1)
default:
end = scan.acceptMinSize(2)
}
return end
}
// getExtension returns the name, body and end position of the extension.
func getExtension(s string, p int) (end int, ext string) {
if s[p] == '-' {
p++
}
if s[p] == 'x' {
return len(s), s[p:]
}
end = nextExtension(s, p)
return end, s[p:end]
}
// nextExtension finds the next extension within the string, searching
// for the -<char>- pattern from position p.
// In the fast majority of cases, language tags will have at most
// one extension and extensions tend to be small.
func nextExtension(s string, p int) int {
for n := len(s) - 3; p < n; {
if s[p] == '-' {
if s[p+2] == '-' {
return p
}
p += 3
} else {
p++
}
}
return len(s)
}
// Copyright 2013 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 language
// MustParse is like Parse, but panics if the given BCP 47 tag cannot be parsed.
// It simplifies safe initialization of Tag values.
func MustParse(s string) Tag {
t, err := Parse(s)
if err != nil {
panic(err)
}
return t
}
// MustParseBase is like ParseBase, but panics if the given base cannot be parsed.
// It simplifies safe initialization of Base values.
func MustParseBase(s string) Language {
b, err := ParseBase(s)
if err != nil {
panic(err)
}
return b
}
// MustParseScript is like ParseScript, but panics if the given script cannot be
// parsed. It simplifies safe initialization of Script values.
func MustParseScript(s string) Script {
scr, err := ParseScript(s)
if err != nil {
panic(err)
}
return scr
}
// MustParseRegion is like ParseRegion, but panics if the given region cannot be
// parsed. It simplifies safe initialization of Region values.
func MustParseRegion(s string) Region {
r, err := ParseRegion(s)
if err != nil {
panic(err)
}
return r
}
// Und is the root language.
var Und Tag
// 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.
package internal
// This file contains matchers that implement CLDR inheritance.
//
// See https://unicode.org/reports/tr35/#Locale_Inheritance.
//
// Some of the inheritance described in this document is already handled by
// the cldr package.
import (
"golang.org/x/text/language"
)
// TODO: consider if (some of the) matching algorithm needs to be public after
// getting some feel about what is generic and what is specific.
// NewInheritanceMatcher returns a matcher that matches based on the inheritance
// chain.
//
// The matcher uses canonicalization and the parent relationship to find a
// match. The resulting match will always be either Und or a language with the
// same language and script as the requested language. It will not match
// languages for which there is understood to be mutual or one-directional
// intelligibility.
//
// A Match will indicate an Exact match if the language matches after
// canonicalization and High if the matched tag is a parent.
func NewInheritanceMatcher(t []language.Tag) *InheritanceMatcher {
tags := &InheritanceMatcher{make(map[language.Tag]int)}
for i, tag := range t {
ct, err := language.All.Canonicalize(tag)
if err != nil {
ct = tag
}
tags.index[ct] = i
}
return tags
}
type InheritanceMatcher struct {
index map[language.Tag]int
}
func (m InheritanceMatcher) Match(want ...language.Tag) (language.Tag, int, language.Confidence) {
for _, t := range want {
ct, err := language.All.Canonicalize(t)
if err != nil {
ct = t
}
conf := language.Exact
for {
if index, ok := m.index[ct]; ok {
return ct, index, conf
}
if ct == language.Und {
break
}
ct = ct.Parent()
conf = language.High
}
}
return language.Und, 0, language.No
}
// 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.
//go:generate stringer -type RoundingMode
package number
import (
"math"
"strconv"
)
// RoundingMode determines how a number is rounded to the desired precision.
type RoundingMode byte
const (
ToNearestEven RoundingMode = iota // towards the nearest integer, or towards an even number if equidistant.
ToNearestZero // towards the nearest integer, or towards zero if equidistant.
ToNearestAway // towards the nearest integer, or away from zero if equidistant.
ToPositiveInf // towards infinity
ToNegativeInf // towards negative infinity
ToZero // towards zero
AwayFromZero // away from zero
numModes
)
const maxIntDigits = 20
// A Decimal represents a floating point number in decimal format.
// Digits represents a number [0, 1.0), and the absolute value represented by
// Decimal is Digits * 10^Exp. Leading and trailing zeros may be omitted and Exp
// may point outside a valid position in Digits.
//
// Examples:
//
// Number Decimal
// 12345 Digits: [1, 2, 3, 4, 5], Exp: 5
// 12.345 Digits: [1, 2, 3, 4, 5], Exp: 2
// 12000 Digits: [1, 2], Exp: 5
// 12000.00 Digits: [1, 2], Exp: 5
// 0.00123 Digits: [1, 2, 3], Exp: -2
// 0 Digits: [], Exp: 0
type Decimal struct {
digits
buf [maxIntDigits]byte
}
type digits struct {
Digits []byte // mantissa digits, big-endian
Exp int32 // exponent
Neg bool
Inf bool // Takes precedence over Digits and Exp.
NaN bool // Takes precedence over Inf.
}
// Digits represents a floating point number represented in digits of the
// base in which a number is to be displayed. It is similar to Decimal, but
// keeps track of trailing fraction zeros and the comma placement for
// engineering notation. Digits must have at least one digit.
//
// Examples:
//
// Number Decimal
// decimal
// 12345 Digits: [1, 2, 3, 4, 5], Exp: 5 End: 5
// 12.345 Digits: [1, 2, 3, 4, 5], Exp: 2 End: 5
// 12000 Digits: [1, 2], Exp: 5 End: 5
// 12000.00 Digits: [1, 2], Exp: 5 End: 7
// 0.00123 Digits: [1, 2, 3], Exp: -2 End: 3
// 0 Digits: [], Exp: 0 End: 1
// scientific (actual exp is Exp - Comma)
// 0e0 Digits: [0], Exp: 1, End: 1, Comma: 1
// .0e0 Digits: [0], Exp: 0, End: 1, Comma: 0
// 0.0e0 Digits: [0], Exp: 1, End: 2, Comma: 1
// 1.23e4 Digits: [1, 2, 3], Exp: 5, End: 3, Comma: 1
// .123e5 Digits: [1, 2, 3], Exp: 5, End: 3, Comma: 0
// engineering
// 12.3e3 Digits: [1, 2, 3], Exp: 5, End: 3, Comma: 2
type Digits struct {
digits
// End indicates the end position of the number.
End int32 // For decimals Exp <= End. For scientific len(Digits) <= End.
// Comma is used for the comma position for scientific (always 0 or 1) and
// engineering notation (always 0, 1, 2, or 3).
Comma uint8
// IsScientific indicates whether this number is to be rendered as a
// scientific number.
IsScientific bool
}
func (d *Digits) NumFracDigits() int {
if d.Exp >= d.End {
return 0
}
return int(d.End - d.Exp)
}
// normalize returns a new Decimal with leading and trailing zeros removed.
func (d *Decimal) normalize() (n Decimal) {
n = *d
b := n.Digits
// Strip leading zeros. Resulting number of digits is significant digits.
for len(b) > 0 && b[0] == 0 {
b = b[1:]
n.Exp--
}
// Strip trailing zeros
for len(b) > 0 && b[len(b)-1] == 0 {
b = b[:len(b)-1]
}
if len(b) == 0 {
n.Exp = 0
}
n.Digits = b
return n
}
func (d *Decimal) clear() {
b := d.Digits
if b == nil {
b = d.buf[:0]
}
*d = Decimal{}
d.Digits = b[:0]
}
func (x *Decimal) String() string {
if x.NaN {
return "NaN"
}
var buf []byte
if x.Neg {
buf = append(buf, '-')
}
if x.Inf {
buf = append(buf, "Inf"...)
return string(buf)
}
switch {
case len(x.Digits) == 0:
buf = append(buf, '0')
case x.Exp <= 0:
// 0.00ddd
buf = append(buf, "0."...)
buf = appendZeros(buf, -int(x.Exp))
buf = appendDigits(buf, x.Digits)
case /* 0 < */ int(x.Exp) < len(x.Digits):
// dd.ddd
buf = appendDigits(buf, x.Digits[:x.Exp])
buf = append(buf, '.')
buf = appendDigits(buf, x.Digits[x.Exp:])
default: // len(x.Digits) <= x.Exp
// ddd00
buf = appendDigits(buf, x.Digits)
buf = appendZeros(buf, int(x.Exp)-len(x.Digits))
}
return string(buf)
}
func appendDigits(buf []byte, digits []byte) []byte {
for _, c := range digits {
buf = append(buf, c+'0')
}
return buf
}
// appendZeros appends n 0 digits to buf and returns buf.
func appendZeros(buf []byte, n int) []byte {
for ; n > 0; n-- {
buf = append(buf, '0')
}
return buf
}
func (d *digits) round(mode RoundingMode, n int) {
if n >= len(d.Digits) {
return
}
// Make rounding decision: The result mantissa is truncated ("rounded down")
// by default. Decide if we need to increment, or "round up", the (unsigned)
// mantissa.
inc := false
switch mode {
case ToNegativeInf:
inc = d.Neg
case ToPositiveInf:
inc = !d.Neg
case ToZero:
// nothing to do
case AwayFromZero:
inc = true
case ToNearestEven:
inc = d.Digits[n] > 5 || d.Digits[n] == 5 &&
(len(d.Digits) > n+1 || n == 0 || d.Digits[n-1]&1 != 0)
case ToNearestAway:
inc = d.Digits[n] >= 5
case ToNearestZero:
inc = d.Digits[n] > 5 || d.Digits[n] == 5 && len(d.Digits) > n+1
default:
panic("unreachable")
}
if inc {
d.roundUp(n)
} else {
d.roundDown(n)
}
}
// roundFloat rounds a floating point number.
func (r RoundingMode) roundFloat(x float64) float64 {
// Make rounding decision: The result mantissa is truncated ("rounded down")
// by default. Decide if we need to increment, or "round up", the (unsigned)
// mantissa.
abs := x
if x < 0 {
abs = -x
}
i, f := math.Modf(abs)
if f == 0.0 {
return x
}
inc := false
switch r {
case ToNegativeInf:
inc = x < 0
case ToPositiveInf:
inc = x >= 0
case ToZero:
// nothing to do
case AwayFromZero:
inc = true
case ToNearestEven:
// TODO: check overflow
inc = f > 0.5 || f == 0.5 && int64(i)&1 != 0
case ToNearestAway:
inc = f >= 0.5
case ToNearestZero:
inc = f > 0.5
default:
panic("unreachable")
}
if inc {
i += 1
}
if abs != x {
i = -i
}
return i
}
func (x *digits) roundUp(n int) {
if n < 0 || n >= len(x.Digits) {
return // nothing to do
}
// find first digit < 9
for n > 0 && x.Digits[n-1] >= 9 {
n--
}
if n == 0 {
// all digits are 9s => round up to 1 and update exponent
x.Digits[0] = 1 // ok since len(x.Digits) > n
x.Digits = x.Digits[:1]
x.Exp++
return
}
x.Digits[n-1]++
x.Digits = x.Digits[:n]
// x already trimmed
}
func (x *digits) roundDown(n int) {
if n < 0 || n >= len(x.Digits) {
return // nothing to do
}
x.Digits = x.Digits[:n]
trim(x)
}
// trim cuts off any trailing zeros from x's mantissa;
// they are meaningless for the value of x.
func trim(x *digits) {
i := len(x.Digits)
for i > 0 && x.Digits[i-1] == 0 {
i--
}
x.Digits = x.Digits[:i]
if i == 0 {
x.Exp = 0
}
}
// A Converter converts a number into decimals according to the given rounding
// criteria.
type Converter interface {
Convert(d *Decimal, r RoundingContext)
}
const (
signed = true
unsigned = false
)
// Convert converts the given number to the decimal representation using the
// supplied RoundingContext.
func (d *Decimal) Convert(r RoundingContext, number interface{}) {
switch f := number.(type) {
case Converter:
d.clear()
f.Convert(d, r)
case float32:
d.ConvertFloat(r, float64(f), 32)
case float64:
d.ConvertFloat(r, f, 64)
case int:
d.ConvertInt(r, signed, uint64(f))
case int8:
d.ConvertInt(r, signed, uint64(f))
case int16:
d.ConvertInt(r, signed, uint64(f))
case int32:
d.ConvertInt(r, signed, uint64(f))
case int64:
d.ConvertInt(r, signed, uint64(f))
case uint:
d.ConvertInt(r, unsigned, uint64(f))
case uint8:
d.ConvertInt(r, unsigned, uint64(f))
case uint16:
d.ConvertInt(r, unsigned, uint64(f))
case uint32:
d.ConvertInt(r, unsigned, uint64(f))
case uint64:
d.ConvertInt(r, unsigned, f)
default:
d.NaN = true
// TODO:
// case string: if produced by strconv, allows for easy arbitrary pos.
// case reflect.Value:
// case big.Float
// case big.Int
// case big.Rat?
// catch underlyings using reflect or will this already be done by the
// message package?
}
}
// ConvertInt converts an integer to decimals.
func (d *Decimal) ConvertInt(r RoundingContext, signed bool, x uint64) {
if r.Increment > 0 {
// TODO: if uint64 is too large, fall back to float64
if signed {
d.ConvertFloat(r, float64(int64(x)), 64)
} else {
d.ConvertFloat(r, float64(x), 64)
}
return
}
d.clear()
if signed && int64(x) < 0 {
x = uint64(-int64(x))
d.Neg = true
}
d.fillIntDigits(x)
d.Exp = int32(len(d.Digits))
}
// ConvertFloat converts a floating point number to decimals.
func (d *Decimal) ConvertFloat(r RoundingContext, x float64, size int) {
d.clear()
if math.IsNaN(x) {
d.NaN = true
return
}
// Simple case: decimal notation
if r.Increment > 0 {
scale := int(r.IncrementScale)
mult := 1.0
if scale >= len(scales) {
mult = math.Pow(10, float64(scale))
} else {
mult = scales[scale]
}
// We multiply x instead of dividing inc as it gives less rounding
// issues.
x *= mult
x /= float64(r.Increment)
x = r.Mode.roundFloat(x)
x *= float64(r.Increment)
x /= mult
}
abs := x
if x < 0 {
d.Neg = true
abs = -x
}
if math.IsInf(abs, 1) {
d.Inf = true
return
}
// By default we get the exact decimal representation.
verb := byte('g')
prec := -1
// As the strconv API does not return the rounding accuracy, we can only
// round using ToNearestEven.
if r.Mode == ToNearestEven {
if n := r.RoundSignificantDigits(); n >= 0 {
prec = n
} else if n = r.RoundFractionDigits(); n >= 0 {
prec = n
verb = 'f'
}
} else {
// TODO: At this point strconv's rounding is imprecise to the point that
// it is not usable for this purpose.
// See https://github.com/golang/go/issues/21714
// If rounding is requested, we ask for a large number of digits and
// round from there to simulate rounding only once.
// Ideally we would have strconv export an AppendDigits that would take
// a rounding mode and/or return an accuracy. Something like this would
// work:
// AppendDigits(dst []byte, x float64, base, size, prec int) (digits []byte, exp, accuracy int)
hasPrec := r.RoundSignificantDigits() >= 0
hasScale := r.RoundFractionDigits() >= 0
if hasPrec || hasScale {
// prec is the number of mantissa bits plus some extra for safety.
// We need at least the number of mantissa bits as decimals to
// accurately represent the floating point without rounding, as each
// bit requires one more decimal to represent: 0.5, 0.25, 0.125, ...
prec = 60
}
}
b := strconv.AppendFloat(d.Digits[:0], abs, verb, prec, size)
i := 0
k := 0
beforeDot := 1
for i < len(b) {
if c := b[i]; '0' <= c && c <= '9' {
b[k] = c - '0'
k++
d.Exp += int32(beforeDot)
} else if c == '.' {
beforeDot = 0
d.Exp = int32(k)
} else {
break
}
i++
}
d.Digits = b[:k]
if i != len(b) {
i += len("e")
pSign := i
exp := 0
for i++; i < len(b); i++ {
exp *= 10
exp += int(b[i] - '0')
}
if b[pSign] == '-' {
exp = -exp
}
d.Exp = int32(exp) + 1
}
}
func (d *Decimal) fillIntDigits(x uint64) {
if cap(d.Digits) < maxIntDigits {
d.Digits = d.buf[:]
} else {
d.Digits = d.buf[:maxIntDigits]
}
i := 0
for ; x > 0; x /= 10 {
d.Digits[i] = byte(x % 10)
i++
}
d.Digits = d.Digits[:i]
for p := 0; p < i; p++ {
i--
d.Digits[p], d.Digits[i] = d.Digits[i], d.Digits[p]
}
}
var scales [70]float64
func init() {
x := 1.0
for i := range scales {
scales[i] = x
x *= 10
}
}
// 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 number
import (
"strconv"
"unicode/utf8"
"golang.org/x/text/language"
)
// TODO:
// - grouping of fractions
// - allow user-defined superscript notation (such as <sup>4</sup>)
// - same for non-breaking spaces, like
// A VisibleDigits computes digits, comma placement and trailing zeros as they
// will be shown to the user.
type VisibleDigits interface {
Digits(buf []byte, t language.Tag, scale int) Digits
// TODO: Do we also need to add the verb or pass a format.State?
}
// Formatting proceeds along the following lines:
// 0) Compose rounding information from format and context.
// 1) Convert a number into a Decimal.
// 2) Sanitize Decimal by adding trailing zeros, removing leading digits, and
// (non-increment) rounding. The Decimal that results from this is suitable
// for determining the plural form.
// 3) Render the Decimal in the localized form.
// Formatter contains all the information needed to render a number.
type Formatter struct {
Pattern
Info
}
func (f *Formatter) init(t language.Tag, index []uint8) {
f.Info = InfoFromTag(t)
f.Pattern = formats[index[tagToID(t)]]
}
// InitPattern initializes a Formatter for the given Pattern.
func (f *Formatter) InitPattern(t language.Tag, pat *Pattern) {
f.Info = InfoFromTag(t)
f.Pattern = *pat
}
// InitDecimal initializes a Formatter using the default Pattern for the given
// language.
func (f *Formatter) InitDecimal(t language.Tag) {
f.init(t, tagToDecimal)
}
// InitScientific initializes a Formatter using the default Pattern for the
// given language.
func (f *Formatter) InitScientific(t language.Tag) {
f.init(t, tagToScientific)
f.Pattern.MinFractionDigits = 0
f.Pattern.MaxFractionDigits = -1
}
// InitEngineering initializes a Formatter using the default Pattern for the
// given language.
func (f *Formatter) InitEngineering(t language.Tag) {
f.init(t, tagToScientific)
f.Pattern.MinFractionDigits = 0
f.Pattern.MaxFractionDigits = -1
f.Pattern.MaxIntegerDigits = 3
f.Pattern.MinIntegerDigits = 1
}
// InitPercent initializes a Formatter using the default Pattern for the given
// language.
func (f *Formatter) InitPercent(t language.Tag) {
f.init(t, tagToPercent)
}
// InitPerMille initializes a Formatter using the default Pattern for the given
// language.
func (f *Formatter) InitPerMille(t language.Tag) {
f.init(t, tagToPercent)
f.Pattern.DigitShift = 3
}
func (f *Formatter) Append(dst []byte, x interface{}) []byte {
var d Decimal
r := f.RoundingContext
d.Convert(r, x)
return f.Render(dst, FormatDigits(&d, r))
}
func FormatDigits(d *Decimal, r RoundingContext) Digits {
if r.isScientific() {
return scientificVisibleDigits(r, d)
}
return decimalVisibleDigits(r, d)
}
func (f *Formatter) Format(dst []byte, d *Decimal) []byte {
return f.Render(dst, FormatDigits(d, f.RoundingContext))
}
func (f *Formatter) Render(dst []byte, d Digits) []byte {
var result []byte
var postPrefix, preSuffix int
if d.IsScientific {
result, postPrefix, preSuffix = appendScientific(dst, f, &d)
} else {
result, postPrefix, preSuffix = appendDecimal(dst, f, &d)
}
if f.PadRune == 0 {
return result
}
width := int(f.FormatWidth)
if count := utf8.RuneCount(result); count < width {
insertPos := 0
switch f.Flags & PadMask {
case PadAfterPrefix:
insertPos = postPrefix
case PadBeforeSuffix:
insertPos = preSuffix
case PadAfterSuffix:
insertPos = len(result)
}
num := width - count
pad := [utf8.UTFMax]byte{' '}
sz := 1
if r := f.PadRune; r != 0 {
sz = utf8.EncodeRune(pad[:], r)
}
extra := sz * num
if n := len(result) + extra; n < cap(result) {
result = result[:n]
copy(result[insertPos+extra:], result[insertPos:])
} else {
buf := make([]byte, n)
copy(buf, result[:insertPos])
copy(buf[insertPos+extra:], result[insertPos:])
result = buf
}
for ; num > 0; num-- {
insertPos += copy(result[insertPos:], pad[:sz])
}
}
return result
}
// decimalVisibleDigits converts d according to the RoundingContext. Note that
// the exponent may change as a result of this operation.
func decimalVisibleDigits(r RoundingContext, d *Decimal) Digits {
if d.NaN || d.Inf {
return Digits{digits: digits{Neg: d.Neg, NaN: d.NaN, Inf: d.Inf}}
}
n := Digits{digits: d.normalize().digits}
exp := n.Exp
exp += int32(r.DigitShift)
// Cap integer digits. Remove *most-significant* digits.
if r.MaxIntegerDigits > 0 {
if p := int(exp) - int(r.MaxIntegerDigits); p > 0 {
if p > len(n.Digits) {
p = len(n.Digits)
}
if n.Digits = n.Digits[p:]; len(n.Digits) == 0 {
exp = 0
} else {
exp -= int32(p)
}
// Strip leading zeros.
for len(n.Digits) > 0 && n.Digits[0] == 0 {
n.Digits = n.Digits[1:]
exp--
}
}
}
// Rounding if not already done by Convert.
p := len(n.Digits)
if maxSig := int(r.MaxSignificantDigits); maxSig > 0 {
p = maxSig
}
if maxFrac := int(r.MaxFractionDigits); maxFrac >= 0 {
if cap := int(exp) + maxFrac; cap < p {
p = int(exp) + maxFrac
}
if p < 0 {
p = 0
}
}
n.round(r.Mode, p)
// set End (trailing zeros)
n.End = int32(len(n.Digits))
if n.End == 0 {
exp = 0
if r.MinFractionDigits > 0 {
n.End = int32(r.MinFractionDigits)
}
if p := int32(r.MinSignificantDigits) - 1; p > n.End {
n.End = p
}
} else {
if end := exp + int32(r.MinFractionDigits); end > n.End {
n.End = end
}
if n.End < int32(r.MinSignificantDigits) {
n.End = int32(r.MinSignificantDigits)
}
}
n.Exp = exp
return n
}
// appendDecimal appends a formatted number to dst. It returns two possible
// insertion points for padding.
func appendDecimal(dst []byte, f *Formatter, n *Digits) (b []byte, postPre, preSuf int) {
if dst, ok := f.renderSpecial(dst, n); ok {
return dst, 0, len(dst)
}
digits := n.Digits
exp := n.Exp
// Split in integer and fraction part.
var intDigits, fracDigits []byte
numInt := 0
numFrac := int(n.End - n.Exp)
if exp > 0 {
numInt = int(exp)
if int(exp) >= len(digits) { // ddddd | ddddd00
intDigits = digits
} else { // ddd.dd
intDigits = digits[:exp]
fracDigits = digits[exp:]
}
} else {
fracDigits = digits
}
neg := n.Neg
affix, suffix := f.getAffixes(neg)
dst = appendAffix(dst, f, affix, neg)
savedLen := len(dst)
minInt := int(f.MinIntegerDigits)
if minInt == 0 && f.MinSignificantDigits > 0 {
minInt = 1
}
// add leading zeros
for i := minInt; i > numInt; i-- {
dst = f.AppendDigit(dst, 0)
if f.needsSep(i) {
dst = append(dst, f.Symbol(SymGroup)...)
}
}
i := 0
for ; i < len(intDigits); i++ {
dst = f.AppendDigit(dst, intDigits[i])
if f.needsSep(numInt - i) {
dst = append(dst, f.Symbol(SymGroup)...)
}
}
for ; i < numInt; i++ {
dst = f.AppendDigit(dst, 0)
if f.needsSep(numInt - i) {
dst = append(dst, f.Symbol(SymGroup)...)
}
}
if numFrac > 0 || f.Flags&AlwaysDecimalSeparator != 0 {
dst = append(dst, f.Symbol(SymDecimal)...)
}
// Add trailing zeros
i = 0
for n := -int(n.Exp); i < n; i++ {
dst = f.AppendDigit(dst, 0)
}
for _, d := range fracDigits {
i++
dst = f.AppendDigit(dst, d)
}
for ; i < numFrac; i++ {
dst = f.AppendDigit(dst, 0)
}
return appendAffix(dst, f, suffix, neg), savedLen, len(dst)
}
func scientificVisibleDigits(r RoundingContext, d *Decimal) Digits {
if d.NaN || d.Inf {
return Digits{digits: digits{Neg: d.Neg, NaN: d.NaN, Inf: d.Inf}}
}
n := Digits{digits: d.normalize().digits, IsScientific: true}
// Normalize to have at least one digit. This simplifies engineering
// notation.
if len(n.Digits) == 0 {
n.Digits = append(n.Digits, 0)
n.Exp = 1
}
// Significant digits are transformed by the parser for scientific notation
// and do not need to be handled here.
maxInt, numInt := int(r.MaxIntegerDigits), int(r.MinIntegerDigits)
if numInt == 0 {
numInt = 1
}
// If a maximum number of integers is specified, the minimum must be 1
// and the exponent is grouped by this number (e.g. for engineering)
if maxInt > numInt {
// Correct the exponent to reflect a single integer digit.
numInt = 1
// engineering
// 0.01234 ([12345]e-1) -> 1.2345e-2 12.345e-3
// 12345 ([12345]e+5) -> 1.2345e4 12.345e3
d := int(n.Exp-1) % maxInt
if d < 0 {
d += maxInt
}
numInt += d
}
p := len(n.Digits)
if maxSig := int(r.MaxSignificantDigits); maxSig > 0 {
p = maxSig
}
if maxFrac := int(r.MaxFractionDigits); maxFrac >= 0 && numInt+maxFrac < p {
p = numInt + maxFrac
}
n.round(r.Mode, p)
n.Comma = uint8(numInt)
n.End = int32(len(n.Digits))
if minSig := int32(r.MinFractionDigits) + int32(numInt); n.End < minSig {
n.End = minSig
}
return n
}
// appendScientific appends a formatted number to dst. It returns two possible
// insertion points for padding.
func appendScientific(dst []byte, f *Formatter, n *Digits) (b []byte, postPre, preSuf int) {
if dst, ok := f.renderSpecial(dst, n); ok {
return dst, 0, 0
}
digits := n.Digits
numInt := int(n.Comma)
numFrac := int(n.End) - int(n.Comma)
var intDigits, fracDigits []byte
if numInt <= len(digits) {
intDigits = digits[:numInt]
fracDigits = digits[numInt:]
} else {
intDigits = digits
}
neg := n.Neg
affix, suffix := f.getAffixes(neg)
dst = appendAffix(dst, f, affix, neg)
savedLen := len(dst)
i := 0
for ; i < len(intDigits); i++ {
dst = f.AppendDigit(dst, intDigits[i])
if f.needsSep(numInt - i) {
dst = append(dst, f.Symbol(SymGroup)...)
}
}
for ; i < numInt; i++ {
dst = f.AppendDigit(dst, 0)
if f.needsSep(numInt - i) {
dst = append(dst, f.Symbol(SymGroup)...)
}
}
if numFrac > 0 || f.Flags&AlwaysDecimalSeparator != 0 {
dst = append(dst, f.Symbol(SymDecimal)...)
}
i = 0
for ; i < len(fracDigits); i++ {
dst = f.AppendDigit(dst, fracDigits[i])
}
for ; i < numFrac; i++ {
dst = f.AppendDigit(dst, 0)
}
// exp
buf := [12]byte{}
// TODO: use exponential if superscripting is not available (no Latin
// numbers or no tags) and use exponential in all other cases.
exp := n.Exp - int32(n.Comma)
exponential := f.Symbol(SymExponential)
if exponential == "E" {
dst = append(dst, f.Symbol(SymSuperscriptingExponent)...)
dst = f.AppendDigit(dst, 1)
dst = f.AppendDigit(dst, 0)
switch {
case exp < 0:
dst = append(dst, superMinus...)
exp = -exp
case f.Flags&AlwaysExpSign != 0:
dst = append(dst, superPlus...)
}
b = strconv.AppendUint(buf[:0], uint64(exp), 10)
for i := len(b); i < int(f.MinExponentDigits); i++ {
dst = append(dst, superDigits[0]...)
}
for _, c := range b {
dst = append(dst, superDigits[c-'0']...)
}
} else {
dst = append(dst, exponential...)
switch {
case exp < 0:
dst = append(dst, f.Symbol(SymMinusSign)...)
exp = -exp
case f.Flags&AlwaysExpSign != 0:
dst = append(dst, f.Symbol(SymPlusSign)...)
}
b = strconv.AppendUint(buf[:0], uint64(exp), 10)
for i := len(b); i < int(f.MinExponentDigits); i++ {
dst = f.AppendDigit(dst, 0)
}
for _, c := range b {
dst = f.AppendDigit(dst, c-'0')
}
}
return appendAffix(dst, f, suffix, neg), savedLen, len(dst)
}
const (
superMinus = "\u207B" // SUPERSCRIPT HYPHEN-MINUS
superPlus = "\u207A" // SUPERSCRIPT PLUS SIGN
)
var (
// Note: the digits are not sequential!!!
superDigits = []string{
"\u2070", // SUPERSCRIPT DIGIT ZERO
"\u00B9", // SUPERSCRIPT DIGIT ONE
"\u00B2", // SUPERSCRIPT DIGIT TWO
"\u00B3", // SUPERSCRIPT DIGIT THREE
"\u2074", // SUPERSCRIPT DIGIT FOUR
"\u2075", // SUPERSCRIPT DIGIT FIVE
"\u2076", // SUPERSCRIPT DIGIT SIX
"\u2077", // SUPERSCRIPT DIGIT SEVEN
"\u2078", // SUPERSCRIPT DIGIT EIGHT
"\u2079", // SUPERSCRIPT DIGIT NINE
}
)
func (f *Formatter) getAffixes(neg bool) (affix, suffix string) {
str := f.Affix
if str != "" {
if f.NegOffset > 0 {
if neg {
str = str[f.NegOffset:]
} else {
str = str[:f.NegOffset]
}
}
sufStart := 1 + str[0]
affix = str[1:sufStart]
suffix = str[sufStart+1:]
}
// TODO: introduce a NeedNeg sign to indicate if the left pattern already
// has a sign marked?
if f.NegOffset == 0 && (neg || f.Flags&AlwaysSign != 0) {
affix = "-" + affix
}
return affix, suffix
}
func (f *Formatter) renderSpecial(dst []byte, d *Digits) (b []byte, ok bool) {
if d.NaN {
return fmtNaN(dst, f), true
}
if d.Inf {
return fmtInfinite(dst, f, d), true
}
return dst, false
}
func fmtNaN(dst []byte, f *Formatter) []byte {
return append(dst, f.Symbol(SymNan)...)
}
func fmtInfinite(dst []byte, f *Formatter, d *Digits) []byte {
affix, suffix := f.getAffixes(d.Neg)
dst = appendAffix(dst, f, affix, d.Neg)
dst = append(dst, f.Symbol(SymInfinity)...)
dst = appendAffix(dst, f, suffix, d.Neg)
return dst
}
func appendAffix(dst []byte, f *Formatter, affix string, neg bool) []byte {
quoting := false
escaping := false
for _, r := range affix {
switch {
case escaping:
// escaping occurs both inside and outside of quotes
dst = append(dst, string(r)...)
escaping = false
case r == '\\':
escaping = true
case r == '\'':
quoting = !quoting
case quoting:
dst = append(dst, string(r)...)
case r == '%':
if f.DigitShift == 3 {
dst = append(dst, f.Symbol(SymPerMille)...)
} else {
dst = append(dst, f.Symbol(SymPercentSign)...)
}
case r == '-' || r == '+':
if neg {
dst = append(dst, f.Symbol(SymMinusSign)...)
} else if f.Flags&ElideSign == 0 {
dst = append(dst, f.Symbol(SymPlusSign)...)
} else {
dst = append(dst, ' ')
}
default:
dst = append(dst, string(r)...)
}
}
return dst
}
// 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.
//go:generate go run gen.go gen_common.go
// Package number contains tools and data for formatting numbers.
package number
import (
"unicode/utf8"
"golang.org/x/text/internal/language/compact"
"golang.org/x/text/language"
)
// Info holds number formatting configuration data.
type Info struct {
system systemData // numbering system information
symIndex symOffset // index to symbols
}
// InfoFromLangID returns a Info for the given compact language identifier and
// numbering system identifier. If system is the empty string, the default
// numbering system will be taken for that language.
func InfoFromLangID(compactIndex compact.ID, numberSystem string) Info {
p := langToDefaults[compactIndex]
// Lookup the entry for the language.
pSymIndex := symOffset(0) // Default: Latin, default symbols
system, ok := systemMap[numberSystem]
if !ok {
// Take the value for the default numbering system. This is by far the
// most common case as an alternative numbering system is hardly used.
if p&hasNonLatnMask == 0 { // Latn digits.
pSymIndex = p
} else { // Non-Latn or multiple numbering systems.
// Take the first entry from the alternatives list.
data := langToAlt[p&^hasNonLatnMask]
pSymIndex = data.symIndex
system = data.system
}
} else {
langIndex := compactIndex
ns := system
outerLoop:
for ; ; p = langToDefaults[langIndex] {
if p&hasNonLatnMask == 0 {
if ns == 0 {
// The index directly points to the symbol data.
pSymIndex = p
break
}
// Move to the parent and retry.
langIndex = langIndex.Parent()
} else {
// The index points to a list of symbol data indexes.
for _, e := range langToAlt[p&^hasNonLatnMask:] {
if e.compactTag != langIndex {
if langIndex == 0 {
// The CLDR root defines full symbol information for
// all numbering systems (even though mostly by
// means of aliases). Fall back to the default entry
// for Latn if there is no data for the numbering
// system of this language.
if ns == 0 {
break
}
// Fall back to Latin and start from the original
// language. See
// https://unicode.org/reports/tr35/#Locale_Inheritance.
ns = numLatn
langIndex = compactIndex
continue outerLoop
}
// Fall back to parent.
langIndex = langIndex.Parent()
} else if e.system == ns {
pSymIndex = e.symIndex
break outerLoop
}
}
}
}
}
if int(system) >= len(numSysData) { // algorithmic
// Will generate ASCII digits in case the user inadvertently calls
// WriteDigit or Digit on it.
d := numSysData[0]
d.id = system
return Info{
system: d,
symIndex: pSymIndex,
}
}
return Info{
system: numSysData[system],
symIndex: pSymIndex,
}
}
// InfoFromTag returns a Info for the given language tag.
func InfoFromTag(t language.Tag) Info {
return InfoFromLangID(tagToID(t), t.TypeForKey("nu"))
}
// IsDecimal reports if the numbering system can convert decimal to native
// symbols one-to-one.
func (n Info) IsDecimal() bool {
return int(n.system.id) < len(numSysData)
}
// WriteDigit writes the UTF-8 sequence for n corresponding to the given ASCII
// digit to dst and reports the number of bytes written. dst must be large
// enough to hold the rune (can be up to utf8.UTFMax bytes).
func (n Info) WriteDigit(dst []byte, asciiDigit rune) int {
copy(dst, n.system.zero[:n.system.digitSize])
dst[n.system.digitSize-1] += byte(asciiDigit - '0')
return int(n.system.digitSize)
}
// AppendDigit appends the UTF-8 sequence for n corresponding to the given digit
// to dst and reports the number of bytes written. dst must be large enough to
// hold the rune (can be up to utf8.UTFMax bytes).
func (n Info) AppendDigit(dst []byte, digit byte) []byte {
dst = append(dst, n.system.zero[:n.system.digitSize]...)
dst[len(dst)-1] += digit
return dst
}
// Digit returns the digit for the numbering system for the corresponding ASCII
// value. For example, ni.Digit('3') could return '三'. Note that the argument
// is the rune constant '3', which equals 51, not the integer constant 3.
func (n Info) Digit(asciiDigit rune) rune {
var x [utf8.UTFMax]byte
n.WriteDigit(x[:], asciiDigit)
r, _ := utf8.DecodeRune(x[:])
return r
}
// Symbol returns the string for the given symbol type.
func (n Info) Symbol(t SymbolType) string {
return symData.Elem(int(symIndex[n.symIndex][t]))
}
func formatForLang(t language.Tag, index []byte) *Pattern {
return &formats[index[tagToID(t)]]
}
func tagToID(t language.Tag) compact.ID {
id, _ := compact.RegionalID(compact.Tag(t))
return id
}
// 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.
package number
import (
"errors"
"unicode/utf8"
)
// This file contains a parser for the CLDR number patterns as described in
// https://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns.
//
// The following BNF is derived from this standard.
//
// pattern := subpattern (';' subpattern)?
// subpattern := affix? number exponent? affix?
// number := decimal | sigDigits
// decimal := '#'* '0'* ('.' fraction)? | '#' | '0'
// fraction := '0'* '#'*
// sigDigits := '#'* '@' '@'* '#'*
// exponent := 'E' '+'? '0'* '0'
// padSpec := '*' \L
//
// Notes:
// - An affix pattern may contain any runes, but runes with special meaning
// should be escaped.
// - Sequences of digits, '#', and '@' in decimal and sigDigits may have
// interstitial commas.
// TODO: replace special characters in affixes (-, +, ¤) with control codes.
// Pattern holds information for formatting numbers. It is designed to hold
// information from CLDR number patterns.
//
// This pattern is precompiled for all patterns for all languages. Even though
// the number of patterns is not very large, we want to keep this small.
//
// This type is only intended for internal use.
type Pattern struct {
RoundingContext
Affix string // includes prefix and suffix. First byte is prefix length.
Offset uint16 // Offset into Affix for prefix and suffix
NegOffset uint16 // Offset into Affix for negative prefix and suffix or 0.
PadRune rune
FormatWidth uint16
GroupingSize [2]uint8
Flags PatternFlag
}
// A RoundingContext indicates how a number should be converted to digits.
// It contains all information needed to determine the "visible digits" as
// required by the pluralization rules.
type RoundingContext struct {
// TODO: unify these two fields so that there is a more unambiguous meaning
// of how precision is handled.
MaxSignificantDigits int16 // -1 is unlimited
MaxFractionDigits int16 // -1 is unlimited
Increment uint32
IncrementScale uint8 // May differ from printed scale.
Mode RoundingMode
DigitShift uint8 // Number of decimals to shift. Used for % and ‰.
// Number of digits.
MinIntegerDigits uint8
MaxIntegerDigits uint8
MinFractionDigits uint8
MinSignificantDigits uint8
MinExponentDigits uint8
}
// RoundSignificantDigits returns the number of significant digits an
// implementation of Convert may round to or n < 0 if there is no maximum or
// a maximum is not recommended.
func (r *RoundingContext) RoundSignificantDigits() (n int) {
if r.MaxFractionDigits == 0 && r.MaxSignificantDigits > 0 {
return int(r.MaxSignificantDigits)
} else if r.isScientific() && r.MaxIntegerDigits == 1 {
if r.MaxSignificantDigits == 0 ||
int(r.MaxFractionDigits+1) == int(r.MaxSignificantDigits) {
// Note: don't add DigitShift: it is only used for decimals.
return int(r.MaxFractionDigits) + 1
}
}
return -1
}
// RoundFractionDigits returns the number of fraction digits an implementation
// of Convert may round to or n < 0 if there is no maximum or a maximum is not
// recommended.
func (r *RoundingContext) RoundFractionDigits() (n int) {
if r.MinExponentDigits == 0 &&
r.MaxSignificantDigits == 0 &&
r.MaxFractionDigits >= 0 {
return int(r.MaxFractionDigits) + int(r.DigitShift)
}
return -1
}
// SetScale fixes the RoundingContext to a fixed number of fraction digits.
func (r *RoundingContext) SetScale(scale int) {
r.MinFractionDigits = uint8(scale)
r.MaxFractionDigits = int16(scale)
}
func (r *RoundingContext) SetPrecision(prec int) {
r.MaxSignificantDigits = int16(prec)
}
func (r *RoundingContext) isScientific() bool {
return r.MinExponentDigits > 0
}
func (f *Pattern) needsSep(pos int) bool {
p := pos - 1
size := int(f.GroupingSize[0])
if size == 0 || p == 0 {
return false
}
if p == size {
return true
}
if p -= size; p < 0 {
return false
}
// TODO: make second groupingsize the same as first if 0 so that we can
// avoid this check.
if x := int(f.GroupingSize[1]); x != 0 {
size = x
}
return p%size == 0
}
// A PatternFlag is a bit mask for the flag field of a Pattern.
type PatternFlag uint8
const (
AlwaysSign PatternFlag = 1 << iota
ElideSign // Use space instead of plus sign. AlwaysSign must be true.
AlwaysExpSign
AlwaysDecimalSeparator
ParenthesisForNegative // Common pattern. Saves space.
PadAfterNumber
PadAfterAffix
PadBeforePrefix = 0 // Default
PadAfterPrefix = PadAfterAffix
PadBeforeSuffix = PadAfterNumber
PadAfterSuffix = PadAfterNumber | PadAfterAffix
PadMask = PadAfterNumber | PadAfterAffix
)
type parser struct {
*Pattern
leadingSharps int
pos int
err error
doNotTerminate bool
groupingCount uint
hasGroup bool
buf []byte
}
func (p *parser) setError(err error) {
if p.err == nil {
p.err = err
}
}
func (p *parser) updateGrouping() {
if p.hasGroup &&
0 < p.groupingCount && p.groupingCount < 255 {
p.GroupingSize[1] = p.GroupingSize[0]
p.GroupingSize[0] = uint8(p.groupingCount)
}
p.groupingCount = 0
p.hasGroup = true
}
var (
// TODO: more sensible and localizeable error messages.
errMultiplePadSpecifiers = errors.New("format: pattern has multiple pad specifiers")
errInvalidPadSpecifier = errors.New("format: invalid pad specifier")
errInvalidQuote = errors.New("format: invalid quote")
errAffixTooLarge = errors.New("format: prefix or suffix exceeds maximum UTF-8 length of 256 bytes")
errDuplicatePercentSign = errors.New("format: duplicate percent sign")
errDuplicatePermilleSign = errors.New("format: duplicate permille sign")
errUnexpectedEnd = errors.New("format: unexpected end of pattern")
)
// ParsePattern extracts formatting information from a CLDR number pattern.
//
// See https://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns.
func ParsePattern(s string) (f *Pattern, err error) {
p := parser{Pattern: &Pattern{}}
s = p.parseSubPattern(s)
if s != "" {
// Parse negative sub pattern.
if s[0] != ';' {
p.setError(errors.New("format: error parsing first sub pattern"))
return nil, p.err
}
neg := parser{Pattern: &Pattern{}} // just for extracting the affixes.
s = neg.parseSubPattern(s[len(";"):])
p.NegOffset = uint16(len(p.buf))
p.buf = append(p.buf, neg.buf...)
}
if s != "" {
p.setError(errors.New("format: spurious characters at end of pattern"))
}
if p.err != nil {
return nil, p.err
}
if affix := string(p.buf); affix == "\x00\x00" || affix == "\x00\x00\x00\x00" {
// No prefix or suffixes.
p.NegOffset = 0
} else {
p.Affix = affix
}
if p.Increment == 0 {
p.IncrementScale = 0
}
return p.Pattern, nil
}
func (p *parser) parseSubPattern(s string) string {
s = p.parsePad(s, PadBeforePrefix)
s = p.parseAffix(s)
s = p.parsePad(s, PadAfterPrefix)
s = p.parse(p.number, s)
p.updateGrouping()
s = p.parsePad(s, PadBeforeSuffix)
s = p.parseAffix(s)
s = p.parsePad(s, PadAfterSuffix)
return s
}
func (p *parser) parsePad(s string, f PatternFlag) (tail string) {
if len(s) >= 2 && s[0] == '*' {
r, sz := utf8.DecodeRuneInString(s[1:])
if p.PadRune != 0 {
p.err = errMultiplePadSpecifiers
} else {
p.Flags |= f
p.PadRune = r
}
return s[1+sz:]
}
return s
}
func (p *parser) parseAffix(s string) string {
x := len(p.buf)
p.buf = append(p.buf, 0) // placeholder for affix length
s = p.parse(p.affix, s)
n := len(p.buf) - x - 1
if n > 0xFF {
p.setError(errAffixTooLarge)
}
p.buf[x] = uint8(n)
return s
}
// state implements a state transition. It returns the new state. A state
// function may set an error on the parser or may simply return on an incorrect
// token and let the next phase fail.
type state func(r rune) state
// parse repeatedly applies a state function on the given string until a
// termination condition is reached.
func (p *parser) parse(fn state, s string) (tail string) {
for i, r := range s {
p.doNotTerminate = false
if fn = fn(r); fn == nil || p.err != nil {
return s[i:]
}
p.FormatWidth++
}
if p.doNotTerminate {
p.setError(errUnexpectedEnd)
}
return ""
}
func (p *parser) affix(r rune) state {
switch r {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'#', '@', '.', '*', ',', ';':
return nil
case '\'':
p.FormatWidth--
return p.escapeFirst
case '%':
if p.DigitShift != 0 {
p.setError(errDuplicatePercentSign)
}
p.DigitShift = 2
case '\u2030': // ‰ Per mille
if p.DigitShift != 0 {
p.setError(errDuplicatePermilleSign)
}
p.DigitShift = 3
// TODO: handle currency somehow: ¤, ¤¤, ¤¤¤, ¤¤¤¤
}
p.buf = append(p.buf, string(r)...)
return p.affix
}
func (p *parser) escapeFirst(r rune) state {
switch r {
case '\'':
p.buf = append(p.buf, "\\'"...)
return p.affix
default:
p.buf = append(p.buf, '\'')
p.buf = append(p.buf, string(r)...)
}
return p.escape
}
func (p *parser) escape(r rune) state {
switch r {
case '\'':
p.FormatWidth--
p.buf = append(p.buf, '\'')
return p.affix
default:
p.buf = append(p.buf, string(r)...)
}
return p.escape
}
// number parses a number. The BNF says the integer part should always have
// a '0', but that does not appear to be the case according to the rest of the
// documentation. We will allow having only '#' numbers.
func (p *parser) number(r rune) state {
switch r {
case '#':
p.groupingCount++
p.leadingSharps++
case '@':
p.groupingCount++
p.leadingSharps = 0
p.MaxFractionDigits = -1
return p.sigDigits(r)
case ',':
if p.leadingSharps == 0 { // no leading commas
return nil
}
p.updateGrouping()
case 'E':
p.MaxIntegerDigits = uint8(p.leadingSharps)
return p.exponent
case '.': // allow ".##" etc.
p.updateGrouping()
return p.fraction
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return p.integer(r)
default:
return nil
}
return p.number
}
func (p *parser) integer(r rune) state {
if !('0' <= r && r <= '9') {
var next state
switch r {
case 'E':
if p.leadingSharps > 0 {
p.MaxIntegerDigits = uint8(p.leadingSharps) + p.MinIntegerDigits
}
next = p.exponent
case '.':
next = p.fraction
case ',':
next = p.integer
}
p.updateGrouping()
return next
}
p.Increment = p.Increment*10 + uint32(r-'0')
p.groupingCount++
p.MinIntegerDigits++
return p.integer
}
func (p *parser) sigDigits(r rune) state {
switch r {
case '@':
p.groupingCount++
p.MaxSignificantDigits++
p.MinSignificantDigits++
case '#':
return p.sigDigitsFinal(r)
case 'E':
p.updateGrouping()
return p.normalizeSigDigitsWithExponent()
default:
p.updateGrouping()
return nil
}
return p.sigDigits
}
func (p *parser) sigDigitsFinal(r rune) state {
switch r {
case '#':
p.groupingCount++
p.MaxSignificantDigits++
case 'E':
p.updateGrouping()
return p.normalizeSigDigitsWithExponent()
default:
p.updateGrouping()
return nil
}
return p.sigDigitsFinal
}
func (p *parser) normalizeSigDigitsWithExponent() state {
p.MinIntegerDigits, p.MaxIntegerDigits = 1, 1
p.MinFractionDigits = p.MinSignificantDigits - 1
p.MaxFractionDigits = p.MaxSignificantDigits - 1
p.MinSignificantDigits, p.MaxSignificantDigits = 0, 0
return p.exponent
}
func (p *parser) fraction(r rune) state {
switch r {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
p.Increment = p.Increment*10 + uint32(r-'0')
p.IncrementScale++
p.MinFractionDigits++
p.MaxFractionDigits++
case '#':
p.MaxFractionDigits++
case 'E':
if p.leadingSharps > 0 {
p.MaxIntegerDigits = uint8(p.leadingSharps) + p.MinIntegerDigits
}
return p.exponent
default:
return nil
}
return p.fraction
}
func (p *parser) exponent(r rune) state {
switch r {
case '+':
// Set mode and check it wasn't already set.
if p.Flags&AlwaysExpSign != 0 || p.MinExponentDigits > 0 {
break
}
p.Flags |= AlwaysExpSign
p.doNotTerminate = true
return p.exponent
case '0':
p.MinExponentDigits++
return p.exponent
}
// termination condition
if p.MinExponentDigits == 0 {
p.setError(errors.New("format: need at least one digit"))
}
return nil
}
// Code generated by "stringer -type RoundingMode"; DO NOT EDIT.
package number
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[ToNearestEven-0]
_ = x[ToNearestZero-1]
_ = x[ToNearestAway-2]
_ = x[ToPositiveInf-3]
_ = x[ToNegativeInf-4]
_ = x[ToZero-5]
_ = x[AwayFromZero-6]
_ = x[numModes-7]
}
const _RoundingMode_name = "ToNearestEvenToNearestZeroToNearestAwayToPositiveInfToNegativeInfToZeroAwayFromZeronumModes"
var _RoundingMode_index = [...]uint8{0, 13, 26, 39, 52, 65, 71, 83, 91}
func (i RoundingMode) String() string {
if i >= RoundingMode(len(_RoundingMode_index)-1) {
return "RoundingMode(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _RoundingMode_name[_RoundingMode_index[i]:_RoundingMode_index[i+1]]
}
// 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.
// Package stringset provides a way to represent a collection of strings
// compactly.
package stringset
import "sort"
// A Set holds a collection of strings that can be looked up by an index number.
type Set struct {
// These fields are exported to allow for code generation.
Data string
Index []uint16
}
// Elem returns the string with index i. It panics if i is out of range.
func (s *Set) Elem(i int) string {
return s.Data[s.Index[i]:s.Index[i+1]]
}
// Len returns the number of strings in the set.
func (s *Set) Len() int {
return len(s.Index) - 1
}
// Search returns the index of the given string or -1 if it is not in the set.
// The Set must have been created with strings in sorted order.
func Search(s *Set, str string) int {
// TODO: optimize this if it gets used a lot.
n := len(s.Index) - 1
p := sort.Search(n, func(i int) bool {
return s.Elem(i) >= str
})
if p == n || str != s.Elem(p) {
return -1
}
return p
}
// A Builder constructs Sets.
type Builder struct {
set Set
index map[string]int
}
// NewBuilder returns a new and initialized Builder.
func NewBuilder() *Builder {
return &Builder{
set: Set{
Index: []uint16{0},
},
index: map[string]int{},
}
}
// Set creates the set created so far.
func (b *Builder) Set() Set {
return b.set
}
// Index returns the index for the given string, which must have been added
// before.
func (b *Builder) Index(s string) int {
return b.index[s]
}
// Add adds a string to the index. Strings that are added by a single Add will
// be stored together, unless they match an existing string.
func (b *Builder) Add(ss ...string) {
// First check if the string already exists.
for _, s := range ss {
if _, ok := b.index[s]; ok {
continue
}
b.index[s] = len(b.set.Index) - 1
b.set.Data += s
x := len(b.set.Data)
if x > 0xFFFF {
panic("Index too > 0xFFFF")
}
b.set.Index = append(b.set.Index, uint16(x))
}
}
// 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.
// Package tag contains functionality handling tags and related data.
package tag // import "golang.org/x/text/internal/tag"
import "sort"
// An Index converts tags to a compact numeric value.
//
// All elements are of size 4. Tags may be up to 4 bytes long. Excess bytes can
// be used to store additional information about the tag.
type Index string
// Elem returns the element data at the given index.
func (s Index) Elem(x int) string {
return string(s[x*4 : x*4+4])
}
// Index reports the index of the given key or -1 if it could not be found.
// Only the first len(key) bytes from the start of the 4-byte entries will be
// considered for the search and the first match in Index will be returned.
func (s Index) Index(key []byte) int {
n := len(key)
// search the index of the first entry with an equal or higher value than
// key in s.
index := sort.Search(len(s)/4, func(i int) bool {
return cmp(s[i*4:i*4+n], key) != -1
})
i := index * 4
if cmp(s[i:i+len(key)], key) != 0 {
return -1
}
return index
}
// Next finds the next occurrence of key after index x, which must have been
// obtained from a call to Index using the same key. It returns x+1 or -1.
func (s Index) Next(key []byte, x int) int {
if x++; x*4 < len(s) && cmp(s[x*4:x*4+len(key)], key) == 0 {
return x
}
return -1
}
// cmp returns an integer comparing a and b lexicographically.
func cmp(a Index, b []byte) int {
n := len(a)
if len(b) < n {
n = len(b)
}
for i, c := range b[:n] {
switch {
case a[i] > c:
return 1
case a[i] < c:
return -1
}
}
switch {
case len(a) < len(b):
return -1
case len(a) > len(b):
return 1
}
return 0
}
// Compare returns an integer comparing a and b lexicographically.
func Compare(a string, b []byte) int {
return cmp(Index(a), b)
}
// FixCase reformats b to the same pattern of cases as form.
// If returns false if string b is malformed.
func FixCase(form string, b []byte) bool {
if len(form) != len(b) {
return false
}
for i, c := range b {
if form[i] <= 'Z' {
if c >= 'a' {
c -= 'z' - 'Z'
}
if c < 'A' || 'Z' < c {
return false
}
} else {
if c <= 'Z' {
c += 'z' - 'Z'
}
if c < 'a' || 'z' < c {
return false
}
}
b[i] = c
}
return true
}
// 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 language
import (
"fmt"
"sort"
"golang.org/x/text/internal/language"
)
// The Coverage interface is used to define the level of coverage of an
// internationalization service. Note that not all types are supported by all
// services. As lists may be generated on the fly, it is recommended that users
// of a Coverage cache the results.
type Coverage interface {
// Tags returns the list of supported tags.
Tags() []Tag
// BaseLanguages returns the list of supported base languages.
BaseLanguages() []Base
// Scripts returns the list of supported scripts.
Scripts() []Script
// Regions returns the list of supported regions.
Regions() []Region
}
var (
// Supported defines a Coverage that lists all supported subtags. Tags
// always returns nil.
Supported Coverage = allSubtags{}
)
// TODO:
// - Support Variants, numbering systems.
// - CLDR coverage levels.
// - Set of common tags defined in this package.
type allSubtags struct{}
// Regions returns the list of supported regions. As all regions are in a
// consecutive range, it simply returns a slice of numbers in increasing order.
// The "undefined" region is not returned.
func (s allSubtags) Regions() []Region {
reg := make([]Region, language.NumRegions)
for i := range reg {
reg[i] = Region{language.Region(i + 1)}
}
return reg
}
// Scripts returns the list of supported scripts. As all scripts are in a
// consecutive range, it simply returns a slice of numbers in increasing order.
// The "undefined" script is not returned.
func (s allSubtags) Scripts() []Script {
scr := make([]Script, language.NumScripts)
for i := range scr {
scr[i] = Script{language.Script(i + 1)}
}
return scr
}
// BaseLanguages returns the list of all supported base languages. It generates
// the list by traversing the internal structures.
func (s allSubtags) BaseLanguages() []Base {
bs := language.BaseLanguages()
base := make([]Base, len(bs))
for i, b := range bs {
base[i] = Base{b}
}
return base
}
// Tags always returns nil.
func (s allSubtags) Tags() []Tag {
return nil
}
// coverage is used by NewCoverage which is used as a convenient way for
// creating Coverage implementations for partially defined data. Very often a
// package will only need to define a subset of slices. coverage provides a
// convenient way to do this. Moreover, packages using NewCoverage, instead of
// their own implementation, will not break if later new slice types are added.
type coverage struct {
tags func() []Tag
bases func() []Base
scripts func() []Script
regions func() []Region
}
func (s *coverage) Tags() []Tag {
if s.tags == nil {
return nil
}
return s.tags()
}
// bases implements sort.Interface and is used to sort base languages.
type bases []Base
func (b bases) Len() int {
return len(b)
}
func (b bases) Swap(i, j int) {
b[i], b[j] = b[j], b[i]
}
func (b bases) Less(i, j int) bool {
return b[i].langID < b[j].langID
}
// BaseLanguages returns the result from calling s.bases if it is specified or
// otherwise derives the set of supported base languages from tags.
func (s *coverage) BaseLanguages() []Base {
if s.bases == nil {
tags := s.Tags()
if len(tags) == 0 {
return nil
}
a := make([]Base, len(tags))
for i, t := range tags {
a[i] = Base{language.Language(t.lang())}
}
sort.Sort(bases(a))
k := 0
for i := 1; i < len(a); i++ {
if a[k] != a[i] {
k++
a[k] = a[i]
}
}
return a[:k+1]
}
return s.bases()
}
func (s *coverage) Scripts() []Script {
if s.scripts == nil {
return nil
}
return s.scripts()
}
func (s *coverage) Regions() []Region {
if s.regions == nil {
return nil
}
return s.regions()
}
// NewCoverage returns a Coverage for the given lists. It is typically used by
// packages providing internationalization services to define their level of
// coverage. A list may be of type []T or func() []T, where T is either Tag,
// Base, Script or Region. The returned Coverage derives the value for Bases
// from Tags if no func or slice for []Base is specified. For other unspecified
// types the returned Coverage will return nil for the respective methods.
func NewCoverage(list ...interface{}) Coverage {
s := &coverage{}
for _, x := range list {
switch v := x.(type) {
case func() []Base:
s.bases = v
case func() []Script:
s.scripts = v
case func() []Region:
s.regions = v
case func() []Tag:
s.tags = v
case []Base:
s.bases = func() []Base { return v }
case []Script:
s.scripts = func() []Script { return v }
case []Region:
s.regions = func() []Region { return v }
case []Tag:
s.tags = func() []Tag { return v }
default:
panic(fmt.Sprintf("language: unsupported set type %T", v))
}
}
return s
}
// Copyright 2013 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.
//go:generate go run gen.go -output tables.go
package language
// TODO: Remove above NOTE after:
// - verifying that tables are dropped correctly (most notably matcher tables).
import (
"strings"
"golang.org/x/text/internal/language"
"golang.org/x/text/internal/language/compact"
)
// Tag represents a BCP 47 language tag. It is used to specify an instance of a
// specific language or locale. All language tag values are guaranteed to be
// well-formed.
type Tag compact.Tag
func makeTag(t language.Tag) (tag Tag) {
return Tag(compact.Make(t))
}
func (t *Tag) tag() language.Tag {
return (*compact.Tag)(t).Tag()
}
func (t *Tag) isCompact() bool {
return (*compact.Tag)(t).IsCompact()
}
// TODO: improve performance.
func (t *Tag) lang() language.Language { return t.tag().LangID }
func (t *Tag) region() language.Region { return t.tag().RegionID }
func (t *Tag) script() language.Script { return t.tag().ScriptID }
// Make is a convenience wrapper for Parse that omits the error.
// In case of an error, a sensible default is returned.
func Make(s string) Tag {
return Default.Make(s)
}
// Make is a convenience wrapper for c.Parse that omits the error.
// In case of an error, a sensible default is returned.
func (c CanonType) Make(s string) Tag {
t, _ := c.Parse(s)
return t
}
// Raw returns the raw base language, script and region, without making an
// attempt to infer their values.
func (t Tag) Raw() (b Base, s Script, r Region) {
tt := t.tag()
return Base{tt.LangID}, Script{tt.ScriptID}, Region{tt.RegionID}
}
// IsRoot returns true if t is equal to language "und".
func (t Tag) IsRoot() bool {
return compact.Tag(t).IsRoot()
}
// CanonType can be used to enable or disable various types of canonicalization.
type CanonType int
const (
// Replace deprecated base languages with their preferred replacements.
DeprecatedBase CanonType = 1 << iota
// Replace deprecated scripts with their preferred replacements.
DeprecatedScript
// Replace deprecated regions with their preferred replacements.
DeprecatedRegion
// Remove redundant scripts.
SuppressScript
// Normalize legacy encodings. This includes legacy languages defined in
// CLDR as well as bibliographic codes defined in ISO-639.
Legacy
// Map the dominant language of a macro language group to the macro language
// subtag. For example cmn -> zh.
Macro
// The CLDR flag should be used if full compatibility with CLDR is required.
// There are a few cases where language.Tag may differ from CLDR. To follow all
// of CLDR's suggestions, use All|CLDR.
CLDR
// Raw can be used to Compose or Parse without Canonicalization.
Raw CanonType = 0
// Replace all deprecated tags with their preferred replacements.
Deprecated = DeprecatedBase | DeprecatedScript | DeprecatedRegion
// All canonicalizations recommended by BCP 47.
BCP47 = Deprecated | SuppressScript
// All canonicalizations.
All = BCP47 | Legacy | Macro
// Default is the canonicalization used by Parse, Make and Compose. To
// preserve as much information as possible, canonicalizations that remove
// potentially valuable information are not included. The Matcher is
// designed to recognize similar tags that would be the same if
// they were canonicalized using All.
Default = Deprecated | Legacy
canonLang = DeprecatedBase | Legacy | Macro
// TODO: LikelyScript, LikelyRegion: suppress similar to ICU.
)
// canonicalize returns the canonicalized equivalent of the tag and
// whether there was any change.
func canonicalize(c CanonType, t language.Tag) (language.Tag, bool) {
if c == Raw {
return t, false
}
changed := false
if c&SuppressScript != 0 {
if t.LangID.SuppressScript() == t.ScriptID {
t.ScriptID = 0
changed = true
}
}
if c&canonLang != 0 {
for {
if l, aliasType := t.LangID.Canonicalize(); l != t.LangID {
switch aliasType {
case language.Legacy:
if c&Legacy != 0 {
if t.LangID == _sh && t.ScriptID == 0 {
t.ScriptID = _Latn
}
t.LangID = l
changed = true
}
case language.Macro:
if c&Macro != 0 {
// We deviate here from CLDR. The mapping "nb" -> "no"
// qualifies as a typical Macro language mapping. However,
// for legacy reasons, CLDR maps "no", the macro language
// code for Norwegian, to the dominant variant "nb". This
// change is currently under consideration for CLDR as well.
// See https://unicode.org/cldr/trac/ticket/2698 and also
// https://unicode.org/cldr/trac/ticket/1790 for some of the
// practical implications. TODO: this check could be removed
// if CLDR adopts this change.
if c&CLDR == 0 || t.LangID != _nb {
changed = true
t.LangID = l
}
}
case language.Deprecated:
if c&DeprecatedBase != 0 {
if t.LangID == _mo && t.RegionID == 0 {
t.RegionID = _MD
}
t.LangID = l
changed = true
// Other canonicalization types may still apply.
continue
}
}
} else if c&Legacy != 0 && t.LangID == _no && c&CLDR != 0 {
t.LangID = _nb
changed = true
}
break
}
}
if c&DeprecatedScript != 0 {
if t.ScriptID == _Qaai {
changed = true
t.ScriptID = _Zinh
}
}
if c&DeprecatedRegion != 0 {
if r := t.RegionID.Canonicalize(); r != t.RegionID {
changed = true
t.RegionID = r
}
}
return t, changed
}
// Canonicalize returns the canonicalized equivalent of the tag.
func (c CanonType) Canonicalize(t Tag) (Tag, error) {
// First try fast path.
if t.isCompact() {
if _, changed := canonicalize(c, compact.Tag(t).Tag()); !changed {
return t, nil
}
}
// It is unlikely that one will canonicalize a tag after matching. So do
// a slow but simple approach here.
if tag, changed := canonicalize(c, t.tag()); changed {
tag.RemakeString()
return makeTag(tag), nil
}
return t, nil
}
// Confidence indicates the level of certainty for a given return value.
// For example, Serbian may be written in Cyrillic or Latin script.
// The confidence level indicates whether a value was explicitly specified,
// whether it is typically the only possible value, or whether there is
// an ambiguity.
type Confidence int
const (
No Confidence = iota // full confidence that there was no match
Low // most likely value picked out of a set of alternatives
High // value is generally assumed to be the correct match
Exact // exact match or explicitly specified value
)
var confName = []string{"No", "Low", "High", "Exact"}
func (c Confidence) String() string {
return confName[c]
}
// String returns the canonical string representation of the language tag.
func (t Tag) String() string {
return t.tag().String()
}
// MarshalText implements encoding.TextMarshaler.
func (t Tag) MarshalText() (text []byte, err error) {
return t.tag().MarshalText()
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (t *Tag) UnmarshalText(text []byte) error {
var tag language.Tag
err := tag.UnmarshalText(text)
*t = makeTag(tag)
return err
}
// Base returns the base language of the language tag. If the base language is
// unspecified, an attempt will be made to infer it from the context.
// It uses a variant of CLDR's Add Likely Subtags algorithm. This is subject to change.
func (t Tag) Base() (Base, Confidence) {
if b := t.lang(); b != 0 {
return Base{b}, Exact
}
tt := t.tag()
c := High
if tt.ScriptID == 0 && !tt.RegionID.IsCountry() {
c = Low
}
if tag, err := tt.Maximize(); err == nil && tag.LangID != 0 {
return Base{tag.LangID}, c
}
return Base{0}, No
}
// Script infers the script for the language tag. If it was not explicitly given, it will infer
// a most likely candidate.
// If more than one script is commonly used for a language, the most likely one
// is returned with a low confidence indication. For example, it returns (Cyrl, Low)
// for Serbian.
// If a script cannot be inferred (Zzzz, No) is returned. We do not use Zyyy (undetermined)
// as one would suspect from the IANA registry for BCP 47. In a Unicode context Zyyy marks
// common characters (like 1, 2, 3, '.', etc.) and is therefore more like multiple scripts.
// See https://www.unicode.org/reports/tr24/#Values for more details. Zzzz is also used for
// unknown value in CLDR. (Zzzz, Exact) is returned if Zzzz was explicitly specified.
// Note that an inferred script is never guaranteed to be the correct one. Latin is
// almost exclusively used for Afrikaans, but Arabic has been used for some texts
// in the past. Also, the script that is commonly used may change over time.
// It uses a variant of CLDR's Add Likely Subtags algorithm. This is subject to change.
func (t Tag) Script() (Script, Confidence) {
if scr := t.script(); scr != 0 {
return Script{scr}, Exact
}
tt := t.tag()
sc, c := language.Script(_Zzzz), No
if scr := tt.LangID.SuppressScript(); scr != 0 {
// Note: it is not always the case that a language with a suppress
// script value is only written in one script (e.g. kk, ms, pa).
if tt.RegionID == 0 {
return Script{scr}, High
}
sc, c = scr, High
}
if tag, err := tt.Maximize(); err == nil {
if tag.ScriptID != sc {
sc, c = tag.ScriptID, Low
}
} else {
tt, _ = canonicalize(Deprecated|Macro, tt)
if tag, err := tt.Maximize(); err == nil && tag.ScriptID != sc {
sc, c = tag.ScriptID, Low
}
}
return Script{sc}, c
}
// Region returns the region for the language tag. If it was not explicitly given, it will
// infer a most likely candidate from the context.
// It uses a variant of CLDR's Add Likely Subtags algorithm. This is subject to change.
func (t Tag) Region() (Region, Confidence) {
if r := t.region(); r != 0 {
return Region{r}, Exact
}
tt := t.tag()
if tt, err := tt.Maximize(); err == nil {
return Region{tt.RegionID}, Low // TODO: differentiate between high and low.
}
tt, _ = canonicalize(Deprecated|Macro, tt)
if tag, err := tt.Maximize(); err == nil {
return Region{tag.RegionID}, Low
}
return Region{_ZZ}, No // TODO: return world instead of undetermined?
}
// Variants returns the variants specified explicitly for this language tag.
// or nil if no variant was specified.
func (t Tag) Variants() []Variant {
if !compact.Tag(t).MayHaveVariants() {
return nil
}
v := []Variant{}
x, str := "", t.tag().Variants()
for str != "" {
x, str = nextToken(str)
v = append(v, Variant{x})
}
return v
}
// Parent returns the CLDR parent of t. In CLDR, missing fields in data for a
// specific language are substituted with fields from the parent language.
// The parent for a language may change for newer versions of CLDR.
//
// Parent returns a tag for a less specific language that is mutually
// intelligible or Und if there is no such language. This may not be the same as
// simply stripping the last BCP 47 subtag. For instance, the parent of "zh-TW"
// is "zh-Hant", and the parent of "zh-Hant" is "und".
func (t Tag) Parent() Tag {
return Tag(compact.Tag(t).Parent())
}
// nextToken returns token t and the rest of the string.
func nextToken(s string) (t, tail string) {
p := strings.Index(s[1:], "-")
if p == -1 {
return s[1:], ""
}
p++
return s[1:p], s[p:]
}
// Extension is a single BCP 47 extension.
type Extension struct {
s string
}
// String returns the string representation of the extension, including the
// type tag.
func (e Extension) String() string {
return e.s
}
// ParseExtension parses s as an extension and returns it on success.
func ParseExtension(s string) (e Extension, err error) {
ext, err := language.ParseExtension(s)
return Extension{ext}, err
}
// Type returns the one-byte extension type of e. It returns 0 for the zero
// exception.
func (e Extension) Type() byte {
if e.s == "" {
return 0
}
return e.s[0]
}
// Tokens returns the list of tokens of e.
func (e Extension) Tokens() []string {
return strings.Split(e.s, "-")
}
// Extension returns the extension of type x for tag t. It will return
// false for ok if t does not have the requested extension. The returned
// extension will be invalid in this case.
func (t Tag) Extension(x byte) (ext Extension, ok bool) {
if !compact.Tag(t).MayHaveExtensions() {
return Extension{}, false
}
e, ok := t.tag().Extension(x)
return Extension{e}, ok
}
// Extensions returns all extensions of t.
func (t Tag) Extensions() []Extension {
if !compact.Tag(t).MayHaveExtensions() {
return nil
}
e := []Extension{}
for _, ext := range t.tag().Extensions() {
e = append(e, Extension{ext})
}
return e
}
// TypeForKey returns the type associated with the given key, where key and type
// are of the allowed values defined for the Unicode locale extension ('u') in
// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
// TypeForKey will traverse the inheritance chain to get the correct value.
//
// If there are multiple types associated with a key, only the first will be
// returned. If there is no type associated with a key, it returns the empty
// string.
func (t Tag) TypeForKey(key string) string {
if !compact.Tag(t).MayHaveExtensions() {
if key != "rg" && key != "va" {
return ""
}
}
return t.tag().TypeForKey(key)
}
// SetTypeForKey returns a new Tag with the key set to type, where key and type
// are of the allowed values defined for the Unicode locale extension ('u') in
// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
// An empty value removes an existing pair with the same key.
func (t Tag) SetTypeForKey(key, value string) (Tag, error) {
tt, err := t.tag().SetTypeForKey(key, value)
return makeTag(tt), err
}
// NumCompactTags is the number of compact tags. The maximum tag is
// NumCompactTags-1.
const NumCompactTags = compact.NumCompactTags
// CompactIndex returns an index, where 0 <= index < NumCompactTags, for tags
// for which data exists in the text repository.The index will change over time
// and should not be stored in persistent storage. If t does not match a compact
// index, exact will be false and the compact index will be returned for the
// first match after repeatedly taking the Parent of t.
func CompactIndex(t Tag) (index int, exact bool) {
id, exact := compact.LanguageID(compact.Tag(t))
return int(id), exact
}
var root = language.Tag{}
// Base is an ISO 639 language code, used for encoding the base language
// of a language tag.
type Base struct {
langID language.Language
}
// ParseBase parses a 2- or 3-letter ISO 639 code.
// It returns a ValueError if s is a well-formed but unknown language identifier
// or another error if another error occurred.
func ParseBase(s string) (Base, error) {
l, err := language.ParseBase(s)
return Base{l}, err
}
// String returns the BCP 47 representation of the base language.
func (b Base) String() string {
return b.langID.String()
}
// ISO3 returns the ISO 639-3 language code.
func (b Base) ISO3() string {
return b.langID.ISO3()
}
// IsPrivateUse reports whether this language code is reserved for private use.
func (b Base) IsPrivateUse() bool {
return b.langID.IsPrivateUse()
}
// Script is a 4-letter ISO 15924 code for representing scripts.
// It is idiomatically represented in title case.
type Script struct {
scriptID language.Script
}
// ParseScript parses a 4-letter ISO 15924 code.
// It returns a ValueError if s is a well-formed but unknown script identifier
// or another error if another error occurred.
func ParseScript(s string) (Script, error) {
sc, err := language.ParseScript(s)
return Script{sc}, err
}
// String returns the script code in title case.
// It returns "Zzzz" for an unspecified script.
func (s Script) String() string {
return s.scriptID.String()
}
// IsPrivateUse reports whether this script code is reserved for private use.
func (s Script) IsPrivateUse() bool {
return s.scriptID.IsPrivateUse()
}
// Region is an ISO 3166-1 or UN M.49 code for representing countries and regions.
type Region struct {
regionID language.Region
}
// EncodeM49 returns the Region for the given UN M.49 code.
// It returns an error if r is not a valid code.
func EncodeM49(r int) (Region, error) {
rid, err := language.EncodeM49(r)
return Region{rid}, err
}
// ParseRegion parses a 2- or 3-letter ISO 3166-1 or a UN M.49 code.
// It returns a ValueError if s is a well-formed but unknown region identifier
// or another error if another error occurred.
func ParseRegion(s string) (Region, error) {
r, err := language.ParseRegion(s)
return Region{r}, err
}
// String returns the BCP 47 representation for the region.
// It returns "ZZ" for an unspecified region.
func (r Region) String() string {
return r.regionID.String()
}
// ISO3 returns the 3-letter ISO code of r.
// Note that not all regions have a 3-letter ISO code.
// In such cases this method returns "ZZZ".
func (r Region) ISO3() string {
return r.regionID.ISO3()
}
// M49 returns the UN M.49 encoding of r, or 0 if this encoding
// is not defined for r.
func (r Region) M49() int {
return r.regionID.M49()
}
// IsPrivateUse reports whether r has the ISO 3166 User-assigned status. This
// may include private-use tags that are assigned by CLDR and used in this
// implementation. So IsPrivateUse and IsCountry can be simultaneously true.
func (r Region) IsPrivateUse() bool {
return r.regionID.IsPrivateUse()
}
// IsCountry returns whether this region is a country or autonomous area. This
// includes non-standard definitions from CLDR.
func (r Region) IsCountry() bool {
return r.regionID.IsCountry()
}
// IsGroup returns whether this region defines a collection of regions. This
// includes non-standard definitions from CLDR.
func (r Region) IsGroup() bool {
return r.regionID.IsGroup()
}
// Contains returns whether Region c is contained by Region r. It returns true
// if c == r.
func (r Region) Contains(c Region) bool {
return r.regionID.Contains(c.regionID)
}
// TLD returns the country code top-level domain (ccTLD). UK is returned for GB.
// In all other cases it returns either the region itself or an error.
//
// This method may return an error for a region for which there exists a
// canonical form with a ccTLD. To get that ccTLD canonicalize r first. The
// region will already be canonicalized it was obtained from a Tag that was
// obtained using any of the default methods.
func (r Region) TLD() (Region, error) {
tld, err := r.regionID.TLD()
return Region{tld}, err
}
// Canonicalize returns the region or a possible replacement if the region is
// deprecated. It will not return a replacement for deprecated regions that
// are split into multiple regions.
func (r Region) Canonicalize() Region {
return Region{r.regionID.Canonicalize()}
}
// Variant represents a registered variant of a language as defined by BCP 47.
type Variant struct {
variant string
}
// ParseVariant parses and returns a Variant. An error is returned if s is not
// a valid variant.
func ParseVariant(s string) (Variant, error) {
v, err := language.ParseVariant(s)
return Variant{v.String()}, err
}
// String returns the string representation of the variant.
func (v Variant) String() string {
return v.variant
}
// Copyright 2013 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 language
import (
"errors"
"strings"
"golang.org/x/text/internal/language"
)
// A MatchOption configures a Matcher.
type MatchOption func(*matcher)
// PreferSameScript will, in the absence of a match, result in the first
// preferred tag with the same script as a supported tag to match this supported
// tag. The default is currently true, but this may change in the future.
func PreferSameScript(preferSame bool) MatchOption {
return func(m *matcher) { m.preferSameScript = preferSame }
}
// TODO(v1.0.0): consider making Matcher a concrete type, instead of interface.
// There doesn't seem to be too much need for multiple types.
// Making it a concrete type allows MatchStrings to be a method, which will
// improve its discoverability.
// MatchStrings parses and matches the given strings until one of them matches
// the language in the Matcher. A string may be an Accept-Language header as
// handled by ParseAcceptLanguage. The default language is returned if no
// other language matched.
func MatchStrings(m Matcher, lang ...string) (tag Tag, index int) {
for _, accept := range lang {
desired, _, err := ParseAcceptLanguage(accept)
if err != nil {
continue
}
if tag, index, conf := m.Match(desired...); conf != No {
return tag, index
}
}
tag, index, _ = m.Match()
return
}
// Matcher is the interface that wraps the Match method.
//
// Match returns the best match for any of the given tags, along with
// a unique index associated with the returned tag and a confidence
// score.
type Matcher interface {
Match(t ...Tag) (tag Tag, index int, c Confidence)
}
// Comprehends reports the confidence score for a speaker of a given language
// to being able to comprehend the written form of an alternative language.
func Comprehends(speaker, alternative Tag) Confidence {
_, _, c := NewMatcher([]Tag{alternative}).Match(speaker)
return c
}
// NewMatcher returns a Matcher that matches an ordered list of preferred tags
// against a list of supported tags based on written intelligibility, closeness
// of dialect, equivalence of subtags and various other rules. It is initialized
// with the list of supported tags. The first element is used as the default
// value in case no match is found.
//
// Its Match method matches the first of the given Tags to reach a certain
// confidence threshold. The tags passed to Match should therefore be specified
// in order of preference. Extensions are ignored for matching.
//
// The index returned by the Match method corresponds to the index of the
// matched tag in t, but is augmented with the Unicode extension ('u')of the
// corresponding preferred tag. This allows user locale options to be passed
// transparently.
func NewMatcher(t []Tag, options ...MatchOption) Matcher {
return newMatcher(t, options)
}
func (m *matcher) Match(want ...Tag) (t Tag, index int, c Confidence) {
var tt language.Tag
match, w, c := m.getBest(want...)
if match != nil {
tt, index = match.tag, match.index
} else {
// TODO: this should be an option
tt = m.default_.tag
if m.preferSameScript {
outer:
for _, w := range want {
script, _ := w.Script()
if script.scriptID == 0 {
// Don't do anything if there is no script, such as with
// private subtags.
continue
}
for i, h := range m.supported {
if script.scriptID == h.maxScript {
tt, index = h.tag, i
break outer
}
}
}
}
// TODO: select first language tag based on script.
}
if w.RegionID != tt.RegionID && w.RegionID != 0 {
if w.RegionID != 0 && tt.RegionID != 0 && tt.RegionID.Contains(w.RegionID) {
tt.RegionID = w.RegionID
tt.RemakeString()
} else if r := w.RegionID.String(); len(r) == 2 {
// TODO: also filter macro and deprecated.
tt, _ = tt.SetTypeForKey("rg", strings.ToLower(r)+"zzzz")
}
}
// Copy options from the user-provided tag into the result tag. This is hard
// to do after the fact, so we do it here.
// TODO: add in alternative variants to -u-va-.
// TODO: add preferred region to -u-rg-.
if e := w.Extensions(); len(e) > 0 {
b := language.Builder{}
b.SetTag(tt)
for _, e := range e {
b.AddExt(e)
}
tt = b.Make()
}
return makeTag(tt), index, c
}
// ErrMissingLikelyTagsData indicates no information was available
// to compute likely values of missing tags.
var ErrMissingLikelyTagsData = errors.New("missing likely tags data")
// func (t *Tag) setTagsFrom(id Tag) {
// t.LangID = id.LangID
// t.ScriptID = id.ScriptID
// t.RegionID = id.RegionID
// }
// Tag Matching
// CLDR defines an algorithm for finding the best match between two sets of language
// tags. The basic algorithm defines how to score a possible match and then find
// the match with the best score
// (see https://www.unicode.org/reports/tr35/#LanguageMatching).
// Using scoring has several disadvantages. The scoring obfuscates the importance of
// the various factors considered, making the algorithm harder to understand. Using
// scoring also requires the full score to be computed for each pair of tags.
//
// We will use a different algorithm which aims to have the following properties:
// - clarity on the precedence of the various selection factors, and
// - improved performance by allowing early termination of a comparison.
//
// Matching algorithm (overview)
// Input:
// - supported: a set of supported tags
// - default: the default tag to return in case there is no match
// - desired: list of desired tags, ordered by preference, starting with
// the most-preferred.
//
// Algorithm:
// 1) Set the best match to the lowest confidence level
// 2) For each tag in "desired":
// a) For each tag in "supported":
// 1) compute the match between the two tags.
// 2) if the match is better than the previous best match, replace it
// with the new match. (see next section)
// b) if the current best match is Exact and pin is true the result will be
// frozen to the language found thusfar, although better matches may
// still be found for the same language.
// 3) If the best match so far is below a certain threshold, return "default".
//
// Ranking:
// We use two phases to determine whether one pair of tags are a better match
// than another pair of tags. First, we determine a rough confidence level. If the
// levels are different, the one with the highest confidence wins.
// Second, if the rough confidence levels are identical, we use a set of tie-breaker
// rules.
//
// The confidence level of matching a pair of tags is determined by finding the
// lowest confidence level of any matches of the corresponding subtags (the
// result is deemed as good as its weakest link).
// We define the following levels:
// Exact - An exact match of a subtag, before adding likely subtags.
// MaxExact - An exact match of a subtag, after adding likely subtags.
// [See Note 2].
// High - High level of mutual intelligibility between different subtag
// variants.
// Low - Low level of mutual intelligibility between different subtag
// variants.
// No - No mutual intelligibility.
//
// The following levels can occur for each type of subtag:
// Base: Exact, MaxExact, High, Low, No
// Script: Exact, MaxExact [see Note 3], Low, No
// Region: Exact, MaxExact, High
// Variant: Exact, High
// Private: Exact, No
//
// Any result with a confidence level of Low or higher is deemed a possible match.
// Once a desired tag matches any of the supported tags with a level of MaxExact
// or higher, the next desired tag is not considered (see Step 2.b).
// Note that CLDR provides languageMatching data that defines close equivalence
// classes for base languages, scripts and regions.
//
// Tie-breaking
// If we get the same confidence level for two matches, we apply a sequence of
// tie-breaking rules. The first that succeeds defines the result. The rules are
// applied in the following order.
// 1) Original language was defined and was identical.
// 2) Original region was defined and was identical.
// 3) Distance between two maximized regions was the smallest.
// 4) Original script was defined and was identical.
// 5) Distance from want tag to have tag using the parent relation [see Note 5.]
// If there is still no winner after these rules are applied, the first match
// found wins.
//
// Notes:
// [2] In practice, as matching of Exact is done in a separate phase from
// matching the other levels, we reuse the Exact level to mean MaxExact in
// the second phase. As a consequence, we only need the levels defined by
// the Confidence type. The MaxExact confidence level is mapped to High in
// the public API.
// [3] We do not differentiate between maximized script values that were derived
// from suppressScript versus most likely tag data. We determined that in
// ranking the two, one ranks just after the other. Moreover, the two cannot
// occur concurrently. As a consequence, they are identical for practical
// purposes.
// [4] In case of deprecated, macro-equivalents and legacy mappings, we assign
// the MaxExact level to allow iw vs he to still be a closer match than
// en-AU vs en-US, for example.
// [5] In CLDR a locale inherits fields that are unspecified for this locale
// from its parent. Therefore, if a locale is a parent of another locale,
// it is a strong measure for closeness, especially when no other tie
// breaker rule applies. One could also argue it is inconsistent, for
// example, when pt-AO matches pt (which CLDR equates with pt-BR), even
// though its parent is pt-PT according to the inheritance rules.
//
// Implementation Details:
// There are several performance considerations worth pointing out. Most notably,
// we preprocess as much as possible (within reason) at the time of creation of a
// matcher. This includes:
// - creating a per-language map, which includes data for the raw base language
// and its canonicalized variant (if applicable),
// - expanding entries for the equivalence classes defined in CLDR's
// languageMatch data.
// The per-language map ensures that typically only a very small number of tags
// need to be considered. The pre-expansion of canonicalized subtags and
// equivalence classes reduces the amount of map lookups that need to be done at
// runtime.
// matcher keeps a set of supported language tags, indexed by language.
type matcher struct {
default_ *haveTag
supported []*haveTag
index map[language.Language]*matchHeader
passSettings bool
preferSameScript bool
}
// matchHeader has the lists of tags for exact matches and matches based on
// maximized and canonicalized tags for a given language.
type matchHeader struct {
haveTags []*haveTag
original bool
}
// haveTag holds a supported Tag and its maximized script and region. The maximized
// or canonicalized language is not stored as it is not needed during matching.
type haveTag struct {
tag language.Tag
// index of this tag in the original list of supported tags.
index int
// conf is the maximum confidence that can result from matching this haveTag.
// When conf < Exact this means it was inserted after applying a CLDR equivalence rule.
conf Confidence
// Maximized region and script.
maxRegion language.Region
maxScript language.Script
// altScript may be checked as an alternative match to maxScript. If altScript
// matches, the confidence level for this match is Low. Theoretically there
// could be multiple alternative scripts. This does not occur in practice.
altScript language.Script
// nextMax is the index of the next haveTag with the same maximized tags.
nextMax uint16
}
func makeHaveTag(tag language.Tag, index int) (haveTag, language.Language) {
max := tag
if tag.LangID != 0 || tag.RegionID != 0 || tag.ScriptID != 0 {
max, _ = canonicalize(All, max)
max, _ = max.Maximize()
max.RemakeString()
}
return haveTag{tag, index, Exact, max.RegionID, max.ScriptID, altScript(max.LangID, max.ScriptID), 0}, max.LangID
}
// altScript returns an alternative script that may match the given script with
// a low confidence. At the moment, the langMatch data allows for at most one
// script to map to another and we rely on this to keep the code simple.
func altScript(l language.Language, s language.Script) language.Script {
for _, alt := range matchScript {
// TODO: also match cases where language is not the same.
if (language.Language(alt.wantLang) == l || language.Language(alt.haveLang) == l) &&
language.Script(alt.haveScript) == s {
return language.Script(alt.wantScript)
}
}
return 0
}
// addIfNew adds a haveTag to the list of tags only if it is a unique tag.
// Tags that have the same maximized values are linked by index.
func (h *matchHeader) addIfNew(n haveTag, exact bool) {
h.original = h.original || exact
// Don't add new exact matches.
for _, v := range h.haveTags {
if equalsRest(v.tag, n.tag) {
return
}
}
// Allow duplicate maximized tags, but create a linked list to allow quickly
// comparing the equivalents and bail out.
for i, v := range h.haveTags {
if v.maxScript == n.maxScript &&
v.maxRegion == n.maxRegion &&
v.tag.VariantOrPrivateUseTags() == n.tag.VariantOrPrivateUseTags() {
for h.haveTags[i].nextMax != 0 {
i = int(h.haveTags[i].nextMax)
}
h.haveTags[i].nextMax = uint16(len(h.haveTags))
break
}
}
h.haveTags = append(h.haveTags, &n)
}
// header returns the matchHeader for the given language. It creates one if
// it doesn't already exist.
func (m *matcher) header(l language.Language) *matchHeader {
if h := m.index[l]; h != nil {
return h
}
h := &matchHeader{}
m.index[l] = h
return h
}
func toConf(d uint8) Confidence {
if d <= 10 {
return High
}
if d < 30 {
return Low
}
return No
}
// newMatcher builds an index for the given supported tags and returns it as
// a matcher. It also expands the index by considering various equivalence classes
// for a given tag.
func newMatcher(supported []Tag, options []MatchOption) *matcher {
m := &matcher{
index: make(map[language.Language]*matchHeader),
preferSameScript: true,
}
for _, o := range options {
o(m)
}
if len(supported) == 0 {
m.default_ = &haveTag{}
return m
}
// Add supported languages to the index. Add exact matches first to give
// them precedence.
for i, tag := range supported {
tt := tag.tag()
pair, _ := makeHaveTag(tt, i)
m.header(tt.LangID).addIfNew(pair, true)
m.supported = append(m.supported, &pair)
}
m.default_ = m.header(supported[0].lang()).haveTags[0]
// Keep these in two different loops to support the case that two equivalent
// languages are distinguished, such as iw and he.
for i, tag := range supported {
tt := tag.tag()
pair, max := makeHaveTag(tt, i)
if max != tt.LangID {
m.header(max).addIfNew(pair, true)
}
}
// update is used to add indexes in the map for equivalent languages.
// update will only add entries to original indexes, thus not computing any
// transitive relations.
update := func(want, have uint16, conf Confidence) {
if hh := m.index[language.Language(have)]; hh != nil {
if !hh.original {
return
}
hw := m.header(language.Language(want))
for _, ht := range hh.haveTags {
v := *ht
if conf < v.conf {
v.conf = conf
}
v.nextMax = 0 // this value needs to be recomputed
if v.altScript != 0 {
v.altScript = altScript(language.Language(want), v.maxScript)
}
hw.addIfNew(v, conf == Exact && hh.original)
}
}
}
// Add entries for languages with mutual intelligibility as defined by CLDR's
// languageMatch data.
for _, ml := range matchLang {
update(ml.want, ml.have, toConf(ml.distance))
if !ml.oneway {
update(ml.have, ml.want, toConf(ml.distance))
}
}
// Add entries for possible canonicalizations. This is an optimization to
// ensure that only one map lookup needs to be done at runtime per desired tag.
// First we match deprecated equivalents. If they are perfect equivalents
// (their canonicalization simply substitutes a different language code, but
// nothing else), the match confidence is Exact, otherwise it is High.
for i, lm := range language.AliasMap {
// If deprecated codes match and there is no fiddling with the script
// or region, we consider it an exact match.
conf := Exact
if language.AliasTypes[i] != language.Macro {
if !isExactEquivalent(language.Language(lm.From)) {
conf = High
}
update(lm.To, lm.From, conf)
}
update(lm.From, lm.To, conf)
}
return m
}
// getBest gets the best matching tag in m for any of the given tags, taking into
// account the order of preference of the given tags.
func (m *matcher) getBest(want ...Tag) (got *haveTag, orig language.Tag, c Confidence) {
best := bestMatch{}
for i, ww := range want {
w := ww.tag()
var max language.Tag
// Check for exact match first.
h := m.index[w.LangID]
if w.LangID != 0 {
if h == nil {
continue
}
// Base language is defined.
max, _ = canonicalize(Legacy|Deprecated|Macro, w)
// A region that is added through canonicalization is stronger than
// a maximized region: set it in the original (e.g. mo -> ro-MD).
if w.RegionID != max.RegionID {
w.RegionID = max.RegionID
}
// TODO: should we do the same for scripts?
// See test case: en, sr, nl ; sh ; sr
max, _ = max.Maximize()
} else {
// Base language is not defined.
if h != nil {
for i := range h.haveTags {
have := h.haveTags[i]
if equalsRest(have.tag, w) {
return have, w, Exact
}
}
}
if w.ScriptID == 0 && w.RegionID == 0 {
// We skip all tags matching und for approximate matching, including
// private tags.
continue
}
max, _ = w.Maximize()
if h = m.index[max.LangID]; h == nil {
continue
}
}
pin := true
for _, t := range want[i+1:] {
if w.LangID == t.lang() {
pin = false
break
}
}
// Check for match based on maximized tag.
for i := range h.haveTags {
have := h.haveTags[i]
best.update(have, w, max.ScriptID, max.RegionID, pin)
if best.conf == Exact {
for have.nextMax != 0 {
have = h.haveTags[have.nextMax]
best.update(have, w, max.ScriptID, max.RegionID, pin)
}
return best.have, best.want, best.conf
}
}
}
if best.conf <= No {
if len(want) != 0 {
return nil, want[0].tag(), No
}
return nil, language.Tag{}, No
}
return best.have, best.want, best.conf
}
// bestMatch accumulates the best match so far.
type bestMatch struct {
have *haveTag
want language.Tag
conf Confidence
pinnedRegion language.Region
pinLanguage bool
sameRegionGroup bool
// Cached results from applying tie-breaking rules.
origLang bool
origReg bool
paradigmReg bool
regGroupDist uint8
origScript bool
}
// update updates the existing best match if the new pair is considered to be a
// better match. To determine if the given pair is a better match, it first
// computes the rough confidence level. If this surpasses the current match, it
// will replace it and update the tie-breaker rule cache. If there is a tie, it
// proceeds with applying a series of tie-breaker rules. If there is no
// conclusive winner after applying the tie-breaker rules, it leaves the current
// match as the preferred match.
//
// If pin is true and have and tag are a strong match, it will henceforth only
// consider matches for this language. This corresponds to the idea that most
// users have a strong preference for the first defined language. A user can
// still prefer a second language over a dialect of the preferred language by
// explicitly specifying dialects, e.g. "en, nl, en-GB". In this case pin should
// be false.
func (m *bestMatch) update(have *haveTag, tag language.Tag, maxScript language.Script, maxRegion language.Region, pin bool) {
// Bail if the maximum attainable confidence is below that of the current best match.
c := have.conf
if c < m.conf {
return
}
// Don't change the language once we already have found an exact match.
if m.pinLanguage && tag.LangID != m.want.LangID {
return
}
// Pin the region group if we are comparing tags for the same language.
if tag.LangID == m.want.LangID && m.sameRegionGroup {
_, sameGroup := regionGroupDist(m.pinnedRegion, have.maxRegion, have.maxScript, m.want.LangID)
if !sameGroup {
return
}
}
if c == Exact && have.maxScript == maxScript {
// If there is another language and then another entry of this language,
// don't pin anything, otherwise pin the language.
m.pinLanguage = pin
}
if equalsRest(have.tag, tag) {
} else if have.maxScript != maxScript {
// There is usually very little comprehension between different scripts.
// In a few cases there may still be Low comprehension. This possibility
// is pre-computed and stored in have.altScript.
if Low < m.conf || have.altScript != maxScript {
return
}
c = Low
} else if have.maxRegion != maxRegion {
if High < c {
// There is usually a small difference between languages across regions.
c = High
}
}
// We store the results of the computations of the tie-breaker rules along
// with the best match. There is no need to do the checks once we determine
// we have a winner, but we do still need to do the tie-breaker computations.
// We use "beaten" to keep track if we still need to do the checks.
beaten := false // true if the new pair defeats the current one.
if c != m.conf {
if c < m.conf {
return
}
beaten = true
}
// Tie-breaker rules:
// We prefer if the pre-maximized language was specified and identical.
origLang := have.tag.LangID == tag.LangID && tag.LangID != 0
if !beaten && m.origLang != origLang {
if m.origLang {
return
}
beaten = true
}
// We prefer if the pre-maximized region was specified and identical.
origReg := have.tag.RegionID == tag.RegionID && tag.RegionID != 0
if !beaten && m.origReg != origReg {
if m.origReg {
return
}
beaten = true
}
regGroupDist, sameGroup := regionGroupDist(have.maxRegion, maxRegion, maxScript, tag.LangID)
if !beaten && m.regGroupDist != regGroupDist {
if regGroupDist > m.regGroupDist {
return
}
beaten = true
}
paradigmReg := isParadigmLocale(tag.LangID, have.maxRegion)
if !beaten && m.paradigmReg != paradigmReg {
if !paradigmReg {
return
}
beaten = true
}
// Next we prefer if the pre-maximized script was specified and identical.
origScript := have.tag.ScriptID == tag.ScriptID && tag.ScriptID != 0
if !beaten && m.origScript != origScript {
if m.origScript {
return
}
beaten = true
}
// Update m to the newly found best match.
if beaten {
m.have = have
m.want = tag
m.conf = c
m.pinnedRegion = maxRegion
m.sameRegionGroup = sameGroup
m.origLang = origLang
m.origReg = origReg
m.paradigmReg = paradigmReg
m.origScript = origScript
m.regGroupDist = regGroupDist
}
}
func isParadigmLocale(lang language.Language, r language.Region) bool {
for _, e := range paradigmLocales {
if language.Language(e[0]) == lang && (r == language.Region(e[1]) || r == language.Region(e[2])) {
return true
}
}
return false
}
// regionGroupDist computes the distance between two regions based on their
// CLDR grouping.
func regionGroupDist(a, b language.Region, script language.Script, lang language.Language) (dist uint8, same bool) {
const defaultDistance = 4
aGroup := uint(regionToGroups[a]) << 1
bGroup := uint(regionToGroups[b]) << 1
for _, ri := range matchRegion {
if language.Language(ri.lang) == lang && (ri.script == 0 || language.Script(ri.script) == script) {
group := uint(1 << (ri.group &^ 0x80))
if 0x80&ri.group == 0 {
if aGroup&bGroup&group != 0 { // Both regions are in the group.
return ri.distance, ri.distance == defaultDistance
}
} else {
if (aGroup|bGroup)&group == 0 { // Both regions are not in the group.
return ri.distance, ri.distance == defaultDistance
}
}
}
}
return defaultDistance, true
}
// equalsRest compares everything except the language.
func equalsRest(a, b language.Tag) bool {
// TODO: don't include extensions in this comparison. To do this efficiently,
// though, we should handle private tags separately.
return a.ScriptID == b.ScriptID && a.RegionID == b.RegionID && a.VariantOrPrivateUseTags() == b.VariantOrPrivateUseTags()
}
// isExactEquivalent returns true if canonicalizing the language will not alter
// the script or region of a tag.
func isExactEquivalent(l language.Language) bool {
for _, o := range notEquivalent {
if o == l {
return false
}
}
return true
}
var notEquivalent []language.Language
func init() {
// Create a list of all languages for which canonicalization may alter the
// script or region.
for _, lm := range language.AliasMap {
tag := language.Tag{LangID: language.Language(lm.From)}
if tag, _ = canonicalize(All, tag); tag.ScriptID != 0 || tag.RegionID != 0 {
notEquivalent = append(notEquivalent, language.Language(lm.From))
}
}
// Maximize undefined regions of paradigm locales.
for i, v := range paradigmLocales {
t := language.Tag{LangID: language.Language(v[0])}
max, _ := t.Maximize()
if v[1] == 0 {
paradigmLocales[i][1] = uint16(max.RegionID)
}
if v[2] == 0 {
paradigmLocales[i][2] = uint16(max.RegionID)
}
}
}
// Copyright 2013 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 language
import (
"errors"
"sort"
"strconv"
"strings"
"golang.org/x/text/internal/language"
)
// ValueError is returned by any of the parsing functions when the
// input is well-formed but the respective subtag is not recognized
// as a valid value.
type ValueError interface {
error
// Subtag returns the subtag for which the error occurred.
Subtag() string
}
// Parse parses the given BCP 47 string and returns a valid Tag. If parsing
// failed it returns an error and any part of the tag that could be parsed.
// If parsing succeeded but an unknown value was found, it returns
// ValueError. The Tag returned in this case is just stripped of the unknown
// value. All other values are preserved. It accepts tags in the BCP 47 format
// and extensions to this standard defined in
// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
// The resulting tag is canonicalized using the default canonicalization type.
func Parse(s string) (t Tag, err error) {
return Default.Parse(s)
}
// Parse parses the given BCP 47 string and returns a valid Tag. If parsing
// failed it returns an error and any part of the tag that could be parsed.
// If parsing succeeded but an unknown value was found, it returns
// ValueError. The Tag returned in this case is just stripped of the unknown
// value. All other values are preserved. It accepts tags in the BCP 47 format
// and extensions to this standard defined in
// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
// The resulting tag is canonicalized using the canonicalization type c.
func (c CanonType) Parse(s string) (t Tag, err error) {
defer func() {
if recover() != nil {
t = Tag{}
err = language.ErrSyntax
}
}()
tt, err := language.Parse(s)
if err != nil {
return makeTag(tt), err
}
tt, changed := canonicalize(c, tt)
if changed {
tt.RemakeString()
}
return makeTag(tt), nil
}
// Compose creates a Tag from individual parts, which may be of type Tag, Base,
// Script, Region, Variant, []Variant, Extension, []Extension or error. If a
// Base, Script or Region or slice of type Variant or Extension is passed more
// than once, the latter will overwrite the former. Variants and Extensions are
// accumulated, but if two extensions of the same type are passed, the latter
// will replace the former. For -u extensions, though, the key-type pairs are
// added, where later values overwrite older ones. A Tag overwrites all former
// values and typically only makes sense as the first argument. The resulting
// tag is returned after canonicalizing using the Default CanonType. If one or
// more errors are encountered, one of the errors is returned.
func Compose(part ...interface{}) (t Tag, err error) {
return Default.Compose(part...)
}
// Compose creates a Tag from individual parts, which may be of type Tag, Base,
// Script, Region, Variant, []Variant, Extension, []Extension or error. If a
// Base, Script or Region or slice of type Variant or Extension is passed more
// than once, the latter will overwrite the former. Variants and Extensions are
// accumulated, but if two extensions of the same type are passed, the latter
// will replace the former. For -u extensions, though, the key-type pairs are
// added, where later values overwrite older ones. A Tag overwrites all former
// values and typically only makes sense as the first argument. The resulting
// tag is returned after canonicalizing using CanonType c. If one or more errors
// are encountered, one of the errors is returned.
func (c CanonType) Compose(part ...interface{}) (t Tag, err error) {
defer func() {
if recover() != nil {
t = Tag{}
err = language.ErrSyntax
}
}()
var b language.Builder
if err = update(&b, part...); err != nil {
return und, err
}
b.Tag, _ = canonicalize(c, b.Tag)
return makeTag(b.Make()), err
}
var errInvalidArgument = errors.New("invalid Extension or Variant")
func update(b *language.Builder, part ...interface{}) (err error) {
for _, x := range part {
switch v := x.(type) {
case Tag:
b.SetTag(v.tag())
case Base:
b.Tag.LangID = v.langID
case Script:
b.Tag.ScriptID = v.scriptID
case Region:
b.Tag.RegionID = v.regionID
case Variant:
if v.variant == "" {
err = errInvalidArgument
break
}
b.AddVariant(v.variant)
case Extension:
if v.s == "" {
err = errInvalidArgument
break
}
b.SetExt(v.s)
case []Variant:
b.ClearVariants()
for _, v := range v {
b.AddVariant(v.variant)
}
case []Extension:
b.ClearExtensions()
for _, e := range v {
b.SetExt(e.s)
}
// TODO: support parsing of raw strings based on morphology or just extensions?
case error:
if v != nil {
err = v
}
}
}
return
}
var errInvalidWeight = errors.New("ParseAcceptLanguage: invalid weight")
var errTagListTooLarge = errors.New("tag list exceeds max length")
// ParseAcceptLanguage parses the contents of an Accept-Language header as
// defined in http://www.ietf.org/rfc/rfc2616.txt and returns a list of Tags and
// a list of corresponding quality weights. It is more permissive than RFC 2616
// and may return non-nil slices even if the input is not valid.
// The Tags will be sorted by highest weight first and then by first occurrence.
// Tags with a weight of zero will be dropped. An error will be returned if the
// input could not be parsed.
func ParseAcceptLanguage(s string) (tag []Tag, q []float32, err error) {
defer func() {
if recover() != nil {
tag = nil
q = nil
err = language.ErrSyntax
}
}()
if strings.Count(s, "-") > 1000 {
return nil, nil, errTagListTooLarge
}
var entry string
for s != "" {
if entry, s = split(s, ','); entry == "" {
continue
}
entry, weight := split(entry, ';')
// Scan the language.
t, err := Parse(entry)
if err != nil {
id, ok := acceptFallback[entry]
if !ok {
return nil, nil, err
}
t = makeTag(language.Tag{LangID: id})
}
// Scan the optional weight.
w := 1.0
if weight != "" {
weight = consume(weight, 'q')
weight = consume(weight, '=')
// consume returns the empty string when a token could not be
// consumed, resulting in an error for ParseFloat.
if w, err = strconv.ParseFloat(weight, 32); err != nil {
return nil, nil, errInvalidWeight
}
// Drop tags with a quality weight of 0.
if w <= 0 {
continue
}
}
tag = append(tag, t)
q = append(q, float32(w))
}
sort.Stable(&tagSort{tag, q})
return tag, q, nil
}
// consume removes a leading token c from s and returns the result or the empty
// string if there is no such token.
func consume(s string, c byte) string {
if s == "" || s[0] != c {
return ""
}
return strings.TrimSpace(s[1:])
}
func split(s string, c byte) (head, tail string) {
if i := strings.IndexByte(s, c); i >= 0 {
return strings.TrimSpace(s[:i]), strings.TrimSpace(s[i+1:])
}
return strings.TrimSpace(s), ""
}
// Add hack mapping to deal with a small number of cases that occur
// in Accept-Language (with reasonable frequency).
var acceptFallback = map[string]language.Language{
"english": _en,
"deutsch": _de,
"italian": _it,
"french": _fr,
"*": _mul, // defined in the spec to match all languages.
}
type tagSort struct {
tag []Tag
q []float32
}
func (s *tagSort) Len() int {
return len(s.q)
}
func (s *tagSort) Less(i, j int) bool {
return s.q[i] > s.q[j]
}
func (s *tagSort) Swap(i, j int) {
s.tag[i], s.tag[j] = s.tag[j], s.tag[i]
s.q[i], s.q[j] = s.q[j], s.q[i]
}
// Copyright 2013 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 language
import "golang.org/x/text/internal/language/compact"
// TODO: Various sets of commonly use tags and regions.
// MustParse is like Parse, but panics if the given BCP 47 tag cannot be parsed.
// It simplifies safe initialization of Tag values.
func MustParse(s string) Tag {
t, err := Parse(s)
if err != nil {
panic(err)
}
return t
}
// MustParse is like Parse, but panics if the given BCP 47 tag cannot be parsed.
// It simplifies safe initialization of Tag values.
func (c CanonType) MustParse(s string) Tag {
t, err := c.Parse(s)
if err != nil {
panic(err)
}
return t
}
// MustParseBase is like ParseBase, but panics if the given base cannot be parsed.
// It simplifies safe initialization of Base values.
func MustParseBase(s string) Base {
b, err := ParseBase(s)
if err != nil {
panic(err)
}
return b
}
// MustParseScript is like ParseScript, but panics if the given script cannot be
// parsed. It simplifies safe initialization of Script values.
func MustParseScript(s string) Script {
scr, err := ParseScript(s)
if err != nil {
panic(err)
}
return scr
}
// MustParseRegion is like ParseRegion, but panics if the given region cannot be
// parsed. It simplifies safe initialization of Region values.
func MustParseRegion(s string) Region {
r, err := ParseRegion(s)
if err != nil {
panic(err)
}
return r
}
var (
und = Tag{}
Und Tag = Tag{}
Afrikaans Tag = Tag(compact.Afrikaans)
Amharic Tag = Tag(compact.Amharic)
Arabic Tag = Tag(compact.Arabic)
ModernStandardArabic Tag = Tag(compact.ModernStandardArabic)
Azerbaijani Tag = Tag(compact.Azerbaijani)
Bulgarian Tag = Tag(compact.Bulgarian)
Bengali Tag = Tag(compact.Bengali)
Catalan Tag = Tag(compact.Catalan)
Czech Tag = Tag(compact.Czech)
Danish Tag = Tag(compact.Danish)
German Tag = Tag(compact.German)
Greek Tag = Tag(compact.Greek)
English Tag = Tag(compact.English)
AmericanEnglish Tag = Tag(compact.AmericanEnglish)
BritishEnglish Tag = Tag(compact.BritishEnglish)
Spanish Tag = Tag(compact.Spanish)
EuropeanSpanish Tag = Tag(compact.EuropeanSpanish)
LatinAmericanSpanish Tag = Tag(compact.LatinAmericanSpanish)
Estonian Tag = Tag(compact.Estonian)
Persian Tag = Tag(compact.Persian)
Finnish Tag = Tag(compact.Finnish)
Filipino Tag = Tag(compact.Filipino)
French Tag = Tag(compact.French)
CanadianFrench Tag = Tag(compact.CanadianFrench)
Gujarati Tag = Tag(compact.Gujarati)
Hebrew Tag = Tag(compact.Hebrew)
Hindi Tag = Tag(compact.Hindi)
Croatian Tag = Tag(compact.Croatian)
Hungarian Tag = Tag(compact.Hungarian)
Armenian Tag = Tag(compact.Armenian)
Indonesian Tag = Tag(compact.Indonesian)
Icelandic Tag = Tag(compact.Icelandic)
Italian Tag = Tag(compact.Italian)
Japanese Tag = Tag(compact.Japanese)
Georgian Tag = Tag(compact.Georgian)
Kazakh Tag = Tag(compact.Kazakh)
Khmer Tag = Tag(compact.Khmer)
Kannada Tag = Tag(compact.Kannada)
Korean Tag = Tag(compact.Korean)
Kirghiz Tag = Tag(compact.Kirghiz)
Lao Tag = Tag(compact.Lao)
Lithuanian Tag = Tag(compact.Lithuanian)
Latvian Tag = Tag(compact.Latvian)
Macedonian Tag = Tag(compact.Macedonian)
Malayalam Tag = Tag(compact.Malayalam)
Mongolian Tag = Tag(compact.Mongolian)
Marathi Tag = Tag(compact.Marathi)
Malay Tag = Tag(compact.Malay)
Burmese Tag = Tag(compact.Burmese)
Nepali Tag = Tag(compact.Nepali)
Dutch Tag = Tag(compact.Dutch)
Norwegian Tag = Tag(compact.Norwegian)
Punjabi Tag = Tag(compact.Punjabi)
Polish Tag = Tag(compact.Polish)
Portuguese Tag = Tag(compact.Portuguese)
BrazilianPortuguese Tag = Tag(compact.BrazilianPortuguese)
EuropeanPortuguese Tag = Tag(compact.EuropeanPortuguese)
Romanian Tag = Tag(compact.Romanian)
Russian Tag = Tag(compact.Russian)
Sinhala Tag = Tag(compact.Sinhala)
Slovak Tag = Tag(compact.Slovak)
Slovenian Tag = Tag(compact.Slovenian)
Albanian Tag = Tag(compact.Albanian)
Serbian Tag = Tag(compact.Serbian)
SerbianLatin Tag = Tag(compact.SerbianLatin)
Swedish Tag = Tag(compact.Swedish)
Swahili Tag = Tag(compact.Swahili)
Tamil Tag = Tag(compact.Tamil)
Telugu Tag = Tag(compact.Telugu)
Thai Tag = Tag(compact.Thai)
Turkish Tag = Tag(compact.Turkish)
Ukrainian Tag = Tag(compact.Ukrainian)
Urdu Tag = Tag(compact.Urdu)
Uzbek Tag = Tag(compact.Uzbek)
Vietnamese Tag = Tag(compact.Vietnamese)
Chinese Tag = Tag(compact.Chinese)
SimplifiedChinese Tag = Tag(compact.SimplifiedChinese)
TraditionalChinese Tag = Tag(compact.TraditionalChinese)
Zulu Tag = Tag(compact.Zulu)
)
// 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 catalog defines collections of translated format strings.
//
// This package mostly defines types for populating catalogs with messages. The
// catmsg package contains further definitions for creating custom message and
// dictionary types as well as packages that use Catalogs.
//
// Package catalog defines various interfaces: Dictionary, Loader, and Message.
// A Dictionary maintains a set of translations of format strings for a single
// language. The Loader interface defines a source of dictionaries. A
// translation of a format string is represented by a Message.
//
// # Catalogs
//
// A Catalog defines a programmatic interface for setting message translations.
// It maintains a set of per-language dictionaries with translations for a set
// of keys. For message translation to function properly, a translation should
// be defined for each key for each supported language. A dictionary may be
// underspecified, though, if there is a parent language that already defines
// the key. For example, a Dictionary for "en-GB" could leave out entries that
// are identical to those in a dictionary for "en".
//
// # Messages
//
// A Message is a format string which varies on the value of substitution
// variables. For instance, to indicate the number of results one could want "no
// results" if there are none, "1 result" if there is 1, and "%d results" for
// any other number. Catalog is agnostic to the kind of format strings that are
// used: for instance, messages can follow either the printf-style substitution
// from package fmt or use templates.
//
// A Message does not substitute arguments in the format string. This job is
// reserved for packages that render strings, such as message, that use Catalogs
// to selected string. This separation of concerns allows Catalog to be used to
// store any kind of formatting strings.
//
// # Selecting messages based on linguistic features of substitution arguments
//
// Messages may vary based on any linguistic features of the argument values.
// The most common one is plural form, but others exist.
//
// Selection messages are provided in packages that provide support for a
// specific linguistic feature. The following snippet uses plural.Selectf:
//
// catalog.Set(language.English, "You are %d minute(s) late.",
// plural.Selectf(1, "",
// plural.One, "You are 1 minute late.",
// plural.Other, "You are %d minutes late."))
//
// In this example, a message is stored in the Catalog where one of two messages
// is selected based on the first argument, a number. The first message is
// selected if the argument is singular (identified by the selector "one") and
// the second message is selected in all other cases. The selectors are defined
// by the plural rules defined in CLDR. The selector "other" is special and will
// always match. Each language always defines one of the linguistic categories
// to be "other." For English, singular is "one" and plural is "other".
//
// Selects can be nested. This allows selecting sentences based on features of
// multiple arguments or multiple linguistic properties of a single argument.
//
// # String interpolation
//
// There is often a lot of commonality between the possible variants of a
// message. For instance, in the example above the word "minute" varies based on
// the plural catogory of the argument, but the rest of the sentence is
// identical. Using interpolation the above message can be rewritten as:
//
// catalog.Set(language.English, "You are %d minute(s) late.",
// catalog.Var("minutes",
// plural.Selectf(1, "", plural.One, "minute", plural.Other, "minutes")),
// catalog.String("You are %[1]d ${minutes} late."))
//
// Var is defined to return the variable name if the message does not yield a
// match. This allows us to further simplify this snippet to
//
// catalog.Set(language.English, "You are %d minute(s) late.",
// catalog.Var("minutes", plural.Selectf(1, "", plural.One, "minute")),
// catalog.String("You are %d ${minutes} late."))
//
// Overall this is still only a minor improvement, but things can get a lot more
// unwieldy if more than one linguistic feature is used to determine a message
// variant. Consider the following example:
//
// // argument 1: list of hosts, argument 2: list of guests
// catalog.Set(language.English, "%[1]v invite(s) %[2]v to their party.",
// catalog.Var("their",
// plural.Selectf(1, ""
// plural.One, gender.Select(1, "female", "her", "other", "his"))),
// catalog.Var("invites", plural.Selectf(1, "", plural.One, "invite"))
// catalog.String("%[1]v ${invites} %[2]v to ${their} party.")),
//
// Without variable substitution, this would have to be written as
//
// // argument 1: list of hosts, argument 2: list of guests
// catalog.Set(language.English, "%[1]v invite(s) %[2]v to their party.",
// plural.Selectf(1, "",
// plural.One, gender.Select(1,
// "female", "%[1]v invites %[2]v to her party."
// "other", "%[1]v invites %[2]v to his party."),
// plural.Other, "%[1]v invites %[2]v to their party."))
//
// Not necessarily shorter, but using variables there is less duplication and
// the messages are more maintenance friendly. Moreover, languages may have up
// to six plural forms. This makes the use of variables more welcome.
//
// Different messages using the same inflections can reuse variables by moving
// them to macros. Using macros we can rewrite the message as:
//
// // argument 1: list of hosts, argument 2: list of guests
// catalog.SetString(language.English, "%[1]v invite(s) %[2]v to their party.",
// "%[1]v ${invites(1)} %[2]v to ${their(1)} party.")
//
// Where the following macros were defined separately.
//
// catalog.SetMacro(language.English, "invites", plural.Selectf(1, "",
// plural.One, "invite"))
// catalog.SetMacro(language.English, "their", plural.Selectf(1, "",
// plural.One, gender.Select(1, "female", "her", "other", "his"))),
//
// Placeholders use parentheses and the arguments to invoke a macro.
//
// # Looking up messages
//
// Message lookup using Catalogs is typically only done by specialized packages
// and is not something the user should be concerned with. For instance, to
// express the tardiness of a user using the related message we defined earlier,
// the user may use the package message like so:
//
// p := message.NewPrinter(language.English)
// p.Printf("You are %d minute(s) late.", 5)
//
// Which would print:
//
// You are 5 minutes late.
//
// This package is UNDER CONSTRUCTION and its API may change.
package catalog // import "golang.org/x/text/message/catalog"
// TODO:
// Some way to freeze a catalog.
// - Locking on each lockup turns out to be about 50% of the total running time
// for some of the benchmarks in the message package.
// Consider these:
// - Sequence type to support sequences in user-defined messages.
// - Garbage collection: Remove dictionaries that can no longer be reached
// as other dictionaries have been added that cover all possible keys.
import (
"errors"
"fmt"
"golang.org/x/text/internal"
"golang.org/x/text/internal/catmsg"
"golang.org/x/text/language"
)
// A Catalog allows lookup of translated messages.
type Catalog interface {
// Languages returns all languages for which the Catalog contains variants.
Languages() []language.Tag
// Matcher returns a Matcher for languages from this Catalog.
Matcher() language.Matcher
// A Context is used for evaluating Messages.
Context(tag language.Tag, r catmsg.Renderer) *Context
// This method also makes Catalog a private interface.
lookup(tag language.Tag, key string) (data string, ok bool)
}
// NewFromMap creates a Catalog from the given map. If a Dictionary is
// underspecified the entry is retrieved from a parent language.
func NewFromMap(dictionaries map[string]Dictionary, opts ...Option) (Catalog, error) {
options := options{}
for _, o := range opts {
o(&options)
}
c := &catalog{
dicts: map[language.Tag]Dictionary{},
}
_, hasFallback := dictionaries[options.fallback.String()]
if hasFallback {
// TODO: Should it be okay to not have a fallback language?
// Catalog generators could enforce there is always a fallback.
c.langs = append(c.langs, options.fallback)
}
for lang, dict := range dictionaries {
tag, err := language.Parse(lang)
if err != nil {
return nil, fmt.Errorf("catalog: invalid language tag %q", lang)
}
if _, ok := c.dicts[tag]; ok {
return nil, fmt.Errorf("catalog: duplicate entry for tag %q after normalization", tag)
}
c.dicts[tag] = dict
if !hasFallback || tag != options.fallback {
c.langs = append(c.langs, tag)
}
}
if hasFallback {
internal.SortTags(c.langs[1:])
} else {
internal.SortTags(c.langs)
}
c.matcher = language.NewMatcher(c.langs)
return c, nil
}
// A Dictionary is a source of translations for a single language.
type Dictionary interface {
// Lookup returns a message compiled with catmsg.Compile for the given key.
// It returns false for ok if such a message could not be found.
Lookup(key string) (data string, ok bool)
}
type catalog struct {
langs []language.Tag
dicts map[language.Tag]Dictionary
macros store
matcher language.Matcher
}
func (c *catalog) Languages() []language.Tag { return c.langs }
func (c *catalog) Matcher() language.Matcher { return c.matcher }
func (c *catalog) lookup(tag language.Tag, key string) (data string, ok bool) {
for ; ; tag = tag.Parent() {
if dict, ok := c.dicts[tag]; ok {
if data, ok := dict.Lookup(key); ok {
return data, true
}
}
if tag == language.Und {
break
}
}
return "", false
}
// Context returns a Context for formatting messages.
// Only one Message may be formatted per context at any given time.
func (c *catalog) Context(tag language.Tag, r catmsg.Renderer) *Context {
return &Context{
cat: c,
tag: tag,
dec: catmsg.NewDecoder(tag, r, &dict{&c.macros, tag}),
}
}
// A Builder allows building a Catalog programmatically.
type Builder struct {
options
matcher language.Matcher
index store
macros store
}
type options struct {
fallback language.Tag
}
// An Option configures Catalog behavior.
type Option func(*options)
// Fallback specifies the default fallback language. The default is Und.
func Fallback(tag language.Tag) Option {
return func(o *options) { o.fallback = tag }
}
// TODO:
// // Catalogs specifies one or more sources for a Catalog.
// // Lookups are in order.
// // This can be changed inserting a Catalog used for setting, which implements
// // Loader, used for setting in the chain.
// func Catalogs(d ...Loader) Option {
// return nil
// }
//
// func Delims(start, end string) Option {}
//
// func Dict(tag language.Tag, d ...Dictionary) Option
// NewBuilder returns an empty mutable Catalog.
func NewBuilder(opts ...Option) *Builder {
c := &Builder{}
for _, o := range opts {
o(&c.options)
}
return c
}
// SetString is shorthand for Set(tag, key, String(msg)).
func (c *Builder) SetString(tag language.Tag, key string, msg string) error {
return c.set(tag, key, &c.index, String(msg))
}
// Set sets the translation for the given language and key.
//
// When evaluation this message, the first Message in the sequence to msgs to
// evaluate to a string will be the message returned.
func (c *Builder) Set(tag language.Tag, key string, msg ...Message) error {
return c.set(tag, key, &c.index, msg...)
}
// SetMacro defines a Message that may be substituted in another message.
// The arguments to a macro Message are passed as arguments in the
// placeholder the form "${foo(arg1, arg2)}".
func (c *Builder) SetMacro(tag language.Tag, name string, msg ...Message) error {
return c.set(tag, name, &c.macros, msg...)
}
// ErrNotFound indicates there was no message for the given key.
var ErrNotFound = errors.New("catalog: message not found")
// String specifies a plain message string. It can be used as fallback if no
// other strings match or as a simple standalone message.
//
// It is an error to pass more than one String in a message sequence.
func String(name string) Message {
return catmsg.String(name)
}
// Var sets a variable that may be substituted in formatting patterns using
// named substitution of the form "${name}". The name argument is used as a
// fallback if the statements do not produce a match. The statement sequence may
// not contain any Var calls.
//
// The name passed to a Var must be unique within message sequence.
func Var(name string, msg ...Message) Message {
return &catmsg.Var{Name: name, Message: firstInSequence(msg)}
}
// Context returns a Context for formatting messages.
// Only one Message may be formatted per context at any given time.
func (b *Builder) Context(tag language.Tag, r catmsg.Renderer) *Context {
return &Context{
cat: b,
tag: tag,
dec: catmsg.NewDecoder(tag, r, &dict{&b.macros, tag}),
}
}
// A Context is used for evaluating Messages.
// Only one Message may be formatted per context at any given time.
type Context struct {
cat Catalog
tag language.Tag // TODO: use compact index.
dec *catmsg.Decoder
}
// Execute looks up and executes the message with the given key.
// It returns ErrNotFound if no message could be found in the index.
func (c *Context) Execute(key string) error {
data, ok := c.cat.lookup(c.tag, key)
if !ok {
return ErrNotFound
}
return c.dec.Execute(data)
}
// 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 catalog
import (
"sync"
"golang.org/x/text/internal"
"golang.org/x/text/internal/catmsg"
"golang.org/x/text/language"
)
// TODO:
// Dictionary returns a Dictionary that returns the first Message, using the
// given language tag, that matches:
// 1. the last one registered by one of the Set methods
// 2. returned by one of the Loaders
// 3. repeat from 1. using the parent language
// This approach allows messages to be underspecified.
// func (c *Catalog) Dictionary(tag language.Tag) (Dictionary, error) {
// // TODO: verify dictionary exists.
// return &dict{&c.index, tag}, nil
// }
type dict struct {
s *store
tag language.Tag // TODO: make compact tag.
}
func (d *dict) Lookup(key string) (data string, ok bool) {
return d.s.lookup(d.tag, key)
}
func (b *Builder) lookup(tag language.Tag, key string) (data string, ok bool) {
return b.index.lookup(tag, key)
}
func (c *Builder) set(tag language.Tag, key string, s *store, msg ...Message) error {
data, err := catmsg.Compile(tag, &dict{&c.macros, tag}, firstInSequence(msg))
s.mutex.Lock()
defer s.mutex.Unlock()
m := s.index[tag]
if m == nil {
m = msgMap{}
if s.index == nil {
s.index = map[language.Tag]msgMap{}
}
c.matcher = nil
s.index[tag] = m
}
m[key] = data
return err
}
func (c *Builder) Matcher() language.Matcher {
c.index.mutex.RLock()
m := c.matcher
c.index.mutex.RUnlock()
if m != nil {
return m
}
c.index.mutex.Lock()
if c.matcher == nil {
c.matcher = language.NewMatcher(c.unlockedLanguages())
}
m = c.matcher
c.index.mutex.Unlock()
return m
}
type store struct {
mutex sync.RWMutex
index map[language.Tag]msgMap
}
type msgMap map[string]string
func (s *store) lookup(tag language.Tag, key string) (data string, ok bool) {
s.mutex.RLock()
defer s.mutex.RUnlock()
for ; ; tag = tag.Parent() {
if msgs, ok := s.index[tag]; ok {
if msg, ok := msgs[key]; ok {
return msg, true
}
}
if tag == language.Und {
break
}
}
return "", false
}
// Languages returns all languages for which the Catalog contains variants.
func (b *Builder) Languages() []language.Tag {
s := &b.index
s.mutex.RLock()
defer s.mutex.RUnlock()
return b.unlockedLanguages()
}
func (b *Builder) unlockedLanguages() []language.Tag {
s := &b.index
if len(s.index) == 0 {
return nil
}
tags := make([]language.Tag, 0, len(s.index))
_, hasFallback := s.index[b.options.fallback]
offset := 0
if hasFallback {
tags = append(tags, b.options.fallback)
offset = 1
}
for t := range s.index {
if t != b.options.fallback {
tags = append(tags, t)
}
}
internal.SortTags(tags[offset:])
return tags
}
// 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.
package pipeline
import (
"bytes"
"errors"
"fmt"
"go/ast"
"go/constant"
"go/format"
"go/token"
"go/types"
"path/filepath"
"sort"
"strings"
"unicode"
"unicode/utf8"
fmtparser "golang.org/x/text/internal/format"
"golang.org/x/tools/go/callgraph"
"golang.org/x/tools/go/callgraph/cha"
"golang.org/x/tools/go/loader"
"golang.org/x/tools/go/ssa"
"golang.org/x/tools/go/ssa/ssautil"
)
const debug = false
// TODO:
// - merge information into existing files
// - handle different file formats (PO, XLIFF)
// - handle features (gender, plural)
// - message rewriting
// - `msg:"etc"` tags
// Extract extracts all strings form the package defined in Config.
func Extract(c *Config) (*State, error) {
x, err := newExtracter(c)
if err != nil {
return nil, wrap(err, "")
}
if err := x.seedEndpoints(); err != nil {
return nil, err
}
x.extractMessages()
return &State{
Config: *c,
program: x.iprog,
Extracted: Messages{
Language: c.SourceLanguage,
Messages: x.messages,
},
}, nil
}
type extracter struct {
conf loader.Config
iprog *loader.Program
prog *ssa.Program
callGraph *callgraph.Graph
// Calls and other expressions to collect.
globals map[token.Pos]*constData
funcs map[token.Pos]*callData
messages []Message
}
func newExtracter(c *Config) (x *extracter, err error) {
x = &extracter{
conf: loader.Config{},
globals: map[token.Pos]*constData{},
funcs: map[token.Pos]*callData{},
}
x.iprog, err = loadPackages(&x.conf, c.Packages)
if err != nil {
return nil, wrap(err, "")
}
x.prog = ssautil.CreateProgram(x.iprog, ssa.GlobalDebug|ssa.BareInits)
x.prog.Build()
x.callGraph = cha.CallGraph(x.prog)
return x, nil
}
func (x *extracter) globalData(pos token.Pos) *constData {
cd := x.globals[pos]
if cd == nil {
cd = &constData{}
x.globals[pos] = cd
}
return cd
}
func (x *extracter) seedEndpoints() error {
pkgInfo := x.iprog.Package("golang.org/x/text/message")
if pkgInfo == nil {
return errors.New("pipeline: golang.org/x/text/message is not imported")
}
pkg := x.prog.Package(pkgInfo.Pkg)
typ := types.NewPointer(pkg.Type("Printer").Type())
x.processGlobalVars()
x.handleFunc(x.prog.LookupMethod(typ, pkg.Pkg, "Printf"), &callData{
formatPos: 1,
argPos: 2,
isMethod: true,
})
x.handleFunc(x.prog.LookupMethod(typ, pkg.Pkg, "Sprintf"), &callData{
formatPos: 1,
argPos: 2,
isMethod: true,
})
x.handleFunc(x.prog.LookupMethod(typ, pkg.Pkg, "Fprintf"), &callData{
formatPos: 2,
argPos: 3,
isMethod: true,
})
return nil
}
// processGlobalVars finds string constants that are assigned to global
// variables.
func (x *extracter) processGlobalVars() {
for _, p := range x.prog.AllPackages() {
m, ok := p.Members["init"]
if !ok {
continue
}
for _, b := range m.(*ssa.Function).Blocks {
for _, i := range b.Instrs {
s, ok := i.(*ssa.Store)
if !ok {
continue
}
a, ok := s.Addr.(*ssa.Global)
if !ok {
continue
}
t := a.Type()
for {
p, ok := types.Unalias(t).(*types.Pointer)
if !ok {
break
}
t = p.Elem()
}
if b, ok := types.Unalias(t).(*types.Basic); !ok || b.Kind() != types.String {
continue
}
x.visitInit(a, s.Val)
}
}
}
}
type constData struct {
call *callData // to provide a signature for the constants
values []constVal
others []token.Pos // Assigned to other global data.
}
func (d *constData) visit(x *extracter, f func(c constant.Value)) {
for _, v := range d.values {
f(v.value)
}
for _, p := range d.others {
if od, ok := x.globals[p]; ok {
od.visit(x, f)
}
}
}
type constVal struct {
value constant.Value
pos token.Pos
}
type callData struct {
call ssa.CallInstruction
expr *ast.CallExpr
formats []constant.Value
callee *callData
isMethod bool
formatPos int
argPos int // varargs at this position in the call
argTypes []int // arguments extractable from this position
}
func (c *callData) callFormatPos() int {
c = c.callee
if c.isMethod {
return c.formatPos - 1
}
return c.formatPos
}
func (c *callData) callArgsStart() int {
c = c.callee
if c.isMethod {
return c.argPos - 1
}
return c.argPos
}
func (c *callData) Pos() token.Pos { return c.call.Pos() }
func (c *callData) Pkg() *types.Package { return c.call.Parent().Pkg.Pkg }
func (x *extracter) handleFunc(f *ssa.Function, fd *callData) {
for _, e := range x.callGraph.Nodes[f].In {
if e.Pos() == 0 {
continue
}
call := e.Site
caller := x.funcs[call.Pos()]
if caller != nil {
// TODO: theoretically a format string could be passed to multiple
// arguments of a function. Support this eventually.
continue
}
x.debug(call, "CALL", f.String())
caller = &callData{
call: call,
callee: fd,
formatPos: -1,
argPos: -1,
}
// Offset by one if we are invoking an interface method.
offset := 0
if call.Common().IsInvoke() {
offset = -1
}
x.funcs[call.Pos()] = caller
if fd.argPos >= 0 {
x.visitArgs(caller, call.Common().Args[fd.argPos+offset])
}
x.visitFormats(caller, call.Common().Args[fd.formatPos+offset])
}
}
type posser interface {
Pos() token.Pos
Parent() *ssa.Function
}
func (x *extracter) debug(v posser, header string, args ...interface{}) {
if debug {
pos := ""
if p := v.Parent(); p != nil {
pos = posString(&x.conf, p.Package().Pkg, v.Pos())
}
if header != "CALL" && header != "INSERT" {
header = " " + header
}
fmt.Printf("%-32s%-10s%-15T ", pos+fmt.Sprintf("@%d", v.Pos()), header, v)
for _, a := range args {
fmt.Printf(" %v", a)
}
fmt.Println()
}
}
// visitInit evaluates and collects values assigned to global variables in an
// init function.
func (x *extracter) visitInit(global *ssa.Global, v ssa.Value) {
if v == nil {
return
}
x.debug(v, "GLOBAL", v)
switch v := v.(type) {
case *ssa.Phi:
for _, e := range v.Edges {
x.visitInit(global, e)
}
case *ssa.Const:
// Only record strings with letters.
if str := constant.StringVal(v.Value); isMsg(str) {
cd := x.globalData(global.Pos())
cd.values = append(cd.values, constVal{v.Value, v.Pos()})
}
// TODO: handle %m-directive.
case *ssa.Global:
cd := x.globalData(global.Pos())
cd.others = append(cd.others, v.Pos())
case *ssa.FieldAddr, *ssa.Field:
// TODO: mark field index v.Field of v.X.Type() for extraction. extract
// an example args as to give parameters for the translator.
case *ssa.Slice:
if v.Low == nil && v.High == nil && v.Max == nil {
x.visitInit(global, v.X)
}
case *ssa.Alloc:
if ref := v.Referrers(); ref == nil {
for _, r := range *ref {
values := []ssa.Value{}
for _, o := range r.Operands(nil) {
if o == nil || *o == v {
continue
}
values = append(values, *o)
}
// TODO: return something different if we care about multiple
// values as well.
if len(values) == 1 {
x.visitInit(global, values[0])
}
}
}
case ssa.Instruction:
rands := v.Operands(nil)
if len(rands) == 1 && rands[0] != nil {
x.visitInit(global, *rands[0])
}
}
return
}
// visitFormats finds the original source of the value. The returned index is
// position of the argument if originated from a function argument or -1
// otherwise.
func (x *extracter) visitFormats(call *callData, v ssa.Value) {
if v == nil {
return
}
x.debug(v, "VALUE", v)
switch v := v.(type) {
case *ssa.Phi:
for _, e := range v.Edges {
x.visitFormats(call, e)
}
case *ssa.Const:
// Only record strings with letters.
if isMsg(constant.StringVal(v.Value)) {
x.debug(call.call, "FORMAT", v.Value.ExactString())
call.formats = append(call.formats, v.Value)
}
// TODO: handle %m-directive.
case *ssa.Global:
x.globalData(v.Pos()).call = call
case *ssa.FieldAddr, *ssa.Field:
// TODO: mark field index v.Field of v.X.Type() for extraction. extract
// an example args as to give parameters for the translator.
case *ssa.Slice:
if v.Low == nil && v.High == nil && v.Max == nil {
x.visitFormats(call, v.X)
}
case *ssa.Parameter:
// TODO: handle the function for the index parameter.
f := v.Parent()
for i, p := range f.Params {
if p == v {
if call.formatPos < 0 {
call.formatPos = i
// TODO: is there a better way to detect this is calling
// a method rather than a function?
call.isMethod = len(f.Params) > f.Signature.Params().Len()
x.handleFunc(v.Parent(), call)
} else if debug && i != call.formatPos {
// TODO: support this.
fmt.Printf("WARNING:%s: format string passed to arg %d and %d\n",
posString(&x.conf, call.Pkg(), call.Pos()),
call.formatPos, i)
}
}
}
case *ssa.Alloc:
if ref := v.Referrers(); ref == nil {
for _, r := range *ref {
values := []ssa.Value{}
for _, o := range r.Operands(nil) {
if o == nil || *o == v {
continue
}
values = append(values, *o)
}
// TODO: return something different if we care about multiple
// values as well.
if len(values) == 1 {
x.visitFormats(call, values[0])
}
}
}
// TODO:
// case *ssa.Index:
// // Get all values in the array if applicable
// case *ssa.IndexAddr:
// // Get all values in the slice or *array if applicable.
// case *ssa.Lookup:
// // Get all values in the map if applicable.
case *ssa.FreeVar:
// TODO: find the link between free variables and parameters:
//
// func freeVar(p *message.Printer, str string) {
// fn := func(p *message.Printer) {
// p.Printf(str)
// }
// fn(p)
// }
case *ssa.Call:
case ssa.Instruction:
rands := v.Operands(nil)
if len(rands) == 1 && rands[0] != nil {
x.visitFormats(call, *rands[0])
}
}
}
// Note: a function may have an argument marked as both format and passthrough.
// visitArgs collects information on arguments. For wrapped functions it will
// just determine the position of the variable args slice.
func (x *extracter) visitArgs(fd *callData, v ssa.Value) {
if v == nil {
return
}
x.debug(v, "ARGV", v)
switch v := v.(type) {
case *ssa.Slice:
if v.Low == nil && v.High == nil && v.Max == nil {
x.visitArgs(fd, v.X)
}
case *ssa.Parameter:
// TODO: handle the function for the index parameter.
f := v.Parent()
for i, p := range f.Params {
if p == v {
fd.argPos = i
}
}
case *ssa.Alloc:
if ref := v.Referrers(); ref == nil {
for _, r := range *ref {
values := []ssa.Value{}
for _, o := range r.Operands(nil) {
if o == nil || *o == v {
continue
}
values = append(values, *o)
}
// TODO: return something different if we care about
// multiple values as well.
if len(values) == 1 {
x.visitArgs(fd, values[0])
}
}
}
case ssa.Instruction:
rands := v.Operands(nil)
if len(rands) == 1 && rands[0] != nil {
x.visitArgs(fd, *rands[0])
}
}
}
// print returns Go syntax for the specified node.
func (x *extracter) print(n ast.Node) string {
var buf bytes.Buffer
format.Node(&buf, x.conf.Fset, n)
return buf.String()
}
type packageExtracter struct {
f *ast.File
x *extracter
info *loader.PackageInfo
cmap ast.CommentMap
}
func (px packageExtracter) getComment(n ast.Node) string {
cs := px.cmap.Filter(n).Comments()
if len(cs) > 0 {
return strings.TrimSpace(cs[0].Text())
}
return ""
}
func (x *extracter) extractMessages() {
prog := x.iprog
keys := make([]*types.Package, 0, len(x.iprog.AllPackages))
for k := range x.iprog.AllPackages {
keys = append(keys, k)
}
sort.Slice(keys, func(i, j int) bool { return keys[i].Path() < keys[j].Path() })
files := []packageExtracter{}
for _, k := range keys {
info := x.iprog.AllPackages[k]
for _, f := range info.Files {
// Associate comments with nodes.
px := packageExtracter{
f, x, info,
ast.NewCommentMap(prog.Fset, f, f.Comments),
}
files = append(files, px)
}
}
for _, px := range files {
ast.Inspect(px.f, func(n ast.Node) bool {
switch v := n.(type) {
case *ast.CallExpr:
if d := x.funcs[v.Lparen]; d != nil {
d.expr = v
}
}
return true
})
}
for _, px := range files {
ast.Inspect(px.f, func(n ast.Node) bool {
switch v := n.(type) {
case *ast.CallExpr:
return px.handleCall(v)
case *ast.ValueSpec:
return px.handleGlobal(v)
}
return true
})
}
}
func (px packageExtracter) handleGlobal(spec *ast.ValueSpec) bool {
comment := px.getComment(spec)
for _, ident := range spec.Names {
data, ok := px.x.globals[ident.Pos()]
if !ok {
continue
}
name := ident.Name
var arguments []argument
if data.call != nil {
arguments = px.getArguments(data.call)
} else if !strings.HasPrefix(name, "msg") && !strings.HasPrefix(name, "Msg") {
continue
}
data.visit(px.x, func(c constant.Value) {
px.addMessage(spec.Pos(), []string{name}, c, comment, arguments)
})
}
return true
}
func (px packageExtracter) handleCall(call *ast.CallExpr) bool {
x := px.x
data := x.funcs[call.Lparen]
if data == nil || len(data.formats) == 0 {
return true
}
if data.expr != call {
panic("invariant `data.call != call` failed")
}
x.debug(data.call, "INSERT", data.formats)
argn := data.callFormatPos()
if argn >= len(call.Args) {
return true
}
format := call.Args[argn]
arguments := px.getArguments(data)
comment := ""
key := []string{}
if ident, ok := format.(*ast.Ident); ok {
key = append(key, ident.Name)
// Ident.Obj may be nil if the referenced declaration is in another
// file.
if ident.Obj != nil {
if v, ok := ident.Obj.Decl.(*ast.ValueSpec); ok && v.Comment != nil {
// TODO: get comment above ValueSpec as well
comment = v.Comment.Text()
}
}
}
if c := px.getComment(call.Args[0]); c != "" {
comment = c
}
formats := data.formats
for _, c := range formats {
px.addMessage(call.Lparen, key, c, comment, arguments)
}
return true
}
func (px packageExtracter) getArguments(data *callData) []argument {
arguments := []argument{}
x := px.x
info := px.info
if data.callArgsStart() >= 0 {
args := data.expr.Args[data.callArgsStart():]
for i, arg := range args {
expr := x.print(arg)
val := ""
if v := info.Types[arg].Value; v != nil {
val = v.ExactString()
switch arg.(type) {
case *ast.BinaryExpr, *ast.UnaryExpr:
expr = val
}
}
arguments = append(arguments, argument{
ArgNum: i + 1,
Type: info.Types[arg].Type.String(),
UnderlyingType: info.Types[arg].Type.Underlying().String(),
Expr: expr,
Value: val,
Comment: px.getComment(arg),
Position: posString(&x.conf, info.Pkg, arg.Pos()),
// TODO report whether it implements
// interfaces plural.Interface,
// gender.Interface.
})
}
}
return arguments
}
func (px packageExtracter) addMessage(
pos token.Pos,
key []string,
c constant.Value,
comment string,
arguments []argument) {
x := px.x
fmtMsg := constant.StringVal(c)
ph := placeholders{index: map[string]string{}}
trimmed, _, _ := trimWS(fmtMsg)
p := fmtparser.Parser{}
simArgs := make([]interface{}, len(arguments))
for i, v := range arguments {
simArgs[i] = v
}
msg := ""
p.Reset(simArgs)
for p.SetFormat(trimmed); p.Scan(); {
name := ""
var arg *argument
switch p.Status {
case fmtparser.StatusText:
msg += p.Text()
continue
case fmtparser.StatusSubstitution,
fmtparser.StatusBadWidthSubstitution,
fmtparser.StatusBadPrecSubstitution:
arguments[p.ArgNum-1].used = true
arg = &arguments[p.ArgNum-1]
name = getID(arg)
case fmtparser.StatusBadArgNum, fmtparser.StatusMissingArg:
arg = &argument{
ArgNum: p.ArgNum,
Position: posString(&x.conf, px.info.Pkg, pos),
}
name, arg.UnderlyingType = verbToPlaceholder(p.Text(), p.ArgNum)
}
sub := p.Text()
if !p.HasIndex {
r, sz := utf8.DecodeLastRuneInString(sub)
sub = fmt.Sprintf("%s[%d]%c", sub[:len(sub)-sz], p.ArgNum, r)
}
msg += fmt.Sprintf("{%s}", ph.addArg(arg, name, sub))
}
key = append(key, msg)
// Add additional Placeholders that can be used in translations
// that are not present in the string.
for _, arg := range arguments {
if arg.used {
continue
}
ph.addArg(&arg, getID(&arg), fmt.Sprintf("%%[%d]v", arg.ArgNum))
}
x.messages = append(x.messages, Message{
ID: key,
Key: fmtMsg,
Message: Text{Msg: msg},
// TODO(fix): this doesn't get the before comment.
Comment: comment,
Placeholders: ph.slice,
Position: posString(&x.conf, px.info.Pkg, pos),
})
}
func posString(conf *loader.Config, pkg *types.Package, pos token.Pos) string {
p := conf.Fset.Position(pos)
file := fmt.Sprintf("%s:%d:%d", filepath.Base(p.Filename), p.Line, p.Column)
return filepath.Join(pkg.Path(), file)
}
func getID(arg *argument) string {
s := getLastComponent(arg.Expr)
s = strip(s)
s = strings.Replace(s, " ", "", -1)
// For small variable names, use user-defined types for more info.
if len(s) <= 2 && arg.UnderlyingType != arg.Type {
s = getLastComponent(arg.Type)
}
return strings.Title(s)
}
// strip is a dirty hack to convert function calls to placeholder IDs.
func strip(s string) string {
s = strings.Map(func(r rune) rune {
if unicode.IsSpace(r) || r == '-' {
return '_'
}
if !unicode.In(r, unicode.Letter, unicode.Mark, unicode.Number) {
return -1
}
return r
}, s)
// Strip "Get" from getter functions.
if strings.HasPrefix(s, "Get") || strings.HasPrefix(s, "get") {
if len(s) > len("get") {
r, _ := utf8.DecodeRuneInString(s)
if !unicode.In(r, unicode.Ll, unicode.M) { // not lower or mark
s = s[len("get"):]
}
}
}
return s
}
// verbToPlaceholder gives a name for a placeholder based on the substitution
// verb. This is only to be used if there is otherwise no other type information
// available.
func verbToPlaceholder(sub string, pos int) (name, underlying string) {
r, _ := utf8.DecodeLastRuneInString(sub)
name = fmt.Sprintf("Arg_%d", pos)
switch r {
case 's', 'q':
underlying = "string"
case 'd':
name = "Integer"
underlying = "int"
case 'e', 'f', 'g':
name = "Number"
underlying = "float64"
case 'm':
name = "Message"
underlying = "string"
default:
underlying = "interface{}"
}
return name, underlying
}
type placeholders struct {
index map[string]string
slice []Placeholder
}
func (p *placeholders) addArg(arg *argument, name, sub string) (id string) {
id = name
alt, ok := p.index[id]
for i := 1; ok && alt != sub; i++ {
id = fmt.Sprintf("%s_%d", name, i)
alt, ok = p.index[id]
}
p.index[id] = sub
p.slice = append(p.slice, Placeholder{
ID: id,
String: sub,
Type: arg.Type,
UnderlyingType: arg.UnderlyingType,
ArgNum: arg.ArgNum,
Expr: arg.Expr,
Comment: arg.Comment,
})
return id
}
func getLastComponent(s string) string {
return s[1+strings.LastIndexByte(s, '.'):]
}
// isMsg returns whether s should be translated.
func isMsg(s string) bool {
// TODO: parse as format string and omit strings that contain letters
// coming from format verbs.
for _, r := range s {
if unicode.In(r, unicode.L) {
return true
}
}
return false
}
// 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 pipeline
import (
"fmt"
"go/build"
"io"
"os"
"path/filepath"
"regexp"
"sort"
"strings"
"text/template"
"golang.org/x/text/collate"
"golang.org/x/text/feature/plural"
"golang.org/x/text/internal"
"golang.org/x/text/internal/catmsg"
"golang.org/x/text/internal/gen"
"golang.org/x/text/language"
"golang.org/x/tools/go/loader"
)
var transRe = regexp.MustCompile(`messages\.(.*)\.json`)
// Generate writes a Go file that defines a Catalog with translated messages.
// Translations are retrieved from s.Messages, not s.Translations, so it
// is assumed Merge has been called.
func (s *State) Generate() error {
path := s.Config.GenPackage
if path == "" {
path = "."
}
isDir := path[0] == '.'
prog, err := loadPackages(&loader.Config{}, []string{path})
if err != nil {
return wrap(err, "could not load package")
}
pkgs := prog.InitialPackages()
if len(pkgs) != 1 {
return errorf("more than one package selected: %v", pkgs)
}
pkg := pkgs[0].Pkg.Name()
cw, err := s.generate()
if err != nil {
return err
}
if !isDir {
gopath := filepath.SplitList(build.Default.GOPATH)[0]
path = filepath.Join(gopath, "src", filepath.FromSlash(pkgs[0].Pkg.Path()))
}
if len(s.Config.GenFile) == 0 {
cw.WriteGo(os.Stdout, pkg, "")
return nil
}
if filepath.IsAbs(s.Config.GenFile) {
path = s.Config.GenFile
} else {
path = filepath.Join(path, s.Config.GenFile)
}
cw.WriteGoFile(path, pkg) // TODO: WriteGoFile should return error.
return err
}
// WriteGen writes a Go file with the given package name to w that defines a
// Catalog with translated messages. Translations are retrieved from s.Messages,
// not s.Translations, so it is assumed Merge has been called.
func (s *State) WriteGen(w io.Writer, pkg string) error {
cw, err := s.generate()
if err != nil {
return err
}
_, err = cw.WriteGo(w, pkg, "")
return err
}
// Generate is deprecated; use (*State).Generate().
func Generate(w io.Writer, pkg string, extracted *Messages, trans ...Messages) (n int, err error) {
s := State{
Extracted: *extracted,
Translations: trans,
}
cw, err := s.generate()
if err != nil {
return 0, err
}
return cw.WriteGo(w, pkg, "")
}
func (s *State) generate() (*gen.CodeWriter, error) {
// Build up index of translations and original messages.
translations := map[language.Tag]map[string]Message{}
languages := []language.Tag{}
usedKeys := map[string]int{}
for _, loc := range s.Messages {
tag := loc.Language
if _, ok := translations[tag]; !ok {
translations[tag] = map[string]Message{}
languages = append(languages, tag)
}
for _, m := range loc.Messages {
if !m.Translation.IsEmpty() {
for _, id := range m.ID {
if _, ok := translations[tag][id]; ok {
warnf("Duplicate translation in locale %q for message %q", tag, id)
}
translations[tag][id] = m
}
}
}
}
// Verify completeness and register keys.
internal.SortTags(languages)
langVars := []string{}
for _, tag := range languages {
langVars = append(langVars, strings.Replace(tag.String(), "-", "_", -1))
dict := translations[tag]
for _, msg := range s.Extracted.Messages {
for _, id := range msg.ID {
if trans, ok := dict[id]; ok && !trans.Translation.IsEmpty() {
if _, ok := usedKeys[msg.Key]; !ok {
usedKeys[msg.Key] = len(usedKeys)
}
break
}
// TODO: log missing entry.
warnf("%s: Missing entry for %q.", tag, id)
}
}
}
cw := gen.NewCodeWriter()
x := &struct {
Fallback language.Tag
Languages []string
}{
Fallback: s.Extracted.Language,
Languages: langVars,
}
if err := lookup.Execute(cw, x); err != nil {
return nil, wrap(err, "error")
}
keyToIndex := []string{}
for k := range usedKeys {
keyToIndex = append(keyToIndex, k)
}
sort.Strings(keyToIndex)
fmt.Fprint(cw, "var messageKeyToIndex = map[string]int{\n")
for _, k := range keyToIndex {
fmt.Fprintf(cw, "%q: %d,\n", k, usedKeys[k])
}
fmt.Fprint(cw, "}\n\n")
for i, tag := range languages {
dict := translations[tag]
a := make([]string, len(usedKeys))
for _, msg := range s.Extracted.Messages {
for _, id := range msg.ID {
if trans, ok := dict[id]; ok && !trans.Translation.IsEmpty() {
m, err := assemble(&msg, &trans.Translation)
if err != nil {
return nil, wrap(err, "error")
}
_, leadWS, trailWS := trimWS(msg.Key)
if leadWS != "" || trailWS != "" {
m = catmsg.Affix{
Message: m,
Prefix: leadWS,
Suffix: trailWS,
}
}
// TODO: support macros.
data, err := catmsg.Compile(tag, nil, m)
if err != nil {
return nil, wrap(err, "error")
}
key := usedKeys[msg.Key]
if d := a[key]; d != "" && d != data {
warnf("Duplicate non-consistent translation for key %q, picking the one for message %q", msg.Key, id)
}
a[key] = string(data)
break
}
}
}
index := []uint32{0}
p := 0
for _, s := range a {
p += len(s)
index = append(index, uint32(p))
}
cw.WriteVar(langVars[i]+"Index", index)
cw.WriteConst(langVars[i]+"Data", strings.Join(a, ""))
}
return cw, nil
}
func assemble(m *Message, t *Text) (msg catmsg.Message, err error) {
keys := []string{}
for k := range t.Var {
keys = append(keys, k)
}
sort.Strings(keys)
var a []catmsg.Message
for _, k := range keys {
t := t.Var[k]
m, err := assemble(m, &t)
if err != nil {
return nil, err
}
a = append(a, &catmsg.Var{Name: k, Message: m})
}
if t.Select != nil {
s, err := assembleSelect(m, t.Select)
if err != nil {
return nil, err
}
a = append(a, s)
}
if t.Msg != "" {
sub, err := m.Substitute(t.Msg)
if err != nil {
return nil, err
}
a = append(a, catmsg.String(sub))
}
switch len(a) {
case 0:
return nil, errorf("generate: empty message")
case 1:
return a[0], nil
default:
return catmsg.FirstOf(a), nil
}
}
func assembleSelect(m *Message, s *Select) (msg catmsg.Message, err error) {
cases := []string{}
for c := range s.Cases {
cases = append(cases, c)
}
sortCases(cases)
caseMsg := []interface{}{}
for _, c := range cases {
cm := s.Cases[c]
m, err := assemble(m, &cm)
if err != nil {
return nil, err
}
caseMsg = append(caseMsg, c, m)
}
ph := m.Placeholder(s.Arg)
switch s.Feature {
case "plural":
// TODO: only printf-style selects are supported as of yet.
return plural.Selectf(ph.ArgNum, ph.String, caseMsg...), nil
}
return nil, errorf("unknown feature type %q", s.Feature)
}
func sortCases(cases []string) {
// TODO: implement full interface.
sort.Slice(cases, func(i, j int) bool {
switch {
case cases[i] != "other" && cases[j] == "other":
return true
case cases[i] == "other" && cases[j] != "other":
return false
}
// the following code relies on '<' < '=' < any letter.
return cmpNumeric(cases[i], cases[j]) == -1
})
}
var cmpNumeric = collate.New(language.Und, collate.Numeric).CompareString
var lookup = template.Must(template.New("gen").Parse(`
import (
"golang.org/x/text/language"
"golang.org/x/text/message"
"golang.org/x/text/message/catalog"
)
type dictionary struct {
index []uint32
data string
}
func (d *dictionary) Lookup(key string) (data string, ok bool) {
p, ok := messageKeyToIndex[key]
if !ok {
return "", false
}
start, end := d.index[p], d.index[p+1]
if start == end {
return "", false
}
return d.data[start:end], true
}
func init() {
dict := map[string]catalog.Dictionary{
{{range .Languages}}"{{.}}": &dictionary{index: {{.}}Index, data: {{.}}Data },
{{end}}
}
fallback := language.MustParse("{{.Fallback}}")
cat, err := catalog.NewFromMap(dict, catalog.Fallback(fallback))
if err != nil {
panic(err)
}
message.DefaultCatalog = cat
}
`))
// 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 pipeline
import (
"encoding/json"
"errors"
"strings"
"golang.org/x/text/language"
)
// TODO: these definitions should be moved to a package so that the can be used
// by other tools.
// The file contains the structures used to define translations of a certain
// messages.
//
// A translation may have multiple translations strings, or messages, depending
// on the feature values of the various arguments. For instance, consider
// a hypothetical translation from English to English, where the source defines
// the format string "%d file(s) remaining".
// See the examples directory for examples of extracted messages.
// Messages is used to store translations for a single language.
type Messages struct {
Language language.Tag `json:"language"`
Messages []Message `json:"messages"`
Macros map[string]Text `json:"macros,omitempty"`
}
// A Message describes a message to be translated.
type Message struct {
// ID contains a list of identifiers for the message.
ID IDList `json:"id"`
// Key is the string that is used to look up the message at runtime.
Key string `json:"key,omitempty"`
Meaning string `json:"meaning,omitempty"`
Message Text `json:"message"`
Translation Text `json:"translation"`
Comment string `json:"comment,omitempty"`
TranslatorComment string `json:"translatorComment,omitempty"`
Placeholders []Placeholder `json:"placeholders,omitempty"`
// Fuzzy indicates that the provide translation needs review by a
// translator, for instance because it was derived from automated
// translation.
Fuzzy bool `json:"fuzzy,omitempty"`
// TODO: default placeholder syntax is {foo}. Allow alternative escaping
// like `foo`.
// Extraction information.
Position string `json:"position,omitempty"` // filePosition:line
}
// Placeholder reports the placeholder for the given ID if it is defined or nil
// otherwise.
func (m *Message) Placeholder(id string) *Placeholder {
for _, p := range m.Placeholders {
if p.ID == id {
return &p
}
}
return nil
}
// Substitute replaces placeholders in msg with their original value.
func (m *Message) Substitute(msg string) (sub string, err error) {
last := 0
for i := 0; i < len(msg); {
pLeft := strings.IndexByte(msg[i:], '{')
if pLeft == -1 {
break
}
pLeft += i
pRight := strings.IndexByte(msg[pLeft:], '}')
if pRight == -1 {
return "", errorf("unmatched '}'")
}
pRight += pLeft
id := strings.TrimSpace(msg[pLeft+1 : pRight])
i = pRight + 1
if id != "" && id[0] == '$' {
continue
}
sub += msg[last:pLeft]
last = i
ph := m.Placeholder(id)
if ph == nil {
return "", errorf("unknown placeholder %q in message %q", id, msg)
}
sub += ph.String
}
sub += msg[last:]
return sub, err
}
var errIncompatibleMessage = errors.New("messages incompatible")
func checkEquivalence(a, b *Message) error {
for _, v := range a.ID {
for _, w := range b.ID {
if v == w {
return nil
}
}
}
// TODO: canonicalize placeholders and check for type equivalence.
return errIncompatibleMessage
}
// A Placeholder is a part of the message that should not be changed by a
// translator. It can be used to hide or prettify format strings (e.g. %d or
// {{.Count}}), hide HTML, or mark common names that should not be translated.
type Placeholder struct {
// ID is the placeholder identifier without the curly braces.
ID string `json:"id"`
// String is the string with which to replace the placeholder. This may be a
// formatting string (for instance "%d" or "{{.Count}}") or a literal string
// (<div>).
String string `json:"string"`
Type string `json:"type"`
UnderlyingType string `json:"underlyingType"`
// ArgNum and Expr are set if the placeholder is a substitution of an
// argument.
ArgNum int `json:"argNum,omitempty"`
Expr string `json:"expr,omitempty"`
Comment string `json:"comment,omitempty"`
Example string `json:"example,omitempty"`
// Features contains the features that are available for the implementation
// of this argument.
Features []Feature `json:"features,omitempty"`
}
// An argument contains information about the arguments passed to a message.
type argument struct {
// ArgNum corresponds to the number that should be used for explicit argument indexes (e.g.
// "%[1]d").
ArgNum int `json:"argNum,omitempty"`
used bool // Used by Placeholder
Type string `json:"type"`
UnderlyingType string `json:"underlyingType"`
Expr string `json:"expr"`
Value string `json:"value,omitempty"`
Comment string `json:"comment,omitempty"`
Position string `json:"position,omitempty"`
}
// Feature holds information about a feature that can be implemented by
// an Argument.
type Feature struct {
Type string `json:"type"` // Right now this is only gender and plural.
// TODO: possible values and examples for the language under consideration.
}
// Text defines a message to be displayed.
type Text struct {
// Msg and Select contains the message to be displayed. Msg may be used as
// a fallback value if none of the select cases match.
Msg string `json:"msg,omitempty"`
Select *Select `json:"select,omitempty"`
// Var defines a map of variables that may be substituted in the selected
// message.
Var map[string]Text `json:"var,omitempty"`
// Example contains an example message formatted with default values.
Example string `json:"example,omitempty"`
}
// IsEmpty reports whether this Text can generate anything.
func (t *Text) IsEmpty() bool {
return t.Msg == "" && t.Select == nil && t.Var == nil
}
// rawText erases the UnmarshalJSON method.
type rawText Text
// UnmarshalJSON implements json.Unmarshaler.
func (t *Text) UnmarshalJSON(b []byte) error {
if b[0] == '"' {
return json.Unmarshal(b, &t.Msg)
}
return json.Unmarshal(b, (*rawText)(t))
}
// MarshalJSON implements json.Marshaler.
func (t *Text) MarshalJSON() ([]byte, error) {
if t.Select == nil && t.Var == nil && t.Example == "" {
return json.Marshal(t.Msg)
}
return json.Marshal((*rawText)(t))
}
// IDList is a set identifiers that each may refer to possibly different
// versions of the same message. When looking up a messages, the first
// identifier in the list takes precedence.
type IDList []string
// UnmarshalJSON implements json.Unmarshaler.
func (id *IDList) UnmarshalJSON(b []byte) error {
if b[0] == '"' {
*id = []string{""}
return json.Unmarshal(b, &((*id)[0]))
}
return json.Unmarshal(b, (*[]string)(id))
}
// MarshalJSON implements json.Marshaler.
func (id *IDList) MarshalJSON() ([]byte, error) {
if len(*id) == 1 {
return json.Marshal((*id)[0])
}
return json.Marshal((*[]string)(id))
}
// Select selects a Text based on the feature value associated with a feature of
// a certain argument.
type Select struct {
Feature string `json:"feature"` // Name of Feature type (e.g plural)
Arg string `json:"arg"` // The placeholder ID
Cases map[string]Text `json:"cases"`
}
// TODO: order matters, but can we derive the ordering from the case keys?
// type Case struct {
// Key string `json:"key"`
// Value Text `json:"value"`
// }
// 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 pipeline provides tools for creating translation pipelines.
//
// NOTE: UNDER DEVELOPMENT. API MAY CHANGE.
package pipeline
import (
"bytes"
"encoding/json"
"fmt"
"go/build"
"go/parser"
"io/ioutil"
"log"
"os"
"path/filepath"
"regexp"
"strings"
"text/template"
"unicode"
"golang.org/x/text/internal"
"golang.org/x/text/language"
"golang.org/x/text/runes"
"golang.org/x/tools/go/loader"
)
const (
extractFile = "extracted.gotext.json"
outFile = "out.gotext.json"
gotextSuffix = "gotext.json"
)
// Config contains configuration for the translation pipeline.
type Config struct {
// Supported indicates the languages for which data should be generated.
// The default is to support all locales for which there are matching
// translation files.
Supported []language.Tag
// --- Extraction
SourceLanguage language.Tag
Packages []string
// --- File structure
// Dir is the root dir for all operations.
Dir string
// TranslationsPattern is a regular expression to match incoming translation
// files. These files may appear in any directory rooted at Dir.
// language for the translation files is determined as follows:
// 1. From the Language field in the file.
// 2. If not present, from a valid language tag in the filename, separated
// by dots (e.g. "en-US.json" or "incoming.pt_PT.xmb").
// 3. If not present, from the closest subdirectory in which the file
// is contained that parses as a valid language tag.
TranslationsPattern string
// OutPattern defines the location for translation files for a certain
// language. The default is "{{.Dir}}/{{.Language}}/out.{{.Ext}}"
OutPattern string
// Format defines the file format for generated translation files.
// The default is XMB. Alternatives are GetText, XLIFF, L20n, GoText.
Format string
Ext string
// TODO:
// Actions are additional actions to be performed after the initial extract
// and merge.
// Actions []struct {
// Name string
// Options map[string]string
// }
// --- Generation
// GenFile may be in a different package. It is not defined, it will
// be written to stdout.
GenFile string
// GenPackage is the package or relative path into which to generate the
// file. If not specified it is relative to the current directory.
GenPackage string
// DeclareVar defines a variable to which to assign the generated Catalog.
DeclareVar string
// SetDefault determines whether to assign the generated Catalog to
// message.DefaultCatalog. The default for this is true if DeclareVar is
// not defined, false otherwise.
SetDefault bool
// TODO:
// - Printf-style configuration
// - Template-style configuration
// - Extraction options
// - Rewrite options
// - Generation options
}
// Operations:
// - extract: get the strings
// - disambiguate: find messages with the same key, but possible different meaning.
// - create out: create a list of messages that need translations
// - load trans: load the list of current translations
// - merge: assign list of translations as done
// - (action)expand: analyze features and create example sentences for each version.
// - (action)googletrans: pre-populate messages with automatic translations.
// - (action)export: send out messages somewhere non-standard
// - (action)import: load messages from somewhere non-standard
// - vet program: don't pass "foo" + var + "bar" strings. Not using funcs for translated strings.
// - vet trans: coverage: all translations/ all features.
// - generate: generate Go code
// State holds all accumulated information on translations during processing.
type State struct {
Config Config
Package string
program *loader.Program
Extracted Messages `json:"messages"`
// Messages includes all messages for which there need to be translations.
// Duplicates may be eliminated. Generation will be done from these messages
// (usually after merging).
Messages []Messages
// Translations are incoming translations for the application messages.
Translations []Messages
}
func (s *State) dir() string {
if d := s.Config.Dir; d != "" {
return d
}
return "./locales"
}
func outPattern(s *State) (string, error) {
c := s.Config
pat := c.OutPattern
if pat == "" {
pat = "{{.Dir}}/{{.Language}}/out.{{.Ext}}"
}
ext := c.Ext
if ext == "" {
ext = c.Format
}
if ext == "" {
ext = gotextSuffix
}
t, err := template.New("").Parse(pat)
if err != nil {
return "", wrap(err, "error parsing template")
}
buf := bytes.Buffer{}
err = t.Execute(&buf, map[string]string{
"Dir": s.dir(),
"Language": "%s",
"Ext": ext,
})
return filepath.FromSlash(buf.String()), wrap(err, "incorrect OutPattern")
}
var transRE = regexp.MustCompile(`.*\.` + gotextSuffix)
// Import loads existing translation files.
func (s *State) Import() error {
outPattern, err := outPattern(s)
if err != nil {
return err
}
re := transRE
if pat := s.Config.TranslationsPattern; pat != "" {
if re, err = regexp.Compile(pat); err != nil {
return wrapf(err, "error parsing regexp %q", s.Config.TranslationsPattern)
}
}
x := importer{s, outPattern, re}
return x.walkImport(s.dir(), s.Config.SourceLanguage)
}
type importer struct {
state *State
outPattern string
transFile *regexp.Regexp
}
func (i *importer) walkImport(path string, tag language.Tag) error {
files, err := ioutil.ReadDir(path)
if err != nil {
return nil
}
for _, f := range files {
name := f.Name()
tag := tag
if f.IsDir() {
if t, err := language.Parse(name); err == nil {
tag = t
}
// We ignore errors
if err := i.walkImport(filepath.Join(path, name), tag); err != nil {
return err
}
continue
}
for _, l := range strings.Split(name, ".") {
if t, err := language.Parse(l); err == nil {
tag = t
}
}
file := filepath.Join(path, name)
// TODO: Should we skip files that match output files?
if fmt.Sprintf(i.outPattern, tag) == file {
continue
}
// TODO: handle different file formats.
if !i.transFile.MatchString(name) {
continue
}
b, err := ioutil.ReadFile(file)
if err != nil {
return wrap(err, "read file failed")
}
var translations Messages
if err := json.Unmarshal(b, &translations); err != nil {
return wrap(err, "parsing translation file failed")
}
i.state.Translations = append(i.state.Translations, translations)
}
return nil
}
// Merge merges the extracted messages with the existing translations.
func (s *State) Merge() error {
if s.Messages != nil {
panic("already merged")
}
// Create an index for each unique message.
// Duplicates are okay as long as the substitution arguments are okay as
// well.
// Top-level messages are okay to appear in multiple substitution points.
// Collect key equivalence.
msgs := []*Message{}
keyToIDs := map[string]*Message{}
for _, m := range s.Extracted.Messages {
m := m
if prev, ok := keyToIDs[m.Key]; ok {
if err := checkEquivalence(&m, prev); err != nil {
warnf("Key %q matches conflicting messages: %v and %v", m.Key, prev.ID, m.ID)
// TODO: track enough information so that the rewriter can
// suggest/disambiguate messages.
}
// TODO: add position to message.
continue
}
i := len(msgs)
msgs = append(msgs, &m)
keyToIDs[m.Key] = msgs[i]
}
// Messages with different keys may still refer to the same translated
// message (e.g. different whitespace). Filter these.
idMap := map[string]bool{}
filtered := []*Message{}
for _, m := range msgs {
found := false
for _, id := range m.ID {
found = found || idMap[id]
}
if !found {
filtered = append(filtered, m)
}
for _, id := range m.ID {
idMap[id] = true
}
}
// Build index of translations.
translations := map[language.Tag]map[string]Message{}
languages := append([]language.Tag{}, s.Config.Supported...)
for _, t := range s.Translations {
tag := t.Language
if _, ok := translations[tag]; !ok {
translations[tag] = map[string]Message{}
languages = append(languages, tag)
}
for _, m := range t.Messages {
if !m.Translation.IsEmpty() {
for _, id := range m.ID {
if _, ok := translations[tag][id]; ok {
warnf("Duplicate translation in locale %q for message %q", tag, id)
}
translations[tag][id] = m
}
}
}
}
languages = internal.UniqueTags(languages)
for _, tag := range languages {
ms := Messages{Language: tag}
for _, orig := range filtered {
m := *orig
m.Key = ""
m.Position = ""
for _, id := range m.ID {
if t, ok := translations[tag][id]; ok {
m.Translation = t.Translation
if t.TranslatorComment != "" {
m.TranslatorComment = t.TranslatorComment
m.Fuzzy = t.Fuzzy
}
break
}
}
if tag == s.Config.SourceLanguage && m.Translation.IsEmpty() {
m.Translation = m.Message
if m.TranslatorComment == "" {
m.TranslatorComment = "Copied from source."
m.Fuzzy = true
}
}
// TODO: if translation is empty: pre-expand based on available
// linguistic features. This may also be done as a plugin.
ms.Messages = append(ms.Messages, m)
}
s.Messages = append(s.Messages, ms)
}
return nil
}
// Export writes out the messages to translation out files.
func (s *State) Export() error {
path, err := outPattern(s)
if err != nil {
return wrap(err, "export failed")
}
for _, out := range s.Messages {
// TODO: inject translations from existing files to avoid retranslation.
data, err := json.MarshalIndent(out, "", " ")
if err != nil {
return wrap(err, "JSON marshal failed")
}
file := fmt.Sprintf(path, out.Language)
if err := os.MkdirAll(filepath.Dir(file), 0755); err != nil {
return wrap(err, "dir create failed")
}
if err := ioutil.WriteFile(file, data, 0644); err != nil {
return wrap(err, "write failed")
}
}
return nil
}
var (
ws = runes.In(unicode.White_Space).Contains
notWS = runes.NotIn(unicode.White_Space).Contains
)
func trimWS(s string) (trimmed, leadWS, trailWS string) {
trimmed = strings.TrimRightFunc(s, ws)
trailWS = s[len(trimmed):]
if i := strings.IndexFunc(trimmed, notWS); i > 0 {
leadWS = trimmed[:i]
trimmed = trimmed[i:]
}
return trimmed, leadWS, trailWS
}
// NOTE: The command line tool already prefixes with "gotext:".
var (
wrap = func(err error, msg string) error {
if err == nil {
return nil
}
return fmt.Errorf("%s: %v", msg, err)
}
wrapf = func(err error, msg string, args ...interface{}) error {
if err == nil {
return nil
}
return wrap(err, fmt.Sprintf(msg, args...))
}
errorf = fmt.Errorf
)
func warnf(format string, args ...interface{}) {
// TODO: don't log.
log.Printf(format, args...)
}
func loadPackages(conf *loader.Config, args []string) (*loader.Program, error) {
if len(args) == 0 {
args = []string{"."}
}
conf.Build = &build.Default
conf.ParserMode = parser.ParseComments
// Use the initial packages from the command line.
args, err := conf.FromArgs(args, false)
if err != nil {
return nil, wrap(err, "loading packages failed")
}
// Load, parse and type-check the whole program.
return conf.Load()
}
// 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 pipeline
import (
"bytes"
"fmt"
"go/ast"
"go/constant"
"go/format"
"go/token"
"io"
"os"
"strings"
"golang.org/x/tools/go/loader"
)
const printerType = "golang.org/x/text/message.Printer"
// Rewrite rewrites the Go files in a single package to use the localization
// machinery and rewrites strings to adopt best practices when possible.
// If w is not nil the generated files are written to it, each files with a
// "--- <filename>" header. Otherwise the files are overwritten.
func Rewrite(w io.Writer, args ...string) error {
conf := &loader.Config{
AllowErrors: true, // Allow unused instances of message.Printer.
}
prog, err := loadPackages(conf, args)
if err != nil {
return wrap(err, "")
}
for _, info := range prog.InitialPackages() {
for _, f := range info.Files {
// Associate comments with nodes.
// Pick up initialized Printers at the package level.
r := rewriter{info: info, conf: conf}
for _, n := range info.InitOrder {
if t := r.info.Types[n.Rhs].Type.String(); strings.HasSuffix(t, printerType) {
r.printerVar = n.Lhs[0].Name()
}
}
ast.Walk(&r, f)
w := w
if w == nil {
var err error
if w, err = os.Create(conf.Fset.File(f.Pos()).Name()); err != nil {
return wrap(err, "open failed")
}
} else {
fmt.Fprintln(w, "---", conf.Fset.File(f.Pos()).Name())
}
if err := format.Node(w, conf.Fset, f); err != nil {
return wrap(err, "go format failed")
}
}
}
return nil
}
type rewriter struct {
info *loader.PackageInfo
conf *loader.Config
printerVar string
}
// print returns Go syntax for the specified node.
func (r *rewriter) print(n ast.Node) string {
var buf bytes.Buffer
format.Node(&buf, r.conf.Fset, n)
return buf.String()
}
func (r *rewriter) Visit(n ast.Node) ast.Visitor {
// Save the state by scope.
if _, ok := n.(*ast.BlockStmt); ok {
r := *r
return &r
}
// Find Printers created by assignment.
stmt, ok := n.(*ast.AssignStmt)
if ok {
for _, v := range stmt.Lhs {
if r.printerVar == r.print(v) {
r.printerVar = ""
}
}
for i, v := range stmt.Rhs {
if t := r.info.Types[v].Type.String(); strings.HasSuffix(t, printerType) {
r.printerVar = r.print(stmt.Lhs[i])
return r
}
}
}
// Find Printers created by variable declaration.
spec, ok := n.(*ast.ValueSpec)
if ok {
for _, v := range spec.Names {
if r.printerVar == r.print(v) {
r.printerVar = ""
}
}
for i, v := range spec.Values {
if t := r.info.Types[v].Type.String(); strings.HasSuffix(t, printerType) {
r.printerVar = r.print(spec.Names[i])
return r
}
}
}
if r.printerVar == "" {
return r
}
call, ok := n.(*ast.CallExpr)
if !ok {
return r
}
// TODO: Handle literal values?
sel, ok := call.Fun.(*ast.SelectorExpr)
if !ok {
return r
}
meth := r.info.Selections[sel]
source := r.print(sel.X)
fun := r.print(sel.Sel)
if meth != nil {
source = meth.Recv().String()
fun = meth.Obj().Name()
}
// TODO: remove cheap hack and check if the type either
// implements some interface or is specifically of type
// "golang.org/x/text/message".Printer.
m, ok := rewriteFuncs[source]
if !ok {
return r
}
rewriteType, ok := m[fun]
if !ok {
return r
}
ident := ast.NewIdent(r.printerVar)
ident.NamePos = sel.X.Pos()
sel.X = ident
if rewriteType.method != "" {
sel.Sel.Name = rewriteType.method
}
// Analyze arguments.
argn := rewriteType.arg
if rewriteType.format || argn >= len(call.Args) {
return r
}
hasConst := false
for _, a := range call.Args[argn:] {
if v := r.info.Types[a].Value; v != nil && v.Kind() == constant.String {
hasConst = true
break
}
}
if !hasConst {
return r
}
sel.Sel.Name = rewriteType.methodf
// We are done if there is only a single string that does not need to be
// escaped.
if len(call.Args) == 1 {
s, ok := constStr(r.info, call.Args[0])
if ok && !strings.Contains(s, "%") && !rewriteType.newLine {
return r
}
}
// Rewrite arguments as format string.
expr := &ast.BasicLit{
ValuePos: call.Lparen,
Kind: token.STRING,
}
newArgs := append(call.Args[:argn:argn], expr)
newStr := []string{}
for i, a := range call.Args[argn:] {
if s, ok := constStr(r.info, a); ok {
newStr = append(newStr, strings.Replace(s, "%", "%%", -1))
} else {
newStr = append(newStr, "%v")
newArgs = append(newArgs, call.Args[argn+i])
}
}
s := strings.Join(newStr, rewriteType.sep)
if rewriteType.newLine {
s += "\n"
}
expr.Value = fmt.Sprintf("%q", s)
call.Args = newArgs
// TODO: consider creating an expression instead of a constant string and
// then wrapping it in an escape function or so:
// call.Args[argn+i] = &ast.CallExpr{
// Fun: &ast.SelectorExpr{
// X: ast.NewIdent("message"),
// Sel: ast.NewIdent("Lookup"),
// },
// Args: []ast.Expr{a},
// }
// }
return r
}
type rewriteType struct {
// method is the name of the equivalent method on a printer, or "" if it is
// the same.
method string
// methodf is the method to use if the arguments can be rewritten as a
// arguments to a printf-style call.
methodf string
// format is true if the method takes a formatting string followed by
// substitution arguments.
format bool
// arg indicates the position of the argument to extract. If all is
// positive, all arguments from this argument onwards needs to be extracted.
arg int
sep string
newLine bool
}
// rewriteFuncs list functions that can be directly mapped to the printer
// functions of the message package.
var rewriteFuncs = map[string]map[string]rewriteType{
// TODO: Printer -> *golang.org/x/text/message.Printer
"fmt": {
"Print": rewriteType{methodf: "Printf"},
"Sprint": rewriteType{methodf: "Sprintf"},
"Fprint": rewriteType{methodf: "Fprintf"},
"Println": rewriteType{methodf: "Printf", sep: " ", newLine: true},
"Sprintln": rewriteType{methodf: "Sprintf", sep: " ", newLine: true},
"Fprintln": rewriteType{methodf: "Fprintf", sep: " ", newLine: true},
"Printf": rewriteType{method: "Printf", format: true},
"Sprintf": rewriteType{method: "Sprintf", format: true},
"Fprintf": rewriteType{method: "Fprintf", format: true},
},
}
func constStr(info *loader.PackageInfo, e ast.Expr) (s string, ok bool) {
v := info.Types[e].Value
if v == nil || v.Kind() != constant.String {
return "", false
}
return constant.StringVal(v), true
}
// 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.
package runes
import (
"unicode/utf8"
"golang.org/x/text/transform"
)
// Note: below we pass invalid UTF-8 to the tIn and tNotIn transformers as is.
// This is done for various reasons:
// - To retain the semantics of the Nop transformer: if input is passed to a Nop
// one would expect it to be unchanged.
// - It would be very expensive to pass a converted RuneError to a transformer:
// a transformer might need more source bytes after RuneError, meaning that
// the only way to pass it safely is to create a new buffer and manage the
// intermingling of RuneErrors and normal input.
// - Many transformers leave ill-formed UTF-8 as is, so this is not
// inconsistent. Generally ill-formed UTF-8 is only replaced if it is a
// logical consequence of the operation (as for Map) or if it otherwise would
// pose security concerns (as for Remove).
// - An alternative would be to return an error on ill-formed UTF-8, but this
// would be inconsistent with other operations.
// If returns a transformer that applies tIn to consecutive runes for which
// s.Contains(r) and tNotIn to consecutive runes for which !s.Contains(r). Reset
// is called on tIn and tNotIn at the start of each run. A Nop transformer will
// substitute a nil value passed to tIn or tNotIn. Invalid UTF-8 is translated
// to RuneError to determine which transformer to apply, but is passed as is to
// the respective transformer.
func If(s Set, tIn, tNotIn transform.Transformer) Transformer {
if tIn == nil && tNotIn == nil {
return Transformer{transform.Nop}
}
if tIn == nil {
tIn = transform.Nop
}
if tNotIn == nil {
tNotIn = transform.Nop
}
sIn, ok := tIn.(transform.SpanningTransformer)
if !ok {
sIn = dummySpan{tIn}
}
sNotIn, ok := tNotIn.(transform.SpanningTransformer)
if !ok {
sNotIn = dummySpan{tNotIn}
}
a := &cond{
tIn: sIn,
tNotIn: sNotIn,
f: s.Contains,
}
a.Reset()
return Transformer{a}
}
type dummySpan struct{ transform.Transformer }
func (d dummySpan) Span(src []byte, atEOF bool) (n int, err error) {
return 0, transform.ErrEndOfSpan
}
type cond struct {
tIn, tNotIn transform.SpanningTransformer
f func(rune) bool
check func(rune) bool // current check to perform
t transform.SpanningTransformer // current transformer to use
}
// Reset implements transform.Transformer.
func (t *cond) Reset() {
t.check = t.is
t.t = t.tIn
t.t.Reset() // notIn will be reset on first usage.
}
func (t *cond) is(r rune) bool {
if t.f(r) {
return true
}
t.check = t.isNot
t.t = t.tNotIn
t.tNotIn.Reset()
return false
}
func (t *cond) isNot(r rune) bool {
if !t.f(r) {
return true
}
t.check = t.is
t.t = t.tIn
t.tIn.Reset()
return false
}
// This implementation of Span doesn't help all too much, but it needs to be
// there to satisfy this package's Transformer interface.
// TODO: there are certainly room for improvements, though. For example, if
// t.t == transform.Nop (which will a common occurrence) it will save a bundle
// to special-case that loop.
func (t *cond) Span(src []byte, atEOF bool) (n int, err error) {
p := 0
for n < len(src) && err == nil {
// Don't process too much at a time as the Spanner that will be
// called on this block may terminate early.
const maxChunk = 4096
max := len(src)
if v := n + maxChunk; v < max {
max = v
}
atEnd := false
size := 0
current := t.t
for ; p < max; p += size {
r := rune(src[p])
if r < utf8.RuneSelf {
size = 1
} else if r, size = utf8.DecodeRune(src[p:]); size == 1 {
if !atEOF && !utf8.FullRune(src[p:]) {
err = transform.ErrShortSrc
break
}
}
if !t.check(r) {
// The next rune will be the start of a new run.
atEnd = true
break
}
}
n2, err2 := current.Span(src[n:p], atEnd || (atEOF && p == len(src)))
n += n2
if err2 != nil {
return n, err2
}
// At this point either err != nil or t.check will pass for the rune at p.
p = n + size
}
return n, err
}
func (t *cond) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
p := 0
for nSrc < len(src) && err == nil {
// Don't process too much at a time, as the work might be wasted if the
// destination buffer isn't large enough to hold the result or a
// transform returns an error early.
const maxChunk = 4096
max := len(src)
if n := nSrc + maxChunk; n < len(src) {
max = n
}
atEnd := false
size := 0
current := t.t
for ; p < max; p += size {
r := rune(src[p])
if r < utf8.RuneSelf {
size = 1
} else if r, size = utf8.DecodeRune(src[p:]); size == 1 {
if !atEOF && !utf8.FullRune(src[p:]) {
err = transform.ErrShortSrc
break
}
}
if !t.check(r) {
// The next rune will be the start of a new run.
atEnd = true
break
}
}
nDst2, nSrc2, err2 := current.Transform(dst[nDst:], src[nSrc:p], atEnd || (atEOF && p == len(src)))
nDst += nDst2
nSrc += nSrc2
if err2 != nil {
return nDst, nSrc, err2
}
// At this point either err != nil or t.check will pass for the rune at p.
p = nSrc + size
}
return nDst, nSrc, err
}
// 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 runes provide transforms for UTF-8 encoded text.
package runes // import "golang.org/x/text/runes"
import (
"unicode"
"unicode/utf8"
"golang.org/x/text/transform"
)
// A Set is a collection of runes.
type Set interface {
// Contains returns true if r is contained in the set.
Contains(r rune) bool
}
type setFunc func(rune) bool
func (s setFunc) Contains(r rune) bool {
return s(r)
}
// Note: using funcs here instead of wrapping types result in cleaner
// documentation and a smaller API.
// In creates a Set with a Contains method that returns true for all runes in
// the given RangeTable.
func In(rt *unicode.RangeTable) Set {
return setFunc(func(r rune) bool { return unicode.Is(rt, r) })
}
// NotIn creates a Set with a Contains method that returns true for all runes not
// in the given RangeTable.
func NotIn(rt *unicode.RangeTable) Set {
return setFunc(func(r rune) bool { return !unicode.Is(rt, r) })
}
// Predicate creates a Set with a Contains method that returns f(r).
func Predicate(f func(rune) bool) Set {
return setFunc(f)
}
// Transformer implements the transform.Transformer interface.
type Transformer struct {
t transform.SpanningTransformer
}
func (t Transformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
return t.t.Transform(dst, src, atEOF)
}
func (t Transformer) Span(b []byte, atEOF bool) (n int, err error) {
return t.t.Span(b, atEOF)
}
func (t Transformer) Reset() { t.t.Reset() }
// Bytes returns a new byte slice with the result of converting b using t. It
// calls Reset on t. It returns nil if any error was found. This can only happen
// if an error-producing Transformer is passed to If.
func (t Transformer) Bytes(b []byte) []byte {
b, _, err := transform.Bytes(t, b)
if err != nil {
return nil
}
return b
}
// String returns a string with the result of converting s using t. It calls
// Reset on t. It returns the empty string if any error was found. This can only
// happen if an error-producing Transformer is passed to If.
func (t Transformer) String(s string) string {
s, _, err := transform.String(t, s)
if err != nil {
return ""
}
return s
}
// TODO:
// - Copy: copying strings and bytes in whole-rune units.
// - Validation (maybe)
// - Well-formed-ness (maybe)
const runeErrorString = string(utf8.RuneError)
// Remove returns a Transformer that removes runes r for which s.Contains(r).
// Illegal input bytes are replaced by RuneError before being passed to f.
func Remove(s Set) Transformer {
if f, ok := s.(setFunc); ok {
// This little trick cuts the running time of BenchmarkRemove for sets
// created by Predicate roughly in half.
// TODO: special-case RangeTables as well.
return Transformer{remove(f)}
}
return Transformer{remove(s.Contains)}
}
// TODO: remove transform.RemoveFunc.
type remove func(r rune) bool
func (remove) Reset() {}
// Span implements transform.Spanner.
func (t remove) Span(src []byte, atEOF bool) (n int, err error) {
for r, size := rune(0), 0; n < len(src); {
if r = rune(src[n]); r < utf8.RuneSelf {
size = 1
} else if r, size = utf8.DecodeRune(src[n:]); size == 1 {
// Invalid rune.
if !atEOF && !utf8.FullRune(src[n:]) {
err = transform.ErrShortSrc
} else {
err = transform.ErrEndOfSpan
}
break
}
if t(r) {
err = transform.ErrEndOfSpan
break
}
n += size
}
return
}
// Transform implements transform.Transformer.
func (t remove) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
for r, size := rune(0), 0; nSrc < len(src); {
if r = rune(src[nSrc]); r < utf8.RuneSelf {
size = 1
} else if r, size = utf8.DecodeRune(src[nSrc:]); size == 1 {
// Invalid rune.
if !atEOF && !utf8.FullRune(src[nSrc:]) {
err = transform.ErrShortSrc
break
}
// We replace illegal bytes with RuneError. Not doing so might
// otherwise turn a sequence of invalid UTF-8 into valid UTF-8.
// The resulting byte sequence may subsequently contain runes
// for which t(r) is true that were passed unnoticed.
if !t(utf8.RuneError) {
if nDst+3 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst+0] = runeErrorString[0]
dst[nDst+1] = runeErrorString[1]
dst[nDst+2] = runeErrorString[2]
nDst += 3
}
nSrc++
continue
}
if t(r) {
nSrc += size
continue
}
if nDst+size > len(dst) {
err = transform.ErrShortDst
break
}
for i := 0; i < size; i++ {
dst[nDst] = src[nSrc]
nDst++
nSrc++
}
}
return
}
// Map returns a Transformer that maps the runes in the input using the given
// mapping. Illegal bytes in the input are converted to utf8.RuneError before
// being passed to the mapping func.
func Map(mapping func(rune) rune) Transformer {
return Transformer{mapper(mapping)}
}
type mapper func(rune) rune
func (mapper) Reset() {}
// Span implements transform.Spanner.
func (t mapper) Span(src []byte, atEOF bool) (n int, err error) {
for r, size := rune(0), 0; n < len(src); n += size {
if r = rune(src[n]); r < utf8.RuneSelf {
size = 1
} else if r, size = utf8.DecodeRune(src[n:]); size == 1 {
// Invalid rune.
if !atEOF && !utf8.FullRune(src[n:]) {
err = transform.ErrShortSrc
} else {
err = transform.ErrEndOfSpan
}
break
}
if t(r) != r {
err = transform.ErrEndOfSpan
break
}
}
return n, err
}
// Transform implements transform.Transformer.
func (t mapper) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
var replacement rune
var b [utf8.UTFMax]byte
for r, size := rune(0), 0; nSrc < len(src); {
if r = rune(src[nSrc]); r < utf8.RuneSelf {
if replacement = t(r); replacement < utf8.RuneSelf {
if nDst == len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst] = byte(replacement)
nDst++
nSrc++
continue
}
size = 1
} else if r, size = utf8.DecodeRune(src[nSrc:]); size == 1 {
// Invalid rune.
if !atEOF && !utf8.FullRune(src[nSrc:]) {
err = transform.ErrShortSrc
break
}
if replacement = t(utf8.RuneError); replacement == utf8.RuneError {
if nDst+3 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst+0] = runeErrorString[0]
dst[nDst+1] = runeErrorString[1]
dst[nDst+2] = runeErrorString[2]
nDst += 3
nSrc++
continue
}
} else if replacement = t(r); replacement == r {
if nDst+size > len(dst) {
err = transform.ErrShortDst
break
}
for i := 0; i < size; i++ {
dst[nDst] = src[nSrc]
nDst++
nSrc++
}
continue
}
n := utf8.EncodeRune(b[:], replacement)
if nDst+n > len(dst) {
err = transform.ErrShortDst
break
}
for i := 0; i < n; i++ {
dst[nDst] = b[i]
nDst++
}
nSrc += size
}
return
}
// ReplaceIllFormed returns a transformer that replaces all input bytes that are
// not part of a well-formed UTF-8 code sequence with utf8.RuneError.
func ReplaceIllFormed() Transformer {
return Transformer{&replaceIllFormed{}}
}
type replaceIllFormed struct{ transform.NopResetter }
func (t replaceIllFormed) Span(src []byte, atEOF bool) (n int, err error) {
for n < len(src) {
// ASCII fast path.
if src[n] < utf8.RuneSelf {
n++
continue
}
r, size := utf8.DecodeRune(src[n:])
// Look for a valid non-ASCII rune.
if r != utf8.RuneError || size != 1 {
n += size
continue
}
// Look for short source data.
if !atEOF && !utf8.FullRune(src[n:]) {
err = transform.ErrShortSrc
break
}
// We have an invalid rune.
err = transform.ErrEndOfSpan
break
}
return n, err
}
func (t replaceIllFormed) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
for nSrc < len(src) {
// ASCII fast path.
if r := src[nSrc]; r < utf8.RuneSelf {
if nDst == len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst] = r
nDst++
nSrc++
continue
}
// Look for a valid non-ASCII rune.
if _, size := utf8.DecodeRune(src[nSrc:]); size != 1 {
if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
err = transform.ErrShortDst
break
}
nDst += size
nSrc += size
continue
}
// Look for short source data.
if !atEOF && !utf8.FullRune(src[nSrc:]) {
err = transform.ErrShortSrc
break
}
// We have an invalid rune.
if nDst+3 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst+0] = runeErrorString[0]
dst[nDst+1] = runeErrorString[1]
dst[nDst+2] = runeErrorString[2]
nDst += 3
nSrc++
}
return nDst, nSrc, err
}
// 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.
// Package bidirule implements the Bidi Rule defined by RFC 5893.
//
// This package is under development. The API may change without notice and
// without preserving backward compatibility.
package bidirule
import (
"errors"
"unicode/utf8"
"golang.org/x/text/transform"
"golang.org/x/text/unicode/bidi"
)
// This file contains an implementation of RFC 5893: Right-to-Left Scripts for
// Internationalized Domain Names for Applications (IDNA)
//
// A label is an individual component of a domain name. Labels are usually
// shown separated by dots; for example, the domain name "www.example.com" is
// composed of three labels: "www", "example", and "com".
//
// An RTL label is a label that contains at least one character of class R, AL,
// or AN. An LTR label is any label that is not an RTL label.
//
// A "Bidi domain name" is a domain name that contains at least one RTL label.
//
// The following guarantees can be made based on the above:
//
// o In a domain name consisting of only labels that satisfy the rule,
// the requirements of Section 3 are satisfied. Note that even LTR
// labels and pure ASCII labels have to be tested.
//
// o In a domain name consisting of only LDH labels (as defined in the
// Definitions document [RFC5890]) and labels that satisfy the rule,
// the requirements of Section 3 are satisfied as long as a label
// that starts with an ASCII digit does not come after a
// right-to-left label.
//
// No guarantee is given for other combinations.
// ErrInvalid indicates a label is invalid according to the Bidi Rule.
var ErrInvalid = errors.New("bidirule: failed Bidi Rule")
type ruleState uint8
const (
ruleInitial ruleState = iota
ruleLTR
ruleLTRFinal
ruleRTL
ruleRTLFinal
ruleInvalid
)
type ruleTransition struct {
next ruleState
mask uint16
}
var transitions = [...][2]ruleTransition{
// [2.1] The first character must be a character with Bidi property L, R, or
// AL. If it has the R or AL property, it is an RTL label; if it has the L
// property, it is an LTR label.
ruleInitial: {
{ruleLTRFinal, 1 << bidi.L},
{ruleRTLFinal, 1<<bidi.R | 1<<bidi.AL},
},
ruleRTL: {
// [2.3] In an RTL label, the end of the label must be a character with
// Bidi property R, AL, EN, or AN, followed by zero or more characters
// with Bidi property NSM.
{ruleRTLFinal, 1<<bidi.R | 1<<bidi.AL | 1<<bidi.EN | 1<<bidi.AN},
// [2.2] In an RTL label, only characters with the Bidi properties R,
// AL, AN, EN, ES, CS, ET, ON, BN, or NSM are allowed.
// We exclude the entries from [2.3]
{ruleRTL, 1<<bidi.ES | 1<<bidi.CS | 1<<bidi.ET | 1<<bidi.ON | 1<<bidi.BN | 1<<bidi.NSM},
},
ruleRTLFinal: {
// [2.3] In an RTL label, the end of the label must be a character with
// Bidi property R, AL, EN, or AN, followed by zero or more characters
// with Bidi property NSM.
{ruleRTLFinal, 1<<bidi.R | 1<<bidi.AL | 1<<bidi.EN | 1<<bidi.AN | 1<<bidi.NSM},
// [2.2] In an RTL label, only characters with the Bidi properties R,
// AL, AN, EN, ES, CS, ET, ON, BN, or NSM are allowed.
// We exclude the entries from [2.3] and NSM.
{ruleRTL, 1<<bidi.ES | 1<<bidi.CS | 1<<bidi.ET | 1<<bidi.ON | 1<<bidi.BN},
},
ruleLTR: {
// [2.6] In an LTR label, the end of the label must be a character with
// Bidi property L or EN, followed by zero or more characters with Bidi
// property NSM.
{ruleLTRFinal, 1<<bidi.L | 1<<bidi.EN},
// [2.5] In an LTR label, only characters with the Bidi properties L,
// EN, ES, CS, ET, ON, BN, or NSM are allowed.
// We exclude the entries from [2.6].
{ruleLTR, 1<<bidi.ES | 1<<bidi.CS | 1<<bidi.ET | 1<<bidi.ON | 1<<bidi.BN | 1<<bidi.NSM},
},
ruleLTRFinal: {
// [2.6] In an LTR label, the end of the label must be a character with
// Bidi property L or EN, followed by zero or more characters with Bidi
// property NSM.
{ruleLTRFinal, 1<<bidi.L | 1<<bidi.EN | 1<<bidi.NSM},
// [2.5] In an LTR label, only characters with the Bidi properties L,
// EN, ES, CS, ET, ON, BN, or NSM are allowed.
// We exclude the entries from [2.6].
{ruleLTR, 1<<bidi.ES | 1<<bidi.CS | 1<<bidi.ET | 1<<bidi.ON | 1<<bidi.BN},
},
ruleInvalid: {
{ruleInvalid, 0},
{ruleInvalid, 0},
},
}
// [2.4] In an RTL label, if an EN is present, no AN may be present, and
// vice versa.
const exclusiveRTL = uint16(1<<bidi.EN | 1<<bidi.AN)
// From RFC 5893
// An RTL label is a label that contains at least one character of type
// R, AL, or AN.
//
// An LTR label is any label that is not an RTL label.
// Direction reports the direction of the given label as defined by RFC 5893.
// The Bidi Rule does not have to be applied to labels of the category
// LeftToRight.
func Direction(b []byte) bidi.Direction {
for i := 0; i < len(b); {
e, sz := bidi.Lookup(b[i:])
if sz == 0 {
i++
}
c := e.Class()
if c == bidi.R || c == bidi.AL || c == bidi.AN {
return bidi.RightToLeft
}
i += sz
}
return bidi.LeftToRight
}
// DirectionString reports the direction of the given label as defined by RFC
// 5893. The Bidi Rule does not have to be applied to labels of the category
// LeftToRight.
func DirectionString(s string) bidi.Direction {
for i := 0; i < len(s); {
e, sz := bidi.LookupString(s[i:])
if sz == 0 {
i++
continue
}
c := e.Class()
if c == bidi.R || c == bidi.AL || c == bidi.AN {
return bidi.RightToLeft
}
i += sz
}
return bidi.LeftToRight
}
// Valid reports whether b conforms to the BiDi rule.
func Valid(b []byte) bool {
var t Transformer
if n, ok := t.advance(b); !ok || n < len(b) {
return false
}
return t.isFinal()
}
// ValidString reports whether s conforms to the BiDi rule.
func ValidString(s string) bool {
var t Transformer
if n, ok := t.advanceString(s); !ok || n < len(s) {
return false
}
return t.isFinal()
}
// New returns a Transformer that verifies that input adheres to the Bidi Rule.
func New() *Transformer {
return &Transformer{}
}
// Transformer implements transform.Transform.
type Transformer struct {
state ruleState
hasRTL bool
seen uint16
}
// A rule can only be violated for "Bidi Domain names", meaning if one of the
// following categories has been observed.
func (t *Transformer) isRTL() bool {
const isRTL = 1<<bidi.R | 1<<bidi.AL | 1<<bidi.AN
return t.seen&isRTL != 0
}
// Reset implements transform.Transformer.
func (t *Transformer) Reset() { *t = Transformer{} }
// Transform implements transform.Transformer. This Transformer has state and
// needs to be reset between uses.
func (t *Transformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
if len(dst) < len(src) {
src = src[:len(dst)]
atEOF = false
err = transform.ErrShortDst
}
n, err1 := t.Span(src, atEOF)
copy(dst, src[:n])
if err == nil || err1 != nil && err1 != transform.ErrShortSrc {
err = err1
}
return n, n, err
}
// Span returns the first n bytes of src that conform to the Bidi rule.
func (t *Transformer) Span(src []byte, atEOF bool) (n int, err error) {
if t.state == ruleInvalid && t.isRTL() {
return 0, ErrInvalid
}
n, ok := t.advance(src)
switch {
case !ok:
err = ErrInvalid
case n < len(src):
if !atEOF {
err = transform.ErrShortSrc
break
}
err = ErrInvalid
case !t.isFinal():
err = ErrInvalid
}
return n, err
}
// Precomputing the ASCII values decreases running time for the ASCII fast path
// by about 30%.
var asciiTable [128]bidi.Properties
func init() {
for i := range asciiTable {
p, _ := bidi.LookupRune(rune(i))
asciiTable[i] = p
}
}
func (t *Transformer) advance(s []byte) (n int, ok bool) {
var e bidi.Properties
var sz int
for n < len(s) {
if s[n] < utf8.RuneSelf {
e, sz = asciiTable[s[n]], 1
} else {
e, sz = bidi.Lookup(s[n:])
if sz <= 1 {
if sz == 1 {
// We always consider invalid UTF-8 to be invalid, even if
// the string has not yet been determined to be RTL.
// TODO: is this correct?
return n, false
}
return n, true // incomplete UTF-8 encoding
}
}
// TODO: using CompactClass would result in noticeable speedup.
// See unicode/bidi/prop.go:Properties.CompactClass.
c := uint16(1 << e.Class())
t.seen |= c
if t.seen&exclusiveRTL == exclusiveRTL {
t.state = ruleInvalid
return n, false
}
switch tr := transitions[t.state]; {
case tr[0].mask&c != 0:
t.state = tr[0].next
case tr[1].mask&c != 0:
t.state = tr[1].next
default:
t.state = ruleInvalid
if t.isRTL() {
return n, false
}
}
n += sz
}
return n, true
}
func (t *Transformer) advanceString(s string) (n int, ok bool) {
var e bidi.Properties
var sz int
for n < len(s) {
if s[n] < utf8.RuneSelf {
e, sz = asciiTable[s[n]], 1
} else {
e, sz = bidi.LookupString(s[n:])
if sz <= 1 {
if sz == 1 {
return n, false // invalid UTF-8
}
return n, true // incomplete UTF-8 encoding
}
}
// TODO: using CompactClass results in noticeable speedup.
// See unicode/bidi/prop.go:Properties.CompactClass.
c := uint16(1 << e.Class())
t.seen |= c
if t.seen&exclusiveRTL == exclusiveRTL {
t.state = ruleInvalid
return n, false
}
switch tr := transitions[t.state]; {
case tr[0].mask&c != 0:
t.state = tr[0].next
case tr[1].mask&c != 0:
t.state = tr[1].next
default:
t.state = ruleInvalid
if t.isRTL() {
return n, false
}
}
n += sz
}
return n, true
}
// 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.
//go:build go1.10
package bidirule
func (t *Transformer) isFinal() bool {
return t.state == ruleLTRFinal || t.state == ruleRTLFinal || t.state == ruleInitial
}
// 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.
package precis
import (
"unicode/utf8"
)
// TODO: Add contextual character rules from Appendix A of RFC5892.
// A class is a set of characters that match certain derived properties. The
// PRECIS framework defines two classes: The Freeform class and the Identifier
// class. The freeform class should be used for profiles where expressiveness is
// prioritized over safety such as nicknames or passwords. The identifier class
// should be used for profiles where safety is the first priority such as
// addressable network labels and usernames.
type class struct {
validFrom property
}
// Contains satisfies the runes.Set interface and returns whether the given rune
// is a member of the class.
func (c class) Contains(r rune) bool {
b := make([]byte, 4)
n := utf8.EncodeRune(b, r)
trieval, _ := dpTrie.lookup(b[:n])
return c.validFrom <= property(trieval)
}
var (
identifier = &class{validFrom: pValid}
freeform = &class{validFrom: idDisOrFreePVal}
)
// 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.
package precis
import "errors"
// This file contains tables and code related to context rules.
type catBitmap uint16
const (
// These bits, once set depending on the current value, are never unset.
bJapanese catBitmap = 1 << iota
bArabicIndicDigit
bExtendedArabicIndicDigit
// These bits are set on each iteration depending on the current value.
bJoinStart
bJoinMid
bJoinEnd
bVirama
bLatinSmallL
bGreek
bHebrew
// These bits indicated which of the permanent bits need to be set at the
// end of the checks.
bMustHaveJapn
permanent = bJapanese | bArabicIndicDigit | bExtendedArabicIndicDigit | bMustHaveJapn
)
const finalShift = 10
var errContext = errors.New("precis: contextual rule violated")
func init() {
// Programmatically set these required bits as, manually setting them seems
// too error prone.
for i, ct := range categoryTransitions {
categoryTransitions[i].keep |= permanent
categoryTransitions[i].accept |= ct.term
}
}
var categoryTransitions = []struct {
keep catBitmap // mask selecting which bits to keep from the previous state
set catBitmap // mask for which bits to set for this transition
// These bitmaps are used for rules that require lookahead.
// term&accept == term must be true, which is enforced programmatically.
term catBitmap // bits accepted as termination condition
accept catBitmap // bits that pass, but not sufficient as termination
// The rule function cannot take a *context as an argument, as it would
// cause the context to escape, adding significant overhead.
rule func(beforeBits catBitmap) (doLookahead bool, err error)
}{
joiningL: {set: bJoinStart},
joiningD: {set: bJoinStart | bJoinEnd},
joiningT: {keep: bJoinStart, set: bJoinMid},
joiningR: {set: bJoinEnd},
viramaModifier: {set: bVirama},
viramaJoinT: {set: bVirama | bJoinMid},
latinSmallL: {set: bLatinSmallL},
greek: {set: bGreek},
greekJoinT: {set: bGreek | bJoinMid},
hebrew: {set: bHebrew},
hebrewJoinT: {set: bHebrew | bJoinMid},
japanese: {set: bJapanese},
katakanaMiddleDot: {set: bMustHaveJapn},
zeroWidthNonJoiner: {
term: bJoinEnd,
accept: bJoinMid,
rule: func(before catBitmap) (doLookAhead bool, err error) {
if before&bVirama != 0 {
return false, nil
}
if before&bJoinStart == 0 {
return false, errContext
}
return true, nil
},
},
zeroWidthJoiner: {
rule: func(before catBitmap) (doLookAhead bool, err error) {
if before&bVirama == 0 {
err = errContext
}
return false, err
},
},
middleDot: {
term: bLatinSmallL,
rule: func(before catBitmap) (doLookAhead bool, err error) {
if before&bLatinSmallL == 0 {
return false, errContext
}
return true, nil
},
},
greekLowerNumeralSign: {
set: bGreek,
term: bGreek,
rule: func(before catBitmap) (doLookAhead bool, err error) {
return true, nil
},
},
hebrewPreceding: {
set: bHebrew,
rule: func(before catBitmap) (doLookAhead bool, err error) {
if before&bHebrew == 0 {
err = errContext
}
return false, err
},
},
arabicIndicDigit: {
set: bArabicIndicDigit,
rule: func(before catBitmap) (doLookAhead bool, err error) {
if before&bExtendedArabicIndicDigit != 0 {
err = errContext
}
return false, err
},
},
extendedArabicIndicDigit: {
set: bExtendedArabicIndicDigit,
rule: func(before catBitmap) (doLookAhead bool, err error) {
if before&bArabicIndicDigit != 0 {
err = errContext
}
return false, err
},
},
}
// 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.
package precis
import (
"unicode"
"unicode/utf8"
"golang.org/x/text/transform"
)
type nickAdditionalMapping struct {
// TODO: This transformer needs to be stateless somehow…
notStart bool
prevSpace bool
}
func (t *nickAdditionalMapping) Reset() {
t.prevSpace = false
t.notStart = false
}
func (t *nickAdditionalMapping) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
// RFC 8266 §2.1. Rules
//
// 2. Additional Mapping Rule: The additional mapping rule consists of
// the following sub-rules.
//
// a. Map any instances of non-ASCII space to SPACE (U+0020); a
// non-ASCII space is any Unicode code point having a general
// category of "Zs", naturally with the exception of SPACE
// (U+0020). (The inclusion of only ASCII space prevents
// confusion with various non-ASCII space code points, many of
// which are difficult to reproduce across different input
// methods.)
//
// b. Remove any instances of the ASCII space character at the
// beginning or end of a nickname (e.g., "stpeter " is mapped to
// "stpeter").
//
// c. Map interior sequences of more than one ASCII space character
// to a single ASCII space character (e.g., "St Peter" is
// mapped to "St Peter").
for nSrc < len(src) {
r, size := utf8.DecodeRune(src[nSrc:])
if size == 0 { // Incomplete UTF-8 encoding
if !atEOF {
return nDst, nSrc, transform.ErrShortSrc
}
size = 1
}
if unicode.Is(unicode.Zs, r) {
t.prevSpace = true
} else {
if t.prevSpace && t.notStart {
dst[nDst] = ' '
nDst += 1
}
if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
nDst += size
return nDst, nSrc, transform.ErrShortDst
}
nDst += size
t.prevSpace = false
t.notStart = true
}
nSrc += size
}
return nDst, nSrc, nil
}
// 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.
package precis
import (
"golang.org/x/text/cases"
"golang.org/x/text/language"
"golang.org/x/text/runes"
"golang.org/x/text/transform"
"golang.org/x/text/unicode/norm"
)
// An Option is used to define the behavior and rules of a Profile.
type Option func(*options)
type options struct {
// Preparation options
foldWidth bool
// Enforcement options
asciiLower bool
cases transform.SpanningTransformer
disallow runes.Set
norm transform.SpanningTransformer
additional []func() transform.SpanningTransformer
width transform.SpanningTransformer
disallowEmpty bool
bidiRule bool
repeat bool
// Comparison options
ignorecase bool
}
func getOpts(o ...Option) (res options) {
for _, f := range o {
f(&res)
}
// Using a SpanningTransformer, instead of norm.Form prevents an allocation
// down the road.
if res.norm == nil {
res.norm = norm.NFC
}
return
}
var (
// The IgnoreCase option causes the profile to perform a case insensitive
// comparison during the PRECIS comparison step.
IgnoreCase Option = ignoreCase
// The FoldWidth option causes the profile to map non-canonical wide and
// narrow variants to their decomposition mapping. This is useful for
// profiles that are based on the identifier class which would otherwise
// disallow such characters.
FoldWidth Option = foldWidth
// The DisallowEmpty option causes the enforcement step to return an error if
// the resulting string would be empty.
DisallowEmpty Option = disallowEmpty
// The BidiRule option causes the Bidi Rule defined in RFC 5893 to be
// applied.
BidiRule Option = bidiRule
)
var (
ignoreCase = func(o *options) {
o.ignorecase = true
}
foldWidth = func(o *options) {
o.foldWidth = true
}
disallowEmpty = func(o *options) {
o.disallowEmpty = true
}
bidiRule = func(o *options) {
o.bidiRule = true
}
repeat = func(o *options) {
o.repeat = true
}
)
// TODO: move this logic to package transform
type spanWrap struct{ transform.Transformer }
func (s spanWrap) Span(src []byte, atEOF bool) (n int, err error) {
return 0, transform.ErrEndOfSpan
}
// TODO: allow different types? For instance:
// func() transform.Transformer
// func() transform.SpanningTransformer
// func([]byte) bool // validation only
//
// Also, would be great if we could detect if a transformer is reentrant.
// The AdditionalMapping option defines the additional mapping rule for the
// Profile by applying Transformer's in sequence.
func AdditionalMapping(t ...func() transform.Transformer) Option {
return func(o *options) {
for _, f := range t {
sf := func() transform.SpanningTransformer {
return f().(transform.SpanningTransformer)
}
if _, ok := f().(transform.SpanningTransformer); !ok {
sf = func() transform.SpanningTransformer {
return spanWrap{f()}
}
}
o.additional = append(o.additional, sf)
}
}
}
// The Norm option defines a Profile's normalization rule. Defaults to NFC.
func Norm(f norm.Form) Option {
return func(o *options) {
o.norm = f
}
}
// The FoldCase option defines a Profile's case mapping rule. Options can be
// provided to determine the type of case folding used.
func FoldCase(opts ...cases.Option) Option {
return func(o *options) {
o.asciiLower = true
o.cases = cases.Fold(opts...)
}
}
// The LowerCase option defines a Profile's case mapping rule. Options can be
// provided to determine the type of case folding used.
func LowerCase(opts ...cases.Option) Option {
return func(o *options) {
o.asciiLower = true
if len(opts) == 0 {
o.cases = cases.Lower(language.Und, cases.HandleFinalSigma(false))
return
}
opts = append([]cases.Option{cases.HandleFinalSigma(false)}, opts...)
o.cases = cases.Lower(language.Und, opts...)
}
}
// The Disallow option further restricts a Profile's allowed characters beyond
// what is disallowed by the underlying string class.
func Disallow(set runes.Set) Option {
return func(o *options) {
o.disallow = set
}
}
// 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.
package precis
import (
"bytes"
"errors"
"unicode/utf8"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"golang.org/x/text/runes"
"golang.org/x/text/secure/bidirule"
"golang.org/x/text/transform"
"golang.org/x/text/width"
)
var (
errDisallowedRune = errors.New("precis: disallowed rune encountered")
)
var dpTrie = newDerivedPropertiesTrie(0)
// A Profile represents a set of rules for normalizing and validating strings in
// the PRECIS framework.
type Profile struct {
options
class *class
}
// NewIdentifier creates a new PRECIS profile based on the Identifier string
// class. Profiles created from this class are suitable for use where safety is
// prioritized over expressiveness like network identifiers, user accounts, chat
// rooms, and file names.
func NewIdentifier(opts ...Option) *Profile {
return &Profile{
options: getOpts(opts...),
class: identifier,
}
}
// NewFreeform creates a new PRECIS profile based on the Freeform string class.
// Profiles created from this class are suitable for use where expressiveness is
// prioritized over safety like passwords, and display-elements such as
// nicknames in a chat room.
func NewFreeform(opts ...Option) *Profile {
return &Profile{
options: getOpts(opts...),
class: freeform,
}
}
// NewRestrictedProfile creates a new PRECIS profile based on an existing
// profile.
// If the parent profile already had the Disallow option set, the new rule
// overrides the parents rule.
func NewRestrictedProfile(parent *Profile, disallow runes.Set) *Profile {
p := *parent
Disallow(disallow)(&p.options)
return &p
}
// NewTransformer creates a new transform.Transformer that performs the PRECIS
// preparation and enforcement steps on the given UTF-8 encoded bytes.
func (p *Profile) NewTransformer() *Transformer {
var ts []transform.Transformer
// These transforms are applied in the order defined in
// https://tools.ietf.org/html/rfc7564#section-7
// RFC 8266 §2.1:
//
// Implementation experience has shown that applying the rules for the
// Nickname profile is not an idempotent procedure for all code points.
// Therefore, an implementation SHOULD apply the rules repeatedly until
// the output string is stable; if the output string does not stabilize
// after reapplying the rules three (3) additional times after the first
// application, the implementation SHOULD terminate application of the
// rules and reject the input string as invalid.
//
// There is no known string that will change indefinitely, so repeat 4 times
// and rely on the Span method to keep things relatively performant.
r := 1
if p.options.repeat {
r = 4
}
for ; r > 0; r-- {
if p.options.foldWidth {
ts = append(ts, width.Fold)
}
for _, f := range p.options.additional {
ts = append(ts, f())
}
if p.options.cases != nil {
ts = append(ts, p.options.cases)
}
ts = append(ts, p.options.norm)
if p.options.bidiRule {
ts = append(ts, bidirule.New())
}
ts = append(ts, &checker{p: p, allowed: p.Allowed()})
}
// TODO: Add the disallow empty rule with a dummy transformer?
return &Transformer{transform.Chain(ts...)}
}
var errEmptyString = errors.New("precis: transformation resulted in empty string")
type buffers struct {
src []byte
buf [2][]byte
next int
}
func (b *buffers) apply(t transform.SpanningTransformer) (err error) {
n, err := t.Span(b.src, true)
if err != transform.ErrEndOfSpan {
return err
}
x := b.next & 1
if b.buf[x] == nil {
b.buf[x] = make([]byte, 0, 8+len(b.src)+len(b.src)>>2)
}
span := append(b.buf[x][:0], b.src[:n]...)
b.src, _, err = transform.Append(t, span, b.src[n:])
b.buf[x] = b.src
b.next++
return err
}
// Pre-allocate transformers when possible. In some cases this avoids allocation.
var (
foldWidthT transform.SpanningTransformer = width.Fold
lowerCaseT transform.SpanningTransformer = cases.Lower(language.Und, cases.HandleFinalSigma(false))
)
// TODO: make this a method on profile.
func (b *buffers) enforce(p *Profile, src []byte, comparing bool) (str []byte, err error) {
b.src = src
ascii := true
for _, c := range src {
if c >= utf8.RuneSelf {
ascii = false
break
}
}
// ASCII fast path.
if ascii {
for _, f := range p.options.additional {
if err = b.apply(f()); err != nil {
return nil, err
}
}
switch {
case p.options.asciiLower || (comparing && p.options.ignorecase):
for i, c := range b.src {
if 'A' <= c && c <= 'Z' {
b.src[i] = c ^ 1<<5
}
}
case p.options.cases != nil:
b.apply(p.options.cases)
}
c := checker{p: p}
if _, err := c.span(b.src, true); err != nil {
return nil, err
}
if p.disallow != nil {
for _, c := range b.src {
if p.disallow.Contains(rune(c)) {
return nil, errDisallowedRune
}
}
}
if p.options.disallowEmpty && len(b.src) == 0 {
return nil, errEmptyString
}
return b.src, nil
}
// These transforms are applied in the order defined in
// https://tools.ietf.org/html/rfc8264#section-7
r := 1
if p.options.repeat {
r = 4
}
for ; r > 0; r-- {
// TODO: allow different width transforms options.
if p.options.foldWidth || (p.options.ignorecase && comparing) {
b.apply(foldWidthT)
}
for _, f := range p.options.additional {
if err = b.apply(f()); err != nil {
return nil, err
}
}
if p.options.cases != nil {
b.apply(p.options.cases)
}
if comparing && p.options.ignorecase {
b.apply(lowerCaseT)
}
b.apply(p.norm)
if p.options.bidiRule && !bidirule.Valid(b.src) {
return nil, bidirule.ErrInvalid
}
c := checker{p: p}
if _, err := c.span(b.src, true); err != nil {
return nil, err
}
if p.disallow != nil {
for i := 0; i < len(b.src); {
r, size := utf8.DecodeRune(b.src[i:])
if p.disallow.Contains(r) {
return nil, errDisallowedRune
}
i += size
}
}
if p.options.disallowEmpty && len(b.src) == 0 {
return nil, errEmptyString
}
}
return b.src, nil
}
// Append appends the result of applying p to src writing the result to dst.
// It returns an error if the input string is invalid.
func (p *Profile) Append(dst, src []byte) ([]byte, error) {
var buf buffers
b, err := buf.enforce(p, src, false)
if err != nil {
return nil, err
}
return append(dst, b...), nil
}
func processBytes(p *Profile, b []byte, key bool) ([]byte, error) {
var buf buffers
b, err := buf.enforce(p, b, key)
if err != nil {
return nil, err
}
if buf.next == 0 {
c := make([]byte, len(b))
copy(c, b)
return c, nil
}
return b, nil
}
// Bytes returns a new byte slice with the result of applying the profile to b.
func (p *Profile) Bytes(b []byte) ([]byte, error) {
return processBytes(p, b, false)
}
// AppendCompareKey appends the result of applying p to src (including any
// optional rules to make strings comparable or useful in a map key such as
// applying lowercasing) writing the result to dst. It returns an error if the
// input string is invalid.
func (p *Profile) AppendCompareKey(dst, src []byte) ([]byte, error) {
var buf buffers
b, err := buf.enforce(p, src, true)
if err != nil {
return nil, err
}
return append(dst, b...), nil
}
func processString(p *Profile, s string, key bool) (string, error) {
var buf buffers
b, err := buf.enforce(p, []byte(s), key)
if err != nil {
return "", err
}
return string(b), nil
}
// String returns a string with the result of applying the profile to s.
func (p *Profile) String(s string) (string, error) {
return processString(p, s, false)
}
// CompareKey returns a string that can be used for comparison, hashing, or
// collation.
func (p *Profile) CompareKey(s string) (string, error) {
return processString(p, s, true)
}
// Compare enforces both strings, and then compares them for bit-string identity
// (byte-for-byte equality). If either string cannot be enforced, the comparison
// is false.
func (p *Profile) Compare(a, b string) bool {
var buf buffers
akey, err := buf.enforce(p, []byte(a), true)
if err != nil {
return false
}
buf = buffers{}
bkey, err := buf.enforce(p, []byte(b), true)
if err != nil {
return false
}
return bytes.Equal(akey, bkey)
}
// Allowed returns a runes.Set containing every rune that is a member of the
// underlying profile's string class and not disallowed by any profile specific
// rules.
func (p *Profile) Allowed() runes.Set {
if p.options.disallow != nil {
return runes.Predicate(func(r rune) bool {
return p.class.Contains(r) && !p.options.disallow.Contains(r)
})
}
return p.class
}
type checker struct {
p *Profile
allowed runes.Set
beforeBits catBitmap
termBits catBitmap
acceptBits catBitmap
}
func (c *checker) Reset() {
c.beforeBits = 0
c.termBits = 0
c.acceptBits = 0
}
func (c *checker) span(src []byte, atEOF bool) (n int, err error) {
for n < len(src) {
e, sz := dpTrie.lookup(src[n:])
d := categoryTransitions[category(e&catMask)]
if sz == 0 {
if !atEOF {
return n, transform.ErrShortSrc
}
return n, errDisallowedRune
}
doLookAhead := false
if property(e) < c.p.class.validFrom {
if d.rule == nil {
return n, errDisallowedRune
}
doLookAhead, err = d.rule(c.beforeBits)
if err != nil {
return n, err
}
}
c.beforeBits &= d.keep
c.beforeBits |= d.set
if c.termBits != 0 {
// We are currently in an unterminated lookahead.
if c.beforeBits&c.termBits != 0 {
c.termBits = 0
c.acceptBits = 0
} else if c.beforeBits&c.acceptBits == 0 {
// Invalid continuation of the unterminated lookahead sequence.
return n, errContext
}
}
if doLookAhead {
if c.termBits != 0 {
// A previous lookahead run has not been terminated yet.
return n, errContext
}
c.termBits = d.term
c.acceptBits = d.accept
}
n += sz
}
if m := c.beforeBits >> finalShift; c.beforeBits&m != m || c.termBits != 0 {
err = errContext
}
return n, err
}
// TODO: we may get rid of this transform if transform.Chain understands
// something like a Spanner interface.
func (c checker) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
short := false
if len(dst) < len(src) {
src = src[:len(dst)]
atEOF = false
short = true
}
nSrc, err = c.span(src, atEOF)
nDst = copy(dst, src[:nSrc])
if short && (err == transform.ErrShortSrc || err == nil) {
err = transform.ErrShortDst
}
return nDst, nSrc, err
}
// 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.
package precis
import (
"unicode"
"golang.org/x/text/runes"
"golang.org/x/text/transform"
"golang.org/x/text/unicode/norm"
)
var (
// Implements the Nickname profile specified in RFC 8266.
Nickname *Profile = nickname
// Implements the UsernameCaseMapped profile specified in RFC 8265.
UsernameCaseMapped *Profile = usernameCaseMap
// Implements the UsernameCasePreserved profile specified in RFC 8265.
UsernameCasePreserved *Profile = usernameNoCaseMap
// Implements the OpaqueString profile defined in RFC 8265 for passwords and
// other secure labels.
OpaqueString *Profile = opaquestring
)
var (
nickname = &Profile{
options: getOpts(
AdditionalMapping(func() transform.Transformer {
return &nickAdditionalMapping{}
}),
IgnoreCase,
Norm(norm.NFKC),
DisallowEmpty,
repeat,
),
class: freeform,
}
usernameCaseMap = &Profile{
options: getOpts(
FoldWidth,
LowerCase(),
Norm(norm.NFC),
BidiRule,
),
class: identifier,
}
usernameNoCaseMap = &Profile{
options: getOpts(
FoldWidth,
Norm(norm.NFC),
BidiRule,
),
class: identifier,
}
opaquestring = &Profile{
options: getOpts(
AdditionalMapping(func() transform.Transformer {
return mapSpaces
}),
Norm(norm.NFC),
DisallowEmpty,
),
class: freeform,
}
)
// mapSpaces is a shared value of a runes.Map transformer.
var mapSpaces transform.Transformer = runes.Map(func(r rune) rune {
if unicode.Is(unicode.Zs, r) {
return ' '
}
return r
})
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.21
package precis
// UnicodeVersion is the Unicode version from which the tables in this package are derived.
const UnicodeVersion = "15.0.0"
// lookup returns the trie value for the first UTF-8 encoding in s and
// the width in bytes of this encoding. The size will be 0 if s does not
// hold enough bytes to complete the encoding. len(s) must be greater than 0.
func (t *derivedPropertiesTrie) lookup(s []byte) (v uint8, sz int) {
c0 := s[0]
switch {
case c0 < 0x80: // is ASCII
return derivedPropertiesValues[c0], 1
case c0 < 0xC2:
return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
case c0 < 0xE0: // 2-byte UTF-8
if len(s) < 2 {
return 0, 0
}
i := derivedPropertiesIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c1), 2
case c0 < 0xF0: // 3-byte UTF-8
if len(s) < 3 {
return 0, 0
}
i := derivedPropertiesIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = derivedPropertiesIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c2), 3
case c0 < 0xF8: // 4-byte UTF-8
if len(s) < 4 {
return 0, 0
}
i := derivedPropertiesIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = derivedPropertiesIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
o = uint32(i)<<6 + uint32(c2)
i = derivedPropertiesIndex[o]
c3 := s[3]
if c3 < 0x80 || 0xC0 <= c3 {
return 0, 3 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c3), 4
}
// Illegal rune
return 0, 1
}
// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
// s must start with a full and valid UTF-8 encoded rune.
func (t *derivedPropertiesTrie) lookupUnsafe(s []byte) uint8 {
c0 := s[0]
if c0 < 0x80 { // is ASCII
return derivedPropertiesValues[c0]
}
i := derivedPropertiesIndex[c0]
if c0 < 0xE0 { // 2-byte UTF-8
return t.lookupValue(uint32(i), s[1])
}
i = derivedPropertiesIndex[uint32(i)<<6+uint32(s[1])]
if c0 < 0xF0 { // 3-byte UTF-8
return t.lookupValue(uint32(i), s[2])
}
i = derivedPropertiesIndex[uint32(i)<<6+uint32(s[2])]
if c0 < 0xF8 { // 4-byte UTF-8
return t.lookupValue(uint32(i), s[3])
}
return 0
}
// lookupString returns the trie value for the first UTF-8 encoding in s and
// the width in bytes of this encoding. The size will be 0 if s does not
// hold enough bytes to complete the encoding. len(s) must be greater than 0.
func (t *derivedPropertiesTrie) lookupString(s string) (v uint8, sz int) {
c0 := s[0]
switch {
case c0 < 0x80: // is ASCII
return derivedPropertiesValues[c0], 1
case c0 < 0xC2:
return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
case c0 < 0xE0: // 2-byte UTF-8
if len(s) < 2 {
return 0, 0
}
i := derivedPropertiesIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c1), 2
case c0 < 0xF0: // 3-byte UTF-8
if len(s) < 3 {
return 0, 0
}
i := derivedPropertiesIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = derivedPropertiesIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c2), 3
case c0 < 0xF8: // 4-byte UTF-8
if len(s) < 4 {
return 0, 0
}
i := derivedPropertiesIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = derivedPropertiesIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
o = uint32(i)<<6 + uint32(c2)
i = derivedPropertiesIndex[o]
c3 := s[3]
if c3 < 0x80 || 0xC0 <= c3 {
return 0, 3 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c3), 4
}
// Illegal rune
return 0, 1
}
// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
// s must start with a full and valid UTF-8 encoded rune.
func (t *derivedPropertiesTrie) lookupStringUnsafe(s string) uint8 {
c0 := s[0]
if c0 < 0x80 { // is ASCII
return derivedPropertiesValues[c0]
}
i := derivedPropertiesIndex[c0]
if c0 < 0xE0 { // 2-byte UTF-8
return t.lookupValue(uint32(i), s[1])
}
i = derivedPropertiesIndex[uint32(i)<<6+uint32(s[1])]
if c0 < 0xF0 { // 3-byte UTF-8
return t.lookupValue(uint32(i), s[2])
}
i = derivedPropertiesIndex[uint32(i)<<6+uint32(s[2])]
if c0 < 0xF8 { // 4-byte UTF-8
return t.lookupValue(uint32(i), s[3])
}
return 0
}
// derivedPropertiesTrie. Total size: 28992 bytes (28.31 KiB). Checksum: 6ba05cbedd26c252.
type derivedPropertiesTrie struct{}
func newDerivedPropertiesTrie(i int) *derivedPropertiesTrie {
return &derivedPropertiesTrie{}
}
// lookupValue determines the type of block n and looks up the value for b.
func (t *derivedPropertiesTrie) lookupValue(n uint32, b byte) uint8 {
switch {
default:
return uint8(derivedPropertiesValues[n<<6+uint32(b)])
}
}
// derivedPropertiesValues: 373 blocks, 23872 entries, 23872 bytes
// The third block is the zero block.
var derivedPropertiesValues = [23872]uint8{
// Block 0x0, offset 0x0
0x00: 0x0040, 0x01: 0x0040, 0x02: 0x0040, 0x03: 0x0040, 0x04: 0x0040, 0x05: 0x0040,
0x06: 0x0040, 0x07: 0x0040, 0x08: 0x0040, 0x09: 0x0040, 0x0a: 0x0040, 0x0b: 0x0040,
0x0c: 0x0040, 0x0d: 0x0040, 0x0e: 0x0040, 0x0f: 0x0040, 0x10: 0x0040, 0x11: 0x0040,
0x12: 0x0040, 0x13: 0x0040, 0x14: 0x0040, 0x15: 0x0040, 0x16: 0x0040, 0x17: 0x0040,
0x18: 0x0040, 0x19: 0x0040, 0x1a: 0x0040, 0x1b: 0x0040, 0x1c: 0x0040, 0x1d: 0x0040,
0x1e: 0x0040, 0x1f: 0x0040, 0x20: 0x0080, 0x21: 0x00c0, 0x22: 0x00c0, 0x23: 0x00c0,
0x24: 0x00c0, 0x25: 0x00c0, 0x26: 0x00c0, 0x27: 0x00c0, 0x28: 0x00c0, 0x29: 0x00c0,
0x2a: 0x00c0, 0x2b: 0x00c0, 0x2c: 0x00c0, 0x2d: 0x00c0, 0x2e: 0x00c0, 0x2f: 0x00c0,
0x30: 0x00c0, 0x31: 0x00c0, 0x32: 0x00c0, 0x33: 0x00c0, 0x34: 0x00c0, 0x35: 0x00c0,
0x36: 0x00c0, 0x37: 0x00c0, 0x38: 0x00c0, 0x39: 0x00c0, 0x3a: 0x00c0, 0x3b: 0x00c0,
0x3c: 0x00c0, 0x3d: 0x00c0, 0x3e: 0x00c0, 0x3f: 0x00c0,
// Block 0x1, offset 0x40
0x40: 0x00c0, 0x41: 0x00c0, 0x42: 0x00c0, 0x43: 0x00c0, 0x44: 0x00c0, 0x45: 0x00c0,
0x46: 0x00c0, 0x47: 0x00c0, 0x48: 0x00c0, 0x49: 0x00c0, 0x4a: 0x00c0, 0x4b: 0x00c0,
0x4c: 0x00c0, 0x4d: 0x00c0, 0x4e: 0x00c0, 0x4f: 0x00c0, 0x50: 0x00c0, 0x51: 0x00c0,
0x52: 0x00c0, 0x53: 0x00c0, 0x54: 0x00c0, 0x55: 0x00c0, 0x56: 0x00c0, 0x57: 0x00c0,
0x58: 0x00c0, 0x59: 0x00c0, 0x5a: 0x00c0, 0x5b: 0x00c0, 0x5c: 0x00c0, 0x5d: 0x00c0,
0x5e: 0x00c0, 0x5f: 0x00c0, 0x60: 0x00c0, 0x61: 0x00c0, 0x62: 0x00c0, 0x63: 0x00c0,
0x64: 0x00c0, 0x65: 0x00c0, 0x66: 0x00c0, 0x67: 0x00c0, 0x68: 0x00c0, 0x69: 0x00c0,
0x6a: 0x00c0, 0x6b: 0x00c0, 0x6c: 0x00c7, 0x6d: 0x00c0, 0x6e: 0x00c0, 0x6f: 0x00c0,
0x70: 0x00c0, 0x71: 0x00c0, 0x72: 0x00c0, 0x73: 0x00c0, 0x74: 0x00c0, 0x75: 0x00c0,
0x76: 0x00c0, 0x77: 0x00c0, 0x78: 0x00c0, 0x79: 0x00c0, 0x7a: 0x00c0, 0x7b: 0x00c0,
0x7c: 0x00c0, 0x7d: 0x00c0, 0x7e: 0x00c0, 0x7f: 0x0040,
// Block 0x2, offset 0x80
// Block 0x3, offset 0xc0
0xc0: 0x0040, 0xc1: 0x0040, 0xc2: 0x0040, 0xc3: 0x0040, 0xc4: 0x0040, 0xc5: 0x0040,
0xc6: 0x0040, 0xc7: 0x0040, 0xc8: 0x0040, 0xc9: 0x0040, 0xca: 0x0040, 0xcb: 0x0040,
0xcc: 0x0040, 0xcd: 0x0040, 0xce: 0x0040, 0xcf: 0x0040, 0xd0: 0x0040, 0xd1: 0x0040,
0xd2: 0x0040, 0xd3: 0x0040, 0xd4: 0x0040, 0xd5: 0x0040, 0xd6: 0x0040, 0xd7: 0x0040,
0xd8: 0x0040, 0xd9: 0x0040, 0xda: 0x0040, 0xdb: 0x0040, 0xdc: 0x0040, 0xdd: 0x0040,
0xde: 0x0040, 0xdf: 0x0040, 0xe0: 0x0080, 0xe1: 0x0080, 0xe2: 0x0080, 0xe3: 0x0080,
0xe4: 0x0080, 0xe5: 0x0080, 0xe6: 0x0080, 0xe7: 0x0080, 0xe8: 0x0080, 0xe9: 0x0080,
0xea: 0x0080, 0xeb: 0x0080, 0xec: 0x0080, 0xed: 0x0040, 0xee: 0x0080, 0xef: 0x0080,
0xf0: 0x0080, 0xf1: 0x0080, 0xf2: 0x0080, 0xf3: 0x0080, 0xf4: 0x0080, 0xf5: 0x0080,
0xf6: 0x0080, 0xf7: 0x004f, 0xf8: 0x0080, 0xf9: 0x0080, 0xfa: 0x0080, 0xfb: 0x0080,
0xfc: 0x0080, 0xfd: 0x0080, 0xfe: 0x0080, 0xff: 0x0080,
// Block 0x4, offset 0x100
0x100: 0x00c0, 0x101: 0x00c0, 0x102: 0x00c0, 0x103: 0x00c0, 0x104: 0x00c0, 0x105: 0x00c0,
0x106: 0x00c0, 0x107: 0x00c0, 0x108: 0x00c0, 0x109: 0x00c0, 0x10a: 0x00c0, 0x10b: 0x00c0,
0x10c: 0x00c0, 0x10d: 0x00c0, 0x10e: 0x00c0, 0x10f: 0x00c0, 0x110: 0x00c0, 0x111: 0x00c0,
0x112: 0x00c0, 0x113: 0x00c0, 0x114: 0x00c0, 0x115: 0x00c0, 0x116: 0x00c0, 0x117: 0x0080,
0x118: 0x00c0, 0x119: 0x00c0, 0x11a: 0x00c0, 0x11b: 0x00c0, 0x11c: 0x00c0, 0x11d: 0x00c0,
0x11e: 0x00c0, 0x11f: 0x00c0, 0x120: 0x00c0, 0x121: 0x00c0, 0x122: 0x00c0, 0x123: 0x00c0,
0x124: 0x00c0, 0x125: 0x00c0, 0x126: 0x00c0, 0x127: 0x00c0, 0x128: 0x00c0, 0x129: 0x00c0,
0x12a: 0x00c0, 0x12b: 0x00c0, 0x12c: 0x00c0, 0x12d: 0x00c0, 0x12e: 0x00c0, 0x12f: 0x00c0,
0x130: 0x00c0, 0x131: 0x00c0, 0x132: 0x00c0, 0x133: 0x00c0, 0x134: 0x00c0, 0x135: 0x00c0,
0x136: 0x00c0, 0x137: 0x0080, 0x138: 0x00c0, 0x139: 0x00c0, 0x13a: 0x00c0, 0x13b: 0x00c0,
0x13c: 0x00c0, 0x13d: 0x00c0, 0x13e: 0x00c0, 0x13f: 0x00c0,
// Block 0x5, offset 0x140
0x140: 0x00c0, 0x141: 0x00c0, 0x142: 0x00c0, 0x143: 0x00c0, 0x144: 0x00c0, 0x145: 0x00c0,
0x146: 0x00c0, 0x147: 0x00c0, 0x148: 0x00c0, 0x149: 0x00c0, 0x14a: 0x00c0, 0x14b: 0x00c0,
0x14c: 0x00c0, 0x14d: 0x00c0, 0x14e: 0x00c0, 0x14f: 0x00c0, 0x150: 0x00c0, 0x151: 0x00c0,
0x152: 0x00c0, 0x153: 0x00c0, 0x154: 0x00c0, 0x155: 0x00c0, 0x156: 0x00c0, 0x157: 0x00c0,
0x158: 0x00c0, 0x159: 0x00c0, 0x15a: 0x00c0, 0x15b: 0x00c0, 0x15c: 0x00c0, 0x15d: 0x00c0,
0x15e: 0x00c0, 0x15f: 0x00c0, 0x160: 0x00c0, 0x161: 0x00c0, 0x162: 0x00c0, 0x163: 0x00c0,
0x164: 0x00c0, 0x165: 0x00c0, 0x166: 0x00c0, 0x167: 0x00c0, 0x168: 0x00c0, 0x169: 0x00c0,
0x16a: 0x00c0, 0x16b: 0x00c0, 0x16c: 0x00c0, 0x16d: 0x00c0, 0x16e: 0x00c0, 0x16f: 0x00c0,
0x170: 0x00c0, 0x171: 0x00c0, 0x172: 0x0080, 0x173: 0x0080, 0x174: 0x00c0, 0x175: 0x00c0,
0x176: 0x00c0, 0x177: 0x00c0, 0x178: 0x00c0, 0x179: 0x00c0, 0x17a: 0x00c0, 0x17b: 0x00c0,
0x17c: 0x00c0, 0x17d: 0x00c0, 0x17e: 0x00c0, 0x17f: 0x0080,
// Block 0x6, offset 0x180
0x180: 0x0080, 0x181: 0x00c0, 0x182: 0x00c0, 0x183: 0x00c0, 0x184: 0x00c0, 0x185: 0x00c0,
0x186: 0x00c0, 0x187: 0x00c0, 0x188: 0x00c0, 0x189: 0x0080, 0x18a: 0x00c0, 0x18b: 0x00c0,
0x18c: 0x00c0, 0x18d: 0x00c0, 0x18e: 0x00c0, 0x18f: 0x00c0, 0x190: 0x00c0, 0x191: 0x00c0,
0x192: 0x00c0, 0x193: 0x00c0, 0x194: 0x00c0, 0x195: 0x00c0, 0x196: 0x00c0, 0x197: 0x00c0,
0x198: 0x00c0, 0x199: 0x00c0, 0x19a: 0x00c0, 0x19b: 0x00c0, 0x19c: 0x00c0, 0x19d: 0x00c0,
0x19e: 0x00c0, 0x19f: 0x00c0, 0x1a0: 0x00c0, 0x1a1: 0x00c0, 0x1a2: 0x00c0, 0x1a3: 0x00c0,
0x1a4: 0x00c0, 0x1a5: 0x00c0, 0x1a6: 0x00c0, 0x1a7: 0x00c0, 0x1a8: 0x00c0, 0x1a9: 0x00c0,
0x1aa: 0x00c0, 0x1ab: 0x00c0, 0x1ac: 0x00c0, 0x1ad: 0x00c0, 0x1ae: 0x00c0, 0x1af: 0x00c0,
0x1b0: 0x00c0, 0x1b1: 0x00c0, 0x1b2: 0x00c0, 0x1b3: 0x00c0, 0x1b4: 0x00c0, 0x1b5: 0x00c0,
0x1b6: 0x00c0, 0x1b7: 0x00c0, 0x1b8: 0x00c0, 0x1b9: 0x00c0, 0x1ba: 0x00c0, 0x1bb: 0x00c0,
0x1bc: 0x00c0, 0x1bd: 0x00c0, 0x1be: 0x00c0, 0x1bf: 0x0080,
// Block 0x7, offset 0x1c0
0x1c0: 0x00c0, 0x1c1: 0x00c0, 0x1c2: 0x00c0, 0x1c3: 0x00c0, 0x1c4: 0x00c0, 0x1c5: 0x00c0,
0x1c6: 0x00c0, 0x1c7: 0x00c0, 0x1c8: 0x00c0, 0x1c9: 0x00c0, 0x1ca: 0x00c0, 0x1cb: 0x00c0,
0x1cc: 0x00c0, 0x1cd: 0x00c0, 0x1ce: 0x00c0, 0x1cf: 0x00c0, 0x1d0: 0x00c0, 0x1d1: 0x00c0,
0x1d2: 0x00c0, 0x1d3: 0x00c0, 0x1d4: 0x00c0, 0x1d5: 0x00c0, 0x1d6: 0x00c0, 0x1d7: 0x00c0,
0x1d8: 0x00c0, 0x1d9: 0x00c0, 0x1da: 0x00c0, 0x1db: 0x00c0, 0x1dc: 0x00c0, 0x1dd: 0x00c0,
0x1de: 0x00c0, 0x1df: 0x00c0, 0x1e0: 0x00c0, 0x1e1: 0x00c0, 0x1e2: 0x00c0, 0x1e3: 0x00c0,
0x1e4: 0x00c0, 0x1e5: 0x00c0, 0x1e6: 0x00c0, 0x1e7: 0x00c0, 0x1e8: 0x00c0, 0x1e9: 0x00c0,
0x1ea: 0x00c0, 0x1eb: 0x00c0, 0x1ec: 0x00c0, 0x1ed: 0x00c0, 0x1ee: 0x00c0, 0x1ef: 0x00c0,
0x1f0: 0x00c0, 0x1f1: 0x00c0, 0x1f2: 0x00c0, 0x1f3: 0x00c0, 0x1f4: 0x00c0, 0x1f5: 0x00c0,
0x1f6: 0x00c0, 0x1f7: 0x00c0, 0x1f8: 0x00c0, 0x1f9: 0x00c0, 0x1fa: 0x00c0, 0x1fb: 0x00c0,
0x1fc: 0x00c0, 0x1fd: 0x00c0, 0x1fe: 0x00c0, 0x1ff: 0x00c0,
// Block 0x8, offset 0x200
0x200: 0x00c0, 0x201: 0x00c0, 0x202: 0x00c0, 0x203: 0x00c0, 0x204: 0x0080, 0x205: 0x0080,
0x206: 0x0080, 0x207: 0x0080, 0x208: 0x0080, 0x209: 0x0080, 0x20a: 0x0080, 0x20b: 0x0080,
0x20c: 0x0080, 0x20d: 0x00c0, 0x20e: 0x00c0, 0x20f: 0x00c0, 0x210: 0x00c0, 0x211: 0x00c0,
0x212: 0x00c0, 0x213: 0x00c0, 0x214: 0x00c0, 0x215: 0x00c0, 0x216: 0x00c0, 0x217: 0x00c0,
0x218: 0x00c0, 0x219: 0x00c0, 0x21a: 0x00c0, 0x21b: 0x00c0, 0x21c: 0x00c0, 0x21d: 0x00c0,
0x21e: 0x00c0, 0x21f: 0x00c0, 0x220: 0x00c0, 0x221: 0x00c0, 0x222: 0x00c0, 0x223: 0x00c0,
0x224: 0x00c0, 0x225: 0x00c0, 0x226: 0x00c0, 0x227: 0x00c0, 0x228: 0x00c0, 0x229: 0x00c0,
0x22a: 0x00c0, 0x22b: 0x00c0, 0x22c: 0x00c0, 0x22d: 0x00c0, 0x22e: 0x00c0, 0x22f: 0x00c0,
0x230: 0x00c0, 0x231: 0x0080, 0x232: 0x0080, 0x233: 0x0080, 0x234: 0x00c0, 0x235: 0x00c0,
0x236: 0x00c0, 0x237: 0x00c0, 0x238: 0x00c0, 0x239: 0x00c0, 0x23a: 0x00c0, 0x23b: 0x00c0,
0x23c: 0x00c0, 0x23d: 0x00c0, 0x23e: 0x00c0, 0x23f: 0x00c0,
// Block 0x9, offset 0x240
0x240: 0x00c0, 0x241: 0x00c0, 0x242: 0x00c0, 0x243: 0x00c0, 0x244: 0x00c0, 0x245: 0x00c0,
0x246: 0x00c0, 0x247: 0x00c0, 0x248: 0x00c0, 0x249: 0x00c0, 0x24a: 0x00c0, 0x24b: 0x00c0,
0x24c: 0x00c0, 0x24d: 0x00c0, 0x24e: 0x00c0, 0x24f: 0x00c0, 0x250: 0x00c0, 0x251: 0x00c0,
0x252: 0x00c0, 0x253: 0x00c0, 0x254: 0x00c0, 0x255: 0x00c0, 0x256: 0x00c0, 0x257: 0x00c0,
0x258: 0x00c0, 0x259: 0x00c0, 0x25a: 0x00c0, 0x25b: 0x00c0, 0x25c: 0x00c0, 0x25d: 0x00c0,
0x25e: 0x00c0, 0x25f: 0x00c0, 0x260: 0x00c0, 0x261: 0x00c0, 0x262: 0x00c0, 0x263: 0x00c0,
0x264: 0x00c0, 0x265: 0x00c0, 0x266: 0x00c0, 0x267: 0x00c0, 0x268: 0x00c0, 0x269: 0x00c0,
0x26a: 0x00c0, 0x26b: 0x00c0, 0x26c: 0x00c0, 0x26d: 0x00c0, 0x26e: 0x00c0, 0x26f: 0x00c0,
0x270: 0x0080, 0x271: 0x0080, 0x272: 0x0080, 0x273: 0x0080, 0x274: 0x0080, 0x275: 0x0080,
0x276: 0x0080, 0x277: 0x0080, 0x278: 0x0080, 0x279: 0x00c0, 0x27a: 0x00c0, 0x27b: 0x00c0,
0x27c: 0x00c0, 0x27d: 0x00c0, 0x27e: 0x00c0, 0x27f: 0x00c0,
// Block 0xa, offset 0x280
0x280: 0x00c0, 0x281: 0x00c0, 0x282: 0x0080, 0x283: 0x0080, 0x284: 0x0080, 0x285: 0x0080,
0x286: 0x00c0, 0x287: 0x00c0, 0x288: 0x00c0, 0x289: 0x00c0, 0x28a: 0x00c0, 0x28b: 0x00c0,
0x28c: 0x00c0, 0x28d: 0x00c0, 0x28e: 0x00c0, 0x28f: 0x00c0, 0x290: 0x00c0, 0x291: 0x00c0,
0x292: 0x0080, 0x293: 0x0080, 0x294: 0x0080, 0x295: 0x0080, 0x296: 0x0080, 0x297: 0x0080,
0x298: 0x0080, 0x299: 0x0080, 0x29a: 0x0080, 0x29b: 0x0080, 0x29c: 0x0080, 0x29d: 0x0080,
0x29e: 0x0080, 0x29f: 0x0080, 0x2a0: 0x0080, 0x2a1: 0x0080, 0x2a2: 0x0080, 0x2a3: 0x0080,
0x2a4: 0x0080, 0x2a5: 0x0080, 0x2a6: 0x0080, 0x2a7: 0x0080, 0x2a8: 0x0080, 0x2a9: 0x0080,
0x2aa: 0x0080, 0x2ab: 0x0080, 0x2ac: 0x00c0, 0x2ad: 0x0080, 0x2ae: 0x00c0, 0x2af: 0x0080,
0x2b0: 0x0080, 0x2b1: 0x0080, 0x2b2: 0x0080, 0x2b3: 0x0080, 0x2b4: 0x0080, 0x2b5: 0x0080,
0x2b6: 0x0080, 0x2b7: 0x0080, 0x2b8: 0x0080, 0x2b9: 0x0080, 0x2ba: 0x0080, 0x2bb: 0x0080,
0x2bc: 0x0080, 0x2bd: 0x0080, 0x2be: 0x0080, 0x2bf: 0x0080,
// Block 0xb, offset 0x2c0
0x2c0: 0x00c3, 0x2c1: 0x00c3, 0x2c2: 0x00c3, 0x2c3: 0x00c3, 0x2c4: 0x00c3, 0x2c5: 0x00c3,
0x2c6: 0x00c3, 0x2c7: 0x00c3, 0x2c8: 0x00c3, 0x2c9: 0x00c3, 0x2ca: 0x00c3, 0x2cb: 0x00c3,
0x2cc: 0x00c3, 0x2cd: 0x00c3, 0x2ce: 0x00c3, 0x2cf: 0x00c3, 0x2d0: 0x00c3, 0x2d1: 0x00c3,
0x2d2: 0x00c3, 0x2d3: 0x00c3, 0x2d4: 0x00c3, 0x2d5: 0x00c3, 0x2d6: 0x00c3, 0x2d7: 0x00c3,
0x2d8: 0x00c3, 0x2d9: 0x00c3, 0x2da: 0x00c3, 0x2db: 0x00c3, 0x2dc: 0x00c3, 0x2dd: 0x00c3,
0x2de: 0x00c3, 0x2df: 0x00c3, 0x2e0: 0x00c3, 0x2e1: 0x00c3, 0x2e2: 0x00c3, 0x2e3: 0x00c3,
0x2e4: 0x00c3, 0x2e5: 0x00c3, 0x2e6: 0x00c3, 0x2e7: 0x00c3, 0x2e8: 0x00c3, 0x2e9: 0x00c3,
0x2ea: 0x00c3, 0x2eb: 0x00c3, 0x2ec: 0x00c3, 0x2ed: 0x00c3, 0x2ee: 0x00c3, 0x2ef: 0x00c3,
0x2f0: 0x00c3, 0x2f1: 0x00c3, 0x2f2: 0x00c3, 0x2f3: 0x00c3, 0x2f4: 0x00c3, 0x2f5: 0x00c3,
0x2f6: 0x00c3, 0x2f7: 0x00c3, 0x2f8: 0x00c3, 0x2f9: 0x00c3, 0x2fa: 0x00c3, 0x2fb: 0x00c3,
0x2fc: 0x00c3, 0x2fd: 0x00c3, 0x2fe: 0x00c3, 0x2ff: 0x00c3,
// Block 0xc, offset 0x300
0x300: 0x0083, 0x301: 0x0083, 0x302: 0x00c3, 0x303: 0x0083, 0x304: 0x0083, 0x305: 0x00c3,
0x306: 0x00c3, 0x307: 0x00c3, 0x308: 0x00c3, 0x309: 0x00c3, 0x30a: 0x00c3, 0x30b: 0x00c3,
0x30c: 0x00c3, 0x30d: 0x00c3, 0x30e: 0x00c3, 0x30f: 0x0040, 0x310: 0x00c3, 0x311: 0x00c3,
0x312: 0x00c3, 0x313: 0x00c3, 0x314: 0x00c3, 0x315: 0x00c3, 0x316: 0x00c3, 0x317: 0x00c3,
0x318: 0x00c3, 0x319: 0x00c3, 0x31a: 0x00c3, 0x31b: 0x00c3, 0x31c: 0x00c3, 0x31d: 0x00c3,
0x31e: 0x00c3, 0x31f: 0x00c3, 0x320: 0x00c3, 0x321: 0x00c3, 0x322: 0x00c3, 0x323: 0x00c3,
0x324: 0x00c3, 0x325: 0x00c3, 0x326: 0x00c3, 0x327: 0x00c3, 0x328: 0x00c3, 0x329: 0x00c3,
0x32a: 0x00c3, 0x32b: 0x00c3, 0x32c: 0x00c3, 0x32d: 0x00c3, 0x32e: 0x00c3, 0x32f: 0x00c3,
0x330: 0x00c8, 0x331: 0x00c8, 0x332: 0x00c8, 0x333: 0x00c8, 0x334: 0x0080, 0x335: 0x0050,
0x336: 0x00c8, 0x337: 0x00c8, 0x33a: 0x0088, 0x33b: 0x00c8,
0x33c: 0x00c8, 0x33d: 0x00c8, 0x33e: 0x0080, 0x33f: 0x00c8,
// Block 0xd, offset 0x340
0x344: 0x0088, 0x345: 0x0080,
0x346: 0x00c8, 0x347: 0x0080, 0x348: 0x00c8, 0x349: 0x00c8, 0x34a: 0x00c8,
0x34c: 0x00c8, 0x34e: 0x00c8, 0x34f: 0x00c8, 0x350: 0x00c8, 0x351: 0x00c8,
0x352: 0x00c8, 0x353: 0x00c8, 0x354: 0x00c8, 0x355: 0x00c8, 0x356: 0x00c8, 0x357: 0x00c8,
0x358: 0x00c8, 0x359: 0x00c8, 0x35a: 0x00c8, 0x35b: 0x00c8, 0x35c: 0x00c8, 0x35d: 0x00c8,
0x35e: 0x00c8, 0x35f: 0x00c8, 0x360: 0x00c8, 0x361: 0x00c8, 0x363: 0x00c8,
0x364: 0x00c8, 0x365: 0x00c8, 0x366: 0x00c8, 0x367: 0x00c8, 0x368: 0x00c8, 0x369: 0x00c8,
0x36a: 0x00c8, 0x36b: 0x00c8, 0x36c: 0x00c8, 0x36d: 0x00c8, 0x36e: 0x00c8, 0x36f: 0x00c8,
0x370: 0x00c8, 0x371: 0x00c8, 0x372: 0x00c8, 0x373: 0x00c8, 0x374: 0x00c8, 0x375: 0x00c8,
0x376: 0x00c8, 0x377: 0x00c8, 0x378: 0x00c8, 0x379: 0x00c8, 0x37a: 0x00c8, 0x37b: 0x00c8,
0x37c: 0x00c8, 0x37d: 0x00c8, 0x37e: 0x00c8, 0x37f: 0x00c8,
// Block 0xe, offset 0x380
0x380: 0x00c8, 0x381: 0x00c8, 0x382: 0x00c8, 0x383: 0x00c8, 0x384: 0x00c8, 0x385: 0x00c8,
0x386: 0x00c8, 0x387: 0x00c8, 0x388: 0x00c8, 0x389: 0x00c8, 0x38a: 0x00c8, 0x38b: 0x00c8,
0x38c: 0x00c8, 0x38d: 0x00c8, 0x38e: 0x00c8, 0x38f: 0x00c8, 0x390: 0x0088, 0x391: 0x0088,
0x392: 0x0088, 0x393: 0x0088, 0x394: 0x0088, 0x395: 0x0088, 0x396: 0x0088, 0x397: 0x00c8,
0x398: 0x00c8, 0x399: 0x00c8, 0x39a: 0x00c8, 0x39b: 0x00c8, 0x39c: 0x00c8, 0x39d: 0x00c8,
0x39e: 0x00c8, 0x39f: 0x00c8, 0x3a0: 0x00c8, 0x3a1: 0x00c8, 0x3a2: 0x00c0, 0x3a3: 0x00c0,
0x3a4: 0x00c0, 0x3a5: 0x00c0, 0x3a6: 0x00c0, 0x3a7: 0x00c0, 0x3a8: 0x00c0, 0x3a9: 0x00c0,
0x3aa: 0x00c0, 0x3ab: 0x00c0, 0x3ac: 0x00c0, 0x3ad: 0x00c0, 0x3ae: 0x00c0, 0x3af: 0x00c0,
0x3b0: 0x0088, 0x3b1: 0x0088, 0x3b2: 0x0088, 0x3b3: 0x00c8, 0x3b4: 0x0088, 0x3b5: 0x0088,
0x3b6: 0x0088, 0x3b7: 0x00c8, 0x3b8: 0x00c8, 0x3b9: 0x0088, 0x3ba: 0x00c8, 0x3bb: 0x00c8,
0x3bc: 0x00c8, 0x3bd: 0x00c8, 0x3be: 0x00c8, 0x3bf: 0x00c8,
// Block 0xf, offset 0x3c0
0x3c0: 0x00c0, 0x3c1: 0x00c0, 0x3c2: 0x0080, 0x3c3: 0x00c3, 0x3c4: 0x00c3, 0x3c5: 0x00c3,
0x3c6: 0x00c3, 0x3c7: 0x00c3, 0x3c8: 0x0083, 0x3c9: 0x0083, 0x3ca: 0x00c0, 0x3cb: 0x00c0,
0x3cc: 0x00c0, 0x3cd: 0x00c0, 0x3ce: 0x00c0, 0x3cf: 0x00c0, 0x3d0: 0x00c0, 0x3d1: 0x00c0,
0x3d2: 0x00c0, 0x3d3: 0x00c0, 0x3d4: 0x00c0, 0x3d5: 0x00c0, 0x3d6: 0x00c0, 0x3d7: 0x00c0,
0x3d8: 0x00c0, 0x3d9: 0x00c0, 0x3da: 0x00c0, 0x3db: 0x00c0, 0x3dc: 0x00c0, 0x3dd: 0x00c0,
0x3de: 0x00c0, 0x3df: 0x00c0, 0x3e0: 0x00c0, 0x3e1: 0x00c0, 0x3e2: 0x00c0, 0x3e3: 0x00c0,
0x3e4: 0x00c0, 0x3e5: 0x00c0, 0x3e6: 0x00c0, 0x3e7: 0x00c0, 0x3e8: 0x00c0, 0x3e9: 0x00c0,
0x3ea: 0x00c0, 0x3eb: 0x00c0, 0x3ec: 0x00c0, 0x3ed: 0x00c0, 0x3ee: 0x00c0, 0x3ef: 0x00c0,
0x3f0: 0x00c0, 0x3f1: 0x00c0, 0x3f2: 0x00c0, 0x3f3: 0x00c0, 0x3f4: 0x00c0, 0x3f5: 0x00c0,
0x3f6: 0x00c0, 0x3f7: 0x00c0, 0x3f8: 0x00c0, 0x3f9: 0x00c0, 0x3fa: 0x00c0, 0x3fb: 0x00c0,
0x3fc: 0x00c0, 0x3fd: 0x00c0, 0x3fe: 0x00c0, 0x3ff: 0x00c0,
// Block 0x10, offset 0x400
0x400: 0x00c0, 0x401: 0x00c0, 0x402: 0x00c0, 0x403: 0x00c0, 0x404: 0x00c0, 0x405: 0x00c0,
0x406: 0x00c0, 0x407: 0x00c0, 0x408: 0x00c0, 0x409: 0x00c0, 0x40a: 0x00c0, 0x40b: 0x00c0,
0x40c: 0x00c0, 0x40d: 0x00c0, 0x40e: 0x00c0, 0x40f: 0x00c0, 0x410: 0x00c0, 0x411: 0x00c0,
0x412: 0x00c0, 0x413: 0x00c0, 0x414: 0x00c0, 0x415: 0x00c0, 0x416: 0x00c0, 0x417: 0x00c0,
0x418: 0x00c0, 0x419: 0x00c0, 0x41a: 0x00c0, 0x41b: 0x00c0, 0x41c: 0x00c0, 0x41d: 0x00c0,
0x41e: 0x00c0, 0x41f: 0x00c0, 0x420: 0x00c0, 0x421: 0x00c0, 0x422: 0x00c0, 0x423: 0x00c0,
0x424: 0x00c0, 0x425: 0x00c0, 0x426: 0x00c0, 0x427: 0x00c0, 0x428: 0x00c0, 0x429: 0x00c0,
0x42a: 0x00c0, 0x42b: 0x00c0, 0x42c: 0x00c0, 0x42d: 0x00c0, 0x42e: 0x00c0, 0x42f: 0x00c0,
0x431: 0x00c0, 0x432: 0x00c0, 0x433: 0x00c0, 0x434: 0x00c0, 0x435: 0x00c0,
0x436: 0x00c0, 0x437: 0x00c0, 0x438: 0x00c0, 0x439: 0x00c0, 0x43a: 0x00c0, 0x43b: 0x00c0,
0x43c: 0x00c0, 0x43d: 0x00c0, 0x43e: 0x00c0, 0x43f: 0x00c0,
// Block 0x11, offset 0x440
0x440: 0x00c0, 0x441: 0x00c0, 0x442: 0x00c0, 0x443: 0x00c0, 0x444: 0x00c0, 0x445: 0x00c0,
0x446: 0x00c0, 0x447: 0x00c0, 0x448: 0x00c0, 0x449: 0x00c0, 0x44a: 0x00c0, 0x44b: 0x00c0,
0x44c: 0x00c0, 0x44d: 0x00c0, 0x44e: 0x00c0, 0x44f: 0x00c0, 0x450: 0x00c0, 0x451: 0x00c0,
0x452: 0x00c0, 0x453: 0x00c0, 0x454: 0x00c0, 0x455: 0x00c0, 0x456: 0x00c0,
0x459: 0x00c0, 0x45a: 0x0080, 0x45b: 0x0080, 0x45c: 0x0080, 0x45d: 0x0080,
0x45e: 0x0080, 0x45f: 0x0080, 0x460: 0x00c0, 0x461: 0x00c0, 0x462: 0x00c0, 0x463: 0x00c0,
0x464: 0x00c0, 0x465: 0x00c0, 0x466: 0x00c0, 0x467: 0x00c0, 0x468: 0x00c0, 0x469: 0x00c0,
0x46a: 0x00c0, 0x46b: 0x00c0, 0x46c: 0x00c0, 0x46d: 0x00c0, 0x46e: 0x00c0, 0x46f: 0x00c0,
0x470: 0x00c0, 0x471: 0x00c0, 0x472: 0x00c0, 0x473: 0x00c0, 0x474: 0x00c0, 0x475: 0x00c0,
0x476: 0x00c0, 0x477: 0x00c0, 0x478: 0x00c0, 0x479: 0x00c0, 0x47a: 0x00c0, 0x47b: 0x00c0,
0x47c: 0x00c0, 0x47d: 0x00c0, 0x47e: 0x00c0, 0x47f: 0x00c0,
// Block 0x12, offset 0x480
0x480: 0x00c0, 0x481: 0x00c0, 0x482: 0x00c0, 0x483: 0x00c0, 0x484: 0x00c0, 0x485: 0x00c0,
0x486: 0x00c0, 0x487: 0x0080, 0x488: 0x00c0, 0x489: 0x0080, 0x48a: 0x0080,
0x48d: 0x0080, 0x48e: 0x0080, 0x48f: 0x0080, 0x491: 0x00cb,
0x492: 0x00cb, 0x493: 0x00cb, 0x494: 0x00cb, 0x495: 0x00cb, 0x496: 0x00cb, 0x497: 0x00cb,
0x498: 0x00cb, 0x499: 0x00cb, 0x49a: 0x00cb, 0x49b: 0x00cb, 0x49c: 0x00cb, 0x49d: 0x00cb,
0x49e: 0x00cb, 0x49f: 0x00cb, 0x4a0: 0x00cb, 0x4a1: 0x00cb, 0x4a2: 0x00cb, 0x4a3: 0x00cb,
0x4a4: 0x00cb, 0x4a5: 0x00cb, 0x4a6: 0x00cb, 0x4a7: 0x00cb, 0x4a8: 0x00cb, 0x4a9: 0x00cb,
0x4aa: 0x00cb, 0x4ab: 0x00cb, 0x4ac: 0x00cb, 0x4ad: 0x00cb, 0x4ae: 0x00cb, 0x4af: 0x00cb,
0x4b0: 0x00cb, 0x4b1: 0x00cb, 0x4b2: 0x00cb, 0x4b3: 0x00cb, 0x4b4: 0x00cb, 0x4b5: 0x00cb,
0x4b6: 0x00cb, 0x4b7: 0x00cb, 0x4b8: 0x00cb, 0x4b9: 0x00cb, 0x4ba: 0x00cb, 0x4bb: 0x00cb,
0x4bc: 0x00cb, 0x4bd: 0x00cb, 0x4be: 0x008a, 0x4bf: 0x00cb,
// Block 0x13, offset 0x4c0
0x4c0: 0x008a, 0x4c1: 0x00cb, 0x4c2: 0x00cb, 0x4c3: 0x008a, 0x4c4: 0x00cb, 0x4c5: 0x00cb,
0x4c6: 0x008a, 0x4c7: 0x00cb,
0x4d0: 0x00ca, 0x4d1: 0x00ca,
0x4d2: 0x00ca, 0x4d3: 0x00ca, 0x4d4: 0x00ca, 0x4d5: 0x00ca, 0x4d6: 0x00ca, 0x4d7: 0x00ca,
0x4d8: 0x00ca, 0x4d9: 0x00ca, 0x4da: 0x00ca, 0x4db: 0x00ca, 0x4dc: 0x00ca, 0x4dd: 0x00ca,
0x4de: 0x00ca, 0x4df: 0x00ca, 0x4e0: 0x00ca, 0x4e1: 0x00ca, 0x4e2: 0x00ca, 0x4e3: 0x00ca,
0x4e4: 0x00ca, 0x4e5: 0x00ca, 0x4e6: 0x00ca, 0x4e7: 0x00ca, 0x4e8: 0x00ca, 0x4e9: 0x00ca,
0x4ea: 0x00ca, 0x4ef: 0x00ca,
0x4f0: 0x00ca, 0x4f1: 0x00ca, 0x4f2: 0x00ca, 0x4f3: 0x0051, 0x4f4: 0x0051,
// Block 0x14, offset 0x500
0x500: 0x0040, 0x501: 0x0040, 0x502: 0x0040, 0x503: 0x0040, 0x504: 0x0040, 0x505: 0x0040,
0x506: 0x0080, 0x507: 0x0080, 0x508: 0x0080, 0x509: 0x0080, 0x50a: 0x0080, 0x50b: 0x0080,
0x50c: 0x0080, 0x50d: 0x0080, 0x50e: 0x0080, 0x50f: 0x0080, 0x510: 0x00c3, 0x511: 0x00c3,
0x512: 0x00c3, 0x513: 0x00c3, 0x514: 0x00c3, 0x515: 0x00c3, 0x516: 0x00c3, 0x517: 0x00c3,
0x518: 0x00c3, 0x519: 0x00c3, 0x51a: 0x00c3, 0x51b: 0x0080, 0x51c: 0x0040, 0x51d: 0x0080,
0x51e: 0x0080, 0x51f: 0x0080, 0x520: 0x00c2, 0x521: 0x00c0, 0x522: 0x00c4, 0x523: 0x00c4,
0x524: 0x00c4, 0x525: 0x00c4, 0x526: 0x00c2, 0x527: 0x00c4, 0x528: 0x00c2, 0x529: 0x00c4,
0x52a: 0x00c2, 0x52b: 0x00c2, 0x52c: 0x00c2, 0x52d: 0x00c2, 0x52e: 0x00c2, 0x52f: 0x00c4,
0x530: 0x00c4, 0x531: 0x00c4, 0x532: 0x00c4, 0x533: 0x00c2, 0x534: 0x00c2, 0x535: 0x00c2,
0x536: 0x00c2, 0x537: 0x00c2, 0x538: 0x00c2, 0x539: 0x00c2, 0x53a: 0x00c2, 0x53b: 0x00c2,
0x53c: 0x00c2, 0x53d: 0x00c2, 0x53e: 0x00c2, 0x53f: 0x00c2,
// Block 0x15, offset 0x540
0x540: 0x0040, 0x541: 0x00c2, 0x542: 0x00c2, 0x543: 0x00c2, 0x544: 0x00c2, 0x545: 0x00c2,
0x546: 0x00c2, 0x547: 0x00c2, 0x548: 0x00c4, 0x549: 0x00c2, 0x54a: 0x00c2, 0x54b: 0x00c3,
0x54c: 0x00c3, 0x54d: 0x00c3, 0x54e: 0x00c3, 0x54f: 0x00c3, 0x550: 0x00c3, 0x551: 0x00c3,
0x552: 0x00c3, 0x553: 0x00c3, 0x554: 0x00c3, 0x555: 0x00c3, 0x556: 0x00c3, 0x557: 0x00c3,
0x558: 0x00c3, 0x559: 0x00c3, 0x55a: 0x00c3, 0x55b: 0x00c3, 0x55c: 0x00c3, 0x55d: 0x00c3,
0x55e: 0x00c3, 0x55f: 0x00c3, 0x560: 0x0053, 0x561: 0x0053, 0x562: 0x0053, 0x563: 0x0053,
0x564: 0x0053, 0x565: 0x0053, 0x566: 0x0053, 0x567: 0x0053, 0x568: 0x0053, 0x569: 0x0053,
0x56a: 0x0080, 0x56b: 0x0080, 0x56c: 0x0080, 0x56d: 0x0080, 0x56e: 0x00c2, 0x56f: 0x00c2,
0x570: 0x00c3, 0x571: 0x00c4, 0x572: 0x00c4, 0x573: 0x00c4, 0x574: 0x00c0, 0x575: 0x0084,
0x576: 0x0084, 0x577: 0x0084, 0x578: 0x0082, 0x579: 0x00c2, 0x57a: 0x00c2, 0x57b: 0x00c2,
0x57c: 0x00c2, 0x57d: 0x00c2, 0x57e: 0x00c2, 0x57f: 0x00c2,
// Block 0x16, offset 0x580
0x580: 0x00c2, 0x581: 0x00c2, 0x582: 0x00c2, 0x583: 0x00c2, 0x584: 0x00c2, 0x585: 0x00c2,
0x586: 0x00c2, 0x587: 0x00c2, 0x588: 0x00c4, 0x589: 0x00c4, 0x58a: 0x00c4, 0x58b: 0x00c4,
0x58c: 0x00c4, 0x58d: 0x00c4, 0x58e: 0x00c4, 0x58f: 0x00c4, 0x590: 0x00c4, 0x591: 0x00c4,
0x592: 0x00c4, 0x593: 0x00c4, 0x594: 0x00c4, 0x595: 0x00c4, 0x596: 0x00c4, 0x597: 0x00c4,
0x598: 0x00c4, 0x599: 0x00c4, 0x59a: 0x00c2, 0x59b: 0x00c2, 0x59c: 0x00c2, 0x59d: 0x00c2,
0x59e: 0x00c2, 0x59f: 0x00c2, 0x5a0: 0x00c2, 0x5a1: 0x00c2, 0x5a2: 0x00c2, 0x5a3: 0x00c2,
0x5a4: 0x00c2, 0x5a5: 0x00c2, 0x5a6: 0x00c2, 0x5a7: 0x00c2, 0x5a8: 0x00c2, 0x5a9: 0x00c2,
0x5aa: 0x00c2, 0x5ab: 0x00c2, 0x5ac: 0x00c2, 0x5ad: 0x00c2, 0x5ae: 0x00c2, 0x5af: 0x00c2,
0x5b0: 0x00c2, 0x5b1: 0x00c2, 0x5b2: 0x00c2, 0x5b3: 0x00c2, 0x5b4: 0x00c2, 0x5b5: 0x00c2,
0x5b6: 0x00c2, 0x5b7: 0x00c2, 0x5b8: 0x00c2, 0x5b9: 0x00c2, 0x5ba: 0x00c2, 0x5bb: 0x00c2,
0x5bc: 0x00c2, 0x5bd: 0x00c2, 0x5be: 0x00c2, 0x5bf: 0x00c2,
// Block 0x17, offset 0x5c0
0x5c0: 0x00c4, 0x5c1: 0x00c2, 0x5c2: 0x00c2, 0x5c3: 0x00c4, 0x5c4: 0x00c4, 0x5c5: 0x00c4,
0x5c6: 0x00c4, 0x5c7: 0x00c4, 0x5c8: 0x00c4, 0x5c9: 0x00c4, 0x5ca: 0x00c4, 0x5cb: 0x00c4,
0x5cc: 0x00c2, 0x5cd: 0x00c4, 0x5ce: 0x00c2, 0x5cf: 0x00c4, 0x5d0: 0x00c2, 0x5d1: 0x00c2,
0x5d2: 0x00c4, 0x5d3: 0x00c4, 0x5d4: 0x0080, 0x5d5: 0x00c4, 0x5d6: 0x00c3, 0x5d7: 0x00c3,
0x5d8: 0x00c3, 0x5d9: 0x00c3, 0x5da: 0x00c3, 0x5db: 0x00c3, 0x5dc: 0x00c3, 0x5dd: 0x0040,
0x5de: 0x0080, 0x5df: 0x00c3, 0x5e0: 0x00c3, 0x5e1: 0x00c3, 0x5e2: 0x00c3, 0x5e3: 0x00c3,
0x5e4: 0x00c3, 0x5e5: 0x00c0, 0x5e6: 0x00c0, 0x5e7: 0x00c3, 0x5e8: 0x00c3, 0x5e9: 0x0080,
0x5ea: 0x00c3, 0x5eb: 0x00c3, 0x5ec: 0x00c3, 0x5ed: 0x00c3, 0x5ee: 0x00c4, 0x5ef: 0x00c4,
0x5f0: 0x0054, 0x5f1: 0x0054, 0x5f2: 0x0054, 0x5f3: 0x0054, 0x5f4: 0x0054, 0x5f5: 0x0054,
0x5f6: 0x0054, 0x5f7: 0x0054, 0x5f8: 0x0054, 0x5f9: 0x0054, 0x5fa: 0x00c2, 0x5fb: 0x00c2,
0x5fc: 0x00c2, 0x5fd: 0x00c0, 0x5fe: 0x00c0, 0x5ff: 0x00c2,
// Block 0x18, offset 0x600
0x600: 0x0080, 0x601: 0x0080, 0x602: 0x0080, 0x603: 0x0080, 0x604: 0x0080, 0x605: 0x0080,
0x606: 0x0080, 0x607: 0x0080, 0x608: 0x0080, 0x609: 0x0080, 0x60a: 0x0080, 0x60b: 0x0080,
0x60c: 0x0080, 0x60d: 0x0080, 0x60f: 0x0040, 0x610: 0x00c4, 0x611: 0x00c3,
0x612: 0x00c2, 0x613: 0x00c2, 0x614: 0x00c2, 0x615: 0x00c4, 0x616: 0x00c4, 0x617: 0x00c4,
0x618: 0x00c4, 0x619: 0x00c4, 0x61a: 0x00c2, 0x61b: 0x00c2, 0x61c: 0x00c2, 0x61d: 0x00c2,
0x61e: 0x00c4, 0x61f: 0x00c2, 0x620: 0x00c2, 0x621: 0x00c2, 0x622: 0x00c2, 0x623: 0x00c2,
0x624: 0x00c2, 0x625: 0x00c2, 0x626: 0x00c2, 0x627: 0x00c2, 0x628: 0x00c4, 0x629: 0x00c2,
0x62a: 0x00c4, 0x62b: 0x00c2, 0x62c: 0x00c4, 0x62d: 0x00c2, 0x62e: 0x00c2, 0x62f: 0x00c4,
0x630: 0x00c3, 0x631: 0x00c3, 0x632: 0x00c3, 0x633: 0x00c3, 0x634: 0x00c3, 0x635: 0x00c3,
0x636: 0x00c3, 0x637: 0x00c3, 0x638: 0x00c3, 0x639: 0x00c3, 0x63a: 0x00c3, 0x63b: 0x00c3,
0x63c: 0x00c3, 0x63d: 0x00c3, 0x63e: 0x00c3, 0x63f: 0x00c3,
// Block 0x19, offset 0x640
0x640: 0x00c3, 0x641: 0x00c3, 0x642: 0x00c3, 0x643: 0x00c3, 0x644: 0x00c3, 0x645: 0x00c3,
0x646: 0x00c3, 0x647: 0x00c3, 0x648: 0x00c3, 0x649: 0x00c3, 0x64a: 0x00c3,
0x64d: 0x00c4, 0x64e: 0x00c2, 0x64f: 0x00c2, 0x650: 0x00c2, 0x651: 0x00c2,
0x652: 0x00c2, 0x653: 0x00c2, 0x654: 0x00c2, 0x655: 0x00c2, 0x656: 0x00c2, 0x657: 0x00c2,
0x658: 0x00c2, 0x659: 0x00c4, 0x65a: 0x00c4, 0x65b: 0x00c4, 0x65c: 0x00c2, 0x65d: 0x00c2,
0x65e: 0x00c2, 0x65f: 0x00c2, 0x660: 0x00c2, 0x661: 0x00c2, 0x662: 0x00c2, 0x663: 0x00c2,
0x664: 0x00c2, 0x665: 0x00c2, 0x666: 0x00c2, 0x667: 0x00c2, 0x668: 0x00c2, 0x669: 0x00c2,
0x66a: 0x00c2, 0x66b: 0x00c4, 0x66c: 0x00c4, 0x66d: 0x00c2, 0x66e: 0x00c2, 0x66f: 0x00c2,
0x670: 0x00c2, 0x671: 0x00c4, 0x672: 0x00c2, 0x673: 0x00c4, 0x674: 0x00c4, 0x675: 0x00c2,
0x676: 0x00c2, 0x677: 0x00c2, 0x678: 0x00c4, 0x679: 0x00c4, 0x67a: 0x00c2, 0x67b: 0x00c2,
0x67c: 0x00c2, 0x67d: 0x00c2, 0x67e: 0x00c2, 0x67f: 0x00c2,
// Block 0x1a, offset 0x680
0x680: 0x00c0, 0x681: 0x00c0, 0x682: 0x00c0, 0x683: 0x00c0, 0x684: 0x00c0, 0x685: 0x00c0,
0x686: 0x00c0, 0x687: 0x00c0, 0x688: 0x00c0, 0x689: 0x00c0, 0x68a: 0x00c0, 0x68b: 0x00c0,
0x68c: 0x00c0, 0x68d: 0x00c0, 0x68e: 0x00c0, 0x68f: 0x00c0, 0x690: 0x00c0, 0x691: 0x00c0,
0x692: 0x00c0, 0x693: 0x00c0, 0x694: 0x00c0, 0x695: 0x00c0, 0x696: 0x00c0, 0x697: 0x00c0,
0x698: 0x00c0, 0x699: 0x00c0, 0x69a: 0x00c0, 0x69b: 0x00c0, 0x69c: 0x00c0, 0x69d: 0x00c0,
0x69e: 0x00c0, 0x69f: 0x00c0, 0x6a0: 0x00c0, 0x6a1: 0x00c0, 0x6a2: 0x00c0, 0x6a3: 0x00c0,
0x6a4: 0x00c0, 0x6a5: 0x00c0, 0x6a6: 0x00c3, 0x6a7: 0x00c3, 0x6a8: 0x00c3, 0x6a9: 0x00c3,
0x6aa: 0x00c3, 0x6ab: 0x00c3, 0x6ac: 0x00c3, 0x6ad: 0x00c3, 0x6ae: 0x00c3, 0x6af: 0x00c3,
0x6b0: 0x00c3, 0x6b1: 0x00c0,
// Block 0x1b, offset 0x6c0
0x6c0: 0x00c0, 0x6c1: 0x00c0, 0x6c2: 0x00c0, 0x6c3: 0x00c0, 0x6c4: 0x00c0, 0x6c5: 0x00c0,
0x6c6: 0x00c0, 0x6c7: 0x00c0, 0x6c8: 0x00c0, 0x6c9: 0x00c0, 0x6ca: 0x00c2, 0x6cb: 0x00c2,
0x6cc: 0x00c2, 0x6cd: 0x00c2, 0x6ce: 0x00c2, 0x6cf: 0x00c2, 0x6d0: 0x00c2, 0x6d1: 0x00c2,
0x6d2: 0x00c2, 0x6d3: 0x00c2, 0x6d4: 0x00c2, 0x6d5: 0x00c2, 0x6d6: 0x00c2, 0x6d7: 0x00c2,
0x6d8: 0x00c2, 0x6d9: 0x00c2, 0x6da: 0x00c2, 0x6db: 0x00c2, 0x6dc: 0x00c2, 0x6dd: 0x00c2,
0x6de: 0x00c2, 0x6df: 0x00c2, 0x6e0: 0x00c2, 0x6e1: 0x00c2, 0x6e2: 0x00c2, 0x6e3: 0x00c2,
0x6e4: 0x00c2, 0x6e5: 0x00c2, 0x6e6: 0x00c2, 0x6e7: 0x00c2, 0x6e8: 0x00c2, 0x6e9: 0x00c2,
0x6ea: 0x00c2, 0x6eb: 0x00c3, 0x6ec: 0x00c3, 0x6ed: 0x00c3, 0x6ee: 0x00c3, 0x6ef: 0x00c3,
0x6f0: 0x00c3, 0x6f1: 0x00c3, 0x6f2: 0x00c3, 0x6f3: 0x00c3, 0x6f4: 0x00c0, 0x6f5: 0x00c0,
0x6f6: 0x0080, 0x6f7: 0x0080, 0x6f8: 0x0080, 0x6f9: 0x0080, 0x6fa: 0x0040,
0x6fd: 0x00c3, 0x6fe: 0x0080, 0x6ff: 0x0080,
// Block 0x1c, offset 0x700
0x700: 0x00c0, 0x701: 0x00c0, 0x702: 0x00c0, 0x703: 0x00c0, 0x704: 0x00c0, 0x705: 0x00c0,
0x706: 0x00c0, 0x707: 0x00c0, 0x708: 0x00c0, 0x709: 0x00c0, 0x70a: 0x00c0, 0x70b: 0x00c0,
0x70c: 0x00c0, 0x70d: 0x00c0, 0x70e: 0x00c0, 0x70f: 0x00c0, 0x710: 0x00c0, 0x711: 0x00c0,
0x712: 0x00c0, 0x713: 0x00c0, 0x714: 0x00c0, 0x715: 0x00c0, 0x716: 0x00c3, 0x717: 0x00c3,
0x718: 0x00c3, 0x719: 0x00c3, 0x71a: 0x00c0, 0x71b: 0x00c3, 0x71c: 0x00c3, 0x71d: 0x00c3,
0x71e: 0x00c3, 0x71f: 0x00c3, 0x720: 0x00c3, 0x721: 0x00c3, 0x722: 0x00c3, 0x723: 0x00c3,
0x724: 0x00c0, 0x725: 0x00c3, 0x726: 0x00c3, 0x727: 0x00c3, 0x728: 0x00c0, 0x729: 0x00c3,
0x72a: 0x00c3, 0x72b: 0x00c3, 0x72c: 0x00c3, 0x72d: 0x00c3,
0x730: 0x0080, 0x731: 0x0080, 0x732: 0x0080, 0x733: 0x0080, 0x734: 0x0080, 0x735: 0x0080,
0x736: 0x0080, 0x737: 0x0080, 0x738: 0x0080, 0x739: 0x0080, 0x73a: 0x0080, 0x73b: 0x0080,
0x73c: 0x0080, 0x73d: 0x0080, 0x73e: 0x0080,
// Block 0x1d, offset 0x740
0x740: 0x00c4, 0x741: 0x00c2, 0x742: 0x00c2, 0x743: 0x00c2, 0x744: 0x00c2, 0x745: 0x00c2,
0x746: 0x00c4, 0x747: 0x00c4, 0x748: 0x00c2, 0x749: 0x00c4, 0x74a: 0x00c2, 0x74b: 0x00c2,
0x74c: 0x00c2, 0x74d: 0x00c2, 0x74e: 0x00c2, 0x74f: 0x00c2, 0x750: 0x00c2, 0x751: 0x00c2,
0x752: 0x00c2, 0x753: 0x00c2, 0x754: 0x00c4, 0x755: 0x00c2, 0x756: 0x00c4, 0x757: 0x00c4,
0x758: 0x00c4, 0x759: 0x00c3, 0x75a: 0x00c3, 0x75b: 0x00c3,
0x75e: 0x0080, 0x760: 0x00c2, 0x761: 0x00c0, 0x762: 0x00c2, 0x763: 0x00c2,
0x764: 0x00c2, 0x765: 0x00c2, 0x766: 0x00c0, 0x767: 0x00c4, 0x768: 0x00c2, 0x769: 0x00c4,
0x76a: 0x00c4,
0x770: 0x00c4, 0x771: 0x00c4, 0x772: 0x00c4, 0x773: 0x00c4, 0x774: 0x00c4, 0x775: 0x00c4,
0x776: 0x00c4, 0x777: 0x00c4, 0x778: 0x00c4, 0x779: 0x00c4, 0x77a: 0x00c4, 0x77b: 0x00c4,
0x77c: 0x00c4, 0x77d: 0x00c4, 0x77e: 0x00c4, 0x77f: 0x00c4,
// Block 0x1e, offset 0x780
0x780: 0x00c4, 0x781: 0x00c4, 0x782: 0x00c4, 0x783: 0x00c0, 0x784: 0x00c0, 0x785: 0x00c0,
0x786: 0x00c2, 0x787: 0x00c0, 0x788: 0x0080, 0x789: 0x00c2, 0x78a: 0x00c2, 0x78b: 0x00c2,
0x78c: 0x00c2, 0x78d: 0x00c2, 0x78e: 0x00c4, 0x790: 0x0040, 0x791: 0x0040,
0x798: 0x00c3, 0x799: 0x00c3, 0x79a: 0x00c3, 0x79b: 0x00c3, 0x79c: 0x00c3, 0x79d: 0x00c3,
0x79e: 0x00c3, 0x79f: 0x00c3, 0x7a0: 0x00c2, 0x7a1: 0x00c2, 0x7a2: 0x00c2, 0x7a3: 0x00c2,
0x7a4: 0x00c2, 0x7a5: 0x00c2, 0x7a6: 0x00c2, 0x7a7: 0x00c2, 0x7a8: 0x00c2, 0x7a9: 0x00c2,
0x7aa: 0x00c4, 0x7ab: 0x00c4, 0x7ac: 0x00c4, 0x7ad: 0x00c0, 0x7ae: 0x00c4, 0x7af: 0x00c2,
0x7b0: 0x00c2, 0x7b1: 0x00c4, 0x7b2: 0x00c4, 0x7b3: 0x00c2, 0x7b4: 0x00c2, 0x7b5: 0x00c2,
0x7b6: 0x00c2, 0x7b7: 0x00c2, 0x7b8: 0x00c2, 0x7b9: 0x00c4, 0x7ba: 0x00c2, 0x7bb: 0x00c2,
0x7bc: 0x00c2, 0x7bd: 0x00c2, 0x7be: 0x00c2, 0x7bf: 0x00c2,
// Block 0x1f, offset 0x7c0
0x7c0: 0x00c2, 0x7c1: 0x00c2, 0x7c2: 0x00c2, 0x7c3: 0x00c2, 0x7c4: 0x00c2, 0x7c5: 0x00c2,
0x7c6: 0x00c2, 0x7c7: 0x00c2, 0x7c8: 0x00c2, 0x7c9: 0x00c0, 0x7ca: 0x00c3, 0x7cb: 0x00c3,
0x7cc: 0x00c3, 0x7cd: 0x00c3, 0x7ce: 0x00c3, 0x7cf: 0x00c3, 0x7d0: 0x00c3, 0x7d1: 0x00c3,
0x7d2: 0x00c3, 0x7d3: 0x00c3, 0x7d4: 0x00c3, 0x7d5: 0x00c3, 0x7d6: 0x00c3, 0x7d7: 0x00c3,
0x7d8: 0x00c3, 0x7d9: 0x00c3, 0x7da: 0x00c3, 0x7db: 0x00c3, 0x7dc: 0x00c3, 0x7dd: 0x00c3,
0x7de: 0x00c3, 0x7df: 0x00c3, 0x7e0: 0x00c3, 0x7e1: 0x00c3, 0x7e2: 0x0040, 0x7e3: 0x00c3,
0x7e4: 0x00c3, 0x7e5: 0x00c3, 0x7e6: 0x00c3, 0x7e7: 0x00c3, 0x7e8: 0x00c3, 0x7e9: 0x00c3,
0x7ea: 0x00c3, 0x7eb: 0x00c3, 0x7ec: 0x00c3, 0x7ed: 0x00c3, 0x7ee: 0x00c3, 0x7ef: 0x00c3,
0x7f0: 0x00c3, 0x7f1: 0x00c3, 0x7f2: 0x00c3, 0x7f3: 0x00c3, 0x7f4: 0x00c3, 0x7f5: 0x00c3,
0x7f6: 0x00c3, 0x7f7: 0x00c3, 0x7f8: 0x00c3, 0x7f9: 0x00c3, 0x7fa: 0x00c3, 0x7fb: 0x00c3,
0x7fc: 0x00c3, 0x7fd: 0x00c3, 0x7fe: 0x00c3, 0x7ff: 0x00c3,
// Block 0x20, offset 0x800
0x800: 0x00c3, 0x801: 0x00c3, 0x802: 0x00c3, 0x803: 0x00c0, 0x804: 0x00c0, 0x805: 0x00c0,
0x806: 0x00c0, 0x807: 0x00c0, 0x808: 0x00c0, 0x809: 0x00c0, 0x80a: 0x00c0, 0x80b: 0x00c0,
0x80c: 0x00c0, 0x80d: 0x00c0, 0x80e: 0x00c0, 0x80f: 0x00c0, 0x810: 0x00c0, 0x811: 0x00c0,
0x812: 0x00c0, 0x813: 0x00c0, 0x814: 0x00c0, 0x815: 0x00c0, 0x816: 0x00c0, 0x817: 0x00c0,
0x818: 0x00c0, 0x819: 0x00c0, 0x81a: 0x00c0, 0x81b: 0x00c0, 0x81c: 0x00c0, 0x81d: 0x00c0,
0x81e: 0x00c0, 0x81f: 0x00c0, 0x820: 0x00c0, 0x821: 0x00c0, 0x822: 0x00c0, 0x823: 0x00c0,
0x824: 0x00c0, 0x825: 0x00c0, 0x826: 0x00c0, 0x827: 0x00c0, 0x828: 0x00c0, 0x829: 0x00c0,
0x82a: 0x00c0, 0x82b: 0x00c0, 0x82c: 0x00c0, 0x82d: 0x00c0, 0x82e: 0x00c0, 0x82f: 0x00c0,
0x830: 0x00c0, 0x831: 0x00c0, 0x832: 0x00c0, 0x833: 0x00c0, 0x834: 0x00c0, 0x835: 0x00c0,
0x836: 0x00c0, 0x837: 0x00c0, 0x838: 0x00c0, 0x839: 0x00c0, 0x83a: 0x00c3, 0x83b: 0x00c0,
0x83c: 0x00c3, 0x83d: 0x00c0, 0x83e: 0x00c0, 0x83f: 0x00c0,
// Block 0x21, offset 0x840
0x840: 0x00c0, 0x841: 0x00c3, 0x842: 0x00c3, 0x843: 0x00c3, 0x844: 0x00c3, 0x845: 0x00c3,
0x846: 0x00c3, 0x847: 0x00c3, 0x848: 0x00c3, 0x849: 0x00c0, 0x84a: 0x00c0, 0x84b: 0x00c0,
0x84c: 0x00c0, 0x84d: 0x00c6, 0x84e: 0x00c0, 0x84f: 0x00c0, 0x850: 0x00c0, 0x851: 0x00c3,
0x852: 0x00c3, 0x853: 0x00c3, 0x854: 0x00c3, 0x855: 0x00c3, 0x856: 0x00c3, 0x857: 0x00c3,
0x858: 0x0080, 0x859: 0x0080, 0x85a: 0x0080, 0x85b: 0x0080, 0x85c: 0x0080, 0x85d: 0x0080,
0x85e: 0x0080, 0x85f: 0x0080, 0x860: 0x00c0, 0x861: 0x00c0, 0x862: 0x00c3, 0x863: 0x00c3,
0x864: 0x0080, 0x865: 0x0080, 0x866: 0x00c0, 0x867: 0x00c0, 0x868: 0x00c0, 0x869: 0x00c0,
0x86a: 0x00c0, 0x86b: 0x00c0, 0x86c: 0x00c0, 0x86d: 0x00c0, 0x86e: 0x00c0, 0x86f: 0x00c0,
0x870: 0x0080, 0x871: 0x00c0, 0x872: 0x00c0, 0x873: 0x00c0, 0x874: 0x00c0, 0x875: 0x00c0,
0x876: 0x00c0, 0x877: 0x00c0, 0x878: 0x00c0, 0x879: 0x00c0, 0x87a: 0x00c0, 0x87b: 0x00c0,
0x87c: 0x00c0, 0x87d: 0x00c0, 0x87e: 0x00c0, 0x87f: 0x00c0,
// Block 0x22, offset 0x880
0x880: 0x00c0, 0x881: 0x00c3, 0x882: 0x00c0, 0x883: 0x00c0, 0x885: 0x00c0,
0x886: 0x00c0, 0x887: 0x00c0, 0x888: 0x00c0, 0x889: 0x00c0, 0x88a: 0x00c0, 0x88b: 0x00c0,
0x88c: 0x00c0, 0x88f: 0x00c0, 0x890: 0x00c0,
0x893: 0x00c0, 0x894: 0x00c0, 0x895: 0x00c0, 0x896: 0x00c0, 0x897: 0x00c0,
0x898: 0x00c0, 0x899: 0x00c0, 0x89a: 0x00c0, 0x89b: 0x00c0, 0x89c: 0x00c0, 0x89d: 0x00c0,
0x89e: 0x00c0, 0x89f: 0x00c0, 0x8a0: 0x00c0, 0x8a1: 0x00c0, 0x8a2: 0x00c0, 0x8a3: 0x00c0,
0x8a4: 0x00c0, 0x8a5: 0x00c0, 0x8a6: 0x00c0, 0x8a7: 0x00c0, 0x8a8: 0x00c0,
0x8aa: 0x00c0, 0x8ab: 0x00c0, 0x8ac: 0x00c0, 0x8ad: 0x00c0, 0x8ae: 0x00c0, 0x8af: 0x00c0,
0x8b0: 0x00c0, 0x8b2: 0x00c0,
0x8b6: 0x00c0, 0x8b7: 0x00c0, 0x8b8: 0x00c0, 0x8b9: 0x00c0,
0x8bc: 0x00c3, 0x8bd: 0x00c0, 0x8be: 0x00c0, 0x8bf: 0x00c0,
// Block 0x23, offset 0x8c0
0x8c0: 0x00c0, 0x8c1: 0x00c3, 0x8c2: 0x00c3, 0x8c3: 0x00c3, 0x8c4: 0x00c3,
0x8c7: 0x00c0, 0x8c8: 0x00c0, 0x8cb: 0x00c0,
0x8cc: 0x00c0, 0x8cd: 0x00c6, 0x8ce: 0x00c0,
0x8d7: 0x00c0,
0x8dc: 0x0080, 0x8dd: 0x0080,
0x8df: 0x0080, 0x8e0: 0x00c0, 0x8e1: 0x00c0, 0x8e2: 0x00c3, 0x8e3: 0x00c3,
0x8e6: 0x00c0, 0x8e7: 0x00c0, 0x8e8: 0x00c0, 0x8e9: 0x00c0,
0x8ea: 0x00c0, 0x8eb: 0x00c0, 0x8ec: 0x00c0, 0x8ed: 0x00c0, 0x8ee: 0x00c0, 0x8ef: 0x00c0,
0x8f0: 0x00c0, 0x8f1: 0x00c0, 0x8f2: 0x0080, 0x8f3: 0x0080, 0x8f4: 0x0080, 0x8f5: 0x0080,
0x8f6: 0x0080, 0x8f7: 0x0080, 0x8f8: 0x0080, 0x8f9: 0x0080, 0x8fa: 0x0080, 0x8fb: 0x0080,
0x8fc: 0x00c0, 0x8fd: 0x0080, 0x8fe: 0x00c3,
// Block 0x24, offset 0x900
0x901: 0x00c3, 0x902: 0x00c3, 0x903: 0x00c0, 0x905: 0x00c0,
0x906: 0x00c0, 0x907: 0x00c0, 0x908: 0x00c0, 0x909: 0x00c0, 0x90a: 0x00c0,
0x90f: 0x00c0, 0x910: 0x00c0,
0x913: 0x00c0, 0x914: 0x00c0, 0x915: 0x00c0, 0x916: 0x00c0, 0x917: 0x00c0,
0x918: 0x00c0, 0x919: 0x00c0, 0x91a: 0x00c0, 0x91b: 0x00c0, 0x91c: 0x00c0, 0x91d: 0x00c0,
0x91e: 0x00c0, 0x91f: 0x00c0, 0x920: 0x00c0, 0x921: 0x00c0, 0x922: 0x00c0, 0x923: 0x00c0,
0x924: 0x00c0, 0x925: 0x00c0, 0x926: 0x00c0, 0x927: 0x00c0, 0x928: 0x00c0,
0x92a: 0x00c0, 0x92b: 0x00c0, 0x92c: 0x00c0, 0x92d: 0x00c0, 0x92e: 0x00c0, 0x92f: 0x00c0,
0x930: 0x00c0, 0x932: 0x00c0, 0x933: 0x0080, 0x935: 0x00c0,
0x936: 0x0080, 0x938: 0x00c0, 0x939: 0x00c0,
0x93c: 0x00c3, 0x93e: 0x00c0, 0x93f: 0x00c0,
// Block 0x25, offset 0x940
0x940: 0x00c0, 0x941: 0x00c3, 0x942: 0x00c3,
0x947: 0x00c3, 0x948: 0x00c3, 0x94b: 0x00c3,
0x94c: 0x00c3, 0x94d: 0x00c6, 0x951: 0x00c3,
0x959: 0x0080, 0x95a: 0x0080, 0x95b: 0x0080, 0x95c: 0x00c0,
0x95e: 0x0080,
0x966: 0x00c0, 0x967: 0x00c0, 0x968: 0x00c0, 0x969: 0x00c0,
0x96a: 0x00c0, 0x96b: 0x00c0, 0x96c: 0x00c0, 0x96d: 0x00c0, 0x96e: 0x00c0, 0x96f: 0x00c0,
0x970: 0x00c3, 0x971: 0x00c3, 0x972: 0x00c0, 0x973: 0x00c0, 0x974: 0x00c0, 0x975: 0x00c3,
0x976: 0x0080,
// Block 0x26, offset 0x980
0x981: 0x00c3, 0x982: 0x00c3, 0x983: 0x00c0, 0x985: 0x00c0,
0x986: 0x00c0, 0x987: 0x00c0, 0x988: 0x00c0, 0x989: 0x00c0, 0x98a: 0x00c0, 0x98b: 0x00c0,
0x98c: 0x00c0, 0x98d: 0x00c0, 0x98f: 0x00c0, 0x990: 0x00c0, 0x991: 0x00c0,
0x993: 0x00c0, 0x994: 0x00c0, 0x995: 0x00c0, 0x996: 0x00c0, 0x997: 0x00c0,
0x998: 0x00c0, 0x999: 0x00c0, 0x99a: 0x00c0, 0x99b: 0x00c0, 0x99c: 0x00c0, 0x99d: 0x00c0,
0x99e: 0x00c0, 0x99f: 0x00c0, 0x9a0: 0x00c0, 0x9a1: 0x00c0, 0x9a2: 0x00c0, 0x9a3: 0x00c0,
0x9a4: 0x00c0, 0x9a5: 0x00c0, 0x9a6: 0x00c0, 0x9a7: 0x00c0, 0x9a8: 0x00c0,
0x9aa: 0x00c0, 0x9ab: 0x00c0, 0x9ac: 0x00c0, 0x9ad: 0x00c0, 0x9ae: 0x00c0, 0x9af: 0x00c0,
0x9b0: 0x00c0, 0x9b2: 0x00c0, 0x9b3: 0x00c0, 0x9b5: 0x00c0,
0x9b6: 0x00c0, 0x9b7: 0x00c0, 0x9b8: 0x00c0, 0x9b9: 0x00c0,
0x9bc: 0x00c3, 0x9bd: 0x00c0, 0x9be: 0x00c0, 0x9bf: 0x00c0,
// Block 0x27, offset 0x9c0
0x9c0: 0x00c0, 0x9c1: 0x00c3, 0x9c2: 0x00c3, 0x9c3: 0x00c3, 0x9c4: 0x00c3, 0x9c5: 0x00c3,
0x9c7: 0x00c3, 0x9c8: 0x00c3, 0x9c9: 0x00c0, 0x9cb: 0x00c0,
0x9cc: 0x00c0, 0x9cd: 0x00c6, 0x9d0: 0x00c0,
0x9e0: 0x00c0, 0x9e1: 0x00c0, 0x9e2: 0x00c3, 0x9e3: 0x00c3,
0x9e6: 0x00c0, 0x9e7: 0x00c0, 0x9e8: 0x00c0, 0x9e9: 0x00c0,
0x9ea: 0x00c0, 0x9eb: 0x00c0, 0x9ec: 0x00c0, 0x9ed: 0x00c0, 0x9ee: 0x00c0, 0x9ef: 0x00c0,
0x9f0: 0x0080, 0x9f1: 0x0080,
0x9f9: 0x00c0, 0x9fa: 0x00c3, 0x9fb: 0x00c3,
0x9fc: 0x00c3, 0x9fd: 0x00c3, 0x9fe: 0x00c3, 0x9ff: 0x00c3,
// Block 0x28, offset 0xa00
0xa01: 0x00c3, 0xa02: 0x00c0, 0xa03: 0x00c0, 0xa05: 0x00c0,
0xa06: 0x00c0, 0xa07: 0x00c0, 0xa08: 0x00c0, 0xa09: 0x00c0, 0xa0a: 0x00c0, 0xa0b: 0x00c0,
0xa0c: 0x00c0, 0xa0f: 0x00c0, 0xa10: 0x00c0,
0xa13: 0x00c0, 0xa14: 0x00c0, 0xa15: 0x00c0, 0xa16: 0x00c0, 0xa17: 0x00c0,
0xa18: 0x00c0, 0xa19: 0x00c0, 0xa1a: 0x00c0, 0xa1b: 0x00c0, 0xa1c: 0x00c0, 0xa1d: 0x00c0,
0xa1e: 0x00c0, 0xa1f: 0x00c0, 0xa20: 0x00c0, 0xa21: 0x00c0, 0xa22: 0x00c0, 0xa23: 0x00c0,
0xa24: 0x00c0, 0xa25: 0x00c0, 0xa26: 0x00c0, 0xa27: 0x00c0, 0xa28: 0x00c0,
0xa2a: 0x00c0, 0xa2b: 0x00c0, 0xa2c: 0x00c0, 0xa2d: 0x00c0, 0xa2e: 0x00c0, 0xa2f: 0x00c0,
0xa30: 0x00c0, 0xa32: 0x00c0, 0xa33: 0x00c0, 0xa35: 0x00c0,
0xa36: 0x00c0, 0xa37: 0x00c0, 0xa38: 0x00c0, 0xa39: 0x00c0,
0xa3c: 0x00c3, 0xa3d: 0x00c0, 0xa3e: 0x00c0, 0xa3f: 0x00c3,
// Block 0x29, offset 0xa40
0xa40: 0x00c0, 0xa41: 0x00c3, 0xa42: 0x00c3, 0xa43: 0x00c3, 0xa44: 0x00c3,
0xa47: 0x00c0, 0xa48: 0x00c0, 0xa4b: 0x00c0,
0xa4c: 0x00c0, 0xa4d: 0x00c6,
0xa55: 0x00c3, 0xa56: 0x00c3, 0xa57: 0x00c0,
0xa5c: 0x0080, 0xa5d: 0x0080,
0xa5f: 0x00c0, 0xa60: 0x00c0, 0xa61: 0x00c0, 0xa62: 0x00c3, 0xa63: 0x00c3,
0xa66: 0x00c0, 0xa67: 0x00c0, 0xa68: 0x00c0, 0xa69: 0x00c0,
0xa6a: 0x00c0, 0xa6b: 0x00c0, 0xa6c: 0x00c0, 0xa6d: 0x00c0, 0xa6e: 0x00c0, 0xa6f: 0x00c0,
0xa70: 0x0080, 0xa71: 0x00c0, 0xa72: 0x0080, 0xa73: 0x0080, 0xa74: 0x0080, 0xa75: 0x0080,
0xa76: 0x0080, 0xa77: 0x0080,
// Block 0x2a, offset 0xa80
0xa82: 0x00c3, 0xa83: 0x00c0, 0xa85: 0x00c0,
0xa86: 0x00c0, 0xa87: 0x00c0, 0xa88: 0x00c0, 0xa89: 0x00c0, 0xa8a: 0x00c0,
0xa8e: 0x00c0, 0xa8f: 0x00c0, 0xa90: 0x00c0,
0xa92: 0x00c0, 0xa93: 0x00c0, 0xa94: 0x00c0, 0xa95: 0x00c0,
0xa99: 0x00c0, 0xa9a: 0x00c0, 0xa9c: 0x00c0,
0xa9e: 0x00c0, 0xa9f: 0x00c0, 0xaa3: 0x00c0,
0xaa4: 0x00c0, 0xaa8: 0x00c0, 0xaa9: 0x00c0,
0xaaa: 0x00c0, 0xaae: 0x00c0, 0xaaf: 0x00c0,
0xab0: 0x00c0, 0xab1: 0x00c0, 0xab2: 0x00c0, 0xab3: 0x00c0, 0xab4: 0x00c0, 0xab5: 0x00c0,
0xab6: 0x00c0, 0xab7: 0x00c0, 0xab8: 0x00c0, 0xab9: 0x00c0,
0xabe: 0x00c0, 0xabf: 0x00c0,
// Block 0x2b, offset 0xac0
0xac0: 0x00c3, 0xac1: 0x00c0, 0xac2: 0x00c0,
0xac6: 0x00c0, 0xac7: 0x00c0, 0xac8: 0x00c0, 0xaca: 0x00c0, 0xacb: 0x00c0,
0xacc: 0x00c0, 0xacd: 0x00c6, 0xad0: 0x00c0,
0xad7: 0x00c0,
0xae6: 0x00c0, 0xae7: 0x00c0, 0xae8: 0x00c0, 0xae9: 0x00c0,
0xaea: 0x00c0, 0xaeb: 0x00c0, 0xaec: 0x00c0, 0xaed: 0x00c0, 0xaee: 0x00c0, 0xaef: 0x00c0,
0xaf0: 0x0080, 0xaf1: 0x0080, 0xaf2: 0x0080, 0xaf3: 0x0080, 0xaf4: 0x0080, 0xaf5: 0x0080,
0xaf6: 0x0080, 0xaf7: 0x0080, 0xaf8: 0x0080, 0xaf9: 0x0080, 0xafa: 0x0080,
// Block 0x2c, offset 0xb00
0xb00: 0x00c3, 0xb01: 0x00c0, 0xb02: 0x00c0, 0xb03: 0x00c0, 0xb04: 0x00c3, 0xb05: 0x00c0,
0xb06: 0x00c0, 0xb07: 0x00c0, 0xb08: 0x00c0, 0xb09: 0x00c0, 0xb0a: 0x00c0, 0xb0b: 0x00c0,
0xb0c: 0x00c0, 0xb0e: 0x00c0, 0xb0f: 0x00c0, 0xb10: 0x00c0,
0xb12: 0x00c0, 0xb13: 0x00c0, 0xb14: 0x00c0, 0xb15: 0x00c0, 0xb16: 0x00c0, 0xb17: 0x00c0,
0xb18: 0x00c0, 0xb19: 0x00c0, 0xb1a: 0x00c0, 0xb1b: 0x00c0, 0xb1c: 0x00c0, 0xb1d: 0x00c0,
0xb1e: 0x00c0, 0xb1f: 0x00c0, 0xb20: 0x00c0, 0xb21: 0x00c0, 0xb22: 0x00c0, 0xb23: 0x00c0,
0xb24: 0x00c0, 0xb25: 0x00c0, 0xb26: 0x00c0, 0xb27: 0x00c0, 0xb28: 0x00c0,
0xb2a: 0x00c0, 0xb2b: 0x00c0, 0xb2c: 0x00c0, 0xb2d: 0x00c0, 0xb2e: 0x00c0, 0xb2f: 0x00c0,
0xb30: 0x00c0, 0xb31: 0x00c0, 0xb32: 0x00c0, 0xb33: 0x00c0, 0xb34: 0x00c0, 0xb35: 0x00c0,
0xb36: 0x00c0, 0xb37: 0x00c0, 0xb38: 0x00c0, 0xb39: 0x00c0,
0xb3c: 0x00c3, 0xb3d: 0x00c0, 0xb3e: 0x00c3, 0xb3f: 0x00c3,
// Block 0x2d, offset 0xb40
0xb40: 0x00c3, 0xb41: 0x00c0, 0xb42: 0x00c0, 0xb43: 0x00c0, 0xb44: 0x00c0,
0xb46: 0x00c3, 0xb47: 0x00c3, 0xb48: 0x00c3, 0xb4a: 0x00c3, 0xb4b: 0x00c3,
0xb4c: 0x00c3, 0xb4d: 0x00c6,
0xb55: 0x00c3, 0xb56: 0x00c3,
0xb58: 0x00c0, 0xb59: 0x00c0, 0xb5a: 0x00c0, 0xb5d: 0x00c0,
0xb60: 0x00c0, 0xb61: 0x00c0, 0xb62: 0x00c3, 0xb63: 0x00c3,
0xb66: 0x00c0, 0xb67: 0x00c0, 0xb68: 0x00c0, 0xb69: 0x00c0,
0xb6a: 0x00c0, 0xb6b: 0x00c0, 0xb6c: 0x00c0, 0xb6d: 0x00c0, 0xb6e: 0x00c0, 0xb6f: 0x00c0,
0xb77: 0x0080, 0xb78: 0x0080, 0xb79: 0x0080, 0xb7a: 0x0080, 0xb7b: 0x0080,
0xb7c: 0x0080, 0xb7d: 0x0080, 0xb7e: 0x0080, 0xb7f: 0x0080,
// Block 0x2e, offset 0xb80
0xb80: 0x00c0, 0xb81: 0x00c3, 0xb82: 0x00c0, 0xb83: 0x00c0, 0xb84: 0x0080, 0xb85: 0x00c0,
0xb86: 0x00c0, 0xb87: 0x00c0, 0xb88: 0x00c0, 0xb89: 0x00c0, 0xb8a: 0x00c0, 0xb8b: 0x00c0,
0xb8c: 0x00c0, 0xb8e: 0x00c0, 0xb8f: 0x00c0, 0xb90: 0x00c0,
0xb92: 0x00c0, 0xb93: 0x00c0, 0xb94: 0x00c0, 0xb95: 0x00c0, 0xb96: 0x00c0, 0xb97: 0x00c0,
0xb98: 0x00c0, 0xb99: 0x00c0, 0xb9a: 0x00c0, 0xb9b: 0x00c0, 0xb9c: 0x00c0, 0xb9d: 0x00c0,
0xb9e: 0x00c0, 0xb9f: 0x00c0, 0xba0: 0x00c0, 0xba1: 0x00c0, 0xba2: 0x00c0, 0xba3: 0x00c0,
0xba4: 0x00c0, 0xba5: 0x00c0, 0xba6: 0x00c0, 0xba7: 0x00c0, 0xba8: 0x00c0,
0xbaa: 0x00c0, 0xbab: 0x00c0, 0xbac: 0x00c0, 0xbad: 0x00c0, 0xbae: 0x00c0, 0xbaf: 0x00c0,
0xbb0: 0x00c0, 0xbb1: 0x00c0, 0xbb2: 0x00c0, 0xbb3: 0x00c0, 0xbb5: 0x00c0,
0xbb6: 0x00c0, 0xbb7: 0x00c0, 0xbb8: 0x00c0, 0xbb9: 0x00c0,
0xbbc: 0x00c3, 0xbbd: 0x00c0, 0xbbe: 0x00c0, 0xbbf: 0x00c3,
// Block 0x2f, offset 0xbc0
0xbc0: 0x00c0, 0xbc1: 0x00c0, 0xbc2: 0x00c0, 0xbc3: 0x00c0, 0xbc4: 0x00c0,
0xbc6: 0x00c3, 0xbc7: 0x00c0, 0xbc8: 0x00c0, 0xbca: 0x00c0, 0xbcb: 0x00c0,
0xbcc: 0x00c3, 0xbcd: 0x00c6,
0xbd5: 0x00c0, 0xbd6: 0x00c0,
0xbdd: 0x00c0,
0xbde: 0x00c0, 0xbe0: 0x00c0, 0xbe1: 0x00c0, 0xbe2: 0x00c3, 0xbe3: 0x00c3,
0xbe6: 0x00c0, 0xbe7: 0x00c0, 0xbe8: 0x00c0, 0xbe9: 0x00c0,
0xbea: 0x00c0, 0xbeb: 0x00c0, 0xbec: 0x00c0, 0xbed: 0x00c0, 0xbee: 0x00c0, 0xbef: 0x00c0,
0xbf1: 0x00c0, 0xbf2: 0x00c0, 0xbf3: 0x00c0,
// Block 0x30, offset 0xc00
0xc00: 0x00c3, 0xc01: 0x00c3, 0xc02: 0x00c0, 0xc03: 0x00c0, 0xc04: 0x00c0, 0xc05: 0x00c0,
0xc06: 0x00c0, 0xc07: 0x00c0, 0xc08: 0x00c0, 0xc09: 0x00c0, 0xc0a: 0x00c0, 0xc0b: 0x00c0,
0xc0c: 0x00c0, 0xc0e: 0x00c0, 0xc0f: 0x00c0, 0xc10: 0x00c0,
0xc12: 0x00c0, 0xc13: 0x00c0, 0xc14: 0x00c0, 0xc15: 0x00c0, 0xc16: 0x00c0, 0xc17: 0x00c0,
0xc18: 0x00c0, 0xc19: 0x00c0, 0xc1a: 0x00c0, 0xc1b: 0x00c0, 0xc1c: 0x00c0, 0xc1d: 0x00c0,
0xc1e: 0x00c0, 0xc1f: 0x00c0, 0xc20: 0x00c0, 0xc21: 0x00c0, 0xc22: 0x00c0, 0xc23: 0x00c0,
0xc24: 0x00c0, 0xc25: 0x00c0, 0xc26: 0x00c0, 0xc27: 0x00c0, 0xc28: 0x00c0, 0xc29: 0x00c0,
0xc2a: 0x00c0, 0xc2b: 0x00c0, 0xc2c: 0x00c0, 0xc2d: 0x00c0, 0xc2e: 0x00c0, 0xc2f: 0x00c0,
0xc30: 0x00c0, 0xc31: 0x00c0, 0xc32: 0x00c0, 0xc33: 0x00c0, 0xc34: 0x00c0, 0xc35: 0x00c0,
0xc36: 0x00c0, 0xc37: 0x00c0, 0xc38: 0x00c0, 0xc39: 0x00c0, 0xc3a: 0x00c0, 0xc3b: 0x00c6,
0xc3c: 0x00c6, 0xc3d: 0x00c0, 0xc3e: 0x00c0, 0xc3f: 0x00c0,
// Block 0x31, offset 0xc40
0xc40: 0x00c0, 0xc41: 0x00c3, 0xc42: 0x00c3, 0xc43: 0x00c3, 0xc44: 0x00c3,
0xc46: 0x00c0, 0xc47: 0x00c0, 0xc48: 0x00c0, 0xc4a: 0x00c0, 0xc4b: 0x00c0,
0xc4c: 0x00c0, 0xc4d: 0x00c6, 0xc4e: 0x00c0, 0xc4f: 0x0080,
0xc54: 0x00c0, 0xc55: 0x00c0, 0xc56: 0x00c0, 0xc57: 0x00c0,
0xc58: 0x0080, 0xc59: 0x0080, 0xc5a: 0x0080, 0xc5b: 0x0080, 0xc5c: 0x0080, 0xc5d: 0x0080,
0xc5e: 0x0080, 0xc5f: 0x00c0, 0xc60: 0x00c0, 0xc61: 0x00c0, 0xc62: 0x00c3, 0xc63: 0x00c3,
0xc66: 0x00c0, 0xc67: 0x00c0, 0xc68: 0x00c0, 0xc69: 0x00c0,
0xc6a: 0x00c0, 0xc6b: 0x00c0, 0xc6c: 0x00c0, 0xc6d: 0x00c0, 0xc6e: 0x00c0, 0xc6f: 0x00c0,
0xc70: 0x0080, 0xc71: 0x0080, 0xc72: 0x0080, 0xc73: 0x0080, 0xc74: 0x0080, 0xc75: 0x0080,
0xc76: 0x0080, 0xc77: 0x0080, 0xc78: 0x0080, 0xc79: 0x0080, 0xc7a: 0x00c0, 0xc7b: 0x00c0,
0xc7c: 0x00c0, 0xc7d: 0x00c0, 0xc7e: 0x00c0, 0xc7f: 0x00c0,
// Block 0x32, offset 0xc80
0xc81: 0x00c3, 0xc82: 0x00c0, 0xc83: 0x00c0, 0xc85: 0x00c0,
0xc86: 0x00c0, 0xc87: 0x00c0, 0xc88: 0x00c0, 0xc89: 0x00c0, 0xc8a: 0x00c0, 0xc8b: 0x00c0,
0xc8c: 0x00c0, 0xc8d: 0x00c0, 0xc8e: 0x00c0, 0xc8f: 0x00c0, 0xc90: 0x00c0, 0xc91: 0x00c0,
0xc92: 0x00c0, 0xc93: 0x00c0, 0xc94: 0x00c0, 0xc95: 0x00c0, 0xc96: 0x00c0,
0xc9a: 0x00c0, 0xc9b: 0x00c0, 0xc9c: 0x00c0, 0xc9d: 0x00c0,
0xc9e: 0x00c0, 0xc9f: 0x00c0, 0xca0: 0x00c0, 0xca1: 0x00c0, 0xca2: 0x00c0, 0xca3: 0x00c0,
0xca4: 0x00c0, 0xca5: 0x00c0, 0xca6: 0x00c0, 0xca7: 0x00c0, 0xca8: 0x00c0, 0xca9: 0x00c0,
0xcaa: 0x00c0, 0xcab: 0x00c0, 0xcac: 0x00c0, 0xcad: 0x00c0, 0xcae: 0x00c0, 0xcaf: 0x00c0,
0xcb0: 0x00c0, 0xcb1: 0x00c0, 0xcb3: 0x00c0, 0xcb4: 0x00c0, 0xcb5: 0x00c0,
0xcb6: 0x00c0, 0xcb7: 0x00c0, 0xcb8: 0x00c0, 0xcb9: 0x00c0, 0xcba: 0x00c0, 0xcbb: 0x00c0,
0xcbd: 0x00c0,
// Block 0x33, offset 0xcc0
0xcc0: 0x00c0, 0xcc1: 0x00c0, 0xcc2: 0x00c0, 0xcc3: 0x00c0, 0xcc4: 0x00c0, 0xcc5: 0x00c0,
0xcc6: 0x00c0, 0xcca: 0x00c6,
0xccf: 0x00c0, 0xcd0: 0x00c0, 0xcd1: 0x00c0,
0xcd2: 0x00c3, 0xcd3: 0x00c3, 0xcd4: 0x00c3, 0xcd6: 0x00c3,
0xcd8: 0x00c0, 0xcd9: 0x00c0, 0xcda: 0x00c0, 0xcdb: 0x00c0, 0xcdc: 0x00c0, 0xcdd: 0x00c0,
0xcde: 0x00c0, 0xcdf: 0x00c0,
0xce6: 0x00c0, 0xce7: 0x00c0, 0xce8: 0x00c0, 0xce9: 0x00c0,
0xcea: 0x00c0, 0xceb: 0x00c0, 0xcec: 0x00c0, 0xced: 0x00c0, 0xcee: 0x00c0, 0xcef: 0x00c0,
0xcf2: 0x00c0, 0xcf3: 0x00c0, 0xcf4: 0x0080,
// Block 0x34, offset 0xd00
0xd01: 0x00c0, 0xd02: 0x00c0, 0xd03: 0x00c0, 0xd04: 0x00c0, 0xd05: 0x00c0,
0xd06: 0x00c0, 0xd07: 0x00c0, 0xd08: 0x00c0, 0xd09: 0x00c0, 0xd0a: 0x00c0, 0xd0b: 0x00c0,
0xd0c: 0x00c0, 0xd0d: 0x00c0, 0xd0e: 0x00c0, 0xd0f: 0x00c0, 0xd10: 0x00c0, 0xd11: 0x00c0,
0xd12: 0x00c0, 0xd13: 0x00c0, 0xd14: 0x00c0, 0xd15: 0x00c0, 0xd16: 0x00c0, 0xd17: 0x00c0,
0xd18: 0x00c0, 0xd19: 0x00c0, 0xd1a: 0x00c0, 0xd1b: 0x00c0, 0xd1c: 0x00c0, 0xd1d: 0x00c0,
0xd1e: 0x00c0, 0xd1f: 0x00c0, 0xd20: 0x00c0, 0xd21: 0x00c0, 0xd22: 0x00c0, 0xd23: 0x00c0,
0xd24: 0x00c0, 0xd25: 0x00c0, 0xd26: 0x00c0, 0xd27: 0x00c0, 0xd28: 0x00c0, 0xd29: 0x00c0,
0xd2a: 0x00c0, 0xd2b: 0x00c0, 0xd2c: 0x00c0, 0xd2d: 0x00c0, 0xd2e: 0x00c0, 0xd2f: 0x00c0,
0xd30: 0x00c0, 0xd31: 0x00c3, 0xd32: 0x00c0, 0xd33: 0x0080, 0xd34: 0x00c3, 0xd35: 0x00c3,
0xd36: 0x00c3, 0xd37: 0x00c3, 0xd38: 0x00c3, 0xd39: 0x00c3, 0xd3a: 0x00c6,
0xd3f: 0x0080,
// Block 0x35, offset 0xd40
0xd40: 0x00c0, 0xd41: 0x00c0, 0xd42: 0x00c0, 0xd43: 0x00c0, 0xd44: 0x00c0, 0xd45: 0x00c0,
0xd46: 0x00c0, 0xd47: 0x00c3, 0xd48: 0x00c3, 0xd49: 0x00c3, 0xd4a: 0x00c3, 0xd4b: 0x00c3,
0xd4c: 0x00c3, 0xd4d: 0x00c3, 0xd4e: 0x00c3, 0xd4f: 0x0080, 0xd50: 0x00c0, 0xd51: 0x00c0,
0xd52: 0x00c0, 0xd53: 0x00c0, 0xd54: 0x00c0, 0xd55: 0x00c0, 0xd56: 0x00c0, 0xd57: 0x00c0,
0xd58: 0x00c0, 0xd59: 0x00c0, 0xd5a: 0x0080, 0xd5b: 0x0080,
// Block 0x36, offset 0xd80
0xd81: 0x00c0, 0xd82: 0x00c0, 0xd84: 0x00c0,
0xd86: 0x00c0, 0xd87: 0x00c0, 0xd88: 0x00c0, 0xd89: 0x00c0, 0xd8a: 0x00c0,
0xd8c: 0x00c0, 0xd8d: 0x00c0, 0xd8e: 0x00c0, 0xd8f: 0x00c0, 0xd90: 0x00c0, 0xd91: 0x00c0,
0xd92: 0x00c0, 0xd93: 0x00c0, 0xd94: 0x00c0, 0xd95: 0x00c0, 0xd96: 0x00c0, 0xd97: 0x00c0,
0xd98: 0x00c0, 0xd99: 0x00c0, 0xd9a: 0x00c0, 0xd9b: 0x00c0, 0xd9c: 0x00c0, 0xd9d: 0x00c0,
0xd9e: 0x00c0, 0xd9f: 0x00c0, 0xda0: 0x00c0, 0xda1: 0x00c0, 0xda2: 0x00c0, 0xda3: 0x00c0,
0xda5: 0x00c0, 0xda7: 0x00c0, 0xda8: 0x00c0, 0xda9: 0x00c0,
0xdaa: 0x00c0, 0xdab: 0x00c0, 0xdac: 0x00c0, 0xdad: 0x00c0, 0xdae: 0x00c0, 0xdaf: 0x00c0,
0xdb0: 0x00c0, 0xdb1: 0x00c3, 0xdb2: 0x00c0, 0xdb3: 0x0080, 0xdb4: 0x00c3, 0xdb5: 0x00c3,
0xdb6: 0x00c3, 0xdb7: 0x00c3, 0xdb8: 0x00c3, 0xdb9: 0x00c3, 0xdba: 0x00c6, 0xdbb: 0x00c3,
0xdbc: 0x00c3, 0xdbd: 0x00c0,
// Block 0x37, offset 0xdc0
0xdc0: 0x00c0, 0xdc1: 0x00c0, 0xdc2: 0x00c0, 0xdc3: 0x00c0, 0xdc4: 0x00c0,
0xdc6: 0x00c0, 0xdc8: 0x00c3, 0xdc9: 0x00c3, 0xdca: 0x00c3, 0xdcb: 0x00c3,
0xdcc: 0x00c3, 0xdcd: 0x00c3, 0xdce: 0x00c3, 0xdd0: 0x00c0, 0xdd1: 0x00c0,
0xdd2: 0x00c0, 0xdd3: 0x00c0, 0xdd4: 0x00c0, 0xdd5: 0x00c0, 0xdd6: 0x00c0, 0xdd7: 0x00c0,
0xdd8: 0x00c0, 0xdd9: 0x00c0, 0xddc: 0x0080, 0xddd: 0x0080,
0xdde: 0x00c0, 0xddf: 0x00c0,
// Block 0x38, offset 0xe00
0xe00: 0x00c0, 0xe01: 0x0080, 0xe02: 0x0080, 0xe03: 0x0080, 0xe04: 0x0080, 0xe05: 0x0080,
0xe06: 0x0080, 0xe07: 0x0080, 0xe08: 0x0080, 0xe09: 0x0080, 0xe0a: 0x0080, 0xe0b: 0x00c0,
0xe0c: 0x0080, 0xe0d: 0x0080, 0xe0e: 0x0080, 0xe0f: 0x0080, 0xe10: 0x0080, 0xe11: 0x0080,
0xe12: 0x0080, 0xe13: 0x0080, 0xe14: 0x0080, 0xe15: 0x0080, 0xe16: 0x0080, 0xe17: 0x0080,
0xe18: 0x00c3, 0xe19: 0x00c3, 0xe1a: 0x0080, 0xe1b: 0x0080, 0xe1c: 0x0080, 0xe1d: 0x0080,
0xe1e: 0x0080, 0xe1f: 0x0080, 0xe20: 0x00c0, 0xe21: 0x00c0, 0xe22: 0x00c0, 0xe23: 0x00c0,
0xe24: 0x00c0, 0xe25: 0x00c0, 0xe26: 0x00c0, 0xe27: 0x00c0, 0xe28: 0x00c0, 0xe29: 0x00c0,
0xe2a: 0x0080, 0xe2b: 0x0080, 0xe2c: 0x0080, 0xe2d: 0x0080, 0xe2e: 0x0080, 0xe2f: 0x0080,
0xe30: 0x0080, 0xe31: 0x0080, 0xe32: 0x0080, 0xe33: 0x0080, 0xe34: 0x0080, 0xe35: 0x00c3,
0xe36: 0x0080, 0xe37: 0x00c3, 0xe38: 0x0080, 0xe39: 0x00c3, 0xe3a: 0x0080, 0xe3b: 0x0080,
0xe3c: 0x0080, 0xe3d: 0x0080, 0xe3e: 0x00c0, 0xe3f: 0x00c0,
// Block 0x39, offset 0xe40
0xe40: 0x00c0, 0xe41: 0x00c0, 0xe42: 0x00c0, 0xe43: 0x0080, 0xe44: 0x00c0, 0xe45: 0x00c0,
0xe46: 0x00c0, 0xe47: 0x00c0, 0xe49: 0x00c0, 0xe4a: 0x00c0, 0xe4b: 0x00c0,
0xe4c: 0x00c0, 0xe4d: 0x0080, 0xe4e: 0x00c0, 0xe4f: 0x00c0, 0xe50: 0x00c0, 0xe51: 0x00c0,
0xe52: 0x0080, 0xe53: 0x00c0, 0xe54: 0x00c0, 0xe55: 0x00c0, 0xe56: 0x00c0, 0xe57: 0x0080,
0xe58: 0x00c0, 0xe59: 0x00c0, 0xe5a: 0x00c0, 0xe5b: 0x00c0, 0xe5c: 0x0080, 0xe5d: 0x00c0,
0xe5e: 0x00c0, 0xe5f: 0x00c0, 0xe60: 0x00c0, 0xe61: 0x00c0, 0xe62: 0x00c0, 0xe63: 0x00c0,
0xe64: 0x00c0, 0xe65: 0x00c0, 0xe66: 0x00c0, 0xe67: 0x00c0, 0xe68: 0x00c0, 0xe69: 0x0080,
0xe6a: 0x00c0, 0xe6b: 0x00c0, 0xe6c: 0x00c0,
0xe71: 0x00c3, 0xe72: 0x00c3, 0xe73: 0x0083, 0xe74: 0x00c3, 0xe75: 0x0083,
0xe76: 0x0083, 0xe77: 0x0083, 0xe78: 0x0083, 0xe79: 0x0083, 0xe7a: 0x00c3, 0xe7b: 0x00c3,
0xe7c: 0x00c3, 0xe7d: 0x00c3, 0xe7e: 0x00c3, 0xe7f: 0x00c0,
// Block 0x3a, offset 0xe80
0xe80: 0x00c3, 0xe81: 0x0083, 0xe82: 0x00c3, 0xe83: 0x00c3, 0xe84: 0x00c6, 0xe85: 0x0080,
0xe86: 0x00c3, 0xe87: 0x00c3, 0xe88: 0x00c0, 0xe89: 0x00c0, 0xe8a: 0x00c0, 0xe8b: 0x00c0,
0xe8c: 0x00c0, 0xe8d: 0x00c3, 0xe8e: 0x00c3, 0xe8f: 0x00c3, 0xe90: 0x00c3, 0xe91: 0x00c3,
0xe92: 0x00c3, 0xe93: 0x0083, 0xe94: 0x00c3, 0xe95: 0x00c3, 0xe96: 0x00c3, 0xe97: 0x00c3,
0xe99: 0x00c3, 0xe9a: 0x00c3, 0xe9b: 0x00c3, 0xe9c: 0x00c3, 0xe9d: 0x0083,
0xe9e: 0x00c3, 0xe9f: 0x00c3, 0xea0: 0x00c3, 0xea1: 0x00c3, 0xea2: 0x0083, 0xea3: 0x00c3,
0xea4: 0x00c3, 0xea5: 0x00c3, 0xea6: 0x00c3, 0xea7: 0x0083, 0xea8: 0x00c3, 0xea9: 0x00c3,
0xeaa: 0x00c3, 0xeab: 0x00c3, 0xeac: 0x0083, 0xead: 0x00c3, 0xeae: 0x00c3, 0xeaf: 0x00c3,
0xeb0: 0x00c3, 0xeb1: 0x00c3, 0xeb2: 0x00c3, 0xeb3: 0x00c3, 0xeb4: 0x00c3, 0xeb5: 0x00c3,
0xeb6: 0x00c3, 0xeb7: 0x00c3, 0xeb8: 0x00c3, 0xeb9: 0x0083, 0xeba: 0x00c3, 0xebb: 0x00c3,
0xebc: 0x00c3, 0xebe: 0x0080, 0xebf: 0x0080,
// Block 0x3b, offset 0xec0
0xec0: 0x0080, 0xec1: 0x0080, 0xec2: 0x0080, 0xec3: 0x0080, 0xec4: 0x0080, 0xec5: 0x0080,
0xec6: 0x00c3, 0xec7: 0x0080, 0xec8: 0x0080, 0xec9: 0x0080, 0xeca: 0x0080, 0xecb: 0x0080,
0xecc: 0x0080, 0xece: 0x0080, 0xecf: 0x0080, 0xed0: 0x0080, 0xed1: 0x0080,
0xed2: 0x0080, 0xed3: 0x0080, 0xed4: 0x0080, 0xed5: 0x0080, 0xed6: 0x0080, 0xed7: 0x0080,
0xed8: 0x0080, 0xed9: 0x0080, 0xeda: 0x0080,
// Block 0x3c, offset 0xf00
0xf00: 0x00c0, 0xf01: 0x00c0, 0xf02: 0x00c0, 0xf03: 0x00c0, 0xf04: 0x00c0, 0xf05: 0x00c0,
0xf06: 0x00c0, 0xf07: 0x00c0, 0xf08: 0x00c0, 0xf09: 0x00c0, 0xf0a: 0x00c0, 0xf0b: 0x00c0,
0xf0c: 0x00c0, 0xf0d: 0x00c0, 0xf0e: 0x00c0, 0xf0f: 0x00c0, 0xf10: 0x00c0, 0xf11: 0x00c0,
0xf12: 0x00c0, 0xf13: 0x00c0, 0xf14: 0x00c0, 0xf15: 0x00c0, 0xf16: 0x00c0, 0xf17: 0x00c0,
0xf18: 0x00c0, 0xf19: 0x00c0, 0xf1a: 0x00c0, 0xf1b: 0x00c0, 0xf1c: 0x00c0, 0xf1d: 0x00c0,
0xf1e: 0x00c0, 0xf1f: 0x00c0, 0xf20: 0x00c0, 0xf21: 0x00c0, 0xf22: 0x00c0, 0xf23: 0x00c0,
0xf24: 0x00c0, 0xf25: 0x00c0, 0xf26: 0x00c0, 0xf27: 0x00c0, 0xf28: 0x00c0, 0xf29: 0x00c0,
0xf2a: 0x00c0, 0xf2b: 0x00c0, 0xf2c: 0x00c0, 0xf2d: 0x00c3, 0xf2e: 0x00c3, 0xf2f: 0x00c3,
0xf30: 0x00c3, 0xf31: 0x00c0, 0xf32: 0x00c3, 0xf33: 0x00c3, 0xf34: 0x00c3, 0xf35: 0x00c3,
0xf36: 0x00c3, 0xf37: 0x00c3, 0xf38: 0x00c0, 0xf39: 0x00c6, 0xf3a: 0x00c6, 0xf3b: 0x00c0,
0xf3c: 0x00c0, 0xf3d: 0x00c3, 0xf3e: 0x00c3, 0xf3f: 0x00c0,
// Block 0x3d, offset 0xf40
0xf40: 0x00c0, 0xf41: 0x00c0, 0xf42: 0x00c0, 0xf43: 0x00c0, 0xf44: 0x00c0, 0xf45: 0x00c0,
0xf46: 0x00c0, 0xf47: 0x00c0, 0xf48: 0x00c0, 0xf49: 0x00c0, 0xf4a: 0x0080, 0xf4b: 0x0080,
0xf4c: 0x0080, 0xf4d: 0x0080, 0xf4e: 0x0080, 0xf4f: 0x0080, 0xf50: 0x00c0, 0xf51: 0x00c0,
0xf52: 0x00c0, 0xf53: 0x00c0, 0xf54: 0x00c0, 0xf55: 0x00c0, 0xf56: 0x00c0, 0xf57: 0x00c0,
0xf58: 0x00c3, 0xf59: 0x00c3, 0xf5a: 0x00c0, 0xf5b: 0x00c0, 0xf5c: 0x00c0, 0xf5d: 0x00c0,
0xf5e: 0x00c3, 0xf5f: 0x00c3, 0xf60: 0x00c3, 0xf61: 0x00c0, 0xf62: 0x00c0, 0xf63: 0x00c0,
0xf64: 0x00c0, 0xf65: 0x00c0, 0xf66: 0x00c0, 0xf67: 0x00c0, 0xf68: 0x00c0, 0xf69: 0x00c0,
0xf6a: 0x00c0, 0xf6b: 0x00c0, 0xf6c: 0x00c0, 0xf6d: 0x00c0, 0xf6e: 0x00c0, 0xf6f: 0x00c0,
0xf70: 0x00c0, 0xf71: 0x00c3, 0xf72: 0x00c3, 0xf73: 0x00c3, 0xf74: 0x00c3, 0xf75: 0x00c0,
0xf76: 0x00c0, 0xf77: 0x00c0, 0xf78: 0x00c0, 0xf79: 0x00c0, 0xf7a: 0x00c0, 0xf7b: 0x00c0,
0xf7c: 0x00c0, 0xf7d: 0x00c0, 0xf7e: 0x00c0, 0xf7f: 0x00c0,
// Block 0x3e, offset 0xf80
0xf80: 0x00c0, 0xf81: 0x00c0, 0xf82: 0x00c3, 0xf83: 0x00c0, 0xf84: 0x00c0, 0xf85: 0x00c3,
0xf86: 0x00c3, 0xf87: 0x00c0, 0xf88: 0x00c0, 0xf89: 0x00c0, 0xf8a: 0x00c0, 0xf8b: 0x00c0,
0xf8c: 0x00c0, 0xf8d: 0x00c3, 0xf8e: 0x00c0, 0xf8f: 0x00c0, 0xf90: 0x00c0, 0xf91: 0x00c0,
0xf92: 0x00c0, 0xf93: 0x00c0, 0xf94: 0x00c0, 0xf95: 0x00c0, 0xf96: 0x00c0, 0xf97: 0x00c0,
0xf98: 0x00c0, 0xf99: 0x00c0, 0xf9a: 0x00c0, 0xf9b: 0x00c0, 0xf9c: 0x00c0, 0xf9d: 0x00c3,
0xf9e: 0x0080, 0xf9f: 0x0080, 0xfa0: 0x00c0, 0xfa1: 0x00c0, 0xfa2: 0x00c0, 0xfa3: 0x00c0,
0xfa4: 0x00c0, 0xfa5: 0x00c0, 0xfa6: 0x00c0, 0xfa7: 0x00c0, 0xfa8: 0x00c0, 0xfa9: 0x00c0,
0xfaa: 0x00c0, 0xfab: 0x00c0, 0xfac: 0x00c0, 0xfad: 0x00c0, 0xfae: 0x00c0, 0xfaf: 0x00c0,
0xfb0: 0x00c0, 0xfb1: 0x00c0, 0xfb2: 0x00c0, 0xfb3: 0x00c0, 0xfb4: 0x00c0, 0xfb5: 0x00c0,
0xfb6: 0x00c0, 0xfb7: 0x00c0, 0xfb8: 0x00c0, 0xfb9: 0x00c0, 0xfba: 0x00c0, 0xfbb: 0x00c0,
0xfbc: 0x00c0, 0xfbd: 0x00c0, 0xfbe: 0x00c0, 0xfbf: 0x00c0,
// Block 0x3f, offset 0xfc0
0xfc0: 0x00c0, 0xfc1: 0x00c0, 0xfc2: 0x00c0, 0xfc3: 0x00c0, 0xfc4: 0x00c0, 0xfc5: 0x00c0,
0xfc7: 0x00c0,
0xfcd: 0x00c0, 0xfd0: 0x00c0, 0xfd1: 0x00c0,
0xfd2: 0x00c0, 0xfd3: 0x00c0, 0xfd4: 0x00c0, 0xfd5: 0x00c0, 0xfd6: 0x00c0, 0xfd7: 0x00c0,
0xfd8: 0x00c0, 0xfd9: 0x00c0, 0xfda: 0x00c0, 0xfdb: 0x00c0, 0xfdc: 0x00c0, 0xfdd: 0x00c0,
0xfde: 0x00c0, 0xfdf: 0x00c0, 0xfe0: 0x00c0, 0xfe1: 0x00c0, 0xfe2: 0x00c0, 0xfe3: 0x00c0,
0xfe4: 0x00c0, 0xfe5: 0x00c0, 0xfe6: 0x00c0, 0xfe7: 0x00c0, 0xfe8: 0x00c0, 0xfe9: 0x00c0,
0xfea: 0x00c0, 0xfeb: 0x00c0, 0xfec: 0x00c0, 0xfed: 0x00c0, 0xfee: 0x00c0, 0xfef: 0x00c0,
0xff0: 0x00c0, 0xff1: 0x00c0, 0xff2: 0x00c0, 0xff3: 0x00c0, 0xff4: 0x00c0, 0xff5: 0x00c0,
0xff6: 0x00c0, 0xff7: 0x00c0, 0xff8: 0x00c0, 0xff9: 0x00c0, 0xffa: 0x00c0, 0xffb: 0x0080,
0xffc: 0x0080, 0xffd: 0x00c0, 0xffe: 0x00c0, 0xfff: 0x00c0,
// Block 0x40, offset 0x1000
0x1000: 0x0040, 0x1001: 0x0040, 0x1002: 0x0040, 0x1003: 0x0040, 0x1004: 0x0040, 0x1005: 0x0040,
0x1006: 0x0040, 0x1007: 0x0040, 0x1008: 0x0040, 0x1009: 0x0040, 0x100a: 0x0040, 0x100b: 0x0040,
0x100c: 0x0040, 0x100d: 0x0040, 0x100e: 0x0040, 0x100f: 0x0040, 0x1010: 0x0040, 0x1011: 0x0040,
0x1012: 0x0040, 0x1013: 0x0040, 0x1014: 0x0040, 0x1015: 0x0040, 0x1016: 0x0040, 0x1017: 0x0040,
0x1018: 0x0040, 0x1019: 0x0040, 0x101a: 0x0040, 0x101b: 0x0040, 0x101c: 0x0040, 0x101d: 0x0040,
0x101e: 0x0040, 0x101f: 0x0040, 0x1020: 0x0040, 0x1021: 0x0040, 0x1022: 0x0040, 0x1023: 0x0040,
0x1024: 0x0040, 0x1025: 0x0040, 0x1026: 0x0040, 0x1027: 0x0040, 0x1028: 0x0040, 0x1029: 0x0040,
0x102a: 0x0040, 0x102b: 0x0040, 0x102c: 0x0040, 0x102d: 0x0040, 0x102e: 0x0040, 0x102f: 0x0040,
0x1030: 0x0040, 0x1031: 0x0040, 0x1032: 0x0040, 0x1033: 0x0040, 0x1034: 0x0040, 0x1035: 0x0040,
0x1036: 0x0040, 0x1037: 0x0040, 0x1038: 0x0040, 0x1039: 0x0040, 0x103a: 0x0040, 0x103b: 0x0040,
0x103c: 0x0040, 0x103d: 0x0040, 0x103e: 0x0040, 0x103f: 0x0040,
// Block 0x41, offset 0x1040
0x1040: 0x00c0, 0x1041: 0x00c0, 0x1042: 0x00c0, 0x1043: 0x00c0, 0x1044: 0x00c0, 0x1045: 0x00c0,
0x1046: 0x00c0, 0x1047: 0x00c0, 0x1048: 0x00c0, 0x104a: 0x00c0, 0x104b: 0x00c0,
0x104c: 0x00c0, 0x104d: 0x00c0, 0x1050: 0x00c0, 0x1051: 0x00c0,
0x1052: 0x00c0, 0x1053: 0x00c0, 0x1054: 0x00c0, 0x1055: 0x00c0, 0x1056: 0x00c0,
0x1058: 0x00c0, 0x105a: 0x00c0, 0x105b: 0x00c0, 0x105c: 0x00c0, 0x105d: 0x00c0,
0x1060: 0x00c0, 0x1061: 0x00c0, 0x1062: 0x00c0, 0x1063: 0x00c0,
0x1064: 0x00c0, 0x1065: 0x00c0, 0x1066: 0x00c0, 0x1067: 0x00c0, 0x1068: 0x00c0, 0x1069: 0x00c0,
0x106a: 0x00c0, 0x106b: 0x00c0, 0x106c: 0x00c0, 0x106d: 0x00c0, 0x106e: 0x00c0, 0x106f: 0x00c0,
0x1070: 0x00c0, 0x1071: 0x00c0, 0x1072: 0x00c0, 0x1073: 0x00c0, 0x1074: 0x00c0, 0x1075: 0x00c0,
0x1076: 0x00c0, 0x1077: 0x00c0, 0x1078: 0x00c0, 0x1079: 0x00c0, 0x107a: 0x00c0, 0x107b: 0x00c0,
0x107c: 0x00c0, 0x107d: 0x00c0, 0x107e: 0x00c0, 0x107f: 0x00c0,
// Block 0x42, offset 0x1080
0x1080: 0x00c0, 0x1081: 0x00c0, 0x1082: 0x00c0, 0x1083: 0x00c0, 0x1084: 0x00c0, 0x1085: 0x00c0,
0x1086: 0x00c0, 0x1087: 0x00c0, 0x1088: 0x00c0, 0x108a: 0x00c0, 0x108b: 0x00c0,
0x108c: 0x00c0, 0x108d: 0x00c0, 0x1090: 0x00c0, 0x1091: 0x00c0,
0x1092: 0x00c0, 0x1093: 0x00c0, 0x1094: 0x00c0, 0x1095: 0x00c0, 0x1096: 0x00c0, 0x1097: 0x00c0,
0x1098: 0x00c0, 0x1099: 0x00c0, 0x109a: 0x00c0, 0x109b: 0x00c0, 0x109c: 0x00c0, 0x109d: 0x00c0,
0x109e: 0x00c0, 0x109f: 0x00c0, 0x10a0: 0x00c0, 0x10a1: 0x00c0, 0x10a2: 0x00c0, 0x10a3: 0x00c0,
0x10a4: 0x00c0, 0x10a5: 0x00c0, 0x10a6: 0x00c0, 0x10a7: 0x00c0, 0x10a8: 0x00c0, 0x10a9: 0x00c0,
0x10aa: 0x00c0, 0x10ab: 0x00c0, 0x10ac: 0x00c0, 0x10ad: 0x00c0, 0x10ae: 0x00c0, 0x10af: 0x00c0,
0x10b0: 0x00c0, 0x10b2: 0x00c0, 0x10b3: 0x00c0, 0x10b4: 0x00c0, 0x10b5: 0x00c0,
0x10b8: 0x00c0, 0x10b9: 0x00c0, 0x10ba: 0x00c0, 0x10bb: 0x00c0,
0x10bc: 0x00c0, 0x10bd: 0x00c0, 0x10be: 0x00c0,
// Block 0x43, offset 0x10c0
0x10c0: 0x00c0, 0x10c2: 0x00c0, 0x10c3: 0x00c0, 0x10c4: 0x00c0, 0x10c5: 0x00c0,
0x10c8: 0x00c0, 0x10c9: 0x00c0, 0x10ca: 0x00c0, 0x10cb: 0x00c0,
0x10cc: 0x00c0, 0x10cd: 0x00c0, 0x10ce: 0x00c0, 0x10cf: 0x00c0, 0x10d0: 0x00c0, 0x10d1: 0x00c0,
0x10d2: 0x00c0, 0x10d3: 0x00c0, 0x10d4: 0x00c0, 0x10d5: 0x00c0, 0x10d6: 0x00c0,
0x10d8: 0x00c0, 0x10d9: 0x00c0, 0x10da: 0x00c0, 0x10db: 0x00c0, 0x10dc: 0x00c0, 0x10dd: 0x00c0,
0x10de: 0x00c0, 0x10df: 0x00c0, 0x10e0: 0x00c0, 0x10e1: 0x00c0, 0x10e2: 0x00c0, 0x10e3: 0x00c0,
0x10e4: 0x00c0, 0x10e5: 0x00c0, 0x10e6: 0x00c0, 0x10e7: 0x00c0, 0x10e8: 0x00c0, 0x10e9: 0x00c0,
0x10ea: 0x00c0, 0x10eb: 0x00c0, 0x10ec: 0x00c0, 0x10ed: 0x00c0, 0x10ee: 0x00c0, 0x10ef: 0x00c0,
0x10f0: 0x00c0, 0x10f1: 0x00c0, 0x10f2: 0x00c0, 0x10f3: 0x00c0, 0x10f4: 0x00c0, 0x10f5: 0x00c0,
0x10f6: 0x00c0, 0x10f7: 0x00c0, 0x10f8: 0x00c0, 0x10f9: 0x00c0, 0x10fa: 0x00c0, 0x10fb: 0x00c0,
0x10fc: 0x00c0, 0x10fd: 0x00c0, 0x10fe: 0x00c0, 0x10ff: 0x00c0,
// Block 0x44, offset 0x1100
0x1100: 0x00c0, 0x1101: 0x00c0, 0x1102: 0x00c0, 0x1103: 0x00c0, 0x1104: 0x00c0, 0x1105: 0x00c0,
0x1106: 0x00c0, 0x1107: 0x00c0, 0x1108: 0x00c0, 0x1109: 0x00c0, 0x110a: 0x00c0, 0x110b: 0x00c0,
0x110c: 0x00c0, 0x110d: 0x00c0, 0x110e: 0x00c0, 0x110f: 0x00c0, 0x1110: 0x00c0,
0x1112: 0x00c0, 0x1113: 0x00c0, 0x1114: 0x00c0, 0x1115: 0x00c0,
0x1118: 0x00c0, 0x1119: 0x00c0, 0x111a: 0x00c0, 0x111b: 0x00c0, 0x111c: 0x00c0, 0x111d: 0x00c0,
0x111e: 0x00c0, 0x111f: 0x00c0, 0x1120: 0x00c0, 0x1121: 0x00c0, 0x1122: 0x00c0, 0x1123: 0x00c0,
0x1124: 0x00c0, 0x1125: 0x00c0, 0x1126: 0x00c0, 0x1127: 0x00c0, 0x1128: 0x00c0, 0x1129: 0x00c0,
0x112a: 0x00c0, 0x112b: 0x00c0, 0x112c: 0x00c0, 0x112d: 0x00c0, 0x112e: 0x00c0, 0x112f: 0x00c0,
0x1130: 0x00c0, 0x1131: 0x00c0, 0x1132: 0x00c0, 0x1133: 0x00c0, 0x1134: 0x00c0, 0x1135: 0x00c0,
0x1136: 0x00c0, 0x1137: 0x00c0, 0x1138: 0x00c0, 0x1139: 0x00c0, 0x113a: 0x00c0, 0x113b: 0x00c0,
0x113c: 0x00c0, 0x113d: 0x00c0, 0x113e: 0x00c0, 0x113f: 0x00c0,
// Block 0x45, offset 0x1140
0x1140: 0x00c0, 0x1141: 0x00c0, 0x1142: 0x00c0, 0x1143: 0x00c0, 0x1144: 0x00c0, 0x1145: 0x00c0,
0x1146: 0x00c0, 0x1147: 0x00c0, 0x1148: 0x00c0, 0x1149: 0x00c0, 0x114a: 0x00c0, 0x114b: 0x00c0,
0x114c: 0x00c0, 0x114d: 0x00c0, 0x114e: 0x00c0, 0x114f: 0x00c0, 0x1150: 0x00c0, 0x1151: 0x00c0,
0x1152: 0x00c0, 0x1153: 0x00c0, 0x1154: 0x00c0, 0x1155: 0x00c0, 0x1156: 0x00c0, 0x1157: 0x00c0,
0x1158: 0x00c0, 0x1159: 0x00c0, 0x115a: 0x00c0, 0x115d: 0x00c3,
0x115e: 0x00c3, 0x115f: 0x00c3, 0x1160: 0x0080, 0x1161: 0x0080, 0x1162: 0x0080, 0x1163: 0x0080,
0x1164: 0x0080, 0x1165: 0x0080, 0x1166: 0x0080, 0x1167: 0x0080, 0x1168: 0x0080, 0x1169: 0x0080,
0x116a: 0x0080, 0x116b: 0x0080, 0x116c: 0x0080, 0x116d: 0x0080, 0x116e: 0x0080, 0x116f: 0x0080,
0x1170: 0x0080, 0x1171: 0x0080, 0x1172: 0x0080, 0x1173: 0x0080, 0x1174: 0x0080, 0x1175: 0x0080,
0x1176: 0x0080, 0x1177: 0x0080, 0x1178: 0x0080, 0x1179: 0x0080, 0x117a: 0x0080, 0x117b: 0x0080,
0x117c: 0x0080,
// Block 0x46, offset 0x1180
0x1180: 0x00c0, 0x1181: 0x00c0, 0x1182: 0x00c0, 0x1183: 0x00c0, 0x1184: 0x00c0, 0x1185: 0x00c0,
0x1186: 0x00c0, 0x1187: 0x00c0, 0x1188: 0x00c0, 0x1189: 0x00c0, 0x118a: 0x00c0, 0x118b: 0x00c0,
0x118c: 0x00c0, 0x118d: 0x00c0, 0x118e: 0x00c0, 0x118f: 0x00c0, 0x1190: 0x0080, 0x1191: 0x0080,
0x1192: 0x0080, 0x1193: 0x0080, 0x1194: 0x0080, 0x1195: 0x0080, 0x1196: 0x0080, 0x1197: 0x0080,
0x1198: 0x0080, 0x1199: 0x0080,
0x11a0: 0x00c0, 0x11a1: 0x00c0, 0x11a2: 0x00c0, 0x11a3: 0x00c0,
0x11a4: 0x00c0, 0x11a5: 0x00c0, 0x11a6: 0x00c0, 0x11a7: 0x00c0, 0x11a8: 0x00c0, 0x11a9: 0x00c0,
0x11aa: 0x00c0, 0x11ab: 0x00c0, 0x11ac: 0x00c0, 0x11ad: 0x00c0, 0x11ae: 0x00c0, 0x11af: 0x00c0,
0x11b0: 0x00c0, 0x11b1: 0x00c0, 0x11b2: 0x00c0, 0x11b3: 0x00c0, 0x11b4: 0x00c0, 0x11b5: 0x00c0,
0x11b6: 0x00c0, 0x11b7: 0x00c0, 0x11b8: 0x00c0, 0x11b9: 0x00c0, 0x11ba: 0x00c0, 0x11bb: 0x00c0,
0x11bc: 0x00c0, 0x11bd: 0x00c0, 0x11be: 0x00c0, 0x11bf: 0x00c0,
// Block 0x47, offset 0x11c0
0x11c0: 0x00c0, 0x11c1: 0x00c0, 0x11c2: 0x00c0, 0x11c3: 0x00c0, 0x11c4: 0x00c0, 0x11c5: 0x00c0,
0x11c6: 0x00c0, 0x11c7: 0x00c0, 0x11c8: 0x00c0, 0x11c9: 0x00c0, 0x11ca: 0x00c0, 0x11cb: 0x00c0,
0x11cc: 0x00c0, 0x11cd: 0x00c0, 0x11ce: 0x00c0, 0x11cf: 0x00c0, 0x11d0: 0x00c0, 0x11d1: 0x00c0,
0x11d2: 0x00c0, 0x11d3: 0x00c0, 0x11d4: 0x00c0, 0x11d5: 0x00c0, 0x11d6: 0x00c0, 0x11d7: 0x00c0,
0x11d8: 0x00c0, 0x11d9: 0x00c0, 0x11da: 0x00c0, 0x11db: 0x00c0, 0x11dc: 0x00c0, 0x11dd: 0x00c0,
0x11de: 0x00c0, 0x11df: 0x00c0, 0x11e0: 0x00c0, 0x11e1: 0x00c0, 0x11e2: 0x00c0, 0x11e3: 0x00c0,
0x11e4: 0x00c0, 0x11e5: 0x00c0, 0x11e6: 0x00c0, 0x11e7: 0x00c0, 0x11e8: 0x00c0, 0x11e9: 0x00c0,
0x11ea: 0x00c0, 0x11eb: 0x00c0, 0x11ec: 0x00c0, 0x11ed: 0x00c0, 0x11ee: 0x00c0, 0x11ef: 0x00c0,
0x11f0: 0x00c0, 0x11f1: 0x00c0, 0x11f2: 0x00c0, 0x11f3: 0x00c0, 0x11f4: 0x00c0, 0x11f5: 0x00c0,
0x11f8: 0x00c0, 0x11f9: 0x00c0, 0x11fa: 0x00c0, 0x11fb: 0x00c0,
0x11fc: 0x00c0, 0x11fd: 0x00c0,
// Block 0x48, offset 0x1200
0x1200: 0x0080, 0x1201: 0x00c0, 0x1202: 0x00c0, 0x1203: 0x00c0, 0x1204: 0x00c0, 0x1205: 0x00c0,
0x1206: 0x00c0, 0x1207: 0x00c0, 0x1208: 0x00c0, 0x1209: 0x00c0, 0x120a: 0x00c0, 0x120b: 0x00c0,
0x120c: 0x00c0, 0x120d: 0x00c0, 0x120e: 0x00c0, 0x120f: 0x00c0, 0x1210: 0x00c0, 0x1211: 0x00c0,
0x1212: 0x00c0, 0x1213: 0x00c0, 0x1214: 0x00c0, 0x1215: 0x00c0, 0x1216: 0x00c0, 0x1217: 0x00c0,
0x1218: 0x00c0, 0x1219: 0x00c0, 0x121a: 0x00c0, 0x121b: 0x00c0, 0x121c: 0x00c0, 0x121d: 0x00c0,
0x121e: 0x00c0, 0x121f: 0x00c0, 0x1220: 0x00c0, 0x1221: 0x00c0, 0x1222: 0x00c0, 0x1223: 0x00c0,
0x1224: 0x00c0, 0x1225: 0x00c0, 0x1226: 0x00c0, 0x1227: 0x00c0, 0x1228: 0x00c0, 0x1229: 0x00c0,
0x122a: 0x00c0, 0x122b: 0x00c0, 0x122c: 0x00c0, 0x122d: 0x00c0, 0x122e: 0x00c0, 0x122f: 0x00c0,
0x1230: 0x00c0, 0x1231: 0x00c0, 0x1232: 0x00c0, 0x1233: 0x00c0, 0x1234: 0x00c0, 0x1235: 0x00c0,
0x1236: 0x00c0, 0x1237: 0x00c0, 0x1238: 0x00c0, 0x1239: 0x00c0, 0x123a: 0x00c0, 0x123b: 0x00c0,
0x123c: 0x00c0, 0x123d: 0x00c0, 0x123e: 0x00c0, 0x123f: 0x00c0,
// Block 0x49, offset 0x1240
0x1240: 0x00c0, 0x1241: 0x00c0, 0x1242: 0x00c0, 0x1243: 0x00c0, 0x1244: 0x00c0, 0x1245: 0x00c0,
0x1246: 0x00c0, 0x1247: 0x00c0, 0x1248: 0x00c0, 0x1249: 0x00c0, 0x124a: 0x00c0, 0x124b: 0x00c0,
0x124c: 0x00c0, 0x124d: 0x00c0, 0x124e: 0x00c0, 0x124f: 0x00c0, 0x1250: 0x00c0, 0x1251: 0x00c0,
0x1252: 0x00c0, 0x1253: 0x00c0, 0x1254: 0x00c0, 0x1255: 0x00c0, 0x1256: 0x00c0, 0x1257: 0x00c0,
0x1258: 0x00c0, 0x1259: 0x00c0, 0x125a: 0x00c0, 0x125b: 0x00c0, 0x125c: 0x00c0, 0x125d: 0x00c0,
0x125e: 0x00c0, 0x125f: 0x00c0, 0x1260: 0x00c0, 0x1261: 0x00c0, 0x1262: 0x00c0, 0x1263: 0x00c0,
0x1264: 0x00c0, 0x1265: 0x00c0, 0x1266: 0x00c0, 0x1267: 0x00c0, 0x1268: 0x00c0, 0x1269: 0x00c0,
0x126a: 0x00c0, 0x126b: 0x00c0, 0x126c: 0x00c0, 0x126d: 0x0080, 0x126e: 0x0080, 0x126f: 0x00c0,
0x1270: 0x00c0, 0x1271: 0x00c0, 0x1272: 0x00c0, 0x1273: 0x00c0, 0x1274: 0x00c0, 0x1275: 0x00c0,
0x1276: 0x00c0, 0x1277: 0x00c0, 0x1278: 0x00c0, 0x1279: 0x00c0, 0x127a: 0x00c0, 0x127b: 0x00c0,
0x127c: 0x00c0, 0x127d: 0x00c0, 0x127e: 0x00c0, 0x127f: 0x00c0,
// Block 0x4a, offset 0x1280
0x1280: 0x0080, 0x1281: 0x00c0, 0x1282: 0x00c0, 0x1283: 0x00c0, 0x1284: 0x00c0, 0x1285: 0x00c0,
0x1286: 0x00c0, 0x1287: 0x00c0, 0x1288: 0x00c0, 0x1289: 0x00c0, 0x128a: 0x00c0, 0x128b: 0x00c0,
0x128c: 0x00c0, 0x128d: 0x00c0, 0x128e: 0x00c0, 0x128f: 0x00c0, 0x1290: 0x00c0, 0x1291: 0x00c0,
0x1292: 0x00c0, 0x1293: 0x00c0, 0x1294: 0x00c0, 0x1295: 0x00c0, 0x1296: 0x00c0, 0x1297: 0x00c0,
0x1298: 0x00c0, 0x1299: 0x00c0, 0x129a: 0x00c0, 0x129b: 0x0080, 0x129c: 0x0080,
0x12a0: 0x00c0, 0x12a1: 0x00c0, 0x12a2: 0x00c0, 0x12a3: 0x00c0,
0x12a4: 0x00c0, 0x12a5: 0x00c0, 0x12a6: 0x00c0, 0x12a7: 0x00c0, 0x12a8: 0x00c0, 0x12a9: 0x00c0,
0x12aa: 0x00c0, 0x12ab: 0x00c0, 0x12ac: 0x00c0, 0x12ad: 0x00c0, 0x12ae: 0x00c0, 0x12af: 0x00c0,
0x12b0: 0x00c0, 0x12b1: 0x00c0, 0x12b2: 0x00c0, 0x12b3: 0x00c0, 0x12b4: 0x00c0, 0x12b5: 0x00c0,
0x12b6: 0x00c0, 0x12b7: 0x00c0, 0x12b8: 0x00c0, 0x12b9: 0x00c0, 0x12ba: 0x00c0, 0x12bb: 0x00c0,
0x12bc: 0x00c0, 0x12bd: 0x00c0, 0x12be: 0x00c0, 0x12bf: 0x00c0,
// Block 0x4b, offset 0x12c0
0x12c0: 0x00c0, 0x12c1: 0x00c0, 0x12c2: 0x00c0, 0x12c3: 0x00c0, 0x12c4: 0x00c0, 0x12c5: 0x00c0,
0x12c6: 0x00c0, 0x12c7: 0x00c0, 0x12c8: 0x00c0, 0x12c9: 0x00c0, 0x12ca: 0x00c0, 0x12cb: 0x00c0,
0x12cc: 0x00c0, 0x12cd: 0x00c0, 0x12ce: 0x00c0, 0x12cf: 0x00c0, 0x12d0: 0x00c0, 0x12d1: 0x00c0,
0x12d2: 0x00c0, 0x12d3: 0x00c0, 0x12d4: 0x00c0, 0x12d5: 0x00c0, 0x12d6: 0x00c0, 0x12d7: 0x00c0,
0x12d8: 0x00c0, 0x12d9: 0x00c0, 0x12da: 0x00c0, 0x12db: 0x00c0, 0x12dc: 0x00c0, 0x12dd: 0x00c0,
0x12de: 0x00c0, 0x12df: 0x00c0, 0x12e0: 0x00c0, 0x12e1: 0x00c0, 0x12e2: 0x00c0, 0x12e3: 0x00c0,
0x12e4: 0x00c0, 0x12e5: 0x00c0, 0x12e6: 0x00c0, 0x12e7: 0x00c0, 0x12e8: 0x00c0, 0x12e9: 0x00c0,
0x12ea: 0x00c0, 0x12eb: 0x0080, 0x12ec: 0x0080, 0x12ed: 0x0080, 0x12ee: 0x0080, 0x12ef: 0x0080,
0x12f0: 0x0080, 0x12f1: 0x00c0, 0x12f2: 0x00c0, 0x12f3: 0x00c0, 0x12f4: 0x00c0, 0x12f5: 0x00c0,
0x12f6: 0x00c0, 0x12f7: 0x00c0, 0x12f8: 0x00c0,
// Block 0x4c, offset 0x1300
0x1300: 0x00c0, 0x1301: 0x00c0, 0x1302: 0x00c0, 0x1303: 0x00c0, 0x1304: 0x00c0, 0x1305: 0x00c0,
0x1306: 0x00c0, 0x1307: 0x00c0, 0x1308: 0x00c0, 0x1309: 0x00c0, 0x130a: 0x00c0, 0x130b: 0x00c0,
0x130c: 0x00c0, 0x130d: 0x00c0, 0x130e: 0x00c0, 0x130f: 0x00c0, 0x1310: 0x00c0, 0x1311: 0x00c0,
0x1312: 0x00c3, 0x1313: 0x00c3, 0x1314: 0x00c6, 0x1315: 0x00c5,
0x131f: 0x00c0, 0x1320: 0x00c0, 0x1321: 0x00c0, 0x1322: 0x00c0, 0x1323: 0x00c0,
0x1324: 0x00c0, 0x1325: 0x00c0, 0x1326: 0x00c0, 0x1327: 0x00c0, 0x1328: 0x00c0, 0x1329: 0x00c0,
0x132a: 0x00c0, 0x132b: 0x00c0, 0x132c: 0x00c0, 0x132d: 0x00c0, 0x132e: 0x00c0, 0x132f: 0x00c0,
0x1330: 0x00c0, 0x1331: 0x00c0, 0x1332: 0x00c3, 0x1333: 0x00c3, 0x1334: 0x00c5, 0x1335: 0x0080,
0x1336: 0x0080,
// Block 0x4d, offset 0x1340
0x1340: 0x00c0, 0x1341: 0x00c0, 0x1342: 0x00c0, 0x1343: 0x00c0, 0x1344: 0x00c0, 0x1345: 0x00c0,
0x1346: 0x00c0, 0x1347: 0x00c0, 0x1348: 0x00c0, 0x1349: 0x00c0, 0x134a: 0x00c0, 0x134b: 0x00c0,
0x134c: 0x00c0, 0x134d: 0x00c0, 0x134e: 0x00c0, 0x134f: 0x00c0, 0x1350: 0x00c0, 0x1351: 0x00c0,
0x1352: 0x00c3, 0x1353: 0x00c3,
0x1360: 0x00c0, 0x1361: 0x00c0, 0x1362: 0x00c0, 0x1363: 0x00c0,
0x1364: 0x00c0, 0x1365: 0x00c0, 0x1366: 0x00c0, 0x1367: 0x00c0, 0x1368: 0x00c0, 0x1369: 0x00c0,
0x136a: 0x00c0, 0x136b: 0x00c0, 0x136c: 0x00c0, 0x136e: 0x00c0, 0x136f: 0x00c0,
0x1370: 0x00c0, 0x1372: 0x00c3, 0x1373: 0x00c3,
// Block 0x4e, offset 0x1380
0x1380: 0x00c0, 0x1381: 0x00c0, 0x1382: 0x00c0, 0x1383: 0x00c0, 0x1384: 0x00c0, 0x1385: 0x00c0,
0x1386: 0x00c0, 0x1387: 0x00c0, 0x1388: 0x00c0, 0x1389: 0x00c0, 0x138a: 0x00c0, 0x138b: 0x00c0,
0x138c: 0x00c0, 0x138d: 0x00c0, 0x138e: 0x00c0, 0x138f: 0x00c0, 0x1390: 0x00c0, 0x1391: 0x00c0,
0x1392: 0x00c0, 0x1393: 0x00c0, 0x1394: 0x00c0, 0x1395: 0x00c0, 0x1396: 0x00c0, 0x1397: 0x00c0,
0x1398: 0x00c0, 0x1399: 0x00c0, 0x139a: 0x00c0, 0x139b: 0x00c0, 0x139c: 0x00c0, 0x139d: 0x00c0,
0x139e: 0x00c0, 0x139f: 0x00c0, 0x13a0: 0x00c0, 0x13a1: 0x00c0, 0x13a2: 0x00c0, 0x13a3: 0x00c0,
0x13a4: 0x00c0, 0x13a5: 0x00c0, 0x13a6: 0x00c0, 0x13a7: 0x00c0, 0x13a8: 0x00c0, 0x13a9: 0x00c0,
0x13aa: 0x00c0, 0x13ab: 0x00c0, 0x13ac: 0x00c0, 0x13ad: 0x00c0, 0x13ae: 0x00c0, 0x13af: 0x00c0,
0x13b0: 0x00c0, 0x13b1: 0x00c0, 0x13b2: 0x00c0, 0x13b3: 0x00c0, 0x13b4: 0x0040, 0x13b5: 0x0040,
0x13b6: 0x00c0, 0x13b7: 0x00c3, 0x13b8: 0x00c3, 0x13b9: 0x00c3, 0x13ba: 0x00c3, 0x13bb: 0x00c3,
0x13bc: 0x00c3, 0x13bd: 0x00c3, 0x13be: 0x00c0, 0x13bf: 0x00c0,
// Block 0x4f, offset 0x13c0
0x13c0: 0x00c0, 0x13c1: 0x00c0, 0x13c2: 0x00c0, 0x13c3: 0x00c0, 0x13c4: 0x00c0, 0x13c5: 0x00c0,
0x13c6: 0x00c3, 0x13c7: 0x00c0, 0x13c8: 0x00c0, 0x13c9: 0x00c3, 0x13ca: 0x00c3, 0x13cb: 0x00c3,
0x13cc: 0x00c3, 0x13cd: 0x00c3, 0x13ce: 0x00c3, 0x13cf: 0x00c3, 0x13d0: 0x00c3, 0x13d1: 0x00c3,
0x13d2: 0x00c6, 0x13d3: 0x00c3, 0x13d4: 0x0080, 0x13d5: 0x0080, 0x13d6: 0x0080, 0x13d7: 0x00c0,
0x13d8: 0x0080, 0x13d9: 0x0080, 0x13da: 0x0080, 0x13db: 0x0080, 0x13dc: 0x00c0, 0x13dd: 0x00c3,
0x13e0: 0x00c0, 0x13e1: 0x00c0, 0x13e2: 0x00c0, 0x13e3: 0x00c0,
0x13e4: 0x00c0, 0x13e5: 0x00c0, 0x13e6: 0x00c0, 0x13e7: 0x00c0, 0x13e8: 0x00c0, 0x13e9: 0x00c0,
0x13f0: 0x0080, 0x13f1: 0x0080, 0x13f2: 0x0080, 0x13f3: 0x0080, 0x13f4: 0x0080, 0x13f5: 0x0080,
0x13f6: 0x0080, 0x13f7: 0x0080, 0x13f8: 0x0080, 0x13f9: 0x0080,
// Block 0x50, offset 0x1400
0x1400: 0x0080, 0x1401: 0x0080, 0x1402: 0x0080, 0x1403: 0x0080, 0x1404: 0x0080, 0x1405: 0x0080,
0x1406: 0x0080, 0x1407: 0x0082, 0x1408: 0x0080, 0x1409: 0x0080, 0x140a: 0x0080, 0x140b: 0x0040,
0x140c: 0x0040, 0x140d: 0x0040, 0x140e: 0x0040, 0x140f: 0x0040, 0x1410: 0x00c0, 0x1411: 0x00c0,
0x1412: 0x00c0, 0x1413: 0x00c0, 0x1414: 0x00c0, 0x1415: 0x00c0, 0x1416: 0x00c0, 0x1417: 0x00c0,
0x1418: 0x00c0, 0x1419: 0x00c0,
0x1420: 0x00c2, 0x1421: 0x00c2, 0x1422: 0x00c2, 0x1423: 0x00c2,
0x1424: 0x00c2, 0x1425: 0x00c2, 0x1426: 0x00c2, 0x1427: 0x00c2, 0x1428: 0x00c2, 0x1429: 0x00c2,
0x142a: 0x00c2, 0x142b: 0x00c2, 0x142c: 0x00c2, 0x142d: 0x00c2, 0x142e: 0x00c2, 0x142f: 0x00c2,
0x1430: 0x00c2, 0x1431: 0x00c2, 0x1432: 0x00c2, 0x1433: 0x00c2, 0x1434: 0x00c2, 0x1435: 0x00c2,
0x1436: 0x00c2, 0x1437: 0x00c2, 0x1438: 0x00c2, 0x1439: 0x00c2, 0x143a: 0x00c2, 0x143b: 0x00c2,
0x143c: 0x00c2, 0x143d: 0x00c2, 0x143e: 0x00c2, 0x143f: 0x00c2,
// Block 0x51, offset 0x1440
0x1440: 0x00c2, 0x1441: 0x00c2, 0x1442: 0x00c2, 0x1443: 0x00c2, 0x1444: 0x00c2, 0x1445: 0x00c2,
0x1446: 0x00c2, 0x1447: 0x00c2, 0x1448: 0x00c2, 0x1449: 0x00c2, 0x144a: 0x00c2, 0x144b: 0x00c2,
0x144c: 0x00c2, 0x144d: 0x00c2, 0x144e: 0x00c2, 0x144f: 0x00c2, 0x1450: 0x00c2, 0x1451: 0x00c2,
0x1452: 0x00c2, 0x1453: 0x00c2, 0x1454: 0x00c2, 0x1455: 0x00c2, 0x1456: 0x00c2, 0x1457: 0x00c2,
0x1458: 0x00c2, 0x1459: 0x00c2, 0x145a: 0x00c2, 0x145b: 0x00c2, 0x145c: 0x00c2, 0x145d: 0x00c2,
0x145e: 0x00c2, 0x145f: 0x00c2, 0x1460: 0x00c2, 0x1461: 0x00c2, 0x1462: 0x00c2, 0x1463: 0x00c2,
0x1464: 0x00c2, 0x1465: 0x00c2, 0x1466: 0x00c2, 0x1467: 0x00c2, 0x1468: 0x00c2, 0x1469: 0x00c2,
0x146a: 0x00c2, 0x146b: 0x00c2, 0x146c: 0x00c2, 0x146d: 0x00c2, 0x146e: 0x00c2, 0x146f: 0x00c2,
0x1470: 0x00c2, 0x1471: 0x00c2, 0x1472: 0x00c2, 0x1473: 0x00c2, 0x1474: 0x00c2, 0x1475: 0x00c2,
0x1476: 0x00c2, 0x1477: 0x00c2, 0x1478: 0x00c2,
// Block 0x52, offset 0x1480
0x1480: 0x00c0, 0x1481: 0x00c0, 0x1482: 0x00c0, 0x1483: 0x00c0, 0x1484: 0x00c0, 0x1485: 0x00c3,
0x1486: 0x00c3, 0x1487: 0x00c2, 0x1488: 0x00c2, 0x1489: 0x00c2, 0x148a: 0x00c2, 0x148b: 0x00c2,
0x148c: 0x00c2, 0x148d: 0x00c2, 0x148e: 0x00c2, 0x148f: 0x00c2, 0x1490: 0x00c2, 0x1491: 0x00c2,
0x1492: 0x00c2, 0x1493: 0x00c2, 0x1494: 0x00c2, 0x1495: 0x00c2, 0x1496: 0x00c2, 0x1497: 0x00c2,
0x1498: 0x00c2, 0x1499: 0x00c2, 0x149a: 0x00c2, 0x149b: 0x00c2, 0x149c: 0x00c2, 0x149d: 0x00c2,
0x149e: 0x00c2, 0x149f: 0x00c2, 0x14a0: 0x00c2, 0x14a1: 0x00c2, 0x14a2: 0x00c2, 0x14a3: 0x00c2,
0x14a4: 0x00c2, 0x14a5: 0x00c2, 0x14a6: 0x00c2, 0x14a7: 0x00c2, 0x14a8: 0x00c2, 0x14a9: 0x00c3,
0x14aa: 0x00c2,
0x14b0: 0x00c0, 0x14b1: 0x00c0, 0x14b2: 0x00c0, 0x14b3: 0x00c0, 0x14b4: 0x00c0, 0x14b5: 0x00c0,
0x14b6: 0x00c0, 0x14b7: 0x00c0, 0x14b8: 0x00c0, 0x14b9: 0x00c0, 0x14ba: 0x00c0, 0x14bb: 0x00c0,
0x14bc: 0x00c0, 0x14bd: 0x00c0, 0x14be: 0x00c0, 0x14bf: 0x00c0,
// Block 0x53, offset 0x14c0
0x14c0: 0x00c0, 0x14c1: 0x00c0, 0x14c2: 0x00c0, 0x14c3: 0x00c0, 0x14c4: 0x00c0, 0x14c5: 0x00c0,
0x14c6: 0x00c0, 0x14c7: 0x00c0, 0x14c8: 0x00c0, 0x14c9: 0x00c0, 0x14ca: 0x00c0, 0x14cb: 0x00c0,
0x14cc: 0x00c0, 0x14cd: 0x00c0, 0x14ce: 0x00c0, 0x14cf: 0x00c0, 0x14d0: 0x00c0, 0x14d1: 0x00c0,
0x14d2: 0x00c0, 0x14d3: 0x00c0, 0x14d4: 0x00c0, 0x14d5: 0x00c0, 0x14d6: 0x00c0, 0x14d7: 0x00c0,
0x14d8: 0x00c0, 0x14d9: 0x00c0, 0x14da: 0x00c0, 0x14db: 0x00c0, 0x14dc: 0x00c0, 0x14dd: 0x00c0,
0x14de: 0x00c0, 0x14df: 0x00c0, 0x14e0: 0x00c0, 0x14e1: 0x00c0, 0x14e2: 0x00c0, 0x14e3: 0x00c0,
0x14e4: 0x00c0, 0x14e5: 0x00c0, 0x14e6: 0x00c0, 0x14e7: 0x00c0, 0x14e8: 0x00c0, 0x14e9: 0x00c0,
0x14ea: 0x00c0, 0x14eb: 0x00c0, 0x14ec: 0x00c0, 0x14ed: 0x00c0, 0x14ee: 0x00c0, 0x14ef: 0x00c0,
0x14f0: 0x00c0, 0x14f1: 0x00c0, 0x14f2: 0x00c0, 0x14f3: 0x00c0, 0x14f4: 0x00c0, 0x14f5: 0x00c0,
// Block 0x54, offset 0x1500
0x1500: 0x00c0, 0x1501: 0x00c0, 0x1502: 0x00c0, 0x1503: 0x00c0, 0x1504: 0x00c0, 0x1505: 0x00c0,
0x1506: 0x00c0, 0x1507: 0x00c0, 0x1508: 0x00c0, 0x1509: 0x00c0, 0x150a: 0x00c0, 0x150b: 0x00c0,
0x150c: 0x00c0, 0x150d: 0x00c0, 0x150e: 0x00c0, 0x150f: 0x00c0, 0x1510: 0x00c0, 0x1511: 0x00c0,
0x1512: 0x00c0, 0x1513: 0x00c0, 0x1514: 0x00c0, 0x1515: 0x00c0, 0x1516: 0x00c0, 0x1517: 0x00c0,
0x1518: 0x00c0, 0x1519: 0x00c0, 0x151a: 0x00c0, 0x151b: 0x00c0, 0x151c: 0x00c0, 0x151d: 0x00c0,
0x151e: 0x00c0, 0x1520: 0x00c3, 0x1521: 0x00c3, 0x1522: 0x00c3, 0x1523: 0x00c0,
0x1524: 0x00c0, 0x1525: 0x00c0, 0x1526: 0x00c0, 0x1527: 0x00c3, 0x1528: 0x00c3, 0x1529: 0x00c0,
0x152a: 0x00c0, 0x152b: 0x00c0,
0x1530: 0x00c0, 0x1531: 0x00c0, 0x1532: 0x00c3, 0x1533: 0x00c0, 0x1534: 0x00c0, 0x1535: 0x00c0,
0x1536: 0x00c0, 0x1537: 0x00c0, 0x1538: 0x00c0, 0x1539: 0x00c3, 0x153a: 0x00c3, 0x153b: 0x00c3,
// Block 0x55, offset 0x1540
0x1540: 0x0080, 0x1544: 0x0080, 0x1545: 0x0080,
0x1546: 0x00c0, 0x1547: 0x00c0, 0x1548: 0x00c0, 0x1549: 0x00c0, 0x154a: 0x00c0, 0x154b: 0x00c0,
0x154c: 0x00c0, 0x154d: 0x00c0, 0x154e: 0x00c0, 0x154f: 0x00c0, 0x1550: 0x00c0, 0x1551: 0x00c0,
0x1552: 0x00c0, 0x1553: 0x00c0, 0x1554: 0x00c0, 0x1555: 0x00c0, 0x1556: 0x00c0, 0x1557: 0x00c0,
0x1558: 0x00c0, 0x1559: 0x00c0, 0x155a: 0x00c0, 0x155b: 0x00c0, 0x155c: 0x00c0, 0x155d: 0x00c0,
0x155e: 0x00c0, 0x155f: 0x00c0, 0x1560: 0x00c0, 0x1561: 0x00c0, 0x1562: 0x00c0, 0x1563: 0x00c0,
0x1564: 0x00c0, 0x1565: 0x00c0, 0x1566: 0x00c0, 0x1567: 0x00c0, 0x1568: 0x00c0, 0x1569: 0x00c0,
0x156a: 0x00c0, 0x156b: 0x00c0, 0x156c: 0x00c0, 0x156d: 0x00c0,
0x1570: 0x00c0, 0x1571: 0x00c0, 0x1572: 0x00c0, 0x1573: 0x00c0, 0x1574: 0x00c0,
// Block 0x56, offset 0x1580
0x1580: 0x00c0, 0x1581: 0x00c0, 0x1582: 0x00c0, 0x1583: 0x00c0, 0x1584: 0x00c0, 0x1585: 0x00c0,
0x1586: 0x00c0, 0x1587: 0x00c0, 0x1588: 0x00c0, 0x1589: 0x00c0, 0x158a: 0x00c0, 0x158b: 0x00c0,
0x158c: 0x00c0, 0x158d: 0x00c0, 0x158e: 0x00c0, 0x158f: 0x00c0, 0x1590: 0x00c0, 0x1591: 0x00c0,
0x1592: 0x00c0, 0x1593: 0x00c0, 0x1594: 0x00c0, 0x1595: 0x00c0, 0x1596: 0x00c0, 0x1597: 0x00c0,
0x1598: 0x00c0, 0x1599: 0x00c0, 0x159a: 0x00c0, 0x159b: 0x00c0, 0x159c: 0x00c0, 0x159d: 0x00c0,
0x159e: 0x00c0, 0x159f: 0x00c0, 0x15a0: 0x00c0, 0x15a1: 0x00c0, 0x15a2: 0x00c0, 0x15a3: 0x00c0,
0x15a4: 0x00c0, 0x15a5: 0x00c0, 0x15a6: 0x00c0, 0x15a7: 0x00c0, 0x15a8: 0x00c0, 0x15a9: 0x00c0,
0x15aa: 0x00c0, 0x15ab: 0x00c0,
0x15b0: 0x00c0, 0x15b1: 0x00c0, 0x15b2: 0x00c0, 0x15b3: 0x00c0, 0x15b4: 0x00c0, 0x15b5: 0x00c0,
0x15b6: 0x00c0, 0x15b7: 0x00c0, 0x15b8: 0x00c0, 0x15b9: 0x00c0, 0x15ba: 0x00c0, 0x15bb: 0x00c0,
0x15bc: 0x00c0, 0x15bd: 0x00c0, 0x15be: 0x00c0, 0x15bf: 0x00c0,
// Block 0x57, offset 0x15c0
0x15c0: 0x00c0, 0x15c1: 0x00c0, 0x15c2: 0x00c0, 0x15c3: 0x00c0, 0x15c4: 0x00c0, 0x15c5: 0x00c0,
0x15c6: 0x00c0, 0x15c7: 0x00c0, 0x15c8: 0x00c0, 0x15c9: 0x00c0,
0x15d0: 0x00c0, 0x15d1: 0x00c0,
0x15d2: 0x00c0, 0x15d3: 0x00c0, 0x15d4: 0x00c0, 0x15d5: 0x00c0, 0x15d6: 0x00c0, 0x15d7: 0x00c0,
0x15d8: 0x00c0, 0x15d9: 0x00c0, 0x15da: 0x0080,
0x15de: 0x0080, 0x15df: 0x0080, 0x15e0: 0x0080, 0x15e1: 0x0080, 0x15e2: 0x0080, 0x15e3: 0x0080,
0x15e4: 0x0080, 0x15e5: 0x0080, 0x15e6: 0x0080, 0x15e7: 0x0080, 0x15e8: 0x0080, 0x15e9: 0x0080,
0x15ea: 0x0080, 0x15eb: 0x0080, 0x15ec: 0x0080, 0x15ed: 0x0080, 0x15ee: 0x0080, 0x15ef: 0x0080,
0x15f0: 0x0080, 0x15f1: 0x0080, 0x15f2: 0x0080, 0x15f3: 0x0080, 0x15f4: 0x0080, 0x15f5: 0x0080,
0x15f6: 0x0080, 0x15f7: 0x0080, 0x15f8: 0x0080, 0x15f9: 0x0080, 0x15fa: 0x0080, 0x15fb: 0x0080,
0x15fc: 0x0080, 0x15fd: 0x0080, 0x15fe: 0x0080, 0x15ff: 0x0080,
// Block 0x58, offset 0x1600
0x1600: 0x00c0, 0x1601: 0x00c0, 0x1602: 0x00c0, 0x1603: 0x00c0, 0x1604: 0x00c0, 0x1605: 0x00c0,
0x1606: 0x00c0, 0x1607: 0x00c0, 0x1608: 0x00c0, 0x1609: 0x00c0, 0x160a: 0x00c0, 0x160b: 0x00c0,
0x160c: 0x00c0, 0x160d: 0x00c0, 0x160e: 0x00c0, 0x160f: 0x00c0, 0x1610: 0x00c0, 0x1611: 0x00c0,
0x1612: 0x00c0, 0x1613: 0x00c0, 0x1614: 0x00c0, 0x1615: 0x00c0, 0x1616: 0x00c0, 0x1617: 0x00c3,
0x1618: 0x00c3, 0x1619: 0x00c0, 0x161a: 0x00c0, 0x161b: 0x00c3,
0x161e: 0x0080, 0x161f: 0x0080, 0x1620: 0x00c0, 0x1621: 0x00c0, 0x1622: 0x00c0, 0x1623: 0x00c0,
0x1624: 0x00c0, 0x1625: 0x00c0, 0x1626: 0x00c0, 0x1627: 0x00c0, 0x1628: 0x00c0, 0x1629: 0x00c0,
0x162a: 0x00c0, 0x162b: 0x00c0, 0x162c: 0x00c0, 0x162d: 0x00c0, 0x162e: 0x00c0, 0x162f: 0x00c0,
0x1630: 0x00c0, 0x1631: 0x00c0, 0x1632: 0x00c0, 0x1633: 0x00c0, 0x1634: 0x00c0, 0x1635: 0x00c0,
0x1636: 0x00c0, 0x1637: 0x00c0, 0x1638: 0x00c0, 0x1639: 0x00c0, 0x163a: 0x00c0, 0x163b: 0x00c0,
0x163c: 0x00c0, 0x163d: 0x00c0, 0x163e: 0x00c0, 0x163f: 0x00c0,
// Block 0x59, offset 0x1640
0x1640: 0x00c0, 0x1641: 0x00c0, 0x1642: 0x00c0, 0x1643: 0x00c0, 0x1644: 0x00c0, 0x1645: 0x00c0,
0x1646: 0x00c0, 0x1647: 0x00c0, 0x1648: 0x00c0, 0x1649: 0x00c0, 0x164a: 0x00c0, 0x164b: 0x00c0,
0x164c: 0x00c0, 0x164d: 0x00c0, 0x164e: 0x00c0, 0x164f: 0x00c0, 0x1650: 0x00c0, 0x1651: 0x00c0,
0x1652: 0x00c0, 0x1653: 0x00c0, 0x1654: 0x00c0, 0x1655: 0x00c0, 0x1656: 0x00c3, 0x1657: 0x00c0,
0x1658: 0x00c3, 0x1659: 0x00c3, 0x165a: 0x00c3, 0x165b: 0x00c3, 0x165c: 0x00c3, 0x165d: 0x00c3,
0x165e: 0x00c3, 0x1660: 0x00c6, 0x1661: 0x00c0, 0x1662: 0x00c3, 0x1663: 0x00c0,
0x1664: 0x00c0, 0x1665: 0x00c3, 0x1666: 0x00c3, 0x1667: 0x00c3, 0x1668: 0x00c3, 0x1669: 0x00c3,
0x166a: 0x00c3, 0x166b: 0x00c3, 0x166c: 0x00c3, 0x166d: 0x00c0, 0x166e: 0x00c0, 0x166f: 0x00c0,
0x1670: 0x00c0, 0x1671: 0x00c0, 0x1672: 0x00c0, 0x1673: 0x00c3, 0x1674: 0x00c3, 0x1675: 0x00c3,
0x1676: 0x00c3, 0x1677: 0x00c3, 0x1678: 0x00c3, 0x1679: 0x00c3, 0x167a: 0x00c3, 0x167b: 0x00c3,
0x167c: 0x00c3, 0x167f: 0x00c3,
// Block 0x5a, offset 0x1680
0x1680: 0x00c0, 0x1681: 0x00c0, 0x1682: 0x00c0, 0x1683: 0x00c0, 0x1684: 0x00c0, 0x1685: 0x00c0,
0x1686: 0x00c0, 0x1687: 0x00c0, 0x1688: 0x00c0, 0x1689: 0x00c0,
0x1690: 0x00c0, 0x1691: 0x00c0,
0x1692: 0x00c0, 0x1693: 0x00c0, 0x1694: 0x00c0, 0x1695: 0x00c0, 0x1696: 0x00c0, 0x1697: 0x00c0,
0x1698: 0x00c0, 0x1699: 0x00c0,
0x16a0: 0x0080, 0x16a1: 0x0080, 0x16a2: 0x0080, 0x16a3: 0x0080,
0x16a4: 0x0080, 0x16a5: 0x0080, 0x16a6: 0x0080, 0x16a7: 0x00c0, 0x16a8: 0x0080, 0x16a9: 0x0080,
0x16aa: 0x0080, 0x16ab: 0x0080, 0x16ac: 0x0080, 0x16ad: 0x0080,
0x16b0: 0x00c3, 0x16b1: 0x00c3, 0x16b2: 0x00c3, 0x16b3: 0x00c3, 0x16b4: 0x00c3, 0x16b5: 0x00c3,
0x16b6: 0x00c3, 0x16b7: 0x00c3, 0x16b8: 0x00c3, 0x16b9: 0x00c3, 0x16ba: 0x00c3, 0x16bb: 0x00c3,
0x16bc: 0x00c3, 0x16bd: 0x00c3, 0x16be: 0x0083, 0x16bf: 0x00c3,
// Block 0x5b, offset 0x16c0
0x16c0: 0x00c3, 0x16c1: 0x00c3, 0x16c2: 0x00c3, 0x16c3: 0x00c3, 0x16c4: 0x00c3, 0x16c5: 0x00c3,
0x16c6: 0x00c3, 0x16c7: 0x00c3, 0x16c8: 0x00c3, 0x16c9: 0x00c3, 0x16ca: 0x00c3, 0x16cb: 0x00c3,
0x16cc: 0x00c3, 0x16cd: 0x00c3, 0x16ce: 0x00c3,
// Block 0x5c, offset 0x1700
0x1700: 0x00c3, 0x1701: 0x00c3, 0x1702: 0x00c3, 0x1703: 0x00c3, 0x1704: 0x00c0, 0x1705: 0x00c0,
0x1706: 0x00c0, 0x1707: 0x00c0, 0x1708: 0x00c0, 0x1709: 0x00c0, 0x170a: 0x00c0, 0x170b: 0x00c0,
0x170c: 0x00c0, 0x170d: 0x00c0, 0x170e: 0x00c0, 0x170f: 0x00c0, 0x1710: 0x00c0, 0x1711: 0x00c0,
0x1712: 0x00c0, 0x1713: 0x00c0, 0x1714: 0x00c0, 0x1715: 0x00c0, 0x1716: 0x00c0, 0x1717: 0x00c0,
0x1718: 0x00c0, 0x1719: 0x00c0, 0x171a: 0x00c0, 0x171b: 0x00c0, 0x171c: 0x00c0, 0x171d: 0x00c0,
0x171e: 0x00c0, 0x171f: 0x00c0, 0x1720: 0x00c0, 0x1721: 0x00c0, 0x1722: 0x00c0, 0x1723: 0x00c0,
0x1724: 0x00c0, 0x1725: 0x00c0, 0x1726: 0x00c0, 0x1727: 0x00c0, 0x1728: 0x00c0, 0x1729: 0x00c0,
0x172a: 0x00c0, 0x172b: 0x00c0, 0x172c: 0x00c0, 0x172d: 0x00c0, 0x172e: 0x00c0, 0x172f: 0x00c0,
0x1730: 0x00c0, 0x1731: 0x00c0, 0x1732: 0x00c0, 0x1733: 0x00c0, 0x1734: 0x00c3, 0x1735: 0x00c0,
0x1736: 0x00c3, 0x1737: 0x00c3, 0x1738: 0x00c3, 0x1739: 0x00c3, 0x173a: 0x00c3, 0x173b: 0x00c0,
0x173c: 0x00c3, 0x173d: 0x00c0, 0x173e: 0x00c0, 0x173f: 0x00c0,
// Block 0x5d, offset 0x1740
0x1740: 0x00c0, 0x1741: 0x00c0, 0x1742: 0x00c3, 0x1743: 0x00c0, 0x1744: 0x00c5, 0x1745: 0x00c0,
0x1746: 0x00c0, 0x1747: 0x00c0, 0x1748: 0x00c0, 0x1749: 0x00c0, 0x174a: 0x00c0, 0x174b: 0x00c0,
0x174c: 0x00c0, 0x1750: 0x00c0, 0x1751: 0x00c0,
0x1752: 0x00c0, 0x1753: 0x00c0, 0x1754: 0x00c0, 0x1755: 0x00c0, 0x1756: 0x00c0, 0x1757: 0x00c0,
0x1758: 0x00c0, 0x1759: 0x00c0, 0x175a: 0x0080, 0x175b: 0x0080, 0x175c: 0x0080, 0x175d: 0x0080,
0x175e: 0x0080, 0x175f: 0x0080, 0x1760: 0x0080, 0x1761: 0x0080, 0x1762: 0x0080, 0x1763: 0x0080,
0x1764: 0x0080, 0x1765: 0x0080, 0x1766: 0x0080, 0x1767: 0x0080, 0x1768: 0x0080, 0x1769: 0x0080,
0x176a: 0x0080, 0x176b: 0x00c3, 0x176c: 0x00c3, 0x176d: 0x00c3, 0x176e: 0x00c3, 0x176f: 0x00c3,
0x1770: 0x00c3, 0x1771: 0x00c3, 0x1772: 0x00c3, 0x1773: 0x00c3, 0x1774: 0x0080, 0x1775: 0x0080,
0x1776: 0x0080, 0x1777: 0x0080, 0x1778: 0x0080, 0x1779: 0x0080, 0x177a: 0x0080, 0x177b: 0x0080,
0x177c: 0x0080, 0x177d: 0x0080, 0x177e: 0x0080,
// Block 0x5e, offset 0x1780
0x1780: 0x00c3, 0x1781: 0x00c3, 0x1782: 0x00c0, 0x1783: 0x00c0, 0x1784: 0x00c0, 0x1785: 0x00c0,
0x1786: 0x00c0, 0x1787: 0x00c0, 0x1788: 0x00c0, 0x1789: 0x00c0, 0x178a: 0x00c0, 0x178b: 0x00c0,
0x178c: 0x00c0, 0x178d: 0x00c0, 0x178e: 0x00c0, 0x178f: 0x00c0, 0x1790: 0x00c0, 0x1791: 0x00c0,
0x1792: 0x00c0, 0x1793: 0x00c0, 0x1794: 0x00c0, 0x1795: 0x00c0, 0x1796: 0x00c0, 0x1797: 0x00c0,
0x1798: 0x00c0, 0x1799: 0x00c0, 0x179a: 0x00c0, 0x179b: 0x00c0, 0x179c: 0x00c0, 0x179d: 0x00c0,
0x179e: 0x00c0, 0x179f: 0x00c0, 0x17a0: 0x00c0, 0x17a1: 0x00c0, 0x17a2: 0x00c3, 0x17a3: 0x00c3,
0x17a4: 0x00c3, 0x17a5: 0x00c3, 0x17a6: 0x00c0, 0x17a7: 0x00c0, 0x17a8: 0x00c3, 0x17a9: 0x00c3,
0x17aa: 0x00c5, 0x17ab: 0x00c6, 0x17ac: 0x00c3, 0x17ad: 0x00c3, 0x17ae: 0x00c0, 0x17af: 0x00c0,
0x17b0: 0x00c0, 0x17b1: 0x00c0, 0x17b2: 0x00c0, 0x17b3: 0x00c0, 0x17b4: 0x00c0, 0x17b5: 0x00c0,
0x17b6: 0x00c0, 0x17b7: 0x00c0, 0x17b8: 0x00c0, 0x17b9: 0x00c0, 0x17ba: 0x00c0, 0x17bb: 0x00c0,
0x17bc: 0x00c0, 0x17bd: 0x00c0, 0x17be: 0x00c0, 0x17bf: 0x00c0,
// Block 0x5f, offset 0x17c0
0x17c0: 0x00c0, 0x17c1: 0x00c0, 0x17c2: 0x00c0, 0x17c3: 0x00c0, 0x17c4: 0x00c0, 0x17c5: 0x00c0,
0x17c6: 0x00c0, 0x17c7: 0x00c0, 0x17c8: 0x00c0, 0x17c9: 0x00c0, 0x17ca: 0x00c0, 0x17cb: 0x00c0,
0x17cc: 0x00c0, 0x17cd: 0x00c0, 0x17ce: 0x00c0, 0x17cf: 0x00c0, 0x17d0: 0x00c0, 0x17d1: 0x00c0,
0x17d2: 0x00c0, 0x17d3: 0x00c0, 0x17d4: 0x00c0, 0x17d5: 0x00c0, 0x17d6: 0x00c0, 0x17d7: 0x00c0,
0x17d8: 0x00c0, 0x17d9: 0x00c0, 0x17da: 0x00c0, 0x17db: 0x00c0, 0x17dc: 0x00c0, 0x17dd: 0x00c0,
0x17de: 0x00c0, 0x17df: 0x00c0, 0x17e0: 0x00c0, 0x17e1: 0x00c0, 0x17e2: 0x00c0, 0x17e3: 0x00c0,
0x17e4: 0x00c0, 0x17e5: 0x00c0, 0x17e6: 0x00c3, 0x17e7: 0x00c0, 0x17e8: 0x00c3, 0x17e9: 0x00c3,
0x17ea: 0x00c0, 0x17eb: 0x00c0, 0x17ec: 0x00c0, 0x17ed: 0x00c3, 0x17ee: 0x00c0, 0x17ef: 0x00c3,
0x17f0: 0x00c3, 0x17f1: 0x00c3, 0x17f2: 0x00c5, 0x17f3: 0x00c5,
0x17fc: 0x0080, 0x17fd: 0x0080, 0x17fe: 0x0080, 0x17ff: 0x0080,
// Block 0x60, offset 0x1800
0x1800: 0x00c0, 0x1801: 0x00c0, 0x1802: 0x00c0, 0x1803: 0x00c0, 0x1804: 0x00c0, 0x1805: 0x00c0,
0x1806: 0x00c0, 0x1807: 0x00c0, 0x1808: 0x00c0, 0x1809: 0x00c0, 0x180a: 0x00c0, 0x180b: 0x00c0,
0x180c: 0x00c0, 0x180d: 0x00c0, 0x180e: 0x00c0, 0x180f: 0x00c0, 0x1810: 0x00c0, 0x1811: 0x00c0,
0x1812: 0x00c0, 0x1813: 0x00c0, 0x1814: 0x00c0, 0x1815: 0x00c0, 0x1816: 0x00c0, 0x1817: 0x00c0,
0x1818: 0x00c0, 0x1819: 0x00c0, 0x181a: 0x00c0, 0x181b: 0x00c0, 0x181c: 0x00c0, 0x181d: 0x00c0,
0x181e: 0x00c0, 0x181f: 0x00c0, 0x1820: 0x00c0, 0x1821: 0x00c0, 0x1822: 0x00c0, 0x1823: 0x00c0,
0x1824: 0x00c0, 0x1825: 0x00c0, 0x1826: 0x00c0, 0x1827: 0x00c0, 0x1828: 0x00c0, 0x1829: 0x00c0,
0x182a: 0x00c0, 0x182b: 0x00c0, 0x182c: 0x00c3, 0x182d: 0x00c3, 0x182e: 0x00c3, 0x182f: 0x00c3,
0x1830: 0x00c3, 0x1831: 0x00c3, 0x1832: 0x00c3, 0x1833: 0x00c3, 0x1834: 0x00c0, 0x1835: 0x00c0,
0x1836: 0x00c3, 0x1837: 0x00c3, 0x183b: 0x0080,
0x183c: 0x0080, 0x183d: 0x0080, 0x183e: 0x0080, 0x183f: 0x0080,
// Block 0x61, offset 0x1840
0x1840: 0x00c0, 0x1841: 0x00c0, 0x1842: 0x00c0, 0x1843: 0x00c0, 0x1844: 0x00c0, 0x1845: 0x00c0,
0x1846: 0x00c0, 0x1847: 0x00c0, 0x1848: 0x00c0, 0x1849: 0x00c0,
0x184d: 0x00c0, 0x184e: 0x00c0, 0x184f: 0x00c0, 0x1850: 0x00c0, 0x1851: 0x00c0,
0x1852: 0x00c0, 0x1853: 0x00c0, 0x1854: 0x00c0, 0x1855: 0x00c0, 0x1856: 0x00c0, 0x1857: 0x00c0,
0x1858: 0x00c0, 0x1859: 0x00c0, 0x185a: 0x00c0, 0x185b: 0x00c0, 0x185c: 0x00c0, 0x185d: 0x00c0,
0x185e: 0x00c0, 0x185f: 0x00c0, 0x1860: 0x00c0, 0x1861: 0x00c0, 0x1862: 0x00c0, 0x1863: 0x00c0,
0x1864: 0x00c0, 0x1865: 0x00c0, 0x1866: 0x00c0, 0x1867: 0x00c0, 0x1868: 0x00c0, 0x1869: 0x00c0,
0x186a: 0x00c0, 0x186b: 0x00c0, 0x186c: 0x00c0, 0x186d: 0x00c0, 0x186e: 0x00c0, 0x186f: 0x00c0,
0x1870: 0x00c0, 0x1871: 0x00c0, 0x1872: 0x00c0, 0x1873: 0x00c0, 0x1874: 0x00c0, 0x1875: 0x00c0,
0x1876: 0x00c0, 0x1877: 0x00c0, 0x1878: 0x00c0, 0x1879: 0x00c0, 0x187a: 0x00c0, 0x187b: 0x00c0,
0x187c: 0x00c0, 0x187d: 0x00c0, 0x187e: 0x0080, 0x187f: 0x0080,
// Block 0x62, offset 0x1880
0x1880: 0x00c0, 0x1881: 0x00c0, 0x1882: 0x00c0, 0x1883: 0x00c0, 0x1884: 0x00c0, 0x1885: 0x00c0,
0x1886: 0x00c0, 0x1887: 0x00c0, 0x1888: 0x00c0,
0x1890: 0x00c0, 0x1891: 0x00c0,
0x1892: 0x00c0, 0x1893: 0x00c0, 0x1894: 0x00c0, 0x1895: 0x00c0, 0x1896: 0x00c0, 0x1897: 0x00c0,
0x1898: 0x00c0, 0x1899: 0x00c0, 0x189a: 0x00c0, 0x189b: 0x00c0, 0x189c: 0x00c0, 0x189d: 0x00c0,
0x189e: 0x00c0, 0x189f: 0x00c0, 0x18a0: 0x00c0, 0x18a1: 0x00c0, 0x18a2: 0x00c0, 0x18a3: 0x00c0,
0x18a4: 0x00c0, 0x18a5: 0x00c0, 0x18a6: 0x00c0, 0x18a7: 0x00c0, 0x18a8: 0x00c0, 0x18a9: 0x00c0,
0x18aa: 0x00c0, 0x18ab: 0x00c0, 0x18ac: 0x00c0, 0x18ad: 0x00c0, 0x18ae: 0x00c0, 0x18af: 0x00c0,
0x18b0: 0x00c0, 0x18b1: 0x00c0, 0x18b2: 0x00c0, 0x18b3: 0x00c0, 0x18b4: 0x00c0, 0x18b5: 0x00c0,
0x18b6: 0x00c0, 0x18b7: 0x00c0, 0x18b8: 0x00c0, 0x18b9: 0x00c0, 0x18ba: 0x00c0,
0x18bd: 0x00c0, 0x18be: 0x00c0, 0x18bf: 0x00c0,
// Block 0x63, offset 0x18c0
0x18c0: 0x0080, 0x18c1: 0x0080, 0x18c2: 0x0080, 0x18c3: 0x0080, 0x18c4: 0x0080, 0x18c5: 0x0080,
0x18c6: 0x0080, 0x18c7: 0x0080,
0x18d0: 0x00c3, 0x18d1: 0x00c3,
0x18d2: 0x00c3, 0x18d3: 0x0080, 0x18d4: 0x00c3, 0x18d5: 0x00c3, 0x18d6: 0x00c3, 0x18d7: 0x00c3,
0x18d8: 0x00c3, 0x18d9: 0x00c3, 0x18da: 0x00c3, 0x18db: 0x00c3, 0x18dc: 0x00c3, 0x18dd: 0x00c3,
0x18de: 0x00c3, 0x18df: 0x00c3, 0x18e0: 0x00c3, 0x18e1: 0x00c0, 0x18e2: 0x00c3, 0x18e3: 0x00c3,
0x18e4: 0x00c3, 0x18e5: 0x00c3, 0x18e6: 0x00c3, 0x18e7: 0x00c3, 0x18e8: 0x00c3, 0x18e9: 0x00c0,
0x18ea: 0x00c0, 0x18eb: 0x00c0, 0x18ec: 0x00c0, 0x18ed: 0x00c3, 0x18ee: 0x00c0, 0x18ef: 0x00c0,
0x18f0: 0x00c0, 0x18f1: 0x00c0, 0x18f2: 0x00c0, 0x18f3: 0x00c0, 0x18f4: 0x00c3, 0x18f5: 0x00c0,
0x18f6: 0x00c0, 0x18f7: 0x00c0, 0x18f8: 0x00c3, 0x18f9: 0x00c3, 0x18fa: 0x00c0,
// Block 0x64, offset 0x1900
0x1900: 0x00c0, 0x1901: 0x00c0, 0x1902: 0x00c0, 0x1903: 0x00c0, 0x1904: 0x00c0, 0x1905: 0x00c0,
0x1906: 0x00c0, 0x1907: 0x00c0, 0x1908: 0x00c0, 0x1909: 0x00c0, 0x190a: 0x00c0, 0x190b: 0x00c0,
0x190c: 0x00c0, 0x190d: 0x00c0, 0x190e: 0x00c0, 0x190f: 0x00c0, 0x1910: 0x00c0, 0x1911: 0x00c0,
0x1912: 0x00c0, 0x1913: 0x00c0, 0x1914: 0x00c0, 0x1915: 0x00c0, 0x1916: 0x00c0, 0x1917: 0x00c0,
0x1918: 0x00c0, 0x1919: 0x00c0, 0x191a: 0x00c0, 0x191b: 0x00c0, 0x191c: 0x00c0, 0x191d: 0x00c0,
0x191e: 0x00c0, 0x191f: 0x00c0, 0x1920: 0x00c0, 0x1921: 0x00c0, 0x1922: 0x00c0, 0x1923: 0x00c0,
0x1924: 0x00c0, 0x1925: 0x00c0, 0x1926: 0x00c8, 0x1927: 0x00c8, 0x1928: 0x00c8, 0x1929: 0x00c8,
0x192a: 0x00c8, 0x192b: 0x00c0, 0x192c: 0x0080, 0x192d: 0x0080, 0x192e: 0x0080, 0x192f: 0x00c0,
0x1930: 0x0080, 0x1931: 0x0080, 0x1932: 0x0080, 0x1933: 0x0080, 0x1934: 0x0080, 0x1935: 0x0080,
0x1936: 0x0080, 0x1937: 0x0080, 0x1938: 0x0080, 0x1939: 0x0080, 0x193a: 0x0080, 0x193b: 0x00c0,
0x193c: 0x0080, 0x193d: 0x0080, 0x193e: 0x0080, 0x193f: 0x0080,
// Block 0x65, offset 0x1940
0x1940: 0x0080, 0x1941: 0x0080, 0x1942: 0x0080, 0x1943: 0x0080, 0x1944: 0x0080, 0x1945: 0x0080,
0x1946: 0x0080, 0x1947: 0x0080, 0x1948: 0x0080, 0x1949: 0x0080, 0x194a: 0x0080, 0x194b: 0x0080,
0x194c: 0x0080, 0x194d: 0x0080, 0x194e: 0x00c0, 0x194f: 0x0080, 0x1950: 0x0080, 0x1951: 0x0080,
0x1952: 0x0080, 0x1953: 0x0080, 0x1954: 0x0080, 0x1955: 0x0080, 0x1956: 0x0080, 0x1957: 0x0080,
0x1958: 0x0080, 0x1959: 0x0080, 0x195a: 0x0080, 0x195b: 0x0080, 0x195c: 0x0080, 0x195d: 0x0088,
0x195e: 0x0088, 0x195f: 0x0088, 0x1960: 0x0088, 0x1961: 0x0088, 0x1962: 0x0080, 0x1963: 0x0080,
0x1964: 0x0080, 0x1965: 0x0080, 0x1966: 0x0088, 0x1967: 0x0088, 0x1968: 0x0088, 0x1969: 0x0088,
0x196a: 0x0088, 0x196b: 0x00c0, 0x196c: 0x00c0, 0x196d: 0x00c0, 0x196e: 0x00c0, 0x196f: 0x00c0,
0x1970: 0x00c0, 0x1971: 0x00c0, 0x1972: 0x00c0, 0x1973: 0x00c0, 0x1974: 0x00c0, 0x1975: 0x00c0,
0x1976: 0x00c0, 0x1977: 0x00c0, 0x1978: 0x0080, 0x1979: 0x00c0, 0x197a: 0x00c0, 0x197b: 0x00c0,
0x197c: 0x00c0, 0x197d: 0x00c0, 0x197e: 0x00c0, 0x197f: 0x00c0,
// Block 0x66, offset 0x1980
0x1980: 0x00c0, 0x1981: 0x00c0, 0x1982: 0x00c0, 0x1983: 0x00c0, 0x1984: 0x00c0, 0x1985: 0x00c0,
0x1986: 0x00c0, 0x1987: 0x00c0, 0x1988: 0x00c0, 0x1989: 0x00c0, 0x198a: 0x00c0, 0x198b: 0x00c0,
0x198c: 0x00c0, 0x198d: 0x00c0, 0x198e: 0x00c0, 0x198f: 0x00c0, 0x1990: 0x00c0, 0x1991: 0x00c0,
0x1992: 0x00c0, 0x1993: 0x00c0, 0x1994: 0x00c0, 0x1995: 0x00c0, 0x1996: 0x00c0, 0x1997: 0x00c0,
0x1998: 0x00c0, 0x1999: 0x00c0, 0x199a: 0x00c0, 0x199b: 0x0080, 0x199c: 0x0080, 0x199d: 0x0080,
0x199e: 0x0080, 0x199f: 0x0080, 0x19a0: 0x0080, 0x19a1: 0x0080, 0x19a2: 0x0080, 0x19a3: 0x0080,
0x19a4: 0x0080, 0x19a5: 0x0080, 0x19a6: 0x0080, 0x19a7: 0x0080, 0x19a8: 0x0080, 0x19a9: 0x0080,
0x19aa: 0x0080, 0x19ab: 0x0080, 0x19ac: 0x0080, 0x19ad: 0x0080, 0x19ae: 0x0080, 0x19af: 0x0080,
0x19b0: 0x0080, 0x19b1: 0x0080, 0x19b2: 0x0080, 0x19b3: 0x0080, 0x19b4: 0x0080, 0x19b5: 0x0080,
0x19b6: 0x0080, 0x19b7: 0x0080, 0x19b8: 0x0080, 0x19b9: 0x0080, 0x19ba: 0x0080, 0x19bb: 0x0080,
0x19bc: 0x0080, 0x19bd: 0x0080, 0x19be: 0x0080, 0x19bf: 0x0088,
// Block 0x67, offset 0x19c0
0x19c0: 0x00c0, 0x19c1: 0x00c0, 0x19c2: 0x00c0, 0x19c3: 0x00c0, 0x19c4: 0x00c0, 0x19c5: 0x00c0,
0x19c6: 0x00c0, 0x19c7: 0x00c0, 0x19c8: 0x00c0, 0x19c9: 0x00c0, 0x19ca: 0x00c0, 0x19cb: 0x00c0,
0x19cc: 0x00c0, 0x19cd: 0x00c0, 0x19ce: 0x00c0, 0x19cf: 0x00c0, 0x19d0: 0x00c0, 0x19d1: 0x00c0,
0x19d2: 0x00c0, 0x19d3: 0x00c0, 0x19d4: 0x00c0, 0x19d5: 0x00c0, 0x19d6: 0x00c0, 0x19d7: 0x00c0,
0x19d8: 0x00c0, 0x19d9: 0x00c0, 0x19da: 0x0080, 0x19db: 0x0080, 0x19dc: 0x00c0, 0x19dd: 0x00c0,
0x19de: 0x00c0, 0x19df: 0x00c0, 0x19e0: 0x00c0, 0x19e1: 0x00c0, 0x19e2: 0x00c0, 0x19e3: 0x00c0,
0x19e4: 0x00c0, 0x19e5: 0x00c0, 0x19e6: 0x00c0, 0x19e7: 0x00c0, 0x19e8: 0x00c0, 0x19e9: 0x00c0,
0x19ea: 0x00c0, 0x19eb: 0x00c0, 0x19ec: 0x00c0, 0x19ed: 0x00c0, 0x19ee: 0x00c0, 0x19ef: 0x00c0,
0x19f0: 0x00c0, 0x19f1: 0x00c0, 0x19f2: 0x00c0, 0x19f3: 0x00c0, 0x19f4: 0x00c0, 0x19f5: 0x00c0,
0x19f6: 0x00c0, 0x19f7: 0x00c0, 0x19f8: 0x00c0, 0x19f9: 0x00c0, 0x19fa: 0x00c0, 0x19fb: 0x00c0,
0x19fc: 0x00c0, 0x19fd: 0x00c0, 0x19fe: 0x00c0, 0x19ff: 0x00c0,
// Block 0x68, offset 0x1a00
0x1a00: 0x00c8, 0x1a01: 0x00c8, 0x1a02: 0x00c8, 0x1a03: 0x00c8, 0x1a04: 0x00c8, 0x1a05: 0x00c8,
0x1a06: 0x00c8, 0x1a07: 0x00c8, 0x1a08: 0x00c8, 0x1a09: 0x00c8, 0x1a0a: 0x00c8, 0x1a0b: 0x00c8,
0x1a0c: 0x00c8, 0x1a0d: 0x00c8, 0x1a0e: 0x00c8, 0x1a0f: 0x00c8, 0x1a10: 0x00c8, 0x1a11: 0x00c8,
0x1a12: 0x00c8, 0x1a13: 0x00c8, 0x1a14: 0x00c8, 0x1a15: 0x00c8,
0x1a18: 0x00c8, 0x1a19: 0x00c8, 0x1a1a: 0x00c8, 0x1a1b: 0x00c8, 0x1a1c: 0x00c8, 0x1a1d: 0x00c8,
0x1a20: 0x00c8, 0x1a21: 0x00c8, 0x1a22: 0x00c8, 0x1a23: 0x00c8,
0x1a24: 0x00c8, 0x1a25: 0x00c8, 0x1a26: 0x00c8, 0x1a27: 0x00c8, 0x1a28: 0x00c8, 0x1a29: 0x00c8,
0x1a2a: 0x00c8, 0x1a2b: 0x00c8, 0x1a2c: 0x00c8, 0x1a2d: 0x00c8, 0x1a2e: 0x00c8, 0x1a2f: 0x00c8,
0x1a30: 0x00c8, 0x1a31: 0x00c8, 0x1a32: 0x00c8, 0x1a33: 0x00c8, 0x1a34: 0x00c8, 0x1a35: 0x00c8,
0x1a36: 0x00c8, 0x1a37: 0x00c8, 0x1a38: 0x00c8, 0x1a39: 0x00c8, 0x1a3a: 0x00c8, 0x1a3b: 0x00c8,
0x1a3c: 0x00c8, 0x1a3d: 0x00c8, 0x1a3e: 0x00c8, 0x1a3f: 0x00c8,
// Block 0x69, offset 0x1a40
0x1a40: 0x00c8, 0x1a41: 0x00c8, 0x1a42: 0x00c8, 0x1a43: 0x00c8, 0x1a44: 0x00c8, 0x1a45: 0x00c8,
0x1a48: 0x00c8, 0x1a49: 0x00c8, 0x1a4a: 0x00c8, 0x1a4b: 0x00c8,
0x1a4c: 0x00c8, 0x1a4d: 0x00c8, 0x1a50: 0x00c8, 0x1a51: 0x00c8,
0x1a52: 0x00c8, 0x1a53: 0x00c8, 0x1a54: 0x00c8, 0x1a55: 0x00c8, 0x1a56: 0x00c8, 0x1a57: 0x00c8,
0x1a59: 0x00c8, 0x1a5b: 0x00c8, 0x1a5d: 0x00c8,
0x1a5f: 0x00c8, 0x1a60: 0x00c8, 0x1a61: 0x00c8, 0x1a62: 0x00c8, 0x1a63: 0x00c8,
0x1a64: 0x00c8, 0x1a65: 0x00c8, 0x1a66: 0x00c8, 0x1a67: 0x00c8, 0x1a68: 0x00c8, 0x1a69: 0x00c8,
0x1a6a: 0x00c8, 0x1a6b: 0x00c8, 0x1a6c: 0x00c8, 0x1a6d: 0x00c8, 0x1a6e: 0x00c8, 0x1a6f: 0x00c8,
0x1a70: 0x00c8, 0x1a71: 0x0088, 0x1a72: 0x00c8, 0x1a73: 0x0088, 0x1a74: 0x00c8, 0x1a75: 0x0088,
0x1a76: 0x00c8, 0x1a77: 0x0088, 0x1a78: 0x00c8, 0x1a79: 0x0088, 0x1a7a: 0x00c8, 0x1a7b: 0x0088,
0x1a7c: 0x00c8, 0x1a7d: 0x0088,
// Block 0x6a, offset 0x1a80
0x1a80: 0x00c8, 0x1a81: 0x00c8, 0x1a82: 0x00c8, 0x1a83: 0x00c8, 0x1a84: 0x00c8, 0x1a85: 0x00c8,
0x1a86: 0x00c8, 0x1a87: 0x00c8, 0x1a88: 0x0088, 0x1a89: 0x0088, 0x1a8a: 0x0088, 0x1a8b: 0x0088,
0x1a8c: 0x0088, 0x1a8d: 0x0088, 0x1a8e: 0x0088, 0x1a8f: 0x0088, 0x1a90: 0x00c8, 0x1a91: 0x00c8,
0x1a92: 0x00c8, 0x1a93: 0x00c8, 0x1a94: 0x00c8, 0x1a95: 0x00c8, 0x1a96: 0x00c8, 0x1a97: 0x00c8,
0x1a98: 0x0088, 0x1a99: 0x0088, 0x1a9a: 0x0088, 0x1a9b: 0x0088, 0x1a9c: 0x0088, 0x1a9d: 0x0088,
0x1a9e: 0x0088, 0x1a9f: 0x0088, 0x1aa0: 0x00c8, 0x1aa1: 0x00c8, 0x1aa2: 0x00c8, 0x1aa3: 0x00c8,
0x1aa4: 0x00c8, 0x1aa5: 0x00c8, 0x1aa6: 0x00c8, 0x1aa7: 0x00c8, 0x1aa8: 0x0088, 0x1aa9: 0x0088,
0x1aaa: 0x0088, 0x1aab: 0x0088, 0x1aac: 0x0088, 0x1aad: 0x0088, 0x1aae: 0x0088, 0x1aaf: 0x0088,
0x1ab0: 0x00c8, 0x1ab1: 0x00c8, 0x1ab2: 0x00c8, 0x1ab3: 0x00c8, 0x1ab4: 0x00c8,
0x1ab6: 0x00c8, 0x1ab7: 0x00c8, 0x1ab8: 0x00c8, 0x1ab9: 0x00c8, 0x1aba: 0x00c8, 0x1abb: 0x0088,
0x1abc: 0x0088, 0x1abd: 0x0088, 0x1abe: 0x0088, 0x1abf: 0x0088,
// Block 0x6b, offset 0x1ac0
0x1ac0: 0x0088, 0x1ac1: 0x0088, 0x1ac2: 0x00c8, 0x1ac3: 0x00c8, 0x1ac4: 0x00c8,
0x1ac6: 0x00c8, 0x1ac7: 0x00c8, 0x1ac8: 0x00c8, 0x1ac9: 0x0088, 0x1aca: 0x00c8, 0x1acb: 0x0088,
0x1acc: 0x0088, 0x1acd: 0x0088, 0x1ace: 0x0088, 0x1acf: 0x0088, 0x1ad0: 0x00c8, 0x1ad1: 0x00c8,
0x1ad2: 0x00c8, 0x1ad3: 0x0088, 0x1ad6: 0x00c8, 0x1ad7: 0x00c8,
0x1ad8: 0x00c8, 0x1ad9: 0x00c8, 0x1ada: 0x00c8, 0x1adb: 0x0088, 0x1add: 0x0088,
0x1ade: 0x0088, 0x1adf: 0x0088, 0x1ae0: 0x00c8, 0x1ae1: 0x00c8, 0x1ae2: 0x00c8, 0x1ae3: 0x0088,
0x1ae4: 0x00c8, 0x1ae5: 0x00c8, 0x1ae6: 0x00c8, 0x1ae7: 0x00c8, 0x1ae8: 0x00c8, 0x1ae9: 0x00c8,
0x1aea: 0x00c8, 0x1aeb: 0x0088, 0x1aec: 0x00c8, 0x1aed: 0x0088, 0x1aee: 0x0088, 0x1aef: 0x0088,
0x1af2: 0x00c8, 0x1af3: 0x00c8, 0x1af4: 0x00c8,
0x1af6: 0x00c8, 0x1af7: 0x00c8, 0x1af8: 0x00c8, 0x1af9: 0x0088, 0x1afa: 0x00c8, 0x1afb: 0x0088,
0x1afc: 0x0088, 0x1afd: 0x0088, 0x1afe: 0x0088,
// Block 0x6c, offset 0x1b00
0x1b00: 0x0080, 0x1b01: 0x0080, 0x1b02: 0x0080, 0x1b03: 0x0080, 0x1b04: 0x0080, 0x1b05: 0x0080,
0x1b06: 0x0080, 0x1b07: 0x0080, 0x1b08: 0x0080, 0x1b09: 0x0080, 0x1b0a: 0x0080, 0x1b0b: 0x0040,
0x1b0c: 0x004d, 0x1b0d: 0x004e, 0x1b0e: 0x0040, 0x1b0f: 0x0040, 0x1b10: 0x0080, 0x1b11: 0x0080,
0x1b12: 0x0080, 0x1b13: 0x0080, 0x1b14: 0x0080, 0x1b15: 0x0080, 0x1b16: 0x0080, 0x1b17: 0x0080,
0x1b18: 0x0080, 0x1b19: 0x0080, 0x1b1a: 0x0080, 0x1b1b: 0x0080, 0x1b1c: 0x0080, 0x1b1d: 0x0080,
0x1b1e: 0x0080, 0x1b1f: 0x0080, 0x1b20: 0x0080, 0x1b21: 0x0080, 0x1b22: 0x0080, 0x1b23: 0x0080,
0x1b24: 0x0080, 0x1b25: 0x0080, 0x1b26: 0x0080, 0x1b27: 0x0080, 0x1b28: 0x0040, 0x1b29: 0x0040,
0x1b2a: 0x0040, 0x1b2b: 0x0040, 0x1b2c: 0x0040, 0x1b2d: 0x0040, 0x1b2e: 0x0040, 0x1b2f: 0x0080,
0x1b30: 0x0080, 0x1b31: 0x0080, 0x1b32: 0x0080, 0x1b33: 0x0080, 0x1b34: 0x0080, 0x1b35: 0x0080,
0x1b36: 0x0080, 0x1b37: 0x0080, 0x1b38: 0x0080, 0x1b39: 0x0080, 0x1b3a: 0x0080, 0x1b3b: 0x0080,
0x1b3c: 0x0080, 0x1b3d: 0x0080, 0x1b3e: 0x0080, 0x1b3f: 0x0080,
// Block 0x6d, offset 0x1b40
0x1b40: 0x0080, 0x1b41: 0x0080, 0x1b42: 0x0080, 0x1b43: 0x0080, 0x1b44: 0x0080, 0x1b45: 0x0080,
0x1b46: 0x0080, 0x1b47: 0x0080, 0x1b48: 0x0080, 0x1b49: 0x0080, 0x1b4a: 0x0080, 0x1b4b: 0x0080,
0x1b4c: 0x0080, 0x1b4d: 0x0080, 0x1b4e: 0x0080, 0x1b4f: 0x0080, 0x1b50: 0x0080, 0x1b51: 0x0080,
0x1b52: 0x0080, 0x1b53: 0x0080, 0x1b54: 0x0080, 0x1b55: 0x0080, 0x1b56: 0x0080, 0x1b57: 0x0080,
0x1b58: 0x0080, 0x1b59: 0x0080, 0x1b5a: 0x0080, 0x1b5b: 0x0080, 0x1b5c: 0x0080, 0x1b5d: 0x0080,
0x1b5e: 0x0080, 0x1b5f: 0x0080, 0x1b60: 0x0040, 0x1b61: 0x0040, 0x1b62: 0x0040, 0x1b63: 0x0040,
0x1b64: 0x0040, 0x1b66: 0x0040, 0x1b67: 0x0040, 0x1b68: 0x0040, 0x1b69: 0x0040,
0x1b6a: 0x0040, 0x1b6b: 0x0040, 0x1b6c: 0x0040, 0x1b6d: 0x0040, 0x1b6e: 0x0040, 0x1b6f: 0x0040,
0x1b70: 0x0080, 0x1b71: 0x0080, 0x1b74: 0x0080, 0x1b75: 0x0080,
0x1b76: 0x0080, 0x1b77: 0x0080, 0x1b78: 0x0080, 0x1b79: 0x0080, 0x1b7a: 0x0080, 0x1b7b: 0x0080,
0x1b7c: 0x0080, 0x1b7d: 0x0080, 0x1b7e: 0x0080, 0x1b7f: 0x0080,
// Block 0x6e, offset 0x1b80
0x1b80: 0x0080, 0x1b81: 0x0080, 0x1b82: 0x0080, 0x1b83: 0x0080, 0x1b84: 0x0080, 0x1b85: 0x0080,
0x1b86: 0x0080, 0x1b87: 0x0080, 0x1b88: 0x0080, 0x1b89: 0x0080, 0x1b8a: 0x0080, 0x1b8b: 0x0080,
0x1b8c: 0x0080, 0x1b8d: 0x0080, 0x1b8e: 0x0080, 0x1b90: 0x0080, 0x1b91: 0x0080,
0x1b92: 0x0080, 0x1b93: 0x0080, 0x1b94: 0x0080, 0x1b95: 0x0080, 0x1b96: 0x0080, 0x1b97: 0x0080,
0x1b98: 0x0080, 0x1b99: 0x0080, 0x1b9a: 0x0080, 0x1b9b: 0x0080, 0x1b9c: 0x0080,
0x1ba0: 0x0080, 0x1ba1: 0x0080, 0x1ba2: 0x0080, 0x1ba3: 0x0080,
0x1ba4: 0x0080, 0x1ba5: 0x0080, 0x1ba6: 0x0080, 0x1ba7: 0x0080, 0x1ba8: 0x0080, 0x1ba9: 0x0080,
0x1baa: 0x0080, 0x1bab: 0x0080, 0x1bac: 0x0080, 0x1bad: 0x0080, 0x1bae: 0x0080, 0x1baf: 0x0080,
0x1bb0: 0x0080, 0x1bb1: 0x0080, 0x1bb2: 0x0080, 0x1bb3: 0x0080, 0x1bb4: 0x0080, 0x1bb5: 0x0080,
0x1bb6: 0x0080, 0x1bb7: 0x0080, 0x1bb8: 0x0080, 0x1bb9: 0x0080, 0x1bba: 0x0080, 0x1bbb: 0x0080,
0x1bbc: 0x0080, 0x1bbd: 0x0080, 0x1bbe: 0x0080, 0x1bbf: 0x0080,
// Block 0x6f, offset 0x1bc0
0x1bc0: 0x0080,
0x1bd0: 0x00c3, 0x1bd1: 0x00c3,
0x1bd2: 0x00c3, 0x1bd3: 0x00c3, 0x1bd4: 0x00c3, 0x1bd5: 0x00c3, 0x1bd6: 0x00c3, 0x1bd7: 0x00c3,
0x1bd8: 0x00c3, 0x1bd9: 0x00c3, 0x1bda: 0x00c3, 0x1bdb: 0x00c3, 0x1bdc: 0x00c3, 0x1bdd: 0x0083,
0x1bde: 0x0083, 0x1bdf: 0x0083, 0x1be0: 0x0083, 0x1be1: 0x00c3, 0x1be2: 0x0083, 0x1be3: 0x0083,
0x1be4: 0x0083, 0x1be5: 0x00c3, 0x1be6: 0x00c3, 0x1be7: 0x00c3, 0x1be8: 0x00c3, 0x1be9: 0x00c3,
0x1bea: 0x00c3, 0x1beb: 0x00c3, 0x1bec: 0x00c3, 0x1bed: 0x00c3, 0x1bee: 0x00c3, 0x1bef: 0x00c3,
0x1bf0: 0x00c3,
// Block 0x70, offset 0x1c00
0x1c00: 0x0080, 0x1c01: 0x0080, 0x1c02: 0x0080, 0x1c03: 0x0080, 0x1c04: 0x0080, 0x1c05: 0x0080,
0x1c06: 0x0080, 0x1c07: 0x0080, 0x1c08: 0x0080, 0x1c09: 0x0080, 0x1c0a: 0x0080, 0x1c0b: 0x0080,
0x1c0c: 0x0080, 0x1c0d: 0x0080, 0x1c0e: 0x0080, 0x1c0f: 0x0080, 0x1c10: 0x0080, 0x1c11: 0x0080,
0x1c12: 0x0080, 0x1c13: 0x0080, 0x1c14: 0x0080, 0x1c15: 0x0080, 0x1c16: 0x0080, 0x1c17: 0x0080,
0x1c18: 0x0080, 0x1c19: 0x0080, 0x1c1a: 0x0080, 0x1c1b: 0x0080, 0x1c1c: 0x0080, 0x1c1d: 0x0080,
0x1c1e: 0x0080, 0x1c1f: 0x0080, 0x1c20: 0x0080, 0x1c21: 0x0080, 0x1c22: 0x0080, 0x1c23: 0x0080,
0x1c24: 0x0080, 0x1c25: 0x0080, 0x1c26: 0x0088, 0x1c27: 0x0080, 0x1c28: 0x0080, 0x1c29: 0x0080,
0x1c2a: 0x0080, 0x1c2b: 0x0080, 0x1c2c: 0x0080, 0x1c2d: 0x0080, 0x1c2e: 0x0080, 0x1c2f: 0x0080,
0x1c30: 0x0080, 0x1c31: 0x0080, 0x1c32: 0x00c0, 0x1c33: 0x0080, 0x1c34: 0x0080, 0x1c35: 0x0080,
0x1c36: 0x0080, 0x1c37: 0x0080, 0x1c38: 0x0080, 0x1c39: 0x0080, 0x1c3a: 0x0080, 0x1c3b: 0x0080,
0x1c3c: 0x0080, 0x1c3d: 0x0080, 0x1c3e: 0x0080, 0x1c3f: 0x0080,
// Block 0x71, offset 0x1c40
0x1c40: 0x0080, 0x1c41: 0x0080, 0x1c42: 0x0080, 0x1c43: 0x0080, 0x1c44: 0x0080, 0x1c45: 0x0080,
0x1c46: 0x0080, 0x1c47: 0x0080, 0x1c48: 0x0080, 0x1c49: 0x0080, 0x1c4a: 0x0080, 0x1c4b: 0x0080,
0x1c4c: 0x0080, 0x1c4d: 0x0080, 0x1c4e: 0x00c0, 0x1c4f: 0x0080, 0x1c50: 0x0080, 0x1c51: 0x0080,
0x1c52: 0x0080, 0x1c53: 0x0080, 0x1c54: 0x0080, 0x1c55: 0x0080, 0x1c56: 0x0080, 0x1c57: 0x0080,
0x1c58: 0x0080, 0x1c59: 0x0080, 0x1c5a: 0x0080, 0x1c5b: 0x0080, 0x1c5c: 0x0080, 0x1c5d: 0x0080,
0x1c5e: 0x0080, 0x1c5f: 0x0080, 0x1c60: 0x0080, 0x1c61: 0x0080, 0x1c62: 0x0080, 0x1c63: 0x0080,
0x1c64: 0x0080, 0x1c65: 0x0080, 0x1c66: 0x0080, 0x1c67: 0x0080, 0x1c68: 0x0080, 0x1c69: 0x0080,
0x1c6a: 0x0080, 0x1c6b: 0x0080, 0x1c6c: 0x0080, 0x1c6d: 0x0080, 0x1c6e: 0x0080, 0x1c6f: 0x0080,
0x1c70: 0x0080, 0x1c71: 0x0080, 0x1c72: 0x0080, 0x1c73: 0x0080, 0x1c74: 0x0080, 0x1c75: 0x0080,
0x1c76: 0x0080, 0x1c77: 0x0080, 0x1c78: 0x0080, 0x1c79: 0x0080, 0x1c7a: 0x0080, 0x1c7b: 0x0080,
0x1c7c: 0x0080, 0x1c7d: 0x0080, 0x1c7e: 0x0080, 0x1c7f: 0x0080,
// Block 0x72, offset 0x1c80
0x1c80: 0x0080, 0x1c81: 0x0080, 0x1c82: 0x0080, 0x1c83: 0x00c0, 0x1c84: 0x00c0, 0x1c85: 0x0080,
0x1c86: 0x0080, 0x1c87: 0x0080, 0x1c88: 0x0080, 0x1c89: 0x0080, 0x1c8a: 0x0080, 0x1c8b: 0x0080,
0x1c90: 0x0080, 0x1c91: 0x0080,
0x1c92: 0x0080, 0x1c93: 0x0080, 0x1c94: 0x0080, 0x1c95: 0x0080, 0x1c96: 0x0080, 0x1c97: 0x0080,
0x1c98: 0x0080, 0x1c99: 0x0080, 0x1c9a: 0x0080, 0x1c9b: 0x0080, 0x1c9c: 0x0080, 0x1c9d: 0x0080,
0x1c9e: 0x0080, 0x1c9f: 0x0080, 0x1ca0: 0x0080, 0x1ca1: 0x0080, 0x1ca2: 0x0080, 0x1ca3: 0x0080,
0x1ca4: 0x0080, 0x1ca5: 0x0080, 0x1ca6: 0x0080, 0x1ca7: 0x0080, 0x1ca8: 0x0080, 0x1ca9: 0x0080,
0x1caa: 0x0080, 0x1cab: 0x0080, 0x1cac: 0x0080, 0x1cad: 0x0080, 0x1cae: 0x0080, 0x1caf: 0x0080,
0x1cb0: 0x0080, 0x1cb1: 0x0080, 0x1cb2: 0x0080, 0x1cb3: 0x0080, 0x1cb4: 0x0080, 0x1cb5: 0x0080,
0x1cb6: 0x0080, 0x1cb7: 0x0080, 0x1cb8: 0x0080, 0x1cb9: 0x0080, 0x1cba: 0x0080, 0x1cbb: 0x0080,
0x1cbc: 0x0080, 0x1cbd: 0x0080, 0x1cbe: 0x0080, 0x1cbf: 0x0080,
// Block 0x73, offset 0x1cc0
0x1cc0: 0x0080, 0x1cc1: 0x0080, 0x1cc2: 0x0080, 0x1cc3: 0x0080, 0x1cc4: 0x0080, 0x1cc5: 0x0080,
0x1cc6: 0x0080, 0x1cc7: 0x0080, 0x1cc8: 0x0080, 0x1cc9: 0x0080, 0x1cca: 0x0080, 0x1ccb: 0x0080,
0x1ccc: 0x0080, 0x1ccd: 0x0080, 0x1cce: 0x0080, 0x1ccf: 0x0080, 0x1cd0: 0x0080, 0x1cd1: 0x0080,
0x1cd2: 0x0080, 0x1cd3: 0x0080, 0x1cd4: 0x0080, 0x1cd5: 0x0080, 0x1cd6: 0x0080, 0x1cd7: 0x0080,
0x1cd8: 0x0080, 0x1cd9: 0x0080, 0x1cda: 0x0080, 0x1cdb: 0x0080, 0x1cdc: 0x0080, 0x1cdd: 0x0080,
0x1cde: 0x0080, 0x1cdf: 0x0080, 0x1ce0: 0x0080, 0x1ce1: 0x0080, 0x1ce2: 0x0080, 0x1ce3: 0x0080,
0x1ce4: 0x0080, 0x1ce5: 0x0080, 0x1ce6: 0x0080, 0x1ce7: 0x0080, 0x1ce8: 0x0080, 0x1ce9: 0x0080,
0x1cea: 0x0080, 0x1ceb: 0x0080, 0x1cec: 0x0080, 0x1ced: 0x0080, 0x1cee: 0x0080, 0x1cef: 0x0080,
0x1cf0: 0x0080, 0x1cf1: 0x0080, 0x1cf2: 0x0080, 0x1cf3: 0x0080, 0x1cf4: 0x0080, 0x1cf5: 0x0080,
0x1cf6: 0x0080, 0x1cf7: 0x0080, 0x1cf8: 0x0080, 0x1cf9: 0x0080, 0x1cfa: 0x0080, 0x1cfb: 0x0080,
0x1cfc: 0x0080, 0x1cfd: 0x0080, 0x1cfe: 0x0080, 0x1cff: 0x0080,
// Block 0x74, offset 0x1d00
0x1d00: 0x0080, 0x1d01: 0x0080, 0x1d02: 0x0080, 0x1d03: 0x0080, 0x1d04: 0x0080, 0x1d05: 0x0080,
0x1d06: 0x0080, 0x1d07: 0x0080, 0x1d08: 0x0080, 0x1d09: 0x0080, 0x1d0a: 0x0080, 0x1d0b: 0x0080,
0x1d0c: 0x0080, 0x1d0d: 0x0080, 0x1d0e: 0x0080, 0x1d0f: 0x0080, 0x1d10: 0x0080, 0x1d11: 0x0080,
0x1d12: 0x0080, 0x1d13: 0x0080, 0x1d14: 0x0080, 0x1d15: 0x0080, 0x1d16: 0x0080, 0x1d17: 0x0080,
0x1d18: 0x0080, 0x1d19: 0x0080, 0x1d1a: 0x0080, 0x1d1b: 0x0080, 0x1d1c: 0x0080, 0x1d1d: 0x0080,
0x1d1e: 0x0080, 0x1d1f: 0x0080, 0x1d20: 0x0080, 0x1d21: 0x0080, 0x1d22: 0x0080, 0x1d23: 0x0080,
0x1d24: 0x0080, 0x1d25: 0x0080, 0x1d26: 0x0080,
// Block 0x75, offset 0x1d40
0x1d40: 0x0080, 0x1d41: 0x0080, 0x1d42: 0x0080, 0x1d43: 0x0080, 0x1d44: 0x0080, 0x1d45: 0x0080,
0x1d46: 0x0080, 0x1d47: 0x0080, 0x1d48: 0x0080, 0x1d49: 0x0080, 0x1d4a: 0x0080,
0x1d60: 0x0080, 0x1d61: 0x0080, 0x1d62: 0x0080, 0x1d63: 0x0080,
0x1d64: 0x0080, 0x1d65: 0x0080, 0x1d66: 0x0080, 0x1d67: 0x0080, 0x1d68: 0x0080, 0x1d69: 0x0080,
0x1d6a: 0x0080, 0x1d6b: 0x0080, 0x1d6c: 0x0080, 0x1d6d: 0x0080, 0x1d6e: 0x0080, 0x1d6f: 0x0080,
0x1d70: 0x0080, 0x1d71: 0x0080, 0x1d72: 0x0080, 0x1d73: 0x0080, 0x1d74: 0x0080, 0x1d75: 0x0080,
0x1d76: 0x0080, 0x1d77: 0x0080, 0x1d78: 0x0080, 0x1d79: 0x0080, 0x1d7a: 0x0080, 0x1d7b: 0x0080,
0x1d7c: 0x0080, 0x1d7d: 0x0080, 0x1d7e: 0x0080, 0x1d7f: 0x0080,
// Block 0x76, offset 0x1d80
0x1d80: 0x0080, 0x1d81: 0x0080, 0x1d82: 0x0080, 0x1d83: 0x0080, 0x1d84: 0x0080, 0x1d85: 0x0080,
0x1d86: 0x0080, 0x1d87: 0x0080, 0x1d88: 0x0080, 0x1d89: 0x0080, 0x1d8a: 0x0080, 0x1d8b: 0x0080,
0x1d8c: 0x0080, 0x1d8d: 0x0080, 0x1d8e: 0x0080, 0x1d8f: 0x0080, 0x1d90: 0x0080, 0x1d91: 0x0080,
0x1d92: 0x0080, 0x1d93: 0x0080, 0x1d94: 0x0080, 0x1d95: 0x0080, 0x1d96: 0x0080, 0x1d97: 0x0080,
0x1d98: 0x0080, 0x1d99: 0x0080, 0x1d9a: 0x0080, 0x1d9b: 0x0080, 0x1d9c: 0x0080, 0x1d9d: 0x0080,
0x1d9e: 0x0080, 0x1d9f: 0x0080, 0x1da0: 0x0080, 0x1da1: 0x0080, 0x1da2: 0x0080, 0x1da3: 0x0080,
0x1da4: 0x0080, 0x1da5: 0x0080, 0x1da6: 0x0080, 0x1da7: 0x0080, 0x1da8: 0x0080, 0x1da9: 0x0080,
0x1daa: 0x0080, 0x1dab: 0x0080, 0x1dac: 0x0080, 0x1dad: 0x0080, 0x1dae: 0x0080, 0x1daf: 0x0080,
0x1db0: 0x0080, 0x1db1: 0x0080, 0x1db2: 0x0080, 0x1db3: 0x0080,
0x1db6: 0x0080, 0x1db7: 0x0080, 0x1db8: 0x0080, 0x1db9: 0x0080, 0x1dba: 0x0080, 0x1dbb: 0x0080,
0x1dbc: 0x0080, 0x1dbd: 0x0080, 0x1dbe: 0x0080, 0x1dbf: 0x0080,
// Block 0x77, offset 0x1dc0
0x1dc0: 0x0080, 0x1dc1: 0x0080, 0x1dc2: 0x0080, 0x1dc3: 0x0080, 0x1dc4: 0x0080, 0x1dc5: 0x0080,
0x1dc6: 0x0080, 0x1dc7: 0x0080, 0x1dc8: 0x0080, 0x1dc9: 0x0080, 0x1dca: 0x0080, 0x1dcb: 0x0080,
0x1dcc: 0x0080, 0x1dcd: 0x0080, 0x1dce: 0x0080, 0x1dcf: 0x0080, 0x1dd0: 0x0080, 0x1dd1: 0x0080,
0x1dd2: 0x0080, 0x1dd3: 0x0080, 0x1dd4: 0x0080, 0x1dd5: 0x0080, 0x1dd7: 0x0080,
0x1dd8: 0x0080, 0x1dd9: 0x0080, 0x1dda: 0x0080, 0x1ddb: 0x0080, 0x1ddc: 0x0080, 0x1ddd: 0x0080,
0x1dde: 0x0080, 0x1ddf: 0x0080, 0x1de0: 0x0080, 0x1de1: 0x0080, 0x1de2: 0x0080, 0x1de3: 0x0080,
0x1de4: 0x0080, 0x1de5: 0x0080, 0x1de6: 0x0080, 0x1de7: 0x0080, 0x1de8: 0x0080, 0x1de9: 0x0080,
0x1dea: 0x0080, 0x1deb: 0x0080, 0x1dec: 0x0080, 0x1ded: 0x0080, 0x1dee: 0x0080, 0x1def: 0x0080,
0x1df0: 0x0080, 0x1df1: 0x0080, 0x1df2: 0x0080, 0x1df3: 0x0080, 0x1df4: 0x0080, 0x1df5: 0x0080,
0x1df6: 0x0080, 0x1df7: 0x0080, 0x1df8: 0x0080, 0x1df9: 0x0080, 0x1dfa: 0x0080, 0x1dfb: 0x0080,
0x1dfc: 0x0080, 0x1dfd: 0x0080, 0x1dfe: 0x0080, 0x1dff: 0x0080,
// Block 0x78, offset 0x1e00
0x1e00: 0x00c0, 0x1e01: 0x00c0, 0x1e02: 0x00c0, 0x1e03: 0x00c0, 0x1e04: 0x00c0, 0x1e05: 0x00c0,
0x1e06: 0x00c0, 0x1e07: 0x00c0, 0x1e08: 0x00c0, 0x1e09: 0x00c0, 0x1e0a: 0x00c0, 0x1e0b: 0x00c0,
0x1e0c: 0x00c0, 0x1e0d: 0x00c0, 0x1e0e: 0x00c0, 0x1e0f: 0x00c0, 0x1e10: 0x00c0, 0x1e11: 0x00c0,
0x1e12: 0x00c0, 0x1e13: 0x00c0, 0x1e14: 0x00c0, 0x1e15: 0x00c0, 0x1e16: 0x00c0, 0x1e17: 0x00c0,
0x1e18: 0x00c0, 0x1e19: 0x00c0, 0x1e1a: 0x00c0, 0x1e1b: 0x00c0, 0x1e1c: 0x00c0, 0x1e1d: 0x00c0,
0x1e1e: 0x00c0, 0x1e1f: 0x00c0, 0x1e20: 0x00c0, 0x1e21: 0x00c0, 0x1e22: 0x00c0, 0x1e23: 0x00c0,
0x1e24: 0x00c0, 0x1e25: 0x00c0, 0x1e26: 0x00c0, 0x1e27: 0x00c0, 0x1e28: 0x00c0, 0x1e29: 0x00c0,
0x1e2a: 0x00c0, 0x1e2b: 0x00c0, 0x1e2c: 0x00c0, 0x1e2d: 0x00c0, 0x1e2e: 0x00c0, 0x1e2f: 0x00c0,
0x1e30: 0x00c0, 0x1e31: 0x00c0, 0x1e32: 0x00c0, 0x1e33: 0x00c0, 0x1e34: 0x00c0, 0x1e35: 0x00c0,
0x1e36: 0x00c0, 0x1e37: 0x00c0, 0x1e38: 0x00c0, 0x1e39: 0x00c0, 0x1e3a: 0x00c0, 0x1e3b: 0x00c0,
0x1e3c: 0x0080, 0x1e3d: 0x0080, 0x1e3e: 0x00c0, 0x1e3f: 0x00c0,
// Block 0x79, offset 0x1e40
0x1e40: 0x00c0, 0x1e41: 0x00c0, 0x1e42: 0x00c0, 0x1e43: 0x00c0, 0x1e44: 0x00c0, 0x1e45: 0x00c0,
0x1e46: 0x00c0, 0x1e47: 0x00c0, 0x1e48: 0x00c0, 0x1e49: 0x00c0, 0x1e4a: 0x00c0, 0x1e4b: 0x00c0,
0x1e4c: 0x00c0, 0x1e4d: 0x00c0, 0x1e4e: 0x00c0, 0x1e4f: 0x00c0, 0x1e50: 0x00c0, 0x1e51: 0x00c0,
0x1e52: 0x00c0, 0x1e53: 0x00c0, 0x1e54: 0x00c0, 0x1e55: 0x00c0, 0x1e56: 0x00c0, 0x1e57: 0x00c0,
0x1e58: 0x00c0, 0x1e59: 0x00c0, 0x1e5a: 0x00c0, 0x1e5b: 0x00c0, 0x1e5c: 0x00c0, 0x1e5d: 0x00c0,
0x1e5e: 0x00c0, 0x1e5f: 0x00c0, 0x1e60: 0x00c0, 0x1e61: 0x00c0, 0x1e62: 0x00c0, 0x1e63: 0x00c0,
0x1e64: 0x00c0, 0x1e65: 0x0080, 0x1e66: 0x0080, 0x1e67: 0x0080, 0x1e68: 0x0080, 0x1e69: 0x0080,
0x1e6a: 0x0080, 0x1e6b: 0x00c0, 0x1e6c: 0x00c0, 0x1e6d: 0x00c0, 0x1e6e: 0x00c0, 0x1e6f: 0x00c3,
0x1e70: 0x00c3, 0x1e71: 0x00c3, 0x1e72: 0x00c0, 0x1e73: 0x00c0,
0x1e79: 0x0080, 0x1e7a: 0x0080, 0x1e7b: 0x0080,
0x1e7c: 0x0080, 0x1e7d: 0x0080, 0x1e7e: 0x0080, 0x1e7f: 0x0080,
// Block 0x7a, offset 0x1e80
0x1e80: 0x00c0, 0x1e81: 0x00c0, 0x1e82: 0x00c0, 0x1e83: 0x00c0, 0x1e84: 0x00c0, 0x1e85: 0x00c0,
0x1e86: 0x00c0, 0x1e87: 0x00c0, 0x1e88: 0x00c0, 0x1e89: 0x00c0, 0x1e8a: 0x00c0, 0x1e8b: 0x00c0,
0x1e8c: 0x00c0, 0x1e8d: 0x00c0, 0x1e8e: 0x00c0, 0x1e8f: 0x00c0, 0x1e90: 0x00c0, 0x1e91: 0x00c0,
0x1e92: 0x00c0, 0x1e93: 0x00c0, 0x1e94: 0x00c0, 0x1e95: 0x00c0, 0x1e96: 0x00c0, 0x1e97: 0x00c0,
0x1e98: 0x00c0, 0x1e99: 0x00c0, 0x1e9a: 0x00c0, 0x1e9b: 0x00c0, 0x1e9c: 0x00c0, 0x1e9d: 0x00c0,
0x1e9e: 0x00c0, 0x1e9f: 0x00c0, 0x1ea0: 0x00c0, 0x1ea1: 0x00c0, 0x1ea2: 0x00c0, 0x1ea3: 0x00c0,
0x1ea4: 0x00c0, 0x1ea5: 0x00c0, 0x1ea7: 0x00c0,
0x1ead: 0x00c0,
0x1eb0: 0x00c0, 0x1eb1: 0x00c0, 0x1eb2: 0x00c0, 0x1eb3: 0x00c0, 0x1eb4: 0x00c0, 0x1eb5: 0x00c0,
0x1eb6: 0x00c0, 0x1eb7: 0x00c0, 0x1eb8: 0x00c0, 0x1eb9: 0x00c0, 0x1eba: 0x00c0, 0x1ebb: 0x00c0,
0x1ebc: 0x00c0, 0x1ebd: 0x00c0, 0x1ebe: 0x00c0, 0x1ebf: 0x00c0,
// Block 0x7b, offset 0x1ec0
0x1ec0: 0x00c0, 0x1ec1: 0x00c0, 0x1ec2: 0x00c0, 0x1ec3: 0x00c0, 0x1ec4: 0x00c0, 0x1ec5: 0x00c0,
0x1ec6: 0x00c0, 0x1ec7: 0x00c0, 0x1ec8: 0x00c0, 0x1ec9: 0x00c0, 0x1eca: 0x00c0, 0x1ecb: 0x00c0,
0x1ecc: 0x00c0, 0x1ecd: 0x00c0, 0x1ece: 0x00c0, 0x1ecf: 0x00c0, 0x1ed0: 0x00c0, 0x1ed1: 0x00c0,
0x1ed2: 0x00c0, 0x1ed3: 0x00c0, 0x1ed4: 0x00c0, 0x1ed5: 0x00c0, 0x1ed6: 0x00c0, 0x1ed7: 0x00c0,
0x1ed8: 0x00c0, 0x1ed9: 0x00c0, 0x1eda: 0x00c0, 0x1edb: 0x00c0, 0x1edc: 0x00c0, 0x1edd: 0x00c0,
0x1ede: 0x00c0, 0x1edf: 0x00c0, 0x1ee0: 0x00c0, 0x1ee1: 0x00c0, 0x1ee2: 0x00c0, 0x1ee3: 0x00c0,
0x1ee4: 0x00c0, 0x1ee5: 0x00c0, 0x1ee6: 0x00c0, 0x1ee7: 0x00c0,
0x1eef: 0x0080,
0x1ef0: 0x0080,
0x1eff: 0x00c6,
// Block 0x7c, offset 0x1f00
0x1f00: 0x00c0, 0x1f01: 0x00c0, 0x1f02: 0x00c0, 0x1f03: 0x00c0, 0x1f04: 0x00c0, 0x1f05: 0x00c0,
0x1f06: 0x00c0, 0x1f07: 0x00c0, 0x1f08: 0x00c0, 0x1f09: 0x00c0, 0x1f0a: 0x00c0, 0x1f0b: 0x00c0,
0x1f0c: 0x00c0, 0x1f0d: 0x00c0, 0x1f0e: 0x00c0, 0x1f0f: 0x00c0, 0x1f10: 0x00c0, 0x1f11: 0x00c0,
0x1f12: 0x00c0, 0x1f13: 0x00c0, 0x1f14: 0x00c0, 0x1f15: 0x00c0, 0x1f16: 0x00c0,
0x1f20: 0x00c0, 0x1f21: 0x00c0, 0x1f22: 0x00c0, 0x1f23: 0x00c0,
0x1f24: 0x00c0, 0x1f25: 0x00c0, 0x1f26: 0x00c0, 0x1f28: 0x00c0, 0x1f29: 0x00c0,
0x1f2a: 0x00c0, 0x1f2b: 0x00c0, 0x1f2c: 0x00c0, 0x1f2d: 0x00c0, 0x1f2e: 0x00c0,
0x1f30: 0x00c0, 0x1f31: 0x00c0, 0x1f32: 0x00c0, 0x1f33: 0x00c0, 0x1f34: 0x00c0, 0x1f35: 0x00c0,
0x1f36: 0x00c0, 0x1f38: 0x00c0, 0x1f39: 0x00c0, 0x1f3a: 0x00c0, 0x1f3b: 0x00c0,
0x1f3c: 0x00c0, 0x1f3d: 0x00c0, 0x1f3e: 0x00c0,
// Block 0x7d, offset 0x1f40
0x1f40: 0x00c0, 0x1f41: 0x00c0, 0x1f42: 0x00c0, 0x1f43: 0x00c0, 0x1f44: 0x00c0, 0x1f45: 0x00c0,
0x1f46: 0x00c0, 0x1f48: 0x00c0, 0x1f49: 0x00c0, 0x1f4a: 0x00c0, 0x1f4b: 0x00c0,
0x1f4c: 0x00c0, 0x1f4d: 0x00c0, 0x1f4e: 0x00c0, 0x1f50: 0x00c0, 0x1f51: 0x00c0,
0x1f52: 0x00c0, 0x1f53: 0x00c0, 0x1f54: 0x00c0, 0x1f55: 0x00c0, 0x1f56: 0x00c0,
0x1f58: 0x00c0, 0x1f59: 0x00c0, 0x1f5a: 0x00c0, 0x1f5b: 0x00c0, 0x1f5c: 0x00c0, 0x1f5d: 0x00c0,
0x1f5e: 0x00c0, 0x1f60: 0x00c3, 0x1f61: 0x00c3, 0x1f62: 0x00c3, 0x1f63: 0x00c3,
0x1f64: 0x00c3, 0x1f65: 0x00c3, 0x1f66: 0x00c3, 0x1f67: 0x00c3, 0x1f68: 0x00c3, 0x1f69: 0x00c3,
0x1f6a: 0x00c3, 0x1f6b: 0x00c3, 0x1f6c: 0x00c3, 0x1f6d: 0x00c3, 0x1f6e: 0x00c3, 0x1f6f: 0x00c3,
0x1f70: 0x00c3, 0x1f71: 0x00c3, 0x1f72: 0x00c3, 0x1f73: 0x00c3, 0x1f74: 0x00c3, 0x1f75: 0x00c3,
0x1f76: 0x00c3, 0x1f77: 0x00c3, 0x1f78: 0x00c3, 0x1f79: 0x00c3, 0x1f7a: 0x00c3, 0x1f7b: 0x00c3,
0x1f7c: 0x00c3, 0x1f7d: 0x00c3, 0x1f7e: 0x00c3, 0x1f7f: 0x00c3,
// Block 0x7e, offset 0x1f80
0x1f80: 0x0080, 0x1f81: 0x0080, 0x1f82: 0x0080, 0x1f83: 0x0080, 0x1f84: 0x0080, 0x1f85: 0x0080,
0x1f86: 0x0080, 0x1f87: 0x0080, 0x1f88: 0x0080, 0x1f89: 0x0080, 0x1f8a: 0x0080, 0x1f8b: 0x0080,
0x1f8c: 0x0080, 0x1f8d: 0x0080, 0x1f8e: 0x0080, 0x1f8f: 0x0080, 0x1f90: 0x0080, 0x1f91: 0x0080,
0x1f92: 0x0080, 0x1f93: 0x0080, 0x1f94: 0x0080, 0x1f95: 0x0080, 0x1f96: 0x0080, 0x1f97: 0x0080,
0x1f98: 0x0080, 0x1f99: 0x0080, 0x1f9a: 0x0080, 0x1f9b: 0x0080, 0x1f9c: 0x0080, 0x1f9d: 0x0080,
0x1f9e: 0x0080, 0x1f9f: 0x0080, 0x1fa0: 0x0080, 0x1fa1: 0x0080, 0x1fa2: 0x0080, 0x1fa3: 0x0080,
0x1fa4: 0x0080, 0x1fa5: 0x0080, 0x1fa6: 0x0080, 0x1fa7: 0x0080, 0x1fa8: 0x0080, 0x1fa9: 0x0080,
0x1faa: 0x0080, 0x1fab: 0x0080, 0x1fac: 0x0080, 0x1fad: 0x0080, 0x1fae: 0x0080, 0x1faf: 0x00c0,
0x1fb0: 0x0080, 0x1fb1: 0x0080, 0x1fb2: 0x0080, 0x1fb3: 0x0080, 0x1fb4: 0x0080, 0x1fb5: 0x0080,
0x1fb6: 0x0080, 0x1fb7: 0x0080, 0x1fb8: 0x0080, 0x1fb9: 0x0080, 0x1fba: 0x0080, 0x1fbb: 0x0080,
0x1fbc: 0x0080, 0x1fbd: 0x0080, 0x1fbe: 0x0080, 0x1fbf: 0x0080,
// Block 0x7f, offset 0x1fc0
0x1fc0: 0x0080, 0x1fc1: 0x0080, 0x1fc2: 0x0080, 0x1fc3: 0x0080, 0x1fc4: 0x0080, 0x1fc5: 0x0080,
0x1fc6: 0x0080, 0x1fc7: 0x0080, 0x1fc8: 0x0080, 0x1fc9: 0x0080, 0x1fca: 0x0080, 0x1fcb: 0x0080,
0x1fcc: 0x0080, 0x1fcd: 0x0080, 0x1fce: 0x0080, 0x1fcf: 0x0080, 0x1fd0: 0x0080, 0x1fd1: 0x0080,
0x1fd2: 0x0080, 0x1fd3: 0x0080, 0x1fd4: 0x0080, 0x1fd5: 0x0080, 0x1fd6: 0x0080, 0x1fd7: 0x0080,
0x1fd8: 0x0080, 0x1fd9: 0x0080, 0x1fda: 0x0080, 0x1fdb: 0x0080, 0x1fdc: 0x0080, 0x1fdd: 0x0080,
// Block 0x80, offset 0x2000
0x2000: 0x008c, 0x2001: 0x008c, 0x2002: 0x008c, 0x2003: 0x008c, 0x2004: 0x008c, 0x2005: 0x008c,
0x2006: 0x008c, 0x2007: 0x008c, 0x2008: 0x008c, 0x2009: 0x008c, 0x200a: 0x008c, 0x200b: 0x008c,
0x200c: 0x008c, 0x200d: 0x008c, 0x200e: 0x008c, 0x200f: 0x008c, 0x2010: 0x008c, 0x2011: 0x008c,
0x2012: 0x008c, 0x2013: 0x008c, 0x2014: 0x008c, 0x2015: 0x008c, 0x2016: 0x008c, 0x2017: 0x008c,
0x2018: 0x008c, 0x2019: 0x008c, 0x201b: 0x008c, 0x201c: 0x008c, 0x201d: 0x008c,
0x201e: 0x008c, 0x201f: 0x008c, 0x2020: 0x008c, 0x2021: 0x008c, 0x2022: 0x008c, 0x2023: 0x008c,
0x2024: 0x008c, 0x2025: 0x008c, 0x2026: 0x008c, 0x2027: 0x008c, 0x2028: 0x008c, 0x2029: 0x008c,
0x202a: 0x008c, 0x202b: 0x008c, 0x202c: 0x008c, 0x202d: 0x008c, 0x202e: 0x008c, 0x202f: 0x008c,
0x2030: 0x008c, 0x2031: 0x008c, 0x2032: 0x008c, 0x2033: 0x008c, 0x2034: 0x008c, 0x2035: 0x008c,
0x2036: 0x008c, 0x2037: 0x008c, 0x2038: 0x008c, 0x2039: 0x008c, 0x203a: 0x008c, 0x203b: 0x008c,
0x203c: 0x008c, 0x203d: 0x008c, 0x203e: 0x008c, 0x203f: 0x008c,
// Block 0x81, offset 0x2040
0x2040: 0x008c, 0x2041: 0x008c, 0x2042: 0x008c, 0x2043: 0x008c, 0x2044: 0x008c, 0x2045: 0x008c,
0x2046: 0x008c, 0x2047: 0x008c, 0x2048: 0x008c, 0x2049: 0x008c, 0x204a: 0x008c, 0x204b: 0x008c,
0x204c: 0x008c, 0x204d: 0x008c, 0x204e: 0x008c, 0x204f: 0x008c, 0x2050: 0x008c, 0x2051: 0x008c,
0x2052: 0x008c, 0x2053: 0x008c, 0x2054: 0x008c, 0x2055: 0x008c, 0x2056: 0x008c, 0x2057: 0x008c,
0x2058: 0x008c, 0x2059: 0x008c, 0x205a: 0x008c, 0x205b: 0x008c, 0x205c: 0x008c, 0x205d: 0x008c,
0x205e: 0x008c, 0x205f: 0x008c, 0x2060: 0x008c, 0x2061: 0x008c, 0x2062: 0x008c, 0x2063: 0x008c,
0x2064: 0x008c, 0x2065: 0x008c, 0x2066: 0x008c, 0x2067: 0x008c, 0x2068: 0x008c, 0x2069: 0x008c,
0x206a: 0x008c, 0x206b: 0x008c, 0x206c: 0x008c, 0x206d: 0x008c, 0x206e: 0x008c, 0x206f: 0x008c,
0x2070: 0x008c, 0x2071: 0x008c, 0x2072: 0x008c, 0x2073: 0x008c,
// Block 0x82, offset 0x2080
0x2080: 0x008c, 0x2081: 0x008c, 0x2082: 0x008c, 0x2083: 0x008c, 0x2084: 0x008c, 0x2085: 0x008c,
0x2086: 0x008c, 0x2087: 0x008c, 0x2088: 0x008c, 0x2089: 0x008c, 0x208a: 0x008c, 0x208b: 0x008c,
0x208c: 0x008c, 0x208d: 0x008c, 0x208e: 0x008c, 0x208f: 0x008c, 0x2090: 0x008c, 0x2091: 0x008c,
0x2092: 0x008c, 0x2093: 0x008c, 0x2094: 0x008c, 0x2095: 0x008c, 0x2096: 0x008c, 0x2097: 0x008c,
0x2098: 0x008c, 0x2099: 0x008c, 0x209a: 0x008c, 0x209b: 0x008c, 0x209c: 0x008c, 0x209d: 0x008c,
0x209e: 0x008c, 0x209f: 0x008c, 0x20a0: 0x008c, 0x20a1: 0x008c, 0x20a2: 0x008c, 0x20a3: 0x008c,
0x20a4: 0x008c, 0x20a5: 0x008c, 0x20a6: 0x008c, 0x20a7: 0x008c, 0x20a8: 0x008c, 0x20a9: 0x008c,
0x20aa: 0x008c, 0x20ab: 0x008c, 0x20ac: 0x008c, 0x20ad: 0x008c, 0x20ae: 0x008c, 0x20af: 0x008c,
0x20b0: 0x008c, 0x20b1: 0x008c, 0x20b2: 0x008c, 0x20b3: 0x008c, 0x20b4: 0x008c, 0x20b5: 0x008c,
0x20b6: 0x008c, 0x20b7: 0x008c, 0x20b8: 0x008c, 0x20b9: 0x008c, 0x20ba: 0x008c, 0x20bb: 0x008c,
0x20bc: 0x008c, 0x20bd: 0x008c, 0x20be: 0x008c, 0x20bf: 0x008c,
// Block 0x83, offset 0x20c0
0x20c0: 0x008c, 0x20c1: 0x008c, 0x20c2: 0x008c, 0x20c3: 0x008c, 0x20c4: 0x008c, 0x20c5: 0x008c,
0x20c6: 0x008c, 0x20c7: 0x008c, 0x20c8: 0x008c, 0x20c9: 0x008c, 0x20ca: 0x008c, 0x20cb: 0x008c,
0x20cc: 0x008c, 0x20cd: 0x008c, 0x20ce: 0x008c, 0x20cf: 0x008c, 0x20d0: 0x008c, 0x20d1: 0x008c,
0x20d2: 0x008c, 0x20d3: 0x008c, 0x20d4: 0x008c, 0x20d5: 0x008c,
0x20f0: 0x0080, 0x20f1: 0x0080, 0x20f2: 0x0080, 0x20f3: 0x0080, 0x20f4: 0x0080, 0x20f5: 0x0080,
0x20f6: 0x0080, 0x20f7: 0x0080, 0x20f8: 0x0080, 0x20f9: 0x0080, 0x20fa: 0x0080, 0x20fb: 0x0080,
// Block 0x84, offset 0x2100
0x2100: 0x0080, 0x2101: 0x0080, 0x2102: 0x0080, 0x2103: 0x0080, 0x2104: 0x0080, 0x2105: 0x00cc,
0x2106: 0x00c0, 0x2107: 0x00cc, 0x2108: 0x0080, 0x2109: 0x0080, 0x210a: 0x0080, 0x210b: 0x0080,
0x210c: 0x0080, 0x210d: 0x0080, 0x210e: 0x0080, 0x210f: 0x0080, 0x2110: 0x0080, 0x2111: 0x0080,
0x2112: 0x0080, 0x2113: 0x0080, 0x2114: 0x0080, 0x2115: 0x0080, 0x2116: 0x0080, 0x2117: 0x0080,
0x2118: 0x0080, 0x2119: 0x0080, 0x211a: 0x0080, 0x211b: 0x0080, 0x211c: 0x0080, 0x211d: 0x0080,
0x211e: 0x0080, 0x211f: 0x0080, 0x2120: 0x0080, 0x2121: 0x008c, 0x2122: 0x008c, 0x2123: 0x008c,
0x2124: 0x008c, 0x2125: 0x008c, 0x2126: 0x008c, 0x2127: 0x008c, 0x2128: 0x008c, 0x2129: 0x008c,
0x212a: 0x00c3, 0x212b: 0x00c3, 0x212c: 0x00c3, 0x212d: 0x00c3, 0x212e: 0x0040, 0x212f: 0x0040,
0x2130: 0x0080, 0x2131: 0x0040, 0x2132: 0x0040, 0x2133: 0x0040, 0x2134: 0x0040, 0x2135: 0x0040,
0x2136: 0x0080, 0x2137: 0x0080, 0x2138: 0x008c, 0x2139: 0x008c, 0x213a: 0x008c, 0x213b: 0x0040,
0x213c: 0x00c0, 0x213d: 0x0080, 0x213e: 0x0080, 0x213f: 0x0080,
// Block 0x85, offset 0x2140
0x2141: 0x00cc, 0x2142: 0x00cc, 0x2143: 0x00cc, 0x2144: 0x00cc, 0x2145: 0x00cc,
0x2146: 0x00cc, 0x2147: 0x00cc, 0x2148: 0x00cc, 0x2149: 0x00cc, 0x214a: 0x00cc, 0x214b: 0x00cc,
0x214c: 0x00cc, 0x214d: 0x00cc, 0x214e: 0x00cc, 0x214f: 0x00cc, 0x2150: 0x00cc, 0x2151: 0x00cc,
0x2152: 0x00cc, 0x2153: 0x00cc, 0x2154: 0x00cc, 0x2155: 0x00cc, 0x2156: 0x00cc, 0x2157: 0x00cc,
0x2158: 0x00cc, 0x2159: 0x00cc, 0x215a: 0x00cc, 0x215b: 0x00cc, 0x215c: 0x00cc, 0x215d: 0x00cc,
0x215e: 0x00cc, 0x215f: 0x00cc, 0x2160: 0x00cc, 0x2161: 0x00cc, 0x2162: 0x00cc, 0x2163: 0x00cc,
0x2164: 0x00cc, 0x2165: 0x00cc, 0x2166: 0x00cc, 0x2167: 0x00cc, 0x2168: 0x00cc, 0x2169: 0x00cc,
0x216a: 0x00cc, 0x216b: 0x00cc, 0x216c: 0x00cc, 0x216d: 0x00cc, 0x216e: 0x00cc, 0x216f: 0x00cc,
0x2170: 0x00cc, 0x2171: 0x00cc, 0x2172: 0x00cc, 0x2173: 0x00cc, 0x2174: 0x00cc, 0x2175: 0x00cc,
0x2176: 0x00cc, 0x2177: 0x00cc, 0x2178: 0x00cc, 0x2179: 0x00cc, 0x217a: 0x00cc, 0x217b: 0x00cc,
0x217c: 0x00cc, 0x217d: 0x00cc, 0x217e: 0x00cc, 0x217f: 0x00cc,
// Block 0x86, offset 0x2180
0x2180: 0x00cc, 0x2181: 0x00cc, 0x2182: 0x00cc, 0x2183: 0x00cc, 0x2184: 0x00cc, 0x2185: 0x00cc,
0x2186: 0x00cc, 0x2187: 0x00cc, 0x2188: 0x00cc, 0x2189: 0x00cc, 0x218a: 0x00cc, 0x218b: 0x00cc,
0x218c: 0x00cc, 0x218d: 0x00cc, 0x218e: 0x00cc, 0x218f: 0x00cc, 0x2190: 0x00cc, 0x2191: 0x00cc,
0x2192: 0x00cc, 0x2193: 0x00cc, 0x2194: 0x00cc, 0x2195: 0x00cc, 0x2196: 0x00cc,
0x2199: 0x00c3, 0x219a: 0x00c3, 0x219b: 0x0080, 0x219c: 0x0080, 0x219d: 0x00cc,
0x219e: 0x00cc, 0x219f: 0x008c, 0x21a0: 0x0080, 0x21a1: 0x00cc, 0x21a2: 0x00cc, 0x21a3: 0x00cc,
0x21a4: 0x00cc, 0x21a5: 0x00cc, 0x21a6: 0x00cc, 0x21a7: 0x00cc, 0x21a8: 0x00cc, 0x21a9: 0x00cc,
0x21aa: 0x00cc, 0x21ab: 0x00cc, 0x21ac: 0x00cc, 0x21ad: 0x00cc, 0x21ae: 0x00cc, 0x21af: 0x00cc,
0x21b0: 0x00cc, 0x21b1: 0x00cc, 0x21b2: 0x00cc, 0x21b3: 0x00cc, 0x21b4: 0x00cc, 0x21b5: 0x00cc,
0x21b6: 0x00cc, 0x21b7: 0x00cc, 0x21b8: 0x00cc, 0x21b9: 0x00cc, 0x21ba: 0x00cc, 0x21bb: 0x00cc,
0x21bc: 0x00cc, 0x21bd: 0x00cc, 0x21be: 0x00cc, 0x21bf: 0x00cc,
// Block 0x87, offset 0x21c0
0x21c0: 0x00cc, 0x21c1: 0x00cc, 0x21c2: 0x00cc, 0x21c3: 0x00cc, 0x21c4: 0x00cc, 0x21c5: 0x00cc,
0x21c6: 0x00cc, 0x21c7: 0x00cc, 0x21c8: 0x00cc, 0x21c9: 0x00cc, 0x21ca: 0x00cc, 0x21cb: 0x00cc,
0x21cc: 0x00cc, 0x21cd: 0x00cc, 0x21ce: 0x00cc, 0x21cf: 0x00cc, 0x21d0: 0x00cc, 0x21d1: 0x00cc,
0x21d2: 0x00cc, 0x21d3: 0x00cc, 0x21d4: 0x00cc, 0x21d5: 0x00cc, 0x21d6: 0x00cc, 0x21d7: 0x00cc,
0x21d8: 0x00cc, 0x21d9: 0x00cc, 0x21da: 0x00cc, 0x21db: 0x00cc, 0x21dc: 0x00cc, 0x21dd: 0x00cc,
0x21de: 0x00cc, 0x21df: 0x00cc, 0x21e0: 0x00cc, 0x21e1: 0x00cc, 0x21e2: 0x00cc, 0x21e3: 0x00cc,
0x21e4: 0x00cc, 0x21e5: 0x00cc, 0x21e6: 0x00cc, 0x21e7: 0x00cc, 0x21e8: 0x00cc, 0x21e9: 0x00cc,
0x21ea: 0x00cc, 0x21eb: 0x00cc, 0x21ec: 0x00cc, 0x21ed: 0x00cc, 0x21ee: 0x00cc, 0x21ef: 0x00cc,
0x21f0: 0x00cc, 0x21f1: 0x00cc, 0x21f2: 0x00cc, 0x21f3: 0x00cc, 0x21f4: 0x00cc, 0x21f5: 0x00cc,
0x21f6: 0x00cc, 0x21f7: 0x00cc, 0x21f8: 0x00cc, 0x21f9: 0x00cc, 0x21fa: 0x00cc, 0x21fb: 0x00d2,
0x21fc: 0x00c0, 0x21fd: 0x00cc, 0x21fe: 0x00cc, 0x21ff: 0x008c,
// Block 0x88, offset 0x2200
0x2205: 0x00c0,
0x2206: 0x00c0, 0x2207: 0x00c0, 0x2208: 0x00c0, 0x2209: 0x00c0, 0x220a: 0x00c0, 0x220b: 0x00c0,
0x220c: 0x00c0, 0x220d: 0x00c0, 0x220e: 0x00c0, 0x220f: 0x00c0, 0x2210: 0x00c0, 0x2211: 0x00c0,
0x2212: 0x00c0, 0x2213: 0x00c0, 0x2214: 0x00c0, 0x2215: 0x00c0, 0x2216: 0x00c0, 0x2217: 0x00c0,
0x2218: 0x00c0, 0x2219: 0x00c0, 0x221a: 0x00c0, 0x221b: 0x00c0, 0x221c: 0x00c0, 0x221d: 0x00c0,
0x221e: 0x00c0, 0x221f: 0x00c0, 0x2220: 0x00c0, 0x2221: 0x00c0, 0x2222: 0x00c0, 0x2223: 0x00c0,
0x2224: 0x00c0, 0x2225: 0x00c0, 0x2226: 0x00c0, 0x2227: 0x00c0, 0x2228: 0x00c0, 0x2229: 0x00c0,
0x222a: 0x00c0, 0x222b: 0x00c0, 0x222c: 0x00c0, 0x222d: 0x00c0, 0x222e: 0x00c0, 0x222f: 0x00c0,
0x2231: 0x0080, 0x2232: 0x0080, 0x2233: 0x0080, 0x2234: 0x0080, 0x2235: 0x0080,
0x2236: 0x0080, 0x2237: 0x0080, 0x2238: 0x0080, 0x2239: 0x0080, 0x223a: 0x0080, 0x223b: 0x0080,
0x223c: 0x0080, 0x223d: 0x0080, 0x223e: 0x0080, 0x223f: 0x0080,
// Block 0x89, offset 0x2240
0x2240: 0x0080, 0x2241: 0x0080, 0x2242: 0x0080, 0x2243: 0x0080, 0x2244: 0x0080, 0x2245: 0x0080,
0x2246: 0x0080, 0x2247: 0x0080, 0x2248: 0x0080, 0x2249: 0x0080, 0x224a: 0x0080, 0x224b: 0x0080,
0x224c: 0x0080, 0x224d: 0x0080, 0x224e: 0x0080, 0x224f: 0x0080, 0x2250: 0x0080, 0x2251: 0x0080,
0x2252: 0x0080, 0x2253: 0x0080, 0x2254: 0x0080, 0x2255: 0x0080, 0x2256: 0x0080, 0x2257: 0x0080,
0x2258: 0x0080, 0x2259: 0x0080, 0x225a: 0x0080, 0x225b: 0x0080, 0x225c: 0x0080, 0x225d: 0x0080,
0x225e: 0x0080, 0x225f: 0x0080, 0x2260: 0x0080, 0x2261: 0x0080, 0x2262: 0x0080, 0x2263: 0x0080,
0x2264: 0x0040, 0x2265: 0x0080, 0x2266: 0x0080, 0x2267: 0x0080, 0x2268: 0x0080, 0x2269: 0x0080,
0x226a: 0x0080, 0x226b: 0x0080, 0x226c: 0x0080, 0x226d: 0x0080, 0x226e: 0x0080, 0x226f: 0x0080,
0x2270: 0x0080, 0x2271: 0x0080, 0x2272: 0x0080, 0x2273: 0x0080, 0x2274: 0x0080, 0x2275: 0x0080,
0x2276: 0x0080, 0x2277: 0x0080, 0x2278: 0x0080, 0x2279: 0x0080, 0x227a: 0x0080, 0x227b: 0x0080,
0x227c: 0x0080, 0x227d: 0x0080, 0x227e: 0x0080, 0x227f: 0x0080,
// Block 0x8a, offset 0x2280
0x2280: 0x0080, 0x2281: 0x0080, 0x2282: 0x0080, 0x2283: 0x0080, 0x2284: 0x0080, 0x2285: 0x0080,
0x2286: 0x0080, 0x2287: 0x0080, 0x2288: 0x0080, 0x2289: 0x0080, 0x228a: 0x0080, 0x228b: 0x0080,
0x228c: 0x0080, 0x228d: 0x0080, 0x228e: 0x0080, 0x2290: 0x0080, 0x2291: 0x0080,
0x2292: 0x0080, 0x2293: 0x0080, 0x2294: 0x0080, 0x2295: 0x0080, 0x2296: 0x0080, 0x2297: 0x0080,
0x2298: 0x0080, 0x2299: 0x0080, 0x229a: 0x0080, 0x229b: 0x0080, 0x229c: 0x0080, 0x229d: 0x0080,
0x229e: 0x0080, 0x229f: 0x0080, 0x22a0: 0x00c0, 0x22a1: 0x00c0, 0x22a2: 0x00c0, 0x22a3: 0x00c0,
0x22a4: 0x00c0, 0x22a5: 0x00c0, 0x22a6: 0x00c0, 0x22a7: 0x00c0, 0x22a8: 0x00c0, 0x22a9: 0x00c0,
0x22aa: 0x00c0, 0x22ab: 0x00c0, 0x22ac: 0x00c0, 0x22ad: 0x00c0, 0x22ae: 0x00c0, 0x22af: 0x00c0,
0x22b0: 0x00c0, 0x22b1: 0x00c0, 0x22b2: 0x00c0, 0x22b3: 0x00c0, 0x22b4: 0x00c0, 0x22b5: 0x00c0,
0x22b6: 0x00c0, 0x22b7: 0x00c0, 0x22b8: 0x00c0, 0x22b9: 0x00c0, 0x22ba: 0x00c0, 0x22bb: 0x00c0,
0x22bc: 0x00c0, 0x22bd: 0x00c0, 0x22be: 0x00c0, 0x22bf: 0x00c0,
// Block 0x8b, offset 0x22c0
0x22c0: 0x0080, 0x22c1: 0x0080, 0x22c2: 0x0080, 0x22c3: 0x0080, 0x22c4: 0x0080, 0x22c5: 0x0080,
0x22c6: 0x0080, 0x22c7: 0x0080, 0x22c8: 0x0080, 0x22c9: 0x0080, 0x22ca: 0x0080, 0x22cb: 0x0080,
0x22cc: 0x0080, 0x22cd: 0x0080, 0x22ce: 0x0080, 0x22cf: 0x0080, 0x22d0: 0x0080, 0x22d1: 0x0080,
0x22d2: 0x0080, 0x22d3: 0x0080, 0x22d4: 0x0080, 0x22d5: 0x0080, 0x22d6: 0x0080, 0x22d7: 0x0080,
0x22d8: 0x0080, 0x22d9: 0x0080, 0x22da: 0x0080, 0x22db: 0x0080, 0x22dc: 0x0080, 0x22dd: 0x0080,
0x22de: 0x0080, 0x22df: 0x0080, 0x22e0: 0x0080, 0x22e1: 0x0080, 0x22e2: 0x0080, 0x22e3: 0x0080,
0x22f0: 0x00cc, 0x22f1: 0x00cc, 0x22f2: 0x00cc, 0x22f3: 0x00cc, 0x22f4: 0x00cc, 0x22f5: 0x00cc,
0x22f6: 0x00cc, 0x22f7: 0x00cc, 0x22f8: 0x00cc, 0x22f9: 0x00cc, 0x22fa: 0x00cc, 0x22fb: 0x00cc,
0x22fc: 0x00cc, 0x22fd: 0x00cc, 0x22fe: 0x00cc, 0x22ff: 0x00cc,
// Block 0x8c, offset 0x2300
0x2300: 0x0080, 0x2301: 0x0080, 0x2302: 0x0080, 0x2303: 0x0080, 0x2304: 0x0080, 0x2305: 0x0080,
0x2306: 0x0080, 0x2307: 0x0080, 0x2308: 0x0080, 0x2309: 0x0080, 0x230a: 0x0080, 0x230b: 0x0080,
0x230c: 0x0080, 0x230d: 0x0080, 0x230e: 0x0080, 0x230f: 0x0080, 0x2310: 0x0080, 0x2311: 0x0080,
0x2312: 0x0080, 0x2313: 0x0080, 0x2314: 0x0080, 0x2315: 0x0080, 0x2316: 0x0080, 0x2317: 0x0080,
0x2318: 0x0080, 0x2319: 0x0080, 0x231a: 0x0080, 0x231b: 0x0080, 0x231c: 0x0080, 0x231d: 0x0080,
0x231e: 0x0080, 0x2320: 0x0080, 0x2321: 0x0080, 0x2322: 0x0080, 0x2323: 0x0080,
0x2324: 0x0080, 0x2325: 0x0080, 0x2326: 0x0080, 0x2327: 0x0080, 0x2328: 0x0080, 0x2329: 0x0080,
0x232a: 0x0080, 0x232b: 0x0080, 0x232c: 0x0080, 0x232d: 0x0080, 0x232e: 0x0080, 0x232f: 0x0080,
0x2330: 0x0080, 0x2331: 0x0080, 0x2332: 0x0080, 0x2333: 0x0080, 0x2334: 0x0080, 0x2335: 0x0080,
0x2336: 0x0080, 0x2337: 0x0080, 0x2338: 0x0080, 0x2339: 0x0080, 0x233a: 0x0080, 0x233b: 0x0080,
0x233c: 0x0080, 0x233d: 0x0080, 0x233e: 0x0080, 0x233f: 0x0080,
// Block 0x8d, offset 0x2340
0x2340: 0x0080, 0x2341: 0x0080, 0x2342: 0x0080, 0x2343: 0x0080, 0x2344: 0x0080, 0x2345: 0x0080,
0x2346: 0x0080, 0x2347: 0x0080, 0x2348: 0x0080, 0x2349: 0x0080, 0x234a: 0x0080, 0x234b: 0x0080,
0x234c: 0x0080, 0x234d: 0x0080, 0x234e: 0x0080, 0x234f: 0x0080, 0x2350: 0x008c, 0x2351: 0x008c,
0x2352: 0x008c, 0x2353: 0x008c, 0x2354: 0x008c, 0x2355: 0x008c, 0x2356: 0x008c, 0x2357: 0x008c,
0x2358: 0x008c, 0x2359: 0x008c, 0x235a: 0x008c, 0x235b: 0x008c, 0x235c: 0x008c, 0x235d: 0x008c,
0x235e: 0x008c, 0x235f: 0x008c, 0x2360: 0x008c, 0x2361: 0x008c, 0x2362: 0x008c, 0x2363: 0x008c,
0x2364: 0x008c, 0x2365: 0x008c, 0x2366: 0x008c, 0x2367: 0x008c, 0x2368: 0x008c, 0x2369: 0x008c,
0x236a: 0x008c, 0x236b: 0x008c, 0x236c: 0x008c, 0x236d: 0x008c, 0x236e: 0x008c, 0x236f: 0x008c,
0x2370: 0x008c, 0x2371: 0x008c, 0x2372: 0x008c, 0x2373: 0x008c, 0x2374: 0x008c, 0x2375: 0x008c,
0x2376: 0x008c, 0x2377: 0x008c, 0x2378: 0x008c, 0x2379: 0x008c, 0x237a: 0x008c, 0x237b: 0x008c,
0x237c: 0x008c, 0x237d: 0x008c, 0x237e: 0x008c, 0x237f: 0x0080,
// Block 0x8e, offset 0x2380
0x2380: 0x008c, 0x2381: 0x008c, 0x2382: 0x008c, 0x2383: 0x008c, 0x2384: 0x008c, 0x2385: 0x008c,
0x2386: 0x008c, 0x2387: 0x008c, 0x2388: 0x008c, 0x2389: 0x008c, 0x238a: 0x008c, 0x238b: 0x008c,
0x238c: 0x008c, 0x238d: 0x008c, 0x238e: 0x008c, 0x238f: 0x008c, 0x2390: 0x008c, 0x2391: 0x008c,
0x2392: 0x008c, 0x2393: 0x008c, 0x2394: 0x008c, 0x2395: 0x008c, 0x2396: 0x008c, 0x2397: 0x008c,
0x2398: 0x0080, 0x2399: 0x0080, 0x239a: 0x0080, 0x239b: 0x0080, 0x239c: 0x0080, 0x239d: 0x0080,
0x239e: 0x0080, 0x239f: 0x0080, 0x23a0: 0x0080, 0x23a1: 0x0080, 0x23a2: 0x0080, 0x23a3: 0x0080,
0x23a4: 0x0080, 0x23a5: 0x0080, 0x23a6: 0x0080, 0x23a7: 0x0080, 0x23a8: 0x0080, 0x23a9: 0x0080,
0x23aa: 0x0080, 0x23ab: 0x0080, 0x23ac: 0x0080, 0x23ad: 0x0080, 0x23ae: 0x0080, 0x23af: 0x0080,
0x23b0: 0x0080, 0x23b1: 0x0080, 0x23b2: 0x0080, 0x23b3: 0x0080, 0x23b4: 0x0080, 0x23b5: 0x0080,
0x23b6: 0x0080, 0x23b7: 0x0080, 0x23b8: 0x0080, 0x23b9: 0x0080, 0x23ba: 0x0080, 0x23bb: 0x0080,
0x23bc: 0x0080, 0x23bd: 0x0080, 0x23be: 0x0080, 0x23bf: 0x0080,
// Block 0x8f, offset 0x23c0
0x23c0: 0x00cc, 0x23c1: 0x00cc, 0x23c2: 0x00cc, 0x23c3: 0x00cc, 0x23c4: 0x00cc, 0x23c5: 0x00cc,
0x23c6: 0x00cc, 0x23c7: 0x00cc, 0x23c8: 0x00cc, 0x23c9: 0x00cc, 0x23ca: 0x00cc, 0x23cb: 0x00cc,
0x23cc: 0x00cc, 0x23cd: 0x00cc, 0x23ce: 0x00cc, 0x23cf: 0x00cc, 0x23d0: 0x00cc, 0x23d1: 0x00cc,
0x23d2: 0x00cc, 0x23d3: 0x00cc, 0x23d4: 0x00cc, 0x23d5: 0x00cc, 0x23d6: 0x00cc, 0x23d7: 0x00cc,
0x23d8: 0x00cc, 0x23d9: 0x00cc, 0x23da: 0x00cc, 0x23db: 0x00cc, 0x23dc: 0x00cc, 0x23dd: 0x00cc,
0x23de: 0x00cc, 0x23df: 0x00cc, 0x23e0: 0x00cc, 0x23e1: 0x00cc, 0x23e2: 0x00cc, 0x23e3: 0x00cc,
0x23e4: 0x00cc, 0x23e5: 0x00cc, 0x23e6: 0x00cc, 0x23e7: 0x00cc, 0x23e8: 0x00cc, 0x23e9: 0x00cc,
0x23ea: 0x00cc, 0x23eb: 0x00cc, 0x23ec: 0x00cc, 0x23ed: 0x00cc, 0x23ee: 0x00cc, 0x23ef: 0x00cc,
0x23f0: 0x00cc, 0x23f1: 0x00cc, 0x23f2: 0x00cc, 0x23f3: 0x00cc, 0x23f4: 0x00cc, 0x23f5: 0x00cc,
0x23f6: 0x00cc, 0x23f7: 0x00cc, 0x23f8: 0x00cc, 0x23f9: 0x00cc, 0x23fa: 0x00cc, 0x23fb: 0x00cc,
0x23fc: 0x00cc, 0x23fd: 0x00cc, 0x23fe: 0x00cc, 0x23ff: 0x00cc,
// Block 0x90, offset 0x2400
0x2400: 0x00c0, 0x2401: 0x00c0, 0x2402: 0x00c0, 0x2403: 0x00c0, 0x2404: 0x00c0, 0x2405: 0x00c0,
0x2406: 0x00c0, 0x2407: 0x00c0, 0x2408: 0x00c0, 0x2409: 0x00c0, 0x240a: 0x00c0, 0x240b: 0x00c0,
0x240c: 0x00c0, 0x2410: 0x0080, 0x2411: 0x0080,
0x2412: 0x0080, 0x2413: 0x0080, 0x2414: 0x0080, 0x2415: 0x0080, 0x2416: 0x0080, 0x2417: 0x0080,
0x2418: 0x0080, 0x2419: 0x0080, 0x241a: 0x0080, 0x241b: 0x0080, 0x241c: 0x0080, 0x241d: 0x0080,
0x241e: 0x0080, 0x241f: 0x0080, 0x2420: 0x0080, 0x2421: 0x0080, 0x2422: 0x0080, 0x2423: 0x0080,
0x2424: 0x0080, 0x2425: 0x0080, 0x2426: 0x0080, 0x2427: 0x0080, 0x2428: 0x0080, 0x2429: 0x0080,
0x242a: 0x0080, 0x242b: 0x0080, 0x242c: 0x0080, 0x242d: 0x0080, 0x242e: 0x0080, 0x242f: 0x0080,
0x2430: 0x0080, 0x2431: 0x0080, 0x2432: 0x0080, 0x2433: 0x0080, 0x2434: 0x0080, 0x2435: 0x0080,
0x2436: 0x0080, 0x2437: 0x0080, 0x2438: 0x0080, 0x2439: 0x0080, 0x243a: 0x0080, 0x243b: 0x0080,
0x243c: 0x0080, 0x243d: 0x0080, 0x243e: 0x0080, 0x243f: 0x0080,
// Block 0x91, offset 0x2440
0x2440: 0x0080, 0x2441: 0x0080, 0x2442: 0x0080, 0x2443: 0x0080, 0x2444: 0x0080, 0x2445: 0x0080,
0x2446: 0x0080,
0x2450: 0x00c0, 0x2451: 0x00c0,
0x2452: 0x00c0, 0x2453: 0x00c0, 0x2454: 0x00c0, 0x2455: 0x00c0, 0x2456: 0x00c0, 0x2457: 0x00c0,
0x2458: 0x00c0, 0x2459: 0x00c0, 0x245a: 0x00c0, 0x245b: 0x00c0, 0x245c: 0x00c0, 0x245d: 0x00c0,
0x245e: 0x00c0, 0x245f: 0x00c0, 0x2460: 0x00c0, 0x2461: 0x00c0, 0x2462: 0x00c0, 0x2463: 0x00c0,
0x2464: 0x00c0, 0x2465: 0x00c0, 0x2466: 0x00c0, 0x2467: 0x00c0, 0x2468: 0x00c0, 0x2469: 0x00c0,
0x246a: 0x00c0, 0x246b: 0x00c0, 0x246c: 0x00c0, 0x246d: 0x00c0, 0x246e: 0x00c0, 0x246f: 0x00c0,
0x2470: 0x00c0, 0x2471: 0x00c0, 0x2472: 0x00c0, 0x2473: 0x00c0, 0x2474: 0x00c0, 0x2475: 0x00c0,
0x2476: 0x00c0, 0x2477: 0x00c0, 0x2478: 0x00c0, 0x2479: 0x00c0, 0x247a: 0x00c0, 0x247b: 0x00c0,
0x247c: 0x00c0, 0x247d: 0x00c0, 0x247e: 0x0080, 0x247f: 0x0080,
// Block 0x92, offset 0x2480
0x2480: 0x00c0, 0x2481: 0x00c0, 0x2482: 0x00c0, 0x2483: 0x00c0, 0x2484: 0x00c0, 0x2485: 0x00c0,
0x2486: 0x00c0, 0x2487: 0x00c0, 0x2488: 0x00c0, 0x2489: 0x00c0, 0x248a: 0x00c0, 0x248b: 0x00c0,
0x248c: 0x00c0, 0x248d: 0x0080, 0x248e: 0x0080, 0x248f: 0x0080, 0x2490: 0x00c0, 0x2491: 0x00c0,
0x2492: 0x00c0, 0x2493: 0x00c0, 0x2494: 0x00c0, 0x2495: 0x00c0, 0x2496: 0x00c0, 0x2497: 0x00c0,
0x2498: 0x00c0, 0x2499: 0x00c0, 0x249a: 0x00c0, 0x249b: 0x00c0, 0x249c: 0x00c0, 0x249d: 0x00c0,
0x249e: 0x00c0, 0x249f: 0x00c0, 0x24a0: 0x00c0, 0x24a1: 0x00c0, 0x24a2: 0x00c0, 0x24a3: 0x00c0,
0x24a4: 0x00c0, 0x24a5: 0x00c0, 0x24a6: 0x00c0, 0x24a7: 0x00c0, 0x24a8: 0x00c0, 0x24a9: 0x00c0,
0x24aa: 0x00c0, 0x24ab: 0x00c0,
// Block 0x93, offset 0x24c0
0x24c0: 0x00c0, 0x24c1: 0x00c0, 0x24c2: 0x00c0, 0x24c3: 0x00c0, 0x24c4: 0x00c0, 0x24c5: 0x00c0,
0x24c6: 0x00c0, 0x24c7: 0x00c0, 0x24c8: 0x00c0, 0x24c9: 0x00c0, 0x24ca: 0x00c0, 0x24cb: 0x00c0,
0x24cc: 0x00c0, 0x24cd: 0x00c0, 0x24ce: 0x00c0, 0x24cf: 0x00c0, 0x24d0: 0x00c0, 0x24d1: 0x00c0,
0x24d2: 0x00c0, 0x24d3: 0x00c0, 0x24d4: 0x00c0, 0x24d5: 0x00c0, 0x24d6: 0x00c0, 0x24d7: 0x00c0,
0x24d8: 0x00c0, 0x24d9: 0x00c0, 0x24da: 0x00c0, 0x24db: 0x00c0, 0x24dc: 0x00c0, 0x24dd: 0x00c0,
0x24de: 0x00c0, 0x24df: 0x00c0, 0x24e0: 0x00c0, 0x24e1: 0x00c0, 0x24e2: 0x00c0, 0x24e3: 0x00c0,
0x24e4: 0x00c0, 0x24e5: 0x00c0, 0x24e6: 0x00c0, 0x24e7: 0x00c0, 0x24e8: 0x00c0, 0x24e9: 0x00c0,
0x24ea: 0x00c0, 0x24eb: 0x00c0, 0x24ec: 0x00c0, 0x24ed: 0x00c0, 0x24ee: 0x00c0, 0x24ef: 0x00c3,
0x24f0: 0x0083, 0x24f1: 0x0083, 0x24f2: 0x0083, 0x24f3: 0x0080, 0x24f4: 0x00c3, 0x24f5: 0x00c3,
0x24f6: 0x00c3, 0x24f7: 0x00c3, 0x24f8: 0x00c3, 0x24f9: 0x00c3, 0x24fa: 0x00c3, 0x24fb: 0x00c3,
0x24fc: 0x00c3, 0x24fd: 0x00c3, 0x24fe: 0x0080, 0x24ff: 0x00c0,
// Block 0x94, offset 0x2500
0x2500: 0x00c0, 0x2501: 0x00c0, 0x2502: 0x00c0, 0x2503: 0x00c0, 0x2504: 0x00c0, 0x2505: 0x00c0,
0x2506: 0x00c0, 0x2507: 0x00c0, 0x2508: 0x00c0, 0x2509: 0x00c0, 0x250a: 0x00c0, 0x250b: 0x00c0,
0x250c: 0x00c0, 0x250d: 0x00c0, 0x250e: 0x00c0, 0x250f: 0x00c0, 0x2510: 0x00c0, 0x2511: 0x00c0,
0x2512: 0x00c0, 0x2513: 0x00c0, 0x2514: 0x00c0, 0x2515: 0x00c0, 0x2516: 0x00c0, 0x2517: 0x00c0,
0x2518: 0x00c0, 0x2519: 0x00c0, 0x251a: 0x00c0, 0x251b: 0x00c0, 0x251c: 0x0080, 0x251d: 0x0080,
0x251e: 0x00c3, 0x251f: 0x00c3, 0x2520: 0x00c0, 0x2521: 0x00c0, 0x2522: 0x00c0, 0x2523: 0x00c0,
0x2524: 0x00c0, 0x2525: 0x00c0, 0x2526: 0x00c0, 0x2527: 0x00c0, 0x2528: 0x00c0, 0x2529: 0x00c0,
0x252a: 0x00c0, 0x252b: 0x00c0, 0x252c: 0x00c0, 0x252d: 0x00c0, 0x252e: 0x00c0, 0x252f: 0x00c0,
0x2530: 0x00c0, 0x2531: 0x00c0, 0x2532: 0x00c0, 0x2533: 0x00c0, 0x2534: 0x00c0, 0x2535: 0x00c0,
0x2536: 0x00c0, 0x2537: 0x00c0, 0x2538: 0x00c0, 0x2539: 0x00c0, 0x253a: 0x00c0, 0x253b: 0x00c0,
0x253c: 0x00c0, 0x253d: 0x00c0, 0x253e: 0x00c0, 0x253f: 0x00c0,
// Block 0x95, offset 0x2540
0x2540: 0x00c0, 0x2541: 0x00c0, 0x2542: 0x00c0, 0x2543: 0x00c0, 0x2544: 0x00c0, 0x2545: 0x00c0,
0x2546: 0x00c0, 0x2547: 0x00c0, 0x2548: 0x00c0, 0x2549: 0x00c0, 0x254a: 0x00c0, 0x254b: 0x00c0,
0x254c: 0x00c0, 0x254d: 0x00c0, 0x254e: 0x00c0, 0x254f: 0x00c0, 0x2550: 0x00c0, 0x2551: 0x00c0,
0x2552: 0x00c0, 0x2553: 0x00c0, 0x2554: 0x00c0, 0x2555: 0x00c0, 0x2556: 0x00c0, 0x2557: 0x00c0,
0x2558: 0x00c0, 0x2559: 0x00c0, 0x255a: 0x00c0, 0x255b: 0x00c0, 0x255c: 0x00c0, 0x255d: 0x00c0,
0x255e: 0x00c0, 0x255f: 0x00c0, 0x2560: 0x00c0, 0x2561: 0x00c0, 0x2562: 0x00c0, 0x2563: 0x00c0,
0x2564: 0x00c0, 0x2565: 0x00c0, 0x2566: 0x0080, 0x2567: 0x0080, 0x2568: 0x0080, 0x2569: 0x0080,
0x256a: 0x0080, 0x256b: 0x0080, 0x256c: 0x0080, 0x256d: 0x0080, 0x256e: 0x0080, 0x256f: 0x0080,
0x2570: 0x00c3, 0x2571: 0x00c3, 0x2572: 0x0080, 0x2573: 0x0080, 0x2574: 0x0080, 0x2575: 0x0080,
0x2576: 0x0080, 0x2577: 0x0080,
// Block 0x96, offset 0x2580
0x2580: 0x0080, 0x2581: 0x0080, 0x2582: 0x0080, 0x2583: 0x0080, 0x2584: 0x0080, 0x2585: 0x0080,
0x2586: 0x0080, 0x2587: 0x0080, 0x2588: 0x0080, 0x2589: 0x0080, 0x258a: 0x0080, 0x258b: 0x0080,
0x258c: 0x0080, 0x258d: 0x0080, 0x258e: 0x0080, 0x258f: 0x0080, 0x2590: 0x0080, 0x2591: 0x0080,
0x2592: 0x0080, 0x2593: 0x0080, 0x2594: 0x0080, 0x2595: 0x0080, 0x2596: 0x0080, 0x2597: 0x00c0,
0x2598: 0x00c0, 0x2599: 0x00c0, 0x259a: 0x00c0, 0x259b: 0x00c0, 0x259c: 0x00c0, 0x259d: 0x00c0,
0x259e: 0x00c0, 0x259f: 0x00c0, 0x25a0: 0x0080, 0x25a1: 0x0080, 0x25a2: 0x00c0, 0x25a3: 0x00c0,
0x25a4: 0x00c0, 0x25a5: 0x00c0, 0x25a6: 0x00c0, 0x25a7: 0x00c0, 0x25a8: 0x00c0, 0x25a9: 0x00c0,
0x25aa: 0x00c0, 0x25ab: 0x00c0, 0x25ac: 0x00c0, 0x25ad: 0x00c0, 0x25ae: 0x00c0, 0x25af: 0x00c0,
0x25b0: 0x00c0, 0x25b1: 0x00c0, 0x25b2: 0x00c0, 0x25b3: 0x00c0, 0x25b4: 0x00c0, 0x25b5: 0x00c0,
0x25b6: 0x00c0, 0x25b7: 0x00c0, 0x25b8: 0x00c0, 0x25b9: 0x00c0, 0x25ba: 0x00c0, 0x25bb: 0x00c0,
0x25bc: 0x00c0, 0x25bd: 0x00c0, 0x25be: 0x00c0, 0x25bf: 0x00c0,
// Block 0x97, offset 0x25c0
0x25c0: 0x00c0, 0x25c1: 0x00c0, 0x25c2: 0x00c0, 0x25c3: 0x00c0, 0x25c4: 0x00c0, 0x25c5: 0x00c0,
0x25c6: 0x00c0, 0x25c7: 0x00c0, 0x25c8: 0x00c0, 0x25c9: 0x00c0, 0x25ca: 0x00c0, 0x25cb: 0x00c0,
0x25cc: 0x00c0, 0x25cd: 0x00c0, 0x25ce: 0x00c0, 0x25cf: 0x00c0, 0x25d0: 0x00c0, 0x25d1: 0x00c0,
0x25d2: 0x00c0, 0x25d3: 0x00c0, 0x25d4: 0x00c0, 0x25d5: 0x00c0, 0x25d6: 0x00c0, 0x25d7: 0x00c0,
0x25d8: 0x00c0, 0x25d9: 0x00c0, 0x25da: 0x00c0, 0x25db: 0x00c0, 0x25dc: 0x00c0, 0x25dd: 0x00c0,
0x25de: 0x00c0, 0x25df: 0x00c0, 0x25e0: 0x00c0, 0x25e1: 0x00c0, 0x25e2: 0x00c0, 0x25e3: 0x00c0,
0x25e4: 0x00c0, 0x25e5: 0x00c0, 0x25e6: 0x00c0, 0x25e7: 0x00c0, 0x25e8: 0x00c0, 0x25e9: 0x00c0,
0x25ea: 0x00c0, 0x25eb: 0x00c0, 0x25ec: 0x00c0, 0x25ed: 0x00c0, 0x25ee: 0x00c0, 0x25ef: 0x00c0,
0x25f0: 0x0080, 0x25f1: 0x00c0, 0x25f2: 0x00c0, 0x25f3: 0x00c0, 0x25f4: 0x00c0, 0x25f5: 0x00c0,
0x25f6: 0x00c0, 0x25f7: 0x00c0, 0x25f8: 0x00c0, 0x25f9: 0x00c0, 0x25fa: 0x00c0, 0x25fb: 0x00c0,
0x25fc: 0x00c0, 0x25fd: 0x00c0, 0x25fe: 0x00c0, 0x25ff: 0x00c0,
// Block 0x98, offset 0x2600
0x2600: 0x00c0, 0x2601: 0x00c0, 0x2602: 0x00c0, 0x2603: 0x00c0, 0x2604: 0x00c0, 0x2605: 0x00c0,
0x2606: 0x00c0, 0x2607: 0x00c0, 0x2608: 0x00c0, 0x2609: 0x0080, 0x260a: 0x0080, 0x260b: 0x00c0,
0x260c: 0x00c0, 0x260d: 0x00c0, 0x260e: 0x00c0, 0x260f: 0x00c0, 0x2610: 0x00c0, 0x2611: 0x00c0,
0x2612: 0x00c0, 0x2613: 0x00c0, 0x2614: 0x00c0, 0x2615: 0x00c0, 0x2616: 0x00c0, 0x2617: 0x00c0,
0x2618: 0x00c0, 0x2619: 0x00c0, 0x261a: 0x00c0, 0x261b: 0x00c0, 0x261c: 0x00c0, 0x261d: 0x00c0,
0x261e: 0x00c0, 0x261f: 0x00c0, 0x2620: 0x00c0, 0x2621: 0x00c0, 0x2622: 0x00c0, 0x2623: 0x00c0,
0x2624: 0x00c0, 0x2625: 0x00c0, 0x2626: 0x00c0, 0x2627: 0x00c0, 0x2628: 0x00c0, 0x2629: 0x00c0,
0x262a: 0x00c0, 0x262b: 0x00c0, 0x262c: 0x00c0, 0x262d: 0x00c0, 0x262e: 0x00c0, 0x262f: 0x00c0,
0x2630: 0x00c0, 0x2631: 0x00c0, 0x2632: 0x00c0, 0x2633: 0x00c0, 0x2634: 0x00c0, 0x2635: 0x00c0,
0x2636: 0x00c0, 0x2637: 0x00c0, 0x2638: 0x00c0, 0x2639: 0x00c0, 0x263a: 0x00c0, 0x263b: 0x00c0,
0x263c: 0x00c0, 0x263d: 0x00c0, 0x263e: 0x00c0, 0x263f: 0x00c0,
// Block 0x99, offset 0x2640
0x2640: 0x00c0, 0x2641: 0x00c0, 0x2642: 0x00c0, 0x2643: 0x00c0, 0x2644: 0x00c0, 0x2645: 0x00c0,
0x2646: 0x00c0, 0x2647: 0x00c0, 0x2648: 0x00c0, 0x2649: 0x00c0, 0x264a: 0x00c0,
0x2650: 0x00c0, 0x2651: 0x00c0,
0x2653: 0x00c0, 0x2655: 0x00c0, 0x2656: 0x00c0, 0x2657: 0x00c0,
0x2658: 0x00c0, 0x2659: 0x00c0,
0x2672: 0x0080, 0x2673: 0x0080, 0x2674: 0x0080, 0x2675: 0x00c0,
0x2676: 0x00c0, 0x2677: 0x00c0, 0x2678: 0x0080, 0x2679: 0x0080, 0x267a: 0x00c0, 0x267b: 0x00c0,
0x267c: 0x00c0, 0x267d: 0x00c0, 0x267e: 0x00c0, 0x267f: 0x00c0,
// Block 0x9a, offset 0x2680
0x2680: 0x00c0, 0x2681: 0x00c0, 0x2682: 0x00c3, 0x2683: 0x00c0, 0x2684: 0x00c0, 0x2685: 0x00c0,
0x2686: 0x00c6, 0x2687: 0x00c0, 0x2688: 0x00c0, 0x2689: 0x00c0, 0x268a: 0x00c0, 0x268b: 0x00c3,
0x268c: 0x00c0, 0x268d: 0x00c0, 0x268e: 0x00c0, 0x268f: 0x00c0, 0x2690: 0x00c0, 0x2691: 0x00c0,
0x2692: 0x00c0, 0x2693: 0x00c0, 0x2694: 0x00c0, 0x2695: 0x00c0, 0x2696: 0x00c0, 0x2697: 0x00c0,
0x2698: 0x00c0, 0x2699: 0x00c0, 0x269a: 0x00c0, 0x269b: 0x00c0, 0x269c: 0x00c0, 0x269d: 0x00c0,
0x269e: 0x00c0, 0x269f: 0x00c0, 0x26a0: 0x00c0, 0x26a1: 0x00c0, 0x26a2: 0x00c0, 0x26a3: 0x00c0,
0x26a4: 0x00c0, 0x26a5: 0x00c3, 0x26a6: 0x00c3, 0x26a7: 0x00c0, 0x26a8: 0x0080, 0x26a9: 0x0080,
0x26aa: 0x0080, 0x26ab: 0x0080, 0x26ac: 0x00c6,
0x26b0: 0x0080, 0x26b1: 0x0080, 0x26b2: 0x0080, 0x26b3: 0x0080, 0x26b4: 0x0080, 0x26b5: 0x0080,
0x26b6: 0x0080, 0x26b7: 0x0080, 0x26b8: 0x0080, 0x26b9: 0x0080,
// Block 0x9b, offset 0x26c0
0x26c0: 0x00c2, 0x26c1: 0x00c2, 0x26c2: 0x00c2, 0x26c3: 0x00c2, 0x26c4: 0x00c2, 0x26c5: 0x00c2,
0x26c6: 0x00c2, 0x26c7: 0x00c2, 0x26c8: 0x00c2, 0x26c9: 0x00c2, 0x26ca: 0x00c2, 0x26cb: 0x00c2,
0x26cc: 0x00c2, 0x26cd: 0x00c2, 0x26ce: 0x00c2, 0x26cf: 0x00c2, 0x26d0: 0x00c2, 0x26d1: 0x00c2,
0x26d2: 0x00c2, 0x26d3: 0x00c2, 0x26d4: 0x00c2, 0x26d5: 0x00c2, 0x26d6: 0x00c2, 0x26d7: 0x00c2,
0x26d8: 0x00c2, 0x26d9: 0x00c2, 0x26da: 0x00c2, 0x26db: 0x00c2, 0x26dc: 0x00c2, 0x26dd: 0x00c2,
0x26de: 0x00c2, 0x26df: 0x00c2, 0x26e0: 0x00c2, 0x26e1: 0x00c2, 0x26e2: 0x00c2, 0x26e3: 0x00c2,
0x26e4: 0x00c2, 0x26e5: 0x00c2, 0x26e6: 0x00c2, 0x26e7: 0x00c2, 0x26e8: 0x00c2, 0x26e9: 0x00c2,
0x26ea: 0x00c2, 0x26eb: 0x00c2, 0x26ec: 0x00c2, 0x26ed: 0x00c2, 0x26ee: 0x00c2, 0x26ef: 0x00c2,
0x26f0: 0x00c2, 0x26f1: 0x00c2, 0x26f2: 0x00c1, 0x26f3: 0x00c0, 0x26f4: 0x0080, 0x26f5: 0x0080,
0x26f6: 0x0080, 0x26f7: 0x0080,
// Block 0x9c, offset 0x2700
0x2700: 0x00c0, 0x2701: 0x00c0, 0x2702: 0x00c0, 0x2703: 0x00c0, 0x2704: 0x00c6, 0x2705: 0x00c3,
0x270e: 0x0080, 0x270f: 0x0080, 0x2710: 0x00c0, 0x2711: 0x00c0,
0x2712: 0x00c0, 0x2713: 0x00c0, 0x2714: 0x00c0, 0x2715: 0x00c0, 0x2716: 0x00c0, 0x2717: 0x00c0,
0x2718: 0x00c0, 0x2719: 0x00c0,
0x2720: 0x00c3, 0x2721: 0x00c3, 0x2722: 0x00c3, 0x2723: 0x00c3,
0x2724: 0x00c3, 0x2725: 0x00c3, 0x2726: 0x00c3, 0x2727: 0x00c3, 0x2728: 0x00c3, 0x2729: 0x00c3,
0x272a: 0x00c3, 0x272b: 0x00c3, 0x272c: 0x00c3, 0x272d: 0x00c3, 0x272e: 0x00c3, 0x272f: 0x00c3,
0x2730: 0x00c3, 0x2731: 0x00c3, 0x2732: 0x00c0, 0x2733: 0x00c0, 0x2734: 0x00c0, 0x2735: 0x00c0,
0x2736: 0x00c0, 0x2737: 0x00c0, 0x2738: 0x0080, 0x2739: 0x0080, 0x273a: 0x0080, 0x273b: 0x00c0,
0x273c: 0x0080, 0x273d: 0x00c0, 0x273e: 0x00c0, 0x273f: 0x00c3,
// Block 0x9d, offset 0x2740
0x2740: 0x00c0, 0x2741: 0x00c0, 0x2742: 0x00c0, 0x2743: 0x00c0, 0x2744: 0x00c0, 0x2745: 0x00c0,
0x2746: 0x00c0, 0x2747: 0x00c0, 0x2748: 0x00c0, 0x2749: 0x00c0, 0x274a: 0x00c0, 0x274b: 0x00c0,
0x274c: 0x00c0, 0x274d: 0x00c0, 0x274e: 0x00c0, 0x274f: 0x00c0, 0x2750: 0x00c0, 0x2751: 0x00c0,
0x2752: 0x00c0, 0x2753: 0x00c0, 0x2754: 0x00c0, 0x2755: 0x00c0, 0x2756: 0x00c0, 0x2757: 0x00c0,
0x2758: 0x00c0, 0x2759: 0x00c0, 0x275a: 0x00c0, 0x275b: 0x00c0, 0x275c: 0x00c0, 0x275d: 0x00c0,
0x275e: 0x00c0, 0x275f: 0x00c0, 0x2760: 0x00c0, 0x2761: 0x00c0, 0x2762: 0x00c0, 0x2763: 0x00c0,
0x2764: 0x00c0, 0x2765: 0x00c0, 0x2766: 0x00c3, 0x2767: 0x00c3, 0x2768: 0x00c3, 0x2769: 0x00c3,
0x276a: 0x00c3, 0x276b: 0x00c3, 0x276c: 0x00c3, 0x276d: 0x00c3, 0x276e: 0x0080, 0x276f: 0x0080,
0x2770: 0x00c0, 0x2771: 0x00c0, 0x2772: 0x00c0, 0x2773: 0x00c0, 0x2774: 0x00c0, 0x2775: 0x00c0,
0x2776: 0x00c0, 0x2777: 0x00c0, 0x2778: 0x00c0, 0x2779: 0x00c0, 0x277a: 0x00c0, 0x277b: 0x00c0,
0x277c: 0x00c0, 0x277d: 0x00c0, 0x277e: 0x00c0, 0x277f: 0x00c0,
// Block 0x9e, offset 0x2780
0x2780: 0x00c0, 0x2781: 0x00c0, 0x2782: 0x00c0, 0x2783: 0x00c0, 0x2784: 0x00c0, 0x2785: 0x00c0,
0x2786: 0x00c0, 0x2787: 0x00c3, 0x2788: 0x00c3, 0x2789: 0x00c3, 0x278a: 0x00c3, 0x278b: 0x00c3,
0x278c: 0x00c3, 0x278d: 0x00c3, 0x278e: 0x00c3, 0x278f: 0x00c3, 0x2790: 0x00c3, 0x2791: 0x00c3,
0x2792: 0x00c0, 0x2793: 0x00c5,
0x279f: 0x0080, 0x27a0: 0x0040, 0x27a1: 0x0040, 0x27a2: 0x0040, 0x27a3: 0x0040,
0x27a4: 0x0040, 0x27a5: 0x0040, 0x27a6: 0x0040, 0x27a7: 0x0040, 0x27a8: 0x0040, 0x27a9: 0x0040,
0x27aa: 0x0040, 0x27ab: 0x0040, 0x27ac: 0x0040, 0x27ad: 0x0040, 0x27ae: 0x0040, 0x27af: 0x0040,
0x27b0: 0x0040, 0x27b1: 0x0040, 0x27b2: 0x0040, 0x27b3: 0x0040, 0x27b4: 0x0040, 0x27b5: 0x0040,
0x27b6: 0x0040, 0x27b7: 0x0040, 0x27b8: 0x0040, 0x27b9: 0x0040, 0x27ba: 0x0040, 0x27bb: 0x0040,
0x27bc: 0x0040,
// Block 0x9f, offset 0x27c0
0x27c0: 0x00c3, 0x27c1: 0x00c3, 0x27c2: 0x00c3, 0x27c3: 0x00c0, 0x27c4: 0x00c0, 0x27c5: 0x00c0,
0x27c6: 0x00c0, 0x27c7: 0x00c0, 0x27c8: 0x00c0, 0x27c9: 0x00c0, 0x27ca: 0x00c0, 0x27cb: 0x00c0,
0x27cc: 0x00c0, 0x27cd: 0x00c0, 0x27ce: 0x00c0, 0x27cf: 0x00c0, 0x27d0: 0x00c0, 0x27d1: 0x00c0,
0x27d2: 0x00c0, 0x27d3: 0x00c0, 0x27d4: 0x00c0, 0x27d5: 0x00c0, 0x27d6: 0x00c0, 0x27d7: 0x00c0,
0x27d8: 0x00c0, 0x27d9: 0x00c0, 0x27da: 0x00c0, 0x27db: 0x00c0, 0x27dc: 0x00c0, 0x27dd: 0x00c0,
0x27de: 0x00c0, 0x27df: 0x00c0, 0x27e0: 0x00c0, 0x27e1: 0x00c0, 0x27e2: 0x00c0, 0x27e3: 0x00c0,
0x27e4: 0x00c0, 0x27e5: 0x00c0, 0x27e6: 0x00c0, 0x27e7: 0x00c0, 0x27e8: 0x00c0, 0x27e9: 0x00c0,
0x27ea: 0x00c0, 0x27eb: 0x00c0, 0x27ec: 0x00c0, 0x27ed: 0x00c0, 0x27ee: 0x00c0, 0x27ef: 0x00c0,
0x27f0: 0x00c0, 0x27f1: 0x00c0, 0x27f2: 0x00c0, 0x27f3: 0x00c3, 0x27f4: 0x00c0, 0x27f5: 0x00c0,
0x27f6: 0x00c3, 0x27f7: 0x00c3, 0x27f8: 0x00c3, 0x27f9: 0x00c3, 0x27fa: 0x00c0, 0x27fb: 0x00c0,
0x27fc: 0x00c3, 0x27fd: 0x00c3, 0x27fe: 0x00c0, 0x27ff: 0x00c0,
// Block 0xa0, offset 0x2800
0x2800: 0x00c5, 0x2801: 0x0080, 0x2802: 0x0080, 0x2803: 0x0080, 0x2804: 0x0080, 0x2805: 0x0080,
0x2806: 0x0080, 0x2807: 0x0080, 0x2808: 0x0080, 0x2809: 0x0080, 0x280a: 0x0080, 0x280b: 0x0080,
0x280c: 0x0080, 0x280d: 0x0080, 0x280f: 0x00c0, 0x2810: 0x00c0, 0x2811: 0x00c0,
0x2812: 0x00c0, 0x2813: 0x00c0, 0x2814: 0x00c0, 0x2815: 0x00c0, 0x2816: 0x00c0, 0x2817: 0x00c0,
0x2818: 0x00c0, 0x2819: 0x00c0,
0x281e: 0x0080, 0x281f: 0x0080, 0x2820: 0x00c0, 0x2821: 0x00c0, 0x2822: 0x00c0, 0x2823: 0x00c0,
0x2824: 0x00c0, 0x2825: 0x00c3, 0x2826: 0x00c0, 0x2827: 0x00c0, 0x2828: 0x00c0, 0x2829: 0x00c0,
0x282a: 0x00c0, 0x282b: 0x00c0, 0x282c: 0x00c0, 0x282d: 0x00c0, 0x282e: 0x00c0, 0x282f: 0x00c0,
0x2830: 0x00c0, 0x2831: 0x00c0, 0x2832: 0x00c0, 0x2833: 0x00c0, 0x2834: 0x00c0, 0x2835: 0x00c0,
0x2836: 0x00c0, 0x2837: 0x00c0, 0x2838: 0x00c0, 0x2839: 0x00c0, 0x283a: 0x00c0, 0x283b: 0x00c0,
0x283c: 0x00c0, 0x283d: 0x00c0, 0x283e: 0x00c0,
// Block 0xa1, offset 0x2840
0x2840: 0x00c0, 0x2841: 0x00c0, 0x2842: 0x00c0, 0x2843: 0x00c0, 0x2844: 0x00c0, 0x2845: 0x00c0,
0x2846: 0x00c0, 0x2847: 0x00c0, 0x2848: 0x00c0, 0x2849: 0x00c0, 0x284a: 0x00c0, 0x284b: 0x00c0,
0x284c: 0x00c0, 0x284d: 0x00c0, 0x284e: 0x00c0, 0x284f: 0x00c0, 0x2850: 0x00c0, 0x2851: 0x00c0,
0x2852: 0x00c0, 0x2853: 0x00c0, 0x2854: 0x00c0, 0x2855: 0x00c0, 0x2856: 0x00c0, 0x2857: 0x00c0,
0x2858: 0x00c0, 0x2859: 0x00c0, 0x285a: 0x00c0, 0x285b: 0x00c0, 0x285c: 0x00c0, 0x285d: 0x00c0,
0x285e: 0x00c0, 0x285f: 0x00c0, 0x2860: 0x00c0, 0x2861: 0x00c0, 0x2862: 0x00c0, 0x2863: 0x00c0,
0x2864: 0x00c0, 0x2865: 0x00c0, 0x2866: 0x00c0, 0x2867: 0x00c0, 0x2868: 0x00c0, 0x2869: 0x00c3,
0x286a: 0x00c3, 0x286b: 0x00c3, 0x286c: 0x00c3, 0x286d: 0x00c3, 0x286e: 0x00c3, 0x286f: 0x00c0,
0x2870: 0x00c0, 0x2871: 0x00c3, 0x2872: 0x00c3, 0x2873: 0x00c0, 0x2874: 0x00c0, 0x2875: 0x00c3,
0x2876: 0x00c3,
// Block 0xa2, offset 0x2880
0x2880: 0x00c0, 0x2881: 0x00c0, 0x2882: 0x00c0, 0x2883: 0x00c3, 0x2884: 0x00c0, 0x2885: 0x00c0,
0x2886: 0x00c0, 0x2887: 0x00c0, 0x2888: 0x00c0, 0x2889: 0x00c0, 0x288a: 0x00c0, 0x288b: 0x00c0,
0x288c: 0x00c3, 0x288d: 0x00c0, 0x2890: 0x00c0, 0x2891: 0x00c0,
0x2892: 0x00c0, 0x2893: 0x00c0, 0x2894: 0x00c0, 0x2895: 0x00c0, 0x2896: 0x00c0, 0x2897: 0x00c0,
0x2898: 0x00c0, 0x2899: 0x00c0, 0x289c: 0x0080, 0x289d: 0x0080,
0x289e: 0x0080, 0x289f: 0x0080, 0x28a0: 0x00c0, 0x28a1: 0x00c0, 0x28a2: 0x00c0, 0x28a3: 0x00c0,
0x28a4: 0x00c0, 0x28a5: 0x00c0, 0x28a6: 0x00c0, 0x28a7: 0x00c0, 0x28a8: 0x00c0, 0x28a9: 0x00c0,
0x28aa: 0x00c0, 0x28ab: 0x00c0, 0x28ac: 0x00c0, 0x28ad: 0x00c0, 0x28ae: 0x00c0, 0x28af: 0x00c0,
0x28b0: 0x00c0, 0x28b1: 0x00c0, 0x28b2: 0x00c0, 0x28b3: 0x00c0, 0x28b4: 0x00c0, 0x28b5: 0x00c0,
0x28b6: 0x00c0, 0x28b7: 0x0080, 0x28b8: 0x0080, 0x28b9: 0x0080, 0x28ba: 0x00c0, 0x28bb: 0x00c0,
0x28bc: 0x00c3, 0x28bd: 0x00c0, 0x28be: 0x00c0, 0x28bf: 0x00c0,
// Block 0xa3, offset 0x28c0
0x28c0: 0x00c0, 0x28c1: 0x00c0, 0x28c2: 0x00c0, 0x28c3: 0x00c0, 0x28c4: 0x00c0, 0x28c5: 0x00c0,
0x28c6: 0x00c0, 0x28c7: 0x00c0, 0x28c8: 0x00c0, 0x28c9: 0x00c0, 0x28ca: 0x00c0, 0x28cb: 0x00c0,
0x28cc: 0x00c0, 0x28cd: 0x00c0, 0x28ce: 0x00c0, 0x28cf: 0x00c0, 0x28d0: 0x00c0, 0x28d1: 0x00c0,
0x28d2: 0x00c0, 0x28d3: 0x00c0, 0x28d4: 0x00c0, 0x28d5: 0x00c0, 0x28d6: 0x00c0, 0x28d7: 0x00c0,
0x28d8: 0x00c0, 0x28d9: 0x00c0, 0x28da: 0x00c0, 0x28db: 0x00c0, 0x28dc: 0x00c0, 0x28dd: 0x00c0,
0x28de: 0x00c0, 0x28df: 0x00c0, 0x28e0: 0x00c0, 0x28e1: 0x00c0, 0x28e2: 0x00c0, 0x28e3: 0x00c0,
0x28e4: 0x00c0, 0x28e5: 0x00c0, 0x28e6: 0x00c0, 0x28e7: 0x00c0, 0x28e8: 0x00c0, 0x28e9: 0x00c0,
0x28ea: 0x00c0, 0x28eb: 0x00c0, 0x28ec: 0x00c0, 0x28ed: 0x00c0, 0x28ee: 0x00c0, 0x28ef: 0x00c0,
0x28f0: 0x00c3, 0x28f1: 0x00c0, 0x28f2: 0x00c3, 0x28f3: 0x00c3, 0x28f4: 0x00c3, 0x28f5: 0x00c0,
0x28f6: 0x00c0, 0x28f7: 0x00c3, 0x28f8: 0x00c3, 0x28f9: 0x00c0, 0x28fa: 0x00c0, 0x28fb: 0x00c0,
0x28fc: 0x00c0, 0x28fd: 0x00c0, 0x28fe: 0x00c3, 0x28ff: 0x00c3,
// Block 0xa4, offset 0x2900
0x2900: 0x00c0, 0x2901: 0x00c3, 0x2902: 0x00c0,
0x291b: 0x00c0, 0x291c: 0x00c0, 0x291d: 0x00c0,
0x291e: 0x0080, 0x291f: 0x0080, 0x2920: 0x00c0, 0x2921: 0x00c0, 0x2922: 0x00c0, 0x2923: 0x00c0,
0x2924: 0x00c0, 0x2925: 0x00c0, 0x2926: 0x00c0, 0x2927: 0x00c0, 0x2928: 0x00c0, 0x2929: 0x00c0,
0x292a: 0x00c0, 0x292b: 0x00c0, 0x292c: 0x00c3, 0x292d: 0x00c3, 0x292e: 0x00c0, 0x292f: 0x00c0,
0x2930: 0x0080, 0x2931: 0x0080, 0x2932: 0x00c0, 0x2933: 0x00c0, 0x2934: 0x00c0, 0x2935: 0x00c0,
0x2936: 0x00c6,
// Block 0xa5, offset 0x2940
0x2941: 0x00c0, 0x2942: 0x00c0, 0x2943: 0x00c0, 0x2944: 0x00c0, 0x2945: 0x00c0,
0x2946: 0x00c0, 0x2949: 0x00c0, 0x294a: 0x00c0, 0x294b: 0x00c0,
0x294c: 0x00c0, 0x294d: 0x00c0, 0x294e: 0x00c0, 0x2951: 0x00c0,
0x2952: 0x00c0, 0x2953: 0x00c0, 0x2954: 0x00c0, 0x2955: 0x00c0, 0x2956: 0x00c0,
0x2960: 0x00c0, 0x2961: 0x00c0, 0x2962: 0x00c0, 0x2963: 0x00c0,
0x2964: 0x00c0, 0x2965: 0x00c0, 0x2966: 0x00c0, 0x2968: 0x00c0, 0x2969: 0x00c0,
0x296a: 0x00c0, 0x296b: 0x00c0, 0x296c: 0x00c0, 0x296d: 0x00c0, 0x296e: 0x00c0,
0x2970: 0x00c0, 0x2971: 0x00c0, 0x2972: 0x00c0, 0x2973: 0x00c0, 0x2974: 0x00c0, 0x2975: 0x00c0,
0x2976: 0x00c0, 0x2977: 0x00c0, 0x2978: 0x00c0, 0x2979: 0x00c0, 0x297a: 0x00c0, 0x297b: 0x00c0,
0x297c: 0x00c0, 0x297d: 0x00c0, 0x297e: 0x00c0, 0x297f: 0x00c0,
// Block 0xa6, offset 0x2980
0x2980: 0x00c0, 0x2981: 0x00c0, 0x2982: 0x00c0, 0x2983: 0x00c0, 0x2984: 0x00c0, 0x2985: 0x00c0,
0x2986: 0x00c0, 0x2987: 0x00c0, 0x2988: 0x00c0, 0x2989: 0x00c0, 0x298a: 0x00c0, 0x298b: 0x00c0,
0x298c: 0x00c0, 0x298d: 0x00c0, 0x298e: 0x00c0, 0x298f: 0x00c0, 0x2990: 0x00c0, 0x2991: 0x00c0,
0x2992: 0x00c0, 0x2993: 0x00c0, 0x2994: 0x00c0, 0x2995: 0x00c0, 0x2996: 0x00c0, 0x2997: 0x00c0,
0x2998: 0x00c0, 0x2999: 0x00c0, 0x299a: 0x00c0, 0x299b: 0x0080, 0x299c: 0x0080, 0x299d: 0x0080,
0x299e: 0x0080, 0x299f: 0x0080, 0x29a0: 0x00c0, 0x29a1: 0x00c0, 0x29a2: 0x00c0, 0x29a3: 0x00c0,
0x29a4: 0x00c0, 0x29a5: 0x00c8, 0x29a6: 0x00c0, 0x29a7: 0x00c0, 0x29a8: 0x00c0, 0x29a9: 0x0080,
0x29aa: 0x0080, 0x29ab: 0x0080,
0x29b0: 0x00c0, 0x29b1: 0x00c0, 0x29b2: 0x00c0, 0x29b3: 0x00c0, 0x29b4: 0x00c0, 0x29b5: 0x00c0,
0x29b6: 0x00c0, 0x29b7: 0x00c0, 0x29b8: 0x00c0, 0x29b9: 0x00c0, 0x29ba: 0x00c0, 0x29bb: 0x00c0,
0x29bc: 0x00c0, 0x29bd: 0x00c0, 0x29be: 0x00c0, 0x29bf: 0x00c0,
// Block 0xa7, offset 0x29c0
0x29c0: 0x00c0, 0x29c1: 0x00c0, 0x29c2: 0x00c0, 0x29c3: 0x00c0, 0x29c4: 0x00c0, 0x29c5: 0x00c0,
0x29c6: 0x00c0, 0x29c7: 0x00c0, 0x29c8: 0x00c0, 0x29c9: 0x00c0, 0x29ca: 0x00c0, 0x29cb: 0x00c0,
0x29cc: 0x00c0, 0x29cd: 0x00c0, 0x29ce: 0x00c0, 0x29cf: 0x00c0, 0x29d0: 0x00c0, 0x29d1: 0x00c0,
0x29d2: 0x00c0, 0x29d3: 0x00c0, 0x29d4: 0x00c0, 0x29d5: 0x00c0, 0x29d6: 0x00c0, 0x29d7: 0x00c0,
0x29d8: 0x00c0, 0x29d9: 0x00c0, 0x29da: 0x00c0, 0x29db: 0x00c0, 0x29dc: 0x00c0, 0x29dd: 0x00c0,
0x29de: 0x00c0, 0x29df: 0x00c0, 0x29e0: 0x00c0, 0x29e1: 0x00c0, 0x29e2: 0x00c0, 0x29e3: 0x00c0,
0x29e4: 0x00c0, 0x29e5: 0x00c3, 0x29e6: 0x00c0, 0x29e7: 0x00c0, 0x29e8: 0x00c3, 0x29e9: 0x00c0,
0x29ea: 0x00c0, 0x29eb: 0x0080, 0x29ec: 0x00c0, 0x29ed: 0x00c6,
0x29f0: 0x00c0, 0x29f1: 0x00c0, 0x29f2: 0x00c0, 0x29f3: 0x00c0, 0x29f4: 0x00c0, 0x29f5: 0x00c0,
0x29f6: 0x00c0, 0x29f7: 0x00c0, 0x29f8: 0x00c0, 0x29f9: 0x00c0,
// Block 0xa8, offset 0x2a00
0x2a00: 0x00c0, 0x2a01: 0x00c0, 0x2a02: 0x00c0, 0x2a03: 0x00c0, 0x2a04: 0x00c0, 0x2a05: 0x00c0,
0x2a06: 0x00c0, 0x2a07: 0x00c0, 0x2a08: 0x00c0, 0x2a09: 0x00c0, 0x2a0a: 0x00c0, 0x2a0b: 0x00c0,
0x2a0c: 0x00c0, 0x2a0d: 0x00c0, 0x2a0e: 0x00c0, 0x2a0f: 0x00c0, 0x2a10: 0x00c0, 0x2a11: 0x00c0,
0x2a12: 0x00c0, 0x2a13: 0x00c0, 0x2a14: 0x00c0, 0x2a15: 0x00c0, 0x2a16: 0x00c0, 0x2a17: 0x00c0,
0x2a18: 0x00c0, 0x2a19: 0x00c0, 0x2a1a: 0x00c0, 0x2a1b: 0x00c0, 0x2a1c: 0x00c0, 0x2a1d: 0x00c0,
0x2a1e: 0x00c0, 0x2a1f: 0x00c0, 0x2a20: 0x00c0, 0x2a21: 0x00c0, 0x2a22: 0x00c0, 0x2a23: 0x00c0,
0x2a30: 0x0040, 0x2a31: 0x0040, 0x2a32: 0x0040, 0x2a33: 0x0040, 0x2a34: 0x0040, 0x2a35: 0x0040,
0x2a36: 0x0040, 0x2a37: 0x0040, 0x2a38: 0x0040, 0x2a39: 0x0040, 0x2a3a: 0x0040, 0x2a3b: 0x0040,
0x2a3c: 0x0040, 0x2a3d: 0x0040, 0x2a3e: 0x0040, 0x2a3f: 0x0040,
// Block 0xa9, offset 0x2a40
0x2a40: 0x0040, 0x2a41: 0x0040, 0x2a42: 0x0040, 0x2a43: 0x0040, 0x2a44: 0x0040, 0x2a45: 0x0040,
0x2a46: 0x0040, 0x2a4b: 0x0040,
0x2a4c: 0x0040, 0x2a4d: 0x0040, 0x2a4e: 0x0040, 0x2a4f: 0x0040, 0x2a50: 0x0040, 0x2a51: 0x0040,
0x2a52: 0x0040, 0x2a53: 0x0040, 0x2a54: 0x0040, 0x2a55: 0x0040, 0x2a56: 0x0040, 0x2a57: 0x0040,
0x2a58: 0x0040, 0x2a59: 0x0040, 0x2a5a: 0x0040, 0x2a5b: 0x0040, 0x2a5c: 0x0040, 0x2a5d: 0x0040,
0x2a5e: 0x0040, 0x2a5f: 0x0040, 0x2a60: 0x0040, 0x2a61: 0x0040, 0x2a62: 0x0040, 0x2a63: 0x0040,
0x2a64: 0x0040, 0x2a65: 0x0040, 0x2a66: 0x0040, 0x2a67: 0x0040, 0x2a68: 0x0040, 0x2a69: 0x0040,
0x2a6a: 0x0040, 0x2a6b: 0x0040, 0x2a6c: 0x0040, 0x2a6d: 0x0040, 0x2a6e: 0x0040, 0x2a6f: 0x0040,
0x2a70: 0x0040, 0x2a71: 0x0040, 0x2a72: 0x0040, 0x2a73: 0x0040, 0x2a74: 0x0040, 0x2a75: 0x0040,
0x2a76: 0x0040, 0x2a77: 0x0040, 0x2a78: 0x0040, 0x2a79: 0x0040, 0x2a7a: 0x0040, 0x2a7b: 0x0040,
// Block 0xaa, offset 0x2a80
0x2a80: 0x008c, 0x2a81: 0x008c, 0x2a82: 0x008c, 0x2a83: 0x008c, 0x2a84: 0x008c, 0x2a85: 0x008c,
0x2a86: 0x008c, 0x2a87: 0x008c, 0x2a88: 0x008c, 0x2a89: 0x008c, 0x2a8a: 0x008c, 0x2a8b: 0x008c,
0x2a8c: 0x008c, 0x2a8d: 0x008c, 0x2a8e: 0x00cc, 0x2a8f: 0x00cc, 0x2a90: 0x008c, 0x2a91: 0x00cc,
0x2a92: 0x008c, 0x2a93: 0x00cc, 0x2a94: 0x00cc, 0x2a95: 0x008c, 0x2a96: 0x008c, 0x2a97: 0x008c,
0x2a98: 0x008c, 0x2a99: 0x008c, 0x2a9a: 0x008c, 0x2a9b: 0x008c, 0x2a9c: 0x008c, 0x2a9d: 0x008c,
0x2a9e: 0x008c, 0x2a9f: 0x00cc, 0x2aa0: 0x008c, 0x2aa1: 0x00cc, 0x2aa2: 0x008c, 0x2aa3: 0x00cc,
0x2aa4: 0x00cc, 0x2aa5: 0x008c, 0x2aa6: 0x008c, 0x2aa7: 0x00cc, 0x2aa8: 0x00cc, 0x2aa9: 0x00cc,
0x2aaa: 0x008c, 0x2aab: 0x008c, 0x2aac: 0x008c, 0x2aad: 0x008c, 0x2aae: 0x008c, 0x2aaf: 0x008c,
0x2ab0: 0x008c, 0x2ab1: 0x008c, 0x2ab2: 0x008c, 0x2ab3: 0x008c, 0x2ab4: 0x008c, 0x2ab5: 0x008c,
0x2ab6: 0x008c, 0x2ab7: 0x008c, 0x2ab8: 0x008c, 0x2ab9: 0x008c, 0x2aba: 0x008c, 0x2abb: 0x008c,
0x2abc: 0x008c, 0x2abd: 0x008c, 0x2abe: 0x008c, 0x2abf: 0x008c,
// Block 0xab, offset 0x2ac0
0x2ac0: 0x008c, 0x2ac1: 0x008c, 0x2ac2: 0x008c, 0x2ac3: 0x008c, 0x2ac4: 0x008c, 0x2ac5: 0x008c,
0x2ac6: 0x008c, 0x2ac7: 0x008c, 0x2ac8: 0x008c, 0x2ac9: 0x008c, 0x2aca: 0x008c, 0x2acb: 0x008c,
0x2acc: 0x008c, 0x2acd: 0x008c, 0x2ace: 0x008c, 0x2acf: 0x008c, 0x2ad0: 0x008c, 0x2ad1: 0x008c,
0x2ad2: 0x008c, 0x2ad3: 0x008c, 0x2ad4: 0x008c, 0x2ad5: 0x008c, 0x2ad6: 0x008c, 0x2ad7: 0x008c,
0x2ad8: 0x008c, 0x2ad9: 0x008c, 0x2ada: 0x008c, 0x2adb: 0x008c, 0x2adc: 0x008c, 0x2add: 0x008c,
0x2ade: 0x008c, 0x2adf: 0x008c, 0x2ae0: 0x008c, 0x2ae1: 0x008c, 0x2ae2: 0x008c, 0x2ae3: 0x008c,
0x2ae4: 0x008c, 0x2ae5: 0x008c, 0x2ae6: 0x008c, 0x2ae7: 0x008c, 0x2ae8: 0x008c, 0x2ae9: 0x008c,
0x2aea: 0x008c, 0x2aeb: 0x008c, 0x2aec: 0x008c, 0x2aed: 0x008c,
0x2af0: 0x008c, 0x2af1: 0x008c, 0x2af2: 0x008c, 0x2af3: 0x008c, 0x2af4: 0x008c, 0x2af5: 0x008c,
0x2af6: 0x008c, 0x2af7: 0x008c, 0x2af8: 0x008c, 0x2af9: 0x008c, 0x2afa: 0x008c, 0x2afb: 0x008c,
0x2afc: 0x008c, 0x2afd: 0x008c, 0x2afe: 0x008c, 0x2aff: 0x008c,
// Block 0xac, offset 0x2b00
0x2b00: 0x008c, 0x2b01: 0x008c, 0x2b02: 0x008c, 0x2b03: 0x008c, 0x2b04: 0x008c, 0x2b05: 0x008c,
0x2b06: 0x008c, 0x2b07: 0x008c, 0x2b08: 0x008c, 0x2b09: 0x008c, 0x2b0a: 0x008c, 0x2b0b: 0x008c,
0x2b0c: 0x008c, 0x2b0d: 0x008c, 0x2b0e: 0x008c, 0x2b0f: 0x008c, 0x2b10: 0x008c, 0x2b11: 0x008c,
0x2b12: 0x008c, 0x2b13: 0x008c, 0x2b14: 0x008c, 0x2b15: 0x008c, 0x2b16: 0x008c, 0x2b17: 0x008c,
0x2b18: 0x008c, 0x2b19: 0x008c,
// Block 0xad, offset 0x2b40
0x2b40: 0x0080, 0x2b41: 0x0080, 0x2b42: 0x0080, 0x2b43: 0x0080, 0x2b44: 0x0080, 0x2b45: 0x0080,
0x2b46: 0x0080,
0x2b53: 0x0080, 0x2b54: 0x0080, 0x2b55: 0x0080, 0x2b56: 0x0080, 0x2b57: 0x0080,
0x2b5d: 0x008a,
0x2b5e: 0x00cb, 0x2b5f: 0x008a, 0x2b60: 0x008a, 0x2b61: 0x008a, 0x2b62: 0x008a, 0x2b63: 0x008a,
0x2b64: 0x008a, 0x2b65: 0x008a, 0x2b66: 0x008a, 0x2b67: 0x008a, 0x2b68: 0x008a, 0x2b69: 0x008a,
0x2b6a: 0x008a, 0x2b6b: 0x008a, 0x2b6c: 0x008a, 0x2b6d: 0x008a, 0x2b6e: 0x008a, 0x2b6f: 0x008a,
0x2b70: 0x008a, 0x2b71: 0x008a, 0x2b72: 0x008a, 0x2b73: 0x008a, 0x2b74: 0x008a, 0x2b75: 0x008a,
0x2b76: 0x008a, 0x2b78: 0x008a, 0x2b79: 0x008a, 0x2b7a: 0x008a, 0x2b7b: 0x008a,
0x2b7c: 0x008a, 0x2b7e: 0x008a,
// Block 0xae, offset 0x2b80
0x2b80: 0x008a, 0x2b81: 0x008a, 0x2b83: 0x008a, 0x2b84: 0x008a,
0x2b86: 0x008a, 0x2b87: 0x008a, 0x2b88: 0x008a, 0x2b89: 0x008a, 0x2b8a: 0x008a, 0x2b8b: 0x008a,
0x2b8c: 0x008a, 0x2b8d: 0x008a, 0x2b8e: 0x008a, 0x2b8f: 0x008a, 0x2b90: 0x0080, 0x2b91: 0x0080,
0x2b92: 0x0080, 0x2b93: 0x0080, 0x2b94: 0x0080, 0x2b95: 0x0080, 0x2b96: 0x0080, 0x2b97: 0x0080,
0x2b98: 0x0080, 0x2b99: 0x0080, 0x2b9a: 0x0080, 0x2b9b: 0x0080, 0x2b9c: 0x0080, 0x2b9d: 0x0080,
0x2b9e: 0x0080, 0x2b9f: 0x0080, 0x2ba0: 0x0080, 0x2ba1: 0x0080, 0x2ba2: 0x0080, 0x2ba3: 0x0080,
0x2ba4: 0x0080, 0x2ba5: 0x0080, 0x2ba6: 0x0080, 0x2ba7: 0x0080, 0x2ba8: 0x0080, 0x2ba9: 0x0080,
0x2baa: 0x0080, 0x2bab: 0x0080, 0x2bac: 0x0080, 0x2bad: 0x0080, 0x2bae: 0x0080, 0x2baf: 0x0080,
0x2bb0: 0x0080, 0x2bb1: 0x0080, 0x2bb2: 0x0080, 0x2bb3: 0x0080, 0x2bb4: 0x0080, 0x2bb5: 0x0080,
0x2bb6: 0x0080, 0x2bb7: 0x0080, 0x2bb8: 0x0080, 0x2bb9: 0x0080, 0x2bba: 0x0080, 0x2bbb: 0x0080,
0x2bbc: 0x0080, 0x2bbd: 0x0080, 0x2bbe: 0x0080, 0x2bbf: 0x0080,
// Block 0xaf, offset 0x2bc0
0x2bc0: 0x0080, 0x2bc1: 0x0080, 0x2bc2: 0x0080,
0x2bd3: 0x0080, 0x2bd4: 0x0080, 0x2bd5: 0x0080, 0x2bd6: 0x0080, 0x2bd7: 0x0080,
0x2bd8: 0x0080, 0x2bd9: 0x0080, 0x2bda: 0x0080, 0x2bdb: 0x0080, 0x2bdc: 0x0080, 0x2bdd: 0x0080,
0x2bde: 0x0080, 0x2bdf: 0x0080, 0x2be0: 0x0080, 0x2be1: 0x0080, 0x2be2: 0x0080, 0x2be3: 0x0080,
0x2be4: 0x0080, 0x2be5: 0x0080, 0x2be6: 0x0080, 0x2be7: 0x0080, 0x2be8: 0x0080, 0x2be9: 0x0080,
0x2bea: 0x0080, 0x2beb: 0x0080, 0x2bec: 0x0080, 0x2bed: 0x0080, 0x2bee: 0x0080, 0x2bef: 0x0080,
0x2bf0: 0x0080, 0x2bf1: 0x0080, 0x2bf2: 0x0080, 0x2bf3: 0x0080, 0x2bf4: 0x0080, 0x2bf5: 0x0080,
0x2bf6: 0x0080, 0x2bf7: 0x0080, 0x2bf8: 0x0080, 0x2bf9: 0x0080, 0x2bfa: 0x0080, 0x2bfb: 0x0080,
0x2bfc: 0x0080, 0x2bfd: 0x0080, 0x2bfe: 0x0080, 0x2bff: 0x0080,
// Block 0xb0, offset 0x2c00
0x2c00: 0x0080, 0x2c01: 0x0080, 0x2c02: 0x0080, 0x2c03: 0x0080, 0x2c04: 0x0080, 0x2c05: 0x0080,
0x2c06: 0x0080, 0x2c07: 0x0080, 0x2c08: 0x0080, 0x2c09: 0x0080, 0x2c0a: 0x0080, 0x2c0b: 0x0080,
0x2c0c: 0x0080, 0x2c0d: 0x0080, 0x2c0e: 0x0080, 0x2c0f: 0x0080,
0x2c12: 0x0080, 0x2c13: 0x0080, 0x2c14: 0x0080, 0x2c15: 0x0080, 0x2c16: 0x0080, 0x2c17: 0x0080,
0x2c18: 0x0080, 0x2c19: 0x0080, 0x2c1a: 0x0080, 0x2c1b: 0x0080, 0x2c1c: 0x0080, 0x2c1d: 0x0080,
0x2c1e: 0x0080, 0x2c1f: 0x0080, 0x2c20: 0x0080, 0x2c21: 0x0080, 0x2c22: 0x0080, 0x2c23: 0x0080,
0x2c24: 0x0080, 0x2c25: 0x0080, 0x2c26: 0x0080, 0x2c27: 0x0080, 0x2c28: 0x0080, 0x2c29: 0x0080,
0x2c2a: 0x0080, 0x2c2b: 0x0080, 0x2c2c: 0x0080, 0x2c2d: 0x0080, 0x2c2e: 0x0080, 0x2c2f: 0x0080,
0x2c30: 0x0080, 0x2c31: 0x0080, 0x2c32: 0x0080, 0x2c33: 0x0080, 0x2c34: 0x0080, 0x2c35: 0x0080,
0x2c36: 0x0080, 0x2c37: 0x0080, 0x2c38: 0x0080, 0x2c39: 0x0080, 0x2c3a: 0x0080, 0x2c3b: 0x0080,
0x2c3c: 0x0080, 0x2c3d: 0x0080, 0x2c3e: 0x0080, 0x2c3f: 0x0080,
// Block 0xb1, offset 0x2c40
0x2c40: 0x0080, 0x2c41: 0x0080, 0x2c42: 0x0080, 0x2c43: 0x0080, 0x2c44: 0x0080, 0x2c45: 0x0080,
0x2c46: 0x0080, 0x2c47: 0x0080,
0x2c4f: 0x0080,
0x2c70: 0x0080, 0x2c71: 0x0080, 0x2c72: 0x0080, 0x2c73: 0x0080, 0x2c74: 0x0080, 0x2c75: 0x0080,
0x2c76: 0x0080, 0x2c77: 0x0080, 0x2c78: 0x0080, 0x2c79: 0x0080, 0x2c7a: 0x0080, 0x2c7b: 0x0080,
0x2c7c: 0x0080, 0x2c7d: 0x0080, 0x2c7e: 0x0080, 0x2c7f: 0x0080,
// Block 0xb2, offset 0x2c80
0x2c80: 0x0040, 0x2c81: 0x0040, 0x2c82: 0x0040, 0x2c83: 0x0040, 0x2c84: 0x0040, 0x2c85: 0x0040,
0x2c86: 0x0040, 0x2c87: 0x0040, 0x2c88: 0x0040, 0x2c89: 0x0040, 0x2c8a: 0x0040, 0x2c8b: 0x0040,
0x2c8c: 0x0040, 0x2c8d: 0x0040, 0x2c8e: 0x0040, 0x2c8f: 0x0040, 0x2c90: 0x0080, 0x2c91: 0x0080,
0x2c92: 0x0080, 0x2c93: 0x0080, 0x2c94: 0x0080, 0x2c95: 0x0080, 0x2c96: 0x0080, 0x2c97: 0x0080,
0x2c98: 0x0080, 0x2c99: 0x0080,
0x2ca0: 0x00c3, 0x2ca1: 0x00c3, 0x2ca2: 0x00c3, 0x2ca3: 0x00c3,
0x2ca4: 0x00c3, 0x2ca5: 0x00c3, 0x2ca6: 0x00c3, 0x2ca7: 0x00c3, 0x2ca8: 0x00c3, 0x2ca9: 0x00c3,
0x2caa: 0x00c3, 0x2cab: 0x00c3, 0x2cac: 0x00c3, 0x2cad: 0x00c3, 0x2cae: 0x00c3, 0x2caf: 0x00c3,
0x2cb0: 0x0080, 0x2cb1: 0x0080, 0x2cb2: 0x0080, 0x2cb3: 0x0080, 0x2cb4: 0x0080, 0x2cb5: 0x0080,
0x2cb6: 0x0080, 0x2cb7: 0x0080, 0x2cb8: 0x0080, 0x2cb9: 0x0080, 0x2cba: 0x0080, 0x2cbb: 0x0080,
0x2cbc: 0x0080, 0x2cbd: 0x0080, 0x2cbe: 0x0080, 0x2cbf: 0x0080,
// Block 0xb3, offset 0x2cc0
0x2cc0: 0x0080, 0x2cc1: 0x0080, 0x2cc2: 0x0080, 0x2cc3: 0x0080, 0x2cc4: 0x0080, 0x2cc5: 0x0080,
0x2cc6: 0x0080, 0x2cc7: 0x0080, 0x2cc8: 0x0080, 0x2cc9: 0x0080, 0x2cca: 0x0080, 0x2ccb: 0x0080,
0x2ccc: 0x0080, 0x2ccd: 0x0080, 0x2cce: 0x0080, 0x2ccf: 0x0080, 0x2cd0: 0x0080, 0x2cd1: 0x0080,
0x2cd2: 0x0080, 0x2cd4: 0x0080, 0x2cd5: 0x0080, 0x2cd6: 0x0080, 0x2cd7: 0x0080,
0x2cd8: 0x0080, 0x2cd9: 0x0080, 0x2cda: 0x0080, 0x2cdb: 0x0080, 0x2cdc: 0x0080, 0x2cdd: 0x0080,
0x2cde: 0x0080, 0x2cdf: 0x0080, 0x2ce0: 0x0080, 0x2ce1: 0x0080, 0x2ce2: 0x0080, 0x2ce3: 0x0080,
0x2ce4: 0x0080, 0x2ce5: 0x0080, 0x2ce6: 0x0080, 0x2ce8: 0x0080, 0x2ce9: 0x0080,
0x2cea: 0x0080, 0x2ceb: 0x0080,
0x2cf0: 0x0080, 0x2cf1: 0x0080, 0x2cf2: 0x0080, 0x2cf3: 0x00c0, 0x2cf4: 0x0080,
0x2cf6: 0x0080, 0x2cf7: 0x0080, 0x2cf8: 0x0080, 0x2cf9: 0x0080, 0x2cfa: 0x0080, 0x2cfb: 0x0080,
0x2cfc: 0x0080, 0x2cfd: 0x0080, 0x2cfe: 0x0080, 0x2cff: 0x0080,
// Block 0xb4, offset 0x2d00
0x2d00: 0x0080, 0x2d01: 0x0080, 0x2d02: 0x0080, 0x2d03: 0x0080, 0x2d04: 0x0080, 0x2d05: 0x0080,
0x2d06: 0x0080, 0x2d07: 0x0080, 0x2d08: 0x0080, 0x2d09: 0x0080, 0x2d0a: 0x0080, 0x2d0b: 0x0080,
0x2d0c: 0x0080, 0x2d0d: 0x0080, 0x2d0e: 0x0080, 0x2d0f: 0x0080, 0x2d10: 0x0080, 0x2d11: 0x0080,
0x2d12: 0x0080, 0x2d13: 0x0080, 0x2d14: 0x0080, 0x2d15: 0x0080, 0x2d16: 0x0080, 0x2d17: 0x0080,
0x2d18: 0x0080, 0x2d19: 0x0080, 0x2d1a: 0x0080, 0x2d1b: 0x0080, 0x2d1c: 0x0080, 0x2d1d: 0x0080,
0x2d1e: 0x0080, 0x2d1f: 0x0080, 0x2d20: 0x0080, 0x2d21: 0x0080, 0x2d22: 0x0080, 0x2d23: 0x0080,
0x2d24: 0x0080, 0x2d25: 0x0080, 0x2d26: 0x0080, 0x2d27: 0x0080, 0x2d28: 0x0080, 0x2d29: 0x0080,
0x2d2a: 0x0080, 0x2d2b: 0x0080, 0x2d2c: 0x0080, 0x2d2d: 0x0080, 0x2d2e: 0x0080, 0x2d2f: 0x0080,
0x2d30: 0x0080, 0x2d31: 0x0080, 0x2d32: 0x0080, 0x2d33: 0x0080, 0x2d34: 0x0080, 0x2d35: 0x0080,
0x2d36: 0x0080, 0x2d37: 0x0080, 0x2d38: 0x0080, 0x2d39: 0x0080, 0x2d3a: 0x0080, 0x2d3b: 0x0080,
0x2d3c: 0x0080, 0x2d3f: 0x0040,
// Block 0xb5, offset 0x2d40
0x2d41: 0x0080, 0x2d42: 0x0080, 0x2d43: 0x0080, 0x2d44: 0x0080, 0x2d45: 0x0080,
0x2d46: 0x0080, 0x2d47: 0x0080, 0x2d48: 0x0080, 0x2d49: 0x0080, 0x2d4a: 0x0080, 0x2d4b: 0x0080,
0x2d4c: 0x0080, 0x2d4d: 0x0080, 0x2d4e: 0x0080, 0x2d4f: 0x0080, 0x2d50: 0x0080, 0x2d51: 0x0080,
0x2d52: 0x0080, 0x2d53: 0x0080, 0x2d54: 0x0080, 0x2d55: 0x0080, 0x2d56: 0x0080, 0x2d57: 0x0080,
0x2d58: 0x0080, 0x2d59: 0x0080, 0x2d5a: 0x0080, 0x2d5b: 0x0080, 0x2d5c: 0x0080, 0x2d5d: 0x0080,
0x2d5e: 0x0080, 0x2d5f: 0x0080, 0x2d60: 0x0080, 0x2d61: 0x0080, 0x2d62: 0x0080, 0x2d63: 0x0080,
0x2d64: 0x0080, 0x2d65: 0x0080, 0x2d66: 0x0080, 0x2d67: 0x0080, 0x2d68: 0x0080, 0x2d69: 0x0080,
0x2d6a: 0x0080, 0x2d6b: 0x0080, 0x2d6c: 0x0080, 0x2d6d: 0x0080, 0x2d6e: 0x0080, 0x2d6f: 0x0080,
0x2d70: 0x0080, 0x2d71: 0x0080, 0x2d72: 0x0080, 0x2d73: 0x0080, 0x2d74: 0x0080, 0x2d75: 0x0080,
0x2d76: 0x0080, 0x2d77: 0x0080, 0x2d78: 0x0080, 0x2d79: 0x0080, 0x2d7a: 0x0080, 0x2d7b: 0x0080,
0x2d7c: 0x0080, 0x2d7d: 0x0080, 0x2d7e: 0x0080, 0x2d7f: 0x0080,
// Block 0xb6, offset 0x2d80
0x2d80: 0x0080, 0x2d81: 0x0080, 0x2d82: 0x0080, 0x2d83: 0x0080, 0x2d84: 0x0080, 0x2d85: 0x0080,
0x2d86: 0x0080, 0x2d87: 0x0080, 0x2d88: 0x0080, 0x2d89: 0x0080, 0x2d8a: 0x0080, 0x2d8b: 0x0080,
0x2d8c: 0x0080, 0x2d8d: 0x0080, 0x2d8e: 0x0080, 0x2d8f: 0x0080, 0x2d90: 0x0080, 0x2d91: 0x0080,
0x2d92: 0x0080, 0x2d93: 0x0080, 0x2d94: 0x0080, 0x2d95: 0x0080, 0x2d96: 0x0080, 0x2d97: 0x0080,
0x2d98: 0x0080, 0x2d99: 0x0080, 0x2d9a: 0x0080, 0x2d9b: 0x0080, 0x2d9c: 0x0080, 0x2d9d: 0x0080,
0x2d9e: 0x0080, 0x2d9f: 0x0080, 0x2da0: 0x0080, 0x2da1: 0x0080, 0x2da2: 0x0080, 0x2da3: 0x0080,
0x2da4: 0x0080, 0x2da5: 0x0080, 0x2da6: 0x008c, 0x2da7: 0x008c, 0x2da8: 0x008c, 0x2da9: 0x008c,
0x2daa: 0x008c, 0x2dab: 0x008c, 0x2dac: 0x008c, 0x2dad: 0x008c, 0x2dae: 0x008c, 0x2daf: 0x008c,
0x2db0: 0x0080, 0x2db1: 0x008c, 0x2db2: 0x008c, 0x2db3: 0x008c, 0x2db4: 0x008c, 0x2db5: 0x008c,
0x2db6: 0x008c, 0x2db7: 0x008c, 0x2db8: 0x008c, 0x2db9: 0x008c, 0x2dba: 0x008c, 0x2dbb: 0x008c,
0x2dbc: 0x008c, 0x2dbd: 0x008c, 0x2dbe: 0x008c, 0x2dbf: 0x008c,
// Block 0xb7, offset 0x2dc0
0x2dc0: 0x008c, 0x2dc1: 0x008c, 0x2dc2: 0x008c, 0x2dc3: 0x008c, 0x2dc4: 0x008c, 0x2dc5: 0x008c,
0x2dc6: 0x008c, 0x2dc7: 0x008c, 0x2dc8: 0x008c, 0x2dc9: 0x008c, 0x2dca: 0x008c, 0x2dcb: 0x008c,
0x2dcc: 0x008c, 0x2dcd: 0x008c, 0x2dce: 0x008c, 0x2dcf: 0x008c, 0x2dd0: 0x008c, 0x2dd1: 0x008c,
0x2dd2: 0x008c, 0x2dd3: 0x008c, 0x2dd4: 0x008c, 0x2dd5: 0x008c, 0x2dd6: 0x008c, 0x2dd7: 0x008c,
0x2dd8: 0x008c, 0x2dd9: 0x008c, 0x2dda: 0x008c, 0x2ddb: 0x008c, 0x2ddc: 0x008c, 0x2ddd: 0x008c,
0x2dde: 0x0080, 0x2ddf: 0x0080, 0x2de0: 0x0040, 0x2de1: 0x0080, 0x2de2: 0x0080, 0x2de3: 0x0080,
0x2de4: 0x0080, 0x2de5: 0x0080, 0x2de6: 0x0080, 0x2de7: 0x0080, 0x2de8: 0x0080, 0x2de9: 0x0080,
0x2dea: 0x0080, 0x2deb: 0x0080, 0x2dec: 0x0080, 0x2ded: 0x0080, 0x2dee: 0x0080, 0x2def: 0x0080,
0x2df0: 0x0080, 0x2df1: 0x0080, 0x2df2: 0x0080, 0x2df3: 0x0080, 0x2df4: 0x0080, 0x2df5: 0x0080,
0x2df6: 0x0080, 0x2df7: 0x0080, 0x2df8: 0x0080, 0x2df9: 0x0080, 0x2dfa: 0x0080, 0x2dfb: 0x0080,
0x2dfc: 0x0080, 0x2dfd: 0x0080, 0x2dfe: 0x0080,
// Block 0xb8, offset 0x2e00
0x2e02: 0x0080, 0x2e03: 0x0080, 0x2e04: 0x0080, 0x2e05: 0x0080,
0x2e06: 0x0080, 0x2e07: 0x0080, 0x2e0a: 0x0080, 0x2e0b: 0x0080,
0x2e0c: 0x0080, 0x2e0d: 0x0080, 0x2e0e: 0x0080, 0x2e0f: 0x0080,
0x2e12: 0x0080, 0x2e13: 0x0080, 0x2e14: 0x0080, 0x2e15: 0x0080, 0x2e16: 0x0080, 0x2e17: 0x0080,
0x2e1a: 0x0080, 0x2e1b: 0x0080, 0x2e1c: 0x0080,
0x2e20: 0x0080, 0x2e21: 0x0080, 0x2e22: 0x0080, 0x2e23: 0x0080,
0x2e24: 0x0080, 0x2e25: 0x0080, 0x2e26: 0x0080, 0x2e28: 0x0080, 0x2e29: 0x0080,
0x2e2a: 0x0080, 0x2e2b: 0x0080, 0x2e2c: 0x0080, 0x2e2d: 0x0080, 0x2e2e: 0x0080,
0x2e39: 0x0040, 0x2e3a: 0x0040, 0x2e3b: 0x0040,
0x2e3c: 0x0080, 0x2e3d: 0x0080,
// Block 0xb9, offset 0x2e40
0x2e40: 0x00c0, 0x2e41: 0x00c0, 0x2e42: 0x00c0, 0x2e43: 0x00c0, 0x2e44: 0x00c0, 0x2e45: 0x00c0,
0x2e46: 0x00c0, 0x2e47: 0x00c0, 0x2e48: 0x00c0, 0x2e49: 0x00c0, 0x2e4a: 0x00c0, 0x2e4b: 0x00c0,
0x2e4d: 0x00c0, 0x2e4e: 0x00c0, 0x2e4f: 0x00c0, 0x2e50: 0x00c0, 0x2e51: 0x00c0,
0x2e52: 0x00c0, 0x2e53: 0x00c0, 0x2e54: 0x00c0, 0x2e55: 0x00c0, 0x2e56: 0x00c0, 0x2e57: 0x00c0,
0x2e58: 0x00c0, 0x2e59: 0x00c0, 0x2e5a: 0x00c0, 0x2e5b: 0x00c0, 0x2e5c: 0x00c0, 0x2e5d: 0x00c0,
0x2e5e: 0x00c0, 0x2e5f: 0x00c0, 0x2e60: 0x00c0, 0x2e61: 0x00c0, 0x2e62: 0x00c0, 0x2e63: 0x00c0,
0x2e64: 0x00c0, 0x2e65: 0x00c0, 0x2e66: 0x00c0, 0x2e68: 0x00c0, 0x2e69: 0x00c0,
0x2e6a: 0x00c0, 0x2e6b: 0x00c0, 0x2e6c: 0x00c0, 0x2e6d: 0x00c0, 0x2e6e: 0x00c0, 0x2e6f: 0x00c0,
0x2e70: 0x00c0, 0x2e71: 0x00c0, 0x2e72: 0x00c0, 0x2e73: 0x00c0, 0x2e74: 0x00c0, 0x2e75: 0x00c0,
0x2e76: 0x00c0, 0x2e77: 0x00c0, 0x2e78: 0x00c0, 0x2e79: 0x00c0, 0x2e7a: 0x00c0,
0x2e7c: 0x00c0, 0x2e7d: 0x00c0, 0x2e7f: 0x00c0,
// Block 0xba, offset 0x2e80
0x2e80: 0x00c0, 0x2e81: 0x00c0, 0x2e82: 0x00c0, 0x2e83: 0x00c0, 0x2e84: 0x00c0, 0x2e85: 0x00c0,
0x2e86: 0x00c0, 0x2e87: 0x00c0, 0x2e88: 0x00c0, 0x2e89: 0x00c0, 0x2e8a: 0x00c0, 0x2e8b: 0x00c0,
0x2e8c: 0x00c0, 0x2e8d: 0x00c0, 0x2e90: 0x00c0, 0x2e91: 0x00c0,
0x2e92: 0x00c0, 0x2e93: 0x00c0, 0x2e94: 0x00c0, 0x2e95: 0x00c0, 0x2e96: 0x00c0, 0x2e97: 0x00c0,
0x2e98: 0x00c0, 0x2e99: 0x00c0, 0x2e9a: 0x00c0, 0x2e9b: 0x00c0, 0x2e9c: 0x00c0, 0x2e9d: 0x00c0,
// Block 0xbb, offset 0x2ec0
0x2ec0: 0x00c0, 0x2ec1: 0x00c0, 0x2ec2: 0x00c0, 0x2ec3: 0x00c0, 0x2ec4: 0x00c0, 0x2ec5: 0x00c0,
0x2ec6: 0x00c0, 0x2ec7: 0x00c0, 0x2ec8: 0x00c0, 0x2ec9: 0x00c0, 0x2eca: 0x00c0, 0x2ecb: 0x00c0,
0x2ecc: 0x00c0, 0x2ecd: 0x00c0, 0x2ece: 0x00c0, 0x2ecf: 0x00c0, 0x2ed0: 0x00c0, 0x2ed1: 0x00c0,
0x2ed2: 0x00c0, 0x2ed3: 0x00c0, 0x2ed4: 0x00c0, 0x2ed5: 0x00c0, 0x2ed6: 0x00c0, 0x2ed7: 0x00c0,
0x2ed8: 0x00c0, 0x2ed9: 0x00c0, 0x2eda: 0x00c0, 0x2edb: 0x00c0, 0x2edc: 0x00c0, 0x2edd: 0x00c0,
0x2ede: 0x00c0, 0x2edf: 0x00c0, 0x2ee0: 0x00c0, 0x2ee1: 0x00c0, 0x2ee2: 0x00c0, 0x2ee3: 0x00c0,
0x2ee4: 0x00c0, 0x2ee5: 0x00c0, 0x2ee6: 0x00c0, 0x2ee7: 0x00c0, 0x2ee8: 0x00c0, 0x2ee9: 0x00c0,
0x2eea: 0x00c0, 0x2eeb: 0x00c0, 0x2eec: 0x00c0, 0x2eed: 0x00c0, 0x2eee: 0x00c0, 0x2eef: 0x00c0,
0x2ef0: 0x00c0, 0x2ef1: 0x00c0, 0x2ef2: 0x00c0, 0x2ef3: 0x00c0, 0x2ef4: 0x00c0, 0x2ef5: 0x00c0,
0x2ef6: 0x00c0, 0x2ef7: 0x00c0, 0x2ef8: 0x00c0, 0x2ef9: 0x00c0, 0x2efa: 0x00c0,
// Block 0xbc, offset 0x2f00
0x2f00: 0x0080, 0x2f01: 0x0080, 0x2f02: 0x0080,
0x2f07: 0x0080, 0x2f08: 0x0080, 0x2f09: 0x0080, 0x2f0a: 0x0080, 0x2f0b: 0x0080,
0x2f0c: 0x0080, 0x2f0d: 0x0080, 0x2f0e: 0x0080, 0x2f0f: 0x0080, 0x2f10: 0x0080, 0x2f11: 0x0080,
0x2f12: 0x0080, 0x2f13: 0x0080, 0x2f14: 0x0080, 0x2f15: 0x0080, 0x2f16: 0x0080, 0x2f17: 0x0080,
0x2f18: 0x0080, 0x2f19: 0x0080, 0x2f1a: 0x0080, 0x2f1b: 0x0080, 0x2f1c: 0x0080, 0x2f1d: 0x0080,
0x2f1e: 0x0080, 0x2f1f: 0x0080, 0x2f20: 0x0080, 0x2f21: 0x0080, 0x2f22: 0x0080, 0x2f23: 0x0080,
0x2f24: 0x0080, 0x2f25: 0x0080, 0x2f26: 0x0080, 0x2f27: 0x0080, 0x2f28: 0x0080, 0x2f29: 0x0080,
0x2f2a: 0x0080, 0x2f2b: 0x0080, 0x2f2c: 0x0080, 0x2f2d: 0x0080, 0x2f2e: 0x0080, 0x2f2f: 0x0080,
0x2f30: 0x0080, 0x2f31: 0x0080, 0x2f32: 0x0080, 0x2f33: 0x0080,
0x2f37: 0x0080, 0x2f38: 0x0080, 0x2f39: 0x0080, 0x2f3a: 0x0080, 0x2f3b: 0x0080,
0x2f3c: 0x0080, 0x2f3d: 0x0080, 0x2f3e: 0x0080, 0x2f3f: 0x0080,
// Block 0xbd, offset 0x2f40
0x2f40: 0x0088, 0x2f41: 0x0088, 0x2f42: 0x0088, 0x2f43: 0x0088, 0x2f44: 0x0088, 0x2f45: 0x0088,
0x2f46: 0x0088, 0x2f47: 0x0088, 0x2f48: 0x0088, 0x2f49: 0x0088, 0x2f4a: 0x0088, 0x2f4b: 0x0088,
0x2f4c: 0x0088, 0x2f4d: 0x0088, 0x2f4e: 0x0088, 0x2f4f: 0x0088, 0x2f50: 0x0088, 0x2f51: 0x0088,
0x2f52: 0x0088, 0x2f53: 0x0088, 0x2f54: 0x0088, 0x2f55: 0x0088, 0x2f56: 0x0088, 0x2f57: 0x0088,
0x2f58: 0x0088, 0x2f59: 0x0088, 0x2f5a: 0x0088, 0x2f5b: 0x0088, 0x2f5c: 0x0088, 0x2f5d: 0x0088,
0x2f5e: 0x0088, 0x2f5f: 0x0088, 0x2f60: 0x0088, 0x2f61: 0x0088, 0x2f62: 0x0088, 0x2f63: 0x0088,
0x2f64: 0x0088, 0x2f65: 0x0088, 0x2f66: 0x0088, 0x2f67: 0x0088, 0x2f68: 0x0088, 0x2f69: 0x0088,
0x2f6a: 0x0088, 0x2f6b: 0x0088, 0x2f6c: 0x0088, 0x2f6d: 0x0088, 0x2f6e: 0x0088, 0x2f6f: 0x0088,
0x2f70: 0x0088, 0x2f71: 0x0088, 0x2f72: 0x0088, 0x2f73: 0x0088, 0x2f74: 0x0088, 0x2f75: 0x0088,
0x2f76: 0x0088, 0x2f77: 0x0088, 0x2f78: 0x0088, 0x2f79: 0x0088, 0x2f7a: 0x0088, 0x2f7b: 0x0088,
0x2f7c: 0x0088, 0x2f7d: 0x0088, 0x2f7e: 0x0088, 0x2f7f: 0x0088,
// Block 0xbe, offset 0x2f80
0x2f80: 0x0088, 0x2f81: 0x0088, 0x2f82: 0x0088, 0x2f83: 0x0088, 0x2f84: 0x0088, 0x2f85: 0x0088,
0x2f86: 0x0088, 0x2f87: 0x0088, 0x2f88: 0x0088, 0x2f89: 0x0088, 0x2f8a: 0x0088, 0x2f8b: 0x0088,
0x2f8c: 0x0088, 0x2f8d: 0x0088, 0x2f8e: 0x0088, 0x2f90: 0x0080, 0x2f91: 0x0080,
0x2f92: 0x0080, 0x2f93: 0x0080, 0x2f94: 0x0080, 0x2f95: 0x0080, 0x2f96: 0x0080, 0x2f97: 0x0080,
0x2f98: 0x0080, 0x2f99: 0x0080, 0x2f9a: 0x0080, 0x2f9b: 0x0080, 0x2f9c: 0x0080,
0x2fa0: 0x0088,
// Block 0xbf, offset 0x2fc0
0x2fd0: 0x0080, 0x2fd1: 0x0080,
0x2fd2: 0x0080, 0x2fd3: 0x0080, 0x2fd4: 0x0080, 0x2fd5: 0x0080, 0x2fd6: 0x0080, 0x2fd7: 0x0080,
0x2fd8: 0x0080, 0x2fd9: 0x0080, 0x2fda: 0x0080, 0x2fdb: 0x0080, 0x2fdc: 0x0080, 0x2fdd: 0x0080,
0x2fde: 0x0080, 0x2fdf: 0x0080, 0x2fe0: 0x0080, 0x2fe1: 0x0080, 0x2fe2: 0x0080, 0x2fe3: 0x0080,
0x2fe4: 0x0080, 0x2fe5: 0x0080, 0x2fe6: 0x0080, 0x2fe7: 0x0080, 0x2fe8: 0x0080, 0x2fe9: 0x0080,
0x2fea: 0x0080, 0x2feb: 0x0080, 0x2fec: 0x0080, 0x2fed: 0x0080, 0x2fee: 0x0080, 0x2fef: 0x0080,
0x2ff0: 0x0080, 0x2ff1: 0x0080, 0x2ff2: 0x0080, 0x2ff3: 0x0080, 0x2ff4: 0x0080, 0x2ff5: 0x0080,
0x2ff6: 0x0080, 0x2ff7: 0x0080, 0x2ff8: 0x0080, 0x2ff9: 0x0080, 0x2ffa: 0x0080, 0x2ffb: 0x0080,
0x2ffc: 0x0080, 0x2ffd: 0x00c3,
// Block 0xc0, offset 0x3000
0x3000: 0x00c0, 0x3001: 0x00c0, 0x3002: 0x00c0, 0x3003: 0x00c0, 0x3004: 0x00c0, 0x3005: 0x00c0,
0x3006: 0x00c0, 0x3007: 0x00c0, 0x3008: 0x00c0, 0x3009: 0x00c0, 0x300a: 0x00c0, 0x300b: 0x00c0,
0x300c: 0x00c0, 0x300d: 0x00c0, 0x300e: 0x00c0, 0x300f: 0x00c0, 0x3010: 0x00c0, 0x3011: 0x00c0,
0x3012: 0x00c0, 0x3013: 0x00c0, 0x3014: 0x00c0, 0x3015: 0x00c0, 0x3016: 0x00c0, 0x3017: 0x00c0,
0x3018: 0x00c0, 0x3019: 0x00c0, 0x301a: 0x00c0, 0x301b: 0x00c0, 0x301c: 0x00c0,
0x3020: 0x00c0, 0x3021: 0x00c0, 0x3022: 0x00c0, 0x3023: 0x00c0,
0x3024: 0x00c0, 0x3025: 0x00c0, 0x3026: 0x00c0, 0x3027: 0x00c0, 0x3028: 0x00c0, 0x3029: 0x00c0,
0x302a: 0x00c0, 0x302b: 0x00c0, 0x302c: 0x00c0, 0x302d: 0x00c0, 0x302e: 0x00c0, 0x302f: 0x00c0,
0x3030: 0x00c0, 0x3031: 0x00c0, 0x3032: 0x00c0, 0x3033: 0x00c0, 0x3034: 0x00c0, 0x3035: 0x00c0,
0x3036: 0x00c0, 0x3037: 0x00c0, 0x3038: 0x00c0, 0x3039: 0x00c0, 0x303a: 0x00c0, 0x303b: 0x00c0,
0x303c: 0x00c0, 0x303d: 0x00c0, 0x303e: 0x00c0, 0x303f: 0x00c0,
// Block 0xc1, offset 0x3040
0x3040: 0x00c0, 0x3041: 0x00c0, 0x3042: 0x00c0, 0x3043: 0x00c0, 0x3044: 0x00c0, 0x3045: 0x00c0,
0x3046: 0x00c0, 0x3047: 0x00c0, 0x3048: 0x00c0, 0x3049: 0x00c0, 0x304a: 0x00c0, 0x304b: 0x00c0,
0x304c: 0x00c0, 0x304d: 0x00c0, 0x304e: 0x00c0, 0x304f: 0x00c0, 0x3050: 0x00c0,
0x3060: 0x00c3, 0x3061: 0x0080, 0x3062: 0x0080, 0x3063: 0x0080,
0x3064: 0x0080, 0x3065: 0x0080, 0x3066: 0x0080, 0x3067: 0x0080, 0x3068: 0x0080, 0x3069: 0x0080,
0x306a: 0x0080, 0x306b: 0x0080, 0x306c: 0x0080, 0x306d: 0x0080, 0x306e: 0x0080, 0x306f: 0x0080,
0x3070: 0x0080, 0x3071: 0x0080, 0x3072: 0x0080, 0x3073: 0x0080, 0x3074: 0x0080, 0x3075: 0x0080,
0x3076: 0x0080, 0x3077: 0x0080, 0x3078: 0x0080, 0x3079: 0x0080, 0x307a: 0x0080, 0x307b: 0x0080,
// Block 0xc2, offset 0x3080
0x3080: 0x00c0, 0x3081: 0x00c0, 0x3082: 0x00c0, 0x3083: 0x00c0, 0x3084: 0x00c0, 0x3085: 0x00c0,
0x3086: 0x00c0, 0x3087: 0x00c0, 0x3088: 0x00c0, 0x3089: 0x00c0, 0x308a: 0x00c0, 0x308b: 0x00c0,
0x308c: 0x00c0, 0x308d: 0x00c0, 0x308e: 0x00c0, 0x308f: 0x00c0, 0x3090: 0x00c0, 0x3091: 0x00c0,
0x3092: 0x00c0, 0x3093: 0x00c0, 0x3094: 0x00c0, 0x3095: 0x00c0, 0x3096: 0x00c0, 0x3097: 0x00c0,
0x3098: 0x00c0, 0x3099: 0x00c0, 0x309a: 0x00c0, 0x309b: 0x00c0, 0x309c: 0x00c0, 0x309d: 0x00c0,
0x309e: 0x00c0, 0x309f: 0x00c0, 0x30a0: 0x0080, 0x30a1: 0x0080, 0x30a2: 0x0080, 0x30a3: 0x0080,
0x30ad: 0x00c0, 0x30ae: 0x00c0, 0x30af: 0x00c0,
0x30b0: 0x00c0, 0x30b1: 0x00c0, 0x30b2: 0x00c0, 0x30b3: 0x00c0, 0x30b4: 0x00c0, 0x30b5: 0x00c0,
0x30b6: 0x00c0, 0x30b7: 0x00c0, 0x30b8: 0x00c0, 0x30b9: 0x00c0, 0x30ba: 0x00c0, 0x30bb: 0x00c0,
0x30bc: 0x00c0, 0x30bd: 0x00c0, 0x30be: 0x00c0, 0x30bf: 0x00c0,
// Block 0xc3, offset 0x30c0
0x30c0: 0x00c0, 0x30c1: 0x0080, 0x30c2: 0x00c0, 0x30c3: 0x00c0, 0x30c4: 0x00c0, 0x30c5: 0x00c0,
0x30c6: 0x00c0, 0x30c7: 0x00c0, 0x30c8: 0x00c0, 0x30c9: 0x00c0, 0x30ca: 0x0080,
0x30d0: 0x00c0, 0x30d1: 0x00c0,
0x30d2: 0x00c0, 0x30d3: 0x00c0, 0x30d4: 0x00c0, 0x30d5: 0x00c0, 0x30d6: 0x00c0, 0x30d7: 0x00c0,
0x30d8: 0x00c0, 0x30d9: 0x00c0, 0x30da: 0x00c0, 0x30db: 0x00c0, 0x30dc: 0x00c0, 0x30dd: 0x00c0,
0x30de: 0x00c0, 0x30df: 0x00c0, 0x30e0: 0x00c0, 0x30e1: 0x00c0, 0x30e2: 0x00c0, 0x30e3: 0x00c0,
0x30e4: 0x00c0, 0x30e5: 0x00c0, 0x30e6: 0x00c0, 0x30e7: 0x00c0, 0x30e8: 0x00c0, 0x30e9: 0x00c0,
0x30ea: 0x00c0, 0x30eb: 0x00c0, 0x30ec: 0x00c0, 0x30ed: 0x00c0, 0x30ee: 0x00c0, 0x30ef: 0x00c0,
0x30f0: 0x00c0, 0x30f1: 0x00c0, 0x30f2: 0x00c0, 0x30f3: 0x00c0, 0x30f4: 0x00c0, 0x30f5: 0x00c0,
0x30f6: 0x00c3, 0x30f7: 0x00c3, 0x30f8: 0x00c3, 0x30f9: 0x00c3, 0x30fa: 0x00c3,
// Block 0xc4, offset 0x3100
0x3100: 0x00c0, 0x3101: 0x00c0, 0x3102: 0x00c0, 0x3103: 0x00c0, 0x3104: 0x00c0, 0x3105: 0x00c0,
0x3106: 0x00c0, 0x3107: 0x00c0, 0x3108: 0x00c0, 0x3109: 0x00c0, 0x310a: 0x00c0, 0x310b: 0x00c0,
0x310c: 0x00c0, 0x310d: 0x00c0, 0x310e: 0x00c0, 0x310f: 0x00c0, 0x3110: 0x00c0, 0x3111: 0x00c0,
0x3112: 0x00c0, 0x3113: 0x00c0, 0x3114: 0x00c0, 0x3115: 0x00c0, 0x3116: 0x00c0, 0x3117: 0x00c0,
0x3118: 0x00c0, 0x3119: 0x00c0, 0x311a: 0x00c0, 0x311b: 0x00c0, 0x311c: 0x00c0, 0x311d: 0x00c0,
0x311f: 0x0080, 0x3120: 0x00c0, 0x3121: 0x00c0, 0x3122: 0x00c0, 0x3123: 0x00c0,
0x3124: 0x00c0, 0x3125: 0x00c0, 0x3126: 0x00c0, 0x3127: 0x00c0, 0x3128: 0x00c0, 0x3129: 0x00c0,
0x312a: 0x00c0, 0x312b: 0x00c0, 0x312c: 0x00c0, 0x312d: 0x00c0, 0x312e: 0x00c0, 0x312f: 0x00c0,
0x3130: 0x00c0, 0x3131: 0x00c0, 0x3132: 0x00c0, 0x3133: 0x00c0, 0x3134: 0x00c0, 0x3135: 0x00c0,
0x3136: 0x00c0, 0x3137: 0x00c0, 0x3138: 0x00c0, 0x3139: 0x00c0, 0x313a: 0x00c0, 0x313b: 0x00c0,
0x313c: 0x00c0, 0x313d: 0x00c0, 0x313e: 0x00c0, 0x313f: 0x00c0,
// Block 0xc5, offset 0x3140
0x3140: 0x00c0, 0x3141: 0x00c0, 0x3142: 0x00c0, 0x3143: 0x00c0,
0x3148: 0x00c0, 0x3149: 0x00c0, 0x314a: 0x00c0, 0x314b: 0x00c0,
0x314c: 0x00c0, 0x314d: 0x00c0, 0x314e: 0x00c0, 0x314f: 0x00c0, 0x3150: 0x0080, 0x3151: 0x0080,
0x3152: 0x0080, 0x3153: 0x0080, 0x3154: 0x0080, 0x3155: 0x0080,
// Block 0xc6, offset 0x3180
0x3180: 0x00c0, 0x3181: 0x00c0, 0x3182: 0x00c0, 0x3183: 0x00c0, 0x3184: 0x00c0, 0x3185: 0x00c0,
0x3186: 0x00c0, 0x3187: 0x00c0, 0x3188: 0x00c0, 0x3189: 0x00c0, 0x318a: 0x00c0, 0x318b: 0x00c0,
0x318c: 0x00c0, 0x318d: 0x00c0, 0x318e: 0x00c0, 0x318f: 0x00c0, 0x3190: 0x00c0, 0x3191: 0x00c0,
0x3192: 0x00c0, 0x3193: 0x00c0, 0x3194: 0x00c0, 0x3195: 0x00c0, 0x3196: 0x00c0, 0x3197: 0x00c0,
0x3198: 0x00c0, 0x3199: 0x00c0, 0x319a: 0x00c0, 0x319b: 0x00c0, 0x319c: 0x00c0, 0x319d: 0x00c0,
0x31a0: 0x00c0, 0x31a1: 0x00c0, 0x31a2: 0x00c0, 0x31a3: 0x00c0,
0x31a4: 0x00c0, 0x31a5: 0x00c0, 0x31a6: 0x00c0, 0x31a7: 0x00c0, 0x31a8: 0x00c0, 0x31a9: 0x00c0,
0x31b0: 0x00c0, 0x31b1: 0x00c0, 0x31b2: 0x00c0, 0x31b3: 0x00c0, 0x31b4: 0x00c0, 0x31b5: 0x00c0,
0x31b6: 0x00c0, 0x31b7: 0x00c0, 0x31b8: 0x00c0, 0x31b9: 0x00c0, 0x31ba: 0x00c0, 0x31bb: 0x00c0,
0x31bc: 0x00c0, 0x31bd: 0x00c0, 0x31be: 0x00c0, 0x31bf: 0x00c0,
// Block 0xc7, offset 0x31c0
0x31c0: 0x00c0, 0x31c1: 0x00c0, 0x31c2: 0x00c0, 0x31c3: 0x00c0, 0x31c4: 0x00c0, 0x31c5: 0x00c0,
0x31c6: 0x00c0, 0x31c7: 0x00c0, 0x31c8: 0x00c0, 0x31c9: 0x00c0, 0x31ca: 0x00c0, 0x31cb: 0x00c0,
0x31cc: 0x00c0, 0x31cd: 0x00c0, 0x31ce: 0x00c0, 0x31cf: 0x00c0, 0x31d0: 0x00c0, 0x31d1: 0x00c0,
0x31d2: 0x00c0, 0x31d3: 0x00c0,
0x31d8: 0x00c0, 0x31d9: 0x00c0, 0x31da: 0x00c0, 0x31db: 0x00c0, 0x31dc: 0x00c0, 0x31dd: 0x00c0,
0x31de: 0x00c0, 0x31df: 0x00c0, 0x31e0: 0x00c0, 0x31e1: 0x00c0, 0x31e2: 0x00c0, 0x31e3: 0x00c0,
0x31e4: 0x00c0, 0x31e5: 0x00c0, 0x31e6: 0x00c0, 0x31e7: 0x00c0, 0x31e8: 0x00c0, 0x31e9: 0x00c0,
0x31ea: 0x00c0, 0x31eb: 0x00c0, 0x31ec: 0x00c0, 0x31ed: 0x00c0, 0x31ee: 0x00c0, 0x31ef: 0x00c0,
0x31f0: 0x00c0, 0x31f1: 0x00c0, 0x31f2: 0x00c0, 0x31f3: 0x00c0, 0x31f4: 0x00c0, 0x31f5: 0x00c0,
0x31f6: 0x00c0, 0x31f7: 0x00c0, 0x31f8: 0x00c0, 0x31f9: 0x00c0, 0x31fa: 0x00c0, 0x31fb: 0x00c0,
// Block 0xc8, offset 0x3200
0x3200: 0x00c0, 0x3201: 0x00c0, 0x3202: 0x00c0, 0x3203: 0x00c0, 0x3204: 0x00c0, 0x3205: 0x00c0,
0x3206: 0x00c0, 0x3207: 0x00c0, 0x3208: 0x00c0, 0x3209: 0x00c0, 0x320a: 0x00c0, 0x320b: 0x00c0,
0x320c: 0x00c0, 0x320d: 0x00c0, 0x320e: 0x00c0, 0x320f: 0x00c0, 0x3210: 0x00c0, 0x3211: 0x00c0,
0x3212: 0x00c0, 0x3213: 0x00c0, 0x3214: 0x00c0, 0x3215: 0x00c0, 0x3216: 0x00c0, 0x3217: 0x00c0,
0x3218: 0x00c0, 0x3219: 0x00c0, 0x321a: 0x00c0, 0x321b: 0x00c0, 0x321c: 0x00c0, 0x321d: 0x00c0,
0x321e: 0x00c0, 0x321f: 0x00c0, 0x3220: 0x00c0, 0x3221: 0x00c0, 0x3222: 0x00c0, 0x3223: 0x00c0,
0x3224: 0x00c0, 0x3225: 0x00c0, 0x3226: 0x00c0, 0x3227: 0x00c0,
0x3230: 0x00c0, 0x3231: 0x00c0, 0x3232: 0x00c0, 0x3233: 0x00c0, 0x3234: 0x00c0, 0x3235: 0x00c0,
0x3236: 0x00c0, 0x3237: 0x00c0, 0x3238: 0x00c0, 0x3239: 0x00c0, 0x323a: 0x00c0, 0x323b: 0x00c0,
0x323c: 0x00c0, 0x323d: 0x00c0, 0x323e: 0x00c0, 0x323f: 0x00c0,
// Block 0xc9, offset 0x3240
0x3240: 0x00c0, 0x3241: 0x00c0, 0x3242: 0x00c0, 0x3243: 0x00c0, 0x3244: 0x00c0, 0x3245: 0x00c0,
0x3246: 0x00c0, 0x3247: 0x00c0, 0x3248: 0x00c0, 0x3249: 0x00c0, 0x324a: 0x00c0, 0x324b: 0x00c0,
0x324c: 0x00c0, 0x324d: 0x00c0, 0x324e: 0x00c0, 0x324f: 0x00c0, 0x3250: 0x00c0, 0x3251: 0x00c0,
0x3252: 0x00c0, 0x3253: 0x00c0, 0x3254: 0x00c0, 0x3255: 0x00c0, 0x3256: 0x00c0, 0x3257: 0x00c0,
0x3258: 0x00c0, 0x3259: 0x00c0, 0x325a: 0x00c0, 0x325b: 0x00c0, 0x325c: 0x00c0, 0x325d: 0x00c0,
0x325e: 0x00c0, 0x325f: 0x00c0, 0x3260: 0x00c0, 0x3261: 0x00c0, 0x3262: 0x00c0, 0x3263: 0x00c0,
0x326f: 0x0080,
0x3270: 0x00c0, 0x3271: 0x00c0, 0x3272: 0x00c0, 0x3273: 0x00c0, 0x3274: 0x00c0, 0x3275: 0x00c0,
0x3276: 0x00c0, 0x3277: 0x00c0, 0x3278: 0x00c0, 0x3279: 0x00c0, 0x327a: 0x00c0,
0x327c: 0x00c0, 0x327d: 0x00c0, 0x327e: 0x00c0, 0x327f: 0x00c0,
// Block 0xca, offset 0x3280
0x3280: 0x00c0, 0x3281: 0x00c0, 0x3282: 0x00c0, 0x3283: 0x00c0, 0x3284: 0x00c0, 0x3285: 0x00c0,
0x3286: 0x00c0, 0x3287: 0x00c0, 0x3288: 0x00c0, 0x3289: 0x00c0, 0x328a: 0x00c0,
0x328c: 0x00c0, 0x328d: 0x00c0, 0x328e: 0x00c0, 0x328f: 0x00c0, 0x3290: 0x00c0, 0x3291: 0x00c0,
0x3292: 0x00c0, 0x3294: 0x00c0, 0x3295: 0x00c0, 0x3297: 0x00c0,
0x3298: 0x00c0, 0x3299: 0x00c0, 0x329a: 0x00c0, 0x329b: 0x00c0, 0x329c: 0x00c0, 0x329d: 0x00c0,
0x329e: 0x00c0, 0x329f: 0x00c0, 0x32a0: 0x00c0, 0x32a1: 0x00c0, 0x32a3: 0x00c0,
0x32a4: 0x00c0, 0x32a5: 0x00c0, 0x32a6: 0x00c0, 0x32a7: 0x00c0, 0x32a8: 0x00c0, 0x32a9: 0x00c0,
0x32aa: 0x00c0, 0x32ab: 0x00c0, 0x32ac: 0x00c0, 0x32ad: 0x00c0, 0x32ae: 0x00c0, 0x32af: 0x00c0,
0x32b0: 0x00c0, 0x32b1: 0x00c0, 0x32b3: 0x00c0, 0x32b4: 0x00c0, 0x32b5: 0x00c0,
0x32b6: 0x00c0, 0x32b7: 0x00c0, 0x32b8: 0x00c0, 0x32b9: 0x00c0, 0x32bb: 0x00c0,
0x32bc: 0x00c0,
// Block 0xcb, offset 0x32c0
0x32c0: 0x00c0, 0x32c1: 0x00c0, 0x32c2: 0x00c0, 0x32c3: 0x00c0, 0x32c4: 0x00c0, 0x32c5: 0x00c0,
0x32c6: 0x00c0, 0x32c7: 0x00c0, 0x32c8: 0x00c0, 0x32c9: 0x00c0, 0x32ca: 0x00c0, 0x32cb: 0x00c0,
0x32cc: 0x00c0, 0x32cd: 0x00c0, 0x32ce: 0x00c0, 0x32cf: 0x00c0, 0x32d0: 0x00c0, 0x32d1: 0x00c0,
0x32d2: 0x00c0, 0x32d3: 0x00c0, 0x32d4: 0x00c0, 0x32d5: 0x00c0, 0x32d6: 0x00c0, 0x32d7: 0x00c0,
0x32d8: 0x00c0, 0x32d9: 0x00c0, 0x32da: 0x00c0, 0x32db: 0x00c0, 0x32dc: 0x00c0, 0x32dd: 0x00c0,
0x32de: 0x00c0, 0x32df: 0x00c0, 0x32e0: 0x00c0, 0x32e1: 0x00c0, 0x32e2: 0x00c0, 0x32e3: 0x00c0,
0x32e4: 0x00c0, 0x32e5: 0x00c0, 0x32e6: 0x00c0, 0x32e7: 0x00c0, 0x32e8: 0x00c0, 0x32e9: 0x00c0,
0x32ea: 0x00c0, 0x32eb: 0x00c0, 0x32ec: 0x00c0, 0x32ed: 0x00c0, 0x32ee: 0x00c0, 0x32ef: 0x00c0,
0x32f0: 0x00c0, 0x32f1: 0x00c0, 0x32f2: 0x00c0, 0x32f3: 0x00c0, 0x32f4: 0x00c0, 0x32f5: 0x00c0,
0x32f6: 0x00c0,
// Block 0xcc, offset 0x3300
0x3300: 0x00c0, 0x3301: 0x00c0, 0x3302: 0x00c0, 0x3303: 0x00c0, 0x3304: 0x00c0, 0x3305: 0x00c0,
0x3306: 0x00c0, 0x3307: 0x00c0, 0x3308: 0x00c0, 0x3309: 0x00c0, 0x330a: 0x00c0, 0x330b: 0x00c0,
0x330c: 0x00c0, 0x330d: 0x00c0, 0x330e: 0x00c0, 0x330f: 0x00c0, 0x3310: 0x00c0, 0x3311: 0x00c0,
0x3312: 0x00c0, 0x3313: 0x00c0, 0x3314: 0x00c0, 0x3315: 0x00c0,
0x3320: 0x00c0, 0x3321: 0x00c0, 0x3322: 0x00c0, 0x3323: 0x00c0,
0x3324: 0x00c0, 0x3325: 0x00c0, 0x3326: 0x00c0, 0x3327: 0x00c0,
// Block 0xcd, offset 0x3340
0x3340: 0x00c0, 0x3341: 0x0080, 0x3342: 0x0080, 0x3343: 0x0080, 0x3344: 0x0080, 0x3345: 0x0080,
0x3347: 0x0080, 0x3348: 0x0080, 0x3349: 0x0080, 0x334a: 0x0080, 0x334b: 0x0080,
0x334c: 0x0080, 0x334d: 0x0080, 0x334e: 0x0080, 0x334f: 0x0080, 0x3350: 0x0080, 0x3351: 0x0080,
0x3352: 0x0080, 0x3353: 0x0080, 0x3354: 0x0080, 0x3355: 0x0080, 0x3356: 0x0080, 0x3357: 0x0080,
0x3358: 0x0080, 0x3359: 0x0080, 0x335a: 0x0080, 0x335b: 0x0080, 0x335c: 0x0080, 0x335d: 0x0080,
0x335e: 0x0080, 0x335f: 0x0080, 0x3360: 0x0080, 0x3361: 0x0080, 0x3362: 0x0080, 0x3363: 0x0080,
0x3364: 0x0080, 0x3365: 0x0080, 0x3366: 0x0080, 0x3367: 0x0080, 0x3368: 0x0080, 0x3369: 0x0080,
0x336a: 0x0080, 0x336b: 0x0080, 0x336c: 0x0080, 0x336d: 0x0080, 0x336e: 0x0080, 0x336f: 0x0080,
0x3370: 0x0080, 0x3372: 0x0080, 0x3373: 0x0080, 0x3374: 0x0080, 0x3375: 0x0080,
0x3376: 0x0080, 0x3377: 0x0080, 0x3378: 0x0080, 0x3379: 0x0080, 0x337a: 0x0080,
// Block 0xce, offset 0x3380
0x3380: 0x00c0, 0x3381: 0x00c0, 0x3382: 0x00c0, 0x3383: 0x00c0, 0x3384: 0x00c0, 0x3385: 0x00c0,
0x3388: 0x00c0, 0x338a: 0x00c0, 0x338b: 0x00c0,
0x338c: 0x00c0, 0x338d: 0x00c0, 0x338e: 0x00c0, 0x338f: 0x00c0, 0x3390: 0x00c0, 0x3391: 0x00c0,
0x3392: 0x00c0, 0x3393: 0x00c0, 0x3394: 0x00c0, 0x3395: 0x00c0, 0x3396: 0x00c0, 0x3397: 0x00c0,
0x3398: 0x00c0, 0x3399: 0x00c0, 0x339a: 0x00c0, 0x339b: 0x00c0, 0x339c: 0x00c0, 0x339d: 0x00c0,
0x339e: 0x00c0, 0x339f: 0x00c0, 0x33a0: 0x00c0, 0x33a1: 0x00c0, 0x33a2: 0x00c0, 0x33a3: 0x00c0,
0x33a4: 0x00c0, 0x33a5: 0x00c0, 0x33a6: 0x00c0, 0x33a7: 0x00c0, 0x33a8: 0x00c0, 0x33a9: 0x00c0,
0x33aa: 0x00c0, 0x33ab: 0x00c0, 0x33ac: 0x00c0, 0x33ad: 0x00c0, 0x33ae: 0x00c0, 0x33af: 0x00c0,
0x33b0: 0x00c0, 0x33b1: 0x00c0, 0x33b2: 0x00c0, 0x33b3: 0x00c0, 0x33b4: 0x00c0, 0x33b5: 0x00c0,
0x33b7: 0x00c0, 0x33b8: 0x00c0,
0x33bc: 0x00c0, 0x33bf: 0x00c0,
// Block 0xcf, offset 0x33c0
0x33c0: 0x00c0, 0x33c1: 0x00c0, 0x33c2: 0x00c0, 0x33c3: 0x00c0, 0x33c4: 0x00c0, 0x33c5: 0x00c0,
0x33c6: 0x00c0, 0x33c7: 0x00c0, 0x33c8: 0x00c0, 0x33c9: 0x00c0, 0x33ca: 0x00c0, 0x33cb: 0x00c0,
0x33cc: 0x00c0, 0x33cd: 0x00c0, 0x33ce: 0x00c0, 0x33cf: 0x00c0, 0x33d0: 0x00c0, 0x33d1: 0x00c0,
0x33d2: 0x00c0, 0x33d3: 0x00c0, 0x33d4: 0x00c0, 0x33d5: 0x00c0, 0x33d7: 0x0080,
0x33d8: 0x0080, 0x33d9: 0x0080, 0x33da: 0x0080, 0x33db: 0x0080, 0x33dc: 0x0080, 0x33dd: 0x0080,
0x33de: 0x0080, 0x33df: 0x0080, 0x33e0: 0x00c0, 0x33e1: 0x00c0, 0x33e2: 0x00c0, 0x33e3: 0x00c0,
0x33e4: 0x00c0, 0x33e5: 0x00c0, 0x33e6: 0x00c0, 0x33e7: 0x00c0, 0x33e8: 0x00c0, 0x33e9: 0x00c0,
0x33ea: 0x00c0, 0x33eb: 0x00c0, 0x33ec: 0x00c0, 0x33ed: 0x00c0, 0x33ee: 0x00c0, 0x33ef: 0x00c0,
0x33f0: 0x00c0, 0x33f1: 0x00c0, 0x33f2: 0x00c0, 0x33f3: 0x00c0, 0x33f4: 0x00c0, 0x33f5: 0x00c0,
0x33f6: 0x00c0, 0x33f7: 0x0080, 0x33f8: 0x0080, 0x33f9: 0x0080, 0x33fa: 0x0080, 0x33fb: 0x0080,
0x33fc: 0x0080, 0x33fd: 0x0080, 0x33fe: 0x0080, 0x33ff: 0x0080,
// Block 0xd0, offset 0x3400
0x3400: 0x00c0, 0x3401: 0x00c0, 0x3402: 0x00c0, 0x3403: 0x00c0, 0x3404: 0x00c0, 0x3405: 0x00c0,
0x3406: 0x00c0, 0x3407: 0x00c0, 0x3408: 0x00c0, 0x3409: 0x00c0, 0x340a: 0x00c0, 0x340b: 0x00c0,
0x340c: 0x00c0, 0x340d: 0x00c0, 0x340e: 0x00c0, 0x340f: 0x00c0, 0x3410: 0x00c0, 0x3411: 0x00c0,
0x3412: 0x00c0, 0x3413: 0x00c0, 0x3414: 0x00c0, 0x3415: 0x00c0, 0x3416: 0x00c0, 0x3417: 0x00c0,
0x3418: 0x00c0, 0x3419: 0x00c0, 0x341a: 0x00c0, 0x341b: 0x00c0, 0x341c: 0x00c0, 0x341d: 0x00c0,
0x341e: 0x00c0,
0x3427: 0x0080, 0x3428: 0x0080, 0x3429: 0x0080,
0x342a: 0x0080, 0x342b: 0x0080, 0x342c: 0x0080, 0x342d: 0x0080, 0x342e: 0x0080, 0x342f: 0x0080,
// Block 0xd1, offset 0x3440
0x3460: 0x00c0, 0x3461: 0x00c0, 0x3462: 0x00c0, 0x3463: 0x00c0,
0x3464: 0x00c0, 0x3465: 0x00c0, 0x3466: 0x00c0, 0x3467: 0x00c0, 0x3468: 0x00c0, 0x3469: 0x00c0,
0x346a: 0x00c0, 0x346b: 0x00c0, 0x346c: 0x00c0, 0x346d: 0x00c0, 0x346e: 0x00c0, 0x346f: 0x00c0,
0x3470: 0x00c0, 0x3471: 0x00c0, 0x3472: 0x00c0, 0x3474: 0x00c0, 0x3475: 0x00c0,
0x347b: 0x0080,
0x347c: 0x0080, 0x347d: 0x0080, 0x347e: 0x0080, 0x347f: 0x0080,
// Block 0xd2, offset 0x3480
0x3480: 0x00c0, 0x3481: 0x00c0, 0x3482: 0x00c0, 0x3483: 0x00c0, 0x3484: 0x00c0, 0x3485: 0x00c0,
0x3486: 0x00c0, 0x3487: 0x00c0, 0x3488: 0x00c0, 0x3489: 0x00c0, 0x348a: 0x00c0, 0x348b: 0x00c0,
0x348c: 0x00c0, 0x348d: 0x00c0, 0x348e: 0x00c0, 0x348f: 0x00c0, 0x3490: 0x00c0, 0x3491: 0x00c0,
0x3492: 0x00c0, 0x3493: 0x00c0, 0x3494: 0x00c0, 0x3495: 0x00c0, 0x3496: 0x0080, 0x3497: 0x0080,
0x3498: 0x0080, 0x3499: 0x0080, 0x349a: 0x0080, 0x349b: 0x0080,
0x349f: 0x0080, 0x34a0: 0x00c0, 0x34a1: 0x00c0, 0x34a2: 0x00c0, 0x34a3: 0x00c0,
0x34a4: 0x00c0, 0x34a5: 0x00c0, 0x34a6: 0x00c0, 0x34a7: 0x00c0, 0x34a8: 0x00c0, 0x34a9: 0x00c0,
0x34aa: 0x00c0, 0x34ab: 0x00c0, 0x34ac: 0x00c0, 0x34ad: 0x00c0, 0x34ae: 0x00c0, 0x34af: 0x00c0,
0x34b0: 0x00c0, 0x34b1: 0x00c0, 0x34b2: 0x00c0, 0x34b3: 0x00c0, 0x34b4: 0x00c0, 0x34b5: 0x00c0,
0x34b6: 0x00c0, 0x34b7: 0x00c0, 0x34b8: 0x00c0, 0x34b9: 0x00c0,
0x34bf: 0x0080,
// Block 0xd3, offset 0x34c0
0x34c0: 0x00c0, 0x34c1: 0x00c0, 0x34c2: 0x00c0, 0x34c3: 0x00c0, 0x34c4: 0x00c0, 0x34c5: 0x00c0,
0x34c6: 0x00c0, 0x34c7: 0x00c0, 0x34c8: 0x00c0, 0x34c9: 0x00c0, 0x34ca: 0x00c0, 0x34cb: 0x00c0,
0x34cc: 0x00c0, 0x34cd: 0x00c0, 0x34ce: 0x00c0, 0x34cf: 0x00c0, 0x34d0: 0x00c0, 0x34d1: 0x00c0,
0x34d2: 0x00c0, 0x34d3: 0x00c0, 0x34d4: 0x00c0, 0x34d5: 0x00c0, 0x34d6: 0x00c0, 0x34d7: 0x00c0,
0x34d8: 0x00c0, 0x34d9: 0x00c0, 0x34da: 0x00c0, 0x34db: 0x00c0, 0x34dc: 0x00c0, 0x34dd: 0x00c0,
0x34de: 0x00c0, 0x34df: 0x00c0, 0x34e0: 0x00c0, 0x34e1: 0x00c0, 0x34e2: 0x00c0, 0x34e3: 0x00c0,
0x34e4: 0x00c0, 0x34e5: 0x00c0, 0x34e6: 0x00c0, 0x34e7: 0x00c0, 0x34e8: 0x00c0, 0x34e9: 0x00c0,
0x34ea: 0x00c0, 0x34eb: 0x00c0, 0x34ec: 0x00c0, 0x34ed: 0x00c0, 0x34ee: 0x00c0, 0x34ef: 0x00c0,
0x34f0: 0x00c0, 0x34f1: 0x00c0, 0x34f2: 0x00c0, 0x34f3: 0x00c0, 0x34f4: 0x00c0, 0x34f5: 0x00c0,
0x34f6: 0x00c0, 0x34f7: 0x00c0,
0x34fc: 0x0080, 0x34fd: 0x0080, 0x34fe: 0x00c0, 0x34ff: 0x00c0,
// Block 0xd4, offset 0x3500
0x3500: 0x00c0, 0x3501: 0x00c3, 0x3502: 0x00c3, 0x3503: 0x00c3, 0x3505: 0x00c3,
0x3506: 0x00c3,
0x350c: 0x00c3, 0x350d: 0x00c3, 0x350e: 0x00c3, 0x350f: 0x00c3, 0x3510: 0x00c0, 0x3511: 0x00c0,
0x3512: 0x00c0, 0x3513: 0x00c0, 0x3515: 0x00c0, 0x3516: 0x00c0, 0x3517: 0x00c0,
0x3519: 0x00c0, 0x351a: 0x00c0, 0x351b: 0x00c0, 0x351c: 0x00c0, 0x351d: 0x00c0,
0x351e: 0x00c0, 0x351f: 0x00c0, 0x3520: 0x00c0, 0x3521: 0x00c0, 0x3522: 0x00c0, 0x3523: 0x00c0,
0x3524: 0x00c0, 0x3525: 0x00c0, 0x3526: 0x00c0, 0x3527: 0x00c0, 0x3528: 0x00c0, 0x3529: 0x00c0,
0x352a: 0x00c0, 0x352b: 0x00c0, 0x352c: 0x00c0, 0x352d: 0x00c0, 0x352e: 0x00c0, 0x352f: 0x00c0,
0x3530: 0x00c0, 0x3531: 0x00c0, 0x3532: 0x00c0, 0x3533: 0x00c0, 0x3534: 0x00c0, 0x3535: 0x00c0,
0x3538: 0x00c3, 0x3539: 0x00c3, 0x353a: 0x00c3,
0x353f: 0x00c6,
// Block 0xd5, offset 0x3540
0x3540: 0x0080, 0x3541: 0x0080, 0x3542: 0x0080, 0x3543: 0x0080, 0x3544: 0x0080, 0x3545: 0x0080,
0x3546: 0x0080, 0x3547: 0x0080, 0x3548: 0x0080,
0x3550: 0x0080, 0x3551: 0x0080,
0x3552: 0x0080, 0x3553: 0x0080, 0x3554: 0x0080, 0x3555: 0x0080, 0x3556: 0x0080, 0x3557: 0x0080,
0x3558: 0x0080,
0x3560: 0x00c0, 0x3561: 0x00c0, 0x3562: 0x00c0, 0x3563: 0x00c0,
0x3564: 0x00c0, 0x3565: 0x00c0, 0x3566: 0x00c0, 0x3567: 0x00c0, 0x3568: 0x00c0, 0x3569: 0x00c0,
0x356a: 0x00c0, 0x356b: 0x00c0, 0x356c: 0x00c0, 0x356d: 0x00c0, 0x356e: 0x00c0, 0x356f: 0x00c0,
0x3570: 0x00c0, 0x3571: 0x00c0, 0x3572: 0x00c0, 0x3573: 0x00c0, 0x3574: 0x00c0, 0x3575: 0x00c0,
0x3576: 0x00c0, 0x3577: 0x00c0, 0x3578: 0x00c0, 0x3579: 0x00c0, 0x357a: 0x00c0, 0x357b: 0x00c0,
0x357c: 0x00c0, 0x357d: 0x0080, 0x357e: 0x0080, 0x357f: 0x0080,
// Block 0xd6, offset 0x3580
0x3580: 0x00c0, 0x3581: 0x00c0, 0x3582: 0x00c0, 0x3583: 0x00c0, 0x3584: 0x00c0, 0x3585: 0x00c0,
0x3586: 0x00c0, 0x3587: 0x00c0, 0x3588: 0x00c0, 0x3589: 0x00c0, 0x358a: 0x00c0, 0x358b: 0x00c0,
0x358c: 0x00c0, 0x358d: 0x00c0, 0x358e: 0x00c0, 0x358f: 0x00c0, 0x3590: 0x00c0, 0x3591: 0x00c0,
0x3592: 0x00c0, 0x3593: 0x00c0, 0x3594: 0x00c0, 0x3595: 0x00c0, 0x3596: 0x00c0, 0x3597: 0x00c0,
0x3598: 0x00c0, 0x3599: 0x00c0, 0x359a: 0x00c0, 0x359b: 0x00c0, 0x359c: 0x00c0, 0x359d: 0x0080,
0x359e: 0x0080, 0x359f: 0x0080,
// Block 0xd7, offset 0x35c0
0x35c0: 0x00c2, 0x35c1: 0x00c2, 0x35c2: 0x00c2, 0x35c3: 0x00c2, 0x35c4: 0x00c2, 0x35c5: 0x00c4,
0x35c6: 0x00c0, 0x35c7: 0x00c4, 0x35c8: 0x0080, 0x35c9: 0x00c4, 0x35ca: 0x00c4, 0x35cb: 0x00c0,
0x35cc: 0x00c0, 0x35cd: 0x00c1, 0x35ce: 0x00c4, 0x35cf: 0x00c4, 0x35d0: 0x00c4, 0x35d1: 0x00c4,
0x35d2: 0x00c4, 0x35d3: 0x00c2, 0x35d4: 0x00c2, 0x35d5: 0x00c2, 0x35d6: 0x00c2, 0x35d7: 0x00c1,
0x35d8: 0x00c2, 0x35d9: 0x00c2, 0x35da: 0x00c2, 0x35db: 0x00c2, 0x35dc: 0x00c2, 0x35dd: 0x00c4,
0x35de: 0x00c2, 0x35df: 0x00c2, 0x35e0: 0x00c2, 0x35e1: 0x00c4, 0x35e2: 0x00c0, 0x35e3: 0x00c0,
0x35e4: 0x00c4, 0x35e5: 0x00c3, 0x35e6: 0x00c3,
0x35eb: 0x0082, 0x35ec: 0x0082, 0x35ed: 0x0082, 0x35ee: 0x0082, 0x35ef: 0x0084,
0x35f0: 0x0080, 0x35f1: 0x0080, 0x35f2: 0x0080, 0x35f3: 0x0080, 0x35f4: 0x0080, 0x35f5: 0x0080,
0x35f6: 0x0080,
// Block 0xd8, offset 0x3600
0x3600: 0x00c0, 0x3601: 0x00c0, 0x3602: 0x00c0, 0x3603: 0x00c0, 0x3604: 0x00c0, 0x3605: 0x00c0,
0x3606: 0x00c0, 0x3607: 0x00c0, 0x3608: 0x00c0, 0x3609: 0x00c0, 0x360a: 0x00c0, 0x360b: 0x00c0,
0x360c: 0x00c0, 0x360d: 0x00c0, 0x360e: 0x00c0, 0x360f: 0x00c0, 0x3610: 0x00c0, 0x3611: 0x00c0,
0x3612: 0x00c0, 0x3613: 0x00c0, 0x3614: 0x00c0, 0x3615: 0x00c0, 0x3616: 0x00c0, 0x3617: 0x00c0,
0x3618: 0x00c0, 0x3619: 0x00c0, 0x361a: 0x00c0, 0x361b: 0x00c0, 0x361c: 0x00c0, 0x361d: 0x00c0,
0x361e: 0x00c0, 0x361f: 0x00c0, 0x3620: 0x00c0, 0x3621: 0x00c0, 0x3622: 0x00c0, 0x3623: 0x00c0,
0x3624: 0x00c0, 0x3625: 0x00c0, 0x3626: 0x00c0, 0x3627: 0x00c0, 0x3628: 0x00c0, 0x3629: 0x00c0,
0x362a: 0x00c0, 0x362b: 0x00c0, 0x362c: 0x00c0, 0x362d: 0x00c0, 0x362e: 0x00c0, 0x362f: 0x00c0,
0x3630: 0x00c0, 0x3631: 0x00c0, 0x3632: 0x00c0, 0x3633: 0x00c0, 0x3634: 0x00c0, 0x3635: 0x00c0,
0x3639: 0x0080, 0x363a: 0x0080, 0x363b: 0x0080,
0x363c: 0x0080, 0x363d: 0x0080, 0x363e: 0x0080, 0x363f: 0x0080,
// Block 0xd9, offset 0x3640
0x3640: 0x00c0, 0x3641: 0x00c0, 0x3642: 0x00c0, 0x3643: 0x00c0, 0x3644: 0x00c0, 0x3645: 0x00c0,
0x3646: 0x00c0, 0x3647: 0x00c0, 0x3648: 0x00c0, 0x3649: 0x00c0, 0x364a: 0x00c0, 0x364b: 0x00c0,
0x364c: 0x00c0, 0x364d: 0x00c0, 0x364e: 0x00c0, 0x364f: 0x00c0, 0x3650: 0x00c0, 0x3651: 0x00c0,
0x3652: 0x00c0, 0x3653: 0x00c0, 0x3654: 0x00c0, 0x3655: 0x00c0,
0x3658: 0x0080, 0x3659: 0x0080, 0x365a: 0x0080, 0x365b: 0x0080, 0x365c: 0x0080, 0x365d: 0x0080,
0x365e: 0x0080, 0x365f: 0x0080, 0x3660: 0x00c0, 0x3661: 0x00c0, 0x3662: 0x00c0, 0x3663: 0x00c0,
0x3664: 0x00c0, 0x3665: 0x00c0, 0x3666: 0x00c0, 0x3667: 0x00c0, 0x3668: 0x00c0, 0x3669: 0x00c0,
0x366a: 0x00c0, 0x366b: 0x00c0, 0x366c: 0x00c0, 0x366d: 0x00c0, 0x366e: 0x00c0, 0x366f: 0x00c0,
0x3670: 0x00c0, 0x3671: 0x00c0, 0x3672: 0x00c0,
0x3678: 0x0080, 0x3679: 0x0080, 0x367a: 0x0080, 0x367b: 0x0080,
0x367c: 0x0080, 0x367d: 0x0080, 0x367e: 0x0080, 0x367f: 0x0080,
// Block 0xda, offset 0x3680
0x3680: 0x00c2, 0x3681: 0x00c4, 0x3682: 0x00c2, 0x3683: 0x00c4, 0x3684: 0x00c4, 0x3685: 0x00c4,
0x3686: 0x00c2, 0x3687: 0x00c2, 0x3688: 0x00c2, 0x3689: 0x00c4, 0x368a: 0x00c2, 0x368b: 0x00c2,
0x368c: 0x00c4, 0x368d: 0x00c2, 0x368e: 0x00c4, 0x368f: 0x00c4, 0x3690: 0x00c2, 0x3691: 0x00c4,
0x3699: 0x0080, 0x369a: 0x0080, 0x369b: 0x0080, 0x369c: 0x0080,
0x36a9: 0x0084,
0x36aa: 0x0084, 0x36ab: 0x0084, 0x36ac: 0x0084, 0x36ad: 0x0082, 0x36ae: 0x0082, 0x36af: 0x0080,
// Block 0xdb, offset 0x36c0
0x36c0: 0x00c0, 0x36c1: 0x00c0, 0x36c2: 0x00c0, 0x36c3: 0x00c0, 0x36c4: 0x00c0, 0x36c5: 0x00c0,
0x36c6: 0x00c0, 0x36c7: 0x00c0, 0x36c8: 0x00c0,
// Block 0xdc, offset 0x3700
0x3700: 0x00c0, 0x3701: 0x00c0, 0x3702: 0x00c0, 0x3703: 0x00c0, 0x3704: 0x00c0, 0x3705: 0x00c0,
0x3706: 0x00c0, 0x3707: 0x00c0, 0x3708: 0x00c0, 0x3709: 0x00c0, 0x370a: 0x00c0, 0x370b: 0x00c0,
0x370c: 0x00c0, 0x370d: 0x00c0, 0x370e: 0x00c0, 0x370f: 0x00c0, 0x3710: 0x00c0, 0x3711: 0x00c0,
0x3712: 0x00c0, 0x3713: 0x00c0, 0x3714: 0x00c0, 0x3715: 0x00c0, 0x3716: 0x00c0, 0x3717: 0x00c0,
0x3718: 0x00c0, 0x3719: 0x00c0, 0x371a: 0x00c0, 0x371b: 0x00c0, 0x371c: 0x00c0, 0x371d: 0x00c0,
0x371e: 0x00c0, 0x371f: 0x00c0, 0x3720: 0x00c0, 0x3721: 0x00c0, 0x3722: 0x00c0, 0x3723: 0x00c0,
0x3724: 0x00c0, 0x3725: 0x00c0, 0x3726: 0x00c0, 0x3727: 0x00c0, 0x3728: 0x00c0, 0x3729: 0x00c0,
0x372a: 0x00c0, 0x372b: 0x00c0, 0x372c: 0x00c0, 0x372d: 0x00c0, 0x372e: 0x00c0, 0x372f: 0x00c0,
0x3730: 0x00c0, 0x3731: 0x00c0, 0x3732: 0x00c0,
// Block 0xdd, offset 0x3740
0x3740: 0x00c0, 0x3741: 0x00c0, 0x3742: 0x00c0, 0x3743: 0x00c0, 0x3744: 0x00c0, 0x3745: 0x00c0,
0x3746: 0x00c0, 0x3747: 0x00c0, 0x3748: 0x00c0, 0x3749: 0x00c0, 0x374a: 0x00c0, 0x374b: 0x00c0,
0x374c: 0x00c0, 0x374d: 0x00c0, 0x374e: 0x00c0, 0x374f: 0x00c0, 0x3750: 0x00c0, 0x3751: 0x00c0,
0x3752: 0x00c0, 0x3753: 0x00c0, 0x3754: 0x00c0, 0x3755: 0x00c0, 0x3756: 0x00c0, 0x3757: 0x00c0,
0x3758: 0x00c0, 0x3759: 0x00c0, 0x375a: 0x00c0, 0x375b: 0x00c0, 0x375c: 0x00c0, 0x375d: 0x00c0,
0x375e: 0x00c0, 0x375f: 0x00c0, 0x3760: 0x00c0, 0x3761: 0x00c0, 0x3762: 0x00c0, 0x3763: 0x00c0,
0x3764: 0x00c0, 0x3765: 0x00c0, 0x3766: 0x00c0, 0x3767: 0x00c0, 0x3768: 0x00c0, 0x3769: 0x00c0,
0x376a: 0x00c0, 0x376b: 0x00c0, 0x376c: 0x00c0, 0x376d: 0x00c0, 0x376e: 0x00c0, 0x376f: 0x00c0,
0x3770: 0x00c0, 0x3771: 0x00c0, 0x3772: 0x00c0,
0x377a: 0x0080, 0x377b: 0x0080,
0x377c: 0x0080, 0x377d: 0x0080, 0x377e: 0x0080, 0x377f: 0x0080,
// Block 0xde, offset 0x3780
0x3780: 0x00c1, 0x3781: 0x00c2, 0x3782: 0x00c2, 0x3783: 0x00c2, 0x3784: 0x00c2, 0x3785: 0x00c2,
0x3786: 0x00c2, 0x3787: 0x00c2, 0x3788: 0x00c2, 0x3789: 0x00c2, 0x378a: 0x00c2, 0x378b: 0x00c2,
0x378c: 0x00c2, 0x378d: 0x00c2, 0x378e: 0x00c2, 0x378f: 0x00c2, 0x3790: 0x00c2, 0x3791: 0x00c2,
0x3792: 0x00c2, 0x3793: 0x00c2, 0x3794: 0x00c2, 0x3795: 0x00c2, 0x3796: 0x00c2, 0x3797: 0x00c2,
0x3798: 0x00c2, 0x3799: 0x00c2, 0x379a: 0x00c2, 0x379b: 0x00c2, 0x379c: 0x00c2, 0x379d: 0x00c2,
0x379e: 0x00c2, 0x379f: 0x00c2, 0x37a0: 0x00c2, 0x37a1: 0x00c2, 0x37a2: 0x00c4, 0x37a3: 0x00c2,
0x37a4: 0x00c3, 0x37a5: 0x00c3, 0x37a6: 0x00c3, 0x37a7: 0x00c3,
0x37b0: 0x00c0, 0x37b1: 0x00c0, 0x37b2: 0x00c0, 0x37b3: 0x00c0, 0x37b4: 0x00c0, 0x37b5: 0x00c0,
0x37b6: 0x00c0, 0x37b7: 0x00c0, 0x37b8: 0x00c0, 0x37b9: 0x00c0,
// Block 0xdf, offset 0x37c0
0x37e0: 0x0080, 0x37e1: 0x0080, 0x37e2: 0x0080, 0x37e3: 0x0080,
0x37e4: 0x0080, 0x37e5: 0x0080, 0x37e6: 0x0080, 0x37e7: 0x0080, 0x37e8: 0x0080, 0x37e9: 0x0080,
0x37ea: 0x0080, 0x37eb: 0x0080, 0x37ec: 0x0080, 0x37ed: 0x0080, 0x37ee: 0x0080, 0x37ef: 0x0080,
0x37f0: 0x0080, 0x37f1: 0x0080, 0x37f2: 0x0080, 0x37f3: 0x0080, 0x37f4: 0x0080, 0x37f5: 0x0080,
0x37f6: 0x0080, 0x37f7: 0x0080, 0x37f8: 0x0080, 0x37f9: 0x0080, 0x37fa: 0x0080, 0x37fb: 0x0080,
0x37fc: 0x0080, 0x37fd: 0x0080, 0x37fe: 0x0080,
// Block 0xe0, offset 0x3800
0x3800: 0x00c0, 0x3801: 0x00c0, 0x3802: 0x00c0, 0x3803: 0x00c0, 0x3804: 0x00c0, 0x3805: 0x00c0,
0x3806: 0x00c0, 0x3807: 0x00c0, 0x3808: 0x00c0, 0x3809: 0x00c0, 0x380a: 0x00c0, 0x380b: 0x00c0,
0x380c: 0x00c0, 0x380d: 0x00c0, 0x380e: 0x00c0, 0x380f: 0x00c0, 0x3810: 0x00c0, 0x3811: 0x00c0,
0x3812: 0x00c0, 0x3813: 0x00c0, 0x3814: 0x00c0, 0x3815: 0x00c0, 0x3816: 0x00c0, 0x3817: 0x00c0,
0x3818: 0x00c0, 0x3819: 0x00c0, 0x381a: 0x00c0, 0x381b: 0x00c0, 0x381c: 0x00c0, 0x381d: 0x00c0,
0x381e: 0x00c0, 0x381f: 0x00c0, 0x3820: 0x00c0, 0x3821: 0x00c0, 0x3822: 0x00c0, 0x3823: 0x00c0,
0x3824: 0x00c0, 0x3825: 0x00c0, 0x3826: 0x00c0, 0x3827: 0x00c0, 0x3828: 0x00c0, 0x3829: 0x00c0,
0x382b: 0x00c3, 0x382c: 0x00c3, 0x382d: 0x0080,
0x3830: 0x00c0, 0x3831: 0x00c0,
// Block 0xe1, offset 0x3840
0x387d: 0x00c3, 0x387e: 0x00c3, 0x387f: 0x00c3,
// Block 0xe2, offset 0x3880
0x3880: 0x00c0, 0x3881: 0x00c0, 0x3882: 0x00c0, 0x3883: 0x00c0, 0x3884: 0x00c0, 0x3885: 0x00c0,
0x3886: 0x00c0, 0x3887: 0x00c0, 0x3888: 0x00c0, 0x3889: 0x00c0, 0x388a: 0x00c0, 0x388b: 0x00c0,
0x388c: 0x00c0, 0x388d: 0x00c0, 0x388e: 0x00c0, 0x388f: 0x00c0, 0x3890: 0x00c0, 0x3891: 0x00c0,
0x3892: 0x00c0, 0x3893: 0x00c0, 0x3894: 0x00c0, 0x3895: 0x00c0, 0x3896: 0x00c0, 0x3897: 0x00c0,
0x3898: 0x00c0, 0x3899: 0x00c0, 0x389a: 0x00c0, 0x389b: 0x00c0, 0x389c: 0x00c0, 0x389d: 0x0080,
0x389e: 0x0080, 0x389f: 0x0080, 0x38a0: 0x0080, 0x38a1: 0x0080, 0x38a2: 0x0080, 0x38a3: 0x0080,
0x38a4: 0x0080, 0x38a5: 0x0080, 0x38a6: 0x0080, 0x38a7: 0x00c0,
0x38b0: 0x00c2, 0x38b1: 0x00c2, 0x38b2: 0x00c2, 0x38b3: 0x00c4, 0x38b4: 0x00c2, 0x38b5: 0x00c2,
0x38b6: 0x00c2, 0x38b7: 0x00c2, 0x38b8: 0x00c2, 0x38b9: 0x00c2, 0x38ba: 0x00c2, 0x38bb: 0x00c2,
0x38bc: 0x00c2, 0x38bd: 0x00c2, 0x38be: 0x00c2, 0x38bf: 0x00c2,
// Block 0xe3, offset 0x38c0
0x38c0: 0x00c2, 0x38c1: 0x00c2, 0x38c2: 0x00c2, 0x38c3: 0x00c2, 0x38c4: 0x00c2, 0x38c5: 0x00c0,
0x38c6: 0x00c3, 0x38c7: 0x00c3, 0x38c8: 0x00c3, 0x38c9: 0x00c3, 0x38ca: 0x00c3, 0x38cb: 0x00c3,
0x38cc: 0x00c3, 0x38cd: 0x00c3, 0x38ce: 0x00c3, 0x38cf: 0x00c3, 0x38d0: 0x00c3, 0x38d1: 0x0082,
0x38d2: 0x0082, 0x38d3: 0x0082, 0x38d4: 0x0084, 0x38d5: 0x0080, 0x38d6: 0x0080, 0x38d7: 0x0080,
0x38d8: 0x0080, 0x38d9: 0x0080,
0x38f0: 0x00c2, 0x38f1: 0x00c2, 0x38f2: 0x00c2, 0x38f3: 0x00c2, 0x38f4: 0x00c4, 0x38f5: 0x00c4,
0x38f6: 0x00c2, 0x38f7: 0x00c2, 0x38f8: 0x00c2, 0x38f9: 0x00c2, 0x38fa: 0x00c2, 0x38fb: 0x00c2,
0x38fc: 0x00c2, 0x38fd: 0x00c2, 0x38fe: 0x00c2, 0x38ff: 0x00c2,
// Block 0xe4, offset 0x3900
0x3900: 0x00c2, 0x3901: 0x00c2, 0x3902: 0x00c3, 0x3903: 0x00c3, 0x3904: 0x00c3, 0x3905: 0x00c3,
0x3906: 0x0080, 0x3907: 0x0080, 0x3908: 0x0080, 0x3909: 0x0080,
0x3930: 0x00c2, 0x3931: 0x00c0, 0x3932: 0x00c2, 0x3933: 0x00c2, 0x3934: 0x00c4, 0x3935: 0x00c4,
0x3936: 0x00c4, 0x3937: 0x00c0, 0x3938: 0x00c2, 0x3939: 0x00c4, 0x393a: 0x00c4, 0x393b: 0x00c2,
0x393c: 0x00c2, 0x393d: 0x00c4, 0x393e: 0x00c2, 0x393f: 0x00c2,
// Block 0xe5, offset 0x3940
0x3940: 0x00c0, 0x3941: 0x00c2, 0x3942: 0x00c4, 0x3943: 0x00c4, 0x3944: 0x00c2, 0x3945: 0x0080,
0x3946: 0x0080, 0x3947: 0x0080, 0x3948: 0x0080, 0x3949: 0x0084, 0x394a: 0x0082, 0x394b: 0x0081,
0x3960: 0x00c0, 0x3961: 0x00c0, 0x3962: 0x00c0, 0x3963: 0x00c0,
0x3964: 0x00c0, 0x3965: 0x00c0, 0x3966: 0x00c0, 0x3967: 0x00c0, 0x3968: 0x00c0, 0x3969: 0x00c0,
0x396a: 0x00c0, 0x396b: 0x00c0, 0x396c: 0x00c0, 0x396d: 0x00c0, 0x396e: 0x00c0, 0x396f: 0x00c0,
0x3970: 0x00c0, 0x3971: 0x00c0, 0x3972: 0x00c0, 0x3973: 0x00c0, 0x3974: 0x00c0, 0x3975: 0x00c0,
0x3976: 0x00c0,
// Block 0xe6, offset 0x3980
0x3980: 0x00c0, 0x3981: 0x00c3, 0x3982: 0x00c0, 0x3983: 0x00c0, 0x3984: 0x00c0, 0x3985: 0x00c0,
0x3986: 0x00c0, 0x3987: 0x00c0, 0x3988: 0x00c0, 0x3989: 0x00c0, 0x398a: 0x00c0, 0x398b: 0x00c0,
0x398c: 0x00c0, 0x398d: 0x00c0, 0x398e: 0x00c0, 0x398f: 0x00c0, 0x3990: 0x00c0, 0x3991: 0x00c0,
0x3992: 0x00c0, 0x3993: 0x00c0, 0x3994: 0x00c0, 0x3995: 0x00c0, 0x3996: 0x00c0, 0x3997: 0x00c0,
0x3998: 0x00c0, 0x3999: 0x00c0, 0x399a: 0x00c0, 0x399b: 0x00c0, 0x399c: 0x00c0, 0x399d: 0x00c0,
0x399e: 0x00c0, 0x399f: 0x00c0, 0x39a0: 0x00c0, 0x39a1: 0x00c0, 0x39a2: 0x00c0, 0x39a3: 0x00c0,
0x39a4: 0x00c0, 0x39a5: 0x00c0, 0x39a6: 0x00c0, 0x39a7: 0x00c0, 0x39a8: 0x00c0, 0x39a9: 0x00c0,
0x39aa: 0x00c0, 0x39ab: 0x00c0, 0x39ac: 0x00c0, 0x39ad: 0x00c0, 0x39ae: 0x00c0, 0x39af: 0x00c0,
0x39b0: 0x00c0, 0x39b1: 0x00c0, 0x39b2: 0x00c0, 0x39b3: 0x00c0, 0x39b4: 0x00c0, 0x39b5: 0x00c0,
0x39b6: 0x00c0, 0x39b7: 0x00c0, 0x39b8: 0x00c3, 0x39b9: 0x00c3, 0x39ba: 0x00c3, 0x39bb: 0x00c3,
0x39bc: 0x00c3, 0x39bd: 0x00c3, 0x39be: 0x00c3, 0x39bf: 0x00c3,
// Block 0xe7, offset 0x39c0
0x39c0: 0x00c3, 0x39c1: 0x00c3, 0x39c2: 0x00c3, 0x39c3: 0x00c3, 0x39c4: 0x00c3, 0x39c5: 0x00c3,
0x39c6: 0x00c6, 0x39c7: 0x0080, 0x39c8: 0x0080, 0x39c9: 0x0080, 0x39ca: 0x0080, 0x39cb: 0x0080,
0x39cc: 0x0080, 0x39cd: 0x0080,
0x39d2: 0x0080, 0x39d3: 0x0080, 0x39d4: 0x0080, 0x39d5: 0x0080, 0x39d6: 0x0080, 0x39d7: 0x0080,
0x39d8: 0x0080, 0x39d9: 0x0080, 0x39da: 0x0080, 0x39db: 0x0080, 0x39dc: 0x0080, 0x39dd: 0x0080,
0x39de: 0x0080, 0x39df: 0x0080, 0x39e0: 0x0080, 0x39e1: 0x0080, 0x39e2: 0x0080, 0x39e3: 0x0080,
0x39e4: 0x0080, 0x39e5: 0x0080, 0x39e6: 0x00c0, 0x39e7: 0x00c0, 0x39e8: 0x00c0, 0x39e9: 0x00c0,
0x39ea: 0x00c0, 0x39eb: 0x00c0, 0x39ec: 0x00c0, 0x39ed: 0x00c0, 0x39ee: 0x00c0, 0x39ef: 0x00c0,
0x39f0: 0x00c6, 0x39f1: 0x00c0, 0x39f2: 0x00c0, 0x39f3: 0x00c3, 0x39f4: 0x00c3, 0x39f5: 0x00c0,
0x39ff: 0x00c6,
// Block 0xe8, offset 0x3a00
0x3a00: 0x00c3, 0x3a01: 0x00c3, 0x3a02: 0x00c0, 0x3a03: 0x00c0, 0x3a04: 0x00c0, 0x3a05: 0x00c0,
0x3a06: 0x00c0, 0x3a07: 0x00c0, 0x3a08: 0x00c0, 0x3a09: 0x00c0, 0x3a0a: 0x00c0, 0x3a0b: 0x00c0,
0x3a0c: 0x00c0, 0x3a0d: 0x00c0, 0x3a0e: 0x00c0, 0x3a0f: 0x00c0, 0x3a10: 0x00c0, 0x3a11: 0x00c0,
0x3a12: 0x00c0, 0x3a13: 0x00c0, 0x3a14: 0x00c0, 0x3a15: 0x00c0, 0x3a16: 0x00c0, 0x3a17: 0x00c0,
0x3a18: 0x00c0, 0x3a19: 0x00c0, 0x3a1a: 0x00c0, 0x3a1b: 0x00c0, 0x3a1c: 0x00c0, 0x3a1d: 0x00c0,
0x3a1e: 0x00c0, 0x3a1f: 0x00c0, 0x3a20: 0x00c0, 0x3a21: 0x00c0, 0x3a22: 0x00c0, 0x3a23: 0x00c0,
0x3a24: 0x00c0, 0x3a25: 0x00c0, 0x3a26: 0x00c0, 0x3a27: 0x00c0, 0x3a28: 0x00c0, 0x3a29: 0x00c0,
0x3a2a: 0x00c0, 0x3a2b: 0x00c0, 0x3a2c: 0x00c0, 0x3a2d: 0x00c0, 0x3a2e: 0x00c0, 0x3a2f: 0x00c0,
0x3a30: 0x00c0, 0x3a31: 0x00c0, 0x3a32: 0x00c0, 0x3a33: 0x00c3, 0x3a34: 0x00c3, 0x3a35: 0x00c3,
0x3a36: 0x00c3, 0x3a37: 0x00c0, 0x3a38: 0x00c0, 0x3a39: 0x00c6, 0x3a3a: 0x00c3, 0x3a3b: 0x0080,
0x3a3c: 0x0080, 0x3a3d: 0x0040, 0x3a3e: 0x0080, 0x3a3f: 0x0080,
// Block 0xe9, offset 0x3a40
0x3a40: 0x0080, 0x3a41: 0x0080, 0x3a42: 0x00c3,
0x3a4d: 0x0040, 0x3a50: 0x00c0, 0x3a51: 0x00c0,
0x3a52: 0x00c0, 0x3a53: 0x00c0, 0x3a54: 0x00c0, 0x3a55: 0x00c0, 0x3a56: 0x00c0, 0x3a57: 0x00c0,
0x3a58: 0x00c0, 0x3a59: 0x00c0, 0x3a5a: 0x00c0, 0x3a5b: 0x00c0, 0x3a5c: 0x00c0, 0x3a5d: 0x00c0,
0x3a5e: 0x00c0, 0x3a5f: 0x00c0, 0x3a60: 0x00c0, 0x3a61: 0x00c0, 0x3a62: 0x00c0, 0x3a63: 0x00c0,
0x3a64: 0x00c0, 0x3a65: 0x00c0, 0x3a66: 0x00c0, 0x3a67: 0x00c0, 0x3a68: 0x00c0,
0x3a70: 0x00c0, 0x3a71: 0x00c0, 0x3a72: 0x00c0, 0x3a73: 0x00c0, 0x3a74: 0x00c0, 0x3a75: 0x00c0,
0x3a76: 0x00c0, 0x3a77: 0x00c0, 0x3a78: 0x00c0, 0x3a79: 0x00c0,
// Block 0xea, offset 0x3a80
0x3a80: 0x00c3, 0x3a81: 0x00c3, 0x3a82: 0x00c3, 0x3a83: 0x00c0, 0x3a84: 0x00c0, 0x3a85: 0x00c0,
0x3a86: 0x00c0, 0x3a87: 0x00c0, 0x3a88: 0x00c0, 0x3a89: 0x00c0, 0x3a8a: 0x00c0, 0x3a8b: 0x00c0,
0x3a8c: 0x00c0, 0x3a8d: 0x00c0, 0x3a8e: 0x00c0, 0x3a8f: 0x00c0, 0x3a90: 0x00c0, 0x3a91: 0x00c0,
0x3a92: 0x00c0, 0x3a93: 0x00c0, 0x3a94: 0x00c0, 0x3a95: 0x00c0, 0x3a96: 0x00c0, 0x3a97: 0x00c0,
0x3a98: 0x00c0, 0x3a99: 0x00c0, 0x3a9a: 0x00c0, 0x3a9b: 0x00c0, 0x3a9c: 0x00c0, 0x3a9d: 0x00c0,
0x3a9e: 0x00c0, 0x3a9f: 0x00c0, 0x3aa0: 0x00c0, 0x3aa1: 0x00c0, 0x3aa2: 0x00c0, 0x3aa3: 0x00c0,
0x3aa4: 0x00c0, 0x3aa5: 0x00c0, 0x3aa6: 0x00c0, 0x3aa7: 0x00c3, 0x3aa8: 0x00c3, 0x3aa9: 0x00c3,
0x3aaa: 0x00c3, 0x3aab: 0x00c3, 0x3aac: 0x00c0, 0x3aad: 0x00c3, 0x3aae: 0x00c3, 0x3aaf: 0x00c3,
0x3ab0: 0x00c3, 0x3ab1: 0x00c3, 0x3ab2: 0x00c3, 0x3ab3: 0x00c6, 0x3ab4: 0x00c6,
0x3ab6: 0x00c0, 0x3ab7: 0x00c0, 0x3ab8: 0x00c0, 0x3ab9: 0x00c0, 0x3aba: 0x00c0, 0x3abb: 0x00c0,
0x3abc: 0x00c0, 0x3abd: 0x00c0, 0x3abe: 0x00c0, 0x3abf: 0x00c0,
// Block 0xeb, offset 0x3ac0
0x3ac0: 0x0080, 0x3ac1: 0x0080, 0x3ac2: 0x0080, 0x3ac3: 0x0080, 0x3ac4: 0x00c0, 0x3ac5: 0x00c0,
0x3ac6: 0x00c0, 0x3ac7: 0x00c0,
0x3ad0: 0x00c0, 0x3ad1: 0x00c0,
0x3ad2: 0x00c0, 0x3ad3: 0x00c0, 0x3ad4: 0x00c0, 0x3ad5: 0x00c0, 0x3ad6: 0x00c0, 0x3ad7: 0x00c0,
0x3ad8: 0x00c0, 0x3ad9: 0x00c0, 0x3ada: 0x00c0, 0x3adb: 0x00c0, 0x3adc: 0x00c0, 0x3add: 0x00c0,
0x3ade: 0x00c0, 0x3adf: 0x00c0, 0x3ae0: 0x00c0, 0x3ae1: 0x00c0, 0x3ae2: 0x00c0, 0x3ae3: 0x00c0,
0x3ae4: 0x00c0, 0x3ae5: 0x00c0, 0x3ae6: 0x00c0, 0x3ae7: 0x00c0, 0x3ae8: 0x00c0, 0x3ae9: 0x00c0,
0x3aea: 0x00c0, 0x3aeb: 0x00c0, 0x3aec: 0x00c0, 0x3aed: 0x00c0, 0x3aee: 0x00c0, 0x3aef: 0x00c0,
0x3af0: 0x00c0, 0x3af1: 0x00c0, 0x3af2: 0x00c0, 0x3af3: 0x00c3, 0x3af4: 0x0080, 0x3af5: 0x0080,
0x3af6: 0x00c0,
// Block 0xec, offset 0x3b00
0x3b00: 0x00c3, 0x3b01: 0x00c3, 0x3b02: 0x00c0, 0x3b03: 0x00c0, 0x3b04: 0x00c0, 0x3b05: 0x00c0,
0x3b06: 0x00c0, 0x3b07: 0x00c0, 0x3b08: 0x00c0, 0x3b09: 0x00c0, 0x3b0a: 0x00c0, 0x3b0b: 0x00c0,
0x3b0c: 0x00c0, 0x3b0d: 0x00c0, 0x3b0e: 0x00c0, 0x3b0f: 0x00c0, 0x3b10: 0x00c0, 0x3b11: 0x00c0,
0x3b12: 0x00c0, 0x3b13: 0x00c0, 0x3b14: 0x00c0, 0x3b15: 0x00c0, 0x3b16: 0x00c0, 0x3b17: 0x00c0,
0x3b18: 0x00c0, 0x3b19: 0x00c0, 0x3b1a: 0x00c0, 0x3b1b: 0x00c0, 0x3b1c: 0x00c0, 0x3b1d: 0x00c0,
0x3b1e: 0x00c0, 0x3b1f: 0x00c0, 0x3b20: 0x00c0, 0x3b21: 0x00c0, 0x3b22: 0x00c0, 0x3b23: 0x00c0,
0x3b24: 0x00c0, 0x3b25: 0x00c0, 0x3b26: 0x00c0, 0x3b27: 0x00c0, 0x3b28: 0x00c0, 0x3b29: 0x00c0,
0x3b2a: 0x00c0, 0x3b2b: 0x00c0, 0x3b2c: 0x00c0, 0x3b2d: 0x00c0, 0x3b2e: 0x00c0, 0x3b2f: 0x00c0,
0x3b30: 0x00c0, 0x3b31: 0x00c0, 0x3b32: 0x00c0, 0x3b33: 0x00c0, 0x3b34: 0x00c0, 0x3b35: 0x00c0,
0x3b36: 0x00c3, 0x3b37: 0x00c3, 0x3b38: 0x00c3, 0x3b39: 0x00c3, 0x3b3a: 0x00c3, 0x3b3b: 0x00c3,
0x3b3c: 0x00c3, 0x3b3d: 0x00c3, 0x3b3e: 0x00c3, 0x3b3f: 0x00c0,
// Block 0xed, offset 0x3b40
0x3b40: 0x00c5, 0x3b41: 0x00c0, 0x3b42: 0x00c0, 0x3b43: 0x00c0, 0x3b44: 0x00c0, 0x3b45: 0x0080,
0x3b46: 0x0080, 0x3b47: 0x0080, 0x3b48: 0x0080, 0x3b49: 0x00c3, 0x3b4a: 0x00c3, 0x3b4b: 0x00c3,
0x3b4c: 0x00c3, 0x3b4d: 0x0080, 0x3b4e: 0x00c0, 0x3b4f: 0x00c3, 0x3b50: 0x00c0, 0x3b51: 0x00c0,
0x3b52: 0x00c0, 0x3b53: 0x00c0, 0x3b54: 0x00c0, 0x3b55: 0x00c0, 0x3b56: 0x00c0, 0x3b57: 0x00c0,
0x3b58: 0x00c0, 0x3b59: 0x00c0, 0x3b5a: 0x00c0, 0x3b5b: 0x0080, 0x3b5c: 0x00c0, 0x3b5d: 0x0080,
0x3b5e: 0x0080, 0x3b5f: 0x0080, 0x3b61: 0x0080, 0x3b62: 0x0080, 0x3b63: 0x0080,
0x3b64: 0x0080, 0x3b65: 0x0080, 0x3b66: 0x0080, 0x3b67: 0x0080, 0x3b68: 0x0080, 0x3b69: 0x0080,
0x3b6a: 0x0080, 0x3b6b: 0x0080, 0x3b6c: 0x0080, 0x3b6d: 0x0080, 0x3b6e: 0x0080, 0x3b6f: 0x0080,
0x3b70: 0x0080, 0x3b71: 0x0080, 0x3b72: 0x0080, 0x3b73: 0x0080, 0x3b74: 0x0080,
// Block 0xee, offset 0x3b80
0x3b80: 0x00c0, 0x3b81: 0x00c0, 0x3b82: 0x00c0, 0x3b83: 0x00c0, 0x3b84: 0x00c0, 0x3b85: 0x00c0,
0x3b86: 0x00c0, 0x3b87: 0x00c0, 0x3b88: 0x00c0, 0x3b89: 0x00c0, 0x3b8a: 0x00c0, 0x3b8b: 0x00c0,
0x3b8c: 0x00c0, 0x3b8d: 0x00c0, 0x3b8e: 0x00c0, 0x3b8f: 0x00c0, 0x3b90: 0x00c0, 0x3b91: 0x00c0,
0x3b93: 0x00c0, 0x3b94: 0x00c0, 0x3b95: 0x00c0, 0x3b96: 0x00c0, 0x3b97: 0x00c0,
0x3b98: 0x00c0, 0x3b99: 0x00c0, 0x3b9a: 0x00c0, 0x3b9b: 0x00c0, 0x3b9c: 0x00c0, 0x3b9d: 0x00c0,
0x3b9e: 0x00c0, 0x3b9f: 0x00c0, 0x3ba0: 0x00c0, 0x3ba1: 0x00c0, 0x3ba2: 0x00c0, 0x3ba3: 0x00c0,
0x3ba4: 0x00c0, 0x3ba5: 0x00c0, 0x3ba6: 0x00c0, 0x3ba7: 0x00c0, 0x3ba8: 0x00c0, 0x3ba9: 0x00c0,
0x3baa: 0x00c0, 0x3bab: 0x00c0, 0x3bac: 0x00c0, 0x3bad: 0x00c0, 0x3bae: 0x00c0, 0x3baf: 0x00c3,
0x3bb0: 0x00c3, 0x3bb1: 0x00c3, 0x3bb2: 0x00c0, 0x3bb3: 0x00c0, 0x3bb4: 0x00c3, 0x3bb5: 0x00c5,
0x3bb6: 0x00c3, 0x3bb7: 0x00c3, 0x3bb8: 0x0080, 0x3bb9: 0x0080, 0x3bba: 0x0080, 0x3bbb: 0x0080,
0x3bbc: 0x0080, 0x3bbd: 0x0080, 0x3bbe: 0x00c3, 0x3bbf: 0x00c0,
// Block 0xef, offset 0x3bc0
0x3bc0: 0x00c0, 0x3bc1: 0x00c3,
// Block 0xf0, offset 0x3c00
0x3c00: 0x00c0, 0x3c01: 0x00c0, 0x3c02: 0x00c0, 0x3c03: 0x00c0, 0x3c04: 0x00c0, 0x3c05: 0x00c0,
0x3c06: 0x00c0, 0x3c08: 0x00c0, 0x3c0a: 0x00c0, 0x3c0b: 0x00c0,
0x3c0c: 0x00c0, 0x3c0d: 0x00c0, 0x3c0f: 0x00c0, 0x3c10: 0x00c0, 0x3c11: 0x00c0,
0x3c12: 0x00c0, 0x3c13: 0x00c0, 0x3c14: 0x00c0, 0x3c15: 0x00c0, 0x3c16: 0x00c0, 0x3c17: 0x00c0,
0x3c18: 0x00c0, 0x3c19: 0x00c0, 0x3c1a: 0x00c0, 0x3c1b: 0x00c0, 0x3c1c: 0x00c0, 0x3c1d: 0x00c0,
0x3c1f: 0x00c0, 0x3c20: 0x00c0, 0x3c21: 0x00c0, 0x3c22: 0x00c0, 0x3c23: 0x00c0,
0x3c24: 0x00c0, 0x3c25: 0x00c0, 0x3c26: 0x00c0, 0x3c27: 0x00c0, 0x3c28: 0x00c0, 0x3c29: 0x0080,
0x3c30: 0x00c0, 0x3c31: 0x00c0, 0x3c32: 0x00c0, 0x3c33: 0x00c0, 0x3c34: 0x00c0, 0x3c35: 0x00c0,
0x3c36: 0x00c0, 0x3c37: 0x00c0, 0x3c38: 0x00c0, 0x3c39: 0x00c0, 0x3c3a: 0x00c0, 0x3c3b: 0x00c0,
0x3c3c: 0x00c0, 0x3c3d: 0x00c0, 0x3c3e: 0x00c0, 0x3c3f: 0x00c0,
// Block 0xf1, offset 0x3c40
0x3c40: 0x00c0, 0x3c41: 0x00c0, 0x3c42: 0x00c0, 0x3c43: 0x00c0, 0x3c44: 0x00c0, 0x3c45: 0x00c0,
0x3c46: 0x00c0, 0x3c47: 0x00c0, 0x3c48: 0x00c0, 0x3c49: 0x00c0, 0x3c4a: 0x00c0, 0x3c4b: 0x00c0,
0x3c4c: 0x00c0, 0x3c4d: 0x00c0, 0x3c4e: 0x00c0, 0x3c4f: 0x00c0, 0x3c50: 0x00c0, 0x3c51: 0x00c0,
0x3c52: 0x00c0, 0x3c53: 0x00c0, 0x3c54: 0x00c0, 0x3c55: 0x00c0, 0x3c56: 0x00c0, 0x3c57: 0x00c0,
0x3c58: 0x00c0, 0x3c59: 0x00c0, 0x3c5a: 0x00c0, 0x3c5b: 0x00c0, 0x3c5c: 0x00c0, 0x3c5d: 0x00c0,
0x3c5e: 0x00c0, 0x3c5f: 0x00c3, 0x3c60: 0x00c0, 0x3c61: 0x00c0, 0x3c62: 0x00c0, 0x3c63: 0x00c3,
0x3c64: 0x00c3, 0x3c65: 0x00c3, 0x3c66: 0x00c3, 0x3c67: 0x00c3, 0x3c68: 0x00c3, 0x3c69: 0x00c3,
0x3c6a: 0x00c6,
0x3c70: 0x00c0, 0x3c71: 0x00c0, 0x3c72: 0x00c0, 0x3c73: 0x00c0, 0x3c74: 0x00c0, 0x3c75: 0x00c0,
0x3c76: 0x00c0, 0x3c77: 0x00c0, 0x3c78: 0x00c0, 0x3c79: 0x00c0,
// Block 0xf2, offset 0x3c80
0x3c80: 0x00c3, 0x3c81: 0x00c3, 0x3c82: 0x00c0, 0x3c83: 0x00c0, 0x3c85: 0x00c0,
0x3c86: 0x00c0, 0x3c87: 0x00c0, 0x3c88: 0x00c0, 0x3c89: 0x00c0, 0x3c8a: 0x00c0, 0x3c8b: 0x00c0,
0x3c8c: 0x00c0, 0x3c8f: 0x00c0, 0x3c90: 0x00c0,
0x3c93: 0x00c0, 0x3c94: 0x00c0, 0x3c95: 0x00c0, 0x3c96: 0x00c0, 0x3c97: 0x00c0,
0x3c98: 0x00c0, 0x3c99: 0x00c0, 0x3c9a: 0x00c0, 0x3c9b: 0x00c0, 0x3c9c: 0x00c0, 0x3c9d: 0x00c0,
0x3c9e: 0x00c0, 0x3c9f: 0x00c0, 0x3ca0: 0x00c0, 0x3ca1: 0x00c0, 0x3ca2: 0x00c0, 0x3ca3: 0x00c0,
0x3ca4: 0x00c0, 0x3ca5: 0x00c0, 0x3ca6: 0x00c0, 0x3ca7: 0x00c0, 0x3ca8: 0x00c0,
0x3caa: 0x00c0, 0x3cab: 0x00c0, 0x3cac: 0x00c0, 0x3cad: 0x00c0, 0x3cae: 0x00c0, 0x3caf: 0x00c0,
0x3cb0: 0x00c0, 0x3cb2: 0x00c0, 0x3cb3: 0x00c0, 0x3cb5: 0x00c0,
0x3cb6: 0x00c0, 0x3cb7: 0x00c0, 0x3cb8: 0x00c0, 0x3cb9: 0x00c0, 0x3cbb: 0x00c3,
0x3cbc: 0x00c3, 0x3cbd: 0x00c0, 0x3cbe: 0x00c0, 0x3cbf: 0x00c0,
// Block 0xf3, offset 0x3cc0
0x3cc0: 0x00c3, 0x3cc1: 0x00c0, 0x3cc2: 0x00c0, 0x3cc3: 0x00c0, 0x3cc4: 0x00c0,
0x3cc7: 0x00c0, 0x3cc8: 0x00c0, 0x3ccb: 0x00c0,
0x3ccc: 0x00c0, 0x3ccd: 0x00c5, 0x3cd0: 0x00c0,
0x3cd7: 0x00c0,
0x3cdd: 0x00c0,
0x3cde: 0x00c0, 0x3cdf: 0x00c0, 0x3ce0: 0x00c0, 0x3ce1: 0x00c0, 0x3ce2: 0x00c0, 0x3ce3: 0x00c0,
0x3ce6: 0x00c3, 0x3ce7: 0x00c3, 0x3ce8: 0x00c3, 0x3ce9: 0x00c3,
0x3cea: 0x00c3, 0x3ceb: 0x00c3, 0x3cec: 0x00c3,
0x3cf0: 0x00c3, 0x3cf1: 0x00c3, 0x3cf2: 0x00c3, 0x3cf3: 0x00c3, 0x3cf4: 0x00c3,
// Block 0xf4, offset 0x3d00
0x3d00: 0x00c0, 0x3d01: 0x00c0, 0x3d02: 0x00c0, 0x3d03: 0x00c0, 0x3d04: 0x00c0, 0x3d05: 0x00c0,
0x3d06: 0x00c0, 0x3d07: 0x00c0, 0x3d08: 0x00c0, 0x3d09: 0x00c0, 0x3d0a: 0x00c0, 0x3d0b: 0x00c0,
0x3d0c: 0x00c0, 0x3d0d: 0x00c0, 0x3d0e: 0x00c0, 0x3d0f: 0x00c0, 0x3d10: 0x00c0, 0x3d11: 0x00c0,
0x3d12: 0x00c0, 0x3d13: 0x00c0, 0x3d14: 0x00c0, 0x3d15: 0x00c0, 0x3d16: 0x00c0, 0x3d17: 0x00c0,
0x3d18: 0x00c0, 0x3d19: 0x00c0, 0x3d1a: 0x00c0, 0x3d1b: 0x00c0, 0x3d1c: 0x00c0, 0x3d1d: 0x00c0,
0x3d1e: 0x00c0, 0x3d1f: 0x00c0, 0x3d20: 0x00c0, 0x3d21: 0x00c0, 0x3d22: 0x00c0, 0x3d23: 0x00c0,
0x3d24: 0x00c0, 0x3d25: 0x00c0, 0x3d26: 0x00c0, 0x3d27: 0x00c0, 0x3d28: 0x00c0, 0x3d29: 0x00c0,
0x3d2a: 0x00c0, 0x3d2b: 0x00c0, 0x3d2c: 0x00c0, 0x3d2d: 0x00c0, 0x3d2e: 0x00c0, 0x3d2f: 0x00c0,
0x3d30: 0x00c0, 0x3d31: 0x00c0, 0x3d32: 0x00c0, 0x3d33: 0x00c0, 0x3d34: 0x00c0, 0x3d35: 0x00c0,
0x3d36: 0x00c0, 0x3d37: 0x00c0, 0x3d38: 0x00c3, 0x3d39: 0x00c3, 0x3d3a: 0x00c3, 0x3d3b: 0x00c3,
0x3d3c: 0x00c3, 0x3d3d: 0x00c3, 0x3d3e: 0x00c3, 0x3d3f: 0x00c3,
// Block 0xf5, offset 0x3d40
0x3d40: 0x00c0, 0x3d41: 0x00c0, 0x3d42: 0x00c6, 0x3d43: 0x00c3, 0x3d44: 0x00c3, 0x3d45: 0x00c0,
0x3d46: 0x00c3, 0x3d47: 0x00c0, 0x3d48: 0x00c0, 0x3d49: 0x00c0, 0x3d4a: 0x00c0, 0x3d4b: 0x0080,
0x3d4c: 0x0080, 0x3d4d: 0x0080, 0x3d4e: 0x0080, 0x3d4f: 0x0080, 0x3d50: 0x00c0, 0x3d51: 0x00c0,
0x3d52: 0x00c0, 0x3d53: 0x00c0, 0x3d54: 0x00c0, 0x3d55: 0x00c0, 0x3d56: 0x00c0, 0x3d57: 0x00c0,
0x3d58: 0x00c0, 0x3d59: 0x00c0, 0x3d5a: 0x0080, 0x3d5b: 0x0080, 0x3d5d: 0x0080,
0x3d5e: 0x00c3, 0x3d5f: 0x00c0, 0x3d60: 0x00c0, 0x3d61: 0x00c0,
// Block 0xf6, offset 0x3d80
0x3d80: 0x00c0, 0x3d81: 0x00c0, 0x3d82: 0x00c0, 0x3d83: 0x00c0, 0x3d84: 0x00c0, 0x3d85: 0x00c0,
0x3d86: 0x00c0, 0x3d87: 0x00c0, 0x3d88: 0x00c0, 0x3d89: 0x00c0, 0x3d8a: 0x00c0, 0x3d8b: 0x00c0,
0x3d8c: 0x00c0, 0x3d8d: 0x00c0, 0x3d8e: 0x00c0, 0x3d8f: 0x00c0, 0x3d90: 0x00c0, 0x3d91: 0x00c0,
0x3d92: 0x00c0, 0x3d93: 0x00c0, 0x3d94: 0x00c0, 0x3d95: 0x00c0, 0x3d96: 0x00c0, 0x3d97: 0x00c0,
0x3d98: 0x00c0, 0x3d99: 0x00c0, 0x3d9a: 0x00c0, 0x3d9b: 0x00c0, 0x3d9c: 0x00c0, 0x3d9d: 0x00c0,
0x3d9e: 0x00c0, 0x3d9f: 0x00c0, 0x3da0: 0x00c0, 0x3da1: 0x00c0, 0x3da2: 0x00c0, 0x3da3: 0x00c0,
0x3da4: 0x00c0, 0x3da5: 0x00c0, 0x3da6: 0x00c0, 0x3da7: 0x00c0, 0x3da8: 0x00c0, 0x3da9: 0x00c0,
0x3daa: 0x00c0, 0x3dab: 0x00c0, 0x3dac: 0x00c0, 0x3dad: 0x00c0, 0x3dae: 0x00c0, 0x3daf: 0x00c0,
0x3db0: 0x00c0, 0x3db1: 0x00c0, 0x3db2: 0x00c0, 0x3db3: 0x00c3, 0x3db4: 0x00c3, 0x3db5: 0x00c3,
0x3db6: 0x00c3, 0x3db7: 0x00c3, 0x3db8: 0x00c3, 0x3db9: 0x00c0, 0x3dba: 0x00c3, 0x3dbb: 0x00c0,
0x3dbc: 0x00c0, 0x3dbd: 0x00c0, 0x3dbe: 0x00c0, 0x3dbf: 0x00c3,
// Block 0xf7, offset 0x3dc0
0x3dc0: 0x00c3, 0x3dc1: 0x00c0, 0x3dc2: 0x00c6, 0x3dc3: 0x00c3, 0x3dc4: 0x00c0, 0x3dc5: 0x00c0,
0x3dc6: 0x0080, 0x3dc7: 0x00c0,
0x3dd0: 0x00c0, 0x3dd1: 0x00c0,
0x3dd2: 0x00c0, 0x3dd3: 0x00c0, 0x3dd4: 0x00c0, 0x3dd5: 0x00c0, 0x3dd6: 0x00c0, 0x3dd7: 0x00c0,
0x3dd8: 0x00c0, 0x3dd9: 0x00c0,
// Block 0xf8, offset 0x3e00
0x3e00: 0x00c0, 0x3e01: 0x00c0, 0x3e02: 0x00c0, 0x3e03: 0x00c0, 0x3e04: 0x00c0, 0x3e05: 0x00c0,
0x3e06: 0x00c0, 0x3e07: 0x00c0, 0x3e08: 0x00c0, 0x3e09: 0x00c0, 0x3e0a: 0x00c0, 0x3e0b: 0x00c0,
0x3e0c: 0x00c0, 0x3e0d: 0x00c0, 0x3e0e: 0x00c0, 0x3e0f: 0x00c0, 0x3e10: 0x00c0, 0x3e11: 0x00c0,
0x3e12: 0x00c0, 0x3e13: 0x00c0, 0x3e14: 0x00c0, 0x3e15: 0x00c0, 0x3e16: 0x00c0, 0x3e17: 0x00c0,
0x3e18: 0x00c0, 0x3e19: 0x00c0, 0x3e1a: 0x00c0, 0x3e1b: 0x00c0, 0x3e1c: 0x00c0, 0x3e1d: 0x00c0,
0x3e1e: 0x00c0, 0x3e1f: 0x00c0, 0x3e20: 0x00c0, 0x3e21: 0x00c0, 0x3e22: 0x00c0, 0x3e23: 0x00c0,
0x3e24: 0x00c0, 0x3e25: 0x00c0, 0x3e26: 0x00c0, 0x3e27: 0x00c0, 0x3e28: 0x00c0, 0x3e29: 0x00c0,
0x3e2a: 0x00c0, 0x3e2b: 0x00c0, 0x3e2c: 0x00c0, 0x3e2d: 0x00c0, 0x3e2e: 0x00c0, 0x3e2f: 0x00c0,
0x3e30: 0x00c0, 0x3e31: 0x00c0, 0x3e32: 0x00c3, 0x3e33: 0x00c3, 0x3e34: 0x00c3, 0x3e35: 0x00c3,
0x3e38: 0x00c0, 0x3e39: 0x00c0, 0x3e3a: 0x00c0, 0x3e3b: 0x00c0,
0x3e3c: 0x00c3, 0x3e3d: 0x00c3, 0x3e3e: 0x00c0, 0x3e3f: 0x00c6,
// Block 0xf9, offset 0x3e40
0x3e40: 0x00c3, 0x3e41: 0x0080, 0x3e42: 0x0080, 0x3e43: 0x0080, 0x3e44: 0x0080, 0x3e45: 0x0080,
0x3e46: 0x0080, 0x3e47: 0x0080, 0x3e48: 0x0080, 0x3e49: 0x0080, 0x3e4a: 0x0080, 0x3e4b: 0x0080,
0x3e4c: 0x0080, 0x3e4d: 0x0080, 0x3e4e: 0x0080, 0x3e4f: 0x0080, 0x3e50: 0x0080, 0x3e51: 0x0080,
0x3e52: 0x0080, 0x3e53: 0x0080, 0x3e54: 0x0080, 0x3e55: 0x0080, 0x3e56: 0x0080, 0x3e57: 0x0080,
0x3e58: 0x00c0, 0x3e59: 0x00c0, 0x3e5a: 0x00c0, 0x3e5b: 0x00c0, 0x3e5c: 0x00c3, 0x3e5d: 0x00c3,
// Block 0xfa, offset 0x3e80
0x3e80: 0x00c0, 0x3e81: 0x00c0, 0x3e82: 0x00c0, 0x3e83: 0x00c0, 0x3e84: 0x00c0, 0x3e85: 0x00c0,
0x3e86: 0x00c0, 0x3e87: 0x00c0, 0x3e88: 0x00c0, 0x3e89: 0x00c0, 0x3e8a: 0x00c0, 0x3e8b: 0x00c0,
0x3e8c: 0x00c0, 0x3e8d: 0x00c0, 0x3e8e: 0x00c0, 0x3e8f: 0x00c0, 0x3e90: 0x00c0, 0x3e91: 0x00c0,
0x3e92: 0x00c0, 0x3e93: 0x00c0, 0x3e94: 0x00c0, 0x3e95: 0x00c0, 0x3e96: 0x00c0, 0x3e97: 0x00c0,
0x3e98: 0x00c0, 0x3e99: 0x00c0, 0x3e9a: 0x00c0, 0x3e9b: 0x00c0, 0x3e9c: 0x00c0, 0x3e9d: 0x00c0,
0x3e9e: 0x00c0, 0x3e9f: 0x00c0, 0x3ea0: 0x00c0, 0x3ea1: 0x00c0, 0x3ea2: 0x00c0, 0x3ea3: 0x00c0,
0x3ea4: 0x00c0, 0x3ea5: 0x00c0, 0x3ea6: 0x00c0, 0x3ea7: 0x00c0, 0x3ea8: 0x00c0, 0x3ea9: 0x00c0,
0x3eaa: 0x00c0, 0x3eab: 0x00c0, 0x3eac: 0x00c0, 0x3ead: 0x00c0, 0x3eae: 0x00c0, 0x3eaf: 0x00c0,
0x3eb0: 0x00c0, 0x3eb1: 0x00c0, 0x3eb2: 0x00c0, 0x3eb3: 0x00c3, 0x3eb4: 0x00c3, 0x3eb5: 0x00c3,
0x3eb6: 0x00c3, 0x3eb7: 0x00c3, 0x3eb8: 0x00c3, 0x3eb9: 0x00c3, 0x3eba: 0x00c3, 0x3ebb: 0x00c0,
0x3ebc: 0x00c0, 0x3ebd: 0x00c3, 0x3ebe: 0x00c0, 0x3ebf: 0x00c6,
// Block 0xfb, offset 0x3ec0
0x3ec0: 0x00c3, 0x3ec1: 0x0080, 0x3ec2: 0x0080, 0x3ec3: 0x0080, 0x3ec4: 0x00c0,
0x3ed0: 0x00c0, 0x3ed1: 0x00c0,
0x3ed2: 0x00c0, 0x3ed3: 0x00c0, 0x3ed4: 0x00c0, 0x3ed5: 0x00c0, 0x3ed6: 0x00c0, 0x3ed7: 0x00c0,
0x3ed8: 0x00c0, 0x3ed9: 0x00c0,
0x3ee0: 0x0080, 0x3ee1: 0x0080, 0x3ee2: 0x0080, 0x3ee3: 0x0080,
0x3ee4: 0x0080, 0x3ee5: 0x0080, 0x3ee6: 0x0080, 0x3ee7: 0x0080, 0x3ee8: 0x0080, 0x3ee9: 0x0080,
0x3eea: 0x0080, 0x3eeb: 0x0080, 0x3eec: 0x0080,
// Block 0xfc, offset 0x3f00
0x3f00: 0x00c0, 0x3f01: 0x00c0, 0x3f02: 0x00c0, 0x3f03: 0x00c0, 0x3f04: 0x00c0, 0x3f05: 0x00c0,
0x3f06: 0x00c0, 0x3f07: 0x00c0, 0x3f08: 0x00c0, 0x3f09: 0x00c0, 0x3f0a: 0x00c0, 0x3f0b: 0x00c0,
0x3f0c: 0x00c0, 0x3f0d: 0x00c0, 0x3f0e: 0x00c0, 0x3f0f: 0x00c0, 0x3f10: 0x00c0, 0x3f11: 0x00c0,
0x3f12: 0x00c0, 0x3f13: 0x00c0, 0x3f14: 0x00c0, 0x3f15: 0x00c0, 0x3f16: 0x00c0, 0x3f17: 0x00c0,
0x3f18: 0x00c0, 0x3f19: 0x00c0, 0x3f1a: 0x00c0, 0x3f1b: 0x00c0, 0x3f1c: 0x00c0, 0x3f1d: 0x00c0,
0x3f1e: 0x00c0, 0x3f1f: 0x00c0, 0x3f20: 0x00c0, 0x3f21: 0x00c0, 0x3f22: 0x00c0, 0x3f23: 0x00c0,
0x3f24: 0x00c0, 0x3f25: 0x00c0, 0x3f26: 0x00c0, 0x3f27: 0x00c0, 0x3f28: 0x00c0, 0x3f29: 0x00c0,
0x3f2a: 0x00c0, 0x3f2b: 0x00c3, 0x3f2c: 0x00c0, 0x3f2d: 0x00c3, 0x3f2e: 0x00c0, 0x3f2f: 0x00c0,
0x3f30: 0x00c3, 0x3f31: 0x00c3, 0x3f32: 0x00c3, 0x3f33: 0x00c3, 0x3f34: 0x00c3, 0x3f35: 0x00c3,
0x3f36: 0x00c5, 0x3f37: 0x00c3, 0x3f38: 0x00c0, 0x3f39: 0x0080,
// Block 0xfd, offset 0x3f40
0x3f40: 0x00c0, 0x3f41: 0x00c0, 0x3f42: 0x00c0, 0x3f43: 0x00c0, 0x3f44: 0x00c0, 0x3f45: 0x00c0,
0x3f46: 0x00c0, 0x3f47: 0x00c0, 0x3f48: 0x00c0, 0x3f49: 0x00c0,
// Block 0xfe, offset 0x3f80
0x3f80: 0x00c0, 0x3f81: 0x00c0, 0x3f82: 0x00c0, 0x3f83: 0x00c0, 0x3f84: 0x00c0, 0x3f85: 0x00c0,
0x3f86: 0x00c0, 0x3f87: 0x00c0, 0x3f88: 0x00c0, 0x3f89: 0x00c0, 0x3f8a: 0x00c0, 0x3f8b: 0x00c0,
0x3f8c: 0x00c0, 0x3f8d: 0x00c0, 0x3f8e: 0x00c0, 0x3f8f: 0x00c0, 0x3f90: 0x00c0, 0x3f91: 0x00c0,
0x3f92: 0x00c0, 0x3f93: 0x00c0, 0x3f94: 0x00c0, 0x3f95: 0x00c0, 0x3f96: 0x00c0, 0x3f97: 0x00c0,
0x3f98: 0x00c0, 0x3f99: 0x00c0, 0x3f9a: 0x00c0, 0x3f9d: 0x00c3,
0x3f9e: 0x00c3, 0x3f9f: 0x00c3, 0x3fa0: 0x00c0, 0x3fa1: 0x00c0, 0x3fa2: 0x00c3, 0x3fa3: 0x00c3,
0x3fa4: 0x00c3, 0x3fa5: 0x00c3, 0x3fa6: 0x00c0, 0x3fa7: 0x00c3, 0x3fa8: 0x00c3, 0x3fa9: 0x00c3,
0x3faa: 0x00c3, 0x3fab: 0x00c6,
0x3fb0: 0x00c0, 0x3fb1: 0x00c0, 0x3fb2: 0x00c0, 0x3fb3: 0x00c0, 0x3fb4: 0x00c0, 0x3fb5: 0x00c0,
0x3fb6: 0x00c0, 0x3fb7: 0x00c0, 0x3fb8: 0x00c0, 0x3fb9: 0x00c0, 0x3fba: 0x0080, 0x3fbb: 0x0080,
0x3fbc: 0x0080, 0x3fbd: 0x0080, 0x3fbe: 0x0080, 0x3fbf: 0x0080,
// Block 0xff, offset 0x3fc0
0x3fc0: 0x00c0, 0x3fc1: 0x00c0, 0x3fc2: 0x00c0, 0x3fc3: 0x00c0, 0x3fc4: 0x00c0, 0x3fc5: 0x00c0,
0x3fc6: 0x00c0,
// Block 0x100, offset 0x4000
0x4000: 0x00c0, 0x4001: 0x00c0, 0x4002: 0x00c0, 0x4003: 0x00c0, 0x4004: 0x00c0, 0x4005: 0x00c0,
0x4006: 0x00c0, 0x4007: 0x00c0, 0x4008: 0x00c0, 0x4009: 0x00c0, 0x400a: 0x00c0, 0x400b: 0x00c0,
0x400c: 0x00c0, 0x400d: 0x00c0, 0x400e: 0x00c0, 0x400f: 0x00c0, 0x4010: 0x00c0, 0x4011: 0x00c0,
0x4012: 0x00c0, 0x4013: 0x00c0, 0x4014: 0x00c0, 0x4015: 0x00c0, 0x4016: 0x00c0, 0x4017: 0x00c0,
0x4018: 0x00c0, 0x4019: 0x00c0, 0x401a: 0x00c0, 0x401b: 0x00c0, 0x401c: 0x00c0, 0x401d: 0x00c0,
0x401e: 0x00c0, 0x401f: 0x00c0, 0x4020: 0x00c0, 0x4021: 0x00c0, 0x4022: 0x00c0, 0x4023: 0x00c0,
0x4024: 0x00c0, 0x4025: 0x00c0, 0x4026: 0x00c0, 0x4027: 0x00c0, 0x4028: 0x00c0, 0x4029: 0x00c0,
0x402a: 0x00c0, 0x402b: 0x00c0, 0x402c: 0x00c0, 0x402d: 0x00c0, 0x402e: 0x00c0, 0x402f: 0x00c3,
0x4030: 0x00c3, 0x4031: 0x00c3, 0x4032: 0x00c3, 0x4033: 0x00c3, 0x4034: 0x00c3, 0x4035: 0x00c3,
0x4036: 0x00c3, 0x4037: 0x00c3, 0x4038: 0x00c0, 0x4039: 0x00c6, 0x403a: 0x00c3, 0x403b: 0x0080,
// Block 0x101, offset 0x4040
0x4060: 0x00c0, 0x4061: 0x00c0, 0x4062: 0x00c0, 0x4063: 0x00c0,
0x4064: 0x00c0, 0x4065: 0x00c0, 0x4066: 0x00c0, 0x4067: 0x00c0, 0x4068: 0x00c0, 0x4069: 0x00c0,
0x406a: 0x00c0, 0x406b: 0x00c0, 0x406c: 0x00c0, 0x406d: 0x00c0, 0x406e: 0x00c0, 0x406f: 0x00c0,
0x4070: 0x00c0, 0x4071: 0x00c0, 0x4072: 0x00c0, 0x4073: 0x00c0, 0x4074: 0x00c0, 0x4075: 0x00c0,
0x4076: 0x00c0, 0x4077: 0x00c0, 0x4078: 0x00c0, 0x4079: 0x00c0, 0x407a: 0x00c0, 0x407b: 0x00c0,
0x407c: 0x00c0, 0x407d: 0x00c0, 0x407e: 0x00c0, 0x407f: 0x00c0,
// Block 0x102, offset 0x4080
0x4080: 0x00c0, 0x4081: 0x00c0, 0x4082: 0x00c0, 0x4083: 0x00c0, 0x4084: 0x00c0, 0x4085: 0x00c0,
0x4086: 0x00c0, 0x4087: 0x00c0, 0x4088: 0x00c0, 0x4089: 0x00c0, 0x408a: 0x00c0, 0x408b: 0x00c0,
0x408c: 0x00c0, 0x408d: 0x00c0, 0x408e: 0x00c0, 0x408f: 0x00c0, 0x4090: 0x00c0, 0x4091: 0x00c0,
0x4092: 0x00c0, 0x4093: 0x00c0, 0x4094: 0x00c0, 0x4095: 0x00c0, 0x4096: 0x00c0, 0x4097: 0x00c0,
0x4098: 0x00c0, 0x4099: 0x00c0, 0x409a: 0x00c0, 0x409b: 0x00c0, 0x409c: 0x00c0, 0x409d: 0x00c0,
0x409e: 0x00c0, 0x409f: 0x00c0, 0x40a0: 0x00c0, 0x40a1: 0x00c0, 0x40a2: 0x00c0, 0x40a3: 0x00c0,
0x40a4: 0x00c0, 0x40a5: 0x00c0, 0x40a6: 0x00c0, 0x40a7: 0x00c0, 0x40a8: 0x00c0, 0x40a9: 0x00c0,
0x40aa: 0x0080, 0x40ab: 0x0080, 0x40ac: 0x0080, 0x40ad: 0x0080, 0x40ae: 0x0080, 0x40af: 0x0080,
0x40b0: 0x0080, 0x40b1: 0x0080, 0x40b2: 0x0080,
0x40bf: 0x00c0,
// Block 0x103, offset 0x40c0
0x40c0: 0x00c0, 0x40c1: 0x00c0, 0x40c2: 0x00c0, 0x40c3: 0x00c0, 0x40c4: 0x00c0, 0x40c5: 0x00c0,
0x40c6: 0x00c0, 0x40c9: 0x00c0,
0x40cc: 0x00c0, 0x40cd: 0x00c0, 0x40ce: 0x00c0, 0x40cf: 0x00c0, 0x40d0: 0x00c0, 0x40d1: 0x00c0,
0x40d2: 0x00c0, 0x40d3: 0x00c0, 0x40d5: 0x00c0, 0x40d6: 0x00c0,
0x40d8: 0x00c0, 0x40d9: 0x00c0, 0x40da: 0x00c0, 0x40db: 0x00c0, 0x40dc: 0x00c0, 0x40dd: 0x00c0,
0x40de: 0x00c0, 0x40df: 0x00c0, 0x40e0: 0x00c0, 0x40e1: 0x00c0, 0x40e2: 0x00c0, 0x40e3: 0x00c0,
0x40e4: 0x00c0, 0x40e5: 0x00c0, 0x40e6: 0x00c0, 0x40e7: 0x00c0, 0x40e8: 0x00c0, 0x40e9: 0x00c0,
0x40ea: 0x00c0, 0x40eb: 0x00c0, 0x40ec: 0x00c0, 0x40ed: 0x00c0, 0x40ee: 0x00c0, 0x40ef: 0x00c0,
0x40f0: 0x00c0, 0x40f1: 0x00c0, 0x40f2: 0x00c0, 0x40f3: 0x00c0, 0x40f4: 0x00c0, 0x40f5: 0x00c0,
0x40f7: 0x00c0, 0x40f8: 0x00c0, 0x40fb: 0x00c3,
0x40fc: 0x00c3, 0x40fd: 0x00c5, 0x40fe: 0x00c6, 0x40ff: 0x00c0,
// Block 0x104, offset 0x4100
0x4100: 0x00c0, 0x4101: 0x00c0, 0x4102: 0x00c0, 0x4103: 0x00c3, 0x4104: 0x0080, 0x4105: 0x0080,
0x4106: 0x0080,
0x4110: 0x00c0, 0x4111: 0x00c0,
0x4112: 0x00c0, 0x4113: 0x00c0, 0x4114: 0x00c0, 0x4115: 0x00c0, 0x4116: 0x00c0, 0x4117: 0x00c0,
0x4118: 0x00c0, 0x4119: 0x00c0,
// Block 0x105, offset 0x4140
0x4160: 0x00c0, 0x4161: 0x00c0, 0x4162: 0x00c0, 0x4163: 0x00c0,
0x4164: 0x00c0, 0x4165: 0x00c0, 0x4166: 0x00c0, 0x4167: 0x00c0,
0x416a: 0x00c0, 0x416b: 0x00c0, 0x416c: 0x00c0, 0x416d: 0x00c0, 0x416e: 0x00c0, 0x416f: 0x00c0,
0x4170: 0x00c0, 0x4171: 0x00c0, 0x4172: 0x00c0, 0x4173: 0x00c0, 0x4174: 0x00c0, 0x4175: 0x00c0,
0x4176: 0x00c0, 0x4177: 0x00c0, 0x4178: 0x00c0, 0x4179: 0x00c0, 0x417a: 0x00c0, 0x417b: 0x00c0,
0x417c: 0x00c0, 0x417d: 0x00c0, 0x417e: 0x00c0, 0x417f: 0x00c0,
// Block 0x106, offset 0x4180
0x4180: 0x00c0, 0x4181: 0x00c0, 0x4182: 0x00c0, 0x4183: 0x00c0, 0x4184: 0x00c0, 0x4185: 0x00c0,
0x4186: 0x00c0, 0x4187: 0x00c0, 0x4188: 0x00c0, 0x4189: 0x00c0, 0x418a: 0x00c0, 0x418b: 0x00c0,
0x418c: 0x00c0, 0x418d: 0x00c0, 0x418e: 0x00c0, 0x418f: 0x00c0, 0x4190: 0x00c0, 0x4191: 0x00c0,
0x4192: 0x00c0, 0x4193: 0x00c0, 0x4194: 0x00c3, 0x4195: 0x00c3, 0x4196: 0x00c3, 0x4197: 0x00c3,
0x419a: 0x00c3, 0x419b: 0x00c3, 0x419c: 0x00c0, 0x419d: 0x00c0,
0x419e: 0x00c0, 0x419f: 0x00c0, 0x41a0: 0x00c6, 0x41a1: 0x00c0, 0x41a2: 0x0080, 0x41a3: 0x00c0,
0x41a4: 0x00c0,
// Block 0x107, offset 0x41c0
0x41c0: 0x00c0, 0x41c1: 0x00c3, 0x41c2: 0x00c3, 0x41c3: 0x00c3, 0x41c4: 0x00c3, 0x41c5: 0x00c3,
0x41c6: 0x00c3, 0x41c7: 0x00c3, 0x41c8: 0x00c3, 0x41c9: 0x00c3, 0x41ca: 0x00c3, 0x41cb: 0x00c0,
0x41cc: 0x00c0, 0x41cd: 0x00c0, 0x41ce: 0x00c0, 0x41cf: 0x00c0, 0x41d0: 0x00c0, 0x41d1: 0x00c0,
0x41d2: 0x00c0, 0x41d3: 0x00c0, 0x41d4: 0x00c0, 0x41d5: 0x00c0, 0x41d6: 0x00c0, 0x41d7: 0x00c0,
0x41d8: 0x00c0, 0x41d9: 0x00c0, 0x41da: 0x00c0, 0x41db: 0x00c0, 0x41dc: 0x00c0, 0x41dd: 0x00c0,
0x41de: 0x00c0, 0x41df: 0x00c0, 0x41e0: 0x00c0, 0x41e1: 0x00c0, 0x41e2: 0x00c0, 0x41e3: 0x00c0,
0x41e4: 0x00c0, 0x41e5: 0x00c0, 0x41e6: 0x00c0, 0x41e7: 0x00c0, 0x41e8: 0x00c0, 0x41e9: 0x00c0,
0x41ea: 0x00c0, 0x41eb: 0x00c0, 0x41ec: 0x00c0, 0x41ed: 0x00c0, 0x41ee: 0x00c0, 0x41ef: 0x00c0,
0x41f0: 0x00c0, 0x41f1: 0x00c0, 0x41f2: 0x00c0, 0x41f3: 0x00c3, 0x41f4: 0x00c6, 0x41f5: 0x00c3,
0x41f6: 0x00c3, 0x41f7: 0x00c3, 0x41f8: 0x00c3, 0x41f9: 0x00c0, 0x41fa: 0x00c0, 0x41fb: 0x00c3,
0x41fc: 0x00c3, 0x41fd: 0x00c3, 0x41fe: 0x00c3, 0x41ff: 0x0080,
// Block 0x108, offset 0x4200
0x4200: 0x0080, 0x4201: 0x0080, 0x4202: 0x0080, 0x4203: 0x0080, 0x4204: 0x0080, 0x4205: 0x0080,
0x4206: 0x0080, 0x4207: 0x00c6,
0x4210: 0x00c0, 0x4211: 0x00c3,
0x4212: 0x00c3, 0x4213: 0x00c3, 0x4214: 0x00c3, 0x4215: 0x00c3, 0x4216: 0x00c3, 0x4217: 0x00c0,
0x4218: 0x00c0, 0x4219: 0x00c3, 0x421a: 0x00c3, 0x421b: 0x00c3, 0x421c: 0x00c0, 0x421d: 0x00c0,
0x421e: 0x00c0, 0x421f: 0x00c0, 0x4220: 0x00c0, 0x4221: 0x00c0, 0x4222: 0x00c0, 0x4223: 0x00c0,
0x4224: 0x00c0, 0x4225: 0x00c0, 0x4226: 0x00c0, 0x4227: 0x00c0, 0x4228: 0x00c0, 0x4229: 0x00c0,
0x422a: 0x00c0, 0x422b: 0x00c0, 0x422c: 0x00c0, 0x422d: 0x00c0, 0x422e: 0x00c0, 0x422f: 0x00c0,
0x4230: 0x00c0, 0x4231: 0x00c0, 0x4232: 0x00c0, 0x4233: 0x00c0, 0x4234: 0x00c0, 0x4235: 0x00c0,
0x4236: 0x00c0, 0x4237: 0x00c0, 0x4238: 0x00c0, 0x4239: 0x00c0, 0x423a: 0x00c0, 0x423b: 0x00c0,
0x423c: 0x00c0, 0x423d: 0x00c0, 0x423e: 0x00c0, 0x423f: 0x00c0,
// Block 0x109, offset 0x4240
0x4240: 0x00c0, 0x4241: 0x00c0, 0x4242: 0x00c0, 0x4243: 0x00c0, 0x4244: 0x00c0, 0x4245: 0x00c0,
0x4246: 0x00c0, 0x4247: 0x00c0, 0x4248: 0x00c0, 0x4249: 0x00c0, 0x424a: 0x00c3, 0x424b: 0x00c3,
0x424c: 0x00c3, 0x424d: 0x00c3, 0x424e: 0x00c3, 0x424f: 0x00c3, 0x4250: 0x00c3, 0x4251: 0x00c3,
0x4252: 0x00c3, 0x4253: 0x00c3, 0x4254: 0x00c3, 0x4255: 0x00c3, 0x4256: 0x00c3, 0x4257: 0x00c0,
0x4258: 0x00c3, 0x4259: 0x00c6, 0x425a: 0x0080, 0x425b: 0x0080, 0x425c: 0x0080, 0x425d: 0x00c0,
0x425e: 0x0080, 0x425f: 0x0080, 0x4260: 0x0080, 0x4261: 0x0080, 0x4262: 0x0080,
0x4270: 0x00c0, 0x4271: 0x00c0, 0x4272: 0x00c0, 0x4273: 0x00c0, 0x4274: 0x00c0, 0x4275: 0x00c0,
0x4276: 0x00c0, 0x4277: 0x00c0, 0x4278: 0x00c0, 0x4279: 0x00c0, 0x427a: 0x00c0, 0x427b: 0x00c0,
0x427c: 0x00c0, 0x427d: 0x00c0, 0x427e: 0x00c0, 0x427f: 0x00c0,
// Block 0x10a, offset 0x4280
0x4280: 0x00c0, 0x4281: 0x00c0, 0x4282: 0x00c0, 0x4283: 0x00c0, 0x4284: 0x00c0, 0x4285: 0x00c0,
0x4286: 0x00c0, 0x4287: 0x00c0, 0x4288: 0x00c0, 0x4289: 0x00c0, 0x428a: 0x00c0, 0x428b: 0x00c0,
0x428c: 0x00c0, 0x428d: 0x00c0, 0x428e: 0x00c0, 0x428f: 0x00c0, 0x4290: 0x00c0, 0x4291: 0x00c0,
0x4292: 0x00c0, 0x4293: 0x00c0, 0x4294: 0x00c0, 0x4295: 0x00c0, 0x4296: 0x00c0, 0x4297: 0x00c0,
0x4298: 0x00c0, 0x4299: 0x00c0, 0x429a: 0x00c0, 0x429b: 0x00c0, 0x429c: 0x00c0, 0x429d: 0x00c0,
0x429e: 0x00c0, 0x429f: 0x00c0, 0x42a0: 0x00c0, 0x42a1: 0x00c0, 0x42a2: 0x00c0, 0x42a3: 0x00c0,
0x42a4: 0x00c0, 0x42a5: 0x00c0, 0x42a6: 0x00c0, 0x42a7: 0x00c0, 0x42a8: 0x00c0, 0x42a9: 0x00c0,
0x42aa: 0x00c0, 0x42ab: 0x00c0, 0x42ac: 0x00c0, 0x42ad: 0x00c0, 0x42ae: 0x00c0, 0x42af: 0x00c0,
0x42b0: 0x00c0, 0x42b1: 0x00c0, 0x42b2: 0x00c0, 0x42b3: 0x00c0, 0x42b4: 0x00c0, 0x42b5: 0x00c0,
0x42b6: 0x00c0, 0x42b7: 0x00c0, 0x42b8: 0x00c0,
// Block 0x10b, offset 0x42c0
0x42c0: 0x0080, 0x42c1: 0x0080, 0x42c2: 0x0080, 0x42c3: 0x0080, 0x42c4: 0x0080, 0x42c5: 0x0080,
0x42c6: 0x0080, 0x42c7: 0x0080, 0x42c8: 0x0080, 0x42c9: 0x0080,
// Block 0x10c, offset 0x4300
0x4300: 0x00c0, 0x4301: 0x00c0, 0x4302: 0x00c0, 0x4303: 0x00c0, 0x4304: 0x00c0, 0x4305: 0x00c0,
0x4306: 0x00c0, 0x4307: 0x00c0, 0x4308: 0x00c0, 0x430a: 0x00c0, 0x430b: 0x00c0,
0x430c: 0x00c0, 0x430d: 0x00c0, 0x430e: 0x00c0, 0x430f: 0x00c0, 0x4310: 0x00c0, 0x4311: 0x00c0,
0x4312: 0x00c0, 0x4313: 0x00c0, 0x4314: 0x00c0, 0x4315: 0x00c0, 0x4316: 0x00c0, 0x4317: 0x00c0,
0x4318: 0x00c0, 0x4319: 0x00c0, 0x431a: 0x00c0, 0x431b: 0x00c0, 0x431c: 0x00c0, 0x431d: 0x00c0,
0x431e: 0x00c0, 0x431f: 0x00c0, 0x4320: 0x00c0, 0x4321: 0x00c0, 0x4322: 0x00c0, 0x4323: 0x00c0,
0x4324: 0x00c0, 0x4325: 0x00c0, 0x4326: 0x00c0, 0x4327: 0x00c0, 0x4328: 0x00c0, 0x4329: 0x00c0,
0x432a: 0x00c0, 0x432b: 0x00c0, 0x432c: 0x00c0, 0x432d: 0x00c0, 0x432e: 0x00c0, 0x432f: 0x00c0,
0x4330: 0x00c3, 0x4331: 0x00c3, 0x4332: 0x00c3, 0x4333: 0x00c3, 0x4334: 0x00c3, 0x4335: 0x00c3,
0x4336: 0x00c3, 0x4338: 0x00c3, 0x4339: 0x00c3, 0x433a: 0x00c3, 0x433b: 0x00c3,
0x433c: 0x00c3, 0x433d: 0x00c3, 0x433e: 0x00c0, 0x433f: 0x00c6,
// Block 0x10d, offset 0x4340
0x4340: 0x00c0, 0x4341: 0x0080, 0x4342: 0x0080, 0x4343: 0x0080, 0x4344: 0x0080, 0x4345: 0x0080,
0x4350: 0x00c0, 0x4351: 0x00c0,
0x4352: 0x00c0, 0x4353: 0x00c0, 0x4354: 0x00c0, 0x4355: 0x00c0, 0x4356: 0x00c0, 0x4357: 0x00c0,
0x4358: 0x00c0, 0x4359: 0x00c0, 0x435a: 0x0080, 0x435b: 0x0080, 0x435c: 0x0080, 0x435d: 0x0080,
0x435e: 0x0080, 0x435f: 0x0080, 0x4360: 0x0080, 0x4361: 0x0080, 0x4362: 0x0080, 0x4363: 0x0080,
0x4364: 0x0080, 0x4365: 0x0080, 0x4366: 0x0080, 0x4367: 0x0080, 0x4368: 0x0080, 0x4369: 0x0080,
0x436a: 0x0080, 0x436b: 0x0080, 0x436c: 0x0080,
0x4370: 0x0080, 0x4371: 0x0080, 0x4372: 0x00c0, 0x4373: 0x00c0, 0x4374: 0x00c0, 0x4375: 0x00c0,
0x4376: 0x00c0, 0x4377: 0x00c0, 0x4378: 0x00c0, 0x4379: 0x00c0, 0x437a: 0x00c0, 0x437b: 0x00c0,
0x437c: 0x00c0, 0x437d: 0x00c0, 0x437e: 0x00c0, 0x437f: 0x00c0,
// Block 0x10e, offset 0x4380
0x4380: 0x00c0, 0x4381: 0x00c0, 0x4382: 0x00c0, 0x4383: 0x00c0, 0x4384: 0x00c0, 0x4385: 0x00c0,
0x4386: 0x00c0, 0x4387: 0x00c0, 0x4388: 0x00c0, 0x4389: 0x00c0, 0x438a: 0x00c0, 0x438b: 0x00c0,
0x438c: 0x00c0, 0x438d: 0x00c0, 0x438e: 0x00c0, 0x438f: 0x00c0,
0x4392: 0x00c3, 0x4393: 0x00c3, 0x4394: 0x00c3, 0x4395: 0x00c3, 0x4396: 0x00c3, 0x4397: 0x00c3,
0x4398: 0x00c3, 0x4399: 0x00c3, 0x439a: 0x00c3, 0x439b: 0x00c3, 0x439c: 0x00c3, 0x439d: 0x00c3,
0x439e: 0x00c3, 0x439f: 0x00c3, 0x43a0: 0x00c3, 0x43a1: 0x00c3, 0x43a2: 0x00c3, 0x43a3: 0x00c3,
0x43a4: 0x00c3, 0x43a5: 0x00c3, 0x43a6: 0x00c3, 0x43a7: 0x00c3, 0x43a9: 0x00c0,
0x43aa: 0x00c3, 0x43ab: 0x00c3, 0x43ac: 0x00c3, 0x43ad: 0x00c3, 0x43ae: 0x00c3, 0x43af: 0x00c3,
0x43b0: 0x00c3, 0x43b1: 0x00c0, 0x43b2: 0x00c3, 0x43b3: 0x00c3, 0x43b4: 0x00c0, 0x43b5: 0x00c3,
0x43b6: 0x00c3,
// Block 0x10f, offset 0x43c0
0x43c0: 0x00c0, 0x43c1: 0x00c0, 0x43c2: 0x00c0, 0x43c3: 0x00c0, 0x43c4: 0x00c0, 0x43c5: 0x00c0,
0x43c6: 0x00c0, 0x43c8: 0x00c0, 0x43c9: 0x00c0, 0x43cb: 0x00c0,
0x43cc: 0x00c0, 0x43cd: 0x00c0, 0x43ce: 0x00c0, 0x43cf: 0x00c0, 0x43d0: 0x00c0, 0x43d1: 0x00c0,
0x43d2: 0x00c0, 0x43d3: 0x00c0, 0x43d4: 0x00c0, 0x43d5: 0x00c0, 0x43d6: 0x00c0, 0x43d7: 0x00c0,
0x43d8: 0x00c0, 0x43d9: 0x00c0, 0x43da: 0x00c0, 0x43db: 0x00c0, 0x43dc: 0x00c0, 0x43dd: 0x00c0,
0x43de: 0x00c0, 0x43df: 0x00c0, 0x43e0: 0x00c0, 0x43e1: 0x00c0, 0x43e2: 0x00c0, 0x43e3: 0x00c0,
0x43e4: 0x00c0, 0x43e5: 0x00c0, 0x43e6: 0x00c0, 0x43e7: 0x00c0, 0x43e8: 0x00c0, 0x43e9: 0x00c0,
0x43ea: 0x00c0, 0x43eb: 0x00c0, 0x43ec: 0x00c0, 0x43ed: 0x00c0, 0x43ee: 0x00c0, 0x43ef: 0x00c0,
0x43f0: 0x00c0, 0x43f1: 0x00c3, 0x43f2: 0x00c3, 0x43f3: 0x00c3, 0x43f4: 0x00c3, 0x43f5: 0x00c3,
0x43f6: 0x00c3, 0x43fa: 0x00c3,
0x43fc: 0x00c3, 0x43fd: 0x00c3, 0x43ff: 0x00c3,
// Block 0x110, offset 0x4400
0x4400: 0x00c3, 0x4401: 0x00c3, 0x4402: 0x00c3, 0x4403: 0x00c3, 0x4404: 0x00c6, 0x4405: 0x00c6,
0x4406: 0x00c0, 0x4407: 0x00c3,
0x4410: 0x00c0, 0x4411: 0x00c0,
0x4412: 0x00c0, 0x4413: 0x00c0, 0x4414: 0x00c0, 0x4415: 0x00c0, 0x4416: 0x00c0, 0x4417: 0x00c0,
0x4418: 0x00c0, 0x4419: 0x00c0,
0x4420: 0x00c0, 0x4421: 0x00c0, 0x4422: 0x00c0, 0x4423: 0x00c0,
0x4424: 0x00c0, 0x4425: 0x00c0, 0x4427: 0x00c0, 0x4428: 0x00c0,
0x442a: 0x00c0, 0x442b: 0x00c0, 0x442c: 0x00c0, 0x442d: 0x00c0, 0x442e: 0x00c0, 0x442f: 0x00c0,
0x4430: 0x00c0, 0x4431: 0x00c0, 0x4432: 0x00c0, 0x4433: 0x00c0, 0x4434: 0x00c0, 0x4435: 0x00c0,
0x4436: 0x00c0, 0x4437: 0x00c0, 0x4438: 0x00c0, 0x4439: 0x00c0, 0x443a: 0x00c0, 0x443b: 0x00c0,
0x443c: 0x00c0, 0x443d: 0x00c0, 0x443e: 0x00c0, 0x443f: 0x00c0,
// Block 0x111, offset 0x4440
0x4440: 0x00c0, 0x4441: 0x00c0, 0x4442: 0x00c0, 0x4443: 0x00c0, 0x4444: 0x00c0, 0x4445: 0x00c0,
0x4446: 0x00c0, 0x4447: 0x00c0, 0x4448: 0x00c0, 0x4449: 0x00c0, 0x444a: 0x00c0, 0x444b: 0x00c0,
0x444c: 0x00c0, 0x444d: 0x00c0, 0x444e: 0x00c0, 0x4450: 0x00c3, 0x4451: 0x00c3,
0x4453: 0x00c0, 0x4454: 0x00c0, 0x4455: 0x00c3, 0x4456: 0x00c0, 0x4457: 0x00c6,
0x4458: 0x00c0,
0x4460: 0x00c0, 0x4461: 0x00c0, 0x4462: 0x00c0, 0x4463: 0x00c0,
0x4464: 0x00c0, 0x4465: 0x00c0, 0x4466: 0x00c0, 0x4467: 0x00c0, 0x4468: 0x00c0, 0x4469: 0x00c0,
// Block 0x112, offset 0x4480
0x44a0: 0x00c0, 0x44a1: 0x00c0, 0x44a2: 0x00c0, 0x44a3: 0x00c0,
0x44a4: 0x00c0, 0x44a5: 0x00c0, 0x44a6: 0x00c0, 0x44a7: 0x00c0, 0x44a8: 0x00c0, 0x44a9: 0x00c0,
0x44aa: 0x00c0, 0x44ab: 0x00c0, 0x44ac: 0x00c0, 0x44ad: 0x00c0, 0x44ae: 0x00c0, 0x44af: 0x00c0,
0x44b0: 0x00c0, 0x44b1: 0x00c0, 0x44b2: 0x00c0, 0x44b3: 0x00c3, 0x44b4: 0x00c3, 0x44b5: 0x00c0,
0x44b6: 0x00c0, 0x44b7: 0x0080, 0x44b8: 0x0080,
// Block 0x113, offset 0x44c0
0x44c0: 0x00c3, 0x44c1: 0x00c3, 0x44c2: 0x00c0, 0x44c3: 0x00c0, 0x44c4: 0x00c0, 0x44c5: 0x00c0,
0x44c6: 0x00c0, 0x44c7: 0x00c0, 0x44c8: 0x00c0, 0x44c9: 0x00c0, 0x44ca: 0x00c0, 0x44cb: 0x00c0,
0x44cc: 0x00c0, 0x44cd: 0x00c0, 0x44ce: 0x00c0, 0x44cf: 0x00c0, 0x44d0: 0x00c0,
0x44d2: 0x00c0, 0x44d3: 0x00c0, 0x44d4: 0x00c0, 0x44d5: 0x00c0, 0x44d6: 0x00c0, 0x44d7: 0x00c0,
0x44d8: 0x00c0, 0x44d9: 0x00c0, 0x44da: 0x00c0, 0x44db: 0x00c0, 0x44dc: 0x00c0, 0x44dd: 0x00c0,
0x44de: 0x00c0, 0x44df: 0x00c0, 0x44e0: 0x00c0, 0x44e1: 0x00c0, 0x44e2: 0x00c0, 0x44e3: 0x00c0,
0x44e4: 0x00c0, 0x44e5: 0x00c0, 0x44e6: 0x00c0, 0x44e7: 0x00c0, 0x44e8: 0x00c0, 0x44e9: 0x00c0,
0x44ea: 0x00c0, 0x44eb: 0x00c0, 0x44ec: 0x00c0, 0x44ed: 0x00c0, 0x44ee: 0x00c0, 0x44ef: 0x00c0,
0x44f0: 0x00c0, 0x44f1: 0x00c0, 0x44f2: 0x00c0, 0x44f3: 0x00c0, 0x44f4: 0x00c0, 0x44f5: 0x00c0,
0x44f6: 0x00c3, 0x44f7: 0x00c3, 0x44f8: 0x00c3, 0x44f9: 0x00c3, 0x44fa: 0x00c3,
0x44fe: 0x00c0, 0x44ff: 0x00c0,
// Block 0x114, offset 0x4500
0x4500: 0x00c3, 0x4501: 0x00c5, 0x4502: 0x00c6, 0x4503: 0x0080, 0x4504: 0x0080, 0x4505: 0x0080,
0x4506: 0x0080, 0x4507: 0x0080, 0x4508: 0x0080, 0x4509: 0x0080, 0x450a: 0x0080, 0x450b: 0x0080,
0x450c: 0x0080, 0x450d: 0x0080, 0x450e: 0x0080, 0x450f: 0x0080, 0x4510: 0x00c0, 0x4511: 0x00c0,
0x4512: 0x00c0, 0x4513: 0x00c0, 0x4514: 0x00c0, 0x4515: 0x00c0, 0x4516: 0x00c0, 0x4517: 0x00c0,
0x4518: 0x00c0, 0x4519: 0x00c0,
// Block 0x115, offset 0x4540
0x4570: 0x00c0,
// Block 0x116, offset 0x4580
0x4580: 0x0080, 0x4581: 0x0080, 0x4582: 0x0080, 0x4583: 0x0080, 0x4584: 0x0080, 0x4585: 0x0080,
0x4586: 0x0080, 0x4587: 0x0080, 0x4588: 0x0080, 0x4589: 0x0080, 0x458a: 0x0080, 0x458b: 0x0080,
0x458c: 0x0080, 0x458d: 0x0080, 0x458e: 0x0080, 0x458f: 0x0080, 0x4590: 0x0080, 0x4591: 0x0080,
0x4592: 0x0080, 0x4593: 0x0080, 0x4594: 0x0080, 0x4595: 0x0080, 0x4596: 0x0080, 0x4597: 0x0080,
0x4598: 0x0080, 0x4599: 0x0080, 0x459a: 0x0080, 0x459b: 0x0080, 0x459c: 0x0080, 0x459d: 0x0080,
0x459e: 0x0080, 0x459f: 0x0080, 0x45a0: 0x0080, 0x45a1: 0x0080, 0x45a2: 0x0080, 0x45a3: 0x0080,
0x45a4: 0x0080, 0x45a5: 0x0080, 0x45a6: 0x0080, 0x45a7: 0x0080, 0x45a8: 0x0080, 0x45a9: 0x0080,
0x45aa: 0x0080, 0x45ab: 0x0080, 0x45ac: 0x0080, 0x45ad: 0x0080, 0x45ae: 0x0080, 0x45af: 0x0080,
0x45b0: 0x0080, 0x45b1: 0x0080,
0x45bf: 0x0080,
// Block 0x117, offset 0x45c0
0x45c0: 0x00c0, 0x45c1: 0x00c0, 0x45c2: 0x00c0, 0x45c3: 0x00c0, 0x45c4: 0x00c0, 0x45c5: 0x00c0,
0x45c6: 0x00c0, 0x45c7: 0x00c0, 0x45c8: 0x00c0, 0x45c9: 0x00c0, 0x45ca: 0x00c0, 0x45cb: 0x00c0,
0x45cc: 0x00c0, 0x45cd: 0x00c0, 0x45ce: 0x00c0, 0x45cf: 0x00c0, 0x45d0: 0x00c0, 0x45d1: 0x00c0,
0x45d2: 0x00c0, 0x45d3: 0x00c0, 0x45d4: 0x00c0, 0x45d5: 0x00c0, 0x45d6: 0x00c0, 0x45d7: 0x00c0,
0x45d8: 0x00c0, 0x45d9: 0x00c0,
// Block 0x118, offset 0x4600
0x4600: 0x0080, 0x4601: 0x0080, 0x4602: 0x0080, 0x4603: 0x0080, 0x4604: 0x0080, 0x4605: 0x0080,
0x4606: 0x0080, 0x4607: 0x0080, 0x4608: 0x0080, 0x4609: 0x0080, 0x460a: 0x0080, 0x460b: 0x0080,
0x460c: 0x0080, 0x460d: 0x0080, 0x460e: 0x0080, 0x460f: 0x0080, 0x4610: 0x0080, 0x4611: 0x0080,
0x4612: 0x0080, 0x4613: 0x0080, 0x4614: 0x0080, 0x4615: 0x0080, 0x4616: 0x0080, 0x4617: 0x0080,
0x4618: 0x0080, 0x4619: 0x0080, 0x461a: 0x0080, 0x461b: 0x0080, 0x461c: 0x0080, 0x461d: 0x0080,
0x461e: 0x0080, 0x461f: 0x0080, 0x4620: 0x0080, 0x4621: 0x0080, 0x4622: 0x0080, 0x4623: 0x0080,
0x4624: 0x0080, 0x4625: 0x0080, 0x4626: 0x0080, 0x4627: 0x0080, 0x4628: 0x0080, 0x4629: 0x0080,
0x462a: 0x0080, 0x462b: 0x0080, 0x462c: 0x0080, 0x462d: 0x0080, 0x462e: 0x0080,
0x4630: 0x0080, 0x4631: 0x0080, 0x4632: 0x0080, 0x4633: 0x0080, 0x4634: 0x0080,
// Block 0x119, offset 0x4640
0x4640: 0x00c0, 0x4641: 0x00c0, 0x4642: 0x00c0, 0x4643: 0x00c0,
// Block 0x11a, offset 0x4680
0x4690: 0x00c0, 0x4691: 0x00c0,
0x4692: 0x00c0, 0x4693: 0x00c0, 0x4694: 0x00c0, 0x4695: 0x00c0, 0x4696: 0x00c0, 0x4697: 0x00c0,
0x4698: 0x00c0, 0x4699: 0x00c0, 0x469a: 0x00c0, 0x469b: 0x00c0, 0x469c: 0x00c0, 0x469d: 0x00c0,
0x469e: 0x00c0, 0x469f: 0x00c0, 0x46a0: 0x00c0, 0x46a1: 0x00c0, 0x46a2: 0x00c0, 0x46a3: 0x00c0,
0x46a4: 0x00c0, 0x46a5: 0x00c0, 0x46a6: 0x00c0, 0x46a7: 0x00c0, 0x46a8: 0x00c0, 0x46a9: 0x00c0,
0x46aa: 0x00c0, 0x46ab: 0x00c0, 0x46ac: 0x00c0, 0x46ad: 0x00c0, 0x46ae: 0x00c0, 0x46af: 0x00c0,
0x46b0: 0x00c0, 0x46b1: 0x00c0, 0x46b2: 0x00c0, 0x46b3: 0x00c0, 0x46b4: 0x00c0, 0x46b5: 0x00c0,
0x46b6: 0x00c0, 0x46b7: 0x00c0, 0x46b8: 0x00c0, 0x46b9: 0x00c0, 0x46ba: 0x00c0, 0x46bb: 0x00c0,
0x46bc: 0x00c0, 0x46bd: 0x00c0, 0x46be: 0x00c0, 0x46bf: 0x00c0,
// Block 0x11b, offset 0x46c0
0x46c0: 0x00c0, 0x46c1: 0x00c0, 0x46c2: 0x00c0, 0x46c3: 0x00c0, 0x46c4: 0x00c0, 0x46c5: 0x00c0,
0x46c6: 0x00c0, 0x46c7: 0x00c0, 0x46c8: 0x00c0, 0x46c9: 0x00c0, 0x46ca: 0x00c0, 0x46cb: 0x00c0,
0x46cc: 0x00c0, 0x46cd: 0x00c0, 0x46ce: 0x00c0, 0x46cf: 0x00c0, 0x46d0: 0x00c0, 0x46d1: 0x00c0,
0x46d2: 0x00c0, 0x46d3: 0x00c0, 0x46d4: 0x00c0, 0x46d5: 0x00c0, 0x46d6: 0x00c0, 0x46d7: 0x00c0,
0x46d8: 0x00c0, 0x46d9: 0x00c0, 0x46da: 0x00c0, 0x46db: 0x00c0, 0x46dc: 0x00c0, 0x46dd: 0x00c0,
0x46de: 0x00c0, 0x46df: 0x00c0, 0x46e0: 0x00c0, 0x46e1: 0x00c0, 0x46e2: 0x00c0, 0x46e3: 0x00c0,
0x46e4: 0x00c0, 0x46e5: 0x00c0, 0x46e6: 0x00c0, 0x46e7: 0x00c0, 0x46e8: 0x00c0, 0x46e9: 0x00c0,
0x46ea: 0x00c0, 0x46eb: 0x00c0, 0x46ec: 0x00c0, 0x46ed: 0x00c0, 0x46ee: 0x00c0, 0x46ef: 0x00c0,
0x46f0: 0x00c0, 0x46f1: 0x0080, 0x46f2: 0x0080,
// Block 0x11c, offset 0x4700
0x4700: 0x00c0, 0x4701: 0x00c0, 0x4702: 0x00c0, 0x4703: 0x00c0, 0x4704: 0x00c0, 0x4705: 0x00c0,
0x4706: 0x00c0, 0x4707: 0x00c0, 0x4708: 0x00c0, 0x4709: 0x00c0, 0x470a: 0x00c0, 0x470b: 0x00c0,
0x470c: 0x00c0, 0x470d: 0x00c0, 0x470e: 0x00c0, 0x470f: 0x00c0, 0x4710: 0x00c0, 0x4711: 0x00c0,
0x4712: 0x00c0, 0x4713: 0x00c0, 0x4714: 0x00c0, 0x4715: 0x00c0, 0x4716: 0x00c0, 0x4717: 0x00c0,
0x4718: 0x00c0, 0x4719: 0x00c0, 0x471a: 0x00c0, 0x471b: 0x00c0, 0x471c: 0x00c0, 0x471d: 0x00c0,
0x471e: 0x00c0, 0x471f: 0x00c0, 0x4720: 0x00c0, 0x4721: 0x00c0, 0x4722: 0x00c0, 0x4723: 0x00c0,
0x4724: 0x00c0, 0x4725: 0x00c0, 0x4726: 0x00c0, 0x4727: 0x00c0, 0x4728: 0x00c0, 0x4729: 0x00c0,
0x472a: 0x00c0, 0x472b: 0x00c0, 0x472c: 0x00c0, 0x472d: 0x00c0, 0x472e: 0x00c0, 0x472f: 0x00c0,
0x4730: 0x0040, 0x4731: 0x0040, 0x4732: 0x0040, 0x4733: 0x0040, 0x4734: 0x0040, 0x4735: 0x0040,
0x4736: 0x0040, 0x4737: 0x0040, 0x4738: 0x0040, 0x4739: 0x0040, 0x473a: 0x0040, 0x473b: 0x0040,
0x473c: 0x0040, 0x473d: 0x0040, 0x473e: 0x0040, 0x473f: 0x0040,
// Block 0x11d, offset 0x4740
0x4740: 0x00c3, 0x4741: 0x00c0, 0x4742: 0x00c0, 0x4743: 0x00c0, 0x4744: 0x00c0, 0x4745: 0x00c0,
0x4746: 0x00c0, 0x4747: 0x00c3, 0x4748: 0x00c3, 0x4749: 0x00c3, 0x474a: 0x00c3, 0x474b: 0x00c3,
0x474c: 0x00c3, 0x474d: 0x00c3, 0x474e: 0x00c3, 0x474f: 0x00c3, 0x4750: 0x00c3, 0x4751: 0x00c3,
0x4752: 0x00c3, 0x4753: 0x00c3, 0x4754: 0x00c3, 0x4755: 0x00c3,
// Block 0x11e, offset 0x4780
0x4780: 0x00c0, 0x4781: 0x00c0, 0x4782: 0x00c0, 0x4783: 0x00c0, 0x4784: 0x00c0, 0x4785: 0x00c0,
0x4786: 0x00c0, 0x4787: 0x00c0, 0x4788: 0x00c0, 0x4789: 0x00c0, 0x478a: 0x00c0, 0x478b: 0x00c0,
0x478c: 0x00c0, 0x478d: 0x00c0, 0x478e: 0x00c0, 0x478f: 0x00c0, 0x4790: 0x00c0, 0x4791: 0x00c0,
0x4792: 0x00c0, 0x4793: 0x00c0, 0x4794: 0x00c0, 0x4795: 0x00c0, 0x4796: 0x00c0, 0x4797: 0x00c0,
0x4798: 0x00c0, 0x4799: 0x00c0, 0x479a: 0x00c0, 0x479b: 0x00c0, 0x479c: 0x00c0, 0x479d: 0x00c0,
0x479e: 0x00c0, 0x47a0: 0x00c0, 0x47a1: 0x00c0, 0x47a2: 0x00c0, 0x47a3: 0x00c0,
0x47a4: 0x00c0, 0x47a5: 0x00c0, 0x47a6: 0x00c0, 0x47a7: 0x00c0, 0x47a8: 0x00c0, 0x47a9: 0x00c0,
0x47ae: 0x0080, 0x47af: 0x0080,
0x47b0: 0x00c0, 0x47b1: 0x00c0, 0x47b2: 0x00c0, 0x47b3: 0x00c0, 0x47b4: 0x00c0, 0x47b5: 0x00c0,
0x47b6: 0x00c0, 0x47b7: 0x00c0, 0x47b8: 0x00c0, 0x47b9: 0x00c0, 0x47ba: 0x00c0, 0x47bb: 0x00c0,
0x47bc: 0x00c0, 0x47bd: 0x00c0, 0x47be: 0x00c0, 0x47bf: 0x00c0,
// Block 0x11f, offset 0x47c0
0x47c0: 0x00c0, 0x47c1: 0x00c0, 0x47c2: 0x00c0, 0x47c3: 0x00c0, 0x47c4: 0x00c0, 0x47c5: 0x00c0,
0x47c6: 0x00c0, 0x47c7: 0x00c0, 0x47c8: 0x00c0, 0x47c9: 0x00c0, 0x47ca: 0x00c0, 0x47cb: 0x00c0,
0x47cc: 0x00c0, 0x47cd: 0x00c0, 0x47ce: 0x00c0, 0x47cf: 0x00c0, 0x47d0: 0x00c0, 0x47d1: 0x00c0,
0x47d2: 0x00c0, 0x47d3: 0x00c0, 0x47d4: 0x00c0, 0x47d5: 0x00c0, 0x47d6: 0x00c0, 0x47d7: 0x00c0,
0x47d8: 0x00c0, 0x47d9: 0x00c0, 0x47da: 0x00c0, 0x47db: 0x00c0, 0x47dc: 0x00c0, 0x47dd: 0x00c0,
0x47de: 0x00c0, 0x47df: 0x00c0, 0x47e0: 0x00c0, 0x47e1: 0x00c0, 0x47e2: 0x00c0, 0x47e3: 0x00c0,
0x47e4: 0x00c0, 0x47e5: 0x00c0, 0x47e6: 0x00c0, 0x47e7: 0x00c0, 0x47e8: 0x00c0, 0x47e9: 0x00c0,
0x47ea: 0x00c0, 0x47eb: 0x00c0, 0x47ec: 0x00c0, 0x47ed: 0x00c0, 0x47ee: 0x00c0, 0x47ef: 0x00c0,
0x47f0: 0x00c0, 0x47f1: 0x00c0, 0x47f2: 0x00c0, 0x47f3: 0x00c0, 0x47f4: 0x00c0, 0x47f5: 0x00c0,
0x47f6: 0x00c0, 0x47f7: 0x00c0, 0x47f8: 0x00c0, 0x47f9: 0x00c0, 0x47fa: 0x00c0, 0x47fb: 0x00c0,
0x47fc: 0x00c0, 0x47fd: 0x00c0, 0x47fe: 0x00c0,
// Block 0x120, offset 0x4800
0x4800: 0x00c0, 0x4801: 0x00c0, 0x4802: 0x00c0, 0x4803: 0x00c0, 0x4804: 0x00c0, 0x4805: 0x00c0,
0x4806: 0x00c0, 0x4807: 0x00c0, 0x4808: 0x00c0, 0x4809: 0x00c0,
0x4810: 0x00c0, 0x4811: 0x00c0,
0x4812: 0x00c0, 0x4813: 0x00c0, 0x4814: 0x00c0, 0x4815: 0x00c0, 0x4816: 0x00c0, 0x4817: 0x00c0,
0x4818: 0x00c0, 0x4819: 0x00c0, 0x481a: 0x00c0, 0x481b: 0x00c0, 0x481c: 0x00c0, 0x481d: 0x00c0,
0x481e: 0x00c0, 0x481f: 0x00c0, 0x4820: 0x00c0, 0x4821: 0x00c0, 0x4822: 0x00c0, 0x4823: 0x00c0,
0x4824: 0x00c0, 0x4825: 0x00c0, 0x4826: 0x00c0, 0x4827: 0x00c0, 0x4828: 0x00c0, 0x4829: 0x00c0,
0x482a: 0x00c0, 0x482b: 0x00c0, 0x482c: 0x00c0, 0x482d: 0x00c0,
0x4830: 0x00c3, 0x4831: 0x00c3, 0x4832: 0x00c3, 0x4833: 0x00c3, 0x4834: 0x00c3, 0x4835: 0x0080,
// Block 0x121, offset 0x4840
0x4840: 0x00c0, 0x4841: 0x00c0, 0x4842: 0x00c0, 0x4843: 0x00c0, 0x4844: 0x00c0, 0x4845: 0x00c0,
0x4846: 0x00c0, 0x4847: 0x00c0, 0x4848: 0x00c0, 0x4849: 0x00c0, 0x484a: 0x00c0, 0x484b: 0x00c0,
0x484c: 0x00c0, 0x484d: 0x00c0, 0x484e: 0x00c0, 0x484f: 0x00c0, 0x4850: 0x00c0, 0x4851: 0x00c0,
0x4852: 0x00c0, 0x4853: 0x00c0, 0x4854: 0x00c0, 0x4855: 0x00c0, 0x4856: 0x00c0, 0x4857: 0x00c0,
0x4858: 0x00c0, 0x4859: 0x00c0, 0x485a: 0x00c0, 0x485b: 0x00c0, 0x485c: 0x00c0, 0x485d: 0x00c0,
0x485e: 0x00c0, 0x485f: 0x00c0, 0x4860: 0x00c0, 0x4861: 0x00c0, 0x4862: 0x00c0, 0x4863: 0x00c0,
0x4864: 0x00c0, 0x4865: 0x00c0, 0x4866: 0x00c0, 0x4867: 0x00c0, 0x4868: 0x00c0, 0x4869: 0x00c0,
0x486a: 0x00c0, 0x486b: 0x00c0, 0x486c: 0x00c0, 0x486d: 0x00c0, 0x486e: 0x00c0, 0x486f: 0x00c0,
0x4870: 0x00c3, 0x4871: 0x00c3, 0x4872: 0x00c3, 0x4873: 0x00c3, 0x4874: 0x00c3, 0x4875: 0x00c3,
0x4876: 0x00c3, 0x4877: 0x0080, 0x4878: 0x0080, 0x4879: 0x0080, 0x487a: 0x0080, 0x487b: 0x0080,
0x487c: 0x0080, 0x487d: 0x0080, 0x487e: 0x0080, 0x487f: 0x0080,
// Block 0x122, offset 0x4880
0x4880: 0x00c0, 0x4881: 0x00c0, 0x4882: 0x00c0, 0x4883: 0x00c0, 0x4884: 0x0080, 0x4885: 0x0080,
0x4890: 0x00c0, 0x4891: 0x00c0,
0x4892: 0x00c0, 0x4893: 0x00c0, 0x4894: 0x00c0, 0x4895: 0x00c0, 0x4896: 0x00c0, 0x4897: 0x00c0,
0x4898: 0x00c0, 0x4899: 0x00c0, 0x489b: 0x0080, 0x489c: 0x0080, 0x489d: 0x0080,
0x489e: 0x0080, 0x489f: 0x0080, 0x48a0: 0x0080, 0x48a1: 0x0080, 0x48a3: 0x00c0,
0x48a4: 0x00c0, 0x48a5: 0x00c0, 0x48a6: 0x00c0, 0x48a7: 0x00c0, 0x48a8: 0x00c0, 0x48a9: 0x00c0,
0x48aa: 0x00c0, 0x48ab: 0x00c0, 0x48ac: 0x00c0, 0x48ad: 0x00c0, 0x48ae: 0x00c0, 0x48af: 0x00c0,
0x48b0: 0x00c0, 0x48b1: 0x00c0, 0x48b2: 0x00c0, 0x48b3: 0x00c0, 0x48b4: 0x00c0, 0x48b5: 0x00c0,
0x48b6: 0x00c0, 0x48b7: 0x00c0,
0x48bd: 0x00c0, 0x48be: 0x00c0, 0x48bf: 0x00c0,
// Block 0x123, offset 0x48c0
0x48c0: 0x00c0, 0x48c1: 0x00c0, 0x48c2: 0x00c0, 0x48c3: 0x00c0, 0x48c4: 0x00c0, 0x48c5: 0x00c0,
0x48c6: 0x00c0, 0x48c7: 0x00c0, 0x48c8: 0x00c0, 0x48c9: 0x00c0, 0x48ca: 0x00c0, 0x48cb: 0x00c0,
0x48cc: 0x00c0, 0x48cd: 0x00c0, 0x48ce: 0x00c0, 0x48cf: 0x00c0,
// Block 0x124, offset 0x4900
0x4900: 0x0080, 0x4901: 0x0080, 0x4902: 0x0080, 0x4903: 0x0080, 0x4904: 0x0080, 0x4905: 0x0080,
0x4906: 0x0080, 0x4907: 0x0080, 0x4908: 0x0080, 0x4909: 0x0080, 0x490a: 0x0080, 0x490b: 0x0080,
0x490c: 0x0080, 0x490d: 0x0080, 0x490e: 0x0080, 0x490f: 0x0080, 0x4910: 0x0080, 0x4911: 0x0080,
0x4912: 0x0080, 0x4913: 0x0080, 0x4914: 0x0080, 0x4915: 0x0080, 0x4916: 0x0080, 0x4917: 0x0080,
0x4918: 0x0080, 0x4919: 0x0080, 0x491a: 0x0080,
// Block 0x125, offset 0x4940
0x4940: 0x00c0, 0x4941: 0x00c0, 0x4942: 0x00c0, 0x4943: 0x00c0, 0x4944: 0x00c0, 0x4945: 0x00c0,
0x4946: 0x00c0, 0x4947: 0x00c0, 0x4948: 0x00c0, 0x4949: 0x00c0, 0x494a: 0x00c0,
0x494f: 0x00c3, 0x4950: 0x00c0, 0x4951: 0x00c0,
0x4952: 0x00c0, 0x4953: 0x00c0, 0x4954: 0x00c0, 0x4955: 0x00c0, 0x4956: 0x00c0, 0x4957: 0x00c0,
0x4958: 0x00c0, 0x4959: 0x00c0, 0x495a: 0x00c0, 0x495b: 0x00c0, 0x495c: 0x00c0, 0x495d: 0x00c0,
0x495e: 0x00c0, 0x495f: 0x00c0, 0x4960: 0x00c0, 0x4961: 0x00c0, 0x4962: 0x00c0, 0x4963: 0x00c0,
0x4964: 0x00c0, 0x4965: 0x00c0, 0x4966: 0x00c0, 0x4967: 0x00c0, 0x4968: 0x00c0, 0x4969: 0x00c0,
0x496a: 0x00c0, 0x496b: 0x00c0, 0x496c: 0x00c0, 0x496d: 0x00c0, 0x496e: 0x00c0, 0x496f: 0x00c0,
0x4970: 0x00c0, 0x4971: 0x00c0, 0x4972: 0x00c0, 0x4973: 0x00c0, 0x4974: 0x00c0, 0x4975: 0x00c0,
0x4976: 0x00c0, 0x4977: 0x00c0, 0x4978: 0x00c0, 0x4979: 0x00c0, 0x497a: 0x00c0, 0x497b: 0x00c0,
0x497c: 0x00c0, 0x497d: 0x00c0, 0x497e: 0x00c0, 0x497f: 0x00c0,
// Block 0x126, offset 0x4980
0x4980: 0x00c0, 0x4981: 0x00c0, 0x4982: 0x00c0, 0x4983: 0x00c0, 0x4984: 0x00c0, 0x4985: 0x00c0,
0x4986: 0x00c0, 0x4987: 0x00c0,
0x498f: 0x00c3, 0x4990: 0x00c3, 0x4991: 0x00c3,
0x4992: 0x00c3, 0x4993: 0x00c0, 0x4994: 0x00c0, 0x4995: 0x00c0, 0x4996: 0x00c0, 0x4997: 0x00c0,
0x4998: 0x00c0, 0x4999: 0x00c0, 0x499a: 0x00c0, 0x499b: 0x00c0, 0x499c: 0x00c0, 0x499d: 0x00c0,
0x499e: 0x00c0, 0x499f: 0x00c0,
// Block 0x127, offset 0x49c0
0x49e0: 0x00c0, 0x49e1: 0x00c0, 0x49e2: 0x008c, 0x49e3: 0x00cc,
0x49e4: 0x00c3,
0x49f0: 0x00cc, 0x49f1: 0x00cc,
// Block 0x128, offset 0x4a00
0x4a00: 0x00c0, 0x4a01: 0x00c0, 0x4a02: 0x00c0, 0x4a03: 0x00c0, 0x4a04: 0x00c0, 0x4a05: 0x00c0,
0x4a06: 0x00c0, 0x4a07: 0x00c0, 0x4a08: 0x00c0, 0x4a09: 0x00c0, 0x4a0a: 0x00c0, 0x4a0b: 0x00c0,
0x4a0c: 0x00c0, 0x4a0d: 0x00c0, 0x4a0e: 0x00c0, 0x4a0f: 0x00c0, 0x4a10: 0x00c0, 0x4a11: 0x00c0,
0x4a12: 0x00c0, 0x4a13: 0x00c0, 0x4a14: 0x00c0, 0x4a15: 0x00c0, 0x4a16: 0x00c0, 0x4a17: 0x00c0,
0x4a18: 0x00c0, 0x4a19: 0x00c0, 0x4a1a: 0x00c0, 0x4a1b: 0x00c0, 0x4a1c: 0x00c0, 0x4a1d: 0x00c0,
0x4a1e: 0x00c0, 0x4a1f: 0x00c0, 0x4a20: 0x00c0, 0x4a21: 0x00c0, 0x4a22: 0x00c0, 0x4a23: 0x00c0,
0x4a24: 0x00c0, 0x4a25: 0x00c0, 0x4a26: 0x00c0, 0x4a27: 0x00c0, 0x4a28: 0x00c0, 0x4a29: 0x00c0,
0x4a2a: 0x00c0, 0x4a2b: 0x00c0, 0x4a2c: 0x00c0, 0x4a2d: 0x00c0, 0x4a2e: 0x00c0, 0x4a2f: 0x00c0,
0x4a30: 0x00c0, 0x4a31: 0x00c0, 0x4a32: 0x00c0, 0x4a33: 0x00c0, 0x4a34: 0x00c0, 0x4a35: 0x00c0,
0x4a36: 0x00c0, 0x4a37: 0x00c0,
// Block 0x129, offset 0x4a40
0x4a40: 0x00c0, 0x4a41: 0x00c0, 0x4a42: 0x00c0, 0x4a43: 0x00c0, 0x4a44: 0x00c0, 0x4a45: 0x00c0,
0x4a46: 0x00c0, 0x4a47: 0x00c0, 0x4a48: 0x00c0, 0x4a49: 0x00c0, 0x4a4a: 0x00c0, 0x4a4b: 0x00c0,
0x4a4c: 0x00c0, 0x4a4d: 0x00c0, 0x4a4e: 0x00c0, 0x4a4f: 0x00c0, 0x4a50: 0x00c0, 0x4a51: 0x00c0,
0x4a52: 0x00c0, 0x4a53: 0x00c0, 0x4a54: 0x00c0, 0x4a55: 0x00c0,
// Block 0x12a, offset 0x4a80
0x4ab0: 0x00cc, 0x4ab1: 0x00cc, 0x4ab2: 0x00cc, 0x4ab3: 0x00cc, 0x4ab5: 0x00cc,
0x4ab6: 0x00cc, 0x4ab7: 0x00cc, 0x4ab8: 0x00cc, 0x4ab9: 0x00cc, 0x4aba: 0x00cc, 0x4abb: 0x00cc,
0x4abd: 0x00cc, 0x4abe: 0x00cc,
// Block 0x12b, offset 0x4ac0
0x4ac0: 0x00cc, 0x4ac1: 0x00cc, 0x4ac2: 0x00cc, 0x4ac3: 0x00cc, 0x4ac4: 0x00cc, 0x4ac5: 0x00cc,
0x4ac6: 0x00cc, 0x4ac7: 0x00cc, 0x4ac8: 0x00cc, 0x4ac9: 0x00cc, 0x4aca: 0x00cc, 0x4acb: 0x00cc,
0x4acc: 0x00cc, 0x4acd: 0x00cc, 0x4ace: 0x00cc, 0x4acf: 0x00cc, 0x4ad0: 0x00cc, 0x4ad1: 0x00cc,
0x4ad2: 0x00cc, 0x4ad3: 0x00cc, 0x4ad4: 0x00cc, 0x4ad5: 0x00cc, 0x4ad6: 0x00cc, 0x4ad7: 0x00cc,
0x4ad8: 0x00cc, 0x4ad9: 0x00cc, 0x4ada: 0x00cc, 0x4adb: 0x00cc, 0x4adc: 0x00cc, 0x4add: 0x00cc,
0x4ade: 0x00cc, 0x4adf: 0x00cc, 0x4ae0: 0x00cc, 0x4ae1: 0x00cc, 0x4ae2: 0x00cc,
0x4af2: 0x00cc,
// Block 0x12c, offset 0x4b00
0x4b10: 0x00cc, 0x4b11: 0x00cc,
0x4b12: 0x00cc, 0x4b15: 0x00cc,
0x4b24: 0x00cc, 0x4b25: 0x00cc, 0x4b26: 0x00cc, 0x4b27: 0x00cc,
0x4b30: 0x00c0, 0x4b31: 0x00c0, 0x4b32: 0x00c0, 0x4b33: 0x00c0, 0x4b34: 0x00c0, 0x4b35: 0x00c0,
0x4b36: 0x00c0, 0x4b37: 0x00c0, 0x4b38: 0x00c0, 0x4b39: 0x00c0, 0x4b3a: 0x00c0, 0x4b3b: 0x00c0,
0x4b3c: 0x00c0, 0x4b3d: 0x00c0, 0x4b3e: 0x00c0, 0x4b3f: 0x00c0,
// Block 0x12d, offset 0x4b40
0x4b40: 0x00c0, 0x4b41: 0x00c0, 0x4b42: 0x00c0, 0x4b43: 0x00c0, 0x4b44: 0x00c0, 0x4b45: 0x00c0,
0x4b46: 0x00c0, 0x4b47: 0x00c0, 0x4b48: 0x00c0, 0x4b49: 0x00c0, 0x4b4a: 0x00c0, 0x4b4b: 0x00c0,
0x4b4c: 0x00c0, 0x4b4d: 0x00c0, 0x4b4e: 0x00c0, 0x4b4f: 0x00c0, 0x4b50: 0x00c0, 0x4b51: 0x00c0,
0x4b52: 0x00c0, 0x4b53: 0x00c0, 0x4b54: 0x00c0, 0x4b55: 0x00c0, 0x4b56: 0x00c0, 0x4b57: 0x00c0,
0x4b58: 0x00c0, 0x4b59: 0x00c0, 0x4b5a: 0x00c0, 0x4b5b: 0x00c0, 0x4b5c: 0x00c0, 0x4b5d: 0x00c0,
0x4b5e: 0x00c0, 0x4b5f: 0x00c0, 0x4b60: 0x00c0, 0x4b61: 0x00c0, 0x4b62: 0x00c0, 0x4b63: 0x00c0,
0x4b64: 0x00c0, 0x4b65: 0x00c0, 0x4b66: 0x00c0, 0x4b67: 0x00c0, 0x4b68: 0x00c0, 0x4b69: 0x00c0,
0x4b6a: 0x00c0, 0x4b6b: 0x00c0, 0x4b6c: 0x00c0, 0x4b6d: 0x00c0, 0x4b6e: 0x00c0, 0x4b6f: 0x00c0,
0x4b70: 0x00c0, 0x4b71: 0x00c0, 0x4b72: 0x00c0, 0x4b73: 0x00c0, 0x4b74: 0x00c0, 0x4b75: 0x00c0,
0x4b76: 0x00c0, 0x4b77: 0x00c0, 0x4b78: 0x00c0, 0x4b79: 0x00c0, 0x4b7a: 0x00c0, 0x4b7b: 0x00c0,
// Block 0x12e, offset 0x4b80
0x4b80: 0x00c0, 0x4b81: 0x00c0, 0x4b82: 0x00c0, 0x4b83: 0x00c0, 0x4b84: 0x00c0, 0x4b85: 0x00c0,
0x4b86: 0x00c0, 0x4b87: 0x00c0, 0x4b88: 0x00c0, 0x4b89: 0x00c0, 0x4b8a: 0x00c0, 0x4b8b: 0x00c0,
0x4b8c: 0x00c0, 0x4b8d: 0x00c0, 0x4b8e: 0x00c0, 0x4b8f: 0x00c0, 0x4b90: 0x00c0, 0x4b91: 0x00c0,
0x4b92: 0x00c0, 0x4b93: 0x00c0, 0x4b94: 0x00c0, 0x4b95: 0x00c0, 0x4b96: 0x00c0, 0x4b97: 0x00c0,
0x4b98: 0x00c0, 0x4b99: 0x00c0, 0x4b9a: 0x00c0, 0x4b9b: 0x00c0, 0x4b9c: 0x00c0, 0x4b9d: 0x00c0,
0x4b9e: 0x00c0, 0x4b9f: 0x00c0, 0x4ba0: 0x00c0, 0x4ba1: 0x00c0, 0x4ba2: 0x00c0, 0x4ba3: 0x00c0,
0x4ba4: 0x00c0, 0x4ba5: 0x00c0, 0x4ba6: 0x00c0, 0x4ba7: 0x00c0, 0x4ba8: 0x00c0, 0x4ba9: 0x00c0,
0x4baa: 0x00c0,
0x4bb0: 0x00c0, 0x4bb1: 0x00c0, 0x4bb2: 0x00c0, 0x4bb3: 0x00c0, 0x4bb4: 0x00c0, 0x4bb5: 0x00c0,
0x4bb6: 0x00c0, 0x4bb7: 0x00c0, 0x4bb8: 0x00c0, 0x4bb9: 0x00c0, 0x4bba: 0x00c0, 0x4bbb: 0x00c0,
0x4bbc: 0x00c0,
// Block 0x12f, offset 0x4bc0
0x4bc0: 0x00c0, 0x4bc1: 0x00c0, 0x4bc2: 0x00c0, 0x4bc3: 0x00c0, 0x4bc4: 0x00c0, 0x4bc5: 0x00c0,
0x4bc6: 0x00c0, 0x4bc7: 0x00c0, 0x4bc8: 0x00c0,
0x4bd0: 0x00c0, 0x4bd1: 0x00c0,
0x4bd2: 0x00c0, 0x4bd3: 0x00c0, 0x4bd4: 0x00c0, 0x4bd5: 0x00c0, 0x4bd6: 0x00c0, 0x4bd7: 0x00c0,
0x4bd8: 0x00c0, 0x4bd9: 0x00c0, 0x4bdc: 0x0080, 0x4bdd: 0x00c3,
0x4bde: 0x00c3, 0x4bdf: 0x0080, 0x4be0: 0x0040, 0x4be1: 0x0040, 0x4be2: 0x0040, 0x4be3: 0x0040,
// Block 0x130, offset 0x4c00
0x4c00: 0x00c3, 0x4c01: 0x00c3, 0x4c02: 0x00c3, 0x4c03: 0x00c3, 0x4c04: 0x00c3, 0x4c05: 0x00c3,
0x4c06: 0x00c3, 0x4c07: 0x00c3, 0x4c08: 0x00c3, 0x4c09: 0x00c3, 0x4c0a: 0x00c3, 0x4c0b: 0x00c3,
0x4c0c: 0x00c3, 0x4c0d: 0x00c3, 0x4c0e: 0x00c3, 0x4c0f: 0x00c3, 0x4c10: 0x00c3, 0x4c11: 0x00c3,
0x4c12: 0x00c3, 0x4c13: 0x00c3, 0x4c14: 0x00c3, 0x4c15: 0x00c3, 0x4c16: 0x00c3, 0x4c17: 0x00c3,
0x4c18: 0x00c3, 0x4c19: 0x00c3, 0x4c1a: 0x00c3, 0x4c1b: 0x00c3, 0x4c1c: 0x00c3, 0x4c1d: 0x00c3,
0x4c1e: 0x00c3, 0x4c1f: 0x00c3, 0x4c20: 0x00c3, 0x4c21: 0x00c3, 0x4c22: 0x00c3, 0x4c23: 0x00c3,
0x4c24: 0x00c3, 0x4c25: 0x00c3, 0x4c26: 0x00c3, 0x4c27: 0x00c3, 0x4c28: 0x00c3, 0x4c29: 0x00c3,
0x4c2a: 0x00c3, 0x4c2b: 0x00c3, 0x4c2c: 0x00c3, 0x4c2d: 0x00c3,
0x4c30: 0x00c3, 0x4c31: 0x00c3, 0x4c32: 0x00c3, 0x4c33: 0x00c3, 0x4c34: 0x00c3, 0x4c35: 0x00c3,
0x4c36: 0x00c3, 0x4c37: 0x00c3, 0x4c38: 0x00c3, 0x4c39: 0x00c3, 0x4c3a: 0x00c3, 0x4c3b: 0x00c3,
0x4c3c: 0x00c3, 0x4c3d: 0x00c3, 0x4c3e: 0x00c3, 0x4c3f: 0x00c3,
// Block 0x131, offset 0x4c40
0x4c40: 0x00c3, 0x4c41: 0x00c3, 0x4c42: 0x00c3, 0x4c43: 0x00c3, 0x4c44: 0x00c3, 0x4c45: 0x00c3,
0x4c46: 0x00c3,
0x4c50: 0x0080, 0x4c51: 0x0080,
0x4c52: 0x0080, 0x4c53: 0x0080, 0x4c54: 0x0080, 0x4c55: 0x0080, 0x4c56: 0x0080, 0x4c57: 0x0080,
0x4c58: 0x0080, 0x4c59: 0x0080, 0x4c5a: 0x0080, 0x4c5b: 0x0080, 0x4c5c: 0x0080, 0x4c5d: 0x0080,
0x4c5e: 0x0080, 0x4c5f: 0x0080, 0x4c60: 0x0080, 0x4c61: 0x0080, 0x4c62: 0x0080, 0x4c63: 0x0080,
0x4c64: 0x0080, 0x4c65: 0x0080, 0x4c66: 0x0080, 0x4c67: 0x0080, 0x4c68: 0x0080, 0x4c69: 0x0080,
0x4c6a: 0x0080, 0x4c6b: 0x0080, 0x4c6c: 0x0080, 0x4c6d: 0x0080, 0x4c6e: 0x0080, 0x4c6f: 0x0080,
0x4c70: 0x0080, 0x4c71: 0x0080, 0x4c72: 0x0080, 0x4c73: 0x0080, 0x4c74: 0x0080, 0x4c75: 0x0080,
0x4c76: 0x0080, 0x4c77: 0x0080, 0x4c78: 0x0080, 0x4c79: 0x0080, 0x4c7a: 0x0080, 0x4c7b: 0x0080,
0x4c7c: 0x0080, 0x4c7d: 0x0080, 0x4c7e: 0x0080, 0x4c7f: 0x0080,
// Block 0x132, offset 0x4c80
0x4c80: 0x0080, 0x4c81: 0x0080, 0x4c82: 0x0080, 0x4c83: 0x0080,
// Block 0x133, offset 0x4cc0
0x4cc0: 0x0080, 0x4cc1: 0x0080, 0x4cc2: 0x0080, 0x4cc3: 0x0080, 0x4cc4: 0x0080, 0x4cc5: 0x0080,
0x4cc6: 0x0080, 0x4cc7: 0x0080, 0x4cc8: 0x0080, 0x4cc9: 0x0080, 0x4cca: 0x0080, 0x4ccb: 0x0080,
0x4ccc: 0x0080, 0x4ccd: 0x0080, 0x4cce: 0x0080, 0x4ccf: 0x0080, 0x4cd0: 0x0080, 0x4cd1: 0x0080,
0x4cd2: 0x0080, 0x4cd3: 0x0080, 0x4cd4: 0x0080, 0x4cd5: 0x0080, 0x4cd6: 0x0080, 0x4cd7: 0x0080,
0x4cd8: 0x0080, 0x4cd9: 0x0080, 0x4cda: 0x0080, 0x4cdb: 0x0080, 0x4cdc: 0x0080, 0x4cdd: 0x0080,
0x4cde: 0x0080, 0x4cdf: 0x0080, 0x4ce0: 0x0080, 0x4ce1: 0x0080, 0x4ce2: 0x0080, 0x4ce3: 0x0080,
0x4ce4: 0x0080, 0x4ce5: 0x0080, 0x4ce6: 0x0080, 0x4ce7: 0x0080, 0x4ce8: 0x0080, 0x4ce9: 0x0080,
0x4cea: 0x0080, 0x4ceb: 0x0080, 0x4cec: 0x0080, 0x4ced: 0x0080, 0x4cee: 0x0080, 0x4cef: 0x0080,
0x4cf0: 0x0080, 0x4cf1: 0x0080, 0x4cf2: 0x0080, 0x4cf3: 0x0080, 0x4cf4: 0x0080, 0x4cf5: 0x0080,
// Block 0x134, offset 0x4d00
0x4d00: 0x0080, 0x4d01: 0x0080, 0x4d02: 0x0080, 0x4d03: 0x0080, 0x4d04: 0x0080, 0x4d05: 0x0080,
0x4d06: 0x0080, 0x4d07: 0x0080, 0x4d08: 0x0080, 0x4d09: 0x0080, 0x4d0a: 0x0080, 0x4d0b: 0x0080,
0x4d0c: 0x0080, 0x4d0d: 0x0080, 0x4d0e: 0x0080, 0x4d0f: 0x0080, 0x4d10: 0x0080, 0x4d11: 0x0080,
0x4d12: 0x0080, 0x4d13: 0x0080, 0x4d14: 0x0080, 0x4d15: 0x0080, 0x4d16: 0x0080, 0x4d17: 0x0080,
0x4d18: 0x0080, 0x4d19: 0x0080, 0x4d1a: 0x0080, 0x4d1b: 0x0080, 0x4d1c: 0x0080, 0x4d1d: 0x0080,
0x4d1e: 0x0080, 0x4d1f: 0x0080, 0x4d20: 0x0080, 0x4d21: 0x0080, 0x4d22: 0x0080, 0x4d23: 0x0080,
0x4d24: 0x0080, 0x4d25: 0x0080, 0x4d26: 0x0080, 0x4d29: 0x0080,
0x4d2a: 0x0080, 0x4d2b: 0x0080, 0x4d2c: 0x0080, 0x4d2d: 0x0080, 0x4d2e: 0x0080, 0x4d2f: 0x0080,
0x4d30: 0x0080, 0x4d31: 0x0080, 0x4d32: 0x0080, 0x4d33: 0x0080, 0x4d34: 0x0080, 0x4d35: 0x0080,
0x4d36: 0x0080, 0x4d37: 0x0080, 0x4d38: 0x0080, 0x4d39: 0x0080, 0x4d3a: 0x0080, 0x4d3b: 0x0080,
0x4d3c: 0x0080, 0x4d3d: 0x0080, 0x4d3e: 0x0080, 0x4d3f: 0x0080,
// Block 0x135, offset 0x4d40
0x4d40: 0x0080, 0x4d41: 0x0080, 0x4d42: 0x0080, 0x4d43: 0x0080, 0x4d44: 0x0080, 0x4d45: 0x0080,
0x4d46: 0x0080, 0x4d47: 0x0080, 0x4d48: 0x0080, 0x4d49: 0x0080, 0x4d4a: 0x0080, 0x4d4b: 0x0080,
0x4d4c: 0x0080, 0x4d4d: 0x0080, 0x4d4e: 0x0080, 0x4d4f: 0x0080, 0x4d50: 0x0080, 0x4d51: 0x0080,
0x4d52: 0x0080, 0x4d53: 0x0080, 0x4d54: 0x0080, 0x4d55: 0x0080, 0x4d56: 0x0080, 0x4d57: 0x0080,
0x4d58: 0x0080, 0x4d59: 0x0080, 0x4d5a: 0x0080, 0x4d5b: 0x0080, 0x4d5c: 0x0080, 0x4d5d: 0x0080,
0x4d5e: 0x0080, 0x4d5f: 0x0080, 0x4d60: 0x0080, 0x4d61: 0x0080, 0x4d62: 0x0080, 0x4d63: 0x0080,
0x4d64: 0x0080, 0x4d65: 0x00c0, 0x4d66: 0x00c0, 0x4d67: 0x00c3, 0x4d68: 0x00c3, 0x4d69: 0x00c3,
0x4d6a: 0x0080, 0x4d6b: 0x0080, 0x4d6c: 0x0080, 0x4d6d: 0x00c0, 0x4d6e: 0x00c0, 0x4d6f: 0x00c0,
0x4d70: 0x00c0, 0x4d71: 0x00c0, 0x4d72: 0x00c0, 0x4d73: 0x0040, 0x4d74: 0x0040, 0x4d75: 0x0040,
0x4d76: 0x0040, 0x4d77: 0x0040, 0x4d78: 0x0040, 0x4d79: 0x0040, 0x4d7a: 0x0040, 0x4d7b: 0x00c3,
0x4d7c: 0x00c3, 0x4d7d: 0x00c3, 0x4d7e: 0x00c3, 0x4d7f: 0x00c3,
// Block 0x136, offset 0x4d80
0x4d80: 0x00c3, 0x4d81: 0x00c3, 0x4d82: 0x00c3, 0x4d83: 0x0080, 0x4d84: 0x0080, 0x4d85: 0x00c3,
0x4d86: 0x00c3, 0x4d87: 0x00c3, 0x4d88: 0x00c3, 0x4d89: 0x00c3, 0x4d8a: 0x00c3, 0x4d8b: 0x00c3,
0x4d8c: 0x0080, 0x4d8d: 0x0080, 0x4d8e: 0x0080, 0x4d8f: 0x0080, 0x4d90: 0x0080, 0x4d91: 0x0080,
0x4d92: 0x0080, 0x4d93: 0x0080, 0x4d94: 0x0080, 0x4d95: 0x0080, 0x4d96: 0x0080, 0x4d97: 0x0080,
0x4d98: 0x0080, 0x4d99: 0x0080, 0x4d9a: 0x0080, 0x4d9b: 0x0080, 0x4d9c: 0x0080, 0x4d9d: 0x0080,
0x4d9e: 0x0080, 0x4d9f: 0x0080, 0x4da0: 0x0080, 0x4da1: 0x0080, 0x4da2: 0x0080, 0x4da3: 0x0080,
0x4da4: 0x0080, 0x4da5: 0x0080, 0x4da6: 0x0080, 0x4da7: 0x0080, 0x4da8: 0x0080, 0x4da9: 0x0080,
0x4daa: 0x00c3, 0x4dab: 0x00c3, 0x4dac: 0x00c3, 0x4dad: 0x00c3, 0x4dae: 0x0080, 0x4daf: 0x0080,
0x4db0: 0x0080, 0x4db1: 0x0080, 0x4db2: 0x0080, 0x4db3: 0x0080, 0x4db4: 0x0080, 0x4db5: 0x0080,
0x4db6: 0x0080, 0x4db7: 0x0080, 0x4db8: 0x0080, 0x4db9: 0x0080, 0x4dba: 0x0080, 0x4dbb: 0x0080,
0x4dbc: 0x0080, 0x4dbd: 0x0080, 0x4dbe: 0x0080, 0x4dbf: 0x0080,
// Block 0x137, offset 0x4dc0
0x4dc0: 0x0080, 0x4dc1: 0x0080, 0x4dc2: 0x0080, 0x4dc3: 0x0080, 0x4dc4: 0x0080, 0x4dc5: 0x0080,
0x4dc6: 0x0080, 0x4dc7: 0x0080, 0x4dc8: 0x0080, 0x4dc9: 0x0080, 0x4dca: 0x0080, 0x4dcb: 0x0080,
0x4dcc: 0x0080, 0x4dcd: 0x0080, 0x4dce: 0x0080, 0x4dcf: 0x0080, 0x4dd0: 0x0080, 0x4dd1: 0x0080,
0x4dd2: 0x0080, 0x4dd3: 0x0080, 0x4dd4: 0x0080, 0x4dd5: 0x0080, 0x4dd6: 0x0080, 0x4dd7: 0x0080,
0x4dd8: 0x0080, 0x4dd9: 0x0080, 0x4dda: 0x0080, 0x4ddb: 0x0080, 0x4ddc: 0x0080, 0x4ddd: 0x0080,
0x4dde: 0x0080, 0x4ddf: 0x0080, 0x4de0: 0x0080, 0x4de1: 0x0080, 0x4de2: 0x0080, 0x4de3: 0x0080,
0x4de4: 0x0080, 0x4de5: 0x0080, 0x4de6: 0x0080, 0x4de7: 0x0080, 0x4de8: 0x0080, 0x4de9: 0x0080,
0x4dea: 0x0080,
// Block 0x138, offset 0x4e00
0x4e00: 0x0088, 0x4e01: 0x0088, 0x4e02: 0x00c9, 0x4e03: 0x00c9, 0x4e04: 0x00c9, 0x4e05: 0x0088,
// Block 0x139, offset 0x4e40
0x4e40: 0x0080, 0x4e41: 0x0080, 0x4e42: 0x0080, 0x4e43: 0x0080, 0x4e44: 0x0080, 0x4e45: 0x0080,
0x4e46: 0x0080, 0x4e47: 0x0080, 0x4e48: 0x0080, 0x4e49: 0x0080, 0x4e4a: 0x0080, 0x4e4b: 0x0080,
0x4e4c: 0x0080, 0x4e4d: 0x0080, 0x4e4e: 0x0080, 0x4e4f: 0x0080, 0x4e50: 0x0080, 0x4e51: 0x0080,
0x4e52: 0x0080, 0x4e53: 0x0080,
0x4e60: 0x0080, 0x4e61: 0x0080, 0x4e62: 0x0080, 0x4e63: 0x0080,
0x4e64: 0x0080, 0x4e65: 0x0080, 0x4e66: 0x0080, 0x4e67: 0x0080, 0x4e68: 0x0080, 0x4e69: 0x0080,
0x4e6a: 0x0080, 0x4e6b: 0x0080, 0x4e6c: 0x0080, 0x4e6d: 0x0080, 0x4e6e: 0x0080, 0x4e6f: 0x0080,
0x4e70: 0x0080, 0x4e71: 0x0080, 0x4e72: 0x0080, 0x4e73: 0x0080,
// Block 0x13a, offset 0x4e80
0x4e80: 0x0080, 0x4e81: 0x0080, 0x4e82: 0x0080, 0x4e83: 0x0080, 0x4e84: 0x0080, 0x4e85: 0x0080,
0x4e86: 0x0080, 0x4e87: 0x0080, 0x4e88: 0x0080, 0x4e89: 0x0080, 0x4e8a: 0x0080, 0x4e8b: 0x0080,
0x4e8c: 0x0080, 0x4e8d: 0x0080, 0x4e8e: 0x0080, 0x4e8f: 0x0080, 0x4e90: 0x0080, 0x4e91: 0x0080,
0x4e92: 0x0080, 0x4e93: 0x0080, 0x4e94: 0x0080, 0x4e95: 0x0080, 0x4e96: 0x0080,
0x4ea0: 0x0080, 0x4ea1: 0x0080, 0x4ea2: 0x0080, 0x4ea3: 0x0080,
0x4ea4: 0x0080, 0x4ea5: 0x0080, 0x4ea6: 0x0080, 0x4ea7: 0x0080, 0x4ea8: 0x0080, 0x4ea9: 0x0080,
0x4eaa: 0x0080, 0x4eab: 0x0080, 0x4eac: 0x0080, 0x4ead: 0x0080, 0x4eae: 0x0080, 0x4eaf: 0x0080,
0x4eb0: 0x0080, 0x4eb1: 0x0080, 0x4eb2: 0x0080, 0x4eb3: 0x0080, 0x4eb4: 0x0080, 0x4eb5: 0x0080,
0x4eb6: 0x0080, 0x4eb7: 0x0080, 0x4eb8: 0x0080,
// Block 0x13b, offset 0x4ec0
0x4ec0: 0x0080, 0x4ec1: 0x0080, 0x4ec2: 0x0080, 0x4ec3: 0x0080, 0x4ec4: 0x0080, 0x4ec5: 0x0080,
0x4ec6: 0x0080, 0x4ec7: 0x0080, 0x4ec8: 0x0080, 0x4ec9: 0x0080, 0x4eca: 0x0080, 0x4ecb: 0x0080,
0x4ecc: 0x0080, 0x4ecd: 0x0080, 0x4ece: 0x0080, 0x4ecf: 0x0080, 0x4ed0: 0x0080, 0x4ed1: 0x0080,
0x4ed2: 0x0080, 0x4ed3: 0x0080, 0x4ed4: 0x0080, 0x4ed6: 0x0080, 0x4ed7: 0x0080,
0x4ed8: 0x0080, 0x4ed9: 0x0080, 0x4eda: 0x0080, 0x4edb: 0x0080, 0x4edc: 0x0080, 0x4edd: 0x0080,
0x4ede: 0x0080, 0x4edf: 0x0080, 0x4ee0: 0x0080, 0x4ee1: 0x0080, 0x4ee2: 0x0080, 0x4ee3: 0x0080,
0x4ee4: 0x0080, 0x4ee5: 0x0080, 0x4ee6: 0x0080, 0x4ee7: 0x0080, 0x4ee8: 0x0080, 0x4ee9: 0x0080,
0x4eea: 0x0080, 0x4eeb: 0x0080, 0x4eec: 0x0080, 0x4eed: 0x0080, 0x4eee: 0x0080, 0x4eef: 0x0080,
0x4ef0: 0x0080, 0x4ef1: 0x0080, 0x4ef2: 0x0080, 0x4ef3: 0x0080, 0x4ef4: 0x0080, 0x4ef5: 0x0080,
0x4ef6: 0x0080, 0x4ef7: 0x0080, 0x4ef8: 0x0080, 0x4ef9: 0x0080, 0x4efa: 0x0080, 0x4efb: 0x0080,
0x4efc: 0x0080, 0x4efd: 0x0080, 0x4efe: 0x0080, 0x4eff: 0x0080,
// Block 0x13c, offset 0x4f00
0x4f00: 0x0080, 0x4f01: 0x0080, 0x4f02: 0x0080, 0x4f03: 0x0080, 0x4f04: 0x0080, 0x4f05: 0x0080,
0x4f06: 0x0080, 0x4f07: 0x0080, 0x4f08: 0x0080, 0x4f09: 0x0080, 0x4f0a: 0x0080, 0x4f0b: 0x0080,
0x4f0c: 0x0080, 0x4f0d: 0x0080, 0x4f0e: 0x0080, 0x4f0f: 0x0080, 0x4f10: 0x0080, 0x4f11: 0x0080,
0x4f12: 0x0080, 0x4f13: 0x0080, 0x4f14: 0x0080, 0x4f15: 0x0080, 0x4f16: 0x0080, 0x4f17: 0x0080,
0x4f18: 0x0080, 0x4f19: 0x0080, 0x4f1a: 0x0080, 0x4f1b: 0x0080, 0x4f1c: 0x0080,
0x4f1e: 0x0080, 0x4f1f: 0x0080, 0x4f22: 0x0080,
0x4f25: 0x0080, 0x4f26: 0x0080, 0x4f29: 0x0080,
0x4f2a: 0x0080, 0x4f2b: 0x0080, 0x4f2c: 0x0080, 0x4f2e: 0x0080, 0x4f2f: 0x0080,
0x4f30: 0x0080, 0x4f31: 0x0080, 0x4f32: 0x0080, 0x4f33: 0x0080, 0x4f34: 0x0080, 0x4f35: 0x0080,
0x4f36: 0x0080, 0x4f37: 0x0080, 0x4f38: 0x0080, 0x4f39: 0x0080, 0x4f3b: 0x0080,
0x4f3d: 0x0080, 0x4f3e: 0x0080, 0x4f3f: 0x0080,
// Block 0x13d, offset 0x4f40
0x4f40: 0x0080, 0x4f41: 0x0080, 0x4f42: 0x0080, 0x4f43: 0x0080, 0x4f45: 0x0080,
0x4f46: 0x0080, 0x4f47: 0x0080, 0x4f48: 0x0080, 0x4f49: 0x0080, 0x4f4a: 0x0080, 0x4f4b: 0x0080,
0x4f4c: 0x0080, 0x4f4d: 0x0080, 0x4f4e: 0x0080, 0x4f4f: 0x0080, 0x4f50: 0x0080, 0x4f51: 0x0080,
0x4f52: 0x0080, 0x4f53: 0x0080, 0x4f54: 0x0080, 0x4f55: 0x0080, 0x4f56: 0x0080, 0x4f57: 0x0080,
0x4f58: 0x0080, 0x4f59: 0x0080, 0x4f5a: 0x0080, 0x4f5b: 0x0080, 0x4f5c: 0x0080, 0x4f5d: 0x0080,
0x4f5e: 0x0080, 0x4f5f: 0x0080, 0x4f60: 0x0080, 0x4f61: 0x0080, 0x4f62: 0x0080, 0x4f63: 0x0080,
0x4f64: 0x0080, 0x4f65: 0x0080, 0x4f66: 0x0080, 0x4f67: 0x0080, 0x4f68: 0x0080, 0x4f69: 0x0080,
0x4f6a: 0x0080, 0x4f6b: 0x0080, 0x4f6c: 0x0080, 0x4f6d: 0x0080, 0x4f6e: 0x0080, 0x4f6f: 0x0080,
0x4f70: 0x0080, 0x4f71: 0x0080, 0x4f72: 0x0080, 0x4f73: 0x0080, 0x4f74: 0x0080, 0x4f75: 0x0080,
0x4f76: 0x0080, 0x4f77: 0x0080, 0x4f78: 0x0080, 0x4f79: 0x0080, 0x4f7a: 0x0080, 0x4f7b: 0x0080,
0x4f7c: 0x0080, 0x4f7d: 0x0080, 0x4f7e: 0x0080, 0x4f7f: 0x0080,
// Block 0x13e, offset 0x4f80
0x4f80: 0x0080, 0x4f81: 0x0080, 0x4f82: 0x0080, 0x4f83: 0x0080, 0x4f84: 0x0080, 0x4f85: 0x0080,
0x4f87: 0x0080, 0x4f88: 0x0080, 0x4f89: 0x0080, 0x4f8a: 0x0080,
0x4f8d: 0x0080, 0x4f8e: 0x0080, 0x4f8f: 0x0080, 0x4f90: 0x0080, 0x4f91: 0x0080,
0x4f92: 0x0080, 0x4f93: 0x0080, 0x4f94: 0x0080, 0x4f96: 0x0080, 0x4f97: 0x0080,
0x4f98: 0x0080, 0x4f99: 0x0080, 0x4f9a: 0x0080, 0x4f9b: 0x0080, 0x4f9c: 0x0080,
0x4f9e: 0x0080, 0x4f9f: 0x0080, 0x4fa0: 0x0080, 0x4fa1: 0x0080, 0x4fa2: 0x0080, 0x4fa3: 0x0080,
0x4fa4: 0x0080, 0x4fa5: 0x0080, 0x4fa6: 0x0080, 0x4fa7: 0x0080, 0x4fa8: 0x0080, 0x4fa9: 0x0080,
0x4faa: 0x0080, 0x4fab: 0x0080, 0x4fac: 0x0080, 0x4fad: 0x0080, 0x4fae: 0x0080, 0x4faf: 0x0080,
0x4fb0: 0x0080, 0x4fb1: 0x0080, 0x4fb2: 0x0080, 0x4fb3: 0x0080, 0x4fb4: 0x0080, 0x4fb5: 0x0080,
0x4fb6: 0x0080, 0x4fb7: 0x0080, 0x4fb8: 0x0080, 0x4fb9: 0x0080, 0x4fbb: 0x0080,
0x4fbc: 0x0080, 0x4fbd: 0x0080, 0x4fbe: 0x0080,
// Block 0x13f, offset 0x4fc0
0x4fc0: 0x0080, 0x4fc1: 0x0080, 0x4fc2: 0x0080, 0x4fc3: 0x0080, 0x4fc4: 0x0080,
0x4fc6: 0x0080, 0x4fca: 0x0080, 0x4fcb: 0x0080,
0x4fcc: 0x0080, 0x4fcd: 0x0080, 0x4fce: 0x0080, 0x4fcf: 0x0080, 0x4fd0: 0x0080,
0x4fd2: 0x0080, 0x4fd3: 0x0080, 0x4fd4: 0x0080, 0x4fd5: 0x0080, 0x4fd6: 0x0080, 0x4fd7: 0x0080,
0x4fd8: 0x0080, 0x4fd9: 0x0080, 0x4fda: 0x0080, 0x4fdb: 0x0080, 0x4fdc: 0x0080, 0x4fdd: 0x0080,
0x4fde: 0x0080, 0x4fdf: 0x0080, 0x4fe0: 0x0080, 0x4fe1: 0x0080, 0x4fe2: 0x0080, 0x4fe3: 0x0080,
0x4fe4: 0x0080, 0x4fe5: 0x0080, 0x4fe6: 0x0080, 0x4fe7: 0x0080, 0x4fe8: 0x0080, 0x4fe9: 0x0080,
0x4fea: 0x0080, 0x4feb: 0x0080, 0x4fec: 0x0080, 0x4fed: 0x0080, 0x4fee: 0x0080, 0x4fef: 0x0080,
0x4ff0: 0x0080, 0x4ff1: 0x0080, 0x4ff2: 0x0080, 0x4ff3: 0x0080, 0x4ff4: 0x0080, 0x4ff5: 0x0080,
0x4ff6: 0x0080, 0x4ff7: 0x0080, 0x4ff8: 0x0080, 0x4ff9: 0x0080, 0x4ffa: 0x0080, 0x4ffb: 0x0080,
0x4ffc: 0x0080, 0x4ffd: 0x0080, 0x4ffe: 0x0080, 0x4fff: 0x0080,
// Block 0x140, offset 0x5000
0x5000: 0x0080, 0x5001: 0x0080, 0x5002: 0x0080, 0x5003: 0x0080, 0x5004: 0x0080, 0x5005: 0x0080,
0x5006: 0x0080, 0x5007: 0x0080, 0x5008: 0x0080, 0x5009: 0x0080, 0x500a: 0x0080, 0x500b: 0x0080,
0x500c: 0x0080, 0x500d: 0x0080, 0x500e: 0x0080, 0x500f: 0x0080, 0x5010: 0x0080, 0x5011: 0x0080,
0x5012: 0x0080, 0x5013: 0x0080, 0x5014: 0x0080, 0x5015: 0x0080, 0x5016: 0x0080, 0x5017: 0x0080,
0x5018: 0x0080, 0x5019: 0x0080, 0x501a: 0x0080, 0x501b: 0x0080, 0x501c: 0x0080, 0x501d: 0x0080,
0x501e: 0x0080, 0x501f: 0x0080, 0x5020: 0x0080, 0x5021: 0x0080, 0x5022: 0x0080, 0x5023: 0x0080,
0x5024: 0x0080, 0x5025: 0x0080, 0x5028: 0x0080, 0x5029: 0x0080,
0x502a: 0x0080, 0x502b: 0x0080, 0x502c: 0x0080, 0x502d: 0x0080, 0x502e: 0x0080, 0x502f: 0x0080,
0x5030: 0x0080, 0x5031: 0x0080, 0x5032: 0x0080, 0x5033: 0x0080, 0x5034: 0x0080, 0x5035: 0x0080,
0x5036: 0x0080, 0x5037: 0x0080, 0x5038: 0x0080, 0x5039: 0x0080, 0x503a: 0x0080, 0x503b: 0x0080,
0x503c: 0x0080, 0x503d: 0x0080, 0x503e: 0x0080, 0x503f: 0x0080,
// Block 0x141, offset 0x5040
0x5040: 0x0080, 0x5041: 0x0080, 0x5042: 0x0080, 0x5043: 0x0080, 0x5044: 0x0080, 0x5045: 0x0080,
0x5046: 0x0080, 0x5047: 0x0080, 0x5048: 0x0080, 0x5049: 0x0080, 0x504a: 0x0080, 0x504b: 0x0080,
0x504e: 0x0080, 0x504f: 0x0080, 0x5050: 0x0080, 0x5051: 0x0080,
0x5052: 0x0080, 0x5053: 0x0080, 0x5054: 0x0080, 0x5055: 0x0080, 0x5056: 0x0080, 0x5057: 0x0080,
0x5058: 0x0080, 0x5059: 0x0080, 0x505a: 0x0080, 0x505b: 0x0080, 0x505c: 0x0080, 0x505d: 0x0080,
0x505e: 0x0080, 0x505f: 0x0080, 0x5060: 0x0080, 0x5061: 0x0080, 0x5062: 0x0080, 0x5063: 0x0080,
0x5064: 0x0080, 0x5065: 0x0080, 0x5066: 0x0080, 0x5067: 0x0080, 0x5068: 0x0080, 0x5069: 0x0080,
0x506a: 0x0080, 0x506b: 0x0080, 0x506c: 0x0080, 0x506d: 0x0080, 0x506e: 0x0080, 0x506f: 0x0080,
0x5070: 0x0080, 0x5071: 0x0080, 0x5072: 0x0080, 0x5073: 0x0080, 0x5074: 0x0080, 0x5075: 0x0080,
0x5076: 0x0080, 0x5077: 0x0080, 0x5078: 0x0080, 0x5079: 0x0080, 0x507a: 0x0080, 0x507b: 0x0080,
0x507c: 0x0080, 0x507d: 0x0080, 0x507e: 0x0080, 0x507f: 0x0080,
// Block 0x142, offset 0x5080
0x5080: 0x00c3, 0x5081: 0x00c3, 0x5082: 0x00c3, 0x5083: 0x00c3, 0x5084: 0x00c3, 0x5085: 0x00c3,
0x5086: 0x00c3, 0x5087: 0x00c3, 0x5088: 0x00c3, 0x5089: 0x00c3, 0x508a: 0x00c3, 0x508b: 0x00c3,
0x508c: 0x00c3, 0x508d: 0x00c3, 0x508e: 0x00c3, 0x508f: 0x00c3, 0x5090: 0x00c3, 0x5091: 0x00c3,
0x5092: 0x00c3, 0x5093: 0x00c3, 0x5094: 0x00c3, 0x5095: 0x00c3, 0x5096: 0x00c3, 0x5097: 0x00c3,
0x5098: 0x00c3, 0x5099: 0x00c3, 0x509a: 0x00c3, 0x509b: 0x00c3, 0x509c: 0x00c3, 0x509d: 0x00c3,
0x509e: 0x00c3, 0x509f: 0x00c3, 0x50a0: 0x00c3, 0x50a1: 0x00c3, 0x50a2: 0x00c3, 0x50a3: 0x00c3,
0x50a4: 0x00c3, 0x50a5: 0x00c3, 0x50a6: 0x00c3, 0x50a7: 0x00c3, 0x50a8: 0x00c3, 0x50a9: 0x00c3,
0x50aa: 0x00c3, 0x50ab: 0x00c3, 0x50ac: 0x00c3, 0x50ad: 0x00c3, 0x50ae: 0x00c3, 0x50af: 0x00c3,
0x50b0: 0x00c3, 0x50b1: 0x00c3, 0x50b2: 0x00c3, 0x50b3: 0x00c3, 0x50b4: 0x00c3, 0x50b5: 0x00c3,
0x50b6: 0x00c3, 0x50b7: 0x0080, 0x50b8: 0x0080, 0x50b9: 0x0080, 0x50ba: 0x0080, 0x50bb: 0x00c3,
0x50bc: 0x00c3, 0x50bd: 0x00c3, 0x50be: 0x00c3, 0x50bf: 0x00c3,
// Block 0x143, offset 0x50c0
0x50c0: 0x00c3, 0x50c1: 0x00c3, 0x50c2: 0x00c3, 0x50c3: 0x00c3, 0x50c4: 0x00c3, 0x50c5: 0x00c3,
0x50c6: 0x00c3, 0x50c7: 0x00c3, 0x50c8: 0x00c3, 0x50c9: 0x00c3, 0x50ca: 0x00c3, 0x50cb: 0x00c3,
0x50cc: 0x00c3, 0x50cd: 0x00c3, 0x50ce: 0x00c3, 0x50cf: 0x00c3, 0x50d0: 0x00c3, 0x50d1: 0x00c3,
0x50d2: 0x00c3, 0x50d3: 0x00c3, 0x50d4: 0x00c3, 0x50d5: 0x00c3, 0x50d6: 0x00c3, 0x50d7: 0x00c3,
0x50d8: 0x00c3, 0x50d9: 0x00c3, 0x50da: 0x00c3, 0x50db: 0x00c3, 0x50dc: 0x00c3, 0x50dd: 0x00c3,
0x50de: 0x00c3, 0x50df: 0x00c3, 0x50e0: 0x00c3, 0x50e1: 0x00c3, 0x50e2: 0x00c3, 0x50e3: 0x00c3,
0x50e4: 0x00c3, 0x50e5: 0x00c3, 0x50e6: 0x00c3, 0x50e7: 0x00c3, 0x50e8: 0x00c3, 0x50e9: 0x00c3,
0x50ea: 0x00c3, 0x50eb: 0x00c3, 0x50ec: 0x00c3, 0x50ed: 0x0080, 0x50ee: 0x0080, 0x50ef: 0x0080,
0x50f0: 0x0080, 0x50f1: 0x0080, 0x50f2: 0x0080, 0x50f3: 0x0080, 0x50f4: 0x0080, 0x50f5: 0x00c3,
0x50f6: 0x0080, 0x50f7: 0x0080, 0x50f8: 0x0080, 0x50f9: 0x0080, 0x50fa: 0x0080, 0x50fb: 0x0080,
0x50fc: 0x0080, 0x50fd: 0x0080, 0x50fe: 0x0080, 0x50ff: 0x0080,
// Block 0x144, offset 0x5100
0x5100: 0x0080, 0x5101: 0x0080, 0x5102: 0x0080, 0x5103: 0x0080, 0x5104: 0x00c3, 0x5105: 0x0080,
0x5106: 0x0080, 0x5107: 0x0080, 0x5108: 0x0080, 0x5109: 0x0080, 0x510a: 0x0080, 0x510b: 0x0080,
0x511b: 0x00c3, 0x511c: 0x00c3, 0x511d: 0x00c3,
0x511e: 0x00c3, 0x511f: 0x00c3, 0x5121: 0x00c3, 0x5122: 0x00c3, 0x5123: 0x00c3,
0x5124: 0x00c3, 0x5125: 0x00c3, 0x5126: 0x00c3, 0x5127: 0x00c3, 0x5128: 0x00c3, 0x5129: 0x00c3,
0x512a: 0x00c3, 0x512b: 0x00c3, 0x512c: 0x00c3, 0x512d: 0x00c3, 0x512e: 0x00c3, 0x512f: 0x00c3,
// Block 0x145, offset 0x5140
0x5140: 0x00c0, 0x5141: 0x00c0, 0x5142: 0x00c0, 0x5143: 0x00c0, 0x5144: 0x00c0, 0x5145: 0x00c0,
0x5146: 0x00c0, 0x5147: 0x00c0, 0x5148: 0x00c0, 0x5149: 0x00c0, 0x514a: 0x00c0, 0x514b: 0x00c0,
0x514c: 0x00c0, 0x514d: 0x00c0, 0x514e: 0x00c0, 0x514f: 0x00c0, 0x5150: 0x00c0, 0x5151: 0x00c0,
0x5152: 0x00c0, 0x5153: 0x00c0, 0x5154: 0x00c0, 0x5155: 0x00c0, 0x5156: 0x00c0, 0x5157: 0x00c0,
0x5158: 0x00c0, 0x5159: 0x00c0, 0x515a: 0x00c0, 0x515b: 0x00c0, 0x515c: 0x00c0, 0x515d: 0x00c0,
0x515e: 0x00c0,
0x5165: 0x00c0, 0x5166: 0x00c0, 0x5167: 0x00c0, 0x5168: 0x00c0, 0x5169: 0x00c0,
0x516a: 0x00c0,
// Block 0x146, offset 0x5180
0x5180: 0x00c3, 0x5181: 0x00c3, 0x5182: 0x00c3, 0x5183: 0x00c3, 0x5184: 0x00c3, 0x5185: 0x00c3,
0x5186: 0x00c3, 0x5188: 0x00c3, 0x5189: 0x00c3, 0x518a: 0x00c3, 0x518b: 0x00c3,
0x518c: 0x00c3, 0x518d: 0x00c3, 0x518e: 0x00c3, 0x518f: 0x00c3, 0x5190: 0x00c3, 0x5191: 0x00c3,
0x5192: 0x00c3, 0x5193: 0x00c3, 0x5194: 0x00c3, 0x5195: 0x00c3, 0x5196: 0x00c3, 0x5197: 0x00c3,
0x5198: 0x00c3, 0x519b: 0x00c3, 0x519c: 0x00c3, 0x519d: 0x00c3,
0x519e: 0x00c3, 0x519f: 0x00c3, 0x51a0: 0x00c3, 0x51a1: 0x00c3, 0x51a3: 0x00c3,
0x51a4: 0x00c3, 0x51a6: 0x00c3, 0x51a7: 0x00c3, 0x51a8: 0x00c3, 0x51a9: 0x00c3,
0x51aa: 0x00c3,
0x51b0: 0x0080, 0x51b1: 0x0080, 0x51b2: 0x0080, 0x51b3: 0x0080, 0x51b4: 0x0080, 0x51b5: 0x0080,
0x51b6: 0x0080, 0x51b7: 0x0080, 0x51b8: 0x0080, 0x51b9: 0x0080, 0x51ba: 0x0080, 0x51bb: 0x0080,
0x51bc: 0x0080, 0x51bd: 0x0080, 0x51be: 0x0080, 0x51bf: 0x0080,
// Block 0x147, offset 0x51c0
0x51c0: 0x0080, 0x51c1: 0x0080, 0x51c2: 0x0080, 0x51c3: 0x0080, 0x51c4: 0x0080, 0x51c5: 0x0080,
0x51c6: 0x0080, 0x51c7: 0x0080, 0x51c8: 0x0080, 0x51c9: 0x0080, 0x51ca: 0x0080, 0x51cb: 0x0080,
0x51cc: 0x0080, 0x51cd: 0x0080, 0x51ce: 0x0080, 0x51cf: 0x0080, 0x51d0: 0x0080, 0x51d1: 0x0080,
0x51d2: 0x0080, 0x51d3: 0x0080, 0x51d4: 0x0080, 0x51d5: 0x0080, 0x51d6: 0x0080, 0x51d7: 0x0080,
0x51d8: 0x0080, 0x51d9: 0x0080, 0x51da: 0x0080, 0x51db: 0x0080, 0x51dc: 0x0080, 0x51dd: 0x0080,
0x51de: 0x0080, 0x51df: 0x0080, 0x51e0: 0x0080, 0x51e1: 0x0080, 0x51e2: 0x0080, 0x51e3: 0x0080,
0x51e4: 0x0080, 0x51e5: 0x0080, 0x51e6: 0x0080, 0x51e7: 0x0080, 0x51e8: 0x0080, 0x51e9: 0x0080,
0x51ea: 0x0080, 0x51eb: 0x0080, 0x51ec: 0x0080, 0x51ed: 0x0080,
// Block 0x148, offset 0x5200
0x520f: 0x00c3,
// Block 0x149, offset 0x5240
0x5240: 0x00c0, 0x5241: 0x00c0, 0x5242: 0x00c0, 0x5243: 0x00c0, 0x5244: 0x00c0, 0x5245: 0x00c0,
0x5246: 0x00c0, 0x5247: 0x00c0, 0x5248: 0x00c0, 0x5249: 0x00c0, 0x524a: 0x00c0, 0x524b: 0x00c0,
0x524c: 0x00c0, 0x524d: 0x00c0, 0x524e: 0x00c0, 0x524f: 0x00c0, 0x5250: 0x00c0, 0x5251: 0x00c0,
0x5252: 0x00c0, 0x5253: 0x00c0, 0x5254: 0x00c0, 0x5255: 0x00c0, 0x5256: 0x00c0, 0x5257: 0x00c0,
0x5258: 0x00c0, 0x5259: 0x00c0, 0x525a: 0x00c0, 0x525b: 0x00c0, 0x525c: 0x00c0, 0x525d: 0x00c0,
0x525e: 0x00c0, 0x525f: 0x00c0, 0x5260: 0x00c0, 0x5261: 0x00c0, 0x5262: 0x00c0, 0x5263: 0x00c0,
0x5264: 0x00c0, 0x5265: 0x00c0, 0x5266: 0x00c0, 0x5267: 0x00c0, 0x5268: 0x00c0, 0x5269: 0x00c0,
0x526a: 0x00c0, 0x526b: 0x00c0, 0x526c: 0x00c0,
0x5270: 0x00c3, 0x5271: 0x00c3, 0x5272: 0x00c3, 0x5273: 0x00c3, 0x5274: 0x00c3, 0x5275: 0x00c3,
0x5276: 0x00c3, 0x5277: 0x00c0, 0x5278: 0x00c0, 0x5279: 0x00c0, 0x527a: 0x00c0, 0x527b: 0x00c0,
0x527c: 0x00c0, 0x527d: 0x00c0,
// Block 0x14a, offset 0x5280
0x5280: 0x00c0, 0x5281: 0x00c0, 0x5282: 0x00c0, 0x5283: 0x00c0, 0x5284: 0x00c0, 0x5285: 0x00c0,
0x5286: 0x00c0, 0x5287: 0x00c0, 0x5288: 0x00c0, 0x5289: 0x00c0,
0x528e: 0x00c0, 0x528f: 0x0080,
// Block 0x14b, offset 0x52c0
0x52d0: 0x00c0, 0x52d1: 0x00c0,
0x52d2: 0x00c0, 0x52d3: 0x00c0, 0x52d4: 0x00c0, 0x52d5: 0x00c0, 0x52d6: 0x00c0, 0x52d7: 0x00c0,
0x52d8: 0x00c0, 0x52d9: 0x00c0, 0x52da: 0x00c0, 0x52db: 0x00c0, 0x52dc: 0x00c0, 0x52dd: 0x00c0,
0x52de: 0x00c0, 0x52df: 0x00c0, 0x52e0: 0x00c0, 0x52e1: 0x00c0, 0x52e2: 0x00c0, 0x52e3: 0x00c0,
0x52e4: 0x00c0, 0x52e5: 0x00c0, 0x52e6: 0x00c0, 0x52e7: 0x00c0, 0x52e8: 0x00c0, 0x52e9: 0x00c0,
0x52ea: 0x00c0, 0x52eb: 0x00c0, 0x52ec: 0x00c0, 0x52ed: 0x00c0, 0x52ee: 0x00c3,
// Block 0x14c, offset 0x5300
0x5300: 0x00c0, 0x5301: 0x00c0, 0x5302: 0x00c0, 0x5303: 0x00c0, 0x5304: 0x00c0, 0x5305: 0x00c0,
0x5306: 0x00c0, 0x5307: 0x00c0, 0x5308: 0x00c0, 0x5309: 0x00c0, 0x530a: 0x00c0, 0x530b: 0x00c0,
0x530c: 0x00c0, 0x530d: 0x00c0, 0x530e: 0x00c0, 0x530f: 0x00c0, 0x5310: 0x00c0, 0x5311: 0x00c0,
0x5312: 0x00c0, 0x5313: 0x00c0, 0x5314: 0x00c0, 0x5315: 0x00c0, 0x5316: 0x00c0, 0x5317: 0x00c0,
0x5318: 0x00c0, 0x5319: 0x00c0, 0x531a: 0x00c0, 0x531b: 0x00c0, 0x531c: 0x00c0, 0x531d: 0x00c0,
0x531e: 0x00c0, 0x531f: 0x00c0, 0x5320: 0x00c0, 0x5321: 0x00c0, 0x5322: 0x00c0, 0x5323: 0x00c0,
0x5324: 0x00c0, 0x5325: 0x00c0, 0x5326: 0x00c0, 0x5327: 0x00c0, 0x5328: 0x00c0, 0x5329: 0x00c0,
0x532a: 0x00c0, 0x532b: 0x00c0, 0x532c: 0x00c3, 0x532d: 0x00c3, 0x532e: 0x00c3, 0x532f: 0x00c3,
0x5330: 0x00c0, 0x5331: 0x00c0, 0x5332: 0x00c0, 0x5333: 0x00c0, 0x5334: 0x00c0, 0x5335: 0x00c0,
0x5336: 0x00c0, 0x5337: 0x00c0, 0x5338: 0x00c0, 0x5339: 0x00c0,
0x533f: 0x0080,
// Block 0x14d, offset 0x5340
0x5350: 0x00c0, 0x5351: 0x00c0,
0x5352: 0x00c0, 0x5353: 0x00c0, 0x5354: 0x00c0, 0x5355: 0x00c0, 0x5356: 0x00c0, 0x5357: 0x00c0,
0x5358: 0x00c0, 0x5359: 0x00c0, 0x535a: 0x00c0, 0x535b: 0x00c0, 0x535c: 0x00c0, 0x535d: 0x00c0,
0x535e: 0x00c0, 0x535f: 0x00c0, 0x5360: 0x00c0, 0x5361: 0x00c0, 0x5362: 0x00c0, 0x5363: 0x00c0,
0x5364: 0x00c0, 0x5365: 0x00c0, 0x5366: 0x00c0, 0x5367: 0x00c0, 0x5368: 0x00c0, 0x5369: 0x00c0,
0x536a: 0x00c0, 0x536b: 0x00c0, 0x536c: 0x00c3, 0x536d: 0x00c3, 0x536e: 0x00c3, 0x536f: 0x00c3,
0x5370: 0x00c0, 0x5371: 0x00c0, 0x5372: 0x00c0, 0x5373: 0x00c0, 0x5374: 0x00c0, 0x5375: 0x00c0,
0x5376: 0x00c0, 0x5377: 0x00c0, 0x5378: 0x00c0, 0x5379: 0x00c0,
// Block 0x14e, offset 0x5380
0x53a0: 0x00c0, 0x53a1: 0x00c0, 0x53a2: 0x00c0, 0x53a3: 0x00c0,
0x53a4: 0x00c0, 0x53a5: 0x00c0, 0x53a6: 0x00c0, 0x53a8: 0x00c0, 0x53a9: 0x00c0,
0x53aa: 0x00c0, 0x53ab: 0x00c0, 0x53ad: 0x00c0, 0x53ae: 0x00c0,
0x53b0: 0x00c0, 0x53b1: 0x00c0, 0x53b2: 0x00c0, 0x53b3: 0x00c0, 0x53b4: 0x00c0, 0x53b5: 0x00c0,
0x53b6: 0x00c0, 0x53b7: 0x00c0, 0x53b8: 0x00c0, 0x53b9: 0x00c0, 0x53ba: 0x00c0, 0x53bb: 0x00c0,
0x53bc: 0x00c0, 0x53bd: 0x00c0, 0x53be: 0x00c0,
// Block 0x14f, offset 0x53c0
0x53c0: 0x00c0, 0x53c1: 0x00c0, 0x53c2: 0x00c0, 0x53c3: 0x00c0, 0x53c4: 0x00c0,
0x53c7: 0x0080, 0x53c8: 0x0080, 0x53c9: 0x0080, 0x53ca: 0x0080, 0x53cb: 0x0080,
0x53cc: 0x0080, 0x53cd: 0x0080, 0x53ce: 0x0080, 0x53cf: 0x0080, 0x53d0: 0x00c3, 0x53d1: 0x00c3,
0x53d2: 0x00c3, 0x53d3: 0x00c3, 0x53d4: 0x00c3, 0x53d5: 0x00c3, 0x53d6: 0x00c3,
// Block 0x150, offset 0x5400
0x5400: 0x00c2, 0x5401: 0x00c2, 0x5402: 0x00c2, 0x5403: 0x00c2, 0x5404: 0x00c2, 0x5405: 0x00c2,
0x5406: 0x00c2, 0x5407: 0x00c2, 0x5408: 0x00c2, 0x5409: 0x00c2, 0x540a: 0x00c2, 0x540b: 0x00c2,
0x540c: 0x00c2, 0x540d: 0x00c2, 0x540e: 0x00c2, 0x540f: 0x00c2, 0x5410: 0x00c2, 0x5411: 0x00c2,
0x5412: 0x00c2, 0x5413: 0x00c2, 0x5414: 0x00c2, 0x5415: 0x00c2, 0x5416: 0x00c2, 0x5417: 0x00c2,
0x5418: 0x00c2, 0x5419: 0x00c2, 0x541a: 0x00c2, 0x541b: 0x00c2, 0x541c: 0x00c2, 0x541d: 0x00c2,
0x541e: 0x00c2, 0x541f: 0x00c2, 0x5420: 0x00c2, 0x5421: 0x00c2, 0x5422: 0x00c2, 0x5423: 0x00c2,
0x5424: 0x00c2, 0x5425: 0x00c2, 0x5426: 0x00c2, 0x5427: 0x00c2, 0x5428: 0x00c2, 0x5429: 0x00c2,
0x542a: 0x00c2, 0x542b: 0x00c2, 0x542c: 0x00c2, 0x542d: 0x00c2, 0x542e: 0x00c2, 0x542f: 0x00c2,
0x5430: 0x00c2, 0x5431: 0x00c2, 0x5432: 0x00c2, 0x5433: 0x00c2, 0x5434: 0x00c2, 0x5435: 0x00c2,
0x5436: 0x00c2, 0x5437: 0x00c2, 0x5438: 0x00c2, 0x5439: 0x00c2, 0x543a: 0x00c2, 0x543b: 0x00c2,
0x543c: 0x00c2, 0x543d: 0x00c2, 0x543e: 0x00c2, 0x543f: 0x00c2,
// Block 0x151, offset 0x5440
0x5440: 0x00c2, 0x5441: 0x00c2, 0x5442: 0x00c2, 0x5443: 0x00c2, 0x5444: 0x00c3, 0x5445: 0x00c3,
0x5446: 0x00c3, 0x5447: 0x00c3, 0x5448: 0x00c3, 0x5449: 0x00c3, 0x544a: 0x00c3, 0x544b: 0x00c3,
0x5450: 0x00c0, 0x5451: 0x00c0,
0x5452: 0x00c0, 0x5453: 0x00c0, 0x5454: 0x00c0, 0x5455: 0x00c0, 0x5456: 0x00c0, 0x5457: 0x00c0,
0x5458: 0x00c0, 0x5459: 0x00c0,
0x545e: 0x0080, 0x545f: 0x0080,
// Block 0x152, offset 0x5480
0x54b1: 0x0080, 0x54b2: 0x0080, 0x54b3: 0x0080, 0x54b4: 0x0080, 0x54b5: 0x0080,
0x54b6: 0x0080, 0x54b7: 0x0080, 0x54b8: 0x0080, 0x54b9: 0x0080, 0x54ba: 0x0080, 0x54bb: 0x0080,
0x54bc: 0x0080, 0x54bd: 0x0080, 0x54be: 0x0080, 0x54bf: 0x0080,
// Block 0x153, offset 0x54c0
0x54c0: 0x0080, 0x54c1: 0x0080, 0x54c2: 0x0080, 0x54c3: 0x0080, 0x54c4: 0x0080, 0x54c5: 0x0080,
0x54c6: 0x0080, 0x54c7: 0x0080, 0x54c8: 0x0080, 0x54c9: 0x0080, 0x54ca: 0x0080, 0x54cb: 0x0080,
0x54cc: 0x0080, 0x54cd: 0x0080, 0x54ce: 0x0080, 0x54cf: 0x0080, 0x54d0: 0x0080, 0x54d1: 0x0080,
0x54d2: 0x0080, 0x54d3: 0x0080, 0x54d4: 0x0080, 0x54d5: 0x0080, 0x54d6: 0x0080, 0x54d7: 0x0080,
0x54d8: 0x0080, 0x54d9: 0x0080, 0x54da: 0x0080, 0x54db: 0x0080, 0x54dc: 0x0080, 0x54dd: 0x0080,
0x54de: 0x0080, 0x54df: 0x0080, 0x54e0: 0x0080, 0x54e1: 0x0080, 0x54e2: 0x0080, 0x54e3: 0x0080,
0x54e4: 0x0080, 0x54e5: 0x0080, 0x54e6: 0x0080, 0x54e7: 0x0080, 0x54e8: 0x0080, 0x54e9: 0x0080,
0x54ea: 0x0080, 0x54eb: 0x0080, 0x54ec: 0x0080, 0x54ed: 0x0080, 0x54ee: 0x0080, 0x54ef: 0x0080,
0x54f0: 0x0080, 0x54f1: 0x0080, 0x54f2: 0x0080, 0x54f3: 0x0080, 0x54f4: 0x0080,
// Block 0x154, offset 0x5500
0x5501: 0x0080, 0x5502: 0x0080, 0x5503: 0x0080, 0x5504: 0x0080, 0x5505: 0x0080,
0x5506: 0x0080, 0x5507: 0x0080, 0x5508: 0x0080, 0x5509: 0x0080, 0x550a: 0x0080, 0x550b: 0x0080,
0x550c: 0x0080, 0x550d: 0x0080, 0x550e: 0x0080, 0x550f: 0x0080, 0x5510: 0x0080, 0x5511: 0x0080,
0x5512: 0x0080, 0x5513: 0x0080, 0x5514: 0x0080, 0x5515: 0x0080, 0x5516: 0x0080, 0x5517: 0x0080,
0x5518: 0x0080, 0x5519: 0x0080, 0x551a: 0x0080, 0x551b: 0x0080, 0x551c: 0x0080, 0x551d: 0x0080,
0x551e: 0x0080, 0x551f: 0x0080, 0x5520: 0x0080, 0x5521: 0x0080, 0x5522: 0x0080, 0x5523: 0x0080,
0x5524: 0x0080, 0x5525: 0x0080, 0x5526: 0x0080, 0x5527: 0x0080, 0x5528: 0x0080, 0x5529: 0x0080,
0x552a: 0x0080, 0x552b: 0x0080, 0x552c: 0x0080, 0x552d: 0x0080, 0x552e: 0x0080, 0x552f: 0x0080,
0x5530: 0x0080, 0x5531: 0x0080, 0x5532: 0x0080, 0x5533: 0x0080, 0x5534: 0x0080, 0x5535: 0x0080,
0x5536: 0x0080, 0x5537: 0x0080, 0x5538: 0x0080, 0x5539: 0x0080, 0x553a: 0x0080, 0x553b: 0x0080,
0x553c: 0x0080, 0x553d: 0x0080,
// Block 0x155, offset 0x5540
0x5540: 0x0080, 0x5541: 0x0080, 0x5542: 0x0080, 0x5543: 0x0080, 0x5545: 0x0080,
0x5546: 0x0080, 0x5547: 0x0080, 0x5548: 0x0080, 0x5549: 0x0080, 0x554a: 0x0080, 0x554b: 0x0080,
0x554c: 0x0080, 0x554d: 0x0080, 0x554e: 0x0080, 0x554f: 0x0080, 0x5550: 0x0080, 0x5551: 0x0080,
0x5552: 0x0080, 0x5553: 0x0080, 0x5554: 0x0080, 0x5555: 0x0080, 0x5556: 0x0080, 0x5557: 0x0080,
0x5558: 0x0080, 0x5559: 0x0080, 0x555a: 0x0080, 0x555b: 0x0080, 0x555c: 0x0080, 0x555d: 0x0080,
0x555e: 0x0080, 0x555f: 0x0080, 0x5561: 0x0080, 0x5562: 0x0080,
0x5564: 0x0080, 0x5567: 0x0080, 0x5569: 0x0080,
0x556a: 0x0080, 0x556b: 0x0080, 0x556c: 0x0080, 0x556d: 0x0080, 0x556e: 0x0080, 0x556f: 0x0080,
0x5570: 0x0080, 0x5571: 0x0080, 0x5572: 0x0080, 0x5574: 0x0080, 0x5575: 0x0080,
0x5576: 0x0080, 0x5577: 0x0080, 0x5579: 0x0080, 0x557b: 0x0080,
// Block 0x156, offset 0x5580
0x5582: 0x0080,
0x5587: 0x0080, 0x5589: 0x0080, 0x558b: 0x0080,
0x558d: 0x0080, 0x558e: 0x0080, 0x558f: 0x0080, 0x5591: 0x0080,
0x5592: 0x0080, 0x5594: 0x0080, 0x5597: 0x0080,
0x5599: 0x0080, 0x559b: 0x0080, 0x559d: 0x0080,
0x559f: 0x0080, 0x55a1: 0x0080, 0x55a2: 0x0080,
0x55a4: 0x0080, 0x55a7: 0x0080, 0x55a8: 0x0080, 0x55a9: 0x0080,
0x55aa: 0x0080, 0x55ac: 0x0080, 0x55ad: 0x0080, 0x55ae: 0x0080, 0x55af: 0x0080,
0x55b0: 0x0080, 0x55b1: 0x0080, 0x55b2: 0x0080, 0x55b4: 0x0080, 0x55b5: 0x0080,
0x55b6: 0x0080, 0x55b7: 0x0080, 0x55b9: 0x0080, 0x55ba: 0x0080, 0x55bb: 0x0080,
0x55bc: 0x0080, 0x55be: 0x0080,
// Block 0x157, offset 0x55c0
0x55c0: 0x0080, 0x55c1: 0x0080, 0x55c2: 0x0080, 0x55c3: 0x0080, 0x55c4: 0x0080, 0x55c5: 0x0080,
0x55c6: 0x0080, 0x55c7: 0x0080, 0x55c8: 0x0080, 0x55c9: 0x0080, 0x55cb: 0x0080,
0x55cc: 0x0080, 0x55cd: 0x0080, 0x55ce: 0x0080, 0x55cf: 0x0080, 0x55d0: 0x0080, 0x55d1: 0x0080,
0x55d2: 0x0080, 0x55d3: 0x0080, 0x55d4: 0x0080, 0x55d5: 0x0080, 0x55d6: 0x0080, 0x55d7: 0x0080,
0x55d8: 0x0080, 0x55d9: 0x0080, 0x55da: 0x0080, 0x55db: 0x0080,
0x55e1: 0x0080, 0x55e2: 0x0080, 0x55e3: 0x0080,
0x55e5: 0x0080, 0x55e6: 0x0080, 0x55e7: 0x0080, 0x55e8: 0x0080, 0x55e9: 0x0080,
0x55eb: 0x0080, 0x55ec: 0x0080, 0x55ed: 0x0080, 0x55ee: 0x0080, 0x55ef: 0x0080,
0x55f0: 0x0080, 0x55f1: 0x0080, 0x55f2: 0x0080, 0x55f3: 0x0080, 0x55f4: 0x0080, 0x55f5: 0x0080,
0x55f6: 0x0080, 0x55f7: 0x0080, 0x55f8: 0x0080, 0x55f9: 0x0080, 0x55fa: 0x0080, 0x55fb: 0x0080,
// Block 0x158, offset 0x5600
0x5630: 0x0080, 0x5631: 0x0080,
// Block 0x159, offset 0x5640
0x5640: 0x0080, 0x5641: 0x0080, 0x5642: 0x0080, 0x5643: 0x0080, 0x5644: 0x0080, 0x5645: 0x0080,
0x5646: 0x0080, 0x5647: 0x0080, 0x5648: 0x0080, 0x5649: 0x0080, 0x564a: 0x0080, 0x564b: 0x0080,
0x564c: 0x0080, 0x564d: 0x0080, 0x564e: 0x0080, 0x564f: 0x0080, 0x5650: 0x0080, 0x5651: 0x0080,
0x5652: 0x0080, 0x5653: 0x0080, 0x5654: 0x0080, 0x5655: 0x0080, 0x5656: 0x0080, 0x5657: 0x0080,
0x5658: 0x0080, 0x5659: 0x0080, 0x565a: 0x0080, 0x565b: 0x0080, 0x565c: 0x0080, 0x565d: 0x0080,
0x565e: 0x0080, 0x565f: 0x0080, 0x5660: 0x0080, 0x5661: 0x0080, 0x5662: 0x0080, 0x5663: 0x0080,
0x5664: 0x0080, 0x5665: 0x0080, 0x5666: 0x0080, 0x5667: 0x0080, 0x5668: 0x0080, 0x5669: 0x0080,
0x566a: 0x0080, 0x566b: 0x0080,
0x5670: 0x0080, 0x5671: 0x0080, 0x5672: 0x0080, 0x5673: 0x0080, 0x5674: 0x0080, 0x5675: 0x0080,
0x5676: 0x0080, 0x5677: 0x0080, 0x5678: 0x0080, 0x5679: 0x0080, 0x567a: 0x0080, 0x567b: 0x0080,
0x567c: 0x0080, 0x567d: 0x0080, 0x567e: 0x0080, 0x567f: 0x0080,
// Block 0x15a, offset 0x5680
0x5680: 0x0080, 0x5681: 0x0080, 0x5682: 0x0080, 0x5683: 0x0080, 0x5684: 0x0080, 0x5685: 0x0080,
0x5686: 0x0080, 0x5687: 0x0080, 0x5688: 0x0080, 0x5689: 0x0080, 0x568a: 0x0080, 0x568b: 0x0080,
0x568c: 0x0080, 0x568d: 0x0080, 0x568e: 0x0080, 0x568f: 0x0080, 0x5690: 0x0080, 0x5691: 0x0080,
0x5692: 0x0080, 0x5693: 0x0080,
0x56a0: 0x0080, 0x56a1: 0x0080, 0x56a2: 0x0080, 0x56a3: 0x0080,
0x56a4: 0x0080, 0x56a5: 0x0080, 0x56a6: 0x0080, 0x56a7: 0x0080, 0x56a8: 0x0080, 0x56a9: 0x0080,
0x56aa: 0x0080, 0x56ab: 0x0080, 0x56ac: 0x0080, 0x56ad: 0x0080, 0x56ae: 0x0080,
0x56b1: 0x0080, 0x56b2: 0x0080, 0x56b3: 0x0080, 0x56b4: 0x0080, 0x56b5: 0x0080,
0x56b6: 0x0080, 0x56b7: 0x0080, 0x56b8: 0x0080, 0x56b9: 0x0080, 0x56ba: 0x0080, 0x56bb: 0x0080,
0x56bc: 0x0080, 0x56bd: 0x0080, 0x56be: 0x0080, 0x56bf: 0x0080,
// Block 0x15b, offset 0x56c0
0x56c1: 0x0080, 0x56c2: 0x0080, 0x56c3: 0x0080, 0x56c4: 0x0080, 0x56c5: 0x0080,
0x56c6: 0x0080, 0x56c7: 0x0080, 0x56c8: 0x0080, 0x56c9: 0x0080, 0x56ca: 0x0080, 0x56cb: 0x0080,
0x56cc: 0x0080, 0x56cd: 0x0080, 0x56ce: 0x0080, 0x56cf: 0x0080, 0x56d1: 0x0080,
0x56d2: 0x0080, 0x56d3: 0x0080, 0x56d4: 0x0080, 0x56d5: 0x0080, 0x56d6: 0x0080, 0x56d7: 0x0080,
0x56d8: 0x0080, 0x56d9: 0x0080, 0x56da: 0x0080, 0x56db: 0x0080, 0x56dc: 0x0080, 0x56dd: 0x0080,
0x56de: 0x0080, 0x56df: 0x0080, 0x56e0: 0x0080, 0x56e1: 0x0080, 0x56e2: 0x0080, 0x56e3: 0x0080,
0x56e4: 0x0080, 0x56e5: 0x0080, 0x56e6: 0x0080, 0x56e7: 0x0080, 0x56e8: 0x0080, 0x56e9: 0x0080,
0x56ea: 0x0080, 0x56eb: 0x0080, 0x56ec: 0x0080, 0x56ed: 0x0080, 0x56ee: 0x0080, 0x56ef: 0x0080,
0x56f0: 0x0080, 0x56f1: 0x0080, 0x56f2: 0x0080, 0x56f3: 0x0080, 0x56f4: 0x0080, 0x56f5: 0x0080,
// Block 0x15c, offset 0x5700
0x5726: 0x0080, 0x5727: 0x0080, 0x5728: 0x0080, 0x5729: 0x0080,
0x572a: 0x0080, 0x572b: 0x0080, 0x572c: 0x0080, 0x572d: 0x0080, 0x572e: 0x0080, 0x572f: 0x0080,
0x5730: 0x0080, 0x5731: 0x0080, 0x5732: 0x0080, 0x5733: 0x0080, 0x5734: 0x0080, 0x5735: 0x0080,
0x5736: 0x0080, 0x5737: 0x0080, 0x5738: 0x0080, 0x5739: 0x0080, 0x573a: 0x0080, 0x573b: 0x0080,
0x573c: 0x0080, 0x573d: 0x0080, 0x573e: 0x0080, 0x573f: 0x0080,
// Block 0x15d, offset 0x5740
0x5740: 0x008c, 0x5741: 0x0080, 0x5742: 0x0080,
0x5750: 0x0080, 0x5751: 0x0080,
0x5752: 0x0080, 0x5753: 0x0080, 0x5754: 0x0080, 0x5755: 0x0080, 0x5756: 0x0080, 0x5757: 0x0080,
0x5758: 0x0080, 0x5759: 0x0080, 0x575a: 0x0080, 0x575b: 0x0080, 0x575c: 0x0080, 0x575d: 0x0080,
0x575e: 0x0080, 0x575f: 0x0080, 0x5760: 0x0080, 0x5761: 0x0080, 0x5762: 0x0080, 0x5763: 0x0080,
0x5764: 0x0080, 0x5765: 0x0080, 0x5766: 0x0080, 0x5767: 0x0080, 0x5768: 0x0080, 0x5769: 0x0080,
0x576a: 0x0080, 0x576b: 0x0080, 0x576c: 0x0080, 0x576d: 0x0080, 0x576e: 0x0080, 0x576f: 0x0080,
0x5770: 0x0080, 0x5771: 0x0080, 0x5772: 0x0080, 0x5773: 0x0080, 0x5774: 0x0080, 0x5775: 0x0080,
0x5776: 0x0080, 0x5777: 0x0080, 0x5778: 0x0080, 0x5779: 0x0080, 0x577a: 0x0080, 0x577b: 0x0080,
// Block 0x15e, offset 0x5780
0x5780: 0x0080, 0x5781: 0x0080, 0x5782: 0x0080, 0x5783: 0x0080, 0x5784: 0x0080, 0x5785: 0x0080,
0x5786: 0x0080, 0x5787: 0x0080, 0x5788: 0x0080,
0x5790: 0x0080, 0x5791: 0x0080,
0x57a0: 0x0080, 0x57a1: 0x0080, 0x57a2: 0x0080, 0x57a3: 0x0080,
0x57a4: 0x0080, 0x57a5: 0x0080,
// Block 0x15f, offset 0x57c0
0x57c0: 0x0080, 0x57c1: 0x0080, 0x57c2: 0x0080, 0x57c3: 0x0080, 0x57c4: 0x0080, 0x57c5: 0x0080,
0x57c6: 0x0080, 0x57c7: 0x0080, 0x57c8: 0x0080, 0x57c9: 0x0080, 0x57ca: 0x0080, 0x57cb: 0x0080,
0x57cc: 0x0080, 0x57cd: 0x0080, 0x57ce: 0x0080, 0x57cf: 0x0080, 0x57d0: 0x0080, 0x57d1: 0x0080,
0x57d2: 0x0080, 0x57d3: 0x0080, 0x57d4: 0x0080, 0x57d5: 0x0080, 0x57d6: 0x0080, 0x57d7: 0x0080,
0x57dc: 0x0080, 0x57dd: 0x0080,
0x57de: 0x0080, 0x57df: 0x0080, 0x57e0: 0x0080, 0x57e1: 0x0080, 0x57e2: 0x0080, 0x57e3: 0x0080,
0x57e4: 0x0080, 0x57e5: 0x0080, 0x57e6: 0x0080, 0x57e7: 0x0080, 0x57e8: 0x0080, 0x57e9: 0x0080,
0x57ea: 0x0080, 0x57eb: 0x0080, 0x57ec: 0x0080,
0x57f0: 0x0080, 0x57f1: 0x0080, 0x57f2: 0x0080, 0x57f3: 0x0080, 0x57f4: 0x0080, 0x57f5: 0x0080,
0x57f6: 0x0080, 0x57f7: 0x0080, 0x57f8: 0x0080, 0x57f9: 0x0080, 0x57fa: 0x0080, 0x57fb: 0x0080,
0x57fc: 0x0080,
// Block 0x160, offset 0x5800
0x5800: 0x0080, 0x5801: 0x0080, 0x5802: 0x0080, 0x5803: 0x0080, 0x5804: 0x0080, 0x5805: 0x0080,
0x5806: 0x0080, 0x5807: 0x0080, 0x5808: 0x0080, 0x5809: 0x0080, 0x580a: 0x0080, 0x580b: 0x0080,
0x580c: 0x0080, 0x580d: 0x0080, 0x580e: 0x0080, 0x580f: 0x0080, 0x5810: 0x0080, 0x5811: 0x0080,
0x5812: 0x0080, 0x5813: 0x0080, 0x5814: 0x0080, 0x5815: 0x0080, 0x5816: 0x0080, 0x5817: 0x0080,
0x5818: 0x0080, 0x5819: 0x0080, 0x581a: 0x0080, 0x581b: 0x0080, 0x581c: 0x0080, 0x581d: 0x0080,
0x581e: 0x0080, 0x581f: 0x0080, 0x5820: 0x0080, 0x5821: 0x0080, 0x5822: 0x0080, 0x5823: 0x0080,
0x5824: 0x0080, 0x5825: 0x0080, 0x5826: 0x0080, 0x5827: 0x0080, 0x5828: 0x0080, 0x5829: 0x0080,
0x582a: 0x0080, 0x582b: 0x0080, 0x582c: 0x0080, 0x582d: 0x0080, 0x582e: 0x0080, 0x582f: 0x0080,
0x5830: 0x0080, 0x5831: 0x0080, 0x5832: 0x0080, 0x5833: 0x0080, 0x5834: 0x0080, 0x5835: 0x0080,
0x5836: 0x0080, 0x583b: 0x0080,
0x583c: 0x0080, 0x583d: 0x0080, 0x583e: 0x0080, 0x583f: 0x0080,
// Block 0x161, offset 0x5840
0x5840: 0x0080, 0x5841: 0x0080, 0x5842: 0x0080, 0x5843: 0x0080, 0x5844: 0x0080, 0x5845: 0x0080,
0x5846: 0x0080, 0x5847: 0x0080, 0x5848: 0x0080, 0x5849: 0x0080, 0x584a: 0x0080, 0x584b: 0x0080,
0x584c: 0x0080, 0x584d: 0x0080, 0x584e: 0x0080, 0x584f: 0x0080, 0x5850: 0x0080, 0x5851: 0x0080,
0x5852: 0x0080, 0x5853: 0x0080, 0x5854: 0x0080, 0x5855: 0x0080, 0x5856: 0x0080, 0x5857: 0x0080,
0x5858: 0x0080, 0x5859: 0x0080,
0x5860: 0x0080, 0x5861: 0x0080, 0x5862: 0x0080, 0x5863: 0x0080,
0x5864: 0x0080, 0x5865: 0x0080, 0x5866: 0x0080, 0x5867: 0x0080, 0x5868: 0x0080, 0x5869: 0x0080,
0x586a: 0x0080, 0x586b: 0x0080,
0x5870: 0x0080,
// Block 0x162, offset 0x5880
0x5880: 0x0080, 0x5881: 0x0080, 0x5882: 0x0080, 0x5883: 0x0080, 0x5884: 0x0080, 0x5885: 0x0080,
0x5886: 0x0080, 0x5887: 0x0080, 0x5888: 0x0080, 0x5889: 0x0080, 0x588a: 0x0080, 0x588b: 0x0080,
0x5890: 0x0080, 0x5891: 0x0080,
0x5892: 0x0080, 0x5893: 0x0080, 0x5894: 0x0080, 0x5895: 0x0080, 0x5896: 0x0080, 0x5897: 0x0080,
0x5898: 0x0080, 0x5899: 0x0080, 0x589a: 0x0080, 0x589b: 0x0080, 0x589c: 0x0080, 0x589d: 0x0080,
0x589e: 0x0080, 0x589f: 0x0080, 0x58a0: 0x0080, 0x58a1: 0x0080, 0x58a2: 0x0080, 0x58a3: 0x0080,
0x58a4: 0x0080, 0x58a5: 0x0080, 0x58a6: 0x0080, 0x58a7: 0x0080, 0x58a8: 0x0080, 0x58a9: 0x0080,
0x58aa: 0x0080, 0x58ab: 0x0080, 0x58ac: 0x0080, 0x58ad: 0x0080, 0x58ae: 0x0080, 0x58af: 0x0080,
0x58b0: 0x0080, 0x58b1: 0x0080, 0x58b2: 0x0080, 0x58b3: 0x0080, 0x58b4: 0x0080, 0x58b5: 0x0080,
0x58b6: 0x0080, 0x58b7: 0x0080, 0x58b8: 0x0080, 0x58b9: 0x0080, 0x58ba: 0x0080, 0x58bb: 0x0080,
0x58bc: 0x0080, 0x58bd: 0x0080, 0x58be: 0x0080, 0x58bf: 0x0080,
// Block 0x163, offset 0x58c0
0x58c0: 0x0080, 0x58c1: 0x0080, 0x58c2: 0x0080, 0x58c3: 0x0080, 0x58c4: 0x0080, 0x58c5: 0x0080,
0x58c6: 0x0080, 0x58c7: 0x0080,
0x58d0: 0x0080, 0x58d1: 0x0080,
0x58d2: 0x0080, 0x58d3: 0x0080, 0x58d4: 0x0080, 0x58d5: 0x0080, 0x58d6: 0x0080, 0x58d7: 0x0080,
0x58d8: 0x0080, 0x58d9: 0x0080,
0x58e0: 0x0080, 0x58e1: 0x0080, 0x58e2: 0x0080, 0x58e3: 0x0080,
0x58e4: 0x0080, 0x58e5: 0x0080, 0x58e6: 0x0080, 0x58e7: 0x0080, 0x58e8: 0x0080, 0x58e9: 0x0080,
0x58ea: 0x0080, 0x58eb: 0x0080, 0x58ec: 0x0080, 0x58ed: 0x0080, 0x58ee: 0x0080, 0x58ef: 0x0080,
0x58f0: 0x0080, 0x58f1: 0x0080, 0x58f2: 0x0080, 0x58f3: 0x0080, 0x58f4: 0x0080, 0x58f5: 0x0080,
0x58f6: 0x0080, 0x58f7: 0x0080, 0x58f8: 0x0080, 0x58f9: 0x0080, 0x58fa: 0x0080, 0x58fb: 0x0080,
0x58fc: 0x0080, 0x58fd: 0x0080, 0x58fe: 0x0080, 0x58ff: 0x0080,
// Block 0x164, offset 0x5900
0x5900: 0x0080, 0x5901: 0x0080, 0x5902: 0x0080, 0x5903: 0x0080, 0x5904: 0x0080, 0x5905: 0x0080,
0x5906: 0x0080, 0x5907: 0x0080,
0x5910: 0x0080, 0x5911: 0x0080,
0x5912: 0x0080, 0x5913: 0x0080, 0x5914: 0x0080, 0x5915: 0x0080, 0x5916: 0x0080, 0x5917: 0x0080,
0x5918: 0x0080, 0x5919: 0x0080, 0x591a: 0x0080, 0x591b: 0x0080, 0x591c: 0x0080, 0x591d: 0x0080,
0x591e: 0x0080, 0x591f: 0x0080, 0x5920: 0x0080, 0x5921: 0x0080, 0x5922: 0x0080, 0x5923: 0x0080,
0x5924: 0x0080, 0x5925: 0x0080, 0x5926: 0x0080, 0x5927: 0x0080, 0x5928: 0x0080, 0x5929: 0x0080,
0x592a: 0x0080, 0x592b: 0x0080, 0x592c: 0x0080, 0x592d: 0x0080,
0x5930: 0x0080, 0x5931: 0x0080,
// Block 0x165, offset 0x5940
0x5940: 0x0080, 0x5941: 0x0080, 0x5942: 0x0080, 0x5943: 0x0080, 0x5944: 0x0080, 0x5945: 0x0080,
0x5946: 0x0080, 0x5947: 0x0080, 0x5948: 0x0080, 0x5949: 0x0080, 0x594a: 0x0080, 0x594b: 0x0080,
0x594c: 0x0080, 0x594d: 0x0080, 0x594e: 0x0080, 0x594f: 0x0080, 0x5950: 0x0080, 0x5951: 0x0080,
0x5952: 0x0080, 0x5953: 0x0080,
0x5960: 0x0080, 0x5961: 0x0080, 0x5962: 0x0080, 0x5963: 0x0080,
0x5964: 0x0080, 0x5965: 0x0080, 0x5966: 0x0080, 0x5967: 0x0080, 0x5968: 0x0080, 0x5969: 0x0080,
0x596a: 0x0080, 0x596b: 0x0080, 0x596c: 0x0080, 0x596d: 0x0080,
0x5970: 0x0080, 0x5971: 0x0080, 0x5972: 0x0080, 0x5973: 0x0080, 0x5974: 0x0080, 0x5975: 0x0080,
0x5976: 0x0080, 0x5977: 0x0080, 0x5978: 0x0080, 0x5979: 0x0080, 0x597a: 0x0080, 0x597b: 0x0080,
0x597c: 0x0080,
// Block 0x166, offset 0x5980
0x5980: 0x0080, 0x5981: 0x0080, 0x5982: 0x0080, 0x5983: 0x0080, 0x5984: 0x0080, 0x5985: 0x0080,
0x5986: 0x0080, 0x5987: 0x0080, 0x5988: 0x0080,
0x5990: 0x0080, 0x5991: 0x0080,
0x5992: 0x0080, 0x5993: 0x0080, 0x5994: 0x0080, 0x5995: 0x0080, 0x5996: 0x0080, 0x5997: 0x0080,
0x5998: 0x0080, 0x5999: 0x0080, 0x599a: 0x0080, 0x599b: 0x0080, 0x599c: 0x0080, 0x599d: 0x0080,
0x599e: 0x0080, 0x599f: 0x0080, 0x59a0: 0x0080, 0x59a1: 0x0080, 0x59a2: 0x0080, 0x59a3: 0x0080,
0x59a4: 0x0080, 0x59a5: 0x0080, 0x59a6: 0x0080, 0x59a7: 0x0080, 0x59a8: 0x0080, 0x59a9: 0x0080,
0x59aa: 0x0080, 0x59ab: 0x0080, 0x59ac: 0x0080, 0x59ad: 0x0080, 0x59ae: 0x0080, 0x59af: 0x0080,
0x59b0: 0x0080, 0x59b1: 0x0080, 0x59b2: 0x0080, 0x59b3: 0x0080, 0x59b4: 0x0080, 0x59b5: 0x0080,
0x59b6: 0x0080, 0x59b7: 0x0080, 0x59b8: 0x0080, 0x59b9: 0x0080, 0x59ba: 0x0080, 0x59bb: 0x0080,
0x59bc: 0x0080, 0x59bd: 0x0080, 0x59bf: 0x0080,
// Block 0x167, offset 0x59c0
0x59c0: 0x0080, 0x59c1: 0x0080, 0x59c2: 0x0080, 0x59c3: 0x0080, 0x59c4: 0x0080, 0x59c5: 0x0080,
0x59ce: 0x0080, 0x59cf: 0x0080, 0x59d0: 0x0080, 0x59d1: 0x0080,
0x59d2: 0x0080, 0x59d3: 0x0080, 0x59d4: 0x0080, 0x59d5: 0x0080, 0x59d6: 0x0080, 0x59d7: 0x0080,
0x59d8: 0x0080, 0x59d9: 0x0080, 0x59da: 0x0080, 0x59db: 0x0080,
0x59e0: 0x0080, 0x59e1: 0x0080, 0x59e2: 0x0080, 0x59e3: 0x0080,
0x59e4: 0x0080, 0x59e5: 0x0080, 0x59e6: 0x0080, 0x59e7: 0x0080, 0x59e8: 0x0080,
0x59f0: 0x0080, 0x59f1: 0x0080, 0x59f2: 0x0080, 0x59f3: 0x0080, 0x59f4: 0x0080, 0x59f5: 0x0080,
0x59f6: 0x0080, 0x59f7: 0x0080, 0x59f8: 0x0080,
// Block 0x168, offset 0x5a00
0x5a00: 0x0080, 0x5a01: 0x0080, 0x5a02: 0x0080, 0x5a03: 0x0080, 0x5a04: 0x0080, 0x5a05: 0x0080,
0x5a06: 0x0080, 0x5a07: 0x0080, 0x5a08: 0x0080, 0x5a09: 0x0080, 0x5a0a: 0x0080, 0x5a0b: 0x0080,
0x5a0c: 0x0080, 0x5a0d: 0x0080, 0x5a0e: 0x0080, 0x5a0f: 0x0080, 0x5a10: 0x0080, 0x5a11: 0x0080,
0x5a12: 0x0080, 0x5a14: 0x0080, 0x5a15: 0x0080, 0x5a16: 0x0080, 0x5a17: 0x0080,
0x5a18: 0x0080, 0x5a19: 0x0080, 0x5a1a: 0x0080, 0x5a1b: 0x0080, 0x5a1c: 0x0080, 0x5a1d: 0x0080,
0x5a1e: 0x0080, 0x5a1f: 0x0080, 0x5a20: 0x0080, 0x5a21: 0x0080, 0x5a22: 0x0080, 0x5a23: 0x0080,
0x5a24: 0x0080, 0x5a25: 0x0080, 0x5a26: 0x0080, 0x5a27: 0x0080, 0x5a28: 0x0080, 0x5a29: 0x0080,
0x5a2a: 0x0080, 0x5a2b: 0x0080, 0x5a2c: 0x0080, 0x5a2d: 0x0080, 0x5a2e: 0x0080, 0x5a2f: 0x0080,
0x5a30: 0x0080, 0x5a31: 0x0080, 0x5a32: 0x0080, 0x5a33: 0x0080, 0x5a34: 0x0080, 0x5a35: 0x0080,
0x5a36: 0x0080, 0x5a37: 0x0080, 0x5a38: 0x0080, 0x5a39: 0x0080, 0x5a3a: 0x0080, 0x5a3b: 0x0080,
0x5a3c: 0x0080, 0x5a3d: 0x0080, 0x5a3e: 0x0080, 0x5a3f: 0x0080,
// Block 0x169, offset 0x5a40
0x5a40: 0x0080, 0x5a41: 0x0080, 0x5a42: 0x0080, 0x5a43: 0x0080, 0x5a44: 0x0080, 0x5a45: 0x0080,
0x5a46: 0x0080, 0x5a47: 0x0080, 0x5a48: 0x0080, 0x5a49: 0x0080, 0x5a4a: 0x0080,
0x5a70: 0x0080, 0x5a71: 0x0080, 0x5a72: 0x0080, 0x5a73: 0x0080, 0x5a74: 0x0080, 0x5a75: 0x0080,
0x5a76: 0x0080, 0x5a77: 0x0080, 0x5a78: 0x0080, 0x5a79: 0x0080,
// Block 0x16a, offset 0x5a80
0x5a80: 0x00cc, 0x5a81: 0x00cc, 0x5a82: 0x00cc, 0x5a83: 0x00cc, 0x5a84: 0x00cc, 0x5a85: 0x00cc,
0x5a86: 0x00cc, 0x5a87: 0x00cc, 0x5a88: 0x00cc, 0x5a89: 0x00cc, 0x5a8a: 0x00cc, 0x5a8b: 0x00cc,
0x5a8c: 0x00cc, 0x5a8d: 0x00cc, 0x5a8e: 0x00cc, 0x5a8f: 0x00cc, 0x5a90: 0x00cc, 0x5a91: 0x00cc,
0x5a92: 0x00cc, 0x5a93: 0x00cc, 0x5a94: 0x00cc, 0x5a95: 0x00cc, 0x5a96: 0x00cc, 0x5a97: 0x00cc,
0x5a98: 0x00cc, 0x5a99: 0x00cc, 0x5a9a: 0x00cc, 0x5a9b: 0x00cc, 0x5a9c: 0x00cc, 0x5a9d: 0x00cc,
0x5a9e: 0x00cc, 0x5a9f: 0x00cc,
// Block 0x16b, offset 0x5ac0
0x5ac0: 0x00cc, 0x5ac1: 0x00cc, 0x5ac2: 0x00cc, 0x5ac3: 0x00cc, 0x5ac4: 0x00cc, 0x5ac5: 0x00cc,
0x5ac6: 0x00cc, 0x5ac7: 0x00cc, 0x5ac8: 0x00cc, 0x5ac9: 0x00cc, 0x5aca: 0x00cc, 0x5acb: 0x00cc,
0x5acc: 0x00cc, 0x5acd: 0x00cc, 0x5ace: 0x00cc, 0x5acf: 0x00cc, 0x5ad0: 0x00cc, 0x5ad1: 0x00cc,
0x5ad2: 0x00cc, 0x5ad3: 0x00cc, 0x5ad4: 0x00cc, 0x5ad5: 0x00cc, 0x5ad6: 0x00cc, 0x5ad7: 0x00cc,
0x5ad8: 0x00cc, 0x5ad9: 0x00cc, 0x5ada: 0x00cc, 0x5adb: 0x00cc, 0x5adc: 0x00cc, 0x5add: 0x00cc,
0x5ade: 0x00cc, 0x5adf: 0x00cc, 0x5ae0: 0x00cc, 0x5ae1: 0x00cc, 0x5ae2: 0x00cc, 0x5ae3: 0x00cc,
0x5ae4: 0x00cc, 0x5ae5: 0x00cc, 0x5ae6: 0x00cc, 0x5ae7: 0x00cc, 0x5ae8: 0x00cc, 0x5ae9: 0x00cc,
0x5aea: 0x00cc, 0x5aeb: 0x00cc, 0x5aec: 0x00cc, 0x5aed: 0x00cc, 0x5aee: 0x00cc, 0x5aef: 0x00cc,
0x5af0: 0x00cc, 0x5af1: 0x00cc, 0x5af2: 0x00cc, 0x5af3: 0x00cc, 0x5af4: 0x00cc, 0x5af5: 0x00cc,
0x5af6: 0x00cc, 0x5af7: 0x00cc, 0x5af8: 0x00cc, 0x5af9: 0x00cc,
// Block 0x16c, offset 0x5b00
0x5b00: 0x00cc, 0x5b01: 0x00cc, 0x5b02: 0x00cc, 0x5b03: 0x00cc, 0x5b04: 0x00cc, 0x5b05: 0x00cc,
0x5b06: 0x00cc, 0x5b07: 0x00cc, 0x5b08: 0x00cc, 0x5b09: 0x00cc, 0x5b0a: 0x00cc, 0x5b0b: 0x00cc,
0x5b0c: 0x00cc, 0x5b0d: 0x00cc, 0x5b0e: 0x00cc, 0x5b0f: 0x00cc, 0x5b10: 0x00cc, 0x5b11: 0x00cc,
0x5b12: 0x00cc, 0x5b13: 0x00cc, 0x5b14: 0x00cc, 0x5b15: 0x00cc, 0x5b16: 0x00cc, 0x5b17: 0x00cc,
0x5b18: 0x00cc, 0x5b19: 0x00cc, 0x5b1a: 0x00cc, 0x5b1b: 0x00cc, 0x5b1c: 0x00cc, 0x5b1d: 0x00cc,
0x5b20: 0x00cc, 0x5b21: 0x00cc, 0x5b22: 0x00cc, 0x5b23: 0x00cc,
0x5b24: 0x00cc, 0x5b25: 0x00cc, 0x5b26: 0x00cc, 0x5b27: 0x00cc, 0x5b28: 0x00cc, 0x5b29: 0x00cc,
0x5b2a: 0x00cc, 0x5b2b: 0x00cc, 0x5b2c: 0x00cc, 0x5b2d: 0x00cc, 0x5b2e: 0x00cc, 0x5b2f: 0x00cc,
0x5b30: 0x00cc, 0x5b31: 0x00cc, 0x5b32: 0x00cc, 0x5b33: 0x00cc, 0x5b34: 0x00cc, 0x5b35: 0x00cc,
0x5b36: 0x00cc, 0x5b37: 0x00cc, 0x5b38: 0x00cc, 0x5b39: 0x00cc, 0x5b3a: 0x00cc, 0x5b3b: 0x00cc,
0x5b3c: 0x00cc, 0x5b3d: 0x00cc, 0x5b3e: 0x00cc, 0x5b3f: 0x00cc,
// Block 0x16d, offset 0x5b40
0x5b40: 0x00cc, 0x5b41: 0x00cc, 0x5b42: 0x00cc, 0x5b43: 0x00cc, 0x5b44: 0x00cc, 0x5b45: 0x00cc,
0x5b46: 0x00cc, 0x5b47: 0x00cc, 0x5b48: 0x00cc, 0x5b49: 0x00cc, 0x5b4a: 0x00cc, 0x5b4b: 0x00cc,
0x5b4c: 0x00cc, 0x5b4d: 0x00cc, 0x5b4e: 0x00cc, 0x5b4f: 0x00cc, 0x5b50: 0x00cc, 0x5b51: 0x00cc,
0x5b52: 0x00cc, 0x5b53: 0x00cc, 0x5b54: 0x00cc, 0x5b55: 0x00cc, 0x5b56: 0x00cc, 0x5b57: 0x00cc,
0x5b58: 0x00cc, 0x5b59: 0x00cc, 0x5b5a: 0x00cc, 0x5b5b: 0x00cc, 0x5b5c: 0x00cc, 0x5b5d: 0x00cc,
0x5b5e: 0x00cc, 0x5b5f: 0x00cc, 0x5b60: 0x00cc, 0x5b61: 0x00cc,
0x5b70: 0x00cc, 0x5b71: 0x00cc, 0x5b72: 0x00cc, 0x5b73: 0x00cc, 0x5b74: 0x00cc, 0x5b75: 0x00cc,
0x5b76: 0x00cc, 0x5b77: 0x00cc, 0x5b78: 0x00cc, 0x5b79: 0x00cc, 0x5b7a: 0x00cc, 0x5b7b: 0x00cc,
0x5b7c: 0x00cc, 0x5b7d: 0x00cc, 0x5b7e: 0x00cc, 0x5b7f: 0x00cc,
// Block 0x16e, offset 0x5b80
0x5b80: 0x00cc, 0x5b81: 0x00cc, 0x5b82: 0x00cc, 0x5b83: 0x00cc, 0x5b84: 0x00cc, 0x5b85: 0x00cc,
0x5b86: 0x00cc, 0x5b87: 0x00cc, 0x5b88: 0x00cc, 0x5b89: 0x00cc, 0x5b8a: 0x00cc, 0x5b8b: 0x00cc,
0x5b8c: 0x00cc, 0x5b8d: 0x00cc, 0x5b8e: 0x00cc, 0x5b8f: 0x00cc, 0x5b90: 0x00cc, 0x5b91: 0x00cc,
0x5b92: 0x00cc, 0x5b93: 0x00cc, 0x5b94: 0x00cc, 0x5b95: 0x00cc, 0x5b96: 0x00cc, 0x5b97: 0x00cc,
0x5b98: 0x00cc, 0x5b99: 0x00cc, 0x5b9a: 0x00cc, 0x5b9b: 0x00cc, 0x5b9c: 0x00cc, 0x5b9d: 0x00cc,
0x5b9e: 0x00cc, 0x5b9f: 0x00cc, 0x5ba0: 0x00cc,
// Block 0x16f, offset 0x5bc0
0x5bc0: 0x008c, 0x5bc1: 0x008c, 0x5bc2: 0x008c, 0x5bc3: 0x008c, 0x5bc4: 0x008c, 0x5bc5: 0x008c,
0x5bc6: 0x008c, 0x5bc7: 0x008c, 0x5bc8: 0x008c, 0x5bc9: 0x008c, 0x5bca: 0x008c, 0x5bcb: 0x008c,
0x5bcc: 0x008c, 0x5bcd: 0x008c, 0x5bce: 0x008c, 0x5bcf: 0x008c, 0x5bd0: 0x008c, 0x5bd1: 0x008c,
0x5bd2: 0x008c, 0x5bd3: 0x008c, 0x5bd4: 0x008c, 0x5bd5: 0x008c, 0x5bd6: 0x008c, 0x5bd7: 0x008c,
0x5bd8: 0x008c, 0x5bd9: 0x008c, 0x5bda: 0x008c, 0x5bdb: 0x008c, 0x5bdc: 0x008c, 0x5bdd: 0x008c,
// Block 0x170, offset 0x5c00
0x5c00: 0x00cc, 0x5c01: 0x00cc, 0x5c02: 0x00cc, 0x5c03: 0x00cc, 0x5c04: 0x00cc, 0x5c05: 0x00cc,
0x5c06: 0x00cc, 0x5c07: 0x00cc, 0x5c08: 0x00cc, 0x5c09: 0x00cc, 0x5c0a: 0x00cc,
0x5c10: 0x00cc, 0x5c11: 0x00cc,
0x5c12: 0x00cc, 0x5c13: 0x00cc, 0x5c14: 0x00cc, 0x5c15: 0x00cc, 0x5c16: 0x00cc, 0x5c17: 0x00cc,
0x5c18: 0x00cc, 0x5c19: 0x00cc, 0x5c1a: 0x00cc, 0x5c1b: 0x00cc, 0x5c1c: 0x00cc, 0x5c1d: 0x00cc,
0x5c1e: 0x00cc, 0x5c1f: 0x00cc, 0x5c20: 0x00cc, 0x5c21: 0x00cc, 0x5c22: 0x00cc, 0x5c23: 0x00cc,
0x5c24: 0x00cc, 0x5c25: 0x00cc, 0x5c26: 0x00cc, 0x5c27: 0x00cc, 0x5c28: 0x00cc, 0x5c29: 0x00cc,
0x5c2a: 0x00cc, 0x5c2b: 0x00cc, 0x5c2c: 0x00cc, 0x5c2d: 0x00cc, 0x5c2e: 0x00cc, 0x5c2f: 0x00cc,
0x5c30: 0x00cc, 0x5c31: 0x00cc, 0x5c32: 0x00cc, 0x5c33: 0x00cc, 0x5c34: 0x00cc, 0x5c35: 0x00cc,
0x5c36: 0x00cc, 0x5c37: 0x00cc, 0x5c38: 0x00cc, 0x5c39: 0x00cc, 0x5c3a: 0x00cc, 0x5c3b: 0x00cc,
0x5c3c: 0x00cc, 0x5c3d: 0x00cc, 0x5c3e: 0x00cc, 0x5c3f: 0x00cc,
// Block 0x171, offset 0x5c40
0x5c40: 0x00cc, 0x5c41: 0x00cc, 0x5c42: 0x00cc, 0x5c43: 0x00cc, 0x5c44: 0x00cc, 0x5c45: 0x00cc,
0x5c46: 0x00cc, 0x5c47: 0x00cc, 0x5c48: 0x00cc, 0x5c49: 0x00cc, 0x5c4a: 0x00cc, 0x5c4b: 0x00cc,
0x5c4c: 0x00cc, 0x5c4d: 0x00cc, 0x5c4e: 0x00cc, 0x5c4f: 0x00cc, 0x5c50: 0x00cc, 0x5c51: 0x00cc,
0x5c52: 0x00cc, 0x5c53: 0x00cc, 0x5c54: 0x00cc, 0x5c55: 0x00cc, 0x5c56: 0x00cc, 0x5c57: 0x00cc,
0x5c58: 0x00cc, 0x5c59: 0x00cc, 0x5c5a: 0x00cc, 0x5c5b: 0x00cc, 0x5c5c: 0x00cc, 0x5c5d: 0x00cc,
0x5c5e: 0x00cc, 0x5c5f: 0x00cc, 0x5c60: 0x00cc, 0x5c61: 0x00cc, 0x5c62: 0x00cc, 0x5c63: 0x00cc,
0x5c64: 0x00cc, 0x5c65: 0x00cc, 0x5c66: 0x00cc, 0x5c67: 0x00cc, 0x5c68: 0x00cc, 0x5c69: 0x00cc,
0x5c6a: 0x00cc, 0x5c6b: 0x00cc, 0x5c6c: 0x00cc, 0x5c6d: 0x00cc, 0x5c6e: 0x00cc, 0x5c6f: 0x00cc,
// Block 0x172, offset 0x5c80
0x5c81: 0x0040,
0x5ca0: 0x0040, 0x5ca1: 0x0040, 0x5ca2: 0x0040, 0x5ca3: 0x0040,
0x5ca4: 0x0040, 0x5ca5: 0x0040, 0x5ca6: 0x0040, 0x5ca7: 0x0040, 0x5ca8: 0x0040, 0x5ca9: 0x0040,
0x5caa: 0x0040, 0x5cab: 0x0040, 0x5cac: 0x0040, 0x5cad: 0x0040, 0x5cae: 0x0040, 0x5caf: 0x0040,
0x5cb0: 0x0040, 0x5cb1: 0x0040, 0x5cb2: 0x0040, 0x5cb3: 0x0040, 0x5cb4: 0x0040, 0x5cb5: 0x0040,
0x5cb6: 0x0040, 0x5cb7: 0x0040, 0x5cb8: 0x0040, 0x5cb9: 0x0040, 0x5cba: 0x0040, 0x5cbb: 0x0040,
0x5cbc: 0x0040, 0x5cbd: 0x0040, 0x5cbe: 0x0040, 0x5cbf: 0x0040,
// Block 0x173, offset 0x5cc0
0x5cc0: 0x0040, 0x5cc1: 0x0040, 0x5cc2: 0x0040, 0x5cc3: 0x0040, 0x5cc4: 0x0040, 0x5cc5: 0x0040,
0x5cc6: 0x0040, 0x5cc7: 0x0040, 0x5cc8: 0x0040, 0x5cc9: 0x0040, 0x5cca: 0x0040, 0x5ccb: 0x0040,
0x5ccc: 0x0040, 0x5ccd: 0x0040, 0x5cce: 0x0040, 0x5ccf: 0x0040, 0x5cd0: 0x0040, 0x5cd1: 0x0040,
0x5cd2: 0x0040, 0x5cd3: 0x0040, 0x5cd4: 0x0040, 0x5cd5: 0x0040, 0x5cd6: 0x0040, 0x5cd7: 0x0040,
0x5cd8: 0x0040, 0x5cd9: 0x0040, 0x5cda: 0x0040, 0x5cdb: 0x0040, 0x5cdc: 0x0040, 0x5cdd: 0x0040,
0x5cde: 0x0040, 0x5cdf: 0x0040, 0x5ce0: 0x0040, 0x5ce1: 0x0040, 0x5ce2: 0x0040, 0x5ce3: 0x0040,
0x5ce4: 0x0040, 0x5ce5: 0x0040, 0x5ce6: 0x0040, 0x5ce7: 0x0040, 0x5ce8: 0x0040, 0x5ce9: 0x0040,
0x5cea: 0x0040, 0x5ceb: 0x0040, 0x5cec: 0x0040, 0x5ced: 0x0040, 0x5cee: 0x0040, 0x5cef: 0x0040,
// Block 0x174, offset 0x5d00
0x5d00: 0x0040, 0x5d01: 0x0040, 0x5d02: 0x0040, 0x5d03: 0x0040, 0x5d04: 0x0040, 0x5d05: 0x0040,
0x5d06: 0x0040, 0x5d07: 0x0040, 0x5d08: 0x0040, 0x5d09: 0x0040, 0x5d0a: 0x0040, 0x5d0b: 0x0040,
0x5d0c: 0x0040, 0x5d0d: 0x0040, 0x5d0e: 0x0040, 0x5d0f: 0x0040, 0x5d10: 0x0040, 0x5d11: 0x0040,
0x5d12: 0x0040, 0x5d13: 0x0040, 0x5d14: 0x0040, 0x5d15: 0x0040, 0x5d16: 0x0040, 0x5d17: 0x0040,
0x5d18: 0x0040, 0x5d19: 0x0040, 0x5d1a: 0x0040, 0x5d1b: 0x0040, 0x5d1c: 0x0040, 0x5d1d: 0x0040,
0x5d1e: 0x0040, 0x5d1f: 0x0040, 0x5d20: 0x0040, 0x5d21: 0x0040, 0x5d22: 0x0040, 0x5d23: 0x0040,
0x5d24: 0x0040, 0x5d25: 0x0040, 0x5d26: 0x0040, 0x5d27: 0x0040, 0x5d28: 0x0040, 0x5d29: 0x0040,
0x5d2a: 0x0040, 0x5d2b: 0x0040, 0x5d2c: 0x0040, 0x5d2d: 0x0040, 0x5d2e: 0x0040, 0x5d2f: 0x0040,
0x5d30: 0x0040, 0x5d31: 0x0040, 0x5d32: 0x0040, 0x5d33: 0x0040, 0x5d34: 0x0040, 0x5d35: 0x0040,
0x5d36: 0x0040, 0x5d37: 0x0040, 0x5d38: 0x0040, 0x5d39: 0x0040, 0x5d3a: 0x0040, 0x5d3b: 0x0040,
0x5d3c: 0x0040, 0x5d3d: 0x0040,
}
// derivedPropertiesIndex: 40 blocks, 2560 entries, 5120 bytes
// Block 0 is the zero block.
var derivedPropertiesIndex = [2560]uint16{
// Block 0x0, offset 0x0
// Block 0x1, offset 0x40
// Block 0x2, offset 0x80
// Block 0x3, offset 0xc0
0xc2: 0x01, 0xc3: 0x02, 0xc4: 0x03, 0xc5: 0x04, 0xc6: 0x05, 0xc7: 0x06,
0xc8: 0x05, 0xc9: 0x05, 0xca: 0x07, 0xcb: 0x08, 0xcc: 0x09, 0xcd: 0x0a, 0xce: 0x0b, 0xcf: 0x0c,
0xd0: 0x05, 0xd1: 0x05, 0xd2: 0x0d, 0xd3: 0x05, 0xd4: 0x0e, 0xd5: 0x0f, 0xd6: 0x10, 0xd7: 0x11,
0xd8: 0x12, 0xd9: 0x13, 0xda: 0x14, 0xdb: 0x15, 0xdc: 0x16, 0xdd: 0x17, 0xde: 0x18, 0xdf: 0x19,
0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, 0xe4: 0x06, 0xe5: 0x07, 0xe6: 0x07, 0xe7: 0x07,
0xe8: 0x07, 0xe9: 0x07, 0xea: 0x08, 0xeb: 0x09, 0xec: 0x09, 0xed: 0x0a, 0xee: 0x0b, 0xef: 0x0c,
0xf0: 0x21, 0xf3: 0x24, 0xf4: 0x25,
// Block 0x4, offset 0x100
0x120: 0x1a, 0x121: 0x1b, 0x122: 0x1c, 0x123: 0x1d, 0x124: 0x1e, 0x125: 0x1f, 0x126: 0x20, 0x127: 0x21,
0x128: 0x22, 0x129: 0x23, 0x12a: 0x24, 0x12b: 0x25, 0x12c: 0x26, 0x12d: 0x27, 0x12e: 0x28, 0x12f: 0x29,
0x130: 0x2a, 0x131: 0x2b, 0x132: 0x2c, 0x133: 0x2d, 0x134: 0x2e, 0x135: 0x2f, 0x136: 0x30, 0x137: 0x31,
0x138: 0x32, 0x139: 0x33, 0x13a: 0x34, 0x13b: 0x35, 0x13c: 0x36, 0x13d: 0x37, 0x13e: 0x38, 0x13f: 0x39,
// Block 0x5, offset 0x140
0x140: 0x3a, 0x141: 0x3b, 0x142: 0x3c, 0x143: 0x3d, 0x144: 0x3e, 0x145: 0x3e, 0x146: 0x3e, 0x147: 0x3e,
0x148: 0x05, 0x149: 0x3f, 0x14a: 0x40, 0x14b: 0x41, 0x14c: 0x42, 0x14d: 0x43, 0x14e: 0x44, 0x14f: 0x45,
0x150: 0x46, 0x151: 0x05, 0x152: 0x05, 0x153: 0x05, 0x154: 0x05, 0x155: 0x05, 0x156: 0x05, 0x157: 0x05,
0x158: 0x05, 0x159: 0x47, 0x15a: 0x48, 0x15b: 0x49, 0x15c: 0x4a, 0x15d: 0x4b, 0x15e: 0x4c, 0x15f: 0x4d,
0x160: 0x4e, 0x161: 0x4f, 0x162: 0x50, 0x163: 0x51, 0x164: 0x52, 0x165: 0x53, 0x166: 0x54, 0x167: 0x55,
0x168: 0x56, 0x169: 0x57, 0x16a: 0x58, 0x16b: 0x59, 0x16c: 0x5a, 0x16d: 0x5b, 0x16e: 0x5c, 0x16f: 0x5d,
0x170: 0x5e, 0x171: 0x5f, 0x172: 0x60, 0x173: 0x61, 0x174: 0x62, 0x175: 0x63, 0x176: 0x64, 0x177: 0x09,
0x178: 0x05, 0x179: 0x05, 0x17a: 0x65, 0x17b: 0x05, 0x17c: 0x66, 0x17d: 0x67, 0x17e: 0x68, 0x17f: 0x69,
// Block 0x6, offset 0x180
0x180: 0x6a, 0x181: 0x6b, 0x182: 0x6c, 0x183: 0x6d, 0x184: 0x6e, 0x185: 0x6f, 0x186: 0x70, 0x187: 0x71,
0x188: 0x71, 0x189: 0x71, 0x18a: 0x71, 0x18b: 0x71, 0x18c: 0x71, 0x18d: 0x71, 0x18e: 0x71, 0x18f: 0x71,
0x190: 0x72, 0x191: 0x73, 0x192: 0x71, 0x193: 0x71, 0x194: 0x71, 0x195: 0x71, 0x196: 0x71, 0x197: 0x71,
0x198: 0x71, 0x199: 0x71, 0x19a: 0x71, 0x19b: 0x71, 0x19c: 0x71, 0x19d: 0x71, 0x19e: 0x71, 0x19f: 0x71,
0x1a0: 0x71, 0x1a1: 0x71, 0x1a2: 0x71, 0x1a3: 0x71, 0x1a4: 0x71, 0x1a5: 0x71, 0x1a6: 0x71, 0x1a7: 0x71,
0x1a8: 0x71, 0x1a9: 0x71, 0x1aa: 0x71, 0x1ab: 0x71, 0x1ac: 0x71, 0x1ad: 0x74, 0x1ae: 0x75, 0x1af: 0x71,
0x1b0: 0x05, 0x1b1: 0x76, 0x1b2: 0x05, 0x1b3: 0x77, 0x1b4: 0x78, 0x1b5: 0x79, 0x1b6: 0x7a, 0x1b7: 0x7b,
0x1b8: 0x7c, 0x1b9: 0x7d, 0x1ba: 0x7e, 0x1bb: 0x7f, 0x1bc: 0x80, 0x1bd: 0x80, 0x1be: 0x80, 0x1bf: 0x81,
// Block 0x7, offset 0x1c0
0x1c0: 0x82, 0x1c1: 0x83, 0x1c2: 0x84, 0x1c3: 0x85, 0x1c4: 0x86, 0x1c5: 0x87, 0x1c6: 0x88, 0x1c7: 0x89,
0x1c8: 0x8a, 0x1c9: 0x71, 0x1ca: 0x71, 0x1cb: 0x8b, 0x1cc: 0x80, 0x1cd: 0x8c, 0x1ce: 0x71, 0x1cf: 0x71,
0x1d0: 0x8d, 0x1d1: 0x8d, 0x1d2: 0x8d, 0x1d3: 0x8d, 0x1d4: 0x8d, 0x1d5: 0x8d, 0x1d6: 0x8d, 0x1d7: 0x8d,
0x1d8: 0x8d, 0x1d9: 0x8d, 0x1da: 0x8d, 0x1db: 0x8d, 0x1dc: 0x8d, 0x1dd: 0x8d, 0x1de: 0x8d, 0x1df: 0x8d,
0x1e0: 0x8d, 0x1e1: 0x8d, 0x1e2: 0x8d, 0x1e3: 0x8d, 0x1e4: 0x8d, 0x1e5: 0x8d, 0x1e6: 0x8d, 0x1e7: 0x8d,
0x1e8: 0x8d, 0x1e9: 0x8d, 0x1ea: 0x8d, 0x1eb: 0x8d, 0x1ec: 0x8d, 0x1ed: 0x8d, 0x1ee: 0x8d, 0x1ef: 0x8d,
0x1f0: 0x8d, 0x1f1: 0x8d, 0x1f2: 0x8d, 0x1f3: 0x8d, 0x1f4: 0x8d, 0x1f5: 0x8d, 0x1f6: 0x8d, 0x1f7: 0x8d,
0x1f8: 0x8d, 0x1f9: 0x8d, 0x1fa: 0x8d, 0x1fb: 0x8d, 0x1fc: 0x8d, 0x1fd: 0x8d, 0x1fe: 0x8d, 0x1ff: 0x8d,
// Block 0x8, offset 0x200
0x200: 0x8d, 0x201: 0x8d, 0x202: 0x8d, 0x203: 0x8d, 0x204: 0x8d, 0x205: 0x8d, 0x206: 0x8d, 0x207: 0x8d,
0x208: 0x8d, 0x209: 0x8d, 0x20a: 0x8d, 0x20b: 0x8d, 0x20c: 0x8d, 0x20d: 0x8d, 0x20e: 0x8d, 0x20f: 0x8d,
0x210: 0x8d, 0x211: 0x8d, 0x212: 0x8d, 0x213: 0x8d, 0x214: 0x8d, 0x215: 0x8d, 0x216: 0x8d, 0x217: 0x8d,
0x218: 0x8d, 0x219: 0x8d, 0x21a: 0x8d, 0x21b: 0x8d, 0x21c: 0x8d, 0x21d: 0x8d, 0x21e: 0x8d, 0x21f: 0x8d,
0x220: 0x8d, 0x221: 0x8d, 0x222: 0x8d, 0x223: 0x8d, 0x224: 0x8d, 0x225: 0x8d, 0x226: 0x8d, 0x227: 0x8d,
0x228: 0x8d, 0x229: 0x8d, 0x22a: 0x8d, 0x22b: 0x8d, 0x22c: 0x8d, 0x22d: 0x8d, 0x22e: 0x8d, 0x22f: 0x8d,
0x230: 0x8d, 0x231: 0x8d, 0x232: 0x8d, 0x233: 0x8d, 0x234: 0x8d, 0x235: 0x8d, 0x236: 0x8d, 0x237: 0x71,
0x238: 0x8d, 0x239: 0x8d, 0x23a: 0x8d, 0x23b: 0x8d, 0x23c: 0x8d, 0x23d: 0x8d, 0x23e: 0x8d, 0x23f: 0x8d,
// Block 0x9, offset 0x240
0x240: 0x8d, 0x241: 0x8d, 0x242: 0x8d, 0x243: 0x8d, 0x244: 0x8d, 0x245: 0x8d, 0x246: 0x8d, 0x247: 0x8d,
0x248: 0x8d, 0x249: 0x8d, 0x24a: 0x8d, 0x24b: 0x8d, 0x24c: 0x8d, 0x24d: 0x8d, 0x24e: 0x8d, 0x24f: 0x8d,
0x250: 0x8d, 0x251: 0x8d, 0x252: 0x8d, 0x253: 0x8d, 0x254: 0x8d, 0x255: 0x8d, 0x256: 0x8d, 0x257: 0x8d,
0x258: 0x8d, 0x259: 0x8d, 0x25a: 0x8d, 0x25b: 0x8d, 0x25c: 0x8d, 0x25d: 0x8d, 0x25e: 0x8d, 0x25f: 0x8d,
0x260: 0x8d, 0x261: 0x8d, 0x262: 0x8d, 0x263: 0x8d, 0x264: 0x8d, 0x265: 0x8d, 0x266: 0x8d, 0x267: 0x8d,
0x268: 0x8d, 0x269: 0x8d, 0x26a: 0x8d, 0x26b: 0x8d, 0x26c: 0x8d, 0x26d: 0x8d, 0x26e: 0x8d, 0x26f: 0x8d,
0x270: 0x8d, 0x271: 0x8d, 0x272: 0x8d, 0x273: 0x8d, 0x274: 0x8d, 0x275: 0x8d, 0x276: 0x8d, 0x277: 0x8d,
0x278: 0x8d, 0x279: 0x8d, 0x27a: 0x8d, 0x27b: 0x8d, 0x27c: 0x8d, 0x27d: 0x8d, 0x27e: 0x8d, 0x27f: 0x8d,
// Block 0xa, offset 0x280
0x280: 0x05, 0x281: 0x05, 0x282: 0x05, 0x283: 0x05, 0x284: 0x05, 0x285: 0x05, 0x286: 0x05, 0x287: 0x05,
0x288: 0x05, 0x289: 0x05, 0x28a: 0x05, 0x28b: 0x05, 0x28c: 0x05, 0x28d: 0x05, 0x28e: 0x05, 0x28f: 0x05,
0x290: 0x05, 0x291: 0x05, 0x292: 0x8e, 0x293: 0x8f, 0x294: 0x05, 0x295: 0x05, 0x296: 0x05, 0x297: 0x05,
0x298: 0x90, 0x299: 0x91, 0x29a: 0x92, 0x29b: 0x93, 0x29c: 0x94, 0x29d: 0x95, 0x29e: 0x96, 0x29f: 0x97,
0x2a0: 0x98, 0x2a1: 0x99, 0x2a2: 0x05, 0x2a3: 0x9a, 0x2a4: 0x9b, 0x2a5: 0x9c, 0x2a6: 0x9d, 0x2a7: 0x9e,
0x2a8: 0x9f, 0x2a9: 0xa0, 0x2aa: 0xa1, 0x2ab: 0xa2, 0x2ac: 0xa3, 0x2ad: 0xa4, 0x2ae: 0x05, 0x2af: 0xa5,
0x2b0: 0x05, 0x2b1: 0x05, 0x2b2: 0x05, 0x2b3: 0x05, 0x2b4: 0x05, 0x2b5: 0x05, 0x2b6: 0x05, 0x2b7: 0x05,
0x2b8: 0x05, 0x2b9: 0x05, 0x2ba: 0x05, 0x2bb: 0x05, 0x2bc: 0x05, 0x2bd: 0x05, 0x2be: 0x05, 0x2bf: 0x05,
// Block 0xb, offset 0x2c0
0x2c0: 0x05, 0x2c1: 0x05, 0x2c2: 0x05, 0x2c3: 0x05, 0x2c4: 0x05, 0x2c5: 0x05, 0x2c6: 0x05, 0x2c7: 0x05,
0x2c8: 0x05, 0x2c9: 0x05, 0x2ca: 0x05, 0x2cb: 0x05, 0x2cc: 0x05, 0x2cd: 0x05, 0x2ce: 0x05, 0x2cf: 0x05,
0x2d0: 0x05, 0x2d1: 0x05, 0x2d2: 0x05, 0x2d3: 0x05, 0x2d4: 0x05, 0x2d5: 0x05, 0x2d6: 0x05, 0x2d7: 0x05,
0x2d8: 0x05, 0x2d9: 0x05, 0x2da: 0x05, 0x2db: 0x05, 0x2dc: 0x05, 0x2dd: 0x05, 0x2de: 0x05, 0x2df: 0x05,
0x2e0: 0x05, 0x2e1: 0x05, 0x2e2: 0x05, 0x2e3: 0x05, 0x2e4: 0x05, 0x2e5: 0x05, 0x2e6: 0x05, 0x2e7: 0x05,
0x2e8: 0x05, 0x2e9: 0x05, 0x2ea: 0x05, 0x2eb: 0x05, 0x2ec: 0x05, 0x2ed: 0x05, 0x2ee: 0x05, 0x2ef: 0x05,
0x2f0: 0x05, 0x2f1: 0x05, 0x2f2: 0x05, 0x2f3: 0x05, 0x2f4: 0x05, 0x2f5: 0x05, 0x2f6: 0x05, 0x2f7: 0x05,
0x2f8: 0x05, 0x2f9: 0x05, 0x2fa: 0x05, 0x2fb: 0x05, 0x2fc: 0x05, 0x2fd: 0x05, 0x2fe: 0x05, 0x2ff: 0x05,
// Block 0xc, offset 0x300
0x300: 0x05, 0x301: 0x05, 0x302: 0x05, 0x303: 0x05, 0x304: 0x05, 0x305: 0x05, 0x306: 0x05, 0x307: 0x05,
0x308: 0x05, 0x309: 0x05, 0x30a: 0x05, 0x30b: 0x05, 0x30c: 0x05, 0x30d: 0x05, 0x30e: 0x05, 0x30f: 0x05,
0x310: 0x05, 0x311: 0x05, 0x312: 0x05, 0x313: 0x05, 0x314: 0x05, 0x315: 0x05, 0x316: 0x05, 0x317: 0x05,
0x318: 0x05, 0x319: 0x05, 0x31a: 0x05, 0x31b: 0x05, 0x31c: 0x05, 0x31d: 0x05, 0x31e: 0xa6, 0x31f: 0xa7,
// Block 0xd, offset 0x340
0x340: 0x3e, 0x341: 0x3e, 0x342: 0x3e, 0x343: 0x3e, 0x344: 0x3e, 0x345: 0x3e, 0x346: 0x3e, 0x347: 0x3e,
0x348: 0x3e, 0x349: 0x3e, 0x34a: 0x3e, 0x34b: 0x3e, 0x34c: 0x3e, 0x34d: 0x3e, 0x34e: 0x3e, 0x34f: 0x3e,
0x350: 0x3e, 0x351: 0x3e, 0x352: 0x3e, 0x353: 0x3e, 0x354: 0x3e, 0x355: 0x3e, 0x356: 0x3e, 0x357: 0x3e,
0x358: 0x3e, 0x359: 0x3e, 0x35a: 0x3e, 0x35b: 0x3e, 0x35c: 0x3e, 0x35d: 0x3e, 0x35e: 0x3e, 0x35f: 0x3e,
0x360: 0x3e, 0x361: 0x3e, 0x362: 0x3e, 0x363: 0x3e, 0x364: 0x3e, 0x365: 0x3e, 0x366: 0x3e, 0x367: 0x3e,
0x368: 0x3e, 0x369: 0x3e, 0x36a: 0x3e, 0x36b: 0x3e, 0x36c: 0x3e, 0x36d: 0x3e, 0x36e: 0x3e, 0x36f: 0x3e,
0x370: 0x3e, 0x371: 0x3e, 0x372: 0x3e, 0x373: 0x3e, 0x374: 0x3e, 0x375: 0x3e, 0x376: 0x3e, 0x377: 0x3e,
0x378: 0x3e, 0x379: 0x3e, 0x37a: 0x3e, 0x37b: 0x3e, 0x37c: 0x3e, 0x37d: 0x3e, 0x37e: 0x3e, 0x37f: 0x3e,
// Block 0xe, offset 0x380
0x380: 0x3e, 0x381: 0x3e, 0x382: 0x3e, 0x383: 0x3e, 0x384: 0x3e, 0x385: 0x3e, 0x386: 0x3e, 0x387: 0x3e,
0x388: 0x3e, 0x389: 0x3e, 0x38a: 0x3e, 0x38b: 0x3e, 0x38c: 0x3e, 0x38d: 0x3e, 0x38e: 0x3e, 0x38f: 0x3e,
0x390: 0x3e, 0x391: 0x3e, 0x392: 0x3e, 0x393: 0x3e, 0x394: 0x3e, 0x395: 0x3e, 0x396: 0x3e, 0x397: 0x3e,
0x398: 0x3e, 0x399: 0x3e, 0x39a: 0x3e, 0x39b: 0x3e, 0x39c: 0x3e, 0x39d: 0x3e, 0x39e: 0x3e, 0x39f: 0x3e,
0x3a0: 0x3e, 0x3a1: 0x3e, 0x3a2: 0x3e, 0x3a3: 0x3e, 0x3a4: 0x80, 0x3a5: 0x80, 0x3a6: 0x80, 0x3a7: 0x80,
0x3a8: 0xa8, 0x3a9: 0xa9, 0x3aa: 0x80, 0x3ab: 0xaa, 0x3ac: 0xab, 0x3ad: 0xac, 0x3ae: 0x71, 0x3af: 0xad,
0x3b0: 0x71, 0x3b1: 0x71, 0x3b2: 0x71, 0x3b3: 0x71, 0x3b4: 0x71, 0x3b5: 0x71, 0x3b6: 0xae, 0x3b7: 0xaf,
0x3b8: 0xb0, 0x3b9: 0xb1, 0x3ba: 0x71, 0x3bb: 0xb2, 0x3bc: 0xb3, 0x3bd: 0xb4, 0x3be: 0xb5, 0x3bf: 0xb6,
// Block 0xf, offset 0x3c0
0x3c0: 0xb7, 0x3c1: 0xb8, 0x3c2: 0x05, 0x3c3: 0xb9, 0x3c4: 0xba, 0x3c5: 0xbb, 0x3c6: 0xbc, 0x3c7: 0xbd,
0x3ca: 0xbe, 0x3cb: 0xbf, 0x3cc: 0xc0, 0x3cd: 0xc1, 0x3ce: 0xc2, 0x3cf: 0xc3,
0x3d0: 0x05, 0x3d1: 0x05, 0x3d2: 0xc4, 0x3d3: 0xc5, 0x3d4: 0xc6, 0x3d5: 0xc7, 0x3d6: 0xc8,
0x3d8: 0x05, 0x3d9: 0x05, 0x3da: 0x05, 0x3db: 0x05, 0x3dc: 0xc9, 0x3dd: 0xca, 0x3de: 0xcb,
0x3e0: 0xcc, 0x3e1: 0xcd, 0x3e2: 0xce, 0x3e3: 0xcf, 0x3e4: 0xd0, 0x3e6: 0xd1, 0x3e7: 0xae,
0x3e8: 0xd2, 0x3e9: 0xd3, 0x3ea: 0xd4, 0x3eb: 0xd5, 0x3ec: 0xd6, 0x3ed: 0xd7, 0x3ee: 0xd8,
0x3f0: 0x05, 0x3f1: 0xd9, 0x3f2: 0xda, 0x3f3: 0xdb, 0x3f4: 0xdc,
0x3f9: 0xdd, 0x3fa: 0xde, 0x3fb: 0xdf, 0x3fc: 0xe0, 0x3fd: 0xe1, 0x3fe: 0xe2, 0x3ff: 0xe3,
// Block 0x10, offset 0x400
0x400: 0xe4, 0x401: 0xe5, 0x402: 0xe6, 0x403: 0xe7, 0x404: 0xe8, 0x405: 0xe9, 0x406: 0xea, 0x407: 0xeb,
0x408: 0xec, 0x409: 0xed, 0x40a: 0xee, 0x40b: 0xef, 0x40c: 0xf0, 0x40d: 0xf1,
0x410: 0xf2, 0x411: 0xf3, 0x412: 0xf4, 0x413: 0xf5, 0x416: 0xf6, 0x417: 0xf7,
0x418: 0xf8, 0x419: 0xf9, 0x41a: 0xfa, 0x41b: 0xfb, 0x41c: 0xfc, 0x41d: 0xfd,
0x420: 0xfe, 0x422: 0xff, 0x423: 0x100, 0x424: 0x101, 0x425: 0x102, 0x426: 0x103, 0x427: 0x104,
0x428: 0x105, 0x429: 0x106, 0x42a: 0x107, 0x42b: 0x108, 0x42c: 0x109,
0x430: 0x10a, 0x431: 0x10b, 0x432: 0x10c, 0x434: 0x10d, 0x435: 0x10e, 0x436: 0x10f,
0x43b: 0x110, 0x43c: 0x111, 0x43d: 0x112, 0x43e: 0x113, 0x43f: 0x114,
// Block 0x11, offset 0x440
0x440: 0x05, 0x441: 0x05, 0x442: 0x05, 0x443: 0x05, 0x444: 0x05, 0x445: 0x05, 0x446: 0x05, 0x447: 0x05,
0x448: 0x05, 0x449: 0x05, 0x44a: 0x05, 0x44b: 0x05, 0x44c: 0x05, 0x44d: 0x05, 0x44e: 0x115,
0x450: 0x71, 0x451: 0x116, 0x452: 0x05, 0x453: 0x05, 0x454: 0x05, 0x455: 0x117,
0x47e: 0x118, 0x47f: 0x119,
// Block 0x12, offset 0x480
0x480: 0x05, 0x481: 0x05, 0x482: 0x05, 0x483: 0x05, 0x484: 0x05, 0x485: 0x05, 0x486: 0x05, 0x487: 0x05,
0x488: 0x05, 0x489: 0x05, 0x48a: 0x05, 0x48b: 0x05, 0x48c: 0x05, 0x48d: 0x05, 0x48e: 0x05, 0x48f: 0x05,
0x490: 0x11a, 0x491: 0x11b,
// Block 0x13, offset 0x4c0
0x4d0: 0x05, 0x4d1: 0x05, 0x4d2: 0x05, 0x4d3: 0x05, 0x4d4: 0x05, 0x4d5: 0x05, 0x4d6: 0x05, 0x4d7: 0x05,
0x4d8: 0x05, 0x4d9: 0xfd,
// Block 0x14, offset 0x500
0x520: 0x05, 0x521: 0x05, 0x522: 0x05, 0x523: 0x05, 0x524: 0x05, 0x525: 0x05, 0x526: 0x05, 0x527: 0x05,
0x528: 0x108, 0x529: 0x11c, 0x52a: 0x11d, 0x52b: 0x11e, 0x52c: 0x11f, 0x52d: 0x120, 0x52e: 0x121,
0x539: 0x05, 0x53a: 0x122, 0x53c: 0x05, 0x53d: 0x123, 0x53e: 0x124, 0x53f: 0x125,
// Block 0x15, offset 0x540
0x540: 0x05, 0x541: 0x05, 0x542: 0x05, 0x543: 0x05, 0x544: 0x05, 0x545: 0x05, 0x546: 0x05, 0x547: 0x05,
0x548: 0x05, 0x549: 0x05, 0x54a: 0x05, 0x54b: 0x05, 0x54c: 0x05, 0x54d: 0x05, 0x54e: 0x05, 0x54f: 0x05,
0x550: 0x05, 0x551: 0x05, 0x552: 0x05, 0x553: 0x05, 0x554: 0x05, 0x555: 0x05, 0x556: 0x05, 0x557: 0x05,
0x558: 0x05, 0x559: 0x05, 0x55a: 0x05, 0x55b: 0x05, 0x55c: 0x05, 0x55d: 0x05, 0x55e: 0x05, 0x55f: 0x126,
0x560: 0x05, 0x561: 0x05, 0x562: 0x05, 0x563: 0x05, 0x564: 0x05, 0x565: 0x05, 0x566: 0x05, 0x567: 0x05,
0x568: 0x05, 0x569: 0x05, 0x56a: 0x05, 0x56b: 0x05, 0x56c: 0x05, 0x56d: 0x05, 0x56e: 0x05, 0x56f: 0x05,
0x570: 0x05, 0x571: 0x05, 0x572: 0x05, 0x573: 0x127, 0x574: 0xd9,
// Block 0x16, offset 0x580
0x5bf: 0x128,
// Block 0x17, offset 0x5c0
0x5c0: 0x8d, 0x5c1: 0x8d, 0x5c2: 0x8d, 0x5c3: 0x8d, 0x5c4: 0x129, 0x5c5: 0x12a, 0x5c6: 0x05, 0x5c7: 0x05,
0x5c8: 0x05, 0x5c9: 0x05, 0x5ca: 0x05, 0x5cb: 0x12b,
0x5f0: 0x05, 0x5f1: 0x12c, 0x5f2: 0x12d,
// Block 0x18, offset 0x600
0x63c: 0x12e, 0x63d: 0x12f, 0x63e: 0x71, 0x63f: 0x130,
// Block 0x19, offset 0x640
0x640: 0x71, 0x641: 0x71, 0x642: 0x71, 0x643: 0x131, 0x644: 0x132, 0x645: 0x133, 0x646: 0x134, 0x647: 0x135,
0x648: 0xbb, 0x649: 0x136, 0x64b: 0x137, 0x64c: 0x71, 0x64d: 0x138,
0x650: 0x71, 0x651: 0x139, 0x652: 0x13a, 0x653: 0x13b, 0x654: 0x13c, 0x655: 0x13d, 0x656: 0x71, 0x657: 0x71,
0x658: 0x71, 0x659: 0x71, 0x65a: 0x13e, 0x65b: 0x71, 0x65c: 0x71, 0x65d: 0x71, 0x65e: 0x71, 0x65f: 0x13f,
0x660: 0x71, 0x661: 0x71, 0x662: 0x71, 0x663: 0x71, 0x664: 0x71, 0x665: 0x71, 0x666: 0x71, 0x667: 0x71,
0x668: 0x140, 0x669: 0x141, 0x66a: 0x142,
0x67c: 0x143,
// Block 0x1a, offset 0x680
0x680: 0x144, 0x681: 0x145, 0x682: 0x146, 0x684: 0x147, 0x685: 0x148,
0x68a: 0x149, 0x68b: 0x14a,
0x693: 0x14b,
0x69f: 0x14c,
0x6a0: 0x05, 0x6a1: 0x05, 0x6a2: 0x05, 0x6a3: 0x14d, 0x6a4: 0x14e, 0x6a5: 0x14f,
0x6b1: 0x150, 0x6b2: 0x151, 0x6b4: 0x152,
0x6b8: 0x153, 0x6b9: 0x154, 0x6ba: 0x155, 0x6bb: 0x156,
// Block 0x1b, offset 0x6c0
0x6c0: 0x157, 0x6c1: 0x71, 0x6c2: 0x158, 0x6c3: 0x159, 0x6c4: 0x71, 0x6c5: 0x71, 0x6c6: 0x145, 0x6c7: 0x15a,
0x6c8: 0x15b, 0x6c9: 0x15c, 0x6cc: 0x71, 0x6cd: 0x71, 0x6ce: 0x71, 0x6cf: 0x71,
0x6d0: 0x71, 0x6d1: 0x71, 0x6d2: 0x71, 0x6d3: 0x71, 0x6d4: 0x71, 0x6d5: 0x71, 0x6d6: 0x71, 0x6d7: 0x71,
0x6d8: 0x71, 0x6d9: 0x71, 0x6da: 0x71, 0x6db: 0x15d, 0x6dc: 0x71, 0x6dd: 0x15e, 0x6de: 0x71, 0x6df: 0x15f,
0x6e0: 0x160, 0x6e1: 0x161, 0x6e2: 0x162, 0x6e4: 0x71, 0x6e5: 0x71, 0x6e6: 0x71, 0x6e7: 0x71,
0x6e8: 0x71, 0x6e9: 0x163, 0x6ea: 0x164, 0x6eb: 0x165, 0x6ec: 0x71, 0x6ed: 0x71, 0x6ee: 0x166, 0x6ef: 0x167,
// Block 0x1c, offset 0x700
0x700: 0x8d, 0x701: 0x8d, 0x702: 0x8d, 0x703: 0x8d, 0x704: 0x8d, 0x705: 0x8d, 0x706: 0x8d, 0x707: 0x8d,
0x708: 0x8d, 0x709: 0x8d, 0x70a: 0x8d, 0x70b: 0x8d, 0x70c: 0x8d, 0x70d: 0x8d, 0x70e: 0x8d, 0x70f: 0x8d,
0x710: 0x8d, 0x711: 0x8d, 0x712: 0x8d, 0x713: 0x8d, 0x714: 0x8d, 0x715: 0x8d, 0x716: 0x8d, 0x717: 0x8d,
0x718: 0x8d, 0x719: 0x8d, 0x71a: 0x8d, 0x71b: 0x168, 0x71c: 0x8d, 0x71d: 0x8d, 0x71e: 0x8d, 0x71f: 0x8d,
0x720: 0x8d, 0x721: 0x8d, 0x722: 0x8d, 0x723: 0x8d, 0x724: 0x8d, 0x725: 0x8d, 0x726: 0x8d, 0x727: 0x8d,
0x728: 0x8d, 0x729: 0x8d, 0x72a: 0x8d, 0x72b: 0x8d, 0x72c: 0x8d, 0x72d: 0x8d, 0x72e: 0x8d, 0x72f: 0x8d,
0x730: 0x8d, 0x731: 0x8d, 0x732: 0x8d, 0x733: 0x8d, 0x734: 0x8d, 0x735: 0x8d, 0x736: 0x8d, 0x737: 0x8d,
0x738: 0x8d, 0x739: 0x8d, 0x73a: 0x8d, 0x73b: 0x8d, 0x73c: 0x8d, 0x73d: 0x8d, 0x73e: 0x8d, 0x73f: 0x8d,
// Block 0x1d, offset 0x740
0x740: 0x8d, 0x741: 0x8d, 0x742: 0x8d, 0x743: 0x8d, 0x744: 0x8d, 0x745: 0x8d, 0x746: 0x8d, 0x747: 0x8d,
0x748: 0x8d, 0x749: 0x8d, 0x74a: 0x8d, 0x74b: 0x8d, 0x74c: 0x8d, 0x74d: 0x8d, 0x74e: 0x8d, 0x74f: 0x8d,
0x750: 0x8d, 0x751: 0x8d, 0x752: 0x8d, 0x753: 0x8d, 0x754: 0x8d, 0x755: 0x8d, 0x756: 0x8d, 0x757: 0x8d,
0x758: 0x8d, 0x759: 0x8d, 0x75a: 0x8d, 0x75b: 0x8d, 0x75c: 0x169, 0x75d: 0x8d, 0x75e: 0x8d, 0x75f: 0x8d,
0x760: 0x16a, 0x761: 0x8d, 0x762: 0x8d, 0x763: 0x8d, 0x764: 0x8d, 0x765: 0x8d, 0x766: 0x8d, 0x767: 0x8d,
0x768: 0x8d, 0x769: 0x8d, 0x76a: 0x8d, 0x76b: 0x8d, 0x76c: 0x8d, 0x76d: 0x8d, 0x76e: 0x8d, 0x76f: 0x8d,
0x770: 0x8d, 0x771: 0x8d, 0x772: 0x8d, 0x773: 0x8d, 0x774: 0x8d, 0x775: 0x8d, 0x776: 0x8d, 0x777: 0x8d,
0x778: 0x8d, 0x779: 0x8d, 0x77a: 0x8d, 0x77b: 0x8d, 0x77c: 0x8d, 0x77d: 0x8d, 0x77e: 0x8d, 0x77f: 0x8d,
// Block 0x1e, offset 0x780
0x780: 0x8d, 0x781: 0x8d, 0x782: 0x8d, 0x783: 0x8d, 0x784: 0x8d, 0x785: 0x8d, 0x786: 0x8d, 0x787: 0x8d,
0x788: 0x8d, 0x789: 0x8d, 0x78a: 0x8d, 0x78b: 0x8d, 0x78c: 0x8d, 0x78d: 0x8d, 0x78e: 0x8d, 0x78f: 0x8d,
0x790: 0x8d, 0x791: 0x8d, 0x792: 0x8d, 0x793: 0x8d, 0x794: 0x8d, 0x795: 0x8d, 0x796: 0x8d, 0x797: 0x8d,
0x798: 0x8d, 0x799: 0x8d, 0x79a: 0x8d, 0x79b: 0x8d, 0x79c: 0x8d, 0x79d: 0x8d, 0x79e: 0x8d, 0x79f: 0x8d,
0x7a0: 0x8d, 0x7a1: 0x8d, 0x7a2: 0x8d, 0x7a3: 0x8d, 0x7a4: 0x8d, 0x7a5: 0x8d, 0x7a6: 0x8d, 0x7a7: 0x8d,
0x7a8: 0x8d, 0x7a9: 0x8d, 0x7aa: 0x8d, 0x7ab: 0x8d, 0x7ac: 0x8d, 0x7ad: 0x8d, 0x7ae: 0x8d, 0x7af: 0x8d,
0x7b0: 0x8d, 0x7b1: 0x8d, 0x7b2: 0x8d, 0x7b3: 0x8d, 0x7b4: 0x8d, 0x7b5: 0x8d, 0x7b6: 0x8d, 0x7b7: 0x8d,
0x7b8: 0x8d, 0x7b9: 0x8d, 0x7ba: 0x16b, 0x7bb: 0x8d, 0x7bc: 0x8d, 0x7bd: 0x8d, 0x7be: 0x8d, 0x7bf: 0x8d,
// Block 0x1f, offset 0x7c0
0x7c0: 0x8d, 0x7c1: 0x8d, 0x7c2: 0x8d, 0x7c3: 0x8d, 0x7c4: 0x8d, 0x7c5: 0x8d, 0x7c6: 0x8d, 0x7c7: 0x8d,
0x7c8: 0x8d, 0x7c9: 0x8d, 0x7ca: 0x8d, 0x7cb: 0x8d, 0x7cc: 0x8d, 0x7cd: 0x8d, 0x7ce: 0x8d, 0x7cf: 0x8d,
0x7d0: 0x8d, 0x7d1: 0x8d, 0x7d2: 0x8d, 0x7d3: 0x8d, 0x7d4: 0x8d, 0x7d5: 0x8d, 0x7d6: 0x8d, 0x7d7: 0x8d,
0x7d8: 0x8d, 0x7d9: 0x8d, 0x7da: 0x8d, 0x7db: 0x8d, 0x7dc: 0x8d, 0x7dd: 0x8d, 0x7de: 0x8d, 0x7df: 0x8d,
0x7e0: 0x8d, 0x7e1: 0x8d, 0x7e2: 0x8d, 0x7e3: 0x8d, 0x7e4: 0x8d, 0x7e5: 0x8d, 0x7e6: 0x8d, 0x7e7: 0x8d,
0x7e8: 0x8d, 0x7e9: 0x8d, 0x7ea: 0x8d, 0x7eb: 0x8d, 0x7ec: 0x8d, 0x7ed: 0x8d, 0x7ee: 0x8d, 0x7ef: 0x16c,
// Block 0x20, offset 0x800
0x820: 0x80, 0x821: 0x80, 0x822: 0x80, 0x823: 0x80, 0x824: 0x80, 0x825: 0x80, 0x826: 0x80, 0x827: 0x80,
0x828: 0x16d,
// Block 0x21, offset 0x840
0x840: 0x8d, 0x841: 0x8d, 0x842: 0x8d, 0x843: 0x8d, 0x844: 0x8d, 0x845: 0x8d, 0x846: 0x8d, 0x847: 0x8d,
0x848: 0x8d, 0x849: 0x8d, 0x84a: 0x8d, 0x84b: 0x8d, 0x84c: 0x8d, 0x84d: 0x16e, 0x84e: 0x8d, 0x84f: 0x8d,
0x850: 0x8d, 0x851: 0x8d, 0x852: 0x8d, 0x853: 0x8d, 0x854: 0x8d, 0x855: 0x8d, 0x856: 0x8d, 0x857: 0x8d,
0x858: 0x8d, 0x859: 0x8d, 0x85a: 0x8d, 0x85b: 0x8d, 0x85c: 0x8d, 0x85d: 0x8d, 0x85e: 0x8d, 0x85f: 0x8d,
0x860: 0x8d, 0x861: 0x8d, 0x862: 0x8d, 0x863: 0x8d, 0x864: 0x8d, 0x865: 0x8d, 0x866: 0x8d, 0x867: 0x8d,
0x868: 0x8d, 0x869: 0x8d, 0x86a: 0x8d, 0x86b: 0x8d, 0x86c: 0x8d, 0x86d: 0x8d, 0x86e: 0x8d, 0x86f: 0x8d,
0x870: 0x8d, 0x871: 0x8d, 0x872: 0x8d, 0x873: 0x8d, 0x874: 0x8d, 0x875: 0x8d, 0x876: 0x8d, 0x877: 0x8d,
0x878: 0x8d, 0x879: 0x8d, 0x87a: 0x8d, 0x87b: 0x8d, 0x87c: 0x8d, 0x87d: 0x8d, 0x87e: 0x8d, 0x87f: 0x8d,
// Block 0x22, offset 0x880
0x880: 0x8d, 0x881: 0x8d, 0x882: 0x8d, 0x883: 0x8d, 0x884: 0x8d, 0x885: 0x8d, 0x886: 0x8d, 0x887: 0x8d,
0x888: 0x8d, 0x889: 0x8d, 0x88a: 0x8d, 0x88b: 0x8d, 0x88c: 0x8d, 0x88d: 0x8d, 0x88e: 0x16f,
// Block 0x23, offset 0x8c0
0x8d0: 0x0d, 0x8d1: 0x0e, 0x8d2: 0x0f, 0x8d3: 0x10, 0x8d4: 0x11, 0x8d6: 0x12, 0x8d7: 0x09,
0x8d8: 0x13, 0x8da: 0x14, 0x8db: 0x15, 0x8dc: 0x16, 0x8dd: 0x17, 0x8de: 0x18, 0x8df: 0x19,
0x8e0: 0x07, 0x8e1: 0x07, 0x8e2: 0x07, 0x8e3: 0x07, 0x8e4: 0x07, 0x8e5: 0x07, 0x8e6: 0x07, 0x8e7: 0x07,
0x8e8: 0x07, 0x8e9: 0x07, 0x8ea: 0x1a, 0x8eb: 0x1b, 0x8ec: 0x1c, 0x8ed: 0x07, 0x8ee: 0x1d, 0x8ef: 0x1e,
0x8f0: 0x07, 0x8f1: 0x1f, 0x8f2: 0x20,
// Block 0x24, offset 0x900
0x900: 0x170, 0x901: 0x3e, 0x904: 0x3e, 0x905: 0x3e, 0x906: 0x3e, 0x907: 0x171,
// Block 0x25, offset 0x940
0x940: 0x3e, 0x941: 0x3e, 0x942: 0x3e, 0x943: 0x3e, 0x944: 0x3e, 0x945: 0x3e, 0x946: 0x3e, 0x947: 0x3e,
0x948: 0x3e, 0x949: 0x3e, 0x94a: 0x3e, 0x94b: 0x3e, 0x94c: 0x3e, 0x94d: 0x3e, 0x94e: 0x3e, 0x94f: 0x3e,
0x950: 0x3e, 0x951: 0x3e, 0x952: 0x3e, 0x953: 0x3e, 0x954: 0x3e, 0x955: 0x3e, 0x956: 0x3e, 0x957: 0x3e,
0x958: 0x3e, 0x959: 0x3e, 0x95a: 0x3e, 0x95b: 0x3e, 0x95c: 0x3e, 0x95d: 0x3e, 0x95e: 0x3e, 0x95f: 0x3e,
0x960: 0x3e, 0x961: 0x3e, 0x962: 0x3e, 0x963: 0x3e, 0x964: 0x3e, 0x965: 0x3e, 0x966: 0x3e, 0x967: 0x3e,
0x968: 0x3e, 0x969: 0x3e, 0x96a: 0x3e, 0x96b: 0x3e, 0x96c: 0x3e, 0x96d: 0x3e, 0x96e: 0x3e, 0x96f: 0x3e,
0x970: 0x3e, 0x971: 0x3e, 0x972: 0x3e, 0x973: 0x3e, 0x974: 0x3e, 0x975: 0x3e, 0x976: 0x3e, 0x977: 0x3e,
0x978: 0x3e, 0x979: 0x3e, 0x97a: 0x3e, 0x97b: 0x3e, 0x97c: 0x3e, 0x97d: 0x3e, 0x97e: 0x3e, 0x97f: 0x172,
// Block 0x26, offset 0x980
0x9a0: 0x22,
0x9b0: 0x0b, 0x9b1: 0x0b, 0x9b2: 0x0b, 0x9b3: 0x0b, 0x9b4: 0x0b, 0x9b5: 0x0b, 0x9b6: 0x0b, 0x9b7: 0x0b,
0x9b8: 0x0b, 0x9b9: 0x0b, 0x9ba: 0x0b, 0x9bb: 0x0b, 0x9bc: 0x0b, 0x9bd: 0x0b, 0x9be: 0x0b, 0x9bf: 0x23,
// Block 0x27, offset 0x9c0
0x9c0: 0x0b, 0x9c1: 0x0b, 0x9c2: 0x0b, 0x9c3: 0x0b, 0x9c4: 0x0b, 0x9c5: 0x0b, 0x9c6: 0x0b, 0x9c7: 0x0b,
0x9c8: 0x0b, 0x9c9: 0x0b, 0x9ca: 0x0b, 0x9cb: 0x0b, 0x9cc: 0x0b, 0x9cd: 0x0b, 0x9ce: 0x0b, 0x9cf: 0x23,
}
// Total table size 28992 bytes (28KiB); checksum: 811C9DC5
// 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.
package precis
import "golang.org/x/text/transform"
// Transformer implements the transform.Transformer interface.
type Transformer struct {
t transform.Transformer
}
// Reset implements the transform.Transformer interface.
func (t Transformer) Reset() { t.t.Reset() }
// Transform implements the transform.Transformer interface.
func (t Transformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
return t.t.Transform(dst, src, atEOF)
}
// Bytes returns a new byte slice with the result of applying t to b.
func (t Transformer) Bytes(b []byte) []byte {
b, _, _ = transform.Bytes(t, b)
return b
}
// String returns a string with the result of applying t to s.
func (t Transformer) String(s string) string {
s, _, _ = transform.String(t, s)
return s
}
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
package precis
// entry is the entry of a trie table
// 7..6 property (unassigned, disallowed, maybe, valid)
// 5..0 category
type entry uint8
const (
propShift = 6
propMask = 0xc0
catMask = 0x3f
)
func (e entry) property() property { return property(e & propMask) }
func (e entry) category() category { return category(e & catMask) }
type property uint8
// The order of these constants matter. A Profile may consider runes to be
// allowed either from pValid or idDisOrFreePVal.
const (
unassigned property = iota << propShift
disallowed
idDisOrFreePVal // disallowed for Identifier, pValid for FreeForm
pValid
)
// compute permutations of all properties and specialCategories.
type category uint8
const (
other category = iota
// Special rune types
joiningL
joiningD
joiningT
joiningR
viramaModifier
viramaJoinT // Virama + JoiningT
latinSmallL // U+006c
greek
greekJoinT // Greek + JoiningT
hebrew
hebrewJoinT // Hebrew + JoiningT
japanese // hirigana, katakana, han
// Special rune types associated with contextual rules defined in
// https://tools.ietf.org/html/rfc5892#appendix-A.
// ContextO
zeroWidthNonJoiner // rule 1
zeroWidthJoiner // rule 2
// ContextJ
middleDot // rule 3
greekLowerNumeralSign // rule 4
hebrewPreceding // rule 5 and 6
katakanaMiddleDot // rule 7
arabicIndicDigit // rule 8
extendedArabicIndicDigit // rule 9
numCategories
)
// Copyright 2013 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 transform provides reader and writer wrappers that transform the
// bytes passing through as well as various transformations. Example
// transformations provided by other packages include normalization and
// conversion between character sets.
package transform // import "golang.org/x/text/transform"
import (
"bytes"
"errors"
"io"
"unicode/utf8"
)
var (
// ErrShortDst means that the destination buffer was too short to
// receive all of the transformed bytes.
ErrShortDst = errors.New("transform: short destination buffer")
// ErrShortSrc means that the source buffer has insufficient data to
// complete the transformation.
ErrShortSrc = errors.New("transform: short source buffer")
// ErrEndOfSpan means that the input and output (the transformed input)
// are not identical.
ErrEndOfSpan = errors.New("transform: input and output are not identical")
// errInconsistentByteCount means that Transform returned success (nil
// error) but also returned nSrc inconsistent with the src argument.
errInconsistentByteCount = errors.New("transform: inconsistent byte count returned")
// errShortInternal means that an internal buffer is not large enough
// to make progress and the Transform operation must be aborted.
errShortInternal = errors.New("transform: short internal buffer")
)
// Transformer transforms bytes.
type Transformer interface {
// Transform writes to dst the transformed bytes read from src, and
// returns the number of dst bytes written and src bytes read. The
// atEOF argument tells whether src represents the last bytes of the
// input.
//
// Callers should always process the nDst bytes produced and account
// for the nSrc bytes consumed before considering the error err.
//
// A nil error means that all of the transformed bytes (whether freshly
// transformed from src or left over from previous Transform calls)
// were written to dst. A nil error can be returned regardless of
// whether atEOF is true. If err is nil then nSrc must equal len(src);
// the converse is not necessarily true.
//
// ErrShortDst means that dst was too short to receive all of the
// transformed bytes. ErrShortSrc means that src had insufficient data
// to complete the transformation. If both conditions apply, then
// either error may be returned. Other than the error conditions listed
// here, implementations are free to report other errors that arise.
Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error)
// Reset resets the state and allows a Transformer to be reused.
Reset()
}
// SpanningTransformer extends the Transformer interface with a Span method
// that determines how much of the input already conforms to the Transformer.
type SpanningTransformer interface {
Transformer
// Span returns a position in src such that transforming src[:n] results in
// identical output src[:n] for these bytes. It does not necessarily return
// the largest such n. The atEOF argument tells whether src represents the
// last bytes of the input.
//
// Callers should always account for the n bytes consumed before
// considering the error err.
//
// A nil error means that all input bytes are known to be identical to the
// output produced by the Transformer. A nil error can be returned
// regardless of whether atEOF is true. If err is nil, then n must
// equal len(src); the converse is not necessarily true.
//
// ErrEndOfSpan means that the Transformer output may differ from the
// input after n bytes. Note that n may be len(src), meaning that the output
// would contain additional bytes after otherwise identical output.
// ErrShortSrc means that src had insufficient data to determine whether the
// remaining bytes would change. Other than the error conditions listed
// here, implementations are free to report other errors that arise.
//
// Calling Span can modify the Transformer state as a side effect. In
// effect, it does the transformation just as calling Transform would, only
// without copying to a destination buffer and only up to a point it can
// determine the input and output bytes are the same. This is obviously more
// limited than calling Transform, but can be more efficient in terms of
// copying and allocating buffers. Calls to Span and Transform may be
// interleaved.
Span(src []byte, atEOF bool) (n int, err error)
}
// NopResetter can be embedded by implementations of Transformer to add a nop
// Reset method.
type NopResetter struct{}
// Reset implements the Reset method of the Transformer interface.
func (NopResetter) Reset() {}
// Reader wraps another io.Reader by transforming the bytes read.
type Reader struct {
r io.Reader
t Transformer
err error
// dst[dst0:dst1] contains bytes that have been transformed by t but
// not yet copied out via Read.
dst []byte
dst0, dst1 int
// src[src0:src1] contains bytes that have been read from r but not
// yet transformed through t.
src []byte
src0, src1 int
// transformComplete is whether the transformation is complete,
// regardless of whether or not it was successful.
transformComplete bool
}
const defaultBufSize = 4096
// NewReader returns a new Reader that wraps r by transforming the bytes read
// via t. It calls Reset on t.
func NewReader(r io.Reader, t Transformer) *Reader {
t.Reset()
return &Reader{
r: r,
t: t,
dst: make([]byte, defaultBufSize),
src: make([]byte, defaultBufSize),
}
}
// Read implements the io.Reader interface.
func (r *Reader) Read(p []byte) (int, error) {
n, err := 0, error(nil)
for {
// Copy out any transformed bytes and return the final error if we are done.
if r.dst0 != r.dst1 {
n = copy(p, r.dst[r.dst0:r.dst1])
r.dst0 += n
if r.dst0 == r.dst1 && r.transformComplete {
return n, r.err
}
return n, nil
} else if r.transformComplete {
return 0, r.err
}
// Try to transform some source bytes, or to flush the transformer if we
// are out of source bytes. We do this even if r.r.Read returned an error.
// As the io.Reader documentation says, "process the n > 0 bytes returned
// before considering the error".
if r.src0 != r.src1 || r.err != nil {
r.dst0 = 0
r.dst1, n, err = r.t.Transform(r.dst, r.src[r.src0:r.src1], r.err == io.EOF)
r.src0 += n
switch {
case err == nil:
if r.src0 != r.src1 {
r.err = errInconsistentByteCount
}
// The Transform call was successful; we are complete if we
// cannot read more bytes into src.
r.transformComplete = r.err != nil
continue
case err == ErrShortDst && (r.dst1 != 0 || n != 0):
// Make room in dst by copying out, and try again.
continue
case err == ErrShortSrc && r.src1-r.src0 != len(r.src) && r.err == nil:
// Read more bytes into src via the code below, and try again.
default:
r.transformComplete = true
// The reader error (r.err) takes precedence over the
// transformer error (err) unless r.err is nil or io.EOF.
if r.err == nil || r.err == io.EOF {
r.err = err
}
continue
}
}
// Move any untransformed source bytes to the start of the buffer
// and read more bytes.
if r.src0 != 0 {
r.src0, r.src1 = 0, copy(r.src, r.src[r.src0:r.src1])
}
n, r.err = r.r.Read(r.src[r.src1:])
r.src1 += n
}
}
// TODO: implement ReadByte (and ReadRune??).
// Writer wraps another io.Writer by transforming the bytes read.
// The user needs to call Close to flush unwritten bytes that may
// be buffered.
type Writer struct {
w io.Writer
t Transformer
dst []byte
// src[:n] contains bytes that have not yet passed through t.
src []byte
n int
}
// NewWriter returns a new Writer that wraps w by transforming the bytes written
// via t. It calls Reset on t.
func NewWriter(w io.Writer, t Transformer) *Writer {
t.Reset()
return &Writer{
w: w,
t: t,
dst: make([]byte, defaultBufSize),
src: make([]byte, defaultBufSize),
}
}
// Write implements the io.Writer interface. If there are not enough
// bytes available to complete a Transform, the bytes will be buffered
// for the next write. Call Close to convert the remaining bytes.
func (w *Writer) Write(data []byte) (n int, err error) {
src := data
if w.n > 0 {
// Append bytes from data to the last remainder.
// TODO: limit the amount copied on first try.
n = copy(w.src[w.n:], data)
w.n += n
src = w.src[:w.n]
}
for {
nDst, nSrc, err := w.t.Transform(w.dst, src, false)
if _, werr := w.w.Write(w.dst[:nDst]); werr != nil {
return n, werr
}
src = src[nSrc:]
if w.n == 0 {
n += nSrc
} else if len(src) <= n {
// Enough bytes from w.src have been consumed. We make src point
// to data instead to reduce the copying.
w.n = 0
n -= len(src)
src = data[n:]
if n < len(data) && (err == nil || err == ErrShortSrc) {
continue
}
}
switch err {
case ErrShortDst:
// This error is okay as long as we are making progress.
if nDst > 0 || nSrc > 0 {
continue
}
case ErrShortSrc:
if len(src) < len(w.src) {
m := copy(w.src, src)
// If w.n > 0, bytes from data were already copied to w.src and n
// was already set to the number of bytes consumed.
if w.n == 0 {
n += m
}
w.n = m
err = nil
} else if nDst > 0 || nSrc > 0 {
// Not enough buffer to store the remainder. Keep processing as
// long as there is progress. Without this case, transforms that
// require a lookahead larger than the buffer may result in an
// error. This is not something one may expect to be common in
// practice, but it may occur when buffers are set to small
// sizes during testing.
continue
}
case nil:
if w.n > 0 {
err = errInconsistentByteCount
}
}
return n, err
}
}
// Close implements the io.Closer interface.
func (w *Writer) Close() error {
src := w.src[:w.n]
for {
nDst, nSrc, err := w.t.Transform(w.dst, src, true)
if _, werr := w.w.Write(w.dst[:nDst]); werr != nil {
return werr
}
if err != ErrShortDst {
return err
}
src = src[nSrc:]
}
}
type nop struct{ NopResetter }
func (nop) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
n := copy(dst, src)
if n < len(src) {
err = ErrShortDst
}
return n, n, err
}
func (nop) Span(src []byte, atEOF bool) (n int, err error) {
return len(src), nil
}
type discard struct{ NopResetter }
func (discard) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
return 0, len(src), nil
}
var (
// Discard is a Transformer for which all Transform calls succeed
// by consuming all bytes and writing nothing.
Discard Transformer = discard{}
// Nop is a SpanningTransformer that copies src to dst.
Nop SpanningTransformer = nop{}
)
// chain is a sequence of links. A chain with N Transformers has N+1 links and
// N+1 buffers. Of those N+1 buffers, the first and last are the src and dst
// buffers given to chain.Transform and the middle N-1 buffers are intermediate
// buffers owned by the chain. The i'th link transforms bytes from the i'th
// buffer chain.link[i].b at read offset chain.link[i].p to the i+1'th buffer
// chain.link[i+1].b at write offset chain.link[i+1].n, for i in [0, N).
type chain struct {
link []link
err error
// errStart is the index at which the error occurred plus 1. Processing
// errStart at this level at the next call to Transform. As long as
// errStart > 0, chain will not consume any more source bytes.
errStart int
}
func (c *chain) fatalError(errIndex int, err error) {
if i := errIndex + 1; i > c.errStart {
c.errStart = i
c.err = err
}
}
type link struct {
t Transformer
// b[p:n] holds the bytes to be transformed by t.
b []byte
p int
n int
}
func (l *link) src() []byte {
return l.b[l.p:l.n]
}
func (l *link) dst() []byte {
return l.b[l.n:]
}
// Chain returns a Transformer that applies t in sequence.
func Chain(t ...Transformer) Transformer {
if len(t) == 0 {
return nop{}
}
c := &chain{link: make([]link, len(t)+1)}
for i, tt := range t {
c.link[i].t = tt
}
// Allocate intermediate buffers.
b := make([][defaultBufSize]byte, len(t)-1)
for i := range b {
c.link[i+1].b = b[i][:]
}
return c
}
// Reset resets the state of Chain. It calls Reset on all the Transformers.
func (c *chain) Reset() {
for i, l := range c.link {
if l.t != nil {
l.t.Reset()
}
c.link[i].p, c.link[i].n = 0, 0
}
}
// TODO: make chain use Span (is going to be fun to implement!)
// Transform applies the transformers of c in sequence.
func (c *chain) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
// Set up src and dst in the chain.
srcL := &c.link[0]
dstL := &c.link[len(c.link)-1]
srcL.b, srcL.p, srcL.n = src, 0, len(src)
dstL.b, dstL.n = dst, 0
var lastFull, needProgress bool // for detecting progress
// i is the index of the next Transformer to apply, for i in [low, high].
// low is the lowest index for which c.link[low] may still produce bytes.
// high is the highest index for which c.link[high] has a Transformer.
// The error returned by Transform determines whether to increase or
// decrease i. We try to completely fill a buffer before converting it.
for low, i, high := c.errStart, c.errStart, len(c.link)-2; low <= i && i <= high; {
in, out := &c.link[i], &c.link[i+1]
nDst, nSrc, err0 := in.t.Transform(out.dst(), in.src(), atEOF && low == i)
out.n += nDst
in.p += nSrc
if i > 0 && in.p == in.n {
in.p, in.n = 0, 0
}
needProgress, lastFull = lastFull, false
switch err0 {
case ErrShortDst:
// Process the destination buffer next. Return if we are already
// at the high index.
if i == high {
return dstL.n, srcL.p, ErrShortDst
}
if out.n != 0 {
i++
// If the Transformer at the next index is not able to process any
// source bytes there is nothing that can be done to make progress
// and the bytes will remain unprocessed. lastFull is used to
// detect this and break out of the loop with a fatal error.
lastFull = true
continue
}
// The destination buffer was too small, but is completely empty.
// Return a fatal error as this transformation can never complete.
c.fatalError(i, errShortInternal)
case ErrShortSrc:
if i == 0 {
// Save ErrShortSrc in err. All other errors take precedence.
err = ErrShortSrc
break
}
// Source bytes were depleted before filling up the destination buffer.
// Verify we made some progress, move the remaining bytes to the errStart
// and try to get more source bytes.
if needProgress && nSrc == 0 || in.n-in.p == len(in.b) {
// There were not enough source bytes to proceed while the source
// buffer cannot hold any more bytes. Return a fatal error as this
// transformation can never complete.
c.fatalError(i, errShortInternal)
break
}
// in.b is an internal buffer and we can make progress.
in.p, in.n = 0, copy(in.b, in.src())
fallthrough
case nil:
// if i == low, we have depleted the bytes at index i or any lower levels.
// In that case we increase low and i. In all other cases we decrease i to
// fetch more bytes before proceeding to the next index.
if i > low {
i--
continue
}
default:
c.fatalError(i, err0)
}
// Exhausted level low or fatal error: increase low and continue
// to process the bytes accepted so far.
i++
low = i
}
// If c.errStart > 0, this means we found a fatal error. We will clear
// all upstream buffers. At this point, no more progress can be made
// downstream, as Transform would have bailed while handling ErrShortDst.
if c.errStart > 0 {
for i := 1; i < c.errStart; i++ {
c.link[i].p, c.link[i].n = 0, 0
}
err, c.errStart, c.err = c.err, 0, nil
}
return dstL.n, srcL.p, err
}
// Deprecated: Use runes.Remove instead.
func RemoveFunc(f func(r rune) bool) Transformer {
return removeF(f)
}
type removeF func(r rune) bool
func (removeF) Reset() {}
// Transform implements the Transformer interface.
func (t removeF) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
for r, sz := rune(0), 0; len(src) > 0; src = src[sz:] {
if r = rune(src[0]); r < utf8.RuneSelf {
sz = 1
} else {
r, sz = utf8.DecodeRune(src)
if sz == 1 {
// Invalid rune.
if !atEOF && !utf8.FullRune(src) {
err = ErrShortSrc
break
}
// We replace illegal bytes with RuneError. Not doing so might
// otherwise turn a sequence of invalid UTF-8 into valid UTF-8.
// The resulting byte sequence may subsequently contain runes
// for which t(r) is true that were passed unnoticed.
if !t(r) {
if nDst+3 > len(dst) {
err = ErrShortDst
break
}
nDst += copy(dst[nDst:], "\uFFFD")
}
nSrc++
continue
}
}
if !t(r) {
if nDst+sz > len(dst) {
err = ErrShortDst
break
}
nDst += copy(dst[nDst:], src[:sz])
}
nSrc += sz
}
return
}
// grow returns a new []byte that is longer than b, and copies the first n bytes
// of b to the start of the new slice.
func grow(b []byte, n int) []byte {
m := len(b)
if m <= 32 {
m = 64
} else if m <= 256 {
m *= 2
} else {
m += m >> 1
}
buf := make([]byte, m)
copy(buf, b[:n])
return buf
}
const initialBufSize = 128
// String returns a string with the result of converting s[:n] using t, where
// n <= len(s). If err == nil, n will be len(s). It calls Reset on t.
func String(t Transformer, s string) (result string, n int, err error) {
t.Reset()
if s == "" {
// Fast path for the common case for empty input. Results in about a
// 86% reduction of running time for BenchmarkStringLowerEmpty.
if _, _, err := t.Transform(nil, nil, true); err == nil {
return "", 0, nil
}
}
// Allocate only once. Note that both dst and src escape when passed to
// Transform.
buf := [2 * initialBufSize]byte{}
dst := buf[:initialBufSize:initialBufSize]
src := buf[initialBufSize : 2*initialBufSize]
// The input string s is transformed in multiple chunks (starting with a
// chunk size of initialBufSize). nDst and nSrc are per-chunk (or
// per-Transform-call) indexes, pDst and pSrc are overall indexes.
nDst, nSrc := 0, 0
pDst, pSrc := 0, 0
// pPrefix is the length of a common prefix: the first pPrefix bytes of the
// result will equal the first pPrefix bytes of s. It is not guaranteed to
// be the largest such value, but if pPrefix, len(result) and len(s) are
// all equal after the final transform (i.e. calling Transform with atEOF
// being true returned nil error) then we don't need to allocate a new
// result string.
pPrefix := 0
for {
// Invariant: pDst == pPrefix && pSrc == pPrefix.
n := copy(src, s[pSrc:])
nDst, nSrc, err = t.Transform(dst, src[:n], pSrc+n == len(s))
pDst += nDst
pSrc += nSrc
// TODO: let transformers implement an optional Spanner interface, akin
// to norm's QuickSpan. This would even allow us to avoid any allocation.
if !bytes.Equal(dst[:nDst], src[:nSrc]) {
break
}
pPrefix = pSrc
if err == ErrShortDst {
// A buffer can only be short if a transformer modifies its input.
break
} else if err == ErrShortSrc {
if nSrc == 0 {
// No progress was made.
break
}
// Equal so far and !atEOF, so continue checking.
} else if err != nil || pPrefix == len(s) {
return string(s[:pPrefix]), pPrefix, err
}
}
// Post-condition: pDst == pPrefix + nDst && pSrc == pPrefix + nSrc.
// We have transformed the first pSrc bytes of the input s to become pDst
// transformed bytes. Those transformed bytes are discontiguous: the first
// pPrefix of them equal s[:pPrefix] and the last nDst of them equal
// dst[:nDst]. We copy them around, into a new dst buffer if necessary, so
// that they become one contiguous slice: dst[:pDst].
if pPrefix != 0 {
newDst := dst
if pDst > len(newDst) {
newDst = make([]byte, len(s)+nDst-nSrc)
}
copy(newDst[pPrefix:pDst], dst[:nDst])
copy(newDst[:pPrefix], s[:pPrefix])
dst = newDst
}
// Prevent duplicate Transform calls with atEOF being true at the end of
// the input. Also return if we have an unrecoverable error.
if (err == nil && pSrc == len(s)) ||
(err != nil && err != ErrShortDst && err != ErrShortSrc) {
return string(dst[:pDst]), pSrc, err
}
// Transform the remaining input, growing dst and src buffers as necessary.
for {
n := copy(src, s[pSrc:])
atEOF := pSrc+n == len(s)
nDst, nSrc, err := t.Transform(dst[pDst:], src[:n], atEOF)
pDst += nDst
pSrc += nSrc
// If we got ErrShortDst or ErrShortSrc, do not grow as long as we can
// make progress. This may avoid excessive allocations.
if err == ErrShortDst {
if nDst == 0 {
dst = grow(dst, pDst)
}
} else if err == ErrShortSrc {
if atEOF {
return string(dst[:pDst]), pSrc, err
}
if nSrc == 0 {
src = grow(src, 0)
}
} else if err != nil || pSrc == len(s) {
return string(dst[:pDst]), pSrc, err
}
}
}
// Bytes returns a new byte slice with the result of converting b[:n] using t,
// where n <= len(b). If err == nil, n will be len(b). It calls Reset on t.
func Bytes(t Transformer, b []byte) (result []byte, n int, err error) {
return doAppend(t, 0, make([]byte, len(b)), b)
}
// Append appends the result of converting src[:n] using t to dst, where
// n <= len(src), If err == nil, n will be len(src). It calls Reset on t.
func Append(t Transformer, dst, src []byte) (result []byte, n int, err error) {
if len(dst) == cap(dst) {
n := len(src) + len(dst) // It is okay for this to be 0.
b := make([]byte, n)
dst = b[:copy(b, dst)]
}
return doAppend(t, len(dst), dst[:cap(dst)], src)
}
func doAppend(t Transformer, pDst int, dst, src []byte) (result []byte, n int, err error) {
t.Reset()
pSrc := 0
for {
nDst, nSrc, err := t.Transform(dst[pDst:], src[pSrc:], true)
pDst += nDst
pSrc += nSrc
if err != ErrShortDst {
return dst[:pDst], pSrc, err
}
// Grow the destination buffer, but do not grow as long as we can make
// progress. This may avoid excessive allocations.
if nDst == 0 {
dst = grow(dst, pDst)
}
}
}
// 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.
//go:generate go run gen.go gen_trieval.go gen_ranges.go
// Package bidi contains functionality for bidirectional text support.
//
// See https://www.unicode.org/reports/tr9.
//
// NOTE: UNDER CONSTRUCTION. This API may change in backwards incompatible ways
// and without notice.
package bidi // import "golang.org/x/text/unicode/bidi"
// TODO
// - Transformer for reordering?
// - Transformer (validator, really) for Bidi Rule.
import (
"bytes"
)
// This API tries to avoid dealing with embedding levels for now. Under the hood
// these will be computed, but the question is to which extent the user should
// know they exist. We should at some point allow the user to specify an
// embedding hierarchy, though.
// A Direction indicates the overall flow of text.
type Direction int
const (
// LeftToRight indicates the text contains no right-to-left characters and
// that either there are some left-to-right characters or the option
// DefaultDirection(LeftToRight) was passed.
LeftToRight Direction = iota
// RightToLeft indicates the text contains no left-to-right characters and
// that either there are some right-to-left characters or the option
// DefaultDirection(RightToLeft) was passed.
RightToLeft
// Mixed indicates text contains both left-to-right and right-to-left
// characters.
Mixed
// Neutral means that text contains no left-to-right and right-to-left
// characters and that no default direction has been set.
Neutral
)
type options struct {
defaultDirection Direction
}
// An Option is an option for Bidi processing.
type Option func(*options)
// ICU allows the user to define embedding levels. This may be used, for example,
// to use hierarchical structure of markup languages to define embeddings.
// The following option may be a way to expose this functionality in this API.
// // LevelFunc sets a function that associates nesting levels with the given text.
// // The levels function will be called with monotonically increasing values for p.
// func LevelFunc(levels func(p int) int) Option {
// panic("unimplemented")
// }
// DefaultDirection sets the default direction for a Paragraph. The direction is
// overridden if the text contains directional characters.
func DefaultDirection(d Direction) Option {
return func(opts *options) {
opts.defaultDirection = d
}
}
// A Paragraph holds a single Paragraph for Bidi processing.
type Paragraph struct {
p []byte
o Ordering
opts []Option
types []Class
pairTypes []bracketType
pairValues []rune
runes []rune
options options
}
// Initialize the p.pairTypes, p.pairValues and p.types from the input previously
// set by p.SetBytes() or p.SetString(). Also limit the input up to (and including) a paragraph
// separator (bidi class B).
//
// The function p.Order() needs these values to be set, so this preparation could be postponed.
// But since the SetBytes and SetStrings functions return the length of the input up to the paragraph
// separator, the whole input needs to be processed anyway and should not be done twice.
//
// The function has the same return values as SetBytes() / SetString()
func (p *Paragraph) prepareInput() (n int, err error) {
p.runes = bytes.Runes(p.p)
bytecount := 0
// clear slices from previous SetString or SetBytes
p.pairTypes = nil
p.pairValues = nil
p.types = nil
for _, r := range p.runes {
props, i := LookupRune(r)
bytecount += i
cls := props.Class()
if cls == B {
return bytecount, nil
}
p.types = append(p.types, cls)
if props.IsOpeningBracket() {
p.pairTypes = append(p.pairTypes, bpOpen)
p.pairValues = append(p.pairValues, r)
} else if props.IsBracket() {
// this must be a closing bracket,
// since IsOpeningBracket is not true
p.pairTypes = append(p.pairTypes, bpClose)
p.pairValues = append(p.pairValues, r)
} else {
p.pairTypes = append(p.pairTypes, bpNone)
p.pairValues = append(p.pairValues, 0)
}
}
return bytecount, nil
}
// SetBytes configures p for the given paragraph text. It replaces text
// previously set by SetBytes or SetString. If b contains a paragraph separator
// it will only process the first paragraph and report the number of bytes
// consumed from b including this separator. Error may be non-nil if options are
// given.
func (p *Paragraph) SetBytes(b []byte, opts ...Option) (n int, err error) {
p.p = b
p.opts = opts
return p.prepareInput()
}
// SetString configures s for the given paragraph text. It replaces text
// previously set by SetBytes or SetString. If s contains a paragraph separator
// it will only process the first paragraph and report the number of bytes
// consumed from s including this separator. Error may be non-nil if options are
// given.
func (p *Paragraph) SetString(s string, opts ...Option) (n int, err error) {
p.p = []byte(s)
p.opts = opts
return p.prepareInput()
}
// IsLeftToRight reports whether the principle direction of rendering for this
// paragraphs is left-to-right. If this returns false, the principle direction
// of rendering is right-to-left.
func (p *Paragraph) IsLeftToRight() bool {
return p.Direction() == LeftToRight
}
// Direction returns the direction of the text of this paragraph.
//
// The direction may be LeftToRight, RightToLeft, Mixed, or Neutral.
func (p *Paragraph) Direction() Direction {
return p.o.Direction()
}
// TODO: what happens if the position is > len(input)? This should return an error.
// RunAt reports the Run at the given position of the input text.
//
// This method can be used for computing line breaks on paragraphs.
func (p *Paragraph) RunAt(pos int) Run {
c := 0
runNumber := 0
for i, r := range p.o.runes {
c += len(r)
if pos < c {
runNumber = i
}
}
return p.o.Run(runNumber)
}
func calculateOrdering(levels []level, runes []rune) Ordering {
var curDir Direction
prevDir := Neutral
prevI := 0
o := Ordering{}
// lvl = 0,2,4,...: left to right
// lvl = 1,3,5,...: right to left
for i, lvl := range levels {
if lvl%2 == 0 {
curDir = LeftToRight
} else {
curDir = RightToLeft
}
if curDir != prevDir {
if i > 0 {
o.runes = append(o.runes, runes[prevI:i])
o.directions = append(o.directions, prevDir)
o.startpos = append(o.startpos, prevI)
}
prevI = i
prevDir = curDir
}
}
o.runes = append(o.runes, runes[prevI:])
o.directions = append(o.directions, prevDir)
o.startpos = append(o.startpos, prevI)
return o
}
// Order computes the visual ordering of all the runs in a Paragraph.
func (p *Paragraph) Order() (Ordering, error) {
if len(p.types) == 0 {
return Ordering{}, nil
}
for _, fn := range p.opts {
fn(&p.options)
}
lvl := level(-1)
if p.options.defaultDirection == RightToLeft {
lvl = 1
}
para, err := newParagraph(p.types, p.pairTypes, p.pairValues, lvl)
if err != nil {
return Ordering{}, err
}
levels := para.getLevels([]int{len(p.types)})
p.o = calculateOrdering(levels, p.runes)
return p.o, nil
}
// Line computes the visual ordering of runs for a single line starting and
// ending at the given positions in the original text.
func (p *Paragraph) Line(start, end int) (Ordering, error) {
lineTypes := p.types[start:end]
para, err := newParagraph(lineTypes, p.pairTypes[start:end], p.pairValues[start:end], -1)
if err != nil {
return Ordering{}, err
}
levels := para.getLevels([]int{len(lineTypes)})
o := calculateOrdering(levels, p.runes[start:end])
return o, nil
}
// An Ordering holds the computed visual order of runs of a Paragraph. Calling
// SetBytes or SetString on the originating Paragraph invalidates an Ordering.
// The methods of an Ordering should only be called by one goroutine at a time.
type Ordering struct {
runes [][]rune
directions []Direction
startpos []int
}
// Direction reports the directionality of the runs.
//
// The direction may be LeftToRight, RightToLeft, Mixed, or Neutral.
func (o *Ordering) Direction() Direction {
return o.directions[0]
}
// NumRuns returns the number of runs.
func (o *Ordering) NumRuns() int {
return len(o.runes)
}
// Run returns the ith run within the ordering.
func (o *Ordering) Run(i int) Run {
r := Run{
runes: o.runes[i],
direction: o.directions[i],
startpos: o.startpos[i],
}
return r
}
// TODO: perhaps with options.
// // Reorder creates a reader that reads the runes in visual order per character.
// // Modifiers remain after the runes they modify.
// func (l *Runs) Reorder() io.Reader {
// panic("unimplemented")
// }
// A Run is a continuous sequence of characters of a single direction.
type Run struct {
runes []rune
direction Direction
startpos int
}
// String returns the text of the run in its original order.
func (r *Run) String() string {
return string(r.runes)
}
// Bytes returns the text of the run in its original order.
func (r *Run) Bytes() []byte {
return []byte(r.String())
}
// TODO: methods for
// - Display order
// - headers and footers
// - bracket replacement.
// Direction reports the direction of the run.
func (r *Run) Direction() Direction {
return r.direction
}
// Pos returns the position of the Run within the text passed to SetBytes or SetString of the
// originating Paragraph value.
func (r *Run) Pos() (start, end int) {
return r.startpos, r.startpos + len(r.runes) - 1
}
// AppendReverse reverses the order of characters of in, appends them to out,
// and returns the result. Modifiers will still follow the runes they modify.
// Brackets are replaced with their counterparts.
func AppendReverse(out, in []byte) []byte {
ret := make([]byte, len(in)+len(out))
copy(ret, out)
inRunes := bytes.Runes(in)
for i, r := range inRunes {
prop, _ := LookupRune(r)
if prop.IsBracket() {
inRunes[i] = prop.reverseBracket(r)
}
}
for i, j := 0, len(inRunes)-1; i < j; i, j = i+1, j-1 {
inRunes[i], inRunes[j] = inRunes[j], inRunes[i]
}
copy(ret[len(out):], string(inRunes))
return ret
}
// ReverseString reverses the order of characters in s and returns a new string.
// Modifiers will still follow the runes they modify. Brackets are replaced with
// their counterparts.
func ReverseString(s string) string {
input := []rune(s)
li := len(input)
ret := make([]rune, li)
for i, r := range input {
prop, _ := LookupRune(r)
if prop.IsBracket() {
ret[li-i-1] = prop.reverseBracket(r)
} else {
ret[li-i-1] = r
}
}
return string(ret)
}
// 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.
package bidi
import (
"container/list"
"fmt"
"sort"
)
// This file contains a port of the reference implementation of the
// Bidi Parentheses Algorithm:
// https://www.unicode.org/Public/PROGRAMS/BidiReferenceJava/BidiPBAReference.java
//
// The implementation in this file covers definitions BD14-BD16 and rule N0
// of UAX#9.
//
// Some preprocessing is done for each rune before data is passed to this
// algorithm:
// - opening and closing brackets are identified
// - a bracket pair type, like '(' and ')' is assigned a unique identifier that
// is identical for the opening and closing bracket. It is left to do these
// mappings.
// - The BPA algorithm requires that bracket characters that are canonical
// equivalents of each other be able to be substituted for each other.
// It is the responsibility of the caller to do this canonicalization.
//
// In implementing BD16, this implementation departs slightly from the "logical"
// algorithm defined in UAX#9. In particular, the stack referenced there
// supports operations that go beyond a "basic" stack. An equivalent
// implementation based on a linked list is used here.
// Bidi_Paired_Bracket_Type
// BD14. An opening paired bracket is a character whose
// Bidi_Paired_Bracket_Type property value is Open.
//
// BD15. A closing paired bracket is a character whose
// Bidi_Paired_Bracket_Type property value is Close.
type bracketType byte
const (
bpNone bracketType = iota
bpOpen
bpClose
)
// bracketPair holds a pair of index values for opening and closing bracket
// location of a bracket pair.
type bracketPair struct {
opener int
closer int
}
func (b *bracketPair) String() string {
return fmt.Sprintf("(%v, %v)", b.opener, b.closer)
}
// bracketPairs is a slice of bracketPairs with a sort.Interface implementation.
type bracketPairs []bracketPair
func (b bracketPairs) Len() int { return len(b) }
func (b bracketPairs) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
func (b bracketPairs) Less(i, j int) bool { return b[i].opener < b[j].opener }
// resolvePairedBrackets runs the paired bracket part of the UBA algorithm.
//
// For each rune, it takes the indexes into the original string, the class the
// bracket type (in pairTypes) and the bracket identifier (pairValues). It also
// takes the direction type for the start-of-sentence and the embedding level.
//
// The identifiers for bracket types are the rune of the canonicalized opening
// bracket for brackets (open or close) or 0 for runes that are not brackets.
func resolvePairedBrackets(s *isolatingRunSequence) {
p := bracketPairer{
sos: s.sos,
openers: list.New(),
codesIsolatedRun: s.types,
indexes: s.indexes,
}
dirEmbed := L
if s.level&1 != 0 {
dirEmbed = R
}
p.locateBrackets(s.p.pairTypes, s.p.pairValues)
p.resolveBrackets(dirEmbed, s.p.initialTypes)
}
type bracketPairer struct {
sos Class // direction corresponding to start of sequence
// The following is a restatement of BD 16 using non-algorithmic language.
//
// A bracket pair is a pair of characters consisting of an opening
// paired bracket and a closing paired bracket such that the
// Bidi_Paired_Bracket property value of the former equals the latter,
// subject to the following constraints.
// - both characters of a pair occur in the same isolating run sequence
// - the closing character of a pair follows the opening character
// - any bracket character can belong at most to one pair, the earliest possible one
// - any bracket character not part of a pair is treated like an ordinary character
// - pairs may nest properly, but their spans may not overlap otherwise
// Bracket characters with canonical decompositions are supposed to be
// treated as if they had been normalized, to allow normalized and non-
// normalized text to give the same result. In this implementation that step
// is pushed out to the caller. The caller has to ensure that the pairValue
// slices contain the rune of the opening bracket after normalization for
// any opening or closing bracket.
openers *list.List // list of positions for opening brackets
// bracket pair positions sorted by location of opening bracket
pairPositions bracketPairs
codesIsolatedRun []Class // directional bidi codes for an isolated run
indexes []int // array of index values into the original string
}
// matchOpener reports whether characters at given positions form a matching
// bracket pair.
func (p *bracketPairer) matchOpener(pairValues []rune, opener, closer int) bool {
return pairValues[p.indexes[opener]] == pairValues[p.indexes[closer]]
}
const maxPairingDepth = 63
// locateBrackets locates matching bracket pairs according to BD16.
//
// This implementation uses a linked list instead of a stack, because, while
// elements are added at the front (like a push) they are not generally removed
// in atomic 'pop' operations, reducing the benefit of the stack archetype.
func (p *bracketPairer) locateBrackets(pairTypes []bracketType, pairValues []rune) {
// traverse the run
// do that explicitly (not in a for-each) so we can record position
for i, index := range p.indexes {
// look at the bracket type for each character
if pairTypes[index] == bpNone || p.codesIsolatedRun[i] != ON {
// continue scanning
continue
}
switch pairTypes[index] {
case bpOpen:
// check if maximum pairing depth reached
if p.openers.Len() == maxPairingDepth {
p.openers.Init()
return
}
// remember opener location, most recent first
p.openers.PushFront(i)
case bpClose:
// see if there is a match
count := 0
for elem := p.openers.Front(); elem != nil; elem = elem.Next() {
count++
opener := elem.Value.(int)
if p.matchOpener(pairValues, opener, i) {
// if the opener matches, add nested pair to the ordered list
p.pairPositions = append(p.pairPositions, bracketPair{opener, i})
// remove up to and including matched opener
for ; count > 0; count-- {
p.openers.Remove(p.openers.Front())
}
break
}
}
sort.Sort(p.pairPositions)
// if we get here, the closing bracket matched no openers
// and gets ignored
}
}
}
// Bracket pairs within an isolating run sequence are processed as units so
// that both the opening and the closing paired bracket in a pair resolve to
// the same direction.
//
// N0. Process bracket pairs in an isolating run sequence sequentially in
// the logical order of the text positions of the opening paired brackets
// using the logic given below. Within this scope, bidirectional types EN
// and AN are treated as R.
//
// Identify the bracket pairs in the current isolating run sequence
// according to BD16. For each bracket-pair element in the list of pairs of
// text positions:
//
// a Inspect the bidirectional types of the characters enclosed within the
// bracket pair.
//
// b If any strong type (either L or R) matching the embedding direction is
// found, set the type for both brackets in the pair to match the embedding
// direction.
//
// o [ e ] o -> o e e e o
//
// o [ o e ] -> o e o e e
//
// o [ NI e ] -> o e NI e e
//
// c Otherwise, if a strong type (opposite the embedding direction) is
// found, test for adjacent strong types as follows: 1 First, check
// backwards before the opening paired bracket until the first strong type
// (L, R, or sos) is found. If that first preceding strong type is opposite
// the embedding direction, then set the type for both brackets in the pair
// to that type. 2 Otherwise, set the type for both brackets in the pair to
// the embedding direction.
//
// o [ o ] e -> o o o o e
//
// o [ o NI ] o -> o o o NI o o
//
// e [ o ] o -> e e o e o
//
// e [ o ] e -> e e o e e
//
// e ( o [ o ] NI ) e -> e e o o o o NI e e
//
// d Otherwise, do not set the type for the current bracket pair. Note that
// if the enclosed text contains no strong types the paired brackets will
// both resolve to the same level when resolved individually using rules N1
// and N2.
//
// e ( NI ) o -> e ( NI ) o
// getStrongTypeN0 maps character's directional code to strong type as required
// by rule N0.
//
// TODO: have separate type for "strong" directionality.
func (p *bracketPairer) getStrongTypeN0(index int) Class {
switch p.codesIsolatedRun[index] {
// in the scope of N0, number types are treated as R
case EN, AN, AL, R:
return R
case L:
return L
default:
return ON
}
}
// classifyPairContent reports the strong types contained inside a Bracket Pair,
// assuming the given embedding direction.
//
// It returns ON if no strong type is found. If a single strong type is found,
// it returns this type. Otherwise it returns the embedding direction.
//
// TODO: use separate type for "strong" directionality.
func (p *bracketPairer) classifyPairContent(loc bracketPair, dirEmbed Class) Class {
dirOpposite := ON
for i := loc.opener + 1; i < loc.closer; i++ {
dir := p.getStrongTypeN0(i)
if dir == ON {
continue
}
if dir == dirEmbed {
return dir // type matching embedding direction found
}
dirOpposite = dir
}
// return ON if no strong type found, or class opposite to dirEmbed
return dirOpposite
}
// classBeforePair determines which strong types are present before a Bracket
// Pair. Return R or L if strong type found, otherwise ON.
func (p *bracketPairer) classBeforePair(loc bracketPair) Class {
for i := loc.opener - 1; i >= 0; i-- {
if dir := p.getStrongTypeN0(i); dir != ON {
return dir
}
}
// no strong types found, return sos
return p.sos
}
// assignBracketType implements rule N0 for a single bracket pair.
func (p *bracketPairer) assignBracketType(loc bracketPair, dirEmbed Class, initialTypes []Class) {
// rule "N0, a", inspect contents of pair
dirPair := p.classifyPairContent(loc, dirEmbed)
// dirPair is now L, R, or N (no strong type found)
// the following logical tests are performed out of order compared to
// the statement of the rules but yield the same results
if dirPair == ON {
return // case "d" - nothing to do
}
if dirPair != dirEmbed {
// case "c": strong type found, opposite - check before (c.1)
dirPair = p.classBeforePair(loc)
if dirPair == dirEmbed || dirPair == ON {
// no strong opposite type found before - use embedding (c.2)
dirPair = dirEmbed
}
}
// else: case "b", strong type found matching embedding,
// no explicit action needed, as dirPair is already set to embedding
// direction
// set the bracket types to the type found
p.setBracketsToType(loc, dirPair, initialTypes)
}
func (p *bracketPairer) setBracketsToType(loc bracketPair, dirPair Class, initialTypes []Class) {
p.codesIsolatedRun[loc.opener] = dirPair
p.codesIsolatedRun[loc.closer] = dirPair
for i := loc.opener + 1; i < loc.closer; i++ {
index := p.indexes[i]
if initialTypes[index] != NSM {
break
}
p.codesIsolatedRun[i] = dirPair
}
for i := loc.closer + 1; i < len(p.indexes); i++ {
index := p.indexes[i]
if initialTypes[index] != NSM {
break
}
p.codesIsolatedRun[i] = dirPair
}
}
// resolveBrackets implements rule N0 for a list of pairs.
func (p *bracketPairer) resolveBrackets(dirEmbed Class, initialTypes []Class) {
for _, loc := range p.pairPositions {
p.assignBracketType(loc, dirEmbed, initialTypes)
}
}
// 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.
package bidi
import (
"fmt"
"log"
)
// This implementation is a port based on the reference implementation found at:
// https://www.unicode.org/Public/PROGRAMS/BidiReferenceJava/
//
// described in Unicode Bidirectional Algorithm (UAX #9).
//
// Input:
// There are two levels of input to the algorithm, since clients may prefer to
// supply some information from out-of-band sources rather than relying on the
// default behavior.
//
// - Bidi class array
// - Bidi class array, with externally supplied base line direction
//
// Output:
// Output is separated into several stages:
//
// - levels array over entire paragraph
// - reordering array over entire paragraph
// - levels array over line
// - reordering array over line
//
// Note that for conformance to the Unicode Bidirectional Algorithm,
// implementations are only required to generate correct reordering and
// character directionality (odd or even levels) over a line. Generating
// identical level arrays over a line is not required. Bidi explicit format
// codes (LRE, RLE, LRO, RLO, PDF) and BN can be assigned arbitrary levels and
// positions as long as the rest of the input is properly reordered.
//
// As the algorithm is defined to operate on a single paragraph at a time, this
// implementation is written to handle single paragraphs. Thus rule P1 is
// presumed by this implementation-- the data provided to the implementation is
// assumed to be a single paragraph, and either contains no 'B' codes, or a
// single 'B' code at the end of the input. 'B' is allowed as input to
// illustrate how the algorithm assigns it a level.
//
// Also note that rules L3 and L4 depend on the rendering engine that uses the
// result of the bidi algorithm. This implementation assumes that the rendering
// engine expects combining marks in visual order (e.g. to the left of their
// base character in RTL runs) and that it adjusts the glyphs used to render
// mirrored characters that are in RTL runs so that they render appropriately.
// level is the embedding level of a character. Even embedding levels indicate
// left-to-right order and odd levels indicate right-to-left order. The special
// level of -1 is reserved for undefined order.
type level int8
const implicitLevel level = -1
// in returns if x is equal to any of the values in set.
func (c Class) in(set ...Class) bool {
for _, s := range set {
if c == s {
return true
}
}
return false
}
// A paragraph contains the state of a paragraph.
type paragraph struct {
initialTypes []Class
// Arrays of properties needed for paired bracket evaluation in N0
pairTypes []bracketType // paired Bracket types for paragraph
pairValues []rune // rune for opening bracket or pbOpen and pbClose; 0 for pbNone
embeddingLevel level // default: = implicitLevel;
// at the paragraph levels
resultTypes []Class
resultLevels []level
// Index of matching PDI for isolate initiator characters. For other
// characters, the value of matchingPDI will be set to -1. For isolate
// initiators with no matching PDI, matchingPDI will be set to the length of
// the input string.
matchingPDI []int
// Index of matching isolate initiator for PDI characters. For other
// characters, and for PDIs with no matching isolate initiator, the value of
// matchingIsolateInitiator will be set to -1.
matchingIsolateInitiator []int
}
// newParagraph initializes a paragraph. The user needs to supply a few arrays
// corresponding to the preprocessed text input. The types correspond to the
// Unicode BiDi classes for each rune. pairTypes indicates the bracket type for
// each rune. pairValues provides a unique bracket class identifier for each
// rune (suggested is the rune of the open bracket for opening and matching
// close brackets, after normalization). The embedding levels are optional, but
// may be supplied to encode embedding levels of styled text.
func newParagraph(types []Class, pairTypes []bracketType, pairValues []rune, levels level) (*paragraph, error) {
var err error
if err = validateTypes(types); err != nil {
return nil, err
}
if err = validatePbTypes(pairTypes); err != nil {
return nil, err
}
if err = validatePbValues(pairValues, pairTypes); err != nil {
return nil, err
}
if err = validateParagraphEmbeddingLevel(levels); err != nil {
return nil, err
}
p := ¶graph{
initialTypes: append([]Class(nil), types...),
embeddingLevel: levels,
pairTypes: pairTypes,
pairValues: pairValues,
resultTypes: append([]Class(nil), types...),
}
p.run()
return p, nil
}
func (p *paragraph) Len() int { return len(p.initialTypes) }
// The algorithm. Does not include line-based processing (Rules L1, L2).
// These are applied later in the line-based phase of the algorithm.
func (p *paragraph) run() {
p.determineMatchingIsolates()
// 1) determining the paragraph level
// Rule P1 is the requirement for entering this algorithm.
// Rules P2, P3.
// If no externally supplied paragraph embedding level, use default.
if p.embeddingLevel == implicitLevel {
p.embeddingLevel = p.determineParagraphEmbeddingLevel(0, p.Len())
}
// Initialize result levels to paragraph embedding level.
p.resultLevels = make([]level, p.Len())
setLevels(p.resultLevels, p.embeddingLevel)
// 2) Explicit levels and directions
// Rules X1-X8.
p.determineExplicitEmbeddingLevels()
// Rule X9.
// We do not remove the embeddings, the overrides, the PDFs, and the BNs
// from the string explicitly. But they are not copied into isolating run
// sequences when they are created, so they are removed for all
// practical purposes.
// Rule X10.
// Run remainder of algorithm one isolating run sequence at a time
for _, seq := range p.determineIsolatingRunSequences() {
// 3) resolving weak types
// Rules W1-W7.
seq.resolveWeakTypes()
// 4a) resolving paired brackets
// Rule N0
resolvePairedBrackets(seq)
// 4b) resolving neutral types
// Rules N1-N3.
seq.resolveNeutralTypes()
// 5) resolving implicit embedding levels
// Rules I1, I2.
seq.resolveImplicitLevels()
// Apply the computed levels and types
seq.applyLevelsAndTypes()
}
// Assign appropriate levels to 'hide' LREs, RLEs, LROs, RLOs, PDFs, and
// BNs. This is for convenience, so the resulting level array will have
// a value for every character.
p.assignLevelsToCharactersRemovedByX9()
}
// determineMatchingIsolates determines the matching PDI for each isolate
// initiator and vice versa.
//
// Definition BD9.
//
// At the end of this function:
//
// - The member variable matchingPDI is set to point to the index of the
// matching PDI character for each isolate initiator character. If there is
// no matching PDI, it is set to the length of the input text. For other
// characters, it is set to -1.
// - The member variable matchingIsolateInitiator is set to point to the
// index of the matching isolate initiator character for each PDI character.
// If there is no matching isolate initiator, or the character is not a PDI,
// it is set to -1.
func (p *paragraph) determineMatchingIsolates() {
p.matchingPDI = make([]int, p.Len())
p.matchingIsolateInitiator = make([]int, p.Len())
for i := range p.matchingIsolateInitiator {
p.matchingIsolateInitiator[i] = -1
}
for i := range p.matchingPDI {
p.matchingPDI[i] = -1
if t := p.resultTypes[i]; t.in(LRI, RLI, FSI) {
depthCounter := 1
for j := i + 1; j < p.Len(); j++ {
if u := p.resultTypes[j]; u.in(LRI, RLI, FSI) {
depthCounter++
} else if u == PDI {
if depthCounter--; depthCounter == 0 {
p.matchingPDI[i] = j
p.matchingIsolateInitiator[j] = i
break
}
}
}
if p.matchingPDI[i] == -1 {
p.matchingPDI[i] = p.Len()
}
}
}
}
// determineParagraphEmbeddingLevel reports the resolved paragraph direction of
// the substring limited by the given range [start, end).
//
// Determines the paragraph level based on rules P2, P3. This is also used
// in rule X5c to find if an FSI should resolve to LRI or RLI.
func (p *paragraph) determineParagraphEmbeddingLevel(start, end int) level {
var strongType Class = unknownClass
// Rule P2.
for i := start; i < end; i++ {
if t := p.resultTypes[i]; t.in(L, AL, R) {
strongType = t
break
} else if t.in(FSI, LRI, RLI) {
i = p.matchingPDI[i] // skip over to the matching PDI
if i > end {
log.Panic("assert (i <= end)")
}
}
}
// Rule P3.
switch strongType {
case unknownClass: // none found
// default embedding level when no strong types found is 0.
return 0
case L:
return 0
default: // AL, R
return 1
}
}
const maxDepth = 125
// This stack will store the embedding levels and override and isolated
// statuses
type directionalStatusStack struct {
stackCounter int
embeddingLevelStack [maxDepth + 1]level
overrideStatusStack [maxDepth + 1]Class
isolateStatusStack [maxDepth + 1]bool
}
func (s *directionalStatusStack) empty() { s.stackCounter = 0 }
func (s *directionalStatusStack) pop() { s.stackCounter-- }
func (s *directionalStatusStack) depth() int { return s.stackCounter }
func (s *directionalStatusStack) push(level level, overrideStatus Class, isolateStatus bool) {
s.embeddingLevelStack[s.stackCounter] = level
s.overrideStatusStack[s.stackCounter] = overrideStatus
s.isolateStatusStack[s.stackCounter] = isolateStatus
s.stackCounter++
}
func (s *directionalStatusStack) lastEmbeddingLevel() level {
return s.embeddingLevelStack[s.stackCounter-1]
}
func (s *directionalStatusStack) lastDirectionalOverrideStatus() Class {
return s.overrideStatusStack[s.stackCounter-1]
}
func (s *directionalStatusStack) lastDirectionalIsolateStatus() bool {
return s.isolateStatusStack[s.stackCounter-1]
}
// Determine explicit levels using rules X1 - X8
func (p *paragraph) determineExplicitEmbeddingLevels() {
var stack directionalStatusStack
var overflowIsolateCount, overflowEmbeddingCount, validIsolateCount int
// Rule X1.
stack.push(p.embeddingLevel, ON, false)
for i, t := range p.resultTypes {
// Rules X2, X3, X4, X5, X5a, X5b, X5c
switch t {
case RLE, LRE, RLO, LRO, RLI, LRI, FSI:
isIsolate := t.in(RLI, LRI, FSI)
isRTL := t.in(RLE, RLO, RLI)
// override if this is an FSI that resolves to RLI
if t == FSI {
isRTL = (p.determineParagraphEmbeddingLevel(i+1, p.matchingPDI[i]) == 1)
}
if isIsolate {
p.resultLevels[i] = stack.lastEmbeddingLevel()
if stack.lastDirectionalOverrideStatus() != ON {
p.resultTypes[i] = stack.lastDirectionalOverrideStatus()
}
}
var newLevel level
if isRTL {
// least greater odd
newLevel = (stack.lastEmbeddingLevel() + 1) | 1
} else {
// least greater even
newLevel = (stack.lastEmbeddingLevel() + 2) &^ 1
}
if newLevel <= maxDepth && overflowIsolateCount == 0 && overflowEmbeddingCount == 0 {
if isIsolate {
validIsolateCount++
}
// Push new embedding level, override status, and isolated
// status.
// No check for valid stack counter, since the level check
// suffices.
switch t {
case LRO:
stack.push(newLevel, L, isIsolate)
case RLO:
stack.push(newLevel, R, isIsolate)
default:
stack.push(newLevel, ON, isIsolate)
}
// Not really part of the spec
if !isIsolate {
p.resultLevels[i] = newLevel
}
} else {
// This is an invalid explicit formatting character,
// so apply the "Otherwise" part of rules X2-X5b.
if isIsolate {
overflowIsolateCount++
} else { // !isIsolate
if overflowIsolateCount == 0 {
overflowEmbeddingCount++
}
}
}
// Rule X6a
case PDI:
if overflowIsolateCount > 0 {
overflowIsolateCount--
} else if validIsolateCount == 0 {
// do nothing
} else {
overflowEmbeddingCount = 0
for !stack.lastDirectionalIsolateStatus() {
stack.pop()
}
stack.pop()
validIsolateCount--
}
p.resultLevels[i] = stack.lastEmbeddingLevel()
// Rule X7
case PDF:
// Not really part of the spec
p.resultLevels[i] = stack.lastEmbeddingLevel()
if overflowIsolateCount > 0 {
// do nothing
} else if overflowEmbeddingCount > 0 {
overflowEmbeddingCount--
} else if !stack.lastDirectionalIsolateStatus() && stack.depth() >= 2 {
stack.pop()
}
case B: // paragraph separator.
// Rule X8.
// These values are reset for clarity, in this implementation B
// can only occur as the last code in the array.
stack.empty()
overflowIsolateCount = 0
overflowEmbeddingCount = 0
validIsolateCount = 0
p.resultLevels[i] = p.embeddingLevel
default:
p.resultLevels[i] = stack.lastEmbeddingLevel()
if stack.lastDirectionalOverrideStatus() != ON {
p.resultTypes[i] = stack.lastDirectionalOverrideStatus()
}
}
}
}
type isolatingRunSequence struct {
p *paragraph
indexes []int // indexes to the original string
types []Class // type of each character using the index
resolvedLevels []level // resolved levels after application of rules
level level
sos, eos Class
}
func (i *isolatingRunSequence) Len() int { return len(i.indexes) }
// Rule X10, second bullet: Determine the start-of-sequence (sos) and end-of-sequence (eos) types,
// either L or R, for each isolating run sequence.
func (p *paragraph) isolatingRunSequence(indexes []int) *isolatingRunSequence {
length := len(indexes)
types := make([]Class, length)
for i, x := range indexes {
types[i] = p.resultTypes[x]
}
// assign level, sos and eos
prevChar := indexes[0] - 1
for prevChar >= 0 && isRemovedByX9(p.initialTypes[prevChar]) {
prevChar--
}
prevLevel := p.embeddingLevel
if prevChar >= 0 {
prevLevel = p.resultLevels[prevChar]
}
var succLevel level
lastType := types[length-1]
if lastType.in(LRI, RLI, FSI) {
succLevel = p.embeddingLevel
} else {
// the first character after the end of run sequence
limit := indexes[length-1] + 1
for ; limit < p.Len() && isRemovedByX9(p.initialTypes[limit]); limit++ {
}
succLevel = p.embeddingLevel
if limit < p.Len() {
succLevel = p.resultLevels[limit]
}
}
level := p.resultLevels[indexes[0]]
return &isolatingRunSequence{
p: p,
indexes: indexes,
types: types,
level: level,
sos: typeForLevel(max(prevLevel, level)),
eos: typeForLevel(max(succLevel, level)),
}
}
// Resolving weak types Rules W1-W7.
//
// Note that some weak types (EN, AN) remain after this processing is
// complete.
func (s *isolatingRunSequence) resolveWeakTypes() {
// on entry, only these types remain
s.assertOnly(L, R, AL, EN, ES, ET, AN, CS, B, S, WS, ON, NSM, LRI, RLI, FSI, PDI)
// Rule W1.
// Changes all NSMs.
precedingCharacterType := s.sos
for i, t := range s.types {
if t == NSM {
s.types[i] = precedingCharacterType
} else {
// if t.in(LRI, RLI, FSI, PDI) {
// precedingCharacterType = ON
// }
precedingCharacterType = t
}
}
// Rule W2.
// EN does not change at the start of the run, because sos != AL.
for i, t := range s.types {
if t == EN {
for j := i - 1; j >= 0; j-- {
if t := s.types[j]; t.in(L, R, AL) {
if t == AL {
s.types[i] = AN
}
break
}
}
}
}
// Rule W3.
for i, t := range s.types {
if t == AL {
s.types[i] = R
}
}
// Rule W4.
// Since there must be values on both sides for this rule to have an
// effect, the scan skips the first and last value.
//
// Although the scan proceeds left to right, and changes the type
// values in a way that would appear to affect the computations
// later in the scan, there is actually no problem. A change in the
// current value can only affect the value to its immediate right,
// and only affect it if it is ES or CS. But the current value can
// only change if the value to its right is not ES or CS. Thus
// either the current value will not change, or its change will have
// no effect on the remainder of the analysis.
for i := 1; i < s.Len()-1; i++ {
t := s.types[i]
if t == ES || t == CS {
prevSepType := s.types[i-1]
succSepType := s.types[i+1]
if prevSepType == EN && succSepType == EN {
s.types[i] = EN
} else if s.types[i] == CS && prevSepType == AN && succSepType == AN {
s.types[i] = AN
}
}
}
// Rule W5.
for i, t := range s.types {
if t == ET {
// locate end of sequence
runStart := i
runEnd := s.findRunLimit(runStart, ET)
// check values at ends of sequence
t := s.sos
if runStart > 0 {
t = s.types[runStart-1]
}
if t != EN {
t = s.eos
if runEnd < len(s.types) {
t = s.types[runEnd]
}
}
if t == EN {
setTypes(s.types[runStart:runEnd], EN)
}
// continue at end of sequence
i = runEnd
}
}
// Rule W6.
for i, t := range s.types {
if t.in(ES, ET, CS) {
s.types[i] = ON
}
}
// Rule W7.
for i, t := range s.types {
if t == EN {
// set default if we reach start of run
prevStrongType := s.sos
for j := i - 1; j >= 0; j-- {
t = s.types[j]
if t == L || t == R { // AL's have been changed to R
prevStrongType = t
break
}
}
if prevStrongType == L {
s.types[i] = L
}
}
}
}
// 6) resolving neutral types Rules N1-N2.
func (s *isolatingRunSequence) resolveNeutralTypes() {
// on entry, only these types can be in resultTypes
s.assertOnly(L, R, EN, AN, B, S, WS, ON, RLI, LRI, FSI, PDI)
for i, t := range s.types {
switch t {
case WS, ON, B, S, RLI, LRI, FSI, PDI:
// find bounds of run of neutrals
runStart := i
runEnd := s.findRunLimit(runStart, B, S, WS, ON, RLI, LRI, FSI, PDI)
// determine effective types at ends of run
var leadType, trailType Class
// Note that the character found can only be L, R, AN, or
// EN.
if runStart == 0 {
leadType = s.sos
} else {
leadType = s.types[runStart-1]
if leadType.in(AN, EN) {
leadType = R
}
}
if runEnd == len(s.types) {
trailType = s.eos
} else {
trailType = s.types[runEnd]
if trailType.in(AN, EN) {
trailType = R
}
}
var resolvedType Class
if leadType == trailType {
// Rule N1.
resolvedType = leadType
} else {
// Rule N2.
// Notice the embedding level of the run is used, not
// the paragraph embedding level.
resolvedType = typeForLevel(s.level)
}
setTypes(s.types[runStart:runEnd], resolvedType)
// skip over run of (former) neutrals
i = runEnd
}
}
}
func setLevels(levels []level, newLevel level) {
for i := range levels {
levels[i] = newLevel
}
}
func setTypes(types []Class, newType Class) {
for i := range types {
types[i] = newType
}
}
// 7) resolving implicit embedding levels Rules I1, I2.
func (s *isolatingRunSequence) resolveImplicitLevels() {
// on entry, only these types can be in resultTypes
s.assertOnly(L, R, EN, AN)
s.resolvedLevels = make([]level, len(s.types))
setLevels(s.resolvedLevels, s.level)
if (s.level & 1) == 0 { // even level
for i, t := range s.types {
// Rule I1.
if t == L {
// no change
} else if t == R {
s.resolvedLevels[i] += 1
} else { // t == AN || t == EN
s.resolvedLevels[i] += 2
}
}
} else { // odd level
for i, t := range s.types {
// Rule I2.
if t == R {
// no change
} else { // t == L || t == AN || t == EN
s.resolvedLevels[i] += 1
}
}
}
}
// Applies the levels and types resolved in rules W1-I2 to the
// resultLevels array.
func (s *isolatingRunSequence) applyLevelsAndTypes() {
for i, x := range s.indexes {
s.p.resultTypes[x] = s.types[i]
s.p.resultLevels[x] = s.resolvedLevels[i]
}
}
// Return the limit of the run consisting only of the types in validSet
// starting at index. This checks the value at index, and will return
// index if that value is not in validSet.
func (s *isolatingRunSequence) findRunLimit(index int, validSet ...Class) int {
loop:
for ; index < len(s.types); index++ {
t := s.types[index]
for _, valid := range validSet {
if t == valid {
continue loop
}
}
return index // didn't find a match in validSet
}
return len(s.types)
}
// Algorithm validation. Assert that all values in types are in the
// provided set.
func (s *isolatingRunSequence) assertOnly(codes ...Class) {
loop:
for i, t := range s.types {
for _, c := range codes {
if t == c {
continue loop
}
}
log.Panicf("invalid bidi code %v present in assertOnly at position %d", t, s.indexes[i])
}
}
// determineLevelRuns returns an array of level runs. Each level run is
// described as an array of indexes into the input string.
//
// Determines the level runs. Rule X9 will be applied in determining the
// runs, in the way that makes sure the characters that are supposed to be
// removed are not included in the runs.
func (p *paragraph) determineLevelRuns() [][]int {
run := []int{}
allRuns := [][]int{}
currentLevel := implicitLevel
for i := range p.initialTypes {
if !isRemovedByX9(p.initialTypes[i]) {
if p.resultLevels[i] != currentLevel {
// we just encountered a new run; wrap up last run
if currentLevel >= 0 { // only wrap it up if there was a run
allRuns = append(allRuns, run)
run = nil
}
// Start new run
currentLevel = p.resultLevels[i]
}
run = append(run, i)
}
}
// Wrap up the final run, if any
if len(run) > 0 {
allRuns = append(allRuns, run)
}
return allRuns
}
// Definition BD13. Determine isolating run sequences.
func (p *paragraph) determineIsolatingRunSequences() []*isolatingRunSequence {
levelRuns := p.determineLevelRuns()
// Compute the run that each character belongs to
runForCharacter := make([]int, p.Len())
for i, run := range levelRuns {
for _, index := range run {
runForCharacter[index] = i
}
}
sequences := []*isolatingRunSequence{}
var currentRunSequence []int
for _, run := range levelRuns {
first := run[0]
if p.initialTypes[first] != PDI || p.matchingIsolateInitiator[first] == -1 {
currentRunSequence = nil
// int run = i;
for {
// Copy this level run into currentRunSequence
currentRunSequence = append(currentRunSequence, run...)
last := currentRunSequence[len(currentRunSequence)-1]
lastT := p.initialTypes[last]
if lastT.in(LRI, RLI, FSI) && p.matchingPDI[last] != p.Len() {
run = levelRuns[runForCharacter[p.matchingPDI[last]]]
} else {
break
}
}
sequences = append(sequences, p.isolatingRunSequence(currentRunSequence))
}
}
return sequences
}
// Assign level information to characters removed by rule X9. This is for
// ease of relating the level information to the original input data. Note
// that the levels assigned to these codes are arbitrary, they're chosen so
// as to avoid breaking level runs.
func (p *paragraph) assignLevelsToCharactersRemovedByX9() {
for i, t := range p.initialTypes {
if t.in(LRE, RLE, LRO, RLO, PDF, BN) {
p.resultTypes[i] = t
p.resultLevels[i] = -1
}
}
// now propagate forward the levels information (could have
// propagated backward, the main thing is not to introduce a level
// break where one doesn't already exist).
if p.resultLevels[0] == -1 {
p.resultLevels[0] = p.embeddingLevel
}
for i := 1; i < len(p.initialTypes); i++ {
if p.resultLevels[i] == -1 {
p.resultLevels[i] = p.resultLevels[i-1]
}
}
// Embedding information is for informational purposes only so need not be
// adjusted.
}
//
// Output
//
// getLevels computes levels array breaking lines at offsets in linebreaks.
// Rule L1.
//
// The linebreaks array must include at least one value. The values must be
// in strictly increasing order (no duplicates) between 1 and the length of
// the text, inclusive. The last value must be the length of the text.
func (p *paragraph) getLevels(linebreaks []int) []level {
// Note that since the previous processing has removed all
// P, S, and WS values from resultTypes, the values referred to
// in these rules are the initial types, before any processing
// has been applied (including processing of overrides).
//
// This example implementation has reinserted explicit format codes
// and BN, in order that the levels array correspond to the
// initial text. Their final placement is not normative.
// These codes are treated like WS in this implementation,
// so they don't interrupt sequences of WS.
validateLineBreaks(linebreaks, p.Len())
result := append([]level(nil), p.resultLevels...)
// don't worry about linebreaks since if there is a break within
// a series of WS values preceding S, the linebreak itself
// causes the reset.
for i, t := range p.initialTypes {
if t.in(B, S) {
// Rule L1, clauses one and two.
result[i] = p.embeddingLevel
// Rule L1, clause three.
for j := i - 1; j >= 0; j-- {
if isWhitespace(p.initialTypes[j]) { // including format codes
result[j] = p.embeddingLevel
} else {
break
}
}
}
}
// Rule L1, clause four.
start := 0
for _, limit := range linebreaks {
for j := limit - 1; j >= start; j-- {
if isWhitespace(p.initialTypes[j]) { // including format codes
result[j] = p.embeddingLevel
} else {
break
}
}
start = limit
}
return result
}
// getReordering returns the reordering of lines from a visual index to a
// logical index for line breaks at the given offsets.
//
// Lines are concatenated from left to right. So for example, the fifth
// character from the left on the third line is
//
// getReordering(linebreaks)[linebreaks[1] + 4]
//
// (linebreaks[1] is the position after the last character of the second
// line, which is also the index of the first character on the third line,
// and adding four gets the fifth character from the left).
//
// The linebreaks array must include at least one value. The values must be
// in strictly increasing order (no duplicates) between 1 and the length of
// the text, inclusive. The last value must be the length of the text.
func (p *paragraph) getReordering(linebreaks []int) []int {
validateLineBreaks(linebreaks, p.Len())
return computeMultilineReordering(p.getLevels(linebreaks), linebreaks)
}
// Return multiline reordering array for a given level array. Reordering
// does not occur across a line break.
func computeMultilineReordering(levels []level, linebreaks []int) []int {
result := make([]int, len(levels))
start := 0
for _, limit := range linebreaks {
tempLevels := make([]level, limit-start)
copy(tempLevels, levels[start:])
for j, order := range computeReordering(tempLevels) {
result[start+j] = order + start
}
start = limit
}
return result
}
// Return reordering array for a given level array. This reorders a single
// line. The reordering is a visual to logical map. For example, the
// leftmost char is string.charAt(order[0]). Rule L2.
func computeReordering(levels []level) []int {
result := make([]int, len(levels))
// initialize order
for i := range result {
result[i] = i
}
// locate highest level found on line.
// Note the rules say text, but no reordering across line bounds is
// performed, so this is sufficient.
highestLevel := level(0)
lowestOddLevel := level(maxDepth + 2)
for _, level := range levels {
if level > highestLevel {
highestLevel = level
}
if level&1 != 0 && level < lowestOddLevel {
lowestOddLevel = level
}
}
for level := highestLevel; level >= lowestOddLevel; level-- {
for i := 0; i < len(levels); i++ {
if levels[i] >= level {
// find range of text at or above this level
start := i
limit := i + 1
for limit < len(levels) && levels[limit] >= level {
limit++
}
for j, k := start, limit-1; j < k; j, k = j+1, k-1 {
result[j], result[k] = result[k], result[j]
}
// skip to end of level run
i = limit
}
}
}
return result
}
// isWhitespace reports whether the type is considered a whitespace type for the
// line break rules.
func isWhitespace(c Class) bool {
switch c {
case LRE, RLE, LRO, RLO, PDF, LRI, RLI, FSI, PDI, BN, WS:
return true
}
return false
}
// isRemovedByX9 reports whether the type is one of the types removed in X9.
func isRemovedByX9(c Class) bool {
switch c {
case LRE, RLE, LRO, RLO, PDF, BN:
return true
}
return false
}
// typeForLevel reports the strong type (L or R) corresponding to the level.
func typeForLevel(level level) Class {
if (level & 0x1) == 0 {
return L
}
return R
}
func validateTypes(types []Class) error {
if len(types) == 0 {
return fmt.Errorf("types is null")
}
for i, t := range types[:len(types)-1] {
if t == B {
return fmt.Errorf("B type before end of paragraph at index: %d", i)
}
}
return nil
}
func validateParagraphEmbeddingLevel(embeddingLevel level) error {
if embeddingLevel != implicitLevel &&
embeddingLevel != 0 &&
embeddingLevel != 1 {
return fmt.Errorf("illegal paragraph embedding level: %d", embeddingLevel)
}
return nil
}
func validateLineBreaks(linebreaks []int, textLength int) error {
prev := 0
for i, next := range linebreaks {
if next <= prev {
return fmt.Errorf("bad linebreak: %d at index: %d", next, i)
}
prev = next
}
if prev != textLength {
return fmt.Errorf("last linebreak was %d, want %d", prev, textLength)
}
return nil
}
func validatePbTypes(pairTypes []bracketType) error {
if len(pairTypes) == 0 {
return fmt.Errorf("pairTypes is null")
}
for i, pt := range pairTypes {
switch pt {
case bpNone, bpOpen, bpClose:
default:
return fmt.Errorf("illegal pairType value at %d: %v", i, pairTypes[i])
}
}
return nil
}
func validatePbValues(pairValues []rune, pairTypes []bracketType) error {
if pairValues == nil {
return fmt.Errorf("pairValues is null")
}
if len(pairTypes) != len(pairValues) {
return fmt.Errorf("pairTypes is different length from pairValues")
}
return nil
}
// 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.
package bidi
import "unicode/utf8"
// Properties provides access to BiDi properties of runes.
type Properties struct {
entry uint8
last uint8
}
var trie = newBidiTrie(0)
// TODO: using this for bidirule reduces the running time by about 5%. Consider
// if this is worth exposing or if we can find a way to speed up the Class
// method.
//
// // CompactClass is like Class, but maps all of the BiDi control classes
// // (LRO, RLO, LRE, RLE, PDF, LRI, RLI, FSI, PDI) to the class Control.
// func (p Properties) CompactClass() Class {
// return Class(p.entry & 0x0F)
// }
// Class returns the Bidi class for p.
func (p Properties) Class() Class {
c := Class(p.entry & 0x0F)
if c == Control {
c = controlByteToClass[p.last&0xF]
}
return c
}
// IsBracket reports whether the rune is a bracket.
func (p Properties) IsBracket() bool { return p.entry&0xF0 != 0 }
// IsOpeningBracket reports whether the rune is an opening bracket.
// IsBracket must return true.
func (p Properties) IsOpeningBracket() bool { return p.entry&openMask != 0 }
// TODO: find a better API and expose.
func (p Properties) reverseBracket(r rune) rune {
return xorMasks[p.entry>>xorMaskShift] ^ r
}
var controlByteToClass = [16]Class{
0xD: LRO, // U+202D LeftToRightOverride,
0xE: RLO, // U+202E RightToLeftOverride,
0xA: LRE, // U+202A LeftToRightEmbedding,
0xB: RLE, // U+202B RightToLeftEmbedding,
0xC: PDF, // U+202C PopDirectionalFormat,
0x6: LRI, // U+2066 LeftToRightIsolate,
0x7: RLI, // U+2067 RightToLeftIsolate,
0x8: FSI, // U+2068 FirstStrongIsolate,
0x9: PDI, // U+2069 PopDirectionalIsolate,
}
// LookupRune returns properties for r.
func LookupRune(r rune) (p Properties, size int) {
var buf [4]byte
n := utf8.EncodeRune(buf[:], r)
return Lookup(buf[:n])
}
// TODO: these lookup methods are based on the generated trie code. The returned
// sizes have slightly different semantics from the generated code, in that it
// always returns size==1 for an illegal UTF-8 byte (instead of the length
// of the maximum invalid subsequence). Most Transformers, like unicode/norm,
// leave invalid UTF-8 untouched, in which case it has performance benefits to
// do so (without changing the semantics). Bidi requires the semantics used here
// for the bidirule implementation to be compatible with the Go semantics.
// They ultimately should perhaps be adopted by all trie implementations, for
// convenience sake.
// This unrolled code also boosts performance of the secure/bidirule package by
// about 30%.
// So, to remove this code:
// - add option to trie generator to define return type.
// - always return 1 byte size for ill-formed UTF-8 runes.
// Lookup returns properties for the first rune in s and the width in bytes of
// its encoding. The size will be 0 if s does not hold enough bytes to complete
// the encoding.
func Lookup(s []byte) (p Properties, sz int) {
c0 := s[0]
switch {
case c0 < 0x80: // is ASCII
return Properties{entry: bidiValues[c0]}, 1
case c0 < 0xC2:
return Properties{}, 1
case c0 < 0xE0: // 2-byte UTF-8
if len(s) < 2 {
return Properties{}, 0
}
i := bidiIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return Properties{}, 1
}
return Properties{entry: trie.lookupValue(uint32(i), c1)}, 2
case c0 < 0xF0: // 3-byte UTF-8
if len(s) < 3 {
return Properties{}, 0
}
i := bidiIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return Properties{}, 1
}
o := uint32(i)<<6 + uint32(c1)
i = bidiIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return Properties{}, 1
}
return Properties{entry: trie.lookupValue(uint32(i), c2), last: c2}, 3
case c0 < 0xF8: // 4-byte UTF-8
if len(s) < 4 {
return Properties{}, 0
}
i := bidiIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return Properties{}, 1
}
o := uint32(i)<<6 + uint32(c1)
i = bidiIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return Properties{}, 1
}
o = uint32(i)<<6 + uint32(c2)
i = bidiIndex[o]
c3 := s[3]
if c3 < 0x80 || 0xC0 <= c3 {
return Properties{}, 1
}
return Properties{entry: trie.lookupValue(uint32(i), c3)}, 4
}
// Illegal rune
return Properties{}, 1
}
// LookupString returns properties for the first rune in s and the width in
// bytes of its encoding. The size will be 0 if s does not hold enough bytes to
// complete the encoding.
func LookupString(s string) (p Properties, sz int) {
c0 := s[0]
switch {
case c0 < 0x80: // is ASCII
return Properties{entry: bidiValues[c0]}, 1
case c0 < 0xC2:
return Properties{}, 1
case c0 < 0xE0: // 2-byte UTF-8
if len(s) < 2 {
return Properties{}, 0
}
i := bidiIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return Properties{}, 1
}
return Properties{entry: trie.lookupValue(uint32(i), c1)}, 2
case c0 < 0xF0: // 3-byte UTF-8
if len(s) < 3 {
return Properties{}, 0
}
i := bidiIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return Properties{}, 1
}
o := uint32(i)<<6 + uint32(c1)
i = bidiIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return Properties{}, 1
}
return Properties{entry: trie.lookupValue(uint32(i), c2), last: c2}, 3
case c0 < 0xF8: // 4-byte UTF-8
if len(s) < 4 {
return Properties{}, 0
}
i := bidiIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return Properties{}, 1
}
o := uint32(i)<<6 + uint32(c1)
i = bidiIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return Properties{}, 1
}
o = uint32(i)<<6 + uint32(c2)
i = bidiIndex[o]
c3 := s[3]
if c3 < 0x80 || 0xC0 <= c3 {
return Properties{}, 1
}
return Properties{entry: trie.lookupValue(uint32(i), c3)}, 4
}
// Illegal rune
return Properties{}, 1
}
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.21
package bidi
// UnicodeVersion is the Unicode version from which the tables in this package are derived.
const UnicodeVersion = "15.0.0"
// xorMasks contains masks to be xor-ed with brackets to get the reverse
// version.
var xorMasks = []int32{ // 8 elements
0, 1, 6, 7, 3, 15, 29, 63,
} // Size: 56 bytes
// lookup returns the trie value for the first UTF-8 encoding in s and
// the width in bytes of this encoding. The size will be 0 if s does not
// hold enough bytes to complete the encoding. len(s) must be greater than 0.
func (t *bidiTrie) lookup(s []byte) (v uint8, sz int) {
c0 := s[0]
switch {
case c0 < 0x80: // is ASCII
return bidiValues[c0], 1
case c0 < 0xC2:
return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
case c0 < 0xE0: // 2-byte UTF-8
if len(s) < 2 {
return 0, 0
}
i := bidiIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c1), 2
case c0 < 0xF0: // 3-byte UTF-8
if len(s) < 3 {
return 0, 0
}
i := bidiIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = bidiIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c2), 3
case c0 < 0xF8: // 4-byte UTF-8
if len(s) < 4 {
return 0, 0
}
i := bidiIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = bidiIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
o = uint32(i)<<6 + uint32(c2)
i = bidiIndex[o]
c3 := s[3]
if c3 < 0x80 || 0xC0 <= c3 {
return 0, 3 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c3), 4
}
// Illegal rune
return 0, 1
}
// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
// s must start with a full and valid UTF-8 encoded rune.
func (t *bidiTrie) lookupUnsafe(s []byte) uint8 {
c0 := s[0]
if c0 < 0x80 { // is ASCII
return bidiValues[c0]
}
i := bidiIndex[c0]
if c0 < 0xE0 { // 2-byte UTF-8
return t.lookupValue(uint32(i), s[1])
}
i = bidiIndex[uint32(i)<<6+uint32(s[1])]
if c0 < 0xF0 { // 3-byte UTF-8
return t.lookupValue(uint32(i), s[2])
}
i = bidiIndex[uint32(i)<<6+uint32(s[2])]
if c0 < 0xF8 { // 4-byte UTF-8
return t.lookupValue(uint32(i), s[3])
}
return 0
}
// lookupString returns the trie value for the first UTF-8 encoding in s and
// the width in bytes of this encoding. The size will be 0 if s does not
// hold enough bytes to complete the encoding. len(s) must be greater than 0.
func (t *bidiTrie) lookupString(s string) (v uint8, sz int) {
c0 := s[0]
switch {
case c0 < 0x80: // is ASCII
return bidiValues[c0], 1
case c0 < 0xC2:
return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
case c0 < 0xE0: // 2-byte UTF-8
if len(s) < 2 {
return 0, 0
}
i := bidiIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c1), 2
case c0 < 0xF0: // 3-byte UTF-8
if len(s) < 3 {
return 0, 0
}
i := bidiIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = bidiIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c2), 3
case c0 < 0xF8: // 4-byte UTF-8
if len(s) < 4 {
return 0, 0
}
i := bidiIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = bidiIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
o = uint32(i)<<6 + uint32(c2)
i = bidiIndex[o]
c3 := s[3]
if c3 < 0x80 || 0xC0 <= c3 {
return 0, 3 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c3), 4
}
// Illegal rune
return 0, 1
}
// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
// s must start with a full and valid UTF-8 encoded rune.
func (t *bidiTrie) lookupStringUnsafe(s string) uint8 {
c0 := s[0]
if c0 < 0x80 { // is ASCII
return bidiValues[c0]
}
i := bidiIndex[c0]
if c0 < 0xE0 { // 2-byte UTF-8
return t.lookupValue(uint32(i), s[1])
}
i = bidiIndex[uint32(i)<<6+uint32(s[1])]
if c0 < 0xF0 { // 3-byte UTF-8
return t.lookupValue(uint32(i), s[2])
}
i = bidiIndex[uint32(i)<<6+uint32(s[2])]
if c0 < 0xF8 { // 4-byte UTF-8
return t.lookupValue(uint32(i), s[3])
}
return 0
}
// bidiTrie. Total size: 19904 bytes (19.44 KiB). Checksum: b1f201ed2debb6c8.
type bidiTrie struct{}
func newBidiTrie(i int) *bidiTrie {
return &bidiTrie{}
}
// lookupValue determines the type of block n and looks up the value for b.
func (t *bidiTrie) lookupValue(n uint32, b byte) uint8 {
switch {
default:
return uint8(bidiValues[n<<6+uint32(b)])
}
}
// bidiValues: 259 blocks, 16576 entries, 16576 bytes
// The third block is the zero block.
var bidiValues = [16576]uint8{
// Block 0x0, offset 0x0
0x00: 0x000b, 0x01: 0x000b, 0x02: 0x000b, 0x03: 0x000b, 0x04: 0x000b, 0x05: 0x000b,
0x06: 0x000b, 0x07: 0x000b, 0x08: 0x000b, 0x09: 0x0008, 0x0a: 0x0007, 0x0b: 0x0008,
0x0c: 0x0009, 0x0d: 0x0007, 0x0e: 0x000b, 0x0f: 0x000b, 0x10: 0x000b, 0x11: 0x000b,
0x12: 0x000b, 0x13: 0x000b, 0x14: 0x000b, 0x15: 0x000b, 0x16: 0x000b, 0x17: 0x000b,
0x18: 0x000b, 0x19: 0x000b, 0x1a: 0x000b, 0x1b: 0x000b, 0x1c: 0x0007, 0x1d: 0x0007,
0x1e: 0x0007, 0x1f: 0x0008, 0x20: 0x0009, 0x21: 0x000a, 0x22: 0x000a, 0x23: 0x0004,
0x24: 0x0004, 0x25: 0x0004, 0x26: 0x000a, 0x27: 0x000a, 0x28: 0x003a, 0x29: 0x002a,
0x2a: 0x000a, 0x2b: 0x0003, 0x2c: 0x0006, 0x2d: 0x0003, 0x2e: 0x0006, 0x2f: 0x0006,
0x30: 0x0002, 0x31: 0x0002, 0x32: 0x0002, 0x33: 0x0002, 0x34: 0x0002, 0x35: 0x0002,
0x36: 0x0002, 0x37: 0x0002, 0x38: 0x0002, 0x39: 0x0002, 0x3a: 0x0006, 0x3b: 0x000a,
0x3c: 0x000a, 0x3d: 0x000a, 0x3e: 0x000a, 0x3f: 0x000a,
// Block 0x1, offset 0x40
0x40: 0x000a,
0x5b: 0x005a, 0x5c: 0x000a, 0x5d: 0x004a,
0x5e: 0x000a, 0x5f: 0x000a, 0x60: 0x000a,
0x7b: 0x005a,
0x7c: 0x000a, 0x7d: 0x004a, 0x7e: 0x000a, 0x7f: 0x000b,
// Block 0x2, offset 0x80
// Block 0x3, offset 0xc0
0xc0: 0x000b, 0xc1: 0x000b, 0xc2: 0x000b, 0xc3: 0x000b, 0xc4: 0x000b, 0xc5: 0x0007,
0xc6: 0x000b, 0xc7: 0x000b, 0xc8: 0x000b, 0xc9: 0x000b, 0xca: 0x000b, 0xcb: 0x000b,
0xcc: 0x000b, 0xcd: 0x000b, 0xce: 0x000b, 0xcf: 0x000b, 0xd0: 0x000b, 0xd1: 0x000b,
0xd2: 0x000b, 0xd3: 0x000b, 0xd4: 0x000b, 0xd5: 0x000b, 0xd6: 0x000b, 0xd7: 0x000b,
0xd8: 0x000b, 0xd9: 0x000b, 0xda: 0x000b, 0xdb: 0x000b, 0xdc: 0x000b, 0xdd: 0x000b,
0xde: 0x000b, 0xdf: 0x000b, 0xe0: 0x0006, 0xe1: 0x000a, 0xe2: 0x0004, 0xe3: 0x0004,
0xe4: 0x0004, 0xe5: 0x0004, 0xe6: 0x000a, 0xe7: 0x000a, 0xe8: 0x000a, 0xe9: 0x000a,
0xeb: 0x000a, 0xec: 0x000a, 0xed: 0x000b, 0xee: 0x000a, 0xef: 0x000a,
0xf0: 0x0004, 0xf1: 0x0004, 0xf2: 0x0002, 0xf3: 0x0002, 0xf4: 0x000a,
0xf6: 0x000a, 0xf7: 0x000a, 0xf8: 0x000a, 0xf9: 0x0002, 0xfb: 0x000a,
0xfc: 0x000a, 0xfd: 0x000a, 0xfe: 0x000a, 0xff: 0x000a,
// Block 0x4, offset 0x100
0x117: 0x000a,
0x137: 0x000a,
// Block 0x5, offset 0x140
0x179: 0x000a, 0x17a: 0x000a,
// Block 0x6, offset 0x180
0x182: 0x000a, 0x183: 0x000a, 0x184: 0x000a, 0x185: 0x000a,
0x186: 0x000a, 0x187: 0x000a, 0x188: 0x000a, 0x189: 0x000a, 0x18a: 0x000a, 0x18b: 0x000a,
0x18c: 0x000a, 0x18d: 0x000a, 0x18e: 0x000a, 0x18f: 0x000a,
0x192: 0x000a, 0x193: 0x000a, 0x194: 0x000a, 0x195: 0x000a, 0x196: 0x000a, 0x197: 0x000a,
0x198: 0x000a, 0x199: 0x000a, 0x19a: 0x000a, 0x19b: 0x000a, 0x19c: 0x000a, 0x19d: 0x000a,
0x19e: 0x000a, 0x19f: 0x000a,
0x1a5: 0x000a, 0x1a6: 0x000a, 0x1a7: 0x000a, 0x1a8: 0x000a, 0x1a9: 0x000a,
0x1aa: 0x000a, 0x1ab: 0x000a, 0x1ac: 0x000a, 0x1ad: 0x000a, 0x1af: 0x000a,
0x1b0: 0x000a, 0x1b1: 0x000a, 0x1b2: 0x000a, 0x1b3: 0x000a, 0x1b4: 0x000a, 0x1b5: 0x000a,
0x1b6: 0x000a, 0x1b7: 0x000a, 0x1b8: 0x000a, 0x1b9: 0x000a, 0x1ba: 0x000a, 0x1bb: 0x000a,
0x1bc: 0x000a, 0x1bd: 0x000a, 0x1be: 0x000a, 0x1bf: 0x000a,
// Block 0x7, offset 0x1c0
0x1c0: 0x000c, 0x1c1: 0x000c, 0x1c2: 0x000c, 0x1c3: 0x000c, 0x1c4: 0x000c, 0x1c5: 0x000c,
0x1c6: 0x000c, 0x1c7: 0x000c, 0x1c8: 0x000c, 0x1c9: 0x000c, 0x1ca: 0x000c, 0x1cb: 0x000c,
0x1cc: 0x000c, 0x1cd: 0x000c, 0x1ce: 0x000c, 0x1cf: 0x000c, 0x1d0: 0x000c, 0x1d1: 0x000c,
0x1d2: 0x000c, 0x1d3: 0x000c, 0x1d4: 0x000c, 0x1d5: 0x000c, 0x1d6: 0x000c, 0x1d7: 0x000c,
0x1d8: 0x000c, 0x1d9: 0x000c, 0x1da: 0x000c, 0x1db: 0x000c, 0x1dc: 0x000c, 0x1dd: 0x000c,
0x1de: 0x000c, 0x1df: 0x000c, 0x1e0: 0x000c, 0x1e1: 0x000c, 0x1e2: 0x000c, 0x1e3: 0x000c,
0x1e4: 0x000c, 0x1e5: 0x000c, 0x1e6: 0x000c, 0x1e7: 0x000c, 0x1e8: 0x000c, 0x1e9: 0x000c,
0x1ea: 0x000c, 0x1eb: 0x000c, 0x1ec: 0x000c, 0x1ed: 0x000c, 0x1ee: 0x000c, 0x1ef: 0x000c,
0x1f0: 0x000c, 0x1f1: 0x000c, 0x1f2: 0x000c, 0x1f3: 0x000c, 0x1f4: 0x000c, 0x1f5: 0x000c,
0x1f6: 0x000c, 0x1f7: 0x000c, 0x1f8: 0x000c, 0x1f9: 0x000c, 0x1fa: 0x000c, 0x1fb: 0x000c,
0x1fc: 0x000c, 0x1fd: 0x000c, 0x1fe: 0x000c, 0x1ff: 0x000c,
// Block 0x8, offset 0x200
0x200: 0x000c, 0x201: 0x000c, 0x202: 0x000c, 0x203: 0x000c, 0x204: 0x000c, 0x205: 0x000c,
0x206: 0x000c, 0x207: 0x000c, 0x208: 0x000c, 0x209: 0x000c, 0x20a: 0x000c, 0x20b: 0x000c,
0x20c: 0x000c, 0x20d: 0x000c, 0x20e: 0x000c, 0x20f: 0x000c, 0x210: 0x000c, 0x211: 0x000c,
0x212: 0x000c, 0x213: 0x000c, 0x214: 0x000c, 0x215: 0x000c, 0x216: 0x000c, 0x217: 0x000c,
0x218: 0x000c, 0x219: 0x000c, 0x21a: 0x000c, 0x21b: 0x000c, 0x21c: 0x000c, 0x21d: 0x000c,
0x21e: 0x000c, 0x21f: 0x000c, 0x220: 0x000c, 0x221: 0x000c, 0x222: 0x000c, 0x223: 0x000c,
0x224: 0x000c, 0x225: 0x000c, 0x226: 0x000c, 0x227: 0x000c, 0x228: 0x000c, 0x229: 0x000c,
0x22a: 0x000c, 0x22b: 0x000c, 0x22c: 0x000c, 0x22d: 0x000c, 0x22e: 0x000c, 0x22f: 0x000c,
0x234: 0x000a, 0x235: 0x000a,
0x23e: 0x000a,
// Block 0x9, offset 0x240
0x244: 0x000a, 0x245: 0x000a,
0x247: 0x000a,
// Block 0xa, offset 0x280
0x2b6: 0x000a,
// Block 0xb, offset 0x2c0
0x2c3: 0x000c, 0x2c4: 0x000c, 0x2c5: 0x000c,
0x2c6: 0x000c, 0x2c7: 0x000c, 0x2c8: 0x000c, 0x2c9: 0x000c,
// Block 0xc, offset 0x300
0x30a: 0x000a,
0x30d: 0x000a, 0x30e: 0x000a, 0x30f: 0x0004, 0x310: 0x0001, 0x311: 0x000c,
0x312: 0x000c, 0x313: 0x000c, 0x314: 0x000c, 0x315: 0x000c, 0x316: 0x000c, 0x317: 0x000c,
0x318: 0x000c, 0x319: 0x000c, 0x31a: 0x000c, 0x31b: 0x000c, 0x31c: 0x000c, 0x31d: 0x000c,
0x31e: 0x000c, 0x31f: 0x000c, 0x320: 0x000c, 0x321: 0x000c, 0x322: 0x000c, 0x323: 0x000c,
0x324: 0x000c, 0x325: 0x000c, 0x326: 0x000c, 0x327: 0x000c, 0x328: 0x000c, 0x329: 0x000c,
0x32a: 0x000c, 0x32b: 0x000c, 0x32c: 0x000c, 0x32d: 0x000c, 0x32e: 0x000c, 0x32f: 0x000c,
0x330: 0x000c, 0x331: 0x000c, 0x332: 0x000c, 0x333: 0x000c, 0x334: 0x000c, 0x335: 0x000c,
0x336: 0x000c, 0x337: 0x000c, 0x338: 0x000c, 0x339: 0x000c, 0x33a: 0x000c, 0x33b: 0x000c,
0x33c: 0x000c, 0x33d: 0x000c, 0x33e: 0x0001, 0x33f: 0x000c,
// Block 0xd, offset 0x340
0x340: 0x0001, 0x341: 0x000c, 0x342: 0x000c, 0x343: 0x0001, 0x344: 0x000c, 0x345: 0x000c,
0x346: 0x0001, 0x347: 0x000c, 0x348: 0x0001, 0x349: 0x0001, 0x34a: 0x0001, 0x34b: 0x0001,
0x34c: 0x0001, 0x34d: 0x0001, 0x34e: 0x0001, 0x34f: 0x0001, 0x350: 0x0001, 0x351: 0x0001,
0x352: 0x0001, 0x353: 0x0001, 0x354: 0x0001, 0x355: 0x0001, 0x356: 0x0001, 0x357: 0x0001,
0x358: 0x0001, 0x359: 0x0001, 0x35a: 0x0001, 0x35b: 0x0001, 0x35c: 0x0001, 0x35d: 0x0001,
0x35e: 0x0001, 0x35f: 0x0001, 0x360: 0x0001, 0x361: 0x0001, 0x362: 0x0001, 0x363: 0x0001,
0x364: 0x0001, 0x365: 0x0001, 0x366: 0x0001, 0x367: 0x0001, 0x368: 0x0001, 0x369: 0x0001,
0x36a: 0x0001, 0x36b: 0x0001, 0x36c: 0x0001, 0x36d: 0x0001, 0x36e: 0x0001, 0x36f: 0x0001,
0x370: 0x0001, 0x371: 0x0001, 0x372: 0x0001, 0x373: 0x0001, 0x374: 0x0001, 0x375: 0x0001,
0x376: 0x0001, 0x377: 0x0001, 0x378: 0x0001, 0x379: 0x0001, 0x37a: 0x0001, 0x37b: 0x0001,
0x37c: 0x0001, 0x37d: 0x0001, 0x37e: 0x0001, 0x37f: 0x0001,
// Block 0xe, offset 0x380
0x380: 0x0005, 0x381: 0x0005, 0x382: 0x0005, 0x383: 0x0005, 0x384: 0x0005, 0x385: 0x0005,
0x386: 0x000a, 0x387: 0x000a, 0x388: 0x000d, 0x389: 0x0004, 0x38a: 0x0004, 0x38b: 0x000d,
0x38c: 0x0006, 0x38d: 0x000d, 0x38e: 0x000a, 0x38f: 0x000a, 0x390: 0x000c, 0x391: 0x000c,
0x392: 0x000c, 0x393: 0x000c, 0x394: 0x000c, 0x395: 0x000c, 0x396: 0x000c, 0x397: 0x000c,
0x398: 0x000c, 0x399: 0x000c, 0x39a: 0x000c, 0x39b: 0x000d, 0x39c: 0x000d, 0x39d: 0x000d,
0x39e: 0x000d, 0x39f: 0x000d, 0x3a0: 0x000d, 0x3a1: 0x000d, 0x3a2: 0x000d, 0x3a3: 0x000d,
0x3a4: 0x000d, 0x3a5: 0x000d, 0x3a6: 0x000d, 0x3a7: 0x000d, 0x3a8: 0x000d, 0x3a9: 0x000d,
0x3aa: 0x000d, 0x3ab: 0x000d, 0x3ac: 0x000d, 0x3ad: 0x000d, 0x3ae: 0x000d, 0x3af: 0x000d,
0x3b0: 0x000d, 0x3b1: 0x000d, 0x3b2: 0x000d, 0x3b3: 0x000d, 0x3b4: 0x000d, 0x3b5: 0x000d,
0x3b6: 0x000d, 0x3b7: 0x000d, 0x3b8: 0x000d, 0x3b9: 0x000d, 0x3ba: 0x000d, 0x3bb: 0x000d,
0x3bc: 0x000d, 0x3bd: 0x000d, 0x3be: 0x000d, 0x3bf: 0x000d,
// Block 0xf, offset 0x3c0
0x3c0: 0x000d, 0x3c1: 0x000d, 0x3c2: 0x000d, 0x3c3: 0x000d, 0x3c4: 0x000d, 0x3c5: 0x000d,
0x3c6: 0x000d, 0x3c7: 0x000d, 0x3c8: 0x000d, 0x3c9: 0x000d, 0x3ca: 0x000d, 0x3cb: 0x000c,
0x3cc: 0x000c, 0x3cd: 0x000c, 0x3ce: 0x000c, 0x3cf: 0x000c, 0x3d0: 0x000c, 0x3d1: 0x000c,
0x3d2: 0x000c, 0x3d3: 0x000c, 0x3d4: 0x000c, 0x3d5: 0x000c, 0x3d6: 0x000c, 0x3d7: 0x000c,
0x3d8: 0x000c, 0x3d9: 0x000c, 0x3da: 0x000c, 0x3db: 0x000c, 0x3dc: 0x000c, 0x3dd: 0x000c,
0x3de: 0x000c, 0x3df: 0x000c, 0x3e0: 0x0005, 0x3e1: 0x0005, 0x3e2: 0x0005, 0x3e3: 0x0005,
0x3e4: 0x0005, 0x3e5: 0x0005, 0x3e6: 0x0005, 0x3e7: 0x0005, 0x3e8: 0x0005, 0x3e9: 0x0005,
0x3ea: 0x0004, 0x3eb: 0x0005, 0x3ec: 0x0005, 0x3ed: 0x000d, 0x3ee: 0x000d, 0x3ef: 0x000d,
0x3f0: 0x000c, 0x3f1: 0x000d, 0x3f2: 0x000d, 0x3f3: 0x000d, 0x3f4: 0x000d, 0x3f5: 0x000d,
0x3f6: 0x000d, 0x3f7: 0x000d, 0x3f8: 0x000d, 0x3f9: 0x000d, 0x3fa: 0x000d, 0x3fb: 0x000d,
0x3fc: 0x000d, 0x3fd: 0x000d, 0x3fe: 0x000d, 0x3ff: 0x000d,
// Block 0x10, offset 0x400
0x400: 0x000d, 0x401: 0x000d, 0x402: 0x000d, 0x403: 0x000d, 0x404: 0x000d, 0x405: 0x000d,
0x406: 0x000d, 0x407: 0x000d, 0x408: 0x000d, 0x409: 0x000d, 0x40a: 0x000d, 0x40b: 0x000d,
0x40c: 0x000d, 0x40d: 0x000d, 0x40e: 0x000d, 0x40f: 0x000d, 0x410: 0x000d, 0x411: 0x000d,
0x412: 0x000d, 0x413: 0x000d, 0x414: 0x000d, 0x415: 0x000d, 0x416: 0x000d, 0x417: 0x000d,
0x418: 0x000d, 0x419: 0x000d, 0x41a: 0x000d, 0x41b: 0x000d, 0x41c: 0x000d, 0x41d: 0x000d,
0x41e: 0x000d, 0x41f: 0x000d, 0x420: 0x000d, 0x421: 0x000d, 0x422: 0x000d, 0x423: 0x000d,
0x424: 0x000d, 0x425: 0x000d, 0x426: 0x000d, 0x427: 0x000d, 0x428: 0x000d, 0x429: 0x000d,
0x42a: 0x000d, 0x42b: 0x000d, 0x42c: 0x000d, 0x42d: 0x000d, 0x42e: 0x000d, 0x42f: 0x000d,
0x430: 0x000d, 0x431: 0x000d, 0x432: 0x000d, 0x433: 0x000d, 0x434: 0x000d, 0x435: 0x000d,
0x436: 0x000d, 0x437: 0x000d, 0x438: 0x000d, 0x439: 0x000d, 0x43a: 0x000d, 0x43b: 0x000d,
0x43c: 0x000d, 0x43d: 0x000d, 0x43e: 0x000d, 0x43f: 0x000d,
// Block 0x11, offset 0x440
0x440: 0x000d, 0x441: 0x000d, 0x442: 0x000d, 0x443: 0x000d, 0x444: 0x000d, 0x445: 0x000d,
0x446: 0x000d, 0x447: 0x000d, 0x448: 0x000d, 0x449: 0x000d, 0x44a: 0x000d, 0x44b: 0x000d,
0x44c: 0x000d, 0x44d: 0x000d, 0x44e: 0x000d, 0x44f: 0x000d, 0x450: 0x000d, 0x451: 0x000d,
0x452: 0x000d, 0x453: 0x000d, 0x454: 0x000d, 0x455: 0x000d, 0x456: 0x000c, 0x457: 0x000c,
0x458: 0x000c, 0x459: 0x000c, 0x45a: 0x000c, 0x45b: 0x000c, 0x45c: 0x000c, 0x45d: 0x0005,
0x45e: 0x000a, 0x45f: 0x000c, 0x460: 0x000c, 0x461: 0x000c, 0x462: 0x000c, 0x463: 0x000c,
0x464: 0x000c, 0x465: 0x000d, 0x466: 0x000d, 0x467: 0x000c, 0x468: 0x000c, 0x469: 0x000a,
0x46a: 0x000c, 0x46b: 0x000c, 0x46c: 0x000c, 0x46d: 0x000c, 0x46e: 0x000d, 0x46f: 0x000d,
0x470: 0x0002, 0x471: 0x0002, 0x472: 0x0002, 0x473: 0x0002, 0x474: 0x0002, 0x475: 0x0002,
0x476: 0x0002, 0x477: 0x0002, 0x478: 0x0002, 0x479: 0x0002, 0x47a: 0x000d, 0x47b: 0x000d,
0x47c: 0x000d, 0x47d: 0x000d, 0x47e: 0x000d, 0x47f: 0x000d,
// Block 0x12, offset 0x480
0x480: 0x000d, 0x481: 0x000d, 0x482: 0x000d, 0x483: 0x000d, 0x484: 0x000d, 0x485: 0x000d,
0x486: 0x000d, 0x487: 0x000d, 0x488: 0x000d, 0x489: 0x000d, 0x48a: 0x000d, 0x48b: 0x000d,
0x48c: 0x000d, 0x48d: 0x000d, 0x48e: 0x000d, 0x48f: 0x000d, 0x490: 0x000d, 0x491: 0x000c,
0x492: 0x000d, 0x493: 0x000d, 0x494: 0x000d, 0x495: 0x000d, 0x496: 0x000d, 0x497: 0x000d,
0x498: 0x000d, 0x499: 0x000d, 0x49a: 0x000d, 0x49b: 0x000d, 0x49c: 0x000d, 0x49d: 0x000d,
0x49e: 0x000d, 0x49f: 0x000d, 0x4a0: 0x000d, 0x4a1: 0x000d, 0x4a2: 0x000d, 0x4a3: 0x000d,
0x4a4: 0x000d, 0x4a5: 0x000d, 0x4a6: 0x000d, 0x4a7: 0x000d, 0x4a8: 0x000d, 0x4a9: 0x000d,
0x4aa: 0x000d, 0x4ab: 0x000d, 0x4ac: 0x000d, 0x4ad: 0x000d, 0x4ae: 0x000d, 0x4af: 0x000d,
0x4b0: 0x000c, 0x4b1: 0x000c, 0x4b2: 0x000c, 0x4b3: 0x000c, 0x4b4: 0x000c, 0x4b5: 0x000c,
0x4b6: 0x000c, 0x4b7: 0x000c, 0x4b8: 0x000c, 0x4b9: 0x000c, 0x4ba: 0x000c, 0x4bb: 0x000c,
0x4bc: 0x000c, 0x4bd: 0x000c, 0x4be: 0x000c, 0x4bf: 0x000c,
// Block 0x13, offset 0x4c0
0x4c0: 0x000c, 0x4c1: 0x000c, 0x4c2: 0x000c, 0x4c3: 0x000c, 0x4c4: 0x000c, 0x4c5: 0x000c,
0x4c6: 0x000c, 0x4c7: 0x000c, 0x4c8: 0x000c, 0x4c9: 0x000c, 0x4ca: 0x000c, 0x4cb: 0x000d,
0x4cc: 0x000d, 0x4cd: 0x000d, 0x4ce: 0x000d, 0x4cf: 0x000d, 0x4d0: 0x000d, 0x4d1: 0x000d,
0x4d2: 0x000d, 0x4d3: 0x000d, 0x4d4: 0x000d, 0x4d5: 0x000d, 0x4d6: 0x000d, 0x4d7: 0x000d,
0x4d8: 0x000d, 0x4d9: 0x000d, 0x4da: 0x000d, 0x4db: 0x000d, 0x4dc: 0x000d, 0x4dd: 0x000d,
0x4de: 0x000d, 0x4df: 0x000d, 0x4e0: 0x000d, 0x4e1: 0x000d, 0x4e2: 0x000d, 0x4e3: 0x000d,
0x4e4: 0x000d, 0x4e5: 0x000d, 0x4e6: 0x000d, 0x4e7: 0x000d, 0x4e8: 0x000d, 0x4e9: 0x000d,
0x4ea: 0x000d, 0x4eb: 0x000d, 0x4ec: 0x000d, 0x4ed: 0x000d, 0x4ee: 0x000d, 0x4ef: 0x000d,
0x4f0: 0x000d, 0x4f1: 0x000d, 0x4f2: 0x000d, 0x4f3: 0x000d, 0x4f4: 0x000d, 0x4f5: 0x000d,
0x4f6: 0x000d, 0x4f7: 0x000d, 0x4f8: 0x000d, 0x4f9: 0x000d, 0x4fa: 0x000d, 0x4fb: 0x000d,
0x4fc: 0x000d, 0x4fd: 0x000d, 0x4fe: 0x000d, 0x4ff: 0x000d,
// Block 0x14, offset 0x500
0x500: 0x000d, 0x501: 0x000d, 0x502: 0x000d, 0x503: 0x000d, 0x504: 0x000d, 0x505: 0x000d,
0x506: 0x000d, 0x507: 0x000d, 0x508: 0x000d, 0x509: 0x000d, 0x50a: 0x000d, 0x50b: 0x000d,
0x50c: 0x000d, 0x50d: 0x000d, 0x50e: 0x000d, 0x50f: 0x000d, 0x510: 0x000d, 0x511: 0x000d,
0x512: 0x000d, 0x513: 0x000d, 0x514: 0x000d, 0x515: 0x000d, 0x516: 0x000d, 0x517: 0x000d,
0x518: 0x000d, 0x519: 0x000d, 0x51a: 0x000d, 0x51b: 0x000d, 0x51c: 0x000d, 0x51d: 0x000d,
0x51e: 0x000d, 0x51f: 0x000d, 0x520: 0x000d, 0x521: 0x000d, 0x522: 0x000d, 0x523: 0x000d,
0x524: 0x000d, 0x525: 0x000d, 0x526: 0x000c, 0x527: 0x000c, 0x528: 0x000c, 0x529: 0x000c,
0x52a: 0x000c, 0x52b: 0x000c, 0x52c: 0x000c, 0x52d: 0x000c, 0x52e: 0x000c, 0x52f: 0x000c,
0x530: 0x000c, 0x531: 0x000d, 0x532: 0x000d, 0x533: 0x000d, 0x534: 0x000d, 0x535: 0x000d,
0x536: 0x000d, 0x537: 0x000d, 0x538: 0x000d, 0x539: 0x000d, 0x53a: 0x000d, 0x53b: 0x000d,
0x53c: 0x000d, 0x53d: 0x000d, 0x53e: 0x000d, 0x53f: 0x000d,
// Block 0x15, offset 0x540
0x540: 0x0001, 0x541: 0x0001, 0x542: 0x0001, 0x543: 0x0001, 0x544: 0x0001, 0x545: 0x0001,
0x546: 0x0001, 0x547: 0x0001, 0x548: 0x0001, 0x549: 0x0001, 0x54a: 0x0001, 0x54b: 0x0001,
0x54c: 0x0001, 0x54d: 0x0001, 0x54e: 0x0001, 0x54f: 0x0001, 0x550: 0x0001, 0x551: 0x0001,
0x552: 0x0001, 0x553: 0x0001, 0x554: 0x0001, 0x555: 0x0001, 0x556: 0x0001, 0x557: 0x0001,
0x558: 0x0001, 0x559: 0x0001, 0x55a: 0x0001, 0x55b: 0x0001, 0x55c: 0x0001, 0x55d: 0x0001,
0x55e: 0x0001, 0x55f: 0x0001, 0x560: 0x0001, 0x561: 0x0001, 0x562: 0x0001, 0x563: 0x0001,
0x564: 0x0001, 0x565: 0x0001, 0x566: 0x0001, 0x567: 0x0001, 0x568: 0x0001, 0x569: 0x0001,
0x56a: 0x0001, 0x56b: 0x000c, 0x56c: 0x000c, 0x56d: 0x000c, 0x56e: 0x000c, 0x56f: 0x000c,
0x570: 0x000c, 0x571: 0x000c, 0x572: 0x000c, 0x573: 0x000c, 0x574: 0x0001, 0x575: 0x0001,
0x576: 0x000a, 0x577: 0x000a, 0x578: 0x000a, 0x579: 0x000a, 0x57a: 0x0001, 0x57b: 0x0001,
0x57c: 0x0001, 0x57d: 0x000c, 0x57e: 0x0001, 0x57f: 0x0001,
// Block 0x16, offset 0x580
0x580: 0x0001, 0x581: 0x0001, 0x582: 0x0001, 0x583: 0x0001, 0x584: 0x0001, 0x585: 0x0001,
0x586: 0x0001, 0x587: 0x0001, 0x588: 0x0001, 0x589: 0x0001, 0x58a: 0x0001, 0x58b: 0x0001,
0x58c: 0x0001, 0x58d: 0x0001, 0x58e: 0x0001, 0x58f: 0x0001, 0x590: 0x0001, 0x591: 0x0001,
0x592: 0x0001, 0x593: 0x0001, 0x594: 0x0001, 0x595: 0x0001, 0x596: 0x000c, 0x597: 0x000c,
0x598: 0x000c, 0x599: 0x000c, 0x59a: 0x0001, 0x59b: 0x000c, 0x59c: 0x000c, 0x59d: 0x000c,
0x59e: 0x000c, 0x59f: 0x000c, 0x5a0: 0x000c, 0x5a1: 0x000c, 0x5a2: 0x000c, 0x5a3: 0x000c,
0x5a4: 0x0001, 0x5a5: 0x000c, 0x5a6: 0x000c, 0x5a7: 0x000c, 0x5a8: 0x0001, 0x5a9: 0x000c,
0x5aa: 0x000c, 0x5ab: 0x000c, 0x5ac: 0x000c, 0x5ad: 0x000c, 0x5ae: 0x0001, 0x5af: 0x0001,
0x5b0: 0x0001, 0x5b1: 0x0001, 0x5b2: 0x0001, 0x5b3: 0x0001, 0x5b4: 0x0001, 0x5b5: 0x0001,
0x5b6: 0x0001, 0x5b7: 0x0001, 0x5b8: 0x0001, 0x5b9: 0x0001, 0x5ba: 0x0001, 0x5bb: 0x0001,
0x5bc: 0x0001, 0x5bd: 0x0001, 0x5be: 0x0001, 0x5bf: 0x0001,
// Block 0x17, offset 0x5c0
0x5c0: 0x0001, 0x5c1: 0x0001, 0x5c2: 0x0001, 0x5c3: 0x0001, 0x5c4: 0x0001, 0x5c5: 0x0001,
0x5c6: 0x0001, 0x5c7: 0x0001, 0x5c8: 0x0001, 0x5c9: 0x0001, 0x5ca: 0x0001, 0x5cb: 0x0001,
0x5cc: 0x0001, 0x5cd: 0x0001, 0x5ce: 0x0001, 0x5cf: 0x0001, 0x5d0: 0x0001, 0x5d1: 0x0001,
0x5d2: 0x0001, 0x5d3: 0x0001, 0x5d4: 0x0001, 0x5d5: 0x0001, 0x5d6: 0x0001, 0x5d7: 0x0001,
0x5d8: 0x0001, 0x5d9: 0x000c, 0x5da: 0x000c, 0x5db: 0x000c, 0x5dc: 0x0001, 0x5dd: 0x0001,
0x5de: 0x0001, 0x5df: 0x0001, 0x5e0: 0x000d, 0x5e1: 0x000d, 0x5e2: 0x000d, 0x5e3: 0x000d,
0x5e4: 0x000d, 0x5e5: 0x000d, 0x5e6: 0x000d, 0x5e7: 0x000d, 0x5e8: 0x000d, 0x5e9: 0x000d,
0x5ea: 0x000d, 0x5eb: 0x0001, 0x5ec: 0x0001, 0x5ed: 0x0001, 0x5ee: 0x0001, 0x5ef: 0x0001,
0x5f0: 0x000d, 0x5f1: 0x000d, 0x5f2: 0x000d, 0x5f3: 0x000d, 0x5f4: 0x000d, 0x5f5: 0x000d,
0x5f6: 0x000d, 0x5f7: 0x000d, 0x5f8: 0x000d, 0x5f9: 0x000d, 0x5fa: 0x000d, 0x5fb: 0x000d,
0x5fc: 0x000d, 0x5fd: 0x000d, 0x5fe: 0x000d, 0x5ff: 0x000d,
// Block 0x18, offset 0x600
0x600: 0x000d, 0x601: 0x000d, 0x602: 0x000d, 0x603: 0x000d, 0x604: 0x000d, 0x605: 0x000d,
0x606: 0x000d, 0x607: 0x000d, 0x608: 0x000d, 0x609: 0x000d, 0x60a: 0x000d, 0x60b: 0x000d,
0x60c: 0x000d, 0x60d: 0x000d, 0x60e: 0x000d, 0x60f: 0x0001, 0x610: 0x0005, 0x611: 0x0005,
0x612: 0x0001, 0x613: 0x0001, 0x614: 0x0001, 0x615: 0x0001, 0x616: 0x0001, 0x617: 0x0001,
0x618: 0x000c, 0x619: 0x000c, 0x61a: 0x000c, 0x61b: 0x000c, 0x61c: 0x000c, 0x61d: 0x000c,
0x61e: 0x000c, 0x61f: 0x000c, 0x620: 0x000d, 0x621: 0x000d, 0x622: 0x000d, 0x623: 0x000d,
0x624: 0x000d, 0x625: 0x000d, 0x626: 0x000d, 0x627: 0x000d, 0x628: 0x000d, 0x629: 0x000d,
0x62a: 0x000d, 0x62b: 0x000d, 0x62c: 0x000d, 0x62d: 0x000d, 0x62e: 0x000d, 0x62f: 0x000d,
0x630: 0x000d, 0x631: 0x000d, 0x632: 0x000d, 0x633: 0x000d, 0x634: 0x000d, 0x635: 0x000d,
0x636: 0x000d, 0x637: 0x000d, 0x638: 0x000d, 0x639: 0x000d, 0x63a: 0x000d, 0x63b: 0x000d,
0x63c: 0x000d, 0x63d: 0x000d, 0x63e: 0x000d, 0x63f: 0x000d,
// Block 0x19, offset 0x640
0x640: 0x000d, 0x641: 0x000d, 0x642: 0x000d, 0x643: 0x000d, 0x644: 0x000d, 0x645: 0x000d,
0x646: 0x000d, 0x647: 0x000d, 0x648: 0x000d, 0x649: 0x000d, 0x64a: 0x000c, 0x64b: 0x000c,
0x64c: 0x000c, 0x64d: 0x000c, 0x64e: 0x000c, 0x64f: 0x000c, 0x650: 0x000c, 0x651: 0x000c,
0x652: 0x000c, 0x653: 0x000c, 0x654: 0x000c, 0x655: 0x000c, 0x656: 0x000c, 0x657: 0x000c,
0x658: 0x000c, 0x659: 0x000c, 0x65a: 0x000c, 0x65b: 0x000c, 0x65c: 0x000c, 0x65d: 0x000c,
0x65e: 0x000c, 0x65f: 0x000c, 0x660: 0x000c, 0x661: 0x000c, 0x662: 0x0005, 0x663: 0x000c,
0x664: 0x000c, 0x665: 0x000c, 0x666: 0x000c, 0x667: 0x000c, 0x668: 0x000c, 0x669: 0x000c,
0x66a: 0x000c, 0x66b: 0x000c, 0x66c: 0x000c, 0x66d: 0x000c, 0x66e: 0x000c, 0x66f: 0x000c,
0x670: 0x000c, 0x671: 0x000c, 0x672: 0x000c, 0x673: 0x000c, 0x674: 0x000c, 0x675: 0x000c,
0x676: 0x000c, 0x677: 0x000c, 0x678: 0x000c, 0x679: 0x000c, 0x67a: 0x000c, 0x67b: 0x000c,
0x67c: 0x000c, 0x67d: 0x000c, 0x67e: 0x000c, 0x67f: 0x000c,
// Block 0x1a, offset 0x680
0x680: 0x000c, 0x681: 0x000c, 0x682: 0x000c,
0x6ba: 0x000c,
0x6bc: 0x000c,
// Block 0x1b, offset 0x6c0
0x6c1: 0x000c, 0x6c2: 0x000c, 0x6c3: 0x000c, 0x6c4: 0x000c, 0x6c5: 0x000c,
0x6c6: 0x000c, 0x6c7: 0x000c, 0x6c8: 0x000c,
0x6cd: 0x000c, 0x6d1: 0x000c,
0x6d2: 0x000c, 0x6d3: 0x000c, 0x6d4: 0x000c, 0x6d5: 0x000c, 0x6d6: 0x000c, 0x6d7: 0x000c,
0x6e2: 0x000c, 0x6e3: 0x000c,
// Block 0x1c, offset 0x700
0x701: 0x000c,
0x73c: 0x000c,
// Block 0x1d, offset 0x740
0x741: 0x000c, 0x742: 0x000c, 0x743: 0x000c, 0x744: 0x000c,
0x74d: 0x000c,
0x762: 0x000c, 0x763: 0x000c,
0x772: 0x0004, 0x773: 0x0004,
0x77b: 0x0004,
0x77e: 0x000c,
// Block 0x1e, offset 0x780
0x781: 0x000c, 0x782: 0x000c,
0x7bc: 0x000c,
// Block 0x1f, offset 0x7c0
0x7c1: 0x000c, 0x7c2: 0x000c,
0x7c7: 0x000c, 0x7c8: 0x000c, 0x7cb: 0x000c,
0x7cc: 0x000c, 0x7cd: 0x000c, 0x7d1: 0x000c,
0x7f0: 0x000c, 0x7f1: 0x000c, 0x7f5: 0x000c,
// Block 0x20, offset 0x800
0x801: 0x000c, 0x802: 0x000c, 0x803: 0x000c, 0x804: 0x000c, 0x805: 0x000c,
0x807: 0x000c, 0x808: 0x000c,
0x80d: 0x000c,
0x822: 0x000c, 0x823: 0x000c,
0x831: 0x0004,
0x83a: 0x000c, 0x83b: 0x000c,
0x83c: 0x000c, 0x83d: 0x000c, 0x83e: 0x000c, 0x83f: 0x000c,
// Block 0x21, offset 0x840
0x841: 0x000c,
0x87c: 0x000c, 0x87f: 0x000c,
// Block 0x22, offset 0x880
0x881: 0x000c, 0x882: 0x000c, 0x883: 0x000c, 0x884: 0x000c,
0x88d: 0x000c,
0x895: 0x000c, 0x896: 0x000c,
0x8a2: 0x000c, 0x8a3: 0x000c,
// Block 0x23, offset 0x8c0
0x8c2: 0x000c,
// Block 0x24, offset 0x900
0x900: 0x000c,
0x90d: 0x000c,
0x933: 0x000a, 0x934: 0x000a, 0x935: 0x000a,
0x936: 0x000a, 0x937: 0x000a, 0x938: 0x000a, 0x939: 0x0004, 0x93a: 0x000a,
// Block 0x25, offset 0x940
0x940: 0x000c, 0x944: 0x000c,
0x97c: 0x000c, 0x97e: 0x000c, 0x97f: 0x000c,
// Block 0x26, offset 0x980
0x980: 0x000c,
0x986: 0x000c, 0x987: 0x000c, 0x988: 0x000c, 0x98a: 0x000c, 0x98b: 0x000c,
0x98c: 0x000c, 0x98d: 0x000c,
0x995: 0x000c, 0x996: 0x000c,
0x9a2: 0x000c, 0x9a3: 0x000c,
0x9b8: 0x000a, 0x9b9: 0x000a, 0x9ba: 0x000a, 0x9bb: 0x000a,
0x9bc: 0x000a, 0x9bd: 0x000a, 0x9be: 0x000a,
// Block 0x27, offset 0x9c0
0x9cc: 0x000c, 0x9cd: 0x000c,
0x9e2: 0x000c, 0x9e3: 0x000c,
// Block 0x28, offset 0xa00
0xa00: 0x000c, 0xa01: 0x000c,
0xa3b: 0x000c,
0xa3c: 0x000c,
// Block 0x29, offset 0xa40
0xa41: 0x000c, 0xa42: 0x000c, 0xa43: 0x000c, 0xa44: 0x000c,
0xa4d: 0x000c,
0xa62: 0x000c, 0xa63: 0x000c,
// Block 0x2a, offset 0xa80
0xa81: 0x000c,
// Block 0x2b, offset 0xac0
0xaca: 0x000c,
0xad2: 0x000c, 0xad3: 0x000c, 0xad4: 0x000c, 0xad6: 0x000c,
// Block 0x2c, offset 0xb00
0xb31: 0x000c, 0xb34: 0x000c, 0xb35: 0x000c,
0xb36: 0x000c, 0xb37: 0x000c, 0xb38: 0x000c, 0xb39: 0x000c, 0xb3a: 0x000c,
0xb3f: 0x0004,
// Block 0x2d, offset 0xb40
0xb47: 0x000c, 0xb48: 0x000c, 0xb49: 0x000c, 0xb4a: 0x000c, 0xb4b: 0x000c,
0xb4c: 0x000c, 0xb4d: 0x000c, 0xb4e: 0x000c,
// Block 0x2e, offset 0xb80
0xbb1: 0x000c, 0xbb4: 0x000c, 0xbb5: 0x000c,
0xbb6: 0x000c, 0xbb7: 0x000c, 0xbb8: 0x000c, 0xbb9: 0x000c, 0xbba: 0x000c, 0xbbb: 0x000c,
0xbbc: 0x000c,
// Block 0x2f, offset 0xbc0
0xbc8: 0x000c, 0xbc9: 0x000c, 0xbca: 0x000c, 0xbcb: 0x000c,
0xbcc: 0x000c, 0xbcd: 0x000c, 0xbce: 0x000c,
// Block 0x30, offset 0xc00
0xc18: 0x000c, 0xc19: 0x000c,
0xc35: 0x000c,
0xc37: 0x000c, 0xc39: 0x000c, 0xc3a: 0x003a, 0xc3b: 0x002a,
0xc3c: 0x003a, 0xc3d: 0x002a,
// Block 0x31, offset 0xc40
0xc71: 0x000c, 0xc72: 0x000c, 0xc73: 0x000c, 0xc74: 0x000c, 0xc75: 0x000c,
0xc76: 0x000c, 0xc77: 0x000c, 0xc78: 0x000c, 0xc79: 0x000c, 0xc7a: 0x000c, 0xc7b: 0x000c,
0xc7c: 0x000c, 0xc7d: 0x000c, 0xc7e: 0x000c,
// Block 0x32, offset 0xc80
0xc80: 0x000c, 0xc81: 0x000c, 0xc82: 0x000c, 0xc83: 0x000c, 0xc84: 0x000c,
0xc86: 0x000c, 0xc87: 0x000c,
0xc8d: 0x000c, 0xc8e: 0x000c, 0xc8f: 0x000c, 0xc90: 0x000c, 0xc91: 0x000c,
0xc92: 0x000c, 0xc93: 0x000c, 0xc94: 0x000c, 0xc95: 0x000c, 0xc96: 0x000c, 0xc97: 0x000c,
0xc99: 0x000c, 0xc9a: 0x000c, 0xc9b: 0x000c, 0xc9c: 0x000c, 0xc9d: 0x000c,
0xc9e: 0x000c, 0xc9f: 0x000c, 0xca0: 0x000c, 0xca1: 0x000c, 0xca2: 0x000c, 0xca3: 0x000c,
0xca4: 0x000c, 0xca5: 0x000c, 0xca6: 0x000c, 0xca7: 0x000c, 0xca8: 0x000c, 0xca9: 0x000c,
0xcaa: 0x000c, 0xcab: 0x000c, 0xcac: 0x000c, 0xcad: 0x000c, 0xcae: 0x000c, 0xcaf: 0x000c,
0xcb0: 0x000c, 0xcb1: 0x000c, 0xcb2: 0x000c, 0xcb3: 0x000c, 0xcb4: 0x000c, 0xcb5: 0x000c,
0xcb6: 0x000c, 0xcb7: 0x000c, 0xcb8: 0x000c, 0xcb9: 0x000c, 0xcba: 0x000c, 0xcbb: 0x000c,
0xcbc: 0x000c,
// Block 0x33, offset 0xcc0
0xcc6: 0x000c,
// Block 0x34, offset 0xd00
0xd2d: 0x000c, 0xd2e: 0x000c, 0xd2f: 0x000c,
0xd30: 0x000c, 0xd32: 0x000c, 0xd33: 0x000c, 0xd34: 0x000c, 0xd35: 0x000c,
0xd36: 0x000c, 0xd37: 0x000c, 0xd39: 0x000c, 0xd3a: 0x000c,
0xd3d: 0x000c, 0xd3e: 0x000c,
// Block 0x35, offset 0xd40
0xd58: 0x000c, 0xd59: 0x000c,
0xd5e: 0x000c, 0xd5f: 0x000c, 0xd60: 0x000c,
0xd71: 0x000c, 0xd72: 0x000c, 0xd73: 0x000c, 0xd74: 0x000c,
// Block 0x36, offset 0xd80
0xd82: 0x000c, 0xd85: 0x000c,
0xd86: 0x000c,
0xd8d: 0x000c,
0xd9d: 0x000c,
// Block 0x37, offset 0xdc0
0xddd: 0x000c,
0xdde: 0x000c, 0xddf: 0x000c,
// Block 0x38, offset 0xe00
0xe10: 0x000a, 0xe11: 0x000a,
0xe12: 0x000a, 0xe13: 0x000a, 0xe14: 0x000a, 0xe15: 0x000a, 0xe16: 0x000a, 0xe17: 0x000a,
0xe18: 0x000a, 0xe19: 0x000a,
// Block 0x39, offset 0xe40
0xe40: 0x000a,
// Block 0x3a, offset 0xe80
0xe80: 0x0009,
0xe9b: 0x007a, 0xe9c: 0x006a,
// Block 0x3b, offset 0xec0
0xed2: 0x000c, 0xed3: 0x000c, 0xed4: 0x000c,
0xef2: 0x000c, 0xef3: 0x000c,
// Block 0x3c, offset 0xf00
0xf12: 0x000c, 0xf13: 0x000c,
0xf32: 0x000c, 0xf33: 0x000c,
// Block 0x3d, offset 0xf40
0xf74: 0x000c, 0xf75: 0x000c,
0xf77: 0x000c, 0xf78: 0x000c, 0xf79: 0x000c, 0xf7a: 0x000c, 0xf7b: 0x000c,
0xf7c: 0x000c, 0xf7d: 0x000c,
// Block 0x3e, offset 0xf80
0xf86: 0x000c, 0xf89: 0x000c, 0xf8a: 0x000c, 0xf8b: 0x000c,
0xf8c: 0x000c, 0xf8d: 0x000c, 0xf8e: 0x000c, 0xf8f: 0x000c, 0xf90: 0x000c, 0xf91: 0x000c,
0xf92: 0x000c, 0xf93: 0x000c,
0xf9b: 0x0004, 0xf9d: 0x000c,
0xfb0: 0x000a, 0xfb1: 0x000a, 0xfb2: 0x000a, 0xfb3: 0x000a, 0xfb4: 0x000a, 0xfb5: 0x000a,
0xfb6: 0x000a, 0xfb7: 0x000a, 0xfb8: 0x000a, 0xfb9: 0x000a,
// Block 0x3f, offset 0xfc0
0xfc0: 0x000a, 0xfc1: 0x000a, 0xfc2: 0x000a, 0xfc3: 0x000a, 0xfc4: 0x000a, 0xfc5: 0x000a,
0xfc6: 0x000a, 0xfc7: 0x000a, 0xfc8: 0x000a, 0xfc9: 0x000a, 0xfca: 0x000a, 0xfcb: 0x000c,
0xfcc: 0x000c, 0xfcd: 0x000c, 0xfce: 0x000b, 0xfcf: 0x000c,
// Block 0x40, offset 0x1000
0x1005: 0x000c,
0x1006: 0x000c,
0x1029: 0x000c,
// Block 0x41, offset 0x1040
0x1060: 0x000c, 0x1061: 0x000c, 0x1062: 0x000c,
0x1067: 0x000c, 0x1068: 0x000c,
0x1072: 0x000c,
0x1079: 0x000c, 0x107a: 0x000c, 0x107b: 0x000c,
// Block 0x42, offset 0x1080
0x1080: 0x000a, 0x1084: 0x000a, 0x1085: 0x000a,
// Block 0x43, offset 0x10c0
0x10de: 0x000a, 0x10df: 0x000a, 0x10e0: 0x000a, 0x10e1: 0x000a, 0x10e2: 0x000a, 0x10e3: 0x000a,
0x10e4: 0x000a, 0x10e5: 0x000a, 0x10e6: 0x000a, 0x10e7: 0x000a, 0x10e8: 0x000a, 0x10e9: 0x000a,
0x10ea: 0x000a, 0x10eb: 0x000a, 0x10ec: 0x000a, 0x10ed: 0x000a, 0x10ee: 0x000a, 0x10ef: 0x000a,
0x10f0: 0x000a, 0x10f1: 0x000a, 0x10f2: 0x000a, 0x10f3: 0x000a, 0x10f4: 0x000a, 0x10f5: 0x000a,
0x10f6: 0x000a, 0x10f7: 0x000a, 0x10f8: 0x000a, 0x10f9: 0x000a, 0x10fa: 0x000a, 0x10fb: 0x000a,
0x10fc: 0x000a, 0x10fd: 0x000a, 0x10fe: 0x000a, 0x10ff: 0x000a,
// Block 0x44, offset 0x1100
0x1117: 0x000c,
0x1118: 0x000c, 0x111b: 0x000c,
// Block 0x45, offset 0x1140
0x1156: 0x000c,
0x1158: 0x000c, 0x1159: 0x000c, 0x115a: 0x000c, 0x115b: 0x000c, 0x115c: 0x000c, 0x115d: 0x000c,
0x115e: 0x000c, 0x1160: 0x000c, 0x1162: 0x000c,
0x1165: 0x000c, 0x1166: 0x000c, 0x1167: 0x000c, 0x1168: 0x000c, 0x1169: 0x000c,
0x116a: 0x000c, 0x116b: 0x000c, 0x116c: 0x000c,
0x1173: 0x000c, 0x1174: 0x000c, 0x1175: 0x000c,
0x1176: 0x000c, 0x1177: 0x000c, 0x1178: 0x000c, 0x1179: 0x000c, 0x117a: 0x000c, 0x117b: 0x000c,
0x117c: 0x000c, 0x117f: 0x000c,
// Block 0x46, offset 0x1180
0x11b0: 0x000c, 0x11b1: 0x000c, 0x11b2: 0x000c, 0x11b3: 0x000c, 0x11b4: 0x000c, 0x11b5: 0x000c,
0x11b6: 0x000c, 0x11b7: 0x000c, 0x11b8: 0x000c, 0x11b9: 0x000c, 0x11ba: 0x000c, 0x11bb: 0x000c,
0x11bc: 0x000c, 0x11bd: 0x000c, 0x11be: 0x000c, 0x11bf: 0x000c,
// Block 0x47, offset 0x11c0
0x11c0: 0x000c, 0x11c1: 0x000c, 0x11c2: 0x000c, 0x11c3: 0x000c, 0x11c4: 0x000c, 0x11c5: 0x000c,
0x11c6: 0x000c, 0x11c7: 0x000c, 0x11c8: 0x000c, 0x11c9: 0x000c, 0x11ca: 0x000c, 0x11cb: 0x000c,
0x11cc: 0x000c, 0x11cd: 0x000c, 0x11ce: 0x000c,
// Block 0x48, offset 0x1200
0x1200: 0x000c, 0x1201: 0x000c, 0x1202: 0x000c, 0x1203: 0x000c,
0x1234: 0x000c,
0x1236: 0x000c, 0x1237: 0x000c, 0x1238: 0x000c, 0x1239: 0x000c, 0x123a: 0x000c,
0x123c: 0x000c,
// Block 0x49, offset 0x1240
0x1242: 0x000c,
0x126b: 0x000c, 0x126c: 0x000c, 0x126d: 0x000c, 0x126e: 0x000c, 0x126f: 0x000c,
0x1270: 0x000c, 0x1271: 0x000c, 0x1272: 0x000c, 0x1273: 0x000c,
// Block 0x4a, offset 0x1280
0x1280: 0x000c, 0x1281: 0x000c,
0x12a2: 0x000c, 0x12a3: 0x000c,
0x12a4: 0x000c, 0x12a5: 0x000c, 0x12a8: 0x000c, 0x12a9: 0x000c,
0x12ab: 0x000c, 0x12ac: 0x000c, 0x12ad: 0x000c,
// Block 0x4b, offset 0x12c0
0x12e6: 0x000c, 0x12e8: 0x000c, 0x12e9: 0x000c,
0x12ed: 0x000c, 0x12ef: 0x000c,
0x12f0: 0x000c, 0x12f1: 0x000c,
// Block 0x4c, offset 0x1300
0x132c: 0x000c, 0x132d: 0x000c, 0x132e: 0x000c, 0x132f: 0x000c,
0x1330: 0x000c, 0x1331: 0x000c, 0x1332: 0x000c, 0x1333: 0x000c,
0x1336: 0x000c, 0x1337: 0x000c,
// Block 0x4d, offset 0x1340
0x1350: 0x000c, 0x1351: 0x000c,
0x1352: 0x000c, 0x1354: 0x000c, 0x1355: 0x000c, 0x1356: 0x000c, 0x1357: 0x000c,
0x1358: 0x000c, 0x1359: 0x000c, 0x135a: 0x000c, 0x135b: 0x000c, 0x135c: 0x000c, 0x135d: 0x000c,
0x135e: 0x000c, 0x135f: 0x000c, 0x1360: 0x000c, 0x1362: 0x000c, 0x1363: 0x000c,
0x1364: 0x000c, 0x1365: 0x000c, 0x1366: 0x000c, 0x1367: 0x000c, 0x1368: 0x000c,
0x136d: 0x000c,
0x1374: 0x000c,
0x1378: 0x000c, 0x1379: 0x000c,
// Block 0x4e, offset 0x1380
0x13bd: 0x000a, 0x13bf: 0x000a,
// Block 0x4f, offset 0x13c0
0x13c0: 0x000a, 0x13c1: 0x000a,
0x13cd: 0x000a, 0x13ce: 0x000a, 0x13cf: 0x000a,
0x13dd: 0x000a,
0x13de: 0x000a, 0x13df: 0x000a,
0x13ed: 0x000a, 0x13ee: 0x000a, 0x13ef: 0x000a,
0x13fd: 0x000a, 0x13fe: 0x000a,
// Block 0x50, offset 0x1400
0x1400: 0x0009, 0x1401: 0x0009, 0x1402: 0x0009, 0x1403: 0x0009, 0x1404: 0x0009, 0x1405: 0x0009,
0x1406: 0x0009, 0x1407: 0x0009, 0x1408: 0x0009, 0x1409: 0x0009, 0x140a: 0x0009, 0x140b: 0x000b,
0x140c: 0x000b, 0x140d: 0x000b, 0x140f: 0x0001, 0x1410: 0x000a, 0x1411: 0x000a,
0x1412: 0x000a, 0x1413: 0x000a, 0x1414: 0x000a, 0x1415: 0x000a, 0x1416: 0x000a, 0x1417: 0x000a,
0x1418: 0x000a, 0x1419: 0x000a, 0x141a: 0x000a, 0x141b: 0x000a, 0x141c: 0x000a, 0x141d: 0x000a,
0x141e: 0x000a, 0x141f: 0x000a, 0x1420: 0x000a, 0x1421: 0x000a, 0x1422: 0x000a, 0x1423: 0x000a,
0x1424: 0x000a, 0x1425: 0x000a, 0x1426: 0x000a, 0x1427: 0x000a, 0x1428: 0x0009, 0x1429: 0x0007,
0x142a: 0x000e, 0x142b: 0x000e, 0x142c: 0x000e, 0x142d: 0x000e, 0x142e: 0x000e, 0x142f: 0x0006,
0x1430: 0x0004, 0x1431: 0x0004, 0x1432: 0x0004, 0x1433: 0x0004, 0x1434: 0x0004, 0x1435: 0x000a,
0x1436: 0x000a, 0x1437: 0x000a, 0x1438: 0x000a, 0x1439: 0x000a, 0x143a: 0x000a, 0x143b: 0x000a,
0x143c: 0x000a, 0x143d: 0x000a, 0x143e: 0x000a, 0x143f: 0x000a,
// Block 0x51, offset 0x1440
0x1440: 0x000a, 0x1441: 0x000a, 0x1442: 0x000a, 0x1443: 0x000a, 0x1444: 0x0006, 0x1445: 0x009a,
0x1446: 0x008a, 0x1447: 0x000a, 0x1448: 0x000a, 0x1449: 0x000a, 0x144a: 0x000a, 0x144b: 0x000a,
0x144c: 0x000a, 0x144d: 0x000a, 0x144e: 0x000a, 0x144f: 0x000a, 0x1450: 0x000a, 0x1451: 0x000a,
0x1452: 0x000a, 0x1453: 0x000a, 0x1454: 0x000a, 0x1455: 0x000a, 0x1456: 0x000a, 0x1457: 0x000a,
0x1458: 0x000a, 0x1459: 0x000a, 0x145a: 0x000a, 0x145b: 0x000a, 0x145c: 0x000a, 0x145d: 0x000a,
0x145e: 0x000a, 0x145f: 0x0009, 0x1460: 0x000b, 0x1461: 0x000b, 0x1462: 0x000b, 0x1463: 0x000b,
0x1464: 0x000b, 0x1465: 0x000b, 0x1466: 0x000e, 0x1467: 0x000e, 0x1468: 0x000e, 0x1469: 0x000e,
0x146a: 0x000b, 0x146b: 0x000b, 0x146c: 0x000b, 0x146d: 0x000b, 0x146e: 0x000b, 0x146f: 0x000b,
0x1470: 0x0002, 0x1474: 0x0002, 0x1475: 0x0002,
0x1476: 0x0002, 0x1477: 0x0002, 0x1478: 0x0002, 0x1479: 0x0002, 0x147a: 0x0003, 0x147b: 0x0003,
0x147c: 0x000a, 0x147d: 0x009a, 0x147e: 0x008a,
// Block 0x52, offset 0x1480
0x1480: 0x0002, 0x1481: 0x0002, 0x1482: 0x0002, 0x1483: 0x0002, 0x1484: 0x0002, 0x1485: 0x0002,
0x1486: 0x0002, 0x1487: 0x0002, 0x1488: 0x0002, 0x1489: 0x0002, 0x148a: 0x0003, 0x148b: 0x0003,
0x148c: 0x000a, 0x148d: 0x009a, 0x148e: 0x008a,
0x14a0: 0x0004, 0x14a1: 0x0004, 0x14a2: 0x0004, 0x14a3: 0x0004,
0x14a4: 0x0004, 0x14a5: 0x0004, 0x14a6: 0x0004, 0x14a7: 0x0004, 0x14a8: 0x0004, 0x14a9: 0x0004,
0x14aa: 0x0004, 0x14ab: 0x0004, 0x14ac: 0x0004, 0x14ad: 0x0004, 0x14ae: 0x0004, 0x14af: 0x0004,
0x14b0: 0x0004, 0x14b1: 0x0004, 0x14b2: 0x0004, 0x14b3: 0x0004, 0x14b4: 0x0004, 0x14b5: 0x0004,
0x14b6: 0x0004, 0x14b7: 0x0004, 0x14b8: 0x0004, 0x14b9: 0x0004, 0x14ba: 0x0004, 0x14bb: 0x0004,
0x14bc: 0x0004, 0x14bd: 0x0004, 0x14be: 0x0004, 0x14bf: 0x0004,
// Block 0x53, offset 0x14c0
0x14c0: 0x0004, 0x14c1: 0x0004, 0x14c2: 0x0004, 0x14c3: 0x0004, 0x14c4: 0x0004, 0x14c5: 0x0004,
0x14c6: 0x0004, 0x14c7: 0x0004, 0x14c8: 0x0004, 0x14c9: 0x0004, 0x14ca: 0x0004, 0x14cb: 0x0004,
0x14cc: 0x0004, 0x14cd: 0x0004, 0x14ce: 0x0004, 0x14cf: 0x0004, 0x14d0: 0x000c, 0x14d1: 0x000c,
0x14d2: 0x000c, 0x14d3: 0x000c, 0x14d4: 0x000c, 0x14d5: 0x000c, 0x14d6: 0x000c, 0x14d7: 0x000c,
0x14d8: 0x000c, 0x14d9: 0x000c, 0x14da: 0x000c, 0x14db: 0x000c, 0x14dc: 0x000c, 0x14dd: 0x000c,
0x14de: 0x000c, 0x14df: 0x000c, 0x14e0: 0x000c, 0x14e1: 0x000c, 0x14e2: 0x000c, 0x14e3: 0x000c,
0x14e4: 0x000c, 0x14e5: 0x000c, 0x14e6: 0x000c, 0x14e7: 0x000c, 0x14e8: 0x000c, 0x14e9: 0x000c,
0x14ea: 0x000c, 0x14eb: 0x000c, 0x14ec: 0x000c, 0x14ed: 0x000c, 0x14ee: 0x000c, 0x14ef: 0x000c,
0x14f0: 0x000c,
// Block 0x54, offset 0x1500
0x1500: 0x000a, 0x1501: 0x000a, 0x1503: 0x000a, 0x1504: 0x000a, 0x1505: 0x000a,
0x1506: 0x000a, 0x1508: 0x000a, 0x1509: 0x000a,
0x1514: 0x000a, 0x1516: 0x000a, 0x1517: 0x000a,
0x1518: 0x000a,
0x151e: 0x000a, 0x151f: 0x000a, 0x1520: 0x000a, 0x1521: 0x000a, 0x1522: 0x000a, 0x1523: 0x000a,
0x1525: 0x000a, 0x1527: 0x000a, 0x1529: 0x000a,
0x152e: 0x0004,
0x153a: 0x000a, 0x153b: 0x000a,
// Block 0x55, offset 0x1540
0x1540: 0x000a, 0x1541: 0x000a, 0x1542: 0x000a, 0x1543: 0x000a, 0x1544: 0x000a,
0x154a: 0x000a, 0x154b: 0x000a,
0x154c: 0x000a, 0x154d: 0x000a, 0x1550: 0x000a, 0x1551: 0x000a,
0x1552: 0x000a, 0x1553: 0x000a, 0x1554: 0x000a, 0x1555: 0x000a, 0x1556: 0x000a, 0x1557: 0x000a,
0x1558: 0x000a, 0x1559: 0x000a, 0x155a: 0x000a, 0x155b: 0x000a, 0x155c: 0x000a, 0x155d: 0x000a,
0x155e: 0x000a, 0x155f: 0x000a,
// Block 0x56, offset 0x1580
0x1589: 0x000a, 0x158a: 0x000a, 0x158b: 0x000a,
0x1590: 0x000a, 0x1591: 0x000a,
0x1592: 0x000a, 0x1593: 0x000a, 0x1594: 0x000a, 0x1595: 0x000a, 0x1596: 0x000a, 0x1597: 0x000a,
0x1598: 0x000a, 0x1599: 0x000a, 0x159a: 0x000a, 0x159b: 0x000a, 0x159c: 0x000a, 0x159d: 0x000a,
0x159e: 0x000a, 0x159f: 0x000a, 0x15a0: 0x000a, 0x15a1: 0x000a, 0x15a2: 0x000a, 0x15a3: 0x000a,
0x15a4: 0x000a, 0x15a5: 0x000a, 0x15a6: 0x000a, 0x15a7: 0x000a, 0x15a8: 0x000a, 0x15a9: 0x000a,
0x15aa: 0x000a, 0x15ab: 0x000a, 0x15ac: 0x000a, 0x15ad: 0x000a, 0x15ae: 0x000a, 0x15af: 0x000a,
0x15b0: 0x000a, 0x15b1: 0x000a, 0x15b2: 0x000a, 0x15b3: 0x000a, 0x15b4: 0x000a, 0x15b5: 0x000a,
0x15b6: 0x000a, 0x15b7: 0x000a, 0x15b8: 0x000a, 0x15b9: 0x000a, 0x15ba: 0x000a, 0x15bb: 0x000a,
0x15bc: 0x000a, 0x15bd: 0x000a, 0x15be: 0x000a, 0x15bf: 0x000a,
// Block 0x57, offset 0x15c0
0x15c0: 0x000a, 0x15c1: 0x000a, 0x15c2: 0x000a, 0x15c3: 0x000a, 0x15c4: 0x000a, 0x15c5: 0x000a,
0x15c6: 0x000a, 0x15c7: 0x000a, 0x15c8: 0x000a, 0x15c9: 0x000a, 0x15ca: 0x000a, 0x15cb: 0x000a,
0x15cc: 0x000a, 0x15cd: 0x000a, 0x15ce: 0x000a, 0x15cf: 0x000a, 0x15d0: 0x000a, 0x15d1: 0x000a,
0x15d2: 0x000a, 0x15d3: 0x000a, 0x15d4: 0x000a, 0x15d5: 0x000a, 0x15d6: 0x000a, 0x15d7: 0x000a,
0x15d8: 0x000a, 0x15d9: 0x000a, 0x15da: 0x000a, 0x15db: 0x000a, 0x15dc: 0x000a, 0x15dd: 0x000a,
0x15de: 0x000a, 0x15df: 0x000a, 0x15e0: 0x000a, 0x15e1: 0x000a, 0x15e2: 0x000a, 0x15e3: 0x000a,
0x15e4: 0x000a, 0x15e5: 0x000a, 0x15e6: 0x000a, 0x15e7: 0x000a, 0x15e8: 0x000a, 0x15e9: 0x000a,
0x15ea: 0x000a, 0x15eb: 0x000a, 0x15ec: 0x000a, 0x15ed: 0x000a, 0x15ee: 0x000a, 0x15ef: 0x000a,
0x15f0: 0x000a, 0x15f1: 0x000a, 0x15f2: 0x000a, 0x15f3: 0x000a, 0x15f4: 0x000a, 0x15f5: 0x000a,
0x15f6: 0x000a, 0x15f7: 0x000a, 0x15f8: 0x000a, 0x15f9: 0x000a, 0x15fa: 0x000a, 0x15fb: 0x000a,
0x15fc: 0x000a, 0x15fd: 0x000a, 0x15fe: 0x000a, 0x15ff: 0x000a,
// Block 0x58, offset 0x1600
0x1600: 0x000a, 0x1601: 0x000a, 0x1602: 0x000a, 0x1603: 0x000a, 0x1604: 0x000a, 0x1605: 0x000a,
0x1606: 0x000a, 0x1607: 0x000a, 0x1608: 0x000a, 0x1609: 0x000a, 0x160a: 0x000a, 0x160b: 0x000a,
0x160c: 0x000a, 0x160d: 0x000a, 0x160e: 0x000a, 0x160f: 0x000a, 0x1610: 0x000a, 0x1611: 0x000a,
0x1612: 0x0003, 0x1613: 0x0004, 0x1614: 0x000a, 0x1615: 0x000a, 0x1616: 0x000a, 0x1617: 0x000a,
0x1618: 0x000a, 0x1619: 0x000a, 0x161a: 0x000a, 0x161b: 0x000a, 0x161c: 0x000a, 0x161d: 0x000a,
0x161e: 0x000a, 0x161f: 0x000a, 0x1620: 0x000a, 0x1621: 0x000a, 0x1622: 0x000a, 0x1623: 0x000a,
0x1624: 0x000a, 0x1625: 0x000a, 0x1626: 0x000a, 0x1627: 0x000a, 0x1628: 0x000a, 0x1629: 0x000a,
0x162a: 0x000a, 0x162b: 0x000a, 0x162c: 0x000a, 0x162d: 0x000a, 0x162e: 0x000a, 0x162f: 0x000a,
0x1630: 0x000a, 0x1631: 0x000a, 0x1632: 0x000a, 0x1633: 0x000a, 0x1634: 0x000a, 0x1635: 0x000a,
0x1636: 0x000a, 0x1637: 0x000a, 0x1638: 0x000a, 0x1639: 0x000a, 0x163a: 0x000a, 0x163b: 0x000a,
0x163c: 0x000a, 0x163d: 0x000a, 0x163e: 0x000a, 0x163f: 0x000a,
// Block 0x59, offset 0x1640
0x1640: 0x000a, 0x1641: 0x000a, 0x1642: 0x000a, 0x1643: 0x000a, 0x1644: 0x000a, 0x1645: 0x000a,
0x1646: 0x000a, 0x1647: 0x000a, 0x1648: 0x003a, 0x1649: 0x002a, 0x164a: 0x003a, 0x164b: 0x002a,
0x164c: 0x000a, 0x164d: 0x000a, 0x164e: 0x000a, 0x164f: 0x000a, 0x1650: 0x000a, 0x1651: 0x000a,
0x1652: 0x000a, 0x1653: 0x000a, 0x1654: 0x000a, 0x1655: 0x000a, 0x1656: 0x000a, 0x1657: 0x000a,
0x1658: 0x000a, 0x1659: 0x000a, 0x165a: 0x000a, 0x165b: 0x000a, 0x165c: 0x000a, 0x165d: 0x000a,
0x165e: 0x000a, 0x165f: 0x000a, 0x1660: 0x000a, 0x1661: 0x000a, 0x1662: 0x000a, 0x1663: 0x000a,
0x1664: 0x000a, 0x1665: 0x000a, 0x1666: 0x000a, 0x1667: 0x000a, 0x1668: 0x000a, 0x1669: 0x009a,
0x166a: 0x008a, 0x166b: 0x000a, 0x166c: 0x000a, 0x166d: 0x000a, 0x166e: 0x000a, 0x166f: 0x000a,
0x1670: 0x000a, 0x1671: 0x000a, 0x1672: 0x000a, 0x1673: 0x000a, 0x1674: 0x000a, 0x1675: 0x000a,
// Block 0x5a, offset 0x1680
0x16bb: 0x000a,
0x16bc: 0x000a, 0x16bd: 0x000a, 0x16be: 0x000a, 0x16bf: 0x000a,
// Block 0x5b, offset 0x16c0
0x16c0: 0x000a, 0x16c1: 0x000a, 0x16c2: 0x000a, 0x16c3: 0x000a, 0x16c4: 0x000a, 0x16c5: 0x000a,
0x16c6: 0x000a, 0x16c7: 0x000a, 0x16c8: 0x000a, 0x16c9: 0x000a, 0x16ca: 0x000a, 0x16cb: 0x000a,
0x16cc: 0x000a, 0x16cd: 0x000a, 0x16ce: 0x000a, 0x16cf: 0x000a, 0x16d0: 0x000a, 0x16d1: 0x000a,
0x16d2: 0x000a, 0x16d3: 0x000a, 0x16d4: 0x000a, 0x16d6: 0x000a, 0x16d7: 0x000a,
0x16d8: 0x000a, 0x16d9: 0x000a, 0x16da: 0x000a, 0x16db: 0x000a, 0x16dc: 0x000a, 0x16dd: 0x000a,
0x16de: 0x000a, 0x16df: 0x000a, 0x16e0: 0x000a, 0x16e1: 0x000a, 0x16e2: 0x000a, 0x16e3: 0x000a,
0x16e4: 0x000a, 0x16e5: 0x000a, 0x16e6: 0x000a, 0x16e7: 0x000a, 0x16e8: 0x000a, 0x16e9: 0x000a,
0x16ea: 0x000a, 0x16eb: 0x000a, 0x16ec: 0x000a, 0x16ed: 0x000a, 0x16ee: 0x000a, 0x16ef: 0x000a,
0x16f0: 0x000a, 0x16f1: 0x000a, 0x16f2: 0x000a, 0x16f3: 0x000a, 0x16f4: 0x000a, 0x16f5: 0x000a,
0x16f6: 0x000a, 0x16f7: 0x000a, 0x16f8: 0x000a, 0x16f9: 0x000a, 0x16fa: 0x000a, 0x16fb: 0x000a,
0x16fc: 0x000a, 0x16fd: 0x000a, 0x16fe: 0x000a, 0x16ff: 0x000a,
// Block 0x5c, offset 0x1700
0x1700: 0x000a, 0x1701: 0x000a, 0x1702: 0x000a, 0x1703: 0x000a, 0x1704: 0x000a, 0x1705: 0x000a,
0x1706: 0x000a, 0x1707: 0x000a, 0x1708: 0x000a, 0x1709: 0x000a, 0x170a: 0x000a, 0x170b: 0x000a,
0x170c: 0x000a, 0x170d: 0x000a, 0x170e: 0x000a, 0x170f: 0x000a, 0x1710: 0x000a, 0x1711: 0x000a,
0x1712: 0x000a, 0x1713: 0x000a, 0x1714: 0x000a, 0x1715: 0x000a, 0x1716: 0x000a, 0x1717: 0x000a,
0x1718: 0x000a, 0x1719: 0x000a, 0x171a: 0x000a, 0x171b: 0x000a, 0x171c: 0x000a, 0x171d: 0x000a,
0x171e: 0x000a, 0x171f: 0x000a, 0x1720: 0x000a, 0x1721: 0x000a, 0x1722: 0x000a, 0x1723: 0x000a,
0x1724: 0x000a, 0x1725: 0x000a, 0x1726: 0x000a,
// Block 0x5d, offset 0x1740
0x1740: 0x000a, 0x1741: 0x000a, 0x1742: 0x000a, 0x1743: 0x000a, 0x1744: 0x000a, 0x1745: 0x000a,
0x1746: 0x000a, 0x1747: 0x000a, 0x1748: 0x000a, 0x1749: 0x000a, 0x174a: 0x000a,
0x1760: 0x000a, 0x1761: 0x000a, 0x1762: 0x000a, 0x1763: 0x000a,
0x1764: 0x000a, 0x1765: 0x000a, 0x1766: 0x000a, 0x1767: 0x000a, 0x1768: 0x000a, 0x1769: 0x000a,
0x176a: 0x000a, 0x176b: 0x000a, 0x176c: 0x000a, 0x176d: 0x000a, 0x176e: 0x000a, 0x176f: 0x000a,
0x1770: 0x000a, 0x1771: 0x000a, 0x1772: 0x000a, 0x1773: 0x000a, 0x1774: 0x000a, 0x1775: 0x000a,
0x1776: 0x000a, 0x1777: 0x000a, 0x1778: 0x000a, 0x1779: 0x000a, 0x177a: 0x000a, 0x177b: 0x000a,
0x177c: 0x000a, 0x177d: 0x000a, 0x177e: 0x000a, 0x177f: 0x000a,
// Block 0x5e, offset 0x1780
0x1780: 0x000a, 0x1781: 0x000a, 0x1782: 0x000a, 0x1783: 0x000a, 0x1784: 0x000a, 0x1785: 0x000a,
0x1786: 0x000a, 0x1787: 0x000a, 0x1788: 0x0002, 0x1789: 0x0002, 0x178a: 0x0002, 0x178b: 0x0002,
0x178c: 0x0002, 0x178d: 0x0002, 0x178e: 0x0002, 0x178f: 0x0002, 0x1790: 0x0002, 0x1791: 0x0002,
0x1792: 0x0002, 0x1793: 0x0002, 0x1794: 0x0002, 0x1795: 0x0002, 0x1796: 0x0002, 0x1797: 0x0002,
0x1798: 0x0002, 0x1799: 0x0002, 0x179a: 0x0002, 0x179b: 0x0002,
// Block 0x5f, offset 0x17c0
0x17ea: 0x000a, 0x17eb: 0x000a, 0x17ec: 0x000a, 0x17ed: 0x000a, 0x17ee: 0x000a, 0x17ef: 0x000a,
0x17f0: 0x000a, 0x17f1: 0x000a, 0x17f2: 0x000a, 0x17f3: 0x000a, 0x17f4: 0x000a, 0x17f5: 0x000a,
0x17f6: 0x000a, 0x17f7: 0x000a, 0x17f8: 0x000a, 0x17f9: 0x000a, 0x17fa: 0x000a, 0x17fb: 0x000a,
0x17fc: 0x000a, 0x17fd: 0x000a, 0x17fe: 0x000a, 0x17ff: 0x000a,
// Block 0x60, offset 0x1800
0x1800: 0x000a, 0x1801: 0x000a, 0x1802: 0x000a, 0x1803: 0x000a, 0x1804: 0x000a, 0x1805: 0x000a,
0x1806: 0x000a, 0x1807: 0x000a, 0x1808: 0x000a, 0x1809: 0x000a, 0x180a: 0x000a, 0x180b: 0x000a,
0x180c: 0x000a, 0x180d: 0x000a, 0x180e: 0x000a, 0x180f: 0x000a, 0x1810: 0x000a, 0x1811: 0x000a,
0x1812: 0x000a, 0x1813: 0x000a, 0x1814: 0x000a, 0x1815: 0x000a, 0x1816: 0x000a, 0x1817: 0x000a,
0x1818: 0x000a, 0x1819: 0x000a, 0x181a: 0x000a, 0x181b: 0x000a, 0x181c: 0x000a, 0x181d: 0x000a,
0x181e: 0x000a, 0x181f: 0x000a, 0x1820: 0x000a, 0x1821: 0x000a, 0x1822: 0x000a, 0x1823: 0x000a,
0x1824: 0x000a, 0x1825: 0x000a, 0x1826: 0x000a, 0x1827: 0x000a, 0x1828: 0x000a, 0x1829: 0x000a,
0x182a: 0x000a, 0x182b: 0x000a, 0x182d: 0x000a, 0x182e: 0x000a, 0x182f: 0x000a,
0x1830: 0x000a, 0x1831: 0x000a, 0x1832: 0x000a, 0x1833: 0x000a, 0x1834: 0x000a, 0x1835: 0x000a,
0x1836: 0x000a, 0x1837: 0x000a, 0x1838: 0x000a, 0x1839: 0x000a, 0x183a: 0x000a, 0x183b: 0x000a,
0x183c: 0x000a, 0x183d: 0x000a, 0x183e: 0x000a, 0x183f: 0x000a,
// Block 0x61, offset 0x1840
0x1840: 0x000a, 0x1841: 0x000a, 0x1842: 0x000a, 0x1843: 0x000a, 0x1844: 0x000a, 0x1845: 0x000a,
0x1846: 0x000a, 0x1847: 0x000a, 0x1848: 0x000a, 0x1849: 0x000a, 0x184a: 0x000a, 0x184b: 0x000a,
0x184c: 0x000a, 0x184d: 0x000a, 0x184e: 0x000a, 0x184f: 0x000a, 0x1850: 0x000a, 0x1851: 0x000a,
0x1852: 0x000a, 0x1853: 0x000a, 0x1854: 0x000a, 0x1855: 0x000a, 0x1856: 0x000a, 0x1857: 0x000a,
0x1858: 0x000a, 0x1859: 0x000a, 0x185a: 0x000a, 0x185b: 0x000a, 0x185c: 0x000a, 0x185d: 0x000a,
0x185e: 0x000a, 0x185f: 0x000a, 0x1860: 0x000a, 0x1861: 0x000a, 0x1862: 0x000a, 0x1863: 0x000a,
0x1864: 0x000a, 0x1865: 0x000a, 0x1866: 0x000a, 0x1867: 0x000a, 0x1868: 0x003a, 0x1869: 0x002a,
0x186a: 0x003a, 0x186b: 0x002a, 0x186c: 0x003a, 0x186d: 0x002a, 0x186e: 0x003a, 0x186f: 0x002a,
0x1870: 0x003a, 0x1871: 0x002a, 0x1872: 0x003a, 0x1873: 0x002a, 0x1874: 0x003a, 0x1875: 0x002a,
0x1876: 0x000a, 0x1877: 0x000a, 0x1878: 0x000a, 0x1879: 0x000a, 0x187a: 0x000a, 0x187b: 0x000a,
0x187c: 0x000a, 0x187d: 0x000a, 0x187e: 0x000a, 0x187f: 0x000a,
// Block 0x62, offset 0x1880
0x1880: 0x000a, 0x1881: 0x000a, 0x1882: 0x000a, 0x1883: 0x000a, 0x1884: 0x000a, 0x1885: 0x009a,
0x1886: 0x008a, 0x1887: 0x000a, 0x1888: 0x000a, 0x1889: 0x000a, 0x188a: 0x000a, 0x188b: 0x000a,
0x188c: 0x000a, 0x188d: 0x000a, 0x188e: 0x000a, 0x188f: 0x000a, 0x1890: 0x000a, 0x1891: 0x000a,
0x1892: 0x000a, 0x1893: 0x000a, 0x1894: 0x000a, 0x1895: 0x000a, 0x1896: 0x000a, 0x1897: 0x000a,
0x1898: 0x000a, 0x1899: 0x000a, 0x189a: 0x000a, 0x189b: 0x000a, 0x189c: 0x000a, 0x189d: 0x000a,
0x189e: 0x000a, 0x189f: 0x000a, 0x18a0: 0x000a, 0x18a1: 0x000a, 0x18a2: 0x000a, 0x18a3: 0x000a,
0x18a4: 0x000a, 0x18a5: 0x000a, 0x18a6: 0x003a, 0x18a7: 0x002a, 0x18a8: 0x003a, 0x18a9: 0x002a,
0x18aa: 0x003a, 0x18ab: 0x002a, 0x18ac: 0x003a, 0x18ad: 0x002a, 0x18ae: 0x003a, 0x18af: 0x002a,
0x18b0: 0x000a, 0x18b1: 0x000a, 0x18b2: 0x000a, 0x18b3: 0x000a, 0x18b4: 0x000a, 0x18b5: 0x000a,
0x18b6: 0x000a, 0x18b7: 0x000a, 0x18b8: 0x000a, 0x18b9: 0x000a, 0x18ba: 0x000a, 0x18bb: 0x000a,
0x18bc: 0x000a, 0x18bd: 0x000a, 0x18be: 0x000a, 0x18bf: 0x000a,
// Block 0x63, offset 0x18c0
0x18c0: 0x000a, 0x18c1: 0x000a, 0x18c2: 0x000a, 0x18c3: 0x007a, 0x18c4: 0x006a, 0x18c5: 0x009a,
0x18c6: 0x008a, 0x18c7: 0x00ba, 0x18c8: 0x00aa, 0x18c9: 0x009a, 0x18ca: 0x008a, 0x18cb: 0x007a,
0x18cc: 0x006a, 0x18cd: 0x00da, 0x18ce: 0x002a, 0x18cf: 0x003a, 0x18d0: 0x00ca, 0x18d1: 0x009a,
0x18d2: 0x008a, 0x18d3: 0x007a, 0x18d4: 0x006a, 0x18d5: 0x009a, 0x18d6: 0x008a, 0x18d7: 0x00ba,
0x18d8: 0x00aa, 0x18d9: 0x000a, 0x18da: 0x000a, 0x18db: 0x000a, 0x18dc: 0x000a, 0x18dd: 0x000a,
0x18de: 0x000a, 0x18df: 0x000a, 0x18e0: 0x000a, 0x18e1: 0x000a, 0x18e2: 0x000a, 0x18e3: 0x000a,
0x18e4: 0x000a, 0x18e5: 0x000a, 0x18e6: 0x000a, 0x18e7: 0x000a, 0x18e8: 0x000a, 0x18e9: 0x000a,
0x18ea: 0x000a, 0x18eb: 0x000a, 0x18ec: 0x000a, 0x18ed: 0x000a, 0x18ee: 0x000a, 0x18ef: 0x000a,
0x18f0: 0x000a, 0x18f1: 0x000a, 0x18f2: 0x000a, 0x18f3: 0x000a, 0x18f4: 0x000a, 0x18f5: 0x000a,
0x18f6: 0x000a, 0x18f7: 0x000a, 0x18f8: 0x000a, 0x18f9: 0x000a, 0x18fa: 0x000a, 0x18fb: 0x000a,
0x18fc: 0x000a, 0x18fd: 0x000a, 0x18fe: 0x000a, 0x18ff: 0x000a,
// Block 0x64, offset 0x1900
0x1900: 0x000a, 0x1901: 0x000a, 0x1902: 0x000a, 0x1903: 0x000a, 0x1904: 0x000a, 0x1905: 0x000a,
0x1906: 0x000a, 0x1907: 0x000a, 0x1908: 0x000a, 0x1909: 0x000a, 0x190a: 0x000a, 0x190b: 0x000a,
0x190c: 0x000a, 0x190d: 0x000a, 0x190e: 0x000a, 0x190f: 0x000a, 0x1910: 0x000a, 0x1911: 0x000a,
0x1912: 0x000a, 0x1913: 0x000a, 0x1914: 0x000a, 0x1915: 0x000a, 0x1916: 0x000a, 0x1917: 0x000a,
0x1918: 0x003a, 0x1919: 0x002a, 0x191a: 0x003a, 0x191b: 0x002a, 0x191c: 0x000a, 0x191d: 0x000a,
0x191e: 0x000a, 0x191f: 0x000a, 0x1920: 0x000a, 0x1921: 0x000a, 0x1922: 0x000a, 0x1923: 0x000a,
0x1924: 0x000a, 0x1925: 0x000a, 0x1926: 0x000a, 0x1927: 0x000a, 0x1928: 0x000a, 0x1929: 0x000a,
0x192a: 0x000a, 0x192b: 0x000a, 0x192c: 0x000a, 0x192d: 0x000a, 0x192e: 0x000a, 0x192f: 0x000a,
0x1930: 0x000a, 0x1931: 0x000a, 0x1932: 0x000a, 0x1933: 0x000a, 0x1934: 0x000a, 0x1935: 0x000a,
0x1936: 0x000a, 0x1937: 0x000a, 0x1938: 0x000a, 0x1939: 0x000a, 0x193a: 0x000a, 0x193b: 0x000a,
0x193c: 0x003a, 0x193d: 0x002a, 0x193e: 0x000a, 0x193f: 0x000a,
// Block 0x65, offset 0x1940
0x1940: 0x000a, 0x1941: 0x000a, 0x1942: 0x000a, 0x1943: 0x000a, 0x1944: 0x000a, 0x1945: 0x000a,
0x1946: 0x000a, 0x1947: 0x000a, 0x1948: 0x000a, 0x1949: 0x000a, 0x194a: 0x000a, 0x194b: 0x000a,
0x194c: 0x000a, 0x194d: 0x000a, 0x194e: 0x000a, 0x194f: 0x000a, 0x1950: 0x000a, 0x1951: 0x000a,
0x1952: 0x000a, 0x1953: 0x000a, 0x1954: 0x000a, 0x1955: 0x000a, 0x1956: 0x000a, 0x1957: 0x000a,
0x1958: 0x000a, 0x1959: 0x000a, 0x195a: 0x000a, 0x195b: 0x000a, 0x195c: 0x000a, 0x195d: 0x000a,
0x195e: 0x000a, 0x195f: 0x000a, 0x1960: 0x000a, 0x1961: 0x000a, 0x1962: 0x000a, 0x1963: 0x000a,
0x1964: 0x000a, 0x1965: 0x000a, 0x1966: 0x000a, 0x1967: 0x000a, 0x1968: 0x000a, 0x1969: 0x000a,
0x196a: 0x000a, 0x196b: 0x000a, 0x196c: 0x000a, 0x196d: 0x000a, 0x196e: 0x000a, 0x196f: 0x000a,
0x1970: 0x000a, 0x1971: 0x000a, 0x1972: 0x000a, 0x1973: 0x000a,
0x1976: 0x000a, 0x1977: 0x000a, 0x1978: 0x000a, 0x1979: 0x000a, 0x197a: 0x000a, 0x197b: 0x000a,
0x197c: 0x000a, 0x197d: 0x000a, 0x197e: 0x000a, 0x197f: 0x000a,
// Block 0x66, offset 0x1980
0x1980: 0x000a, 0x1981: 0x000a, 0x1982: 0x000a, 0x1983: 0x000a, 0x1984: 0x000a, 0x1985: 0x000a,
0x1986: 0x000a, 0x1987: 0x000a, 0x1988: 0x000a, 0x1989: 0x000a, 0x198a: 0x000a, 0x198b: 0x000a,
0x198c: 0x000a, 0x198d: 0x000a, 0x198e: 0x000a, 0x198f: 0x000a, 0x1990: 0x000a, 0x1991: 0x000a,
0x1992: 0x000a, 0x1993: 0x000a, 0x1994: 0x000a, 0x1995: 0x000a, 0x1997: 0x000a,
0x1998: 0x000a, 0x1999: 0x000a, 0x199a: 0x000a, 0x199b: 0x000a, 0x199c: 0x000a, 0x199d: 0x000a,
0x199e: 0x000a, 0x199f: 0x000a, 0x19a0: 0x000a, 0x19a1: 0x000a, 0x19a2: 0x000a, 0x19a3: 0x000a,
0x19a4: 0x000a, 0x19a5: 0x000a, 0x19a6: 0x000a, 0x19a7: 0x000a, 0x19a8: 0x000a, 0x19a9: 0x000a,
0x19aa: 0x000a, 0x19ab: 0x000a, 0x19ac: 0x000a, 0x19ad: 0x000a, 0x19ae: 0x000a, 0x19af: 0x000a,
0x19b0: 0x000a, 0x19b1: 0x000a, 0x19b2: 0x000a, 0x19b3: 0x000a, 0x19b4: 0x000a, 0x19b5: 0x000a,
0x19b6: 0x000a, 0x19b7: 0x000a, 0x19b8: 0x000a, 0x19b9: 0x000a, 0x19ba: 0x000a, 0x19bb: 0x000a,
0x19bc: 0x000a, 0x19bd: 0x000a, 0x19be: 0x000a, 0x19bf: 0x000a,
// Block 0x67, offset 0x19c0
0x19e5: 0x000a, 0x19e6: 0x000a, 0x19e7: 0x000a, 0x19e8: 0x000a, 0x19e9: 0x000a,
0x19ea: 0x000a, 0x19ef: 0x000c,
0x19f0: 0x000c, 0x19f1: 0x000c,
0x19f9: 0x000a, 0x19fa: 0x000a, 0x19fb: 0x000a,
0x19fc: 0x000a, 0x19fd: 0x000a, 0x19fe: 0x000a, 0x19ff: 0x000a,
// Block 0x68, offset 0x1a00
0x1a3f: 0x000c,
// Block 0x69, offset 0x1a40
0x1a60: 0x000c, 0x1a61: 0x000c, 0x1a62: 0x000c, 0x1a63: 0x000c,
0x1a64: 0x000c, 0x1a65: 0x000c, 0x1a66: 0x000c, 0x1a67: 0x000c, 0x1a68: 0x000c, 0x1a69: 0x000c,
0x1a6a: 0x000c, 0x1a6b: 0x000c, 0x1a6c: 0x000c, 0x1a6d: 0x000c, 0x1a6e: 0x000c, 0x1a6f: 0x000c,
0x1a70: 0x000c, 0x1a71: 0x000c, 0x1a72: 0x000c, 0x1a73: 0x000c, 0x1a74: 0x000c, 0x1a75: 0x000c,
0x1a76: 0x000c, 0x1a77: 0x000c, 0x1a78: 0x000c, 0x1a79: 0x000c, 0x1a7a: 0x000c, 0x1a7b: 0x000c,
0x1a7c: 0x000c, 0x1a7d: 0x000c, 0x1a7e: 0x000c, 0x1a7f: 0x000c,
// Block 0x6a, offset 0x1a80
0x1a80: 0x000a, 0x1a81: 0x000a, 0x1a82: 0x000a, 0x1a83: 0x000a, 0x1a84: 0x000a, 0x1a85: 0x000a,
0x1a86: 0x000a, 0x1a87: 0x000a, 0x1a88: 0x000a, 0x1a89: 0x000a, 0x1a8a: 0x000a, 0x1a8b: 0x000a,
0x1a8c: 0x000a, 0x1a8d: 0x000a, 0x1a8e: 0x000a, 0x1a8f: 0x000a, 0x1a90: 0x000a, 0x1a91: 0x000a,
0x1a92: 0x000a, 0x1a93: 0x000a, 0x1a94: 0x000a, 0x1a95: 0x000a, 0x1a96: 0x000a, 0x1a97: 0x000a,
0x1a98: 0x000a, 0x1a99: 0x000a, 0x1a9a: 0x000a, 0x1a9b: 0x000a, 0x1a9c: 0x000a, 0x1a9d: 0x000a,
0x1a9e: 0x000a, 0x1a9f: 0x000a, 0x1aa0: 0x000a, 0x1aa1: 0x000a, 0x1aa2: 0x003a, 0x1aa3: 0x002a,
0x1aa4: 0x003a, 0x1aa5: 0x002a, 0x1aa6: 0x003a, 0x1aa7: 0x002a, 0x1aa8: 0x003a, 0x1aa9: 0x002a,
0x1aaa: 0x000a, 0x1aab: 0x000a, 0x1aac: 0x000a, 0x1aad: 0x000a, 0x1aae: 0x000a, 0x1aaf: 0x000a,
0x1ab0: 0x000a, 0x1ab1: 0x000a, 0x1ab2: 0x000a, 0x1ab3: 0x000a, 0x1ab4: 0x000a, 0x1ab5: 0x000a,
0x1ab6: 0x000a, 0x1ab7: 0x000a, 0x1ab8: 0x000a, 0x1ab9: 0x000a, 0x1aba: 0x000a, 0x1abb: 0x000a,
0x1abc: 0x000a, 0x1abd: 0x000a, 0x1abe: 0x000a, 0x1abf: 0x000a,
// Block 0x6b, offset 0x1ac0
0x1ac0: 0x000a, 0x1ac1: 0x000a, 0x1ac2: 0x000a, 0x1ac3: 0x000a, 0x1ac4: 0x000a, 0x1ac5: 0x000a,
0x1ac6: 0x000a, 0x1ac7: 0x000a, 0x1ac8: 0x000a, 0x1ac9: 0x000a, 0x1aca: 0x000a, 0x1acb: 0x000a,
0x1acc: 0x000a, 0x1acd: 0x000a, 0x1ace: 0x000a, 0x1acf: 0x000a, 0x1ad0: 0x000a, 0x1ad1: 0x000a,
0x1ad2: 0x000a, 0x1ad3: 0x000a, 0x1ad4: 0x000a, 0x1ad5: 0x009a, 0x1ad6: 0x008a, 0x1ad7: 0x00ba,
0x1ad8: 0x00aa, 0x1ad9: 0x009a, 0x1ada: 0x008a, 0x1adb: 0x007a, 0x1adc: 0x006a, 0x1add: 0x000a,
// Block 0x6c, offset 0x1b00
0x1b00: 0x000a, 0x1b01: 0x000a, 0x1b02: 0x000a, 0x1b03: 0x000a, 0x1b04: 0x000a, 0x1b05: 0x000a,
0x1b06: 0x000a, 0x1b07: 0x000a, 0x1b08: 0x000a, 0x1b09: 0x000a, 0x1b0a: 0x000a, 0x1b0b: 0x000a,
0x1b0c: 0x000a, 0x1b0d: 0x000a, 0x1b0e: 0x000a, 0x1b0f: 0x000a, 0x1b10: 0x000a, 0x1b11: 0x000a,
0x1b12: 0x000a, 0x1b13: 0x000a, 0x1b14: 0x000a, 0x1b15: 0x000a, 0x1b16: 0x000a, 0x1b17: 0x000a,
0x1b18: 0x000a, 0x1b19: 0x000a, 0x1b1b: 0x000a, 0x1b1c: 0x000a, 0x1b1d: 0x000a,
0x1b1e: 0x000a, 0x1b1f: 0x000a, 0x1b20: 0x000a, 0x1b21: 0x000a, 0x1b22: 0x000a, 0x1b23: 0x000a,
0x1b24: 0x000a, 0x1b25: 0x000a, 0x1b26: 0x000a, 0x1b27: 0x000a, 0x1b28: 0x000a, 0x1b29: 0x000a,
0x1b2a: 0x000a, 0x1b2b: 0x000a, 0x1b2c: 0x000a, 0x1b2d: 0x000a, 0x1b2e: 0x000a, 0x1b2f: 0x000a,
0x1b30: 0x000a, 0x1b31: 0x000a, 0x1b32: 0x000a, 0x1b33: 0x000a, 0x1b34: 0x000a, 0x1b35: 0x000a,
0x1b36: 0x000a, 0x1b37: 0x000a, 0x1b38: 0x000a, 0x1b39: 0x000a, 0x1b3a: 0x000a, 0x1b3b: 0x000a,
0x1b3c: 0x000a, 0x1b3d: 0x000a, 0x1b3e: 0x000a, 0x1b3f: 0x000a,
// Block 0x6d, offset 0x1b40
0x1b40: 0x000a, 0x1b41: 0x000a, 0x1b42: 0x000a, 0x1b43: 0x000a, 0x1b44: 0x000a, 0x1b45: 0x000a,
0x1b46: 0x000a, 0x1b47: 0x000a, 0x1b48: 0x000a, 0x1b49: 0x000a, 0x1b4a: 0x000a, 0x1b4b: 0x000a,
0x1b4c: 0x000a, 0x1b4d: 0x000a, 0x1b4e: 0x000a, 0x1b4f: 0x000a, 0x1b50: 0x000a, 0x1b51: 0x000a,
0x1b52: 0x000a, 0x1b53: 0x000a, 0x1b54: 0x000a, 0x1b55: 0x000a, 0x1b56: 0x000a, 0x1b57: 0x000a,
0x1b58: 0x000a, 0x1b59: 0x000a, 0x1b5a: 0x000a, 0x1b5b: 0x000a, 0x1b5c: 0x000a, 0x1b5d: 0x000a,
0x1b5e: 0x000a, 0x1b5f: 0x000a, 0x1b60: 0x000a, 0x1b61: 0x000a, 0x1b62: 0x000a, 0x1b63: 0x000a,
0x1b64: 0x000a, 0x1b65: 0x000a, 0x1b66: 0x000a, 0x1b67: 0x000a, 0x1b68: 0x000a, 0x1b69: 0x000a,
0x1b6a: 0x000a, 0x1b6b: 0x000a, 0x1b6c: 0x000a, 0x1b6d: 0x000a, 0x1b6e: 0x000a, 0x1b6f: 0x000a,
0x1b70: 0x000a, 0x1b71: 0x000a, 0x1b72: 0x000a, 0x1b73: 0x000a,
// Block 0x6e, offset 0x1b80
0x1b80: 0x000a, 0x1b81: 0x000a, 0x1b82: 0x000a, 0x1b83: 0x000a, 0x1b84: 0x000a, 0x1b85: 0x000a,
0x1b86: 0x000a, 0x1b87: 0x000a, 0x1b88: 0x000a, 0x1b89: 0x000a, 0x1b8a: 0x000a, 0x1b8b: 0x000a,
0x1b8c: 0x000a, 0x1b8d: 0x000a, 0x1b8e: 0x000a, 0x1b8f: 0x000a, 0x1b90: 0x000a, 0x1b91: 0x000a,
0x1b92: 0x000a, 0x1b93: 0x000a, 0x1b94: 0x000a, 0x1b95: 0x000a,
0x1bb0: 0x000a, 0x1bb1: 0x000a, 0x1bb2: 0x000a, 0x1bb3: 0x000a, 0x1bb4: 0x000a, 0x1bb5: 0x000a,
0x1bb6: 0x000a, 0x1bb7: 0x000a, 0x1bb8: 0x000a, 0x1bb9: 0x000a, 0x1bba: 0x000a, 0x1bbb: 0x000a,
// Block 0x6f, offset 0x1bc0
0x1bc0: 0x0009, 0x1bc1: 0x000a, 0x1bc2: 0x000a, 0x1bc3: 0x000a, 0x1bc4: 0x000a,
0x1bc8: 0x003a, 0x1bc9: 0x002a, 0x1bca: 0x003a, 0x1bcb: 0x002a,
0x1bcc: 0x003a, 0x1bcd: 0x002a, 0x1bce: 0x003a, 0x1bcf: 0x002a, 0x1bd0: 0x003a, 0x1bd1: 0x002a,
0x1bd2: 0x000a, 0x1bd3: 0x000a, 0x1bd4: 0x003a, 0x1bd5: 0x002a, 0x1bd6: 0x003a, 0x1bd7: 0x002a,
0x1bd8: 0x003a, 0x1bd9: 0x002a, 0x1bda: 0x003a, 0x1bdb: 0x002a, 0x1bdc: 0x000a, 0x1bdd: 0x000a,
0x1bde: 0x000a, 0x1bdf: 0x000a, 0x1be0: 0x000a,
0x1bea: 0x000c, 0x1beb: 0x000c, 0x1bec: 0x000c, 0x1bed: 0x000c,
0x1bf0: 0x000a,
0x1bf6: 0x000a, 0x1bf7: 0x000a,
0x1bfd: 0x000a, 0x1bfe: 0x000a, 0x1bff: 0x000a,
// Block 0x70, offset 0x1c00
0x1c19: 0x000c, 0x1c1a: 0x000c, 0x1c1b: 0x000a, 0x1c1c: 0x000a,
0x1c20: 0x000a,
// Block 0x71, offset 0x1c40
0x1c7b: 0x000a,
// Block 0x72, offset 0x1c80
0x1c80: 0x000a, 0x1c81: 0x000a, 0x1c82: 0x000a, 0x1c83: 0x000a, 0x1c84: 0x000a, 0x1c85: 0x000a,
0x1c86: 0x000a, 0x1c87: 0x000a, 0x1c88: 0x000a, 0x1c89: 0x000a, 0x1c8a: 0x000a, 0x1c8b: 0x000a,
0x1c8c: 0x000a, 0x1c8d: 0x000a, 0x1c8e: 0x000a, 0x1c8f: 0x000a, 0x1c90: 0x000a, 0x1c91: 0x000a,
0x1c92: 0x000a, 0x1c93: 0x000a, 0x1c94: 0x000a, 0x1c95: 0x000a, 0x1c96: 0x000a, 0x1c97: 0x000a,
0x1c98: 0x000a, 0x1c99: 0x000a, 0x1c9a: 0x000a, 0x1c9b: 0x000a, 0x1c9c: 0x000a, 0x1c9d: 0x000a,
0x1c9e: 0x000a, 0x1c9f: 0x000a, 0x1ca0: 0x000a, 0x1ca1: 0x000a, 0x1ca2: 0x000a, 0x1ca3: 0x000a,
// Block 0x73, offset 0x1cc0
0x1cdd: 0x000a,
0x1cde: 0x000a,
// Block 0x74, offset 0x1d00
0x1d10: 0x000a, 0x1d11: 0x000a,
0x1d12: 0x000a, 0x1d13: 0x000a, 0x1d14: 0x000a, 0x1d15: 0x000a, 0x1d16: 0x000a, 0x1d17: 0x000a,
0x1d18: 0x000a, 0x1d19: 0x000a, 0x1d1a: 0x000a, 0x1d1b: 0x000a, 0x1d1c: 0x000a, 0x1d1d: 0x000a,
0x1d1e: 0x000a, 0x1d1f: 0x000a,
0x1d3c: 0x000a, 0x1d3d: 0x000a, 0x1d3e: 0x000a,
// Block 0x75, offset 0x1d40
0x1d71: 0x000a, 0x1d72: 0x000a, 0x1d73: 0x000a, 0x1d74: 0x000a, 0x1d75: 0x000a,
0x1d76: 0x000a, 0x1d77: 0x000a, 0x1d78: 0x000a, 0x1d79: 0x000a, 0x1d7a: 0x000a, 0x1d7b: 0x000a,
0x1d7c: 0x000a, 0x1d7d: 0x000a, 0x1d7e: 0x000a, 0x1d7f: 0x000a,
// Block 0x76, offset 0x1d80
0x1d8c: 0x000a, 0x1d8d: 0x000a, 0x1d8e: 0x000a, 0x1d8f: 0x000a,
// Block 0x77, offset 0x1dc0
0x1df7: 0x000a, 0x1df8: 0x000a, 0x1df9: 0x000a, 0x1dfa: 0x000a,
// Block 0x78, offset 0x1e00
0x1e1e: 0x000a, 0x1e1f: 0x000a,
0x1e3f: 0x000a,
// Block 0x79, offset 0x1e40
0x1e50: 0x000a, 0x1e51: 0x000a,
0x1e52: 0x000a, 0x1e53: 0x000a, 0x1e54: 0x000a, 0x1e55: 0x000a, 0x1e56: 0x000a, 0x1e57: 0x000a,
0x1e58: 0x000a, 0x1e59: 0x000a, 0x1e5a: 0x000a, 0x1e5b: 0x000a, 0x1e5c: 0x000a, 0x1e5d: 0x000a,
0x1e5e: 0x000a, 0x1e5f: 0x000a, 0x1e60: 0x000a, 0x1e61: 0x000a, 0x1e62: 0x000a, 0x1e63: 0x000a,
0x1e64: 0x000a, 0x1e65: 0x000a, 0x1e66: 0x000a, 0x1e67: 0x000a, 0x1e68: 0x000a, 0x1e69: 0x000a,
0x1e6a: 0x000a, 0x1e6b: 0x000a, 0x1e6c: 0x000a, 0x1e6d: 0x000a, 0x1e6e: 0x000a, 0x1e6f: 0x000a,
0x1e70: 0x000a, 0x1e71: 0x000a, 0x1e72: 0x000a, 0x1e73: 0x000a, 0x1e74: 0x000a, 0x1e75: 0x000a,
0x1e76: 0x000a, 0x1e77: 0x000a, 0x1e78: 0x000a, 0x1e79: 0x000a, 0x1e7a: 0x000a, 0x1e7b: 0x000a,
0x1e7c: 0x000a, 0x1e7d: 0x000a, 0x1e7e: 0x000a, 0x1e7f: 0x000a,
// Block 0x7a, offset 0x1e80
0x1e80: 0x000a, 0x1e81: 0x000a, 0x1e82: 0x000a, 0x1e83: 0x000a, 0x1e84: 0x000a, 0x1e85: 0x000a,
0x1e86: 0x000a,
// Block 0x7b, offset 0x1ec0
0x1ecd: 0x000a, 0x1ece: 0x000a, 0x1ecf: 0x000a,
// Block 0x7c, offset 0x1f00
0x1f2f: 0x000c,
0x1f30: 0x000c, 0x1f31: 0x000c, 0x1f32: 0x000c, 0x1f33: 0x000a, 0x1f34: 0x000c, 0x1f35: 0x000c,
0x1f36: 0x000c, 0x1f37: 0x000c, 0x1f38: 0x000c, 0x1f39: 0x000c, 0x1f3a: 0x000c, 0x1f3b: 0x000c,
0x1f3c: 0x000c, 0x1f3d: 0x000c, 0x1f3e: 0x000a, 0x1f3f: 0x000a,
// Block 0x7d, offset 0x1f40
0x1f5e: 0x000c, 0x1f5f: 0x000c,
// Block 0x7e, offset 0x1f80
0x1fb0: 0x000c, 0x1fb1: 0x000c,
// Block 0x7f, offset 0x1fc0
0x1fc0: 0x000a, 0x1fc1: 0x000a, 0x1fc2: 0x000a, 0x1fc3: 0x000a, 0x1fc4: 0x000a, 0x1fc5: 0x000a,
0x1fc6: 0x000a, 0x1fc7: 0x000a, 0x1fc8: 0x000a, 0x1fc9: 0x000a, 0x1fca: 0x000a, 0x1fcb: 0x000a,
0x1fcc: 0x000a, 0x1fcd: 0x000a, 0x1fce: 0x000a, 0x1fcf: 0x000a, 0x1fd0: 0x000a, 0x1fd1: 0x000a,
0x1fd2: 0x000a, 0x1fd3: 0x000a, 0x1fd4: 0x000a, 0x1fd5: 0x000a, 0x1fd6: 0x000a, 0x1fd7: 0x000a,
0x1fd8: 0x000a, 0x1fd9: 0x000a, 0x1fda: 0x000a, 0x1fdb: 0x000a, 0x1fdc: 0x000a, 0x1fdd: 0x000a,
0x1fde: 0x000a, 0x1fdf: 0x000a, 0x1fe0: 0x000a, 0x1fe1: 0x000a,
// Block 0x80, offset 0x2000
0x2008: 0x000a,
// Block 0x81, offset 0x2040
0x2042: 0x000c,
0x2046: 0x000c, 0x204b: 0x000c,
0x2065: 0x000c, 0x2066: 0x000c, 0x2068: 0x000a, 0x2069: 0x000a,
0x206a: 0x000a, 0x206b: 0x000a, 0x206c: 0x000c,
0x2078: 0x0004, 0x2079: 0x0004,
// Block 0x82, offset 0x2080
0x20b4: 0x000a, 0x20b5: 0x000a,
0x20b6: 0x000a, 0x20b7: 0x000a,
// Block 0x83, offset 0x20c0
0x20c4: 0x000c, 0x20c5: 0x000c,
0x20e0: 0x000c, 0x20e1: 0x000c, 0x20e2: 0x000c, 0x20e3: 0x000c,
0x20e4: 0x000c, 0x20e5: 0x000c, 0x20e6: 0x000c, 0x20e7: 0x000c, 0x20e8: 0x000c, 0x20e9: 0x000c,
0x20ea: 0x000c, 0x20eb: 0x000c, 0x20ec: 0x000c, 0x20ed: 0x000c, 0x20ee: 0x000c, 0x20ef: 0x000c,
0x20f0: 0x000c, 0x20f1: 0x000c,
0x20ff: 0x000c,
// Block 0x84, offset 0x2100
0x2126: 0x000c, 0x2127: 0x000c, 0x2128: 0x000c, 0x2129: 0x000c,
0x212a: 0x000c, 0x212b: 0x000c, 0x212c: 0x000c, 0x212d: 0x000c,
// Block 0x85, offset 0x2140
0x2147: 0x000c, 0x2148: 0x000c, 0x2149: 0x000c, 0x214a: 0x000c, 0x214b: 0x000c,
0x214c: 0x000c, 0x214d: 0x000c, 0x214e: 0x000c, 0x214f: 0x000c, 0x2150: 0x000c, 0x2151: 0x000c,
// Block 0x86, offset 0x2180
0x2180: 0x000c, 0x2181: 0x000c, 0x2182: 0x000c,
0x21b3: 0x000c,
0x21b6: 0x000c, 0x21b7: 0x000c, 0x21b8: 0x000c, 0x21b9: 0x000c,
0x21bc: 0x000c, 0x21bd: 0x000c,
// Block 0x87, offset 0x21c0
0x21e5: 0x000c,
// Block 0x88, offset 0x2200
0x2229: 0x000c,
0x222a: 0x000c, 0x222b: 0x000c, 0x222c: 0x000c, 0x222d: 0x000c, 0x222e: 0x000c,
0x2231: 0x000c, 0x2232: 0x000c, 0x2235: 0x000c,
0x2236: 0x000c,
// Block 0x89, offset 0x2240
0x2243: 0x000c,
0x224c: 0x000c,
0x227c: 0x000c,
// Block 0x8a, offset 0x2280
0x22b0: 0x000c, 0x22b2: 0x000c, 0x22b3: 0x000c, 0x22b4: 0x000c,
0x22b7: 0x000c, 0x22b8: 0x000c,
0x22be: 0x000c, 0x22bf: 0x000c,
// Block 0x8b, offset 0x22c0
0x22c1: 0x000c,
0x22ec: 0x000c, 0x22ed: 0x000c,
0x22f6: 0x000c,
// Block 0x8c, offset 0x2300
0x232a: 0x000a, 0x232b: 0x000a,
// Block 0x8d, offset 0x2340
0x2365: 0x000c, 0x2368: 0x000c,
0x236d: 0x000c,
// Block 0x8e, offset 0x2380
0x239d: 0x0001,
0x239e: 0x000c, 0x239f: 0x0001, 0x23a0: 0x0001, 0x23a1: 0x0001, 0x23a2: 0x0001, 0x23a3: 0x0001,
0x23a4: 0x0001, 0x23a5: 0x0001, 0x23a6: 0x0001, 0x23a7: 0x0001, 0x23a8: 0x0001, 0x23a9: 0x0003,
0x23aa: 0x0001, 0x23ab: 0x0001, 0x23ac: 0x0001, 0x23ad: 0x0001, 0x23ae: 0x0001, 0x23af: 0x0001,
0x23b0: 0x0001, 0x23b1: 0x0001, 0x23b2: 0x0001, 0x23b3: 0x0001, 0x23b4: 0x0001, 0x23b5: 0x0001,
0x23b6: 0x0001, 0x23b7: 0x0001, 0x23b8: 0x0001, 0x23b9: 0x0001, 0x23ba: 0x0001, 0x23bb: 0x0001,
0x23bc: 0x0001, 0x23bd: 0x0001, 0x23be: 0x0001, 0x23bf: 0x0001,
// Block 0x8f, offset 0x23c0
0x23c0: 0x0001, 0x23c1: 0x0001, 0x23c2: 0x0001, 0x23c3: 0x0001, 0x23c4: 0x0001, 0x23c5: 0x0001,
0x23c6: 0x0001, 0x23c7: 0x0001, 0x23c8: 0x0001, 0x23c9: 0x0001, 0x23ca: 0x0001, 0x23cb: 0x0001,
0x23cc: 0x0001, 0x23cd: 0x0001, 0x23ce: 0x0001, 0x23cf: 0x0001, 0x23d0: 0x000d, 0x23d1: 0x000d,
0x23d2: 0x000d, 0x23d3: 0x000d, 0x23d4: 0x000d, 0x23d5: 0x000d, 0x23d6: 0x000d, 0x23d7: 0x000d,
0x23d8: 0x000d, 0x23d9: 0x000d, 0x23da: 0x000d, 0x23db: 0x000d, 0x23dc: 0x000d, 0x23dd: 0x000d,
0x23de: 0x000d, 0x23df: 0x000d, 0x23e0: 0x000d, 0x23e1: 0x000d, 0x23e2: 0x000d, 0x23e3: 0x000d,
0x23e4: 0x000d, 0x23e5: 0x000d, 0x23e6: 0x000d, 0x23e7: 0x000d, 0x23e8: 0x000d, 0x23e9: 0x000d,
0x23ea: 0x000d, 0x23eb: 0x000d, 0x23ec: 0x000d, 0x23ed: 0x000d, 0x23ee: 0x000d, 0x23ef: 0x000d,
0x23f0: 0x000d, 0x23f1: 0x000d, 0x23f2: 0x000d, 0x23f3: 0x000d, 0x23f4: 0x000d, 0x23f5: 0x000d,
0x23f6: 0x000d, 0x23f7: 0x000d, 0x23f8: 0x000d, 0x23f9: 0x000d, 0x23fa: 0x000d, 0x23fb: 0x000d,
0x23fc: 0x000d, 0x23fd: 0x000d, 0x23fe: 0x000d, 0x23ff: 0x000d,
// Block 0x90, offset 0x2400
0x2400: 0x000d, 0x2401: 0x000d, 0x2402: 0x000d, 0x2403: 0x000d, 0x2404: 0x000d, 0x2405: 0x000d,
0x2406: 0x000d, 0x2407: 0x000d, 0x2408: 0x000d, 0x2409: 0x000d, 0x240a: 0x000d, 0x240b: 0x000d,
0x240c: 0x000d, 0x240d: 0x000d, 0x240e: 0x000d, 0x240f: 0x000d, 0x2410: 0x000d, 0x2411: 0x000d,
0x2412: 0x000d, 0x2413: 0x000d, 0x2414: 0x000d, 0x2415: 0x000d, 0x2416: 0x000d, 0x2417: 0x000d,
0x2418: 0x000d, 0x2419: 0x000d, 0x241a: 0x000d, 0x241b: 0x000d, 0x241c: 0x000d, 0x241d: 0x000d,
0x241e: 0x000d, 0x241f: 0x000d, 0x2420: 0x000d, 0x2421: 0x000d, 0x2422: 0x000d, 0x2423: 0x000d,
0x2424: 0x000d, 0x2425: 0x000d, 0x2426: 0x000d, 0x2427: 0x000d, 0x2428: 0x000d, 0x2429: 0x000d,
0x242a: 0x000d, 0x242b: 0x000d, 0x242c: 0x000d, 0x242d: 0x000d, 0x242e: 0x000d, 0x242f: 0x000d,
0x2430: 0x000d, 0x2431: 0x000d, 0x2432: 0x000d, 0x2433: 0x000d, 0x2434: 0x000d, 0x2435: 0x000d,
0x2436: 0x000d, 0x2437: 0x000d, 0x2438: 0x000d, 0x2439: 0x000d, 0x243a: 0x000d, 0x243b: 0x000d,
0x243c: 0x000d, 0x243d: 0x000d, 0x243e: 0x000a, 0x243f: 0x000a,
// Block 0x91, offset 0x2440
0x2440: 0x000a, 0x2441: 0x000a, 0x2442: 0x000a, 0x2443: 0x000a, 0x2444: 0x000a, 0x2445: 0x000a,
0x2446: 0x000a, 0x2447: 0x000a, 0x2448: 0x000a, 0x2449: 0x000a, 0x244a: 0x000a, 0x244b: 0x000a,
0x244c: 0x000a, 0x244d: 0x000a, 0x244e: 0x000a, 0x244f: 0x000a, 0x2450: 0x000d, 0x2451: 0x000d,
0x2452: 0x000d, 0x2453: 0x000d, 0x2454: 0x000d, 0x2455: 0x000d, 0x2456: 0x000d, 0x2457: 0x000d,
0x2458: 0x000d, 0x2459: 0x000d, 0x245a: 0x000d, 0x245b: 0x000d, 0x245c: 0x000d, 0x245d: 0x000d,
0x245e: 0x000d, 0x245f: 0x000d, 0x2460: 0x000d, 0x2461: 0x000d, 0x2462: 0x000d, 0x2463: 0x000d,
0x2464: 0x000d, 0x2465: 0x000d, 0x2466: 0x000d, 0x2467: 0x000d, 0x2468: 0x000d, 0x2469: 0x000d,
0x246a: 0x000d, 0x246b: 0x000d, 0x246c: 0x000d, 0x246d: 0x000d, 0x246e: 0x000d, 0x246f: 0x000d,
0x2470: 0x000d, 0x2471: 0x000d, 0x2472: 0x000d, 0x2473: 0x000d, 0x2474: 0x000d, 0x2475: 0x000d,
0x2476: 0x000d, 0x2477: 0x000d, 0x2478: 0x000d, 0x2479: 0x000d, 0x247a: 0x000d, 0x247b: 0x000d,
0x247c: 0x000d, 0x247d: 0x000d, 0x247e: 0x000d, 0x247f: 0x000d,
// Block 0x92, offset 0x2480
0x2480: 0x000d, 0x2481: 0x000d, 0x2482: 0x000d, 0x2483: 0x000d, 0x2484: 0x000d, 0x2485: 0x000d,
0x2486: 0x000d, 0x2487: 0x000d, 0x2488: 0x000d, 0x2489: 0x000d, 0x248a: 0x000d, 0x248b: 0x000d,
0x248c: 0x000d, 0x248d: 0x000d, 0x248e: 0x000d, 0x248f: 0x000a, 0x2490: 0x000b, 0x2491: 0x000b,
0x2492: 0x000b, 0x2493: 0x000b, 0x2494: 0x000b, 0x2495: 0x000b, 0x2496: 0x000b, 0x2497: 0x000b,
0x2498: 0x000b, 0x2499: 0x000b, 0x249a: 0x000b, 0x249b: 0x000b, 0x249c: 0x000b, 0x249d: 0x000b,
0x249e: 0x000b, 0x249f: 0x000b, 0x24a0: 0x000b, 0x24a1: 0x000b, 0x24a2: 0x000b, 0x24a3: 0x000b,
0x24a4: 0x000b, 0x24a5: 0x000b, 0x24a6: 0x000b, 0x24a7: 0x000b, 0x24a8: 0x000b, 0x24a9: 0x000b,
0x24aa: 0x000b, 0x24ab: 0x000b, 0x24ac: 0x000b, 0x24ad: 0x000b, 0x24ae: 0x000b, 0x24af: 0x000b,
0x24b0: 0x000d, 0x24b1: 0x000d, 0x24b2: 0x000d, 0x24b3: 0x000d, 0x24b4: 0x000d, 0x24b5: 0x000d,
0x24b6: 0x000d, 0x24b7: 0x000d, 0x24b8: 0x000d, 0x24b9: 0x000d, 0x24ba: 0x000d, 0x24bb: 0x000d,
0x24bc: 0x000d, 0x24bd: 0x000a, 0x24be: 0x000a, 0x24bf: 0x000a,
// Block 0x93, offset 0x24c0
0x24c0: 0x000c, 0x24c1: 0x000c, 0x24c2: 0x000c, 0x24c3: 0x000c, 0x24c4: 0x000c, 0x24c5: 0x000c,
0x24c6: 0x000c, 0x24c7: 0x000c, 0x24c8: 0x000c, 0x24c9: 0x000c, 0x24ca: 0x000c, 0x24cb: 0x000c,
0x24cc: 0x000c, 0x24cd: 0x000c, 0x24ce: 0x000c, 0x24cf: 0x000c, 0x24d0: 0x000a, 0x24d1: 0x000a,
0x24d2: 0x000a, 0x24d3: 0x000a, 0x24d4: 0x000a, 0x24d5: 0x000a, 0x24d6: 0x000a, 0x24d7: 0x000a,
0x24d8: 0x000a, 0x24d9: 0x000a,
0x24e0: 0x000c, 0x24e1: 0x000c, 0x24e2: 0x000c, 0x24e3: 0x000c,
0x24e4: 0x000c, 0x24e5: 0x000c, 0x24e6: 0x000c, 0x24e7: 0x000c, 0x24e8: 0x000c, 0x24e9: 0x000c,
0x24ea: 0x000c, 0x24eb: 0x000c, 0x24ec: 0x000c, 0x24ed: 0x000c, 0x24ee: 0x000c, 0x24ef: 0x000c,
0x24f0: 0x000a, 0x24f1: 0x000a, 0x24f2: 0x000a, 0x24f3: 0x000a, 0x24f4: 0x000a, 0x24f5: 0x000a,
0x24f6: 0x000a, 0x24f7: 0x000a, 0x24f8: 0x000a, 0x24f9: 0x000a, 0x24fa: 0x000a, 0x24fb: 0x000a,
0x24fc: 0x000a, 0x24fd: 0x000a, 0x24fe: 0x000a, 0x24ff: 0x000a,
// Block 0x94, offset 0x2500
0x2500: 0x000a, 0x2501: 0x000a, 0x2502: 0x000a, 0x2503: 0x000a, 0x2504: 0x000a, 0x2505: 0x000a,
0x2506: 0x000a, 0x2507: 0x000a, 0x2508: 0x000a, 0x2509: 0x000a, 0x250a: 0x000a, 0x250b: 0x000a,
0x250c: 0x000a, 0x250d: 0x000a, 0x250e: 0x000a, 0x250f: 0x000a, 0x2510: 0x0006, 0x2511: 0x000a,
0x2512: 0x0006, 0x2514: 0x000a, 0x2515: 0x0006, 0x2516: 0x000a, 0x2517: 0x000a,
0x2518: 0x000a, 0x2519: 0x009a, 0x251a: 0x008a, 0x251b: 0x007a, 0x251c: 0x006a, 0x251d: 0x009a,
0x251e: 0x008a, 0x251f: 0x0004, 0x2520: 0x000a, 0x2521: 0x000a, 0x2522: 0x0003, 0x2523: 0x0003,
0x2524: 0x000a, 0x2525: 0x000a, 0x2526: 0x000a, 0x2528: 0x000a, 0x2529: 0x0004,
0x252a: 0x0004, 0x252b: 0x000a,
0x2530: 0x000d, 0x2531: 0x000d, 0x2532: 0x000d, 0x2533: 0x000d, 0x2534: 0x000d, 0x2535: 0x000d,
0x2536: 0x000d, 0x2537: 0x000d, 0x2538: 0x000d, 0x2539: 0x000d, 0x253a: 0x000d, 0x253b: 0x000d,
0x253c: 0x000d, 0x253d: 0x000d, 0x253e: 0x000d, 0x253f: 0x000d,
// Block 0x95, offset 0x2540
0x2540: 0x000d, 0x2541: 0x000d, 0x2542: 0x000d, 0x2543: 0x000d, 0x2544: 0x000d, 0x2545: 0x000d,
0x2546: 0x000d, 0x2547: 0x000d, 0x2548: 0x000d, 0x2549: 0x000d, 0x254a: 0x000d, 0x254b: 0x000d,
0x254c: 0x000d, 0x254d: 0x000d, 0x254e: 0x000d, 0x254f: 0x000d, 0x2550: 0x000d, 0x2551: 0x000d,
0x2552: 0x000d, 0x2553: 0x000d, 0x2554: 0x000d, 0x2555: 0x000d, 0x2556: 0x000d, 0x2557: 0x000d,
0x2558: 0x000d, 0x2559: 0x000d, 0x255a: 0x000d, 0x255b: 0x000d, 0x255c: 0x000d, 0x255d: 0x000d,
0x255e: 0x000d, 0x255f: 0x000d, 0x2560: 0x000d, 0x2561: 0x000d, 0x2562: 0x000d, 0x2563: 0x000d,
0x2564: 0x000d, 0x2565: 0x000d, 0x2566: 0x000d, 0x2567: 0x000d, 0x2568: 0x000d, 0x2569: 0x000d,
0x256a: 0x000d, 0x256b: 0x000d, 0x256c: 0x000d, 0x256d: 0x000d, 0x256e: 0x000d, 0x256f: 0x000d,
0x2570: 0x000d, 0x2571: 0x000d, 0x2572: 0x000d, 0x2573: 0x000d, 0x2574: 0x000d, 0x2575: 0x000d,
0x2576: 0x000d, 0x2577: 0x000d, 0x2578: 0x000d, 0x2579: 0x000d, 0x257a: 0x000d, 0x257b: 0x000d,
0x257c: 0x000d, 0x257d: 0x000d, 0x257e: 0x000d, 0x257f: 0x000b,
// Block 0x96, offset 0x2580
0x2581: 0x000a, 0x2582: 0x000a, 0x2583: 0x0004, 0x2584: 0x0004, 0x2585: 0x0004,
0x2586: 0x000a, 0x2587: 0x000a, 0x2588: 0x003a, 0x2589: 0x002a, 0x258a: 0x000a, 0x258b: 0x0003,
0x258c: 0x0006, 0x258d: 0x0003, 0x258e: 0x0006, 0x258f: 0x0006, 0x2590: 0x0002, 0x2591: 0x0002,
0x2592: 0x0002, 0x2593: 0x0002, 0x2594: 0x0002, 0x2595: 0x0002, 0x2596: 0x0002, 0x2597: 0x0002,
0x2598: 0x0002, 0x2599: 0x0002, 0x259a: 0x0006, 0x259b: 0x000a, 0x259c: 0x000a, 0x259d: 0x000a,
0x259e: 0x000a, 0x259f: 0x000a, 0x25a0: 0x000a,
0x25bb: 0x005a,
0x25bc: 0x000a, 0x25bd: 0x004a, 0x25be: 0x000a, 0x25bf: 0x000a,
// Block 0x97, offset 0x25c0
0x25c0: 0x000a,
0x25db: 0x005a, 0x25dc: 0x000a, 0x25dd: 0x004a,
0x25de: 0x000a, 0x25df: 0x00fa, 0x25e0: 0x00ea, 0x25e1: 0x000a, 0x25e2: 0x003a, 0x25e3: 0x002a,
0x25e4: 0x000a, 0x25e5: 0x000a,
// Block 0x98, offset 0x2600
0x2620: 0x0004, 0x2621: 0x0004, 0x2622: 0x000a, 0x2623: 0x000a,
0x2624: 0x000a, 0x2625: 0x0004, 0x2626: 0x0004, 0x2628: 0x000a, 0x2629: 0x000a,
0x262a: 0x000a, 0x262b: 0x000a, 0x262c: 0x000a, 0x262d: 0x000a, 0x262e: 0x000a,
0x2630: 0x000b, 0x2631: 0x000b, 0x2632: 0x000b, 0x2633: 0x000b, 0x2634: 0x000b, 0x2635: 0x000b,
0x2636: 0x000b, 0x2637: 0x000b, 0x2638: 0x000b, 0x2639: 0x000a, 0x263a: 0x000a, 0x263b: 0x000a,
0x263c: 0x000a, 0x263d: 0x000a, 0x263e: 0x000b, 0x263f: 0x000b,
// Block 0x99, offset 0x2640
0x2641: 0x000a,
// Block 0x9a, offset 0x2680
0x2680: 0x000a, 0x2681: 0x000a, 0x2682: 0x000a, 0x2683: 0x000a, 0x2684: 0x000a, 0x2685: 0x000a,
0x2686: 0x000a, 0x2687: 0x000a, 0x2688: 0x000a, 0x2689: 0x000a, 0x268a: 0x000a, 0x268b: 0x000a,
0x268c: 0x000a, 0x2690: 0x000a, 0x2691: 0x000a,
0x2692: 0x000a, 0x2693: 0x000a, 0x2694: 0x000a, 0x2695: 0x000a, 0x2696: 0x000a, 0x2697: 0x000a,
0x2698: 0x000a, 0x2699: 0x000a, 0x269a: 0x000a, 0x269b: 0x000a, 0x269c: 0x000a,
0x26a0: 0x000a,
// Block 0x9b, offset 0x26c0
0x26fd: 0x000c,
// Block 0x9c, offset 0x2700
0x2720: 0x000c, 0x2721: 0x0002, 0x2722: 0x0002, 0x2723: 0x0002,
0x2724: 0x0002, 0x2725: 0x0002, 0x2726: 0x0002, 0x2727: 0x0002, 0x2728: 0x0002, 0x2729: 0x0002,
0x272a: 0x0002, 0x272b: 0x0002, 0x272c: 0x0002, 0x272d: 0x0002, 0x272e: 0x0002, 0x272f: 0x0002,
0x2730: 0x0002, 0x2731: 0x0002, 0x2732: 0x0002, 0x2733: 0x0002, 0x2734: 0x0002, 0x2735: 0x0002,
0x2736: 0x0002, 0x2737: 0x0002, 0x2738: 0x0002, 0x2739: 0x0002, 0x273a: 0x0002, 0x273b: 0x0002,
// Block 0x9d, offset 0x2740
0x2776: 0x000c, 0x2777: 0x000c, 0x2778: 0x000c, 0x2779: 0x000c, 0x277a: 0x000c,
// Block 0x9e, offset 0x2780
0x2780: 0x0001, 0x2781: 0x0001, 0x2782: 0x0001, 0x2783: 0x0001, 0x2784: 0x0001, 0x2785: 0x0001,
0x2786: 0x0001, 0x2787: 0x0001, 0x2788: 0x0001, 0x2789: 0x0001, 0x278a: 0x0001, 0x278b: 0x0001,
0x278c: 0x0001, 0x278d: 0x0001, 0x278e: 0x0001, 0x278f: 0x0001, 0x2790: 0x0001, 0x2791: 0x0001,
0x2792: 0x0001, 0x2793: 0x0001, 0x2794: 0x0001, 0x2795: 0x0001, 0x2796: 0x0001, 0x2797: 0x0001,
0x2798: 0x0001, 0x2799: 0x0001, 0x279a: 0x0001, 0x279b: 0x0001, 0x279c: 0x0001, 0x279d: 0x0001,
0x279e: 0x0001, 0x279f: 0x0001, 0x27a0: 0x0001, 0x27a1: 0x0001, 0x27a2: 0x0001, 0x27a3: 0x0001,
0x27a4: 0x0001, 0x27a5: 0x0001, 0x27a6: 0x0001, 0x27a7: 0x0001, 0x27a8: 0x0001, 0x27a9: 0x0001,
0x27aa: 0x0001, 0x27ab: 0x0001, 0x27ac: 0x0001, 0x27ad: 0x0001, 0x27ae: 0x0001, 0x27af: 0x0001,
0x27b0: 0x0001, 0x27b1: 0x0001, 0x27b2: 0x0001, 0x27b3: 0x0001, 0x27b4: 0x0001, 0x27b5: 0x0001,
0x27b6: 0x0001, 0x27b7: 0x0001, 0x27b8: 0x0001, 0x27b9: 0x0001, 0x27ba: 0x0001, 0x27bb: 0x0001,
0x27bc: 0x0001, 0x27bd: 0x0001, 0x27be: 0x0001, 0x27bf: 0x0001,
// Block 0x9f, offset 0x27c0
0x27c0: 0x0001, 0x27c1: 0x0001, 0x27c2: 0x0001, 0x27c3: 0x0001, 0x27c4: 0x0001, 0x27c5: 0x0001,
0x27c6: 0x0001, 0x27c7: 0x0001, 0x27c8: 0x0001, 0x27c9: 0x0001, 0x27ca: 0x0001, 0x27cb: 0x0001,
0x27cc: 0x0001, 0x27cd: 0x0001, 0x27ce: 0x0001, 0x27cf: 0x0001, 0x27d0: 0x0001, 0x27d1: 0x0001,
0x27d2: 0x0001, 0x27d3: 0x0001, 0x27d4: 0x0001, 0x27d5: 0x0001, 0x27d6: 0x0001, 0x27d7: 0x0001,
0x27d8: 0x0001, 0x27d9: 0x0001, 0x27da: 0x0001, 0x27db: 0x0001, 0x27dc: 0x0001, 0x27dd: 0x0001,
0x27de: 0x0001, 0x27df: 0x000a, 0x27e0: 0x0001, 0x27e1: 0x0001, 0x27e2: 0x0001, 0x27e3: 0x0001,
0x27e4: 0x0001, 0x27e5: 0x0001, 0x27e6: 0x0001, 0x27e7: 0x0001, 0x27e8: 0x0001, 0x27e9: 0x0001,
0x27ea: 0x0001, 0x27eb: 0x0001, 0x27ec: 0x0001, 0x27ed: 0x0001, 0x27ee: 0x0001, 0x27ef: 0x0001,
0x27f0: 0x0001, 0x27f1: 0x0001, 0x27f2: 0x0001, 0x27f3: 0x0001, 0x27f4: 0x0001, 0x27f5: 0x0001,
0x27f6: 0x0001, 0x27f7: 0x0001, 0x27f8: 0x0001, 0x27f9: 0x0001, 0x27fa: 0x0001, 0x27fb: 0x0001,
0x27fc: 0x0001, 0x27fd: 0x0001, 0x27fe: 0x0001, 0x27ff: 0x0001,
// Block 0xa0, offset 0x2800
0x2800: 0x0001, 0x2801: 0x000c, 0x2802: 0x000c, 0x2803: 0x000c, 0x2804: 0x0001, 0x2805: 0x000c,
0x2806: 0x000c, 0x2807: 0x0001, 0x2808: 0x0001, 0x2809: 0x0001, 0x280a: 0x0001, 0x280b: 0x0001,
0x280c: 0x000c, 0x280d: 0x000c, 0x280e: 0x000c, 0x280f: 0x000c, 0x2810: 0x0001, 0x2811: 0x0001,
0x2812: 0x0001, 0x2813: 0x0001, 0x2814: 0x0001, 0x2815: 0x0001, 0x2816: 0x0001, 0x2817: 0x0001,
0x2818: 0x0001, 0x2819: 0x0001, 0x281a: 0x0001, 0x281b: 0x0001, 0x281c: 0x0001, 0x281d: 0x0001,
0x281e: 0x0001, 0x281f: 0x0001, 0x2820: 0x0001, 0x2821: 0x0001, 0x2822: 0x0001, 0x2823: 0x0001,
0x2824: 0x0001, 0x2825: 0x0001, 0x2826: 0x0001, 0x2827: 0x0001, 0x2828: 0x0001, 0x2829: 0x0001,
0x282a: 0x0001, 0x282b: 0x0001, 0x282c: 0x0001, 0x282d: 0x0001, 0x282e: 0x0001, 0x282f: 0x0001,
0x2830: 0x0001, 0x2831: 0x0001, 0x2832: 0x0001, 0x2833: 0x0001, 0x2834: 0x0001, 0x2835: 0x0001,
0x2836: 0x0001, 0x2837: 0x0001, 0x2838: 0x000c, 0x2839: 0x000c, 0x283a: 0x000c, 0x283b: 0x0001,
0x283c: 0x0001, 0x283d: 0x0001, 0x283e: 0x0001, 0x283f: 0x000c,
// Block 0xa1, offset 0x2840
0x2840: 0x0001, 0x2841: 0x0001, 0x2842: 0x0001, 0x2843: 0x0001, 0x2844: 0x0001, 0x2845: 0x0001,
0x2846: 0x0001, 0x2847: 0x0001, 0x2848: 0x0001, 0x2849: 0x0001, 0x284a: 0x0001, 0x284b: 0x0001,
0x284c: 0x0001, 0x284d: 0x0001, 0x284e: 0x0001, 0x284f: 0x0001, 0x2850: 0x0001, 0x2851: 0x0001,
0x2852: 0x0001, 0x2853: 0x0001, 0x2854: 0x0001, 0x2855: 0x0001, 0x2856: 0x0001, 0x2857: 0x0001,
0x2858: 0x0001, 0x2859: 0x0001, 0x285a: 0x0001, 0x285b: 0x0001, 0x285c: 0x0001, 0x285d: 0x0001,
0x285e: 0x0001, 0x285f: 0x0001, 0x2860: 0x0001, 0x2861: 0x0001, 0x2862: 0x0001, 0x2863: 0x0001,
0x2864: 0x0001, 0x2865: 0x000c, 0x2866: 0x000c, 0x2867: 0x0001, 0x2868: 0x0001, 0x2869: 0x0001,
0x286a: 0x0001, 0x286b: 0x0001, 0x286c: 0x0001, 0x286d: 0x0001, 0x286e: 0x0001, 0x286f: 0x0001,
0x2870: 0x0001, 0x2871: 0x0001, 0x2872: 0x0001, 0x2873: 0x0001, 0x2874: 0x0001, 0x2875: 0x0001,
0x2876: 0x0001, 0x2877: 0x0001, 0x2878: 0x0001, 0x2879: 0x0001, 0x287a: 0x0001, 0x287b: 0x0001,
0x287c: 0x0001, 0x287d: 0x0001, 0x287e: 0x0001, 0x287f: 0x0001,
// Block 0xa2, offset 0x2880
0x2880: 0x0001, 0x2881: 0x0001, 0x2882: 0x0001, 0x2883: 0x0001, 0x2884: 0x0001, 0x2885: 0x0001,
0x2886: 0x0001, 0x2887: 0x0001, 0x2888: 0x0001, 0x2889: 0x0001, 0x288a: 0x0001, 0x288b: 0x0001,
0x288c: 0x0001, 0x288d: 0x0001, 0x288e: 0x0001, 0x288f: 0x0001, 0x2890: 0x0001, 0x2891: 0x0001,
0x2892: 0x0001, 0x2893: 0x0001, 0x2894: 0x0001, 0x2895: 0x0001, 0x2896: 0x0001, 0x2897: 0x0001,
0x2898: 0x0001, 0x2899: 0x0001, 0x289a: 0x0001, 0x289b: 0x0001, 0x289c: 0x0001, 0x289d: 0x0001,
0x289e: 0x0001, 0x289f: 0x0001, 0x28a0: 0x0001, 0x28a1: 0x0001, 0x28a2: 0x0001, 0x28a3: 0x0001,
0x28a4: 0x0001, 0x28a5: 0x0001, 0x28a6: 0x0001, 0x28a7: 0x0001, 0x28a8: 0x0001, 0x28a9: 0x0001,
0x28aa: 0x0001, 0x28ab: 0x0001, 0x28ac: 0x0001, 0x28ad: 0x0001, 0x28ae: 0x0001, 0x28af: 0x0001,
0x28b0: 0x0001, 0x28b1: 0x0001, 0x28b2: 0x0001, 0x28b3: 0x0001, 0x28b4: 0x0001, 0x28b5: 0x0001,
0x28b6: 0x0001, 0x28b7: 0x0001, 0x28b8: 0x0001, 0x28b9: 0x000a, 0x28ba: 0x000a, 0x28bb: 0x000a,
0x28bc: 0x000a, 0x28bd: 0x000a, 0x28be: 0x000a, 0x28bf: 0x000a,
// Block 0xa3, offset 0x28c0
0x28c0: 0x000d, 0x28c1: 0x000d, 0x28c2: 0x000d, 0x28c3: 0x000d, 0x28c4: 0x000d, 0x28c5: 0x000d,
0x28c6: 0x000d, 0x28c7: 0x000d, 0x28c8: 0x000d, 0x28c9: 0x000d, 0x28ca: 0x000d, 0x28cb: 0x000d,
0x28cc: 0x000d, 0x28cd: 0x000d, 0x28ce: 0x000d, 0x28cf: 0x000d, 0x28d0: 0x000d, 0x28d1: 0x000d,
0x28d2: 0x000d, 0x28d3: 0x000d, 0x28d4: 0x000d, 0x28d5: 0x000d, 0x28d6: 0x000d, 0x28d7: 0x000d,
0x28d8: 0x000d, 0x28d9: 0x000d, 0x28da: 0x000d, 0x28db: 0x000d, 0x28dc: 0x000d, 0x28dd: 0x000d,
0x28de: 0x000d, 0x28df: 0x000d, 0x28e0: 0x000d, 0x28e1: 0x000d, 0x28e2: 0x000d, 0x28e3: 0x000d,
0x28e4: 0x000c, 0x28e5: 0x000c, 0x28e6: 0x000c, 0x28e7: 0x000c, 0x28e8: 0x0001, 0x28e9: 0x0001,
0x28ea: 0x0001, 0x28eb: 0x0001, 0x28ec: 0x0001, 0x28ed: 0x0001, 0x28ee: 0x0001, 0x28ef: 0x0001,
0x28f0: 0x0005, 0x28f1: 0x0005, 0x28f2: 0x0005, 0x28f3: 0x0005, 0x28f4: 0x0005, 0x28f5: 0x0005,
0x28f6: 0x0005, 0x28f7: 0x0005, 0x28f8: 0x0005, 0x28f9: 0x0005, 0x28fa: 0x0001, 0x28fb: 0x0001,
0x28fc: 0x0001, 0x28fd: 0x0001, 0x28fe: 0x0001, 0x28ff: 0x0001,
// Block 0xa4, offset 0x2900
0x2900: 0x0001, 0x2901: 0x0001, 0x2902: 0x0001, 0x2903: 0x0001, 0x2904: 0x0001, 0x2905: 0x0001,
0x2906: 0x0001, 0x2907: 0x0001, 0x2908: 0x0001, 0x2909: 0x0001, 0x290a: 0x0001, 0x290b: 0x0001,
0x290c: 0x0001, 0x290d: 0x0001, 0x290e: 0x0001, 0x290f: 0x0001, 0x2910: 0x0001, 0x2911: 0x0001,
0x2912: 0x0001, 0x2913: 0x0001, 0x2914: 0x0001, 0x2915: 0x0001, 0x2916: 0x0001, 0x2917: 0x0001,
0x2918: 0x0001, 0x2919: 0x0001, 0x291a: 0x0001, 0x291b: 0x0001, 0x291c: 0x0001, 0x291d: 0x0001,
0x291e: 0x0001, 0x291f: 0x0001, 0x2920: 0x0005, 0x2921: 0x0005, 0x2922: 0x0005, 0x2923: 0x0005,
0x2924: 0x0005, 0x2925: 0x0005, 0x2926: 0x0005, 0x2927: 0x0005, 0x2928: 0x0005, 0x2929: 0x0005,
0x292a: 0x0005, 0x292b: 0x0005, 0x292c: 0x0005, 0x292d: 0x0005, 0x292e: 0x0005, 0x292f: 0x0005,
0x2930: 0x0005, 0x2931: 0x0005, 0x2932: 0x0005, 0x2933: 0x0005, 0x2934: 0x0005, 0x2935: 0x0005,
0x2936: 0x0005, 0x2937: 0x0005, 0x2938: 0x0005, 0x2939: 0x0005, 0x293a: 0x0005, 0x293b: 0x0005,
0x293c: 0x0005, 0x293d: 0x0005, 0x293e: 0x0005, 0x293f: 0x0001,
// Block 0xa5, offset 0x2940
0x2940: 0x0001, 0x2941: 0x0001, 0x2942: 0x0001, 0x2943: 0x0001, 0x2944: 0x0001, 0x2945: 0x0001,
0x2946: 0x0001, 0x2947: 0x0001, 0x2948: 0x0001, 0x2949: 0x0001, 0x294a: 0x0001, 0x294b: 0x0001,
0x294c: 0x0001, 0x294d: 0x0001, 0x294e: 0x0001, 0x294f: 0x0001, 0x2950: 0x0001, 0x2951: 0x0001,
0x2952: 0x0001, 0x2953: 0x0001, 0x2954: 0x0001, 0x2955: 0x0001, 0x2956: 0x0001, 0x2957: 0x0001,
0x2958: 0x0001, 0x2959: 0x0001, 0x295a: 0x0001, 0x295b: 0x0001, 0x295c: 0x0001, 0x295d: 0x0001,
0x295e: 0x0001, 0x295f: 0x0001, 0x2960: 0x0001, 0x2961: 0x0001, 0x2962: 0x0001, 0x2963: 0x0001,
0x2964: 0x0001, 0x2965: 0x0001, 0x2966: 0x0001, 0x2967: 0x0001, 0x2968: 0x0001, 0x2969: 0x0001,
0x296a: 0x0001, 0x296b: 0x000c, 0x296c: 0x000c, 0x296d: 0x0001, 0x296e: 0x0001, 0x296f: 0x0001,
0x2970: 0x0001, 0x2971: 0x0001, 0x2972: 0x0001, 0x2973: 0x0001, 0x2974: 0x0001, 0x2975: 0x0001,
0x2976: 0x0001, 0x2977: 0x0001, 0x2978: 0x0001, 0x2979: 0x0001, 0x297a: 0x0001, 0x297b: 0x0001,
0x297c: 0x0001, 0x297d: 0x0001, 0x297e: 0x0001, 0x297f: 0x0001,
// Block 0xa6, offset 0x2980
0x2980: 0x0001, 0x2981: 0x0001, 0x2982: 0x0001, 0x2983: 0x0001, 0x2984: 0x0001, 0x2985: 0x0001,
0x2986: 0x0001, 0x2987: 0x0001, 0x2988: 0x0001, 0x2989: 0x0001, 0x298a: 0x0001, 0x298b: 0x0001,
0x298c: 0x0001, 0x298d: 0x0001, 0x298e: 0x0001, 0x298f: 0x0001, 0x2990: 0x0001, 0x2991: 0x0001,
0x2992: 0x0001, 0x2993: 0x0001, 0x2994: 0x0001, 0x2995: 0x0001, 0x2996: 0x0001, 0x2997: 0x0001,
0x2998: 0x0001, 0x2999: 0x0001, 0x299a: 0x0001, 0x299b: 0x0001, 0x299c: 0x0001, 0x299d: 0x0001,
0x299e: 0x0001, 0x299f: 0x0001, 0x29a0: 0x0001, 0x29a1: 0x0001, 0x29a2: 0x0001, 0x29a3: 0x0001,
0x29a4: 0x0001, 0x29a5: 0x0001, 0x29a6: 0x0001, 0x29a7: 0x0001, 0x29a8: 0x0001, 0x29a9: 0x0001,
0x29aa: 0x0001, 0x29ab: 0x0001, 0x29ac: 0x0001, 0x29ad: 0x0001, 0x29ae: 0x0001, 0x29af: 0x0001,
0x29b0: 0x0001, 0x29b1: 0x0001, 0x29b2: 0x0001, 0x29b3: 0x0001, 0x29b4: 0x0001, 0x29b5: 0x0001,
0x29b6: 0x0001, 0x29b7: 0x0001, 0x29b8: 0x0001, 0x29b9: 0x0001, 0x29ba: 0x0001, 0x29bb: 0x0001,
0x29bc: 0x0001, 0x29bd: 0x000c, 0x29be: 0x000c, 0x29bf: 0x000c,
// Block 0xa7, offset 0x29c0
0x29c0: 0x0001, 0x29c1: 0x0001, 0x29c2: 0x0001, 0x29c3: 0x0001, 0x29c4: 0x0001, 0x29c5: 0x0001,
0x29c6: 0x0001, 0x29c7: 0x0001, 0x29c8: 0x0001, 0x29c9: 0x0001, 0x29ca: 0x0001, 0x29cb: 0x0001,
0x29cc: 0x0001, 0x29cd: 0x0001, 0x29ce: 0x0001, 0x29cf: 0x0001, 0x29d0: 0x0001, 0x29d1: 0x0001,
0x29d2: 0x0001, 0x29d3: 0x0001, 0x29d4: 0x0001, 0x29d5: 0x0001, 0x29d6: 0x0001, 0x29d7: 0x0001,
0x29d8: 0x0001, 0x29d9: 0x0001, 0x29da: 0x0001, 0x29db: 0x0001, 0x29dc: 0x0001, 0x29dd: 0x0001,
0x29de: 0x0001, 0x29df: 0x0001, 0x29e0: 0x0001, 0x29e1: 0x0001, 0x29e2: 0x0001, 0x29e3: 0x0001,
0x29e4: 0x0001, 0x29e5: 0x0001, 0x29e6: 0x0001, 0x29e7: 0x0001, 0x29e8: 0x0001, 0x29e9: 0x0001,
0x29ea: 0x0001, 0x29eb: 0x0001, 0x29ec: 0x0001, 0x29ed: 0x0001, 0x29ee: 0x0001, 0x29ef: 0x0001,
0x29f0: 0x000d, 0x29f1: 0x000d, 0x29f2: 0x000d, 0x29f3: 0x000d, 0x29f4: 0x000d, 0x29f5: 0x000d,
0x29f6: 0x000d, 0x29f7: 0x000d, 0x29f8: 0x000d, 0x29f9: 0x000d, 0x29fa: 0x000d, 0x29fb: 0x000d,
0x29fc: 0x000d, 0x29fd: 0x000d, 0x29fe: 0x000d, 0x29ff: 0x000d,
// Block 0xa8, offset 0x2a00
0x2a00: 0x000d, 0x2a01: 0x000d, 0x2a02: 0x000d, 0x2a03: 0x000d, 0x2a04: 0x000d, 0x2a05: 0x000d,
0x2a06: 0x000c, 0x2a07: 0x000c, 0x2a08: 0x000c, 0x2a09: 0x000c, 0x2a0a: 0x000c, 0x2a0b: 0x000c,
0x2a0c: 0x000c, 0x2a0d: 0x000c, 0x2a0e: 0x000c, 0x2a0f: 0x000c, 0x2a10: 0x000c, 0x2a11: 0x000d,
0x2a12: 0x000d, 0x2a13: 0x000d, 0x2a14: 0x000d, 0x2a15: 0x000d, 0x2a16: 0x000d, 0x2a17: 0x000d,
0x2a18: 0x000d, 0x2a19: 0x000d, 0x2a1a: 0x0001, 0x2a1b: 0x0001, 0x2a1c: 0x0001, 0x2a1d: 0x0001,
0x2a1e: 0x0001, 0x2a1f: 0x0001, 0x2a20: 0x0001, 0x2a21: 0x0001, 0x2a22: 0x0001, 0x2a23: 0x0001,
0x2a24: 0x0001, 0x2a25: 0x0001, 0x2a26: 0x0001, 0x2a27: 0x0001, 0x2a28: 0x0001, 0x2a29: 0x0001,
0x2a2a: 0x0001, 0x2a2b: 0x0001, 0x2a2c: 0x0001, 0x2a2d: 0x0001, 0x2a2e: 0x0001, 0x2a2f: 0x0001,
0x2a30: 0x0001, 0x2a31: 0x0001, 0x2a32: 0x0001, 0x2a33: 0x0001, 0x2a34: 0x0001, 0x2a35: 0x0001,
0x2a36: 0x0001, 0x2a37: 0x0001, 0x2a38: 0x0001, 0x2a39: 0x0001, 0x2a3a: 0x0001, 0x2a3b: 0x0001,
0x2a3c: 0x0001, 0x2a3d: 0x0001, 0x2a3e: 0x0001, 0x2a3f: 0x0001,
// Block 0xa9, offset 0x2a40
0x2a40: 0x0001, 0x2a41: 0x0001, 0x2a42: 0x000c, 0x2a43: 0x000c, 0x2a44: 0x000c, 0x2a45: 0x000c,
0x2a46: 0x0001, 0x2a47: 0x0001, 0x2a48: 0x0001, 0x2a49: 0x0001, 0x2a4a: 0x0001, 0x2a4b: 0x0001,
0x2a4c: 0x0001, 0x2a4d: 0x0001, 0x2a4e: 0x0001, 0x2a4f: 0x0001, 0x2a50: 0x0001, 0x2a51: 0x0001,
0x2a52: 0x0001, 0x2a53: 0x0001, 0x2a54: 0x0001, 0x2a55: 0x0001, 0x2a56: 0x0001, 0x2a57: 0x0001,
0x2a58: 0x0001, 0x2a59: 0x0001, 0x2a5a: 0x0001, 0x2a5b: 0x0001, 0x2a5c: 0x0001, 0x2a5d: 0x0001,
0x2a5e: 0x0001, 0x2a5f: 0x0001, 0x2a60: 0x0001, 0x2a61: 0x0001, 0x2a62: 0x0001, 0x2a63: 0x0001,
0x2a64: 0x0001, 0x2a65: 0x0001, 0x2a66: 0x0001, 0x2a67: 0x0001, 0x2a68: 0x0001, 0x2a69: 0x0001,
0x2a6a: 0x0001, 0x2a6b: 0x0001, 0x2a6c: 0x0001, 0x2a6d: 0x0001, 0x2a6e: 0x0001, 0x2a6f: 0x0001,
0x2a70: 0x0001, 0x2a71: 0x0001, 0x2a72: 0x0001, 0x2a73: 0x0001, 0x2a74: 0x0001, 0x2a75: 0x0001,
0x2a76: 0x0001, 0x2a77: 0x0001, 0x2a78: 0x0001, 0x2a79: 0x0001, 0x2a7a: 0x0001, 0x2a7b: 0x0001,
0x2a7c: 0x0001, 0x2a7d: 0x0001, 0x2a7e: 0x0001, 0x2a7f: 0x0001,
// Block 0xaa, offset 0x2a80
0x2a81: 0x000c,
0x2ab8: 0x000c, 0x2ab9: 0x000c, 0x2aba: 0x000c, 0x2abb: 0x000c,
0x2abc: 0x000c, 0x2abd: 0x000c, 0x2abe: 0x000c, 0x2abf: 0x000c,
// Block 0xab, offset 0x2ac0
0x2ac0: 0x000c, 0x2ac1: 0x000c, 0x2ac2: 0x000c, 0x2ac3: 0x000c, 0x2ac4: 0x000c, 0x2ac5: 0x000c,
0x2ac6: 0x000c,
0x2ad2: 0x000a, 0x2ad3: 0x000a, 0x2ad4: 0x000a, 0x2ad5: 0x000a, 0x2ad6: 0x000a, 0x2ad7: 0x000a,
0x2ad8: 0x000a, 0x2ad9: 0x000a, 0x2ada: 0x000a, 0x2adb: 0x000a, 0x2adc: 0x000a, 0x2add: 0x000a,
0x2ade: 0x000a, 0x2adf: 0x000a, 0x2ae0: 0x000a, 0x2ae1: 0x000a, 0x2ae2: 0x000a, 0x2ae3: 0x000a,
0x2ae4: 0x000a, 0x2ae5: 0x000a,
0x2af0: 0x000c, 0x2af3: 0x000c, 0x2af4: 0x000c,
0x2aff: 0x000c,
// Block 0xac, offset 0x2b00
0x2b00: 0x000c, 0x2b01: 0x000c,
0x2b33: 0x000c, 0x2b34: 0x000c, 0x2b35: 0x000c,
0x2b36: 0x000c, 0x2b39: 0x000c, 0x2b3a: 0x000c,
// Block 0xad, offset 0x2b40
0x2b40: 0x000c, 0x2b41: 0x000c, 0x2b42: 0x000c,
0x2b67: 0x000c, 0x2b68: 0x000c, 0x2b69: 0x000c,
0x2b6a: 0x000c, 0x2b6b: 0x000c, 0x2b6d: 0x000c, 0x2b6e: 0x000c, 0x2b6f: 0x000c,
0x2b70: 0x000c, 0x2b71: 0x000c, 0x2b72: 0x000c, 0x2b73: 0x000c, 0x2b74: 0x000c,
// Block 0xae, offset 0x2b80
0x2bb3: 0x000c,
// Block 0xaf, offset 0x2bc0
0x2bc0: 0x000c, 0x2bc1: 0x000c,
0x2bf6: 0x000c, 0x2bf7: 0x000c, 0x2bf8: 0x000c, 0x2bf9: 0x000c, 0x2bfa: 0x000c, 0x2bfb: 0x000c,
0x2bfc: 0x000c, 0x2bfd: 0x000c, 0x2bfe: 0x000c,
// Block 0xb0, offset 0x2c00
0x2c09: 0x000c, 0x2c0a: 0x000c, 0x2c0b: 0x000c,
0x2c0c: 0x000c, 0x2c0f: 0x000c,
// Block 0xb1, offset 0x2c40
0x2c6f: 0x000c,
0x2c70: 0x000c, 0x2c71: 0x000c, 0x2c74: 0x000c,
0x2c76: 0x000c, 0x2c77: 0x000c,
0x2c7e: 0x000c,
// Block 0xb2, offset 0x2c80
0x2c9f: 0x000c, 0x2ca3: 0x000c,
0x2ca4: 0x000c, 0x2ca5: 0x000c, 0x2ca6: 0x000c, 0x2ca7: 0x000c, 0x2ca8: 0x000c, 0x2ca9: 0x000c,
0x2caa: 0x000c,
// Block 0xb3, offset 0x2cc0
0x2cc0: 0x000c,
0x2ce6: 0x000c, 0x2ce7: 0x000c, 0x2ce8: 0x000c, 0x2ce9: 0x000c,
0x2cea: 0x000c, 0x2ceb: 0x000c, 0x2cec: 0x000c,
0x2cf0: 0x000c, 0x2cf1: 0x000c, 0x2cf2: 0x000c, 0x2cf3: 0x000c, 0x2cf4: 0x000c,
// Block 0xb4, offset 0x2d00
0x2d38: 0x000c, 0x2d39: 0x000c, 0x2d3a: 0x000c, 0x2d3b: 0x000c,
0x2d3c: 0x000c, 0x2d3d: 0x000c, 0x2d3e: 0x000c, 0x2d3f: 0x000c,
// Block 0xb5, offset 0x2d40
0x2d42: 0x000c, 0x2d43: 0x000c, 0x2d44: 0x000c,
0x2d46: 0x000c,
0x2d5e: 0x000c,
// Block 0xb6, offset 0x2d80
0x2db3: 0x000c, 0x2db4: 0x000c, 0x2db5: 0x000c,
0x2db6: 0x000c, 0x2db7: 0x000c, 0x2db8: 0x000c, 0x2dba: 0x000c,
0x2dbf: 0x000c,
// Block 0xb7, offset 0x2dc0
0x2dc0: 0x000c, 0x2dc2: 0x000c, 0x2dc3: 0x000c,
// Block 0xb8, offset 0x2e00
0x2e32: 0x000c, 0x2e33: 0x000c, 0x2e34: 0x000c, 0x2e35: 0x000c,
0x2e3c: 0x000c, 0x2e3d: 0x000c, 0x2e3f: 0x000c,
// Block 0xb9, offset 0x2e40
0x2e40: 0x000c,
0x2e5c: 0x000c, 0x2e5d: 0x000c,
// Block 0xba, offset 0x2e80
0x2eb3: 0x000c, 0x2eb4: 0x000c, 0x2eb5: 0x000c,
0x2eb6: 0x000c, 0x2eb7: 0x000c, 0x2eb8: 0x000c, 0x2eb9: 0x000c, 0x2eba: 0x000c,
0x2ebd: 0x000c, 0x2ebf: 0x000c,
// Block 0xbb, offset 0x2ec0
0x2ec0: 0x000c,
0x2ee0: 0x000a, 0x2ee1: 0x000a, 0x2ee2: 0x000a, 0x2ee3: 0x000a,
0x2ee4: 0x000a, 0x2ee5: 0x000a, 0x2ee6: 0x000a, 0x2ee7: 0x000a, 0x2ee8: 0x000a, 0x2ee9: 0x000a,
0x2eea: 0x000a, 0x2eeb: 0x000a, 0x2eec: 0x000a,
// Block 0xbc, offset 0x2f00
0x2f2b: 0x000c, 0x2f2d: 0x000c,
0x2f30: 0x000c, 0x2f31: 0x000c, 0x2f32: 0x000c, 0x2f33: 0x000c, 0x2f34: 0x000c, 0x2f35: 0x000c,
0x2f37: 0x000c,
// Block 0xbd, offset 0x2f40
0x2f5d: 0x000c,
0x2f5e: 0x000c, 0x2f5f: 0x000c, 0x2f62: 0x000c, 0x2f63: 0x000c,
0x2f64: 0x000c, 0x2f65: 0x000c, 0x2f67: 0x000c, 0x2f68: 0x000c, 0x2f69: 0x000c,
0x2f6a: 0x000c, 0x2f6b: 0x000c,
// Block 0xbe, offset 0x2f80
0x2faf: 0x000c,
0x2fb0: 0x000c, 0x2fb1: 0x000c, 0x2fb2: 0x000c, 0x2fb3: 0x000c, 0x2fb4: 0x000c, 0x2fb5: 0x000c,
0x2fb6: 0x000c, 0x2fb7: 0x000c, 0x2fb9: 0x000c, 0x2fba: 0x000c,
// Block 0xbf, offset 0x2fc0
0x2ffb: 0x000c,
0x2ffc: 0x000c, 0x2ffe: 0x000c,
// Block 0xc0, offset 0x3000
0x3003: 0x000c,
// Block 0xc1, offset 0x3040
0x3054: 0x000c, 0x3055: 0x000c, 0x3056: 0x000c, 0x3057: 0x000c,
0x305a: 0x000c, 0x305b: 0x000c,
0x3060: 0x000c,
// Block 0xc2, offset 0x3080
0x3081: 0x000c, 0x3082: 0x000c, 0x3083: 0x000c, 0x3084: 0x000c, 0x3085: 0x000c,
0x3086: 0x000c, 0x3089: 0x000c, 0x308a: 0x000c,
0x30b3: 0x000c, 0x30b4: 0x000c, 0x30b5: 0x000c,
0x30b6: 0x000c, 0x30b7: 0x000c, 0x30b8: 0x000c, 0x30bb: 0x000c,
0x30bc: 0x000c, 0x30bd: 0x000c, 0x30be: 0x000c,
// Block 0xc3, offset 0x30c0
0x30c7: 0x000c,
0x30d1: 0x000c,
0x30d2: 0x000c, 0x30d3: 0x000c, 0x30d4: 0x000c, 0x30d5: 0x000c, 0x30d6: 0x000c,
0x30d9: 0x000c, 0x30da: 0x000c, 0x30db: 0x000c,
// Block 0xc4, offset 0x3100
0x310a: 0x000c, 0x310b: 0x000c,
0x310c: 0x000c, 0x310d: 0x000c, 0x310e: 0x000c, 0x310f: 0x000c, 0x3110: 0x000c, 0x3111: 0x000c,
0x3112: 0x000c, 0x3113: 0x000c, 0x3114: 0x000c, 0x3115: 0x000c, 0x3116: 0x000c,
0x3118: 0x000c, 0x3119: 0x000c,
// Block 0xc5, offset 0x3140
0x3170: 0x000c, 0x3171: 0x000c, 0x3172: 0x000c, 0x3173: 0x000c, 0x3174: 0x000c, 0x3175: 0x000c,
0x3176: 0x000c, 0x3178: 0x000c, 0x3179: 0x000c, 0x317a: 0x000c, 0x317b: 0x000c,
0x317c: 0x000c, 0x317d: 0x000c,
// Block 0xc6, offset 0x3180
0x3192: 0x000c, 0x3193: 0x000c, 0x3194: 0x000c, 0x3195: 0x000c, 0x3196: 0x000c, 0x3197: 0x000c,
0x3198: 0x000c, 0x3199: 0x000c, 0x319a: 0x000c, 0x319b: 0x000c, 0x319c: 0x000c, 0x319d: 0x000c,
0x319e: 0x000c, 0x319f: 0x000c, 0x31a0: 0x000c, 0x31a1: 0x000c, 0x31a2: 0x000c, 0x31a3: 0x000c,
0x31a4: 0x000c, 0x31a5: 0x000c, 0x31a6: 0x000c, 0x31a7: 0x000c,
0x31aa: 0x000c, 0x31ab: 0x000c, 0x31ac: 0x000c, 0x31ad: 0x000c, 0x31ae: 0x000c, 0x31af: 0x000c,
0x31b0: 0x000c, 0x31b2: 0x000c, 0x31b3: 0x000c, 0x31b5: 0x000c,
0x31b6: 0x000c,
// Block 0xc7, offset 0x31c0
0x31f1: 0x000c, 0x31f2: 0x000c, 0x31f3: 0x000c, 0x31f4: 0x000c, 0x31f5: 0x000c,
0x31f6: 0x000c, 0x31fa: 0x000c,
0x31fc: 0x000c, 0x31fd: 0x000c, 0x31ff: 0x000c,
// Block 0xc8, offset 0x3200
0x3200: 0x000c, 0x3201: 0x000c, 0x3202: 0x000c, 0x3203: 0x000c, 0x3204: 0x000c, 0x3205: 0x000c,
0x3207: 0x000c,
// Block 0xc9, offset 0x3240
0x3250: 0x000c, 0x3251: 0x000c,
0x3255: 0x000c, 0x3257: 0x000c,
// Block 0xca, offset 0x3280
0x32b3: 0x000c, 0x32b4: 0x000c,
// Block 0xcb, offset 0x32c0
0x32c0: 0x000c, 0x32c1: 0x000c,
0x32f6: 0x000c, 0x32f7: 0x000c, 0x32f8: 0x000c, 0x32f9: 0x000c, 0x32fa: 0x000c,
// Block 0xcc, offset 0x3300
0x3300: 0x000c, 0x3302: 0x000c,
// Block 0xcd, offset 0x3340
0x3355: 0x000a, 0x3356: 0x000a, 0x3357: 0x000a,
0x3358: 0x000a, 0x3359: 0x000a, 0x335a: 0x000a, 0x335b: 0x000a, 0x335c: 0x000a, 0x335d: 0x0004,
0x335e: 0x0004, 0x335f: 0x0004, 0x3360: 0x0004, 0x3361: 0x000a, 0x3362: 0x000a, 0x3363: 0x000a,
0x3364: 0x000a, 0x3365: 0x000a, 0x3366: 0x000a, 0x3367: 0x000a, 0x3368: 0x000a, 0x3369: 0x000a,
0x336a: 0x000a, 0x336b: 0x000a, 0x336c: 0x000a, 0x336d: 0x000a, 0x336e: 0x000a, 0x336f: 0x000a,
0x3370: 0x000a, 0x3371: 0x000a,
// Block 0xce, offset 0x3380
0x3380: 0x000c,
0x3387: 0x000c, 0x3388: 0x000c, 0x3389: 0x000c, 0x338a: 0x000c, 0x338b: 0x000c,
0x338c: 0x000c, 0x338d: 0x000c, 0x338e: 0x000c, 0x338f: 0x000c, 0x3390: 0x000c, 0x3391: 0x000c,
0x3392: 0x000c, 0x3393: 0x000c, 0x3394: 0x000c, 0x3395: 0x000c,
// Block 0xcf, offset 0x33c0
0x33f0: 0x000c, 0x33f1: 0x000c, 0x33f2: 0x000c, 0x33f3: 0x000c, 0x33f4: 0x000c,
// Block 0xd0, offset 0x3400
0x3430: 0x000c, 0x3431: 0x000c, 0x3432: 0x000c, 0x3433: 0x000c, 0x3434: 0x000c, 0x3435: 0x000c,
0x3436: 0x000c,
// Block 0xd1, offset 0x3440
0x344f: 0x000c,
// Block 0xd2, offset 0x3480
0x348f: 0x000c, 0x3490: 0x000c, 0x3491: 0x000c,
0x3492: 0x000c,
// Block 0xd3, offset 0x34c0
0x34e2: 0x000a,
0x34e4: 0x000c,
// Block 0xd4, offset 0x3500
0x351d: 0x000c,
0x351e: 0x000c, 0x3520: 0x000b, 0x3521: 0x000b, 0x3522: 0x000b, 0x3523: 0x000b,
// Block 0xd5, offset 0x3540
0x3540: 0x000c, 0x3541: 0x000c, 0x3542: 0x000c, 0x3543: 0x000c, 0x3544: 0x000c, 0x3545: 0x000c,
0x3546: 0x000c, 0x3547: 0x000c, 0x3548: 0x000c, 0x3549: 0x000c, 0x354a: 0x000c, 0x354b: 0x000c,
0x354c: 0x000c, 0x354d: 0x000c, 0x354e: 0x000c, 0x354f: 0x000c, 0x3550: 0x000c, 0x3551: 0x000c,
0x3552: 0x000c, 0x3553: 0x000c, 0x3554: 0x000c, 0x3555: 0x000c, 0x3556: 0x000c, 0x3557: 0x000c,
0x3558: 0x000c, 0x3559: 0x000c, 0x355a: 0x000c, 0x355b: 0x000c, 0x355c: 0x000c, 0x355d: 0x000c,
0x355e: 0x000c, 0x355f: 0x000c, 0x3560: 0x000c, 0x3561: 0x000c, 0x3562: 0x000c, 0x3563: 0x000c,
0x3564: 0x000c, 0x3565: 0x000c, 0x3566: 0x000c, 0x3567: 0x000c, 0x3568: 0x000c, 0x3569: 0x000c,
0x356a: 0x000c, 0x356b: 0x000c, 0x356c: 0x000c, 0x356d: 0x000c,
0x3570: 0x000c, 0x3571: 0x000c, 0x3572: 0x000c, 0x3573: 0x000c, 0x3574: 0x000c, 0x3575: 0x000c,
0x3576: 0x000c, 0x3577: 0x000c, 0x3578: 0x000c, 0x3579: 0x000c, 0x357a: 0x000c, 0x357b: 0x000c,
0x357c: 0x000c, 0x357d: 0x000c, 0x357e: 0x000c, 0x357f: 0x000c,
// Block 0xd6, offset 0x3580
0x3580: 0x000c, 0x3581: 0x000c, 0x3582: 0x000c, 0x3583: 0x000c, 0x3584: 0x000c, 0x3585: 0x000c,
0x3586: 0x000c,
// Block 0xd7, offset 0x35c0
0x35e7: 0x000c, 0x35e8: 0x000c, 0x35e9: 0x000c,
0x35f3: 0x000b, 0x35f4: 0x000b, 0x35f5: 0x000b,
0x35f6: 0x000b, 0x35f7: 0x000b, 0x35f8: 0x000b, 0x35f9: 0x000b, 0x35fa: 0x000b, 0x35fb: 0x000c,
0x35fc: 0x000c, 0x35fd: 0x000c, 0x35fe: 0x000c, 0x35ff: 0x000c,
// Block 0xd8, offset 0x3600
0x3600: 0x000c, 0x3601: 0x000c, 0x3602: 0x000c, 0x3605: 0x000c,
0x3606: 0x000c, 0x3607: 0x000c, 0x3608: 0x000c, 0x3609: 0x000c, 0x360a: 0x000c, 0x360b: 0x000c,
0x362a: 0x000c, 0x362b: 0x000c, 0x362c: 0x000c, 0x362d: 0x000c,
// Block 0xd9, offset 0x3640
0x3669: 0x000a,
0x366a: 0x000a,
// Block 0xda, offset 0x3680
0x3680: 0x000a, 0x3681: 0x000a, 0x3682: 0x000c, 0x3683: 0x000c, 0x3684: 0x000c, 0x3685: 0x000a,
// Block 0xdb, offset 0x36c0
0x36c0: 0x000a, 0x36c1: 0x000a, 0x36c2: 0x000a, 0x36c3: 0x000a, 0x36c4: 0x000a, 0x36c5: 0x000a,
0x36c6: 0x000a, 0x36c7: 0x000a, 0x36c8: 0x000a, 0x36c9: 0x000a, 0x36ca: 0x000a, 0x36cb: 0x000a,
0x36cc: 0x000a, 0x36cd: 0x000a, 0x36ce: 0x000a, 0x36cf: 0x000a, 0x36d0: 0x000a, 0x36d1: 0x000a,
0x36d2: 0x000a, 0x36d3: 0x000a, 0x36d4: 0x000a, 0x36d5: 0x000a, 0x36d6: 0x000a,
// Block 0xdc, offset 0x3700
0x371b: 0x000a,
// Block 0xdd, offset 0x3740
0x3755: 0x000a,
// Block 0xde, offset 0x3780
0x378f: 0x000a,
// Block 0xdf, offset 0x37c0
0x37c9: 0x000a,
// Block 0xe0, offset 0x3800
0x3803: 0x000a,
0x380e: 0x0002, 0x380f: 0x0002, 0x3810: 0x0002, 0x3811: 0x0002,
0x3812: 0x0002, 0x3813: 0x0002, 0x3814: 0x0002, 0x3815: 0x0002, 0x3816: 0x0002, 0x3817: 0x0002,
0x3818: 0x0002, 0x3819: 0x0002, 0x381a: 0x0002, 0x381b: 0x0002, 0x381c: 0x0002, 0x381d: 0x0002,
0x381e: 0x0002, 0x381f: 0x0002, 0x3820: 0x0002, 0x3821: 0x0002, 0x3822: 0x0002, 0x3823: 0x0002,
0x3824: 0x0002, 0x3825: 0x0002, 0x3826: 0x0002, 0x3827: 0x0002, 0x3828: 0x0002, 0x3829: 0x0002,
0x382a: 0x0002, 0x382b: 0x0002, 0x382c: 0x0002, 0x382d: 0x0002, 0x382e: 0x0002, 0x382f: 0x0002,
0x3830: 0x0002, 0x3831: 0x0002, 0x3832: 0x0002, 0x3833: 0x0002, 0x3834: 0x0002, 0x3835: 0x0002,
0x3836: 0x0002, 0x3837: 0x0002, 0x3838: 0x0002, 0x3839: 0x0002, 0x383a: 0x0002, 0x383b: 0x0002,
0x383c: 0x0002, 0x383d: 0x0002, 0x383e: 0x0002, 0x383f: 0x0002,
// Block 0xe1, offset 0x3840
0x3840: 0x000c, 0x3841: 0x000c, 0x3842: 0x000c, 0x3843: 0x000c, 0x3844: 0x000c, 0x3845: 0x000c,
0x3846: 0x000c, 0x3847: 0x000c, 0x3848: 0x000c, 0x3849: 0x000c, 0x384a: 0x000c, 0x384b: 0x000c,
0x384c: 0x000c, 0x384d: 0x000c, 0x384e: 0x000c, 0x384f: 0x000c, 0x3850: 0x000c, 0x3851: 0x000c,
0x3852: 0x000c, 0x3853: 0x000c, 0x3854: 0x000c, 0x3855: 0x000c, 0x3856: 0x000c, 0x3857: 0x000c,
0x3858: 0x000c, 0x3859: 0x000c, 0x385a: 0x000c, 0x385b: 0x000c, 0x385c: 0x000c, 0x385d: 0x000c,
0x385e: 0x000c, 0x385f: 0x000c, 0x3860: 0x000c, 0x3861: 0x000c, 0x3862: 0x000c, 0x3863: 0x000c,
0x3864: 0x000c, 0x3865: 0x000c, 0x3866: 0x000c, 0x3867: 0x000c, 0x3868: 0x000c, 0x3869: 0x000c,
0x386a: 0x000c, 0x386b: 0x000c, 0x386c: 0x000c, 0x386d: 0x000c, 0x386e: 0x000c, 0x386f: 0x000c,
0x3870: 0x000c, 0x3871: 0x000c, 0x3872: 0x000c, 0x3873: 0x000c, 0x3874: 0x000c, 0x3875: 0x000c,
0x3876: 0x000c, 0x387b: 0x000c,
0x387c: 0x000c, 0x387d: 0x000c, 0x387e: 0x000c, 0x387f: 0x000c,
// Block 0xe2, offset 0x3880
0x3880: 0x000c, 0x3881: 0x000c, 0x3882: 0x000c, 0x3883: 0x000c, 0x3884: 0x000c, 0x3885: 0x000c,
0x3886: 0x000c, 0x3887: 0x000c, 0x3888: 0x000c, 0x3889: 0x000c, 0x388a: 0x000c, 0x388b: 0x000c,
0x388c: 0x000c, 0x388d: 0x000c, 0x388e: 0x000c, 0x388f: 0x000c, 0x3890: 0x000c, 0x3891: 0x000c,
0x3892: 0x000c, 0x3893: 0x000c, 0x3894: 0x000c, 0x3895: 0x000c, 0x3896: 0x000c, 0x3897: 0x000c,
0x3898: 0x000c, 0x3899: 0x000c, 0x389a: 0x000c, 0x389b: 0x000c, 0x389c: 0x000c, 0x389d: 0x000c,
0x389e: 0x000c, 0x389f: 0x000c, 0x38a0: 0x000c, 0x38a1: 0x000c, 0x38a2: 0x000c, 0x38a3: 0x000c,
0x38a4: 0x000c, 0x38a5: 0x000c, 0x38a6: 0x000c, 0x38a7: 0x000c, 0x38a8: 0x000c, 0x38a9: 0x000c,
0x38aa: 0x000c, 0x38ab: 0x000c, 0x38ac: 0x000c,
0x38b5: 0x000c,
// Block 0xe3, offset 0x38c0
0x38c4: 0x000c,
0x38db: 0x000c, 0x38dc: 0x000c, 0x38dd: 0x000c,
0x38de: 0x000c, 0x38df: 0x000c, 0x38e1: 0x000c, 0x38e2: 0x000c, 0x38e3: 0x000c,
0x38e4: 0x000c, 0x38e5: 0x000c, 0x38e6: 0x000c, 0x38e7: 0x000c, 0x38e8: 0x000c, 0x38e9: 0x000c,
0x38ea: 0x000c, 0x38eb: 0x000c, 0x38ec: 0x000c, 0x38ed: 0x000c, 0x38ee: 0x000c, 0x38ef: 0x000c,
// Block 0xe4, offset 0x3900
0x3900: 0x000c, 0x3901: 0x000c, 0x3902: 0x000c, 0x3903: 0x000c, 0x3904: 0x000c, 0x3905: 0x000c,
0x3906: 0x000c, 0x3908: 0x000c, 0x3909: 0x000c, 0x390a: 0x000c, 0x390b: 0x000c,
0x390c: 0x000c, 0x390d: 0x000c, 0x390e: 0x000c, 0x390f: 0x000c, 0x3910: 0x000c, 0x3911: 0x000c,
0x3912: 0x000c, 0x3913: 0x000c, 0x3914: 0x000c, 0x3915: 0x000c, 0x3916: 0x000c, 0x3917: 0x000c,
0x3918: 0x000c, 0x391b: 0x000c, 0x391c: 0x000c, 0x391d: 0x000c,
0x391e: 0x000c, 0x391f: 0x000c, 0x3920: 0x000c, 0x3921: 0x000c, 0x3923: 0x000c,
0x3924: 0x000c, 0x3926: 0x000c, 0x3927: 0x000c, 0x3928: 0x000c, 0x3929: 0x000c,
0x392a: 0x000c,
// Block 0xe5, offset 0x3940
0x396e: 0x000c,
// Block 0xe6, offset 0x3980
0x39ac: 0x000c, 0x39ad: 0x000c, 0x39ae: 0x000c, 0x39af: 0x000c,
0x39bf: 0x0004,
// Block 0xe7, offset 0x39c0
0x39ec: 0x000c, 0x39ed: 0x000c, 0x39ee: 0x000c, 0x39ef: 0x000c,
// Block 0xe8, offset 0x3a00
0x3a00: 0x0001, 0x3a01: 0x0001, 0x3a02: 0x0001, 0x3a03: 0x0001, 0x3a04: 0x0001, 0x3a05: 0x0001,
0x3a06: 0x0001, 0x3a07: 0x0001, 0x3a08: 0x0001, 0x3a09: 0x0001, 0x3a0a: 0x0001, 0x3a0b: 0x0001,
0x3a0c: 0x0001, 0x3a0d: 0x0001, 0x3a0e: 0x0001, 0x3a0f: 0x0001, 0x3a10: 0x000c, 0x3a11: 0x000c,
0x3a12: 0x000c, 0x3a13: 0x000c, 0x3a14: 0x000c, 0x3a15: 0x000c, 0x3a16: 0x000c, 0x3a17: 0x0001,
0x3a18: 0x0001, 0x3a19: 0x0001, 0x3a1a: 0x0001, 0x3a1b: 0x0001, 0x3a1c: 0x0001, 0x3a1d: 0x0001,
0x3a1e: 0x0001, 0x3a1f: 0x0001, 0x3a20: 0x0001, 0x3a21: 0x0001, 0x3a22: 0x0001, 0x3a23: 0x0001,
0x3a24: 0x0001, 0x3a25: 0x0001, 0x3a26: 0x0001, 0x3a27: 0x0001, 0x3a28: 0x0001, 0x3a29: 0x0001,
0x3a2a: 0x0001, 0x3a2b: 0x0001, 0x3a2c: 0x0001, 0x3a2d: 0x0001, 0x3a2e: 0x0001, 0x3a2f: 0x0001,
0x3a30: 0x0001, 0x3a31: 0x0001, 0x3a32: 0x0001, 0x3a33: 0x0001, 0x3a34: 0x0001, 0x3a35: 0x0001,
0x3a36: 0x0001, 0x3a37: 0x0001, 0x3a38: 0x0001, 0x3a39: 0x0001, 0x3a3a: 0x0001, 0x3a3b: 0x0001,
0x3a3c: 0x0001, 0x3a3d: 0x0001, 0x3a3e: 0x0001, 0x3a3f: 0x0001,
// Block 0xe9, offset 0x3a40
0x3a40: 0x0001, 0x3a41: 0x0001, 0x3a42: 0x0001, 0x3a43: 0x0001, 0x3a44: 0x000c, 0x3a45: 0x000c,
0x3a46: 0x000c, 0x3a47: 0x000c, 0x3a48: 0x000c, 0x3a49: 0x000c, 0x3a4a: 0x000c, 0x3a4b: 0x0001,
0x3a4c: 0x0001, 0x3a4d: 0x0001, 0x3a4e: 0x0001, 0x3a4f: 0x0001, 0x3a50: 0x0001, 0x3a51: 0x0001,
0x3a52: 0x0001, 0x3a53: 0x0001, 0x3a54: 0x0001, 0x3a55: 0x0001, 0x3a56: 0x0001, 0x3a57: 0x0001,
0x3a58: 0x0001, 0x3a59: 0x0001, 0x3a5a: 0x0001, 0x3a5b: 0x0001, 0x3a5c: 0x0001, 0x3a5d: 0x0001,
0x3a5e: 0x0001, 0x3a5f: 0x0001, 0x3a60: 0x0001, 0x3a61: 0x0001, 0x3a62: 0x0001, 0x3a63: 0x0001,
0x3a64: 0x0001, 0x3a65: 0x0001, 0x3a66: 0x0001, 0x3a67: 0x0001, 0x3a68: 0x0001, 0x3a69: 0x0001,
0x3a6a: 0x0001, 0x3a6b: 0x0001, 0x3a6c: 0x0001, 0x3a6d: 0x0001, 0x3a6e: 0x0001, 0x3a6f: 0x0001,
0x3a70: 0x0001, 0x3a71: 0x0001, 0x3a72: 0x0001, 0x3a73: 0x0001, 0x3a74: 0x0001, 0x3a75: 0x0001,
0x3a76: 0x0001, 0x3a77: 0x0001, 0x3a78: 0x0001, 0x3a79: 0x0001, 0x3a7a: 0x0001, 0x3a7b: 0x0001,
0x3a7c: 0x0001, 0x3a7d: 0x0001, 0x3a7e: 0x0001, 0x3a7f: 0x0001,
// Block 0xea, offset 0x3a80
0x3a80: 0x0001, 0x3a81: 0x0001, 0x3a82: 0x0001, 0x3a83: 0x0001, 0x3a84: 0x0001, 0x3a85: 0x0001,
0x3a86: 0x0001, 0x3a87: 0x0001, 0x3a88: 0x0001, 0x3a89: 0x0001, 0x3a8a: 0x0001, 0x3a8b: 0x0001,
0x3a8c: 0x0001, 0x3a8d: 0x0001, 0x3a8e: 0x0001, 0x3a8f: 0x0001, 0x3a90: 0x0001, 0x3a91: 0x0001,
0x3a92: 0x0001, 0x3a93: 0x0001, 0x3a94: 0x0001, 0x3a95: 0x0001, 0x3a96: 0x0001, 0x3a97: 0x0001,
0x3a98: 0x0001, 0x3a99: 0x0001, 0x3a9a: 0x0001, 0x3a9b: 0x0001, 0x3a9c: 0x0001, 0x3a9d: 0x0001,
0x3a9e: 0x0001, 0x3a9f: 0x0001, 0x3aa0: 0x0001, 0x3aa1: 0x0001, 0x3aa2: 0x0001, 0x3aa3: 0x0001,
0x3aa4: 0x0001, 0x3aa5: 0x0001, 0x3aa6: 0x0001, 0x3aa7: 0x0001, 0x3aa8: 0x0001, 0x3aa9: 0x0001,
0x3aaa: 0x0001, 0x3aab: 0x0001, 0x3aac: 0x0001, 0x3aad: 0x0001, 0x3aae: 0x0001, 0x3aaf: 0x0001,
0x3ab0: 0x0001, 0x3ab1: 0x000d, 0x3ab2: 0x000d, 0x3ab3: 0x000d, 0x3ab4: 0x000d, 0x3ab5: 0x000d,
0x3ab6: 0x000d, 0x3ab7: 0x000d, 0x3ab8: 0x000d, 0x3ab9: 0x000d, 0x3aba: 0x000d, 0x3abb: 0x000d,
0x3abc: 0x000d, 0x3abd: 0x000d, 0x3abe: 0x000d, 0x3abf: 0x000d,
// Block 0xeb, offset 0x3ac0
0x3ac0: 0x000d, 0x3ac1: 0x000d, 0x3ac2: 0x000d, 0x3ac3: 0x000d, 0x3ac4: 0x000d, 0x3ac5: 0x000d,
0x3ac6: 0x000d, 0x3ac7: 0x000d, 0x3ac8: 0x000d, 0x3ac9: 0x000d, 0x3aca: 0x000d, 0x3acb: 0x000d,
0x3acc: 0x000d, 0x3acd: 0x000d, 0x3ace: 0x000d, 0x3acf: 0x000d, 0x3ad0: 0x000d, 0x3ad1: 0x000d,
0x3ad2: 0x000d, 0x3ad3: 0x000d, 0x3ad4: 0x000d, 0x3ad5: 0x000d, 0x3ad6: 0x000d, 0x3ad7: 0x000d,
0x3ad8: 0x000d, 0x3ad9: 0x000d, 0x3ada: 0x000d, 0x3adb: 0x000d, 0x3adc: 0x000d, 0x3add: 0x000d,
0x3ade: 0x000d, 0x3adf: 0x000d, 0x3ae0: 0x000d, 0x3ae1: 0x000d, 0x3ae2: 0x000d, 0x3ae3: 0x000d,
0x3ae4: 0x000d, 0x3ae5: 0x000d, 0x3ae6: 0x000d, 0x3ae7: 0x000d, 0x3ae8: 0x000d, 0x3ae9: 0x000d,
0x3aea: 0x000d, 0x3aeb: 0x000d, 0x3aec: 0x000d, 0x3aed: 0x000d, 0x3aee: 0x000d, 0x3aef: 0x000d,
0x3af0: 0x000d, 0x3af1: 0x000d, 0x3af2: 0x000d, 0x3af3: 0x000d, 0x3af4: 0x000d, 0x3af5: 0x0001,
0x3af6: 0x0001, 0x3af7: 0x0001, 0x3af8: 0x0001, 0x3af9: 0x0001, 0x3afa: 0x0001, 0x3afb: 0x0001,
0x3afc: 0x0001, 0x3afd: 0x0001, 0x3afe: 0x0001, 0x3aff: 0x0001,
// Block 0xec, offset 0x3b00
0x3b00: 0x0001, 0x3b01: 0x000d, 0x3b02: 0x000d, 0x3b03: 0x000d, 0x3b04: 0x000d, 0x3b05: 0x000d,
0x3b06: 0x000d, 0x3b07: 0x000d, 0x3b08: 0x000d, 0x3b09: 0x000d, 0x3b0a: 0x000d, 0x3b0b: 0x000d,
0x3b0c: 0x000d, 0x3b0d: 0x000d, 0x3b0e: 0x000d, 0x3b0f: 0x000d, 0x3b10: 0x000d, 0x3b11: 0x000d,
0x3b12: 0x000d, 0x3b13: 0x000d, 0x3b14: 0x000d, 0x3b15: 0x000d, 0x3b16: 0x000d, 0x3b17: 0x000d,
0x3b18: 0x000d, 0x3b19: 0x000d, 0x3b1a: 0x000d, 0x3b1b: 0x000d, 0x3b1c: 0x000d, 0x3b1d: 0x000d,
0x3b1e: 0x000d, 0x3b1f: 0x000d, 0x3b20: 0x000d, 0x3b21: 0x000d, 0x3b22: 0x000d, 0x3b23: 0x000d,
0x3b24: 0x000d, 0x3b25: 0x000d, 0x3b26: 0x000d, 0x3b27: 0x000d, 0x3b28: 0x000d, 0x3b29: 0x000d,
0x3b2a: 0x000d, 0x3b2b: 0x000d, 0x3b2c: 0x000d, 0x3b2d: 0x000d, 0x3b2e: 0x000d, 0x3b2f: 0x000d,
0x3b30: 0x000d, 0x3b31: 0x000d, 0x3b32: 0x000d, 0x3b33: 0x000d, 0x3b34: 0x000d, 0x3b35: 0x000d,
0x3b36: 0x000d, 0x3b37: 0x000d, 0x3b38: 0x000d, 0x3b39: 0x000d, 0x3b3a: 0x000d, 0x3b3b: 0x000d,
0x3b3c: 0x000d, 0x3b3d: 0x000d, 0x3b3e: 0x0001, 0x3b3f: 0x0001,
// Block 0xed, offset 0x3b40
0x3b40: 0x000d, 0x3b41: 0x000d, 0x3b42: 0x000d, 0x3b43: 0x000d, 0x3b44: 0x000d, 0x3b45: 0x000d,
0x3b46: 0x000d, 0x3b47: 0x000d, 0x3b48: 0x000d, 0x3b49: 0x000d, 0x3b4a: 0x000d, 0x3b4b: 0x000d,
0x3b4c: 0x000d, 0x3b4d: 0x000d, 0x3b4e: 0x000d, 0x3b4f: 0x000d, 0x3b50: 0x000d, 0x3b51: 0x000d,
0x3b52: 0x000d, 0x3b53: 0x000d, 0x3b54: 0x000d, 0x3b55: 0x000d, 0x3b56: 0x000d, 0x3b57: 0x000d,
0x3b58: 0x000d, 0x3b59: 0x000d, 0x3b5a: 0x000d, 0x3b5b: 0x000d, 0x3b5c: 0x000d, 0x3b5d: 0x000d,
0x3b5e: 0x000d, 0x3b5f: 0x000d, 0x3b60: 0x000d, 0x3b61: 0x000d, 0x3b62: 0x000d, 0x3b63: 0x000d,
0x3b64: 0x000d, 0x3b65: 0x000d, 0x3b66: 0x000d, 0x3b67: 0x000d, 0x3b68: 0x000d, 0x3b69: 0x000d,
0x3b6a: 0x000d, 0x3b6b: 0x000d, 0x3b6c: 0x000d, 0x3b6d: 0x000d, 0x3b6e: 0x000d, 0x3b6f: 0x000d,
0x3b70: 0x000a, 0x3b71: 0x000a, 0x3b72: 0x000d, 0x3b73: 0x000d, 0x3b74: 0x000d, 0x3b75: 0x000d,
0x3b76: 0x000d, 0x3b77: 0x000d, 0x3b78: 0x000d, 0x3b79: 0x000d, 0x3b7a: 0x000d, 0x3b7b: 0x000d,
0x3b7c: 0x000d, 0x3b7d: 0x000d, 0x3b7e: 0x000d, 0x3b7f: 0x000d,
// Block 0xee, offset 0x3b80
0x3b80: 0x000a, 0x3b81: 0x000a, 0x3b82: 0x000a, 0x3b83: 0x000a, 0x3b84: 0x000a, 0x3b85: 0x000a,
0x3b86: 0x000a, 0x3b87: 0x000a, 0x3b88: 0x000a, 0x3b89: 0x000a, 0x3b8a: 0x000a, 0x3b8b: 0x000a,
0x3b8c: 0x000a, 0x3b8d: 0x000a, 0x3b8e: 0x000a, 0x3b8f: 0x000a, 0x3b90: 0x000a, 0x3b91: 0x000a,
0x3b92: 0x000a, 0x3b93: 0x000a, 0x3b94: 0x000a, 0x3b95: 0x000a, 0x3b96: 0x000a, 0x3b97: 0x000a,
0x3b98: 0x000a, 0x3b99: 0x000a, 0x3b9a: 0x000a, 0x3b9b: 0x000a, 0x3b9c: 0x000a, 0x3b9d: 0x000a,
0x3b9e: 0x000a, 0x3b9f: 0x000a, 0x3ba0: 0x000a, 0x3ba1: 0x000a, 0x3ba2: 0x000a, 0x3ba3: 0x000a,
0x3ba4: 0x000a, 0x3ba5: 0x000a, 0x3ba6: 0x000a, 0x3ba7: 0x000a, 0x3ba8: 0x000a, 0x3ba9: 0x000a,
0x3baa: 0x000a, 0x3bab: 0x000a,
0x3bb0: 0x000a, 0x3bb1: 0x000a, 0x3bb2: 0x000a, 0x3bb3: 0x000a, 0x3bb4: 0x000a, 0x3bb5: 0x000a,
0x3bb6: 0x000a, 0x3bb7: 0x000a, 0x3bb8: 0x000a, 0x3bb9: 0x000a, 0x3bba: 0x000a, 0x3bbb: 0x000a,
0x3bbc: 0x000a, 0x3bbd: 0x000a, 0x3bbe: 0x000a, 0x3bbf: 0x000a,
// Block 0xef, offset 0x3bc0
0x3bc0: 0x000a, 0x3bc1: 0x000a, 0x3bc2: 0x000a, 0x3bc3: 0x000a, 0x3bc4: 0x000a, 0x3bc5: 0x000a,
0x3bc6: 0x000a, 0x3bc7: 0x000a, 0x3bc8: 0x000a, 0x3bc9: 0x000a, 0x3bca: 0x000a, 0x3bcb: 0x000a,
0x3bcc: 0x000a, 0x3bcd: 0x000a, 0x3bce: 0x000a, 0x3bcf: 0x000a, 0x3bd0: 0x000a, 0x3bd1: 0x000a,
0x3bd2: 0x000a, 0x3bd3: 0x000a,
0x3be0: 0x000a, 0x3be1: 0x000a, 0x3be2: 0x000a, 0x3be3: 0x000a,
0x3be4: 0x000a, 0x3be5: 0x000a, 0x3be6: 0x000a, 0x3be7: 0x000a, 0x3be8: 0x000a, 0x3be9: 0x000a,
0x3bea: 0x000a, 0x3beb: 0x000a, 0x3bec: 0x000a, 0x3bed: 0x000a, 0x3bee: 0x000a,
0x3bf1: 0x000a, 0x3bf2: 0x000a, 0x3bf3: 0x000a, 0x3bf4: 0x000a, 0x3bf5: 0x000a,
0x3bf6: 0x000a, 0x3bf7: 0x000a, 0x3bf8: 0x000a, 0x3bf9: 0x000a, 0x3bfa: 0x000a, 0x3bfb: 0x000a,
0x3bfc: 0x000a, 0x3bfd: 0x000a, 0x3bfe: 0x000a, 0x3bff: 0x000a,
// Block 0xf0, offset 0x3c00
0x3c01: 0x000a, 0x3c02: 0x000a, 0x3c03: 0x000a, 0x3c04: 0x000a, 0x3c05: 0x000a,
0x3c06: 0x000a, 0x3c07: 0x000a, 0x3c08: 0x000a, 0x3c09: 0x000a, 0x3c0a: 0x000a, 0x3c0b: 0x000a,
0x3c0c: 0x000a, 0x3c0d: 0x000a, 0x3c0e: 0x000a, 0x3c0f: 0x000a, 0x3c11: 0x000a,
0x3c12: 0x000a, 0x3c13: 0x000a, 0x3c14: 0x000a, 0x3c15: 0x000a, 0x3c16: 0x000a, 0x3c17: 0x000a,
0x3c18: 0x000a, 0x3c19: 0x000a, 0x3c1a: 0x000a, 0x3c1b: 0x000a, 0x3c1c: 0x000a, 0x3c1d: 0x000a,
0x3c1e: 0x000a, 0x3c1f: 0x000a, 0x3c20: 0x000a, 0x3c21: 0x000a, 0x3c22: 0x000a, 0x3c23: 0x000a,
0x3c24: 0x000a, 0x3c25: 0x000a, 0x3c26: 0x000a, 0x3c27: 0x000a, 0x3c28: 0x000a, 0x3c29: 0x000a,
0x3c2a: 0x000a, 0x3c2b: 0x000a, 0x3c2c: 0x000a, 0x3c2d: 0x000a, 0x3c2e: 0x000a, 0x3c2f: 0x000a,
0x3c30: 0x000a, 0x3c31: 0x000a, 0x3c32: 0x000a, 0x3c33: 0x000a, 0x3c34: 0x000a, 0x3c35: 0x000a,
// Block 0xf1, offset 0x3c40
0x3c40: 0x0002, 0x3c41: 0x0002, 0x3c42: 0x0002, 0x3c43: 0x0002, 0x3c44: 0x0002, 0x3c45: 0x0002,
0x3c46: 0x0002, 0x3c47: 0x0002, 0x3c48: 0x0002, 0x3c49: 0x0002, 0x3c4a: 0x0002, 0x3c4b: 0x000a,
0x3c4c: 0x000a, 0x3c4d: 0x000a, 0x3c4e: 0x000a, 0x3c4f: 0x000a,
0x3c6f: 0x000a,
// Block 0xf2, offset 0x3c80
0x3caa: 0x000a, 0x3cab: 0x000a, 0x3cac: 0x000a, 0x3cad: 0x000a, 0x3cae: 0x000a, 0x3caf: 0x000a,
// Block 0xf3, offset 0x3cc0
0x3ced: 0x000a,
// Block 0xf4, offset 0x3d00
0x3d20: 0x000a, 0x3d21: 0x000a, 0x3d22: 0x000a, 0x3d23: 0x000a,
0x3d24: 0x000a, 0x3d25: 0x000a,
// Block 0xf5, offset 0x3d40
0x3d40: 0x000a, 0x3d41: 0x000a, 0x3d42: 0x000a, 0x3d43: 0x000a, 0x3d44: 0x000a, 0x3d45: 0x000a,
0x3d46: 0x000a, 0x3d47: 0x000a, 0x3d48: 0x000a, 0x3d49: 0x000a, 0x3d4a: 0x000a, 0x3d4b: 0x000a,
0x3d4c: 0x000a, 0x3d4d: 0x000a, 0x3d4e: 0x000a, 0x3d4f: 0x000a, 0x3d50: 0x000a, 0x3d51: 0x000a,
0x3d52: 0x000a, 0x3d53: 0x000a, 0x3d54: 0x000a, 0x3d55: 0x000a, 0x3d56: 0x000a, 0x3d57: 0x000a,
0x3d5c: 0x000a, 0x3d5d: 0x000a,
0x3d5e: 0x000a, 0x3d5f: 0x000a, 0x3d60: 0x000a, 0x3d61: 0x000a, 0x3d62: 0x000a, 0x3d63: 0x000a,
0x3d64: 0x000a, 0x3d65: 0x000a, 0x3d66: 0x000a, 0x3d67: 0x000a, 0x3d68: 0x000a, 0x3d69: 0x000a,
0x3d6a: 0x000a, 0x3d6b: 0x000a, 0x3d6c: 0x000a,
0x3d70: 0x000a, 0x3d71: 0x000a, 0x3d72: 0x000a, 0x3d73: 0x000a, 0x3d74: 0x000a, 0x3d75: 0x000a,
0x3d76: 0x000a, 0x3d77: 0x000a, 0x3d78: 0x000a, 0x3d79: 0x000a, 0x3d7a: 0x000a, 0x3d7b: 0x000a,
0x3d7c: 0x000a,
// Block 0xf6, offset 0x3d80
0x3d80: 0x000a, 0x3d81: 0x000a, 0x3d82: 0x000a, 0x3d83: 0x000a, 0x3d84: 0x000a, 0x3d85: 0x000a,
0x3d86: 0x000a, 0x3d87: 0x000a, 0x3d88: 0x000a, 0x3d89: 0x000a, 0x3d8a: 0x000a, 0x3d8b: 0x000a,
0x3d8c: 0x000a, 0x3d8d: 0x000a, 0x3d8e: 0x000a, 0x3d8f: 0x000a, 0x3d90: 0x000a, 0x3d91: 0x000a,
0x3d92: 0x000a, 0x3d93: 0x000a, 0x3d94: 0x000a, 0x3d95: 0x000a, 0x3d96: 0x000a, 0x3d97: 0x000a,
0x3d98: 0x000a, 0x3d99: 0x000a, 0x3d9a: 0x000a, 0x3d9b: 0x000a, 0x3d9c: 0x000a, 0x3d9d: 0x000a,
0x3d9e: 0x000a, 0x3d9f: 0x000a, 0x3da0: 0x000a, 0x3da1: 0x000a, 0x3da2: 0x000a, 0x3da3: 0x000a,
0x3da4: 0x000a, 0x3da5: 0x000a, 0x3da6: 0x000a, 0x3da7: 0x000a, 0x3da8: 0x000a, 0x3da9: 0x000a,
0x3daa: 0x000a, 0x3dab: 0x000a, 0x3dac: 0x000a, 0x3dad: 0x000a, 0x3dae: 0x000a, 0x3daf: 0x000a,
0x3db0: 0x000a, 0x3db1: 0x000a, 0x3db2: 0x000a, 0x3db3: 0x000a, 0x3db4: 0x000a, 0x3db5: 0x000a,
0x3db6: 0x000a, 0x3dbb: 0x000a,
0x3dbc: 0x000a, 0x3dbd: 0x000a, 0x3dbe: 0x000a, 0x3dbf: 0x000a,
// Block 0xf7, offset 0x3dc0
0x3dc0: 0x000a, 0x3dc1: 0x000a, 0x3dc2: 0x000a, 0x3dc3: 0x000a, 0x3dc4: 0x000a, 0x3dc5: 0x000a,
0x3dc6: 0x000a, 0x3dc7: 0x000a, 0x3dc8: 0x000a, 0x3dc9: 0x000a, 0x3dca: 0x000a, 0x3dcb: 0x000a,
0x3dcc: 0x000a, 0x3dcd: 0x000a, 0x3dce: 0x000a, 0x3dcf: 0x000a, 0x3dd0: 0x000a, 0x3dd1: 0x000a,
0x3dd2: 0x000a, 0x3dd3: 0x000a, 0x3dd4: 0x000a, 0x3dd5: 0x000a, 0x3dd6: 0x000a, 0x3dd7: 0x000a,
0x3dd8: 0x000a, 0x3dd9: 0x000a,
0x3de0: 0x000a, 0x3de1: 0x000a, 0x3de2: 0x000a, 0x3de3: 0x000a,
0x3de4: 0x000a, 0x3de5: 0x000a, 0x3de6: 0x000a, 0x3de7: 0x000a, 0x3de8: 0x000a, 0x3de9: 0x000a,
0x3dea: 0x000a, 0x3deb: 0x000a,
0x3df0: 0x000a,
// Block 0xf8, offset 0x3e00
0x3e00: 0x000a, 0x3e01: 0x000a, 0x3e02: 0x000a, 0x3e03: 0x000a, 0x3e04: 0x000a, 0x3e05: 0x000a,
0x3e06: 0x000a, 0x3e07: 0x000a, 0x3e08: 0x000a, 0x3e09: 0x000a, 0x3e0a: 0x000a, 0x3e0b: 0x000a,
0x3e10: 0x000a, 0x3e11: 0x000a,
0x3e12: 0x000a, 0x3e13: 0x000a, 0x3e14: 0x000a, 0x3e15: 0x000a, 0x3e16: 0x000a, 0x3e17: 0x000a,
0x3e18: 0x000a, 0x3e19: 0x000a, 0x3e1a: 0x000a, 0x3e1b: 0x000a, 0x3e1c: 0x000a, 0x3e1d: 0x000a,
0x3e1e: 0x000a, 0x3e1f: 0x000a, 0x3e20: 0x000a, 0x3e21: 0x000a, 0x3e22: 0x000a, 0x3e23: 0x000a,
0x3e24: 0x000a, 0x3e25: 0x000a, 0x3e26: 0x000a, 0x3e27: 0x000a, 0x3e28: 0x000a, 0x3e29: 0x000a,
0x3e2a: 0x000a, 0x3e2b: 0x000a, 0x3e2c: 0x000a, 0x3e2d: 0x000a, 0x3e2e: 0x000a, 0x3e2f: 0x000a,
0x3e30: 0x000a, 0x3e31: 0x000a, 0x3e32: 0x000a, 0x3e33: 0x000a, 0x3e34: 0x000a, 0x3e35: 0x000a,
0x3e36: 0x000a, 0x3e37: 0x000a, 0x3e38: 0x000a, 0x3e39: 0x000a, 0x3e3a: 0x000a, 0x3e3b: 0x000a,
0x3e3c: 0x000a, 0x3e3d: 0x000a, 0x3e3e: 0x000a, 0x3e3f: 0x000a,
// Block 0xf9, offset 0x3e40
0x3e40: 0x000a, 0x3e41: 0x000a, 0x3e42: 0x000a, 0x3e43: 0x000a, 0x3e44: 0x000a, 0x3e45: 0x000a,
0x3e46: 0x000a, 0x3e47: 0x000a,
0x3e50: 0x000a, 0x3e51: 0x000a,
0x3e52: 0x000a, 0x3e53: 0x000a, 0x3e54: 0x000a, 0x3e55: 0x000a, 0x3e56: 0x000a, 0x3e57: 0x000a,
0x3e58: 0x000a, 0x3e59: 0x000a,
0x3e60: 0x000a, 0x3e61: 0x000a, 0x3e62: 0x000a, 0x3e63: 0x000a,
0x3e64: 0x000a, 0x3e65: 0x000a, 0x3e66: 0x000a, 0x3e67: 0x000a, 0x3e68: 0x000a, 0x3e69: 0x000a,
0x3e6a: 0x000a, 0x3e6b: 0x000a, 0x3e6c: 0x000a, 0x3e6d: 0x000a, 0x3e6e: 0x000a, 0x3e6f: 0x000a,
0x3e70: 0x000a, 0x3e71: 0x000a, 0x3e72: 0x000a, 0x3e73: 0x000a, 0x3e74: 0x000a, 0x3e75: 0x000a,
0x3e76: 0x000a, 0x3e77: 0x000a, 0x3e78: 0x000a, 0x3e79: 0x000a, 0x3e7a: 0x000a, 0x3e7b: 0x000a,
0x3e7c: 0x000a, 0x3e7d: 0x000a, 0x3e7e: 0x000a, 0x3e7f: 0x000a,
// Block 0xfa, offset 0x3e80
0x3e80: 0x000a, 0x3e81: 0x000a, 0x3e82: 0x000a, 0x3e83: 0x000a, 0x3e84: 0x000a, 0x3e85: 0x000a,
0x3e86: 0x000a, 0x3e87: 0x000a,
0x3e90: 0x000a, 0x3e91: 0x000a,
0x3e92: 0x000a, 0x3e93: 0x000a, 0x3e94: 0x000a, 0x3e95: 0x000a, 0x3e96: 0x000a, 0x3e97: 0x000a,
0x3e98: 0x000a, 0x3e99: 0x000a, 0x3e9a: 0x000a, 0x3e9b: 0x000a, 0x3e9c: 0x000a, 0x3e9d: 0x000a,
0x3e9e: 0x000a, 0x3e9f: 0x000a, 0x3ea0: 0x000a, 0x3ea1: 0x000a, 0x3ea2: 0x000a, 0x3ea3: 0x000a,
0x3ea4: 0x000a, 0x3ea5: 0x000a, 0x3ea6: 0x000a, 0x3ea7: 0x000a, 0x3ea8: 0x000a, 0x3ea9: 0x000a,
0x3eaa: 0x000a, 0x3eab: 0x000a, 0x3eac: 0x000a, 0x3ead: 0x000a,
0x3eb0: 0x000a, 0x3eb1: 0x000a,
// Block 0xfb, offset 0x3ec0
0x3ec0: 0x000a, 0x3ec1: 0x000a, 0x3ec2: 0x000a, 0x3ec3: 0x000a, 0x3ec4: 0x000a, 0x3ec5: 0x000a,
0x3ec6: 0x000a, 0x3ec7: 0x000a, 0x3ec8: 0x000a, 0x3ec9: 0x000a, 0x3eca: 0x000a, 0x3ecb: 0x000a,
0x3ecc: 0x000a, 0x3ecd: 0x000a, 0x3ece: 0x000a, 0x3ecf: 0x000a, 0x3ed0: 0x000a, 0x3ed1: 0x000a,
0x3ed2: 0x000a, 0x3ed3: 0x000a,
0x3ee0: 0x000a, 0x3ee1: 0x000a, 0x3ee2: 0x000a, 0x3ee3: 0x000a,
0x3ee4: 0x000a, 0x3ee5: 0x000a, 0x3ee6: 0x000a, 0x3ee7: 0x000a, 0x3ee8: 0x000a, 0x3ee9: 0x000a,
0x3eea: 0x000a, 0x3eeb: 0x000a, 0x3eec: 0x000a, 0x3eed: 0x000a,
0x3ef0: 0x000a, 0x3ef1: 0x000a, 0x3ef2: 0x000a, 0x3ef3: 0x000a, 0x3ef4: 0x000a, 0x3ef5: 0x000a,
0x3ef6: 0x000a, 0x3ef7: 0x000a, 0x3ef8: 0x000a, 0x3ef9: 0x000a, 0x3efa: 0x000a, 0x3efb: 0x000a,
0x3efc: 0x000a,
// Block 0xfc, offset 0x3f00
0x3f00: 0x000a, 0x3f01: 0x000a, 0x3f02: 0x000a, 0x3f03: 0x000a, 0x3f04: 0x000a, 0x3f05: 0x000a,
0x3f06: 0x000a, 0x3f07: 0x000a, 0x3f08: 0x000a,
0x3f10: 0x000a, 0x3f11: 0x000a,
0x3f12: 0x000a, 0x3f13: 0x000a, 0x3f14: 0x000a, 0x3f15: 0x000a, 0x3f16: 0x000a, 0x3f17: 0x000a,
0x3f18: 0x000a, 0x3f19: 0x000a, 0x3f1a: 0x000a, 0x3f1b: 0x000a, 0x3f1c: 0x000a, 0x3f1d: 0x000a,
0x3f1e: 0x000a, 0x3f1f: 0x000a, 0x3f20: 0x000a, 0x3f21: 0x000a, 0x3f22: 0x000a, 0x3f23: 0x000a,
0x3f24: 0x000a, 0x3f25: 0x000a, 0x3f26: 0x000a, 0x3f27: 0x000a, 0x3f28: 0x000a, 0x3f29: 0x000a,
0x3f2a: 0x000a, 0x3f2b: 0x000a, 0x3f2c: 0x000a, 0x3f2d: 0x000a, 0x3f2e: 0x000a, 0x3f2f: 0x000a,
0x3f30: 0x000a, 0x3f31: 0x000a, 0x3f32: 0x000a, 0x3f33: 0x000a, 0x3f34: 0x000a, 0x3f35: 0x000a,
0x3f36: 0x000a, 0x3f37: 0x000a, 0x3f38: 0x000a, 0x3f39: 0x000a, 0x3f3a: 0x000a, 0x3f3b: 0x000a,
0x3f3c: 0x000a, 0x3f3d: 0x000a, 0x3f3f: 0x000a,
// Block 0xfd, offset 0x3f40
0x3f40: 0x000a, 0x3f41: 0x000a, 0x3f42: 0x000a, 0x3f43: 0x000a, 0x3f44: 0x000a, 0x3f45: 0x000a,
0x3f4e: 0x000a, 0x3f4f: 0x000a, 0x3f50: 0x000a, 0x3f51: 0x000a,
0x3f52: 0x000a, 0x3f53: 0x000a, 0x3f54: 0x000a, 0x3f55: 0x000a, 0x3f56: 0x000a, 0x3f57: 0x000a,
0x3f58: 0x000a, 0x3f59: 0x000a, 0x3f5a: 0x000a, 0x3f5b: 0x000a,
0x3f60: 0x000a, 0x3f61: 0x000a, 0x3f62: 0x000a, 0x3f63: 0x000a,
0x3f64: 0x000a, 0x3f65: 0x000a, 0x3f66: 0x000a, 0x3f67: 0x000a, 0x3f68: 0x000a,
0x3f70: 0x000a, 0x3f71: 0x000a, 0x3f72: 0x000a, 0x3f73: 0x000a, 0x3f74: 0x000a, 0x3f75: 0x000a,
0x3f76: 0x000a, 0x3f77: 0x000a, 0x3f78: 0x000a,
// Block 0xfe, offset 0x3f80
0x3f80: 0x000a, 0x3f81: 0x000a, 0x3f82: 0x000a, 0x3f83: 0x000a, 0x3f84: 0x000a, 0x3f85: 0x000a,
0x3f86: 0x000a, 0x3f87: 0x000a, 0x3f88: 0x000a, 0x3f89: 0x000a, 0x3f8a: 0x000a, 0x3f8b: 0x000a,
0x3f8c: 0x000a, 0x3f8d: 0x000a, 0x3f8e: 0x000a, 0x3f8f: 0x000a, 0x3f90: 0x000a, 0x3f91: 0x000a,
0x3f92: 0x000a, 0x3f94: 0x000a, 0x3f95: 0x000a, 0x3f96: 0x000a, 0x3f97: 0x000a,
0x3f98: 0x000a, 0x3f99: 0x000a, 0x3f9a: 0x000a, 0x3f9b: 0x000a, 0x3f9c: 0x000a, 0x3f9d: 0x000a,
0x3f9e: 0x000a, 0x3f9f: 0x000a, 0x3fa0: 0x000a, 0x3fa1: 0x000a, 0x3fa2: 0x000a, 0x3fa3: 0x000a,
0x3fa4: 0x000a, 0x3fa5: 0x000a, 0x3fa6: 0x000a, 0x3fa7: 0x000a, 0x3fa8: 0x000a, 0x3fa9: 0x000a,
0x3faa: 0x000a, 0x3fab: 0x000a, 0x3fac: 0x000a, 0x3fad: 0x000a, 0x3fae: 0x000a, 0x3faf: 0x000a,
0x3fb0: 0x000a, 0x3fb1: 0x000a, 0x3fb2: 0x000a, 0x3fb3: 0x000a, 0x3fb4: 0x000a, 0x3fb5: 0x000a,
0x3fb6: 0x000a, 0x3fb7: 0x000a, 0x3fb8: 0x000a, 0x3fb9: 0x000a, 0x3fba: 0x000a, 0x3fbb: 0x000a,
0x3fbc: 0x000a, 0x3fbd: 0x000a, 0x3fbe: 0x000a, 0x3fbf: 0x000a,
// Block 0xff, offset 0x3fc0
0x3fc0: 0x000a, 0x3fc1: 0x000a, 0x3fc2: 0x000a, 0x3fc3: 0x000a, 0x3fc4: 0x000a, 0x3fc5: 0x000a,
0x3fc6: 0x000a, 0x3fc7: 0x000a, 0x3fc8: 0x000a, 0x3fc9: 0x000a, 0x3fca: 0x000a,
0x3ff0: 0x0002, 0x3ff1: 0x0002, 0x3ff2: 0x0002, 0x3ff3: 0x0002, 0x3ff4: 0x0002, 0x3ff5: 0x0002,
0x3ff6: 0x0002, 0x3ff7: 0x0002, 0x3ff8: 0x0002, 0x3ff9: 0x0002,
// Block 0x100, offset 0x4000
0x403e: 0x000b, 0x403f: 0x000b,
// Block 0x101, offset 0x4040
0x4040: 0x000b, 0x4041: 0x000b, 0x4042: 0x000b, 0x4043: 0x000b, 0x4044: 0x000b, 0x4045: 0x000b,
0x4046: 0x000b, 0x4047: 0x000b, 0x4048: 0x000b, 0x4049: 0x000b, 0x404a: 0x000b, 0x404b: 0x000b,
0x404c: 0x000b, 0x404d: 0x000b, 0x404e: 0x000b, 0x404f: 0x000b, 0x4050: 0x000b, 0x4051: 0x000b,
0x4052: 0x000b, 0x4053: 0x000b, 0x4054: 0x000b, 0x4055: 0x000b, 0x4056: 0x000b, 0x4057: 0x000b,
0x4058: 0x000b, 0x4059: 0x000b, 0x405a: 0x000b, 0x405b: 0x000b, 0x405c: 0x000b, 0x405d: 0x000b,
0x405e: 0x000b, 0x405f: 0x000b, 0x4060: 0x000b, 0x4061: 0x000b, 0x4062: 0x000b, 0x4063: 0x000b,
0x4064: 0x000b, 0x4065: 0x000b, 0x4066: 0x000b, 0x4067: 0x000b, 0x4068: 0x000b, 0x4069: 0x000b,
0x406a: 0x000b, 0x406b: 0x000b, 0x406c: 0x000b, 0x406d: 0x000b, 0x406e: 0x000b, 0x406f: 0x000b,
0x4070: 0x000b, 0x4071: 0x000b, 0x4072: 0x000b, 0x4073: 0x000b, 0x4074: 0x000b, 0x4075: 0x000b,
0x4076: 0x000b, 0x4077: 0x000b, 0x4078: 0x000b, 0x4079: 0x000b, 0x407a: 0x000b, 0x407b: 0x000b,
0x407c: 0x000b, 0x407d: 0x000b, 0x407e: 0x000b, 0x407f: 0x000b,
// Block 0x102, offset 0x4080
0x4080: 0x000c, 0x4081: 0x000c, 0x4082: 0x000c, 0x4083: 0x000c, 0x4084: 0x000c, 0x4085: 0x000c,
0x4086: 0x000c, 0x4087: 0x000c, 0x4088: 0x000c, 0x4089: 0x000c, 0x408a: 0x000c, 0x408b: 0x000c,
0x408c: 0x000c, 0x408d: 0x000c, 0x408e: 0x000c, 0x408f: 0x000c, 0x4090: 0x000c, 0x4091: 0x000c,
0x4092: 0x000c, 0x4093: 0x000c, 0x4094: 0x000c, 0x4095: 0x000c, 0x4096: 0x000c, 0x4097: 0x000c,
0x4098: 0x000c, 0x4099: 0x000c, 0x409a: 0x000c, 0x409b: 0x000c, 0x409c: 0x000c, 0x409d: 0x000c,
0x409e: 0x000c, 0x409f: 0x000c, 0x40a0: 0x000c, 0x40a1: 0x000c, 0x40a2: 0x000c, 0x40a3: 0x000c,
0x40a4: 0x000c, 0x40a5: 0x000c, 0x40a6: 0x000c, 0x40a7: 0x000c, 0x40a8: 0x000c, 0x40a9: 0x000c,
0x40aa: 0x000c, 0x40ab: 0x000c, 0x40ac: 0x000c, 0x40ad: 0x000c, 0x40ae: 0x000c, 0x40af: 0x000c,
0x40b0: 0x000b, 0x40b1: 0x000b, 0x40b2: 0x000b, 0x40b3: 0x000b, 0x40b4: 0x000b, 0x40b5: 0x000b,
0x40b6: 0x000b, 0x40b7: 0x000b, 0x40b8: 0x000b, 0x40b9: 0x000b, 0x40ba: 0x000b, 0x40bb: 0x000b,
0x40bc: 0x000b, 0x40bd: 0x000b, 0x40be: 0x000b, 0x40bf: 0x000b,
}
// bidiIndex: 26 blocks, 1664 entries, 3328 bytes
// Block 0 is the zero block.
var bidiIndex = [1664]uint16{
// Block 0x0, offset 0x0
// Block 0x1, offset 0x40
// Block 0x2, offset 0x80
// Block 0x3, offset 0xc0
0xc2: 0x01, 0xc3: 0x02,
0xca: 0x03, 0xcb: 0x04, 0xcc: 0x05, 0xcd: 0x06, 0xce: 0x07, 0xcf: 0x08,
0xd2: 0x09, 0xd6: 0x0a, 0xd7: 0x0b,
0xd8: 0x0c, 0xd9: 0x0d, 0xda: 0x0e, 0xdb: 0x0f, 0xdc: 0x10, 0xdd: 0x11, 0xde: 0x12, 0xdf: 0x13,
0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, 0xe4: 0x06,
0xea: 0x07, 0xef: 0x08,
0xf0: 0x13, 0xf1: 0x14, 0xf2: 0x14, 0xf3: 0x16, 0xf4: 0x17,
// Block 0x4, offset 0x100
0x120: 0x14, 0x121: 0x15, 0x122: 0x16, 0x123: 0x17, 0x124: 0x18, 0x125: 0x19, 0x126: 0x1a, 0x127: 0x1b,
0x128: 0x1c, 0x129: 0x1d, 0x12a: 0x1c, 0x12b: 0x1e, 0x12c: 0x1f, 0x12d: 0x20, 0x12e: 0x21, 0x12f: 0x22,
0x130: 0x23, 0x131: 0x24, 0x132: 0x1a, 0x133: 0x25, 0x134: 0x26, 0x135: 0x27, 0x136: 0x28, 0x137: 0x29,
0x138: 0x2a, 0x139: 0x2b, 0x13a: 0x2c, 0x13b: 0x2d, 0x13c: 0x2e, 0x13d: 0x2f, 0x13e: 0x30, 0x13f: 0x31,
// Block 0x5, offset 0x140
0x140: 0x32, 0x141: 0x33, 0x142: 0x34,
0x14d: 0x35, 0x14e: 0x36,
0x150: 0x37,
0x15a: 0x38, 0x15c: 0x39, 0x15d: 0x3a, 0x15e: 0x3b, 0x15f: 0x3c,
0x160: 0x3d, 0x162: 0x3e, 0x164: 0x3f, 0x165: 0x40, 0x167: 0x41,
0x168: 0x42, 0x169: 0x43, 0x16a: 0x44, 0x16b: 0x45, 0x16c: 0x46, 0x16d: 0x47, 0x16e: 0x48, 0x16f: 0x49,
0x170: 0x4a, 0x173: 0x4b, 0x177: 0x05,
0x17e: 0x4c, 0x17f: 0x4d,
// Block 0x6, offset 0x180
0x180: 0x4e, 0x181: 0x4f, 0x182: 0x50, 0x183: 0x51, 0x184: 0x52, 0x185: 0x53, 0x186: 0x54, 0x187: 0x55,
0x188: 0x56, 0x189: 0x55, 0x18a: 0x55, 0x18b: 0x55, 0x18c: 0x57, 0x18d: 0x58, 0x18e: 0x59, 0x18f: 0x55,
0x190: 0x5a, 0x191: 0x5b, 0x192: 0x5c, 0x193: 0x5d, 0x194: 0x55, 0x195: 0x55, 0x196: 0x55, 0x197: 0x55,
0x198: 0x55, 0x199: 0x55, 0x19a: 0x5e, 0x19b: 0x55, 0x19c: 0x55, 0x19d: 0x5f, 0x19e: 0x55, 0x19f: 0x60,
0x1a4: 0x55, 0x1a5: 0x55, 0x1a6: 0x61, 0x1a7: 0x62,
0x1a8: 0x55, 0x1a9: 0x55, 0x1aa: 0x55, 0x1ab: 0x55, 0x1ac: 0x55, 0x1ad: 0x63, 0x1ae: 0x64, 0x1af: 0x55,
0x1b3: 0x65, 0x1b5: 0x66, 0x1b7: 0x67,
0x1b8: 0x68, 0x1b9: 0x69, 0x1ba: 0x6a, 0x1bb: 0x6b, 0x1bc: 0x55, 0x1bd: 0x55, 0x1be: 0x55, 0x1bf: 0x6c,
// Block 0x7, offset 0x1c0
0x1c0: 0x6d, 0x1c2: 0x6e, 0x1c3: 0x6f, 0x1c7: 0x70,
0x1c8: 0x71, 0x1c9: 0x72, 0x1ca: 0x73, 0x1cb: 0x74, 0x1cd: 0x75, 0x1cf: 0x76,
// Block 0x8, offset 0x200
0x237: 0x55,
// Block 0x9, offset 0x240
0x252: 0x77, 0x253: 0x78,
0x258: 0x79, 0x259: 0x7a, 0x25a: 0x7b, 0x25b: 0x7c, 0x25c: 0x7d, 0x25e: 0x7e,
0x260: 0x7f, 0x261: 0x80, 0x263: 0x81, 0x264: 0x82, 0x265: 0x83, 0x266: 0x84, 0x267: 0x85,
0x268: 0x86, 0x269: 0x87, 0x26a: 0x88, 0x26b: 0x89, 0x26d: 0x8a, 0x26f: 0x8b,
// Block 0xa, offset 0x280
0x2ac: 0x8c, 0x2ad: 0x8d, 0x2ae: 0x0e, 0x2af: 0x0e,
0x2b0: 0x0e, 0x2b1: 0x0e, 0x2b2: 0x0e, 0x2b3: 0x0e, 0x2b4: 0x8e, 0x2b5: 0x8f, 0x2b6: 0x0e, 0x2b7: 0x90,
0x2b8: 0x91, 0x2b9: 0x92, 0x2ba: 0x0e, 0x2bb: 0x93, 0x2bc: 0x94, 0x2bd: 0x95, 0x2bf: 0x96,
// Block 0xb, offset 0x2c0
0x2c4: 0x97, 0x2c5: 0x55, 0x2c6: 0x98, 0x2c7: 0x99,
0x2cb: 0x9a, 0x2cd: 0x9b,
0x2e0: 0x9c, 0x2e1: 0x9c, 0x2e2: 0x9c, 0x2e3: 0x9c, 0x2e4: 0x9d, 0x2e5: 0x9c, 0x2e6: 0x9c, 0x2e7: 0x9c,
0x2e8: 0x9e, 0x2e9: 0x9c, 0x2ea: 0x9c, 0x2eb: 0x9f, 0x2ec: 0xa0, 0x2ed: 0x9c, 0x2ee: 0x9c, 0x2ef: 0x9c,
0x2f0: 0x9c, 0x2f1: 0x9c, 0x2f2: 0x9c, 0x2f3: 0x9c, 0x2f4: 0xa1, 0x2f5: 0x9c, 0x2f6: 0x9c, 0x2f7: 0x9c,
0x2f8: 0x9c, 0x2f9: 0xa2, 0x2fa: 0xa3, 0x2fb: 0xa4, 0x2fc: 0xa5, 0x2fd: 0xa6, 0x2fe: 0xa7, 0x2ff: 0x9c,
// Block 0xc, offset 0x300
0x300: 0xa8, 0x301: 0xa9, 0x302: 0xaa, 0x303: 0x21, 0x304: 0xab, 0x305: 0xac, 0x306: 0xad, 0x307: 0xae,
0x308: 0xaf, 0x309: 0x28, 0x30b: 0xb0, 0x30c: 0x26, 0x30d: 0xb1,
0x310: 0xb2, 0x311: 0xb3, 0x312: 0xb4, 0x313: 0xb5, 0x316: 0xb6, 0x317: 0xb7,
0x318: 0xb8, 0x319: 0xb9, 0x31a: 0xba, 0x31c: 0xbb,
0x320: 0xbc, 0x324: 0xbd, 0x325: 0xbe, 0x327: 0xbf,
0x328: 0xc0, 0x329: 0xc1, 0x32a: 0xc2,
0x330: 0xc3, 0x332: 0xc4, 0x334: 0xc5, 0x335: 0xc6, 0x336: 0xc7,
0x33b: 0xc8, 0x33c: 0xc9, 0x33d: 0xca, 0x33f: 0xcb,
// Block 0xd, offset 0x340
0x351: 0xcc,
// Block 0xe, offset 0x380
0x3ab: 0xcd, 0x3ac: 0xce,
0x3bd: 0xcf, 0x3be: 0xd0, 0x3bf: 0xd1,
// Block 0xf, offset 0x3c0
0x3f2: 0xd2,
// Block 0x10, offset 0x400
0x43c: 0xd3, 0x43d: 0xd4,
// Block 0x11, offset 0x440
0x445: 0xd5, 0x446: 0xd6, 0x447: 0xd7,
0x448: 0x55, 0x449: 0xd8, 0x44c: 0x55, 0x44d: 0xd9,
0x45b: 0xda, 0x45c: 0xdb, 0x45d: 0xdc, 0x45e: 0xdd, 0x45f: 0xde,
0x468: 0xdf, 0x469: 0xe0, 0x46a: 0xe1,
// Block 0x12, offset 0x480
0x480: 0xe2, 0x482: 0xcf, 0x484: 0xce,
0x48a: 0xe3, 0x48b: 0xe4,
0x493: 0xe5,
0x4a0: 0x9c, 0x4a1: 0x9c, 0x4a2: 0x9c, 0x4a3: 0xe6, 0x4a4: 0x9c, 0x4a5: 0xe7, 0x4a6: 0x9c, 0x4a7: 0x9c,
0x4a8: 0x9c, 0x4a9: 0x9c, 0x4aa: 0x9c, 0x4ab: 0x9c, 0x4ac: 0x9c, 0x4ad: 0x9c, 0x4ae: 0x9c, 0x4af: 0x9c,
0x4b0: 0x9c, 0x4b1: 0xe8, 0x4b2: 0xe9, 0x4b3: 0x9c, 0x4b4: 0xea, 0x4b5: 0x9c, 0x4b6: 0x9c, 0x4b7: 0x9c,
0x4b8: 0x0e, 0x4b9: 0x0e, 0x4ba: 0x0e, 0x4bb: 0xeb, 0x4bc: 0x9c, 0x4bd: 0x9c, 0x4be: 0x9c, 0x4bf: 0x9c,
// Block 0x13, offset 0x4c0
0x4c0: 0xec, 0x4c1: 0x55, 0x4c2: 0xed, 0x4c3: 0xee, 0x4c4: 0xef, 0x4c5: 0xf0, 0x4c6: 0xf1,
0x4c9: 0xf2, 0x4cc: 0x55, 0x4cd: 0x55, 0x4ce: 0x55, 0x4cf: 0x55,
0x4d0: 0x55, 0x4d1: 0x55, 0x4d2: 0x55, 0x4d3: 0x55, 0x4d4: 0x55, 0x4d5: 0x55, 0x4d6: 0x55, 0x4d7: 0x55,
0x4d8: 0x55, 0x4d9: 0x55, 0x4da: 0x55, 0x4db: 0xf3, 0x4dc: 0x55, 0x4dd: 0xf4, 0x4de: 0x55, 0x4df: 0xf5,
0x4e0: 0xf6, 0x4e1: 0xf7, 0x4e2: 0xf8, 0x4e4: 0x55, 0x4e5: 0x55, 0x4e6: 0x55, 0x4e7: 0x55,
0x4e8: 0x55, 0x4e9: 0xf9, 0x4ea: 0xfa, 0x4eb: 0xfb, 0x4ec: 0x55, 0x4ed: 0x55, 0x4ee: 0xfc, 0x4ef: 0xfd,
0x4ff: 0xfe,
// Block 0x14, offset 0x500
0x53f: 0xfe,
// Block 0x15, offset 0x540
0x550: 0x09, 0x551: 0x0a, 0x553: 0x0b, 0x556: 0x0c,
0x55b: 0x0d, 0x55c: 0x0e, 0x55d: 0x0f, 0x55e: 0x10, 0x55f: 0x11,
0x56f: 0x12,
0x57f: 0x12,
// Block 0x16, offset 0x580
0x58f: 0x12,
0x59f: 0x12,
0x5af: 0x12,
0x5bf: 0x12,
// Block 0x17, offset 0x5c0
0x5c0: 0xff, 0x5c1: 0xff, 0x5c2: 0xff, 0x5c3: 0xff, 0x5c4: 0x05, 0x5c5: 0x05, 0x5c6: 0x05, 0x5c7: 0x100,
0x5c8: 0xff, 0x5c9: 0xff, 0x5ca: 0xff, 0x5cb: 0xff, 0x5cc: 0xff, 0x5cd: 0xff, 0x5ce: 0xff, 0x5cf: 0xff,
0x5d0: 0xff, 0x5d1: 0xff, 0x5d2: 0xff, 0x5d3: 0xff, 0x5d4: 0xff, 0x5d5: 0xff, 0x5d6: 0xff, 0x5d7: 0xff,
0x5d8: 0xff, 0x5d9: 0xff, 0x5da: 0xff, 0x5db: 0xff, 0x5dc: 0xff, 0x5dd: 0xff, 0x5de: 0xff, 0x5df: 0xff,
0x5e0: 0xff, 0x5e1: 0xff, 0x5e2: 0xff, 0x5e3: 0xff, 0x5e4: 0xff, 0x5e5: 0xff, 0x5e6: 0xff, 0x5e7: 0xff,
0x5e8: 0xff, 0x5e9: 0xff, 0x5ea: 0xff, 0x5eb: 0xff, 0x5ec: 0xff, 0x5ed: 0xff, 0x5ee: 0xff, 0x5ef: 0xff,
0x5f0: 0xff, 0x5f1: 0xff, 0x5f2: 0xff, 0x5f3: 0xff, 0x5f4: 0xff, 0x5f5: 0xff, 0x5f6: 0xff, 0x5f7: 0xff,
0x5f8: 0xff, 0x5f9: 0xff, 0x5fa: 0xff, 0x5fb: 0xff, 0x5fc: 0xff, 0x5fd: 0xff, 0x5fe: 0xff, 0x5ff: 0xff,
// Block 0x18, offset 0x600
0x60f: 0x12,
0x61f: 0x12,
0x620: 0x15,
0x62f: 0x12,
0x63f: 0x12,
// Block 0x19, offset 0x640
0x64f: 0x12,
}
// Total table size 19960 bytes (19KiB); checksum: F50EF68C
// Copyright 2013 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 cldr
import (
"encoding/xml"
"regexp"
"strconv"
)
// Elem is implemented by every XML element.
type Elem interface {
setEnclosing(Elem)
setName(string)
enclosing() Elem
GetCommon() *Common
}
type hidden struct {
CharData string `xml:",chardata"`
Alias *struct {
Common
Source string `xml:"source,attr"`
Path string `xml:"path,attr"`
} `xml:"alias"`
Def *struct {
Common
Choice string `xml:"choice,attr,omitempty"`
Type string `xml:"type,attr,omitempty"`
} `xml:"default"`
}
// Common holds several of the most common attributes and sub elements
// of an XML element.
type Common struct {
XMLName xml.Name
name string
enclElem Elem
Type string `xml:"type,attr,omitempty"`
Reference string `xml:"reference,attr,omitempty"`
Alt string `xml:"alt,attr,omitempty"`
ValidSubLocales string `xml:"validSubLocales,attr,omitempty"`
Draft string `xml:"draft,attr,omitempty"`
hidden
}
// Default returns the default type to select from the enclosed list
// or "" if no default value is specified.
func (e *Common) Default() string {
if e.Def == nil {
return ""
}
if e.Def.Choice != "" {
return e.Def.Choice
} else if e.Def.Type != "" {
// Type is still used by the default element in collation.
return e.Def.Type
}
return ""
}
// Element returns the XML element name.
func (e *Common) Element() string {
return e.name
}
// GetCommon returns e. It is provided such that Common implements Elem.
func (e *Common) GetCommon() *Common {
return e
}
// Data returns the character data accumulated for this element.
func (e *Common) Data() string {
e.CharData = charRe.ReplaceAllStringFunc(e.CharData, replaceUnicode)
return e.CharData
}
func (e *Common) setName(s string) {
e.name = s
}
func (e *Common) enclosing() Elem {
return e.enclElem
}
func (e *Common) setEnclosing(en Elem) {
e.enclElem = en
}
// Escape characters that can be escaped without further escaping the string.
var charRe = regexp.MustCompile(`&#x[0-9a-fA-F]*;|\\u[0-9a-fA-F]{4}|\\U[0-9a-fA-F]{8}|\\x[0-9a-fA-F]{2}|\\[0-7]{3}|\\[abtnvfr]`)
// replaceUnicode converts hexadecimal Unicode codepoint notations to a one-rune string.
// It assumes the input string is correctly formatted.
func replaceUnicode(s string) string {
if s[1] == '#' {
r, _ := strconv.ParseInt(s[3:len(s)-1], 16, 32)
return string(rune(r))
}
r, _, _, _ := strconv.UnquoteChar(s, 0)
return string(r)
}
// Copyright 2013 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.
//go:generate go run makexml.go -output xml.go
// Package cldr provides a parser for LDML and related XML formats.
//
// This package is intended to be used by the table generation tools for the
// various packages in x/text and is not internal for historical reasons.
//
// As the XML types are generated from the CLDR DTD, and as the CLDR standard is
// periodically amended, this package may change considerably over time. This
// mostly means that data may appear and disappear between versions. That is,
// old code should keep compiling for newer versions, but data may have moved or
// changed. CLDR version 22 is the first version supported by this package.
// Older versions may not work.
package cldr // import "golang.org/x/text/unicode/cldr"
import (
"fmt"
"sort"
)
// CLDR provides access to parsed data of the Unicode Common Locale Data Repository.
type CLDR struct {
parent map[string][]string
locale map[string]*LDML
resolved map[string]*LDML
bcp47 *LDMLBCP47
supp *SupplementalData
}
func makeCLDR() *CLDR {
return &CLDR{
parent: make(map[string][]string),
locale: make(map[string]*LDML),
resolved: make(map[string]*LDML),
bcp47: &LDMLBCP47{},
supp: &SupplementalData{},
}
}
// BCP47 returns the parsed BCP47 LDML data. If no such data was parsed, nil is returned.
func (cldr *CLDR) BCP47() *LDMLBCP47 {
return nil
}
// Draft indicates the draft level of an element.
type Draft int
const (
Approved Draft = iota
Contributed
Provisional
Unconfirmed
)
var drafts = []string{"unconfirmed", "provisional", "contributed", "approved", ""}
// ParseDraft returns the Draft value corresponding to the given string. The
// empty string corresponds to Approved.
func ParseDraft(level string) (Draft, error) {
if level == "" {
return Approved, nil
}
for i, s := range drafts {
if level == s {
return Unconfirmed - Draft(i), nil
}
}
return Approved, fmt.Errorf("cldr: unknown draft level %q", level)
}
func (d Draft) String() string {
return drafts[len(drafts)-1-int(d)]
}
// SetDraftLevel sets which draft levels to include in the evaluated LDML.
// Any draft element for which the draft level is higher than lev will be excluded.
// If multiple draft levels are available for a single element, the one with the
// lowest draft level will be selected, unless preferDraft is true, in which case
// the highest draft will be chosen.
// It is assumed that the underlying LDML is canonicalized.
func (cldr *CLDR) SetDraftLevel(lev Draft, preferDraft bool) {
// TODO: implement
cldr.resolved = make(map[string]*LDML)
}
// RawLDML returns the LDML XML for id in unresolved form.
// id must be one of the strings returned by Locales.
func (cldr *CLDR) RawLDML(loc string) *LDML {
return cldr.locale[loc]
}
// LDML returns the fully resolved LDML XML for loc, which must be one of
// the strings returned by Locales.
//
// Deprecated: Use RawLDML and implement inheritance manually or using the
// internal cldrtree package.
// Inheritance has changed quite a bit since the onset of this package and in
// practice data often represented in a way where knowledge of how it was
// inherited is relevant.
func (cldr *CLDR) LDML(loc string) (*LDML, error) {
return cldr.resolve(loc)
}
// Supplemental returns the parsed supplemental data. If no such data was parsed,
// nil is returned.
func (cldr *CLDR) Supplemental() *SupplementalData {
return cldr.supp
}
// Locales returns the locales for which there exist files.
// Valid sublocales for which there is no file are not included.
// The root locale is always sorted first.
func (cldr *CLDR) Locales() []string {
loc := []string{"root"}
hasRoot := false
for l, _ := range cldr.locale {
if l == "root" {
hasRoot = true
continue
}
loc = append(loc, l)
}
sort.Strings(loc[1:])
if !hasRoot {
return loc[1:]
}
return loc
}
// Get fills in the fields of x based on the XPath path.
func Get(e Elem, path string) (res Elem, err error) {
return walkXPath(e, path)
}
// Copyright 2013 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 cldr
import (
"bufio"
"encoding/xml"
"errors"
"fmt"
"strconv"
"strings"
"unicode"
"unicode/utf8"
)
// RuleProcessor can be passed to Collator's Process method, which
// parses the rules and calls the respective method for each rule found.
type RuleProcessor interface {
Reset(anchor string, before int) error
Insert(level int, str, context, extend string) error
Index(id string)
}
const (
// cldrIndex is a Unicode-reserved sentinel value used to mark the start
// of a grouping within an index.
// We ignore any rule that starts with this rune.
// See https://unicode.org/reports/tr35/#Collation_Elements for details.
cldrIndex = "\uFDD0"
// specialAnchor is the format in which to represent logical reset positions,
// such as "first tertiary ignorable".
specialAnchor = "<%s/>"
)
// Process parses the rules for the tailorings of this collation
// and calls the respective methods of p for each rule found.
func (c Collation) Process(p RuleProcessor) (err error) {
if len(c.Cr) > 0 {
if len(c.Cr) > 1 {
return fmt.Errorf("multiple cr elements, want 0 or 1")
}
return processRules(p, c.Cr[0].Data())
}
if c.Rules.Any != nil {
return c.processXML(p)
}
return errors.New("no tailoring data")
}
// processRules parses rules in the Collation Rule Syntax defined in
// https://www.unicode.org/reports/tr35/tr35-collation.html#Collation_Tailorings.
func processRules(p RuleProcessor, s string) (err error) {
chk := func(s string, e error) string {
if err == nil {
err = e
}
return s
}
i := 0 // Save the line number for use after the loop.
scanner := bufio.NewScanner(strings.NewReader(s))
for ; scanner.Scan() && err == nil; i++ {
for s := skipSpace(scanner.Text()); s != "" && s[0] != '#'; s = skipSpace(s) {
level := 5
var ch byte
switch ch, s = s[0], s[1:]; ch {
case '&': // followed by <anchor> or '[' <key> ']'
if s = skipSpace(s); consume(&s, '[') {
s = chk(parseSpecialAnchor(p, s))
} else {
s = chk(parseAnchor(p, 0, s))
}
case '<': // sort relation '<'{1,4}, optionally followed by '*'.
for level = 1; consume(&s, '<'); level++ {
}
if level > 4 {
err = fmt.Errorf("level %d > 4", level)
}
fallthrough
case '=': // identity relation, optionally followed by *.
if consume(&s, '*') {
s = chk(parseSequence(p, level, s))
} else {
s = chk(parseOrder(p, level, s))
}
default:
chk("", fmt.Errorf("illegal operator %q", ch))
break
}
}
}
if chk("", scanner.Err()); err != nil {
return fmt.Errorf("%d: %v", i, err)
}
return nil
}
// parseSpecialAnchor parses the anchor syntax which is either of the form
//
// ['before' <level>] <anchor>
//
// or
//
// [<label>]
//
// The starting should already be consumed.
func parseSpecialAnchor(p RuleProcessor, s string) (tail string, err error) {
i := strings.IndexByte(s, ']')
if i == -1 {
return "", errors.New("unmatched bracket")
}
a := strings.TrimSpace(s[:i])
s = s[i+1:]
if strings.HasPrefix(a, "before ") {
l, err := strconv.ParseUint(skipSpace(a[len("before "):]), 10, 3)
if err != nil {
return s, err
}
return parseAnchor(p, int(l), s)
}
return s, p.Reset(fmt.Sprintf(specialAnchor, a), 0)
}
func parseAnchor(p RuleProcessor, level int, s string) (tail string, err error) {
anchor, s, err := scanString(s)
if err != nil {
return s, err
}
return s, p.Reset(anchor, level)
}
func parseOrder(p RuleProcessor, level int, s string) (tail string, err error) {
var value, context, extend string
if value, s, err = scanString(s); err != nil {
return s, err
}
if strings.HasPrefix(value, cldrIndex) {
p.Index(value[len(cldrIndex):])
return
}
if consume(&s, '|') {
if context, s, err = scanString(s); err != nil {
return s, errors.New("missing string after context")
}
}
if consume(&s, '/') {
if extend, s, err = scanString(s); err != nil {
return s, errors.New("missing string after extension")
}
}
return s, p.Insert(level, value, context, extend)
}
// scanString scans a single input string.
func scanString(s string) (str, tail string, err error) {
if s = skipSpace(s); s == "" {
return s, s, errors.New("missing string")
}
buf := [16]byte{} // small but enough to hold most cases.
value := buf[:0]
for s != "" {
if consume(&s, '\'') {
i := strings.IndexByte(s, '\'')
if i == -1 {
return "", "", errors.New(`unmatched single quote`)
}
if i == 0 {
value = append(value, '\'')
} else {
value = append(value, s[:i]...)
}
s = s[i+1:]
continue
}
r, sz := utf8.DecodeRuneInString(s)
if unicode.IsSpace(r) || strings.ContainsRune("&<=#", r) {
break
}
value = append(value, s[:sz]...)
s = s[sz:]
}
return string(value), skipSpace(s), nil
}
func parseSequence(p RuleProcessor, level int, s string) (tail string, err error) {
if s = skipSpace(s); s == "" {
return s, errors.New("empty sequence")
}
last := rune(0)
for s != "" {
r, sz := utf8.DecodeRuneInString(s)
s = s[sz:]
if r == '-' {
// We have a range. The first element was already written.
if last == 0 {
return s, errors.New("range without starter value")
}
r, sz = utf8.DecodeRuneInString(s)
s = s[sz:]
if r == utf8.RuneError || r < last {
return s, fmt.Errorf("invalid range %q-%q", last, r)
}
for i := last + 1; i <= r; i++ {
if err := p.Insert(level, string(i), "", ""); err != nil {
return s, err
}
}
last = 0
continue
}
if unicode.IsSpace(r) || unicode.IsPunct(r) {
break
}
// normal case
if err := p.Insert(level, string(r), "", ""); err != nil {
return s, err
}
last = r
}
return s, nil
}
func skipSpace(s string) string {
return strings.TrimLeftFunc(s, unicode.IsSpace)
}
// consume returns whether the next byte is ch. If so, it gobbles it by
// updating s.
func consume(s *string, ch byte) (ok bool) {
if *s == "" || (*s)[0] != ch {
return false
}
*s = (*s)[1:]
return true
}
// The following code parses Collation rules of CLDR version 24 and before.
var lmap = map[byte]int{
'p': 1,
's': 2,
't': 3,
'i': 5,
}
type rulesElem struct {
Rules struct {
Common
Any []*struct {
XMLName xml.Name
rule
} `xml:",any"`
} `xml:"rules"`
}
type rule struct {
Value string `xml:",chardata"`
Before string `xml:"before,attr"`
Any []*struct {
XMLName xml.Name
rule
} `xml:",any"`
}
var emptyValueError = errors.New("cldr: empty rule value")
func (r *rule) value() (string, error) {
// Convert hexadecimal Unicode codepoint notation to a string.
s := charRe.ReplaceAllStringFunc(r.Value, replaceUnicode)
r.Value = s
if s == "" {
if len(r.Any) != 1 {
return "", emptyValueError
}
r.Value = fmt.Sprintf(specialAnchor, r.Any[0].XMLName.Local)
r.Any = nil
} else if len(r.Any) != 0 {
return "", fmt.Errorf("cldr: XML elements found in collation rule: %v", r.Any)
}
return r.Value, nil
}
func (r rule) process(p RuleProcessor, name, context, extend string) error {
v, err := r.value()
if err != nil {
return err
}
switch name {
case "p", "s", "t", "i":
if strings.HasPrefix(v, cldrIndex) {
p.Index(v[len(cldrIndex):])
return nil
}
if err := p.Insert(lmap[name[0]], v, context, extend); err != nil {
return err
}
case "pc", "sc", "tc", "ic":
level := lmap[name[0]]
for _, s := range v {
if err := p.Insert(level, string(s), context, extend); err != nil {
return err
}
}
default:
return fmt.Errorf("cldr: unsupported tag: %q", name)
}
return nil
}
// processXML parses the format of CLDR versions 24 and older.
func (c Collation) processXML(p RuleProcessor) (err error) {
// Collation is generated and defined in xml.go.
var v string
for _, r := range c.Rules.Any {
switch r.XMLName.Local {
case "reset":
level := 0
switch r.Before {
case "primary", "1":
level = 1
case "secondary", "2":
level = 2
case "tertiary", "3":
level = 3
case "":
default:
return fmt.Errorf("cldr: unknown level %q", r.Before)
}
v, err = r.value()
if err == nil {
err = p.Reset(v, level)
}
case "x":
var context, extend string
for _, r1 := range r.Any {
v, err = r1.value()
switch r1.XMLName.Local {
case "context":
context = v
case "extend":
extend = v
}
}
for _, r1 := range r.Any {
if t := r1.XMLName.Local; t == "context" || t == "extend" {
continue
}
r1.rule.process(p, r1.XMLName.Local, context, extend)
}
default:
err = r.rule.process(p, r.XMLName.Local, "", "")
}
if err != nil {
return err
}
}
return nil
}
// Copyright 2013 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 cldr
import (
"archive/zip"
"bytes"
"encoding/xml"
"fmt"
"io"
"log"
"os"
"path/filepath"
"regexp"
)
// A Decoder loads an archive of CLDR data.
type Decoder struct {
dirFilter []string
sectionFilter []string
loader Loader
cldr *CLDR
curLocale string
}
// SetSectionFilter takes a list top-level LDML element names to which
// evaluation of LDML should be limited. It automatically calls SetDirFilter.
func (d *Decoder) SetSectionFilter(filter ...string) {
d.sectionFilter = filter
// TODO: automatically set dir filter
}
// SetDirFilter limits the loading of LDML XML files of the specified directories.
// Note that sections may be split across directories differently for different CLDR versions.
// For more robust code, use SetSectionFilter.
func (d *Decoder) SetDirFilter(dir ...string) {
d.dirFilter = dir
}
// A Loader provides access to the files of a CLDR archive.
type Loader interface {
Len() int
Path(i int) string
Reader(i int) (io.ReadCloser, error)
}
var fileRe = regexp.MustCompile(`.*[/\\](.*)[/\\](.*)\.xml`)
// Decode loads and decodes the files represented by l.
func (d *Decoder) Decode(l Loader) (cldr *CLDR, err error) {
d.cldr = makeCLDR()
for i := 0; i < l.Len(); i++ {
fname := l.Path(i)
if m := fileRe.FindStringSubmatch(fname); m != nil {
if len(d.dirFilter) > 0 && !in(d.dirFilter, m[1]) {
continue
}
var r io.ReadCloser
if r, err = l.Reader(i); err == nil {
err = d.decode(m[1], m[2], r)
r.Close()
}
if err != nil {
return nil, err
}
}
}
d.cldr.finalize(d.sectionFilter)
return d.cldr, nil
}
func (d *Decoder) decode(dir, id string, r io.Reader) error {
var v interface{}
var l *LDML
cldr := d.cldr
switch {
case dir == "supplemental":
v = cldr.supp
case dir == "transforms":
return nil
case dir == "bcp47":
v = cldr.bcp47
case dir == "validity":
return nil
default:
ok := false
if v, ok = cldr.locale[id]; !ok {
l = &LDML{}
v, cldr.locale[id] = l, l
}
}
x := xml.NewDecoder(r)
if err := x.Decode(v); err != nil {
log.Printf("%s/%s: %v", dir, id, err)
return err
}
if l != nil {
if l.Identity == nil {
return fmt.Errorf("%s/%s: missing identity element", dir, id)
}
// TODO: verify when CLDR bug https://unicode.org/cldr/trac/ticket/8970
// is resolved.
// path := strings.Split(id, "_")
// if lang := l.Identity.Language.Type; lang != path[0] {
// return fmt.Errorf("%s/%s: language was %s; want %s", dir, id, lang, path[0])
// }
}
return nil
}
type pathLoader []string
func makePathLoader(path string) (pl pathLoader, err error) {
err = filepath.Walk(path, func(path string, _ os.FileInfo, err error) error {
pl = append(pl, path)
return err
})
return pl, err
}
func (pl pathLoader) Len() int {
return len(pl)
}
func (pl pathLoader) Path(i int) string {
return pl[i]
}
func (pl pathLoader) Reader(i int) (io.ReadCloser, error) {
return os.Open(pl[i])
}
// DecodePath loads CLDR data from the given path.
func (d *Decoder) DecodePath(path string) (cldr *CLDR, err error) {
loader, err := makePathLoader(path)
if err != nil {
return nil, err
}
return d.Decode(loader)
}
type zipLoader struct {
r *zip.Reader
}
func (zl zipLoader) Len() int {
return len(zl.r.File)
}
func (zl zipLoader) Path(i int) string {
return zl.r.File[i].Name
}
func (zl zipLoader) Reader(i int) (io.ReadCloser, error) {
return zl.r.File[i].Open()
}
// DecodeZip loads CLDR data from the zip archive for which r is the source.
func (d *Decoder) DecodeZip(r io.Reader) (cldr *CLDR, err error) {
buffer, err := io.ReadAll(r)
if err != nil {
return nil, err
}
archive, err := zip.NewReader(bytes.NewReader(buffer), int64(len(buffer)))
if err != nil {
return nil, err
}
return d.Decode(zipLoader{archive})
}
// Copyright 2013 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 cldr
// This file implements the various inheritance constructs defined by LDML.
// See https://www.unicode.org/reports/tr35/#Inheritance_and_Validity
// for more details.
import (
"fmt"
"log"
"reflect"
"regexp"
"sort"
"strings"
)
// fieldIter iterates over fields in a struct. It includes
// fields of embedded structs.
type fieldIter struct {
v reflect.Value
index, n []int
}
func iter(v reflect.Value) fieldIter {
if v.Kind() != reflect.Struct {
log.Panicf("value %v must be a struct", v)
}
i := fieldIter{
v: v,
index: []int{0},
n: []int{v.NumField()},
}
i.descent()
return i
}
func (i *fieldIter) descent() {
for f := i.field(); f.Anonymous && f.Type.NumField() > 0; f = i.field() {
i.index = append(i.index, 0)
i.n = append(i.n, f.Type.NumField())
}
}
func (i *fieldIter) done() bool {
return len(i.index) == 1 && i.index[0] >= i.n[0]
}
func skip(f reflect.StructField) bool {
return !f.Anonymous && (f.Name[0] < 'A' || f.Name[0] > 'Z')
}
func (i *fieldIter) next() {
for {
k := len(i.index) - 1
i.index[k]++
if i.index[k] < i.n[k] {
if !skip(i.field()) {
break
}
} else {
if k == 0 {
return
}
i.index = i.index[:k]
i.n = i.n[:k]
}
}
i.descent()
}
func (i *fieldIter) value() reflect.Value {
return i.v.FieldByIndex(i.index)
}
func (i *fieldIter) field() reflect.StructField {
return i.v.Type().FieldByIndex(i.index)
}
type visitor func(v reflect.Value) error
var stopDescent = fmt.Errorf("do not recurse")
func (f visitor) visit(x interface{}) error {
return f.visitRec(reflect.ValueOf(x))
}
// visit recursively calls f on all nodes in v.
func (f visitor) visitRec(v reflect.Value) error {
if v.Kind() == reflect.Ptr {
if v.IsNil() {
return nil
}
return f.visitRec(v.Elem())
}
if err := f(v); err != nil {
if err == stopDescent {
return nil
}
return err
}
switch v.Kind() {
case reflect.Struct:
for i := iter(v); !i.done(); i.next() {
if err := f.visitRec(i.value()); err != nil {
return err
}
}
case reflect.Slice:
for i := 0; i < v.Len(); i++ {
if err := f.visitRec(v.Index(i)); err != nil {
return err
}
}
}
return nil
}
// getPath is used for error reporting purposes only.
func getPath(e Elem) string {
if e == nil {
return "<nil>"
}
if e.enclosing() == nil {
return e.GetCommon().name
}
if e.GetCommon().Type == "" {
return fmt.Sprintf("%s.%s", getPath(e.enclosing()), e.GetCommon().name)
}
return fmt.Sprintf("%s.%s[type=%s]", getPath(e.enclosing()), e.GetCommon().name, e.GetCommon().Type)
}
// xmlName returns the xml name of the element or attribute
func xmlName(f reflect.StructField) (name string, attr bool) {
tags := strings.Split(f.Tag.Get("xml"), ",")
for _, s := range tags {
attr = attr || s == "attr"
}
return tags[0], attr
}
func findField(v reflect.Value, key string) (reflect.Value, error) {
v = reflect.Indirect(v)
for i := iter(v); !i.done(); i.next() {
if n, _ := xmlName(i.field()); n == key {
return i.value(), nil
}
}
return reflect.Value{}, fmt.Errorf("cldr: no field %q in element %#v", key, v.Interface())
}
var xpathPart = regexp.MustCompile(`(\pL+)(?:\[@(\pL+)='([\w-]+)'\])?`)
func walkXPath(e Elem, path string) (res Elem, err error) {
for _, c := range strings.Split(path, "/") {
if c == ".." {
if e = e.enclosing(); e == nil {
panic("path ..")
}
continue
} else if c == "" {
continue
}
m := xpathPart.FindStringSubmatch(c)
if len(m) == 0 || len(m[0]) != len(c) {
return nil, fmt.Errorf("cldr: syntax error in path component %q", c)
}
v, err := findField(reflect.ValueOf(e), m[1])
if err != nil {
return nil, err
}
switch v.Kind() {
case reflect.Slice:
i := 0
if m[2] != "" || v.Len() > 1 {
if m[2] == "" {
m[2] = "type"
if m[3] = e.GetCommon().Default(); m[3] == "" {
return nil, fmt.Errorf("cldr: type selector or default value needed for element %s", m[1])
}
}
for ; i < v.Len(); i++ {
vi := v.Index(i)
key, err := findField(vi.Elem(), m[2])
if err != nil {
return nil, err
}
key = reflect.Indirect(key)
if key.Kind() == reflect.String && key.String() == m[3] {
break
}
}
}
if i == v.Len() || v.Index(i).IsNil() {
return nil, fmt.Errorf("no %s found with %s==%s", m[1], m[2], m[3])
}
e = v.Index(i).Interface().(Elem)
case reflect.Ptr:
if v.IsNil() {
return nil, fmt.Errorf("cldr: element %q not found within element %q", m[1], e.GetCommon().name)
}
var ok bool
if e, ok = v.Interface().(Elem); !ok {
return nil, fmt.Errorf("cldr: %q is not an XML element", m[1])
} else if m[2] != "" || m[3] != "" {
return nil, fmt.Errorf("cldr: no type selector allowed for element %s", m[1])
}
default:
return nil, fmt.Errorf("cldr: %q is not an XML element", m[1])
}
}
return e, nil
}
const absPrefix = "//ldml/"
func (cldr *CLDR) resolveAlias(e Elem, src, path string) (res Elem, err error) {
if src != "locale" {
if !strings.HasPrefix(path, absPrefix) {
return nil, fmt.Errorf("cldr: expected absolute path, found %q", path)
}
path = path[len(absPrefix):]
if e, err = cldr.resolve(src); err != nil {
return nil, err
}
}
return walkXPath(e, path)
}
func (cldr *CLDR) resolveAndMergeAlias(e Elem) error {
alias := e.GetCommon().Alias
if alias == nil {
return nil
}
a, err := cldr.resolveAlias(e, alias.Source, alias.Path)
if err != nil {
return fmt.Errorf("%v: error evaluating path %q: %v", getPath(e), alias.Path, err)
}
// Ensure alias node was already evaluated. TODO: avoid double evaluation.
err = cldr.resolveAndMergeAlias(a)
v := reflect.ValueOf(e).Elem()
for i := iter(reflect.ValueOf(a).Elem()); !i.done(); i.next() {
if vv := i.value(); vv.Kind() != reflect.Ptr || !vv.IsNil() {
if _, attr := xmlName(i.field()); !attr {
v.FieldByIndex(i.index).Set(vv)
}
}
}
return err
}
func (cldr *CLDR) aliasResolver() visitor {
return func(v reflect.Value) (err error) {
if e, ok := v.Addr().Interface().(Elem); ok {
err = cldr.resolveAndMergeAlias(e)
if err == nil && blocking[e.GetCommon().name] {
return stopDescent
}
}
return err
}
}
// elements within blocking elements do not inherit.
// Taken from CLDR's supplementalMetaData.xml.
var blocking = map[string]bool{
"identity": true,
"supplementalData": true,
"cldrTest": true,
"collation": true,
"transform": true,
}
// Distinguishing attributes affect inheritance; two elements with different
// distinguishing attributes are treated as different for purposes of inheritance,
// except when such attributes occur in the indicated elements.
// Taken from CLDR's supplementalMetaData.xml.
var distinguishing = map[string][]string{
"key": nil,
"request_id": nil,
"id": nil,
"registry": nil,
"alt": nil,
"iso4217": nil,
"iso3166": nil,
"mzone": nil,
"from": nil,
"to": nil,
"type": []string{
"abbreviationFallback",
"default",
"mapping",
"measurementSystem",
"preferenceOrdering",
},
"numberSystem": nil,
}
func in(set []string, s string) bool {
for _, v := range set {
if v == s {
return true
}
}
return false
}
// attrKey computes a key based on the distinguishable attributes of
// an element and its values.
func attrKey(v reflect.Value, exclude ...string) string {
parts := []string{}
ename := v.Interface().(Elem).GetCommon().name
v = v.Elem()
for i := iter(v); !i.done(); i.next() {
if name, attr := xmlName(i.field()); attr {
if except, ok := distinguishing[name]; ok && !in(exclude, name) && !in(except, ename) {
v := i.value()
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.IsValid() {
parts = append(parts, fmt.Sprintf("%s=%s", name, v.String()))
}
}
}
}
sort.Strings(parts)
return strings.Join(parts, ";")
}
// Key returns a key for e derived from all distinguishing attributes
// except those specified by exclude.
func Key(e Elem, exclude ...string) string {
return attrKey(reflect.ValueOf(e), exclude...)
}
// linkEnclosing sets the enclosing element as well as the name
// for all sub-elements of child, recursively.
func linkEnclosing(parent, child Elem) {
child.setEnclosing(parent)
v := reflect.ValueOf(child).Elem()
for i := iter(v); !i.done(); i.next() {
vf := i.value()
if vf.Kind() == reflect.Slice {
for j := 0; j < vf.Len(); j++ {
linkEnclosing(child, vf.Index(j).Interface().(Elem))
}
} else if vf.Kind() == reflect.Ptr && !vf.IsNil() && vf.Elem().Kind() == reflect.Struct {
linkEnclosing(child, vf.Interface().(Elem))
}
}
}
func setNames(e Elem, name string) {
e.setName(name)
v := reflect.ValueOf(e).Elem()
for i := iter(v); !i.done(); i.next() {
vf := i.value()
name, _ = xmlName(i.field())
if vf.Kind() == reflect.Slice {
for j := 0; j < vf.Len(); j++ {
setNames(vf.Index(j).Interface().(Elem), name)
}
} else if vf.Kind() == reflect.Ptr && !vf.IsNil() && vf.Elem().Kind() == reflect.Struct {
setNames(vf.Interface().(Elem), name)
}
}
}
// deepCopy copies elements of v recursively. All elements of v that may
// be modified by inheritance are explicitly copied.
func deepCopy(v reflect.Value) reflect.Value {
switch v.Kind() {
case reflect.Ptr:
if v.IsNil() || v.Elem().Kind() != reflect.Struct {
return v
}
nv := reflect.New(v.Elem().Type())
nv.Elem().Set(v.Elem())
deepCopyRec(nv.Elem(), v.Elem())
return nv
case reflect.Slice:
nv := reflect.MakeSlice(v.Type(), v.Len(), v.Len())
for i := 0; i < v.Len(); i++ {
deepCopyRec(nv.Index(i), v.Index(i))
}
return nv
}
panic("deepCopy: must be called with pointer or slice")
}
// deepCopyRec is only called by deepCopy.
func deepCopyRec(nv, v reflect.Value) {
if v.Kind() == reflect.Struct {
t := v.Type()
for i := 0; i < v.NumField(); i++ {
if name, attr := xmlName(t.Field(i)); name != "" && !attr {
deepCopyRec(nv.Field(i), v.Field(i))
}
}
} else {
nv.Set(deepCopy(v))
}
}
// newNode is used to insert a missing node during inheritance.
func (cldr *CLDR) newNode(v, enc reflect.Value) reflect.Value {
n := reflect.New(v.Type())
for i := iter(v); !i.done(); i.next() {
if name, attr := xmlName(i.field()); name == "" || attr {
n.Elem().FieldByIndex(i.index).Set(i.value())
}
}
n.Interface().(Elem).GetCommon().setEnclosing(enc.Addr().Interface().(Elem))
return n
}
// v, parent must be pointers to struct
func (cldr *CLDR) inheritFields(v, parent reflect.Value) (res reflect.Value, err error) {
t := v.Type()
nv := reflect.New(t)
nv.Elem().Set(v)
for i := iter(v); !i.done(); i.next() {
vf := i.value()
f := i.field()
name, attr := xmlName(f)
if name == "" || attr {
continue
}
pf := parent.FieldByIndex(i.index)
if blocking[name] {
if vf.IsNil() {
vf = pf
}
nv.Elem().FieldByIndex(i.index).Set(deepCopy(vf))
continue
}
switch f.Type.Kind() {
case reflect.Ptr:
if f.Type.Elem().Kind() == reflect.Struct {
if !vf.IsNil() {
if vf, err = cldr.inheritStructPtr(vf, pf); err != nil {
return reflect.Value{}, err
}
vf.Interface().(Elem).setEnclosing(nv.Interface().(Elem))
nv.Elem().FieldByIndex(i.index).Set(vf)
} else if !pf.IsNil() {
n := cldr.newNode(pf.Elem(), v)
if vf, err = cldr.inheritStructPtr(n, pf); err != nil {
return reflect.Value{}, err
}
vf.Interface().(Elem).setEnclosing(nv.Interface().(Elem))
nv.Elem().FieldByIndex(i.index).Set(vf)
}
}
case reflect.Slice:
vf, err := cldr.inheritSlice(nv.Elem(), vf, pf)
if err != nil {
return reflect.Zero(t), err
}
nv.Elem().FieldByIndex(i.index).Set(vf)
}
}
return nv, nil
}
func root(e Elem) *LDML {
for ; e.enclosing() != nil; e = e.enclosing() {
}
return e.(*LDML)
}
// inheritStructPtr first merges possible aliases in with v and then inherits
// any underspecified elements from parent.
func (cldr *CLDR) inheritStructPtr(v, parent reflect.Value) (r reflect.Value, err error) {
if !v.IsNil() {
e := v.Interface().(Elem).GetCommon()
alias := e.Alias
if alias == nil && !parent.IsNil() {
alias = parent.Interface().(Elem).GetCommon().Alias
}
if alias != nil {
a, err := cldr.resolveAlias(v.Interface().(Elem), alias.Source, alias.Path)
if a != nil {
if v, err = cldr.inheritFields(v.Elem(), reflect.ValueOf(a).Elem()); err != nil {
return reflect.Value{}, err
}
}
}
if !parent.IsNil() {
return cldr.inheritFields(v.Elem(), parent.Elem())
}
} else if parent.IsNil() {
panic("should not reach here")
}
return v, nil
}
// Must be slice of struct pointers.
func (cldr *CLDR) inheritSlice(enc, v, parent reflect.Value) (res reflect.Value, err error) {
t := v.Type()
index := make(map[string]reflect.Value)
if !v.IsNil() {
for i := 0; i < v.Len(); i++ {
vi := v.Index(i)
key := attrKey(vi)
index[key] = vi
}
}
if !parent.IsNil() {
for i := 0; i < parent.Len(); i++ {
vi := parent.Index(i)
key := attrKey(vi)
if w, ok := index[key]; ok {
index[key], err = cldr.inheritStructPtr(w, vi)
} else {
n := cldr.newNode(vi.Elem(), enc)
index[key], err = cldr.inheritStructPtr(n, vi)
}
index[key].Interface().(Elem).setEnclosing(enc.Addr().Interface().(Elem))
if err != nil {
return v, err
}
}
}
keys := make([]string, 0, len(index))
for k, _ := range index {
keys = append(keys, k)
}
sort.Strings(keys)
sl := reflect.MakeSlice(t, len(index), len(index))
for i, k := range keys {
sl.Index(i).Set(index[k])
}
return sl, nil
}
func parentLocale(loc string) string {
parts := strings.Split(loc, "_")
if len(parts) == 1 {
return "root"
}
parts = parts[:len(parts)-1]
key := strings.Join(parts, "_")
return key
}
func (cldr *CLDR) resolve(loc string) (res *LDML, err error) {
if r := cldr.resolved[loc]; r != nil {
return r, nil
}
x := cldr.RawLDML(loc)
if x == nil {
return nil, fmt.Errorf("cldr: unknown locale %q", loc)
}
var v reflect.Value
if loc == "root" {
x = deepCopy(reflect.ValueOf(x)).Interface().(*LDML)
linkEnclosing(nil, x)
err = cldr.aliasResolver().visit(x)
} else {
key := parentLocale(loc)
var parent *LDML
for ; cldr.locale[key] == nil; key = parentLocale(key) {
}
if parent, err = cldr.resolve(key); err != nil {
return nil, err
}
v, err = cldr.inheritFields(reflect.ValueOf(x).Elem(), reflect.ValueOf(parent).Elem())
x = v.Interface().(*LDML)
linkEnclosing(nil, x)
}
if err != nil {
return nil, err
}
cldr.resolved[loc] = x
return x, err
}
// finalize finalizes the initialization of the raw LDML structs. It also
// removed unwanted fields, as specified by filter, so that they will not
// be unnecessarily evaluated.
func (cldr *CLDR) finalize(filter []string) {
for _, x := range cldr.locale {
if filter != nil {
v := reflect.ValueOf(x).Elem()
t := v.Type()
for i := 0; i < v.NumField(); i++ {
f := t.Field(i)
name, _ := xmlName(f)
if name != "" && name != "identity" && !in(filter, name) {
v.Field(i).Set(reflect.Zero(f.Type))
}
}
}
linkEnclosing(nil, x) // for resolving aliases and paths
setNames(x, "ldml")
}
}
// Copyright 2013 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 cldr
import (
"fmt"
"reflect"
"sort"
)
// Slice provides utilities for modifying slices of elements.
// It can be wrapped around any slice of which the element type implements
// interface Elem.
type Slice struct {
ptr reflect.Value
typ reflect.Type
}
// Value returns the reflect.Value of the underlying slice.
func (s *Slice) Value() reflect.Value {
return s.ptr.Elem()
}
// MakeSlice wraps a pointer to a slice of Elems.
// It replaces the array pointed to by the slice so that subsequent modifications
// do not alter the data in a CLDR type.
// It panics if an incorrect type is passed.
func MakeSlice(slicePtr interface{}) Slice {
ptr := reflect.ValueOf(slicePtr)
if ptr.Kind() != reflect.Ptr {
panic(fmt.Sprintf("MakeSlice: argument must be pointer to slice, found %v", ptr.Type()))
}
sl := ptr.Elem()
if sl.Kind() != reflect.Slice {
panic(fmt.Sprintf("MakeSlice: argument must point to a slice, found %v", sl.Type()))
}
intf := reflect.TypeFor[Elem]()
if !sl.Type().Elem().Implements(intf) {
panic(fmt.Sprintf("MakeSlice: element type of slice (%v) does not implement Elem", sl.Type().Elem()))
}
nsl := reflect.MakeSlice(sl.Type(), sl.Len(), sl.Len())
reflect.Copy(nsl, sl)
sl.Set(nsl)
return Slice{
ptr: ptr,
typ: sl.Type().Elem().Elem(),
}
}
func (s Slice) indexForAttr(a string) []int {
for i := iter(reflect.Zero(s.typ)); !i.done(); i.next() {
if n, _ := xmlName(i.field()); n == a {
return i.index
}
}
panic(fmt.Sprintf("MakeSlice: no attribute %q for type %v", a, s.typ))
}
// Filter filters s to only include elements for which fn returns true.
func (s Slice) Filter(fn func(e Elem) bool) {
k := 0
sl := s.Value()
for i := 0; i < sl.Len(); i++ {
vi := sl.Index(i)
if fn(vi.Interface().(Elem)) {
sl.Index(k).Set(vi)
k++
}
}
sl.Set(sl.Slice(0, k))
}
// Group finds elements in s for which fn returns the same value and groups
// them in a new Slice.
func (s Slice) Group(fn func(e Elem) string) []Slice {
m := make(map[string][]reflect.Value)
sl := s.Value()
for i := 0; i < sl.Len(); i++ {
vi := sl.Index(i)
key := fn(vi.Interface().(Elem))
m[key] = append(m[key], vi)
}
keys := []string{}
for k, _ := range m {
keys = append(keys, k)
}
sort.Strings(keys)
res := []Slice{}
for _, k := range keys {
nsl := reflect.New(sl.Type())
nsl.Elem().Set(reflect.Append(nsl.Elem(), m[k]...))
res = append(res, MakeSlice(nsl.Interface()))
}
return res
}
// SelectAnyOf filters s to contain only elements for which attr matches
// any of the values.
func (s Slice) SelectAnyOf(attr string, values ...string) {
index := s.indexForAttr(attr)
s.Filter(func(e Elem) bool {
vf := reflect.ValueOf(e).Elem().FieldByIndex(index)
return in(values, vf.String())
})
}
// SelectOnePerGroup filters s to include at most one element e per group of
// elements matching Key(attr), where e has an attribute a that matches any
// the values in v.
// If more than one element in a group matches a value in v preference
// is given to the element that matches the first value in v.
func (s Slice) SelectOnePerGroup(a string, v []string) {
index := s.indexForAttr(a)
grouped := s.Group(func(e Elem) string { return Key(e, a) })
sl := s.Value()
sl.Set(sl.Slice(0, 0))
for _, g := range grouped {
e := reflect.Value{}
found := len(v)
gsl := g.Value()
for i := 0; i < gsl.Len(); i++ {
vi := gsl.Index(i).Elem().FieldByIndex(index)
j := 0
for ; j < len(v) && v[j] != vi.String(); j++ {
}
if j < found {
found = j
e = gsl.Index(i)
}
}
if found < len(v) {
sl.Set(reflect.Append(sl, e))
}
}
}
// SelectDraft drops all elements from the list with a draft level smaller than d
// and selects the highest draft level of the remaining.
// This method assumes that the input CLDR is canonicalized.
func (s Slice) SelectDraft(d Draft) {
s.SelectOnePerGroup("draft", drafts[len(drafts)-2-int(d):])
}
// Copyright 2011 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 norm
import "unicode/utf8"
const (
maxNonStarters = 30
// The maximum number of characters needed for a buffer is
// maxNonStarters + 1 for the starter + 1 for the GCJ
maxBufferSize = maxNonStarters + 2
maxNFCExpansion = 3 // NFC(0x1D160)
maxNFKCExpansion = 18 // NFKC(0xFDFA)
maxByteBufferSize = utf8.UTFMax * maxBufferSize // 128
)
// ssState is used for reporting the segment state after inserting a rune.
// It is returned by streamSafe.next.
type ssState int
const (
// Indicates a rune was successfully added to the segment.
ssSuccess ssState = iota
// Indicates a rune starts a new segment and should not be added.
ssStarter
// Indicates a rune caused a segment overflow and a CGJ should be inserted.
ssOverflow
)
// streamSafe implements the policy of when a CGJ should be inserted.
type streamSafe uint8
// first inserts the first rune of a segment. It is a faster version of next if
// it is known p represents the first rune in a segment.
func (ss *streamSafe) first(p Properties) {
*ss = streamSafe(p.nTrailingNonStarters())
}
// insert returns a ssState value to indicate whether a rune represented by p
// can be inserted.
func (ss *streamSafe) next(p Properties) ssState {
if *ss > maxNonStarters {
panic("streamSafe was not reset")
}
n := p.nLeadingNonStarters()
if *ss += streamSafe(n); *ss > maxNonStarters {
*ss = 0
return ssOverflow
}
// The Stream-Safe Text Processing prescribes that the counting can stop
// as soon as a starter is encountered. However, there are some starters,
// like Jamo V and T, that can combine with other runes, leaving their
// successive non-starters appended to the previous, possibly causing an
// overflow. We will therefore consider any rune with a non-zero nLead to
// be a non-starter. Note that it always hold that if nLead > 0 then
// nLead == nTrail.
if n == 0 {
*ss = streamSafe(p.nTrailingNonStarters())
return ssStarter
}
return ssSuccess
}
// backwards is used for checking for overflow and segment starts
// when traversing a string backwards. Users do not need to call first
// for the first rune. The state of the streamSafe retains the count of
// the non-starters loaded.
func (ss *streamSafe) backwards(p Properties) ssState {
if *ss > maxNonStarters {
panic("streamSafe was not reset")
}
c := *ss + streamSafe(p.nTrailingNonStarters())
if c > maxNonStarters {
return ssOverflow
}
*ss = c
if p.nLeadingNonStarters() == 0 {
return ssStarter
}
return ssSuccess
}
func (ss streamSafe) isMax() bool {
return ss == maxNonStarters
}
// GraphemeJoiner is inserted after maxNonStarters non-starter runes.
const GraphemeJoiner = "\u034F"
// reorderBuffer is used to normalize a single segment. Characters inserted with
// insert are decomposed and reordered based on CCC. The compose method can
// be used to recombine characters. Note that the byte buffer does not hold
// the UTF-8 characters in order. Only the rune array is maintained in sorted
// order. flush writes the resulting segment to a byte array.
type reorderBuffer struct {
rune [maxBufferSize]Properties // Per character info.
byte [maxByteBufferSize]byte // UTF-8 buffer. Referenced by runeInfo.pos.
nbyte uint8 // Number or bytes.
ss streamSafe // For limiting length of non-starter sequence.
nrune int // Number of runeInfos.
f formInfo
src input
nsrc int
tmpBytes input
out []byte
flushF func(*reorderBuffer) bool
}
func (rb *reorderBuffer) init(f Form, src []byte) {
rb.f = *formTable[f]
rb.src.setBytes(src)
rb.nsrc = len(src)
rb.ss = 0
}
func (rb *reorderBuffer) initString(f Form, src string) {
rb.f = *formTable[f]
rb.src.setString(src)
rb.nsrc = len(src)
rb.ss = 0
}
func (rb *reorderBuffer) setFlusher(out []byte, f func(*reorderBuffer) bool) {
rb.out = out
rb.flushF = f
}
// reset discards all characters from the buffer.
func (rb *reorderBuffer) reset() {
rb.nrune = 0
rb.nbyte = 0
}
func (rb *reorderBuffer) doFlush() bool {
if rb.f.composing {
rb.compose()
}
res := rb.flushF(rb)
rb.reset()
return res
}
// appendFlush appends the normalized segment to rb.out.
func appendFlush(rb *reorderBuffer) bool {
for i := 0; i < rb.nrune; i++ {
start := rb.rune[i].pos
end := start + rb.rune[i].size
rb.out = append(rb.out, rb.byte[start:end]...)
}
return true
}
// flush appends the normalized segment to out and resets rb.
func (rb *reorderBuffer) flush(out []byte) []byte {
for i := 0; i < rb.nrune; i++ {
start := rb.rune[i].pos
end := start + rb.rune[i].size
out = append(out, rb.byte[start:end]...)
}
rb.reset()
return out
}
// flushCopy copies the normalized segment to buf and resets rb.
// It returns the number of bytes written to buf.
func (rb *reorderBuffer) flushCopy(buf []byte) int {
p := 0
for i := 0; i < rb.nrune; i++ {
runep := rb.rune[i]
p += copy(buf[p:], rb.byte[runep.pos:runep.pos+runep.size])
}
rb.reset()
return p
}
// insertOrdered inserts a rune in the buffer, ordered by Canonical Combining Class.
// It returns false if the buffer is not large enough to hold the rune.
// It is used internally by insert and insertString only.
func (rb *reorderBuffer) insertOrdered(info Properties) {
n := rb.nrune
b := rb.rune[:]
cc := info.ccc
if cc > 0 {
// Find insertion position + move elements to make room.
for ; n > 0; n-- {
if b[n-1].ccc <= cc {
break
}
b[n] = b[n-1]
}
}
rb.nrune += 1
pos := uint8(rb.nbyte)
rb.nbyte += utf8.UTFMax
info.pos = pos
b[n] = info
}
// insertErr is an error code returned by insert. Using this type instead
// of error improves performance up to 20% for many of the benchmarks.
type insertErr int
const (
iSuccess insertErr = -iota
iShortDst
iShortSrc
)
// insertFlush inserts the given rune in the buffer ordered by CCC.
// If a decomposition with multiple segments are encountered, they leading
// ones are flushed.
// It returns a non-zero error code if the rune was not inserted.
func (rb *reorderBuffer) insertFlush(src input, i int, info Properties) insertErr {
if rune := src.hangul(i); rune != 0 {
rb.decomposeHangul(rune)
return iSuccess
}
if info.hasDecomposition() {
return rb.insertDecomposed(info.Decomposition())
}
rb.insertSingle(src, i, info)
return iSuccess
}
// insertUnsafe inserts the given rune in the buffer ordered by CCC.
// It is assumed there is sufficient space to hold the runes. It is the
// responsibility of the caller to ensure this. This can be done by checking
// the state returned by the streamSafe type.
func (rb *reorderBuffer) insertUnsafe(src input, i int, info Properties) {
if rune := src.hangul(i); rune != 0 {
rb.decomposeHangul(rune)
}
if info.hasDecomposition() {
// TODO: inline.
rb.insertDecomposed(info.Decomposition())
} else {
rb.insertSingle(src, i, info)
}
}
// insertDecomposed inserts an entry in to the reorderBuffer for each rune
// in dcomp. dcomp must be a sequence of decomposed UTF-8-encoded runes.
// It flushes the buffer on each new segment start.
func (rb *reorderBuffer) insertDecomposed(dcomp []byte) insertErr {
rb.tmpBytes.setBytes(dcomp)
// As the streamSafe accounting already handles the counting for modifiers,
// we don't have to call next. However, we do need to keep the accounting
// intact when flushing the buffer.
for i := 0; i < len(dcomp); {
info := rb.f.info(rb.tmpBytes, i)
if info.BoundaryBefore() && rb.nrune > 0 && !rb.doFlush() {
return iShortDst
}
i += copy(rb.byte[rb.nbyte:], dcomp[i:i+int(info.size)])
rb.insertOrdered(info)
}
return iSuccess
}
// insertSingle inserts an entry in the reorderBuffer for the rune at
// position i. info is the runeInfo for the rune at position i.
func (rb *reorderBuffer) insertSingle(src input, i int, info Properties) {
src.copySlice(rb.byte[rb.nbyte:], i, i+int(info.size))
rb.insertOrdered(info)
}
// insertCGJ inserts a Combining Grapheme Joiner (0x034f) into rb.
func (rb *reorderBuffer) insertCGJ() {
rb.insertSingle(input{str: GraphemeJoiner}, 0, Properties{size: uint8(len(GraphemeJoiner))})
}
// appendRune inserts a rune at the end of the buffer. It is used for Hangul.
func (rb *reorderBuffer) appendRune(r rune) {
bn := rb.nbyte
sz := utf8.EncodeRune(rb.byte[bn:], rune(r))
rb.nbyte += utf8.UTFMax
rb.rune[rb.nrune] = Properties{pos: bn, size: uint8(sz)}
rb.nrune++
}
// assignRune sets a rune at position pos. It is used for Hangul and recomposition.
func (rb *reorderBuffer) assignRune(pos int, r rune) {
bn := rb.rune[pos].pos
sz := utf8.EncodeRune(rb.byte[bn:], rune(r))
rb.rune[pos] = Properties{pos: bn, size: uint8(sz)}
}
// runeAt returns the rune at position n. It is used for Hangul and recomposition.
func (rb *reorderBuffer) runeAt(n int) rune {
inf := rb.rune[n]
r, _ := utf8.DecodeRune(rb.byte[inf.pos : inf.pos+inf.size])
return r
}
// bytesAt returns the UTF-8 encoding of the rune at position n.
// It is used for Hangul and recomposition.
func (rb *reorderBuffer) bytesAt(n int) []byte {
inf := rb.rune[n]
return rb.byte[inf.pos : int(inf.pos)+int(inf.size)]
}
// For Hangul we combine algorithmically, instead of using tables.
const (
hangulBase = 0xAC00 // UTF-8(hangulBase) -> EA B0 80
hangulBase0 = 0xEA
hangulBase1 = 0xB0
hangulBase2 = 0x80
hangulEnd = hangulBase + jamoLVTCount // UTF-8(0xD7A4) -> ED 9E A4
hangulEnd0 = 0xED
hangulEnd1 = 0x9E
hangulEnd2 = 0xA4
jamoLBase = 0x1100 // UTF-8(jamoLBase) -> E1 84 00
jamoLBase0 = 0xE1
jamoLBase1 = 0x84
jamoLEnd = 0x1113
jamoVBase = 0x1161
jamoVEnd = 0x1176
jamoTBase = 0x11A7
jamoTEnd = 0x11C3
jamoTCount = 28
jamoVCount = 21
jamoVTCount = 21 * 28
jamoLVTCount = 19 * 21 * 28
)
const hangulUTF8Size = 3
func isHangul(b []byte) bool {
if len(b) < hangulUTF8Size {
return false
}
b0 := b[0]
if b0 < hangulBase0 {
return false
}
b1 := b[1]
switch {
case b0 == hangulBase0:
return b1 >= hangulBase1
case b0 < hangulEnd0:
return true
case b0 > hangulEnd0:
return false
case b1 < hangulEnd1:
return true
}
return b1 == hangulEnd1 && b[2] < hangulEnd2
}
func isHangulString(b string) bool {
if len(b) < hangulUTF8Size {
return false
}
b0 := b[0]
if b0 < hangulBase0 {
return false
}
b1 := b[1]
switch {
case b0 == hangulBase0:
return b1 >= hangulBase1
case b0 < hangulEnd0:
return true
case b0 > hangulEnd0:
return false
case b1 < hangulEnd1:
return true
}
return b1 == hangulEnd1 && b[2] < hangulEnd2
}
// Caller must ensure len(b) >= 2.
func isJamoVT(b []byte) bool {
// True if (rune & 0xff00) == jamoLBase
return b[0] == jamoLBase0 && (b[1]&0xFC) == jamoLBase1
}
func isHangulWithoutJamoT(b []byte) bool {
c, _ := utf8.DecodeRune(b)
c -= hangulBase
return c < jamoLVTCount && c%jamoTCount == 0
}
// decomposeHangul writes the decomposed Hangul to buf and returns the number
// of bytes written. len(buf) should be at least 9.
func decomposeHangul(buf []byte, r rune) int {
const JamoUTF8Len = 3
r -= hangulBase
x := r % jamoTCount
r /= jamoTCount
utf8.EncodeRune(buf, jamoLBase+r/jamoVCount)
utf8.EncodeRune(buf[JamoUTF8Len:], jamoVBase+r%jamoVCount)
if x != 0 {
utf8.EncodeRune(buf[2*JamoUTF8Len:], jamoTBase+x)
return 3 * JamoUTF8Len
}
return 2 * JamoUTF8Len
}
// decomposeHangul algorithmically decomposes a Hangul rune into
// its Jamo components.
// See https://unicode.org/reports/tr15/#Hangul for details on decomposing Hangul.
func (rb *reorderBuffer) decomposeHangul(r rune) {
r -= hangulBase
x := r % jamoTCount
r /= jamoTCount
rb.appendRune(jamoLBase + r/jamoVCount)
rb.appendRune(jamoVBase + r%jamoVCount)
if x != 0 {
rb.appendRune(jamoTBase + x)
}
}
// combineHangul algorithmically combines Jamo character components into Hangul.
// See https://unicode.org/reports/tr15/#Hangul for details on combining Hangul.
func (rb *reorderBuffer) combineHangul(s, i, k int) {
b := rb.rune[:]
bn := rb.nrune
for ; i < bn; i++ {
cccB := b[k-1].ccc
cccC := b[i].ccc
if cccB == 0 {
s = k - 1
}
if s != k-1 && cccB >= cccC {
// b[i] is blocked by greater-equal cccX below it
b[k] = b[i]
k++
} else {
l := rb.runeAt(s) // also used to compare to hangulBase
v := rb.runeAt(i) // also used to compare to jamoT
switch {
case jamoLBase <= l && l < jamoLEnd &&
jamoVBase <= v && v < jamoVEnd:
// 11xx plus 116x to LV
rb.assignRune(s, hangulBase+
(l-jamoLBase)*jamoVTCount+(v-jamoVBase)*jamoTCount)
case hangulBase <= l && l < hangulEnd &&
jamoTBase < v && v < jamoTEnd &&
((l-hangulBase)%jamoTCount) == 0:
// ACxx plus 11Ax to LVT
rb.assignRune(s, l+v-jamoTBase)
default:
b[k] = b[i]
k++
}
}
}
rb.nrune = k
}
// compose recombines the runes in the buffer.
// It should only be used to recompose a single segment, as it will not
// handle alternations between Hangul and non-Hangul characters correctly.
func (rb *reorderBuffer) compose() {
// Lazily load the map used by the combine func below, but do
// it outside of the loop.
recompMapOnce.Do(buildRecompMap)
// UAX #15, section X5 , including Corrigendum #5
// "In any character sequence beginning with starter S, a character C is
// blocked from S if and only if there is some character B between S
// and C, and either B is a starter or it has the same or higher
// combining class as C."
bn := rb.nrune
if bn == 0 {
return
}
k := 1
b := rb.rune[:]
for s, i := 0, 1; i < bn; i++ {
if isJamoVT(rb.bytesAt(i)) {
// Redo from start in Hangul mode. Necessary to support
// U+320E..U+321E in NFKC mode.
rb.combineHangul(s, i, k)
return
}
ii := b[i]
// We can only use combineForward as a filter if we later
// get the info for the combined character. This is more
// expensive than using the filter. Using combinesBackward()
// is safe.
if ii.combinesBackward() {
cccB := b[k-1].ccc
cccC := ii.ccc
blocked := false // b[i] blocked by starter or greater or equal CCC?
if cccB == 0 {
s = k - 1
} else {
blocked = s != k-1 && cccB >= cccC
}
if !blocked {
combined := combine(rb.runeAt(s), rb.runeAt(i))
if combined != 0 {
rb.assignRune(s, combined)
continue
}
}
}
b[k] = b[i]
k++
}
rb.nrune = k
}
// Copyright 2011 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 norm
import "encoding/binary"
// This file contains Form-specific logic and wrappers for data in tables.go.
// Rune info is stored in a separate trie per composing form. A composing form
// and its corresponding decomposing form share the same trie. Each trie maps
// a rune to a uint16. The values take two forms. For v >= 0x8000:
// bits
// 15: 1 (inverse of NFD_QC bit of qcInfo)
// 13..7: qcInfo (see below). isYesD is always true (no decomposition).
// 6..0: ccc (compressed CCC value).
// For v < 0x8000, the respective rune has a decomposition and v is an index
// into a byte array of UTF-8 decomposition sequences and additional info and
// has the form:
// <header> <decomp_byte>* [<tccc> [<lccc>]]
// The header contains the number of bytes in the decomposition (excluding this
// length byte). The two most significant bits of this length byte correspond
// to bit 5 and 4 of qcInfo (see below). The byte sequence itself starts at v+1.
// The byte sequence is followed by a trailing and leading CCC if the values
// for these are not zero. The value of v determines which ccc are appended
// to the sequences. For v < firstCCC, there are none, for v >= firstCCC,
// the sequence is followed by a trailing ccc, and for v >= firstLeadingCC
// there is an additional leading ccc. The value of tccc itself is the
// trailing CCC shifted left 2 bits. The two least-significant bits of tccc
// are the number of trailing non-starters.
const (
qcInfoMask = 0x3F // to clear all but the relevant bits in a qcInfo
headerLenMask = 0x3F // extract the length value from the header byte
headerFlagsMask = 0xC0 // extract the qcInfo bits from the header byte
)
// Properties provides access to normalization properties of a rune.
type Properties struct {
pos uint8 // start position in reorderBuffer; used in composition.go
size uint8 // length of UTF-8 encoding of this rune
ccc uint8 // leading canonical combining class (ccc if not decomposition)
tccc uint8 // trailing canonical combining class (ccc if not decomposition)
nLead uint8 // number of leading non-starters.
flags qcInfo // quick check flags
index uint16
}
// functions dispatchable per form
type lookupFunc func(b input, i int) Properties
// formInfo holds Form-specific functions and tables.
type formInfo struct {
form Form
composing, compatibility bool // form type
info lookupFunc
nextMain iterFunc
}
var formTable = []*formInfo{{
form: NFC,
composing: true,
compatibility: false,
info: lookupInfoNFC,
nextMain: nextComposed,
}, {
form: NFD,
composing: false,
compatibility: false,
info: lookupInfoNFC,
nextMain: nextDecomposed,
}, {
form: NFKC,
composing: true,
compatibility: true,
info: lookupInfoNFKC,
nextMain: nextComposed,
}, {
form: NFKD,
composing: false,
compatibility: true,
info: lookupInfoNFKC,
nextMain: nextDecomposed,
}}
// We do not distinguish between boundaries for NFC, NFD, etc. to avoid
// unexpected behavior for the user. For example, in NFD, there is a boundary
// after 'a'. However, 'a' might combine with modifiers, so from the application's
// perspective it is not a good boundary. We will therefore always use the
// boundaries for the combining variants.
// BoundaryBefore returns true if this rune starts a new segment and
// cannot combine with any rune on the left.
func (p Properties) BoundaryBefore() bool {
if p.ccc == 0 && !p.combinesBackward() {
return true
}
// We assume that the CCC of the first character in a decomposition
// is always non-zero if different from info.ccc and that we can return
// false at this point. This is verified by maketables.
return false
}
// BoundaryAfter returns true if runes cannot combine with or otherwise
// interact with this or previous runes.
func (p Properties) BoundaryAfter() bool {
// TODO: loosen these conditions.
return p.isInert()
}
// We pack quick check data in 4 bits:
//
// 5: Combines forward (0 == false, 1 == true)
// 4..3: NFC_QC Yes(00), No (10), or Maybe (11)
// 2: NFD_QC Yes (0) or No (1). No also means there is a decomposition.
// 1..0: Number of trailing non-starters.
//
// When all 4 bits are zero, the character is inert, meaning it is never
// influenced by normalization.
type qcInfo uint8
func (p Properties) isYesC() bool { return p.flags&0x10 == 0 }
func (p Properties) isYesD() bool { return p.flags&0x4 == 0 }
func (p Properties) combinesForward() bool { return p.flags&0x20 != 0 }
func (p Properties) combinesBackward() bool { return p.flags&0x8 != 0 } // == isMaybe
func (p Properties) hasDecomposition() bool { return p.flags&0x4 != 0 } // == isNoD
func (p Properties) isInert() bool {
return p.flags&qcInfoMask == 0 && p.ccc == 0
}
func (p Properties) multiSegment() bool {
return p.index >= firstMulti && p.index < endMulti
}
func (p Properties) nLeadingNonStarters() uint8 {
return p.nLead
}
func (p Properties) nTrailingNonStarters() uint8 {
return uint8(p.flags & 0x03)
}
// Decomposition returns the decomposition for the underlying rune
// or nil if there is none.
func (p Properties) Decomposition() []byte {
// TODO: create the decomposition for Hangul?
if p.index == 0 {
return nil
}
i := p.index
n := decomps[i] & headerLenMask
i++
return decomps[i : i+uint16(n)]
}
// Size returns the length of UTF-8 encoding of the rune.
func (p Properties) Size() int {
return int(p.size)
}
// CCC returns the canonical combining class of the underlying rune.
func (p Properties) CCC() uint8 {
if p.index >= firstCCCZeroExcept {
return 0
}
return ccc[p.ccc]
}
// LeadCCC returns the CCC of the first rune in the decomposition.
// If there is no decomposition, LeadCCC equals CCC.
func (p Properties) LeadCCC() uint8 {
return ccc[p.ccc]
}
// TrailCCC returns the CCC of the last rune in the decomposition.
// If there is no decomposition, TrailCCC equals CCC.
func (p Properties) TrailCCC() uint8 {
return ccc[p.tccc]
}
func buildRecompMap() {
recompMap = make(map[uint32]rune, len(recompMapPacked)/8)
var buf [8]byte
for i := 0; i < len(recompMapPacked); i += 8 {
copy(buf[:], recompMapPacked[i:i+8])
key := binary.BigEndian.Uint32(buf[:4])
val := binary.BigEndian.Uint32(buf[4:])
recompMap[key] = rune(val)
}
}
// Recomposition
// We use 32-bit keys instead of 64-bit for the two codepoint keys.
// This clips off the bits of three entries, but we know this will not
// result in a collision. In the unlikely event that changes to
// UnicodeData.txt introduce collisions, the compiler will catch it.
// Note that the recomposition map for NFC and NFKC are identical.
// combine returns the combined rune or 0 if it doesn't exist.
//
// The caller is responsible for calling
// recompMapOnce.Do(buildRecompMap) sometime before this is called.
func combine(a, b rune) rune {
key := uint32(uint16(a))<<16 + uint32(uint16(b))
if recompMap == nil {
panic("caller error") // see func comment
}
return recompMap[key]
}
func lookupInfoNFC(b input, i int) Properties {
v, sz := b.charinfoNFC(i)
return compInfo(v, sz)
}
func lookupInfoNFKC(b input, i int) Properties {
v, sz := b.charinfoNFKC(i)
return compInfo(v, sz)
}
// Properties returns properties for the first rune in s.
func (f Form) Properties(s []byte) Properties {
if f == NFC || f == NFD {
return compInfo(nfcData.lookup(s))
}
return compInfo(nfkcData.lookup(s))
}
// PropertiesString returns properties for the first rune in s.
func (f Form) PropertiesString(s string) Properties {
if f == NFC || f == NFD {
return compInfo(nfcData.lookupString(s))
}
return compInfo(nfkcData.lookupString(s))
}
// compInfo converts the information contained in v and sz
// to a Properties. See the comment at the top of the file
// for more information on the format.
func compInfo(v uint16, sz int) Properties {
if v == 0 {
return Properties{size: uint8(sz)}
} else if v >= 0x8000 {
p := Properties{
size: uint8(sz),
ccc: uint8(v),
tccc: uint8(v),
flags: qcInfo(v >> 8),
}
if p.ccc > 0 || p.combinesBackward() {
p.nLead = uint8(p.flags & 0x3)
}
return p
}
// has decomposition
h := decomps[v]
f := (qcInfo(h&headerFlagsMask) >> 2) | 0x4
p := Properties{size: uint8(sz), flags: f, index: v}
if v >= firstCCC {
v += uint16(h&headerLenMask) + 1
c := decomps[v]
p.tccc = c >> 2
p.flags |= qcInfo(c & 0x3)
if v >= firstLeadingCCC {
p.nLead = c & 0x3
if v >= firstStarterWithNLead {
// We were tricked. Remove the decomposition.
p.flags &= 0x03
p.index = 0
return p
}
p.ccc = decomps[v+1]
}
}
return p
}
// Copyright 2011 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 norm
import "unicode/utf8"
type input struct {
str string
bytes []byte
}
func inputBytes(str []byte) input {
return input{bytes: str}
}
func inputString(str string) input {
return input{str: str}
}
func (in *input) setBytes(str []byte) {
in.str = ""
in.bytes = str
}
func (in *input) setString(str string) {
in.str = str
in.bytes = nil
}
func (in *input) _byte(p int) byte {
if in.bytes == nil {
return in.str[p]
}
return in.bytes[p]
}
func (in *input) skipASCII(p, max int) int {
if in.bytes == nil {
for ; p < max && in.str[p] < utf8.RuneSelf; p++ {
}
} else {
for ; p < max && in.bytes[p] < utf8.RuneSelf; p++ {
}
}
return p
}
func (in *input) skipContinuationBytes(p int) int {
if in.bytes == nil {
for ; p < len(in.str) && !utf8.RuneStart(in.str[p]); p++ {
}
} else {
for ; p < len(in.bytes) && !utf8.RuneStart(in.bytes[p]); p++ {
}
}
return p
}
func (in *input) appendSlice(buf []byte, b, e int) []byte {
if in.bytes != nil {
return append(buf, in.bytes[b:e]...)
}
for i := b; i < e; i++ {
buf = append(buf, in.str[i])
}
return buf
}
func (in *input) copySlice(buf []byte, b, e int) int {
if in.bytes == nil {
return copy(buf, in.str[b:e])
}
return copy(buf, in.bytes[b:e])
}
func (in *input) charinfoNFC(p int) (uint16, int) {
if in.bytes == nil {
return nfcData.lookupString(in.str[p:])
}
return nfcData.lookup(in.bytes[p:])
}
func (in *input) charinfoNFKC(p int) (uint16, int) {
if in.bytes == nil {
return nfkcData.lookupString(in.str[p:])
}
return nfkcData.lookup(in.bytes[p:])
}
func (in *input) hangul(p int) (r rune) {
var size int
if in.bytes == nil {
if !isHangulString(in.str[p:]) {
return 0
}
r, size = utf8.DecodeRuneInString(in.str[p:])
} else {
if !isHangul(in.bytes[p:]) {
return 0
}
r, size = utf8.DecodeRune(in.bytes[p:])
}
if size != hangulUTF8Size {
return 0
}
return r
}
// Copyright 2011 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 norm
import (
"fmt"
"unicode/utf8"
)
// MaxSegmentSize is the maximum size of a byte buffer needed to consider any
// sequence of starter and non-starter runes for the purpose of normalization.
const MaxSegmentSize = maxByteBufferSize
// An Iter iterates over a string or byte slice, while normalizing it
// to a given Form.
type Iter struct {
rb reorderBuffer
buf [maxByteBufferSize]byte
info Properties // first character saved from previous iteration
next iterFunc // implementation of next depends on form
asciiF iterFunc
p int // current position in input source
multiSeg []byte // remainder of multi-segment decomposition
}
type iterFunc func(*Iter) []byte
// Init initializes i to iterate over src after normalizing it to Form f.
func (i *Iter) Init(f Form, src []byte) {
i.p = 0
if len(src) == 0 {
i.setDone()
i.rb.nsrc = 0
return
}
i.multiSeg = nil
i.rb.init(f, src)
i.next = i.rb.f.nextMain
i.asciiF = nextASCIIBytes
i.info = i.rb.f.info(i.rb.src, i.p)
i.rb.ss.first(i.info)
}
// InitString initializes i to iterate over src after normalizing it to Form f.
func (i *Iter) InitString(f Form, src string) {
i.p = 0
if len(src) == 0 {
i.setDone()
i.rb.nsrc = 0
return
}
i.multiSeg = nil
i.rb.initString(f, src)
i.next = i.rb.f.nextMain
i.asciiF = nextASCIIString
i.info = i.rb.f.info(i.rb.src, i.p)
i.rb.ss.first(i.info)
}
// Seek sets the segment to be returned by the next call to Next to start
// at position p. It is the responsibility of the caller to set p to the
// start of a segment.
func (i *Iter) Seek(offset int64, whence int) (int64, error) {
var abs int64
switch whence {
case 0:
abs = offset
case 1:
abs = int64(i.p) + offset
case 2:
abs = int64(i.rb.nsrc) + offset
default:
return 0, fmt.Errorf("norm: invalid whence")
}
if abs < 0 {
return 0, fmt.Errorf("norm: negative position")
}
if int(abs) >= i.rb.nsrc {
i.setDone()
return int64(i.p), nil
}
i.p = int(abs)
i.multiSeg = nil
i.next = i.rb.f.nextMain
i.info = i.rb.f.info(i.rb.src, i.p)
i.rb.ss.first(i.info)
return abs, nil
}
// returnSlice returns a slice of the underlying input type as a byte slice.
// If the underlying is of type []byte, it will simply return a slice.
// If the underlying is of type string, it will copy the slice to the buffer
// and return that.
func (i *Iter) returnSlice(a, b int) []byte {
if i.rb.src.bytes == nil {
return i.buf[:copy(i.buf[:], i.rb.src.str[a:b])]
}
return i.rb.src.bytes[a:b]
}
// Pos returns the byte position at which the next call to Next will commence processing.
func (i *Iter) Pos() int {
return i.p
}
func (i *Iter) setDone() {
i.next = nextDone
i.p = i.rb.nsrc
}
// Done returns true if there is no more input to process.
func (i *Iter) Done() bool {
return i.p >= i.rb.nsrc
}
// Next returns f(i.input[i.Pos():n]), where n is a boundary of i.input.
// For any input a and b for which f(a) == f(b), subsequent calls
// to Next will return the same segments.
// Modifying runes are grouped together with the preceding starter, if such a starter exists.
// Although not guaranteed, n will typically be the smallest possible n.
func (i *Iter) Next() []byte {
return i.next(i)
}
func nextASCIIBytes(i *Iter) []byte {
p := i.p + 1
if p >= i.rb.nsrc {
p0 := i.p
i.setDone()
return i.rb.src.bytes[p0:p]
}
if i.rb.src.bytes[p] < utf8.RuneSelf {
p0 := i.p
i.p = p
return i.rb.src.bytes[p0:p]
}
i.info = i.rb.f.info(i.rb.src, i.p)
i.next = i.rb.f.nextMain
return i.next(i)
}
func nextASCIIString(i *Iter) []byte {
p := i.p + 1
if p >= i.rb.nsrc {
i.buf[0] = i.rb.src.str[i.p]
i.setDone()
return i.buf[:1]
}
if i.rb.src.str[p] < utf8.RuneSelf {
i.buf[0] = i.rb.src.str[i.p]
i.p = p
return i.buf[:1]
}
i.info = i.rb.f.info(i.rb.src, i.p)
i.next = i.rb.f.nextMain
return i.next(i)
}
func nextHangul(i *Iter) []byte {
p := i.p
next := p + hangulUTF8Size
if next >= i.rb.nsrc {
i.setDone()
} else if i.rb.src.hangul(next) == 0 {
i.rb.ss.next(i.info)
i.info = i.rb.f.info(i.rb.src, i.p)
i.next = i.rb.f.nextMain
return i.next(i)
}
i.p = next
return i.buf[:decomposeHangul(i.buf[:], i.rb.src.hangul(p))]
}
func nextDone(i *Iter) []byte {
return nil
}
// nextMulti is used for iterating over multi-segment decompositions
// for decomposing normal forms.
func nextMulti(i *Iter) []byte {
j := 0
d := i.multiSeg
// skip first rune
for j = 1; j < len(d) && !utf8.RuneStart(d[j]); j++ {
}
for j < len(d) {
info := i.rb.f.info(input{bytes: d}, j)
if info.BoundaryBefore() {
i.multiSeg = d[j:]
return d[:j]
}
j += int(info.size)
}
// treat last segment as normal decomposition
i.next = i.rb.f.nextMain
return i.next(i)
}
// nextMultiNorm is used for iterating over multi-segment decompositions
// for composing normal forms.
func nextMultiNorm(i *Iter) []byte {
j := 0
d := i.multiSeg
for j < len(d) {
info := i.rb.f.info(input{bytes: d}, j)
if info.BoundaryBefore() {
i.rb.compose()
seg := i.buf[:i.rb.flushCopy(i.buf[:])]
i.rb.insertUnsafe(input{bytes: d}, j, info)
i.multiSeg = d[j+int(info.size):]
return seg
}
i.rb.insertUnsafe(input{bytes: d}, j, info)
j += int(info.size)
}
i.multiSeg = nil
i.next = nextComposed
return doNormComposed(i)
}
// nextDecomposed is the implementation of Next for forms NFD and NFKD.
func nextDecomposed(i *Iter) (next []byte) {
outp := 0
inCopyStart, outCopyStart := i.p, 0
for {
if sz := int(i.info.size); sz <= 1 {
i.rb.ss = 0
p := i.p
i.p++ // ASCII or illegal byte. Either way, advance by 1.
if i.p >= i.rb.nsrc {
i.setDone()
return i.returnSlice(p, i.p)
} else if i.rb.src._byte(i.p) < utf8.RuneSelf {
i.next = i.asciiF
return i.returnSlice(p, i.p)
}
outp++
} else if d := i.info.Decomposition(); d != nil {
// Note: If leading CCC != 0, then len(d) == 2 and last is also non-zero.
// Case 1: there is a leftover to copy. In this case the decomposition
// must begin with a modifier and should always be appended.
// Case 2: no leftover. Simply return d if followed by a ccc == 0 value.
p := outp + len(d)
if outp > 0 {
i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p)
// TODO: this condition should not be possible, but we leave it
// in for defensive purposes.
if p > len(i.buf) {
return i.buf[:outp]
}
} else if i.info.multiSegment() {
// outp must be 0 as multi-segment decompositions always
// start a new segment.
if i.multiSeg == nil {
i.multiSeg = d
i.next = nextMulti
return nextMulti(i)
}
// We are in the last segment. Treat as normal decomposition.
d = i.multiSeg
i.multiSeg = nil
p = len(d)
}
prevCC := i.info.tccc
if i.p += sz; i.p >= i.rb.nsrc {
i.setDone()
i.info = Properties{} // Force BoundaryBefore to succeed.
} else {
i.info = i.rb.f.info(i.rb.src, i.p)
}
switch i.rb.ss.next(i.info) {
case ssOverflow:
i.next = nextCGJDecompose
fallthrough
case ssStarter:
if outp > 0 {
copy(i.buf[outp:], d)
return i.buf[:p]
}
return d
}
copy(i.buf[outp:], d)
outp = p
inCopyStart, outCopyStart = i.p, outp
if i.info.ccc < prevCC {
goto doNorm
}
continue
} else if r := i.rb.src.hangul(i.p); r != 0 {
outp = decomposeHangul(i.buf[:], r)
i.p += hangulUTF8Size
inCopyStart, outCopyStart = i.p, outp
if i.p >= i.rb.nsrc {
i.setDone()
break
} else if i.rb.src.hangul(i.p) != 0 {
i.next = nextHangul
return i.buf[:outp]
}
} else {
p := outp + sz
if p > len(i.buf) {
break
}
outp = p
i.p += sz
}
if i.p >= i.rb.nsrc {
i.setDone()
break
}
prevCC := i.info.tccc
i.info = i.rb.f.info(i.rb.src, i.p)
if v := i.rb.ss.next(i.info); v == ssStarter {
break
} else if v == ssOverflow {
i.next = nextCGJDecompose
break
}
if i.info.ccc < prevCC {
goto doNorm
}
}
if outCopyStart == 0 {
return i.returnSlice(inCopyStart, i.p)
} else if inCopyStart < i.p {
i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p)
}
return i.buf[:outp]
doNorm:
// Insert what we have decomposed so far in the reorderBuffer.
// As we will only reorder, there will always be enough room.
i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p)
i.rb.insertDecomposed(i.buf[0:outp])
return doNormDecomposed(i)
}
func doNormDecomposed(i *Iter) []byte {
for {
i.rb.insertUnsafe(i.rb.src, i.p, i.info)
if i.p += int(i.info.size); i.p >= i.rb.nsrc {
i.setDone()
break
}
i.info = i.rb.f.info(i.rb.src, i.p)
if i.info.ccc == 0 {
break
}
if s := i.rb.ss.next(i.info); s == ssOverflow {
i.next = nextCGJDecompose
break
}
}
// new segment or too many combining characters: exit normalization
return i.buf[:i.rb.flushCopy(i.buf[:])]
}
func nextCGJDecompose(i *Iter) []byte {
i.rb.ss = 0
i.rb.insertCGJ()
i.next = nextDecomposed
i.rb.ss.first(i.info)
buf := doNormDecomposed(i)
return buf
}
// nextComposed is the implementation of Next for forms NFC and NFKC.
func nextComposed(i *Iter) []byte {
outp, startp := 0, i.p
var prevCC uint8
for {
if !i.info.isYesC() {
goto doNorm
}
prevCC = i.info.tccc
sz := int(i.info.size)
if sz == 0 {
sz = 1 // illegal rune: copy byte-by-byte
}
p := outp + sz
if p > len(i.buf) {
break
}
outp = p
i.p += sz
if i.p >= i.rb.nsrc {
i.setDone()
break
} else if i.rb.src._byte(i.p) < utf8.RuneSelf {
i.rb.ss = 0
i.next = i.asciiF
break
}
i.info = i.rb.f.info(i.rb.src, i.p)
if v := i.rb.ss.next(i.info); v == ssStarter {
break
} else if v == ssOverflow {
i.next = nextCGJCompose
break
}
if i.info.ccc < prevCC {
goto doNorm
}
}
return i.returnSlice(startp, i.p)
doNorm:
// reset to start position
i.p = startp
i.info = i.rb.f.info(i.rb.src, i.p)
i.rb.ss.first(i.info)
if i.info.multiSegment() {
d := i.info.Decomposition()
info := i.rb.f.info(input{bytes: d}, 0)
i.rb.insertUnsafe(input{bytes: d}, 0, info)
i.multiSeg = d[int(info.size):]
i.next = nextMultiNorm
return nextMultiNorm(i)
}
i.rb.ss.first(i.info)
i.rb.insertUnsafe(i.rb.src, i.p, i.info)
return doNormComposed(i)
}
func doNormComposed(i *Iter) []byte {
// First rune should already be inserted.
for {
if i.p += int(i.info.size); i.p >= i.rb.nsrc {
i.setDone()
break
}
i.info = i.rb.f.info(i.rb.src, i.p)
if s := i.rb.ss.next(i.info); s == ssStarter {
break
} else if s == ssOverflow {
i.next = nextCGJCompose
break
}
i.rb.insertUnsafe(i.rb.src, i.p, i.info)
}
i.rb.compose()
seg := i.buf[:i.rb.flushCopy(i.buf[:])]
return seg
}
func nextCGJCompose(i *Iter) []byte {
i.rb.ss = 0 // instead of first
i.rb.insertCGJ()
i.next = nextComposed
// Note that we treat any rune with nLeadingNonStarters > 0 as a non-starter,
// even if they are not. This is particularly dubious for U+FF9E and UFF9A.
// If we ever change that, insert a check here.
i.rb.ss.first(i.info)
i.rb.insertUnsafe(i.rb.src, i.p, i.info)
return doNormComposed(i)
}
// Copyright 2011 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.
// Note: the file data_test.go that is generated should not be checked in.
//go:generate go run maketables.go triegen.go
//go:generate go test -tags test
// Package norm contains types and functions for normalizing Unicode strings.
package norm // import "golang.org/x/text/unicode/norm"
import (
"unicode/utf8"
"golang.org/x/text/transform"
)
// A Form denotes a canonical representation of Unicode code points.
// The Unicode-defined normalization and equivalence forms are:
//
// NFC Unicode Normalization Form C
// NFD Unicode Normalization Form D
// NFKC Unicode Normalization Form KC
// NFKD Unicode Normalization Form KD
//
// For a Form f, this documentation uses the notation f(x) to mean
// the bytes or string x converted to the given form.
// A position n in x is called a boundary if conversion to the form can
// proceed independently on both sides:
//
// f(x) == append(f(x[0:n]), f(x[n:])...)
//
// References: https://unicode.org/reports/tr15/ and
// https://unicode.org/notes/tn5/.
type Form int
const (
NFC Form = iota
NFD
NFKC
NFKD
)
// Bytes returns f(b). May return b if f(b) = b.
func (f Form) Bytes(b []byte) []byte {
src := inputBytes(b)
ft := formTable[f]
n, ok := ft.quickSpan(src, 0, len(b), true)
if ok {
return b
}
out := make([]byte, n, len(b))
copy(out, b[0:n])
rb := reorderBuffer{f: *ft, src: src, nsrc: len(b), out: out, flushF: appendFlush}
return doAppendInner(&rb, n)
}
// String returns f(s).
func (f Form) String(s string) string {
src := inputString(s)
ft := formTable[f]
n, ok := ft.quickSpan(src, 0, len(s), true)
if ok {
return s
}
out := make([]byte, n, len(s))
copy(out, s[0:n])
rb := reorderBuffer{f: *ft, src: src, nsrc: len(s), out: out, flushF: appendFlush}
return string(doAppendInner(&rb, n))
}
// IsNormal returns true if b == f(b).
func (f Form) IsNormal(b []byte) bool {
src := inputBytes(b)
ft := formTable[f]
bp, ok := ft.quickSpan(src, 0, len(b), true)
if ok {
return true
}
rb := reorderBuffer{f: *ft, src: src, nsrc: len(b)}
rb.setFlusher(nil, cmpNormalBytes)
for bp < len(b) {
rb.out = b[bp:]
if bp = decomposeSegment(&rb, bp, true); bp < 0 {
return false
}
bp, _ = rb.f.quickSpan(rb.src, bp, len(b), true)
}
return true
}
func cmpNormalBytes(rb *reorderBuffer) bool {
b := rb.out
for i := 0; i < rb.nrune; i++ {
info := rb.rune[i]
if int(info.size) > len(b) {
return false
}
p := info.pos
pe := p + info.size
for ; p < pe; p++ {
if b[0] != rb.byte[p] {
return false
}
b = b[1:]
}
}
return true
}
// IsNormalString returns true if s == f(s).
func (f Form) IsNormalString(s string) bool {
src := inputString(s)
ft := formTable[f]
bp, ok := ft.quickSpan(src, 0, len(s), true)
if ok {
return true
}
rb := reorderBuffer{f: *ft, src: src, nsrc: len(s)}
rb.setFlusher(nil, func(rb *reorderBuffer) bool {
for i := 0; i < rb.nrune; i++ {
info := rb.rune[i]
if bp+int(info.size) > len(s) {
return false
}
p := info.pos
pe := p + info.size
for ; p < pe; p++ {
if s[bp] != rb.byte[p] {
return false
}
bp++
}
}
return true
})
for bp < len(s) {
if bp = decomposeSegment(&rb, bp, true); bp < 0 {
return false
}
bp, _ = rb.f.quickSpan(rb.src, bp, len(s), true)
}
return true
}
// patchTail fixes a case where a rune may be incorrectly normalized
// if it is followed by illegal continuation bytes. It returns the
// patched buffer and whether the decomposition is still in progress.
func patchTail(rb *reorderBuffer) bool {
info, p := lastRuneStart(&rb.f, rb.out)
if p == -1 || info.size == 0 {
return true
}
end := p + int(info.size)
extra := len(rb.out) - end
if extra > 0 {
// Potentially allocating memory. However, this only
// happens with ill-formed UTF-8.
x := make([]byte, 0)
x = append(x, rb.out[len(rb.out)-extra:]...)
rb.out = rb.out[:end]
decomposeToLastBoundary(rb)
rb.doFlush()
rb.out = append(rb.out, x...)
return false
}
buf := rb.out[p:]
rb.out = rb.out[:p]
decomposeToLastBoundary(rb)
if s := rb.ss.next(info); s == ssStarter {
rb.doFlush()
rb.ss.first(info)
} else if s == ssOverflow {
rb.doFlush()
rb.insertCGJ()
rb.ss = 0
}
rb.insertUnsafe(inputBytes(buf), 0, info)
return true
}
func appendQuick(rb *reorderBuffer, i int) int {
if rb.nsrc == i {
return i
}
end, _ := rb.f.quickSpan(rb.src, i, rb.nsrc, true)
rb.out = rb.src.appendSlice(rb.out, i, end)
return end
}
// Append returns f(append(out, b...)).
// The buffer out must be nil, empty, or equal to f(out).
func (f Form) Append(out []byte, src ...byte) []byte {
return f.doAppend(out, inputBytes(src), len(src))
}
func (f Form) doAppend(out []byte, src input, n int) []byte {
if n == 0 {
return out
}
ft := formTable[f]
// Attempt to do a quickSpan first so we can avoid initializing the reorderBuffer.
if len(out) == 0 {
p, _ := ft.quickSpan(src, 0, n, true)
out = src.appendSlice(out, 0, p)
if p == n {
return out
}
rb := reorderBuffer{f: *ft, src: src, nsrc: n, out: out, flushF: appendFlush}
return doAppendInner(&rb, p)
}
rb := reorderBuffer{f: *ft, src: src, nsrc: n}
return doAppend(&rb, out, 0)
}
func doAppend(rb *reorderBuffer, out []byte, p int) []byte {
rb.setFlusher(out, appendFlush)
src, n := rb.src, rb.nsrc
doMerge := len(out) > 0
if q := src.skipContinuationBytes(p); q > p {
// Move leading non-starters to destination.
rb.out = src.appendSlice(rb.out, p, q)
p = q
doMerge = patchTail(rb)
}
fd := &rb.f
if doMerge {
var info Properties
if p < n {
info = fd.info(src, p)
if !info.BoundaryBefore() || info.nLeadingNonStarters() > 0 {
if p == 0 {
decomposeToLastBoundary(rb)
}
p = decomposeSegment(rb, p, true)
}
}
if info.size == 0 {
rb.doFlush()
// Append incomplete UTF-8 encoding.
return src.appendSlice(rb.out, p, n)
}
if rb.nrune > 0 {
return doAppendInner(rb, p)
}
}
p = appendQuick(rb, p)
return doAppendInner(rb, p)
}
func doAppendInner(rb *reorderBuffer, p int) []byte {
for n := rb.nsrc; p < n; {
p = decomposeSegment(rb, p, true)
p = appendQuick(rb, p)
}
return rb.out
}
// AppendString returns f(append(out, []byte(s))).
// The buffer out must be nil, empty, or equal to f(out).
func (f Form) AppendString(out []byte, src string) []byte {
return f.doAppend(out, inputString(src), len(src))
}
// QuickSpan returns a boundary n such that b[0:n] == f(b[0:n]).
// It is not guaranteed to return the largest such n.
func (f Form) QuickSpan(b []byte) int {
n, _ := formTable[f].quickSpan(inputBytes(b), 0, len(b), true)
return n
}
// Span implements transform.SpanningTransformer. It returns a boundary n such
// that b[0:n] == f(b[0:n]). It is not guaranteed to return the largest such n.
func (f Form) Span(b []byte, atEOF bool) (n int, err error) {
n, ok := formTable[f].quickSpan(inputBytes(b), 0, len(b), atEOF)
if n < len(b) {
if !ok {
err = transform.ErrEndOfSpan
} else {
err = transform.ErrShortSrc
}
}
return n, err
}
// SpanString returns a boundary n such that s[0:n] == f(s[0:n]).
// It is not guaranteed to return the largest such n.
func (f Form) SpanString(s string, atEOF bool) (n int, err error) {
n, ok := formTable[f].quickSpan(inputString(s), 0, len(s), atEOF)
if n < len(s) {
if !ok {
err = transform.ErrEndOfSpan
} else {
err = transform.ErrShortSrc
}
}
return n, err
}
// quickSpan returns a boundary n such that src[0:n] == f(src[0:n]) and
// whether any non-normalized parts were found. If atEOF is false, n will
// not point past the last segment if this segment might be become
// non-normalized by appending other runes.
func (f *formInfo) quickSpan(src input, i, end int, atEOF bool) (n int, ok bool) {
var lastCC uint8
ss := streamSafe(0)
lastSegStart := i
for n = end; i < n; {
if j := src.skipASCII(i, n); i != j {
i = j
lastSegStart = i - 1
lastCC = 0
ss = 0
continue
}
info := f.info(src, i)
if info.size == 0 {
if atEOF {
// include incomplete runes
return n, true
}
return lastSegStart, true
}
// This block needs to be before the next, because it is possible to
// have an overflow for runes that are starters (e.g. with U+FF9E).
switch ss.next(info) {
case ssStarter:
lastSegStart = i
case ssOverflow:
return lastSegStart, false
case ssSuccess:
if lastCC > info.ccc {
return lastSegStart, false
}
}
if f.composing {
if !info.isYesC() {
break
}
} else {
if !info.isYesD() {
break
}
}
lastCC = info.ccc
i += int(info.size)
}
if i == n {
if !atEOF {
n = lastSegStart
}
return n, true
}
return lastSegStart, false
}
// QuickSpanString returns a boundary n such that s[0:n] == f(s[0:n]).
// It is not guaranteed to return the largest such n.
func (f Form) QuickSpanString(s string) int {
n, _ := formTable[f].quickSpan(inputString(s), 0, len(s), true)
return n
}
// FirstBoundary returns the position i of the first boundary in b
// or -1 if b contains no boundary.
func (f Form) FirstBoundary(b []byte) int {
return f.firstBoundary(inputBytes(b), len(b))
}
func (f Form) firstBoundary(src input, nsrc int) int {
i := src.skipContinuationBytes(0)
if i >= nsrc {
return -1
}
fd := formTable[f]
ss := streamSafe(0)
// We should call ss.first here, but we can't as the first rune is
// skipped already. This means FirstBoundary can't really determine
// CGJ insertion points correctly. Luckily it doesn't have to.
for {
info := fd.info(src, i)
if info.size == 0 {
return -1
}
if s := ss.next(info); s != ssSuccess {
return i
}
i += int(info.size)
if i >= nsrc {
if !info.BoundaryAfter() && !ss.isMax() {
return -1
}
return nsrc
}
}
}
// FirstBoundaryInString returns the position i of the first boundary in s
// or -1 if s contains no boundary.
func (f Form) FirstBoundaryInString(s string) int {
return f.firstBoundary(inputString(s), len(s))
}
// NextBoundary reports the index of the boundary between the first and next
// segment in b or -1 if atEOF is false and there are not enough bytes to
// determine this boundary.
func (f Form) NextBoundary(b []byte, atEOF bool) int {
return f.nextBoundary(inputBytes(b), len(b), atEOF)
}
// NextBoundaryInString reports the index of the boundary between the first and
// next segment in b or -1 if atEOF is false and there are not enough bytes to
// determine this boundary.
func (f Form) NextBoundaryInString(s string, atEOF bool) int {
return f.nextBoundary(inputString(s), len(s), atEOF)
}
func (f Form) nextBoundary(src input, nsrc int, atEOF bool) int {
if nsrc == 0 {
if atEOF {
return 0
}
return -1
}
fd := formTable[f]
info := fd.info(src, 0)
if info.size == 0 {
if atEOF {
return 1
}
return -1
}
ss := streamSafe(0)
ss.first(info)
for i := int(info.size); i < nsrc; i += int(info.size) {
info = fd.info(src, i)
if info.size == 0 {
if atEOF {
return i
}
return -1
}
// TODO: Using streamSafe to determine the boundary isn't the same as
// using BoundaryBefore. Determine which should be used.
if s := ss.next(info); s != ssSuccess {
return i
}
}
if !atEOF && !info.BoundaryAfter() && !ss.isMax() {
return -1
}
return nsrc
}
// LastBoundary returns the position i of the last boundary in b
// or -1 if b contains no boundary.
func (f Form) LastBoundary(b []byte) int {
return lastBoundary(formTable[f], b)
}
func lastBoundary(fd *formInfo, b []byte) int {
i := len(b)
info, p := lastRuneStart(fd, b)
if p == -1 {
return -1
}
if info.size == 0 { // ends with incomplete rune
if p == 0 { // starts with incomplete rune
return -1
}
i = p
info, p = lastRuneStart(fd, b[:i])
if p == -1 { // incomplete UTF-8 encoding or non-starter bytes without a starter
return i
}
}
if p+int(info.size) != i { // trailing non-starter bytes: illegal UTF-8
return i
}
if info.BoundaryAfter() {
return i
}
ss := streamSafe(0)
v := ss.backwards(info)
for i = p; i >= 0 && v != ssStarter; i = p {
info, p = lastRuneStart(fd, b[:i])
if v = ss.backwards(info); v == ssOverflow {
break
}
if p+int(info.size) != i {
if p == -1 { // no boundary found
return -1
}
return i // boundary after an illegal UTF-8 encoding
}
}
return i
}
// decomposeSegment scans the first segment in src into rb. It inserts 0x034f
// (Grapheme Joiner) when it encounters a sequence of more than 30 non-starters
// and returns the number of bytes consumed from src or iShortDst or iShortSrc.
func decomposeSegment(rb *reorderBuffer, sp int, atEOF bool) int {
// Force one character to be consumed.
info := rb.f.info(rb.src, sp)
if info.size == 0 {
return 0
}
if s := rb.ss.next(info); s == ssStarter {
// TODO: this could be removed if we don't support merging.
if rb.nrune > 0 {
goto end
}
} else if s == ssOverflow {
rb.insertCGJ()
goto end
}
if err := rb.insertFlush(rb.src, sp, info); err != iSuccess {
return int(err)
}
for {
sp += int(info.size)
if sp >= rb.nsrc {
if !atEOF && !info.BoundaryAfter() {
return int(iShortSrc)
}
break
}
info = rb.f.info(rb.src, sp)
if info.size == 0 {
if !atEOF {
return int(iShortSrc)
}
break
}
if s := rb.ss.next(info); s == ssStarter {
break
} else if s == ssOverflow {
rb.insertCGJ()
break
}
if err := rb.insertFlush(rb.src, sp, info); err != iSuccess {
return int(err)
}
}
end:
if !rb.doFlush() {
return int(iShortDst)
}
return sp
}
// lastRuneStart returns the runeInfo and position of the last
// rune in buf or the zero runeInfo and -1 if no rune was found.
func lastRuneStart(fd *formInfo, buf []byte) (Properties, int) {
p := len(buf) - 1
for ; p >= 0 && !utf8.RuneStart(buf[p]); p-- {
}
if p < 0 {
return Properties{}, -1
}
return fd.info(inputBytes(buf), p), p
}
// decomposeToLastBoundary finds an open segment at the end of the buffer
// and scans it into rb. Returns the buffer minus the last segment.
func decomposeToLastBoundary(rb *reorderBuffer) {
fd := &rb.f
info, i := lastRuneStart(fd, rb.out)
if int(info.size) != len(rb.out)-i {
// illegal trailing continuation bytes
return
}
if info.BoundaryAfter() {
return
}
var add [maxNonStarters + 1]Properties // stores runeInfo in reverse order
padd := 0
ss := streamSafe(0)
p := len(rb.out)
for {
add[padd] = info
v := ss.backwards(info)
if v == ssOverflow {
// Note that if we have an overflow, it the string we are appending to
// is not correctly normalized. In this case the behavior is undefined.
break
}
padd++
p -= int(info.size)
if v == ssStarter || p < 0 {
break
}
info, i = lastRuneStart(fd, rb.out[:p])
if int(info.size) != p-i {
break
}
}
rb.ss = ss
// Copy bytes for insertion as we may need to overwrite rb.out.
var buf [maxBufferSize * utf8.UTFMax]byte
cp := buf[:copy(buf[:], rb.out[p:])]
rb.out = rb.out[:p]
for padd--; padd >= 0; padd-- {
info = add[padd]
rb.insertUnsafe(inputBytes(cp), 0, info)
cp = cp[info.size:]
}
}
// Copyright 2011 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 norm
import "io"
type normWriter struct {
rb reorderBuffer
w io.Writer
buf []byte
}
// Write implements the standard write interface. If the last characters are
// not at a normalization boundary, the bytes will be buffered for the next
// write. The remaining bytes will be written on close.
func (w *normWriter) Write(data []byte) (n int, err error) {
// Process data in pieces to keep w.buf size bounded.
const chunk = 4000
for len(data) > 0 {
// Normalize into w.buf.
m := len(data)
if m > chunk {
m = chunk
}
w.rb.src = inputBytes(data[:m])
w.rb.nsrc = m
w.buf = doAppend(&w.rb, w.buf, 0)
data = data[m:]
n += m
// Write out complete prefix, save remainder.
// Note that lastBoundary looks back at most 31 runes.
i := lastBoundary(&w.rb.f, w.buf)
if i == -1 {
i = 0
}
if i > 0 {
if _, err = w.w.Write(w.buf[:i]); err != nil {
break
}
bn := copy(w.buf, w.buf[i:])
w.buf = w.buf[:bn]
}
}
return n, err
}
// Close forces data that remains in the buffer to be written.
func (w *normWriter) Close() error {
if len(w.buf) > 0 {
_, err := w.w.Write(w.buf)
if err != nil {
return err
}
}
return nil
}
// Writer returns a new writer that implements Write(b)
// by writing f(b) to w. The returned writer may use an
// internal buffer to maintain state across Write calls.
// Calling its Close method writes any buffered data to w.
func (f Form) Writer(w io.Writer) io.WriteCloser {
wr := &normWriter{rb: reorderBuffer{}, w: w}
wr.rb.init(f, nil)
return wr
}
type normReader struct {
rb reorderBuffer
r io.Reader
inbuf []byte
outbuf []byte
bufStart int
lastBoundary int
err error
}
// Read implements the standard read interface.
func (r *normReader) Read(p []byte) (int, error) {
for {
if r.lastBoundary-r.bufStart > 0 {
n := copy(p, r.outbuf[r.bufStart:r.lastBoundary])
r.bufStart += n
if r.lastBoundary-r.bufStart > 0 {
return n, nil
}
return n, r.err
}
if r.err != nil {
return 0, r.err
}
outn := copy(r.outbuf, r.outbuf[r.lastBoundary:])
r.outbuf = r.outbuf[0:outn]
r.bufStart = 0
n, err := r.r.Read(r.inbuf)
r.rb.src = inputBytes(r.inbuf[0:n])
r.rb.nsrc, r.err = n, err
if n > 0 {
r.outbuf = doAppend(&r.rb, r.outbuf, 0)
}
if err == io.EOF {
r.lastBoundary = len(r.outbuf)
} else {
r.lastBoundary = lastBoundary(&r.rb.f, r.outbuf)
if r.lastBoundary == -1 {
r.lastBoundary = 0
}
}
}
}
// Reader returns a new reader that implements Read
// by reading data from r and returning f(data).
func (f Form) Reader(r io.Reader) io.Reader {
const chunk = 4000
buf := make([]byte, chunk)
rr := &normReader{rb: reorderBuffer{}, r: r, inbuf: buf}
rr.rb.init(f, buf)
return rr
}
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.21
package norm
import "sync"
const (
// Version is the Unicode edition from which the tables are derived.
Version = "15.0.0"
// MaxTransformChunkSize indicates the maximum number of bytes that Transform
// may need to write atomically for any Form. Making a destination buffer at
// least this size ensures that Transform can always make progress and that
// the user does not need to grow the buffer on an ErrShortDst.
MaxTransformChunkSize = 35 + maxNonStarters*4
)
var ccc = [56]uint8{
0, 1, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31, 32, 33, 34, 35,
36, 84, 91, 103, 107, 118, 122, 129,
130, 132, 202, 214, 216, 218, 220, 222,
224, 226, 228, 230, 232, 233, 234, 240,
}
const (
firstMulti = 0x199A
firstCCC = 0x2DD5
endMulti = 0x30A1
firstLeadingCCC = 0x4AEF
firstCCCZeroExcept = 0x4BB9
firstStarterWithNLead = 0x4BE0
lastDecomp = 0x4BE2
maxDecomp = 0x8000
)
// decomps: 19426 bytes
var decomps = [...]byte{
// Bytes 0 - 3f
0x00, 0x41, 0x20, 0x41, 0x21, 0x41, 0x22, 0x41,
0x23, 0x41, 0x24, 0x41, 0x25, 0x41, 0x26, 0x41,
0x27, 0x41, 0x28, 0x41, 0x29, 0x41, 0x2A, 0x41,
0x2B, 0x41, 0x2C, 0x41, 0x2D, 0x41, 0x2E, 0x41,
0x2F, 0x41, 0x30, 0x41, 0x31, 0x41, 0x32, 0x41,
0x33, 0x41, 0x34, 0x41, 0x35, 0x41, 0x36, 0x41,
0x37, 0x41, 0x38, 0x41, 0x39, 0x41, 0x3A, 0x41,
0x3B, 0x41, 0x3C, 0x41, 0x3D, 0x41, 0x3E, 0x41,
// Bytes 40 - 7f
0x3F, 0x41, 0x40, 0x41, 0x41, 0x41, 0x42, 0x41,
0x43, 0x41, 0x44, 0x41, 0x45, 0x41, 0x46, 0x41,
0x47, 0x41, 0x48, 0x41, 0x49, 0x41, 0x4A, 0x41,
0x4B, 0x41, 0x4C, 0x41, 0x4D, 0x41, 0x4E, 0x41,
0x4F, 0x41, 0x50, 0x41, 0x51, 0x41, 0x52, 0x41,
0x53, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41,
0x57, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5A, 0x41,
0x5B, 0x41, 0x5C, 0x41, 0x5D, 0x41, 0x5E, 0x41,
// Bytes 80 - bf
0x5F, 0x41, 0x60, 0x41, 0x61, 0x41, 0x62, 0x41,
0x63, 0x41, 0x64, 0x41, 0x65, 0x41, 0x66, 0x41,
0x67, 0x41, 0x68, 0x41, 0x69, 0x41, 0x6A, 0x41,
0x6B, 0x41, 0x6C, 0x41, 0x6D, 0x41, 0x6E, 0x41,
0x6F, 0x41, 0x70, 0x41, 0x71, 0x41, 0x72, 0x41,
0x73, 0x41, 0x74, 0x41, 0x75, 0x41, 0x76, 0x41,
0x77, 0x41, 0x78, 0x41, 0x79, 0x41, 0x7A, 0x41,
0x7B, 0x41, 0x7C, 0x41, 0x7D, 0x41, 0x7E, 0x42,
// Bytes c0 - ff
0xC2, 0xA2, 0x42, 0xC2, 0xA3, 0x42, 0xC2, 0xA5,
0x42, 0xC2, 0xA6, 0x42, 0xC2, 0xAC, 0x42, 0xC2,
0xB7, 0x42, 0xC3, 0x86, 0x42, 0xC3, 0xA6, 0x42,
0xC3, 0xB0, 0x42, 0xC3, 0xB8, 0x42, 0xC4, 0xA6,
0x42, 0xC4, 0xA7, 0x42, 0xC4, 0xB1, 0x42, 0xC5,
0x8B, 0x42, 0xC5, 0x93, 0x42, 0xC6, 0x8E, 0x42,
0xC6, 0x90, 0x42, 0xC6, 0xAB, 0x42, 0xC7, 0x80,
0x42, 0xC7, 0x81, 0x42, 0xC7, 0x82, 0x42, 0xC8,
// Bytes 100 - 13f
0xA2, 0x42, 0xC8, 0xB7, 0x42, 0xC9, 0x90, 0x42,
0xC9, 0x91, 0x42, 0xC9, 0x92, 0x42, 0xC9, 0x93,
0x42, 0xC9, 0x94, 0x42, 0xC9, 0x95, 0x42, 0xC9,
0x96, 0x42, 0xC9, 0x97, 0x42, 0xC9, 0x98, 0x42,
0xC9, 0x99, 0x42, 0xC9, 0x9B, 0x42, 0xC9, 0x9C,
0x42, 0xC9, 0x9E, 0x42, 0xC9, 0x9F, 0x42, 0xC9,
0xA0, 0x42, 0xC9, 0xA1, 0x42, 0xC9, 0xA2, 0x42,
0xC9, 0xA3, 0x42, 0xC9, 0xA4, 0x42, 0xC9, 0xA5,
// Bytes 140 - 17f
0x42, 0xC9, 0xA6, 0x42, 0xC9, 0xA7, 0x42, 0xC9,
0xA8, 0x42, 0xC9, 0xA9, 0x42, 0xC9, 0xAA, 0x42,
0xC9, 0xAB, 0x42, 0xC9, 0xAC, 0x42, 0xC9, 0xAD,
0x42, 0xC9, 0xAE, 0x42, 0xC9, 0xAF, 0x42, 0xC9,
0xB0, 0x42, 0xC9, 0xB1, 0x42, 0xC9, 0xB2, 0x42,
0xC9, 0xB3, 0x42, 0xC9, 0xB4, 0x42, 0xC9, 0xB5,
0x42, 0xC9, 0xB6, 0x42, 0xC9, 0xB7, 0x42, 0xC9,
0xB8, 0x42, 0xC9, 0xB9, 0x42, 0xC9, 0xBA, 0x42,
// Bytes 180 - 1bf
0xC9, 0xBB, 0x42, 0xC9, 0xBD, 0x42, 0xC9, 0xBE,
0x42, 0xCA, 0x80, 0x42, 0xCA, 0x81, 0x42, 0xCA,
0x82, 0x42, 0xCA, 0x83, 0x42, 0xCA, 0x84, 0x42,
0xCA, 0x88, 0x42, 0xCA, 0x89, 0x42, 0xCA, 0x8A,
0x42, 0xCA, 0x8B, 0x42, 0xCA, 0x8C, 0x42, 0xCA,
0x8D, 0x42, 0xCA, 0x8E, 0x42, 0xCA, 0x8F, 0x42,
0xCA, 0x90, 0x42, 0xCA, 0x91, 0x42, 0xCA, 0x92,
0x42, 0xCA, 0x95, 0x42, 0xCA, 0x98, 0x42, 0xCA,
// Bytes 1c0 - 1ff
0x99, 0x42, 0xCA, 0x9B, 0x42, 0xCA, 0x9C, 0x42,
0xCA, 0x9D, 0x42, 0xCA, 0x9F, 0x42, 0xCA, 0xA1,
0x42, 0xCA, 0xA2, 0x42, 0xCA, 0xA3, 0x42, 0xCA,
0xA4, 0x42, 0xCA, 0xA5, 0x42, 0xCA, 0xA6, 0x42,
0xCA, 0xA7, 0x42, 0xCA, 0xA8, 0x42, 0xCA, 0xA9,
0x42, 0xCA, 0xAA, 0x42, 0xCA, 0xAB, 0x42, 0xCA,
0xB9, 0x42, 0xCB, 0x90, 0x42, 0xCB, 0x91, 0x42,
0xCE, 0x91, 0x42, 0xCE, 0x92, 0x42, 0xCE, 0x93,
// Bytes 200 - 23f
0x42, 0xCE, 0x94, 0x42, 0xCE, 0x95, 0x42, 0xCE,
0x96, 0x42, 0xCE, 0x97, 0x42, 0xCE, 0x98, 0x42,
0xCE, 0x99, 0x42, 0xCE, 0x9A, 0x42, 0xCE, 0x9B,
0x42, 0xCE, 0x9C, 0x42, 0xCE, 0x9D, 0x42, 0xCE,
0x9E, 0x42, 0xCE, 0x9F, 0x42, 0xCE, 0xA0, 0x42,
0xCE, 0xA1, 0x42, 0xCE, 0xA3, 0x42, 0xCE, 0xA4,
0x42, 0xCE, 0xA5, 0x42, 0xCE, 0xA6, 0x42, 0xCE,
0xA7, 0x42, 0xCE, 0xA8, 0x42, 0xCE, 0xA9, 0x42,
// Bytes 240 - 27f
0xCE, 0xB1, 0x42, 0xCE, 0xB2, 0x42, 0xCE, 0xB3,
0x42, 0xCE, 0xB4, 0x42, 0xCE, 0xB5, 0x42, 0xCE,
0xB6, 0x42, 0xCE, 0xB7, 0x42, 0xCE, 0xB8, 0x42,
0xCE, 0xB9, 0x42, 0xCE, 0xBA, 0x42, 0xCE, 0xBB,
0x42, 0xCE, 0xBC, 0x42, 0xCE, 0xBD, 0x42, 0xCE,
0xBE, 0x42, 0xCE, 0xBF, 0x42, 0xCF, 0x80, 0x42,
0xCF, 0x81, 0x42, 0xCF, 0x82, 0x42, 0xCF, 0x83,
0x42, 0xCF, 0x84, 0x42, 0xCF, 0x85, 0x42, 0xCF,
// Bytes 280 - 2bf
0x86, 0x42, 0xCF, 0x87, 0x42, 0xCF, 0x88, 0x42,
0xCF, 0x89, 0x42, 0xCF, 0x9C, 0x42, 0xCF, 0x9D,
0x42, 0xD0, 0xB0, 0x42, 0xD0, 0xB1, 0x42, 0xD0,
0xB2, 0x42, 0xD0, 0xB3, 0x42, 0xD0, 0xB4, 0x42,
0xD0, 0xB5, 0x42, 0xD0, 0xB6, 0x42, 0xD0, 0xB7,
0x42, 0xD0, 0xB8, 0x42, 0xD0, 0xBA, 0x42, 0xD0,
0xBB, 0x42, 0xD0, 0xBC, 0x42, 0xD0, 0xBD, 0x42,
0xD0, 0xBE, 0x42, 0xD0, 0xBF, 0x42, 0xD1, 0x80,
// Bytes 2c0 - 2ff
0x42, 0xD1, 0x81, 0x42, 0xD1, 0x82, 0x42, 0xD1,
0x83, 0x42, 0xD1, 0x84, 0x42, 0xD1, 0x85, 0x42,
0xD1, 0x86, 0x42, 0xD1, 0x87, 0x42, 0xD1, 0x88,
0x42, 0xD1, 0x8A, 0x42, 0xD1, 0x8B, 0x42, 0xD1,
0x8C, 0x42, 0xD1, 0x8D, 0x42, 0xD1, 0x8E, 0x42,
0xD1, 0x95, 0x42, 0xD1, 0x96, 0x42, 0xD1, 0x98,
0x42, 0xD1, 0x9F, 0x42, 0xD2, 0x91, 0x42, 0xD2,
0xAB, 0x42, 0xD2, 0xAF, 0x42, 0xD2, 0xB1, 0x42,
// Bytes 300 - 33f
0xD3, 0x8F, 0x42, 0xD3, 0x99, 0x42, 0xD3, 0xA9,
0x42, 0xD7, 0x90, 0x42, 0xD7, 0x91, 0x42, 0xD7,
0x92, 0x42, 0xD7, 0x93, 0x42, 0xD7, 0x94, 0x42,
0xD7, 0x9B, 0x42, 0xD7, 0x9C, 0x42, 0xD7, 0x9D,
0x42, 0xD7, 0xA2, 0x42, 0xD7, 0xA8, 0x42, 0xD7,
0xAA, 0x42, 0xD8, 0xA1, 0x42, 0xD8, 0xA7, 0x42,
0xD8, 0xA8, 0x42, 0xD8, 0xA9, 0x42, 0xD8, 0xAA,
0x42, 0xD8, 0xAB, 0x42, 0xD8, 0xAC, 0x42, 0xD8,
// Bytes 340 - 37f
0xAD, 0x42, 0xD8, 0xAE, 0x42, 0xD8, 0xAF, 0x42,
0xD8, 0xB0, 0x42, 0xD8, 0xB1, 0x42, 0xD8, 0xB2,
0x42, 0xD8, 0xB3, 0x42, 0xD8, 0xB4, 0x42, 0xD8,
0xB5, 0x42, 0xD8, 0xB6, 0x42, 0xD8, 0xB7, 0x42,
0xD8, 0xB8, 0x42, 0xD8, 0xB9, 0x42, 0xD8, 0xBA,
0x42, 0xD9, 0x81, 0x42, 0xD9, 0x82, 0x42, 0xD9,
0x83, 0x42, 0xD9, 0x84, 0x42, 0xD9, 0x85, 0x42,
0xD9, 0x86, 0x42, 0xD9, 0x87, 0x42, 0xD9, 0x88,
// Bytes 380 - 3bf
0x42, 0xD9, 0x89, 0x42, 0xD9, 0x8A, 0x42, 0xD9,
0xAE, 0x42, 0xD9, 0xAF, 0x42, 0xD9, 0xB1, 0x42,
0xD9, 0xB9, 0x42, 0xD9, 0xBA, 0x42, 0xD9, 0xBB,
0x42, 0xD9, 0xBE, 0x42, 0xD9, 0xBF, 0x42, 0xDA,
0x80, 0x42, 0xDA, 0x83, 0x42, 0xDA, 0x84, 0x42,
0xDA, 0x86, 0x42, 0xDA, 0x87, 0x42, 0xDA, 0x88,
0x42, 0xDA, 0x8C, 0x42, 0xDA, 0x8D, 0x42, 0xDA,
0x8E, 0x42, 0xDA, 0x91, 0x42, 0xDA, 0x98, 0x42,
// Bytes 3c0 - 3ff
0xDA, 0xA1, 0x42, 0xDA, 0xA4, 0x42, 0xDA, 0xA6,
0x42, 0xDA, 0xA9, 0x42, 0xDA, 0xAD, 0x42, 0xDA,
0xAF, 0x42, 0xDA, 0xB1, 0x42, 0xDA, 0xB3, 0x42,
0xDA, 0xBA, 0x42, 0xDA, 0xBB, 0x42, 0xDA, 0xBE,
0x42, 0xDB, 0x81, 0x42, 0xDB, 0x85, 0x42, 0xDB,
0x86, 0x42, 0xDB, 0x87, 0x42, 0xDB, 0x88, 0x42,
0xDB, 0x89, 0x42, 0xDB, 0x8B, 0x42, 0xDB, 0x8C,
0x42, 0xDB, 0x90, 0x42, 0xDB, 0x92, 0x43, 0xE0,
// Bytes 400 - 43f
0xBC, 0x8B, 0x43, 0xE1, 0x83, 0x9C, 0x43, 0xE1,
0x84, 0x80, 0x43, 0xE1, 0x84, 0x81, 0x43, 0xE1,
0x84, 0x82, 0x43, 0xE1, 0x84, 0x83, 0x43, 0xE1,
0x84, 0x84, 0x43, 0xE1, 0x84, 0x85, 0x43, 0xE1,
0x84, 0x86, 0x43, 0xE1, 0x84, 0x87, 0x43, 0xE1,
0x84, 0x88, 0x43, 0xE1, 0x84, 0x89, 0x43, 0xE1,
0x84, 0x8A, 0x43, 0xE1, 0x84, 0x8B, 0x43, 0xE1,
0x84, 0x8C, 0x43, 0xE1, 0x84, 0x8D, 0x43, 0xE1,
// Bytes 440 - 47f
0x84, 0x8E, 0x43, 0xE1, 0x84, 0x8F, 0x43, 0xE1,
0x84, 0x90, 0x43, 0xE1, 0x84, 0x91, 0x43, 0xE1,
0x84, 0x92, 0x43, 0xE1, 0x84, 0x94, 0x43, 0xE1,
0x84, 0x95, 0x43, 0xE1, 0x84, 0x9A, 0x43, 0xE1,
0x84, 0x9C, 0x43, 0xE1, 0x84, 0x9D, 0x43, 0xE1,
0x84, 0x9E, 0x43, 0xE1, 0x84, 0xA0, 0x43, 0xE1,
0x84, 0xA1, 0x43, 0xE1, 0x84, 0xA2, 0x43, 0xE1,
0x84, 0xA3, 0x43, 0xE1, 0x84, 0xA7, 0x43, 0xE1,
// Bytes 480 - 4bf
0x84, 0xA9, 0x43, 0xE1, 0x84, 0xAB, 0x43, 0xE1,
0x84, 0xAC, 0x43, 0xE1, 0x84, 0xAD, 0x43, 0xE1,
0x84, 0xAE, 0x43, 0xE1, 0x84, 0xAF, 0x43, 0xE1,
0x84, 0xB2, 0x43, 0xE1, 0x84, 0xB6, 0x43, 0xE1,
0x85, 0x80, 0x43, 0xE1, 0x85, 0x87, 0x43, 0xE1,
0x85, 0x8C, 0x43, 0xE1, 0x85, 0x97, 0x43, 0xE1,
0x85, 0x98, 0x43, 0xE1, 0x85, 0x99, 0x43, 0xE1,
0x85, 0xA0, 0x43, 0xE1, 0x86, 0x84, 0x43, 0xE1,
// Bytes 4c0 - 4ff
0x86, 0x85, 0x43, 0xE1, 0x86, 0x88, 0x43, 0xE1,
0x86, 0x91, 0x43, 0xE1, 0x86, 0x92, 0x43, 0xE1,
0x86, 0x94, 0x43, 0xE1, 0x86, 0x9E, 0x43, 0xE1,
0x86, 0xA1, 0x43, 0xE1, 0x87, 0x87, 0x43, 0xE1,
0x87, 0x88, 0x43, 0xE1, 0x87, 0x8C, 0x43, 0xE1,
0x87, 0x8E, 0x43, 0xE1, 0x87, 0x93, 0x43, 0xE1,
0x87, 0x97, 0x43, 0xE1, 0x87, 0x99, 0x43, 0xE1,
0x87, 0x9D, 0x43, 0xE1, 0x87, 0x9F, 0x43, 0xE1,
// Bytes 500 - 53f
0x87, 0xB1, 0x43, 0xE1, 0x87, 0xB2, 0x43, 0xE1,
0xB4, 0x82, 0x43, 0xE1, 0xB4, 0x96, 0x43, 0xE1,
0xB4, 0x97, 0x43, 0xE1, 0xB4, 0x9C, 0x43, 0xE1,
0xB4, 0x9D, 0x43, 0xE1, 0xB4, 0xA5, 0x43, 0xE1,
0xB5, 0xBB, 0x43, 0xE1, 0xB6, 0x85, 0x43, 0xE1,
0xB6, 0x91, 0x43, 0xE2, 0x80, 0x82, 0x43, 0xE2,
0x80, 0x83, 0x43, 0xE2, 0x80, 0x90, 0x43, 0xE2,
0x80, 0x93, 0x43, 0xE2, 0x80, 0x94, 0x43, 0xE2,
// Bytes 540 - 57f
0x82, 0xA9, 0x43, 0xE2, 0x86, 0x90, 0x43, 0xE2,
0x86, 0x91, 0x43, 0xE2, 0x86, 0x92, 0x43, 0xE2,
0x86, 0x93, 0x43, 0xE2, 0x88, 0x82, 0x43, 0xE2,
0x88, 0x87, 0x43, 0xE2, 0x88, 0x91, 0x43, 0xE2,
0x88, 0x92, 0x43, 0xE2, 0x94, 0x82, 0x43, 0xE2,
0x96, 0xA0, 0x43, 0xE2, 0x97, 0x8B, 0x43, 0xE2,
0xA6, 0x85, 0x43, 0xE2, 0xA6, 0x86, 0x43, 0xE2,
0xB1, 0xB1, 0x43, 0xE2, 0xB5, 0xA1, 0x43, 0xE3,
// Bytes 580 - 5bf
0x80, 0x81, 0x43, 0xE3, 0x80, 0x82, 0x43, 0xE3,
0x80, 0x88, 0x43, 0xE3, 0x80, 0x89, 0x43, 0xE3,
0x80, 0x8A, 0x43, 0xE3, 0x80, 0x8B, 0x43, 0xE3,
0x80, 0x8C, 0x43, 0xE3, 0x80, 0x8D, 0x43, 0xE3,
0x80, 0x8E, 0x43, 0xE3, 0x80, 0x8F, 0x43, 0xE3,
0x80, 0x90, 0x43, 0xE3, 0x80, 0x91, 0x43, 0xE3,
0x80, 0x92, 0x43, 0xE3, 0x80, 0x94, 0x43, 0xE3,
0x80, 0x95, 0x43, 0xE3, 0x80, 0x96, 0x43, 0xE3,
// Bytes 5c0 - 5ff
0x80, 0x97, 0x43, 0xE3, 0x82, 0xA1, 0x43, 0xE3,
0x82, 0xA2, 0x43, 0xE3, 0x82, 0xA3, 0x43, 0xE3,
0x82, 0xA4, 0x43, 0xE3, 0x82, 0xA5, 0x43, 0xE3,
0x82, 0xA6, 0x43, 0xE3, 0x82, 0xA7, 0x43, 0xE3,
0x82, 0xA8, 0x43, 0xE3, 0x82, 0xA9, 0x43, 0xE3,
0x82, 0xAA, 0x43, 0xE3, 0x82, 0xAB, 0x43, 0xE3,
0x82, 0xAD, 0x43, 0xE3, 0x82, 0xAF, 0x43, 0xE3,
0x82, 0xB1, 0x43, 0xE3, 0x82, 0xB3, 0x43, 0xE3,
// Bytes 600 - 63f
0x82, 0xB5, 0x43, 0xE3, 0x82, 0xB7, 0x43, 0xE3,
0x82, 0xB9, 0x43, 0xE3, 0x82, 0xBB, 0x43, 0xE3,
0x82, 0xBD, 0x43, 0xE3, 0x82, 0xBF, 0x43, 0xE3,
0x83, 0x81, 0x43, 0xE3, 0x83, 0x83, 0x43, 0xE3,
0x83, 0x84, 0x43, 0xE3, 0x83, 0x86, 0x43, 0xE3,
0x83, 0x88, 0x43, 0xE3, 0x83, 0x8A, 0x43, 0xE3,
0x83, 0x8B, 0x43, 0xE3, 0x83, 0x8C, 0x43, 0xE3,
0x83, 0x8D, 0x43, 0xE3, 0x83, 0x8E, 0x43, 0xE3,
// Bytes 640 - 67f
0x83, 0x8F, 0x43, 0xE3, 0x83, 0x92, 0x43, 0xE3,
0x83, 0x95, 0x43, 0xE3, 0x83, 0x98, 0x43, 0xE3,
0x83, 0x9B, 0x43, 0xE3, 0x83, 0x9E, 0x43, 0xE3,
0x83, 0x9F, 0x43, 0xE3, 0x83, 0xA0, 0x43, 0xE3,
0x83, 0xA1, 0x43, 0xE3, 0x83, 0xA2, 0x43, 0xE3,
0x83, 0xA3, 0x43, 0xE3, 0x83, 0xA4, 0x43, 0xE3,
0x83, 0xA5, 0x43, 0xE3, 0x83, 0xA6, 0x43, 0xE3,
0x83, 0xA7, 0x43, 0xE3, 0x83, 0xA8, 0x43, 0xE3,
// Bytes 680 - 6bf
0x83, 0xA9, 0x43, 0xE3, 0x83, 0xAA, 0x43, 0xE3,
0x83, 0xAB, 0x43, 0xE3, 0x83, 0xAC, 0x43, 0xE3,
0x83, 0xAD, 0x43, 0xE3, 0x83, 0xAF, 0x43, 0xE3,
0x83, 0xB0, 0x43, 0xE3, 0x83, 0xB1, 0x43, 0xE3,
0x83, 0xB2, 0x43, 0xE3, 0x83, 0xB3, 0x43, 0xE3,
0x83, 0xBB, 0x43, 0xE3, 0x83, 0xBC, 0x43, 0xE3,
0x92, 0x9E, 0x43, 0xE3, 0x92, 0xB9, 0x43, 0xE3,
0x92, 0xBB, 0x43, 0xE3, 0x93, 0x9F, 0x43, 0xE3,
// Bytes 6c0 - 6ff
0x94, 0x95, 0x43, 0xE3, 0x9B, 0xAE, 0x43, 0xE3,
0x9B, 0xBC, 0x43, 0xE3, 0x9E, 0x81, 0x43, 0xE3,
0xA0, 0xAF, 0x43, 0xE3, 0xA1, 0xA2, 0x43, 0xE3,
0xA1, 0xBC, 0x43, 0xE3, 0xA3, 0x87, 0x43, 0xE3,
0xA3, 0xA3, 0x43, 0xE3, 0xA4, 0x9C, 0x43, 0xE3,
0xA4, 0xBA, 0x43, 0xE3, 0xA8, 0xAE, 0x43, 0xE3,
0xA9, 0xAC, 0x43, 0xE3, 0xAB, 0xA4, 0x43, 0xE3,
0xAC, 0x88, 0x43, 0xE3, 0xAC, 0x99, 0x43, 0xE3,
// Bytes 700 - 73f
0xAD, 0x89, 0x43, 0xE3, 0xAE, 0x9D, 0x43, 0xE3,
0xB0, 0x98, 0x43, 0xE3, 0xB1, 0x8E, 0x43, 0xE3,
0xB4, 0xB3, 0x43, 0xE3, 0xB6, 0x96, 0x43, 0xE3,
0xBA, 0xAC, 0x43, 0xE3, 0xBA, 0xB8, 0x43, 0xE3,
0xBC, 0x9B, 0x43, 0xE3, 0xBF, 0xBC, 0x43, 0xE4,
0x80, 0x88, 0x43, 0xE4, 0x80, 0x98, 0x43, 0xE4,
0x80, 0xB9, 0x43, 0xE4, 0x81, 0x86, 0x43, 0xE4,
0x82, 0x96, 0x43, 0xE4, 0x83, 0xA3, 0x43, 0xE4,
// Bytes 740 - 77f
0x84, 0xAF, 0x43, 0xE4, 0x88, 0x82, 0x43, 0xE4,
0x88, 0xA7, 0x43, 0xE4, 0x8A, 0xA0, 0x43, 0xE4,
0x8C, 0x81, 0x43, 0xE4, 0x8C, 0xB4, 0x43, 0xE4,
0x8D, 0x99, 0x43, 0xE4, 0x8F, 0x95, 0x43, 0xE4,
0x8F, 0x99, 0x43, 0xE4, 0x90, 0x8B, 0x43, 0xE4,
0x91, 0xAB, 0x43, 0xE4, 0x94, 0xAB, 0x43, 0xE4,
0x95, 0x9D, 0x43, 0xE4, 0x95, 0xA1, 0x43, 0xE4,
0x95, 0xAB, 0x43, 0xE4, 0x97, 0x97, 0x43, 0xE4,
// Bytes 780 - 7bf
0x97, 0xB9, 0x43, 0xE4, 0x98, 0xB5, 0x43, 0xE4,
0x9A, 0xBE, 0x43, 0xE4, 0x9B, 0x87, 0x43, 0xE4,
0xA6, 0x95, 0x43, 0xE4, 0xA7, 0xA6, 0x43, 0xE4,
0xA9, 0xAE, 0x43, 0xE4, 0xA9, 0xB6, 0x43, 0xE4,
0xAA, 0xB2, 0x43, 0xE4, 0xAC, 0xB3, 0x43, 0xE4,
0xAF, 0x8E, 0x43, 0xE4, 0xB3, 0x8E, 0x43, 0xE4,
0xB3, 0xAD, 0x43, 0xE4, 0xB3, 0xB8, 0x43, 0xE4,
0xB5, 0x96, 0x43, 0xE4, 0xB8, 0x80, 0x43, 0xE4,
// Bytes 7c0 - 7ff
0xB8, 0x81, 0x43, 0xE4, 0xB8, 0x83, 0x43, 0xE4,
0xB8, 0x89, 0x43, 0xE4, 0xB8, 0x8A, 0x43, 0xE4,
0xB8, 0x8B, 0x43, 0xE4, 0xB8, 0x8D, 0x43, 0xE4,
0xB8, 0x99, 0x43, 0xE4, 0xB8, 0xA6, 0x43, 0xE4,
0xB8, 0xA8, 0x43, 0xE4, 0xB8, 0xAD, 0x43, 0xE4,
0xB8, 0xB2, 0x43, 0xE4, 0xB8, 0xB6, 0x43, 0xE4,
0xB8, 0xB8, 0x43, 0xE4, 0xB8, 0xB9, 0x43, 0xE4,
0xB8, 0xBD, 0x43, 0xE4, 0xB8, 0xBF, 0x43, 0xE4,
// Bytes 800 - 83f
0xB9, 0x81, 0x43, 0xE4, 0xB9, 0x99, 0x43, 0xE4,
0xB9, 0x9D, 0x43, 0xE4, 0xBA, 0x82, 0x43, 0xE4,
0xBA, 0x85, 0x43, 0xE4, 0xBA, 0x86, 0x43, 0xE4,
0xBA, 0x8C, 0x43, 0xE4, 0xBA, 0x94, 0x43, 0xE4,
0xBA, 0xA0, 0x43, 0xE4, 0xBA, 0xA4, 0x43, 0xE4,
0xBA, 0xAE, 0x43, 0xE4, 0xBA, 0xBA, 0x43, 0xE4,
0xBB, 0x80, 0x43, 0xE4, 0xBB, 0x8C, 0x43, 0xE4,
0xBB, 0xA4, 0x43, 0xE4, 0xBC, 0x81, 0x43, 0xE4,
// Bytes 840 - 87f
0xBC, 0x91, 0x43, 0xE4, 0xBD, 0xA0, 0x43, 0xE4,
0xBE, 0x80, 0x43, 0xE4, 0xBE, 0x86, 0x43, 0xE4,
0xBE, 0x8B, 0x43, 0xE4, 0xBE, 0xAE, 0x43, 0xE4,
0xBE, 0xBB, 0x43, 0xE4, 0xBE, 0xBF, 0x43, 0xE5,
0x80, 0x82, 0x43, 0xE5, 0x80, 0xAB, 0x43, 0xE5,
0x81, 0xBA, 0x43, 0xE5, 0x82, 0x99, 0x43, 0xE5,
0x83, 0x8F, 0x43, 0xE5, 0x83, 0x9A, 0x43, 0xE5,
0x83, 0xA7, 0x43, 0xE5, 0x84, 0xAA, 0x43, 0xE5,
// Bytes 880 - 8bf
0x84, 0xBF, 0x43, 0xE5, 0x85, 0x80, 0x43, 0xE5,
0x85, 0x85, 0x43, 0xE5, 0x85, 0x8D, 0x43, 0xE5,
0x85, 0x94, 0x43, 0xE5, 0x85, 0xA4, 0x43, 0xE5,
0x85, 0xA5, 0x43, 0xE5, 0x85, 0xA7, 0x43, 0xE5,
0x85, 0xA8, 0x43, 0xE5, 0x85, 0xA9, 0x43, 0xE5,
0x85, 0xAB, 0x43, 0xE5, 0x85, 0xAD, 0x43, 0xE5,
0x85, 0xB7, 0x43, 0xE5, 0x86, 0x80, 0x43, 0xE5,
0x86, 0x82, 0x43, 0xE5, 0x86, 0x8D, 0x43, 0xE5,
// Bytes 8c0 - 8ff
0x86, 0x92, 0x43, 0xE5, 0x86, 0x95, 0x43, 0xE5,
0x86, 0x96, 0x43, 0xE5, 0x86, 0x97, 0x43, 0xE5,
0x86, 0x99, 0x43, 0xE5, 0x86, 0xA4, 0x43, 0xE5,
0x86, 0xAB, 0x43, 0xE5, 0x86, 0xAC, 0x43, 0xE5,
0x86, 0xB5, 0x43, 0xE5, 0x86, 0xB7, 0x43, 0xE5,
0x87, 0x89, 0x43, 0xE5, 0x87, 0x8C, 0x43, 0xE5,
0x87, 0x9C, 0x43, 0xE5, 0x87, 0x9E, 0x43, 0xE5,
0x87, 0xA0, 0x43, 0xE5, 0x87, 0xB5, 0x43, 0xE5,
// Bytes 900 - 93f
0x88, 0x80, 0x43, 0xE5, 0x88, 0x83, 0x43, 0xE5,
0x88, 0x87, 0x43, 0xE5, 0x88, 0x97, 0x43, 0xE5,
0x88, 0x9D, 0x43, 0xE5, 0x88, 0xA9, 0x43, 0xE5,
0x88, 0xBA, 0x43, 0xE5, 0x88, 0xBB, 0x43, 0xE5,
0x89, 0x86, 0x43, 0xE5, 0x89, 0x8D, 0x43, 0xE5,
0x89, 0xB2, 0x43, 0xE5, 0x89, 0xB7, 0x43, 0xE5,
0x8A, 0x89, 0x43, 0xE5, 0x8A, 0x9B, 0x43, 0xE5,
0x8A, 0xA3, 0x43, 0xE5, 0x8A, 0xB3, 0x43, 0xE5,
// Bytes 940 - 97f
0x8A, 0xB4, 0x43, 0xE5, 0x8B, 0x87, 0x43, 0xE5,
0x8B, 0x89, 0x43, 0xE5, 0x8B, 0x92, 0x43, 0xE5,
0x8B, 0x9E, 0x43, 0xE5, 0x8B, 0xA4, 0x43, 0xE5,
0x8B, 0xB5, 0x43, 0xE5, 0x8B, 0xB9, 0x43, 0xE5,
0x8B, 0xBA, 0x43, 0xE5, 0x8C, 0x85, 0x43, 0xE5,
0x8C, 0x86, 0x43, 0xE5, 0x8C, 0x95, 0x43, 0xE5,
0x8C, 0x97, 0x43, 0xE5, 0x8C, 0x9A, 0x43, 0xE5,
0x8C, 0xB8, 0x43, 0xE5, 0x8C, 0xBB, 0x43, 0xE5,
// Bytes 980 - 9bf
0x8C, 0xBF, 0x43, 0xE5, 0x8D, 0x81, 0x43, 0xE5,
0x8D, 0x84, 0x43, 0xE5, 0x8D, 0x85, 0x43, 0xE5,
0x8D, 0x89, 0x43, 0xE5, 0x8D, 0x91, 0x43, 0xE5,
0x8D, 0x94, 0x43, 0xE5, 0x8D, 0x9A, 0x43, 0xE5,
0x8D, 0x9C, 0x43, 0xE5, 0x8D, 0xA9, 0x43, 0xE5,
0x8D, 0xB0, 0x43, 0xE5, 0x8D, 0xB3, 0x43, 0xE5,
0x8D, 0xB5, 0x43, 0xE5, 0x8D, 0xBD, 0x43, 0xE5,
0x8D, 0xBF, 0x43, 0xE5, 0x8E, 0x82, 0x43, 0xE5,
// Bytes 9c0 - 9ff
0x8E, 0xB6, 0x43, 0xE5, 0x8F, 0x83, 0x43, 0xE5,
0x8F, 0x88, 0x43, 0xE5, 0x8F, 0x8A, 0x43, 0xE5,
0x8F, 0x8C, 0x43, 0xE5, 0x8F, 0x9F, 0x43, 0xE5,
0x8F, 0xA3, 0x43, 0xE5, 0x8F, 0xA5, 0x43, 0xE5,
0x8F, 0xAB, 0x43, 0xE5, 0x8F, 0xAF, 0x43, 0xE5,
0x8F, 0xB1, 0x43, 0xE5, 0x8F, 0xB3, 0x43, 0xE5,
0x90, 0x86, 0x43, 0xE5, 0x90, 0x88, 0x43, 0xE5,
0x90, 0x8D, 0x43, 0xE5, 0x90, 0x8F, 0x43, 0xE5,
// Bytes a00 - a3f
0x90, 0x9D, 0x43, 0xE5, 0x90, 0xB8, 0x43, 0xE5,
0x90, 0xB9, 0x43, 0xE5, 0x91, 0x82, 0x43, 0xE5,
0x91, 0x88, 0x43, 0xE5, 0x91, 0xA8, 0x43, 0xE5,
0x92, 0x9E, 0x43, 0xE5, 0x92, 0xA2, 0x43, 0xE5,
0x92, 0xBD, 0x43, 0xE5, 0x93, 0xB6, 0x43, 0xE5,
0x94, 0x90, 0x43, 0xE5, 0x95, 0x8F, 0x43, 0xE5,
0x95, 0x93, 0x43, 0xE5, 0x95, 0x95, 0x43, 0xE5,
0x95, 0xA3, 0x43, 0xE5, 0x96, 0x84, 0x43, 0xE5,
// Bytes a40 - a7f
0x96, 0x87, 0x43, 0xE5, 0x96, 0x99, 0x43, 0xE5,
0x96, 0x9D, 0x43, 0xE5, 0x96, 0xAB, 0x43, 0xE5,
0x96, 0xB3, 0x43, 0xE5, 0x96, 0xB6, 0x43, 0xE5,
0x97, 0x80, 0x43, 0xE5, 0x97, 0x82, 0x43, 0xE5,
0x97, 0xA2, 0x43, 0xE5, 0x98, 0x86, 0x43, 0xE5,
0x99, 0x91, 0x43, 0xE5, 0x99, 0xA8, 0x43, 0xE5,
0x99, 0xB4, 0x43, 0xE5, 0x9B, 0x97, 0x43, 0xE5,
0x9B, 0x9B, 0x43, 0xE5, 0x9B, 0xB9, 0x43, 0xE5,
// Bytes a80 - abf
0x9C, 0x96, 0x43, 0xE5, 0x9C, 0x97, 0x43, 0xE5,
0x9C, 0x9F, 0x43, 0xE5, 0x9C, 0xB0, 0x43, 0xE5,
0x9E, 0x8B, 0x43, 0xE5, 0x9F, 0x8E, 0x43, 0xE5,
0x9F, 0xB4, 0x43, 0xE5, 0xA0, 0x8D, 0x43, 0xE5,
0xA0, 0xB1, 0x43, 0xE5, 0xA0, 0xB2, 0x43, 0xE5,
0xA1, 0x80, 0x43, 0xE5, 0xA1, 0x9A, 0x43, 0xE5,
0xA1, 0x9E, 0x43, 0xE5, 0xA2, 0xA8, 0x43, 0xE5,
0xA2, 0xAC, 0x43, 0xE5, 0xA2, 0xB3, 0x43, 0xE5,
// Bytes ac0 - aff
0xA3, 0x98, 0x43, 0xE5, 0xA3, 0x9F, 0x43, 0xE5,
0xA3, 0xAB, 0x43, 0xE5, 0xA3, 0xAE, 0x43, 0xE5,
0xA3, 0xB0, 0x43, 0xE5, 0xA3, 0xB2, 0x43, 0xE5,
0xA3, 0xB7, 0x43, 0xE5, 0xA4, 0x82, 0x43, 0xE5,
0xA4, 0x86, 0x43, 0xE5, 0xA4, 0x8A, 0x43, 0xE5,
0xA4, 0x95, 0x43, 0xE5, 0xA4, 0x9A, 0x43, 0xE5,
0xA4, 0x9C, 0x43, 0xE5, 0xA4, 0xA2, 0x43, 0xE5,
0xA4, 0xA7, 0x43, 0xE5, 0xA4, 0xA9, 0x43, 0xE5,
// Bytes b00 - b3f
0xA5, 0x84, 0x43, 0xE5, 0xA5, 0x88, 0x43, 0xE5,
0xA5, 0x91, 0x43, 0xE5, 0xA5, 0x94, 0x43, 0xE5,
0xA5, 0xA2, 0x43, 0xE5, 0xA5, 0xB3, 0x43, 0xE5,
0xA7, 0x98, 0x43, 0xE5, 0xA7, 0xAC, 0x43, 0xE5,
0xA8, 0x9B, 0x43, 0xE5, 0xA8, 0xA7, 0x43, 0xE5,
0xA9, 0xA2, 0x43, 0xE5, 0xA9, 0xA6, 0x43, 0xE5,
0xAA, 0xB5, 0x43, 0xE5, 0xAC, 0x88, 0x43, 0xE5,
0xAC, 0xA8, 0x43, 0xE5, 0xAC, 0xBE, 0x43, 0xE5,
// Bytes b40 - b7f
0xAD, 0x90, 0x43, 0xE5, 0xAD, 0x97, 0x43, 0xE5,
0xAD, 0xA6, 0x43, 0xE5, 0xAE, 0x80, 0x43, 0xE5,
0xAE, 0x85, 0x43, 0xE5, 0xAE, 0x97, 0x43, 0xE5,
0xAF, 0x83, 0x43, 0xE5, 0xAF, 0x98, 0x43, 0xE5,
0xAF, 0xA7, 0x43, 0xE5, 0xAF, 0xAE, 0x43, 0xE5,
0xAF, 0xB3, 0x43, 0xE5, 0xAF, 0xB8, 0x43, 0xE5,
0xAF, 0xBF, 0x43, 0xE5, 0xB0, 0x86, 0x43, 0xE5,
0xB0, 0x8F, 0x43, 0xE5, 0xB0, 0xA2, 0x43, 0xE5,
// Bytes b80 - bbf
0xB0, 0xB8, 0x43, 0xE5, 0xB0, 0xBF, 0x43, 0xE5,
0xB1, 0xA0, 0x43, 0xE5, 0xB1, 0xA2, 0x43, 0xE5,
0xB1, 0xA4, 0x43, 0xE5, 0xB1, 0xA5, 0x43, 0xE5,
0xB1, 0xAE, 0x43, 0xE5, 0xB1, 0xB1, 0x43, 0xE5,
0xB2, 0x8D, 0x43, 0xE5, 0xB3, 0x80, 0x43, 0xE5,
0xB4, 0x99, 0x43, 0xE5, 0xB5, 0x83, 0x43, 0xE5,
0xB5, 0x90, 0x43, 0xE5, 0xB5, 0xAB, 0x43, 0xE5,
0xB5, 0xAE, 0x43, 0xE5, 0xB5, 0xBC, 0x43, 0xE5,
// Bytes bc0 - bff
0xB6, 0xB2, 0x43, 0xE5, 0xB6, 0xBA, 0x43, 0xE5,
0xB7, 0x9B, 0x43, 0xE5, 0xB7, 0xA1, 0x43, 0xE5,
0xB7, 0xA2, 0x43, 0xE5, 0xB7, 0xA5, 0x43, 0xE5,
0xB7, 0xA6, 0x43, 0xE5, 0xB7, 0xB1, 0x43, 0xE5,
0xB7, 0xBD, 0x43, 0xE5, 0xB7, 0xBE, 0x43, 0xE5,
0xB8, 0xA8, 0x43, 0xE5, 0xB8, 0xBD, 0x43, 0xE5,
0xB9, 0xA9, 0x43, 0xE5, 0xB9, 0xB2, 0x43, 0xE5,
0xB9, 0xB4, 0x43, 0xE5, 0xB9, 0xBA, 0x43, 0xE5,
// Bytes c00 - c3f
0xB9, 0xBC, 0x43, 0xE5, 0xB9, 0xBF, 0x43, 0xE5,
0xBA, 0xA6, 0x43, 0xE5, 0xBA, 0xB0, 0x43, 0xE5,
0xBA, 0xB3, 0x43, 0xE5, 0xBA, 0xB6, 0x43, 0xE5,
0xBB, 0x89, 0x43, 0xE5, 0xBB, 0x8A, 0x43, 0xE5,
0xBB, 0x92, 0x43, 0xE5, 0xBB, 0x93, 0x43, 0xE5,
0xBB, 0x99, 0x43, 0xE5, 0xBB, 0xAC, 0x43, 0xE5,
0xBB, 0xB4, 0x43, 0xE5, 0xBB, 0xBE, 0x43, 0xE5,
0xBC, 0x84, 0x43, 0xE5, 0xBC, 0x8B, 0x43, 0xE5,
// Bytes c40 - c7f
0xBC, 0x93, 0x43, 0xE5, 0xBC, 0xA2, 0x43, 0xE5,
0xBD, 0x90, 0x43, 0xE5, 0xBD, 0x93, 0x43, 0xE5,
0xBD, 0xA1, 0x43, 0xE5, 0xBD, 0xA2, 0x43, 0xE5,
0xBD, 0xA9, 0x43, 0xE5, 0xBD, 0xAB, 0x43, 0xE5,
0xBD, 0xB3, 0x43, 0xE5, 0xBE, 0x8B, 0x43, 0xE5,
0xBE, 0x8C, 0x43, 0xE5, 0xBE, 0x97, 0x43, 0xE5,
0xBE, 0x9A, 0x43, 0xE5, 0xBE, 0xA9, 0x43, 0xE5,
0xBE, 0xAD, 0x43, 0xE5, 0xBF, 0x83, 0x43, 0xE5,
// Bytes c80 - cbf
0xBF, 0x8D, 0x43, 0xE5, 0xBF, 0x97, 0x43, 0xE5,
0xBF, 0xB5, 0x43, 0xE5, 0xBF, 0xB9, 0x43, 0xE6,
0x80, 0x92, 0x43, 0xE6, 0x80, 0x9C, 0x43, 0xE6,
0x81, 0xB5, 0x43, 0xE6, 0x82, 0x81, 0x43, 0xE6,
0x82, 0x94, 0x43, 0xE6, 0x83, 0x87, 0x43, 0xE6,
0x83, 0x98, 0x43, 0xE6, 0x83, 0xA1, 0x43, 0xE6,
0x84, 0x88, 0x43, 0xE6, 0x85, 0x84, 0x43, 0xE6,
0x85, 0x88, 0x43, 0xE6, 0x85, 0x8C, 0x43, 0xE6,
// Bytes cc0 - cff
0x85, 0x8E, 0x43, 0xE6, 0x85, 0xA0, 0x43, 0xE6,
0x85, 0xA8, 0x43, 0xE6, 0x85, 0xBA, 0x43, 0xE6,
0x86, 0x8E, 0x43, 0xE6, 0x86, 0x90, 0x43, 0xE6,
0x86, 0xA4, 0x43, 0xE6, 0x86, 0xAF, 0x43, 0xE6,
0x86, 0xB2, 0x43, 0xE6, 0x87, 0x9E, 0x43, 0xE6,
0x87, 0xB2, 0x43, 0xE6, 0x87, 0xB6, 0x43, 0xE6,
0x88, 0x80, 0x43, 0xE6, 0x88, 0x88, 0x43, 0xE6,
0x88, 0x90, 0x43, 0xE6, 0x88, 0x9B, 0x43, 0xE6,
// Bytes d00 - d3f
0x88, 0xAE, 0x43, 0xE6, 0x88, 0xB4, 0x43, 0xE6,
0x88, 0xB6, 0x43, 0xE6, 0x89, 0x8B, 0x43, 0xE6,
0x89, 0x93, 0x43, 0xE6, 0x89, 0x9D, 0x43, 0xE6,
0x8A, 0x95, 0x43, 0xE6, 0x8A, 0xB1, 0x43, 0xE6,
0x8B, 0x89, 0x43, 0xE6, 0x8B, 0x8F, 0x43, 0xE6,
0x8B, 0x93, 0x43, 0xE6, 0x8B, 0x94, 0x43, 0xE6,
0x8B, 0xBC, 0x43, 0xE6, 0x8B, 0xBE, 0x43, 0xE6,
0x8C, 0x87, 0x43, 0xE6, 0x8C, 0xBD, 0x43, 0xE6,
// Bytes d40 - d7f
0x8D, 0x90, 0x43, 0xE6, 0x8D, 0x95, 0x43, 0xE6,
0x8D, 0xA8, 0x43, 0xE6, 0x8D, 0xBB, 0x43, 0xE6,
0x8E, 0x83, 0x43, 0xE6, 0x8E, 0xA0, 0x43, 0xE6,
0x8E, 0xA9, 0x43, 0xE6, 0x8F, 0x84, 0x43, 0xE6,
0x8F, 0x85, 0x43, 0xE6, 0x8F, 0xA4, 0x43, 0xE6,
0x90, 0x9C, 0x43, 0xE6, 0x90, 0xA2, 0x43, 0xE6,
0x91, 0x92, 0x43, 0xE6, 0x91, 0xA9, 0x43, 0xE6,
0x91, 0xB7, 0x43, 0xE6, 0x91, 0xBE, 0x43, 0xE6,
// Bytes d80 - dbf
0x92, 0x9A, 0x43, 0xE6, 0x92, 0x9D, 0x43, 0xE6,
0x93, 0x84, 0x43, 0xE6, 0x94, 0xAF, 0x43, 0xE6,
0x94, 0xB4, 0x43, 0xE6, 0x95, 0x8F, 0x43, 0xE6,
0x95, 0x96, 0x43, 0xE6, 0x95, 0xAC, 0x43, 0xE6,
0x95, 0xB8, 0x43, 0xE6, 0x96, 0x87, 0x43, 0xE6,
0x96, 0x97, 0x43, 0xE6, 0x96, 0x99, 0x43, 0xE6,
0x96, 0xA4, 0x43, 0xE6, 0x96, 0xB0, 0x43, 0xE6,
0x96, 0xB9, 0x43, 0xE6, 0x97, 0x85, 0x43, 0xE6,
// Bytes dc0 - dff
0x97, 0xA0, 0x43, 0xE6, 0x97, 0xA2, 0x43, 0xE6,
0x97, 0xA3, 0x43, 0xE6, 0x97, 0xA5, 0x43, 0xE6,
0x98, 0x93, 0x43, 0xE6, 0x98, 0xA0, 0x43, 0xE6,
0x99, 0x89, 0x43, 0xE6, 0x99, 0xB4, 0x43, 0xE6,
0x9A, 0x88, 0x43, 0xE6, 0x9A, 0x91, 0x43, 0xE6,
0x9A, 0x9C, 0x43, 0xE6, 0x9A, 0xB4, 0x43, 0xE6,
0x9B, 0x86, 0x43, 0xE6, 0x9B, 0xB0, 0x43, 0xE6,
0x9B, 0xB4, 0x43, 0xE6, 0x9B, 0xB8, 0x43, 0xE6,
// Bytes e00 - e3f
0x9C, 0x80, 0x43, 0xE6, 0x9C, 0x88, 0x43, 0xE6,
0x9C, 0x89, 0x43, 0xE6, 0x9C, 0x97, 0x43, 0xE6,
0x9C, 0x9B, 0x43, 0xE6, 0x9C, 0xA1, 0x43, 0xE6,
0x9C, 0xA8, 0x43, 0xE6, 0x9D, 0x8E, 0x43, 0xE6,
0x9D, 0x93, 0x43, 0xE6, 0x9D, 0x96, 0x43, 0xE6,
0x9D, 0x9E, 0x43, 0xE6, 0x9D, 0xBB, 0x43, 0xE6,
0x9E, 0x85, 0x43, 0xE6, 0x9E, 0x97, 0x43, 0xE6,
0x9F, 0xB3, 0x43, 0xE6, 0x9F, 0xBA, 0x43, 0xE6,
// Bytes e40 - e7f
0xA0, 0x97, 0x43, 0xE6, 0xA0, 0x9F, 0x43, 0xE6,
0xA0, 0xAA, 0x43, 0xE6, 0xA1, 0x92, 0x43, 0xE6,
0xA2, 0x81, 0x43, 0xE6, 0xA2, 0x85, 0x43, 0xE6,
0xA2, 0x8E, 0x43, 0xE6, 0xA2, 0xA8, 0x43, 0xE6,
0xA4, 0x94, 0x43, 0xE6, 0xA5, 0x82, 0x43, 0xE6,
0xA6, 0xA3, 0x43, 0xE6, 0xA7, 0xAA, 0x43, 0xE6,
0xA8, 0x82, 0x43, 0xE6, 0xA8, 0x93, 0x43, 0xE6,
0xAA, 0xA8, 0x43, 0xE6, 0xAB, 0x93, 0x43, 0xE6,
// Bytes e80 - ebf
0xAB, 0x9B, 0x43, 0xE6, 0xAC, 0x84, 0x43, 0xE6,
0xAC, 0xA0, 0x43, 0xE6, 0xAC, 0xA1, 0x43, 0xE6,
0xAD, 0x94, 0x43, 0xE6, 0xAD, 0xA2, 0x43, 0xE6,
0xAD, 0xA3, 0x43, 0xE6, 0xAD, 0xB2, 0x43, 0xE6,
0xAD, 0xB7, 0x43, 0xE6, 0xAD, 0xB9, 0x43, 0xE6,
0xAE, 0x9F, 0x43, 0xE6, 0xAE, 0xAE, 0x43, 0xE6,
0xAE, 0xB3, 0x43, 0xE6, 0xAE, 0xBA, 0x43, 0xE6,
0xAE, 0xBB, 0x43, 0xE6, 0xAF, 0x8B, 0x43, 0xE6,
// Bytes ec0 - eff
0xAF, 0x8D, 0x43, 0xE6, 0xAF, 0x94, 0x43, 0xE6,
0xAF, 0x9B, 0x43, 0xE6, 0xB0, 0x8F, 0x43, 0xE6,
0xB0, 0x94, 0x43, 0xE6, 0xB0, 0xB4, 0x43, 0xE6,
0xB1, 0x8E, 0x43, 0xE6, 0xB1, 0xA7, 0x43, 0xE6,
0xB2, 0x88, 0x43, 0xE6, 0xB2, 0xBF, 0x43, 0xE6,
0xB3, 0x8C, 0x43, 0xE6, 0xB3, 0x8D, 0x43, 0xE6,
0xB3, 0xA5, 0x43, 0xE6, 0xB3, 0xA8, 0x43, 0xE6,
0xB4, 0x96, 0x43, 0xE6, 0xB4, 0x9B, 0x43, 0xE6,
// Bytes f00 - f3f
0xB4, 0x9E, 0x43, 0xE6, 0xB4, 0xB4, 0x43, 0xE6,
0xB4, 0xBE, 0x43, 0xE6, 0xB5, 0x81, 0x43, 0xE6,
0xB5, 0xA9, 0x43, 0xE6, 0xB5, 0xAA, 0x43, 0xE6,
0xB5, 0xB7, 0x43, 0xE6, 0xB5, 0xB8, 0x43, 0xE6,
0xB6, 0x85, 0x43, 0xE6, 0xB7, 0x8B, 0x43, 0xE6,
0xB7, 0x9A, 0x43, 0xE6, 0xB7, 0xAA, 0x43, 0xE6,
0xB7, 0xB9, 0x43, 0xE6, 0xB8, 0x9A, 0x43, 0xE6,
0xB8, 0xAF, 0x43, 0xE6, 0xB9, 0xAE, 0x43, 0xE6,
// Bytes f40 - f7f
0xBA, 0x80, 0x43, 0xE6, 0xBA, 0x9C, 0x43, 0xE6,
0xBA, 0xBA, 0x43, 0xE6, 0xBB, 0x87, 0x43, 0xE6,
0xBB, 0x8B, 0x43, 0xE6, 0xBB, 0x91, 0x43, 0xE6,
0xBB, 0x9B, 0x43, 0xE6, 0xBC, 0x8F, 0x43, 0xE6,
0xBC, 0x94, 0x43, 0xE6, 0xBC, 0xA2, 0x43, 0xE6,
0xBC, 0xA3, 0x43, 0xE6, 0xBD, 0xAE, 0x43, 0xE6,
0xBF, 0x86, 0x43, 0xE6, 0xBF, 0xAB, 0x43, 0xE6,
0xBF, 0xBE, 0x43, 0xE7, 0x80, 0x9B, 0x43, 0xE7,
// Bytes f80 - fbf
0x80, 0x9E, 0x43, 0xE7, 0x80, 0xB9, 0x43, 0xE7,
0x81, 0x8A, 0x43, 0xE7, 0x81, 0xAB, 0x43, 0xE7,
0x81, 0xB0, 0x43, 0xE7, 0x81, 0xB7, 0x43, 0xE7,
0x81, 0xBD, 0x43, 0xE7, 0x82, 0x99, 0x43, 0xE7,
0x82, 0xAD, 0x43, 0xE7, 0x83, 0x88, 0x43, 0xE7,
0x83, 0x99, 0x43, 0xE7, 0x84, 0xA1, 0x43, 0xE7,
0x85, 0x85, 0x43, 0xE7, 0x85, 0x89, 0x43, 0xE7,
0x85, 0xAE, 0x43, 0xE7, 0x86, 0x9C, 0x43, 0xE7,
// Bytes fc0 - fff
0x87, 0x8E, 0x43, 0xE7, 0x87, 0x90, 0x43, 0xE7,
0x88, 0x90, 0x43, 0xE7, 0x88, 0x9B, 0x43, 0xE7,
0x88, 0xA8, 0x43, 0xE7, 0x88, 0xAA, 0x43, 0xE7,
0x88, 0xAB, 0x43, 0xE7, 0x88, 0xB5, 0x43, 0xE7,
0x88, 0xB6, 0x43, 0xE7, 0x88, 0xBB, 0x43, 0xE7,
0x88, 0xBF, 0x43, 0xE7, 0x89, 0x87, 0x43, 0xE7,
0x89, 0x90, 0x43, 0xE7, 0x89, 0x99, 0x43, 0xE7,
0x89, 0x9B, 0x43, 0xE7, 0x89, 0xA2, 0x43, 0xE7,
// Bytes 1000 - 103f
0x89, 0xB9, 0x43, 0xE7, 0x8A, 0x80, 0x43, 0xE7,
0x8A, 0x95, 0x43, 0xE7, 0x8A, 0xAC, 0x43, 0xE7,
0x8A, 0xAF, 0x43, 0xE7, 0x8B, 0x80, 0x43, 0xE7,
0x8B, 0xBC, 0x43, 0xE7, 0x8C, 0xAA, 0x43, 0xE7,
0x8D, 0xB5, 0x43, 0xE7, 0x8D, 0xBA, 0x43, 0xE7,
0x8E, 0x84, 0x43, 0xE7, 0x8E, 0x87, 0x43, 0xE7,
0x8E, 0x89, 0x43, 0xE7, 0x8E, 0x8B, 0x43, 0xE7,
0x8E, 0xA5, 0x43, 0xE7, 0x8E, 0xB2, 0x43, 0xE7,
// Bytes 1040 - 107f
0x8F, 0x9E, 0x43, 0xE7, 0x90, 0x86, 0x43, 0xE7,
0x90, 0x89, 0x43, 0xE7, 0x90, 0xA2, 0x43, 0xE7,
0x91, 0x87, 0x43, 0xE7, 0x91, 0x9C, 0x43, 0xE7,
0x91, 0xA9, 0x43, 0xE7, 0x91, 0xB1, 0x43, 0xE7,
0x92, 0x85, 0x43, 0xE7, 0x92, 0x89, 0x43, 0xE7,
0x92, 0x98, 0x43, 0xE7, 0x93, 0x8A, 0x43, 0xE7,
0x93, 0x9C, 0x43, 0xE7, 0x93, 0xA6, 0x43, 0xE7,
0x94, 0x86, 0x43, 0xE7, 0x94, 0x98, 0x43, 0xE7,
// Bytes 1080 - 10bf
0x94, 0x9F, 0x43, 0xE7, 0x94, 0xA4, 0x43, 0xE7,
0x94, 0xA8, 0x43, 0xE7, 0x94, 0xB0, 0x43, 0xE7,
0x94, 0xB2, 0x43, 0xE7, 0x94, 0xB3, 0x43, 0xE7,
0x94, 0xB7, 0x43, 0xE7, 0x94, 0xBB, 0x43, 0xE7,
0x94, 0xBE, 0x43, 0xE7, 0x95, 0x99, 0x43, 0xE7,
0x95, 0xA5, 0x43, 0xE7, 0x95, 0xB0, 0x43, 0xE7,
0x96, 0x8B, 0x43, 0xE7, 0x96, 0x92, 0x43, 0xE7,
0x97, 0xA2, 0x43, 0xE7, 0x98, 0x90, 0x43, 0xE7,
// Bytes 10c0 - 10ff
0x98, 0x9D, 0x43, 0xE7, 0x98, 0x9F, 0x43, 0xE7,
0x99, 0x82, 0x43, 0xE7, 0x99, 0xA9, 0x43, 0xE7,
0x99, 0xB6, 0x43, 0xE7, 0x99, 0xBD, 0x43, 0xE7,
0x9A, 0xAE, 0x43, 0xE7, 0x9A, 0xBF, 0x43, 0xE7,
0x9B, 0x8A, 0x43, 0xE7, 0x9B, 0x9B, 0x43, 0xE7,
0x9B, 0xA3, 0x43, 0xE7, 0x9B, 0xA7, 0x43, 0xE7,
0x9B, 0xAE, 0x43, 0xE7, 0x9B, 0xB4, 0x43, 0xE7,
0x9C, 0x81, 0x43, 0xE7, 0x9C, 0x9E, 0x43, 0xE7,
// Bytes 1100 - 113f
0x9C, 0x9F, 0x43, 0xE7, 0x9D, 0x80, 0x43, 0xE7,
0x9D, 0x8A, 0x43, 0xE7, 0x9E, 0x8B, 0x43, 0xE7,
0x9E, 0xA7, 0x43, 0xE7, 0x9F, 0x9B, 0x43, 0xE7,
0x9F, 0xA2, 0x43, 0xE7, 0x9F, 0xB3, 0x43, 0xE7,
0xA1, 0x8E, 0x43, 0xE7, 0xA1, 0xAB, 0x43, 0xE7,
0xA2, 0x8C, 0x43, 0xE7, 0xA2, 0x91, 0x43, 0xE7,
0xA3, 0x8A, 0x43, 0xE7, 0xA3, 0x8C, 0x43, 0xE7,
0xA3, 0xBB, 0x43, 0xE7, 0xA4, 0xAA, 0x43, 0xE7,
// Bytes 1140 - 117f
0xA4, 0xBA, 0x43, 0xE7, 0xA4, 0xBC, 0x43, 0xE7,
0xA4, 0xBE, 0x43, 0xE7, 0xA5, 0x88, 0x43, 0xE7,
0xA5, 0x89, 0x43, 0xE7, 0xA5, 0x90, 0x43, 0xE7,
0xA5, 0x96, 0x43, 0xE7, 0xA5, 0x9D, 0x43, 0xE7,
0xA5, 0x9E, 0x43, 0xE7, 0xA5, 0xA5, 0x43, 0xE7,
0xA5, 0xBF, 0x43, 0xE7, 0xA6, 0x81, 0x43, 0xE7,
0xA6, 0x8D, 0x43, 0xE7, 0xA6, 0x8E, 0x43, 0xE7,
0xA6, 0x8F, 0x43, 0xE7, 0xA6, 0xAE, 0x43, 0xE7,
// Bytes 1180 - 11bf
0xA6, 0xB8, 0x43, 0xE7, 0xA6, 0xBE, 0x43, 0xE7,
0xA7, 0x8A, 0x43, 0xE7, 0xA7, 0x98, 0x43, 0xE7,
0xA7, 0xAB, 0x43, 0xE7, 0xA8, 0x9C, 0x43, 0xE7,
0xA9, 0x80, 0x43, 0xE7, 0xA9, 0x8A, 0x43, 0xE7,
0xA9, 0x8F, 0x43, 0xE7, 0xA9, 0xB4, 0x43, 0xE7,
0xA9, 0xBA, 0x43, 0xE7, 0xAA, 0x81, 0x43, 0xE7,
0xAA, 0xB1, 0x43, 0xE7, 0xAB, 0x8B, 0x43, 0xE7,
0xAB, 0xAE, 0x43, 0xE7, 0xAB, 0xB9, 0x43, 0xE7,
// Bytes 11c0 - 11ff
0xAC, 0xA0, 0x43, 0xE7, 0xAE, 0x8F, 0x43, 0xE7,
0xAF, 0x80, 0x43, 0xE7, 0xAF, 0x86, 0x43, 0xE7,
0xAF, 0x89, 0x43, 0xE7, 0xB0, 0xBE, 0x43, 0xE7,
0xB1, 0xA0, 0x43, 0xE7, 0xB1, 0xB3, 0x43, 0xE7,
0xB1, 0xBB, 0x43, 0xE7, 0xB2, 0x92, 0x43, 0xE7,
0xB2, 0xBE, 0x43, 0xE7, 0xB3, 0x92, 0x43, 0xE7,
0xB3, 0x96, 0x43, 0xE7, 0xB3, 0xA3, 0x43, 0xE7,
0xB3, 0xA7, 0x43, 0xE7, 0xB3, 0xA8, 0x43, 0xE7,
// Bytes 1200 - 123f
0xB3, 0xB8, 0x43, 0xE7, 0xB4, 0x80, 0x43, 0xE7,
0xB4, 0x90, 0x43, 0xE7, 0xB4, 0xA2, 0x43, 0xE7,
0xB4, 0xAF, 0x43, 0xE7, 0xB5, 0x82, 0x43, 0xE7,
0xB5, 0x9B, 0x43, 0xE7, 0xB5, 0xA3, 0x43, 0xE7,
0xB6, 0xA0, 0x43, 0xE7, 0xB6, 0xBE, 0x43, 0xE7,
0xB7, 0x87, 0x43, 0xE7, 0xB7, 0xB4, 0x43, 0xE7,
0xB8, 0x82, 0x43, 0xE7, 0xB8, 0x89, 0x43, 0xE7,
0xB8, 0xB7, 0x43, 0xE7, 0xB9, 0x81, 0x43, 0xE7,
// Bytes 1240 - 127f
0xB9, 0x85, 0x43, 0xE7, 0xBC, 0xB6, 0x43, 0xE7,
0xBC, 0xBE, 0x43, 0xE7, 0xBD, 0x91, 0x43, 0xE7,
0xBD, 0xB2, 0x43, 0xE7, 0xBD, 0xB9, 0x43, 0xE7,
0xBD, 0xBA, 0x43, 0xE7, 0xBE, 0x85, 0x43, 0xE7,
0xBE, 0x8A, 0x43, 0xE7, 0xBE, 0x95, 0x43, 0xE7,
0xBE, 0x9A, 0x43, 0xE7, 0xBE, 0xBD, 0x43, 0xE7,
0xBF, 0xBA, 0x43, 0xE8, 0x80, 0x81, 0x43, 0xE8,
0x80, 0x85, 0x43, 0xE8, 0x80, 0x8C, 0x43, 0xE8,
// Bytes 1280 - 12bf
0x80, 0x92, 0x43, 0xE8, 0x80, 0xB3, 0x43, 0xE8,
0x81, 0x86, 0x43, 0xE8, 0x81, 0xA0, 0x43, 0xE8,
0x81, 0xAF, 0x43, 0xE8, 0x81, 0xB0, 0x43, 0xE8,
0x81, 0xBE, 0x43, 0xE8, 0x81, 0xBF, 0x43, 0xE8,
0x82, 0x89, 0x43, 0xE8, 0x82, 0x8B, 0x43, 0xE8,
0x82, 0xAD, 0x43, 0xE8, 0x82, 0xB2, 0x43, 0xE8,
0x84, 0x83, 0x43, 0xE8, 0x84, 0xBE, 0x43, 0xE8,
0x87, 0x98, 0x43, 0xE8, 0x87, 0xA3, 0x43, 0xE8,
// Bytes 12c0 - 12ff
0x87, 0xA8, 0x43, 0xE8, 0x87, 0xAA, 0x43, 0xE8,
0x87, 0xAD, 0x43, 0xE8, 0x87, 0xB3, 0x43, 0xE8,
0x87, 0xBC, 0x43, 0xE8, 0x88, 0x81, 0x43, 0xE8,
0x88, 0x84, 0x43, 0xE8, 0x88, 0x8C, 0x43, 0xE8,
0x88, 0x98, 0x43, 0xE8, 0x88, 0x9B, 0x43, 0xE8,
0x88, 0x9F, 0x43, 0xE8, 0x89, 0xAE, 0x43, 0xE8,
0x89, 0xAF, 0x43, 0xE8, 0x89, 0xB2, 0x43, 0xE8,
0x89, 0xB8, 0x43, 0xE8, 0x89, 0xB9, 0x43, 0xE8,
// Bytes 1300 - 133f
0x8A, 0x8B, 0x43, 0xE8, 0x8A, 0x91, 0x43, 0xE8,
0x8A, 0x9D, 0x43, 0xE8, 0x8A, 0xB1, 0x43, 0xE8,
0x8A, 0xB3, 0x43, 0xE8, 0x8A, 0xBD, 0x43, 0xE8,
0x8B, 0xA5, 0x43, 0xE8, 0x8B, 0xA6, 0x43, 0xE8,
0x8C, 0x9D, 0x43, 0xE8, 0x8C, 0xA3, 0x43, 0xE8,
0x8C, 0xB6, 0x43, 0xE8, 0x8D, 0x92, 0x43, 0xE8,
0x8D, 0x93, 0x43, 0xE8, 0x8D, 0xA3, 0x43, 0xE8,
0x8E, 0xAD, 0x43, 0xE8, 0x8E, 0xBD, 0x43, 0xE8,
// Bytes 1340 - 137f
0x8F, 0x89, 0x43, 0xE8, 0x8F, 0x8A, 0x43, 0xE8,
0x8F, 0x8C, 0x43, 0xE8, 0x8F, 0x9C, 0x43, 0xE8,
0x8F, 0xA7, 0x43, 0xE8, 0x8F, 0xAF, 0x43, 0xE8,
0x8F, 0xB1, 0x43, 0xE8, 0x90, 0xBD, 0x43, 0xE8,
0x91, 0x89, 0x43, 0xE8, 0x91, 0x97, 0x43, 0xE8,
0x93, 0xAE, 0x43, 0xE8, 0x93, 0xB1, 0x43, 0xE8,
0x93, 0xB3, 0x43, 0xE8, 0x93, 0xBC, 0x43, 0xE8,
0x94, 0x96, 0x43, 0xE8, 0x95, 0xA4, 0x43, 0xE8,
// Bytes 1380 - 13bf
0x97, 0x8D, 0x43, 0xE8, 0x97, 0xBA, 0x43, 0xE8,
0x98, 0x86, 0x43, 0xE8, 0x98, 0x92, 0x43, 0xE8,
0x98, 0xAD, 0x43, 0xE8, 0x98, 0xBF, 0x43, 0xE8,
0x99, 0x8D, 0x43, 0xE8, 0x99, 0x90, 0x43, 0xE8,
0x99, 0x9C, 0x43, 0xE8, 0x99, 0xA7, 0x43, 0xE8,
0x99, 0xA9, 0x43, 0xE8, 0x99, 0xAB, 0x43, 0xE8,
0x9A, 0x88, 0x43, 0xE8, 0x9A, 0xA9, 0x43, 0xE8,
0x9B, 0xA2, 0x43, 0xE8, 0x9C, 0x8E, 0x43, 0xE8,
// Bytes 13c0 - 13ff
0x9C, 0xA8, 0x43, 0xE8, 0x9D, 0xAB, 0x43, 0xE8,
0x9D, 0xB9, 0x43, 0xE8, 0x9E, 0x86, 0x43, 0xE8,
0x9E, 0xBA, 0x43, 0xE8, 0x9F, 0xA1, 0x43, 0xE8,
0xA0, 0x81, 0x43, 0xE8, 0xA0, 0x9F, 0x43, 0xE8,
0xA1, 0x80, 0x43, 0xE8, 0xA1, 0x8C, 0x43, 0xE8,
0xA1, 0xA0, 0x43, 0xE8, 0xA1, 0xA3, 0x43, 0xE8,
0xA3, 0x82, 0x43, 0xE8, 0xA3, 0x8F, 0x43, 0xE8,
0xA3, 0x97, 0x43, 0xE8, 0xA3, 0x9E, 0x43, 0xE8,
// Bytes 1400 - 143f
0xA3, 0xA1, 0x43, 0xE8, 0xA3, 0xB8, 0x43, 0xE8,
0xA3, 0xBA, 0x43, 0xE8, 0xA4, 0x90, 0x43, 0xE8,
0xA5, 0x81, 0x43, 0xE8, 0xA5, 0xA4, 0x43, 0xE8,
0xA5, 0xBE, 0x43, 0xE8, 0xA6, 0x86, 0x43, 0xE8,
0xA6, 0x8B, 0x43, 0xE8, 0xA6, 0x96, 0x43, 0xE8,
0xA7, 0x92, 0x43, 0xE8, 0xA7, 0xA3, 0x43, 0xE8,
0xA8, 0x80, 0x43, 0xE8, 0xAA, 0xA0, 0x43, 0xE8,
0xAA, 0xAA, 0x43, 0xE8, 0xAA, 0xBF, 0x43, 0xE8,
// Bytes 1440 - 147f
0xAB, 0x8B, 0x43, 0xE8, 0xAB, 0x92, 0x43, 0xE8,
0xAB, 0x96, 0x43, 0xE8, 0xAB, 0xAD, 0x43, 0xE8,
0xAB, 0xB8, 0x43, 0xE8, 0xAB, 0xBE, 0x43, 0xE8,
0xAC, 0x81, 0x43, 0xE8, 0xAC, 0xB9, 0x43, 0xE8,
0xAD, 0x98, 0x43, 0xE8, 0xAE, 0x80, 0x43, 0xE8,
0xAE, 0x8A, 0x43, 0xE8, 0xB0, 0xB7, 0x43, 0xE8,
0xB1, 0x86, 0x43, 0xE8, 0xB1, 0x88, 0x43, 0xE8,
0xB1, 0x95, 0x43, 0xE8, 0xB1, 0xB8, 0x43, 0xE8,
// Bytes 1480 - 14bf
0xB2, 0x9D, 0x43, 0xE8, 0xB2, 0xA1, 0x43, 0xE8,
0xB2, 0xA9, 0x43, 0xE8, 0xB2, 0xAB, 0x43, 0xE8,
0xB3, 0x81, 0x43, 0xE8, 0xB3, 0x82, 0x43, 0xE8,
0xB3, 0x87, 0x43, 0xE8, 0xB3, 0x88, 0x43, 0xE8,
0xB3, 0x93, 0x43, 0xE8, 0xB4, 0x88, 0x43, 0xE8,
0xB4, 0x9B, 0x43, 0xE8, 0xB5, 0xA4, 0x43, 0xE8,
0xB5, 0xB0, 0x43, 0xE8, 0xB5, 0xB7, 0x43, 0xE8,
0xB6, 0xB3, 0x43, 0xE8, 0xB6, 0xBC, 0x43, 0xE8,
// Bytes 14c0 - 14ff
0xB7, 0x8B, 0x43, 0xE8, 0xB7, 0xAF, 0x43, 0xE8,
0xB7, 0xB0, 0x43, 0xE8, 0xBA, 0xAB, 0x43, 0xE8,
0xBB, 0x8A, 0x43, 0xE8, 0xBB, 0x94, 0x43, 0xE8,
0xBC, 0xA6, 0x43, 0xE8, 0xBC, 0xAA, 0x43, 0xE8,
0xBC, 0xB8, 0x43, 0xE8, 0xBC, 0xBB, 0x43, 0xE8,
0xBD, 0xA2, 0x43, 0xE8, 0xBE, 0x9B, 0x43, 0xE8,
0xBE, 0x9E, 0x43, 0xE8, 0xBE, 0xB0, 0x43, 0xE8,
0xBE, 0xB5, 0x43, 0xE8, 0xBE, 0xB6, 0x43, 0xE9,
// Bytes 1500 - 153f
0x80, 0xA3, 0x43, 0xE9, 0x80, 0xB8, 0x43, 0xE9,
0x81, 0x8A, 0x43, 0xE9, 0x81, 0xA9, 0x43, 0xE9,
0x81, 0xB2, 0x43, 0xE9, 0x81, 0xBC, 0x43, 0xE9,
0x82, 0x8F, 0x43, 0xE9, 0x82, 0x91, 0x43, 0xE9,
0x82, 0x94, 0x43, 0xE9, 0x83, 0x8E, 0x43, 0xE9,
0x83, 0x9E, 0x43, 0xE9, 0x83, 0xB1, 0x43, 0xE9,
0x83, 0xBD, 0x43, 0xE9, 0x84, 0x91, 0x43, 0xE9,
0x84, 0x9B, 0x43, 0xE9, 0x85, 0x89, 0x43, 0xE9,
// Bytes 1540 - 157f
0x85, 0x8D, 0x43, 0xE9, 0x85, 0xAA, 0x43, 0xE9,
0x86, 0x99, 0x43, 0xE9, 0x86, 0xB4, 0x43, 0xE9,
0x87, 0x86, 0x43, 0xE9, 0x87, 0x8C, 0x43, 0xE9,
0x87, 0x8F, 0x43, 0xE9, 0x87, 0x91, 0x43, 0xE9,
0x88, 0xB4, 0x43, 0xE9, 0x88, 0xB8, 0x43, 0xE9,
0x89, 0xB6, 0x43, 0xE9, 0x89, 0xBC, 0x43, 0xE9,
0x8B, 0x97, 0x43, 0xE9, 0x8B, 0x98, 0x43, 0xE9,
0x8C, 0x84, 0x43, 0xE9, 0x8D, 0x8A, 0x43, 0xE9,
// Bytes 1580 - 15bf
0x8F, 0xB9, 0x43, 0xE9, 0x90, 0x95, 0x43, 0xE9,
0x95, 0xB7, 0x43, 0xE9, 0x96, 0x80, 0x43, 0xE9,
0x96, 0x8B, 0x43, 0xE9, 0x96, 0xAD, 0x43, 0xE9,
0x96, 0xB7, 0x43, 0xE9, 0x98, 0x9C, 0x43, 0xE9,
0x98, 0xAE, 0x43, 0xE9, 0x99, 0x8B, 0x43, 0xE9,
0x99, 0x8D, 0x43, 0xE9, 0x99, 0xB5, 0x43, 0xE9,
0x99, 0xB8, 0x43, 0xE9, 0x99, 0xBC, 0x43, 0xE9,
0x9A, 0x86, 0x43, 0xE9, 0x9A, 0xA3, 0x43, 0xE9,
// Bytes 15c0 - 15ff
0x9A, 0xB6, 0x43, 0xE9, 0x9A, 0xB7, 0x43, 0xE9,
0x9A, 0xB8, 0x43, 0xE9, 0x9A, 0xB9, 0x43, 0xE9,
0x9B, 0x83, 0x43, 0xE9, 0x9B, 0xA2, 0x43, 0xE9,
0x9B, 0xA3, 0x43, 0xE9, 0x9B, 0xA8, 0x43, 0xE9,
0x9B, 0xB6, 0x43, 0xE9, 0x9B, 0xB7, 0x43, 0xE9,
0x9C, 0xA3, 0x43, 0xE9, 0x9C, 0xB2, 0x43, 0xE9,
0x9D, 0x88, 0x43, 0xE9, 0x9D, 0x91, 0x43, 0xE9,
0x9D, 0x96, 0x43, 0xE9, 0x9D, 0x9E, 0x43, 0xE9,
// Bytes 1600 - 163f
0x9D, 0xA2, 0x43, 0xE9, 0x9D, 0xA9, 0x43, 0xE9,
0x9F, 0x8B, 0x43, 0xE9, 0x9F, 0x9B, 0x43, 0xE9,
0x9F, 0xA0, 0x43, 0xE9, 0x9F, 0xAD, 0x43, 0xE9,
0x9F, 0xB3, 0x43, 0xE9, 0x9F, 0xBF, 0x43, 0xE9,
0xA0, 0x81, 0x43, 0xE9, 0xA0, 0x85, 0x43, 0xE9,
0xA0, 0x8B, 0x43, 0xE9, 0xA0, 0x98, 0x43, 0xE9,
0xA0, 0xA9, 0x43, 0xE9, 0xA0, 0xBB, 0x43, 0xE9,
0xA1, 0x9E, 0x43, 0xE9, 0xA2, 0xA8, 0x43, 0xE9,
// Bytes 1640 - 167f
0xA3, 0x9B, 0x43, 0xE9, 0xA3, 0x9F, 0x43, 0xE9,
0xA3, 0xA2, 0x43, 0xE9, 0xA3, 0xAF, 0x43, 0xE9,
0xA3, 0xBC, 0x43, 0xE9, 0xA4, 0xA8, 0x43, 0xE9,
0xA4, 0xA9, 0x43, 0xE9, 0xA6, 0x96, 0x43, 0xE9,
0xA6, 0x99, 0x43, 0xE9, 0xA6, 0xA7, 0x43, 0xE9,
0xA6, 0xAC, 0x43, 0xE9, 0xA7, 0x82, 0x43, 0xE9,
0xA7, 0xB1, 0x43, 0xE9, 0xA7, 0xBE, 0x43, 0xE9,
0xA9, 0xAA, 0x43, 0xE9, 0xAA, 0xA8, 0x43, 0xE9,
// Bytes 1680 - 16bf
0xAB, 0x98, 0x43, 0xE9, 0xAB, 0x9F, 0x43, 0xE9,
0xAC, 0x92, 0x43, 0xE9, 0xAC, 0xA5, 0x43, 0xE9,
0xAC, 0xAF, 0x43, 0xE9, 0xAC, 0xB2, 0x43, 0xE9,
0xAC, 0xBC, 0x43, 0xE9, 0xAD, 0x9A, 0x43, 0xE9,
0xAD, 0xAF, 0x43, 0xE9, 0xB1, 0x80, 0x43, 0xE9,
0xB1, 0x97, 0x43, 0xE9, 0xB3, 0xA5, 0x43, 0xE9,
0xB3, 0xBD, 0x43, 0xE9, 0xB5, 0xA7, 0x43, 0xE9,
0xB6, 0xB4, 0x43, 0xE9, 0xB7, 0xBA, 0x43, 0xE9,
// Bytes 16c0 - 16ff
0xB8, 0x9E, 0x43, 0xE9, 0xB9, 0xB5, 0x43, 0xE9,
0xB9, 0xBF, 0x43, 0xE9, 0xBA, 0x97, 0x43, 0xE9,
0xBA, 0x9F, 0x43, 0xE9, 0xBA, 0xA5, 0x43, 0xE9,
0xBA, 0xBB, 0x43, 0xE9, 0xBB, 0x83, 0x43, 0xE9,
0xBB, 0x8D, 0x43, 0xE9, 0xBB, 0x8E, 0x43, 0xE9,
0xBB, 0x91, 0x43, 0xE9, 0xBB, 0xB9, 0x43, 0xE9,
0xBB, 0xBD, 0x43, 0xE9, 0xBB, 0xBE, 0x43, 0xE9,
0xBC, 0x85, 0x43, 0xE9, 0xBC, 0x8E, 0x43, 0xE9,
// Bytes 1700 - 173f
0xBC, 0x8F, 0x43, 0xE9, 0xBC, 0x93, 0x43, 0xE9,
0xBC, 0x96, 0x43, 0xE9, 0xBC, 0xA0, 0x43, 0xE9,
0xBC, 0xBB, 0x43, 0xE9, 0xBD, 0x83, 0x43, 0xE9,
0xBD, 0x8A, 0x43, 0xE9, 0xBD, 0x92, 0x43, 0xE9,
0xBE, 0x8D, 0x43, 0xE9, 0xBE, 0x8E, 0x43, 0xE9,
0xBE, 0x9C, 0x43, 0xE9, 0xBE, 0x9F, 0x43, 0xE9,
0xBE, 0xA0, 0x43, 0xEA, 0x99, 0x91, 0x43, 0xEA,
0x9A, 0x89, 0x43, 0xEA, 0x9C, 0xA7, 0x43, 0xEA,
// Bytes 1740 - 177f
0x9D, 0xAF, 0x43, 0xEA, 0x9E, 0x8E, 0x43, 0xEA,
0xAC, 0xB7, 0x43, 0xEA, 0xAD, 0x92, 0x43, 0xEA,
0xAD, 0xA6, 0x43, 0xEA, 0xAD, 0xA7, 0x44, 0xF0,
0x9D, 0xBC, 0x84, 0x44, 0xF0, 0x9D, 0xBC, 0x85,
0x44, 0xF0, 0x9D, 0xBC, 0x86, 0x44, 0xF0, 0x9D,
0xBC, 0x88, 0x44, 0xF0, 0x9D, 0xBC, 0x8A, 0x44,
0xF0, 0x9D, 0xBC, 0x9E, 0x44, 0xF0, 0xA0, 0x84,
0xA2, 0x44, 0xF0, 0xA0, 0x94, 0x9C, 0x44, 0xF0,
// Bytes 1780 - 17bf
0xA0, 0x94, 0xA5, 0x44, 0xF0, 0xA0, 0x95, 0x8B,
0x44, 0xF0, 0xA0, 0x98, 0xBA, 0x44, 0xF0, 0xA0,
0xA0, 0x84, 0x44, 0xF0, 0xA0, 0xA3, 0x9E, 0x44,
0xF0, 0xA0, 0xA8, 0xAC, 0x44, 0xF0, 0xA0, 0xAD,
0xA3, 0x44, 0xF0, 0xA1, 0x93, 0xA4, 0x44, 0xF0,
0xA1, 0x9A, 0xA8, 0x44, 0xF0, 0xA1, 0x9B, 0xAA,
0x44, 0xF0, 0xA1, 0xA7, 0x88, 0x44, 0xF0, 0xA1,
0xAC, 0x98, 0x44, 0xF0, 0xA1, 0xB4, 0x8B, 0x44,
// Bytes 17c0 - 17ff
0xF0, 0xA1, 0xB7, 0xA4, 0x44, 0xF0, 0xA1, 0xB7,
0xA6, 0x44, 0xF0, 0xA2, 0x86, 0x83, 0x44, 0xF0,
0xA2, 0x86, 0x9F, 0x44, 0xF0, 0xA2, 0x8C, 0xB1,
0x44, 0xF0, 0xA2, 0x9B, 0x94, 0x44, 0xF0, 0xA2,
0xA1, 0x84, 0x44, 0xF0, 0xA2, 0xA1, 0x8A, 0x44,
0xF0, 0xA2, 0xAC, 0x8C, 0x44, 0xF0, 0xA2, 0xAF,
0xB1, 0x44, 0xF0, 0xA3, 0x80, 0x8A, 0x44, 0xF0,
0xA3, 0x8A, 0xB8, 0x44, 0xF0, 0xA3, 0x8D, 0x9F,
// Bytes 1800 - 183f
0x44, 0xF0, 0xA3, 0x8E, 0x93, 0x44, 0xF0, 0xA3,
0x8E, 0x9C, 0x44, 0xF0, 0xA3, 0x8F, 0x83, 0x44,
0xF0, 0xA3, 0x8F, 0x95, 0x44, 0xF0, 0xA3, 0x91,
0xAD, 0x44, 0xF0, 0xA3, 0x9A, 0xA3, 0x44, 0xF0,
0xA3, 0xA2, 0xA7, 0x44, 0xF0, 0xA3, 0xAA, 0x8D,
0x44, 0xF0, 0xA3, 0xAB, 0xBA, 0x44, 0xF0, 0xA3,
0xB2, 0xBC, 0x44, 0xF0, 0xA3, 0xB4, 0x9E, 0x44,
0xF0, 0xA3, 0xBB, 0x91, 0x44, 0xF0, 0xA3, 0xBD,
// Bytes 1840 - 187f
0x9E, 0x44, 0xF0, 0xA3, 0xBE, 0x8E, 0x44, 0xF0,
0xA4, 0x89, 0xA3, 0x44, 0xF0, 0xA4, 0x8B, 0xAE,
0x44, 0xF0, 0xA4, 0x8E, 0xAB, 0x44, 0xF0, 0xA4,
0x98, 0x88, 0x44, 0xF0, 0xA4, 0x9C, 0xB5, 0x44,
0xF0, 0xA4, 0xA0, 0x94, 0x44, 0xF0, 0xA4, 0xB0,
0xB6, 0x44, 0xF0, 0xA4, 0xB2, 0x92, 0x44, 0xF0,
0xA4, 0xBE, 0xA1, 0x44, 0xF0, 0xA4, 0xBE, 0xB8,
0x44, 0xF0, 0xA5, 0x81, 0x84, 0x44, 0xF0, 0xA5,
// Bytes 1880 - 18bf
0x83, 0xB2, 0x44, 0xF0, 0xA5, 0x83, 0xB3, 0x44,
0xF0, 0xA5, 0x84, 0x99, 0x44, 0xF0, 0xA5, 0x84,
0xB3, 0x44, 0xF0, 0xA5, 0x89, 0x89, 0x44, 0xF0,
0xA5, 0x90, 0x9D, 0x44, 0xF0, 0xA5, 0x98, 0xA6,
0x44, 0xF0, 0xA5, 0x9A, 0x9A, 0x44, 0xF0, 0xA5,
0x9B, 0x85, 0x44, 0xF0, 0xA5, 0xA5, 0xBC, 0x44,
0xF0, 0xA5, 0xAA, 0xA7, 0x44, 0xF0, 0xA5, 0xAE,
0xAB, 0x44, 0xF0, 0xA5, 0xB2, 0x80, 0x44, 0xF0,
// Bytes 18c0 - 18ff
0xA5, 0xB3, 0x90, 0x44, 0xF0, 0xA5, 0xBE, 0x86,
0x44, 0xF0, 0xA6, 0x87, 0x9A, 0x44, 0xF0, 0xA6,
0x88, 0xA8, 0x44, 0xF0, 0xA6, 0x89, 0x87, 0x44,
0xF0, 0xA6, 0x8B, 0x99, 0x44, 0xF0, 0xA6, 0x8C,
0xBE, 0x44, 0xF0, 0xA6, 0x93, 0x9A, 0x44, 0xF0,
0xA6, 0x94, 0xA3, 0x44, 0xF0, 0xA6, 0x96, 0xA8,
0x44, 0xF0, 0xA6, 0x9E, 0xA7, 0x44, 0xF0, 0xA6,
0x9E, 0xB5, 0x44, 0xF0, 0xA6, 0xAC, 0xBC, 0x44,
// Bytes 1900 - 193f
0xF0, 0xA6, 0xB0, 0xB6, 0x44, 0xF0, 0xA6, 0xB3,
0x95, 0x44, 0xF0, 0xA6, 0xB5, 0xAB, 0x44, 0xF0,
0xA6, 0xBC, 0xAC, 0x44, 0xF0, 0xA6, 0xBE, 0xB1,
0x44, 0xF0, 0xA7, 0x83, 0x92, 0x44, 0xF0, 0xA7,
0x8F, 0x8A, 0x44, 0xF0, 0xA7, 0x99, 0xA7, 0x44,
0xF0, 0xA7, 0xA2, 0xAE, 0x44, 0xF0, 0xA7, 0xA5,
0xA6, 0x44, 0xF0, 0xA7, 0xB2, 0xA8, 0x44, 0xF0,
0xA7, 0xBB, 0x93, 0x44, 0xF0, 0xA7, 0xBC, 0xAF,
// Bytes 1940 - 197f
0x44, 0xF0, 0xA8, 0x97, 0x92, 0x44, 0xF0, 0xA8,
0x97, 0xAD, 0x44, 0xF0, 0xA8, 0x9C, 0xAE, 0x44,
0xF0, 0xA8, 0xAF, 0xBA, 0x44, 0xF0, 0xA8, 0xB5,
0xB7, 0x44, 0xF0, 0xA9, 0x85, 0x85, 0x44, 0xF0,
0xA9, 0x87, 0x9F, 0x44, 0xF0, 0xA9, 0x88, 0x9A,
0x44, 0xF0, 0xA9, 0x90, 0x8A, 0x44, 0xF0, 0xA9,
0x92, 0x96, 0x44, 0xF0, 0xA9, 0x96, 0xB6, 0x44,
0xF0, 0xA9, 0xAC, 0xB0, 0x44, 0xF0, 0xAA, 0x83,
// Bytes 1980 - 19bf
0x8E, 0x44, 0xF0, 0xAA, 0x84, 0x85, 0x44, 0xF0,
0xAA, 0x88, 0x8E, 0x44, 0xF0, 0xAA, 0x8A, 0x91,
0x44, 0xF0, 0xAA, 0x8E, 0x92, 0x44, 0xF0, 0xAA,
0x98, 0x80, 0x42, 0x21, 0x21, 0x42, 0x21, 0x3F,
0x42, 0x2E, 0x2E, 0x42, 0x30, 0x2C, 0x42, 0x30,
0x2E, 0x42, 0x31, 0x2C, 0x42, 0x31, 0x2E, 0x42,
0x31, 0x30, 0x42, 0x31, 0x31, 0x42, 0x31, 0x32,
0x42, 0x31, 0x33, 0x42, 0x31, 0x34, 0x42, 0x31,
// Bytes 19c0 - 19ff
0x35, 0x42, 0x31, 0x36, 0x42, 0x31, 0x37, 0x42,
0x31, 0x38, 0x42, 0x31, 0x39, 0x42, 0x32, 0x2C,
0x42, 0x32, 0x2E, 0x42, 0x32, 0x30, 0x42, 0x32,
0x31, 0x42, 0x32, 0x32, 0x42, 0x32, 0x33, 0x42,
0x32, 0x34, 0x42, 0x32, 0x35, 0x42, 0x32, 0x36,
0x42, 0x32, 0x37, 0x42, 0x32, 0x38, 0x42, 0x32,
0x39, 0x42, 0x33, 0x2C, 0x42, 0x33, 0x2E, 0x42,
0x33, 0x30, 0x42, 0x33, 0x31, 0x42, 0x33, 0x32,
// Bytes 1a00 - 1a3f
0x42, 0x33, 0x33, 0x42, 0x33, 0x34, 0x42, 0x33,
0x35, 0x42, 0x33, 0x36, 0x42, 0x33, 0x37, 0x42,
0x33, 0x38, 0x42, 0x33, 0x39, 0x42, 0x34, 0x2C,
0x42, 0x34, 0x2E, 0x42, 0x34, 0x30, 0x42, 0x34,
0x31, 0x42, 0x34, 0x32, 0x42, 0x34, 0x33, 0x42,
0x34, 0x34, 0x42, 0x34, 0x35, 0x42, 0x34, 0x36,
0x42, 0x34, 0x37, 0x42, 0x34, 0x38, 0x42, 0x34,
0x39, 0x42, 0x35, 0x2C, 0x42, 0x35, 0x2E, 0x42,
// Bytes 1a40 - 1a7f
0x35, 0x30, 0x42, 0x36, 0x2C, 0x42, 0x36, 0x2E,
0x42, 0x37, 0x2C, 0x42, 0x37, 0x2E, 0x42, 0x38,
0x2C, 0x42, 0x38, 0x2E, 0x42, 0x39, 0x2C, 0x42,
0x39, 0x2E, 0x42, 0x3D, 0x3D, 0x42, 0x3F, 0x21,
0x42, 0x3F, 0x3F, 0x42, 0x41, 0x55, 0x42, 0x42,
0x71, 0x42, 0x43, 0x44, 0x42, 0x44, 0x4A, 0x42,
0x44, 0x5A, 0x42, 0x44, 0x7A, 0x42, 0x47, 0x42,
0x42, 0x47, 0x79, 0x42, 0x48, 0x50, 0x42, 0x48,
// Bytes 1a80 - 1abf
0x56, 0x42, 0x48, 0x67, 0x42, 0x48, 0x7A, 0x42,
0x49, 0x49, 0x42, 0x49, 0x4A, 0x42, 0x49, 0x55,
0x42, 0x49, 0x56, 0x42, 0x49, 0x58, 0x42, 0x4B,
0x42, 0x42, 0x4B, 0x4B, 0x42, 0x4B, 0x4D, 0x42,
0x4C, 0x4A, 0x42, 0x4C, 0x6A, 0x42, 0x4D, 0x42,
0x42, 0x4D, 0x43, 0x42, 0x4D, 0x44, 0x42, 0x4D,
0x52, 0x42, 0x4D, 0x56, 0x42, 0x4D, 0x57, 0x42,
0x4E, 0x4A, 0x42, 0x4E, 0x6A, 0x42, 0x4E, 0x6F,
// Bytes 1ac0 - 1aff
0x42, 0x50, 0x48, 0x42, 0x50, 0x52, 0x42, 0x50,
0x61, 0x42, 0x52, 0x73, 0x42, 0x53, 0x44, 0x42,
0x53, 0x4D, 0x42, 0x53, 0x53, 0x42, 0x53, 0x76,
0x42, 0x54, 0x4D, 0x42, 0x56, 0x49, 0x42, 0x57,
0x43, 0x42, 0x57, 0x5A, 0x42, 0x57, 0x62, 0x42,
0x58, 0x49, 0x42, 0x63, 0x63, 0x42, 0x63, 0x64,
0x42, 0x63, 0x6D, 0x42, 0x64, 0x42, 0x42, 0x64,
0x61, 0x42, 0x64, 0x6C, 0x42, 0x64, 0x6D, 0x42,
// Bytes 1b00 - 1b3f
0x64, 0x7A, 0x42, 0x65, 0x56, 0x42, 0x66, 0x66,
0x42, 0x66, 0x69, 0x42, 0x66, 0x6C, 0x42, 0x66,
0x6D, 0x42, 0x68, 0x61, 0x42, 0x69, 0x69, 0x42,
0x69, 0x6A, 0x42, 0x69, 0x6E, 0x42, 0x69, 0x76,
0x42, 0x69, 0x78, 0x42, 0x6B, 0x41, 0x42, 0x6B,
0x56, 0x42, 0x6B, 0x57, 0x42, 0x6B, 0x67, 0x42,
0x6B, 0x6C, 0x42, 0x6B, 0x6D, 0x42, 0x6B, 0x74,
0x42, 0x6C, 0x6A, 0x42, 0x6C, 0x6D, 0x42, 0x6C,
// Bytes 1b40 - 1b7f
0x6E, 0x42, 0x6C, 0x78, 0x42, 0x6D, 0x32, 0x42,
0x6D, 0x33, 0x42, 0x6D, 0x41, 0x42, 0x6D, 0x56,
0x42, 0x6D, 0x57, 0x42, 0x6D, 0x62, 0x42, 0x6D,
0x67, 0x42, 0x6D, 0x6C, 0x42, 0x6D, 0x6D, 0x42,
0x6D, 0x73, 0x42, 0x6E, 0x41, 0x42, 0x6E, 0x46,
0x42, 0x6E, 0x56, 0x42, 0x6E, 0x57, 0x42, 0x6E,
0x6A, 0x42, 0x6E, 0x6D, 0x42, 0x6E, 0x73, 0x42,
0x6F, 0x56, 0x42, 0x70, 0x41, 0x42, 0x70, 0x46,
// Bytes 1b80 - 1bbf
0x42, 0x70, 0x56, 0x42, 0x70, 0x57, 0x42, 0x70,
0x63, 0x42, 0x70, 0x73, 0x42, 0x73, 0x72, 0x42,
0x73, 0x74, 0x42, 0x76, 0x69, 0x42, 0x78, 0x69,
0x43, 0x28, 0x31, 0x29, 0x43, 0x28, 0x32, 0x29,
0x43, 0x28, 0x33, 0x29, 0x43, 0x28, 0x34, 0x29,
0x43, 0x28, 0x35, 0x29, 0x43, 0x28, 0x36, 0x29,
0x43, 0x28, 0x37, 0x29, 0x43, 0x28, 0x38, 0x29,
0x43, 0x28, 0x39, 0x29, 0x43, 0x28, 0x41, 0x29,
// Bytes 1bc0 - 1bff
0x43, 0x28, 0x42, 0x29, 0x43, 0x28, 0x43, 0x29,
0x43, 0x28, 0x44, 0x29, 0x43, 0x28, 0x45, 0x29,
0x43, 0x28, 0x46, 0x29, 0x43, 0x28, 0x47, 0x29,
0x43, 0x28, 0x48, 0x29, 0x43, 0x28, 0x49, 0x29,
0x43, 0x28, 0x4A, 0x29, 0x43, 0x28, 0x4B, 0x29,
0x43, 0x28, 0x4C, 0x29, 0x43, 0x28, 0x4D, 0x29,
0x43, 0x28, 0x4E, 0x29, 0x43, 0x28, 0x4F, 0x29,
0x43, 0x28, 0x50, 0x29, 0x43, 0x28, 0x51, 0x29,
// Bytes 1c00 - 1c3f
0x43, 0x28, 0x52, 0x29, 0x43, 0x28, 0x53, 0x29,
0x43, 0x28, 0x54, 0x29, 0x43, 0x28, 0x55, 0x29,
0x43, 0x28, 0x56, 0x29, 0x43, 0x28, 0x57, 0x29,
0x43, 0x28, 0x58, 0x29, 0x43, 0x28, 0x59, 0x29,
0x43, 0x28, 0x5A, 0x29, 0x43, 0x28, 0x61, 0x29,
0x43, 0x28, 0x62, 0x29, 0x43, 0x28, 0x63, 0x29,
0x43, 0x28, 0x64, 0x29, 0x43, 0x28, 0x65, 0x29,
0x43, 0x28, 0x66, 0x29, 0x43, 0x28, 0x67, 0x29,
// Bytes 1c40 - 1c7f
0x43, 0x28, 0x68, 0x29, 0x43, 0x28, 0x69, 0x29,
0x43, 0x28, 0x6A, 0x29, 0x43, 0x28, 0x6B, 0x29,
0x43, 0x28, 0x6C, 0x29, 0x43, 0x28, 0x6D, 0x29,
0x43, 0x28, 0x6E, 0x29, 0x43, 0x28, 0x6F, 0x29,
0x43, 0x28, 0x70, 0x29, 0x43, 0x28, 0x71, 0x29,
0x43, 0x28, 0x72, 0x29, 0x43, 0x28, 0x73, 0x29,
0x43, 0x28, 0x74, 0x29, 0x43, 0x28, 0x75, 0x29,
0x43, 0x28, 0x76, 0x29, 0x43, 0x28, 0x77, 0x29,
// Bytes 1c80 - 1cbf
0x43, 0x28, 0x78, 0x29, 0x43, 0x28, 0x79, 0x29,
0x43, 0x28, 0x7A, 0x29, 0x43, 0x2E, 0x2E, 0x2E,
0x43, 0x31, 0x30, 0x2E, 0x43, 0x31, 0x31, 0x2E,
0x43, 0x31, 0x32, 0x2E, 0x43, 0x31, 0x33, 0x2E,
0x43, 0x31, 0x34, 0x2E, 0x43, 0x31, 0x35, 0x2E,
0x43, 0x31, 0x36, 0x2E, 0x43, 0x31, 0x37, 0x2E,
0x43, 0x31, 0x38, 0x2E, 0x43, 0x31, 0x39, 0x2E,
0x43, 0x32, 0x30, 0x2E, 0x43, 0x3A, 0x3A, 0x3D,
// Bytes 1cc0 - 1cff
0x43, 0x3D, 0x3D, 0x3D, 0x43, 0x43, 0x6F, 0x2E,
0x43, 0x46, 0x41, 0x58, 0x43, 0x47, 0x48, 0x7A,
0x43, 0x47, 0x50, 0x61, 0x43, 0x49, 0x49, 0x49,
0x43, 0x4C, 0x54, 0x44, 0x43, 0x4C, 0xC2, 0xB7,
0x43, 0x4D, 0x48, 0x7A, 0x43, 0x4D, 0x50, 0x61,
0x43, 0x4D, 0xCE, 0xA9, 0x43, 0x50, 0x50, 0x4D,
0x43, 0x50, 0x50, 0x56, 0x43, 0x50, 0x54, 0x45,
0x43, 0x54, 0x45, 0x4C, 0x43, 0x54, 0x48, 0x7A,
// Bytes 1d00 - 1d3f
0x43, 0x56, 0x49, 0x49, 0x43, 0x58, 0x49, 0x49,
0x43, 0x61, 0x2F, 0x63, 0x43, 0x61, 0x2F, 0x73,
0x43, 0x61, 0xCA, 0xBE, 0x43, 0x62, 0x61, 0x72,
0x43, 0x63, 0x2F, 0x6F, 0x43, 0x63, 0x2F, 0x75,
0x43, 0x63, 0x61, 0x6C, 0x43, 0x63, 0x6D, 0x32,
0x43, 0x63, 0x6D, 0x33, 0x43, 0x64, 0x6D, 0x32,
0x43, 0x64, 0x6D, 0x33, 0x43, 0x65, 0x72, 0x67,
0x43, 0x66, 0x66, 0x69, 0x43, 0x66, 0x66, 0x6C,
// Bytes 1d40 - 1d7f
0x43, 0x67, 0x61, 0x6C, 0x43, 0x68, 0x50, 0x61,
0x43, 0x69, 0x69, 0x69, 0x43, 0x6B, 0x48, 0x7A,
0x43, 0x6B, 0x50, 0x61, 0x43, 0x6B, 0x6D, 0x32,
0x43, 0x6B, 0x6D, 0x33, 0x43, 0x6B, 0xCE, 0xA9,
0x43, 0x6C, 0x6F, 0x67, 0x43, 0x6C, 0xC2, 0xB7,
0x43, 0x6D, 0x69, 0x6C, 0x43, 0x6D, 0x6D, 0x32,
0x43, 0x6D, 0x6D, 0x33, 0x43, 0x6D, 0x6F, 0x6C,
0x43, 0x72, 0x61, 0x64, 0x43, 0x76, 0x69, 0x69,
// Bytes 1d80 - 1dbf
0x43, 0x78, 0x69, 0x69, 0x43, 0xC2, 0xB0, 0x43,
0x43, 0xC2, 0xB0, 0x46, 0x43, 0xCA, 0xBC, 0x6E,
0x43, 0xCE, 0xBC, 0x41, 0x43, 0xCE, 0xBC, 0x46,
0x43, 0xCE, 0xBC, 0x56, 0x43, 0xCE, 0xBC, 0x57,
0x43, 0xCE, 0xBC, 0x67, 0x43, 0xCE, 0xBC, 0x6C,
0x43, 0xCE, 0xBC, 0x6D, 0x43, 0xCE, 0xBC, 0x73,
0x44, 0x28, 0x31, 0x30, 0x29, 0x44, 0x28, 0x31,
0x31, 0x29, 0x44, 0x28, 0x31, 0x32, 0x29, 0x44,
// Bytes 1dc0 - 1dff
0x28, 0x31, 0x33, 0x29, 0x44, 0x28, 0x31, 0x34,
0x29, 0x44, 0x28, 0x31, 0x35, 0x29, 0x44, 0x28,
0x31, 0x36, 0x29, 0x44, 0x28, 0x31, 0x37, 0x29,
0x44, 0x28, 0x31, 0x38, 0x29, 0x44, 0x28, 0x31,
0x39, 0x29, 0x44, 0x28, 0x32, 0x30, 0x29, 0x44,
0x30, 0xE7, 0x82, 0xB9, 0x44, 0x31, 0xE2, 0x81,
0x84, 0x44, 0x31, 0xE6, 0x97, 0xA5, 0x44, 0x31,
0xE6, 0x9C, 0x88, 0x44, 0x31, 0xE7, 0x82, 0xB9,
// Bytes 1e00 - 1e3f
0x44, 0x32, 0xE6, 0x97, 0xA5, 0x44, 0x32, 0xE6,
0x9C, 0x88, 0x44, 0x32, 0xE7, 0x82, 0xB9, 0x44,
0x33, 0xE6, 0x97, 0xA5, 0x44, 0x33, 0xE6, 0x9C,
0x88, 0x44, 0x33, 0xE7, 0x82, 0xB9, 0x44, 0x34,
0xE6, 0x97, 0xA5, 0x44, 0x34, 0xE6, 0x9C, 0x88,
0x44, 0x34, 0xE7, 0x82, 0xB9, 0x44, 0x35, 0xE6,
0x97, 0xA5, 0x44, 0x35, 0xE6, 0x9C, 0x88, 0x44,
0x35, 0xE7, 0x82, 0xB9, 0x44, 0x36, 0xE6, 0x97,
// Bytes 1e40 - 1e7f
0xA5, 0x44, 0x36, 0xE6, 0x9C, 0x88, 0x44, 0x36,
0xE7, 0x82, 0xB9, 0x44, 0x37, 0xE6, 0x97, 0xA5,
0x44, 0x37, 0xE6, 0x9C, 0x88, 0x44, 0x37, 0xE7,
0x82, 0xB9, 0x44, 0x38, 0xE6, 0x97, 0xA5, 0x44,
0x38, 0xE6, 0x9C, 0x88, 0x44, 0x38, 0xE7, 0x82,
0xB9, 0x44, 0x39, 0xE6, 0x97, 0xA5, 0x44, 0x39,
0xE6, 0x9C, 0x88, 0x44, 0x39, 0xE7, 0x82, 0xB9,
0x44, 0x56, 0x49, 0x49, 0x49, 0x44, 0x61, 0x2E,
// Bytes 1e80 - 1ebf
0x6D, 0x2E, 0x44, 0x6B, 0x63, 0x61, 0x6C, 0x44,
0x70, 0x2E, 0x6D, 0x2E, 0x44, 0x76, 0x69, 0x69,
0x69, 0x44, 0xD5, 0xA5, 0xD6, 0x82, 0x44, 0xD5,
0xB4, 0xD5, 0xA5, 0x44, 0xD5, 0xB4, 0xD5, 0xAB,
0x44, 0xD5, 0xB4, 0xD5, 0xAD, 0x44, 0xD5, 0xB4,
0xD5, 0xB6, 0x44, 0xD5, 0xBE, 0xD5, 0xB6, 0x44,
0xD7, 0x90, 0xD7, 0x9C, 0x44, 0xD8, 0xA7, 0xD9,
0xB4, 0x44, 0xD8, 0xA8, 0xD8, 0xAC, 0x44, 0xD8,
// Bytes 1ec0 - 1eff
0xA8, 0xD8, 0xAD, 0x44, 0xD8, 0xA8, 0xD8, 0xAE,
0x44, 0xD8, 0xA8, 0xD8, 0xB1, 0x44, 0xD8, 0xA8,
0xD8, 0xB2, 0x44, 0xD8, 0xA8, 0xD9, 0x85, 0x44,
0xD8, 0xA8, 0xD9, 0x86, 0x44, 0xD8, 0xA8, 0xD9,
0x87, 0x44, 0xD8, 0xA8, 0xD9, 0x89, 0x44, 0xD8,
0xA8, 0xD9, 0x8A, 0x44, 0xD8, 0xAA, 0xD8, 0xAC,
0x44, 0xD8, 0xAA, 0xD8, 0xAD, 0x44, 0xD8, 0xAA,
0xD8, 0xAE, 0x44, 0xD8, 0xAA, 0xD8, 0xB1, 0x44,
// Bytes 1f00 - 1f3f
0xD8, 0xAA, 0xD8, 0xB2, 0x44, 0xD8, 0xAA, 0xD9,
0x85, 0x44, 0xD8, 0xAA, 0xD9, 0x86, 0x44, 0xD8,
0xAA, 0xD9, 0x87, 0x44, 0xD8, 0xAA, 0xD9, 0x89,
0x44, 0xD8, 0xAA, 0xD9, 0x8A, 0x44, 0xD8, 0xAB,
0xD8, 0xAC, 0x44, 0xD8, 0xAB, 0xD8, 0xB1, 0x44,
0xD8, 0xAB, 0xD8, 0xB2, 0x44, 0xD8, 0xAB, 0xD9,
0x85, 0x44, 0xD8, 0xAB, 0xD9, 0x86, 0x44, 0xD8,
0xAB, 0xD9, 0x87, 0x44, 0xD8, 0xAB, 0xD9, 0x89,
// Bytes 1f40 - 1f7f
0x44, 0xD8, 0xAB, 0xD9, 0x8A, 0x44, 0xD8, 0xAC,
0xD8, 0xAD, 0x44, 0xD8, 0xAC, 0xD9, 0x85, 0x44,
0xD8, 0xAC, 0xD9, 0x89, 0x44, 0xD8, 0xAC, 0xD9,
0x8A, 0x44, 0xD8, 0xAD, 0xD8, 0xAC, 0x44, 0xD8,
0xAD, 0xD9, 0x85, 0x44, 0xD8, 0xAD, 0xD9, 0x89,
0x44, 0xD8, 0xAD, 0xD9, 0x8A, 0x44, 0xD8, 0xAE,
0xD8, 0xAC, 0x44, 0xD8, 0xAE, 0xD8, 0xAD, 0x44,
0xD8, 0xAE, 0xD9, 0x85, 0x44, 0xD8, 0xAE, 0xD9,
// Bytes 1f80 - 1fbf
0x89, 0x44, 0xD8, 0xAE, 0xD9, 0x8A, 0x44, 0xD8,
0xB3, 0xD8, 0xAC, 0x44, 0xD8, 0xB3, 0xD8, 0xAD,
0x44, 0xD8, 0xB3, 0xD8, 0xAE, 0x44, 0xD8, 0xB3,
0xD8, 0xB1, 0x44, 0xD8, 0xB3, 0xD9, 0x85, 0x44,
0xD8, 0xB3, 0xD9, 0x87, 0x44, 0xD8, 0xB3, 0xD9,
0x89, 0x44, 0xD8, 0xB3, 0xD9, 0x8A, 0x44, 0xD8,
0xB4, 0xD8, 0xAC, 0x44, 0xD8, 0xB4, 0xD8, 0xAD,
0x44, 0xD8, 0xB4, 0xD8, 0xAE, 0x44, 0xD8, 0xB4,
// Bytes 1fc0 - 1fff
0xD8, 0xB1, 0x44, 0xD8, 0xB4, 0xD9, 0x85, 0x44,
0xD8, 0xB4, 0xD9, 0x87, 0x44, 0xD8, 0xB4, 0xD9,
0x89, 0x44, 0xD8, 0xB4, 0xD9, 0x8A, 0x44, 0xD8,
0xB5, 0xD8, 0xAD, 0x44, 0xD8, 0xB5, 0xD8, 0xAE,
0x44, 0xD8, 0xB5, 0xD8, 0xB1, 0x44, 0xD8, 0xB5,
0xD9, 0x85, 0x44, 0xD8, 0xB5, 0xD9, 0x89, 0x44,
0xD8, 0xB5, 0xD9, 0x8A, 0x44, 0xD8, 0xB6, 0xD8,
0xAC, 0x44, 0xD8, 0xB6, 0xD8, 0xAD, 0x44, 0xD8,
// Bytes 2000 - 203f
0xB6, 0xD8, 0xAE, 0x44, 0xD8, 0xB6, 0xD8, 0xB1,
0x44, 0xD8, 0xB6, 0xD9, 0x85, 0x44, 0xD8, 0xB6,
0xD9, 0x89, 0x44, 0xD8, 0xB6, 0xD9, 0x8A, 0x44,
0xD8, 0xB7, 0xD8, 0xAD, 0x44, 0xD8, 0xB7, 0xD9,
0x85, 0x44, 0xD8, 0xB7, 0xD9, 0x89, 0x44, 0xD8,
0xB7, 0xD9, 0x8A, 0x44, 0xD8, 0xB8, 0xD9, 0x85,
0x44, 0xD8, 0xB9, 0xD8, 0xAC, 0x44, 0xD8, 0xB9,
0xD9, 0x85, 0x44, 0xD8, 0xB9, 0xD9, 0x89, 0x44,
// Bytes 2040 - 207f
0xD8, 0xB9, 0xD9, 0x8A, 0x44, 0xD8, 0xBA, 0xD8,
0xAC, 0x44, 0xD8, 0xBA, 0xD9, 0x85, 0x44, 0xD8,
0xBA, 0xD9, 0x89, 0x44, 0xD8, 0xBA, 0xD9, 0x8A,
0x44, 0xD9, 0x81, 0xD8, 0xAC, 0x44, 0xD9, 0x81,
0xD8, 0xAD, 0x44, 0xD9, 0x81, 0xD8, 0xAE, 0x44,
0xD9, 0x81, 0xD9, 0x85, 0x44, 0xD9, 0x81, 0xD9,
0x89, 0x44, 0xD9, 0x81, 0xD9, 0x8A, 0x44, 0xD9,
0x82, 0xD8, 0xAD, 0x44, 0xD9, 0x82, 0xD9, 0x85,
// Bytes 2080 - 20bf
0x44, 0xD9, 0x82, 0xD9, 0x89, 0x44, 0xD9, 0x82,
0xD9, 0x8A, 0x44, 0xD9, 0x83, 0xD8, 0xA7, 0x44,
0xD9, 0x83, 0xD8, 0xAC, 0x44, 0xD9, 0x83, 0xD8,
0xAD, 0x44, 0xD9, 0x83, 0xD8, 0xAE, 0x44, 0xD9,
0x83, 0xD9, 0x84, 0x44, 0xD9, 0x83, 0xD9, 0x85,
0x44, 0xD9, 0x83, 0xD9, 0x89, 0x44, 0xD9, 0x83,
0xD9, 0x8A, 0x44, 0xD9, 0x84, 0xD8, 0xA7, 0x44,
0xD9, 0x84, 0xD8, 0xAC, 0x44, 0xD9, 0x84, 0xD8,
// Bytes 20c0 - 20ff
0xAD, 0x44, 0xD9, 0x84, 0xD8, 0xAE, 0x44, 0xD9,
0x84, 0xD9, 0x85, 0x44, 0xD9, 0x84, 0xD9, 0x87,
0x44, 0xD9, 0x84, 0xD9, 0x89, 0x44, 0xD9, 0x84,
0xD9, 0x8A, 0x44, 0xD9, 0x85, 0xD8, 0xA7, 0x44,
0xD9, 0x85, 0xD8, 0xAC, 0x44, 0xD9, 0x85, 0xD8,
0xAD, 0x44, 0xD9, 0x85, 0xD8, 0xAE, 0x44, 0xD9,
0x85, 0xD9, 0x85, 0x44, 0xD9, 0x85, 0xD9, 0x89,
0x44, 0xD9, 0x85, 0xD9, 0x8A, 0x44, 0xD9, 0x86,
// Bytes 2100 - 213f
0xD8, 0xAC, 0x44, 0xD9, 0x86, 0xD8, 0xAD, 0x44,
0xD9, 0x86, 0xD8, 0xAE, 0x44, 0xD9, 0x86, 0xD8,
0xB1, 0x44, 0xD9, 0x86, 0xD8, 0xB2, 0x44, 0xD9,
0x86, 0xD9, 0x85, 0x44, 0xD9, 0x86, 0xD9, 0x86,
0x44, 0xD9, 0x86, 0xD9, 0x87, 0x44, 0xD9, 0x86,
0xD9, 0x89, 0x44, 0xD9, 0x86, 0xD9, 0x8A, 0x44,
0xD9, 0x87, 0xD8, 0xAC, 0x44, 0xD9, 0x87, 0xD9,
0x85, 0x44, 0xD9, 0x87, 0xD9, 0x89, 0x44, 0xD9,
// Bytes 2140 - 217f
0x87, 0xD9, 0x8A, 0x44, 0xD9, 0x88, 0xD9, 0xB4,
0x44, 0xD9, 0x8A, 0xD8, 0xAC, 0x44, 0xD9, 0x8A,
0xD8, 0xAD, 0x44, 0xD9, 0x8A, 0xD8, 0xAE, 0x44,
0xD9, 0x8A, 0xD8, 0xB1, 0x44, 0xD9, 0x8A, 0xD8,
0xB2, 0x44, 0xD9, 0x8A, 0xD9, 0x85, 0x44, 0xD9,
0x8A, 0xD9, 0x86, 0x44, 0xD9, 0x8A, 0xD9, 0x87,
0x44, 0xD9, 0x8A, 0xD9, 0x89, 0x44, 0xD9, 0x8A,
0xD9, 0x8A, 0x44, 0xD9, 0x8A, 0xD9, 0xB4, 0x44,
// Bytes 2180 - 21bf
0xDB, 0x87, 0xD9, 0xB4, 0x45, 0x28, 0xE1, 0x84,
0x80, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x82, 0x29,
0x45, 0x28, 0xE1, 0x84, 0x83, 0x29, 0x45, 0x28,
0xE1, 0x84, 0x85, 0x29, 0x45, 0x28, 0xE1, 0x84,
0x86, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x87, 0x29,
0x45, 0x28, 0xE1, 0x84, 0x89, 0x29, 0x45, 0x28,
0xE1, 0x84, 0x8B, 0x29, 0x45, 0x28, 0xE1, 0x84,
0x8C, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x8E, 0x29,
// Bytes 21c0 - 21ff
0x45, 0x28, 0xE1, 0x84, 0x8F, 0x29, 0x45, 0x28,
0xE1, 0x84, 0x90, 0x29, 0x45, 0x28, 0xE1, 0x84,
0x91, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x92, 0x29,
0x45, 0x28, 0xE4, 0xB8, 0x80, 0x29, 0x45, 0x28,
0xE4, 0xB8, 0x83, 0x29, 0x45, 0x28, 0xE4, 0xB8,
0x89, 0x29, 0x45, 0x28, 0xE4, 0xB9, 0x9D, 0x29,
0x45, 0x28, 0xE4, 0xBA, 0x8C, 0x29, 0x45, 0x28,
0xE4, 0xBA, 0x94, 0x29, 0x45, 0x28, 0xE4, 0xBB,
// Bytes 2200 - 223f
0xA3, 0x29, 0x45, 0x28, 0xE4, 0xBC, 0x81, 0x29,
0x45, 0x28, 0xE4, 0xBC, 0x91, 0x29, 0x45, 0x28,
0xE5, 0x85, 0xAB, 0x29, 0x45, 0x28, 0xE5, 0x85,
0xAD, 0x29, 0x45, 0x28, 0xE5, 0x8A, 0xB4, 0x29,
0x45, 0x28, 0xE5, 0x8D, 0x81, 0x29, 0x45, 0x28,
0xE5, 0x8D, 0x94, 0x29, 0x45, 0x28, 0xE5, 0x90,
0x8D, 0x29, 0x45, 0x28, 0xE5, 0x91, 0xBC, 0x29,
0x45, 0x28, 0xE5, 0x9B, 0x9B, 0x29, 0x45, 0x28,
// Bytes 2240 - 227f
0xE5, 0x9C, 0x9F, 0x29, 0x45, 0x28, 0xE5, 0xAD,
0xA6, 0x29, 0x45, 0x28, 0xE6, 0x97, 0xA5, 0x29,
0x45, 0x28, 0xE6, 0x9C, 0x88, 0x29, 0x45, 0x28,
0xE6, 0x9C, 0x89, 0x29, 0x45, 0x28, 0xE6, 0x9C,
0xA8, 0x29, 0x45, 0x28, 0xE6, 0xA0, 0xAA, 0x29,
0x45, 0x28, 0xE6, 0xB0, 0xB4, 0x29, 0x45, 0x28,
0xE7, 0x81, 0xAB, 0x29, 0x45, 0x28, 0xE7, 0x89,
0xB9, 0x29, 0x45, 0x28, 0xE7, 0x9B, 0xA3, 0x29,
// Bytes 2280 - 22bf
0x45, 0x28, 0xE7, 0xA4, 0xBE, 0x29, 0x45, 0x28,
0xE7, 0xA5, 0x9D, 0x29, 0x45, 0x28, 0xE7, 0xA5,
0xAD, 0x29, 0x45, 0x28, 0xE8, 0x87, 0xAA, 0x29,
0x45, 0x28, 0xE8, 0x87, 0xB3, 0x29, 0x45, 0x28,
0xE8, 0xB2, 0xA1, 0x29, 0x45, 0x28, 0xE8, 0xB3,
0x87, 0x29, 0x45, 0x28, 0xE9, 0x87, 0x91, 0x29,
0x45, 0x30, 0xE2, 0x81, 0x84, 0x33, 0x45, 0x31,
0x30, 0xE6, 0x97, 0xA5, 0x45, 0x31, 0x30, 0xE6,
// Bytes 22c0 - 22ff
0x9C, 0x88, 0x45, 0x31, 0x30, 0xE7, 0x82, 0xB9,
0x45, 0x31, 0x31, 0xE6, 0x97, 0xA5, 0x45, 0x31,
0x31, 0xE6, 0x9C, 0x88, 0x45, 0x31, 0x31, 0xE7,
0x82, 0xB9, 0x45, 0x31, 0x32, 0xE6, 0x97, 0xA5,
0x45, 0x31, 0x32, 0xE6, 0x9C, 0x88, 0x45, 0x31,
0x32, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x33, 0xE6,
0x97, 0xA5, 0x45, 0x31, 0x33, 0xE7, 0x82, 0xB9,
0x45, 0x31, 0x34, 0xE6, 0x97, 0xA5, 0x45, 0x31,
// Bytes 2300 - 233f
0x34, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x35, 0xE6,
0x97, 0xA5, 0x45, 0x31, 0x35, 0xE7, 0x82, 0xB9,
0x45, 0x31, 0x36, 0xE6, 0x97, 0xA5, 0x45, 0x31,
0x36, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x37, 0xE6,
0x97, 0xA5, 0x45, 0x31, 0x37, 0xE7, 0x82, 0xB9,
0x45, 0x31, 0x38, 0xE6, 0x97, 0xA5, 0x45, 0x31,
0x38, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x39, 0xE6,
0x97, 0xA5, 0x45, 0x31, 0x39, 0xE7, 0x82, 0xB9,
// Bytes 2340 - 237f
0x45, 0x31, 0xE2, 0x81, 0x84, 0x32, 0x45, 0x31,
0xE2, 0x81, 0x84, 0x33, 0x45, 0x31, 0xE2, 0x81,
0x84, 0x34, 0x45, 0x31, 0xE2, 0x81, 0x84, 0x35,
0x45, 0x31, 0xE2, 0x81, 0x84, 0x36, 0x45, 0x31,
0xE2, 0x81, 0x84, 0x37, 0x45, 0x31, 0xE2, 0x81,
0x84, 0x38, 0x45, 0x31, 0xE2, 0x81, 0x84, 0x39,
0x45, 0x32, 0x30, 0xE6, 0x97, 0xA5, 0x45, 0x32,
0x30, 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x31, 0xE6,
// Bytes 2380 - 23bf
0x97, 0xA5, 0x45, 0x32, 0x31, 0xE7, 0x82, 0xB9,
0x45, 0x32, 0x32, 0xE6, 0x97, 0xA5, 0x45, 0x32,
0x32, 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x33, 0xE6,
0x97, 0xA5, 0x45, 0x32, 0x33, 0xE7, 0x82, 0xB9,
0x45, 0x32, 0x34, 0xE6, 0x97, 0xA5, 0x45, 0x32,
0x34, 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x35, 0xE6,
0x97, 0xA5, 0x45, 0x32, 0x36, 0xE6, 0x97, 0xA5,
0x45, 0x32, 0x37, 0xE6, 0x97, 0xA5, 0x45, 0x32,
// Bytes 23c0 - 23ff
0x38, 0xE6, 0x97, 0xA5, 0x45, 0x32, 0x39, 0xE6,
0x97, 0xA5, 0x45, 0x32, 0xE2, 0x81, 0x84, 0x33,
0x45, 0x32, 0xE2, 0x81, 0x84, 0x35, 0x45, 0x33,
0x30, 0xE6, 0x97, 0xA5, 0x45, 0x33, 0x31, 0xE6,
0x97, 0xA5, 0x45, 0x33, 0xE2, 0x81, 0x84, 0x34,
0x45, 0x33, 0xE2, 0x81, 0x84, 0x35, 0x45, 0x33,
0xE2, 0x81, 0x84, 0x38, 0x45, 0x34, 0xE2, 0x81,
0x84, 0x35, 0x45, 0x35, 0xE2, 0x81, 0x84, 0x36,
// Bytes 2400 - 243f
0x45, 0x35, 0xE2, 0x81, 0x84, 0x38, 0x45, 0x37,
0xE2, 0x81, 0x84, 0x38, 0x45, 0x41, 0xE2, 0x88,
0x95, 0x6D, 0x45, 0x56, 0xE2, 0x88, 0x95, 0x6D,
0x45, 0x6D, 0xE2, 0x88, 0x95, 0x73, 0x46, 0x31,
0xE2, 0x81, 0x84, 0x31, 0x30, 0x46, 0x43, 0xE2,
0x88, 0x95, 0x6B, 0x67, 0x46, 0x6D, 0xE2, 0x88,
0x95, 0x73, 0x32, 0x46, 0xD8, 0xA8, 0xD8, 0xAD,
0xD9, 0x8A, 0x46, 0xD8, 0xA8, 0xD8, 0xAE, 0xD9,
// Bytes 2440 - 247f
0x8A, 0x46, 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x85,
0x46, 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x89, 0x46,
0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD8,
0xAA, 0xD8, 0xAD, 0xD8, 0xAC, 0x46, 0xD8, 0xAA,
0xD8, 0xAD, 0xD9, 0x85, 0x46, 0xD8, 0xAA, 0xD8,
0xAE, 0xD9, 0x85, 0x46, 0xD8, 0xAA, 0xD8, 0xAE,
0xD9, 0x89, 0x46, 0xD8, 0xAA, 0xD8, 0xAE, 0xD9,
0x8A, 0x46, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAC,
// Bytes 2480 - 24bf
0x46, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAD, 0x46,
0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAE, 0x46, 0xD8,
0xAA, 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8, 0xAA,
0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xAC, 0xD8,
0xAD, 0xD9, 0x89, 0x46, 0xD8, 0xAC, 0xD8, 0xAD,
0xD9, 0x8A, 0x46, 0xD8, 0xAC, 0xD9, 0x85, 0xD8,
0xAD, 0x46, 0xD8, 0xAC, 0xD9, 0x85, 0xD9, 0x89,
0x46, 0xD8, 0xAC, 0xD9, 0x85, 0xD9, 0x8A, 0x46,
// Bytes 24c0 - 24ff
0xD8, 0xAD, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD8,
0xAD, 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8, 0xAD,
0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xB3, 0xD8,
0xAC, 0xD8, 0xAD, 0x46, 0xD8, 0xB3, 0xD8, 0xAC,
0xD9, 0x89, 0x46, 0xD8, 0xB3, 0xD8, 0xAD, 0xD8,
0xAC, 0x46, 0xD8, 0xB3, 0xD8, 0xAE, 0xD9, 0x89,
0x46, 0xD8, 0xB3, 0xD8, 0xAE, 0xD9, 0x8A, 0x46,
0xD8, 0xB3, 0xD9, 0x85, 0xD8, 0xAC, 0x46, 0xD8,
// Bytes 2500 - 253f
0xB3, 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD8, 0xB3,
0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD8, 0xB4, 0xD8,
0xAC, 0xD9, 0x8A, 0x46, 0xD8, 0xB4, 0xD8, 0xAD,
0xD9, 0x85, 0x46, 0xD8, 0xB4, 0xD8, 0xAD, 0xD9,
0x8A, 0x46, 0xD8, 0xB4, 0xD9, 0x85, 0xD8, 0xAE,
0x46, 0xD8, 0xB4, 0xD9, 0x85, 0xD9, 0x85, 0x46,
0xD8, 0xB5, 0xD8, 0xAD, 0xD8, 0xAD, 0x46, 0xD8,
0xB5, 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD8, 0xB5,
// Bytes 2540 - 257f
0xD9, 0x84, 0xD9, 0x89, 0x46, 0xD8, 0xB5, 0xD9,
0x84, 0xDB, 0x92, 0x46, 0xD8, 0xB5, 0xD9, 0x85,
0xD9, 0x85, 0x46, 0xD8, 0xB6, 0xD8, 0xAD, 0xD9,
0x89, 0x46, 0xD8, 0xB6, 0xD8, 0xAD, 0xD9, 0x8A,
0x46, 0xD8, 0xB6, 0xD8, 0xAE, 0xD9, 0x85, 0x46,
0xD8, 0xB7, 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD8,
0xB7, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD8, 0xB7,
0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xB9, 0xD8,
// Bytes 2580 - 25bf
0xAC, 0xD9, 0x85, 0x46, 0xD8, 0xB9, 0xD9, 0x85,
0xD9, 0x85, 0x46, 0xD8, 0xB9, 0xD9, 0x85, 0xD9,
0x89, 0x46, 0xD8, 0xB9, 0xD9, 0x85, 0xD9, 0x8A,
0x46, 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x85, 0x46,
0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8,
0xBA, 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x81,
0xD8, 0xAE, 0xD9, 0x85, 0x46, 0xD9, 0x81, 0xD9,
0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x82, 0xD9, 0x84,
// Bytes 25c0 - 25ff
0xDB, 0x92, 0x46, 0xD9, 0x82, 0xD9, 0x85, 0xD8,
0xAD, 0x46, 0xD9, 0x82, 0xD9, 0x85, 0xD9, 0x85,
0x46, 0xD9, 0x82, 0xD9, 0x85, 0xD9, 0x8A, 0x46,
0xD9, 0x83, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD9,
0x83, 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x84,
0xD8, 0xAC, 0xD8, 0xAC, 0x46, 0xD9, 0x84, 0xD8,
0xAC, 0xD9, 0x85, 0x46, 0xD9, 0x84, 0xD8, 0xAC,
0xD9, 0x8A, 0x46, 0xD9, 0x84, 0xD8, 0xAD, 0xD9,
// Bytes 2600 - 263f
0x85, 0x46, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x89,
0x46, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x8A, 0x46,
0xD9, 0x84, 0xD8, 0xAE, 0xD9, 0x85, 0x46, 0xD9,
0x84, 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD9, 0x84,
0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x85, 0xD8,
0xAC, 0xD8, 0xAD, 0x46, 0xD9, 0x85, 0xD8, 0xAC,
0xD8, 0xAE, 0x46, 0xD9, 0x85, 0xD8, 0xAC, 0xD9,
0x85, 0x46, 0xD9, 0x85, 0xD8, 0xAC, 0xD9, 0x8A,
// Bytes 2640 - 267f
0x46, 0xD9, 0x85, 0xD8, 0xAD, 0xD8, 0xAC, 0x46,
0xD9, 0x85, 0xD8, 0xAD, 0xD9, 0x85, 0x46, 0xD9,
0x85, 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD9, 0x85,
0xD8, 0xAE, 0xD8, 0xAC, 0x46, 0xD9, 0x85, 0xD8,
0xAE, 0xD9, 0x85, 0x46, 0xD9, 0x85, 0xD8, 0xAE,
0xD9, 0x8A, 0x46, 0xD9, 0x85, 0xD9, 0x85, 0xD9,
0x8A, 0x46, 0xD9, 0x86, 0xD8, 0xAC, 0xD8, 0xAD,
0x46, 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x85, 0x46,
// Bytes 2680 - 26bf
0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x89, 0x46, 0xD9,
0x86, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD9, 0x86,
0xD8, 0xAD, 0xD9, 0x85, 0x46, 0xD9, 0x86, 0xD8,
0xAD, 0xD9, 0x89, 0x46, 0xD9, 0x86, 0xD8, 0xAD,
0xD9, 0x8A, 0x46, 0xD9, 0x86, 0xD9, 0x85, 0xD9,
0x89, 0x46, 0xD9, 0x86, 0xD9, 0x85, 0xD9, 0x8A,
0x46, 0xD9, 0x87, 0xD9, 0x85, 0xD8, 0xAC, 0x46,
0xD9, 0x87, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD9,
// Bytes 26c0 - 26ff
0x8A, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD9, 0x8A,
0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD9, 0x8A, 0xD9,
0x85, 0xD9, 0x85, 0x46, 0xD9, 0x8A, 0xD9, 0x85,
0xD9, 0x8A, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8,
0xA7, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAC,
0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAD, 0x46,
0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAE, 0x46, 0xD9,
0x8A, 0xD9, 0x94, 0xD8, 0xB1, 0x46, 0xD9, 0x8A,
// Bytes 2700 - 273f
0xD9, 0x94, 0xD8, 0xB2, 0x46, 0xD9, 0x8A, 0xD9,
0x94, 0xD9, 0x85, 0x46, 0xD9, 0x8A, 0xD9, 0x94,
0xD9, 0x86, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9,
0x87, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x88,
0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x89, 0x46,
0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x8A, 0x46, 0xD9,
0x8A, 0xD9, 0x94, 0xDB, 0x86, 0x46, 0xD9, 0x8A,
0xD9, 0x94, 0xDB, 0x87, 0x46, 0xD9, 0x8A, 0xD9,
// Bytes 2740 - 277f
0x94, 0xDB, 0x88, 0x46, 0xD9, 0x8A, 0xD9, 0x94,
0xDB, 0x90, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xDB,
0x95, 0x46, 0xE0, 0xB9, 0x8D, 0xE0, 0xB8, 0xB2,
0x46, 0xE0, 0xBA, 0xAB, 0xE0, 0xBA, 0x99, 0x46,
0xE0, 0xBA, 0xAB, 0xE0, 0xBA, 0xA1, 0x46, 0xE0,
0xBB, 0x8D, 0xE0, 0xBA, 0xB2, 0x46, 0xE0, 0xBD,
0x80, 0xE0, 0xBE, 0xB5, 0x46, 0xE0, 0xBD, 0x82,
0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBD, 0x8C, 0xE0,
// Bytes 2780 - 27bf
0xBE, 0xB7, 0x46, 0xE0, 0xBD, 0x91, 0xE0, 0xBE,
0xB7, 0x46, 0xE0, 0xBD, 0x96, 0xE0, 0xBE, 0xB7,
0x46, 0xE0, 0xBD, 0x9B, 0xE0, 0xBE, 0xB7, 0x46,
0xE0, 0xBE, 0x90, 0xE0, 0xBE, 0xB5, 0x46, 0xE0,
0xBE, 0x92, 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE,
0x9C, 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0xA1,
0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0xA6, 0xE0,
0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0xAB, 0xE0, 0xBE,
// Bytes 27c0 - 27ff
0xB7, 0x46, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2,
0x46, 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0x46,
0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0x46, 0xE2,
0x88, 0xAE, 0xE2, 0x88, 0xAE, 0x46, 0xE3, 0x81,
0xBB, 0xE3, 0x81, 0x8B, 0x46, 0xE3, 0x82, 0x88,
0xE3, 0x82, 0x8A, 0x46, 0xE3, 0x82, 0xAD, 0xE3,
0x83, 0xAD, 0x46, 0xE3, 0x82, 0xB3, 0xE3, 0x82,
0xB3, 0x46, 0xE3, 0x82, 0xB3, 0xE3, 0x83, 0x88,
// Bytes 2800 - 283f
0x46, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xB3, 0x46,
0xE3, 0x83, 0x8A, 0xE3, 0x83, 0x8E, 0x46, 0xE3,
0x83, 0x9B, 0xE3, 0x83, 0xB3, 0x46, 0xE3, 0x83,
0x9F, 0xE3, 0x83, 0xAA, 0x46, 0xE3, 0x83, 0xAA,
0xE3, 0x83, 0xA9, 0x46, 0xE3, 0x83, 0xAC, 0xE3,
0x83, 0xA0, 0x46, 0xE4, 0xBB, 0xA4, 0xE5, 0x92,
0x8C, 0x46, 0xE5, 0xA4, 0xA7, 0xE6, 0xAD, 0xA3,
0x46, 0xE5, 0xB9, 0xB3, 0xE6, 0x88, 0x90, 0x46,
// Bytes 2840 - 287f
0xE6, 0x98, 0x8E, 0xE6, 0xB2, 0xBB, 0x46, 0xE6,
0x98, 0xAD, 0xE5, 0x92, 0x8C, 0x47, 0x72, 0x61,
0x64, 0xE2, 0x88, 0x95, 0x73, 0x47, 0xE3, 0x80,
0x94, 0x53, 0xE3, 0x80, 0x95, 0x48, 0x28, 0xE1,
0x84, 0x80, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28,
0xE1, 0x84, 0x82, 0xE1, 0x85, 0xA1, 0x29, 0x48,
0x28, 0xE1, 0x84, 0x83, 0xE1, 0x85, 0xA1, 0x29,
0x48, 0x28, 0xE1, 0x84, 0x85, 0xE1, 0x85, 0xA1,
// Bytes 2880 - 28bf
0x29, 0x48, 0x28, 0xE1, 0x84, 0x86, 0xE1, 0x85,
0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x87, 0xE1,
0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x89,
0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84,
0x8B, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1,
0x84, 0x8C, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28,
0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xAE, 0x29, 0x48,
0x28, 0xE1, 0x84, 0x8E, 0xE1, 0x85, 0xA1, 0x29,
// Bytes 28c0 - 28ff
0x48, 0x28, 0xE1, 0x84, 0x8F, 0xE1, 0x85, 0xA1,
0x29, 0x48, 0x28, 0xE1, 0x84, 0x90, 0xE1, 0x85,
0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x91, 0xE1,
0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x92,
0xE1, 0x85, 0xA1, 0x29, 0x48, 0x72, 0x61, 0x64,
0xE2, 0x88, 0x95, 0x73, 0x32, 0x48, 0xD8, 0xA7,
0xD9, 0x83, 0xD8, 0xA8, 0xD8, 0xB1, 0x48, 0xD8,
0xA7, 0xD9, 0x84, 0xD9, 0x84, 0xD9, 0x87, 0x48,
// Bytes 2900 - 293f
0xD8, 0xB1, 0xD8, 0xB3, 0xD9, 0x88, 0xD9, 0x84,
0x48, 0xD8, 0xB1, 0xDB, 0x8C, 0xD8, 0xA7, 0xD9,
0x84, 0x48, 0xD8, 0xB5, 0xD9, 0x84, 0xD8, 0xB9,
0xD9, 0x85, 0x48, 0xD8, 0xB9, 0xD9, 0x84, 0xD9,
0x8A, 0xD9, 0x87, 0x48, 0xD9, 0x85, 0xD8, 0xAD,
0xD9, 0x85, 0xD8, 0xAF, 0x48, 0xD9, 0x88, 0xD8,
0xB3, 0xD9, 0x84, 0xD9, 0x85, 0x49, 0xE2, 0x80,
0xB2, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0x49,
// Bytes 2940 - 297f
0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0xE2, 0x80,
0xB5, 0x49, 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB,
0xE2, 0x88, 0xAB, 0x49, 0xE2, 0x88, 0xAE, 0xE2,
0x88, 0xAE, 0xE2, 0x88, 0xAE, 0x49, 0xE3, 0x80,
0x94, 0xE4, 0xB8, 0x89, 0xE3, 0x80, 0x95, 0x49,
0xE3, 0x80, 0x94, 0xE4, 0xBA, 0x8C, 0xE3, 0x80,
0x95, 0x49, 0xE3, 0x80, 0x94, 0xE5, 0x8B, 0x9D,
0xE3, 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, 0xE5,
// Bytes 2980 - 29bf
0xAE, 0x89, 0xE3, 0x80, 0x95, 0x49, 0xE3, 0x80,
0x94, 0xE6, 0x89, 0x93, 0xE3, 0x80, 0x95, 0x49,
0xE3, 0x80, 0x94, 0xE6, 0x95, 0x97, 0xE3, 0x80,
0x95, 0x49, 0xE3, 0x80, 0x94, 0xE6, 0x9C, 0xAC,
0xE3, 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, 0xE7,
0x82, 0xB9, 0xE3, 0x80, 0x95, 0x49, 0xE3, 0x80,
0x94, 0xE7, 0x9B, 0x97, 0xE3, 0x80, 0x95, 0x49,
0xE3, 0x82, 0xA2, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
// Bytes 29c0 - 29ff
0xAB, 0x49, 0xE3, 0x82, 0xA4, 0xE3, 0x83, 0xB3,
0xE3, 0x83, 0x81, 0x49, 0xE3, 0x82, 0xA6, 0xE3,
0x82, 0xA9, 0xE3, 0x83, 0xB3, 0x49, 0xE3, 0x82,
0xAA, 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xB9, 0x49,
0xE3, 0x82, 0xAA, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
0xA0, 0x49, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0xA4,
0xE3, 0x83, 0xAA, 0x49, 0xE3, 0x82, 0xB1, 0xE3,
0x83, 0xBC, 0xE3, 0x82, 0xB9, 0x49, 0xE3, 0x82,
// Bytes 2a00 - 2a3f
0xB3, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x8A, 0x49,
0xE3, 0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3, 0x83,
0x81, 0x49, 0xE3, 0x82, 0xBB, 0xE3, 0x83, 0xB3,
0xE3, 0x83, 0x88, 0x49, 0xE3, 0x83, 0x86, 0xE3,
0x82, 0x99, 0xE3, 0x82, 0xB7, 0x49, 0xE3, 0x83,
0x88, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB, 0x49,
0xE3, 0x83, 0x8E, 0xE3, 0x83, 0x83, 0xE3, 0x83,
0x88, 0x49, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0xA4,
// Bytes 2a40 - 2a7f
0xE3, 0x83, 0x84, 0x49, 0xE3, 0x83, 0x92, 0xE3,
0x82, 0x99, 0xE3, 0x83, 0xAB, 0x49, 0xE3, 0x83,
0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xB3, 0x49,
0xE3, 0x83, 0x95, 0xE3, 0x83, 0xA9, 0xE3, 0x83,
0xB3, 0x49, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A,
0xE3, 0x82, 0xBD, 0x49, 0xE3, 0x83, 0x98, 0xE3,
0x83, 0xAB, 0xE3, 0x83, 0x84, 0x49, 0xE3, 0x83,
0x9B, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAB, 0x49,
// Bytes 2a80 - 2abf
0xE3, 0x83, 0x9B, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
0xB3, 0x49, 0xE3, 0x83, 0x9E, 0xE3, 0x82, 0xA4,
0xE3, 0x83, 0xAB, 0x49, 0xE3, 0x83, 0x9E, 0xE3,
0x83, 0x83, 0xE3, 0x83, 0x8F, 0x49, 0xE3, 0x83,
0x9E, 0xE3, 0x83, 0xAB, 0xE3, 0x82, 0xAF, 0x49,
0xE3, 0x83, 0xA4, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
0xAB, 0x49, 0xE3, 0x83, 0xA6, 0xE3, 0x82, 0xA2,
0xE3, 0x83, 0xB3, 0x49, 0xE3, 0x83, 0xAF, 0xE3,
// Bytes 2ac0 - 2aff
0x83, 0x83, 0xE3, 0x83, 0x88, 0x4C, 0xE2, 0x80,
0xB2, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0xE2,
0x80, 0xB2, 0x4C, 0xE2, 0x88, 0xAB, 0xE2, 0x88,
0xAB, 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0x4C,
0xE3, 0x82, 0xA2, 0xE3, 0x83, 0xAB, 0xE3, 0x83,
0x95, 0xE3, 0x82, 0xA1, 0x4C, 0xE3, 0x82, 0xA8,
0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xAB, 0xE3, 0x83,
0xBC, 0x4C, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99,
// Bytes 2b00 - 2b3f
0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xB3, 0x4C, 0xE3,
0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xB3,
0xE3, 0x83, 0x9E, 0x4C, 0xE3, 0x82, 0xAB, 0xE3,
0x83, 0xA9, 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88,
0x4C, 0xE3, 0x82, 0xAB, 0xE3, 0x83, 0xAD, 0xE3,
0x83, 0xAA, 0xE3, 0x83, 0xBC, 0x4C, 0xE3, 0x82,
0xAD, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0x8B, 0xE3,
0x83, 0xBC, 0x4C, 0xE3, 0x82, 0xAD, 0xE3, 0x83,
// Bytes 2b40 - 2b7f
0xA5, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xBC, 0x4C,
0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x83,
0xA9, 0xE3, 0x83, 0xA0, 0x4C, 0xE3, 0x82, 0xAF,
0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
0x8D, 0x4C, 0xE3, 0x82, 0xB5, 0xE3, 0x82, 0xA4,
0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, 0x4C, 0xE3,
0x82, 0xBF, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC,
0xE3, 0x82, 0xB9, 0x4C, 0xE3, 0x83, 0x8F, 0xE3,
// Bytes 2b80 - 2bbf
0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x84,
0x4C, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3,
0x82, 0xAF, 0xE3, 0x83, 0xAB, 0x4C, 0xE3, 0x83,
0x95, 0xE3, 0x82, 0xA3, 0xE3, 0x83, 0xBC, 0xE3,
0x83, 0x88, 0x4C, 0xE3, 0x83, 0x98, 0xE3, 0x82,
0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xBF, 0x4C,
0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83,
0x8B, 0xE3, 0x83, 0x92, 0x4C, 0xE3, 0x83, 0x98,
// Bytes 2bc0 - 2bff
0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xB3, 0xE3, 0x82,
0xB9, 0x4C, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x99,
0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x88, 0x4C, 0xE3,
0x83, 0x9E, 0xE3, 0x82, 0xA4, 0xE3, 0x82, 0xAF,
0xE3, 0x83, 0xAD, 0x4C, 0xE3, 0x83, 0x9F, 0xE3,
0x82, 0xAF, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xB3,
0x4C, 0xE3, 0x83, 0xA1, 0xE3, 0x83, 0xBC, 0xE3,
0x83, 0x88, 0xE3, 0x83, 0xAB, 0x4C, 0xE3, 0x83,
// Bytes 2c00 - 2c3f
0xAA, 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88, 0xE3,
0x83, 0xAB, 0x4C, 0xE3, 0x83, 0xAB, 0xE3, 0x83,
0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0x4C,
0xE6, 0xA0, 0xAA, 0xE5, 0xBC, 0x8F, 0xE4, 0xBC,
0x9A, 0xE7, 0xA4, 0xBE, 0x4E, 0x28, 0xE1, 0x84,
0x8B, 0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x92, 0xE1,
0x85, 0xAE, 0x29, 0x4F, 0xD8, 0xAC, 0xD9, 0x84,
0x20, 0xD8, 0xAC, 0xD9, 0x84, 0xD8, 0xA7, 0xD9,
// Bytes 2c40 - 2c7f
0x84, 0xD9, 0x87, 0x4F, 0xE3, 0x82, 0xA2, 0xE3,
0x83, 0x8F, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC,
0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x82, 0xA2, 0xE3,
0x83, 0xB3, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A,
0xE3, 0x82, 0xA2, 0x4F, 0xE3, 0x82, 0xAD, 0xE3,
0x83, 0xAD, 0xE3, 0x83, 0xAF, 0xE3, 0x83, 0x83,
0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x82, 0xB5, 0xE3,
0x83, 0xB3, 0xE3, 0x83, 0x81, 0xE3, 0x83, 0xBC,
// Bytes 2c80 - 2cbf
0xE3, 0x83, 0xA0, 0x4F, 0xE3, 0x83, 0x8F, 0xE3,
0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAC,
0xE3, 0x83, 0xAB, 0x4F, 0xE3, 0x83, 0x98, 0xE3,
0x82, 0xAF, 0xE3, 0x82, 0xBF, 0xE3, 0x83, 0xBC,
0xE3, 0x83, 0xAB, 0x4F, 0xE3, 0x83, 0x9B, 0xE3,
0x82, 0x9A, 0xE3, 0x82, 0xA4, 0xE3, 0x83, 0xB3,
0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x83, 0x9E, 0xE3,
0x83, 0xB3, 0xE3, 0x82, 0xB7, 0xE3, 0x83, 0xA7,
// Bytes 2cc0 - 2cff
0xE3, 0x83, 0xB3, 0x4F, 0xE3, 0x83, 0xA1, 0xE3,
0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0x88,
0xE3, 0x83, 0xB3, 0x4F, 0xE3, 0x83, 0xAB, 0xE3,
0x83, 0xBC, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x99,
0xE3, 0x83, 0xAB, 0x51, 0x28, 0xE1, 0x84, 0x8B,
0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x8C, 0xE1, 0x85,
0xA5, 0xE1, 0x86, 0xAB, 0x29, 0x52, 0xE3, 0x82,
0xAD, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB, 0xE3,
// Bytes 2d00 - 2d3f
0x82, 0xBF, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC,
0x52, 0xE3, 0x82, 0xAD, 0xE3, 0x83, 0xAD, 0xE3,
0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xA9,
0xE3, 0x83, 0xA0, 0x52, 0xE3, 0x82, 0xAD, 0xE3,
0x83, 0xAD, 0xE3, 0x83, 0xA1, 0xE3, 0x83, 0xBC,
0xE3, 0x83, 0x88, 0xE3, 0x83, 0xAB, 0x52, 0xE3,
0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xA9,
0xE3, 0x83, 0xA0, 0xE3, 0x83, 0x88, 0xE3, 0x83,
// Bytes 2d40 - 2d7f
0xB3, 0x52, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB,
0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99, 0xE3, 0x82,
0xA4, 0xE3, 0x83, 0xAD, 0x52, 0xE3, 0x83, 0x8F,
0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3, 0x82,
0xBB, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x88, 0x52,
0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x82,
0xA2, 0xE3, 0x82, 0xB9, 0xE3, 0x83, 0x88, 0xE3,
0x83, 0xAB, 0x52, 0xE3, 0x83, 0x95, 0xE3, 0x82,
// Bytes 2d80 - 2dbf
0x99, 0xE3, 0x83, 0x83, 0xE3, 0x82, 0xB7, 0xE3,
0x82, 0xA7, 0xE3, 0x83, 0xAB, 0x52, 0xE3, 0x83,
0x9F, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0x8F, 0xE3,
0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAB,
0x52, 0xE3, 0x83, 0xAC, 0xE3, 0x83, 0xB3, 0xE3,
0x83, 0x88, 0xE3, 0x82, 0xB1, 0xE3, 0x82, 0x99,
0xE3, 0x83, 0xB3, 0x61, 0xD8, 0xB5, 0xD9, 0x84,
0xD9, 0x89, 0x20, 0xD8, 0xA7, 0xD9, 0x84, 0xD9,
// Bytes 2dc0 - 2dff
0x84, 0xD9, 0x87, 0x20, 0xD8, 0xB9, 0xD9, 0x84,
0xD9, 0x8A, 0xD9, 0x87, 0x20, 0xD9, 0x88, 0xD8,
0xB3, 0xD9, 0x84, 0xD9, 0x85, 0x06, 0xE0, 0xA7,
0x87, 0xE0, 0xA6, 0xBE, 0x01, 0x06, 0xE0, 0xA7,
0x87, 0xE0, 0xA7, 0x97, 0x01, 0x06, 0xE0, 0xAD,
0x87, 0xE0, 0xAC, 0xBE, 0x01, 0x06, 0xE0, 0xAD,
0x87, 0xE0, 0xAD, 0x96, 0x01, 0x06, 0xE0, 0xAD,
0x87, 0xE0, 0xAD, 0x97, 0x01, 0x06, 0xE0, 0xAE,
// Bytes 2e00 - 2e3f
0x92, 0xE0, 0xAF, 0x97, 0x01, 0x06, 0xE0, 0xAF,
0x86, 0xE0, 0xAE, 0xBE, 0x01, 0x06, 0xE0, 0xAF,
0x86, 0xE0, 0xAF, 0x97, 0x01, 0x06, 0xE0, 0xAF,
0x87, 0xE0, 0xAE, 0xBE, 0x01, 0x06, 0xE0, 0xB2,
0xBF, 0xE0, 0xB3, 0x95, 0x01, 0x06, 0xE0, 0xB3,
0x86, 0xE0, 0xB3, 0x95, 0x01, 0x06, 0xE0, 0xB3,
0x86, 0xE0, 0xB3, 0x96, 0x01, 0x06, 0xE0, 0xB5,
0x86, 0xE0, 0xB4, 0xBE, 0x01, 0x06, 0xE0, 0xB5,
// Bytes 2e40 - 2e7f
0x86, 0xE0, 0xB5, 0x97, 0x01, 0x06, 0xE0, 0xB5,
0x87, 0xE0, 0xB4, 0xBE, 0x01, 0x06, 0xE0, 0xB7,
0x99, 0xE0, 0xB7, 0x9F, 0x01, 0x06, 0xE1, 0x80,
0xA5, 0xE1, 0x80, 0xAE, 0x01, 0x06, 0xE1, 0xAC,
0x85, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, 0xAC,
0x87, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, 0xAC,
0x89, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, 0xAC,
0x8B, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, 0xAC,
// Bytes 2e80 - 2ebf
0x8D, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, 0xAC,
0x91, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, 0xAC,
0xBA, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, 0xAC,
0xBC, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, 0xAC,
0xBE, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, 0xAC,
0xBF, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, 0xAD,
0x82, 0xE1, 0xAC, 0xB5, 0x01, 0x08, 0xF0, 0x91,
0x84, 0xB1, 0xF0, 0x91, 0x84, 0xA7, 0x01, 0x08,
// Bytes 2ec0 - 2eff
0xF0, 0x91, 0x84, 0xB2, 0xF0, 0x91, 0x84, 0xA7,
0x01, 0x08, 0xF0, 0x91, 0x8D, 0x87, 0xF0, 0x91,
0x8C, 0xBE, 0x01, 0x08, 0xF0, 0x91, 0x8D, 0x87,
0xF0, 0x91, 0x8D, 0x97, 0x01, 0x08, 0xF0, 0x91,
0x92, 0xB9, 0xF0, 0x91, 0x92, 0xB0, 0x01, 0x08,
0xF0, 0x91, 0x92, 0xB9, 0xF0, 0x91, 0x92, 0xBA,
0x01, 0x08, 0xF0, 0x91, 0x92, 0xB9, 0xF0, 0x91,
0x92, 0xBD, 0x01, 0x08, 0xF0, 0x91, 0x96, 0xB8,
// Bytes 2f00 - 2f3f
0xF0, 0x91, 0x96, 0xAF, 0x01, 0x08, 0xF0, 0x91,
0x96, 0xB9, 0xF0, 0x91, 0x96, 0xAF, 0x01, 0x08,
0xF0, 0x91, 0xA4, 0xB5, 0xF0, 0x91, 0xA4, 0xB0,
0x01, 0x09, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x82,
0xE0, 0xB3, 0x95, 0x02, 0x09, 0xE0, 0xB7, 0x99,
0xE0, 0xB7, 0x8F, 0xE0, 0xB7, 0x8A, 0x16, 0x44,
0x44, 0x5A, 0xCC, 0x8C, 0xCD, 0x44, 0x44, 0x7A,
0xCC, 0x8C, 0xCD, 0x44, 0x64, 0x7A, 0xCC, 0x8C,
// Bytes 2f40 - 2f7f
0xCD, 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x93,
0xCD, 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x94,
0xCD, 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x95,
0xB9, 0x46, 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xA1,
0x01, 0x46, 0xE1, 0x84, 0x82, 0xE1, 0x85, 0xA1,
0x01, 0x46, 0xE1, 0x84, 0x83, 0xE1, 0x85, 0xA1,
0x01, 0x46, 0xE1, 0x84, 0x85, 0xE1, 0x85, 0xA1,
0x01, 0x46, 0xE1, 0x84, 0x86, 0xE1, 0x85, 0xA1,
// Bytes 2f80 - 2fbf
0x01, 0x46, 0xE1, 0x84, 0x87, 0xE1, 0x85, 0xA1,
0x01, 0x46, 0xE1, 0x84, 0x89, 0xE1, 0x85, 0xA1,
0x01, 0x46, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xA1,
0x01, 0x46, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xAE,
0x01, 0x46, 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xA1,
0x01, 0x46, 0xE1, 0x84, 0x8E, 0xE1, 0x85, 0xA1,
0x01, 0x46, 0xE1, 0x84, 0x8F, 0xE1, 0x85, 0xA1,
0x01, 0x46, 0xE1, 0x84, 0x90, 0xE1, 0x85, 0xA1,
// Bytes 2fc0 - 2fff
0x01, 0x46, 0xE1, 0x84, 0x91, 0xE1, 0x85, 0xA1,
0x01, 0x46, 0xE1, 0x84, 0x92, 0xE1, 0x85, 0xA1,
0x01, 0x49, 0xE3, 0x83, 0xA1, 0xE3, 0x82, 0xAB,
0xE3, 0x82, 0x99, 0x11, 0x4C, 0xE1, 0x84, 0x8C,
0xE1, 0x85, 0xAE, 0xE1, 0x84, 0x8B, 0xE1, 0x85,
0xB4, 0x01, 0x4C, 0xE3, 0x82, 0xAD, 0xE3, 0x82,
0x99, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x11,
0x4C, 0xE3, 0x82, 0xB3, 0xE3, 0x83, 0xBC, 0xE3,
// Bytes 3000 - 303f
0x83, 0x9B, 0xE3, 0x82, 0x9A, 0x11, 0x4C, 0xE3,
0x83, 0xA4, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88,
0xE3, 0x82, 0x99, 0x11, 0x4F, 0xE1, 0x84, 0x8E,
0xE1, 0x85, 0xA1, 0xE1, 0x86, 0xB7, 0xE1, 0x84,
0x80, 0xE1, 0x85, 0xA9, 0x01, 0x4F, 0xE3, 0x82,
0xA4, 0xE3, 0x83, 0x8B, 0xE3, 0x83, 0xB3, 0xE3,
0x82, 0xAF, 0xE3, 0x82, 0x99, 0x11, 0x4F, 0xE3,
0x82, 0xB7, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xB3,
// Bytes 3040 - 307f
0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x11, 0x4F,
0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83,
0xBC, 0xE3, 0x82, 0xB7, 0xE3, 0x82, 0x99, 0x11,
0x4F, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0xE3,
0x83, 0xB3, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99,
0x11, 0x52, 0xE3, 0x82, 0xA8, 0xE3, 0x82, 0xB9,
0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
0x88, 0xE3, 0x82, 0x99, 0x11, 0x52, 0xE3, 0x83,
// Bytes 3080 - 30bf
0x95, 0xE3, 0x82, 0xA1, 0xE3, 0x83, 0xA9, 0xE3,
0x83, 0x83, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99,
0x11, 0x86, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x82,
0x01, 0x86, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x8F,
0x01, 0x03, 0x3C, 0xCC, 0xB8, 0x05, 0x03, 0x3D,
0xCC, 0xB8, 0x05, 0x03, 0x3E, 0xCC, 0xB8, 0x05,
0x03, 0x41, 0xCC, 0x80, 0xCD, 0x03, 0x41, 0xCC,
0x81, 0xCD, 0x03, 0x41, 0xCC, 0x83, 0xCD, 0x03,
// Bytes 30c0 - 30ff
0x41, 0xCC, 0x84, 0xCD, 0x03, 0x41, 0xCC, 0x89,
0xCD, 0x03, 0x41, 0xCC, 0x8C, 0xCD, 0x03, 0x41,
0xCC, 0x8F, 0xCD, 0x03, 0x41, 0xCC, 0x91, 0xCD,
0x03, 0x41, 0xCC, 0xA5, 0xB9, 0x03, 0x41, 0xCC,
0xA8, 0xA9, 0x03, 0x42, 0xCC, 0x87, 0xCD, 0x03,
0x42, 0xCC, 0xA3, 0xB9, 0x03, 0x42, 0xCC, 0xB1,
0xB9, 0x03, 0x43, 0xCC, 0x81, 0xCD, 0x03, 0x43,
0xCC, 0x82, 0xCD, 0x03, 0x43, 0xCC, 0x87, 0xCD,
// Bytes 3100 - 313f
0x03, 0x43, 0xCC, 0x8C, 0xCD, 0x03, 0x44, 0xCC,
0x87, 0xCD, 0x03, 0x44, 0xCC, 0x8C, 0xCD, 0x03,
0x44, 0xCC, 0xA3, 0xB9, 0x03, 0x44, 0xCC, 0xA7,
0xA9, 0x03, 0x44, 0xCC, 0xAD, 0xB9, 0x03, 0x44,
0xCC, 0xB1, 0xB9, 0x03, 0x45, 0xCC, 0x80, 0xCD,
0x03, 0x45, 0xCC, 0x81, 0xCD, 0x03, 0x45, 0xCC,
0x83, 0xCD, 0x03, 0x45, 0xCC, 0x86, 0xCD, 0x03,
0x45, 0xCC, 0x87, 0xCD, 0x03, 0x45, 0xCC, 0x88,
// Bytes 3140 - 317f
0xCD, 0x03, 0x45, 0xCC, 0x89, 0xCD, 0x03, 0x45,
0xCC, 0x8C, 0xCD, 0x03, 0x45, 0xCC, 0x8F, 0xCD,
0x03, 0x45, 0xCC, 0x91, 0xCD, 0x03, 0x45, 0xCC,
0xA8, 0xA9, 0x03, 0x45, 0xCC, 0xAD, 0xB9, 0x03,
0x45, 0xCC, 0xB0, 0xB9, 0x03, 0x46, 0xCC, 0x87,
0xCD, 0x03, 0x47, 0xCC, 0x81, 0xCD, 0x03, 0x47,
0xCC, 0x82, 0xCD, 0x03, 0x47, 0xCC, 0x84, 0xCD,
0x03, 0x47, 0xCC, 0x86, 0xCD, 0x03, 0x47, 0xCC,
// Bytes 3180 - 31bf
0x87, 0xCD, 0x03, 0x47, 0xCC, 0x8C, 0xCD, 0x03,
0x47, 0xCC, 0xA7, 0xA9, 0x03, 0x48, 0xCC, 0x82,
0xCD, 0x03, 0x48, 0xCC, 0x87, 0xCD, 0x03, 0x48,
0xCC, 0x88, 0xCD, 0x03, 0x48, 0xCC, 0x8C, 0xCD,
0x03, 0x48, 0xCC, 0xA3, 0xB9, 0x03, 0x48, 0xCC,
0xA7, 0xA9, 0x03, 0x48, 0xCC, 0xAE, 0xB9, 0x03,
0x49, 0xCC, 0x80, 0xCD, 0x03, 0x49, 0xCC, 0x81,
0xCD, 0x03, 0x49, 0xCC, 0x82, 0xCD, 0x03, 0x49,
// Bytes 31c0 - 31ff
0xCC, 0x83, 0xCD, 0x03, 0x49, 0xCC, 0x84, 0xCD,
0x03, 0x49, 0xCC, 0x86, 0xCD, 0x03, 0x49, 0xCC,
0x87, 0xCD, 0x03, 0x49, 0xCC, 0x89, 0xCD, 0x03,
0x49, 0xCC, 0x8C, 0xCD, 0x03, 0x49, 0xCC, 0x8F,
0xCD, 0x03, 0x49, 0xCC, 0x91, 0xCD, 0x03, 0x49,
0xCC, 0xA3, 0xB9, 0x03, 0x49, 0xCC, 0xA8, 0xA9,
0x03, 0x49, 0xCC, 0xB0, 0xB9, 0x03, 0x4A, 0xCC,
0x82, 0xCD, 0x03, 0x4B, 0xCC, 0x81, 0xCD, 0x03,
// Bytes 3200 - 323f
0x4B, 0xCC, 0x8C, 0xCD, 0x03, 0x4B, 0xCC, 0xA3,
0xB9, 0x03, 0x4B, 0xCC, 0xA7, 0xA9, 0x03, 0x4B,
0xCC, 0xB1, 0xB9, 0x03, 0x4C, 0xCC, 0x81, 0xCD,
0x03, 0x4C, 0xCC, 0x8C, 0xCD, 0x03, 0x4C, 0xCC,
0xA7, 0xA9, 0x03, 0x4C, 0xCC, 0xAD, 0xB9, 0x03,
0x4C, 0xCC, 0xB1, 0xB9, 0x03, 0x4D, 0xCC, 0x81,
0xCD, 0x03, 0x4D, 0xCC, 0x87, 0xCD, 0x03, 0x4D,
0xCC, 0xA3, 0xB9, 0x03, 0x4E, 0xCC, 0x80, 0xCD,
// Bytes 3240 - 327f
0x03, 0x4E, 0xCC, 0x81, 0xCD, 0x03, 0x4E, 0xCC,
0x83, 0xCD, 0x03, 0x4E, 0xCC, 0x87, 0xCD, 0x03,
0x4E, 0xCC, 0x8C, 0xCD, 0x03, 0x4E, 0xCC, 0xA3,
0xB9, 0x03, 0x4E, 0xCC, 0xA7, 0xA9, 0x03, 0x4E,
0xCC, 0xAD, 0xB9, 0x03, 0x4E, 0xCC, 0xB1, 0xB9,
0x03, 0x4F, 0xCC, 0x80, 0xCD, 0x03, 0x4F, 0xCC,
0x81, 0xCD, 0x03, 0x4F, 0xCC, 0x86, 0xCD, 0x03,
0x4F, 0xCC, 0x89, 0xCD, 0x03, 0x4F, 0xCC, 0x8B,
// Bytes 3280 - 32bf
0xCD, 0x03, 0x4F, 0xCC, 0x8C, 0xCD, 0x03, 0x4F,
0xCC, 0x8F, 0xCD, 0x03, 0x4F, 0xCC, 0x91, 0xCD,
0x03, 0x50, 0xCC, 0x81, 0xCD, 0x03, 0x50, 0xCC,
0x87, 0xCD, 0x03, 0x52, 0xCC, 0x81, 0xCD, 0x03,
0x52, 0xCC, 0x87, 0xCD, 0x03, 0x52, 0xCC, 0x8C,
0xCD, 0x03, 0x52, 0xCC, 0x8F, 0xCD, 0x03, 0x52,
0xCC, 0x91, 0xCD, 0x03, 0x52, 0xCC, 0xA7, 0xA9,
0x03, 0x52, 0xCC, 0xB1, 0xB9, 0x03, 0x53, 0xCC,
// Bytes 32c0 - 32ff
0x82, 0xCD, 0x03, 0x53, 0xCC, 0x87, 0xCD, 0x03,
0x53, 0xCC, 0xA6, 0xB9, 0x03, 0x53, 0xCC, 0xA7,
0xA9, 0x03, 0x54, 0xCC, 0x87, 0xCD, 0x03, 0x54,
0xCC, 0x8C, 0xCD, 0x03, 0x54, 0xCC, 0xA3, 0xB9,
0x03, 0x54, 0xCC, 0xA6, 0xB9, 0x03, 0x54, 0xCC,
0xA7, 0xA9, 0x03, 0x54, 0xCC, 0xAD, 0xB9, 0x03,
0x54, 0xCC, 0xB1, 0xB9, 0x03, 0x55, 0xCC, 0x80,
0xCD, 0x03, 0x55, 0xCC, 0x81, 0xCD, 0x03, 0x55,
// Bytes 3300 - 333f
0xCC, 0x82, 0xCD, 0x03, 0x55, 0xCC, 0x86, 0xCD,
0x03, 0x55, 0xCC, 0x89, 0xCD, 0x03, 0x55, 0xCC,
0x8A, 0xCD, 0x03, 0x55, 0xCC, 0x8B, 0xCD, 0x03,
0x55, 0xCC, 0x8C, 0xCD, 0x03, 0x55, 0xCC, 0x8F,
0xCD, 0x03, 0x55, 0xCC, 0x91, 0xCD, 0x03, 0x55,
0xCC, 0xA3, 0xB9, 0x03, 0x55, 0xCC, 0xA4, 0xB9,
0x03, 0x55, 0xCC, 0xA8, 0xA9, 0x03, 0x55, 0xCC,
0xAD, 0xB9, 0x03, 0x55, 0xCC, 0xB0, 0xB9, 0x03,
// Bytes 3340 - 337f
0x56, 0xCC, 0x83, 0xCD, 0x03, 0x56, 0xCC, 0xA3,
0xB9, 0x03, 0x57, 0xCC, 0x80, 0xCD, 0x03, 0x57,
0xCC, 0x81, 0xCD, 0x03, 0x57, 0xCC, 0x82, 0xCD,
0x03, 0x57, 0xCC, 0x87, 0xCD, 0x03, 0x57, 0xCC,
0x88, 0xCD, 0x03, 0x57, 0xCC, 0xA3, 0xB9, 0x03,
0x58, 0xCC, 0x87, 0xCD, 0x03, 0x58, 0xCC, 0x88,
0xCD, 0x03, 0x59, 0xCC, 0x80, 0xCD, 0x03, 0x59,
0xCC, 0x81, 0xCD, 0x03, 0x59, 0xCC, 0x82, 0xCD,
// Bytes 3380 - 33bf
0x03, 0x59, 0xCC, 0x83, 0xCD, 0x03, 0x59, 0xCC,
0x84, 0xCD, 0x03, 0x59, 0xCC, 0x87, 0xCD, 0x03,
0x59, 0xCC, 0x88, 0xCD, 0x03, 0x59, 0xCC, 0x89,
0xCD, 0x03, 0x59, 0xCC, 0xA3, 0xB9, 0x03, 0x5A,
0xCC, 0x81, 0xCD, 0x03, 0x5A, 0xCC, 0x82, 0xCD,
0x03, 0x5A, 0xCC, 0x87, 0xCD, 0x03, 0x5A, 0xCC,
0x8C, 0xCD, 0x03, 0x5A, 0xCC, 0xA3, 0xB9, 0x03,
0x5A, 0xCC, 0xB1, 0xB9, 0x03, 0x61, 0xCC, 0x80,
// Bytes 33c0 - 33ff
0xCD, 0x03, 0x61, 0xCC, 0x81, 0xCD, 0x03, 0x61,
0xCC, 0x83, 0xCD, 0x03, 0x61, 0xCC, 0x84, 0xCD,
0x03, 0x61, 0xCC, 0x89, 0xCD, 0x03, 0x61, 0xCC,
0x8C, 0xCD, 0x03, 0x61, 0xCC, 0x8F, 0xCD, 0x03,
0x61, 0xCC, 0x91, 0xCD, 0x03, 0x61, 0xCC, 0xA5,
0xB9, 0x03, 0x61, 0xCC, 0xA8, 0xA9, 0x03, 0x62,
0xCC, 0x87, 0xCD, 0x03, 0x62, 0xCC, 0xA3, 0xB9,
0x03, 0x62, 0xCC, 0xB1, 0xB9, 0x03, 0x63, 0xCC,
// Bytes 3400 - 343f
0x81, 0xCD, 0x03, 0x63, 0xCC, 0x82, 0xCD, 0x03,
0x63, 0xCC, 0x87, 0xCD, 0x03, 0x63, 0xCC, 0x8C,
0xCD, 0x03, 0x64, 0xCC, 0x87, 0xCD, 0x03, 0x64,
0xCC, 0x8C, 0xCD, 0x03, 0x64, 0xCC, 0xA3, 0xB9,
0x03, 0x64, 0xCC, 0xA7, 0xA9, 0x03, 0x64, 0xCC,
0xAD, 0xB9, 0x03, 0x64, 0xCC, 0xB1, 0xB9, 0x03,
0x65, 0xCC, 0x80, 0xCD, 0x03, 0x65, 0xCC, 0x81,
0xCD, 0x03, 0x65, 0xCC, 0x83, 0xCD, 0x03, 0x65,
// Bytes 3440 - 347f
0xCC, 0x86, 0xCD, 0x03, 0x65, 0xCC, 0x87, 0xCD,
0x03, 0x65, 0xCC, 0x88, 0xCD, 0x03, 0x65, 0xCC,
0x89, 0xCD, 0x03, 0x65, 0xCC, 0x8C, 0xCD, 0x03,
0x65, 0xCC, 0x8F, 0xCD, 0x03, 0x65, 0xCC, 0x91,
0xCD, 0x03, 0x65, 0xCC, 0xA8, 0xA9, 0x03, 0x65,
0xCC, 0xAD, 0xB9, 0x03, 0x65, 0xCC, 0xB0, 0xB9,
0x03, 0x66, 0xCC, 0x87, 0xCD, 0x03, 0x67, 0xCC,
0x81, 0xCD, 0x03, 0x67, 0xCC, 0x82, 0xCD, 0x03,
// Bytes 3480 - 34bf
0x67, 0xCC, 0x84, 0xCD, 0x03, 0x67, 0xCC, 0x86,
0xCD, 0x03, 0x67, 0xCC, 0x87, 0xCD, 0x03, 0x67,
0xCC, 0x8C, 0xCD, 0x03, 0x67, 0xCC, 0xA7, 0xA9,
0x03, 0x68, 0xCC, 0x82, 0xCD, 0x03, 0x68, 0xCC,
0x87, 0xCD, 0x03, 0x68, 0xCC, 0x88, 0xCD, 0x03,
0x68, 0xCC, 0x8C, 0xCD, 0x03, 0x68, 0xCC, 0xA3,
0xB9, 0x03, 0x68, 0xCC, 0xA7, 0xA9, 0x03, 0x68,
0xCC, 0xAE, 0xB9, 0x03, 0x68, 0xCC, 0xB1, 0xB9,
// Bytes 34c0 - 34ff
0x03, 0x69, 0xCC, 0x80, 0xCD, 0x03, 0x69, 0xCC,
0x81, 0xCD, 0x03, 0x69, 0xCC, 0x82, 0xCD, 0x03,
0x69, 0xCC, 0x83, 0xCD, 0x03, 0x69, 0xCC, 0x84,
0xCD, 0x03, 0x69, 0xCC, 0x86, 0xCD, 0x03, 0x69,
0xCC, 0x89, 0xCD, 0x03, 0x69, 0xCC, 0x8C, 0xCD,
0x03, 0x69, 0xCC, 0x8F, 0xCD, 0x03, 0x69, 0xCC,
0x91, 0xCD, 0x03, 0x69, 0xCC, 0xA3, 0xB9, 0x03,
0x69, 0xCC, 0xA8, 0xA9, 0x03, 0x69, 0xCC, 0xB0,
// Bytes 3500 - 353f
0xB9, 0x03, 0x6A, 0xCC, 0x82, 0xCD, 0x03, 0x6A,
0xCC, 0x8C, 0xCD, 0x03, 0x6B, 0xCC, 0x81, 0xCD,
0x03, 0x6B, 0xCC, 0x8C, 0xCD, 0x03, 0x6B, 0xCC,
0xA3, 0xB9, 0x03, 0x6B, 0xCC, 0xA7, 0xA9, 0x03,
0x6B, 0xCC, 0xB1, 0xB9, 0x03, 0x6C, 0xCC, 0x81,
0xCD, 0x03, 0x6C, 0xCC, 0x8C, 0xCD, 0x03, 0x6C,
0xCC, 0xA7, 0xA9, 0x03, 0x6C, 0xCC, 0xAD, 0xB9,
0x03, 0x6C, 0xCC, 0xB1, 0xB9, 0x03, 0x6D, 0xCC,
// Bytes 3540 - 357f
0x81, 0xCD, 0x03, 0x6D, 0xCC, 0x87, 0xCD, 0x03,
0x6D, 0xCC, 0xA3, 0xB9, 0x03, 0x6E, 0xCC, 0x80,
0xCD, 0x03, 0x6E, 0xCC, 0x81, 0xCD, 0x03, 0x6E,
0xCC, 0x83, 0xCD, 0x03, 0x6E, 0xCC, 0x87, 0xCD,
0x03, 0x6E, 0xCC, 0x8C, 0xCD, 0x03, 0x6E, 0xCC,
0xA3, 0xB9, 0x03, 0x6E, 0xCC, 0xA7, 0xA9, 0x03,
0x6E, 0xCC, 0xAD, 0xB9, 0x03, 0x6E, 0xCC, 0xB1,
0xB9, 0x03, 0x6F, 0xCC, 0x80, 0xCD, 0x03, 0x6F,
// Bytes 3580 - 35bf
0xCC, 0x81, 0xCD, 0x03, 0x6F, 0xCC, 0x86, 0xCD,
0x03, 0x6F, 0xCC, 0x89, 0xCD, 0x03, 0x6F, 0xCC,
0x8B, 0xCD, 0x03, 0x6F, 0xCC, 0x8C, 0xCD, 0x03,
0x6F, 0xCC, 0x8F, 0xCD, 0x03, 0x6F, 0xCC, 0x91,
0xCD, 0x03, 0x70, 0xCC, 0x81, 0xCD, 0x03, 0x70,
0xCC, 0x87, 0xCD, 0x03, 0x72, 0xCC, 0x81, 0xCD,
0x03, 0x72, 0xCC, 0x87, 0xCD, 0x03, 0x72, 0xCC,
0x8C, 0xCD, 0x03, 0x72, 0xCC, 0x8F, 0xCD, 0x03,
// Bytes 35c0 - 35ff
0x72, 0xCC, 0x91, 0xCD, 0x03, 0x72, 0xCC, 0xA7,
0xA9, 0x03, 0x72, 0xCC, 0xB1, 0xB9, 0x03, 0x73,
0xCC, 0x82, 0xCD, 0x03, 0x73, 0xCC, 0x87, 0xCD,
0x03, 0x73, 0xCC, 0xA6, 0xB9, 0x03, 0x73, 0xCC,
0xA7, 0xA9, 0x03, 0x74, 0xCC, 0x87, 0xCD, 0x03,
0x74, 0xCC, 0x88, 0xCD, 0x03, 0x74, 0xCC, 0x8C,
0xCD, 0x03, 0x74, 0xCC, 0xA3, 0xB9, 0x03, 0x74,
0xCC, 0xA6, 0xB9, 0x03, 0x74, 0xCC, 0xA7, 0xA9,
// Bytes 3600 - 363f
0x03, 0x74, 0xCC, 0xAD, 0xB9, 0x03, 0x74, 0xCC,
0xB1, 0xB9, 0x03, 0x75, 0xCC, 0x80, 0xCD, 0x03,
0x75, 0xCC, 0x81, 0xCD, 0x03, 0x75, 0xCC, 0x82,
0xCD, 0x03, 0x75, 0xCC, 0x86, 0xCD, 0x03, 0x75,
0xCC, 0x89, 0xCD, 0x03, 0x75, 0xCC, 0x8A, 0xCD,
0x03, 0x75, 0xCC, 0x8B, 0xCD, 0x03, 0x75, 0xCC,
0x8C, 0xCD, 0x03, 0x75, 0xCC, 0x8F, 0xCD, 0x03,
0x75, 0xCC, 0x91, 0xCD, 0x03, 0x75, 0xCC, 0xA3,
// Bytes 3640 - 367f
0xB9, 0x03, 0x75, 0xCC, 0xA4, 0xB9, 0x03, 0x75,
0xCC, 0xA8, 0xA9, 0x03, 0x75, 0xCC, 0xAD, 0xB9,
0x03, 0x75, 0xCC, 0xB0, 0xB9, 0x03, 0x76, 0xCC,
0x83, 0xCD, 0x03, 0x76, 0xCC, 0xA3, 0xB9, 0x03,
0x77, 0xCC, 0x80, 0xCD, 0x03, 0x77, 0xCC, 0x81,
0xCD, 0x03, 0x77, 0xCC, 0x82, 0xCD, 0x03, 0x77,
0xCC, 0x87, 0xCD, 0x03, 0x77, 0xCC, 0x88, 0xCD,
0x03, 0x77, 0xCC, 0x8A, 0xCD, 0x03, 0x77, 0xCC,
// Bytes 3680 - 36bf
0xA3, 0xB9, 0x03, 0x78, 0xCC, 0x87, 0xCD, 0x03,
0x78, 0xCC, 0x88, 0xCD, 0x03, 0x79, 0xCC, 0x80,
0xCD, 0x03, 0x79, 0xCC, 0x81, 0xCD, 0x03, 0x79,
0xCC, 0x82, 0xCD, 0x03, 0x79, 0xCC, 0x83, 0xCD,
0x03, 0x79, 0xCC, 0x84, 0xCD, 0x03, 0x79, 0xCC,
0x87, 0xCD, 0x03, 0x79, 0xCC, 0x88, 0xCD, 0x03,
0x79, 0xCC, 0x89, 0xCD, 0x03, 0x79, 0xCC, 0x8A,
0xCD, 0x03, 0x79, 0xCC, 0xA3, 0xB9, 0x03, 0x7A,
// Bytes 36c0 - 36ff
0xCC, 0x81, 0xCD, 0x03, 0x7A, 0xCC, 0x82, 0xCD,
0x03, 0x7A, 0xCC, 0x87, 0xCD, 0x03, 0x7A, 0xCC,
0x8C, 0xCD, 0x03, 0x7A, 0xCC, 0xA3, 0xB9, 0x03,
0x7A, 0xCC, 0xB1, 0xB9, 0x04, 0xC2, 0xA8, 0xCC,
0x80, 0xCE, 0x04, 0xC2, 0xA8, 0xCC, 0x81, 0xCE,
0x04, 0xC2, 0xA8, 0xCD, 0x82, 0xCE, 0x04, 0xC3,
0x86, 0xCC, 0x81, 0xCD, 0x04, 0xC3, 0x86, 0xCC,
0x84, 0xCD, 0x04, 0xC3, 0x98, 0xCC, 0x81, 0xCD,
// Bytes 3700 - 373f
0x04, 0xC3, 0xA6, 0xCC, 0x81, 0xCD, 0x04, 0xC3,
0xA6, 0xCC, 0x84, 0xCD, 0x04, 0xC3, 0xB8, 0xCC,
0x81, 0xCD, 0x04, 0xC5, 0xBF, 0xCC, 0x87, 0xCD,
0x04, 0xC6, 0xB7, 0xCC, 0x8C, 0xCD, 0x04, 0xCA,
0x92, 0xCC, 0x8C, 0xCD, 0x04, 0xCE, 0x91, 0xCC,
0x80, 0xCD, 0x04, 0xCE, 0x91, 0xCC, 0x81, 0xCD,
0x04, 0xCE, 0x91, 0xCC, 0x84, 0xCD, 0x04, 0xCE,
0x91, 0xCC, 0x86, 0xCD, 0x04, 0xCE, 0x91, 0xCD,
// Bytes 3740 - 377f
0x85, 0xDD, 0x04, 0xCE, 0x95, 0xCC, 0x80, 0xCD,
0x04, 0xCE, 0x95, 0xCC, 0x81, 0xCD, 0x04, 0xCE,
0x97, 0xCC, 0x80, 0xCD, 0x04, 0xCE, 0x97, 0xCC,
0x81, 0xCD, 0x04, 0xCE, 0x97, 0xCD, 0x85, 0xDD,
0x04, 0xCE, 0x99, 0xCC, 0x80, 0xCD, 0x04, 0xCE,
0x99, 0xCC, 0x81, 0xCD, 0x04, 0xCE, 0x99, 0xCC,
0x84, 0xCD, 0x04, 0xCE, 0x99, 0xCC, 0x86, 0xCD,
0x04, 0xCE, 0x99, 0xCC, 0x88, 0xCD, 0x04, 0xCE,
// Bytes 3780 - 37bf
0x9F, 0xCC, 0x80, 0xCD, 0x04, 0xCE, 0x9F, 0xCC,
0x81, 0xCD, 0x04, 0xCE, 0xA1, 0xCC, 0x94, 0xCD,
0x04, 0xCE, 0xA5, 0xCC, 0x80, 0xCD, 0x04, 0xCE,
0xA5, 0xCC, 0x81, 0xCD, 0x04, 0xCE, 0xA5, 0xCC,
0x84, 0xCD, 0x04, 0xCE, 0xA5, 0xCC, 0x86, 0xCD,
0x04, 0xCE, 0xA5, 0xCC, 0x88, 0xCD, 0x04, 0xCE,
0xA9, 0xCC, 0x80, 0xCD, 0x04, 0xCE, 0xA9, 0xCC,
0x81, 0xCD, 0x04, 0xCE, 0xA9, 0xCD, 0x85, 0xDD,
// Bytes 37c0 - 37ff
0x04, 0xCE, 0xB1, 0xCC, 0x84, 0xCD, 0x04, 0xCE,
0xB1, 0xCC, 0x86, 0xCD, 0x04, 0xCE, 0xB1, 0xCD,
0x85, 0xDD, 0x04, 0xCE, 0xB5, 0xCC, 0x80, 0xCD,
0x04, 0xCE, 0xB5, 0xCC, 0x81, 0xCD, 0x04, 0xCE,
0xB7, 0xCD, 0x85, 0xDD, 0x04, 0xCE, 0xB9, 0xCC,
0x80, 0xCD, 0x04, 0xCE, 0xB9, 0xCC, 0x81, 0xCD,
0x04, 0xCE, 0xB9, 0xCC, 0x84, 0xCD, 0x04, 0xCE,
0xB9, 0xCC, 0x86, 0xCD, 0x04, 0xCE, 0xB9, 0xCD,
// Bytes 3800 - 383f
0x82, 0xCD, 0x04, 0xCE, 0xBF, 0xCC, 0x80, 0xCD,
0x04, 0xCE, 0xBF, 0xCC, 0x81, 0xCD, 0x04, 0xCF,
0x81, 0xCC, 0x93, 0xCD, 0x04, 0xCF, 0x81, 0xCC,
0x94, 0xCD, 0x04, 0xCF, 0x85, 0xCC, 0x80, 0xCD,
0x04, 0xCF, 0x85, 0xCC, 0x81, 0xCD, 0x04, 0xCF,
0x85, 0xCC, 0x84, 0xCD, 0x04, 0xCF, 0x85, 0xCC,
0x86, 0xCD, 0x04, 0xCF, 0x85, 0xCD, 0x82, 0xCD,
0x04, 0xCF, 0x89, 0xCD, 0x85, 0xDD, 0x04, 0xCF,
// Bytes 3840 - 387f
0x92, 0xCC, 0x81, 0xCD, 0x04, 0xCF, 0x92, 0xCC,
0x88, 0xCD, 0x04, 0xD0, 0x86, 0xCC, 0x88, 0xCD,
0x04, 0xD0, 0x90, 0xCC, 0x86, 0xCD, 0x04, 0xD0,
0x90, 0xCC, 0x88, 0xCD, 0x04, 0xD0, 0x93, 0xCC,
0x81, 0xCD, 0x04, 0xD0, 0x95, 0xCC, 0x80, 0xCD,
0x04, 0xD0, 0x95, 0xCC, 0x86, 0xCD, 0x04, 0xD0,
0x95, 0xCC, 0x88, 0xCD, 0x04, 0xD0, 0x96, 0xCC,
0x86, 0xCD, 0x04, 0xD0, 0x96, 0xCC, 0x88, 0xCD,
// Bytes 3880 - 38bf
0x04, 0xD0, 0x97, 0xCC, 0x88, 0xCD, 0x04, 0xD0,
0x98, 0xCC, 0x80, 0xCD, 0x04, 0xD0, 0x98, 0xCC,
0x84, 0xCD, 0x04, 0xD0, 0x98, 0xCC, 0x86, 0xCD,
0x04, 0xD0, 0x98, 0xCC, 0x88, 0xCD, 0x04, 0xD0,
0x9A, 0xCC, 0x81, 0xCD, 0x04, 0xD0, 0x9E, 0xCC,
0x88, 0xCD, 0x04, 0xD0, 0xA3, 0xCC, 0x84, 0xCD,
0x04, 0xD0, 0xA3, 0xCC, 0x86, 0xCD, 0x04, 0xD0,
0xA3, 0xCC, 0x88, 0xCD, 0x04, 0xD0, 0xA3, 0xCC,
// Bytes 38c0 - 38ff
0x8B, 0xCD, 0x04, 0xD0, 0xA7, 0xCC, 0x88, 0xCD,
0x04, 0xD0, 0xAB, 0xCC, 0x88, 0xCD, 0x04, 0xD0,
0xAD, 0xCC, 0x88, 0xCD, 0x04, 0xD0, 0xB0, 0xCC,
0x86, 0xCD, 0x04, 0xD0, 0xB0, 0xCC, 0x88, 0xCD,
0x04, 0xD0, 0xB3, 0xCC, 0x81, 0xCD, 0x04, 0xD0,
0xB5, 0xCC, 0x80, 0xCD, 0x04, 0xD0, 0xB5, 0xCC,
0x86, 0xCD, 0x04, 0xD0, 0xB5, 0xCC, 0x88, 0xCD,
0x04, 0xD0, 0xB6, 0xCC, 0x86, 0xCD, 0x04, 0xD0,
// Bytes 3900 - 393f
0xB6, 0xCC, 0x88, 0xCD, 0x04, 0xD0, 0xB7, 0xCC,
0x88, 0xCD, 0x04, 0xD0, 0xB8, 0xCC, 0x80, 0xCD,
0x04, 0xD0, 0xB8, 0xCC, 0x84, 0xCD, 0x04, 0xD0,
0xB8, 0xCC, 0x86, 0xCD, 0x04, 0xD0, 0xB8, 0xCC,
0x88, 0xCD, 0x04, 0xD0, 0xBA, 0xCC, 0x81, 0xCD,
0x04, 0xD0, 0xBE, 0xCC, 0x88, 0xCD, 0x04, 0xD1,
0x83, 0xCC, 0x84, 0xCD, 0x04, 0xD1, 0x83, 0xCC,
0x86, 0xCD, 0x04, 0xD1, 0x83, 0xCC, 0x88, 0xCD,
// Bytes 3940 - 397f
0x04, 0xD1, 0x83, 0xCC, 0x8B, 0xCD, 0x04, 0xD1,
0x87, 0xCC, 0x88, 0xCD, 0x04, 0xD1, 0x8B, 0xCC,
0x88, 0xCD, 0x04, 0xD1, 0x8D, 0xCC, 0x88, 0xCD,
0x04, 0xD1, 0x96, 0xCC, 0x88, 0xCD, 0x04, 0xD1,
0xB4, 0xCC, 0x8F, 0xCD, 0x04, 0xD1, 0xB5, 0xCC,
0x8F, 0xCD, 0x04, 0xD3, 0x98, 0xCC, 0x88, 0xCD,
0x04, 0xD3, 0x99, 0xCC, 0x88, 0xCD, 0x04, 0xD3,
0xA8, 0xCC, 0x88, 0xCD, 0x04, 0xD3, 0xA9, 0xCC,
// Bytes 3980 - 39bf
0x88, 0xCD, 0x04, 0xD8, 0xA7, 0xD9, 0x93, 0xCD,
0x04, 0xD8, 0xA7, 0xD9, 0x94, 0xCD, 0x04, 0xD8,
0xA7, 0xD9, 0x95, 0xB9, 0x04, 0xD9, 0x88, 0xD9,
0x94, 0xCD, 0x04, 0xD9, 0x8A, 0xD9, 0x94, 0xCD,
0x04, 0xDB, 0x81, 0xD9, 0x94, 0xCD, 0x04, 0xDB,
0x92, 0xD9, 0x94, 0xCD, 0x04, 0xDB, 0x95, 0xD9,
0x94, 0xCD, 0x05, 0x41, 0xCC, 0x82, 0xCC, 0x80,
0xCE, 0x05, 0x41, 0xCC, 0x82, 0xCC, 0x81, 0xCE,
// Bytes 39c0 - 39ff
0x05, 0x41, 0xCC, 0x82, 0xCC, 0x83, 0xCE, 0x05,
0x41, 0xCC, 0x82, 0xCC, 0x89, 0xCE, 0x05, 0x41,
0xCC, 0x86, 0xCC, 0x80, 0xCE, 0x05, 0x41, 0xCC,
0x86, 0xCC, 0x81, 0xCE, 0x05, 0x41, 0xCC, 0x86,
0xCC, 0x83, 0xCE, 0x05, 0x41, 0xCC, 0x86, 0xCC,
0x89, 0xCE, 0x05, 0x41, 0xCC, 0x87, 0xCC, 0x84,
0xCE, 0x05, 0x41, 0xCC, 0x88, 0xCC, 0x84, 0xCE,
0x05, 0x41, 0xCC, 0x8A, 0xCC, 0x81, 0xCE, 0x05,
// Bytes 3a00 - 3a3f
0x41, 0xCC, 0xA3, 0xCC, 0x82, 0xCE, 0x05, 0x41,
0xCC, 0xA3, 0xCC, 0x86, 0xCE, 0x05, 0x43, 0xCC,
0xA7, 0xCC, 0x81, 0xCE, 0x05, 0x45, 0xCC, 0x82,
0xCC, 0x80, 0xCE, 0x05, 0x45, 0xCC, 0x82, 0xCC,
0x81, 0xCE, 0x05, 0x45, 0xCC, 0x82, 0xCC, 0x83,
0xCE, 0x05, 0x45, 0xCC, 0x82, 0xCC, 0x89, 0xCE,
0x05, 0x45, 0xCC, 0x84, 0xCC, 0x80, 0xCE, 0x05,
0x45, 0xCC, 0x84, 0xCC, 0x81, 0xCE, 0x05, 0x45,
// Bytes 3a40 - 3a7f
0xCC, 0xA3, 0xCC, 0x82, 0xCE, 0x05, 0x45, 0xCC,
0xA7, 0xCC, 0x86, 0xCE, 0x05, 0x49, 0xCC, 0x88,
0xCC, 0x81, 0xCE, 0x05, 0x4C, 0xCC, 0xA3, 0xCC,
0x84, 0xCE, 0x05, 0x4F, 0xCC, 0x82, 0xCC, 0x80,
0xCE, 0x05, 0x4F, 0xCC, 0x82, 0xCC, 0x81, 0xCE,
0x05, 0x4F, 0xCC, 0x82, 0xCC, 0x83, 0xCE, 0x05,
0x4F, 0xCC, 0x82, 0xCC, 0x89, 0xCE, 0x05, 0x4F,
0xCC, 0x83, 0xCC, 0x81, 0xCE, 0x05, 0x4F, 0xCC,
// Bytes 3a80 - 3abf
0x83, 0xCC, 0x84, 0xCE, 0x05, 0x4F, 0xCC, 0x83,
0xCC, 0x88, 0xCE, 0x05, 0x4F, 0xCC, 0x84, 0xCC,
0x80, 0xCE, 0x05, 0x4F, 0xCC, 0x84, 0xCC, 0x81,
0xCE, 0x05, 0x4F, 0xCC, 0x87, 0xCC, 0x84, 0xCE,
0x05, 0x4F, 0xCC, 0x88, 0xCC, 0x84, 0xCE, 0x05,
0x4F, 0xCC, 0x9B, 0xCC, 0x80, 0xCE, 0x05, 0x4F,
0xCC, 0x9B, 0xCC, 0x81, 0xCE, 0x05, 0x4F, 0xCC,
0x9B, 0xCC, 0x83, 0xCE, 0x05, 0x4F, 0xCC, 0x9B,
// Bytes 3ac0 - 3aff
0xCC, 0x89, 0xCE, 0x05, 0x4F, 0xCC, 0x9B, 0xCC,
0xA3, 0xBA, 0x05, 0x4F, 0xCC, 0xA3, 0xCC, 0x82,
0xCE, 0x05, 0x4F, 0xCC, 0xA8, 0xCC, 0x84, 0xCE,
0x05, 0x52, 0xCC, 0xA3, 0xCC, 0x84, 0xCE, 0x05,
0x53, 0xCC, 0x81, 0xCC, 0x87, 0xCE, 0x05, 0x53,
0xCC, 0x8C, 0xCC, 0x87, 0xCE, 0x05, 0x53, 0xCC,
0xA3, 0xCC, 0x87, 0xCE, 0x05, 0x55, 0xCC, 0x83,
0xCC, 0x81, 0xCE, 0x05, 0x55, 0xCC, 0x84, 0xCC,
// Bytes 3b00 - 3b3f
0x88, 0xCE, 0x05, 0x55, 0xCC, 0x88, 0xCC, 0x80,
0xCE, 0x05, 0x55, 0xCC, 0x88, 0xCC, 0x81, 0xCE,
0x05, 0x55, 0xCC, 0x88, 0xCC, 0x84, 0xCE, 0x05,
0x55, 0xCC, 0x88, 0xCC, 0x8C, 0xCE, 0x05, 0x55,
0xCC, 0x9B, 0xCC, 0x80, 0xCE, 0x05, 0x55, 0xCC,
0x9B, 0xCC, 0x81, 0xCE, 0x05, 0x55, 0xCC, 0x9B,
0xCC, 0x83, 0xCE, 0x05, 0x55, 0xCC, 0x9B, 0xCC,
0x89, 0xCE, 0x05, 0x55, 0xCC, 0x9B, 0xCC, 0xA3,
// Bytes 3b40 - 3b7f
0xBA, 0x05, 0x61, 0xCC, 0x82, 0xCC, 0x80, 0xCE,
0x05, 0x61, 0xCC, 0x82, 0xCC, 0x81, 0xCE, 0x05,
0x61, 0xCC, 0x82, 0xCC, 0x83, 0xCE, 0x05, 0x61,
0xCC, 0x82, 0xCC, 0x89, 0xCE, 0x05, 0x61, 0xCC,
0x86, 0xCC, 0x80, 0xCE, 0x05, 0x61, 0xCC, 0x86,
0xCC, 0x81, 0xCE, 0x05, 0x61, 0xCC, 0x86, 0xCC,
0x83, 0xCE, 0x05, 0x61, 0xCC, 0x86, 0xCC, 0x89,
0xCE, 0x05, 0x61, 0xCC, 0x87, 0xCC, 0x84, 0xCE,
// Bytes 3b80 - 3bbf
0x05, 0x61, 0xCC, 0x88, 0xCC, 0x84, 0xCE, 0x05,
0x61, 0xCC, 0x8A, 0xCC, 0x81, 0xCE, 0x05, 0x61,
0xCC, 0xA3, 0xCC, 0x82, 0xCE, 0x05, 0x61, 0xCC,
0xA3, 0xCC, 0x86, 0xCE, 0x05, 0x63, 0xCC, 0xA7,
0xCC, 0x81, 0xCE, 0x05, 0x65, 0xCC, 0x82, 0xCC,
0x80, 0xCE, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x81,
0xCE, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x83, 0xCE,
0x05, 0x65, 0xCC, 0x82, 0xCC, 0x89, 0xCE, 0x05,
// Bytes 3bc0 - 3bff
0x65, 0xCC, 0x84, 0xCC, 0x80, 0xCE, 0x05, 0x65,
0xCC, 0x84, 0xCC, 0x81, 0xCE, 0x05, 0x65, 0xCC,
0xA3, 0xCC, 0x82, 0xCE, 0x05, 0x65, 0xCC, 0xA7,
0xCC, 0x86, 0xCE, 0x05, 0x69, 0xCC, 0x88, 0xCC,
0x81, 0xCE, 0x05, 0x6C, 0xCC, 0xA3, 0xCC, 0x84,
0xCE, 0x05, 0x6F, 0xCC, 0x82, 0xCC, 0x80, 0xCE,
0x05, 0x6F, 0xCC, 0x82, 0xCC, 0x81, 0xCE, 0x05,
0x6F, 0xCC, 0x82, 0xCC, 0x83, 0xCE, 0x05, 0x6F,
// Bytes 3c00 - 3c3f
0xCC, 0x82, 0xCC, 0x89, 0xCE, 0x05, 0x6F, 0xCC,
0x83, 0xCC, 0x81, 0xCE, 0x05, 0x6F, 0xCC, 0x83,
0xCC, 0x84, 0xCE, 0x05, 0x6F, 0xCC, 0x83, 0xCC,
0x88, 0xCE, 0x05, 0x6F, 0xCC, 0x84, 0xCC, 0x80,
0xCE, 0x05, 0x6F, 0xCC, 0x84, 0xCC, 0x81, 0xCE,
0x05, 0x6F, 0xCC, 0x87, 0xCC, 0x84, 0xCE, 0x05,
0x6F, 0xCC, 0x88, 0xCC, 0x84, 0xCE, 0x05, 0x6F,
0xCC, 0x9B, 0xCC, 0x80, 0xCE, 0x05, 0x6F, 0xCC,
// Bytes 3c40 - 3c7f
0x9B, 0xCC, 0x81, 0xCE, 0x05, 0x6F, 0xCC, 0x9B,
0xCC, 0x83, 0xCE, 0x05, 0x6F, 0xCC, 0x9B, 0xCC,
0x89, 0xCE, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0xA3,
0xBA, 0x05, 0x6F, 0xCC, 0xA3, 0xCC, 0x82, 0xCE,
0x05, 0x6F, 0xCC, 0xA8, 0xCC, 0x84, 0xCE, 0x05,
0x72, 0xCC, 0xA3, 0xCC, 0x84, 0xCE, 0x05, 0x73,
0xCC, 0x81, 0xCC, 0x87, 0xCE, 0x05, 0x73, 0xCC,
0x8C, 0xCC, 0x87, 0xCE, 0x05, 0x73, 0xCC, 0xA3,
// Bytes 3c80 - 3cbf
0xCC, 0x87, 0xCE, 0x05, 0x75, 0xCC, 0x83, 0xCC,
0x81, 0xCE, 0x05, 0x75, 0xCC, 0x84, 0xCC, 0x88,
0xCE, 0x05, 0x75, 0xCC, 0x88, 0xCC, 0x80, 0xCE,
0x05, 0x75, 0xCC, 0x88, 0xCC, 0x81, 0xCE, 0x05,
0x75, 0xCC, 0x88, 0xCC, 0x84, 0xCE, 0x05, 0x75,
0xCC, 0x88, 0xCC, 0x8C, 0xCE, 0x05, 0x75, 0xCC,
0x9B, 0xCC, 0x80, 0xCE, 0x05, 0x75, 0xCC, 0x9B,
0xCC, 0x81, 0xCE, 0x05, 0x75, 0xCC, 0x9B, 0xCC,
// Bytes 3cc0 - 3cff
0x83, 0xCE, 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0x89,
0xCE, 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0xA3, 0xBA,
0x05, 0xE1, 0xBE, 0xBF, 0xCC, 0x80, 0xCE, 0x05,
0xE1, 0xBE, 0xBF, 0xCC, 0x81, 0xCE, 0x05, 0xE1,
0xBE, 0xBF, 0xCD, 0x82, 0xCE, 0x05, 0xE1, 0xBF,
0xBE, 0xCC, 0x80, 0xCE, 0x05, 0xE1, 0xBF, 0xBE,
0xCC, 0x81, 0xCE, 0x05, 0xE1, 0xBF, 0xBE, 0xCD,
0x82, 0xCE, 0x05, 0xE2, 0x86, 0x90, 0xCC, 0xB8,
// Bytes 3d00 - 3d3f
0x05, 0x05, 0xE2, 0x86, 0x92, 0xCC, 0xB8, 0x05,
0x05, 0xE2, 0x86, 0x94, 0xCC, 0xB8, 0x05, 0x05,
0xE2, 0x87, 0x90, 0xCC, 0xB8, 0x05, 0x05, 0xE2,
0x87, 0x92, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x87,
0x94, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x88, 0x83,
0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x88, 0x88, 0xCC,
0xB8, 0x05, 0x05, 0xE2, 0x88, 0x8B, 0xCC, 0xB8,
0x05, 0x05, 0xE2, 0x88, 0xA3, 0xCC, 0xB8, 0x05,
// Bytes 3d40 - 3d7f
0x05, 0xE2, 0x88, 0xA5, 0xCC, 0xB8, 0x05, 0x05,
0xE2, 0x88, 0xBC, 0xCC, 0xB8, 0x05, 0x05, 0xE2,
0x89, 0x83, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89,
0x85, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0x88,
0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0x8D, 0xCC,
0xB8, 0x05, 0x05, 0xE2, 0x89, 0xA1, 0xCC, 0xB8,
0x05, 0x05, 0xE2, 0x89, 0xA4, 0xCC, 0xB8, 0x05,
0x05, 0xE2, 0x89, 0xA5, 0xCC, 0xB8, 0x05, 0x05,
// Bytes 3d80 - 3dbf
0xE2, 0x89, 0xB2, 0xCC, 0xB8, 0x05, 0x05, 0xE2,
0x89, 0xB3, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89,
0xB6, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xB7,
0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xBA, 0xCC,
0xB8, 0x05, 0x05, 0xE2, 0x89, 0xBB, 0xCC, 0xB8,
0x05, 0x05, 0xE2, 0x89, 0xBC, 0xCC, 0xB8, 0x05,
0x05, 0xE2, 0x89, 0xBD, 0xCC, 0xB8, 0x05, 0x05,
0xE2, 0x8A, 0x82, 0xCC, 0xB8, 0x05, 0x05, 0xE2,
// Bytes 3dc0 - 3dff
0x8A, 0x83, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A,
0x86, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x87,
0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x91, 0xCC,
0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x92, 0xCC, 0xB8,
0x05, 0x05, 0xE2, 0x8A, 0xA2, 0xCC, 0xB8, 0x05,
0x05, 0xE2, 0x8A, 0xA8, 0xCC, 0xB8, 0x05, 0x05,
0xE2, 0x8A, 0xA9, 0xCC, 0xB8, 0x05, 0x05, 0xE2,
0x8A, 0xAB, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A,
// Bytes 3e00 - 3e3f
0xB2, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xB3,
0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xB4, 0xCC,
0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xB5, 0xCC, 0xB8,
0x05, 0x06, 0xCE, 0x91, 0xCC, 0x93, 0xCD, 0x85,
0xDE, 0x06, 0xCE, 0x91, 0xCC, 0x94, 0xCD, 0x85,
0xDE, 0x06, 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x80,
0xCE, 0x06, 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x81,
0xCE, 0x06, 0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x80,
// Bytes 3e40 - 3e7f
0xCE, 0x06, 0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x81,
0xCE, 0x06, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x85,
0xDE, 0x06, 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x85,
0xDE, 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCC, 0x80,
0xCE, 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCC, 0x81,
0xCE, 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCD, 0x82,
0xCE, 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCC, 0x80,
0xCE, 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCC, 0x81,
// Bytes 3e80 - 3ebf
0xCE, 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCD, 0x82,
0xCE, 0x06, 0xCE, 0x9F, 0xCC, 0x93, 0xCC, 0x80,
0xCE, 0x06, 0xCE, 0x9F, 0xCC, 0x93, 0xCC, 0x81,
0xCE, 0x06, 0xCE, 0x9F, 0xCC, 0x94, 0xCC, 0x80,
0xCE, 0x06, 0xCE, 0x9F, 0xCC, 0x94, 0xCC, 0x81,
0xCE, 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCC, 0x80,
0xCE, 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCC, 0x81,
0xCE, 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCD, 0x82,
// Bytes 3ec0 - 3eff
0xCE, 0x06, 0xCE, 0xA9, 0xCC, 0x93, 0xCD, 0x85,
0xDE, 0x06, 0xCE, 0xA9, 0xCC, 0x94, 0xCD, 0x85,
0xDE, 0x06, 0xCE, 0xB1, 0xCC, 0x80, 0xCD, 0x85,
0xDE, 0x06, 0xCE, 0xB1, 0xCC, 0x81, 0xCD, 0x85,
0xDE, 0x06, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x85,
0xDE, 0x06, 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x85,
0xDE, 0x06, 0xCE, 0xB1, 0xCD, 0x82, 0xCD, 0x85,
0xDE, 0x06, 0xCE, 0xB5, 0xCC, 0x93, 0xCC, 0x80,
// Bytes 3f00 - 3f3f
0xCE, 0x06, 0xCE, 0xB5, 0xCC, 0x93, 0xCC, 0x81,
0xCE, 0x06, 0xCE, 0xB5, 0xCC, 0x94, 0xCC, 0x80,
0xCE, 0x06, 0xCE, 0xB5, 0xCC, 0x94, 0xCC, 0x81,
0xCE, 0x06, 0xCE, 0xB7, 0xCC, 0x80, 0xCD, 0x85,
0xDE, 0x06, 0xCE, 0xB7, 0xCC, 0x81, 0xCD, 0x85,
0xDE, 0x06, 0xCE, 0xB7, 0xCC, 0x93, 0xCD, 0x85,
0xDE, 0x06, 0xCE, 0xB7, 0xCC, 0x94, 0xCD, 0x85,
0xDE, 0x06, 0xCE, 0xB7, 0xCD, 0x82, 0xCD, 0x85,
// Bytes 3f40 - 3f7f
0xDE, 0x06, 0xCE, 0xB9, 0xCC, 0x88, 0xCC, 0x80,
0xCE, 0x06, 0xCE, 0xB9, 0xCC, 0x88, 0xCC, 0x81,
0xCE, 0x06, 0xCE, 0xB9, 0xCC, 0x88, 0xCD, 0x82,
0xCE, 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x80,
0xCE, 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x81,
0xCE, 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCD, 0x82,
0xCE, 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCC, 0x80,
0xCE, 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCC, 0x81,
// Bytes 3f80 - 3fbf
0xCE, 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCD, 0x82,
0xCE, 0x06, 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x80,
0xCE, 0x06, 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x81,
0xCE, 0x06, 0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x80,
0xCE, 0x06, 0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x81,
0xCE, 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x80,
0xCE, 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x81,
0xCE, 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCD, 0x82,
// Bytes 3fc0 - 3fff
0xCE, 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCC, 0x80,
0xCE, 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCC, 0x81,
0xCE, 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCD, 0x82,
0xCE, 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCC, 0x80,
0xCE, 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCC, 0x81,
0xCE, 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCD, 0x82,
0xCE, 0x06, 0xCF, 0x89, 0xCC, 0x80, 0xCD, 0x85,
0xDE, 0x06, 0xCF, 0x89, 0xCC, 0x81, 0xCD, 0x85,
// Bytes 4000 - 403f
0xDE, 0x06, 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x85,
0xDE, 0x06, 0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x85,
0xDE, 0x06, 0xCF, 0x89, 0xCD, 0x82, 0xCD, 0x85,
0xDE, 0x06, 0xE0, 0xA4, 0xA8, 0xE0, 0xA4, 0xBC,
0x0D, 0x06, 0xE0, 0xA4, 0xB0, 0xE0, 0xA4, 0xBC,
0x0D, 0x06, 0xE0, 0xA4, 0xB3, 0xE0, 0xA4, 0xBC,
0x0D, 0x06, 0xE0, 0xB1, 0x86, 0xE0, 0xB1, 0x96,
0x89, 0x06, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x8A,
// Bytes 4040 - 407f
0x15, 0x06, 0xE3, 0x81, 0x86, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x81, 0x8B, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x81, 0x8D, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x81, 0x8F, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x81, 0x91, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x81, 0x93, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x81, 0x95, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x81, 0x97, 0xE3, 0x82, 0x99,
// Bytes 4080 - 40bf
0x11, 0x06, 0xE3, 0x81, 0x99, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x81, 0x9B, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x81, 0x9D, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x81, 0x9F, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x81, 0xA1, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x81, 0xA4, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x81, 0xA6, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x81, 0xA8, 0xE3, 0x82, 0x99,
// Bytes 40c0 - 40ff
0x11, 0x06, 0xE3, 0x81, 0xAF, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x81, 0xAF, 0xE3, 0x82, 0x9A,
0x11, 0x06, 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x9A,
0x11, 0x06, 0xE3, 0x81, 0xB5, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x81, 0xB5, 0xE3, 0x82, 0x9A,
0x11, 0x06, 0xE3, 0x81, 0xB8, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x81, 0xB8, 0xE3, 0x82, 0x9A,
// Bytes 4100 - 413f
0x11, 0x06, 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x9A,
0x11, 0x06, 0xE3, 0x82, 0x9D, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x82, 0xA6, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x82, 0xB1, 0xE3, 0x82, 0x99,
// Bytes 4140 - 417f
0x11, 0x06, 0xE3, 0x82, 0xB3, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x82, 0xB5, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x82, 0xB7, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x82, 0xB9, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x82, 0xBD, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x83, 0x81, 0xE3, 0x82, 0x99,
// Bytes 4180 - 41bf
0x11, 0x06, 0xE3, 0x83, 0x84, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x83, 0x86, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A,
0x11, 0x06, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A,
0x11, 0x06, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x99,
// Bytes 41c0 - 41ff
0x11, 0x06, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x9A,
0x11, 0x06, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A,
0x11, 0x06, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A,
0x11, 0x06, 0xE3, 0x83, 0xAF, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x83, 0xB0, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x83, 0xB1, 0xE3, 0x82, 0x99,
// Bytes 4200 - 423f
0x11, 0x06, 0xE3, 0x83, 0xB2, 0xE3, 0x82, 0x99,
0x11, 0x06, 0xE3, 0x83, 0xBD, 0xE3, 0x82, 0x99,
0x11, 0x08, 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x80,
0xCD, 0x85, 0xDF, 0x08, 0xCE, 0x91, 0xCC, 0x93,
0xCC, 0x81, 0xCD, 0x85, 0xDF, 0x08, 0xCE, 0x91,
0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0xDF, 0x08,
0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85,
0xDF, 0x08, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x81,
// Bytes 4240 - 427f
0xCD, 0x85, 0xDF, 0x08, 0xCE, 0x91, 0xCC, 0x94,
0xCD, 0x82, 0xCD, 0x85, 0xDF, 0x08, 0xCE, 0x97,
0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0xDF, 0x08,
0xCE, 0x97, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85,
0xDF, 0x08, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x82,
0xCD, 0x85, 0xDF, 0x08, 0xCE, 0x97, 0xCC, 0x94,
0xCC, 0x80, 0xCD, 0x85, 0xDF, 0x08, 0xCE, 0x97,
0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xDF, 0x08,
// Bytes 4280 - 42bf
0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85,
0xDF, 0x08, 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x80,
0xCD, 0x85, 0xDF, 0x08, 0xCE, 0xA9, 0xCC, 0x93,
0xCC, 0x81, 0xCD, 0x85, 0xDF, 0x08, 0xCE, 0xA9,
0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0xDF, 0x08,
0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85,
0xDF, 0x08, 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x81,
0xCD, 0x85, 0xDF, 0x08, 0xCE, 0xA9, 0xCC, 0x94,
// Bytes 42c0 - 42ff
0xCD, 0x82, 0xCD, 0x85, 0xDF, 0x08, 0xCE, 0xB1,
0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0xDF, 0x08,
0xCE, 0xB1, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85,
0xDF, 0x08, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x82,
0xCD, 0x85, 0xDF, 0x08, 0xCE, 0xB1, 0xCC, 0x94,
0xCC, 0x80, 0xCD, 0x85, 0xDF, 0x08, 0xCE, 0xB1,
0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xDF, 0x08,
0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85,
// Bytes 4300 - 433f
0xDF, 0x08, 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x80,
0xCD, 0x85, 0xDF, 0x08, 0xCE, 0xB7, 0xCC, 0x93,
0xCC, 0x81, 0xCD, 0x85, 0xDF, 0x08, 0xCE, 0xB7,
0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0xDF, 0x08,
0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85,
0xDF, 0x08, 0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x81,
0xCD, 0x85, 0xDF, 0x08, 0xCE, 0xB7, 0xCC, 0x94,
0xCD, 0x82, 0xCD, 0x85, 0xDF, 0x08, 0xCF, 0x89,
// Bytes 4340 - 437f
0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0xDF, 0x08,
0xCF, 0x89, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85,
0xDF, 0x08, 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x82,
0xCD, 0x85, 0xDF, 0x08, 0xCF, 0x89, 0xCC, 0x94,
0xCC, 0x80, 0xCD, 0x85, 0xDF, 0x08, 0xCF, 0x89,
0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xDF, 0x08,
0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85,
0xDF, 0x08, 0xF0, 0x91, 0x82, 0x99, 0xF0, 0x91,
// Bytes 4380 - 43bf
0x82, 0xBA, 0x0D, 0x08, 0xF0, 0x91, 0x82, 0x9B,
0xF0, 0x91, 0x82, 0xBA, 0x0D, 0x08, 0xF0, 0x91,
0x82, 0xA5, 0xF0, 0x91, 0x82, 0xBA, 0x0D, 0x42,
0xC2, 0xB4, 0x01, 0x43, 0x20, 0xCC, 0x81, 0xCD,
0x43, 0x20, 0xCC, 0x83, 0xCD, 0x43, 0x20, 0xCC,
0x84, 0xCD, 0x43, 0x20, 0xCC, 0x85, 0xCD, 0x43,
0x20, 0xCC, 0x86, 0xCD, 0x43, 0x20, 0xCC, 0x87,
0xCD, 0x43, 0x20, 0xCC, 0x88, 0xCD, 0x43, 0x20,
// Bytes 43c0 - 43ff
0xCC, 0x8A, 0xCD, 0x43, 0x20, 0xCC, 0x8B, 0xCD,
0x43, 0x20, 0xCC, 0x93, 0xCD, 0x43, 0x20, 0xCC,
0x94, 0xCD, 0x43, 0x20, 0xCC, 0xA7, 0xA9, 0x43,
0x20, 0xCC, 0xA8, 0xA9, 0x43, 0x20, 0xCC, 0xB3,
0xB9, 0x43, 0x20, 0xCD, 0x82, 0xCD, 0x43, 0x20,
0xCD, 0x85, 0xDD, 0x43, 0x20, 0xD9, 0x8B, 0x5D,
0x43, 0x20, 0xD9, 0x8C, 0x61, 0x43, 0x20, 0xD9,
0x8D, 0x65, 0x43, 0x20, 0xD9, 0x8E, 0x69, 0x43,
// Bytes 4400 - 443f
0x20, 0xD9, 0x8F, 0x6D, 0x43, 0x20, 0xD9, 0x90,
0x71, 0x43, 0x20, 0xD9, 0x91, 0x75, 0x43, 0x20,
0xD9, 0x92, 0x79, 0x43, 0x41, 0xCC, 0x8A, 0xCD,
0x43, 0x73, 0xCC, 0x87, 0xCD, 0x44, 0x20, 0xE3,
0x82, 0x99, 0x11, 0x44, 0x20, 0xE3, 0x82, 0x9A,
0x11, 0x44, 0xC2, 0xA8, 0xCC, 0x81, 0xCE, 0x44,
0xCE, 0x91, 0xCC, 0x81, 0xCD, 0x44, 0xCE, 0x95,
0xCC, 0x81, 0xCD, 0x44, 0xCE, 0x97, 0xCC, 0x81,
// Bytes 4440 - 447f
0xCD, 0x44, 0xCE, 0x99, 0xCC, 0x81, 0xCD, 0x44,
0xCE, 0x9F, 0xCC, 0x81, 0xCD, 0x44, 0xCE, 0xA5,
0xCC, 0x81, 0xCD, 0x44, 0xCE, 0xA5, 0xCC, 0x88,
0xCD, 0x44, 0xCE, 0xA9, 0xCC, 0x81, 0xCD, 0x44,
0xCE, 0xB1, 0xCC, 0x81, 0xCD, 0x44, 0xCE, 0xB5,
0xCC, 0x81, 0xCD, 0x44, 0xCE, 0xB7, 0xCC, 0x81,
0xCD, 0x44, 0xCE, 0xB9, 0xCC, 0x81, 0xCD, 0x44,
0xCE, 0xBF, 0xCC, 0x81, 0xCD, 0x44, 0xCF, 0x85,
// Bytes 4480 - 44bf
0xCC, 0x81, 0xCD, 0x44, 0xCF, 0x89, 0xCC, 0x81,
0xCD, 0x44, 0xD7, 0x90, 0xD6, 0xB7, 0x35, 0x44,
0xD7, 0x90, 0xD6, 0xB8, 0x39, 0x44, 0xD7, 0x90,
0xD6, 0xBC, 0x45, 0x44, 0xD7, 0x91, 0xD6, 0xBC,
0x45, 0x44, 0xD7, 0x91, 0xD6, 0xBF, 0x4D, 0x44,
0xD7, 0x92, 0xD6, 0xBC, 0x45, 0x44, 0xD7, 0x93,
0xD6, 0xBC, 0x45, 0x44, 0xD7, 0x94, 0xD6, 0xBC,
0x45, 0x44, 0xD7, 0x95, 0xD6, 0xB9, 0x3D, 0x44,
// Bytes 44c0 - 44ff
0xD7, 0x95, 0xD6, 0xBC, 0x45, 0x44, 0xD7, 0x96,
0xD6, 0xBC, 0x45, 0x44, 0xD7, 0x98, 0xD6, 0xBC,
0x45, 0x44, 0xD7, 0x99, 0xD6, 0xB4, 0x29, 0x44,
0xD7, 0x99, 0xD6, 0xBC, 0x45, 0x44, 0xD7, 0x9A,
0xD6, 0xBC, 0x45, 0x44, 0xD7, 0x9B, 0xD6, 0xBC,
0x45, 0x44, 0xD7, 0x9B, 0xD6, 0xBF, 0x4D, 0x44,
0xD7, 0x9C, 0xD6, 0xBC, 0x45, 0x44, 0xD7, 0x9E,
0xD6, 0xBC, 0x45, 0x44, 0xD7, 0xA0, 0xD6, 0xBC,
// Bytes 4500 - 453f
0x45, 0x44, 0xD7, 0xA1, 0xD6, 0xBC, 0x45, 0x44,
0xD7, 0xA3, 0xD6, 0xBC, 0x45, 0x44, 0xD7, 0xA4,
0xD6, 0xBC, 0x45, 0x44, 0xD7, 0xA4, 0xD6, 0xBF,
0x4D, 0x44, 0xD7, 0xA6, 0xD6, 0xBC, 0x45, 0x44,
0xD7, 0xA7, 0xD6, 0xBC, 0x45, 0x44, 0xD7, 0xA8,
0xD6, 0xBC, 0x45, 0x44, 0xD7, 0xA9, 0xD6, 0xBC,
0x45, 0x44, 0xD7, 0xA9, 0xD7, 0x81, 0x51, 0x44,
0xD7, 0xA9, 0xD7, 0x82, 0x55, 0x44, 0xD7, 0xAA,
// Bytes 4540 - 457f
0xD6, 0xBC, 0x45, 0x44, 0xD7, 0xB2, 0xD6, 0xB7,
0x35, 0x44, 0xD8, 0xA7, 0xD9, 0x8B, 0x5D, 0x44,
0xD8, 0xA7, 0xD9, 0x93, 0xCD, 0x44, 0xD8, 0xA7,
0xD9, 0x94, 0xCD, 0x44, 0xD8, 0xA7, 0xD9, 0x95,
0xB9, 0x44, 0xD8, 0xB0, 0xD9, 0xB0, 0x7D, 0x44,
0xD8, 0xB1, 0xD9, 0xB0, 0x7D, 0x44, 0xD9, 0x80,
0xD9, 0x8B, 0x5D, 0x44, 0xD9, 0x80, 0xD9, 0x8E,
0x69, 0x44, 0xD9, 0x80, 0xD9, 0x8F, 0x6D, 0x44,
// Bytes 4580 - 45bf
0xD9, 0x80, 0xD9, 0x90, 0x71, 0x44, 0xD9, 0x80,
0xD9, 0x91, 0x75, 0x44, 0xD9, 0x80, 0xD9, 0x92,
0x79, 0x44, 0xD9, 0x87, 0xD9, 0xB0, 0x7D, 0x44,
0xD9, 0x88, 0xD9, 0x94, 0xCD, 0x44, 0xD9, 0x89,
0xD9, 0xB0, 0x7D, 0x44, 0xD9, 0x8A, 0xD9, 0x94,
0xCD, 0x44, 0xDB, 0x92, 0xD9, 0x94, 0xCD, 0x44,
0xDB, 0x95, 0xD9, 0x94, 0xCD, 0x45, 0x20, 0xCC,
0x88, 0xCC, 0x80, 0xCE, 0x45, 0x20, 0xCC, 0x88,
// Bytes 45c0 - 45ff
0xCC, 0x81, 0xCE, 0x45, 0x20, 0xCC, 0x88, 0xCD,
0x82, 0xCE, 0x45, 0x20, 0xCC, 0x93, 0xCC, 0x80,
0xCE, 0x45, 0x20, 0xCC, 0x93, 0xCC, 0x81, 0xCE,
0x45, 0x20, 0xCC, 0x93, 0xCD, 0x82, 0xCE, 0x45,
0x20, 0xCC, 0x94, 0xCC, 0x80, 0xCE, 0x45, 0x20,
0xCC, 0x94, 0xCC, 0x81, 0xCE, 0x45, 0x20, 0xCC,
0x94, 0xCD, 0x82, 0xCE, 0x45, 0x20, 0xD9, 0x8C,
0xD9, 0x91, 0x76, 0x45, 0x20, 0xD9, 0x8D, 0xD9,
// Bytes 4600 - 463f
0x91, 0x76, 0x45, 0x20, 0xD9, 0x8E, 0xD9, 0x91,
0x76, 0x45, 0x20, 0xD9, 0x8F, 0xD9, 0x91, 0x76,
0x45, 0x20, 0xD9, 0x90, 0xD9, 0x91, 0x76, 0x45,
0x20, 0xD9, 0x91, 0xD9, 0xB0, 0x7E, 0x45, 0xE2,
0xAB, 0x9D, 0xCC, 0xB8, 0x05, 0x46, 0xCE, 0xB9,
0xCC, 0x88, 0xCC, 0x81, 0xCE, 0x46, 0xCF, 0x85,
0xCC, 0x88, 0xCC, 0x81, 0xCE, 0x46, 0xD7, 0xA9,
0xD6, 0xBC, 0xD7, 0x81, 0x52, 0x46, 0xD7, 0xA9,
// Bytes 4640 - 467f
0xD6, 0xBC, 0xD7, 0x82, 0x56, 0x46, 0xD9, 0x80,
0xD9, 0x8E, 0xD9, 0x91, 0x76, 0x46, 0xD9, 0x80,
0xD9, 0x8F, 0xD9, 0x91, 0x76, 0x46, 0xD9, 0x80,
0xD9, 0x90, 0xD9, 0x91, 0x76, 0x46, 0xE0, 0xA4,
0x95, 0xE0, 0xA4, 0xBC, 0x0D, 0x46, 0xE0, 0xA4,
0x96, 0xE0, 0xA4, 0xBC, 0x0D, 0x46, 0xE0, 0xA4,
0x97, 0xE0, 0xA4, 0xBC, 0x0D, 0x46, 0xE0, 0xA4,
0x9C, 0xE0, 0xA4, 0xBC, 0x0D, 0x46, 0xE0, 0xA4,
// Bytes 4680 - 46bf
0xA1, 0xE0, 0xA4, 0xBC, 0x0D, 0x46, 0xE0, 0xA4,
0xA2, 0xE0, 0xA4, 0xBC, 0x0D, 0x46, 0xE0, 0xA4,
0xAB, 0xE0, 0xA4, 0xBC, 0x0D, 0x46, 0xE0, 0xA4,
0xAF, 0xE0, 0xA4, 0xBC, 0x0D, 0x46, 0xE0, 0xA6,
0xA1, 0xE0, 0xA6, 0xBC, 0x0D, 0x46, 0xE0, 0xA6,
0xA2, 0xE0, 0xA6, 0xBC, 0x0D, 0x46, 0xE0, 0xA6,
0xAF, 0xE0, 0xA6, 0xBC, 0x0D, 0x46, 0xE0, 0xA8,
0x96, 0xE0, 0xA8, 0xBC, 0x0D, 0x46, 0xE0, 0xA8,
// Bytes 46c0 - 46ff
0x97, 0xE0, 0xA8, 0xBC, 0x0D, 0x46, 0xE0, 0xA8,
0x9C, 0xE0, 0xA8, 0xBC, 0x0D, 0x46, 0xE0, 0xA8,
0xAB, 0xE0, 0xA8, 0xBC, 0x0D, 0x46, 0xE0, 0xA8,
0xB2, 0xE0, 0xA8, 0xBC, 0x0D, 0x46, 0xE0, 0xA8,
0xB8, 0xE0, 0xA8, 0xBC, 0x0D, 0x46, 0xE0, 0xAC,
0xA1, 0xE0, 0xAC, 0xBC, 0x0D, 0x46, 0xE0, 0xAC,
0xA2, 0xE0, 0xAC, 0xBC, 0x0D, 0x46, 0xE0, 0xBE,
0xB2, 0xE0, 0xBE, 0x80, 0xA1, 0x46, 0xE0, 0xBE,
// Bytes 4700 - 473f
0xB3, 0xE0, 0xBE, 0x80, 0xA1, 0x46, 0xE3, 0x83,
0x86, 0xE3, 0x82, 0x99, 0x11, 0x48, 0xF0, 0x9D,
0x85, 0x97, 0xF0, 0x9D, 0x85, 0xA5, 0xB1, 0x48,
0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5,
0xB1, 0x48, 0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D,
0x85, 0xA5, 0xB1, 0x48, 0xF0, 0x9D, 0x86, 0xBA,
0xF0, 0x9D, 0x85, 0xA5, 0xB1, 0x49, 0xE0, 0xBE,
0xB2, 0xE0, 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0xA2,
// Bytes 4740 - 477f
0x49, 0xE0, 0xBE, 0xB3, 0xE0, 0xBD, 0xB1, 0xE0,
0xBE, 0x80, 0xA2, 0x4C, 0xF0, 0x9D, 0x85, 0x98,
0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAE,
0xB2, 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D,
0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0xB2, 0x4C,
0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5,
0xF0, 0x9D, 0x85, 0xB0, 0xB2, 0x4C, 0xF0, 0x9D,
0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D,
// Bytes 4780 - 47bf
0x85, 0xB1, 0xB2, 0x4C, 0xF0, 0x9D, 0x85, 0x98,
0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB2,
0xB2, 0x4C, 0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D,
0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0xB2, 0x4C,
0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5,
0xF0, 0x9D, 0x85, 0xAF, 0xB2, 0x4C, 0xF0, 0x9D,
0x86, 0xBA, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D,
0x85, 0xAE, 0xB2, 0x4C, 0xF0, 0x9D, 0x86, 0xBA,
// Bytes 47c0 - 47ff
0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAF,
0xB2, 0x83, 0x41, 0xCC, 0x82, 0xCD, 0x83, 0x41,
0xCC, 0x86, 0xCD, 0x83, 0x41, 0xCC, 0x87, 0xCD,
0x83, 0x41, 0xCC, 0x88, 0xCD, 0x83, 0x41, 0xCC,
0x8A, 0xCD, 0x83, 0x41, 0xCC, 0xA3, 0xB9, 0x83,
0x43, 0xCC, 0xA7, 0xA9, 0x83, 0x45, 0xCC, 0x82,
0xCD, 0x83, 0x45, 0xCC, 0x84, 0xCD, 0x83, 0x45,
0xCC, 0xA3, 0xB9, 0x83, 0x45, 0xCC, 0xA7, 0xA9,
// Bytes 4800 - 483f
0x83, 0x49, 0xCC, 0x88, 0xCD, 0x83, 0x4C, 0xCC,
0xA3, 0xB9, 0x83, 0x4F, 0xCC, 0x82, 0xCD, 0x83,
0x4F, 0xCC, 0x83, 0xCD, 0x83, 0x4F, 0xCC, 0x84,
0xCD, 0x83, 0x4F, 0xCC, 0x87, 0xCD, 0x83, 0x4F,
0xCC, 0x88, 0xCD, 0x83, 0x4F, 0xCC, 0x9B, 0xB1,
0x83, 0x4F, 0xCC, 0xA3, 0xB9, 0x83, 0x4F, 0xCC,
0xA8, 0xA9, 0x83, 0x52, 0xCC, 0xA3, 0xB9, 0x83,
0x53, 0xCC, 0x81, 0xCD, 0x83, 0x53, 0xCC, 0x8C,
// Bytes 4840 - 487f
0xCD, 0x83, 0x53, 0xCC, 0xA3, 0xB9, 0x83, 0x55,
0xCC, 0x83, 0xCD, 0x83, 0x55, 0xCC, 0x84, 0xCD,
0x83, 0x55, 0xCC, 0x88, 0xCD, 0x83, 0x55, 0xCC,
0x9B, 0xB1, 0x83, 0x61, 0xCC, 0x82, 0xCD, 0x83,
0x61, 0xCC, 0x86, 0xCD, 0x83, 0x61, 0xCC, 0x87,
0xCD, 0x83, 0x61, 0xCC, 0x88, 0xCD, 0x83, 0x61,
0xCC, 0x8A, 0xCD, 0x83, 0x61, 0xCC, 0xA3, 0xB9,
0x83, 0x63, 0xCC, 0xA7, 0xA9, 0x83, 0x65, 0xCC,
// Bytes 4880 - 48bf
0x82, 0xCD, 0x83, 0x65, 0xCC, 0x84, 0xCD, 0x83,
0x65, 0xCC, 0xA3, 0xB9, 0x83, 0x65, 0xCC, 0xA7,
0xA9, 0x83, 0x69, 0xCC, 0x88, 0xCD, 0x83, 0x6C,
0xCC, 0xA3, 0xB9, 0x83, 0x6F, 0xCC, 0x82, 0xCD,
0x83, 0x6F, 0xCC, 0x83, 0xCD, 0x83, 0x6F, 0xCC,
0x84, 0xCD, 0x83, 0x6F, 0xCC, 0x87, 0xCD, 0x83,
0x6F, 0xCC, 0x88, 0xCD, 0x83, 0x6F, 0xCC, 0x9B,
0xB1, 0x83, 0x6F, 0xCC, 0xA3, 0xB9, 0x83, 0x6F,
// Bytes 48c0 - 48ff
0xCC, 0xA8, 0xA9, 0x83, 0x72, 0xCC, 0xA3, 0xB9,
0x83, 0x73, 0xCC, 0x81, 0xCD, 0x83, 0x73, 0xCC,
0x8C, 0xCD, 0x83, 0x73, 0xCC, 0xA3, 0xB9, 0x83,
0x75, 0xCC, 0x83, 0xCD, 0x83, 0x75, 0xCC, 0x84,
0xCD, 0x83, 0x75, 0xCC, 0x88, 0xCD, 0x83, 0x75,
0xCC, 0x9B, 0xB1, 0x84, 0xCE, 0x91, 0xCC, 0x93,
0xCD, 0x84, 0xCE, 0x91, 0xCC, 0x94, 0xCD, 0x84,
0xCE, 0x95, 0xCC, 0x93, 0xCD, 0x84, 0xCE, 0x95,
// Bytes 4900 - 493f
0xCC, 0x94, 0xCD, 0x84, 0xCE, 0x97, 0xCC, 0x93,
0xCD, 0x84, 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x84,
0xCE, 0x99, 0xCC, 0x93, 0xCD, 0x84, 0xCE, 0x99,
0xCC, 0x94, 0xCD, 0x84, 0xCE, 0x9F, 0xCC, 0x93,
0xCD, 0x84, 0xCE, 0x9F, 0xCC, 0x94, 0xCD, 0x84,
0xCE, 0xA5, 0xCC, 0x94, 0xCD, 0x84, 0xCE, 0xA9,
0xCC, 0x93, 0xCD, 0x84, 0xCE, 0xA9, 0xCC, 0x94,
0xCD, 0x84, 0xCE, 0xB1, 0xCC, 0x80, 0xCD, 0x84,
// Bytes 4940 - 497f
0xCE, 0xB1, 0xCC, 0x81, 0xCD, 0x84, 0xCE, 0xB1,
0xCC, 0x93, 0xCD, 0x84, 0xCE, 0xB1, 0xCC, 0x94,
0xCD, 0x84, 0xCE, 0xB1, 0xCD, 0x82, 0xCD, 0x84,
0xCE, 0xB5, 0xCC, 0x93, 0xCD, 0x84, 0xCE, 0xB5,
0xCC, 0x94, 0xCD, 0x84, 0xCE, 0xB7, 0xCC, 0x80,
0xCD, 0x84, 0xCE, 0xB7, 0xCC, 0x81, 0xCD, 0x84,
0xCE, 0xB7, 0xCC, 0x93, 0xCD, 0x84, 0xCE, 0xB7,
0xCC, 0x94, 0xCD, 0x84, 0xCE, 0xB7, 0xCD, 0x82,
// Bytes 4980 - 49bf
0xCD, 0x84, 0xCE, 0xB9, 0xCC, 0x88, 0xCD, 0x84,
0xCE, 0xB9, 0xCC, 0x93, 0xCD, 0x84, 0xCE, 0xB9,
0xCC, 0x94, 0xCD, 0x84, 0xCE, 0xBF, 0xCC, 0x93,
0xCD, 0x84, 0xCE, 0xBF, 0xCC, 0x94, 0xCD, 0x84,
0xCF, 0x85, 0xCC, 0x88, 0xCD, 0x84, 0xCF, 0x85,
0xCC, 0x93, 0xCD, 0x84, 0xCF, 0x85, 0xCC, 0x94,
0xCD, 0x84, 0xCF, 0x89, 0xCC, 0x80, 0xCD, 0x84,
0xCF, 0x89, 0xCC, 0x81, 0xCD, 0x84, 0xCF, 0x89,
// Bytes 49c0 - 49ff
0xCC, 0x93, 0xCD, 0x84, 0xCF, 0x89, 0xCC, 0x94,
0xCD, 0x84, 0xCF, 0x89, 0xCD, 0x82, 0xCD, 0x86,
0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x80, 0xCE, 0x86,
0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x81, 0xCE, 0x86,
0xCE, 0x91, 0xCC, 0x93, 0xCD, 0x82, 0xCE, 0x86,
0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x80, 0xCE, 0x86,
0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x81, 0xCE, 0x86,
0xCE, 0x91, 0xCC, 0x94, 0xCD, 0x82, 0xCE, 0x86,
// Bytes 4a00 - 4a3f
0xCE, 0x97, 0xCC, 0x93, 0xCC, 0x80, 0xCE, 0x86,
0xCE, 0x97, 0xCC, 0x93, 0xCC, 0x81, 0xCE, 0x86,
0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x82, 0xCE, 0x86,
0xCE, 0x97, 0xCC, 0x94, 0xCC, 0x80, 0xCE, 0x86,
0xCE, 0x97, 0xCC, 0x94, 0xCC, 0x81, 0xCE, 0x86,
0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x82, 0xCE, 0x86,
0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x80, 0xCE, 0x86,
0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x81, 0xCE, 0x86,
// Bytes 4a40 - 4a7f
0xCE, 0xA9, 0xCC, 0x93, 0xCD, 0x82, 0xCE, 0x86,
0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x80, 0xCE, 0x86,
0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x81, 0xCE, 0x86,
0xCE, 0xA9, 0xCC, 0x94, 0xCD, 0x82, 0xCE, 0x86,
0xCE, 0xB1, 0xCC, 0x93, 0xCC, 0x80, 0xCE, 0x86,
0xCE, 0xB1, 0xCC, 0x93, 0xCC, 0x81, 0xCE, 0x86,
0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x82, 0xCE, 0x86,
0xCE, 0xB1, 0xCC, 0x94, 0xCC, 0x80, 0xCE, 0x86,
// Bytes 4a80 - 4abf
0xCE, 0xB1, 0xCC, 0x94, 0xCC, 0x81, 0xCE, 0x86,
0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x82, 0xCE, 0x86,
0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x80, 0xCE, 0x86,
0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x81, 0xCE, 0x86,
0xCE, 0xB7, 0xCC, 0x93, 0xCD, 0x82, 0xCE, 0x86,
0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x80, 0xCE, 0x86,
0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x81, 0xCE, 0x86,
0xCE, 0xB7, 0xCC, 0x94, 0xCD, 0x82, 0xCE, 0x86,
// Bytes 4ac0 - 4aff
0xCF, 0x89, 0xCC, 0x93, 0xCC, 0x80, 0xCE, 0x86,
0xCF, 0x89, 0xCC, 0x93, 0xCC, 0x81, 0xCE, 0x86,
0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x82, 0xCE, 0x86,
0xCF, 0x89, 0xCC, 0x94, 0xCC, 0x80, 0xCE, 0x86,
0xCF, 0x89, 0xCC, 0x94, 0xCC, 0x81, 0xCE, 0x86,
0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x82, 0xCE, 0x42,
0xCC, 0x80, 0xCD, 0x33, 0x42, 0xCC, 0x81, 0xCD,
0x33, 0x42, 0xCC, 0x93, 0xCD, 0x33, 0x43, 0xE1,
// Bytes 4b00 - 4b3f
0x85, 0xA1, 0x01, 0x00, 0x43, 0xE1, 0x85, 0xA2,
0x01, 0x00, 0x43, 0xE1, 0x85, 0xA3, 0x01, 0x00,
0x43, 0xE1, 0x85, 0xA4, 0x01, 0x00, 0x43, 0xE1,
0x85, 0xA5, 0x01, 0x00, 0x43, 0xE1, 0x85, 0xA6,
0x01, 0x00, 0x43, 0xE1, 0x85, 0xA7, 0x01, 0x00,
0x43, 0xE1, 0x85, 0xA8, 0x01, 0x00, 0x43, 0xE1,
0x85, 0xA9, 0x01, 0x00, 0x43, 0xE1, 0x85, 0xAA,
0x01, 0x00, 0x43, 0xE1, 0x85, 0xAB, 0x01, 0x00,
// Bytes 4b40 - 4b7f
0x43, 0xE1, 0x85, 0xAC, 0x01, 0x00, 0x43, 0xE1,
0x85, 0xAD, 0x01, 0x00, 0x43, 0xE1, 0x85, 0xAE,
0x01, 0x00, 0x43, 0xE1, 0x85, 0xAF, 0x01, 0x00,
0x43, 0xE1, 0x85, 0xB0, 0x01, 0x00, 0x43, 0xE1,
0x85, 0xB1, 0x01, 0x00, 0x43, 0xE1, 0x85, 0xB2,
0x01, 0x00, 0x43, 0xE1, 0x85, 0xB3, 0x01, 0x00,
0x43, 0xE1, 0x85, 0xB4, 0x01, 0x00, 0x43, 0xE1,
0x85, 0xB5, 0x01, 0x00, 0x43, 0xE1, 0x86, 0xAA,
// Bytes 4b80 - 4bbf
0x01, 0x00, 0x43, 0xE1, 0x86, 0xAC, 0x01, 0x00,
0x43, 0xE1, 0x86, 0xAD, 0x01, 0x00, 0x43, 0xE1,
0x86, 0xB0, 0x01, 0x00, 0x43, 0xE1, 0x86, 0xB1,
0x01, 0x00, 0x43, 0xE1, 0x86, 0xB2, 0x01, 0x00,
0x43, 0xE1, 0x86, 0xB3, 0x01, 0x00, 0x43, 0xE1,
0x86, 0xB4, 0x01, 0x00, 0x43, 0xE1, 0x86, 0xB5,
0x01, 0x00, 0x44, 0xCC, 0x88, 0xCC, 0x81, 0xCE,
0x33, 0x43, 0xE3, 0x82, 0x99, 0x11, 0x04, 0x43,
// Bytes 4bc0 - 4bff
0xE3, 0x82, 0x9A, 0x11, 0x04, 0x46, 0xE0, 0xBD,
0xB1, 0xE0, 0xBD, 0xB2, 0xA2, 0x27, 0x46, 0xE0,
0xBD, 0xB1, 0xE0, 0xBD, 0xB4, 0xA6, 0x27, 0x46,
0xE0, 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0xA2, 0x27,
0x00, 0x01,
}
// lookup returns the trie value for the first UTF-8 encoding in s and
// the width in bytes of this encoding. The size will be 0 if s does not
// hold enough bytes to complete the encoding. len(s) must be greater than 0.
func (t *nfcTrie) lookup(s []byte) (v uint16, sz int) {
c0 := s[0]
switch {
case c0 < 0x80: // is ASCII
return nfcValues[c0], 1
case c0 < 0xC2:
return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
case c0 < 0xE0: // 2-byte UTF-8
if len(s) < 2 {
return 0, 0
}
i := nfcIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c1), 2
case c0 < 0xF0: // 3-byte UTF-8
if len(s) < 3 {
return 0, 0
}
i := nfcIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = nfcIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c2), 3
case c0 < 0xF8: // 4-byte UTF-8
if len(s) < 4 {
return 0, 0
}
i := nfcIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = nfcIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
o = uint32(i)<<6 + uint32(c2)
i = nfcIndex[o]
c3 := s[3]
if c3 < 0x80 || 0xC0 <= c3 {
return 0, 3 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c3), 4
}
// Illegal rune
return 0, 1
}
// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
// s must start with a full and valid UTF-8 encoded rune.
func (t *nfcTrie) lookupUnsafe(s []byte) uint16 {
c0 := s[0]
if c0 < 0x80 { // is ASCII
return nfcValues[c0]
}
i := nfcIndex[c0]
if c0 < 0xE0 { // 2-byte UTF-8
return t.lookupValue(uint32(i), s[1])
}
i = nfcIndex[uint32(i)<<6+uint32(s[1])]
if c0 < 0xF0 { // 3-byte UTF-8
return t.lookupValue(uint32(i), s[2])
}
i = nfcIndex[uint32(i)<<6+uint32(s[2])]
if c0 < 0xF8 { // 4-byte UTF-8
return t.lookupValue(uint32(i), s[3])
}
return 0
}
// lookupString returns the trie value for the first UTF-8 encoding in s and
// the width in bytes of this encoding. The size will be 0 if s does not
// hold enough bytes to complete the encoding. len(s) must be greater than 0.
func (t *nfcTrie) lookupString(s string) (v uint16, sz int) {
c0 := s[0]
switch {
case c0 < 0x80: // is ASCII
return nfcValues[c0], 1
case c0 < 0xC2:
return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
case c0 < 0xE0: // 2-byte UTF-8
if len(s) < 2 {
return 0, 0
}
i := nfcIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c1), 2
case c0 < 0xF0: // 3-byte UTF-8
if len(s) < 3 {
return 0, 0
}
i := nfcIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = nfcIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c2), 3
case c0 < 0xF8: // 4-byte UTF-8
if len(s) < 4 {
return 0, 0
}
i := nfcIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = nfcIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
o = uint32(i)<<6 + uint32(c2)
i = nfcIndex[o]
c3 := s[3]
if c3 < 0x80 || 0xC0 <= c3 {
return 0, 3 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c3), 4
}
// Illegal rune
return 0, 1
}
// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
// s must start with a full and valid UTF-8 encoded rune.
func (t *nfcTrie) lookupStringUnsafe(s string) uint16 {
c0 := s[0]
if c0 < 0x80 { // is ASCII
return nfcValues[c0]
}
i := nfcIndex[c0]
if c0 < 0xE0 { // 2-byte UTF-8
return t.lookupValue(uint32(i), s[1])
}
i = nfcIndex[uint32(i)<<6+uint32(s[1])]
if c0 < 0xF0 { // 3-byte UTF-8
return t.lookupValue(uint32(i), s[2])
}
i = nfcIndex[uint32(i)<<6+uint32(s[2])]
if c0 < 0xF8 { // 4-byte UTF-8
return t.lookupValue(uint32(i), s[3])
}
return 0
}
// nfcTrie. Total size: 10798 bytes (10.54 KiB). Checksum: b5981cc85e3bd14.
type nfcTrie struct{}
func newNfcTrie(i int) *nfcTrie {
return &nfcTrie{}
}
// lookupValue determines the type of block n and looks up the value for b.
func (t *nfcTrie) lookupValue(n uint32, b byte) uint16 {
switch {
case n < 46:
return uint16(nfcValues[n<<6+uint32(b)])
default:
n -= 46
return uint16(nfcSparse.lookup(n, b))
}
}
// nfcValues: 48 blocks, 3072 entries, 6144 bytes
// The third block is the zero block.
var nfcValues = [3072]uint16{
// Block 0x0, offset 0x0
0x3c: 0xa000, 0x3d: 0xa000, 0x3e: 0xa000,
// Block 0x1, offset 0x40
0x41: 0xa000, 0x42: 0xa000, 0x43: 0xa000, 0x44: 0xa000, 0x45: 0xa000,
0x46: 0xa000, 0x47: 0xa000, 0x48: 0xa000, 0x49: 0xa000, 0x4a: 0xa000, 0x4b: 0xa000,
0x4c: 0xa000, 0x4d: 0xa000, 0x4e: 0xa000, 0x4f: 0xa000, 0x50: 0xa000,
0x52: 0xa000, 0x53: 0xa000, 0x54: 0xa000, 0x55: 0xa000, 0x56: 0xa000, 0x57: 0xa000,
0x58: 0xa000, 0x59: 0xa000, 0x5a: 0xa000,
0x61: 0xa000, 0x62: 0xa000, 0x63: 0xa000,
0x64: 0xa000, 0x65: 0xa000, 0x66: 0xa000, 0x67: 0xa000, 0x68: 0xa000, 0x69: 0xa000,
0x6a: 0xa000, 0x6b: 0xa000, 0x6c: 0xa000, 0x6d: 0xa000, 0x6e: 0xa000, 0x6f: 0xa000,
0x70: 0xa000, 0x72: 0xa000, 0x73: 0xa000, 0x74: 0xa000, 0x75: 0xa000,
0x76: 0xa000, 0x77: 0xa000, 0x78: 0xa000, 0x79: 0xa000, 0x7a: 0xa000,
// Block 0x2, offset 0x80
// Block 0x3, offset 0xc0
0xc0: 0x30b0, 0xc1: 0x30b5, 0xc2: 0x47c9, 0xc3: 0x30ba, 0xc4: 0x47d8, 0xc5: 0x47dd,
0xc6: 0xa000, 0xc7: 0x47e7, 0xc8: 0x3123, 0xc9: 0x3128, 0xca: 0x47ec, 0xcb: 0x313c,
0xcc: 0x31af, 0xcd: 0x31b4, 0xce: 0x31b9, 0xcf: 0x4800, 0xd1: 0x3245,
0xd2: 0x3268, 0xd3: 0x326d, 0xd4: 0x480a, 0xd5: 0x480f, 0xd6: 0x481e,
0xd8: 0xa000, 0xd9: 0x32f4, 0xda: 0x32f9, 0xdb: 0x32fe, 0xdc: 0x4850, 0xdd: 0x3376,
0xe0: 0x33bc, 0xe1: 0x33c1, 0xe2: 0x485a, 0xe3: 0x33c6,
0xe4: 0x4869, 0xe5: 0x486e, 0xe6: 0xa000, 0xe7: 0x4878, 0xe8: 0x342f, 0xe9: 0x3434,
0xea: 0x487d, 0xeb: 0x3448, 0xec: 0x34c0, 0xed: 0x34c5, 0xee: 0x34ca, 0xef: 0x4891,
0xf1: 0x3556, 0xf2: 0x3579, 0xf3: 0x357e, 0xf4: 0x489b, 0xf5: 0x48a0,
0xf6: 0x48af, 0xf8: 0xa000, 0xf9: 0x360a, 0xfa: 0x360f, 0xfb: 0x3614,
0xfc: 0x48e1, 0xfd: 0x3691, 0xff: 0x36aa,
// Block 0x4, offset 0x100
0x100: 0x30bf, 0x101: 0x33cb, 0x102: 0x47ce, 0x103: 0x485f, 0x104: 0x30dd, 0x105: 0x33e9,
0x106: 0x30f1, 0x107: 0x33fd, 0x108: 0x30f6, 0x109: 0x3402, 0x10a: 0x30fb, 0x10b: 0x3407,
0x10c: 0x3100, 0x10d: 0x340c, 0x10e: 0x310a, 0x10f: 0x3416,
0x112: 0x47f1, 0x113: 0x4882, 0x114: 0x3132, 0x115: 0x343e, 0x116: 0x3137, 0x117: 0x3443,
0x118: 0x3155, 0x119: 0x3461, 0x11a: 0x3146, 0x11b: 0x3452, 0x11c: 0x316e, 0x11d: 0x347a,
0x11e: 0x3178, 0x11f: 0x3484, 0x120: 0x317d, 0x121: 0x3489, 0x122: 0x3187, 0x123: 0x3493,
0x124: 0x318c, 0x125: 0x3498, 0x128: 0x31be, 0x129: 0x34cf,
0x12a: 0x31c3, 0x12b: 0x34d4, 0x12c: 0x31c8, 0x12d: 0x34d9, 0x12e: 0x31eb, 0x12f: 0x34f7,
0x130: 0x31cd, 0x134: 0x31f5, 0x135: 0x3501,
0x136: 0x3209, 0x137: 0x351a, 0x139: 0x3213, 0x13a: 0x3524, 0x13b: 0x321d,
0x13c: 0x352e, 0x13d: 0x3218, 0x13e: 0x3529,
// Block 0x5, offset 0x140
0x143: 0x3240, 0x144: 0x3551, 0x145: 0x3259,
0x146: 0x356a, 0x147: 0x324f, 0x148: 0x3560,
0x14c: 0x4814, 0x14d: 0x48a5, 0x14e: 0x3272, 0x14f: 0x3583, 0x150: 0x327c, 0x151: 0x358d,
0x154: 0x329a, 0x155: 0x35ab, 0x156: 0x32b3, 0x157: 0x35c4,
0x158: 0x32a4, 0x159: 0x35b5, 0x15a: 0x4837, 0x15b: 0x48c8, 0x15c: 0x32bd, 0x15d: 0x35ce,
0x15e: 0x32cc, 0x15f: 0x35dd, 0x160: 0x483c, 0x161: 0x48cd, 0x162: 0x32e5, 0x163: 0x35fb,
0x164: 0x32d6, 0x165: 0x35ec, 0x168: 0x4846, 0x169: 0x48d7,
0x16a: 0x484b, 0x16b: 0x48dc, 0x16c: 0x3303, 0x16d: 0x3619, 0x16e: 0x330d, 0x16f: 0x3623,
0x170: 0x3312, 0x171: 0x3628, 0x172: 0x3330, 0x173: 0x3646, 0x174: 0x3353, 0x175: 0x3669,
0x176: 0x337b, 0x177: 0x3696, 0x178: 0x338f, 0x179: 0x339e, 0x17a: 0x36be, 0x17b: 0x33a8,
0x17c: 0x36c8, 0x17d: 0x33ad, 0x17e: 0x36cd, 0x17f: 0xa000,
// Block 0x6, offset 0x180
0x184: 0x8100, 0x185: 0x8100,
0x186: 0x8100,
0x18d: 0x30c9, 0x18e: 0x33d5, 0x18f: 0x31d7, 0x190: 0x34e3, 0x191: 0x3281,
0x192: 0x3592, 0x193: 0x3317, 0x194: 0x362d, 0x195: 0x3b10, 0x196: 0x3c9f, 0x197: 0x3b09,
0x198: 0x3c98, 0x199: 0x3b17, 0x19a: 0x3ca6, 0x19b: 0x3b02, 0x19c: 0x3c91,
0x19e: 0x39f1, 0x19f: 0x3b80, 0x1a0: 0x39ea, 0x1a1: 0x3b79, 0x1a2: 0x36f4, 0x1a3: 0x3706,
0x1a6: 0x3182, 0x1a7: 0x348e, 0x1a8: 0x31ff, 0x1a9: 0x3510,
0x1aa: 0x482d, 0x1ab: 0x48be, 0x1ac: 0x3ad1, 0x1ad: 0x3c60, 0x1ae: 0x3718, 0x1af: 0x371e,
0x1b0: 0x3506, 0x1b4: 0x3169, 0x1b5: 0x3475,
0x1b8: 0x323b, 0x1b9: 0x354c, 0x1ba: 0x39f8, 0x1bb: 0x3b87,
0x1bc: 0x36ee, 0x1bd: 0x3700, 0x1be: 0x36fa, 0x1bf: 0x370c,
// Block 0x7, offset 0x1c0
0x1c0: 0x30ce, 0x1c1: 0x33da, 0x1c2: 0x30d3, 0x1c3: 0x33df, 0x1c4: 0x314b, 0x1c5: 0x3457,
0x1c6: 0x3150, 0x1c7: 0x345c, 0x1c8: 0x31dc, 0x1c9: 0x34e8, 0x1ca: 0x31e1, 0x1cb: 0x34ed,
0x1cc: 0x3286, 0x1cd: 0x3597, 0x1ce: 0x328b, 0x1cf: 0x359c, 0x1d0: 0x32a9, 0x1d1: 0x35ba,
0x1d2: 0x32ae, 0x1d3: 0x35bf, 0x1d4: 0x331c, 0x1d5: 0x3632, 0x1d6: 0x3321, 0x1d7: 0x3637,
0x1d8: 0x32c7, 0x1d9: 0x35d8, 0x1da: 0x32e0, 0x1db: 0x35f6,
0x1de: 0x319b, 0x1df: 0x34a7,
0x1e6: 0x47d3, 0x1e7: 0x4864, 0x1e8: 0x47fb, 0x1e9: 0x488c,
0x1ea: 0x3aa0, 0x1eb: 0x3c2f, 0x1ec: 0x3a7d, 0x1ed: 0x3c0c, 0x1ee: 0x4819, 0x1ef: 0x48aa,
0x1f0: 0x3a99, 0x1f1: 0x3c28, 0x1f2: 0x3385, 0x1f3: 0x36a0,
// Block 0x8, offset 0x200
0x200: 0x9933, 0x201: 0x9933, 0x202: 0x9933, 0x203: 0x9933, 0x204: 0x9933, 0x205: 0x8133,
0x206: 0x9933, 0x207: 0x9933, 0x208: 0x9933, 0x209: 0x9933, 0x20a: 0x9933, 0x20b: 0x9933,
0x20c: 0x9933, 0x20d: 0x8133, 0x20e: 0x8133, 0x20f: 0x9933, 0x210: 0x8133, 0x211: 0x9933,
0x212: 0x8133, 0x213: 0x9933, 0x214: 0x9933, 0x215: 0x8134, 0x216: 0x812e, 0x217: 0x812e,
0x218: 0x812e, 0x219: 0x812e, 0x21a: 0x8134, 0x21b: 0x992c, 0x21c: 0x812e, 0x21d: 0x812e,
0x21e: 0x812e, 0x21f: 0x812e, 0x220: 0x812e, 0x221: 0x812a, 0x222: 0x812a, 0x223: 0x992e,
0x224: 0x992e, 0x225: 0x992e, 0x226: 0x992e, 0x227: 0x992a, 0x228: 0x992a, 0x229: 0x812e,
0x22a: 0x812e, 0x22b: 0x812e, 0x22c: 0x812e, 0x22d: 0x992e, 0x22e: 0x992e, 0x22f: 0x812e,
0x230: 0x992e, 0x231: 0x992e, 0x232: 0x812e, 0x233: 0x812e, 0x234: 0x8101, 0x235: 0x8101,
0x236: 0x8101, 0x237: 0x8101, 0x238: 0x9901, 0x239: 0x812e, 0x23a: 0x812e, 0x23b: 0x812e,
0x23c: 0x812e, 0x23d: 0x8133, 0x23e: 0x8133, 0x23f: 0x8133,
// Block 0x9, offset 0x240
0x240: 0x4aef, 0x241: 0x4af4, 0x242: 0x9933, 0x243: 0x4af9, 0x244: 0x4bb2, 0x245: 0x9937,
0x246: 0x8133, 0x247: 0x812e, 0x248: 0x812e, 0x249: 0x812e, 0x24a: 0x8133, 0x24b: 0x8133,
0x24c: 0x8133, 0x24d: 0x812e, 0x24e: 0x812e, 0x250: 0x8133, 0x251: 0x8133,
0x252: 0x8133, 0x253: 0x812e, 0x254: 0x812e, 0x255: 0x812e, 0x256: 0x812e, 0x257: 0x8133,
0x258: 0x8134, 0x259: 0x812e, 0x25a: 0x812e, 0x25b: 0x8133, 0x25c: 0x8135, 0x25d: 0x8136,
0x25e: 0x8136, 0x25f: 0x8135, 0x260: 0x8136, 0x261: 0x8136, 0x262: 0x8135, 0x263: 0x8133,
0x264: 0x8133, 0x265: 0x8133, 0x266: 0x8133, 0x267: 0x8133, 0x268: 0x8133, 0x269: 0x8133,
0x26a: 0x8133, 0x26b: 0x8133, 0x26c: 0x8133, 0x26d: 0x8133, 0x26e: 0x8133, 0x26f: 0x8133,
0x274: 0x01ee,
0x27a: 0x8100,
0x27e: 0x0037,
// Block 0xa, offset 0x280
0x284: 0x8100, 0x285: 0x36e2,
0x286: 0x372a, 0x287: 0x00ce, 0x288: 0x3748, 0x289: 0x3754, 0x28a: 0x3766,
0x28c: 0x3784, 0x28e: 0x3796, 0x28f: 0x37b4, 0x290: 0x3f49, 0x291: 0xa000,
0x295: 0xa000, 0x297: 0xa000,
0x299: 0xa000,
0x29f: 0xa000, 0x2a1: 0xa000,
0x2a5: 0xa000, 0x2a9: 0xa000,
0x2aa: 0x3778, 0x2ab: 0x37a8, 0x2ac: 0x493f, 0x2ad: 0x37d8, 0x2ae: 0x4969, 0x2af: 0x37ea,
0x2b0: 0x3fb1, 0x2b1: 0xa000, 0x2b5: 0xa000,
0x2b7: 0xa000, 0x2b9: 0xa000,
0x2bf: 0xa000,
// Block 0xb, offset 0x2c0
0x2c0: 0x3862, 0x2c1: 0x386e, 0x2c3: 0x385c,
0x2c6: 0xa000, 0x2c7: 0x384a,
0x2cc: 0x389e, 0x2cd: 0x3886, 0x2ce: 0x38b0, 0x2d0: 0xa000,
0x2d3: 0xa000, 0x2d5: 0xa000, 0x2d6: 0xa000, 0x2d7: 0xa000,
0x2d8: 0xa000, 0x2d9: 0x3892, 0x2da: 0xa000,
0x2de: 0xa000, 0x2e3: 0xa000,
0x2e7: 0xa000,
0x2eb: 0xa000, 0x2ed: 0xa000,
0x2f0: 0xa000, 0x2f3: 0xa000, 0x2f5: 0xa000,
0x2f6: 0xa000, 0x2f7: 0xa000, 0x2f8: 0xa000, 0x2f9: 0x3916, 0x2fa: 0xa000,
0x2fe: 0xa000,
// Block 0xc, offset 0x300
0x301: 0x3874, 0x302: 0x38f8,
0x310: 0x3850, 0x311: 0x38d4,
0x312: 0x3856, 0x313: 0x38da, 0x316: 0x3868, 0x317: 0x38ec,
0x318: 0xa000, 0x319: 0xa000, 0x31a: 0x396a, 0x31b: 0x3970, 0x31c: 0x387a, 0x31d: 0x38fe,
0x31e: 0x3880, 0x31f: 0x3904, 0x322: 0x388c, 0x323: 0x3910,
0x324: 0x3898, 0x325: 0x391c, 0x326: 0x38a4, 0x327: 0x3928, 0x328: 0xa000, 0x329: 0xa000,
0x32a: 0x3976, 0x32b: 0x397c, 0x32c: 0x38ce, 0x32d: 0x3952, 0x32e: 0x38aa, 0x32f: 0x392e,
0x330: 0x38b6, 0x331: 0x393a, 0x332: 0x38bc, 0x333: 0x3940, 0x334: 0x38c2, 0x335: 0x3946,
0x338: 0x38c8, 0x339: 0x394c,
// Block 0xd, offset 0x340
0x351: 0x812e,
0x352: 0x8133, 0x353: 0x8133, 0x354: 0x8133, 0x355: 0x8133, 0x356: 0x812e, 0x357: 0x8133,
0x358: 0x8133, 0x359: 0x8133, 0x35a: 0x812f, 0x35b: 0x812e, 0x35c: 0x8133, 0x35d: 0x8133,
0x35e: 0x8133, 0x35f: 0x8133, 0x360: 0x8133, 0x361: 0x8133, 0x362: 0x812e, 0x363: 0x812e,
0x364: 0x812e, 0x365: 0x812e, 0x366: 0x812e, 0x367: 0x812e, 0x368: 0x8133, 0x369: 0x8133,
0x36a: 0x812e, 0x36b: 0x8133, 0x36c: 0x8133, 0x36d: 0x812f, 0x36e: 0x8132, 0x36f: 0x8133,
0x370: 0x8106, 0x371: 0x8107, 0x372: 0x8108, 0x373: 0x8109, 0x374: 0x810a, 0x375: 0x810b,
0x376: 0x810c, 0x377: 0x810d, 0x378: 0x810e, 0x379: 0x810f, 0x37a: 0x810f, 0x37b: 0x8110,
0x37c: 0x8111, 0x37d: 0x8112, 0x37f: 0x8113,
// Block 0xe, offset 0x380
0x388: 0xa000, 0x38a: 0xa000, 0x38b: 0x8117,
0x38c: 0x8118, 0x38d: 0x8119, 0x38e: 0x811a, 0x38f: 0x811b, 0x390: 0x811c, 0x391: 0x811d,
0x392: 0x811e, 0x393: 0x9933, 0x394: 0x9933, 0x395: 0x992e, 0x396: 0x812e, 0x397: 0x8133,
0x398: 0x8133, 0x399: 0x8133, 0x39a: 0x8133, 0x39b: 0x8133, 0x39c: 0x812e, 0x39d: 0x8133,
0x39e: 0x8133, 0x39f: 0x812e,
0x3b0: 0x811f,
// Block 0xf, offset 0x3c0
0x3ca: 0x8133, 0x3cb: 0x8133,
0x3cc: 0x8133, 0x3cd: 0x8133, 0x3ce: 0x8133, 0x3cf: 0x812e, 0x3d0: 0x812e, 0x3d1: 0x812e,
0x3d2: 0x812e, 0x3d3: 0x812e, 0x3d4: 0x8133, 0x3d5: 0x8133, 0x3d6: 0x8133, 0x3d7: 0x8133,
0x3d8: 0x8133, 0x3d9: 0x8133, 0x3da: 0x8133, 0x3db: 0x8133, 0x3dc: 0x8133, 0x3dd: 0x8133,
0x3de: 0x8133, 0x3df: 0x8133, 0x3e0: 0x8133, 0x3e1: 0x8133, 0x3e3: 0x812e,
0x3e4: 0x8133, 0x3e5: 0x8133, 0x3e6: 0x812e, 0x3e7: 0x8133, 0x3e8: 0x8133, 0x3e9: 0x812e,
0x3ea: 0x8133, 0x3eb: 0x8133, 0x3ec: 0x8133, 0x3ed: 0x812e, 0x3ee: 0x812e, 0x3ef: 0x812e,
0x3f0: 0x8117, 0x3f1: 0x8118, 0x3f2: 0x8119, 0x3f3: 0x8133, 0x3f4: 0x8133, 0x3f5: 0x8133,
0x3f6: 0x812e, 0x3f7: 0x8133, 0x3f8: 0x8133, 0x3f9: 0x812e, 0x3fa: 0x812e, 0x3fb: 0x8133,
0x3fc: 0x8133, 0x3fd: 0x8133, 0x3fe: 0x8133, 0x3ff: 0x8133,
// Block 0x10, offset 0x400
0x405: 0xa000,
0x406: 0x2e5d, 0x407: 0xa000, 0x408: 0x2e65, 0x409: 0xa000, 0x40a: 0x2e6d, 0x40b: 0xa000,
0x40c: 0x2e75, 0x40d: 0xa000, 0x40e: 0x2e7d, 0x411: 0xa000,
0x412: 0x2e85,
0x434: 0x8103, 0x435: 0x9900,
0x43a: 0xa000, 0x43b: 0x2e8d,
0x43c: 0xa000, 0x43d: 0x2e95, 0x43e: 0xa000, 0x43f: 0xa000,
// Block 0x11, offset 0x440
0x440: 0x8133, 0x441: 0x8133, 0x442: 0x812e, 0x443: 0x8133, 0x444: 0x8133, 0x445: 0x8133,
0x446: 0x8133, 0x447: 0x8133, 0x448: 0x8133, 0x449: 0x8133, 0x44a: 0x812e, 0x44b: 0x8133,
0x44c: 0x8133, 0x44d: 0x8136, 0x44e: 0x812b, 0x44f: 0x812e, 0x450: 0x812a, 0x451: 0x8133,
0x452: 0x8133, 0x453: 0x8133, 0x454: 0x8133, 0x455: 0x8133, 0x456: 0x8133, 0x457: 0x8133,
0x458: 0x8133, 0x459: 0x8133, 0x45a: 0x8133, 0x45b: 0x8133, 0x45c: 0x8133, 0x45d: 0x8133,
0x45e: 0x8133, 0x45f: 0x8133, 0x460: 0x8133, 0x461: 0x8133, 0x462: 0x8133, 0x463: 0x8133,
0x464: 0x8133, 0x465: 0x8133, 0x466: 0x8133, 0x467: 0x8133, 0x468: 0x8133, 0x469: 0x8133,
0x46a: 0x8133, 0x46b: 0x8133, 0x46c: 0x8133, 0x46d: 0x8133, 0x46e: 0x8133, 0x46f: 0x8133,
0x470: 0x8133, 0x471: 0x8133, 0x472: 0x8133, 0x473: 0x8133, 0x474: 0x8133, 0x475: 0x8133,
0x476: 0x8134, 0x477: 0x8132, 0x478: 0x8132, 0x479: 0x812e, 0x47a: 0x812d, 0x47b: 0x8133,
0x47c: 0x8135, 0x47d: 0x812e, 0x47e: 0x8133, 0x47f: 0x812e,
// Block 0x12, offset 0x480
0x480: 0x30d8, 0x481: 0x33e4, 0x482: 0x30e2, 0x483: 0x33ee, 0x484: 0x30e7, 0x485: 0x33f3,
0x486: 0x30ec, 0x487: 0x33f8, 0x488: 0x3a0d, 0x489: 0x3b9c, 0x48a: 0x3105, 0x48b: 0x3411,
0x48c: 0x310f, 0x48d: 0x341b, 0x48e: 0x311e, 0x48f: 0x342a, 0x490: 0x3114, 0x491: 0x3420,
0x492: 0x3119, 0x493: 0x3425, 0x494: 0x3a30, 0x495: 0x3bbf, 0x496: 0x3a37, 0x497: 0x3bc6,
0x498: 0x315a, 0x499: 0x3466, 0x49a: 0x315f, 0x49b: 0x346b, 0x49c: 0x3a45, 0x49d: 0x3bd4,
0x49e: 0x3164, 0x49f: 0x3470, 0x4a0: 0x3173, 0x4a1: 0x347f, 0x4a2: 0x3191, 0x4a3: 0x349d,
0x4a4: 0x31a0, 0x4a5: 0x34ac, 0x4a6: 0x3196, 0x4a7: 0x34a2, 0x4a8: 0x31a5, 0x4a9: 0x34b1,
0x4aa: 0x31aa, 0x4ab: 0x34b6, 0x4ac: 0x31f0, 0x4ad: 0x34fc, 0x4ae: 0x3a4c, 0x4af: 0x3bdb,
0x4b0: 0x31fa, 0x4b1: 0x350b, 0x4b2: 0x3204, 0x4b3: 0x3515, 0x4b4: 0x320e, 0x4b5: 0x351f,
0x4b6: 0x4805, 0x4b7: 0x4896, 0x4b8: 0x3a53, 0x4b9: 0x3be2, 0x4ba: 0x3227, 0x4bb: 0x3538,
0x4bc: 0x3222, 0x4bd: 0x3533, 0x4be: 0x322c, 0x4bf: 0x353d,
// Block 0x13, offset 0x4c0
0x4c0: 0x3231, 0x4c1: 0x3542, 0x4c2: 0x3236, 0x4c3: 0x3547, 0x4c4: 0x324a, 0x4c5: 0x355b,
0x4c6: 0x3254, 0x4c7: 0x3565, 0x4c8: 0x3263, 0x4c9: 0x3574, 0x4ca: 0x325e, 0x4cb: 0x356f,
0x4cc: 0x3a76, 0x4cd: 0x3c05, 0x4ce: 0x3a84, 0x4cf: 0x3c13, 0x4d0: 0x3a8b, 0x4d1: 0x3c1a,
0x4d2: 0x3a92, 0x4d3: 0x3c21, 0x4d4: 0x3290, 0x4d5: 0x35a1, 0x4d6: 0x3295, 0x4d7: 0x35a6,
0x4d8: 0x329f, 0x4d9: 0x35b0, 0x4da: 0x4832, 0x4db: 0x48c3, 0x4dc: 0x3ad8, 0x4dd: 0x3c67,
0x4de: 0x32b8, 0x4df: 0x35c9, 0x4e0: 0x32c2, 0x4e1: 0x35d3, 0x4e2: 0x4841, 0x4e3: 0x48d2,
0x4e4: 0x3adf, 0x4e5: 0x3c6e, 0x4e6: 0x3ae6, 0x4e7: 0x3c75, 0x4e8: 0x3aed, 0x4e9: 0x3c7c,
0x4ea: 0x32d1, 0x4eb: 0x35e2, 0x4ec: 0x32db, 0x4ed: 0x35f1, 0x4ee: 0x32ef, 0x4ef: 0x3605,
0x4f0: 0x32ea, 0x4f1: 0x3600, 0x4f2: 0x332b, 0x4f3: 0x3641, 0x4f4: 0x333a, 0x4f5: 0x3650,
0x4f6: 0x3335, 0x4f7: 0x364b, 0x4f8: 0x3af4, 0x4f9: 0x3c83, 0x4fa: 0x3afb, 0x4fb: 0x3c8a,
0x4fc: 0x333f, 0x4fd: 0x3655, 0x4fe: 0x3344, 0x4ff: 0x365a,
// Block 0x14, offset 0x500
0x500: 0x3349, 0x501: 0x365f, 0x502: 0x334e, 0x503: 0x3664, 0x504: 0x335d, 0x505: 0x3673,
0x506: 0x3358, 0x507: 0x366e, 0x508: 0x3362, 0x509: 0x367d, 0x50a: 0x3367, 0x50b: 0x3682,
0x50c: 0x336c, 0x50d: 0x3687, 0x50e: 0x338a, 0x50f: 0x36a5, 0x510: 0x33a3, 0x511: 0x36c3,
0x512: 0x33b2, 0x513: 0x36d2, 0x514: 0x33b7, 0x515: 0x36d7, 0x516: 0x34bb, 0x517: 0x35e7,
0x518: 0x3678, 0x519: 0x36b4, 0x51b: 0x3712,
0x520: 0x47e2, 0x521: 0x4873, 0x522: 0x30c4, 0x523: 0x33d0,
0x524: 0x39b9, 0x525: 0x3b48, 0x526: 0x39b2, 0x527: 0x3b41, 0x528: 0x39c7, 0x529: 0x3b56,
0x52a: 0x39c0, 0x52b: 0x3b4f, 0x52c: 0x39ff, 0x52d: 0x3b8e, 0x52e: 0x39d5, 0x52f: 0x3b64,
0x530: 0x39ce, 0x531: 0x3b5d, 0x532: 0x39e3, 0x533: 0x3b72, 0x534: 0x39dc, 0x535: 0x3b6b,
0x536: 0x3a06, 0x537: 0x3b95, 0x538: 0x47f6, 0x539: 0x4887, 0x53a: 0x3141, 0x53b: 0x344d,
0x53c: 0x312d, 0x53d: 0x3439, 0x53e: 0x3a1b, 0x53f: 0x3baa,
// Block 0x15, offset 0x540
0x540: 0x3a14, 0x541: 0x3ba3, 0x542: 0x3a29, 0x543: 0x3bb8, 0x544: 0x3a22, 0x545: 0x3bb1,
0x546: 0x3a3e, 0x547: 0x3bcd, 0x548: 0x31d2, 0x549: 0x34de, 0x54a: 0x31e6, 0x54b: 0x34f2,
0x54c: 0x4828, 0x54d: 0x48b9, 0x54e: 0x3277, 0x54f: 0x3588, 0x550: 0x3a61, 0x551: 0x3bf0,
0x552: 0x3a5a, 0x553: 0x3be9, 0x554: 0x3a6f, 0x555: 0x3bfe, 0x556: 0x3a68, 0x557: 0x3bf7,
0x558: 0x3aca, 0x559: 0x3c59, 0x55a: 0x3aae, 0x55b: 0x3c3d, 0x55c: 0x3aa7, 0x55d: 0x3c36,
0x55e: 0x3abc, 0x55f: 0x3c4b, 0x560: 0x3ab5, 0x561: 0x3c44, 0x562: 0x3ac3, 0x563: 0x3c52,
0x564: 0x3326, 0x565: 0x363c, 0x566: 0x3308, 0x567: 0x361e, 0x568: 0x3b25, 0x569: 0x3cb4,
0x56a: 0x3b1e, 0x56b: 0x3cad, 0x56c: 0x3b33, 0x56d: 0x3cc2, 0x56e: 0x3b2c, 0x56f: 0x3cbb,
0x570: 0x3b3a, 0x571: 0x3cc9, 0x572: 0x3371, 0x573: 0x368c, 0x574: 0x3399, 0x575: 0x36b9,
0x576: 0x3394, 0x577: 0x36af, 0x578: 0x3380, 0x579: 0x369b,
// Block 0x16, offset 0x580
0x580: 0x4945, 0x581: 0x494b, 0x582: 0x4a5f, 0x583: 0x4a77, 0x584: 0x4a67, 0x585: 0x4a7f,
0x586: 0x4a6f, 0x587: 0x4a87, 0x588: 0x48eb, 0x589: 0x48f1, 0x58a: 0x49cf, 0x58b: 0x49e7,
0x58c: 0x49d7, 0x58d: 0x49ef, 0x58e: 0x49df, 0x58f: 0x49f7, 0x590: 0x4957, 0x591: 0x495d,
0x592: 0x3ef9, 0x593: 0x3f09, 0x594: 0x3f01, 0x595: 0x3f11,
0x598: 0x48f7, 0x599: 0x48fd, 0x59a: 0x3e29, 0x59b: 0x3e39, 0x59c: 0x3e31, 0x59d: 0x3e41,
0x5a0: 0x496f, 0x5a1: 0x4975, 0x5a2: 0x4a8f, 0x5a3: 0x4aa7,
0x5a4: 0x4a97, 0x5a5: 0x4aaf, 0x5a6: 0x4a9f, 0x5a7: 0x4ab7, 0x5a8: 0x4903, 0x5a9: 0x4909,
0x5aa: 0x49ff, 0x5ab: 0x4a17, 0x5ac: 0x4a07, 0x5ad: 0x4a1f, 0x5ae: 0x4a0f, 0x5af: 0x4a27,
0x5b0: 0x4987, 0x5b1: 0x498d, 0x5b2: 0x3f59, 0x5b3: 0x3f71, 0x5b4: 0x3f61, 0x5b5: 0x3f79,
0x5b6: 0x3f69, 0x5b7: 0x3f81, 0x5b8: 0x490f, 0x5b9: 0x4915, 0x5ba: 0x3e59, 0x5bb: 0x3e71,
0x5bc: 0x3e61, 0x5bd: 0x3e79, 0x5be: 0x3e69, 0x5bf: 0x3e81,
// Block 0x17, offset 0x5c0
0x5c0: 0x4993, 0x5c1: 0x4999, 0x5c2: 0x3f89, 0x5c3: 0x3f99, 0x5c4: 0x3f91, 0x5c5: 0x3fa1,
0x5c8: 0x491b, 0x5c9: 0x4921, 0x5ca: 0x3e89, 0x5cb: 0x3e99,
0x5cc: 0x3e91, 0x5cd: 0x3ea1, 0x5d0: 0x49a5, 0x5d1: 0x49ab,
0x5d2: 0x3fc1, 0x5d3: 0x3fd9, 0x5d4: 0x3fc9, 0x5d5: 0x3fe1, 0x5d6: 0x3fd1, 0x5d7: 0x3fe9,
0x5d9: 0x4927, 0x5db: 0x3ea9, 0x5dd: 0x3eb1,
0x5df: 0x3eb9, 0x5e0: 0x49bd, 0x5e1: 0x49c3, 0x5e2: 0x4abf, 0x5e3: 0x4ad7,
0x5e4: 0x4ac7, 0x5e5: 0x4adf, 0x5e6: 0x4acf, 0x5e7: 0x4ae7, 0x5e8: 0x492d, 0x5e9: 0x4933,
0x5ea: 0x4a2f, 0x5eb: 0x4a47, 0x5ec: 0x4a37, 0x5ed: 0x4a4f, 0x5ee: 0x4a3f, 0x5ef: 0x4a57,
0x5f0: 0x4939, 0x5f1: 0x445f, 0x5f2: 0x37d2, 0x5f3: 0x4465, 0x5f4: 0x4963, 0x5f5: 0x446b,
0x5f6: 0x37e4, 0x5f7: 0x4471, 0x5f8: 0x3802, 0x5f9: 0x4477, 0x5fa: 0x381a, 0x5fb: 0x447d,
0x5fc: 0x49b1, 0x5fd: 0x4483,
// Block 0x18, offset 0x600
0x600: 0x3ee1, 0x601: 0x3ee9, 0x602: 0x42c5, 0x603: 0x42e3, 0x604: 0x42cf, 0x605: 0x42ed,
0x606: 0x42d9, 0x607: 0x42f7, 0x608: 0x3e19, 0x609: 0x3e21, 0x60a: 0x4211, 0x60b: 0x422f,
0x60c: 0x421b, 0x60d: 0x4239, 0x60e: 0x4225, 0x60f: 0x4243, 0x610: 0x3f29, 0x611: 0x3f31,
0x612: 0x4301, 0x613: 0x431f, 0x614: 0x430b, 0x615: 0x4329, 0x616: 0x4315, 0x617: 0x4333,
0x618: 0x3e49, 0x619: 0x3e51, 0x61a: 0x424d, 0x61b: 0x426b, 0x61c: 0x4257, 0x61d: 0x4275,
0x61e: 0x4261, 0x61f: 0x427f, 0x620: 0x4001, 0x621: 0x4009, 0x622: 0x433d, 0x623: 0x435b,
0x624: 0x4347, 0x625: 0x4365, 0x626: 0x4351, 0x627: 0x436f, 0x628: 0x3ec1, 0x629: 0x3ec9,
0x62a: 0x4289, 0x62b: 0x42a7, 0x62c: 0x4293, 0x62d: 0x42b1, 0x62e: 0x429d, 0x62f: 0x42bb,
0x630: 0x37c6, 0x631: 0x37c0, 0x632: 0x3ed1, 0x633: 0x37cc, 0x634: 0x3ed9,
0x636: 0x4951, 0x637: 0x3ef1, 0x638: 0x3736, 0x639: 0x3730, 0x63a: 0x3724, 0x63b: 0x442f,
0x63c: 0x373c, 0x63d: 0x8100, 0x63e: 0x0257, 0x63f: 0xa100,
// Block 0x19, offset 0x640
0x640: 0x8100, 0x641: 0x36e8, 0x642: 0x3f19, 0x643: 0x37de, 0x644: 0x3f21,
0x646: 0x497b, 0x647: 0x3f39, 0x648: 0x3742, 0x649: 0x4435, 0x64a: 0x374e, 0x64b: 0x443b,
0x64c: 0x375a, 0x64d: 0x3cd0, 0x64e: 0x3cd7, 0x64f: 0x3cde, 0x650: 0x37f6, 0x651: 0x37f0,
0x652: 0x3f41, 0x653: 0x4625, 0x656: 0x37fc, 0x657: 0x3f51,
0x658: 0x3772, 0x659: 0x376c, 0x65a: 0x3760, 0x65b: 0x4441, 0x65d: 0x3ce5,
0x65e: 0x3cec, 0x65f: 0x3cf3, 0x660: 0x382c, 0x661: 0x3826, 0x662: 0x3fa9, 0x663: 0x462d,
0x664: 0x380e, 0x665: 0x3814, 0x666: 0x3832, 0x667: 0x3fb9, 0x668: 0x37a2, 0x669: 0x379c,
0x66a: 0x3790, 0x66b: 0x444d, 0x66c: 0x378a, 0x66d: 0x36dc, 0x66e: 0x4429, 0x66f: 0x0081,
0x672: 0x3ff1, 0x673: 0x3838, 0x674: 0x3ff9,
0x676: 0x49c9, 0x677: 0x4011, 0x678: 0x377e, 0x679: 0x4447, 0x67a: 0x37ae, 0x67b: 0x4459,
0x67c: 0x37ba, 0x67d: 0x4397, 0x67e: 0xa100,
// Block 0x1a, offset 0x680
0x681: 0x3d47, 0x683: 0xa000, 0x684: 0x3d4e, 0x685: 0xa000,
0x687: 0x3d55, 0x688: 0xa000, 0x689: 0x3d5c,
0x68d: 0xa000,
0x6a0: 0x30a6, 0x6a1: 0xa000, 0x6a2: 0x3d6a,
0x6a4: 0xa000, 0x6a5: 0xa000,
0x6ad: 0x3d63, 0x6ae: 0x30a1, 0x6af: 0x30ab,
0x6b0: 0x3d71, 0x6b1: 0x3d78, 0x6b2: 0xa000, 0x6b3: 0xa000, 0x6b4: 0x3d7f, 0x6b5: 0x3d86,
0x6b6: 0xa000, 0x6b7: 0xa000, 0x6b8: 0x3d8d, 0x6b9: 0x3d94, 0x6ba: 0xa000, 0x6bb: 0xa000,
0x6bc: 0xa000, 0x6bd: 0xa000,
// Block 0x1b, offset 0x6c0
0x6c0: 0x3d9b, 0x6c1: 0x3da2, 0x6c2: 0xa000, 0x6c3: 0xa000, 0x6c4: 0x3db7, 0x6c5: 0x3dbe,
0x6c6: 0xa000, 0x6c7: 0xa000, 0x6c8: 0x3dc5, 0x6c9: 0x3dcc,
0x6d1: 0xa000,
0x6d2: 0xa000,
0x6e2: 0xa000,
0x6e8: 0xa000, 0x6e9: 0xa000,
0x6eb: 0xa000, 0x6ec: 0x3de1, 0x6ed: 0x3de8, 0x6ee: 0x3def, 0x6ef: 0x3df6,
0x6f2: 0xa000, 0x6f3: 0xa000, 0x6f4: 0xa000, 0x6f5: 0xa000,
// Block 0x1c, offset 0x700
0x706: 0xa000, 0x70b: 0xa000,
0x70c: 0x4049, 0x70d: 0xa000, 0x70e: 0x4051, 0x70f: 0xa000, 0x710: 0x4059, 0x711: 0xa000,
0x712: 0x4061, 0x713: 0xa000, 0x714: 0x4069, 0x715: 0xa000, 0x716: 0x4071, 0x717: 0xa000,
0x718: 0x4079, 0x719: 0xa000, 0x71a: 0x4081, 0x71b: 0xa000, 0x71c: 0x4089, 0x71d: 0xa000,
0x71e: 0x4091, 0x71f: 0xa000, 0x720: 0x4099, 0x721: 0xa000, 0x722: 0x40a1,
0x724: 0xa000, 0x725: 0x40a9, 0x726: 0xa000, 0x727: 0x40b1, 0x728: 0xa000, 0x729: 0x40b9,
0x72f: 0xa000,
0x730: 0x40c1, 0x731: 0x40c9, 0x732: 0xa000, 0x733: 0x40d1, 0x734: 0x40d9, 0x735: 0xa000,
0x736: 0x40e1, 0x737: 0x40e9, 0x738: 0xa000, 0x739: 0x40f1, 0x73a: 0x40f9, 0x73b: 0xa000,
0x73c: 0x4101, 0x73d: 0x4109,
// Block 0x1d, offset 0x740
0x754: 0x4041,
0x759: 0x9904, 0x75a: 0x9904, 0x75b: 0x8100, 0x75c: 0x8100, 0x75d: 0xa000,
0x75e: 0x4111,
0x766: 0xa000,
0x76b: 0xa000, 0x76c: 0x4121, 0x76d: 0xa000, 0x76e: 0x4129, 0x76f: 0xa000,
0x770: 0x4131, 0x771: 0xa000, 0x772: 0x4139, 0x773: 0xa000, 0x774: 0x4141, 0x775: 0xa000,
0x776: 0x4149, 0x777: 0xa000, 0x778: 0x4151, 0x779: 0xa000, 0x77a: 0x4159, 0x77b: 0xa000,
0x77c: 0x4161, 0x77d: 0xa000, 0x77e: 0x4169, 0x77f: 0xa000,
// Block 0x1e, offset 0x780
0x780: 0x4171, 0x781: 0xa000, 0x782: 0x4179, 0x784: 0xa000, 0x785: 0x4181,
0x786: 0xa000, 0x787: 0x4189, 0x788: 0xa000, 0x789: 0x4191,
0x78f: 0xa000, 0x790: 0x4199, 0x791: 0x41a1,
0x792: 0xa000, 0x793: 0x41a9, 0x794: 0x41b1, 0x795: 0xa000, 0x796: 0x41b9, 0x797: 0x41c1,
0x798: 0xa000, 0x799: 0x41c9, 0x79a: 0x41d1, 0x79b: 0xa000, 0x79c: 0x41d9, 0x79d: 0x41e1,
0x7af: 0xa000,
0x7b0: 0xa000, 0x7b1: 0xa000, 0x7b2: 0xa000, 0x7b4: 0x4119,
0x7b7: 0x41e9, 0x7b8: 0x41f1, 0x7b9: 0x41f9, 0x7ba: 0x4201,
0x7bd: 0xa000, 0x7be: 0x4209,
// Block 0x1f, offset 0x7c0
0x7c0: 0x1472, 0x7c1: 0x0df6, 0x7c2: 0x14ce, 0x7c3: 0x149a, 0x7c4: 0x0f52, 0x7c5: 0x07e6,
0x7c6: 0x09da, 0x7c7: 0x1726, 0x7c8: 0x1726, 0x7c9: 0x0b06, 0x7ca: 0x155a, 0x7cb: 0x0a3e,
0x7cc: 0x0b02, 0x7cd: 0x0cea, 0x7ce: 0x10ca, 0x7cf: 0x125a, 0x7d0: 0x1392, 0x7d1: 0x13ce,
0x7d2: 0x1402, 0x7d3: 0x1516, 0x7d4: 0x0e6e, 0x7d5: 0x0efa, 0x7d6: 0x0fa6, 0x7d7: 0x103e,
0x7d8: 0x135a, 0x7d9: 0x1542, 0x7da: 0x166e, 0x7db: 0x080a, 0x7dc: 0x09ae, 0x7dd: 0x0e82,
0x7de: 0x0fca, 0x7df: 0x138e, 0x7e0: 0x16be, 0x7e1: 0x0bae, 0x7e2: 0x0f72, 0x7e3: 0x137e,
0x7e4: 0x1412, 0x7e5: 0x0d1e, 0x7e6: 0x12b6, 0x7e7: 0x13da, 0x7e8: 0x0c1a, 0x7e9: 0x0e0a,
0x7ea: 0x0f12, 0x7eb: 0x1016, 0x7ec: 0x1522, 0x7ed: 0x084a, 0x7ee: 0x08e2, 0x7ef: 0x094e,
0x7f0: 0x0d86, 0x7f1: 0x0e7a, 0x7f2: 0x0fc6, 0x7f3: 0x10ea, 0x7f4: 0x1272, 0x7f5: 0x1386,
0x7f6: 0x139e, 0x7f7: 0x14c2, 0x7f8: 0x15ea, 0x7f9: 0x169e, 0x7fa: 0x16ba, 0x7fb: 0x1126,
0x7fc: 0x1166, 0x7fd: 0x121e, 0x7fe: 0x133e, 0x7ff: 0x1576,
// Block 0x20, offset 0x800
0x800: 0x16c6, 0x801: 0x1446, 0x802: 0x0ac2, 0x803: 0x0c36, 0x804: 0x11d6, 0x805: 0x1296,
0x806: 0x0ffa, 0x807: 0x112e, 0x808: 0x1492, 0x809: 0x15e2, 0x80a: 0x0abe, 0x80b: 0x0b8a,
0x80c: 0x0e72, 0x80d: 0x0f26, 0x80e: 0x0f5a, 0x80f: 0x120e, 0x810: 0x1236, 0x811: 0x15a2,
0x812: 0x094a, 0x813: 0x12a2, 0x814: 0x08ee, 0x815: 0x08ea, 0x816: 0x1192, 0x817: 0x1222,
0x818: 0x1356, 0x819: 0x15aa, 0x81a: 0x1462, 0x81b: 0x0d22, 0x81c: 0x0e6e, 0x81d: 0x1452,
0x81e: 0x07f2, 0x81f: 0x0b5e, 0x820: 0x0c8e, 0x821: 0x102a, 0x822: 0x10aa, 0x823: 0x096e,
0x824: 0x1136, 0x825: 0x085a, 0x826: 0x0c72, 0x827: 0x07d2, 0x828: 0x0ee6, 0x829: 0x0d9e,
0x82a: 0x120a, 0x82b: 0x09c2, 0x82c: 0x0aae, 0x82d: 0x10f6, 0x82e: 0x135e, 0x82f: 0x1436,
0x830: 0x0eb2, 0x831: 0x14f2, 0x832: 0x0ede, 0x833: 0x0d32, 0x834: 0x1316, 0x835: 0x0d52,
0x836: 0x10a6, 0x837: 0x0826, 0x838: 0x08a2, 0x839: 0x08e6, 0x83a: 0x0e4e, 0x83b: 0x11f6,
0x83c: 0x12ee, 0x83d: 0x1442, 0x83e: 0x1556, 0x83f: 0x0956,
// Block 0x21, offset 0x840
0x840: 0x0a0a, 0x841: 0x0b12, 0x842: 0x0c2a, 0x843: 0x0dba, 0x844: 0x0f76, 0x845: 0x113a,
0x846: 0x1592, 0x847: 0x1676, 0x848: 0x16ca, 0x849: 0x16e2, 0x84a: 0x0932, 0x84b: 0x0dee,
0x84c: 0x0e9e, 0x84d: 0x14e6, 0x84e: 0x0bf6, 0x84f: 0x0cd2, 0x850: 0x0cee, 0x851: 0x0d7e,
0x852: 0x0f66, 0x853: 0x0fb2, 0x854: 0x1062, 0x855: 0x1186, 0x856: 0x122a, 0x857: 0x128e,
0x858: 0x14d6, 0x859: 0x1366, 0x85a: 0x14fe, 0x85b: 0x157a, 0x85c: 0x090a, 0x85d: 0x0936,
0x85e: 0x0a1e, 0x85f: 0x0fa2, 0x860: 0x13ee, 0x861: 0x1436, 0x862: 0x0c16, 0x863: 0x0c86,
0x864: 0x0d4a, 0x865: 0x0eaa, 0x866: 0x11d2, 0x867: 0x101e, 0x868: 0x0836, 0x869: 0x0a7a,
0x86a: 0x0b5e, 0x86b: 0x0bc2, 0x86c: 0x0c92, 0x86d: 0x103a, 0x86e: 0x1056, 0x86f: 0x1266,
0x870: 0x1286, 0x871: 0x155e, 0x872: 0x15de, 0x873: 0x15ee, 0x874: 0x162a, 0x875: 0x084e,
0x876: 0x117a, 0x877: 0x154a, 0x878: 0x15c6, 0x879: 0x0caa, 0x87a: 0x0812, 0x87b: 0x0872,
0x87c: 0x0b62, 0x87d: 0x0b82, 0x87e: 0x0daa, 0x87f: 0x0e6e,
// Block 0x22, offset 0x880
0x880: 0x0fbe, 0x881: 0x10c6, 0x882: 0x1372, 0x883: 0x1512, 0x884: 0x171e, 0x885: 0x0dde,
0x886: 0x159e, 0x887: 0x092e, 0x888: 0x0e2a, 0x889: 0x0e36, 0x88a: 0x0f0a, 0x88b: 0x0f42,
0x88c: 0x1046, 0x88d: 0x10a2, 0x88e: 0x1122, 0x88f: 0x1206, 0x890: 0x1636, 0x891: 0x08aa,
0x892: 0x0cfe, 0x893: 0x15ae, 0x894: 0x0862, 0x895: 0x0ba6, 0x896: 0x0f2a, 0x897: 0x14da,
0x898: 0x0c62, 0x899: 0x0cb2, 0x89a: 0x0e3e, 0x89b: 0x102a, 0x89c: 0x15b6, 0x89d: 0x0912,
0x89e: 0x09fa, 0x89f: 0x0b92, 0x8a0: 0x0dce, 0x8a1: 0x0e1a, 0x8a2: 0x0e5a, 0x8a3: 0x0eee,
0x8a4: 0x1042, 0x8a5: 0x10b6, 0x8a6: 0x1252, 0x8a7: 0x13f2, 0x8a8: 0x13fe, 0x8a9: 0x1552,
0x8aa: 0x15d2, 0x8ab: 0x097e, 0x8ac: 0x0f46, 0x8ad: 0x09fe, 0x8ae: 0x0fc2, 0x8af: 0x1066,
0x8b0: 0x1382, 0x8b1: 0x15ba, 0x8b2: 0x16a6, 0x8b3: 0x16ce, 0x8b4: 0x0e32, 0x8b5: 0x0f22,
0x8b6: 0x12be, 0x8b7: 0x11b2, 0x8b8: 0x11be, 0x8b9: 0x11e2, 0x8ba: 0x1012, 0x8bb: 0x0f9a,
0x8bc: 0x145e, 0x8bd: 0x082e, 0x8be: 0x1326, 0x8bf: 0x0916,
// Block 0x23, offset 0x8c0
0x8c0: 0x0906, 0x8c1: 0x0c06, 0x8c2: 0x0d26, 0x8c3: 0x11ee, 0x8c4: 0x0b4e, 0x8c5: 0x0efe,
0x8c6: 0x0dea, 0x8c7: 0x14e2, 0x8c8: 0x13e2, 0x8c9: 0x15a6, 0x8ca: 0x141e, 0x8cb: 0x0c22,
0x8cc: 0x0882, 0x8cd: 0x0a56, 0x8d0: 0x0aaa,
0x8d2: 0x0dda, 0x8d5: 0x08f2, 0x8d6: 0x101a, 0x8d7: 0x10de,
0x8d8: 0x1142, 0x8d9: 0x115e, 0x8da: 0x1162, 0x8db: 0x1176, 0x8dc: 0x15f6, 0x8dd: 0x11e6,
0x8de: 0x126a, 0x8e0: 0x138a, 0x8e2: 0x144e,
0x8e5: 0x1502, 0x8e6: 0x152e,
0x8ea: 0x164a, 0x8eb: 0x164e, 0x8ec: 0x1652, 0x8ed: 0x16b6, 0x8ee: 0x1526, 0x8ef: 0x15c2,
0x8f0: 0x0852, 0x8f1: 0x0876, 0x8f2: 0x088a, 0x8f3: 0x0946, 0x8f4: 0x0952, 0x8f5: 0x0992,
0x8f6: 0x0a46, 0x8f7: 0x0a62, 0x8f8: 0x0a6a, 0x8f9: 0x0aa6, 0x8fa: 0x0ab2, 0x8fb: 0x0b8e,
0x8fc: 0x0b96, 0x8fd: 0x0c9e, 0x8fe: 0x0cc6, 0x8ff: 0x0cce,
// Block 0x24, offset 0x900
0x900: 0x0ce6, 0x901: 0x0d92, 0x902: 0x0dc2, 0x903: 0x0de2, 0x904: 0x0e52, 0x905: 0x0f16,
0x906: 0x0f32, 0x907: 0x0f62, 0x908: 0x0fb6, 0x909: 0x0fd6, 0x90a: 0x104a, 0x90b: 0x112a,
0x90c: 0x1146, 0x90d: 0x114e, 0x90e: 0x114a, 0x90f: 0x1152, 0x910: 0x1156, 0x911: 0x115a,
0x912: 0x116e, 0x913: 0x1172, 0x914: 0x1196, 0x915: 0x11aa, 0x916: 0x11c6, 0x917: 0x122a,
0x918: 0x1232, 0x919: 0x123a, 0x91a: 0x124e, 0x91b: 0x1276, 0x91c: 0x12c6, 0x91d: 0x12fa,
0x91e: 0x12fa, 0x91f: 0x1362, 0x920: 0x140a, 0x921: 0x1422, 0x922: 0x1456, 0x923: 0x145a,
0x924: 0x149e, 0x925: 0x14a2, 0x926: 0x14fa, 0x927: 0x1502, 0x928: 0x15d6, 0x929: 0x161a,
0x92a: 0x1632, 0x92b: 0x0c96, 0x92c: 0x184b, 0x92d: 0x12de,
0x930: 0x07da, 0x931: 0x08de, 0x932: 0x089e, 0x933: 0x0846, 0x934: 0x0886, 0x935: 0x08b2,
0x936: 0x0942, 0x937: 0x095e, 0x938: 0x0a46, 0x939: 0x0a32, 0x93a: 0x0a42, 0x93b: 0x0a5e,
0x93c: 0x0aaa, 0x93d: 0x0aba, 0x93e: 0x0afe, 0x93f: 0x0b0a,
// Block 0x25, offset 0x940
0x940: 0x0b26, 0x941: 0x0b36, 0x942: 0x0c1e, 0x943: 0x0c26, 0x944: 0x0c56, 0x945: 0x0c76,
0x946: 0x0ca6, 0x947: 0x0cbe, 0x948: 0x0cae, 0x949: 0x0cce, 0x94a: 0x0cc2, 0x94b: 0x0ce6,
0x94c: 0x0d02, 0x94d: 0x0d5a, 0x94e: 0x0d66, 0x94f: 0x0d6e, 0x950: 0x0d96, 0x951: 0x0dda,
0x952: 0x0e0a, 0x953: 0x0e0e, 0x954: 0x0e22, 0x955: 0x0ea2, 0x956: 0x0eb2, 0x957: 0x0f0a,
0x958: 0x0f56, 0x959: 0x0f4e, 0x95a: 0x0f62, 0x95b: 0x0f7e, 0x95c: 0x0fb6, 0x95d: 0x110e,
0x95e: 0x0fda, 0x95f: 0x100e, 0x960: 0x101a, 0x961: 0x105a, 0x962: 0x1076, 0x963: 0x109a,
0x964: 0x10be, 0x965: 0x10c2, 0x966: 0x10de, 0x967: 0x10e2, 0x968: 0x10f2, 0x969: 0x1106,
0x96a: 0x1102, 0x96b: 0x1132, 0x96c: 0x11ae, 0x96d: 0x11c6, 0x96e: 0x11de, 0x96f: 0x1216,
0x970: 0x122a, 0x971: 0x1246, 0x972: 0x1276, 0x973: 0x132a, 0x974: 0x1352, 0x975: 0x13c6,
0x976: 0x140e, 0x977: 0x141a, 0x978: 0x1422, 0x979: 0x143a, 0x97a: 0x144e, 0x97b: 0x143e,
0x97c: 0x1456, 0x97d: 0x1452, 0x97e: 0x144a, 0x97f: 0x145a,
// Block 0x26, offset 0x980
0x980: 0x1466, 0x981: 0x14a2, 0x982: 0x14de, 0x983: 0x150e, 0x984: 0x1546, 0x985: 0x1566,
0x986: 0x15b2, 0x987: 0x15d6, 0x988: 0x15f6, 0x989: 0x160a, 0x98a: 0x161a, 0x98b: 0x1626,
0x98c: 0x1632, 0x98d: 0x1686, 0x98e: 0x1726, 0x98f: 0x17e2, 0x990: 0x17dd, 0x991: 0x180f,
0x992: 0x0702, 0x993: 0x072a, 0x994: 0x072e, 0x995: 0x1891, 0x996: 0x18be, 0x997: 0x1936,
0x998: 0x1712, 0x999: 0x1722,
// Block 0x27, offset 0x9c0
0x9c0: 0x07f6, 0x9c1: 0x07ee, 0x9c2: 0x07fe, 0x9c3: 0x1774, 0x9c4: 0x0842, 0x9c5: 0x0852,
0x9c6: 0x0856, 0x9c7: 0x085e, 0x9c8: 0x0866, 0x9c9: 0x086a, 0x9ca: 0x0876, 0x9cb: 0x086e,
0x9cc: 0x06ae, 0x9cd: 0x1788, 0x9ce: 0x088a, 0x9cf: 0x088e, 0x9d0: 0x0892, 0x9d1: 0x08ae,
0x9d2: 0x1779, 0x9d3: 0x06b2, 0x9d4: 0x089a, 0x9d5: 0x08ba, 0x9d6: 0x1783, 0x9d7: 0x08ca,
0x9d8: 0x08d2, 0x9d9: 0x0832, 0x9da: 0x08da, 0x9db: 0x08de, 0x9dc: 0x195e, 0x9dd: 0x08fa,
0x9de: 0x0902, 0x9df: 0x06ba, 0x9e0: 0x091a, 0x9e1: 0x091e, 0x9e2: 0x0926, 0x9e3: 0x092a,
0x9e4: 0x06be, 0x9e5: 0x0942, 0x9e6: 0x0946, 0x9e7: 0x0952, 0x9e8: 0x095e, 0x9e9: 0x0962,
0x9ea: 0x0966, 0x9eb: 0x096e, 0x9ec: 0x098e, 0x9ed: 0x0992, 0x9ee: 0x099a, 0x9ef: 0x09aa,
0x9f0: 0x09b2, 0x9f1: 0x09b6, 0x9f2: 0x09b6, 0x9f3: 0x09b6, 0x9f4: 0x1797, 0x9f5: 0x0f8e,
0x9f6: 0x09ca, 0x9f7: 0x09d2, 0x9f8: 0x179c, 0x9f9: 0x09de, 0x9fa: 0x09e6, 0x9fb: 0x09ee,
0x9fc: 0x0a16, 0x9fd: 0x0a02, 0x9fe: 0x0a0e, 0x9ff: 0x0a12,
// Block 0x28, offset 0xa00
0xa00: 0x0a1a, 0xa01: 0x0a22, 0xa02: 0x0a26, 0xa03: 0x0a2e, 0xa04: 0x0a36, 0xa05: 0x0a3a,
0xa06: 0x0a3a, 0xa07: 0x0a42, 0xa08: 0x0a4a, 0xa09: 0x0a4e, 0xa0a: 0x0a5a, 0xa0b: 0x0a7e,
0xa0c: 0x0a62, 0xa0d: 0x0a82, 0xa0e: 0x0a66, 0xa0f: 0x0a6e, 0xa10: 0x0906, 0xa11: 0x0aca,
0xa12: 0x0a92, 0xa13: 0x0a96, 0xa14: 0x0a9a, 0xa15: 0x0a8e, 0xa16: 0x0aa2, 0xa17: 0x0a9e,
0xa18: 0x0ab6, 0xa19: 0x17a1, 0xa1a: 0x0ad2, 0xa1b: 0x0ad6, 0xa1c: 0x0ade, 0xa1d: 0x0aea,
0xa1e: 0x0af2, 0xa1f: 0x0b0e, 0xa20: 0x17a6, 0xa21: 0x17ab, 0xa22: 0x0b1a, 0xa23: 0x0b1e,
0xa24: 0x0b22, 0xa25: 0x0b16, 0xa26: 0x0b2a, 0xa27: 0x06c2, 0xa28: 0x06c6, 0xa29: 0x0b32,
0xa2a: 0x0b3a, 0xa2b: 0x0b3a, 0xa2c: 0x17b0, 0xa2d: 0x0b56, 0xa2e: 0x0b5a, 0xa2f: 0x0b5e,
0xa30: 0x0b66, 0xa31: 0x17b5, 0xa32: 0x0b6e, 0xa33: 0x0b72, 0xa34: 0x0c4a, 0xa35: 0x0b7a,
0xa36: 0x06ca, 0xa37: 0x0b86, 0xa38: 0x0b96, 0xa39: 0x0ba2, 0xa3a: 0x0b9e, 0xa3b: 0x17bf,
0xa3c: 0x0baa, 0xa3d: 0x17c4, 0xa3e: 0x0bb6, 0xa3f: 0x0bb2,
// Block 0x29, offset 0xa40
0xa40: 0x0bba, 0xa41: 0x0bca, 0xa42: 0x0bce, 0xa43: 0x06ce, 0xa44: 0x0bde, 0xa45: 0x0be6,
0xa46: 0x0bea, 0xa47: 0x0bee, 0xa48: 0x06d2, 0xa49: 0x17c9, 0xa4a: 0x06d6, 0xa4b: 0x0c0a,
0xa4c: 0x0c0e, 0xa4d: 0x0c12, 0xa4e: 0x0c1a, 0xa4f: 0x1990, 0xa50: 0x0c32, 0xa51: 0x17d3,
0xa52: 0x17d3, 0xa53: 0x12d2, 0xa54: 0x0c42, 0xa55: 0x0c42, 0xa56: 0x06da, 0xa57: 0x17f6,
0xa58: 0x18c8, 0xa59: 0x0c52, 0xa5a: 0x0c5a, 0xa5b: 0x06de, 0xa5c: 0x0c6e, 0xa5d: 0x0c7e,
0xa5e: 0x0c82, 0xa5f: 0x0c8a, 0xa60: 0x0c9a, 0xa61: 0x06e6, 0xa62: 0x06e2, 0xa63: 0x0c9e,
0xa64: 0x17d8, 0xa65: 0x0ca2, 0xa66: 0x0cb6, 0xa67: 0x0cba, 0xa68: 0x0cbe, 0xa69: 0x0cba,
0xa6a: 0x0cca, 0xa6b: 0x0cce, 0xa6c: 0x0cde, 0xa6d: 0x0cd6, 0xa6e: 0x0cda, 0xa6f: 0x0ce2,
0xa70: 0x0ce6, 0xa71: 0x0cea, 0xa72: 0x0cf6, 0xa73: 0x0cfa, 0xa74: 0x0d12, 0xa75: 0x0d1a,
0xa76: 0x0d2a, 0xa77: 0x0d3e, 0xa78: 0x17e7, 0xa79: 0x0d3a, 0xa7a: 0x0d2e, 0xa7b: 0x0d46,
0xa7c: 0x0d4e, 0xa7d: 0x0d62, 0xa7e: 0x17ec, 0xa7f: 0x0d6a,
// Block 0x2a, offset 0xa80
0xa80: 0x0d5e, 0xa81: 0x0d56, 0xa82: 0x06ea, 0xa83: 0x0d72, 0xa84: 0x0d7a, 0xa85: 0x0d82,
0xa86: 0x0d76, 0xa87: 0x06ee, 0xa88: 0x0d92, 0xa89: 0x0d9a, 0xa8a: 0x17f1, 0xa8b: 0x0dc6,
0xa8c: 0x0dfa, 0xa8d: 0x0dd6, 0xa8e: 0x06fa, 0xa8f: 0x0de2, 0xa90: 0x06f6, 0xa91: 0x06f2,
0xa92: 0x08be, 0xa93: 0x08c2, 0xa94: 0x0dfe, 0xa95: 0x0de6, 0xa96: 0x12a6, 0xa97: 0x075e,
0xa98: 0x0e0a, 0xa99: 0x0e0e, 0xa9a: 0x0e12, 0xa9b: 0x0e26, 0xa9c: 0x0e1e, 0xa9d: 0x180a,
0xa9e: 0x06fe, 0xa9f: 0x0e3a, 0xaa0: 0x0e2e, 0xaa1: 0x0e4a, 0xaa2: 0x0e52, 0xaa3: 0x1814,
0xaa4: 0x0e56, 0xaa5: 0x0e42, 0xaa6: 0x0e5e, 0xaa7: 0x0702, 0xaa8: 0x0e62, 0xaa9: 0x0e66,
0xaaa: 0x0e6a, 0xaab: 0x0e76, 0xaac: 0x1819, 0xaad: 0x0e7e, 0xaae: 0x0706, 0xaaf: 0x0e8a,
0xab0: 0x181e, 0xab1: 0x0e8e, 0xab2: 0x070a, 0xab3: 0x0e9a, 0xab4: 0x0ea6, 0xab5: 0x0eb2,
0xab6: 0x0eb6, 0xab7: 0x1823, 0xab8: 0x17ba, 0xab9: 0x1828, 0xaba: 0x0ed6, 0xabb: 0x182d,
0xabc: 0x0ee2, 0xabd: 0x0eea, 0xabe: 0x0eda, 0xabf: 0x0ef6,
// Block 0x2b, offset 0xac0
0xac0: 0x0f06, 0xac1: 0x0f16, 0xac2: 0x0f0a, 0xac3: 0x0f0e, 0xac4: 0x0f1a, 0xac5: 0x0f1e,
0xac6: 0x1832, 0xac7: 0x0f02, 0xac8: 0x0f36, 0xac9: 0x0f3a, 0xaca: 0x070e, 0xacb: 0x0f4e,
0xacc: 0x0f4a, 0xacd: 0x1837, 0xace: 0x0f2e, 0xacf: 0x0f6a, 0xad0: 0x183c, 0xad1: 0x1841,
0xad2: 0x0f6e, 0xad3: 0x0f82, 0xad4: 0x0f7e, 0xad5: 0x0f7a, 0xad6: 0x0712, 0xad7: 0x0f86,
0xad8: 0x0f96, 0xad9: 0x0f92, 0xada: 0x0f9e, 0xadb: 0x177e, 0xadc: 0x0fae, 0xadd: 0x1846,
0xade: 0x0fba, 0xadf: 0x1850, 0xae0: 0x0fce, 0xae1: 0x0fda, 0xae2: 0x0fee, 0xae3: 0x1855,
0xae4: 0x1002, 0xae5: 0x1006, 0xae6: 0x185a, 0xae7: 0x185f, 0xae8: 0x1022, 0xae9: 0x1032,
0xaea: 0x0716, 0xaeb: 0x1036, 0xaec: 0x071a, 0xaed: 0x071a, 0xaee: 0x104e, 0xaef: 0x1052,
0xaf0: 0x105a, 0xaf1: 0x105e, 0xaf2: 0x106a, 0xaf3: 0x071e, 0xaf4: 0x1082, 0xaf5: 0x1864,
0xaf6: 0x109e, 0xaf7: 0x1869, 0xaf8: 0x10aa, 0xaf9: 0x17ce, 0xafa: 0x10ba, 0xafb: 0x186e,
0xafc: 0x1873, 0xafd: 0x1878, 0xafe: 0x0722, 0xaff: 0x0726,
// Block 0x2c, offset 0xb00
0xb00: 0x10f2, 0xb01: 0x1882, 0xb02: 0x187d, 0xb03: 0x1887, 0xb04: 0x188c, 0xb05: 0x10fa,
0xb06: 0x10fe, 0xb07: 0x10fe, 0xb08: 0x1106, 0xb09: 0x072e, 0xb0a: 0x110a, 0xb0b: 0x0732,
0xb0c: 0x0736, 0xb0d: 0x1896, 0xb0e: 0x111e, 0xb0f: 0x1126, 0xb10: 0x1132, 0xb11: 0x073a,
0xb12: 0x189b, 0xb13: 0x1156, 0xb14: 0x18a0, 0xb15: 0x18a5, 0xb16: 0x1176, 0xb17: 0x118e,
0xb18: 0x073e, 0xb19: 0x1196, 0xb1a: 0x119a, 0xb1b: 0x119e, 0xb1c: 0x18aa, 0xb1d: 0x18af,
0xb1e: 0x18af, 0xb1f: 0x11b6, 0xb20: 0x0742, 0xb21: 0x18b4, 0xb22: 0x11ca, 0xb23: 0x11ce,
0xb24: 0x0746, 0xb25: 0x18b9, 0xb26: 0x11ea, 0xb27: 0x074a, 0xb28: 0x11fa, 0xb29: 0x11f2,
0xb2a: 0x1202, 0xb2b: 0x18c3, 0xb2c: 0x121a, 0xb2d: 0x074e, 0xb2e: 0x1226, 0xb2f: 0x122e,
0xb30: 0x123e, 0xb31: 0x0752, 0xb32: 0x18cd, 0xb33: 0x18d2, 0xb34: 0x0756, 0xb35: 0x18d7,
0xb36: 0x1256, 0xb37: 0x18dc, 0xb38: 0x1262, 0xb39: 0x126e, 0xb3a: 0x1276, 0xb3b: 0x18e1,
0xb3c: 0x18e6, 0xb3d: 0x128a, 0xb3e: 0x18eb, 0xb3f: 0x1292,
// Block 0x2d, offset 0xb40
0xb40: 0x17fb, 0xb41: 0x075a, 0xb42: 0x12aa, 0xb43: 0x12ae, 0xb44: 0x0762, 0xb45: 0x12b2,
0xb46: 0x0b2e, 0xb47: 0x18f0, 0xb48: 0x18f5, 0xb49: 0x1800, 0xb4a: 0x1805, 0xb4b: 0x12d2,
0xb4c: 0x12d6, 0xb4d: 0x14ee, 0xb4e: 0x0766, 0xb4f: 0x1302, 0xb50: 0x12fe, 0xb51: 0x1306,
0xb52: 0x093a, 0xb53: 0x130a, 0xb54: 0x130e, 0xb55: 0x1312, 0xb56: 0x131a, 0xb57: 0x18fa,
0xb58: 0x1316, 0xb59: 0x131e, 0xb5a: 0x1332, 0xb5b: 0x1336, 0xb5c: 0x1322, 0xb5d: 0x133a,
0xb5e: 0x134e, 0xb5f: 0x1362, 0xb60: 0x132e, 0xb61: 0x1342, 0xb62: 0x1346, 0xb63: 0x134a,
0xb64: 0x18ff, 0xb65: 0x1909, 0xb66: 0x1904, 0xb67: 0x076a, 0xb68: 0x136a, 0xb69: 0x136e,
0xb6a: 0x1376, 0xb6b: 0x191d, 0xb6c: 0x137a, 0xb6d: 0x190e, 0xb6e: 0x076e, 0xb6f: 0x0772,
0xb70: 0x1913, 0xb71: 0x1918, 0xb72: 0x0776, 0xb73: 0x139a, 0xb74: 0x139e, 0xb75: 0x13a2,
0xb76: 0x13a6, 0xb77: 0x13b2, 0xb78: 0x13ae, 0xb79: 0x13ba, 0xb7a: 0x13b6, 0xb7b: 0x13c6,
0xb7c: 0x13be, 0xb7d: 0x13c2, 0xb7e: 0x13ca, 0xb7f: 0x077a,
// Block 0x2e, offset 0xb80
0xb80: 0x13d2, 0xb81: 0x13d6, 0xb82: 0x077e, 0xb83: 0x13e6, 0xb84: 0x13ea, 0xb85: 0x1922,
0xb86: 0x13f6, 0xb87: 0x13fa, 0xb88: 0x0782, 0xb89: 0x1406, 0xb8a: 0x06b6, 0xb8b: 0x1927,
0xb8c: 0x192c, 0xb8d: 0x0786, 0xb8e: 0x078a, 0xb8f: 0x1432, 0xb90: 0x144a, 0xb91: 0x1466,
0xb92: 0x1476, 0xb93: 0x1931, 0xb94: 0x148a, 0xb95: 0x148e, 0xb96: 0x14a6, 0xb97: 0x14b2,
0xb98: 0x193b, 0xb99: 0x178d, 0xb9a: 0x14be, 0xb9b: 0x14ba, 0xb9c: 0x14c6, 0xb9d: 0x1792,
0xb9e: 0x14d2, 0xb9f: 0x14de, 0xba0: 0x1940, 0xba1: 0x1945, 0xba2: 0x151e, 0xba3: 0x152a,
0xba4: 0x1532, 0xba5: 0x194a, 0xba6: 0x1536, 0xba7: 0x1562, 0xba8: 0x156e, 0xba9: 0x1572,
0xbaa: 0x156a, 0xbab: 0x157e, 0xbac: 0x1582, 0xbad: 0x194f, 0xbae: 0x158e, 0xbaf: 0x078e,
0xbb0: 0x1596, 0xbb1: 0x1954, 0xbb2: 0x0792, 0xbb3: 0x15ce, 0xbb4: 0x0bbe, 0xbb5: 0x15e6,
0xbb6: 0x1959, 0xbb7: 0x1963, 0xbb8: 0x0796, 0xbb9: 0x079a, 0xbba: 0x160e, 0xbbb: 0x1968,
0xbbc: 0x079e, 0xbbd: 0x196d, 0xbbe: 0x1626, 0xbbf: 0x1626,
// Block 0x2f, offset 0xbc0
0xbc0: 0x162e, 0xbc1: 0x1972, 0xbc2: 0x1646, 0xbc3: 0x07a2, 0xbc4: 0x1656, 0xbc5: 0x1662,
0xbc6: 0x166a, 0xbc7: 0x1672, 0xbc8: 0x07a6, 0xbc9: 0x1977, 0xbca: 0x1686, 0xbcb: 0x16a2,
0xbcc: 0x16ae, 0xbcd: 0x07aa, 0xbce: 0x07ae, 0xbcf: 0x16b2, 0xbd0: 0x197c, 0xbd1: 0x07b2,
0xbd2: 0x1981, 0xbd3: 0x1986, 0xbd4: 0x198b, 0xbd5: 0x16d6, 0xbd6: 0x07b6, 0xbd7: 0x16ea,
0xbd8: 0x16f2, 0xbd9: 0x16f6, 0xbda: 0x16fe, 0xbdb: 0x1706, 0xbdc: 0x170e, 0xbdd: 0x1995,
}
// nfcIndex: 22 blocks, 1408 entries, 1408 bytes
// Block 0 is the zero block.
var nfcIndex = [1408]uint8{
// Block 0x0, offset 0x0
// Block 0x1, offset 0x40
// Block 0x2, offset 0x80
// Block 0x3, offset 0xc0
0xc2: 0x2e, 0xc3: 0x01, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x2f, 0xc7: 0x04,
0xc8: 0x05, 0xca: 0x30, 0xcb: 0x31, 0xcc: 0x06, 0xcd: 0x07, 0xce: 0x08, 0xcf: 0x32,
0xd0: 0x09, 0xd1: 0x33, 0xd2: 0x34, 0xd3: 0x0a, 0xd6: 0x0b, 0xd7: 0x35,
0xd8: 0x36, 0xd9: 0x0c, 0xdb: 0x37, 0xdc: 0x38, 0xdd: 0x39, 0xdf: 0x3a,
0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05,
0xea: 0x06, 0xeb: 0x07, 0xec: 0x08, 0xed: 0x09, 0xef: 0x0a,
0xf0: 0x13,
// Block 0x4, offset 0x100
0x120: 0x3b, 0x121: 0x3c, 0x122: 0x3d, 0x123: 0x0d, 0x124: 0x3e, 0x125: 0x3f, 0x126: 0x40, 0x127: 0x41,
0x128: 0x42, 0x129: 0x43, 0x12a: 0x44, 0x12b: 0x45, 0x12c: 0x40, 0x12d: 0x46, 0x12e: 0x47, 0x12f: 0x48,
0x130: 0x44, 0x131: 0x49, 0x132: 0x4a, 0x133: 0x4b, 0x134: 0x4c, 0x135: 0x4d, 0x137: 0x4e,
0x138: 0x4f, 0x139: 0x50, 0x13a: 0x51, 0x13b: 0x52, 0x13c: 0x53, 0x13d: 0x54, 0x13e: 0x55, 0x13f: 0x56,
// Block 0x5, offset 0x140
0x140: 0x57, 0x142: 0x58, 0x144: 0x59, 0x145: 0x5a, 0x146: 0x5b, 0x147: 0x5c,
0x14d: 0x5d,
0x15c: 0x5e, 0x15f: 0x5f,
0x162: 0x60, 0x164: 0x61,
0x168: 0x62, 0x169: 0x63, 0x16a: 0x64, 0x16b: 0x65, 0x16c: 0x0e, 0x16d: 0x66, 0x16e: 0x67, 0x16f: 0x68,
0x170: 0x69, 0x173: 0x6a, 0x177: 0x0f,
0x178: 0x10, 0x179: 0x11, 0x17a: 0x12, 0x17b: 0x13, 0x17c: 0x14, 0x17d: 0x15, 0x17e: 0x16, 0x17f: 0x17,
// Block 0x6, offset 0x180
0x180: 0x6b, 0x183: 0x6c, 0x184: 0x6d, 0x186: 0x6e, 0x187: 0x6f,
0x188: 0x70, 0x189: 0x18, 0x18a: 0x19, 0x18b: 0x71, 0x18c: 0x72,
0x1ab: 0x73,
0x1b3: 0x74, 0x1b5: 0x75, 0x1b7: 0x76,
// Block 0x7, offset 0x1c0
0x1c0: 0x77, 0x1c1: 0x1a, 0x1c2: 0x1b, 0x1c3: 0x1c, 0x1c4: 0x78, 0x1c5: 0x79,
0x1c9: 0x7a, 0x1cc: 0x7b, 0x1cd: 0x7c,
// Block 0x8, offset 0x200
0x219: 0x7d, 0x21a: 0x7e, 0x21b: 0x7f,
0x220: 0x80, 0x223: 0x81, 0x224: 0x82, 0x225: 0x83, 0x226: 0x84, 0x227: 0x85,
0x22a: 0x86, 0x22b: 0x87, 0x22f: 0x88,
0x230: 0x89, 0x231: 0x8a, 0x232: 0x8b, 0x233: 0x8c, 0x234: 0x8d, 0x235: 0x8e, 0x236: 0x8f, 0x237: 0x89,
0x238: 0x8a, 0x239: 0x8b, 0x23a: 0x8c, 0x23b: 0x8d, 0x23c: 0x8e, 0x23d: 0x8f, 0x23e: 0x89, 0x23f: 0x8a,
// Block 0x9, offset 0x240
0x240: 0x8b, 0x241: 0x8c, 0x242: 0x8d, 0x243: 0x8e, 0x244: 0x8f, 0x245: 0x89, 0x246: 0x8a, 0x247: 0x8b,
0x248: 0x8c, 0x249: 0x8d, 0x24a: 0x8e, 0x24b: 0x8f, 0x24c: 0x89, 0x24d: 0x8a, 0x24e: 0x8b, 0x24f: 0x8c,
0x250: 0x8d, 0x251: 0x8e, 0x252: 0x8f, 0x253: 0x89, 0x254: 0x8a, 0x255: 0x8b, 0x256: 0x8c, 0x257: 0x8d,
0x258: 0x8e, 0x259: 0x8f, 0x25a: 0x89, 0x25b: 0x8a, 0x25c: 0x8b, 0x25d: 0x8c, 0x25e: 0x8d, 0x25f: 0x8e,
0x260: 0x8f, 0x261: 0x89, 0x262: 0x8a, 0x263: 0x8b, 0x264: 0x8c, 0x265: 0x8d, 0x266: 0x8e, 0x267: 0x8f,
0x268: 0x89, 0x269: 0x8a, 0x26a: 0x8b, 0x26b: 0x8c, 0x26c: 0x8d, 0x26d: 0x8e, 0x26e: 0x8f, 0x26f: 0x89,
0x270: 0x8a, 0x271: 0x8b, 0x272: 0x8c, 0x273: 0x8d, 0x274: 0x8e, 0x275: 0x8f, 0x276: 0x89, 0x277: 0x8a,
0x278: 0x8b, 0x279: 0x8c, 0x27a: 0x8d, 0x27b: 0x8e, 0x27c: 0x8f, 0x27d: 0x89, 0x27e: 0x8a, 0x27f: 0x8b,
// Block 0xa, offset 0x280
0x280: 0x8c, 0x281: 0x8d, 0x282: 0x8e, 0x283: 0x8f, 0x284: 0x89, 0x285: 0x8a, 0x286: 0x8b, 0x287: 0x8c,
0x288: 0x8d, 0x289: 0x8e, 0x28a: 0x8f, 0x28b: 0x89, 0x28c: 0x8a, 0x28d: 0x8b, 0x28e: 0x8c, 0x28f: 0x8d,
0x290: 0x8e, 0x291: 0x8f, 0x292: 0x89, 0x293: 0x8a, 0x294: 0x8b, 0x295: 0x8c, 0x296: 0x8d, 0x297: 0x8e,
0x298: 0x8f, 0x299: 0x89, 0x29a: 0x8a, 0x29b: 0x8b, 0x29c: 0x8c, 0x29d: 0x8d, 0x29e: 0x8e, 0x29f: 0x8f,
0x2a0: 0x89, 0x2a1: 0x8a, 0x2a2: 0x8b, 0x2a3: 0x8c, 0x2a4: 0x8d, 0x2a5: 0x8e, 0x2a6: 0x8f, 0x2a7: 0x89,
0x2a8: 0x8a, 0x2a9: 0x8b, 0x2aa: 0x8c, 0x2ab: 0x8d, 0x2ac: 0x8e, 0x2ad: 0x8f, 0x2ae: 0x89, 0x2af: 0x8a,
0x2b0: 0x8b, 0x2b1: 0x8c, 0x2b2: 0x8d, 0x2b3: 0x8e, 0x2b4: 0x8f, 0x2b5: 0x89, 0x2b6: 0x8a, 0x2b7: 0x8b,
0x2b8: 0x8c, 0x2b9: 0x8d, 0x2ba: 0x8e, 0x2bb: 0x8f, 0x2bc: 0x89, 0x2bd: 0x8a, 0x2be: 0x8b, 0x2bf: 0x8c,
// Block 0xb, offset 0x2c0
0x2c0: 0x8d, 0x2c1: 0x8e, 0x2c2: 0x8f, 0x2c3: 0x89, 0x2c4: 0x8a, 0x2c5: 0x8b, 0x2c6: 0x8c, 0x2c7: 0x8d,
0x2c8: 0x8e, 0x2c9: 0x8f, 0x2ca: 0x89, 0x2cb: 0x8a, 0x2cc: 0x8b, 0x2cd: 0x8c, 0x2ce: 0x8d, 0x2cf: 0x8e,
0x2d0: 0x8f, 0x2d1: 0x89, 0x2d2: 0x8a, 0x2d3: 0x8b, 0x2d4: 0x8c, 0x2d5: 0x8d, 0x2d6: 0x8e, 0x2d7: 0x8f,
0x2d8: 0x89, 0x2d9: 0x8a, 0x2da: 0x8b, 0x2db: 0x8c, 0x2dc: 0x8d, 0x2dd: 0x8e, 0x2de: 0x90,
// Block 0xc, offset 0x300
0x324: 0x1d, 0x325: 0x1e, 0x326: 0x1f, 0x327: 0x20,
0x328: 0x21, 0x329: 0x22, 0x32a: 0x23, 0x32b: 0x24, 0x32c: 0x91, 0x32d: 0x92, 0x32e: 0x93,
0x331: 0x94, 0x332: 0x95, 0x333: 0x96, 0x334: 0x97,
0x338: 0x98, 0x339: 0x99, 0x33a: 0x9a, 0x33b: 0x9b, 0x33e: 0x9c, 0x33f: 0x9d,
// Block 0xd, offset 0x340
0x347: 0x9e,
0x34b: 0x9f, 0x34d: 0xa0,
0x368: 0xa1, 0x36b: 0xa2,
0x374: 0xa3,
0x37a: 0xa4, 0x37b: 0xa5, 0x37d: 0xa6, 0x37e: 0xa7,
// Block 0xe, offset 0x380
0x381: 0xa8, 0x382: 0xa9, 0x384: 0xaa, 0x385: 0x84, 0x387: 0xab,
0x388: 0xac, 0x38b: 0xad, 0x38c: 0xae, 0x38d: 0xaf,
0x391: 0xb0, 0x392: 0xb1, 0x393: 0xb2, 0x396: 0xb3, 0x397: 0xb4,
0x398: 0x75, 0x39a: 0xb5, 0x39c: 0xb6,
0x3a0: 0xb7, 0x3a4: 0xb8, 0x3a5: 0xb9, 0x3a7: 0xba,
0x3a8: 0xbb, 0x3a9: 0xbc, 0x3aa: 0xbd,
0x3b0: 0x75, 0x3b5: 0xbe, 0x3b6: 0xbf,
0x3bd: 0xc0,
// Block 0xf, offset 0x3c0
0x3eb: 0xc1, 0x3ec: 0xc2,
0x3ff: 0xc3,
// Block 0x10, offset 0x400
0x432: 0xc4,
// Block 0x11, offset 0x440
0x445: 0xc5, 0x446: 0xc6, 0x447: 0xc7,
0x449: 0xc8,
// Block 0x12, offset 0x480
0x480: 0xc9, 0x482: 0xca, 0x484: 0xc2,
0x48a: 0xcb, 0x48b: 0xcc,
0x493: 0xcd,
0x4a3: 0xce, 0x4a5: 0xcf,
// Block 0x13, offset 0x4c0
0x4c8: 0xd0,
// Block 0x14, offset 0x500
0x520: 0x25, 0x521: 0x26, 0x522: 0x27, 0x523: 0x28, 0x524: 0x29, 0x525: 0x2a, 0x526: 0x2b, 0x527: 0x2c,
0x528: 0x2d,
// Block 0x15, offset 0x540
0x550: 0x0b, 0x551: 0x0c, 0x556: 0x0d,
0x55b: 0x0e, 0x55d: 0x0f, 0x55e: 0x10, 0x55f: 0x11,
0x56f: 0x12,
}
// nfcSparseOffset: 163 entries, 326 bytes
var nfcSparseOffset = []uint16{0x0, 0x5, 0x9, 0xb, 0xd, 0x18, 0x28, 0x2a, 0x2f, 0x3a, 0x49, 0x56, 0x5e, 0x63, 0x68, 0x6a, 0x6e, 0x76, 0x7d, 0x80, 0x88, 0x8c, 0x90, 0x92, 0x94, 0x9d, 0xa1, 0xa8, 0xad, 0xb0, 0xba, 0xbd, 0xc4, 0xcc, 0xcf, 0xd1, 0xd4, 0xd6, 0xdb, 0xec, 0xf8, 0xfa, 0x100, 0x102, 0x104, 0x106, 0x108, 0x10a, 0x10c, 0x10f, 0x112, 0x114, 0x117, 0x11a, 0x11e, 0x124, 0x12b, 0x134, 0x136, 0x139, 0x13b, 0x146, 0x14a, 0x158, 0x15b, 0x161, 0x167, 0x172, 0x176, 0x178, 0x17a, 0x17c, 0x17e, 0x180, 0x186, 0x18a, 0x18c, 0x18e, 0x196, 0x19a, 0x19d, 0x19f, 0x1a1, 0x1a4, 0x1a7, 0x1a9, 0x1ab, 0x1ad, 0x1af, 0x1b5, 0x1b8, 0x1ba, 0x1c1, 0x1c7, 0x1cd, 0x1d5, 0x1db, 0x1e1, 0x1e7, 0x1eb, 0x1f9, 0x202, 0x205, 0x208, 0x20a, 0x20d, 0x20f, 0x213, 0x218, 0x21a, 0x21c, 0x221, 0x227, 0x229, 0x22b, 0x22d, 0x233, 0x236, 0x238, 0x23a, 0x23c, 0x242, 0x246, 0x24a, 0x252, 0x259, 0x25c, 0x25f, 0x261, 0x264, 0x26c, 0x270, 0x277, 0x27a, 0x280, 0x282, 0x285, 0x287, 0x28a, 0x28f, 0x291, 0x293, 0x295, 0x297, 0x299, 0x29c, 0x29e, 0x2a0, 0x2a2, 0x2a4, 0x2a6, 0x2a8, 0x2b5, 0x2bf, 0x2c1, 0x2c3, 0x2c9, 0x2cb, 0x2cd, 0x2cf, 0x2d3, 0x2d5, 0x2d8}
// nfcSparseValues: 730 entries, 2920 bytes
var nfcSparseValues = [730]valueRange{
// Block 0x0, offset 0x0
{value: 0x0000, lo: 0x04},
{value: 0xa100, lo: 0xa8, hi: 0xa8},
{value: 0x8100, lo: 0xaf, hi: 0xaf},
{value: 0x8100, lo: 0xb4, hi: 0xb4},
{value: 0x8100, lo: 0xb8, hi: 0xb8},
// Block 0x1, offset 0x5
{value: 0x0091, lo: 0x03},
{value: 0x4823, lo: 0xa0, hi: 0xa1},
{value: 0x4855, lo: 0xaf, hi: 0xb0},
{value: 0xa000, lo: 0xb7, hi: 0xb7},
// Block 0x2, offset 0x9
{value: 0x0000, lo: 0x01},
{value: 0xa000, lo: 0x92, hi: 0x92},
// Block 0x3, offset 0xb
{value: 0x0000, lo: 0x01},
{value: 0x8100, lo: 0x98, hi: 0x9d},
// Block 0x4, offset 0xd
{value: 0x0006, lo: 0x0a},
{value: 0xa000, lo: 0x81, hi: 0x81},
{value: 0xa000, lo: 0x85, hi: 0x85},
{value: 0xa000, lo: 0x89, hi: 0x89},
{value: 0x4981, lo: 0x8a, hi: 0x8a},
{value: 0x499f, lo: 0x8b, hi: 0x8b},
{value: 0x3808, lo: 0x8c, hi: 0x8c},
{value: 0x3820, lo: 0x8d, hi: 0x8d},
{value: 0x49b7, lo: 0x8e, hi: 0x8e},
{value: 0xa000, lo: 0x92, hi: 0x92},
{value: 0x383e, lo: 0x93, hi: 0x94},
// Block 0x5, offset 0x18
{value: 0x0000, lo: 0x0f},
{value: 0xa000, lo: 0x83, hi: 0x83},
{value: 0xa000, lo: 0x87, hi: 0x87},
{value: 0xa000, lo: 0x8b, hi: 0x8b},
{value: 0xa000, lo: 0x8d, hi: 0x8d},
{value: 0x38e6, lo: 0x90, hi: 0x90},
{value: 0x38f2, lo: 0x91, hi: 0x91},
{value: 0x38e0, lo: 0x93, hi: 0x93},
{value: 0xa000, lo: 0x96, hi: 0x96},
{value: 0x3958, lo: 0x97, hi: 0x97},
{value: 0x3922, lo: 0x9c, hi: 0x9c},
{value: 0x390a, lo: 0x9d, hi: 0x9d},
{value: 0x3934, lo: 0x9e, hi: 0x9e},
{value: 0xa000, lo: 0xb4, hi: 0xb5},
{value: 0x395e, lo: 0xb6, hi: 0xb6},
{value: 0x3964, lo: 0xb7, hi: 0xb7},
// Block 0x6, offset 0x28
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0x83, hi: 0x87},
// Block 0x7, offset 0x2a
{value: 0x0001, lo: 0x04},
{value: 0x8114, lo: 0x81, hi: 0x82},
{value: 0x8133, lo: 0x84, hi: 0x84},
{value: 0x812e, lo: 0x85, hi: 0x85},
{value: 0x810e, lo: 0x87, hi: 0x87},
// Block 0x8, offset 0x2f
{value: 0x0000, lo: 0x0a},
{value: 0x8133, lo: 0x90, hi: 0x97},
{value: 0x811a, lo: 0x98, hi: 0x98},
{value: 0x811b, lo: 0x99, hi: 0x99},
{value: 0x811c, lo: 0x9a, hi: 0x9a},
{value: 0x3982, lo: 0xa2, hi: 0xa2},
{value: 0x3988, lo: 0xa3, hi: 0xa3},
{value: 0x3994, lo: 0xa4, hi: 0xa4},
{value: 0x398e, lo: 0xa5, hi: 0xa5},
{value: 0x399a, lo: 0xa6, hi: 0xa6},
{value: 0xa000, lo: 0xa7, hi: 0xa7},
// Block 0x9, offset 0x3a
{value: 0x0000, lo: 0x0e},
{value: 0x39ac, lo: 0x80, hi: 0x80},
{value: 0xa000, lo: 0x81, hi: 0x81},
{value: 0x39a0, lo: 0x82, hi: 0x82},
{value: 0xa000, lo: 0x92, hi: 0x92},
{value: 0x39a6, lo: 0x93, hi: 0x93},
{value: 0xa000, lo: 0x95, hi: 0x95},
{value: 0x8133, lo: 0x96, hi: 0x9c},
{value: 0x8133, lo: 0x9f, hi: 0xa2},
{value: 0x812e, lo: 0xa3, hi: 0xa3},
{value: 0x8133, lo: 0xa4, hi: 0xa4},
{value: 0x8133, lo: 0xa7, hi: 0xa8},
{value: 0x812e, lo: 0xaa, hi: 0xaa},
{value: 0x8133, lo: 0xab, hi: 0xac},
{value: 0x812e, lo: 0xad, hi: 0xad},
// Block 0xa, offset 0x49
{value: 0x0000, lo: 0x0c},
{value: 0x8120, lo: 0x91, hi: 0x91},
{value: 0x8133, lo: 0xb0, hi: 0xb0},
{value: 0x812e, lo: 0xb1, hi: 0xb1},
{value: 0x8133, lo: 0xb2, hi: 0xb3},
{value: 0x812e, lo: 0xb4, hi: 0xb4},
{value: 0x8133, lo: 0xb5, hi: 0xb6},
{value: 0x812e, lo: 0xb7, hi: 0xb9},
{value: 0x8133, lo: 0xba, hi: 0xba},
{value: 0x812e, lo: 0xbb, hi: 0xbc},
{value: 0x8133, lo: 0xbd, hi: 0xbd},
{value: 0x812e, lo: 0xbe, hi: 0xbe},
{value: 0x8133, lo: 0xbf, hi: 0xbf},
// Block 0xb, offset 0x56
{value: 0x0005, lo: 0x07},
{value: 0x8133, lo: 0x80, hi: 0x80},
{value: 0x8133, lo: 0x81, hi: 0x81},
{value: 0x812e, lo: 0x82, hi: 0x83},
{value: 0x812e, lo: 0x84, hi: 0x85},
{value: 0x812e, lo: 0x86, hi: 0x87},
{value: 0x812e, lo: 0x88, hi: 0x89},
{value: 0x8133, lo: 0x8a, hi: 0x8a},
// Block 0xc, offset 0x5e
{value: 0x0000, lo: 0x04},
{value: 0x8133, lo: 0xab, hi: 0xb1},
{value: 0x812e, lo: 0xb2, hi: 0xb2},
{value: 0x8133, lo: 0xb3, hi: 0xb3},
{value: 0x812e, lo: 0xbd, hi: 0xbd},
// Block 0xd, offset 0x63
{value: 0x0000, lo: 0x04},
{value: 0x8133, lo: 0x96, hi: 0x99},
{value: 0x8133, lo: 0x9b, hi: 0xa3},
{value: 0x8133, lo: 0xa5, hi: 0xa7},
{value: 0x8133, lo: 0xa9, hi: 0xad},
// Block 0xe, offset 0x68
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0x99, hi: 0x9b},
// Block 0xf, offset 0x6a
{value: 0x0000, lo: 0x03},
{value: 0x8133, lo: 0x98, hi: 0x98},
{value: 0x812e, lo: 0x99, hi: 0x9b},
{value: 0x8133, lo: 0x9c, hi: 0x9f},
// Block 0x10, offset 0x6e
{value: 0x0000, lo: 0x07},
{value: 0xa000, lo: 0xa8, hi: 0xa8},
{value: 0x4019, lo: 0xa9, hi: 0xa9},
{value: 0xa000, lo: 0xb0, hi: 0xb0},
{value: 0x4021, lo: 0xb1, hi: 0xb1},
{value: 0xa000, lo: 0xb3, hi: 0xb3},
{value: 0x4029, lo: 0xb4, hi: 0xb4},
{value: 0x9903, lo: 0xbc, hi: 0xbc},
// Block 0x11, offset 0x76
{value: 0x0008, lo: 0x06},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x8133, lo: 0x91, hi: 0x91},
{value: 0x812e, lo: 0x92, hi: 0x92},
{value: 0x8133, lo: 0x93, hi: 0x93},
{value: 0x8133, lo: 0x94, hi: 0x94},
{value: 0x465d, lo: 0x98, hi: 0x9f},
// Block 0x12, offset 0x7d
{value: 0x0000, lo: 0x02},
{value: 0x8103, lo: 0xbc, hi: 0xbc},
{value: 0x9900, lo: 0xbe, hi: 0xbe},
// Block 0x13, offset 0x80
{value: 0x0008, lo: 0x07},
{value: 0xa000, lo: 0x87, hi: 0x87},
{value: 0x2dd5, lo: 0x8b, hi: 0x8c},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x9900, lo: 0x97, hi: 0x97},
{value: 0x469d, lo: 0x9c, hi: 0x9d},
{value: 0x46ad, lo: 0x9f, hi: 0x9f},
{value: 0x8133, lo: 0xbe, hi: 0xbe},
// Block 0x14, offset 0x88
{value: 0x0000, lo: 0x03},
{value: 0x46d5, lo: 0xb3, hi: 0xb3},
{value: 0x46dd, lo: 0xb6, hi: 0xb6},
{value: 0x8103, lo: 0xbc, hi: 0xbc},
// Block 0x15, offset 0x8c
{value: 0x0008, lo: 0x03},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x46b5, lo: 0x99, hi: 0x9b},
{value: 0x46cd, lo: 0x9e, hi: 0x9e},
// Block 0x16, offset 0x90
{value: 0x0000, lo: 0x01},
{value: 0x8103, lo: 0xbc, hi: 0xbc},
// Block 0x17, offset 0x92
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
// Block 0x18, offset 0x94
{value: 0x0000, lo: 0x08},
{value: 0xa000, lo: 0x87, hi: 0x87},
{value: 0x2ded, lo: 0x88, hi: 0x88},
{value: 0x2de5, lo: 0x8b, hi: 0x8b},
{value: 0x2df5, lo: 0x8c, hi: 0x8c},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x9900, lo: 0x96, hi: 0x97},
{value: 0x46e5, lo: 0x9c, hi: 0x9c},
{value: 0x46ed, lo: 0x9d, hi: 0x9d},
// Block 0x19, offset 0x9d
{value: 0x0000, lo: 0x03},
{value: 0xa000, lo: 0x92, hi: 0x92},
{value: 0x2dfd, lo: 0x94, hi: 0x94},
{value: 0x9900, lo: 0xbe, hi: 0xbe},
// Block 0x1a, offset 0xa1
{value: 0x0000, lo: 0x06},
{value: 0xa000, lo: 0x86, hi: 0x87},
{value: 0x2e05, lo: 0x8a, hi: 0x8a},
{value: 0x2e15, lo: 0x8b, hi: 0x8b},
{value: 0x2e0d, lo: 0x8c, hi: 0x8c},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x9900, lo: 0x97, hi: 0x97},
// Block 0x1b, offset 0xa8
{value: 0x1801, lo: 0x04},
{value: 0xa000, lo: 0x86, hi: 0x86},
{value: 0x4031, lo: 0x88, hi: 0x88},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x8121, lo: 0x95, hi: 0x96},
// Block 0x1c, offset 0xad
{value: 0x0000, lo: 0x02},
{value: 0x8103, lo: 0xbc, hi: 0xbc},
{value: 0xa000, lo: 0xbf, hi: 0xbf},
// Block 0x1d, offset 0xb0
{value: 0x0000, lo: 0x09},
{value: 0x2e1d, lo: 0x80, hi: 0x80},
{value: 0x9900, lo: 0x82, hi: 0x82},
{value: 0xa000, lo: 0x86, hi: 0x86},
{value: 0x2e25, lo: 0x87, hi: 0x87},
{value: 0x2e2d, lo: 0x88, hi: 0x88},
{value: 0x3091, lo: 0x8a, hi: 0x8a},
{value: 0x2f19, lo: 0x8b, hi: 0x8b},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x9900, lo: 0x95, hi: 0x96},
// Block 0x1e, offset 0xba
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0xbb, hi: 0xbc},
{value: 0x9900, lo: 0xbe, hi: 0xbe},
// Block 0x1f, offset 0xbd
{value: 0x0000, lo: 0x06},
{value: 0xa000, lo: 0x86, hi: 0x87},
{value: 0x2e35, lo: 0x8a, hi: 0x8a},
{value: 0x2e45, lo: 0x8b, hi: 0x8b},
{value: 0x2e3d, lo: 0x8c, hi: 0x8c},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x9900, lo: 0x97, hi: 0x97},
// Block 0x20, offset 0xc4
{value: 0x6ab3, lo: 0x07},
{value: 0x9905, lo: 0x8a, hi: 0x8a},
{value: 0x9900, lo: 0x8f, hi: 0x8f},
{value: 0xa000, lo: 0x99, hi: 0x99},
{value: 0x4039, lo: 0x9a, hi: 0x9a},
{value: 0x3099, lo: 0x9c, hi: 0x9c},
{value: 0x2f24, lo: 0x9d, hi: 0x9d},
{value: 0x2e4d, lo: 0x9e, hi: 0x9f},
// Block 0x21, offset 0xcc
{value: 0x0000, lo: 0x02},
{value: 0x8123, lo: 0xb8, hi: 0xb9},
{value: 0x8105, lo: 0xba, hi: 0xba},
// Block 0x22, offset 0xcf
{value: 0x0000, lo: 0x01},
{value: 0x8124, lo: 0x88, hi: 0x8b},
// Block 0x23, offset 0xd1
{value: 0x0000, lo: 0x02},
{value: 0x8125, lo: 0xb8, hi: 0xb9},
{value: 0x8105, lo: 0xba, hi: 0xba},
// Block 0x24, offset 0xd4
{value: 0x0000, lo: 0x01},
{value: 0x8126, lo: 0x88, hi: 0x8b},
// Block 0x25, offset 0xd6
{value: 0x0000, lo: 0x04},
{value: 0x812e, lo: 0x98, hi: 0x99},
{value: 0x812e, lo: 0xb5, hi: 0xb5},
{value: 0x812e, lo: 0xb7, hi: 0xb7},
{value: 0x812c, lo: 0xb9, hi: 0xb9},
// Block 0x26, offset 0xdb
{value: 0x0000, lo: 0x10},
{value: 0x2774, lo: 0x83, hi: 0x83},
{value: 0x277b, lo: 0x8d, hi: 0x8d},
{value: 0x2782, lo: 0x92, hi: 0x92},
{value: 0x2789, lo: 0x97, hi: 0x97},
{value: 0x2790, lo: 0x9c, hi: 0x9c},
{value: 0x276d, lo: 0xa9, hi: 0xa9},
{value: 0x8127, lo: 0xb1, hi: 0xb1},
{value: 0x8128, lo: 0xb2, hi: 0xb2},
{value: 0x4bc5, lo: 0xb3, hi: 0xb3},
{value: 0x8129, lo: 0xb4, hi: 0xb4},
{value: 0x4bce, lo: 0xb5, hi: 0xb5},
{value: 0x46f5, lo: 0xb6, hi: 0xb6},
{value: 0x8200, lo: 0xb7, hi: 0xb7},
{value: 0x46fd, lo: 0xb8, hi: 0xb8},
{value: 0x8200, lo: 0xb9, hi: 0xb9},
{value: 0x8128, lo: 0xba, hi: 0xbd},
// Block 0x27, offset 0xec
{value: 0x0000, lo: 0x0b},
{value: 0x8128, lo: 0x80, hi: 0x80},
{value: 0x4bd7, lo: 0x81, hi: 0x81},
{value: 0x8133, lo: 0x82, hi: 0x83},
{value: 0x8105, lo: 0x84, hi: 0x84},
{value: 0x8133, lo: 0x86, hi: 0x87},
{value: 0x279e, lo: 0x93, hi: 0x93},
{value: 0x27a5, lo: 0x9d, hi: 0x9d},
{value: 0x27ac, lo: 0xa2, hi: 0xa2},
{value: 0x27b3, lo: 0xa7, hi: 0xa7},
{value: 0x27ba, lo: 0xac, hi: 0xac},
{value: 0x2797, lo: 0xb9, hi: 0xb9},
// Block 0x28, offset 0xf8
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0x86, hi: 0x86},
// Block 0x29, offset 0xfa
{value: 0x0000, lo: 0x05},
{value: 0xa000, lo: 0xa5, hi: 0xa5},
{value: 0x2e55, lo: 0xa6, hi: 0xa6},
{value: 0x9900, lo: 0xae, hi: 0xae},
{value: 0x8103, lo: 0xb7, hi: 0xb7},
{value: 0x8105, lo: 0xb9, hi: 0xba},
// Block 0x2a, offset 0x100
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0x8d, hi: 0x8d},
// Block 0x2b, offset 0x102
{value: 0x0000, lo: 0x01},
{value: 0xa000, lo: 0x80, hi: 0x92},
// Block 0x2c, offset 0x104
{value: 0x0000, lo: 0x01},
{value: 0xb900, lo: 0xa1, hi: 0xb5},
// Block 0x2d, offset 0x106
{value: 0x0000, lo: 0x01},
{value: 0x9900, lo: 0xa8, hi: 0xbf},
// Block 0x2e, offset 0x108
{value: 0x0000, lo: 0x01},
{value: 0x9900, lo: 0x80, hi: 0x82},
// Block 0x2f, offset 0x10a
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0x9d, hi: 0x9f},
// Block 0x30, offset 0x10c
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0x94, hi: 0x95},
{value: 0x8105, lo: 0xb4, hi: 0xb4},
// Block 0x31, offset 0x10f
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0x92, hi: 0x92},
{value: 0x8133, lo: 0x9d, hi: 0x9d},
// Block 0x32, offset 0x112
{value: 0x0000, lo: 0x01},
{value: 0x8132, lo: 0xa9, hi: 0xa9},
// Block 0x33, offset 0x114
{value: 0x0004, lo: 0x02},
{value: 0x812f, lo: 0xb9, hi: 0xba},
{value: 0x812e, lo: 0xbb, hi: 0xbb},
// Block 0x34, offset 0x117
{value: 0x0000, lo: 0x02},
{value: 0x8133, lo: 0x97, hi: 0x97},
{value: 0x812e, lo: 0x98, hi: 0x98},
// Block 0x35, offset 0x11a
{value: 0x0000, lo: 0x03},
{value: 0x8105, lo: 0xa0, hi: 0xa0},
{value: 0x8133, lo: 0xb5, hi: 0xbc},
{value: 0x812e, lo: 0xbf, hi: 0xbf},
// Block 0x36, offset 0x11e
{value: 0x0000, lo: 0x05},
{value: 0x8133, lo: 0xb0, hi: 0xb4},
{value: 0x812e, lo: 0xb5, hi: 0xba},
{value: 0x8133, lo: 0xbb, hi: 0xbc},
{value: 0x812e, lo: 0xbd, hi: 0xbd},
{value: 0x812e, lo: 0xbf, hi: 0xbf},
// Block 0x37, offset 0x124
{value: 0x0000, lo: 0x06},
{value: 0x812e, lo: 0x80, hi: 0x80},
{value: 0x8133, lo: 0x81, hi: 0x82},
{value: 0x812e, lo: 0x83, hi: 0x84},
{value: 0x8133, lo: 0x85, hi: 0x89},
{value: 0x812e, lo: 0x8a, hi: 0x8a},
{value: 0x8133, lo: 0x8b, hi: 0x8e},
// Block 0x38, offset 0x12b
{value: 0x0000, lo: 0x08},
{value: 0x2e9d, lo: 0x80, hi: 0x80},
{value: 0x2ea5, lo: 0x81, hi: 0x81},
{value: 0xa000, lo: 0x82, hi: 0x82},
{value: 0x2ead, lo: 0x83, hi: 0x83},
{value: 0x8105, lo: 0x84, hi: 0x84},
{value: 0x8133, lo: 0xab, hi: 0xab},
{value: 0x812e, lo: 0xac, hi: 0xac},
{value: 0x8133, lo: 0xad, hi: 0xb3},
// Block 0x39, offset 0x134
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xaa, hi: 0xab},
// Block 0x3a, offset 0x136
{value: 0x0000, lo: 0x02},
{value: 0x8103, lo: 0xa6, hi: 0xa6},
{value: 0x8105, lo: 0xb2, hi: 0xb3},
// Block 0x3b, offset 0x139
{value: 0x0000, lo: 0x01},
{value: 0x8103, lo: 0xb7, hi: 0xb7},
// Block 0x3c, offset 0x13b
{value: 0x0000, lo: 0x0a},
{value: 0x8133, lo: 0x90, hi: 0x92},
{value: 0x8101, lo: 0x94, hi: 0x94},
{value: 0x812e, lo: 0x95, hi: 0x99},
{value: 0x8133, lo: 0x9a, hi: 0x9b},
{value: 0x812e, lo: 0x9c, hi: 0x9f},
{value: 0x8133, lo: 0xa0, hi: 0xa0},
{value: 0x8101, lo: 0xa2, hi: 0xa8},
{value: 0x812e, lo: 0xad, hi: 0xad},
{value: 0x8133, lo: 0xb4, hi: 0xb4},
{value: 0x8133, lo: 0xb8, hi: 0xb9},
// Block 0x3d, offset 0x146
{value: 0x0004, lo: 0x03},
{value: 0x052a, lo: 0x80, hi: 0x81},
{value: 0x8100, lo: 0x97, hi: 0x97},
{value: 0x8100, lo: 0xbe, hi: 0xbe},
// Block 0x3e, offset 0x14a
{value: 0x0000, lo: 0x0d},
{value: 0x8133, lo: 0x90, hi: 0x91},
{value: 0x8101, lo: 0x92, hi: 0x93},
{value: 0x8133, lo: 0x94, hi: 0x97},
{value: 0x8101, lo: 0x98, hi: 0x9a},
{value: 0x8133, lo: 0x9b, hi: 0x9c},
{value: 0x8133, lo: 0xa1, hi: 0xa1},
{value: 0x8101, lo: 0xa5, hi: 0xa6},
{value: 0x8133, lo: 0xa7, hi: 0xa7},
{value: 0x812e, lo: 0xa8, hi: 0xa8},
{value: 0x8133, lo: 0xa9, hi: 0xa9},
{value: 0x8101, lo: 0xaa, hi: 0xab},
{value: 0x812e, lo: 0xac, hi: 0xaf},
{value: 0x8133, lo: 0xb0, hi: 0xb0},
// Block 0x3f, offset 0x158
{value: 0x43bc, lo: 0x02},
{value: 0x023c, lo: 0xa6, hi: 0xa6},
{value: 0x0057, lo: 0xaa, hi: 0xab},
// Block 0x40, offset 0x15b
{value: 0x0007, lo: 0x05},
{value: 0xa000, lo: 0x90, hi: 0x90},
{value: 0xa000, lo: 0x92, hi: 0x92},
{value: 0xa000, lo: 0x94, hi: 0x94},
{value: 0x3cfa, lo: 0x9a, hi: 0x9b},
{value: 0x3d08, lo: 0xae, hi: 0xae},
// Block 0x41, offset 0x161
{value: 0x000e, lo: 0x05},
{value: 0x3d0f, lo: 0x8d, hi: 0x8e},
{value: 0x3d16, lo: 0x8f, hi: 0x8f},
{value: 0xa000, lo: 0x90, hi: 0x90},
{value: 0xa000, lo: 0x92, hi: 0x92},
{value: 0xa000, lo: 0x94, hi: 0x94},
// Block 0x42, offset 0x167
{value: 0x62c7, lo: 0x0a},
{value: 0xa000, lo: 0x83, hi: 0x83},
{value: 0x3d24, lo: 0x84, hi: 0x84},
{value: 0xa000, lo: 0x88, hi: 0x88},
{value: 0x3d2b, lo: 0x89, hi: 0x89},
{value: 0xa000, lo: 0x8b, hi: 0x8b},
{value: 0x3d32, lo: 0x8c, hi: 0x8c},
{value: 0xa000, lo: 0xa3, hi: 0xa3},
{value: 0x3d39, lo: 0xa4, hi: 0xa5},
{value: 0x3d40, lo: 0xa6, hi: 0xa6},
{value: 0xa000, lo: 0xbc, hi: 0xbc},
// Block 0x43, offset 0x172
{value: 0x0007, lo: 0x03},
{value: 0x3da9, lo: 0xa0, hi: 0xa1},
{value: 0x3dd3, lo: 0xa2, hi: 0xa3},
{value: 0x3dfd, lo: 0xaa, hi: 0xad},
// Block 0x44, offset 0x176
{value: 0x0004, lo: 0x01},
{value: 0x0586, lo: 0xa9, hi: 0xaa},
// Block 0x45, offset 0x178
{value: 0x0000, lo: 0x01},
{value: 0x461e, lo: 0x9c, hi: 0x9c},
// Block 0x46, offset 0x17a
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xaf, hi: 0xb1},
// Block 0x47, offset 0x17c
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xbf, hi: 0xbf},
// Block 0x48, offset 0x17e
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xa0, hi: 0xbf},
// Block 0x49, offset 0x180
{value: 0x0000, lo: 0x05},
{value: 0x812d, lo: 0xaa, hi: 0xaa},
{value: 0x8132, lo: 0xab, hi: 0xab},
{value: 0x8134, lo: 0xac, hi: 0xac},
{value: 0x812f, lo: 0xad, hi: 0xad},
{value: 0x8130, lo: 0xae, hi: 0xaf},
// Block 0x4a, offset 0x186
{value: 0x0000, lo: 0x03},
{value: 0x4be0, lo: 0xb3, hi: 0xb3},
{value: 0x4be0, lo: 0xb5, hi: 0xb6},
{value: 0x4be0, lo: 0xba, hi: 0xbf},
// Block 0x4b, offset 0x18a
{value: 0x0000, lo: 0x01},
{value: 0x4be0, lo: 0x8f, hi: 0xa3},
// Block 0x4c, offset 0x18c
{value: 0x0000, lo: 0x01},
{value: 0x8100, lo: 0xae, hi: 0xbe},
// Block 0x4d, offset 0x18e
{value: 0x0000, lo: 0x07},
{value: 0x8100, lo: 0x84, hi: 0x84},
{value: 0x8100, lo: 0x87, hi: 0x87},
{value: 0x8100, lo: 0x90, hi: 0x90},
{value: 0x8100, lo: 0x9e, hi: 0x9e},
{value: 0x8100, lo: 0xa1, hi: 0xa1},
{value: 0x8100, lo: 0xb2, hi: 0xb2},
{value: 0x8100, lo: 0xbb, hi: 0xbb},
// Block 0x4e, offset 0x196
{value: 0x0000, lo: 0x03},
{value: 0x8100, lo: 0x80, hi: 0x80},
{value: 0x8100, lo: 0x8b, hi: 0x8b},
{value: 0x8100, lo: 0x8e, hi: 0x8e},
// Block 0x4f, offset 0x19a
{value: 0x0000, lo: 0x02},
{value: 0x8133, lo: 0xaf, hi: 0xaf},
{value: 0x8133, lo: 0xb4, hi: 0xbd},
// Block 0x50, offset 0x19d
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0x9e, hi: 0x9f},
// Block 0x51, offset 0x19f
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xb0, hi: 0xb1},
// Block 0x52, offset 0x1a1
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0x86, hi: 0x86},
{value: 0x8105, lo: 0xac, hi: 0xac},
// Block 0x53, offset 0x1a4
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0x84, hi: 0x84},
{value: 0x8133, lo: 0xa0, hi: 0xb1},
// Block 0x54, offset 0x1a7
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0xab, hi: 0xad},
// Block 0x55, offset 0x1a9
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x93, hi: 0x93},
// Block 0x56, offset 0x1ab
{value: 0x0000, lo: 0x01},
{value: 0x8103, lo: 0xb3, hi: 0xb3},
// Block 0x57, offset 0x1ad
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x80, hi: 0x80},
// Block 0x58, offset 0x1af
{value: 0x0000, lo: 0x05},
{value: 0x8133, lo: 0xb0, hi: 0xb0},
{value: 0x8133, lo: 0xb2, hi: 0xb3},
{value: 0x812e, lo: 0xb4, hi: 0xb4},
{value: 0x8133, lo: 0xb7, hi: 0xb8},
{value: 0x8133, lo: 0xbe, hi: 0xbf},
// Block 0x59, offset 0x1b5
{value: 0x0000, lo: 0x02},
{value: 0x8133, lo: 0x81, hi: 0x81},
{value: 0x8105, lo: 0xb6, hi: 0xb6},
// Block 0x5a, offset 0x1b8
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xad, hi: 0xad},
// Block 0x5b, offset 0x1ba
{value: 0x0000, lo: 0x06},
{value: 0xe500, lo: 0x80, hi: 0x80},
{value: 0xc600, lo: 0x81, hi: 0x9b},
{value: 0xe500, lo: 0x9c, hi: 0x9c},
{value: 0xc600, lo: 0x9d, hi: 0xb7},
{value: 0xe500, lo: 0xb8, hi: 0xb8},
{value: 0xc600, lo: 0xb9, hi: 0xbf},
// Block 0x5c, offset 0x1c1
{value: 0x0000, lo: 0x05},
{value: 0xc600, lo: 0x80, hi: 0x93},
{value: 0xe500, lo: 0x94, hi: 0x94},
{value: 0xc600, lo: 0x95, hi: 0xaf},
{value: 0xe500, lo: 0xb0, hi: 0xb0},
{value: 0xc600, lo: 0xb1, hi: 0xbf},
// Block 0x5d, offset 0x1c7
{value: 0x0000, lo: 0x05},
{value: 0xc600, lo: 0x80, hi: 0x8b},
{value: 0xe500, lo: 0x8c, hi: 0x8c},
{value: 0xc600, lo: 0x8d, hi: 0xa7},
{value: 0xe500, lo: 0xa8, hi: 0xa8},
{value: 0xc600, lo: 0xa9, hi: 0xbf},
// Block 0x5e, offset 0x1cd
{value: 0x0000, lo: 0x07},
{value: 0xc600, lo: 0x80, hi: 0x83},
{value: 0xe500, lo: 0x84, hi: 0x84},
{value: 0xc600, lo: 0x85, hi: 0x9f},
{value: 0xe500, lo: 0xa0, hi: 0xa0},
{value: 0xc600, lo: 0xa1, hi: 0xbb},
{value: 0xe500, lo: 0xbc, hi: 0xbc},
{value: 0xc600, lo: 0xbd, hi: 0xbf},
// Block 0x5f, offset 0x1d5
{value: 0x0000, lo: 0x05},
{value: 0xc600, lo: 0x80, hi: 0x97},
{value: 0xe500, lo: 0x98, hi: 0x98},
{value: 0xc600, lo: 0x99, hi: 0xb3},
{value: 0xe500, lo: 0xb4, hi: 0xb4},
{value: 0xc600, lo: 0xb5, hi: 0xbf},
// Block 0x60, offset 0x1db
{value: 0x0000, lo: 0x05},
{value: 0xc600, lo: 0x80, hi: 0x8f},
{value: 0xe500, lo: 0x90, hi: 0x90},
{value: 0xc600, lo: 0x91, hi: 0xab},
{value: 0xe500, lo: 0xac, hi: 0xac},
{value: 0xc600, lo: 0xad, hi: 0xbf},
// Block 0x61, offset 0x1e1
{value: 0x0000, lo: 0x05},
{value: 0xc600, lo: 0x80, hi: 0x87},
{value: 0xe500, lo: 0x88, hi: 0x88},
{value: 0xc600, lo: 0x89, hi: 0xa3},
{value: 0xe500, lo: 0xa4, hi: 0xa4},
{value: 0xc600, lo: 0xa5, hi: 0xbf},
// Block 0x62, offset 0x1e7
{value: 0x0000, lo: 0x03},
{value: 0xc600, lo: 0x80, hi: 0x87},
{value: 0xe500, lo: 0x88, hi: 0x88},
{value: 0xc600, lo: 0x89, hi: 0xa3},
// Block 0x63, offset 0x1eb
{value: 0x0006, lo: 0x0d},
{value: 0x44d1, lo: 0x9d, hi: 0x9d},
{value: 0x8116, lo: 0x9e, hi: 0x9e},
{value: 0x4543, lo: 0x9f, hi: 0x9f},
{value: 0x4531, lo: 0xaa, hi: 0xab},
{value: 0x4635, lo: 0xac, hi: 0xac},
{value: 0x463d, lo: 0xad, hi: 0xad},
{value: 0x4489, lo: 0xae, hi: 0xb1},
{value: 0x44a7, lo: 0xb2, hi: 0xb4},
{value: 0x44bf, lo: 0xb5, hi: 0xb6},
{value: 0x44cb, lo: 0xb8, hi: 0xb8},
{value: 0x44d7, lo: 0xb9, hi: 0xbb},
{value: 0x44ef, lo: 0xbc, hi: 0xbc},
{value: 0x44f5, lo: 0xbe, hi: 0xbe},
// Block 0x64, offset 0x1f9
{value: 0x0006, lo: 0x08},
{value: 0x44fb, lo: 0x80, hi: 0x81},
{value: 0x4507, lo: 0x83, hi: 0x84},
{value: 0x4519, lo: 0x86, hi: 0x89},
{value: 0x453d, lo: 0x8a, hi: 0x8a},
{value: 0x44b9, lo: 0x8b, hi: 0x8b},
{value: 0x44a1, lo: 0x8c, hi: 0x8c},
{value: 0x44e9, lo: 0x8d, hi: 0x8d},
{value: 0x4513, lo: 0x8e, hi: 0x8e},
// Block 0x65, offset 0x202
{value: 0x0000, lo: 0x02},
{value: 0x8100, lo: 0xa4, hi: 0xa5},
{value: 0x8100, lo: 0xb0, hi: 0xb1},
// Block 0x66, offset 0x205
{value: 0x0000, lo: 0x02},
{value: 0x8100, lo: 0x9b, hi: 0x9d},
{value: 0x8200, lo: 0x9e, hi: 0xa3},
// Block 0x67, offset 0x208
{value: 0x0000, lo: 0x01},
{value: 0x8100, lo: 0x90, hi: 0x90},
// Block 0x68, offset 0x20a
{value: 0x0000, lo: 0x02},
{value: 0x8100, lo: 0x99, hi: 0x99},
{value: 0x8200, lo: 0xb2, hi: 0xb4},
// Block 0x69, offset 0x20d
{value: 0x0000, lo: 0x01},
{value: 0x8100, lo: 0xbc, hi: 0xbd},
// Block 0x6a, offset 0x20f
{value: 0x0000, lo: 0x03},
{value: 0x8133, lo: 0xa0, hi: 0xa6},
{value: 0x812e, lo: 0xa7, hi: 0xad},
{value: 0x8133, lo: 0xae, hi: 0xaf},
// Block 0x6b, offset 0x213
{value: 0x0000, lo: 0x04},
{value: 0x8100, lo: 0x89, hi: 0x8c},
{value: 0x8100, lo: 0xb0, hi: 0xb2},
{value: 0x8100, lo: 0xb4, hi: 0xb4},
{value: 0x8100, lo: 0xb6, hi: 0xbf},
// Block 0x6c, offset 0x218
{value: 0x0000, lo: 0x01},
{value: 0x8100, lo: 0x81, hi: 0x8c},
// Block 0x6d, offset 0x21a
{value: 0x0000, lo: 0x01},
{value: 0x8100, lo: 0xb5, hi: 0xba},
// Block 0x6e, offset 0x21c
{value: 0x0000, lo: 0x04},
{value: 0x4be0, lo: 0x9e, hi: 0x9f},
{value: 0x4be0, lo: 0xa3, hi: 0xa3},
{value: 0x4be0, lo: 0xa5, hi: 0xa6},
{value: 0x4be0, lo: 0xaa, hi: 0xaf},
// Block 0x6f, offset 0x221
{value: 0x0000, lo: 0x05},
{value: 0x4be0, lo: 0x82, hi: 0x87},
{value: 0x4be0, lo: 0x8a, hi: 0x8f},
{value: 0x4be0, lo: 0x92, hi: 0x97},
{value: 0x4be0, lo: 0x9a, hi: 0x9c},
{value: 0x8100, lo: 0xa3, hi: 0xa3},
// Block 0x70, offset 0x227
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0xbd, hi: 0xbd},
// Block 0x71, offset 0x229
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0xa0, hi: 0xa0},
// Block 0x72, offset 0x22b
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xb6, hi: 0xba},
// Block 0x73, offset 0x22d
{value: 0x002d, lo: 0x05},
{value: 0x812e, lo: 0x8d, hi: 0x8d},
{value: 0x8133, lo: 0x8f, hi: 0x8f},
{value: 0x8133, lo: 0xb8, hi: 0xb8},
{value: 0x8101, lo: 0xb9, hi: 0xba},
{value: 0x8105, lo: 0xbf, hi: 0xbf},
// Block 0x74, offset 0x233
{value: 0x0000, lo: 0x02},
{value: 0x8133, lo: 0xa5, hi: 0xa5},
{value: 0x812e, lo: 0xa6, hi: 0xa6},
// Block 0x75, offset 0x236
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xa4, hi: 0xa7},
// Block 0x76, offset 0x238
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xab, hi: 0xac},
// Block 0x77, offset 0x23a
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0xbd, hi: 0xbf},
// Block 0x78, offset 0x23c
{value: 0x0000, lo: 0x05},
{value: 0x812e, lo: 0x86, hi: 0x87},
{value: 0x8133, lo: 0x88, hi: 0x8a},
{value: 0x812e, lo: 0x8b, hi: 0x8b},
{value: 0x8133, lo: 0x8c, hi: 0x8c},
{value: 0x812e, lo: 0x8d, hi: 0x90},
// Block 0x79, offset 0x242
{value: 0x0005, lo: 0x03},
{value: 0x8133, lo: 0x82, hi: 0x82},
{value: 0x812e, lo: 0x83, hi: 0x84},
{value: 0x812e, lo: 0x85, hi: 0x85},
// Block 0x7a, offset 0x246
{value: 0x0000, lo: 0x03},
{value: 0x8105, lo: 0x86, hi: 0x86},
{value: 0x8105, lo: 0xb0, hi: 0xb0},
{value: 0x8105, lo: 0xbf, hi: 0xbf},
// Block 0x7b, offset 0x24a
{value: 0x17fe, lo: 0x07},
{value: 0xa000, lo: 0x99, hi: 0x99},
{value: 0x4379, lo: 0x9a, hi: 0x9a},
{value: 0xa000, lo: 0x9b, hi: 0x9b},
{value: 0x4383, lo: 0x9c, hi: 0x9c},
{value: 0xa000, lo: 0xa5, hi: 0xa5},
{value: 0x438d, lo: 0xab, hi: 0xab},
{value: 0x8105, lo: 0xb9, hi: 0xba},
// Block 0x7c, offset 0x252
{value: 0x0000, lo: 0x06},
{value: 0x8133, lo: 0x80, hi: 0x82},
{value: 0x9900, lo: 0xa7, hi: 0xa7},
{value: 0x2eb5, lo: 0xae, hi: 0xae},
{value: 0x2ebf, lo: 0xaf, hi: 0xaf},
{value: 0xa000, lo: 0xb1, hi: 0xb2},
{value: 0x8105, lo: 0xb3, hi: 0xb4},
// Block 0x7d, offset 0x259
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0x80, hi: 0x80},
{value: 0x8103, lo: 0x8a, hi: 0x8a},
// Block 0x7e, offset 0x25c
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0xb5, hi: 0xb5},
{value: 0x8103, lo: 0xb6, hi: 0xb6},
// Block 0x7f, offset 0x25f
{value: 0x0002, lo: 0x01},
{value: 0x8103, lo: 0xa9, hi: 0xaa},
// Block 0x80, offset 0x261
{value: 0x0000, lo: 0x02},
{value: 0x8103, lo: 0xbb, hi: 0xbc},
{value: 0x9900, lo: 0xbe, hi: 0xbe},
// Block 0x81, offset 0x264
{value: 0x0000, lo: 0x07},
{value: 0xa000, lo: 0x87, hi: 0x87},
{value: 0x2ec9, lo: 0x8b, hi: 0x8b},
{value: 0x2ed3, lo: 0x8c, hi: 0x8c},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x9900, lo: 0x97, hi: 0x97},
{value: 0x8133, lo: 0xa6, hi: 0xac},
{value: 0x8133, lo: 0xb0, hi: 0xb4},
// Block 0x82, offset 0x26c
{value: 0x0000, lo: 0x03},
{value: 0x8105, lo: 0x82, hi: 0x82},
{value: 0x8103, lo: 0x86, hi: 0x86},
{value: 0x8133, lo: 0x9e, hi: 0x9e},
// Block 0x83, offset 0x270
{value: 0x6a23, lo: 0x06},
{value: 0x9900, lo: 0xb0, hi: 0xb0},
{value: 0xa000, lo: 0xb9, hi: 0xb9},
{value: 0x9900, lo: 0xba, hi: 0xba},
{value: 0x2ee7, lo: 0xbb, hi: 0xbb},
{value: 0x2edd, lo: 0xbc, hi: 0xbd},
{value: 0x2ef1, lo: 0xbe, hi: 0xbe},
// Block 0x84, offset 0x277
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0x82, hi: 0x82},
{value: 0x8103, lo: 0x83, hi: 0x83},
// Block 0x85, offset 0x27a
{value: 0x0000, lo: 0x05},
{value: 0x9900, lo: 0xaf, hi: 0xaf},
{value: 0xa000, lo: 0xb8, hi: 0xb9},
{value: 0x2efb, lo: 0xba, hi: 0xba},
{value: 0x2f05, lo: 0xbb, hi: 0xbb},
{value: 0x8105, lo: 0xbf, hi: 0xbf},
// Block 0x86, offset 0x280
{value: 0x0000, lo: 0x01},
{value: 0x8103, lo: 0x80, hi: 0x80},
// Block 0x87, offset 0x282
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0xb6, hi: 0xb6},
{value: 0x8103, lo: 0xb7, hi: 0xb7},
// Block 0x88, offset 0x285
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xab, hi: 0xab},
// Block 0x89, offset 0x287
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0xb9, hi: 0xb9},
{value: 0x8103, lo: 0xba, hi: 0xba},
// Block 0x8a, offset 0x28a
{value: 0x0000, lo: 0x04},
{value: 0x9900, lo: 0xb0, hi: 0xb0},
{value: 0xa000, lo: 0xb5, hi: 0xb5},
{value: 0x2f0f, lo: 0xb8, hi: 0xb8},
{value: 0x8105, lo: 0xbd, hi: 0xbe},
// Block 0x8b, offset 0x28f
{value: 0x0000, lo: 0x01},
{value: 0x8103, lo: 0x83, hi: 0x83},
// Block 0x8c, offset 0x291
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xa0, hi: 0xa0},
// Block 0x8d, offset 0x293
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xb4, hi: 0xb4},
// Block 0x8e, offset 0x295
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x87, hi: 0x87},
// Block 0x8f, offset 0x297
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x99, hi: 0x99},
// Block 0x90, offset 0x299
{value: 0x0000, lo: 0x02},
{value: 0x8103, lo: 0x82, hi: 0x82},
{value: 0x8105, lo: 0x84, hi: 0x85},
// Block 0x91, offset 0x29c
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x97, hi: 0x97},
// Block 0x92, offset 0x29e
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x81, hi: 0x82},
// Block 0x93, offset 0x2a0
{value: 0x0000, lo: 0x01},
{value: 0x8101, lo: 0xb0, hi: 0xb4},
// Block 0x94, offset 0x2a2
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xb0, hi: 0xb6},
// Block 0x95, offset 0x2a4
{value: 0x0000, lo: 0x01},
{value: 0x8102, lo: 0xb0, hi: 0xb1},
// Block 0x96, offset 0x2a6
{value: 0x0000, lo: 0x01},
{value: 0x8101, lo: 0x9e, hi: 0x9e},
// Block 0x97, offset 0x2a8
{value: 0x0000, lo: 0x0c},
{value: 0x470d, lo: 0x9e, hi: 0x9e},
{value: 0x4717, lo: 0x9f, hi: 0x9f},
{value: 0x474b, lo: 0xa0, hi: 0xa0},
{value: 0x4759, lo: 0xa1, hi: 0xa1},
{value: 0x4767, lo: 0xa2, hi: 0xa2},
{value: 0x4775, lo: 0xa3, hi: 0xa3},
{value: 0x4783, lo: 0xa4, hi: 0xa4},
{value: 0x812c, lo: 0xa5, hi: 0xa6},
{value: 0x8101, lo: 0xa7, hi: 0xa9},
{value: 0x8131, lo: 0xad, hi: 0xad},
{value: 0x812c, lo: 0xae, hi: 0xb2},
{value: 0x812e, lo: 0xbb, hi: 0xbf},
// Block 0x98, offset 0x2b5
{value: 0x0000, lo: 0x09},
{value: 0x812e, lo: 0x80, hi: 0x82},
{value: 0x8133, lo: 0x85, hi: 0x89},
{value: 0x812e, lo: 0x8a, hi: 0x8b},
{value: 0x8133, lo: 0xaa, hi: 0xad},
{value: 0x4721, lo: 0xbb, hi: 0xbb},
{value: 0x472b, lo: 0xbc, hi: 0xbc},
{value: 0x4791, lo: 0xbd, hi: 0xbd},
{value: 0x47ad, lo: 0xbe, hi: 0xbe},
{value: 0x479f, lo: 0xbf, hi: 0xbf},
// Block 0x99, offset 0x2bf
{value: 0x0000, lo: 0x01},
{value: 0x47bb, lo: 0x80, hi: 0x80},
// Block 0x9a, offset 0x2c1
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0x82, hi: 0x84},
// Block 0x9b, offset 0x2c3
{value: 0x0000, lo: 0x05},
{value: 0x8133, lo: 0x80, hi: 0x86},
{value: 0x8133, lo: 0x88, hi: 0x98},
{value: 0x8133, lo: 0x9b, hi: 0xa1},
{value: 0x8133, lo: 0xa3, hi: 0xa4},
{value: 0x8133, lo: 0xa6, hi: 0xaa},
// Block 0x9c, offset 0x2c9
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0x8f, hi: 0x8f},
// Block 0x9d, offset 0x2cb
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xae, hi: 0xae},
// Block 0x9e, offset 0x2cd
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xac, hi: 0xaf},
// Block 0x9f, offset 0x2cf
{value: 0x0000, lo: 0x03},
{value: 0x8134, lo: 0xac, hi: 0xad},
{value: 0x812e, lo: 0xae, hi: 0xae},
{value: 0x8133, lo: 0xaf, hi: 0xaf},
// Block 0xa0, offset 0x2d3
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0x90, hi: 0x96},
// Block 0xa1, offset 0x2d5
{value: 0x0000, lo: 0x02},
{value: 0x8133, lo: 0x84, hi: 0x89},
{value: 0x8103, lo: 0x8a, hi: 0x8a},
// Block 0xa2, offset 0x2d8
{value: 0x0000, lo: 0x01},
{value: 0x8100, lo: 0x93, hi: 0x93},
}
// lookup returns the trie value for the first UTF-8 encoding in s and
// the width in bytes of this encoding. The size will be 0 if s does not
// hold enough bytes to complete the encoding. len(s) must be greater than 0.
func (t *nfkcTrie) lookup(s []byte) (v uint16, sz int) {
c0 := s[0]
switch {
case c0 < 0x80: // is ASCII
return nfkcValues[c0], 1
case c0 < 0xC2:
return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
case c0 < 0xE0: // 2-byte UTF-8
if len(s) < 2 {
return 0, 0
}
i := nfkcIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c1), 2
case c0 < 0xF0: // 3-byte UTF-8
if len(s) < 3 {
return 0, 0
}
i := nfkcIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = nfkcIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c2), 3
case c0 < 0xF8: // 4-byte UTF-8
if len(s) < 4 {
return 0, 0
}
i := nfkcIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = nfkcIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
o = uint32(i)<<6 + uint32(c2)
i = nfkcIndex[o]
c3 := s[3]
if c3 < 0x80 || 0xC0 <= c3 {
return 0, 3 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c3), 4
}
// Illegal rune
return 0, 1
}
// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
// s must start with a full and valid UTF-8 encoded rune.
func (t *nfkcTrie) lookupUnsafe(s []byte) uint16 {
c0 := s[0]
if c0 < 0x80 { // is ASCII
return nfkcValues[c0]
}
i := nfkcIndex[c0]
if c0 < 0xE0 { // 2-byte UTF-8
return t.lookupValue(uint32(i), s[1])
}
i = nfkcIndex[uint32(i)<<6+uint32(s[1])]
if c0 < 0xF0 { // 3-byte UTF-8
return t.lookupValue(uint32(i), s[2])
}
i = nfkcIndex[uint32(i)<<6+uint32(s[2])]
if c0 < 0xF8 { // 4-byte UTF-8
return t.lookupValue(uint32(i), s[3])
}
return 0
}
// lookupString returns the trie value for the first UTF-8 encoding in s and
// the width in bytes of this encoding. The size will be 0 if s does not
// hold enough bytes to complete the encoding. len(s) must be greater than 0.
func (t *nfkcTrie) lookupString(s string) (v uint16, sz int) {
c0 := s[0]
switch {
case c0 < 0x80: // is ASCII
return nfkcValues[c0], 1
case c0 < 0xC2:
return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
case c0 < 0xE0: // 2-byte UTF-8
if len(s) < 2 {
return 0, 0
}
i := nfkcIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c1), 2
case c0 < 0xF0: // 3-byte UTF-8
if len(s) < 3 {
return 0, 0
}
i := nfkcIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = nfkcIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c2), 3
case c0 < 0xF8: // 4-byte UTF-8
if len(s) < 4 {
return 0, 0
}
i := nfkcIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = nfkcIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
o = uint32(i)<<6 + uint32(c2)
i = nfkcIndex[o]
c3 := s[3]
if c3 < 0x80 || 0xC0 <= c3 {
return 0, 3 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c3), 4
}
// Illegal rune
return 0, 1
}
// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
// s must start with a full and valid UTF-8 encoded rune.
func (t *nfkcTrie) lookupStringUnsafe(s string) uint16 {
c0 := s[0]
if c0 < 0x80 { // is ASCII
return nfkcValues[c0]
}
i := nfkcIndex[c0]
if c0 < 0xE0 { // 2-byte UTF-8
return t.lookupValue(uint32(i), s[1])
}
i = nfkcIndex[uint32(i)<<6+uint32(s[1])]
if c0 < 0xF0 { // 3-byte UTF-8
return t.lookupValue(uint32(i), s[2])
}
i = nfkcIndex[uint32(i)<<6+uint32(s[2])]
if c0 < 0xF8 { // 4-byte UTF-8
return t.lookupValue(uint32(i), s[3])
}
return 0
}
// nfkcTrie. Total size: 19260 bytes (18.81 KiB). Checksum: 1a0bbc4c8c24da49.
type nfkcTrie struct{}
func newNfkcTrie(i int) *nfkcTrie {
return &nfkcTrie{}
}
// lookupValue determines the type of block n and looks up the value for b.
func (t *nfkcTrie) lookupValue(n uint32, b byte) uint16 {
switch {
case n < 95:
return uint16(nfkcValues[n<<6+uint32(b)])
default:
n -= 95
return uint16(nfkcSparse.lookup(n, b))
}
}
// nfkcValues: 97 blocks, 6208 entries, 12416 bytes
// The third block is the zero block.
var nfkcValues = [6208]uint16{
// Block 0x0, offset 0x0
0x3c: 0xa000, 0x3d: 0xa000, 0x3e: 0xa000,
// Block 0x1, offset 0x40
0x41: 0xa000, 0x42: 0xa000, 0x43: 0xa000, 0x44: 0xa000, 0x45: 0xa000,
0x46: 0xa000, 0x47: 0xa000, 0x48: 0xa000, 0x49: 0xa000, 0x4a: 0xa000, 0x4b: 0xa000,
0x4c: 0xa000, 0x4d: 0xa000, 0x4e: 0xa000, 0x4f: 0xa000, 0x50: 0xa000,
0x52: 0xa000, 0x53: 0xa000, 0x54: 0xa000, 0x55: 0xa000, 0x56: 0xa000, 0x57: 0xa000,
0x58: 0xa000, 0x59: 0xa000, 0x5a: 0xa000,
0x61: 0xa000, 0x62: 0xa000, 0x63: 0xa000,
0x64: 0xa000, 0x65: 0xa000, 0x66: 0xa000, 0x67: 0xa000, 0x68: 0xa000, 0x69: 0xa000,
0x6a: 0xa000, 0x6b: 0xa000, 0x6c: 0xa000, 0x6d: 0xa000, 0x6e: 0xa000, 0x6f: 0xa000,
0x70: 0xa000, 0x72: 0xa000, 0x73: 0xa000, 0x74: 0xa000, 0x75: 0xa000,
0x76: 0xa000, 0x77: 0xa000, 0x78: 0xa000, 0x79: 0xa000, 0x7a: 0xa000,
// Block 0x2, offset 0x80
// Block 0x3, offset 0xc0
0xc0: 0x30b0, 0xc1: 0x30b5, 0xc2: 0x47c9, 0xc3: 0x30ba, 0xc4: 0x47d8, 0xc5: 0x47dd,
0xc6: 0xa000, 0xc7: 0x47e7, 0xc8: 0x3123, 0xc9: 0x3128, 0xca: 0x47ec, 0xcb: 0x313c,
0xcc: 0x31af, 0xcd: 0x31b4, 0xce: 0x31b9, 0xcf: 0x4800, 0xd1: 0x3245,
0xd2: 0x3268, 0xd3: 0x326d, 0xd4: 0x480a, 0xd5: 0x480f, 0xd6: 0x481e,
0xd8: 0xa000, 0xd9: 0x32f4, 0xda: 0x32f9, 0xdb: 0x32fe, 0xdc: 0x4850, 0xdd: 0x3376,
0xe0: 0x33bc, 0xe1: 0x33c1, 0xe2: 0x485a, 0xe3: 0x33c6,
0xe4: 0x4869, 0xe5: 0x486e, 0xe6: 0xa000, 0xe7: 0x4878, 0xe8: 0x342f, 0xe9: 0x3434,
0xea: 0x487d, 0xeb: 0x3448, 0xec: 0x34c0, 0xed: 0x34c5, 0xee: 0x34ca, 0xef: 0x4891,
0xf1: 0x3556, 0xf2: 0x3579, 0xf3: 0x357e, 0xf4: 0x489b, 0xf5: 0x48a0,
0xf6: 0x48af, 0xf8: 0xa000, 0xf9: 0x360a, 0xfa: 0x360f, 0xfb: 0x3614,
0xfc: 0x48e1, 0xfd: 0x3691, 0xff: 0x36aa,
// Block 0x4, offset 0x100
0x100: 0x30bf, 0x101: 0x33cb, 0x102: 0x47ce, 0x103: 0x485f, 0x104: 0x30dd, 0x105: 0x33e9,
0x106: 0x30f1, 0x107: 0x33fd, 0x108: 0x30f6, 0x109: 0x3402, 0x10a: 0x30fb, 0x10b: 0x3407,
0x10c: 0x3100, 0x10d: 0x340c, 0x10e: 0x310a, 0x10f: 0x3416,
0x112: 0x47f1, 0x113: 0x4882, 0x114: 0x3132, 0x115: 0x343e, 0x116: 0x3137, 0x117: 0x3443,
0x118: 0x3155, 0x119: 0x3461, 0x11a: 0x3146, 0x11b: 0x3452, 0x11c: 0x316e, 0x11d: 0x347a,
0x11e: 0x3178, 0x11f: 0x3484, 0x120: 0x317d, 0x121: 0x3489, 0x122: 0x3187, 0x123: 0x3493,
0x124: 0x318c, 0x125: 0x3498, 0x128: 0x31be, 0x129: 0x34cf,
0x12a: 0x31c3, 0x12b: 0x34d4, 0x12c: 0x31c8, 0x12d: 0x34d9, 0x12e: 0x31eb, 0x12f: 0x34f7,
0x130: 0x31cd, 0x132: 0x1a8a, 0x133: 0x1b17, 0x134: 0x31f5, 0x135: 0x3501,
0x136: 0x3209, 0x137: 0x351a, 0x139: 0x3213, 0x13a: 0x3524, 0x13b: 0x321d,
0x13c: 0x352e, 0x13d: 0x3218, 0x13e: 0x3529, 0x13f: 0x1cdc,
// Block 0x5, offset 0x140
0x140: 0x1d64, 0x143: 0x3240, 0x144: 0x3551, 0x145: 0x3259,
0x146: 0x356a, 0x147: 0x324f, 0x148: 0x3560, 0x149: 0x1d8c,
0x14c: 0x4814, 0x14d: 0x48a5, 0x14e: 0x3272, 0x14f: 0x3583, 0x150: 0x327c, 0x151: 0x358d,
0x154: 0x329a, 0x155: 0x35ab, 0x156: 0x32b3, 0x157: 0x35c4,
0x158: 0x32a4, 0x159: 0x35b5, 0x15a: 0x4837, 0x15b: 0x48c8, 0x15c: 0x32bd, 0x15d: 0x35ce,
0x15e: 0x32cc, 0x15f: 0x35dd, 0x160: 0x483c, 0x161: 0x48cd, 0x162: 0x32e5, 0x163: 0x35fb,
0x164: 0x32d6, 0x165: 0x35ec, 0x168: 0x4846, 0x169: 0x48d7,
0x16a: 0x484b, 0x16b: 0x48dc, 0x16c: 0x3303, 0x16d: 0x3619, 0x16e: 0x330d, 0x16f: 0x3623,
0x170: 0x3312, 0x171: 0x3628, 0x172: 0x3330, 0x173: 0x3646, 0x174: 0x3353, 0x175: 0x3669,
0x176: 0x337b, 0x177: 0x3696, 0x178: 0x338f, 0x179: 0x339e, 0x17a: 0x36be, 0x17b: 0x33a8,
0x17c: 0x36c8, 0x17d: 0x33ad, 0x17e: 0x36cd, 0x17f: 0x00a7,
// Block 0x6, offset 0x180
0x184: 0x2f2f, 0x185: 0x2f35,
0x186: 0x2f3b, 0x187: 0x1a9f, 0x188: 0x1aa2, 0x189: 0x1b38, 0x18a: 0x1ab7, 0x18b: 0x1aba,
0x18c: 0x1b6e, 0x18d: 0x30c9, 0x18e: 0x33d5, 0x18f: 0x31d7, 0x190: 0x34e3, 0x191: 0x3281,
0x192: 0x3592, 0x193: 0x3317, 0x194: 0x362d, 0x195: 0x3b10, 0x196: 0x3c9f, 0x197: 0x3b09,
0x198: 0x3c98, 0x199: 0x3b17, 0x19a: 0x3ca6, 0x19b: 0x3b02, 0x19c: 0x3c91,
0x19e: 0x39f1, 0x19f: 0x3b80, 0x1a0: 0x39ea, 0x1a1: 0x3b79, 0x1a2: 0x36f4, 0x1a3: 0x3706,
0x1a6: 0x3182, 0x1a7: 0x348e, 0x1a8: 0x31ff, 0x1a9: 0x3510,
0x1aa: 0x482d, 0x1ab: 0x48be, 0x1ac: 0x3ad1, 0x1ad: 0x3c60, 0x1ae: 0x3718, 0x1af: 0x371e,
0x1b0: 0x3506, 0x1b1: 0x1a6f, 0x1b2: 0x1a72, 0x1b3: 0x1aff, 0x1b4: 0x3169, 0x1b5: 0x3475,
0x1b8: 0x323b, 0x1b9: 0x354c, 0x1ba: 0x39f8, 0x1bb: 0x3b87,
0x1bc: 0x36ee, 0x1bd: 0x3700, 0x1be: 0x36fa, 0x1bf: 0x370c,
// Block 0x7, offset 0x1c0
0x1c0: 0x30ce, 0x1c1: 0x33da, 0x1c2: 0x30d3, 0x1c3: 0x33df, 0x1c4: 0x314b, 0x1c5: 0x3457,
0x1c6: 0x3150, 0x1c7: 0x345c, 0x1c8: 0x31dc, 0x1c9: 0x34e8, 0x1ca: 0x31e1, 0x1cb: 0x34ed,
0x1cc: 0x3286, 0x1cd: 0x3597, 0x1ce: 0x328b, 0x1cf: 0x359c, 0x1d0: 0x32a9, 0x1d1: 0x35ba,
0x1d2: 0x32ae, 0x1d3: 0x35bf, 0x1d4: 0x331c, 0x1d5: 0x3632, 0x1d6: 0x3321, 0x1d7: 0x3637,
0x1d8: 0x32c7, 0x1d9: 0x35d8, 0x1da: 0x32e0, 0x1db: 0x35f6,
0x1de: 0x319b, 0x1df: 0x34a7,
0x1e6: 0x47d3, 0x1e7: 0x4864, 0x1e8: 0x47fb, 0x1e9: 0x488c,
0x1ea: 0x3aa0, 0x1eb: 0x3c2f, 0x1ec: 0x3a7d, 0x1ed: 0x3c0c, 0x1ee: 0x4819, 0x1ef: 0x48aa,
0x1f0: 0x3a99, 0x1f1: 0x3c28, 0x1f2: 0x3385, 0x1f3: 0x36a0,
// Block 0x8, offset 0x200
0x200: 0x9933, 0x201: 0x9933, 0x202: 0x9933, 0x203: 0x9933, 0x204: 0x9933, 0x205: 0x8133,
0x206: 0x9933, 0x207: 0x9933, 0x208: 0x9933, 0x209: 0x9933, 0x20a: 0x9933, 0x20b: 0x9933,
0x20c: 0x9933, 0x20d: 0x8133, 0x20e: 0x8133, 0x20f: 0x9933, 0x210: 0x8133, 0x211: 0x9933,
0x212: 0x8133, 0x213: 0x9933, 0x214: 0x9933, 0x215: 0x8134, 0x216: 0x812e, 0x217: 0x812e,
0x218: 0x812e, 0x219: 0x812e, 0x21a: 0x8134, 0x21b: 0x992c, 0x21c: 0x812e, 0x21d: 0x812e,
0x21e: 0x812e, 0x21f: 0x812e, 0x220: 0x812e, 0x221: 0x812a, 0x222: 0x812a, 0x223: 0x992e,
0x224: 0x992e, 0x225: 0x992e, 0x226: 0x992e, 0x227: 0x992a, 0x228: 0x992a, 0x229: 0x812e,
0x22a: 0x812e, 0x22b: 0x812e, 0x22c: 0x812e, 0x22d: 0x992e, 0x22e: 0x992e, 0x22f: 0x812e,
0x230: 0x992e, 0x231: 0x992e, 0x232: 0x812e, 0x233: 0x812e, 0x234: 0x8101, 0x235: 0x8101,
0x236: 0x8101, 0x237: 0x8101, 0x238: 0x9901, 0x239: 0x812e, 0x23a: 0x812e, 0x23b: 0x812e,
0x23c: 0x812e, 0x23d: 0x8133, 0x23e: 0x8133, 0x23f: 0x8133,
// Block 0x9, offset 0x240
0x240: 0x4aef, 0x241: 0x4af4, 0x242: 0x9933, 0x243: 0x4af9, 0x244: 0x4bb2, 0x245: 0x9937,
0x246: 0x8133, 0x247: 0x812e, 0x248: 0x812e, 0x249: 0x812e, 0x24a: 0x8133, 0x24b: 0x8133,
0x24c: 0x8133, 0x24d: 0x812e, 0x24e: 0x812e, 0x250: 0x8133, 0x251: 0x8133,
0x252: 0x8133, 0x253: 0x812e, 0x254: 0x812e, 0x255: 0x812e, 0x256: 0x812e, 0x257: 0x8133,
0x258: 0x8134, 0x259: 0x812e, 0x25a: 0x812e, 0x25b: 0x8133, 0x25c: 0x8135, 0x25d: 0x8136,
0x25e: 0x8136, 0x25f: 0x8135, 0x260: 0x8136, 0x261: 0x8136, 0x262: 0x8135, 0x263: 0x8133,
0x264: 0x8133, 0x265: 0x8133, 0x266: 0x8133, 0x267: 0x8133, 0x268: 0x8133, 0x269: 0x8133,
0x26a: 0x8133, 0x26b: 0x8133, 0x26c: 0x8133, 0x26d: 0x8133, 0x26e: 0x8133, 0x26f: 0x8133,
0x274: 0x01ee,
0x27a: 0x43e6,
0x27e: 0x0037,
// Block 0xa, offset 0x280
0x284: 0x439b, 0x285: 0x45bc,
0x286: 0x372a, 0x287: 0x00ce, 0x288: 0x3748, 0x289: 0x3754, 0x28a: 0x3766,
0x28c: 0x3784, 0x28e: 0x3796, 0x28f: 0x37b4, 0x290: 0x3f49, 0x291: 0xa000,
0x295: 0xa000, 0x297: 0xa000,
0x299: 0xa000,
0x29f: 0xa000, 0x2a1: 0xa000,
0x2a5: 0xa000, 0x2a9: 0xa000,
0x2aa: 0x3778, 0x2ab: 0x37a8, 0x2ac: 0x493f, 0x2ad: 0x37d8, 0x2ae: 0x4969, 0x2af: 0x37ea,
0x2b0: 0x3fb1, 0x2b1: 0xa000, 0x2b5: 0xa000,
0x2b7: 0xa000, 0x2b9: 0xa000,
0x2bf: 0xa000,
// Block 0xb, offset 0x2c0
0x2c1: 0xa000, 0x2c5: 0xa000,
0x2c9: 0xa000, 0x2ca: 0x4981, 0x2cb: 0x499f,
0x2cc: 0x3808, 0x2cd: 0x3820, 0x2ce: 0x49b7, 0x2d0: 0x0242, 0x2d1: 0x0254,
0x2d2: 0x0230, 0x2d3: 0x444d, 0x2d4: 0x4453, 0x2d5: 0x027e, 0x2d6: 0x026c,
0x2f0: 0x025a, 0x2f1: 0x026f, 0x2f2: 0x0272, 0x2f4: 0x020c, 0x2f5: 0x024b,
0x2f9: 0x022a,
// Block 0xc, offset 0x300
0x300: 0x3862, 0x301: 0x386e, 0x303: 0x385c,
0x306: 0xa000, 0x307: 0x384a,
0x30c: 0x389e, 0x30d: 0x3886, 0x30e: 0x38b0, 0x310: 0xa000,
0x313: 0xa000, 0x315: 0xa000, 0x316: 0xa000, 0x317: 0xa000,
0x318: 0xa000, 0x319: 0x3892, 0x31a: 0xa000,
0x31e: 0xa000, 0x323: 0xa000,
0x327: 0xa000,
0x32b: 0xa000, 0x32d: 0xa000,
0x330: 0xa000, 0x333: 0xa000, 0x335: 0xa000,
0x336: 0xa000, 0x337: 0xa000, 0x338: 0xa000, 0x339: 0x3916, 0x33a: 0xa000,
0x33e: 0xa000,
// Block 0xd, offset 0x340
0x341: 0x3874, 0x342: 0x38f8,
0x350: 0x3850, 0x351: 0x38d4,
0x352: 0x3856, 0x353: 0x38da, 0x356: 0x3868, 0x357: 0x38ec,
0x358: 0xa000, 0x359: 0xa000, 0x35a: 0x396a, 0x35b: 0x3970, 0x35c: 0x387a, 0x35d: 0x38fe,
0x35e: 0x3880, 0x35f: 0x3904, 0x362: 0x388c, 0x363: 0x3910,
0x364: 0x3898, 0x365: 0x391c, 0x366: 0x38a4, 0x367: 0x3928, 0x368: 0xa000, 0x369: 0xa000,
0x36a: 0x3976, 0x36b: 0x397c, 0x36c: 0x38ce, 0x36d: 0x3952, 0x36e: 0x38aa, 0x36f: 0x392e,
0x370: 0x38b6, 0x371: 0x393a, 0x372: 0x38bc, 0x373: 0x3940, 0x374: 0x38c2, 0x375: 0x3946,
0x378: 0x38c8, 0x379: 0x394c,
// Block 0xe, offset 0x380
0x387: 0x1e91,
0x391: 0x812e,
0x392: 0x8133, 0x393: 0x8133, 0x394: 0x8133, 0x395: 0x8133, 0x396: 0x812e, 0x397: 0x8133,
0x398: 0x8133, 0x399: 0x8133, 0x39a: 0x812f, 0x39b: 0x812e, 0x39c: 0x8133, 0x39d: 0x8133,
0x39e: 0x8133, 0x39f: 0x8133, 0x3a0: 0x8133, 0x3a1: 0x8133, 0x3a2: 0x812e, 0x3a3: 0x812e,
0x3a4: 0x812e, 0x3a5: 0x812e, 0x3a6: 0x812e, 0x3a7: 0x812e, 0x3a8: 0x8133, 0x3a9: 0x8133,
0x3aa: 0x812e, 0x3ab: 0x8133, 0x3ac: 0x8133, 0x3ad: 0x812f, 0x3ae: 0x8132, 0x3af: 0x8133,
0x3b0: 0x8106, 0x3b1: 0x8107, 0x3b2: 0x8108, 0x3b3: 0x8109, 0x3b4: 0x810a, 0x3b5: 0x810b,
0x3b6: 0x810c, 0x3b7: 0x810d, 0x3b8: 0x810e, 0x3b9: 0x810f, 0x3ba: 0x810f, 0x3bb: 0x8110,
0x3bc: 0x8111, 0x3bd: 0x8112, 0x3bf: 0x8113,
// Block 0xf, offset 0x3c0
0x3c8: 0xa000, 0x3ca: 0xa000, 0x3cb: 0x8117,
0x3cc: 0x8118, 0x3cd: 0x8119, 0x3ce: 0x811a, 0x3cf: 0x811b, 0x3d0: 0x811c, 0x3d1: 0x811d,
0x3d2: 0x811e, 0x3d3: 0x9933, 0x3d4: 0x9933, 0x3d5: 0x992e, 0x3d6: 0x812e, 0x3d7: 0x8133,
0x3d8: 0x8133, 0x3d9: 0x8133, 0x3da: 0x8133, 0x3db: 0x8133, 0x3dc: 0x812e, 0x3dd: 0x8133,
0x3de: 0x8133, 0x3df: 0x812e,
0x3f0: 0x811f, 0x3f5: 0x1eb4,
0x3f6: 0x2143, 0x3f7: 0x217f, 0x3f8: 0x217a,
// Block 0x10, offset 0x400
0x40a: 0x8133, 0x40b: 0x8133,
0x40c: 0x8133, 0x40d: 0x8133, 0x40e: 0x8133, 0x40f: 0x812e, 0x410: 0x812e, 0x411: 0x812e,
0x412: 0x812e, 0x413: 0x812e, 0x414: 0x8133, 0x415: 0x8133, 0x416: 0x8133, 0x417: 0x8133,
0x418: 0x8133, 0x419: 0x8133, 0x41a: 0x8133, 0x41b: 0x8133, 0x41c: 0x8133, 0x41d: 0x8133,
0x41e: 0x8133, 0x41f: 0x8133, 0x420: 0x8133, 0x421: 0x8133, 0x423: 0x812e,
0x424: 0x8133, 0x425: 0x8133, 0x426: 0x812e, 0x427: 0x8133, 0x428: 0x8133, 0x429: 0x812e,
0x42a: 0x8133, 0x42b: 0x8133, 0x42c: 0x8133, 0x42d: 0x812e, 0x42e: 0x812e, 0x42f: 0x812e,
0x430: 0x8117, 0x431: 0x8118, 0x432: 0x8119, 0x433: 0x8133, 0x434: 0x8133, 0x435: 0x8133,
0x436: 0x812e, 0x437: 0x8133, 0x438: 0x8133, 0x439: 0x812e, 0x43a: 0x812e, 0x43b: 0x8133,
0x43c: 0x8133, 0x43d: 0x8133, 0x43e: 0x8133, 0x43f: 0x8133,
// Block 0x11, offset 0x440
0x445: 0xa000,
0x446: 0x2e5d, 0x447: 0xa000, 0x448: 0x2e65, 0x449: 0xa000, 0x44a: 0x2e6d, 0x44b: 0xa000,
0x44c: 0x2e75, 0x44d: 0xa000, 0x44e: 0x2e7d, 0x451: 0xa000,
0x452: 0x2e85,
0x474: 0x8103, 0x475: 0x9900,
0x47a: 0xa000, 0x47b: 0x2e8d,
0x47c: 0xa000, 0x47d: 0x2e95, 0x47e: 0xa000, 0x47f: 0xa000,
// Block 0x12, offset 0x480
0x480: 0x0069, 0x481: 0x006b, 0x482: 0x006f, 0x483: 0x0083, 0x484: 0x0104, 0x485: 0x0107,
0x486: 0x0506, 0x487: 0x0085, 0x488: 0x0089, 0x489: 0x008b, 0x48a: 0x011f, 0x48b: 0x0122,
0x48c: 0x0125, 0x48d: 0x008f, 0x48f: 0x0097, 0x490: 0x009b, 0x491: 0x00e6,
0x492: 0x009f, 0x493: 0x0110, 0x494: 0x050a, 0x495: 0x050e, 0x496: 0x00a1, 0x497: 0x00a9,
0x498: 0x00ab, 0x499: 0x0516, 0x49a: 0x015b, 0x49b: 0x00ad, 0x49c: 0x051a, 0x49d: 0x0242,
0x49e: 0x0245, 0x49f: 0x0248, 0x4a0: 0x027e, 0x4a1: 0x0281, 0x4a2: 0x0093, 0x4a3: 0x00a5,
0x4a4: 0x00ab, 0x4a5: 0x00ad, 0x4a6: 0x0242, 0x4a7: 0x0245, 0x4a8: 0x026f, 0x4a9: 0x027e,
0x4aa: 0x0281,
0x4b8: 0x02b4,
// Block 0x13, offset 0x4c0
0x4db: 0x010a, 0x4dc: 0x0087, 0x4dd: 0x0113,
0x4de: 0x00d7, 0x4df: 0x0125, 0x4e0: 0x008d, 0x4e1: 0x012b, 0x4e2: 0x0131, 0x4e3: 0x013d,
0x4e4: 0x0146, 0x4e5: 0x0149, 0x4e6: 0x014c, 0x4e7: 0x051e, 0x4e8: 0x01c7, 0x4e9: 0x0155,
0x4ea: 0x0522, 0x4eb: 0x01ca, 0x4ec: 0x0161, 0x4ed: 0x015e, 0x4ee: 0x0164, 0x4ef: 0x0167,
0x4f0: 0x016a, 0x4f1: 0x016d, 0x4f2: 0x0176, 0x4f3: 0x018e, 0x4f4: 0x0191, 0x4f5: 0x00f2,
0x4f6: 0x019a, 0x4f7: 0x019d, 0x4f8: 0x0512, 0x4f9: 0x01a0, 0x4fa: 0x01a3, 0x4fb: 0x00b5,
0x4fc: 0x01af, 0x4fd: 0x01b2, 0x4fe: 0x01b5, 0x4ff: 0x0254,
// Block 0x14, offset 0x500
0x500: 0x8133, 0x501: 0x8133, 0x502: 0x812e, 0x503: 0x8133, 0x504: 0x8133, 0x505: 0x8133,
0x506: 0x8133, 0x507: 0x8133, 0x508: 0x8133, 0x509: 0x8133, 0x50a: 0x812e, 0x50b: 0x8133,
0x50c: 0x8133, 0x50d: 0x8136, 0x50e: 0x812b, 0x50f: 0x812e, 0x510: 0x812a, 0x511: 0x8133,
0x512: 0x8133, 0x513: 0x8133, 0x514: 0x8133, 0x515: 0x8133, 0x516: 0x8133, 0x517: 0x8133,
0x518: 0x8133, 0x519: 0x8133, 0x51a: 0x8133, 0x51b: 0x8133, 0x51c: 0x8133, 0x51d: 0x8133,
0x51e: 0x8133, 0x51f: 0x8133, 0x520: 0x8133, 0x521: 0x8133, 0x522: 0x8133, 0x523: 0x8133,
0x524: 0x8133, 0x525: 0x8133, 0x526: 0x8133, 0x527: 0x8133, 0x528: 0x8133, 0x529: 0x8133,
0x52a: 0x8133, 0x52b: 0x8133, 0x52c: 0x8133, 0x52d: 0x8133, 0x52e: 0x8133, 0x52f: 0x8133,
0x530: 0x8133, 0x531: 0x8133, 0x532: 0x8133, 0x533: 0x8133, 0x534: 0x8133, 0x535: 0x8133,
0x536: 0x8134, 0x537: 0x8132, 0x538: 0x8132, 0x539: 0x812e, 0x53a: 0x812d, 0x53b: 0x8133,
0x53c: 0x8135, 0x53d: 0x812e, 0x53e: 0x8133, 0x53f: 0x812e,
// Block 0x15, offset 0x540
0x540: 0x30d8, 0x541: 0x33e4, 0x542: 0x30e2, 0x543: 0x33ee, 0x544: 0x30e7, 0x545: 0x33f3,
0x546: 0x30ec, 0x547: 0x33f8, 0x548: 0x3a0d, 0x549: 0x3b9c, 0x54a: 0x3105, 0x54b: 0x3411,
0x54c: 0x310f, 0x54d: 0x341b, 0x54e: 0x311e, 0x54f: 0x342a, 0x550: 0x3114, 0x551: 0x3420,
0x552: 0x3119, 0x553: 0x3425, 0x554: 0x3a30, 0x555: 0x3bbf, 0x556: 0x3a37, 0x557: 0x3bc6,
0x558: 0x315a, 0x559: 0x3466, 0x55a: 0x315f, 0x55b: 0x346b, 0x55c: 0x3a45, 0x55d: 0x3bd4,
0x55e: 0x3164, 0x55f: 0x3470, 0x560: 0x3173, 0x561: 0x347f, 0x562: 0x3191, 0x563: 0x349d,
0x564: 0x31a0, 0x565: 0x34ac, 0x566: 0x3196, 0x567: 0x34a2, 0x568: 0x31a5, 0x569: 0x34b1,
0x56a: 0x31aa, 0x56b: 0x34b6, 0x56c: 0x31f0, 0x56d: 0x34fc, 0x56e: 0x3a4c, 0x56f: 0x3bdb,
0x570: 0x31fa, 0x571: 0x350b, 0x572: 0x3204, 0x573: 0x3515, 0x574: 0x320e, 0x575: 0x351f,
0x576: 0x4805, 0x577: 0x4896, 0x578: 0x3a53, 0x579: 0x3be2, 0x57a: 0x3227, 0x57b: 0x3538,
0x57c: 0x3222, 0x57d: 0x3533, 0x57e: 0x322c, 0x57f: 0x353d,
// Block 0x16, offset 0x580
0x580: 0x3231, 0x581: 0x3542, 0x582: 0x3236, 0x583: 0x3547, 0x584: 0x324a, 0x585: 0x355b,
0x586: 0x3254, 0x587: 0x3565, 0x588: 0x3263, 0x589: 0x3574, 0x58a: 0x325e, 0x58b: 0x356f,
0x58c: 0x3a76, 0x58d: 0x3c05, 0x58e: 0x3a84, 0x58f: 0x3c13, 0x590: 0x3a8b, 0x591: 0x3c1a,
0x592: 0x3a92, 0x593: 0x3c21, 0x594: 0x3290, 0x595: 0x35a1, 0x596: 0x3295, 0x597: 0x35a6,
0x598: 0x329f, 0x599: 0x35b0, 0x59a: 0x4832, 0x59b: 0x48c3, 0x59c: 0x3ad8, 0x59d: 0x3c67,
0x59e: 0x32b8, 0x59f: 0x35c9, 0x5a0: 0x32c2, 0x5a1: 0x35d3, 0x5a2: 0x4841, 0x5a3: 0x48d2,
0x5a4: 0x3adf, 0x5a5: 0x3c6e, 0x5a6: 0x3ae6, 0x5a7: 0x3c75, 0x5a8: 0x3aed, 0x5a9: 0x3c7c,
0x5aa: 0x32d1, 0x5ab: 0x35e2, 0x5ac: 0x32db, 0x5ad: 0x35f1, 0x5ae: 0x32ef, 0x5af: 0x3605,
0x5b0: 0x32ea, 0x5b1: 0x3600, 0x5b2: 0x332b, 0x5b3: 0x3641, 0x5b4: 0x333a, 0x5b5: 0x3650,
0x5b6: 0x3335, 0x5b7: 0x364b, 0x5b8: 0x3af4, 0x5b9: 0x3c83, 0x5ba: 0x3afb, 0x5bb: 0x3c8a,
0x5bc: 0x333f, 0x5bd: 0x3655, 0x5be: 0x3344, 0x5bf: 0x365a,
// Block 0x17, offset 0x5c0
0x5c0: 0x3349, 0x5c1: 0x365f, 0x5c2: 0x334e, 0x5c3: 0x3664, 0x5c4: 0x335d, 0x5c5: 0x3673,
0x5c6: 0x3358, 0x5c7: 0x366e, 0x5c8: 0x3362, 0x5c9: 0x367d, 0x5ca: 0x3367, 0x5cb: 0x3682,
0x5cc: 0x336c, 0x5cd: 0x3687, 0x5ce: 0x338a, 0x5cf: 0x36a5, 0x5d0: 0x33a3, 0x5d1: 0x36c3,
0x5d2: 0x33b2, 0x5d3: 0x36d2, 0x5d4: 0x33b7, 0x5d5: 0x36d7, 0x5d6: 0x34bb, 0x5d7: 0x35e7,
0x5d8: 0x3678, 0x5d9: 0x36b4, 0x5da: 0x1d10, 0x5db: 0x4418,
0x5e0: 0x47e2, 0x5e1: 0x4873, 0x5e2: 0x30c4, 0x5e3: 0x33d0,
0x5e4: 0x39b9, 0x5e5: 0x3b48, 0x5e6: 0x39b2, 0x5e7: 0x3b41, 0x5e8: 0x39c7, 0x5e9: 0x3b56,
0x5ea: 0x39c0, 0x5eb: 0x3b4f, 0x5ec: 0x39ff, 0x5ed: 0x3b8e, 0x5ee: 0x39d5, 0x5ef: 0x3b64,
0x5f0: 0x39ce, 0x5f1: 0x3b5d, 0x5f2: 0x39e3, 0x5f3: 0x3b72, 0x5f4: 0x39dc, 0x5f5: 0x3b6b,
0x5f6: 0x3a06, 0x5f7: 0x3b95, 0x5f8: 0x47f6, 0x5f9: 0x4887, 0x5fa: 0x3141, 0x5fb: 0x344d,
0x5fc: 0x312d, 0x5fd: 0x3439, 0x5fe: 0x3a1b, 0x5ff: 0x3baa,
// Block 0x18, offset 0x600
0x600: 0x3a14, 0x601: 0x3ba3, 0x602: 0x3a29, 0x603: 0x3bb8, 0x604: 0x3a22, 0x605: 0x3bb1,
0x606: 0x3a3e, 0x607: 0x3bcd, 0x608: 0x31d2, 0x609: 0x34de, 0x60a: 0x31e6, 0x60b: 0x34f2,
0x60c: 0x4828, 0x60d: 0x48b9, 0x60e: 0x3277, 0x60f: 0x3588, 0x610: 0x3a61, 0x611: 0x3bf0,
0x612: 0x3a5a, 0x613: 0x3be9, 0x614: 0x3a6f, 0x615: 0x3bfe, 0x616: 0x3a68, 0x617: 0x3bf7,
0x618: 0x3aca, 0x619: 0x3c59, 0x61a: 0x3aae, 0x61b: 0x3c3d, 0x61c: 0x3aa7, 0x61d: 0x3c36,
0x61e: 0x3abc, 0x61f: 0x3c4b, 0x620: 0x3ab5, 0x621: 0x3c44, 0x622: 0x3ac3, 0x623: 0x3c52,
0x624: 0x3326, 0x625: 0x363c, 0x626: 0x3308, 0x627: 0x361e, 0x628: 0x3b25, 0x629: 0x3cb4,
0x62a: 0x3b1e, 0x62b: 0x3cad, 0x62c: 0x3b33, 0x62d: 0x3cc2, 0x62e: 0x3b2c, 0x62f: 0x3cbb,
0x630: 0x3b3a, 0x631: 0x3cc9, 0x632: 0x3371, 0x633: 0x368c, 0x634: 0x3399, 0x635: 0x36b9,
0x636: 0x3394, 0x637: 0x36af, 0x638: 0x3380, 0x639: 0x369b,
// Block 0x19, offset 0x640
0x640: 0x4945, 0x641: 0x494b, 0x642: 0x4a5f, 0x643: 0x4a77, 0x644: 0x4a67, 0x645: 0x4a7f,
0x646: 0x4a6f, 0x647: 0x4a87, 0x648: 0x48eb, 0x649: 0x48f1, 0x64a: 0x49cf, 0x64b: 0x49e7,
0x64c: 0x49d7, 0x64d: 0x49ef, 0x64e: 0x49df, 0x64f: 0x49f7, 0x650: 0x4957, 0x651: 0x495d,
0x652: 0x3ef9, 0x653: 0x3f09, 0x654: 0x3f01, 0x655: 0x3f11,
0x658: 0x48f7, 0x659: 0x48fd, 0x65a: 0x3e29, 0x65b: 0x3e39, 0x65c: 0x3e31, 0x65d: 0x3e41,
0x660: 0x496f, 0x661: 0x4975, 0x662: 0x4a8f, 0x663: 0x4aa7,
0x664: 0x4a97, 0x665: 0x4aaf, 0x666: 0x4a9f, 0x667: 0x4ab7, 0x668: 0x4903, 0x669: 0x4909,
0x66a: 0x49ff, 0x66b: 0x4a17, 0x66c: 0x4a07, 0x66d: 0x4a1f, 0x66e: 0x4a0f, 0x66f: 0x4a27,
0x670: 0x4987, 0x671: 0x498d, 0x672: 0x3f59, 0x673: 0x3f71, 0x674: 0x3f61, 0x675: 0x3f79,
0x676: 0x3f69, 0x677: 0x3f81, 0x678: 0x490f, 0x679: 0x4915, 0x67a: 0x3e59, 0x67b: 0x3e71,
0x67c: 0x3e61, 0x67d: 0x3e79, 0x67e: 0x3e69, 0x67f: 0x3e81,
// Block 0x1a, offset 0x680
0x680: 0x4993, 0x681: 0x4999, 0x682: 0x3f89, 0x683: 0x3f99, 0x684: 0x3f91, 0x685: 0x3fa1,
0x688: 0x491b, 0x689: 0x4921, 0x68a: 0x3e89, 0x68b: 0x3e99,
0x68c: 0x3e91, 0x68d: 0x3ea1, 0x690: 0x49a5, 0x691: 0x49ab,
0x692: 0x3fc1, 0x693: 0x3fd9, 0x694: 0x3fc9, 0x695: 0x3fe1, 0x696: 0x3fd1, 0x697: 0x3fe9,
0x699: 0x4927, 0x69b: 0x3ea9, 0x69d: 0x3eb1,
0x69f: 0x3eb9, 0x6a0: 0x49bd, 0x6a1: 0x49c3, 0x6a2: 0x4abf, 0x6a3: 0x4ad7,
0x6a4: 0x4ac7, 0x6a5: 0x4adf, 0x6a6: 0x4acf, 0x6a7: 0x4ae7, 0x6a8: 0x492d, 0x6a9: 0x4933,
0x6aa: 0x4a2f, 0x6ab: 0x4a47, 0x6ac: 0x4a37, 0x6ad: 0x4a4f, 0x6ae: 0x4a3f, 0x6af: 0x4a57,
0x6b0: 0x4939, 0x6b1: 0x445f, 0x6b2: 0x37d2, 0x6b3: 0x4465, 0x6b4: 0x4963, 0x6b5: 0x446b,
0x6b6: 0x37e4, 0x6b7: 0x4471, 0x6b8: 0x3802, 0x6b9: 0x4477, 0x6ba: 0x381a, 0x6bb: 0x447d,
0x6bc: 0x49b1, 0x6bd: 0x4483,
// Block 0x1b, offset 0x6c0
0x6c0: 0x3ee1, 0x6c1: 0x3ee9, 0x6c2: 0x42c5, 0x6c3: 0x42e3, 0x6c4: 0x42cf, 0x6c5: 0x42ed,
0x6c6: 0x42d9, 0x6c7: 0x42f7, 0x6c8: 0x3e19, 0x6c9: 0x3e21, 0x6ca: 0x4211, 0x6cb: 0x422f,
0x6cc: 0x421b, 0x6cd: 0x4239, 0x6ce: 0x4225, 0x6cf: 0x4243, 0x6d0: 0x3f29, 0x6d1: 0x3f31,
0x6d2: 0x4301, 0x6d3: 0x431f, 0x6d4: 0x430b, 0x6d5: 0x4329, 0x6d6: 0x4315, 0x6d7: 0x4333,
0x6d8: 0x3e49, 0x6d9: 0x3e51, 0x6da: 0x424d, 0x6db: 0x426b, 0x6dc: 0x4257, 0x6dd: 0x4275,
0x6de: 0x4261, 0x6df: 0x427f, 0x6e0: 0x4001, 0x6e1: 0x4009, 0x6e2: 0x433d, 0x6e3: 0x435b,
0x6e4: 0x4347, 0x6e5: 0x4365, 0x6e6: 0x4351, 0x6e7: 0x436f, 0x6e8: 0x3ec1, 0x6e9: 0x3ec9,
0x6ea: 0x4289, 0x6eb: 0x42a7, 0x6ec: 0x4293, 0x6ed: 0x42b1, 0x6ee: 0x429d, 0x6ef: 0x42bb,
0x6f0: 0x37c6, 0x6f1: 0x37c0, 0x6f2: 0x3ed1, 0x6f3: 0x37cc, 0x6f4: 0x3ed9,
0x6f6: 0x4951, 0x6f7: 0x3ef1, 0x6f8: 0x3736, 0x6f9: 0x3730, 0x6fa: 0x3724, 0x6fb: 0x442f,
0x6fc: 0x373c, 0x6fd: 0x43c8, 0x6fe: 0x0257, 0x6ff: 0x43c8,
// Block 0x1c, offset 0x700
0x700: 0x43e1, 0x701: 0x45c3, 0x702: 0x3f19, 0x703: 0x37de, 0x704: 0x3f21,
0x706: 0x497b, 0x707: 0x3f39, 0x708: 0x3742, 0x709: 0x4435, 0x70a: 0x374e, 0x70b: 0x443b,
0x70c: 0x375a, 0x70d: 0x45ca, 0x70e: 0x45d1, 0x70f: 0x45d8, 0x710: 0x37f6, 0x711: 0x37f0,
0x712: 0x3f41, 0x713: 0x4625, 0x716: 0x37fc, 0x717: 0x3f51,
0x718: 0x3772, 0x719: 0x376c, 0x71a: 0x3760, 0x71b: 0x4441, 0x71d: 0x45df,
0x71e: 0x45e6, 0x71f: 0x45ed, 0x720: 0x382c, 0x721: 0x3826, 0x722: 0x3fa9, 0x723: 0x462d,
0x724: 0x380e, 0x725: 0x3814, 0x726: 0x3832, 0x727: 0x3fb9, 0x728: 0x37a2, 0x729: 0x379c,
0x72a: 0x3790, 0x72b: 0x444d, 0x72c: 0x378a, 0x72d: 0x45b5, 0x72e: 0x45bc, 0x72f: 0x0081,
0x732: 0x3ff1, 0x733: 0x3838, 0x734: 0x3ff9,
0x736: 0x49c9, 0x737: 0x4011, 0x738: 0x377e, 0x739: 0x4447, 0x73a: 0x37ae, 0x73b: 0x4459,
0x73c: 0x37ba, 0x73d: 0x439b, 0x73e: 0x43cd,
// Block 0x1d, offset 0x740
0x740: 0x1d08, 0x741: 0x1d0c, 0x742: 0x0047, 0x743: 0x1d84, 0x745: 0x1d18,
0x746: 0x1d1c, 0x747: 0x00ef, 0x749: 0x1d88, 0x74a: 0x008f, 0x74b: 0x0051,
0x74c: 0x0051, 0x74d: 0x0051, 0x74e: 0x0091, 0x74f: 0x00e0, 0x750: 0x0053, 0x751: 0x0053,
0x752: 0x0059, 0x753: 0x0099, 0x755: 0x005d, 0x756: 0x1abd,
0x759: 0x0061, 0x75a: 0x0063, 0x75b: 0x0065, 0x75c: 0x0065, 0x75d: 0x0065,
0x760: 0x1acf, 0x761: 0x1cf8, 0x762: 0x1ad8,
0x764: 0x0075, 0x766: 0x023c, 0x768: 0x0075,
0x76a: 0x0057, 0x76b: 0x4413, 0x76c: 0x0045, 0x76d: 0x0047, 0x76f: 0x008b,
0x770: 0x004b, 0x771: 0x004d, 0x773: 0x005b, 0x774: 0x009f, 0x775: 0x0308,
0x776: 0x030b, 0x777: 0x030e, 0x778: 0x0311, 0x779: 0x0093, 0x77b: 0x1cc8,
0x77c: 0x026c, 0x77d: 0x0245, 0x77e: 0x01fd, 0x77f: 0x0224,
// Block 0x1e, offset 0x780
0x780: 0x055a, 0x785: 0x0049,
0x786: 0x0089, 0x787: 0x008b, 0x788: 0x0093, 0x789: 0x0095,
0x790: 0x235e, 0x791: 0x236a,
0x792: 0x241e, 0x793: 0x2346, 0x794: 0x23ca, 0x795: 0x2352, 0x796: 0x23d0, 0x797: 0x23e8,
0x798: 0x23f4, 0x799: 0x2358, 0x79a: 0x23fa, 0x79b: 0x2364, 0x79c: 0x23ee, 0x79d: 0x2400,
0x79e: 0x2406, 0x79f: 0x1dec, 0x7a0: 0x0053, 0x7a1: 0x1a87, 0x7a2: 0x1cd4, 0x7a3: 0x1a90,
0x7a4: 0x006d, 0x7a5: 0x1adb, 0x7a6: 0x1d00, 0x7a7: 0x1e78, 0x7a8: 0x1a93, 0x7a9: 0x0071,
0x7aa: 0x1ae7, 0x7ab: 0x1d04, 0x7ac: 0x0059, 0x7ad: 0x0047, 0x7ae: 0x0049, 0x7af: 0x005b,
0x7b0: 0x0093, 0x7b1: 0x1b14, 0x7b2: 0x1d48, 0x7b3: 0x1b1d, 0x7b4: 0x00ad, 0x7b5: 0x1b92,
0x7b6: 0x1d7c, 0x7b7: 0x1e8c, 0x7b8: 0x1b20, 0x7b9: 0x00b1, 0x7ba: 0x1b95, 0x7bb: 0x1d80,
0x7bc: 0x0099, 0x7bd: 0x0087, 0x7be: 0x0089, 0x7bf: 0x009b,
// Block 0x1f, offset 0x7c0
0x7c1: 0x3d47, 0x7c3: 0xa000, 0x7c4: 0x3d4e, 0x7c5: 0xa000,
0x7c7: 0x3d55, 0x7c8: 0xa000, 0x7c9: 0x3d5c,
0x7cd: 0xa000,
0x7e0: 0x30a6, 0x7e1: 0xa000, 0x7e2: 0x3d6a,
0x7e4: 0xa000, 0x7e5: 0xa000,
0x7ed: 0x3d63, 0x7ee: 0x30a1, 0x7ef: 0x30ab,
0x7f0: 0x3d71, 0x7f1: 0x3d78, 0x7f2: 0xa000, 0x7f3: 0xa000, 0x7f4: 0x3d7f, 0x7f5: 0x3d86,
0x7f6: 0xa000, 0x7f7: 0xa000, 0x7f8: 0x3d8d, 0x7f9: 0x3d94, 0x7fa: 0xa000, 0x7fb: 0xa000,
0x7fc: 0xa000, 0x7fd: 0xa000,
// Block 0x20, offset 0x800
0x800: 0x3d9b, 0x801: 0x3da2, 0x802: 0xa000, 0x803: 0xa000, 0x804: 0x3db7, 0x805: 0x3dbe,
0x806: 0xa000, 0x807: 0xa000, 0x808: 0x3dc5, 0x809: 0x3dcc,
0x811: 0xa000,
0x812: 0xa000,
0x822: 0xa000,
0x828: 0xa000, 0x829: 0xa000,
0x82b: 0xa000, 0x82c: 0x3de1, 0x82d: 0x3de8, 0x82e: 0x3def, 0x82f: 0x3df6,
0x832: 0xa000, 0x833: 0xa000, 0x834: 0xa000, 0x835: 0xa000,
// Block 0x21, offset 0x840
0x860: 0x0023, 0x861: 0x0025, 0x862: 0x0027, 0x863: 0x0029,
0x864: 0x002b, 0x865: 0x002d, 0x866: 0x002f, 0x867: 0x0031, 0x868: 0x0033, 0x869: 0x19af,
0x86a: 0x19b2, 0x86b: 0x19b5, 0x86c: 0x19b8, 0x86d: 0x19bb, 0x86e: 0x19be, 0x86f: 0x19c1,
0x870: 0x19c4, 0x871: 0x19c7, 0x872: 0x19ca, 0x873: 0x19d3, 0x874: 0x1b98, 0x875: 0x1b9c,
0x876: 0x1ba0, 0x877: 0x1ba4, 0x878: 0x1ba8, 0x879: 0x1bac, 0x87a: 0x1bb0, 0x87b: 0x1bb4,
0x87c: 0x1bb8, 0x87d: 0x1db0, 0x87e: 0x1db5, 0x87f: 0x1dba,
// Block 0x22, offset 0x880
0x880: 0x1dbf, 0x881: 0x1dc4, 0x882: 0x1dc9, 0x883: 0x1dce, 0x884: 0x1dd3, 0x885: 0x1dd8,
0x886: 0x1ddd, 0x887: 0x1de2, 0x888: 0x19ac, 0x889: 0x19d0, 0x88a: 0x19f4, 0x88b: 0x1a18,
0x88c: 0x1a3c, 0x88d: 0x1a45, 0x88e: 0x1a4b, 0x88f: 0x1a51, 0x890: 0x1a57, 0x891: 0x1c90,
0x892: 0x1c94, 0x893: 0x1c98, 0x894: 0x1c9c, 0x895: 0x1ca0, 0x896: 0x1ca4, 0x897: 0x1ca8,
0x898: 0x1cac, 0x899: 0x1cb0, 0x89a: 0x1cb4, 0x89b: 0x1cb8, 0x89c: 0x1c24, 0x89d: 0x1c28,
0x89e: 0x1c2c, 0x89f: 0x1c30, 0x8a0: 0x1c34, 0x8a1: 0x1c38, 0x8a2: 0x1c3c, 0x8a3: 0x1c40,
0x8a4: 0x1c44, 0x8a5: 0x1c48, 0x8a6: 0x1c4c, 0x8a7: 0x1c50, 0x8a8: 0x1c54, 0x8a9: 0x1c58,
0x8aa: 0x1c5c, 0x8ab: 0x1c60, 0x8ac: 0x1c64, 0x8ad: 0x1c68, 0x8ae: 0x1c6c, 0x8af: 0x1c70,
0x8b0: 0x1c74, 0x8b1: 0x1c78, 0x8b2: 0x1c7c, 0x8b3: 0x1c80, 0x8b4: 0x1c84, 0x8b5: 0x1c88,
0x8b6: 0x0043, 0x8b7: 0x0045, 0x8b8: 0x0047, 0x8b9: 0x0049, 0x8ba: 0x004b, 0x8bb: 0x004d,
0x8bc: 0x004f, 0x8bd: 0x0051, 0x8be: 0x0053, 0x8bf: 0x0055,
// Block 0x23, offset 0x8c0
0x8c0: 0x07ba, 0x8c1: 0x07de, 0x8c2: 0x07ea, 0x8c3: 0x07fa, 0x8c4: 0x0802, 0x8c5: 0x080e,
0x8c6: 0x0816, 0x8c7: 0x081e, 0x8c8: 0x082a, 0x8c9: 0x087e, 0x8ca: 0x0896, 0x8cb: 0x08a6,
0x8cc: 0x08b6, 0x8cd: 0x08c6, 0x8ce: 0x08d6, 0x8cf: 0x08f6, 0x8d0: 0x08fa, 0x8d1: 0x08fe,
0x8d2: 0x0932, 0x8d3: 0x095a, 0x8d4: 0x096a, 0x8d5: 0x0972, 0x8d6: 0x0976, 0x8d7: 0x0982,
0x8d8: 0x099e, 0x8d9: 0x09a2, 0x8da: 0x09ba, 0x8db: 0x09be, 0x8dc: 0x09c6, 0x8dd: 0x09d6,
0x8de: 0x0a72, 0x8df: 0x0a86, 0x8e0: 0x0ac6, 0x8e1: 0x0ada, 0x8e2: 0x0ae2, 0x8e3: 0x0ae6,
0x8e4: 0x0af6, 0x8e5: 0x0b12, 0x8e6: 0x0b3e, 0x8e7: 0x0b4a, 0x8e8: 0x0b6a, 0x8e9: 0x0b76,
0x8ea: 0x0b7a, 0x8eb: 0x0b7e, 0x8ec: 0x0b96, 0x8ed: 0x0b9a, 0x8ee: 0x0bc6, 0x8ef: 0x0bd2,
0x8f0: 0x0bda, 0x8f1: 0x0be2, 0x8f2: 0x0bf2, 0x8f3: 0x0bfa, 0x8f4: 0x0c02, 0x8f5: 0x0c2e,
0x8f6: 0x0c32, 0x8f7: 0x0c3a, 0x8f8: 0x0c3e, 0x8f9: 0x0c46, 0x8fa: 0x0c4e, 0x8fb: 0x0c5e,
0x8fc: 0x0c7a, 0x8fd: 0x0cf2, 0x8fe: 0x0d06, 0x8ff: 0x0d0a,
// Block 0x24, offset 0x900
0x900: 0x0d8a, 0x901: 0x0d8e, 0x902: 0x0da2, 0x903: 0x0da6, 0x904: 0x0dae, 0x905: 0x0db6,
0x906: 0x0dbe, 0x907: 0x0dca, 0x908: 0x0df2, 0x909: 0x0e02, 0x90a: 0x0e16, 0x90b: 0x0e86,
0x90c: 0x0e92, 0x90d: 0x0ea2, 0x90e: 0x0eae, 0x90f: 0x0eba, 0x910: 0x0ec2, 0x911: 0x0ec6,
0x912: 0x0eca, 0x913: 0x0ece, 0x914: 0x0ed2, 0x915: 0x0f8a, 0x916: 0x0fd2, 0x917: 0x0fde,
0x918: 0x0fe2, 0x919: 0x0fe6, 0x91a: 0x0fea, 0x91b: 0x0ff2, 0x91c: 0x0ff6, 0x91d: 0x100a,
0x91e: 0x1026, 0x91f: 0x102e, 0x920: 0x106e, 0x921: 0x1072, 0x922: 0x107a, 0x923: 0x107e,
0x924: 0x1086, 0x925: 0x108a, 0x926: 0x10ae, 0x927: 0x10b2, 0x928: 0x10ce, 0x929: 0x10d2,
0x92a: 0x10d6, 0x92b: 0x10da, 0x92c: 0x10ee, 0x92d: 0x1112, 0x92e: 0x1116, 0x92f: 0x111a,
0x930: 0x113e, 0x931: 0x117e, 0x932: 0x1182, 0x933: 0x11a2, 0x934: 0x11b2, 0x935: 0x11ba,
0x936: 0x11da, 0x937: 0x11fe, 0x938: 0x1242, 0x939: 0x124a, 0x93a: 0x125e, 0x93b: 0x126a,
0x93c: 0x1272, 0x93d: 0x127a, 0x93e: 0x127e, 0x93f: 0x1282,
// Block 0x25, offset 0x940
0x940: 0x129a, 0x941: 0x129e, 0x942: 0x12ba, 0x943: 0x12c2, 0x944: 0x12ca, 0x945: 0x12ce,
0x946: 0x12da, 0x947: 0x12e2, 0x948: 0x12e6, 0x949: 0x12ea, 0x94a: 0x12f2, 0x94b: 0x12f6,
0x94c: 0x1396, 0x94d: 0x13aa, 0x94e: 0x13de, 0x94f: 0x13e2, 0x950: 0x13ea, 0x951: 0x1416,
0x952: 0x141e, 0x953: 0x1426, 0x954: 0x142e, 0x955: 0x146a, 0x956: 0x146e, 0x957: 0x1476,
0x958: 0x147a, 0x959: 0x147e, 0x95a: 0x14aa, 0x95b: 0x14ae, 0x95c: 0x14b6, 0x95d: 0x14ca,
0x95e: 0x14ce, 0x95f: 0x14ea, 0x960: 0x14f2, 0x961: 0x14f6, 0x962: 0x151a, 0x963: 0x153a,
0x964: 0x154e, 0x965: 0x1552, 0x966: 0x155a, 0x967: 0x1586, 0x968: 0x158a, 0x969: 0x159a,
0x96a: 0x15be, 0x96b: 0x15ca, 0x96c: 0x15da, 0x96d: 0x15f2, 0x96e: 0x15fa, 0x96f: 0x15fe,
0x970: 0x1602, 0x971: 0x1606, 0x972: 0x1612, 0x973: 0x1616, 0x974: 0x161e, 0x975: 0x163a,
0x976: 0x163e, 0x977: 0x1642, 0x978: 0x165a, 0x979: 0x165e, 0x97a: 0x1666, 0x97b: 0x167a,
0x97c: 0x167e, 0x97d: 0x1682, 0x97e: 0x168a, 0x97f: 0x168e,
// Block 0x26, offset 0x980
0x986: 0xa000, 0x98b: 0xa000,
0x98c: 0x4049, 0x98d: 0xa000, 0x98e: 0x4051, 0x98f: 0xa000, 0x990: 0x4059, 0x991: 0xa000,
0x992: 0x4061, 0x993: 0xa000, 0x994: 0x4069, 0x995: 0xa000, 0x996: 0x4071, 0x997: 0xa000,
0x998: 0x4079, 0x999: 0xa000, 0x99a: 0x4081, 0x99b: 0xa000, 0x99c: 0x4089, 0x99d: 0xa000,
0x99e: 0x4091, 0x99f: 0xa000, 0x9a0: 0x4099, 0x9a1: 0xa000, 0x9a2: 0x40a1,
0x9a4: 0xa000, 0x9a5: 0x40a9, 0x9a6: 0xa000, 0x9a7: 0x40b1, 0x9a8: 0xa000, 0x9a9: 0x40b9,
0x9af: 0xa000,
0x9b0: 0x40c1, 0x9b1: 0x40c9, 0x9b2: 0xa000, 0x9b3: 0x40d1, 0x9b4: 0x40d9, 0x9b5: 0xa000,
0x9b6: 0x40e1, 0x9b7: 0x40e9, 0x9b8: 0xa000, 0x9b9: 0x40f1, 0x9ba: 0x40f9, 0x9bb: 0xa000,
0x9bc: 0x4101, 0x9bd: 0x4109,
// Block 0x27, offset 0x9c0
0x9d4: 0x4041,
0x9d9: 0x9904, 0x9da: 0x9904, 0x9db: 0x441d, 0x9dc: 0x4423, 0x9dd: 0xa000,
0x9de: 0x4111, 0x9df: 0x27e4,
0x9e6: 0xa000,
0x9eb: 0xa000, 0x9ec: 0x4121, 0x9ed: 0xa000, 0x9ee: 0x4129, 0x9ef: 0xa000,
0x9f0: 0x4131, 0x9f1: 0xa000, 0x9f2: 0x4139, 0x9f3: 0xa000, 0x9f4: 0x4141, 0x9f5: 0xa000,
0x9f6: 0x4149, 0x9f7: 0xa000, 0x9f8: 0x4151, 0x9f9: 0xa000, 0x9fa: 0x4159, 0x9fb: 0xa000,
0x9fc: 0x4161, 0x9fd: 0xa000, 0x9fe: 0x4169, 0x9ff: 0xa000,
// Block 0x28, offset 0xa00
0xa00: 0x4171, 0xa01: 0xa000, 0xa02: 0x4179, 0xa04: 0xa000, 0xa05: 0x4181,
0xa06: 0xa000, 0xa07: 0x4189, 0xa08: 0xa000, 0xa09: 0x4191,
0xa0f: 0xa000, 0xa10: 0x4199, 0xa11: 0x41a1,
0xa12: 0xa000, 0xa13: 0x41a9, 0xa14: 0x41b1, 0xa15: 0xa000, 0xa16: 0x41b9, 0xa17: 0x41c1,
0xa18: 0xa000, 0xa19: 0x41c9, 0xa1a: 0x41d1, 0xa1b: 0xa000, 0xa1c: 0x41d9, 0xa1d: 0x41e1,
0xa2f: 0xa000,
0xa30: 0xa000, 0xa31: 0xa000, 0xa32: 0xa000, 0xa34: 0x4119,
0xa37: 0x41e9, 0xa38: 0x41f1, 0xa39: 0x41f9, 0xa3a: 0x4201,
0xa3d: 0xa000, 0xa3e: 0x4209, 0xa3f: 0x27f9,
// Block 0x29, offset 0xa40
0xa40: 0x045a, 0xa41: 0x041e, 0xa42: 0x0422, 0xa43: 0x0426, 0xa44: 0x046e, 0xa45: 0x042a,
0xa46: 0x042e, 0xa47: 0x0432, 0xa48: 0x0436, 0xa49: 0x043a, 0xa4a: 0x043e, 0xa4b: 0x0442,
0xa4c: 0x0446, 0xa4d: 0x044a, 0xa4e: 0x044e, 0xa4f: 0x4afe, 0xa50: 0x4b04, 0xa51: 0x4b0a,
0xa52: 0x4b10, 0xa53: 0x4b16, 0xa54: 0x4b1c, 0xa55: 0x4b22, 0xa56: 0x4b28, 0xa57: 0x4b2e,
0xa58: 0x4b34, 0xa59: 0x4b3a, 0xa5a: 0x4b40, 0xa5b: 0x4b46, 0xa5c: 0x4b4c, 0xa5d: 0x4b52,
0xa5e: 0x4b58, 0xa5f: 0x4b5e, 0xa60: 0x4b64, 0xa61: 0x4b6a, 0xa62: 0x4b70, 0xa63: 0x4b76,
0xa64: 0x04b6, 0xa65: 0x0452, 0xa66: 0x0456, 0xa67: 0x04da, 0xa68: 0x04de, 0xa69: 0x04e2,
0xa6a: 0x04e6, 0xa6b: 0x04ea, 0xa6c: 0x04ee, 0xa6d: 0x04f2, 0xa6e: 0x045e, 0xa6f: 0x04f6,
0xa70: 0x04fa, 0xa71: 0x0462, 0xa72: 0x0466, 0xa73: 0x046a, 0xa74: 0x0472, 0xa75: 0x0476,
0xa76: 0x047a, 0xa77: 0x047e, 0xa78: 0x0482, 0xa79: 0x0486, 0xa7a: 0x048a, 0xa7b: 0x048e,
0xa7c: 0x0492, 0xa7d: 0x0496, 0xa7e: 0x049a, 0xa7f: 0x049e,
// Block 0x2a, offset 0xa80
0xa80: 0x04a2, 0xa81: 0x04a6, 0xa82: 0x04fe, 0xa83: 0x0502, 0xa84: 0x04aa, 0xa85: 0x04ae,
0xa86: 0x04b2, 0xa87: 0x04ba, 0xa88: 0x04be, 0xa89: 0x04c2, 0xa8a: 0x04c6, 0xa8b: 0x04ca,
0xa8c: 0x04ce, 0xa8d: 0x04d2, 0xa8e: 0x04d6,
0xa92: 0x07ba, 0xa93: 0x0816, 0xa94: 0x07c6, 0xa95: 0x0a76, 0xa96: 0x07ca, 0xa97: 0x07e2,
0xa98: 0x07ce, 0xa99: 0x108e, 0xa9a: 0x0802, 0xa9b: 0x07d6, 0xa9c: 0x07be, 0xa9d: 0x0afa,
0xa9e: 0x0a8a, 0xa9f: 0x082a,
// Block 0x2b, offset 0xac0
0xac0: 0x2184, 0xac1: 0x218a, 0xac2: 0x2190, 0xac3: 0x2196, 0xac4: 0x219c, 0xac5: 0x21a2,
0xac6: 0x21a8, 0xac7: 0x21ae, 0xac8: 0x21b4, 0xac9: 0x21ba, 0xaca: 0x21c0, 0xacb: 0x21c6,
0xacc: 0x21cc, 0xacd: 0x21d2, 0xace: 0x285d, 0xacf: 0x2866, 0xad0: 0x286f, 0xad1: 0x2878,
0xad2: 0x2881, 0xad3: 0x288a, 0xad4: 0x2893, 0xad5: 0x289c, 0xad6: 0x28a5, 0xad7: 0x28b7,
0xad8: 0x28c0, 0xad9: 0x28c9, 0xada: 0x28d2, 0xadb: 0x28db, 0xadc: 0x28ae, 0xadd: 0x2ce3,
0xade: 0x2c24, 0xae0: 0x21d8, 0xae1: 0x21f0, 0xae2: 0x21e4, 0xae3: 0x2238,
0xae4: 0x21f6, 0xae5: 0x2214, 0xae6: 0x21de, 0xae7: 0x220e, 0xae8: 0x21ea, 0xae9: 0x2220,
0xaea: 0x2250, 0xaeb: 0x226e, 0xaec: 0x2268, 0xaed: 0x225c, 0xaee: 0x22aa, 0xaef: 0x223e,
0xaf0: 0x224a, 0xaf1: 0x2262, 0xaf2: 0x2256, 0xaf3: 0x2280, 0xaf4: 0x222c, 0xaf5: 0x2274,
0xaf6: 0x229e, 0xaf7: 0x2286, 0xaf8: 0x221a, 0xaf9: 0x21fc, 0xafa: 0x2232, 0xafb: 0x2244,
0xafc: 0x227a, 0xafd: 0x2202, 0xafe: 0x22a4, 0xaff: 0x2226,
// Block 0x2c, offset 0xb00
0xb00: 0x228c, 0xb01: 0x2208, 0xb02: 0x2292, 0xb03: 0x2298, 0xb04: 0x0a2a, 0xb05: 0x0bfe,
0xb06: 0x0da2, 0xb07: 0x11c2,
0xb10: 0x1cf4, 0xb11: 0x19d6,
0xb12: 0x19d9, 0xb13: 0x19dc, 0xb14: 0x19df, 0xb15: 0x19e2, 0xb16: 0x19e5, 0xb17: 0x19e8,
0xb18: 0x19eb, 0xb19: 0x19ee, 0xb1a: 0x19f7, 0xb1b: 0x19fa, 0xb1c: 0x19fd, 0xb1d: 0x1a00,
0xb1e: 0x1a03, 0xb1f: 0x1a06, 0xb20: 0x0406, 0xb21: 0x040e, 0xb22: 0x0412, 0xb23: 0x041a,
0xb24: 0x041e, 0xb25: 0x0422, 0xb26: 0x042a, 0xb27: 0x0432, 0xb28: 0x0436, 0xb29: 0x043e,
0xb2a: 0x0442, 0xb2b: 0x0446, 0xb2c: 0x044a, 0xb2d: 0x044e, 0xb2e: 0x2f59, 0xb2f: 0x2f61,
0xb30: 0x2f69, 0xb31: 0x2f71, 0xb32: 0x2f79, 0xb33: 0x2f81, 0xb34: 0x2f89, 0xb35: 0x2f91,
0xb36: 0x2fa1, 0xb37: 0x2fa9, 0xb38: 0x2fb1, 0xb39: 0x2fb9, 0xb3a: 0x2fc1, 0xb3b: 0x2fc9,
0xb3c: 0x3014, 0xb3d: 0x2fdc, 0xb3e: 0x2f99,
// Block 0x2d, offset 0xb40
0xb40: 0x07ba, 0xb41: 0x0816, 0xb42: 0x07c6, 0xb43: 0x0a76, 0xb44: 0x081a, 0xb45: 0x08aa,
0xb46: 0x07c2, 0xb47: 0x08a6, 0xb48: 0x0806, 0xb49: 0x0982, 0xb4a: 0x0e02, 0xb4b: 0x0f8a,
0xb4c: 0x0ed2, 0xb4d: 0x0e16, 0xb4e: 0x155a, 0xb4f: 0x0a86, 0xb50: 0x0dca, 0xb51: 0x0e46,
0xb52: 0x0e06, 0xb53: 0x1146, 0xb54: 0x09f6, 0xb55: 0x0ffe, 0xb56: 0x1482, 0xb57: 0x115a,
0xb58: 0x093e, 0xb59: 0x118a, 0xb5a: 0x1096, 0xb5b: 0x0b12, 0xb5c: 0x150a, 0xb5d: 0x087a,
0xb5e: 0x09a6, 0xb5f: 0x0ef2, 0xb60: 0x1622, 0xb61: 0x083e, 0xb62: 0x08ce, 0xb63: 0x0e96,
0xb64: 0x07ca, 0xb65: 0x07e2, 0xb66: 0x07ce, 0xb67: 0x0bd6, 0xb68: 0x09ea, 0xb69: 0x097a,
0xb6a: 0x0b52, 0xb6b: 0x0b46, 0xb6c: 0x10e6, 0xb6d: 0x083a, 0xb6e: 0x1496, 0xb6f: 0x0996,
0xb70: 0x0aee, 0xb71: 0x1a09, 0xb72: 0x1a0c, 0xb73: 0x1a0f, 0xb74: 0x1a12, 0xb75: 0x1a1b,
0xb76: 0x1a1e, 0xb77: 0x1a21, 0xb78: 0x1a24, 0xb79: 0x1a27, 0xb7a: 0x1a2a, 0xb7b: 0x1a2d,
0xb7c: 0x1a30, 0xb7d: 0x1a33, 0xb7e: 0x1a36, 0xb7f: 0x1a3f,
// Block 0x2e, offset 0xb80
0xb80: 0x1df6, 0xb81: 0x1e05, 0xb82: 0x1e14, 0xb83: 0x1e23, 0xb84: 0x1e32, 0xb85: 0x1e41,
0xb86: 0x1e50, 0xb87: 0x1e5f, 0xb88: 0x1e6e, 0xb89: 0x22bc, 0xb8a: 0x22ce, 0xb8b: 0x22e0,
0xb8c: 0x1a81, 0xb8d: 0x1d34, 0xb8e: 0x1b02, 0xb8f: 0x1cd8, 0xb90: 0x05c6, 0xb91: 0x05ce,
0xb92: 0x05d6, 0xb93: 0x05de, 0xb94: 0x05e6, 0xb95: 0x05ea, 0xb96: 0x05ee, 0xb97: 0x05f2,
0xb98: 0x05f6, 0xb99: 0x05fa, 0xb9a: 0x05fe, 0xb9b: 0x0602, 0xb9c: 0x0606, 0xb9d: 0x060a,
0xb9e: 0x060e, 0xb9f: 0x0612, 0xba0: 0x0616, 0xba1: 0x061e, 0xba2: 0x0622, 0xba3: 0x0626,
0xba4: 0x062a, 0xba5: 0x062e, 0xba6: 0x0632, 0xba7: 0x0636, 0xba8: 0x063a, 0xba9: 0x063e,
0xbaa: 0x0642, 0xbab: 0x0646, 0xbac: 0x064a, 0xbad: 0x064e, 0xbae: 0x0652, 0xbaf: 0x0656,
0xbb0: 0x065a, 0xbb1: 0x065e, 0xbb2: 0x0662, 0xbb3: 0x066a, 0xbb4: 0x0672, 0xbb5: 0x067a,
0xbb6: 0x067e, 0xbb7: 0x0682, 0xbb8: 0x0686, 0xbb9: 0x068a, 0xbba: 0x068e, 0xbbb: 0x0692,
0xbbc: 0x0696, 0xbbd: 0x069a, 0xbbe: 0x069e, 0xbbf: 0x282a,
// Block 0x2f, offset 0xbc0
0xbc0: 0x2c43, 0xbc1: 0x2adf, 0xbc2: 0x2c53, 0xbc3: 0x29b7, 0xbc4: 0x3025, 0xbc5: 0x29c1,
0xbc6: 0x29cb, 0xbc7: 0x3069, 0xbc8: 0x2aec, 0xbc9: 0x29d5, 0xbca: 0x29df, 0xbcb: 0x29e9,
0xbcc: 0x2b13, 0xbcd: 0x2b20, 0xbce: 0x2af9, 0xbcf: 0x2b06, 0xbd0: 0x2fea, 0xbd1: 0x2b2d,
0xbd2: 0x2b3a, 0xbd3: 0x2cf5, 0xbd4: 0x27eb, 0xbd5: 0x2d08, 0xbd6: 0x2d1b, 0xbd7: 0x2c63,
0xbd8: 0x2b47, 0xbd9: 0x2d2e, 0xbda: 0x2d41, 0xbdb: 0x2b54, 0xbdc: 0x29f3, 0xbdd: 0x29fd,
0xbde: 0x2ff8, 0xbdf: 0x2b61, 0xbe0: 0x2c73, 0xbe1: 0x3036, 0xbe2: 0x2a07, 0xbe3: 0x2a11,
0xbe4: 0x2b6e, 0xbe5: 0x2a1b, 0xbe6: 0x2a25, 0xbe7: 0x2800, 0xbe8: 0x2807, 0xbe9: 0x2a2f,
0xbea: 0x2a39, 0xbeb: 0x2d54, 0xbec: 0x2b7b, 0xbed: 0x2c83, 0xbee: 0x2d67, 0xbef: 0x2b88,
0xbf0: 0x2a4d, 0xbf1: 0x2a43, 0xbf2: 0x307d, 0xbf3: 0x2b95, 0xbf4: 0x2d7a, 0xbf5: 0x2a57,
0xbf6: 0x2c93, 0xbf7: 0x2a61, 0xbf8: 0x2baf, 0xbf9: 0x2a6b, 0xbfa: 0x2bbc, 0xbfb: 0x3047,
0xbfc: 0x2ba2, 0xbfd: 0x2ca3, 0xbfe: 0x2bc9, 0xbff: 0x280e,
// Block 0x30, offset 0xc00
0xc00: 0x3058, 0xc01: 0x2a75, 0xc02: 0x2a7f, 0xc03: 0x2bd6, 0xc04: 0x2a89, 0xc05: 0x2a93,
0xc06: 0x2a9d, 0xc07: 0x2cb3, 0xc08: 0x2be3, 0xc09: 0x2815, 0xc0a: 0x2d8d, 0xc0b: 0x2fd1,
0xc0c: 0x2cc3, 0xc0d: 0x2bf0, 0xc0e: 0x3006, 0xc0f: 0x2aa7, 0xc10: 0x2ab1, 0xc11: 0x2bfd,
0xc12: 0x281c, 0xc13: 0x2c0a, 0xc14: 0x2cd3, 0xc15: 0x2823, 0xc16: 0x2da0, 0xc17: 0x2abb,
0xc18: 0x1de7, 0xc19: 0x1dfb, 0xc1a: 0x1e0a, 0xc1b: 0x1e19, 0xc1c: 0x1e28, 0xc1d: 0x1e37,
0xc1e: 0x1e46, 0xc1f: 0x1e55, 0xc20: 0x1e64, 0xc21: 0x1e73, 0xc22: 0x22c2, 0xc23: 0x22d4,
0xc24: 0x22e6, 0xc25: 0x22f2, 0xc26: 0x22fe, 0xc27: 0x230a, 0xc28: 0x2316, 0xc29: 0x2322,
0xc2a: 0x232e, 0xc2b: 0x233a, 0xc2c: 0x2376, 0xc2d: 0x2382, 0xc2e: 0x238e, 0xc2f: 0x239a,
0xc30: 0x23a6, 0xc31: 0x1d44, 0xc32: 0x1af6, 0xc33: 0x1a63, 0xc34: 0x1d14, 0xc35: 0x1b77,
0xc36: 0x1b86, 0xc37: 0x1afc, 0xc38: 0x1d2c, 0xc39: 0x1d30, 0xc3a: 0x1a8d, 0xc3b: 0x2838,
0xc3c: 0x2846, 0xc3d: 0x2831, 0xc3e: 0x283f, 0xc3f: 0x2c17,
// Block 0x31, offset 0xc40
0xc40: 0x1b7a, 0xc41: 0x1b62, 0xc42: 0x1d90, 0xc43: 0x1b4a, 0xc44: 0x1b23, 0xc45: 0x1a96,
0xc46: 0x1aa5, 0xc47: 0x1a75, 0xc48: 0x1d20, 0xc49: 0x1e82, 0xc4a: 0x1b7d, 0xc4b: 0x1b65,
0xc4c: 0x1d94, 0xc4d: 0x1da0, 0xc4e: 0x1b56, 0xc4f: 0x1b2c, 0xc50: 0x1a84, 0xc51: 0x1d4c,
0xc52: 0x1ce0, 0xc53: 0x1ccc, 0xc54: 0x1cfc, 0xc55: 0x1da4, 0xc56: 0x1b59, 0xc57: 0x1af9,
0xc58: 0x1b2f, 0xc59: 0x1b0e, 0xc5a: 0x1b71, 0xc5b: 0x1da8, 0xc5c: 0x1b5c, 0xc5d: 0x1af0,
0xc5e: 0x1b32, 0xc5f: 0x1d6c, 0xc60: 0x1d24, 0xc61: 0x1b44, 0xc62: 0x1d54, 0xc63: 0x1d70,
0xc64: 0x1d28, 0xc65: 0x1b47, 0xc66: 0x1d58, 0xc67: 0x2418, 0xc68: 0x242c, 0xc69: 0x1ac6,
0xc6a: 0x1d50, 0xc6b: 0x1ce4, 0xc6c: 0x1cd0, 0xc6d: 0x1d78, 0xc6e: 0x284d, 0xc6f: 0x28e4,
0xc70: 0x1b89, 0xc71: 0x1b74, 0xc72: 0x1dac, 0xc73: 0x1b5f, 0xc74: 0x1b80, 0xc75: 0x1b68,
0xc76: 0x1d98, 0xc77: 0x1b4d, 0xc78: 0x1b26, 0xc79: 0x1ab1, 0xc7a: 0x1b83, 0xc7b: 0x1b6b,
0xc7c: 0x1d9c, 0xc7d: 0x1b50, 0xc7e: 0x1b29, 0xc7f: 0x1ab4,
// Block 0x32, offset 0xc80
0xc80: 0x1d5c, 0xc81: 0x1ce8, 0xc82: 0x1e7d, 0xc83: 0x1a66, 0xc84: 0x1aea, 0xc85: 0x1aed,
0xc86: 0x2425, 0xc87: 0x1cc4, 0xc88: 0x1af3, 0xc89: 0x1a78, 0xc8a: 0x1b11, 0xc8b: 0x1a7b,
0xc8c: 0x1b1a, 0xc8d: 0x1a99, 0xc8e: 0x1a9c, 0xc8f: 0x1b35, 0xc90: 0x1b3b, 0xc91: 0x1b3e,
0xc92: 0x1d60, 0xc93: 0x1b41, 0xc94: 0x1b53, 0xc95: 0x1d68, 0xc96: 0x1d74, 0xc97: 0x1ac0,
0xc98: 0x1e87, 0xc99: 0x1cec, 0xc9a: 0x1ac3, 0xc9b: 0x1b8c, 0xc9c: 0x1ad5, 0xc9d: 0x1ae4,
0xc9e: 0x2412, 0xc9f: 0x240c, 0xca0: 0x1df1, 0xca1: 0x1e00, 0xca2: 0x1e0f, 0xca3: 0x1e1e,
0xca4: 0x1e2d, 0xca5: 0x1e3c, 0xca6: 0x1e4b, 0xca7: 0x1e5a, 0xca8: 0x1e69, 0xca9: 0x22b6,
0xcaa: 0x22c8, 0xcab: 0x22da, 0xcac: 0x22ec, 0xcad: 0x22f8, 0xcae: 0x2304, 0xcaf: 0x2310,
0xcb0: 0x231c, 0xcb1: 0x2328, 0xcb2: 0x2334, 0xcb3: 0x2370, 0xcb4: 0x237c, 0xcb5: 0x2388,
0xcb6: 0x2394, 0xcb7: 0x23a0, 0xcb8: 0x23ac, 0xcb9: 0x23b2, 0xcba: 0x23b8, 0xcbb: 0x23be,
0xcbc: 0x23c4, 0xcbd: 0x23d6, 0xcbe: 0x23dc, 0xcbf: 0x1d40,
// Block 0x33, offset 0xcc0
0xcc0: 0x1472, 0xcc1: 0x0df6, 0xcc2: 0x14ce, 0xcc3: 0x149a, 0xcc4: 0x0f52, 0xcc5: 0x07e6,
0xcc6: 0x09da, 0xcc7: 0x1726, 0xcc8: 0x1726, 0xcc9: 0x0b06, 0xcca: 0x155a, 0xccb: 0x0a3e,
0xccc: 0x0b02, 0xccd: 0x0cea, 0xcce: 0x10ca, 0xccf: 0x125a, 0xcd0: 0x1392, 0xcd1: 0x13ce,
0xcd2: 0x1402, 0xcd3: 0x1516, 0xcd4: 0x0e6e, 0xcd5: 0x0efa, 0xcd6: 0x0fa6, 0xcd7: 0x103e,
0xcd8: 0x135a, 0xcd9: 0x1542, 0xcda: 0x166e, 0xcdb: 0x080a, 0xcdc: 0x09ae, 0xcdd: 0x0e82,
0xcde: 0x0fca, 0xcdf: 0x138e, 0xce0: 0x16be, 0xce1: 0x0bae, 0xce2: 0x0f72, 0xce3: 0x137e,
0xce4: 0x1412, 0xce5: 0x0d1e, 0xce6: 0x12b6, 0xce7: 0x13da, 0xce8: 0x0c1a, 0xce9: 0x0e0a,
0xcea: 0x0f12, 0xceb: 0x1016, 0xcec: 0x1522, 0xced: 0x084a, 0xcee: 0x08e2, 0xcef: 0x094e,
0xcf0: 0x0d86, 0xcf1: 0x0e7a, 0xcf2: 0x0fc6, 0xcf3: 0x10ea, 0xcf4: 0x1272, 0xcf5: 0x1386,
0xcf6: 0x139e, 0xcf7: 0x14c2, 0xcf8: 0x15ea, 0xcf9: 0x169e, 0xcfa: 0x16ba, 0xcfb: 0x1126,
0xcfc: 0x1166, 0xcfd: 0x121e, 0xcfe: 0x133e, 0xcff: 0x1576,
// Block 0x34, offset 0xd00
0xd00: 0x16c6, 0xd01: 0x1446, 0xd02: 0x0ac2, 0xd03: 0x0c36, 0xd04: 0x11d6, 0xd05: 0x1296,
0xd06: 0x0ffa, 0xd07: 0x112e, 0xd08: 0x1492, 0xd09: 0x15e2, 0xd0a: 0x0abe, 0xd0b: 0x0b8a,
0xd0c: 0x0e72, 0xd0d: 0x0f26, 0xd0e: 0x0f5a, 0xd0f: 0x120e, 0xd10: 0x1236, 0xd11: 0x15a2,
0xd12: 0x094a, 0xd13: 0x12a2, 0xd14: 0x08ee, 0xd15: 0x08ea, 0xd16: 0x1192, 0xd17: 0x1222,
0xd18: 0x1356, 0xd19: 0x15aa, 0xd1a: 0x1462, 0xd1b: 0x0d22, 0xd1c: 0x0e6e, 0xd1d: 0x1452,
0xd1e: 0x07f2, 0xd1f: 0x0b5e, 0xd20: 0x0c8e, 0xd21: 0x102a, 0xd22: 0x10aa, 0xd23: 0x096e,
0xd24: 0x1136, 0xd25: 0x085a, 0xd26: 0x0c72, 0xd27: 0x07d2, 0xd28: 0x0ee6, 0xd29: 0x0d9e,
0xd2a: 0x120a, 0xd2b: 0x09c2, 0xd2c: 0x0aae, 0xd2d: 0x10f6, 0xd2e: 0x135e, 0xd2f: 0x1436,
0xd30: 0x0eb2, 0xd31: 0x14f2, 0xd32: 0x0ede, 0xd33: 0x0d32, 0xd34: 0x1316, 0xd35: 0x0d52,
0xd36: 0x10a6, 0xd37: 0x0826, 0xd38: 0x08a2, 0xd39: 0x08e6, 0xd3a: 0x0e4e, 0xd3b: 0x11f6,
0xd3c: 0x12ee, 0xd3d: 0x1442, 0xd3e: 0x1556, 0xd3f: 0x0956,
// Block 0x35, offset 0xd40
0xd40: 0x0a0a, 0xd41: 0x0b12, 0xd42: 0x0c2a, 0xd43: 0x0dba, 0xd44: 0x0f76, 0xd45: 0x113a,
0xd46: 0x1592, 0xd47: 0x1676, 0xd48: 0x16ca, 0xd49: 0x16e2, 0xd4a: 0x0932, 0xd4b: 0x0dee,
0xd4c: 0x0e9e, 0xd4d: 0x14e6, 0xd4e: 0x0bf6, 0xd4f: 0x0cd2, 0xd50: 0x0cee, 0xd51: 0x0d7e,
0xd52: 0x0f66, 0xd53: 0x0fb2, 0xd54: 0x1062, 0xd55: 0x1186, 0xd56: 0x122a, 0xd57: 0x128e,
0xd58: 0x14d6, 0xd59: 0x1366, 0xd5a: 0x14fe, 0xd5b: 0x157a, 0xd5c: 0x090a, 0xd5d: 0x0936,
0xd5e: 0x0a1e, 0xd5f: 0x0fa2, 0xd60: 0x13ee, 0xd61: 0x1436, 0xd62: 0x0c16, 0xd63: 0x0c86,
0xd64: 0x0d4a, 0xd65: 0x0eaa, 0xd66: 0x11d2, 0xd67: 0x101e, 0xd68: 0x0836, 0xd69: 0x0a7a,
0xd6a: 0x0b5e, 0xd6b: 0x0bc2, 0xd6c: 0x0c92, 0xd6d: 0x103a, 0xd6e: 0x1056, 0xd6f: 0x1266,
0xd70: 0x1286, 0xd71: 0x155e, 0xd72: 0x15de, 0xd73: 0x15ee, 0xd74: 0x162a, 0xd75: 0x084e,
0xd76: 0x117a, 0xd77: 0x154a, 0xd78: 0x15c6, 0xd79: 0x0caa, 0xd7a: 0x0812, 0xd7b: 0x0872,
0xd7c: 0x0b62, 0xd7d: 0x0b82, 0xd7e: 0x0daa, 0xd7f: 0x0e6e,
// Block 0x36, offset 0xd80
0xd80: 0x0fbe, 0xd81: 0x10c6, 0xd82: 0x1372, 0xd83: 0x1512, 0xd84: 0x171e, 0xd85: 0x0dde,
0xd86: 0x159e, 0xd87: 0x092e, 0xd88: 0x0e2a, 0xd89: 0x0e36, 0xd8a: 0x0f0a, 0xd8b: 0x0f42,
0xd8c: 0x1046, 0xd8d: 0x10a2, 0xd8e: 0x1122, 0xd8f: 0x1206, 0xd90: 0x1636, 0xd91: 0x08aa,
0xd92: 0x0cfe, 0xd93: 0x15ae, 0xd94: 0x0862, 0xd95: 0x0ba6, 0xd96: 0x0f2a, 0xd97: 0x14da,
0xd98: 0x0c62, 0xd99: 0x0cb2, 0xd9a: 0x0e3e, 0xd9b: 0x102a, 0xd9c: 0x15b6, 0xd9d: 0x0912,
0xd9e: 0x09fa, 0xd9f: 0x0b92, 0xda0: 0x0dce, 0xda1: 0x0e1a, 0xda2: 0x0e5a, 0xda3: 0x0eee,
0xda4: 0x1042, 0xda5: 0x10b6, 0xda6: 0x1252, 0xda7: 0x13f2, 0xda8: 0x13fe, 0xda9: 0x1552,
0xdaa: 0x15d2, 0xdab: 0x097e, 0xdac: 0x0f46, 0xdad: 0x09fe, 0xdae: 0x0fc2, 0xdaf: 0x1066,
0xdb0: 0x1382, 0xdb1: 0x15ba, 0xdb2: 0x16a6, 0xdb3: 0x16ce, 0xdb4: 0x0e32, 0xdb5: 0x0f22,
0xdb6: 0x12be, 0xdb7: 0x11b2, 0xdb8: 0x11be, 0xdb9: 0x11e2, 0xdba: 0x1012, 0xdbb: 0x0f9a,
0xdbc: 0x145e, 0xdbd: 0x082e, 0xdbe: 0x1326, 0xdbf: 0x0916,
// Block 0x37, offset 0xdc0
0xdc0: 0x0906, 0xdc1: 0x0c06, 0xdc2: 0x0d26, 0xdc3: 0x11ee, 0xdc4: 0x0b4e, 0xdc5: 0x0efe,
0xdc6: 0x0dea, 0xdc7: 0x14e2, 0xdc8: 0x13e2, 0xdc9: 0x15a6, 0xdca: 0x141e, 0xdcb: 0x0c22,
0xdcc: 0x0882, 0xdcd: 0x0a56, 0xdd0: 0x0aaa,
0xdd2: 0x0dda, 0xdd5: 0x08f2, 0xdd6: 0x101a, 0xdd7: 0x10de,
0xdd8: 0x1142, 0xdd9: 0x115e, 0xdda: 0x1162, 0xddb: 0x1176, 0xddc: 0x15f6, 0xddd: 0x11e6,
0xdde: 0x126a, 0xde0: 0x138a, 0xde2: 0x144e,
0xde5: 0x1502, 0xde6: 0x152e,
0xdea: 0x164a, 0xdeb: 0x164e, 0xdec: 0x1652, 0xded: 0x16b6, 0xdee: 0x1526, 0xdef: 0x15c2,
0xdf0: 0x0852, 0xdf1: 0x0876, 0xdf2: 0x088a, 0xdf3: 0x0946, 0xdf4: 0x0952, 0xdf5: 0x0992,
0xdf6: 0x0a46, 0xdf7: 0x0a62, 0xdf8: 0x0a6a, 0xdf9: 0x0aa6, 0xdfa: 0x0ab2, 0xdfb: 0x0b8e,
0xdfc: 0x0b96, 0xdfd: 0x0c9e, 0xdfe: 0x0cc6, 0xdff: 0x0cce,
// Block 0x38, offset 0xe00
0xe00: 0x0ce6, 0xe01: 0x0d92, 0xe02: 0x0dc2, 0xe03: 0x0de2, 0xe04: 0x0e52, 0xe05: 0x0f16,
0xe06: 0x0f32, 0xe07: 0x0f62, 0xe08: 0x0fb6, 0xe09: 0x0fd6, 0xe0a: 0x104a, 0xe0b: 0x112a,
0xe0c: 0x1146, 0xe0d: 0x114e, 0xe0e: 0x114a, 0xe0f: 0x1152, 0xe10: 0x1156, 0xe11: 0x115a,
0xe12: 0x116e, 0xe13: 0x1172, 0xe14: 0x1196, 0xe15: 0x11aa, 0xe16: 0x11c6, 0xe17: 0x122a,
0xe18: 0x1232, 0xe19: 0x123a, 0xe1a: 0x124e, 0xe1b: 0x1276, 0xe1c: 0x12c6, 0xe1d: 0x12fa,
0xe1e: 0x12fa, 0xe1f: 0x1362, 0xe20: 0x140a, 0xe21: 0x1422, 0xe22: 0x1456, 0xe23: 0x145a,
0xe24: 0x149e, 0xe25: 0x14a2, 0xe26: 0x14fa, 0xe27: 0x1502, 0xe28: 0x15d6, 0xe29: 0x161a,
0xe2a: 0x1632, 0xe2b: 0x0c96, 0xe2c: 0x184b, 0xe2d: 0x12de,
0xe30: 0x07da, 0xe31: 0x08de, 0xe32: 0x089e, 0xe33: 0x0846, 0xe34: 0x0886, 0xe35: 0x08b2,
0xe36: 0x0942, 0xe37: 0x095e, 0xe38: 0x0a46, 0xe39: 0x0a32, 0xe3a: 0x0a42, 0xe3b: 0x0a5e,
0xe3c: 0x0aaa, 0xe3d: 0x0aba, 0xe3e: 0x0afe, 0xe3f: 0x0b0a,
// Block 0x39, offset 0xe40
0xe40: 0x0b26, 0xe41: 0x0b36, 0xe42: 0x0c1e, 0xe43: 0x0c26, 0xe44: 0x0c56, 0xe45: 0x0c76,
0xe46: 0x0ca6, 0xe47: 0x0cbe, 0xe48: 0x0cae, 0xe49: 0x0cce, 0xe4a: 0x0cc2, 0xe4b: 0x0ce6,
0xe4c: 0x0d02, 0xe4d: 0x0d5a, 0xe4e: 0x0d66, 0xe4f: 0x0d6e, 0xe50: 0x0d96, 0xe51: 0x0dda,
0xe52: 0x0e0a, 0xe53: 0x0e0e, 0xe54: 0x0e22, 0xe55: 0x0ea2, 0xe56: 0x0eb2, 0xe57: 0x0f0a,
0xe58: 0x0f56, 0xe59: 0x0f4e, 0xe5a: 0x0f62, 0xe5b: 0x0f7e, 0xe5c: 0x0fb6, 0xe5d: 0x110e,
0xe5e: 0x0fda, 0xe5f: 0x100e, 0xe60: 0x101a, 0xe61: 0x105a, 0xe62: 0x1076, 0xe63: 0x109a,
0xe64: 0x10be, 0xe65: 0x10c2, 0xe66: 0x10de, 0xe67: 0x10e2, 0xe68: 0x10f2, 0xe69: 0x1106,
0xe6a: 0x1102, 0xe6b: 0x1132, 0xe6c: 0x11ae, 0xe6d: 0x11c6, 0xe6e: 0x11de, 0xe6f: 0x1216,
0xe70: 0x122a, 0xe71: 0x1246, 0xe72: 0x1276, 0xe73: 0x132a, 0xe74: 0x1352, 0xe75: 0x13c6,
0xe76: 0x140e, 0xe77: 0x141a, 0xe78: 0x1422, 0xe79: 0x143a, 0xe7a: 0x144e, 0xe7b: 0x143e,
0xe7c: 0x1456, 0xe7d: 0x1452, 0xe7e: 0x144a, 0xe7f: 0x145a,
// Block 0x3a, offset 0xe80
0xe80: 0x1466, 0xe81: 0x14a2, 0xe82: 0x14de, 0xe83: 0x150e, 0xe84: 0x1546, 0xe85: 0x1566,
0xe86: 0x15b2, 0xe87: 0x15d6, 0xe88: 0x15f6, 0xe89: 0x160a, 0xe8a: 0x161a, 0xe8b: 0x1626,
0xe8c: 0x1632, 0xe8d: 0x1686, 0xe8e: 0x1726, 0xe8f: 0x17e2, 0xe90: 0x17dd, 0xe91: 0x180f,
0xe92: 0x0702, 0xe93: 0x072a, 0xe94: 0x072e, 0xe95: 0x1891, 0xe96: 0x18be, 0xe97: 0x1936,
0xe98: 0x1712, 0xe99: 0x1722,
// Block 0x3b, offset 0xec0
0xec0: 0x1b05, 0xec1: 0x1b08, 0xec2: 0x1b0b, 0xec3: 0x1d38, 0xec4: 0x1d3c, 0xec5: 0x1b8f,
0xec6: 0x1b8f,
0xed3: 0x1ea5, 0xed4: 0x1e96, 0xed5: 0x1e9b, 0xed6: 0x1eaa, 0xed7: 0x1ea0,
0xedd: 0x44d1,
0xede: 0x8116, 0xedf: 0x4543, 0xee0: 0x0320, 0xee1: 0x0308, 0xee2: 0x0311, 0xee3: 0x0314,
0xee4: 0x0317, 0xee5: 0x031a, 0xee6: 0x031d, 0xee7: 0x0323, 0xee8: 0x0326, 0xee9: 0x0017,
0xeea: 0x4531, 0xeeb: 0x4537, 0xeec: 0x4635, 0xeed: 0x463d, 0xeee: 0x4489, 0xeef: 0x448f,
0xef0: 0x4495, 0xef1: 0x449b, 0xef2: 0x44a7, 0xef3: 0x44ad, 0xef4: 0x44b3, 0xef5: 0x44bf,
0xef6: 0x44c5, 0xef8: 0x44cb, 0xef9: 0x44d7, 0xefa: 0x44dd, 0xefb: 0x44e3,
0xefc: 0x44ef, 0xefe: 0x44f5,
// Block 0x3c, offset 0xf00
0xf00: 0x44fb, 0xf01: 0x4501, 0xf03: 0x4507, 0xf04: 0x450d,
0xf06: 0x4519, 0xf07: 0x451f, 0xf08: 0x4525, 0xf09: 0x452b, 0xf0a: 0x453d, 0xf0b: 0x44b9,
0xf0c: 0x44a1, 0xf0d: 0x44e9, 0xf0e: 0x4513, 0xf0f: 0x1eaf, 0xf10: 0x038c, 0xf11: 0x038c,
0xf12: 0x0395, 0xf13: 0x0395, 0xf14: 0x0395, 0xf15: 0x0395, 0xf16: 0x0398, 0xf17: 0x0398,
0xf18: 0x0398, 0xf19: 0x0398, 0xf1a: 0x039e, 0xf1b: 0x039e, 0xf1c: 0x039e, 0xf1d: 0x039e,
0xf1e: 0x0392, 0xf1f: 0x0392, 0xf20: 0x0392, 0xf21: 0x0392, 0xf22: 0x039b, 0xf23: 0x039b,
0xf24: 0x039b, 0xf25: 0x039b, 0xf26: 0x038f, 0xf27: 0x038f, 0xf28: 0x038f, 0xf29: 0x038f,
0xf2a: 0x03c2, 0xf2b: 0x03c2, 0xf2c: 0x03c2, 0xf2d: 0x03c2, 0xf2e: 0x03c5, 0xf2f: 0x03c5,
0xf30: 0x03c5, 0xf31: 0x03c5, 0xf32: 0x03a4, 0xf33: 0x03a4, 0xf34: 0x03a4, 0xf35: 0x03a4,
0xf36: 0x03a1, 0xf37: 0x03a1, 0xf38: 0x03a1, 0xf39: 0x03a1, 0xf3a: 0x03a7, 0xf3b: 0x03a7,
0xf3c: 0x03a7, 0xf3d: 0x03a7, 0xf3e: 0x03aa, 0xf3f: 0x03aa,
// Block 0x3d, offset 0xf40
0xf40: 0x03aa, 0xf41: 0x03aa, 0xf42: 0x03b3, 0xf43: 0x03b3, 0xf44: 0x03b0, 0xf45: 0x03b0,
0xf46: 0x03b6, 0xf47: 0x03b6, 0xf48: 0x03ad, 0xf49: 0x03ad, 0xf4a: 0x03bc, 0xf4b: 0x03bc,
0xf4c: 0x03b9, 0xf4d: 0x03b9, 0xf4e: 0x03c8, 0xf4f: 0x03c8, 0xf50: 0x03c8, 0xf51: 0x03c8,
0xf52: 0x03ce, 0xf53: 0x03ce, 0xf54: 0x03ce, 0xf55: 0x03ce, 0xf56: 0x03d4, 0xf57: 0x03d4,
0xf58: 0x03d4, 0xf59: 0x03d4, 0xf5a: 0x03d1, 0xf5b: 0x03d1, 0xf5c: 0x03d1, 0xf5d: 0x03d1,
0xf5e: 0x03d7, 0xf5f: 0x03d7, 0xf60: 0x03da, 0xf61: 0x03da, 0xf62: 0x03da, 0xf63: 0x03da,
0xf64: 0x45af, 0xf65: 0x45af, 0xf66: 0x03e0, 0xf67: 0x03e0, 0xf68: 0x03e0, 0xf69: 0x03e0,
0xf6a: 0x03dd, 0xf6b: 0x03dd, 0xf6c: 0x03dd, 0xf6d: 0x03dd, 0xf6e: 0x03fb, 0xf6f: 0x03fb,
0xf70: 0x45a9, 0xf71: 0x45a9,
// Block 0x3e, offset 0xf80
0xf93: 0x03cb, 0xf94: 0x03cb, 0xf95: 0x03cb, 0xf96: 0x03cb, 0xf97: 0x03e9,
0xf98: 0x03e9, 0xf99: 0x03e6, 0xf9a: 0x03e6, 0xf9b: 0x03ec, 0xf9c: 0x03ec, 0xf9d: 0x217f,
0xf9e: 0x03f2, 0xf9f: 0x03f2, 0xfa0: 0x03e3, 0xfa1: 0x03e3, 0xfa2: 0x03ef, 0xfa3: 0x03ef,
0xfa4: 0x03f8, 0xfa5: 0x03f8, 0xfa6: 0x03f8, 0xfa7: 0x03f8, 0xfa8: 0x0380, 0xfa9: 0x0380,
0xfaa: 0x26da, 0xfab: 0x26da, 0xfac: 0x274a, 0xfad: 0x274a, 0xfae: 0x2719, 0xfaf: 0x2719,
0xfb0: 0x2735, 0xfb1: 0x2735, 0xfb2: 0x272e, 0xfb3: 0x272e, 0xfb4: 0x273c, 0xfb5: 0x273c,
0xfb6: 0x2743, 0xfb7: 0x2743, 0xfb8: 0x2743, 0xfb9: 0x2720, 0xfba: 0x2720, 0xfbb: 0x2720,
0xfbc: 0x03f5, 0xfbd: 0x03f5, 0xfbe: 0x03f5, 0xfbf: 0x03f5,
// Block 0x3f, offset 0xfc0
0xfc0: 0x26e1, 0xfc1: 0x26e8, 0xfc2: 0x2704, 0xfc3: 0x2720, 0xfc4: 0x2727, 0xfc5: 0x1eb9,
0xfc6: 0x1ebe, 0xfc7: 0x1ec3, 0xfc8: 0x1ed2, 0xfc9: 0x1ee1, 0xfca: 0x1ee6, 0xfcb: 0x1eeb,
0xfcc: 0x1ef0, 0xfcd: 0x1ef5, 0xfce: 0x1f04, 0xfcf: 0x1f13, 0xfd0: 0x1f18, 0xfd1: 0x1f1d,
0xfd2: 0x1f2c, 0xfd3: 0x1f3b, 0xfd4: 0x1f40, 0xfd5: 0x1f45, 0xfd6: 0x1f4a, 0xfd7: 0x1f59,
0xfd8: 0x1f5e, 0xfd9: 0x1f6d, 0xfda: 0x1f72, 0xfdb: 0x1f77, 0xfdc: 0x1f86, 0xfdd: 0x1f8b,
0xfde: 0x1f90, 0xfdf: 0x1f9a, 0xfe0: 0x1fd6, 0xfe1: 0x1fe5, 0xfe2: 0x1ff4, 0xfe3: 0x1ff9,
0xfe4: 0x1ffe, 0xfe5: 0x2008, 0xfe6: 0x2017, 0xfe7: 0x201c, 0xfe8: 0x202b, 0xfe9: 0x2030,
0xfea: 0x2035, 0xfeb: 0x2044, 0xfec: 0x2049, 0xfed: 0x2058, 0xfee: 0x205d, 0xfef: 0x2062,
0xff0: 0x2067, 0xff1: 0x206c, 0xff2: 0x2071, 0xff3: 0x2076, 0xff4: 0x207b, 0xff5: 0x2080,
0xff6: 0x2085, 0xff7: 0x208a, 0xff8: 0x208f, 0xff9: 0x2094, 0xffa: 0x2099, 0xffb: 0x209e,
0xffc: 0x20a3, 0xffd: 0x20a8, 0xffe: 0x20ad, 0xfff: 0x20b7,
// Block 0x40, offset 0x1000
0x1000: 0x20bc, 0x1001: 0x20c1, 0x1002: 0x20c6, 0x1003: 0x20d0, 0x1004: 0x20d5, 0x1005: 0x20df,
0x1006: 0x20e4, 0x1007: 0x20e9, 0x1008: 0x20ee, 0x1009: 0x20f3, 0x100a: 0x20f8, 0x100b: 0x20fd,
0x100c: 0x2102, 0x100d: 0x2107, 0x100e: 0x2116, 0x100f: 0x2125, 0x1010: 0x212a, 0x1011: 0x212f,
0x1012: 0x2134, 0x1013: 0x2139, 0x1014: 0x213e, 0x1015: 0x2148, 0x1016: 0x214d, 0x1017: 0x2152,
0x1018: 0x2161, 0x1019: 0x2170, 0x101a: 0x2175, 0x101b: 0x4561, 0x101c: 0x4567, 0x101d: 0x459d,
0x101e: 0x45f4, 0x101f: 0x45fb, 0x1020: 0x4602, 0x1021: 0x4609, 0x1022: 0x4610, 0x1023: 0x4617,
0x1024: 0x26f6, 0x1025: 0x26fd, 0x1026: 0x2704, 0x1027: 0x270b, 0x1028: 0x2720, 0x1029: 0x2727,
0x102a: 0x1ec8, 0x102b: 0x1ecd, 0x102c: 0x1ed2, 0x102d: 0x1ed7, 0x102e: 0x1ee1, 0x102f: 0x1ee6,
0x1030: 0x1efa, 0x1031: 0x1eff, 0x1032: 0x1f04, 0x1033: 0x1f09, 0x1034: 0x1f13, 0x1035: 0x1f18,
0x1036: 0x1f22, 0x1037: 0x1f27, 0x1038: 0x1f2c, 0x1039: 0x1f31, 0x103a: 0x1f3b, 0x103b: 0x1f40,
0x103c: 0x206c, 0x103d: 0x2071, 0x103e: 0x2080, 0x103f: 0x2085,
// Block 0x41, offset 0x1040
0x1040: 0x208a, 0x1041: 0x209e, 0x1042: 0x20a3, 0x1043: 0x20a8, 0x1044: 0x20ad, 0x1045: 0x20c6,
0x1046: 0x20d0, 0x1047: 0x20d5, 0x1048: 0x20da, 0x1049: 0x20ee, 0x104a: 0x210c, 0x104b: 0x2111,
0x104c: 0x2116, 0x104d: 0x211b, 0x104e: 0x2125, 0x104f: 0x212a, 0x1050: 0x459d, 0x1051: 0x2157,
0x1052: 0x215c, 0x1053: 0x2161, 0x1054: 0x2166, 0x1055: 0x2170, 0x1056: 0x2175, 0x1057: 0x26e1,
0x1058: 0x26e8, 0x1059: 0x26ef, 0x105a: 0x2704, 0x105b: 0x2712, 0x105c: 0x1eb9, 0x105d: 0x1ebe,
0x105e: 0x1ec3, 0x105f: 0x1ed2, 0x1060: 0x1edc, 0x1061: 0x1eeb, 0x1062: 0x1ef0, 0x1063: 0x1ef5,
0x1064: 0x1f04, 0x1065: 0x1f0e, 0x1066: 0x1f2c, 0x1067: 0x1f45, 0x1068: 0x1f4a, 0x1069: 0x1f59,
0x106a: 0x1f5e, 0x106b: 0x1f6d, 0x106c: 0x1f77, 0x106d: 0x1f86, 0x106e: 0x1f8b, 0x106f: 0x1f90,
0x1070: 0x1f9a, 0x1071: 0x1fd6, 0x1072: 0x1fdb, 0x1073: 0x1fe5, 0x1074: 0x1ff4, 0x1075: 0x1ff9,
0x1076: 0x1ffe, 0x1077: 0x2008, 0x1078: 0x2017, 0x1079: 0x202b, 0x107a: 0x2030, 0x107b: 0x2035,
0x107c: 0x2044, 0x107d: 0x2049, 0x107e: 0x2058, 0x107f: 0x205d,
// Block 0x42, offset 0x1080
0x1080: 0x2062, 0x1081: 0x2067, 0x1082: 0x2076, 0x1083: 0x207b, 0x1084: 0x208f, 0x1085: 0x2094,
0x1086: 0x2099, 0x1087: 0x209e, 0x1088: 0x20a3, 0x1089: 0x20b7, 0x108a: 0x20bc, 0x108b: 0x20c1,
0x108c: 0x20c6, 0x108d: 0x20cb, 0x108e: 0x20df, 0x108f: 0x20e4, 0x1090: 0x20e9, 0x1091: 0x20ee,
0x1092: 0x20fd, 0x1093: 0x2102, 0x1094: 0x2107, 0x1095: 0x2116, 0x1096: 0x2120, 0x1097: 0x212f,
0x1098: 0x2134, 0x1099: 0x4591, 0x109a: 0x2148, 0x109b: 0x214d, 0x109c: 0x2152, 0x109d: 0x2161,
0x109e: 0x216b, 0x109f: 0x2704, 0x10a0: 0x2712, 0x10a1: 0x1ed2, 0x10a2: 0x1edc, 0x10a3: 0x1f04,
0x10a4: 0x1f0e, 0x10a5: 0x1f2c, 0x10a6: 0x1f36, 0x10a7: 0x1f9a, 0x10a8: 0x1f9f, 0x10a9: 0x1fc2,
0x10aa: 0x1fc7, 0x10ab: 0x209e, 0x10ac: 0x20a3, 0x10ad: 0x20c6, 0x10ae: 0x2116, 0x10af: 0x2120,
0x10b0: 0x2161, 0x10b1: 0x216b, 0x10b2: 0x4645, 0x10b3: 0x464d, 0x10b4: 0x4655, 0x10b5: 0x2021,
0x10b6: 0x2026, 0x10b7: 0x203a, 0x10b8: 0x203f, 0x10b9: 0x204e, 0x10ba: 0x2053, 0x10bb: 0x1fa4,
0x10bc: 0x1fa9, 0x10bd: 0x1fcc, 0x10be: 0x1fd1, 0x10bf: 0x1f63,
// Block 0x43, offset 0x10c0
0x10c0: 0x1f68, 0x10c1: 0x1f4f, 0x10c2: 0x1f54, 0x10c3: 0x1f7c, 0x10c4: 0x1f81, 0x10c5: 0x1fea,
0x10c6: 0x1fef, 0x10c7: 0x200d, 0x10c8: 0x2012, 0x10c9: 0x1fae, 0x10ca: 0x1fb3, 0x10cb: 0x1fb8,
0x10cc: 0x1fc2, 0x10cd: 0x1fbd, 0x10ce: 0x1f95, 0x10cf: 0x1fe0, 0x10d0: 0x2003, 0x10d1: 0x2021,
0x10d2: 0x2026, 0x10d3: 0x203a, 0x10d4: 0x203f, 0x10d5: 0x204e, 0x10d6: 0x2053, 0x10d7: 0x1fa4,
0x10d8: 0x1fa9, 0x10d9: 0x1fcc, 0x10da: 0x1fd1, 0x10db: 0x1f63, 0x10dc: 0x1f68, 0x10dd: 0x1f4f,
0x10de: 0x1f54, 0x10df: 0x1f7c, 0x10e0: 0x1f81, 0x10e1: 0x1fea, 0x10e2: 0x1fef, 0x10e3: 0x200d,
0x10e4: 0x2012, 0x10e5: 0x1fae, 0x10e6: 0x1fb3, 0x10e7: 0x1fb8, 0x10e8: 0x1fc2, 0x10e9: 0x1fbd,
0x10ea: 0x1f95, 0x10eb: 0x1fe0, 0x10ec: 0x2003, 0x10ed: 0x1fae, 0x10ee: 0x1fb3, 0x10ef: 0x1fb8,
0x10f0: 0x1fc2, 0x10f1: 0x1f9f, 0x10f2: 0x1fc7, 0x10f3: 0x201c, 0x10f4: 0x1f86, 0x10f5: 0x1f8b,
0x10f6: 0x1f90, 0x10f7: 0x1fae, 0x10f8: 0x1fb3, 0x10f9: 0x1fb8, 0x10fa: 0x201c, 0x10fb: 0x202b,
0x10fc: 0x4549, 0x10fd: 0x4549,
// Block 0x44, offset 0x1100
0x1110: 0x2441, 0x1111: 0x2456,
0x1112: 0x2456, 0x1113: 0x245d, 0x1114: 0x2464, 0x1115: 0x2479, 0x1116: 0x2480, 0x1117: 0x2487,
0x1118: 0x24aa, 0x1119: 0x24aa, 0x111a: 0x24cd, 0x111b: 0x24c6, 0x111c: 0x24e2, 0x111d: 0x24d4,
0x111e: 0x24db, 0x111f: 0x24fe, 0x1120: 0x24fe, 0x1121: 0x24f7, 0x1122: 0x2505, 0x1123: 0x2505,
0x1124: 0x252f, 0x1125: 0x252f, 0x1126: 0x254b, 0x1127: 0x2513, 0x1128: 0x2513, 0x1129: 0x250c,
0x112a: 0x2521, 0x112b: 0x2521, 0x112c: 0x2528, 0x112d: 0x2528, 0x112e: 0x2552, 0x112f: 0x2560,
0x1130: 0x2560, 0x1131: 0x2567, 0x1132: 0x2567, 0x1133: 0x256e, 0x1134: 0x2575, 0x1135: 0x257c,
0x1136: 0x2583, 0x1137: 0x2583, 0x1138: 0x258a, 0x1139: 0x2598, 0x113a: 0x25a6, 0x113b: 0x259f,
0x113c: 0x25ad, 0x113d: 0x25ad, 0x113e: 0x25c2, 0x113f: 0x25c9,
// Block 0x45, offset 0x1140
0x1140: 0x25fa, 0x1141: 0x2608, 0x1142: 0x2601, 0x1143: 0x25e5, 0x1144: 0x25e5, 0x1145: 0x260f,
0x1146: 0x260f, 0x1147: 0x2616, 0x1148: 0x2616, 0x1149: 0x2640, 0x114a: 0x2647, 0x114b: 0x264e,
0x114c: 0x2624, 0x114d: 0x2632, 0x114e: 0x2655, 0x114f: 0x265c,
0x1152: 0x262b, 0x1153: 0x26b0, 0x1154: 0x26b7, 0x1155: 0x268d, 0x1156: 0x2694, 0x1157: 0x2678,
0x1158: 0x2678, 0x1159: 0x267f, 0x115a: 0x26a9, 0x115b: 0x26a2, 0x115c: 0x26cc, 0x115d: 0x26cc,
0x115e: 0x243a, 0x115f: 0x244f, 0x1160: 0x2448, 0x1161: 0x2472, 0x1162: 0x246b, 0x1163: 0x2495,
0x1164: 0x248e, 0x1165: 0x24b8, 0x1166: 0x249c, 0x1167: 0x24b1, 0x1168: 0x24e9, 0x1169: 0x2536,
0x116a: 0x251a, 0x116b: 0x2559, 0x116c: 0x25f3, 0x116d: 0x261d, 0x116e: 0x26c5, 0x116f: 0x26be,
0x1170: 0x26d3, 0x1171: 0x266a, 0x1172: 0x25d0, 0x1173: 0x269b, 0x1174: 0x25c2, 0x1175: 0x25fa,
0x1176: 0x2591, 0x1177: 0x25de, 0x1178: 0x2671, 0x1179: 0x2663, 0x117a: 0x25ec, 0x117b: 0x25d7,
0x117c: 0x25ec, 0x117d: 0x2671, 0x117e: 0x24a3, 0x117f: 0x24bf,
// Block 0x46, offset 0x1180
0x1180: 0x2639, 0x1181: 0x25b4, 0x1182: 0x2433, 0x1183: 0x25d7, 0x1184: 0x257c, 0x1185: 0x254b,
0x1186: 0x24f0, 0x1187: 0x2686,
0x11b0: 0x2544, 0x11b1: 0x25bb, 0x11b2: 0x28f6, 0x11b3: 0x28ed, 0x11b4: 0x2923, 0x11b5: 0x2911,
0x11b6: 0x28ff, 0x11b7: 0x291a, 0x11b8: 0x292c, 0x11b9: 0x253d, 0x11ba: 0x2db3, 0x11bb: 0x2c33,
0x11bc: 0x2908,
// Block 0x47, offset 0x11c0
0x11d0: 0x0019, 0x11d1: 0x057e,
0x11d2: 0x0582, 0x11d3: 0x0035, 0x11d4: 0x0037, 0x11d5: 0x0003, 0x11d6: 0x003f, 0x11d7: 0x05ba,
0x11d8: 0x05be, 0x11d9: 0x1c8c,
0x11e0: 0x8133, 0x11e1: 0x8133, 0x11e2: 0x8133, 0x11e3: 0x8133,
0x11e4: 0x8133, 0x11e5: 0x8133, 0x11e6: 0x8133, 0x11e7: 0x812e, 0x11e8: 0x812e, 0x11e9: 0x812e,
0x11ea: 0x812e, 0x11eb: 0x812e, 0x11ec: 0x812e, 0x11ed: 0x812e, 0x11ee: 0x8133, 0x11ef: 0x8133,
0x11f0: 0x19a0, 0x11f1: 0x053a, 0x11f2: 0x0536, 0x11f3: 0x007f, 0x11f4: 0x007f, 0x11f5: 0x0011,
0x11f6: 0x0013, 0x11f7: 0x00b7, 0x11f8: 0x00bb, 0x11f9: 0x05b2, 0x11fa: 0x05b6, 0x11fb: 0x05a6,
0x11fc: 0x05aa, 0x11fd: 0x058e, 0x11fe: 0x0592, 0x11ff: 0x0586,
// Block 0x48, offset 0x1200
0x1200: 0x058a, 0x1201: 0x0596, 0x1202: 0x059a, 0x1203: 0x059e, 0x1204: 0x05a2,
0x1207: 0x0077, 0x1208: 0x007b, 0x1209: 0x43aa, 0x120a: 0x43aa, 0x120b: 0x43aa,
0x120c: 0x43aa, 0x120d: 0x007f, 0x120e: 0x007f, 0x120f: 0x007f, 0x1210: 0x0019, 0x1211: 0x057e,
0x1212: 0x001d, 0x1214: 0x0037, 0x1215: 0x0035, 0x1216: 0x003f, 0x1217: 0x0003,
0x1218: 0x053a, 0x1219: 0x0011, 0x121a: 0x0013, 0x121b: 0x00b7, 0x121c: 0x00bb, 0x121d: 0x05b2,
0x121e: 0x05b6, 0x121f: 0x0007, 0x1220: 0x000d, 0x1221: 0x0015, 0x1222: 0x0017, 0x1223: 0x001b,
0x1224: 0x0039, 0x1225: 0x003d, 0x1226: 0x003b, 0x1228: 0x0079, 0x1229: 0x0009,
0x122a: 0x000b, 0x122b: 0x0041,
0x1230: 0x43eb, 0x1231: 0x456d, 0x1232: 0x43f0, 0x1234: 0x43f5,
0x1236: 0x43fa, 0x1237: 0x4573, 0x1238: 0x43ff, 0x1239: 0x4579, 0x123a: 0x4404, 0x123b: 0x457f,
0x123c: 0x4409, 0x123d: 0x4585, 0x123e: 0x440e, 0x123f: 0x458b,
// Block 0x49, offset 0x1240
0x1240: 0x0329, 0x1241: 0x454f, 0x1242: 0x454f, 0x1243: 0x4555, 0x1244: 0x4555, 0x1245: 0x4597,
0x1246: 0x4597, 0x1247: 0x455b, 0x1248: 0x455b, 0x1249: 0x45a3, 0x124a: 0x45a3, 0x124b: 0x45a3,
0x124c: 0x45a3, 0x124d: 0x032c, 0x124e: 0x032c, 0x124f: 0x032f, 0x1250: 0x032f, 0x1251: 0x032f,
0x1252: 0x032f, 0x1253: 0x0332, 0x1254: 0x0332, 0x1255: 0x0335, 0x1256: 0x0335, 0x1257: 0x0335,
0x1258: 0x0335, 0x1259: 0x0338, 0x125a: 0x0338, 0x125b: 0x0338, 0x125c: 0x0338, 0x125d: 0x033b,
0x125e: 0x033b, 0x125f: 0x033b, 0x1260: 0x033b, 0x1261: 0x033e, 0x1262: 0x033e, 0x1263: 0x033e,
0x1264: 0x033e, 0x1265: 0x0341, 0x1266: 0x0341, 0x1267: 0x0341, 0x1268: 0x0341, 0x1269: 0x0344,
0x126a: 0x0344, 0x126b: 0x0347, 0x126c: 0x0347, 0x126d: 0x034a, 0x126e: 0x034a, 0x126f: 0x034d,
0x1270: 0x034d, 0x1271: 0x0350, 0x1272: 0x0350, 0x1273: 0x0350, 0x1274: 0x0350, 0x1275: 0x0353,
0x1276: 0x0353, 0x1277: 0x0353, 0x1278: 0x0353, 0x1279: 0x0356, 0x127a: 0x0356, 0x127b: 0x0356,
0x127c: 0x0356, 0x127d: 0x0359, 0x127e: 0x0359, 0x127f: 0x0359,
// Block 0x4a, offset 0x1280
0x1280: 0x0359, 0x1281: 0x035c, 0x1282: 0x035c, 0x1283: 0x035c, 0x1284: 0x035c, 0x1285: 0x035f,
0x1286: 0x035f, 0x1287: 0x035f, 0x1288: 0x035f, 0x1289: 0x0362, 0x128a: 0x0362, 0x128b: 0x0362,
0x128c: 0x0362, 0x128d: 0x0365, 0x128e: 0x0365, 0x128f: 0x0365, 0x1290: 0x0365, 0x1291: 0x0368,
0x1292: 0x0368, 0x1293: 0x0368, 0x1294: 0x0368, 0x1295: 0x036b, 0x1296: 0x036b, 0x1297: 0x036b,
0x1298: 0x036b, 0x1299: 0x036e, 0x129a: 0x036e, 0x129b: 0x036e, 0x129c: 0x036e, 0x129d: 0x0371,
0x129e: 0x0371, 0x129f: 0x0371, 0x12a0: 0x0371, 0x12a1: 0x0374, 0x12a2: 0x0374, 0x12a3: 0x0374,
0x12a4: 0x0374, 0x12a5: 0x0377, 0x12a6: 0x0377, 0x12a7: 0x0377, 0x12a8: 0x0377, 0x12a9: 0x037a,
0x12aa: 0x037a, 0x12ab: 0x037a, 0x12ac: 0x037a, 0x12ad: 0x037d, 0x12ae: 0x037d, 0x12af: 0x0380,
0x12b0: 0x0380, 0x12b1: 0x0383, 0x12b2: 0x0383, 0x12b3: 0x0383, 0x12b4: 0x0383, 0x12b5: 0x2f41,
0x12b6: 0x2f41, 0x12b7: 0x2f49, 0x12b8: 0x2f49, 0x12b9: 0x2f51, 0x12ba: 0x2f51, 0x12bb: 0x20b2,
0x12bc: 0x20b2,
// Block 0x4b, offset 0x12c0
0x12c0: 0x0081, 0x12c1: 0x0083, 0x12c2: 0x0085, 0x12c3: 0x0087, 0x12c4: 0x0089, 0x12c5: 0x008b,
0x12c6: 0x008d, 0x12c7: 0x008f, 0x12c8: 0x0091, 0x12c9: 0x0093, 0x12ca: 0x0095, 0x12cb: 0x0097,
0x12cc: 0x0099, 0x12cd: 0x009b, 0x12ce: 0x009d, 0x12cf: 0x009f, 0x12d0: 0x00a1, 0x12d1: 0x00a3,
0x12d2: 0x00a5, 0x12d3: 0x00a7, 0x12d4: 0x00a9, 0x12d5: 0x00ab, 0x12d6: 0x00ad, 0x12d7: 0x00af,
0x12d8: 0x00b1, 0x12d9: 0x00b3, 0x12da: 0x00b5, 0x12db: 0x00b7, 0x12dc: 0x00b9, 0x12dd: 0x00bb,
0x12de: 0x00bd, 0x12df: 0x056e, 0x12e0: 0x0572, 0x12e1: 0x0582, 0x12e2: 0x0596, 0x12e3: 0x059a,
0x12e4: 0x057e, 0x12e5: 0x06a6, 0x12e6: 0x069e, 0x12e7: 0x05c2, 0x12e8: 0x05ca, 0x12e9: 0x05d2,
0x12ea: 0x05da, 0x12eb: 0x05e2, 0x12ec: 0x0666, 0x12ed: 0x066e, 0x12ee: 0x0676, 0x12ef: 0x061a,
0x12f0: 0x06aa, 0x12f1: 0x05c6, 0x12f2: 0x05ce, 0x12f3: 0x05d6, 0x12f4: 0x05de, 0x12f5: 0x05e6,
0x12f6: 0x05ea, 0x12f7: 0x05ee, 0x12f8: 0x05f2, 0x12f9: 0x05f6, 0x12fa: 0x05fa, 0x12fb: 0x05fe,
0x12fc: 0x0602, 0x12fd: 0x0606, 0x12fe: 0x060a, 0x12ff: 0x060e,
// Block 0x4c, offset 0x1300
0x1300: 0x0612, 0x1301: 0x0616, 0x1302: 0x061e, 0x1303: 0x0622, 0x1304: 0x0626, 0x1305: 0x062a,
0x1306: 0x062e, 0x1307: 0x0632, 0x1308: 0x0636, 0x1309: 0x063a, 0x130a: 0x063e, 0x130b: 0x0642,
0x130c: 0x0646, 0x130d: 0x064a, 0x130e: 0x064e, 0x130f: 0x0652, 0x1310: 0x0656, 0x1311: 0x065a,
0x1312: 0x065e, 0x1313: 0x0662, 0x1314: 0x066a, 0x1315: 0x0672, 0x1316: 0x067a, 0x1317: 0x067e,
0x1318: 0x0682, 0x1319: 0x0686, 0x131a: 0x068a, 0x131b: 0x068e, 0x131c: 0x0692, 0x131d: 0x06a2,
0x131e: 0x4bb9, 0x131f: 0x4bbf, 0x1320: 0x04b6, 0x1321: 0x0406, 0x1322: 0x040a, 0x1323: 0x4b7c,
0x1324: 0x040e, 0x1325: 0x4b82, 0x1326: 0x4b88, 0x1327: 0x0412, 0x1328: 0x0416, 0x1329: 0x041a,
0x132a: 0x4b8e, 0x132b: 0x4b94, 0x132c: 0x4b9a, 0x132d: 0x4ba0, 0x132e: 0x4ba6, 0x132f: 0x4bac,
0x1330: 0x045a, 0x1331: 0x041e, 0x1332: 0x0422, 0x1333: 0x0426, 0x1334: 0x046e, 0x1335: 0x042a,
0x1336: 0x042e, 0x1337: 0x0432, 0x1338: 0x0436, 0x1339: 0x043a, 0x133a: 0x043e, 0x133b: 0x0442,
0x133c: 0x0446, 0x133d: 0x044a, 0x133e: 0x044e,
// Block 0x4d, offset 0x1340
0x1342: 0x4afe, 0x1343: 0x4b04, 0x1344: 0x4b0a, 0x1345: 0x4b10,
0x1346: 0x4b16, 0x1347: 0x4b1c, 0x134a: 0x4b22, 0x134b: 0x4b28,
0x134c: 0x4b2e, 0x134d: 0x4b34, 0x134e: 0x4b3a, 0x134f: 0x4b40,
0x1352: 0x4b46, 0x1353: 0x4b4c, 0x1354: 0x4b52, 0x1355: 0x4b58, 0x1356: 0x4b5e, 0x1357: 0x4b64,
0x135a: 0x4b6a, 0x135b: 0x4b70, 0x135c: 0x4b76,
0x1360: 0x00bf, 0x1361: 0x00c2, 0x1362: 0x00cb, 0x1363: 0x43a5,
0x1364: 0x00c8, 0x1365: 0x00c5, 0x1366: 0x053e, 0x1368: 0x0562, 0x1369: 0x0542,
0x136a: 0x0546, 0x136b: 0x054a, 0x136c: 0x054e, 0x136d: 0x0566, 0x136e: 0x056a,
// Block 0x4e, offset 0x1380
0x1381: 0x01f1, 0x1382: 0x01f4, 0x1383: 0x00d4, 0x1384: 0x01be, 0x1385: 0x010d,
0x1387: 0x01d3, 0x1388: 0x174e, 0x1389: 0x01d9, 0x138a: 0x01d6, 0x138b: 0x0116,
0x138c: 0x0119, 0x138d: 0x0526, 0x138e: 0x011c, 0x138f: 0x0128, 0x1390: 0x01e5, 0x1391: 0x013a,
0x1392: 0x0134, 0x1393: 0x012e, 0x1394: 0x01c1, 0x1395: 0x00e0, 0x1396: 0x01c4, 0x1397: 0x0143,
0x1398: 0x0194, 0x1399: 0x01e8, 0x139a: 0x01eb, 0x139b: 0x0152, 0x139c: 0x1756, 0x139d: 0x1742,
0x139e: 0x0158, 0x139f: 0x175b, 0x13a0: 0x01a9, 0x13a1: 0x1760, 0x13a2: 0x00da, 0x13a3: 0x0170,
0x13a4: 0x0173, 0x13a5: 0x00a3, 0x13a6: 0x017c, 0x13a7: 0x1765, 0x13a8: 0x0182, 0x13a9: 0x0185,
0x13aa: 0x0188, 0x13ab: 0x01e2, 0x13ac: 0x01dc, 0x13ad: 0x1752, 0x13ae: 0x01df, 0x13af: 0x0197,
0x13b0: 0x0576, 0x13b2: 0x01ac, 0x13b3: 0x01cd, 0x13b4: 0x01d0, 0x13b5: 0x01bb,
0x13b6: 0x00f5, 0x13b7: 0x00f8, 0x13b8: 0x00fb, 0x13b9: 0x176a, 0x13ba: 0x176f,
// Block 0x4f, offset 0x13c0
0x13c0: 0x0063, 0x13c1: 0x0065, 0x13c2: 0x0067, 0x13c3: 0x0069, 0x13c4: 0x006b, 0x13c5: 0x006d,
0x13c6: 0x006f, 0x13c7: 0x0071, 0x13c8: 0x0073, 0x13c9: 0x0075, 0x13ca: 0x0083, 0x13cb: 0x0085,
0x13cc: 0x0087, 0x13cd: 0x0089, 0x13ce: 0x008b, 0x13cf: 0x008d, 0x13d0: 0x008f, 0x13d1: 0x0091,
0x13d2: 0x0093, 0x13d3: 0x0095, 0x13d4: 0x0097, 0x13d5: 0x0099, 0x13d6: 0x009b, 0x13d7: 0x009d,
0x13d8: 0x009f, 0x13d9: 0x00a1, 0x13da: 0x00a3, 0x13db: 0x00a5, 0x13dc: 0x00a7, 0x13dd: 0x00a9,
0x13de: 0x00ab, 0x13df: 0x00ad, 0x13e0: 0x00af, 0x13e1: 0x00b1, 0x13e2: 0x00b3, 0x13e3: 0x00b5,
0x13e4: 0x00e3, 0x13e5: 0x0101, 0x13e8: 0x01f7, 0x13e9: 0x01fa,
0x13ea: 0x01fd, 0x13eb: 0x0200, 0x13ec: 0x0203, 0x13ed: 0x0206, 0x13ee: 0x0209, 0x13ef: 0x020c,
0x13f0: 0x020f, 0x13f1: 0x0212, 0x13f2: 0x0215, 0x13f3: 0x0218, 0x13f4: 0x021b, 0x13f5: 0x021e,
0x13f6: 0x0221, 0x13f7: 0x0224, 0x13f8: 0x0227, 0x13f9: 0x020c, 0x13fa: 0x022a, 0x13fb: 0x022d,
0x13fc: 0x0230, 0x13fd: 0x0233, 0x13fe: 0x0236, 0x13ff: 0x0239,
// Block 0x50, offset 0x1400
0x1400: 0x0281, 0x1401: 0x0284, 0x1402: 0x0287, 0x1403: 0x0552, 0x1404: 0x024b, 0x1405: 0x0254,
0x1406: 0x025a, 0x1407: 0x027e, 0x1408: 0x026f, 0x1409: 0x026c, 0x140a: 0x028a, 0x140b: 0x028d,
0x140e: 0x0021, 0x140f: 0x0023, 0x1410: 0x0025, 0x1411: 0x0027,
0x1412: 0x0029, 0x1413: 0x002b, 0x1414: 0x002d, 0x1415: 0x002f, 0x1416: 0x0031, 0x1417: 0x0033,
0x1418: 0x0021, 0x1419: 0x0023, 0x141a: 0x0025, 0x141b: 0x0027, 0x141c: 0x0029, 0x141d: 0x002b,
0x141e: 0x002d, 0x141f: 0x002f, 0x1420: 0x0031, 0x1421: 0x0033, 0x1422: 0x0021, 0x1423: 0x0023,
0x1424: 0x0025, 0x1425: 0x0027, 0x1426: 0x0029, 0x1427: 0x002b, 0x1428: 0x002d, 0x1429: 0x002f,
0x142a: 0x0031, 0x142b: 0x0033, 0x142c: 0x0021, 0x142d: 0x0023, 0x142e: 0x0025, 0x142f: 0x0027,
0x1430: 0x0029, 0x1431: 0x002b, 0x1432: 0x002d, 0x1433: 0x002f, 0x1434: 0x0031, 0x1435: 0x0033,
0x1436: 0x0021, 0x1437: 0x0023, 0x1438: 0x0025, 0x1439: 0x0027, 0x143a: 0x0029, 0x143b: 0x002b,
0x143c: 0x002d, 0x143d: 0x002f, 0x143e: 0x0031, 0x143f: 0x0033,
// Block 0x51, offset 0x1440
0x1440: 0x8133, 0x1441: 0x8133, 0x1442: 0x8133, 0x1443: 0x8133, 0x1444: 0x8133, 0x1445: 0x8133,
0x1446: 0x8133, 0x1448: 0x8133, 0x1449: 0x8133, 0x144a: 0x8133, 0x144b: 0x8133,
0x144c: 0x8133, 0x144d: 0x8133, 0x144e: 0x8133, 0x144f: 0x8133, 0x1450: 0x8133, 0x1451: 0x8133,
0x1452: 0x8133, 0x1453: 0x8133, 0x1454: 0x8133, 0x1455: 0x8133, 0x1456: 0x8133, 0x1457: 0x8133,
0x1458: 0x8133, 0x145b: 0x8133, 0x145c: 0x8133, 0x145d: 0x8133,
0x145e: 0x8133, 0x145f: 0x8133, 0x1460: 0x8133, 0x1461: 0x8133, 0x1463: 0x8133,
0x1464: 0x8133, 0x1466: 0x8133, 0x1467: 0x8133, 0x1468: 0x8133, 0x1469: 0x8133,
0x146a: 0x8133,
0x1470: 0x0290, 0x1471: 0x0293, 0x1472: 0x0296, 0x1473: 0x0299, 0x1474: 0x029c, 0x1475: 0x029f,
0x1476: 0x02a2, 0x1477: 0x02a5, 0x1478: 0x02a8, 0x1479: 0x02ab, 0x147a: 0x02ae, 0x147b: 0x02b1,
0x147c: 0x02b7, 0x147d: 0x02ba, 0x147e: 0x02bd, 0x147f: 0x02c0,
// Block 0x52, offset 0x1480
0x1480: 0x02c3, 0x1481: 0x02c6, 0x1482: 0x02c9, 0x1483: 0x02cc, 0x1484: 0x02cf, 0x1485: 0x02d2,
0x1486: 0x02d5, 0x1487: 0x02db, 0x1488: 0x02e1, 0x1489: 0x02e4, 0x148a: 0x1736, 0x148b: 0x0302,
0x148c: 0x02ea, 0x148d: 0x02ed, 0x148e: 0x0305, 0x148f: 0x02f9, 0x1490: 0x02ff, 0x1491: 0x0290,
0x1492: 0x0293, 0x1493: 0x0296, 0x1494: 0x0299, 0x1495: 0x029c, 0x1496: 0x029f, 0x1497: 0x02a2,
0x1498: 0x02a5, 0x1499: 0x02a8, 0x149a: 0x02ab, 0x149b: 0x02ae, 0x149c: 0x02b7, 0x149d: 0x02ba,
0x149e: 0x02c0, 0x149f: 0x02c6, 0x14a0: 0x02c9, 0x14a1: 0x02cc, 0x14a2: 0x02cf, 0x14a3: 0x02d2,
0x14a4: 0x02d5, 0x14a5: 0x02d8, 0x14a6: 0x02db, 0x14a7: 0x02f3, 0x14a8: 0x02ea, 0x14a9: 0x02e7,
0x14aa: 0x02f0, 0x14ab: 0x02f6, 0x14ac: 0x1732, 0x14ad: 0x02fc,
// Block 0x53, offset 0x14c0
0x14c0: 0x032c, 0x14c1: 0x032f, 0x14c2: 0x033b, 0x14c3: 0x0344, 0x14c5: 0x037d,
0x14c6: 0x034d, 0x14c7: 0x033e, 0x14c8: 0x035c, 0x14c9: 0x0383, 0x14ca: 0x036e, 0x14cb: 0x0371,
0x14cc: 0x0374, 0x14cd: 0x0377, 0x14ce: 0x0350, 0x14cf: 0x0362, 0x14d0: 0x0368, 0x14d1: 0x0356,
0x14d2: 0x036b, 0x14d3: 0x034a, 0x14d4: 0x0353, 0x14d5: 0x0335, 0x14d6: 0x0338, 0x14d7: 0x0341,
0x14d8: 0x0347, 0x14d9: 0x0359, 0x14da: 0x035f, 0x14db: 0x0365, 0x14dc: 0x0386, 0x14dd: 0x03d7,
0x14de: 0x03bf, 0x14df: 0x0389, 0x14e1: 0x032f, 0x14e2: 0x033b,
0x14e4: 0x037a, 0x14e7: 0x033e, 0x14e9: 0x0383,
0x14ea: 0x036e, 0x14eb: 0x0371, 0x14ec: 0x0374, 0x14ed: 0x0377, 0x14ee: 0x0350, 0x14ef: 0x0362,
0x14f0: 0x0368, 0x14f1: 0x0356, 0x14f2: 0x036b, 0x14f4: 0x0353, 0x14f5: 0x0335,
0x14f6: 0x0338, 0x14f7: 0x0341, 0x14f9: 0x0359, 0x14fb: 0x0365,
// Block 0x54, offset 0x1500
0x1502: 0x033b,
0x1507: 0x033e, 0x1509: 0x0383, 0x150b: 0x0371,
0x150d: 0x0377, 0x150e: 0x0350, 0x150f: 0x0362, 0x1511: 0x0356,
0x1512: 0x036b, 0x1514: 0x0353, 0x1517: 0x0341,
0x1519: 0x0359, 0x151b: 0x0365, 0x151d: 0x03d7,
0x151f: 0x0389, 0x1521: 0x032f, 0x1522: 0x033b,
0x1524: 0x037a, 0x1527: 0x033e, 0x1528: 0x035c, 0x1529: 0x0383,
0x152a: 0x036e, 0x152c: 0x0374, 0x152d: 0x0377, 0x152e: 0x0350, 0x152f: 0x0362,
0x1530: 0x0368, 0x1531: 0x0356, 0x1532: 0x036b, 0x1534: 0x0353, 0x1535: 0x0335,
0x1536: 0x0338, 0x1537: 0x0341, 0x1539: 0x0359, 0x153a: 0x035f, 0x153b: 0x0365,
0x153c: 0x0386, 0x153e: 0x03bf,
// Block 0x55, offset 0x1540
0x1540: 0x032c, 0x1541: 0x032f, 0x1542: 0x033b, 0x1543: 0x0344, 0x1544: 0x037a, 0x1545: 0x037d,
0x1546: 0x034d, 0x1547: 0x033e, 0x1548: 0x035c, 0x1549: 0x0383, 0x154b: 0x0371,
0x154c: 0x0374, 0x154d: 0x0377, 0x154e: 0x0350, 0x154f: 0x0362, 0x1550: 0x0368, 0x1551: 0x0356,
0x1552: 0x036b, 0x1553: 0x034a, 0x1554: 0x0353, 0x1555: 0x0335, 0x1556: 0x0338, 0x1557: 0x0341,
0x1558: 0x0347, 0x1559: 0x0359, 0x155a: 0x035f, 0x155b: 0x0365,
0x1561: 0x032f, 0x1562: 0x033b, 0x1563: 0x0344,
0x1565: 0x037d, 0x1566: 0x034d, 0x1567: 0x033e, 0x1568: 0x035c, 0x1569: 0x0383,
0x156b: 0x0371, 0x156c: 0x0374, 0x156d: 0x0377, 0x156e: 0x0350, 0x156f: 0x0362,
0x1570: 0x0368, 0x1571: 0x0356, 0x1572: 0x036b, 0x1573: 0x034a, 0x1574: 0x0353, 0x1575: 0x0335,
0x1576: 0x0338, 0x1577: 0x0341, 0x1578: 0x0347, 0x1579: 0x0359, 0x157a: 0x035f, 0x157b: 0x0365,
// Block 0x56, offset 0x1580
0x1580: 0x19a6, 0x1581: 0x19a3, 0x1582: 0x19a9, 0x1583: 0x19cd, 0x1584: 0x19f1, 0x1585: 0x1a15,
0x1586: 0x1a39, 0x1587: 0x1a42, 0x1588: 0x1a48, 0x1589: 0x1a4e, 0x158a: 0x1a54,
0x1590: 0x1bbc, 0x1591: 0x1bc0,
0x1592: 0x1bc4, 0x1593: 0x1bc8, 0x1594: 0x1bcc, 0x1595: 0x1bd0, 0x1596: 0x1bd4, 0x1597: 0x1bd8,
0x1598: 0x1bdc, 0x1599: 0x1be0, 0x159a: 0x1be4, 0x159b: 0x1be8, 0x159c: 0x1bec, 0x159d: 0x1bf0,
0x159e: 0x1bf4, 0x159f: 0x1bf8, 0x15a0: 0x1bfc, 0x15a1: 0x1c00, 0x15a2: 0x1c04, 0x15a3: 0x1c08,
0x15a4: 0x1c0c, 0x15a5: 0x1c10, 0x15a6: 0x1c14, 0x15a7: 0x1c18, 0x15a8: 0x1c1c, 0x15a9: 0x1c20,
0x15aa: 0x2855, 0x15ab: 0x0047, 0x15ac: 0x0065, 0x15ad: 0x1a69, 0x15ae: 0x1ae1,
0x15b0: 0x0043, 0x15b1: 0x0045, 0x15b2: 0x0047, 0x15b3: 0x0049, 0x15b4: 0x004b, 0x15b5: 0x004d,
0x15b6: 0x004f, 0x15b7: 0x0051, 0x15b8: 0x0053, 0x15b9: 0x0055, 0x15ba: 0x0057, 0x15bb: 0x0059,
0x15bc: 0x005b, 0x15bd: 0x005d, 0x15be: 0x005f, 0x15bf: 0x0061,
// Block 0x57, offset 0x15c0
0x15c0: 0x27dd, 0x15c1: 0x27f2, 0x15c2: 0x05fe,
0x15d0: 0x0d0a, 0x15d1: 0x0b42,
0x15d2: 0x09ce, 0x15d3: 0x4705, 0x15d4: 0x0816, 0x15d5: 0x0aea, 0x15d6: 0x142a, 0x15d7: 0x0afa,
0x15d8: 0x0822, 0x15d9: 0x0dd2, 0x15da: 0x0faa, 0x15db: 0x0daa, 0x15dc: 0x0922, 0x15dd: 0x0c66,
0x15de: 0x08ba, 0x15df: 0x0db2, 0x15e0: 0x090e, 0x15e1: 0x1212, 0x15e2: 0x107e, 0x15e3: 0x1486,
0x15e4: 0x0ace, 0x15e5: 0x0a06, 0x15e6: 0x0f5e, 0x15e7: 0x0d16, 0x15e8: 0x0d42, 0x15e9: 0x07ba,
0x15ea: 0x07c6, 0x15eb: 0x1506, 0x15ec: 0x0bd6, 0x15ed: 0x07e2, 0x15ee: 0x09ea, 0x15ef: 0x0d36,
0x15f0: 0x14ae, 0x15f1: 0x0d0e, 0x15f2: 0x116a, 0x15f3: 0x11a6, 0x15f4: 0x09f2, 0x15f5: 0x0f3e,
0x15f6: 0x0e06, 0x15f7: 0x0e02, 0x15f8: 0x1092, 0x15f9: 0x0926, 0x15fa: 0x0a52, 0x15fb: 0x153e,
// Block 0x58, offset 0x1600
0x1600: 0x07f6, 0x1601: 0x07ee, 0x1602: 0x07fe, 0x1603: 0x1774, 0x1604: 0x0842, 0x1605: 0x0852,
0x1606: 0x0856, 0x1607: 0x085e, 0x1608: 0x0866, 0x1609: 0x086a, 0x160a: 0x0876, 0x160b: 0x086e,
0x160c: 0x06ae, 0x160d: 0x1788, 0x160e: 0x088a, 0x160f: 0x088e, 0x1610: 0x0892, 0x1611: 0x08ae,
0x1612: 0x1779, 0x1613: 0x06b2, 0x1614: 0x089a, 0x1615: 0x08ba, 0x1616: 0x1783, 0x1617: 0x08ca,
0x1618: 0x08d2, 0x1619: 0x0832, 0x161a: 0x08da, 0x161b: 0x08de, 0x161c: 0x195e, 0x161d: 0x08fa,
0x161e: 0x0902, 0x161f: 0x06ba, 0x1620: 0x091a, 0x1621: 0x091e, 0x1622: 0x0926, 0x1623: 0x092a,
0x1624: 0x06be, 0x1625: 0x0942, 0x1626: 0x0946, 0x1627: 0x0952, 0x1628: 0x095e, 0x1629: 0x0962,
0x162a: 0x0966, 0x162b: 0x096e, 0x162c: 0x098e, 0x162d: 0x0992, 0x162e: 0x099a, 0x162f: 0x09aa,
0x1630: 0x09b2, 0x1631: 0x09b6, 0x1632: 0x09b6, 0x1633: 0x09b6, 0x1634: 0x1797, 0x1635: 0x0f8e,
0x1636: 0x09ca, 0x1637: 0x09d2, 0x1638: 0x179c, 0x1639: 0x09de, 0x163a: 0x09e6, 0x163b: 0x09ee,
0x163c: 0x0a16, 0x163d: 0x0a02, 0x163e: 0x0a0e, 0x163f: 0x0a12,
// Block 0x59, offset 0x1640
0x1640: 0x0a1a, 0x1641: 0x0a22, 0x1642: 0x0a26, 0x1643: 0x0a2e, 0x1644: 0x0a36, 0x1645: 0x0a3a,
0x1646: 0x0a3a, 0x1647: 0x0a42, 0x1648: 0x0a4a, 0x1649: 0x0a4e, 0x164a: 0x0a5a, 0x164b: 0x0a7e,
0x164c: 0x0a62, 0x164d: 0x0a82, 0x164e: 0x0a66, 0x164f: 0x0a6e, 0x1650: 0x0906, 0x1651: 0x0aca,
0x1652: 0x0a92, 0x1653: 0x0a96, 0x1654: 0x0a9a, 0x1655: 0x0a8e, 0x1656: 0x0aa2, 0x1657: 0x0a9e,
0x1658: 0x0ab6, 0x1659: 0x17a1, 0x165a: 0x0ad2, 0x165b: 0x0ad6, 0x165c: 0x0ade, 0x165d: 0x0aea,
0x165e: 0x0af2, 0x165f: 0x0b0e, 0x1660: 0x17a6, 0x1661: 0x17ab, 0x1662: 0x0b1a, 0x1663: 0x0b1e,
0x1664: 0x0b22, 0x1665: 0x0b16, 0x1666: 0x0b2a, 0x1667: 0x06c2, 0x1668: 0x06c6, 0x1669: 0x0b32,
0x166a: 0x0b3a, 0x166b: 0x0b3a, 0x166c: 0x17b0, 0x166d: 0x0b56, 0x166e: 0x0b5a, 0x166f: 0x0b5e,
0x1670: 0x0b66, 0x1671: 0x17b5, 0x1672: 0x0b6e, 0x1673: 0x0b72, 0x1674: 0x0c4a, 0x1675: 0x0b7a,
0x1676: 0x06ca, 0x1677: 0x0b86, 0x1678: 0x0b96, 0x1679: 0x0ba2, 0x167a: 0x0b9e, 0x167b: 0x17bf,
0x167c: 0x0baa, 0x167d: 0x17c4, 0x167e: 0x0bb6, 0x167f: 0x0bb2,
// Block 0x5a, offset 0x1680
0x1680: 0x0bba, 0x1681: 0x0bca, 0x1682: 0x0bce, 0x1683: 0x06ce, 0x1684: 0x0bde, 0x1685: 0x0be6,
0x1686: 0x0bea, 0x1687: 0x0bee, 0x1688: 0x06d2, 0x1689: 0x17c9, 0x168a: 0x06d6, 0x168b: 0x0c0a,
0x168c: 0x0c0e, 0x168d: 0x0c12, 0x168e: 0x0c1a, 0x168f: 0x1990, 0x1690: 0x0c32, 0x1691: 0x17d3,
0x1692: 0x17d3, 0x1693: 0x12d2, 0x1694: 0x0c42, 0x1695: 0x0c42, 0x1696: 0x06da, 0x1697: 0x17f6,
0x1698: 0x18c8, 0x1699: 0x0c52, 0x169a: 0x0c5a, 0x169b: 0x06de, 0x169c: 0x0c6e, 0x169d: 0x0c7e,
0x169e: 0x0c82, 0x169f: 0x0c8a, 0x16a0: 0x0c9a, 0x16a1: 0x06e6, 0x16a2: 0x06e2, 0x16a3: 0x0c9e,
0x16a4: 0x17d8, 0x16a5: 0x0ca2, 0x16a6: 0x0cb6, 0x16a7: 0x0cba, 0x16a8: 0x0cbe, 0x16a9: 0x0cba,
0x16aa: 0x0cca, 0x16ab: 0x0cce, 0x16ac: 0x0cde, 0x16ad: 0x0cd6, 0x16ae: 0x0cda, 0x16af: 0x0ce2,
0x16b0: 0x0ce6, 0x16b1: 0x0cea, 0x16b2: 0x0cf6, 0x16b3: 0x0cfa, 0x16b4: 0x0d12, 0x16b5: 0x0d1a,
0x16b6: 0x0d2a, 0x16b7: 0x0d3e, 0x16b8: 0x17e7, 0x16b9: 0x0d3a, 0x16ba: 0x0d2e, 0x16bb: 0x0d46,
0x16bc: 0x0d4e, 0x16bd: 0x0d62, 0x16be: 0x17ec, 0x16bf: 0x0d6a,
// Block 0x5b, offset 0x16c0
0x16c0: 0x0d5e, 0x16c1: 0x0d56, 0x16c2: 0x06ea, 0x16c3: 0x0d72, 0x16c4: 0x0d7a, 0x16c5: 0x0d82,
0x16c6: 0x0d76, 0x16c7: 0x06ee, 0x16c8: 0x0d92, 0x16c9: 0x0d9a, 0x16ca: 0x17f1, 0x16cb: 0x0dc6,
0x16cc: 0x0dfa, 0x16cd: 0x0dd6, 0x16ce: 0x06fa, 0x16cf: 0x0de2, 0x16d0: 0x06f6, 0x16d1: 0x06f2,
0x16d2: 0x08be, 0x16d3: 0x08c2, 0x16d4: 0x0dfe, 0x16d5: 0x0de6, 0x16d6: 0x12a6, 0x16d7: 0x075e,
0x16d8: 0x0e0a, 0x16d9: 0x0e0e, 0x16da: 0x0e12, 0x16db: 0x0e26, 0x16dc: 0x0e1e, 0x16dd: 0x180a,
0x16de: 0x06fe, 0x16df: 0x0e3a, 0x16e0: 0x0e2e, 0x16e1: 0x0e4a, 0x16e2: 0x0e52, 0x16e3: 0x1814,
0x16e4: 0x0e56, 0x16e5: 0x0e42, 0x16e6: 0x0e5e, 0x16e7: 0x0702, 0x16e8: 0x0e62, 0x16e9: 0x0e66,
0x16ea: 0x0e6a, 0x16eb: 0x0e76, 0x16ec: 0x1819, 0x16ed: 0x0e7e, 0x16ee: 0x0706, 0x16ef: 0x0e8a,
0x16f0: 0x181e, 0x16f1: 0x0e8e, 0x16f2: 0x070a, 0x16f3: 0x0e9a, 0x16f4: 0x0ea6, 0x16f5: 0x0eb2,
0x16f6: 0x0eb6, 0x16f7: 0x1823, 0x16f8: 0x17ba, 0x16f9: 0x1828, 0x16fa: 0x0ed6, 0x16fb: 0x182d,
0x16fc: 0x0ee2, 0x16fd: 0x0eea, 0x16fe: 0x0eda, 0x16ff: 0x0ef6,
// Block 0x5c, offset 0x1700
0x1700: 0x0f06, 0x1701: 0x0f16, 0x1702: 0x0f0a, 0x1703: 0x0f0e, 0x1704: 0x0f1a, 0x1705: 0x0f1e,
0x1706: 0x1832, 0x1707: 0x0f02, 0x1708: 0x0f36, 0x1709: 0x0f3a, 0x170a: 0x070e, 0x170b: 0x0f4e,
0x170c: 0x0f4a, 0x170d: 0x1837, 0x170e: 0x0f2e, 0x170f: 0x0f6a, 0x1710: 0x183c, 0x1711: 0x1841,
0x1712: 0x0f6e, 0x1713: 0x0f82, 0x1714: 0x0f7e, 0x1715: 0x0f7a, 0x1716: 0x0712, 0x1717: 0x0f86,
0x1718: 0x0f96, 0x1719: 0x0f92, 0x171a: 0x0f9e, 0x171b: 0x177e, 0x171c: 0x0fae, 0x171d: 0x1846,
0x171e: 0x0fba, 0x171f: 0x1850, 0x1720: 0x0fce, 0x1721: 0x0fda, 0x1722: 0x0fee, 0x1723: 0x1855,
0x1724: 0x1002, 0x1725: 0x1006, 0x1726: 0x185a, 0x1727: 0x185f, 0x1728: 0x1022, 0x1729: 0x1032,
0x172a: 0x0716, 0x172b: 0x1036, 0x172c: 0x071a, 0x172d: 0x071a, 0x172e: 0x104e, 0x172f: 0x1052,
0x1730: 0x105a, 0x1731: 0x105e, 0x1732: 0x106a, 0x1733: 0x071e, 0x1734: 0x1082, 0x1735: 0x1864,
0x1736: 0x109e, 0x1737: 0x1869, 0x1738: 0x10aa, 0x1739: 0x17ce, 0x173a: 0x10ba, 0x173b: 0x186e,
0x173c: 0x1873, 0x173d: 0x1878, 0x173e: 0x0722, 0x173f: 0x0726,
// Block 0x5d, offset 0x1740
0x1740: 0x10f2, 0x1741: 0x1882, 0x1742: 0x187d, 0x1743: 0x1887, 0x1744: 0x188c, 0x1745: 0x10fa,
0x1746: 0x10fe, 0x1747: 0x10fe, 0x1748: 0x1106, 0x1749: 0x072e, 0x174a: 0x110a, 0x174b: 0x0732,
0x174c: 0x0736, 0x174d: 0x1896, 0x174e: 0x111e, 0x174f: 0x1126, 0x1750: 0x1132, 0x1751: 0x073a,
0x1752: 0x189b, 0x1753: 0x1156, 0x1754: 0x18a0, 0x1755: 0x18a5, 0x1756: 0x1176, 0x1757: 0x118e,
0x1758: 0x073e, 0x1759: 0x1196, 0x175a: 0x119a, 0x175b: 0x119e, 0x175c: 0x18aa, 0x175d: 0x18af,
0x175e: 0x18af, 0x175f: 0x11b6, 0x1760: 0x0742, 0x1761: 0x18b4, 0x1762: 0x11ca, 0x1763: 0x11ce,
0x1764: 0x0746, 0x1765: 0x18b9, 0x1766: 0x11ea, 0x1767: 0x074a, 0x1768: 0x11fa, 0x1769: 0x11f2,
0x176a: 0x1202, 0x176b: 0x18c3, 0x176c: 0x121a, 0x176d: 0x074e, 0x176e: 0x1226, 0x176f: 0x122e,
0x1770: 0x123e, 0x1771: 0x0752, 0x1772: 0x18cd, 0x1773: 0x18d2, 0x1774: 0x0756, 0x1775: 0x18d7,
0x1776: 0x1256, 0x1777: 0x18dc, 0x1778: 0x1262, 0x1779: 0x126e, 0x177a: 0x1276, 0x177b: 0x18e1,
0x177c: 0x18e6, 0x177d: 0x128a, 0x177e: 0x18eb, 0x177f: 0x1292,
// Block 0x5e, offset 0x1780
0x1780: 0x17fb, 0x1781: 0x075a, 0x1782: 0x12aa, 0x1783: 0x12ae, 0x1784: 0x0762, 0x1785: 0x12b2,
0x1786: 0x0b2e, 0x1787: 0x18f0, 0x1788: 0x18f5, 0x1789: 0x1800, 0x178a: 0x1805, 0x178b: 0x12d2,
0x178c: 0x12d6, 0x178d: 0x14ee, 0x178e: 0x0766, 0x178f: 0x1302, 0x1790: 0x12fe, 0x1791: 0x1306,
0x1792: 0x093a, 0x1793: 0x130a, 0x1794: 0x130e, 0x1795: 0x1312, 0x1796: 0x131a, 0x1797: 0x18fa,
0x1798: 0x1316, 0x1799: 0x131e, 0x179a: 0x1332, 0x179b: 0x1336, 0x179c: 0x1322, 0x179d: 0x133a,
0x179e: 0x134e, 0x179f: 0x1362, 0x17a0: 0x132e, 0x17a1: 0x1342, 0x17a2: 0x1346, 0x17a3: 0x134a,
0x17a4: 0x18ff, 0x17a5: 0x1909, 0x17a6: 0x1904, 0x17a7: 0x076a, 0x17a8: 0x136a, 0x17a9: 0x136e,
0x17aa: 0x1376, 0x17ab: 0x191d, 0x17ac: 0x137a, 0x17ad: 0x190e, 0x17ae: 0x076e, 0x17af: 0x0772,
0x17b0: 0x1913, 0x17b1: 0x1918, 0x17b2: 0x0776, 0x17b3: 0x139a, 0x17b4: 0x139e, 0x17b5: 0x13a2,
0x17b6: 0x13a6, 0x17b7: 0x13b2, 0x17b8: 0x13ae, 0x17b9: 0x13ba, 0x17ba: 0x13b6, 0x17bb: 0x13c6,
0x17bc: 0x13be, 0x17bd: 0x13c2, 0x17be: 0x13ca, 0x17bf: 0x077a,
// Block 0x5f, offset 0x17c0
0x17c0: 0x13d2, 0x17c1: 0x13d6, 0x17c2: 0x077e, 0x17c3: 0x13e6, 0x17c4: 0x13ea, 0x17c5: 0x1922,
0x17c6: 0x13f6, 0x17c7: 0x13fa, 0x17c8: 0x0782, 0x17c9: 0x1406, 0x17ca: 0x06b6, 0x17cb: 0x1927,
0x17cc: 0x192c, 0x17cd: 0x0786, 0x17ce: 0x078a, 0x17cf: 0x1432, 0x17d0: 0x144a, 0x17d1: 0x1466,
0x17d2: 0x1476, 0x17d3: 0x1931, 0x17d4: 0x148a, 0x17d5: 0x148e, 0x17d6: 0x14a6, 0x17d7: 0x14b2,
0x17d8: 0x193b, 0x17d9: 0x178d, 0x17da: 0x14be, 0x17db: 0x14ba, 0x17dc: 0x14c6, 0x17dd: 0x1792,
0x17de: 0x14d2, 0x17df: 0x14de, 0x17e0: 0x1940, 0x17e1: 0x1945, 0x17e2: 0x151e, 0x17e3: 0x152a,
0x17e4: 0x1532, 0x17e5: 0x194a, 0x17e6: 0x1536, 0x17e7: 0x1562, 0x17e8: 0x156e, 0x17e9: 0x1572,
0x17ea: 0x156a, 0x17eb: 0x157e, 0x17ec: 0x1582, 0x17ed: 0x194f, 0x17ee: 0x158e, 0x17ef: 0x078e,
0x17f0: 0x1596, 0x17f1: 0x1954, 0x17f2: 0x0792, 0x17f3: 0x15ce, 0x17f4: 0x0bbe, 0x17f5: 0x15e6,
0x17f6: 0x1959, 0x17f7: 0x1963, 0x17f8: 0x0796, 0x17f9: 0x079a, 0x17fa: 0x160e, 0x17fb: 0x1968,
0x17fc: 0x079e, 0x17fd: 0x196d, 0x17fe: 0x1626, 0x17ff: 0x1626,
// Block 0x60, offset 0x1800
0x1800: 0x162e, 0x1801: 0x1972, 0x1802: 0x1646, 0x1803: 0x07a2, 0x1804: 0x1656, 0x1805: 0x1662,
0x1806: 0x166a, 0x1807: 0x1672, 0x1808: 0x07a6, 0x1809: 0x1977, 0x180a: 0x1686, 0x180b: 0x16a2,
0x180c: 0x16ae, 0x180d: 0x07aa, 0x180e: 0x07ae, 0x180f: 0x16b2, 0x1810: 0x197c, 0x1811: 0x07b2,
0x1812: 0x1981, 0x1813: 0x1986, 0x1814: 0x198b, 0x1815: 0x16d6, 0x1816: 0x07b6, 0x1817: 0x16ea,
0x1818: 0x16f2, 0x1819: 0x16f6, 0x181a: 0x16fe, 0x181b: 0x1706, 0x181c: 0x170e, 0x181d: 0x1995,
}
// nfkcIndex: 22 blocks, 1408 entries, 2816 bytes
// Block 0 is the zero block.
var nfkcIndex = [1408]uint16{
// Block 0x0, offset 0x0
// Block 0x1, offset 0x40
// Block 0x2, offset 0x80
// Block 0x3, offset 0xc0
0xc2: 0x5f, 0xc3: 0x01, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x60, 0xc7: 0x04,
0xc8: 0x05, 0xca: 0x61, 0xcb: 0x62, 0xcc: 0x06, 0xcd: 0x07, 0xce: 0x08, 0xcf: 0x09,
0xd0: 0x0a, 0xd1: 0x63, 0xd2: 0x64, 0xd3: 0x0b, 0xd6: 0x0c, 0xd7: 0x65,
0xd8: 0x66, 0xd9: 0x0d, 0xdb: 0x67, 0xdc: 0x68, 0xdd: 0x69, 0xdf: 0x6a,
0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05,
0xea: 0x06, 0xeb: 0x07, 0xec: 0x08, 0xed: 0x09, 0xef: 0x0a,
0xf0: 0x13,
// Block 0x4, offset 0x100
0x120: 0x6b, 0x121: 0x6c, 0x122: 0x6d, 0x123: 0x0e, 0x124: 0x6e, 0x125: 0x6f, 0x126: 0x70, 0x127: 0x71,
0x128: 0x72, 0x129: 0x73, 0x12a: 0x74, 0x12b: 0x75, 0x12c: 0x70, 0x12d: 0x76, 0x12e: 0x77, 0x12f: 0x78,
0x130: 0x74, 0x131: 0x79, 0x132: 0x7a, 0x133: 0x7b, 0x134: 0x7c, 0x135: 0x7d, 0x137: 0x7e,
0x138: 0x7f, 0x139: 0x80, 0x13a: 0x81, 0x13b: 0x82, 0x13c: 0x83, 0x13d: 0x84, 0x13e: 0x85, 0x13f: 0x86,
// Block 0x5, offset 0x140
0x140: 0x87, 0x142: 0x88, 0x143: 0x89, 0x144: 0x8a, 0x145: 0x8b, 0x146: 0x8c, 0x147: 0x8d,
0x14d: 0x8e,
0x15c: 0x8f, 0x15f: 0x90,
0x162: 0x91, 0x164: 0x92,
0x168: 0x93, 0x169: 0x94, 0x16a: 0x95, 0x16b: 0x96, 0x16c: 0x0f, 0x16d: 0x97, 0x16e: 0x98, 0x16f: 0x99,
0x170: 0x9a, 0x173: 0x9b, 0x174: 0x9c, 0x175: 0x10, 0x176: 0x11, 0x177: 0x12,
0x178: 0x13, 0x179: 0x14, 0x17a: 0x15, 0x17b: 0x16, 0x17c: 0x17, 0x17d: 0x18, 0x17e: 0x19, 0x17f: 0x1a,
// Block 0x6, offset 0x180
0x180: 0x9d, 0x181: 0x9e, 0x182: 0x9f, 0x183: 0xa0, 0x184: 0x1b, 0x185: 0x1c, 0x186: 0xa1, 0x187: 0xa2,
0x188: 0xa3, 0x189: 0x1d, 0x18a: 0x1e, 0x18b: 0xa4, 0x18c: 0xa5,
0x191: 0x1f, 0x192: 0x20, 0x193: 0xa6,
0x1a8: 0xa7, 0x1a9: 0xa8, 0x1ab: 0xa9,
0x1b1: 0xaa, 0x1b3: 0xab, 0x1b5: 0xac, 0x1b7: 0xad,
0x1ba: 0xae, 0x1bb: 0xaf, 0x1bc: 0x21, 0x1bd: 0x22, 0x1be: 0x23, 0x1bf: 0xb0,
// Block 0x7, offset 0x1c0
0x1c0: 0xb1, 0x1c1: 0x24, 0x1c2: 0x25, 0x1c3: 0x26, 0x1c4: 0xb2, 0x1c5: 0x27, 0x1c6: 0x28,
0x1c8: 0x29, 0x1c9: 0x2a, 0x1ca: 0x2b, 0x1cb: 0x2c, 0x1cc: 0x2d, 0x1cd: 0x2e, 0x1ce: 0x2f, 0x1cf: 0x30,
// Block 0x8, offset 0x200
0x219: 0xb3, 0x21a: 0xb4, 0x21b: 0xb5, 0x21d: 0xb6, 0x21f: 0xb7,
0x220: 0xb8, 0x223: 0xb9, 0x224: 0xba, 0x225: 0xbb, 0x226: 0xbc, 0x227: 0xbd,
0x22a: 0xbe, 0x22b: 0xbf, 0x22d: 0xc0, 0x22f: 0xc1,
0x230: 0xc2, 0x231: 0xc3, 0x232: 0xc4, 0x233: 0xc5, 0x234: 0xc6, 0x235: 0xc7, 0x236: 0xc8, 0x237: 0xc2,
0x238: 0xc3, 0x239: 0xc4, 0x23a: 0xc5, 0x23b: 0xc6, 0x23c: 0xc7, 0x23d: 0xc8, 0x23e: 0xc2, 0x23f: 0xc3,
// Block 0x9, offset 0x240
0x240: 0xc4, 0x241: 0xc5, 0x242: 0xc6, 0x243: 0xc7, 0x244: 0xc8, 0x245: 0xc2, 0x246: 0xc3, 0x247: 0xc4,
0x248: 0xc5, 0x249: 0xc6, 0x24a: 0xc7, 0x24b: 0xc8, 0x24c: 0xc2, 0x24d: 0xc3, 0x24e: 0xc4, 0x24f: 0xc5,
0x250: 0xc6, 0x251: 0xc7, 0x252: 0xc8, 0x253: 0xc2, 0x254: 0xc3, 0x255: 0xc4, 0x256: 0xc5, 0x257: 0xc6,
0x258: 0xc7, 0x259: 0xc8, 0x25a: 0xc2, 0x25b: 0xc3, 0x25c: 0xc4, 0x25d: 0xc5, 0x25e: 0xc6, 0x25f: 0xc7,
0x260: 0xc8, 0x261: 0xc2, 0x262: 0xc3, 0x263: 0xc4, 0x264: 0xc5, 0x265: 0xc6, 0x266: 0xc7, 0x267: 0xc8,
0x268: 0xc2, 0x269: 0xc3, 0x26a: 0xc4, 0x26b: 0xc5, 0x26c: 0xc6, 0x26d: 0xc7, 0x26e: 0xc8, 0x26f: 0xc2,
0x270: 0xc3, 0x271: 0xc4, 0x272: 0xc5, 0x273: 0xc6, 0x274: 0xc7, 0x275: 0xc8, 0x276: 0xc2, 0x277: 0xc3,
0x278: 0xc4, 0x279: 0xc5, 0x27a: 0xc6, 0x27b: 0xc7, 0x27c: 0xc8, 0x27d: 0xc2, 0x27e: 0xc3, 0x27f: 0xc4,
// Block 0xa, offset 0x280
0x280: 0xc5, 0x281: 0xc6, 0x282: 0xc7, 0x283: 0xc8, 0x284: 0xc2, 0x285: 0xc3, 0x286: 0xc4, 0x287: 0xc5,
0x288: 0xc6, 0x289: 0xc7, 0x28a: 0xc8, 0x28b: 0xc2, 0x28c: 0xc3, 0x28d: 0xc4, 0x28e: 0xc5, 0x28f: 0xc6,
0x290: 0xc7, 0x291: 0xc8, 0x292: 0xc2, 0x293: 0xc3, 0x294: 0xc4, 0x295: 0xc5, 0x296: 0xc6, 0x297: 0xc7,
0x298: 0xc8, 0x299: 0xc2, 0x29a: 0xc3, 0x29b: 0xc4, 0x29c: 0xc5, 0x29d: 0xc6, 0x29e: 0xc7, 0x29f: 0xc8,
0x2a0: 0xc2, 0x2a1: 0xc3, 0x2a2: 0xc4, 0x2a3: 0xc5, 0x2a4: 0xc6, 0x2a5: 0xc7, 0x2a6: 0xc8, 0x2a7: 0xc2,
0x2a8: 0xc3, 0x2a9: 0xc4, 0x2aa: 0xc5, 0x2ab: 0xc6, 0x2ac: 0xc7, 0x2ad: 0xc8, 0x2ae: 0xc2, 0x2af: 0xc3,
0x2b0: 0xc4, 0x2b1: 0xc5, 0x2b2: 0xc6, 0x2b3: 0xc7, 0x2b4: 0xc8, 0x2b5: 0xc2, 0x2b6: 0xc3, 0x2b7: 0xc4,
0x2b8: 0xc5, 0x2b9: 0xc6, 0x2ba: 0xc7, 0x2bb: 0xc8, 0x2bc: 0xc2, 0x2bd: 0xc3, 0x2be: 0xc4, 0x2bf: 0xc5,
// Block 0xb, offset 0x2c0
0x2c0: 0xc6, 0x2c1: 0xc7, 0x2c2: 0xc8, 0x2c3: 0xc2, 0x2c4: 0xc3, 0x2c5: 0xc4, 0x2c6: 0xc5, 0x2c7: 0xc6,
0x2c8: 0xc7, 0x2c9: 0xc8, 0x2ca: 0xc2, 0x2cb: 0xc3, 0x2cc: 0xc4, 0x2cd: 0xc5, 0x2ce: 0xc6, 0x2cf: 0xc7,
0x2d0: 0xc8, 0x2d1: 0xc2, 0x2d2: 0xc3, 0x2d3: 0xc4, 0x2d4: 0xc5, 0x2d5: 0xc6, 0x2d6: 0xc7, 0x2d7: 0xc8,
0x2d8: 0xc2, 0x2d9: 0xc3, 0x2da: 0xc4, 0x2db: 0xc5, 0x2dc: 0xc6, 0x2dd: 0xc7, 0x2de: 0xc9,
// Block 0xc, offset 0x300
0x324: 0x31, 0x325: 0x32, 0x326: 0x33, 0x327: 0x34,
0x328: 0x35, 0x329: 0x36, 0x32a: 0x37, 0x32b: 0x38, 0x32c: 0x39, 0x32d: 0x3a, 0x32e: 0x3b, 0x32f: 0x3c,
0x330: 0x3d, 0x331: 0x3e, 0x332: 0x3f, 0x333: 0x40, 0x334: 0x41, 0x335: 0x42, 0x336: 0x43, 0x337: 0x44,
0x338: 0x45, 0x339: 0x46, 0x33a: 0x47, 0x33b: 0x48, 0x33c: 0xca, 0x33d: 0x49, 0x33e: 0x4a, 0x33f: 0x4b,
// Block 0xd, offset 0x340
0x347: 0xcb,
0x34b: 0xcc, 0x34d: 0xcd,
0x35e: 0x4c,
0x368: 0xce, 0x36b: 0xcf,
0x374: 0xd0,
0x37a: 0xd1, 0x37b: 0xd2, 0x37d: 0xd3, 0x37e: 0xd4,
// Block 0xe, offset 0x380
0x381: 0xd5, 0x382: 0xd6, 0x384: 0xd7, 0x385: 0xbc, 0x387: 0xd8,
0x388: 0xd9, 0x38b: 0xda, 0x38c: 0xdb, 0x38d: 0xdc,
0x391: 0xdd, 0x392: 0xde, 0x393: 0xdf, 0x396: 0xe0, 0x397: 0xe1,
0x398: 0xe2, 0x39a: 0xe3, 0x39c: 0xe4,
0x3a0: 0xe5, 0x3a4: 0xe6, 0x3a5: 0xe7, 0x3a7: 0xe8,
0x3a8: 0xe9, 0x3a9: 0xea, 0x3aa: 0xeb,
0x3b0: 0xe2, 0x3b5: 0xec, 0x3b6: 0xed,
0x3bd: 0xee,
// Block 0xf, offset 0x3c0
0x3eb: 0xef, 0x3ec: 0xf0,
0x3ff: 0xf1,
// Block 0x10, offset 0x400
0x432: 0xf2,
// Block 0x11, offset 0x440
0x445: 0xf3, 0x446: 0xf4, 0x447: 0xf5,
0x449: 0xf6,
0x450: 0xf7, 0x451: 0xf8, 0x452: 0xf9, 0x453: 0xfa, 0x454: 0xfb, 0x455: 0xfc, 0x456: 0xfd, 0x457: 0xfe,
0x458: 0xff, 0x459: 0x100, 0x45a: 0x4d, 0x45b: 0x101, 0x45c: 0x102, 0x45d: 0x103, 0x45e: 0x104, 0x45f: 0x4e,
// Block 0x12, offset 0x480
0x480: 0x4f, 0x481: 0x50, 0x482: 0x105, 0x484: 0xf0,
0x48a: 0x106, 0x48b: 0x107,
0x493: 0x108,
0x4a3: 0x109, 0x4a5: 0x10a,
0x4b8: 0x51, 0x4b9: 0x52, 0x4ba: 0x53,
// Block 0x13, offset 0x4c0
0x4c4: 0x54, 0x4c5: 0x10b, 0x4c6: 0x10c,
0x4c8: 0x55, 0x4c9: 0x10d,
0x4ef: 0x10e,
// Block 0x14, offset 0x500
0x520: 0x56, 0x521: 0x57, 0x522: 0x58, 0x523: 0x59, 0x524: 0x5a, 0x525: 0x5b, 0x526: 0x5c, 0x527: 0x5d,
0x528: 0x5e,
// Block 0x15, offset 0x540
0x550: 0x0b, 0x551: 0x0c, 0x556: 0x0d,
0x55b: 0x0e, 0x55d: 0x0f, 0x55e: 0x10, 0x55f: 0x11,
0x56f: 0x12,
}
// nfkcSparseOffset: 176 entries, 352 bytes
var nfkcSparseOffset = []uint16{0x0, 0xe, 0x12, 0x1c, 0x26, 0x36, 0x38, 0x3d, 0x48, 0x57, 0x64, 0x6c, 0x71, 0x76, 0x78, 0x7c, 0x84, 0x8b, 0x8e, 0x96, 0x9a, 0x9e, 0xa0, 0xa2, 0xab, 0xaf, 0xb6, 0xbb, 0xbe, 0xc8, 0xcb, 0xd2, 0xda, 0xde, 0xe0, 0xe4, 0xe8, 0xee, 0xff, 0x10b, 0x10d, 0x113, 0x115, 0x117, 0x119, 0x11b, 0x11d, 0x11f, 0x121, 0x124, 0x127, 0x129, 0x12c, 0x12f, 0x133, 0x139, 0x140, 0x149, 0x14b, 0x14e, 0x150, 0x15b, 0x166, 0x174, 0x182, 0x192, 0x1a0, 0x1a7, 0x1ad, 0x1bc, 0x1c0, 0x1c2, 0x1c6, 0x1c8, 0x1cb, 0x1cd, 0x1d0, 0x1d2, 0x1d5, 0x1d7, 0x1d9, 0x1db, 0x1e7, 0x1f1, 0x1fb, 0x1fe, 0x202, 0x204, 0x206, 0x20b, 0x20e, 0x211, 0x213, 0x215, 0x217, 0x219, 0x21f, 0x222, 0x227, 0x229, 0x230, 0x236, 0x23c, 0x244, 0x24a, 0x250, 0x256, 0x25a, 0x25c, 0x25e, 0x260, 0x262, 0x268, 0x26b, 0x26d, 0x26f, 0x271, 0x277, 0x27b, 0x27f, 0x287, 0x28e, 0x291, 0x294, 0x296, 0x299, 0x2a1, 0x2a5, 0x2ac, 0x2af, 0x2b5, 0x2b7, 0x2b9, 0x2bc, 0x2be, 0x2c1, 0x2c6, 0x2c8, 0x2ca, 0x2cc, 0x2ce, 0x2d0, 0x2d3, 0x2d5, 0x2d7, 0x2d9, 0x2db, 0x2dd, 0x2df, 0x2ec, 0x2f6, 0x2f8, 0x2fa, 0x2fe, 0x303, 0x30f, 0x314, 0x31d, 0x323, 0x328, 0x32c, 0x331, 0x335, 0x345, 0x353, 0x361, 0x36f, 0x371, 0x373, 0x375, 0x379, 0x37b, 0x37e, 0x389, 0x38b, 0x395}
// nfkcSparseValues: 919 entries, 3676 bytes
var nfkcSparseValues = [919]valueRange{
// Block 0x0, offset 0x0
{value: 0x0002, lo: 0x0d},
{value: 0x0001, lo: 0xa0, hi: 0xa0},
{value: 0x43b9, lo: 0xa8, hi: 0xa8},
{value: 0x0083, lo: 0xaa, hi: 0xaa},
{value: 0x43a5, lo: 0xaf, hi: 0xaf},
{value: 0x0025, lo: 0xb2, hi: 0xb3},
{value: 0x439b, lo: 0xb4, hi: 0xb4},
{value: 0x0260, lo: 0xb5, hi: 0xb5},
{value: 0x43d2, lo: 0xb8, hi: 0xb8},
{value: 0x0023, lo: 0xb9, hi: 0xb9},
{value: 0x009f, lo: 0xba, hi: 0xba},
{value: 0x234c, lo: 0xbc, hi: 0xbc},
{value: 0x2340, lo: 0xbd, hi: 0xbd},
{value: 0x23e2, lo: 0xbe, hi: 0xbe},
// Block 0x1, offset 0xe
{value: 0x0091, lo: 0x03},
{value: 0x4823, lo: 0xa0, hi: 0xa1},
{value: 0x4855, lo: 0xaf, hi: 0xb0},
{value: 0xa000, lo: 0xb7, hi: 0xb7},
// Block 0x2, offset 0x12
{value: 0x0004, lo: 0x09},
{value: 0xa000, lo: 0x92, hi: 0x92},
{value: 0x0091, lo: 0xb0, hi: 0xb0},
{value: 0x0140, lo: 0xb1, hi: 0xb1},
{value: 0x0095, lo: 0xb2, hi: 0xb2},
{value: 0x00a5, lo: 0xb3, hi: 0xb3},
{value: 0x0179, lo: 0xb4, hi: 0xb4},
{value: 0x017f, lo: 0xb5, hi: 0xb5},
{value: 0x018b, lo: 0xb6, hi: 0xb6},
{value: 0x00af, lo: 0xb7, hi: 0xb8},
// Block 0x3, offset 0x1c
{value: 0x000a, lo: 0x09},
{value: 0x43af, lo: 0x98, hi: 0x98},
{value: 0x43b4, lo: 0x99, hi: 0x9a},
{value: 0x43d7, lo: 0x9b, hi: 0x9b},
{value: 0x43a0, lo: 0x9c, hi: 0x9c},
{value: 0x43c3, lo: 0x9d, hi: 0x9d},
{value: 0x0137, lo: 0xa0, hi: 0xa0},
{value: 0x0099, lo: 0xa1, hi: 0xa1},
{value: 0x00a7, lo: 0xa2, hi: 0xa3},
{value: 0x01b8, lo: 0xa4, hi: 0xa4},
// Block 0x4, offset 0x26
{value: 0x0000, lo: 0x0f},
{value: 0xa000, lo: 0x83, hi: 0x83},
{value: 0xa000, lo: 0x87, hi: 0x87},
{value: 0xa000, lo: 0x8b, hi: 0x8b},
{value: 0xa000, lo: 0x8d, hi: 0x8d},
{value: 0x38e6, lo: 0x90, hi: 0x90},
{value: 0x38f2, lo: 0x91, hi: 0x91},
{value: 0x38e0, lo: 0x93, hi: 0x93},
{value: 0xa000, lo: 0x96, hi: 0x96},
{value: 0x3958, lo: 0x97, hi: 0x97},
{value: 0x3922, lo: 0x9c, hi: 0x9c},
{value: 0x390a, lo: 0x9d, hi: 0x9d},
{value: 0x3934, lo: 0x9e, hi: 0x9e},
{value: 0xa000, lo: 0xb4, hi: 0xb5},
{value: 0x395e, lo: 0xb6, hi: 0xb6},
{value: 0x3964, lo: 0xb7, hi: 0xb7},
// Block 0x5, offset 0x36
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0x83, hi: 0x87},
// Block 0x6, offset 0x38
{value: 0x0001, lo: 0x04},
{value: 0x8114, lo: 0x81, hi: 0x82},
{value: 0x8133, lo: 0x84, hi: 0x84},
{value: 0x812e, lo: 0x85, hi: 0x85},
{value: 0x810e, lo: 0x87, hi: 0x87},
// Block 0x7, offset 0x3d
{value: 0x0000, lo: 0x0a},
{value: 0x8133, lo: 0x90, hi: 0x97},
{value: 0x811a, lo: 0x98, hi: 0x98},
{value: 0x811b, lo: 0x99, hi: 0x99},
{value: 0x811c, lo: 0x9a, hi: 0x9a},
{value: 0x3982, lo: 0xa2, hi: 0xa2},
{value: 0x3988, lo: 0xa3, hi: 0xa3},
{value: 0x3994, lo: 0xa4, hi: 0xa4},
{value: 0x398e, lo: 0xa5, hi: 0xa5},
{value: 0x399a, lo: 0xa6, hi: 0xa6},
{value: 0xa000, lo: 0xa7, hi: 0xa7},
// Block 0x8, offset 0x48
{value: 0x0000, lo: 0x0e},
{value: 0x39ac, lo: 0x80, hi: 0x80},
{value: 0xa000, lo: 0x81, hi: 0x81},
{value: 0x39a0, lo: 0x82, hi: 0x82},
{value: 0xa000, lo: 0x92, hi: 0x92},
{value: 0x39a6, lo: 0x93, hi: 0x93},
{value: 0xa000, lo: 0x95, hi: 0x95},
{value: 0x8133, lo: 0x96, hi: 0x9c},
{value: 0x8133, lo: 0x9f, hi: 0xa2},
{value: 0x812e, lo: 0xa3, hi: 0xa3},
{value: 0x8133, lo: 0xa4, hi: 0xa4},
{value: 0x8133, lo: 0xa7, hi: 0xa8},
{value: 0x812e, lo: 0xaa, hi: 0xaa},
{value: 0x8133, lo: 0xab, hi: 0xac},
{value: 0x812e, lo: 0xad, hi: 0xad},
// Block 0x9, offset 0x57
{value: 0x0000, lo: 0x0c},
{value: 0x8120, lo: 0x91, hi: 0x91},
{value: 0x8133, lo: 0xb0, hi: 0xb0},
{value: 0x812e, lo: 0xb1, hi: 0xb1},
{value: 0x8133, lo: 0xb2, hi: 0xb3},
{value: 0x812e, lo: 0xb4, hi: 0xb4},
{value: 0x8133, lo: 0xb5, hi: 0xb6},
{value: 0x812e, lo: 0xb7, hi: 0xb9},
{value: 0x8133, lo: 0xba, hi: 0xba},
{value: 0x812e, lo: 0xbb, hi: 0xbc},
{value: 0x8133, lo: 0xbd, hi: 0xbd},
{value: 0x812e, lo: 0xbe, hi: 0xbe},
{value: 0x8133, lo: 0xbf, hi: 0xbf},
// Block 0xa, offset 0x64
{value: 0x0005, lo: 0x07},
{value: 0x8133, lo: 0x80, hi: 0x80},
{value: 0x8133, lo: 0x81, hi: 0x81},
{value: 0x812e, lo: 0x82, hi: 0x83},
{value: 0x812e, lo: 0x84, hi: 0x85},
{value: 0x812e, lo: 0x86, hi: 0x87},
{value: 0x812e, lo: 0x88, hi: 0x89},
{value: 0x8133, lo: 0x8a, hi: 0x8a},
// Block 0xb, offset 0x6c
{value: 0x0000, lo: 0x04},
{value: 0x8133, lo: 0xab, hi: 0xb1},
{value: 0x812e, lo: 0xb2, hi: 0xb2},
{value: 0x8133, lo: 0xb3, hi: 0xb3},
{value: 0x812e, lo: 0xbd, hi: 0xbd},
// Block 0xc, offset 0x71
{value: 0x0000, lo: 0x04},
{value: 0x8133, lo: 0x96, hi: 0x99},
{value: 0x8133, lo: 0x9b, hi: 0xa3},
{value: 0x8133, lo: 0xa5, hi: 0xa7},
{value: 0x8133, lo: 0xa9, hi: 0xad},
// Block 0xd, offset 0x76
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0x99, hi: 0x9b},
// Block 0xe, offset 0x78
{value: 0x0000, lo: 0x03},
{value: 0x8133, lo: 0x98, hi: 0x98},
{value: 0x812e, lo: 0x99, hi: 0x9b},
{value: 0x8133, lo: 0x9c, hi: 0x9f},
// Block 0xf, offset 0x7c
{value: 0x0000, lo: 0x07},
{value: 0xa000, lo: 0xa8, hi: 0xa8},
{value: 0x4019, lo: 0xa9, hi: 0xa9},
{value: 0xa000, lo: 0xb0, hi: 0xb0},
{value: 0x4021, lo: 0xb1, hi: 0xb1},
{value: 0xa000, lo: 0xb3, hi: 0xb3},
{value: 0x4029, lo: 0xb4, hi: 0xb4},
{value: 0x9903, lo: 0xbc, hi: 0xbc},
// Block 0x10, offset 0x84
{value: 0x0008, lo: 0x06},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x8133, lo: 0x91, hi: 0x91},
{value: 0x812e, lo: 0x92, hi: 0x92},
{value: 0x8133, lo: 0x93, hi: 0x93},
{value: 0x8133, lo: 0x94, hi: 0x94},
{value: 0x465d, lo: 0x98, hi: 0x9f},
// Block 0x11, offset 0x8b
{value: 0x0000, lo: 0x02},
{value: 0x8103, lo: 0xbc, hi: 0xbc},
{value: 0x9900, lo: 0xbe, hi: 0xbe},
// Block 0x12, offset 0x8e
{value: 0x0008, lo: 0x07},
{value: 0xa000, lo: 0x87, hi: 0x87},
{value: 0x2dd5, lo: 0x8b, hi: 0x8c},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x9900, lo: 0x97, hi: 0x97},
{value: 0x469d, lo: 0x9c, hi: 0x9d},
{value: 0x46ad, lo: 0x9f, hi: 0x9f},
{value: 0x8133, lo: 0xbe, hi: 0xbe},
// Block 0x13, offset 0x96
{value: 0x0000, lo: 0x03},
{value: 0x46d5, lo: 0xb3, hi: 0xb3},
{value: 0x46dd, lo: 0xb6, hi: 0xb6},
{value: 0x8103, lo: 0xbc, hi: 0xbc},
// Block 0x14, offset 0x9a
{value: 0x0008, lo: 0x03},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x46b5, lo: 0x99, hi: 0x9b},
{value: 0x46cd, lo: 0x9e, hi: 0x9e},
// Block 0x15, offset 0x9e
{value: 0x0000, lo: 0x01},
{value: 0x8103, lo: 0xbc, hi: 0xbc},
// Block 0x16, offset 0xa0
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
// Block 0x17, offset 0xa2
{value: 0x0000, lo: 0x08},
{value: 0xa000, lo: 0x87, hi: 0x87},
{value: 0x2ded, lo: 0x88, hi: 0x88},
{value: 0x2de5, lo: 0x8b, hi: 0x8b},
{value: 0x2df5, lo: 0x8c, hi: 0x8c},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x9900, lo: 0x96, hi: 0x97},
{value: 0x46e5, lo: 0x9c, hi: 0x9c},
{value: 0x46ed, lo: 0x9d, hi: 0x9d},
// Block 0x18, offset 0xab
{value: 0x0000, lo: 0x03},
{value: 0xa000, lo: 0x92, hi: 0x92},
{value: 0x2dfd, lo: 0x94, hi: 0x94},
{value: 0x9900, lo: 0xbe, hi: 0xbe},
// Block 0x19, offset 0xaf
{value: 0x0000, lo: 0x06},
{value: 0xa000, lo: 0x86, hi: 0x87},
{value: 0x2e05, lo: 0x8a, hi: 0x8a},
{value: 0x2e15, lo: 0x8b, hi: 0x8b},
{value: 0x2e0d, lo: 0x8c, hi: 0x8c},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x9900, lo: 0x97, hi: 0x97},
// Block 0x1a, offset 0xb6
{value: 0x1801, lo: 0x04},
{value: 0xa000, lo: 0x86, hi: 0x86},
{value: 0x4031, lo: 0x88, hi: 0x88},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x8121, lo: 0x95, hi: 0x96},
// Block 0x1b, offset 0xbb
{value: 0x0000, lo: 0x02},
{value: 0x8103, lo: 0xbc, hi: 0xbc},
{value: 0xa000, lo: 0xbf, hi: 0xbf},
// Block 0x1c, offset 0xbe
{value: 0x0000, lo: 0x09},
{value: 0x2e1d, lo: 0x80, hi: 0x80},
{value: 0x9900, lo: 0x82, hi: 0x82},
{value: 0xa000, lo: 0x86, hi: 0x86},
{value: 0x2e25, lo: 0x87, hi: 0x87},
{value: 0x2e2d, lo: 0x88, hi: 0x88},
{value: 0x3091, lo: 0x8a, hi: 0x8a},
{value: 0x2f19, lo: 0x8b, hi: 0x8b},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x9900, lo: 0x95, hi: 0x96},
// Block 0x1d, offset 0xc8
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0xbb, hi: 0xbc},
{value: 0x9900, lo: 0xbe, hi: 0xbe},
// Block 0x1e, offset 0xcb
{value: 0x0000, lo: 0x06},
{value: 0xa000, lo: 0x86, hi: 0x87},
{value: 0x2e35, lo: 0x8a, hi: 0x8a},
{value: 0x2e45, lo: 0x8b, hi: 0x8b},
{value: 0x2e3d, lo: 0x8c, hi: 0x8c},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x9900, lo: 0x97, hi: 0x97},
// Block 0x1f, offset 0xd2
{value: 0x6ab3, lo: 0x07},
{value: 0x9905, lo: 0x8a, hi: 0x8a},
{value: 0x9900, lo: 0x8f, hi: 0x8f},
{value: 0xa000, lo: 0x99, hi: 0x99},
{value: 0x4039, lo: 0x9a, hi: 0x9a},
{value: 0x3099, lo: 0x9c, hi: 0x9c},
{value: 0x2f24, lo: 0x9d, hi: 0x9d},
{value: 0x2e4d, lo: 0x9e, hi: 0x9f},
// Block 0x20, offset 0xda
{value: 0x0000, lo: 0x03},
{value: 0x2751, lo: 0xb3, hi: 0xb3},
{value: 0x8123, lo: 0xb8, hi: 0xb9},
{value: 0x8105, lo: 0xba, hi: 0xba},
// Block 0x21, offset 0xde
{value: 0x0000, lo: 0x01},
{value: 0x8124, lo: 0x88, hi: 0x8b},
// Block 0x22, offset 0xe0
{value: 0x0000, lo: 0x03},
{value: 0x2766, lo: 0xb3, hi: 0xb3},
{value: 0x8125, lo: 0xb8, hi: 0xb9},
{value: 0x8105, lo: 0xba, hi: 0xba},
// Block 0x23, offset 0xe4
{value: 0x0000, lo: 0x03},
{value: 0x8126, lo: 0x88, hi: 0x8b},
{value: 0x2758, lo: 0x9c, hi: 0x9c},
{value: 0x275f, lo: 0x9d, hi: 0x9d},
// Block 0x24, offset 0xe8
{value: 0x0000, lo: 0x05},
{value: 0x03fe, lo: 0x8c, hi: 0x8c},
{value: 0x812e, lo: 0x98, hi: 0x99},
{value: 0x812e, lo: 0xb5, hi: 0xb5},
{value: 0x812e, lo: 0xb7, hi: 0xb7},
{value: 0x812c, lo: 0xb9, hi: 0xb9},
// Block 0x25, offset 0xee
{value: 0x0000, lo: 0x10},
{value: 0x2774, lo: 0x83, hi: 0x83},
{value: 0x277b, lo: 0x8d, hi: 0x8d},
{value: 0x2782, lo: 0x92, hi: 0x92},
{value: 0x2789, lo: 0x97, hi: 0x97},
{value: 0x2790, lo: 0x9c, hi: 0x9c},
{value: 0x276d, lo: 0xa9, hi: 0xa9},
{value: 0x8127, lo: 0xb1, hi: 0xb1},
{value: 0x8128, lo: 0xb2, hi: 0xb2},
{value: 0x4bc5, lo: 0xb3, hi: 0xb3},
{value: 0x8129, lo: 0xb4, hi: 0xb4},
{value: 0x4bce, lo: 0xb5, hi: 0xb5},
{value: 0x46f5, lo: 0xb6, hi: 0xb6},
{value: 0x4735, lo: 0xb7, hi: 0xb7},
{value: 0x46fd, lo: 0xb8, hi: 0xb8},
{value: 0x4740, lo: 0xb9, hi: 0xb9},
{value: 0x8128, lo: 0xba, hi: 0xbd},
// Block 0x26, offset 0xff
{value: 0x0000, lo: 0x0b},
{value: 0x8128, lo: 0x80, hi: 0x80},
{value: 0x4bd7, lo: 0x81, hi: 0x81},
{value: 0x8133, lo: 0x82, hi: 0x83},
{value: 0x8105, lo: 0x84, hi: 0x84},
{value: 0x8133, lo: 0x86, hi: 0x87},
{value: 0x279e, lo: 0x93, hi: 0x93},
{value: 0x27a5, lo: 0x9d, hi: 0x9d},
{value: 0x27ac, lo: 0xa2, hi: 0xa2},
{value: 0x27b3, lo: 0xa7, hi: 0xa7},
{value: 0x27ba, lo: 0xac, hi: 0xac},
{value: 0x2797, lo: 0xb9, hi: 0xb9},
// Block 0x27, offset 0x10b
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0x86, hi: 0x86},
// Block 0x28, offset 0x10d
{value: 0x0000, lo: 0x05},
{value: 0xa000, lo: 0xa5, hi: 0xa5},
{value: 0x2e55, lo: 0xa6, hi: 0xa6},
{value: 0x9900, lo: 0xae, hi: 0xae},
{value: 0x8103, lo: 0xb7, hi: 0xb7},
{value: 0x8105, lo: 0xb9, hi: 0xba},
// Block 0x29, offset 0x113
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0x8d, hi: 0x8d},
// Block 0x2a, offset 0x115
{value: 0x0000, lo: 0x01},
{value: 0x0402, lo: 0xbc, hi: 0xbc},
// Block 0x2b, offset 0x117
{value: 0x0000, lo: 0x01},
{value: 0xa000, lo: 0x80, hi: 0x92},
// Block 0x2c, offset 0x119
{value: 0x0000, lo: 0x01},
{value: 0xb900, lo: 0xa1, hi: 0xb5},
// Block 0x2d, offset 0x11b
{value: 0x0000, lo: 0x01},
{value: 0x9900, lo: 0xa8, hi: 0xbf},
// Block 0x2e, offset 0x11d
{value: 0x0000, lo: 0x01},
{value: 0x9900, lo: 0x80, hi: 0x82},
// Block 0x2f, offset 0x11f
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0x9d, hi: 0x9f},
// Block 0x30, offset 0x121
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0x94, hi: 0x95},
{value: 0x8105, lo: 0xb4, hi: 0xb4},
// Block 0x31, offset 0x124
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0x92, hi: 0x92},
{value: 0x8133, lo: 0x9d, hi: 0x9d},
// Block 0x32, offset 0x127
{value: 0x0000, lo: 0x01},
{value: 0x8132, lo: 0xa9, hi: 0xa9},
// Block 0x33, offset 0x129
{value: 0x0004, lo: 0x02},
{value: 0x812f, lo: 0xb9, hi: 0xba},
{value: 0x812e, lo: 0xbb, hi: 0xbb},
// Block 0x34, offset 0x12c
{value: 0x0000, lo: 0x02},
{value: 0x8133, lo: 0x97, hi: 0x97},
{value: 0x812e, lo: 0x98, hi: 0x98},
// Block 0x35, offset 0x12f
{value: 0x0000, lo: 0x03},
{value: 0x8105, lo: 0xa0, hi: 0xa0},
{value: 0x8133, lo: 0xb5, hi: 0xbc},
{value: 0x812e, lo: 0xbf, hi: 0xbf},
// Block 0x36, offset 0x133
{value: 0x0000, lo: 0x05},
{value: 0x8133, lo: 0xb0, hi: 0xb4},
{value: 0x812e, lo: 0xb5, hi: 0xba},
{value: 0x8133, lo: 0xbb, hi: 0xbc},
{value: 0x812e, lo: 0xbd, hi: 0xbd},
{value: 0x812e, lo: 0xbf, hi: 0xbf},
// Block 0x37, offset 0x139
{value: 0x0000, lo: 0x06},
{value: 0x812e, lo: 0x80, hi: 0x80},
{value: 0x8133, lo: 0x81, hi: 0x82},
{value: 0x812e, lo: 0x83, hi: 0x84},
{value: 0x8133, lo: 0x85, hi: 0x89},
{value: 0x812e, lo: 0x8a, hi: 0x8a},
{value: 0x8133, lo: 0x8b, hi: 0x8e},
// Block 0x38, offset 0x140
{value: 0x0000, lo: 0x08},
{value: 0x2e9d, lo: 0x80, hi: 0x80},
{value: 0x2ea5, lo: 0x81, hi: 0x81},
{value: 0xa000, lo: 0x82, hi: 0x82},
{value: 0x2ead, lo: 0x83, hi: 0x83},
{value: 0x8105, lo: 0x84, hi: 0x84},
{value: 0x8133, lo: 0xab, hi: 0xab},
{value: 0x812e, lo: 0xac, hi: 0xac},
{value: 0x8133, lo: 0xad, hi: 0xb3},
// Block 0x39, offset 0x149
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xaa, hi: 0xab},
// Block 0x3a, offset 0x14b
{value: 0x0000, lo: 0x02},
{value: 0x8103, lo: 0xa6, hi: 0xa6},
{value: 0x8105, lo: 0xb2, hi: 0xb3},
// Block 0x3b, offset 0x14e
{value: 0x0000, lo: 0x01},
{value: 0x8103, lo: 0xb7, hi: 0xb7},
// Block 0x3c, offset 0x150
{value: 0x0000, lo: 0x0a},
{value: 0x8133, lo: 0x90, hi: 0x92},
{value: 0x8101, lo: 0x94, hi: 0x94},
{value: 0x812e, lo: 0x95, hi: 0x99},
{value: 0x8133, lo: 0x9a, hi: 0x9b},
{value: 0x812e, lo: 0x9c, hi: 0x9f},
{value: 0x8133, lo: 0xa0, hi: 0xa0},
{value: 0x8101, lo: 0xa2, hi: 0xa8},
{value: 0x812e, lo: 0xad, hi: 0xad},
{value: 0x8133, lo: 0xb4, hi: 0xb4},
{value: 0x8133, lo: 0xb8, hi: 0xb9},
// Block 0x3d, offset 0x15b
{value: 0x0002, lo: 0x0a},
{value: 0x0043, lo: 0xac, hi: 0xac},
{value: 0x00d1, lo: 0xad, hi: 0xad},
{value: 0x0045, lo: 0xae, hi: 0xae},
{value: 0x0049, lo: 0xb0, hi: 0xb1},
{value: 0x00ec, lo: 0xb2, hi: 0xb2},
{value: 0x004f, lo: 0xb3, hi: 0xba},
{value: 0x005f, lo: 0xbc, hi: 0xbc},
{value: 0x00fe, lo: 0xbd, hi: 0xbd},
{value: 0x0061, lo: 0xbe, hi: 0xbe},
{value: 0x0065, lo: 0xbf, hi: 0xbf},
// Block 0x3e, offset 0x166
{value: 0x0000, lo: 0x0d},
{value: 0x0001, lo: 0x80, hi: 0x8a},
{value: 0x0532, lo: 0x91, hi: 0x91},
{value: 0x43dc, lo: 0x97, hi: 0x97},
{value: 0x001d, lo: 0xa4, hi: 0xa4},
{value: 0x19a0, lo: 0xa5, hi: 0xa5},
{value: 0x1c8c, lo: 0xa6, hi: 0xa6},
{value: 0x0001, lo: 0xaf, hi: 0xaf},
{value: 0x27c1, lo: 0xb3, hi: 0xb3},
{value: 0x2935, lo: 0xb4, hi: 0xb4},
{value: 0x27c8, lo: 0xb6, hi: 0xb6},
{value: 0x293f, lo: 0xb7, hi: 0xb7},
{value: 0x199a, lo: 0xbc, hi: 0xbc},
{value: 0x43aa, lo: 0xbe, hi: 0xbe},
// Block 0x3f, offset 0x174
{value: 0x0002, lo: 0x0d},
{value: 0x1a60, lo: 0x87, hi: 0x87},
{value: 0x1a5d, lo: 0x88, hi: 0x88},
{value: 0x199d, lo: 0x89, hi: 0x89},
{value: 0x2ac5, lo: 0x97, hi: 0x97},
{value: 0x0001, lo: 0x9f, hi: 0x9f},
{value: 0x0021, lo: 0xb0, hi: 0xb0},
{value: 0x0093, lo: 0xb1, hi: 0xb1},
{value: 0x0029, lo: 0xb4, hi: 0xb9},
{value: 0x0017, lo: 0xba, hi: 0xba},
{value: 0x055e, lo: 0xbb, hi: 0xbb},
{value: 0x003b, lo: 0xbc, hi: 0xbc},
{value: 0x0011, lo: 0xbd, hi: 0xbe},
{value: 0x009d, lo: 0xbf, hi: 0xbf},
// Block 0x40, offset 0x182
{value: 0x0002, lo: 0x0f},
{value: 0x0021, lo: 0x80, hi: 0x89},
{value: 0x0017, lo: 0x8a, hi: 0x8a},
{value: 0x055e, lo: 0x8b, hi: 0x8b},
{value: 0x003b, lo: 0x8c, hi: 0x8c},
{value: 0x0011, lo: 0x8d, hi: 0x8e},
{value: 0x0083, lo: 0x90, hi: 0x90},
{value: 0x008b, lo: 0x91, hi: 0x91},
{value: 0x009f, lo: 0x92, hi: 0x92},
{value: 0x00b1, lo: 0x93, hi: 0x93},
{value: 0x011f, lo: 0x94, hi: 0x94},
{value: 0x0091, lo: 0x95, hi: 0x95},
{value: 0x0097, lo: 0x96, hi: 0x99},
{value: 0x00a1, lo: 0x9a, hi: 0x9a},
{value: 0x00a7, lo: 0x9b, hi: 0x9c},
{value: 0x1ac9, lo: 0xa8, hi: 0xa8},
// Block 0x41, offset 0x192
{value: 0x0000, lo: 0x0d},
{value: 0x8133, lo: 0x90, hi: 0x91},
{value: 0x8101, lo: 0x92, hi: 0x93},
{value: 0x8133, lo: 0x94, hi: 0x97},
{value: 0x8101, lo: 0x98, hi: 0x9a},
{value: 0x8133, lo: 0x9b, hi: 0x9c},
{value: 0x8133, lo: 0xa1, hi: 0xa1},
{value: 0x8101, lo: 0xa5, hi: 0xa6},
{value: 0x8133, lo: 0xa7, hi: 0xa7},
{value: 0x812e, lo: 0xa8, hi: 0xa8},
{value: 0x8133, lo: 0xa9, hi: 0xa9},
{value: 0x8101, lo: 0xaa, hi: 0xab},
{value: 0x812e, lo: 0xac, hi: 0xaf},
{value: 0x8133, lo: 0xb0, hi: 0xb0},
// Block 0x42, offset 0x1a0
{value: 0x0007, lo: 0x06},
{value: 0x22b0, lo: 0x89, hi: 0x89},
{value: 0xa000, lo: 0x90, hi: 0x90},
{value: 0xa000, lo: 0x92, hi: 0x92},
{value: 0xa000, lo: 0x94, hi: 0x94},
{value: 0x3cfa, lo: 0x9a, hi: 0x9b},
{value: 0x3d08, lo: 0xae, hi: 0xae},
// Block 0x43, offset 0x1a7
{value: 0x000e, lo: 0x05},
{value: 0x3d0f, lo: 0x8d, hi: 0x8e},
{value: 0x3d16, lo: 0x8f, hi: 0x8f},
{value: 0xa000, lo: 0x90, hi: 0x90},
{value: 0xa000, lo: 0x92, hi: 0x92},
{value: 0xa000, lo: 0x94, hi: 0x94},
// Block 0x44, offset 0x1ad
{value: 0x017a, lo: 0x0e},
{value: 0xa000, lo: 0x83, hi: 0x83},
{value: 0x3d24, lo: 0x84, hi: 0x84},
{value: 0xa000, lo: 0x88, hi: 0x88},
{value: 0x3d2b, lo: 0x89, hi: 0x89},
{value: 0xa000, lo: 0x8b, hi: 0x8b},
{value: 0x3d32, lo: 0x8c, hi: 0x8c},
{value: 0xa000, lo: 0xa3, hi: 0xa3},
{value: 0x3d39, lo: 0xa4, hi: 0xa4},
{value: 0xa000, lo: 0xa5, hi: 0xa5},
{value: 0x3d40, lo: 0xa6, hi: 0xa6},
{value: 0x27cf, lo: 0xac, hi: 0xad},
{value: 0x27d6, lo: 0xaf, hi: 0xaf},
{value: 0x2953, lo: 0xb0, hi: 0xb0},
{value: 0xa000, lo: 0xbc, hi: 0xbc},
// Block 0x45, offset 0x1bc
{value: 0x0007, lo: 0x03},
{value: 0x3da9, lo: 0xa0, hi: 0xa1},
{value: 0x3dd3, lo: 0xa2, hi: 0xa3},
{value: 0x3dfd, lo: 0xaa, hi: 0xad},
// Block 0x46, offset 0x1c0
{value: 0x0004, lo: 0x01},
{value: 0x0586, lo: 0xa9, hi: 0xaa},
// Block 0x47, offset 0x1c2
{value: 0x0002, lo: 0x03},
{value: 0x0057, lo: 0x80, hi: 0x8f},
{value: 0x0083, lo: 0x90, hi: 0xa9},
{value: 0x0021, lo: 0xaa, hi: 0xaa},
// Block 0x48, offset 0x1c6
{value: 0x0000, lo: 0x01},
{value: 0x2ad2, lo: 0x8c, hi: 0x8c},
// Block 0x49, offset 0x1c8
{value: 0x0266, lo: 0x02},
{value: 0x1cbc, lo: 0xb4, hi: 0xb4},
{value: 0x1a5a, lo: 0xb5, hi: 0xb6},
// Block 0x4a, offset 0x1cb
{value: 0x0000, lo: 0x01},
{value: 0x461e, lo: 0x9c, hi: 0x9c},
// Block 0x4b, offset 0x1cd
{value: 0x0000, lo: 0x02},
{value: 0x0095, lo: 0xbc, hi: 0xbc},
{value: 0x006d, lo: 0xbd, hi: 0xbd},
// Block 0x4c, offset 0x1d0
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xaf, hi: 0xb1},
// Block 0x4d, offset 0x1d2
{value: 0x0000, lo: 0x02},
{value: 0x057a, lo: 0xaf, hi: 0xaf},
{value: 0x8105, lo: 0xbf, hi: 0xbf},
// Block 0x4e, offset 0x1d5
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xa0, hi: 0xbf},
// Block 0x4f, offset 0x1d7
{value: 0x0000, lo: 0x01},
{value: 0x0ebe, lo: 0x9f, hi: 0x9f},
// Block 0x50, offset 0x1d9
{value: 0x0000, lo: 0x01},
{value: 0x172a, lo: 0xb3, hi: 0xb3},
// Block 0x51, offset 0x1db
{value: 0x0004, lo: 0x0b},
{value: 0x1692, lo: 0x80, hi: 0x82},
{value: 0x16aa, lo: 0x83, hi: 0x83},
{value: 0x16c2, lo: 0x84, hi: 0x85},
{value: 0x16d2, lo: 0x86, hi: 0x89},
{value: 0x16e6, lo: 0x8a, hi: 0x8c},
{value: 0x16fa, lo: 0x8d, hi: 0x8d},
{value: 0x1702, lo: 0x8e, hi: 0x8e},
{value: 0x170a, lo: 0x8f, hi: 0x90},
{value: 0x1716, lo: 0x91, hi: 0x93},
{value: 0x1726, lo: 0x94, hi: 0x94},
{value: 0x172e, lo: 0x95, hi: 0x95},
// Block 0x52, offset 0x1e7
{value: 0x0004, lo: 0x09},
{value: 0x0001, lo: 0x80, hi: 0x80},
{value: 0x812d, lo: 0xaa, hi: 0xaa},
{value: 0x8132, lo: 0xab, hi: 0xab},
{value: 0x8134, lo: 0xac, hi: 0xac},
{value: 0x812f, lo: 0xad, hi: 0xad},
{value: 0x8130, lo: 0xae, hi: 0xae},
{value: 0x8130, lo: 0xaf, hi: 0xaf},
{value: 0x05ae, lo: 0xb6, hi: 0xb6},
{value: 0x0982, lo: 0xb8, hi: 0xba},
// Block 0x53, offset 0x1f1
{value: 0x0006, lo: 0x09},
{value: 0x0406, lo: 0xb1, hi: 0xb1},
{value: 0x040a, lo: 0xb2, hi: 0xb2},
{value: 0x4b7c, lo: 0xb3, hi: 0xb3},
{value: 0x040e, lo: 0xb4, hi: 0xb4},
{value: 0x4b82, lo: 0xb5, hi: 0xb6},
{value: 0x0412, lo: 0xb7, hi: 0xb7},
{value: 0x0416, lo: 0xb8, hi: 0xb8},
{value: 0x041a, lo: 0xb9, hi: 0xb9},
{value: 0x4b8e, lo: 0xba, hi: 0xbf},
// Block 0x54, offset 0x1fb
{value: 0x0000, lo: 0x02},
{value: 0x8133, lo: 0xaf, hi: 0xaf},
{value: 0x8133, lo: 0xb4, hi: 0xbd},
// Block 0x55, offset 0x1fe
{value: 0x0000, lo: 0x03},
{value: 0x02d8, lo: 0x9c, hi: 0x9c},
{value: 0x02de, lo: 0x9d, hi: 0x9d},
{value: 0x8133, lo: 0x9e, hi: 0x9f},
// Block 0x56, offset 0x202
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xb0, hi: 0xb1},
// Block 0x57, offset 0x204
{value: 0x0000, lo: 0x01},
{value: 0x173e, lo: 0xb0, hi: 0xb0},
// Block 0x58, offset 0x206
{value: 0x0006, lo: 0x04},
{value: 0x0047, lo: 0xb2, hi: 0xb3},
{value: 0x0063, lo: 0xb4, hi: 0xb4},
{value: 0x00dd, lo: 0xb8, hi: 0xb8},
{value: 0x00e9, lo: 0xb9, hi: 0xb9},
// Block 0x59, offset 0x20b
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0x86, hi: 0x86},
{value: 0x8105, lo: 0xac, hi: 0xac},
// Block 0x5a, offset 0x20e
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0x84, hi: 0x84},
{value: 0x8133, lo: 0xa0, hi: 0xb1},
// Block 0x5b, offset 0x211
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0xab, hi: 0xad},
// Block 0x5c, offset 0x213
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x93, hi: 0x93},
// Block 0x5d, offset 0x215
{value: 0x0000, lo: 0x01},
{value: 0x8103, lo: 0xb3, hi: 0xb3},
// Block 0x5e, offset 0x217
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x80, hi: 0x80},
// Block 0x5f, offset 0x219
{value: 0x0000, lo: 0x05},
{value: 0x8133, lo: 0xb0, hi: 0xb0},
{value: 0x8133, lo: 0xb2, hi: 0xb3},
{value: 0x812e, lo: 0xb4, hi: 0xb4},
{value: 0x8133, lo: 0xb7, hi: 0xb8},
{value: 0x8133, lo: 0xbe, hi: 0xbf},
// Block 0x60, offset 0x21f
{value: 0x0000, lo: 0x02},
{value: 0x8133, lo: 0x81, hi: 0x81},
{value: 0x8105, lo: 0xb6, hi: 0xb6},
// Block 0x61, offset 0x222
{value: 0x000c, lo: 0x04},
{value: 0x173a, lo: 0x9c, hi: 0x9d},
{value: 0x014f, lo: 0x9e, hi: 0x9e},
{value: 0x174a, lo: 0x9f, hi: 0x9f},
{value: 0x01a6, lo: 0xa9, hi: 0xa9},
// Block 0x62, offset 0x227
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xad, hi: 0xad},
// Block 0x63, offset 0x229
{value: 0x0000, lo: 0x06},
{value: 0xe500, lo: 0x80, hi: 0x80},
{value: 0xc600, lo: 0x81, hi: 0x9b},
{value: 0xe500, lo: 0x9c, hi: 0x9c},
{value: 0xc600, lo: 0x9d, hi: 0xb7},
{value: 0xe500, lo: 0xb8, hi: 0xb8},
{value: 0xc600, lo: 0xb9, hi: 0xbf},
// Block 0x64, offset 0x230
{value: 0x0000, lo: 0x05},
{value: 0xc600, lo: 0x80, hi: 0x93},
{value: 0xe500, lo: 0x94, hi: 0x94},
{value: 0xc600, lo: 0x95, hi: 0xaf},
{value: 0xe500, lo: 0xb0, hi: 0xb0},
{value: 0xc600, lo: 0xb1, hi: 0xbf},
// Block 0x65, offset 0x236
{value: 0x0000, lo: 0x05},
{value: 0xc600, lo: 0x80, hi: 0x8b},
{value: 0xe500, lo: 0x8c, hi: 0x8c},
{value: 0xc600, lo: 0x8d, hi: 0xa7},
{value: 0xe500, lo: 0xa8, hi: 0xa8},
{value: 0xc600, lo: 0xa9, hi: 0xbf},
// Block 0x66, offset 0x23c
{value: 0x0000, lo: 0x07},
{value: 0xc600, lo: 0x80, hi: 0x83},
{value: 0xe500, lo: 0x84, hi: 0x84},
{value: 0xc600, lo: 0x85, hi: 0x9f},
{value: 0xe500, lo: 0xa0, hi: 0xa0},
{value: 0xc600, lo: 0xa1, hi: 0xbb},
{value: 0xe500, lo: 0xbc, hi: 0xbc},
{value: 0xc600, lo: 0xbd, hi: 0xbf},
// Block 0x67, offset 0x244
{value: 0x0000, lo: 0x05},
{value: 0xc600, lo: 0x80, hi: 0x97},
{value: 0xe500, lo: 0x98, hi: 0x98},
{value: 0xc600, lo: 0x99, hi: 0xb3},
{value: 0xe500, lo: 0xb4, hi: 0xb4},
{value: 0xc600, lo: 0xb5, hi: 0xbf},
// Block 0x68, offset 0x24a
{value: 0x0000, lo: 0x05},
{value: 0xc600, lo: 0x80, hi: 0x8f},
{value: 0xe500, lo: 0x90, hi: 0x90},
{value: 0xc600, lo: 0x91, hi: 0xab},
{value: 0xe500, lo: 0xac, hi: 0xac},
{value: 0xc600, lo: 0xad, hi: 0xbf},
// Block 0x69, offset 0x250
{value: 0x0000, lo: 0x05},
{value: 0xc600, lo: 0x80, hi: 0x87},
{value: 0xe500, lo: 0x88, hi: 0x88},
{value: 0xc600, lo: 0x89, hi: 0xa3},
{value: 0xe500, lo: 0xa4, hi: 0xa4},
{value: 0xc600, lo: 0xa5, hi: 0xbf},
// Block 0x6a, offset 0x256
{value: 0x0000, lo: 0x03},
{value: 0xc600, lo: 0x80, hi: 0x87},
{value: 0xe500, lo: 0x88, hi: 0x88},
{value: 0xc600, lo: 0x89, hi: 0xa3},
// Block 0x6b, offset 0x25a
{value: 0x0002, lo: 0x01},
{value: 0x0003, lo: 0x81, hi: 0xbf},
// Block 0x6c, offset 0x25c
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0xbd, hi: 0xbd},
// Block 0x6d, offset 0x25e
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0xa0, hi: 0xa0},
// Block 0x6e, offset 0x260
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xb6, hi: 0xba},
// Block 0x6f, offset 0x262
{value: 0x002d, lo: 0x05},
{value: 0x812e, lo: 0x8d, hi: 0x8d},
{value: 0x8133, lo: 0x8f, hi: 0x8f},
{value: 0x8133, lo: 0xb8, hi: 0xb8},
{value: 0x8101, lo: 0xb9, hi: 0xba},
{value: 0x8105, lo: 0xbf, hi: 0xbf},
// Block 0x70, offset 0x268
{value: 0x0000, lo: 0x02},
{value: 0x8133, lo: 0xa5, hi: 0xa5},
{value: 0x812e, lo: 0xa6, hi: 0xa6},
// Block 0x71, offset 0x26b
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xa4, hi: 0xa7},
// Block 0x72, offset 0x26d
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xab, hi: 0xac},
// Block 0x73, offset 0x26f
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0xbd, hi: 0xbf},
// Block 0x74, offset 0x271
{value: 0x0000, lo: 0x05},
{value: 0x812e, lo: 0x86, hi: 0x87},
{value: 0x8133, lo: 0x88, hi: 0x8a},
{value: 0x812e, lo: 0x8b, hi: 0x8b},
{value: 0x8133, lo: 0x8c, hi: 0x8c},
{value: 0x812e, lo: 0x8d, hi: 0x90},
// Block 0x75, offset 0x277
{value: 0x0005, lo: 0x03},
{value: 0x8133, lo: 0x82, hi: 0x82},
{value: 0x812e, lo: 0x83, hi: 0x84},
{value: 0x812e, lo: 0x85, hi: 0x85},
// Block 0x76, offset 0x27b
{value: 0x0000, lo: 0x03},
{value: 0x8105, lo: 0x86, hi: 0x86},
{value: 0x8105, lo: 0xb0, hi: 0xb0},
{value: 0x8105, lo: 0xbf, hi: 0xbf},
// Block 0x77, offset 0x27f
{value: 0x17fe, lo: 0x07},
{value: 0xa000, lo: 0x99, hi: 0x99},
{value: 0x4379, lo: 0x9a, hi: 0x9a},
{value: 0xa000, lo: 0x9b, hi: 0x9b},
{value: 0x4383, lo: 0x9c, hi: 0x9c},
{value: 0xa000, lo: 0xa5, hi: 0xa5},
{value: 0x438d, lo: 0xab, hi: 0xab},
{value: 0x8105, lo: 0xb9, hi: 0xba},
// Block 0x78, offset 0x287
{value: 0x0000, lo: 0x06},
{value: 0x8133, lo: 0x80, hi: 0x82},
{value: 0x9900, lo: 0xa7, hi: 0xa7},
{value: 0x2eb5, lo: 0xae, hi: 0xae},
{value: 0x2ebf, lo: 0xaf, hi: 0xaf},
{value: 0xa000, lo: 0xb1, hi: 0xb2},
{value: 0x8105, lo: 0xb3, hi: 0xb4},
// Block 0x79, offset 0x28e
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0x80, hi: 0x80},
{value: 0x8103, lo: 0x8a, hi: 0x8a},
// Block 0x7a, offset 0x291
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0xb5, hi: 0xb5},
{value: 0x8103, lo: 0xb6, hi: 0xb6},
// Block 0x7b, offset 0x294
{value: 0x0002, lo: 0x01},
{value: 0x8103, lo: 0xa9, hi: 0xaa},
// Block 0x7c, offset 0x296
{value: 0x0000, lo: 0x02},
{value: 0x8103, lo: 0xbb, hi: 0xbc},
{value: 0x9900, lo: 0xbe, hi: 0xbe},
// Block 0x7d, offset 0x299
{value: 0x0000, lo: 0x07},
{value: 0xa000, lo: 0x87, hi: 0x87},
{value: 0x2ec9, lo: 0x8b, hi: 0x8b},
{value: 0x2ed3, lo: 0x8c, hi: 0x8c},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x9900, lo: 0x97, hi: 0x97},
{value: 0x8133, lo: 0xa6, hi: 0xac},
{value: 0x8133, lo: 0xb0, hi: 0xb4},
// Block 0x7e, offset 0x2a1
{value: 0x0000, lo: 0x03},
{value: 0x8105, lo: 0x82, hi: 0x82},
{value: 0x8103, lo: 0x86, hi: 0x86},
{value: 0x8133, lo: 0x9e, hi: 0x9e},
// Block 0x7f, offset 0x2a5
{value: 0x6a23, lo: 0x06},
{value: 0x9900, lo: 0xb0, hi: 0xb0},
{value: 0xa000, lo: 0xb9, hi: 0xb9},
{value: 0x9900, lo: 0xba, hi: 0xba},
{value: 0x2ee7, lo: 0xbb, hi: 0xbb},
{value: 0x2edd, lo: 0xbc, hi: 0xbd},
{value: 0x2ef1, lo: 0xbe, hi: 0xbe},
// Block 0x80, offset 0x2ac
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0x82, hi: 0x82},
{value: 0x8103, lo: 0x83, hi: 0x83},
// Block 0x81, offset 0x2af
{value: 0x0000, lo: 0x05},
{value: 0x9900, lo: 0xaf, hi: 0xaf},
{value: 0xa000, lo: 0xb8, hi: 0xb9},
{value: 0x2efb, lo: 0xba, hi: 0xba},
{value: 0x2f05, lo: 0xbb, hi: 0xbb},
{value: 0x8105, lo: 0xbf, hi: 0xbf},
// Block 0x82, offset 0x2b5
{value: 0x0000, lo: 0x01},
{value: 0x8103, lo: 0x80, hi: 0x80},
// Block 0x83, offset 0x2b7
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xbf, hi: 0xbf},
// Block 0x84, offset 0x2b9
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0xb6, hi: 0xb6},
{value: 0x8103, lo: 0xb7, hi: 0xb7},
// Block 0x85, offset 0x2bc
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xab, hi: 0xab},
// Block 0x86, offset 0x2be
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0xb9, hi: 0xb9},
{value: 0x8103, lo: 0xba, hi: 0xba},
// Block 0x87, offset 0x2c1
{value: 0x0000, lo: 0x04},
{value: 0x9900, lo: 0xb0, hi: 0xb0},
{value: 0xa000, lo: 0xb5, hi: 0xb5},
{value: 0x2f0f, lo: 0xb8, hi: 0xb8},
{value: 0x8105, lo: 0xbd, hi: 0xbe},
// Block 0x88, offset 0x2c6
{value: 0x0000, lo: 0x01},
{value: 0x8103, lo: 0x83, hi: 0x83},
// Block 0x89, offset 0x2c8
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xa0, hi: 0xa0},
// Block 0x8a, offset 0x2ca
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xb4, hi: 0xb4},
// Block 0x8b, offset 0x2cc
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x87, hi: 0x87},
// Block 0x8c, offset 0x2ce
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x99, hi: 0x99},
// Block 0x8d, offset 0x2d0
{value: 0x0000, lo: 0x02},
{value: 0x8103, lo: 0x82, hi: 0x82},
{value: 0x8105, lo: 0x84, hi: 0x85},
// Block 0x8e, offset 0x2d3
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x97, hi: 0x97},
// Block 0x8f, offset 0x2d5
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x81, hi: 0x82},
// Block 0x90, offset 0x2d7
{value: 0x0000, lo: 0x01},
{value: 0x8101, lo: 0xb0, hi: 0xb4},
// Block 0x91, offset 0x2d9
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xb0, hi: 0xb6},
// Block 0x92, offset 0x2db
{value: 0x0000, lo: 0x01},
{value: 0x8102, lo: 0xb0, hi: 0xb1},
// Block 0x93, offset 0x2dd
{value: 0x0000, lo: 0x01},
{value: 0x8101, lo: 0x9e, hi: 0x9e},
// Block 0x94, offset 0x2df
{value: 0x0000, lo: 0x0c},
{value: 0x470d, lo: 0x9e, hi: 0x9e},
{value: 0x4717, lo: 0x9f, hi: 0x9f},
{value: 0x474b, lo: 0xa0, hi: 0xa0},
{value: 0x4759, lo: 0xa1, hi: 0xa1},
{value: 0x4767, lo: 0xa2, hi: 0xa2},
{value: 0x4775, lo: 0xa3, hi: 0xa3},
{value: 0x4783, lo: 0xa4, hi: 0xa4},
{value: 0x812c, lo: 0xa5, hi: 0xa6},
{value: 0x8101, lo: 0xa7, hi: 0xa9},
{value: 0x8131, lo: 0xad, hi: 0xad},
{value: 0x812c, lo: 0xae, hi: 0xb2},
{value: 0x812e, lo: 0xbb, hi: 0xbf},
// Block 0x95, offset 0x2ec
{value: 0x0000, lo: 0x09},
{value: 0x812e, lo: 0x80, hi: 0x82},
{value: 0x8133, lo: 0x85, hi: 0x89},
{value: 0x812e, lo: 0x8a, hi: 0x8b},
{value: 0x8133, lo: 0xaa, hi: 0xad},
{value: 0x4721, lo: 0xbb, hi: 0xbb},
{value: 0x472b, lo: 0xbc, hi: 0xbc},
{value: 0x4791, lo: 0xbd, hi: 0xbd},
{value: 0x47ad, lo: 0xbe, hi: 0xbe},
{value: 0x479f, lo: 0xbf, hi: 0xbf},
// Block 0x96, offset 0x2f6
{value: 0x0000, lo: 0x01},
{value: 0x47bb, lo: 0x80, hi: 0x80},
// Block 0x97, offset 0x2f8
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0x82, hi: 0x84},
// Block 0x98, offset 0x2fa
{value: 0x0002, lo: 0x03},
{value: 0x0043, lo: 0x80, hi: 0x99},
{value: 0x0083, lo: 0x9a, hi: 0xb3},
{value: 0x0043, lo: 0xb4, hi: 0xbf},
// Block 0x99, offset 0x2fe
{value: 0x0002, lo: 0x04},
{value: 0x005b, lo: 0x80, hi: 0x8d},
{value: 0x0083, lo: 0x8e, hi: 0x94},
{value: 0x0093, lo: 0x96, hi: 0xa7},
{value: 0x0043, lo: 0xa8, hi: 0xbf},
// Block 0x9a, offset 0x303
{value: 0x0002, lo: 0x0b},
{value: 0x0073, lo: 0x80, hi: 0x81},
{value: 0x0083, lo: 0x82, hi: 0x9b},
{value: 0x0043, lo: 0x9c, hi: 0x9c},
{value: 0x0047, lo: 0x9e, hi: 0x9f},
{value: 0x004f, lo: 0xa2, hi: 0xa2},
{value: 0x0055, lo: 0xa5, hi: 0xa6},
{value: 0x005d, lo: 0xa9, hi: 0xac},
{value: 0x0067, lo: 0xae, hi: 0xb5},
{value: 0x0083, lo: 0xb6, hi: 0xb9},
{value: 0x008d, lo: 0xbb, hi: 0xbb},
{value: 0x0091, lo: 0xbd, hi: 0xbf},
// Block 0x9b, offset 0x30f
{value: 0x0002, lo: 0x04},
{value: 0x0097, lo: 0x80, hi: 0x83},
{value: 0x00a1, lo: 0x85, hi: 0x8f},
{value: 0x0043, lo: 0x90, hi: 0xa9},
{value: 0x0083, lo: 0xaa, hi: 0xbf},
// Block 0x9c, offset 0x314
{value: 0x0002, lo: 0x08},
{value: 0x00af, lo: 0x80, hi: 0x83},
{value: 0x0043, lo: 0x84, hi: 0x85},
{value: 0x0049, lo: 0x87, hi: 0x8a},
{value: 0x0055, lo: 0x8d, hi: 0x94},
{value: 0x0067, lo: 0x96, hi: 0x9c},
{value: 0x0083, lo: 0x9e, hi: 0xb7},
{value: 0x0043, lo: 0xb8, hi: 0xb9},
{value: 0x0049, lo: 0xbb, hi: 0xbe},
// Block 0x9d, offset 0x31d
{value: 0x0002, lo: 0x05},
{value: 0x0053, lo: 0x80, hi: 0x84},
{value: 0x005f, lo: 0x86, hi: 0x86},
{value: 0x0067, lo: 0x8a, hi: 0x90},
{value: 0x0083, lo: 0x92, hi: 0xab},
{value: 0x0043, lo: 0xac, hi: 0xbf},
// Block 0x9e, offset 0x323
{value: 0x0002, lo: 0x04},
{value: 0x006b, lo: 0x80, hi: 0x85},
{value: 0x0083, lo: 0x86, hi: 0x9f},
{value: 0x0043, lo: 0xa0, hi: 0xb9},
{value: 0x0083, lo: 0xba, hi: 0xbf},
// Block 0x9f, offset 0x328
{value: 0x0002, lo: 0x03},
{value: 0x008f, lo: 0x80, hi: 0x93},
{value: 0x0043, lo: 0x94, hi: 0xad},
{value: 0x0083, lo: 0xae, hi: 0xbf},
// Block 0xa0, offset 0x32c
{value: 0x0002, lo: 0x04},
{value: 0x00a7, lo: 0x80, hi: 0x87},
{value: 0x0043, lo: 0x88, hi: 0xa1},
{value: 0x0083, lo: 0xa2, hi: 0xbb},
{value: 0x0043, lo: 0xbc, hi: 0xbf},
// Block 0xa1, offset 0x331
{value: 0x0002, lo: 0x03},
{value: 0x004b, lo: 0x80, hi: 0x95},
{value: 0x0083, lo: 0x96, hi: 0xaf},
{value: 0x0043, lo: 0xb0, hi: 0xbf},
// Block 0xa2, offset 0x335
{value: 0x0003, lo: 0x0f},
{value: 0x023c, lo: 0x80, hi: 0x80},
{value: 0x0556, lo: 0x81, hi: 0x81},
{value: 0x023f, lo: 0x82, hi: 0x9a},
{value: 0x0552, lo: 0x9b, hi: 0x9b},
{value: 0x024b, lo: 0x9c, hi: 0x9c},
{value: 0x0254, lo: 0x9d, hi: 0x9d},
{value: 0x025a, lo: 0x9e, hi: 0x9e},
{value: 0x027e, lo: 0x9f, hi: 0x9f},
{value: 0x026f, lo: 0xa0, hi: 0xa0},
{value: 0x026c, lo: 0xa1, hi: 0xa1},
{value: 0x01f7, lo: 0xa2, hi: 0xb2},
{value: 0x020c, lo: 0xb3, hi: 0xb3},
{value: 0x022a, lo: 0xb4, hi: 0xba},
{value: 0x0556, lo: 0xbb, hi: 0xbb},
{value: 0x023f, lo: 0xbc, hi: 0xbf},
// Block 0xa3, offset 0x345
{value: 0x0003, lo: 0x0d},
{value: 0x024b, lo: 0x80, hi: 0x94},
{value: 0x0552, lo: 0x95, hi: 0x95},
{value: 0x024b, lo: 0x96, hi: 0x96},
{value: 0x0254, lo: 0x97, hi: 0x97},
{value: 0x025a, lo: 0x98, hi: 0x98},
{value: 0x027e, lo: 0x99, hi: 0x99},
{value: 0x026f, lo: 0x9a, hi: 0x9a},
{value: 0x026c, lo: 0x9b, hi: 0x9b},
{value: 0x01f7, lo: 0x9c, hi: 0xac},
{value: 0x020c, lo: 0xad, hi: 0xad},
{value: 0x022a, lo: 0xae, hi: 0xb4},
{value: 0x0556, lo: 0xb5, hi: 0xb5},
{value: 0x023f, lo: 0xb6, hi: 0xbf},
// Block 0xa4, offset 0x353
{value: 0x0003, lo: 0x0d},
{value: 0x025d, lo: 0x80, hi: 0x8e},
{value: 0x0552, lo: 0x8f, hi: 0x8f},
{value: 0x024b, lo: 0x90, hi: 0x90},
{value: 0x0254, lo: 0x91, hi: 0x91},
{value: 0x025a, lo: 0x92, hi: 0x92},
{value: 0x027e, lo: 0x93, hi: 0x93},
{value: 0x026f, lo: 0x94, hi: 0x94},
{value: 0x026c, lo: 0x95, hi: 0x95},
{value: 0x01f7, lo: 0x96, hi: 0xa6},
{value: 0x020c, lo: 0xa7, hi: 0xa7},
{value: 0x022a, lo: 0xa8, hi: 0xae},
{value: 0x0556, lo: 0xaf, hi: 0xaf},
{value: 0x023f, lo: 0xb0, hi: 0xbf},
// Block 0xa5, offset 0x361
{value: 0x0003, lo: 0x0d},
{value: 0x026f, lo: 0x80, hi: 0x88},
{value: 0x0552, lo: 0x89, hi: 0x89},
{value: 0x024b, lo: 0x8a, hi: 0x8a},
{value: 0x0254, lo: 0x8b, hi: 0x8b},
{value: 0x025a, lo: 0x8c, hi: 0x8c},
{value: 0x027e, lo: 0x8d, hi: 0x8d},
{value: 0x026f, lo: 0x8e, hi: 0x8e},
{value: 0x026c, lo: 0x8f, hi: 0x8f},
{value: 0x01f7, lo: 0x90, hi: 0xa0},
{value: 0x020c, lo: 0xa1, hi: 0xa1},
{value: 0x022a, lo: 0xa2, hi: 0xa8},
{value: 0x0556, lo: 0xa9, hi: 0xa9},
{value: 0x023f, lo: 0xaa, hi: 0xbf},
// Block 0xa6, offset 0x36f
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0x8f, hi: 0x8f},
// Block 0xa7, offset 0x371
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xae, hi: 0xae},
// Block 0xa8, offset 0x373
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xac, hi: 0xaf},
// Block 0xa9, offset 0x375
{value: 0x0000, lo: 0x03},
{value: 0x8134, lo: 0xac, hi: 0xad},
{value: 0x812e, lo: 0xae, hi: 0xae},
{value: 0x8133, lo: 0xaf, hi: 0xaf},
// Block 0xaa, offset 0x379
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0x90, hi: 0x96},
// Block 0xab, offset 0x37b
{value: 0x0000, lo: 0x02},
{value: 0x8133, lo: 0x84, hi: 0x89},
{value: 0x8103, lo: 0x8a, hi: 0x8a},
// Block 0xac, offset 0x37e
{value: 0x0002, lo: 0x0a},
{value: 0x0063, lo: 0x80, hi: 0x89},
{value: 0x1a7e, lo: 0x8a, hi: 0x8a},
{value: 0x1ab1, lo: 0x8b, hi: 0x8b},
{value: 0x1acc, lo: 0x8c, hi: 0x8c},
{value: 0x1ad2, lo: 0x8d, hi: 0x8d},
{value: 0x1cf0, lo: 0x8e, hi: 0x8e},
{value: 0x1ade, lo: 0x8f, hi: 0x8f},
{value: 0x1aa8, lo: 0xaa, hi: 0xaa},
{value: 0x1aab, lo: 0xab, hi: 0xab},
{value: 0x1aae, lo: 0xac, hi: 0xac},
// Block 0xad, offset 0x389
{value: 0x0000, lo: 0x01},
{value: 0x1a6c, lo: 0x90, hi: 0x90},
// Block 0xae, offset 0x38b
{value: 0x0028, lo: 0x09},
{value: 0x2999, lo: 0x80, hi: 0x80},
{value: 0x295d, lo: 0x81, hi: 0x81},
{value: 0x2967, lo: 0x82, hi: 0x82},
{value: 0x297b, lo: 0x83, hi: 0x84},
{value: 0x2985, lo: 0x85, hi: 0x86},
{value: 0x2971, lo: 0x87, hi: 0x87},
{value: 0x298f, lo: 0x88, hi: 0x88},
{value: 0x0c6a, lo: 0x90, hi: 0x90},
{value: 0x09e2, lo: 0x91, hi: 0x91},
// Block 0xaf, offset 0x395
{value: 0x0002, lo: 0x01},
{value: 0x0021, lo: 0xb0, hi: 0xb9},
}
// recompMap: 7528 bytes (entries only)
var recompMap map[uint32]rune
var recompMapOnce sync.Once
const recompMapPacked = "" +
"\x00A\x03\x00\x00\x00\x00\xc0" + // 0x00410300: 0x000000C0
"\x00A\x03\x01\x00\x00\x00\xc1" + // 0x00410301: 0x000000C1
"\x00A\x03\x02\x00\x00\x00\xc2" + // 0x00410302: 0x000000C2
"\x00A\x03\x03\x00\x00\x00\xc3" + // 0x00410303: 0x000000C3
"\x00A\x03\b\x00\x00\x00\xc4" + // 0x00410308: 0x000000C4
"\x00A\x03\n\x00\x00\x00\xc5" + // 0x0041030A: 0x000000C5
"\x00C\x03'\x00\x00\x00\xc7" + // 0x00430327: 0x000000C7
"\x00E\x03\x00\x00\x00\x00\xc8" + // 0x00450300: 0x000000C8
"\x00E\x03\x01\x00\x00\x00\xc9" + // 0x00450301: 0x000000C9
"\x00E\x03\x02\x00\x00\x00\xca" + // 0x00450302: 0x000000CA
"\x00E\x03\b\x00\x00\x00\xcb" + // 0x00450308: 0x000000CB
"\x00I\x03\x00\x00\x00\x00\xcc" + // 0x00490300: 0x000000CC
"\x00I\x03\x01\x00\x00\x00\xcd" + // 0x00490301: 0x000000CD
"\x00I\x03\x02\x00\x00\x00\xce" + // 0x00490302: 0x000000CE
"\x00I\x03\b\x00\x00\x00\xcf" + // 0x00490308: 0x000000CF
"\x00N\x03\x03\x00\x00\x00\xd1" + // 0x004E0303: 0x000000D1
"\x00O\x03\x00\x00\x00\x00\xd2" + // 0x004F0300: 0x000000D2
"\x00O\x03\x01\x00\x00\x00\xd3" + // 0x004F0301: 0x000000D3
"\x00O\x03\x02\x00\x00\x00\xd4" + // 0x004F0302: 0x000000D4
"\x00O\x03\x03\x00\x00\x00\xd5" + // 0x004F0303: 0x000000D5
"\x00O\x03\b\x00\x00\x00\xd6" + // 0x004F0308: 0x000000D6
"\x00U\x03\x00\x00\x00\x00\xd9" + // 0x00550300: 0x000000D9
"\x00U\x03\x01\x00\x00\x00\xda" + // 0x00550301: 0x000000DA
"\x00U\x03\x02\x00\x00\x00\xdb" + // 0x00550302: 0x000000DB
"\x00U\x03\b\x00\x00\x00\xdc" + // 0x00550308: 0x000000DC
"\x00Y\x03\x01\x00\x00\x00\xdd" + // 0x00590301: 0x000000DD
"\x00a\x03\x00\x00\x00\x00\xe0" + // 0x00610300: 0x000000E0
"\x00a\x03\x01\x00\x00\x00\xe1" + // 0x00610301: 0x000000E1
"\x00a\x03\x02\x00\x00\x00\xe2" + // 0x00610302: 0x000000E2
"\x00a\x03\x03\x00\x00\x00\xe3" + // 0x00610303: 0x000000E3
"\x00a\x03\b\x00\x00\x00\xe4" + // 0x00610308: 0x000000E4
"\x00a\x03\n\x00\x00\x00\xe5" + // 0x0061030A: 0x000000E5
"\x00c\x03'\x00\x00\x00\xe7" + // 0x00630327: 0x000000E7
"\x00e\x03\x00\x00\x00\x00\xe8" + // 0x00650300: 0x000000E8
"\x00e\x03\x01\x00\x00\x00\xe9" + // 0x00650301: 0x000000E9
"\x00e\x03\x02\x00\x00\x00\xea" + // 0x00650302: 0x000000EA
"\x00e\x03\b\x00\x00\x00\xeb" + // 0x00650308: 0x000000EB
"\x00i\x03\x00\x00\x00\x00\xec" + // 0x00690300: 0x000000EC
"\x00i\x03\x01\x00\x00\x00\xed" + // 0x00690301: 0x000000ED
"\x00i\x03\x02\x00\x00\x00\xee" + // 0x00690302: 0x000000EE
"\x00i\x03\b\x00\x00\x00\xef" + // 0x00690308: 0x000000EF
"\x00n\x03\x03\x00\x00\x00\xf1" + // 0x006E0303: 0x000000F1
"\x00o\x03\x00\x00\x00\x00\xf2" + // 0x006F0300: 0x000000F2
"\x00o\x03\x01\x00\x00\x00\xf3" + // 0x006F0301: 0x000000F3
"\x00o\x03\x02\x00\x00\x00\xf4" + // 0x006F0302: 0x000000F4
"\x00o\x03\x03\x00\x00\x00\xf5" + // 0x006F0303: 0x000000F5
"\x00o\x03\b\x00\x00\x00\xf6" + // 0x006F0308: 0x000000F6
"\x00u\x03\x00\x00\x00\x00\xf9" + // 0x00750300: 0x000000F9
"\x00u\x03\x01\x00\x00\x00\xfa" + // 0x00750301: 0x000000FA
"\x00u\x03\x02\x00\x00\x00\xfb" + // 0x00750302: 0x000000FB
"\x00u\x03\b\x00\x00\x00\xfc" + // 0x00750308: 0x000000FC
"\x00y\x03\x01\x00\x00\x00\xfd" + // 0x00790301: 0x000000FD
"\x00y\x03\b\x00\x00\x00\xff" + // 0x00790308: 0x000000FF
"\x00A\x03\x04\x00\x00\x01\x00" + // 0x00410304: 0x00000100
"\x00a\x03\x04\x00\x00\x01\x01" + // 0x00610304: 0x00000101
"\x00A\x03\x06\x00\x00\x01\x02" + // 0x00410306: 0x00000102
"\x00a\x03\x06\x00\x00\x01\x03" + // 0x00610306: 0x00000103
"\x00A\x03(\x00\x00\x01\x04" + // 0x00410328: 0x00000104
"\x00a\x03(\x00\x00\x01\x05" + // 0x00610328: 0x00000105
"\x00C\x03\x01\x00\x00\x01\x06" + // 0x00430301: 0x00000106
"\x00c\x03\x01\x00\x00\x01\a" + // 0x00630301: 0x00000107
"\x00C\x03\x02\x00\x00\x01\b" + // 0x00430302: 0x00000108
"\x00c\x03\x02\x00\x00\x01\t" + // 0x00630302: 0x00000109
"\x00C\x03\a\x00\x00\x01\n" + // 0x00430307: 0x0000010A
"\x00c\x03\a\x00\x00\x01\v" + // 0x00630307: 0x0000010B
"\x00C\x03\f\x00\x00\x01\f" + // 0x0043030C: 0x0000010C
"\x00c\x03\f\x00\x00\x01\r" + // 0x0063030C: 0x0000010D
"\x00D\x03\f\x00\x00\x01\x0e" + // 0x0044030C: 0x0000010E
"\x00d\x03\f\x00\x00\x01\x0f" + // 0x0064030C: 0x0000010F
"\x00E\x03\x04\x00\x00\x01\x12" + // 0x00450304: 0x00000112
"\x00e\x03\x04\x00\x00\x01\x13" + // 0x00650304: 0x00000113
"\x00E\x03\x06\x00\x00\x01\x14" + // 0x00450306: 0x00000114
"\x00e\x03\x06\x00\x00\x01\x15" + // 0x00650306: 0x00000115
"\x00E\x03\a\x00\x00\x01\x16" + // 0x00450307: 0x00000116
"\x00e\x03\a\x00\x00\x01\x17" + // 0x00650307: 0x00000117
"\x00E\x03(\x00\x00\x01\x18" + // 0x00450328: 0x00000118
"\x00e\x03(\x00\x00\x01\x19" + // 0x00650328: 0x00000119
"\x00E\x03\f\x00\x00\x01\x1a" + // 0x0045030C: 0x0000011A
"\x00e\x03\f\x00\x00\x01\x1b" + // 0x0065030C: 0x0000011B
"\x00G\x03\x02\x00\x00\x01\x1c" + // 0x00470302: 0x0000011C
"\x00g\x03\x02\x00\x00\x01\x1d" + // 0x00670302: 0x0000011D
"\x00G\x03\x06\x00\x00\x01\x1e" + // 0x00470306: 0x0000011E
"\x00g\x03\x06\x00\x00\x01\x1f" + // 0x00670306: 0x0000011F
"\x00G\x03\a\x00\x00\x01 " + // 0x00470307: 0x00000120
"\x00g\x03\a\x00\x00\x01!" + // 0x00670307: 0x00000121
"\x00G\x03'\x00\x00\x01\"" + // 0x00470327: 0x00000122
"\x00g\x03'\x00\x00\x01#" + // 0x00670327: 0x00000123
"\x00H\x03\x02\x00\x00\x01$" + // 0x00480302: 0x00000124
"\x00h\x03\x02\x00\x00\x01%" + // 0x00680302: 0x00000125
"\x00I\x03\x03\x00\x00\x01(" + // 0x00490303: 0x00000128
"\x00i\x03\x03\x00\x00\x01)" + // 0x00690303: 0x00000129
"\x00I\x03\x04\x00\x00\x01*" + // 0x00490304: 0x0000012A
"\x00i\x03\x04\x00\x00\x01+" + // 0x00690304: 0x0000012B
"\x00I\x03\x06\x00\x00\x01," + // 0x00490306: 0x0000012C
"\x00i\x03\x06\x00\x00\x01-" + // 0x00690306: 0x0000012D
"\x00I\x03(\x00\x00\x01." + // 0x00490328: 0x0000012E
"\x00i\x03(\x00\x00\x01/" + // 0x00690328: 0x0000012F
"\x00I\x03\a\x00\x00\x010" + // 0x00490307: 0x00000130
"\x00J\x03\x02\x00\x00\x014" + // 0x004A0302: 0x00000134
"\x00j\x03\x02\x00\x00\x015" + // 0x006A0302: 0x00000135
"\x00K\x03'\x00\x00\x016" + // 0x004B0327: 0x00000136
"\x00k\x03'\x00\x00\x017" + // 0x006B0327: 0x00000137
"\x00L\x03\x01\x00\x00\x019" + // 0x004C0301: 0x00000139
"\x00l\x03\x01\x00\x00\x01:" + // 0x006C0301: 0x0000013A
"\x00L\x03'\x00\x00\x01;" + // 0x004C0327: 0x0000013B
"\x00l\x03'\x00\x00\x01<" + // 0x006C0327: 0x0000013C
"\x00L\x03\f\x00\x00\x01=" + // 0x004C030C: 0x0000013D
"\x00l\x03\f\x00\x00\x01>" + // 0x006C030C: 0x0000013E
"\x00N\x03\x01\x00\x00\x01C" + // 0x004E0301: 0x00000143
"\x00n\x03\x01\x00\x00\x01D" + // 0x006E0301: 0x00000144
"\x00N\x03'\x00\x00\x01E" + // 0x004E0327: 0x00000145
"\x00n\x03'\x00\x00\x01F" + // 0x006E0327: 0x00000146
"\x00N\x03\f\x00\x00\x01G" + // 0x004E030C: 0x00000147
"\x00n\x03\f\x00\x00\x01H" + // 0x006E030C: 0x00000148
"\x00O\x03\x04\x00\x00\x01L" + // 0x004F0304: 0x0000014C
"\x00o\x03\x04\x00\x00\x01M" + // 0x006F0304: 0x0000014D
"\x00O\x03\x06\x00\x00\x01N" + // 0x004F0306: 0x0000014E
"\x00o\x03\x06\x00\x00\x01O" + // 0x006F0306: 0x0000014F
"\x00O\x03\v\x00\x00\x01P" + // 0x004F030B: 0x00000150
"\x00o\x03\v\x00\x00\x01Q" + // 0x006F030B: 0x00000151
"\x00R\x03\x01\x00\x00\x01T" + // 0x00520301: 0x00000154
"\x00r\x03\x01\x00\x00\x01U" + // 0x00720301: 0x00000155
"\x00R\x03'\x00\x00\x01V" + // 0x00520327: 0x00000156
"\x00r\x03'\x00\x00\x01W" + // 0x00720327: 0x00000157
"\x00R\x03\f\x00\x00\x01X" + // 0x0052030C: 0x00000158
"\x00r\x03\f\x00\x00\x01Y" + // 0x0072030C: 0x00000159
"\x00S\x03\x01\x00\x00\x01Z" + // 0x00530301: 0x0000015A
"\x00s\x03\x01\x00\x00\x01[" + // 0x00730301: 0x0000015B
"\x00S\x03\x02\x00\x00\x01\\" + // 0x00530302: 0x0000015C
"\x00s\x03\x02\x00\x00\x01]" + // 0x00730302: 0x0000015D
"\x00S\x03'\x00\x00\x01^" + // 0x00530327: 0x0000015E
"\x00s\x03'\x00\x00\x01_" + // 0x00730327: 0x0000015F
"\x00S\x03\f\x00\x00\x01`" + // 0x0053030C: 0x00000160
"\x00s\x03\f\x00\x00\x01a" + // 0x0073030C: 0x00000161
"\x00T\x03'\x00\x00\x01b" + // 0x00540327: 0x00000162
"\x00t\x03'\x00\x00\x01c" + // 0x00740327: 0x00000163
"\x00T\x03\f\x00\x00\x01d" + // 0x0054030C: 0x00000164
"\x00t\x03\f\x00\x00\x01e" + // 0x0074030C: 0x00000165
"\x00U\x03\x03\x00\x00\x01h" + // 0x00550303: 0x00000168
"\x00u\x03\x03\x00\x00\x01i" + // 0x00750303: 0x00000169
"\x00U\x03\x04\x00\x00\x01j" + // 0x00550304: 0x0000016A
"\x00u\x03\x04\x00\x00\x01k" + // 0x00750304: 0x0000016B
"\x00U\x03\x06\x00\x00\x01l" + // 0x00550306: 0x0000016C
"\x00u\x03\x06\x00\x00\x01m" + // 0x00750306: 0x0000016D
"\x00U\x03\n\x00\x00\x01n" + // 0x0055030A: 0x0000016E
"\x00u\x03\n\x00\x00\x01o" + // 0x0075030A: 0x0000016F
"\x00U\x03\v\x00\x00\x01p" + // 0x0055030B: 0x00000170
"\x00u\x03\v\x00\x00\x01q" + // 0x0075030B: 0x00000171
"\x00U\x03(\x00\x00\x01r" + // 0x00550328: 0x00000172
"\x00u\x03(\x00\x00\x01s" + // 0x00750328: 0x00000173
"\x00W\x03\x02\x00\x00\x01t" + // 0x00570302: 0x00000174
"\x00w\x03\x02\x00\x00\x01u" + // 0x00770302: 0x00000175
"\x00Y\x03\x02\x00\x00\x01v" + // 0x00590302: 0x00000176
"\x00y\x03\x02\x00\x00\x01w" + // 0x00790302: 0x00000177
"\x00Y\x03\b\x00\x00\x01x" + // 0x00590308: 0x00000178
"\x00Z\x03\x01\x00\x00\x01y" + // 0x005A0301: 0x00000179
"\x00z\x03\x01\x00\x00\x01z" + // 0x007A0301: 0x0000017A
"\x00Z\x03\a\x00\x00\x01{" + // 0x005A0307: 0x0000017B
"\x00z\x03\a\x00\x00\x01|" + // 0x007A0307: 0x0000017C
"\x00Z\x03\f\x00\x00\x01}" + // 0x005A030C: 0x0000017D
"\x00z\x03\f\x00\x00\x01~" + // 0x007A030C: 0x0000017E
"\x00O\x03\x1b\x00\x00\x01\xa0" + // 0x004F031B: 0x000001A0
"\x00o\x03\x1b\x00\x00\x01\xa1" + // 0x006F031B: 0x000001A1
"\x00U\x03\x1b\x00\x00\x01\xaf" + // 0x0055031B: 0x000001AF
"\x00u\x03\x1b\x00\x00\x01\xb0" + // 0x0075031B: 0x000001B0
"\x00A\x03\f\x00\x00\x01\xcd" + // 0x0041030C: 0x000001CD
"\x00a\x03\f\x00\x00\x01\xce" + // 0x0061030C: 0x000001CE
"\x00I\x03\f\x00\x00\x01\xcf" + // 0x0049030C: 0x000001CF
"\x00i\x03\f\x00\x00\x01\xd0" + // 0x0069030C: 0x000001D0
"\x00O\x03\f\x00\x00\x01\xd1" + // 0x004F030C: 0x000001D1
"\x00o\x03\f\x00\x00\x01\xd2" + // 0x006F030C: 0x000001D2
"\x00U\x03\f\x00\x00\x01\xd3" + // 0x0055030C: 0x000001D3
"\x00u\x03\f\x00\x00\x01\xd4" + // 0x0075030C: 0x000001D4
"\x00\xdc\x03\x04\x00\x00\x01\xd5" + // 0x00DC0304: 0x000001D5
"\x00\xfc\x03\x04\x00\x00\x01\xd6" + // 0x00FC0304: 0x000001D6
"\x00\xdc\x03\x01\x00\x00\x01\xd7" + // 0x00DC0301: 0x000001D7
"\x00\xfc\x03\x01\x00\x00\x01\xd8" + // 0x00FC0301: 0x000001D8
"\x00\xdc\x03\f\x00\x00\x01\xd9" + // 0x00DC030C: 0x000001D9
"\x00\xfc\x03\f\x00\x00\x01\xda" + // 0x00FC030C: 0x000001DA
"\x00\xdc\x03\x00\x00\x00\x01\xdb" + // 0x00DC0300: 0x000001DB
"\x00\xfc\x03\x00\x00\x00\x01\xdc" + // 0x00FC0300: 0x000001DC
"\x00\xc4\x03\x04\x00\x00\x01\xde" + // 0x00C40304: 0x000001DE
"\x00\xe4\x03\x04\x00\x00\x01\xdf" + // 0x00E40304: 0x000001DF
"\x02&\x03\x04\x00\x00\x01\xe0" + // 0x02260304: 0x000001E0
"\x02'\x03\x04\x00\x00\x01\xe1" + // 0x02270304: 0x000001E1
"\x00\xc6\x03\x04\x00\x00\x01\xe2" + // 0x00C60304: 0x000001E2
"\x00\xe6\x03\x04\x00\x00\x01\xe3" + // 0x00E60304: 0x000001E3
"\x00G\x03\f\x00\x00\x01\xe6" + // 0x0047030C: 0x000001E6
"\x00g\x03\f\x00\x00\x01\xe7" + // 0x0067030C: 0x000001E7
"\x00K\x03\f\x00\x00\x01\xe8" + // 0x004B030C: 0x000001E8
"\x00k\x03\f\x00\x00\x01\xe9" + // 0x006B030C: 0x000001E9
"\x00O\x03(\x00\x00\x01\xea" + // 0x004F0328: 0x000001EA
"\x00o\x03(\x00\x00\x01\xeb" + // 0x006F0328: 0x000001EB
"\x01\xea\x03\x04\x00\x00\x01\xec" + // 0x01EA0304: 0x000001EC
"\x01\xeb\x03\x04\x00\x00\x01\xed" + // 0x01EB0304: 0x000001ED
"\x01\xb7\x03\f\x00\x00\x01\xee" + // 0x01B7030C: 0x000001EE
"\x02\x92\x03\f\x00\x00\x01\xef" + // 0x0292030C: 0x000001EF
"\x00j\x03\f\x00\x00\x01\xf0" + // 0x006A030C: 0x000001F0
"\x00G\x03\x01\x00\x00\x01\xf4" + // 0x00470301: 0x000001F4
"\x00g\x03\x01\x00\x00\x01\xf5" + // 0x00670301: 0x000001F5
"\x00N\x03\x00\x00\x00\x01\xf8" + // 0x004E0300: 0x000001F8
"\x00n\x03\x00\x00\x00\x01\xf9" + // 0x006E0300: 0x000001F9
"\x00\xc5\x03\x01\x00\x00\x01\xfa" + // 0x00C50301: 0x000001FA
"\x00\xe5\x03\x01\x00\x00\x01\xfb" + // 0x00E50301: 0x000001FB
"\x00\xc6\x03\x01\x00\x00\x01\xfc" + // 0x00C60301: 0x000001FC
"\x00\xe6\x03\x01\x00\x00\x01\xfd" + // 0x00E60301: 0x000001FD
"\x00\xd8\x03\x01\x00\x00\x01\xfe" + // 0x00D80301: 0x000001FE
"\x00\xf8\x03\x01\x00\x00\x01\xff" + // 0x00F80301: 0x000001FF
"\x00A\x03\x0f\x00\x00\x02\x00" + // 0x0041030F: 0x00000200
"\x00a\x03\x0f\x00\x00\x02\x01" + // 0x0061030F: 0x00000201
"\x00A\x03\x11\x00\x00\x02\x02" + // 0x00410311: 0x00000202
"\x00a\x03\x11\x00\x00\x02\x03" + // 0x00610311: 0x00000203
"\x00E\x03\x0f\x00\x00\x02\x04" + // 0x0045030F: 0x00000204
"\x00e\x03\x0f\x00\x00\x02\x05" + // 0x0065030F: 0x00000205
"\x00E\x03\x11\x00\x00\x02\x06" + // 0x00450311: 0x00000206
"\x00e\x03\x11\x00\x00\x02\a" + // 0x00650311: 0x00000207
"\x00I\x03\x0f\x00\x00\x02\b" + // 0x0049030F: 0x00000208
"\x00i\x03\x0f\x00\x00\x02\t" + // 0x0069030F: 0x00000209
"\x00I\x03\x11\x00\x00\x02\n" + // 0x00490311: 0x0000020A
"\x00i\x03\x11\x00\x00\x02\v" + // 0x00690311: 0x0000020B
"\x00O\x03\x0f\x00\x00\x02\f" + // 0x004F030F: 0x0000020C
"\x00o\x03\x0f\x00\x00\x02\r" + // 0x006F030F: 0x0000020D
"\x00O\x03\x11\x00\x00\x02\x0e" + // 0x004F0311: 0x0000020E
"\x00o\x03\x11\x00\x00\x02\x0f" + // 0x006F0311: 0x0000020F
"\x00R\x03\x0f\x00\x00\x02\x10" + // 0x0052030F: 0x00000210
"\x00r\x03\x0f\x00\x00\x02\x11" + // 0x0072030F: 0x00000211
"\x00R\x03\x11\x00\x00\x02\x12" + // 0x00520311: 0x00000212
"\x00r\x03\x11\x00\x00\x02\x13" + // 0x00720311: 0x00000213
"\x00U\x03\x0f\x00\x00\x02\x14" + // 0x0055030F: 0x00000214
"\x00u\x03\x0f\x00\x00\x02\x15" + // 0x0075030F: 0x00000215
"\x00U\x03\x11\x00\x00\x02\x16" + // 0x00550311: 0x00000216
"\x00u\x03\x11\x00\x00\x02\x17" + // 0x00750311: 0x00000217
"\x00S\x03&\x00\x00\x02\x18" + // 0x00530326: 0x00000218
"\x00s\x03&\x00\x00\x02\x19" + // 0x00730326: 0x00000219
"\x00T\x03&\x00\x00\x02\x1a" + // 0x00540326: 0x0000021A
"\x00t\x03&\x00\x00\x02\x1b" + // 0x00740326: 0x0000021B
"\x00H\x03\f\x00\x00\x02\x1e" + // 0x0048030C: 0x0000021E
"\x00h\x03\f\x00\x00\x02\x1f" + // 0x0068030C: 0x0000021F
"\x00A\x03\a\x00\x00\x02&" + // 0x00410307: 0x00000226
"\x00a\x03\a\x00\x00\x02'" + // 0x00610307: 0x00000227
"\x00E\x03'\x00\x00\x02(" + // 0x00450327: 0x00000228
"\x00e\x03'\x00\x00\x02)" + // 0x00650327: 0x00000229
"\x00\xd6\x03\x04\x00\x00\x02*" + // 0x00D60304: 0x0000022A
"\x00\xf6\x03\x04\x00\x00\x02+" + // 0x00F60304: 0x0000022B
"\x00\xd5\x03\x04\x00\x00\x02," + // 0x00D50304: 0x0000022C
"\x00\xf5\x03\x04\x00\x00\x02-" + // 0x00F50304: 0x0000022D
"\x00O\x03\a\x00\x00\x02." + // 0x004F0307: 0x0000022E
"\x00o\x03\a\x00\x00\x02/" + // 0x006F0307: 0x0000022F
"\x02.\x03\x04\x00\x00\x020" + // 0x022E0304: 0x00000230
"\x02/\x03\x04\x00\x00\x021" + // 0x022F0304: 0x00000231
"\x00Y\x03\x04\x00\x00\x022" + // 0x00590304: 0x00000232
"\x00y\x03\x04\x00\x00\x023" + // 0x00790304: 0x00000233
"\x00\xa8\x03\x01\x00\x00\x03\x85" + // 0x00A80301: 0x00000385
"\x03\x91\x03\x01\x00\x00\x03\x86" + // 0x03910301: 0x00000386
"\x03\x95\x03\x01\x00\x00\x03\x88" + // 0x03950301: 0x00000388
"\x03\x97\x03\x01\x00\x00\x03\x89" + // 0x03970301: 0x00000389
"\x03\x99\x03\x01\x00\x00\x03\x8a" + // 0x03990301: 0x0000038A
"\x03\x9f\x03\x01\x00\x00\x03\x8c" + // 0x039F0301: 0x0000038C
"\x03\xa5\x03\x01\x00\x00\x03\x8e" + // 0x03A50301: 0x0000038E
"\x03\xa9\x03\x01\x00\x00\x03\x8f" + // 0x03A90301: 0x0000038F
"\x03\xca\x03\x01\x00\x00\x03\x90" + // 0x03CA0301: 0x00000390
"\x03\x99\x03\b\x00\x00\x03\xaa" + // 0x03990308: 0x000003AA
"\x03\xa5\x03\b\x00\x00\x03\xab" + // 0x03A50308: 0x000003AB
"\x03\xb1\x03\x01\x00\x00\x03\xac" + // 0x03B10301: 0x000003AC
"\x03\xb5\x03\x01\x00\x00\x03\xad" + // 0x03B50301: 0x000003AD
"\x03\xb7\x03\x01\x00\x00\x03\xae" + // 0x03B70301: 0x000003AE
"\x03\xb9\x03\x01\x00\x00\x03\xaf" + // 0x03B90301: 0x000003AF
"\x03\xcb\x03\x01\x00\x00\x03\xb0" + // 0x03CB0301: 0x000003B0
"\x03\xb9\x03\b\x00\x00\x03\xca" + // 0x03B90308: 0x000003CA
"\x03\xc5\x03\b\x00\x00\x03\xcb" + // 0x03C50308: 0x000003CB
"\x03\xbf\x03\x01\x00\x00\x03\xcc" + // 0x03BF0301: 0x000003CC
"\x03\xc5\x03\x01\x00\x00\x03\xcd" + // 0x03C50301: 0x000003CD
"\x03\xc9\x03\x01\x00\x00\x03\xce" + // 0x03C90301: 0x000003CE
"\x03\xd2\x03\x01\x00\x00\x03\xd3" + // 0x03D20301: 0x000003D3
"\x03\xd2\x03\b\x00\x00\x03\xd4" + // 0x03D20308: 0x000003D4
"\x04\x15\x03\x00\x00\x00\x04\x00" + // 0x04150300: 0x00000400
"\x04\x15\x03\b\x00\x00\x04\x01" + // 0x04150308: 0x00000401
"\x04\x13\x03\x01\x00\x00\x04\x03" + // 0x04130301: 0x00000403
"\x04\x06\x03\b\x00\x00\x04\a" + // 0x04060308: 0x00000407
"\x04\x1a\x03\x01\x00\x00\x04\f" + // 0x041A0301: 0x0000040C
"\x04\x18\x03\x00\x00\x00\x04\r" + // 0x04180300: 0x0000040D
"\x04#\x03\x06\x00\x00\x04\x0e" + // 0x04230306: 0x0000040E
"\x04\x18\x03\x06\x00\x00\x04\x19" + // 0x04180306: 0x00000419
"\x048\x03\x06\x00\x00\x049" + // 0x04380306: 0x00000439
"\x045\x03\x00\x00\x00\x04P" + // 0x04350300: 0x00000450
"\x045\x03\b\x00\x00\x04Q" + // 0x04350308: 0x00000451
"\x043\x03\x01\x00\x00\x04S" + // 0x04330301: 0x00000453
"\x04V\x03\b\x00\x00\x04W" + // 0x04560308: 0x00000457
"\x04:\x03\x01\x00\x00\x04\\" + // 0x043A0301: 0x0000045C
"\x048\x03\x00\x00\x00\x04]" + // 0x04380300: 0x0000045D
"\x04C\x03\x06\x00\x00\x04^" + // 0x04430306: 0x0000045E
"\x04t\x03\x0f\x00\x00\x04v" + // 0x0474030F: 0x00000476
"\x04u\x03\x0f\x00\x00\x04w" + // 0x0475030F: 0x00000477
"\x04\x16\x03\x06\x00\x00\x04\xc1" + // 0x04160306: 0x000004C1
"\x046\x03\x06\x00\x00\x04\xc2" + // 0x04360306: 0x000004C2
"\x04\x10\x03\x06\x00\x00\x04\xd0" + // 0x04100306: 0x000004D0
"\x040\x03\x06\x00\x00\x04\xd1" + // 0x04300306: 0x000004D1
"\x04\x10\x03\b\x00\x00\x04\xd2" + // 0x04100308: 0x000004D2
"\x040\x03\b\x00\x00\x04\xd3" + // 0x04300308: 0x000004D3
"\x04\x15\x03\x06\x00\x00\x04\xd6" + // 0x04150306: 0x000004D6
"\x045\x03\x06\x00\x00\x04\xd7" + // 0x04350306: 0x000004D7
"\x04\xd8\x03\b\x00\x00\x04\xda" + // 0x04D80308: 0x000004DA
"\x04\xd9\x03\b\x00\x00\x04\xdb" + // 0x04D90308: 0x000004DB
"\x04\x16\x03\b\x00\x00\x04\xdc" + // 0x04160308: 0x000004DC
"\x046\x03\b\x00\x00\x04\xdd" + // 0x04360308: 0x000004DD
"\x04\x17\x03\b\x00\x00\x04\xde" + // 0x04170308: 0x000004DE
"\x047\x03\b\x00\x00\x04\xdf" + // 0x04370308: 0x000004DF
"\x04\x18\x03\x04\x00\x00\x04\xe2" + // 0x04180304: 0x000004E2
"\x048\x03\x04\x00\x00\x04\xe3" + // 0x04380304: 0x000004E3
"\x04\x18\x03\b\x00\x00\x04\xe4" + // 0x04180308: 0x000004E4
"\x048\x03\b\x00\x00\x04\xe5" + // 0x04380308: 0x000004E5
"\x04\x1e\x03\b\x00\x00\x04\xe6" + // 0x041E0308: 0x000004E6
"\x04>\x03\b\x00\x00\x04\xe7" + // 0x043E0308: 0x000004E7
"\x04\xe8\x03\b\x00\x00\x04\xea" + // 0x04E80308: 0x000004EA
"\x04\xe9\x03\b\x00\x00\x04\xeb" + // 0x04E90308: 0x000004EB
"\x04-\x03\b\x00\x00\x04\xec" + // 0x042D0308: 0x000004EC
"\x04M\x03\b\x00\x00\x04\xed" + // 0x044D0308: 0x000004ED
"\x04#\x03\x04\x00\x00\x04\xee" + // 0x04230304: 0x000004EE
"\x04C\x03\x04\x00\x00\x04\xef" + // 0x04430304: 0x000004EF
"\x04#\x03\b\x00\x00\x04\xf0" + // 0x04230308: 0x000004F0
"\x04C\x03\b\x00\x00\x04\xf1" + // 0x04430308: 0x000004F1
"\x04#\x03\v\x00\x00\x04\xf2" + // 0x0423030B: 0x000004F2
"\x04C\x03\v\x00\x00\x04\xf3" + // 0x0443030B: 0x000004F3
"\x04'\x03\b\x00\x00\x04\xf4" + // 0x04270308: 0x000004F4
"\x04G\x03\b\x00\x00\x04\xf5" + // 0x04470308: 0x000004F5
"\x04+\x03\b\x00\x00\x04\xf8" + // 0x042B0308: 0x000004F8
"\x04K\x03\b\x00\x00\x04\xf9" + // 0x044B0308: 0x000004F9
"\x06'\x06S\x00\x00\x06\"" + // 0x06270653: 0x00000622
"\x06'\x06T\x00\x00\x06#" + // 0x06270654: 0x00000623
"\x06H\x06T\x00\x00\x06$" + // 0x06480654: 0x00000624
"\x06'\x06U\x00\x00\x06%" + // 0x06270655: 0x00000625
"\x06J\x06T\x00\x00\x06&" + // 0x064A0654: 0x00000626
"\x06\xd5\x06T\x00\x00\x06\xc0" + // 0x06D50654: 0x000006C0
"\x06\xc1\x06T\x00\x00\x06\xc2" + // 0x06C10654: 0x000006C2
"\x06\xd2\x06T\x00\x00\x06\xd3" + // 0x06D20654: 0x000006D3
"\t(\t<\x00\x00\t)" + // 0x0928093C: 0x00000929
"\t0\t<\x00\x00\t1" + // 0x0930093C: 0x00000931
"\t3\t<\x00\x00\t4" + // 0x0933093C: 0x00000934
"\t\xc7\t\xbe\x00\x00\t\xcb" + // 0x09C709BE: 0x000009CB
"\t\xc7\t\xd7\x00\x00\t\xcc" + // 0x09C709D7: 0x000009CC
"\vG\vV\x00\x00\vH" + // 0x0B470B56: 0x00000B48
"\vG\v>\x00\x00\vK" + // 0x0B470B3E: 0x00000B4B
"\vG\vW\x00\x00\vL" + // 0x0B470B57: 0x00000B4C
"\v\x92\v\xd7\x00\x00\v\x94" + // 0x0B920BD7: 0x00000B94
"\v\xc6\v\xbe\x00\x00\v\xca" + // 0x0BC60BBE: 0x00000BCA
"\v\xc7\v\xbe\x00\x00\v\xcb" + // 0x0BC70BBE: 0x00000BCB
"\v\xc6\v\xd7\x00\x00\v\xcc" + // 0x0BC60BD7: 0x00000BCC
"\fF\fV\x00\x00\fH" + // 0x0C460C56: 0x00000C48
"\f\xbf\f\xd5\x00\x00\f\xc0" + // 0x0CBF0CD5: 0x00000CC0
"\f\xc6\f\xd5\x00\x00\f\xc7" + // 0x0CC60CD5: 0x00000CC7
"\f\xc6\f\xd6\x00\x00\f\xc8" + // 0x0CC60CD6: 0x00000CC8
"\f\xc6\f\xc2\x00\x00\f\xca" + // 0x0CC60CC2: 0x00000CCA
"\f\xca\f\xd5\x00\x00\f\xcb" + // 0x0CCA0CD5: 0x00000CCB
"\rF\r>\x00\x00\rJ" + // 0x0D460D3E: 0x00000D4A
"\rG\r>\x00\x00\rK" + // 0x0D470D3E: 0x00000D4B
"\rF\rW\x00\x00\rL" + // 0x0D460D57: 0x00000D4C
"\r\xd9\r\xca\x00\x00\r\xda" + // 0x0DD90DCA: 0x00000DDA
"\r\xd9\r\xcf\x00\x00\r\xdc" + // 0x0DD90DCF: 0x00000DDC
"\r\xdc\r\xca\x00\x00\r\xdd" + // 0x0DDC0DCA: 0x00000DDD
"\r\xd9\r\xdf\x00\x00\r\xde" + // 0x0DD90DDF: 0x00000DDE
"\x10%\x10.\x00\x00\x10&" + // 0x1025102E: 0x00001026
"\x1b\x05\x1b5\x00\x00\x1b\x06" + // 0x1B051B35: 0x00001B06
"\x1b\a\x1b5\x00\x00\x1b\b" + // 0x1B071B35: 0x00001B08
"\x1b\t\x1b5\x00\x00\x1b\n" + // 0x1B091B35: 0x00001B0A
"\x1b\v\x1b5\x00\x00\x1b\f" + // 0x1B0B1B35: 0x00001B0C
"\x1b\r\x1b5\x00\x00\x1b\x0e" + // 0x1B0D1B35: 0x00001B0E
"\x1b\x11\x1b5\x00\x00\x1b\x12" + // 0x1B111B35: 0x00001B12
"\x1b:\x1b5\x00\x00\x1b;" + // 0x1B3A1B35: 0x00001B3B
"\x1b<\x1b5\x00\x00\x1b=" + // 0x1B3C1B35: 0x00001B3D
"\x1b>\x1b5\x00\x00\x1b@" + // 0x1B3E1B35: 0x00001B40
"\x1b?\x1b5\x00\x00\x1bA" + // 0x1B3F1B35: 0x00001B41
"\x1bB\x1b5\x00\x00\x1bC" + // 0x1B421B35: 0x00001B43
"\x00A\x03%\x00\x00\x1e\x00" + // 0x00410325: 0x00001E00
"\x00a\x03%\x00\x00\x1e\x01" + // 0x00610325: 0x00001E01
"\x00B\x03\a\x00\x00\x1e\x02" + // 0x00420307: 0x00001E02
"\x00b\x03\a\x00\x00\x1e\x03" + // 0x00620307: 0x00001E03
"\x00B\x03#\x00\x00\x1e\x04" + // 0x00420323: 0x00001E04
"\x00b\x03#\x00\x00\x1e\x05" + // 0x00620323: 0x00001E05
"\x00B\x031\x00\x00\x1e\x06" + // 0x00420331: 0x00001E06
"\x00b\x031\x00\x00\x1e\a" + // 0x00620331: 0x00001E07
"\x00\xc7\x03\x01\x00\x00\x1e\b" + // 0x00C70301: 0x00001E08
"\x00\xe7\x03\x01\x00\x00\x1e\t" + // 0x00E70301: 0x00001E09
"\x00D\x03\a\x00\x00\x1e\n" + // 0x00440307: 0x00001E0A
"\x00d\x03\a\x00\x00\x1e\v" + // 0x00640307: 0x00001E0B
"\x00D\x03#\x00\x00\x1e\f" + // 0x00440323: 0x00001E0C
"\x00d\x03#\x00\x00\x1e\r" + // 0x00640323: 0x00001E0D
"\x00D\x031\x00\x00\x1e\x0e" + // 0x00440331: 0x00001E0E
"\x00d\x031\x00\x00\x1e\x0f" + // 0x00640331: 0x00001E0F
"\x00D\x03'\x00\x00\x1e\x10" + // 0x00440327: 0x00001E10
"\x00d\x03'\x00\x00\x1e\x11" + // 0x00640327: 0x00001E11
"\x00D\x03-\x00\x00\x1e\x12" + // 0x0044032D: 0x00001E12
"\x00d\x03-\x00\x00\x1e\x13" + // 0x0064032D: 0x00001E13
"\x01\x12\x03\x00\x00\x00\x1e\x14" + // 0x01120300: 0x00001E14
"\x01\x13\x03\x00\x00\x00\x1e\x15" + // 0x01130300: 0x00001E15
"\x01\x12\x03\x01\x00\x00\x1e\x16" + // 0x01120301: 0x00001E16
"\x01\x13\x03\x01\x00\x00\x1e\x17" + // 0x01130301: 0x00001E17
"\x00E\x03-\x00\x00\x1e\x18" + // 0x0045032D: 0x00001E18
"\x00e\x03-\x00\x00\x1e\x19" + // 0x0065032D: 0x00001E19
"\x00E\x030\x00\x00\x1e\x1a" + // 0x00450330: 0x00001E1A
"\x00e\x030\x00\x00\x1e\x1b" + // 0x00650330: 0x00001E1B
"\x02(\x03\x06\x00\x00\x1e\x1c" + // 0x02280306: 0x00001E1C
"\x02)\x03\x06\x00\x00\x1e\x1d" + // 0x02290306: 0x00001E1D
"\x00F\x03\a\x00\x00\x1e\x1e" + // 0x00460307: 0x00001E1E
"\x00f\x03\a\x00\x00\x1e\x1f" + // 0x00660307: 0x00001E1F
"\x00G\x03\x04\x00\x00\x1e " + // 0x00470304: 0x00001E20
"\x00g\x03\x04\x00\x00\x1e!" + // 0x00670304: 0x00001E21
"\x00H\x03\a\x00\x00\x1e\"" + // 0x00480307: 0x00001E22
"\x00h\x03\a\x00\x00\x1e#" + // 0x00680307: 0x00001E23
"\x00H\x03#\x00\x00\x1e$" + // 0x00480323: 0x00001E24
"\x00h\x03#\x00\x00\x1e%" + // 0x00680323: 0x00001E25
"\x00H\x03\b\x00\x00\x1e&" + // 0x00480308: 0x00001E26
"\x00h\x03\b\x00\x00\x1e'" + // 0x00680308: 0x00001E27
"\x00H\x03'\x00\x00\x1e(" + // 0x00480327: 0x00001E28
"\x00h\x03'\x00\x00\x1e)" + // 0x00680327: 0x00001E29
"\x00H\x03.\x00\x00\x1e*" + // 0x0048032E: 0x00001E2A
"\x00h\x03.\x00\x00\x1e+" + // 0x0068032E: 0x00001E2B
"\x00I\x030\x00\x00\x1e," + // 0x00490330: 0x00001E2C
"\x00i\x030\x00\x00\x1e-" + // 0x00690330: 0x00001E2D
"\x00\xcf\x03\x01\x00\x00\x1e." + // 0x00CF0301: 0x00001E2E
"\x00\xef\x03\x01\x00\x00\x1e/" + // 0x00EF0301: 0x00001E2F
"\x00K\x03\x01\x00\x00\x1e0" + // 0x004B0301: 0x00001E30
"\x00k\x03\x01\x00\x00\x1e1" + // 0x006B0301: 0x00001E31
"\x00K\x03#\x00\x00\x1e2" + // 0x004B0323: 0x00001E32
"\x00k\x03#\x00\x00\x1e3" + // 0x006B0323: 0x00001E33
"\x00K\x031\x00\x00\x1e4" + // 0x004B0331: 0x00001E34
"\x00k\x031\x00\x00\x1e5" + // 0x006B0331: 0x00001E35
"\x00L\x03#\x00\x00\x1e6" + // 0x004C0323: 0x00001E36
"\x00l\x03#\x00\x00\x1e7" + // 0x006C0323: 0x00001E37
"\x1e6\x03\x04\x00\x00\x1e8" + // 0x1E360304: 0x00001E38
"\x1e7\x03\x04\x00\x00\x1e9" + // 0x1E370304: 0x00001E39
"\x00L\x031\x00\x00\x1e:" + // 0x004C0331: 0x00001E3A
"\x00l\x031\x00\x00\x1e;" + // 0x006C0331: 0x00001E3B
"\x00L\x03-\x00\x00\x1e<" + // 0x004C032D: 0x00001E3C
"\x00l\x03-\x00\x00\x1e=" + // 0x006C032D: 0x00001E3D
"\x00M\x03\x01\x00\x00\x1e>" + // 0x004D0301: 0x00001E3E
"\x00m\x03\x01\x00\x00\x1e?" + // 0x006D0301: 0x00001E3F
"\x00M\x03\a\x00\x00\x1e@" + // 0x004D0307: 0x00001E40
"\x00m\x03\a\x00\x00\x1eA" + // 0x006D0307: 0x00001E41
"\x00M\x03#\x00\x00\x1eB" + // 0x004D0323: 0x00001E42
"\x00m\x03#\x00\x00\x1eC" + // 0x006D0323: 0x00001E43
"\x00N\x03\a\x00\x00\x1eD" + // 0x004E0307: 0x00001E44
"\x00n\x03\a\x00\x00\x1eE" + // 0x006E0307: 0x00001E45
"\x00N\x03#\x00\x00\x1eF" + // 0x004E0323: 0x00001E46
"\x00n\x03#\x00\x00\x1eG" + // 0x006E0323: 0x00001E47
"\x00N\x031\x00\x00\x1eH" + // 0x004E0331: 0x00001E48
"\x00n\x031\x00\x00\x1eI" + // 0x006E0331: 0x00001E49
"\x00N\x03-\x00\x00\x1eJ" + // 0x004E032D: 0x00001E4A
"\x00n\x03-\x00\x00\x1eK" + // 0x006E032D: 0x00001E4B
"\x00\xd5\x03\x01\x00\x00\x1eL" + // 0x00D50301: 0x00001E4C
"\x00\xf5\x03\x01\x00\x00\x1eM" + // 0x00F50301: 0x00001E4D
"\x00\xd5\x03\b\x00\x00\x1eN" + // 0x00D50308: 0x00001E4E
"\x00\xf5\x03\b\x00\x00\x1eO" + // 0x00F50308: 0x00001E4F
"\x01L\x03\x00\x00\x00\x1eP" + // 0x014C0300: 0x00001E50
"\x01M\x03\x00\x00\x00\x1eQ" + // 0x014D0300: 0x00001E51
"\x01L\x03\x01\x00\x00\x1eR" + // 0x014C0301: 0x00001E52
"\x01M\x03\x01\x00\x00\x1eS" + // 0x014D0301: 0x00001E53
"\x00P\x03\x01\x00\x00\x1eT" + // 0x00500301: 0x00001E54
"\x00p\x03\x01\x00\x00\x1eU" + // 0x00700301: 0x00001E55
"\x00P\x03\a\x00\x00\x1eV" + // 0x00500307: 0x00001E56
"\x00p\x03\a\x00\x00\x1eW" + // 0x00700307: 0x00001E57
"\x00R\x03\a\x00\x00\x1eX" + // 0x00520307: 0x00001E58
"\x00r\x03\a\x00\x00\x1eY" + // 0x00720307: 0x00001E59
"\x00R\x03#\x00\x00\x1eZ" + // 0x00520323: 0x00001E5A
"\x00r\x03#\x00\x00\x1e[" + // 0x00720323: 0x00001E5B
"\x1eZ\x03\x04\x00\x00\x1e\\" + // 0x1E5A0304: 0x00001E5C
"\x1e[\x03\x04\x00\x00\x1e]" + // 0x1E5B0304: 0x00001E5D
"\x00R\x031\x00\x00\x1e^" + // 0x00520331: 0x00001E5E
"\x00r\x031\x00\x00\x1e_" + // 0x00720331: 0x00001E5F
"\x00S\x03\a\x00\x00\x1e`" + // 0x00530307: 0x00001E60
"\x00s\x03\a\x00\x00\x1ea" + // 0x00730307: 0x00001E61
"\x00S\x03#\x00\x00\x1eb" + // 0x00530323: 0x00001E62
"\x00s\x03#\x00\x00\x1ec" + // 0x00730323: 0x00001E63
"\x01Z\x03\a\x00\x00\x1ed" + // 0x015A0307: 0x00001E64
"\x01[\x03\a\x00\x00\x1ee" + // 0x015B0307: 0x00001E65
"\x01`\x03\a\x00\x00\x1ef" + // 0x01600307: 0x00001E66
"\x01a\x03\a\x00\x00\x1eg" + // 0x01610307: 0x00001E67
"\x1eb\x03\a\x00\x00\x1eh" + // 0x1E620307: 0x00001E68
"\x1ec\x03\a\x00\x00\x1ei" + // 0x1E630307: 0x00001E69
"\x00T\x03\a\x00\x00\x1ej" + // 0x00540307: 0x00001E6A
"\x00t\x03\a\x00\x00\x1ek" + // 0x00740307: 0x00001E6B
"\x00T\x03#\x00\x00\x1el" + // 0x00540323: 0x00001E6C
"\x00t\x03#\x00\x00\x1em" + // 0x00740323: 0x00001E6D
"\x00T\x031\x00\x00\x1en" + // 0x00540331: 0x00001E6E
"\x00t\x031\x00\x00\x1eo" + // 0x00740331: 0x00001E6F
"\x00T\x03-\x00\x00\x1ep" + // 0x0054032D: 0x00001E70
"\x00t\x03-\x00\x00\x1eq" + // 0x0074032D: 0x00001E71
"\x00U\x03$\x00\x00\x1er" + // 0x00550324: 0x00001E72
"\x00u\x03$\x00\x00\x1es" + // 0x00750324: 0x00001E73
"\x00U\x030\x00\x00\x1et" + // 0x00550330: 0x00001E74
"\x00u\x030\x00\x00\x1eu" + // 0x00750330: 0x00001E75
"\x00U\x03-\x00\x00\x1ev" + // 0x0055032D: 0x00001E76
"\x00u\x03-\x00\x00\x1ew" + // 0x0075032D: 0x00001E77
"\x01h\x03\x01\x00\x00\x1ex" + // 0x01680301: 0x00001E78
"\x01i\x03\x01\x00\x00\x1ey" + // 0x01690301: 0x00001E79
"\x01j\x03\b\x00\x00\x1ez" + // 0x016A0308: 0x00001E7A
"\x01k\x03\b\x00\x00\x1e{" + // 0x016B0308: 0x00001E7B
"\x00V\x03\x03\x00\x00\x1e|" + // 0x00560303: 0x00001E7C
"\x00v\x03\x03\x00\x00\x1e}" + // 0x00760303: 0x00001E7D
"\x00V\x03#\x00\x00\x1e~" + // 0x00560323: 0x00001E7E
"\x00v\x03#\x00\x00\x1e\x7f" + // 0x00760323: 0x00001E7F
"\x00W\x03\x00\x00\x00\x1e\x80" + // 0x00570300: 0x00001E80
"\x00w\x03\x00\x00\x00\x1e\x81" + // 0x00770300: 0x00001E81
"\x00W\x03\x01\x00\x00\x1e\x82" + // 0x00570301: 0x00001E82
"\x00w\x03\x01\x00\x00\x1e\x83" + // 0x00770301: 0x00001E83
"\x00W\x03\b\x00\x00\x1e\x84" + // 0x00570308: 0x00001E84
"\x00w\x03\b\x00\x00\x1e\x85" + // 0x00770308: 0x00001E85
"\x00W\x03\a\x00\x00\x1e\x86" + // 0x00570307: 0x00001E86
"\x00w\x03\a\x00\x00\x1e\x87" + // 0x00770307: 0x00001E87
"\x00W\x03#\x00\x00\x1e\x88" + // 0x00570323: 0x00001E88
"\x00w\x03#\x00\x00\x1e\x89" + // 0x00770323: 0x00001E89
"\x00X\x03\a\x00\x00\x1e\x8a" + // 0x00580307: 0x00001E8A
"\x00x\x03\a\x00\x00\x1e\x8b" + // 0x00780307: 0x00001E8B
"\x00X\x03\b\x00\x00\x1e\x8c" + // 0x00580308: 0x00001E8C
"\x00x\x03\b\x00\x00\x1e\x8d" + // 0x00780308: 0x00001E8D
"\x00Y\x03\a\x00\x00\x1e\x8e" + // 0x00590307: 0x00001E8E
"\x00y\x03\a\x00\x00\x1e\x8f" + // 0x00790307: 0x00001E8F
"\x00Z\x03\x02\x00\x00\x1e\x90" + // 0x005A0302: 0x00001E90
"\x00z\x03\x02\x00\x00\x1e\x91" + // 0x007A0302: 0x00001E91
"\x00Z\x03#\x00\x00\x1e\x92" + // 0x005A0323: 0x00001E92
"\x00z\x03#\x00\x00\x1e\x93" + // 0x007A0323: 0x00001E93
"\x00Z\x031\x00\x00\x1e\x94" + // 0x005A0331: 0x00001E94
"\x00z\x031\x00\x00\x1e\x95" + // 0x007A0331: 0x00001E95
"\x00h\x031\x00\x00\x1e\x96" + // 0x00680331: 0x00001E96
"\x00t\x03\b\x00\x00\x1e\x97" + // 0x00740308: 0x00001E97
"\x00w\x03\n\x00\x00\x1e\x98" + // 0x0077030A: 0x00001E98
"\x00y\x03\n\x00\x00\x1e\x99" + // 0x0079030A: 0x00001E99
"\x01\x7f\x03\a\x00\x00\x1e\x9b" + // 0x017F0307: 0x00001E9B
"\x00A\x03#\x00\x00\x1e\xa0" + // 0x00410323: 0x00001EA0
"\x00a\x03#\x00\x00\x1e\xa1" + // 0x00610323: 0x00001EA1
"\x00A\x03\t\x00\x00\x1e\xa2" + // 0x00410309: 0x00001EA2
"\x00a\x03\t\x00\x00\x1e\xa3" + // 0x00610309: 0x00001EA3
"\x00\xc2\x03\x01\x00\x00\x1e\xa4" + // 0x00C20301: 0x00001EA4
"\x00\xe2\x03\x01\x00\x00\x1e\xa5" + // 0x00E20301: 0x00001EA5
"\x00\xc2\x03\x00\x00\x00\x1e\xa6" + // 0x00C20300: 0x00001EA6
"\x00\xe2\x03\x00\x00\x00\x1e\xa7" + // 0x00E20300: 0x00001EA7
"\x00\xc2\x03\t\x00\x00\x1e\xa8" + // 0x00C20309: 0x00001EA8
"\x00\xe2\x03\t\x00\x00\x1e\xa9" + // 0x00E20309: 0x00001EA9
"\x00\xc2\x03\x03\x00\x00\x1e\xaa" + // 0x00C20303: 0x00001EAA
"\x00\xe2\x03\x03\x00\x00\x1e\xab" + // 0x00E20303: 0x00001EAB
"\x1e\xa0\x03\x02\x00\x00\x1e\xac" + // 0x1EA00302: 0x00001EAC
"\x1e\xa1\x03\x02\x00\x00\x1e\xad" + // 0x1EA10302: 0x00001EAD
"\x01\x02\x03\x01\x00\x00\x1e\xae" + // 0x01020301: 0x00001EAE
"\x01\x03\x03\x01\x00\x00\x1e\xaf" + // 0x01030301: 0x00001EAF
"\x01\x02\x03\x00\x00\x00\x1e\xb0" + // 0x01020300: 0x00001EB0
"\x01\x03\x03\x00\x00\x00\x1e\xb1" + // 0x01030300: 0x00001EB1
"\x01\x02\x03\t\x00\x00\x1e\xb2" + // 0x01020309: 0x00001EB2
"\x01\x03\x03\t\x00\x00\x1e\xb3" + // 0x01030309: 0x00001EB3
"\x01\x02\x03\x03\x00\x00\x1e\xb4" + // 0x01020303: 0x00001EB4
"\x01\x03\x03\x03\x00\x00\x1e\xb5" + // 0x01030303: 0x00001EB5
"\x1e\xa0\x03\x06\x00\x00\x1e\xb6" + // 0x1EA00306: 0x00001EB6
"\x1e\xa1\x03\x06\x00\x00\x1e\xb7" + // 0x1EA10306: 0x00001EB7
"\x00E\x03#\x00\x00\x1e\xb8" + // 0x00450323: 0x00001EB8
"\x00e\x03#\x00\x00\x1e\xb9" + // 0x00650323: 0x00001EB9
"\x00E\x03\t\x00\x00\x1e\xba" + // 0x00450309: 0x00001EBA
"\x00e\x03\t\x00\x00\x1e\xbb" + // 0x00650309: 0x00001EBB
"\x00E\x03\x03\x00\x00\x1e\xbc" + // 0x00450303: 0x00001EBC
"\x00e\x03\x03\x00\x00\x1e\xbd" + // 0x00650303: 0x00001EBD
"\x00\xca\x03\x01\x00\x00\x1e\xbe" + // 0x00CA0301: 0x00001EBE
"\x00\xea\x03\x01\x00\x00\x1e\xbf" + // 0x00EA0301: 0x00001EBF
"\x00\xca\x03\x00\x00\x00\x1e\xc0" + // 0x00CA0300: 0x00001EC0
"\x00\xea\x03\x00\x00\x00\x1e\xc1" + // 0x00EA0300: 0x00001EC1
"\x00\xca\x03\t\x00\x00\x1e\xc2" + // 0x00CA0309: 0x00001EC2
"\x00\xea\x03\t\x00\x00\x1e\xc3" + // 0x00EA0309: 0x00001EC3
"\x00\xca\x03\x03\x00\x00\x1e\xc4" + // 0x00CA0303: 0x00001EC4
"\x00\xea\x03\x03\x00\x00\x1e\xc5" + // 0x00EA0303: 0x00001EC5
"\x1e\xb8\x03\x02\x00\x00\x1e\xc6" + // 0x1EB80302: 0x00001EC6
"\x1e\xb9\x03\x02\x00\x00\x1e\xc7" + // 0x1EB90302: 0x00001EC7
"\x00I\x03\t\x00\x00\x1e\xc8" + // 0x00490309: 0x00001EC8
"\x00i\x03\t\x00\x00\x1e\xc9" + // 0x00690309: 0x00001EC9
"\x00I\x03#\x00\x00\x1e\xca" + // 0x00490323: 0x00001ECA
"\x00i\x03#\x00\x00\x1e\xcb" + // 0x00690323: 0x00001ECB
"\x00O\x03#\x00\x00\x1e\xcc" + // 0x004F0323: 0x00001ECC
"\x00o\x03#\x00\x00\x1e\xcd" + // 0x006F0323: 0x00001ECD
"\x00O\x03\t\x00\x00\x1e\xce" + // 0x004F0309: 0x00001ECE
"\x00o\x03\t\x00\x00\x1e\xcf" + // 0x006F0309: 0x00001ECF
"\x00\xd4\x03\x01\x00\x00\x1e\xd0" + // 0x00D40301: 0x00001ED0
"\x00\xf4\x03\x01\x00\x00\x1e\xd1" + // 0x00F40301: 0x00001ED1
"\x00\xd4\x03\x00\x00\x00\x1e\xd2" + // 0x00D40300: 0x00001ED2
"\x00\xf4\x03\x00\x00\x00\x1e\xd3" + // 0x00F40300: 0x00001ED3
"\x00\xd4\x03\t\x00\x00\x1e\xd4" + // 0x00D40309: 0x00001ED4
"\x00\xf4\x03\t\x00\x00\x1e\xd5" + // 0x00F40309: 0x00001ED5
"\x00\xd4\x03\x03\x00\x00\x1e\xd6" + // 0x00D40303: 0x00001ED6
"\x00\xf4\x03\x03\x00\x00\x1e\xd7" + // 0x00F40303: 0x00001ED7
"\x1e\xcc\x03\x02\x00\x00\x1e\xd8" + // 0x1ECC0302: 0x00001ED8
"\x1e\xcd\x03\x02\x00\x00\x1e\xd9" + // 0x1ECD0302: 0x00001ED9
"\x01\xa0\x03\x01\x00\x00\x1e\xda" + // 0x01A00301: 0x00001EDA
"\x01\xa1\x03\x01\x00\x00\x1e\xdb" + // 0x01A10301: 0x00001EDB
"\x01\xa0\x03\x00\x00\x00\x1e\xdc" + // 0x01A00300: 0x00001EDC
"\x01\xa1\x03\x00\x00\x00\x1e\xdd" + // 0x01A10300: 0x00001EDD
"\x01\xa0\x03\t\x00\x00\x1e\xde" + // 0x01A00309: 0x00001EDE
"\x01\xa1\x03\t\x00\x00\x1e\xdf" + // 0x01A10309: 0x00001EDF
"\x01\xa0\x03\x03\x00\x00\x1e\xe0" + // 0x01A00303: 0x00001EE0
"\x01\xa1\x03\x03\x00\x00\x1e\xe1" + // 0x01A10303: 0x00001EE1
"\x01\xa0\x03#\x00\x00\x1e\xe2" + // 0x01A00323: 0x00001EE2
"\x01\xa1\x03#\x00\x00\x1e\xe3" + // 0x01A10323: 0x00001EE3
"\x00U\x03#\x00\x00\x1e\xe4" + // 0x00550323: 0x00001EE4
"\x00u\x03#\x00\x00\x1e\xe5" + // 0x00750323: 0x00001EE5
"\x00U\x03\t\x00\x00\x1e\xe6" + // 0x00550309: 0x00001EE6
"\x00u\x03\t\x00\x00\x1e\xe7" + // 0x00750309: 0x00001EE7
"\x01\xaf\x03\x01\x00\x00\x1e\xe8" + // 0x01AF0301: 0x00001EE8
"\x01\xb0\x03\x01\x00\x00\x1e\xe9" + // 0x01B00301: 0x00001EE9
"\x01\xaf\x03\x00\x00\x00\x1e\xea" + // 0x01AF0300: 0x00001EEA
"\x01\xb0\x03\x00\x00\x00\x1e\xeb" + // 0x01B00300: 0x00001EEB
"\x01\xaf\x03\t\x00\x00\x1e\xec" + // 0x01AF0309: 0x00001EEC
"\x01\xb0\x03\t\x00\x00\x1e\xed" + // 0x01B00309: 0x00001EED
"\x01\xaf\x03\x03\x00\x00\x1e\xee" + // 0x01AF0303: 0x00001EEE
"\x01\xb0\x03\x03\x00\x00\x1e\xef" + // 0x01B00303: 0x00001EEF
"\x01\xaf\x03#\x00\x00\x1e\xf0" + // 0x01AF0323: 0x00001EF0
"\x01\xb0\x03#\x00\x00\x1e\xf1" + // 0x01B00323: 0x00001EF1
"\x00Y\x03\x00\x00\x00\x1e\xf2" + // 0x00590300: 0x00001EF2
"\x00y\x03\x00\x00\x00\x1e\xf3" + // 0x00790300: 0x00001EF3
"\x00Y\x03#\x00\x00\x1e\xf4" + // 0x00590323: 0x00001EF4
"\x00y\x03#\x00\x00\x1e\xf5" + // 0x00790323: 0x00001EF5
"\x00Y\x03\t\x00\x00\x1e\xf6" + // 0x00590309: 0x00001EF6
"\x00y\x03\t\x00\x00\x1e\xf7" + // 0x00790309: 0x00001EF7
"\x00Y\x03\x03\x00\x00\x1e\xf8" + // 0x00590303: 0x00001EF8
"\x00y\x03\x03\x00\x00\x1e\xf9" + // 0x00790303: 0x00001EF9
"\x03\xb1\x03\x13\x00\x00\x1f\x00" + // 0x03B10313: 0x00001F00
"\x03\xb1\x03\x14\x00\x00\x1f\x01" + // 0x03B10314: 0x00001F01
"\x1f\x00\x03\x00\x00\x00\x1f\x02" + // 0x1F000300: 0x00001F02
"\x1f\x01\x03\x00\x00\x00\x1f\x03" + // 0x1F010300: 0x00001F03
"\x1f\x00\x03\x01\x00\x00\x1f\x04" + // 0x1F000301: 0x00001F04
"\x1f\x01\x03\x01\x00\x00\x1f\x05" + // 0x1F010301: 0x00001F05
"\x1f\x00\x03B\x00\x00\x1f\x06" + // 0x1F000342: 0x00001F06
"\x1f\x01\x03B\x00\x00\x1f\a" + // 0x1F010342: 0x00001F07
"\x03\x91\x03\x13\x00\x00\x1f\b" + // 0x03910313: 0x00001F08
"\x03\x91\x03\x14\x00\x00\x1f\t" + // 0x03910314: 0x00001F09
"\x1f\b\x03\x00\x00\x00\x1f\n" + // 0x1F080300: 0x00001F0A
"\x1f\t\x03\x00\x00\x00\x1f\v" + // 0x1F090300: 0x00001F0B
"\x1f\b\x03\x01\x00\x00\x1f\f" + // 0x1F080301: 0x00001F0C
"\x1f\t\x03\x01\x00\x00\x1f\r" + // 0x1F090301: 0x00001F0D
"\x1f\b\x03B\x00\x00\x1f\x0e" + // 0x1F080342: 0x00001F0E
"\x1f\t\x03B\x00\x00\x1f\x0f" + // 0x1F090342: 0x00001F0F
"\x03\xb5\x03\x13\x00\x00\x1f\x10" + // 0x03B50313: 0x00001F10
"\x03\xb5\x03\x14\x00\x00\x1f\x11" + // 0x03B50314: 0x00001F11
"\x1f\x10\x03\x00\x00\x00\x1f\x12" + // 0x1F100300: 0x00001F12
"\x1f\x11\x03\x00\x00\x00\x1f\x13" + // 0x1F110300: 0x00001F13
"\x1f\x10\x03\x01\x00\x00\x1f\x14" + // 0x1F100301: 0x00001F14
"\x1f\x11\x03\x01\x00\x00\x1f\x15" + // 0x1F110301: 0x00001F15
"\x03\x95\x03\x13\x00\x00\x1f\x18" + // 0x03950313: 0x00001F18
"\x03\x95\x03\x14\x00\x00\x1f\x19" + // 0x03950314: 0x00001F19
"\x1f\x18\x03\x00\x00\x00\x1f\x1a" + // 0x1F180300: 0x00001F1A
"\x1f\x19\x03\x00\x00\x00\x1f\x1b" + // 0x1F190300: 0x00001F1B
"\x1f\x18\x03\x01\x00\x00\x1f\x1c" + // 0x1F180301: 0x00001F1C
"\x1f\x19\x03\x01\x00\x00\x1f\x1d" + // 0x1F190301: 0x00001F1D
"\x03\xb7\x03\x13\x00\x00\x1f " + // 0x03B70313: 0x00001F20
"\x03\xb7\x03\x14\x00\x00\x1f!" + // 0x03B70314: 0x00001F21
"\x1f \x03\x00\x00\x00\x1f\"" + // 0x1F200300: 0x00001F22
"\x1f!\x03\x00\x00\x00\x1f#" + // 0x1F210300: 0x00001F23
"\x1f \x03\x01\x00\x00\x1f$" + // 0x1F200301: 0x00001F24
"\x1f!\x03\x01\x00\x00\x1f%" + // 0x1F210301: 0x00001F25
"\x1f \x03B\x00\x00\x1f&" + // 0x1F200342: 0x00001F26
"\x1f!\x03B\x00\x00\x1f'" + // 0x1F210342: 0x00001F27
"\x03\x97\x03\x13\x00\x00\x1f(" + // 0x03970313: 0x00001F28
"\x03\x97\x03\x14\x00\x00\x1f)" + // 0x03970314: 0x00001F29
"\x1f(\x03\x00\x00\x00\x1f*" + // 0x1F280300: 0x00001F2A
"\x1f)\x03\x00\x00\x00\x1f+" + // 0x1F290300: 0x00001F2B
"\x1f(\x03\x01\x00\x00\x1f," + // 0x1F280301: 0x00001F2C
"\x1f)\x03\x01\x00\x00\x1f-" + // 0x1F290301: 0x00001F2D
"\x1f(\x03B\x00\x00\x1f." + // 0x1F280342: 0x00001F2E
"\x1f)\x03B\x00\x00\x1f/" + // 0x1F290342: 0x00001F2F
"\x03\xb9\x03\x13\x00\x00\x1f0" + // 0x03B90313: 0x00001F30
"\x03\xb9\x03\x14\x00\x00\x1f1" + // 0x03B90314: 0x00001F31
"\x1f0\x03\x00\x00\x00\x1f2" + // 0x1F300300: 0x00001F32
"\x1f1\x03\x00\x00\x00\x1f3" + // 0x1F310300: 0x00001F33
"\x1f0\x03\x01\x00\x00\x1f4" + // 0x1F300301: 0x00001F34
"\x1f1\x03\x01\x00\x00\x1f5" + // 0x1F310301: 0x00001F35
"\x1f0\x03B\x00\x00\x1f6" + // 0x1F300342: 0x00001F36
"\x1f1\x03B\x00\x00\x1f7" + // 0x1F310342: 0x00001F37
"\x03\x99\x03\x13\x00\x00\x1f8" + // 0x03990313: 0x00001F38
"\x03\x99\x03\x14\x00\x00\x1f9" + // 0x03990314: 0x00001F39
"\x1f8\x03\x00\x00\x00\x1f:" + // 0x1F380300: 0x00001F3A
"\x1f9\x03\x00\x00\x00\x1f;" + // 0x1F390300: 0x00001F3B
"\x1f8\x03\x01\x00\x00\x1f<" + // 0x1F380301: 0x00001F3C
"\x1f9\x03\x01\x00\x00\x1f=" + // 0x1F390301: 0x00001F3D
"\x1f8\x03B\x00\x00\x1f>" + // 0x1F380342: 0x00001F3E
"\x1f9\x03B\x00\x00\x1f?" + // 0x1F390342: 0x00001F3F
"\x03\xbf\x03\x13\x00\x00\x1f@" + // 0x03BF0313: 0x00001F40
"\x03\xbf\x03\x14\x00\x00\x1fA" + // 0x03BF0314: 0x00001F41
"\x1f@\x03\x00\x00\x00\x1fB" + // 0x1F400300: 0x00001F42
"\x1fA\x03\x00\x00\x00\x1fC" + // 0x1F410300: 0x00001F43
"\x1f@\x03\x01\x00\x00\x1fD" + // 0x1F400301: 0x00001F44
"\x1fA\x03\x01\x00\x00\x1fE" + // 0x1F410301: 0x00001F45
"\x03\x9f\x03\x13\x00\x00\x1fH" + // 0x039F0313: 0x00001F48
"\x03\x9f\x03\x14\x00\x00\x1fI" + // 0x039F0314: 0x00001F49
"\x1fH\x03\x00\x00\x00\x1fJ" + // 0x1F480300: 0x00001F4A
"\x1fI\x03\x00\x00\x00\x1fK" + // 0x1F490300: 0x00001F4B
"\x1fH\x03\x01\x00\x00\x1fL" + // 0x1F480301: 0x00001F4C
"\x1fI\x03\x01\x00\x00\x1fM" + // 0x1F490301: 0x00001F4D
"\x03\xc5\x03\x13\x00\x00\x1fP" + // 0x03C50313: 0x00001F50
"\x03\xc5\x03\x14\x00\x00\x1fQ" + // 0x03C50314: 0x00001F51
"\x1fP\x03\x00\x00\x00\x1fR" + // 0x1F500300: 0x00001F52
"\x1fQ\x03\x00\x00\x00\x1fS" + // 0x1F510300: 0x00001F53
"\x1fP\x03\x01\x00\x00\x1fT" + // 0x1F500301: 0x00001F54
"\x1fQ\x03\x01\x00\x00\x1fU" + // 0x1F510301: 0x00001F55
"\x1fP\x03B\x00\x00\x1fV" + // 0x1F500342: 0x00001F56
"\x1fQ\x03B\x00\x00\x1fW" + // 0x1F510342: 0x00001F57
"\x03\xa5\x03\x14\x00\x00\x1fY" + // 0x03A50314: 0x00001F59
"\x1fY\x03\x00\x00\x00\x1f[" + // 0x1F590300: 0x00001F5B
"\x1fY\x03\x01\x00\x00\x1f]" + // 0x1F590301: 0x00001F5D
"\x1fY\x03B\x00\x00\x1f_" + // 0x1F590342: 0x00001F5F
"\x03\xc9\x03\x13\x00\x00\x1f`" + // 0x03C90313: 0x00001F60
"\x03\xc9\x03\x14\x00\x00\x1fa" + // 0x03C90314: 0x00001F61
"\x1f`\x03\x00\x00\x00\x1fb" + // 0x1F600300: 0x00001F62
"\x1fa\x03\x00\x00\x00\x1fc" + // 0x1F610300: 0x00001F63
"\x1f`\x03\x01\x00\x00\x1fd" + // 0x1F600301: 0x00001F64
"\x1fa\x03\x01\x00\x00\x1fe" + // 0x1F610301: 0x00001F65
"\x1f`\x03B\x00\x00\x1ff" + // 0x1F600342: 0x00001F66
"\x1fa\x03B\x00\x00\x1fg" + // 0x1F610342: 0x00001F67
"\x03\xa9\x03\x13\x00\x00\x1fh" + // 0x03A90313: 0x00001F68
"\x03\xa9\x03\x14\x00\x00\x1fi" + // 0x03A90314: 0x00001F69
"\x1fh\x03\x00\x00\x00\x1fj" + // 0x1F680300: 0x00001F6A
"\x1fi\x03\x00\x00\x00\x1fk" + // 0x1F690300: 0x00001F6B
"\x1fh\x03\x01\x00\x00\x1fl" + // 0x1F680301: 0x00001F6C
"\x1fi\x03\x01\x00\x00\x1fm" + // 0x1F690301: 0x00001F6D
"\x1fh\x03B\x00\x00\x1fn" + // 0x1F680342: 0x00001F6E
"\x1fi\x03B\x00\x00\x1fo" + // 0x1F690342: 0x00001F6F
"\x03\xb1\x03\x00\x00\x00\x1fp" + // 0x03B10300: 0x00001F70
"\x03\xb5\x03\x00\x00\x00\x1fr" + // 0x03B50300: 0x00001F72
"\x03\xb7\x03\x00\x00\x00\x1ft" + // 0x03B70300: 0x00001F74
"\x03\xb9\x03\x00\x00\x00\x1fv" + // 0x03B90300: 0x00001F76
"\x03\xbf\x03\x00\x00\x00\x1fx" + // 0x03BF0300: 0x00001F78
"\x03\xc5\x03\x00\x00\x00\x1fz" + // 0x03C50300: 0x00001F7A
"\x03\xc9\x03\x00\x00\x00\x1f|" + // 0x03C90300: 0x00001F7C
"\x1f\x00\x03E\x00\x00\x1f\x80" + // 0x1F000345: 0x00001F80
"\x1f\x01\x03E\x00\x00\x1f\x81" + // 0x1F010345: 0x00001F81
"\x1f\x02\x03E\x00\x00\x1f\x82" + // 0x1F020345: 0x00001F82
"\x1f\x03\x03E\x00\x00\x1f\x83" + // 0x1F030345: 0x00001F83
"\x1f\x04\x03E\x00\x00\x1f\x84" + // 0x1F040345: 0x00001F84
"\x1f\x05\x03E\x00\x00\x1f\x85" + // 0x1F050345: 0x00001F85
"\x1f\x06\x03E\x00\x00\x1f\x86" + // 0x1F060345: 0x00001F86
"\x1f\a\x03E\x00\x00\x1f\x87" + // 0x1F070345: 0x00001F87
"\x1f\b\x03E\x00\x00\x1f\x88" + // 0x1F080345: 0x00001F88
"\x1f\t\x03E\x00\x00\x1f\x89" + // 0x1F090345: 0x00001F89
"\x1f\n\x03E\x00\x00\x1f\x8a" + // 0x1F0A0345: 0x00001F8A
"\x1f\v\x03E\x00\x00\x1f\x8b" + // 0x1F0B0345: 0x00001F8B
"\x1f\f\x03E\x00\x00\x1f\x8c" + // 0x1F0C0345: 0x00001F8C
"\x1f\r\x03E\x00\x00\x1f\x8d" + // 0x1F0D0345: 0x00001F8D
"\x1f\x0e\x03E\x00\x00\x1f\x8e" + // 0x1F0E0345: 0x00001F8E
"\x1f\x0f\x03E\x00\x00\x1f\x8f" + // 0x1F0F0345: 0x00001F8F
"\x1f \x03E\x00\x00\x1f\x90" + // 0x1F200345: 0x00001F90
"\x1f!\x03E\x00\x00\x1f\x91" + // 0x1F210345: 0x00001F91
"\x1f\"\x03E\x00\x00\x1f\x92" + // 0x1F220345: 0x00001F92
"\x1f#\x03E\x00\x00\x1f\x93" + // 0x1F230345: 0x00001F93
"\x1f$\x03E\x00\x00\x1f\x94" + // 0x1F240345: 0x00001F94
"\x1f%\x03E\x00\x00\x1f\x95" + // 0x1F250345: 0x00001F95
"\x1f&\x03E\x00\x00\x1f\x96" + // 0x1F260345: 0x00001F96
"\x1f'\x03E\x00\x00\x1f\x97" + // 0x1F270345: 0x00001F97
"\x1f(\x03E\x00\x00\x1f\x98" + // 0x1F280345: 0x00001F98
"\x1f)\x03E\x00\x00\x1f\x99" + // 0x1F290345: 0x00001F99
"\x1f*\x03E\x00\x00\x1f\x9a" + // 0x1F2A0345: 0x00001F9A
"\x1f+\x03E\x00\x00\x1f\x9b" + // 0x1F2B0345: 0x00001F9B
"\x1f,\x03E\x00\x00\x1f\x9c" + // 0x1F2C0345: 0x00001F9C
"\x1f-\x03E\x00\x00\x1f\x9d" + // 0x1F2D0345: 0x00001F9D
"\x1f.\x03E\x00\x00\x1f\x9e" + // 0x1F2E0345: 0x00001F9E
"\x1f/\x03E\x00\x00\x1f\x9f" + // 0x1F2F0345: 0x00001F9F
"\x1f`\x03E\x00\x00\x1f\xa0" + // 0x1F600345: 0x00001FA0
"\x1fa\x03E\x00\x00\x1f\xa1" + // 0x1F610345: 0x00001FA1
"\x1fb\x03E\x00\x00\x1f\xa2" + // 0x1F620345: 0x00001FA2
"\x1fc\x03E\x00\x00\x1f\xa3" + // 0x1F630345: 0x00001FA3
"\x1fd\x03E\x00\x00\x1f\xa4" + // 0x1F640345: 0x00001FA4
"\x1fe\x03E\x00\x00\x1f\xa5" + // 0x1F650345: 0x00001FA5
"\x1ff\x03E\x00\x00\x1f\xa6" + // 0x1F660345: 0x00001FA6
"\x1fg\x03E\x00\x00\x1f\xa7" + // 0x1F670345: 0x00001FA7
"\x1fh\x03E\x00\x00\x1f\xa8" + // 0x1F680345: 0x00001FA8
"\x1fi\x03E\x00\x00\x1f\xa9" + // 0x1F690345: 0x00001FA9
"\x1fj\x03E\x00\x00\x1f\xaa" + // 0x1F6A0345: 0x00001FAA
"\x1fk\x03E\x00\x00\x1f\xab" + // 0x1F6B0345: 0x00001FAB
"\x1fl\x03E\x00\x00\x1f\xac" + // 0x1F6C0345: 0x00001FAC
"\x1fm\x03E\x00\x00\x1f\xad" + // 0x1F6D0345: 0x00001FAD
"\x1fn\x03E\x00\x00\x1f\xae" + // 0x1F6E0345: 0x00001FAE
"\x1fo\x03E\x00\x00\x1f\xaf" + // 0x1F6F0345: 0x00001FAF
"\x03\xb1\x03\x06\x00\x00\x1f\xb0" + // 0x03B10306: 0x00001FB0
"\x03\xb1\x03\x04\x00\x00\x1f\xb1" + // 0x03B10304: 0x00001FB1
"\x1fp\x03E\x00\x00\x1f\xb2" + // 0x1F700345: 0x00001FB2
"\x03\xb1\x03E\x00\x00\x1f\xb3" + // 0x03B10345: 0x00001FB3
"\x03\xac\x03E\x00\x00\x1f\xb4" + // 0x03AC0345: 0x00001FB4
"\x03\xb1\x03B\x00\x00\x1f\xb6" + // 0x03B10342: 0x00001FB6
"\x1f\xb6\x03E\x00\x00\x1f\xb7" + // 0x1FB60345: 0x00001FB7
"\x03\x91\x03\x06\x00\x00\x1f\xb8" + // 0x03910306: 0x00001FB8
"\x03\x91\x03\x04\x00\x00\x1f\xb9" + // 0x03910304: 0x00001FB9
"\x03\x91\x03\x00\x00\x00\x1f\xba" + // 0x03910300: 0x00001FBA
"\x03\x91\x03E\x00\x00\x1f\xbc" + // 0x03910345: 0x00001FBC
"\x00\xa8\x03B\x00\x00\x1f\xc1" + // 0x00A80342: 0x00001FC1
"\x1ft\x03E\x00\x00\x1f\xc2" + // 0x1F740345: 0x00001FC2
"\x03\xb7\x03E\x00\x00\x1f\xc3" + // 0x03B70345: 0x00001FC3
"\x03\xae\x03E\x00\x00\x1f\xc4" + // 0x03AE0345: 0x00001FC4
"\x03\xb7\x03B\x00\x00\x1f\xc6" + // 0x03B70342: 0x00001FC6
"\x1f\xc6\x03E\x00\x00\x1f\xc7" + // 0x1FC60345: 0x00001FC7
"\x03\x95\x03\x00\x00\x00\x1f\xc8" + // 0x03950300: 0x00001FC8
"\x03\x97\x03\x00\x00\x00\x1f\xca" + // 0x03970300: 0x00001FCA
"\x03\x97\x03E\x00\x00\x1f\xcc" + // 0x03970345: 0x00001FCC
"\x1f\xbf\x03\x00\x00\x00\x1f\xcd" + // 0x1FBF0300: 0x00001FCD
"\x1f\xbf\x03\x01\x00\x00\x1f\xce" + // 0x1FBF0301: 0x00001FCE
"\x1f\xbf\x03B\x00\x00\x1f\xcf" + // 0x1FBF0342: 0x00001FCF
"\x03\xb9\x03\x06\x00\x00\x1f\xd0" + // 0x03B90306: 0x00001FD0
"\x03\xb9\x03\x04\x00\x00\x1f\xd1" + // 0x03B90304: 0x00001FD1
"\x03\xca\x03\x00\x00\x00\x1f\xd2" + // 0x03CA0300: 0x00001FD2
"\x03\xb9\x03B\x00\x00\x1f\xd6" + // 0x03B90342: 0x00001FD6
"\x03\xca\x03B\x00\x00\x1f\xd7" + // 0x03CA0342: 0x00001FD7
"\x03\x99\x03\x06\x00\x00\x1f\xd8" + // 0x03990306: 0x00001FD8
"\x03\x99\x03\x04\x00\x00\x1f\xd9" + // 0x03990304: 0x00001FD9
"\x03\x99\x03\x00\x00\x00\x1f\xda" + // 0x03990300: 0x00001FDA
"\x1f\xfe\x03\x00\x00\x00\x1f\xdd" + // 0x1FFE0300: 0x00001FDD
"\x1f\xfe\x03\x01\x00\x00\x1f\xde" + // 0x1FFE0301: 0x00001FDE
"\x1f\xfe\x03B\x00\x00\x1f\xdf" + // 0x1FFE0342: 0x00001FDF
"\x03\xc5\x03\x06\x00\x00\x1f\xe0" + // 0x03C50306: 0x00001FE0
"\x03\xc5\x03\x04\x00\x00\x1f\xe1" + // 0x03C50304: 0x00001FE1
"\x03\xcb\x03\x00\x00\x00\x1f\xe2" + // 0x03CB0300: 0x00001FE2
"\x03\xc1\x03\x13\x00\x00\x1f\xe4" + // 0x03C10313: 0x00001FE4
"\x03\xc1\x03\x14\x00\x00\x1f\xe5" + // 0x03C10314: 0x00001FE5
"\x03\xc5\x03B\x00\x00\x1f\xe6" + // 0x03C50342: 0x00001FE6
"\x03\xcb\x03B\x00\x00\x1f\xe7" + // 0x03CB0342: 0x00001FE7
"\x03\xa5\x03\x06\x00\x00\x1f\xe8" + // 0x03A50306: 0x00001FE8
"\x03\xa5\x03\x04\x00\x00\x1f\xe9" + // 0x03A50304: 0x00001FE9
"\x03\xa5\x03\x00\x00\x00\x1f\xea" + // 0x03A50300: 0x00001FEA
"\x03\xa1\x03\x14\x00\x00\x1f\xec" + // 0x03A10314: 0x00001FEC
"\x00\xa8\x03\x00\x00\x00\x1f\xed" + // 0x00A80300: 0x00001FED
"\x1f|\x03E\x00\x00\x1f\xf2" + // 0x1F7C0345: 0x00001FF2
"\x03\xc9\x03E\x00\x00\x1f\xf3" + // 0x03C90345: 0x00001FF3
"\x03\xce\x03E\x00\x00\x1f\xf4" + // 0x03CE0345: 0x00001FF4
"\x03\xc9\x03B\x00\x00\x1f\xf6" + // 0x03C90342: 0x00001FF6
"\x1f\xf6\x03E\x00\x00\x1f\xf7" + // 0x1FF60345: 0x00001FF7
"\x03\x9f\x03\x00\x00\x00\x1f\xf8" + // 0x039F0300: 0x00001FF8
"\x03\xa9\x03\x00\x00\x00\x1f\xfa" + // 0x03A90300: 0x00001FFA
"\x03\xa9\x03E\x00\x00\x1f\xfc" + // 0x03A90345: 0x00001FFC
"!\x90\x038\x00\x00!\x9a" + // 0x21900338: 0x0000219A
"!\x92\x038\x00\x00!\x9b" + // 0x21920338: 0x0000219B
"!\x94\x038\x00\x00!\xae" + // 0x21940338: 0x000021AE
"!\xd0\x038\x00\x00!\xcd" + // 0x21D00338: 0x000021CD
"!\xd4\x038\x00\x00!\xce" + // 0x21D40338: 0x000021CE
"!\xd2\x038\x00\x00!\xcf" + // 0x21D20338: 0x000021CF
"\"\x03\x038\x00\x00\"\x04" + // 0x22030338: 0x00002204
"\"\b\x038\x00\x00\"\t" + // 0x22080338: 0x00002209
"\"\v\x038\x00\x00\"\f" + // 0x220B0338: 0x0000220C
"\"#\x038\x00\x00\"$" + // 0x22230338: 0x00002224
"\"%\x038\x00\x00\"&" + // 0x22250338: 0x00002226
"\"<\x038\x00\x00\"A" + // 0x223C0338: 0x00002241
"\"C\x038\x00\x00\"D" + // 0x22430338: 0x00002244
"\"E\x038\x00\x00\"G" + // 0x22450338: 0x00002247
"\"H\x038\x00\x00\"I" + // 0x22480338: 0x00002249
"\x00=\x038\x00\x00\"`" + // 0x003D0338: 0x00002260
"\"a\x038\x00\x00\"b" + // 0x22610338: 0x00002262
"\"M\x038\x00\x00\"m" + // 0x224D0338: 0x0000226D
"\x00<\x038\x00\x00\"n" + // 0x003C0338: 0x0000226E
"\x00>\x038\x00\x00\"o" + // 0x003E0338: 0x0000226F
"\"d\x038\x00\x00\"p" + // 0x22640338: 0x00002270
"\"e\x038\x00\x00\"q" + // 0x22650338: 0x00002271
"\"r\x038\x00\x00\"t" + // 0x22720338: 0x00002274
"\"s\x038\x00\x00\"u" + // 0x22730338: 0x00002275
"\"v\x038\x00\x00\"x" + // 0x22760338: 0x00002278
"\"w\x038\x00\x00\"y" + // 0x22770338: 0x00002279
"\"z\x038\x00\x00\"\x80" + // 0x227A0338: 0x00002280
"\"{\x038\x00\x00\"\x81" + // 0x227B0338: 0x00002281
"\"\x82\x038\x00\x00\"\x84" + // 0x22820338: 0x00002284
"\"\x83\x038\x00\x00\"\x85" + // 0x22830338: 0x00002285
"\"\x86\x038\x00\x00\"\x88" + // 0x22860338: 0x00002288
"\"\x87\x038\x00\x00\"\x89" + // 0x22870338: 0x00002289
"\"\xa2\x038\x00\x00\"\xac" + // 0x22A20338: 0x000022AC
"\"\xa8\x038\x00\x00\"\xad" + // 0x22A80338: 0x000022AD
"\"\xa9\x038\x00\x00\"\xae" + // 0x22A90338: 0x000022AE
"\"\xab\x038\x00\x00\"\xaf" + // 0x22AB0338: 0x000022AF
"\"|\x038\x00\x00\"\xe0" + // 0x227C0338: 0x000022E0
"\"}\x038\x00\x00\"\xe1" + // 0x227D0338: 0x000022E1
"\"\x91\x038\x00\x00\"\xe2" + // 0x22910338: 0x000022E2
"\"\x92\x038\x00\x00\"\xe3" + // 0x22920338: 0x000022E3
"\"\xb2\x038\x00\x00\"\xea" + // 0x22B20338: 0x000022EA
"\"\xb3\x038\x00\x00\"\xeb" + // 0x22B30338: 0x000022EB
"\"\xb4\x038\x00\x00\"\xec" + // 0x22B40338: 0x000022EC
"\"\xb5\x038\x00\x00\"\xed" + // 0x22B50338: 0x000022ED
"0K0\x99\x00\x000L" + // 0x304B3099: 0x0000304C
"0M0\x99\x00\x000N" + // 0x304D3099: 0x0000304E
"0O0\x99\x00\x000P" + // 0x304F3099: 0x00003050
"0Q0\x99\x00\x000R" + // 0x30513099: 0x00003052
"0S0\x99\x00\x000T" + // 0x30533099: 0x00003054
"0U0\x99\x00\x000V" + // 0x30553099: 0x00003056
"0W0\x99\x00\x000X" + // 0x30573099: 0x00003058
"0Y0\x99\x00\x000Z" + // 0x30593099: 0x0000305A
"0[0\x99\x00\x000\\" + // 0x305B3099: 0x0000305C
"0]0\x99\x00\x000^" + // 0x305D3099: 0x0000305E
"0_0\x99\x00\x000`" + // 0x305F3099: 0x00003060
"0a0\x99\x00\x000b" + // 0x30613099: 0x00003062
"0d0\x99\x00\x000e" + // 0x30643099: 0x00003065
"0f0\x99\x00\x000g" + // 0x30663099: 0x00003067
"0h0\x99\x00\x000i" + // 0x30683099: 0x00003069
"0o0\x99\x00\x000p" + // 0x306F3099: 0x00003070
"0o0\x9a\x00\x000q" + // 0x306F309A: 0x00003071
"0r0\x99\x00\x000s" + // 0x30723099: 0x00003073
"0r0\x9a\x00\x000t" + // 0x3072309A: 0x00003074
"0u0\x99\x00\x000v" + // 0x30753099: 0x00003076
"0u0\x9a\x00\x000w" + // 0x3075309A: 0x00003077
"0x0\x99\x00\x000y" + // 0x30783099: 0x00003079
"0x0\x9a\x00\x000z" + // 0x3078309A: 0x0000307A
"0{0\x99\x00\x000|" + // 0x307B3099: 0x0000307C
"0{0\x9a\x00\x000}" + // 0x307B309A: 0x0000307D
"0F0\x99\x00\x000\x94" + // 0x30463099: 0x00003094
"0\x9d0\x99\x00\x000\x9e" + // 0x309D3099: 0x0000309E
"0\xab0\x99\x00\x000\xac" + // 0x30AB3099: 0x000030AC
"0\xad0\x99\x00\x000\xae" + // 0x30AD3099: 0x000030AE
"0\xaf0\x99\x00\x000\xb0" + // 0x30AF3099: 0x000030B0
"0\xb10\x99\x00\x000\xb2" + // 0x30B13099: 0x000030B2
"0\xb30\x99\x00\x000\xb4" + // 0x30B33099: 0x000030B4
"0\xb50\x99\x00\x000\xb6" + // 0x30B53099: 0x000030B6
"0\xb70\x99\x00\x000\xb8" + // 0x30B73099: 0x000030B8
"0\xb90\x99\x00\x000\xba" + // 0x30B93099: 0x000030BA
"0\xbb0\x99\x00\x000\xbc" + // 0x30BB3099: 0x000030BC
"0\xbd0\x99\x00\x000\xbe" + // 0x30BD3099: 0x000030BE
"0\xbf0\x99\x00\x000\xc0" + // 0x30BF3099: 0x000030C0
"0\xc10\x99\x00\x000\xc2" + // 0x30C13099: 0x000030C2
"0\xc40\x99\x00\x000\xc5" + // 0x30C43099: 0x000030C5
"0\xc60\x99\x00\x000\xc7" + // 0x30C63099: 0x000030C7
"0\xc80\x99\x00\x000\xc9" + // 0x30C83099: 0x000030C9
"0\xcf0\x99\x00\x000\xd0" + // 0x30CF3099: 0x000030D0
"0\xcf0\x9a\x00\x000\xd1" + // 0x30CF309A: 0x000030D1
"0\xd20\x99\x00\x000\xd3" + // 0x30D23099: 0x000030D3
"0\xd20\x9a\x00\x000\xd4" + // 0x30D2309A: 0x000030D4
"0\xd50\x99\x00\x000\xd6" + // 0x30D53099: 0x000030D6
"0\xd50\x9a\x00\x000\xd7" + // 0x30D5309A: 0x000030D7
"0\xd80\x99\x00\x000\xd9" + // 0x30D83099: 0x000030D9
"0\xd80\x9a\x00\x000\xda" + // 0x30D8309A: 0x000030DA
"0\xdb0\x99\x00\x000\xdc" + // 0x30DB3099: 0x000030DC
"0\xdb0\x9a\x00\x000\xdd" + // 0x30DB309A: 0x000030DD
"0\xa60\x99\x00\x000\xf4" + // 0x30A63099: 0x000030F4
"0\xef0\x99\x00\x000\xf7" + // 0x30EF3099: 0x000030F7
"0\xf00\x99\x00\x000\xf8" + // 0x30F03099: 0x000030F8
"0\xf10\x99\x00\x000\xf9" + // 0x30F13099: 0x000030F9
"0\xf20\x99\x00\x000\xfa" + // 0x30F23099: 0x000030FA
"0\xfd0\x99\x00\x000\xfe" + // 0x30FD3099: 0x000030FE
"\x10\x99\x10\xba\x00\x01\x10\x9a" + // 0x109910BA: 0x0001109A
"\x10\x9b\x10\xba\x00\x01\x10\x9c" + // 0x109B10BA: 0x0001109C
"\x10\xa5\x10\xba\x00\x01\x10\xab" + // 0x10A510BA: 0x000110AB
"\x111\x11'\x00\x01\x11." + // 0x11311127: 0x0001112E
"\x112\x11'\x00\x01\x11/" + // 0x11321127: 0x0001112F
"\x13G\x13>\x00\x01\x13K" + // 0x1347133E: 0x0001134B
"\x13G\x13W\x00\x01\x13L" + // 0x13471357: 0x0001134C
"\x14\xb9\x14\xba\x00\x01\x14\xbb" + // 0x14B914BA: 0x000114BB
"\x14\xb9\x14\xb0\x00\x01\x14\xbc" + // 0x14B914B0: 0x000114BC
"\x14\xb9\x14\xbd\x00\x01\x14\xbe" + // 0x14B914BD: 0x000114BE
"\x15\xb8\x15\xaf\x00\x01\x15\xba" + // 0x15B815AF: 0x000115BA
"\x15\xb9\x15\xaf\x00\x01\x15\xbb" + // 0x15B915AF: 0x000115BB
"\x195\x190\x00\x01\x198" + // 0x19351930: 0x00011938
""
// Total size of tables: 56KB (57068 bytes)
// Copyright 2013 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 norm
import (
"unicode/utf8"
"golang.org/x/text/transform"
)
// Reset implements the Reset method of the transform.Transformer interface.
func (Form) Reset() {}
// Transform implements the Transform method of the transform.Transformer
// interface. It may need to write segments of up to MaxSegmentSize at once.
// Users should either catch ErrShortDst and allow dst to grow or have dst be at
// least of size MaxTransformChunkSize to be guaranteed of progress.
func (f Form) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
// Cap the maximum number of src bytes to check.
b := src
eof := atEOF
if ns := len(dst); ns < len(b) {
err = transform.ErrShortDst
eof = false
b = b[:ns]
}
i, ok := formTable[f].quickSpan(inputBytes(b), 0, len(b), eof)
n := copy(dst, b[:i])
if !ok {
nDst, nSrc, err = f.transform(dst[n:], src[n:], atEOF)
return nDst + n, nSrc + n, err
}
if err == nil && n < len(src) && !atEOF {
err = transform.ErrShortSrc
}
return n, n, err
}
func flushTransform(rb *reorderBuffer) bool {
// Write out (must fully fit in dst, or else it is an ErrShortDst).
if len(rb.out) < rb.nrune*utf8.UTFMax {
return false
}
rb.out = rb.out[rb.flushCopy(rb.out):]
return true
}
var errs = []error{nil, transform.ErrShortDst, transform.ErrShortSrc}
// transform implements the transform.Transformer interface. It is only called
// when quickSpan does not pass for a given string.
func (f Form) transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
// TODO: get rid of reorderBuffer. See CL 23460044.
rb := reorderBuffer{}
rb.init(f, src)
for {
// Load segment into reorder buffer.
rb.setFlusher(dst[nDst:], flushTransform)
end := decomposeSegment(&rb, nSrc, atEOF)
if end < 0 {
return nDst, nSrc, errs[-end]
}
nDst = len(dst) - len(rb.out)
nSrc = end
// Next quickSpan.
end = rb.nsrc
eof := atEOF
if n := nSrc + len(dst) - nDst; n < end {
err = transform.ErrShortDst
end = n
eof = false
}
end, ok := rb.f.quickSpan(rb.src, nSrc, end, eof)
n := copy(dst[nDst:], rb.src.bytes[nSrc:end])
nSrc += n
nDst += n
if ok {
if err == nil && n < rb.nsrc && !atEOF {
err = transform.ErrShortSrc
}
return nDst, nSrc, err
}
}
}
// Copyright 2011 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 norm
type valueRange struct {
value uint16 // header: value:stride
lo, hi byte // header: lo:n
}
type sparseBlocks struct {
values []valueRange
offset []uint16
}
var nfcSparse = sparseBlocks{
values: nfcSparseValues[:],
offset: nfcSparseOffset[:],
}
var nfkcSparse = sparseBlocks{
values: nfkcSparseValues[:],
offset: nfkcSparseOffset[:],
}
var (
nfcData = newNfcTrie(0)
nfkcData = newNfkcTrie(0)
)
// lookup determines the type of block n and looks up the value for b.
// For n < t.cutoff, the block is a simple lookup table. Otherwise, the block
// is a list of ranges with an accompanying value. Given a matching range r,
// the value for b is by r.value + (b - r.lo) * stride.
func (t *sparseBlocks) lookup(n uint32, b byte) uint16 {
offset := t.offset[n]
header := t.values[offset]
lo := offset + 1
hi := lo + uint16(header.lo)
for lo < hi {
m := lo + (hi-lo)/2
r := t.values[m]
if r.lo <= b && b <= r.hi {
return r.value + uint16(b-r.lo)*header.value
}
if b < r.lo {
hi = m
} else {
lo = m + 1
}
}
return 0
}
// 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.
package rangetable
import (
"unicode"
)
// atEnd is used to mark a completed iteration.
const atEnd = unicode.MaxRune + 1
// Merge returns a new RangeTable that is the union of the given tables.
// It can also be used to compact user-created RangeTables. The entries in
// R16 and R32 for any given RangeTable should be sorted and non-overlapping.
//
// A lookup in the resulting table can be several times faster than using In
// directly on the ranges. Merge is an expensive operation, however, and only
// makes sense if one intends to use the result for more than a couple of
// hundred lookups.
func Merge(ranges ...*unicode.RangeTable) *unicode.RangeTable {
rt := &unicode.RangeTable{}
if len(ranges) == 0 {
return rt
}
iter := tablesIter(make([]tableIndex, len(ranges)))
for i, t := range ranges {
iter[i] = tableIndex{t, 0, atEnd}
if len(t.R16) > 0 {
iter[i].next = rune(t.R16[0].Lo)
}
}
if r0 := iter.next16(); r0.Stride != 0 {
for {
r1 := iter.next16()
if r1.Stride == 0 {
rt.R16 = append(rt.R16, r0)
break
}
stride := r1.Lo - r0.Hi
if (r1.Lo == r1.Hi || stride == r1.Stride) && (r0.Lo == r0.Hi || stride == r0.Stride) {
// Fully merge the next range into the previous one.
r0.Hi, r0.Stride = r1.Hi, stride
continue
} else if stride == r0.Stride {
// Move the first element of r1 to r0. This may eliminate an
// entry.
r0.Hi = r1.Lo
r0.Stride = stride
r1.Lo = r1.Lo + r1.Stride
if r1.Lo > r1.Hi {
continue
}
}
rt.R16 = append(rt.R16, r0)
r0 = r1
}
}
for i, t := range ranges {
iter[i] = tableIndex{t, 0, atEnd}
if len(t.R32) > 0 {
iter[i].next = rune(t.R32[0].Lo)
}
}
if r0 := iter.next32(); r0.Stride != 0 {
for {
r1 := iter.next32()
if r1.Stride == 0 {
rt.R32 = append(rt.R32, r0)
break
}
stride := r1.Lo - r0.Hi
if (r1.Lo == r1.Hi || stride == r1.Stride) && (r0.Lo == r0.Hi || stride == r0.Stride) {
// Fully merge the next range into the previous one.
r0.Hi, r0.Stride = r1.Hi, stride
continue
} else if stride == r0.Stride {
// Move the first element of r1 to r0. This may eliminate an
// entry.
r0.Hi = r1.Lo
r1.Lo = r1.Lo + r1.Stride
if r1.Lo > r1.Hi {
continue
}
}
rt.R32 = append(rt.R32, r0)
r0 = r1
}
}
for i := 0; i < len(rt.R16) && rt.R16[i].Hi <= unicode.MaxLatin1; i++ {
rt.LatinOffset = i + 1
}
return rt
}
type tableIndex struct {
t *unicode.RangeTable
p uint32
next rune
}
type tablesIter []tableIndex
// sortIter does an insertion sort using the next field of tableIndex. Insertion
// sort is a good sorting algorithm for this case.
func sortIter(t []tableIndex) {
for i := range t {
for j := i; j > 0 && t[j-1].next > t[j].next; j-- {
t[j], t[j-1] = t[j-1], t[j]
}
}
}
// next16 finds the ranged to be added to the table. If ranges overlap between
// multiple tables it clips the result to a non-overlapping range if the
// elements are not fully subsumed. It returns a zero range if there are no more
// ranges.
func (ti tablesIter) next16() unicode.Range16 {
sortIter(ti)
t0 := ti[0]
if t0.next == atEnd {
return unicode.Range16{}
}
r0 := t0.t.R16[t0.p]
r0.Lo = uint16(t0.next)
// We restrict the Hi of the current range if it overlaps with another range.
for i := range ti {
tn := ti[i]
// Since our tableIndices are sorted by next, we can break if the there
// is no overlap. The first value of a next range can always be merged
// into the current one, so we can break in case of equality as well.
if rune(r0.Hi) <= tn.next {
break
}
rn := tn.t.R16[tn.p]
rn.Lo = uint16(tn.next)
// Limit r0.Hi based on next ranges in list, but allow it to overlap
// with ranges as long as it subsumes it.
m := (rn.Lo - r0.Lo) % r0.Stride
if m == 0 && (rn.Stride == r0.Stride || rn.Lo == rn.Hi) {
// Overlap, take the min of the two Hi values: for simplicity's sake
// we only process one range at a time.
if r0.Hi > rn.Hi {
r0.Hi = rn.Hi
}
} else {
// Not a compatible stride. Set to the last possible value before
// rn.Lo, but ensure there is at least one value.
if x := rn.Lo - m; r0.Lo <= x {
r0.Hi = x
}
break
}
}
// Update the next values for each table.
for i := range ti {
tn := &ti[i]
if rune(r0.Hi) < tn.next {
break
}
rn := tn.t.R16[tn.p]
stride := rune(rn.Stride)
tn.next += stride * (1 + ((rune(r0.Hi) - tn.next) / stride))
if rune(rn.Hi) < tn.next {
if tn.p++; int(tn.p) == len(tn.t.R16) {
tn.next = atEnd
} else {
tn.next = rune(tn.t.R16[tn.p].Lo)
}
}
}
if r0.Lo == r0.Hi {
r0.Stride = 1
}
return r0
}
// next32 finds the ranged to be added to the table. If ranges overlap between
// multiple tables it clips the result to a non-overlapping range if the
// elements are not fully subsumed. It returns a zero range if there are no more
// ranges.
func (ti tablesIter) next32() unicode.Range32 {
sortIter(ti)
t0 := ti[0]
if t0.next == atEnd {
return unicode.Range32{}
}
r0 := t0.t.R32[t0.p]
r0.Lo = uint32(t0.next)
// We restrict the Hi of the current range if it overlaps with another range.
for i := range ti {
tn := ti[i]
// Since our tableIndices are sorted by next, we can break if the there
// is no overlap. The first value of a next range can always be merged
// into the current one, so we can break in case of equality as well.
if rune(r0.Hi) <= tn.next {
break
}
rn := tn.t.R32[tn.p]
rn.Lo = uint32(tn.next)
// Limit r0.Hi based on next ranges in list, but allow it to overlap
// with ranges as long as it subsumes it.
m := (rn.Lo - r0.Lo) % r0.Stride
if m == 0 && (rn.Stride == r0.Stride || rn.Lo == rn.Hi) {
// Overlap, take the min of the two Hi values: for simplicity's sake
// we only process one range at a time.
if r0.Hi > rn.Hi {
r0.Hi = rn.Hi
}
} else {
// Not a compatible stride. Set to the last possible value before
// rn.Lo, but ensure there is at least one value.
if x := rn.Lo - m; r0.Lo <= x {
r0.Hi = x
}
break
}
}
// Update the next values for each table.
for i := range ti {
tn := &ti[i]
if rune(r0.Hi) < tn.next {
break
}
rn := tn.t.R32[tn.p]
stride := rune(rn.Stride)
tn.next += stride * (1 + ((rune(r0.Hi) - tn.next) / stride))
if rune(rn.Hi) < tn.next {
if tn.p++; int(tn.p) == len(tn.t.R32) {
tn.next = atEnd
} else {
tn.next = rune(tn.t.R32[tn.p].Lo)
}
}
}
if r0.Lo == r0.Hi {
r0.Stride = 1
}
return r0
}
// 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.
// Package rangetable provides utilities for creating and inspecting
// unicode.RangeTables.
package rangetable
import (
"sort"
"unicode"
)
// New creates a RangeTable from the given runes, which may contain duplicates.
func New(r ...rune) *unicode.RangeTable {
if len(r) == 0 {
return &unicode.RangeTable{}
}
sort.Sort(byRune(r))
// Remove duplicates.
k := 1
for i := 1; i < len(r); i++ {
if r[k-1] != r[i] {
r[k] = r[i]
k++
}
}
var rt unicode.RangeTable
for _, r := range r[:k] {
if r <= 0xFFFF {
rt.R16 = append(rt.R16, unicode.Range16{Lo: uint16(r), Hi: uint16(r), Stride: 1})
} else {
rt.R32 = append(rt.R32, unicode.Range32{Lo: uint32(r), Hi: uint32(r), Stride: 1})
}
}
// Optimize RangeTable.
return Merge(&rt)
}
type byRune []rune
func (r byRune) Len() int { return len(r) }
func (r byRune) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
func (r byRune) Less(i, j int) bool { return r[i] < r[j] }
// Visit visits all runes in the given RangeTable in order, calling fn for each.
func Visit(rt *unicode.RangeTable, fn func(rune)) {
for _, r16 := range rt.R16 {
for r := rune(r16.Lo); r <= rune(r16.Hi); r += rune(r16.Stride) {
fn(r)
}
}
for _, r32 := range rt.R32 {
for r := rune(r32.Lo); r <= rune(r32.Hi); r += rune(r32.Stride) {
fn(r)
}
}
}
// Assigned returns a RangeTable with all assigned code points for a given
// Unicode version. This includes graphic, format, control, and private-use
// characters. It returns nil if the data for the given version is not
// available.
func Assigned(version string) *unicode.RangeTable {
return assigned[version]
}
// 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.
//go:generate go run gen.go
// Package runenames provides rune names from the Unicode Character Database.
// For example, the name for '\u0100' is "LATIN CAPITAL LETTER A WITH MACRON".
//
// See https://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt
package runenames
import (
"sort"
)
// Name returns the name for r.
func Name(r rune) string {
i := sort.Search(len(entries), func(j int) bool {
return entries[j].startRune() > r
})
if i == 0 {
return ""
}
e := entries[i-1]
offset := int(r - e.startRune())
if offset >= e.numRunes() {
return ""
}
if e.direct() {
o := e.index()
n := e.len()
return directData[o : o+n]
}
start := int(index[e.index()+offset])
end := int(index[e.index()+offset+1])
base1 := e.base() << 16
base2 := base1
if start > end {
base2 += 1 << 16
}
return singleData[start+base1 : end+base2]
}
func (e entry) len() int { return e.base() }
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.21
package runenames
// UnicodeVersion is the Unicode version from which the tables in this package are derived.
const UnicodeVersion = "15.0.0"
type entry uint64
func (e entry) startRune() int32 {
return int32((e >> 43) & 0x1fffff)
}
func (e entry) numRunes() int {
return int((e >> 27) & 0xffff)
}
func (e entry) index() int {
return int((e >> 11) & 0xffff)
}
func (e entry) base() int {
return int((e >> 5) & 0x3f)
}
func (e entry) direct() bool {
const bit = 1 << 4
return e&bit == bit
}
var entries = []entry{ // 731 elements
// Entry 0 - 1F
0x00000001000d5930, 0x00010002f8000000, 0x0003f801080d5930, 0x00050016c002f800,
0x001bd0003019b800, 0x001c20003819e800, 0x001c6000081a2000, 0x001c7000a01a2800,
0x001d180c681ac800, 0x0029880130273000, 0x002ac80190286000, 0x002c68001829f000,
0x002c8801b82a0800, 0x002e8000d82bc000, 0x002f7800302c9800, 0x00300008702cc800,
0x00387801e0353800, 0x003a680328371800, 0x003e0001d83a4000, 0x003fe801883c1800,
0x00418000783da000, 0x00420000e03e1800, 0x0042f000083ef800, 0x00430000583f0000,
0x00438000f83f5800, 0x0044800010405000, 0x0044c00760406000, 0x004c28004047c000,
0x004c780010480000, 0x004c9800b0481000, 0x004d50003848c000, 0x004d90000848f800,
// Entry 20 - 3F
0x004db00020490000, 0x004de00048492000, 0x004e380010496800, 0x004e580020497800,
0x004eb80008499800, 0x004ee0001049a000, 0x004ef8002849b000, 0x004f30000849d800,
0x004f3800c049e020, 0x00500800184aa020, 0x00502800304ab820, 0x00507800104ae820,
0x00509800b04af820, 0x00515000384ba820, 0x00519000104be020, 0x0051a800104bf020,
0x0051c000104c0020, 0x0051e000084c1020, 0x0051f000284c1820, 0x00523800104c4020,
0x00525800184c5020, 0x00528800084c6820, 0x0052c800204c7020, 0x0052f000084c9020,
0x00533000884c9820, 0x00540800184d2020, 0x00542800484d3820, 0x00547800184d8020,
0x00549800b04d9820, 0x00555000384e4820, 0x00559000104e8020, 0x0055a800284e9020,
// Entry 40 - 5F
0x0055e000504eb820, 0x00563800184f0820, 0x00565800184f2020, 0x00568000084f3820,
0x00570000204f4020, 0x00573000604f6020, 0x0057c800384fc020, 0x00580800184ff820,
0x0058280040501020, 0x0058780010505020, 0x00589800b0506020, 0x0059500038511020,
0x0059900010514820, 0x0059a80028515820, 0x0059e00048518020, 0x005a38001051c820,
0x005a58001851d820, 0x005aa8001851f020, 0x005ae00010520820, 0x005af80028521820,
0x005b300090524020, 0x005c10001052d020, 0x005c28003052e020, 0x005c700018531020,
0x005c900020532820, 0x005cc80010534820, 0x005ce00008535820, 0x005cf00010536020,
0x005d180010537020, 0x005d400018538020, 0x005d700060539820, 0x005df0002853f820,
// Entry 60 - 7F
0x005e300018542020, 0x005e500020543820, 0x005e800008545820, 0x005eb80008546020,
0x005f3000a8546820, 0x0060000068551020, 0x0060700018557820, 0x00609000b8559020,
0x0061500080564820, 0x0061e0004856c820, 0x0062300018571020, 0x0062500020572820,
0x0062a80010574820, 0x0062c00018575820, 0x0062e80008577020, 0x0063000020577820,
0x0063300050579820, 0x0063b800b057e820, 0x0064700018589820, 0x00649000b858b020,
0x0065500050596820, 0x0065a8002859b820, 0x0065e0004859e020, 0x00663000185a2820,
0x00665000205a4020, 0x0066a800105a6020, 0x0066e800105a7020, 0x00670000205a8020,
0x00673000505aa020, 0x00678800185af020, 0x00680000685b0820, 0x00687000185b7020,
// Entry 80 - 9F
0x00689001985b8820, 0x006a3000185d2020, 0x006a5000305d3820, 0x006aa000805d6820,
0x006b3000d05de820, 0x006c0800185eb820, 0x006c2800905ed020, 0x006cd000c05f6020,
0x006d980048602020, 0x006de80008606820, 0x006e000038607020, 0x006e50000860a820,
0x006e78003060b020, 0x006eb0000860e020, 0x006ec0004060e820, 0x006f300050612820,
0x006f900018617820, 0x00700801d0619020, 0x0071f800e8636020, 0x0074080010644820,
0x0074200008645820, 0x0074300028646020, 0x00746000c0648820, 0x0075280008654820,
0x00753800b8655020, 0x0076000028660820, 0x0076300008663020, 0x0076400038663820,
0x0076800050667020, 0x0076e0002066c020, 0x007800024066e020, 0x007a480120692020,
// Entry A0 - BF
0x007b8801386a4020, 0x007cc801206b7820, 0x007df000786c9820, 0x007e7000686d1020,
0x00800006306d7820, 0x008638000873a820, 0x008668000873b020, 0x0086800bc873b820,
0x00925000207f8020, 0x00928000387fa020, 0x0092c000087fd820, 0x0092d000207fe020,
0x0093000148800020, 0x0094500020814820, 0x0094800108816820, 0x0095900020827020,
0x0095c00038829020, 0x009600000882c820, 0x009610002082d020, 0x009640007882f020,
0x0096c001c8836820, 0x0098900020853020, 0x0098c00218855020, 0x009ae80100876820,
0x009c0000d0886820, 0x009d0002b0893820, 0x009fc000308be820, 0x00a00014e88c1820,
0x00b50000e0a10020, 0x00b5e001e8a1e040, 0x00b80000b0a3c840, 0x00b8f800c0a47840,
// Entry C0 - DF
0x00ba0000a0a53840, 0x00bb000068a5d840, 0x00bb700018a64040, 0x00bb900010a65840,
0x00bc0002f0a66840, 0x00bf000050a95840, 0x00bf800050a9a840, 0x00c00000d0a9f840,
0x00c10002c8aac840, 0x00c4000158ad9040, 0x00c5800230aee840, 0x00c80000f8b11840,
0x00c9000060b21040, 0x00c9800060b27040, 0x00ca000008b2d040, 0x00ca200150b2d840,
0x00cb800028b42840, 0x00cc000160b45040, 0x00cd8000d0b5b040, 0x00ce800058b68040,
0x00cef001f0b6d840, 0x00d0f00208b8c840, 0x00d30000e8bad040, 0x00d3f80058bbb840,
0x00d4800050bc1040, 0x00d5000070bc6040, 0x00d58000f8bcd040, 0x00d8000268bdc840,
0x00da800178c03040, 0x00dc0003a0c1a840, 0x00dfe001e0c54840, 0x00e1d80078c72840,
// Entry E0 - FF
0x00e26801e0c7a040, 0x00e4800158c98040, 0x00e5e80058cad840, 0x00e6800158cb3040,
0x00e80010b0cc8840, 0x00f8c00030dd3840, 0x00f9000130dd6840, 0x00fa400030de9840,
0x00fa800040dec840, 0x00fac80008df0840, 0x00fad80008df1040, 0x00fae80008df1840,
0x00faf800f8df2040, 0x00fc0001a8e01840, 0x00fdb00078e1c040, 0x00fe300070e23840,
0x00feb00030e2a840, 0x00fee80098e2d840, 0x00ff900018e37040, 0x00ffb00048e38840,
0x0100000328e3d040, 0x0103300060e6f840, 0x0103a000d8e75840, 0x0104800068e83040,
0x0105000108e89840, 0x0106800108e9a040, 0x01080000e8eaa840, 0x0108e80378eb9060,
0x010c8014b8ef0860, 0x012200005903c060, 0x0123003579041860, 0x0158780329399080,
// Entry 100 - 11F
0x015bb001013cb880, 0x015cb80ae93db880, 0x0167c8016948a080, 0x01693800094a0880,
0x01696800094a1080, 0x01698001c14a1880, 0x016b7800114bd880, 0x016bf800c14be880,
0x016d0000394ca880, 0x016d4000394ce080, 0x016d8000394d1880, 0x016dc000394d5080,
0x016e0000394d8880, 0x016e4000394dc080, 0x016e8000394df880, 0x016ec000394e3080,
0x016f0003f14e6880, 0x01740000d1525880, 0x0174d802c9532880, 0x01780006b155f080,
0x017f8000615ca080, 0x01800002015d0080, 0x01820802b15f0080, 0x0184c8033961b080,
0x018828015964e880, 0x01898802f1664080, 0x018c8002a1693080, 0x018f8001796bd080,
0x0191000f016d4880, 0x01a000ce00000370, 0x026e0002017c4880, 0x027002900006c1f0,
// Entry 120 - 13F
0x0500001a097e4880, 0x051a080a619850a0, 0x05248001b9a2b0a0, 0x0526800ae1a468a0,
0x05320005c1af48a0, 0x0538000659b508a0, 0x053e800011bb60a0, 0x053e980009bb70a0,
0x053ea80029bb78a0, 0x053f9001d9bba0a0, 0x0541800051bd78a0, 0x05420001c1bdc8a0,
0x0544000231bf88a0, 0x0546700061c1b8a0, 0x05470003a1c218a0, 0x054af800f1c5b8a0,
0x054c000271c6a8a0, 0x054e780059c918a0, 0x054ef00109c970a0, 0x05500001b9ca78a0,
0x0552000071cc30a0, 0x0552800051cca0a0, 0x0552e00339ccf0a0, 0x0556d800e1d028a0,
0x0558080031d108a0, 0x0558480031d138a0, 0x0558880031d168a0, 0x0559000039d198a0,
0x0559400039d1d0a0, 0x05598001e1d208a0, 0x055b8003f1d3e8a0, 0x055f800051d7d8a0,
// Entry 140 - 15F
0x0560015d20073a30, 0x06bd8000b9d828a0, 0x06be580189d8e0a0, 0x06c0001c00083c10,
0x06dc0004000a9b90, 0x06e000200007c1f0, 0x070000c8000b79b0, 0x07c8000b71da68a0,
0x07d3800351e5d8a0, 0x07d8000039e928a0, 0x07d8980029e960a0, 0x07d8e800d1e988a0,
0x07d9c00029ea58a0, 0x07d9f00009ea80a0, 0x07da000011ea88a0, 0x07da180011ea98a0,
0x07da3002a9eaa8a0, 0x07dcd80141ed50c0, 0x07de980de9ee90c0, 0x07ec9001b1fc78c0,
0x07ee780009fe28c0, 0x07ef800151fe30c0, 0x07f1000199ff80c0, 0x07f2a0009a0118c0,
0x07f340002201b0c0, 0x07f380002a01d0c0, 0x07f3b0043a01f8c0, 0x07f7f8000a0630c0,
0x07f80805f20638c0, 0x07fe1000320c28c0, 0x07fe5000320c58c0, 0x07fe9000320c88c0,
// Entry 160 - 17F
0x07fed0001a0cb8c0, 0x07ff00003a0cd0c0, 0x07ff40003a0d08c0, 0x07ffc8002a0d40c0,
0x08000000620d68c0, 0x08006800d20dc8c0, 0x080140009a0e98c0, 0x0801e000120f30c0,
0x0801f8007a0f40c0, 0x08028000720fb8c0, 0x08040003da1028c0, 0x080800001a1400c0,
0x080838016a1418c0, 0x0809b802c21580c0, 0x080c80006a1840c0, 0x080d00000a18a8c0,
0x080e80017218b0c0, 0x08140000ea1a20c0, 0x081500018a1b08c0, 0x08170000e21c90c0,
0x08180001221d70c0, 0x08196800f21e90c0, 0x081a80015a1f80c0, 0x081c0000f220d8c0,
0x081cf8012a21c8c0, 0x081e40007222f0c0, 0x08200004f22360c0, 0x08250000522850c0,
0x082580012228a0c0, 0x0826c0012229c0c0, 0x08280001422ae0c0, 0x08298001a22c20c0,
// Entry 180 - 19F
0x082b7800622dc0c0, 0x082be0007a2e20c0, 0x082c60003a2e98c0, 0x082ca000122ed0c0,
0x082cb8005a2ee0c0, 0x082d18007a2f38c0, 0x082d98003a2fb0c0, 0x082dd800122fe8c0,
0x08300001222ff8c0, 0x083120089a3118e0, 0x083a0000b239b0e0, 0x083b0000423a60e0,
0x083c0000323aa0e0, 0x083c3801523ad0e0, 0x083d90004a3c20e0, 0x08400000323c68e0,
0x084040000a3c98e0, 0x08405001623ca0e0, 0x0841b800123e00e0, 0x0841e0000a3e10e0,
0x0841f800ba3e18e0, 0x0842b802423ed0e0, 0x084538004a4110e0, 0x084700009a4158e0,
0x0847a0001241f0e0, 0x0847d8010a4200e0, 0x0848f800da4308e0, 0x0849f8000a43e0e0,
0x084c0001c243e8e0, 0x084de000a245a8e0, 0x084e9001924648e0, 0x085028001247d8e0,
// Entry 1A0 - 1BF
0x085060004247e8e0, 0x0850a8001a4828e0, 0x0850c800ea4840e0, 0x0851c0001a4928e0,
0x0851f800524940e0, 0x085280004a4990e0, 0x085300020249d8e0, 0x085600013a4bd8e0,
0x08575800624d10e0, 0x08580001b24d70e0, 0x0859c800ea4f20e0, 0x085ac000da5008e0,
0x085bc000d250e0e0, 0x085cc8002251b0e0, 0x085d48003a51d0e0, 0x086000024a5208e0,
0x086400019a5450e0, 0x086600019a55e8e0, 0x0867d001725780e0, 0x086980005258f0e0,
0x08730000fa5940e0, 0x08740001525a38e0, 0x087558001a5b88e0, 0x08758000125ba0e0,
0x0877e8015a5bb0e0, 0x08798001525d08e0, 0x087b8000d25e58e0, 0x087d8000e25f28e0,
0x087f0000ba6008e0, 0x088000027260c0e0, 0x08829001226330e0, 0x0883f802226450e0,
// Entry 1C0 - 1DF
0x088668000a6670e0, 0x08868000ca6678e0, 0x08878000526740e0, 0x08880001aa6790e0,
0x0889b000926938e0, 0x088a80013a69c8e0, 0x088c0003026b00e0, 0x088f0800a26e00e0,
0x08900000926ea0e0, 0x089098017a6f30e0, 0x089400003a70a8e0, 0x089440000a70e0e0,
0x089450002270e8e0, 0x089478007a7108e0, 0x0894f8005a7180e0, 0x08958001da71d8e0,
0x089780005273b0e0, 0x08980000227400e0, 0x08982800427420e0, 0x08987800127460e0,
0x08989800b27470e0, 0x089950003a7520e0, 0x08999000127558e0, 0x0899a8002a7568e0,
0x0899d800527590e0, 0x089a38001275e0e0, 0x089a58001a75f0e0, 0x089a80000a7608e0,
0x089ab8000a7610e0, 0x089ae8003a7618e0, 0x089b30003a7650e0, 0x089b80002a7688e0,
// Entry 1E0 - 1FF
0x08a00002e276b0e0, 0x08a2e8002a7990e0, 0x08a400024279b8e0, 0x08a68000527bf8e0,
0x08ac0001b27c48e0, 0x08adc001327df8e0, 0x08b000022a7f28e0, 0x08b28000528150e0,
0x08b300006a81a0e0, 0x08b40001d28208e0, 0x08b600005283d8e0, 0x08b80000da8428e0,
0x08b8e8007a8500e0, 0x08b98000ba8578e0, 0x08c00001e28630e0, 0x08c500029a8810e0,
0x08c7f800428aa8e0, 0x08c848000a8ae8e0, 0x08c86000428af0e0, 0x08c8a800128b30e0,
0x08c8c000f28b40e0, 0x08c9b800128c30e0, 0x08c9d800628c40e0, 0x08ca8000528ca0e0,
0x08cd00002a8cf0e0, 0x08cd28001a8d1900, 0x08cd5001728d3100, 0x08ced0005a8ea100,
0x08d00002428ef900, 0x08d280029a913900, 0x08d580024a93d100, 0x08d8000052961900,
// Entry 200 - 21F
0x08e000004a966900, 0x08e050016a96b100, 0x08e1c00072981900, 0x08e28000ea988900,
0x08e3800102997100, 0x08e49000b29a7100, 0x08e54800729b2100, 0x08e800003a9b9100,
0x08e84000129bc900, 0x08e85801629bd900, 0x08e9d0000a9d3900, 0x08e9e000129d4100,
0x08e9f8004a9d5100, 0x08ea8000529d9900, 0x08eb0000329de900, 0x08eb3800129e1900,
0x08eb50012a9e2900, 0x08ec8000129f5100, 0x08ec9800329f6100, 0x08ed0000529f9100,
0x08f70000ca9fe100, 0x08f800008aa0a900, 0x08f890014aa13100, 0x08f9f000e2a27900,
0x08fd80000aa35900, 0x08fe000192a36100, 0x08fff81cdaa4f100, 0x092000037ac1c900,
0x092380002ac54100, 0x0924000622c56900, 0x097c80031acb8900, 0x0980000daacea100,
// Entry 220 - 23F
0x098da8150adc4920, 0x0a2000123af15120, 0x0b400011cb038920, 0x0b520000fb155120,
0x0b53000053164920, 0x0b5370028b169920, 0x0b56000053192120, 0x0b568000f3197120,
0x0b578000331a6120, 0x0b580002331a9120, 0x0b5a8000531cc120, 0x0b5ad8003b1d1120,
0x0b5b1800ab1d4920, 0x0b5be8009b1df120, 0x0b720002db1e8920, 0x0b7800025b216120,
0x0b7a7801cb23b920, 0x0b7c78008b258120, 0x0b7f00002b260920, 0x0b7f800013263120,
0x0b8000bfc00cca50, 0x0c40000bc3264120, 0x0c4bc01af3320140, 0x0c680000480be3b0,
0x0d7f8000234cf140, 0x0d7fa8003b4d1140, 0x0d7fe800134d4940, 0x0d8000091b4d5940,
0x0d8990000b567140, 0x0d8a80001b567940, 0x0d8aa8000b569140, 0x0d8b200023569940,
// Entry 240 - 25F
0x0d8b800c6356b940, 0x0de000035b631940, 0x0de380006b667140, 0x0de400004b66d940,
0x0de4800053672140, 0x0de4e00043677140, 0x0e7800017367b140, 0x0e798000bb692140,
0x0e7a8003a369d940, 0x0e800007b36d7940, 0x0e8800013b752940, 0x0e894804fb766140,
0x0e8e40011b7b5960, 0x0e900002337c7160, 0x0e960000a37ea160, 0x0e970000a37f4160,
0x0e980002bb7fe160, 0x0e9b0000cb829960, 0x0ea00002ab836160, 0x0ea2b0023b860960,
0x0ea4f00013884160, 0x0ea510000b885160, 0x0ea5280013885960, 0x0ea5480023886960,
0x0ea5700063888960, 0x0ea5d8000b88e960, 0x0ea5e8003b88f160, 0x0ea628020b892960,
0x0ea83800238b3160, 0x0ea86800438b5160, 0x0ea8b0003b8b9160, 0x0ea8f000e38bc960,
// Entry 260 - 27F
0x0ea9d800238ca960, 0x0eaa00002b8cc960, 0x0eaa30000b8cf160, 0x0eaa50003b8cf960,
0x0eaa900aa38d3160, 0x0eb540092397d160, 0x0ebe7012eba0f160, 0x0ed158030bb3d980,
0x0ed4d8002bb6e180, 0x0ed508007bb70980, 0x0ef80000fbb78180, 0x0ef9280033b87980,
0x0f0000003bb8a980, 0x0f0040008bb8e180, 0x0f00d8003bb96980, 0x0f01180013b9a180,
0x0f0130002bb9b180, 0x0f018001f3b9d980, 0x0f0478000bbbc980, 0x0f0800016bbbd180,
0x0f09800073bd3980, 0x0f0a000053bda980, 0x0f0a700013bdf980, 0x0f148000fbbe0980,
0x0f160001d3bf0180, 0x0f17f8000bc0d180, 0x0f26800153c0d980, 0x0f3f00003bc22980,
0x0f3f400023c26180, 0x0f3f680013c28180, 0x0f3f80007bc29180, 0x0f4000062bc30980,
// Entry 280 - 29F
0x0f46380083c93180, 0x0f48000263c9b180, 0x0f4a800053cc1180, 0x0f4af00013cc6180,
0x0f63880223cc7180, 0x0f680801ebce9180, 0x0f70000023d07980, 0x0f702800dbd09980,
0x0f71080013d17180, 0x0f7120000bd18180, 0x0f7138000bd18980, 0x0f71480053d19180,
0x0f71a00023d1e180, 0x0f71c8000bd20180, 0x0f71d8000bd20980, 0x0f7210000bd21180,
0x0f7238000bd21980, 0x0f7248000bd22180, 0x0f7258000bd22980, 0x0f7268001bd23180,
0x0f72880013d24980, 0x0f72a0000bd25980, 0x0f72b8000bd26180, 0x0f72c8000bd26980,
0x0f72d8000bd27180, 0x0f72e8000bd27980, 0x0f72f8000bd28180, 0x0f73080013d28980,
0x0f7320000bd29980, 0x0f73380023d2a180, 0x0f7360003bd2c180, 0x0f73a00023d2f980,
// Entry 2A0 - 2BF
0x0f73c80023d31980, 0x0f73f0000bd33980, 0x0f74000053d34180, 0x0f7458008bd39180,
0x0f7508001bd41980, 0x0f7528002bd43180, 0x0f7558008bd45980, 0x0f77800013d4e180,
0x0f80000163d4f180, 0x0f81800323d65180, 0x0f8500007bd97180, 0x0f8588007bd9e980,
0x0f8608007bda6180, 0x0f8688012bdad980, 0x0f88000573dc0180, 0x0f8f3000ebe17180,
0x0f90800163e25980, 0x0f9200004be3b980, 0x0f92800013e40180, 0x0f93000033e41180,
0x0f98001ec3e44180, 0x0fb6e0008c030180, 0x0fb780006c038980, 0x0fb80003bc03f180,
0x0fbbd800a407a980, 0x0fbc78025c0849a0, 0x0fbf0000640aa1a0, 0x0fbf80000c0b01a0,
0x0fc00000640b09a0, 0x0fc08001c40b69a0, 0x0fc28000540d29a0, 0x0fc30001440d79a0,
// Entry 2C0 - 2DF
0x0fc48000f40eb9a0, 0x0fc58000140fa9a0, 0x0fc8000aa40fb9a0, 0x0fd30000741a59a0,
0x0fd380006c1ac9a0, 0x0fd400004c1b31a0, 0x0fd48001741b79a0, 0x0fd5f8003c1ce9a0,
0x0fd67000741d21a0, 0x0fd700004c1d91a0, 0x0fd780004c1dd9a0, 0x0fd800049c1e21a0,
0x0fdca001bc22b9a0, 0x0fdf8000542471a0, 0x100005370000db70, 0x15380081d001b370,
0x15ba0006f0028b70, 0x15c100b410036370, 0x167580e988043b70, 0x17c00010f424c1a0,
0x1800009a58051370, 0x189a80830005eb70, 0x700008000c35b1a0, 0x700100030435b9a0,
0x700800078438b9a0, 0x780007fff0093ad0, 0x800007fff009ead0,
} // Size: 5872 bytes
var index = []uint16{ // 34824 elements
// Entry 0 - 3F
0x0000, 0x0005, 0x0015, 0x0023, 0x002e, 0x0039, 0x0045, 0x004e,
0x0058, 0x0068, 0x0079, 0x0081, 0x008a, 0x008f, 0x009b, 0x00a4,
0x00ab, 0x00b5, 0x00be, 0x00c7, 0x00d2, 0x00dc, 0x00e6, 0x00ef,
0x00fa, 0x0105, 0x010f, 0x0114, 0x011d, 0x012b, 0x0136, 0x0147,
0x0154, 0x0161, 0x0177, 0x018d, 0x01a3, 0x01b9, 0x01cf, 0x01e5,
0x01fb, 0x0211, 0x0227, 0x023d, 0x0253, 0x0269, 0x027f, 0x0295,
0x02ab, 0x02c1, 0x02d7, 0x02ed, 0x0303, 0x0319, 0x032f, 0x0345,
0x035b, 0x0371, 0x0387, 0x039d, 0x03b0, 0x03bf, 0x03d3, 0x03e4,
// Entry 40 - 7F
0x03ec, 0x03f8, 0x040c, 0x0420, 0x0434, 0x0448, 0x045c, 0x0470,
0x0484, 0x0498, 0x04ac, 0x04c0, 0x04d4, 0x04e8, 0x04fc, 0x0510,
0x0524, 0x0538, 0x054c, 0x0560, 0x0574, 0x0588, 0x059c, 0x05b0,
0x05c4, 0x05d8, 0x05ec, 0x0600, 0x0612, 0x061f, 0x0632, 0x0637,
0x0645, 0x065e, 0x0667, 0x0671, 0x067e, 0x0686, 0x0690, 0x069c,
0x06a5, 0x06b3, 0x06cd, 0x06f6, 0x06fe, 0x0709, 0x0718, 0x071e,
0x0729, 0x0738, 0x0747, 0x0758, 0x0764, 0x076e, 0x077a, 0x0784,
0x078b, 0x079a, 0x07b5, 0x07df, 0x07fa, 0x0812, 0x0830, 0x0846,
// Entry 80 - BF
0x0867, 0x0888, 0x08ae, 0x08cf, 0x08f4, 0x091a, 0x0931, 0x0954,
0x0975, 0x0996, 0x09bc, 0x09e1, 0x0a02, 0x0a23, 0x0a49, 0x0a6e,
0x0a86, 0x0aa7, 0x0ac8, 0x0ae9, 0x0b0f, 0x0b30, 0x0b55, 0x0b68,
0x0b8a, 0x0bab, 0x0bcc, 0x0bf2, 0x0c17, 0x0c38, 0x0c52, 0x0c6c,
0x0c8b, 0x0caa, 0x0cce, 0x0ced, 0x0d10, 0x0d34, 0x0d49, 0x0d6a,
0x0d89, 0x0da8, 0x0dcc, 0x0def, 0x0e0e, 0x0e2d, 0x0e51, 0x0e74,
0x0e8a, 0x0ea9, 0x0ec8, 0x0ee7, 0x0f0b, 0x0f2a, 0x0f4d, 0x0f5a,
0x0f7a, 0x0f99, 0x0fb8, 0x0fdc, 0x0fff, 0x101e, 0x1036, 0x1059,
// Entry C0 - FF
0x107b, 0x109b, 0x10bc, 0x10db, 0x10fd, 0x111d, 0x113e, 0x115d,
0x1183, 0x11a7, 0x11cc, 0x11ef, 0x1210, 0x122f, 0x1250, 0x126f,
0x1291, 0x12b1, 0x12d3, 0x12f3, 0x1314, 0x1333, 0x1358, 0x137b,
0x139d, 0x13bd, 0x13de, 0x13fd, 0x1423, 0x1447, 0x1468, 0x1487,
0x14ac, 0x14cf, 0x14f2, 0x1513, 0x1539, 0x155d, 0x157f, 0x159f,
0x15c0, 0x15df, 0x1601, 0x1621, 0x1642, 0x1661, 0x1683, 0x16a3,
0x16c8, 0x16e4, 0x16fd, 0x1714, 0x173a, 0x175e, 0x1781, 0x17a2,
0x17b8, 0x17d9, 0x17f8, 0x181b, 0x183c, 0x185d, 0x187c, 0x18a2,
// Entry 100 - 13F
0x18c6, 0x18e8, 0x1908, 0x1929, 0x1948, 0x196b, 0x198c, 0x19ad,
0x19cc, 0x19f7, 0x1a0f, 0x1a25, 0x1a47, 0x1a67, 0x1a88, 0x1aa7,
0x1acf, 0x1af5, 0x1b0e, 0x1b25, 0x1b46, 0x1b65, 0x1b88, 0x1ba9,
0x1bca, 0x1be9, 0x1c0a, 0x1c29, 0x1c4f, 0x1c73, 0x1c96, 0x1cb7,
0x1cd8, 0x1cf7, 0x1d1a, 0x1d3b, 0x1d5c, 0x1d7b, 0x1d9d, 0x1dbd,
0x1dde, 0x1dfd, 0x1e1f, 0x1e3f, 0x1e60, 0x1e7f, 0x1ea5, 0x1ec9,
0x1ef1, 0x1f17, 0x1f39, 0x1f59, 0x1f7f, 0x1fa3, 0x1fc9, 0x1fed,
0x2012, 0x2033, 0x2052, 0x2077, 0x209a, 0x20bb, 0x20da, 0x20f3,
// Entry 140 - 17F
0x2113, 0x2133, 0x2155, 0x2175, 0x2192, 0x21ad, 0x21c8, 0x21e8,
0x2206, 0x2224, 0x2244, 0x2266, 0x2286, 0x22a5, 0x22c4, 0x22de,
0x22f9, 0x2319, 0x2337, 0x2357, 0x2371, 0x2386, 0x239f, 0x23c1,
0x23e1, 0x23ff, 0x241c, 0x2441, 0x245e, 0x2483, 0x24ab, 0x24d3,
0x24f3, 0x2511, 0x2528, 0x253d, 0x255d, 0x257b, 0x258a, 0x25a7,
0x25c2, 0x25da, 0x25f8, 0x261e, 0x263e, 0x265c, 0x2686, 0x26a6,
0x26c4, 0x26e0, 0x2700, 0x2720, 0x273e, 0x2760, 0x2780, 0x2798,
0x27b9, 0x27d8, 0x27f8, 0x2814, 0x2832, 0x284e, 0x287c, 0x288d,
// Entry 180 - 1BF
0x28a6, 0x28c0, 0x28db, 0x28f7, 0x2919, 0x294e, 0x296e, 0x2985,
0x29af, 0x29c4, 0x29db, 0x2a05, 0x2a1a, 0x2a3b, 0x2a5a, 0x2a7b,
0x2a9a, 0x2abb, 0x2ada, 0x2afb, 0x2b1a, 0x2b4a, 0x2b78, 0x2ba7,
0x2bd4, 0x2c03, 0x2c30, 0x2c5f, 0x2c8c, 0x2ca7, 0x2cd7, 0x2d05,
0x2d35, 0x2d63, 0x2d86, 0x2da7, 0x2dc9, 0x2de9, 0x2e0a, 0x2e29,
0x2e4a, 0x2e69, 0x2e8b, 0x2eab, 0x2ed8, 0x2f03, 0x2f26, 0x2f47,
0x2f66, 0x2f7d, 0x2fa7, 0x2fbc, 0x2fdd, 0x2ffc, 0x3016, 0x302f,
0x3050, 0x306f, 0x309f, 0x30cd, 0x30ef, 0x310f, 0x313b, 0x3165,
// Entry 1C0 - 1FF
0x318d, 0x31b3, 0x31dd, 0x3205, 0x322d, 0x3253, 0x327d, 0x32a5,
0x32cd, 0x32f3, 0x331d, 0x3345, 0x336d, 0x3393, 0x33bd, 0x33e5,
0x340d, 0x3433, 0x345d, 0x3485, 0x34ad, 0x34d3, 0x34fd, 0x3525,
0x354c, 0x3571, 0x3598, 0x35bd, 0x35d6, 0x35ed, 0x360e, 0x362d,
0x3657, 0x3675, 0x368c, 0x36a1, 0x36c1, 0x36df, 0x3704, 0x3727,
0x374a, 0x376b, 0x379b, 0x37c9, 0x37f5, 0x381f, 0x3844, 0x3867,
0x3897, 0x38c5, 0x38e7, 0x3907, 0x3925, 0x3943, 0x3961, 0x397d,
0x399a, 0x39b7, 0x39d9, 0x39fb, 0x3a1b, 0x3a3a, 0x3a65, 0x3a89,
// Entry 200 - 23F
0x3aad, 0x3ace, 0x3aed, 0x3b0f, 0x3b29, 0x3b46, 0x3b68, 0x3b88,
0x3baa, 0x3bca, 0x3bf5, 0x3c18, 0x3c3a, 0x3c5a, 0x3c7c, 0x3c9c,
0x3cb7, 0x3ccf, 0x3cee, 0x3d0c, 0x3d25, 0x3d43, 0x3d61, 0x3d7f,
0x3d9c, 0x3db4, 0x3dd6, 0x3def, 0x3e11, 0x3e3d, 0x3e66, 0x3e8e,
0x3eac, 0x3ec7, 0x3ee3, 0x3efb, 0x3f17, 0x3f32, 0x3f50, 0x3f71,
0x3f91, 0x3fa8, 0x3fc4, 0x3fea, 0x4008, 0x4030, 0x4047, 0x4062,
0x408b, 0x40a9, 0x40cc, 0x40f4, 0x4110, 0x412b, 0x4148, 0x4167,
0x417d, 0x4198, 0x41c1, 0x41e6, 0x4208, 0x4226, 0x4248, 0x4273,
// Entry 240 - 27F
0x428f, 0x42b4, 0x42d2, 0x42e8, 0x4319, 0x433e, 0x435e, 0x4379,
0x43a1, 0x43b9, 0x43d3, 0x43f1, 0x440c, 0x4427, 0x4442, 0x445e,
0x4486, 0x44a4, 0x44ba, 0x44da, 0x44f3, 0x451b, 0x453d, 0x4555,
0x4570, 0x458c, 0x45ac, 0x45d2, 0x45ee, 0x4614, 0x462f, 0x464b,
0x4669, 0x468e, 0x46bc, 0x46d9, 0x46f8, 0x471f, 0x473c, 0x475b,
0x4782, 0x47a1, 0x47be, 0x47db, 0x47fb, 0x481b, 0x4844, 0x4876,
0x488d, 0x48ae, 0x48c5, 0x48dc, 0x48fa, 0x4922, 0x494a, 0x4961,
0x4978, 0x498d, 0x49a9, 0x49c5, 0x49df, 0x49fd, 0x4a1c, 0x4a3a,
// Entry 280 - 2BF
0x4a56, 0x4a7b, 0x4a99, 0x4ab8, 0x4ad4, 0x4af2, 0x4b13, 0x4b18,
0x4b35, 0x4b4b, 0x4b67, 0x4b83, 0x4ba4, 0x4bbe, 0x4bde, 0x4bfe,
0x4c1e, 0x4c43, 0x4c6a, 0x4c90, 0x4ca7, 0x4cc0, 0x4cd9, 0x4cf3,
0x4cf8, 0x4d01, 0x4d0b, 0x4d11, 0x4d1c, 0x4d2f, 0x4d4a, 0x4d66,
0x4d81, 0x4d98, 0x4daf, 0x4dc6, 0x4df1, 0x4e14, 0x4e31, 0x4e4d,
0x4e69, 0x4e8b, 0x4eb2, 0x4eda, 0x4ef1, 0x4f0c, 0x4f2d, 0x4f4f,
0x4f6f, 0x4f91, 0x4fb4, 0x4fcc, 0x4fef, 0x5019, 0x5043, 0x505c,
0x5078, 0x5097, 0x50b4, 0x50d2, 0x50ee, 0x5103, 0x511d, 0x513b,
// Entry 2C0 - 2FF
0x5151, 0x5167, 0x5182, 0x5191, 0x51a1, 0x51b3, 0x51c2, 0x51d5,
0x51e8, 0x51fc, 0x5210, 0x522d, 0x523c, 0x5259, 0x527d, 0x529a,
0x52af, 0x52c7, 0x52e3, 0x52f8, 0x5316, 0x5331, 0x534d, 0x5369,
0x5382, 0x539c, 0x53b6, 0x53c4, 0x53e2, 0x53f9, 0x5412, 0x542b,
0x5445, 0x5465, 0x5483, 0x5496, 0x54af, 0x54c3, 0x54d8, 0x54e9,
0x54f9, 0x5516, 0x552c, 0x5550, 0x5565, 0x5586, 0x559b, 0x55b9,
0x55ce, 0x55e4, 0x55f6, 0x560f, 0x5626, 0x5644, 0x5661, 0x5680,
0x569e, 0x56bd, 0x56dc, 0x56f2, 0x5709, 0x571a, 0x5732, 0x574b,
// Entry 300 - 33F
0x5764, 0x577d, 0x5798, 0x57af, 0x57ce, 0x57eb, 0x5801, 0x581c,
0x5840, 0x585a, 0x5873, 0x588d, 0x58ac, 0x58cc, 0x58e9, 0x5902,
0x5921, 0x593f, 0x5950, 0x5961, 0x597f, 0x599e, 0x59ce, 0x59ed,
0x5a06, 0x5a1e, 0x5a39, 0x5a4f, 0x5a6b, 0x5a81, 0x5a98, 0x5ab5,
0x5acb, 0x5aea, 0x5b11, 0x5b2f, 0x5b4d, 0x5b6b, 0x5b89, 0x5ba7,
0x5bc5, 0x5be3, 0x5c01, 0x5c1f, 0x5c3d, 0x5c5b, 0x5c79, 0x5c97,
0x5cb0, 0x5cc7, 0x5ce9, 0x5d09, 0x5d1b, 0x5d33, 0x5d5a, 0x5d7f,
0x5d92, 0x5dba, 0x5de0, 0x5e0f, 0x5e22, 0x5e3a, 0x5e45, 0x5e5a,
// Entry 340 - 37F
0x5e7f, 0x5e8f, 0x5eb6, 0x5ed9, 0x5efd, 0x5f24, 0x5f4b, 0x5f70,
0x5fa0, 0x5fba, 0x5fd3, 0x5fed, 0x6007, 0x6023, 0x603c, 0x6054,
0x606e, 0x6087, 0x60a1, 0x60bb, 0x60d2, 0x60e9, 0x6100, 0x611c,
0x6133, 0x614b, 0x6165, 0x617d, 0x6199, 0x61b1, 0x61c9, 0x61e1,
0x61fb, 0x6223, 0x624e, 0x6271, 0x6296, 0x62b7, 0x62d9, 0x630c,
0x6324, 0x633b, 0x6353, 0x636b, 0x6385, 0x639c, 0x63b2, 0x63ca,
0x63e1, 0x63f9, 0x6411, 0x6426, 0x643b, 0x6450, 0x646a, 0x647f,
0x6495, 0x64b3, 0x64cb, 0x64e1, 0x64fb, 0x6511, 0x6527, 0x653d,
// Entry 380 - 3BF
0x6555, 0x657b, 0x65a4, 0x65c9, 0x65ee, 0x6611, 0x6629, 0x663a,
0x664c, 0x666a, 0x6692, 0x66be, 0x66ce, 0x66dd, 0x66ed, 0x6707,
0x6727, 0x673a, 0x6753, 0x6767, 0x6781, 0x6793, 0x67ab, 0x67bd,
0x67d5, 0x67ef, 0x6807, 0x6820, 0x6837, 0x6851, 0x6869, 0x6883,
0x689b, 0x68b7, 0x68d1, 0x68ec, 0x6905, 0x691e, 0x6935, 0x6947,
0x6957, 0x6970, 0x6980, 0x699a, 0x69b5, 0x69d9, 0x69f1, 0x6a07,
0x6a28, 0x6a40, 0x6a56, 0x6a72, 0x6a9c, 0x6ac4, 0x6af5, 0x6b1a,
0x6b34, 0x6b4f, 0x6b6a, 0x6b8e, 0x6ba9, 0x6bd9, 0x6bf3, 0x6c0d,
// Entry 3C0 - 3FF
0x6c28, 0x6c43, 0x6c5f, 0x6c7a, 0x6c9e, 0x6cbd, 0x6cd9, 0x6cf2,
0x6d0c, 0x6d26, 0x6d41, 0x6d5b, 0x6d75, 0x6d90, 0x6daa, 0x6dc3,
0x6de2, 0x6dfc, 0x6e16, 0x6e30, 0x6e4a, 0x6e63, 0x6e7d, 0x6e97,
0x6eb1, 0x6ecb, 0x6ee4, 0x6efe, 0x6f18, 0x6f33, 0x6f4e, 0x6f69,
0x6f86, 0x6fa7, 0x6fc3, 0x6fe4, 0x6ffd, 0x7017, 0x7031, 0x7048,
0x7060, 0x7078, 0x7091, 0x70a9, 0x70c1, 0x70da, 0x70f2, 0x7109,
0x7126, 0x713e, 0x7156, 0x716e, 0x7186, 0x719d, 0x71b5, 0x71cd,
0x71e5, 0x71fd, 0x7214, 0x722c, 0x7244, 0x725d, 0x7276, 0x728f,
// Entry 400 - 43F
0x72aa, 0x72c9, 0x72e3, 0x7302, 0x7319, 0x7331, 0x7349, 0x736c,
0x7384, 0x739d, 0x73b6, 0x73d8, 0x73f1, 0x741f, 0x7437, 0x744f,
0x7468, 0x7481, 0x749b, 0x74b4, 0x74d6, 0x74f3, 0x750d, 0x752a,
0x7545, 0x7560, 0x7579, 0x759b, 0x75bb, 0x75dd, 0x75fd, 0x7628,
0x7651, 0x7670, 0x768d, 0x76b5, 0x76db, 0x76f6, 0x770f, 0x772a,
0x7743, 0x775f, 0x7779, 0x7798, 0x77b5, 0x77ed, 0x7823, 0x783d,
0x7855, 0x7878, 0x7899, 0x78c1, 0x78e7, 0x7901, 0x7919, 0x7936,
0x7951, 0x7968, 0x7980, 0x79a1, 0x79c2, 0x79e3, 0x79fe, 0x7a27,
// Entry 440 - 47F
0x7a47, 0x7a70, 0x7a97, 0x7abc, 0x7adf, 0x7b03, 0x7b25, 0x7b4c,
0x7b71, 0x7b98, 0x7bbd, 0x7be9, 0x7c13, 0x7c3d, 0x7c65, 0x7c8e,
0x7cb5, 0x7cde, 0x7d05, 0x7d34, 0x7d61, 0x7d87, 0x7dab, 0x7dcd,
0x7ded, 0x7e16, 0x7e3d, 0x7e5d, 0x7e7b, 0x7ea6, 0x7ecf, 0x7ef3,
0x7f15, 0x7f3e, 0x7f65, 0x7f8e, 0x7fb5, 0x7fd7, 0x7ff7, 0x8025,
0x8051, 0x807a, 0x80a1, 0x80c1, 0x80df, 0x8109, 0x8131, 0x8161,
0x818f, 0x81ab, 0x81c5, 0x81ea, 0x820d, 0x8241, 0x8273, 0x828b,
0x82b1, 0x82d5, 0x82f9, 0x831b, 0x833f, 0x8361, 0x8385, 0x83a7,
// Entry 480 - 4BF
0x83cb, 0x83ed, 0x8413, 0x8437, 0x845b, 0x847d, 0x849b, 0x84bf,
0x84e1, 0x8509, 0x852f, 0x854d, 0x8569, 0x858e, 0x85b1, 0x85ce,
0x85e9, 0x8615, 0x863f, 0x8669, 0x8691, 0x86ba, 0x86e1, 0x8706,
0x8729, 0x874e, 0x8771, 0x8799, 0x87bf, 0x87e7, 0x880d, 0x882d,
0x884b, 0x887a, 0x88a7, 0x88cf, 0x88f5, 0x891a, 0x893d, 0x8965,
0x898b, 0x89b6, 0x89df, 0x8a09, 0x8a31, 0x8a5b, 0x8a83, 0x8aae,
0x8ad7, 0x8b07, 0x8b35, 0x8b59, 0x8b7b, 0x8ba1, 0x8bc5, 0x8be4,
0x8c01, 0x8c21, 0x8c3f, 0x8c5f, 0x8c7d, 0x8c9e, 0x8cbd, 0x8cdd,
// Entry 4C0 - 4FF
0x8cfb, 0x8d1b, 0x8d39, 0x8d59, 0x8d77, 0x8d97, 0x8db5, 0x8dd8,
0x8df9, 0x8e1d, 0x8e3f, 0x8e5a, 0x8e73, 0x8e8e, 0x8ea7, 0x8ec2,
0x8edb, 0x8ef5, 0x8f0d, 0x8f27, 0x8f3f, 0x8f5f, 0x8f7d, 0x8fa8,
0x8fd1, 0x8ffc, 0x9025, 0x904e, 0x9075, 0x90a0, 0x90c9, 0x90f2,
0x9119, 0x9136, 0x9151, 0x916d, 0x9187, 0x91b0, 0x91d7, 0x91f2,
0x920d, 0x9228, 0x9242, 0x925d, 0x9277, 0x9291, 0x92ab, 0x92c5,
0x92e0, 0x92fb, 0x9317, 0x9332, 0x934c, 0x9367, 0x9381, 0x939b,
0x93b7, 0x93d3, 0x93ee, 0x9408, 0x9423, 0x943e, 0x9458, 0x9473,
// Entry 500 - 53F
0x948e, 0x94aa, 0x94c4, 0x94df, 0x94fa, 0x9516, 0x9531, 0x954b,
0x9567, 0x9583, 0x959e, 0x95b8, 0x95d3, 0x95fa, 0x960d, 0x9623,
0x963c, 0x964a, 0x9660, 0x967a, 0x969a, 0x96b3, 0x96cc, 0x96e5,
0x96fd, 0x9716, 0x972e, 0x9746, 0x975e, 0x9776, 0x978f, 0x97a8,
0x97c2, 0x97db, 0x97f3, 0x980c, 0x9824, 0x983c, 0x9856, 0x9870,
0x9889, 0x98a1, 0x98ba, 0x98d3, 0x98eb, 0x9904, 0x991d, 0x9937,
0x994f, 0x9968, 0x9981, 0x999b, 0x99b4, 0x99cc, 0x99e6, 0x9a00,
0x9a19, 0x9a31, 0x9a4a, 0x9a6a, 0x9a8e, 0x9aa0, 0x9aaf, 0x9ad2,
// Entry 540 - 57F
0x9af4, 0x9b06, 0x9b1b, 0x9b2e, 0x9b46, 0x9b5f, 0x9b78, 0x9b8c,
0x9b9f, 0x9bb2, 0x9bc6, 0x9bd9, 0x9bec, 0x9c00, 0x9c1b, 0x9c32,
0x9c4b, 0x9c67, 0x9c7a, 0x9c94, 0x9ca7, 0x9cbd, 0x9cd1, 0x9cec,
0x9cff, 0x9d12, 0x9d2e, 0x9d4a, 0x9d5b, 0x9d6d, 0x9d7f, 0x9d92,
0x9dab, 0x9dbd, 0x9dd5, 0x9ded, 0x9e06, 0x9e18, 0x9e2a, 0x9e3c,
0x9e4e, 0x9e61, 0x9e73, 0x9e93, 0x9ea6, 0x9ec2, 0x9ed4, 0x9eec,
0x9efd, 0x9f15, 0x9f2a, 0x9f3e, 0x9f5a, 0x9f6f, 0x9f84, 0x9fa2,
0x9fbb, 0x9fcd, 0x9fde, 0x9ff1, 0xa004, 0xa014, 0xa025, 0xa038,
// Entry 580 - 5BF
0xa049, 0xa05a, 0xa06b, 0xa082, 0xa093, 0xa0a6, 0xa0bd, 0xa0ce,
0xa0e5, 0xa0f6, 0xa10a, 0xa11c, 0xa132, 0xa142, 0xa15b, 0xa16e,
0xa17f, 0xa191, 0xa1a3, 0xa1b4, 0xa1c7, 0xa1e9, 0xa208, 0xa22a,
0xa243, 0xa25f, 0xa271, 0xa282, 0xa298, 0xa2a9, 0xa2bb, 0xa2d3,
0xa2e9, 0xa301, 0xa30b, 0xa326, 0xa348, 0xa354, 0xa360, 0xa375,
0xa38d, 0xa39e, 0xa3c6, 0xa3e1, 0xa3ff, 0xa41c, 0xa431, 0xa446,
0xa477, 0xa48d, 0xa49f, 0xa4b1, 0xa4c3, 0xa4d3, 0xa4e5, 0xa4fc,
0xa51e, 0xa532, 0xa54c, 0xa55f, 0xa582, 0xa5a5, 0xa5c7, 0xa5ea,
// Entry 5C0 - 5FF
0xa60c, 0xa61e, 0xa62f, 0xa648, 0xa659, 0xa66b, 0xa67d, 0xa68e,
0xa6a0, 0xa6b1, 0xa6c3, 0xa6d4, 0xa6e6, 0xa6f8, 0xa70b, 0xa71c,
0xa72d, 0xa73e, 0xa74f, 0xa760, 0xa773, 0xa79a, 0xa7c3, 0xa7ea,
0xa815, 0xa842, 0xa850, 0xa861, 0xa872, 0xa883, 0xa894, 0xa8a6,
0xa8b8, 0xa8c9, 0xa8da, 0xa8f4, 0xa905, 0xa914, 0xa923, 0xa932,
0xa93e, 0xa94a, 0xa956, 0xa963, 0xa96f, 0xa982, 0xa994, 0xa9a6,
0xa9bb, 0xa9d0, 0xa9e7, 0xa9f6, 0xaa15, 0xaa3d, 0xaa58, 0xaa6d,
0xaa87, 0xaa9e, 0xaab5, 0xaacb, 0xaae1, 0xaaf9, 0xab10, 0xab27,
// Entry 600 - 63F
0xab3d, 0xab55, 0xab6d, 0xab84, 0xab97, 0xabaf, 0xabc9, 0xabe1,
0xabfa, 0xac13, 0xac31, 0xac49, 0xac71, 0xac99, 0xacb1, 0xacce,
0xacea, 0xad0a, 0xad26, 0xad38, 0xad4c, 0xad5e, 0xad79, 0xadaa,
0xadbb, 0xadce, 0xade1, 0xae03, 0xae31, 0xae43, 0xae55, 0xae7c,
0xae8f, 0xaea4, 0xaeb6, 0xaed1, 0xaef1, 0xaf1f, 0xaf32, 0xaf46,
0xaf57, 0xaf88, 0xafae, 0xafc0, 0xafde, 0xaff9, 0xb019, 0xb03d,
0xb06b, 0xb090, 0xb0a1, 0xb0c7, 0xb0f6, 0xb11e, 0xb15b, 0xb180,
0xb1a7, 0xb1ce, 0xb1f5, 0xb20e, 0xb234, 0xb254, 0xb265, 0xb28c,
// Entry 640 - 67F
0xb29f, 0xb2bf, 0xb2e6, 0xb2f9, 0xb310, 0xb32b, 0xb34b, 0xb35b,
0xb382, 0xb393, 0xb3ae, 0xb3c1, 0xb3e6, 0xb3f8, 0xb41f, 0xb43d,
0xb45d, 0xb484, 0xb4ab, 0xb4cc, 0xb4e5, 0xb4f8, 0xb514, 0xb53c,
0xb559, 0xb57b, 0xb59b, 0xb5b1, 0xb5d8, 0xb5f6, 0xb611, 0xb629,
0xb639, 0xb648, 0xb658, 0xb670, 0xb695, 0xb6a5, 0xb6bc, 0xb6d7,
0xb6f5, 0xb715, 0xb724, 0xb74b, 0xb763, 0xb78c, 0xb79c, 0xb7ac,
0xb7e5, 0xb81e, 0xb841, 0xb85b, 0xb871, 0xb88d, 0xb8a3, 0xb8b5,
0xb8d0, 0xb8ee, 0xb918, 0xb93e, 0xb962, 0xb977, 0xb98e, 0xb99e,
// Entry 680 - 6BF
0xb9ae, 0xb9c3, 0xb9d9, 0xb9ef, 0xba0b, 0xba28, 0xba53, 0xba68,
0xba89, 0xbaaa, 0xbaca, 0xbae9, 0xbb08, 0xbb29, 0xbb49, 0xbb69,
0xbb88, 0xbba9, 0xbbca, 0xbbea, 0xbc0c, 0xbc2c, 0xbc4e, 0xbc6a,
0xbc8d, 0xbcae, 0xbcc5, 0xbce1, 0xbcfb, 0xbd13, 0xbd29, 0xbd40,
0xbd58, 0xbd71, 0xbd95, 0xbdb8, 0xbdca, 0xbde0, 0xbdf9, 0xbe13,
0xbe2b, 0xbe3e, 0xbe5d, 0xbe6f, 0xbe82, 0xbe9e, 0xbeb2, 0xbed3,
0xbee3, 0xbef4, 0xbf06, 0xbf18, 0xbf2a, 0xbf45, 0xbf57, 0xbf6c,
0xbf7e, 0xbf92, 0xbfa3, 0xbfb4, 0xbfc9, 0xbfe4, 0xbff3, 0xc003,
// Entry 6C0 - 6FF
0xc01c, 0xc02f, 0xc041, 0xc053, 0xc065, 0xc076, 0xc091, 0xc0ad,
0xc0ca, 0xc0dd, 0xc0f0, 0xc104, 0xc117, 0xc12a, 0xc13e, 0xc150,
0xc162, 0xc180, 0xc19b, 0xc1ad, 0xc1bf, 0xc1d8, 0xc1ea, 0xc1fc,
0xc208, 0xc21b, 0xc22b, 0xc23a, 0xc258, 0xc276, 0xc28d, 0xc2a4,
0xc2bd, 0xc2d6, 0xc2e2, 0xc2f0, 0xc30b, 0xc326, 0xc33e, 0xc372,
0xc3a7, 0xc3df, 0xc42a, 0xc45d, 0xc48a, 0xc4a8, 0xc4cd, 0xc505,
0xc543, 0xc570, 0xc58d, 0xc5b4, 0xc5d9, 0xc613, 0xc643, 0xc668,
0xc6a0, 0xc6c2, 0xc6eb, 0xc725, 0xc746, 0xc767, 0xc78d, 0xc7ae,
// Entry 700 - 73F
0xc7cd, 0xc7e7, 0xc817, 0xc839, 0xc86a, 0xc89e, 0xc8d9, 0xc915,
0xc950, 0xc984, 0xc9c1, 0xca00, 0xca42, 0xca86, 0xcac9, 0xcb05,
0xcb43, 0xcb86, 0xcbcb, 0xcc08, 0xcc46, 0xcc68, 0xcc8d, 0xcc9e,
0xccb5, 0xccc8, 0xccd9, 0xccea, 0xcd01, 0xcd14, 0xcd27, 0xcd3a,
0xcd4d, 0xcd60, 0xcd74, 0xcd86, 0xcd99, 0xcdac, 0xcdc3, 0xcdd6,
0xcdec, 0xce02, 0xce18, 0xce29, 0xce3f, 0xce55, 0xce6c, 0xce7e,
0xce90, 0xcea2, 0xceb6, 0xcec7, 0xcedb, 0xceef, 0xcf03, 0xcf13,
0xcf23, 0xcf35, 0xcf49, 0xcf5c, 0xcf6f, 0xcf7d, 0xcf8d, 0xcf9b,
// Entry 740 - 77F
0xcfab, 0xcfb9, 0xcfc9, 0xcfd7, 0xcfe7, 0xcff5, 0xd005, 0xd011,
0xd022, 0xd030, 0xd03d, 0xd04a, 0xd059, 0xd067, 0xd075, 0xd082,
0xd091, 0xd0a0, 0xd0ae, 0xd0ba, 0xd0c7, 0xd0d3, 0xd0df, 0xd0eb,
0xd0f8, 0xd104, 0xd119, 0xd125, 0xd132, 0xd13f, 0xd14c, 0xd159,
0xd167, 0xd174, 0xd181, 0xd18f, 0xd19c, 0xd1aa, 0xd1b7, 0xd1c4,
0xd1d1, 0xd1e5, 0xd1f2, 0xd200, 0xd20d, 0xd21a, 0xd227, 0xd234,
0xd249, 0xd25b, 0xd26e, 0xd280, 0xd29d, 0xd2b9, 0xd2d8, 0xd2fa,
0xd316, 0xd331, 0xd34f, 0xd36e, 0xd38c, 0xd3a4, 0xd3bb, 0xd3cf,
// Entry 780 - 7BF
0xd3e4, 0xd3ed, 0xd401, 0xd40f, 0xd41d, 0xd42c, 0xd43a, 0xd44f,
0xd463, 0xd479, 0xd48f, 0xd4a2, 0xd4b6, 0xd4ca, 0xd4dd, 0xd4f1,
0xd505, 0xd51a, 0xd530, 0xd544, 0xd558, 0xd570, 0xd583, 0xd596,
0xd5ae, 0xd5c2, 0xd5d7, 0xd5ec, 0xd601, 0xd612, 0xd628, 0xd640,
0xd655, 0xd67d, 0xd69a, 0xd6b5, 0xd6cb, 0xd6eb, 0xd707, 0xd71e,
0xd73d, 0xd758, 0xd76e, 0xd78f, 0xd7ab, 0xd7c6, 0xd7dc, 0xd7f7,
0xd812, 0xd828, 0xd83e, 0xd858, 0xd86e, 0xd88b, 0xd8a7, 0xd8c2,
0xd8db, 0xd8f7, 0xd917, 0xd932, 0xd955, 0xd970, 0xd98b, 0xd9a5,
// Entry 7C0 - 7FF
0xd9bf, 0xd9dc, 0xd9fe, 0xda1a, 0xda2e, 0xda3f, 0xda50, 0xda61,
0xda72, 0xda88, 0xda99, 0xdaaa, 0xdabc, 0xdacf, 0xdae0, 0xdaf1,
0xdb02, 0xdb13, 0xdb24, 0xdb35, 0xdb46, 0xdb58, 0xdb69, 0xdb7a,
0xdb8c, 0xdb9d, 0xdbb4, 0xdbc6, 0xdbd8, 0xdbf0, 0xdc09, 0xdc20,
0xdc33, 0xdc4e, 0xdc68, 0xdc83, 0xdc9e, 0xdcb9, 0xdcd5, 0xdcf0,
0xdd0a, 0xdd25, 0xdd41, 0xdd5c, 0xdd82, 0xddb2, 0xdddd, 0xde07,
0xde2d, 0xde60, 0xde90, 0xdec0, 0xdeef, 0xdf1f, 0xdf40, 0xdf7e,
0xdfb7, 0xdff8, 0xe036, 0xe06f, 0xe0b0, 0xe0dc, 0xe107, 0xe12b,
// Entry 800 - 83F
0xe14d, 0xe16f, 0xe185, 0xe19e, 0xe1b5, 0xe1dd, 0xe20a, 0xe22a,
0xe251, 0xe283, 0xe297, 0xe2ae, 0xe2c7, 0xe2e4, 0xe301, 0xe31d,
0xe33a, 0xe34d, 0xe36e, 0xe382, 0xe39e, 0xe3c2, 0xe3e4, 0xe40a,
0xe42f, 0xe464, 0xe484, 0xe4a5, 0xe4cd, 0xe502, 0xe535, 0xe550,
0xe571, 0xe58b, 0xe5a1, 0xe5c8, 0xe5ef, 0xe615, 0xe62f, 0xe657,
0xe67e, 0xe69e, 0xe6d0, 0xe6f7, 0xe71e, 0xe744, 0xe76b, 0xe7a5,
0xe7be, 0xe7d7, 0xe7f1, 0xe80f, 0xe82d, 0xe84c, 0xe86c, 0xe88c,
0xe8b5, 0xe8e4, 0xe90c, 0xe934, 0xe968, 0xe97a, 0xe990, 0xe9ab,
// Entry 840 - 87F
0xe9db, 0xe9f5, 0xea0a, 0xea26, 0xea42, 0xea54, 0xea6d, 0xea97,
0xeaab, 0xeac8, 0xeadd, 0xeaf2, 0xeb07, 0xeb28, 0xeb48, 0xeb6b,
0xeb8a, 0xeba8, 0xebc4, 0xebde, 0xebfa, 0xec1b, 0xec37, 0xec52,
0xec6b, 0xec7d, 0xec8f, 0xeca1, 0xecb6, 0xeccb, 0xece0, 0xecf9,
0xed13, 0xed29, 0xed42, 0xed5c, 0xed72, 0xed86, 0xed9a, 0xedae,
0xedc3, 0xedd9, 0xedf4, 0xee0f, 0xee2a, 0xee46, 0xee61, 0xee7d,
0xeea0, 0xeecc, 0xeef1, 0xef06, 0xef26, 0xef4a, 0xef65, 0xef7d,
0xef94, 0xefad, 0xefc0, 0xefd4, 0xefe7, 0xeffb, 0xf00e, 0xf022,
// Entry 880 - 8BF
0xf03d, 0xf058, 0xf072, 0xf08b, 0xf09e, 0xf0b2, 0xf0cc, 0xf0e5,
0xf0f8, 0xf10c, 0xf120, 0xf135, 0xf149, 0xf15e, 0xf173, 0xf187,
0xf19c, 0xf1b0, 0xf1c5, 0xf1da, 0xf1ef, 0xf205, 0xf21a, 0xf230,
0xf245, 0xf259, 0xf26e, 0xf282, 0xf297, 0xf2ab, 0xf2c1, 0xf2d5,
0xf2ea, 0xf2fe, 0xf313, 0xf327, 0xf33b, 0xf34f, 0xf364, 0xf378,
0xf38d, 0xf3a3, 0xf3b7, 0xf3cc, 0xf3e1, 0xf3f5, 0xf409, 0xf421,
0xf43a, 0xf44f, 0xf467, 0xf47f, 0xf496, 0xf4ae, 0xf4c5, 0xf4dd,
0xf4fc, 0xf51c, 0xf53a, 0xf557, 0xf56e, 0xf586, 0xf5a4, 0xf5c1,
// Entry 8C0 - 8FF
0xf5d8, 0xf5f0, 0xf606, 0xf62b, 0xf643, 0xf650, 0xf66d, 0xf68c,
0xf6a3, 0xf6ba, 0xf6dd, 0xf6f5, 0xf70e, 0xf722, 0xf738, 0xf74e,
0xf762, 0xf779, 0xf78e, 0xf7a2, 0xf7b7, 0xf7d3, 0xf7ef, 0xf80e,
0xf82e, 0xf83e, 0xf855, 0xf86a, 0xf87e, 0xf892, 0xf8a8, 0xf8bd,
0xf8d2, 0xf8e6, 0xf8fc, 0xf912, 0xf927, 0xf943, 0xf963, 0xf97d,
0xf991, 0xf9a6, 0xf9ba, 0xf9ce, 0xf9e3, 0xfa00, 0xfa15, 0xfa2f,
0xfa44, 0xfa59, 0xfa77, 0xfa8d, 0xfaa2, 0xfaae, 0xfac6, 0xfadb,
0xfaef, 0xfaff, 0xfb10, 0xfb20, 0xfb31, 0xfb41, 0xfb52, 0xfb6a,
// Entry 900 - 93F
0xfb82, 0xfb92, 0xfba3, 0xfbb3, 0xfbc4, 0xfbd5, 0xfbe7, 0xfbf8,
0xfc0a, 0xfc1c, 0xfc2d, 0xfc3f, 0xfc50, 0xfc62, 0xfc74, 0xfc86,
0xfc99, 0xfcab, 0xfcbe, 0xfcd0, 0xfce1, 0xfcf3, 0xfd04, 0xfd16,
0xfd27, 0xfd38, 0xfd4a, 0xfd5b, 0xfd6d, 0xfd7e, 0xfd8f, 0xfda0,
0xfdb1, 0xfdc3, 0xfdd5, 0xfde6, 0xfdf7, 0xfe09, 0xfe1e, 0xfe33,
0xfe47, 0xfe5c, 0xfe70, 0xfe85, 0xfea1, 0xfebe, 0xfed2, 0xfee7,
0xfefb, 0xff10, 0xff23, 0xff3b, 0xff51, 0xff63, 0xff75, 0xff87,
0xffa0, 0xffb9, 0xffd5, 0xfff2, 0x0004, 0x0015, 0x0026, 0x0039,
// Entry 940 - 97F
0x004b, 0x005d, 0x006e, 0x0081, 0x0094, 0x00a6, 0x00cc, 0x00f1,
0x0103, 0x0115, 0x0133, 0x0151, 0x0171, 0x0190, 0x01c8, 0x01ec,
0x01fa, 0x020c, 0x0229, 0x0242, 0x0255, 0x026d, 0x0280, 0x0295,
0x02a6, 0x02b8, 0x02c9, 0x02db, 0x02ec, 0x02fe, 0x0310, 0x0322,
0x0334, 0x0346, 0x0358, 0x036b, 0x037d, 0x0390, 0x03a3, 0x03b5,
0x03c8, 0x03da, 0x03ed, 0x0400, 0x0413, 0x0427, 0x043a, 0x044e,
0x0461, 0x0473, 0x0486, 0x0498, 0x04ab, 0x04bd, 0x04cf, 0x04e2,
0x04f4, 0x0507, 0x0519, 0x052b, 0x053d, 0x054f, 0x0562, 0x0574,
// Entry 980 - 9BF
0x0587, 0x0599, 0x05ab, 0x05be, 0x05d4, 0x05e9, 0x05ff, 0x0614,
0x062a, 0x0640, 0x0656, 0x066c, 0x0682, 0x0696, 0x06a9, 0x06bd,
0x06d1, 0x06e3, 0x06f6, 0x0708, 0x071b, 0x072d, 0x073f, 0x0753,
0x0766, 0x0779, 0x078b, 0x079f, 0x07b3, 0x07c6, 0x07d4, 0x07e2,
0x07ee, 0x07fa, 0x080b, 0x081f, 0x0839, 0x0852, 0x0868, 0x087d,
0x088e, 0x08a0, 0x08b1, 0x08c3, 0x08d4, 0x08e6, 0x08ff, 0x0918,
0x092f, 0x0940, 0x0952, 0x0969, 0x097a, 0x098c, 0x099e, 0x09b1,
0x09c3, 0x09d6, 0x09e9, 0x09fb, 0x0a0e, 0x0a20, 0x0a33, 0x0a46,
// Entry 9C0 - 9FF
0x0a59, 0x0a6d, 0x0a80, 0x0a94, 0x0aa7, 0x0ab9, 0x0acc, 0x0ade,
0x0af1, 0x0b03, 0x0b15, 0x0b28, 0x0b3a, 0x0b4d, 0x0b5f, 0x0b71,
0x0b83, 0x0b95, 0x0ba8, 0x0bba, 0x0bcd, 0x0be0, 0x0bf2, 0x0c04,
0x0c17, 0x0c2d, 0x0c43, 0x0c58, 0x0c6e, 0x0c83, 0x0c99, 0x0cb6,
0x0cd4, 0x0cf0, 0x0d05, 0x0d1b, 0x0d37, 0x0d4c, 0x0d62, 0x0d76,
0x0d81, 0x0d9b, 0x0db5, 0x0dd2, 0x0df0, 0x0e03, 0x0e15, 0x0e27,
0x0e3b, 0x0e4e, 0x0e61, 0x0e73, 0x0e87, 0x0e9b, 0x0eae, 0x0ec8,
0x0edb, 0x0eee, 0x0f01, 0x0f15, 0x0f29, 0x0f4c, 0x0f6c, 0x0f90,
// Entry A00 - A3F
0x0fa6, 0x0fb9, 0x0fcb, 0x0fd9, 0x0fe8, 0x0ff6, 0x1005, 0x1013,
0x1022, 0x1038, 0x104e, 0x105c, 0x106b, 0x1079, 0x1088, 0x1097,
0x10a7, 0x10b6, 0x10c6, 0x10d6, 0x10e5, 0x10f5, 0x1104, 0x1114,
0x1124, 0x1134, 0x1145, 0x1155, 0x1166, 0x1176, 0x1185, 0x1195,
0x11a4, 0x11b4, 0x11c3, 0x11d2, 0x11e2, 0x11f1, 0x1201, 0x1210,
0x121f, 0x122e, 0x123d, 0x124d, 0x125c, 0x126c, 0x127c, 0x128b,
0x129a, 0x12aa, 0x12bd, 0x12d0, 0x12e2, 0x12f5, 0x1307, 0x131a,
0x1334, 0x134f, 0x1361, 0x1374, 0x1386, 0x1399, 0x13aa, 0x13bd,
// Entry A40 - A7F
0x13d1, 0x13e5, 0x13f5, 0x1405, 0x1415, 0x142c, 0x1443, 0x145d,
0x1478, 0x1488, 0x1497, 0x14a6, 0x14b7, 0x14c7, 0x14d7, 0x14e6,
0x14f7, 0x1508, 0x1518, 0x1524, 0x1533, 0x154d, 0x1564, 0x1581,
0x159d, 0x15b6, 0x15d5, 0x15e8, 0x15fa, 0x1608, 0x1617, 0x1625,
0x1634, 0x1642, 0x1651, 0x165f, 0x166e, 0x167d, 0x168b, 0x169a,
0x16a9, 0x16b8, 0x16c8, 0x16d7, 0x16e6, 0x16f6, 0x1706, 0x1716,
0x1725, 0x1734, 0x1745, 0x1754, 0x1763, 0x1772, 0x1781, 0x1791,
0x17a0, 0x17b0, 0x17c1, 0x17d0, 0x17e0, 0x17f0, 0x17ff, 0x180e,
// Entry A80 - ABF
0x1821, 0x1833, 0x1846, 0x1858, 0x186b, 0x187d, 0x1890, 0x18a3,
0x18b5, 0x18c8, 0x18db, 0x18ec, 0x18f4, 0x1908, 0x1918, 0x1927,
0x1936, 0x1947, 0x1957, 0x1967, 0x1976, 0x1987, 0x1998, 0x19a8,
0x19b8, 0x19d0, 0x19e9, 0x19f7, 0x1a07, 0x1a16, 0x1a26, 0x1a37,
0x1a4a, 0x1a5a, 0x1a6b, 0x1a92, 0x1aa9, 0x1abd, 0x1ad0, 0x1af4,
0x1b03, 0x1b13, 0x1b22, 0x1b32, 0x1b41, 0x1b51, 0x1b68, 0x1b7f,
0x1b8e, 0x1b9e, 0x1bae, 0x1bbd, 0x1bcd, 0x1bdd, 0x1bed, 0x1bfe,
0x1c0e, 0x1c1f, 0x1c30, 0x1c40, 0x1c51, 0x1c61, 0x1c72, 0x1c83,
// Entry AC0 - AFF
0x1c94, 0x1ca6, 0x1cb7, 0x1cc9, 0x1cda, 0x1cea, 0x1cfb, 0x1d0b,
0x1d1c, 0x1d2c, 0x1d3c, 0x1d4d, 0x1d5d, 0x1d6e, 0x1d7e, 0x1d8e,
0x1d9e, 0x1daf, 0x1dbf, 0x1dd0, 0x1de2, 0x1df2, 0x1e03, 0x1e14,
0x1e24, 0x1e34, 0x1e45, 0x1e59, 0x1e6d, 0x1e80, 0x1e94, 0x1ea7,
0x1ebb, 0x1ed6, 0x1ef2, 0x1f05, 0x1f19, 0x1f2d, 0x1f40, 0x1f54,
0x1f68, 0x1f7a, 0x1f8c, 0x1fa1, 0x1fb2, 0x1fc3, 0x1fd5, 0x1ff0,
0x2008, 0x2020, 0x203b, 0x2057, 0x2068, 0x2078, 0x2088, 0x209a,
0x20ab, 0x20bc, 0x20cc, 0x20de, 0x20f0, 0x2101, 0x2114, 0x2145,
// Entry B00 - B3F
0x2175, 0x21a5, 0x21d7, 0x2208, 0x2239, 0x226c, 0x227d, 0x229d,
0x22b5, 0x22ca, 0x22de, 0x22f2, 0x2302, 0x2313, 0x2323, 0x2334,
0x2344, 0x2355, 0x236d, 0x2385, 0x2395, 0x23a6, 0x23b7, 0x23c7,
0x23d8, 0x23e9, 0x23fa, 0x240c, 0x241d, 0x242f, 0x2441, 0x2452,
0x2464, 0x2475, 0x2487, 0x2499, 0x24ab, 0x24be, 0x24d0, 0x24e3,
0x24f5, 0x2506, 0x2518, 0x2529, 0x253b, 0x254c, 0x255d, 0x256f,
0x2580, 0x2592, 0x25a3, 0x25b4, 0x25c5, 0x25d7, 0x25e8, 0x25fa,
0x260b, 0x261d, 0x262f, 0x2640, 0x2651, 0x2663, 0x2678, 0x268d,
// Entry B40 - B7F
0x26a1, 0x26b6, 0x26ca, 0x26df, 0x26fb, 0x2718, 0x272c, 0x2741,
0x2756, 0x276a, 0x277f, 0x2794, 0x27a7, 0x27ba, 0x27d0, 0x27ec,
0x27fd, 0x2816, 0x282f, 0x284b, 0x2868, 0x287a, 0x288b, 0x289c,
0x28af, 0x28c1, 0x28d3, 0x28e4, 0x28f7, 0x290a, 0x291c, 0x2934,
0x294c, 0x2977, 0x299e, 0x29b8, 0x29cf, 0x29e5, 0x2a04, 0x2a16,
0x2a29, 0x2a3b, 0x2a4e, 0x2a60, 0x2a73, 0x2a8d, 0x2aa7, 0x2ab9,
0x2acc, 0x2adf, 0x2af1, 0x2b04, 0x2b17, 0x2b2a, 0x2b3e, 0x2b51,
0x2b65, 0x2b79, 0x2b8c, 0x2ba0, 0x2bb3, 0x2bc7, 0x2bdb, 0x2bef,
// Entry B80 - BBF
0x2c04, 0x2c18, 0x2c2d, 0x2c41, 0x2c54, 0x2c68, 0x2c7b, 0x2c8f,
0x2ca2, 0x2cb7, 0x2cca, 0x2cde, 0x2cf1, 0x2d05, 0x2d18, 0x2d2b,
0x2d3e, 0x2d52, 0x2d65, 0x2d79, 0x2d8e, 0x2da1, 0x2db5, 0x2dc9,
0x2ddc, 0x2def, 0x2e04, 0x2e26, 0x2e44, 0x2e5b, 0x2e72, 0x2e88,
0x2e9f, 0x2eb5, 0x2ecc, 0x2eea, 0x2f09, 0x2f1f, 0x2f36, 0x2f4d,
0x2f63, 0x2f7a, 0x2f91, 0x2fa6, 0x2fbf, 0x2fd2, 0x2feb, 0x3004,
0x301f, 0x3037, 0x3066, 0x3085, 0x30a8, 0x30c8, 0x30e4, 0x3107,
0x3123, 0x313e, 0x3159, 0x3174, 0x3192, 0x31b1, 0x31c5, 0x31d8,
// Entry BC0 - BFF
0x31eb, 0x3200, 0x3214, 0x3228, 0x323b, 0x3250, 0x3265, 0x3279,
0x328d, 0x32a9, 0x32c6, 0x32e4, 0x32ff, 0x3320, 0x3340, 0x335d,
0x3380, 0x3393, 0x33ad, 0x33c6, 0x33e0, 0x33f9, 0x3413, 0x342c,
0x3444, 0x345b, 0x3471, 0x3486, 0x349c, 0x34b2, 0x34c9, 0x34de,
0x34f4, 0x3509, 0x351f, 0x3536, 0x354e, 0x3565, 0x357d, 0x3592,
0x35a8, 0x35be, 0x35d3, 0x35e9, 0x35ff, 0x3620, 0x3642, 0x3663,
0x3685, 0x36a6, 0x36c4, 0x36e5, 0x3707, 0x3728, 0x374a, 0x376b,
0x3796, 0x37b4, 0x37d6, 0x37f9, 0x381b, 0x383e, 0x385e, 0x387d,
// Entry C00 - C3F
0x389e, 0x38c0, 0x38e1, 0x3903, 0x3921, 0x393f, 0x3960, 0x3982,
0x39a3, 0x39c5, 0x39db, 0x39f6, 0x3a0c, 0x3a22, 0x3a40, 0x3a56,
0x3a74, 0x3a94, 0x3ab2, 0x3ac8, 0x3ae8, 0x3afe, 0x3b14, 0x3b31,
0x3b54, 0x3b76, 0x3b97, 0x3bb7, 0x3bd9, 0x3bfa, 0x3c19, 0x3c33,
0x3c52, 0x3c6f, 0x3c98, 0x3cc6, 0x3cf0, 0x3d0e, 0x3d25, 0x3d3b,
0x3d51, 0x3d69, 0x3d80, 0x3d97, 0x3dad, 0x3dc5, 0x3ddd, 0x3df4,
0x3e18, 0x3e3b, 0x3e59, 0x3e6e, 0x3e85, 0x3e9d, 0x3eb5, 0x3ecc,
0x3ee6, 0x3efc, 0x3f13, 0x3f2b, 0x3f43, 0x3f57, 0x3f6e, 0x3f84,
// Entry C40 - C7F
0x3f9b, 0x3fb2, 0x3fc9, 0x3fe6, 0x4000, 0x4015, 0x402a, 0x403f,
0x4057, 0x4070, 0x4088, 0x409c, 0x40b4, 0x40c9, 0x40e1, 0x40f5,
0x410c, 0x4121, 0x413b, 0x414f, 0x4164, 0x4179, 0x418a, 0x41a0,
0x41b1, 0x41c7, 0x41dd, 0x41f3, 0x4208, 0x421d, 0x4234, 0x4248,
0x4260, 0x4278, 0x428d, 0x42a8, 0x42be, 0x42d4, 0x42e9, 0x42ff,
0x4315, 0x432c, 0x4341, 0x4357, 0x436d, 0x4386, 0x439b, 0x43b1,
0x43c6, 0x43e4, 0x4403, 0x441d, 0x4434, 0x444c, 0x4461, 0x4477,
0x448d, 0x44a8, 0x44c2, 0x44d9, 0x44f0, 0x4506, 0x4515, 0x4523,
// Entry C80 - CBF
0x4531, 0x4541, 0x4550, 0x455f, 0x456d, 0x457d, 0x458d, 0x459c,
0x45b5, 0x45ca, 0x45d7, 0x45ea, 0x45fc, 0x460f, 0x461d, 0x462a,
0x463d, 0x464e, 0x4661, 0x466f, 0x4682, 0x4695, 0x46a9, 0x46bc,
0x46d0, 0x46e3, 0x46f0, 0x46fd, 0x4710, 0x4722, 0x4735, 0x4742,
0x474f, 0x475c, 0x476f, 0x4780, 0x4792, 0x47a4, 0x47b7, 0x47c4,
0x47d1, 0x47e3, 0x47f5, 0x4802, 0x4819, 0x4830, 0x4842, 0x4854,
0x4867, 0x4873, 0x4884, 0x4890, 0x48a0, 0x48b6, 0x48c7, 0x48d8,
0x48e8, 0x48f9, 0x4909, 0x491a, 0x492a, 0x493b, 0x494f, 0x4965,
// Entry CC0 - CFF
0x497a, 0x4990, 0x49a0, 0x49b1, 0x49c1, 0x49d2, 0x49e3, 0x49ec,
0x49fb, 0x4a0b, 0x4a1a, 0x4a2d, 0x4a42, 0x4a4f, 0x4a5b, 0x4a69,
0x4a76, 0x4a83, 0x4a92, 0x4aa0, 0x4aae, 0x4abb, 0x4aca, 0x4ad9,
0x4ae7, 0x4af0, 0x4af9, 0x4b0b, 0x4b1e, 0x4b31, 0x4b56, 0x4b80,
0x4bab, 0x4bcf, 0x4bf3, 0x4c1a, 0x4c3c, 0x4c53, 0x4c6d, 0x4c8b,
0x4cab, 0x4ccd, 0x4cde, 0x4cf4, 0x4d0b, 0x4d27, 0x4d48, 0x4d63,
0x4d8d, 0x4da4, 0x4dc4, 0x4de4, 0x4e13, 0x4e36, 0x4e5c, 0x4e77,
0x4e93, 0x4eae, 0x4ec8, 0x4ee3, 0x4f02, 0x4f14, 0x4f25, 0x4f36,
// Entry D00 - D3F
0x4f49, 0x4f5b, 0x4f6d, 0x4f7e, 0x4f91, 0x4fa4, 0x4fb6, 0x4fcc,
0x4fe2, 0x4ffa, 0x5011, 0x5028, 0x503e, 0x5056, 0x506e, 0x5085,
0x509c, 0x50b4, 0x50d3, 0x50fe, 0x5120, 0x5134, 0x514a, 0x5165,
0x5180, 0x519b, 0x51b6, 0x51cc, 0x51e2, 0x51f3, 0x5205, 0x5216,
0x5228, 0x523a, 0x524b, 0x525d, 0x526e, 0x5280, 0x5292, 0x52a5,
0x52b7, 0x52ca, 0x52dc, 0x52ed, 0x52ff, 0x5310, 0x5322, 0x5333,
0x5344, 0x5356, 0x5367, 0x5379, 0x538a, 0x539c, 0x53af, 0x53c1,
0x53d4, 0x53e5, 0x53f7, 0x5408, 0x5419, 0x542a, 0x543b, 0x544c,
// Entry D40 - D7F
0x545e, 0x5470, 0x5481, 0x5492, 0x54a2, 0x54b5, 0x54d1, 0x54e3,
0x54f5, 0x550a, 0x551e, 0x5533, 0x5547, 0x555c, 0x5578, 0x5595,
0x55b1, 0x55ce, 0x55e2, 0x55f7, 0x560b, 0x5620, 0x563b, 0x5651,
0x566e, 0x568c, 0x56a7, 0x56bc, 0x56d0, 0x56e3, 0x56f9, 0x5710,
0x5728, 0x573d, 0x5759, 0x5775, 0x5793, 0x57b5, 0x57d4, 0x57fc,
0x5817, 0x5833, 0x584e, 0x586a, 0x5886, 0x58a1, 0x58bd, 0x58d8,
0x58f4, 0x5910, 0x592d, 0x5949, 0x5966, 0x5982, 0x599d, 0x59b9,
0x59d4, 0x59f0, 0x5a0b, 0x5a26, 0x5a42, 0x5a5d, 0x5a79, 0x5a94,
// Entry D80 - DBF
0x5ab0, 0x5acd, 0x5ae9, 0x5b06, 0x5b21, 0x5b3d, 0x5b58, 0x5b73,
0x5b8e, 0x5ba9, 0x5bc4, 0x5be0, 0x5bfc, 0x5c17, 0x5c32, 0x5c4c,
0x5c69, 0x5c8f, 0x5cb5, 0x5cdb, 0x5cec, 0x5d0a, 0x5d2e, 0x5d52,
0x5d75, 0x5d99, 0x5daf, 0x5dc5, 0x5dde, 0x5dfe, 0x5e14, 0x5e29,
0x5e4a, 0x5e6b, 0x5e8c, 0x5eab, 0x5ec5, 0x5ee9, 0x5f0c, 0x5f23,
0x5f53, 0x5f83, 0x5f9b, 0x5fb2, 0x5fd4, 0x5ff5, 0x6015, 0x6036,
0x6047, 0x6059, 0x606a, 0x607c, 0x608e, 0x609f, 0x60b1, 0x60c2,
0x60d4, 0x60e6, 0x60f9, 0x610b, 0x611e, 0x6130, 0x6143, 0x6155,
// Entry DC0 - DFF
0x6166, 0x6178, 0x6189, 0x619b, 0x61ac, 0x61bd, 0x61cf, 0x61e0,
0x61f2, 0x6203, 0x6214, 0x6225, 0x6236, 0x6247, 0x6258, 0x6269,
0x627b, 0x628b, 0x62a0, 0x62b0, 0x62c1, 0x62d1, 0x62e2, 0x62f2,
0x6306, 0x6316, 0x6327, 0x6341, 0x6356, 0x636a, 0x637f, 0x6393,
0x63a8, 0x63bc, 0x63d1, 0x63ea, 0x6402, 0x641c, 0x6431, 0x6447,
0x645b, 0x646e, 0x647f, 0x649f, 0x64bf, 0x64df, 0x64ff, 0x6516,
0x6528, 0x6539, 0x654a, 0x655d, 0x656f, 0x6581, 0x6592, 0x65a5,
0x65b8, 0x65ca, 0x65e5, 0x65f9, 0x6610, 0x6628, 0x6645, 0x665c,
// Entry E00 - E3F
0x666e, 0x6680, 0x6698, 0x66b1, 0x66c9, 0x66e2, 0x66fe, 0x671b,
0x6737, 0x6754, 0x676a, 0x6780, 0x6796, 0x67ac, 0x67d0, 0x67f4,
0x6818, 0x6835, 0x6855, 0x6877, 0x689a, 0x68be, 0x68e2, 0x6909,
0x6930, 0x6955, 0x697a, 0x699f, 0x69c4, 0x69e9, 0x6a0d, 0x6a31,
0x6a56, 0x6a75, 0x6a90, 0x6aaa, 0x6ac5, 0x6adb, 0x6af2, 0x6b08,
0x6b1e, 0x6b34, 0x6b4b, 0x6b61, 0x6b77, 0x6b8e, 0x6ba4, 0x6bba,
0x6bd1, 0x6be7, 0x6c0c, 0x6c26, 0x6c3f, 0x6c5e, 0x6c7d, 0x6c95,
0x6cad, 0x6cc5, 0x6cdd, 0x6cfd, 0x6d1d, 0x6d44, 0x6d63, 0x6d84,
// Entry E40 - E7F
0x6d9b, 0x6db1, 0x6dc7, 0x6ddf, 0x6df6, 0x6e0d, 0x6e23, 0x6e3b,
0x6e53, 0x6e6a, 0x6e84, 0x6e9e, 0x6eb8, 0x6ed3, 0x6eea, 0x6f09,
0x6f23, 0x6f3e, 0x6f59, 0x6f74, 0x6f8e, 0x6fa9, 0x6fc4, 0x6fdf,
0x6ff9, 0x7014, 0x702f, 0x704a, 0x7065, 0x707f, 0x709a, 0x70b6,
0x70d1, 0x70ec, 0x7107, 0x7121, 0x713d, 0x7159, 0x7175, 0x7190,
0x71ac, 0x71c8, 0x71e3, 0x71fe, 0x7219, 0x7235, 0x7250, 0x726c,
0x7287, 0x72a1, 0x72bc, 0x72d6, 0x72f1, 0x730c, 0x7326, 0x7341,
0x7353, 0x7366, 0x7379, 0x738c, 0x739e, 0x73b1, 0x73c4, 0x73d7,
// Entry E80 - EBF
0x73e9, 0x73fc, 0x740f, 0x7422, 0x7435, 0x7447, 0x745a, 0x746e,
0x7481, 0x7494, 0x74a7, 0x74b9, 0x74cd, 0x74e1, 0x74f5, 0x7508,
0x751c, 0x7530, 0x7543, 0x7556, 0x7569, 0x757d, 0x7590, 0x75a4,
0x75b7, 0x75c9, 0x75dc, 0x75ee, 0x7601, 0x7614, 0x7626, 0x7638,
0x764d, 0x7667, 0x767a, 0x7696, 0x76b2, 0x76c5, 0x76de, 0x76f9,
0x770f, 0x772a, 0x773f, 0x7755, 0x7770, 0x7785, 0x779a, 0x77af,
0x77c9, 0x77dd, 0x77f6, 0x780b, 0x7820, 0x783a, 0x7851, 0x7868,
0x787f, 0x7896, 0x78ab, 0x78c7, 0x78e1, 0x78fd, 0x7918, 0x7935,
// Entry EC0 - EFF
0x7950, 0x796a, 0x7985, 0x79a2, 0x79bd, 0x79da, 0x79f6, 0x7a11,
0x7a2d, 0x7a47, 0x7a68, 0x7a89, 0x7aa9, 0x7ac8, 0x7ae8, 0x7b03,
0x7b20, 0x7b3d, 0x7b5a, 0x7b77, 0x7b99, 0x7bb4, 0x7bce, 0x7be9,
0x7c03, 0x7c1d, 0x7c37, 0x7c58, 0x7c76, 0x7c90, 0x7caa, 0x7cc6,
0x7ce2, 0x7cfe, 0x7d1a, 0x7d34, 0x7d50, 0x7d71, 0x7d90, 0x7db4,
0x7dcb, 0x7de7, 0x7e03, 0x7e1e, 0x7e39, 0x7e53, 0x7e70, 0x7e8a,
0x7ea5, 0x7ec2, 0x7edf, 0x7efc, 0x7f14, 0x7f2f, 0x7f4c, 0x7f6e,
0x7f8e, 0x7fb3, 0x7fd2, 0x7fef, 0x800e, 0x8030, 0x804d, 0x806c,
// Entry F00 - F3F
0x8086, 0x80a1, 0x80be, 0x80d8, 0x80f3, 0x810e, 0x812a, 0x8140,
0x8157, 0x8169, 0x817c, 0x818f, 0x81a3, 0x81b6, 0x81c8, 0x81dc,
0x81ef, 0x8201, 0x8214, 0x8228, 0x823b, 0x824e, 0x8260, 0x8274,
0x8287, 0x829a, 0x82ad, 0x82c0, 0x82d3, 0x82e5, 0x82f9, 0x830d,
0x8322, 0x8338, 0x834d, 0x8362, 0x8378, 0x838e, 0x83a4, 0x83b9,
0x83cd, 0x83e2, 0x83f6, 0x840a, 0x8420, 0x8437, 0x844e, 0x8463,
0x8478, 0x848c, 0x84a1, 0x84b9, 0x84ce, 0x84e2, 0x84f7, 0x850d,
0x8522, 0x8539, 0x854f, 0x8564, 0x8579, 0x858e, 0x85a4, 0x85b9,
// Entry F40 - F7F
0x85cd, 0x85e2, 0x85f6, 0x860a, 0x861f, 0x8637, 0x864d, 0x8666,
0x867e, 0x8696, 0x86b1, 0x86c6, 0x86db, 0x86f2, 0x8707, 0x871d,
0x8734, 0x8750, 0x876c, 0x8782, 0x879e, 0x87ba, 0x87d1, 0x87e7,
0x8804, 0x8820, 0x883c, 0x8857, 0x8875, 0x8893, 0x88af, 0x88c5,
0x88db, 0x88f6, 0x890b, 0x8925, 0x893b, 0x8951, 0x8969, 0x8981,
0x8999, 0x89b1, 0x89c7, 0x89e4, 0x8a07, 0x8a24, 0x8a41, 0x8a5c,
0x8a7a, 0x8a98, 0x8ab6, 0x8ad3, 0x8af5, 0x8b11, 0x8b2e, 0x8b51,
0x8b6c, 0x8b8f, 0x8bb0, 0x8bd1, 0x8bf3, 0x8c17, 0x8c37, 0x8c55,
// Entry F80 - FBF
0x8c73, 0x8c95, 0x8cb2, 0x8cce, 0x8cea, 0x8d05, 0x8d25, 0x8d43,
0x8d61, 0x8d7d, 0x8d9b, 0x8db7, 0x8dd5, 0x8df1, 0x8e0f, 0x8e2b,
0x8e47, 0x8e62, 0x8e7d, 0x8e95, 0x8eb2, 0x8ed4, 0x8eef, 0x8f0d,
0x8f26, 0x8f44, 0x8f65, 0x8f83, 0x8fa3, 0x8fbf, 0x8fdb, 0x8ff7,
0x9013, 0x902f, 0x904c, 0x9069, 0x9088, 0x90a7, 0x90c4, 0x90df,
0x90f3, 0x9107, 0x911b, 0x9130, 0x9145, 0x9159, 0x916d, 0x9182,
0x9196, 0x91aa, 0x91be, 0x91d3, 0x91e8, 0x91fc, 0x9210, 0x9225,
0x923a, 0x924f, 0x9264, 0x927a, 0x9290, 0x92a5, 0x92ba, 0x92d0,
// Entry FC0 - FFF
0x92e4, 0x92f8, 0x930c, 0x9321, 0x9336, 0x934a, 0x935e, 0x9373,
0x9388, 0x939d, 0x93b2, 0x93c8, 0x93de, 0x93f3, 0x9408, 0x941e,
0x9432, 0x9446, 0x945a, 0x946f, 0x9484, 0x9498, 0x94ac, 0x94c1,
0x94d5, 0x94e9, 0x94fd, 0x9512, 0x9527, 0x953b, 0x954f, 0x9564,
0x9579, 0x958e, 0x95a3, 0x95b9, 0x95cf, 0x95e4, 0x95f9, 0x960f,
0x9623, 0x9637, 0x964b, 0x9660, 0x9675, 0x9689, 0x969d, 0x96b2,
0x96c7, 0x96dc, 0x96f2, 0x9708, 0x971d, 0x9732, 0x9747, 0x975c,
0x9772, 0x9788, 0x979d, 0x97b2, 0x97c8, 0x97de, 0x97f5, 0x980c,
// Entry 1000 - 103F
0x9822, 0x9836, 0x984a, 0x985e, 0x9873, 0x9888, 0x989c, 0x98b0,
0x98c5, 0x98d9, 0x98ed, 0x9901, 0x9916, 0x992b, 0x993f, 0x9953,
0x9968, 0x997c, 0x9990, 0x99a4, 0x99b9, 0x99ce, 0x99e2, 0x99f6,
0x9a0b, 0x9a1f, 0x9a33, 0x9a47, 0x9a5c, 0x9a71, 0x9a85, 0x9a99,
0x9aae, 0x9ac2, 0x9ad6, 0x9aea, 0x9aff, 0x9b14, 0x9b28, 0x9b3c,
0x9b51, 0x9b66, 0x9b7b, 0x9b91, 0x9ba7, 0x9bbc, 0x9bd0, 0x9be4,
0x9bf8, 0x9c0d, 0x9c22, 0x9c36, 0x9c4a, 0x9c5f, 0x9c74, 0x9c89,
0x9c9e, 0x9cb4, 0x9cca, 0x9cdf, 0x9cf4, 0x9d0a, 0x9d25, 0x9d40,
// Entry 1040 - 107F
0x9d5b, 0x9d77, 0x9d93, 0x9dae, 0x9dc9, 0x9de5, 0x9df9, 0x9e0d,
0x9e21, 0x9e36, 0x9e4b, 0x9e5f, 0x9e73, 0x9e88, 0x9e9d, 0x9eb2,
0x9ec8, 0x9ede, 0x9ef3, 0x9f08, 0x9f1d, 0x9f32, 0x9f48, 0x9f5e,
0x9f73, 0x9f88, 0x9f9e, 0x9fb4, 0x9fcb, 0x9fe2, 0x9ff8, 0xa00c,
0xa020, 0xa034, 0xa049, 0xa05e, 0xa072, 0xa086, 0xa09b, 0xa0b9,
0xa0d7, 0xa0f5, 0xa114, 0xa133, 0xa151, 0xa16f, 0xa183, 0xa197,
0xa1ab, 0xa1c0, 0xa1d5, 0xa1e9, 0xa1fd, 0xa212, 0xa227, 0xa23c,
0xa251, 0xa267, 0xa27d, 0xa292, 0xa2a7, 0xa2bd, 0xa2d1, 0xa2e5,
// Entry 1080 - 10BF
0xa2f9, 0xa30e, 0xa323, 0xa337, 0xa34b, 0xa360, 0xa374, 0xa388,
0xa39c, 0xa3b1, 0xa3c6, 0xa3da, 0xa3ee, 0xa403, 0xa418, 0xa42d,
0xa442, 0xa458, 0xa46e, 0xa483, 0xa498, 0xa4ae, 0xa4c2, 0xa4d6,
0xa4ea, 0xa4ff, 0xa514, 0xa528, 0xa53c, 0xa551, 0xa565, 0xa579,
0xa58d, 0xa5a2, 0xa5b7, 0xa5cb, 0xa5df, 0xa5f4, 0xa609, 0xa61e,
0xa634, 0xa64a, 0xa65f, 0xa674, 0xa689, 0xa69e, 0xa6b4, 0xa6ca,
0xa6df, 0xa6f4, 0xa70b, 0xa720, 0xa735, 0xa74a, 0xa760, 0xa776,
0xa78b, 0xa7a0, 0xa7b6, 0xa7cb, 0xa7e0, 0xa7f5, 0xa80b, 0xa821,
// Entry 10C0 - 10FF
0xa836, 0xa84b, 0xa861, 0xa876, 0xa88b, 0xa8a0, 0xa8b6, 0xa8cc,
0xa8e1, 0xa8f6, 0xa90c, 0xa921, 0xa936, 0xa94b, 0xa961, 0xa977,
0xa98c, 0xa9a1, 0xa9b7, 0xa9cc, 0xa9e1, 0xa9f6, 0xaa0c, 0xaa22,
0xaa37, 0xaa4c, 0xaa62, 0xaa76, 0xaa8a, 0xaa9e, 0xaab3, 0xaac8,
0xaadc, 0xaaf0, 0xab05, 0xab19, 0xab2d, 0xab41, 0xab56, 0xab6b,
0xab7f, 0xab93, 0xaba8, 0xabbd, 0xabd2, 0xabe7, 0xac1a, 0xac3e,
0xac60, 0xac75, 0xac87, 0xac99, 0xaca7, 0xacb9, 0xacc7, 0xacdd,
0xacf3, 0xad0f, 0xad21, 0xad33, 0xad47, 0xad5a, 0xad6d, 0xad7f,
// Entry 1100 - 113F
0xad93, 0xada7, 0xadba, 0xadcd, 0xade3, 0xadf9, 0xae0e, 0xae23,
0xae38, 0xae4f, 0xae65, 0xae7b, 0xae92, 0xaeae, 0xaecd, 0xaee2,
0xaef8, 0xaf0d, 0xaf2c, 0xaf41, 0xaf57, 0xaf6c, 0xaf8b, 0xafa0,
0xafb6, 0xafcb, 0xafea, 0xafff, 0xb015, 0xb02a, 0xb043, 0xb05c,
0xb076, 0xb096, 0xb0af, 0xb0c8, 0xb0e2, 0xb0fb, 0xb11a, 0xb132,
0xb143, 0xb154, 0xb165, 0xb176, 0xb187, 0xb198, 0xb1aa, 0xb1bc,
0xb1ce, 0xb1e0, 0xb1f2, 0xb204, 0xb216, 0xb228, 0xb23a, 0xb24c,
0xb25e, 0xb270, 0xb282, 0xb294, 0xb2a6, 0xb2b8, 0xb2ca, 0xb2dc,
// Entry 1140 - 117F
0xb2ee, 0xb300, 0xb312, 0xb324, 0xb336, 0xb348, 0xb35a, 0xb36d,
0xb380, 0xb392, 0xb3a4, 0xb3b6, 0xb3c8, 0xb3da, 0xb3ed, 0xb400,
0xb413, 0xb426, 0xb439, 0xb44c, 0xb45e, 0xb46f, 0xb481, 0xb493,
0xb4a5, 0xb4b7, 0xb4c9, 0xb4db, 0xb4ed, 0xb4ff, 0xb511, 0xb523,
0xb535, 0xb547, 0xb559, 0xb56b, 0xb57e, 0xb591, 0xb5a4, 0xb5b7,
0xb5ca, 0xb5dd, 0xb5f0, 0xb603, 0xb616, 0xb629, 0xb63c, 0xb64f,
0xb662, 0xb674, 0xb686, 0xb698, 0xb6aa, 0xb6bc, 0xb6ce, 0xb6e0,
0xb6f2, 0xb704, 0xb716, 0xb728, 0xb73a, 0xb74c, 0xb764, 0xb77c,
// Entry 1180 - 11BF
0xb794, 0xb7ac, 0xb7c4, 0xb7dc, 0xb7f5, 0xb809, 0xb81f, 0xb833,
0xb848, 0xb85c, 0xb871, 0xb88d, 0xb8aa, 0xb8c6, 0xb8da, 0xb8ef,
0xb904, 0xb923, 0xb938, 0xb957, 0xb96d, 0xb98d, 0xb9a2, 0xb9c1,
0xb9d7, 0xb9f7, 0xba15, 0xba2a, 0xba49, 0xba5f, 0xba7f, 0xba9d,
0xbab2, 0xbacd, 0xbaec, 0xbb0a, 0xbb28, 0xbb51, 0xbb77, 0xbb9f,
0xbbbc, 0xbbe1, 0xbc17, 0xbc3a, 0xbc6a, 0xbc87, 0xbca9, 0xbcbe,
0xbcd3, 0xbce8, 0xbcfd, 0xbd12, 0xbd29, 0xbd3e, 0xbd54, 0xbd69,
0xbd7f, 0xbd9c, 0xbdba, 0xbdd7, 0xbdec, 0xbe02, 0xbe18, 0xbe38,
// Entry 11C0 - 11FF
0xbe4e, 0xbe6e, 0xbe85, 0xbea6, 0xbebc, 0xbedc, 0xbef3, 0xbf14,
0xbf2a, 0xbf4a, 0xbf61, 0xbf82, 0xbfa0, 0xbfb4, 0xbfd2, 0xbfee,
0xc003, 0xc01a, 0xc02f, 0xc045, 0xc05a, 0xc070, 0xc08d, 0xc0ab,
0xc0c8, 0xc0dd, 0xc0f3, 0xc109, 0xc129, 0xc13f, 0xc15f, 0xc176,
0xc197, 0xc1ad, 0xc1cd, 0xc1e4, 0xc205, 0xc21b, 0xc23b, 0xc252,
0xc273, 0xc292, 0xc2a6, 0xc2bc, 0xc2d2, 0xc2e8, 0xc2fe, 0xc313,
0xc32a, 0xc33f, 0xc355, 0xc36a, 0xc380, 0xc39d, 0xc3b2, 0xc3c8,
0xc3de, 0xc3fe, 0xc414, 0xc434, 0xc44b, 0xc46c, 0xc482, 0xc4a2,
// Entry 1200 - 123F
0xc4b9, 0xc4da, 0xc4f0, 0xc510, 0xc527, 0xc548, 0xc567, 0xc57b,
0xc590, 0xc5b3, 0xc5d6, 0xc5f9, 0xc61c, 0xc631, 0xc648, 0xc65d,
0xc673, 0xc688, 0xc69e, 0xc6bb, 0xc6d0, 0xc6e6, 0xc6fc, 0xc71c,
0xc732, 0xc752, 0xc769, 0xc78a, 0xc7a0, 0xc7c0, 0xc7d7, 0xc7f8,
0xc80e, 0xc82e, 0xc845, 0xc866, 0xc885, 0xc899, 0xc8b5, 0xc8ca,
0xc8e1, 0xc8f6, 0xc90c, 0xc921, 0xc937, 0xc954, 0xc969, 0xc97f,
0xc995, 0xc9b5, 0xc9cb, 0xc9eb, 0xca02, 0xca23, 0xca39, 0xca59,
0xca70, 0xca91, 0xcaa7, 0xcac7, 0xcade, 0xcaff, 0xcb1e, 0xcb32,
// Entry 1240 - 127F
0xcb50, 0xcb65, 0xcb84, 0xcb9f, 0xcbb4, 0xcbcb, 0xcbe0, 0xcbf6,
0xcc0b, 0xcc21, 0xcc3e, 0xcc53, 0xcc69, 0xcc7f, 0xcc9f, 0xccb5,
0xccd5, 0xccec, 0xcd0d, 0xcd2c, 0xcd40, 0xcd5d, 0xcd72, 0xcd87,
0xcd9e, 0xcdb3, 0xcdc9, 0xcdde, 0xcdf4, 0xce11, 0xce26, 0xce3c,
0xce52, 0xce72, 0xce88, 0xcea8, 0xcebf, 0xcee0, 0xcef6, 0xcf16,
0xcf2d, 0xcf4e, 0xcf64, 0xcf84, 0xcf9b, 0xcfbc, 0xcfd0, 0xcfee,
0xd009, 0xd01e, 0xd035, 0xd04a, 0xd060, 0xd075, 0xd08b, 0xd0a8,
0xd0bd, 0xd0d3, 0xd0e9, 0xd109, 0xd11f, 0xd13f, 0xd156, 0xd177,
// Entry 1280 - 12BF
0xd18d, 0xd1ad, 0xd1c4, 0xd1e5, 0xd1fb, 0xd21b, 0xd232, 0xd253,
0xd272, 0xd286, 0xd2a5, 0xd2ba, 0xd2d8, 0xd2f8, 0xd316, 0xd334,
0xd353, 0xd372, 0xd391, 0xd3b0, 0xd3c6, 0xd3dc, 0xd3f3, 0xd409,
0xd420, 0xd436, 0xd44d, 0xd464, 0xd485, 0xd49c, 0xd4bd, 0xd4d5,
0xd4f7, 0xd50e, 0xd52f, 0xd547, 0xd569, 0xd580, 0xd5a1, 0xd5b9,
0xd5db, 0xd5f0, 0xd605, 0xd61c, 0xd631, 0xd647, 0xd65c, 0xd672,
0xd68f, 0xd6a4, 0xd6ba, 0xd6d0, 0xd6f0, 0xd706, 0xd726, 0xd73d,
0xd75e, 0xd774, 0xd794, 0xd7ab, 0xd7cc, 0xd7e2, 0xd802, 0xd819,
// Entry 12C0 - 12FF
0xd83a, 0xd859, 0xd86d, 0xd88c, 0xd8aa, 0xd8c6, 0xd8db, 0xd8f7,
0xd916, 0xd92d, 0xd942, 0xd958, 0xd96d, 0xd983, 0xd9a2, 0xd9b7,
0xd9cd, 0xd9ec, 0xda03, 0xda24, 0xda38, 0xda56, 0xda71, 0xda86,
0xda9d, 0xdab2, 0xdac8, 0xdadd, 0xdaf3, 0xdb08, 0xdb1e, 0xdb35,
0xdb56, 0xdb6a, 0xdb80, 0xdb9d, 0xdbb3, 0xdbd0, 0xdbe7, 0xdc05,
0xdc1b, 0xdc32, 0xdc48, 0xdc5f, 0xdc77, 0xdc99, 0xdcae, 0xdcc5,
0xdcdc, 0xdcf3, 0xdd0a, 0xdd20, 0xdd36, 0xdd4c, 0xdd62, 0xdd78,
0xdd95, 0xddb2, 0xddd0, 0xdded, 0xde0b, 0xde28, 0xde46, 0xde62,
// Entry 1300 - 133F
0xde7e, 0xde93, 0xdeaa, 0xdebf, 0xded5, 0xdeea, 0xdf00, 0xdf15,
0xdf2b, 0xdf3f, 0xdf56, 0xdf6d, 0xdf84, 0xdf9b, 0xdfba, 0xdfd9,
0xdff8, 0xe017, 0xe02f, 0xe045, 0xe05c, 0xe072, 0xe089, 0xe09f,
0xe0b6, 0xe0cb, 0xe0e1, 0xe0fe, 0xe11b, 0xe138, 0xe155, 0xe176,
0xe197, 0xe1b8, 0xe1d9, 0xe1f9, 0xe20f, 0xe226, 0xe23c, 0xe253,
0xe269, 0xe280, 0xe295, 0xe2b3, 0xe2d1, 0xe2f0, 0xe30e, 0xe32d,
0xe34b, 0xe36a, 0xe387, 0xe3a3, 0xe3c1, 0xe3df, 0xe3fd, 0xe41b,
0xe43a, 0xe459, 0xe478, 0xe497, 0xe4b6, 0xe4d5, 0xe4f4, 0xe513,
// Entry 1340 - 137F
0xe532, 0xe551, 0xe570, 0xe58f, 0xe5ab, 0xe5c7, 0xe5e3, 0xe5ff,
0xe61d, 0xe63b, 0xe659, 0xe678, 0xe696, 0xe6b4, 0xe6d1, 0xe6ee,
0xe70b, 0xe729, 0xe746, 0xe763, 0xe780, 0xe79d, 0xe7ba, 0xe7d8,
0xe7f5, 0xe812, 0xe830, 0xe84e, 0xe86c, 0xe88b, 0xe8a9, 0xe8c7,
0xe8e5, 0xe903, 0xe921, 0xe940, 0xe95e, 0xe97c, 0xe99a, 0xe9b8,
0xe9d6, 0xe9f5, 0xea13, 0xea31, 0xea4e, 0xea6b, 0xea88, 0xeaa6,
0xeac3, 0xeae0, 0xeafc, 0xeb19, 0xeb36, 0xeb53, 0xeb71, 0xeb8e,
0xebab, 0xebc9, 0xebe7, 0xec05, 0xec24, 0xec42, 0xec60, 0xec7e,
// Entry 1380 - 13BF
0xec9c, 0xecba, 0xecd9, 0xecf7, 0xed15, 0xed32, 0xed4f, 0xed6c,
0xed89, 0xeda7, 0xedc4, 0xede1, 0xedfe, 0xee1b, 0xee38, 0xee56,
0xee73, 0xee90, 0xeead, 0xeeca, 0xeee7, 0xef05, 0xef22, 0xef3f,
0xef5c, 0xef78, 0xef95, 0xefb2, 0xefd0, 0xefed, 0xf009, 0xf026,
0xf044, 0xf062, 0xf080, 0xf09f, 0xf0bd, 0xf0db, 0xf0f8, 0xf115,
0xf132, 0xf150, 0xf16d, 0xf18a, 0xf1a8, 0xf1c6, 0xf1e4, 0xf203,
0xf221, 0xf23f, 0xf25d, 0xf27b, 0xf299, 0xf2b8, 0xf2d6, 0xf2f4,
0xf313, 0xf332, 0xf351, 0xf371, 0xf390, 0xf3af, 0xf3cd, 0xf3eb,
// Entry 13C0 - 13FF
0xf409, 0xf428, 0xf446, 0xf464, 0xf481, 0xf49e, 0xf4bb, 0xf4d9,
0xf4f6, 0xf513, 0xf52f, 0xf553, 0xf571, 0xf58f, 0xf5ad, 0xf5cc,
0xf5ea, 0xf608, 0xf625, 0xf642, 0xf65f, 0xf67d, 0xf69a, 0xf6b7,
0xf6d5, 0xf6f3, 0xf711, 0xf730, 0xf74e, 0xf76c, 0xf789, 0xf7a7,
0xf7c5, 0xf7e3, 0xf802, 0xf820, 0xf83e, 0xf85c, 0xf87a, 0xf898,
0xf8b7, 0xf8d5, 0xf8f3, 0xf912, 0xf931, 0xf950, 0xf970, 0xf98f,
0xf9ae, 0xf9c9, 0xf9e5, 0xf9fb, 0xfa12, 0xfa29, 0xfa41, 0xfa58,
0xfa70, 0xfa87, 0xfa9f, 0xfac2, 0xfae4, 0xfb07, 0xfb29, 0xfb4c,
// Entry 1400 - 143F
0xfb6e, 0xfb91, 0xfbb7, 0xfbd5, 0xfbe5, 0xfbf7, 0xfc08, 0xfc1a,
0xfc2b, 0xfc3c, 0xfc4d, 0xfc5e, 0xfc70, 0xfc81, 0xfc93, 0xfca4,
0xfcb5, 0xfcc9, 0xfcdc, 0xfced, 0xfcfe, 0xfd0e, 0xfd1d, 0xfd31,
0xfd45, 0xfd59, 0xfd68, 0xfd7d, 0xfd8e, 0xfda6, 0xfdb8, 0xfdca,
0xfde5, 0xfe00, 0xfe0e, 0xfe24, 0xfe33, 0xfe41, 0xfe4f, 0xfe70,
0xfe80, 0xfe94, 0xfea5, 0xfeb6, 0xfec7, 0xfee5, 0xff02, 0xff10,
0xff1f, 0xff2e, 0xff4b, 0xff5d, 0xff6d, 0xff80, 0xff8e, 0xff9e,
0xffb6, 0xffc6, 0xffdf, 0xfff4, 0x0008, 0x0029, 0x0049, 0x0067,
// Entry 1440 - 147F
0x0085, 0x009a, 0x00b4, 0x00c2, 0x00d6, 0x00e6, 0x0104, 0x0120,
0x0135, 0x0151, 0x0169, 0x017e, 0x01a2, 0x01bf, 0x01cd, 0x01db,
0x01f7, 0x0214, 0x0222, 0x0247, 0x0268, 0x027d, 0x0290, 0x02a7,
0x02c0, 0x02df, 0x02fd, 0x031c, 0x0331, 0x0344, 0x0354, 0x036d,
0x0389, 0x0399, 0x03a9, 0x03bd, 0x03ce, 0x03e0, 0x03f1, 0x040c,
0x0426, 0x043f, 0x044d, 0x045b, 0x0473, 0x048d, 0x04a4, 0x04b7,
0x04cc, 0x04e1, 0x04ef, 0x04fe, 0x050d, 0x052a, 0x0547, 0x0564,
0x0581, 0x05a0, 0x05b0, 0x05c0, 0x05d0, 0x05e1, 0x05f2, 0x0604,
// Entry 1480 - 14BF
0x0615, 0x0626, 0x0637, 0x0648, 0x0659, 0x066a, 0x067b, 0x068c,
0x069d, 0x06ae, 0x06bf, 0x06d0, 0x06e4, 0x06f8, 0x070b, 0x0720,
0x0739, 0x0749, 0x0759, 0x0769, 0x077a, 0x078b, 0x079d, 0x07ae,
0x07bf, 0x07d0, 0x07e1, 0x07f2, 0x0803, 0x0814, 0x0825, 0x0836,
0x0847, 0x0858, 0x0869, 0x087d, 0x0891, 0x08a6, 0x08c3, 0x08e0,
0x08ee, 0x08fc, 0x090a, 0x0919, 0x0928, 0x0938, 0x0947, 0x0956,
0x0965, 0x0974, 0x0983, 0x0992, 0x09a1, 0x09b0, 0x09bf, 0x09ce,
0x09dd, 0x09ec, 0x09fe, 0x0a10, 0x0a21, 0x0a32, 0x0a43, 0x0a55,
// Entry 14C0 - 14FF
0x0a67, 0x0a7a, 0x0a8c, 0x0a9e, 0x0ab0, 0x0ac2, 0x0ad4, 0x0ae6,
0x0af8, 0x0b0a, 0x0b1c, 0x0b2e, 0x0b43, 0x0b58, 0x0b67, 0x0b77,
0x0b86, 0x0b96, 0x0ba6, 0x0bb5, 0x0bc5, 0x0bd4, 0x0be4, 0x0bf4,
0x0c03, 0x0c14, 0x0c23, 0x0c34, 0x0c44, 0x0c53, 0x0c63, 0x0c72,
0x0c82, 0x0c91, 0x0ca0, 0x0cb0, 0x0cbf, 0x0ccf, 0x0cde, 0x0ced,
0x0cfc, 0x0d0b, 0x0d1a, 0x0d2a, 0x0d3a, 0x0d49, 0x0d58, 0x0d67,
0x0d76, 0x0d91, 0x0dac, 0x0dc6, 0x0de1, 0x0dfb, 0x0e16, 0x0e31,
0x0e4d, 0x0e67, 0x0e82, 0x0e9c, 0x0eb7, 0x0ed1, 0x0eec, 0x0f10,
// Entry 1500 - 153F
0x0f34, 0x0f4f, 0x0f66, 0x0f7d, 0x0f90, 0x0fa2, 0x0fb5, 0x0fc7,
0x0fda, 0x0fec, 0x0fff, 0x1012, 0x1025, 0x1038, 0x104b, 0x105d,
0x1070, 0x1083, 0x1096, 0x10a9, 0x10bb, 0x10cd, 0x10e5, 0x10fb,
0x110d, 0x111e, 0x112e, 0x1144, 0x1156, 0x1166, 0x117e, 0x118f,
0x119f, 0x11b4, 0x11c3, 0x11d8, 0x11f2, 0x1204, 0x1215, 0x122b,
0x123d, 0x1257, 0x126f, 0x1282, 0x1292, 0x12a1, 0x12b0, 0x12c1,
0x12d1, 0x12e1, 0x12f0, 0x1301, 0x1312, 0x1322, 0x133c, 0x1357,
0x1371, 0x138b, 0x13a6, 0x13c1, 0x13e1, 0x1400, 0x141f, 0x143f,
// Entry 1540 - 157F
0x144e, 0x1460, 0x146f, 0x1482, 0x1491, 0x14a4, 0x14be, 0x14e5,
0x14fb, 0x1515, 0x1525, 0x154a, 0x156f, 0x1596, 0x15af, 0x15d5,
0x15e9, 0x15fc, 0x160f, 0x1624, 0x1638, 0x164c, 0x165f, 0x1674,
0x1689, 0x169d, 0x16af, 0x16c1, 0x16d3, 0x16e5, 0x16f7, 0x170a,
0x171d, 0x1730, 0x1743, 0x1757, 0x176a, 0x177d, 0x1790, 0x17a3,
0x17b6, 0x17c9, 0x17dc, 0x17f0, 0x1803, 0x1816, 0x182a, 0x183d,
0x1850, 0x1863, 0x1876, 0x1889, 0x189c, 0x18b0, 0x18c4, 0x18d7,
0x18eb, 0x18ff, 0x1913, 0x1927, 0x193b, 0x1960, 0x1977, 0x198e,
// Entry 1580 - 15BF
0x19a5, 0x19bc, 0x19d4, 0x19ec, 0x1a05, 0x1a1d, 0x1a35, 0x1a4d,
0x1a65, 0x1a7d, 0x1a95, 0x1aad, 0x1ac6, 0x1ade, 0x1af7, 0x1b0f,
0x1b27, 0x1b3f, 0x1b58, 0x1b71, 0x1b8a, 0x1ba3, 0x1bbc, 0x1bd3,
0x1bea, 0x1c02, 0x1c1a, 0x1c31, 0x1c4a, 0x1c62, 0x1c7a, 0x1c92,
0x1caa, 0x1cc3, 0x1cdb, 0x1cf3, 0x1d0b, 0x1d23, 0x1d3c, 0x1d55,
0x1d6e, 0x1d86, 0x1d9f, 0x1db8, 0x1dd1, 0x1dea, 0x1e04, 0x1e1e,
0x1e38, 0x1e53, 0x1e75, 0x1e9b, 0x1ec0, 0x1ee0, 0x1f01, 0x1f2b,
0x1f4b, 0x1f71, 0x1f8c, 0x1fa7, 0x1fc3, 0x1fe0, 0x1ffc, 0x2019,
// Entry 15C0 - 15FF
0x2037, 0x2054, 0x2071, 0x208d, 0x20a9, 0x20c5, 0x20e2, 0x20ff,
0x211c, 0x2138, 0x2154, 0x2175, 0x2197, 0x21bb, 0x21df, 0x2202,
0x2226, 0x224a, 0x226f, 0x2292, 0x22b6, 0x22da, 0x22fe, 0x2322,
0x2345, 0x2365, 0x2386, 0x23aa, 0x23cb, 0x23ef, 0x2404, 0x2419,
0x242f, 0x2445, 0x245b, 0x2471, 0x2488, 0x249e, 0x24b4, 0x24cb,
0x24e1, 0x24f7, 0x250d, 0x2523, 0x2539, 0x254f, 0x2566, 0x257d,
0x2595, 0x25ab, 0x25c1, 0x25d7, 0x25ed, 0x260b, 0x2622, 0x2641,
0x2657, 0x2675, 0x268c, 0x26ab, 0x26c2, 0x26d8, 0x26ef, 0x2705,
// Entry 1600 - 163F
0x271c, 0x2732, 0x274e, 0x276a, 0x2786, 0x27a2, 0x27be, 0x27da,
0x27f6, 0x2813, 0x282f, 0x284b, 0x286e, 0x2891, 0x28ae, 0x28ce,
0x28ee, 0x2905, 0x291c, 0x2934, 0x294c, 0x2964, 0x297c, 0x2994,
0x29b2, 0x29d0, 0x29ed, 0x2a0b, 0x2a2e, 0x2a4c, 0x2a6a, 0x2a87,
0x2aa5, 0x2ac5, 0x2ae5, 0x2b08, 0x2b22, 0x2b31, 0x2b41, 0x2b50,
0x2b60, 0x2b70, 0x2b7f, 0x2b8f, 0x2b9e, 0x2bae, 0x2bbe, 0x2bcd,
0x2bdd, 0x2bec, 0x2bfc, 0x2c0b, 0x2c1a, 0x2c2a, 0x2c39, 0x2c49,
0x2c58, 0x2c67, 0x2c76, 0x2c85, 0x2c94, 0x2ca4, 0x2cb4, 0x2cc3,
// Entry 1640 - 167F
0x2cd2, 0x2ce3, 0x2cf3, 0x2d05, 0x2d17, 0x2d29, 0x2d3c, 0x2d4f,
0x2d62, 0x2d75, 0x2d87, 0x2d99, 0x2db2, 0x2dcb, 0x2de4, 0x2df9,
0x2e0f, 0x2e2a, 0x2e3f, 0x2e54, 0x2e69, 0x2e7e, 0x2e93, 0x2ea8,
0x2ebc, 0x2ed0, 0x2edf, 0x2eed, 0x2f03, 0x2f16, 0x2f26, 0x2f35,
0x2f44, 0x2f55, 0x2f65, 0x2f75, 0x2f84, 0x2f95, 0x2fa6, 0x2fb6,
0x2fc6, 0x2fd6, 0x2fe7, 0x2ff8, 0x3008, 0x3018, 0x3028, 0x3039,
0x3049, 0x3059, 0x306a, 0x307a, 0x308a, 0x309a, 0x30aa, 0x30ba,
0x30cb, 0x30dd, 0x30ed, 0x30fc, 0x310b, 0x311b, 0x312b, 0x313a,
// Entry 1680 - 16BF
0x314a, 0x3159, 0x3169, 0x3178, 0x3189, 0x3199, 0x31ad, 0x31c1,
0x31d5, 0x31e9, 0x31fd, 0x3217, 0x3230, 0x324a, 0x3264, 0x327f,
0x3298, 0x32b1, 0x32cb, 0x32e6, 0x3300, 0x331a, 0x3334, 0x334d,
0x3366, 0x3380, 0x339b, 0x33b5, 0x33ce, 0x33e8, 0x3401, 0x341b,
0x3436, 0x3450, 0x3469, 0x3483, 0x349c, 0x34b6, 0x34d0, 0x34ea,
0x3503, 0x351c, 0x3535, 0x354f, 0x3569, 0x3583, 0x359c, 0x35b5,
0x35ce, 0x35e9, 0x3604, 0x361e, 0x3638, 0x3653, 0x366d, 0x3693,
0x36ac, 0x36c5, 0x36dd, 0x36f6, 0x370e, 0x3727, 0x373f, 0x3758,
// Entry 16C0 - 16FF
0x3771, 0x378a, 0x37a4, 0x37bd, 0x37d6, 0x37f0, 0x380a, 0x3823,
0x383d, 0x3858, 0x3872, 0x388c, 0x38a6, 0x38c0, 0x38da, 0x38f1,
0x3908, 0x391e, 0x3933, 0x3948, 0x395f, 0x3975, 0x398b, 0x39a0,
0x39b7, 0x39ce, 0x39e4, 0x39fe, 0x3a12, 0x3a27, 0x3a3e, 0x3a54,
0x3a69, 0x3a7e, 0x3a94, 0x3aaa, 0x3ac5, 0x3adf, 0x3af9, 0x3b14,
0x3b29, 0x3b43, 0x3b5c, 0x3b75, 0x3b8f, 0x3ba9, 0x3bbf, 0x3bd4,
0x3be8, 0x3bfc, 0x3c11, 0x3c26, 0x3c40, 0x3c59, 0x3c72, 0x3c8c,
0x3ca0, 0x3cb9, 0x3cd1, 0x3ce9, 0x3d02, 0x3d1b, 0x3d2d, 0x3d3f,
// Entry 1700 - 173F
0x3d52, 0x3d66, 0x3d78, 0x3d8a, 0x3d9c, 0x3daf, 0x3dc1, 0x3dd3,
0x3de5, 0x3df8, 0x3e0a, 0x3e1c, 0x3e2f, 0x3e43, 0x3e55, 0x3e67,
0x3e79, 0x3e8b, 0x3e9d, 0x3eae, 0x3ec0, 0x3ed5, 0x3eea, 0x3eff,
0x3f14, 0x3f2a, 0x3f3a, 0x3f51, 0x3f68, 0x3f80, 0x3f98, 0x3fae,
0x3fc5, 0x3fdc, 0x3fef, 0x4006, 0x401e, 0x4034, 0x404a, 0x4061,
0x4074, 0x4088, 0x40a2, 0x40b4, 0x40cd, 0x40e1, 0x40f8, 0x4110,
0x4126, 0x413d, 0x414f, 0x4161, 0x4178, 0x4190, 0x41a7, 0x41bd,
0x41d3, 0x41ea, 0x41fc, 0x4212, 0x4229, 0x423b, 0x424e, 0x4260,
// Entry 1740 - 177F
0x4273, 0x4285, 0x429d, 0x42b5, 0x42cc, 0x42e3, 0x42f6, 0x4307,
0x431d, 0x432e, 0x4340, 0x4351, 0x4363, 0x4375, 0x4387, 0x439a,
0x43b2, 0x43d3, 0x43f4, 0x4417, 0x4431, 0x4452, 0x4470, 0x449c,
0x44b6, 0x44d0, 0x44ea, 0x44fd, 0x4512, 0x452d, 0x4543, 0x455e,
0x4573, 0x4589, 0x459f, 0x45b6, 0x45cb, 0x45e1, 0x45f6, 0x4612,
0x4628, 0x463d, 0x4653, 0x4669, 0x467f, 0x469a, 0x46b6, 0x46cc,
0x46e0, 0x46f4, 0x470e, 0x4728, 0x4742, 0x4757, 0x476c, 0x4789,
0x47ad, 0x47c5, 0x47dc, 0x47f3, 0x480c, 0x4824, 0x483c, 0x4853,
// Entry 1780 - 17BF
0x486c, 0x4885, 0x489d, 0x48b5, 0x48cc, 0x48e3, 0x48fc, 0x4914,
0x492c, 0x4943, 0x495c, 0x4975, 0x498d, 0x49a0, 0x49b7, 0x49ca,
0x49dc, 0x49ed, 0x4a01, 0x4a24, 0x4a3b, 0x4a4d, 0x4a62, 0x4a77,
0x4a8f, 0x4aa1, 0x4ab4, 0x4ad7, 0x4aef, 0x4b01, 0x4b1a, 0x4b2e,
0x4b41, 0x4b5c, 0x4b75, 0x4b95, 0x4bc0, 0x4bec, 0x4c07, 0x4c29,
0x4c44, 0x4c61, 0x4c85, 0x4cb0, 0x4cd5, 0x4cfc, 0x4d21, 0x4d48,
0x4d67, 0x4d82, 0x4da6, 0x4dbf, 0x4ddf, 0x4dff, 0x4e1c, 0x4e42,
0x4e68, 0x4e8e, 0x4ea5, 0x4ebd, 0x4ed0, 0x4ee4, 0x4ef7, 0x4f0c,
// Entry 17C0 - 17FF
0x4f28, 0x4f3d, 0x4f59, 0x4f6e, 0x4f8a, 0x4fa1, 0x4fbf, 0x4fd7,
0x4ff6, 0x500b, 0x5021, 0x5036, 0x5052, 0x5064, 0x5080, 0x5092,
0x50a9, 0x50bc, 0x50ce, 0x50e5, 0x50f7, 0x510e, 0x5121, 0x5139,
0x515b, 0x517d, 0x519f, 0x51b8, 0x51ca, 0x51e1, 0x51f3, 0x520a,
0x521c, 0x522e, 0x5246, 0x5258, 0x5272, 0x5284, 0x5296, 0x52a8,
0x52ba, 0x52cc, 0x52e3, 0x52fa, 0x530c, 0x531e, 0x5333, 0x534d,
0x5364, 0x5380, 0x5398, 0x53b5, 0x53d0, 0x53f2, 0x540e, 0x5431,
0x544b, 0x546a, 0x548b, 0x54b1, 0x54ca, 0x54ea, 0x54fc, 0x5515,
// Entry 1800 - 183F
0x552f, 0x5549, 0x5561, 0x5579, 0x5592, 0x55ae, 0x55ca, 0x55dd,
0x55ef, 0x5601, 0x5615, 0x5628, 0x563b, 0x564d, 0x5661, 0x5675,
0x5688, 0x5696, 0x56a5, 0x56b3, 0x56cb, 0x56de, 0x56f4, 0x5705,
0x5721, 0x573d, 0x5759, 0x5775, 0x5798, 0x57b4, 0x57d1, 0x57ee,
0x580b, 0x582c, 0x5853, 0x587a, 0x58a2, 0x58ca, 0x58f3, 0x5928,
0x595d, 0x5984, 0x59aa, 0x59d5, 0x5a00, 0x5a2d, 0x5a5a, 0x5a85,
0x5ab0, 0x5add, 0x5b0a, 0x5b35, 0x5b4b, 0x5b62, 0x5b79, 0x5b91,
0x5ba9, 0x5bbb, 0x5bcd, 0x5bdf, 0x5bf2, 0x5c04, 0x5c16, 0x5c29,
// Entry 1840 - 187F
0x5c3c, 0x5c4f, 0x5c62, 0x5c76, 0x5c89, 0x5c9c, 0x5caf, 0x5cc3,
0x5cd6, 0x5ce9, 0x5cfc, 0x5d0f, 0x5d22, 0x5d35, 0x5d48, 0x5d5b,
0x5d6e, 0x5d81, 0x5d94, 0x5da7, 0x5dba, 0x5dcd, 0x5de0, 0x5e02,
0x5e23, 0x5e43, 0x5e60, 0x5e7c, 0x5e9b, 0x5eb8, 0x5ed4, 0x5ef3,
0x5f09, 0x5f1e, 0x5f42, 0x5f66, 0x5f7a, 0x5f8e, 0x5fa2, 0x5fb5,
0x5fc8, 0x5fdd, 0x5ff1, 0x6005, 0x6018, 0x602d, 0x6042, 0x6056,
0x6068, 0x607c, 0x6090, 0x60a4, 0x60bc, 0x60d4, 0x60e2, 0x60fb,
0x610a, 0x6124, 0x613e, 0x614d, 0x6161, 0x6170, 0x618a, 0x6199,
// Entry 1880 - 18BF
0x61b3, 0x61c2, 0x61dc, 0x61f2, 0x6201, 0x621b, 0x622a, 0x6239,
0x6248, 0x6262, 0x6271, 0x628b, 0x62a3, 0x62bb, 0x62ca, 0x62e4,
0x62fe, 0x630d, 0x6327, 0x6337, 0x6346, 0x6360, 0x6370, 0x637f,
0x638f, 0x639f, 0x63ad, 0x63bb, 0x63cb, 0x63dd, 0x63f6, 0x6409,
0x641b, 0x6432, 0x6444, 0x645b, 0x646d, 0x6491, 0x64a8, 0x64be,
0x64cc, 0x64dc, 0x64f7, 0x6514, 0x652c, 0x6547, 0x6557, 0x6568,
0x6579, 0x6589, 0x659a, 0x65ab, 0x65bb, 0x65cc, 0x65dc, 0x65ed,
0x65fd, 0x660e, 0x661e, 0x662e, 0x663e, 0x664f, 0x6660, 0x6670,
// Entry 18C0 - 18FF
0x6681, 0x6691, 0x66a2, 0x66b2, 0x66c3, 0x66d4, 0x66e6, 0x66f7,
0x6707, 0x6717, 0x6727, 0x6737, 0x6748, 0x6758, 0x6768, 0x6779,
0x6789, 0x6798, 0x67b2, 0x67cc, 0x67e0, 0x67f3, 0x6806, 0x681a,
0x682d, 0x6841, 0x6854, 0x686b, 0x6882, 0x6899, 0x68b0, 0x68c7,
0x68de, 0x68f5, 0x6912, 0x692c, 0x693b, 0x694c, 0x6965, 0x698a,
0x69a3, 0x69c3, 0x69dc, 0x69ed, 0x69fd, 0x6a0d, 0x6a1f, 0x6a30,
0x6a41, 0x6a51, 0x6a63, 0x6a75, 0x6a86, 0x6a97, 0x6aa9, 0x6aba,
0x6acd, 0x6adf, 0x6af1, 0x6b05, 0x6b18, 0x6b2b, 0x6b3d, 0x6b51,
// Entry 1900 - 193F
0x6b65, 0x6b78, 0x6b8a, 0x6b9c, 0x6bae, 0x6bc1, 0x6bd3, 0x6be6,
0x6bf9, 0x6c0c, 0x6c1f, 0x6c32, 0x6c44, 0x6c56, 0x6c68, 0x6c7b,
0x6c8d, 0x6c9f, 0x6cb1, 0x6cc3, 0x6cd6, 0x6ce8, 0x6cfa, 0x6d0c,
0x6d1f, 0x6d31, 0x6d44, 0x6d56, 0x6d69, 0x6d7b, 0x6d8d, 0x6d9f,
0x6db2, 0x6dcb, 0x6de7, 0x6df5, 0x6e06, 0x6e13, 0x6e2e, 0x6e50,
0x6e70, 0x6e94, 0x6eb2, 0x6ecf, 0x6eec, 0x6f11, 0x6f35, 0x6f53,
0x6f75, 0x6f98, 0x6fbc, 0x6fe0, 0x7004, 0x7027, 0x704b, 0x706f,
0x7093, 0x70b6, 0x70da, 0x70fe, 0x7122, 0x7146, 0x7169, 0x718d,
// Entry 1940 - 197F
0x71b2, 0x71d6, 0x71fa, 0x721e, 0x7241, 0x7266, 0x728b, 0x72b0,
0x72d4, 0x72f9, 0x731e, 0x7342, 0x7366, 0x738a, 0x73af, 0x73d3,
0x73f8, 0x741c, 0x743f, 0x7463, 0x7486, 0x74aa, 0x74ce, 0x74f1,
0x7514, 0x753a, 0x7565, 0x7589, 0x75ad, 0x75d7, 0x7603, 0x7624,
0x7648, 0x766b, 0x768c, 0x76b3, 0x76d9, 0x76ff, 0x7725, 0x7738,
0x7748, 0x775a, 0x776e, 0x7793, 0x77c7, 0x77f0, 0x7821, 0x7838,
0x7873, 0x788c, 0x78a5, 0x78c0, 0x78d4, 0x78ed, 0x7908, 0x7938,
0x7963, 0x797d, 0x7996, 0x79b8, 0x79d3, 0x79f7, 0x7a1a, 0x7a3f,
// Entry 1980 - 19BF
0x7a5f, 0x7a7f, 0x7a9e, 0x7ac7, 0x7ad8, 0x7af9, 0x7b11, 0x7b30,
0x7b52, 0x7b69, 0x7b88, 0x7b9f, 0x7bb5, 0x7bcb, 0x7bde, 0x7bf3,
0x7c0f, 0x7c36, 0x7c52, 0x7c6f, 0x7c8b, 0x7cae, 0x7cca, 0x7ce6,
0x7d04, 0x7d20, 0x7d40, 0x7d5b, 0x7d77, 0x7d93, 0x7dbb, 0x7dd7,
0x7dfc, 0x7e18, 0x7e39, 0x7e56, 0x7e78, 0x7ea1, 0x7ebd, 0x7eda,
0x7ef7, 0x7f17, 0x7f33, 0x7f58, 0x7f7b, 0x7f97, 0x7fb3, 0x7fd0,
0x7ff9, 0x801d, 0x8039, 0x8055, 0x8071, 0x808f, 0x80b4, 0x80c4,
0x80e4, 0x8104, 0x8121, 0x813f, 0x815d, 0x817d, 0x8196, 0x81b0,
// Entry 19C0 - 19FF
0x81c9, 0x81e9, 0x8202, 0x821b, 0x823d, 0x8256, 0x826f, 0x8288,
0x82a1, 0x82ba, 0x82d3, 0x82ec, 0x8305, 0x8327, 0x8340, 0x835a,
0x8373, 0x838c, 0x83a5, 0x83be, 0x83d7, 0x83ee, 0x840c, 0x8427,
0x8446, 0x845d, 0x8474, 0x848b, 0x84a6, 0x84c2, 0x84e5, 0x84fc,
0x851a, 0x8531, 0x8548, 0x8561, 0x8578, 0x8594, 0x85b4, 0x85d7,
0x85ee, 0x8605, 0x861c, 0x863c, 0x865a, 0x8671, 0x868a, 0x86a4,
0x86c5, 0x86e0, 0x86ff, 0x8718, 0x8736, 0x8754, 0x8772, 0x8790,
0x87b1, 0x87d3, 0x87f3, 0x8813, 0x8833, 0x8848, 0x886e, 0x8894,
// Entry 1A00 - 1A3F
0x88ba, 0x88e0, 0x8906, 0x892c, 0x8952, 0x8985, 0x89ab, 0x89d1,
0x89f7, 0x8a12, 0x8a2d, 0x8a49, 0x8a71, 0x8a99, 0x8abc, 0x8adc,
0x8b04, 0x8b2a, 0x8b50, 0x8b76, 0x8b9c, 0x8bc2, 0x8be8, 0x8c0e,
0x8c34, 0x8c5a, 0x8c80, 0x8ca6, 0x8ccc, 0x8cf4, 0x8d1a, 0x8d40,
0x8d66, 0x8d8e, 0x8dba, 0x8de1, 0x8e09, 0x8e36, 0x8e6c, 0x8e98,
0x8ec0, 0x8eed, 0x8f17, 0x8f3f, 0x8f69, 0x8f8b, 0x8fa2, 0x8fc3,
0x8fdc, 0x9001, 0x9018, 0x9043, 0x9061, 0x907f, 0x90a2, 0x90bc,
0x90db, 0x9106, 0x912f, 0x915a, 0x9183, 0x91a2, 0x91c3, 0x91ef,
// Entry 1A40 - 1A7F
0x9215, 0x9240, 0x925f, 0x927d, 0x9296, 0x92b7, 0x92d0, 0x92f9,
0x9314, 0x9331, 0x9350, 0x9371, 0x938f, 0x93a6, 0x93d1, 0x93f2,
0x940b, 0x9426, 0x9443, 0x9460, 0x9475, 0x948e, 0x94a4, 0x94ba,
0x94d0, 0x94e6, 0x9501, 0x951c, 0x9540, 0x9556, 0x956c, 0x958d,
0x95a3, 0x95b9, 0x95cb, 0x95dd, 0x95ef, 0x9622, 0x9641, 0x9660,
0x967f, 0x96a5, 0x96cb, 0x96eb, 0x9709, 0x972f, 0x974d, 0x976b,
0x9791, 0x97b7, 0x97d5, 0x97fb, 0x9821, 0x9847, 0x9865, 0x9888,
0x98a6, 0x98c8, 0x98e6, 0x9907, 0x9929, 0x9947, 0x997e, 0x99bd,
// Entry 1A80 - 1ABF
0x99db, 0x99fb, 0x9a3a, 0x9a58, 0x9a85, 0x9ab2, 0x9adf, 0x9af6,
0x9b12, 0x9b2d, 0x9b45, 0x9b69, 0x9b81, 0x9b98, 0x9bbd, 0x9bdc,
0x9bfa, 0x9c2c, 0x9c52, 0x9c76, 0x9c9b, 0x9cbe, 0x9ce3, 0x9d06,
0x9d2c, 0x9d50, 0x9d7d, 0x9da8, 0x9dcd, 0x9df0, 0x9e15, 0x9e38,
0x9e5e, 0x9e82, 0x9ea5, 0x9ec6, 0x9ef2, 0x9f1c, 0x9f48, 0x9f72,
0x9f9e, 0x9fc8, 0x9ff4, 0xa01e, 0xa045, 0xa06a, 0xa097, 0xa0c2,
0xa0e7, 0xa10a, 0xa12c, 0xa14c, 0xa171, 0xa194, 0xa1b9, 0xa1dc,
0xa201, 0xa224, 0xa247, 0xa268, 0xa28f, 0xa2b4, 0xa2db, 0xa300,
// Entry 1AC0 - 1AFF
0xa32f, 0xa35c, 0xa37d, 0xa39c, 0xa3c1, 0xa3e4, 0xa40a, 0xa42e,
0xa453, 0xa476, 0xa4a6, 0xa4d4, 0xa4fa, 0xa51e, 0xa54a, 0xa574,
0xa595, 0xa5b4, 0xa5d9, 0xa5fc, 0xa621, 0xa644, 0xa669, 0xa68c,
0xa6b1, 0xa6d4, 0xa6fa, 0xa71e, 0xa74a, 0xa774, 0xa79f, 0xa7c8,
0xa7f7, 0xa824, 0xa850, 0xa87a, 0xa8a6, 0xa8d0, 0xa8f1, 0xa910,
0xa935, 0xa958, 0xa97d, 0xa9a0, 0xa9c5, 0xa9e8, 0xaa18, 0xaa46,
0xaa6c, 0xaa90, 0xaab5, 0xaad8, 0xaafd, 0xab20, 0xab4f, 0xab7c,
0xabab, 0xabd8, 0xac0b, 0xac3c, 0xac61, 0xac84, 0xaca9, 0xaccc,
// Entry 1B00 - 1B3F
0xacf2, 0xad16, 0xad42, 0xad6c, 0xad97, 0xadc0, 0xade7, 0xae0c,
0xae38, 0xae62, 0xae8d, 0xaeb6, 0xaee6, 0xaf14, 0xaf35, 0xaf54,
0xaf79, 0xaf9c, 0xafbd, 0xafdc, 0xaffd, 0xb01c, 0xb041, 0xb064,
0xb089, 0xb0ac, 0xb0d1, 0xb0f4, 0xb119, 0xb13c, 0xb161, 0xb184,
0xb1a9, 0xb1cc, 0xb1f2, 0xb216, 0xb23b, 0xb25e, 0xb284, 0xb2a8,
0xb2cc, 0xb2ef, 0xb313, 0xb337, 0xb360, 0xb388, 0xb3b6, 0xb3e0,
0xb3fc, 0xb414, 0xb439, 0xb45c, 0xb482, 0xb4a6, 0xb4d6, 0xb504,
0xb534, 0xb562, 0xb597, 0xb5ca, 0xb5fa, 0xb628, 0xb65c, 0xb68e,
// Entry 1B40 - 1B7F
0xb6b9, 0xb6e2, 0xb70d, 0xb736, 0xb766, 0xb794, 0xb7bf, 0xb7e8,
0xb817, 0xb844, 0xb869, 0xb88c, 0xb8b2, 0xb8d6, 0xb8f7, 0xb916,
0xb946, 0xb974, 0xb9a4, 0xb9d2, 0xba07, 0xba3a, 0xba6a, 0xba98,
0xbacc, 0xbafe, 0xbb24, 0xbb48, 0xbb6d, 0xbb90, 0xbbb5, 0xbbd8,
0xbbfe, 0xbc22, 0xbc52, 0xbc80, 0xbcb0, 0xbcde, 0xbd13, 0xbd46,
0xbd76, 0xbda4, 0xbdd8, 0xbe0a, 0xbe34, 0xbe5c, 0xbe86, 0xbeae,
0xbedd, 0xbf0a, 0xbf34, 0xbf5c, 0xbf8a, 0xbfb6, 0xbfdb, 0xbffe,
0xc024, 0xc048, 0xc072, 0xc09a, 0xc0c4, 0xc0ec, 0xc11b, 0xc148,
// Entry 1B80 - 1BBF
0xc172, 0xc19a, 0xc1c8, 0xc1f4, 0xc215, 0xc234, 0xc259, 0xc27c,
0xc2a2, 0xc2c6, 0xc2e7, 0xc306, 0xc32a, 0xc34c, 0xc36f, 0xc390,
0xc3b0, 0xc3ce, 0xc3f1, 0xc414, 0xc441, 0xc46e, 0xc49a, 0xc4c6,
0xc4f9, 0xc52c, 0xc551, 0xc576, 0xc5a5, 0xc5d4, 0xc602, 0xc630,
0xc665, 0xc69a, 0xc6bf, 0xc6e4, 0xc713, 0xc742, 0xc770, 0xc79e,
0xc7c5, 0xc7ec, 0xc81d, 0xc84e, 0xc87e, 0xc8ae, 0xc8cf, 0xc8f0,
0xc91b, 0xc946, 0xc970, 0xc99a, 0xc9cb, 0xc9fc, 0xca1f, 0xca42,
0xca6f, 0xca9c, 0xcac8, 0xcaf4, 0xcb27, 0xcb5a, 0xcb7c, 0xcb9e,
// Entry 1BC0 - 1BFF
0xcbca, 0xcbf6, 0xcc21, 0xcc4c, 0xcc7e, 0xccb0, 0xccd4, 0xccf8,
0xcd26, 0xcd54, 0xcd81, 0xcdae, 0xcde2, 0xce16, 0xce3b, 0xce60,
0xce8f, 0xcebe, 0xceec, 0xcf1a, 0xcf41, 0xcf68, 0xcf99, 0xcfca,
0xcffa, 0xd02a, 0xd04f, 0xd074, 0xd0a3, 0xd0d2, 0xd100, 0xd12e,
0xd163, 0xd198, 0xd1bf, 0xd1f0, 0xd220, 0xd257, 0xd27a, 0xd29d,
0xd2ca, 0xd2f7, 0xd323, 0xd34f, 0xd382, 0xd3b5, 0xd3da, 0xd3ff,
0xd42e, 0xd45d, 0xd48b, 0xd4b9, 0xd4ee, 0xd523, 0xd546, 0xd568,
0xd58d, 0xd5b1, 0xd5d2, 0xd5f2, 0xd614, 0xd635, 0xd65a, 0xd67e,
// Entry 1C00 - 1C3F
0xd6a3, 0xd6c7, 0xd6ea, 0xd70c, 0xd741, 0xd776, 0xd7b5, 0xd7f4,
0xd832, 0xd870, 0xd8b5, 0xd8fa, 0xd932, 0xd96a, 0xd9ac, 0xd9ee,
0xda2f, 0xda70, 0xdab8, 0xdb00, 0xdb33, 0xdb66, 0xdba3, 0xdbe0,
0xdc1c, 0xdc58, 0xdc9b, 0xdcde, 0xdd14, 0xdd4a, 0xdd8a, 0xddca,
0xde09, 0xde48, 0xde8e, 0xded4, 0xdf09, 0xdf3e, 0xdf7d, 0xdfbc,
0xdffa, 0xe038, 0xe07d, 0xe0c2, 0xe0fa, 0xe132, 0xe174, 0xe1b6,
0xe1f7, 0xe238, 0xe280, 0xe2c8, 0xe2ec, 0xe310, 0xe345, 0xe370,
0xe3a4, 0xe3cd, 0xe408, 0xe42e, 0xe454, 0xe479, 0xe49d, 0xe4cb,
// Entry 1C40 - 1C7F
0xe4d8, 0xe4ec, 0xe4f7, 0xe508, 0xe527, 0xe55a, 0xe583, 0xe5b5,
0xe5dc, 0xe615, 0xe63c, 0xe662, 0xe685, 0xe6a7, 0xe6d3, 0xe6e8,
0xe6fc, 0xe717, 0xe73a, 0xe75d, 0xe78d, 0xe7bc, 0xe7e4, 0xe81a,
0xe83f, 0xe864, 0xe888, 0xe8ab, 0xe8c0, 0xe8d4, 0xe8ef, 0xe915,
0xe93b, 0xe96e, 0xe9a0, 0xe9c1, 0xe9e2, 0xea0d, 0xea46, 0xea6e,
0xea96, 0xeabd, 0xeae3, 0xeb06, 0xeb1f, 0xeb37, 0xeb42, 0xeb77,
0xeba2, 0xebd6, 0xebff, 0xec3a, 0xec61, 0xec87, 0xecac, 0xecd0,
0xecfe, 0xed08, 0xed13, 0xed1a, 0xed21, 0xed29, 0xed31, 0xed43,
// Entry 1C80 - 1CBF
0xed54, 0xed64, 0xed70, 0xed81, 0xed8b, 0xed95, 0xeda5, 0xedba,
0xedcb, 0xeddd, 0xedef, 0xedf5, 0xee08, 0xee13, 0xee1a, 0xee21,
0xee2f, 0xee43, 0xee52, 0xee6c, 0xee87, 0xeea2, 0xeec7, 0xeee1,
0xeefc, 0xef17, 0xef3c, 0xef42, 0xef4f, 0xef55, 0xef66, 0xef74,
0xef82, 0xef95, 0xefa6, 0xefb4, 0xefc7, 0xefde, 0xeff5, 0xf00f,
0xf025, 0xf03b, 0xf050, 0xf05e, 0xf073, 0xf078, 0xf084, 0xf090,
0xf09e, 0xf0b3, 0xf0c8, 0xf0cd, 0xf0f6, 0xf120, 0xf12e, 0xf145,
0xf150, 0xf158, 0xf160, 0xf16d, 0xf182, 0xf18a, 0xf197, 0xf1a5,
// Entry 1CC0 - 1CFF
0xf1c3, 0xf1e2, 0xf1f6, 0xf20f, 0xf228, 0xf238, 0xf24d, 0xf263,
0xf27a, 0xf286, 0xf298, 0xf2a0, 0xf2c0, 0xf2d5, 0xf2df, 0xf2f0,
0xf307, 0xf31c, 0xf32b, 0xf33f, 0xf353, 0xf366, 0xf373, 0xf37f,
0xf387, 0xf399, 0xf3b2, 0xf3bd, 0xf3d1, 0xf3e0, 0xf3f3, 0xf401,
0xf416, 0xf42b, 0xf43f, 0xf456, 0xf470, 0xf48b, 0xf4a6, 0xf4c2,
0xf4d7, 0xf4eb, 0xf4fb, 0xf51b, 0xf52b, 0xf53b, 0xf54a, 0xf55b,
0xf56c, 0xf57c, 0xf591, 0xf5a2, 0xf5b9, 0xf5d5, 0xf5f2, 0xf612,
0xf620, 0xf62d, 0xf63a, 0xf649, 0xf657, 0xf665, 0xf672, 0xf681,
// Entry 1D00 - 1D3F
0xf690, 0xf69e, 0xf6b1, 0xf6c0, 0xf6d5, 0xf6ef, 0xf70a, 0xf728,
0xf746, 0xf764, 0xf782, 0xf7a4, 0xf7c2, 0xf7e0, 0xf7fe, 0xf81c,
0xf83a, 0xf858, 0xf876, 0xf894, 0xf8a6, 0xf8b0, 0xf8bd, 0xf8ce,
0xf8d7, 0xf8e0, 0xf8ea, 0xf8f5, 0xf8ff, 0xf907, 0xf916, 0xf91f,
0xf928, 0xf930, 0xf93b, 0xf947, 0xf958, 0xf961, 0xf96d, 0xf979,
0xf985, 0xf98e, 0xf9a1, 0xf9ae, 0xf9b8, 0xf9c9, 0xf9da, 0xf9ea,
0xf9f4, 0xf9fe, 0xfa07, 0xfa13, 0xfa1b, 0xfa37, 0xfa54, 0xfa78,
0xfa9d, 0xfac0, 0xfadf, 0xfaf9, 0xfb14, 0xfb2a, 0xfb4a, 0xfb6e,
// Entry 1D40 - 1D7F
0xfb88, 0xfba1, 0xfbbb, 0xfbd5, 0xfbf0, 0xfc14, 0xfc34, 0xfc4e,
0xfc68, 0xfc94, 0xfcb5, 0xfcdd, 0xfcf5, 0xfd0e, 0xfd29, 0xfd4a,
0xfd6f, 0xfd9f, 0xfdce, 0xfde8, 0xfe03, 0xfe1b, 0xfe25, 0xfe3d,
0xfe54, 0xfe62, 0xfe74, 0xfe7b, 0xfe83, 0xfe91, 0xfe98, 0xfea9,
0xfeb7, 0xfec7, 0xfedd, 0xfef4, 0xff03, 0xff1e, 0xff2e, 0xff44,
0xff54, 0xff62, 0xff70, 0xff87, 0xff92, 0xffab, 0xffbb, 0xffd2,
0xffe9, 0xfff9, 0x000f, 0x0026, 0x0037, 0x003f, 0x004b, 0x0059,
0x0068, 0x0070, 0x0087, 0x0091, 0x0099, 0x00aa, 0x00c0, 0x00de,
// Entry 1D80 - 1DBF
0x00e9, 0x00f6, 0x0106, 0x011c, 0x012c, 0x013a, 0x014a, 0x015a,
0x016a, 0x017a, 0x0188, 0x0193, 0x019d, 0x01a9, 0x01b5, 0x01c7,
0x01d8, 0x01e6, 0x01fc, 0x0215, 0x0230, 0x0248, 0x0265, 0x0280,
0x029b, 0x02b8, 0x02d3, 0x02f1, 0x030d, 0x0329, 0x0345, 0x0361,
0x036e, 0x037e, 0x0386, 0x0392, 0x03a0, 0x03bb, 0x03d6, 0x03ef,
0x0408, 0x0421, 0x043b, 0x0454, 0x046e, 0x048a, 0x04a5, 0x04be,
0x04d9, 0x04f3, 0x0510, 0x052c, 0x0549, 0x055f, 0x0570, 0x0581,
0x0594, 0x05a6, 0x05b8, 0x05c9, 0x05dc, 0x05ef, 0x0601, 0x0612,
// Entry 1DC0 - 1DFF
0x0626, 0x063a, 0x064d, 0x0666, 0x0680, 0x069a, 0x06b1, 0x06c8,
0x06e1, 0x06f9, 0x0711, 0x0728, 0x0741, 0x075a, 0x0772, 0x0789,
0x07a3, 0x07bd, 0x07d6, 0x07f5, 0x0815, 0x0835, 0x0853, 0x086e,
0x0888, 0x08aa, 0x08c7, 0x08e2, 0x0900, 0x091c, 0x093e, 0x0959,
0x0969, 0x097b, 0x098a, 0x0997, 0x09a7, 0x09b6, 0x09c6, 0x09d3,
0x09e3, 0x09f3, 0x0a03, 0x0a13, 0x0a2e, 0x0a4a, 0x0a5e, 0x0a73,
0x0a8d, 0x0aa5, 0x0ac0, 0x0ada, 0x0af3, 0x0b0d, 0x0b25, 0x0b3b,
0x0b54, 0x0b6c, 0x0b83, 0x0b9c, 0x0bb6, 0x0bcf, 0x0be9, 0x0bfe,
// Entry 1E00 - 1E3F
0x0c1a, 0x0c30, 0x0c50, 0x0c71, 0x0c93, 0x0cb6, 0x0cdc, 0x0d01,
0x0d23, 0x0d41, 0x0d5d, 0x0d90, 0x0daf, 0x0dca, 0x0ded, 0x0e12,
0x0e36, 0x0e59, 0x0e7d, 0x0ea3, 0x0ec9, 0x0eee, 0x0f13, 0x0f3d,
0x0f62, 0x0f79, 0x0f8e, 0x0fa6, 0x0fbd, 0x0fe6, 0x100f, 0x1031,
0x1054, 0x1077, 0x108d, 0x10a1, 0x10b8, 0x10ce, 0x10e5, 0x10f9,
0x1110, 0x1127, 0x113e, 0x1155, 0x116b, 0x1182, 0x119a, 0x11b3,
0x11d3, 0x11f5, 0x120b, 0x121f, 0x1236, 0x124c, 0x1262, 0x1279,
0x128e, 0x12a1, 0x12b7, 0x12cc, 0x12e8, 0x1307, 0x133a, 0x136b,
// Entry 1E40 - 1E7F
0x1385, 0x13ab, 0x13cb, 0x13e5, 0x13ff, 0x1412, 0x142f, 0x1459,
0x1470, 0x1494, 0x14b9, 0x14de, 0x1509, 0x1535, 0x1561, 0x157c,
0x1598, 0x15b4, 0x15bb, 0x15c5, 0x15d9, 0x15e5, 0x15f9, 0x1602,
0x160b, 0x1610, 0x161a, 0x162b, 0x163b, 0x164d, 0x1667, 0x167f,
0x168b, 0x1698, 0x16a7, 0x16b6, 0x16c0, 0x16d2, 0x16da, 0x16e8,
0x16f1, 0x1702, 0x170f, 0x171e, 0x1729, 0x1732, 0x173d, 0x174c,
0x1754, 0x175f, 0x1764, 0x1772, 0x1781, 0x1788, 0x1797, 0x17a2,
0x17b1, 0x17bc, 0x17c6, 0x17d2, 0x17d7, 0x17df, 0x17ee, 0x17fd,
// Entry 1E80 - 1EBF
0x180d, 0x181d, 0x182c, 0x183e, 0x1858, 0x1876, 0x187f, 0x1886,
0x188b, 0x1895, 0x189e, 0x18a4, 0x18b8, 0x18c2, 0x18d0, 0x18de,
0x18ed, 0x18f6, 0x1904, 0x190d, 0x1918, 0x192f, 0x194a, 0x1960,
0x1987, 0x19b2, 0x19c1, 0x19d4, 0x19ec, 0x19f8, 0x1a04, 0x1a11,
0x1a2c, 0x1a3e, 0x1a52, 0x1a68, 0x1a8e, 0x1ab0, 0x1abc, 0x1ac8,
0x1ad8, 0x1ae5, 0x1af3, 0x1afc, 0x1b0a, 0x1b15, 0x1b23, 0x1b39,
0x1b44, 0x1b57, 0x1b63, 0x1b6f, 0x1b7f, 0x1b95, 0x1baa, 0x1bc2,
0x1bd9, 0x1bf3, 0x1c0d, 0x1c2a, 0x1c38, 0x1c49, 0x1c50, 0x1c61,
// Entry 1EC0 - 1EFF
0x1c6e, 0x1c7e, 0x1c9c, 0x1cbd, 0x1cd7, 0x1cf4, 0x1d17, 0x1d3d,
0x1d56, 0x1d6f, 0x1d91, 0x1db3, 0x1dbb, 0x1dc3, 0x1dd7, 0x1deb,
0x1e04, 0x1e1d, 0x1e2d, 0x1e3d, 0x1e46, 0x1e51, 0x1e60, 0x1e71,
0x1e86, 0x1e9d, 0x1ebd, 0x1edf, 0x1efa, 0x1f17, 0x1f1f, 0x1f36,
0x1f44, 0x1f53, 0x1f65, 0x1f80, 0x1f9e, 0x1fa8, 0x1fb2, 0x1fbe,
0x1fcb, 0x1fd8, 0x1fee, 0x2002, 0x2017, 0x2030, 0x203e, 0x204a,
0x2056, 0x2063, 0x2070, 0x2084, 0x208e, 0x2097, 0x20a0, 0x20a7,
0x20b0, 0x20b6, 0x20ba, 0x20c0, 0x20e3, 0x210d, 0x211b, 0x2123,
// Entry 1F00 - 1F3F
0x2131, 0x2163, 0x217a, 0x2191, 0x21a3, 0x21be, 0x21dc, 0x2203,
0x220e, 0x2216, 0x221e, 0x2238, 0x2243, 0x2246, 0x224a, 0x224d,
0x2261, 0x226f, 0x2280, 0x2290, 0x22a2, 0x22ad, 0x22bd, 0x22c9,
0x22d6, 0x22e4, 0x22ea, 0x230f, 0x2335, 0x234c, 0x2364, 0x2379,
0x2389, 0x239a, 0x23a7, 0x23b6, 0x23c9, 0x23d5, 0x23de, 0x23f3,
0x2405, 0x241a, 0x242d, 0x2443, 0x2465, 0x2487, 0x249c, 0x24b4,
0x24c8, 0x24dc, 0x24f5, 0x250e, 0x252d, 0x254f, 0x256e, 0x2590,
0x25af, 0x25d1, 0x25ef, 0x260d, 0x2623, 0x2646, 0x2668, 0x2694,
// Entry 1F40 - 1F7F
0x26a5, 0x26c0, 0x26da, 0x26f6, 0x271c, 0x2754, 0x2792, 0x27ab,
0x27c2, 0x27df, 0x27f7, 0x281d, 0x2841, 0x2877, 0x28b3, 0x28c8,
0x28e3, 0x28fc, 0x2909, 0x2917, 0x291c, 0x2928, 0x2936, 0x2940,
0x294b, 0x2954, 0x2960, 0x296d, 0x2977, 0x2982, 0x2993, 0x29a3,
0x29b1, 0x29be, 0x29cf, 0x29dd, 0x29e0, 0x29e7, 0x29ed, 0x29ff,
0x2a11, 0x2a20, 0x2a36, 0x2a45, 0x2a4a, 0x2a53, 0x2a62, 0x2a72,
0x2a84, 0x2a97, 0x2aa8, 0x2abc, 0x2ac1, 0x2ac6, 0x2aee, 0x2af8,
0x2b0a, 0x2b1e, 0x2b26, 0x2b41, 0x2b5d, 0x2b6e, 0x2b7a, 0x2b86,
// Entry 1F80 - 1FBF
0x2b98, 0x2ba0, 0x2bac, 0x2bbc, 0x2bc9, 0x2bce, 0x2bd9, 0x2be4,
0x2c00, 0x2c21, 0x2c41, 0x2c62, 0x2c84, 0x2ca2, 0x2cc3, 0x2ce5,
0x2d05, 0x2d24, 0x2d47, 0x2d67, 0x2d8b, 0x2daf, 0x2dd6, 0x2dfa,
0x2e1f, 0x2e49, 0x2e74, 0x2e9a, 0x2ec2, 0x2ee3, 0x2f08, 0x2f28,
0x2f4b, 0x2f6d, 0x2f95, 0x2fba, 0x2fd9, 0x2ffc, 0x301a, 0x303b,
0x305f, 0x3089, 0x30ad, 0x30d1, 0x30f7, 0x3119, 0x313e, 0x315f,
0x317f, 0x31a0, 0x31c0, 0x31e7, 0x320a, 0x322e, 0x3251, 0x3277,
0x329c, 0x32c1, 0x32e6, 0x3312, 0x3331, 0x3350, 0x336b, 0x338c,
// Entry 1FC0 - 1FFF
0x33b4, 0x33d8, 0x33fb, 0x3421, 0x3445, 0x345f, 0x3478, 0x3493,
0x34b7, 0x34dd, 0x3500, 0x3524, 0x353f, 0x354d, 0x3574, 0x3587,
0x3592, 0x35af, 0x35bf, 0x35da, 0x35f8, 0x3607, 0x3619, 0x363f,
0x364b, 0x3661, 0x366c, 0x368d, 0x36a2, 0x36c4, 0x36cf, 0x36e0,
0x36f1, 0x3712, 0x3733, 0x3752, 0x376f, 0x378d, 0x37a5, 0x37bf,
0x37db, 0x37e8, 0x37f1, 0x3804, 0x3817, 0x3832, 0x384c, 0x3867,
0x3883, 0x389e, 0x38ba, 0x38da, 0x38f7, 0x3917, 0x3938, 0x3956,
0x3977, 0x3994, 0x39b3, 0x39d0, 0x39e7, 0x3a05, 0x3a25, 0x3a43,
// Entry 2000 - 203F
0x3a55, 0x3a6e, 0x3a9d, 0x3acc, 0x3ad9, 0x3ae9, 0x3afb, 0x3b10,
0x3b3d, 0x3b52, 0x3b68, 0x3b7f, 0x3b95, 0x3bab, 0x3bc1, 0x3bd7,
0x3c04, 0x3c34, 0x3c5f, 0x3c95, 0x3cc9, 0x3cf6, 0x3d2e, 0x3d64,
0x3d8c, 0x3dc0, 0x3df2, 0x3e1c, 0x3e44, 0x3e70, 0x3e9f, 0x3eaa,
0x3eb7, 0x3ec3, 0x3eda, 0x3ee8, 0x3f00, 0x3f18, 0x3f35, 0x3f52,
0x3f6c, 0x3f7c, 0x3f8e, 0x3fa0, 0x3fac, 0x3fb0, 0x3fbf, 0x3fd1,
0x3fe2, 0x3ff6, 0x4010, 0x402d, 0x403c, 0x4054, 0x4060, 0x4068,
0x4072, 0x4089, 0x40a0, 0x40c4, 0x40e7, 0x4108, 0x412b, 0x4161,
// Entry 2040 - 207F
0x4196, 0x41cc, 0x41d7, 0x41e0, 0x41eb, 0x4206, 0x4229, 0x424d,
0x426e, 0x4291, 0x42a4, 0x42b9, 0x42d0, 0x42dc, 0x42ef, 0x42fe,
0x4310, 0x4323, 0x4332, 0x434d, 0x4365, 0x437b, 0x4399, 0x43ab,
0x43c1, 0x43d0, 0x43e4, 0x4404, 0x4418, 0x4436, 0x444a, 0x4464,
0x4478, 0x448b, 0x44a6, 0x44c3, 0x44e0, 0x44ff, 0x451d, 0x453c,
0x4557, 0x457b, 0x458c, 0x45a4, 0x45b9, 0x45ca, 0x45e3, 0x45fd,
0x4618, 0x4631, 0x4641, 0x4652, 0x465e, 0x4666, 0x4678, 0x4692,
0x46b0, 0x46b8, 0x46c1, 0x46c9, 0x46da, 0x46e9, 0x46f4, 0x4712,
// Entry 2080 - 20BF
0x4725, 0x472d, 0x4748, 0x475c, 0x476d, 0x477e, 0x4791, 0x47a3,
0x47b5, 0x47c6, 0x47d9, 0x47ec, 0x47fe, 0x4810, 0x4825, 0x483a,
0x4851, 0x4868, 0x487e, 0x4894, 0x48ac, 0x48c3, 0x48da, 0x48ef,
0x4906, 0x491d, 0x4936, 0x494e, 0x4966, 0x497d, 0x4996, 0x49af,
0x49c7, 0x49df, 0x49fa, 0x4a15, 0x4a32, 0x4a4f, 0x4a6b, 0x4a87,
0x4aa5, 0x4ac2, 0x4adf, 0x4afa, 0x4b0d, 0x4b20, 0x4b35, 0x4b49,
0x4b5d, 0x4b70, 0x4b85, 0x4b9a, 0x4bae, 0x4bc2, 0x4bd9, 0x4bf0,
0x4c09, 0x4c22, 0x4c3a, 0x4c52, 0x4c6c, 0x4c85, 0x4c9e, 0x4cb5,
// Entry 20C0 - 20FF
0x4cd7, 0x4cf9, 0x4d1b, 0x4d3d, 0x4d5f, 0x4d81, 0x4da3, 0x4dc5,
0x4de7, 0x4e09, 0x4e2b, 0x4e4d, 0x4e6f, 0x4e91, 0x4eb3, 0x4ed5,
0x4ef7, 0x4f19, 0x4f3b, 0x4f5d, 0x4f7f, 0x4fa1, 0x4fc3, 0x4fe5,
0x5007, 0x5029, 0x5047, 0x5065, 0x5083, 0x50a1, 0x50bf, 0x50dd,
0x50fb, 0x5119, 0x5137, 0x5155, 0x5173, 0x5191, 0x51af, 0x51cd,
0x51eb, 0x5209, 0x5227, 0x5245, 0x5263, 0x5281, 0x529f, 0x52bd,
0x52db, 0x52f9, 0x5317, 0x5335, 0x5351, 0x536d, 0x5389, 0x53a5,
0x53c1, 0x53dd, 0x53f9, 0x5415, 0x5431, 0x544d, 0x5469, 0x5485,
// Entry 2100 - 213F
0x54a1, 0x54bd, 0x54d9, 0x54f5, 0x5511, 0x552d, 0x5549, 0x5565,
0x5581, 0x559d, 0x55b9, 0x55d5, 0x55f1, 0x560d, 0x561f, 0x563d,
0x565b, 0x567b, 0x569b, 0x56ba, 0x56d9, 0x56fa, 0x571a, 0x573a,
0x5758, 0x5770, 0x5788, 0x57a2, 0x57bb, 0x57d4, 0x57ec, 0x5806,
0x5820, 0x5839, 0x5852, 0x586d, 0x588a, 0x58a7, 0x58c2, 0x58dd,
0x5906, 0x592f, 0x5956, 0x597d, 0x59a9, 0x59d5, 0x59ff, 0x5a29,
0x5a4a, 0x5a71, 0x5a98, 0x5ab9, 0x5ad9, 0x5aff, 0x5b25, 0x5b45,
0x5b64, 0x5b89, 0x5bae, 0x5bcd, 0x5beb, 0x5c0f, 0x5c33, 0x5c51,
// Entry 2140 - 217F
0x5c76, 0x5ca1, 0x5ccb, 0x5cf5, 0x5d20, 0x5d4a, 0x5d74, 0x5d99,
0x5dbd, 0x5de7, 0x5e10, 0x5e39, 0x5e63, 0x5e8c, 0x5eb5, 0x5ed9,
0x5eff, 0x5f2b, 0x5f57, 0x5f83, 0x5faf, 0x5fdb, 0x6007, 0x602d,
0x6051, 0x607b, 0x60a5, 0x60cf, 0x60f9, 0x6123, 0x614d, 0x6171,
0x619b, 0x61cb, 0x61fb, 0x622b, 0x625a, 0x6289, 0x62b9, 0x62e8,
0x6317, 0x6346, 0x6375, 0x63a4, 0x63d3, 0x6403, 0x6433, 0x645d,
0x6486, 0x64af, 0x64d6, 0x64fd, 0x651b, 0x6537, 0x6560, 0x6589,
0x65ab, 0x65d3, 0x65fb, 0x661c, 0x6643, 0x666a, 0x668a, 0x66b0,
// Entry 2180 - 21BF
0x66d6, 0x66f5, 0x6722, 0x674f, 0x6775, 0x67a1, 0x67cd, 0x67f2,
0x6820, 0x684e, 0x6875, 0x68a1, 0x68cd, 0x68f2, 0x6924, 0x6956,
0x6981, 0x69a6, 0x69ca, 0x69ec, 0x6a0f, 0x6a44, 0x6a79, 0x6a9a,
0x6ab1, 0x6ac6, 0x6ade, 0x6af5, 0x6b0c, 0x6b21, 0x6b39, 0x6b50,
0x6b77, 0x6b9b, 0x6bc2, 0x6be6, 0x6bf6, 0x6c0c, 0x6c23, 0x6c3c,
0x6c4c, 0x6c64, 0x6c7e, 0x6c97, 0x6ca1, 0x6cb9, 0x6cd2, 0x6ce9,
0x6cf8, 0x6d10, 0x6d26, 0x6d3b, 0x6d4b, 0x6d56, 0x6d62, 0x6d6c,
0x6d82, 0x6d98, 0x6dab, 0x6dbf, 0x6dd2, 0x6e04, 0x6e27, 0x6e59,
// Entry 21C0 - 21FF
0x6e8c, 0x6ea0, 0x6ec3, 0x6ef6, 0x6f02, 0x6f0e, 0x6f2f, 0x6f59,
0x6f74, 0x6f8d, 0x6fb3, 0x6fdd, 0x7007, 0x702b, 0x703d, 0x704f,
0x705e, 0x706d, 0x7085, 0x709d, 0x70b0, 0x70c3, 0x70dd, 0x70f7,
0x7117, 0x7137, 0x7154, 0x7171, 0x7194, 0x71b7, 0x71d3, 0x71ef,
0x720b, 0x7227, 0x7249, 0x726b, 0x7287, 0x72a3, 0x72c5, 0x72e7,
0x7302, 0x731d, 0x732a, 0x7337, 0x7363, 0x736a, 0x7371, 0x737d,
0x738a, 0x73a3, 0x73ab, 0x73b7, 0x73d2, 0x73ee, 0x740a, 0x7426,
0x744c, 0x7479, 0x748f, 0x74a6, 0x74b4, 0x74c8, 0x74e7, 0x7506,
// Entry 2200 - 223F
0x7526, 0x7547, 0x7568, 0x7588, 0x7599, 0x75aa, 0x75c4, 0x75dd,
0x75f6, 0x7610, 0x761c, 0x7637, 0x7653, 0x767d, 0x76a8, 0x76d1,
0x76f4, 0x771d, 0x7747, 0x7753, 0x7778, 0x779d, 0x77c3, 0x77e9,
0x780e, 0x7833, 0x7859, 0x787f, 0x7892, 0x78a6, 0x78b9, 0x78cc,
0x78df, 0x78f8, 0x7911, 0x7925, 0x7938, 0x793d, 0x7945, 0x794c,
0x7951, 0x795b, 0x7965, 0x796e, 0x797a, 0x797d, 0x798b, 0x799a,
0x79a5, 0x79af, 0x79be, 0x79cd, 0x79d7, 0x79ec, 0x79fd, 0x7a04,
0x7a1c, 0x7a28, 0x7a39, 0x7a4a, 0x7a52, 0x7a76, 0x7a8f, 0x7aa9,
// Entry 2240 - 227F
0x7ac2, 0x7ad9, 0x7af3, 0x7b0c, 0x7b20, 0x7b2c, 0x7b3c, 0x7b4a,
0x7b52, 0x7b56, 0x7b64, 0x7b6b, 0x7b7c, 0x7b8e, 0x7b9f, 0x7bab,
0x7bb5, 0x7bc6, 0x7bd2, 0x7bda, 0x7bec, 0x7bfc, 0x7c0c, 0x7c1f,
0x7c2f, 0x7c40, 0x7c54, 0x7c65, 0x7c74, 0x7c87, 0x7c99, 0x7cab,
0x7cbe, 0x7cd0, 0x7ce1, 0x7ce8, 0x7cf3, 0x7cf8, 0x7d01, 0x7d08,
0x7d0e, 0x7d14, 0x7d1b, 0x7d20, 0x7d25, 0x7d2b, 0x7d31, 0x7d37,
0x7d3a, 0x7d3f, 0x7d44, 0x7d4c, 0x7d57, 0x7d60, 0x7d68, 0x7d6e,
0x7d7e, 0x7d8f, 0x7d9f, 0x7db1, 0x7dc3, 0x7dd3, 0x7de3, 0x7df4,
// Entry 2280 - 22BF
0x7e04, 0x7e16, 0x7e28, 0x7e38, 0x7e48, 0x7e58, 0x7e6a, 0x7e79,
0x7e89, 0x7e99, 0x7eab, 0x7eba, 0x7ec5, 0x7ed1, 0x7edc, 0x7eef,
0x7f05, 0x7f14, 0x7f26, 0x7f36, 0x7f47, 0x7f58, 0x7f72, 0x7f96,
0x7fba, 0x7fde, 0x8002, 0x8026, 0x804a, 0x806e, 0x8094, 0x80b4,
0x80c9, 0x80e8, 0x80fc, 0x810d, 0x8117, 0x8121, 0x812b, 0x8135,
0x813f, 0x8149, 0x8164, 0x817e, 0x819f, 0x81bf, 0x81d0, 0x81e0,
0x81f7, 0x820c, 0x8222, 0x8238, 0x8242, 0x824c, 0x825b, 0x8261,
0x826f, 0x8283, 0x8289, 0x8290, 0x8296, 0x829a, 0x82a9, 0x82b4,
// Entry 22C0 - 22FF
0x82c0, 0x82d3, 0x82ef, 0x830a, 0x8316, 0x8327, 0x833a, 0x834b,
0x836b, 0x837f, 0x8394, 0x83bd, 0x83db, 0x83fb, 0x840e, 0x8421,
0x843a, 0x8449, 0x8457, 0x8473, 0x8479, 0x8484, 0x848a, 0x848f,
0x8495, 0x8499, 0x849e, 0x84a4, 0x84b5, 0x84bc, 0x84c7, 0x84cf,
0x84dd, 0x84e8, 0x84f0, 0x84fb, 0x850d, 0x8520, 0x8532, 0x8545,
0x8559, 0x8569, 0x856d, 0x857a, 0x8590, 0x85a8, 0x85c0, 0x85d7,
0x85e5, 0x85f1, 0x85fa, 0x85fe, 0x8609, 0x8620, 0x8636, 0x863c,
0x8644, 0x8666, 0x8684, 0x86a2, 0x86b7, 0x86cc, 0x86db, 0x86fd,
// Entry 2300 - 233F
0x870e, 0x871d, 0x874d, 0x8758, 0x876f, 0x8786, 0x87a4, 0x87cf,
0x87d8, 0x87f9, 0x8819, 0x882b, 0x8840, 0x884d, 0x8853, 0x8859,
0x8866, 0x8876, 0x8887, 0x88a0, 0x88a8, 0x88ba, 0x88c2, 0x88ce,
0x88d3, 0x88db, 0x88ee, 0x88f3, 0x88fc, 0x890c, 0x8910, 0x8924,
0x893e, 0x8947, 0x895a, 0x8988, 0x899d, 0x89b1, 0x89bf, 0x89d3,
0x89e1, 0x89f7, 0x8a0e, 0x8a18, 0x8a20, 0x8a28, 0x8a33, 0x8a3e,
0x8a4a, 0x8a56, 0x8a68, 0x8a6e, 0x8a80, 0x8a89, 0x8a92, 0x8a9c,
0x8aac, 0x8abc, 0x8ad2, 0x8ada, 0x8ae8, 0x8afc, 0x8b0d, 0x8b1e,
// Entry 2340 - 237F
0x8b35, 0x8b40, 0x8b5a, 0x8b6e, 0x8b7b, 0x8b88, 0x8ba5, 0x8bc1,
0x8be3, 0x8bfc, 0x8c13, 0x8c2a, 0x8c32, 0x8c4c, 0x8c5e, 0x8c74,
0x8c8b, 0x8c9e, 0x8cb7, 0x8cc4, 0x8cd7, 0x8ce5, 0x8cf9, 0x8d0e,
0x8d26, 0x8d41, 0x8d57, 0x8d7b, 0x8da5, 0x8dbe, 0x8dd6, 0x8dee,
0x8e12, 0x8e30, 0x8e55, 0x8e63, 0x8e71, 0x8e97, 0x8ebd, 0x8ee4,
0x8eed, 0x8f07, 0x8f1e, 0x8f25, 0x8f32, 0x8f49, 0x8f71, 0x8f9f,
0x8fa9, 0x8fbe, 0x8fd9, 0x8fff, 0x9025, 0x9046, 0x9067, 0x9083,
0x909f, 0x90be, 0x90d9, 0x90f6, 0x9108, 0x911b, 0x912d, 0x915e,
// Entry 2380 - 23BF
0x9188, 0x91b9, 0x91e3, 0x9211, 0x923f, 0x9262, 0x9281, 0x92a6,
0x92b7, 0x92d7, 0x92e3, 0x92fe, 0x931e, 0x933f, 0x9369, 0x9394,
0x93bf, 0x93eb, 0x941c, 0x944e, 0x9478, 0x94a3, 0x94cd, 0x94f8,
0x951a, 0x953d, 0x955f, 0x9581, 0x95a5, 0x95c8, 0x95eb, 0x960d,
0x9631, 0x9655, 0x9678, 0x969b, 0x96bf, 0x96e3, 0x9709, 0x972e,
0x9753, 0x9777, 0x979d, 0x97c3, 0x97e8, 0x980d, 0x983a, 0x9867,
0x9896, 0x98c4, 0x98f2, 0x991f, 0x994e, 0x997d, 0x99ab, 0x99d9,
0x99fb, 0x9a0a, 0x9a1a, 0x9a2d, 0x9a43, 0x9a59, 0x9a6f, 0x9a8e,
// Entry 23C0 - 23FF
0x9ab1, 0x9ad1, 0x9af7, 0x9b1e, 0x9b4b, 0x9b61, 0x9b89, 0x9bb4,
0x9bce, 0x9bff, 0x9c2e, 0x9c4a, 0x9c76, 0x9c99, 0x9cbb, 0x9ce6,
0x9d12, 0x9d43, 0x9d74, 0x9da7, 0x9db1, 0x9de4, 0x9e08, 0x9e28,
0x9e48, 0x9e68, 0x9e88, 0x9eae, 0x9ed4, 0x9efa, 0x9f1a, 0x9f41,
0x9f5e, 0x9f81, 0x9f9f, 0x9fb0, 0x9fc7, 0x9ff5, 0xa002, 0xa00d,
0xa01a, 0xa035, 0xa051, 0xa063, 0xa083, 0xa09d, 0xa0c0, 0xa0dc,
0xa0e9, 0xa106, 0xa119, 0xa12b, 0xa149, 0xa155, 0xa16f, 0xa18a,
0xa1a4, 0xa1b3, 0xa1c3, 0xa1d2, 0xa1df, 0xa1ee, 0xa20d, 0xa220,
// Entry 2400 - 243F
0xa22d, 0xa23c, 0xa24a, 0xa263, 0xa285, 0xa2a0, 0xa2cf, 0xa2ff,
0xa31f, 0xa340, 0xa366, 0xa38d, 0xa3ac, 0xa3cc, 0xa3f2, 0xa419,
0xa447, 0xa476, 0xa49d, 0xa4c5, 0xa4dc, 0xa4f5, 0xa516, 0xa533,
0xa550, 0xa564, 0xa579, 0xa58e, 0xa5a9, 0xa5c5, 0xa5e1, 0xa5fe,
0xa61c, 0xa640, 0xa665, 0xa683, 0xa698, 0xa6ae, 0xa6c4, 0xa6db,
0xa6f1, 0xa708, 0xa71f, 0xa737, 0xa74d, 0xa764, 0xa77b, 0xa793,
0xa7aa, 0xa7c2, 0xa7da, 0xa7f3, 0xa809, 0xa820, 0xa837, 0xa84f,
0xa866, 0xa87e, 0xa896, 0xa8af, 0xa8c6, 0xa8de, 0xa8f6, 0xa90f,
// Entry 2440 - 247F
0xa927, 0xa940, 0xa959, 0xa973, 0xa989, 0xa9a0, 0xa9b7, 0xa9cf,
0xa9e6, 0xa9fe, 0xaa16, 0xaa2f, 0xaa46, 0xaa5e, 0xaa76, 0xaa8f,
0xaaa7, 0xaac0, 0xaad9, 0xaaf3, 0xab0a, 0xab22, 0xab3a, 0xab53,
0xab6b, 0xab84, 0xab9d, 0xabb7, 0xabcf, 0xabe8, 0xac01, 0xac1b,
0xac34, 0xac4e, 0xac68, 0xac83, 0xac99, 0xacb0, 0xacc7, 0xacdf,
0xacf6, 0xad0e, 0xad26, 0xad3f, 0xad56, 0xad6e, 0xad86, 0xad9f,
0xadb7, 0xadd0, 0xade9, 0xae03, 0xae1a, 0xae32, 0xae4a, 0xae63,
0xae7b, 0xae94, 0xaead, 0xaec7, 0xaedf, 0xaef8, 0xaf11, 0xaf2b,
// Entry 2480 - 24BF
0xaf44, 0xaf5e, 0xaf78, 0xaf93, 0xafaa, 0xafc2, 0xafda, 0xaff3,
0xb00b, 0xb024, 0xb03d, 0xb057, 0xb06f, 0xb088, 0xb0a1, 0xb0bb,
0xb0d4, 0xb0ee, 0xb108, 0xb123, 0xb13b, 0xb154, 0xb16d, 0xb187,
0xb1a0, 0xb1ba, 0xb1d4, 0xb1ef, 0xb208, 0xb222, 0xb23c, 0xb257,
0xb271, 0xb28c, 0xb2a7, 0xb2c3, 0xb2d9, 0xb2f0, 0xb307, 0xb31f,
0xb336, 0xb34e, 0xb366, 0xb37f, 0xb396, 0xb3ae, 0xb3c6, 0xb3df,
0xb3f7, 0xb410, 0xb429, 0xb443, 0xb45a, 0xb472, 0xb48a, 0xb4a3,
0xb4bb, 0xb4d4, 0xb4ed, 0xb507, 0xb51f, 0xb538, 0xb551, 0xb56b,
// Entry 24C0 - 24FF
0xb584, 0xb59e, 0xb5b8, 0xb5d3, 0xb5ea, 0xb602, 0xb61a, 0xb633,
0xb64b, 0xb664, 0xb67d, 0xb697, 0xb6af, 0xb6c8, 0xb6e1, 0xb6fb,
0xb714, 0xb72e, 0xb748, 0xb763, 0xb77b, 0xb794, 0xb7ad, 0xb7c7,
0xb7e0, 0xb7fa, 0xb814, 0xb82f, 0xb848, 0xb862, 0xb87c, 0xb897,
0xb8b1, 0xb8cc, 0xb8e7, 0xb903, 0xb91a, 0xb932, 0xb94a, 0xb963,
0xb97b, 0xb994, 0xb9ad, 0xb9c7, 0xb9df, 0xb9f8, 0xba11, 0xba2b,
0xba44, 0xba5e, 0xba78, 0xba93, 0xbaab, 0xbac4, 0xbadd, 0xbaf7,
0xbb10, 0xbb2a, 0xbb44, 0xbb5f, 0xbb78, 0xbb92, 0xbbac, 0xbbc7,
// Entry 2500 - 253F
0xbbe1, 0xbbfc, 0xbc17, 0xbc33, 0xbc4b, 0xbc64, 0xbc7d, 0xbc97,
0xbcb0, 0xbcca, 0xbce4, 0xbcff, 0xbd18, 0xbd32, 0xbd4c, 0xbd67,
0xbd81, 0xbd9c, 0xbdb7, 0xbdd3, 0xbdec, 0xbe06, 0xbe20, 0xbe3b,
0xbe55, 0xbe70, 0xbe8b, 0xbea7, 0xbec1, 0xbedc, 0xbef7, 0xbf13,
0xbf2e, 0xbf4a, 0xbf66, 0xbf83, 0xbfb3, 0xbfea, 0xc015, 0xc041,
0xc06d, 0xc091, 0xc0b0, 0xc0d0, 0xc0f6, 0xc11a, 0xc12e, 0xc144,
0xc15f, 0xc17b, 0xc196, 0xc1b2, 0xc1d9, 0xc1fa, 0xc20e, 0xc224,
0xc253, 0xc289, 0xc2ae, 0xc2e8, 0xc329, 0xc33d, 0xc352, 0xc36d,
// Entry 2540 - 257F
0xc389, 0xc3a9, 0xc3ca, 0xc3f3, 0xc41d, 0xc43c, 0xc45b, 0xc475,
0xc48f, 0xc4a9, 0xc4c3, 0xc4e8, 0xc50d, 0xc532, 0xc557, 0xc580,
0xc5a9, 0xc5d3, 0xc5fd, 0xc627, 0xc650, 0xc67a, 0xc6a4, 0xc6c6,
0xc6f4, 0xc724, 0xc753, 0xc783, 0xc7a1, 0xc7c2, 0xc7dd, 0xc7fb,
0xc81d, 0xc842, 0xc86a, 0xc895, 0xc8b6, 0xc8d3, 0xc8ff, 0xc92b,
0xc957, 0xc977, 0xc996, 0xc9b0, 0xc9d5, 0xc9ff, 0xca23, 0xca47,
0xca6b, 0xca8f, 0xcab1, 0xcad6, 0xcafc, 0xcb1f, 0xcb44, 0xcb6a,
0xcb90, 0xcbb8, 0xcbdf, 0xcc07, 0xcc2c, 0xcc53, 0xcc7a, 0xcca2,
// Entry 2580 - 25BF
0xccca, 0xccf4, 0xcd1d, 0xcd47, 0xcd6e, 0xcd97, 0xcddc, 0xce21,
0xce68, 0xceb1, 0xcef5, 0xcf3d, 0xcf81, 0xcfc9, 0xcff7, 0xd027,
0xd056, 0xd087, 0xd0ce, 0xd115, 0xd139, 0xd15b, 0xd180, 0xd1a4,
0xd1c9, 0xd1ef, 0xd20e, 0xd22f, 0xd252, 0xd26f, 0xd28d, 0xd2ab,
0xd2b9, 0xd2c8, 0xd2d4, 0xd2e2, 0xd2ff, 0xd30e, 0xd323, 0xd33b,
0xd354, 0xd36a, 0xd381, 0xd39e, 0xd3bc, 0xd3db, 0xd3fb, 0xd41c,
0xd43e, 0xd469, 0xd498, 0xd4c6, 0xd4f2, 0xd50d, 0xd529, 0xd543,
0xd561, 0xd585, 0xd5a7, 0xd5c8, 0xd5ea, 0xd5f6, 0xd60a, 0xd625,
// Entry 25C0 - 25FF
0xd644, 0xd661, 0xd674, 0xd67f, 0xd69b, 0xd6b5, 0xd6c1, 0xd6cf,
0xd6e2, 0xd6fe, 0xd716, 0xd730, 0xd772, 0xd7b3, 0xd7f7, 0xd83a,
0xd87c, 0xd8bd, 0xd901, 0xd944, 0xd956, 0xd96c, 0xd98d, 0xd9ad,
0xd9cc, 0xd9e6, 0xd9fa, 0xda0a, 0xda21, 0xda36, 0xda7b, 0xda95,
0xdac0, 0xdad7, 0xdaeb, 0xdaf9, 0xdb0a, 0xdb1e, 0xdb43, 0xdb72,
0xdb8f, 0xdbad, 0xdbbd, 0xdbd1, 0xdbdf, 0xdbf1, 0xdc08, 0xdc1e,
0xdc2b, 0xdc49, 0xdc6b, 0xdc8c, 0xdcae, 0xdcc9, 0xdce5, 0xdcf1,
0xdd0b, 0xdd26, 0xdd35, 0xdd44, 0xdd55, 0xdd67, 0xdd7f, 0xdd98,
// Entry 2600 - 263F
0xddab, 0xddbc, 0xddde, 0xddf3, 0xde10, 0xde1c, 0xde2b, 0xde4b,
0xde7c, 0xde9d, 0xdea9, 0xdeb6, 0xdee1, 0xdf0d, 0xdf2a, 0xdf37,
0xdf53, 0xdf6f, 0xdf88, 0xdfa1, 0xdfbb, 0xdfd5, 0xdfee, 0xe007,
0xe013, 0xe02b, 0xe03f, 0xe065, 0xe070, 0xe083, 0xe08e, 0xe099,
0xe0bb, 0xe0de, 0xe0e2, 0xe0e6, 0xe100, 0xe11b, 0xe137, 0xe154,
0xe172, 0xe194, 0xe1af, 0xe1c7, 0xe1de, 0xe1f2, 0xe200, 0xe217,
0xe232, 0xe246, 0xe261, 0xe27c, 0xe290, 0xe2a9, 0xe2db, 0xe30e,
0xe335, 0xe355, 0xe371, 0xe398, 0xe3b0, 0xe3ca, 0xe3dd, 0xe3f2,
// Entry 2640 - 267F
0xe408, 0xe40c, 0xe428, 0xe445, 0xe45d, 0xe479, 0xe49a, 0xe4c0,
0xe4da, 0xe4f2, 0xe50c, 0xe528, 0xe545, 0xe560, 0xe579, 0xe595,
0xe5b0, 0xe5cd, 0xe5eb, 0xe602, 0xe624, 0xe645, 0xe66a, 0xe677,
0xe69e, 0xe6c6, 0xe6f8, 0xe71c, 0xe731, 0xe746, 0xe75c, 0xe77b,
0xe78b, 0xe7a5, 0xe7c6, 0xe7df, 0xe7f4, 0xe809, 0xe81b, 0xe834,
0xe851, 0xe866, 0xe87e, 0xe896, 0xe8b8, 0xe8da, 0xe8fc, 0xe92c,
0xe944, 0xe963, 0xe97d, 0xe990, 0xe9ba, 0xe9d4, 0xe9ed, 0xe9ff,
0xea10, 0xea2c, 0xea47, 0xea57, 0xea68, 0xea8a, 0xeaa6, 0xeac1,
// Entry 2680 - 26BF
0xeae1, 0xeb00, 0xeb1f, 0xeb38, 0xeb58, 0xeb6f, 0xeb8d, 0xebac,
0xebcd, 0xebed, 0xec07, 0xec1f, 0xec50, 0xec81, 0xec9e, 0xecbd,
0xecd2, 0xecea, 0xecfe, 0xed24, 0xed43, 0xed5e, 0xed79, 0xed99,
0xedab, 0xedc7, 0xede5, 0xee17, 0xee36, 0xee52, 0xee71, 0xee93,
0xeeb8, 0xeed5, 0xeef5, 0xef22, 0xef52, 0xef7e, 0xefad, 0xefdf,
0xf013, 0xf02b, 0xf046, 0xf06c, 0xf095, 0xf0b2, 0xf0d2, 0xf106,
0xf13a, 0xf15a, 0xf17d, 0xf1a7, 0xf1d1, 0xf205, 0xf239, 0xf27d,
0xf2c1, 0xf2de, 0xf2fe, 0xf32b, 0xf35b, 0xf37c, 0xf3a0, 0xf3c9,
// Entry 26C0 - 26FF
0xf3f5, 0xf409, 0xf420, 0xf449, 0xf475, 0xf48c, 0xf4a6, 0xf4cb,
0xf4ed, 0xf50a, 0xf523, 0xf53f, 0xf56c, 0xf59c, 0xf5a8, 0xf5b3,
0xf5cb, 0xf5e2, 0xf5fe, 0xf624, 0xf64a, 0xf671, 0xf698, 0xf6b2,
0xf6cc, 0xf6e7, 0xf702, 0xf720, 0xf73e, 0xf760, 0xf782, 0xf791,
0xf7a0, 0xf7af, 0xf7c0, 0xf7db, 0xf7f8, 0xf81d, 0xf844, 0xf868,
0xf88e, 0xf8a9, 0xf8c6, 0xf8e4, 0xf904, 0xf923, 0xf944, 0xf960,
0xf97e, 0xf99b, 0xf9b9, 0xf9c6, 0xf9d5, 0xf9ee, 0xfa09, 0xfa1e,
0xfa33, 0xfa46, 0xfa5d, 0xfa73, 0xfaa1, 0xfabd, 0xfad3, 0xfaeb,
// Entry 2700 - 273F
0xfaf2, 0xfafc, 0xfb0b, 0xfb1a, 0xfb27, 0xfb3b, 0xfb5e, 0xfb80,
0xfba2, 0xfbcb, 0xfbf8, 0xfc14, 0xfc2f, 0xfc52, 0xfc62, 0xfc70,
0xfc86, 0xfca5, 0xfcd1, 0xfcf0, 0xfd0f, 0xfd2a, 0xfd49, 0xfd65,
0xfd88, 0xfdb2, 0xfdc7, 0xfdde, 0xfdf8, 0xfe21, 0xfe4d, 0xfe6b,
0xfe8d, 0xfea4, 0xfeb6, 0xfece, 0xfee4, 0xfefa, 0xff10, 0xff26,
0xff3c, 0xff51, 0xff64, 0xff79, 0xff8f, 0xffa5, 0xffbb, 0xffd1,
0xffe7, 0xfffa, 0x001d, 0x003e, 0x0060, 0x0080, 0x009a, 0x00b7,
0x00e2, 0x010c, 0x0128, 0x0145, 0x0160, 0x017e, 0x018b, 0x019d,
// Entry 2740 - 277F
0x01af, 0x01c6, 0x01dd, 0x01eb, 0x01f9, 0x0206, 0x0213, 0x022b,
0x023d, 0x0251, 0x0265, 0x0279, 0x028d, 0x02a0, 0x02b3, 0x02c6,
0x02de, 0x02f6, 0x030c, 0x0322, 0x033e, 0x0354, 0x0370, 0x038d,
0x03bc, 0x03f2, 0x0415, 0x043b, 0x045b, 0x0489, 0x04be, 0x04e2,
0x051b, 0x055b, 0x0574, 0x0595, 0x05b6, 0x05e2, 0x060f, 0x0634,
0x0655, 0x066e, 0x0688, 0x06b5, 0x06e3, 0x0707, 0x072c, 0x0758,
0x0785, 0x07ab, 0x07c4, 0x07e1, 0x07f2, 0x0802, 0x0812, 0x082f,
0x084c, 0x085e, 0x0879, 0x0898, 0x08a4, 0x08b9, 0x08dd, 0x0905,
// Entry 2780 - 27BF
0x092d, 0x0959, 0x0986, 0x09b9, 0x09d8, 0x09f5, 0x0a15, 0x0a34,
0x0a54, 0x0a71, 0x0a91, 0x0ab1, 0x0ad1, 0x0af1, 0x0b17, 0x0b3b,
0x0b62, 0x0b88, 0x0bb3, 0x0be2, 0x0c08, 0x0c2c, 0x0c53, 0x0c79,
0x0ca0, 0x0cc7, 0x0cee, 0x0d15, 0x0d52, 0x0d8d, 0x0dcb, 0x0e08,
0x0e1a, 0x0e2a, 0x0e6f, 0x0eb9, 0x0efe, 0x0f48, 0x0f6f, 0x0f94,
0x0fbc, 0x0fe3, 0x1006, 0x1027, 0x104b, 0x106e, 0x10a0, 0x10d3,
0x1104, 0x1134, 0x113f, 0x114b, 0x1157, 0x1164, 0x118d, 0x11a3,
0x11c0, 0x11f3, 0x1226, 0x125a, 0x128e, 0x12b3, 0x12d6, 0x12fc,
// Entry 27C0 - 27FF
0x1321, 0x1358, 0x1390, 0x13c5, 0x13fb, 0x1430, 0x1466, 0x149d,
0x14d5, 0x14ff, 0x152a, 0x1552, 0x157b, 0x15a3, 0x15cc, 0x15f6,
0x1621, 0x1637, 0x164e, 0x1662, 0x1677, 0x168b, 0x16a0, 0x16b6,
0x16cd, 0x16fd, 0x171c, 0x1735, 0x1758, 0x1771, 0x1788, 0x1791,
0x179f, 0x17b3, 0x17c8, 0x17dd, 0x17f5, 0x1802, 0x182b, 0x1856,
0x1881, 0x18ad, 0x18bd, 0x18d2, 0x18ea, 0x1907, 0x192c, 0x1943,
0x1962, 0x197b, 0x198b, 0x1995, 0x19a3, 0x19b3, 0x19c2, 0x19d1,
0x19db, 0x19e5, 0x19ec, 0x19f2, 0x19f8, 0x19fe, 0x1a0f, 0x1a25,
// Entry 2800 - 283F
0x1a39, 0x1a3f, 0x1a44, 0x1a48, 0x1a4e, 0x1a55, 0x1a5c, 0x1a64,
0x1a6c, 0x1a80, 0x1a95, 0x1aae, 0x1ac8, 0x1afb, 0x1b2c, 0x1b60,
0x1b93, 0x1ba0, 0x1bad, 0x1bb2, 0x1bd7, 0x1bf9, 0x1c1d, 0x1c41,
0x1c65, 0x1c8a, 0x1ca9, 0x1cb6, 0x1cc6, 0x1cd4, 0x1ce1, 0x1cf5,
0x1d0f, 0x1d2c, 0x1d4a, 0x1d68, 0x1d89, 0x1da8, 0x1dc7, 0x1de8,
0x1e07, 0x1e27, 0x1e45, 0x1e6b, 0x1e86, 0x1ea6, 0x1ec4, 0x1ee5,
0x1f06, 0x1f25, 0x1f42, 0x1f62, 0x1f81, 0x1fa0, 0x1fc0, 0x1fdd,
0x1ffc, 0x201a, 0x2037, 0x2053, 0x2071, 0x208e, 0x20ae, 0x20cb,
// Entry 2840 - 287F
0x20e9, 0x2107, 0x2125, 0x2149, 0x2165, 0x2188, 0x21b5, 0x21d1,
0x21fc, 0x221d, 0x2246, 0x2264, 0x2285, 0x22a6, 0x22cc, 0x22f6,
0x231e, 0x2339, 0x2355, 0x2371, 0x2390, 0x23ad, 0x23ca, 0x23e9,
0x2406, 0x2424, 0x2440, 0x2464, 0x247d, 0x249b, 0x24b7, 0x24d6,
0x24f5, 0x2512, 0x252d, 0x254b, 0x2568, 0x2585, 0x25a3, 0x25be,
0x25db, 0x25f7, 0x2612, 0x262c, 0x2648, 0x2663, 0x2681, 0x269c,
0x26b8, 0x26d4, 0x26f0, 0x2712, 0x272c, 0x274d, 0x2778, 0x2792,
0x27bb, 0x27da, 0x2801, 0x281d, 0x283c, 0x285b, 0x287f, 0x28a7,
// Entry 2880 - 28BF
0x28cd, 0x28f3, 0x2917, 0x293f, 0x2961, 0x2981, 0x29a1, 0x29ca,
0x29ef, 0x2a12, 0x2a37, 0x2a5a, 0x2a7f, 0x2aa2, 0x2abc, 0x2adc,
0x2af9, 0x2b1a, 0x2b3e, 0x2b5e, 0x2b7c, 0x2b9a, 0x2bb5, 0x2bce,
0x2bed, 0x2c0c, 0x2c31, 0x2c5a, 0x2c7d, 0x2c9b, 0x2cb4, 0x2cda,
0x2d00, 0x2d1a, 0x2d32, 0x2d4c, 0x2d64, 0x2d7f, 0x2d98, 0x2db3,
0x2dcc, 0x2de5, 0x2dfc, 0x2e15, 0x2e2c, 0x2e46, 0x2e5e, 0x2e78,
0x2e90, 0x2eac, 0x2ec6, 0x2ee1, 0x2efa, 0x2f14, 0x2f2c, 0x2f47,
0x2f60, 0x2f78, 0x2f8e, 0x2fa6, 0x2fbc, 0x2fd5, 0x2fec, 0x3003,
// Entry 28C0 - 28FF
0x3018, 0x3030, 0x3046, 0x305e, 0x3074, 0x308e, 0x30a6, 0x30bf,
0x30d6, 0x30ee, 0x3104, 0x311c, 0x3132, 0x314b, 0x3162, 0x317b,
0x3192, 0x31ab, 0x31c2, 0x31e6, 0x3208, 0x322c, 0x324e, 0x3275,
0x329a, 0x32be, 0x32e0, 0x3302, 0x3322, 0x3348, 0x336c, 0x3390,
0x33b2, 0x33cd, 0x33e6, 0x3408, 0x3428, 0x344d, 0x3470, 0x3494,
0x34b6, 0x34d9, 0x34fa, 0x351e, 0x3540, 0x3565, 0x3588, 0x35ab,
0x35cc, 0x35ed, 0x360c, 0x3630, 0x3652, 0x3676, 0x3698, 0x36bf,
0x36e4, 0x3708, 0x372a, 0x3750, 0x3774, 0x379a, 0x37be, 0x37e2,
// Entry 2900 - 293F
0x3804, 0x3828, 0x384a, 0x386e, 0x3890, 0x38a1, 0x38b4, 0x38c7,
0x38dc, 0x38f0, 0x3904, 0x391c, 0x3944, 0x396a, 0x3994, 0x39bc,
0x39d5, 0x39f4, 0x3a13, 0x3a36, 0x3a57, 0x3a72, 0x3a98, 0x3ac0,
0x3adf, 0x3af7, 0x3b07, 0x3b23, 0x3b3b, 0x3b54, 0x3b6d, 0x3b86,
0x3b9e, 0x3bb7, 0x3bd0, 0x3be9, 0x3c01, 0x3c1a, 0x3c33, 0x3c4c,
0x3c65, 0x3c7d, 0x3c96, 0x3cb0, 0x3cc9, 0x3ce2, 0x3cfb, 0x3d13,
0x3d2d, 0x3d47, 0x3d61, 0x3d7a, 0x3d94, 0x3dae, 0x3dc7, 0x3de0,
0x3df9, 0x3e13, 0x3e2c, 0x3e46, 0x3e5f, 0x3e77, 0x3e90, 0x3ea8,
// Entry 2940 - 297F
0x3ec1, 0x3eda, 0x3ef2, 0x3f0b, 0x3f1d, 0x3f30, 0x3f44, 0x3f57,
0x3f6c, 0x3f8e, 0x3fa1, 0x3fb4, 0x3fc8, 0x3fdc, 0x3ff1, 0x4004,
0x4017, 0x402a, 0x4044, 0x4059, 0x406c, 0x408e, 0x40a8, 0x40bc,
0x40cf, 0x40e3, 0x40fe, 0x4111, 0x412b, 0x413d, 0x4151, 0x416d,
0x4188, 0x419b, 0x41ae, 0x41c1, 0x41dc, 0x41f7, 0x420a, 0x421c,
0x422f, 0x4243, 0x4257, 0x4272, 0x428b, 0x429e, 0x42b2, 0x42c6,
0x42d9, 0x42ed, 0x4301, 0x4315, 0x4328, 0x433b, 0x434e, 0x4361,
0x437f, 0x4393, 0x43a5, 0x43b7, 0x43e2, 0x43f9, 0x4412, 0x4427,
// Entry 2980 - 29BF
0x443c, 0x4451, 0x4466, 0x447c, 0x4491, 0x44a6, 0x44bb, 0x44d0,
0x44e6, 0x4502, 0x4517, 0x452c, 0x4542, 0x4557, 0x456d, 0x4583,
0x4599, 0x45ae, 0x45c4, 0x45da, 0x45f1, 0x4607, 0x461c, 0x4631,
0x4646, 0x465c, 0x4672, 0x4687, 0x469c, 0x46b1, 0x46c6, 0x46db,
0x46f1, 0x4707, 0x471c, 0x4731, 0x4746, 0x475b, 0x4770, 0x4786,
0x479c, 0x47b1, 0x47c6, 0x47dc, 0x47f2, 0x4808, 0x481f, 0x4836,
0x484c, 0x4862, 0x4877, 0x488c, 0x48a1, 0x48b7, 0x48cd, 0x48e2,
0x48f7, 0x490c, 0x4921, 0x4936, 0x494c, 0x4962, 0x4977, 0x498c,
// Entry 29C0 - 29FF
0x49a1, 0x49b6, 0x49cb, 0x49e1, 0x49f7, 0x4a0c, 0x4a21, 0x4a36,
0x4a4b, 0x4a60, 0x4a76, 0x4a8c, 0x4aa1, 0x4ab6, 0x4ad2, 0x4aee,
0x4b0b, 0x4b27, 0x4b44, 0x4b60, 0x4b7c, 0x4b98, 0x4bb4, 0x4bd0,
0x4beb, 0x4c07, 0x4c23, 0x4c3f, 0x4c5b, 0x4c77, 0x4c94, 0x4cb1,
0x4cce, 0x4ced, 0x4d0b, 0x4d2a, 0x4d45, 0x4d61, 0x4d80, 0x4da6,
0x4dc3, 0x4ddf, 0x4e03, 0x4e27, 0x4e48, 0x4e72, 0x4e91, 0x4eb7,
0x4ed0, 0x4eea, 0x4f0a, 0x4f2b, 0x4f46, 0x4f68, 0x4f83, 0x4f9d,
0x4fb8, 0x4fc5, 0x4fe1, 0x4ffe, 0x500f, 0x501a, 0x502c, 0x5047,
// Entry 2A00 - 2A3F
0x5053, 0x5060, 0x5070, 0x507e, 0x5099, 0x50ae, 0x50c2, 0x50cd,
0x50e2, 0x50f7, 0x5112, 0x512e, 0x5142, 0x5156, 0x5172, 0x518f,
0x51a4, 0x51ba, 0x51d2, 0x51eb, 0x5202, 0x521a, 0x5231, 0x5249,
0x526a, 0x528b, 0x52a7, 0x52b4, 0x52ca, 0x52d8, 0x52e2, 0x52fb,
0x5307, 0x5311, 0x531d, 0x532d, 0x5343, 0x535a, 0x5367, 0x537c,
0x5387, 0x5394, 0x53aa, 0x53bb, 0x53cf, 0x53d8, 0x53e5, 0x53f3,
0x5417, 0x542c, 0x5442, 0x5455, 0x547a, 0x5484, 0x5497, 0x54ab,
0x54b9, 0x54c6, 0x54d4, 0x54e4, 0x54f9, 0x550e, 0x552d, 0x554b,
// Entry 2A40 - 2A7F
0x5563, 0x557c, 0x5592, 0x55b1, 0x55d1, 0x55f7, 0x561e, 0x5637,
0x5651, 0x566d, 0x568a, 0x5698, 0x56aa, 0x56bb, 0x56d1, 0x56e7,
0x56ff, 0x5711, 0x5720, 0x5731, 0x5746, 0x575b, 0x5771, 0x5781,
0x5796, 0x57ab, 0x57bf, 0x57d3, 0x57e9, 0x57fe, 0x580f, 0x5821,
0x5836, 0x584b, 0x5860, 0x5875, 0x5885, 0x5894, 0x58a5, 0x58b4,
0x58c4, 0x58d5, 0x58e7, 0x58fb, 0x5910, 0x5925, 0x5935, 0x5948,
0x595b, 0x5981, 0x5990, 0x599f, 0x59af, 0x59c8, 0x59d7, 0x59ed,
0x5a03, 0x5a15, 0x5a25, 0x5a42, 0x5a55, 0x5a68, 0x5a7d, 0x5a91,
// Entry 2A80 - 2ABF
0x5aa1, 0x5ab2, 0x5ac1, 0x5ad0, 0x5adf, 0x5af4, 0x5b09, 0x5b19,
0x5b2b, 0x5b40, 0x5b55, 0x5b6c, 0x5b7d, 0x5b90, 0x5ba4, 0x5bb8,
0x5bd4, 0x5bef, 0x5bff, 0x5c1e, 0x5c3c, 0x5c4c, 0x5c69, 0x5c84,
0x5c98, 0x5cac, 0x5cbc, 0x5cd9, 0x5ced, 0x5d01, 0x5d1e, 0x5d3b,
0x5d50, 0x5d65, 0x5d75, 0x5d85, 0x5dac, 0x5dc9, 0x5de6, 0x5e02,
0x5e15, 0x5e28, 0x5e3d, 0x5e59, 0x5e69, 0x5e87, 0x5e97, 0x5ea8,
0x5ec5, 0x5ee2, 0x5eff, 0x5f1b, 0x5f38, 0x5f55, 0x5f72, 0x5f8f,
0x5fad, 0x5fcb, 0x5fea, 0x6009, 0x601b, 0x603a, 0x6059, 0x606b,
// Entry 2AC0 - 2AFF
0x607e, 0x6090, 0x60a4, 0x60b9, 0x60cc, 0x60de, 0x60f0, 0x6102,
0x6115, 0x6129, 0x613d, 0x6154, 0x6168, 0x617a, 0x618e, 0x61a5,
0x61b9, 0x61cd, 0x61e0, 0x61f4, 0x6211, 0x6230, 0x6242, 0x625b,
0x626e, 0x6282, 0x6298, 0x62ac, 0x62c0, 0x62d8, 0x62ec, 0x6302,
0x6313, 0x632b, 0x6341, 0x6353, 0x6367, 0x637b, 0x638e, 0x63a1,
0x63b5, 0x63c8, 0x63dd, 0x63f2, 0x6409, 0x641d, 0x6430, 0x6446,
0x645b, 0x646d, 0x6488, 0x64a3, 0x64bd, 0x64d5, 0x64e9, 0x64fb,
0x650f, 0x6525, 0x6538, 0x654c, 0x6562, 0x6575, 0x6588, 0x659d,
// Entry 2B00 - 2B3F
0x65af, 0x65c4, 0x65d9, 0x65eb, 0x6600, 0x6612, 0x6624, 0x6636,
0x6649, 0x665c, 0x666f, 0x6682, 0x6696, 0x66ab, 0x66c0, 0x66d6,
0x66e8, 0x66fb, 0x670f, 0x6723, 0x6736, 0x6749, 0x675e, 0x6775,
0x6793, 0x67a7, 0x67ba, 0x67cc, 0x67de, 0x67f5, 0x6808, 0x681c,
0x682f, 0x6843, 0x6856, 0x6868, 0x687c, 0x6898, 0x68af, 0x68c9,
0x68dd, 0x68f0, 0x6903, 0x6915, 0x6929, 0x693d, 0x6951, 0x6966,
0x697a, 0x698e, 0x69a1, 0x69b5, 0x69ca, 0x69dd, 0x69f0, 0x6a02,
0x6a14, 0x6a28, 0x6a3e, 0x6a50, 0x6a62, 0x6a75, 0x6a87, 0x6a9b,
// Entry 2B40 - 2B7F
0x6aae, 0x6ac5, 0x6ad8, 0x6aed, 0x6b02, 0x6b17, 0x6b2c, 0x6b3f,
0x6b56, 0x6b6a, 0x6b7e, 0x6b92, 0x6ba7, 0x6bbb, 0x6bd8, 0x6bee,
0x6c01, 0x6c13, 0x6c26, 0x6c3b, 0x6c50, 0x6c63, 0x6c75, 0x6c8a,
0x6c9e, 0x6cb0, 0x6cc2, 0x6cd5, 0x6ce8, 0x6cfb, 0x6d10, 0x6d26,
0x6d39, 0x6d4c, 0x6d5f, 0x6d79, 0x6d8f, 0x6da2, 0x6db5, 0x6dc8,
0x6ddc, 0x6df0, 0x6e10, 0x6e23, 0x6e36, 0x6e4a, 0x6e5d, 0x6e73,
0x6e90, 0x6ea3, 0x6eb7, 0x6eca, 0x6edd, 0x6eef, 0x6f01, 0x6f14,
0x6f2b, 0x6f3f, 0x6f52, 0x6f65, 0x6f78, 0x6f8c, 0x6fab, 0x6fc2,
// Entry 2B80 - 2BBF
0x6fd6, 0x6fe9, 0x6ffc, 0x700f, 0x7022, 0x7036, 0x7049, 0x705e,
0x7073, 0x7087, 0x70a0, 0x70b3, 0x70c8, 0x70db, 0x70ed, 0x7100,
0x7113, 0x7127, 0x713c, 0x7151, 0x7165, 0x7194, 0x71c4, 0x71fe,
0x7239, 0x7268, 0x729d, 0x72d2, 0x7306, 0x7340, 0x737b, 0x73b5,
0x73df, 0x73f0, 0x7401, 0x7416, 0x7420, 0x7443, 0x745d, 0x7475,
0x748c, 0x749e, 0x74b1, 0x74ca, 0x74e4, 0x74f7, 0x750b, 0x7524,
0x753e, 0x755b, 0x7579, 0x7584, 0x758d, 0x75a8, 0x75c4, 0x75e1,
0x75ff, 0x7620, 0x7642, 0x765b, 0x7675, 0x767e, 0x76a2, 0x76bd,
// Entry 2BC0 - 2BFF
0x76dc, 0x76ec, 0x7700, 0x7714, 0x772a, 0x773f, 0x7754, 0x7768,
0x777e, 0x7794, 0x77a9, 0x77c4, 0x77e0, 0x77ff, 0x781d, 0x7838,
0x7853, 0x785c, 0x7875, 0x78a0, 0x78c4, 0x78fa, 0x791e, 0x7931,
0x7961, 0x7975, 0x798c, 0x79a3, 0x79c6, 0x79cf, 0x79e4, 0x7a03,
0x7a1e, 0x7a35, 0x7a46, 0x7a5d, 0x7a6e, 0x7a85, 0x7a96, 0x7aad,
0x7abe, 0x7ad5, 0x7ae6, 0x7af8, 0x7b0a, 0x7b1c, 0x7b2e, 0x7b40,
0x7b52, 0x7b64, 0x7b76, 0x7b88, 0x7b9a, 0x7bac, 0x7bbe, 0x7bd0,
0x7be2, 0x7bf4, 0x7c06, 0x7c18, 0x7c2a, 0x7c3c, 0x7c4e, 0x7c60,
// Entry 2C00 - 2C3F
0x7c72, 0x7c84, 0x7c96, 0x7cae, 0x7cc0, 0x7cd2, 0x7ce4, 0x7cf6,
0x7d08, 0x7d1a, 0x7d2c, 0x7d3e, 0x7d50, 0x7d62, 0x7d74, 0x7d86,
0x7d98, 0x7daa, 0x7dbc, 0x7dce, 0x7de0, 0x7df2, 0x7e04, 0x7e16,
0x7e28, 0x7e3a, 0x7e4c, 0x7e5e, 0x7e70, 0x7e82, 0x7e94, 0x7ea6,
0x7eb8, 0x7eca, 0x7edc, 0x7ef4, 0x7f06, 0x7f1e, 0x7f30, 0x7f48,
0x7f5a, 0x7f6c, 0x7f7e, 0x7f90, 0x7fa2, 0x7fb4, 0x7fcc, 0x7fde,
0x7ff0, 0x8002, 0x8014, 0x8025, 0x8037, 0x804f, 0x8067, 0x8094,
0x80c6, 0x80e9, 0x8111, 0x8128, 0x8146, 0x815b, 0x817a, 0x8191,
// Entry 2C40 - 2C7F
0x81a2, 0x81b9, 0x81ca, 0x81e1, 0x81f2, 0x8209, 0x821a, 0x8231,
0x8242, 0x8254, 0x8266, 0x8278, 0x828a, 0x829c, 0x82ae, 0x82c0,
0x82d2, 0x82e4, 0x82f6, 0x8308, 0x831a, 0x832c, 0x833e, 0x8350,
0x8362, 0x8374, 0x8386, 0x8398, 0x83aa, 0x83bc, 0x83ce, 0x83e0,
0x83f2, 0x840a, 0x841c, 0x842e, 0x8440, 0x8452, 0x8464, 0x8476,
0x8488, 0x849a, 0x84ac, 0x84be, 0x84d0, 0x84e2, 0x84f4, 0x8506,
0x8518, 0x852a, 0x853c, 0x854e, 0x8560, 0x8572, 0x8584, 0x8596,
0x85a8, 0x85ba, 0x85cc, 0x85de, 0x85f0, 0x8602, 0x8614, 0x8626,
// Entry 2C80 - 2CBF
0x8638, 0x8650, 0x8662, 0x867a, 0x868c, 0x86a4, 0x86b6, 0x86c8,
0x86da, 0x86ec, 0x86fe, 0x8710, 0x8728, 0x873a, 0x874c, 0x875e,
0x8770, 0x8781, 0x8793, 0x87ab, 0x87c3, 0x87d5, 0x87e7, 0x87f9,
0x880b, 0x881e, 0x8844, 0x885b, 0x8879, 0x888e, 0x889f, 0x88b0,
0x88c1, 0x88d2, 0x88e3, 0x88f4, 0x8905, 0x8916, 0x8927, 0x8938,
0x8949, 0x895a, 0x896b, 0x897c, 0x898e, 0x89a0, 0x89b2, 0x89c3,
0x89d4, 0x89e5, 0x89f6, 0x8a07, 0x8a18, 0x8a29, 0x8a3b, 0x8a4d,
0x8a5f, 0x8a71, 0x8a83, 0x8a95, 0x8aa7, 0x8aba, 0x8acd, 0x8adf,
// Entry 2CC0 - 2CFF
0x8af0, 0x8b01, 0x8b13, 0x8b24, 0x8b36, 0x8b48, 0x8b5a, 0x8b7a,
0x8b8c, 0x8ba0, 0x8bb9, 0x8bd2, 0x8be5, 0x8bfe, 0x8c17, 0x8c2b,
0x8c44, 0x8c57, 0x8c71, 0x8c8a, 0x8ca3, 0x8cbb, 0x8cd6, 0x8cf1,
0x8d0a, 0x8d1d, 0x8d30, 0x8d48, 0x8d60, 0x8d72, 0x8d89, 0x8d9c,
0x8daf, 0x8dc7, 0x8ddc, 0x8df1, 0x8e06, 0x8e1b, 0x8e2e, 0x8e3d,
0x8e4d, 0x8e5d, 0x8e6e, 0x8e7e, 0x8e8d, 0x8e9e, 0x8eae, 0x8ebd,
0x8ecd, 0x8ede, 0x8eee, 0x8efe, 0x8f0d, 0x8f1e, 0x8f2e, 0x8f3e,
0x8f4e, 0x8f5e, 0x8f6e, 0x8f7d, 0x8f8a, 0x8fa2, 0x8fbc, 0x8fd4,
// Entry 2D00 - 2D3F
0x8fef, 0x900e, 0x9028, 0x9046, 0x9061, 0x9080, 0x9099, 0x90b1,
0x90cc, 0x90e7, 0x9101, 0x911b, 0x913a, 0x9159, 0x9172, 0x918d,
0x91a8, 0x91c8, 0x91e1, 0x91f9, 0x9212, 0x922a, 0x9242, 0x9257,
0x926f, 0x9285, 0x92a0, 0x92be, 0x92db, 0x92f3, 0x930c, 0x931f,
0x9333, 0x9345, 0x9359, 0x936c, 0x937e, 0x9391, 0x93a5, 0x93c8,
0x93eb, 0x940a, 0x9429, 0x944a, 0x946a, 0x9489, 0x94ab, 0x94cd,
0x94ee, 0x9510, 0x9531, 0x9553, 0x9575, 0x9596, 0x95b5, 0x95c7,
0x95d9, 0x95eb, 0x95fd, 0x960f, 0x9622, 0x9634, 0x9647, 0x9659,
// Entry 2D40 - 2D7F
0x966c, 0x967f, 0x9692, 0x96a4, 0x96b7, 0x96cb, 0x96df, 0x96f1,
0x9703, 0x9716, 0x972a, 0x9741, 0x9758, 0x976f, 0x9786, 0x9798,
0x97aa, 0x97bc, 0x97d3, 0x97e5, 0x97f7, 0x9809, 0x981b, 0x9827,
0x9834, 0x9841, 0x984f, 0x985c, 0x986a, 0x9878, 0x9885, 0x9894,
0x98a3, 0x98b1, 0x98c0, 0x98cf, 0x98dd, 0x98ec, 0x98f8, 0x9904,
0x9910, 0x991c, 0x9929, 0x9935, 0x9942, 0x994f, 0x995c, 0x996a,
0x9977, 0x9984, 0x9991, 0x999e, 0x99ab, 0x99b9, 0x99c7, 0x99d6,
0x99e6, 0x99f3, 0x99ff, 0x9a17, 0x9a2f, 0x9a47, 0x9a5f, 0x9a77,
// Entry 2D80 - 2DBF
0x9a8f, 0x9aa7, 0x9abf, 0x9ad7, 0x9aef, 0x9b07, 0x9b1f, 0x9b37,
0x9b4f, 0x9b67, 0x9b7f, 0x9b9a, 0x9bb4, 0x9bcf, 0x9be9, 0x9c03,
0x9c1d, 0x9c36, 0x9c50, 0x9c6a, 0x9c86, 0x9ca2, 0x9cbe, 0x9cda,
0x9cf4, 0x9d11, 0x9d2d, 0x9d4a, 0x9d66, 0x9d82, 0x9d9e, 0x9db9,
0x9dd5, 0x9df1, 0x9e0f, 0x9e2d, 0x9e4b, 0x9e69, 0x9e85, 0x9ea1,
0x9ec5, 0x9ee8, 0x9f03, 0x9f1e, 0x9f3b, 0x9f57, 0x9f73, 0x9f8e,
0x9fab, 0x9fc8, 0x9fe4, 0x9fff, 0xa01b, 0xa037, 0xa054, 0xa070,
0xa08d, 0xa0aa, 0xa0c5, 0xa0e2, 0xa0fe, 0xa11d, 0xa139, 0xa158,
// Entry 2DC0 - 2DFF
0xa179, 0xa19f, 0xa1bc, 0xa1dd, 0xa1f9, 0xa216, 0xa237, 0xa259,
0xa279, 0xa299, 0xa2b9, 0xa2d5, 0xa2f1, 0xa30e, 0xa328, 0xa346,
0xa35e, 0xa374, 0xa396, 0xa3bb, 0xa3e0, 0xa404, 0xa428, 0xa44c,
0xa472, 0xa497, 0xa4a7, 0xa4c0, 0xa4d9, 0xa4f4, 0xa50e, 0xa528,
0xa541, 0xa55c, 0xa577, 0xa591, 0xa5a6, 0xa5bf, 0xa5d8, 0xa5f3,
0xa60d, 0xa627, 0xa63c, 0xa650, 0xa665, 0xa679, 0xa68d, 0xa6a1,
0xa6b4, 0xa6c8, 0xa6dc, 0xa6f2, 0xa708, 0xa71e, 0xa734, 0xa748,
0xa75f, 0xa775, 0xa78c, 0xa7a2, 0xa7b8, 0xa7ce, 0xa7e3, 0xa7f9,
// Entry 2E00 - 2E3F
0xa80f, 0xa827, 0xa83f, 0xa857, 0xa86f, 0xa885, 0xa8a4, 0xa8c2,
0xa8d8, 0xa8ee, 0xa903, 0xa918, 0xa92f, 0xa945, 0xa95b, 0xa970,
0xa987, 0xa99e, 0xa9b4, 0xa9c9, 0xa9df, 0xa9f5, 0xaa0c, 0xaa22,
0xaa39, 0xaa50, 0xaa65, 0xaa7c, 0xaa92, 0xaaab, 0xaac1, 0xaada,
0xaaf5, 0xab15, 0xab2c, 0xab44, 0xab5a, 0xab72, 0xab8c, 0xaba7,
0xabbe, 0xabd9, 0xabef, 0xac05, 0xac1b, 0xac34, 0xac4a, 0xac62,
0xac77, 0xac8d, 0xaca4, 0xacbe, 0xacd8, 0xacef, 0xad0a, 0xad26,
0xad40, 0xad5a, 0xad71, 0xad8a, 0xada5, 0xadc0, 0xadda, 0xadee,
// Entry 2E40 - 2E7F
0xae06, 0xae1e, 0xae38, 0xae51, 0xae6a, 0xae82, 0xae9c, 0xaeb6,
0xaecf, 0xaee3, 0xaf0b, 0xaf34, 0xaf5a, 0xaf80, 0xafa4, 0xafc9,
0xafee, 0xb015, 0xb03f, 0xb067, 0xb090, 0xb0b9, 0xb0c2, 0xb0cc,
0xb0d5, 0xb0eb, 0xb0fd, 0xb10f, 0xb121, 0xb133, 0xb145, 0xb158,
0xb16b, 0xb17e, 0xb191, 0xb1a4, 0xb1b7, 0xb1ca, 0xb1dd, 0xb1f0,
0xb203, 0xb216, 0xb229, 0xb23c, 0xb24f, 0xb262, 0xb275, 0xb288,
0xb29b, 0xb2ae, 0xb2c1, 0xb2d4, 0xb2e7, 0xb2fa, 0xb30d, 0xb320,
0xb333, 0xb346, 0xb359, 0xb36c, 0xb37f, 0xb392, 0xb3a5, 0xb3b8,
// Entry 2E80 - 2EBF
0xb3cb, 0xb3de, 0xb3f1, 0xb404, 0xb417, 0xb42a, 0xb43d, 0xb450,
0xb463, 0xb478, 0xb485, 0xb492, 0xb49e, 0xb4a9, 0xb4b6, 0xb4c1,
0xb4cb, 0xb4da, 0xb4e6, 0xb4f1, 0xb4fc, 0xb508, 0xb516, 0xb524,
0xb530, 0xb53c, 0xb547, 0xb553, 0xb560, 0xb56e, 0xb579, 0xb58a,
0xb59c, 0xb5ac, 0xb5b9, 0xb5c9, 0xb5d9, 0xb5e7, 0xb5f3, 0xb600,
0xb60c, 0xb61a, 0xb629, 0xb637, 0xb643, 0xb64f, 0xb65b, 0xb666,
0xb671, 0xb67b, 0xb686, 0xb692, 0xb69e, 0xb6ad, 0xb6b9, 0xb6c7,
0xb6d7, 0xb6e4, 0xb6ef, 0xb6fa, 0xb709, 0xb716, 0xb725, 0xb731,
// Entry 2EC0 - 2EFF
0xb741, 0xb74c, 0xb759, 0xb766, 0xb772, 0xb77e, 0xb78a, 0xb797,
0xb7a4, 0xb7ae, 0xb7ba, 0xb7c6, 0xb7d1, 0xb7df, 0xb7eb, 0xb7f7,
0xb804, 0xb812, 0xb820, 0xb82b, 0xb83b, 0xb846, 0xb854, 0xb862,
0xb86e, 0xb87a, 0xb885, 0xb893, 0xb89e, 0xb8aa, 0xb8b8, 0xb8c3,
0xb8d2, 0xb8de, 0xb908, 0xb931, 0xb95a, 0xb985, 0xb9af, 0xb9d9,
0xba02, 0xba2d, 0xba58, 0xba82, 0xbaab, 0xbad7, 0xbb03, 0xbb31,
0xbb5f, 0xbb8c, 0xbbb9, 0xbbe8, 0xbc16, 0xbc44, 0xbc70, 0xbca0,
0xbcd0, 0xbd02, 0xbd33, 0xbd3d, 0xbd46, 0xbd4f, 0xbd59, 0xbd62,
// Entry 2F00 - 2F3F
0xbd6b, 0xbd74, 0xbd85, 0xbd94, 0xbd9d, 0xbdb3, 0xbdc9, 0xbde0,
0xbdf5, 0xbe07, 0xbe15, 0xbe1e, 0xbe29, 0xbe32, 0xbe3b, 0xbe44,
0xbe4d, 0xbe56, 0xbe60, 0xbe6b, 0xbe74, 0xbe7d, 0xbe88, 0xbe93,
0xbe9c, 0xbea5, 0xbeae, 0xbeb8, 0xbec2, 0xbecc, 0xbed6, 0xbee1,
0xbeea, 0xbef3, 0xbefc, 0xbf05, 0xbf0e, 0xbf19, 0xbf22, 0xbf2b,
0xbf34, 0xbf45, 0xbf56, 0xbf66, 0xbf77, 0xbf86, 0xbf95, 0xbfa3,
0xbfb2, 0xbfc1, 0xbfd8, 0xbfe1, 0xbfeb, 0xbff5, 0xbfff, 0xc009,
0xc01a, 0xc033, 0xc03c, 0xc045, 0xc050, 0xc059, 0xc062, 0xc06b,
// Entry 2F40 - 2F7F
0xc076, 0xc07f, 0xc088, 0xc096, 0xc09f, 0xc0a8, 0xc0b3, 0xc0bc,
0xc0c5, 0xc0d3, 0xc0df, 0xc0eb, 0xc0f4, 0xc0fd, 0xc106, 0xc10f,
0xc11f, 0xc128, 0xc131, 0xc13a, 0xc143, 0xc14c, 0xc155, 0xc15e,
0xc16f, 0xc178, 0xc181, 0xc18a, 0xc194, 0xc19d, 0xc1ac, 0xc1b6,
0xc1c0, 0xc1c9, 0xc1d2, 0xc1dc, 0xc1e5, 0xc1ee, 0xc1f7, 0xc200,
0xc20f, 0xc21e, 0xc246, 0xc26e, 0xc298, 0xc2c1, 0xc2ea, 0xc312,
0xc33c, 0xc366, 0xc38f, 0xc3b7, 0xc3e2, 0xc40d, 0xc43a, 0xc467,
0xc493, 0xc4bf, 0xc4ed, 0xc51a, 0xc547, 0xc572, 0xc5a1, 0xc5d0,
// Entry 2F80 - 2FBF
0xc601, 0xc631, 0xc661, 0xc690, 0xc6c1, 0xc6f2, 0xc722, 0xc74d,
0xc77c, 0xc786, 0xc7a6, 0xc7c6, 0xc7ee, 0xc809, 0xc81d, 0xc832,
0xc847, 0xc864, 0xc87d, 0xc892, 0xc8a4, 0xc8bb, 0xc8d2, 0xc8ef,
0xc903, 0xc91a, 0xc930, 0xc950, 0xc965, 0xc97f, 0xc99a, 0xc9ac,
0xc9c8, 0xc9db, 0xc9f1, 0xca0a, 0xca24, 0xca44, 0xca62, 0xca80,
0xca96, 0xcaab, 0xcabf, 0xcad7, 0xcaec, 0xcb0f, 0xcb26, 0xcb3d,
0xcb55, 0xcb6d, 0xcb82, 0xcb97, 0xcbb0, 0xcbcb, 0xcbea, 0xcc05,
0xcc1c, 0xcc31, 0xcc48, 0xcc61, 0xcc82, 0xcca9, 0xccc1, 0xcce1,
// Entry 2FC0 - 2FFF
0xccf7, 0xcd10, 0xcd2c, 0xcd48, 0xcd5f, 0xcd76, 0xcd8e, 0xcdae,
0xcdcb, 0xcde9, 0xcdf7, 0xce05, 0xce12, 0xce20, 0xce2f, 0xce3e,
0xce4c, 0xce5b, 0xce69, 0xce77, 0xce84, 0xce92, 0xcea1, 0xceaf,
0xcebe, 0xcecc, 0xceda, 0xcee7, 0xcef5, 0xcf03, 0xcf10, 0xcf1e,
0xcf2d, 0xcf3c, 0xcf4a, 0xcf59, 0xcf69, 0xcf79, 0xcf88, 0xcf98,
0xcfa7, 0xcfb6, 0xcfc4, 0xcfd3, 0xcfe3, 0xcff2, 0xd002, 0xd011,
0xd020, 0xd02e, 0xd03d, 0xd04c, 0xd05a, 0xd069, 0xd078, 0xd087,
0xd095, 0xd0a4, 0xd0b4, 0xd0c3, 0xd0d2, 0xd0e1, 0xd0ef, 0xd0fe,
// Entry 3000 - 303F
0xd10e, 0xd11d, 0xd12c, 0xd13b, 0xd149, 0xd158, 0xd168, 0xd177,
0xd187, 0xd196, 0xd1a5, 0xd1b3, 0xd1c2, 0xd1d2, 0xd1e1, 0xd1f1,
0xd200, 0xd20f, 0xd21d, 0xd22c, 0xd23b, 0xd24a, 0xd258, 0xd267,
0xd277, 0xd286, 0xd295, 0xd2a4, 0xd2b2, 0xd2c1, 0xd2d1, 0xd2e0,
0xd2f0, 0xd300, 0xd30f, 0xd31f, 0xd330, 0xd341, 0xd351, 0xd362,
0xd372, 0xd382, 0xd391, 0xd3a1, 0xd3b2, 0xd3c2, 0xd3d3, 0xd3e3,
0xd3f3, 0xd402, 0xd412, 0xd422, 0xd431, 0xd441, 0xd451, 0xd461,
0xd470, 0xd480, 0xd491, 0xd4a1, 0xd4b1, 0xd4c1, 0xd4d0, 0xd4e0,
// Entry 3040 - 307F
0xd4f0, 0xd500, 0xd50f, 0xd51f, 0xd530, 0xd540, 0xd551, 0xd561,
0xd571, 0xd580, 0xd590, 0xd5a0, 0xd5b0, 0xd5bf, 0xd5cf, 0xd5df,
0xd5ef, 0xd5fe, 0xd60e, 0xd61f, 0xd62f, 0xd63f, 0xd64f, 0xd65e,
0xd66e, 0xd67f, 0xd68f, 0xd69f, 0xd6af, 0xd6be, 0xd6ce, 0xd6df,
0xd6ef, 0xd700, 0xd710, 0xd720, 0xd72f, 0xd73f, 0xd750, 0xd760,
0xd771, 0xd781, 0xd791, 0xd7a0, 0xd7b0, 0xd7c0, 0xd7d0, 0xd7df,
0xd7ef, 0xd800, 0xd810, 0xd820, 0xd82f, 0xd83f, 0xd850, 0xd860,
0xd86f, 0xd87e, 0xd88c, 0xd89b, 0xd8ab, 0xd8ba, 0xd8ca, 0xd8d9,
// Entry 3080 - 30BF
0xd8e8, 0xd8f6, 0xd905, 0xd915, 0xd925, 0xd934, 0xd944, 0xd953,
0xd962, 0xd970, 0xd97f, 0xd98e, 0xd99c, 0xd9ab, 0xd9ba, 0xd9c8,
0xd9d7, 0xd9e7, 0xd9f6, 0xda05, 0xda14, 0xda22, 0xda31, 0xda40,
0xda4f, 0xda5d, 0xda6c, 0xda7b, 0xda8a, 0xda98, 0xdaa7, 0xdab6,
0xdac4, 0xdad3, 0xdae2, 0xdaf1, 0xdaff, 0xdb0e, 0xdb1e, 0xdb2d,
0xdb3c, 0xdb4b, 0xdb59, 0xdb68, 0xdb77, 0xdb86, 0xdb94, 0xdba3,
0xdbb3, 0xdbc3, 0xdbd2, 0xdbe2, 0xdbf1, 0xdc00, 0xdc0e, 0xdc1d,
0xdc2c, 0xdc3b, 0xdc49, 0xdc58, 0xdc67, 0xdc76, 0xdc85, 0xdc94,
// Entry 30C0 - 30FF
0xdca2, 0xdcb1, 0xdcc1, 0xdcd0, 0xdcdf, 0xdcee, 0xdcfc, 0xdd0b,
0xdd1b, 0xdd2a, 0xdd39, 0xdd48, 0xdd56, 0xdd65, 0xdd75, 0xdd84,
0xdd94, 0xdda3, 0xddb2, 0xddc0, 0xddcf, 0xdddf, 0xddee, 0xddfd,
0xde0c, 0xde1a, 0xde29, 0xde38, 0xde46, 0xde55, 0xde64, 0xde73,
0xde81, 0xde90, 0xdea0, 0xdeaf, 0xdebe, 0xdecd, 0xdedb, 0xdeea,
0xdefa, 0xdf09, 0xdf19, 0xdf28, 0xdf37, 0xdf45, 0xdf54, 0xdf64,
0xdf74, 0xdf83, 0xdf93, 0xdfa2, 0xdfb1, 0xdfbf, 0xdfce, 0xdfdd,
0xdfeb, 0xdffa, 0xe009, 0xe018, 0xe026, 0xe035, 0xe045, 0xe054,
// Entry 3100 - 313F
0xe064, 0xe074, 0xe083, 0xe093, 0xe0a4, 0xe0b4, 0xe0c5, 0xe0d5,
0xe0e5, 0xe0f4, 0xe104, 0xe115, 0xe125, 0xe136, 0xe146, 0xe156,
0xe165, 0xe175, 0xe185, 0xe194, 0xe1a4, 0xe1b4, 0xe1c4, 0xe1d3,
0xe1e3, 0xe1f4, 0xe204, 0xe214, 0xe224, 0xe233, 0xe243, 0xe254,
0xe264, 0xe274, 0xe284, 0xe293, 0xe2a3, 0xe2b3, 0xe2c3, 0xe2d2,
0xe2e2, 0xe2f2, 0xe301, 0xe311, 0xe321, 0xe331, 0xe340, 0xe350,
0xe361, 0xe371, 0xe381, 0xe391, 0xe3a0, 0xe3b0, 0xe3c1, 0xe3d2,
0xe3e2, 0xe3f3, 0xe403, 0xe413, 0xe422, 0xe432, 0xe443, 0xe453,
// Entry 3140 - 317F
0xe463, 0xe473, 0xe483, 0xe493, 0xe4a2, 0xe4b2, 0xe4c2, 0xe4d1,
0xe4e0, 0xe4ee, 0xe4fd, 0xe50d, 0xe51c, 0xe52c, 0xe53b, 0xe549,
0xe558, 0xe568, 0xe577, 0xe587, 0xe596, 0xe5a5, 0xe5b3, 0xe5c2,
0xe5d1, 0xe5df, 0xe5ee, 0xe5fd, 0xe60c, 0xe61a, 0xe629, 0xe639,
0xe648, 0xe658, 0xe668, 0xe677, 0xe687, 0xe698, 0xe6a8, 0xe6b9,
0xe6c9, 0xe6d9, 0xe6e8, 0xe6f8, 0xe709, 0xe719, 0xe72a, 0xe73a,
0xe749, 0xe759, 0xe769, 0xe778, 0xe788, 0xe798, 0xe7a8, 0xe7b7,
0xe7c7, 0xe7d8, 0xe7e8, 0xe7f8, 0xe808, 0xe817, 0xe827, 0xe838,
// Entry 3180 - 31BF
0xe848, 0xe857, 0xe866, 0xe874, 0xe883, 0xe893, 0xe8a3, 0xe8b2,
0xe8c2, 0xe8d1, 0xe8e0, 0xe8ee, 0xe8fd, 0xe90d, 0xe91d, 0xe92c,
0xe93c, 0xe94b, 0xe95a, 0xe968, 0xe977, 0xe986, 0xe994, 0xe9a3,
0xe9b2, 0xe9c1, 0xe9cf, 0xe9de, 0xe9ee, 0xe9fd, 0xea0c, 0xea1b,
0xea29, 0xea38, 0xea48, 0xea57, 0xea66, 0xea75, 0xea83, 0xea92,
0xeaa2, 0xeab2, 0xeac1, 0xead1, 0xeae0, 0xeaef, 0xeafd, 0xeb0c,
0xeb1c, 0xeb2c, 0xeb3b, 0xeb4b, 0xeb5a, 0xeb69, 0xeb77, 0xeb86,
0xeb95, 0xeba4, 0xebb2, 0xebc1, 0xebd0, 0xebdf, 0xebed, 0xebfc,
// Entry 31C0 - 31FF
0xec0c, 0xec1b, 0xec2a, 0xec39, 0xec47, 0xec56, 0xec66, 0xec75,
0xec85, 0xec94, 0xeca3, 0xecb1, 0xecc0, 0xecd0, 0xecdf, 0xecef,
0xecfe, 0xed0d, 0xed1b, 0xed2a, 0xed39, 0xed48, 0xed56, 0xed65,
0xed74, 0xed83, 0xed91, 0xeda0, 0xedb0, 0xedbf, 0xedcf, 0xeddf,
0xedee, 0xedff, 0xee0f, 0xee20, 0xee30, 0xee40, 0xee4f, 0xee5f,
0xee70, 0xee81, 0xee91, 0xeea2, 0xeeb2, 0xeec2, 0xeed1, 0xeee1,
0xeef1, 0xef01, 0xef10, 0xef20, 0xef30, 0xef40, 0xef4f, 0xef5f,
0xef70, 0xef80, 0xef91, 0xefa1, 0xefb1, 0xefc1, 0xefd0, 0xefe0,
// Entry 3200 - 323F
0xeff1, 0xf001, 0xf012, 0xf022, 0xf032, 0xf041, 0xf051, 0xf061,
0xf070, 0xf080, 0xf090, 0xf0a0, 0xf0af, 0xf0bf, 0xf0d0, 0xf0e0,
0xf0f0, 0xf100, 0xf10f, 0xf11f, 0xf130, 0xf141, 0xf151, 0xf162,
0xf172, 0xf182, 0xf191, 0xf1a1, 0xf1b2, 0xf1c3, 0xf1d3, 0xf1e4,
0xf1f4, 0xf204, 0xf213, 0xf223, 0xf233, 0xf242, 0xf252, 0xf263,
0xf273, 0xf284, 0xf294, 0xf2a4, 0xf2b3, 0xf2c3, 0xf2d4, 0xf2e5,
0xf2f5, 0xf305, 0xf315, 0xf324, 0xf334, 0xf344, 0xf353, 0xf363,
0xf372, 0xf382, 0xf391, 0xf3a0, 0xf3af, 0xf3bd, 0xf3cc, 0xf3dc,
// Entry 3240 - 327F
0xf3ec, 0xf3fb, 0xf40b, 0xf41a, 0xf429, 0xf437, 0xf446, 0xf455,
0xf463, 0xf472, 0xf481, 0xf490, 0xf49e, 0xf4ad, 0xf4bd, 0xf4cc,
0xf4dc, 0xf4eb, 0xf4f9, 0xf508, 0xf517, 0xf525, 0xf534, 0xf543,
0xf552, 0xf560, 0xf56f, 0xf57f, 0xf58e, 0xf59e, 0xf5ad, 0xf5bc,
0xf5ca, 0xf5d9, 0xf5e9, 0xf5f8, 0xf608, 0xf617, 0xf626, 0xf634,
0xf643, 0xf652, 0xf660, 0xf66f, 0xf67e, 0xf68d, 0xf69b, 0xf6aa,
0xf6ba, 0xf6c9, 0xf6d8, 0xf6e7, 0xf6f5, 0xf704, 0xf714, 0xf723,
0xf732, 0xf741, 0xf74f, 0xf75e, 0xf76e, 0xf77e, 0xf78d, 0xf79d,
// Entry 3280 - 32BF
0xf7ac, 0xf7bb, 0xf7c9, 0xf7d8, 0xf7e8, 0xf7f7, 0xf807, 0xf816,
0xf825, 0xf833, 0xf842, 0xf851, 0xf85f, 0xf86e, 0xf87d, 0xf88c,
0xf89a, 0xf8a9, 0xf8b9, 0xf8c8, 0xf8d7, 0xf8e6, 0xf8f4, 0xf903,
0xf913, 0xf922, 0xf932, 0xf942, 0xf951, 0xf961, 0xf972, 0xf983,
0xf993, 0xf9a4, 0xf9b4, 0xf9c4, 0xf9d3, 0xf9e3, 0xf9f3, 0xfa02,
0xfa12, 0xfa22, 0xfa31, 0xfa41, 0xfa51, 0xfa60, 0xfa70, 0xfa81,
0xfa91, 0xfaa1, 0xfab1, 0xfac0, 0xfad0, 0xfae1, 0xfaf1, 0xfb01,
0xfb11, 0xfb20, 0xfb30, 0xfb41, 0xfb51, 0xfb62, 0xfb72, 0xfb82,
// Entry 32C0 - 32FF
0xfb91, 0xfba1, 0xfbb2, 0xfbc2, 0xfbd2, 0xfbe2, 0xfbf2, 0xfc01,
0xfc11, 0xfc20, 0xfc30, 0xfc41, 0xfc51, 0xfc61, 0xfc71, 0xfc80,
0xfc90, 0xfca1, 0xfcb1, 0xfcc0, 0xfccf, 0xfcdd, 0xfcec, 0xfcfc,
0xfd0b, 0xfd1b, 0xfd2a, 0xfd39, 0xfd47, 0xfd56, 0xfd66, 0xfd75,
0xfd85, 0xfd94, 0xfda3, 0xfdb1, 0xfdc0, 0xfdcf, 0xfddd, 0xfdec,
0xfdfb, 0xfe0a, 0xfe18, 0xfe27, 0xfe37, 0xfe46, 0xfe55, 0xfe64,
0xfe72, 0xfe81, 0xfe91, 0xfea0, 0xfeb0, 0xfec0, 0xfecf, 0xfedf,
0xfef0, 0xff00, 0xff11, 0xff21, 0xff31, 0xff40, 0xff50, 0xff60,
// Entry 3300 - 333F
0xff70, 0xff7f, 0xff8f, 0xff9f, 0xffae, 0xffbe, 0xffce, 0xffde,
0xffed, 0xfffd, 0x000d, 0x001d, 0x002c, 0x003c, 0x004d, 0x005d,
0x006d, 0x007d, 0x008c, 0x009c, 0x00ad, 0x00bd, 0x00ce, 0x00de,
0x00ee, 0x00fd, 0x010d, 0x011d, 0x012d, 0x013c, 0x014c, 0x015c,
0x016c, 0x017b, 0x018b, 0x019c, 0x01ac, 0x01bc, 0x01cc, 0x01db,
0x01eb, 0x01fc, 0x020c, 0x021c, 0x022c, 0x023b, 0x024b, 0x025c,
0x026d, 0x027d, 0x028e, 0x029e, 0x02ae, 0x02bd, 0x02cd, 0x02dd,
0x02ed, 0x02fc, 0x030c, 0x031c, 0x032b, 0x033b, 0x034c, 0x035c,
// Entry 3340 - 337F
0x036c, 0x037c, 0x038b, 0x039b, 0x03ac, 0x03bc, 0x03cc, 0x03db,
0x03ec, 0x03fc, 0x040c, 0x041c, 0x042b, 0x043b, 0x044b, 0x045b,
0x046a, 0x047a, 0x048a, 0x049a, 0x04a9, 0x04b9, 0x04ca, 0x04da,
0x04ea, 0x04fa, 0x0509, 0x0519, 0x052a, 0x053a, 0x054a, 0x055a,
0x0569, 0x0579, 0x0589, 0x0598, 0x05a8, 0x05b8, 0x05c8, 0x05d7,
0x05e7, 0x05f7, 0x0607, 0x0616, 0x0626, 0x0637, 0x0647, 0x0657,
0x0667, 0x0676, 0x0686, 0x0697, 0x06a7, 0x06b7, 0x06c7, 0x06d6,
0x06e6, 0x06f7, 0x0707, 0x0718, 0x0728, 0x0738, 0x0747, 0x0757,
// Entry 3380 - 33BF
0x0767, 0x0777, 0x0786, 0x0796, 0x07a6, 0x07b6, 0x07c5, 0x07d5,
0x07e6, 0x07f6, 0x0806, 0x0816, 0x0825, 0x0835, 0x0846, 0x0856,
0x0865, 0x0874, 0x0882, 0x0891, 0x08a1, 0x08b0, 0x08c0, 0x08cf,
0x08de, 0x08ec, 0x08fb, 0x090a, 0x0918, 0x0927, 0x0936, 0x0945,
0x0953, 0x0962, 0x0972, 0x0981, 0x0990, 0x099f, 0x09ad, 0x09bc,
0x09cc, 0x09db, 0x09ea, 0x09f9, 0x0a07, 0x0a16, 0x0a26, 0x0a36,
0x0a45, 0x0a55, 0x0a65, 0x0a75, 0x0a84, 0x0a94, 0x0aa3, 0x0ab2,
0x0ac0, 0x0acf, 0x0ade, 0x0aed, 0x0afb, 0x0b0a, 0x0b1a, 0x0b29,
// Entry 33C0 - 33FF
0x0b38, 0x0b47, 0x0b55, 0x0b64, 0x0b74, 0x0b83, 0x0b92, 0x0ba1,
0x0baf, 0x0bbe, 0x0bce, 0x0bde, 0x0bed, 0x0bfd, 0x0c0d, 0x0c1d,
0x0c2c, 0x0c3c, 0x0c4b, 0x0c5a, 0x0c68, 0x0c77, 0x0c86, 0x0c95,
0x0ca3, 0x0cb2, 0x0cc2, 0x0cd1, 0x0ce0, 0x0cef, 0x0cfd, 0x0d0c,
0x0d1c, 0x0d2b, 0x0d3b, 0x0d4b, 0x0d5a, 0x0d6a, 0x0d7b, 0x0d8c,
0x0d9c, 0x0dad, 0x0dbe, 0x0dce, 0x0ddf, 0x0def, 0x0dff, 0x0e0e,
0x0e1e, 0x0e2e, 0x0e3e, 0x0e4d, 0x0e5d, 0x0e6e, 0x0e7e, 0x0e8e,
0x0e9e, 0x0ead, 0x0ebd, 0x0ecd, 0x0edd, 0x0eec, 0x0efc, 0x0f0d,
// Entry 3400 - 343F
0x0f1e, 0x0f2e, 0x0f3f, 0x0f50, 0x0f60, 0x0f70, 0x0f80, 0x0f8f,
0x0f9f, 0x0faf, 0x0fbe, 0x0fce, 0x0fdf, 0x0fef, 0x0fff, 0x100f,
0x101e, 0x102e, 0x103f, 0x104f, 0x105f, 0x106f, 0x107e, 0x108e,
0x109f, 0x10b0, 0x10c0, 0x10d1, 0x10e2, 0x10f2, 0x1103, 0x1113,
0x1123, 0x1132, 0x1142, 0x1152, 0x1162, 0x1171, 0x1181, 0x1190,
0x119f, 0x11ad, 0x11bc, 0x11cc, 0x11dc, 0x11eb, 0x11fb, 0x120b,
0x121a, 0x1229, 0x1238, 0x1246, 0x1255, 0x1264, 0x1273, 0x1281,
0x1290, 0x12a0, 0x12af, 0x12be, 0x12cd, 0x12db, 0x12ea, 0x12fa,
// Entry 3440 - 347F
0x130a, 0x1319, 0x1329, 0x1339, 0x1349, 0x1358, 0x1368, 0x1377,
0x1386, 0x1394, 0x13a3, 0x13b2, 0x13c1, 0x13cf, 0x13de, 0x13ee,
0x13fd, 0x140c, 0x141b, 0x1429, 0x1438, 0x1448, 0x1457, 0x1465,
0x1472, 0x1480, 0x148f, 0x149d, 0x14ab, 0x14ba, 0x14c8, 0x14d5,
0x14e4, 0x14f2, 0x1501, 0x150f, 0x151c, 0x152a, 0x1539, 0x1547,
0x1554, 0x1562, 0x1570, 0x157f, 0x158d, 0x159c, 0x15ab, 0x15b8,
0x15c5, 0x15d4, 0x15e2, 0x15f0, 0x15fe, 0x160c, 0x161a, 0x1628,
0x1636, 0x1643, 0x1650, 0x165f, 0x166d, 0x167b, 0x168a, 0x1697,
// Entry 3480 - 34BF
0x16a4, 0x16b3, 0x16c1, 0x16ce, 0x16dd, 0x16eb, 0x16fa, 0x1709,
0x1717, 0x1726, 0x1734, 0x1744, 0x1753, 0x1760, 0x176e, 0x177c,
0x178b, 0x1799, 0x17a7, 0x17b6, 0x17c4, 0x17d2, 0x17e1, 0x17ef,
0x17fd, 0x180c, 0x181b, 0x182a, 0x183a, 0x1848, 0x1856, 0x1864,
0x1872, 0x1881, 0x188f, 0x189e, 0x18ac, 0x18ba, 0x18c9, 0x18d7,
0x18e5, 0x18f4, 0x1902, 0x1911, 0x191e, 0x192c, 0x1939, 0x1947,
0x1954, 0x1961, 0x196e, 0x197c, 0x198a, 0x1998, 0x19af, 0x19c5,
0x19dd, 0x19f4, 0x1a0b, 0x1a23, 0x1a39, 0x1a53, 0x1a62, 0x1a72,
// Entry 34C0 - 34FF
0x1a82, 0x1a92, 0x1aa3, 0x1ab3, 0x1ac4, 0x1ad4, 0x1ae5, 0x1af6,
0x1b08, 0x1b19, 0x1b29, 0x1b39, 0x1b49, 0x1b5a, 0x1b6b, 0x1b7d,
0x1b8d, 0x1b9d, 0x1bad, 0x1bbe, 0x1bce, 0x1bdf, 0x1bef, 0x1c00,
0x1c10, 0x1c20, 0x1c31, 0x1c41, 0x1c51, 0x1c63, 0x1c73, 0x1c83,
0x1c93, 0x1ca4, 0x1cb2, 0x1cc1, 0x1cd0, 0x1ce0, 0x1cef, 0x1cff,
0x1d0e, 0x1d1e, 0x1d2d, 0x1d3d, 0x1d4d, 0x1d5e, 0x1d6e, 0x1d7d,
0x1d8c, 0x1d9b, 0x1dab, 0x1dbb, 0x1dcc, 0x1ddb, 0x1dea, 0x1df9,
0x1e09, 0x1e18, 0x1e28, 0x1e37, 0x1e47, 0x1e56, 0x1e65, 0x1e75,
// Entry 3500 - 353F
0x1e84, 0x1e93, 0x1ea4, 0x1eb3, 0x1ec2, 0x1ed1, 0x1ee1, 0x1eef,
0x1efe, 0x1f0f, 0x1f1e, 0x1f2e, 0x1f3d, 0x1f4d, 0x1f5c, 0x1f6c,
0x1f7b, 0x1f8b, 0x1f9b, 0x1fac, 0x1fbd, 0x1fcd, 0x1fdc, 0x1feb,
0x1ffa, 0x200a, 0x201a, 0x202b, 0x203a, 0x2049, 0x2058, 0x2068,
0x2077, 0x2087, 0x2096, 0x20a6, 0x20b5, 0x20c4, 0x20d4, 0x20e3,
0x20f2, 0x2102, 0x2113, 0x2122, 0x2131, 0x2140, 0x2150, 0x215f,
0x216f, 0x217f, 0x218f, 0x21a0, 0x21b0, 0x21c1, 0x21d1, 0x21e2,
0x21f3, 0x2205, 0x2216, 0x2226, 0x2236, 0x2246, 0x2257, 0x2268,
// Entry 3540 - 357F
0x227a, 0x228a, 0x229a, 0x22aa, 0x22bb, 0x22cb, 0x22dc, 0x22ec,
0x22fd, 0x230d, 0x231d, 0x232e, 0x233e, 0x234e, 0x2360, 0x2370,
0x2380, 0x2390, 0x23a1, 0x23af, 0x23be, 0x23cd, 0x23dd, 0x23ec,
0x23fc, 0x240b, 0x241b, 0x242a, 0x243a, 0x244a, 0x245b, 0x246b,
0x247a, 0x2489, 0x2498, 0x24a8, 0x24b8, 0x24c9, 0x24d8, 0x24e7,
0x24f6, 0x2506, 0x2515, 0x2525, 0x2534, 0x2544, 0x2553, 0x2562,
0x2572, 0x2581, 0x2590, 0x25a1, 0x25b0, 0x25bf, 0x25ce, 0x25de,
0x25ec, 0x25fb, 0x260c, 0x261b, 0x262b, 0x263a, 0x264a, 0x2659,
// Entry 3580 - 35BF
0x2669, 0x2678, 0x2688, 0x2698, 0x26a9, 0x26b9, 0x26ca, 0x26d9,
0x26e8, 0x26f7, 0x2707, 0x2717, 0x2728, 0x2737, 0x2746, 0x2755,
0x2765, 0x2774, 0x2784, 0x2793, 0x27a3, 0x27b2, 0x27c1, 0x27d1,
0x27e0, 0x27ef, 0x2800, 0x280f, 0x281e, 0x282d, 0x283d, 0x284b,
0x285a, 0x286b, 0x287a, 0x288a, 0x2899, 0x28a9, 0x28b8, 0x28c8,
0x28d7, 0x28e7, 0x28f7, 0x2908, 0x2919, 0x2929, 0x293a, 0x2949,
0x2958, 0x2967, 0x2977, 0x2987, 0x2998, 0x29a7, 0x29b6, 0x29c5,
0x29d5, 0x29e4, 0x29f4, 0x2a03, 0x2a13, 0x2a22, 0x2a31, 0x2a41,
// Entry 35C0 - 35FF
0x2a50, 0x2a5f, 0x2a70, 0x2a82, 0x2a91, 0x2aa1, 0x2ab0, 0x2abf,
0x2acf, 0x2ade, 0x2af5, 0x2afe, 0x2b0b, 0x2b1c, 0x2b31, 0x2b46,
0x2b5c, 0x2b6c, 0x2b7c, 0x2b8b, 0x2b99, 0x2ba8, 0x2bb6, 0x2bc4,
0x2bd3, 0x2be3, 0x2bf2, 0x2c01, 0x2c10, 0x2c1f, 0x2c2d, 0x2c3a,
0x2c47, 0x2c56, 0x2c64, 0x2c72, 0x2c7f, 0x2c8e, 0x2c9d, 0x2cab,
0x2cc0, 0x2cd5, 0x2cf3, 0x2d0f, 0x2d2c, 0x2d47, 0x2d6b, 0x2d8d,
0x2da9, 0x2dc3, 0x2de0, 0x2dfb, 0x2e1f, 0x2e41, 0x2e64, 0x2e85,
0x2ea8, 0x2ec9, 0x2ef3, 0x2f1b, 0x2f3f, 0x2f61, 0x2f84, 0x2fa5,
// Entry 3600 - 363F
0x2fc7, 0x2fe7, 0x3010, 0x3037, 0x305a, 0x307b, 0x30ad, 0x30dd,
0x30f7, 0x310f, 0x3133, 0x3155, 0x3174, 0x3191, 0x31b0, 0x31cd,
0x31ec, 0x3209, 0x322c, 0x324d, 0x3270, 0x3291, 0x32bb, 0x32e3,
0x3300, 0x3318, 0x333c, 0x3364, 0x338d, 0x339e, 0x33c4, 0x33df,
0x33fb, 0x3416, 0x3439, 0x3457, 0x347a, 0x3499, 0x34b2, 0x34cc,
0x34db, 0x34eb, 0x3506, 0x351f, 0x353b, 0x3555, 0x3571, 0x358b,
0x35a7, 0x35c1, 0x35dd, 0x35f7, 0x3622, 0x364b, 0x3666, 0x367f,
0x369b, 0x36b5, 0x36d1, 0x36eb, 0x3707, 0x3721, 0x373c, 0x3755,
// Entry 3640 - 367F
0x3771, 0x378b, 0x37ab, 0x37c9, 0x37ea, 0x3809, 0x382b, 0x384d,
0x3869, 0x388d, 0x389b, 0x38aa, 0x38b8, 0x38c7, 0x38d6, 0x38e6,
0x38f6, 0x3904, 0x3914, 0x3922, 0x3931, 0x3940, 0x3950, 0x3961,
0x3973, 0x3985, 0x3995, 0x39a6, 0x39b8, 0x39c6, 0x39d6, 0x39e5,
0x39f6, 0x3a05, 0x3a17, 0x3a28, 0x3a39, 0x3a49, 0x3a5a, 0x3a69,
0x3a7b, 0x3a8b, 0x3a9b, 0x3aab, 0x3aba, 0x3acb, 0x3adc, 0x3aed,
0x3afe, 0x3b0f, 0x3b1f, 0x3b2f, 0x3b3f, 0x3b4f, 0x3b5e, 0x3b6d,
0x3b7c, 0x3b8b, 0x3b9c, 0x3bac, 0x3bbc, 0x3bd0, 0x3be1, 0x3bf1,
// Entry 3680 - 36BF
0x3c01, 0x3c12, 0x3c21, 0x3c31, 0x3c40, 0x3c4f, 0x3c5e, 0x3c6d,
0x3c7d, 0x3c8c, 0x3c9d, 0x3cad, 0x3cbd, 0x3ccc, 0x3cdb, 0x3cea,
0x3cf9, 0x3d0a, 0x3d1a, 0x3d2a, 0x3d3a, 0x3d4b, 0x3d5d, 0x3d70,
0x3d82, 0x3d95, 0x3db1, 0x3dcf, 0x3ddc, 0x3deb, 0x3df6, 0x3e01,
0x3e10, 0x3e23, 0x3e48, 0x3e6e, 0x3e94, 0x3ebb, 0x3ede, 0x3f02,
0x3f25, 0x3f49, 0x3f73, 0x3f97, 0x3fba, 0x3fdd, 0x4006, 0x403a,
0x4068, 0x4095, 0x40c2, 0x40f5, 0x4122, 0x4149, 0x416f, 0x4195,
0x41c1, 0x41e1, 0x41fa, 0x421c, 0x4244, 0x4263, 0x4284, 0x42ab,
// Entry 36C0 - 36FF
0x42db, 0x4308, 0x432c, 0x434f, 0x4376, 0x439b, 0x43c1, 0x43e5,
0x43fe, 0x4415, 0x442c, 0x4441, 0x445e, 0x4479, 0x4497, 0x44b3,
0x44dc, 0x4503, 0x451f, 0x453b, 0x4552, 0x4567, 0x457e, 0x4593,
0x45aa, 0x45bf, 0x45d6, 0x45eb, 0x4616, 0x463f, 0x4656, 0x466b,
0x4693, 0x46b9, 0x46db, 0x46fb, 0x4726, 0x474f, 0x4785, 0x47b9,
0x47d6, 0x47f1, 0x4818, 0x483d, 0x486c, 0x4899, 0x48b9, 0x48d7,
0x48ee, 0x4903, 0x4937, 0x4969, 0x498d, 0x49af, 0x49d8, 0x49ff,
0x4a33, 0x4a65, 0x4a90, 0x4ab9, 0x4ad7, 0x4af3, 0x4b13, 0x4b31,
// Entry 3700 - 373F
0x4b5c, 0x4b85, 0x4b9c, 0x4bb1, 0x4bd2, 0x4bf1, 0x4c17, 0x4c3b,
0x4c73, 0x4ca9, 0x4cc2, 0x4cd9, 0x4cf0, 0x4d05, 0x4d1c, 0x4d31,
0x4d49, 0x4d5f, 0x4d71, 0x4d87, 0x4d9d, 0x4db3, 0x4dc9, 0x4ddf,
0x4dfd, 0x4e13, 0x4e28, 0x4e46, 0x4e62, 0x4e80, 0x4e9c, 0x4eba,
0x4edf, 0x4f02, 0x4f1f, 0x4f3a, 0x4f58, 0x4f74, 0x4f92, 0x4fae,
0x4fcc, 0x4fe8, 0x500d, 0x5022, 0x5043, 0x5060, 0x507b, 0x5098,
0x50c9, 0x50e5, 0x510a, 0x512d, 0x514c, 0x5169, 0x518f, 0x51b5,
0x51d9, 0x51fb, 0x521d, 0x523d, 0x525c, 0x5279, 0x5298, 0x52b5,
// Entry 3740 - 377F
0x52d4, 0x52f1, 0x531b, 0x5343, 0x536d, 0x5395, 0x53bf, 0x53e7,
0x5411, 0x5439, 0x5463, 0x548b, 0x54ab, 0x54cf, 0x54ec, 0x550c,
0x5530, 0x554c, 0x5569, 0x5586, 0x55ae, 0x55c6, 0x55df, 0x55f6,
0x5610, 0x5628, 0x564a, 0x566a, 0x5688, 0x56a4, 0x56c2, 0x56de,
0x56fc, 0x5718, 0x5739, 0x5758, 0x5778, 0x5796, 0x57be, 0x57de,
0x5806, 0x5836, 0x5864, 0x5894, 0x58c2, 0x58e7, 0x590a, 0x5929,
0x5947, 0x596a, 0x598b, 0x59a9, 0x59c5, 0x59de, 0x59f7, 0x5a10,
0x5a34, 0x5a56, 0x5a78, 0x5a9d, 0x5abe, 0x5ae1, 0x5b03, 0x5b25,
// Entry 3780 - 37BF
0x5b47, 0x5b66, 0x5b87, 0x5b9c, 0x5bb1, 0x5bcb, 0x5be0, 0x5bf5,
0x5c0a, 0x5c23, 0x5c39, 0x5c50, 0x5c66, 0x5c7d, 0x5c97, 0x5cad,
0x5cc4, 0x5cda, 0x5cf1, 0x5d08, 0x5d20, 0x5d37, 0x5d4f, 0x5d65,
0x5d7c, 0x5d92, 0x5da9, 0x5dbf, 0x5dd5, 0x5dec, 0x5e02, 0x5e19,
0x5e2f, 0x5e45, 0x5e5b, 0x5e72, 0x5e88, 0x5e9e, 0x5eb7, 0x5ed0,
0x5ee9, 0x5f02, 0x5f1c, 0x5f36, 0x5f50, 0x5f6a, 0x5f84, 0x5fa7,
0x5fc7, 0x5fe4, 0x6007, 0x6029, 0x6048, 0x606d, 0x6085, 0x60a1,
0x60b7, 0x60d0, 0x60e2, 0x60f5, 0x6107, 0x611a, 0x612c, 0x613f,
// Entry 37C0 - 37FF
0x6151, 0x6164, 0x6176, 0x6189, 0x619b, 0x61ad, 0x61bf, 0x61d2,
0x61e4, 0x61f6, 0x6209, 0x621d, 0x6230, 0x6242, 0x6255, 0x6267,
0x627e, 0x6290, 0x62a2, 0x62b4, 0x62c7, 0x62d9, 0x62eb, 0x62fc,
0x630d, 0x631e, 0x632f, 0x6340, 0x6352, 0x6364, 0x6376, 0x6389,
0x639b, 0x63b7, 0x63d3, 0x63e6, 0x63fa, 0x640d, 0x6420, 0x643c,
0x6459, 0x6472, 0x648e, 0x64aa, 0x64c7, 0x64e2, 0x64fb, 0x6514,
0x6526, 0x653f, 0x6557, 0x656e, 0x6581, 0x6595, 0x65a8, 0x65bc,
0x65cf, 0x65e3, 0x65fe, 0x661a, 0x6635, 0x6651, 0x6664, 0x6678,
// Entry 3800 - 383F
0x668c, 0x669f, 0x66b3, 0x66c7, 0x66db, 0x66f0, 0x6704, 0x6719,
0x672e, 0x6742, 0x6757, 0x676b, 0x6780, 0x6795, 0x67aa, 0x67c0,
0x67d5, 0x67eb, 0x6800, 0x6814, 0x6829, 0x683d, 0x6852, 0x6866,
0x687a, 0x688f, 0x68a3, 0x68b8, 0x68cc, 0x68e0, 0x68f4, 0x6908,
0x691c, 0x6931, 0x6946, 0x695a, 0x696e, 0x6983, 0x69a2, 0x69ba,
0x69d1, 0x69e9, 0x6a00, 0x6a18, 0x6a37, 0x6a57, 0x6a76, 0x6a96,
0x6aad, 0x6ac5, 0x6add, 0x6af4, 0x6b0c, 0x6b24, 0x6b3a, 0x6b55,
0x6b65, 0x6b7c, 0x6b91, 0x6ba5, 0x6bb9, 0x6bcf, 0x6be4, 0x6bf9,
// Entry 3840 - 387F
0x6c0d, 0x6c23, 0x6c39, 0x6c4e, 0x6c6d, 0x6c8b, 0x6ca9, 0x6cc9,
0x6ce8, 0x6d07, 0x6d25, 0x6d45, 0x6d65, 0x6d84, 0x6da1, 0x6dbe,
0x6ddc, 0x6dfa, 0x6e18, 0x6e36, 0x6e54, 0x6e76, 0x6e99, 0x6ebb,
0x6ee4, 0x6f03, 0x6f24, 0x6f48, 0x6f60, 0x6f75, 0x6f85, 0x6f9a,
0x6fb1, 0x6fc3, 0x6fd7, 0x6fef, 0x7002, 0x7014, 0x7026, 0x703a,
0x704d, 0x7060, 0x7072, 0x7086, 0x709a, 0x70ad, 0x70bf, 0x70d2,
0x70e4, 0x70f7, 0x7109, 0x711c, 0x712e, 0x7141, 0x7153, 0x7166,
0x7178, 0x718a, 0x719d, 0x71af, 0x71c1, 0x71d3, 0x71e5, 0x71f7,
// Entry 3880 - 38BF
0x7209, 0x721b, 0x722e, 0x7240, 0x7252, 0x7264, 0x7275, 0x7287,
0x7298, 0x72aa, 0x72bb, 0x72cb, 0x72db, 0x72ec, 0x72fc, 0x7310,
0x7323, 0x733d, 0x734e, 0x7360, 0x7370, 0x7380, 0x7391, 0x73a1,
0x73b1, 0x73c1, 0x73d1, 0x73e1, 0x73f1, 0x7401, 0x7411, 0x7422,
0x7432, 0x7442, 0x7452, 0x7462, 0x7472, 0x7482, 0x7493, 0x74a5,
0x74b6, 0x74c8, 0x74d7, 0x74ea, 0x74fd, 0x7510, 0x7524, 0x7537,
0x754b, 0x755f, 0x7573, 0x758b, 0x75a2, 0x75b9, 0x75d0, 0x75dd,
0x75f0, 0x760c, 0x7628, 0x7643, 0x765f, 0x767b, 0x769c, 0x76b8,
// Entry 38C0 - 38FF
0x76d9, 0x76f4, 0x770f, 0x772f, 0x7752, 0x776c, 0x7787, 0x77a4,
0x77c0, 0x77dc, 0x77f6, 0x7818, 0x7835, 0x7850, 0x786f, 0x788a,
0x78a5, 0x78c5, 0x78e1, 0x78fe, 0x7918, 0x7938, 0x794f, 0x7962,
0x7975, 0x798a, 0x799b, 0x79b1, 0x79c2, 0x79d4, 0x79e5, 0x79fd,
0x7a16, 0x7a37, 0x7a48, 0x7a5a, 0x7a6b, 0x7a7d, 0x7a95, 0x7aad,
0x7abf, 0x7ad7, 0x7aea, 0x7afc, 0x7b14, 0x7b26, 0x7b3f, 0x7b5b,
0x7b6e, 0x7b81, 0x7b9e, 0x7bb1, 0x7bce, 0x7be6, 0x7bf8, 0x7c10,
0x7c22, 0x7c3e, 0x7c50, 0x7c62, 0x7c7a, 0x7c8c, 0x7ca4, 0x7cb6,
// Entry 3900 - 393F
0x7cc8, 0x7cda, 0x7cf2, 0x7d04, 0x7d16, 0x7d2e, 0x7d4a, 0x7d5c,
0x7d6e, 0x7d86, 0x7da0, 0x7dba, 0x7dd2, 0x7df0, 0x7e08, 0x7e27,
0x7e41, 0x7e5f, 0x7e78, 0x7e95, 0x7eb4, 0x7ed1, 0x7ee1, 0x7ef8,
0x7f10, 0x7f23, 0x7f36, 0x7f49, 0x7f5c, 0x7f71, 0x7f85, 0x7f99,
0x7fab, 0x7fc2, 0x7fd7, 0x7ff3, 0x8007, 0x801a, 0x802c, 0x803e,
0x8052, 0x8065, 0x8078, 0x808a, 0x809e, 0x80b2, 0x80c5, 0x80e0,
0x80f7, 0x810e, 0x8125, 0x813c, 0x8153, 0x816a, 0x817f, 0x81a9,
0x81c5, 0x81e0, 0x81fb, 0x8217, 0x8232, 0x824e, 0x826a, 0x8287,
// Entry 3940 - 397F
0x82a3, 0x82bf, 0x82da, 0x82f5, 0x8312, 0x832e, 0x834a, 0x8365,
0x8382, 0x839f, 0x83bb, 0x83d7, 0x83f2, 0x840e, 0x8429, 0x8445,
0x8452, 0x845f, 0x846c, 0x8479, 0x8487, 0x8494, 0x84a2, 0x84b1,
0x84bf, 0x84ce, 0x84de, 0x84ed, 0x84fc, 0x850c, 0x851a, 0x8529,
0x8539, 0x8548, 0x8558, 0x8566, 0x8575, 0x8583, 0x8592, 0x85a1,
0x85af, 0x85be, 0x85cc, 0x85db, 0x85ea, 0x85f8, 0x8607, 0x8616,
0x8624, 0x8633, 0x8641, 0x864f, 0x865d, 0x866b, 0x867a, 0x8688,
0x8696, 0x86a8, 0x86b9, 0x86cb, 0x86dd, 0x86ee, 0x8700, 0x8711,
// Entry 3980 - 39BF
0x8723, 0x8735, 0x8747, 0x875d, 0x8773, 0x8789, 0x879f, 0x87b2,
0x87c5, 0x87d9, 0x87f5, 0x8809, 0x881c, 0x882f, 0x8842, 0x8855,
0x8868, 0x887b, 0x888f, 0x88aa, 0x88c5, 0x88d4, 0x88e2, 0x88f0,
0x8900, 0x890f, 0x891e, 0x892c, 0x893c, 0x894c, 0x895b, 0x8972,
0x8988, 0x89a5, 0x89c2, 0x89da, 0x89f2, 0x8a0b, 0x8a23, 0x8a3c,
0x8a55, 0x8a6e, 0x8a88, 0x8aa1, 0x8abb, 0x8ad4, 0x8aec, 0x8b04,
0x8b1c, 0x8b35, 0x8b4d, 0x8b79, 0x8b91, 0x8ba9, 0x8bc1, 0x8bdc,
0x8bf6, 0x8c10, 0x8c30, 0x8c48, 0x8c60, 0x8c77, 0x8c92, 0x8caf,
// Entry 39C0 - 39FF
0x8ccc, 0x8ceb, 0x8d0a, 0x8d20, 0x8d37, 0x8d4e, 0x8d66, 0x8d7e,
0x8d97, 0x8dad, 0x8dc4, 0x8ddb, 0x8df3, 0x8e09, 0x8e20, 0x8e37,
0x8e4f, 0x8e65, 0x8e7c, 0x8e93, 0x8eab, 0x8ec1, 0x8ed8, 0x8eee,
0x8f05, 0x8f1c, 0x8f34, 0x8f4a, 0x8f61, 0x8f77, 0x8f8e, 0x8fa4,
0x8fbb, 0x8fd2, 0x8fea, 0x9000, 0x9017, 0x902d, 0x9044, 0x905a,
0x9071, 0x9087, 0x909e, 0x90b4, 0x90cb, 0x90e1, 0x90f8, 0x910e,
0x9125, 0x913a, 0x9150, 0x9161, 0x9172, 0x9182, 0x9193, 0x91a3,
0x91b3, 0x91c3, 0x91d4, 0x91e5, 0x91f7, 0x9208, 0x921a, 0x922b,
// Entry 3A00 - 3A3F
0x923c, 0x924d, 0x9261, 0x9278, 0x928d, 0x92a3, 0x92b6, 0x92cb,
0x92de, 0x92f4, 0x930b, 0x9320, 0x9335, 0x934c, 0x9363, 0x937a,
0x9392, 0x93a9, 0x93c1, 0x93d8, 0x93ef, 0x9406, 0x9420, 0x943a,
0x9455, 0x946f, 0x948a, 0x949f, 0x94b8, 0x94c9, 0x94ee, 0x950f,
0x952e, 0x9541, 0x9557, 0x956d, 0x9584, 0x959b, 0x95b1, 0x95c7,
0x95dd, 0x95f3, 0x960a, 0x9621, 0x9637, 0x964d, 0x9662, 0x9677,
0x968d, 0x96a3, 0x96b8, 0x96cd, 0x96e4, 0x96fb, 0x9712, 0x972a,
0x9742, 0x9759, 0x9770, 0x9785, 0x979a, 0x97af, 0x97c5, 0x97db,
// Entry 3A40 - 3A7F
0x97f0, 0x9805, 0x9824, 0x9847, 0x9867, 0x9882, 0x98a4, 0x98be,
0x98eb, 0x9914, 0x9941, 0x9966, 0x998c, 0x99b2, 0x99da, 0x99fa,
0x9a26, 0x9a4b, 0x9a69, 0x9a91, 0x9ac4, 0x9ae6, 0x9b14, 0x9b30,
0x9b5b, 0x9b7e, 0x9b99, 0x9bbf, 0x9bec, 0x9c07, 0x9c2c, 0x9c4b,
0x9c74, 0x9ca1, 0x9cb6, 0x9cd2, 0x9cf5, 0x9d0b, 0x9d35, 0x9d5f,
0x9d87, 0x9dae, 0x9de8, 0x9e1a, 0x9e43, 0x9e65, 0x9e7f, 0x9eab,
0x9ed4, 0x9efa, 0x9f16, 0x9f33, 0x9f4d, 0x9f62, 0x9f83, 0x9fa3,
0x9fd4, 0xa005, 0xa032, 0xa050, 0xa069, 0xa083, 0xa09a, 0xa0b1,
// Entry 3A80 - 3ABF
0xa0c8, 0xa0df, 0xa0f6, 0xa10d, 0xa125, 0xa13d, 0xa155, 0xa16d,
0xa185, 0xa19d, 0xa1b5, 0xa1cd, 0xa1e5, 0xa1fd, 0xa215, 0xa22d,
0xa245, 0xa25d, 0xa275, 0xa28d, 0xa2a5, 0xa2bd, 0xa2d5, 0xa2ed,
0xa305, 0xa31d, 0xa335, 0xa34d, 0xa365, 0xa37e, 0xa397, 0xa3af,
0xa3c7, 0xa3df, 0xa3f7, 0xa40f, 0xa428, 0xa441, 0xa45a, 0xa473,
0xa48c, 0xa4a5, 0xa4bd, 0xa4d4, 0xa4ec, 0xa504, 0xa51c, 0xa534,
0xa54c, 0xa564, 0xa57c, 0xa594, 0xa5ac, 0xa5c4, 0xa5dc, 0xa5f4,
0xa60c, 0xa624, 0xa63d, 0xa656, 0xa66f, 0xa688, 0xa6a1, 0xa6ba,
// Entry 3AC0 - 3AFF
0xa6d3, 0xa6ec, 0xa705, 0xa71e, 0xa737, 0xa750, 0xa769, 0xa781,
0xa799, 0xa7b1, 0xa7c9, 0xa7e1, 0xa7f9, 0xa811, 0xa828, 0xa83f,
0xa856, 0xa86d, 0xa883, 0xa899, 0xa8b1, 0xa8c8, 0xa8e0, 0xa8f8,
0xa910, 0xa927, 0xa93f, 0xa956, 0xa96c, 0xa981, 0xa999, 0xa9b2,
0xa9c9, 0xa9e1, 0xa9f8, 0xaa0e, 0xaa25, 0xaa3c, 0xaa54, 0xaa6c,
0xaa84, 0xaaa2, 0xaac0, 0xaade, 0xaafb, 0xab18, 0xab36, 0xab55,
0xab71, 0xab8d, 0xaba9, 0xabc5, 0xabe2, 0xac00, 0xac1c, 0xac3b,
0xac57, 0xac6c, 0xac81, 0xac97, 0xacae, 0xacc4, 0xacda, 0xacf2,
// Entry 3B00 - 3B3F
0xad09, 0xad20, 0xad36, 0xad4e, 0xad66, 0xad7d, 0xad93, 0xada9,
0xadbe, 0xadd4, 0xadea, 0xae00, 0xae16, 0xae2c, 0xae41, 0xae56,
0xae6c, 0xae81, 0xae96, 0xaead, 0xaec3, 0xaed9, 0xaeee, 0xaf04,
0xaf19, 0xaf2e, 0xaf42, 0xaf5a, 0xaf72, 0xaf8e, 0xafac, 0xafc8,
0xafea, 0xb007, 0xb023, 0xb046, 0xb063, 0xb082, 0xb0a1, 0xb0c3,
0xb0e6, 0xb109, 0xb12b, 0xb14e, 0xb172, 0xb191, 0xb1b9, 0xb1d7,
0xb1f3, 0xb214, 0xb22f, 0xb250, 0xb26c, 0xb289, 0xb2ad, 0xb2c9,
0xb2e4, 0xb306, 0xb322, 0xb340, 0xb35b, 0xb37e, 0xb39f, 0xb3c0,
// Entry 3B40 - 3B7F
0xb3dd, 0xb3f8, 0xb415, 0xb432, 0xb44d, 0xb46b, 0xb491, 0xb4b0,
0xb4cf, 0xb4eb, 0xb50c, 0xb527, 0xb544, 0xb564, 0xb584, 0xb5a4,
0xb5c4, 0xb5e4, 0xb604, 0xb624, 0xb644, 0xb664, 0xb684, 0xb6a4,
0xb6c4, 0xb6e4, 0xb704, 0xb724, 0xb744, 0xb764, 0xb784, 0xb7a4,
0xb7c4, 0xb7e4, 0xb804, 0xb824, 0xb844, 0xb864, 0xb884, 0xb8a4,
0xb8c4, 0xb8e4, 0xb904, 0xb924, 0xb944, 0xb964, 0xb984, 0xb9a4,
0xb9c4, 0xb9e4, 0xba04, 0xba24, 0xba44, 0xba64, 0xba84, 0xbaa4,
0xbac4, 0xbae4, 0xbb04, 0xbb24, 0xbb44, 0xbb64, 0xbb84, 0xbba4,
// Entry 3B80 - 3BBF
0xbbc4, 0xbbe4, 0xbc04, 0xbc24, 0xbc44, 0xbc64, 0xbc84, 0xbca4,
0xbcc4, 0xbce4, 0xbd04, 0xbd24, 0xbd44, 0xbd64, 0xbd84, 0xbda4,
0xbdc4, 0xbde4, 0xbe04, 0xbe24, 0xbe44, 0xbe64, 0xbe84, 0xbea4,
0xbec4, 0xbee4, 0xbf04, 0xbf24, 0xbf44, 0xbf64, 0xbf84, 0xbfa4,
0xbfc4, 0xbfe4, 0xc004, 0xc024, 0xc044, 0xc064, 0xc084, 0xc0a4,
0xc0c4, 0xc0e4, 0xc104, 0xc124, 0xc144, 0xc164, 0xc184, 0xc1a4,
0xc1c4, 0xc1e4, 0xc204, 0xc224, 0xc244, 0xc264, 0xc284, 0xc2a4,
0xc2c4, 0xc2e4, 0xc304, 0xc324, 0xc344, 0xc364, 0xc384, 0xc3a4,
// Entry 3BC0 - 3BFF
0xc3c4, 0xc3e4, 0xc404, 0xc424, 0xc444, 0xc464, 0xc484, 0xc4a4,
0xc4c4, 0xc4e4, 0xc504, 0xc524, 0xc544, 0xc564, 0xc584, 0xc5a4,
0xc5c4, 0xc5e4, 0xc604, 0xc624, 0xc644, 0xc664, 0xc684, 0xc6a4,
0xc6c4, 0xc6e4, 0xc704, 0xc724, 0xc744, 0xc764, 0xc784, 0xc7a4,
0xc7c4, 0xc7e4, 0xc804, 0xc824, 0xc844, 0xc864, 0xc884, 0xc8a4,
0xc8c4, 0xc8e4, 0xc904, 0xc924, 0xc944, 0xc964, 0xc984, 0xc9a4,
0xc9c4, 0xc9e4, 0xca04, 0xca24, 0xca44, 0xca64, 0xca84, 0xcaa4,
0xcac4, 0xcae4, 0xcb04, 0xcb24, 0xcb44, 0xcb64, 0xcb84, 0xcba4,
// Entry 3C00 - 3C3F
0xcbc4, 0xcbe4, 0xcc04, 0xcc24, 0xcc44, 0xcc64, 0xcc84, 0xcca4,
0xccc4, 0xcce4, 0xcd04, 0xcd24, 0xcd44, 0xcd64, 0xcd84, 0xcda4,
0xcdc4, 0xcde4, 0xce04, 0xce24, 0xce44, 0xce64, 0xce84, 0xcea4,
0xcec4, 0xcee4, 0xcf04, 0xcf24, 0xcf44, 0xcf64, 0xcf84, 0xcfa4,
0xcfc4, 0xcfe4, 0xd004, 0xd024, 0xd044, 0xd064, 0xd084, 0xd0a4,
0xd0c4, 0xd0e4, 0xd104, 0xd124, 0xd144, 0xd164, 0xd184, 0xd1a4,
0xd1c4, 0xd1e4, 0xd204, 0xd224, 0xd244, 0xd264, 0xd284, 0xd2a4,
0xd2c4, 0xd2e4, 0xd304, 0xd324, 0xd344, 0xd364, 0xd384, 0xd3a4,
// Entry 3C40 - 3C7F
0xd3c4, 0xd3e4, 0xd404, 0xd424, 0xd444, 0xd464, 0xd484, 0xd4a4,
0xd4c4, 0xd4e4, 0xd504, 0xd524, 0xd544, 0xd564, 0xd584, 0xd5a4,
0xd5c4, 0xd5e4, 0xd604, 0xd624, 0xd644, 0xd664, 0xd684, 0xd6a4,
0xd6c4, 0xd6e4, 0xd704, 0xd724, 0xd744, 0xd764, 0xd784, 0xd7a4,
0xd7c4, 0xd7e4, 0xd804, 0xd824, 0xd844, 0xd864, 0xd884, 0xd8a4,
0xd8c4, 0xd8e4, 0xd904, 0xd924, 0xd944, 0xd964, 0xd984, 0xd9a4,
0xd9c4, 0xd9e4, 0xda04, 0xda24, 0xda44, 0xda64, 0xda84, 0xdaa4,
0xdac4, 0xdae4, 0xdb04, 0xdb24, 0xdb44, 0xdb64, 0xdb84, 0xdba4,
// Entry 3C80 - 3CBF
0xdbc4, 0xdbe4, 0xdc04, 0xdc24, 0xdc44, 0xdc64, 0xdc84, 0xdca4,
0xdcc4, 0xdce4, 0xdd04, 0xdd24, 0xdd44, 0xdd64, 0xdd84, 0xdda4,
0xddc4, 0xdde4, 0xde04, 0xde24, 0xde44, 0xde64, 0xde84, 0xdea4,
0xdec4, 0xdee4, 0xdf04, 0xdf24, 0xdf44, 0xdf64, 0xdf84, 0xdfa4,
0xdfc4, 0xdfe4, 0xe004, 0xe024, 0xe044, 0xe064, 0xe084, 0xe0a4,
0xe0c4, 0xe0e4, 0xe104, 0xe124, 0xe144, 0xe164, 0xe184, 0xe1a4,
0xe1c4, 0xe1e4, 0xe204, 0xe224, 0xe244, 0xe264, 0xe284, 0xe2a4,
0xe2c4, 0xe2e4, 0xe304, 0xe324, 0xe344, 0xe364, 0xe384, 0xe3a4,
// Entry 3CC0 - 3CFF
0xe3c4, 0xe3e4, 0xe404, 0xe424, 0xe444, 0xe464, 0xe484, 0xe4a4,
0xe4c4, 0xe4e4, 0xe504, 0xe524, 0xe544, 0xe564, 0xe584, 0xe5a4,
0xe5c4, 0xe5e4, 0xe604, 0xe624, 0xe644, 0xe664, 0xe684, 0xe6a4,
0xe6c4, 0xe6e4, 0xe704, 0xe724, 0xe744, 0xe764, 0xe784, 0xe7a4,
0xe7c4, 0xe7e4, 0xe804, 0xe824, 0xe844, 0xe864, 0xe884, 0xe8a4,
0xe8c4, 0xe8e4, 0xe904, 0xe924, 0xe944, 0xe964, 0xe984, 0xe9a4,
0xe9c4, 0xe9e4, 0xea04, 0xea24, 0xea44, 0xea64, 0xea84, 0xeaa4,
0xeac4, 0xeae4, 0xeb04, 0xeb24, 0xeb44, 0xeb64, 0xeb84, 0xeba4,
// Entry 3D00 - 3D3F
0xebc4, 0xebe4, 0xec04, 0xec24, 0xec44, 0xec64, 0xec84, 0xeca4,
0xecc4, 0xece4, 0xed04, 0xed24, 0xed44, 0xed64, 0xed84, 0xeda4,
0xedc4, 0xede4, 0xee04, 0xee24, 0xee44, 0xee64, 0xee84, 0xeea4,
0xeec4, 0xeee4, 0xef04, 0xef24, 0xef44, 0xef64, 0xef84, 0xefa4,
0xefc4, 0xefe4, 0xf004, 0xf024, 0xf044, 0xf064, 0xf07b, 0xf092,
0xf0a9, 0xf0c1, 0xf0d9, 0xf0f6, 0xf10d, 0xf12c, 0xf14b, 0xf16a,
0xf189, 0xf1a8, 0xf1c4, 0xf1e5, 0xf20a, 0xf228, 0xf23f, 0xf257,
0xf26c, 0xf282, 0xf29a, 0xf2b6, 0xf2cd, 0xf2e3, 0xf306, 0xf326,
// Entry 3D40 - 3D7F
0xf345, 0xf370, 0xf39a, 0xf3b7, 0xf3d5, 0xf3f2, 0xf40f, 0xf42e,
0xf44d, 0xf468, 0xf485, 0xf4a4, 0xf4c1, 0xf4de, 0xf501, 0xf51e,
0xf53d, 0xf55a, 0xf577, 0xf597, 0xf5b9, 0xf5d5, 0xf5f4, 0xf611,
0xf62f, 0xf64d, 0xf66a, 0xf686, 0xf6a1, 0xf6bc, 0xf6d6, 0xf6f0,
0xf716, 0xf739, 0xf759, 0xf776, 0xf795, 0xf7b3, 0xf7d2, 0xf7ee,
0xf80c, 0xf829, 0xf84a, 0xf868, 0xf888, 0xf8a7, 0xf8c9, 0xf8e8,
0xf909, 0xf929, 0xf94a, 0xf968, 0xf988, 0xf9a7, 0xf9c7, 0xf9e4,
0xfa03, 0xfa21, 0xfa40, 0xfa5c, 0xfa7a, 0xfa97, 0xfab8, 0xfad6,
// Entry 3D80 - 3DBF
0xfaf6, 0xfb15, 0xfb35, 0xfb52, 0xfb71, 0xfb8f, 0xfbaf, 0xfbcc,
0xfbeb, 0xfc09, 0xfc2a, 0xfc48, 0xfc68, 0xfc87, 0xfcaa, 0xfcca,
0xfcec, 0xfd0d, 0xfd2f, 0xfd4e, 0xfd6f, 0xfd8d, 0xfdac, 0xfdc8,
0xfde8, 0xfe05, 0xfe24, 0xfe40, 0xfe60, 0xfe7d, 0xfe9e, 0xfebc,
0xfedc, 0xfefb, 0xff1a, 0xff36, 0xff54, 0xff71, 0xff91, 0xffae,
0xffcd, 0xffeb, 0x000c, 0x002a, 0x004a, 0x0069, 0x0090, 0x00b4,
0x00d5, 0x00f3, 0x0113, 0x0132, 0x0160, 0x018b, 0x01af, 0x01d0,
0x01f3, 0x0215, 0x0240, 0x0268, 0x0292, 0x02bb, 0x02e1, 0x0304,
// Entry 3DC0 - 3DFF
0x033b, 0x036f, 0x0386, 0x039d, 0x03b9, 0x03d5, 0x03f3, 0x0411,
0x0442, 0x0473, 0x0490, 0x04ad, 0x04d4, 0x04fb, 0x0522, 0x0534,
0x0551, 0x056e, 0x0587, 0x05a5, 0x05c0, 0x05dd, 0x05f9, 0x0616,
0x0630, 0x064e, 0x0669, 0x0687, 0x06a2, 0x06d0, 0x06ee, 0x0709,
0x072f, 0x0752, 0x0778, 0x079b, 0x07b8, 0x07d2, 0x07ee, 0x0809,
0x0846, 0x0882, 0x08be, 0x08f7, 0x0931, 0x0968, 0x09a3, 0x09db,
0x0a14, 0x0a4a, 0x0a84, 0x0abb, 0x0af5, 0x0b2c, 0x0b65, 0x0b9b,
0x0bd3, 0x0c26, 0x0c76, 0x0cc8, 0x0ced, 0x0d0f, 0x0d33, 0x0d56,
// Entry 3E00 - 3E3F
0x0d92, 0x0dcd, 0x0e09, 0x0e4d, 0x0e88, 0x0eb3, 0x0edd, 0x0f08,
0x0f33, 0x0f66, 0x0f90, 0x0fbb, 0x0fe5, 0x1010, 0x103b, 0x106e,
0x1098, 0x10c4, 0x10f0, 0x1124, 0x114f, 0x117a, 0x11a6, 0x11d1,
0x11fc, 0x1228, 0x1253, 0x127f, 0x12ab, 0x12d6, 0x1302, 0x132e,
0x1358, 0x1383, 0x13ae, 0x13d8, 0x1403, 0x142e, 0x1458, 0x1483,
0x14ae, 0x14d9, 0x1504, 0x1531, 0x155e, 0x1589, 0x15b3, 0x15de,
0x1609, 0x163c, 0x1666, 0x1690, 0x16bb, 0x16ee, 0x1718, 0x1743,
0x176e, 0x1798, 0x17c3, 0x17ed, 0x1818, 0x184b, 0x1875, 0x18a0,
// Entry 3E40 - 3E7F
0x18ca, 0x18f5, 0x1920, 0x1953, 0x197d, 0x19a9, 0x19d4, 0x1a00,
0x1a2c, 0x1a60, 0x1a8b, 0x1ab7, 0x1ae2, 0x1b0e, 0x1b3a, 0x1b6e,
0x1b99, 0x1bc4, 0x1bef, 0x1c22, 0x1c4c, 0x1c77, 0x1ca1, 0x1ccc,
0x1cf7, 0x1d2a, 0x1d54, 0x1d8c, 0x1dc3, 0x1e03, 0x1e35, 0x1e67,
0x1e96, 0x1ec5, 0x1ef4, 0x1f2e, 0x1f66, 0x1f9f, 0x1fd8, 0x2011,
0x2052, 0x208a, 0x20b1, 0x20d9, 0x2101, 0x2129, 0x2159, 0x2180,
0x21a7, 0x21cf, 0x21f7, 0x221f, 0x224f, 0x2276, 0x229e, 0x22c7,
0x22f0, 0x2319, 0x234a, 0x2372, 0x23a2, 0x23c9, 0x23f9, 0x2420,
// Entry 3E80 - 3EBF
0x2448, 0x246f, 0x2497, 0x24c7, 0x24ee, 0x2516, 0x2546, 0x256d,
0x2596, 0x25bf, 0x25e7, 0x2610, 0x2639, 0x2662, 0x2693, 0x26bb,
0x26f8, 0x271f, 0x2747, 0x276f, 0x2797, 0x27c7, 0x27ee, 0x2829,
0x2863, 0x289e, 0x28d9, 0x2913, 0x293d, 0x2966, 0x2990, 0x29ba,
0x29e3, 0x2a0d, 0x2a36, 0x2a60, 0x2a8a, 0x2ab3, 0x2ade, 0x2b08,
0x2b33, 0x2b5d, 0x2b87, 0x2bb2, 0x2bdd, 0x2c08, 0x2c32, 0x2c5d,
0x2c88, 0x2cb1, 0x2cdb, 0x2d05, 0x2d2f, 0x2d58, 0x2d82, 0x2dac,
0x2dd5, 0x2dff, 0x2e29, 0x2e53, 0x2e7f, 0x2eab, 0x2ed5, 0x2efe,
// Entry 3EC0 - 3EFF
0x2f28, 0x2f52, 0x2f7b, 0x2fa5, 0x2fcf, 0x2ff8, 0x3022, 0x304b,
0x3075, 0x309f, 0x30c8, 0x30f2, 0x311c, 0x3145, 0x3170, 0x319a,
0x31c5, 0x31f0, 0x321b, 0x3245, 0x3270, 0x329b, 0x32c5, 0x32ef,
0x3319, 0x334f, 0x3379, 0x33a2, 0x33cc, 0x33f6, 0x341f, 0x3459,
0x3492, 0x34bb, 0x34e3, 0x350c, 0x3534, 0x355e, 0x3587, 0x35b1,
0x35da, 0x3605, 0x362f, 0x3657, 0x3680, 0x36a9, 0x36d3, 0x36fc,
0x3725, 0x374d, 0x377a, 0x37a7, 0x37d4, 0x3807, 0x3831, 0x3864,
0x388e, 0x38c3, 0x38ef, 0x3923, 0x394e, 0x3983, 0x39af, 0x39e2,
// Entry 3F00 - 3F3F
0x3a0c, 0x3a40, 0x3a6b, 0x3a9f, 0x3aca, 0x3afd, 0x3b27, 0x3b5a,
0x3b84, 0x3bb1, 0x3bdd, 0x3c0a, 0x3c37, 0x3c63, 0x3c8e, 0x3cb8,
0x3ce2, 0x3d12, 0x3d39, 0x3d69, 0x3d90, 0x3dc2, 0x3deb, 0x3e1c,
0x3e44, 0x3e76, 0x3e9f, 0x3ecf, 0x3ef6, 0x3f27, 0x3f4f, 0x3f80,
0x3fa8, 0x3fd8, 0x3fff, 0x402f, 0x4056, 0x4080, 0x40a9, 0x40d3,
0x40fd, 0x4126, 0x414e, 0x4175, 0x419c, 0x41c8, 0x41f3, 0x421f,
0x424b, 0x4275, 0x42a0, 0x42ca, 0x42f4, 0x431d, 0x4347, 0x4372,
0x439c, 0x43c7, 0x43f0, 0x4419, 0x4446, 0x4476, 0x448d, 0x44a5,
// Entry 3F40 - 3F7F
0x44c4, 0x44e4, 0x4506, 0x4528, 0x454c, 0x4570, 0x459b, 0x45bb,
0x45dc, 0x45ff, 0x462b, 0x4649, 0x467e, 0x469f, 0x46c3, 0x46e3,
0x4717, 0x4748, 0x477b, 0x47ae, 0x47e2, 0x4816, 0x4849, 0x487d,
0x48af, 0x48e3, 0x4914, 0x494e, 0x4982, 0x49b6, 0x49f1, 0x4a23,
0x4a57, 0x4a8c, 0x4abf, 0x4af4, 0x4b24, 0x4b56, 0x4b88, 0x4bbb,
0x4bf0, 0x4c23, 0x4c57, 0x4c8d, 0x4cc1, 0x4cf7, 0x4d30, 0x4d62,
0x4d96, 0x4dc7, 0x4dfa, 0x4e2e, 0x4e5f, 0x4e91, 0x4ec3, 0x4ef7,
0x4f31, 0x4f65, 0x4f98, 0x4fd4, 0x5006, 0x503a, 0x506b, 0x509d,
// Entry 3F80 - 3FBF
0x50ce, 0x50fe, 0x5137, 0x516b, 0x519d, 0x51cf, 0x5203, 0x5234,
0x5267, 0x529b, 0x52cf, 0x5300, 0x5334, 0x5369, 0x539e, 0x53d3,
0x5408, 0x543c, 0x5470, 0x54a4, 0x54de, 0x5511, 0x5546, 0x5581,
0x55b3, 0x55ee, 0x5620, 0x5654, 0x5685, 0x56b6, 0x56f0, 0x5721,
0x575b, 0x578c, 0x57c6, 0x57f8, 0x5832, 0x586d, 0x58a8, 0x58d8,
0x590a, 0x593a, 0x596b, 0x599c, 0x59cc, 0x59fd, 0x5a2e, 0x5a60,
0x5a91, 0x5ac2, 0x5af5, 0x5b28, 0x5b59, 0x5b8a, 0x5bbe, 0x5bf0,
0x5c24, 0x5c56, 0x5c88, 0x5cba, 0x5ceb, 0x5d1c, 0x5d4e, 0x5d7f,
// Entry 3FC0 - 3FFF
0x5daf, 0x5de3, 0x5e17, 0x5e4b, 0x5e7d, 0x5eaf, 0x5ed0, 0x5f0d,
0x5f49, 0x5f6c, 0x5f8f, 0x5fb5, 0x5fd8, 0x5ffc, 0x6020, 0x6046,
0x6069, 0x6094, 0x60b3, 0x60bc, 0x60e9, 0x610e, 0x612a, 0x613e,
0x6152, 0x6166, 0x617a, 0x618e, 0x61a2, 0x61b6, 0x61ca, 0x61de,
0x61f3, 0x6208, 0x621d, 0x6232, 0x6247, 0x625c, 0x6271, 0x6295,
0x62c5, 0x62f9, 0x631d, 0x6345, 0x6374, 0x63a0, 0x63dc, 0x6419,
0x644b, 0x6467, 0x6484, 0x64a4, 0x64c5, 0x64df, 0x64fa, 0x6515,
0x6537, 0x655a, 0x6579, 0x6599, 0x65b9, 0x65da, 0x65fb, 0x661d,
// Entry 4000 - 403F
0x6640, 0x666d, 0x6693, 0x66b9, 0x66e0, 0x670c, 0x673b, 0x676b,
0x679c, 0x67ce, 0x6808, 0x6843, 0x687f, 0x68bc, 0x68f4, 0x692d,
0x695e, 0x6990, 0x69c2, 0x69f5, 0x6a2d, 0x6a66, 0x6a70, 0x6a80,
0x6ab2, 0x6ae5, 0x6af4, 0x6b07, 0x6b14, 0x6b28, 0x6b37, 0x6b4a,
0x6b57, 0x6b62, 0x6b79, 0x6b88, 0x6b97, 0x6ba2, 0x6bb5, 0x6bcb,
0x6bd8, 0x6bee, 0x6c05, 0x6c1d, 0x6c36, 0x6c57, 0x6c79, 0x6c8a,
0x6c99, 0x6ca7, 0x6cb6, 0x6cc8, 0x6cdc, 0x6cf3, 0x6d04, 0x6d19,
0x6d2a, 0x6d3c, 0x6d4f, 0x6d6c, 0x6d8e, 0x6dab, 0x6dbf, 0x6ddc,
// Entry 4040 - 407F
0x6df6, 0x6e0e, 0x6e28, 0x6e40, 0x6e5a, 0x6e72, 0x6e8d, 0x6ea6,
0x6ec0, 0x6ed8, 0x6ef9, 0x6f2a, 0x6f58, 0x6f89, 0x6fb7, 0x6fe7,
0x7014, 0x7045, 0x7073, 0x70a3, 0x70d0, 0x70ff, 0x712d, 0x714d,
0x716a, 0x7189, 0x71a5, 0x71c3, 0x71e0, 0x7207, 0x722b, 0x724a,
0x7266, 0x7284, 0x72a1, 0x72c1, 0x72de, 0x72fd, 0x731b, 0x733b,
0x7358, 0x7377, 0x7395, 0x73b4, 0x73d0, 0x73ee, 0x740b, 0x742b,
0x7448, 0x7467, 0x7485, 0x74a4, 0x74c0, 0x74e0, 0x74fd, 0x751c,
0x7538, 0x7558, 0x7575, 0x7595, 0x75b2, 0x75d1, 0x75ef, 0x7610,
// Entry 4080 - 40BF
0x762e, 0x764e, 0x766d, 0x768c, 0x76a8, 0x76c6, 0x76e3, 0x7702,
0x771e, 0x773c, 0x7759, 0x7778, 0x7794, 0x77b2, 0x77cf, 0x77ee,
0x780a, 0x7828, 0x7845, 0x7864, 0x7880, 0x789e, 0x78bb, 0x78dc,
0x78fa, 0x791a, 0x7939, 0x7958, 0x7974, 0x7992, 0x79af, 0x79ce,
0x79ea, 0x7a08, 0x7a25, 0x7a44, 0x7a60, 0x7a7e, 0x7a9b, 0x7aba,
0x7ad6, 0x7af4, 0x7b11, 0x7b31, 0x7b4e, 0x7b6d, 0x7b8b, 0x7bab,
0x7bc8, 0x7be7, 0x7c05, 0x7c24, 0x7c40, 0x7c5e, 0x7c7b, 0x7c9a,
0x7cb6, 0x7cde, 0x7d03, 0x7d22, 0x7d3e, 0x7d5c, 0x7d79, 0x7db5,
// Entry 40C0 - 40FF
0x7dee, 0x7e2a, 0x7e63, 0x7e9f, 0x7ed8, 0x7f03, 0x7f2b, 0x7f44,
0x7f5e, 0x7f76, 0x7f8b, 0x7fa0, 0x7fb6, 0x7fc9, 0x7fdd, 0x7ff7,
0x8012, 0x8024, 0x8037, 0x8046, 0x805c, 0x806f, 0x8080, 0x8094,
0x80a7, 0x80ba, 0x80cf, 0x80e3, 0x80f7, 0x810a, 0x811f, 0x8134,
0x8148, 0x8157, 0x816a, 0x8182, 0x8197, 0x81b2, 0x81c9, 0x81e0,
0x8200, 0x8220, 0x8240, 0x8260, 0x8280, 0x82a0, 0x82c0, 0x82e0,
0x8300, 0x8320, 0x8340, 0x8360, 0x8380, 0x83a0, 0x83c0, 0x83e0,
0x8400, 0x8420, 0x8440, 0x8460, 0x8480, 0x84a0, 0x84c0, 0x84e0,
// Entry 4100 - 413F
0x8500, 0x8520, 0x853d, 0x8556, 0x8574, 0x858f, 0x85a1, 0x85b7,
0x85d5, 0x85f3, 0x8611, 0x862f, 0x864d, 0x866b, 0x8689, 0x86a7,
0x86c5, 0x86e3, 0x8701, 0x871f, 0x873d, 0x875b, 0x8779, 0x8797,
0x87b5, 0x87d3, 0x87f1, 0x880f, 0x882d, 0x884b, 0x8869, 0x8887,
0x88a5, 0x88c3, 0x88df, 0x88f6, 0x8913, 0x8922, 0x8942, 0x8963,
0x8982, 0x899f, 0x89bd, 0x89d8, 0x89f5, 0x8a11, 0x8a32, 0x8a53,
0x8a74, 0x8a95, 0x8ab6, 0x8ad8, 0x8afa, 0x8b1c, 0x8b3e, 0x8b6e,
0x8b89, 0x8ba4, 0x8bbf, 0x8bda, 0x8bf5, 0x8c11, 0x8c2d, 0x8c49,
// Entry 4140 - 417F
0x8c65, 0x8c81, 0x8c9d, 0x8cb9, 0x8cd5, 0x8cf1, 0x8d0d, 0x8d29,
0x8d45, 0x8d61, 0x8d7d, 0x8d99, 0x8db5, 0x8dd1, 0x8ded, 0x8e09,
0x8e25, 0x8e41, 0x8e5d, 0x8e79, 0x8e95, 0x8eb1, 0x8ecd, 0x8ee9,
0x8f05, 0x8f21, 0x8f3d, 0x8f59, 0x8f75, 0x8f91, 0x8fad, 0x8fc9,
0x8fe5, 0x9001, 0x901d, 0x9039, 0x9054, 0x9078, 0x90a1, 0x90b8,
0x90d6, 0x90f9, 0x911c, 0x9139, 0x915c, 0x917f, 0x919d, 0x91c0,
0x91dd, 0x9201, 0x9224, 0x9247, 0x9269, 0x928e, 0x92b3, 0x92d6,
0x92f3, 0x9310, 0x9332, 0x9354, 0x9370, 0x9391, 0x93ae, 0x93cb,
// Entry 4180 - 41BF
0x93ed, 0x940c, 0x942b, 0x944a, 0x9469, 0x9486, 0x949f, 0x94b9,
0x94d3, 0x94ee, 0x9508, 0x9521, 0x953c, 0x9556, 0x956f, 0x9589,
0x95a4, 0x95be, 0x95d8, 0x95f1, 0x960c, 0x9626, 0x9640, 0x965a,
0x9674, 0x968e, 0x96a7, 0x96ba, 0x96ce, 0x96e0, 0x96f0, 0x9704,
0x9716, 0x9728, 0x9746, 0x975f, 0x9776, 0x9790, 0x97a9, 0x97bf,
0x97d5, 0x97f2, 0x9812, 0x9833, 0x984f, 0x9864, 0x987c, 0x9894,
0x98ac, 0x98c4, 0x98dc, 0x98f5, 0x990e, 0x9927, 0x9940, 0x9959,
0x9972, 0x998b, 0x99a4, 0x99bd, 0x99d6, 0x99ef, 0x9a08, 0x9a21,
// Entry 41C0 - 41FF
0x9a3a, 0x9a53, 0x9a6c, 0x9a85, 0x9a9e, 0x9ab7, 0x9ad0, 0x9ae9,
0x9b02, 0x9b1b, 0x9b34, 0x9b4d, 0x9b66, 0x9b7f, 0x9b98, 0x9bb1,
0x9bca, 0x9be3, 0x9bfc, 0x9c15, 0x9c2e, 0x9c47, 0x9c60, 0x9c79,
0x9c92, 0x9cab, 0x9cc4, 0x9cdd, 0x9cf6, 0x9d0f, 0x9d28, 0x9d41,
0x9d5a, 0x9d73, 0x9d8c, 0x9da5, 0x9dbe, 0x9dd7, 0x9df0, 0x9e09,
0x9e22, 0x9e3b, 0x9e54, 0x9e6d, 0x9e86, 0x9ea0, 0x9eba, 0x9ed4,
0x9eee, 0x9f08, 0x9f22, 0x9f3c, 0x9f56, 0x9f70, 0x9f8a, 0x9fa4,
0x9fb8, 0x9fcc, 0x9fe0, 0x9ff4, 0xa008, 0xa01c, 0xa030, 0xa044,
// Entry 4200 - 423F
0xa058, 0xa06c, 0xa080, 0xa094, 0xa0a8, 0xa0bc, 0xa0d6, 0xa0f2,
0xa10d, 0xa129, 0xa145, 0xa165, 0xa180, 0xa19b, 0xa1bb, 0xa1da,
0xa1f5, 0xa211, 0xa22c, 0xa248, 0xa264, 0xa281, 0xa29d, 0xa2b9,
0xa2d7, 0xa2f2, 0xa30f, 0xa329, 0xa344, 0xa35a, 0xa376, 0xa391,
0xa3ae, 0xa3c9, 0xa3df, 0xa3fa, 0xa410, 0xa426, 0xa441, 0xa457,
0xa46d, 0xa483, 0xa49f, 0xa4b5, 0xa4cb, 0xa4e7, 0xa4fd, 0xa513,
0xa531, 0xa54e, 0xa564, 0xa57a, 0xa590, 0xa5a6, 0xa5bc, 0xa5d2,
0xa5e8, 0xa5fe, 0xa614, 0xa630, 0xa646, 0xa661, 0xa677, 0xa68d,
// Entry 4240 - 427F
0xa6a3, 0xa6b9, 0xa6cf, 0xa6e5, 0xa6fb, 0xa711, 0xa727, 0xa73d,
0xa753, 0xa770, 0xa790, 0xa7ae, 0xa7ca, 0xa7e6, 0xa7fc, 0xa818,
0xa82e, 0xa844, 0xa86a, 0xa888, 0xa8ac, 0xa8c8, 0xa8de, 0xa8f4,
0xa910, 0xa926, 0xa93c, 0xa952, 0xa968, 0xa97e, 0xa999, 0xa9af,
0xa9c5, 0xa9db, 0xa9f1, 0xaa07, 0xaa24, 0xaa41, 0xaa5e, 0xaa7b,
0xaa98, 0xaab5, 0xaad2, 0xaaef, 0xab0c, 0xab29, 0xab46, 0xab63,
0xab80, 0xab9d, 0xabba, 0xabd7, 0xabf4, 0xac11, 0xac2e, 0xac4b,
0xac68, 0xac85, 0xaca2, 0xacbf, 0xacdc, 0xacf9, 0xad16, 0xad33,
// Entry 4280 - 42BF
0xad50, 0xad6a, 0xad83, 0xad94, 0xada5, 0xadb6, 0xadc9, 0xaddb,
0xaded, 0xadfe, 0xae11, 0xae24, 0xae36, 0xae47, 0xae5b, 0xae6f,
0xae82, 0xae95, 0xaea8, 0xaebd, 0xaed1, 0xaee5, 0xaefe, 0xaf17,
0xaf32, 0xaf4c, 0xaf66, 0xaf7f, 0xaf9a, 0xafb5, 0xafcf, 0xafe9,
0xb003, 0xb01f, 0xb03a, 0xb055, 0xb06f, 0xb08b, 0xb0a7, 0xb0c2,
0xb0dc, 0xb0f9, 0xb116, 0xb132, 0xb14e, 0xb16a, 0xb188, 0xb1a5,
0xb1c2, 0xb1d9, 0xb1f4, 0xb210, 0xb22b, 0xb247, 0xb267, 0xb28a,
0xb2a7, 0xb2c3, 0xb2e5, 0xb304, 0xb326, 0xb341, 0xb35d, 0xb380,
// Entry 42C0 - 42FF
0xb3a4, 0xb3c9, 0xb3ec, 0xb40e, 0xb432, 0xb45c, 0xb487, 0xb4b2,
0xb4de, 0xb501, 0xb523, 0xb547, 0xb571, 0xb59c, 0xb5c7, 0xb5f2,
0xb61f, 0xb63e, 0xb663, 0xb680, 0xb69f, 0xb6be, 0xb6db, 0xb701,
0xb729, 0xb749, 0xb768, 0xb796, 0xb7b5, 0xb7d3, 0xb7f0, 0xb810,
0xb831, 0xb861, 0xb882, 0xb8a1, 0xb8c6, 0xb8ed, 0xb915, 0xb93d,
0xb963, 0xb98a, 0xb9ae, 0xb9d4, 0xb9fb, 0xba1d, 0xba41, 0xba54,
0xba76, 0xba8b, 0xbaa4, 0xbab3, 0xbac4, 0xbad6, 0xbae5, 0xbaf9,
0xbb0f, 0xbb24, 0xbb39, 0xbb4c, 0xbb63, 0xbb73, 0xbb84, 0xbb95,
// Entry 4300 - 433F
0xbba6, 0xbbb7, 0xbbc8, 0xbbe0, 0xbbef, 0xbc05, 0xbc18, 0xbc2c,
0xbc38, 0xbc4a, 0xbc5a, 0xbc6d, 0xbc7f, 0xbc99, 0xbcab, 0xbcbe,
0xbcd2, 0xbce7, 0xbcfb, 0xbd08, 0xbd1c, 0xbd28, 0xbd3c, 0xbd59,
0xbd77, 0xbd97, 0xbdb1, 0xbdc9, 0xbde1, 0xbdfa, 0xbe15, 0xbe2d,
0xbe45, 0xbe5b, 0xbe74, 0xbe8b, 0xbea6, 0xbec0, 0xbed6, 0xbeec,
0xbf08, 0xbf2a, 0xbf43, 0xbf5a, 0xbf72, 0xbf8b, 0xbfa5, 0xbfbc,
0xbfd3, 0xbfea, 0xc006, 0xc01c, 0xc032, 0xc04a, 0xc061, 0xc079,
0xc08f, 0xc0ac, 0xc0c3, 0xc0dd, 0xc0f7, 0xc10e, 0xc128, 0xc140,
// Entry 4340 - 437F
0xc159, 0xc174, 0xc190, 0xc1ac, 0xc1d7, 0xc1e6, 0xc1f5, 0xc204,
0xc214, 0xc223, 0xc232, 0xc241, 0xc250, 0xc25f, 0xc26f, 0xc27e,
0xc28d, 0xc29c, 0xc2ab, 0xc2ba, 0xc2c9, 0xc2d9, 0xc2e9, 0xc2f8,
0xc307, 0xc317, 0xc326, 0xc335, 0xc344, 0xc354, 0xc364, 0xc374,
0xc383, 0xc392, 0xc3a1, 0xc3b1, 0xc3c0, 0xc3cf, 0xc3e0, 0xc3ef,
0xc3ff, 0xc40f, 0xc41e, 0xc42d, 0xc43c, 0xc44b, 0xc45b, 0xc46a,
0xc47a, 0xc48b, 0xc49a, 0xc4ac, 0xc4bb, 0xc4cb, 0xc4da, 0xc4e9,
0xc4fa, 0xc509, 0xc519, 0xc528, 0xc537, 0xc549, 0xc558, 0xc568,
// Entry 4380 - 43BF
0xc578, 0xc588, 0xc597, 0xc5a7, 0xc5b7, 0xc5c8, 0xc5d8, 0xc5e8,
0xc5fa, 0xc60a, 0xc61c, 0xc62c, 0xc63c, 0xc64d, 0xc65e, 0xc66f,
0xc680, 0xc690, 0xc6a2, 0xc6bd, 0xc6d3, 0xc6e9, 0xc701, 0xc718,
0xc72f, 0xc745, 0xc75d, 0xc775, 0xc78c, 0xc7a3, 0xc7bd, 0xc7d7,
0xc7f0, 0xc809, 0xc822, 0xc83d, 0xc857, 0xc871, 0xc890, 0xc8af,
0xc8d0, 0xc8f0, 0xc910, 0xc92f, 0xc950, 0xc971, 0xc991, 0xc9a4,
0xc9b8, 0xc9cc, 0xc9e0, 0xc9f3, 0xca07, 0xca1b, 0xca2f, 0xca44,
0xca57, 0xca6b, 0xca7f, 0xca93, 0xcaa7, 0xcabc, 0xcacf, 0xcae3,
// Entry 43C0 - 43FF
0xcaf8, 0xcb0c, 0xcb20, 0xcb34, 0xcb48, 0xcb5b, 0xcb70, 0xcb85,
0xcb9a, 0xcbae, 0xcbc3, 0xcbd8, 0xcbec, 0xcc00, 0xcc15, 0xcc2b,
0xcc42, 0xcc58, 0xcc70, 0xcc84, 0xcca2, 0xccc0, 0xccd2, 0xcce7,
0xccf9, 0xcd0b, 0xcd1f, 0xcd35, 0xcd47, 0xcd59, 0xcd6d, 0xcd7e,
0xcd91, 0xcda4, 0xcdb7, 0xcdcb, 0xcddc, 0xcdee, 0xce04, 0xce18,
0xce2b, 0xce3e, 0xce51, 0xce64, 0xce77, 0xce8a, 0xce9d, 0xceb0,
0xceca, 0xcede, 0xcef3, 0xcf08, 0xcf1d, 0xcf30, 0xcf46, 0xcf5d,
0xcf73, 0xcf8a, 0xcf9d, 0xcfb3, 0xcfc8, 0xcfdf, 0xcff6, 0xd00c,
// Entry 4400 - 443F
0xd022, 0xd037, 0xd04c, 0xd061, 0xd074, 0xd08b, 0xd0a2, 0xd0bb,
0xd0d0, 0xd0e6, 0xd0f9, 0xd10d, 0xd121, 0xd135, 0xd14b, 0xd160,
0xd175, 0xd18b, 0xd1a0, 0xd1b4, 0xd1c8, 0xd1dc, 0xd1f0, 0xd20e,
0xd22d, 0xd24d, 0xd26e, 0xd28d, 0xd2a1, 0xd2b5, 0xd2ca, 0xd2dd,
0xd2f2, 0xd304, 0xd316, 0xd32a, 0xd33e, 0xd351, 0xd364, 0xd377,
0xd38b, 0xd3a0, 0xd3b3, 0xd3c7, 0xd3da, 0xd3ec, 0xd401, 0xd414,
0xd426, 0xd43a, 0xd44e, 0xd463, 0xd479, 0xd48e, 0xd4a0, 0xd4b1,
0xd4c2, 0xd4d5, 0xd4ea, 0xd4fc, 0xd50e, 0xd520, 0xd533, 0xd546,
// Entry 4440 - 447F
0xd559, 0xd56c, 0xd57f, 0xd592, 0xd5a5, 0xd5b8, 0xd5cb, 0xd5de,
0xd5f1, 0xd604, 0xd617, 0xd62b, 0xd63e, 0xd651, 0xd664, 0xd677,
0xd68a, 0xd69d, 0xd6b0, 0xd6c3, 0xd6d6, 0xd6e9, 0xd6fc, 0xd70f,
0xd722, 0xd735, 0xd748, 0xd75b, 0xd76f, 0xd783, 0xd796, 0xd7b1,
0xd7ce, 0xd7eb, 0xd808, 0xd822, 0xd83e, 0xd853, 0xd86b, 0xd883,
0xd899, 0xd8af, 0xd8c5, 0xd8de, 0xd8f8, 0xd915, 0xd932, 0xd94f,
0xd96d, 0xd98a, 0xd9a8, 0xd9c6, 0xd9e4, 0xda02, 0xda21, 0xda3f,
0xda5e, 0xda77, 0xda90, 0xdaa9, 0xdac3, 0xdadb, 0xdaf5, 0xdb0f,
// Entry 4480 - 44BF
0xdb29, 0xdb43, 0xdb5e, 0xdb78, 0xdb92, 0xdbac, 0xdbc5, 0xdbdf,
0xdbf9, 0xdc14, 0xdc2d, 0xdc47, 0xdc61, 0xdc7c, 0xdc95, 0xdcae,
0xdcc7, 0xdce0, 0xdcfa, 0xdd13, 0xdd2c, 0xdd47, 0xdd62, 0xdd7d,
0xdd99, 0xddb4, 0xddd0, 0xddec, 0xde08, 0xde24, 0xde41, 0xde5d,
0xde7a, 0xde91, 0xdea8, 0xdebf, 0xded7, 0xdeed, 0xdf05, 0xdf1d,
0xdf35, 0xdf4d, 0xdf66, 0xdf7e, 0xdf96, 0xdfae, 0xdfc5, 0xdfdd,
0xdff5, 0xe00e, 0xe025, 0xe03d, 0xe055, 0xe06e, 0xe085, 0xe09c,
0xe0b3, 0xe0ca, 0xe0e2, 0xe0f9, 0xe110, 0xe123, 0xe135, 0xe148,
// Entry 44C0 - 44FF
0xe15a, 0xe16e, 0xe17f, 0xe192, 0xe1a7, 0xe1b9, 0xe1cc, 0xe1de,
0xe1f1, 0xe203, 0xe215, 0xe228, 0xe23a, 0xe250, 0xe264, 0xe276,
0xe28a, 0xe29d, 0xe2b0, 0xe2c1, 0xe2d3, 0xe2e5, 0xe2f7, 0xe308,
0xe31b, 0xe32d, 0xe33e, 0xe351, 0xe363, 0xe375, 0xe387, 0xe399,
0xe3aa, 0xe3bc, 0xe3cf, 0xe3e1, 0xe3f3, 0xe405, 0xe416, 0xe428,
0xe43a, 0xe44e, 0xe460, 0xe472, 0xe484, 0xe497, 0xe4a8, 0xe4b9,
0xe4ca, 0xe4db, 0xe4ed, 0xe500, 0xe511, 0xe522, 0xe536, 0xe548,
0xe55b, 0xe56c, 0xe57d, 0xe590, 0xe5a3, 0xe5b6, 0xe5c9, 0xe5dc,
// Entry 4500 - 453F
0xe5ee, 0xe5ff, 0xe610, 0xe620, 0xe630, 0xe640, 0xe650, 0xe660,
0xe671, 0xe682, 0xe693, 0xe6a5, 0xe6b6, 0xe6c7, 0xe6da, 0xe6ec,
0xe6fe, 0xe70f, 0xe722, 0xe735, 0xe747, 0xe75d, 0xe774, 0xe78c,
0xe7a3, 0xe7bb, 0xe7d3, 0xe7ed, 0xe803, 0xe81b, 0xe832, 0xe84a,
0xe860, 0xe877, 0xe890, 0xe8a8, 0xe8bf, 0xe8d6, 0xe8ed, 0xe903,
0xe91b, 0xe932, 0xe94b, 0xe962, 0xe97a, 0xe991, 0xe9aa, 0xe9c2,
0xe9dc, 0xe9f5, 0xea0d, 0xea23, 0xea3a, 0xea52, 0xea6a, 0xea81,
0xea99, 0xeaad, 0xeac2, 0xead8, 0xeaed, 0xeb03, 0xeb19, 0xeb31,
// Entry 4540 - 457F
0xeb45, 0xeb5b, 0xeb70, 0xeb86, 0xeb9a, 0xebaf, 0xebc6, 0xebdc,
0xebf1, 0xec06, 0xec1b, 0xec2f, 0xec45, 0xec5a, 0xec71, 0xec86,
0xec9c, 0xecb1, 0xecc8, 0xecde, 0xecf6, 0xed0d, 0xed23, 0xed37,
0xed4c, 0xed62, 0xed78, 0xed8d, 0xeda3, 0xedb3, 0xedc4, 0xedd5,
0xede7, 0xedf8, 0xee0a, 0xee1c, 0xee2d, 0xee3d, 0xee4e, 0xee5f,
0xee71, 0xee82, 0xee92, 0xeea3, 0xeeb4, 0xeec5, 0xeed7, 0xeee8,
0xeef9, 0xef0a, 0xef1c, 0xef2c, 0xef3d, 0xef4e, 0xef5f, 0xef71,
0xef82, 0xef94, 0xefa5, 0xefb7, 0xefc7, 0xefd8, 0xefe9, 0xeff9,
// Entry 4580 - 45BF
0xf00a, 0xf01c, 0xf02e, 0xf043, 0xf055, 0xf072, 0xf08f, 0xf0ac,
0xf0c9, 0xf0e5, 0xf103, 0xf120, 0xf13e, 0xf15b, 0xf178, 0xf196,
0xf1b3, 0xf1d0, 0xf1ed, 0xf20a, 0xf228, 0xf246, 0xf264, 0xf281,
0xf29f, 0xf2bc, 0xf2da, 0xf2f8, 0xf315, 0xf332, 0xf350, 0xf36d,
0xf38b, 0xf3a8, 0xf3c5, 0xf3e3, 0xf402, 0xf420, 0xf43e, 0xf45a,
0xf478, 0xf495, 0xf4b3, 0xf4d1, 0xf4ee, 0xf50d, 0xf52a, 0xf548,
0xf566, 0xf584, 0xf5a2, 0xf5bf, 0xf5dd, 0xf5fb, 0xf619, 0xf637,
0xf654, 0xf674, 0xf68d, 0xf6a8, 0xf6c2, 0xf6dc, 0xf6f7, 0xf711,
// Entry 45C0 - 45FF
0xf72c, 0xf746, 0xf75f, 0xf779, 0xf793, 0xf7ad, 0xf7c8, 0xf7e1,
0xf7fc, 0xf816, 0xf830, 0xf84a, 0xf865, 0xf87f, 0xf899, 0xf8b4,
0xf8cd, 0xf8e7, 0xf901, 0xf91b, 0xf935, 0xf950, 0xf96a, 0xf985,
0xf99e, 0xf9b8, 0xf9d2, 0xf9eb, 0xfa05, 0xfa1c, 0xfa35, 0xfa4d,
0xfa65, 0xfa7e, 0xfa96, 0xfaaf, 0xfac7, 0xfade, 0xfaf6, 0xfb0e,
0xfb26, 0xfb3f, 0xfb56, 0xfb6f, 0xfb87, 0xfb9f, 0xfbb7, 0xfbd0,
0xfbe8, 0xfc00, 0xfc19, 0xfc30, 0xfc48, 0xfc60, 0xfc78, 0xfc90,
0xfca9, 0xfcc1, 0xfcda, 0xfcf1, 0xfd09, 0xfd21, 0xfd38, 0xfd50,
// Entry 4600 - 463F
0xfd63, 0xfd76, 0xfd89, 0xfd9c, 0xfdaf, 0xfdc2, 0xfdd5, 0xfde8,
0xfdfb, 0xfe0e, 0xfe21, 0xfe34, 0xfe47, 0xfe5a, 0xfe6d, 0xfe80,
0xfe94, 0xfea8, 0xfebb, 0xfecf, 0xfee3, 0xfef6, 0xff0a, 0xff1d,
0xff30, 0xff43, 0xff56, 0xff69, 0xff7c, 0xff8f, 0xffa2, 0xffb5,
0xffc8, 0xffdb, 0xffee, 0x0001, 0x0014, 0x0027, 0x003a, 0x004d,
0x0060, 0x0073, 0x0086, 0x0099, 0x00ac, 0x00bf, 0x00d2, 0x00e5,
0x00f8, 0x010b, 0x011e, 0x0131, 0x0144, 0x0157, 0x016a, 0x017d,
0x0190, 0x01a3, 0x01b6, 0x01c9, 0x01dc, 0x01ef, 0x0202, 0x0215,
// Entry 4640 - 467F
0x0228, 0x023b, 0x024e, 0x0261, 0x0274, 0x0287, 0x029a, 0x02b0,
0x02c3, 0x02d6, 0x02e9, 0x02fc, 0x030f, 0x0323, 0x0337, 0x034a,
0x035d, 0x0370, 0x0383, 0x0396, 0x03a9, 0x03bb, 0x03cd, 0x03df,
0x03f1, 0x0403, 0x0415, 0x0427, 0x0439, 0x044c, 0x045f, 0x0472,
0x0484, 0x0496, 0x04a8, 0x04bb, 0x04ce, 0x04e1, 0x04f3, 0x0505,
0x0517, 0x0529, 0x053b, 0x054d, 0x055f, 0x0571, 0x0583, 0x0595,
0x05a7, 0x05b9, 0x05cb, 0x05dd, 0x05ef, 0x0601, 0x0613, 0x0625,
0x0637, 0x0649, 0x065b, 0x066d, 0x067f, 0x0691, 0x06a3, 0x06b5,
// Entry 4680 - 46BF
0x06c7, 0x06d9, 0x06eb, 0x06fd, 0x070f, 0x0721, 0x0733, 0x0745,
0x0757, 0x0769, 0x077b, 0x078d, 0x079f, 0x07b1, 0x07c3, 0x07d5,
0x07e7, 0x07f9, 0x080b, 0x081d, 0x082f, 0x0841, 0x0853, 0x0865,
0x0877, 0x0889, 0x089b, 0x08ad, 0x08bf, 0x08d1, 0x08e3, 0x08f5,
0x090b, 0x0921, 0x0937, 0x094d, 0x0963, 0x0979, 0x098f, 0x09a5,
0x09bb, 0x09d1, 0x09e7, 0x09fd, 0x0a13, 0x0a29, 0x0a3f, 0x0a55,
0x0a6b, 0x0a81, 0x0a97, 0x0aa9, 0x0abb, 0x0acd, 0x0adf, 0x0af1,
0x0b03, 0x0b15, 0x0b27, 0x0b39, 0x0b4b, 0x0b5d, 0x0b6f, 0x0b81,
// Entry 46C0 - 46FF
0x0b93, 0x0ba5, 0x0bb7, 0x0bc9, 0x0bdb, 0x0bed, 0x0bff, 0x0c11,
0x0c23, 0x0c35, 0x0c47, 0x0c59, 0x0c6b, 0x0c7d, 0x0c8f, 0x0ca1,
0x0cb3, 0x0cc5, 0x0cd7, 0x0ce9, 0x0cfb, 0x0d0d, 0x0d1f, 0x0d31,
0x0d43, 0x0d55, 0x0d67, 0x0d79, 0x0d8b, 0x0d9d, 0x0daf, 0x0dc1,
0x0dd3, 0x0de5, 0x0df7, 0x0e09, 0x0e1b, 0x0e2d, 0x0e3f, 0x0e51,
0x0e63, 0x0e75, 0x0e87, 0x0e99, 0x0eab, 0x0ebd, 0x0ecf, 0x0ee1,
0x0ef3, 0x0f05, 0x0f17, 0x0f29, 0x0f3b, 0x0f4d, 0x0f5f, 0x0f71,
0x0f83, 0x0f95, 0x0fa7, 0x0fb9, 0x0fcb, 0x0fdd, 0x0fef, 0x1001,
// Entry 4700 - 473F
0x1013, 0x1025, 0x1037, 0x1049, 0x105b, 0x106d, 0x107f, 0x1091,
0x10a3, 0x10b5, 0x10c7, 0x10d9, 0x10eb, 0x10fd, 0x110f, 0x1121,
0x1133, 0x1145, 0x1157, 0x1169, 0x117b, 0x118d, 0x119f, 0x11b1,
0x11c3, 0x11d5, 0x11e7, 0x11f9, 0x120b, 0x121d, 0x122f, 0x1241,
0x1253, 0x1265, 0x1277, 0x1289, 0x129b, 0x12ad, 0x12bf, 0x12d1,
0x12e3, 0x12f5, 0x1307, 0x1319, 0x132b, 0x133d, 0x134f, 0x1361,
0x1373, 0x1385, 0x1397, 0x13a9, 0x13bb, 0x13cd, 0x13df, 0x13f3,
0x1407, 0x141b, 0x142f, 0x1443, 0x1457, 0x146b, 0x147f, 0x1493,
// Entry 4740 - 477F
0x14aa, 0x14c1, 0x14d8, 0x14ef, 0x1503, 0x1517, 0x152b, 0x1543,
0x1559, 0x156e, 0x1583, 0x159a, 0x15af, 0x15c1, 0x15d3, 0x15e5,
0x15f7, 0x1609, 0x161b, 0x162d, 0x163f, 0x165f, 0x168b, 0x16bc,
0x16d4, 0x16f3, 0x1714, 0x1734, 0x1768, 0x1792, 0x17b4, 0x17d5,
0x17f6, 0x1820, 0x1840, 0x186c, 0x188e, 0x18ad, 0x18cc, 0x18ed,
0x1916, 0x1939, 0x1958, 0x197c, 0x19b0, 0x19d0, 0x19f0, 0x1a11,
0x1a3a, 0x1a6e, 0x1a88, 0x1ab6, 0x1ad4, 0x1afc, 0x1b1f, 0x1b3f,
0x1b61, 0x1b78, 0x1ba4, 0x1be3, 0x1c04, 0x1c29, 0x1c48, 0x1c72,
// Entry 4780 - 47BF
0x1c92, 0x1cc6, 0x1ce8, 0x1d13, 0x1d3a, 0x1d59, 0x1d81, 0x1db2,
0x1dd0, 0x1dec, 0x1e09, 0x1e27, 0x1e5a, 0x1e7b, 0x1e8d, 0x1e9f,
0x1eb1, 0x1ec3, 0x1ed5, 0x1ee8, 0x1efb, 0x1f0e, 0x1f21, 0x1f34,
0x1f47, 0x1f5a, 0x1f6d, 0x1f80, 0x1f93, 0x1fa6, 0x1fb9, 0x1fcc,
0x1fdf, 0x1ff2, 0x2005, 0x2018, 0x202b, 0x203e, 0x2051, 0x2064,
0x2077, 0x208a, 0x209d, 0x20b0, 0x20c3, 0x20d6, 0x20e9, 0x20fc,
0x210f, 0x2122, 0x2135, 0x2148, 0x215b, 0x216e, 0x2181, 0x2194,
0x21a7, 0x21ba, 0x21cd, 0x21e0, 0x21f3, 0x2206, 0x2219, 0x222c,
// Entry 47C0 - 47FF
0x223f, 0x2252, 0x2265, 0x2278, 0x228b, 0x22a8, 0x22c4, 0x22e1,
0x22ff, 0x2319, 0x2334, 0x2351, 0x236d, 0x2389, 0x23a5, 0x23c1,
0x23df, 0x23fa, 0x2415, 0x2433, 0x244f, 0x2469, 0x2486, 0x24a2,
0x24be, 0x24da, 0x24f5, 0x2512, 0x252d, 0x2548, 0x2565, 0x2580,
0x259e, 0x25c1, 0x25e5, 0x2609, 0x261f, 0x2634, 0x264a, 0x2661,
0x2674, 0x2688, 0x269e, 0x26b3, 0x26c8, 0x26dd, 0x26f2, 0x2709,
0x271d, 0x2737, 0x274b, 0x2762, 0x2777, 0x278a, 0x27a0, 0x27b5,
0x27ca, 0x27df, 0x27f3, 0x2812, 0x2832, 0x2846, 0x285a, 0x2870,
// Entry 4800 - 483F
0x2885, 0x289a, 0x28ae, 0x28c5, 0x28e1, 0x28f7, 0x2912, 0x2927,
0x293d, 0x2954, 0x296d, 0x2980, 0x2994, 0x29aa, 0x29bf, 0x29d4,
0x29ef, 0x2a04, 0x2a1f, 0x2a34, 0x2a51, 0x2a68, 0x2a82, 0x2a96,
0x2ab0, 0x2ac4, 0x2adb, 0x2af0, 0x2b03, 0x2b19, 0x2b2e, 0x2b43,
0x2b5e, 0x2b73, 0x2b87, 0x2b9b, 0x2baf, 0x2bc5, 0x2bda, 0x2bf9,
0x2c0e, 0x2c22, 0x2c39, 0x2c55, 0x2c68, 0x2c7a, 0x2c8d, 0x2ca6,
0x2cb6, 0x2cc7, 0x2cd9, 0x2ceb, 0x2cfd, 0x2d0f, 0x2d21, 0x2d35,
0x2d46, 0x2d57, 0x2d6b, 0x2d7c, 0x2d8c, 0x2d9f, 0x2db1, 0x2dc3,
// Entry 4840 - 487F
0x2dd4, 0x2de5, 0x2df7, 0x2e08, 0x2e1c, 0x2e35, 0x2e4a, 0x2e5f,
0x2e75, 0x2e8b, 0x2e9f, 0x2eb4, 0x2ec9, 0x2ede, 0x2ef3, 0x2f08,
0x2f1d, 0x2f33, 0x2f48, 0x2f5d, 0x2f73, 0x2f88, 0x2f9c, 0x2fb2,
0x2fc7, 0x2fdd, 0x2ff3, 0x3008, 0x301d, 0x3032, 0x304a, 0x3067,
0x307c, 0x3093, 0x30ac, 0x30bb, 0x30ca, 0x30d9, 0x30e8, 0x30f7,
0x3106, 0x3115, 0x3124, 0x3133, 0x3142, 0x3151, 0x3160, 0x316f,
0x317e, 0x318e, 0x319d, 0x31ac, 0x31bb, 0x31ca, 0x31d9, 0x31e9,
0x31f9, 0x3209, 0x3219, 0x3229, 0x3238, 0x324e, 0x326c, 0x328a,
// Entry 4880 - 48BF
0x32a8, 0x32c6, 0x32e5, 0x3304, 0x3323, 0x3344, 0x3363, 0x3382,
0x33a1, 0x33c2, 0x33e1, 0x3402, 0x3421, 0x3442, 0x3461, 0x3481,
0x34a1, 0x34c0, 0x34e1, 0x3500, 0x351f, 0x353e, 0x355d, 0x357e,
0x359d, 0x35be, 0x35dd, 0x35fc, 0x361d, 0x3640, 0x3659, 0x3672,
0x368b, 0x36a4, 0x36be, 0x36d8, 0x36f2, 0x370c, 0x3726, 0x3740,
0x375a, 0x3774, 0x378e, 0x37a9, 0x37c4, 0x37de, 0x3800, 0x381a,
0x3834, 0x384e, 0x3868, 0x3882, 0x389c, 0x38b6, 0x38df, 0x3901,
0x391e, 0x393b, 0x3956, 0x3971, 0x398e, 0x39aa, 0x39c6, 0x39e1,
// Entry 48C0 - 48FF
0x39fe, 0x3a1b, 0x3a37, 0x3a52, 0x3a70, 0x3a8e, 0x3aab, 0x3ac8,
0x3ae5, 0x3b04, 0x3b27, 0x3b4a, 0x3b6f, 0x3b93, 0x3bb7, 0x3bda,
0x3bff, 0x3c24, 0x3c48, 0x3c6c, 0x3c90, 0x3cb6, 0x3cdb, 0x3d00,
0x3d24, 0x3d4a, 0x3d70, 0x3d95, 0x3db9, 0x3de0, 0x3e07, 0x3e2d,
0x3e53, 0x3e79, 0x3ea1, 0x3ec8, 0x3eef, 0x3f1b, 0x3f47, 0x3f75,
0x3fa2, 0x3fcf, 0x3ffb, 0x4029, 0x4057, 0x4084, 0x40a9, 0x40cf,
0x40f7, 0x411e, 0x4145, 0x416b, 0x4193, 0x41bb, 0x41e2, 0x4208,
0x421b, 0x4232, 0x4249, 0x4268, 0x427f, 0x4296, 0x42b2, 0x42d3,
// Entry 4900 - 493F
0x42eb, 0x4302, 0x4316, 0x432b, 0x433f, 0x4354, 0x4368, 0x437d,
0x4391, 0x43a6, 0x43bb, 0x43d1, 0x43e6, 0x43fc, 0x4411, 0x4425,
0x443a, 0x444e, 0x4463, 0x4477, 0x448b, 0x44a0, 0x44b4, 0x44c9,
0x44dd, 0x44f1, 0x4505, 0x4519, 0x452d, 0x4542, 0x4557, 0x456b,
0x457f, 0x4593, 0x45a8, 0x45bf, 0x45d5, 0x45ea, 0x4603, 0x4618,
0x4631, 0x4642, 0x4656, 0x466a, 0x4680, 0x4695, 0x46aa, 0x46c2,
0x46df, 0x46fd, 0x4719, 0x4733, 0x4756, 0x4773, 0x4796, 0x47b5,
0x47d1, 0x47ed, 0x4810, 0x482c, 0x4847, 0x4866, 0x4883, 0x489f,
// Entry 4940 - 497F
0x48bc, 0x48d8, 0x48f5, 0x4912, 0x492f, 0x494b, 0x4967, 0x4984,
0x49a0, 0x49be, 0x49dc, 0x49fb, 0x4a16, 0x4a33, 0x4a4f, 0x4a6e,
0x4a8c, 0x4aab, 0x4ac9, 0x4ae6, 0x4b03, 0x4b23, 0x4b40, 0x4b5d,
0x4b7b, 0x4b97, 0x4bb5, 0x4bd8, 0x4bf4, 0x4c10, 0x4c2c, 0x4c49,
0x4c65, 0x4c81, 0x4c9e, 0x4cba, 0x4cd6, 0x4cf2, 0x4d0f, 0x4d2b,
0x4d48, 0x4d65, 0x4d81, 0x4d9e, 0x4dba, 0x4dd7, 0x4df3, 0x4e0f,
0x4e2c, 0x4e48, 0x4e66, 0x4e82, 0x4e9f, 0x4ebc, 0x4ed8, 0x4ef5,
0x4f11, 0x4f2d, 0x4f49, 0x4f68, 0x4f7f, 0x4f95, 0x4fac, 0x4fc3,
// Entry 4980 - 49BF
0x4fdb, 0x4ff3, 0x5007, 0x501c, 0x502e, 0x5045, 0x505d, 0x5074,
0x508c, 0x50a2, 0x50b8, 0x50ce, 0x50e4, 0x50fa, 0x5111, 0x5129,
0x5142, 0x515b, 0x5170, 0x5185, 0x519d, 0x51b3, 0x51ca, 0x51de,
0x51f2, 0x5209, 0x521f, 0x5235, 0x524c, 0x5262, 0x5278, 0x528f,
0x52a4, 0x52c6, 0x52e8, 0x52fd, 0x5313, 0x5328, 0x5340, 0x535d,
0x5378, 0x5396, 0x53c2, 0x53e7, 0x5401, 0x5420, 0x5442, 0x5452,
0x5463, 0x5474, 0x5486, 0x5497, 0x54a9, 0x54ba, 0x54cc, 0x54dc,
0x54ed, 0x54fd, 0x550e, 0x551e, 0x552f, 0x553f, 0x5550, 0x5561,
// Entry 49C0 - 49FF
0x5572, 0x5584, 0x5596, 0x55a7, 0x55b9, 0x55cb, 0x55dc, 0x55ed,
0x55fe, 0x5610, 0x5621, 0x5633, 0x5645, 0x5656, 0x5667, 0x5678,
0x568a, 0x569c, 0x56af, 0x56c2, 0x56d3, 0x56e5, 0x56f7, 0x5708,
0x571a, 0x572c, 0x573d, 0x574e, 0x575f, 0x5770, 0x5781, 0x5792,
0x57a4, 0x57b6, 0x57c9, 0x57dc, 0x57ed, 0x5806, 0x582c, 0x5853,
0x587a, 0x58a1, 0x58ca, 0x58f3, 0x5916, 0x5938, 0x595b, 0x597f,
0x599f, 0x59c0, 0x59e3, 0x5a05, 0x5a27, 0x5a49, 0x5a6b, 0x5a8f,
0x5ab0, 0x5ad1, 0x5af5, 0x5b17, 0x5b37, 0x5b5a, 0x5b7c, 0x5b9e,
// Entry 4A00 - 4A3F
0x5bc0, 0x5be1, 0x5c02, 0x5c23, 0x5c46, 0x5c68, 0x5c89, 0x5cad,
0x5cd6, 0x5d00, 0x5d22, 0x5d43, 0x5d65, 0x5d88, 0x5da7, 0x5dd1,
0x5df3, 0x5e14, 0x5e35, 0x5e56, 0x5e77, 0x5e9a, 0x5ebf, 0x5edf,
0x5f02, 0x5f21, 0x5f43, 0x5f64, 0x5f84, 0x5fa4, 0x5fc4, 0x5fe6,
0x6007, 0x6027, 0x604a, 0x6072, 0x609b, 0x60b7, 0x60d2, 0x60ee,
0x610b, 0x6124, 0x6148, 0x6164, 0x617f, 0x619a, 0x61b5, 0x61d2,
0x61f1, 0x620b, 0x6228, 0x6241, 0x625d, 0x6278, 0x6292, 0x62ae,
0x62d1, 0x62f5, 0x6317, 0x6331, 0x634b, 0x6367, 0x6382, 0x639c,
// Entry 4A40 - 4A7F
0x63b9, 0x63db, 0x63f5, 0x6410, 0x642c, 0x6446, 0x6461, 0x647c,
0x6496, 0x64b1, 0x64cd, 0x64e8, 0x6504, 0x6520, 0x653d, 0x6558,
0x6574, 0x6590, 0x65ad, 0x65c8, 0x65e4, 0x6600, 0x661b, 0x6637,
0x6652, 0x666e, 0x668a, 0x66a7, 0x66c3, 0x66e0, 0x66fc, 0x6719,
0x6734, 0x6750, 0x676c, 0x6788, 0x67a3, 0x67be, 0x67da, 0x67f7,
0x6813, 0x6830, 0x684c, 0x6869, 0x6885, 0x68a2, 0x68bf, 0x68db,
0x68f9, 0x6914, 0x692f, 0x694a, 0x6965, 0x6981, 0x699c, 0x69b8,
0x69d3, 0x69ef, 0x6a0a, 0x6a26, 0x6a41, 0x6a5d, 0x6a79, 0x6a94,
// Entry 4A80 - 4ABF
0x6ab0, 0x6acc, 0x6ae9, 0x6b05, 0x6b22, 0x6b3d, 0x6b59, 0x6b75,
0x6b92, 0x6bad, 0x6bca, 0x6be8, 0x6c07, 0x6c26, 0x6c46, 0x6c65,
0x6c85, 0x6ca5, 0x6cc4, 0x6ce4, 0x6d02, 0x6d26, 0x6d45, 0x6d64,
0x6d83, 0x6da3, 0x6dc2, 0x6de0, 0x6dff, 0x6e1e, 0x6e3d, 0x6e5c,
0x6e7c, 0x6e9b, 0x6ebb, 0x6eda, 0x6ef9, 0x6f19, 0x6f37, 0x6f56,
0x6f80, 0x6fa9, 0x6fc9, 0x6fe8, 0x7008, 0x7027, 0x704c, 0x706b,
0x708b, 0x70aa, 0x70ca, 0x70ea, 0x710a, 0x7128, 0x7147, 0x7171,
0x719a, 0x71b9, 0x71d8, 0x71f8, 0x7224, 0x7243, 0x725f, 0x727c,
// Entry 4AC0 - 4AFF
0x7299, 0x72b7, 0x72d4, 0x72f2, 0x7310, 0x732d, 0x734b, 0x7367,
0x7389, 0x73a6, 0x73c3, 0x73e0, 0x73fe, 0x741b, 0x7437, 0x7454,
0x7471, 0x748e, 0x74ab, 0x74c9, 0x74e6, 0x7504, 0x7521, 0x753e,
0x755c, 0x7578, 0x7595, 0x75bd, 0x75e4, 0x7602, 0x761f, 0x763d,
0x765a, 0x767d, 0x769a, 0x76b8, 0x76d5, 0x76f3, 0x7711, 0x772f,
0x774b, 0x7768, 0x7790, 0x77b7, 0x77d4, 0x77f1, 0x780f, 0x7839,
0x7856, 0x786e, 0x7887, 0x789f, 0x78b9, 0x78d9, 0x78fa, 0x7912,
0x792b, 0x7944, 0x795d, 0x7977, 0x7990, 0x79a9, 0x79c2, 0x79dc,
// Entry 4B00 - 4B3F
0x79f5, 0x7a0e, 0x7a28, 0x7a41, 0x7a5b, 0x7a74, 0x7a8d, 0x7aa7,
0x7ac0, 0x7ad9, 0x7af2, 0x7b0b, 0x7b24, 0x7b3d, 0x7b5c, 0x7b75,
0x7b94, 0x7bae, 0x7bc8, 0x7be1, 0x7bf8, 0x7c0f, 0x7c26, 0x7c3d,
0x7c54, 0x7c6e, 0x7c8c, 0x7ca9, 0x7cc4, 0x7cdd, 0x7cf7, 0x7d11,
0x7d2a, 0x7d43, 0x7d5e, 0x7d78, 0x7d92, 0x7dab, 0x7dc6, 0x7de1,
0x7dfb, 0x7e09, 0x7e17, 0x7e27, 0x7e36, 0x7e45, 0x7e53, 0x7e63,
0x7e73, 0x7e82, 0x7e91, 0x7ea3, 0x7eb5, 0x7ec6, 0x7ed7, 0x7ee8,
0x7efb, 0x7f0d, 0x7f1f, 0x7f36, 0x7f4d, 0x7f66, 0x7f7e, 0x7f96,
// Entry 4B40 - 4B7F
0x7fad, 0x7fc6, 0x7fdf, 0x7ff7, 0x800d, 0x8026, 0x803d, 0x8055,
0x8067, 0x8077, 0x8087, 0x8098, 0x80a9, 0x80b9, 0x80ca, 0x80dc,
0x80ef, 0x8100, 0x8110, 0x8121, 0x8132, 0x8142, 0x8153, 0x8163,
0x8173, 0x8184, 0x8196, 0x81a7, 0x81b8, 0x81c8, 0x81d8, 0x81e9,
0x81fc, 0x820c, 0x821c, 0x823b, 0x824c, 0x825d, 0x826f, 0x8280,
0x8291, 0x82a2, 0x82b3, 0x82c3, 0x82d4, 0x82e4, 0x82f4, 0x8305,
0x8316, 0x8326, 0x8341, 0x835c, 0x8373, 0x8393, 0x83ba, 0x83d5,
0x83ef, 0x840a, 0x8422, 0x8440, 0x8457, 0x8474, 0x848c, 0x84a1,
// Entry 4B80 - 4BBF
0x84bc, 0x84d2, 0x84ea, 0x8501, 0x8518, 0x852f, 0x8548, 0x855e,
0x8574, 0x8590, 0x85bf, 0x85d8, 0x85ef, 0x8610, 0x8625, 0x863d,
0x865b, 0x868c, 0x86af, 0x86c6, 0x86dc, 0x86f8, 0x8727, 0x873d,
0x8753, 0x876b, 0x8782, 0x8799, 0x87af, 0x87c8, 0x87e1, 0x87ff,
0x881c, 0x883c, 0x8850, 0x8863, 0x8877, 0x8888, 0x889a, 0x88ae,
0x88c1, 0x88d4, 0x88e7, 0x88fc, 0x890e, 0x8920, 0x8935, 0x8948,
0x8959, 0x896d, 0x8985, 0x8998, 0x89aa, 0x89bd, 0x89d0, 0x89e8,
0x8a03, 0x8a23, 0x8a3e, 0x8a5e, 0x8a7b, 0x8a98, 0x8ab4, 0x8ad0,
// Entry 4BC0 - 4BFF
0x8af1, 0x8b0d, 0x8b2b, 0x8b3d, 0x8b4f, 0x8b64, 0x8b7e, 0x8ba3,
0x8bd2, 0x8bf5, 0x8c1e, 0x8c46, 0x8c5d, 0x8c73, 0x8c8f, 0x8ca4,
0x8cbb, 0x8cd7, 0x8ced, 0x8d03, 0x8d1b, 0x8d30, 0x8d45, 0x8d5d,
0x8d71, 0x8d88, 0x8d9e, 0x8db4, 0x8dc9, 0x8ddf, 0x8dfd, 0x8e1b,
0x8e3e, 0x8e61, 0x8e7b, 0x8e9a, 0x8eb9, 0x8ed9, 0x8ef0, 0x8f0d,
0x8f23, 0x8f3a, 0x8f52, 0x8f66, 0x8f7b, 0x8f97, 0x8fae, 0x8fc4,
0x8fda, 0x8ff0, 0x9008, 0x901d, 0x9032, 0x904a, 0x9060, 0x9074,
0x908a, 0x90a0, 0x90b5, 0x90ca, 0x90df, 0x90f6, 0x910c, 0x9121,
// Entry 4C00 - 4C3F
0x9139, 0x9156, 0x916a, 0x917d, 0x9191, 0x91a6, 0x91b7, 0x91c9,
0x91dd, 0x91f0, 0x9203, 0x9216, 0x9229, 0x923e, 0x9250, 0x9262,
0x9277, 0x928a, 0x929b, 0x92af, 0x92c2, 0x92d5, 0x92e8, 0x92fa,
0x9315, 0x932c, 0x9340, 0x9353, 0x936a, 0x9381, 0x9390, 0x93a0,
0x93af, 0x93bf, 0x93ce, 0x93de, 0x93f5, 0x940d, 0x9424, 0x943c,
0x944b, 0x945b, 0x946a, 0x947a, 0x948a, 0x949b, 0x94ab, 0x94bc,
0x94cd, 0x94dd, 0x94ee, 0x94fe, 0x950f, 0x9520, 0x9531, 0x9543,
0x9554, 0x9566, 0x9577, 0x9587, 0x9598, 0x95a8, 0x95b9, 0x95c9,
// Entry 4C40 - 4C7F
0x95d9, 0x95ea, 0x95fa, 0x960b, 0x961b, 0x962b, 0x963b, 0x964b,
0x965b, 0x966c, 0x967d, 0x968d, 0x969d, 0x96ae, 0x96ca, 0x96e5,
0x9701, 0x9715, 0x9735, 0x9748, 0x975c, 0x976f, 0x9783, 0x979e,
0x97ba, 0x97d5, 0x97f1, 0x9804, 0x9818, 0x982b, 0x983f, 0x984c,
0x9858, 0x986b, 0x9881, 0x989e, 0x98b5, 0x98d4, 0x98ec, 0x98fd,
0x990e, 0x9921, 0x9933, 0x9945, 0x9956, 0x9969, 0x997c, 0x998e,
0x999f, 0x99b3, 0x99c7, 0x99da, 0x99ed, 0x9a00, 0x9a15, 0x9a29,
0x9a3d, 0x9a56, 0x9a70, 0x9a81, 0x9a91, 0x9aa1, 0x9ab3, 0x9ac4,
// Entry 4C80 - 4CBF
0x9ad5, 0x9ae5, 0x9af7, 0x9b09, 0x9b1a, 0x9b36, 0x9b55, 0x9b74,
0x9b97, 0x9bba, 0x9bd5, 0x9be9, 0x9c00, 0x9c14, 0x9c27, 0x9c36,
0x9c46, 0x9c55, 0x9c65, 0x9c74, 0x9c84, 0x9c93, 0x9ca3, 0x9cb2,
0x9cc2, 0x9cd2, 0x9ce3, 0x9cf3, 0x9d04, 0x9d15, 0x9d25, 0x9d36,
0x9d46, 0x9d57, 0x9d68, 0x9d79, 0x9d8b, 0x9d9c, 0x9daf, 0x9dc1,
0x9dd2, 0x9de3, 0x9df3, 0x9e04, 0x9e14, 0x9e25, 0x9e35, 0x9e45,
0x9e56, 0x9e66, 0x9e77, 0x9e87, 0x9e97, 0x9ea7, 0x9eb7, 0x9ec7,
0x9ed8, 0x9ee9, 0x9ef9, 0x9f09, 0x9f1d, 0x9f30, 0x9f44, 0x9f57,
// Entry 4CC0 - 4CFF
0x9f6b, 0x9f7e, 0x9f92, 0x9fa5, 0x9fb9, 0x9fcb, 0x9fdc, 0x9ff4,
0xa00b, 0xa01d, 0xa030, 0xa04a, 0xa056, 0xa069, 0xa084, 0xa09c,
0xa0b3, 0xa0ca, 0xa0e1, 0xa0f8, 0xa10f, 0xa126, 0xa13d, 0xa155,
0xa16c, 0xa183, 0xa19a, 0xa1b1, 0xa1c8, 0xa1df, 0xa1f6, 0xa20d,
0xa224, 0xa23c, 0xa252, 0xa269, 0xa27f, 0xa295, 0xa2ab, 0xa2c1,
0xa2d8, 0xa2ef, 0xa305, 0xa31b, 0xa333, 0xa34a, 0xa361, 0xa377,
0xa38f, 0xa3a7, 0xa3be, 0xa3d5, 0xa3e9, 0xa3fc, 0xa40c, 0xa41b,
0xa42a, 0xa439, 0xa44a, 0xa45c, 0xa46d, 0xa47f, 0xa491, 0xa4a2,
// Entry 4D00 - 4D3F
0xa4b4, 0xa4c5, 0xa4d7, 0xa4e9, 0xa4fb, 0xa50e, 0xa520, 0xa533,
0xa545, 0xa556, 0xa568, 0xa579, 0xa58b, 0xa59c, 0xa5ad, 0xa5bf,
0xa5d0, 0xa5e2, 0xa5f3, 0xa605, 0xa616, 0xa627, 0xa638, 0xa649,
0xa65a, 0xa66b, 0xa67e, 0xa691, 0xa6a5, 0xa6b8, 0xa6cc, 0xa6df,
0xa6f3, 0xa706, 0xa71a, 0xa72e, 0xa73b, 0xa749, 0xa756, 0xa764,
0xa775, 0xa785, 0xa795, 0xa7a7, 0xa7b8, 0xa7c9, 0xa7d9, 0xa7eb,
0xa7fd, 0xa80e, 0xa821, 0xa82d, 0xa840, 0xa854, 0xa866, 0xa87a,
0xa88e, 0xa89f, 0xa8b0, 0xa8c1, 0xa8d2, 0xa8e3, 0xa8f4, 0xa906,
// Entry 4D40 - 4D7F
0xa919, 0xa92b, 0xa93e, 0xa950, 0xa963, 0xa975, 0xa988, 0xa99b,
0xa9ae, 0xa9c2, 0xa9d5, 0xa9e9, 0xa9fc, 0xaa0e, 0xaa21, 0xaa33,
0xaa46, 0xaa58, 0xaa6a, 0xaa7d, 0xaa8f, 0xaaa2, 0xaab4, 0xaac6,
0xaad8, 0xaaea, 0xaafc, 0xab0e, 0xab21, 0xab34, 0xab4e, 0xab63,
0xab79, 0xab91, 0xaba6, 0xabba, 0xabca, 0xabdb, 0xabeb, 0xabfc,
0xac0c, 0xac1d, 0xac35, 0xac4e, 0xac66, 0xac7f, 0xac8f, 0xaca0,
0xacb0, 0xacc1, 0xacd2, 0xace4, 0xacf5, 0xad07, 0xad19, 0xad2a,
0xad3c, 0xad4d, 0xad5f, 0xad71, 0xad83, 0xad96, 0xada8, 0xadbb,
// Entry 4D80 - 4DBF
0xadcd, 0xadde, 0xadf0, 0xae01, 0xae13, 0xae24, 0xae35, 0xae47,
0xae58, 0xae6a, 0xae7b, 0xae8c, 0xae9d, 0xaeae, 0xaec0, 0xaed1,
0xaee3, 0xaef5, 0xaf06, 0xaf17, 0xaf2c, 0xaf40, 0xaf55, 0xaf69,
0xaf7e, 0xaf9a, 0xafb7, 0xafd3, 0xaff0, 0xb004, 0xb019, 0xb02d,
0xb042, 0xb055, 0xb06a, 0xb082, 0xb09a, 0xb0a4, 0xb0b1, 0xb0c5,
0xb0de, 0xb0ef, 0xb102, 0xb114, 0xb12f, 0xb14d, 0xb15f, 0xb181,
0xb1a2, 0xb1b4, 0xb1c5, 0xb1d6, 0xb1e9, 0xb1fb, 0xb20d, 0xb21e,
0xb231, 0xb244, 0xb256, 0xb262, 0xb276, 0xb288, 0xb2a1, 0xb2b7,
// Entry 4DC0 - 4DFF
0xb2cd, 0xb2e6, 0xb2ff, 0xb31a, 0xb334, 0xb34e, 0xb367, 0xb382,
0xb39d, 0xb3b7, 0xb3d1, 0xb3ee, 0xb40b, 0xb427, 0xb443, 0xb45f,
0xb47d, 0xb49a, 0xb4b7, 0xb4d9, 0xb4fc, 0xb50b, 0xb51b, 0xb52a,
0xb539, 0xb548, 0xb558, 0xb567, 0xb577, 0xb587, 0xb598, 0xb5a8,
0xb5b9, 0xb5ca, 0xb5db, 0xb5eb, 0xb5fc, 0xb60c, 0xb61d, 0xb62e,
0xb63f, 0xb651, 0xb662, 0xb674, 0xb685, 0xb695, 0xb6a6, 0xb6b6,
0xb6c8, 0xb6d9, 0xb6e9, 0xb6f9, 0xb70a, 0xb71a, 0xb72b, 0xb73c,
0xb74c, 0xb75c, 0xb76c, 0xb77c, 0xb78c, 0xb79c, 0xb7ac, 0xb7bd,
// Entry 4E00 - 4E3F
0xb7d1, 0xb7e4, 0xb7f8, 0xb80b, 0xb81e, 0xb832, 0xb845, 0xb859,
0xb86d, 0xb87f, 0xb890, 0xb8a2, 0xb8ae, 0xb8c1, 0xb8d6, 0xb8e9,
0xb903, 0xb91b, 0xb92c, 0xb93c, 0xb951, 0xb96c, 0xb97c, 0xb98c,
0xb99c, 0xb9ac, 0xb9bd, 0xb9cf, 0xb9e0, 0xb9f2, 0xba03, 0xba15,
0xba26, 0xba38, 0xba4a, 0xba5c, 0xba6f, 0xba81, 0xba94, 0xbaa7,
0xbab9, 0xbaca, 0xbadc, 0xbaed, 0xbaff, 0xbb10, 0xbb21, 0xbb33,
0xbb44, 0xbb56, 0xbb67, 0xbb78, 0xbb89, 0xbb9a, 0xbbab, 0xbbbc,
0xbbcd, 0xbbdf, 0xbbf1, 0xbc05, 0xbc17, 0xbc2a, 0xbc3c, 0xbc4f,
// Entry 4E40 - 4E7F
0xbc61, 0xbc74, 0xbc86, 0xbc99, 0xbcab, 0xbcbe, 0xbcd1, 0xbce5,
0xbcf8, 0xbd0c, 0xbd20, 0xbd34, 0xbd47, 0xbd5b, 0xbd6e, 0xbd82,
0xbd96, 0xbdaa, 0xbdbe, 0xbdd3, 0xbde7, 0xbdfc, 0xbe10, 0xbe25,
0xbe39, 0xbe4c, 0xbe60, 0xbe73, 0xbe87, 0xbe9a, 0xbead, 0xbec1,
0xbed4, 0xbee8, 0xbefc, 0xbf0f, 0xbf22, 0xbf35, 0xbf48, 0xbf5b,
0xbf6f, 0xbf82, 0xbf95, 0xbfac, 0xbfc3, 0xbfd9, 0xbff0, 0xc006,
0xc01d, 0xc033, 0xc04a, 0xc060, 0xc077, 0xc08b, 0xc0a0, 0xc0b4,
0xc0c7, 0xc0da, 0xc0ef, 0xc103, 0xc117, 0xc12a, 0xc13f, 0xc154,
// Entry 4E80 - 4EBF
0xc168, 0xc18d, 0xc1a5, 0xc1ba, 0xc1ce, 0xc1de, 0xc1ef, 0xc1ff,
0xc210, 0xc220, 0xc231, 0xc249, 0xc261, 0xc272, 0xc283, 0xc294,
0xc2a5, 0xc2b6, 0xc2c8, 0xc2d9, 0xc2eb, 0xc2fd, 0xc30e, 0xc320,
0xc331, 0xc343, 0xc355, 0xc367, 0xc37a, 0xc38c, 0xc39f, 0xc3b1,
0xc3c2, 0xc3d4, 0xc3e5, 0xc3f7, 0xc408, 0xc419, 0xc42b, 0xc43c,
0xc44e, 0xc45f, 0xc470, 0xc481, 0xc492, 0xc4a4, 0xc4b5, 0xc4c7,
0xc4d9, 0xc4ea, 0xc4fb, 0xc510, 0xc522, 0xc537, 0xc54c, 0xc560,
0xc575, 0xc589, 0xc59e, 0xc5ba, 0xc5d7, 0xc5ec, 0xc601, 0xc616,
// Entry 4EC0 - 4EFF
0xc62b, 0xc63e, 0xc648, 0xc65e, 0xc670, 0xc68d, 0xc6b1, 0xc6ca,
0xc6e3, 0xc6ff, 0xc71c, 0xc738, 0xc753, 0xc76e, 0xc78b, 0xc7a7,
0xc7c3, 0xc7de, 0xc7f8, 0xc813, 0xc82e, 0xc849, 0xc864, 0xc871,
0xc87f, 0xc88c, 0xc89a, 0xc8a7, 0xc8b5, 0xc8ca, 0xc8e0, 0xc8f5,
0xc90b, 0xc918, 0xc926, 0xc933, 0xc941, 0xc94f, 0xc95e, 0xc96c,
0xc97b, 0xc98a, 0xc99a, 0xc9a8, 0xc9b7, 0xc9c5, 0xc9d4, 0xc9e3,
0xc9f3, 0xca02, 0xca12, 0xca21, 0xca31, 0xca40, 0xca4e, 0xca5d,
0xca6b, 0xca7a, 0xca88, 0xca97, 0xcaa5, 0xcab4, 0xcac2, 0xcad1,
// Entry 4F00 - 4F3F
0xcadf, 0xcaee, 0xcafc, 0xcb0a, 0xcb19, 0xcb27, 0xcb36, 0xcb44,
0xcb53, 0xcb62, 0xcb70, 0xcb7e, 0xcb90, 0xcba1, 0xcbb3, 0xcbc4,
0xcbd6, 0xcbef, 0xcc09, 0xcc22, 0xcc3c, 0xcc4d, 0xcc5f, 0xcc70,
0xcc82, 0xcc92, 0xcca7, 0xccb9, 0xccca, 0xccd9, 0xcceb, 0xcd03,
0xcd0a, 0xcd15, 0xcd1f, 0xcd30, 0xcd3a, 0xcd49, 0xcd5f, 0xcd6e,
0xcd7c, 0xcd8a, 0xcd9a, 0xcda9, 0xcdb8, 0xcdc6, 0xcdd6, 0xcde6,
0xcdf5, 0xce06, 0xce1b, 0xce2e, 0xce3e, 0xce58, 0xce6d, 0xce82,
0xce8e, 0xce9e, 0xceaf, 0xcebf, 0xced0, 0xcee0, 0xcef1, 0xcf09,
// Entry 4F40 - 4F7F
0xcf22, 0xcf3a, 0xcf53, 0xcf63, 0xcf74, 0xcf84, 0xcf95, 0xcfa6,
0xcfb8, 0xcfc9, 0xcfdb, 0xcfed, 0xcffe, 0xd010, 0xd021, 0xd033,
0xd045, 0xd057, 0xd06a, 0xd07c, 0xd08f, 0xd0a1, 0xd0b2, 0xd0c4,
0xd0d5, 0xd0e7, 0xd0f8, 0xd109, 0xd11b, 0xd12c, 0xd13e, 0xd14f,
0xd160, 0xd171, 0xd182, 0xd193, 0xd1a5, 0xd1b7, 0xd1c8, 0xd1d9,
0xd1ee, 0xd202, 0xd217, 0xd22b, 0xd240, 0xd25c, 0xd279, 0xd295,
0xd2b2, 0xd2c6, 0xd2e0, 0xd2f5, 0xd309, 0xd323, 0xd338, 0xd350,
0xd365, 0xd379, 0xd38c, 0xd39e, 0xd3b3, 0xd3c0, 0xd3d9, 0xd3e3,
// Entry 4F80 - 4FBF
0xd3f5, 0xd406, 0xd417, 0xd42a, 0xd43c, 0xd44e, 0xd45f, 0xd472,
0xd485, 0xd497, 0xd4a7, 0xd4b8, 0xd4c8, 0xd4d9, 0xd4e9, 0xd4fa,
0xd512, 0xd52b, 0xd543, 0xd55c, 0xd56c, 0xd57d, 0xd58d, 0xd59e,
0xd5af, 0xd5c1, 0xd5d2, 0xd5e4, 0xd5f6, 0xd607, 0xd619, 0xd62a,
0xd63c, 0xd64e, 0xd660, 0xd673, 0xd685, 0xd698, 0xd6aa, 0xd6bb,
0xd6cd, 0xd6de, 0xd6f0, 0xd701, 0xd712, 0xd724, 0xd735, 0xd747,
0xd758, 0xd769, 0xd77a, 0xd78b, 0xd79c, 0xd7ae, 0xd7c0, 0xd7d1,
0xd7e2, 0xd7f7, 0xd80b, 0xd820, 0xd834, 0xd849, 0xd865, 0xd882,
// Entry 4FC0 - 4FFF
0xd896, 0xd8ab, 0xd8bf, 0xd8d4, 0xd8ec, 0xd901, 0xd915, 0xd928,
0xd93a, 0xd94e, 0xd95b, 0xd96f, 0xd984, 0xd999, 0xd9b2, 0xd9cb,
0xd9e4, 0xd9fc, 0xda34, 0xda6a, 0xda9d, 0xdad7, 0xdb11, 0xdb31,
0xdb5b, 0xdb85, 0xdbaf, 0xdbdc, 0xdc08, 0xdc32, 0xdc66, 0xdc9b,
0xdcc2, 0xdce7, 0xdd0d, 0xdd27, 0xdd45, 0xdd64, 0xdd71, 0xdd7f,
0xdd8c, 0xdd9a, 0xdda7, 0xddb5, 0xddca, 0xdde0, 0xddf5, 0xde0b,
0xde18, 0xde26, 0xde33, 0xde41, 0xde4f, 0xde5e, 0xde6c, 0xde7b,
0xde8a, 0xde98, 0xdea7, 0xdeb5, 0xdec4, 0xded3, 0xdee2, 0xdef2,
// Entry 5000 - 503F
0xdf01, 0xdf11, 0xdf20, 0xdf2e, 0xdf3d, 0xdf4b, 0xdf5a, 0xdf68,
0xdf76, 0xdf85, 0xdf93, 0xdfa2, 0xdfb0, 0xdfbe, 0xdfcc, 0xdfda,
0xdfe8, 0xdff7, 0xe006, 0xe014, 0xe022, 0xe031, 0xe043, 0xe054,
0xe066, 0xe077, 0xe089, 0xe0a2, 0xe0bc, 0xe0d5, 0xe0ef, 0xe100,
0xe112, 0xe123, 0xe135, 0xe147, 0xe158, 0xe168, 0xe17d, 0xe187,
0xe198, 0xe1ae, 0xe1bc, 0xe1cb, 0xe1d9, 0xe1e7, 0xe1f7, 0xe206,
0xe215, 0xe223, 0xe233, 0xe243, 0xe252, 0xe26f, 0xe286, 0xe2aa,
0xe2ce, 0xe2f2, 0xe317, 0xe343, 0xe35b, 0xe388, 0xe39d, 0xe3c0,
// Entry 5040 - 507F
0xe3ea, 0xe41b, 0xe429, 0xe438, 0xe446, 0xe455, 0xe463, 0xe472,
0xe480, 0xe48f, 0xe49d, 0xe4ac, 0xe4bb, 0xe4cb, 0xe4da, 0xe4ea,
0xe4fa, 0xe509, 0xe519, 0xe528, 0xe538, 0xe548, 0xe558, 0xe569,
0xe579, 0xe58a, 0xe59a, 0xe5a9, 0xe5b9, 0xe5c8, 0xe5d8, 0xe5e7,
0xe5f6, 0xe606, 0xe615, 0xe625, 0xe634, 0xe643, 0xe652, 0xe661,
0xe670, 0xe680, 0xe68f, 0xe69e, 0xe6ae, 0xe6c1, 0xe6d3, 0xe6e6,
0xe6f8, 0xe70b, 0xe71d, 0xe730, 0xe742, 0xe755, 0xe767, 0xe77a,
0xe78b, 0xe79b, 0xe7b3, 0xe7ca, 0xe7da, 0xe7e9, 0xe7f8, 0xe809,
// Entry 5080 - 50BF
0xe819, 0xe829, 0xe838, 0xe849, 0xe85a, 0xe86a, 0xe878, 0xe887,
0xe896, 0xe8a4, 0xe8b2, 0xe8ca, 0xe8d8, 0xe8e7, 0xe8f5, 0xe903,
0xe911, 0xe920, 0xe92f, 0xe93d, 0xe94b, 0xe959, 0xe968, 0xe976,
0xe983, 0xe991, 0xe9a0, 0xe9ae, 0xe9c6, 0xe9d5, 0xe9e4, 0xe9f3,
0xea0b, 0xea28, 0xea45, 0xea6b, 0xea7c, 0xea8e, 0xea9f, 0xeab1,
0xeac2, 0xead4, 0xeae5, 0xeaf7, 0xeb08, 0xeb1a, 0xeb2c, 0xeb3c,
0xeb4b, 0xeb59, 0xeb67, 0xeb77, 0xeb86, 0xeb95, 0xeba3, 0xebb3,
0xebc3, 0xebd2, 0xebe1, 0xebf3, 0xec0a, 0xec1b, 0xec2a, 0xec38,
// Entry 50C0 - 50FF
0xec46, 0xec55, 0xec65, 0xec74, 0xec84, 0xec93, 0xeca2, 0xecb0,
0xecbf, 0xeccd, 0xecdc, 0xecea, 0xecf9, 0xed07, 0xed16, 0xed24,
0xed33, 0xed42, 0xed52, 0xed61, 0xed71, 0xed81, 0xed90, 0xeda0,
0xedaf, 0xedbf, 0xedcf, 0xeddf, 0xedf0, 0xee00, 0xee11, 0xee21,
0xee30, 0xee40, 0xee4f, 0xee5f, 0xee6e, 0xee7d, 0xee8d, 0xee9c,
0xeeac, 0xeebb, 0xeeca, 0xeed9, 0xeee8, 0xeef7, 0xef07, 0xef17,
0xef26, 0xef35, 0xef45, 0xef58, 0xef6a, 0xef7d, 0xef8f, 0xefa2,
0xefbc, 0xefd7, 0xefe9, 0xeffc, 0xf00e, 0xf021, 0xf034, 0xf046,
// Entry 5100 - 513F
0xf057, 0xf067, 0xf07e, 0xf09d, 0xf0b9, 0xf0d6, 0xf0f3, 0xf110,
0xf12d, 0xf14a, 0xf167, 0xf183, 0xf19f, 0xf1bd, 0xf1da, 0xf1f7,
0xf215, 0xf233, 0xf250, 0xf26e, 0xf28c, 0xf2aa, 0xf2c9, 0xf2e6,
0xf303, 0xf320, 0xf33d, 0xf35a, 0xf379, 0xf398, 0xf3b7, 0xf3d5,
0xf3f4, 0xf412, 0xf431, 0xf44e, 0xf468, 0xf483, 0xf49e, 0xf4b9,
0xf4d4, 0xf4ef, 0xf50a, 0xf524, 0xf53e, 0xf55a, 0xf575, 0xf590,
0xf5ac, 0xf5c8, 0xf5e3, 0xf5ff, 0xf61b, 0xf637, 0xf654, 0xf66f,
0xf68a, 0xf6a5, 0xf6c0, 0xf6db, 0xf6f8, 0xf715, 0xf732, 0xf74e,
// Entry 5140 - 517F
0xf76b, 0xf787, 0xf7a4, 0xf7ba, 0xf7cf, 0xf7e4, 0xf7fb, 0xf811,
0xf827, 0xf83c, 0xf853, 0xf86a, 0xf880, 0xf896, 0xf8af, 0xf8c8,
0xf8e0, 0xf8f8, 0xf910, 0xf92a, 0xf943, 0xf95c, 0xf96a, 0xf97e,
0xf993, 0xf9a7, 0xf9bc, 0xf9d0, 0xf9e5, 0xf9f9, 0xfa0d, 0xfa22,
0xfa38, 0xfa4d, 0xfa63, 0xfa79, 0xfa8e, 0xfaa4, 0xfab9, 0xfacf,
0xfae5, 0xfafb, 0xfb12, 0xfb28, 0xfb3d, 0xfb53, 0xfb68, 0xfb7e,
0xfb93, 0xfba8, 0xfbbe, 0xfbd3, 0xfbe9, 0xfbfe, 0xfc13, 0xfc29,
0xfc3e, 0xfc53, 0xfc68, 0xfc7e, 0xfc94, 0xfca9, 0xfcbe, 0xfcd4,
// Entry 5180 - 51BF
0xfce9, 0xfd02, 0xfd1a, 0xfd33, 0xfd4b, 0xfd64, 0xfd7c, 0xfd95,
0xfdad, 0xfdc6, 0xfde2, 0xfdfa, 0xfe0c, 0xfe2b, 0xfe40, 0xfe56,
0xfe6b, 0xfe81, 0xfe99, 0xfeaf, 0xfecb, 0xfee1, 0xfef6, 0xff0b,
0xff22, 0xff38, 0xff4e, 0xff63, 0xff7a, 0xff91, 0xffa7, 0xffbb,
0xffd0, 0xffe4, 0xfff9, 0x000d, 0x0022, 0x003e, 0x005b, 0x006f,
0x0084, 0x0098, 0x00ad, 0x00c2, 0x00d8, 0x00ed, 0x0103, 0x0119,
0x012e, 0x0144, 0x0159, 0x016f, 0x0185, 0x019b, 0x01b2, 0x01c8,
0x01df, 0x01f5, 0x020a, 0x0220, 0x0235, 0x024b, 0x0260, 0x0275,
// Entry 51C0 - 51FF
0x028b, 0x02a0, 0x02b6, 0x02cb, 0x02e0, 0x02f5, 0x030a, 0x031f,
0x0335, 0x034b, 0x0360, 0x0375, 0x038b, 0x03a1, 0x03ba, 0x03d2,
0x03eb, 0x0403, 0x041c, 0x043c, 0x045d, 0x0475, 0x048e, 0x04a6,
0x04bf, 0x04d8, 0x04f0, 0x0507, 0x0520, 0x0538, 0x054e, 0x0574,
0x058d, 0x05aa, 0x05c8, 0x05e5, 0x0602, 0x0620, 0x063d, 0x065b,
0x0679, 0x069f, 0x06c1, 0x06db, 0x06f6, 0x0710, 0x072b, 0x0746,
0x0760, 0x077b, 0x0795, 0x07b0, 0x07cb, 0x07e7, 0x0802, 0x081e,
0x0839, 0x0853, 0x086e, 0x0888, 0x08a3, 0x08bd, 0x08d7, 0x08f2,
// Entry 5200 - 523F
0x090c, 0x0927, 0x0941, 0x095c, 0x0978, 0x0993, 0x09af, 0x09ca,
0x09e4, 0x09fe, 0x0a18, 0x0a32, 0x0a4c, 0x0a66, 0x0a81, 0x0a9c,
0x0ab6, 0x0ad0, 0x0aec, 0x0b11, 0x0b2d, 0x0b4e, 0x0b7d, 0x0ba7,
0x0bc5, 0x0be2, 0x0c0c, 0x0c34, 0x0c5c, 0x0c84, 0x0cac, 0x0cce,
0x0cf0, 0x0d0b, 0x0d25, 0x0d46, 0x0d66, 0x0d95, 0x0dc4, 0x0dde,
0x0dee, 0x0e02, 0x0e17, 0x0e2b, 0x0e3f, 0x0e53, 0x0e68, 0x0e7d,
0x0e92, 0x0eae, 0x0eca, 0x0ee3, 0x0ef4, 0x0f06, 0x0f17, 0x0f29,
0x0f3b, 0x0f4c, 0x0f5e, 0x0f6f, 0x0f81, 0x0f93, 0x0fa5, 0x0fb8,
// Entry 5240 - 527F
0x0fca, 0x0fdd, 0x0fef, 0x1000, 0x1012, 0x1023, 0x1035, 0x1046,
0x1057, 0x1069, 0x107a, 0x108c, 0x109d, 0x10af, 0x10c2, 0x10d4,
0x10e6, 0x10f7, 0x1108, 0x1119, 0x112a, 0x113b, 0x114c, 0x115e,
0x1170, 0x1181, 0x1192, 0x11a5, 0x11bd, 0x11d5, 0x11f6, 0x1217,
0x1239, 0x125a, 0x1278, 0x1296, 0x12b5, 0x12d3, 0x12f1, 0x130f,
0x132d, 0x134b, 0x1369, 0x1388, 0x13a6, 0x13c5, 0x13da, 0x13ee,
0x1405, 0x1416, 0x1428, 0x1439, 0x1451, 0x1463, 0x1497, 0x14c4,
0x14e7, 0x14fe, 0x1515, 0x1533, 0x1552, 0x1570, 0x158f, 0x15ad,
// Entry 5280 - 52BF
0x15cc, 0x15ec, 0x160d, 0x162d, 0x164e, 0x166e, 0x168f, 0x16a5,
0x16bb, 0x16d1, 0x16e7, 0x16fc, 0x1711, 0x1726, 0x173b, 0x1750,
0x1765, 0x177a, 0x1790, 0x17a5, 0x17ba, 0x17d0, 0x17e5, 0x17fa,
0x180f, 0x1824, 0x183a, 0x184f, 0x1865, 0x187a, 0x188f, 0x18a5,
0x18b9, 0x18cd, 0x18e1, 0x18f5, 0x1909, 0x191e, 0x1933, 0x194d,
0x1967, 0x1981, 0x199b, 0x19b5, 0x19cf, 0x19e9, 0x1a04, 0x1a1e,
0x1a3a, 0x1a51, 0x1a70, 0x1a92, 0x1aaf, 0x1ad4, 0x1af0, 0x1b07,
0x1b29, 0x1b46, 0x1b60, 0x1b80, 0x1ba5, 0x1bc5, 0x1be6, 0x1c02,
// Entry 52C0 - 52FF
0x1c1a, 0x1c41, 0x1c63, 0x1c81, 0x1c95, 0x1cb9, 0x1cce, 0x1ced,
0x1d0b, 0x1d33, 0x1d5a, 0x1d81, 0x1da9, 0x1dbe, 0x1dd0, 0x1de3,
0x1df5, 0x1e08, 0x1e1a, 0x1e2d, 0x1e47, 0x1e62, 0x1e7c, 0x1e8e,
0x1ea1, 0x1eb3, 0x1ec6, 0x1ed9, 0x1eed, 0x1f00, 0x1f14, 0x1f28,
0x1f3b, 0x1f4f, 0x1f62, 0x1f76, 0x1f8a, 0x1f9e, 0x1fb3, 0x1fc7,
0x1fdc, 0x1ff0, 0x2003, 0x2017, 0x202a, 0x203e, 0x2051, 0x2064,
0x2078, 0x208b, 0x209f, 0x20b2, 0x20c5, 0x20d8, 0x20eb, 0x20fe,
0x2112, 0x2126, 0x2139, 0x214c, 0x2163, 0x2179, 0x2190, 0x21a6,
// Entry 5300 - 533F
0x21bd, 0x21db, 0x21fa, 0x2218, 0x222e, 0x2245, 0x225b, 0x2272,
0x228c, 0x22a3, 0x22b9, 0x22ce, 0x22e5, 0x22f4, 0x230a, 0x2322,
0x2338, 0x234e, 0x2362, 0x2375, 0x2388, 0x239d, 0x23b1, 0x23c5,
0x23d8, 0x23ed, 0x2402, 0x2416, 0x242a, 0x243e, 0x2454, 0x2469,
0x247e, 0x2492, 0x24a8, 0x24be, 0x24d3, 0x24e7, 0x24fe, 0x2515,
0x252b, 0x2541, 0x2557, 0x256f, 0x2586, 0x259d, 0x25b9, 0x25ca,
0x25db, 0x25ec, 0x25fe, 0x260f, 0x2621, 0x2632, 0x2644, 0x2655,
0x2667, 0x2678, 0x268a, 0x269b, 0x26ac, 0x26bd, 0x26cf, 0x26e0,
// Entry 5340 - 537F
0x26f1, 0x2703, 0x2716, 0x2728, 0x2739, 0x274b, 0x275c, 0x276d,
0x277e, 0x278f, 0x27a0, 0x27b2, 0x27c3, 0x27d4, 0x27e4, 0x27ff,
0x281b, 0x2836, 0x2852, 0x286d, 0x2889, 0x28a4, 0x28c0, 0x28db,
0x28f7, 0x2912, 0x292d, 0x2948, 0x2964, 0x297f, 0x299a, 0x29b6,
0x29d3, 0x29ef, 0x2a0a, 0x2a26, 0x2a41, 0x2a5c, 0x2a77, 0x2a92,
0x2aae, 0x2ac9, 0x2ae4, 0x2afe, 0x2b13, 0x2b27, 0x2b3b, 0x2b4f,
0x2b63, 0x2b78, 0x2b90, 0x2ba6, 0x2bbd, 0x2bd3, 0x2bea, 0x2c00,
0x2c17, 0x2c2d, 0x2c44, 0x2c5a, 0x2c71, 0x2c88, 0x2ca0, 0x2cb7,
// Entry 5380 - 53BF
0x2ccf, 0x2ce7, 0x2cfe, 0x2d16, 0x2d2d, 0x2d45, 0x2d5d, 0x2d75,
0x2d8e, 0x2da6, 0x2dbf, 0x2dd7, 0x2dee, 0x2e06, 0x2e1d, 0x2e35,
0x2e4c, 0x2e63, 0x2e7b, 0x2e92, 0x2eaa, 0x2ec1, 0x2ed8, 0x2eef,
0x2f06, 0x2f1d, 0x2f35, 0x2f4d, 0x2f64, 0x2f7b, 0x2f93, 0x2fac,
0x2fc5, 0x2fdd, 0x2ff8, 0x3012, 0x302d, 0x3047, 0x3062, 0x3084,
0x309e, 0x30b9, 0x30d3, 0x30ee, 0x3109, 0x3123, 0x313b, 0x3154,
0x316e, 0x3182, 0x3195, 0x31aa, 0x31c2, 0x31d9, 0x31f0, 0x3209,
0x3221, 0x3239, 0x3250, 0x3269, 0x3282, 0x329a, 0x32b0, 0x32c7,
// Entry 53C0 - 53FF
0x32dd, 0x32f4, 0x330a, 0x3321, 0x3338, 0x334f, 0x3366, 0x337d,
0x3394, 0x33ab, 0x33c2, 0x33da, 0x33f1, 0x3408, 0x3420, 0x3437,
0x344f, 0x3466, 0x347d, 0x3495, 0x34ac, 0x34c4, 0x34db, 0x34f2,
0x350a, 0x3522, 0x353b, 0x3553, 0x356a, 0x3582, 0x359a, 0x35b3,
0x35cb, 0x35e2, 0x35fa, 0x3611, 0x3628, 0x363f, 0x365a, 0x3674,
0x368f, 0x36a9, 0x36c4, 0x36df, 0x36fa, 0x3715, 0x3730, 0x374b,
0x3765, 0x3779, 0x3789, 0x37a1, 0x37b8, 0x37cf, 0x37e8, 0x3800,
0x3818, 0x382f, 0x3848, 0x3861, 0x3879, 0x388a, 0x389b, 0x38ad,
// Entry 5400 - 543F
0x38be, 0x38cf, 0x38e0, 0x38f1, 0x3902, 0x3913, 0x3924, 0x3935,
0x3947, 0x3958, 0x3969, 0x397a, 0x398b, 0x399c, 0x39ac, 0x39b9,
0x39cd, 0x39e1, 0x39f5, 0x3a09, 0x3a1b, 0x3a31, 0x3a46, 0x3a58,
0x3a67, 0x3a78, 0x3a85, 0x3a93, 0x3aa0, 0x3aae, 0x3abb, 0x3ac9,
0x3ade, 0x3af4, 0x3b09, 0x3b1f, 0x3b2c, 0x3b3a, 0x3b47, 0x3b55,
0x3b64, 0x3b72, 0x3b81, 0x3b90, 0x3b9e, 0x3bad, 0x3bbb, 0x3bca,
0x3bd9, 0x3be8, 0x3bf8, 0x3c07, 0x3c17, 0x3c26, 0x3c34, 0x3c43,
0x3c51, 0x3c60, 0x3c6e, 0x3c7c, 0x3c8b, 0x3c99, 0x3ca8, 0x3cb6,
// Entry 5440 - 547F
0x3cc4, 0x3cd2, 0x3ce0, 0x3cee, 0x3cfd, 0x3d0c, 0x3d1a, 0x3d28,
0x3d38, 0x3d4a, 0x3d66, 0x3d77, 0x3d89, 0x3d9a, 0x3dac, 0x3dc5,
0x3dd6, 0x3de8, 0x3dfa, 0x3e0a, 0x3e18, 0x3e22, 0x3e33, 0x3e52,
0x3e7b, 0x3e92, 0x3eaf, 0x3ec3, 0x3ede, 0x3ef9, 0x3f10, 0x3f2e,
0x3f45, 0x3f64, 0x3f73, 0x3f81, 0x3f8f, 0x3f9f, 0x3fae, 0x3fbd,
0x3fcb, 0x3fdb, 0x3feb, 0x3ffa, 0x4009, 0x4037, 0x4062, 0x407e,
0x409d, 0x40b8, 0x40d8, 0x40f7, 0x4119, 0x4135, 0x4153, 0x4171,
0x4189, 0x41a2, 0x41c1, 0x41e0, 0x41f8, 0x4212, 0x422b, 0x4244,
// Entry 5480 - 54BF
0x4261, 0x4288, 0x4296, 0x42a7, 0x42bb, 0x42cd, 0x42e3, 0x42f4,
0x4307, 0x431b, 0x432b, 0x433b, 0x4349, 0x435c, 0x436d, 0x437d,
0x438c, 0x43a6, 0x43c0, 0x43cf, 0x43e2, 0x43ff, 0x441c, 0x442e,
0x4440, 0x4450, 0x4460, 0x4478, 0x4490, 0x44a4, 0x44b9, 0x44d6,
0x44e6, 0x44fe, 0x4518, 0x4538, 0x4551, 0x456b, 0x458c, 0x45a7,
0x45c1, 0x45d2, 0x45e3, 0x45ff, 0x4620, 0x463b, 0x465c, 0x4676,
0x4696, 0x46b2, 0x46cf, 0x46ec, 0x4713, 0x4729, 0x473b, 0x4759,
0x477b, 0x479e, 0x47bb, 0x47d8, 0x47e9, 0x47fa, 0x4817, 0x483e,
// Entry 54C0 - 54FF
0x484f, 0x4869, 0x4885, 0x48a1, 0x48bb, 0x48d7, 0x48f1, 0x490c,
0x4927, 0x493a, 0x494e, 0x4961, 0x497e, 0x498f, 0x49a8, 0x49c5,
0x49f6, 0x4a19, 0x4a2d, 0x4a40, 0x4a53, 0x4a70, 0x4a84, 0x4a98,
0x4aaa, 0x4ac6, 0x4ae2, 0x4b1f, 0x4b43, 0x4b86, 0x4b99, 0x4bae,
0x4bbf, 0x4bd1, 0x4be4, 0x4bf9, 0x4c0b, 0x4c26, 0x4c3a, 0x4c4c,
0x4c60, 0x4c71, 0x4c8a, 0x4ca5, 0x4cc5, 0x4cd6, 0x4cf2, 0x4d0e,
0x4d2b, 0x4d3f, 0x4d5e, 0x4d70, 0x4d83, 0x4d94, 0x4da6, 0x4dd1,
0x4df5, 0x4e1a, 0x4e3c, 0x4e5e, 0x4e8a, 0x4eac, 0x4ed0, 0x4ef3,
// Entry 5500 - 553F
0x4f15, 0x4f37, 0x4f61, 0x4f84, 0x4fa6, 0x4fc8, 0x4ff5, 0x5018,
0x503a, 0x5066, 0x5088, 0x50ac, 0x50d8, 0x50fb, 0x510d, 0x511f,
0x5133, 0x5147, 0x5158, 0x516a, 0x517c, 0x5198, 0x51ab, 0x51bd,
0x51e2, 0x51f5, 0x5206, 0x521f, 0x5235, 0x524e, 0x5260, 0x527d,
0x5290, 0x52a2, 0x52b6, 0x52c8, 0x52da, 0x52ed, 0x5305, 0x5322,
0x5335, 0x5348, 0x5358, 0x5372, 0x5396, 0x53a7, 0x53d0, 0x53eb,
0x5405, 0x5420, 0x543b, 0x5454, 0x5467, 0x547a, 0x548b, 0x549c,
0x54b8, 0x54d9, 0x54f3, 0x5510, 0x552d, 0x5546, 0x5559, 0x556d,
// Entry 5540 - 557F
0x5580, 0x5593, 0x55ae, 0x55d2, 0x5600, 0x561c, 0x5639, 0x565c,
0x5684, 0x56a0, 0x56c1, 0x56e3, 0x5703, 0x572b, 0x5748, 0x5764,
0x578b, 0x57a7, 0x57c3, 0x57df, 0x57fb, 0x580c, 0x5822, 0x5834,
0x585e, 0x5880, 0x58a3, 0x58cd, 0x58e8, 0x5904, 0x592a, 0x5946,
0x596a, 0x5986, 0x59aa, 0x59c5, 0x59e0, 0x5a06, 0x5a22, 0x5a3d,
0x5a60, 0x5a7b, 0x5aa6, 0x5ac8, 0x5ae4, 0x5aff, 0x5b1b, 0x5b3e,
0x5b63, 0x5b90, 0x5bac, 0x5bd0, 0x5bf3, 0x5c10, 0x5c31, 0x5c5e,
0x5c7a, 0x5c99, 0x5cb5, 0x5cda, 0x5cfe, 0x5d19, 0x5d3c, 0x5d57,
// Entry 5580 - 55BF
0x5d73, 0x5d98, 0x5db3, 0x5dcf, 0x5deb, 0x5e07, 0x5e2c, 0x5e49,
0x5e65, 0x5e82, 0x5e9c, 0x5eb7, 0x5eda, 0x5ef5, 0x5f08, 0x5f29,
0x5f3b, 0x5f63, 0x5f75, 0x5fa1, 0x5fb5, 0x5fc7, 0x5fd9, 0x5fec,
0x6004, 0x6021, 0x6042, 0x6054, 0x6067, 0x607c, 0x6092, 0x60b2,
0x60c3, 0x60dc, 0x60f5, 0x6112, 0x6124, 0x613f, 0x615e, 0x6172,
0x6185, 0x619d, 0x61b0, 0x61d4, 0x61f7, 0x6214, 0x6239, 0x6255,
0x6269, 0x627c, 0x629d, 0x62ba, 0x62d8, 0x62f0, 0x6301, 0x631e,
0x6330, 0x634c, 0x6377, 0x6393, 0x63b9, 0x63d0, 0x63e2, 0x6405,
// Entry 55C0 - 55FF
0x6421, 0x6442, 0x6454, 0x6466, 0x6482, 0x6494, 0x64a7, 0x64bb,
0x64d0, 0x64e1, 0x64f7, 0x650d, 0x651f, 0x6530, 0x654b, 0x6567,
0x6582, 0x659e, 0x65b9, 0x65d4, 0x65ef, 0x660a, 0x6623, 0x6634,
0x6647, 0x6663, 0x6680, 0x66a0, 0x66be, 0x66da, 0x66ed, 0x66fd,
0x670f, 0x6720, 0x6733, 0x6754, 0x6779, 0x678a, 0x679c, 0x67b2,
0x67c7, 0x67fc, 0x6813, 0x6824, 0x6845, 0x6857, 0x6868, 0x6884,
0x68a1, 0x68be, 0x68d7, 0x68ea, 0x68fb, 0x690c, 0x691e, 0x692f,
0x6948, 0x6962, 0x6985, 0x69a1, 0x69bc, 0x69d9, 0x69f4, 0x6a0e,
// Entry 5600 - 563F
0x6a2b, 0x6a47, 0x6a61, 0x6a7c, 0x6a9d, 0x6ab8, 0x6ae4, 0x6afe,
0x6b1a, 0x6b3f, 0x6b69, 0x6b83, 0x6b9f, 0x6bba, 0x6bd4, 0x6bef,
0x6c09, 0x6c24, 0x6c3e, 0x6c58, 0x6c72, 0x6c94, 0x6cb6, 0x6cd8,
0x6cf2, 0x6d17, 0x6d31, 0x6d4c, 0x6d66, 0x6d80, 0x6d9a, 0x6db5,
0x6dd0, 0x6deb, 0x6e07, 0x6e22, 0x6e3d, 0x6e5a, 0x6e75, 0x6e8e,
0x6ea8, 0x6ec2, 0x6ee7, 0x6f02, 0x6f1c, 0x6f2e, 0x6f4d, 0x6f5f,
0x6f72, 0x6f85, 0x6f98, 0x6fab, 0x6fc8, 0x6fda, 0x6ffb, 0x700d,
0x7029, 0x7048, 0x705b, 0x706e, 0x7083, 0x70b9, 0x70fb, 0x710f,
// Entry 5640 - 567F
0x7120, 0x713b, 0x7154, 0x716e, 0x7180, 0x7192, 0x71a6, 0x71b9,
0x71ce, 0x71ef, 0x7200, 0x723a, 0x724c, 0x725e, 0x727d, 0x728f,
0x72a1, 0x72b8, 0x72ca, 0x72dc, 0x72fb, 0x7310, 0x7325, 0x7336,
0x734a, 0x7366, 0x7392, 0x73b7, 0x73dc, 0x73f9, 0x7416, 0x743e,
0x745c, 0x7479, 0x7497, 0x74b4, 0x74d1, 0x74ef, 0x750d, 0x7534,
0x7551, 0x756f, 0x7596, 0x75b9, 0x75d6, 0x75fb, 0x7620, 0x763d,
0x765b, 0x7679, 0x7697, 0x76c4, 0x76e4, 0x7703, 0x7720, 0x773e,
0x775b, 0x7780, 0x779f, 0x77bc, 0x77e3, 0x7818, 0x7847, 0x7866,
// Entry 5680 - 56BF
0x788f, 0x78ad, 0x78cb, 0x78ea, 0x791e, 0x793a, 0x795d, 0x7987,
0x79ad, 0x79ca, 0x79e8, 0x7a04, 0x7a18, 0x7a36, 0x7a5d, 0x7a76,
0x7aa3, 0x7ab8, 0x7aca, 0x7ae6, 0x7af8, 0x7b14, 0x7b38, 0x7b49,
0x7b5b, 0x7b70, 0x7b83, 0x7b94, 0x7baf, 0x7bc1, 0x7bdc, 0x7bf8,
0x7c15, 0x7c37, 0x7c59, 0x7c7e, 0x7c99, 0x7cb6, 0x7cd3, 0x7cf9,
0x7d14, 0x7d38, 0x7d56, 0x7d79, 0x7d94, 0x7daf, 0x7dd3, 0x7df8,
0x7e15, 0x7e2c, 0x7e4b, 0x7e6a, 0x7e84, 0x7e9e, 0x7eb0, 0x7ec4,
0x7ee3, 0x7f06, 0x7f22, 0x7f34, 0x7f46, 0x7f58, 0x7f73, 0x7f9b,
// Entry 56C0 - 56FF
0x7fac, 0x7fc8, 0x7fde, 0x7ff0, 0x8002, 0x8014, 0x8027, 0x803b,
0x804c, 0x805e, 0x806f, 0x8081, 0x8092, 0x80ab, 0x80bd, 0x80d4,
0x80e9, 0x80fe, 0x8111, 0x812c, 0x8149, 0x8165, 0x8182, 0x81af,
0x81d0, 0x81e4, 0x8200, 0x8224, 0x8241, 0x825a, 0x826b, 0x827d,
0x8290, 0x82ac, 0x82ce, 0x82ef, 0x8303, 0x831d, 0x832f, 0x8342,
0x8353, 0x836c, 0x8386, 0x839f, 0x83b0, 0x83c9, 0x83db, 0x83ed,
0x840f, 0x843a, 0x844f, 0x846d, 0x848c, 0x84b4, 0x84d3, 0x8500,
0x851e, 0x853d, 0x855c, 0x8585, 0x85ad, 0x85de, 0x8605, 0x8624,
// Entry 5700 - 573F
0x8638, 0x8649, 0x865c, 0x866e, 0x8690, 0x86b3, 0x86d5, 0x8710,
0x8732, 0x8749, 0x8764, 0x8783, 0x87b3, 0x87c7, 0x87ec, 0x880d,
0x882f, 0x8851, 0x8878, 0x889b, 0x88bc, 0x88dd, 0x8901, 0x8922,
0x8946, 0x896c, 0x897d, 0x898f, 0x89a1, 0x89b3, 0x89c7, 0x89d8,
0x89f1, 0x8a0b, 0x8a25, 0x8a3f, 0x8a58, 0x8a71, 0x8a8b, 0x8aa4,
0x8abe, 0x8adb, 0x8aef, 0x8b0d, 0x8b2a, 0x8b47, 0x8b6a, 0x8b7b,
0x8b8d, 0x8b9e, 0x8baf, 0x8bc0, 0x8bda, 0x8bec, 0x8c06, 0x8c21,
0x8c3d, 0x8c58, 0x8c74, 0x8c90, 0x8cac, 0x8cc7, 0x8ce3, 0x8cff,
// Entry 5740 - 577F
0x8d1c, 0x8d38, 0x8d53, 0x8d6e, 0x8d89, 0x8da4, 0x8dc0, 0x8ddb,
0x8df2, 0x8e04, 0x8e27, 0x8e3c, 0x8e4e, 0x8e60, 0x8e73, 0x8e8e,
0x8eab, 0x8ec9, 0x8ee5, 0x8f03, 0x8f20, 0x8f3b, 0x8f5d, 0x8f70,
0x8f84, 0x8f98, 0x8faa, 0x8fbf, 0x8ff4, 0x9029, 0x903d, 0x9050,
0x9064, 0x9079, 0x9090, 0x90a3, 0x90be, 0x90da, 0x90ed, 0x9108,
0x9125, 0x9144, 0x9161, 0x917e, 0x919b, 0x91bd, 0x91dd, 0x91fa,
0x9217, 0x9234, 0x9249, 0x925c, 0x9274, 0x929e, 0x92b2, 0x92c4,
0x92e8, 0x92fb, 0x9310, 0x9321, 0x9337, 0x9349, 0x935c, 0x937e,
// Entry 5780 - 57BF
0x9391, 0x93a5, 0x93b6, 0x93cf, 0x93e1, 0x93f4, 0x9408, 0x941a,
0x942f, 0x9441, 0x9454, 0x9465, 0x947f, 0x9499, 0x94b3, 0x94c9,
0x94db, 0x9510, 0x952a, 0x953c, 0x9557, 0x9573, 0x958f, 0x95ab,
0x95c8, 0x95e3, 0x95f6, 0x9608, 0x9619, 0x962f, 0x9640, 0x9656,
0x9668, 0x967a, 0x9697, 0x96b2, 0x96e7, 0x96f8, 0x970b, 0x971d,
0x972f, 0x9741, 0x9767, 0x9777, 0x978b, 0x979f, 0x97ce, 0x97f2,
0x9824, 0x9835, 0x9846, 0x9857, 0x986f, 0x988a, 0x98a4, 0x98cb,
0x98f7, 0x990d, 0x9926, 0x9949, 0x995c, 0x996d, 0x998a, 0x99ac,
// Entry 57C0 - 57FF
0x99c8, 0x99e1, 0x99f5, 0x9a08, 0x9a28, 0x9a44, 0x9a55, 0x9a6b,
0x9a7c, 0x9a99, 0x9ab2, 0x9ac4, 0x9ae6, 0x9b08, 0x9b23, 0x9b3e,
0x9b5a, 0x9b75, 0x9b99, 0x9bbc, 0x9bce, 0x9be0, 0x9bf3, 0x9c05,
0x9c1f, 0x9c3e, 0x9c5a, 0x9c76, 0x9c91, 0x9cad, 0x9ccf, 0x9ceb,
0x9d06, 0x9d21, 0x9d3d, 0x9d58, 0x9d74, 0x9d8f, 0x9dab, 0x9dc7,
0x9de2, 0x9dfe, 0x9e1b, 0x9e36, 0x9e59, 0x9e74, 0x9e92, 0x9ea6,
0x9ec2, 0x9ed4, 0x9eee, 0x9f09, 0x9f25, 0x9f42, 0x9f55, 0x9f68,
0x9f7d, 0x9f91, 0x9fa3, 0x9fc2, 0x9fd4, 0x9fe5, 0x9ffb, 0xa01e,
// Entry 5800 - 583F
0xa030, 0xa043, 0xa055, 0xa066, 0xa07f, 0xa091, 0xa0a3, 0xa0bf,
0xa0d1, 0xa0e4, 0xa0f5, 0xa107, 0xa121, 0xa135, 0xa147, 0xa161,
0xa17c, 0xa196, 0xa1b3, 0xa1df, 0xa1f2, 0xa20e, 0xa22a, 0xa247,
0xa264, 0xa28f, 0xa2ac, 0xa2bf, 0xa2d1, 0xa2e4, 0xa301, 0xa31d,
0xa339, 0xa354, 0xa379, 0xa394, 0xa3ae, 0xa3ca, 0xa3e4, 0xa3ff,
0xa41c, 0xa440, 0xa466, 0xa482, 0xa495, 0xa4b2, 0xa4c4, 0xa4d6,
0xa4e9, 0xa508, 0xa526, 0xa550, 0xa56d, 0xa580, 0xa5a1, 0xa5b3,
0xa5cd, 0xa5df, 0xa5fd, 0xa61d, 0xa63c, 0xa65b, 0xa679, 0xa699,
// Entry 5840 - 587F
0xa6b9, 0xa6d8, 0xa6f9, 0xa719, 0xa739, 0xa758, 0xa779, 0xa79a,
0xa7ba, 0xa7d7, 0xa7f4, 0xa810, 0xa82e, 0xa84c, 0xa869, 0xa889,
0xa8a9, 0xa8cb, 0xa8ec, 0xa90d, 0xa92d, 0xa94f, 0xa971, 0xa992,
0xa9b2, 0xa9d2, 0xa9f4, 0xaa15, 0xaa36, 0xaa56, 0xaa78, 0xaaa7,
0xaac8, 0xaae9, 0xab09, 0xab2b, 0xab4d, 0xab6e, 0xab8e, 0xabae,
0xabd0, 0xabff, 0xac20, 0xac41, 0xac71, 0xaca0, 0xacbf, 0xacde,
0xacff, 0xad2d, 0xad4d, 0xad6d, 0xad9c, 0xadcb, 0xadf9, 0xae28,
0xae58, 0xae88, 0xaeb4, 0xaee3, 0xaf13, 0xaf43, 0xaf71, 0xafa0,
// Entry 5880 - 58BF
0xafcf, 0xafff, 0xb02f, 0xb060, 0xb083, 0xb0a8, 0xb0cc, 0xb0f0,
0xb113, 0xb132, 0xb151, 0xb172, 0xb192, 0xb1bf, 0xb1df, 0xb20c,
0xb22c, 0xb24c, 0xb26c, 0xb28c, 0xb2b1, 0xb2d7, 0xb2fe, 0xb32d,
0xb35d, 0xb382, 0xb3a8, 0xb3d5, 0xb404, 0xb42a, 0xb44d, 0xb475,
0xb49e, 0xb4c2, 0xb4e6, 0xb510, 0xb53a, 0xb563, 0xb58e, 0xb5b9,
0xb5e3, 0xb617, 0xb640, 0xb669, 0xb695, 0xb6c2, 0xb6e2, 0xb6fe,
0xb71a, 0xb73c, 0xb75b, 0xb779, 0xb797, 0xb7ba, 0xb7d6, 0xb7f2,
0xb80e, 0xb82c, 0xb848, 0xb866, 0xb882, 0xb8a6, 0xb8c2, 0xb8de,
// Entry 58C0 - 58FF
0xb8fc, 0xb917, 0xb932, 0xb954, 0xb971, 0xb98c, 0xb9a7, 0xb9c8,
0xb9e7, 0xba03, 0xba22, 0xba4d, 0xba6d, 0xba89, 0xbaaf, 0xbad5,
0xbaf2, 0xbb0e, 0xbb29, 0xbb44, 0xbb5f, 0xbb7b, 0xbb9b, 0xbbb6,
0xbbd1, 0xbbe7, 0xbc08, 0xbc2d, 0xbc51, 0xbc7b, 0xbc9f, 0xbcc4,
0xbce8, 0xbd0d, 0xbd31, 0xbd4d, 0xbd6c, 0xbd8d, 0xbdb8, 0xbde1,
0xbdfe, 0xbe19, 0xbe3d, 0xbe61, 0xbe83, 0xbeae, 0xbeca, 0xbef0,
0xbf0c, 0xbf29, 0xbf44, 0xbf67, 0xbf8a, 0xbfa7, 0xbfc4, 0xbfee,
0xc00c, 0xc038, 0xc059, 0xc080, 0xc09b, 0xc0c8, 0xc0e2, 0xc0fc,
// Entry 5900 - 593F
0xc119, 0xc133, 0xc158, 0xc16e, 0xc184, 0xc19a, 0xc1b0, 0xc1c6,
0xc1dc, 0xc1f2, 0xc21a, 0xc230, 0xc253, 0xc269, 0xc27f, 0xc295,
0xc2ab, 0xc2c1, 0xc2d7, 0xc2ed, 0xc303, 0xc319, 0xc32f, 0xc345,
0xc35b, 0xc371, 0xc387, 0xc39d, 0xc3b3, 0xc3c9, 0xc3df, 0xc3f5,
0xc414, 0xc434, 0xc45d, 0xc48f, 0xc4b6, 0xc4cc, 0xc4e2, 0xc4f8,
0xc50e, 0xc524, 0xc53a, 0xc550, 0xc566, 0xc57c, 0xc592, 0xc5a8,
0xc5c8, 0xc5e8, 0xc613, 0xc633, 0xc652, 0xc672, 0xc691, 0xc6b0,
0xc6cf, 0xc6f1, 0xc707, 0xc71d, 0xc73d, 0xc75c, 0xc77c, 0xc7a1,
// Entry 5940 - 597F
0xc7c0, 0xc7f2, 0xc81c, 0xc83b, 0xc85d, 0xc873, 0xc889, 0xc8aa,
0xc8c7, 0xc8e3, 0xc8ff, 0xc92d, 0xc94a, 0xc964, 0xc98a, 0xc9b1,
0xc9d5, 0xc9f5, 0xca14, 0xca32, 0xca53, 0xca76, 0xca96, 0xcabe,
0xcadb, 0xcaff, 0xcb20, 0xcb40, 0xcb5b, 0xcb7f, 0xcb9c, 0xcbb4,
0xcbcf, 0xcbeb, 0xcc07, 0xcc22, 0xcc47, 0xcc6b, 0xcc87, 0xcca3,
0xccc5, 0xcce8, 0xcd03, 0xcd1e, 0xcd3c, 0xcd5c, 0xcd78, 0xcd8a,
0xcdac, 0xcdd4, 0xcdeb, 0xce02, 0xce19, 0xce30, 0xce47, 0xce5e,
0xce75, 0xce8c, 0xcea3, 0xceba, 0xced1, 0xcee9, 0xcf00, 0xcf17,
// Entry 5980 - 59BF
0xcf2e, 0xcf45, 0xcf5c, 0xcf73, 0xcf8a, 0xcfa1, 0xcfb8, 0xcfcf,
0xcfe6, 0xcffd, 0xd014, 0xd02b, 0xd042, 0xd059, 0xd070, 0xd087,
0xd09e, 0xd0b5, 0xd0cc, 0xd0e3, 0xd0fa, 0xd111, 0xd128, 0xd13f,
0xd156, 0xd16d, 0xd184, 0xd19b, 0xd1b2, 0xd1c9, 0xd1e0, 0xd1f7,
0xd20e, 0xd225, 0xd23c, 0xd253, 0xd26a, 0xd281, 0xd298, 0xd2af,
0xd2c6, 0xd2dd, 0xd2f4, 0xd30b, 0xd322, 0xd339, 0xd350, 0xd367,
0xd37f, 0xd396, 0xd3ad, 0xd3c4, 0xd3db, 0xd3f2, 0xd409, 0xd420,
0xd437, 0xd44e, 0xd465, 0xd47c, 0xd493, 0xd4aa, 0xd4c1, 0xd4d8,
// Entry 59C0 - 59FF
0xd4ef, 0xd506, 0xd51d, 0xd534, 0xd54b, 0xd562, 0xd579, 0xd590,
0xd5a7, 0xd5be, 0xd5d5, 0xd5ec, 0xd603, 0xd61a, 0xd631, 0xd648,
0xd65f, 0xd676, 0xd68d, 0xd6a4, 0xd6bb, 0xd6d3, 0xd6eb, 0xd703,
0xd71b, 0xd733, 0xd74c, 0xd764, 0xd77d, 0xd796, 0xd7ae, 0xd7c6,
0xd7de, 0xd7f6, 0xd80e, 0xd826, 0xd83e, 0xd856, 0xd86f, 0xd887,
0xd89f, 0xd8b7, 0xd8d0, 0xd8e8, 0xd900, 0xd918, 0xd930, 0xd948,
0xd960, 0xd978, 0xd990, 0xd9a8, 0xd9c0, 0xd9d8, 0xd9f0, 0xda08,
0xda20, 0xda38, 0xda51, 0xda69, 0xda81, 0xda99, 0xdab1, 0xdac9,
// Entry 5A00 - 5A3F
0xdae1, 0xdaf9, 0xdb11, 0xdb2a, 0xdb42, 0xdb5a, 0xdb73, 0xdb8b,
0xdba4, 0xdbbc, 0xdbd4, 0xdbed, 0xdc05, 0xdc1d, 0xdc35, 0xdc4d,
0xdc65, 0xdc7d, 0xdc95, 0xdcad, 0xdcc5, 0xdcdd, 0xdcf5, 0xdd0d,
0xdd25, 0xdd3d, 0xdd55, 0xdd6d, 0xdd85, 0xdd9d, 0xddb5, 0xddcd,
0xdde5, 0xddfd, 0xde15, 0xde2d, 0xde45, 0xde5d, 0xde75, 0xde8d,
0xdea5, 0xdebd, 0xded6, 0xdeee, 0xdf06, 0xdf1e, 0xdf36, 0xdf4e,
0xdf66, 0xdf7f, 0xdf98, 0xdfb1, 0xdfc9, 0xdfe1, 0xdff9, 0xe011,
0xe029, 0xe041, 0xe059, 0xe071, 0xe08a, 0xe0a2, 0xe0ba, 0xe0d2,
// Entry 5A40 - 5A7F
0xe0ea, 0xe102, 0xe11a, 0xe132, 0xe14a, 0xe162, 0xe17a, 0xe192,
0xe1aa, 0xe1c2, 0xe1da, 0xe1f2, 0xe20a, 0xe222, 0xe23a, 0xe252,
0xe26a, 0xe282, 0xe29a, 0xe2b3, 0xe2cb, 0xe2e3, 0xe2fb, 0xe313,
0xe32b, 0xe343, 0xe35b, 0xe373, 0xe38b, 0xe3a3, 0xe3bb, 0xe3d3,
0xe3eb, 0xe403, 0xe41b, 0xe433, 0xe44b, 0xe463, 0xe47b, 0xe494,
0xe4ac, 0xe4c4, 0xe4dc, 0xe4f4, 0xe50d, 0xe525, 0xe53d, 0xe555,
0xe56e, 0xe586, 0xe59e, 0xe5b6, 0xe5ce, 0xe5e6, 0xe5fe, 0xe616,
0xe62e, 0xe646, 0xe65e, 0xe676, 0xe68e, 0xe6a7, 0xe6bf, 0xe6d7,
// Entry 5A80 - 5ABF
0xe6f0, 0xe708, 0xe720, 0xe739, 0xe752, 0xe76b, 0xe784, 0xe79d,
0xe7b6, 0xe7cf, 0xe7e8, 0xe801, 0xe819, 0xe831, 0xe84a, 0xe862,
0xe87a, 0xe893, 0xe8ab, 0xe8c3, 0xe8db, 0xe8f3, 0xe90b, 0xe923,
0xe93b, 0xe953, 0xe96b, 0xe983, 0xe99b, 0xe9b3, 0xe9cb, 0xe9e4,
0xe9fd, 0xea16, 0xea2f, 0xea48, 0xea61, 0xea7a, 0xea93, 0xeaab,
0xeac3, 0xeadb, 0xeaf3, 0xeb0b, 0xeb23, 0xeb3b, 0xeb53, 0xeb6c,
0xeb84, 0xeb9d, 0xebb5, 0xebcd, 0xebe5, 0xebfd, 0xec15, 0xec2d,
0xec45, 0xec5e, 0xec76, 0xec8f, 0xeca7, 0xecbf, 0xecd7, 0xecf0,
// Entry 5AC0 - 5AFF
0xed08, 0xed20, 0xed38, 0xed50, 0xed68, 0xed80, 0xed98, 0xedb0,
0xedc9, 0xede1, 0xedf9, 0xee11, 0xee29, 0xee41, 0xee59, 0xee72,
0xee8a, 0xeea2, 0xeeba, 0xeed2, 0xeeeb, 0xef03, 0xef1b, 0xef33,
0xef4b, 0xef63, 0xef7b, 0xef93, 0xefab, 0xefc3, 0xefdb, 0xeff3,
0xf00b, 0xf024, 0xf03c, 0xf054, 0xf06c, 0xf084, 0xf09c, 0xf0b4,
0xf0cc, 0xf0e4, 0xf0fd, 0xf115, 0xf12d, 0xf145, 0xf15d, 0xf175,
0xf18d, 0xf1a5, 0xf1bd, 0xf1d5, 0xf1ed, 0xf206, 0xf21e, 0xf236,
0xf24e, 0xf266, 0xf27e, 0xf296, 0xf2af, 0xf2c7, 0xf2e0, 0xf2f8,
// Entry 5B00 - 5B3F
0xf310, 0xf328, 0xf340, 0xf358, 0xf370, 0xf388, 0xf3a1, 0xf3b9,
0xf3d2, 0xf3ea, 0xf403, 0xf41b, 0xf433, 0xf44b, 0xf463, 0xf47c,
0xf495, 0xf4ae, 0xf4c6, 0xf4de, 0xf4f6, 0xf50e, 0xf526, 0xf53e,
0xf556, 0xf56e, 0xf587, 0xf59f, 0xf5b8, 0xf5d1, 0xf5e9, 0xf601,
0xf619, 0xf631, 0xf64a, 0xf662, 0xf67a, 0xf692, 0xf6aa, 0xf6c2,
0xf6da, 0xf6f2, 0xf70a, 0xf722, 0xf73b, 0xf753, 0xf76b, 0xf783,
0xf79b, 0xf7b3, 0xf7cb, 0xf7e4, 0xf7fc, 0xf814, 0xf82c, 0xf844,
0xf85c, 0xf874, 0xf88c, 0xf8a4, 0xf8bc, 0xf8d4, 0xf8ed, 0xf905,
// Entry 5B40 - 5B7F
0xf91e, 0xf936, 0xf94e, 0xf966, 0xf97e, 0xf996, 0xf9ae, 0xf9c7,
0xf9df, 0xf9f7, 0xfa10, 0xfa28, 0xfa40, 0xfa58, 0xfa70, 0xfa88,
0xfaa0, 0xfab8, 0xfad0, 0xfae8, 0xfb00, 0xfb18, 0xfb30, 0xfb48,
0xfb60, 0xfb78, 0xfb91, 0xfba9, 0xfbc1, 0xfbd9, 0xfbf1, 0xfc09,
0xfc21, 0xfc39, 0xfc52, 0xfc6a, 0xfc82, 0xfc9a, 0xfcb2, 0xfccb,
0xfce3, 0xfcfc, 0xfd14, 0xfd2d, 0xfd45, 0xfd5d, 0xfd75, 0xfd8d,
0xfda5, 0xfdbd, 0xfdd5, 0xfded, 0xfe05, 0xfe1d, 0xfe35, 0xfe4d,
0xfe65, 0xfe7d, 0xfe96, 0xfeae, 0xfec6, 0xfede, 0xfef6, 0xff0f,
// Entry 5B80 - 5BBF
0xff27, 0xff3f, 0xff57, 0xff70, 0xff89, 0xffa1, 0xffb9, 0xffd2,
0xffea, 0x0002, 0x001a, 0x0032, 0x004a, 0x0062, 0x007a, 0x0093,
0x00ab, 0x00c3, 0x00dc, 0x00f5, 0x010e, 0x0127, 0x0140, 0x0159,
0x0172, 0x018b, 0x01a3, 0x01bb, 0x01d3, 0x01ec, 0x0204, 0x021d,
0x0235, 0x024e, 0x0266, 0x027e, 0x0296, 0x02ae, 0x02c6, 0x02df,
0x02f7, 0x030f, 0x0328, 0x0340, 0x0358, 0x0370, 0x0388, 0x03a1,
0x03b9, 0x03d1, 0x03e9, 0x0402, 0x041a, 0x0432, 0x044b, 0x0464,
0x047c, 0x0494, 0x04ac, 0x04c4, 0x04dc, 0x04f4, 0x050c, 0x0525,
// Entry 5BC0 - 5BFF
0x053d, 0x0555, 0x056d, 0x0585, 0x059d, 0x05b5, 0x05cd, 0x05e5,
0x05fd, 0x0615, 0x062d, 0x0645, 0x065d, 0x0675, 0x068d, 0x06a5,
0x06bd, 0x06d5, 0x06ed, 0x0705, 0x071d, 0x0735, 0x074e, 0x0767,
0x077f, 0x0797, 0x07af, 0x07c7, 0x07df, 0x07f7, 0x080f, 0x0828,
0x0840, 0x0858, 0x0870, 0x0888, 0x08a0, 0x08b8, 0x08d0, 0x08e8,
0x0901, 0x0919, 0x0932, 0x094a, 0x0963, 0x097b, 0x0993, 0x09ac,
0x09c4, 0x09dc, 0x09f4, 0x0a0c, 0x0a24, 0x0a3d, 0x0a56, 0x0a6f,
0x0a88, 0x0aa1, 0x0abb, 0x0ad4, 0x0aed, 0x0b06, 0x0b1f, 0x0b38,
// Entry 5C00 - 5C3F
0x0b51, 0x0b6a, 0x0b83, 0x0b9c, 0x0bb5, 0x0bce, 0x0be7, 0x0c01,
0x0c1a, 0x0c33, 0x0c4c, 0x0c65, 0x0c7e, 0x0c97, 0x0cb0, 0x0cc9,
0x0ce2, 0x0cfb, 0x0d14, 0x0d2d, 0x0d46, 0x0d60, 0x0d79, 0x0d93,
0x0dac, 0x0dc5, 0x0dde, 0x0df7, 0x0e10, 0x0e29, 0x0e42, 0x0e5c,
0x0e75, 0x0e8e, 0x0ea7, 0x0ec0, 0x0eda, 0x0ef2, 0x0f0b, 0x0f23,
0x0f3b, 0x0f53, 0x0f6b, 0x0f84, 0x0f9c, 0x0fb5, 0x0fce, 0x0fe7,
0x1000, 0x1019, 0x1032, 0x104a, 0x1062, 0x107a, 0x1092, 0x10ab,
0x10c4, 0x10dd, 0x10f5, 0x110d, 0x1125, 0x113d, 0x1155, 0x116d,
// Entry 5C40 - 5C7F
0x1185, 0x119d, 0x11b5, 0x11ce, 0x11e6, 0x11ff, 0x1217, 0x122f,
0x1247, 0x125f, 0x1278, 0x1290, 0x12a9, 0x12c1, 0x12d9, 0x12f1,
0x1309, 0x1322, 0x133a, 0x1353, 0x136b, 0x1383, 0x139b, 0x13b4,
0x13cc, 0x13e4, 0x13fc, 0x1415, 0x142e, 0x1447, 0x1460, 0x1478,
0x1490, 0x14a8, 0x14c0, 0x14d8, 0x14f0, 0x1508, 0x1520, 0x1538,
0x1550, 0x1568, 0x1580, 0x1598, 0x15b0, 0x15c9, 0x15e2, 0x15fa,
0x1612, 0x162b, 0x1643, 0x165b, 0x1674, 0x168c, 0x16a4, 0x16bc,
0x16d4, 0x16ec, 0x1704, 0x171c, 0x1734, 0x174c, 0x1764, 0x177c,
// Entry 5C80 - 5CBF
0x1794, 0x17ac, 0x17c4, 0x17dc, 0x17f4, 0x180c, 0x1825, 0x183d,
0x1856, 0x186f, 0x1887, 0x189f, 0x18b7, 0x18cf, 0x18e7, 0x18ff,
0x1917, 0x1930, 0x1948, 0x1960, 0x1978, 0x1990, 0x19a8, 0x19c0,
0x19d9, 0x19f1, 0x1a09, 0x1a21, 0x1a39, 0x1a51, 0x1a69, 0x1a81,
0x1a99, 0x1ab1, 0x1ac9, 0x1ae1, 0x1af9, 0x1b11, 0x1b29, 0x1b41,
0x1b5a, 0x1b72, 0x1b8a, 0x1ba2, 0x1bba, 0x1bd3, 0x1beb, 0x1c03,
0x1c1b, 0x1c33, 0x1c4b, 0x1c63, 0x1c7b, 0x1c93, 0x1cac, 0x1cc5,
0x1cdd, 0x1cf5, 0x1d0d, 0x1d26, 0x1d3e, 0x1d56, 0x1d6e, 0x1d86,
// Entry 5CC0 - 5CFF
0x1d9e, 0x1db6, 0x1dce, 0x1de6, 0x1dfe, 0x1e17, 0x1e30, 0x1e48,
0x1e60, 0x1e78, 0x1e90, 0x1ea8, 0x1ec0, 0x1ed8, 0x1ef0, 0x1f08,
0x1f21, 0x1f39, 0x1f51, 0x1f69, 0x1f81, 0x1f99, 0x1fb1, 0x1fc9,
0x1fe1, 0x1ff9, 0x2011, 0x2029, 0x2041, 0x2059, 0x2071, 0x208a,
0x20a2, 0x20ba, 0x20d2, 0x20ea, 0x2103, 0x211b, 0x2134, 0x214c,
0x2165, 0x217d, 0x2195, 0x21ae, 0x21c6, 0x21de, 0x21f6, 0x220e,
0x2226, 0x223f, 0x2257, 0x226f, 0x2287, 0x229f, 0x22b7, 0x22cf,
0x22e7, 0x22ff, 0x2317, 0x232f, 0x2347, 0x235f, 0x2377, 0x238f,
// Entry 5D00 - 5D3F
0x23a7, 0x23bf, 0x23d8, 0x23f0, 0x2409, 0x2421, 0x2439, 0x2451,
0x2469, 0x2481, 0x2499, 0x24b1, 0x24c9, 0x24e1, 0x24fa, 0x2513,
0x252b, 0x2543, 0x255b, 0x2573, 0x258b, 0x25a3, 0x25bb, 0x25d3,
0x25eb, 0x2603, 0x261b, 0x2633, 0x264b, 0x2663, 0x267b, 0x2693,
0x26ab, 0x26c4, 0x26dc, 0x26f4, 0x270c, 0x2724, 0x273c, 0x2754,
0x276d, 0x2785, 0x279d, 0x27b5, 0x27ce, 0x27e6, 0x27fe, 0x2816,
0x282e, 0x2846, 0x285e, 0x2876, 0x288e, 0x28a6, 0x28be, 0x28d6,
0x28ef, 0x2908, 0x2921, 0x293a, 0x2953, 0x296c, 0x2985, 0x299e,
// Entry 5D40 - 5D7F
0x29b7, 0x29cf, 0x29e8, 0x2a00, 0x2a18, 0x2a30, 0x2a48, 0x2a60,
0x2a79, 0x2a92, 0x2aaa, 0x2ac2, 0x2ada, 0x2af2, 0x2b0b, 0x2b24,
0x2b3d, 0x2b55, 0x2b6e, 0x2b87, 0x2b9f, 0x2bb7, 0x2bcf, 0x2be7,
0x2bff, 0x2c17, 0x2c2f, 0x2c47, 0x2c60, 0x2c79, 0x2c92, 0x2cab,
0x2cc4, 0x2cdd, 0x2cf6, 0x2d0f, 0x2d28, 0x2d41, 0x2d5a, 0x2d73,
0x2d8b, 0x2da3, 0x2dbb, 0x2dd4, 0x2dec, 0x2e04, 0x2e1c, 0x2e34,
0x2e4c, 0x2e65, 0x2e7d, 0x2e96, 0x2eae, 0x2ec7, 0x2edf, 0x2ef8,
0x2f10, 0x2f28, 0x2f41, 0x2f59, 0x2f71, 0x2f89, 0x2fa1, 0x2fba,
// Entry 5D80 - 5DBF
0x2fd2, 0x2fea, 0x3002, 0x301b, 0x3033, 0x304b, 0x3063, 0x307c,
0x3094, 0x30ac, 0x30c4, 0x30dc, 0x30f4, 0x310c, 0x3125, 0x313d,
0x3156, 0x316e, 0x3186, 0x319e, 0x31b6, 0x31cf, 0x31e7, 0x31ff,
0x3217, 0x3230, 0x3248, 0x3261, 0x3279, 0x3291, 0x32a9, 0x32c1,
0x32d9, 0x32f1, 0x330a, 0x3322, 0x333a, 0x3352, 0x336a, 0x3382,
0x339b, 0x33b4, 0x33cc, 0x33e4, 0x33fd, 0x3415, 0x342d, 0x3446,
0x345e, 0x3477, 0x348f, 0x34a7, 0x34bf, 0x34d7, 0x34ef, 0x3507,
0x351f, 0x3537, 0x354f, 0x3568, 0x3581, 0x359a, 0x35b3, 0x35cb,
// Entry 5DC0 - 5DFF
0x35e4, 0x35fd, 0x3615, 0x362e, 0x3646, 0x365f, 0x3677, 0x368f,
0x36a7, 0x36bf, 0x36d7, 0x36ef, 0x3707, 0x371f, 0x3737, 0x374f,
0x3768, 0x3781, 0x379a, 0x37b3, 0x37cc, 0x37e5, 0x37fe, 0x3817,
0x3830, 0x3848, 0x3861, 0x387a, 0x3893, 0x38ac, 0x38c5, 0x38de,
0x38f7, 0x3910, 0x3929, 0x3942, 0x395b, 0x3974, 0x398d, 0x39a6,
0x39bf, 0x39d9, 0x39f3, 0x3a0c, 0x3a25, 0x3a3e, 0x3a57, 0x3a70,
0x3a89, 0x3aa2, 0x3abb, 0x3ad4, 0x3aed, 0x3b06, 0x3b1f, 0x3b38,
0x3b51, 0x3b6a, 0x3b83, 0x3b9c, 0x3bb5, 0x3bce, 0x3be7, 0x3c00,
// Entry 5E00 - 5E3F
0x3c19, 0x3c32, 0x3c4b, 0x3c64, 0x3c7d, 0x3ca0, 0x3cc5, 0x3cec,
0x3d16, 0x3d3b, 0x3d63, 0x3d85, 0x3da6, 0x3dc5, 0x3de9, 0x3e0a,
0x3e2e, 0x3e51, 0x3e72, 0x3e9c, 0x3ec4, 0x3eeb, 0x3f09, 0x3f27,
0x3f44, 0x3f66, 0x3f88, 0x3faa, 0x3fdb, 0x400f, 0x403c, 0x406b,
0x4096, 0x40d6, 0x410b, 0x413d, 0x417d, 0x41ab, 0x41e3, 0x420e,
0x4241, 0x4277, 0x429b, 0x42b4, 0x42cd, 0x42e6, 0x42ff, 0x4318,
0x4331, 0x434a, 0x4363, 0x437c, 0x4395, 0x43af, 0x43c8, 0x43e1,
0x43fa, 0x4413, 0x442c, 0x4445, 0x445e, 0x4477, 0x4490, 0x44a9,
// Entry 5E40 - 5E7F
0x44c2, 0x44db, 0x44f4, 0x450d, 0x4526, 0x453f, 0x4559, 0x4572,
0x458b, 0x45a4, 0x45bd, 0x45d6, 0x45ef, 0x4608, 0x4621, 0x463a,
0x4653, 0x466c, 0x4685, 0x469e, 0x46b8, 0x46d1, 0x46ea, 0x4704,
0x471d, 0x4736, 0x474f, 0x4768, 0x4782, 0x479b, 0x47b5, 0x47cf,
0x47e8, 0x4801, 0x481a, 0x4833, 0x484c, 0x4865, 0x487e, 0x4897,
0x48b0, 0x48c9, 0x48e2, 0x48fb, 0x4914, 0x492d, 0x4946, 0x495f,
0x4978, 0x4991, 0x49aa, 0x49c3, 0x49dd, 0x49f7, 0x4a11, 0x4a2a,
0x4a43, 0x4a5c, 0x4a75, 0x4a8e, 0x4aa7, 0x4ac0, 0x4ad9, 0x4af2,
// Entry 5E80 - 5EBF
0x4b0b, 0x4b24, 0x4b3d, 0x4b56, 0x4b6f, 0x4b88, 0x4ba1, 0x4bba,
0x4bd3, 0x4bec, 0x4c05, 0x4c1e, 0x4c37, 0x4c50, 0x4c69, 0x4c82,
0x4c9b, 0x4cb4, 0x4ccd, 0x4ce6, 0x4cff, 0x4d18, 0x4d32, 0x4d4b,
0x4d65, 0x4d7e, 0x4d97, 0x4db1, 0x4dca, 0x4de4, 0x4dfd, 0x4e17,
0x4e30, 0x4e49, 0x4e63, 0x4e7d, 0x4e97, 0x4eb0, 0x4eca, 0x4ee4,
0x4efd, 0x4f16, 0x4f30, 0x4f4a, 0x4f64, 0x4f7d, 0x4f96, 0x4faf,
0x4fc9, 0x4fe3, 0x4ffc, 0x5015, 0x502e, 0x5047, 0x5060, 0x507a,
0x5093, 0x50ac, 0x50c5, 0x50de, 0x50f7, 0x5110, 0x5129, 0x5142,
// Entry 5EC0 - 5EFF
0x515b, 0x5174, 0x518e, 0x51a7, 0x51c0, 0x51d9, 0x51f2, 0x520b,
0x5224, 0x523d, 0x5256, 0x526f, 0x5288, 0x52a2, 0x52bb, 0x52d4,
0x52ed, 0x5306, 0x531f, 0x5338, 0x5351, 0x536a, 0x5383, 0x539c,
0x53b5, 0x53ce, 0x53e7, 0x5400, 0x5419, 0x5432, 0x544b, 0x5464,
0x547d, 0x5496, 0x54af, 0x54c8, 0x54e1, 0x54fa, 0x5513, 0x552c,
0x5545, 0x555e, 0x5577, 0x5590, 0x55a9, 0x55c2, 0x55db, 0x55f4,
0x560d, 0x5626, 0x563f, 0x5658, 0x5671, 0x568a, 0x56a3, 0x56bc,
0x56d5, 0x56ee, 0x5707, 0x5720, 0x5739, 0x5752, 0x576b, 0x5784,
// Entry 5F00 - 5F3F
0x579d, 0x57b6, 0x57cf, 0x57e8, 0x5801, 0x581a, 0x5833, 0x584c,
0x5865, 0x587e, 0x5897, 0x58b0, 0x58c9, 0x58e2, 0x58fb, 0x5914,
0x592d, 0x5947, 0x5961, 0x597a, 0x5993, 0x59ac, 0x59c5, 0x59de,
0x59f8, 0x5a11, 0x5a2a, 0x5a44, 0x5a5d, 0x5a76, 0x5a8f, 0x5aa8,
0x5ac1, 0x5ada, 0x5af4, 0x5b0d, 0x5b27, 0x5b40, 0x5b59, 0x5b72,
0x5b8b, 0x5ba4, 0x5bbd, 0x5bd6, 0x5bef, 0x5c08, 0x5c21, 0x5c3a,
0x5c54, 0x5c6d, 0x5c86, 0x5c9f, 0x5cb8, 0x5cd1, 0x5cea, 0x5d03,
0x5d1c, 0x5d35, 0x5d4e, 0x5d67, 0x5d80, 0x5d99, 0x5db2, 0x5dcb,
// Entry 5F40 - 5F7F
0x5de4, 0x5dfd, 0x5e16, 0x5e2f, 0x5e48, 0x5e61, 0x5e7a, 0x5e93,
0x5eac, 0x5ec5, 0x5ede, 0x5ef7, 0x5f10, 0x5f29, 0x5f42, 0x5f5b,
0x5f74, 0x5f8d, 0x5fa6, 0x5fbf, 0x5fd8, 0x5ff1, 0x600a, 0x6023,
0x603c, 0x6056, 0x606f, 0x6088, 0x60a1, 0x60ba, 0x60d3, 0x60ec,
0x6105, 0x611e, 0x6137, 0x6150, 0x6169, 0x6182, 0x619b, 0x61b4,
0x61cd, 0x61e6, 0x61ff, 0x6218, 0x6231, 0x624a, 0x6263, 0x627c,
0x6296, 0x62af, 0x62c8, 0x62e1, 0x62fa, 0x6313, 0x632d, 0x6346,
0x635f, 0x6378, 0x6391, 0x63aa, 0x63c4, 0x63dd, 0x63f6, 0x640f,
// Entry 5F80 - 5FBF
0x6428, 0x6441, 0x645a, 0x6473, 0x648c, 0x64a5, 0x64be, 0x64d8,
0x64f1, 0x650a, 0x6523, 0x653c, 0x6555, 0x656e, 0x6587, 0x65a0,
0x65b9, 0x65d2, 0x65eb, 0x6604, 0x661d, 0x6636, 0x664f, 0x6668,
0x6681, 0x669a, 0x66b3, 0x66cc, 0x66e6, 0x66ff, 0x6718, 0x6732,
0x674c, 0x6766, 0x677f, 0x6798, 0x67b1, 0x67ca, 0x67e4, 0x67fe,
0x6818, 0x6831, 0x684a, 0x6863, 0x687c, 0x6895, 0x68ae, 0x68c7,
0x68e0, 0x68f9, 0x6912, 0x692b, 0x6944, 0x695d, 0x6976, 0x698f,
0x69a8, 0x69c1, 0x69da, 0x69f3, 0x6a0c, 0x6a25, 0x6a3e, 0x6a57,
// Entry 5FC0 - 5FFF
0x6a71, 0x6a8a, 0x6aa3, 0x6abc, 0x6ad5, 0x6aee, 0x6b08, 0x6b21,
0x6b3a, 0x6b53, 0x6b6c, 0x6b86, 0x6b9f, 0x6bb8, 0x6bd1, 0x6beb,
0x6c04, 0x6c1d, 0x6c36, 0x6c4f, 0x6c68, 0x6c81, 0x6c9a, 0x6cb3,
0x6ccc, 0x6ce5, 0x6cff, 0x6d18, 0x6d3a, 0x6d54, 0x6d6d, 0x6d86,
0x6d9f, 0x6db9, 0x6dd2, 0x6deb, 0x6e04, 0x6e1d, 0x6e36, 0x6e4f,
0x6e6e, 0x6e87, 0x6ea0, 0x6eb9, 0x6ed2, 0x6eeb, 0x6f04, 0x6f1d,
0x6f36, 0x6f4f, 0x6f68, 0x6f81, 0x6f9a, 0x6fb3, 0x6fcc, 0x6fe5,
0x6ffe, 0x702b, 0x7057, 0x7070, 0x7089, 0x70a2, 0x70bb, 0x70d4,
// Entry 6000 - 603F
0x70ed, 0x7106, 0x711f, 0x7138, 0x7151, 0x716a, 0x7183, 0x719c,
0x71b5, 0x71ce, 0x71e7, 0x7200, 0x7219, 0x7232, 0x724b, 0x7264,
0x727d, 0x7296, 0x72af, 0x72c8, 0x72e1, 0x72fa, 0x7313, 0x732c,
0x7345, 0x735e, 0x7377, 0x7390, 0x73a9, 0x73c2, 0x73db, 0x73f4,
0x740d, 0x7426, 0x743f, 0x7459, 0x7472, 0x748b, 0x74a4, 0x74bd,
0x74d6, 0x74ef, 0x7508, 0x7522, 0x753b, 0x7554, 0x756d, 0x7586,
0x759f, 0x75b8, 0x75d1, 0x75ea, 0x7603, 0x761c, 0x7635, 0x764e,
0x7667, 0x7680, 0x7699, 0x76b2, 0x76cb, 0x76e4, 0x76fd, 0x7716,
// Entry 6040 - 607F
0x772f, 0x7748, 0x7761, 0x777a, 0x7793, 0x77ac, 0x77c5, 0x77de,
0x77f7, 0x7810, 0x7829, 0x7842, 0x785b, 0x7874, 0x788d, 0x78a6,
0x78bf, 0x78d8, 0x78f1, 0x790a, 0x7923, 0x793c, 0x7955, 0x796e,
0x7987, 0x79a0, 0x79b9, 0x79d2, 0x79eb, 0x7a04, 0x7a1d, 0x7a36,
0x7a4f, 0x7a68, 0x7a81, 0x7a9a, 0x7ab3, 0x7acc, 0x7ae5, 0x7afe,
0x7b17, 0x7b30, 0x7b49, 0x7b62, 0x7b7b, 0x7b94, 0x7bad, 0x7bc6,
0x7bdf, 0x7bf8, 0x7c17, 0x7c35, 0x7c5e, 0x7c84, 0x7ca1, 0x7cc0,
0x7cde, 0x7cfb, 0x7d1d, 0x7d48, 0x7d70, 0x7d8f, 0x7dad, 0x7dc8,
// Entry 6080 - 60BF
0x7de5, 0x7e01, 0x7e20, 0x7e3c, 0x7e58, 0x7e77, 0x7e92, 0x7eaa,
0x7ec9, 0x7ee3, 0x7eff, 0x7f1d, 0x7f39, 0x7f54, 0x7f72, 0x7f8e,
0x7faf, 0x7fcd, 0x7feb, 0x800c, 0x802a, 0x8043, 0x805e, 0x807f,
0x809b, 0x80b4, 0x80d4, 0x80f5, 0x810d, 0x812a, 0x8143, 0x815b,
0x8175, 0x818f, 0x81aa, 0x81c8, 0x81e3, 0x81fb, 0x821c, 0x8235,
0x8251, 0x826a, 0x8285, 0x829e, 0x82b6, 0x82cf, 0x82e7, 0x8305,
0x8320, 0x8339, 0x835c, 0x8380, 0x839b, 0x83b7, 0x83d3, 0x83ed,
0x8407, 0x8420, 0x843b, 0x8454, 0x846f, 0x8487, 0x84a0, 0x84bb,
// Entry 60C0 - 60FF
0x84d4, 0x84ec, 0x8504, 0x851d, 0x8535, 0x854c, 0x8564, 0x857c,
0x8595, 0x85b0, 0x85d1, 0x85ea, 0x8605, 0x8623, 0x8642, 0x865c,
0x8677, 0x8693, 0x86ab, 0x86c6, 0x86e8, 0x870b, 0x872c, 0x8749,
0x8769, 0x8781, 0x879e, 0x87bc, 0x87da, 0x87fa, 0x881b, 0x8839,
0x8854, 0x8871, 0x888d, 0x88a8, 0x88c2, 0x88db, 0x88fc, 0x891a,
0x8934, 0x8950, 0x8969, 0x8982, 0x899d, 0x89be, 0x89d9, 0x89f1,
0x8a0c, 0x8a29, 0x8a45, 0x8a61, 0x8a81, 0x8a9a, 0x8ab4, 0x8acc,
0x8ae7, 0x8b07, 0x8b24, 0x8b3c, 0x8b57, 0x8b70, 0x8b87, 0x8b9f,
// Entry 6100 - 613F
0x8bb8, 0x8bd9, 0x8bf1, 0x8c09, 0x8c26, 0x8c40, 0x8c5e, 0x8c78,
0x8c93, 0x8cb0, 0x8cca, 0x8cf0, 0x8d0d, 0x8d27, 0x8d43, 0x8d5e,
0x8d84, 0x8da3, 0x8dbc, 0x8dd7, 0x8df5, 0x8e0f, 0x8e28, 0x8e44,
0x8e5d, 0x8e76, 0x8e91, 0x8ea9, 0x8ec2, 0x8edc, 0x8ef8, 0x8f12,
0x8f2f, 0x8f49, 0x8f6a, 0x8f83, 0x8fa0, 0x8fbf, 0x8fd8, 0x8ff3,
0x900b, 0x9028, 0x9044, 0x9061, 0x907d, 0x9097, 0x90af, 0x90c9,
0x90e1, 0x90fb, 0x9114, 0x9131, 0x914c, 0x9163, 0x917d, 0x9195,
0x91b1, 0x91d0, 0x91eb, 0x9203, 0x921c, 0x9236, 0x9251, 0x9268,
// Entry 6140 - 617F
0x9280, 0x9299, 0x92b2, 0x92ca, 0x92e6, 0x92ff, 0x9318, 0x9339,
0x9352, 0x936b, 0x9388, 0x93a0, 0x93b9, 0x93d3, 0x93ee, 0x9406,
0x9421, 0x943c, 0x9458, 0x9472, 0x948b, 0x94ab, 0x94c5, 0x94df,
0x94f8, 0x9511, 0x952a, 0x9546, 0x9566, 0x957f, 0x9597, 0x95af,
0x95c7, 0x95df, 0x95f7, 0x9610, 0x9628, 0x9640, 0x9659, 0x9673,
0x968c, 0x96a6, 0x96c0, 0x96dd, 0x96f6, 0x9710, 0x972a, 0x9743,
0x975d, 0x977c, 0x9795, 0x97b0, 0x97c9, 0x97e1, 0x97f9, 0x9815,
0x982e, 0x9846, 0x9860, 0x987a, 0x9896, 0x98af, 0x98ca, 0x98e2,
// Entry 6180 - 61BF
0x98fe, 0x991e, 0x993a, 0x9951, 0x996a, 0x9985, 0x99a3, 0x99bc,
0x99d8, 0x99f3, 0x9a0c, 0x9a25, 0x9a40, 0x9a59, 0x9a74, 0x9a8c,
0x9aa4, 0x9abf, 0x9ad8, 0x9af2, 0x9b0b, 0x9b26, 0x9b3e, 0x9b58,
0x9b71, 0x9b8a, 0x9ba4, 0x9bc1, 0x9bdc, 0x9bf7, 0x9c10, 0x9c28,
0x9c43, 0x9c5c, 0x9c74, 0x9c8f, 0x9ca9, 0x9cc5, 0x9cde, 0x9cf6,
0x9d0f, 0x9d28, 0x9d42, 0x9d5b, 0x9d73, 0x9d8e, 0x9da9, 0x9dc2,
0x9ddb, 0x9df3, 0x9e0c, 0x9e25, 0x9e41, 0x9e5b, 0x9e74, 0x9e8f,
0x9ea9, 0x9ec3, 0x9ede, 0x9ef5, 0x9f11, 0x9f29, 0x9f41, 0x9f59,
// Entry 61C0 - 61FF
0x9f71, 0x9f8b, 0x9fa5, 0x9fbb, 0x9fd3, 0x9fea, 0xa003, 0xa01d,
0xa036, 0xa04d, 0xa065, 0xa07e, 0xa096, 0xa0ad, 0xa0c6, 0xa0de,
0xa0f7, 0xa10f, 0xa12c, 0xa143, 0xa15c, 0xa17b, 0xa193, 0xa1ab,
0xa1c4, 0xa1dd, 0xa1f7, 0xa20f, 0xa227, 0xa240, 0xa258, 0xa270,
0xa288, 0xa2a3, 0xa2bc, 0xa2d5, 0xa2ed, 0xa306, 0xa320, 0xa338,
0xa350, 0xa36d, 0xa386, 0xa39e, 0xa3b7, 0xa3cf, 0xa3ea, 0xa403,
0xa41c, 0xa437, 0xa450, 0xa46a, 0xa485, 0xa49f, 0xa4b8, 0xa4d0,
0xa4ec, 0xa505, 0xa51f, 0xa53c, 0xa558, 0xa570, 0xa589, 0xa5a5,
// Entry 6200 - 623F
0xa5be, 0xa5dd, 0xa5f5, 0xa60d, 0xa62f, 0xa653, 0xa66c, 0xa686,
0xa69f, 0xa6b9, 0xa6d0, 0xa6ea, 0xa704, 0xa71e, 0xa739, 0xa753,
0xa76c, 0xa785, 0xa79c, 0xa7b5, 0xa7d1, 0xa7ee, 0xa80a, 0xa824,
0xa83d, 0xa856, 0xa86f, 0xa888, 0xa8a0, 0xa8b9, 0xa8d1, 0xa8f1,
0xa909, 0xa923, 0xa93d, 0xa957, 0xa970, 0xa98b, 0xa9a3, 0xa9bd,
0xa9d7, 0xa9ef, 0xaa07, 0xaa23, 0xaa3c, 0xaa53, 0xaa6c, 0xaa85,
0xaa9e, 0xaaba, 0xaada, 0xaaf3, 0xab0c, 0xab25, 0xab3e, 0xab56,
0xab6f, 0xab8a, 0xaba3, 0xabbb, 0xabd4, 0xabee, 0xac06, 0xac1f,
// Entry 6240 - 627F
0xac38, 0xac53, 0xac6d, 0xac8b, 0xaca7, 0xacbf, 0xacd8, 0xacee,
0xad06, 0xad1c, 0xad32, 0xad4a, 0xad68, 0xad80, 0xad98, 0xadba,
0xadd3, 0xadec, 0xae06, 0xae20, 0xae41, 0xae5f, 0xae77, 0xae8f,
0xaea8, 0xaec1, 0xaee0, 0xaef8, 0xaf10, 0xaf28, 0xaf40, 0xaf57,
0xaf6e, 0xaf87, 0xaf9f, 0xafba, 0xafd2, 0xafea, 0xb003, 0xb021,
0xb038, 0xb04f, 0xb067, 0xb07e, 0xb096, 0xb0ad, 0xb0c5, 0xb0dd,
0xb0f4, 0xb10c, 0xb124, 0xb13c, 0xb155, 0xb16c, 0xb182, 0xb199,
0xb1b0, 0xb1c8, 0xb1e0, 0xb1f8, 0xb20f, 0xb227, 0xb240, 0xb25a,
// Entry 6280 - 62BF
0xb272, 0xb28b, 0xb2a5, 0xb2bb, 0xb2d3, 0xb2ec, 0xb303, 0xb31c,
0xb335, 0xb34d, 0xb366, 0xb37d, 0xb397, 0xb3af, 0xb3c7, 0xb3de,
0xb3f7, 0xb410, 0xb429, 0xb441, 0xb459, 0xb470, 0xb487, 0xb4a0,
0xb4b8, 0xb4d4, 0xb4ed, 0xb505, 0xb51e, 0xb536, 0xb54d, 0xb564,
0xb57c, 0xb593, 0xb5ac, 0xb5c4, 0xb5db, 0xb5f2, 0xb60b, 0xb623,
0xb63b, 0xb655, 0xb66e, 0xb67b, 0xb689, 0xb696, 0xb6a4, 0xb6b1,
0xb6be, 0xb6ca, 0xb6d8, 0xb6e7, 0xb6f5, 0xb703, 0xb711, 0xb721,
0xb72e, 0xb73d, 0xb74b, 0xb758, 0xb765, 0xb771, 0xb77e, 0xb78c,
// Entry 62C0 - 62FF
0xb79b, 0xb7a8, 0xb7b5, 0xb7c1, 0xb7ce, 0xb7dc, 0xb7e9, 0xb7f7,
0xb804, 0xb812, 0xb820, 0xb82d, 0xb83a, 0xb849, 0xb857, 0xb865,
0xb872, 0xb881, 0xb890, 0xb89e, 0xb8a7, 0xb8b7, 0xb8c7, 0xb8d7,
0xb8e7, 0xb8f7, 0xb907, 0xb917, 0xb927, 0xb937, 0xb947, 0xb957,
0xb967, 0xb977, 0xb987, 0xb997, 0xb9a7, 0xb9b7, 0xb9c7, 0xb9d7,
0xb9e7, 0xb9f7, 0xba07, 0xba17, 0xba27, 0xba37, 0xba48, 0xba59,
0xba6a, 0xba7b, 0xba8c, 0xba9d, 0xbaae, 0xbabf, 0xbad5, 0xbaeb,
0xbb02, 0xbb19, 0xbb2a, 0xbb3b, 0xbb4c, 0xbb5d, 0xbb6f, 0xbb81,
// Entry 6300 - 633F
0xbb93, 0xbba5, 0xbbb5, 0xbbc5, 0xbbd5, 0xbbe5, 0xbbf5, 0xbc06,
0xbc16, 0xbc27, 0xbc37, 0xbc47, 0xbc57, 0xbc67, 0xbc78, 0xbc89,
0xbc99, 0xbca9, 0xbcb9, 0xbcc9, 0xbcd9, 0xbcea, 0xbcfa, 0xbd0a,
0xbd1a, 0xbd2b, 0xbd3c, 0xbd4c, 0xbd5d, 0xbd6e, 0xbd80, 0xbd91,
0xbda1, 0xbdb1, 0xbdc2, 0xbdd3, 0xbde3, 0xbdf4, 0xbe04, 0xbe14,
0xbe26, 0xbe37, 0xbe48, 0xbe58, 0xbe6a, 0xbe7c, 0xbe8d, 0xbea2,
0xbeb5, 0xbec8, 0xbedb, 0xbeef, 0xbf03, 0xbf17, 0xbf2c, 0xbf41,
0xbf54, 0xbf69, 0xbf7c, 0xbf8f, 0xbfa3, 0xbfb6, 0xbfc9, 0xbfdd,
// Entry 6340 - 637F
0xbff0, 0xc003, 0xc016, 0xc02b, 0xc03e, 0xc054, 0xc066, 0xc078,
0xc08b, 0xc09d, 0xc0b0, 0xc0c2, 0xc0d4, 0xc0f1, 0xc10d, 0xc129,
0xc149, 0xc16a, 0xc17d, 0xc194, 0xc1ab, 0xc1c1, 0xc1d7, 0xc1ee,
0xc205, 0xc21b, 0xc231, 0xc247, 0xc25d, 0xc274, 0xc28b, 0xc2a2,
0xc2b9, 0xc2d0, 0xc2e7, 0xc2fe, 0xc315, 0xc32b, 0xc341, 0xc358,
0xc36f, 0xc385, 0xc39b, 0xc3b1, 0xc3c7, 0xc3de, 0xc3f5, 0xc40f,
0xc42b, 0xc445, 0xc45f, 0xc47a, 0xc494, 0xc4af, 0xc4ca, 0xc4e4,
0xc4ff, 0xc519, 0xc534, 0xc550, 0xc56b, 0xc587, 0xc5a3, 0xc5bd,
// Entry 6380 - 63BF
0xc5d6, 0xc5f0, 0xc60a, 0xc623, 0xc63b, 0xc654, 0xc66e, 0xc688,
0xc6a1, 0xc6bb, 0xc6d5, 0xc6f5, 0xc710, 0xc72b, 0xc745, 0xc762,
0xc77d, 0xc798, 0xc7b4, 0xc7ce, 0xc7e9, 0xc803, 0xc81b, 0xc831,
0xc84f, 0xc866, 0xc87c, 0xc892, 0xc8aa, 0xc8c1, 0xc8d8, 0xc8ee,
0xc906, 0xc91e, 0xc935, 0xc94d, 0xc969, 0xc98a, 0xc9a6, 0xc9ca,
0xc9ea, 0xca07, 0xca20, 0xca36, 0xca4b, 0xca6c, 0xca86, 0xca9c,
0xcab2, 0xcac8, 0xcade, 0xcaf2, 0xcb0f, 0xcb2b, 0xcb40, 0xcb55,
0xcb6a, 0xcb92, 0xcbb3, 0xcbcd, 0xcbec, 0xcc0a, 0xcc28, 0xcc45,
// Entry 63C0 - 63FF
0xcc60, 0xcc7a, 0xcc95, 0xccb1, 0xcccb, 0xcce6, 0xcd01, 0xcd1c,
0xcd37, 0xcd52, 0xcd6d, 0xcd87, 0xcda1, 0xcdbb, 0xcdd5, 0xcdf0,
0xce0a, 0xce24, 0xce40, 0xce5c, 0xce78, 0xce94, 0xceb3, 0xcecf,
0xceec, 0xcf08, 0xcf24, 0xcf40, 0xcf5c, 0xcf78, 0xcf94, 0xcfb0,
0xcfcc, 0xcfe8, 0xd004, 0xd020, 0xd03c, 0xd059, 0xd075, 0xd091,
0xd0ae, 0xd0cb, 0xd0e7, 0xd103, 0xd120, 0xd13c, 0xd158, 0xd174,
0xd191, 0xd1ad, 0xd1c7, 0xd1e1, 0xd1fb, 0xd215, 0xd232, 0xd24c,
0xd267, 0xd281, 0xd29b, 0xd2b5, 0xd2cf, 0xd2e9, 0xd303, 0xd31d,
// Entry 6400 - 643F
0xd337, 0xd351, 0xd36b, 0xd385, 0xd39f, 0xd3ba, 0xd3d4, 0xd3ee,
0xd409, 0xd424, 0xd43e, 0xd458, 0xd473, 0xd48d, 0xd4a7, 0xd4c1,
0xd4dc, 0xd4f6, 0xd50c, 0xd521, 0xd536, 0xd54d, 0xd563, 0xd579,
0xd58e, 0xd5a5, 0xd5bc, 0xd5d2, 0xd5e8, 0xd601, 0xd61a, 0xd635,
0xd650, 0xd66a, 0xd684, 0xd6a0, 0xd6bb, 0xd6d6, 0xd6fa, 0xd71e,
0xd744, 0xd755, 0xd76a, 0xd781, 0xd79b, 0xd7a9, 0xd7b7, 0xd7c8,
0xd7d7, 0xd7e5, 0xd7f4, 0xd80a, 0xd818, 0xd826, 0xd835, 0xd843,
0xd851, 0xd863, 0xd874, 0xd883, 0xd892, 0xd8a0, 0xd8af, 0xd8c1,
// Entry 6440 - 647F
0xd8d7, 0xd8e6, 0xd8f6, 0xd904, 0xd913, 0xd922, 0xd932, 0xd942,
0xd952, 0xd963, 0xd974, 0xd982, 0xd990, 0xd9a1, 0xd9af, 0xd9be,
0xd9cd, 0xd9dd, 0xd9f4, 0xda02, 0xda10, 0xda1f, 0xda2f, 0xda3f,
0xda4f, 0xda5e, 0xda6e, 0xda7e, 0xda8e, 0xdaa1, 0xdab4, 0xdacd,
0xdadc, 0xdaeb, 0xdafa, 0xdb0a, 0xdb19, 0xdb28, 0xdb3a, 0xdb48,
0xdb56, 0xdb65, 0xdb74, 0xdb84, 0xdb9b, 0xdbab, 0xdbbc, 0xdbca,
0xdbd8, 0xdbe7, 0xdbf6, 0xdc05, 0xdc15, 0xdc23, 0xdc32, 0xdc41,
0xdc61, 0xdc79, 0xdc8d, 0xdca7, 0xdcc4, 0xdcd5, 0xdce7, 0xdcfa,
// Entry 6480 - 64BF
0xdd0c, 0xdd1f, 0xdd30, 0xdd42, 0xdd54, 0xdd65, 0xdd76, 0xdd88,
0xdd9b, 0xddae, 0xddbf, 0xddd1, 0xdde4, 0xddf8, 0xde0a, 0xde1c,
0xde2e, 0xde40, 0xde53, 0xde64, 0xde76, 0xde89, 0xde9d, 0xdeaf,
0xdec2, 0xded5, 0xdee6, 0xdef8, 0xdf0a, 0xdf1d, 0xdf30, 0xdf4b,
0xdf5d, 0xdf77, 0xdf89, 0xdf9b, 0xdfad, 0xdfbf, 0xdfd0, 0xdfe2,
0xdff5, 0xe008, 0xe01a, 0xe02d, 0xe03f, 0xe051, 0xe063, 0xe077,
0xe089, 0xe098, 0xe0ab, 0xe0ba, 0xe0c9, 0xe0db, 0xe0ed, 0xe0ff,
0xe111, 0xe123, 0xe135, 0xe147, 0xe162, 0xe17d, 0xe198, 0xe1b3,
// Entry 64C0 - 64FF
0xe1ce, 0xe1e9, 0xe1fe, 0xe212, 0xe227, 0xe241, 0xe25b, 0xe27f,
0xe2a5, 0xe2b9, 0xe2cd, 0xe2e1, 0xe2f5, 0xe309, 0xe31d, 0xe331,
0xe345, 0xe359, 0xe36d, 0xe381, 0xe395, 0xe3a9, 0xe3bd, 0xe3d1,
0xe3e5, 0xe3f9, 0xe40d, 0xe421, 0xe435, 0xe449, 0xe45d, 0xe471,
0xe485, 0xe499, 0xe4ad, 0xe4c1, 0xe4d5, 0xe4e9, 0xe4fd, 0xe511,
0xe525, 0xe539, 0xe54d, 0xe561, 0xe575, 0xe589, 0xe59d, 0xe5b1,
0xe5c5, 0xe5d9, 0xe5ed, 0xe601, 0xe615, 0xe629, 0xe63d, 0xe651,
0xe665, 0xe679, 0xe68d, 0xe6a1, 0xe6b5, 0xe6c9, 0xe6dd, 0xe6f1,
// Entry 6500 - 653F
0xe705, 0xe719, 0xe72d, 0xe741, 0xe755, 0xe769, 0xe77d, 0xe791,
0xe7a5, 0xe7b9, 0xe7cd, 0xe7e1, 0xe7f5, 0xe809, 0xe81d, 0xe831,
0xe845, 0xe859, 0xe86d, 0xe881, 0xe895, 0xe8a9, 0xe8bd, 0xe8d1,
0xe8e5, 0xe8f9, 0xe90d, 0xe921, 0xe935, 0xe949, 0xe95d, 0xe971,
0xe985, 0xe999, 0xe9ad, 0xe9c1, 0xe9d5, 0xe9e9, 0xe9fd, 0xea11,
0xea25, 0xea39, 0xea4d, 0xea61, 0xea75, 0xea89, 0xea9d, 0xeab1,
0xeac5, 0xead9, 0xeaed, 0xeb01, 0xeb15, 0xeb29, 0xeb3d, 0xeb51,
0xeb65, 0xeb79, 0xeb8d, 0xeba1, 0xebb5, 0xebc9, 0xebdd, 0xebf1,
// Entry 6540 - 657F
0xec05, 0xec19, 0xec2d, 0xec41, 0xec55, 0xec69, 0xec7d, 0xec91,
0xeca5, 0xecb9, 0xeccd, 0xece1, 0xecf5, 0xed09, 0xed1d, 0xed31,
0xed45, 0xed59, 0xed6d, 0xed81, 0xed95, 0xeda9, 0xedbd, 0xedd1,
0xede5, 0xedf9, 0xee0d, 0xee21, 0xee35, 0xee49, 0xee5d, 0xee71,
0xee85, 0xee99, 0xeead, 0xeec1, 0xeed5, 0xeee9, 0xeefd, 0xef11,
0xef25, 0xef39, 0xef4d, 0xef61, 0xef75, 0xef89, 0xef9d, 0xefb1,
0xefc5, 0xefd9, 0xefed, 0xf001, 0xf015, 0xf029, 0xf03d, 0xf051,
0xf065, 0xf079, 0xf08d, 0xf0a1, 0xf0b5, 0xf0c9, 0xf0dd, 0xf0f1,
// Entry 6580 - 65BF
0xf105, 0xf119, 0xf12d, 0xf141, 0xf155, 0xf169, 0xf17d, 0xf191,
0xf1a5, 0xf1b9, 0xf1cd, 0xf1e1, 0xf1f5, 0xf209, 0xf21d, 0xf231,
0xf245, 0xf259, 0xf26d, 0xf281, 0xf295, 0xf2a9, 0xf2bd, 0xf2d1,
0xf2e5, 0xf2f9, 0xf30d, 0xf321, 0xf335, 0xf349, 0xf35d, 0xf371,
0xf385, 0xf399, 0xf3ad, 0xf3c1, 0xf3d5, 0xf3e9, 0xf3fd, 0xf411,
0xf425, 0xf439, 0xf44d, 0xf461, 0xf475, 0xf489, 0xf49d, 0xf4b1,
0xf4c5, 0xf4d9, 0xf4ed, 0xf501, 0xf515, 0xf529, 0xf53d, 0xf551,
0xf565, 0xf579, 0xf58d, 0xf5a1, 0xf5b5, 0xf5c9, 0xf5dd, 0xf5f1,
// Entry 65C0 - 65FF
0xf605, 0xf619, 0xf62d, 0xf641, 0xf655, 0xf669, 0xf67d, 0xf691,
0xf6a5, 0xf6b9, 0xf6cd, 0xf6e1, 0xf6f5, 0xf709, 0xf71d, 0xf731,
0xf745, 0xf759, 0xf76d, 0xf781, 0xf795, 0xf7a9, 0xf7bd, 0xf7d1,
0xf7e5, 0xf7f9, 0xf80d, 0xf821, 0xf835, 0xf849, 0xf85d, 0xf871,
0xf885, 0xf899, 0xf8ad, 0xf8c1, 0xf8d5, 0xf8e9, 0xf8fd, 0xf911,
0xf925, 0xf939, 0xf94d, 0xf961, 0xf975, 0xf989, 0xf99d, 0xf9b1,
0xf9c5, 0xf9d9, 0xf9ed, 0xfa01, 0xfa15, 0xfa29, 0xfa3d, 0xfa51,
0xfa65, 0xfa79, 0xfa8d, 0xfaa1, 0xfab5, 0xfac9, 0xfadd, 0xfaf1,
// Entry 6600 - 663F
0xfb05, 0xfb19, 0xfb2d, 0xfb41, 0xfb55, 0xfb69, 0xfb7d, 0xfb91,
0xfba5, 0xfbb9, 0xfbcd, 0xfbe1, 0xfbf5, 0xfc09, 0xfc1d, 0xfc31,
0xfc45, 0xfc59, 0xfc6d, 0xfc81, 0xfc95, 0xfca9, 0xfcbd, 0xfcd1,
0xfce5, 0xfcf9, 0xfd0d, 0xfd21, 0xfd35, 0xfd49, 0xfd5d, 0xfd71,
0xfd85, 0xfd99, 0xfdad, 0xfdc1, 0xfdd5, 0xfde9, 0xfdfd, 0xfe11,
0xfe25, 0xfe39, 0xfe4d, 0xfe61, 0xfe75, 0xfe89, 0xfe9d, 0xfeb1,
0xfec5, 0xfed9, 0xfeed, 0xff01, 0xff15, 0xff29, 0xff3d, 0xff51,
0xff65, 0xff79, 0xff8d, 0xffa1, 0xffb5, 0xffc9, 0xffdd, 0xfff1,
// Entry 6640 - 667F
0x0005, 0x0019, 0x002d, 0x0041, 0x0055, 0x0069, 0x007d, 0x0091,
0x00a5, 0x00b9, 0x00cd, 0x00e1, 0x00f5, 0x0109, 0x011d, 0x0131,
0x0145, 0x0159, 0x016d, 0x0181, 0x0195, 0x01a9, 0x01bd, 0x01d1,
0x01e5, 0x01f9, 0x020d, 0x0221, 0x0235, 0x0249, 0x025d, 0x0271,
0x0285, 0x0299, 0x02ad, 0x02c1, 0x02d5, 0x02e9, 0x02fd, 0x0311,
0x0325, 0x0339, 0x034d, 0x0361, 0x0375, 0x0389, 0x039d, 0x03b1,
0x03c5, 0x03d9, 0x03ed, 0x0401, 0x0415, 0x0429, 0x043d, 0x0451,
0x0465, 0x0479, 0x048d, 0x04a1, 0x04b5, 0x04c9, 0x04dd, 0x04f1,
// Entry 6680 - 66BF
0x0505, 0x0519, 0x052d, 0x0541, 0x0555, 0x0569, 0x057d, 0x0591,
0x05a5, 0x05b9, 0x05cd, 0x05e1, 0x05f5, 0x0609, 0x061d, 0x0631,
0x0645, 0x0659, 0x066d, 0x0681, 0x0695, 0x06a9, 0x06bd, 0x06d1,
0x06e5, 0x06f9, 0x070d, 0x0721, 0x0735, 0x0749, 0x075d, 0x0771,
0x0785, 0x0799, 0x07ad, 0x07c1, 0x07d5, 0x07e9, 0x07fd, 0x0811,
0x0825, 0x0839, 0x084d, 0x0861, 0x0875, 0x0889, 0x089d, 0x08b1,
0x08c5, 0x08d9, 0x08ed, 0x0901, 0x0915, 0x0929, 0x093d, 0x0951,
0x0965, 0x0979, 0x098d, 0x09a1, 0x09b5, 0x09c9, 0x09dd, 0x09f1,
// Entry 66C0 - 66FF
0x0a05, 0x0a19, 0x0a2d, 0x0a41, 0x0a55, 0x0a69, 0x0a7d, 0x0a91,
0x0aa5, 0x0ab9, 0x0acd, 0x0ae1, 0x0af5, 0x0b09, 0x0b1d, 0x0b31,
0x0b45, 0x0b59, 0x0b6d, 0x0b81, 0x0b95, 0x0ba9, 0x0bbd, 0x0bd1,
0x0be5, 0x0bf9, 0x0c0d, 0x0c21, 0x0c35, 0x0c49, 0x0c5d, 0x0c71,
0x0c85, 0x0c99, 0x0cad, 0x0cc1, 0x0cd5, 0x0ce9, 0x0cfd, 0x0d11,
0x0d25, 0x0d39, 0x0d4d, 0x0d61, 0x0d75, 0x0d89, 0x0d9d, 0x0db1,
0x0dc5, 0x0dd9, 0x0ded, 0x0e01, 0x0e15, 0x0e29, 0x0e3d, 0x0e51,
0x0e65, 0x0e79, 0x0e8d, 0x0ea1, 0x0eb5, 0x0ec9, 0x0edd, 0x0ef1,
// Entry 6700 - 673F
0x0f05, 0x0f19, 0x0f2d, 0x0f41, 0x0f55, 0x0f69, 0x0f7d, 0x0f91,
0x0fa5, 0x0fb9, 0x0fcd, 0x0fe1, 0x0ff5, 0x1009, 0x101d, 0x1031,
0x1045, 0x1059, 0x106d, 0x1081, 0x1095, 0x10a9, 0x10bd, 0x10d1,
0x10e5, 0x10f9, 0x110d, 0x1121, 0x1135, 0x1149, 0x115d, 0x1171,
0x1185, 0x1199, 0x11ad, 0x11c1, 0x11d5, 0x11e9, 0x11fd, 0x1211,
0x1225, 0x1239, 0x124d, 0x1261, 0x1275, 0x1289, 0x129d, 0x12b1,
0x12c5, 0x12d9, 0x12ed, 0x1301, 0x1315, 0x1329, 0x133d, 0x1351,
0x1365, 0x1379, 0x138d, 0x13a1, 0x13b5, 0x13c9, 0x13dd, 0x13f1,
// Entry 6740 - 677F
0x1405, 0x1419, 0x142d, 0x1441, 0x1455, 0x1469, 0x147d, 0x1491,
0x14a5, 0x14b9, 0x14cd, 0x14e1, 0x14f5, 0x1509, 0x151d, 0x1531,
0x1545, 0x1559, 0x156d, 0x1581, 0x1595, 0x15a9, 0x15bd, 0x15d1,
0x15e5, 0x15f9, 0x160d, 0x1621, 0x1635, 0x1649, 0x165d, 0x1671,
0x1685, 0x1699, 0x16ad, 0x16c1, 0x16d5, 0x16e9, 0x16fd, 0x1711,
0x1725, 0x1739, 0x174d, 0x1761, 0x1775, 0x1789, 0x179d, 0x17b1,
0x17c5, 0x17d9, 0x17ed, 0x1801, 0x1815, 0x1829, 0x183d, 0x1851,
0x1865, 0x1879, 0x188d, 0x18a1, 0x18b5, 0x18c9, 0x18dd, 0x18f1,
// Entry 6780 - 67BF
0x1905, 0x1919, 0x192d, 0x1941, 0x1955, 0x1969, 0x197d, 0x1991,
0x19a5, 0x19b9, 0x19cd, 0x19e1, 0x19f5, 0x1a09, 0x1a1d, 0x1a31,
0x1a45, 0x1a59, 0x1a6d, 0x1a81, 0x1a95, 0x1aa9, 0x1abd, 0x1ad1,
0x1ae5, 0x1af9, 0x1b0d, 0x1b21, 0x1b35, 0x1b49, 0x1b5d, 0x1b71,
0x1b85, 0x1b99, 0x1bad, 0x1bc1, 0x1bd5, 0x1be9, 0x1bfd, 0x1c11,
0x1c25, 0x1c39, 0x1c4d, 0x1c61, 0x1c75, 0x1c89, 0x1c9d, 0x1cb1,
0x1cc5, 0x1cd9, 0x1ced, 0x1d01, 0x1d15, 0x1d29, 0x1d3d, 0x1d51,
0x1d65, 0x1d79, 0x1d8d, 0x1da1, 0x1db5, 0x1dc9, 0x1ddd, 0x1df1,
// Entry 67C0 - 67FF
0x1e05, 0x1e19, 0x1e2d, 0x1e41, 0x1e55, 0x1e69, 0x1e7d, 0x1e91,
0x1ea5, 0x1ec8, 0x1eeb, 0x1f0e, 0x1f31, 0x1f54, 0x1f77, 0x1f9a,
0x1fbd, 0x1fe0, 0x2003, 0x2026, 0x2049, 0x206c, 0x208f, 0x20b2,
0x20d5, 0x20f8, 0x211b, 0x213e, 0x2161, 0x2184, 0x21a7, 0x21ca,
0x21ed, 0x2210, 0x2233, 0x2256, 0x2279, 0x229c, 0x22bf, 0x22e2,
0x2305, 0x2328, 0x234b, 0x236e, 0x2391, 0x23b4, 0x23d7, 0x23fa,
0x241d, 0x2440, 0x2463, 0x2486, 0x24a9, 0x24cc, 0x24ef, 0x2512,
0x2535, 0x2558, 0x257b, 0x259e, 0x25c1, 0x25e4, 0x2607, 0x262a,
// Entry 6800 - 683F
0x264d, 0x2670, 0x2693, 0x26b6, 0x26d9, 0x26fc, 0x271f, 0x2742,
0x2765, 0x2788, 0x27ab, 0x27ce, 0x27f1, 0x2814, 0x2837, 0x285a,
0x287d, 0x28a0, 0x28c3, 0x28e6, 0x2909, 0x292c, 0x294f, 0x2972,
0x2995, 0x29b8, 0x29db, 0x29fe, 0x2a21, 0x2a44, 0x2a67, 0x2a8a,
0x2aad, 0x2ad0, 0x2af3, 0x2b16, 0x2b39, 0x2b5c, 0x2b7f, 0x2ba2,
0x2bc5, 0x2be8, 0x2c0b, 0x2c2e, 0x2c51, 0x2c74, 0x2c97, 0x2cba,
0x2cdd, 0x2d00, 0x2d23, 0x2d46, 0x2d69, 0x2d8c, 0x2daf, 0x2dd2,
0x2df5, 0x2e18, 0x2e3b, 0x2e5e, 0x2e81, 0x2ea4, 0x2ec7, 0x2eea,
// Entry 6840 - 687F
0x2f0d, 0x2f30, 0x2f53, 0x2f76, 0x2f99, 0x2fbc, 0x2fdf, 0x3002,
0x3025, 0x3048, 0x306b, 0x308e, 0x30b1, 0x30d4, 0x30f7, 0x311a,
0x313d, 0x3160, 0x3183, 0x31a6, 0x31c9, 0x31ec, 0x320f, 0x3232,
0x3255, 0x3278, 0x329b, 0x32be, 0x32e1, 0x3304, 0x3327, 0x334a,
0x336d, 0x3390, 0x33b3, 0x33d6, 0x33f9, 0x341c, 0x343f, 0x3462,
0x3485, 0x34a8, 0x34cb, 0x34ee, 0x3511, 0x3534, 0x3557, 0x357a,
0x359d, 0x35c0, 0x35e3, 0x3606, 0x3629, 0x364c, 0x366f, 0x3692,
0x36b5, 0x36d8, 0x36fb, 0x371e, 0x3741, 0x3764, 0x3787, 0x37aa,
// Entry 6880 - 68BF
0x37cd, 0x37f0, 0x3813, 0x3836, 0x3859, 0x387c, 0x389f, 0x38c2,
0x38e5, 0x3908, 0x392b, 0x394e, 0x3971, 0x3994, 0x39b7, 0x39da,
0x39fd, 0x3a20, 0x3a43, 0x3a66, 0x3a89, 0x3aac, 0x3acf, 0x3af2,
0x3b15, 0x3b38, 0x3b5b, 0x3b7e, 0x3ba1, 0x3bc4, 0x3be7, 0x3c0a,
0x3c2d, 0x3c50, 0x3c73, 0x3c96, 0x3cb9, 0x3cdc, 0x3cff, 0x3d22,
0x3d45, 0x3d68, 0x3d8b, 0x3dae, 0x3dd1, 0x3df4, 0x3e17, 0x3e3a,
0x3e5d, 0x3e80, 0x3ea3, 0x3ec6, 0x3ee9, 0x3f0c, 0x3f2f, 0x3f52,
0x3f75, 0x3f98, 0x3fbb, 0x3fde, 0x4001, 0x4024, 0x4047, 0x406a,
// Entry 68C0 - 68FF
0x408d, 0x40b0, 0x40d3, 0x40f6, 0x4119, 0x413c, 0x415f, 0x4182,
0x41a5, 0x41c8, 0x41eb, 0x420e, 0x4231, 0x4254, 0x4277, 0x429a,
0x42bd, 0x42e0, 0x4303, 0x4326, 0x4349, 0x436c, 0x438f, 0x43b2,
0x43d5, 0x43f8, 0x441b, 0x443e, 0x4461, 0x4484, 0x44a7, 0x44ca,
0x44ed, 0x4510, 0x4533, 0x4556, 0x4579, 0x459c, 0x45bf, 0x45e2,
0x4605, 0x4628, 0x464b, 0x466e, 0x4691, 0x46b4, 0x46d7, 0x46fa,
0x471d, 0x4740, 0x4763, 0x4786, 0x47a9, 0x47cc, 0x47ef, 0x4812,
0x4835, 0x4858, 0x487b, 0x489e, 0x48c1, 0x48e4, 0x4907, 0x492a,
// Entry 6900 - 693F
0x494d, 0x4970, 0x4993, 0x49b6, 0x49d9, 0x49fc, 0x4a1f, 0x4a42,
0x4a65, 0x4a88, 0x4aab, 0x4ace, 0x4af1, 0x4b14, 0x4b37, 0x4b5a,
0x4b7d, 0x4ba0, 0x4bc3, 0x4be6, 0x4c09, 0x4c2c, 0x4c4f, 0x4c72,
0x4c95, 0x4cb8, 0x4cdb, 0x4cfe, 0x4d21, 0x4d44, 0x4d67, 0x4d8a,
0x4dad, 0x4dd0, 0x4df3, 0x4e16, 0x4e39, 0x4e5c, 0x4e7f, 0x4ea2,
0x4ec5, 0x4ee8, 0x4f0b, 0x4f2e, 0x4f51, 0x4f74, 0x4f97, 0x4fba,
0x4fdd, 0x5000, 0x5023, 0x5046, 0x5069, 0x508c, 0x50af, 0x50d2,
0x50f5, 0x5118, 0x513b, 0x515e, 0x5181, 0x51a4, 0x51c7, 0x51ea,
// Entry 6940 - 697F
0x520d, 0x5230, 0x5253, 0x5276, 0x5299, 0x52bc, 0x52df, 0x5302,
0x5325, 0x5348, 0x536b, 0x538e, 0x53b1, 0x53d4, 0x53f7, 0x541a,
0x543d, 0x5460, 0x5483, 0x54a6, 0x54c9, 0x54ec, 0x550f, 0x5532,
0x5555, 0x5578, 0x559b, 0x55be, 0x55e1, 0x5604, 0x5627, 0x564a,
0x566d, 0x5690, 0x56b3, 0x56d6, 0x56f9, 0x571c, 0x573f, 0x5762,
0x5785, 0x57a8, 0x57cb, 0x57ee, 0x5811, 0x5834, 0x5857, 0x587a,
0x589d, 0x58c0, 0x58e3, 0x5906, 0x5929, 0x594c, 0x596f, 0x5992,
0x59b5, 0x59d8, 0x59fb, 0x5a1e, 0x5a41, 0x5a64, 0x5a87, 0x5aaa,
// Entry 6980 - 69BF
0x5acd, 0x5af0, 0x5b13, 0x5b36, 0x5b59, 0x5b7c, 0x5b9f, 0x5bc2,
0x5be5, 0x5c08, 0x5c2b, 0x5c4e, 0x5c71, 0x5c94, 0x5cb7, 0x5cda,
0x5cfd, 0x5d20, 0x5d43, 0x5d66, 0x5d89, 0x5dac, 0x5dcf, 0x5df2,
0x5e15, 0x5e38, 0x5e5b, 0x5e7e, 0x5ea1, 0x5ec4, 0x5ee7, 0x5f04,
0x5f21, 0x5f3e, 0x5f5b, 0x5f78, 0x5f95, 0x5fbc, 0x5fe3, 0x600a,
0x6031, 0x6058, 0x607f, 0x60a6, 0x60bf, 0x60d9, 0x60ee, 0x6103,
0x6118, 0x612e, 0x6143, 0x6158, 0x616d, 0x6182, 0x6197, 0x61ac,
0x61c1, 0x61d6, 0x61eb, 0x6200, 0x6215, 0x622a, 0x623f, 0x6254,
// Entry 69C0 - 69FF
0x6269, 0x627e, 0x6293, 0x62a9, 0x62bf, 0x62d5, 0x62eb, 0x6301,
0x6317, 0x632d, 0x6343, 0x6359, 0x6370, 0x6387, 0x639e, 0x63b4,
0x63ca, 0x63e0, 0x63f6, 0x640c, 0x6422, 0x6438, 0x644e, 0x6464,
0x647a, 0x6490, 0x64a6, 0x64bc, 0x64d2, 0x64e8, 0x64fe, 0x6514,
0x652a, 0x6540, 0x6556, 0x656c, 0x6582, 0x6598, 0x65ae, 0x65c5,
0x65db, 0x65f1, 0x6607, 0x661d, 0x6633, 0x6649, 0x665f, 0x6675,
0x668b, 0x66a1, 0x66b7, 0x66cd, 0x66e3, 0x66f9, 0x670f, 0x6725,
0x673b, 0x6751, 0x6767, 0x677d, 0x6793, 0x67a9, 0x67bf, 0x67d5,
// Entry 6A00 - 6A3F
0x67eb, 0x6801, 0x6817, 0x682d, 0x6843, 0x6859, 0x686f, 0x6885,
0x689b, 0x68b1, 0x68c7, 0x68dd, 0x68f3, 0x6909, 0x691f, 0x6935,
0x694b, 0x6961, 0x6977, 0x698d, 0x69a3, 0x69b9, 0x69cf, 0x69e5,
0x69fb, 0x6a12, 0x6a28, 0x6a3e, 0x6a54, 0x6a6a, 0x6a80, 0x6a96,
0x6aac, 0x6ac2, 0x6ad8, 0x6aee, 0x6b04, 0x6b1a, 0x6b30, 0x6b46,
0x6b5c, 0x6b73, 0x6b89, 0x6b9f, 0x6bb5, 0x6bcb, 0x6be1, 0x6bf7,
0x6c0d, 0x6c23, 0x6c39, 0x6c4f, 0x6c65, 0x6c7b, 0x6c91, 0x6ca7,
0x6cbd, 0x6cd3, 0x6cea, 0x6d00, 0x6d16, 0x6d2c, 0x6d42, 0x6d58,
// Entry 6A40 - 6A7F
0x6d6e, 0x6d84, 0x6d9a, 0x6db0, 0x6dc7, 0x6ddd, 0x6df3, 0x6e09,
0x6e1f, 0x6e35, 0x6e4b, 0x6e61, 0x6e77, 0x6e8d, 0x6ea3, 0x6eb9,
0x6ecf, 0x6ee5, 0x6efb, 0x6f12, 0x6f29, 0x6f3f, 0x6f55, 0x6f6b,
0x6f81, 0x6f97, 0x6fad, 0x6fc3, 0x6fd9, 0x6fef, 0x7005, 0x701b,
0x7031, 0x7047, 0x705d, 0x7073, 0x7089, 0x709f, 0x70b5, 0x70cb,
0x70e1, 0x70f7, 0x710d, 0x7123, 0x7139, 0x714f, 0x7165, 0x717b,
0x7191, 0x71a7, 0x71bd, 0x71d3, 0x71e9, 0x71ff, 0x7215, 0x722b,
0x7241, 0x7257, 0x726d, 0x7283, 0x7299, 0x72af, 0x72c5, 0x72db,
// Entry 6A80 - 6ABF
0x72f1, 0x7307, 0x731e, 0x7334, 0x734a, 0x7360, 0x7376, 0x738c,
0x73a2, 0x73b8, 0x73ce, 0x73e4, 0x73fa, 0x7410, 0x7427, 0x743d,
0x7453, 0x7469, 0x747f, 0x7495, 0x74ab, 0x74c1, 0x74d7, 0x74ed,
0x7503, 0x7519, 0x752f, 0x7545, 0x755b, 0x7571, 0x7587, 0x759d,
0x75b3, 0x75c9, 0x75df, 0x75f5, 0x760b, 0x7621, 0x7637, 0x764d,
0x7663, 0x7679, 0x768f, 0x76a5, 0x76bb, 0x76d1, 0x76e7, 0x76fd,
0x7713, 0x7729, 0x773f, 0x7755, 0x776b, 0x7781, 0x7797, 0x77ad,
0x77c3, 0x77d9, 0x77ef, 0x7805, 0x781b, 0x7831, 0x7847, 0x785d,
// Entry 6AC0 - 6AFF
0x7873, 0x7889, 0x789f, 0x78b5, 0x78cb, 0x78e1, 0x78f7, 0x790d,
0x7923, 0x793e, 0x7959, 0x7973, 0x798d, 0x79a7, 0x79c1, 0x79d9,
0x79f1, 0x7a09, 0x7a21, 0x7a39, 0x7a51, 0x7a69, 0x7a81, 0x7a98,
0x7aad, 0x7ac2, 0x7ad7, 0x7aec, 0x7b01, 0x7b16, 0x7b2b, 0x7b40,
0x7b55, 0x7b6a, 0x7b7f, 0x7b94, 0x7ba9, 0x7bbe, 0x7bd3, 0x7be8,
0x7bfd, 0x7c12, 0x7c27, 0x7c3c, 0x7c51, 0x7c66, 0x7c7b, 0x7c90,
0x7ca5, 0x7cba, 0x7ccf, 0x7ce4, 0x7cf9, 0x7d0e, 0x7d23, 0x7d38,
0x7d4d, 0x7d62, 0x7d77, 0x7d8c, 0x7da1, 0x7db6, 0x7dcb, 0x7de0,
// Entry 6B00 - 6B3F
0x7df5, 0x7e0a, 0x7e1f, 0x7e34, 0x7e49, 0x7e5e, 0x7e73, 0x7e88,
0x7e9d, 0x7eb2, 0x7ec7, 0x7edc, 0x7ef1, 0x7f06, 0x7f1b, 0x7f30,
0x7f45, 0x7f5a, 0x7f6f, 0x7f84, 0x7f99, 0x7fae, 0x7fc3, 0x7fd8,
0x7fed, 0x8002, 0x8017, 0x802c, 0x8041, 0x8056, 0x806b, 0x8080,
0x8095, 0x80aa, 0x80bf, 0x80d4, 0x80e9, 0x80fe, 0x8113, 0x8128,
0x813d, 0x8152, 0x8167, 0x817c, 0x8191, 0x81a6, 0x81bb, 0x81d0,
0x81e5, 0x81fa, 0x820f, 0x8224, 0x8239, 0x824e, 0x8263, 0x8278,
0x828d, 0x82a2, 0x82b7, 0x82cc, 0x82e1, 0x82f6, 0x830b, 0x8320,
// Entry 6B40 - 6B7F
0x8335, 0x834a, 0x835f, 0x8374, 0x8389, 0x839e, 0x83b3, 0x83c8,
0x83dd, 0x83f2, 0x8407, 0x841c, 0x8431, 0x8446, 0x845b, 0x8470,
0x8485, 0x849a, 0x84af, 0x84c4, 0x84d9, 0x84ee, 0x8503, 0x8518,
0x852d, 0x8542, 0x8557, 0x856c, 0x8581, 0x8596, 0x85ab, 0x85c0,
0x85d5, 0x85ea, 0x85ff, 0x8614, 0x8629, 0x863e, 0x8653, 0x8668,
0x867d, 0x8692, 0x86a7, 0x86bc, 0x86d1, 0x86e6, 0x86fb, 0x8710,
0x8725, 0x873a, 0x874f, 0x8764, 0x8779, 0x878e, 0x87a3, 0x87b8,
0x87cd, 0x87e2, 0x87f7, 0x880c, 0x8821, 0x8836, 0x884b, 0x8860,
// Entry 6B80 - 6BBF
0x8875, 0x888a, 0x889f, 0x88b4, 0x88c9, 0x88de, 0x88f3, 0x8908,
0x891d, 0x8932, 0x8947, 0x895c, 0x8971, 0x8986, 0x899b, 0x89b0,
0x89c5, 0x89da, 0x89ef, 0x8a04, 0x8a19, 0x8a2e, 0x8a43, 0x8a58,
0x8a6d, 0x8a82, 0x8a97, 0x8aac, 0x8ac1, 0x8ad6, 0x8aeb, 0x8b00,
0x8b15, 0x8b2a, 0x8b3f, 0x8b54, 0x8b69, 0x8b7e, 0x8b93, 0x8ba8,
0x8bbd, 0x8bd2, 0x8be7, 0x8bfc, 0x8c11, 0x8c26, 0x8c3b, 0x8c50,
0x8c65, 0x8c7a, 0x8c8f, 0x8ca4, 0x8cb9, 0x8cce, 0x8ce3, 0x8cf8,
0x8d0d, 0x8d22, 0x8d37, 0x8d4c, 0x8d61, 0x8d76, 0x8d8b, 0x8da0,
// Entry 6BC0 - 6BFF
0x8db5, 0x8dca, 0x8ddf, 0x8df4, 0x8e09, 0x8e1e, 0x8e33, 0x8e48,
0x8e5d, 0x8e72, 0x8e87, 0x8e9c, 0x8eb1, 0x8ec6, 0x8edb, 0x8ef0,
0x8f05, 0x8f1a, 0x8f2f, 0x8f44, 0x8f59, 0x8f6e, 0x8f83, 0x8f98,
0x8fad, 0x8fc2, 0x8fd7, 0x8fec, 0x9001, 0x9016, 0x902b, 0x9040,
0x9055, 0x906a, 0x907f, 0x9094, 0x90a9, 0x90be, 0x90d3, 0x90e8,
0x90fd, 0x9112, 0x9127, 0x913c, 0x9151, 0x9166, 0x917b, 0x9190,
0x91a5, 0x91ba, 0x91cf, 0x91e4, 0x91f9, 0x920e, 0x9223, 0x9238,
0x924d, 0x9262, 0x9277, 0x928c, 0x92a1, 0x92b6, 0x92cb, 0x92e0,
// Entry 6C00 - 6C3F
0x92f5, 0x930a, 0x931f, 0x9334, 0x9349, 0x935e, 0x9373, 0x9388,
0x939d, 0x93b2, 0x93c7, 0x93dc, 0x93f1, 0x9406, 0x941b, 0x9430,
0x9445, 0x945a, 0x946f, 0x9484, 0x9499, 0x94ae, 0x94c3, 0x94d8,
0x94ed, 0x9502, 0x9517, 0x952c, 0x9541, 0x9556, 0x956b, 0x9580,
0x9595, 0x95aa, 0x95bf, 0x95d4, 0x95e9, 0x95fe, 0x9613, 0x9628,
0x963d, 0x9652, 0x9667, 0x967c, 0x9691, 0x96a6, 0x96bb, 0x96d0,
0x96e5, 0x96fa, 0x970f, 0x9724, 0x9739, 0x974e, 0x9763, 0x9778,
0x978d, 0x97a2, 0x97b7, 0x97cc, 0x97e1, 0x97f6, 0x980b, 0x9820,
// Entry 6C40 - 6C7F
0x9835, 0x984a, 0x985f, 0x9874, 0x9889, 0x989e, 0x98b3, 0x98c8,
0x98dd, 0x98f2, 0x9907, 0x991c, 0x9931, 0x9946, 0x995b, 0x9970,
0x9985, 0x999a, 0x99af, 0x99c4, 0x99d9, 0x99ee, 0x9a03, 0x9a18,
0x9a2d, 0x9a42, 0x9a57, 0x9a6c, 0x9a81, 0x9a96, 0x9aab, 0x9ac0,
0x9ad5, 0x9aea, 0x9aff, 0x9b14, 0x9b25, 0x9b36, 0x9b47, 0x9b58,
0x9b69, 0x9b7a, 0x9b8b, 0x9b9c, 0x9bad, 0x9bbe, 0x9bcf, 0x9be0,
0x9bf3, 0x9c06, 0x9c19, 0x9c2c, 0x9c3f, 0x9c51, 0x9c69, 0x9c7b,
0x9c8d, 0x9ca4, 0x9cb6, 0x9cc8, 0x9cda, 0x9ceb, 0x9cfc, 0x9d0d,
// Entry 6C80 - 6CBF
0x9d1e, 0x9d31, 0x9d44, 0x9d57, 0x9d6a, 0x9d84, 0x9d9e, 0x9db8,
0x9de4, 0x9dfe, 0x9e1e, 0x9e31, 0x9e44, 0x9e57, 0x9e6a, 0x9e7f,
0x9e94, 0x9ea9, 0x9ebe, 0x9eda, 0x9eed, 0x9f02, 0x9f15, 0x9f2a,
0x9f3d, 0x9f52, 0x9f65, 0x9f7a, 0x9f8b, 0x9f9d, 0x9fb0, 0x9fc3,
0x9fd6, 0x9feb, 0xa000, 0xa013, 0xa028, 0xa039, 0xa051, 0xa063,
0xa074, 0xa087, 0xa098, 0xa0a9, 0xa0bb, 0xa0d2, 0xa0e4, 0xa0f6,
0xa10e, 0xa128, 0xa140, 0xa156, 0xa168, 0xa179, 0xa18b, 0xa19d,
0xa1b0, 0xa1c6, 0xa1e0, 0xa1f2, 0xa209, 0xa21c, 0xa22e, 0xa240,
// Entry 6CC0 - 6CFF
0xa252, 0xa264, 0xa276, 0xa289, 0xa29c, 0xa2b3, 0xa2ca, 0xa2e1,
0xa2f8, 0xa311, 0xa32a, 0xa342, 0xa35a, 0xa372, 0xa38b, 0xa3b0,
0xa3d4, 0xa3fa, 0xa41c, 0xa43e, 0xa461, 0xa47f, 0xa4ab, 0xa4ca,
0xa4e6, 0xa504, 0xa522, 0xa546, 0xa55f, 0xa57e, 0xa597, 0xa5b5,
0xa5cc, 0xa5e6, 0xa5fe, 0xa616, 0xa632, 0xa64a, 0xa668, 0xa680,
0xa69d, 0xa6b3, 0xa6cc, 0xa6e3, 0xa6fa, 0xa715, 0xa72d, 0xa747,
0xa765, 0xa779, 0xa79f, 0xa7be, 0xa7e1, 0xa7fb, 0xa813, 0xa84a,
0xa879, 0xa89e, 0xa8cb, 0xa8f0, 0xa916, 0xa942, 0xa969, 0xa98f,
// Entry 6D00 - 6D3F
0xa9c6, 0xa9f8, 0xaa29, 0xaa61, 0xaa91, 0xaab7, 0xaae5, 0xab0b,
0xab32, 0xab5f, 0xab87, 0xabae, 0xabe6, 0xac19, 0xac4b, 0xac72,
0xaca0, 0xaccc, 0xacf5, 0xad1c, 0xad44, 0xad70, 0xad96, 0xadb2,
0xadcc, 0xade9, 0xae08, 0xae27, 0xae45, 0xae66, 0xae83, 0xaea2,
0xaec0, 0xaedd, 0xaefa, 0xaf19, 0xaf3e, 0xaf69, 0xaf93, 0xafc0,
0xafe1, 0xb00e, 0xb02e, 0xb050, 0xb087, 0xb0a6, 0xb0cd, 0xb0ed,
0xb114, 0xb132, 0xb154, 0xb17e, 0xb1a1, 0xb1be, 0xb1ec, 0xb20d,
0xb22e, 0xb256, 0xb275, 0xb292, 0xb2a6, 0xb2c0, 0xb2d7, 0xb2f2,
// Entry 6D40 - 6D7F
0xb307, 0xb31e, 0xb335, 0xb355, 0xb36d, 0xb394, 0xb3c0, 0xb3d9,
0xb3ed, 0xb405, 0xb423, 0xb441, 0xb461, 0xb480, 0xb4a2, 0xb4c2,
0xb4e3, 0xb503, 0xb526, 0xb552, 0xb57f, 0xb5ab, 0xb5da, 0xb5f9,
0xb61b, 0xb632, 0xb648, 0xb65e, 0xb677, 0xb699, 0xb6ba, 0xb6de,
0xb6fe, 0xb71f, 0xb74c, 0xb77a, 0xb7a6, 0xb7d4, 0xb802, 0xb836,
0xb867, 0xb87f, 0xb8a2, 0xb8c3, 0xb8e5, 0xb8f9, 0xb90b, 0xb91e,
0xb933, 0xb949, 0xb95e, 0xb97e, 0xb99d, 0xb9c7, 0xb9f1, 0xba10,
0xba3a, 0xba57, 0xba7f, 0xbaad, 0xbac6, 0xbaea, 0xbb08, 0xbb2c,
// Entry 6D80 - 6DBF
0xbb4c, 0xbb6f, 0xbb8e, 0xbbb2, 0xbbd8, 0xbc03, 0xbc28, 0xbc4a,
0xbc74, 0xbc9d, 0xbccb, 0xbd00, 0xbd34, 0xbd6e, 0xbd8c, 0xbdb0,
0xbdea, 0xbe0f, 0xbe3e, 0xbe53, 0xbe70, 0xbe90, 0xbeb4, 0xbedd,
0xbf01, 0xbf26, 0xbf4b, 0xbf5f, 0xbf7c, 0xbf9c, 0xbfc4, 0xbfed,
0xc01c, 0xc03c, 0xc066, 0xc0a5, 0xc0ea, 0xc113, 0xc142, 0xc187,
0xc1b7, 0xc1f1, 0xc219, 0xc22f, 0xc244, 0xc257, 0xc26b, 0xc27e,
0xc29c, 0xc2bb, 0xc2df, 0xc309, 0xc32d, 0xc358, 0xc37d, 0xc39e,
0xc3c0, 0xc3e4, 0xc406, 0xc42e, 0xc44f, 0xc479, 0xc4a1, 0xc4c0,
// Entry 6DC0 - 6DFF
0xc4e2, 0xc505, 0xc52e, 0xc54e, 0xc56c, 0xc594, 0xc5bc, 0xc5db,
0xc5fc, 0xc61a, 0xc640, 0xc669, 0xc694, 0xc6b5, 0xc6d6, 0xc6ff,
0xc727, 0xc750, 0xc77a, 0xc79b, 0xc7ba, 0xc7d8, 0xc800, 0xc820,
0xc845, 0xc864, 0xc88d, 0xc8ba, 0xc8e5, 0xc903, 0xc921, 0xc93d,
0xc95a, 0xc97a, 0xc99c, 0xc9c2, 0xc9ea, 0xca0c, 0xca36, 0xca5e,
0xca7f, 0xcaa1, 0xcac2, 0xcaec, 0xcb0c, 0xcb39, 0xcb66, 0xcb86,
0xcba3, 0xcbc3, 0xcbe9, 0xcc0f, 0xcc34, 0xcc59, 0xcc7a, 0xcc9d,
0xccbf, 0xccdf, 0xcd00, 0xcd28, 0xcd50, 0xcd75, 0xcd9f, 0xcdc7,
// Entry 6E00 - 6E3F
0xcde6, 0xce0d, 0xce3e, 0xce5e, 0xce86, 0xcea6, 0xcec6, 0xceea,
0xcf0d, 0xcf30, 0xcf56, 0xcf75, 0xcf98, 0xcfb8, 0xcfe0, 0xd008,
0xd033, 0xd053, 0xd07b, 0xd0a0, 0xd0c3, 0xd0e7, 0xd105, 0xd12a,
0xd14b, 0xd16e, 0xd193, 0xd1bc, 0xd1e4, 0xd20b, 0xd236, 0xd262,
0xd289, 0xd2b1, 0xd2d8, 0xd2fe, 0xd32b, 0xd351, 0xd379, 0xd3a1,
0xd3c6, 0xd3ef, 0xd411, 0xd433, 0xd455, 0xd476, 0xd496, 0xd4b9,
0xd4e0, 0xd509, 0xd52e, 0xd552, 0xd577, 0xd594, 0xd5b2, 0xd5d1,
0xd5f2, 0xd612, 0xd63e, 0xd669, 0xd696, 0xd6c6, 0xd6f5, 0xd71c,
// Entry 6E40 - 6E7F
0xd752, 0xd785, 0xd7a6, 0xd7e3, 0xd81f, 0xd854, 0xd876, 0xd894,
0xd8b7, 0xd8d7, 0xd8ff, 0xd926, 0xd949, 0xd96e, 0xd991, 0xd9b5,
0xd9dd, 0xda06, 0xda34, 0xda67, 0xda97, 0xdacc, 0xdafa, 0xdb25,
0xdb55, 0xdb8d, 0xdbbc, 0xdbeb, 0xdc1b, 0xdc4f, 0xdc7d, 0xdcaa,
0xdcd5, 0xdd02, 0xdd34, 0xdd6c, 0xdd98, 0xddc5, 0xddf4, 0xde15,
0xde38, 0xde6f, 0xde9b, 0xdec9, 0xdef3, 0xdf1f, 0xdf52, 0xdf7e,
0xdfaa, 0xdfdb, 0xe00b, 0xe042, 0xe07b, 0xe0af, 0xe0e4, 0xe10a,
0xe12e, 0xe153, 0xe178, 0xe1ae, 0xe1e2, 0xe20d, 0xe238, 0xe265,
// Entry 6E80 - 6EBF
0xe296, 0xe2d2, 0xe307, 0xe33f, 0xe370, 0xe3ac, 0xe3e1, 0xe419,
0xe43f, 0xe465, 0xe491, 0xe4be, 0xe4e5, 0xe50e, 0xe537, 0xe568,
0xe59a, 0xe5ce, 0xe5f6, 0xe626, 0xe657, 0xe68a, 0xe6ae, 0xe6d3,
0xe6f2, 0xe715, 0xe739, 0xe75c, 0xe77f, 0xe7a2, 0xe7c5, 0xe7e8,
0xe813, 0xe83c, 0xe867, 0xe890, 0xe8b4, 0xe8dc, 0xe8f9, 0xe916,
0xe932, 0xe956, 0xe973, 0xe98f, 0xe9ae, 0xe9ce, 0xe9e8, 0xea00,
0xea16, 0xea2a, 0xea3d, 0xea5d, 0xea7d, 0xea9d, 0xeab3, 0xeacf,
0xeae9, 0xeaff, 0xeb13, 0xeb29, 0xeb46, 0xeb63, 0xeb82, 0xeba0,
// Entry 6EC0 - 6EFF
0xebbe, 0xebdb, 0xebfe, 0xec22, 0xec37, 0xec58, 0xec7a, 0xec8f,
0xeca4, 0xecc5, 0xece7, 0xed01, 0xed1b, 0xed3f, 0xed5a, 0xed74,
0xed8a, 0xeda2, 0xedbb, 0xedd6, 0xeded, 0xee06, 0xee27, 0xee47,
0xee61, 0xee78, 0xee92, 0xeead, 0xeecd, 0xeeee, 0xef07, 0xef20,
0xef38, 0xef53, 0xef6d, 0xef8a, 0xefab, 0xefcb, 0xeff8, 0xf011,
0xf02d, 0xf04d, 0xf071, 0xf095, 0xf0be, 0xf0e7, 0xf112, 0xf13d,
0xf169, 0xf195, 0xf1c0, 0xf1eb, 0xf21a, 0xf249, 0xf26b, 0xf28d,
0xf2be, 0xf2ef, 0xf312, 0xf32e, 0xf34b, 0xf367, 0xf38c, 0xf3b1,
// Entry 6F00 - 6F3F
0xf3c5, 0xf3de, 0xf3f6, 0xf411, 0xf42b, 0xf448, 0xf469, 0xf489,
0xf4b6, 0xf4d3, 0xf4fd, 0xf51f, 0xf541, 0xf563, 0xf584, 0xf5a5,
0xf5c6, 0xf5ef, 0xf60e, 0xf62d, 0xf64c, 0xf66b, 0xf68a, 0xf6a3,
0xf6ba, 0xf6d2, 0xf6e8, 0xf701, 0xf718, 0xf733, 0xf74c, 0xf76b,
0xf78c, 0xf7ab, 0xf7d1, 0xf7f1, 0xf81a, 0xf842, 0xf860, 0xf87c,
0xf89a, 0xf8b7, 0xf8d3, 0xf8f0, 0xf90e, 0xf92b, 0xf951, 0xf977,
0xf991, 0xf9a6, 0xf9b6, 0xf9ca, 0xf9de, 0xf9f2, 0xfa0a, 0xfa24,
0xfa43, 0xfa65, 0xfa76, 0xfa89, 0xfaa5, 0xfabe, 0xfad4, 0xfaf4,
// Entry 6F40 - 6F7F
0xfb14, 0xfb34, 0xfb54, 0xfb74, 0xfb94, 0xfbb4, 0xfbd4, 0xfbf4,
0xfc15, 0xfc36, 0xfc50, 0xfc6a, 0xfc86, 0xfca1, 0xfcc2, 0xfce1,
0xfd02, 0xfd29, 0xfd42, 0xfd5e, 0xfd7c, 0xfd97, 0xfdb4, 0xfdd3,
0xfde6, 0xfdfd, 0xfe12, 0xfe26, 0xfe3b, 0xfe5a, 0xfe79, 0xfe8e,
0xfea9, 0xfec8, 0xfee7, 0xff00, 0xff19, 0xff3b, 0xff5f, 0xff79,
0xff97, 0xffb1, 0xffcf, 0x0006, 0x003f, 0x0083, 0x00bc, 0x00f7,
0x013f, 0x0187, 0x01cf, 0x01e3, 0x0202, 0x0221, 0x0238, 0x024c,
0x0262, 0x0277, 0x028f, 0x02a6, 0x02bd, 0x02d5, 0x02f4, 0x0313,
// Entry 6F80 - 6FBF
0x0334, 0x0351, 0x036d, 0x038f, 0x03af, 0x03d4, 0x03f4, 0x0413,
0x043f, 0x0469, 0x0494, 0x04bd, 0x04dc, 0x04ef, 0x0503, 0x0520,
0x053d, 0x055a, 0x0577, 0x0594, 0x05b1, 0x05ce, 0x05eb, 0x0608,
0x0626, 0x0644, 0x0662, 0x0680, 0x069e, 0x06bc, 0x06da, 0x06f8,
0x0716, 0x0734, 0x0752, 0x0770, 0x078e, 0x07ac, 0x07ca, 0x07e8,
0x0806, 0x0824, 0x0842, 0x0860, 0x0884, 0x08a8, 0x08cc, 0x08f0,
0x0914, 0x0938, 0x095d, 0x0982, 0x09a7, 0x09cc, 0x09f1, 0x0a16,
0x0a3b, 0x0a60, 0x0a85, 0x0aaa, 0x0acf, 0x0af4, 0x0b19, 0x0b3e,
// Entry 6FC0 - 6FFF
0x0b63, 0x0b88, 0x0bad, 0x0bd2, 0x0bf7, 0x0c1c, 0x0c41, 0x0c66,
0x0c8b, 0x0cb0, 0x0cd5, 0x0cfa, 0x0d1f, 0x0d44, 0x0d69, 0x0d8e,
0x0db3, 0x0dd2, 0x0df3, 0x0e14, 0x0e28, 0x0e3d, 0x0e51, 0x0e65,
0x0e7b, 0x0e90, 0x0ea5, 0x0eb9, 0x0ecf, 0x0ee5, 0x0efa, 0x0f0e,
0x0f25, 0x0f3c, 0x0f55, 0x0f6e, 0x0f86, 0x0f9e, 0x0fb8, 0x0fd1,
0x0fea, 0x0ffc, 0x100d, 0x101e, 0x1031, 0x1043, 0x1055, 0x1066,
0x1079, 0x108c, 0x109e, 0x10af, 0x10c3, 0x10d7, 0x10ed, 0x1103,
0x1118, 0x112d, 0x1144, 0x115a, 0x1170, 0x1182, 0x119b, 0x11b1,
// Entry 7000 - 703F
0x11ca, 0x11e2, 0x11f2, 0x1206, 0x121f, 0x1232, 0x1247, 0x1262,
0x127b, 0x128f, 0x12a7, 0x12c2, 0x12eb, 0x1303, 0x131d, 0x1333,
0x134c, 0x135f, 0x1374, 0x138e, 0x13a3, 0x13ba, 0x13cf, 0x13e4,
0x13fc, 0x140e, 0x141f, 0x1437, 0x144e, 0x1462, 0x1476, 0x1490,
0x14ad, 0x14c2, 0x14d6, 0x14ed, 0x1502, 0x1519, 0x152f, 0x1543,
0x1559, 0x1570, 0x158a, 0x15a0, 0x15bb, 0x15d3, 0x15e6, 0x15fd,
0x1616, 0x162b, 0x163f, 0x1653, 0x1674, 0x168b, 0x16a0, 0x16b6,
0x16c9, 0x16e3, 0x16fd, 0x1716, 0x1730, 0x1745, 0x175f, 0x177a,
// Entry 7040 - 707F
0x178d, 0x17a0, 0x17b5, 0x17c8, 0x17df, 0x17f6, 0x180b, 0x1823,
0x183a, 0x1850, 0x1866, 0x187e, 0x1893, 0x18a8, 0x18c1, 0x18d9,
0x18f3, 0x190d, 0x1924, 0x193b, 0x1956, 0x1971, 0x198e, 0x19aa,
0x19c6, 0x19e1, 0x19fe, 0x1a1b, 0x1a37, 0x1a52, 0x1a6d, 0x1a8a,
0x1aa6, 0x1ac2, 0x1add, 0x1afa, 0x1b17, 0x1b33, 0x1b4d, 0x1b67,
0x1b83, 0x1b9e, 0x1bb9, 0x1bc7, 0x1bd6, 0x1bf1, 0x1c0c, 0x1c27,
0x1c42, 0x1c5d, 0x1c78, 0x1c93, 0x1cae, 0x1cc9, 0x1ce4, 0x1cff,
0x1d1a, 0x1d35, 0x1d50, 0x1d6b, 0x1d86, 0x1da1, 0x1dbc, 0x1dd7,
// Entry 7080 - 70BF
0x1df2, 0x1e0d, 0x1e28, 0x1e43, 0x1e5e, 0x1e79, 0x1e94, 0x1ead,
0x1ec6, 0x1edf, 0x1ef8, 0x1f11, 0x1f2a, 0x1f43, 0x1f5c, 0x1f75,
0x1f8e, 0x1fa7, 0x1fc0, 0x1fd9, 0x1ff2, 0x200b, 0x2024, 0x203d,
0x2056, 0x206f, 0x2088, 0x20a1, 0x20ba, 0x20d3, 0x20ec, 0x2105,
0x211e, 0x213b, 0x2158, 0x2175, 0x2192, 0x21af, 0x21cc, 0x21e9,
0x2206, 0x2223, 0x2240, 0x225d, 0x227a, 0x2297, 0x22b4, 0x22d1,
0x22ee, 0x230b, 0x2328, 0x2345, 0x2362, 0x237f, 0x239c, 0x23b9,
0x23d6, 0x23f3, 0x2410, 0x242b, 0x2446, 0x2461, 0x247c, 0x2497,
// Entry 70C0 - 70FF
0x24b2, 0x24cd, 0x24e8, 0x2503, 0x251e, 0x2539, 0x2554, 0x256f,
0x258a, 0x25a5, 0x25c0, 0x25db, 0x25f6, 0x2611, 0x262c, 0x2647,
0x2662, 0x267d, 0x2698, 0x26b3, 0x26d5, 0x26f7, 0x2719, 0x273b,
0x275d, 0x277f, 0x27a1, 0x27c3, 0x27e5, 0x2807, 0x2829, 0x284b,
0x286d, 0x288f, 0x28b1, 0x28d3, 0x28f5, 0x2917, 0x2939, 0x295b,
0x297d, 0x299f, 0x29c1, 0x29e3, 0x2a05, 0x2a27, 0x2a47, 0x2a67,
0x2a87, 0x2aa7, 0x2ac7, 0x2ae7, 0x2b07, 0x2b27, 0x2b47, 0x2b67,
0x2b87, 0x2ba7, 0x2bc7, 0x2be7, 0x2c07, 0x2c27, 0x2c47, 0x2c67,
// Entry 7100 - 713F
0x2c87, 0x2ca7, 0x2cc7, 0x2ce7, 0x2d07, 0x2d27, 0x2d47, 0x2d67,
0x2d84, 0x2da1, 0x2dbe, 0x2ddb, 0x2df8, 0x2e15, 0x2e32, 0x2e4f,
0x2e6c, 0x2e89, 0x2ea6, 0x2ec3, 0x2ee0, 0x2efd, 0x2f1a, 0x2f37,
0x2f54, 0x2f71, 0x2f8c, 0x2fa7, 0x2fc2, 0x2fdd, 0x2ff8, 0x3013,
0x302e, 0x3049, 0x3064, 0x307f, 0x309a, 0x30b5, 0x30d0, 0x30eb,
0x3106, 0x3121, 0x313c, 0x3157, 0x3172, 0x318d, 0x31a8, 0x31c3,
0x31de, 0x3200, 0x3222, 0x3244, 0x3266, 0x3288, 0x32aa, 0x32cc,
0x32ee, 0x3310, 0x3332, 0x3354, 0x3376, 0x3398, 0x33ba, 0x33dc,
// Entry 7140 - 717F
0x33fe, 0x3420, 0x3442, 0x3464, 0x3486, 0x34a8, 0x34ca, 0x34ec,
0x350e, 0x3530, 0x3552, 0x3572, 0x3592, 0x35b2, 0x35d2, 0x35f2,
0x3612, 0x3632, 0x3652, 0x3672, 0x3692, 0x36b2, 0x36d2, 0x36f2,
0x3712, 0x3732, 0x3752, 0x3772, 0x3792, 0x37b2, 0x37d2, 0x37f2,
0x3812, 0x3832, 0x3852, 0x3872, 0x3892, 0x38b0, 0x38ce, 0x38ec,
0x390a, 0x3928, 0x3946, 0x3964, 0x3982, 0x39a0, 0x39be, 0x39dc,
0x39fa, 0x3a18, 0x3a36, 0x3a54, 0x3a72, 0x3a90, 0x3aae, 0x3acc,
0x3aea, 0x3b08, 0x3b24, 0x3b40, 0x3b5c, 0x3b78, 0x3b94, 0x3bb0,
// Entry 7180 - 71BF
0x3bcc, 0x3be8, 0x3c04, 0x3c20, 0x3c3c, 0x3c58, 0x3c74, 0x3c90,
0x3cac, 0x3cc8, 0x3ce4, 0x3d00, 0x3d1c, 0x3d38, 0x3d54, 0x3d70,
0x3d8c, 0x3da8, 0x3dc4, 0x3de0, 0x3e04, 0x3e28, 0x3e4c, 0x3e70,
0x3e94, 0x3eb8, 0x3edc, 0x3f00, 0x3f24, 0x3f48, 0x3f6c, 0x3f90,
0x3fb4, 0x3fd8, 0x3ffc, 0x4020, 0x4044, 0x4068, 0x408c, 0x40ae,
0x40d0, 0x40f2, 0x4114, 0x4136, 0x4158, 0x417a, 0x419c, 0x41be,
0x41e0, 0x4202, 0x4224, 0x4246, 0x4268, 0x428a, 0x42ac, 0x42ce,
0x42f0, 0x4312, 0x4334, 0x4356, 0x4378, 0x439a, 0x43bc, 0x43de,
// Entry 71C0 - 71FF
0x4400, 0x4423, 0x4446, 0x4469, 0x448c, 0x44af, 0x44d2, 0x44f5,
0x4518, 0x453b, 0x455e, 0x4581, 0x45a4, 0x45c7, 0x45ea, 0x460d,
0x4630, 0x4653, 0x4676, 0x4699, 0x46bc, 0x46df, 0x4702, 0x4725,
0x4748, 0x476b, 0x478e, 0x47af, 0x47d0, 0x47f1, 0x4812, 0x4833,
0x4854, 0x4875, 0x4896, 0x48b7, 0x48d8, 0x48f9, 0x491a, 0x493b,
0x495c, 0x497d, 0x499e, 0x49bf, 0x49e0, 0x4a01, 0x4a22, 0x4a43,
0x4a64, 0x4a85, 0x4aa6, 0x4ac7, 0x4ae8, 0x4b09, 0x4b2a, 0x4b4b,
0x4b6c, 0x4b8d, 0x4bae, 0x4bcf, 0x4bf0, 0x4c11, 0x4c32, 0x4c53,
// Entry 7200 - 723F
0x4c74, 0x4c95, 0x4cb6, 0x4cd7, 0x4cf8, 0x4d19, 0x4d3a, 0x4d5b,
0x4d7c, 0x4d9d, 0x4dbe, 0x4ddf, 0x4e00, 0x4e21, 0x4e42, 0x4e61,
0x4e80, 0x4e9f, 0x4ebe, 0x4edd, 0x4efc, 0x4f1b, 0x4f3a, 0x4f59,
0x4f78, 0x4f97, 0x4fb6, 0x4fd5, 0x4ff4, 0x5013, 0x5032, 0x5051,
0x5070, 0x508f, 0x50ae, 0x50cd, 0x50ec, 0x510b, 0x512a, 0x5149,
0x5168, 0x518e, 0x51b4, 0x51da, 0x5200, 0x5226, 0x524c, 0x5272,
0x5298, 0x52be, 0x52e4, 0x530a, 0x5330, 0x5356, 0x537c, 0x53a2,
0x53c8, 0x53ee, 0x5414, 0x543a, 0x5460, 0x5486, 0x54ac, 0x54d2,
// Entry 7240 - 727F
0x54f8, 0x551e, 0x5544, 0x5568, 0x558c, 0x55b0, 0x55d4, 0x55f8,
0x561c, 0x5640, 0x5664, 0x5688, 0x56ac, 0x56d0, 0x56f4, 0x5718,
0x573c, 0x5760, 0x5784, 0x57a8, 0x57cc, 0x57f0, 0x5814, 0x5838,
0x585c, 0x5880, 0x58a4, 0x58c8, 0x58ec, 0x5914, 0x593c, 0x5964,
0x598c, 0x59b4, 0x59dc, 0x5a04, 0x5a2c, 0x5a54, 0x5a7c, 0x5aa4,
0x5acc, 0x5af4, 0x5b1c, 0x5b44, 0x5b6c, 0x5b94, 0x5bbc, 0x5be4,
0x5c0c, 0x5c34, 0x5c5c, 0x5c84, 0x5cac, 0x5cd4, 0x5cfc, 0x5d22,
0x5d48, 0x5d6e, 0x5d94, 0x5dba, 0x5de0, 0x5e06, 0x5e2c, 0x5e52,
// Entry 7280 - 72BF
0x5e78, 0x5e9e, 0x5ec4, 0x5eea, 0x5f10, 0x5f36, 0x5f5c, 0x5f82,
0x5fa8, 0x5fce, 0x5ff4, 0x601a, 0x6040, 0x6066, 0x608c, 0x60b2,
0x60d8, 0x6105, 0x6132, 0x615f, 0x618c, 0x61b9, 0x61e6, 0x6213,
0x6240, 0x626d, 0x629a, 0x62c7, 0x62f4, 0x6321, 0x634e, 0x637b,
0x63a8, 0x63d5, 0x6402, 0x642f, 0x645c, 0x6489, 0x64b6, 0x64e3,
0x6510, 0x653d, 0x656a, 0x6595, 0x65c0, 0x65eb, 0x6616, 0x6641,
0x666c, 0x6697, 0x66c2, 0x66ed, 0x6718, 0x6743, 0x676e, 0x6799,
0x67c4, 0x67ef, 0x681a, 0x6845, 0x6870, 0x689b, 0x68c6, 0x68f1,
// Entry 72C0 - 72FF
0x691c, 0x6947, 0x6972, 0x699d, 0x69c8, 0x69e8, 0x6a08, 0x6a28,
0x6a48, 0x6a68, 0x6a88, 0x6aa8, 0x6ac8, 0x6ae8, 0x6b08, 0x6b28,
0x6b48, 0x6b68, 0x6b88, 0x6ba8, 0x6bc8, 0x6be8, 0x6c08, 0x6c28,
0x6c48, 0x6c68, 0x6c88, 0x6ca8, 0x6cc8, 0x6ce8, 0x6d08, 0x6d26,
0x6d44, 0x6d62, 0x6d80, 0x6d9e, 0x6dbc, 0x6dda, 0x6df8, 0x6e16,
0x6e34, 0x6e52, 0x6e70, 0x6e8e, 0x6eac, 0x6eca, 0x6ee8, 0x6f06,
0x6f24, 0x6f42, 0x6f60, 0x6f7e, 0x6f9c, 0x6fba, 0x6fd8, 0x6ff6,
0x7014, 0x7037, 0x705a, 0x7079, 0x7097, 0x70b6, 0x70d5, 0x70f6,
// Entry 7300 - 733F
0x7114, 0x7131, 0x7150, 0x716e, 0x718d, 0x71ac, 0x71c8, 0x71e4,
0x7200, 0x7221, 0x723d, 0x725a, 0x7280, 0x729f, 0x72bc, 0x72dd,
0x72fa, 0x7317, 0x7334, 0x7353, 0x736a, 0x7387, 0x73a3, 0x73c0,
0x73dd, 0x73fc, 0x7418, 0x7433, 0x7450, 0x746c, 0x7489, 0x74a6,
0x74c0, 0x74da, 0x74f4, 0x7513, 0x752d, 0x7548, 0x756b, 0x7588,
0x75a3, 0x75c2, 0x75dd, 0x75f8, 0x7613, 0x7630, 0x7656, 0x7676,
0x7694, 0x76b2, 0x76ce, 0x76ea, 0x7705, 0x7726, 0x7746, 0x7767,
0x7788, 0x77ab, 0x77cb, 0x77ea, 0x780b, 0x782b, 0x784c, 0x786d,
// Entry 7340 - 737F
0x788b, 0x78a9, 0x78c7, 0x78ea, 0x7908, 0x7927, 0x794f, 0x7970,
0x798f, 0x79b2, 0x79d1, 0x79f0, 0x7a0f, 0x7a30, 0x7a49, 0x7a68,
0x7a86, 0x7aa5, 0x7ac4, 0x7ae5, 0x7b03, 0x7b20, 0x7b3f, 0x7b5d,
0x7b7c, 0x7b9b, 0x7bb7, 0x7bd3, 0x7bef, 0x7c10, 0x7c2c, 0x7c49,
0x7c6e, 0x7c8d, 0x7caa, 0x7ccb, 0x7ce8, 0x7d05, 0x7d22, 0x7d41,
0x7d69, 0x7d8b, 0x7dab, 0x7dcb, 0x7de9, 0x7e07, 0x7e24, 0x7e4a,
0x7e6f, 0x7e95, 0x7ebb, 0x7ee3, 0x7f08, 0x7f2c, 0x7f52, 0x7f77,
0x7f9d, 0x7fc3, 0x7fe6, 0x8009, 0x802c, 0x8054, 0x8077, 0x809b,
// Entry 7380 - 73BF
0x80c8, 0x80ee, 0x8112, 0x813a, 0x815e, 0x8182, 0x81a6, 0x81cc,
0x81ea, 0x820e, 0x8231, 0x8255, 0x8279, 0x829f, 0x82c2, 0x82e4,
0x8308, 0x832b, 0x834f, 0x8373, 0x8394, 0x83b5, 0x83d6, 0x83fc,
0x841d, 0x843f, 0x8469, 0x848d, 0x84af, 0x84d5, 0x84f7, 0x8519,
0x853b, 0x855f, 0x858c, 0x85b3, 0x85d8, 0x85fd, 0x8620, 0x8643,
0x8665, 0x868f, 0x86b8, 0x86e2, 0x870c, 0x8738, 0x8761, 0x8789,
0x87b3, 0x87dc, 0x8806, 0x8830, 0x8857, 0x887e, 0x88a5, 0x88d1,
0x88f8, 0x8920, 0x8951, 0x897b, 0x89a3, 0x89cf, 0x89f7, 0x8a1f,
// Entry 73C0 - 73FF
0x8a47, 0x8a71, 0x8a93, 0x8abb, 0x8ae2, 0x8b0a, 0x8b32, 0x8b5c,
0x8b83, 0x8ba9, 0x8bd1, 0x8bf8, 0x8c20, 0x8c48, 0x8c6d, 0x8c92,
0x8cb7, 0x8ce1, 0x8d06, 0x8d2c, 0x8d5a, 0x8d82, 0x8da8, 0x8dd2,
0x8df8, 0x8e1e, 0x8e44, 0x8e6c, 0x8e9d, 0x8ec8, 0x8ef1, 0x8f1a,
0x8f41, 0x8f68, 0x8f8e, 0x8fbf, 0x8fef, 0x9020, 0x9051, 0x9084,
0x90b4, 0x90e3, 0x9114, 0x9144, 0x9175, 0x91a6, 0x91d4, 0x9202,
0x9230, 0x9263, 0x9291, 0x92c0, 0x92f8, 0x9329, 0x9358, 0x938b,
0x93ba, 0x93e9, 0x9418, 0x9449, 0x9472, 0x94a1, 0x94cf, 0x94fe,
// Entry 7400 - 743F
0x952d, 0x955e, 0x958c, 0x95b9, 0x95e8, 0x9616, 0x9645, 0x9674,
0x96a0, 0x96cc, 0x96f8, 0x9729, 0x9755, 0x9782, 0x97b7, 0x97e6,
0x9813, 0x9844, 0x9871, 0x989e, 0x98cb, 0x98fa, 0x9932, 0x9964,
0x9994, 0x99c4, 0x99f2, 0x9a20, 0x9a4d, 0x9a6e, 0x9a8d, 0x9aa9,
0x9ac4, 0x9adf, 0x9afc, 0x9b18, 0x9b34, 0x9b4f, 0x9b6c, 0x9b89,
0x9ba5, 0x9bca, 0x9bee, 0x9c12, 0x9c38, 0x9c5d, 0x9c82, 0x9ca6,
0x9ccc, 0x9cf2, 0x9d17, 0x9d39, 0x9d5a, 0x9d7b, 0x9d9e, 0x9dc0,
0x9de2, 0x9e03, 0x9e26, 0x9e49, 0x9e6b, 0x9e92, 0x9eb8, 0x9ede,
// Entry 7440 - 747F
0x9f06, 0x9f2d, 0x9f54, 0x9f7a, 0x9fa2, 0x9fca, 0x9ff1, 0xa012,
0xa032, 0xa052, 0xa074, 0xa095, 0xa0b6, 0xa0d6, 0xa0f8, 0xa11a,
0xa13b, 0xa156, 0xa173, 0xa18d, 0xa1a8, 0xa1c4, 0xa1e0, 0xa200,
0xa222, 0xa24e, 0xa278, 0xa29a, 0xa2bc, 0xa2e2, 0xa305, 0xa327,
0xa34b, 0xa372, 0xa3a4, 0xa3cd, 0xa3f9, 0xa425, 0xa451, 0xa488,
0xa4c0, 0xa4f3, 0xa526, 0xa550, 0xa57c, 0xa5a8, 0xa5d4, 0xa5fc,
0xa626, 0xa65c, 0xa692, 0xa6bf, 0xa6fa, 0xa731, 0xa76d, 0xa7a4,
0xa7de, 0xa80d, 0xa83d, 0xa86c, 0xa89b, 0xa8d4, 0xa90b, 0xa94c,
// Entry 7480 - 74BF
0xa988, 0xa9ba, 0xa9ec, 0xaa2a, 0xaa5f, 0xaa99, 0xaada, 0xab0c,
0xab3e, 0xab71, 0xaba8, 0xabde, 0xac13, 0xac46, 0xac7f, 0xacb2,
0xace1, 0xad17, 0xad52, 0xad84, 0xadba, 0xaddc, 0xae03, 0xae2c,
0xae58, 0xae8a, 0xaeb6, 0xaee7, 0xaf14, 0xaf3d, 0xaf6b, 0xaf9e,
0xafd6, 0xb004, 0xb037, 0xb06e, 0xb096, 0xb0c3, 0xb0f2, 0xb11b,
0xb14b, 0xb186, 0xb1bf, 0xb1d4, 0xb1fe, 0xb218, 0xb238, 0xb25d,
0xb27d, 0xb2a0, 0xb2cc, 0xb2ee, 0xb31b, 0xb34d, 0xb36f, 0xb384,
0xb3a4, 0xb3c2, 0xb3e5, 0xb403, 0xb418, 0xb431, 0xb445, 0xb469,
// Entry 74C0 - 74FF
0xb488, 0xb4aa, 0xb4c7, 0xb4ee, 0xb510, 0xb52e, 0xb547, 0xb55e,
0xb573, 0xb593, 0xb5b1, 0xb5d4, 0xb5ef, 0xb618, 0xb62e, 0xb64a,
0xb670, 0xb691, 0xb6b5, 0xb6d4, 0xb704, 0xb734, 0xb74a, 0xb771,
0xb79a, 0xb7c2, 0xb7ea, 0xb807, 0xb833, 0xb864, 0xb896, 0xb8b7,
0xb8e8, 0xb917, 0xb947, 0xb966, 0xb991, 0xb9b2, 0xb9d1, 0xb9f1,
0xba1c, 0xba3d, 0xba67, 0xba89, 0xbaac, 0xbad4, 0xbafd, 0xbb36,
0xbb6b, 0xbb8d, 0xbbb1, 0xbbd4, 0xbbf7, 0xbc20, 0xbc4b, 0xbc75,
0xbc90, 0xbcba, 0xbce9, 0xbd1a, 0xbd39, 0xbd71, 0xbdaa, 0xbdc7,
// Entry 7500 - 753F
0xbdf0, 0xbe11, 0xbe34, 0xbe55, 0xbe77, 0xbe98, 0xbec3, 0xbef4,
0xbf14, 0xbf34, 0xbf54, 0xbf7b, 0xbfa4, 0xbfd2, 0xbffd, 0xc027,
0xc054, 0xc07a, 0xc0a2, 0xc0ce, 0xc0f6, 0xc117, 0xc134, 0xc153,
0xc174, 0xc19f, 0xc1c9, 0xc1eb, 0xc214, 0xc237, 0xc25f, 0xc289,
0xc2b8, 0xc2df, 0xc308, 0xc335, 0xc361, 0xc38a, 0xc3b9, 0xc3eb,
0xc422, 0xc458, 0xc48d, 0xc4bf, 0xc4e2, 0xc508, 0xc52f, 0xc564,
0xc59a, 0xc5cb, 0xc5fc, 0xc62c, 0xc65e, 0xc696, 0xc6ca, 0xc6f0,
0xc71a, 0xc74e, 0xc782, 0xc7b5, 0xc7dd, 0xc7fd, 0xc822, 0xc849,
// Entry 7540 - 757F
0xc871, 0xc893, 0xc8bb, 0xc8e1, 0xc906, 0xc928, 0xc943, 0xc963,
0xc98c, 0xc9b6, 0xc9db, 0xc9fe, 0xca2e, 0xca5d, 0xca8c, 0xcab9,
0xcae5, 0xcb14, 0xcb42, 0xcb77, 0xcb8c, 0xcba6, 0xcbbe, 0xcbd8,
0xcbf1, 0xcc09, 0xcc23, 0xcc3c, 0xcc55, 0xcc70, 0xcc8a, 0xcca2,
0xccbc, 0xccd5, 0xcceb, 0xcd03, 0xcd1a, 0xcd35, 0xcd50, 0xcd70,
0xcd90, 0xcdb2, 0xcdd4, 0xcdf2, 0xce10, 0xce2e, 0xce4e, 0xce6e,
0xce8a, 0xceaf, 0xced7, 0xceff, 0xcf27, 0xcf51, 0xcf85, 0xcfb9,
0xcfe9, 0xd016, 0xd044, 0xd078, 0xd0ad, 0xd0e1, 0xd117, 0xd147,
// Entry 7580 - 75BF
0xd175, 0xd1a5, 0xd1d6, 0xd212, 0xd236, 0xd26d, 0xd29d, 0xd2ce,
0xd30a, 0xd333, 0xd35d, 0xd386, 0xd3b1, 0xd3dd, 0xd408, 0xd436,
0xd460, 0xd48b, 0xd4b5, 0xd4dd, 0xd506, 0xd52e, 0xd559, 0xd585,
0xd5b0, 0xd5da, 0xd605, 0xd62f, 0xd665, 0xd69b, 0xd6d6, 0xd70d,
0xd744, 0xd780, 0xd7a4, 0xd7d2, 0xd800, 0xd82e, 0xd856, 0xd87f,
0xd8a7, 0xd8d1, 0xd8fc, 0xd928, 0xd953, 0xd980, 0xd9b0, 0xd9e1,
0xda11, 0xda43, 0xda76, 0xdaaa, 0xdadd, 0xdb12, 0xdb47, 0xdb7d,
0xdbb2, 0xdbe9, 0xdc1a, 0xdc49, 0xdc7a, 0xdcac, 0xdce9, 0xdd0e,
// Entry 75C0 - 75FF
0xdd46, 0xdd77, 0xddb2, 0xddef, 0xde13, 0xde3f, 0xde6c, 0xde98,
0xdebd, 0xdee6, 0xdf10, 0xdf39, 0xdf65, 0xdf92, 0xdfbe, 0xdfe9,
0xe015, 0xe040, 0xe078, 0xe0b0, 0xe0ed, 0xe124, 0xe15b, 0xe197,
0xe1bc, 0xe1ee, 0xe221, 0xe253, 0xe287, 0xe2bd, 0xe2f4, 0xe32a,
0xe362, 0xe3a1, 0xe3e1, 0xe40a, 0xe434, 0xe45d, 0xe486, 0xe4b0,
0xe4d9, 0xe509, 0xe53f, 0xe576, 0xe5ac, 0xe5e2, 0xe619, 0xe64f,
0xe681, 0xe6b2, 0xe6e4, 0xe709, 0xe72e, 0xe756, 0xe77c, 0xe7b3,
0xe7e9, 0xe81f, 0xe855, 0xe88d, 0xe8c5, 0xe902, 0xe934, 0xe965,
// Entry 7600 - 763F
0xe996, 0xe9c7, 0xe9fa, 0xea2d, 0xea65, 0xea9c, 0xead4, 0xeb0b,
0xeb46, 0xeb81, 0xebc2, 0xec03, 0xec44, 0xec85, 0xecc6, 0xed07,
0xed48, 0xed89, 0xedc3, 0xedfd, 0xee33, 0xee69, 0xeea4, 0xeedd,
0xef16, 0xef55, 0xef94, 0xefda, 0xf020, 0xf05f, 0xf09e, 0xf0dd,
0xf11c, 0xf154, 0xf18c, 0xf1c0, 0xf1f4, 0xf22d, 0xf258, 0xf284,
0xf2af, 0xf2dc, 0xf30a, 0xf334, 0xf35e, 0xf388, 0xf3b2, 0xf3dc,
0xf402, 0xf428, 0xf453, 0xf483, 0xf4b9, 0xf4f0, 0xf526, 0xf55d,
0xf5a1, 0xf5e6, 0xf62a, 0xf66e, 0xf6b3, 0xf6f7, 0xf72f, 0xf767,
// Entry 7640 - 767F
0xf7a7, 0xf7e7, 0xf81b, 0xf84f, 0xf891, 0xf8d3, 0xf8f6, 0xf919,
0xf931, 0xf949, 0xf962, 0xf97d, 0xf99d, 0xf9c9, 0xf9ed, 0xfa08,
0xfa18, 0xfa2c, 0xfa58, 0xfa80, 0xfaad, 0xfad6, 0xfb00, 0xfb20,
0xfb58, 0xfb8b, 0xfbc6, 0xfbe6, 0xfc0b, 0xfc2d, 0xfc55, 0xfc7d,
0xfca3, 0xfcc9, 0xfce5, 0xfd01, 0xfd1e, 0xfd33, 0xfd4c, 0xfd63,
0xfd7f, 0xfd9d, 0xfdb7, 0xfdd1, 0xfded, 0xfe0f, 0xfe23, 0xfe3b,
0xfe55, 0xfe75, 0xfe9b, 0xfec8, 0xfefa, 0xff21, 0xff4f, 0xff82,
0xffa6, 0xffcb, 0xfff1, 0x000a, 0x0024, 0x003d, 0x005a, 0x0079,
// Entry 7680 - 76BF
0x0095, 0x00a5, 0x00bd, 0x00d5, 0x00ee, 0x0106, 0x0121, 0x013b,
0x015f, 0x0183, 0x019c, 0x01b5, 0x01d5, 0x01f5, 0x0215, 0x022c,
0x024c, 0x0268, 0x027f, 0x029f, 0x02bb, 0x02d8, 0x02f6, 0x0315,
0x0330, 0x0354, 0x0374, 0x0394, 0x03bd, 0x03e2, 0x03f8, 0x0416,
0x0435, 0x044c, 0x046b, 0x0489, 0x04aa, 0x04ca, 0x04ea, 0x0503,
0x0524, 0x0545, 0x0568, 0x0587, 0x05aa, 0x05d6, 0x05fd, 0x0623,
0x0649, 0x066f, 0x0680, 0x069a, 0x06b5, 0x06d9, 0x06f2, 0x0714,
0x072f, 0x0751, 0x0774, 0x0784, 0x0794, 0x07aa, 0x07c8, 0x07ea,
// Entry 76C0 - 76FF
0x0811, 0x0839, 0x0860, 0x088c, 0x08b3, 0x08d8, 0x0906, 0x0922,
0x093b, 0x0954, 0x096d, 0x0986, 0x099f, 0x09b8, 0x09d1, 0x09e3,
0x0a07, 0x0a2c, 0x0a47, 0x0a61, 0x0a7b, 0x0a99, 0x0ab3, 0x0ad4,
0x0ae5, 0x0afa, 0x0b0f, 0x0b20, 0x0b37, 0x0b52, 0x0b6d, 0x0b88,
0x0ba3, 0x0bbe, 0x0bdd, 0x0bfc, 0x0c1b, 0x0c3a, 0x0c59, 0x0c78,
0x0c97, 0x0cb6, 0x0cd6, 0x0cf6, 0x0d16, 0x0d36, 0x0d56, 0x0d76,
0x0d96, 0x0dc0, 0x0de4, 0x0e07, 0x0e24, 0x0e4a, 0x0e75, 0x0e9a,
0x0eb9, 0x0ef5, 0x0f26, 0x0f56, 0x0f7c, 0x0fab, 0x0fd0, 0x0ffc,
// Entry 7700 - 773F
0x101e, 0x1041, 0x1063, 0x1094, 0x10c3, 0x10eb, 0x1118, 0x114b,
0x117c, 0x11a4, 0x11d7, 0x120a, 0x1232, 0x1265, 0x128d, 0x12ab,
0x12d9, 0x1307, 0x1335, 0x1363, 0x1391, 0x13bf, 0x13de, 0x13fe,
0x141e, 0x1441, 0x1462, 0x1483, 0x14a6, 0x14c8, 0x14e8, 0x1510,
0x152d, 0x154f, 0x156f, 0x1592, 0x15b5, 0x15d6, 0x15f5, 0x1617,
0x1638, 0x1659, 0x167b, 0x169a, 0x16bb, 0x16db, 0x16fb, 0x171a,
0x173c, 0x175b, 0x177b, 0x179b, 0x17bb, 0x17d9, 0x17fe, 0x181c,
0x1849, 0x186c, 0x1897, 0x18b7, 0x18d7, 0x18f8, 0x1919, 0x193b,
// Entry 7740 - 777F
0x195c, 0x197d, 0x199f, 0x19c0, 0x19e0, 0x1a01, 0x1a22, 0x1a43,
0x1a63, 0x1a84, 0x1aa5, 0x1ac6, 0x1ae7, 0x1b07, 0x1b28, 0x1b49,
0x1b6b, 0x1b8d, 0x1baf, 0x1bd2, 0x1bf2, 0x1c13, 0x1c36, 0x1c5a,
0x1c91, 0x1cb2, 0x1cd9, 0x1d02, 0x1d29, 0x1d4a, 0x1d6c, 0x1d8e,
0x1db1, 0x1dd3, 0x1df5, 0x1e18, 0x1e3a, 0x1e5b, 0x1e7d, 0x1e9f,
0x1ec0, 0x1ee2, 0x1f04, 0x1f25, 0x1f47, 0x1f69, 0x1f8c, 0x1faf,
0x1fd2, 0x1ffb, 0x201f, 0x204e, 0x2086, 0x20a9, 0x20cd, 0x20fd,
0x212e, 0x2163, 0x219b, 0x21bb, 0x21dc, 0x21fd, 0x221d, 0x223d,
// Entry 7780 - 77BF
0x225d, 0x227d, 0x229e, 0x22be, 0x22de, 0x22fe, 0x231e, 0x233f,
0x2361, 0x2381, 0x23a1, 0x23c2, 0x23e3, 0x2403, 0x2425, 0x2446,
0x2466, 0x2486, 0x24a6, 0x24c6, 0x24e7, 0x2507, 0x2528, 0x2549,
0x256a, 0x258c, 0x25ad, 0x25ce, 0x25ef, 0x260f, 0x2630, 0x264f,
0x266f, 0x268e, 0x26ad, 0x26cc, 0x26ec, 0x270b, 0x272b, 0x274a,
0x2767, 0x2784, 0x27a1, 0x27be, 0x27db, 0x27f8, 0x2815, 0x283b,
0x2860, 0x2888, 0x28ae, 0x28da, 0x28fb, 0x2925, 0x2946, 0x2966,
0x2986, 0x29a8, 0x29c9, 0x29ea, 0x2a0a, 0x2a2c, 0x2a4e, 0x2a6f,
// Entry 77C0 - 77FF
0x2a93, 0x2ab4, 0x2ac2, 0x2ad0, 0x2ade, 0x2aec, 0x2afa, 0x2b08,
0x2b16, 0x2b24, 0x2b33, 0x2b41, 0x2b50, 0x2b5e, 0x2b6c, 0x2b7a,
0x2b88, 0x2b96, 0x2ba4, 0x2bb1, 0x2bc6, 0x2bd4, 0x2bea, 0x2bf7,
0x2c04, 0x2c19, 0x2c27, 0x2c3d, 0x2c4a, 0x2c58, 0x2c6e, 0x2c7b,
0x2c90, 0x2ca0, 0x2caf, 0x2cbf, 0x2ccf, 0x2cdf, 0x2cef, 0x2cff,
0x2d10, 0x2d20, 0x2d30, 0x2d40, 0x2d50, 0x2d61, 0x2d71, 0x2d81,
0x2d92, 0x2da2, 0x2db2, 0x2dc2, 0x2dd2, 0x2de2, 0x2df1, 0x2e01,
0x2e11, 0x2e21, 0x2e32, 0x2e42, 0x2e51, 0x2e60, 0x2e71, 0x2e80,
// Entry 7800 - 783F
0x2e92, 0x2ea3, 0x2eb4, 0x2ec5, 0x2ed7, 0x2ee8, 0x2ef9, 0x2f09,
0x2f19, 0x2f2a, 0x2f3b, 0x2f4c, 0x2f5d, 0x2f6c, 0x2f7d, 0x2f8c,
0x2f9d, 0x2fae, 0x2fbe, 0x2fce, 0x2fe0, 0x2ff1, 0x3002, 0x3012,
0x3024, 0x3036, 0x3047, 0x3057, 0x306b, 0x3080, 0x3095, 0x30aa,
0x30c0, 0x30d4, 0x30e9, 0x30fe, 0x3114, 0x3129, 0x313d, 0x3152,
0x3168, 0x317d, 0x3192, 0x31a6, 0x31bb, 0x31d0, 0x31e5, 0x31fa,
0x320e, 0x3224, 0x3239, 0x324e, 0x3263, 0x3279, 0x328f, 0x32a4,
0x32ba, 0x32d0, 0x32e5, 0x32fb, 0x3311, 0x3326, 0x333b, 0x3352,
// Entry 7840 - 787F
0x3368, 0x337e, 0x3393, 0x33aa, 0x33c1, 0x33d7, 0x33ed, 0x3403,
0x3419, 0x3430, 0x3447, 0x345d, 0x3473, 0x3490, 0x34a6, 0x34bd,
0x34d3, 0x34ef, 0x350c, 0x3528, 0x3545, 0x3561, 0x357d, 0x359a,
0x35b6, 0x35d3, 0x35ef, 0x360b, 0x3628, 0x3644, 0x3660, 0x367d,
0x3699, 0x36b6, 0x36d4, 0x36f2, 0x3710, 0x372f, 0x374d, 0x376c,
0x378a, 0x37a9, 0x37c7, 0x37e5, 0x3803, 0x3822, 0x3840, 0x385f,
0x387d, 0x389c, 0x38bb, 0x38da, 0x38f9, 0x3918, 0x3937, 0x3956,
0x3975, 0x3994, 0x39b3, 0x39d3, 0x39f3, 0x3a11, 0x3a2f, 0x3a4d,
// Entry 7880 - 78BF
0x3a6c, 0x3a8a, 0x3aa9, 0x3ac7, 0x3ae4, 0x3b01, 0x3b1e, 0x3b3c,
0x3b59, 0x3b77, 0x3b94, 0x3bb2, 0x3bd0, 0x3bee, 0x3c0c, 0x3c2a,
0x3c48, 0x3c66, 0x3c84, 0x3ca3, 0x3cc1, 0x3ce0, 0x3cfe, 0x3d1d,
0x3d3b, 0x3d59, 0x3d77, 0x3d96, 0x3db4, 0x3dd3, 0x3df1, 0x3e14,
0x3e32, 0x3e50, 0x3e6e, 0x3e8d, 0x3eac, 0x3eca, 0x3ee8, 0x3f06,
0x3f24, 0x3f43, 0x3f61, 0x3f80, 0x3f9e, 0x3fbc, 0x3fda, 0x3ff8,
0x4017, 0x4035, 0x4054, 0x4072, 0x4095, 0x40b3, 0x40d1, 0x40ef,
0x410e, 0x412c, 0x414b, 0x4169, 0x4187, 0x41a5, 0x41c3, 0x41e2,
// Entry 78C0 - 78FF
0x4200, 0x421f, 0x423d, 0x425c, 0x427b, 0x429a, 0x42b9, 0x42d8,
0x42f7, 0x4316, 0x4334, 0x4352, 0x4370, 0x438f, 0x43ad, 0x43cc,
0x43ea, 0x440a, 0x442a, 0x4449, 0x4468, 0x4487, 0x44a6, 0x44c5,
0x44e5, 0x4505, 0x4525, 0x4545, 0x4566, 0x4586, 0x45a7, 0x45c7,
0x45e8, 0x4609, 0x462e, 0x4654, 0x4679, 0x4697, 0x46b5, 0x46d3,
0x46f2, 0x4712, 0x4732, 0x4752, 0x4772, 0x4793, 0x47b1, 0x47cf,
0x47ed, 0x480c, 0x482a, 0x4849, 0x4867, 0x4886, 0x48a5, 0x48c4,
0x48e4, 0x4904, 0x4923, 0x4943, 0x4962, 0x4982, 0x49a6, 0x49cb,
// Entry 7900 - 793F
0x49ef, 0x4a0e, 0x4a2d, 0x4a4c, 0x4a6c, 0x4a8b, 0x4aab, 0x4aca,
0x4ae9, 0x4b08, 0x4b27, 0x4b47, 0x4b66, 0x4b86, 0x4ba5, 0x4bc3,
0x4be2, 0x4c01, 0x4c20, 0x4c40, 0x4c5f, 0x4c7f, 0x4c9e, 0x4cbd,
0x4cdc, 0x4cfc, 0x4d1c, 0x4d3a, 0x4d58, 0x4d76, 0x4d95, 0x4db3,
0x4dd2, 0x4df0, 0x4e10, 0x4e30, 0x4e50, 0x4e70, 0x4e90, 0x4ea7,
0x4ebe, 0x4ed7, 0x4eef, 0x4f07, 0x4f1e, 0x4f37, 0x4f50, 0x4f68,
0x4f8c, 0x4faf, 0x4fd6, 0x4ffe, 0x502a, 0x505a, 0x5081, 0x509a,
0x50b4, 0x50cd, 0x50e6, 0x50fd, 0x511c, 0x5133, 0x514b, 0x5162,
// Entry 7940 - 797F
0x5178, 0x518f, 0x51a5, 0x51bb, 0x51d3, 0x51eb, 0x5203, 0x521b,
0x5233, 0x524a, 0x5260, 0x5279, 0x5291, 0x52a8, 0x52c1, 0x52d8,
0x52f0, 0x5307, 0x531f, 0x5336, 0x534e, 0x5366, 0x537e, 0x5396,
0x53ae, 0x53c5, 0x53dd, 0x53f4, 0x540b, 0x5420, 0x543d, 0x5452,
0x5468, 0x547d, 0x5491, 0x54a6, 0x54ba, 0x54ce, 0x54e4, 0x54fa,
0x5510, 0x5526, 0x553c, 0x5551, 0x5565, 0x557c, 0x5592, 0x55a7,
0x55be, 0x55d3, 0x55e9, 0x55fe, 0x5614, 0x5629, 0x563f, 0x5655,
0x566b, 0x5681, 0x5697, 0x56ac, 0x56c2, 0x56d7, 0x56e2, 0x56fa,
// Entry 7980 - 79BF
0x571b, 0x5726, 0x573d, 0x574d, 0x575c, 0x576b, 0x577c, 0x578c,
0x579c, 0x57ab, 0x57bc, 0x57cd, 0x57dd, 0x57fb, 0x5816, 0x582c,
0x5842, 0x585a, 0x5871, 0x5888, 0x589e, 0x58b6, 0x58ce, 0x58e5,
0x58fb, 0x5914, 0x592d, 0x5945, 0x595d, 0x5975, 0x598f, 0x59a8,
0x59c1, 0x59df, 0x59fd, 0x5a1d, 0x5a3c, 0x5a5b, 0x5a79, 0x5a99,
0x5ab9, 0x5ad8, 0x5af7, 0x5b16, 0x5b37, 0x5b57, 0x5b77, 0x5b96,
0x5bb7, 0x5bd8, 0x5bf8, 0x5c17, 0x5c39, 0x5c5b, 0x5c7c, 0x5c9d,
0x5cbe, 0x5ce1, 0x5d03, 0x5d25, 0x5d3c, 0x5d55, 0x5d6a, 0x5d82,
// Entry 79C0 - 79FF
0x5d9c, 0x5dbb, 0x5dda, 0x5dfb, 0x5e1b, 0x5e3b, 0x5e5a, 0x5e7b,
0x5e9c, 0x5ebc, 0x5ed3, 0x5ef3, 0x5f10, 0x5f33, 0x5f49, 0x5f69,
0x5f89, 0x5fb2, 0x5fd1, 0x5fe9, 0x6001, 0x601b, 0x6034, 0x604d,
0x6065, 0x607f, 0x6099, 0x60b2, 0x60ca, 0x60e5, 0x6100, 0x611a,
0x6134, 0x614e, 0x616a, 0x6185, 0x61a0, 0x61c0, 0x61e0, 0x6202,
0x6223, 0x6244, 0x6264, 0x6286, 0x62a8, 0x62c9, 0x62ea, 0x630b,
0x632e, 0x6350, 0x6372, 0x6393, 0x63b6, 0x63d9, 0x63fb, 0x641c,
0x6440, 0x6464, 0x6487, 0x64aa, 0x64cd, 0x64f2, 0x6516, 0x653a,
// Entry 7A00 - 7A3F
0x6550, 0x6572, 0x6596, 0x65b9, 0x65dc, 0x65fe, 0x6622, 0x6646,
0x6669, 0x668b, 0x66b6, 0x66e0, 0x670b, 0x6736, 0x6755, 0x6775,
0x678d, 0x67a4, 0x67bc, 0x67d3, 0x67ea, 0x6802, 0x6819, 0x6830,
0x6847, 0x685e, 0x6875, 0x688d, 0x68a5, 0x68bd, 0x68d4, 0x68eb,
0x6902, 0x6919, 0x6930, 0x6949, 0x6960, 0x6978, 0x6990, 0x69a8,
0x69bf, 0x69d6, 0x69ef, 0x6a0e, 0x6a2e, 0x6a4d, 0x6a6c, 0x6a8b,
0x6aab, 0x6aca, 0x6ae9, 0x6b08, 0x6b27, 0x6b46, 0x6b66, 0x6b86,
0x6ba6, 0x6bc5, 0x6be4, 0x6c03, 0x6c22, 0x6c43, 0x6c62, 0x6c82,
// Entry 7A40 - 7A7F
0x6ca2, 0x6cc1, 0x6ce2, 0x6d01, 0x6d1f, 0x6d3d, 0x6d5b, 0x6d7a,
0x6d99, 0x6db7, 0x6dd5, 0x6df3, 0x6e13, 0x6e32, 0x6e50, 0x6e70,
0x6e97, 0x6ebd, 0x6ede, 0x6f00, 0x6f21, 0x6f42, 0x6f63, 0x6f84,
0x6fa5, 0x6fc7, 0x6fe9, 0x700b, 0x702c, 0x704d, 0x706e, 0x708f,
0x70b2, 0x70d3, 0x70f5, 0x7117, 0x7138, 0x7159, 0x717c, 0x71a5,
0x71ce, 0x71ed, 0x720b, 0x722a, 0x7248, 0x7266, 0x7284, 0x72a3,
0x72c1, 0x72df, 0x72fd, 0x731b, 0x733a, 0x7359, 0x7378, 0x7396,
0x73b4, 0x73d2, 0x73f0, 0x740e, 0x742e, 0x744c, 0x746b, 0x748a,
// Entry 7A80 - 7ABF
0x74a9, 0x74c7, 0x74e5, 0x7505, 0x752a, 0x7550, 0x7575, 0x759a,
0x75c0, 0x75e5, 0x760a, 0x762f, 0x7654, 0x767a, 0x76a0, 0x76c6,
0x76eb, 0x7710, 0x7735, 0x775a, 0x777f, 0x77a6, 0x77cb, 0x77f1,
0x7817, 0x783d, 0x7862, 0x7887, 0x78ae, 0x78e5, 0x790e, 0x7924,
0x793b, 0x7951, 0x7968, 0x797f, 0x7998, 0x79b1, 0x79cf, 0x79ed,
0x7a0d, 0x7a2c, 0x7a4b, 0x7a69, 0x7a89, 0x7aa9, 0x7ac8, 0x7ae3,
0x7afe, 0x7b1b, 0x7b37, 0x7b53, 0x7b6e, 0x7b8b, 0x7ba8, 0x7bc4,
0x7bdf, 0x7bfa, 0x7c17, 0x7c33, 0x7c4f, 0x7c6a, 0x7c87, 0x7ca4,
// Entry 7AC0 - 7AFF
0x7cc0, 0x7cd1, 0x7ce4, 0x7cf7, 0x7d11, 0x7d24, 0x7d37, 0x7d4a,
0x7d5d, 0x7d6f, 0x7d80, 0x7d9b, 0x7db7, 0x7dd3, 0x7def, 0x7e0b,
0x7e27, 0x7e43, 0x7e5f, 0x7e7b, 0x7e97, 0x7eb3, 0x7ecf, 0x7eeb,
0x7f07, 0x7f23, 0x7f3f, 0x7f5b, 0x7f77, 0x7f93, 0x7faf, 0x7fcb,
0x7fe7, 0x8003, 0x801f, 0x803b, 0x8057, 0x8073, 0x808f, 0x80ab,
0x80c7, 0x80e3, 0x80ff, 0x811b, 0x8137, 0x8153, 0x816f, 0x818b,
0x81a7, 0x81c3, 0x81df, 0x81fb, 0x8217, 0x8233, 0x824f, 0x826b,
0x8287, 0x82a3, 0x82bf, 0x82db, 0x82f7, 0x8310, 0x832a, 0x8344,
// Entry 7B00 - 7B3F
0x835e, 0x8378, 0x8392, 0x83ac, 0x83c6, 0x83e0, 0x83fa, 0x8414,
0x842e, 0x8448, 0x8462, 0x847c, 0x8496, 0x84b0, 0x84ca, 0x84e4,
0x84fe, 0x8518, 0x8532, 0x854c, 0x8566, 0x8580, 0x859a, 0x85b4,
0x85ce, 0x85e8, 0x8602, 0x861c, 0x8636, 0x8650, 0x866a, 0x8684,
0x869e, 0x86b8, 0x86d2, 0x86ec, 0x8706, 0x8720, 0x873a, 0x8754,
0x876e, 0x8788, 0x87a2, 0x87bc, 0x87d6, 0x87f0, 0x880a, 0x881b,
0x8835, 0x884f, 0x886b, 0x8886, 0x88a1, 0x88bb, 0x88d7, 0x88f3,
0x890e, 0x8928, 0x8943, 0x8960, 0x897c, 0x8997, 0x89b1, 0x89cb,
// Entry 7B40 - 7B7F
0x89e7, 0x8a02, 0x8a1d, 0x8a37, 0x8a53, 0x8a6f, 0x8a8a, 0x8aa4,
0x8abf, 0x8adc, 0x8af8, 0x8b13, 0x8b29, 0x8b45, 0x8b61, 0x8b7f,
0x8b9c, 0x8bb9, 0x8bd5, 0x8bf3, 0x8c11, 0x8c2e, 0x8c4a, 0x8c67,
0x8c86, 0x8ca4, 0x8cc1, 0x8cd9, 0x8cf2, 0x8d0b, 0x8d26, 0x8d40,
0x8d5a, 0x8d73, 0x8d8e, 0x8da9, 0x8dc3, 0x8ddc, 0x8df6, 0x8e12,
0x8e2d, 0x8e47, 0x8e5f, 0x8e70, 0x8e84, 0x8e98, 0x8eac, 0x8ec0,
0x8ed4, 0x8ee8, 0x8efc, 0x8f10, 0x8f24, 0x8f39, 0x8f4e, 0x8f63,
0x8f78, 0x8f8d, 0x8fa2, 0x8fb7, 0x8fcc, 0x8fe1, 0x8ff6, 0x900b,
// Entry 7B80 - 7BBF
0x9020, 0x9034, 0x9044, 0x9053, 0x9062, 0x9073, 0x9083, 0x9093,
0x90a2, 0x90b3, 0x90c4, 0x90d4, 0x90f9, 0x9127, 0x913e, 0x9159,
0x9184, 0x91a8, 0x91cc, 0x91f0, 0x9214, 0x9238, 0x925c, 0x9280,
0x92a4, 0x92c8, 0x92ec, 0x9310, 0x9334, 0x9358, 0x937c, 0x93a0,
0x93c4, 0x93e8, 0x940c, 0x9430, 0x9454, 0x9478, 0x949c, 0x94c0,
0x94e4, 0x9508, 0x952c, 0x955b, 0x9580, 0x95a5, 0x95af, 0x95b9,
0x95c8, 0x95e6, 0x9604, 0x9622, 0x9640, 0x965e, 0x967c, 0x969a,
0x96b8, 0x96d6, 0x96f4, 0x9712, 0x9730, 0x974e, 0x976c, 0x978a,
// Entry 7BC0 - 7BFF
0x97a8, 0x97c6, 0x97e4, 0x9802, 0x9820, 0x983e, 0x985c, 0x987a,
0x9898, 0x98b6, 0x98d4, 0x98de, 0x98e8, 0x98f2, 0x98fc, 0x9907,
0x9911, 0x9938, 0x995f, 0x9986, 0x99ad, 0x99d4, 0x99fb, 0x9a22,
0x9a49, 0x9a70, 0x9a97, 0x9abe, 0x9ae5, 0x9b0c, 0x9b33, 0x9b5a,
0x9b81, 0x9ba8, 0x9bcf, 0x9bf6, 0x9c1d, 0x9c44, 0x9c6b, 0x9c92,
0x9cb9, 0x9ce0, 0x9d07, 0x9d15, 0x9d23, 0x9d31, 0x9d3b, 0x9d5c,
0x9d70, 0x9d97, 0x9dbe, 0x9de5, 0x9e0c, 0x9e33, 0x9e5a, 0x9e81,
0x9ea8, 0x9ecf, 0x9ef6, 0x9f1d, 0x9f44, 0x9f6b, 0x9f92, 0x9fb9,
// Entry 7C00 - 7C3F
0x9fe0, 0xa007, 0xa02e, 0xa055, 0xa07c, 0xa0a3, 0xa0ca, 0xa0f1,
0xa118, 0xa13f, 0xa166, 0xa195, 0xa1a8, 0xa1bb, 0xa1ce, 0xa1e1,
0xa1f4, 0xa1fd, 0xa207, 0xa213, 0xa21f, 0xa229, 0xa234, 0xa23e,
0xa248, 0xa253, 0xa273, 0xa27d, 0xa28c, 0xa2a1, 0xa2ae, 0xa2bc,
0xa2cb, 0xa2e1, 0xa2f8, 0xa314, 0xa323, 0xa33f, 0xa35b, 0xa365,
0xa370, 0xa37e, 0xa38e, 0xa399, 0xa3a4, 0xa3af, 0xa3bf, 0xa3e1,
0xa403, 0xa425, 0xa447, 0xa469, 0xa48b, 0xa4ad, 0xa4cf, 0xa4f1,
0xa513, 0xa535, 0xa557, 0xa579, 0xa59b, 0xa5bd, 0xa5df, 0xa601,
// Entry 7C40 - 7C7F
0xa623, 0xa645, 0xa667, 0xa689, 0xa6ab, 0xa6cd, 0xa6ef, 0xa711,
0xa733, 0xa747, 0xa75c, 0xa76f, 0xa791, 0xa7b3, 0xa7d5, 0xa7e8,
0xa80a, 0xa82c, 0xa84e, 0xa870, 0xa892, 0xa8b4, 0xa8d6, 0xa8f8,
0xa91a, 0xa93c, 0xa95e, 0xa980, 0xa9a2, 0xa9c4, 0xa9e6, 0xaa08,
0xaa2a, 0xaa4c, 0xaa6e, 0xaa90, 0xaab2, 0xaad4, 0xaaf6, 0xab18,
0xab3a, 0xab5c, 0xab7e, 0xaba0, 0xabc2, 0xabe4, 0xac06, 0xac28,
0xac4a, 0xac6c, 0xac8e, 0xacb0, 0xacd2, 0xacf4, 0xad16, 0xad38,
0xad6b, 0xad9e, 0xadd1, 0xae04, 0xae37, 0xae6a, 0xae9d, 0xaed0,
// Entry 7C80 - 7CBF
0xaf03, 0xaf1e, 0xaf36, 0xaf4b, 0xaf60, 0xaf77, 0xaf8c, 0xafa7,
0xafbd, 0xafc4, 0xafc9, 0xafd8, 0xafe8, 0xaffe, 0xb005, 0xb016,
0xb02b, 0xb032, 0xb041, 0xb04b, 0xb052, 0xb05b, 0xb074, 0xb088,
0xb0a2, 0xb0b6, 0xb0c5, 0xb0e0, 0xb0f9, 0xb113, 0xb123, 0xb13d,
0xb155, 0xb170, 0xb17d, 0xb18f, 0xb1ab, 0xb1c6, 0xb1d9, 0xb1e6,
0xb1f2, 0xb1ff, 0xb20a, 0xb217, 0xb220, 0xb23a, 0xb250, 0xb270,
0xb27f, 0xb28e, 0xb2a2, 0xb2b4, 0xb2b7, 0xb2c8, 0xb2cf, 0xb2d3,
0xb2da, 0xb2e2, 0xb2ea, 0xb2f8, 0xb306, 0xb30f, 0xb315, 0xb31f,
// Entry 7CC0 - 7CFF
0xb324, 0xb332, 0xb336, 0xb33e, 0xb347, 0xb34e, 0xb35a, 0xb365,
0xb369, 0xb379, 0xb383, 0xb38e, 0xb3a5, 0xb3ad, 0xb3b3, 0xb3bc,
0xb3c2, 0xb3c7, 0xb3d1, 0xb3da, 0xb3df, 0xb3e5, 0xb3ee, 0xb3f7,
0xb402, 0xb406, 0xb40b, 0xb413, 0xb41d, 0xb426, 0xb434, 0xb440,
0xb44b, 0xb457, 0xb460, 0xb46b, 0xb479, 0xb486, 0xb48f, 0xb494,
0xb4a0, 0xb4b4, 0xb4b9, 0xb4bd, 0xb4c2, 0xb4ce, 0xb4e9, 0xb4f7,
0xb501, 0xb50a, 0xb512, 0xb518, 0xb525, 0xb52a, 0xb532, 0xb539,
0xb542, 0xb54b, 0xb554, 0xb55f, 0xb566, 0xb574, 0xb589, 0xb59c,
// Entry 7D00 - 7D3F
0xb5a6, 0xb5b4, 0xb5c2, 0xb5ca, 0xb5dc, 0xb5e7, 0xb600, 0xb618,
0xb61f, 0xb625, 0xb634, 0xb641, 0xb64f, 0xb65d, 0xb66d, 0xb676,
0xb687, 0xb68e, 0xb69a, 0xb6a7, 0xb6b4, 0xb6c1, 0xb6d0, 0xb6de,
0xb6eb, 0xb6f5, 0xb70a, 0xb718, 0xb726, 0xb740, 0xb752, 0xb760,
0xb76f, 0xb78a, 0xb79b, 0xb7a7, 0xb7b4, 0xb7d2, 0xb7f1, 0xb7fc,
0xb80d, 0xb81b, 0xb827, 0xb835, 0xb84a, 0xb854, 0xb860, 0xb866,
0xb86f, 0xb87d, 0xb884, 0xb88f, 0xb895, 0xb8a2, 0xb8b1, 0xb8bb,
0xb8c5, 0xb8d1, 0xb8da, 0xb8e2, 0xb8e9, 0xb8fd, 0xb909, 0xb91f,
// Entry 7D40 - 7D7F
0xb928, 0xb92e, 0xb93e, 0xb945, 0xb94b, 0xb958, 0xb96f, 0xb986,
0xb996, 0xb9a9, 0xb9b7, 0xb9c2, 0xb9c8, 0xb9ce, 0xb9da, 0xb9e0,
0xb9ec, 0xb9fd, 0xba0b, 0xba12, 0xba1f, 0xba25, 0xba36, 0xba40,
0xba54, 0xba5e, 0xba79, 0xba92, 0xbaae, 0xbac2, 0xbac9, 0xbadc,
0xbaf1, 0xbb00, 0xbb09, 0xbb20, 0xbb32, 0xbb38, 0xbb45, 0xbb52,
0xbb59, 0xbb67, 0xbb78, 0xbb87, 0xbb9b, 0xbbaf, 0xbbb7, 0xbbbb,
0xbbd3, 0xbbd8, 0xbbe2, 0xbbf3, 0xbbf9, 0xbc09, 0xbc10, 0xbc1f,
0xbc2e, 0xbc3d, 0xbc4a, 0xbc57, 0xbc68, 0xbc79, 0xbc80, 0xbc8d,
// Entry 7D80 - 7DBF
0xbc92, 0xbcb3, 0xbcc0, 0xbcc7, 0xbcea, 0xbd0b, 0xbd2c, 0xbd4d,
0xbd6e, 0xbd71, 0xbd76, 0xbd78, 0xbd85, 0xbd88, 0xbd8d, 0xbd94,
0xbd9a, 0xbd9d, 0xbda3, 0xbdac, 0xbdb1, 0xbdb6, 0xbdbb, 0xbdc0,
0xbdc3, 0xbdc7, 0xbdcc, 0xbdd2, 0xbdd9, 0xbde0, 0xbde3, 0xbde6,
0xbdea, 0xbdf2, 0xbdf9, 0xbe05, 0xbe08, 0xbe0b, 0xbe13, 0xbe1e,
0xbe22, 0xbe2f, 0xbe37, 0xbe3d, 0xbe4b, 0xbe55, 0xbe6c, 0xbe70,
0xbe77, 0xbe7c, 0xbe82, 0xbe91, 0xbe9f, 0xbea6, 0xbeb0, 0xbeb8,
0xbec2, 0xbecd, 0xbed5, 0xbee0, 0xbeee, 0xbef8, 0xbf03, 0xbf0b,
// Entry 7DC0 - 7DFF
0xbf13, 0xbf1c, 0xbf28, 0xbf31, 0xbf3a, 0xbf44, 0xbf4c, 0xbf56,
0xbf5e, 0xbf62, 0xbf65, 0xbf68, 0xbf6c, 0xbf71, 0xbf77, 0xbf97,
0xbfb9, 0xbfdb, 0xbffe, 0xc00e, 0xc01e, 0xc02a, 0xc038, 0xc048,
0xc05b, 0xc06a, 0xc06f, 0xc079, 0xc083, 0xc08a, 0xc091, 0xc096,
0xc09b, 0xc0a1, 0xc0a7, 0xc0b5, 0xc0ba, 0xc0c1, 0xc0c6, 0xc0cf,
0xc0dc, 0xc0ec, 0xc0f9, 0xc105, 0xc10f, 0xc121, 0xc134, 0xc137,
0xc13b, 0xc13e, 0xc143, 0xc149, 0xc164, 0xc179, 0xc190, 0xc19e,
0xc1b3, 0xc1c2, 0xc1d8, 0xc1eb, 0xc1fa, 0xc203, 0xc20e, 0xc212,
// Entry 7E00 - 7E3F
0xc225, 0xc22d, 0xc23a, 0xc249, 0xc24e, 0xc258, 0xc26e, 0xc27b,
0xc27e, 0xc283, 0xc29a, 0xc2a3, 0xc2a9, 0xc2b1, 0xc2bc, 0xc2c8,
0xc2cf, 0xc2da, 0xc2e1, 0xc2e5, 0xc2ee, 0xc2f9, 0xc2fd, 0xc306,
0xc30a, 0xc311, 0xc322, 0xc329, 0xc336, 0xc342, 0xc34c, 0xc35b,
0xc368, 0xc378, 0xc382, 0xc38d, 0xc399, 0xc3a5, 0xc3b6, 0xc3c6,
0xc3d6, 0xc3f5, 0xc408, 0xc414, 0xc418, 0xc427, 0xc437, 0xc44d,
0xc454, 0xc45f, 0xc46a, 0xc477, 0xc483, 0xc491, 0xc4a0, 0xc4ac,
0xc4c1, 0xc4ca, 0xc4db, 0xc4ec, 0xc4f7, 0xc50d, 0xc526, 0xc53d,
// Entry 7E40 - 7E7F
0xc555, 0xc565, 0xc58a, 0xc58e, 0xc59f, 0xc5a8, 0xc5b0, 0xc5bb,
0xc5c7, 0xc5ca, 0xc5d5, 0xc5e5, 0xc5f3, 0xc601, 0xc609, 0xc61a,
0xc624, 0xc63c, 0xc656, 0xc65f, 0xc668, 0xc66f, 0xc67c, 0xc685,
0xc693, 0xc6a3, 0xc6b0, 0xc6b6, 0xc6be, 0xc6dc, 0xc6e7, 0xc6f0,
0xc6fa, 0xc703, 0xc70e, 0xc713, 0xc71d, 0xc723, 0xc727, 0xc739,
0xc73e, 0xc749, 0xc75a, 0xc774, 0xc786, 0xc791, 0xc79b, 0xc7a2,
0xc7af, 0xc7c0, 0xc7e3, 0xc803, 0xc822, 0xc83f, 0xc85d, 0xc864,
0xc86f, 0xc878, 0xc884, 0xc8ae, 0xc8bc, 0xc8cc, 0xc8dc, 0xc8ed,
// Entry 7E80 - 7EBF
0xc8f3, 0xc904, 0xc910, 0xc91a, 0xc91f, 0xc92c, 0xc93a, 0xc949,
0xc955, 0xc96e, 0xc9a3, 0xc9f1, 0xca23, 0xca59, 0xca6e, 0xca84,
0xcaa4, 0xcaab, 0xcac6, 0xcae4, 0xcaeb, 0xcaf8, 0xcb16, 0xcb35,
0xcb46, 0xcb5a, 0xcb5d, 0xcb61, 0xcb6a, 0xcb6e, 0xcb8b, 0xcb93,
0xcb9e, 0xcbaa, 0xcbc9, 0xcbe7, 0xcc1b, 0xcc3b, 0xcc57, 0xcc73,
0xcc7d, 0xcca3, 0xccc7, 0xccdf, 0xccf7, 0xcd15, 0xcd19, 0xcd27,
0xcd2d, 0xcd33, 0xcd3f, 0xcd44, 0xcd4a, 0xcd54, 0xcd5d, 0xcd69,
0xcd89, 0xcda5, 0xcdb3, 0xcdc6, 0xcdd9, 0xcde9, 0xcdfa, 0xce0e,
// Entry 7EC0 - 7EFF
0xce20, 0xce34, 0xce46, 0xce5e, 0xce78, 0xce96, 0xceb6, 0xced7,
0xcef8, 0xcf0c, 0xcf2f, 0xcf3b, 0xcf62, 0xcf8a, 0xcfa2, 0xcfb3,
0xcfc4, 0xcfd0, 0xcfd9, 0xcfe6, 0xcfeb, 0xcff1, 0xcffa, 0xd014,
0xd023, 0xd038, 0xd04d, 0xd064, 0xd07a, 0xd090, 0xd0a5, 0xd0bc,
0xd0d3, 0xd0e9, 0xd0fe, 0xd116, 0xd12e, 0xd143, 0xd158, 0xd16f,
0xd185, 0xd19b, 0xd1b0, 0xd1c7, 0xd1de, 0xd1f4, 0xd209, 0xd221,
0xd239, 0xd246, 0xd267, 0xd28b, 0xd293, 0xd2ac, 0xd2b8, 0xd2bc,
0xd2c2, 0xd2d3, 0xd2ed, 0xd2f6, 0xd2fa, 0xd319, 0xd326, 0xd335,
// Entry 7F00 - 7F3F
0xd33b, 0xd345, 0xd34d, 0xd358, 0xd374, 0xd390, 0xd3ad, 0xd3c6,
0xd3df, 0xd3f8, 0xd40e, 0xd41e, 0xd42e, 0xd445, 0xd454, 0xd46d,
0xd47e, 0xd48b, 0xd49c, 0xd4b4, 0xd4cb, 0xd4e0, 0xd4f1, 0xd502,
0xd515, 0xd535, 0xd55e, 0xd575, 0xd58e, 0xd5a3, 0xd5cc, 0xd601,
0xd624, 0xd646, 0xd669, 0xd68b, 0xd6ae, 0xd6d0, 0xd6f3, 0xd713,
0xd735, 0xd755, 0xd777, 0xd797, 0xd7b9, 0xd7c4, 0xd7d4, 0xd7e6,
0xd7ff, 0xd806, 0xd817, 0xd833, 0xd84f, 0xd865, 0xd873, 0xd881,
0xd891, 0xd8a1, 0xd8b3, 0xd8bc, 0xd8d1, 0xd8da, 0xd8e0, 0xd8ec,
// Entry 7F40 - 7F7F
0xd8f4, 0xd905, 0xd917, 0xd935, 0xd94a, 0xd95c, 0xd96c, 0xd97b,
0xd987, 0xd98d, 0xd998, 0xd9ab, 0xd9b8, 0xd9c4, 0xd9ce, 0xd9dd,
0xd9eb, 0xd9ef, 0xd9f8, 0xda00, 0xda0e, 0xda18, 0xda23, 0xda2b,
0xda2f, 0xda34, 0xda3f, 0xda4e, 0xda61, 0xda6f, 0xda77, 0xda7f,
0xda86, 0xdab0, 0xdabe, 0xdad7, 0xdaf0, 0xdafb, 0xdb02, 0xdb15,
0xdb2b, 0xdb36, 0xdb42, 0xdb46, 0xdb61, 0xdb71, 0xdb81, 0xdb90,
0xdba0, 0xdbb2, 0xdbc5, 0xdbd7, 0xdbeb, 0xdbfe, 0xdc12, 0xdc23,
0xdc35, 0xdc40, 0xdc55, 0xdc63, 0xdc79, 0xdc88, 0xdca0, 0xdcb4,
// Entry 7F80 - 7FBF
0xdcd1, 0xdce1, 0xdcfb, 0xdd04, 0xdd0e, 0xdd19, 0xdd2a, 0xdd3d,
0xdd42, 0xdd4f, 0xdd6e, 0xdd84, 0xdda0, 0xddcd, 0xddf8, 0xde2c,
0xde42, 0xde59, 0xde65, 0xde83, 0xdea0, 0xdead, 0xded0, 0xdeec,
0xdef9, 0xdf05, 0xdf18, 0xdf25, 0xdf39, 0xdf45, 0xdf52, 0xdf61,
0xdf6d, 0xdf81, 0xdf9f, 0xdfbc, 0xdfd6, 0xe000, 0xe032, 0xe043,
0xe04f, 0xe059, 0xe065, 0xe070, 0xe080, 0xe099, 0xe0b7, 0xe0d4,
0xe0e2, 0xe0ee, 0xe0f8, 0xe103, 0xe10d, 0xe11b, 0xe12d, 0xe141,
0xe14c, 0xe16f, 0xe185, 0xe194, 0xe1a0, 0xe1ad, 0xe1b7, 0xe1c9,
// Entry 7FC0 - 7FFF
0xe1df, 0xe202, 0xe21c, 0xe23c, 0xe263, 0xe27a, 0xe29b, 0xe2ab,
0xe2ba, 0xe2c8, 0xe2de, 0xe2f3, 0xe303, 0xe319, 0xe332, 0xe346,
0xe35a, 0xe36c, 0xe37f, 0xe393, 0xe3b0, 0xe3d8, 0xe3e7, 0xe3ff,
0xe417, 0xe42f, 0xe447, 0xe45f, 0xe477, 0xe496, 0xe4b5, 0xe4d4,
0xe4f3, 0xe510, 0xe52d, 0xe54a, 0xe567, 0xe58a, 0xe5ad, 0xe5d0,
0xe5f3, 0xe60a, 0xe621, 0xe638, 0xe64f, 0xe66c, 0xe689, 0xe6a6,
0xe6c3, 0xe6df, 0xe70b, 0xe726, 0xe751, 0xe761, 0xe76f, 0xe780,
0xe790, 0xe7ab, 0xe7cc, 0xe7e5, 0xe804, 0xe81c, 0xe834, 0xe870,
// Entry 8000 - 803F
0xe8a5, 0xe8de, 0xe8f8, 0xe917, 0xe93c, 0xe94e, 0xe968, 0xe975,
0xe98a, 0xe990, 0xe99a, 0xe9aa, 0xe9b5, 0xe9c5, 0xe9e6, 0xe9eb,
0xe9f0, 0xe9fa, 0xea01, 0xea05, 0xea0d, 0xea10, 0xea1c, 0xea26,
0xea2e, 0xea35, 0xea3e, 0xea49, 0xea53, 0xea66, 0xea6a, 0xea77,
0xea81, 0xea94, 0xeaa8, 0xeab6, 0xeac7, 0xeace, 0xead6, 0xeae6,
0xeaf8, 0xeb09, 0xeb17, 0xeb1b, 0xeb22, 0xeb2b, 0xeb43, 0xeb59,
0xeb6a, 0xeb85, 0xeb9c, 0xeba0, 0xebad, 0xebbb, 0xebcc, 0xebea,
0xebfe, 0xec12, 0xec2a, 0xec31, 0xec3c, 0xec45, 0xec57, 0xec61,
// Entry 8040 - 807F
0xec6f, 0xec80, 0xec8b, 0xec98, 0xeca0, 0xecab, 0xecb1, 0xecbd,
0xecc3, 0xecc7, 0xecce, 0xecde, 0xece5, 0xecf2, 0xecfe, 0xed1b,
0xed2a, 0xed44, 0xed4f, 0xed5b, 0xed69, 0xed7f, 0xed8c, 0xed98,
0xed9b, 0xedab, 0xedb9, 0xedc9, 0xedce, 0xedd4, 0xede0, 0xede3,
0xedeb, 0xedf3, 0xee03, 0xee08, 0xee11, 0xee22, 0xee28, 0xee30,
0xee38, 0xee45, 0xee4f, 0xee6c, 0xee80, 0xee9a, 0xeea8, 0xeec3,
0xeed5, 0xeee6, 0xeeef, 0xef03, 0xef14, 0xef22, 0xef29, 0xef36,
0xef3b, 0xef3f, 0xef4c, 0xef56, 0xef63, 0xef6f, 0xef7b, 0xef9d,
// Entry 8080 - 80BF
0xefb6, 0xefd0, 0xefeb, 0xf006, 0xf026, 0xf046, 0xf068, 0xf088,
0xf0aa, 0xf0c7, 0xf0e6, 0xf105, 0xf121, 0xf14a, 0xf16c, 0xf193,
0xf1bc, 0xf1e5, 0xf203, 0xf21d, 0xf238, 0xf255, 0xf274, 0xf293,
0xf2b4, 0xf2ce, 0xf2ea, 0xf308, 0xf328, 0xf34c, 0xf371, 0xf391,
0xf3b6, 0xf3df, 0xf405, 0xf42d, 0xf455, 0xf485, 0xf4b6, 0xf4d5,
0xf4f2, 0xf510, 0xf532, 0xf55d, 0xf583, 0xf5b6, 0xf5df, 0xf608,
0xf633, 0xf650, 0xf66f, 0xf68e, 0xf6ad, 0xf6c9, 0xf6e7, 0xf706,
0xf728, 0xf745, 0xf762, 0xf781, 0xf7a2, 0xf7c3, 0xf7df, 0xf7fd,
// Entry 80C0 - 80FF
0xf81d, 0xf838, 0xf855, 0xf872, 0xf88c, 0xf8a5, 0xf8c1, 0xf8df,
0xf8f8, 0xf911, 0xf92d, 0xf947, 0xf962, 0xf985, 0xf9aa, 0xf9c8,
0xf9e5, 0xfa0a, 0xfa29, 0xfa43, 0xfa5e, 0xfa7e, 0xfa99, 0xfab8,
0xfad3, 0xfaf7, 0xfb14, 0xfb3f, 0xfb6c, 0xfb8d, 0xfbae, 0xfbcb,
0xfbe9, 0xfc09, 0xfc25, 0xfc47, 0xfc65, 0xfc85, 0xfca5, 0xfcc5,
0xfce5, 0xfd02, 0xfd24, 0xfd49, 0xfd65, 0xfd7f, 0xfd9a, 0xfdb9,
0xfdd4, 0xfdf3, 0xfe13, 0xfe21, 0xfe2c, 0xfe39, 0xfe3f, 0xfe47,
0xfe4f, 0xfe55, 0xfe5a, 0xfe86, 0xfeb0, 0xfedd, 0xff09, 0xff24,
// Entry 8100 - 813F
0xff3c, 0xff4d, 0xff5f, 0xff76, 0xff92, 0xffbc, 0xffc8, 0xffd9,
0xfff4, 0x0006, 0x0019, 0x002a, 0x003c, 0x0053, 0x006f, 0x009e,
0x00c9, 0x00d6, 0x00e8, 0x0100, 0x011a, 0x014b, 0x0178, 0x0186,
0x0198, 0x01b0, 0x01ca, 0x01f6, 0x0206, 0x0217, 0x0229, 0x0239,
0x024e, 0x0264, 0x027f, 0x028b, 0x0298, 0x02a6, 0x02b2, 0x02bf,
0x02d1, 0x02e8, 0x0302, 0x031d, 0x0336, 0x0350, 0x036f, 0x0393,
0x03ac, 0x03c6, 0x03de, 0x03f7, 0x0415, 0x0438, 0x0453, 0x046f,
0x0489, 0x04a4, 0x04c4, 0x04e2, 0x0501, 0x0519, 0x053b, 0x0558,
// Entry 8140 - 817F
0x0576, 0x058d, 0x05ae, 0x05d6, 0x05f3, 0x0610, 0x062d, 0x0649,
0x0662, 0x0681, 0x069f, 0x06c2, 0x06e3, 0x0702, 0x0721, 0x0743,
0x0753, 0x076c, 0x077a, 0x0791, 0x07a8, 0x07bb, 0x07ce, 0x07e0,
0x07f3, 0x0805, 0x0815, 0x0826, 0x0839, 0x084c, 0x085e, 0x0871,
0x0883, 0x0894, 0x08c1, 0x08ec, 0x091a, 0x0947, 0x0975, 0x09a1,
0x09d0, 0x09fe, 0x0a2b, 0x0a56, 0x0a84, 0x0ab1, 0x0ae1, 0x0b0f,
0x0b40, 0x0b70, 0x0b9a, 0x0bc2, 0x0bed, 0x0c17, 0x0c47, 0x0c75,
0x0ca6, 0x0cd6, 0x0d0c, 0x0d40, 0x0d77, 0x0dad, 0x0dde, 0x0e0d,
// Entry 8180 - 81BF
0x0e3f, 0x0e70, 0x0ea1, 0x0ed0, 0x0f02, 0x0f33, 0x0f62, 0x0f8f,
0x0fbf, 0x0fee, 0x101e, 0x104c, 0x107d, 0x10ad, 0x10e2, 0x1115,
0x114b, 0x1180, 0x119b, 0x11b4, 0x11d0, 0x11eb, 0x1202, 0x1217,
0x122f, 0x1246, 0x1260, 0x1278, 0x1293, 0x12ad, 0x12cd, 0x12eb,
0x130c, 0x132c, 0x1341, 0x1354, 0x136a, 0x137f, 0x1399, 0x13b1,
0x13cc, 0x13e6, 0x1401, 0x141c, 0x1437, 0x1452, 0x146d, 0x1485,
0x14ab, 0x14cf, 0x14f6, 0x151c, 0x1543, 0x156a, 0x1591, 0x15b8,
0x15d8, 0x15f6, 0x1617, 0x1637, 0x1658, 0x1679, 0x169a, 0x16bb,
// Entry 81C0 - 81FF
0x16e2, 0x1707, 0x172f, 0x1756, 0x177e, 0x17a6, 0x17ce, 0x17f6,
0x181c, 0x1840, 0x1867, 0x188d, 0x18b4, 0x18db, 0x1902, 0x1929,
0x1954, 0x197d, 0x19a9, 0x19d4, 0x1a00, 0x1a2c, 0x1a58, 0x1a84,
0x1aa0, 0x1aba, 0x1ad7, 0x1af3, 0x1b22, 0x1b4f, 0x1b7f, 0x1bae,
0x1bcf, 0x1bee, 0x1c10, 0x1c31, 0x1c4c, 0x1c6e, 0x1c8e, 0x1caf,
0x1cd2, 0x1cf6, 0x1d16, 0x1d37, 0x1d58, 0x1d7b, 0x1d9d, 0x1dbf,
0x1de9, 0x1e14, 0x1e3f, 0x1e6b, 0x1e86, 0x1ea8, 0x1ece, 0x1eff,
0x1f22, 0x1f44, 0x1f58, 0x1f77, 0x1f97, 0x1fb5, 0x1fce, 0x1fde,
// Entry 8200 - 823F
0x1ff2, 0x200e, 0x202b, 0x2050, 0x205f, 0x206a, 0x2075, 0x2082,
0x2093, 0x20a3, 0x20b8, 0x20c1, 0x20ce, 0x20e4, 0x20ee, 0x20fa,
0x210b, 0x2117, 0x212a, 0x213a, 0x214b, 0x2154, 0x217e, 0x2192,
0x21a6, 0x21b0, 0x21be, 0x21db, 0x21e8, 0x21f2, 0x21fb, 0x2208,
0x2224, 0x2240, 0x226e, 0x2293, 0x22bb, 0x22f1, 0x230e, 0x232e,
0x233c, 0x234a, 0x235b, 0x2361, 0x2367, 0x2374, 0x2384, 0x2389,
0x239f, 0x23a7, 0x23ad, 0x23be, 0x23c7, 0x23d1, 0x23d9, 0x23e4,
0x23f1, 0x2405, 0x2415, 0x2422, 0x2427, 0x242f, 0x2434, 0x2445,
// Entry 8240 - 827F
0x2457, 0x2468, 0x2474, 0x2488, 0x2495, 0x24ac, 0x24b4, 0x24bf,
0x24c8, 0x24cf, 0x24d7, 0x24dc, 0x24e2, 0x24e8, 0x24f6, 0x2501,
0x2514, 0x2525, 0x2528, 0x2535, 0x253c, 0x2545, 0x254d, 0x2555,
0x2563, 0x256e, 0x2578, 0x2587, 0x2595, 0x259c, 0x25a4, 0x25a7,
0x25ae, 0x25b9, 0x25c1, 0x25cc, 0x25d7, 0x25dc, 0x25e5, 0x25ea,
0x2619, 0x2625, 0x263b, 0x265d, 0x2681, 0x2690, 0x269d, 0x26a2,
0x26b0, 0x26c7, 0x26de, 0x26e2, 0x26ea, 0x26f1, 0x26fc, 0x2705,
0x2709, 0x2712, 0x271a, 0x2720, 0x272c, 0x2731, 0x2735, 0x2738,
// Entry 8280 - 82BF
0x273d, 0x2740, 0x2748, 0x2751, 0x2755, 0x275c, 0x2762, 0x276c,
0x2772, 0x2777, 0x2783, 0x278d, 0x2795, 0x279d, 0x27a2, 0x27a9,
0x27b1, 0x27b6, 0x27bd, 0x27c9, 0x27cf, 0x27d6, 0x27dd, 0x27e5,
0x27ec, 0x27f2, 0x27f6, 0x27fd, 0x2801, 0x2806, 0x280b, 0x2814,
0x2819, 0x2821, 0x2827, 0x282d, 0x2832, 0x2836, 0x283f, 0x284b,
0x2863, 0x287d, 0x2891, 0x28ab, 0x28af, 0x28b2, 0x28b6, 0x28bb,
0x28c4, 0x28d0, 0x28db, 0x28ef, 0x2903, 0x2914, 0x2922, 0x2930,
0x293c, 0x2943, 0x294e, 0x295a, 0x2960, 0x2965, 0x296c, 0x2972,
// Entry 82C0 - 82FF
0x2978, 0x2982, 0x298a, 0x2994, 0x2999, 0x29a8, 0x29b7, 0x29c2,
0x29d3, 0x29d8, 0x29dd, 0x29e8, 0x29f6, 0x2a0b, 0x2a20, 0x2a2f,
0x2a47, 0x2a4b, 0x2a50, 0x2a57, 0x2a60, 0x2a63, 0x2a68, 0x2a6e,
0x2a73, 0x2a7f, 0x2a89, 0x2a8e, 0x2a94, 0x2a98, 0x2a9d, 0x2aae,
0x2ab9, 0x2acc, 0x2ad5, 0x2adf, 0x2aef, 0x2af6, 0x2afc, 0x2b0d,
0x2b14, 0x2b19, 0x2b1f, 0x2b26, 0x2b33, 0x2b42, 0x2b4e, 0x2b58,
0x2b62, 0x2b67, 0x2b6d, 0x2b7a, 0x2b85, 0x2b8b, 0x2b92, 0x2b9e,
0x2bb0, 0x2bc3, 0x2bd5, 0x2be9, 0x2bfd, 0x2c0f, 0x2c3c, 0x2c69,
// Entry 8300 - 833F
0x2c98, 0x2cbf, 0x2ce7, 0x2d0e, 0x2d37, 0x2d60, 0x2d87, 0x2dae,
0x2dd6, 0x2dfd, 0x2e26, 0x2e4f, 0x2e76, 0x2e9f, 0x2ec9, 0x2ef2,
0x2f1d, 0x2f48, 0x2f71, 0x2fab, 0x2fe5, 0x3021, 0x3038, 0x3050,
0x3067, 0x3080, 0x3099, 0x30b0, 0x30c7, 0x30df, 0x30f6, 0x310f,
0x3128, 0x313f, 0x3158, 0x3172, 0x318b, 0x31a6, 0x31c1, 0x31da,
0x3214, 0x324e, 0x328a, 0x32be, 0x32f3, 0x3327, 0x335d, 0x3393,
0x33c7, 0x33fb, 0x3430, 0x3464, 0x349a, 0x34d0, 0x3504, 0x353a,
0x3571, 0x35a7, 0x35df, 0x3617, 0x364d, 0x3685, 0x36bd, 0x36f7,
// Entry 8340 - 837F
0x370d, 0x3723, 0x373b, 0x3768, 0x3795, 0x37c4, 0x37dc, 0x37f3,
0x380c, 0x3824, 0x383b, 0x3854, 0x3867, 0x387b, 0x388f, 0x38a0,
0x38b3, 0x38c5, 0x38d8, 0x38ed, 0x3903, 0x3919, 0x392c, 0x3941,
0x3955, 0x396a, 0x3976, 0x3988, 0x398e, 0x3994, 0x39a0, 0x39b0,
0x39ba, 0x39c4, 0x39d1, 0x39e1, 0x39ec, 0x39f1, 0x39f7, 0x39fc,
0x3a00, 0x3a09, 0x3a12, 0x3a1c, 0x3a22, 0x3a2f, 0x3a36, 0x3a3b,
0x3a48, 0x3a4d, 0x3a52, 0x3a55, 0x3a5e, 0x3a63, 0x3a72, 0x3a7b,
0x3a84, 0x3a88, 0x3a95, 0x3aa0, 0x3aa6, 0x3aaa, 0x3ab0, 0x3ab6,
// Entry 8380 - 83BF
0x3abd, 0x3aca, 0x3ace, 0x3ad4, 0x3ade, 0x3ae8, 0x3af1, 0x3af8,
0x3afc, 0x3b07, 0x3b1a, 0x3b25, 0x3b2a, 0x3b3a, 0x3b43, 0x3b49,
0x3b4c, 0x3b50, 0x3b56, 0x3b5f, 0x3b6b, 0x3b6f, 0x3b76, 0x3b7b,
0x3b80, 0x3b8a, 0x3b98, 0x3ba0, 0x3ba9, 0x3bad, 0x3bb2, 0x3bc2,
0x3bc7, 0x3bd5, 0x3be1, 0x3bf0, 0x3c01, 0x3c06, 0x3c0c, 0x3c17,
0x3c22, 0x3c27, 0x3c30, 0x3c36, 0x3c3c, 0x3c42, 0x3c50, 0x3c55,
0x3c58, 0x3c63, 0x3c6a, 0x3c76, 0x3c83, 0x3caa, 0x3cbf, 0x3cd7,
0x3ce7, 0x3cf1, 0x3cf8, 0x3d04, 0x3d2c, 0x3d3b, 0x3d49, 0x3d57,
// Entry 83C0 - 83FF
0x3d63, 0x3d7f, 0x3d8a, 0x3da0, 0x3db7, 0x3dc6, 0x3dd5, 0x3de5,
0x3df4, 0x3e04, 0x3e14, 0x3e25, 0x3e34, 0x3e44, 0x3e54, 0x3e65,
0x3e75, 0x3e86, 0x3e97, 0x3ea9, 0x3eb8, 0x3ec8, 0x3ed8, 0x3ee9,
0x3ef9, 0x3f0a, 0x3f1c, 0x3f2c, 0x3f3d, 0x3f4e, 0x3f60, 0x3f71,
0x3f83, 0x3f95, 0x3fa8, 0x3fb7, 0x3fc7, 0x3fd7, 0x3fe8, 0x3ff8,
0x4009, 0x401a, 0x402c, 0x403c, 0x404d, 0x405f, 0x4070, 0x4082,
0x4094, 0x40a7, 0x40b7, 0x40c8, 0x40d9, 0x40eb, 0x40fc, 0x410e,
0x4120, 0x4133, 0x4144, 0x4156, 0x4168, 0x417b, 0x418d, 0x41a0,
// Entry 8400 - 843F
0x41b3, 0x41ee, 0x4228, 0x4263, 0x429d, 0x42d1, 0x430d, 0x4348,
0x4384, 0x43bf, 0x43f4, 0x4436, 0x4473, 0x44ae, 0x44eb, 0x4526,
0x455c, 0x4598, 0x45d2, 0x460e, 0x4648, 0x467d, 0x46be, 0x46fa,
0x4735, 0x4771, 0x47ac, 0x47e1, 0x481c, 0x4856, 0x4891, 0x48cb,
0x48ff, 0x4940, 0x497c, 0x49b6, 0x49f2, 0x4a2c, 0x4a61, 0x4a9e,
0x4ad9, 0x4b16, 0x4b51, 0x4b87, 0x4bc9, 0x4c02, 0x4c3a, 0x4c72,
0x4caa, 0x4ccb, 0x4ced, 0x4d0f, 0x4d31, 0x4d4c, 0x4d67, 0x4d82,
0x4d9d, 0x4db8, 0x4dd3, 0x4df0, 0x4e0d, 0x4e2a, 0x4e47, 0x4e64,
// Entry 8440 - 847F
0x4e81, 0x4ea0, 0x4ebf, 0x4edf, 0x4eff, 0x4f1f, 0x4f3f, 0x4f56,
0x4f6f, 0x4f87, 0x4fa1, 0x4fba, 0x4fd1, 0x4fea, 0x5002, 0x501c,
0x5035, 0x504b, 0x5062, 0x5079, 0x5090, 0x50a4, 0x50d8, 0x510c,
0x513f, 0x5151, 0x516b, 0x5180, 0x519e, 0x51bc, 0x51e1, 0x5205,
0x5227, 0x524a, 0x526d, 0x528f, 0x52c6, 0x52fe, 0x5335, 0x536d,
0x53b4, 0x53fc, 0x5443, 0x548a, 0x54e2, 0x553a, 0x5591, 0x55e8,
0x563f, 0x5696, 0x56b9, 0x56eb, 0x5703, 0x5715, 0x572a, 0x5740,
0x576a, 0x579e, 0x57d3, 0x57fd, 0x5825, 0x5835, 0x5846, 0x5858,
// Entry 8480 - 84BF
0x586e, 0x5885, 0x58b3, 0x58cc, 0x58f4, 0x5919, 0x5940, 0x5966,
0x5984, 0x5990, 0x59ad, 0x59c6, 0x59e0, 0x59f7, 0x5a10, 0x5a24,
0x5a37, 0x5a4a, 0x5a5f, 0x5a73, 0x5a87, 0x5a9a, 0x5aaf, 0x5ac4,
0x5ad8, 0x5af9, 0x5b1a, 0x5b3b, 0x5b5c, 0x5b7d, 0x5b9e, 0x5bbf,
0x5be0, 0x5c01, 0x5c22, 0x5c43, 0x5c64, 0x5c85, 0x5ca6, 0x5cc7,
0x5ce8, 0x5d09, 0x5d2a, 0x5d4b, 0x5d6c, 0x5d8d, 0x5dae, 0x5dcf,
0x5df0, 0x5e11, 0x5e32, 0x5e53, 0x5e74, 0x5e95, 0x5eb6, 0x5ed7,
0x5ef8, 0x5f19, 0x5f3a, 0x5f5b, 0x5f7c, 0x5f9d, 0x5fbe, 0x5fdf,
// Entry 84C0 - 84FF
0x6000, 0x6021, 0x6042, 0x6063, 0x6084, 0x60a5, 0x60c6, 0x60e7,
0x6108, 0x6129, 0x614a, 0x616b, 0x618c, 0x61ad, 0x61ce, 0x61ef,
0x6210, 0x6231, 0x6252, 0x6273, 0x6294, 0x62b5, 0x62d6, 0x62f7,
0x6318, 0x6339, 0x635a, 0x637b, 0x639c, 0x63bd, 0x63de, 0x63ff,
0x6420, 0x6441, 0x6462, 0x6483, 0x64a4, 0x64c5, 0x64e6, 0x6507,
0x6528, 0x6549, 0x656a, 0x658b, 0x65ac, 0x65cd, 0x65ee, 0x660f,
0x6630, 0x6651, 0x6672, 0x6693, 0x66b4, 0x66d5, 0x66f6, 0x6717,
0x6738, 0x6759, 0x677a, 0x679b, 0x67bc, 0x67dd, 0x67fe, 0x681f,
// Entry 8500 - 853F
0x6840, 0x6861, 0x6882, 0x68a3, 0x68c4, 0x68e5, 0x6906, 0x6927,
0x6948, 0x6969, 0x698a, 0x69ab, 0x69cc, 0x69ed, 0x6a0e, 0x6a2f,
0x6a50, 0x6a71, 0x6a92, 0x6ab3, 0x6ad4, 0x6af5, 0x6b16, 0x6b37,
0x6b58, 0x6b79, 0x6b9a, 0x6bbb, 0x6bdc, 0x6bfd, 0x6c1e, 0x6c3f,
0x6c60, 0x6c81, 0x6ca2, 0x6cc3, 0x6ce4, 0x6d05, 0x6d26, 0x6d47,
0x6d68, 0x6d89, 0x6daa, 0x6dcb, 0x6dec, 0x6e0d, 0x6e2e, 0x6e4f,
0x6e70, 0x6e91, 0x6eb2, 0x6ed3, 0x6ef4, 0x6f15, 0x6f36, 0x6f57,
0x6f78, 0x6f99, 0x6fba, 0x6fdb, 0x6ffc, 0x701d, 0x703e, 0x705f,
// Entry 8540 - 857F
0x7080, 0x70a1, 0x70c2, 0x70e3, 0x7104, 0x7125, 0x7146, 0x7167,
0x7188, 0x71a9, 0x71ca, 0x71eb, 0x720c, 0x722d, 0x724e, 0x726f,
0x7290, 0x72b1, 0x72d2, 0x72f3, 0x7314, 0x7335, 0x7356, 0x7377,
0x7398, 0x73b9, 0x73da, 0x73fb, 0x741c, 0x743d, 0x745e, 0x747f,
0x74a0, 0x74c1, 0x74e2, 0x7503, 0x7524, 0x7545, 0x7566, 0x7587,
0x75a8, 0x75c9, 0x75ea, 0x760b, 0x762c, 0x764d, 0x766e, 0x768f,
0x76b0, 0x76d1, 0x76f2, 0x7713, 0x7734, 0x7755, 0x7776, 0x7797,
0x77b8, 0x77d9, 0x77fa, 0x781b, 0x783c, 0x785d, 0x787e, 0x789f,
// Entry 8580 - 85BF
0x78c0, 0x78e1, 0x7902, 0x7923, 0x7944, 0x7965, 0x7986, 0x79a7,
0x79c8, 0x79e9, 0x7a0a, 0x7a2b, 0x7a4c, 0x7a6d, 0x7a8e, 0x7aaf,
0x7ad0, 0x7af1, 0x7b12, 0x7b33, 0x7b54, 0x7b75, 0x7b96, 0x7bb7,
0x7bd8, 0x7bf9, 0x7c1a, 0x7c3b, 0x7c5c, 0x7c7d, 0x7c9e, 0x7cbf,
0x7ce0, 0x7d01, 0x7d22, 0x7d43, 0x7d64, 0x7d85, 0x7da6, 0x7dc7,
0x7de8, 0x7e09, 0x7e2a, 0x7e4b, 0x7e6c, 0x7e8d, 0x7eae, 0x7ecf,
0x7ef0, 0x7f11, 0x7f32, 0x7f53, 0x7f74, 0x7f95, 0x7fb6, 0x7fd7,
0x7ff8, 0x8019, 0x803a, 0x805b, 0x807c, 0x809d, 0x80be, 0x80df,
// Entry 85C0 - 85FF
0x8100, 0x8121, 0x8142, 0x8163, 0x8184, 0x81a5, 0x81c6, 0x81e7,
0x8208, 0x8229, 0x824a, 0x826b, 0x828c, 0x82ad, 0x82ce, 0x82ef,
0x8310, 0x8331, 0x8352, 0x8373, 0x8394, 0x83b5, 0x83d6, 0x83f7,
0x8418, 0x8439, 0x845a, 0x847b, 0x849c, 0x84bd, 0x84de, 0x84ff,
0x8520, 0x8541, 0x8562, 0x8583, 0x85a4, 0x85c5, 0x85e6, 0x8607,
0x8628, 0x8649, 0x866a, 0x868b, 0x86ac, 0x86cd, 0x86ee, 0x870f,
0x8730, 0x8751, 0x8772, 0x8793, 0x87b4, 0x87d5, 0x87f6, 0x8817,
0x8838, 0x8859, 0x887a, 0x889b, 0x88bc, 0x88dd, 0x88fe, 0x891f,
// Entry 8600 - 863F
0x8940, 0x8961, 0x8982, 0x89a3, 0x89c4, 0x89e5, 0x8a06, 0x8a27,
0x8a48, 0x8a69, 0x8a8a, 0x8aab, 0x8acc, 0x8aed, 0x8b0e, 0x8b2f,
0x8b50, 0x8b71, 0x8b92, 0x8bb3, 0x8bd4, 0x8bf5, 0x8c16, 0x8c37,
0x8c58, 0x8c79, 0x8c9a, 0x8cbb, 0x8cdc, 0x8cfd, 0x8d1e, 0x8d3f,
0x8d60, 0x8d81, 0x8da2, 0x8dc3, 0x8de4, 0x8e05, 0x8e26, 0x8e47,
0x8e68, 0x8e89, 0x8eaa, 0x8ecb, 0x8eec, 0x8f0d, 0x8f2e, 0x8f4f,
0x8f70, 0x8f91, 0x8fb2, 0x8fd3, 0x8ff4, 0x9015, 0x9036, 0x9057,
0x9078, 0x9099, 0x90ba, 0x90db, 0x90fc, 0x911d, 0x913e, 0x915f,
// Entry 8640 - 867F
0x9180, 0x91a1, 0x91c2, 0x91e3, 0x9204, 0x9225, 0x9246, 0x9267,
0x9288, 0x92a9, 0x92ca, 0x92eb, 0x930c, 0x932d, 0x934e, 0x936f,
0x9390, 0x93b1, 0x93d2, 0x93f3, 0x9414, 0x9435, 0x9456, 0x9477,
0x9498, 0x94b9, 0x94da, 0x94fb, 0x951c, 0x953d, 0x955e, 0x957f,
0x95a0, 0x95c1, 0x95e2, 0x9603, 0x9624, 0x9645, 0x9666, 0x9687,
0x96a8, 0x96c9, 0x96ea, 0x970b, 0x972c, 0x974d, 0x976e, 0x978f,
0x97b0, 0x97d1, 0x97f2, 0x9813, 0x9834, 0x9855, 0x9876, 0x9897,
0x98b8, 0x98d9, 0x98fa, 0x991b, 0x993c, 0x995d, 0x997e, 0x999f,
// Entry 8680 - 86BF
0x99c0, 0x99e1, 0x9a02, 0x9a23, 0x9a44, 0x9a65, 0x9a86, 0x9aa7,
0x9ac8, 0x9ae9, 0x9b0a, 0x9b2b, 0x9b4c, 0x9b6d, 0x9b8e, 0x9baf,
0x9bd0, 0x9bf1, 0x9c12, 0x9c33, 0x9c54, 0x9c75, 0x9c96, 0x9cb7,
0x9cd8, 0x9cf9, 0x9d1a, 0x9d3b, 0x9d5c, 0x9d7d, 0x9d9e, 0x9dbf,
0x9de0, 0x9e01, 0x9e22, 0x9e43, 0x9e64, 0x9e85, 0x9ea6, 0x9ec7,
0x9ee8, 0x9f09, 0x9f2a, 0x9f4b, 0x9f6c, 0x9f8d, 0x9fae, 0x9fcf,
0x9ff0, 0xa011, 0xa032, 0xa053, 0xa074, 0xa095, 0xa0b6, 0xa0c2,
0xa0cb, 0xa0df, 0xa0f1, 0xa100, 0xa10f, 0xa11f, 0xa12c, 0xa13a,
// Entry 86C0 - 86FF
0xa14e, 0xa163, 0xa16f, 0xa17c, 0xa185, 0xa195, 0xa1a2, 0xa1ad,
0xa1bb, 0xa1c8, 0xa1d5, 0xa1e4, 0xa1f2, 0xa200, 0xa20d, 0xa21c,
0xa22b, 0xa239, 0xa242, 0xa24f, 0xa261, 0xa270, 0xa285, 0xa296,
0xa2a7, 0xa2c1, 0xa2db, 0xa2f5, 0xa30f, 0xa329, 0xa343, 0xa35d,
0xa377, 0xa391, 0xa3ab, 0xa3c5, 0xa3df, 0xa3f9, 0xa413, 0xa42d,
0xa447, 0xa461, 0xa47b, 0xa495, 0xa4af, 0xa4c9, 0xa4e3, 0xa4fd,
0xa517, 0xa531, 0xa54b, 0xa562, 0xa575, 0xa58d, 0xa5a2, 0xa5ae,
0xa5be, 0xa5d6, 0xa5ee, 0xa606, 0xa61e, 0xa636, 0xa64e, 0xa666,
// Entry 8700 - 873F
0xa67e, 0xa696, 0xa6ae, 0xa6c6, 0xa6de, 0xa6f6, 0xa70e, 0xa726,
0xa73e, 0xa756, 0xa76e, 0xa786, 0xa79e, 0xa7b6, 0xa7ce, 0xa7e6,
0xa7fe, 0xa816, 0xa82e, 0xa844, 0xa855, 0xa86c, 0xa875, 0xa87f,
0xa894, 0xa8a9, 0xa8be, 0xa8d3, 0xa8e8, 0xa8fd, 0xa912, 0xa927,
0xa93c, 0xa951, 0xa966, 0xa97b, 0xa990, 0xa9a5, 0xa9ba, 0xa9cf,
0xa9e4, 0xa9f9, 0xaa0e, 0xaa23, 0xaa38, 0xaa4d, 0xaa62, 0xaa77,
0xaa8c, 0xaaa1, 0xaab6, 0xaacb, 0xaae0, 0xaaf5, 0xab0a, 0xab1f,
0xab34, 0xab49, 0xab5e, 0xab73, 0xab88, 0xab9d, 0xabb2, 0xabc7,
// Entry 8740 - 877F
0xabdc, 0xabf1, 0xac06, 0xac1b, 0xac30, 0xac45, 0xac5a, 0xac6f,
0xac84, 0xac99, 0xacae, 0xacc3, 0xacd8, 0xaced, 0xad02, 0xad17,
0xad2c, 0xad41, 0xad56, 0xad6b, 0xad80, 0xad95, 0xadaa, 0xadbf,
0xadd4, 0xade9, 0xadfe, 0xae13, 0xae28, 0xae3d, 0xae52, 0xae67,
0xae7c, 0xae91, 0xaea6, 0xaebb, 0xaed0, 0xaee5, 0xaefa, 0xaf0f,
0xaf24, 0xaf39, 0xaf4e, 0xaf64, 0xaf7a, 0xaf90, 0xafa6, 0xafbc,
0xafd2, 0xafe8, 0xaffe, 0xb014, 0xb02a, 0xb040, 0xb056, 0xb06c,
0xb082, 0xb098, 0xb0ae, 0xb0c4, 0xb0da, 0xb0f0, 0xb106, 0xb11c,
// Entry 8780 - 87BF
0xb132, 0xb148, 0xb15e, 0xb174, 0xb18a, 0xb1a0, 0xb1b6, 0xb1cc,
0xb1e2, 0xb1f8, 0xb20e, 0xb224, 0xb23a, 0xb250, 0xb266, 0xb27c,
0xb292, 0xb2a8, 0xb2be, 0xb2d4, 0xb2ea, 0xb300, 0xb316, 0xb32c,
0xb342, 0xb358, 0xb36e, 0xb384, 0xb39a, 0xb3b0, 0xb3c6, 0xb3dc,
0xb3f2, 0xb408, 0xb41e, 0xb434, 0xb44a, 0xb460, 0xb476, 0xb48c,
0xb4a2, 0xb4b8, 0xb4ce, 0xb4e4, 0xb4fa, 0xb510, 0xb526, 0xb53c,
0xb552, 0xb568, 0xb57e, 0xb594, 0xb5aa, 0xb5c0, 0xb5d6, 0xb5ec,
0xb602, 0xb618, 0xb62e, 0xb644, 0xb65a, 0xb670, 0xb686, 0xb69c,
// Entry 87C0 - 87FF
0xb6b2, 0xb6c8, 0xb6de, 0xb6f4, 0xb70a, 0xb720, 0xb736, 0xb74c,
0xb762, 0xb778, 0xb78e, 0xb7a4, 0xb7ba, 0xb7d0, 0xb7e6, 0xb7fc,
0xb812, 0xb828, 0xb83e, 0xb854, 0xb86a, 0xb880, 0xb896, 0xb8ac,
0xb8c2, 0xb8d8, 0xb8ee, 0xb904, 0xb91a, 0xb930, 0xb946, 0xb95c,
0xb972, 0xb988, 0xb99e, 0xb9b4, 0xb9ca, 0xb9e0, 0xb9f6, 0xba0c,
0xba22, 0xba38, 0xba4e, 0xba64, 0xba7a, 0xba90, 0xbaa6, 0xbabc,
0xbad2, 0xbae8, 0xbafe, 0xbb14, 0xbb2a, 0xbb40, 0xbb56, 0xbb6c,
0xbb82, 0xbb98, 0xbbae, 0xbbc4, 0xbbda, 0xbbf0, 0xbc06, 0xbc1c,
// Entry 8800 - 883F
0xbc32, 0xbc48, 0xbc5e, 0xbc74, 0xbc8a, 0xbca0, 0xbcb6, 0xbccc,
} // Size: 69672 bytes
const directData string = "" + // Size: 436 bytes
"<CJK Ideograph Extension A><CJK Ideograph Extension B><CJK Ideograph Ext" +
"ension C><CJK Ideograph Extension D><CJK Ideograph Extension E><CJK Ideo" +
"graph Extension F><CJK Ideograph Extension G><CJK Ideograph Extension H>" +
"<CJK Ideograph><Hangul Syllable><Low Surrogate><Non Private Use High Sur" +
"rogate><Plane 15 Private Use><Plane 16 Private Use><Private Use High Sur" +
"rogate><Private Use><Tangut Ideograph Supplement><Tangut Ideograph><cont" +
"rol>"
const singleData string = ("" + // Size: 900300 bytes; the redundant, explicit parens are for https://golang.org/issue/18078
"SPACEEXCLAMATION MARKQUOTATION MARKNUMBER SIGNDOLLAR SIGNPERCENT SIGNAMP" +
"ERSANDAPOSTROPHELEFT PARENTHESISRIGHT PARENTHESISASTERISKPLUS SIGNCOMMAH" +
"YPHEN-MINUSFULL STOPSOLIDUSDIGIT ZERODIGIT ONEDIGIT TWODIGIT THREEDIGIT " +
"FOURDIGIT FIVEDIGIT SIXDIGIT SEVENDIGIT EIGHTDIGIT NINECOLONSEMICOLONLES" +
"S-THAN SIGNEQUALS SIGNGREATER-THAN SIGNQUESTION MARKCOMMERCIAL ATLATIN C" +
"APITAL LETTER ALATIN CAPITAL LETTER BLATIN CAPITAL LETTER CLATIN CAPITAL" +
" LETTER DLATIN CAPITAL LETTER ELATIN CAPITAL LETTER FLATIN CAPITAL LETTE" +
"R GLATIN CAPITAL LETTER HLATIN CAPITAL LETTER ILATIN CAPITAL LETTER JLAT" +
"IN CAPITAL LETTER KLATIN CAPITAL LETTER LLATIN CAPITAL LETTER MLATIN CAP" +
"ITAL LETTER NLATIN CAPITAL LETTER OLATIN CAPITAL LETTER PLATIN CAPITAL L" +
"ETTER QLATIN CAPITAL LETTER RLATIN CAPITAL LETTER SLATIN CAPITAL LETTER " +
"TLATIN CAPITAL LETTER ULATIN CAPITAL LETTER VLATIN CAPITAL LETTER WLATIN" +
" CAPITAL LETTER XLATIN CAPITAL LETTER YLATIN CAPITAL LETTER ZLEFT SQUARE" +
" BRACKETREVERSE SOLIDUSRIGHT SQUARE BRACKETCIRCUMFLEX ACCENTLOW LINEGRAV" +
"E ACCENTLATIN SMALL LETTER ALATIN SMALL LETTER BLATIN SMALL LETTER CLATI" +
"N SMALL LETTER DLATIN SMALL LETTER ELATIN SMALL LETTER FLATIN SMALL LETT" +
"ER GLATIN SMALL LETTER HLATIN SMALL LETTER ILATIN SMALL LETTER JLATIN SM" +
"ALL LETTER KLATIN SMALL LETTER LLATIN SMALL LETTER MLATIN SMALL LETTER N" +
"LATIN SMALL LETTER OLATIN SMALL LETTER PLATIN SMALL LETTER QLATIN SMALL " +
"LETTER RLATIN SMALL LETTER SLATIN SMALL LETTER TLATIN SMALL LETTER ULATI" +
"N SMALL LETTER VLATIN SMALL LETTER WLATIN SMALL LETTER XLATIN SMALL LETT" +
"ER YLATIN SMALL LETTER ZLEFT CURLY BRACKETVERTICAL LINERIGHT CURLY BRACK" +
"ETTILDENO-BREAK SPACEINVERTED EXCLAMATION MARKCENT SIGNPOUND SIGNCURRENC" +
"Y SIGNYEN SIGNBROKEN BARSECTION SIGNDIAERESISCOPYRIGHT SIGNFEMININE ORDI" +
"NAL INDICATORLEFT-POINTING DOUBLE ANGLE QUOTATION MARKNOT SIGNSOFT HYPHE" +
"NREGISTERED SIGNMACRONDEGREE SIGNPLUS-MINUS SIGNSUPERSCRIPT TWOSUPERSCRI" +
"PT THREEACUTE ACCENTMICRO SIGNPILCROW SIGNMIDDLE DOTCEDILLASUPERSCRIPT O" +
"NEMASCULINE ORDINAL INDICATORRIGHT-POINTING DOUBLE ANGLE QUOTATION MARKV" +
"ULGAR FRACTION ONE QUARTERVULGAR FRACTION ONE HALFVULGAR FRACTION THREE " +
"QUARTERSINVERTED QUESTION MARKLATIN CAPITAL LETTER A WITH GRAVELATIN CAP" +
"ITAL LETTER A WITH ACUTELATIN CAPITAL LETTER A WITH CIRCUMFLEXLATIN CAPI" +
"TAL LETTER A WITH TILDELATIN CAPITAL LETTER A WITH DIAERESISLATIN CAPITA" +
"L LETTER A WITH RING ABOVELATIN CAPITAL LETTER AELATIN CAPITAL LETTER C " +
"WITH CEDILLALATIN CAPITAL LETTER E WITH GRAVELATIN CAPITAL LETTER E WITH" +
" ACUTELATIN CAPITAL LETTER E WITH CIRCUMFLEXLATIN CAPITAL LETTER E WITH " +
"DIAERESISLATIN CAPITAL LETTER I WITH GRAVELATIN CAPITAL LETTER I WITH AC" +
"UTELATIN CAPITAL LETTER I WITH CIRCUMFLEXLATIN CAPITAL LETTER I WITH DIA" +
"ERESISLATIN CAPITAL LETTER ETHLATIN CAPITAL LETTER N WITH TILDELATIN CAP" +
"ITAL LETTER O WITH GRAVELATIN CAPITAL LETTER O WITH ACUTELATIN CAPITAL L" +
"ETTER O WITH CIRCUMFLEXLATIN CAPITAL LETTER O WITH TILDELATIN CAPITAL LE" +
"TTER O WITH DIAERESISMULTIPLICATION SIGNLATIN CAPITAL LETTER O WITH STRO" +
"KELATIN CAPITAL LETTER U WITH GRAVELATIN CAPITAL LETTER U WITH ACUTELATI" +
"N CAPITAL LETTER U WITH CIRCUMFLEXLATIN CAPITAL LETTER U WITH DIAERESISL" +
"ATIN CAPITAL LETTER Y WITH ACUTELATIN CAPITAL LETTER THORNLATIN SMALL LE" +
"TTER SHARP SLATIN SMALL LETTER A WITH GRAVELATIN SMALL LETTER A WITH ACU" +
"TELATIN SMALL LETTER A WITH CIRCUMFLEXLATIN SMALL LETTER A WITH TILDELAT" +
"IN SMALL LETTER A WITH DIAERESISLATIN SMALL LETTER A WITH RING ABOVELATI" +
"N SMALL LETTER AELATIN SMALL LETTER C WITH CEDILLALATIN SMALL LETTER E W" +
"ITH GRAVELATIN SMALL LETTER E WITH ACUTELATIN SMALL LETTER E WITH CIRCUM" +
"FLEXLATIN SMALL LETTER E WITH DIAERESISLATIN SMALL LETTER I WITH GRAVELA" +
"TIN SMALL LETTER I WITH ACUTELATIN SMALL LETTER I WITH CIRCUMFLEXLATIN S" +
"MALL LETTER I WITH DIAERESISLATIN SMALL LETTER ETHLATIN SMALL LETTER N W" +
"ITH TILDELATIN SMALL LETTER O WITH GRAVELATIN SMALL LETTER O WITH ACUTEL" +
"ATIN SMALL LETTER O WITH CIRCUMFLEXLATIN SMALL LETTER O WITH TILDELATIN " +
"SMALL LETTER O WITH DIAERESISDIVISION SIGNLATIN SMALL LETTER O WITH STRO" +
"KELATIN SMALL LETTER U WITH GRAVELATIN SMALL LETTER U WITH ACUTELATIN SM" +
"ALL LETTER U WITH CIRCUMFLEXLATIN SMALL LETTER U WITH DIAERESISLATIN SMA" +
"LL LETTER Y WITH ACUTELATIN SMALL LETTER THORNLATIN SMALL LETTER Y WITH " +
"DIAERESISLATIN CAPITAL LETTER A WITH MACRONLATIN SMALL LETTER A WITH MAC" +
"RONLATIN CAPITAL LETTER A WITH BREVELATIN SMALL LETTER A WITH BREVELATIN" +
" CAPITAL LETTER A WITH OGONEKLATIN SMALL LETTER A WITH OGONEKLATIN CAPIT" +
"AL LETTER C WITH ACUTELATIN SMALL LETTER C WITH ACUTELATIN CAPITAL LETTE" +
"R C WITH CIRCUMFLEXLATIN SMALL LETTER C WITH CIRCUMFLEXLATIN CAPITAL LET") + ("" +
"TER C WITH DOT ABOVELATIN SMALL LETTER C WITH DOT ABOVELATIN CAPITAL LET" +
"TER C WITH CARONLATIN SMALL LETTER C WITH CARONLATIN CAPITAL LETTER D WI" +
"TH CARONLATIN SMALL LETTER D WITH CARONLATIN CAPITAL LETTER D WITH STROK" +
"ELATIN SMALL LETTER D WITH STROKELATIN CAPITAL LETTER E WITH MACRONLATIN" +
" SMALL LETTER E WITH MACRONLATIN CAPITAL LETTER E WITH BREVELATIN SMALL " +
"LETTER E WITH BREVELATIN CAPITAL LETTER E WITH DOT ABOVELATIN SMALL LETT" +
"ER E WITH DOT ABOVELATIN CAPITAL LETTER E WITH OGONEKLATIN SMALL LETTER " +
"E WITH OGONEKLATIN CAPITAL LETTER E WITH CARONLATIN SMALL LETTER E WITH " +
"CARONLATIN CAPITAL LETTER G WITH CIRCUMFLEXLATIN SMALL LETTER G WITH CIR" +
"CUMFLEXLATIN CAPITAL LETTER G WITH BREVELATIN SMALL LETTER G WITH BREVEL" +
"ATIN CAPITAL LETTER G WITH DOT ABOVELATIN SMALL LETTER G WITH DOT ABOVEL" +
"ATIN CAPITAL LETTER G WITH CEDILLALATIN SMALL LETTER G WITH CEDILLALATIN" +
" CAPITAL LETTER H WITH CIRCUMFLEXLATIN SMALL LETTER H WITH CIRCUMFLEXLAT" +
"IN CAPITAL LETTER H WITH STROKELATIN SMALL LETTER H WITH STROKELATIN CAP" +
"ITAL LETTER I WITH TILDELATIN SMALL LETTER I WITH TILDELATIN CAPITAL LET" +
"TER I WITH MACRONLATIN SMALL LETTER I WITH MACRONLATIN CAPITAL LETTER I " +
"WITH BREVELATIN SMALL LETTER I WITH BREVELATIN CAPITAL LETTER I WITH OGO" +
"NEKLATIN SMALL LETTER I WITH OGONEKLATIN CAPITAL LETTER I WITH DOT ABOVE" +
"LATIN SMALL LETTER DOTLESS ILATIN CAPITAL LIGATURE IJLATIN SMALL LIGATUR" +
"E IJLATIN CAPITAL LETTER J WITH CIRCUMFLEXLATIN SMALL LETTER J WITH CIRC" +
"UMFLEXLATIN CAPITAL LETTER K WITH CEDILLALATIN SMALL LETTER K WITH CEDIL" +
"LALATIN SMALL LETTER KRALATIN CAPITAL LETTER L WITH ACUTELATIN SMALL LET" +
"TER L WITH ACUTELATIN CAPITAL LETTER L WITH CEDILLALATIN SMALL LETTER L " +
"WITH CEDILLALATIN CAPITAL LETTER L WITH CARONLATIN SMALL LETTER L WITH C" +
"ARONLATIN CAPITAL LETTER L WITH MIDDLE DOTLATIN SMALL LETTER L WITH MIDD" +
"LE DOTLATIN CAPITAL LETTER L WITH STROKELATIN SMALL LETTER L WITH STROKE" +
"LATIN CAPITAL LETTER N WITH ACUTELATIN SMALL LETTER N WITH ACUTELATIN CA" +
"PITAL LETTER N WITH CEDILLALATIN SMALL LETTER N WITH CEDILLALATIN CAPITA" +
"L LETTER N WITH CARONLATIN SMALL LETTER N WITH CARONLATIN SMALL LETTER N" +
" PRECEDED BY APOSTROPHELATIN CAPITAL LETTER ENGLATIN SMALL LETTER ENGLAT" +
"IN CAPITAL LETTER O WITH MACRONLATIN SMALL LETTER O WITH MACRONLATIN CAP" +
"ITAL LETTER O WITH BREVELATIN SMALL LETTER O WITH BREVELATIN CAPITAL LET" +
"TER O WITH DOUBLE ACUTELATIN SMALL LETTER O WITH DOUBLE ACUTELATIN CAPIT" +
"AL LIGATURE OELATIN SMALL LIGATURE OELATIN CAPITAL LETTER R WITH ACUTELA" +
"TIN SMALL LETTER R WITH ACUTELATIN CAPITAL LETTER R WITH CEDILLALATIN SM" +
"ALL LETTER R WITH CEDILLALATIN CAPITAL LETTER R WITH CARONLATIN SMALL LE" +
"TTER R WITH CARONLATIN CAPITAL LETTER S WITH ACUTELATIN SMALL LETTER S W" +
"ITH ACUTELATIN CAPITAL LETTER S WITH CIRCUMFLEXLATIN SMALL LETTER S WITH" +
" CIRCUMFLEXLATIN CAPITAL LETTER S WITH CEDILLALATIN SMALL LETTER S WITH " +
"CEDILLALATIN CAPITAL LETTER S WITH CARONLATIN SMALL LETTER S WITH CARONL" +
"ATIN CAPITAL LETTER T WITH CEDILLALATIN SMALL LETTER T WITH CEDILLALATIN" +
" CAPITAL LETTER T WITH CARONLATIN SMALL LETTER T WITH CARONLATIN CAPITAL" +
" LETTER T WITH STROKELATIN SMALL LETTER T WITH STROKELATIN CAPITAL LETTE" +
"R U WITH TILDELATIN SMALL LETTER U WITH TILDELATIN CAPITAL LETTER U WITH" +
" MACRONLATIN SMALL LETTER U WITH MACRONLATIN CAPITAL LETTER U WITH BREVE" +
"LATIN SMALL LETTER U WITH BREVELATIN CAPITAL LETTER U WITH RING ABOVELAT" +
"IN SMALL LETTER U WITH RING ABOVELATIN CAPITAL LETTER U WITH DOUBLE ACUT" +
"ELATIN SMALL LETTER U WITH DOUBLE ACUTELATIN CAPITAL LETTER U WITH OGONE" +
"KLATIN SMALL LETTER U WITH OGONEKLATIN CAPITAL LETTER W WITH CIRCUMFLEXL" +
"ATIN SMALL LETTER W WITH CIRCUMFLEXLATIN CAPITAL LETTER Y WITH CIRCUMFLE" +
"XLATIN SMALL LETTER Y WITH CIRCUMFLEXLATIN CAPITAL LETTER Y WITH DIAERES" +
"ISLATIN CAPITAL LETTER Z WITH ACUTELATIN SMALL LETTER Z WITH ACUTELATIN " +
"CAPITAL LETTER Z WITH DOT ABOVELATIN SMALL LETTER Z WITH DOT ABOVELATIN " +
"CAPITAL LETTER Z WITH CARONLATIN SMALL LETTER Z WITH CARONLATIN SMALL LE" +
"TTER LONG SLATIN SMALL LETTER B WITH STROKELATIN CAPITAL LETTER B WITH H" +
"OOKLATIN CAPITAL LETTER B WITH TOPBARLATIN SMALL LETTER B WITH TOPBARLAT" +
"IN CAPITAL LETTER TONE SIXLATIN SMALL LETTER TONE SIXLATIN CAPITAL LETTE" +
"R OPEN OLATIN CAPITAL LETTER C WITH HOOKLATIN SMALL LETTER C WITH HOOKLA" +
"TIN CAPITAL LETTER AFRICAN DLATIN CAPITAL LETTER D WITH HOOKLATIN CAPITA" +
"L LETTER D WITH TOPBARLATIN SMALL LETTER D WITH TOPBARLATIN SMALL LETTER" +
" TURNED DELTALATIN CAPITAL LETTER REVERSED ELATIN CAPITAL LETTER SCHWALA" +
"TIN CAPITAL LETTER OPEN ELATIN CAPITAL LETTER F WITH HOOKLATIN SMALL LET" +
"TER F WITH HOOKLATIN CAPITAL LETTER G WITH HOOKLATIN CAPITAL LETTER GAMM" +
"ALATIN SMALL LETTER HVLATIN CAPITAL LETTER IOTALATIN CAPITAL LETTER I WI") + ("" +
"TH STROKELATIN CAPITAL LETTER K WITH HOOKLATIN SMALL LETTER K WITH HOOKL" +
"ATIN SMALL LETTER L WITH BARLATIN SMALL LETTER LAMBDA WITH STROKELATIN C" +
"APITAL LETTER TURNED MLATIN CAPITAL LETTER N WITH LEFT HOOKLATIN SMALL L" +
"ETTER N WITH LONG RIGHT LEGLATIN CAPITAL LETTER O WITH MIDDLE TILDELATIN" +
" CAPITAL LETTER O WITH HORNLATIN SMALL LETTER O WITH HORNLATIN CAPITAL L" +
"ETTER OILATIN SMALL LETTER OILATIN CAPITAL LETTER P WITH HOOKLATIN SMALL" +
" LETTER P WITH HOOKLATIN LETTER YRLATIN CAPITAL LETTER TONE TWOLATIN SMA" +
"LL LETTER TONE TWOLATIN CAPITAL LETTER ESHLATIN LETTER REVERSED ESH LOOP" +
"LATIN SMALL LETTER T WITH PALATAL HOOKLATIN CAPITAL LETTER T WITH HOOKLA" +
"TIN SMALL LETTER T WITH HOOKLATIN CAPITAL LETTER T WITH RETROFLEX HOOKLA" +
"TIN CAPITAL LETTER U WITH HORNLATIN SMALL LETTER U WITH HORNLATIN CAPITA" +
"L LETTER UPSILONLATIN CAPITAL LETTER V WITH HOOKLATIN CAPITAL LETTER Y W" +
"ITH HOOKLATIN SMALL LETTER Y WITH HOOKLATIN CAPITAL LETTER Z WITH STROKE" +
"LATIN SMALL LETTER Z WITH STROKELATIN CAPITAL LETTER EZHLATIN CAPITAL LE" +
"TTER EZH REVERSEDLATIN SMALL LETTER EZH REVERSEDLATIN SMALL LETTER EZH W" +
"ITH TAILLATIN LETTER TWO WITH STROKELATIN CAPITAL LETTER TONE FIVELATIN " +
"SMALL LETTER TONE FIVELATIN LETTER INVERTED GLOTTAL STOP WITH STROKELATI" +
"N LETTER WYNNLATIN LETTER DENTAL CLICKLATIN LETTER LATERAL CLICKLATIN LE" +
"TTER ALVEOLAR CLICKLATIN LETTER RETROFLEX CLICKLATIN CAPITAL LETTER DZ W" +
"ITH CARONLATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARONLATIN SMAL" +
"L LETTER DZ WITH CARONLATIN CAPITAL LETTER LJLATIN CAPITAL LETTER L WITH" +
" SMALL LETTER JLATIN SMALL LETTER LJLATIN CAPITAL LETTER NJLATIN CAPITAL" +
" LETTER N WITH SMALL LETTER JLATIN SMALL LETTER NJLATIN CAPITAL LETTER A" +
" WITH CARONLATIN SMALL LETTER A WITH CARONLATIN CAPITAL LETTER I WITH CA" +
"RONLATIN SMALL LETTER I WITH CARONLATIN CAPITAL LETTER O WITH CARONLATIN" +
" SMALL LETTER O WITH CARONLATIN CAPITAL LETTER U WITH CARONLATIN SMALL L" +
"ETTER U WITH CARONLATIN CAPITAL LETTER U WITH DIAERESIS AND MACRONLATIN " +
"SMALL LETTER U WITH DIAERESIS AND MACRONLATIN CAPITAL LETTER U WITH DIAE" +
"RESIS AND ACUTELATIN SMALL LETTER U WITH DIAERESIS AND ACUTELATIN CAPITA" +
"L LETTER U WITH DIAERESIS AND CARONLATIN SMALL LETTER U WITH DIAERESIS A" +
"ND CARONLATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVELATIN SMALL LETTE" +
"R U WITH DIAERESIS AND GRAVELATIN SMALL LETTER TURNED ELATIN CAPITAL LET" +
"TER A WITH DIAERESIS AND MACRONLATIN SMALL LETTER A WITH DIAERESIS AND M" +
"ACRONLATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRONLATIN SMALL LETTER " +
"A WITH DOT ABOVE AND MACRONLATIN CAPITAL LETTER AE WITH MACRONLATIN SMAL" +
"L LETTER AE WITH MACRONLATIN CAPITAL LETTER G WITH STROKELATIN SMALL LET" +
"TER G WITH STROKELATIN CAPITAL LETTER G WITH CARONLATIN SMALL LETTER G W" +
"ITH CARONLATIN CAPITAL LETTER K WITH CARONLATIN SMALL LETTER K WITH CARO" +
"NLATIN CAPITAL LETTER O WITH OGONEKLATIN SMALL LETTER O WITH OGONEKLATIN" +
" CAPITAL LETTER O WITH OGONEK AND MACRONLATIN SMALL LETTER O WITH OGONEK" +
" AND MACRONLATIN CAPITAL LETTER EZH WITH CARONLATIN SMALL LETTER EZH WIT" +
"H CARONLATIN SMALL LETTER J WITH CARONLATIN CAPITAL LETTER DZLATIN CAPIT" +
"AL LETTER D WITH SMALL LETTER ZLATIN SMALL LETTER DZLATIN CAPITAL LETTER" +
" G WITH ACUTELATIN SMALL LETTER G WITH ACUTELATIN CAPITAL LETTER HWAIRLA" +
"TIN CAPITAL LETTER WYNNLATIN CAPITAL LETTER N WITH GRAVELATIN SMALL LETT" +
"ER N WITH GRAVELATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTELATIN SMA" +
"LL LETTER A WITH RING ABOVE AND ACUTELATIN CAPITAL LETTER AE WITH ACUTEL" +
"ATIN SMALL LETTER AE WITH ACUTELATIN CAPITAL LETTER O WITH STROKE AND AC" +
"UTELATIN SMALL LETTER O WITH STROKE AND ACUTELATIN CAPITAL LETTER A WITH" +
" DOUBLE GRAVELATIN SMALL LETTER A WITH DOUBLE GRAVELATIN CAPITAL LETTER " +
"A WITH INVERTED BREVELATIN SMALL LETTER A WITH INVERTED BREVELATIN CAPIT" +
"AL LETTER E WITH DOUBLE GRAVELATIN SMALL LETTER E WITH DOUBLE GRAVELATIN" +
" CAPITAL LETTER E WITH INVERTED BREVELATIN SMALL LETTER E WITH INVERTED " +
"BREVELATIN CAPITAL LETTER I WITH DOUBLE GRAVELATIN SMALL LETTER I WITH D" +
"OUBLE GRAVELATIN CAPITAL LETTER I WITH INVERTED BREVELATIN SMALL LETTER " +
"I WITH INVERTED BREVELATIN CAPITAL LETTER O WITH DOUBLE GRAVELATIN SMALL" +
" LETTER O WITH DOUBLE GRAVELATIN CAPITAL LETTER O WITH INVERTED BREVELAT" +
"IN SMALL LETTER O WITH INVERTED BREVELATIN CAPITAL LETTER R WITH DOUBLE " +
"GRAVELATIN SMALL LETTER R WITH DOUBLE GRAVELATIN CAPITAL LETTER R WITH I" +
"NVERTED BREVELATIN SMALL LETTER R WITH INVERTED BREVELATIN CAPITAL LETTE" +
"R U WITH DOUBLE GRAVELATIN SMALL LETTER U WITH DOUBLE GRAVELATIN CAPITAL" +
" LETTER U WITH INVERTED BREVELATIN SMALL LETTER U WITH INVERTED BREVELAT" +
"IN CAPITAL LETTER S WITH COMMA BELOWLATIN SMALL LETTER S WITH COMMA BELO" +
"WLATIN CAPITAL LETTER T WITH COMMA BELOWLATIN SMALL LETTER T WITH COMMA ") + ("" +
"BELOWLATIN CAPITAL LETTER YOGHLATIN SMALL LETTER YOGHLATIN CAPITAL LETTE" +
"R H WITH CARONLATIN SMALL LETTER H WITH CARONLATIN CAPITAL LETTER N WITH" +
" LONG RIGHT LEGLATIN SMALL LETTER D WITH CURLLATIN CAPITAL LETTER OULATI" +
"N SMALL LETTER OULATIN CAPITAL LETTER Z WITH HOOKLATIN SMALL LETTER Z WI" +
"TH HOOKLATIN CAPITAL LETTER A WITH DOT ABOVELATIN SMALL LETTER A WITH DO" +
"T ABOVELATIN CAPITAL LETTER E WITH CEDILLALATIN SMALL LETTER E WITH CEDI" +
"LLALATIN CAPITAL LETTER O WITH DIAERESIS AND MACRONLATIN SMALL LETTER O " +
"WITH DIAERESIS AND MACRONLATIN CAPITAL LETTER O WITH TILDE AND MACRONLAT" +
"IN SMALL LETTER O WITH TILDE AND MACRONLATIN CAPITAL LETTER O WITH DOT A" +
"BOVELATIN SMALL LETTER O WITH DOT ABOVELATIN CAPITAL LETTER O WITH DOT A" +
"BOVE AND MACRONLATIN SMALL LETTER O WITH DOT ABOVE AND MACRONLATIN CAPIT" +
"AL LETTER Y WITH MACRONLATIN SMALL LETTER Y WITH MACRONLATIN SMALL LETTE" +
"R L WITH CURLLATIN SMALL LETTER N WITH CURLLATIN SMALL LETTER T WITH CUR" +
"LLATIN SMALL LETTER DOTLESS JLATIN SMALL LETTER DB DIGRAPHLATIN SMALL LE" +
"TTER QP DIGRAPHLATIN CAPITAL LETTER A WITH STROKELATIN CAPITAL LETTER C " +
"WITH STROKELATIN SMALL LETTER C WITH STROKELATIN CAPITAL LETTER L WITH B" +
"ARLATIN CAPITAL LETTER T WITH DIAGONAL STROKELATIN SMALL LETTER S WITH S" +
"WASH TAILLATIN SMALL LETTER Z WITH SWASH TAILLATIN CAPITAL LETTER GLOTTA" +
"L STOPLATIN SMALL LETTER GLOTTAL STOPLATIN CAPITAL LETTER B WITH STROKEL" +
"ATIN CAPITAL LETTER U BARLATIN CAPITAL LETTER TURNED VLATIN CAPITAL LETT" +
"ER E WITH STROKELATIN SMALL LETTER E WITH STROKELATIN CAPITAL LETTER J W" +
"ITH STROKELATIN SMALL LETTER J WITH STROKELATIN CAPITAL LETTER SMALL Q W" +
"ITH HOOK TAILLATIN SMALL LETTER Q WITH HOOK TAILLATIN CAPITAL LETTER R W" +
"ITH STROKELATIN SMALL LETTER R WITH STROKELATIN CAPITAL LETTER Y WITH ST" +
"ROKELATIN SMALL LETTER Y WITH STROKELATIN SMALL LETTER TURNED ALATIN SMA" +
"LL LETTER ALPHALATIN SMALL LETTER TURNED ALPHALATIN SMALL LETTER B WITH " +
"HOOKLATIN SMALL LETTER OPEN OLATIN SMALL LETTER C WITH CURLLATIN SMALL L" +
"ETTER D WITH TAILLATIN SMALL LETTER D WITH HOOKLATIN SMALL LETTER REVERS" +
"ED ELATIN SMALL LETTER SCHWALATIN SMALL LETTER SCHWA WITH HOOKLATIN SMAL" +
"L LETTER OPEN ELATIN SMALL LETTER REVERSED OPEN ELATIN SMALL LETTER REVE" +
"RSED OPEN E WITH HOOKLATIN SMALL LETTER CLOSED REVERSED OPEN ELATIN SMAL" +
"L LETTER DOTLESS J WITH STROKELATIN SMALL LETTER G WITH HOOKLATIN SMALL " +
"LETTER SCRIPT GLATIN LETTER SMALL CAPITAL GLATIN SMALL LETTER GAMMALATIN" +
" SMALL LETTER RAMS HORNLATIN SMALL LETTER TURNED HLATIN SMALL LETTER H W" +
"ITH HOOKLATIN SMALL LETTER HENG WITH HOOKLATIN SMALL LETTER I WITH STROK" +
"ELATIN SMALL LETTER IOTALATIN LETTER SMALL CAPITAL ILATIN SMALL LETTER L" +
" WITH MIDDLE TILDELATIN SMALL LETTER L WITH BELTLATIN SMALL LETTER L WIT" +
"H RETROFLEX HOOKLATIN SMALL LETTER LEZHLATIN SMALL LETTER TURNED MLATIN " +
"SMALL LETTER TURNED M WITH LONG LEGLATIN SMALL LETTER M WITH HOOKLATIN S" +
"MALL LETTER N WITH LEFT HOOKLATIN SMALL LETTER N WITH RETROFLEX HOOKLATI" +
"N LETTER SMALL CAPITAL NLATIN SMALL LETTER BARRED OLATIN LETTER SMALL CA" +
"PITAL OELATIN SMALL LETTER CLOSED OMEGALATIN SMALL LETTER PHILATIN SMALL" +
" LETTER TURNED RLATIN SMALL LETTER TURNED R WITH LONG LEGLATIN SMALL LET" +
"TER TURNED R WITH HOOKLATIN SMALL LETTER R WITH LONG LEGLATIN SMALL LETT" +
"ER R WITH TAILLATIN SMALL LETTER R WITH FISHHOOKLATIN SMALL LETTER REVER" +
"SED R WITH FISHHOOKLATIN LETTER SMALL CAPITAL RLATIN LETTER SMALL CAPITA" +
"L INVERTED RLATIN SMALL LETTER S WITH HOOKLATIN SMALL LETTER ESHLATIN SM" +
"ALL LETTER DOTLESS J WITH STROKE AND HOOKLATIN SMALL LETTER SQUAT REVERS" +
"ED ESHLATIN SMALL LETTER ESH WITH CURLLATIN SMALL LETTER TURNED TLATIN S" +
"MALL LETTER T WITH RETROFLEX HOOKLATIN SMALL LETTER U BARLATIN SMALL LET" +
"TER UPSILONLATIN SMALL LETTER V WITH HOOKLATIN SMALL LETTER TURNED VLATI" +
"N SMALL LETTER TURNED WLATIN SMALL LETTER TURNED YLATIN LETTER SMALL CAP" +
"ITAL YLATIN SMALL LETTER Z WITH RETROFLEX HOOKLATIN SMALL LETTER Z WITH " +
"CURLLATIN SMALL LETTER EZHLATIN SMALL LETTER EZH WITH CURLLATIN LETTER G" +
"LOTTAL STOPLATIN LETTER PHARYNGEAL VOICED FRICATIVELATIN LETTER INVERTED" +
" GLOTTAL STOPLATIN LETTER STRETCHED CLATIN LETTER BILABIAL CLICKLATIN LE" +
"TTER SMALL CAPITAL BLATIN SMALL LETTER CLOSED OPEN ELATIN LETTER SMALL C" +
"APITAL G WITH HOOKLATIN LETTER SMALL CAPITAL HLATIN SMALL LETTER J WITH " +
"CROSSED-TAILLATIN SMALL LETTER TURNED KLATIN LETTER SMALL CAPITAL LLATIN" +
" SMALL LETTER Q WITH HOOKLATIN LETTER GLOTTAL STOP WITH STROKELATIN LETT" +
"ER REVERSED GLOTTAL STOP WITH STROKELATIN SMALL LETTER DZ DIGRAPHLATIN S" +
"MALL LETTER DEZH DIGRAPHLATIN SMALL LETTER DZ DIGRAPH WITH CURLLATIN SMA" +
"LL LETTER TS DIGRAPHLATIN SMALL LETTER TESH DIGRAPHLATIN SMALL LETTER TC" +
" DIGRAPH WITH CURLLATIN SMALL LETTER FENG DIGRAPHLATIN SMALL LETTER LS D") + ("" +
"IGRAPHLATIN SMALL LETTER LZ DIGRAPHLATIN LETTER BILABIAL PERCUSSIVELATIN" +
" LETTER BIDENTAL PERCUSSIVELATIN SMALL LETTER TURNED H WITH FISHHOOKLATI" +
"N SMALL LETTER TURNED H WITH FISHHOOK AND TAILMODIFIER LETTER SMALL HMOD" +
"IFIER LETTER SMALL H WITH HOOKMODIFIER LETTER SMALL JMODIFIER LETTER SMA" +
"LL RMODIFIER LETTER SMALL TURNED RMODIFIER LETTER SMALL TURNED R WITH HO" +
"OKMODIFIER LETTER SMALL CAPITAL INVERTED RMODIFIER LETTER SMALL WMODIFIE" +
"R LETTER SMALL YMODIFIER LETTER PRIMEMODIFIER LETTER DOUBLE PRIMEMODIFIE" +
"R LETTER TURNED COMMAMODIFIER LETTER APOSTROPHEMODIFIER LETTER REVERSED " +
"COMMAMODIFIER LETTER RIGHT HALF RINGMODIFIER LETTER LEFT HALF RINGMODIFI" +
"ER LETTER GLOTTAL STOPMODIFIER LETTER REVERSED GLOTTAL STOPMODIFIER LETT" +
"ER LEFT ARROWHEADMODIFIER LETTER RIGHT ARROWHEADMODIFIER LETTER UP ARROW" +
"HEADMODIFIER LETTER DOWN ARROWHEADMODIFIER LETTER CIRCUMFLEX ACCENTCARON" +
"MODIFIER LETTER VERTICAL LINEMODIFIER LETTER MACRONMODIFIER LETTER ACUTE" +
" ACCENTMODIFIER LETTER GRAVE ACCENTMODIFIER LETTER LOW VERTICAL LINEMODI" +
"FIER LETTER LOW MACRONMODIFIER LETTER LOW GRAVE ACCENTMODIFIER LETTER LO" +
"W ACUTE ACCENTMODIFIER LETTER TRIANGULAR COLONMODIFIER LETTER HALF TRIAN" +
"GULAR COLONMODIFIER LETTER CENTRED RIGHT HALF RINGMODIFIER LETTER CENTRE" +
"D LEFT HALF RINGMODIFIER LETTER UP TACKMODIFIER LETTER DOWN TACKMODIFIER" +
" LETTER PLUS SIGNMODIFIER LETTER MINUS SIGNBREVEDOT ABOVERING ABOVEOGONE" +
"KSMALL TILDEDOUBLE ACUTE ACCENTMODIFIER LETTER RHOTIC HOOKMODIFIER LETTE" +
"R CROSS ACCENTMODIFIER LETTER SMALL GAMMAMODIFIER LETTER SMALL LMODIFIER" +
" LETTER SMALL SMODIFIER LETTER SMALL XMODIFIER LETTER SMALL REVERSED GLO" +
"TTAL STOPMODIFIER LETTER EXTRA-HIGH TONE BARMODIFIER LETTER HIGH TONE BA" +
"RMODIFIER LETTER MID TONE BARMODIFIER LETTER LOW TONE BARMODIFIER LETTER" +
" EXTRA-LOW TONE BARMODIFIER LETTER YIN DEPARTING TONE MARKMODIFIER LETTE" +
"R YANG DEPARTING TONE MARKMODIFIER LETTER VOICINGMODIFIER LETTER UNASPIR" +
"ATEDMODIFIER LETTER DOUBLE APOSTROPHEMODIFIER LETTER LOW DOWN ARROWHEADM" +
"ODIFIER LETTER LOW UP ARROWHEADMODIFIER LETTER LOW LEFT ARROWHEADMODIFIE" +
"R LETTER LOW RIGHT ARROWHEADMODIFIER LETTER LOW RINGMODIFIER LETTER MIDD" +
"LE GRAVE ACCENTMODIFIER LETTER MIDDLE DOUBLE GRAVE ACCENTMODIFIER LETTER" +
" MIDDLE DOUBLE ACUTE ACCENTMODIFIER LETTER LOW TILDEMODIFIER LETTER RAIS" +
"ED COLONMODIFIER LETTER BEGIN HIGH TONEMODIFIER LETTER END HIGH TONEMODI" +
"FIER LETTER BEGIN LOW TONEMODIFIER LETTER END LOW TONEMODIFIER LETTER SH" +
"ELFMODIFIER LETTER OPEN SHELFMODIFIER LETTER LOW LEFT ARROWCOMBINING GRA" +
"VE ACCENTCOMBINING ACUTE ACCENTCOMBINING CIRCUMFLEX ACCENTCOMBINING TILD" +
"ECOMBINING MACRONCOMBINING OVERLINECOMBINING BREVECOMBINING DOT ABOVECOM" +
"BINING DIAERESISCOMBINING HOOK ABOVECOMBINING RING ABOVECOMBINING DOUBLE" +
" ACUTE ACCENTCOMBINING CARONCOMBINING VERTICAL LINE ABOVECOMBINING DOUBL" +
"E VERTICAL LINE ABOVECOMBINING DOUBLE GRAVE ACCENTCOMBINING CANDRABINDUC" +
"OMBINING INVERTED BREVECOMBINING TURNED COMMA ABOVECOMBINING COMMA ABOVE" +
"COMBINING REVERSED COMMA ABOVECOMBINING COMMA ABOVE RIGHTCOMBINING GRAVE" +
" ACCENT BELOWCOMBINING ACUTE ACCENT BELOWCOMBINING LEFT TACK BELOWCOMBIN" +
"ING RIGHT TACK BELOWCOMBINING LEFT ANGLE ABOVECOMBINING HORNCOMBINING LE" +
"FT HALF RING BELOWCOMBINING UP TACK BELOWCOMBINING DOWN TACK BELOWCOMBIN" +
"ING PLUS SIGN BELOWCOMBINING MINUS SIGN BELOWCOMBINING PALATALIZED HOOK " +
"BELOWCOMBINING RETROFLEX HOOK BELOWCOMBINING DOT BELOWCOMBINING DIAERESI" +
"S BELOWCOMBINING RING BELOWCOMBINING COMMA BELOWCOMBINING CEDILLACOMBINI" +
"NG OGONEKCOMBINING VERTICAL LINE BELOWCOMBINING BRIDGE BELOWCOMBINING IN" +
"VERTED DOUBLE ARCH BELOWCOMBINING CARON BELOWCOMBINING CIRCUMFLEX ACCENT" +
" BELOWCOMBINING BREVE BELOWCOMBINING INVERTED BREVE BELOWCOMBINING TILDE" +
" BELOWCOMBINING MACRON BELOWCOMBINING LOW LINECOMBINING DOUBLE LOW LINEC" +
"OMBINING TILDE OVERLAYCOMBINING SHORT STROKE OVERLAYCOMBINING LONG STROK" +
"E OVERLAYCOMBINING SHORT SOLIDUS OVERLAYCOMBINING LONG SOLIDUS OVERLAYCO" +
"MBINING RIGHT HALF RING BELOWCOMBINING INVERTED BRIDGE BELOWCOMBINING SQ" +
"UARE BELOWCOMBINING SEAGULL BELOWCOMBINING X ABOVECOMBINING VERTICAL TIL" +
"DECOMBINING DOUBLE OVERLINECOMBINING GRAVE TONE MARKCOMBINING ACUTE TONE" +
" MARKCOMBINING GREEK PERISPOMENICOMBINING GREEK KORONISCOMBINING GREEK D" +
"IALYTIKA TONOSCOMBINING GREEK YPOGEGRAMMENICOMBINING BRIDGE ABOVECOMBINI" +
"NG EQUALS SIGN BELOWCOMBINING DOUBLE VERTICAL LINE BELOWCOMBINING LEFT A" +
"NGLE BELOWCOMBINING NOT TILDE ABOVECOMBINING HOMOTHETIC ABOVECOMBINING A" +
"LMOST EQUAL TO ABOVECOMBINING LEFT RIGHT ARROW BELOWCOMBINING UPWARDS AR" +
"ROW BELOWCOMBINING GRAPHEME JOINERCOMBINING RIGHT ARROWHEAD ABOVECOMBINI" +
"NG LEFT HALF RING ABOVECOMBINING FERMATACOMBINING X BELOWCOMBINING LEFT " +
"ARROWHEAD BELOWCOMBINING RIGHT ARROWHEAD BELOWCOMBINING RIGHT ARROWHEAD ") + ("" +
"AND UP ARROWHEAD BELOWCOMBINING RIGHT HALF RING ABOVECOMBINING DOT ABOVE" +
" RIGHTCOMBINING ASTERISK BELOWCOMBINING DOUBLE RING BELOWCOMBINING ZIGZA" +
"G ABOVECOMBINING DOUBLE BREVE BELOWCOMBINING DOUBLE BREVECOMBINING DOUBL" +
"E MACRONCOMBINING DOUBLE MACRON BELOWCOMBINING DOUBLE TILDECOMBINING DOU" +
"BLE INVERTED BREVECOMBINING DOUBLE RIGHTWARDS ARROW BELOWCOMBINING LATIN" +
" SMALL LETTER ACOMBINING LATIN SMALL LETTER ECOMBINING LATIN SMALL LETTE" +
"R ICOMBINING LATIN SMALL LETTER OCOMBINING LATIN SMALL LETTER UCOMBINING" +
" LATIN SMALL LETTER CCOMBINING LATIN SMALL LETTER DCOMBINING LATIN SMALL" +
" LETTER HCOMBINING LATIN SMALL LETTER MCOMBINING LATIN SMALL LETTER RCOM" +
"BINING LATIN SMALL LETTER TCOMBINING LATIN SMALL LETTER VCOMBINING LATIN" +
" SMALL LETTER XGREEK CAPITAL LETTER HETAGREEK SMALL LETTER HETAGREEK CAP" +
"ITAL LETTER ARCHAIC SAMPIGREEK SMALL LETTER ARCHAIC SAMPIGREEK NUMERAL S" +
"IGNGREEK LOWER NUMERAL SIGNGREEK CAPITAL LETTER PAMPHYLIAN DIGAMMAGREEK " +
"SMALL LETTER PAMPHYLIAN DIGAMMAGREEK YPOGEGRAMMENIGREEK SMALL REVERSED L" +
"UNATE SIGMA SYMBOLGREEK SMALL DOTTED LUNATE SIGMA SYMBOLGREEK SMALL REVE" +
"RSED DOTTED LUNATE SIGMA SYMBOLGREEK QUESTION MARKGREEK CAPITAL LETTER Y" +
"OTGREEK TONOSGREEK DIALYTIKA TONOSGREEK CAPITAL LETTER ALPHA WITH TONOSG" +
"REEK ANO TELEIAGREEK CAPITAL LETTER EPSILON WITH TONOSGREEK CAPITAL LETT" +
"ER ETA WITH TONOSGREEK CAPITAL LETTER IOTA WITH TONOSGREEK CAPITAL LETTE" +
"R OMICRON WITH TONOSGREEK CAPITAL LETTER UPSILON WITH TONOSGREEK CAPITAL" +
" LETTER OMEGA WITH TONOSGREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS" +
"GREEK CAPITAL LETTER ALPHAGREEK CAPITAL LETTER BETAGREEK CAPITAL LETTER " +
"GAMMAGREEK CAPITAL LETTER DELTAGREEK CAPITAL LETTER EPSILONGREEK CAPITAL" +
" LETTER ZETAGREEK CAPITAL LETTER ETAGREEK CAPITAL LETTER THETAGREEK CAPI" +
"TAL LETTER IOTAGREEK CAPITAL LETTER KAPPAGREEK CAPITAL LETTER LAMDAGREEK" +
" CAPITAL LETTER MUGREEK CAPITAL LETTER NUGREEK CAPITAL LETTER XIGREEK CA" +
"PITAL LETTER OMICRONGREEK CAPITAL LETTER PIGREEK CAPITAL LETTER RHOGREEK" +
" CAPITAL LETTER SIGMAGREEK CAPITAL LETTER TAUGREEK CAPITAL LETTER UPSILO" +
"NGREEK CAPITAL LETTER PHIGREEK CAPITAL LETTER CHIGREEK CAPITAL LETTER PS" +
"IGREEK CAPITAL LETTER OMEGAGREEK CAPITAL LETTER IOTA WITH DIALYTIKAGREEK" +
" CAPITAL LETTER UPSILON WITH DIALYTIKAGREEK SMALL LETTER ALPHA WITH TONO" +
"SGREEK SMALL LETTER EPSILON WITH TONOSGREEK SMALL LETTER ETA WITH TONOSG" +
"REEK SMALL LETTER IOTA WITH TONOSGREEK SMALL LETTER UPSILON WITH DIALYTI" +
"KA AND TONOSGREEK SMALL LETTER ALPHAGREEK SMALL LETTER BETAGREEK SMALL L" +
"ETTER GAMMAGREEK SMALL LETTER DELTAGREEK SMALL LETTER EPSILONGREEK SMALL" +
" LETTER ZETAGREEK SMALL LETTER ETAGREEK SMALL LETTER THETAGREEK SMALL LE" +
"TTER IOTAGREEK SMALL LETTER KAPPAGREEK SMALL LETTER LAMDAGREEK SMALL LET" +
"TER MUGREEK SMALL LETTER NUGREEK SMALL LETTER XIGREEK SMALL LETTER OMICR" +
"ONGREEK SMALL LETTER PIGREEK SMALL LETTER RHOGREEK SMALL LETTER FINAL SI" +
"GMAGREEK SMALL LETTER SIGMAGREEK SMALL LETTER TAUGREEK SMALL LETTER UPSI" +
"LONGREEK SMALL LETTER PHIGREEK SMALL LETTER CHIGREEK SMALL LETTER PSIGRE" +
"EK SMALL LETTER OMEGAGREEK SMALL LETTER IOTA WITH DIALYTIKAGREEK SMALL L" +
"ETTER UPSILON WITH DIALYTIKAGREEK SMALL LETTER OMICRON WITH TONOSGREEK S" +
"MALL LETTER UPSILON WITH TONOSGREEK SMALL LETTER OMEGA WITH TONOSGREEK C" +
"APITAL KAI SYMBOLGREEK BETA SYMBOLGREEK THETA SYMBOLGREEK UPSILON WITH H" +
"OOK SYMBOLGREEK UPSILON WITH ACUTE AND HOOK SYMBOLGREEK UPSILON WITH DIA" +
"ERESIS AND HOOK SYMBOLGREEK PHI SYMBOLGREEK PI SYMBOLGREEK KAI SYMBOLGRE" +
"EK LETTER ARCHAIC KOPPAGREEK SMALL LETTER ARCHAIC KOPPAGREEK LETTER STIG" +
"MAGREEK SMALL LETTER STIGMAGREEK LETTER DIGAMMAGREEK SMALL LETTER DIGAMM" +
"AGREEK LETTER KOPPAGREEK SMALL LETTER KOPPAGREEK LETTER SAMPIGREEK SMALL" +
" LETTER SAMPICOPTIC CAPITAL LETTER SHEICOPTIC SMALL LETTER SHEICOPTIC CA" +
"PITAL LETTER FEICOPTIC SMALL LETTER FEICOPTIC CAPITAL LETTER KHEICOPTIC " +
"SMALL LETTER KHEICOPTIC CAPITAL LETTER HORICOPTIC SMALL LETTER HORICOPTI" +
"C CAPITAL LETTER GANGIACOPTIC SMALL LETTER GANGIACOPTIC CAPITAL LETTER S" +
"HIMACOPTIC SMALL LETTER SHIMACOPTIC CAPITAL LETTER DEICOPTIC SMALL LETTE" +
"R DEIGREEK KAPPA SYMBOLGREEK RHO SYMBOLGREEK LUNATE SIGMA SYMBOLGREEK LE" +
"TTER YOTGREEK CAPITAL THETA SYMBOLGREEK LUNATE EPSILON SYMBOLGREEK REVER" +
"SED LUNATE EPSILON SYMBOLGREEK CAPITAL LETTER SHOGREEK SMALL LETTER SHOG" +
"REEK CAPITAL LUNATE SIGMA SYMBOLGREEK CAPITAL LETTER SANGREEK SMALL LETT" +
"ER SANGREEK RHO WITH STROKE SYMBOLGREEK CAPITAL REVERSED LUNATE SIGMA SY" +
"MBOLGREEK CAPITAL DOTTED LUNATE SIGMA SYMBOLGREEK CAPITAL REVERSED DOTTE" +
"D LUNATE SIGMA SYMBOLCYRILLIC CAPITAL LETTER IE WITH GRAVECYRILLIC CAPIT" +
"AL LETTER IOCYRILLIC CAPITAL LETTER DJECYRILLIC CAPITAL LETTER GJECYRILL" +
"IC CAPITAL LETTER UKRAINIAN IECYRILLIC CAPITAL LETTER DZECYRILLIC CAPITA") + ("" +
"L LETTER BYELORUSSIAN-UKRAINIAN ICYRILLIC CAPITAL LETTER YICYRILLIC CAPI" +
"TAL LETTER JECYRILLIC CAPITAL LETTER LJECYRILLIC CAPITAL LETTER NJECYRIL" +
"LIC CAPITAL LETTER TSHECYRILLIC CAPITAL LETTER KJECYRILLIC CAPITAL LETTE" +
"R I WITH GRAVECYRILLIC CAPITAL LETTER SHORT UCYRILLIC CAPITAL LETTER DZH" +
"ECYRILLIC CAPITAL LETTER ACYRILLIC CAPITAL LETTER BECYRILLIC CAPITAL LET" +
"TER VECYRILLIC CAPITAL LETTER GHECYRILLIC CAPITAL LETTER DECYRILLIC CAPI" +
"TAL LETTER IECYRILLIC CAPITAL LETTER ZHECYRILLIC CAPITAL LETTER ZECYRILL" +
"IC CAPITAL LETTER ICYRILLIC CAPITAL LETTER SHORT ICYRILLIC CAPITAL LETTE" +
"R KACYRILLIC CAPITAL LETTER ELCYRILLIC CAPITAL LETTER EMCYRILLIC CAPITAL" +
" LETTER ENCYRILLIC CAPITAL LETTER OCYRILLIC CAPITAL LETTER PECYRILLIC CA" +
"PITAL LETTER ERCYRILLIC CAPITAL LETTER ESCYRILLIC CAPITAL LETTER TECYRIL" +
"LIC CAPITAL LETTER UCYRILLIC CAPITAL LETTER EFCYRILLIC CAPITAL LETTER HA" +
"CYRILLIC CAPITAL LETTER TSECYRILLIC CAPITAL LETTER CHECYRILLIC CAPITAL L" +
"ETTER SHACYRILLIC CAPITAL LETTER SHCHACYRILLIC CAPITAL LETTER HARD SIGNC" +
"YRILLIC CAPITAL LETTER YERUCYRILLIC CAPITAL LETTER SOFT SIGNCYRILLIC CAP" +
"ITAL LETTER ECYRILLIC CAPITAL LETTER YUCYRILLIC CAPITAL LETTER YACYRILLI" +
"C SMALL LETTER ACYRILLIC SMALL LETTER BECYRILLIC SMALL LETTER VECYRILLIC" +
" SMALL LETTER GHECYRILLIC SMALL LETTER DECYRILLIC SMALL LETTER IECYRILLI" +
"C SMALL LETTER ZHECYRILLIC SMALL LETTER ZECYRILLIC SMALL LETTER ICYRILLI" +
"C SMALL LETTER SHORT ICYRILLIC SMALL LETTER KACYRILLIC SMALL LETTER ELCY" +
"RILLIC SMALL LETTER EMCYRILLIC SMALL LETTER ENCYRILLIC SMALL LETTER OCYR" +
"ILLIC SMALL LETTER PECYRILLIC SMALL LETTER ERCYRILLIC SMALL LETTER ESCYR" +
"ILLIC SMALL LETTER TECYRILLIC SMALL LETTER UCYRILLIC SMALL LETTER EFCYRI" +
"LLIC SMALL LETTER HACYRILLIC SMALL LETTER TSECYRILLIC SMALL LETTER CHECY" +
"RILLIC SMALL LETTER SHACYRILLIC SMALL LETTER SHCHACYRILLIC SMALL LETTER " +
"HARD SIGNCYRILLIC SMALL LETTER YERUCYRILLIC SMALL LETTER SOFT SIGNCYRILL" +
"IC SMALL LETTER ECYRILLIC SMALL LETTER YUCYRILLIC SMALL LETTER YACYRILLI" +
"C SMALL LETTER IE WITH GRAVECYRILLIC SMALL LETTER IOCYRILLIC SMALL LETTE" +
"R DJECYRILLIC SMALL LETTER GJECYRILLIC SMALL LETTER UKRAINIAN IECYRILLIC" +
" SMALL LETTER DZECYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN ICYRILLIC " +
"SMALL LETTER YICYRILLIC SMALL LETTER JECYRILLIC SMALL LETTER LJECYRILLIC" +
" SMALL LETTER NJECYRILLIC SMALL LETTER TSHECYRILLIC SMALL LETTER KJECYRI" +
"LLIC SMALL LETTER I WITH GRAVECYRILLIC SMALL LETTER SHORT UCYRILLIC SMAL" +
"L LETTER DZHECYRILLIC CAPITAL LETTER OMEGACYRILLIC SMALL LETTER OMEGACYR" +
"ILLIC CAPITAL LETTER YATCYRILLIC SMALL LETTER YATCYRILLIC CAPITAL LETTER" +
" IOTIFIED ECYRILLIC SMALL LETTER IOTIFIED ECYRILLIC CAPITAL LETTER LITTL" +
"E YUSCYRILLIC SMALL LETTER LITTLE YUSCYRILLIC CAPITAL LETTER IOTIFIED LI" +
"TTLE YUSCYRILLIC SMALL LETTER IOTIFIED LITTLE YUSCYRILLIC CAPITAL LETTER" +
" BIG YUSCYRILLIC SMALL LETTER BIG YUSCYRILLIC CAPITAL LETTER IOTIFIED BI" +
"G YUSCYRILLIC SMALL LETTER IOTIFIED BIG YUSCYRILLIC CAPITAL LETTER KSICY" +
"RILLIC SMALL LETTER KSICYRILLIC CAPITAL LETTER PSICYRILLIC SMALL LETTER " +
"PSICYRILLIC CAPITAL LETTER FITACYRILLIC SMALL LETTER FITACYRILLIC CAPITA" +
"L LETTER IZHITSACYRILLIC SMALL LETTER IZHITSACYRILLIC CAPITAL LETTER IZH" +
"ITSA WITH DOUBLE GRAVE ACCENTCYRILLIC SMALL LETTER IZHITSA WITH DOUBLE G" +
"RAVE ACCENTCYRILLIC CAPITAL LETTER UKCYRILLIC SMALL LETTER UKCYRILLIC CA" +
"PITAL LETTER ROUND OMEGACYRILLIC SMALL LETTER ROUND OMEGACYRILLIC CAPITA" +
"L LETTER OMEGA WITH TITLOCYRILLIC SMALL LETTER OMEGA WITH TITLOCYRILLIC " +
"CAPITAL LETTER OTCYRILLIC SMALL LETTER OTCYRILLIC CAPITAL LETTER KOPPACY" +
"RILLIC SMALL LETTER KOPPACYRILLIC THOUSANDS SIGNCOMBINING CYRILLIC TITLO" +
"COMBINING CYRILLIC PALATALIZATIONCOMBINING CYRILLIC DASIA PNEUMATACOMBIN" +
"ING CYRILLIC PSILI PNEUMATACOMBINING CYRILLIC POKRYTIECOMBINING CYRILLIC" +
" HUNDRED THOUSANDS SIGNCOMBINING CYRILLIC MILLIONS SIGNCYRILLIC CAPITAL " +
"LETTER SHORT I WITH TAILCYRILLIC SMALL LETTER SHORT I WITH TAILCYRILLIC " +
"CAPITAL LETTER SEMISOFT SIGNCYRILLIC SMALL LETTER SEMISOFT SIGNCYRILLIC " +
"CAPITAL LETTER ER WITH TICKCYRILLIC SMALL LETTER ER WITH TICKCYRILLIC CA" +
"PITAL LETTER GHE WITH UPTURNCYRILLIC SMALL LETTER GHE WITH UPTURNCYRILLI" +
"C CAPITAL LETTER GHE WITH STROKECYRILLIC SMALL LETTER GHE WITH STROKECYR" +
"ILLIC CAPITAL LETTER GHE WITH MIDDLE HOOKCYRILLIC SMALL LETTER GHE WITH " +
"MIDDLE HOOKCYRILLIC CAPITAL LETTER ZHE WITH DESCENDERCYRILLIC SMALL LETT" +
"ER ZHE WITH DESCENDERCYRILLIC CAPITAL LETTER ZE WITH DESCENDERCYRILLIC S" +
"MALL LETTER ZE WITH DESCENDERCYRILLIC CAPITAL LETTER KA WITH DESCENDERCY" +
"RILLIC SMALL LETTER KA WITH DESCENDERCYRILLIC CAPITAL LETTER KA WITH VER" +
"TICAL STROKECYRILLIC SMALL LETTER KA WITH VERTICAL STROKECYRILLIC CAPITA" +
"L LETTER KA WITH STROKECYRILLIC SMALL LETTER KA WITH STROKECYRILLIC CAPI") + ("" +
"TAL LETTER BASHKIR KACYRILLIC SMALL LETTER BASHKIR KACYRILLIC CAPITAL LE" +
"TTER EN WITH DESCENDERCYRILLIC SMALL LETTER EN WITH DESCENDERCYRILLIC CA" +
"PITAL LIGATURE EN GHECYRILLIC SMALL LIGATURE EN GHECYRILLIC CAPITAL LETT" +
"ER PE WITH MIDDLE HOOKCYRILLIC SMALL LETTER PE WITH MIDDLE HOOKCYRILLIC " +
"CAPITAL LETTER ABKHASIAN HACYRILLIC SMALL LETTER ABKHASIAN HACYRILLIC CA" +
"PITAL LETTER ES WITH DESCENDERCYRILLIC SMALL LETTER ES WITH DESCENDERCYR" +
"ILLIC CAPITAL LETTER TE WITH DESCENDERCYRILLIC SMALL LETTER TE WITH DESC" +
"ENDERCYRILLIC CAPITAL LETTER STRAIGHT UCYRILLIC SMALL LETTER STRAIGHT UC" +
"YRILLIC CAPITAL LETTER STRAIGHT U WITH STROKECYRILLIC SMALL LETTER STRAI" +
"GHT U WITH STROKECYRILLIC CAPITAL LETTER HA WITH DESCENDERCYRILLIC SMALL" +
" LETTER HA WITH DESCENDERCYRILLIC CAPITAL LIGATURE TE TSECYRILLIC SMALL " +
"LIGATURE TE TSECYRILLIC CAPITAL LETTER CHE WITH DESCENDERCYRILLIC SMALL " +
"LETTER CHE WITH DESCENDERCYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROK" +
"ECYRILLIC SMALL LETTER CHE WITH VERTICAL STROKECYRILLIC CAPITAL LETTER S" +
"HHACYRILLIC SMALL LETTER SHHACYRILLIC CAPITAL LETTER ABKHASIAN CHECYRILL" +
"IC SMALL LETTER ABKHASIAN CHECYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH " +
"DESCENDERCYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDERCYRILLIC LETT" +
"ER PALOCHKACYRILLIC CAPITAL LETTER ZHE WITH BREVECYRILLIC SMALL LETTER Z" +
"HE WITH BREVECYRILLIC CAPITAL LETTER KA WITH HOOKCYRILLIC SMALL LETTER K" +
"A WITH HOOKCYRILLIC CAPITAL LETTER EL WITH TAILCYRILLIC SMALL LETTER EL " +
"WITH TAILCYRILLIC CAPITAL LETTER EN WITH HOOKCYRILLIC SMALL LETTER EN WI" +
"TH HOOKCYRILLIC CAPITAL LETTER EN WITH TAILCYRILLIC SMALL LETTER EN WITH" +
" TAILCYRILLIC CAPITAL LETTER KHAKASSIAN CHECYRILLIC SMALL LETTER KHAKASS" +
"IAN CHECYRILLIC CAPITAL LETTER EM WITH TAILCYRILLIC SMALL LETTER EM WITH" +
" TAILCYRILLIC SMALL LETTER PALOCHKACYRILLIC CAPITAL LETTER A WITH BREVEC" +
"YRILLIC SMALL LETTER A WITH BREVECYRILLIC CAPITAL LETTER A WITH DIAERESI" +
"SCYRILLIC SMALL LETTER A WITH DIAERESISCYRILLIC CAPITAL LIGATURE A IECYR" +
"ILLIC SMALL LIGATURE A IECYRILLIC CAPITAL LETTER IE WITH BREVECYRILLIC S" +
"MALL LETTER IE WITH BREVECYRILLIC CAPITAL LETTER SCHWACYRILLIC SMALL LET" +
"TER SCHWACYRILLIC CAPITAL LETTER SCHWA WITH DIAERESISCYRILLIC SMALL LETT" +
"ER SCHWA WITH DIAERESISCYRILLIC CAPITAL LETTER ZHE WITH DIAERESISCYRILLI" +
"C SMALL LETTER ZHE WITH DIAERESISCYRILLIC CAPITAL LETTER ZE WITH DIAERES" +
"ISCYRILLIC SMALL LETTER ZE WITH DIAERESISCYRILLIC CAPITAL LETTER ABKHASI" +
"AN DZECYRILLIC SMALL LETTER ABKHASIAN DZECYRILLIC CAPITAL LETTER I WITH " +
"MACRONCYRILLIC SMALL LETTER I WITH MACRONCYRILLIC CAPITAL LETTER I WITH " +
"DIAERESISCYRILLIC SMALL LETTER I WITH DIAERESISCYRILLIC CAPITAL LETTER O" +
" WITH DIAERESISCYRILLIC SMALL LETTER O WITH DIAERESISCYRILLIC CAPITAL LE" +
"TTER BARRED OCYRILLIC SMALL LETTER BARRED OCYRILLIC CAPITAL LETTER BARRE" +
"D O WITH DIAERESISCYRILLIC SMALL LETTER BARRED O WITH DIAERESISCYRILLIC " +
"CAPITAL LETTER E WITH DIAERESISCYRILLIC SMALL LETTER E WITH DIAERESISCYR" +
"ILLIC CAPITAL LETTER U WITH MACRONCYRILLIC SMALL LETTER U WITH MACRONCYR" +
"ILLIC CAPITAL LETTER U WITH DIAERESISCYRILLIC SMALL LETTER U WITH DIAERE" +
"SISCYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTECYRILLIC SMALL LETTER U WI" +
"TH DOUBLE ACUTECYRILLIC CAPITAL LETTER CHE WITH DIAERESISCYRILLIC SMALL " +
"LETTER CHE WITH DIAERESISCYRILLIC CAPITAL LETTER GHE WITH DESCENDERCYRIL" +
"LIC SMALL LETTER GHE WITH DESCENDERCYRILLIC CAPITAL LETTER YERU WITH DIA" +
"ERESISCYRILLIC SMALL LETTER YERU WITH DIAERESISCYRILLIC CAPITAL LETTER G" +
"HE WITH STROKE AND HOOKCYRILLIC SMALL LETTER GHE WITH STROKE AND HOOKCYR" +
"ILLIC CAPITAL LETTER HA WITH HOOKCYRILLIC SMALL LETTER HA WITH HOOKCYRIL" +
"LIC CAPITAL LETTER HA WITH STROKECYRILLIC SMALL LETTER HA WITH STROKECYR" +
"ILLIC CAPITAL LETTER KOMI DECYRILLIC SMALL LETTER KOMI DECYRILLIC CAPITA" +
"L LETTER KOMI DJECYRILLIC SMALL LETTER KOMI DJECYRILLIC CAPITAL LETTER K" +
"OMI ZJECYRILLIC SMALL LETTER KOMI ZJECYRILLIC CAPITAL LETTER KOMI DZJECY" +
"RILLIC SMALL LETTER KOMI DZJECYRILLIC CAPITAL LETTER KOMI LJECYRILLIC SM" +
"ALL LETTER KOMI LJECYRILLIC CAPITAL LETTER KOMI NJECYRILLIC SMALL LETTER" +
" KOMI NJECYRILLIC CAPITAL LETTER KOMI SJECYRILLIC SMALL LETTER KOMI SJEC" +
"YRILLIC CAPITAL LETTER KOMI TJECYRILLIC SMALL LETTER KOMI TJECYRILLIC CA" +
"PITAL LETTER REVERSED ZECYRILLIC SMALL LETTER REVERSED ZECYRILLIC CAPITA" +
"L LETTER EL WITH HOOKCYRILLIC SMALL LETTER EL WITH HOOKCYRILLIC CAPITAL " +
"LETTER LHACYRILLIC SMALL LETTER LHACYRILLIC CAPITAL LETTER RHACYRILLIC S" +
"MALL LETTER RHACYRILLIC CAPITAL LETTER YAECYRILLIC SMALL LETTER YAECYRIL" +
"LIC CAPITAL LETTER QACYRILLIC SMALL LETTER QACYRILLIC CAPITAL LETTER WEC" +
"YRILLIC SMALL LETTER WECYRILLIC CAPITAL LETTER ALEUT KACYRILLIC SMALL LE" +
"TTER ALEUT KACYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOKCYRILLIC SMALL L") + ("" +
"ETTER EL WITH MIDDLE HOOKCYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOKCYRI" +
"LLIC SMALL LETTER EN WITH MIDDLE HOOKCYRILLIC CAPITAL LETTER PE WITH DES" +
"CENDERCYRILLIC SMALL LETTER PE WITH DESCENDERCYRILLIC CAPITAL LETTER SHH" +
"A WITH DESCENDERCYRILLIC SMALL LETTER SHHA WITH DESCENDERCYRILLIC CAPITA" +
"L LETTER EN WITH LEFT HOOKCYRILLIC SMALL LETTER EN WITH LEFT HOOKCYRILLI" +
"C CAPITAL LETTER DZZHECYRILLIC SMALL LETTER DZZHECYRILLIC CAPITAL LETTER" +
" DCHECYRILLIC SMALL LETTER DCHECYRILLIC CAPITAL LETTER EL WITH DESCENDER" +
"CYRILLIC SMALL LETTER EL WITH DESCENDERARMENIAN CAPITAL LETTER AYBARMENI" +
"AN CAPITAL LETTER BENARMENIAN CAPITAL LETTER GIMARMENIAN CAPITAL LETTER " +
"DAARMENIAN CAPITAL LETTER ECHARMENIAN CAPITAL LETTER ZAARMENIAN CAPITAL " +
"LETTER EHARMENIAN CAPITAL LETTER ETARMENIAN CAPITAL LETTER TOARMENIAN CA" +
"PITAL LETTER ZHEARMENIAN CAPITAL LETTER INIARMENIAN CAPITAL LETTER LIWNA" +
"RMENIAN CAPITAL LETTER XEHARMENIAN CAPITAL LETTER CAARMENIAN CAPITAL LET" +
"TER KENARMENIAN CAPITAL LETTER HOARMENIAN CAPITAL LETTER JAARMENIAN CAPI" +
"TAL LETTER GHADARMENIAN CAPITAL LETTER CHEHARMENIAN CAPITAL LETTER MENAR" +
"MENIAN CAPITAL LETTER YIARMENIAN CAPITAL LETTER NOWARMENIAN CAPITAL LETT" +
"ER SHAARMENIAN CAPITAL LETTER VOARMENIAN CAPITAL LETTER CHAARMENIAN CAPI" +
"TAL LETTER PEHARMENIAN CAPITAL LETTER JHEHARMENIAN CAPITAL LETTER RAARME" +
"NIAN CAPITAL LETTER SEHARMENIAN CAPITAL LETTER VEWARMENIAN CAPITAL LETTE" +
"R TIWNARMENIAN CAPITAL LETTER REHARMENIAN CAPITAL LETTER COARMENIAN CAPI" +
"TAL LETTER YIWNARMENIAN CAPITAL LETTER PIWRARMENIAN CAPITAL LETTER KEHAR" +
"MENIAN CAPITAL LETTER OHARMENIAN CAPITAL LETTER FEHARMENIAN MODIFIER LET" +
"TER LEFT HALF RINGARMENIAN APOSTROPHEARMENIAN EMPHASIS MARKARMENIAN EXCL" +
"AMATION MARKARMENIAN COMMAARMENIAN QUESTION MARKARMENIAN ABBREVIATION MA" +
"RKARMENIAN SMALL LETTER TURNED AYBARMENIAN SMALL LETTER AYBARMENIAN SMAL" +
"L LETTER BENARMENIAN SMALL LETTER GIMARMENIAN SMALL LETTER DAARMENIAN SM" +
"ALL LETTER ECHARMENIAN SMALL LETTER ZAARMENIAN SMALL LETTER EHARMENIAN S" +
"MALL LETTER ETARMENIAN SMALL LETTER TOARMENIAN SMALL LETTER ZHEARMENIAN " +
"SMALL LETTER INIARMENIAN SMALL LETTER LIWNARMENIAN SMALL LETTER XEHARMEN" +
"IAN SMALL LETTER CAARMENIAN SMALL LETTER KENARMENIAN SMALL LETTER HOARME" +
"NIAN SMALL LETTER JAARMENIAN SMALL LETTER GHADARMENIAN SMALL LETTER CHEH" +
"ARMENIAN SMALL LETTER MENARMENIAN SMALL LETTER YIARMENIAN SMALL LETTER N" +
"OWARMENIAN SMALL LETTER SHAARMENIAN SMALL LETTER VOARMENIAN SMALL LETTER" +
" CHAARMENIAN SMALL LETTER PEHARMENIAN SMALL LETTER JHEHARMENIAN SMALL LE" +
"TTER RAARMENIAN SMALL LETTER SEHARMENIAN SMALL LETTER VEWARMENIAN SMALL " +
"LETTER TIWNARMENIAN SMALL LETTER REHARMENIAN SMALL LETTER COARMENIAN SMA" +
"LL LETTER YIWNARMENIAN SMALL LETTER PIWRARMENIAN SMALL LETTER KEHARMENIA" +
"N SMALL LETTER OHARMENIAN SMALL LETTER FEHARMENIAN SMALL LIGATURE ECH YI" +
"WNARMENIAN SMALL LETTER YI WITH STROKEARMENIAN FULL STOPARMENIAN HYPHENR" +
"IGHT-FACING ARMENIAN ETERNITY SIGNLEFT-FACING ARMENIAN ETERNITY SIGNARME" +
"NIAN DRAM SIGNHEBREW ACCENT ETNAHTAHEBREW ACCENT SEGOLHEBREW ACCENT SHAL" +
"SHELETHEBREW ACCENT ZAQEF QATANHEBREW ACCENT ZAQEF GADOLHEBREW ACCENT TI" +
"PEHAHEBREW ACCENT REVIAHEBREW ACCENT ZARQAHEBREW ACCENT PASHTAHEBREW ACC" +
"ENT YETIVHEBREW ACCENT TEVIRHEBREW ACCENT GERESHHEBREW ACCENT GERESH MUQ" +
"DAMHEBREW ACCENT GERSHAYIMHEBREW ACCENT QARNEY PARAHEBREW ACCENT TELISHA" +
" GEDOLAHEBREW ACCENT PAZERHEBREW ACCENT ATNAH HAFUKHHEBREW ACCENT MUNAHH" +
"EBREW ACCENT MAHAPAKHHEBREW ACCENT MERKHAHEBREW ACCENT MERKHA KEFULAHEBR" +
"EW ACCENT DARGAHEBREW ACCENT QADMAHEBREW ACCENT TELISHA QETANAHEBREW ACC" +
"ENT YERAH BEN YOMOHEBREW ACCENT OLEHEBREW ACCENT ILUYHEBREW ACCENT DEHIH" +
"EBREW ACCENT ZINORHEBREW MARK MASORA CIRCLEHEBREW POINT SHEVAHEBREW POIN" +
"T HATAF SEGOLHEBREW POINT HATAF PATAHHEBREW POINT HATAF QAMATSHEBREW POI" +
"NT HIRIQHEBREW POINT TSEREHEBREW POINT SEGOLHEBREW POINT PATAHHEBREW POI" +
"NT QAMATSHEBREW POINT HOLAMHEBREW POINT HOLAM HASER FOR VAVHEBREW POINT " +
"QUBUTSHEBREW POINT DAGESH OR MAPIQHEBREW POINT METEGHEBREW PUNCTUATION M" +
"AQAFHEBREW POINT RAFEHEBREW PUNCTUATION PASEQHEBREW POINT SHIN DOTHEBREW" +
" POINT SIN DOTHEBREW PUNCTUATION SOF PASUQHEBREW MARK UPPER DOTHEBREW MA" +
"RK LOWER DOTHEBREW PUNCTUATION NUN HAFUKHAHEBREW POINT QAMATS QATANHEBRE" +
"W LETTER ALEFHEBREW LETTER BETHEBREW LETTER GIMELHEBREW LETTER DALETHEBR" +
"EW LETTER HEHEBREW LETTER VAVHEBREW LETTER ZAYINHEBREW LETTER HETHEBREW " +
"LETTER TETHEBREW LETTER YODHEBREW LETTER FINAL KAFHEBREW LETTER KAFHEBRE" +
"W LETTER LAMEDHEBREW LETTER FINAL MEMHEBREW LETTER MEMHEBREW LETTER FINA" +
"L NUNHEBREW LETTER NUNHEBREW LETTER SAMEKHHEBREW LETTER AYINHEBREW LETTE" +
"R FINAL PEHEBREW LETTER PEHEBREW LETTER FINAL TSADIHEBREW LETTER TSADIHE" +
"BREW LETTER QOFHEBREW LETTER RESHHEBREW LETTER SHINHEBREW LETTER TAVHEBR") + ("" +
"EW YOD TRIANGLEHEBREW LIGATURE YIDDISH DOUBLE VAVHEBREW LIGATURE YIDDISH" +
" VAV YODHEBREW LIGATURE YIDDISH DOUBLE YODHEBREW PUNCTUATION GERESHHEBRE" +
"W PUNCTUATION GERSHAYIMARABIC NUMBER SIGNARABIC SIGN SANAHARABIC FOOTNOT" +
"E MARKERARABIC SIGN SAFHAARABIC SIGN SAMVATARABIC NUMBER MARK ABOVEARABI" +
"C-INDIC CUBE ROOTARABIC-INDIC FOURTH ROOTARABIC RAYARABIC-INDIC PER MILL" +
"E SIGNARABIC-INDIC PER TEN THOUSAND SIGNAFGHANI SIGNARABIC COMMAARABIC D" +
"ATE SEPARATORARABIC POETIC VERSE SIGNARABIC SIGN MISRAARABIC SIGN SALLAL" +
"LAHOU ALAYHE WASSALLAMARABIC SIGN ALAYHE ASSALLAMARABIC SIGN RAHMATULLAH" +
" ALAYHEARABIC SIGN RADI ALLAHOU ANHUARABIC SIGN TAKHALLUSARABIC SMALL HI" +
"GH TAHARABIC SMALL HIGH LIGATURE ALEF WITH LAM WITH YEHARABIC SMALL HIGH" +
" ZAINARABIC SMALL FATHAARABIC SMALL DAMMAARABIC SMALL KASRAARABIC SEMICO" +
"LONARABIC LETTER MARKARABIC END OF TEXT MARKARABIC TRIPLE DOT PUNCTUATIO" +
"N MARKARABIC QUESTION MARKARABIC LETTER KASHMIRI YEHARABIC LETTER HAMZAA" +
"RABIC LETTER ALEF WITH MADDA ABOVEARABIC LETTER ALEF WITH HAMZA ABOVEARA" +
"BIC LETTER WAW WITH HAMZA ABOVEARABIC LETTER ALEF WITH HAMZA BELOWARABIC" +
" LETTER YEH WITH HAMZA ABOVEARABIC LETTER ALEFARABIC LETTER BEHARABIC LE" +
"TTER TEH MARBUTAARABIC LETTER TEHARABIC LETTER THEHARABIC LETTER JEEMARA" +
"BIC LETTER HAHARABIC LETTER KHAHARABIC LETTER DALARABIC LETTER THALARABI" +
"C LETTER REHARABIC LETTER ZAINARABIC LETTER SEENARABIC LETTER SHEENARABI" +
"C LETTER SADARABIC LETTER DADARABIC LETTER TAHARABIC LETTER ZAHARABIC LE" +
"TTER AINARABIC LETTER GHAINARABIC LETTER KEHEH WITH TWO DOTS ABOVEARABIC" +
" LETTER KEHEH WITH THREE DOTS BELOWARABIC LETTER FARSI YEH WITH INVERTED" +
" VARABIC LETTER FARSI YEH WITH TWO DOTS ABOVEARABIC LETTER FARSI YEH WIT" +
"H THREE DOTS ABOVEARABIC TATWEELARABIC LETTER FEHARABIC LETTER QAFARABIC" +
" LETTER KAFARABIC LETTER LAMARABIC LETTER MEEMARABIC LETTER NOONARABIC L" +
"ETTER HEHARABIC LETTER WAWARABIC LETTER ALEF MAKSURAARABIC LETTER YEHARA" +
"BIC FATHATANARABIC DAMMATANARABIC KASRATANARABIC FATHAARABIC DAMMAARABIC" +
" KASRAARABIC SHADDAARABIC SUKUNARABIC MADDAH ABOVEARABIC HAMZA ABOVEARAB" +
"IC HAMZA BELOWARABIC SUBSCRIPT ALEFARABIC INVERTED DAMMAARABIC MARK NOON" +
" GHUNNAARABIC ZWARAKAYARABIC VOWEL SIGN SMALL V ABOVEARABIC VOWEL SIGN I" +
"NVERTED SMALL V ABOVEARABIC VOWEL SIGN DOT BELOWARABIC REVERSED DAMMAARA" +
"BIC FATHA WITH TWO DOTSARABIC WAVY HAMZA BELOWARABIC-INDIC DIGIT ZEROARA" +
"BIC-INDIC DIGIT ONEARABIC-INDIC DIGIT TWOARABIC-INDIC DIGIT THREEARABIC-" +
"INDIC DIGIT FOURARABIC-INDIC DIGIT FIVEARABIC-INDIC DIGIT SIXARABIC-INDI" +
"C DIGIT SEVENARABIC-INDIC DIGIT EIGHTARABIC-INDIC DIGIT NINEARABIC PERCE" +
"NT SIGNARABIC DECIMAL SEPARATORARABIC THOUSANDS SEPARATORARABIC FIVE POI" +
"NTED STARARABIC LETTER DOTLESS BEHARABIC LETTER DOTLESS QAFARABIC LETTER" +
" SUPERSCRIPT ALEFARABIC LETTER ALEF WASLAARABIC LETTER ALEF WITH WAVY HA" +
"MZA ABOVEARABIC LETTER ALEF WITH WAVY HAMZA BELOWARABIC LETTER HIGH HAMZ" +
"AARABIC LETTER HIGH HAMZA ALEFARABIC LETTER HIGH HAMZA WAWARABIC LETTER " +
"U WITH HAMZA ABOVEARABIC LETTER HIGH HAMZA YEHARABIC LETTER TTEHARABIC L" +
"ETTER TTEHEHARABIC LETTER BEEHARABIC LETTER TEH WITH RINGARABIC LETTER T" +
"EH WITH THREE DOTS ABOVE DOWNWARDSARABIC LETTER PEHARABIC LETTER TEHEHAR" +
"ABIC LETTER BEHEHARABIC LETTER HAH WITH HAMZA ABOVEARABIC LETTER HAH WIT" +
"H TWO DOTS VERTICAL ABOVEARABIC LETTER NYEHARABIC LETTER DYEHARABIC LETT" +
"ER HAH WITH THREE DOTS ABOVEARABIC LETTER TCHEHARABIC LETTER TCHEHEHARAB" +
"IC LETTER DDALARABIC LETTER DAL WITH RINGARABIC LETTER DAL WITH DOT BELO" +
"WARABIC LETTER DAL WITH DOT BELOW AND SMALL TAHARABIC LETTER DAHALARABIC" +
" LETTER DDAHALARABIC LETTER DULARABIC LETTER DAL WITH THREE DOTS ABOVE D" +
"OWNWARDSARABIC LETTER DAL WITH FOUR DOTS ABOVEARABIC LETTER RREHARABIC L" +
"ETTER REH WITH SMALL VARABIC LETTER REH WITH RINGARABIC LETTER REH WITH " +
"DOT BELOWARABIC LETTER REH WITH SMALL V BELOWARABIC LETTER REH WITH DOT " +
"BELOW AND DOT ABOVEARABIC LETTER REH WITH TWO DOTS ABOVEARABIC LETTER JE" +
"HARABIC LETTER REH WITH FOUR DOTS ABOVEARABIC LETTER SEEN WITH DOT BELOW" +
" AND DOT ABOVEARABIC LETTER SEEN WITH THREE DOTS BELOWARABIC LETTER SEEN" +
" WITH THREE DOTS BELOW AND THREE DOTS ABOVEARABIC LETTER SAD WITH TWO DO" +
"TS BELOWARABIC LETTER SAD WITH THREE DOTS ABOVEARABIC LETTER TAH WITH TH" +
"REE DOTS ABOVEARABIC LETTER AIN WITH THREE DOTS ABOVEARABIC LETTER DOTLE" +
"SS FEHARABIC LETTER FEH WITH DOT MOVED BELOWARABIC LETTER FEH WITH DOT B" +
"ELOWARABIC LETTER VEHARABIC LETTER FEH WITH THREE DOTS BELOWARABIC LETTE" +
"R PEHEHARABIC LETTER QAF WITH DOT ABOVEARABIC LETTER QAF WITH THREE DOTS" +
" ABOVEARABIC LETTER KEHEHARABIC LETTER SWASH KAFARABIC LETTER KAF WITH R" +
"INGARABIC LETTER KAF WITH DOT ABOVEARABIC LETTER NGARABIC LETTER KAF WIT" +
"H THREE DOTS BELOWARABIC LETTER GAFARABIC LETTER GAF WITH RINGARABIC LET") + ("" +
"TER NGOEHARABIC LETTER GAF WITH TWO DOTS BELOWARABIC LETTER GUEHARABIC L" +
"ETTER GAF WITH THREE DOTS ABOVEARABIC LETTER LAM WITH SMALL VARABIC LETT" +
"ER LAM WITH DOT ABOVEARABIC LETTER LAM WITH THREE DOTS ABOVEARABIC LETTE" +
"R LAM WITH THREE DOTS BELOWARABIC LETTER NOON WITH DOT BELOWARABIC LETTE" +
"R NOON GHUNNAARABIC LETTER RNOONARABIC LETTER NOON WITH RINGARABIC LETTE" +
"R NOON WITH THREE DOTS ABOVEARABIC LETTER HEH DOACHASHMEEARABIC LETTER T" +
"CHEH WITH DOT ABOVEARABIC LETTER HEH WITH YEH ABOVEARABIC LETTER HEH GOA" +
"LARABIC LETTER HEH GOAL WITH HAMZA ABOVEARABIC LETTER TEH MARBUTA GOALAR" +
"ABIC LETTER WAW WITH RINGARABIC LETTER KIRGHIZ OEARABIC LETTER OEARABIC " +
"LETTER UARABIC LETTER YUARABIC LETTER KIRGHIZ YUARABIC LETTER WAW WITH T" +
"WO DOTS ABOVEARABIC LETTER VEARABIC LETTER FARSI YEHARABIC LETTER YEH WI" +
"TH TAILARABIC LETTER YEH WITH SMALL VARABIC LETTER WAW WITH DOT ABOVEARA" +
"BIC LETTER EARABIC LETTER YEH WITH THREE DOTS BELOWARABIC LETTER YEH BAR" +
"REEARABIC LETTER YEH BARREE WITH HAMZA ABOVEARABIC FULL STOPARABIC LETTE" +
"R AEARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURAARABIC SMAL" +
"L HIGH LIGATURE QAF WITH LAM WITH ALEF MAKSURAARABIC SMALL HIGH MEEM INI" +
"TIAL FORMARABIC SMALL HIGH LAM ALEFARABIC SMALL HIGH JEEMARABIC SMALL HI" +
"GH THREE DOTSARABIC SMALL HIGH SEENARABIC END OF AYAHARABIC START OF RUB" +
" EL HIZBARABIC SMALL HIGH ROUNDED ZEROARABIC SMALL HIGH UPRIGHT RECTANGU" +
"LAR ZEROARABIC SMALL HIGH DOTLESS HEAD OF KHAHARABIC SMALL HIGH MEEM ISO" +
"LATED FORMARABIC SMALL LOW SEENARABIC SMALL HIGH MADDAARABIC SMALL WAWAR" +
"ABIC SMALL YEHARABIC SMALL HIGH YEHARABIC SMALL HIGH NOONARABIC PLACE OF" +
" SAJDAHARABIC EMPTY CENTRE LOW STOPARABIC EMPTY CENTRE HIGH STOPARABIC R" +
"OUNDED HIGH STOP WITH FILLED CENTREARABIC SMALL LOW MEEMARABIC LETTER DA" +
"L WITH INVERTED VARABIC LETTER REH WITH INVERTED VEXTENDED ARABIC-INDIC " +
"DIGIT ZEROEXTENDED ARABIC-INDIC DIGIT ONEEXTENDED ARABIC-INDIC DIGIT TWO" +
"EXTENDED ARABIC-INDIC DIGIT THREEEXTENDED ARABIC-INDIC DIGIT FOUREXTENDE" +
"D ARABIC-INDIC DIGIT FIVEEXTENDED ARABIC-INDIC DIGIT SIXEXTENDED ARABIC-" +
"INDIC DIGIT SEVENEXTENDED ARABIC-INDIC DIGIT EIGHTEXTENDED ARABIC-INDIC " +
"DIGIT NINEARABIC LETTER SHEEN WITH DOT BELOWARABIC LETTER DAD WITH DOT B" +
"ELOWARABIC LETTER GHAIN WITH DOT BELOWARABIC SIGN SINDHI AMPERSANDARABIC" +
" SIGN SINDHI POSTPOSITION MENARABIC LETTER HEH WITH INVERTED VSYRIAC END" +
" OF PARAGRAPHSYRIAC SUPRALINEAR FULL STOPSYRIAC SUBLINEAR FULL STOPSYRIA" +
"C SUPRALINEAR COLONSYRIAC SUBLINEAR COLONSYRIAC HORIZONTAL COLONSYRIAC C" +
"OLON SKEWED LEFTSYRIAC COLON SKEWED RIGHTSYRIAC SUPRALINEAR COLON SKEWED" +
" LEFTSYRIAC SUBLINEAR COLON SKEWED RIGHTSYRIAC CONTRACTIONSYRIAC HARKLEA" +
"N OBELUSSYRIAC HARKLEAN METOBELUSSYRIAC HARKLEAN ASTERISCUSSYRIAC ABBREV" +
"IATION MARKSYRIAC LETTER ALAPHSYRIAC LETTER SUPERSCRIPT ALAPHSYRIAC LETT" +
"ER BETHSYRIAC LETTER GAMALSYRIAC LETTER GAMAL GARSHUNISYRIAC LETTER DALA" +
"THSYRIAC LETTER DOTLESS DALATH RISHSYRIAC LETTER HESYRIAC LETTER WAWSYRI" +
"AC LETTER ZAINSYRIAC LETTER HETHSYRIAC LETTER TETHSYRIAC LETTER TETH GAR" +
"SHUNISYRIAC LETTER YUDHSYRIAC LETTER YUDH HESYRIAC LETTER KAPHSYRIAC LET" +
"TER LAMADHSYRIAC LETTER MIMSYRIAC LETTER NUNSYRIAC LETTER SEMKATHSYRIAC " +
"LETTER FINAL SEMKATHSYRIAC LETTER ESYRIAC LETTER PESYRIAC LETTER REVERSE" +
"D PESYRIAC LETTER SADHESYRIAC LETTER QAPHSYRIAC LETTER RISHSYRIAC LETTER" +
" SHINSYRIAC LETTER TAWSYRIAC LETTER PERSIAN BHETHSYRIAC LETTER PERSIAN G" +
"HAMALSYRIAC LETTER PERSIAN DHALATHSYRIAC PTHAHA ABOVESYRIAC PTHAHA BELOW" +
"SYRIAC PTHAHA DOTTEDSYRIAC ZQAPHA ABOVESYRIAC ZQAPHA BELOWSYRIAC ZQAPHA " +
"DOTTEDSYRIAC RBASA ABOVESYRIAC RBASA BELOWSYRIAC DOTTED ZLAMA HORIZONTAL" +
"SYRIAC DOTTED ZLAMA ANGULARSYRIAC HBASA ABOVESYRIAC HBASA BELOWSYRIAC HB" +
"ASA-ESASA DOTTEDSYRIAC ESASA ABOVESYRIAC ESASA BELOWSYRIAC RWAHASYRIAC F" +
"EMININE DOTSYRIAC QUSHSHAYASYRIAC RUKKAKHASYRIAC TWO VERTICAL DOTS ABOVE" +
"SYRIAC TWO VERTICAL DOTS BELOWSYRIAC THREE DOTS ABOVESYRIAC THREE DOTS B" +
"ELOWSYRIAC OBLIQUE LINE ABOVESYRIAC OBLIQUE LINE BELOWSYRIAC MUSICSYRIAC" +
" BARREKHSYRIAC LETTER SOGDIAN ZHAINSYRIAC LETTER SOGDIAN KHAPHSYRIAC LET" +
"TER SOGDIAN FEARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOWARABIC" +
" LETTER BEH WITH DOT BELOW AND THREE DOTS ABOVEARABIC LETTER BEH WITH TH" +
"REE DOTS POINTING UPWARDS BELOWARABIC LETTER BEH WITH THREE DOTS POINTIN" +
"G UPWARDS BELOW AND TWO DOTS ABOVEARABIC LETTER BEH WITH TWO DOTS BELOW " +
"AND DOT ABOVEARABIC LETTER BEH WITH INVERTED SMALL V BELOWARABIC LETTER " +
"BEH WITH SMALL VARABIC LETTER HAH WITH TWO DOTS ABOVEARABIC LETTER HAH W" +
"ITH THREE DOTS POINTING UPWARDS BELOWARABIC LETTER DAL WITH TWO DOTS VER" +
"TICALLY BELOW AND SMALL TAHARABIC LETTER DAL WITH INVERTED SMALL V BELOW" +
"ARABIC LETTER REH WITH STROKEARABIC LETTER SEEN WITH FOUR DOTS ABOVEARAB") + ("" +
"IC LETTER AIN WITH TWO DOTS ABOVEARABIC LETTER AIN WITH THREE DOTS POINT" +
"ING DOWNWARDS ABOVEARABIC LETTER AIN WITH TWO DOTS VERTICALLY ABOVEARABI" +
"C LETTER FEH WITH TWO DOTS BELOWARABIC LETTER FEH WITH THREE DOTS POINTI" +
"NG UPWARDS BELOWARABIC LETTER KEHEH WITH DOT ABOVEARABIC LETTER KEHEH WI" +
"TH THREE DOTS ABOVEARABIC LETTER KEHEH WITH THREE DOTS POINTING UPWARDS " +
"BELOWARABIC LETTER MEEM WITH DOT ABOVEARABIC LETTER MEEM WITH DOT BELOWA" +
"RABIC LETTER NOON WITH TWO DOTS BELOWARABIC LETTER NOON WITH SMALL TAHAR" +
"ABIC LETTER NOON WITH SMALL VARABIC LETTER LAM WITH BARARABIC LETTER REH" +
" WITH TWO DOTS VERTICALLY ABOVEARABIC LETTER REH WITH HAMZA ABOVEARABIC " +
"LETTER SEEN WITH TWO DOTS VERTICALLY ABOVEARABIC LETTER HAH WITH SMALL A" +
"RABIC LETTER TAH BELOWARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH AND" +
" TWO DOTSARABIC LETTER SEEN WITH SMALL ARABIC LETTER TAH AND TWO DOTSARA" +
"BIC LETTER REH WITH SMALL ARABIC LETTER TAH AND TWO DOTSARABIC LETTER HA" +
"H WITH SMALL ARABIC LETTER TAH ABOVEARABIC LETTER ALEF WITH EXTENDED ARA" +
"BIC-INDIC DIGIT TWO ABOVEARABIC LETTER ALEF WITH EXTENDED ARABIC-INDIC D" +
"IGIT THREE ABOVEARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT" +
" TWO ABOVEARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT THREE" +
" ABOVEARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT FOUR BELO" +
"WARABIC LETTER WAW WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVEARABIC LETT" +
"ER WAW WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVEARABIC LETTER YEH BAR" +
"REE WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVEARABIC LETTER YEH BARREE W" +
"ITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVEARABIC LETTER HAH WITH EXTEND" +
"ED ARABIC-INDIC DIGIT FOUR BELOWARABIC LETTER SEEN WITH EXTENDED ARABIC-" +
"INDIC DIGIT FOUR ABOVEARABIC LETTER SEEN WITH INVERTED VARABIC LETTER KA" +
"F WITH TWO DOTS ABOVETHAANA LETTER HAATHAANA LETTER SHAVIYANITHAANA LETT" +
"ER NOONUTHAANA LETTER RAATHAANA LETTER BAATHAANA LETTER LHAVIYANITHAANA " +
"LETTER KAAFUTHAANA LETTER ALIFUTHAANA LETTER VAAVUTHAANA LETTER MEEMUTHA" +
"ANA LETTER FAAFUTHAANA LETTER DHAALUTHAANA LETTER THAATHAANA LETTER LAAM" +
"UTHAANA LETTER GAAFUTHAANA LETTER GNAVIYANITHAANA LETTER SEENUTHAANA LET" +
"TER DAVIYANITHAANA LETTER ZAVIYANITHAANA LETTER TAVIYANITHAANA LETTER YA" +
"ATHAANA LETTER PAVIYANITHAANA LETTER JAVIYANITHAANA LETTER CHAVIYANITHAA" +
"NA LETTER TTAATHAANA LETTER HHAATHAANA LETTER KHAATHAANA LETTER THAALUTH" +
"AANA LETTER ZAATHAANA LETTER SHEENUTHAANA LETTER SAADHUTHAANA LETTER DAA" +
"DHUTHAANA LETTER TOTHAANA LETTER ZOTHAANA LETTER AINUTHAANA LETTER GHAIN" +
"UTHAANA LETTER QAAFUTHAANA LETTER WAAVUTHAANA ABAFILITHAANA AABAAFILITHA" +
"ANA IBIFILITHAANA EEBEEFILITHAANA UBUFILITHAANA OOBOOFILITHAANA EBEFILIT" +
"HAANA EYBEYFILITHAANA OBOFILITHAANA OABOAFILITHAANA SUKUNTHAANA LETTER N" +
"AANKO DIGIT ZERONKO DIGIT ONENKO DIGIT TWONKO DIGIT THREENKO DIGIT FOURN" +
"KO DIGIT FIVENKO DIGIT SIXNKO DIGIT SEVENNKO DIGIT EIGHTNKO DIGIT NINENK" +
"O LETTER ANKO LETTER EENKO LETTER INKO LETTER ENKO LETTER UNKO LETTER OO" +
"NKO LETTER ONKO LETTER DAGBASINNANKO LETTER NNKO LETTER BANKO LETTER PAN" +
"KO LETTER TANKO LETTER JANKO LETTER CHANKO LETTER DANKO LETTER RANKO LET" +
"TER RRANKO LETTER SANKO LETTER GBANKO LETTER FANKO LETTER KANKO LETTER L" +
"ANKO LETTER NA WOLOSONKO LETTER MANKO LETTER NYANKO LETTER NANKO LETTER " +
"HANKO LETTER WANKO LETTER YANKO LETTER NYA WOLOSONKO LETTER JONA JANKO L" +
"ETTER JONA CHANKO LETTER JONA RANKO COMBINING SHORT HIGH TONENKO COMBINI" +
"NG SHORT LOW TONENKO COMBINING SHORT RISING TONENKO COMBINING LONG DESCE" +
"NDING TONENKO COMBINING LONG HIGH TONENKO COMBINING LONG LOW TONENKO COM" +
"BINING LONG RISING TONENKO COMBINING NASALIZATION MARKNKO COMBINING DOUB" +
"LE DOT ABOVENKO HIGH TONE APOSTROPHENKO LOW TONE APOSTROPHENKO SYMBOL OO" +
" DENNENNKO SYMBOL GBAKURUNENNKO COMMANKO EXCLAMATION MARKNKO LAJANYALANN" +
"KO DANTAYALANNKO DOROME SIGNNKO TAMAN SIGNSAMARITAN LETTER ALAFSAMARITAN" +
" LETTER BITSAMARITAN LETTER GAMANSAMARITAN LETTER DALATSAMARITAN LETTER " +
"IYSAMARITAN LETTER BAASAMARITAN LETTER ZENSAMARITAN LETTER ITSAMARITAN L" +
"ETTER TITSAMARITAN LETTER YUTSAMARITAN LETTER KAAFSAMARITAN LETTER LABAT" +
"SAMARITAN LETTER MIMSAMARITAN LETTER NUNSAMARITAN LETTER SINGAATSAMARITA" +
"N LETTER INSAMARITAN LETTER FISAMARITAN LETTER TSAADIYSAMARITAN LETTER Q" +
"UFSAMARITAN LETTER RISHSAMARITAN LETTER SHANSAMARITAN LETTER TAAFSAMARIT" +
"AN MARK INSAMARITAN MARK IN-ALAFSAMARITAN MARK OCCLUSIONSAMARITAN MARK D" +
"AGESHSAMARITAN MODIFIER LETTER EPENTHETIC YUTSAMARITAN MARK EPENTHETIC Y" +
"UTSAMARITAN VOWEL SIGN LONG ESAMARITAN VOWEL SIGN ESAMARITAN VOWEL SIGN " +
"OVERLONG AASAMARITAN VOWEL SIGN LONG AASAMARITAN VOWEL SIGN AASAMARITAN " +
"VOWEL SIGN OVERLONG ASAMARITAN VOWEL SIGN LONG ASAMARITAN VOWEL SIGN ASA" +
"MARITAN MODIFIER LETTER SHORT ASAMARITAN VOWEL SIGN SHORT ASAMARITAN VOW") + ("" +
"EL SIGN LONG USAMARITAN VOWEL SIGN USAMARITAN MODIFIER LETTER ISAMARITAN" +
" VOWEL SIGN LONG ISAMARITAN VOWEL SIGN ISAMARITAN VOWEL SIGN OSAMARITAN " +
"VOWEL SIGN SUKUNSAMARITAN MARK NEQUDAASAMARITAN PUNCTUATION NEQUDAASAMAR" +
"ITAN PUNCTUATION AFSAAQSAMARITAN PUNCTUATION ANGEDSAMARITAN PUNCTUATION " +
"BAUSAMARITAN PUNCTUATION ATMAAUSAMARITAN PUNCTUATION SHIYYAALAASAMARITAN" +
" ABBREVIATION MARKSAMARITAN PUNCTUATION MELODIC QITSASAMARITAN PUNCTUATI" +
"ON ZIQAASAMARITAN PUNCTUATION QITSASAMARITAN PUNCTUATION ZAEFSAMARITAN P" +
"UNCTUATION TURUSAMARITAN PUNCTUATION ARKAANUSAMARITAN PUNCTUATION SOF MA" +
"SHFAATSAMARITAN PUNCTUATION ANNAAUMANDAIC LETTER HALQAMANDAIC LETTER ABM" +
"ANDAIC LETTER AGMANDAIC LETTER ADMANDAIC LETTER AHMANDAIC LETTER USHENNA" +
"MANDAIC LETTER AZMANDAIC LETTER ITMANDAIC LETTER ATTMANDAIC LETTER AKSAM" +
"ANDAIC LETTER AKMANDAIC LETTER ALMANDAIC LETTER AMMANDAIC LETTER ANMANDA" +
"IC LETTER ASMANDAIC LETTER INMANDAIC LETTER APMANDAIC LETTER ASZMANDAIC " +
"LETTER AQMANDAIC LETTER ARMANDAIC LETTER ASHMANDAIC LETTER ATMANDAIC LET" +
"TER DUSHENNAMANDAIC LETTER KADMANDAIC LETTER AINMANDAIC AFFRICATION MARK" +
"MANDAIC VOCALIZATION MARKMANDAIC GEMINATION MARKMANDAIC PUNCTUATIONSYRIA" +
"C LETTER MALAYALAM NGASYRIAC LETTER MALAYALAM JASYRIAC LETTER MALAYALAM " +
"NYASYRIAC LETTER MALAYALAM TTASYRIAC LETTER MALAYALAM NNASYRIAC LETTER M" +
"ALAYALAM NNNASYRIAC LETTER MALAYALAM BHASYRIAC LETTER MALAYALAM RASYRIAC" +
" LETTER MALAYALAM LLASYRIAC LETTER MALAYALAM LLLASYRIAC LETTER MALAYALAM" +
" SSAARABIC LETTER ALEF WITH ATTACHED FATHAARABIC LETTER ALEF WITH ATTACH" +
"ED TOP RIGHT FATHAARABIC LETTER ALEF WITH RIGHT MIDDLE STROKEARABIC LETT" +
"ER ALEF WITH LEFT MIDDLE STROKEARABIC LETTER ALEF WITH ATTACHED KASRAARA" +
"BIC LETTER ALEF WITH ATTACHED BOTTOM RIGHT KASRAARABIC LETTER ALEF WITH " +
"ATTACHED ROUND DOT ABOVEARABIC LETTER ALEF WITH ATTACHED RIGHT ROUND DOT" +
"ARABIC LETTER ALEF WITH ATTACHED LEFT ROUND DOTARABIC LETTER ALEF WITH A" +
"TTACHED ROUND DOT BELOWARABIC LETTER ALEF WITH DOT ABOVEARABIC LETTER AL" +
"EF WITH ATTACHED TOP RIGHT FATHA AND DOT ABOVEARABIC LETTER ALEF WITH RI" +
"GHT MIDDLE STROKE AND DOT ABOVEARABIC LETTER ALEF WITH ATTACHED BOTTOM R" +
"IGHT KASRA AND DOT ABOVEARABIC LETTER ALEF WITH ATTACHED TOP RIGHT FATHA" +
" AND LEFT RINGARABIC LETTER ALEF WITH RIGHT MIDDLE STROKE AND LEFT RINGA" +
"RABIC LETTER ALEF WITH ATTACHED BOTTOM RIGHT KASRA AND LEFT RINGARABIC L" +
"ETTER ALEF WITH ATTACHED RIGHT HAMZAARABIC LETTER ALEF WITH ATTACHED LEF" +
"T HAMZAARABIC TATWEEL WITH OVERSTRUCK HAMZAARABIC TATWEEL WITH OVERSTRUC" +
"K WAWARABIC TATWEEL WITH TWO DOTS BELOWARABIC LETTER THIN YEHARABIC BASE" +
"LINE ROUND DOTARABIC RAISED ROUND DOTARABIC LETTER NOON WITH INVERTED SM" +
"ALL VARABIC LETTER HAH WITH INVERTED SMALL V BELOWARABIC LETTER TAH WITH" +
" DOT BELOWARABIC LETTER TAH WITH THREE DOTS BELOWARABIC LETTER KEHEH WIT" +
"H TWO DOTS VERTICALLY BELOWARABIC VERTICAL TAILARABIC POUND MARK ABOVEAR" +
"ABIC PIASTRE MARK ABOVEARABIC SMALL HIGH WORD AL-JUZARABIC SMALL LOW WOR" +
"D ISHMAAMARABIC SMALL LOW WORD IMAALAARABIC SMALL LOW WORD TASHEELARABIC" +
" MADDA WAAJIBARABIC SUPERSCRIPT ALEF MOKHASSASARABIC DOUBLED MADDAARABIC" +
" HALF MADDA OVER MADDAARABIC LETTER BEH WITH SMALL V BELOWARABIC LETTER " +
"BEH WITH HAMZA ABOVEARABIC LETTER JEEM WITH TWO DOTS ABOVEARABIC LETTER " +
"TAH WITH TWO DOTS ABOVEARABIC LETTER FEH WITH DOT BELOW AND THREE DOTS A" +
"BOVEARABIC LETTER QAF WITH DOT BELOWARABIC LETTER LAM WITH DOUBLE BARARA" +
"BIC LETTER MEEM WITH THREE DOTS ABOVEARABIC LETTER YEH WITH TWO DOTS BEL" +
"OW AND HAMZA ABOVEARABIC LETTER YEH WITH TWO DOTS BELOW AND DOT ABOVEARA" +
"BIC LETTER REH WITH LOOPARABIC LETTER WAW WITH DOT WITHINARABIC LETTER R" +
"OHINGYA YEHARABIC LETTER LOW ALEFARABIC LETTER DAL WITH THREE DOTS BELOW" +
"ARABIC LETTER SAD WITH THREE DOTS BELOWARABIC LETTER GAF WITH INVERTED S" +
"TROKEARABIC LETTER STRAIGHT WAWARABIC LETTER ZAIN WITH INVERTED V ABOVEA" +
"RABIC LETTER AIN WITH THREE DOTS BELOWARABIC LETTER KAF WITH DOT BELOWAR" +
"ABIC LETTER QAF WITH DOT BELOW AND NO DOTS ABOVEARABIC LETTER BEH WITH S" +
"MALL MEEM ABOVEARABIC LETTER PEH WITH SMALL MEEM ABOVEARABIC LETTER TEH " +
"WITH SMALL TEH ABOVEARABIC LETTER REH WITH SMALL NOON ABOVEARABIC LETTER" +
" YEH WITH TWO DOTS BELOW AND SMALL NOON ABOVEARABIC LETTER AFRICAN FEHAR" +
"ABIC LETTER AFRICAN QAFARABIC LETTER AFRICAN NOONARABIC LETTER PEH WITH " +
"SMALL VARABIC LETTER TEH WITH SMALL VARABIC LETTER TTEH WITH SMALL VARAB" +
"IC LETTER TCHEH WITH SMALL VARABIC LETTER KEHEH WITH SMALL VARABIC LETTE" +
"R GHAIN WITH THREE DOTS ABOVEARABIC LETTER AFRICAN QAF WITH THREE DOTS A" +
"BOVEARABIC LETTER JEEM WITH THREE DOTS ABOVEARABIC LETTER JEEM WITH THRE" +
"E DOTS BELOWARABIC LETTER LAM WITH SMALL ARABIC LETTER TAH ABOVEARABIC L" +
"ETTER GRAFARABIC SMALL FARSI YEHARABIC SMALL HIGH FARSI YEHARABIC SMALL ") + ("" +
"HIGH YEH BARREE WITH TWO DOTS BELOWARABIC SMALL HIGH WORD SAHARABIC SMAL" +
"L HIGH ZAHARABIC LARGE ROUND DOT ABOVEARABIC LARGE ROUND DOT BELOWARABIC" +
" SUKUN BELOWARABIC LARGE CIRCLE BELOWARABIC LARGE ROUND DOT INSIDE CIRCL" +
"E BELOWARABIC SMALL LOW WAWARABIC SMALL HIGH WORD AR-RUBARABIC SMALL HIG" +
"H SADARABIC SMALL HIGH AINARABIC SMALL HIGH QAFARABIC SMALL HIGH NOON WI" +
"TH KASRAARABIC SMALL LOW NOON WITH KASRAARABIC SMALL HIGH WORD ATH-THALA" +
"THAARABIC SMALL HIGH WORD AS-SAJDAARABIC SMALL HIGH WORD AN-NISFARABIC S" +
"MALL HIGH WORD SAKTAARABIC SMALL HIGH WORD QIFARABIC SMALL HIGH WORD WAQ" +
"FAARABIC SMALL HIGH FOOTNOTE MARKERARABIC SMALL HIGH SIGN SAFHAARABIC DI" +
"SPUTED END OF AYAHARABIC TURNED DAMMA BELOWARABIC CURLY FATHAARABIC CURL" +
"Y DAMMAARABIC CURLY KASRAARABIC CURLY FATHATANARABIC CURLY DAMMATANARABI" +
"C CURLY KASRATANARABIC TONE ONE DOT ABOVEARABIC TONE TWO DOTS ABOVEARABI" +
"C TONE LOOP ABOVEARABIC TONE ONE DOT BELOWARABIC TONE TWO DOTS BELOWARAB" +
"IC TONE LOOP BELOWARABIC OPEN FATHATANARABIC OPEN DAMMATANARABIC OPEN KA" +
"SRATANARABIC SMALL HIGH WAWARABIC FATHA WITH RINGARABIC FATHA WITH DOT A" +
"BOVEARABIC KASRA WITH DOT BELOWARABIC LEFT ARROWHEAD ABOVEARABIC RIGHT A" +
"RROWHEAD ABOVEARABIC LEFT ARROWHEAD BELOWARABIC RIGHT ARROWHEAD BELOWARA" +
"BIC DOUBLE RIGHT ARROWHEAD ABOVEARABIC DOUBLE RIGHT ARROWHEAD ABOVE WITH" +
" DOTARABIC RIGHT ARROWHEAD ABOVE WITH DOTARABIC DAMMA WITH DOTARABIC MAR" +
"K SIDEWAYS NOON GHUNNADEVANAGARI SIGN INVERTED CANDRABINDUDEVANAGARI SIG" +
"N CANDRABINDUDEVANAGARI SIGN ANUSVARADEVANAGARI SIGN VISARGADEVANAGARI L" +
"ETTER SHORT ADEVANAGARI LETTER ADEVANAGARI LETTER AADEVANAGARI LETTER ID" +
"EVANAGARI LETTER IIDEVANAGARI LETTER UDEVANAGARI LETTER UUDEVANAGARI LET" +
"TER VOCALIC RDEVANAGARI LETTER VOCALIC LDEVANAGARI LETTER CANDRA EDEVANA" +
"GARI LETTER SHORT EDEVANAGARI LETTER EDEVANAGARI LETTER AIDEVANAGARI LET" +
"TER CANDRA ODEVANAGARI LETTER SHORT ODEVANAGARI LETTER ODEVANAGARI LETTE" +
"R AUDEVANAGARI LETTER KADEVANAGARI LETTER KHADEVANAGARI LETTER GADEVANAG" +
"ARI LETTER GHADEVANAGARI LETTER NGADEVANAGARI LETTER CADEVANAGARI LETTER" +
" CHADEVANAGARI LETTER JADEVANAGARI LETTER JHADEVANAGARI LETTER NYADEVANA" +
"GARI LETTER TTADEVANAGARI LETTER TTHADEVANAGARI LETTER DDADEVANAGARI LET" +
"TER DDHADEVANAGARI LETTER NNADEVANAGARI LETTER TADEVANAGARI LETTER THADE" +
"VANAGARI LETTER DADEVANAGARI LETTER DHADEVANAGARI LETTER NADEVANAGARI LE" +
"TTER NNNADEVANAGARI LETTER PADEVANAGARI LETTER PHADEVANAGARI LETTER BADE" +
"VANAGARI LETTER BHADEVANAGARI LETTER MADEVANAGARI LETTER YADEVANAGARI LE" +
"TTER RADEVANAGARI LETTER RRADEVANAGARI LETTER LADEVANAGARI LETTER LLADEV" +
"ANAGARI LETTER LLLADEVANAGARI LETTER VADEVANAGARI LETTER SHADEVANAGARI L" +
"ETTER SSADEVANAGARI LETTER SADEVANAGARI LETTER HADEVANAGARI VOWEL SIGN O" +
"EDEVANAGARI VOWEL SIGN OOEDEVANAGARI SIGN NUKTADEVANAGARI SIGN AVAGRAHAD" +
"EVANAGARI VOWEL SIGN AADEVANAGARI VOWEL SIGN IDEVANAGARI VOWEL SIGN IIDE" +
"VANAGARI VOWEL SIGN UDEVANAGARI VOWEL SIGN UUDEVANAGARI VOWEL SIGN VOCAL" +
"IC RDEVANAGARI VOWEL SIGN VOCALIC RRDEVANAGARI VOWEL SIGN CANDRA EDEVANA" +
"GARI VOWEL SIGN SHORT EDEVANAGARI VOWEL SIGN EDEVANAGARI VOWEL SIGN AIDE" +
"VANAGARI VOWEL SIGN CANDRA ODEVANAGARI VOWEL SIGN SHORT ODEVANAGARI VOWE" +
"L SIGN ODEVANAGARI VOWEL SIGN AUDEVANAGARI SIGN VIRAMADEVANAGARI VOWEL S" +
"IGN PRISHTHAMATRA EDEVANAGARI VOWEL SIGN AWDEVANAGARI OMDEVANAGARI STRES" +
"S SIGN UDATTADEVANAGARI STRESS SIGN ANUDATTADEVANAGARI GRAVE ACCENTDEVAN" +
"AGARI ACUTE ACCENTDEVANAGARI VOWEL SIGN CANDRA LONG EDEVANAGARI VOWEL SI" +
"GN UEDEVANAGARI VOWEL SIGN UUEDEVANAGARI LETTER QADEVANAGARI LETTER KHHA" +
"DEVANAGARI LETTER GHHADEVANAGARI LETTER ZADEVANAGARI LETTER DDDHADEVANAG" +
"ARI LETTER RHADEVANAGARI LETTER FADEVANAGARI LETTER YYADEVANAGARI LETTER" +
" VOCALIC RRDEVANAGARI LETTER VOCALIC LLDEVANAGARI VOWEL SIGN VOCALIC LDE" +
"VANAGARI VOWEL SIGN VOCALIC LLDEVANAGARI DANDADEVANAGARI DOUBLE DANDADEV" +
"ANAGARI DIGIT ZERODEVANAGARI DIGIT ONEDEVANAGARI DIGIT TWODEVANAGARI DIG" +
"IT THREEDEVANAGARI DIGIT FOURDEVANAGARI DIGIT FIVEDEVANAGARI DIGIT SIXDE" +
"VANAGARI DIGIT SEVENDEVANAGARI DIGIT EIGHTDEVANAGARI DIGIT NINEDEVANAGAR" +
"I ABBREVIATION SIGNDEVANAGARI SIGN HIGH SPACING DOTDEVANAGARI LETTER CAN" +
"DRA ADEVANAGARI LETTER OEDEVANAGARI LETTER OOEDEVANAGARI LETTER AWDEVANA" +
"GARI LETTER UEDEVANAGARI LETTER UUEDEVANAGARI LETTER MARWARI DDADEVANAGA" +
"RI LETTER ZHADEVANAGARI LETTER HEAVY YADEVANAGARI LETTER GGADEVANAGARI L" +
"ETTER JJADEVANAGARI LETTER GLOTTAL STOPDEVANAGARI LETTER DDDADEVANAGARI " +
"LETTER BBABENGALI ANJIBENGALI SIGN CANDRABINDUBENGALI SIGN ANUSVARABENGA" +
"LI SIGN VISARGABENGALI LETTER ABENGALI LETTER AABENGALI LETTER IBENGALI " +
"LETTER IIBENGALI LETTER UBENGALI LETTER UUBENGALI LETTER VOCALIC RBENGAL" +
"I LETTER VOCALIC LBENGALI LETTER EBENGALI LETTER AIBENGALI LETTER OBENGA") + ("" +
"LI LETTER AUBENGALI LETTER KABENGALI LETTER KHABENGALI LETTER GABENGALI " +
"LETTER GHABENGALI LETTER NGABENGALI LETTER CABENGALI LETTER CHABENGALI L" +
"ETTER JABENGALI LETTER JHABENGALI LETTER NYABENGALI LETTER TTABENGALI LE" +
"TTER TTHABENGALI LETTER DDABENGALI LETTER DDHABENGALI LETTER NNABENGALI " +
"LETTER TABENGALI LETTER THABENGALI LETTER DABENGALI LETTER DHABENGALI LE" +
"TTER NABENGALI LETTER PABENGALI LETTER PHABENGALI LETTER BABENGALI LETTE" +
"R BHABENGALI LETTER MABENGALI LETTER YABENGALI LETTER RABENGALI LETTER L" +
"ABENGALI LETTER SHABENGALI LETTER SSABENGALI LETTER SABENGALI LETTER HAB" +
"ENGALI SIGN NUKTABENGALI SIGN AVAGRAHABENGALI VOWEL SIGN AABENGALI VOWEL" +
" SIGN IBENGALI VOWEL SIGN IIBENGALI VOWEL SIGN UBENGALI VOWEL SIGN UUBEN" +
"GALI VOWEL SIGN VOCALIC RBENGALI VOWEL SIGN VOCALIC RRBENGALI VOWEL SIGN" +
" EBENGALI VOWEL SIGN AIBENGALI VOWEL SIGN OBENGALI VOWEL SIGN AUBENGALI " +
"SIGN VIRAMABENGALI LETTER KHANDA TABENGALI AU LENGTH MARKBENGALI LETTER " +
"RRABENGALI LETTER RHABENGALI LETTER YYABENGALI LETTER VOCALIC RRBENGALI " +
"LETTER VOCALIC LLBENGALI VOWEL SIGN VOCALIC LBENGALI VOWEL SIGN VOCALIC " +
"LLBENGALI DIGIT ZEROBENGALI DIGIT ONEBENGALI DIGIT TWOBENGALI DIGIT THRE" +
"EBENGALI DIGIT FOURBENGALI DIGIT FIVEBENGALI DIGIT SIXBENGALI DIGIT SEVE" +
"NBENGALI DIGIT EIGHTBENGALI DIGIT NINEBENGALI LETTER RA WITH MIDDLE DIAG" +
"ONALBENGALI LETTER RA WITH LOWER DIAGONALBENGALI RUPEE MARKBENGALI RUPEE" +
" SIGNBENGALI CURRENCY NUMERATOR ONEBENGALI CURRENCY NUMERATOR TWOBENGALI" +
" CURRENCY NUMERATOR THREEBENGALI CURRENCY NUMERATOR FOURBENGALI CURRENCY" +
" NUMERATOR ONE LESS THAN THE DENOMINATORBENGALI CURRENCY DENOMINATOR SIX" +
"TEENBENGALI ISSHARBENGALI GANDA MARKBENGALI LETTER VEDIC ANUSVARABENGALI" +
" ABBREVIATION SIGNBENGALI SANDHI MARKGURMUKHI SIGN ADAK BINDIGURMUKHI SI" +
"GN BINDIGURMUKHI SIGN VISARGAGURMUKHI LETTER AGURMUKHI LETTER AAGURMUKHI" +
" LETTER IGURMUKHI LETTER IIGURMUKHI LETTER UGURMUKHI LETTER UUGURMUKHI L" +
"ETTER EEGURMUKHI LETTER AIGURMUKHI LETTER OOGURMUKHI LETTER AUGURMUKHI L" +
"ETTER KAGURMUKHI LETTER KHAGURMUKHI LETTER GAGURMUKHI LETTER GHAGURMUKHI" +
" LETTER NGAGURMUKHI LETTER CAGURMUKHI LETTER CHAGURMUKHI LETTER JAGURMUK" +
"HI LETTER JHAGURMUKHI LETTER NYAGURMUKHI LETTER TTAGURMUKHI LETTER TTHAG" +
"URMUKHI LETTER DDAGURMUKHI LETTER DDHAGURMUKHI LETTER NNAGURMUKHI LETTER" +
" TAGURMUKHI LETTER THAGURMUKHI LETTER DAGURMUKHI LETTER DHAGURMUKHI LETT" +
"ER NAGURMUKHI LETTER PAGURMUKHI LETTER PHAGURMUKHI LETTER BAGURMUKHI LET" +
"TER BHAGURMUKHI LETTER MAGURMUKHI LETTER YAGURMUKHI LETTER RAGURMUKHI LE" +
"TTER LAGURMUKHI LETTER LLAGURMUKHI LETTER VAGURMUKHI LETTER SHAGURMUKHI " +
"LETTER SAGURMUKHI LETTER HAGURMUKHI SIGN NUKTAGURMUKHI VOWEL SIGN AAGURM" +
"UKHI VOWEL SIGN IGURMUKHI VOWEL SIGN IIGURMUKHI VOWEL SIGN UGURMUKHI VOW" +
"EL SIGN UUGURMUKHI VOWEL SIGN EEGURMUKHI VOWEL SIGN AIGURMUKHI VOWEL SIG" +
"N OOGURMUKHI VOWEL SIGN AUGURMUKHI SIGN VIRAMAGURMUKHI SIGN UDAATGURMUKH" +
"I LETTER KHHAGURMUKHI LETTER GHHAGURMUKHI LETTER ZAGURMUKHI LETTER RRAGU" +
"RMUKHI LETTER FAGURMUKHI DIGIT ZEROGURMUKHI DIGIT ONEGURMUKHI DIGIT TWOG" +
"URMUKHI DIGIT THREEGURMUKHI DIGIT FOURGURMUKHI DIGIT FIVEGURMUKHI DIGIT " +
"SIXGURMUKHI DIGIT SEVENGURMUKHI DIGIT EIGHTGURMUKHI DIGIT NINEGURMUKHI T" +
"IPPIGURMUKHI ADDAKGURMUKHI IRIGURMUKHI URAGURMUKHI EK ONKARGURMUKHI SIGN" +
" YAKASHGURMUKHI ABBREVIATION SIGNGUJARATI SIGN CANDRABINDUGUJARATI SIGN " +
"ANUSVARAGUJARATI SIGN VISARGAGUJARATI LETTER AGUJARATI LETTER AAGUJARATI" +
" LETTER IGUJARATI LETTER IIGUJARATI LETTER UGUJARATI LETTER UUGUJARATI L" +
"ETTER VOCALIC RGUJARATI LETTER VOCALIC LGUJARATI VOWEL CANDRA EGUJARATI " +
"LETTER EGUJARATI LETTER AIGUJARATI VOWEL CANDRA OGUJARATI LETTER OGUJARA" +
"TI LETTER AUGUJARATI LETTER KAGUJARATI LETTER KHAGUJARATI LETTER GAGUJAR" +
"ATI LETTER GHAGUJARATI LETTER NGAGUJARATI LETTER CAGUJARATI LETTER CHAGU" +
"JARATI LETTER JAGUJARATI LETTER JHAGUJARATI LETTER NYAGUJARATI LETTER TT" +
"AGUJARATI LETTER TTHAGUJARATI LETTER DDAGUJARATI LETTER DDHAGUJARATI LET" +
"TER NNAGUJARATI LETTER TAGUJARATI LETTER THAGUJARATI LETTER DAGUJARATI L" +
"ETTER DHAGUJARATI LETTER NAGUJARATI LETTER PAGUJARATI LETTER PHAGUJARATI" +
" LETTER BAGUJARATI LETTER BHAGUJARATI LETTER MAGUJARATI LETTER YAGUJARAT" +
"I LETTER RAGUJARATI LETTER LAGUJARATI LETTER LLAGUJARATI LETTER VAGUJARA" +
"TI LETTER SHAGUJARATI LETTER SSAGUJARATI LETTER SAGUJARATI LETTER HAGUJA" +
"RATI SIGN NUKTAGUJARATI SIGN AVAGRAHAGUJARATI VOWEL SIGN AAGUJARATI VOWE" +
"L SIGN IGUJARATI VOWEL SIGN IIGUJARATI VOWEL SIGN UGUJARATI VOWEL SIGN U" +
"UGUJARATI VOWEL SIGN VOCALIC RGUJARATI VOWEL SIGN VOCALIC RRGUJARATI VOW" +
"EL SIGN CANDRA EGUJARATI VOWEL SIGN EGUJARATI VOWEL SIGN AIGUJARATI VOWE" +
"L SIGN CANDRA OGUJARATI VOWEL SIGN OGUJARATI VOWEL SIGN AUGUJARATI SIGN " +
"VIRAMAGUJARATI OMGUJARATI LETTER VOCALIC RRGUJARATI LETTER VOCALIC LLGUJ") + ("" +
"ARATI VOWEL SIGN VOCALIC LGUJARATI VOWEL SIGN VOCALIC LLGUJARATI DIGIT Z" +
"EROGUJARATI DIGIT ONEGUJARATI DIGIT TWOGUJARATI DIGIT THREEGUJARATI DIGI" +
"T FOURGUJARATI DIGIT FIVEGUJARATI DIGIT SIXGUJARATI DIGIT SEVENGUJARATI " +
"DIGIT EIGHTGUJARATI DIGIT NINEGUJARATI ABBREVIATION SIGNGUJARATI RUPEE S" +
"IGNGUJARATI LETTER ZHAGUJARATI SIGN SUKUNGUJARATI SIGN SHADDAGUJARATI SI" +
"GN MADDAHGUJARATI SIGN THREE-DOT NUKTA ABOVEGUJARATI SIGN CIRCLE NUKTA A" +
"BOVEGUJARATI SIGN TWO-CIRCLE NUKTA ABOVEORIYA SIGN CANDRABINDUORIYA SIGN" +
" ANUSVARAORIYA SIGN VISARGAORIYA LETTER AORIYA LETTER AAORIYA LETTER IOR" +
"IYA LETTER IIORIYA LETTER UORIYA LETTER UUORIYA LETTER VOCALIC RORIYA LE" +
"TTER VOCALIC LORIYA LETTER EORIYA LETTER AIORIYA LETTER OORIYA LETTER AU" +
"ORIYA LETTER KAORIYA LETTER KHAORIYA LETTER GAORIYA LETTER GHAORIYA LETT" +
"ER NGAORIYA LETTER CAORIYA LETTER CHAORIYA LETTER JAORIYA LETTER JHAORIY" +
"A LETTER NYAORIYA LETTER TTAORIYA LETTER TTHAORIYA LETTER DDAORIYA LETTE" +
"R DDHAORIYA LETTER NNAORIYA LETTER TAORIYA LETTER THAORIYA LETTER DAORIY" +
"A LETTER DHAORIYA LETTER NAORIYA LETTER PAORIYA LETTER PHAORIYA LETTER B" +
"AORIYA LETTER BHAORIYA LETTER MAORIYA LETTER YAORIYA LETTER RAORIYA LETT" +
"ER LAORIYA LETTER LLAORIYA LETTER VAORIYA LETTER SHAORIYA LETTER SSAORIY" +
"A LETTER SAORIYA LETTER HAORIYA SIGN NUKTAORIYA SIGN AVAGRAHAORIYA VOWEL" +
" SIGN AAORIYA VOWEL SIGN IORIYA VOWEL SIGN IIORIYA VOWEL SIGN UORIYA VOW" +
"EL SIGN UUORIYA VOWEL SIGN VOCALIC RORIYA VOWEL SIGN VOCALIC RRORIYA VOW" +
"EL SIGN EORIYA VOWEL SIGN AIORIYA VOWEL SIGN OORIYA VOWEL SIGN AUORIYA S" +
"IGN VIRAMAORIYA SIGN OVERLINEORIYA AI LENGTH MARKORIYA AU LENGTH MARKORI" +
"YA LETTER RRAORIYA LETTER RHAORIYA LETTER YYAORIYA LETTER VOCALIC RRORIY" +
"A LETTER VOCALIC LLORIYA VOWEL SIGN VOCALIC LORIYA VOWEL SIGN VOCALIC LL" +
"ORIYA DIGIT ZEROORIYA DIGIT ONEORIYA DIGIT TWOORIYA DIGIT THREEORIYA DIG" +
"IT FOURORIYA DIGIT FIVEORIYA DIGIT SIXORIYA DIGIT SEVENORIYA DIGIT EIGHT" +
"ORIYA DIGIT NINEORIYA ISSHARORIYA LETTER WAORIYA FRACTION ONE QUARTERORI" +
"YA FRACTION ONE HALFORIYA FRACTION THREE QUARTERSORIYA FRACTION ONE SIXT" +
"EENTHORIYA FRACTION ONE EIGHTHORIYA FRACTION THREE SIXTEENTHSTAMIL SIGN " +
"ANUSVARATAMIL SIGN VISARGATAMIL LETTER ATAMIL LETTER AATAMIL LETTER ITAM" +
"IL LETTER IITAMIL LETTER UTAMIL LETTER UUTAMIL LETTER ETAMIL LETTER EETA" +
"MIL LETTER AITAMIL LETTER OTAMIL LETTER OOTAMIL LETTER AUTAMIL LETTER KA" +
"TAMIL LETTER NGATAMIL LETTER CATAMIL LETTER JATAMIL LETTER NYATAMIL LETT" +
"ER TTATAMIL LETTER NNATAMIL LETTER TATAMIL LETTER NATAMIL LETTER NNNATAM" +
"IL LETTER PATAMIL LETTER MATAMIL LETTER YATAMIL LETTER RATAMIL LETTER RR" +
"ATAMIL LETTER LATAMIL LETTER LLATAMIL LETTER LLLATAMIL LETTER VATAMIL LE" +
"TTER SHATAMIL LETTER SSATAMIL LETTER SATAMIL LETTER HATAMIL VOWEL SIGN A" +
"ATAMIL VOWEL SIGN ITAMIL VOWEL SIGN IITAMIL VOWEL SIGN UTAMIL VOWEL SIGN" +
" UUTAMIL VOWEL SIGN ETAMIL VOWEL SIGN EETAMIL VOWEL SIGN AITAMIL VOWEL S" +
"IGN OTAMIL VOWEL SIGN OOTAMIL VOWEL SIGN AUTAMIL SIGN VIRAMATAMIL OMTAMI" +
"L AU LENGTH MARKTAMIL DIGIT ZEROTAMIL DIGIT ONETAMIL DIGIT TWOTAMIL DIGI" +
"T THREETAMIL DIGIT FOURTAMIL DIGIT FIVETAMIL DIGIT SIXTAMIL DIGIT SEVENT" +
"AMIL DIGIT EIGHTTAMIL DIGIT NINETAMIL NUMBER TENTAMIL NUMBER ONE HUNDRED" +
"TAMIL NUMBER ONE THOUSANDTAMIL DAY SIGNTAMIL MONTH SIGNTAMIL YEAR SIGNTA" +
"MIL DEBIT SIGNTAMIL CREDIT SIGNTAMIL AS ABOVE SIGNTAMIL RUPEE SIGNTAMIL " +
"NUMBER SIGNTELUGU SIGN COMBINING CANDRABINDU ABOVETELUGU SIGN CANDRABIND" +
"UTELUGU SIGN ANUSVARATELUGU SIGN VISARGATELUGU SIGN COMBINING ANUSVARA A" +
"BOVETELUGU LETTER ATELUGU LETTER AATELUGU LETTER ITELUGU LETTER IITELUGU" +
" LETTER UTELUGU LETTER UUTELUGU LETTER VOCALIC RTELUGU LETTER VOCALIC LT" +
"ELUGU LETTER ETELUGU LETTER EETELUGU LETTER AITELUGU LETTER OTELUGU LETT" +
"ER OOTELUGU LETTER AUTELUGU LETTER KATELUGU LETTER KHATELUGU LETTER GATE" +
"LUGU LETTER GHATELUGU LETTER NGATELUGU LETTER CATELUGU LETTER CHATELUGU " +
"LETTER JATELUGU LETTER JHATELUGU LETTER NYATELUGU LETTER TTATELUGU LETTE" +
"R TTHATELUGU LETTER DDATELUGU LETTER DDHATELUGU LETTER NNATELUGU LETTER " +
"TATELUGU LETTER THATELUGU LETTER DATELUGU LETTER DHATELUGU LETTER NATELU" +
"GU LETTER PATELUGU LETTER PHATELUGU LETTER BATELUGU LETTER BHATELUGU LET" +
"TER MATELUGU LETTER YATELUGU LETTER RATELUGU LETTER RRATELUGU LETTER LAT" +
"ELUGU LETTER LLATELUGU LETTER LLLATELUGU LETTER VATELUGU LETTER SHATELUG" +
"U LETTER SSATELUGU LETTER SATELUGU LETTER HATELUGU SIGN NUKTATELUGU SIGN" +
" AVAGRAHATELUGU VOWEL SIGN AATELUGU VOWEL SIGN ITELUGU VOWEL SIGN IITELU" +
"GU VOWEL SIGN UTELUGU VOWEL SIGN UUTELUGU VOWEL SIGN VOCALIC RTELUGU VOW" +
"EL SIGN VOCALIC RRTELUGU VOWEL SIGN ETELUGU VOWEL SIGN EETELUGU VOWEL SI" +
"GN AITELUGU VOWEL SIGN OTELUGU VOWEL SIGN OOTELUGU VOWEL SIGN AUTELUGU S" +
"IGN VIRAMATELUGU LENGTH MARKTELUGU AI LENGTH MARKTELUGU LETTER TSATELUGU") + ("" +
" LETTER DZATELUGU LETTER RRRATELUGU LETTER NAKAARA POLLUTELUGU LETTER VO" +
"CALIC RRTELUGU LETTER VOCALIC LLTELUGU VOWEL SIGN VOCALIC LTELUGU VOWEL " +
"SIGN VOCALIC LLTELUGU DIGIT ZEROTELUGU DIGIT ONETELUGU DIGIT TWOTELUGU D" +
"IGIT THREETELUGU DIGIT FOURTELUGU DIGIT FIVETELUGU DIGIT SIXTELUGU DIGIT" +
" SEVENTELUGU DIGIT EIGHTTELUGU DIGIT NINETELUGU SIGN SIDDHAMTELUGU FRACT" +
"ION DIGIT ZERO FOR ODD POWERS OF FOURTELUGU FRACTION DIGIT ONE FOR ODD P" +
"OWERS OF FOURTELUGU FRACTION DIGIT TWO FOR ODD POWERS OF FOURTELUGU FRAC" +
"TION DIGIT THREE FOR ODD POWERS OF FOURTELUGU FRACTION DIGIT ONE FOR EVE" +
"N POWERS OF FOURTELUGU FRACTION DIGIT TWO FOR EVEN POWERS OF FOURTELUGU " +
"FRACTION DIGIT THREE FOR EVEN POWERS OF FOURTELUGU SIGN TUUMUKANNADA SIG" +
"N SPACING CANDRABINDUKANNADA SIGN CANDRABINDUKANNADA SIGN ANUSVARAKANNAD" +
"A SIGN VISARGAKANNADA SIGN SIDDHAMKANNADA LETTER AKANNADA LETTER AAKANNA" +
"DA LETTER IKANNADA LETTER IIKANNADA LETTER UKANNADA LETTER UUKANNADA LET" +
"TER VOCALIC RKANNADA LETTER VOCALIC LKANNADA LETTER EKANNADA LETTER EEKA" +
"NNADA LETTER AIKANNADA LETTER OKANNADA LETTER OOKANNADA LETTER AUKANNADA" +
" LETTER KAKANNADA LETTER KHAKANNADA LETTER GAKANNADA LETTER GHAKANNADA L" +
"ETTER NGAKANNADA LETTER CAKANNADA LETTER CHAKANNADA LETTER JAKANNADA LET" +
"TER JHAKANNADA LETTER NYAKANNADA LETTER TTAKANNADA LETTER TTHAKANNADA LE" +
"TTER DDAKANNADA LETTER DDHAKANNADA LETTER NNAKANNADA LETTER TAKANNADA LE" +
"TTER THAKANNADA LETTER DAKANNADA LETTER DHAKANNADA LETTER NAKANNADA LETT" +
"ER PAKANNADA LETTER PHAKANNADA LETTER BAKANNADA LETTER BHAKANNADA LETTER" +
" MAKANNADA LETTER YAKANNADA LETTER RAKANNADA LETTER RRAKANNADA LETTER LA" +
"KANNADA LETTER LLAKANNADA LETTER VAKANNADA LETTER SHAKANNADA LETTER SSAK" +
"ANNADA LETTER SAKANNADA LETTER HAKANNADA SIGN NUKTAKANNADA SIGN AVAGRAHA" +
"KANNADA VOWEL SIGN AAKANNADA VOWEL SIGN IKANNADA VOWEL SIGN IIKANNADA VO" +
"WEL SIGN UKANNADA VOWEL SIGN UUKANNADA VOWEL SIGN VOCALIC RKANNADA VOWEL" +
" SIGN VOCALIC RRKANNADA VOWEL SIGN EKANNADA VOWEL SIGN EEKANNADA VOWEL S" +
"IGN AIKANNADA VOWEL SIGN OKANNADA VOWEL SIGN OOKANNADA VOWEL SIGN AUKANN" +
"ADA SIGN VIRAMAKANNADA LENGTH MARKKANNADA AI LENGTH MARKKANNADA LETTER N" +
"AKAARA POLLUKANNADA LETTER FAKANNADA LETTER VOCALIC RRKANNADA LETTER VOC" +
"ALIC LLKANNADA VOWEL SIGN VOCALIC LKANNADA VOWEL SIGN VOCALIC LLKANNADA " +
"DIGIT ZEROKANNADA DIGIT ONEKANNADA DIGIT TWOKANNADA DIGIT THREEKANNADA D" +
"IGIT FOURKANNADA DIGIT FIVEKANNADA DIGIT SIXKANNADA DIGIT SEVENKANNADA D" +
"IGIT EIGHTKANNADA DIGIT NINEKANNADA SIGN JIHVAMULIYAKANNADA SIGN UPADHMA" +
"NIYAKANNADA SIGN COMBINING ANUSVARA ABOVE RIGHTMALAYALAM SIGN COMBINING " +
"ANUSVARA ABOVEMALAYALAM SIGN CANDRABINDUMALAYALAM SIGN ANUSVARAMALAYALAM" +
" SIGN VISARGAMALAYALAM LETTER VEDIC ANUSVARAMALAYALAM LETTER AMALAYALAM " +
"LETTER AAMALAYALAM LETTER IMALAYALAM LETTER IIMALAYALAM LETTER UMALAYALA" +
"M LETTER UUMALAYALAM LETTER VOCALIC RMALAYALAM LETTER VOCALIC LMALAYALAM" +
" LETTER EMALAYALAM LETTER EEMALAYALAM LETTER AIMALAYALAM LETTER OMALAYAL" +
"AM LETTER OOMALAYALAM LETTER AUMALAYALAM LETTER KAMALAYALAM LETTER KHAMA" +
"LAYALAM LETTER GAMALAYALAM LETTER GHAMALAYALAM LETTER NGAMALAYALAM LETTE" +
"R CAMALAYALAM LETTER CHAMALAYALAM LETTER JAMALAYALAM LETTER JHAMALAYALAM" +
" LETTER NYAMALAYALAM LETTER TTAMALAYALAM LETTER TTHAMALAYALAM LETTER DDA" +
"MALAYALAM LETTER DDHAMALAYALAM LETTER NNAMALAYALAM LETTER TAMALAYALAM LE" +
"TTER THAMALAYALAM LETTER DAMALAYALAM LETTER DHAMALAYALAM LETTER NAMALAYA" +
"LAM LETTER NNNAMALAYALAM LETTER PAMALAYALAM LETTER PHAMALAYALAM LETTER B" +
"AMALAYALAM LETTER BHAMALAYALAM LETTER MAMALAYALAM LETTER YAMALAYALAM LET" +
"TER RAMALAYALAM LETTER RRAMALAYALAM LETTER LAMALAYALAM LETTER LLAMALAYAL" +
"AM LETTER LLLAMALAYALAM LETTER VAMALAYALAM LETTER SHAMALAYALAM LETTER SS" +
"AMALAYALAM LETTER SAMALAYALAM LETTER HAMALAYALAM LETTER TTTAMALAYALAM SI" +
"GN VERTICAL BAR VIRAMAMALAYALAM SIGN CIRCULAR VIRAMAMALAYALAM SIGN AVAGR" +
"AHAMALAYALAM VOWEL SIGN AAMALAYALAM VOWEL SIGN IMALAYALAM VOWEL SIGN IIM" +
"ALAYALAM VOWEL SIGN UMALAYALAM VOWEL SIGN UUMALAYALAM VOWEL SIGN VOCALIC" +
" RMALAYALAM VOWEL SIGN VOCALIC RRMALAYALAM VOWEL SIGN EMALAYALAM VOWEL S" +
"IGN EEMALAYALAM VOWEL SIGN AIMALAYALAM VOWEL SIGN OMALAYALAM VOWEL SIGN " +
"OOMALAYALAM VOWEL SIGN AUMALAYALAM SIGN VIRAMAMALAYALAM LETTER DOT REPHM" +
"ALAYALAM SIGN PARAMALAYALAM LETTER CHILLU MMALAYALAM LETTER CHILLU YMALA" +
"YALAM LETTER CHILLU LLLMALAYALAM AU LENGTH MARKMALAYALAM FRACTION ONE ON" +
"E-HUNDRED-AND-SIXTIETHMALAYALAM FRACTION ONE FORTIETHMALAYALAM FRACTION " +
"THREE EIGHTIETHSMALAYALAM FRACTION ONE TWENTIETHMALAYALAM FRACTION ONE T" +
"ENTHMALAYALAM FRACTION THREE TWENTIETHSMALAYALAM FRACTION ONE FIFTHMALAY" +
"ALAM LETTER ARCHAIC IIMALAYALAM LETTER VOCALIC RRMALAYALAM LETTER VOCALI" +
"C LLMALAYALAM VOWEL SIGN VOCALIC LMALAYALAM VOWEL SIGN VOCALIC LLMALAYAL") + ("" +
"AM DIGIT ZEROMALAYALAM DIGIT ONEMALAYALAM DIGIT TWOMALAYALAM DIGIT THREE" +
"MALAYALAM DIGIT FOURMALAYALAM DIGIT FIVEMALAYALAM DIGIT SIXMALAYALAM DIG" +
"IT SEVENMALAYALAM DIGIT EIGHTMALAYALAM DIGIT NINEMALAYALAM NUMBER TENMAL" +
"AYALAM NUMBER ONE HUNDREDMALAYALAM NUMBER ONE THOUSANDMALAYALAM FRACTION" +
" ONE QUARTERMALAYALAM FRACTION ONE HALFMALAYALAM FRACTION THREE QUARTERS" +
"MALAYALAM FRACTION ONE SIXTEENTHMALAYALAM FRACTION ONE EIGHTHMALAYALAM F" +
"RACTION THREE SIXTEENTHSMALAYALAM DATE MARKMALAYALAM LETTER CHILLU NNMAL" +
"AYALAM LETTER CHILLU NMALAYALAM LETTER CHILLU RRMALAYALAM LETTER CHILLU " +
"LMALAYALAM LETTER CHILLU LLMALAYALAM LETTER CHILLU KSINHALA SIGN CANDRAB" +
"INDUSINHALA SIGN ANUSVARAYASINHALA SIGN VISARGAYASINHALA LETTER AYANNASI" +
"NHALA LETTER AAYANNASINHALA LETTER AEYANNASINHALA LETTER AEEYANNASINHALA" +
" LETTER IYANNASINHALA LETTER IIYANNASINHALA LETTER UYANNASINHALA LETTER " +
"UUYANNASINHALA LETTER IRUYANNASINHALA LETTER IRUUYANNASINHALA LETTER ILU" +
"YANNASINHALA LETTER ILUUYANNASINHALA LETTER EYANNASINHALA LETTER EEYANNA" +
"SINHALA LETTER AIYANNASINHALA LETTER OYANNASINHALA LETTER OOYANNASINHALA" +
" LETTER AUYANNASINHALA LETTER ALPAPRAANA KAYANNASINHALA LETTER MAHAAPRAA" +
"NA KAYANNASINHALA LETTER ALPAPRAANA GAYANNASINHALA LETTER MAHAAPRAANA GA" +
"YANNASINHALA LETTER KANTAJA NAASIKYAYASINHALA LETTER SANYAKA GAYANNASINH" +
"ALA LETTER ALPAPRAANA CAYANNASINHALA LETTER MAHAAPRAANA CAYANNASINHALA L" +
"ETTER ALPAPRAANA JAYANNASINHALA LETTER MAHAAPRAANA JAYANNASINHALA LETTER" +
" TAALUJA NAASIKYAYASINHALA LETTER TAALUJA SANYOOGA NAAKSIKYAYASINHALA LE" +
"TTER SANYAKA JAYANNASINHALA LETTER ALPAPRAANA TTAYANNASINHALA LETTER MAH" +
"AAPRAANA TTAYANNASINHALA LETTER ALPAPRAANA DDAYANNASINHALA LETTER MAHAAP" +
"RAANA DDAYANNASINHALA LETTER MUURDHAJA NAYANNASINHALA LETTER SANYAKA DDA" +
"YANNASINHALA LETTER ALPAPRAANA TAYANNASINHALA LETTER MAHAAPRAANA TAYANNA" +
"SINHALA LETTER ALPAPRAANA DAYANNASINHALA LETTER MAHAAPRAANA DAYANNASINHA" +
"LA LETTER DANTAJA NAYANNASINHALA LETTER SANYAKA DAYANNASINHALA LETTER AL" +
"PAPRAANA PAYANNASINHALA LETTER MAHAAPRAANA PAYANNASINHALA LETTER ALPAPRA" +
"ANA BAYANNASINHALA LETTER MAHAAPRAANA BAYANNASINHALA LETTER MAYANNASINHA" +
"LA LETTER AMBA BAYANNASINHALA LETTER YAYANNASINHALA LETTER RAYANNASINHAL" +
"A LETTER DANTAJA LAYANNASINHALA LETTER VAYANNASINHALA LETTER TAALUJA SAY" +
"ANNASINHALA LETTER MUURDHAJA SAYANNASINHALA LETTER DANTAJA SAYANNASINHAL" +
"A LETTER HAYANNASINHALA LETTER MUURDHAJA LAYANNASINHALA LETTER FAYANNASI" +
"NHALA SIGN AL-LAKUNASINHALA VOWEL SIGN AELA-PILLASINHALA VOWEL SIGN KETT" +
"I AEDA-PILLASINHALA VOWEL SIGN DIGA AEDA-PILLASINHALA VOWEL SIGN KETTI I" +
"S-PILLASINHALA VOWEL SIGN DIGA IS-PILLASINHALA VOWEL SIGN KETTI PAA-PILL" +
"ASINHALA VOWEL SIGN DIGA PAA-PILLASINHALA VOWEL SIGN GAETTA-PILLASINHALA" +
" VOWEL SIGN KOMBUVASINHALA VOWEL SIGN DIGA KOMBUVASINHALA VOWEL SIGN KOM" +
"BU DEKASINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLASINHALA VOWEL SIGN KOMBU" +
"VA HAA DIGA AELA-PILLASINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTASINHALA " +
"VOWEL SIGN GAYANUKITTASINHALA LITH DIGIT ZEROSINHALA LITH DIGIT ONESINHA" +
"LA LITH DIGIT TWOSINHALA LITH DIGIT THREESINHALA LITH DIGIT FOURSINHALA " +
"LITH DIGIT FIVESINHALA LITH DIGIT SIXSINHALA LITH DIGIT SEVENSINHALA LIT" +
"H DIGIT EIGHTSINHALA LITH DIGIT NINESINHALA VOWEL SIGN DIGA GAETTA-PILLA" +
"SINHALA VOWEL SIGN DIGA GAYANUKITTASINHALA PUNCTUATION KUNDDALIYATHAI CH" +
"ARACTER KO KAITHAI CHARACTER KHO KHAITHAI CHARACTER KHO KHUATTHAI CHARAC" +
"TER KHO KHWAITHAI CHARACTER KHO KHONTHAI CHARACTER KHO RAKHANGTHAI CHARA" +
"CTER NGO NGUTHAI CHARACTER CHO CHANTHAI CHARACTER CHO CHINGTHAI CHARACTE" +
"R CHO CHANGTHAI CHARACTER SO SOTHAI CHARACTER CHO CHOETHAI CHARACTER YO " +
"YINGTHAI CHARACTER DO CHADATHAI CHARACTER TO PATAKTHAI CHARACTER THO THA" +
"NTHAI CHARACTER THO NANGMONTHOTHAI CHARACTER THO PHUTHAOTHAI CHARACTER N" +
"O NENTHAI CHARACTER DO DEKTHAI CHARACTER TO TAOTHAI CHARACTER THO THUNGT" +
"HAI CHARACTER THO THAHANTHAI CHARACTER THO THONGTHAI CHARACTER NO NUTHAI" +
" CHARACTER BO BAIMAITHAI CHARACTER PO PLATHAI CHARACTER PHO PHUNGTHAI CH" +
"ARACTER FO FATHAI CHARACTER PHO PHANTHAI CHARACTER FO FANTHAI CHARACTER " +
"PHO SAMPHAOTHAI CHARACTER MO MATHAI CHARACTER YO YAKTHAI CHARACTER RO RU" +
"ATHAI CHARACTER RUTHAI CHARACTER LO LINGTHAI CHARACTER LUTHAI CHARACTER " +
"WO WAENTHAI CHARACTER SO SALATHAI CHARACTER SO RUSITHAI CHARACTER SO SUA" +
"THAI CHARACTER HO HIPTHAI CHARACTER LO CHULATHAI CHARACTER O ANGTHAI CHA" +
"RACTER HO NOKHUKTHAI CHARACTER PAIYANNOITHAI CHARACTER SARA ATHAI CHARAC" +
"TER MAI HAN-AKATTHAI CHARACTER SARA AATHAI CHARACTER SARA AMTHAI CHARACT" +
"ER SARA ITHAI CHARACTER SARA IITHAI CHARACTER SARA UETHAI CHARACTER SARA" +
" UEETHAI CHARACTER SARA UTHAI CHARACTER SARA UUTHAI CHARACTER PHINTHUTHA" +
"I CURRENCY SYMBOL BAHTTHAI CHARACTER SARA ETHAI CHARACTER SARA AETHAI CH") + ("" +
"ARACTER SARA OTHAI CHARACTER SARA AI MAIMUANTHAI CHARACTER SARA AI MAIMA" +
"LAITHAI CHARACTER LAKKHANGYAOTHAI CHARACTER MAIYAMOKTHAI CHARACTER MAITA" +
"IKHUTHAI CHARACTER MAI EKTHAI CHARACTER MAI THOTHAI CHARACTER MAI TRITHA" +
"I CHARACTER MAI CHATTAWATHAI CHARACTER THANTHAKHATTHAI CHARACTER NIKHAHI" +
"TTHAI CHARACTER YAMAKKANTHAI CHARACTER FONGMANTHAI DIGIT ZEROTHAI DIGIT " +
"ONETHAI DIGIT TWOTHAI DIGIT THREETHAI DIGIT FOURTHAI DIGIT FIVETHAI DIGI" +
"T SIXTHAI DIGIT SEVENTHAI DIGIT EIGHTTHAI DIGIT NINETHAI CHARACTER ANGKH" +
"ANKHUTHAI CHARACTER KHOMUTLAO LETTER KOLAO LETTER KHO SUNGLAO LETTER KHO" +
" TAMLAO LETTER PALI GHALAO LETTER NGOLAO LETTER COLAO LETTER PALI CHALAO" +
" LETTER SO TAMLAO LETTER PALI JHALAO LETTER NYOLAO LETTER PALI NYALAO LE" +
"TTER PALI TTALAO LETTER PALI TTHALAO LETTER PALI DDALAO LETTER PALI DDHA" +
"LAO LETTER PALI NNALAO LETTER DOLAO LETTER TOLAO LETTER THO SUNGLAO LETT" +
"ER THO TAMLAO LETTER PALI DHALAO LETTER NOLAO LETTER BOLAO LETTER POLAO " +
"LETTER PHO SUNGLAO LETTER FO TAMLAO LETTER PHO TAMLAO LETTER FO SUNGLAO " +
"LETTER PALI BHALAO LETTER MOLAO LETTER YOLAO LETTER LO LINGLAO LETTER LO" +
" LOOTLAO LETTER WOLAO LETTER SANSKRIT SHALAO LETTER SANSKRIT SSALAO LETT" +
"ER SO SUNGLAO LETTER HO SUNGLAO LETTER PALI LLALAO LETTER OLAO LETTER HO" +
" TAMLAO ELLIPSISLAO VOWEL SIGN ALAO VOWEL SIGN MAI KANLAO VOWEL SIGN AAL" +
"AO VOWEL SIGN AMLAO VOWEL SIGN ILAO VOWEL SIGN IILAO VOWEL SIGN YLAO VOW" +
"EL SIGN YYLAO VOWEL SIGN ULAO VOWEL SIGN UULAO SIGN PALI VIRAMALAO VOWEL" +
" SIGN MAI KONLAO SEMIVOWEL SIGN LOLAO SEMIVOWEL SIGN NYOLAO VOWEL SIGN E" +
"LAO VOWEL SIGN EILAO VOWEL SIGN OLAO VOWEL SIGN AYLAO VOWEL SIGN AILAO K" +
"O LALAO TONE MAI EKLAO TONE MAI THOLAO TONE MAI TILAO TONE MAI CATAWALAO" +
" CANCELLATION MARKLAO NIGGAHITALAO YAMAKKANLAO DIGIT ZEROLAO DIGIT ONELA" +
"O DIGIT TWOLAO DIGIT THREELAO DIGIT FOURLAO DIGIT FIVELAO DIGIT SIXLAO D" +
"IGIT SEVENLAO DIGIT EIGHTLAO DIGIT NINELAO HO NOLAO HO MOLAO LETTER KHMU" +
" GOLAO LETTER KHMU NYOTIBETAN SYLLABLE OMTIBETAN MARK GTER YIG MGO TRUNC" +
"ATED ATIBETAN MARK GTER YIG MGO -UM RNAM BCAD MATIBETAN MARK GTER YIG MG" +
"O -UM GTER TSHEG MATIBETAN MARK INITIAL YIG MGO MDUN MATIBETAN MARK CLOS" +
"ING YIG MGO SGAB MATIBETAN MARK CARET YIG MGO PHUR SHAD MATIBETAN MARK Y" +
"IG MGO TSHEG SHAD MATIBETAN MARK SBRUL SHADTIBETAN MARK BSKUR YIG MGOTIB" +
"ETAN MARK BKA- SHOG YIG MGOTIBETAN MARK INTERSYLLABIC TSHEGTIBETAN MARK " +
"DELIMITER TSHEG BSTARTIBETAN MARK SHADTIBETAN MARK NYIS SHADTIBETAN MARK" +
" TSHEG SHADTIBETAN MARK NYIS TSHEG SHADTIBETAN MARK RIN CHEN SPUNGS SHAD" +
"TIBETAN MARK RGYA GRAM SHADTIBETAN MARK CARET -DZUD RTAGS ME LONG CANTIB" +
"ETAN MARK GTER TSHEGTIBETAN LOGOTYPE SIGN CHAD RTAGSTIBETAN LOGOTYPE SIG" +
"N LHAG RTAGSTIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGSTIBETAN ASTRO" +
"LOGICAL SIGN -KHYUD PATIBETAN ASTROLOGICAL SIGN SDONG TSHUGSTIBETAN SIGN" +
" RDEL DKAR GCIGTIBETAN SIGN RDEL DKAR GNYISTIBETAN SIGN RDEL DKAR GSUMTI" +
"BETAN SIGN RDEL NAG GCIGTIBETAN SIGN RDEL NAG GNYISTIBETAN SIGN RDEL DKA" +
"R RDEL NAGTIBETAN DIGIT ZEROTIBETAN DIGIT ONETIBETAN DIGIT TWOTIBETAN DI" +
"GIT THREETIBETAN DIGIT FOURTIBETAN DIGIT FIVETIBETAN DIGIT SIXTIBETAN DI" +
"GIT SEVENTIBETAN DIGIT EIGHTTIBETAN DIGIT NINETIBETAN DIGIT HALF ONETIBE" +
"TAN DIGIT HALF TWOTIBETAN DIGIT HALF THREETIBETAN DIGIT HALF FOURTIBETAN" +
" DIGIT HALF FIVETIBETAN DIGIT HALF SIXTIBETAN DIGIT HALF SEVENTIBETAN DI" +
"GIT HALF EIGHTTIBETAN DIGIT HALF NINETIBETAN DIGIT HALF ZEROTIBETAN MARK" +
" BSDUS RTAGSTIBETAN MARK NGAS BZUNG NYI ZLATIBETAN MARK CARET -DZUD RTAG" +
"S BZHI MIG CANTIBETAN MARK NGAS BZUNG SGOR RTAGSTIBETAN MARK CHE MGOTIBE" +
"TAN MARK TSA -PHRUTIBETAN MARK GUG RTAGS GYONTIBETAN MARK GUG RTAGS GYAS" +
"TIBETAN MARK ANG KHANG GYONTIBETAN MARK ANG KHANG GYASTIBETAN SIGN YAR T" +
"SHESTIBETAN SIGN MAR TSHESTIBETAN LETTER KATIBETAN LETTER KHATIBETAN LET" +
"TER GATIBETAN LETTER GHATIBETAN LETTER NGATIBETAN LETTER CATIBETAN LETTE" +
"R CHATIBETAN LETTER JATIBETAN LETTER NYATIBETAN LETTER TTATIBETAN LETTER" +
" TTHATIBETAN LETTER DDATIBETAN LETTER DDHATIBETAN LETTER NNATIBETAN LETT" +
"ER TATIBETAN LETTER THATIBETAN LETTER DATIBETAN LETTER DHATIBETAN LETTER" +
" NATIBETAN LETTER PATIBETAN LETTER PHATIBETAN LETTER BATIBETAN LETTER BH" +
"ATIBETAN LETTER MATIBETAN LETTER TSATIBETAN LETTER TSHATIBETAN LETTER DZ" +
"ATIBETAN LETTER DZHATIBETAN LETTER WATIBETAN LETTER ZHATIBETAN LETTER ZA" +
"TIBETAN LETTER -ATIBETAN LETTER YATIBETAN LETTER RATIBETAN LETTER LATIBE" +
"TAN LETTER SHATIBETAN LETTER SSATIBETAN LETTER SATIBETAN LETTER HATIBETA" +
"N LETTER ATIBETAN LETTER KSSATIBETAN LETTER FIXED-FORM RATIBETAN LETTER " +
"KKATIBETAN LETTER RRATIBETAN VOWEL SIGN AATIBETAN VOWEL SIGN ITIBETAN VO" +
"WEL SIGN IITIBETAN VOWEL SIGN UTIBETAN VOWEL SIGN UUTIBETAN VOWEL SIGN V" +
"OCALIC RTIBETAN VOWEL SIGN VOCALIC RRTIBETAN VOWEL SIGN VOCALIC LTIBETAN") + ("" +
" VOWEL SIGN VOCALIC LLTIBETAN VOWEL SIGN ETIBETAN VOWEL SIGN EETIBETAN V" +
"OWEL SIGN OTIBETAN VOWEL SIGN OOTIBETAN SIGN RJES SU NGA ROTIBETAN SIGN " +
"RNAM BCADTIBETAN VOWEL SIGN REVERSED ITIBETAN VOWEL SIGN REVERSED IITIBE" +
"TAN SIGN NYI ZLA NAA DATIBETAN SIGN SNA LDANTIBETAN MARK HALANTATIBETAN " +
"MARK PALUTATIBETAN SIGN LCI RTAGSTIBETAN SIGN YANG RTAGSTIBETAN SIGN LCE" +
" TSA CANTIBETAN SIGN MCHU CANTIBETAN SIGN GRU CAN RGYINGSTIBETAN SIGN GR" +
"U MED RGYINGSTIBETAN SIGN INVERTED MCHU CANTIBETAN SUBJOINED SIGN LCE TS" +
"A CANTIBETAN SUBJOINED SIGN MCHU CANTIBETAN SUBJOINED SIGN INVERTED MCHU" +
" CANTIBETAN SUBJOINED LETTER KATIBETAN SUBJOINED LETTER KHATIBETAN SUBJO" +
"INED LETTER GATIBETAN SUBJOINED LETTER GHATIBETAN SUBJOINED LETTER NGATI" +
"BETAN SUBJOINED LETTER CATIBETAN SUBJOINED LETTER CHATIBETAN SUBJOINED L" +
"ETTER JATIBETAN SUBJOINED LETTER NYATIBETAN SUBJOINED LETTER TTATIBETAN " +
"SUBJOINED LETTER TTHATIBETAN SUBJOINED LETTER DDATIBETAN SUBJOINED LETTE" +
"R DDHATIBETAN SUBJOINED LETTER NNATIBETAN SUBJOINED LETTER TATIBETAN SUB" +
"JOINED LETTER THATIBETAN SUBJOINED LETTER DATIBETAN SUBJOINED LETTER DHA" +
"TIBETAN SUBJOINED LETTER NATIBETAN SUBJOINED LETTER PATIBETAN SUBJOINED " +
"LETTER PHATIBETAN SUBJOINED LETTER BATIBETAN SUBJOINED LETTER BHATIBETAN" +
" SUBJOINED LETTER MATIBETAN SUBJOINED LETTER TSATIBETAN SUBJOINED LETTER" +
" TSHATIBETAN SUBJOINED LETTER DZATIBETAN SUBJOINED LETTER DZHATIBETAN SU" +
"BJOINED LETTER WATIBETAN SUBJOINED LETTER ZHATIBETAN SUBJOINED LETTER ZA" +
"TIBETAN SUBJOINED LETTER -ATIBETAN SUBJOINED LETTER YATIBETAN SUBJOINED " +
"LETTER RATIBETAN SUBJOINED LETTER LATIBETAN SUBJOINED LETTER SHATIBETAN " +
"SUBJOINED LETTER SSATIBETAN SUBJOINED LETTER SATIBETAN SUBJOINED LETTER " +
"HATIBETAN SUBJOINED LETTER ATIBETAN SUBJOINED LETTER KSSATIBETAN SUBJOIN" +
"ED LETTER FIXED-FORM WATIBETAN SUBJOINED LETTER FIXED-FORM YATIBETAN SUB" +
"JOINED LETTER FIXED-FORM RATIBETAN KU RU KHATIBETAN KU RU KHA BZHI MIG C" +
"ANTIBETAN CANTILLATION SIGN HEAVY BEATTIBETAN CANTILLATION SIGN LIGHT BE" +
"ATTIBETAN CANTILLATION SIGN CANG TE-UTIBETAN CANTILLATION SIGN SBUB -CHA" +
"LTIBETAN SYMBOL DRIL BUTIBETAN SYMBOL RDO RJETIBETAN SYMBOL PADMA GDANTI" +
"BETAN SYMBOL RDO RJE RGYA GRAMTIBETAN SYMBOL PHUR PATIBETAN SYMBOL NOR B" +
"UTIBETAN SYMBOL NOR BU NYIS -KHYILTIBETAN SYMBOL NOR BU GSUM -KHYILTIBET" +
"AN SYMBOL NOR BU BZHI -KHYILTIBETAN SIGN RDEL NAG RDEL DKARTIBETAN SIGN " +
"RDEL NAG GSUMTIBETAN MARK BSKA- SHOG GI MGO RGYANTIBETAN MARK MNYAM YIG " +
"GI MGO RGYANTIBETAN MARK NYIS TSHEGTIBETAN MARK INITIAL BRDA RNYING YIG " +
"MGO MDUN MATIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MARIGHT-FACING " +
"SVASTI SIGNLEFT-FACING SVASTI SIGNRIGHT-FACING SVASTI SIGN WITH DOTSLEFT" +
"-FACING SVASTI SIGN WITH DOTSTIBETAN MARK LEADING MCHAN RTAGSTIBETAN MAR" +
"K TRAILING MCHAN RTAGSMYANMAR LETTER KAMYANMAR LETTER KHAMYANMAR LETTER " +
"GAMYANMAR LETTER GHAMYANMAR LETTER NGAMYANMAR LETTER CAMYANMAR LETTER CH" +
"AMYANMAR LETTER JAMYANMAR LETTER JHAMYANMAR LETTER NYAMYANMAR LETTER NNY" +
"AMYANMAR LETTER TTAMYANMAR LETTER TTHAMYANMAR LETTER DDAMYANMAR LETTER D" +
"DHAMYANMAR LETTER NNAMYANMAR LETTER TAMYANMAR LETTER THAMYANMAR LETTER D" +
"AMYANMAR LETTER DHAMYANMAR LETTER NAMYANMAR LETTER PAMYANMAR LETTER PHAM" +
"YANMAR LETTER BAMYANMAR LETTER BHAMYANMAR LETTER MAMYANMAR LETTER YAMYAN" +
"MAR LETTER RAMYANMAR LETTER LAMYANMAR LETTER WAMYANMAR LETTER SAMYANMAR " +
"LETTER HAMYANMAR LETTER LLAMYANMAR LETTER AMYANMAR LETTER SHAN AMYANMAR " +
"LETTER IMYANMAR LETTER IIMYANMAR LETTER UMYANMAR LETTER UUMYANMAR LETTER" +
" EMYANMAR LETTER MON EMYANMAR LETTER OMYANMAR LETTER AUMYANMAR VOWEL SIG" +
"N TALL AAMYANMAR VOWEL SIGN AAMYANMAR VOWEL SIGN IMYANMAR VOWEL SIGN IIM" +
"YANMAR VOWEL SIGN UMYANMAR VOWEL SIGN UUMYANMAR VOWEL SIGN EMYANMAR VOWE" +
"L SIGN AIMYANMAR VOWEL SIGN MON IIMYANMAR VOWEL SIGN MON OMYANMAR VOWEL " +
"SIGN E ABOVEMYANMAR SIGN ANUSVARAMYANMAR SIGN DOT BELOWMYANMAR SIGN VISA" +
"RGAMYANMAR SIGN VIRAMAMYANMAR SIGN ASATMYANMAR CONSONANT SIGN MEDIAL YAM" +
"YANMAR CONSONANT SIGN MEDIAL RAMYANMAR CONSONANT SIGN MEDIAL WAMYANMAR C" +
"ONSONANT SIGN MEDIAL HAMYANMAR LETTER GREAT SAMYANMAR DIGIT ZEROMYANMAR " +
"DIGIT ONEMYANMAR DIGIT TWOMYANMAR DIGIT THREEMYANMAR DIGIT FOURMYANMAR D" +
"IGIT FIVEMYANMAR DIGIT SIXMYANMAR DIGIT SEVENMYANMAR DIGIT EIGHTMYANMAR " +
"DIGIT NINEMYANMAR SIGN LITTLE SECTIONMYANMAR SIGN SECTIONMYANMAR SYMBOL " +
"LOCATIVEMYANMAR SYMBOL COMPLETEDMYANMAR SYMBOL AFOREMENTIONEDMYANMAR SYM" +
"BOL GENITIVEMYANMAR LETTER SHAMYANMAR LETTER SSAMYANMAR LETTER VOCALIC R" +
"MYANMAR LETTER VOCALIC RRMYANMAR LETTER VOCALIC LMYANMAR LETTER VOCALIC " +
"LLMYANMAR VOWEL SIGN VOCALIC RMYANMAR VOWEL SIGN VOCALIC RRMYANMAR VOWEL" +
" SIGN VOCALIC LMYANMAR VOWEL SIGN VOCALIC LLMYANMAR LETTER MON NGAMYANMA" +
"R LETTER MON JHAMYANMAR LETTER MON BBAMYANMAR LETTER MON BBEMYANMAR CONS") + ("" +
"ONANT SIGN MON MEDIAL NAMYANMAR CONSONANT SIGN MON MEDIAL MAMYANMAR CONS" +
"ONANT SIGN MON MEDIAL LAMYANMAR LETTER SGAW KAREN SHAMYANMAR VOWEL SIGN " +
"SGAW KAREN EUMYANMAR TONE MARK SGAW KAREN HATHIMYANMAR TONE MARK SGAW KA" +
"REN KE PHOMYANMAR LETTER WESTERN PWO KAREN THAMYANMAR LETTER WESTERN PWO" +
" KAREN PWAMYANMAR VOWEL SIGN WESTERN PWO KAREN EUMYANMAR VOWEL SIGN WEST" +
"ERN PWO KAREN UEMYANMAR SIGN WESTERN PWO KAREN TONE-1MYANMAR SIGN WESTER" +
"N PWO KAREN TONE-2MYANMAR SIGN WESTERN PWO KAREN TONE-3MYANMAR SIGN WEST" +
"ERN PWO KAREN TONE-4MYANMAR SIGN WESTERN PWO KAREN TONE-5MYANMAR LETTER " +
"EASTERN PWO KAREN NNAMYANMAR LETTER EASTERN PWO KAREN YWAMYANMAR LETTER " +
"EASTERN PWO KAREN GHWAMYANMAR VOWEL SIGN GEBA KAREN IMYANMAR VOWEL SIGN " +
"KAYAH OEMYANMAR VOWEL SIGN KAYAH UMYANMAR VOWEL SIGN KAYAH EEMYANMAR LET" +
"TER SHAN KAMYANMAR LETTER SHAN KHAMYANMAR LETTER SHAN GAMYANMAR LETTER S" +
"HAN CAMYANMAR LETTER SHAN ZAMYANMAR LETTER SHAN NYAMYANMAR LETTER SHAN D" +
"AMYANMAR LETTER SHAN NAMYANMAR LETTER SHAN PHAMYANMAR LETTER SHAN FAMYAN" +
"MAR LETTER SHAN BAMYANMAR LETTER SHAN THAMYANMAR LETTER SHAN HAMYANMAR C" +
"ONSONANT SIGN SHAN MEDIAL WAMYANMAR VOWEL SIGN SHAN AAMYANMAR VOWEL SIGN" +
" SHAN EMYANMAR VOWEL SIGN SHAN E ABOVEMYANMAR VOWEL SIGN SHAN FINAL YMYA" +
"NMAR SIGN SHAN TONE-2MYANMAR SIGN SHAN TONE-3MYANMAR SIGN SHAN TONE-5MYA" +
"NMAR SIGN SHAN TONE-6MYANMAR SIGN SHAN COUNCIL TONE-2MYANMAR SIGN SHAN C" +
"OUNCIL TONE-3MYANMAR SIGN SHAN COUNCIL EMPHATIC TONEMYANMAR LETTER RUMAI" +
" PALAUNG FAMYANMAR SIGN RUMAI PALAUNG TONE-5MYANMAR SHAN DIGIT ZEROMYANM" +
"AR SHAN DIGIT ONEMYANMAR SHAN DIGIT TWOMYANMAR SHAN DIGIT THREEMYANMAR S" +
"HAN DIGIT FOURMYANMAR SHAN DIGIT FIVEMYANMAR SHAN DIGIT SIXMYANMAR SHAN " +
"DIGIT SEVENMYANMAR SHAN DIGIT EIGHTMYANMAR SHAN DIGIT NINEMYANMAR SIGN K" +
"HAMTI TONE-1MYANMAR SIGN KHAMTI TONE-3MYANMAR VOWEL SIGN AITON AMYANMAR " +
"VOWEL SIGN AITON AIMYANMAR SYMBOL SHAN ONEMYANMAR SYMBOL SHAN EXCLAMATIO" +
"NGEORGIAN CAPITAL LETTER ANGEORGIAN CAPITAL LETTER BANGEORGIAN CAPITAL L" +
"ETTER GANGEORGIAN CAPITAL LETTER DONGEORGIAN CAPITAL LETTER ENGEORGIAN C" +
"APITAL LETTER VINGEORGIAN CAPITAL LETTER ZENGEORGIAN CAPITAL LETTER TANG" +
"EORGIAN CAPITAL LETTER INGEORGIAN CAPITAL LETTER KANGEORGIAN CAPITAL LET" +
"TER LASGEORGIAN CAPITAL LETTER MANGEORGIAN CAPITAL LETTER NARGEORGIAN CA" +
"PITAL LETTER ONGEORGIAN CAPITAL LETTER PARGEORGIAN CAPITAL LETTER ZHARGE" +
"ORGIAN CAPITAL LETTER RAEGEORGIAN CAPITAL LETTER SANGEORGIAN CAPITAL LET" +
"TER TARGEORGIAN CAPITAL LETTER UNGEORGIAN CAPITAL LETTER PHARGEORGIAN CA" +
"PITAL LETTER KHARGEORGIAN CAPITAL LETTER GHANGEORGIAN CAPITAL LETTER QAR" +
"GEORGIAN CAPITAL LETTER SHINGEORGIAN CAPITAL LETTER CHINGEORGIAN CAPITAL" +
" LETTER CANGEORGIAN CAPITAL LETTER JILGEORGIAN CAPITAL LETTER CILGEORGIA" +
"N CAPITAL LETTER CHARGEORGIAN CAPITAL LETTER XANGEORGIAN CAPITAL LETTER " +
"JHANGEORGIAN CAPITAL LETTER HAEGEORGIAN CAPITAL LETTER HEGEORGIAN CAPITA" +
"L LETTER HIEGEORGIAN CAPITAL LETTER WEGEORGIAN CAPITAL LETTER HARGEORGIA" +
"N CAPITAL LETTER HOEGEORGIAN CAPITAL LETTER YNGEORGIAN CAPITAL LETTER AE" +
"NGEORGIAN LETTER ANGEORGIAN LETTER BANGEORGIAN LETTER GANGEORGIAN LETTER" +
" DONGEORGIAN LETTER ENGEORGIAN LETTER VINGEORGIAN LETTER ZENGEORGIAN LET" +
"TER TANGEORGIAN LETTER INGEORGIAN LETTER KANGEORGIAN LETTER LASGEORGIAN " +
"LETTER MANGEORGIAN LETTER NARGEORGIAN LETTER ONGEORGIAN LETTER PARGEORGI" +
"AN LETTER ZHARGEORGIAN LETTER RAEGEORGIAN LETTER SANGEORGIAN LETTER TARG" +
"EORGIAN LETTER UNGEORGIAN LETTER PHARGEORGIAN LETTER KHARGEORGIAN LETTER" +
" GHANGEORGIAN LETTER QARGEORGIAN LETTER SHINGEORGIAN LETTER CHINGEORGIAN" +
" LETTER CANGEORGIAN LETTER JILGEORGIAN LETTER CILGEORGIAN LETTER CHARGEO" +
"RGIAN LETTER XANGEORGIAN LETTER JHANGEORGIAN LETTER HAEGEORGIAN LETTER H" +
"EGEORGIAN LETTER HIEGEORGIAN LETTER WEGEORGIAN LETTER HARGEORGIAN LETTER" +
" HOEGEORGIAN LETTER FIGEORGIAN LETTER YNGEORGIAN LETTER ELIFIGEORGIAN LE" +
"TTER TURNED GANGEORGIAN LETTER AINGEORGIAN PARAGRAPH SEPARATORMODIFIER L" +
"ETTER GEORGIAN NARGEORGIAN LETTER AENGEORGIAN LETTER HARD SIGNGEORGIAN L" +
"ETTER LABIAL SIGNHANGUL CHOSEONG KIYEOKHANGUL CHOSEONG SSANGKIYEOKHANGUL" +
" CHOSEONG NIEUNHANGUL CHOSEONG TIKEUTHANGUL CHOSEONG SSANGTIKEUTHANGUL C" +
"HOSEONG RIEULHANGUL CHOSEONG MIEUMHANGUL CHOSEONG PIEUPHANGUL CHOSEONG S" +
"SANGPIEUPHANGUL CHOSEONG SIOSHANGUL CHOSEONG SSANGSIOSHANGUL CHOSEONG IE" +
"UNGHANGUL CHOSEONG CIEUCHANGUL CHOSEONG SSANGCIEUCHANGUL CHOSEONG CHIEUC" +
"HHANGUL CHOSEONG KHIEUKHHANGUL CHOSEONG THIEUTHHANGUL CHOSEONG PHIEUPHHA" +
"NGUL CHOSEONG HIEUHHANGUL CHOSEONG NIEUN-KIYEOKHANGUL CHOSEONG SSANGNIEU" +
"NHANGUL CHOSEONG NIEUN-TIKEUTHANGUL CHOSEONG NIEUN-PIEUPHANGUL CHOSEONG " +
"TIKEUT-KIYEOKHANGUL CHOSEONG RIEUL-NIEUNHANGUL CHOSEONG SSANGRIEULHANGUL" +
" CHOSEONG RIEUL-HIEUHHANGUL CHOSEONG KAPYEOUNRIEULHANGUL CHOSEONG MIEUM-") + ("" +
"PIEUPHANGUL CHOSEONG KAPYEOUNMIEUMHANGUL CHOSEONG PIEUP-KIYEOKHANGUL CHO" +
"SEONG PIEUP-NIEUNHANGUL CHOSEONG PIEUP-TIKEUTHANGUL CHOSEONG PIEUP-SIOSH" +
"ANGUL CHOSEONG PIEUP-SIOS-KIYEOKHANGUL CHOSEONG PIEUP-SIOS-TIKEUTHANGUL " +
"CHOSEONG PIEUP-SIOS-PIEUPHANGUL CHOSEONG PIEUP-SSANGSIOSHANGUL CHOSEONG " +
"PIEUP-SIOS-CIEUCHANGUL CHOSEONG PIEUP-CIEUCHANGUL CHOSEONG PIEUP-CHIEUCH" +
"HANGUL CHOSEONG PIEUP-THIEUTHHANGUL CHOSEONG PIEUP-PHIEUPHHANGUL CHOSEON" +
"G KAPYEOUNPIEUPHANGUL CHOSEONG KAPYEOUNSSANGPIEUPHANGUL CHOSEONG SIOS-KI" +
"YEOKHANGUL CHOSEONG SIOS-NIEUNHANGUL CHOSEONG SIOS-TIKEUTHANGUL CHOSEONG" +
" SIOS-RIEULHANGUL CHOSEONG SIOS-MIEUMHANGUL CHOSEONG SIOS-PIEUPHANGUL CH" +
"OSEONG SIOS-PIEUP-KIYEOKHANGUL CHOSEONG SIOS-SSANGSIOSHANGUL CHOSEONG SI" +
"OS-IEUNGHANGUL CHOSEONG SIOS-CIEUCHANGUL CHOSEONG SIOS-CHIEUCHHANGUL CHO" +
"SEONG SIOS-KHIEUKHHANGUL CHOSEONG SIOS-THIEUTHHANGUL CHOSEONG SIOS-PHIEU" +
"PHHANGUL CHOSEONG SIOS-HIEUHHANGUL CHOSEONG CHITUEUMSIOSHANGUL CHOSEONG " +
"CHITUEUMSSANGSIOSHANGUL CHOSEONG CEONGCHIEUMSIOSHANGUL CHOSEONG CEONGCHI" +
"EUMSSANGSIOSHANGUL CHOSEONG PANSIOSHANGUL CHOSEONG IEUNG-KIYEOKHANGUL CH" +
"OSEONG IEUNG-TIKEUTHANGUL CHOSEONG IEUNG-MIEUMHANGUL CHOSEONG IEUNG-PIEU" +
"PHANGUL CHOSEONG IEUNG-SIOSHANGUL CHOSEONG IEUNG-PANSIOSHANGUL CHOSEONG " +
"SSANGIEUNGHANGUL CHOSEONG IEUNG-CIEUCHANGUL CHOSEONG IEUNG-CHIEUCHHANGUL" +
" CHOSEONG IEUNG-THIEUTHHANGUL CHOSEONG IEUNG-PHIEUPHHANGUL CHOSEONG YESI" +
"EUNGHANGUL CHOSEONG CIEUC-IEUNGHANGUL CHOSEONG CHITUEUMCIEUCHANGUL CHOSE" +
"ONG CHITUEUMSSANGCIEUCHANGUL CHOSEONG CEONGCHIEUMCIEUCHANGUL CHOSEONG CE" +
"ONGCHIEUMSSANGCIEUCHANGUL CHOSEONG CHIEUCH-KHIEUKHHANGUL CHOSEONG CHIEUC" +
"H-HIEUHHANGUL CHOSEONG CHITUEUMCHIEUCHHANGUL CHOSEONG CEONGCHIEUMCHIEUCH" +
"HANGUL CHOSEONG PHIEUPH-PIEUPHANGUL CHOSEONG KAPYEOUNPHIEUPHHANGUL CHOSE" +
"ONG SSANGHIEUHHANGUL CHOSEONG YEORINHIEUHHANGUL CHOSEONG KIYEOK-TIKEUTHA" +
"NGUL CHOSEONG NIEUN-SIOSHANGUL CHOSEONG NIEUN-CIEUCHANGUL CHOSEONG NIEUN" +
"-HIEUHHANGUL CHOSEONG TIKEUT-RIEULHANGUL CHOSEONG FILLERHANGUL JUNGSEONG" +
" FILLERHANGUL JUNGSEONG AHANGUL JUNGSEONG AEHANGUL JUNGSEONG YAHANGUL JU" +
"NGSEONG YAEHANGUL JUNGSEONG EOHANGUL JUNGSEONG EHANGUL JUNGSEONG YEOHANG" +
"UL JUNGSEONG YEHANGUL JUNGSEONG OHANGUL JUNGSEONG WAHANGUL JUNGSEONG WAE" +
"HANGUL JUNGSEONG OEHANGUL JUNGSEONG YOHANGUL JUNGSEONG UHANGUL JUNGSEONG" +
" WEOHANGUL JUNGSEONG WEHANGUL JUNGSEONG WIHANGUL JUNGSEONG YUHANGUL JUNG" +
"SEONG EUHANGUL JUNGSEONG YIHANGUL JUNGSEONG IHANGUL JUNGSEONG A-OHANGUL " +
"JUNGSEONG A-UHANGUL JUNGSEONG YA-OHANGUL JUNGSEONG YA-YOHANGUL JUNGSEONG" +
" EO-OHANGUL JUNGSEONG EO-UHANGUL JUNGSEONG EO-EUHANGUL JUNGSEONG YEO-OHA" +
"NGUL JUNGSEONG YEO-UHANGUL JUNGSEONG O-EOHANGUL JUNGSEONG O-EHANGUL JUNG" +
"SEONG O-YEHANGUL JUNGSEONG O-OHANGUL JUNGSEONG O-UHANGUL JUNGSEONG YO-YA" +
"HANGUL JUNGSEONG YO-YAEHANGUL JUNGSEONG YO-YEOHANGUL JUNGSEONG YO-OHANGU" +
"L JUNGSEONG YO-IHANGUL JUNGSEONG U-AHANGUL JUNGSEONG U-AEHANGUL JUNGSEON" +
"G U-EO-EUHANGUL JUNGSEONG U-YEHANGUL JUNGSEONG U-UHANGUL JUNGSEONG YU-AH" +
"ANGUL JUNGSEONG YU-EOHANGUL JUNGSEONG YU-EHANGUL JUNGSEONG YU-YEOHANGUL " +
"JUNGSEONG YU-YEHANGUL JUNGSEONG YU-UHANGUL JUNGSEONG YU-IHANGUL JUNGSEON" +
"G EU-UHANGUL JUNGSEONG EU-EUHANGUL JUNGSEONG YI-UHANGUL JUNGSEONG I-AHAN" +
"GUL JUNGSEONG I-YAHANGUL JUNGSEONG I-OHANGUL JUNGSEONG I-UHANGUL JUNGSEO" +
"NG I-EUHANGUL JUNGSEONG I-ARAEAHANGUL JUNGSEONG ARAEAHANGUL JUNGSEONG AR" +
"AEA-EOHANGUL JUNGSEONG ARAEA-UHANGUL JUNGSEONG ARAEA-IHANGUL JUNGSEONG S" +
"SANGARAEAHANGUL JUNGSEONG A-EUHANGUL JUNGSEONG YA-UHANGUL JUNGSEONG YEO-" +
"YAHANGUL JUNGSEONG O-YAHANGUL JUNGSEONG O-YAEHANGUL JONGSEONG KIYEOKHANG" +
"UL JONGSEONG SSANGKIYEOKHANGUL JONGSEONG KIYEOK-SIOSHANGUL JONGSEONG NIE" +
"UNHANGUL JONGSEONG NIEUN-CIEUCHANGUL JONGSEONG NIEUN-HIEUHHANGUL JONGSEO" +
"NG TIKEUTHANGUL JONGSEONG RIEULHANGUL JONGSEONG RIEUL-KIYEOKHANGUL JONGS" +
"EONG RIEUL-MIEUMHANGUL JONGSEONG RIEUL-PIEUPHANGUL JONGSEONG RIEUL-SIOSH" +
"ANGUL JONGSEONG RIEUL-THIEUTHHANGUL JONGSEONG RIEUL-PHIEUPHHANGUL JONGSE" +
"ONG RIEUL-HIEUHHANGUL JONGSEONG MIEUMHANGUL JONGSEONG PIEUPHANGUL JONGSE" +
"ONG PIEUP-SIOSHANGUL JONGSEONG SIOSHANGUL JONGSEONG SSANGSIOSHANGUL JONG" +
"SEONG IEUNGHANGUL JONGSEONG CIEUCHANGUL JONGSEONG CHIEUCHHANGUL JONGSEON" +
"G KHIEUKHHANGUL JONGSEONG THIEUTHHANGUL JONGSEONG PHIEUPHHANGUL JONGSEON" +
"G HIEUHHANGUL JONGSEONG KIYEOK-RIEULHANGUL JONGSEONG KIYEOK-SIOS-KIYEOKH" +
"ANGUL JONGSEONG NIEUN-KIYEOKHANGUL JONGSEONG NIEUN-TIKEUTHANGUL JONGSEON" +
"G NIEUN-SIOSHANGUL JONGSEONG NIEUN-PANSIOSHANGUL JONGSEONG NIEUN-THIEUTH" +
"HANGUL JONGSEONG TIKEUT-KIYEOKHANGUL JONGSEONG TIKEUT-RIEULHANGUL JONGSE" +
"ONG RIEUL-KIYEOK-SIOSHANGUL JONGSEONG RIEUL-NIEUNHANGUL JONGSEONG RIEUL-" +
"TIKEUTHANGUL JONGSEONG RIEUL-TIKEUT-HIEUHHANGUL JONGSEONG SSANGRIEULHANG" +
"UL JONGSEONG RIEUL-MIEUM-KIYEOKHANGUL JONGSEONG RIEUL-MIEUM-SIOSHANGUL J") + ("" +
"ONGSEONG RIEUL-PIEUP-SIOSHANGUL JONGSEONG RIEUL-PIEUP-HIEUHHANGUL JONGSE" +
"ONG RIEUL-KAPYEOUNPIEUPHANGUL JONGSEONG RIEUL-SSANGSIOSHANGUL JONGSEONG " +
"RIEUL-PANSIOSHANGUL JONGSEONG RIEUL-KHIEUKHHANGUL JONGSEONG RIEUL-YEORIN" +
"HIEUHHANGUL JONGSEONG MIEUM-KIYEOKHANGUL JONGSEONG MIEUM-RIEULHANGUL JON" +
"GSEONG MIEUM-PIEUPHANGUL JONGSEONG MIEUM-SIOSHANGUL JONGSEONG MIEUM-SSAN" +
"GSIOSHANGUL JONGSEONG MIEUM-PANSIOSHANGUL JONGSEONG MIEUM-CHIEUCHHANGUL " +
"JONGSEONG MIEUM-HIEUHHANGUL JONGSEONG KAPYEOUNMIEUMHANGUL JONGSEONG PIEU" +
"P-RIEULHANGUL JONGSEONG PIEUP-PHIEUPHHANGUL JONGSEONG PIEUP-HIEUHHANGUL " +
"JONGSEONG KAPYEOUNPIEUPHANGUL JONGSEONG SIOS-KIYEOKHANGUL JONGSEONG SIOS" +
"-TIKEUTHANGUL JONGSEONG SIOS-RIEULHANGUL JONGSEONG SIOS-PIEUPHANGUL JONG" +
"SEONG PANSIOSHANGUL JONGSEONG IEUNG-KIYEOKHANGUL JONGSEONG IEUNG-SSANGKI" +
"YEOKHANGUL JONGSEONG SSANGIEUNGHANGUL JONGSEONG IEUNG-KHIEUKHHANGUL JONG" +
"SEONG YESIEUNGHANGUL JONGSEONG YESIEUNG-SIOSHANGUL JONGSEONG YESIEUNG-PA" +
"NSIOSHANGUL JONGSEONG PHIEUPH-PIEUPHANGUL JONGSEONG KAPYEOUNPHIEUPHHANGU" +
"L JONGSEONG HIEUH-NIEUNHANGUL JONGSEONG HIEUH-RIEULHANGUL JONGSEONG HIEU" +
"H-MIEUMHANGUL JONGSEONG HIEUH-PIEUPHANGUL JONGSEONG YEORINHIEUHHANGUL JO" +
"NGSEONG KIYEOK-NIEUNHANGUL JONGSEONG KIYEOK-PIEUPHANGUL JONGSEONG KIYEOK" +
"-CHIEUCHHANGUL JONGSEONG KIYEOK-KHIEUKHHANGUL JONGSEONG KIYEOK-HIEUHHANG" +
"UL JONGSEONG SSANGNIEUNETHIOPIC SYLLABLE HAETHIOPIC SYLLABLE HUETHIOPIC " +
"SYLLABLE HIETHIOPIC SYLLABLE HAAETHIOPIC SYLLABLE HEEETHIOPIC SYLLABLE H" +
"EETHIOPIC SYLLABLE HOETHIOPIC SYLLABLE HOAETHIOPIC SYLLABLE LAETHIOPIC S" +
"YLLABLE LUETHIOPIC SYLLABLE LIETHIOPIC SYLLABLE LAAETHIOPIC SYLLABLE LEE" +
"ETHIOPIC SYLLABLE LEETHIOPIC SYLLABLE LOETHIOPIC SYLLABLE LWAETHIOPIC SY" +
"LLABLE HHAETHIOPIC SYLLABLE HHUETHIOPIC SYLLABLE HHIETHIOPIC SYLLABLE HH" +
"AAETHIOPIC SYLLABLE HHEEETHIOPIC SYLLABLE HHEETHIOPIC SYLLABLE HHOETHIOP" +
"IC SYLLABLE HHWAETHIOPIC SYLLABLE MAETHIOPIC SYLLABLE MUETHIOPIC SYLLABL" +
"E MIETHIOPIC SYLLABLE MAAETHIOPIC SYLLABLE MEEETHIOPIC SYLLABLE MEETHIOP" +
"IC SYLLABLE MOETHIOPIC SYLLABLE MWAETHIOPIC SYLLABLE SZAETHIOPIC SYLLABL" +
"E SZUETHIOPIC SYLLABLE SZIETHIOPIC SYLLABLE SZAAETHIOPIC SYLLABLE SZEEET" +
"HIOPIC SYLLABLE SZEETHIOPIC SYLLABLE SZOETHIOPIC SYLLABLE SZWAETHIOPIC S" +
"YLLABLE RAETHIOPIC SYLLABLE RUETHIOPIC SYLLABLE RIETHIOPIC SYLLABLE RAAE" +
"THIOPIC SYLLABLE REEETHIOPIC SYLLABLE REETHIOPIC SYLLABLE ROETHIOPIC SYL" +
"LABLE RWAETHIOPIC SYLLABLE SAETHIOPIC SYLLABLE SUETHIOPIC SYLLABLE SIETH" +
"IOPIC SYLLABLE SAAETHIOPIC SYLLABLE SEEETHIOPIC SYLLABLE SEETHIOPIC SYLL" +
"ABLE SOETHIOPIC SYLLABLE SWAETHIOPIC SYLLABLE SHAETHIOPIC SYLLABLE SHUET" +
"HIOPIC SYLLABLE SHIETHIOPIC SYLLABLE SHAAETHIOPIC SYLLABLE SHEEETHIOPIC " +
"SYLLABLE SHEETHIOPIC SYLLABLE SHOETHIOPIC SYLLABLE SHWAETHIOPIC SYLLABLE" +
" QAETHIOPIC SYLLABLE QUETHIOPIC SYLLABLE QIETHIOPIC SYLLABLE QAAETHIOPIC" +
" SYLLABLE QEEETHIOPIC SYLLABLE QEETHIOPIC SYLLABLE QOETHIOPIC SYLLABLE Q" +
"OAETHIOPIC SYLLABLE QWAETHIOPIC SYLLABLE QWIETHIOPIC SYLLABLE QWAAETHIOP" +
"IC SYLLABLE QWEEETHIOPIC SYLLABLE QWEETHIOPIC SYLLABLE QHAETHIOPIC SYLLA" +
"BLE QHUETHIOPIC SYLLABLE QHIETHIOPIC SYLLABLE QHAAETHIOPIC SYLLABLE QHEE" +
"ETHIOPIC SYLLABLE QHEETHIOPIC SYLLABLE QHOETHIOPIC SYLLABLE QHWAETHIOPIC" +
" SYLLABLE QHWIETHIOPIC SYLLABLE QHWAAETHIOPIC SYLLABLE QHWEEETHIOPIC SYL" +
"LABLE QHWEETHIOPIC SYLLABLE BAETHIOPIC SYLLABLE BUETHIOPIC SYLLABLE BIET" +
"HIOPIC SYLLABLE BAAETHIOPIC SYLLABLE BEEETHIOPIC SYLLABLE BEETHIOPIC SYL" +
"LABLE BOETHIOPIC SYLLABLE BWAETHIOPIC SYLLABLE VAETHIOPIC SYLLABLE VUETH" +
"IOPIC SYLLABLE VIETHIOPIC SYLLABLE VAAETHIOPIC SYLLABLE VEEETHIOPIC SYLL" +
"ABLE VEETHIOPIC SYLLABLE VOETHIOPIC SYLLABLE VWAETHIOPIC SYLLABLE TAETHI" +
"OPIC SYLLABLE TUETHIOPIC SYLLABLE TIETHIOPIC SYLLABLE TAAETHIOPIC SYLLAB" +
"LE TEEETHIOPIC SYLLABLE TEETHIOPIC SYLLABLE TOETHIOPIC SYLLABLE TWAETHIO" +
"PIC SYLLABLE CAETHIOPIC SYLLABLE CUETHIOPIC SYLLABLE CIETHIOPIC SYLLABLE" +
" CAAETHIOPIC SYLLABLE CEEETHIOPIC SYLLABLE CEETHIOPIC SYLLABLE COETHIOPI" +
"C SYLLABLE CWAETHIOPIC SYLLABLE XAETHIOPIC SYLLABLE XUETHIOPIC SYLLABLE " +
"XIETHIOPIC SYLLABLE XAAETHIOPIC SYLLABLE XEEETHIOPIC SYLLABLE XEETHIOPIC" +
" SYLLABLE XOETHIOPIC SYLLABLE XOAETHIOPIC SYLLABLE XWAETHIOPIC SYLLABLE " +
"XWIETHIOPIC SYLLABLE XWAAETHIOPIC SYLLABLE XWEEETHIOPIC SYLLABLE XWEETHI" +
"OPIC SYLLABLE NAETHIOPIC SYLLABLE NUETHIOPIC SYLLABLE NIETHIOPIC SYLLABL" +
"E NAAETHIOPIC SYLLABLE NEEETHIOPIC SYLLABLE NEETHIOPIC SYLLABLE NOETHIOP" +
"IC SYLLABLE NWAETHIOPIC SYLLABLE NYAETHIOPIC SYLLABLE NYUETHIOPIC SYLLAB" +
"LE NYIETHIOPIC SYLLABLE NYAAETHIOPIC SYLLABLE NYEEETHIOPIC SYLLABLE NYEE" +
"THIOPIC SYLLABLE NYOETHIOPIC SYLLABLE NYWAETHIOPIC SYLLABLE GLOTTAL AETH" +
"IOPIC SYLLABLE GLOTTAL UETHIOPIC SYLLABLE GLOTTAL IETHIOPIC SYLLABLE GLO" +
"TTAL AAETHIOPIC SYLLABLE GLOTTAL EEETHIOPIC SYLLABLE GLOTTAL EETHIOPIC S") + ("" +
"YLLABLE GLOTTAL OETHIOPIC SYLLABLE GLOTTAL WAETHIOPIC SYLLABLE KAETHIOPI" +
"C SYLLABLE KUETHIOPIC SYLLABLE KIETHIOPIC SYLLABLE KAAETHIOPIC SYLLABLE " +
"KEEETHIOPIC SYLLABLE KEETHIOPIC SYLLABLE KOETHIOPIC SYLLABLE KOAETHIOPIC" +
" SYLLABLE KWAETHIOPIC SYLLABLE KWIETHIOPIC SYLLABLE KWAAETHIOPIC SYLLABL" +
"E KWEEETHIOPIC SYLLABLE KWEETHIOPIC SYLLABLE KXAETHIOPIC SYLLABLE KXUETH" +
"IOPIC SYLLABLE KXIETHIOPIC SYLLABLE KXAAETHIOPIC SYLLABLE KXEEETHIOPIC S" +
"YLLABLE KXEETHIOPIC SYLLABLE KXOETHIOPIC SYLLABLE KXWAETHIOPIC SYLLABLE " +
"KXWIETHIOPIC SYLLABLE KXWAAETHIOPIC SYLLABLE KXWEEETHIOPIC SYLLABLE KXWE" +
"ETHIOPIC SYLLABLE WAETHIOPIC SYLLABLE WUETHIOPIC SYLLABLE WIETHIOPIC SYL" +
"LABLE WAAETHIOPIC SYLLABLE WEEETHIOPIC SYLLABLE WEETHIOPIC SYLLABLE WOET" +
"HIOPIC SYLLABLE WOAETHIOPIC SYLLABLE PHARYNGEAL AETHIOPIC SYLLABLE PHARY" +
"NGEAL UETHIOPIC SYLLABLE PHARYNGEAL IETHIOPIC SYLLABLE PHARYNGEAL AAETHI" +
"OPIC SYLLABLE PHARYNGEAL EEETHIOPIC SYLLABLE PHARYNGEAL EETHIOPIC SYLLAB" +
"LE PHARYNGEAL OETHIOPIC SYLLABLE ZAETHIOPIC SYLLABLE ZUETHIOPIC SYLLABLE" +
" ZIETHIOPIC SYLLABLE ZAAETHIOPIC SYLLABLE ZEEETHIOPIC SYLLABLE ZEETHIOPI" +
"C SYLLABLE ZOETHIOPIC SYLLABLE ZWAETHIOPIC SYLLABLE ZHAETHIOPIC SYLLABLE" +
" ZHUETHIOPIC SYLLABLE ZHIETHIOPIC SYLLABLE ZHAAETHIOPIC SYLLABLE ZHEEETH" +
"IOPIC SYLLABLE ZHEETHIOPIC SYLLABLE ZHOETHIOPIC SYLLABLE ZHWAETHIOPIC SY" +
"LLABLE YAETHIOPIC SYLLABLE YUETHIOPIC SYLLABLE YIETHIOPIC SYLLABLE YAAET" +
"HIOPIC SYLLABLE YEEETHIOPIC SYLLABLE YEETHIOPIC SYLLABLE YOETHIOPIC SYLL" +
"ABLE YOAETHIOPIC SYLLABLE DAETHIOPIC SYLLABLE DUETHIOPIC SYLLABLE DIETHI" +
"OPIC SYLLABLE DAAETHIOPIC SYLLABLE DEEETHIOPIC SYLLABLE DEETHIOPIC SYLLA" +
"BLE DOETHIOPIC SYLLABLE DWAETHIOPIC SYLLABLE DDAETHIOPIC SYLLABLE DDUETH" +
"IOPIC SYLLABLE DDIETHIOPIC SYLLABLE DDAAETHIOPIC SYLLABLE DDEEETHIOPIC S" +
"YLLABLE DDEETHIOPIC SYLLABLE DDOETHIOPIC SYLLABLE DDWAETHIOPIC SYLLABLE " +
"JAETHIOPIC SYLLABLE JUETHIOPIC SYLLABLE JIETHIOPIC SYLLABLE JAAETHIOPIC " +
"SYLLABLE JEEETHIOPIC SYLLABLE JEETHIOPIC SYLLABLE JOETHIOPIC SYLLABLE JW" +
"AETHIOPIC SYLLABLE GAETHIOPIC SYLLABLE GUETHIOPIC SYLLABLE GIETHIOPIC SY" +
"LLABLE GAAETHIOPIC SYLLABLE GEEETHIOPIC SYLLABLE GEETHIOPIC SYLLABLE GOE" +
"THIOPIC SYLLABLE GOAETHIOPIC SYLLABLE GWAETHIOPIC SYLLABLE GWIETHIOPIC S" +
"YLLABLE GWAAETHIOPIC SYLLABLE GWEEETHIOPIC SYLLABLE GWEETHIOPIC SYLLABLE" +
" GGAETHIOPIC SYLLABLE GGUETHIOPIC SYLLABLE GGIETHIOPIC SYLLABLE GGAAETHI" +
"OPIC SYLLABLE GGEEETHIOPIC SYLLABLE GGEETHIOPIC SYLLABLE GGOETHIOPIC SYL" +
"LABLE GGWAAETHIOPIC SYLLABLE THAETHIOPIC SYLLABLE THUETHIOPIC SYLLABLE T" +
"HIETHIOPIC SYLLABLE THAAETHIOPIC SYLLABLE THEEETHIOPIC SYLLABLE THEETHIO" +
"PIC SYLLABLE THOETHIOPIC SYLLABLE THWAETHIOPIC SYLLABLE CHAETHIOPIC SYLL" +
"ABLE CHUETHIOPIC SYLLABLE CHIETHIOPIC SYLLABLE CHAAETHIOPIC SYLLABLE CHE" +
"EETHIOPIC SYLLABLE CHEETHIOPIC SYLLABLE CHOETHIOPIC SYLLABLE CHWAETHIOPI" +
"C SYLLABLE PHAETHIOPIC SYLLABLE PHUETHIOPIC SYLLABLE PHIETHIOPIC SYLLABL" +
"E PHAAETHIOPIC SYLLABLE PHEEETHIOPIC SYLLABLE PHEETHIOPIC SYLLABLE PHOET" +
"HIOPIC SYLLABLE PHWAETHIOPIC SYLLABLE TSAETHIOPIC SYLLABLE TSUETHIOPIC S" +
"YLLABLE TSIETHIOPIC SYLLABLE TSAAETHIOPIC SYLLABLE TSEEETHIOPIC SYLLABLE" +
" TSEETHIOPIC SYLLABLE TSOETHIOPIC SYLLABLE TSWAETHIOPIC SYLLABLE TZAETHI" +
"OPIC SYLLABLE TZUETHIOPIC SYLLABLE TZIETHIOPIC SYLLABLE TZAAETHIOPIC SYL" +
"LABLE TZEEETHIOPIC SYLLABLE TZEETHIOPIC SYLLABLE TZOETHIOPIC SYLLABLE TZ" +
"OAETHIOPIC SYLLABLE FAETHIOPIC SYLLABLE FUETHIOPIC SYLLABLE FIETHIOPIC S" +
"YLLABLE FAAETHIOPIC SYLLABLE FEEETHIOPIC SYLLABLE FEETHIOPIC SYLLABLE FO" +
"ETHIOPIC SYLLABLE FWAETHIOPIC SYLLABLE PAETHIOPIC SYLLABLE PUETHIOPIC SY" +
"LLABLE PIETHIOPIC SYLLABLE PAAETHIOPIC SYLLABLE PEEETHIOPIC SYLLABLE PEE" +
"THIOPIC SYLLABLE POETHIOPIC SYLLABLE PWAETHIOPIC SYLLABLE RYAETHIOPIC SY" +
"LLABLE MYAETHIOPIC SYLLABLE FYAETHIOPIC COMBINING GEMINATION AND VOWEL L" +
"ENGTH MARKETHIOPIC COMBINING VOWEL LENGTH MARKETHIOPIC COMBINING GEMINAT" +
"ION MARKETHIOPIC SECTION MARKETHIOPIC WORDSPACEETHIOPIC FULL STOPETHIOPI" +
"C COMMAETHIOPIC SEMICOLONETHIOPIC COLONETHIOPIC PREFACE COLONETHIOPIC QU" +
"ESTION MARKETHIOPIC PARAGRAPH SEPARATORETHIOPIC DIGIT ONEETHIOPIC DIGIT " +
"TWOETHIOPIC DIGIT THREEETHIOPIC DIGIT FOURETHIOPIC DIGIT FIVEETHIOPIC DI" +
"GIT SIXETHIOPIC DIGIT SEVENETHIOPIC DIGIT EIGHTETHIOPIC DIGIT NINEETHIOP" +
"IC NUMBER TENETHIOPIC NUMBER TWENTYETHIOPIC NUMBER THIRTYETHIOPIC NUMBER" +
" FORTYETHIOPIC NUMBER FIFTYETHIOPIC NUMBER SIXTYETHIOPIC NUMBER SEVENTYE" +
"THIOPIC NUMBER EIGHTYETHIOPIC NUMBER NINETYETHIOPIC NUMBER HUNDREDETHIOP" +
"IC NUMBER TEN THOUSANDETHIOPIC SYLLABLE SEBATBEIT MWAETHIOPIC SYLLABLE M" +
"WIETHIOPIC SYLLABLE MWEEETHIOPIC SYLLABLE MWEETHIOPIC SYLLABLE SEBATBEIT" +
" BWAETHIOPIC SYLLABLE BWIETHIOPIC SYLLABLE BWEEETHIOPIC SYLLABLE BWEETHI" +
"OPIC SYLLABLE SEBATBEIT FWAETHIOPIC SYLLABLE FWIETHIOPIC SYLLABLE FWEEET") + ("" +
"HIOPIC SYLLABLE FWEETHIOPIC SYLLABLE SEBATBEIT PWAETHIOPIC SYLLABLE PWIE" +
"THIOPIC SYLLABLE PWEEETHIOPIC SYLLABLE PWEETHIOPIC TONAL MARK YIZETETHIO" +
"PIC TONAL MARK DERETETHIOPIC TONAL MARK RIKRIKETHIOPIC TONAL MARK SHORT " +
"RIKRIKETHIOPIC TONAL MARK DIFATETHIOPIC TONAL MARK KENATETHIOPIC TONAL M" +
"ARK CHIRETETHIOPIC TONAL MARK HIDETETHIOPIC TONAL MARK DERET-HIDETETHIOP" +
"IC TONAL MARK KURTCHEROKEE LETTER ACHEROKEE LETTER ECHEROKEE LETTER ICHE" +
"ROKEE LETTER OCHEROKEE LETTER UCHEROKEE LETTER VCHEROKEE LETTER GACHEROK" +
"EE LETTER KACHEROKEE LETTER GECHEROKEE LETTER GICHEROKEE LETTER GOCHEROK" +
"EE LETTER GUCHEROKEE LETTER GVCHEROKEE LETTER HACHEROKEE LETTER HECHEROK" +
"EE LETTER HICHEROKEE LETTER HOCHEROKEE LETTER HUCHEROKEE LETTER HVCHEROK" +
"EE LETTER LACHEROKEE LETTER LECHEROKEE LETTER LICHEROKEE LETTER LOCHEROK" +
"EE LETTER LUCHEROKEE LETTER LVCHEROKEE LETTER MACHEROKEE LETTER MECHEROK" +
"EE LETTER MICHEROKEE LETTER MOCHEROKEE LETTER MUCHEROKEE LETTER NACHEROK" +
"EE LETTER HNACHEROKEE LETTER NAHCHEROKEE LETTER NECHEROKEE LETTER NICHER" +
"OKEE LETTER NOCHEROKEE LETTER NUCHEROKEE LETTER NVCHEROKEE LETTER QUACHE" +
"ROKEE LETTER QUECHEROKEE LETTER QUICHEROKEE LETTER QUOCHEROKEE LETTER QU" +
"UCHEROKEE LETTER QUVCHEROKEE LETTER SACHEROKEE LETTER SCHEROKEE LETTER S" +
"ECHEROKEE LETTER SICHEROKEE LETTER SOCHEROKEE LETTER SUCHEROKEE LETTER S" +
"VCHEROKEE LETTER DACHEROKEE LETTER TACHEROKEE LETTER DECHEROKEE LETTER T" +
"ECHEROKEE LETTER DICHEROKEE LETTER TICHEROKEE LETTER DOCHEROKEE LETTER D" +
"UCHEROKEE LETTER DVCHEROKEE LETTER DLACHEROKEE LETTER TLACHEROKEE LETTER" +
" TLECHEROKEE LETTER TLICHEROKEE LETTER TLOCHEROKEE LETTER TLUCHEROKEE LE" +
"TTER TLVCHEROKEE LETTER TSACHEROKEE LETTER TSECHEROKEE LETTER TSICHEROKE" +
"E LETTER TSOCHEROKEE LETTER TSUCHEROKEE LETTER TSVCHEROKEE LETTER WACHER" +
"OKEE LETTER WECHEROKEE LETTER WICHEROKEE LETTER WOCHEROKEE LETTER WUCHER" +
"OKEE LETTER WVCHEROKEE LETTER YACHEROKEE LETTER YECHEROKEE LETTER YICHER" +
"OKEE LETTER YOCHEROKEE LETTER YUCHEROKEE LETTER YVCHEROKEE LETTER MVCHER" +
"OKEE SMALL LETTER YECHEROKEE SMALL LETTER YICHEROKEE SMALL LETTER YOCHER" +
"OKEE SMALL LETTER YUCHEROKEE SMALL LETTER YVCHEROKEE SMALL LETTER MVCANA" +
"DIAN SYLLABICS HYPHENCANADIAN SYLLABICS ECANADIAN SYLLABICS AAICANADIAN " +
"SYLLABICS ICANADIAN SYLLABICS IICANADIAN SYLLABICS OCANADIAN SYLLABICS O" +
"OCANADIAN SYLLABICS Y-CREE OOCANADIAN SYLLABICS CARRIER EECANADIAN SYLLA" +
"BICS CARRIER ICANADIAN SYLLABICS ACANADIAN SYLLABICS AACANADIAN SYLLABIC" +
"S WECANADIAN SYLLABICS WEST-CREE WECANADIAN SYLLABICS WICANADIAN SYLLABI" +
"CS WEST-CREE WICANADIAN SYLLABICS WIICANADIAN SYLLABICS WEST-CREE WIICAN" +
"ADIAN SYLLABICS WOCANADIAN SYLLABICS WEST-CREE WOCANADIAN SYLLABICS WOOC" +
"ANADIAN SYLLABICS WEST-CREE WOOCANADIAN SYLLABICS NASKAPI WOOCANADIAN SY" +
"LLABICS WACANADIAN SYLLABICS WEST-CREE WACANADIAN SYLLABICS WAACANADIAN " +
"SYLLABICS WEST-CREE WAACANADIAN SYLLABICS NASKAPI WAACANADIAN SYLLABICS " +
"AICANADIAN SYLLABICS Y-CREE WCANADIAN SYLLABICS GLOTTAL STOPCANADIAN SYL" +
"LABICS FINAL ACUTECANADIAN SYLLABICS FINAL GRAVECANADIAN SYLLABICS FINAL" +
" BOTTOM HALF RINGCANADIAN SYLLABICS FINAL TOP HALF RINGCANADIAN SYLLABIC" +
"S FINAL RIGHT HALF RINGCANADIAN SYLLABICS FINAL RINGCANADIAN SYLLABICS F" +
"INAL DOUBLE ACUTECANADIAN SYLLABICS FINAL DOUBLE SHORT VERTICAL STROKESC" +
"ANADIAN SYLLABICS FINAL MIDDLE DOTCANADIAN SYLLABICS FINAL SHORT HORIZON" +
"TAL STROKECANADIAN SYLLABICS FINAL PLUSCANADIAN SYLLABICS FINAL DOWN TAC" +
"KCANADIAN SYLLABICS ENCANADIAN SYLLABICS INCANADIAN SYLLABICS ONCANADIAN" +
" SYLLABICS ANCANADIAN SYLLABICS PECANADIAN SYLLABICS PAAICANADIAN SYLLAB" +
"ICS PICANADIAN SYLLABICS PIICANADIAN SYLLABICS POCANADIAN SYLLABICS POOC" +
"ANADIAN SYLLABICS Y-CREE POOCANADIAN SYLLABICS CARRIER HEECANADIAN SYLLA" +
"BICS CARRIER HICANADIAN SYLLABICS PACANADIAN SYLLABICS PAACANADIAN SYLLA" +
"BICS PWECANADIAN SYLLABICS WEST-CREE PWECANADIAN SYLLABICS PWICANADIAN S" +
"YLLABICS WEST-CREE PWICANADIAN SYLLABICS PWIICANADIAN SYLLABICS WEST-CRE" +
"E PWIICANADIAN SYLLABICS PWOCANADIAN SYLLABICS WEST-CREE PWOCANADIAN SYL" +
"LABICS PWOOCANADIAN SYLLABICS WEST-CREE PWOOCANADIAN SYLLABICS PWACANADI" +
"AN SYLLABICS WEST-CREE PWACANADIAN SYLLABICS PWAACANADIAN SYLLABICS WEST" +
"-CREE PWAACANADIAN SYLLABICS Y-CREE PWAACANADIAN SYLLABICS PCANADIAN SYL" +
"LABICS WEST-CREE PCANADIAN SYLLABICS CARRIER HCANADIAN SYLLABICS TECANAD" +
"IAN SYLLABICS TAAICANADIAN SYLLABICS TICANADIAN SYLLABICS TIICANADIAN SY" +
"LLABICS TOCANADIAN SYLLABICS TOOCANADIAN SYLLABICS Y-CREE TOOCANADIAN SY" +
"LLABICS CARRIER DEECANADIAN SYLLABICS CARRIER DICANADIAN SYLLABICS TACAN" +
"ADIAN SYLLABICS TAACANADIAN SYLLABICS TWECANADIAN SYLLABICS WEST-CREE TW" +
"ECANADIAN SYLLABICS TWICANADIAN SYLLABICS WEST-CREE TWICANADIAN SYLLABIC" +
"S TWIICANADIAN SYLLABICS WEST-CREE TWIICANADIAN SYLLABICS TWOCANADIAN SY") + ("" +
"LLABICS WEST-CREE TWOCANADIAN SYLLABICS TWOOCANADIAN SYLLABICS WEST-CREE" +
" TWOOCANADIAN SYLLABICS TWACANADIAN SYLLABICS WEST-CREE TWACANADIAN SYLL" +
"ABICS TWAACANADIAN SYLLABICS WEST-CREE TWAACANADIAN SYLLABICS NASKAPI TW" +
"AACANADIAN SYLLABICS TCANADIAN SYLLABICS TTECANADIAN SYLLABICS TTICANADI" +
"AN SYLLABICS TTOCANADIAN SYLLABICS TTACANADIAN SYLLABICS KECANADIAN SYLL" +
"ABICS KAAICANADIAN SYLLABICS KICANADIAN SYLLABICS KIICANADIAN SYLLABICS " +
"KOCANADIAN SYLLABICS KOOCANADIAN SYLLABICS Y-CREE KOOCANADIAN SYLLABICS " +
"KACANADIAN SYLLABICS KAACANADIAN SYLLABICS KWECANADIAN SYLLABICS WEST-CR" +
"EE KWECANADIAN SYLLABICS KWICANADIAN SYLLABICS WEST-CREE KWICANADIAN SYL" +
"LABICS KWIICANADIAN SYLLABICS WEST-CREE KWIICANADIAN SYLLABICS KWOCANADI" +
"AN SYLLABICS WEST-CREE KWOCANADIAN SYLLABICS KWOOCANADIAN SYLLABICS WEST" +
"-CREE KWOOCANADIAN SYLLABICS KWACANADIAN SYLLABICS WEST-CREE KWACANADIAN" +
" SYLLABICS KWAACANADIAN SYLLABICS WEST-CREE KWAACANADIAN SYLLABICS NASKA" +
"PI KWAACANADIAN SYLLABICS KCANADIAN SYLLABICS KWCANADIAN SYLLABICS SOUTH" +
"-SLAVEY KEHCANADIAN SYLLABICS SOUTH-SLAVEY KIHCANADIAN SYLLABICS SOUTH-S" +
"LAVEY KOHCANADIAN SYLLABICS SOUTH-SLAVEY KAHCANADIAN SYLLABICS CECANADIA" +
"N SYLLABICS CAAICANADIAN SYLLABICS CICANADIAN SYLLABICS CIICANADIAN SYLL" +
"ABICS COCANADIAN SYLLABICS COOCANADIAN SYLLABICS Y-CREE COOCANADIAN SYLL" +
"ABICS CACANADIAN SYLLABICS CAACANADIAN SYLLABICS CWECANADIAN SYLLABICS W" +
"EST-CREE CWECANADIAN SYLLABICS CWICANADIAN SYLLABICS WEST-CREE CWICANADI" +
"AN SYLLABICS CWIICANADIAN SYLLABICS WEST-CREE CWIICANADIAN SYLLABICS CWO" +
"CANADIAN SYLLABICS WEST-CREE CWOCANADIAN SYLLABICS CWOOCANADIAN SYLLABIC" +
"S WEST-CREE CWOOCANADIAN SYLLABICS CWACANADIAN SYLLABICS WEST-CREE CWACA" +
"NADIAN SYLLABICS CWAACANADIAN SYLLABICS WEST-CREE CWAACANADIAN SYLLABICS" +
" NASKAPI CWAACANADIAN SYLLABICS CCANADIAN SYLLABICS SAYISI THCANADIAN SY" +
"LLABICS MECANADIAN SYLLABICS MAAICANADIAN SYLLABICS MICANADIAN SYLLABICS" +
" MIICANADIAN SYLLABICS MOCANADIAN SYLLABICS MOOCANADIAN SYLLABICS Y-CREE" +
" MOOCANADIAN SYLLABICS MACANADIAN SYLLABICS MAACANADIAN SYLLABICS MWECAN" +
"ADIAN SYLLABICS WEST-CREE MWECANADIAN SYLLABICS MWICANADIAN SYLLABICS WE" +
"ST-CREE MWICANADIAN SYLLABICS MWIICANADIAN SYLLABICS WEST-CREE MWIICANAD" +
"IAN SYLLABICS MWOCANADIAN SYLLABICS WEST-CREE MWOCANADIAN SYLLABICS MWOO" +
"CANADIAN SYLLABICS WEST-CREE MWOOCANADIAN SYLLABICS MWACANADIAN SYLLABIC" +
"S WEST-CREE MWACANADIAN SYLLABICS MWAACANADIAN SYLLABICS WEST-CREE MWAAC" +
"ANADIAN SYLLABICS NASKAPI MWAACANADIAN SYLLABICS MCANADIAN SYLLABICS WES" +
"T-CREE MCANADIAN SYLLABICS MHCANADIAN SYLLABICS ATHAPASCAN MCANADIAN SYL" +
"LABICS SAYISI MCANADIAN SYLLABICS NECANADIAN SYLLABICS NAAICANADIAN SYLL" +
"ABICS NICANADIAN SYLLABICS NIICANADIAN SYLLABICS NOCANADIAN SYLLABICS NO" +
"OCANADIAN SYLLABICS Y-CREE NOOCANADIAN SYLLABICS NACANADIAN SYLLABICS NA" +
"ACANADIAN SYLLABICS NWECANADIAN SYLLABICS WEST-CREE NWECANADIAN SYLLABIC" +
"S NWACANADIAN SYLLABICS WEST-CREE NWACANADIAN SYLLABICS NWAACANADIAN SYL" +
"LABICS WEST-CREE NWAACANADIAN SYLLABICS NASKAPI NWAACANADIAN SYLLABICS N" +
"CANADIAN SYLLABICS CARRIER NGCANADIAN SYLLABICS NHCANADIAN SYLLABICS LEC" +
"ANADIAN SYLLABICS LAAICANADIAN SYLLABICS LICANADIAN SYLLABICS LIICANADIA" +
"N SYLLABICS LOCANADIAN SYLLABICS LOOCANADIAN SYLLABICS Y-CREE LOOCANADIA" +
"N SYLLABICS LACANADIAN SYLLABICS LAACANADIAN SYLLABICS LWECANADIAN SYLLA" +
"BICS WEST-CREE LWECANADIAN SYLLABICS LWICANADIAN SYLLABICS WEST-CREE LWI" +
"CANADIAN SYLLABICS LWIICANADIAN SYLLABICS WEST-CREE LWIICANADIAN SYLLABI" +
"CS LWOCANADIAN SYLLABICS WEST-CREE LWOCANADIAN SYLLABICS LWOOCANADIAN SY" +
"LLABICS WEST-CREE LWOOCANADIAN SYLLABICS LWACANADIAN SYLLABICS WEST-CREE" +
" LWACANADIAN SYLLABICS LWAACANADIAN SYLLABICS WEST-CREE LWAACANADIAN SYL" +
"LABICS LCANADIAN SYLLABICS WEST-CREE LCANADIAN SYLLABICS MEDIAL LCANADIA" +
"N SYLLABICS SECANADIAN SYLLABICS SAAICANADIAN SYLLABICS SICANADIAN SYLLA" +
"BICS SIICANADIAN SYLLABICS SOCANADIAN SYLLABICS SOOCANADIAN SYLLABICS Y-" +
"CREE SOOCANADIAN SYLLABICS SACANADIAN SYLLABICS SAACANADIAN SYLLABICS SW" +
"ECANADIAN SYLLABICS WEST-CREE SWECANADIAN SYLLABICS SWICANADIAN SYLLABIC" +
"S WEST-CREE SWICANADIAN SYLLABICS SWIICANADIAN SYLLABICS WEST-CREE SWIIC" +
"ANADIAN SYLLABICS SWOCANADIAN SYLLABICS WEST-CREE SWOCANADIAN SYLLABICS " +
"SWOOCANADIAN SYLLABICS WEST-CREE SWOOCANADIAN SYLLABICS SWACANADIAN SYLL" +
"ABICS WEST-CREE SWACANADIAN SYLLABICS SWAACANADIAN SYLLABICS WEST-CREE S" +
"WAACANADIAN SYLLABICS NASKAPI SWAACANADIAN SYLLABICS SCANADIAN SYLLABICS" +
" ATHAPASCAN SCANADIAN SYLLABICS SWCANADIAN SYLLABICS BLACKFOOT SCANADIAN" +
" SYLLABICS MOOSE-CREE SKCANADIAN SYLLABICS NASKAPI SKWCANADIAN SYLLABICS" +
" NASKAPI S-WCANADIAN SYLLABICS NASKAPI SPWACANADIAN SYLLABICS NASKAPI ST" +
"WACANADIAN SYLLABICS NASKAPI SKWACANADIAN SYLLABICS NASKAPI SCWACANADIAN") + ("" +
" SYLLABICS SHECANADIAN SYLLABICS SHICANADIAN SYLLABICS SHIICANADIAN SYLL" +
"ABICS SHOCANADIAN SYLLABICS SHOOCANADIAN SYLLABICS SHACANADIAN SYLLABICS" +
" SHAACANADIAN SYLLABICS SHWECANADIAN SYLLABICS WEST-CREE SHWECANADIAN SY" +
"LLABICS SHWICANADIAN SYLLABICS WEST-CREE SHWICANADIAN SYLLABICS SHWIICAN" +
"ADIAN SYLLABICS WEST-CREE SHWIICANADIAN SYLLABICS SHWOCANADIAN SYLLABICS" +
" WEST-CREE SHWOCANADIAN SYLLABICS SHWOOCANADIAN SYLLABICS WEST-CREE SHWO" +
"OCANADIAN SYLLABICS SHWACANADIAN SYLLABICS WEST-CREE SHWACANADIAN SYLLAB" +
"ICS SHWAACANADIAN SYLLABICS WEST-CREE SHWAACANADIAN SYLLABICS SHCANADIAN" +
" SYLLABICS YECANADIAN SYLLABICS YAAICANADIAN SYLLABICS YICANADIAN SYLLAB" +
"ICS YIICANADIAN SYLLABICS YOCANADIAN SYLLABICS YOOCANADIAN SYLLABICS Y-C" +
"REE YOOCANADIAN SYLLABICS YACANADIAN SYLLABICS YAACANADIAN SYLLABICS YWE" +
"CANADIAN SYLLABICS WEST-CREE YWECANADIAN SYLLABICS YWICANADIAN SYLLABICS" +
" WEST-CREE YWICANADIAN SYLLABICS YWIICANADIAN SYLLABICS WEST-CREE YWIICA" +
"NADIAN SYLLABICS YWOCANADIAN SYLLABICS WEST-CREE YWOCANADIAN SYLLABICS Y" +
"WOOCANADIAN SYLLABICS WEST-CREE YWOOCANADIAN SYLLABICS YWACANADIAN SYLLA" +
"BICS WEST-CREE YWACANADIAN SYLLABICS YWAACANADIAN SYLLABICS WEST-CREE YW" +
"AACANADIAN SYLLABICS NASKAPI YWAACANADIAN SYLLABICS YCANADIAN SYLLABICS " +
"BIBLE-CREE YCANADIAN SYLLABICS WEST-CREE YCANADIAN SYLLABICS SAYISI YICA" +
"NADIAN SYLLABICS RECANADIAN SYLLABICS R-CREE RECANADIAN SYLLABICS WEST-C" +
"REE LECANADIAN SYLLABICS RAAICANADIAN SYLLABICS RICANADIAN SYLLABICS RII" +
"CANADIAN SYLLABICS ROCANADIAN SYLLABICS ROOCANADIAN SYLLABICS WEST-CREE " +
"LOCANADIAN SYLLABICS RACANADIAN SYLLABICS RAACANADIAN SYLLABICS WEST-CRE" +
"E LACANADIAN SYLLABICS RWAACANADIAN SYLLABICS WEST-CREE RWAACANADIAN SYL" +
"LABICS RCANADIAN SYLLABICS WEST-CREE RCANADIAN SYLLABICS MEDIAL RCANADIA" +
"N SYLLABICS FECANADIAN SYLLABICS FAAICANADIAN SYLLABICS FICANADIAN SYLLA" +
"BICS FIICANADIAN SYLLABICS FOCANADIAN SYLLABICS FOOCANADIAN SYLLABICS FA" +
"CANADIAN SYLLABICS FAACANADIAN SYLLABICS FWAACANADIAN SYLLABICS WEST-CRE" +
"E FWAACANADIAN SYLLABICS FCANADIAN SYLLABICS THECANADIAN SYLLABICS N-CRE" +
"E THECANADIAN SYLLABICS THICANADIAN SYLLABICS N-CREE THICANADIAN SYLLABI" +
"CS THIICANADIAN SYLLABICS N-CREE THIICANADIAN SYLLABICS THOCANADIAN SYLL" +
"ABICS THOOCANADIAN SYLLABICS THACANADIAN SYLLABICS THAACANADIAN SYLLABIC" +
"S THWAACANADIAN SYLLABICS WEST-CREE THWAACANADIAN SYLLABICS THCANADIAN S" +
"YLLABICS TTHECANADIAN SYLLABICS TTHICANADIAN SYLLABICS TTHOCANADIAN SYLL" +
"ABICS TTHACANADIAN SYLLABICS TTHCANADIAN SYLLABICS TYECANADIAN SYLLABICS" +
" TYICANADIAN SYLLABICS TYOCANADIAN SYLLABICS TYACANADIAN SYLLABICS NUNAV" +
"IK HECANADIAN SYLLABICS NUNAVIK HICANADIAN SYLLABICS NUNAVIK HIICANADIAN" +
" SYLLABICS NUNAVIK HOCANADIAN SYLLABICS NUNAVIK HOOCANADIAN SYLLABICS NU" +
"NAVIK HACANADIAN SYLLABICS NUNAVIK HAACANADIAN SYLLABICS NUNAVIK HCANADI" +
"AN SYLLABICS NUNAVUT HCANADIAN SYLLABICS HKCANADIAN SYLLABICS QAAICANADI" +
"AN SYLLABICS QICANADIAN SYLLABICS QIICANADIAN SYLLABICS QOCANADIAN SYLLA" +
"BICS QOOCANADIAN SYLLABICS QACANADIAN SYLLABICS QAACANADIAN SYLLABICS QC" +
"ANADIAN SYLLABICS TLHECANADIAN SYLLABICS TLHICANADIAN SYLLABICS TLHOCANA" +
"DIAN SYLLABICS TLHACANADIAN SYLLABICS WEST-CREE RECANADIAN SYLLABICS WES" +
"T-CREE RICANADIAN SYLLABICS WEST-CREE ROCANADIAN SYLLABICS WEST-CREE RAC" +
"ANADIAN SYLLABICS NGAAICANADIAN SYLLABICS NGICANADIAN SYLLABICS NGIICANA" +
"DIAN SYLLABICS NGOCANADIAN SYLLABICS NGOOCANADIAN SYLLABICS NGACANADIAN " +
"SYLLABICS NGAACANADIAN SYLLABICS NGCANADIAN SYLLABICS NNGCANADIAN SYLLAB" +
"ICS SAYISI SHECANADIAN SYLLABICS SAYISI SHICANADIAN SYLLABICS SAYISI SHO" +
"CANADIAN SYLLABICS SAYISI SHACANADIAN SYLLABICS WOODS-CREE THECANADIAN S" +
"YLLABICS WOODS-CREE THICANADIAN SYLLABICS WOODS-CREE THOCANADIAN SYLLABI" +
"CS WOODS-CREE THACANADIAN SYLLABICS WOODS-CREE THCANADIAN SYLLABICS LHIC" +
"ANADIAN SYLLABICS LHIICANADIAN SYLLABICS LHOCANADIAN SYLLABICS LHOOCANAD" +
"IAN SYLLABICS LHACANADIAN SYLLABICS LHAACANADIAN SYLLABICS LHCANADIAN SY" +
"LLABICS TH-CREE THECANADIAN SYLLABICS TH-CREE THICANADIAN SYLLABICS TH-C" +
"REE THIICANADIAN SYLLABICS TH-CREE THOCANADIAN SYLLABICS TH-CREE THOOCAN" +
"ADIAN SYLLABICS TH-CREE THACANADIAN SYLLABICS TH-CREE THAACANADIAN SYLLA" +
"BICS TH-CREE THCANADIAN SYLLABICS AIVILIK BCANADIAN SYLLABICS BLACKFOOT " +
"ECANADIAN SYLLABICS BLACKFOOT ICANADIAN SYLLABICS BLACKFOOT OCANADIAN SY" +
"LLABICS BLACKFOOT ACANADIAN SYLLABICS BLACKFOOT WECANADIAN SYLLABICS BLA" +
"CKFOOT WICANADIAN SYLLABICS BLACKFOOT WOCANADIAN SYLLABICS BLACKFOOT WAC" +
"ANADIAN SYLLABICS BLACKFOOT NECANADIAN SYLLABICS BLACKFOOT NICANADIAN SY" +
"LLABICS BLACKFOOT NOCANADIAN SYLLABICS BLACKFOOT NACANADIAN SYLLABICS BL" +
"ACKFOOT KECANADIAN SYLLABICS BLACKFOOT KICANADIAN SYLLABICS BLACKFOOT KO" +
"CANADIAN SYLLABICS BLACKFOOT KACANADIAN SYLLABICS SAYISI HECANADIAN SYLL") + ("" +
"ABICS SAYISI HICANADIAN SYLLABICS SAYISI HOCANADIAN SYLLABICS SAYISI HAC" +
"ANADIAN SYLLABICS CARRIER GHUCANADIAN SYLLABICS CARRIER GHOCANADIAN SYLL" +
"ABICS CARRIER GHECANADIAN SYLLABICS CARRIER GHEECANADIAN SYLLABICS CARRI" +
"ER GHICANADIAN SYLLABICS CARRIER GHACANADIAN SYLLABICS CARRIER RUCANADIA" +
"N SYLLABICS CARRIER ROCANADIAN SYLLABICS CARRIER RECANADIAN SYLLABICS CA" +
"RRIER REECANADIAN SYLLABICS CARRIER RICANADIAN SYLLABICS CARRIER RACANAD" +
"IAN SYLLABICS CARRIER WUCANADIAN SYLLABICS CARRIER WOCANADIAN SYLLABICS " +
"CARRIER WECANADIAN SYLLABICS CARRIER WEECANADIAN SYLLABICS CARRIER WICAN" +
"ADIAN SYLLABICS CARRIER WACANADIAN SYLLABICS CARRIER HWUCANADIAN SYLLABI" +
"CS CARRIER HWOCANADIAN SYLLABICS CARRIER HWECANADIAN SYLLABICS CARRIER H" +
"WEECANADIAN SYLLABICS CARRIER HWICANADIAN SYLLABICS CARRIER HWACANADIAN " +
"SYLLABICS CARRIER THUCANADIAN SYLLABICS CARRIER THOCANADIAN SYLLABICS CA" +
"RRIER THECANADIAN SYLLABICS CARRIER THEECANADIAN SYLLABICS CARRIER THICA" +
"NADIAN SYLLABICS CARRIER THACANADIAN SYLLABICS CARRIER TTUCANADIAN SYLLA" +
"BICS CARRIER TTOCANADIAN SYLLABICS CARRIER TTECANADIAN SYLLABICS CARRIER" +
" TTEECANADIAN SYLLABICS CARRIER TTICANADIAN SYLLABICS CARRIER TTACANADIA" +
"N SYLLABICS CARRIER PUCANADIAN SYLLABICS CARRIER POCANADIAN SYLLABICS CA" +
"RRIER PECANADIAN SYLLABICS CARRIER PEECANADIAN SYLLABICS CARRIER PICANAD" +
"IAN SYLLABICS CARRIER PACANADIAN SYLLABICS CARRIER PCANADIAN SYLLABICS C" +
"ARRIER GUCANADIAN SYLLABICS CARRIER GOCANADIAN SYLLABICS CARRIER GECANAD" +
"IAN SYLLABICS CARRIER GEECANADIAN SYLLABICS CARRIER GICANADIAN SYLLABICS" +
" CARRIER GACANADIAN SYLLABICS CARRIER KHUCANADIAN SYLLABICS CARRIER KHOC" +
"ANADIAN SYLLABICS CARRIER KHECANADIAN SYLLABICS CARRIER KHEECANADIAN SYL" +
"LABICS CARRIER KHICANADIAN SYLLABICS CARRIER KHACANADIAN SYLLABICS CARRI" +
"ER KKUCANADIAN SYLLABICS CARRIER KKOCANADIAN SYLLABICS CARRIER KKECANADI" +
"AN SYLLABICS CARRIER KKEECANADIAN SYLLABICS CARRIER KKICANADIAN SYLLABIC" +
"S CARRIER KKACANADIAN SYLLABICS CARRIER KKCANADIAN SYLLABICS CARRIER NUC" +
"ANADIAN SYLLABICS CARRIER NOCANADIAN SYLLABICS CARRIER NECANADIAN SYLLAB" +
"ICS CARRIER NEECANADIAN SYLLABICS CARRIER NICANADIAN SYLLABICS CARRIER N" +
"ACANADIAN SYLLABICS CARRIER MUCANADIAN SYLLABICS CARRIER MOCANADIAN SYLL" +
"ABICS CARRIER MECANADIAN SYLLABICS CARRIER MEECANADIAN SYLLABICS CARRIER" +
" MICANADIAN SYLLABICS CARRIER MACANADIAN SYLLABICS CARRIER YUCANADIAN SY" +
"LLABICS CARRIER YOCANADIAN SYLLABICS CARRIER YECANADIAN SYLLABICS CARRIE" +
"R YEECANADIAN SYLLABICS CARRIER YICANADIAN SYLLABICS CARRIER YACANADIAN " +
"SYLLABICS CARRIER JUCANADIAN SYLLABICS SAYISI JUCANADIAN SYLLABICS CARRI" +
"ER JOCANADIAN SYLLABICS CARRIER JECANADIAN SYLLABICS CARRIER JEECANADIAN" +
" SYLLABICS CARRIER JICANADIAN SYLLABICS SAYISI JICANADIAN SYLLABICS CARR" +
"IER JACANADIAN SYLLABICS CARRIER JJUCANADIAN SYLLABICS CARRIER JJOCANADI" +
"AN SYLLABICS CARRIER JJECANADIAN SYLLABICS CARRIER JJEECANADIAN SYLLABIC" +
"S CARRIER JJICANADIAN SYLLABICS CARRIER JJACANADIAN SYLLABICS CARRIER LU" +
"CANADIAN SYLLABICS CARRIER LOCANADIAN SYLLABICS CARRIER LECANADIAN SYLLA" +
"BICS CARRIER LEECANADIAN SYLLABICS CARRIER LICANADIAN SYLLABICS CARRIER " +
"LACANADIAN SYLLABICS CARRIER DLUCANADIAN SYLLABICS CARRIER DLOCANADIAN S" +
"YLLABICS CARRIER DLECANADIAN SYLLABICS CARRIER DLEECANADIAN SYLLABICS CA" +
"RRIER DLICANADIAN SYLLABICS CARRIER DLACANADIAN SYLLABICS CARRIER LHUCAN" +
"ADIAN SYLLABICS CARRIER LHOCANADIAN SYLLABICS CARRIER LHECANADIAN SYLLAB" +
"ICS CARRIER LHEECANADIAN SYLLABICS CARRIER LHICANADIAN SYLLABICS CARRIER" +
" LHACANADIAN SYLLABICS CARRIER TLHUCANADIAN SYLLABICS CARRIER TLHOCANADI" +
"AN SYLLABICS CARRIER TLHECANADIAN SYLLABICS CARRIER TLHEECANADIAN SYLLAB" +
"ICS CARRIER TLHICANADIAN SYLLABICS CARRIER TLHACANADIAN SYLLABICS CARRIE" +
"R TLUCANADIAN SYLLABICS CARRIER TLOCANADIAN SYLLABICS CARRIER TLECANADIA" +
"N SYLLABICS CARRIER TLEECANADIAN SYLLABICS CARRIER TLICANADIAN SYLLABICS" +
" CARRIER TLACANADIAN SYLLABICS CARRIER ZUCANADIAN SYLLABICS CARRIER ZOCA" +
"NADIAN SYLLABICS CARRIER ZECANADIAN SYLLABICS CARRIER ZEECANADIAN SYLLAB" +
"ICS CARRIER ZICANADIAN SYLLABICS CARRIER ZACANADIAN SYLLABICS CARRIER ZC" +
"ANADIAN SYLLABICS CARRIER INITIAL ZCANADIAN SYLLABICS CARRIER DZUCANADIA" +
"N SYLLABICS CARRIER DZOCANADIAN SYLLABICS CARRIER DZECANADIAN SYLLABICS " +
"CARRIER DZEECANADIAN SYLLABICS CARRIER DZICANADIAN SYLLABICS CARRIER DZA" +
"CANADIAN SYLLABICS CARRIER SUCANADIAN SYLLABICS CARRIER SOCANADIAN SYLLA" +
"BICS CARRIER SECANADIAN SYLLABICS CARRIER SEECANADIAN SYLLABICS CARRIER " +
"SICANADIAN SYLLABICS CARRIER SACANADIAN SYLLABICS CARRIER SHUCANADIAN SY" +
"LLABICS CARRIER SHOCANADIAN SYLLABICS CARRIER SHECANADIAN SYLLABICS CARR" +
"IER SHEECANADIAN SYLLABICS CARRIER SHICANADIAN SYLLABICS CARRIER SHACANA" +
"DIAN SYLLABICS CARRIER SHCANADIAN SYLLABICS CARRIER TSUCANADIAN SYLLABIC") + ("" +
"S CARRIER TSOCANADIAN SYLLABICS CARRIER TSECANADIAN SYLLABICS CARRIER TS" +
"EECANADIAN SYLLABICS CARRIER TSICANADIAN SYLLABICS CARRIER TSACANADIAN S" +
"YLLABICS CARRIER CHUCANADIAN SYLLABICS CARRIER CHOCANADIAN SYLLABICS CAR" +
"RIER CHECANADIAN SYLLABICS CARRIER CHEECANADIAN SYLLABICS CARRIER CHICAN" +
"ADIAN SYLLABICS CARRIER CHACANADIAN SYLLABICS CARRIER TTSUCANADIAN SYLLA" +
"BICS CARRIER TTSOCANADIAN SYLLABICS CARRIER TTSECANADIAN SYLLABICS CARRI" +
"ER TTSEECANADIAN SYLLABICS CARRIER TTSICANADIAN SYLLABICS CARRIER TTSACA" +
"NADIAN SYLLABICS CHI SIGNCANADIAN SYLLABICS FULL STOPCANADIAN SYLLABICS " +
"QAICANADIAN SYLLABICS NGAICANADIAN SYLLABICS NNGICANADIAN SYLLABICS NNGI" +
"ICANADIAN SYLLABICS NNGOCANADIAN SYLLABICS NNGOOCANADIAN SYLLABICS NNGAC" +
"ANADIAN SYLLABICS NNGAACANADIAN SYLLABICS WOODS-CREE THWEECANADIAN SYLLA" +
"BICS WOODS-CREE THWICANADIAN SYLLABICS WOODS-CREE THWIICANADIAN SYLLABIC" +
"S WOODS-CREE THWOCANADIAN SYLLABICS WOODS-CREE THWOOCANADIAN SYLLABICS W" +
"OODS-CREE THWACANADIAN SYLLABICS WOODS-CREE THWAACANADIAN SYLLABICS WOOD" +
"S-CREE FINAL THCANADIAN SYLLABICS BLACKFOOT WOGHAM SPACE MARKOGHAM LETTE" +
"R BEITHOGHAM LETTER LUISOGHAM LETTER FEARNOGHAM LETTER SAILOGHAM LETTER " +
"NIONOGHAM LETTER UATHOGHAM LETTER DAIROGHAM LETTER TINNEOGHAM LETTER COL" +
"LOGHAM LETTER CEIRTOGHAM LETTER MUINOGHAM LETTER GORTOGHAM LETTER NGEADA" +
"LOGHAM LETTER STRAIFOGHAM LETTER RUISOGHAM LETTER AILMOGHAM LETTER ONNOG" +
"HAM LETTER UROGHAM LETTER EADHADHOGHAM LETTER IODHADHOGHAM LETTER EABHAD" +
"HOGHAM LETTER OROGHAM LETTER UILLEANNOGHAM LETTER IFINOGHAM LETTER EAMHA" +
"NCHOLLOGHAM LETTER PEITHOGHAM FEATHER MARKOGHAM REVERSED FEATHER MARKRUN" +
"IC LETTER FEHU FEOH FE FRUNIC LETTER VRUNIC LETTER URUZ UR URUNIC LETTER" +
" YRRUNIC LETTER YRUNIC LETTER WRUNIC LETTER THURISAZ THURS THORNRUNIC LE" +
"TTER ETHRUNIC LETTER ANSUZ ARUNIC LETTER OS ORUNIC LETTER AC ARUNIC LETT" +
"ER AESCRUNIC LETTER LONG-BRANCH-OSS ORUNIC LETTER SHORT-TWIG-OSS ORUNIC " +
"LETTER ORUNIC LETTER OERUNIC LETTER ONRUNIC LETTER RAIDO RAD REID RRUNIC" +
" LETTER KAUNARUNIC LETTER CENRUNIC LETTER KAUN KRUNIC LETTER GRUNIC LETT" +
"ER ENGRUNIC LETTER GEBO GYFU GRUNIC LETTER GARRUNIC LETTER WUNJO WYNN WR" +
"UNIC LETTER HAGLAZ HRUNIC LETTER HAEGL HRUNIC LETTER LONG-BRANCH-HAGALL " +
"HRUNIC LETTER SHORT-TWIG-HAGALL HRUNIC LETTER NAUDIZ NYD NAUD NRUNIC LET" +
"TER SHORT-TWIG-NAUD NRUNIC LETTER DOTTED-NRUNIC LETTER ISAZ IS ISS IRUNI" +
"C LETTER ERUNIC LETTER JERAN JRUNIC LETTER GERRUNIC LETTER LONG-BRANCH-A" +
"R AERUNIC LETTER SHORT-TWIG-AR ARUNIC LETTER IWAZ EOHRUNIC LETTER PERTHO" +
" PEORTH PRUNIC LETTER ALGIZ EOLHXRUNIC LETTER SOWILO SRUNIC LETTER SIGEL" +
" LONG-BRANCH-SOL SRUNIC LETTER SHORT-TWIG-SOL SRUNIC LETTER CRUNIC LETTE" +
"R ZRUNIC LETTER TIWAZ TIR TYR TRUNIC LETTER SHORT-TWIG-TYR TRUNIC LETTER" +
" DRUNIC LETTER BERKANAN BEORC BJARKAN BRUNIC LETTER SHORT-TWIG-BJARKAN B" +
"RUNIC LETTER DOTTED-PRUNIC LETTER OPEN-PRUNIC LETTER EHWAZ EH ERUNIC LET" +
"TER MANNAZ MAN MRUNIC LETTER LONG-BRANCH-MADR MRUNIC LETTER SHORT-TWIG-M" +
"ADR MRUNIC LETTER LAUKAZ LAGU LOGR LRUNIC LETTER DOTTED-LRUNIC LETTER IN" +
"GWAZRUNIC LETTER INGRUNIC LETTER DAGAZ DAEG DRUNIC LETTER OTHALAN ETHEL " +
"ORUNIC LETTER EARRUNIC LETTER IORRUNIC LETTER CWEORTHRUNIC LETTER CALCRU" +
"NIC LETTER CEALCRUNIC LETTER STANRUNIC LETTER LONG-BRANCH-YRRUNIC LETTER" +
" SHORT-TWIG-YRRUNIC LETTER ICELANDIC-YRRUNIC LETTER QRUNIC LETTER XRUNIC" +
" SINGLE PUNCTUATIONRUNIC MULTIPLE PUNCTUATIONRUNIC CROSS PUNCTUATIONRUNI" +
"C ARLAUG SYMBOLRUNIC TVIMADUR SYMBOLRUNIC BELGTHOR SYMBOLRUNIC LETTER KR" +
"UNIC LETTER SHRUNIC LETTER OORUNIC LETTER FRANKS CASKET OSRUNIC LETTER F" +
"RANKS CASKET ISRUNIC LETTER FRANKS CASKET EHRUNIC LETTER FRANKS CASKET A" +
"CRUNIC LETTER FRANKS CASKET AESCTAGALOG LETTER ATAGALOG LETTER ITAGALOG " +
"LETTER UTAGALOG LETTER KATAGALOG LETTER GATAGALOG LETTER NGATAGALOG LETT" +
"ER TATAGALOG LETTER DATAGALOG LETTER NATAGALOG LETTER PATAGALOG LETTER B" +
"ATAGALOG LETTER MATAGALOG LETTER YATAGALOG LETTER RATAGALOG LETTER LATAG" +
"ALOG LETTER WATAGALOG LETTER SATAGALOG LETTER HATAGALOG VOWEL SIGN ITAGA" +
"LOG VOWEL SIGN UTAGALOG SIGN VIRAMATAGALOG SIGN PAMUDPODTAGALOG LETTER A" +
"RCHAIC RAHANUNOO LETTER AHANUNOO LETTER IHANUNOO LETTER UHANUNOO LETTER " +
"KAHANUNOO LETTER GAHANUNOO LETTER NGAHANUNOO LETTER TAHANUNOO LETTER DAH" +
"ANUNOO LETTER NAHANUNOO LETTER PAHANUNOO LETTER BAHANUNOO LETTER MAHANUN" +
"OO LETTER YAHANUNOO LETTER RAHANUNOO LETTER LAHANUNOO LETTER WAHANUNOO L" +
"ETTER SAHANUNOO LETTER HAHANUNOO VOWEL SIGN IHANUNOO VOWEL SIGN UHANUNOO" +
" SIGN PAMUDPODPHILIPPINE SINGLE PUNCTUATIONPHILIPPINE DOUBLE PUNCTUATION" +
"BUHID LETTER ABUHID LETTER IBUHID LETTER UBUHID LETTER KABUHID LETTER GA" +
"BUHID LETTER NGABUHID LETTER TABUHID LETTER DABUHID LETTER NABUHID LETTE" +
"R PABUHID LETTER BABUHID LETTER MABUHID LETTER YABUHID LETTER RABUHID LE") + ("" +
"TTER LABUHID LETTER WABUHID LETTER SABUHID LETTER HABUHID VOWEL SIGN IBU" +
"HID VOWEL SIGN UTAGBANWA LETTER ATAGBANWA LETTER ITAGBANWA LETTER UTAGBA" +
"NWA LETTER KATAGBANWA LETTER GATAGBANWA LETTER NGATAGBANWA LETTER TATAGB" +
"ANWA LETTER DATAGBANWA LETTER NATAGBANWA LETTER PATAGBANWA LETTER BATAGB" +
"ANWA LETTER MATAGBANWA LETTER YATAGBANWA LETTER LATAGBANWA LETTER WATAGB" +
"ANWA LETTER SATAGBANWA VOWEL SIGN ITAGBANWA VOWEL SIGN UKHMER LETTER KAK" +
"HMER LETTER KHAKHMER LETTER KOKHMER LETTER KHOKHMER LETTER NGOKHMER LETT" +
"ER CAKHMER LETTER CHAKHMER LETTER COKHMER LETTER CHOKHMER LETTER NYOKHME" +
"R LETTER DAKHMER LETTER TTHAKHMER LETTER DOKHMER LETTER TTHOKHMER LETTER" +
" NNOKHMER LETTER TAKHMER LETTER THAKHMER LETTER TOKHMER LETTER THOKHMER " +
"LETTER NOKHMER LETTER BAKHMER LETTER PHAKHMER LETTER POKHMER LETTER PHOK" +
"HMER LETTER MOKHMER LETTER YOKHMER LETTER ROKHMER LETTER LOKHMER LETTER " +
"VOKHMER LETTER SHAKHMER LETTER SSOKHMER LETTER SAKHMER LETTER HAKHMER LE" +
"TTER LAKHMER LETTER QAKHMER INDEPENDENT VOWEL QAQKHMER INDEPENDENT VOWEL" +
" QAAKHMER INDEPENDENT VOWEL QIKHMER INDEPENDENT VOWEL QIIKHMER INDEPENDE" +
"NT VOWEL QUKHMER INDEPENDENT VOWEL QUKKHMER INDEPENDENT VOWEL QUUKHMER I" +
"NDEPENDENT VOWEL QUUVKHMER INDEPENDENT VOWEL RYKHMER INDEPENDENT VOWEL R" +
"YYKHMER INDEPENDENT VOWEL LYKHMER INDEPENDENT VOWEL LYYKHMER INDEPENDENT" +
" VOWEL QEKHMER INDEPENDENT VOWEL QAIKHMER INDEPENDENT VOWEL QOO TYPE ONE" +
"KHMER INDEPENDENT VOWEL QOO TYPE TWOKHMER INDEPENDENT VOWEL QAUKHMER VOW" +
"EL INHERENT AQKHMER VOWEL INHERENT AAKHMER VOWEL SIGN AAKHMER VOWEL SIGN" +
" IKHMER VOWEL SIGN IIKHMER VOWEL SIGN YKHMER VOWEL SIGN YYKHMER VOWEL SI" +
"GN UKHMER VOWEL SIGN UUKHMER VOWEL SIGN UAKHMER VOWEL SIGN OEKHMER VOWEL" +
" SIGN YAKHMER VOWEL SIGN IEKHMER VOWEL SIGN EKHMER VOWEL SIGN AEKHMER VO" +
"WEL SIGN AIKHMER VOWEL SIGN OOKHMER VOWEL SIGN AUKHMER SIGN NIKAHITKHMER" +
" SIGN REAHMUKKHMER SIGN YUUKALEAPINTUKHMER SIGN MUUSIKATOANKHMER SIGN TR" +
"IISAPKHMER SIGN BANTOCKHMER SIGN ROBATKHMER SIGN TOANDAKHIATKHMER SIGN K" +
"AKABATKHMER SIGN AHSDAKHMER SIGN SAMYOK SANNYAKHMER SIGN VIRIAMKHMER SIG" +
"N COENGKHMER SIGN BATHAMASATKHMER SIGN KHANKHMER SIGN BARIYOOSANKHMER SI" +
"GN CAMNUC PII KUUHKHMER SIGN LEK TOOKHMER SIGN BEYYALKHMER SIGN PHNAEK M" +
"UANKHMER SIGN KOOMUUTKHMER CURRENCY SYMBOL RIELKHMER SIGN AVAKRAHASANYAK" +
"HMER SIGN ATTHACANKHMER DIGIT ZEROKHMER DIGIT ONEKHMER DIGIT TWOKHMER DI" +
"GIT THREEKHMER DIGIT FOURKHMER DIGIT FIVEKHMER DIGIT SIXKHMER DIGIT SEVE" +
"NKHMER DIGIT EIGHTKHMER DIGIT NINEKHMER SYMBOL LEK ATTAK SONKHMER SYMBOL" +
" LEK ATTAK MUOYKHMER SYMBOL LEK ATTAK PIIKHMER SYMBOL LEK ATTAK BEIKHMER" +
" SYMBOL LEK ATTAK BUONKHMER SYMBOL LEK ATTAK PRAMKHMER SYMBOL LEK ATTAK " +
"PRAM-MUOYKHMER SYMBOL LEK ATTAK PRAM-PIIKHMER SYMBOL LEK ATTAK PRAM-BEIK" +
"HMER SYMBOL LEK ATTAK PRAM-BUONMONGOLIAN BIRGAMONGOLIAN ELLIPSISMONGOLIA" +
"N COMMAMONGOLIAN FULL STOPMONGOLIAN COLONMONGOLIAN FOUR DOTSMONGOLIAN TO" +
"DO SOFT HYPHENMONGOLIAN SIBE SYLLABLE BOUNDARY MARKERMONGOLIAN MANCHU CO" +
"MMAMONGOLIAN MANCHU FULL STOPMONGOLIAN NIRUGUMONGOLIAN FREE VARIATION SE" +
"LECTOR ONEMONGOLIAN FREE VARIATION SELECTOR TWOMONGOLIAN FREE VARIATION " +
"SELECTOR THREEMONGOLIAN VOWEL SEPARATORMONGOLIAN FREE VARIATION SELECTOR" +
" FOURMONGOLIAN DIGIT ZEROMONGOLIAN DIGIT ONEMONGOLIAN DIGIT TWOMONGOLIAN" +
" DIGIT THREEMONGOLIAN DIGIT FOURMONGOLIAN DIGIT FIVEMONGOLIAN DIGIT SIXM" +
"ONGOLIAN DIGIT SEVENMONGOLIAN DIGIT EIGHTMONGOLIAN DIGIT NINEMONGOLIAN L" +
"ETTER AMONGOLIAN LETTER EMONGOLIAN LETTER IMONGOLIAN LETTER OMONGOLIAN L" +
"ETTER UMONGOLIAN LETTER OEMONGOLIAN LETTER UEMONGOLIAN LETTER EEMONGOLIA" +
"N LETTER NAMONGOLIAN LETTER ANGMONGOLIAN LETTER BAMONGOLIAN LETTER PAMON" +
"GOLIAN LETTER QAMONGOLIAN LETTER GAMONGOLIAN LETTER MAMONGOLIAN LETTER L" +
"AMONGOLIAN LETTER SAMONGOLIAN LETTER SHAMONGOLIAN LETTER TAMONGOLIAN LET" +
"TER DAMONGOLIAN LETTER CHAMONGOLIAN LETTER JAMONGOLIAN LETTER YAMONGOLIA" +
"N LETTER RAMONGOLIAN LETTER WAMONGOLIAN LETTER FAMONGOLIAN LETTER KAMONG" +
"OLIAN LETTER KHAMONGOLIAN LETTER TSAMONGOLIAN LETTER ZAMONGOLIAN LETTER " +
"HAAMONGOLIAN LETTER ZRAMONGOLIAN LETTER LHAMONGOLIAN LETTER ZHIMONGOLIAN" +
" LETTER CHIMONGOLIAN LETTER TODO LONG VOWEL SIGNMONGOLIAN LETTER TODO EM" +
"ONGOLIAN LETTER TODO IMONGOLIAN LETTER TODO OMONGOLIAN LETTER TODO UMONG" +
"OLIAN LETTER TODO OEMONGOLIAN LETTER TODO UEMONGOLIAN LETTER TODO ANGMON" +
"GOLIAN LETTER TODO BAMONGOLIAN LETTER TODO PAMONGOLIAN LETTER TODO QAMON" +
"GOLIAN LETTER TODO GAMONGOLIAN LETTER TODO MAMONGOLIAN LETTER TODO TAMON" +
"GOLIAN LETTER TODO DAMONGOLIAN LETTER TODO CHAMONGOLIAN LETTER TODO JAMO" +
"NGOLIAN LETTER TODO TSAMONGOLIAN LETTER TODO YAMONGOLIAN LETTER TODO WAM" +
"ONGOLIAN LETTER TODO KAMONGOLIAN LETTER TODO GAAMONGOLIAN LETTER TODO HA" +
"AMONGOLIAN LETTER TODO JIAMONGOLIAN LETTER TODO NIAMONGOLIAN LETTER TODO") + ("" +
" DZAMONGOLIAN LETTER SIBE EMONGOLIAN LETTER SIBE IMONGOLIAN LETTER SIBE " +
"IYMONGOLIAN LETTER SIBE UEMONGOLIAN LETTER SIBE UMONGOLIAN LETTER SIBE A" +
"NGMONGOLIAN LETTER SIBE KAMONGOLIAN LETTER SIBE GAMONGOLIAN LETTER SIBE " +
"HAMONGOLIAN LETTER SIBE PAMONGOLIAN LETTER SIBE SHAMONGOLIAN LETTER SIBE" +
" TAMONGOLIAN LETTER SIBE DAMONGOLIAN LETTER SIBE JAMONGOLIAN LETTER SIBE" +
" FAMONGOLIAN LETTER SIBE GAAMONGOLIAN LETTER SIBE HAAMONGOLIAN LETTER SI" +
"BE TSAMONGOLIAN LETTER SIBE ZAMONGOLIAN LETTER SIBE RAAMONGOLIAN LETTER " +
"SIBE CHAMONGOLIAN LETTER SIBE ZHAMONGOLIAN LETTER MANCHU IMONGOLIAN LETT" +
"ER MANCHU KAMONGOLIAN LETTER MANCHU RAMONGOLIAN LETTER MANCHU FAMONGOLIA" +
"N LETTER MANCHU ZHAMONGOLIAN LETTER CHA WITH TWO DOTSMONGOLIAN LETTER AL" +
"I GALI ANUSVARA ONEMONGOLIAN LETTER ALI GALI VISARGA ONEMONGOLIAN LETTER" +
" ALI GALI DAMARUMONGOLIAN LETTER ALI GALI UBADAMAMONGOLIAN LETTER ALI GA" +
"LI INVERTED UBADAMAMONGOLIAN LETTER ALI GALI BALUDAMONGOLIAN LETTER ALI " +
"GALI THREE BALUDAMONGOLIAN LETTER ALI GALI AMONGOLIAN LETTER ALI GALI IM" +
"ONGOLIAN LETTER ALI GALI KAMONGOLIAN LETTER ALI GALI NGAMONGOLIAN LETTER" +
" ALI GALI CAMONGOLIAN LETTER ALI GALI TTAMONGOLIAN LETTER ALI GALI TTHAM" +
"ONGOLIAN LETTER ALI GALI DDAMONGOLIAN LETTER ALI GALI NNAMONGOLIAN LETTE" +
"R ALI GALI TAMONGOLIAN LETTER ALI GALI DAMONGOLIAN LETTER ALI GALI PAMON" +
"GOLIAN LETTER ALI GALI PHAMONGOLIAN LETTER ALI GALI SSAMONGOLIAN LETTER " +
"ALI GALI ZHAMONGOLIAN LETTER ALI GALI ZAMONGOLIAN LETTER ALI GALI AHMONG" +
"OLIAN LETTER TODO ALI GALI TAMONGOLIAN LETTER TODO ALI GALI ZHAMONGOLIAN" +
" LETTER MANCHU ALI GALI GHAMONGOLIAN LETTER MANCHU ALI GALI NGAMONGOLIAN" +
" LETTER MANCHU ALI GALI CAMONGOLIAN LETTER MANCHU ALI GALI JHAMONGOLIAN " +
"LETTER MANCHU ALI GALI TTAMONGOLIAN LETTER MANCHU ALI GALI DDHAMONGOLIAN" +
" LETTER MANCHU ALI GALI TAMONGOLIAN LETTER MANCHU ALI GALI DHAMONGOLIAN " +
"LETTER MANCHU ALI GALI SSAMONGOLIAN LETTER MANCHU ALI GALI CYAMONGOLIAN " +
"LETTER MANCHU ALI GALI ZHAMONGOLIAN LETTER MANCHU ALI GALI ZAMONGOLIAN L" +
"ETTER ALI GALI HALF UMONGOLIAN LETTER ALI GALI HALF YAMONGOLIAN LETTER M" +
"ANCHU ALI GALI BHAMONGOLIAN LETTER ALI GALI DAGALGAMONGOLIAN LETTER MANC" +
"HU ALI GALI LHACANADIAN SYLLABICS OYCANADIAN SYLLABICS AYCANADIAN SYLLAB" +
"ICS AAYCANADIAN SYLLABICS WAYCANADIAN SYLLABICS POYCANADIAN SYLLABICS PA" +
"YCANADIAN SYLLABICS PWOYCANADIAN SYLLABICS TAYCANADIAN SYLLABICS KAYCANA" +
"DIAN SYLLABICS KWAYCANADIAN SYLLABICS MAYCANADIAN SYLLABICS NOYCANADIAN " +
"SYLLABICS NAYCANADIAN SYLLABICS LAYCANADIAN SYLLABICS SOYCANADIAN SYLLAB" +
"ICS SAYCANADIAN SYLLABICS SHOYCANADIAN SYLLABICS SHAYCANADIAN SYLLABICS " +
"SHWOYCANADIAN SYLLABICS YOYCANADIAN SYLLABICS YAYCANADIAN SYLLABICS RAYC" +
"ANADIAN SYLLABICS NWICANADIAN SYLLABICS OJIBWAY NWICANADIAN SYLLABICS NW" +
"IICANADIAN SYLLABICS OJIBWAY NWIICANADIAN SYLLABICS NWOCANADIAN SYLLABIC" +
"S OJIBWAY NWOCANADIAN SYLLABICS NWOOCANADIAN SYLLABICS OJIBWAY NWOOCANAD" +
"IAN SYLLABICS RWEECANADIAN SYLLABICS RWICANADIAN SYLLABICS RWIICANADIAN " +
"SYLLABICS RWOCANADIAN SYLLABICS RWOOCANADIAN SYLLABICS RWACANADIAN SYLLA" +
"BICS OJIBWAY PCANADIAN SYLLABICS OJIBWAY TCANADIAN SYLLABICS OJIBWAY KCA" +
"NADIAN SYLLABICS OJIBWAY CCANADIAN SYLLABICS OJIBWAY MCANADIAN SYLLABICS" +
" OJIBWAY NCANADIAN SYLLABICS OJIBWAY SCANADIAN SYLLABICS OJIBWAY SHCANAD" +
"IAN SYLLABICS EASTERN WCANADIAN SYLLABICS WESTERN WCANADIAN SYLLABICS FI" +
"NAL SMALL RINGCANADIAN SYLLABICS FINAL RAISED DOTCANADIAN SYLLABICS R-CR" +
"EE RWECANADIAN SYLLABICS WEST-CREE LOOCANADIAN SYLLABICS WEST-CREE LAACA" +
"NADIAN SYLLABICS THWECANADIAN SYLLABICS THWACANADIAN SYLLABICS TTHWECANA" +
"DIAN SYLLABICS TTHOOCANADIAN SYLLABICS TTHAACANADIAN SYLLABICS TLHWECANA" +
"DIAN SYLLABICS TLHOOCANADIAN SYLLABICS SAYISI SHWECANADIAN SYLLABICS SAY" +
"ISI SHOOCANADIAN SYLLABICS SAYISI HOOCANADIAN SYLLABICS CARRIER GWUCANAD" +
"IAN SYLLABICS CARRIER DENE GEECANADIAN SYLLABICS CARRIER GAACANADIAN SYL" +
"LABICS CARRIER GWACANADIAN SYLLABICS SAYISI JUUCANADIAN SYLLABICS CARRIE" +
"R JWACANADIAN SYLLABICS BEAVER DENE LCANADIAN SYLLABICS BEAVER DENE RCAN" +
"ADIAN SYLLABICS CARRIER DENTAL SLIMBU VOWEL-CARRIER LETTERLIMBU LETTER K" +
"ALIMBU LETTER KHALIMBU LETTER GALIMBU LETTER GHALIMBU LETTER NGALIMBU LE" +
"TTER CALIMBU LETTER CHALIMBU LETTER JALIMBU LETTER JHALIMBU LETTER YANLI" +
"MBU LETTER TALIMBU LETTER THALIMBU LETTER DALIMBU LETTER DHALIMBU LETTER" +
" NALIMBU LETTER PALIMBU LETTER PHALIMBU LETTER BALIMBU LETTER BHALIMBU L" +
"ETTER MALIMBU LETTER YALIMBU LETTER RALIMBU LETTER LALIMBU LETTER WALIMB" +
"U LETTER SHALIMBU LETTER SSALIMBU LETTER SALIMBU LETTER HALIMBU LETTER G" +
"YANLIMBU LETTER TRALIMBU VOWEL SIGN ALIMBU VOWEL SIGN ILIMBU VOWEL SIGN " +
"ULIMBU VOWEL SIGN EELIMBU VOWEL SIGN AILIMBU VOWEL SIGN OOLIMBU VOWEL SI" +
"GN AULIMBU VOWEL SIGN ELIMBU VOWEL SIGN OLIMBU SUBJOINED LETTER YALIMBU ") + ("" +
"SUBJOINED LETTER RALIMBU SUBJOINED LETTER WALIMBU SMALL LETTER KALIMBU S" +
"MALL LETTER NGALIMBU SMALL LETTER ANUSVARALIMBU SMALL LETTER TALIMBU SMA" +
"LL LETTER NALIMBU SMALL LETTER PALIMBU SMALL LETTER MALIMBU SMALL LETTER" +
" RALIMBU SMALL LETTER LALIMBU SIGN MUKPHRENGLIMBU SIGN KEMPHRENGLIMBU SI" +
"GN SA-ILIMBU SIGN LOOLIMBU EXCLAMATION MARKLIMBU QUESTION MARKLIMBU DIGI" +
"T ZEROLIMBU DIGIT ONELIMBU DIGIT TWOLIMBU DIGIT THREELIMBU DIGIT FOURLIM" +
"BU DIGIT FIVELIMBU DIGIT SIXLIMBU DIGIT SEVENLIMBU DIGIT EIGHTLIMBU DIGI" +
"T NINETAI LE LETTER KATAI LE LETTER XATAI LE LETTER NGATAI LE LETTER TSA" +
"TAI LE LETTER SATAI LE LETTER YATAI LE LETTER TATAI LE LETTER THATAI LE " +
"LETTER LATAI LE LETTER PATAI LE LETTER PHATAI LE LETTER MATAI LE LETTER " +
"FATAI LE LETTER VATAI LE LETTER HATAI LE LETTER QATAI LE LETTER KHATAI L" +
"E LETTER TSHATAI LE LETTER NATAI LE LETTER ATAI LE LETTER ITAI LE LETTER" +
" EETAI LE LETTER EHTAI LE LETTER UTAI LE LETTER OOTAI LE LETTER OTAI LE " +
"LETTER UETAI LE LETTER ETAI LE LETTER AUETAI LE LETTER AITAI LE LETTER T" +
"ONE-2TAI LE LETTER TONE-3TAI LE LETTER TONE-4TAI LE LETTER TONE-5TAI LE " +
"LETTER TONE-6NEW TAI LUE LETTER HIGH QANEW TAI LUE LETTER LOW QANEW TAI " +
"LUE LETTER HIGH KANEW TAI LUE LETTER HIGH XANEW TAI LUE LETTER HIGH NGAN" +
"EW TAI LUE LETTER LOW KANEW TAI LUE LETTER LOW XANEW TAI LUE LETTER LOW " +
"NGANEW TAI LUE LETTER HIGH TSANEW TAI LUE LETTER HIGH SANEW TAI LUE LETT" +
"ER HIGH YANEW TAI LUE LETTER LOW TSANEW TAI LUE LETTER LOW SANEW TAI LUE" +
" LETTER LOW YANEW TAI LUE LETTER HIGH TANEW TAI LUE LETTER HIGH THANEW T" +
"AI LUE LETTER HIGH NANEW TAI LUE LETTER LOW TANEW TAI LUE LETTER LOW THA" +
"NEW TAI LUE LETTER LOW NANEW TAI LUE LETTER HIGH PANEW TAI LUE LETTER HI" +
"GH PHANEW TAI LUE LETTER HIGH MANEW TAI LUE LETTER LOW PANEW TAI LUE LET" +
"TER LOW PHANEW TAI LUE LETTER LOW MANEW TAI LUE LETTER HIGH FANEW TAI LU" +
"E LETTER HIGH VANEW TAI LUE LETTER HIGH LANEW TAI LUE LETTER LOW FANEW T" +
"AI LUE LETTER LOW VANEW TAI LUE LETTER LOW LANEW TAI LUE LETTER HIGH HAN" +
"EW TAI LUE LETTER HIGH DANEW TAI LUE LETTER HIGH BANEW TAI LUE LETTER LO" +
"W HANEW TAI LUE LETTER LOW DANEW TAI LUE LETTER LOW BANEW TAI LUE LETTER" +
" HIGH KVANEW TAI LUE LETTER HIGH XVANEW TAI LUE LETTER LOW KVANEW TAI LU" +
"E LETTER LOW XVANEW TAI LUE LETTER HIGH SUANEW TAI LUE LETTER LOW SUANEW" +
" TAI LUE VOWEL SIGN VOWEL SHORTENERNEW TAI LUE VOWEL SIGN AANEW TAI LUE " +
"VOWEL SIGN IINEW TAI LUE VOWEL SIGN UNEW TAI LUE VOWEL SIGN UUNEW TAI LU" +
"E VOWEL SIGN ENEW TAI LUE VOWEL SIGN AENEW TAI LUE VOWEL SIGN ONEW TAI L" +
"UE VOWEL SIGN OANEW TAI LUE VOWEL SIGN UENEW TAI LUE VOWEL SIGN AYNEW TA" +
"I LUE VOWEL SIGN AAYNEW TAI LUE VOWEL SIGN UYNEW TAI LUE VOWEL SIGN OYNE" +
"W TAI LUE VOWEL SIGN OAYNEW TAI LUE VOWEL SIGN UEYNEW TAI LUE VOWEL SIGN" +
" IYNEW TAI LUE LETTER FINAL VNEW TAI LUE LETTER FINAL NGNEW TAI LUE LETT" +
"ER FINAL NNEW TAI LUE LETTER FINAL MNEW TAI LUE LETTER FINAL KNEW TAI LU" +
"E LETTER FINAL DNEW TAI LUE LETTER FINAL BNEW TAI LUE TONE MARK-1NEW TAI" +
" LUE TONE MARK-2NEW TAI LUE DIGIT ZERONEW TAI LUE DIGIT ONENEW TAI LUE D" +
"IGIT TWONEW TAI LUE DIGIT THREENEW TAI LUE DIGIT FOURNEW TAI LUE DIGIT F" +
"IVENEW TAI LUE DIGIT SIXNEW TAI LUE DIGIT SEVENNEW TAI LUE DIGIT EIGHTNE" +
"W TAI LUE DIGIT NINENEW TAI LUE THAM DIGIT ONENEW TAI LUE SIGN LAENEW TA" +
"I LUE SIGN LAEVKHMER SYMBOL PATHAMASATKHMER SYMBOL MUOY KOETKHMER SYMBOL" +
" PII KOETKHMER SYMBOL BEI KOETKHMER SYMBOL BUON KOETKHMER SYMBOL PRAM KO" +
"ETKHMER SYMBOL PRAM-MUOY KOETKHMER SYMBOL PRAM-PII KOETKHMER SYMBOL PRAM" +
"-BEI KOETKHMER SYMBOL PRAM-BUON KOETKHMER SYMBOL DAP KOETKHMER SYMBOL DA" +
"P-MUOY KOETKHMER SYMBOL DAP-PII KOETKHMER SYMBOL DAP-BEI KOETKHMER SYMBO" +
"L DAP-BUON KOETKHMER SYMBOL DAP-PRAM KOETKHMER SYMBOL TUTEYASATKHMER SYM" +
"BOL MUOY ROCKHMER SYMBOL PII ROCKHMER SYMBOL BEI ROCKHMER SYMBOL BUON RO" +
"CKHMER SYMBOL PRAM ROCKHMER SYMBOL PRAM-MUOY ROCKHMER SYMBOL PRAM-PII RO" +
"CKHMER SYMBOL PRAM-BEI ROCKHMER SYMBOL PRAM-BUON ROCKHMER SYMBOL DAP ROC" +
"KHMER SYMBOL DAP-MUOY ROCKHMER SYMBOL DAP-PII ROCKHMER SYMBOL DAP-BEI RO" +
"CKHMER SYMBOL DAP-BUON ROCKHMER SYMBOL DAP-PRAM ROCBUGINESE LETTER KABUG" +
"INESE LETTER GABUGINESE LETTER NGABUGINESE LETTER NGKABUGINESE LETTER PA" +
"BUGINESE LETTER BABUGINESE LETTER MABUGINESE LETTER MPABUGINESE LETTER T" +
"ABUGINESE LETTER DABUGINESE LETTER NABUGINESE LETTER NRABUGINESE LETTER " +
"CABUGINESE LETTER JABUGINESE LETTER NYABUGINESE LETTER NYCABUGINESE LETT" +
"ER YABUGINESE LETTER RABUGINESE LETTER LABUGINESE LETTER VABUGINESE LETT" +
"ER SABUGINESE LETTER ABUGINESE LETTER HABUGINESE VOWEL SIGN IBUGINESE VO" +
"WEL SIGN UBUGINESE VOWEL SIGN EBUGINESE VOWEL SIGN OBUGINESE VOWEL SIGN " +
"AEBUGINESE PALLAWABUGINESE END OF SECTIONTAI THAM LETTER HIGH KATAI THAM" +
" LETTER HIGH KHATAI THAM LETTER HIGH KXATAI THAM LETTER LOW KATAI THAM L") + ("" +
"ETTER LOW KXATAI THAM LETTER LOW KHATAI THAM LETTER NGATAI THAM LETTER H" +
"IGH CATAI THAM LETTER HIGH CHATAI THAM LETTER LOW CATAI THAM LETTER LOW " +
"SATAI THAM LETTER LOW CHATAI THAM LETTER NYATAI THAM LETTER RATATAI THAM" +
" LETTER HIGH RATHATAI THAM LETTER DATAI THAM LETTER LOW RATHATAI THAM LE" +
"TTER RANATAI THAM LETTER HIGH TATAI THAM LETTER HIGH THATAI THAM LETTER " +
"LOW TATAI THAM LETTER LOW THATAI THAM LETTER NATAI THAM LETTER BATAI THA" +
"M LETTER HIGH PATAI THAM LETTER HIGH PHATAI THAM LETTER HIGH FATAI THAM " +
"LETTER LOW PATAI THAM LETTER LOW FATAI THAM LETTER LOW PHATAI THAM LETTE" +
"R MATAI THAM LETTER LOW YATAI THAM LETTER HIGH YATAI THAM LETTER RATAI T" +
"HAM LETTER RUETAI THAM LETTER LATAI THAM LETTER LUETAI THAM LETTER WATAI" +
" THAM LETTER HIGH SHATAI THAM LETTER HIGH SSATAI THAM LETTER HIGH SATAI " +
"THAM LETTER HIGH HATAI THAM LETTER LLATAI THAM LETTER ATAI THAM LETTER L" +
"OW HATAI THAM LETTER ITAI THAM LETTER IITAI THAM LETTER UTAI THAM LETTER" +
" UUTAI THAM LETTER EETAI THAM LETTER OOTAI THAM LETTER LAETAI THAM LETTE" +
"R GREAT SATAI THAM CONSONANT SIGN MEDIAL RATAI THAM CONSONANT SIGN MEDIA" +
"L LATAI THAM CONSONANT SIGN LA TANG LAITAI THAM SIGN MAI KANG LAITAI THA" +
"M CONSONANT SIGN FINAL NGATAI THAM CONSONANT SIGN LOW PATAI THAM CONSONA" +
"NT SIGN HIGH RATHA OR LOW PATAI THAM CONSONANT SIGN MATAI THAM CONSONANT" +
" SIGN BATAI THAM CONSONANT SIGN SATAI THAM SIGN SAKOTTAI THAM VOWEL SIGN" +
" ATAI THAM VOWEL SIGN MAI SATTAI THAM VOWEL SIGN AATAI THAM VOWEL SIGN T" +
"ALL AATAI THAM VOWEL SIGN ITAI THAM VOWEL SIGN IITAI THAM VOWEL SIGN UET" +
"AI THAM VOWEL SIGN UUETAI THAM VOWEL SIGN UTAI THAM VOWEL SIGN UUTAI THA" +
"M VOWEL SIGN OTAI THAM VOWEL SIGN OA BELOWTAI THAM VOWEL SIGN OYTAI THAM" +
" VOWEL SIGN ETAI THAM VOWEL SIGN AETAI THAM VOWEL SIGN OOTAI THAM VOWEL " +
"SIGN AITAI THAM VOWEL SIGN THAM AITAI THAM VOWEL SIGN OA ABOVETAI THAM S" +
"IGN MAI KANGTAI THAM SIGN TONE-1TAI THAM SIGN TONE-2TAI THAM SIGN KHUEN " +
"TONE-3TAI THAM SIGN KHUEN TONE-4TAI THAM SIGN KHUEN TONE-5TAI THAM SIGN " +
"RA HAAMTAI THAM SIGN MAI SAMTAI THAM SIGN KHUEN-LUE KARANTAI THAM COMBIN" +
"ING CRYPTOGRAMMIC DOTTAI THAM HORA DIGIT ZEROTAI THAM HORA DIGIT ONETAI " +
"THAM HORA DIGIT TWOTAI THAM HORA DIGIT THREETAI THAM HORA DIGIT FOURTAI " +
"THAM HORA DIGIT FIVETAI THAM HORA DIGIT SIXTAI THAM HORA DIGIT SEVENTAI " +
"THAM HORA DIGIT EIGHTTAI THAM HORA DIGIT NINETAI THAM THAM DIGIT ZEROTAI" +
" THAM THAM DIGIT ONETAI THAM THAM DIGIT TWOTAI THAM THAM DIGIT THREETAI " +
"THAM THAM DIGIT FOURTAI THAM THAM DIGIT FIVETAI THAM THAM DIGIT SIXTAI T" +
"HAM THAM DIGIT SEVENTAI THAM THAM DIGIT EIGHTTAI THAM THAM DIGIT NINETAI" +
" THAM SIGN WIANGTAI THAM SIGN WIANGWAAKTAI THAM SIGN SAWANTAI THAM SIGN " +
"KEOWTAI THAM SIGN HOYTAI THAM SIGN DOKMAITAI THAM SIGN REVERSED ROTATED " +
"RANATAI THAM SIGN MAI YAMOKTAI THAM SIGN KAANTAI THAM SIGN KAANKUUTAI TH" +
"AM SIGN SATKAANTAI THAM SIGN SATKAANKUUTAI THAM SIGN HANGTAI THAM SIGN C" +
"AANGCOMBINING DOUBLED CIRCUMFLEX ACCENTCOMBINING DIAERESIS-RINGCOMBINING" +
" INFINITYCOMBINING DOWNWARDS ARROWCOMBINING TRIPLE DOTCOMBINING X-X BELO" +
"WCOMBINING WIGGLY LINE BELOWCOMBINING OPEN MARK BELOWCOMBINING DOUBLE OP" +
"EN MARK BELOWCOMBINING LIGHT CENTRALIZATION STROKE BELOWCOMBINING STRONG" +
" CENTRALIZATION STROKE BELOWCOMBINING PARENTHESES ABOVECOMBINING DOUBLE " +
"PARENTHESES ABOVECOMBINING PARENTHESES BELOWCOMBINING PARENTHESES OVERLA" +
"YCOMBINING LATIN SMALL LETTER W BELOWCOMBINING LATIN SMALL LETTER TURNED" +
" W BELOWCOMBINING LEFT PARENTHESIS ABOVE LEFTCOMBINING RIGHT PARENTHESIS" +
" ABOVE RIGHTCOMBINING LEFT PARENTHESIS BELOW LEFTCOMBINING RIGHT PARENTH" +
"ESIS BELOW RIGHTCOMBINING SQUARE BRACKETS ABOVECOMBINING NUMBER SIGN ABO" +
"VECOMBINING INVERTED DOUBLE ARCH ABOVECOMBINING PLUS SIGN ABOVECOMBINING" +
" DOUBLE PLUS SIGN ABOVECOMBINING DOUBLE PLUS SIGN BELOWCOMBINING TRIPLE " +
"ACUTE ACCENTCOMBINING LATIN SMALL LETTER INSULAR GCOMBINING LATIN SMALL " +
"LETTER INSULAR RCOMBINING LATIN SMALL LETTER INSULAR TBALINESE SIGN ULU " +
"RICEMBALINESE SIGN ULU CANDRABALINESE SIGN CECEKBALINESE SIGN SURANGBALI" +
"NESE SIGN BISAHBALINESE LETTER AKARABALINESE LETTER AKARA TEDUNGBALINESE" +
" LETTER IKARABALINESE LETTER IKARA TEDUNGBALINESE LETTER UKARABALINESE L" +
"ETTER UKARA TEDUNGBALINESE LETTER RA REPABALINESE LETTER RA REPA TEDUNGB" +
"ALINESE LETTER LA LENGABALINESE LETTER LA LENGA TEDUNGBALINESE LETTER EK" +
"ARABALINESE LETTER AIKARABALINESE LETTER OKARABALINESE LETTER OKARA TEDU" +
"NGBALINESE LETTER KABALINESE LETTER KA MAHAPRANABALINESE LETTER GABALINE" +
"SE LETTER GA GORABALINESE LETTER NGABALINESE LETTER CABALINESE LETTER CA" +
" LACABALINESE LETTER JABALINESE LETTER JA JERABALINESE LETTER NYABALINES" +
"E LETTER TA LATIKBALINESE LETTER TA MURDA MAHAPRANABALINESE LETTER DA MU" +
"RDA ALPAPRANABALINESE LETTER DA MURDA MAHAPRANABALINESE LETTER NA RAMBAT") + ("" +
"BALINESE LETTER TABALINESE LETTER TA TAWABALINESE LETTER DABALINESE LETT" +
"ER DA MADUBALINESE LETTER NABALINESE LETTER PABALINESE LETTER PA KAPALBA" +
"LINESE LETTER BABALINESE LETTER BA KEMBANGBALINESE LETTER MABALINESE LET" +
"TER YABALINESE LETTER RABALINESE LETTER LABALINESE LETTER WABALINESE LET" +
"TER SA SAGABALINESE LETTER SA SAPABALINESE LETTER SABALINESE LETTER HABA" +
"LINESE SIGN REREKANBALINESE VOWEL SIGN TEDUNGBALINESE VOWEL SIGN ULUBALI" +
"NESE VOWEL SIGN ULU SARIBALINESE VOWEL SIGN SUKUBALINESE VOWEL SIGN SUKU" +
" ILUTBALINESE VOWEL SIGN RA REPABALINESE VOWEL SIGN RA REPA TEDUNGBALINE" +
"SE VOWEL SIGN LA LENGABALINESE VOWEL SIGN LA LENGA TEDUNGBALINESE VOWEL " +
"SIGN TALINGBALINESE VOWEL SIGN TALING REPABALINESE VOWEL SIGN TALING TED" +
"UNGBALINESE VOWEL SIGN TALING REPA TEDUNGBALINESE VOWEL SIGN PEPETBALINE" +
"SE VOWEL SIGN PEPET TEDUNGBALINESE ADEG ADEGBALINESE LETTER KAF SASAKBAL" +
"INESE LETTER KHOT SASAKBALINESE LETTER TZIR SASAKBALINESE LETTER EF SASA" +
"KBALINESE LETTER VE SASAKBALINESE LETTER ZAL SASAKBALINESE LETTER ASYURA" +
" SASAKBALINESE LETTER ARCHAIC JNYABALINESE DIGIT ZEROBALINESE DIGIT ONEB" +
"ALINESE DIGIT TWOBALINESE DIGIT THREEBALINESE DIGIT FOURBALINESE DIGIT F" +
"IVEBALINESE DIGIT SIXBALINESE DIGIT SEVENBALINESE DIGIT EIGHTBALINESE DI" +
"GIT NINEBALINESE PANTIBALINESE PAMADABALINESE WINDUBALINESE CARIK PAMUNG" +
"KAHBALINESE CARIK SIKIBALINESE CARIK PARERENBALINESE PAMENENGBALINESE MU" +
"SICAL SYMBOL DONGBALINESE MUSICAL SYMBOL DENGBALINESE MUSICAL SYMBOL DUN" +
"GBALINESE MUSICAL SYMBOL DANGBALINESE MUSICAL SYMBOL DANG SURANGBALINESE" +
" MUSICAL SYMBOL DINGBALINESE MUSICAL SYMBOL DAENGBALINESE MUSICAL SYMBOL" +
" DEUNGBALINESE MUSICAL SYMBOL DAINGBALINESE MUSICAL SYMBOL DANG GEDEBALI" +
"NESE MUSICAL SYMBOL COMBINING TEGEHBALINESE MUSICAL SYMBOL COMBINING END" +
"EPBALINESE MUSICAL SYMBOL COMBINING KEMPULBALINESE MUSICAL SYMBOL COMBIN" +
"ING KEMPLIBALINESE MUSICAL SYMBOL COMBINING JEGOGANBALINESE MUSICAL SYMB" +
"OL COMBINING KEMPUL WITH JEGOGANBALINESE MUSICAL SYMBOL COMBINING KEMPLI" +
" WITH JEGOGANBALINESE MUSICAL SYMBOL COMBINING BENDEBALINESE MUSICAL SYM" +
"BOL COMBINING GONGBALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUGBALINESE MU" +
"SICAL SYMBOL RIGHT-HAND OPEN DAGBALINESE MUSICAL SYMBOL RIGHT-HAND CLOSE" +
"D TUKBALINESE MUSICAL SYMBOL RIGHT-HAND CLOSED TAKBALINESE MUSICAL SYMBO" +
"L LEFT-HAND OPEN PANGBALINESE MUSICAL SYMBOL LEFT-HAND OPEN PUNGBALINESE" +
" MUSICAL SYMBOL LEFT-HAND CLOSED PLAKBALINESE MUSICAL SYMBOL LEFT-HAND C" +
"LOSED PLUKBALINESE MUSICAL SYMBOL LEFT-HAND OPEN PINGBALINESE PANTI LANT" +
"ANGBALINESE PAMADA LANTANGSUNDANESE SIGN PANYECEKSUNDANESE SIGN PANGLAYA" +
"RSUNDANESE SIGN PANGWISADSUNDANESE LETTER ASUNDANESE LETTER ISUNDANESE L" +
"ETTER USUNDANESE LETTER AESUNDANESE LETTER OSUNDANESE LETTER ESUNDANESE " +
"LETTER EUSUNDANESE LETTER KASUNDANESE LETTER QASUNDANESE LETTER GASUNDAN" +
"ESE LETTER NGASUNDANESE LETTER CASUNDANESE LETTER JASUNDANESE LETTER ZAS" +
"UNDANESE LETTER NYASUNDANESE LETTER TASUNDANESE LETTER DASUNDANESE LETTE" +
"R NASUNDANESE LETTER PASUNDANESE LETTER FASUNDANESE LETTER VASUNDANESE L" +
"ETTER BASUNDANESE LETTER MASUNDANESE LETTER YASUNDANESE LETTER RASUNDANE" +
"SE LETTER LASUNDANESE LETTER WASUNDANESE LETTER SASUNDANESE LETTER XASUN" +
"DANESE LETTER HASUNDANESE CONSONANT SIGN PAMINGKALSUNDANESE CONSONANT SI" +
"GN PANYAKRASUNDANESE CONSONANT SIGN PANYIKUSUNDANESE VOWEL SIGN PANGHULU" +
"SUNDANESE VOWEL SIGN PANYUKUSUNDANESE VOWEL SIGN PANAELAENGSUNDANESE VOW" +
"EL SIGN PANOLONGSUNDANESE VOWEL SIGN PAMEPETSUNDANESE VOWEL SIGN PANEULE" +
"UNGSUNDANESE SIGN PAMAAEHSUNDANESE SIGN VIRAMASUNDANESE CONSONANT SIGN P" +
"ASANGAN MASUNDANESE CONSONANT SIGN PASANGAN WASUNDANESE LETTER KHASUNDAN" +
"ESE LETTER SYASUNDANESE DIGIT ZEROSUNDANESE DIGIT ONESUNDANESE DIGIT TWO" +
"SUNDANESE DIGIT THREESUNDANESE DIGIT FOURSUNDANESE DIGIT FIVESUNDANESE D" +
"IGIT SIXSUNDANESE DIGIT SEVENSUNDANESE DIGIT EIGHTSUNDANESE DIGIT NINESU" +
"NDANESE AVAGRAHASUNDANESE LETTER REUSUNDANESE LETTER LEUSUNDANESE LETTER" +
" BHASUNDANESE LETTER FINAL KSUNDANESE LETTER FINAL MBATAK LETTER ABATAK " +
"LETTER SIMALUNGUN ABATAK LETTER HABATAK LETTER SIMALUNGUN HABATAK LETTER" +
" MANDAILING HABATAK LETTER BABATAK LETTER KARO BABATAK LETTER PABATAK LE" +
"TTER SIMALUNGUN PABATAK LETTER NABATAK LETTER MANDAILING NABATAK LETTER " +
"WABATAK LETTER SIMALUNGUN WABATAK LETTER PAKPAK WABATAK LETTER GABATAK L" +
"ETTER SIMALUNGUN GABATAK LETTER JABATAK LETTER DABATAK LETTER RABATAK LE" +
"TTER SIMALUNGUN RABATAK LETTER MABATAK LETTER SIMALUNGUN MABATAK LETTER " +
"SOUTHERN TABATAK LETTER NORTHERN TABATAK LETTER SABATAK LETTER SIMALUNGU" +
"N SABATAK LETTER MANDAILING SABATAK LETTER YABATAK LETTER SIMALUNGUN YAB" +
"ATAK LETTER NGABATAK LETTER LABATAK LETTER SIMALUNGUN LABATAK LETTER NYA" +
"BATAK LETTER CABATAK LETTER NDABATAK LETTER MBABATAK LETTER IBATAK LETTE") + ("" +
"R UBATAK SIGN TOMPIBATAK VOWEL SIGN EBATAK VOWEL SIGN PAKPAK EBATAK VOWE" +
"L SIGN EEBATAK VOWEL SIGN IBATAK VOWEL SIGN KARO IBATAK VOWEL SIGN OBATA" +
"K VOWEL SIGN KARO OBATAK VOWEL SIGN UBATAK VOWEL SIGN U FOR SIMALUNGUN S" +
"ABATAK CONSONANT SIGN NGBATAK CONSONANT SIGN HBATAK PANGOLATBATAK PANONG" +
"ONANBATAK SYMBOL BINDU NA METEKBATAK SYMBOL BINDU PINARBORASBATAK SYMBOL" +
" BINDU JUDULBATAK SYMBOL BINDU PANGOLATLEPCHA LETTER KALEPCHA LETTER KLA" +
"LEPCHA LETTER KHALEPCHA LETTER GALEPCHA LETTER GLALEPCHA LETTER NGALEPCH" +
"A LETTER CALEPCHA LETTER CHALEPCHA LETTER JALEPCHA LETTER NYALEPCHA LETT" +
"ER TALEPCHA LETTER THALEPCHA LETTER DALEPCHA LETTER NALEPCHA LETTER PALE" +
"PCHA LETTER PLALEPCHA LETTER PHALEPCHA LETTER FALEPCHA LETTER FLALEPCHA " +
"LETTER BALEPCHA LETTER BLALEPCHA LETTER MALEPCHA LETTER MLALEPCHA LETTER" +
" TSALEPCHA LETTER TSHALEPCHA LETTER DZALEPCHA LETTER YALEPCHA LETTER RAL" +
"EPCHA LETTER LALEPCHA LETTER HALEPCHA LETTER HLALEPCHA LETTER VALEPCHA L" +
"ETTER SALEPCHA LETTER SHALEPCHA LETTER WALEPCHA LETTER ALEPCHA SUBJOINED" +
" LETTER YALEPCHA SUBJOINED LETTER RALEPCHA VOWEL SIGN AALEPCHA VOWEL SIG" +
"N ILEPCHA VOWEL SIGN OLEPCHA VOWEL SIGN OOLEPCHA VOWEL SIGN ULEPCHA VOWE" +
"L SIGN UULEPCHA VOWEL SIGN ELEPCHA CONSONANT SIGN KLEPCHA CONSONANT SIGN" +
" MLEPCHA CONSONANT SIGN LLEPCHA CONSONANT SIGN NLEPCHA CONSONANT SIGN PL" +
"EPCHA CONSONANT SIGN RLEPCHA CONSONANT SIGN TLEPCHA CONSONANT SIGN NYIN-" +
"DOLEPCHA CONSONANT SIGN KANGLEPCHA SIGN RANLEPCHA SIGN NUKTALEPCHA PUNCT" +
"UATION TA-ROLLEPCHA PUNCTUATION NYET THYOOM TA-ROLLEPCHA PUNCTUATION CER" +
"-WALEPCHA PUNCTUATION TSHOOK CER-WALEPCHA PUNCTUATION TSHOOKLEPCHA DIGIT" +
" ZEROLEPCHA DIGIT ONELEPCHA DIGIT TWOLEPCHA DIGIT THREELEPCHA DIGIT FOUR" +
"LEPCHA DIGIT FIVELEPCHA DIGIT SIXLEPCHA DIGIT SEVENLEPCHA DIGIT EIGHTLEP" +
"CHA DIGIT NINELEPCHA LETTER TTALEPCHA LETTER TTHALEPCHA LETTER DDAOL CHI" +
"KI DIGIT ZEROOL CHIKI DIGIT ONEOL CHIKI DIGIT TWOOL CHIKI DIGIT THREEOL " +
"CHIKI DIGIT FOUROL CHIKI DIGIT FIVEOL CHIKI DIGIT SIXOL CHIKI DIGIT SEVE" +
"NOL CHIKI DIGIT EIGHTOL CHIKI DIGIT NINEOL CHIKI LETTER LAOL CHIKI LETTE" +
"R ATOL CHIKI LETTER AGOL CHIKI LETTER ANGOL CHIKI LETTER ALOL CHIKI LETT" +
"ER LAAOL CHIKI LETTER AAKOL CHIKI LETTER AAJOL CHIKI LETTER AAMOL CHIKI " +
"LETTER AAWOL CHIKI LETTER LIOL CHIKI LETTER ISOL CHIKI LETTER IHOL CHIKI" +
" LETTER INYOL CHIKI LETTER IROL CHIKI LETTER LUOL CHIKI LETTER UCOL CHIK" +
"I LETTER UDOL CHIKI LETTER UNNOL CHIKI LETTER UYOL CHIKI LETTER LEOL CHI" +
"KI LETTER EPOL CHIKI LETTER EDDOL CHIKI LETTER ENOL CHIKI LETTER ERROL C" +
"HIKI LETTER LOOL CHIKI LETTER OTTOL CHIKI LETTER OBOL CHIKI LETTER OVOL " +
"CHIKI LETTER OHOL CHIKI MU TTUDDAGOL CHIKI GAAHLAA TTUDDAAGOL CHIKI MU-G" +
"AAHLAA TTUDDAAGOL CHIKI RELAAOL CHIKI PHAARKAAOL CHIKI AHADOL CHIKI PUNC" +
"TUATION MUCAADOL CHIKI PUNCTUATION DOUBLE MUCAADCYRILLIC SMALL LETTER RO" +
"UNDED VECYRILLIC SMALL LETTER LONG-LEGGED DECYRILLIC SMALL LETTER NARROW" +
" OCYRILLIC SMALL LETTER WIDE ESCYRILLIC SMALL LETTER TALL TECYRILLIC SMA" +
"LL LETTER THREE-LEGGED TECYRILLIC SMALL LETTER TALL HARD SIGNCYRILLIC SM" +
"ALL LETTER TALL YATCYRILLIC SMALL LETTER UNBLENDED UKGEORGIAN MTAVRULI C" +
"APITAL LETTER ANGEORGIAN MTAVRULI CAPITAL LETTER BANGEORGIAN MTAVRULI CA" +
"PITAL LETTER GANGEORGIAN MTAVRULI CAPITAL LETTER DONGEORGIAN MTAVRULI CA" +
"PITAL LETTER ENGEORGIAN MTAVRULI CAPITAL LETTER VINGEORGIAN MTAVRULI CAP" +
"ITAL LETTER ZENGEORGIAN MTAVRULI CAPITAL LETTER TANGEORGIAN MTAVRULI CAP" +
"ITAL LETTER INGEORGIAN MTAVRULI CAPITAL LETTER KANGEORGIAN MTAVRULI CAPI" +
"TAL LETTER LASGEORGIAN MTAVRULI CAPITAL LETTER MANGEORGIAN MTAVRULI CAPI" +
"TAL LETTER NARGEORGIAN MTAVRULI CAPITAL LETTER ONGEORGIAN MTAVRULI CAPIT" +
"AL LETTER PARGEORGIAN MTAVRULI CAPITAL LETTER ZHARGEORGIAN MTAVRULI CAPI" +
"TAL LETTER RAEGEORGIAN MTAVRULI CAPITAL LETTER SANGEORGIAN MTAVRULI CAPI" +
"TAL LETTER TARGEORGIAN MTAVRULI CAPITAL LETTER UNGEORGIAN MTAVRULI CAPIT" +
"AL LETTER PHARGEORGIAN MTAVRULI CAPITAL LETTER KHARGEORGIAN MTAVRULI CAP" +
"ITAL LETTER GHANGEORGIAN MTAVRULI CAPITAL LETTER QARGEORGIAN MTAVRULI CA" +
"PITAL LETTER SHINGEORGIAN MTAVRULI CAPITAL LETTER CHINGEORGIAN MTAVRULI " +
"CAPITAL LETTER CANGEORGIAN MTAVRULI CAPITAL LETTER JILGEORGIAN MTAVRULI " +
"CAPITAL LETTER CILGEORGIAN MTAVRULI CAPITAL LETTER CHARGEORGIAN MTAVRULI" +
" CAPITAL LETTER XANGEORGIAN MTAVRULI CAPITAL LETTER JHANGEORGIAN MTAVRUL" +
"I CAPITAL LETTER HAEGEORGIAN MTAVRULI CAPITAL LETTER HEGEORGIAN MTAVRULI" +
" CAPITAL LETTER HIEGEORGIAN MTAVRULI CAPITAL LETTER WEGEORGIAN MTAVRULI " +
"CAPITAL LETTER HARGEORGIAN MTAVRULI CAPITAL LETTER HOEGEORGIAN MTAVRULI " +
"CAPITAL LETTER FIGEORGIAN MTAVRULI CAPITAL LETTER YNGEORGIAN MTAVRULI CA" +
"PITAL LETTER ELIFIGEORGIAN MTAVRULI CAPITAL LETTER TURNED GANGEORGIAN MT" +
"AVRULI CAPITAL LETTER AINGEORGIAN MTAVRULI CAPITAL LETTER AENGEORGIAN MT") + ("" +
"AVRULI CAPITAL LETTER HARD SIGNGEORGIAN MTAVRULI CAPITAL LETTER LABIAL S" +
"IGNSUNDANESE PUNCTUATION BINDU SURYASUNDANESE PUNCTUATION BINDU PANGLONG" +
"SUNDANESE PUNCTUATION BINDU PURNAMASUNDANESE PUNCTUATION BINDU CAKRASUND" +
"ANESE PUNCTUATION BINDU LEU SATANGASUNDANESE PUNCTUATION BINDU KA SATANG" +
"ASUNDANESE PUNCTUATION BINDU DA SATANGASUNDANESE PUNCTUATION BINDU BA SA" +
"TANGAVEDIC TONE KARSHANAVEDIC TONE SHARAVEDIC TONE PRENKHAVEDIC SIGN NIH" +
"SHVASAVEDIC SIGN YAJURVEDIC MIDLINE SVARITAVEDIC TONE YAJURVEDIC AGGRAVA" +
"TED INDEPENDENT SVARITAVEDIC TONE YAJURVEDIC INDEPENDENT SVARITAVEDIC TO" +
"NE YAJURVEDIC KATHAKA INDEPENDENT SVARITAVEDIC TONE CANDRA BELOWVEDIC TO" +
"NE YAJURVEDIC KATHAKA INDEPENDENT SVARITA SCHROEDERVEDIC TONE DOUBLE SVA" +
"RITAVEDIC TONE TRIPLE SVARITAVEDIC TONE KATHAKA ANUDATTAVEDIC TONE DOT B" +
"ELOWVEDIC TONE TWO DOTS BELOWVEDIC TONE THREE DOTS BELOWVEDIC TONE RIGVE" +
"DIC KASHMIRI INDEPENDENT SVARITAVEDIC TONE ATHARVAVEDIC INDEPENDENT SVAR" +
"ITAVEDIC SIGN VISARGA SVARITAVEDIC SIGN VISARGA UDATTAVEDIC SIGN REVERSE" +
"D VISARGA UDATTAVEDIC SIGN VISARGA ANUDATTAVEDIC SIGN REVERSED VISARGA A" +
"NUDATTAVEDIC SIGN VISARGA UDATTA WITH TAILVEDIC SIGN VISARGA ANUDATTA WI" +
"TH TAILVEDIC SIGN ANUSVARA ANTARGOMUKHAVEDIC SIGN ANUSVARA BAHIRGOMUKHAV" +
"EDIC SIGN ANUSVARA VAMAGOMUKHAVEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAILV" +
"EDIC SIGN TIRYAKVEDIC SIGN HEXIFORM LONG ANUSVARAVEDIC SIGN LONG ANUSVAR" +
"AVEDIC SIGN RTHANG LONG ANUSVARAVEDIC SIGN ANUSVARA UBHAYATO MUKHAVEDIC " +
"SIGN ARDHAVISARGAVEDIC SIGN ROTATED ARDHAVISARGAVEDIC TONE CANDRA ABOVEV" +
"EDIC SIGN JIHVAMULIYAVEDIC SIGN UPADHMANIYAVEDIC SIGN ATIKRAMAVEDIC TONE" +
" RING ABOVEVEDIC TONE DOUBLE RING ABOVEVEDIC SIGN DOUBLE ANUSVARA ANTARG" +
"OMUKHALATIN LETTER SMALL CAPITAL ALATIN LETTER SMALL CAPITAL AELATIN SMA" +
"LL LETTER TURNED AELATIN LETTER SMALL CAPITAL BARRED BLATIN LETTER SMALL" +
" CAPITAL CLATIN LETTER SMALL CAPITAL DLATIN LETTER SMALL CAPITAL ETHLATI" +
"N LETTER SMALL CAPITAL ELATIN SMALL LETTER TURNED OPEN ELATIN SMALL LETT" +
"ER TURNED ILATIN LETTER SMALL CAPITAL JLATIN LETTER SMALL CAPITAL KLATIN" +
" LETTER SMALL CAPITAL L WITH STROKELATIN LETTER SMALL CAPITAL MLATIN LET" +
"TER SMALL CAPITAL REVERSED NLATIN LETTER SMALL CAPITAL OLATIN LETTER SMA" +
"LL CAPITAL OPEN OLATIN SMALL LETTER SIDEWAYS OLATIN SMALL LETTER SIDEWAY" +
"S OPEN OLATIN SMALL LETTER SIDEWAYS O WITH STROKELATIN SMALL LETTER TURN" +
"ED OELATIN LETTER SMALL CAPITAL OULATIN SMALL LETTER TOP HALF OLATIN SMA" +
"LL LETTER BOTTOM HALF OLATIN LETTER SMALL CAPITAL PLATIN LETTER SMALL CA" +
"PITAL REVERSED RLATIN LETTER SMALL CAPITAL TURNED RLATIN LETTER SMALL CA" +
"PITAL TLATIN LETTER SMALL CAPITAL ULATIN SMALL LETTER SIDEWAYS ULATIN SM" +
"ALL LETTER SIDEWAYS DIAERESIZED ULATIN SMALL LETTER SIDEWAYS TURNED MLAT" +
"IN LETTER SMALL CAPITAL VLATIN LETTER SMALL CAPITAL WLATIN LETTER SMALL " +
"CAPITAL ZLATIN LETTER SMALL CAPITAL EZHLATIN LETTER VOICED LARYNGEAL SPI" +
"RANTLATIN LETTER AINGREEK LETTER SMALL CAPITAL GAMMAGREEK LETTER SMALL C" +
"APITAL LAMDAGREEK LETTER SMALL CAPITAL PIGREEK LETTER SMALL CAPITAL RHOG" +
"REEK LETTER SMALL CAPITAL PSICYRILLIC LETTER SMALL CAPITAL ELMODIFIER LE" +
"TTER CAPITAL AMODIFIER LETTER CAPITAL AEMODIFIER LETTER CAPITAL BMODIFIE" +
"R LETTER CAPITAL BARRED BMODIFIER LETTER CAPITAL DMODIFIER LETTER CAPITA" +
"L EMODIFIER LETTER CAPITAL REVERSED EMODIFIER LETTER CAPITAL GMODIFIER L" +
"ETTER CAPITAL HMODIFIER LETTER CAPITAL IMODIFIER LETTER CAPITAL JMODIFIE" +
"R LETTER CAPITAL KMODIFIER LETTER CAPITAL LMODIFIER LETTER CAPITAL MMODI" +
"FIER LETTER CAPITAL NMODIFIER LETTER CAPITAL REVERSED NMODIFIER LETTER C" +
"APITAL OMODIFIER LETTER CAPITAL OUMODIFIER LETTER CAPITAL PMODIFIER LETT" +
"ER CAPITAL RMODIFIER LETTER CAPITAL TMODIFIER LETTER CAPITAL UMODIFIER L" +
"ETTER CAPITAL WMODIFIER LETTER SMALL AMODIFIER LETTER SMALL TURNED AMODI" +
"FIER LETTER SMALL ALPHAMODIFIER LETTER SMALL TURNED AEMODIFIER LETTER SM" +
"ALL BMODIFIER LETTER SMALL DMODIFIER LETTER SMALL EMODIFIER LETTER SMALL" +
" SCHWAMODIFIER LETTER SMALL OPEN EMODIFIER LETTER SMALL TURNED OPEN EMOD" +
"IFIER LETTER SMALL GMODIFIER LETTER SMALL TURNED IMODIFIER LETTER SMALL " +
"KMODIFIER LETTER SMALL MMODIFIER LETTER SMALL ENGMODIFIER LETTER SMALL O" +
"MODIFIER LETTER SMALL OPEN OMODIFIER LETTER SMALL TOP HALF OMODIFIER LET" +
"TER SMALL BOTTOM HALF OMODIFIER LETTER SMALL PMODIFIER LETTER SMALL TMOD" +
"IFIER LETTER SMALL UMODIFIER LETTER SMALL SIDEWAYS UMODIFIER LETTER SMAL" +
"L TURNED MMODIFIER LETTER SMALL VMODIFIER LETTER SMALL AINMODIFIER LETTE" +
"R SMALL BETAMODIFIER LETTER SMALL GREEK GAMMAMODIFIER LETTER SMALL DELTA" +
"MODIFIER LETTER SMALL GREEK PHIMODIFIER LETTER SMALL CHILATIN SUBSCRIPT " +
"SMALL LETTER ILATIN SUBSCRIPT SMALL LETTER RLATIN SUBSCRIPT SMALL LETTER" +
" ULATIN SUBSCRIPT SMALL LETTER VGREEK SUBSCRIPT SMALL LETTER BETAGREEK S") + ("" +
"UBSCRIPT SMALL LETTER GAMMAGREEK SUBSCRIPT SMALL LETTER RHOGREEK SUBSCRI" +
"PT SMALL LETTER PHIGREEK SUBSCRIPT SMALL LETTER CHILATIN SMALL LETTER UE" +
"LATIN SMALL LETTER B WITH MIDDLE TILDELATIN SMALL LETTER D WITH MIDDLE T" +
"ILDELATIN SMALL LETTER F WITH MIDDLE TILDELATIN SMALL LETTER M WITH MIDD" +
"LE TILDELATIN SMALL LETTER N WITH MIDDLE TILDELATIN SMALL LETTER P WITH " +
"MIDDLE TILDELATIN SMALL LETTER R WITH MIDDLE TILDELATIN SMALL LETTER R W" +
"ITH FISHHOOK AND MIDDLE TILDELATIN SMALL LETTER S WITH MIDDLE TILDELATIN" +
" SMALL LETTER T WITH MIDDLE TILDELATIN SMALL LETTER Z WITH MIDDLE TILDEL" +
"ATIN SMALL LETTER TURNED GMODIFIER LETTER CYRILLIC ENLATIN SMALL LETTER " +
"INSULAR GLATIN SMALL LETTER TH WITH STRIKETHROUGHLATIN SMALL CAPITAL LET" +
"TER I WITH STROKELATIN SMALL LETTER IOTA WITH STROKELATIN SMALL LETTER P" +
" WITH STROKELATIN SMALL CAPITAL LETTER U WITH STROKELATIN SMALL LETTER U" +
"PSILON WITH STROKELATIN SMALL LETTER B WITH PALATAL HOOKLATIN SMALL LETT" +
"ER D WITH PALATAL HOOKLATIN SMALL LETTER F WITH PALATAL HOOKLATIN SMALL " +
"LETTER G WITH PALATAL HOOKLATIN SMALL LETTER K WITH PALATAL HOOKLATIN SM" +
"ALL LETTER L WITH PALATAL HOOKLATIN SMALL LETTER M WITH PALATAL HOOKLATI" +
"N SMALL LETTER N WITH PALATAL HOOKLATIN SMALL LETTER P WITH PALATAL HOOK" +
"LATIN SMALL LETTER R WITH PALATAL HOOKLATIN SMALL LETTER S WITH PALATAL " +
"HOOKLATIN SMALL LETTER ESH WITH PALATAL HOOKLATIN SMALL LETTER V WITH PA" +
"LATAL HOOKLATIN SMALL LETTER X WITH PALATAL HOOKLATIN SMALL LETTER Z WIT" +
"H PALATAL HOOKLATIN SMALL LETTER A WITH RETROFLEX HOOKLATIN SMALL LETTER" +
" ALPHA WITH RETROFLEX HOOKLATIN SMALL LETTER D WITH HOOK AND TAILLATIN S" +
"MALL LETTER E WITH RETROFLEX HOOKLATIN SMALL LETTER OPEN E WITH RETROFLE" +
"X HOOKLATIN SMALL LETTER REVERSED OPEN E WITH RETROFLEX HOOKLATIN SMALL " +
"LETTER SCHWA WITH RETROFLEX HOOKLATIN SMALL LETTER I WITH RETROFLEX HOOK" +
"LATIN SMALL LETTER OPEN O WITH RETROFLEX HOOKLATIN SMALL LETTER ESH WITH" +
" RETROFLEX HOOKLATIN SMALL LETTER U WITH RETROFLEX HOOKLATIN SMALL LETTE" +
"R EZH WITH RETROFLEX HOOKMODIFIER LETTER SMALL TURNED ALPHAMODIFIER LETT" +
"ER SMALL CMODIFIER LETTER SMALL C WITH CURLMODIFIER LETTER SMALL ETHMODI" +
"FIER LETTER SMALL REVERSED OPEN EMODIFIER LETTER SMALL FMODIFIER LETTER " +
"SMALL DOTLESS J WITH STROKEMODIFIER LETTER SMALL SCRIPT GMODIFIER LETTER" +
" SMALL TURNED HMODIFIER LETTER SMALL I WITH STROKEMODIFIER LETTER SMALL " +
"IOTAMODIFIER LETTER SMALL CAPITAL IMODIFIER LETTER SMALL CAPITAL I WITH " +
"STROKEMODIFIER LETTER SMALL J WITH CROSSED-TAILMODIFIER LETTER SMALL L W" +
"ITH RETROFLEX HOOKMODIFIER LETTER SMALL L WITH PALATAL HOOKMODIFIER LETT" +
"ER SMALL CAPITAL LMODIFIER LETTER SMALL M WITH HOOKMODIFIER LETTER SMALL" +
" TURNED M WITH LONG LEGMODIFIER LETTER SMALL N WITH LEFT HOOKMODIFIER LE" +
"TTER SMALL N WITH RETROFLEX HOOKMODIFIER LETTER SMALL CAPITAL NMODIFIER " +
"LETTER SMALL BARRED OMODIFIER LETTER SMALL PHIMODIFIER LETTER SMALL S WI" +
"TH HOOKMODIFIER LETTER SMALL ESHMODIFIER LETTER SMALL T WITH PALATAL HOO" +
"KMODIFIER LETTER SMALL U BARMODIFIER LETTER SMALL UPSILONMODIFIER LETTER" +
" SMALL CAPITAL UMODIFIER LETTER SMALL V WITH HOOKMODIFIER LETTER SMALL T" +
"URNED VMODIFIER LETTER SMALL ZMODIFIER LETTER SMALL Z WITH RETROFLEX HOO" +
"KMODIFIER LETTER SMALL Z WITH CURLMODIFIER LETTER SMALL EZHMODIFIER LETT" +
"ER SMALL THETACOMBINING DOTTED GRAVE ACCENTCOMBINING DOTTED ACUTE ACCENT" +
"COMBINING SNAKE BELOWCOMBINING SUSPENSION MARKCOMBINING MACRON-ACUTECOMB" +
"INING GRAVE-MACRONCOMBINING MACRON-GRAVECOMBINING ACUTE-MACRONCOMBINING " +
"GRAVE-ACUTE-GRAVECOMBINING ACUTE-GRAVE-ACUTECOMBINING LATIN SMALL LETTER" +
" R BELOWCOMBINING BREVE-MACRONCOMBINING MACRON-BREVECOMBINING DOUBLE CIR" +
"CUMFLEX ABOVECOMBINING OGONEK ABOVECOMBINING ZIGZAG BELOWCOMBINING IS BE" +
"LOWCOMBINING UR ABOVECOMBINING US ABOVECOMBINING LATIN SMALL LETTER FLAT" +
"TENED OPEN A ABOVECOMBINING LATIN SMALL LETTER AECOMBINING LATIN SMALL L" +
"ETTER AOCOMBINING LATIN SMALL LETTER AVCOMBINING LATIN SMALL LETTER C CE" +
"DILLACOMBINING LATIN SMALL LETTER INSULAR DCOMBINING LATIN SMALL LETTER " +
"ETHCOMBINING LATIN SMALL LETTER GCOMBINING LATIN LETTER SMALL CAPITAL GC" +
"OMBINING LATIN SMALL LETTER KCOMBINING LATIN SMALL LETTER LCOMBINING LAT" +
"IN LETTER SMALL CAPITAL LCOMBINING LATIN LETTER SMALL CAPITAL MCOMBINING" +
" LATIN SMALL LETTER NCOMBINING LATIN LETTER SMALL CAPITAL NCOMBINING LAT" +
"IN LETTER SMALL CAPITAL RCOMBINING LATIN SMALL LETTER R ROTUNDACOMBINING" +
" LATIN SMALL LETTER SCOMBINING LATIN SMALL LETTER LONG SCOMBINING LATIN " +
"SMALL LETTER ZCOMBINING LATIN SMALL LETTER ALPHACOMBINING LATIN SMALL LE" +
"TTER BCOMBINING LATIN SMALL LETTER BETACOMBINING LATIN SMALL LETTER SCHW" +
"ACOMBINING LATIN SMALL LETTER FCOMBINING LATIN SMALL LETTER L WITH DOUBL" +
"E MIDDLE TILDECOMBINING LATIN SMALL LETTER O WITH LIGHT CENTRALIZATION S") + ("" +
"TROKECOMBINING LATIN SMALL LETTER PCOMBINING LATIN SMALL LETTER ESHCOMBI" +
"NING LATIN SMALL LETTER U WITH LIGHT CENTRALIZATION STROKECOMBINING LATI" +
"N SMALL LETTER WCOMBINING LATIN SMALL LETTER A WITH DIAERESISCOMBINING L" +
"ATIN SMALL LETTER O WITH DIAERESISCOMBINING LATIN SMALL LETTER U WITH DI" +
"AERESISCOMBINING UP TACK ABOVECOMBINING KAVYKA ABOVE RIGHTCOMBINING KAVY" +
"KA ABOVE LEFTCOMBINING DOT ABOVE LEFTCOMBINING WIDE INVERTED BRIDGE BELO" +
"WCOMBINING DOT BELOW LEFTCOMBINING DELETION MARKCOMBINING DOUBLE INVERTE" +
"D BREVE BELOWCOMBINING ALMOST EQUAL TO BELOWCOMBINING LEFT ARROWHEAD ABO" +
"VECOMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOWLATIN CAPITAL LETTER" +
" A WITH RING BELOWLATIN SMALL LETTER A WITH RING BELOWLATIN CAPITAL LETT" +
"ER B WITH DOT ABOVELATIN SMALL LETTER B WITH DOT ABOVELATIN CAPITAL LETT" +
"ER B WITH DOT BELOWLATIN SMALL LETTER B WITH DOT BELOWLATIN CAPITAL LETT" +
"ER B WITH LINE BELOWLATIN SMALL LETTER B WITH LINE BELOWLATIN CAPITAL LE" +
"TTER C WITH CEDILLA AND ACUTELATIN SMALL LETTER C WITH CEDILLA AND ACUTE" +
"LATIN CAPITAL LETTER D WITH DOT ABOVELATIN SMALL LETTER D WITH DOT ABOVE" +
"LATIN CAPITAL LETTER D WITH DOT BELOWLATIN SMALL LETTER D WITH DOT BELOW" +
"LATIN CAPITAL LETTER D WITH LINE BELOWLATIN SMALL LETTER D WITH LINE BEL" +
"OWLATIN CAPITAL LETTER D WITH CEDILLALATIN SMALL LETTER D WITH CEDILLALA" +
"TIN CAPITAL LETTER D WITH CIRCUMFLEX BELOWLATIN SMALL LETTER D WITH CIRC" +
"UMFLEX BELOWLATIN CAPITAL LETTER E WITH MACRON AND GRAVELATIN SMALL LETT" +
"ER E WITH MACRON AND GRAVELATIN CAPITAL LETTER E WITH MACRON AND ACUTELA" +
"TIN SMALL LETTER E WITH MACRON AND ACUTELATIN CAPITAL LETTER E WITH CIRC" +
"UMFLEX BELOWLATIN SMALL LETTER E WITH CIRCUMFLEX BELOWLATIN CAPITAL LETT" +
"ER E WITH TILDE BELOWLATIN SMALL LETTER E WITH TILDE BELOWLATIN CAPITAL " +
"LETTER E WITH CEDILLA AND BREVELATIN SMALL LETTER E WITH CEDILLA AND BRE" +
"VELATIN CAPITAL LETTER F WITH DOT ABOVELATIN SMALL LETTER F WITH DOT ABO" +
"VELATIN CAPITAL LETTER G WITH MACRONLATIN SMALL LETTER G WITH MACRONLATI" +
"N CAPITAL LETTER H WITH DOT ABOVELATIN SMALL LETTER H WITH DOT ABOVELATI" +
"N CAPITAL LETTER H WITH DOT BELOWLATIN SMALL LETTER H WITH DOT BELOWLATI" +
"N CAPITAL LETTER H WITH DIAERESISLATIN SMALL LETTER H WITH DIAERESISLATI" +
"N CAPITAL LETTER H WITH CEDILLALATIN SMALL LETTER H WITH CEDILLALATIN CA" +
"PITAL LETTER H WITH BREVE BELOWLATIN SMALL LETTER H WITH BREVE BELOWLATI" +
"N CAPITAL LETTER I WITH TILDE BELOWLATIN SMALL LETTER I WITH TILDE BELOW" +
"LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTELATIN SMALL LETTER I WITH" +
" DIAERESIS AND ACUTELATIN CAPITAL LETTER K WITH ACUTELATIN SMALL LETTER " +
"K WITH ACUTELATIN CAPITAL LETTER K WITH DOT BELOWLATIN SMALL LETTER K WI" +
"TH DOT BELOWLATIN CAPITAL LETTER K WITH LINE BELOWLATIN SMALL LETTER K W" +
"ITH LINE BELOWLATIN CAPITAL LETTER L WITH DOT BELOWLATIN SMALL LETTER L " +
"WITH DOT BELOWLATIN CAPITAL LETTER L WITH DOT BELOW AND MACRONLATIN SMAL" +
"L LETTER L WITH DOT BELOW AND MACRONLATIN CAPITAL LETTER L WITH LINE BEL" +
"OWLATIN SMALL LETTER L WITH LINE BELOWLATIN CAPITAL LETTER L WITH CIRCUM" +
"FLEX BELOWLATIN SMALL LETTER L WITH CIRCUMFLEX BELOWLATIN CAPITAL LETTER" +
" M WITH ACUTELATIN SMALL LETTER M WITH ACUTELATIN CAPITAL LETTER M WITH " +
"DOT ABOVELATIN SMALL LETTER M WITH DOT ABOVELATIN CAPITAL LETTER M WITH " +
"DOT BELOWLATIN SMALL LETTER M WITH DOT BELOWLATIN CAPITAL LETTER N WITH " +
"DOT ABOVELATIN SMALL LETTER N WITH DOT ABOVELATIN CAPITAL LETTER N WITH " +
"DOT BELOWLATIN SMALL LETTER N WITH DOT BELOWLATIN CAPITAL LETTER N WITH " +
"LINE BELOWLATIN SMALL LETTER N WITH LINE BELOWLATIN CAPITAL LETTER N WIT" +
"H CIRCUMFLEX BELOWLATIN SMALL LETTER N WITH CIRCUMFLEX BELOWLATIN CAPITA" +
"L LETTER O WITH TILDE AND ACUTELATIN SMALL LETTER O WITH TILDE AND ACUTE" +
"LATIN CAPITAL LETTER O WITH TILDE AND DIAERESISLATIN SMALL LETTER O WITH" +
" TILDE AND DIAERESISLATIN CAPITAL LETTER O WITH MACRON AND GRAVELATIN SM" +
"ALL LETTER O WITH MACRON AND GRAVELATIN CAPITAL LETTER O WITH MACRON AND" +
" ACUTELATIN SMALL LETTER O WITH MACRON AND ACUTELATIN CAPITAL LETTER P W" +
"ITH ACUTELATIN SMALL LETTER P WITH ACUTELATIN CAPITAL LETTER P WITH DOT " +
"ABOVELATIN SMALL LETTER P WITH DOT ABOVELATIN CAPITAL LETTER R WITH DOT " +
"ABOVELATIN SMALL LETTER R WITH DOT ABOVELATIN CAPITAL LETTER R WITH DOT " +
"BELOWLATIN SMALL LETTER R WITH DOT BELOWLATIN CAPITAL LETTER R WITH DOT " +
"BELOW AND MACRONLATIN SMALL LETTER R WITH DOT BELOW AND MACRONLATIN CAPI" +
"TAL LETTER R WITH LINE BELOWLATIN SMALL LETTER R WITH LINE BELOWLATIN CA" +
"PITAL LETTER S WITH DOT ABOVELATIN SMALL LETTER S WITH DOT ABOVELATIN CA" +
"PITAL LETTER S WITH DOT BELOWLATIN SMALL LETTER S WITH DOT BELOWLATIN CA" +
"PITAL LETTER S WITH ACUTE AND DOT ABOVELATIN SMALL LETTER S WITH ACUTE A" +
"ND DOT ABOVELATIN CAPITAL LETTER S WITH CARON AND DOT ABOVELATIN SMALL L") + ("" +
"ETTER S WITH CARON AND DOT ABOVELATIN CAPITAL LETTER S WITH DOT BELOW AN" +
"D DOT ABOVELATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVELATIN CAPITA" +
"L LETTER T WITH DOT ABOVELATIN SMALL LETTER T WITH DOT ABOVELATIN CAPITA" +
"L LETTER T WITH DOT BELOWLATIN SMALL LETTER T WITH DOT BELOWLATIN CAPITA" +
"L LETTER T WITH LINE BELOWLATIN SMALL LETTER T WITH LINE BELOWLATIN CAPI" +
"TAL LETTER T WITH CIRCUMFLEX BELOWLATIN SMALL LETTER T WITH CIRCUMFLEX B" +
"ELOWLATIN CAPITAL LETTER U WITH DIAERESIS BELOWLATIN SMALL LETTER U WITH" +
" DIAERESIS BELOWLATIN CAPITAL LETTER U WITH TILDE BELOWLATIN SMALL LETTE" +
"R U WITH TILDE BELOWLATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOWLATIN SM" +
"ALL LETTER U WITH CIRCUMFLEX BELOWLATIN CAPITAL LETTER U WITH TILDE AND " +
"ACUTELATIN SMALL LETTER U WITH TILDE AND ACUTELATIN CAPITAL LETTER U WIT" +
"H MACRON AND DIAERESISLATIN SMALL LETTER U WITH MACRON AND DIAERESISLATI" +
"N CAPITAL LETTER V WITH TILDELATIN SMALL LETTER V WITH TILDELATIN CAPITA" +
"L LETTER V WITH DOT BELOWLATIN SMALL LETTER V WITH DOT BELOWLATIN CAPITA" +
"L LETTER W WITH GRAVELATIN SMALL LETTER W WITH GRAVELATIN CAPITAL LETTER" +
" W WITH ACUTELATIN SMALL LETTER W WITH ACUTELATIN CAPITAL LETTER W WITH " +
"DIAERESISLATIN SMALL LETTER W WITH DIAERESISLATIN CAPITAL LETTER W WITH " +
"DOT ABOVELATIN SMALL LETTER W WITH DOT ABOVELATIN CAPITAL LETTER W WITH " +
"DOT BELOWLATIN SMALL LETTER W WITH DOT BELOWLATIN CAPITAL LETTER X WITH " +
"DOT ABOVELATIN SMALL LETTER X WITH DOT ABOVELATIN CAPITAL LETTER X WITH " +
"DIAERESISLATIN SMALL LETTER X WITH DIAERESISLATIN CAPITAL LETTER Y WITH " +
"DOT ABOVELATIN SMALL LETTER Y WITH DOT ABOVELATIN CAPITAL LETTER Z WITH " +
"CIRCUMFLEXLATIN SMALL LETTER Z WITH CIRCUMFLEXLATIN CAPITAL LETTER Z WIT" +
"H DOT BELOWLATIN SMALL LETTER Z WITH DOT BELOWLATIN CAPITAL LETTER Z WIT" +
"H LINE BELOWLATIN SMALL LETTER Z WITH LINE BELOWLATIN SMALL LETTER H WIT" +
"H LINE BELOWLATIN SMALL LETTER T WITH DIAERESISLATIN SMALL LETTER W WITH" +
" RING ABOVELATIN SMALL LETTER Y WITH RING ABOVELATIN SMALL LETTER A WITH" +
" RIGHT HALF RINGLATIN SMALL LETTER LONG S WITH DOT ABOVELATIN SMALL LETT" +
"ER LONG S WITH DIAGONAL STROKELATIN SMALL LETTER LONG S WITH HIGH STROKE" +
"LATIN CAPITAL LETTER SHARP SLATIN SMALL LETTER DELTALATIN CAPITAL LETTER" +
" A WITH DOT BELOWLATIN SMALL LETTER A WITH DOT BELOWLATIN CAPITAL LETTER" +
" A WITH HOOK ABOVELATIN SMALL LETTER A WITH HOOK ABOVELATIN CAPITAL LETT" +
"ER A WITH CIRCUMFLEX AND ACUTELATIN SMALL LETTER A WITH CIRCUMFLEX AND A" +
"CUTELATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVELATIN SMALL LETTER A" +
" WITH CIRCUMFLEX AND GRAVELATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOO" +
"K ABOVELATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVELATIN CAPITAL " +
"LETTER A WITH CIRCUMFLEX AND TILDELATIN SMALL LETTER A WITH CIRCUMFLEX A" +
"ND TILDELATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOWLATIN SMALL " +
"LETTER A WITH CIRCUMFLEX AND DOT BELOWLATIN CAPITAL LETTER A WITH BREVE " +
"AND ACUTELATIN SMALL LETTER A WITH BREVE AND ACUTELATIN CAPITAL LETTER A" +
" WITH BREVE AND GRAVELATIN SMALL LETTER A WITH BREVE AND GRAVELATIN CAPI" +
"TAL LETTER A WITH BREVE AND HOOK ABOVELATIN SMALL LETTER A WITH BREVE AN" +
"D HOOK ABOVELATIN CAPITAL LETTER A WITH BREVE AND TILDELATIN SMALL LETTE" +
"R A WITH BREVE AND TILDELATIN CAPITAL LETTER A WITH BREVE AND DOT BELOWL" +
"ATIN SMALL LETTER A WITH BREVE AND DOT BELOWLATIN CAPITAL LETTER E WITH " +
"DOT BELOWLATIN SMALL LETTER E WITH DOT BELOWLATIN CAPITAL LETTER E WITH " +
"HOOK ABOVELATIN SMALL LETTER E WITH HOOK ABOVELATIN CAPITAL LETTER E WIT" +
"H TILDELATIN SMALL LETTER E WITH TILDELATIN CAPITAL LETTER E WITH CIRCUM" +
"FLEX AND ACUTELATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTELATIN CAPITA" +
"L LETTER E WITH CIRCUMFLEX AND GRAVELATIN SMALL LETTER E WITH CIRCUMFLEX" +
" AND GRAVELATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVELATIN SMA" +
"LL LETTER E WITH CIRCUMFLEX AND HOOK ABOVELATIN CAPITAL LETTER E WITH CI" +
"RCUMFLEX AND TILDELATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDELATIN CA" +
"PITAL LETTER E WITH CIRCUMFLEX AND DOT BELOWLATIN SMALL LETTER E WITH CI" +
"RCUMFLEX AND DOT BELOWLATIN CAPITAL LETTER I WITH HOOK ABOVELATIN SMALL " +
"LETTER I WITH HOOK ABOVELATIN CAPITAL LETTER I WITH DOT BELOWLATIN SMALL" +
" LETTER I WITH DOT BELOWLATIN CAPITAL LETTER O WITH DOT BELOWLATIN SMALL" +
" LETTER O WITH DOT BELOWLATIN CAPITAL LETTER O WITH HOOK ABOVELATIN SMAL" +
"L LETTER O WITH HOOK ABOVELATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACU" +
"TELATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTELATIN CAPITAL LETTER O W" +
"ITH CIRCUMFLEX AND GRAVELATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVELA" +
"TIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVELATIN SMALL LETTER O " +
"WITH CIRCUMFLEX AND HOOK ABOVELATIN CAPITAL LETTER O WITH CIRCUMFLEX AND" +
" TILDELATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDELATIN CAPITAL LETTER") + ("" +
" O WITH CIRCUMFLEX AND DOT BELOWLATIN SMALL LETTER O WITH CIRCUMFLEX AND" +
" DOT BELOWLATIN CAPITAL LETTER O WITH HORN AND ACUTELATIN SMALL LETTER O" +
" WITH HORN AND ACUTELATIN CAPITAL LETTER O WITH HORN AND GRAVELATIN SMAL" +
"L LETTER O WITH HORN AND GRAVELATIN CAPITAL LETTER O WITH HORN AND HOOK " +
"ABOVELATIN SMALL LETTER O WITH HORN AND HOOK ABOVELATIN CAPITAL LETTER O" +
" WITH HORN AND TILDELATIN SMALL LETTER O WITH HORN AND TILDELATIN CAPITA" +
"L LETTER O WITH HORN AND DOT BELOWLATIN SMALL LETTER O WITH HORN AND DOT" +
" BELOWLATIN CAPITAL LETTER U WITH DOT BELOWLATIN SMALL LETTER U WITH DOT" +
" BELOWLATIN CAPITAL LETTER U WITH HOOK ABOVELATIN SMALL LETTER U WITH HO" +
"OK ABOVELATIN CAPITAL LETTER U WITH HORN AND ACUTELATIN SMALL LETTER U W" +
"ITH HORN AND ACUTELATIN CAPITAL LETTER U WITH HORN AND GRAVELATIN SMALL " +
"LETTER U WITH HORN AND GRAVELATIN CAPITAL LETTER U WITH HORN AND HOOK AB" +
"OVELATIN SMALL LETTER U WITH HORN AND HOOK ABOVELATIN CAPITAL LETTER U W" +
"ITH HORN AND TILDELATIN SMALL LETTER U WITH HORN AND TILDELATIN CAPITAL " +
"LETTER U WITH HORN AND DOT BELOWLATIN SMALL LETTER U WITH HORN AND DOT B" +
"ELOWLATIN CAPITAL LETTER Y WITH GRAVELATIN SMALL LETTER Y WITH GRAVELATI" +
"N CAPITAL LETTER Y WITH DOT BELOWLATIN SMALL LETTER Y WITH DOT BELOWLATI" +
"N CAPITAL LETTER Y WITH HOOK ABOVELATIN SMALL LETTER Y WITH HOOK ABOVELA" +
"TIN CAPITAL LETTER Y WITH TILDELATIN SMALL LETTER Y WITH TILDELATIN CAPI" +
"TAL LETTER MIDDLE-WELSH LLLATIN SMALL LETTER MIDDLE-WELSH LLLATIN CAPITA" +
"L LETTER MIDDLE-WELSH VLATIN SMALL LETTER MIDDLE-WELSH VLATIN CAPITAL LE" +
"TTER Y WITH LOOPLATIN SMALL LETTER Y WITH LOOPGREEK SMALL LETTER ALPHA W" +
"ITH PSILIGREEK SMALL LETTER ALPHA WITH DASIAGREEK SMALL LETTER ALPHA WIT" +
"H PSILI AND VARIAGREEK SMALL LETTER ALPHA WITH DASIA AND VARIAGREEK SMAL" +
"L LETTER ALPHA WITH PSILI AND OXIAGREEK SMALL LETTER ALPHA WITH DASIA AN" +
"D OXIAGREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENIGREEK SMALL LET" +
"TER ALPHA WITH DASIA AND PERISPOMENIGREEK CAPITAL LETTER ALPHA WITH PSIL" +
"IGREEK CAPITAL LETTER ALPHA WITH DASIAGREEK CAPITAL LETTER ALPHA WITH PS" +
"ILI AND VARIAGREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIAGREEK CAPITA" +
"L LETTER ALPHA WITH PSILI AND OXIAGREEK CAPITAL LETTER ALPHA WITH DASIA " +
"AND OXIAGREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENIGREEK CAPIT" +
"AL LETTER ALPHA WITH DASIA AND PERISPOMENIGREEK SMALL LETTER EPSILON WIT" +
"H PSILIGREEK SMALL LETTER EPSILON WITH DASIAGREEK SMALL LETTER EPSILON W" +
"ITH PSILI AND VARIAGREEK SMALL LETTER EPSILON WITH DASIA AND VARIAGREEK " +
"SMALL LETTER EPSILON WITH PSILI AND OXIAGREEK SMALL LETTER EPSILON WITH " +
"DASIA AND OXIAGREEK CAPITAL LETTER EPSILON WITH PSILIGREEK CAPITAL LETTE" +
"R EPSILON WITH DASIAGREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIAGRE" +
"EK CAPITAL LETTER EPSILON WITH DASIA AND VARIAGREEK CAPITAL LETTER EPSIL" +
"ON WITH PSILI AND OXIAGREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIAGR" +
"EEK SMALL LETTER ETA WITH PSILIGREEK SMALL LETTER ETA WITH DASIAGREEK SM" +
"ALL LETTER ETA WITH PSILI AND VARIAGREEK SMALL LETTER ETA WITH DASIA AND" +
" VARIAGREEK SMALL LETTER ETA WITH PSILI AND OXIAGREEK SMALL LETTER ETA W" +
"ITH DASIA AND OXIAGREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENIGREEK" +
" SMALL LETTER ETA WITH DASIA AND PERISPOMENIGREEK CAPITAL LETTER ETA WIT" +
"H PSILIGREEK CAPITAL LETTER ETA WITH DASIAGREEK CAPITAL LETTER ETA WITH " +
"PSILI AND VARIAGREEK CAPITAL LETTER ETA WITH DASIA AND VARIAGREEK CAPITA" +
"L LETTER ETA WITH PSILI AND OXIAGREEK CAPITAL LETTER ETA WITH DASIA AND " +
"OXIAGREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENIGREEK CAPITAL LET" +
"TER ETA WITH DASIA AND PERISPOMENIGREEK SMALL LETTER IOTA WITH PSILIGREE" +
"K SMALL LETTER IOTA WITH DASIAGREEK SMALL LETTER IOTA WITH PSILI AND VAR" +
"IAGREEK SMALL LETTER IOTA WITH DASIA AND VARIAGREEK SMALL LETTER IOTA WI" +
"TH PSILI AND OXIAGREEK SMALL LETTER IOTA WITH DASIA AND OXIAGREEK SMALL " +
"LETTER IOTA WITH PSILI AND PERISPOMENIGREEK SMALL LETTER IOTA WITH DASIA" +
" AND PERISPOMENIGREEK CAPITAL LETTER IOTA WITH PSILIGREEK CAPITAL LETTER" +
" IOTA WITH DASIAGREEK CAPITAL LETTER IOTA WITH PSILI AND VARIAGREEK CAPI" +
"TAL LETTER IOTA WITH DASIA AND VARIAGREEK CAPITAL LETTER IOTA WITH PSILI" +
" AND OXIAGREEK CAPITAL LETTER IOTA WITH DASIA AND OXIAGREEK CAPITAL LETT" +
"ER IOTA WITH PSILI AND PERISPOMENIGREEK CAPITAL LETTER IOTA WITH DASIA A" +
"ND PERISPOMENIGREEK SMALL LETTER OMICRON WITH PSILIGREEK SMALL LETTER OM" +
"ICRON WITH DASIAGREEK SMALL LETTER OMICRON WITH PSILI AND VARIAGREEK SMA" +
"LL LETTER OMICRON WITH DASIA AND VARIAGREEK SMALL LETTER OMICRON WITH PS" +
"ILI AND OXIAGREEK SMALL LETTER OMICRON WITH DASIA AND OXIAGREEK CAPITAL " +
"LETTER OMICRON WITH PSILIGREEK CAPITAL LETTER OMICRON WITH DASIAGREEK CA" +
"PITAL LETTER OMICRON WITH PSILI AND VARIAGREEK CAPITAL LETTER OMICRON WI") + ("" +
"TH DASIA AND VARIAGREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIAGREEK " +
"CAPITAL LETTER OMICRON WITH DASIA AND OXIAGREEK SMALL LETTER UPSILON WIT" +
"H PSILIGREEK SMALL LETTER UPSILON WITH DASIAGREEK SMALL LETTER UPSILON W" +
"ITH PSILI AND VARIAGREEK SMALL LETTER UPSILON WITH DASIA AND VARIAGREEK " +
"SMALL LETTER UPSILON WITH PSILI AND OXIAGREEK SMALL LETTER UPSILON WITH " +
"DASIA AND OXIAGREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENIGREEK" +
" SMALL LETTER UPSILON WITH DASIA AND PERISPOMENIGREEK CAPITAL LETTER UPS" +
"ILON WITH DASIAGREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIAGREEK CA" +
"PITAL LETTER UPSILON WITH DASIA AND OXIAGREEK CAPITAL LETTER UPSILON WIT" +
"H DASIA AND PERISPOMENIGREEK SMALL LETTER OMEGA WITH PSILIGREEK SMALL LE" +
"TTER OMEGA WITH DASIAGREEK SMALL LETTER OMEGA WITH PSILI AND VARIAGREEK " +
"SMALL LETTER OMEGA WITH DASIA AND VARIAGREEK SMALL LETTER OMEGA WITH PSI" +
"LI AND OXIAGREEK SMALL LETTER OMEGA WITH DASIA AND OXIAGREEK SMALL LETTE" +
"R OMEGA WITH PSILI AND PERISPOMENIGREEK SMALL LETTER OMEGA WITH DASIA AN" +
"D PERISPOMENIGREEK CAPITAL LETTER OMEGA WITH PSILIGREEK CAPITAL LETTER O" +
"MEGA WITH DASIAGREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIAGREEK CAPI" +
"TAL LETTER OMEGA WITH DASIA AND VARIAGREEK CAPITAL LETTER OMEGA WITH PSI" +
"LI AND OXIAGREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIAGREEK CAPITAL L" +
"ETTER OMEGA WITH PSILI AND PERISPOMENIGREEK CAPITAL LETTER OMEGA WITH DA" +
"SIA AND PERISPOMENIGREEK SMALL LETTER ALPHA WITH VARIAGREEK SMALL LETTER" +
" ALPHA WITH OXIAGREEK SMALL LETTER EPSILON WITH VARIAGREEK SMALL LETTER " +
"EPSILON WITH OXIAGREEK SMALL LETTER ETA WITH VARIAGREEK SMALL LETTER ETA" +
" WITH OXIAGREEK SMALL LETTER IOTA WITH VARIAGREEK SMALL LETTER IOTA WITH" +
" OXIAGREEK SMALL LETTER OMICRON WITH VARIAGREEK SMALL LETTER OMICRON WIT" +
"H OXIAGREEK SMALL LETTER UPSILON WITH VARIAGREEK SMALL LETTER UPSILON WI" +
"TH OXIAGREEK SMALL LETTER OMEGA WITH VARIAGREEK SMALL LETTER OMEGA WITH " +
"OXIAGREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENIGREEK SMALL LET" +
"TER ALPHA WITH DASIA AND YPOGEGRAMMENIGREEK SMALL LETTER ALPHA WITH PSIL" +
"I AND VARIA AND YPOGEGRAMMENIGREEK SMALL LETTER ALPHA WITH DASIA AND VAR" +
"IA AND YPOGEGRAMMENIGREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPO" +
"GEGRAMMENIGREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI" +
"GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENIGRE" +
"EK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENIGREEK " +
"CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENIGREEK CAPITAL LETTER A" +
"LPHA WITH DASIA AND PROSGEGRAMMENIGREEK CAPITAL LETTER ALPHA WITH PSILI " +
"AND VARIA AND PROSGEGRAMMENIGREEK CAPITAL LETTER ALPHA WITH DASIA AND VA" +
"RIA AND PROSGEGRAMMENIGREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND" +
" PROSGEGRAMMENIGREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGE" +
"GRAMMENIGREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGE" +
"GRAMMENIGREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGE" +
"GRAMMENIGREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENIGREEK SMALL L" +
"ETTER ETA WITH DASIA AND YPOGEGRAMMENIGREEK SMALL LETTER ETA WITH PSILI " +
"AND VARIA AND YPOGEGRAMMENIGREEK SMALL LETTER ETA WITH DASIA AND VARIA A" +
"ND YPOGEGRAMMENIGREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAM" +
"MENIGREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENIGREEK SM" +
"ALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENIGREEK SMALL L" +
"ETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENIGREEK CAPITAL LETT" +
"ER ETA WITH PSILI AND PROSGEGRAMMENIGREEK CAPITAL LETTER ETA WITH DASIA " +
"AND PROSGEGRAMMENIGREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROS" +
"GEGRAMMENIGREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMME" +
"NIGREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENIGREEK C" +
"APITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENIGREEK CAPITAL LE" +
"TTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENIGREEK CAPITAL LETT" +
"ER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENIGREEK SMALL LETTER O" +
"MEGA WITH PSILI AND YPOGEGRAMMENIGREEK SMALL LETTER OMEGA WITH DASIA AND" +
" YPOGEGRAMMENIGREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRA" +
"MMENIGREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENIGREE" +
"K SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENIGREEK SMALL LE" +
"TTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENIGREEK SMALL LETTER OMEGA" +
" WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENIGREEK SMALL LETTER OMEGA WI" +
"TH DASIA AND PERISPOMENI AND YPOGEGRAMMENIGREEK CAPITAL LETTER OMEGA WIT" +
"H PSILI AND PROSGEGRAMMENIGREEK CAPITAL LETTER OMEGA WITH DASIA AND PROS" +
"GEGRAMMENIGREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAM" +
"MENIGREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENIGR") + ("" +
"EEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENIGREEK CAP" +
"ITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENIGREEK CAPITAL LE" +
"TTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENIGREEK CAPITAL LE" +
"TTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENIGREEK SMALL LETT" +
"ER ALPHA WITH VRACHYGREEK SMALL LETTER ALPHA WITH MACRONGREEK SMALL LETT" +
"ER ALPHA WITH VARIA AND YPOGEGRAMMENIGREEK SMALL LETTER ALPHA WITH YPOGE" +
"GRAMMENIGREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENIGREEK SMALL " +
"LETTER ALPHA WITH PERISPOMENIGREEK SMALL LETTER ALPHA WITH PERISPOMENI A" +
"ND YPOGEGRAMMENIGREEK CAPITAL LETTER ALPHA WITH VRACHYGREEK CAPITAL LETT" +
"ER ALPHA WITH MACRONGREEK CAPITAL LETTER ALPHA WITH VARIAGREEK CAPITAL L" +
"ETTER ALPHA WITH OXIAGREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENIGREEK" +
" KORONISGREEK PROSGEGRAMMENIGREEK PSILIGREEK PERISPOMENIGREEK DIALYTIKA " +
"AND PERISPOMENIGREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENIGREEK " +
"SMALL LETTER ETA WITH YPOGEGRAMMENIGREEK SMALL LETTER ETA WITH OXIA AND " +
"YPOGEGRAMMENIGREEK SMALL LETTER ETA WITH PERISPOMENIGREEK SMALL LETTER E" +
"TA WITH PERISPOMENI AND YPOGEGRAMMENIGREEK CAPITAL LETTER EPSILON WITH V" +
"ARIAGREEK CAPITAL LETTER EPSILON WITH OXIAGREEK CAPITAL LETTER ETA WITH " +
"VARIAGREEK CAPITAL LETTER ETA WITH OXIAGREEK CAPITAL LETTER ETA WITH PRO" +
"SGEGRAMMENIGREEK PSILI AND VARIAGREEK PSILI AND OXIAGREEK PSILI AND PERI" +
"SPOMENIGREEK SMALL LETTER IOTA WITH VRACHYGREEK SMALL LETTER IOTA WITH M" +
"ACRONGREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIAGREEK SMALL LETTER " +
"IOTA WITH DIALYTIKA AND OXIAGREEK SMALL LETTER IOTA WITH PERISPOMENIGREE" +
"K SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENIGREEK CAPITAL LETTER I" +
"OTA WITH VRACHYGREEK CAPITAL LETTER IOTA WITH MACRONGREEK CAPITAL LETTER" +
" IOTA WITH VARIAGREEK CAPITAL LETTER IOTA WITH OXIAGREEK DASIA AND VARIA" +
"GREEK DASIA AND OXIAGREEK DASIA AND PERISPOMENIGREEK SMALL LETTER UPSILO" +
"N WITH VRACHYGREEK SMALL LETTER UPSILON WITH MACRONGREEK SMALL LETTER UP" +
"SILON WITH DIALYTIKA AND VARIAGREEK SMALL LETTER UPSILON WITH DIALYTIKA " +
"AND OXIAGREEK SMALL LETTER RHO WITH PSILIGREEK SMALL LETTER RHO WITH DAS" +
"IAGREEK SMALL LETTER UPSILON WITH PERISPOMENIGREEK SMALL LETTER UPSILON " +
"WITH DIALYTIKA AND PERISPOMENIGREEK CAPITAL LETTER UPSILON WITH VRACHYGR" +
"EEK CAPITAL LETTER UPSILON WITH MACRONGREEK CAPITAL LETTER UPSILON WITH " +
"VARIAGREEK CAPITAL LETTER UPSILON WITH OXIAGREEK CAPITAL LETTER RHO WITH" +
" DASIAGREEK DIALYTIKA AND VARIAGREEK DIALYTIKA AND OXIAGREEK VARIAGREEK " +
"SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENIGREEK SMALL LETTER OMEGA " +
"WITH YPOGEGRAMMENIGREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENIGR" +
"EEK SMALL LETTER OMEGA WITH PERISPOMENIGREEK SMALL LETTER OMEGA WITH PER" +
"ISPOMENI AND YPOGEGRAMMENIGREEK CAPITAL LETTER OMICRON WITH VARIAGREEK C" +
"APITAL LETTER OMICRON WITH OXIAGREEK CAPITAL LETTER OMEGA WITH VARIAGREE" +
"K CAPITAL LETTER OMEGA WITH OXIAGREEK CAPITAL LETTER OMEGA WITH PROSGEGR" +
"AMMENIGREEK OXIAGREEK DASIAEN QUADEM QUADEN SPACEEM SPACETHREE-PER-EM SP" +
"ACEFOUR-PER-EM SPACESIX-PER-EM SPACEFIGURE SPACEPUNCTUATION SPACETHIN SP" +
"ACEHAIR SPACEZERO WIDTH SPACEZERO WIDTH NON-JOINERZERO WIDTH JOINERLEFT-" +
"TO-RIGHT MARKRIGHT-TO-LEFT MARKHYPHENNON-BREAKING HYPHENFIGURE DASHEN DA" +
"SHEM DASHHORIZONTAL BARDOUBLE VERTICAL LINEDOUBLE LOW LINELEFT SINGLE QU" +
"OTATION MARKRIGHT SINGLE QUOTATION MARKSINGLE LOW-9 QUOTATION MARKSINGLE" +
" HIGH-REVERSED-9 QUOTATION MARKLEFT DOUBLE QUOTATION MARKRIGHT DOUBLE QU" +
"OTATION MARKDOUBLE LOW-9 QUOTATION MARKDOUBLE HIGH-REVERSED-9 QUOTATION " +
"MARKDAGGERDOUBLE DAGGERBULLETTRIANGULAR BULLETONE DOT LEADERTWO DOT LEAD" +
"ERHORIZONTAL ELLIPSISHYPHENATION POINTLINE SEPARATORPARAGRAPH SEPARATORL" +
"EFT-TO-RIGHT EMBEDDINGRIGHT-TO-LEFT EMBEDDINGPOP DIRECTIONAL FORMATTINGL" +
"EFT-TO-RIGHT OVERRIDERIGHT-TO-LEFT OVERRIDENARROW NO-BREAK SPACEPER MILL" +
"E SIGNPER TEN THOUSAND SIGNPRIMEDOUBLE PRIMETRIPLE PRIMEREVERSED PRIMERE" +
"VERSED DOUBLE PRIMEREVERSED TRIPLE PRIMECARETSINGLE LEFT-POINTING ANGLE " +
"QUOTATION MARKSINGLE RIGHT-POINTING ANGLE QUOTATION MARKREFERENCE MARKDO" +
"UBLE EXCLAMATION MARKINTERROBANGOVERLINEUNDERTIECHARACTER TIECARET INSER" +
"TION POINTASTERISMHYPHEN BULLETFRACTION SLASHLEFT SQUARE BRACKET WITH QU" +
"ILLRIGHT SQUARE BRACKET WITH QUILLDOUBLE QUESTION MARKQUESTION EXCLAMATI" +
"ON MARKEXCLAMATION QUESTION MARKTIRONIAN SIGN ETREVERSED PILCROW SIGNBLA" +
"CK LEFTWARDS BULLETBLACK RIGHTWARDS BULLETLOW ASTERISKREVERSED SEMICOLON" +
"CLOSE UPTWO ASTERISKS ALIGNED VERTICALLYCOMMERCIAL MINUS SIGNSWUNG DASHI" +
"NVERTED UNDERTIEFLOWER PUNCTUATION MARKTHREE DOT PUNCTUATIONQUADRUPLE PR" +
"IMEFOUR DOT PUNCTUATIONFIVE DOT PUNCTUATIONTWO DOT PUNCTUATIONFOUR DOT M" +
"ARKDOTTED CROSSTRICOLONVERTICAL FOUR DOTSMEDIUM MATHEMATICAL SPACEWORD J") + ("" +
"OINERFUNCTION APPLICATIONINVISIBLE TIMESINVISIBLE SEPARATORINVISIBLE PLU" +
"SLEFT-TO-RIGHT ISOLATERIGHT-TO-LEFT ISOLATEFIRST STRONG ISOLATEPOP DIREC" +
"TIONAL ISOLATEINHIBIT SYMMETRIC SWAPPINGACTIVATE SYMMETRIC SWAPPINGINHIB" +
"IT ARABIC FORM SHAPINGACTIVATE ARABIC FORM SHAPINGNATIONAL DIGIT SHAPESN" +
"OMINAL DIGIT SHAPESSUPERSCRIPT ZEROSUPERSCRIPT LATIN SMALL LETTER ISUPER" +
"SCRIPT FOURSUPERSCRIPT FIVESUPERSCRIPT SIXSUPERSCRIPT SEVENSUPERSCRIPT E" +
"IGHTSUPERSCRIPT NINESUPERSCRIPT PLUS SIGNSUPERSCRIPT MINUSSUPERSCRIPT EQ" +
"UALS SIGNSUPERSCRIPT LEFT PARENTHESISSUPERSCRIPT RIGHT PARENTHESISSUPERS" +
"CRIPT LATIN SMALL LETTER NSUBSCRIPT ZEROSUBSCRIPT ONESUBSCRIPT TWOSUBSCR" +
"IPT THREESUBSCRIPT FOURSUBSCRIPT FIVESUBSCRIPT SIXSUBSCRIPT SEVENSUBSCRI" +
"PT EIGHTSUBSCRIPT NINESUBSCRIPT PLUS SIGNSUBSCRIPT MINUSSUBSCRIPT EQUALS" +
" SIGNSUBSCRIPT LEFT PARENTHESISSUBSCRIPT RIGHT PARENTHESISLATIN SUBSCRIP" +
"T SMALL LETTER ALATIN SUBSCRIPT SMALL LETTER ELATIN SUBSCRIPT SMALL LETT" +
"ER OLATIN SUBSCRIPT SMALL LETTER XLATIN SUBSCRIPT SMALL LETTER SCHWALATI" +
"N SUBSCRIPT SMALL LETTER HLATIN SUBSCRIPT SMALL LETTER KLATIN SUBSCRIPT " +
"SMALL LETTER LLATIN SUBSCRIPT SMALL LETTER MLATIN SUBSCRIPT SMALL LETTER" +
" NLATIN SUBSCRIPT SMALL LETTER PLATIN SUBSCRIPT SMALL LETTER SLATIN SUBS" +
"CRIPT SMALL LETTER TEURO-CURRENCY SIGNCOLON SIGNCRUZEIRO SIGNFRENCH FRAN" +
"C SIGNLIRA SIGNMILL SIGNNAIRA SIGNPESETA SIGNRUPEE SIGNWON SIGNNEW SHEQE" +
"L SIGNDONG SIGNEURO SIGNKIP SIGNTUGRIK SIGNDRACHMA SIGNGERMAN PENNY SIGN" +
"PESO SIGNGUARANI SIGNAUSTRAL SIGNHRYVNIA SIGNCEDI SIGNLIVRE TOURNOIS SIG" +
"NSPESMILO SIGNTENGE SIGNINDIAN RUPEE SIGNTURKISH LIRA SIGNNORDIC MARK SI" +
"GNMANAT SIGNRUBLE SIGNLARI SIGNBITCOIN SIGNSOM SIGNCOMBINING LEFT HARPOO" +
"N ABOVECOMBINING RIGHT HARPOON ABOVECOMBINING LONG VERTICAL LINE OVERLAY" +
"COMBINING SHORT VERTICAL LINE OVERLAYCOMBINING ANTICLOCKWISE ARROW ABOVE" +
"COMBINING CLOCKWISE ARROW ABOVECOMBINING LEFT ARROW ABOVECOMBINING RIGHT" +
" ARROW ABOVECOMBINING RING OVERLAYCOMBINING CLOCKWISE RING OVERLAYCOMBIN" +
"ING ANTICLOCKWISE RING OVERLAYCOMBINING THREE DOTS ABOVECOMBINING FOUR D" +
"OTS ABOVECOMBINING ENCLOSING CIRCLECOMBINING ENCLOSING SQUARECOMBINING E" +
"NCLOSING DIAMONDCOMBINING ENCLOSING CIRCLE BACKSLASHCOMBINING LEFT RIGHT" +
" ARROW ABOVECOMBINING ENCLOSING SCREENCOMBINING ENCLOSING KEYCAPCOMBININ" +
"G ENCLOSING UPWARD POINTING TRIANGLECOMBINING REVERSE SOLIDUS OVERLAYCOM" +
"BINING DOUBLE VERTICAL STROKE OVERLAYCOMBINING ANNUITY SYMBOLCOMBINING T" +
"RIPLE UNDERDOTCOMBINING WIDE BRIDGE ABOVECOMBINING LEFTWARDS ARROW OVERL" +
"AYCOMBINING LONG DOUBLE SOLIDUS OVERLAYCOMBINING RIGHTWARDS HARPOON WITH" +
" BARB DOWNWARDSCOMBINING LEFTWARDS HARPOON WITH BARB DOWNWARDSCOMBINING " +
"LEFT ARROW BELOWCOMBINING RIGHT ARROW BELOWCOMBINING ASTERISK ABOVEACCOU" +
"NT OFADDRESSED TO THE SUBJECTDOUBLE-STRUCK CAPITAL CDEGREE CELSIUSCENTRE" +
" LINE SYMBOLCARE OFCADA UNAEULER CONSTANTSCRUPLEDEGREE FAHRENHEITSCRIPT " +
"SMALL GSCRIPT CAPITAL HBLACK-LETTER CAPITAL HDOUBLE-STRUCK CAPITAL HPLAN" +
"CK CONSTANTPLANCK CONSTANT OVER TWO PISCRIPT CAPITAL IBLACK-LETTER CAPIT" +
"AL ISCRIPT CAPITAL LSCRIPT SMALL LL B BAR SYMBOLDOUBLE-STRUCK CAPITAL NN" +
"UMERO SIGNSOUND RECORDING COPYRIGHTSCRIPT CAPITAL PDOUBLE-STRUCK CAPITAL" +
" PDOUBLE-STRUCK CAPITAL QSCRIPT CAPITAL RBLACK-LETTER CAPITAL RDOUBLE-ST" +
"RUCK CAPITAL RPRESCRIPTION TAKERESPONSESERVICE MARKTELEPHONE SIGNTRADE M" +
"ARK SIGNVERSICLEDOUBLE-STRUCK CAPITAL ZOUNCE SIGNOHM SIGNINVERTED OHM SI" +
"GNBLACK-LETTER CAPITAL ZTURNED GREEK SMALL LETTER IOTAKELVIN SIGNANGSTRO" +
"M SIGNSCRIPT CAPITAL BBLACK-LETTER CAPITAL CESTIMATED SYMBOLSCRIPT SMALL" +
" ESCRIPT CAPITAL ESCRIPT CAPITAL FTURNED CAPITAL FSCRIPT CAPITAL MSCRIPT" +
" SMALL OALEF SYMBOLBET SYMBOLGIMEL SYMBOLDALET SYMBOLINFORMATION SOURCER" +
"OTATED CAPITAL QFACSIMILE SIGNDOUBLE-STRUCK SMALL PIDOUBLE-STRUCK SMALL " +
"GAMMADOUBLE-STRUCK CAPITAL GAMMADOUBLE-STRUCK CAPITAL PIDOUBLE-STRUCK N-" +
"ARY SUMMATIONTURNED SANS-SERIF CAPITAL GTURNED SANS-SERIF CAPITAL LREVER" +
"SED SANS-SERIF CAPITAL LTURNED SANS-SERIF CAPITAL YDOUBLE-STRUCK ITALIC " +
"CAPITAL DDOUBLE-STRUCK ITALIC SMALL DDOUBLE-STRUCK ITALIC SMALL EDOUBLE-" +
"STRUCK ITALIC SMALL IDOUBLE-STRUCK ITALIC SMALL JPROPERTY LINETURNED AMP" +
"ERSANDPER SIGNAKTIESELSKABTURNED SMALL FSYMBOL FOR SAMARITAN SOURCEVULGA" +
"R FRACTION ONE SEVENTHVULGAR FRACTION ONE NINTHVULGAR FRACTION ONE TENTH" +
"VULGAR FRACTION ONE THIRDVULGAR FRACTION TWO THIRDSVULGAR FRACTION ONE F" +
"IFTHVULGAR FRACTION TWO FIFTHSVULGAR FRACTION THREE FIFTHSVULGAR FRACTIO" +
"N FOUR FIFTHSVULGAR FRACTION ONE SIXTHVULGAR FRACTION FIVE SIXTHSVULGAR " +
"FRACTION ONE EIGHTHVULGAR FRACTION THREE EIGHTHSVULGAR FRACTION FIVE EIG" +
"HTHSVULGAR FRACTION SEVEN EIGHTHSFRACTION NUMERATOR ONEROMAN NUMERAL ONE" +
"ROMAN NUMERAL TWOROMAN NUMERAL THREEROMAN NUMERAL FOURROMAN NUMERAL FIVE") + ("" +
"ROMAN NUMERAL SIXROMAN NUMERAL SEVENROMAN NUMERAL EIGHTROMAN NUMERAL NIN" +
"EROMAN NUMERAL TENROMAN NUMERAL ELEVENROMAN NUMERAL TWELVEROMAN NUMERAL " +
"FIFTYROMAN NUMERAL ONE HUNDREDROMAN NUMERAL FIVE HUNDREDROMAN NUMERAL ON" +
"E THOUSANDSMALL ROMAN NUMERAL ONESMALL ROMAN NUMERAL TWOSMALL ROMAN NUME" +
"RAL THREESMALL ROMAN NUMERAL FOURSMALL ROMAN NUMERAL FIVESMALL ROMAN NUM" +
"ERAL SIXSMALL ROMAN NUMERAL SEVENSMALL ROMAN NUMERAL EIGHTSMALL ROMAN NU" +
"MERAL NINESMALL ROMAN NUMERAL TENSMALL ROMAN NUMERAL ELEVENSMALL ROMAN N" +
"UMERAL TWELVESMALL ROMAN NUMERAL FIFTYSMALL ROMAN NUMERAL ONE HUNDREDSMA" +
"LL ROMAN NUMERAL FIVE HUNDREDSMALL ROMAN NUMERAL ONE THOUSANDROMAN NUMER" +
"AL ONE THOUSAND C DROMAN NUMERAL FIVE THOUSANDROMAN NUMERAL TEN THOUSAND" +
"ROMAN NUMERAL REVERSED ONE HUNDREDLATIN SMALL LETTER REVERSED CROMAN NUM" +
"ERAL SIX LATE FORMROMAN NUMERAL FIFTY EARLY FORMROMAN NUMERAL FIFTY THOU" +
"SANDROMAN NUMERAL ONE HUNDRED THOUSANDVULGAR FRACTION ZERO THIRDSTURNED " +
"DIGIT TWOTURNED DIGIT THREELEFTWARDS ARROWUPWARDS ARROWRIGHTWARDS ARROWD" +
"OWNWARDS ARROWLEFT RIGHT ARROWUP DOWN ARROWNORTH WEST ARROWNORTH EAST AR" +
"ROWSOUTH EAST ARROWSOUTH WEST ARROWLEFTWARDS ARROW WITH STROKERIGHTWARDS" +
" ARROW WITH STROKELEFTWARDS WAVE ARROWRIGHTWARDS WAVE ARROWLEFTWARDS TWO" +
" HEADED ARROWUPWARDS TWO HEADED ARROWRIGHTWARDS TWO HEADED ARROWDOWNWARD" +
"S TWO HEADED ARROWLEFTWARDS ARROW WITH TAILRIGHTWARDS ARROW WITH TAILLEF" +
"TWARDS ARROW FROM BARUPWARDS ARROW FROM BARRIGHTWARDS ARROW FROM BARDOWN" +
"WARDS ARROW FROM BARUP DOWN ARROW WITH BASELEFTWARDS ARROW WITH HOOKRIGH" +
"TWARDS ARROW WITH HOOKLEFTWARDS ARROW WITH LOOPRIGHTWARDS ARROW WITH LOO" +
"PLEFT RIGHT WAVE ARROWLEFT RIGHT ARROW WITH STROKEDOWNWARDS ZIGZAG ARROW" +
"UPWARDS ARROW WITH TIP LEFTWARDSUPWARDS ARROW WITH TIP RIGHTWARDSDOWNWAR" +
"DS ARROW WITH TIP LEFTWARDSDOWNWARDS ARROW WITH TIP RIGHTWARDSRIGHTWARDS" +
" ARROW WITH CORNER DOWNWARDSDOWNWARDS ARROW WITH CORNER LEFTWARDSANTICLO" +
"CKWISE TOP SEMICIRCLE ARROWCLOCKWISE TOP SEMICIRCLE ARROWNORTH WEST ARRO" +
"W TO LONG BARLEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BARANTICLOC" +
"KWISE OPEN CIRCLE ARROWCLOCKWISE OPEN CIRCLE ARROWLEFTWARDS HARPOON WITH" +
" BARB UPWARDSLEFTWARDS HARPOON WITH BARB DOWNWARDSUPWARDS HARPOON WITH B" +
"ARB RIGHTWARDSUPWARDS HARPOON WITH BARB LEFTWARDSRIGHTWARDS HARPOON WITH" +
" BARB UPWARDSRIGHTWARDS HARPOON WITH BARB DOWNWARDSDOWNWARDS HARPOON WIT" +
"H BARB RIGHTWARDSDOWNWARDS HARPOON WITH BARB LEFTWARDSRIGHTWARDS ARROW O" +
"VER LEFTWARDS ARROWUPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROWLEFTWARDS A" +
"RROW OVER RIGHTWARDS ARROWLEFTWARDS PAIRED ARROWSUPWARDS PAIRED ARROWSRI" +
"GHTWARDS PAIRED ARROWSDOWNWARDS PAIRED ARROWSLEFTWARDS HARPOON OVER RIGH" +
"TWARDS HARPOONRIGHTWARDS HARPOON OVER LEFTWARDS HARPOONLEFTWARDS DOUBLE " +
"ARROW WITH STROKELEFT RIGHT DOUBLE ARROW WITH STROKERIGHTWARDS DOUBLE AR" +
"ROW WITH STROKELEFTWARDS DOUBLE ARROWUPWARDS DOUBLE ARROWRIGHTWARDS DOUB" +
"LE ARROWDOWNWARDS DOUBLE ARROWLEFT RIGHT DOUBLE ARROWUP DOWN DOUBLE ARRO" +
"WNORTH WEST DOUBLE ARROWNORTH EAST DOUBLE ARROWSOUTH EAST DOUBLE ARROWSO" +
"UTH WEST DOUBLE ARROWLEFTWARDS TRIPLE ARROWRIGHTWARDS TRIPLE ARROWLEFTWA" +
"RDS SQUIGGLE ARROWRIGHTWARDS SQUIGGLE ARROWUPWARDS ARROW WITH DOUBLE STR" +
"OKEDOWNWARDS ARROW WITH DOUBLE STROKELEFTWARDS DASHED ARROWUPWARDS DASHE" +
"D ARROWRIGHTWARDS DASHED ARROWDOWNWARDS DASHED ARROWLEFTWARDS ARROW TO B" +
"ARRIGHTWARDS ARROW TO BARLEFTWARDS WHITE ARROWUPWARDS WHITE ARROWRIGHTWA" +
"RDS WHITE ARROWDOWNWARDS WHITE ARROWUPWARDS WHITE ARROW FROM BARUPWARDS " +
"WHITE ARROW ON PEDESTALUPWARDS WHITE ARROW ON PEDESTAL WITH HORIZONTAL B" +
"ARUPWARDS WHITE ARROW ON PEDESTAL WITH VERTICAL BARUPWARDS WHITE DOUBLE " +
"ARROWUPWARDS WHITE DOUBLE ARROW ON PEDESTALRIGHTWARDS WHITE ARROW FROM W" +
"ALLNORTH WEST ARROW TO CORNERSOUTH EAST ARROW TO CORNERUP DOWN WHITE ARR" +
"OWRIGHT ARROW WITH SMALL CIRCLEDOWNWARDS ARROW LEFTWARDS OF UPWARDS ARRO" +
"WTHREE RIGHTWARDS ARROWSLEFTWARDS ARROW WITH VERTICAL STROKERIGHTWARDS A" +
"RROW WITH VERTICAL STROKELEFT RIGHT ARROW WITH VERTICAL STROKELEFTWARDS " +
"ARROW WITH DOUBLE VERTICAL STROKERIGHTWARDS ARROW WITH DOUBLE VERTICAL S" +
"TROKELEFT RIGHT ARROW WITH DOUBLE VERTICAL STROKELEFTWARDS OPEN-HEADED A" +
"RROWRIGHTWARDS OPEN-HEADED ARROWLEFT RIGHT OPEN-HEADED ARROWFOR ALLCOMPL" +
"EMENTPARTIAL DIFFERENTIALTHERE EXISTSTHERE DOES NOT EXISTEMPTY SETINCREM" +
"ENTNABLAELEMENT OFNOT AN ELEMENT OFSMALL ELEMENT OFCONTAINS AS MEMBERDOE" +
"S NOT CONTAIN AS MEMBERSMALL CONTAINS AS MEMBEREND OF PROOFN-ARY PRODUCT" +
"N-ARY COPRODUCTN-ARY SUMMATIONMINUS SIGNMINUS-OR-PLUS SIGNDOT PLUSDIVISI" +
"ON SLASHSET MINUSASTERISK OPERATORRING OPERATORBULLET OPERATORSQUARE ROO" +
"TCUBE ROOTFOURTH ROOTPROPORTIONAL TOINFINITYRIGHT ANGLEANGLEMEASURED ANG" +
"LESPHERICAL ANGLEDIVIDESDOES NOT DIVIDEPARALLEL TONOT PARALLEL TOLOGICAL") + ("" +
" ANDLOGICAL ORINTERSECTIONUNIONINTEGRALDOUBLE INTEGRALTRIPLE INTEGRALCON" +
"TOUR INTEGRALSURFACE INTEGRALVOLUME INTEGRALCLOCKWISE INTEGRALCLOCKWISE " +
"CONTOUR INTEGRALANTICLOCKWISE CONTOUR INTEGRALTHEREFOREBECAUSERATIOPROPO" +
"RTIONDOT MINUSEXCESSGEOMETRIC PROPORTIONHOMOTHETICTILDE OPERATORREVERSED" +
" TILDEINVERTED LAZY SSINE WAVEWREATH PRODUCTNOT TILDEMINUS TILDEASYMPTOT" +
"ICALLY EQUAL TONOT ASYMPTOTICALLY EQUAL TOAPPROXIMATELY EQUAL TOAPPROXIM" +
"ATELY BUT NOT ACTUALLY EQUAL TONEITHER APPROXIMATELY NOR ACTUALLY EQUAL " +
"TOALMOST EQUAL TONOT ALMOST EQUAL TOALMOST EQUAL OR EQUAL TOTRIPLE TILDE" +
"ALL EQUAL TOEQUIVALENT TOGEOMETRICALLY EQUIVALENT TODIFFERENCE BETWEENAP" +
"PROACHES THE LIMITGEOMETRICALLY EQUAL TOAPPROXIMATELY EQUAL TO OR THE IM" +
"AGE OFIMAGE OF OR APPROXIMATELY EQUAL TOCOLON EQUALSEQUALS COLONRING IN " +
"EQUAL TORING EQUAL TOCORRESPONDS TOESTIMATESEQUIANGULAR TOSTAR EQUALSDEL" +
"TA EQUAL TOEQUAL TO BY DEFINITIONMEASURED BYQUESTIONED EQUAL TONOT EQUAL" +
" TOIDENTICAL TONOT IDENTICAL TOSTRICTLY EQUIVALENT TOLESS-THAN OR EQUAL " +
"TOGREATER-THAN OR EQUAL TOLESS-THAN OVER EQUAL TOGREATER-THAN OVER EQUAL" +
" TOLESS-THAN BUT NOT EQUAL TOGREATER-THAN BUT NOT EQUAL TOMUCH LESS-THAN" +
"MUCH GREATER-THANBETWEENNOT EQUIVALENT TONOT LESS-THANNOT GREATER-THANNE" +
"ITHER LESS-THAN NOR EQUAL TONEITHER GREATER-THAN NOR EQUAL TOLESS-THAN O" +
"R EQUIVALENT TOGREATER-THAN OR EQUIVALENT TONEITHER LESS-THAN NOR EQUIVA" +
"LENT TONEITHER GREATER-THAN NOR EQUIVALENT TOLESS-THAN OR GREATER-THANGR" +
"EATER-THAN OR LESS-THANNEITHER LESS-THAN NOR GREATER-THANNEITHER GREATER" +
"-THAN NOR LESS-THANPRECEDESSUCCEEDSPRECEDES OR EQUAL TOSUCCEEDS OR EQUAL" +
" TOPRECEDES OR EQUIVALENT TOSUCCEEDS OR EQUIVALENT TODOES NOT PRECEDEDOE" +
"S NOT SUCCEEDSUBSET OFSUPERSET OFNOT A SUBSET OFNOT A SUPERSET OFSUBSET " +
"OF OR EQUAL TOSUPERSET OF OR EQUAL TONEITHER A SUBSET OF NOR EQUAL TONEI" +
"THER A SUPERSET OF NOR EQUAL TOSUBSET OF WITH NOT EQUAL TOSUPERSET OF WI" +
"TH NOT EQUAL TOMULTISETMULTISET MULTIPLICATIONMULTISET UNIONSQUARE IMAGE" +
" OFSQUARE ORIGINAL OFSQUARE IMAGE OF OR EQUAL TOSQUARE ORIGINAL OF OR EQ" +
"UAL TOSQUARE CAPSQUARE CUPCIRCLED PLUSCIRCLED MINUSCIRCLED TIMESCIRCLED " +
"DIVISION SLASHCIRCLED DOT OPERATORCIRCLED RING OPERATORCIRCLED ASTERISK " +
"OPERATORCIRCLED EQUALSCIRCLED DASHSQUARED PLUSSQUARED MINUSSQUARED TIMES" +
"SQUARED DOT OPERATORRIGHT TACKLEFT TACKDOWN TACKUP TACKASSERTIONMODELSTR" +
"UEFORCESTRIPLE VERTICAL BAR RIGHT TURNSTILEDOUBLE VERTICAL BAR DOUBLE RI" +
"GHT TURNSTILEDOES NOT PROVENOT TRUEDOES NOT FORCENEGATED DOUBLE VERTICAL" +
" BAR DOUBLE RIGHT TURNSTILEPRECEDES UNDER RELATIONSUCCEEDS UNDER RELATIO" +
"NNORMAL SUBGROUP OFCONTAINS AS NORMAL SUBGROUPNORMAL SUBGROUP OF OR EQUA" +
"L TOCONTAINS AS NORMAL SUBGROUP OR EQUAL TOORIGINAL OFIMAGE OFMULTIMAPHE" +
"RMITIAN CONJUGATE MATRIXINTERCALATEXORNANDNORRIGHT ANGLE WITH ARCRIGHT T" +
"RIANGLEN-ARY LOGICAL ANDN-ARY LOGICAL ORN-ARY INTERSECTIONN-ARY UNIONDIA" +
"MOND OPERATORDOT OPERATORSTAR OPERATORDIVISION TIMESBOWTIELEFT NORMAL FA" +
"CTOR SEMIDIRECT PRODUCTRIGHT NORMAL FACTOR SEMIDIRECT PRODUCTLEFT SEMIDI" +
"RECT PRODUCTRIGHT SEMIDIRECT PRODUCTREVERSED TILDE EQUALSCURLY LOGICAL O" +
"RCURLY LOGICAL ANDDOUBLE SUBSETDOUBLE SUPERSETDOUBLE INTERSECTIONDOUBLE " +
"UNIONPITCHFORKEQUAL AND PARALLEL TOLESS-THAN WITH DOTGREATER-THAN WITH D" +
"OTVERY MUCH LESS-THANVERY MUCH GREATER-THANLESS-THAN EQUAL TO OR GREATER" +
"-THANGREATER-THAN EQUAL TO OR LESS-THANEQUAL TO OR LESS-THANEQUAL TO OR " +
"GREATER-THANEQUAL TO OR PRECEDESEQUAL TO OR SUCCEEDSDOES NOT PRECEDE OR " +
"EQUALDOES NOT SUCCEED OR EQUALNOT SQUARE IMAGE OF OR EQUAL TONOT SQUARE " +
"ORIGINAL OF OR EQUAL TOSQUARE IMAGE OF OR NOT EQUAL TOSQUARE ORIGINAL OF" +
" OR NOT EQUAL TOLESS-THAN BUT NOT EQUIVALENT TOGREATER-THAN BUT NOT EQUI" +
"VALENT TOPRECEDES BUT NOT EQUIVALENT TOSUCCEEDS BUT NOT EQUIVALENT TONOT" +
" NORMAL SUBGROUP OFDOES NOT CONTAIN AS NORMAL SUBGROUPNOT NORMAL SUBGROU" +
"P OF OR EQUAL TODOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUALVERTICAL ELL" +
"IPSISMIDLINE HORIZONTAL ELLIPSISUP RIGHT DIAGONAL ELLIPSISDOWN RIGHT DIA" +
"GONAL ELLIPSISELEMENT OF WITH LONG HORIZONTAL STROKEELEMENT OF WITH VERT" +
"ICAL BAR AT END OF HORIZONTAL STROKESMALL ELEMENT OF WITH VERTICAL BAR A" +
"T END OF HORIZONTAL STROKEELEMENT OF WITH DOT ABOVEELEMENT OF WITH OVERB" +
"ARSMALL ELEMENT OF WITH OVERBARELEMENT OF WITH UNDERBARELEMENT OF WITH T" +
"WO HORIZONTAL STROKESCONTAINS WITH LONG HORIZONTAL STROKECONTAINS WITH V" +
"ERTICAL BAR AT END OF HORIZONTAL STROKESMALL CONTAINS WITH VERTICAL BAR " +
"AT END OF HORIZONTAL STROKECONTAINS WITH OVERBARSMALL CONTAINS WITH OVER" +
"BARZ NOTATION BAG MEMBERSHIPDIAMETER SIGNELECTRIC ARROWHOUSEUP ARROWHEAD" +
"DOWN ARROWHEADPROJECTIVEPERSPECTIVEWAVY LINELEFT CEILINGRIGHT CEILINGLEF" +
"T FLOORRIGHT FLOORBOTTOM RIGHT CROPBOTTOM LEFT CROPTOP RIGHT CROPTOP LEF") + ("" +
"T CROPREVERSED NOT SIGNSQUARE LOZENGEARCSEGMENTSECTORTELEPHONE RECORDERP" +
"OSITION INDICATORVIEWDATA SQUAREPLACE OF INTEREST SIGNTURNED NOT SIGNWAT" +
"CHHOURGLASSTOP LEFT CORNERTOP RIGHT CORNERBOTTOM LEFT CORNERBOTTOM RIGHT" +
" CORNERTOP HALF INTEGRALBOTTOM HALF INTEGRALFROWNSMILEUP ARROWHEAD BETWE" +
"EN TWO HORIZONTAL BARSOPTION KEYERASE TO THE RIGHTX IN A RECTANGLE BOXKE" +
"YBOARDLEFT-POINTING ANGLE BRACKETRIGHT-POINTING ANGLE BRACKETERASE TO TH" +
"E LEFTBENZENE RINGCYLINDRICITYALL AROUND-PROFILESYMMETRYTOTAL RUNOUTDIME" +
"NSION ORIGINCONICAL TAPERSLOPECOUNTERBORECOUNTERSINKAPL FUNCTIONAL SYMBO" +
"L I-BEAMAPL FUNCTIONAL SYMBOL SQUISH QUADAPL FUNCTIONAL SYMBOL QUAD EQUA" +
"LAPL FUNCTIONAL SYMBOL QUAD DIVIDEAPL FUNCTIONAL SYMBOL QUAD DIAMONDAPL " +
"FUNCTIONAL SYMBOL QUAD JOTAPL FUNCTIONAL SYMBOL QUAD CIRCLEAPL FUNCTIONA" +
"L SYMBOL CIRCLE STILEAPL FUNCTIONAL SYMBOL CIRCLE JOTAPL FUNCTIONAL SYMB" +
"OL SLASH BARAPL FUNCTIONAL SYMBOL BACKSLASH BARAPL FUNCTIONAL SYMBOL QUA" +
"D SLASHAPL FUNCTIONAL SYMBOL QUAD BACKSLASHAPL FUNCTIONAL SYMBOL QUAD LE" +
"SS-THANAPL FUNCTIONAL SYMBOL QUAD GREATER-THANAPL FUNCTIONAL SYMBOL LEFT" +
"WARDS VANEAPL FUNCTIONAL SYMBOL RIGHTWARDS VANEAPL FUNCTIONAL SYMBOL QUA" +
"D LEFTWARDS ARROWAPL FUNCTIONAL SYMBOL QUAD RIGHTWARDS ARROWAPL FUNCTION" +
"AL SYMBOL CIRCLE BACKSLASHAPL FUNCTIONAL SYMBOL DOWN TACK UNDERBARAPL FU" +
"NCTIONAL SYMBOL DELTA STILEAPL FUNCTIONAL SYMBOL QUAD DOWN CARETAPL FUNC" +
"TIONAL SYMBOL QUAD DELTAAPL FUNCTIONAL SYMBOL DOWN TACK JOTAPL FUNCTIONA" +
"L SYMBOL UPWARDS VANEAPL FUNCTIONAL SYMBOL QUAD UPWARDS ARROWAPL FUNCTIO" +
"NAL SYMBOL UP TACK OVERBARAPL FUNCTIONAL SYMBOL DEL STILEAPL FUNCTIONAL " +
"SYMBOL QUAD UP CARETAPL FUNCTIONAL SYMBOL QUAD DELAPL FUNCTIONAL SYMBOL " +
"UP TACK JOTAPL FUNCTIONAL SYMBOL DOWNWARDS VANEAPL FUNCTIONAL SYMBOL QUA" +
"D DOWNWARDS ARROWAPL FUNCTIONAL SYMBOL QUOTE UNDERBARAPL FUNCTIONAL SYMB" +
"OL DELTA UNDERBARAPL FUNCTIONAL SYMBOL DIAMOND UNDERBARAPL FUNCTIONAL SY" +
"MBOL JOT UNDERBARAPL FUNCTIONAL SYMBOL CIRCLE UNDERBARAPL FUNCTIONAL SYM" +
"BOL UP SHOE JOTAPL FUNCTIONAL SYMBOL QUOTE QUADAPL FUNCTIONAL SYMBOL CIR" +
"CLE STARAPL FUNCTIONAL SYMBOL QUAD COLONAPL FUNCTIONAL SYMBOL UP TACK DI" +
"AERESISAPL FUNCTIONAL SYMBOL DEL DIAERESISAPL FUNCTIONAL SYMBOL STAR DIA" +
"ERESISAPL FUNCTIONAL SYMBOL JOT DIAERESISAPL FUNCTIONAL SYMBOL CIRCLE DI" +
"AERESISAPL FUNCTIONAL SYMBOL DOWN SHOE STILEAPL FUNCTIONAL SYMBOL LEFT S" +
"HOE STILEAPL FUNCTIONAL SYMBOL TILDE DIAERESISAPL FUNCTIONAL SYMBOL GREA" +
"TER-THAN DIAERESISAPL FUNCTIONAL SYMBOL COMMA BARAPL FUNCTIONAL SYMBOL D" +
"EL TILDEAPL FUNCTIONAL SYMBOL ZILDEAPL FUNCTIONAL SYMBOL STILE TILDEAPL " +
"FUNCTIONAL SYMBOL SEMICOLON UNDERBARAPL FUNCTIONAL SYMBOL QUAD NOT EQUAL" +
"APL FUNCTIONAL SYMBOL QUAD QUESTIONAPL FUNCTIONAL SYMBOL DOWN CARET TILD" +
"EAPL FUNCTIONAL SYMBOL UP CARET TILDEAPL FUNCTIONAL SYMBOL IOTAAPL FUNCT" +
"IONAL SYMBOL RHOAPL FUNCTIONAL SYMBOL OMEGAAPL FUNCTIONAL SYMBOL ALPHA U" +
"NDERBARAPL FUNCTIONAL SYMBOL EPSILON UNDERBARAPL FUNCTIONAL SYMBOL IOTA " +
"UNDERBARAPL FUNCTIONAL SYMBOL OMEGA UNDERBARAPL FUNCTIONAL SYMBOL ALPHAN" +
"OT CHECK MARKRIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROWSHOULDERED OPEN BOXB" +
"ELL SYMBOLVERTICAL LINE WITH MIDDLE DOTINSERTION SYMBOLCONTINUOUS UNDERL" +
"INE SYMBOLDISCONTINUOUS UNDERLINE SYMBOLEMPHASIS SYMBOLCOMPOSITION SYMBO" +
"LWHITE SQUARE WITH CENTRE VERTICAL LINEENTER SYMBOLALTERNATIVE KEY SYMBO" +
"LHELM SYMBOLCIRCLED HORIZONTAL BAR WITH NOTCHCIRCLED TRIANGLE DOWNBROKEN" +
" CIRCLE WITH NORTHWEST ARROWUNDO SYMBOLMONOSTABLE SYMBOLHYSTERESIS SYMBO" +
"LOPEN-CIRCUIT-OUTPUT H-TYPE SYMBOLOPEN-CIRCUIT-OUTPUT L-TYPE SYMBOLPASSI" +
"VE-PULL-DOWN-OUTPUT SYMBOLPASSIVE-PULL-UP-OUTPUT SYMBOLDIRECT CURRENT SY" +
"MBOL FORM TWOSOFTWARE-FUNCTION SYMBOLAPL FUNCTIONAL SYMBOL QUADDECIMAL S" +
"EPARATOR KEY SYMBOLPREVIOUS PAGENEXT PAGEPRINT SCREEN SYMBOLCLEAR SCREEN" +
" SYMBOLLEFT PARENTHESIS UPPER HOOKLEFT PARENTHESIS EXTENSIONLEFT PARENTH" +
"ESIS LOWER HOOKRIGHT PARENTHESIS UPPER HOOKRIGHT PARENTHESIS EXTENSIONRI" +
"GHT PARENTHESIS LOWER HOOKLEFT SQUARE BRACKET UPPER CORNERLEFT SQUARE BR" +
"ACKET EXTENSIONLEFT SQUARE BRACKET LOWER CORNERRIGHT SQUARE BRACKET UPPE" +
"R CORNERRIGHT SQUARE BRACKET EXTENSIONRIGHT SQUARE BRACKET LOWER CORNERL" +
"EFT CURLY BRACKET UPPER HOOKLEFT CURLY BRACKET MIDDLE PIECELEFT CURLY BR" +
"ACKET LOWER HOOKCURLY BRACKET EXTENSIONRIGHT CURLY BRACKET UPPER HOOKRIG" +
"HT CURLY BRACKET MIDDLE PIECERIGHT CURLY BRACKET LOWER HOOKINTEGRAL EXTE" +
"NSIONHORIZONTAL LINE EXTENSIONUPPER LEFT OR LOWER RIGHT CURLY BRACKET SE" +
"CTIONUPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTIONSUMMATION TOPSUMMATI" +
"ON BOTTOMTOP SQUARE BRACKETBOTTOM SQUARE BRACKETBOTTOM SQUARE BRACKET OV" +
"ER TOP SQUARE BRACKETRADICAL SYMBOL BOTTOMLEFT VERTICAL BOX LINERIGHT VE" +
"RTICAL BOX LINEHORIZONTAL SCAN LINE-1HORIZONTAL SCAN LINE-3HORIZONTAL SC") + ("" +
"AN LINE-7HORIZONTAL SCAN LINE-9DENTISTRY SYMBOL LIGHT VERTICAL AND TOP R" +
"IGHTDENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHTDENTISTRY SYMBOL LIG" +
"HT VERTICAL WITH CIRCLEDENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH C" +
"IRCLEDENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLEDENTISTRY SYMBO" +
"L LIGHT VERTICAL WITH TRIANGLEDENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL" +
" WITH TRIANGLEDENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLEDENT" +
"ISTRY SYMBOL LIGHT VERTICAL AND WAVEDENTISTRY SYMBOL LIGHT DOWN AND HORI" +
"ZONTAL WITH WAVEDENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVEDENTIS" +
"TRY SYMBOL LIGHT DOWN AND HORIZONTALDENTISTRY SYMBOL LIGHT UP AND HORIZO" +
"NTALDENTISTRY SYMBOL LIGHT VERTICAL AND TOP LEFTDENTISTRY SYMBOL LIGHT V" +
"ERTICAL AND BOTTOM LEFTSQUARE FOOTRETURN SYMBOLEJECT SYMBOLVERTICAL LINE" +
" EXTENSIONMETRICAL BREVEMETRICAL LONG OVER SHORTMETRICAL SHORT OVER LONG" +
"METRICAL LONG OVER TWO SHORTSMETRICAL TWO SHORTS OVER LONGMETRICAL TWO S" +
"HORTS JOINEDMETRICAL TRISEMEMETRICAL TETRASEMEMETRICAL PENTASEMEEARTH GR" +
"OUNDFUSETOP PARENTHESISBOTTOM PARENTHESISTOP CURLY BRACKETBOTTOM CURLY B" +
"RACKETTOP TORTOISE SHELL BRACKETBOTTOM TORTOISE SHELL BRACKETWHITE TRAPE" +
"ZIUMBENZENE RING WITH CIRCLESTRAIGHTNESSFLATNESSAC CURRENTELECTRICAL INT" +
"ERSECTIONDECIMAL EXPONENT SYMBOLBLACK RIGHT-POINTING DOUBLE TRIANGLEBLAC" +
"K LEFT-POINTING DOUBLE TRIANGLEBLACK UP-POINTING DOUBLE TRIANGLEBLACK DO" +
"WN-POINTING DOUBLE TRIANGLEBLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VER" +
"TICAL BARBLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BARBLACK RIGH" +
"T-POINTING TRIANGLE WITH DOUBLE VERTICAL BARALARM CLOCKSTOPWATCHTIMER CL" +
"OCKHOURGLASS WITH FLOWING SANDBLACK MEDIUM LEFT-POINTING TRIANGLEBLACK M" +
"EDIUM RIGHT-POINTING TRIANGLEBLACK MEDIUM UP-POINTING TRIANGLEBLACK MEDI" +
"UM DOWN-POINTING TRIANGLEDOUBLE VERTICAL BARBLACK SQUARE FOR STOPBLACK C" +
"IRCLE FOR RECORDPOWER SYMBOLPOWER ON-OFF SYMBOLPOWER ON SYMBOLPOWER SLEE" +
"P SYMBOLOBSERVER EYE SYMBOLSYMBOL FOR NULLSYMBOL FOR START OF HEADINGSYM" +
"BOL FOR START OF TEXTSYMBOL FOR END OF TEXTSYMBOL FOR END OF TRANSMISSIO" +
"NSYMBOL FOR ENQUIRYSYMBOL FOR ACKNOWLEDGESYMBOL FOR BELLSYMBOL FOR BACKS" +
"PACESYMBOL FOR HORIZONTAL TABULATIONSYMBOL FOR LINE FEEDSYMBOL FOR VERTI" +
"CAL TABULATIONSYMBOL FOR FORM FEEDSYMBOL FOR CARRIAGE RETURNSYMBOL FOR S" +
"HIFT OUTSYMBOL FOR SHIFT INSYMBOL FOR DATA LINK ESCAPESYMBOL FOR DEVICE " +
"CONTROL ONESYMBOL FOR DEVICE CONTROL TWOSYMBOL FOR DEVICE CONTROL THREES" +
"YMBOL FOR DEVICE CONTROL FOURSYMBOL FOR NEGATIVE ACKNOWLEDGESYMBOL FOR S" +
"YNCHRONOUS IDLESYMBOL FOR END OF TRANSMISSION BLOCKSYMBOL FOR CANCELSYMB" +
"OL FOR END OF MEDIUMSYMBOL FOR SUBSTITUTESYMBOL FOR ESCAPESYMBOL FOR FIL" +
"E SEPARATORSYMBOL FOR GROUP SEPARATORSYMBOL FOR RECORD SEPARATORSYMBOL F" +
"OR UNIT SEPARATORSYMBOL FOR SPACESYMBOL FOR DELETEBLANK SYMBOLOPEN BOXSY" +
"MBOL FOR NEWLINESYMBOL FOR DELETE FORM TWOSYMBOL FOR SUBSTITUTE FORM TWO" +
"OCR HOOKOCR CHAIROCR FORKOCR INVERTED FORKOCR BELT BUCKLEOCR BOW TIEOCR " +
"BRANCH BANK IDENTIFICATIONOCR AMOUNT OF CHECKOCR DASHOCR CUSTOMER ACCOUN" +
"T NUMBEROCR DOUBLE BACKSLASHCIRCLED DIGIT ONECIRCLED DIGIT TWOCIRCLED DI" +
"GIT THREECIRCLED DIGIT FOURCIRCLED DIGIT FIVECIRCLED DIGIT SIXCIRCLED DI" +
"GIT SEVENCIRCLED DIGIT EIGHTCIRCLED DIGIT NINECIRCLED NUMBER TENCIRCLED " +
"NUMBER ELEVENCIRCLED NUMBER TWELVECIRCLED NUMBER THIRTEENCIRCLED NUMBER " +
"FOURTEENCIRCLED NUMBER FIFTEENCIRCLED NUMBER SIXTEENCIRCLED NUMBER SEVEN" +
"TEENCIRCLED NUMBER EIGHTEENCIRCLED NUMBER NINETEENCIRCLED NUMBER TWENTYP" +
"ARENTHESIZED DIGIT ONEPARENTHESIZED DIGIT TWOPARENTHESIZED DIGIT THREEPA" +
"RENTHESIZED DIGIT FOURPARENTHESIZED DIGIT FIVEPARENTHESIZED DIGIT SIXPAR" +
"ENTHESIZED DIGIT SEVENPARENTHESIZED DIGIT EIGHTPARENTHESIZED DIGIT NINEP" +
"ARENTHESIZED NUMBER TENPARENTHESIZED NUMBER ELEVENPARENTHESIZED NUMBER T" +
"WELVEPARENTHESIZED NUMBER THIRTEENPARENTHESIZED NUMBER FOURTEENPARENTHES" +
"IZED NUMBER FIFTEENPARENTHESIZED NUMBER SIXTEENPARENTHESIZED NUMBER SEVE" +
"NTEENPARENTHESIZED NUMBER EIGHTEENPARENTHESIZED NUMBER NINETEENPARENTHES" +
"IZED NUMBER TWENTYDIGIT ONE FULL STOPDIGIT TWO FULL STOPDIGIT THREE FULL" +
" STOPDIGIT FOUR FULL STOPDIGIT FIVE FULL STOPDIGIT SIX FULL STOPDIGIT SE" +
"VEN FULL STOPDIGIT EIGHT FULL STOPDIGIT NINE FULL STOPNUMBER TEN FULL ST" +
"OPNUMBER ELEVEN FULL STOPNUMBER TWELVE FULL STOPNUMBER THIRTEEN FULL STO" +
"PNUMBER FOURTEEN FULL STOPNUMBER FIFTEEN FULL STOPNUMBER SIXTEEN FULL ST" +
"OPNUMBER SEVENTEEN FULL STOPNUMBER EIGHTEEN FULL STOPNUMBER NINETEEN FUL" +
"L STOPNUMBER TWENTY FULL STOPPARENTHESIZED LATIN SMALL LETTER APARENTHES" +
"IZED LATIN SMALL LETTER BPARENTHESIZED LATIN SMALL LETTER CPARENTHESIZED" +
" LATIN SMALL LETTER DPARENTHESIZED LATIN SMALL LETTER EPARENTHESIZED LAT" +
"IN SMALL LETTER FPARENTHESIZED LATIN SMALL LETTER GPARENTHESIZED LATIN S") + ("" +
"MALL LETTER HPARENTHESIZED LATIN SMALL LETTER IPARENTHESIZED LATIN SMALL" +
" LETTER JPARENTHESIZED LATIN SMALL LETTER KPARENTHESIZED LATIN SMALL LET" +
"TER LPARENTHESIZED LATIN SMALL LETTER MPARENTHESIZED LATIN SMALL LETTER " +
"NPARENTHESIZED LATIN SMALL LETTER OPARENTHESIZED LATIN SMALL LETTER PPAR" +
"ENTHESIZED LATIN SMALL LETTER QPARENTHESIZED LATIN SMALL LETTER RPARENTH" +
"ESIZED LATIN SMALL LETTER SPARENTHESIZED LATIN SMALL LETTER TPARENTHESIZ" +
"ED LATIN SMALL LETTER UPARENTHESIZED LATIN SMALL LETTER VPARENTHESIZED L" +
"ATIN SMALL LETTER WPARENTHESIZED LATIN SMALL LETTER XPARENTHESIZED LATIN" +
" SMALL LETTER YPARENTHESIZED LATIN SMALL LETTER ZCIRCLED LATIN CAPITAL L" +
"ETTER ACIRCLED LATIN CAPITAL LETTER BCIRCLED LATIN CAPITAL LETTER CCIRCL" +
"ED LATIN CAPITAL LETTER DCIRCLED LATIN CAPITAL LETTER ECIRCLED LATIN CAP" +
"ITAL LETTER FCIRCLED LATIN CAPITAL LETTER GCIRCLED LATIN CAPITAL LETTER " +
"HCIRCLED LATIN CAPITAL LETTER ICIRCLED LATIN CAPITAL LETTER JCIRCLED LAT" +
"IN CAPITAL LETTER KCIRCLED LATIN CAPITAL LETTER LCIRCLED LATIN CAPITAL L" +
"ETTER MCIRCLED LATIN CAPITAL LETTER NCIRCLED LATIN CAPITAL LETTER OCIRCL" +
"ED LATIN CAPITAL LETTER PCIRCLED LATIN CAPITAL LETTER QCIRCLED LATIN CAP" +
"ITAL LETTER RCIRCLED LATIN CAPITAL LETTER SCIRCLED LATIN CAPITAL LETTER " +
"TCIRCLED LATIN CAPITAL LETTER UCIRCLED LATIN CAPITAL LETTER VCIRCLED LAT" +
"IN CAPITAL LETTER WCIRCLED LATIN CAPITAL LETTER XCIRCLED LATIN CAPITAL L" +
"ETTER YCIRCLED LATIN CAPITAL LETTER ZCIRCLED LATIN SMALL LETTER ACIRCLED" +
" LATIN SMALL LETTER BCIRCLED LATIN SMALL LETTER CCIRCLED LATIN SMALL LET" +
"TER DCIRCLED LATIN SMALL LETTER ECIRCLED LATIN SMALL LETTER FCIRCLED LAT" +
"IN SMALL LETTER GCIRCLED LATIN SMALL LETTER HCIRCLED LATIN SMALL LETTER " +
"ICIRCLED LATIN SMALL LETTER JCIRCLED LATIN SMALL LETTER KCIRCLED LATIN S" +
"MALL LETTER LCIRCLED LATIN SMALL LETTER MCIRCLED LATIN SMALL LETTER NCIR" +
"CLED LATIN SMALL LETTER OCIRCLED LATIN SMALL LETTER PCIRCLED LATIN SMALL" +
" LETTER QCIRCLED LATIN SMALL LETTER RCIRCLED LATIN SMALL LETTER SCIRCLED" +
" LATIN SMALL LETTER TCIRCLED LATIN SMALL LETTER UCIRCLED LATIN SMALL LET" +
"TER VCIRCLED LATIN SMALL LETTER WCIRCLED LATIN SMALL LETTER XCIRCLED LAT" +
"IN SMALL LETTER YCIRCLED LATIN SMALL LETTER ZCIRCLED DIGIT ZERONEGATIVE " +
"CIRCLED NUMBER ELEVENNEGATIVE CIRCLED NUMBER TWELVENEGATIVE CIRCLED NUMB" +
"ER THIRTEENNEGATIVE CIRCLED NUMBER FOURTEENNEGATIVE CIRCLED NUMBER FIFTE" +
"ENNEGATIVE CIRCLED NUMBER SIXTEENNEGATIVE CIRCLED NUMBER SEVENTEENNEGATI" +
"VE CIRCLED NUMBER EIGHTEENNEGATIVE CIRCLED NUMBER NINETEENNEGATIVE CIRCL" +
"ED NUMBER TWENTYDOUBLE CIRCLED DIGIT ONEDOUBLE CIRCLED DIGIT TWODOUBLE C" +
"IRCLED DIGIT THREEDOUBLE CIRCLED DIGIT FOURDOUBLE CIRCLED DIGIT FIVEDOUB" +
"LE CIRCLED DIGIT SIXDOUBLE CIRCLED DIGIT SEVENDOUBLE CIRCLED DIGIT EIGHT" +
"DOUBLE CIRCLED DIGIT NINEDOUBLE CIRCLED NUMBER TENNEGATIVE CIRCLED DIGIT" +
" ZEROBOX DRAWINGS LIGHT HORIZONTALBOX DRAWINGS HEAVY HORIZONTALBOX DRAWI" +
"NGS LIGHT VERTICALBOX DRAWINGS HEAVY VERTICALBOX DRAWINGS LIGHT TRIPLE D" +
"ASH HORIZONTALBOX DRAWINGS HEAVY TRIPLE DASH HORIZONTALBOX DRAWINGS LIGH" +
"T TRIPLE DASH VERTICALBOX DRAWINGS HEAVY TRIPLE DASH VERTICALBOX DRAWING" +
"S LIGHT QUADRUPLE DASH HORIZONTALBOX DRAWINGS HEAVY QUADRUPLE DASH HORIZ" +
"ONTALBOX DRAWINGS LIGHT QUADRUPLE DASH VERTICALBOX DRAWINGS HEAVY QUADRU" +
"PLE DASH VERTICALBOX DRAWINGS LIGHT DOWN AND RIGHTBOX DRAWINGS DOWN LIGH" +
"T AND RIGHT HEAVYBOX DRAWINGS DOWN HEAVY AND RIGHT LIGHTBOX DRAWINGS HEA" +
"VY DOWN AND RIGHTBOX DRAWINGS LIGHT DOWN AND LEFTBOX DRAWINGS DOWN LIGHT" +
" AND LEFT HEAVYBOX DRAWINGS DOWN HEAVY AND LEFT LIGHTBOX DRAWINGS HEAVY " +
"DOWN AND LEFTBOX DRAWINGS LIGHT UP AND RIGHTBOX DRAWINGS UP LIGHT AND RI" +
"GHT HEAVYBOX DRAWINGS UP HEAVY AND RIGHT LIGHTBOX DRAWINGS HEAVY UP AND " +
"RIGHTBOX DRAWINGS LIGHT UP AND LEFTBOX DRAWINGS UP LIGHT AND LEFT HEAVYB" +
"OX DRAWINGS UP HEAVY AND LEFT LIGHTBOX DRAWINGS HEAVY UP AND LEFTBOX DRA" +
"WINGS LIGHT VERTICAL AND RIGHTBOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAV" +
"YBOX DRAWINGS UP HEAVY AND RIGHT DOWN LIGHTBOX DRAWINGS DOWN HEAVY AND R" +
"IGHT UP LIGHTBOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHTBOX DRAWINGS DOW" +
"N LIGHT AND RIGHT UP HEAVYBOX DRAWINGS UP LIGHT AND RIGHT DOWN HEAVYBOX " +
"DRAWINGS HEAVY VERTICAL AND RIGHTBOX DRAWINGS LIGHT VERTICAL AND LEFTBOX" +
" DRAWINGS VERTICAL LIGHT AND LEFT HEAVYBOX DRAWINGS UP HEAVY AND LEFT DO" +
"WN LIGHTBOX DRAWINGS DOWN HEAVY AND LEFT UP LIGHTBOX DRAWINGS VERTICAL H" +
"EAVY AND LEFT LIGHTBOX DRAWINGS DOWN LIGHT AND LEFT UP HEAVYBOX DRAWINGS" +
" UP LIGHT AND LEFT DOWN HEAVYBOX DRAWINGS HEAVY VERTICAL AND LEFTBOX DRA" +
"WINGS LIGHT DOWN AND HORIZONTALBOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LI" +
"GHTBOX DRAWINGS RIGHT HEAVY AND LEFT DOWN LIGHTBOX DRAWINGS DOWN LIGHT A" +
"ND HORIZONTAL HEAVYBOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHTBOX DRAWI") + ("" +
"NGS RIGHT LIGHT AND LEFT DOWN HEAVYBOX DRAWINGS LEFT LIGHT AND RIGHT DOW" +
"N HEAVYBOX DRAWINGS HEAVY DOWN AND HORIZONTALBOX DRAWINGS LIGHT UP AND H" +
"ORIZONTALBOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHTBOX DRAWINGS RIGHT HE" +
"AVY AND LEFT UP LIGHTBOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVYBOX DRAWI" +
"NGS UP HEAVY AND HORIZONTAL LIGHTBOX DRAWINGS RIGHT LIGHT AND LEFT UP HE" +
"AVYBOX DRAWINGS LEFT LIGHT AND RIGHT UP HEAVYBOX DRAWINGS HEAVY UP AND H" +
"ORIZONTALBOX DRAWINGS LIGHT VERTICAL AND HORIZONTALBOX DRAWINGS LEFT HEA" +
"VY AND RIGHT VERTICAL LIGHTBOX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LI" +
"GHTBOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVYBOX DRAWINGS UP HEAVY" +
" AND DOWN HORIZONTAL LIGHTBOX DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGH" +
"TBOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHTBOX DRAWINGS LEFT UP HE" +
"AVY AND RIGHT DOWN LIGHTBOX DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHTB" +
"OX DRAWINGS LEFT DOWN HEAVY AND RIGHT UP LIGHTBOX DRAWINGS RIGHT DOWN HE" +
"AVY AND LEFT UP LIGHTBOX DRAWINGS DOWN LIGHT AND UP HORIZONTAL HEAVYBOX " +
"DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVYBOX DRAWINGS RIGHT LIGHT AND " +
"LEFT VERTICAL HEAVYBOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVYBOX D" +
"RAWINGS HEAVY VERTICAL AND HORIZONTALBOX DRAWINGS LIGHT DOUBLE DASH HORI" +
"ZONTALBOX DRAWINGS HEAVY DOUBLE DASH HORIZONTALBOX DRAWINGS LIGHT DOUBLE" +
" DASH VERTICALBOX DRAWINGS HEAVY DOUBLE DASH VERTICALBOX DRAWINGS DOUBLE" +
" HORIZONTALBOX DRAWINGS DOUBLE VERTICALBOX DRAWINGS DOWN SINGLE AND RIGH" +
"T DOUBLEBOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLEBOX DRAWINGS DOUBLE DOW" +
"N AND RIGHTBOX DRAWINGS DOWN SINGLE AND LEFT DOUBLEBOX DRAWINGS DOWN DOU" +
"BLE AND LEFT SINGLEBOX DRAWINGS DOUBLE DOWN AND LEFTBOX DRAWINGS UP SING" +
"LE AND RIGHT DOUBLEBOX DRAWINGS UP DOUBLE AND RIGHT SINGLEBOX DRAWINGS D" +
"OUBLE UP AND RIGHTBOX DRAWINGS UP SINGLE AND LEFT DOUBLEBOX DRAWINGS UP " +
"DOUBLE AND LEFT SINGLEBOX DRAWINGS DOUBLE UP AND LEFTBOX DRAWINGS VERTIC" +
"AL SINGLE AND RIGHT DOUBLEBOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLEB" +
"OX DRAWINGS DOUBLE VERTICAL AND RIGHTBOX DRAWINGS VERTICAL SINGLE AND LE" +
"FT DOUBLEBOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLEBOX DRAWINGS DOUBLE" +
" VERTICAL AND LEFTBOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLEBOX DRAW" +
"INGS DOWN DOUBLE AND HORIZONTAL SINGLEBOX DRAWINGS DOUBLE DOWN AND HORIZ" +
"ONTALBOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLEBOX DRAWINGS UP DOUBLE " +
"AND HORIZONTAL SINGLEBOX DRAWINGS DOUBLE UP AND HORIZONTALBOX DRAWINGS V" +
"ERTICAL SINGLE AND HORIZONTAL DOUBLEBOX DRAWINGS VERTICAL DOUBLE AND HOR" +
"IZONTAL SINGLEBOX DRAWINGS DOUBLE VERTICAL AND HORIZONTALBOX DRAWINGS LI" +
"GHT ARC DOWN AND RIGHTBOX DRAWINGS LIGHT ARC DOWN AND LEFTBOX DRAWINGS L" +
"IGHT ARC UP AND LEFTBOX DRAWINGS LIGHT ARC UP AND RIGHTBOX DRAWINGS LIGH" +
"T DIAGONAL UPPER RIGHT TO LOWER LEFTBOX DRAWINGS LIGHT DIAGONAL UPPER LE" +
"FT TO LOWER RIGHTBOX DRAWINGS LIGHT DIAGONAL CROSSBOX DRAWINGS LIGHT LEF" +
"TBOX DRAWINGS LIGHT UPBOX DRAWINGS LIGHT RIGHTBOX DRAWINGS LIGHT DOWNBOX" +
" DRAWINGS HEAVY LEFTBOX DRAWINGS HEAVY UPBOX DRAWINGS HEAVY RIGHTBOX DRA" +
"WINGS HEAVY DOWNBOX DRAWINGS LIGHT LEFT AND HEAVY RIGHTBOX DRAWINGS LIGH" +
"T UP AND HEAVY DOWNBOX DRAWINGS HEAVY LEFT AND LIGHT RIGHTBOX DRAWINGS H" +
"EAVY UP AND LIGHT DOWNUPPER HALF BLOCKLOWER ONE EIGHTH BLOCKLOWER ONE QU" +
"ARTER BLOCKLOWER THREE EIGHTHS BLOCKLOWER HALF BLOCKLOWER FIVE EIGHTHS B" +
"LOCKLOWER THREE QUARTERS BLOCKLOWER SEVEN EIGHTHS BLOCKFULL BLOCKLEFT SE" +
"VEN EIGHTHS BLOCKLEFT THREE QUARTERS BLOCKLEFT FIVE EIGHTHS BLOCKLEFT HA" +
"LF BLOCKLEFT THREE EIGHTHS BLOCKLEFT ONE QUARTER BLOCKLEFT ONE EIGHTH BL" +
"OCKRIGHT HALF BLOCKLIGHT SHADEMEDIUM SHADEDARK SHADEUPPER ONE EIGHTH BLO" +
"CKRIGHT ONE EIGHTH BLOCKQUADRANT LOWER LEFTQUADRANT LOWER RIGHTQUADRANT " +
"UPPER LEFTQUADRANT UPPER LEFT AND LOWER LEFT AND LOWER RIGHTQUADRANT UPP" +
"ER LEFT AND LOWER RIGHTQUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER LEF" +
"TQUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER RIGHTQUADRANT UPPER RIGHT" +
"QUADRANT UPPER RIGHT AND LOWER LEFTQUADRANT UPPER RIGHT AND LOWER LEFT A" +
"ND LOWER RIGHTBLACK SQUAREWHITE SQUAREWHITE SQUARE WITH ROUNDED CORNERSW" +
"HITE SQUARE CONTAINING BLACK SMALL SQUARESQUARE WITH HORIZONTAL FILLSQUA" +
"RE WITH VERTICAL FILLSQUARE WITH ORTHOGONAL CROSSHATCH FILLSQUARE WITH U" +
"PPER LEFT TO LOWER RIGHT FILLSQUARE WITH UPPER RIGHT TO LOWER LEFT FILLS" +
"QUARE WITH DIAGONAL CROSSHATCH FILLBLACK SMALL SQUAREWHITE SMALL SQUAREB" +
"LACK RECTANGLEWHITE RECTANGLEBLACK VERTICAL RECTANGLEWHITE VERTICAL RECT" +
"ANGLEBLACK PARALLELOGRAMWHITE PARALLELOGRAMBLACK UP-POINTING TRIANGLEWHI" +
"TE UP-POINTING TRIANGLEBLACK UP-POINTING SMALL TRIANGLEWHITE UP-POINTING" +
" SMALL TRIANGLEBLACK RIGHT-POINTING TRIANGLEWHITE RIGHT-POINTING TRIANGL" +
"EBLACK RIGHT-POINTING SMALL TRIANGLEWHITE RIGHT-POINTING SMALL TRIANGLEB") + ("" +
"LACK RIGHT-POINTING POINTERWHITE RIGHT-POINTING POINTERBLACK DOWN-POINTI" +
"NG TRIANGLEWHITE DOWN-POINTING TRIANGLEBLACK DOWN-POINTING SMALL TRIANGL" +
"EWHITE DOWN-POINTING SMALL TRIANGLEBLACK LEFT-POINTING TRIANGLEWHITE LEF" +
"T-POINTING TRIANGLEBLACK LEFT-POINTING SMALL TRIANGLEWHITE LEFT-POINTING" +
" SMALL TRIANGLEBLACK LEFT-POINTING POINTERWHITE LEFT-POINTING POINTERBLA" +
"CK DIAMONDWHITE DIAMONDWHITE DIAMOND CONTAINING BLACK SMALL DIAMONDFISHE" +
"YELOZENGEWHITE CIRCLEDOTTED CIRCLECIRCLE WITH VERTICAL FILLBULLSEYEBLACK" +
" CIRCLECIRCLE WITH LEFT HALF BLACKCIRCLE WITH RIGHT HALF BLACKCIRCLE WIT" +
"H LOWER HALF BLACKCIRCLE WITH UPPER HALF BLACKCIRCLE WITH UPPER RIGHT QU" +
"ADRANT BLACKCIRCLE WITH ALL BUT UPPER LEFT QUADRANT BLACKLEFT HALF BLACK" +
" CIRCLERIGHT HALF BLACK CIRCLEINVERSE BULLETINVERSE WHITE CIRCLEUPPER HA" +
"LF INVERSE WHITE CIRCLELOWER HALF INVERSE WHITE CIRCLEUPPER LEFT QUADRAN" +
"T CIRCULAR ARCUPPER RIGHT QUADRANT CIRCULAR ARCLOWER RIGHT QUADRANT CIRC" +
"ULAR ARCLOWER LEFT QUADRANT CIRCULAR ARCUPPER HALF CIRCLELOWER HALF CIRC" +
"LEBLACK LOWER RIGHT TRIANGLEBLACK LOWER LEFT TRIANGLEBLACK UPPER LEFT TR" +
"IANGLEBLACK UPPER RIGHT TRIANGLEWHITE BULLETSQUARE WITH LEFT HALF BLACKS" +
"QUARE WITH RIGHT HALF BLACKSQUARE WITH UPPER LEFT DIAGONAL HALF BLACKSQU" +
"ARE WITH LOWER RIGHT DIAGONAL HALF BLACKWHITE SQUARE WITH VERTICAL BISEC" +
"TING LINEWHITE UP-POINTING TRIANGLE WITH DOTUP-POINTING TRIANGLE WITH LE" +
"FT HALF BLACKUP-POINTING TRIANGLE WITH RIGHT HALF BLACKLARGE CIRCLEWHITE" +
" SQUARE WITH UPPER LEFT QUADRANTWHITE SQUARE WITH LOWER LEFT QUADRANTWHI" +
"TE SQUARE WITH LOWER RIGHT QUADRANTWHITE SQUARE WITH UPPER RIGHT QUADRAN" +
"TWHITE CIRCLE WITH UPPER LEFT QUADRANTWHITE CIRCLE WITH LOWER LEFT QUADR" +
"ANTWHITE CIRCLE WITH LOWER RIGHT QUADRANTWHITE CIRCLE WITH UPPER RIGHT Q" +
"UADRANTUPPER LEFT TRIANGLEUPPER RIGHT TRIANGLELOWER LEFT TRIANGLEWHITE M" +
"EDIUM SQUAREBLACK MEDIUM SQUAREWHITE MEDIUM SMALL SQUAREBLACK MEDIUM SMA" +
"LL SQUARELOWER RIGHT TRIANGLEBLACK SUN WITH RAYSCLOUDUMBRELLASNOWMANCOME" +
"TBLACK STARWHITE STARLIGHTNINGTHUNDERSTORMSUNASCENDING NODEDESCENDING NO" +
"DECONJUNCTIONOPPOSITIONBLACK TELEPHONEWHITE TELEPHONEBALLOT BOXBALLOT BO" +
"X WITH CHECKBALLOT BOX WITH XSALTIREUMBRELLA WITH RAIN DROPSHOT BEVERAGE" +
"WHITE SHOGI PIECEBLACK SHOGI PIECESHAMROCKREVERSED ROTATED FLORAL HEART " +
"BULLETBLACK LEFT POINTING INDEXBLACK RIGHT POINTING INDEXWHITE LEFT POIN" +
"TING INDEXWHITE UP POINTING INDEXWHITE RIGHT POINTING INDEXWHITE DOWN PO" +
"INTING INDEXSKULL AND CROSSBONESCAUTION SIGNRADIOACTIVE SIGNBIOHAZARD SI" +
"GNCADUCEUSANKHORTHODOX CROSSCHI RHOCROSS OF LORRAINECROSS OF JERUSALEMST" +
"AR AND CRESCENTFARSI SYMBOLADI SHAKTIHAMMER AND SICKLEPEACE SYMBOLYIN YA" +
"NGTRIGRAM FOR HEAVENTRIGRAM FOR LAKETRIGRAM FOR FIRETRIGRAM FOR THUNDERT" +
"RIGRAM FOR WINDTRIGRAM FOR WATERTRIGRAM FOR MOUNTAINTRIGRAM FOR EARTHWHE" +
"EL OF DHARMAWHITE FROWNING FACEWHITE SMILING FACEBLACK SMILING FACEWHITE" +
" SUN WITH RAYSFIRST QUARTER MOONLAST QUARTER MOONMERCURYFEMALE SIGNEARTH" +
"MALE SIGNJUPITERSATURNURANUSNEPTUNEPLUTOARIESTAURUSGEMINICANCERLEOVIRGOL" +
"IBRASCORPIUSSAGITTARIUSCAPRICORNAQUARIUSPISCESWHITE CHESS KINGWHITE CHES" +
"S QUEENWHITE CHESS ROOKWHITE CHESS BISHOPWHITE CHESS KNIGHTWHITE CHESS P" +
"AWNBLACK CHESS KINGBLACK CHESS QUEENBLACK CHESS ROOKBLACK CHESS BISHOPBL" +
"ACK CHESS KNIGHTBLACK CHESS PAWNBLACK SPADE SUITWHITE HEART SUITWHITE DI" +
"AMOND SUITBLACK CLUB SUITWHITE SPADE SUITBLACK HEART SUITBLACK DIAMOND S" +
"UITWHITE CLUB SUITHOT SPRINGSQUARTER NOTEEIGHTH NOTEBEAMED EIGHTH NOTESB" +
"EAMED SIXTEENTH NOTESMUSIC FLAT SIGNMUSIC NATURAL SIGNMUSIC SHARP SIGNWE" +
"ST SYRIAC CROSSEAST SYRIAC CROSSUNIVERSAL RECYCLING SYMBOLRECYCLING SYMB" +
"OL FOR TYPE-1 PLASTICSRECYCLING SYMBOL FOR TYPE-2 PLASTICSRECYCLING SYMB" +
"OL FOR TYPE-3 PLASTICSRECYCLING SYMBOL FOR TYPE-4 PLASTICSRECYCLING SYMB" +
"OL FOR TYPE-5 PLASTICSRECYCLING SYMBOL FOR TYPE-6 PLASTICSRECYCLING SYMB" +
"OL FOR TYPE-7 PLASTICSRECYCLING SYMBOL FOR GENERIC MATERIALSBLACK UNIVER" +
"SAL RECYCLING SYMBOLRECYCLED PAPER SYMBOLPARTIALLY-RECYCLED PAPER SYMBOL" +
"PERMANENT PAPER SIGNWHEELCHAIR SYMBOLDIE FACE-1DIE FACE-2DIE FACE-3DIE F" +
"ACE-4DIE FACE-5DIE FACE-6WHITE CIRCLE WITH DOT RIGHTWHITE CIRCLE WITH TW" +
"O DOTSBLACK CIRCLE WITH WHITE DOT RIGHTBLACK CIRCLE WITH TWO WHITE DOTSM" +
"ONOGRAM FOR YANGMONOGRAM FOR YINDIGRAM FOR GREATER YANGDIGRAM FOR LESSER" +
" YINDIGRAM FOR LESSER YANGDIGRAM FOR GREATER YINWHITE FLAGBLACK FLAGHAMM" +
"ER AND PICKANCHORCROSSED SWORDSSTAFF OF AESCULAPIUSSCALESALEMBICFLOWERGE" +
"ARSTAFF OF HERMESATOM SYMBOLFLEUR-DE-LISOUTLINED WHITE STARTHREE LINES C" +
"ONVERGING RIGHTTHREE LINES CONVERGING LEFTWARNING SIGNHIGH VOLTAGE SIGND" +
"OUBLED FEMALE SIGNDOUBLED MALE SIGNINTERLOCKED FEMALE AND MALE SIGNMALE " +
"AND FEMALE SIGNMALE WITH STROKE SIGNMALE WITH STROKE AND MALE AND FEMALE") + ("" +
" SIGNVERTICAL MALE WITH STROKE SIGNHORIZONTAL MALE WITH STROKE SIGNMEDIU" +
"M WHITE CIRCLEMEDIUM BLACK CIRCLEMEDIUM SMALL WHITE CIRCLEMARRIAGE SYMBO" +
"LDIVORCE SYMBOLUNMARRIED PARTNERSHIP SYMBOLCOFFINFUNERAL URNNEUTERCERESP" +
"ALLASJUNOVESTACHIRONBLACK MOON LILITHSEXTILESEMISEXTILEQUINCUNXSESQUIQUA" +
"DRATESOCCER BALLBASEBALLSQUARED KEYWHITE DRAUGHTS MANWHITE DRAUGHTS KING" +
"BLACK DRAUGHTS MANBLACK DRAUGHTS KINGSNOWMAN WITHOUT SNOWSUN BEHIND CLOU" +
"DRAINBLACK SNOWMANTHUNDER CLOUD AND RAINTURNED WHITE SHOGI PIECETURNED B" +
"LACK SHOGI PIECEWHITE DIAMOND IN SQUARECROSSING LANESDISABLED CAROPHIUCH" +
"USPICKCAR SLIDINGHELMET WITH WHITE CROSSCIRCLED CROSSING LANESCHAINSNO E" +
"NTRYALTERNATE ONE-WAY LEFT WAY TRAFFICBLACK TWO-WAY LEFT WAY TRAFFICWHIT" +
"E TWO-WAY LEFT WAY TRAFFICBLACK LEFT LANE MERGEWHITE LEFT LANE MERGEDRIV" +
"E SLOW SIGNHEAVY WHITE DOWN-POINTING TRIANGLELEFT CLOSED ENTRYSQUARED SA" +
"LTIREFALLING DIAGONAL IN WHITE CIRCLE IN BLACK SQUAREBLACK TRUCKRESTRICT" +
"ED LEFT ENTRY-1RESTRICTED LEFT ENTRY-2ASTRONOMICAL SYMBOL FOR URANUSHEAV" +
"Y CIRCLE WITH STROKE AND TWO DOTS ABOVEPENTAGRAMRIGHT-HANDED INTERLACED " +
"PENTAGRAMLEFT-HANDED INTERLACED PENTAGRAMINVERTED PENTAGRAMBLACK CROSS O" +
"N SHIELDSHINTO SHRINECHURCHCASTLEHISTORIC SITEGEAR WITHOUT HUBGEAR WITH " +
"HANDLESMAP SYMBOL FOR LIGHTHOUSEMOUNTAINUMBRELLA ON GROUNDFOUNTAINFLAG I" +
"N HOLEFERRYSAILBOATSQUARE FOUR CORNERSSKIERICE SKATEPERSON WITH BALLTENT" +
"JAPANESE BANK SYMBOLHEADSTONE GRAVEYARD SYMBOLFUEL PUMPCUP ON BLACK SQUA" +
"REWHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPEBLACK SAFETY SCISSORSUPP" +
"ER BLADE SCISSORSBLACK SCISSORSLOWER BLADE SCISSORSWHITE SCISSORSWHITE H" +
"EAVY CHECK MARKTELEPHONE LOCATION SIGNTAPE DRIVEAIRPLANEENVELOPERAISED F" +
"ISTRAISED HANDVICTORY HANDWRITING HANDLOWER RIGHT PENCILPENCILUPPER RIGH" +
"T PENCILWHITE NIBBLACK NIBCHECK MARKHEAVY CHECK MARKMULTIPLICATION XHEAV" +
"Y MULTIPLICATION XBALLOT XHEAVY BALLOT XOUTLINED GREEK CROSSHEAVY GREEK " +
"CROSSOPEN CENTRE CROSSHEAVY OPEN CENTRE CROSSLATIN CROSSSHADOWED WHITE L" +
"ATIN CROSSOUTLINED LATIN CROSSMALTESE CROSSSTAR OF DAVIDFOUR TEARDROP-SP" +
"OKED ASTERISKFOUR BALLOON-SPOKED ASTERISKHEAVY FOUR BALLOON-SPOKED ASTER" +
"ISKFOUR CLUB-SPOKED ASTERISKBLACK FOUR POINTED STARWHITE FOUR POINTED ST" +
"ARSPARKLESSTRESS OUTLINED WHITE STARCIRCLED WHITE STAROPEN CENTRE BLACK " +
"STARBLACK CENTRE WHITE STAROUTLINED BLACK STARHEAVY OUTLINED BLACK STARP" +
"INWHEEL STARSHADOWED WHITE STARHEAVY ASTERISKOPEN CENTRE ASTERISKEIGHT S" +
"POKED ASTERISKEIGHT POINTED BLACK STAREIGHT POINTED PINWHEEL STARSIX POI" +
"NTED BLACK STAREIGHT POINTED RECTILINEAR BLACK STARHEAVY EIGHT POINTED R" +
"ECTILINEAR BLACK STARTWELVE POINTED BLACK STARSIXTEEN POINTED ASTERISKTE" +
"ARDROP-SPOKED ASTERISKOPEN CENTRE TEARDROP-SPOKED ASTERISKHEAVY TEARDROP" +
"-SPOKED ASTERISKSIX PETALLED BLACK AND WHITE FLORETTEBLACK FLORETTEWHITE" +
" FLORETTEEIGHT PETALLED OUTLINED BLACK FLORETTECIRCLED OPEN CENTRE EIGHT" +
" POINTED STARHEAVY TEARDROP-SPOKED PINWHEEL ASTERISKSNOWFLAKETIGHT TRIFO" +
"LIATE SNOWFLAKEHEAVY CHEVRON SNOWFLAKESPARKLEHEAVY SPARKLEBALLOON-SPOKED" +
" ASTERISKEIGHT TEARDROP-SPOKED PROPELLER ASTERISKHEAVY EIGHT TEARDROP-SP" +
"OKED PROPELLER ASTERISKCROSS MARKSHADOWED WHITE CIRCLENEGATIVE SQUARED C" +
"ROSS MARKLOWER RIGHT DROP-SHADOWED WHITE SQUAREUPPER RIGHT DROP-SHADOWED" +
" WHITE SQUARELOWER RIGHT SHADOWED WHITE SQUAREUPPER RIGHT SHADOWED WHITE" +
" SQUAREBLACK QUESTION MARK ORNAMENTWHITE QUESTION MARK ORNAMENTWHITE EXC" +
"LAMATION MARK ORNAMENTBLACK DIAMOND MINUS WHITE XHEAVY EXCLAMATION MARK " +
"SYMBOLLIGHT VERTICAL BARMEDIUM VERTICAL BARHEAVY VERTICAL BARHEAVY SINGL" +
"E TURNED COMMA QUOTATION MARK ORNAMENTHEAVY SINGLE COMMA QUOTATION MARK " +
"ORNAMENTHEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENTHEAVY DOUBLE CO" +
"MMA QUOTATION MARK ORNAMENTHEAVY LOW SINGLE COMMA QUOTATION MARK ORNAMEN" +
"THEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENTCURVED STEM PARAGRAPH SIG" +
"N ORNAMENTHEAVY EXCLAMATION MARK ORNAMENTHEAVY HEART EXCLAMATION MARK OR" +
"NAMENTHEAVY BLACK HEARTROTATED HEAVY BLACK HEART BULLETFLORAL HEARTROTAT" +
"ED FLORAL HEART BULLETMEDIUM LEFT PARENTHESIS ORNAMENTMEDIUM RIGHT PAREN" +
"THESIS ORNAMENTMEDIUM FLATTENED LEFT PARENTHESIS ORNAMENTMEDIUM FLATTENE" +
"D RIGHT PARENTHESIS ORNAMENTMEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENTM" +
"EDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENTHEAVY LEFT-POINTING ANGLE QUO" +
"TATION MARK ORNAMENTHEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENTHE" +
"AVY LEFT-POINTING ANGLE BRACKET ORNAMENTHEAVY RIGHT-POINTING ANGLE BRACK" +
"ET ORNAMENTLIGHT LEFT TORTOISE SHELL BRACKET ORNAMENTLIGHT RIGHT TORTOIS" +
"E SHELL BRACKET ORNAMENTMEDIUM LEFT CURLY BRACKET ORNAMENTMEDIUM RIGHT C" +
"URLY BRACKET ORNAMENTDINGBAT NEGATIVE CIRCLED DIGIT ONEDINGBAT NEGATIVE " +
"CIRCLED DIGIT TWODINGBAT NEGATIVE CIRCLED DIGIT THREEDINGBAT NEGATIVE CI") + ("" +
"RCLED DIGIT FOURDINGBAT NEGATIVE CIRCLED DIGIT FIVEDINGBAT NEGATIVE CIRC" +
"LED DIGIT SIXDINGBAT NEGATIVE CIRCLED DIGIT SEVENDINGBAT NEGATIVE CIRCLE" +
"D DIGIT EIGHTDINGBAT NEGATIVE CIRCLED DIGIT NINEDINGBAT NEGATIVE CIRCLED" +
" NUMBER TENDINGBAT CIRCLED SANS-SERIF DIGIT ONEDINGBAT CIRCLED SANS-SERI" +
"F DIGIT TWODINGBAT CIRCLED SANS-SERIF DIGIT THREEDINGBAT CIRCLED SANS-SE" +
"RIF DIGIT FOURDINGBAT CIRCLED SANS-SERIF DIGIT FIVEDINGBAT CIRCLED SANS-" +
"SERIF DIGIT SIXDINGBAT CIRCLED SANS-SERIF DIGIT SEVENDINGBAT CIRCLED SAN" +
"S-SERIF DIGIT EIGHTDINGBAT CIRCLED SANS-SERIF DIGIT NINEDINGBAT CIRCLED " +
"SANS-SERIF NUMBER TENDINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONEDINGBA" +
"T NEGATIVE CIRCLED SANS-SERIF DIGIT TWODINGBAT NEGATIVE CIRCLED SANS-SER" +
"IF DIGIT THREEDINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FOURDINGBAT NEGA" +
"TIVE CIRCLED SANS-SERIF DIGIT FIVEDINGBAT NEGATIVE CIRCLED SANS-SERIF DI" +
"GIT SIXDINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SEVENDINGBAT NEGATIVE C" +
"IRCLED SANS-SERIF DIGIT EIGHTDINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT N" +
"INEDINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TENHEAVY WIDE-HEADED RIGHT" +
"WARDS ARROWHEAVY PLUS SIGNHEAVY MINUS SIGNHEAVY DIVISION SIGNHEAVY SOUTH" +
" EAST ARROWHEAVY RIGHTWARDS ARROWHEAVY NORTH EAST ARROWDRAFTING POINT RI" +
"GHTWARDS ARROWHEAVY ROUND-TIPPED RIGHTWARDS ARROWTRIANGLE-HEADED RIGHTWA" +
"RDS ARROWHEAVY TRIANGLE-HEADED RIGHTWARDS ARROWDASHED TRIANGLE-HEADED RI" +
"GHTWARDS ARROWHEAVY DASHED TRIANGLE-HEADED RIGHTWARDS ARROWBLACK RIGHTWA" +
"RDS ARROWTHREE-D TOP-LIGHTED RIGHTWARDS ARROWHEADTHREE-D BOTTOM-LIGHTED " +
"RIGHTWARDS ARROWHEADBLACK RIGHTWARDS ARROWHEADHEAVY BLACK CURVED DOWNWAR" +
"DS AND RIGHTWARDS ARROWHEAVY BLACK CURVED UPWARDS AND RIGHTWARDS ARROWSQ" +
"UAT BLACK RIGHTWARDS ARROWHEAVY CONCAVE-POINTED BLACK RIGHTWARDS ARROWRI" +
"GHT-SHADED WHITE RIGHTWARDS ARROWLEFT-SHADED WHITE RIGHTWARDS ARROWBACK-" +
"TILTED SHADOWED WHITE RIGHTWARDS ARROWFRONT-TILTED SHADOWED WHITE RIGHTW" +
"ARDS ARROWHEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROWHEAVY UPPER R" +
"IGHT-SHADOWED WHITE RIGHTWARDS ARROWNOTCHED LOWER RIGHT-SHADOWED WHITE R" +
"IGHTWARDS ARROWCURLY LOOPNOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS A" +
"RROWCIRCLED HEAVY WHITE RIGHTWARDS ARROWWHITE-FEATHERED RIGHTWARDS ARROW" +
"BLACK-FEATHERED SOUTH EAST ARROWBLACK-FEATHERED RIGHTWARDS ARROWBLACK-FE" +
"ATHERED NORTH EAST ARROWHEAVY BLACK-FEATHERED SOUTH EAST ARROWHEAVY BLAC" +
"K-FEATHERED RIGHTWARDS ARROWHEAVY BLACK-FEATHERED NORTH EAST ARROWTEARDR" +
"OP-BARBED RIGHTWARDS ARROWHEAVY TEARDROP-SHANKED RIGHTWARDS ARROWWEDGE-T" +
"AILED RIGHTWARDS ARROWHEAVY WEDGE-TAILED RIGHTWARDS ARROWOPEN-OUTLINED R" +
"IGHTWARDS ARROWDOUBLE CURLY LOOPTHREE DIMENSIONAL ANGLEWHITE TRIANGLE CO" +
"NTAINING SMALL WHITE TRIANGLEPERPENDICULAROPEN SUBSETOPEN SUPERSETLEFT S" +
"-SHAPED BAG DELIMITERRIGHT S-SHAPED BAG DELIMITEROR WITH DOT INSIDEREVER" +
"SE SOLIDUS PRECEDING SUBSETSUPERSET PRECEDING SOLIDUSVERTICAL BAR WITH H" +
"ORIZONTAL STROKEMATHEMATICAL RISING DIAGONALLONG DIVISIONMATHEMATICAL FA" +
"LLING DIAGONALSQUARED LOGICAL ANDSQUARED LOGICAL ORWHITE DIAMOND WITH CE" +
"NTRED DOTAND WITH DOTELEMENT OF OPENING UPWARDSLOWER RIGHT CORNER WITH D" +
"OTUPPER LEFT CORNER WITH DOTLEFT OUTER JOINRIGHT OUTER JOINFULL OUTER JO" +
"INLARGE UP TACKLARGE DOWN TACKLEFT AND RIGHT DOUBLE TURNSTILELEFT AND RI" +
"GHT TACKLEFT MULTIMAPLONG RIGHT TACKLONG LEFT TACKUP TACK WITH CIRCLE AB" +
"OVELOZENGE DIVIDED BY HORIZONTAL RULEWHITE CONCAVE-SIDED DIAMONDWHITE CO" +
"NCAVE-SIDED DIAMOND WITH LEFTWARDS TICKWHITE CONCAVE-SIDED DIAMOND WITH " +
"RIGHTWARDS TICKWHITE SQUARE WITH LEFTWARDS TICKWHITE SQUARE WITH RIGHTWA" +
"RDS TICKMATHEMATICAL LEFT WHITE SQUARE BRACKETMATHEMATICAL RIGHT WHITE S" +
"QUARE BRACKETMATHEMATICAL LEFT ANGLE BRACKETMATHEMATICAL RIGHT ANGLE BRA" +
"CKETMATHEMATICAL LEFT DOUBLE ANGLE BRACKETMATHEMATICAL RIGHT DOUBLE ANGL" +
"E BRACKETMATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKETMATHEMATICAL RIGH" +
"T WHITE TORTOISE SHELL BRACKETMATHEMATICAL LEFT FLATTENED PARENTHESISMAT" +
"HEMATICAL RIGHT FLATTENED PARENTHESISUPWARDS QUADRUPLE ARROWDOWNWARDS QU" +
"ADRUPLE ARROWANTICLOCKWISE GAPPED CIRCLE ARROWCLOCKWISE GAPPED CIRCLE AR" +
"ROWRIGHT ARROW WITH CIRCLED PLUSLONG LEFTWARDS ARROWLONG RIGHTWARDS ARRO" +
"WLONG LEFT RIGHT ARROWLONG LEFTWARDS DOUBLE ARROWLONG RIGHTWARDS DOUBLE " +
"ARROWLONG LEFT RIGHT DOUBLE ARROWLONG LEFTWARDS ARROW FROM BARLONG RIGHT" +
"WARDS ARROW FROM BARLONG LEFTWARDS DOUBLE ARROW FROM BARLONG RIGHTWARDS " +
"DOUBLE ARROW FROM BARLONG RIGHTWARDS SQUIGGLE ARROWBRAILLE PATTERN BLANK" +
"BRAILLE PATTERN DOTS-1BRAILLE PATTERN DOTS-2BRAILLE PATTERN DOTS-12BRAIL" +
"LE PATTERN DOTS-3BRAILLE PATTERN DOTS-13BRAILLE PATTERN DOTS-23BRAILLE P" +
"ATTERN DOTS-123BRAILLE PATTERN DOTS-4BRAILLE PATTERN DOTS-14BRAILLE PATT" +
"ERN DOTS-24BRAILLE PATTERN DOTS-124BRAILLE PATTERN DOTS-34BRAILLE PATTER") + ("" +
"N DOTS-134BRAILLE PATTERN DOTS-234BRAILLE PATTERN DOTS-1234BRAILLE PATTE" +
"RN DOTS-5BRAILLE PATTERN DOTS-15BRAILLE PATTERN DOTS-25BRAILLE PATTERN D" +
"OTS-125BRAILLE PATTERN DOTS-35BRAILLE PATTERN DOTS-135BRAILLE PATTERN DO" +
"TS-235BRAILLE PATTERN DOTS-1235BRAILLE PATTERN DOTS-45BRAILLE PATTERN DO" +
"TS-145BRAILLE PATTERN DOTS-245BRAILLE PATTERN DOTS-1245BRAILLE PATTERN D" +
"OTS-345BRAILLE PATTERN DOTS-1345BRAILLE PATTERN DOTS-2345BRAILLE PATTERN" +
" DOTS-12345BRAILLE PATTERN DOTS-6BRAILLE PATTERN DOTS-16BRAILLE PATTERN " +
"DOTS-26BRAILLE PATTERN DOTS-126BRAILLE PATTERN DOTS-36BRAILLE PATTERN DO" +
"TS-136BRAILLE PATTERN DOTS-236BRAILLE PATTERN DOTS-1236BRAILLE PATTERN D" +
"OTS-46BRAILLE PATTERN DOTS-146BRAILLE PATTERN DOTS-246BRAILLE PATTERN DO" +
"TS-1246BRAILLE PATTERN DOTS-346BRAILLE PATTERN DOTS-1346BRAILLE PATTERN " +
"DOTS-2346BRAILLE PATTERN DOTS-12346BRAILLE PATTERN DOTS-56BRAILLE PATTER" +
"N DOTS-156BRAILLE PATTERN DOTS-256BRAILLE PATTERN DOTS-1256BRAILLE PATTE" +
"RN DOTS-356BRAILLE PATTERN DOTS-1356BRAILLE PATTERN DOTS-2356BRAILLE PAT" +
"TERN DOTS-12356BRAILLE PATTERN DOTS-456BRAILLE PATTERN DOTS-1456BRAILLE " +
"PATTERN DOTS-2456BRAILLE PATTERN DOTS-12456BRAILLE PATTERN DOTS-3456BRAI" +
"LLE PATTERN DOTS-13456BRAILLE PATTERN DOTS-23456BRAILLE PATTERN DOTS-123" +
"456BRAILLE PATTERN DOTS-7BRAILLE PATTERN DOTS-17BRAILLE PATTERN DOTS-27B" +
"RAILLE PATTERN DOTS-127BRAILLE PATTERN DOTS-37BRAILLE PATTERN DOTS-137BR" +
"AILLE PATTERN DOTS-237BRAILLE PATTERN DOTS-1237BRAILLE PATTERN DOTS-47BR" +
"AILLE PATTERN DOTS-147BRAILLE PATTERN DOTS-247BRAILLE PATTERN DOTS-1247B" +
"RAILLE PATTERN DOTS-347BRAILLE PATTERN DOTS-1347BRAILLE PATTERN DOTS-234" +
"7BRAILLE PATTERN DOTS-12347BRAILLE PATTERN DOTS-57BRAILLE PATTERN DOTS-1" +
"57BRAILLE PATTERN DOTS-257BRAILLE PATTERN DOTS-1257BRAILLE PATTERN DOTS-" +
"357BRAILLE PATTERN DOTS-1357BRAILLE PATTERN DOTS-2357BRAILLE PATTERN DOT" +
"S-12357BRAILLE PATTERN DOTS-457BRAILLE PATTERN DOTS-1457BRAILLE PATTERN " +
"DOTS-2457BRAILLE PATTERN DOTS-12457BRAILLE PATTERN DOTS-3457BRAILLE PATT" +
"ERN DOTS-13457BRAILLE PATTERN DOTS-23457BRAILLE PATTERN DOTS-123457BRAIL" +
"LE PATTERN DOTS-67BRAILLE PATTERN DOTS-167BRAILLE PATTERN DOTS-267BRAILL" +
"E PATTERN DOTS-1267BRAILLE PATTERN DOTS-367BRAILLE PATTERN DOTS-1367BRAI" +
"LLE PATTERN DOTS-2367BRAILLE PATTERN DOTS-12367BRAILLE PATTERN DOTS-467B" +
"RAILLE PATTERN DOTS-1467BRAILLE PATTERN DOTS-2467BRAILLE PATTERN DOTS-12" +
"467BRAILLE PATTERN DOTS-3467BRAILLE PATTERN DOTS-13467BRAILLE PATTERN DO" +
"TS-23467BRAILLE PATTERN DOTS-123467BRAILLE PATTERN DOTS-567BRAILLE PATTE" +
"RN DOTS-1567BRAILLE PATTERN DOTS-2567BRAILLE PATTERN DOTS-12567BRAILLE P" +
"ATTERN DOTS-3567BRAILLE PATTERN DOTS-13567BRAILLE PATTERN DOTS-23567BRAI" +
"LLE PATTERN DOTS-123567BRAILLE PATTERN DOTS-4567BRAILLE PATTERN DOTS-145" +
"67BRAILLE PATTERN DOTS-24567BRAILLE PATTERN DOTS-124567BRAILLE PATTERN D" +
"OTS-34567BRAILLE PATTERN DOTS-134567BRAILLE PATTERN DOTS-234567BRAILLE P" +
"ATTERN DOTS-1234567BRAILLE PATTERN DOTS-8BRAILLE PATTERN DOTS-18BRAILLE " +
"PATTERN DOTS-28BRAILLE PATTERN DOTS-128BRAILLE PATTERN DOTS-38BRAILLE PA" +
"TTERN DOTS-138BRAILLE PATTERN DOTS-238BRAILLE PATTERN DOTS-1238BRAILLE P" +
"ATTERN DOTS-48BRAILLE PATTERN DOTS-148BRAILLE PATTERN DOTS-248BRAILLE PA" +
"TTERN DOTS-1248BRAILLE PATTERN DOTS-348BRAILLE PATTERN DOTS-1348BRAILLE " +
"PATTERN DOTS-2348BRAILLE PATTERN DOTS-12348BRAILLE PATTERN DOTS-58BRAILL" +
"E PATTERN DOTS-158BRAILLE PATTERN DOTS-258BRAILLE PATTERN DOTS-1258BRAIL" +
"LE PATTERN DOTS-358BRAILLE PATTERN DOTS-1358BRAILLE PATTERN DOTS-2358BRA" +
"ILLE PATTERN DOTS-12358BRAILLE PATTERN DOTS-458BRAILLE PATTERN DOTS-1458" +
"BRAILLE PATTERN DOTS-2458BRAILLE PATTERN DOTS-12458BRAILLE PATTERN DOTS-" +
"3458BRAILLE PATTERN DOTS-13458BRAILLE PATTERN DOTS-23458BRAILLE PATTERN " +
"DOTS-123458BRAILLE PATTERN DOTS-68BRAILLE PATTERN DOTS-168BRAILLE PATTER" +
"N DOTS-268BRAILLE PATTERN DOTS-1268BRAILLE PATTERN DOTS-368BRAILLE PATTE" +
"RN DOTS-1368BRAILLE PATTERN DOTS-2368BRAILLE PATTERN DOTS-12368BRAILLE P" +
"ATTERN DOTS-468BRAILLE PATTERN DOTS-1468BRAILLE PATTERN DOTS-2468BRAILLE" +
" PATTERN DOTS-12468BRAILLE PATTERN DOTS-3468BRAILLE PATTERN DOTS-13468BR" +
"AILLE PATTERN DOTS-23468BRAILLE PATTERN DOTS-123468BRAILLE PATTERN DOTS-" +
"568BRAILLE PATTERN DOTS-1568BRAILLE PATTERN DOTS-2568BRAILLE PATTERN DOT" +
"S-12568BRAILLE PATTERN DOTS-3568BRAILLE PATTERN DOTS-13568BRAILLE PATTER" +
"N DOTS-23568BRAILLE PATTERN DOTS-123568BRAILLE PATTERN DOTS-4568BRAILLE " +
"PATTERN DOTS-14568BRAILLE PATTERN DOTS-24568BRAILLE PATTERN DOTS-124568B" +
"RAILLE PATTERN DOTS-34568BRAILLE PATTERN DOTS-134568BRAILLE PATTERN DOTS" +
"-234568BRAILLE PATTERN DOTS-1234568BRAILLE PATTERN DOTS-78BRAILLE PATTER" +
"N DOTS-178BRAILLE PATTERN DOTS-278BRAILLE PATTERN DOTS-1278BRAILLE PATTE" +
"RN DOTS-378BRAILLE PATTERN DOTS-1378BRAILLE PATTERN DOTS-2378BRAILLE PAT") + ("" +
"TERN DOTS-12378BRAILLE PATTERN DOTS-478BRAILLE PATTERN DOTS-1478BRAILLE " +
"PATTERN DOTS-2478BRAILLE PATTERN DOTS-12478BRAILLE PATTERN DOTS-3478BRAI" +
"LLE PATTERN DOTS-13478BRAILLE PATTERN DOTS-23478BRAILLE PATTERN DOTS-123" +
"478BRAILLE PATTERN DOTS-578BRAILLE PATTERN DOTS-1578BRAILLE PATTERN DOTS" +
"-2578BRAILLE PATTERN DOTS-12578BRAILLE PATTERN DOTS-3578BRAILLE PATTERN " +
"DOTS-13578BRAILLE PATTERN DOTS-23578BRAILLE PATTERN DOTS-123578BRAILLE P" +
"ATTERN DOTS-4578BRAILLE PATTERN DOTS-14578BRAILLE PATTERN DOTS-24578BRAI" +
"LLE PATTERN DOTS-124578BRAILLE PATTERN DOTS-34578BRAILLE PATTERN DOTS-13" +
"4578BRAILLE PATTERN DOTS-234578BRAILLE PATTERN DOTS-1234578BRAILLE PATTE" +
"RN DOTS-678BRAILLE PATTERN DOTS-1678BRAILLE PATTERN DOTS-2678BRAILLE PAT" +
"TERN DOTS-12678BRAILLE PATTERN DOTS-3678BRAILLE PATTERN DOTS-13678BRAILL" +
"E PATTERN DOTS-23678BRAILLE PATTERN DOTS-123678BRAILLE PATTERN DOTS-4678" +
"BRAILLE PATTERN DOTS-14678BRAILLE PATTERN DOTS-24678BRAILLE PATTERN DOTS" +
"-124678BRAILLE PATTERN DOTS-34678BRAILLE PATTERN DOTS-134678BRAILLE PATT" +
"ERN DOTS-234678BRAILLE PATTERN DOTS-1234678BRAILLE PATTERN DOTS-5678BRAI" +
"LLE PATTERN DOTS-15678BRAILLE PATTERN DOTS-25678BRAILLE PATTERN DOTS-125" +
"678BRAILLE PATTERN DOTS-35678BRAILLE PATTERN DOTS-135678BRAILLE PATTERN " +
"DOTS-235678BRAILLE PATTERN DOTS-1235678BRAILLE PATTERN DOTS-45678BRAILLE" +
" PATTERN DOTS-145678BRAILLE PATTERN DOTS-245678BRAILLE PATTERN DOTS-1245" +
"678BRAILLE PATTERN DOTS-345678BRAILLE PATTERN DOTS-1345678BRAILLE PATTER" +
"N DOTS-2345678BRAILLE PATTERN DOTS-12345678RIGHTWARDS TWO-HEADED ARROW W" +
"ITH VERTICAL STROKERIGHTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STRO" +
"KELEFTWARDS DOUBLE ARROW WITH VERTICAL STROKERIGHTWARDS DOUBLE ARROW WIT" +
"H VERTICAL STROKELEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKERIGHTWARDS " +
"TWO-HEADED ARROW FROM BARLEFTWARDS DOUBLE ARROW FROM BARRIGHTWARDS DOUBL" +
"E ARROW FROM BARDOWNWARDS ARROW WITH HORIZONTAL STROKEUPWARDS ARROW WITH" +
" HORIZONTAL STROKEUPWARDS TRIPLE ARROWDOWNWARDS TRIPLE ARROWLEFTWARDS DO" +
"UBLE DASH ARROWRIGHTWARDS DOUBLE DASH ARROWLEFTWARDS TRIPLE DASH ARROWRI" +
"GHTWARDS TRIPLE DASH ARROWRIGHTWARDS TWO-HEADED TRIPLE DASH ARROWRIGHTWA" +
"RDS ARROW WITH DOTTED STEMUPWARDS ARROW TO BARDOWNWARDS ARROW TO BARRIGH" +
"TWARDS ARROW WITH TAIL WITH VERTICAL STROKERIGHTWARDS ARROW WITH TAIL WI" +
"TH DOUBLE VERTICAL STROKERIGHTWARDS TWO-HEADED ARROW WITH TAILRIGHTWARDS" +
" TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKERIGHTWARDS TWO-HEADED AR" +
"ROW WITH TAIL WITH DOUBLE VERTICAL STROKELEFTWARDS ARROW-TAILRIGHTWARDS " +
"ARROW-TAILLEFTWARDS DOUBLE ARROW-TAILRIGHTWARDS DOUBLE ARROW-TAILLEFTWAR" +
"DS ARROW TO BLACK DIAMONDRIGHTWARDS ARROW TO BLACK DIAMONDLEFTWARDS ARRO" +
"W FROM BAR TO BLACK DIAMONDRIGHTWARDS ARROW FROM BAR TO BLACK DIAMONDNOR" +
"TH WEST AND SOUTH EAST ARROWNORTH EAST AND SOUTH WEST ARROWNORTH WEST AR" +
"ROW WITH HOOKNORTH EAST ARROW WITH HOOKSOUTH EAST ARROW WITH HOOKSOUTH W" +
"EST ARROW WITH HOOKNORTH WEST ARROW AND NORTH EAST ARROWNORTH EAST ARROW" +
" AND SOUTH EAST ARROWSOUTH EAST ARROW AND SOUTH WEST ARROWSOUTH WEST ARR" +
"OW AND NORTH WEST ARROWRISING DIAGONAL CROSSING FALLING DIAGONALFALLING " +
"DIAGONAL CROSSING RISING DIAGONALSOUTH EAST ARROW CROSSING NORTH EAST AR" +
"ROWNORTH EAST ARROW CROSSING SOUTH EAST ARROWFALLING DIAGONAL CROSSING N" +
"ORTH EAST ARROWRISING DIAGONAL CROSSING SOUTH EAST ARROWNORTH EAST ARROW" +
" CROSSING NORTH WEST ARROWNORTH WEST ARROW CROSSING NORTH EAST ARROWWAVE" +
" ARROW POINTING DIRECTLY RIGHTARROW POINTING RIGHTWARDS THEN CURVING UPW" +
"ARDSARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDSARROW POINTING DOWNW" +
"ARDS THEN CURVING LEFTWARDSARROW POINTING DOWNWARDS THEN CURVING RIGHTWA" +
"RDSRIGHT-SIDE ARC CLOCKWISE ARROWLEFT-SIDE ARC ANTICLOCKWISE ARROWTOP AR" +
"C ANTICLOCKWISE ARROWBOTTOM ARC ANTICLOCKWISE ARROWTOP ARC CLOCKWISE ARR" +
"OW WITH MINUSTOP ARC ANTICLOCKWISE ARROW WITH PLUSLOWER RIGHT SEMICIRCUL" +
"AR CLOCKWISE ARROWLOWER LEFT SEMICIRCULAR ANTICLOCKWISE ARROWANTICLOCKWI" +
"SE CLOSED CIRCLE ARROWCLOCKWISE CLOSED CIRCLE ARROWRIGHTWARDS ARROW ABOV" +
"E SHORT LEFTWARDS ARROWLEFTWARDS ARROW ABOVE SHORT RIGHTWARDS ARROWSHORT" +
" RIGHTWARDS ARROW ABOVE LEFTWARDS ARROWRIGHTWARDS ARROW WITH PLUS BELOWL" +
"EFTWARDS ARROW WITH PLUS BELOWRIGHTWARDS ARROW THROUGH XLEFT RIGHT ARROW" +
" THROUGH SMALL CIRCLEUPWARDS TWO-HEADED ARROW FROM SMALL CIRCLELEFT BARB" +
" UP RIGHT BARB DOWN HARPOONLEFT BARB DOWN RIGHT BARB UP HARPOONUP BARB R" +
"IGHT DOWN BARB LEFT HARPOONUP BARB LEFT DOWN BARB RIGHT HARPOONLEFT BARB" +
" UP RIGHT BARB UP HARPOONUP BARB RIGHT DOWN BARB RIGHT HARPOONLEFT BARB " +
"DOWN RIGHT BARB DOWN HARPOONUP BARB LEFT DOWN BARB LEFT HARPOONLEFTWARDS" +
" HARPOON WITH BARB UP TO BARRIGHTWARDS HARPOON WITH BARB UP TO BARUPWARD" +
"S HARPOON WITH BARB RIGHT TO BARDOWNWARDS HARPOON WITH BARB RIGHT TO BAR") + ("" +
"LEFTWARDS HARPOON WITH BARB DOWN TO BARRIGHTWARDS HARPOON WITH BARB DOWN" +
" TO BARUPWARDS HARPOON WITH BARB LEFT TO BARDOWNWARDS HARPOON WITH BARB " +
"LEFT TO BARLEFTWARDS HARPOON WITH BARB UP FROM BARRIGHTWARDS HARPOON WIT" +
"H BARB UP FROM BARUPWARDS HARPOON WITH BARB RIGHT FROM BARDOWNWARDS HARP" +
"OON WITH BARB RIGHT FROM BARLEFTWARDS HARPOON WITH BARB DOWN FROM BARRIG" +
"HTWARDS HARPOON WITH BARB DOWN FROM BARUPWARDS HARPOON WITH BARB LEFT FR" +
"OM BARDOWNWARDS HARPOON WITH BARB LEFT FROM BARLEFTWARDS HARPOON WITH BA" +
"RB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWNUPWARDS HARPOON WITH BARB LE" +
"FT BESIDE UPWARDS HARPOON WITH BARB RIGHTRIGHTWARDS HARPOON WITH BARB UP" +
" ABOVE RIGHTWARDS HARPOON WITH BARB DOWNDOWNWARDS HARPOON WITH BARB LEFT" +
" BESIDE DOWNWARDS HARPOON WITH BARB RIGHTLEFTWARDS HARPOON WITH BARB UP " +
"ABOVE RIGHTWARDS HARPOON WITH BARB UPLEFTWARDS HARPOON WITH BARB DOWN AB" +
"OVE RIGHTWARDS HARPOON WITH BARB DOWNRIGHTWARDS HARPOON WITH BARB UP ABO" +
"VE LEFTWARDS HARPOON WITH BARB UPRIGHTWARDS HARPOON WITH BARB DOWN ABOVE" +
" LEFTWARDS HARPOON WITH BARB DOWNLEFTWARDS HARPOON WITH BARB UP ABOVE LO" +
"NG DASHLEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASHRIGHTWARDS HARPOO" +
"N WITH BARB UP ABOVE LONG DASHRIGHTWARDS HARPOON WITH BARB DOWN BELOW LO" +
"NG DASHUPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB" +
" RIGHTDOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB " +
"RIGHTRIGHT DOUBLE ARROW WITH ROUNDED HEADEQUALS SIGN ABOVE RIGHTWARDS AR" +
"ROWTILDE OPERATOR ABOVE RIGHTWARDS ARROWLEFTWARDS ARROW ABOVE TILDE OPER" +
"ATORRIGHTWARDS ARROW ABOVE TILDE OPERATORRIGHTWARDS ARROW ABOVE ALMOST E" +
"QUAL TOLESS-THAN ABOVE LEFTWARDS ARROWLEFTWARDS ARROW THROUGH LESS-THANG" +
"REATER-THAN ABOVE RIGHTWARDS ARROWSUBSET ABOVE RIGHTWARDS ARROWLEFTWARDS" +
" ARROW THROUGH SUBSETSUPERSET ABOVE LEFTWARDS ARROWLEFT FISH TAILRIGHT F" +
"ISH TAILUP FISH TAILDOWN FISH TAILTRIPLE VERTICAL BAR DELIMITERZ NOTATIO" +
"N SPOTZ NOTATION TYPE COLONLEFT WHITE CURLY BRACKETRIGHT WHITE CURLY BRA" +
"CKETLEFT WHITE PARENTHESISRIGHT WHITE PARENTHESISZ NOTATION LEFT IMAGE B" +
"RACKETZ NOTATION RIGHT IMAGE BRACKETZ NOTATION LEFT BINDING BRACKETZ NOT" +
"ATION RIGHT BINDING BRACKETLEFT SQUARE BRACKET WITH UNDERBARRIGHT SQUARE" +
" BRACKET WITH UNDERBARLEFT SQUARE BRACKET WITH TICK IN TOP CORNERRIGHT S" +
"QUARE BRACKET WITH TICK IN BOTTOM CORNERLEFT SQUARE BRACKET WITH TICK IN" +
" BOTTOM CORNERRIGHT SQUARE BRACKET WITH TICK IN TOP CORNERLEFT ANGLE BRA" +
"CKET WITH DOTRIGHT ANGLE BRACKET WITH DOTLEFT ARC LESS-THAN BRACKETRIGHT" +
" ARC GREATER-THAN BRACKETDOUBLE LEFT ARC GREATER-THAN BRACKETDOUBLE RIGH" +
"T ARC LESS-THAN BRACKETLEFT BLACK TORTOISE SHELL BRACKETRIGHT BLACK TORT" +
"OISE SHELL BRACKETDOTTED FENCEVERTICAL ZIGZAG LINEMEASURED ANGLE OPENING" +
" LEFTRIGHT ANGLE VARIANT WITH SQUAREMEASURED RIGHT ANGLE WITH DOTANGLE W" +
"ITH S INSIDEACUTE ANGLESPHERICAL ANGLE OPENING LEFTSPHERICAL ANGLE OPENI" +
"NG UPTURNED ANGLEREVERSED ANGLEANGLE WITH UNDERBARREVERSED ANGLE WITH UN" +
"DERBAROBLIQUE ANGLE OPENING UPOBLIQUE ANGLE OPENING DOWNMEASURED ANGLE W" +
"ITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHTMEASURED ANGLE WITH OP" +
"EN ARM ENDING IN ARROW POINTING UP AND LEFTMEASURED ANGLE WITH OPEN ARM " +
"ENDING IN ARROW POINTING DOWN AND RIGHTMEASURED ANGLE WITH OPEN ARM ENDI" +
"NG IN ARROW POINTING DOWN AND LEFTMEASURED ANGLE WITH OPEN ARM ENDING IN" +
" ARROW POINTING RIGHT AND UPMEASURED ANGLE WITH OPEN ARM ENDING IN ARROW" +
" POINTING LEFT AND UPMEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTI" +
"NG RIGHT AND DOWNMEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING L" +
"EFT AND DOWNREVERSED EMPTY SETEMPTY SET WITH OVERBAREMPTY SET WITH SMALL" +
" CIRCLE ABOVEEMPTY SET WITH RIGHT ARROW ABOVEEMPTY SET WITH LEFT ARROW A" +
"BOVECIRCLE WITH HORIZONTAL BARCIRCLED VERTICAL BARCIRCLED PARALLELCIRCLE" +
"D REVERSE SOLIDUSCIRCLED PERPENDICULARCIRCLE DIVIDED BY HORIZONTAL BAR A" +
"ND TOP HALF DIVIDED BY VERTICAL BARCIRCLE WITH SUPERIMPOSED XCIRCLED ANT" +
"ICLOCKWISE-ROTATED DIVISION SIGNUP ARROW THROUGH CIRCLECIRCLED WHITE BUL" +
"LETCIRCLED BULLETCIRCLED LESS-THANCIRCLED GREATER-THANCIRCLE WITH SMALL " +
"CIRCLE TO THE RIGHTCIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHTSQUARE" +
"D RISING DIAGONAL SLASHSQUARED FALLING DIAGONAL SLASHSQUARED ASTERISKSQU" +
"ARED SMALL CIRCLESQUARED SQUARETWO JOINED SQUARESTRIANGLE WITH DOT ABOVE" +
"TRIANGLE WITH UNDERBARS IN TRIANGLETRIANGLE WITH SERIFS AT BOTTOMRIGHT T" +
"RIANGLE ABOVE LEFT TRIANGLELEFT TRIANGLE BESIDE VERTICAL BARVERTICAL BAR" +
" BESIDE RIGHT TRIANGLEBOWTIE WITH LEFT HALF BLACKBOWTIE WITH RIGHT HALF " +
"BLACKBLACK BOWTIETIMES WITH LEFT HALF BLACKTIMES WITH RIGHT HALF BLACKWH" +
"ITE HOURGLASSBLACK HOURGLASSLEFT WIGGLY FENCERIGHT WIGGLY FENCELEFT DOUB" +
"LE WIGGLY FENCERIGHT DOUBLE WIGGLY FENCEINCOMPLETE INFINITYTIE OVER INFI") + ("" +
"NITYINFINITY NEGATED WITH VERTICAL BARDOUBLE-ENDED MULTIMAPSQUARE WITH C" +
"ONTOURED OUTLINEINCREASES ASSHUFFLE PRODUCTEQUALS SIGN AND SLANTED PARAL" +
"LELEQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVEIDENTICAL TO AND SLA" +
"NTED PARALLELGLEICH STARKTHERMODYNAMICDOWN-POINTING TRIANGLE WITH LEFT H" +
"ALF BLACKDOWN-POINTING TRIANGLE WITH RIGHT HALF BLACKBLACK DIAMOND WITH " +
"DOWN ARROWBLACK LOZENGEWHITE CIRCLE WITH DOWN ARROWBLACK CIRCLE WITH DOW" +
"N ARROWERROR-BARRED WHITE SQUAREERROR-BARRED BLACK SQUAREERROR-BARRED WH" +
"ITE DIAMONDERROR-BARRED BLACK DIAMONDERROR-BARRED WHITE CIRCLEERROR-BARR" +
"ED BLACK CIRCLERULE-DELAYEDREVERSE SOLIDUS OPERATORSOLIDUS WITH OVERBARR" +
"EVERSE SOLIDUS WITH HORIZONTAL STROKEBIG SOLIDUSBIG REVERSE SOLIDUSDOUBL" +
"E PLUSTRIPLE PLUSLEFT-POINTING CURVED ANGLE BRACKETRIGHT-POINTING CURVED" +
" ANGLE BRACKETTINYMINYN-ARY CIRCLED DOT OPERATORN-ARY CIRCLED PLUS OPERA" +
"TORN-ARY CIRCLED TIMES OPERATORN-ARY UNION OPERATOR WITH DOTN-ARY UNION " +
"OPERATOR WITH PLUSN-ARY SQUARE INTERSECTION OPERATORN-ARY SQUARE UNION O" +
"PERATORTWO LOGICAL AND OPERATORTWO LOGICAL OR OPERATORN-ARY TIMES OPERAT" +
"ORMODULO TWO SUMSUMMATION WITH INTEGRALQUADRUPLE INTEGRAL OPERATORFINITE" +
" PART INTEGRALINTEGRAL WITH DOUBLE STROKEINTEGRAL AVERAGE WITH SLASHCIRC" +
"ULATION FUNCTIONANTICLOCKWISE INTEGRATIONLINE INTEGRATION WITH RECTANGUL" +
"AR PATH AROUND POLELINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLELI" +
"NE INTEGRATION NOT INCLUDING THE POLEINTEGRAL AROUND A POINT OPERATORQUA" +
"TERNION INTEGRAL OPERATORINTEGRAL WITH LEFTWARDS ARROW WITH HOOKINTEGRAL" +
" WITH TIMES SIGNINTEGRAL WITH INTERSECTIONINTEGRAL WITH UNIONINTEGRAL WI" +
"TH OVERBARINTEGRAL WITH UNDERBARJOINLARGE LEFT TRIANGLE OPERATORZ NOTATI" +
"ON SCHEMA COMPOSITIONZ NOTATION SCHEMA PIPINGZ NOTATION SCHEMA PROJECTIO" +
"NPLUS SIGN WITH SMALL CIRCLE ABOVEPLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE" +
"PLUS SIGN WITH TILDE ABOVEPLUS SIGN WITH DOT BELOWPLUS SIGN WITH TILDE B" +
"ELOWPLUS SIGN WITH SUBSCRIPT TWOPLUS SIGN WITH BLACK TRIANGLEMINUS SIGN " +
"WITH COMMA ABOVEMINUS SIGN WITH DOT BELOWMINUS SIGN WITH FALLING DOTSMIN" +
"US SIGN WITH RISING DOTSPLUS SIGN IN LEFT HALF CIRCLEPLUS SIGN IN RIGHT " +
"HALF CIRCLEVECTOR OR CROSS PRODUCTMULTIPLICATION SIGN WITH DOT ABOVEMULT" +
"IPLICATION SIGN WITH UNDERBARSEMIDIRECT PRODUCT WITH BOTTOM CLOSEDSMASH " +
"PRODUCTMULTIPLICATION SIGN IN LEFT HALF CIRCLEMULTIPLICATION SIGN IN RIG" +
"HT HALF CIRCLECIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENTMULTIPLI" +
"CATION SIGN IN DOUBLE CIRCLECIRCLED DIVISION SIGNPLUS SIGN IN TRIANGLEMI" +
"NUS SIGN IN TRIANGLEMULTIPLICATION SIGN IN TRIANGLEINTERIOR PRODUCTRIGHT" +
"HAND INTERIOR PRODUCTZ NOTATION RELATIONAL COMPOSITIONAMALGAMATION OR CO" +
"PRODUCTINTERSECTION WITH DOTUNION WITH MINUS SIGNUNION WITH OVERBARINTER" +
"SECTION WITH OVERBARINTERSECTION WITH LOGICAL ANDUNION WITH LOGICAL ORUN" +
"ION ABOVE INTERSECTIONINTERSECTION ABOVE UNIONUNION ABOVE BAR ABOVE INTE" +
"RSECTIONINTERSECTION ABOVE BAR ABOVE UNIONUNION BESIDE AND JOINED WITH U" +
"NIONINTERSECTION BESIDE AND JOINED WITH INTERSECTIONCLOSED UNION WITH SE" +
"RIFSCLOSED INTERSECTION WITH SERIFSDOUBLE SQUARE INTERSECTIONDOUBLE SQUA" +
"RE UNIONCLOSED UNION WITH SERIFS AND SMASH PRODUCTLOGICAL AND WITH DOT A" +
"BOVELOGICAL OR WITH DOT ABOVEDOUBLE LOGICAL ANDDOUBLE LOGICAL ORTWO INTE" +
"RSECTING LOGICAL ANDTWO INTERSECTING LOGICAL ORSLOPING LARGE ORSLOPING L" +
"ARGE ANDLOGICAL OR OVERLAPPING LOGICAL ANDLOGICAL AND WITH MIDDLE STEMLO" +
"GICAL OR WITH MIDDLE STEMLOGICAL AND WITH HORIZONTAL DASHLOGICAL OR WITH" +
" HORIZONTAL DASHLOGICAL AND WITH DOUBLE OVERBARLOGICAL AND WITH UNDERBAR" +
"LOGICAL AND WITH DOUBLE UNDERBARSMALL VEE WITH UNDERBARLOGICAL OR WITH D" +
"OUBLE OVERBARLOGICAL OR WITH DOUBLE UNDERBARZ NOTATION DOMAIN ANTIRESTRI" +
"CTIONZ NOTATION RANGE ANTIRESTRICTIONEQUALS SIGN WITH DOT BELOWIDENTICAL" +
" WITH DOT ABOVETRIPLE HORIZONTAL BAR WITH DOUBLE VERTICAL STROKETRIPLE H" +
"ORIZONTAL BAR WITH TRIPLE VERTICAL STROKETILDE OPERATOR WITH DOT ABOVETI" +
"LDE OPERATOR WITH RISING DOTSSIMILAR MINUS SIMILARCONGRUENT WITH DOT ABO" +
"VEEQUALS WITH ASTERISKALMOST EQUAL TO WITH CIRCUMFLEX ACCENTAPPROXIMATEL" +
"Y EQUAL OR EQUAL TOEQUALS SIGN ABOVE PLUS SIGNPLUS SIGN ABOVE EQUALS SIG" +
"NEQUALS SIGN ABOVE TILDE OPERATORDOUBLE COLON EQUALTWO CONSECUTIVE EQUAL" +
"S SIGNSTHREE CONSECUTIVE EQUALS SIGNSEQUALS SIGN WITH TWO DOTS ABOVE AND" +
" TWO DOTS BELOWEQUIVALENT WITH FOUR DOTS ABOVELESS-THAN WITH CIRCLE INSI" +
"DEGREATER-THAN WITH CIRCLE INSIDELESS-THAN WITH QUESTION MARK ABOVEGREAT" +
"ER-THAN WITH QUESTION MARK ABOVELESS-THAN OR SLANTED EQUAL TOGREATER-THA" +
"N OR SLANTED EQUAL TOLESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDEGREATE" +
"R-THAN OR SLANTED EQUAL TO WITH DOT INSIDELESS-THAN OR SLANTED EQUAL TO " +
"WITH DOT ABOVEGREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVELESS-THAN O") + ("" +
"R SLANTED EQUAL TO WITH DOT ABOVE RIGHTGREATER-THAN OR SLANTED EQUAL TO " +
"WITH DOT ABOVE LEFTLESS-THAN OR APPROXIMATEGREATER-THAN OR APPROXIMATELE" +
"SS-THAN AND SINGLE-LINE NOT EQUAL TOGREATER-THAN AND SINGLE-LINE NOT EQU" +
"AL TOLESS-THAN AND NOT APPROXIMATEGREATER-THAN AND NOT APPROXIMATELESS-T" +
"HAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THANGREATER-THAN ABOVE DOUBLE-" +
"LINE EQUAL ABOVE LESS-THANLESS-THAN ABOVE SIMILAR OR EQUALGREATER-THAN A" +
"BOVE SIMILAR OR EQUALLESS-THAN ABOVE SIMILAR ABOVE GREATER-THANGREATER-T" +
"HAN ABOVE SIMILAR ABOVE LESS-THANLESS-THAN ABOVE GREATER-THAN ABOVE DOUB" +
"LE-LINE EQUALGREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUALLESS-TH" +
"AN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUALGREATER-THA" +
"N ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUALSLANTED EQUAL T" +
"O OR LESS-THANSLANTED EQUAL TO OR GREATER-THANSLANTED EQUAL TO OR LESS-T" +
"HAN WITH DOT INSIDESLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDEDOUBL" +
"E-LINE EQUAL TO OR LESS-THANDOUBLE-LINE EQUAL TO OR GREATER-THANDOUBLE-L" +
"INE SLANTED EQUAL TO OR LESS-THANDOUBLE-LINE SLANTED EQUAL TO OR GREATER" +
"-THANSIMILAR OR LESS-THANSIMILAR OR GREATER-THANSIMILAR ABOVE LESS-THAN " +
"ABOVE EQUALS SIGNSIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGNDOUBLE NEST" +
"ED LESS-THANDOUBLE NESTED GREATER-THANDOUBLE NESTED LESS-THAN WITH UNDER" +
"BARGREATER-THAN OVERLAPPING LESS-THANGREATER-THAN BESIDE LESS-THANLESS-T" +
"HAN CLOSED BY CURVEGREATER-THAN CLOSED BY CURVELESS-THAN CLOSED BY CURVE" +
" ABOVE SLANTED EQUALGREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUALSMAL" +
"LER THANLARGER THANSMALLER THAN OR EQUAL TOLARGER THAN OR EQUAL TOEQUALS" +
" SIGN WITH BUMPY ABOVEPRECEDES ABOVE SINGLE-LINE EQUALS SIGNSUCCEEDS ABO" +
"VE SINGLE-LINE EQUALS SIGNPRECEDES ABOVE SINGLE-LINE NOT EQUAL TOSUCCEED" +
"S ABOVE SINGLE-LINE NOT EQUAL TOPRECEDES ABOVE EQUALS SIGNSUCCEEDS ABOVE" +
" EQUALS SIGNPRECEDES ABOVE NOT EQUAL TOSUCCEEDS ABOVE NOT EQUAL TOPRECED" +
"ES ABOVE ALMOST EQUAL TOSUCCEEDS ABOVE ALMOST EQUAL TOPRECEDES ABOVE NOT" +
" ALMOST EQUAL TOSUCCEEDS ABOVE NOT ALMOST EQUAL TODOUBLE PRECEDESDOUBLE " +
"SUCCEEDSSUBSET WITH DOTSUPERSET WITH DOTSUBSET WITH PLUS SIGN BELOWSUPER" +
"SET WITH PLUS SIGN BELOWSUBSET WITH MULTIPLICATION SIGN BELOWSUPERSET WI" +
"TH MULTIPLICATION SIGN BELOWSUBSET OF OR EQUAL TO WITH DOT ABOVESUPERSET" +
" OF OR EQUAL TO WITH DOT ABOVESUBSET OF ABOVE EQUALS SIGNSUPERSET OF ABO" +
"VE EQUALS SIGNSUBSET OF ABOVE TILDE OPERATORSUPERSET OF ABOVE TILDE OPER" +
"ATORSUBSET OF ABOVE ALMOST EQUAL TOSUPERSET OF ABOVE ALMOST EQUAL TOSUBS" +
"ET OF ABOVE NOT EQUAL TOSUPERSET OF ABOVE NOT EQUAL TOSQUARE LEFT OPEN B" +
"OX OPERATORSQUARE RIGHT OPEN BOX OPERATORCLOSED SUBSETCLOSED SUPERSETCLO" +
"SED SUBSET OR EQUAL TOCLOSED SUPERSET OR EQUAL TOSUBSET ABOVE SUPERSETSU" +
"PERSET ABOVE SUBSETSUBSET ABOVE SUBSETSUPERSET ABOVE SUPERSETSUPERSET BE" +
"SIDE SUBSETSUPERSET BESIDE AND JOINED BY DASH WITH SUBSETELEMENT OF OPEN" +
"ING DOWNWARDSPITCHFORK WITH TEE TOPTRANSVERSAL INTERSECTIONFORKINGNONFOR" +
"KINGSHORT LEFT TACKSHORT DOWN TACKSHORT UP TACKPERPENDICULAR WITH SVERTI" +
"CAL BAR TRIPLE RIGHT TURNSTILEDOUBLE VERTICAL BAR LEFT TURNSTILEVERTICAL" +
" BAR DOUBLE LEFT TURNSTILEDOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILELONG " +
"DASH FROM LEFT MEMBER OF DOUBLE VERTICALSHORT DOWN TACK WITH OVERBARSHOR" +
"T UP TACK WITH UNDERBARSHORT UP TACK ABOVE SHORT DOWN TACKDOUBLE DOWN TA" +
"CKDOUBLE UP TACKDOUBLE STROKE NOT SIGNREVERSED DOUBLE STROKE NOT SIGNDOE" +
"S NOT DIVIDE WITH REVERSED NEGATION SLASHVERTICAL LINE WITH CIRCLE ABOVE" +
"VERTICAL LINE WITH CIRCLE BELOWDOWN TACK WITH CIRCLE BELOWPARALLEL WITH " +
"HORIZONTAL STROKEPARALLEL WITH TILDE OPERATORTRIPLE VERTICAL BAR BINARY " +
"RELATIONTRIPLE VERTICAL BAR WITH HORIZONTAL STROKETRIPLE COLON OPERATORT" +
"RIPLE NESTED LESS-THANTRIPLE NESTED GREATER-THANDOUBLE-LINE SLANTED LESS" +
"-THAN OR EQUAL TODOUBLE-LINE SLANTED GREATER-THAN OR EQUAL TOTRIPLE SOLI" +
"DUS BINARY RELATIONLARGE TRIPLE VERTICAL BAR OPERATORDOUBLE SOLIDUS OPER" +
"ATORWHITE VERTICAL BARN-ARY WHITE VERTICAL BARNORTH EAST WHITE ARROWNORT" +
"H WEST WHITE ARROWSOUTH EAST WHITE ARROWSOUTH WEST WHITE ARROWLEFT RIGHT" +
" WHITE ARROWLEFTWARDS BLACK ARROWUPWARDS BLACK ARROWDOWNWARDS BLACK ARRO" +
"WNORTH EAST BLACK ARROWNORTH WEST BLACK ARROWSOUTH EAST BLACK ARROWSOUTH" +
" WEST BLACK ARROWLEFT RIGHT BLACK ARROWUP DOWN BLACK ARROWRIGHTWARDS ARR" +
"OW WITH TIP DOWNWARDSRIGHTWARDS ARROW WITH TIP UPWARDSLEFTWARDS ARROW WI" +
"TH TIP DOWNWARDSLEFTWARDS ARROW WITH TIP UPWARDSSQUARE WITH TOP HALF BLA" +
"CKSQUARE WITH BOTTOM HALF BLACKSQUARE WITH UPPER RIGHT DIAGONAL HALF BLA" +
"CKSQUARE WITH LOWER LEFT DIAGONAL HALF BLACKDIAMOND WITH LEFT HALF BLACK" +
"DIAMOND WITH RIGHT HALF BLACKDIAMOND WITH TOP HALF BLACKDIAMOND WITH BOT" +
"TOM HALF BLACKDOTTED SQUAREBLACK LARGE SQUAREWHITE LARGE SQUAREBLACK VER") + ("" +
"Y SMALL SQUAREWHITE VERY SMALL SQUAREBLACK PENTAGONWHITE PENTAGONWHITE H" +
"EXAGONBLACK HEXAGONHORIZONTAL BLACK HEXAGONBLACK LARGE CIRCLEBLACK MEDIU" +
"M DIAMONDWHITE MEDIUM DIAMONDBLACK MEDIUM LOZENGEWHITE MEDIUM LOZENGEBLA" +
"CK SMALL DIAMONDBLACK SMALL LOZENGEWHITE SMALL LOZENGEBLACK HORIZONTAL E" +
"LLIPSEWHITE HORIZONTAL ELLIPSEBLACK VERTICAL ELLIPSEWHITE VERTICAL ELLIP" +
"SELEFT ARROW WITH SMALL CIRCLETHREE LEFTWARDS ARROWSLEFT ARROW WITH CIRC" +
"LED PLUSLONG LEFTWARDS SQUIGGLE ARROWLEFTWARDS TWO-HEADED ARROW WITH VER" +
"TICAL STROKELEFTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKELEFTWA" +
"RDS TWO-HEADED ARROW FROM BARLEFTWARDS TWO-HEADED TRIPLE DASH ARROWLEFTW" +
"ARDS ARROW WITH DOTTED STEMLEFTWARDS ARROW WITH TAIL WITH VERTICAL STROK" +
"ELEFTWARDS ARROW WITH TAIL WITH DOUBLE VERTICAL STROKELEFTWARDS TWO-HEAD" +
"ED ARROW WITH TAILLEFTWARDS TWO-HEADED ARROW WITH TAIL WITH VERTICAL STR" +
"OKELEFTWARDS TWO-HEADED ARROW WITH TAIL WITH DOUBLE VERTICAL STROKELEFTW" +
"ARDS ARROW THROUGH XWAVE ARROW POINTING DIRECTLY LEFTEQUALS SIGN ABOVE L" +
"EFTWARDS ARROWREVERSE TILDE OPERATOR ABOVE LEFTWARDS ARROWLEFTWARDS ARRO" +
"W ABOVE REVERSE ALMOST EQUAL TORIGHTWARDS ARROW THROUGH GREATER-THANRIGH" +
"TWARDS ARROW THROUGH SUPERSETLEFTWARDS QUADRUPLE ARROWRIGHTWARDS QUADRUP" +
"LE ARROWREVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROWRIGHTWARDS ARROW AB" +
"OVE REVERSE ALMOST EQUAL TOTILDE OPERATOR ABOVE LEFTWARDS ARROWLEFTWARDS" +
" ARROW ABOVE ALMOST EQUAL TOLEFTWARDS ARROW ABOVE REVERSE TILDE OPERATOR" +
"RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATORDOWNWARDS TRIANGLE-HEADED Z" +
"IGZAG ARROWSHORT SLANTED NORTH ARROWSHORT BACKSLANTED SOUTH ARROWWHITE M" +
"EDIUM STARBLACK SMALL STARWHITE SMALL STARBLACK RIGHT-POINTING PENTAGONW" +
"HITE RIGHT-POINTING PENTAGONHEAVY LARGE CIRCLEHEAVY OVAL WITH OVAL INSID" +
"EHEAVY CIRCLE WITH CIRCLE INSIDEHEAVY CIRCLEHEAVY CIRCLED SALTIRESLANTED" +
" NORTH ARROW WITH HOOKED HEADBACKSLANTED SOUTH ARROW WITH HOOKED TAILSLA" +
"NTED NORTH ARROW WITH HORIZONTAL TAILBACKSLANTED SOUTH ARROW WITH HORIZO" +
"NTAL TAILBENT ARROW POINTING DOWNWARDS THEN NORTH EASTSHORT BENT ARROW P" +
"OINTING DOWNWARDS THEN NORTH EASTLEFTWARDS TRIANGLE-HEADED ARROWUPWARDS " +
"TRIANGLE-HEADED ARROWRIGHTWARDS TRIANGLE-HEADED ARROWDOWNWARDS TRIANGLE-" +
"HEADED ARROWLEFT RIGHT TRIANGLE-HEADED ARROWUP DOWN TRIANGLE-HEADED ARRO" +
"WNORTH WEST TRIANGLE-HEADED ARROWNORTH EAST TRIANGLE-HEADED ARROWSOUTH E" +
"AST TRIANGLE-HEADED ARROWSOUTH WEST TRIANGLE-HEADED ARROWLEFTWARDS TRIAN" +
"GLE-HEADED DASHED ARROWUPWARDS TRIANGLE-HEADED DASHED ARROWRIGHTWARDS TR" +
"IANGLE-HEADED DASHED ARROWDOWNWARDS TRIANGLE-HEADED DASHED ARROWCLOCKWIS" +
"E TRIANGLE-HEADED OPEN CIRCLE ARROWANTICLOCKWISE TRIANGLE-HEADED OPEN CI" +
"RCLE ARROWLEFTWARDS TRIANGLE-HEADED ARROW TO BARUPWARDS TRIANGLE-HEADED " +
"ARROW TO BARRIGHTWARDS TRIANGLE-HEADED ARROW TO BARDOWNWARDS TRIANGLE-HE" +
"ADED ARROW TO BARNORTH WEST TRIANGLE-HEADED ARROW TO BARNORTH EAST TRIAN" +
"GLE-HEADED ARROW TO BARSOUTH EAST TRIANGLE-HEADED ARROW TO BARSOUTH WEST" +
" TRIANGLE-HEADED ARROW TO BARLEFTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE" +
" HORIZONTAL STROKEUPWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL S" +
"TROKERIGHTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKEDOWNW" +
"ARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKEHORIZONTAL TAB K" +
"EYVERTICAL TAB KEYLEFTWARDS TRIANGLE-HEADED ARROW OVER RIGHTWARDS TRIANG" +
"LE-HEADED ARROWUPWARDS TRIANGLE-HEADED ARROW LEFTWARDS OF DOWNWARDS TRIA" +
"NGLE-HEADED ARROWRIGHTWARDS TRIANGLE-HEADED ARROW OVER LEFTWARDS TRIANGL" +
"E-HEADED ARROWDOWNWARDS TRIANGLE-HEADED ARROW LEFTWARDS OF UPWARDS TRIAN" +
"GLE-HEADED ARROWLEFTWARDS TRIANGLE-HEADED PAIRED ARROWSUPWARDS TRIANGLE-" +
"HEADED PAIRED ARROWSRIGHTWARDS TRIANGLE-HEADED PAIRED ARROWSDOWNWARDS TR" +
"IANGLE-HEADED PAIRED ARROWSLEFTWARDS BLACK CIRCLED WHITE ARROWUPWARDS BL" +
"ACK CIRCLED WHITE ARROWRIGHTWARDS BLACK CIRCLED WHITE ARROWDOWNWARDS BLA" +
"CK CIRCLED WHITE ARROWANTICLOCKWISE TRIANGLE-HEADED RIGHT U-SHAPED ARROW" +
"ANTICLOCKWISE TRIANGLE-HEADED BOTTOM U-SHAPED ARROWANTICLOCKWISE TRIANGL" +
"E-HEADED LEFT U-SHAPED ARROWANTICLOCKWISE TRIANGLE-HEADED TOP U-SHAPED A" +
"RROWRETURN LEFTRETURN RIGHTNEWLINE LEFTNEWLINE RIGHTFOUR CORNER ARROWS C" +
"IRCLING ANTICLOCKWISERIGHTWARDS BLACK ARROWSYMBOL FOR TYPE A ELECTRONICS" +
"THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEADTHREE-D RIGHT-LIGHTED" +
" UPWARDS EQUILATERAL ARROWHEADTHREE-D TOP-LIGHTED RIGHTWARDS EQUILATERAL" +
" ARROWHEADTHREE-D LEFT-LIGHTED DOWNWARDS EQUILATERAL ARROWHEADBLACK LEFT" +
"WARDS EQUILATERAL ARROWHEADBLACK UPWARDS EQUILATERAL ARROWHEADBLACK RIGH" +
"TWARDS EQUILATERAL ARROWHEADBLACK DOWNWARDS EQUILATERAL ARROWHEADDOWNWAR" +
"DS TRIANGLE-HEADED ARROW WITH LONG TIP LEFTWARDSDOWNWARDS TRIANGLE-HEADE" +
"D ARROW WITH LONG TIP RIGHTWARDSUPWARDS TRIANGLE-HEADED ARROW WITH LONG ") + ("" +
"TIP LEFTWARDSUPWARDS TRIANGLE-HEADED ARROW WITH LONG TIP RIGHTWARDSLEFTW" +
"ARDS TRIANGLE-HEADED ARROW WITH LONG TIP UPWARDSRIGHTWARDS TRIANGLE-HEAD" +
"ED ARROW WITH LONG TIP UPWARDSLEFTWARDS TRIANGLE-HEADED ARROW WITH LONG " +
"TIP DOWNWARDSRIGHTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP DOWNWARDSBLA" +
"CK CURVED DOWNWARDS AND LEFTWARDS ARROWBLACK CURVED DOWNWARDS AND RIGHTW" +
"ARDS ARROWBLACK CURVED UPWARDS AND LEFTWARDS ARROWBLACK CURVED UPWARDS A" +
"ND RIGHTWARDS ARROWBLACK CURVED LEFTWARDS AND UPWARDS ARROWBLACK CURVED " +
"RIGHTWARDS AND UPWARDS ARROWBLACK CURVED LEFTWARDS AND DOWNWARDS ARROWBL" +
"ACK CURVED RIGHTWARDS AND DOWNWARDS ARROWRIBBON ARROW DOWN LEFTRIBBON AR" +
"ROW DOWN RIGHTRIBBON ARROW UP LEFTRIBBON ARROW UP RIGHTRIBBON ARROW LEFT" +
" UPRIBBON ARROW RIGHT UPRIBBON ARROW LEFT DOWNRIBBON ARROW RIGHT DOWNUPW" +
"ARDS WHITE ARROW FROM BAR WITH HORIZONTAL BARUP ARROWHEAD IN A RECTANGLE" +
" BOXOVERLAPPING WHITE SQUARESOVERLAPPING WHITE AND BLACK SQUARESOVERLAPP" +
"ING BLACK SQUARESBALLOT BOX WITH LIGHT XCIRCLED XCIRCLED BOLD XBLACK SQU" +
"ARE CENTREDBLACK DIAMOND CENTREDTURNED BLACK PENTAGONHORIZONTAL BLACK OC" +
"TAGONBLACK OCTAGONBLACK MEDIUM UP-POINTING TRIANGLE CENTREDBLACK MEDIUM " +
"DOWN-POINTING TRIANGLE CENTREDBLACK MEDIUM LEFT-POINTING TRIANGLE CENTRE" +
"DBLACK MEDIUM RIGHT-POINTING TRIANGLE CENTREDNEPTUNE FORM TWOTOP HALF BL" +
"ACK CIRCLEBOTTOM HALF BLACK CIRCLELIGHT FOUR POINTED BLACK CUSPROTATED L" +
"IGHT FOUR POINTED BLACK CUSPWHITE FOUR POINTED CUSPROTATED WHITE FOUR PO" +
"INTED CUSPSQUARE POSITION INDICATORUNCERTAINTY SIGNGROUP MARKPLUTO FORM " +
"TWOPLUTO FORM THREEPLUTO FORM FOURPLUTO FORM FIVETRANSPLUTOPROSERPINAAST" +
"RAEAHYGIEAPHOLUSNESSUSWHITE MOON SELENABLACK DIAMOND ON CROSSTRUE LIGHT " +
"MOON ARTACUPIDOHADESZEUSKRONOSAPOLLONADMETOSVULCANUSPOSEIDONLEFT HALF BL" +
"ACK STARRIGHT HALF BLACK STARSTAR WITH LEFT HALF BLACKSTAR WITH RIGHT HA" +
"LF BLACKLEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADSUPWARDS TWO-H" +
"EADED ARROW WITH TRIANGLE ARROWHEADSRIGHTWARDS TWO-HEADED ARROW WITH TRI" +
"ANGLE ARROWHEADSDOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADSERIS " +
"FORM ONEERIS FORM TWOSEDNARUSSIAN ASTROLOGICAL SYMBOL VIGINTILERUSSIAN A" +
"STROLOGICAL SYMBOL NOVILERUSSIAN ASTROLOGICAL SYMBOL QUINTILERUSSIAN AST" +
"ROLOGICAL SYMBOL BINOVILERUSSIAN ASTROLOGICAL SYMBOL SENTAGONRUSSIAN AST" +
"ROLOGICAL SYMBOL TREDECILEEQUALS SIGN WITH INFINITY BELOWUNITED SYMBOLSE" +
"PARATED SYMBOLDOUBLED SYMBOLPASSED SYMBOLREVERSED RIGHT ANGLEHELLSCHREIB" +
"ER PAUSE SYMBOLGLAGOLITIC CAPITAL LETTER AZUGLAGOLITIC CAPITAL LETTER BU" +
"KYGLAGOLITIC CAPITAL LETTER VEDEGLAGOLITIC CAPITAL LETTER GLAGOLIGLAGOLI" +
"TIC CAPITAL LETTER DOBROGLAGOLITIC CAPITAL LETTER YESTUGLAGOLITIC CAPITA" +
"L LETTER ZHIVETEGLAGOLITIC CAPITAL LETTER DZELOGLAGOLITIC CAPITAL LETTER" +
" ZEMLJAGLAGOLITIC CAPITAL LETTER IZHEGLAGOLITIC CAPITAL LETTER INITIAL I" +
"ZHEGLAGOLITIC CAPITAL LETTER IGLAGOLITIC CAPITAL LETTER DJERVIGLAGOLITIC" +
" CAPITAL LETTER KAKOGLAGOLITIC CAPITAL LETTER LJUDIJEGLAGOLITIC CAPITAL " +
"LETTER MYSLITEGLAGOLITIC CAPITAL LETTER NASHIGLAGOLITIC CAPITAL LETTER O" +
"NUGLAGOLITIC CAPITAL LETTER POKOJIGLAGOLITIC CAPITAL LETTER RITSIGLAGOLI" +
"TIC CAPITAL LETTER SLOVOGLAGOLITIC CAPITAL LETTER TVRIDOGLAGOLITIC CAPIT" +
"AL LETTER UKUGLAGOLITIC CAPITAL LETTER FRITUGLAGOLITIC CAPITAL LETTER HE" +
"RUGLAGOLITIC CAPITAL LETTER OTUGLAGOLITIC CAPITAL LETTER PEGLAGOLITIC CA" +
"PITAL LETTER SHTAGLAGOLITIC CAPITAL LETTER TSIGLAGOLITIC CAPITAL LETTER " +
"CHRIVIGLAGOLITIC CAPITAL LETTER SHAGLAGOLITIC CAPITAL LETTER YERUGLAGOLI" +
"TIC CAPITAL LETTER YERIGLAGOLITIC CAPITAL LETTER YATIGLAGOLITIC CAPITAL " +
"LETTER SPIDERY HAGLAGOLITIC CAPITAL LETTER YUGLAGOLITIC CAPITAL LETTER S" +
"MALL YUSGLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAILGLAGOLITIC CAPITAL " +
"LETTER YOGLAGOLITIC CAPITAL LETTER IOTATED SMALL YUSGLAGOLITIC CAPITAL L" +
"ETTER BIG YUSGLAGOLITIC CAPITAL LETTER IOTATED BIG YUSGLAGOLITIC CAPITAL" +
" LETTER FITAGLAGOLITIC CAPITAL LETTER IZHITSAGLAGOLITIC CAPITAL LETTER S" +
"HTAPICGLAGOLITIC CAPITAL LETTER TROKUTASTI AGLAGOLITIC CAPITAL LETTER LA" +
"TINATE MYSLITEGLAGOLITIC CAPITAL LETTER CAUDATE CHRIVIGLAGOLITIC SMALL L" +
"ETTER AZUGLAGOLITIC SMALL LETTER BUKYGLAGOLITIC SMALL LETTER VEDEGLAGOLI" +
"TIC SMALL LETTER GLAGOLIGLAGOLITIC SMALL LETTER DOBROGLAGOLITIC SMALL LE" +
"TTER YESTUGLAGOLITIC SMALL LETTER ZHIVETEGLAGOLITIC SMALL LETTER DZELOGL" +
"AGOLITIC SMALL LETTER ZEMLJAGLAGOLITIC SMALL LETTER IZHEGLAGOLITIC SMALL" +
" LETTER INITIAL IZHEGLAGOLITIC SMALL LETTER IGLAGOLITIC SMALL LETTER DJE" +
"RVIGLAGOLITIC SMALL LETTER KAKOGLAGOLITIC SMALL LETTER LJUDIJEGLAGOLITIC" +
" SMALL LETTER MYSLITEGLAGOLITIC SMALL LETTER NASHIGLAGOLITIC SMALL LETTE" +
"R ONUGLAGOLITIC SMALL LETTER POKOJIGLAGOLITIC SMALL LETTER RITSIGLAGOLIT" +
"IC SMALL LETTER SLOVOGLAGOLITIC SMALL LETTER TVRIDOGLAGOLITIC SMALL LETT") + ("" +
"ER UKUGLAGOLITIC SMALL LETTER FRITUGLAGOLITIC SMALL LETTER HERUGLAGOLITI" +
"C SMALL LETTER OTUGLAGOLITIC SMALL LETTER PEGLAGOLITIC SMALL LETTER SHTA" +
"GLAGOLITIC SMALL LETTER TSIGLAGOLITIC SMALL LETTER CHRIVIGLAGOLITIC SMAL" +
"L LETTER SHAGLAGOLITIC SMALL LETTER YERUGLAGOLITIC SMALL LETTER YERIGLAG" +
"OLITIC SMALL LETTER YATIGLAGOLITIC SMALL LETTER SPIDERY HAGLAGOLITIC SMA" +
"LL LETTER YUGLAGOLITIC SMALL LETTER SMALL YUSGLAGOLITIC SMALL LETTER SMA" +
"LL YUS WITH TAILGLAGOLITIC SMALL LETTER YOGLAGOLITIC SMALL LETTER IOTATE" +
"D SMALL YUSGLAGOLITIC SMALL LETTER BIG YUSGLAGOLITIC SMALL LETTER IOTATE" +
"D BIG YUSGLAGOLITIC SMALL LETTER FITAGLAGOLITIC SMALL LETTER IZHITSAGLAG" +
"OLITIC SMALL LETTER SHTAPICGLAGOLITIC SMALL LETTER TROKUTASTI AGLAGOLITI" +
"C SMALL LETTER LATINATE MYSLITEGLAGOLITIC SMALL LETTER CAUDATE CHRIVILAT" +
"IN CAPITAL LETTER L WITH DOUBLE BARLATIN SMALL LETTER L WITH DOUBLE BARL" +
"ATIN CAPITAL LETTER L WITH MIDDLE TILDELATIN CAPITAL LETTER P WITH STROK" +
"ELATIN CAPITAL LETTER R WITH TAILLATIN SMALL LETTER A WITH STROKELATIN S" +
"MALL LETTER T WITH DIAGONAL STROKELATIN CAPITAL LETTER H WITH DESCENDERL" +
"ATIN SMALL LETTER H WITH DESCENDERLATIN CAPITAL LETTER K WITH DESCENDERL" +
"ATIN SMALL LETTER K WITH DESCENDERLATIN CAPITAL LETTER Z WITH DESCENDERL" +
"ATIN SMALL LETTER Z WITH DESCENDERLATIN CAPITAL LETTER ALPHALATIN CAPITA" +
"L LETTER M WITH HOOKLATIN CAPITAL LETTER TURNED ALATIN CAPITAL LETTER TU" +
"RNED ALPHALATIN SMALL LETTER V WITH RIGHT HOOKLATIN CAPITAL LETTER W WIT" +
"H HOOKLATIN SMALL LETTER W WITH HOOKLATIN SMALL LETTER V WITH CURLLATIN " +
"CAPITAL LETTER HALF HLATIN SMALL LETTER HALF HLATIN SMALL LETTER TAILLES" +
"S PHILATIN SMALL LETTER E WITH NOTCHLATIN SMALL LETTER TURNED R WITH TAI" +
"LLATIN SMALL LETTER O WITH LOW RING INSIDELATIN LETTER SMALL CAPITAL TUR" +
"NED ELATIN SUBSCRIPT SMALL LETTER JMODIFIER LETTER CAPITAL VLATIN CAPITA" +
"L LETTER S WITH SWASH TAILLATIN CAPITAL LETTER Z WITH SWASH TAILCOPTIC C" +
"APITAL LETTER ALFACOPTIC SMALL LETTER ALFACOPTIC CAPITAL LETTER VIDACOPT" +
"IC SMALL LETTER VIDACOPTIC CAPITAL LETTER GAMMACOPTIC SMALL LETTER GAMMA" +
"COPTIC CAPITAL LETTER DALDACOPTIC SMALL LETTER DALDACOPTIC CAPITAL LETTE" +
"R EIECOPTIC SMALL LETTER EIECOPTIC CAPITAL LETTER SOUCOPTIC SMALL LETTER" +
" SOUCOPTIC CAPITAL LETTER ZATACOPTIC SMALL LETTER ZATACOPTIC CAPITAL LET" +
"TER HATECOPTIC SMALL LETTER HATECOPTIC CAPITAL LETTER THETHECOPTIC SMALL" +
" LETTER THETHECOPTIC CAPITAL LETTER IAUDACOPTIC SMALL LETTER IAUDACOPTIC" +
" CAPITAL LETTER KAPACOPTIC SMALL LETTER KAPACOPTIC CAPITAL LETTER LAULAC" +
"OPTIC SMALL LETTER LAULACOPTIC CAPITAL LETTER MICOPTIC SMALL LETTER MICO" +
"PTIC CAPITAL LETTER NICOPTIC SMALL LETTER NICOPTIC CAPITAL LETTER KSICOP" +
"TIC SMALL LETTER KSICOPTIC CAPITAL LETTER OCOPTIC SMALL LETTER OCOPTIC C" +
"APITAL LETTER PICOPTIC SMALL LETTER PICOPTIC CAPITAL LETTER ROCOPTIC SMA" +
"LL LETTER ROCOPTIC CAPITAL LETTER SIMACOPTIC SMALL LETTER SIMACOPTIC CAP" +
"ITAL LETTER TAUCOPTIC SMALL LETTER TAUCOPTIC CAPITAL LETTER UACOPTIC SMA" +
"LL LETTER UACOPTIC CAPITAL LETTER FICOPTIC SMALL LETTER FICOPTIC CAPITAL" +
" LETTER KHICOPTIC SMALL LETTER KHICOPTIC CAPITAL LETTER PSICOPTIC SMALL " +
"LETTER PSICOPTIC CAPITAL LETTER OOUCOPTIC SMALL LETTER OOUCOPTIC CAPITAL" +
" LETTER DIALECT-P ALEFCOPTIC SMALL LETTER DIALECT-P ALEFCOPTIC CAPITAL L" +
"ETTER OLD COPTIC AINCOPTIC SMALL LETTER OLD COPTIC AINCOPTIC CAPITAL LET" +
"TER CRYPTOGRAMMIC EIECOPTIC SMALL LETTER CRYPTOGRAMMIC EIECOPTIC CAPITAL" +
" LETTER DIALECT-P KAPACOPTIC SMALL LETTER DIALECT-P KAPACOPTIC CAPITAL L" +
"ETTER DIALECT-P NICOPTIC SMALL LETTER DIALECT-P NICOPTIC CAPITAL LETTER " +
"CRYPTOGRAMMIC NICOPTIC SMALL LETTER CRYPTOGRAMMIC NICOPTIC CAPITAL LETTE" +
"R OLD COPTIC OOUCOPTIC SMALL LETTER OLD COPTIC OOUCOPTIC CAPITAL LETTER " +
"SAMPICOPTIC SMALL LETTER SAMPICOPTIC CAPITAL LETTER CROSSED SHEICOPTIC S" +
"MALL LETTER CROSSED SHEICOPTIC CAPITAL LETTER OLD COPTIC SHEICOPTIC SMAL" +
"L LETTER OLD COPTIC SHEICOPTIC CAPITAL LETTER OLD COPTIC ESHCOPTIC SMALL" +
" LETTER OLD COPTIC ESHCOPTIC CAPITAL LETTER AKHMIMIC KHEICOPTIC SMALL LE" +
"TTER AKHMIMIC KHEICOPTIC CAPITAL LETTER DIALECT-P HORICOPTIC SMALL LETTE" +
"R DIALECT-P HORICOPTIC CAPITAL LETTER OLD COPTIC HORICOPTIC SMALL LETTER" +
" OLD COPTIC HORICOPTIC CAPITAL LETTER OLD COPTIC HACOPTIC SMALL LETTER O" +
"LD COPTIC HACOPTIC CAPITAL LETTER L-SHAPED HACOPTIC SMALL LETTER L-SHAPE" +
"D HACOPTIC CAPITAL LETTER OLD COPTIC HEICOPTIC SMALL LETTER OLD COPTIC H" +
"EICOPTIC CAPITAL LETTER OLD COPTIC HATCOPTIC SMALL LETTER OLD COPTIC HAT" +
"COPTIC CAPITAL LETTER OLD COPTIC GANGIACOPTIC SMALL LETTER OLD COPTIC GA" +
"NGIACOPTIC CAPITAL LETTER OLD COPTIC DJACOPTIC SMALL LETTER OLD COPTIC D" +
"JACOPTIC CAPITAL LETTER OLD COPTIC SHIMACOPTIC SMALL LETTER OLD COPTIC S" +
"HIMACOPTIC CAPITAL LETTER OLD NUBIAN SHIMACOPTIC SMALL LETTER OLD NUBIAN") + ("" +
" SHIMACOPTIC CAPITAL LETTER OLD NUBIAN NGICOPTIC SMALL LETTER OLD NUBIAN" +
" NGICOPTIC CAPITAL LETTER OLD NUBIAN NYICOPTIC SMALL LETTER OLD NUBIAN N" +
"YICOPTIC CAPITAL LETTER OLD NUBIAN WAUCOPTIC SMALL LETTER OLD NUBIAN WAU" +
"COPTIC SYMBOL KAICOPTIC SYMBOL MI ROCOPTIC SYMBOL PI ROCOPTIC SYMBOL STA" +
"UROSCOPTIC SYMBOL TAU ROCOPTIC SYMBOL KHI ROCOPTIC SYMBOL SHIMA SIMACOPT" +
"IC CAPITAL LETTER CRYPTOGRAMMIC SHEICOPTIC SMALL LETTER CRYPTOGRAMMIC SH" +
"EICOPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIACOPTIC SMALL LETTER CRYPTOGR" +
"AMMIC GANGIACOPTIC COMBINING NI ABOVECOPTIC COMBINING SPIRITUS ASPERCOPT" +
"IC COMBINING SPIRITUS LENISCOPTIC CAPITAL LETTER BOHAIRIC KHEICOPTIC SMA" +
"LL LETTER BOHAIRIC KHEICOPTIC OLD NUBIAN FULL STOPCOPTIC OLD NUBIAN DIRE" +
"CT QUESTION MARKCOPTIC OLD NUBIAN INDIRECT QUESTION MARKCOPTIC OLD NUBIA" +
"N VERSE DIVIDERCOPTIC FRACTION ONE HALFCOPTIC FULL STOPCOPTIC MORPHOLOGI" +
"CAL DIVIDERGEORGIAN SMALL LETTER ANGEORGIAN SMALL LETTER BANGEORGIAN SMA" +
"LL LETTER GANGEORGIAN SMALL LETTER DONGEORGIAN SMALL LETTER ENGEORGIAN S" +
"MALL LETTER VINGEORGIAN SMALL LETTER ZENGEORGIAN SMALL LETTER TANGEORGIA" +
"N SMALL LETTER INGEORGIAN SMALL LETTER KANGEORGIAN SMALL LETTER LASGEORG" +
"IAN SMALL LETTER MANGEORGIAN SMALL LETTER NARGEORGIAN SMALL LETTER ONGEO" +
"RGIAN SMALL LETTER PARGEORGIAN SMALL LETTER ZHARGEORGIAN SMALL LETTER RA" +
"EGEORGIAN SMALL LETTER SANGEORGIAN SMALL LETTER TARGEORGIAN SMALL LETTER" +
" UNGEORGIAN SMALL LETTER PHARGEORGIAN SMALL LETTER KHARGEORGIAN SMALL LE" +
"TTER GHANGEORGIAN SMALL LETTER QARGEORGIAN SMALL LETTER SHINGEORGIAN SMA" +
"LL LETTER CHINGEORGIAN SMALL LETTER CANGEORGIAN SMALL LETTER JILGEORGIAN" +
" SMALL LETTER CILGEORGIAN SMALL LETTER CHARGEORGIAN SMALL LETTER XANGEOR" +
"GIAN SMALL LETTER JHANGEORGIAN SMALL LETTER HAEGEORGIAN SMALL LETTER HEG" +
"EORGIAN SMALL LETTER HIEGEORGIAN SMALL LETTER WEGEORGIAN SMALL LETTER HA" +
"RGEORGIAN SMALL LETTER HOEGEORGIAN SMALL LETTER YNGEORGIAN SMALL LETTER " +
"AENTIFINAGH LETTER YATIFINAGH LETTER YABTIFINAGH LETTER YABHTIFINAGH LET" +
"TER YAGTIFINAGH LETTER YAGHHTIFINAGH LETTER BERBER ACADEMY YAJTIFINAGH L" +
"ETTER YAJTIFINAGH LETTER YADTIFINAGH LETTER YADHTIFINAGH LETTER YADDTIFI" +
"NAGH LETTER YADDHTIFINAGH LETTER YEYTIFINAGH LETTER YAFTIFINAGH LETTER Y" +
"AKTIFINAGH LETTER TUAREG YAKTIFINAGH LETTER YAKHHTIFINAGH LETTER YAHTIFI" +
"NAGH LETTER BERBER ACADEMY YAHTIFINAGH LETTER TUAREG YAHTIFINAGH LETTER " +
"YAHHTIFINAGH LETTER YAATIFINAGH LETTER YAKHTIFINAGH LETTER TUAREG YAKHTI" +
"FINAGH LETTER YAQTIFINAGH LETTER TUAREG YAQTIFINAGH LETTER YITIFINAGH LE" +
"TTER YAZHTIFINAGH LETTER AHAGGAR YAZHTIFINAGH LETTER TUAREG YAZHTIFINAGH" +
" LETTER YALTIFINAGH LETTER YAMTIFINAGH LETTER YANTIFINAGH LETTER TUAREG " +
"YAGNTIFINAGH LETTER TUAREG YANGTIFINAGH LETTER YAPTIFINAGH LETTER YUTIFI" +
"NAGH LETTER YARTIFINAGH LETTER YARRTIFINAGH LETTER YAGHTIFINAGH LETTER T" +
"UAREG YAGHTIFINAGH LETTER AYER YAGHTIFINAGH LETTER YASTIFINAGH LETTER YA" +
"SSTIFINAGH LETTER YASHTIFINAGH LETTER YATTIFINAGH LETTER YATHTIFINAGH LE" +
"TTER YACHTIFINAGH LETTER YATTTIFINAGH LETTER YAVTIFINAGH LETTER YAWTIFIN" +
"AGH LETTER YAYTIFINAGH LETTER YAZTIFINAGH LETTER TAWELLEMET YAZTIFINAGH " +
"LETTER YAZZTIFINAGH LETTER YETIFINAGH LETTER YOTIFINAGH MODIFIER LETTER " +
"LABIALIZATION MARKTIFINAGH SEPARATOR MARKTIFINAGH CONSONANT JOINERETHIOP" +
"IC SYLLABLE LOAETHIOPIC SYLLABLE MOAETHIOPIC SYLLABLE ROAETHIOPIC SYLLAB" +
"LE SOAETHIOPIC SYLLABLE SHOAETHIOPIC SYLLABLE BOAETHIOPIC SYLLABLE TOAET" +
"HIOPIC SYLLABLE COAETHIOPIC SYLLABLE NOAETHIOPIC SYLLABLE NYOAETHIOPIC S" +
"YLLABLE GLOTTAL OAETHIOPIC SYLLABLE ZOAETHIOPIC SYLLABLE DOAETHIOPIC SYL" +
"LABLE DDOAETHIOPIC SYLLABLE JOAETHIOPIC SYLLABLE THOAETHIOPIC SYLLABLE C" +
"HOAETHIOPIC SYLLABLE PHOAETHIOPIC SYLLABLE POAETHIOPIC SYLLABLE GGWAETHI" +
"OPIC SYLLABLE GGWIETHIOPIC SYLLABLE GGWEEETHIOPIC SYLLABLE GGWEETHIOPIC " +
"SYLLABLE SSAETHIOPIC SYLLABLE SSUETHIOPIC SYLLABLE SSIETHIOPIC SYLLABLE " +
"SSAAETHIOPIC SYLLABLE SSEEETHIOPIC SYLLABLE SSEETHIOPIC SYLLABLE SSOETHI" +
"OPIC SYLLABLE CCAETHIOPIC SYLLABLE CCUETHIOPIC SYLLABLE CCIETHIOPIC SYLL" +
"ABLE CCAAETHIOPIC SYLLABLE CCEEETHIOPIC SYLLABLE CCEETHIOPIC SYLLABLE CC" +
"OETHIOPIC SYLLABLE ZZAETHIOPIC SYLLABLE ZZUETHIOPIC SYLLABLE ZZIETHIOPIC" +
" SYLLABLE ZZAAETHIOPIC SYLLABLE ZZEEETHIOPIC SYLLABLE ZZEETHIOPIC SYLLAB" +
"LE ZZOETHIOPIC SYLLABLE CCHAETHIOPIC SYLLABLE CCHUETHIOPIC SYLLABLE CCHI" +
"ETHIOPIC SYLLABLE CCHAAETHIOPIC SYLLABLE CCHEEETHIOPIC SYLLABLE CCHEETHI" +
"OPIC SYLLABLE CCHOETHIOPIC SYLLABLE QYAETHIOPIC SYLLABLE QYUETHIOPIC SYL" +
"LABLE QYIETHIOPIC SYLLABLE QYAAETHIOPIC SYLLABLE QYEEETHIOPIC SYLLABLE Q" +
"YEETHIOPIC SYLLABLE QYOETHIOPIC SYLLABLE KYAETHIOPIC SYLLABLE KYUETHIOPI" +
"C SYLLABLE KYIETHIOPIC SYLLABLE KYAAETHIOPIC SYLLABLE KYEEETHIOPIC SYLLA" +
"BLE KYEETHIOPIC SYLLABLE KYOETHIOPIC SYLLABLE XYAETHIOPIC SYLLABLE XYUET") + ("" +
"HIOPIC SYLLABLE XYIETHIOPIC SYLLABLE XYAAETHIOPIC SYLLABLE XYEEETHIOPIC " +
"SYLLABLE XYEETHIOPIC SYLLABLE XYOETHIOPIC SYLLABLE GYAETHIOPIC SYLLABLE " +
"GYUETHIOPIC SYLLABLE GYIETHIOPIC SYLLABLE GYAAETHIOPIC SYLLABLE GYEEETHI" +
"OPIC SYLLABLE GYEETHIOPIC SYLLABLE GYOCOMBINING CYRILLIC LETTER BECOMBIN" +
"ING CYRILLIC LETTER VECOMBINING CYRILLIC LETTER GHECOMBINING CYRILLIC LE" +
"TTER DECOMBINING CYRILLIC LETTER ZHECOMBINING CYRILLIC LETTER ZECOMBININ" +
"G CYRILLIC LETTER KACOMBINING CYRILLIC LETTER ELCOMBINING CYRILLIC LETTE" +
"R EMCOMBINING CYRILLIC LETTER ENCOMBINING CYRILLIC LETTER OCOMBINING CYR" +
"ILLIC LETTER PECOMBINING CYRILLIC LETTER ERCOMBINING CYRILLIC LETTER ESC" +
"OMBINING CYRILLIC LETTER TECOMBINING CYRILLIC LETTER HACOMBINING CYRILLI" +
"C LETTER TSECOMBINING CYRILLIC LETTER CHECOMBINING CYRILLIC LETTER SHACO" +
"MBINING CYRILLIC LETTER SHCHACOMBINING CYRILLIC LETTER FITACOMBINING CYR" +
"ILLIC LETTER ES-TECOMBINING CYRILLIC LETTER ACOMBINING CYRILLIC LETTER I" +
"ECOMBINING CYRILLIC LETTER DJERVCOMBINING CYRILLIC LETTER MONOGRAPH UKCO" +
"MBINING CYRILLIC LETTER YATCOMBINING CYRILLIC LETTER YUCOMBINING CYRILLI" +
"C LETTER IOTIFIED ACOMBINING CYRILLIC LETTER LITTLE YUSCOMBINING CYRILLI" +
"C LETTER BIG YUSCOMBINING CYRILLIC LETTER IOTIFIED BIG YUSRIGHT ANGLE SU" +
"BSTITUTION MARKERRIGHT ANGLE DOTTED SUBSTITUTION MARKERLEFT SUBSTITUTION" +
" BRACKETRIGHT SUBSTITUTION BRACKETLEFT DOTTED SUBSTITUTION BRACKETRIGHT " +
"DOTTED SUBSTITUTION BRACKETRAISED INTERPOLATION MARKERRAISED DOTTED INTE" +
"RPOLATION MARKERDOTTED TRANSPOSITION MARKERLEFT TRANSPOSITION BRACKETRIG" +
"HT TRANSPOSITION BRACKETRAISED SQUARELEFT RAISED OMISSION BRACKETRIGHT R" +
"AISED OMISSION BRACKETEDITORIAL CORONISPARAGRAPHOSFORKED PARAGRAPHOSREVE" +
"RSED FORKED PARAGRAPHOSHYPODIASTOLEDOTTED OBELOSDOWNWARDS ANCORAUPWARDS " +
"ANCORADOTTED RIGHT-POINTING ANGLEDOUBLE OBLIQUE HYPHENINVERTED INTERROBA" +
"NGPALM BRANCHHYPHEN WITH DIAERESISTILDE WITH RING ABOVELEFT LOW PARAPHRA" +
"SE BRACKETRIGHT LOW PARAPHRASE BRACKETTILDE WITH DOT ABOVETILDE WITH DOT" +
" BELOWLEFT VERTICAL BAR WITH QUILLRIGHT VERTICAL BAR WITH QUILLTOP LEFT " +
"HALF BRACKETTOP RIGHT HALF BRACKETBOTTOM LEFT HALF BRACKETBOTTOM RIGHT H" +
"ALF BRACKETLEFT SIDEWAYS U BRACKETRIGHT SIDEWAYS U BRACKETLEFT DOUBLE PA" +
"RENTHESISRIGHT DOUBLE PARENTHESISTWO DOTS OVER ONE DOT PUNCTUATIONONE DO" +
"T OVER TWO DOTS PUNCTUATIONSQUARED FOUR DOT PUNCTUATIONFIVE DOT MARKREVE" +
"RSED QUESTION MARKVERTICAL TILDERING POINTWORD SEPARATOR MIDDLE DOTTURNE" +
"D COMMARAISED DOTRAISED COMMATURNED SEMICOLONDAGGER WITH LEFT GUARDDAGGE" +
"R WITH RIGHT GUARDTURNED DAGGERTOP HALF SECTION SIGNTWO-EM DASHTHREE-EM " +
"DASHSTENOGRAPHIC FULL STOPVERTICAL SIX DOTSWIGGLY VERTICAL LINECAPITULUM" +
"DOUBLE HYPHENREVERSED COMMADOUBLE LOW-REVERSED-9 QUOTATION MARKDASH WITH" +
" LEFT UPTURNDOUBLE SUSPENSION MARKINVERTED LOW KAVYKAINVERTED LOW KAVYKA" +
" WITH KAVYKA ABOVELOW KAVYKALOW KAVYKA WITH DOTDOUBLE STACKED COMMADOTTE" +
"D SOLIDUSTRIPLE DAGGERMEDIEVAL COMMAPARAGRAPHUS MARKPUNCTUS ELEVATUS MAR" +
"KCORNISH VERSE DIVIDERCROSS PATTY WITH RIGHT CROSSBARCROSS PATTY WITH LE" +
"FT CROSSBARTIRONIAN SIGN CAPITAL ETMEDIEVAL EXCLAMATION MARKMEDIEVAL QUE" +
"STION MARKLEFT SQUARE BRACKET WITH STROKERIGHT SQUARE BRACKET WITH STROK" +
"ELEFT SQUARE BRACKET WITH DOUBLE STROKERIGHT SQUARE BRACKET WITH DOUBLE " +
"STROKETOP HALF LEFT PARENTHESISTOP HALF RIGHT PARENTHESISBOTTOM HALF LEF" +
"T PARENTHESISBOTTOM HALF RIGHT PARENTHESISOBLIQUE HYPHENCJK RADICAL REPE" +
"ATCJK RADICAL CLIFFCJK RADICAL SECOND ONECJK RADICAL SECOND TWOCJK RADIC" +
"AL SECOND THREECJK RADICAL PERSONCJK RADICAL BOXCJK RADICAL TABLECJK RAD" +
"ICAL KNIFE ONECJK RADICAL KNIFE TWOCJK RADICAL DIVINATIONCJK RADICAL SEA" +
"LCJK RADICAL SMALL ONECJK RADICAL SMALL TWOCJK RADICAL LAME ONECJK RADIC" +
"AL LAME TWOCJK RADICAL LAME THREECJK RADICAL LAME FOURCJK RADICAL SNAKEC" +
"JK RADICAL THREADCJK RADICAL SNOUT ONECJK RADICAL SNOUT TWOCJK RADICAL H" +
"EART ONECJK RADICAL HEART TWOCJK RADICAL HANDCJK RADICAL RAPCJK RADICAL " +
"CHOKECJK RADICAL SUNCJK RADICAL MOONCJK RADICAL DEATHCJK RADICAL MOTHERC" +
"JK RADICAL CIVILIANCJK RADICAL WATER ONECJK RADICAL WATER TWOCJK RADICAL" +
" FIRECJK RADICAL PAW ONECJK RADICAL PAW TWOCJK RADICAL SIMPLIFIED HALF T" +
"REE TRUNKCJK RADICAL COWCJK RADICAL DOGCJK RADICAL JADECJK RADICAL BOLT " +
"OF CLOTHCJK RADICAL EYECJK RADICAL SPIRIT ONECJK RADICAL SPIRIT TWOCJK R" +
"ADICAL BAMBOOCJK RADICAL SILKCJK RADICAL C-SIMPLIFIED SILKCJK RADICAL NE" +
"T ONECJK RADICAL NET TWOCJK RADICAL NET THREECJK RADICAL NET FOURCJK RAD" +
"ICAL MESHCJK RADICAL SHEEPCJK RADICAL RAMCJK RADICAL EWECJK RADICAL OLDC" +
"JK RADICAL BRUSH ONECJK RADICAL BRUSH TWOCJK RADICAL MEATCJK RADICAL MOR" +
"TARCJK RADICAL GRASS ONECJK RADICAL GRASS TWOCJK RADICAL GRASS THREECJK " +
"RADICAL TIGERCJK RADICAL CLOTHESCJK RADICAL WEST ONECJK RADICAL WEST TWO") + ("" +
"CJK RADICAL C-SIMPLIFIED SEECJK RADICAL SIMPLIFIED HORNCJK RADICAL HORNC" +
"JK RADICAL C-SIMPLIFIED SPEECHCJK RADICAL C-SIMPLIFIED SHELLCJK RADICAL " +
"FOOTCJK RADICAL C-SIMPLIFIED CARTCJK RADICAL SIMPLIFIED WALKCJK RADICAL " +
"WALK ONECJK RADICAL WALK TWOCJK RADICAL CITYCJK RADICAL C-SIMPLIFIED GOL" +
"DCJK RADICAL LONG ONECJK RADICAL LONG TWOCJK RADICAL C-SIMPLIFIED LONGCJ" +
"K RADICAL C-SIMPLIFIED GATECJK RADICAL MOUND ONECJK RADICAL MOUND TWOCJK" +
" RADICAL RAINCJK RADICAL BLUECJK RADICAL C-SIMPLIFIED TANNED LEATHERCJK " +
"RADICAL C-SIMPLIFIED LEAFCJK RADICAL C-SIMPLIFIED WINDCJK RADICAL C-SIMP" +
"LIFIED FLYCJK RADICAL EAT ONECJK RADICAL EAT TWOCJK RADICAL EAT THREECJK" +
" RADICAL C-SIMPLIFIED EATCJK RADICAL HEADCJK RADICAL C-SIMPLIFIED HORSEC" +
"JK RADICAL BONECJK RADICAL GHOSTCJK RADICAL C-SIMPLIFIED FISHCJK RADICAL" +
" C-SIMPLIFIED BIRDCJK RADICAL C-SIMPLIFIED SALTCJK RADICAL SIMPLIFIED WH" +
"EATCJK RADICAL SIMPLIFIED YELLOWCJK RADICAL C-SIMPLIFIED FROGCJK RADICAL" +
" J-SIMPLIFIED EVENCJK RADICAL C-SIMPLIFIED EVENCJK RADICAL J-SIMPLIFIED " +
"TOOTHCJK RADICAL C-SIMPLIFIED TOOTHCJK RADICAL J-SIMPLIFIED DRAGONCJK RA" +
"DICAL C-SIMPLIFIED DRAGONCJK RADICAL TURTLECJK RADICAL J-SIMPLIFIED TURT" +
"LECJK RADICAL C-SIMPLIFIED TURTLEKANGXI RADICAL ONEKANGXI RADICAL LINEKA" +
"NGXI RADICAL DOTKANGXI RADICAL SLASHKANGXI RADICAL SECONDKANGXI RADICAL " +
"HOOKKANGXI RADICAL TWOKANGXI RADICAL LIDKANGXI RADICAL MANKANGXI RADICAL" +
" LEGSKANGXI RADICAL ENTERKANGXI RADICAL EIGHTKANGXI RADICAL DOWN BOXKANG" +
"XI RADICAL COVERKANGXI RADICAL ICEKANGXI RADICAL TABLEKANGXI RADICAL OPE" +
"N BOXKANGXI RADICAL KNIFEKANGXI RADICAL POWERKANGXI RADICAL WRAPKANGXI R" +
"ADICAL SPOONKANGXI RADICAL RIGHT OPEN BOXKANGXI RADICAL HIDING ENCLOSURE" +
"KANGXI RADICAL TENKANGXI RADICAL DIVINATIONKANGXI RADICAL SEALKANGXI RAD" +
"ICAL CLIFFKANGXI RADICAL PRIVATEKANGXI RADICAL AGAINKANGXI RADICAL MOUTH" +
"KANGXI RADICAL ENCLOSUREKANGXI RADICAL EARTHKANGXI RADICAL SCHOLARKANGXI" +
" RADICAL GOKANGXI RADICAL GO SLOWLYKANGXI RADICAL EVENINGKANGXI RADICAL " +
"BIGKANGXI RADICAL WOMANKANGXI RADICAL CHILDKANGXI RADICAL ROOFKANGXI RAD" +
"ICAL INCHKANGXI RADICAL SMALLKANGXI RADICAL LAMEKANGXI RADICAL CORPSEKAN" +
"GXI RADICAL SPROUTKANGXI RADICAL MOUNTAINKANGXI RADICAL RIVERKANGXI RADI" +
"CAL WORKKANGXI RADICAL ONESELFKANGXI RADICAL TURBANKANGXI RADICAL DRYKAN" +
"GXI RADICAL SHORT THREADKANGXI RADICAL DOTTED CLIFFKANGXI RADICAL LONG S" +
"TRIDEKANGXI RADICAL TWO HANDSKANGXI RADICAL SHOOTKANGXI RADICAL BOWKANGX" +
"I RADICAL SNOUTKANGXI RADICAL BRISTLEKANGXI RADICAL STEPKANGXI RADICAL H" +
"EARTKANGXI RADICAL HALBERDKANGXI RADICAL DOORKANGXI RADICAL HANDKANGXI R" +
"ADICAL BRANCHKANGXI RADICAL RAPKANGXI RADICAL SCRIPTKANGXI RADICAL DIPPE" +
"RKANGXI RADICAL AXEKANGXI RADICAL SQUAREKANGXI RADICAL NOTKANGXI RADICAL" +
" SUNKANGXI RADICAL SAYKANGXI RADICAL MOONKANGXI RADICAL TREEKANGXI RADIC" +
"AL LACKKANGXI RADICAL STOPKANGXI RADICAL DEATHKANGXI RADICAL WEAPONKANGX" +
"I RADICAL DO NOTKANGXI RADICAL COMPAREKANGXI RADICAL FURKANGXI RADICAL C" +
"LANKANGXI RADICAL STEAMKANGXI RADICAL WATERKANGXI RADICAL FIREKANGXI RAD" +
"ICAL CLAWKANGXI RADICAL FATHERKANGXI RADICAL DOUBLE XKANGXI RADICAL HALF" +
" TREE TRUNKKANGXI RADICAL SLICEKANGXI RADICAL FANGKANGXI RADICAL COWKANG" +
"XI RADICAL DOGKANGXI RADICAL PROFOUNDKANGXI RADICAL JADEKANGXI RADICAL M" +
"ELONKANGXI RADICAL TILEKANGXI RADICAL SWEETKANGXI RADICAL LIFEKANGXI RAD" +
"ICAL USEKANGXI RADICAL FIELDKANGXI RADICAL BOLT OF CLOTHKANGXI RADICAL S" +
"ICKNESSKANGXI RADICAL DOTTED TENTKANGXI RADICAL WHITEKANGXI RADICAL SKIN" +
"KANGXI RADICAL DISHKANGXI RADICAL EYEKANGXI RADICAL SPEARKANGXI RADICAL " +
"ARROWKANGXI RADICAL STONEKANGXI RADICAL SPIRITKANGXI RADICAL TRACKKANGXI" +
" RADICAL GRAINKANGXI RADICAL CAVEKANGXI RADICAL STANDKANGXI RADICAL BAMB" +
"OOKANGXI RADICAL RICEKANGXI RADICAL SILKKANGXI RADICAL JARKANGXI RADICAL" +
" NETKANGXI RADICAL SHEEPKANGXI RADICAL FEATHERKANGXI RADICAL OLDKANGXI R" +
"ADICAL ANDKANGXI RADICAL PLOWKANGXI RADICAL EARKANGXI RADICAL BRUSHKANGX" +
"I RADICAL MEATKANGXI RADICAL MINISTERKANGXI RADICAL SELFKANGXI RADICAL A" +
"RRIVEKANGXI RADICAL MORTARKANGXI RADICAL TONGUEKANGXI RADICAL OPPOSEKANG" +
"XI RADICAL BOATKANGXI RADICAL STOPPINGKANGXI RADICAL COLORKANGXI RADICAL" +
" GRASSKANGXI RADICAL TIGERKANGXI RADICAL INSECTKANGXI RADICAL BLOODKANGX" +
"I RADICAL WALK ENCLOSUREKANGXI RADICAL CLOTHESKANGXI RADICAL WESTKANGXI " +
"RADICAL SEEKANGXI RADICAL HORNKANGXI RADICAL SPEECHKANGXI RADICAL VALLEY" +
"KANGXI RADICAL BEANKANGXI RADICAL PIGKANGXI RADICAL BADGERKANGXI RADICAL" +
" SHELLKANGXI RADICAL REDKANGXI RADICAL RUNKANGXI RADICAL FOOTKANGXI RADI" +
"CAL BODYKANGXI RADICAL CARTKANGXI RADICAL BITTERKANGXI RADICAL MORNINGKA" +
"NGXI RADICAL WALKKANGXI RADICAL CITYKANGXI RADICAL WINEKANGXI RADICAL DI" +
"STINGUISHKANGXI RADICAL VILLAGEKANGXI RADICAL GOLDKANGXI RADICAL LONGKAN") + ("" +
"GXI RADICAL GATEKANGXI RADICAL MOUNDKANGXI RADICAL SLAVEKANGXI RADICAL S" +
"HORT TAILED BIRDKANGXI RADICAL RAINKANGXI RADICAL BLUEKANGXI RADICAL WRO" +
"NGKANGXI RADICAL FACEKANGXI RADICAL LEATHERKANGXI RADICAL TANNED LEATHER" +
"KANGXI RADICAL LEEKKANGXI RADICAL SOUNDKANGXI RADICAL LEAFKANGXI RADICAL" +
" WINDKANGXI RADICAL FLYKANGXI RADICAL EATKANGXI RADICAL HEADKANGXI RADIC" +
"AL FRAGRANTKANGXI RADICAL HORSEKANGXI RADICAL BONEKANGXI RADICAL TALLKAN" +
"GXI RADICAL HAIRKANGXI RADICAL FIGHTKANGXI RADICAL SACRIFICIAL WINEKANGX" +
"I RADICAL CAULDRONKANGXI RADICAL GHOSTKANGXI RADICAL FISHKANGXI RADICAL " +
"BIRDKANGXI RADICAL SALTKANGXI RADICAL DEERKANGXI RADICAL WHEATKANGXI RAD" +
"ICAL HEMPKANGXI RADICAL YELLOWKANGXI RADICAL MILLETKANGXI RADICAL BLACKK" +
"ANGXI RADICAL EMBROIDERYKANGXI RADICAL FROGKANGXI RADICAL TRIPODKANGXI R" +
"ADICAL DRUMKANGXI RADICAL RATKANGXI RADICAL NOSEKANGXI RADICAL EVENKANGX" +
"I RADICAL TOOTHKANGXI RADICAL DRAGONKANGXI RADICAL TURTLEKANGXI RADICAL " +
"FLUTEIDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHTIDEOGRAPHIC DESCRIPT" +
"ION CHARACTER ABOVE TO BELOWIDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO MI" +
"DDLE AND RIGHTIDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO MIDDLE AND BELO" +
"WIDEOGRAPHIC DESCRIPTION CHARACTER FULL SURROUNDIDEOGRAPHIC DESCRIPTION " +
"CHARACTER SURROUND FROM ABOVEIDEOGRAPHIC DESCRIPTION CHARACTER SURROUND " +
"FROM BELOWIDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LEFTIDEOGRAPHI" +
"C DESCRIPTION CHARACTER SURROUND FROM UPPER LEFTIDEOGRAPHIC DESCRIPTION " +
"CHARACTER SURROUND FROM UPPER RIGHTIDEOGRAPHIC DESCRIPTION CHARACTER SUR" +
"ROUND FROM LOWER LEFTIDEOGRAPHIC DESCRIPTION CHARACTER OVERLAIDIDEOGRAPH" +
"IC SPACEIDEOGRAPHIC COMMAIDEOGRAPHIC FULL STOPDITTO MARKJAPANESE INDUSTR" +
"IAL STANDARD SYMBOLIDEOGRAPHIC ITERATION MARKIDEOGRAPHIC CLOSING MARKIDE" +
"OGRAPHIC NUMBER ZEROLEFT ANGLE BRACKETRIGHT ANGLE BRACKETLEFT DOUBLE ANG" +
"LE BRACKETRIGHT DOUBLE ANGLE BRACKETLEFT CORNER BRACKETRIGHT CORNER BRAC" +
"KETLEFT WHITE CORNER BRACKETRIGHT WHITE CORNER BRACKETLEFT BLACK LENTICU" +
"LAR BRACKETRIGHT BLACK LENTICULAR BRACKETPOSTAL MARKGETA MARKLEFT TORTOI" +
"SE SHELL BRACKETRIGHT TORTOISE SHELL BRACKETLEFT WHITE LENTICULAR BRACKE" +
"TRIGHT WHITE LENTICULAR BRACKETLEFT WHITE TORTOISE SHELL BRACKETRIGHT WH" +
"ITE TORTOISE SHELL BRACKETLEFT WHITE SQUARE BRACKETRIGHT WHITE SQUARE BR" +
"ACKETWAVE DASHREVERSED DOUBLE PRIME QUOTATION MARKDOUBLE PRIME QUOTATION" +
" MARKLOW DOUBLE PRIME QUOTATION MARKPOSTAL MARK FACEHANGZHOU NUMERAL ONE" +
"HANGZHOU NUMERAL TWOHANGZHOU NUMERAL THREEHANGZHOU NUMERAL FOURHANGZHOU " +
"NUMERAL FIVEHANGZHOU NUMERAL SIXHANGZHOU NUMERAL SEVENHANGZHOU NUMERAL E" +
"IGHTHANGZHOU NUMERAL NINEIDEOGRAPHIC LEVEL TONE MARKIDEOGRAPHIC RISING T" +
"ONE MARKIDEOGRAPHIC DEPARTING TONE MARKIDEOGRAPHIC ENTERING TONE MARKHAN" +
"GUL SINGLE DOT TONE MARKHANGUL DOUBLE DOT TONE MARKWAVY DASHVERTICAL KAN" +
"A REPEAT MARKVERTICAL KANA REPEAT WITH VOICED SOUND MARKVERTICAL KANA RE" +
"PEAT MARK UPPER HALFVERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HA" +
"LFVERTICAL KANA REPEAT MARK LOWER HALFCIRCLED POSTAL MARKIDEOGRAPHIC TEL" +
"EGRAPH LINE FEED SEPARATOR SYMBOLHANGZHOU NUMERAL TENHANGZHOU NUMERAL TW" +
"ENTYHANGZHOU NUMERAL THIRTYVERTICAL IDEOGRAPHIC ITERATION MARKMASU MARKP" +
"ART ALTERNATION MARKIDEOGRAPHIC VARIATION INDICATORIDEOGRAPHIC HALF FILL" +
" SPACEHIRAGANA LETTER SMALL AHIRAGANA LETTER AHIRAGANA LETTER SMALL IHIR" +
"AGANA LETTER IHIRAGANA LETTER SMALL UHIRAGANA LETTER UHIRAGANA LETTER SM" +
"ALL EHIRAGANA LETTER EHIRAGANA LETTER SMALL OHIRAGANA LETTER OHIRAGANA L" +
"ETTER KAHIRAGANA LETTER GAHIRAGANA LETTER KIHIRAGANA LETTER GIHIRAGANA L" +
"ETTER KUHIRAGANA LETTER GUHIRAGANA LETTER KEHIRAGANA LETTER GEHIRAGANA L" +
"ETTER KOHIRAGANA LETTER GOHIRAGANA LETTER SAHIRAGANA LETTER ZAHIRAGANA L" +
"ETTER SIHIRAGANA LETTER ZIHIRAGANA LETTER SUHIRAGANA LETTER ZUHIRAGANA L" +
"ETTER SEHIRAGANA LETTER ZEHIRAGANA LETTER SOHIRAGANA LETTER ZOHIRAGANA L" +
"ETTER TAHIRAGANA LETTER DAHIRAGANA LETTER TIHIRAGANA LETTER DIHIRAGANA L" +
"ETTER SMALL TUHIRAGANA LETTER TUHIRAGANA LETTER DUHIRAGANA LETTER TEHIRA" +
"GANA LETTER DEHIRAGANA LETTER TOHIRAGANA LETTER DOHIRAGANA LETTER NAHIRA" +
"GANA LETTER NIHIRAGANA LETTER NUHIRAGANA LETTER NEHIRAGANA LETTER NOHIRA" +
"GANA LETTER HAHIRAGANA LETTER BAHIRAGANA LETTER PAHIRAGANA LETTER HIHIRA" +
"GANA LETTER BIHIRAGANA LETTER PIHIRAGANA LETTER HUHIRAGANA LETTER BUHIRA" +
"GANA LETTER PUHIRAGANA LETTER HEHIRAGANA LETTER BEHIRAGANA LETTER PEHIRA" +
"GANA LETTER HOHIRAGANA LETTER BOHIRAGANA LETTER POHIRAGANA LETTER MAHIRA" +
"GANA LETTER MIHIRAGANA LETTER MUHIRAGANA LETTER MEHIRAGANA LETTER MOHIRA" +
"GANA LETTER SMALL YAHIRAGANA LETTER YAHIRAGANA LETTER SMALL YUHIRAGANA L" +
"ETTER YUHIRAGANA LETTER SMALL YOHIRAGANA LETTER YOHIRAGANA LETTER RAHIRA" +
"GANA LETTER RIHIRAGANA LETTER RUHIRAGANA LETTER REHIRAGANA LETTER ROHIRA") + ("" +
"GANA LETTER SMALL WAHIRAGANA LETTER WAHIRAGANA LETTER WIHIRAGANA LETTER " +
"WEHIRAGANA LETTER WOHIRAGANA LETTER NHIRAGANA LETTER VUHIRAGANA LETTER S" +
"MALL KAHIRAGANA LETTER SMALL KECOMBINING KATAKANA-HIRAGANA VOICED SOUND " +
"MARKCOMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARKKATAKANA-HIRAGANA " +
"VOICED SOUND MARKKATAKANA-HIRAGANA SEMI-VOICED SOUND MARKHIRAGANA ITERAT" +
"ION MARKHIRAGANA VOICED ITERATION MARKHIRAGANA DIGRAPH YORIKATAKANA-HIRA" +
"GANA DOUBLE HYPHENKATAKANA LETTER SMALL AKATAKANA LETTER AKATAKANA LETTE" +
"R SMALL IKATAKANA LETTER IKATAKANA LETTER SMALL UKATAKANA LETTER UKATAKA" +
"NA LETTER SMALL EKATAKANA LETTER EKATAKANA LETTER SMALL OKATAKANA LETTER" +
" OKATAKANA LETTER KAKATAKANA LETTER GAKATAKANA LETTER KIKATAKANA LETTER " +
"GIKATAKANA LETTER KUKATAKANA LETTER GUKATAKANA LETTER KEKATAKANA LETTER " +
"GEKATAKANA LETTER KOKATAKANA LETTER GOKATAKANA LETTER SAKATAKANA LETTER " +
"ZAKATAKANA LETTER SIKATAKANA LETTER ZIKATAKANA LETTER SUKATAKANA LETTER " +
"ZUKATAKANA LETTER SEKATAKANA LETTER ZEKATAKANA LETTER SOKATAKANA LETTER " +
"ZOKATAKANA LETTER TAKATAKANA LETTER DAKATAKANA LETTER TIKATAKANA LETTER " +
"DIKATAKANA LETTER SMALL TUKATAKANA LETTER TUKATAKANA LETTER DUKATAKANA L" +
"ETTER TEKATAKANA LETTER DEKATAKANA LETTER TOKATAKANA LETTER DOKATAKANA L" +
"ETTER NAKATAKANA LETTER NIKATAKANA LETTER NUKATAKANA LETTER NEKATAKANA L" +
"ETTER NOKATAKANA LETTER HAKATAKANA LETTER BAKATAKANA LETTER PAKATAKANA L" +
"ETTER HIKATAKANA LETTER BIKATAKANA LETTER PIKATAKANA LETTER HUKATAKANA L" +
"ETTER BUKATAKANA LETTER PUKATAKANA LETTER HEKATAKANA LETTER BEKATAKANA L" +
"ETTER PEKATAKANA LETTER HOKATAKANA LETTER BOKATAKANA LETTER POKATAKANA L" +
"ETTER MAKATAKANA LETTER MIKATAKANA LETTER MUKATAKANA LETTER MEKATAKANA L" +
"ETTER MOKATAKANA LETTER SMALL YAKATAKANA LETTER YAKATAKANA LETTER SMALL " +
"YUKATAKANA LETTER YUKATAKANA LETTER SMALL YOKATAKANA LETTER YOKATAKANA L" +
"ETTER RAKATAKANA LETTER RIKATAKANA LETTER RUKATAKANA LETTER REKATAKANA L" +
"ETTER ROKATAKANA LETTER SMALL WAKATAKANA LETTER WAKATAKANA LETTER WIKATA" +
"KANA LETTER WEKATAKANA LETTER WOKATAKANA LETTER NKATAKANA LETTER VUKATAK" +
"ANA LETTER SMALL KAKATAKANA LETTER SMALL KEKATAKANA LETTER VAKATAKANA LE" +
"TTER VIKATAKANA LETTER VEKATAKANA LETTER VOKATAKANA MIDDLE DOTKATAKANA-H" +
"IRAGANA PROLONGED SOUND MARKKATAKANA ITERATION MARKKATAKANA VOICED ITERA" +
"TION MARKKATAKANA DIGRAPH KOTOBOPOMOFO LETTER BBOPOMOFO LETTER PBOPOMOFO" +
" LETTER MBOPOMOFO LETTER FBOPOMOFO LETTER DBOPOMOFO LETTER TBOPOMOFO LET" +
"TER NBOPOMOFO LETTER LBOPOMOFO LETTER GBOPOMOFO LETTER KBOPOMOFO LETTER " +
"HBOPOMOFO LETTER JBOPOMOFO LETTER QBOPOMOFO LETTER XBOPOMOFO LETTER ZHBO" +
"POMOFO LETTER CHBOPOMOFO LETTER SHBOPOMOFO LETTER RBOPOMOFO LETTER ZBOPO" +
"MOFO LETTER CBOPOMOFO LETTER SBOPOMOFO LETTER ABOPOMOFO LETTER OBOPOMOFO" +
" LETTER EBOPOMOFO LETTER EHBOPOMOFO LETTER AIBOPOMOFO LETTER EIBOPOMOFO " +
"LETTER AUBOPOMOFO LETTER OUBOPOMOFO LETTER ANBOPOMOFO LETTER ENBOPOMOFO " +
"LETTER ANGBOPOMOFO LETTER ENGBOPOMOFO LETTER ERBOPOMOFO LETTER IBOPOMOFO" +
" LETTER UBOPOMOFO LETTER IUBOPOMOFO LETTER VBOPOMOFO LETTER NGBOPOMOFO L" +
"ETTER GNBOPOMOFO LETTER IHBOPOMOFO LETTER O WITH DOT ABOVEBOPOMOFO LETTE" +
"R NNHANGUL LETTER KIYEOKHANGUL LETTER SSANGKIYEOKHANGUL LETTER KIYEOK-SI" +
"OSHANGUL LETTER NIEUNHANGUL LETTER NIEUN-CIEUCHANGUL LETTER NIEUN-HIEUHH" +
"ANGUL LETTER TIKEUTHANGUL LETTER SSANGTIKEUTHANGUL LETTER RIEULHANGUL LE" +
"TTER RIEUL-KIYEOKHANGUL LETTER RIEUL-MIEUMHANGUL LETTER RIEUL-PIEUPHANGU" +
"L LETTER RIEUL-SIOSHANGUL LETTER RIEUL-THIEUTHHANGUL LETTER RIEUL-PHIEUP" +
"HHANGUL LETTER RIEUL-HIEUHHANGUL LETTER MIEUMHANGUL LETTER PIEUPHANGUL L" +
"ETTER SSANGPIEUPHANGUL LETTER PIEUP-SIOSHANGUL LETTER SIOSHANGUL LETTER " +
"SSANGSIOSHANGUL LETTER IEUNGHANGUL LETTER CIEUCHANGUL LETTER SSANGCIEUCH" +
"ANGUL LETTER CHIEUCHHANGUL LETTER KHIEUKHHANGUL LETTER THIEUTHHANGUL LET" +
"TER PHIEUPHHANGUL LETTER HIEUHHANGUL LETTER AHANGUL LETTER AEHANGUL LETT" +
"ER YAHANGUL LETTER YAEHANGUL LETTER EOHANGUL LETTER EHANGUL LETTER YEOHA" +
"NGUL LETTER YEHANGUL LETTER OHANGUL LETTER WAHANGUL LETTER WAEHANGUL LET" +
"TER OEHANGUL LETTER YOHANGUL LETTER UHANGUL LETTER WEOHANGUL LETTER WEHA" +
"NGUL LETTER WIHANGUL LETTER YUHANGUL LETTER EUHANGUL LETTER YIHANGUL LET" +
"TER IHANGUL FILLERHANGUL LETTER SSANGNIEUNHANGUL LETTER NIEUN-TIKEUTHANG" +
"UL LETTER NIEUN-SIOSHANGUL LETTER NIEUN-PANSIOSHANGUL LETTER RIEUL-KIYEO" +
"K-SIOSHANGUL LETTER RIEUL-TIKEUTHANGUL LETTER RIEUL-PIEUP-SIOSHANGUL LET" +
"TER RIEUL-PANSIOSHANGUL LETTER RIEUL-YEORINHIEUHHANGUL LETTER MIEUM-PIEU" +
"PHANGUL LETTER MIEUM-SIOSHANGUL LETTER MIEUM-PANSIOSHANGUL LETTER KAPYEO" +
"UNMIEUMHANGUL LETTER PIEUP-KIYEOKHANGUL LETTER PIEUP-TIKEUTHANGUL LETTER" +
" PIEUP-SIOS-KIYEOKHANGUL LETTER PIEUP-SIOS-TIKEUTHANGUL LETTER PIEUP-CIE" +
"UCHANGUL LETTER PIEUP-THIEUTHHANGUL LETTER KAPYEOUNPIEUPHANGUL LETTER KA") + ("" +
"PYEOUNSSANGPIEUPHANGUL LETTER SIOS-KIYEOKHANGUL LETTER SIOS-NIEUNHANGUL " +
"LETTER SIOS-TIKEUTHANGUL LETTER SIOS-PIEUPHANGUL LETTER SIOS-CIEUCHANGUL" +
" LETTER PANSIOSHANGUL LETTER SSANGIEUNGHANGUL LETTER YESIEUNGHANGUL LETT" +
"ER YESIEUNG-SIOSHANGUL LETTER YESIEUNG-PANSIOSHANGUL LETTER KAPYEOUNPHIE" +
"UPHHANGUL LETTER SSANGHIEUHHANGUL LETTER YEORINHIEUHHANGUL LETTER YO-YAH" +
"ANGUL LETTER YO-YAEHANGUL LETTER YO-IHANGUL LETTER YU-YEOHANGUL LETTER Y" +
"U-YEHANGUL LETTER YU-IHANGUL LETTER ARAEAHANGUL LETTER ARAEAEIDEOGRAPHIC" +
" ANNOTATION LINKING MARKIDEOGRAPHIC ANNOTATION REVERSE MARKIDEOGRAPHIC A" +
"NNOTATION ONE MARKIDEOGRAPHIC ANNOTATION TWO MARKIDEOGRAPHIC ANNOTATION " +
"THREE MARKIDEOGRAPHIC ANNOTATION FOUR MARKIDEOGRAPHIC ANNOTATION TOP MAR" +
"KIDEOGRAPHIC ANNOTATION MIDDLE MARKIDEOGRAPHIC ANNOTATION BOTTOM MARKIDE" +
"OGRAPHIC ANNOTATION FIRST MARKIDEOGRAPHIC ANNOTATION SECOND MARKIDEOGRAP" +
"HIC ANNOTATION THIRD MARKIDEOGRAPHIC ANNOTATION FOURTH MARKIDEOGRAPHIC A" +
"NNOTATION HEAVEN MARKIDEOGRAPHIC ANNOTATION EARTH MARKIDEOGRAPHIC ANNOTA" +
"TION MAN MARKBOPOMOFO LETTER BUBOPOMOFO LETTER ZIBOPOMOFO LETTER JIBOPOM" +
"OFO LETTER GUBOPOMOFO LETTER EEBOPOMOFO LETTER ENNBOPOMOFO LETTER OOBOPO" +
"MOFO LETTER ONNBOPOMOFO LETTER IRBOPOMOFO LETTER ANNBOPOMOFO LETTER INNB" +
"OPOMOFO LETTER UNNBOPOMOFO LETTER IMBOPOMOFO LETTER NGGBOPOMOFO LETTER A" +
"INNBOPOMOFO LETTER AUNNBOPOMOFO LETTER AMBOPOMOFO LETTER OMBOPOMOFO LETT" +
"ER ONGBOPOMOFO LETTER INNNBOPOMOFO FINAL LETTER PBOPOMOFO FINAL LETTER T" +
"BOPOMOFO FINAL LETTER KBOPOMOFO FINAL LETTER HBOPOMOFO LETTER GHBOPOMOFO" +
" LETTER LHBOPOMOFO LETTER ZYBOPOMOFO FINAL LETTER GBOPOMOFO LETTER GWBOP" +
"OMOFO LETTER KWBOPOMOFO LETTER OEBOPOMOFO LETTER AHCJK STROKE TCJK STROK" +
"E WGCJK STROKE XGCJK STROKE BXGCJK STROKE SWCJK STROKE HZZCJK STROKE HZG" +
"CJK STROKE HPCJK STROKE HZWGCJK STROKE SZWGCJK STROKE HZTCJK STROKE HZZP" +
"CJK STROKE HPWGCJK STROKE HZWCJK STROKE HZZZCJK STROKE NCJK STROKE HCJK " +
"STROKE SCJK STROKE PCJK STROKE SPCJK STROKE DCJK STROKE HZCJK STROKE HGC" +
"JK STROKE SZCJK STROKE SWZCJK STROKE STCJK STROKE SGCJK STROKE PDCJK STR" +
"OKE PZCJK STROKE TNCJK STROKE SZZCJK STROKE SWGCJK STROKE HXWGCJK STROKE" +
" HZZZGCJK STROKE PGCJK STROKE QKATAKANA LETTER SMALL KUKATAKANA LETTER S" +
"MALL SIKATAKANA LETTER SMALL SUKATAKANA LETTER SMALL TOKATAKANA LETTER S" +
"MALL NUKATAKANA LETTER SMALL HAKATAKANA LETTER SMALL HIKATAKANA LETTER S" +
"MALL HUKATAKANA LETTER SMALL HEKATAKANA LETTER SMALL HOKATAKANA LETTER S" +
"MALL MUKATAKANA LETTER SMALL RAKATAKANA LETTER SMALL RIKATAKANA LETTER S" +
"MALL RUKATAKANA LETTER SMALL REKATAKANA LETTER SMALL ROPARENTHESIZED HAN" +
"GUL KIYEOKPARENTHESIZED HANGUL NIEUNPARENTHESIZED HANGUL TIKEUTPARENTHES" +
"IZED HANGUL RIEULPARENTHESIZED HANGUL MIEUMPARENTHESIZED HANGUL PIEUPPAR" +
"ENTHESIZED HANGUL SIOSPARENTHESIZED HANGUL IEUNGPARENTHESIZED HANGUL CIE" +
"UCPARENTHESIZED HANGUL CHIEUCHPARENTHESIZED HANGUL KHIEUKHPARENTHESIZED " +
"HANGUL THIEUTHPARENTHESIZED HANGUL PHIEUPHPARENTHESIZED HANGUL HIEUHPARE" +
"NTHESIZED HANGUL KIYEOK APARENTHESIZED HANGUL NIEUN APARENTHESIZED HANGU" +
"L TIKEUT APARENTHESIZED HANGUL RIEUL APARENTHESIZED HANGUL MIEUM APARENT" +
"HESIZED HANGUL PIEUP APARENTHESIZED HANGUL SIOS APARENTHESIZED HANGUL IE" +
"UNG APARENTHESIZED HANGUL CIEUC APARENTHESIZED HANGUL CHIEUCH APARENTHES" +
"IZED HANGUL KHIEUKH APARENTHESIZED HANGUL THIEUTH APARENTHESIZED HANGUL " +
"PHIEUPH APARENTHESIZED HANGUL HIEUH APARENTHESIZED HANGUL CIEUC UPARENTH" +
"ESIZED KOREAN CHARACTER OJEONPARENTHESIZED KOREAN CHARACTER O HUPARENTHE" +
"SIZED IDEOGRAPH ONEPARENTHESIZED IDEOGRAPH TWOPARENTHESIZED IDEOGRAPH TH" +
"REEPARENTHESIZED IDEOGRAPH FOURPARENTHESIZED IDEOGRAPH FIVEPARENTHESIZED" +
" IDEOGRAPH SIXPARENTHESIZED IDEOGRAPH SEVENPARENTHESIZED IDEOGRAPH EIGHT" +
"PARENTHESIZED IDEOGRAPH NINEPARENTHESIZED IDEOGRAPH TENPARENTHESIZED IDE" +
"OGRAPH MOONPARENTHESIZED IDEOGRAPH FIREPARENTHESIZED IDEOGRAPH WATERPARE" +
"NTHESIZED IDEOGRAPH WOODPARENTHESIZED IDEOGRAPH METALPARENTHESIZED IDEOG" +
"RAPH EARTHPARENTHESIZED IDEOGRAPH SUNPARENTHESIZED IDEOGRAPH STOCKPARENT" +
"HESIZED IDEOGRAPH HAVEPARENTHESIZED IDEOGRAPH SOCIETYPARENTHESIZED IDEOG" +
"RAPH NAMEPARENTHESIZED IDEOGRAPH SPECIALPARENTHESIZED IDEOGRAPH FINANCIA" +
"LPARENTHESIZED IDEOGRAPH CONGRATULATIONPARENTHESIZED IDEOGRAPH LABORPARE" +
"NTHESIZED IDEOGRAPH REPRESENTPARENTHESIZED IDEOGRAPH CALLPARENTHESIZED I" +
"DEOGRAPH STUDYPARENTHESIZED IDEOGRAPH SUPERVISEPARENTHESIZED IDEOGRAPH E" +
"NTERPRISEPARENTHESIZED IDEOGRAPH RESOURCEPARENTHESIZED IDEOGRAPH ALLIANC" +
"EPARENTHESIZED IDEOGRAPH FESTIVALPARENTHESIZED IDEOGRAPH RESTPARENTHESIZ" +
"ED IDEOGRAPH SELFPARENTHESIZED IDEOGRAPH REACHCIRCLED IDEOGRAPH QUESTION" +
"CIRCLED IDEOGRAPH KINDERGARTENCIRCLED IDEOGRAPH SCHOOLCIRCLED IDEOGRAPH " +
"KOTOCIRCLED NUMBER TEN ON BLACK SQUARECIRCLED NUMBER TWENTY ON BLACK SQU") + ("" +
"ARECIRCLED NUMBER THIRTY ON BLACK SQUARECIRCLED NUMBER FORTY ON BLACK SQ" +
"UARECIRCLED NUMBER FIFTY ON BLACK SQUARECIRCLED NUMBER SIXTY ON BLACK SQ" +
"UARECIRCLED NUMBER SEVENTY ON BLACK SQUARECIRCLED NUMBER EIGHTY ON BLACK" +
" SQUAREPARTNERSHIP SIGNCIRCLED NUMBER TWENTY ONECIRCLED NUMBER TWENTY TW" +
"OCIRCLED NUMBER TWENTY THREECIRCLED NUMBER TWENTY FOURCIRCLED NUMBER TWE" +
"NTY FIVECIRCLED NUMBER TWENTY SIXCIRCLED NUMBER TWENTY SEVENCIRCLED NUMB" +
"ER TWENTY EIGHTCIRCLED NUMBER TWENTY NINECIRCLED NUMBER THIRTYCIRCLED NU" +
"MBER THIRTY ONECIRCLED NUMBER THIRTY TWOCIRCLED NUMBER THIRTY THREECIRCL" +
"ED NUMBER THIRTY FOURCIRCLED NUMBER THIRTY FIVECIRCLED HANGUL KIYEOKCIRC" +
"LED HANGUL NIEUNCIRCLED HANGUL TIKEUTCIRCLED HANGUL RIEULCIRCLED HANGUL " +
"MIEUMCIRCLED HANGUL PIEUPCIRCLED HANGUL SIOSCIRCLED HANGUL IEUNGCIRCLED " +
"HANGUL CIEUCCIRCLED HANGUL CHIEUCHCIRCLED HANGUL KHIEUKHCIRCLED HANGUL T" +
"HIEUTHCIRCLED HANGUL PHIEUPHCIRCLED HANGUL HIEUHCIRCLED HANGUL KIYEOK AC" +
"IRCLED HANGUL NIEUN ACIRCLED HANGUL TIKEUT ACIRCLED HANGUL RIEUL ACIRCLE" +
"D HANGUL MIEUM ACIRCLED HANGUL PIEUP ACIRCLED HANGUL SIOS ACIRCLED HANGU" +
"L IEUNG ACIRCLED HANGUL CIEUC ACIRCLED HANGUL CHIEUCH ACIRCLED HANGUL KH" +
"IEUKH ACIRCLED HANGUL THIEUTH ACIRCLED HANGUL PHIEUPH ACIRCLED HANGUL HI" +
"EUH ACIRCLED KOREAN CHARACTER CHAMKOCIRCLED KOREAN CHARACTER JUEUICIRCLE" +
"D HANGUL IEUNG UKOREAN STANDARD SYMBOLCIRCLED IDEOGRAPH ONECIRCLED IDEOG" +
"RAPH TWOCIRCLED IDEOGRAPH THREECIRCLED IDEOGRAPH FOURCIRCLED IDEOGRAPH F" +
"IVECIRCLED IDEOGRAPH SIXCIRCLED IDEOGRAPH SEVENCIRCLED IDEOGRAPH EIGHTCI" +
"RCLED IDEOGRAPH NINECIRCLED IDEOGRAPH TENCIRCLED IDEOGRAPH MOONCIRCLED I" +
"DEOGRAPH FIRECIRCLED IDEOGRAPH WATERCIRCLED IDEOGRAPH WOODCIRCLED IDEOGR" +
"APH METALCIRCLED IDEOGRAPH EARTHCIRCLED IDEOGRAPH SUNCIRCLED IDEOGRAPH S" +
"TOCKCIRCLED IDEOGRAPH HAVECIRCLED IDEOGRAPH SOCIETYCIRCLED IDEOGRAPH NAM" +
"ECIRCLED IDEOGRAPH SPECIALCIRCLED IDEOGRAPH FINANCIALCIRCLED IDEOGRAPH C" +
"ONGRATULATIONCIRCLED IDEOGRAPH LABORCIRCLED IDEOGRAPH SECRETCIRCLED IDEO" +
"GRAPH MALECIRCLED IDEOGRAPH FEMALECIRCLED IDEOGRAPH SUITABLECIRCLED IDEO" +
"GRAPH EXCELLENTCIRCLED IDEOGRAPH PRINTCIRCLED IDEOGRAPH ATTENTIONCIRCLED" +
" IDEOGRAPH ITEMCIRCLED IDEOGRAPH RESTCIRCLED IDEOGRAPH COPYCIRCLED IDEOG" +
"RAPH CORRECTCIRCLED IDEOGRAPH HIGHCIRCLED IDEOGRAPH CENTRECIRCLED IDEOGR" +
"APH LOWCIRCLED IDEOGRAPH LEFTCIRCLED IDEOGRAPH RIGHTCIRCLED IDEOGRAPH ME" +
"DICINECIRCLED IDEOGRAPH RELIGIONCIRCLED IDEOGRAPH STUDYCIRCLED IDEOGRAPH" +
" SUPERVISECIRCLED IDEOGRAPH ENTERPRISECIRCLED IDEOGRAPH RESOURCECIRCLED " +
"IDEOGRAPH ALLIANCECIRCLED IDEOGRAPH NIGHTCIRCLED NUMBER THIRTY SIXCIRCLE" +
"D NUMBER THIRTY SEVENCIRCLED NUMBER THIRTY EIGHTCIRCLED NUMBER THIRTY NI" +
"NECIRCLED NUMBER FORTYCIRCLED NUMBER FORTY ONECIRCLED NUMBER FORTY TWOCI" +
"RCLED NUMBER FORTY THREECIRCLED NUMBER FORTY FOURCIRCLED NUMBER FORTY FI" +
"VECIRCLED NUMBER FORTY SIXCIRCLED NUMBER FORTY SEVENCIRCLED NUMBER FORTY" +
" EIGHTCIRCLED NUMBER FORTY NINECIRCLED NUMBER FIFTYIDEOGRAPHIC TELEGRAPH" +
" SYMBOL FOR JANUARYIDEOGRAPHIC TELEGRAPH SYMBOL FOR FEBRUARYIDEOGRAPHIC " +
"TELEGRAPH SYMBOL FOR MARCHIDEOGRAPHIC TELEGRAPH SYMBOL FOR APRILIDEOGRAP" +
"HIC TELEGRAPH SYMBOL FOR MAYIDEOGRAPHIC TELEGRAPH SYMBOL FOR JUNEIDEOGRA" +
"PHIC TELEGRAPH SYMBOL FOR JULYIDEOGRAPHIC TELEGRAPH SYMBOL FOR AUGUSTIDE" +
"OGRAPHIC TELEGRAPH SYMBOL FOR SEPTEMBERIDEOGRAPHIC TELEGRAPH SYMBOL FOR " +
"OCTOBERIDEOGRAPHIC TELEGRAPH SYMBOL FOR NOVEMBERIDEOGRAPHIC TELEGRAPH SY" +
"MBOL FOR DECEMBERSQUARE HGSQUARE ERGSQUARE EVLIMITED LIABILITY SIGNCIRCL" +
"ED KATAKANA ACIRCLED KATAKANA ICIRCLED KATAKANA UCIRCLED KATAKANA ECIRCL" +
"ED KATAKANA OCIRCLED KATAKANA KACIRCLED KATAKANA KICIRCLED KATAKANA KUCI" +
"RCLED KATAKANA KECIRCLED KATAKANA KOCIRCLED KATAKANA SACIRCLED KATAKANA " +
"SICIRCLED KATAKANA SUCIRCLED KATAKANA SECIRCLED KATAKANA SOCIRCLED KATAK" +
"ANA TACIRCLED KATAKANA TICIRCLED KATAKANA TUCIRCLED KATAKANA TECIRCLED K" +
"ATAKANA TOCIRCLED KATAKANA NACIRCLED KATAKANA NICIRCLED KATAKANA NUCIRCL" +
"ED KATAKANA NECIRCLED KATAKANA NOCIRCLED KATAKANA HACIRCLED KATAKANA HIC" +
"IRCLED KATAKANA HUCIRCLED KATAKANA HECIRCLED KATAKANA HOCIRCLED KATAKANA" +
" MACIRCLED KATAKANA MICIRCLED KATAKANA MUCIRCLED KATAKANA MECIRCLED KATA" +
"KANA MOCIRCLED KATAKANA YACIRCLED KATAKANA YUCIRCLED KATAKANA YOCIRCLED " +
"KATAKANA RACIRCLED KATAKANA RICIRCLED KATAKANA RUCIRCLED KATAKANA RECIRC" +
"LED KATAKANA ROCIRCLED KATAKANA WACIRCLED KATAKANA WICIRCLED KATAKANA WE" +
"CIRCLED KATAKANA WOSQUARE ERA NAME REIWASQUARE APAATOSQUARE ARUHUASQUARE" +
" ANPEASQUARE AARUSQUARE ININGUSQUARE INTISQUARE UONSQUARE ESUKUUDOSQUARE" +
" EEKAASQUARE ONSUSQUARE OOMUSQUARE KAIRISQUARE KARATTOSQUARE KARORIISQUA" +
"RE GARONSQUARE GANMASQUARE GIGASQUARE GINIISQUARE KYURIISQUARE GIRUDAASQ" +
"UARE KIROSQUARE KIROGURAMUSQUARE KIROMEETORUSQUARE KIROWATTOSQUARE GURAM") + ("" +
"USQUARE GURAMUTONSQUARE KURUZEIROSQUARE KUROONESQUARE KEESUSQUARE KORUNA" +
"SQUARE KOOPOSQUARE SAIKURUSQUARE SANTIIMUSQUARE SIRINGUSQUARE SENTISQUAR" +
"E SENTOSQUARE DAASUSQUARE DESISQUARE DORUSQUARE TONSQUARE NANOSQUARE NOT" +
"TOSQUARE HAITUSQUARE PAASENTOSQUARE PAATUSQUARE BAARERUSQUARE PIASUTORUS" +
"QUARE PIKURUSQUARE PIKOSQUARE BIRUSQUARE HUARADDOSQUARE HUIITOSQUARE BUS" +
"SYERUSQUARE HURANSQUARE HEKUTAARUSQUARE PESOSQUARE PENIHISQUARE HERUTUSQ" +
"UARE PENSUSQUARE PEEZISQUARE BEETASQUARE POINTOSQUARE BORUTOSQUARE HONSQ" +
"UARE PONDOSQUARE HOORUSQUARE HOONSQUARE MAIKUROSQUARE MAIRUSQUARE MAHHAS" +
"QUARE MARUKUSQUARE MANSYONSQUARE MIKURONSQUARE MIRISQUARE MIRIBAARUSQUAR" +
"E MEGASQUARE MEGATONSQUARE MEETORUSQUARE YAADOSQUARE YAARUSQUARE YUANSQU" +
"ARE RITTORUSQUARE RIRASQUARE RUPIISQUARE RUUBURUSQUARE REMUSQUARE RENTOG" +
"ENSQUARE WATTOIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZEROIDEOGRAPHIC TELE" +
"GRAPH SYMBOL FOR HOUR ONEIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWOIDEOGR" +
"APHIC TELEGRAPH SYMBOL FOR HOUR THREEIDEOGRAPHIC TELEGRAPH SYMBOL FOR HO" +
"UR FOURIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIVEIDEOGRAPHIC TELEGRAPH S" +
"YMBOL FOR HOUR SIXIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVENIDEOGRAPHIC" +
" TELEGRAPH SYMBOL FOR HOUR EIGHTIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NI" +
"NEIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TENIDEOGRAPHIC TELEGRAPH SYMBOL " +
"FOR HOUR ELEVENIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWELVEIDEOGRAPHIC T" +
"ELEGRAPH SYMBOL FOR HOUR THIRTEENIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR F" +
"OURTEENIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIFTEENIDEOGRAPHIC TELEGRAP" +
"H SYMBOL FOR HOUR SIXTEENIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVENTEEN" +
"IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHTEENIDEOGRAPHIC TELEGRAPH SYMB" +
"OL FOR HOUR NINETEENIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTYIDEOGRAP" +
"HIC TELEGRAPH SYMBOL FOR HOUR TWENTY-ONEIDEOGRAPHIC TELEGRAPH SYMBOL FOR" +
" HOUR TWENTY-TWOIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-THREEIDEOGR" +
"APHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-FOURSQUARE HPASQUARE DASQUARE AUS" +
"QUARE BARSQUARE OVSQUARE PCSQUARE DMSQUARE DM SQUAREDSQUARE DM CUBEDSQUA" +
"RE IUSQUARE ERA NAME HEISEISQUARE ERA NAME SYOUWASQUARE ERA NAME TAISYOU" +
"SQUARE ERA NAME MEIZISQUARE CORPORATIONSQUARE PA AMPSSQUARE NASQUARE MU " +
"ASQUARE MASQUARE KASQUARE KBSQUARE MBSQUARE GBSQUARE CALSQUARE KCALSQUAR" +
"E PFSQUARE NFSQUARE MU FSQUARE MU GSQUARE MGSQUARE KGSQUARE HZSQUARE KHZ" +
"SQUARE MHZSQUARE GHZSQUARE THZSQUARE MU LSQUARE MLSQUARE DLSQUARE KLSQUA" +
"RE FMSQUARE NMSQUARE MU MSQUARE MMSQUARE CMSQUARE KMSQUARE MM SQUAREDSQU" +
"ARE CM SQUAREDSQUARE M SQUAREDSQUARE KM SQUAREDSQUARE MM CUBEDSQUARE CM " +
"CUBEDSQUARE M CUBEDSQUARE KM CUBEDSQUARE M OVER SSQUARE M OVER S SQUARED" +
"SQUARE PASQUARE KPASQUARE MPASQUARE GPASQUARE RADSQUARE RAD OVER SSQUARE" +
" RAD OVER S SQUAREDSQUARE PSSQUARE NSSQUARE MU SSQUARE MSSQUARE PVSQUARE" +
" NVSQUARE MU VSQUARE MVSQUARE KVSQUARE MV MEGASQUARE PWSQUARE NWSQUARE M" +
"U WSQUARE MWSQUARE KWSQUARE MW MEGASQUARE K OHMSQUARE M OHMSQUARE AMSQUA" +
"RE BQSQUARE CCSQUARE CDSQUARE C OVER KGSQUARE COSQUARE DBSQUARE GYSQUARE" +
" HASQUARE HPSQUARE INSQUARE KKSQUARE KM CAPITALSQUARE KTSQUARE LMSQUARE " +
"LNSQUARE LOGSQUARE LXSQUARE MB SMALLSQUARE MILSQUARE MOLSQUARE PHSQUARE " +
"PMSQUARE PPMSQUARE PRSQUARE SRSQUARE SVSQUARE WBSQUARE V OVER MSQUARE A " +
"OVER MIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONEIDEOGRAPHIC TELEGRAPH SYMB" +
"OL FOR DAY TWOIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THREEIDEOGRAPHIC TELE" +
"GRAPH SYMBOL FOR DAY FOURIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIVEIDEOGR" +
"APHIC TELEGRAPH SYMBOL FOR DAY SIXIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY S" +
"EVENIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHTIDEOGRAPHIC TELEGRAPH SYMB" +
"OL FOR DAY NINEIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TENIDEOGRAPHIC TELEG" +
"RAPH SYMBOL FOR DAY ELEVENIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWELVEIDE" +
"OGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTEENIDEOGRAPHIC TELEGRAPH SYMBOL F" +
"OR DAY FOURTEENIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIFTEENIDEOGRAPHIC T" +
"ELEGRAPH SYMBOL FOR DAY SIXTEENIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVE" +
"NTEENIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHTEENIDEOGRAPHIC TELEGRAPH " +
"SYMBOL FOR DAY NINETEENIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTYIDEOGR" +
"APHIC TELEGRAPH SYMBOL FOR DAY TWENTY-ONEIDEOGRAPHIC TELEGRAPH SYMBOL FO" +
"R DAY TWENTY-TWOIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-THREEIDEOGRA" +
"PHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FOURIDEOGRAPHIC TELEGRAPH SYMBOL FO" +
"R DAY TWENTY-FIVEIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SIXIDEOGRAP" +
"HIC TELEGRAPH SYMBOL FOR DAY TWENTY-SEVENIDEOGRAPHIC TELEGRAPH SYMBOL FO" +
"R DAY TWENTY-EIGHTIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-NINEIDEOGR" +
"APHIC TELEGRAPH SYMBOL FOR DAY THIRTYIDEOGRAPHIC TELEGRAPH SYMBOL FOR DA" +
"Y THIRTY-ONESQUARE GALHEXAGRAM FOR THE CREATIVE HEAVENHEXAGRAM FOR THE R") + ("" +
"ECEPTIVE EARTHHEXAGRAM FOR DIFFICULTY AT THE BEGINNINGHEXAGRAM FOR YOUTH" +
"FUL FOLLYHEXAGRAM FOR WAITINGHEXAGRAM FOR CONFLICTHEXAGRAM FOR THE ARMYH" +
"EXAGRAM FOR HOLDING TOGETHERHEXAGRAM FOR SMALL TAMINGHEXAGRAM FOR TREADI" +
"NGHEXAGRAM FOR PEACEHEXAGRAM FOR STANDSTILLHEXAGRAM FOR FELLOWSHIPHEXAGR" +
"AM FOR GREAT POSSESSIONHEXAGRAM FOR MODESTYHEXAGRAM FOR ENTHUSIASMHEXAGR" +
"AM FOR FOLLOWINGHEXAGRAM FOR WORK ON THE DECAYEDHEXAGRAM FOR APPROACHHEX" +
"AGRAM FOR CONTEMPLATIONHEXAGRAM FOR BITING THROUGHHEXAGRAM FOR GRACEHEXA" +
"GRAM FOR SPLITTING APARTHEXAGRAM FOR RETURNHEXAGRAM FOR INNOCENCEHEXAGRA" +
"M FOR GREAT TAMINGHEXAGRAM FOR MOUTH CORNERSHEXAGRAM FOR GREAT PREPONDER" +
"ANCEHEXAGRAM FOR THE ABYSMAL WATERHEXAGRAM FOR THE CLINGING FIREHEXAGRAM" +
" FOR INFLUENCEHEXAGRAM FOR DURATIONHEXAGRAM FOR RETREATHEXAGRAM FOR GREA" +
"T POWERHEXAGRAM FOR PROGRESSHEXAGRAM FOR DARKENING OF THE LIGHTHEXAGRAM " +
"FOR THE FAMILYHEXAGRAM FOR OPPOSITIONHEXAGRAM FOR OBSTRUCTIONHEXAGRAM FO" +
"R DELIVERANCEHEXAGRAM FOR DECREASEHEXAGRAM FOR INCREASEHEXAGRAM FOR BREA" +
"KTHROUGHHEXAGRAM FOR COMING TO MEETHEXAGRAM FOR GATHERING TOGETHERHEXAGR" +
"AM FOR PUSHING UPWARDHEXAGRAM FOR OPPRESSIONHEXAGRAM FOR THE WELLHEXAGRA" +
"M FOR REVOLUTIONHEXAGRAM FOR THE CAULDRONHEXAGRAM FOR THE AROUSING THUND" +
"ERHEXAGRAM FOR THE KEEPING STILL MOUNTAINHEXAGRAM FOR DEVELOPMENTHEXAGRA" +
"M FOR THE MARRYING MAIDENHEXAGRAM FOR ABUNDANCEHEXAGRAM FOR THE WANDERER" +
"HEXAGRAM FOR THE GENTLE WINDHEXAGRAM FOR THE JOYOUS LAKEHEXAGRAM FOR DIS" +
"PERSIONHEXAGRAM FOR LIMITATIONHEXAGRAM FOR INNER TRUTHHEXAGRAM FOR SMALL" +
" PREPONDERANCEHEXAGRAM FOR AFTER COMPLETIONHEXAGRAM FOR BEFORE COMPLETIO" +
"NYI SYLLABLE ITYI SYLLABLE IXYI SYLLABLE IYI SYLLABLE IPYI SYLLABLE IETY" +
"I SYLLABLE IEXYI SYLLABLE IEYI SYLLABLE IEPYI SYLLABLE ATYI SYLLABLE AXY" +
"I SYLLABLE AYI SYLLABLE APYI SYLLABLE UOXYI SYLLABLE UOYI SYLLABLE UOPYI" +
" SYLLABLE OTYI SYLLABLE OXYI SYLLABLE OYI SYLLABLE OPYI SYLLABLE EXYI SY" +
"LLABLE EYI SYLLABLE WUYI SYLLABLE BITYI SYLLABLE BIXYI SYLLABLE BIYI SYL" +
"LABLE BIPYI SYLLABLE BIETYI SYLLABLE BIEXYI SYLLABLE BIEYI SYLLABLE BIEP" +
"YI SYLLABLE BATYI SYLLABLE BAXYI SYLLABLE BAYI SYLLABLE BAPYI SYLLABLE B" +
"UOXYI SYLLABLE BUOYI SYLLABLE BUOPYI SYLLABLE BOTYI SYLLABLE BOXYI SYLLA" +
"BLE BOYI SYLLABLE BOPYI SYLLABLE BEXYI SYLLABLE BEYI SYLLABLE BEPYI SYLL" +
"ABLE BUTYI SYLLABLE BUXYI SYLLABLE BUYI SYLLABLE BUPYI SYLLABLE BURXYI S" +
"YLLABLE BURYI SYLLABLE BYTYI SYLLABLE BYXYI SYLLABLE BYYI SYLLABLE BYPYI" +
" SYLLABLE BYRXYI SYLLABLE BYRYI SYLLABLE PITYI SYLLABLE PIXYI SYLLABLE P" +
"IYI SYLLABLE PIPYI SYLLABLE PIEXYI SYLLABLE PIEYI SYLLABLE PIEPYI SYLLAB" +
"LE PATYI SYLLABLE PAXYI SYLLABLE PAYI SYLLABLE PAPYI SYLLABLE PUOXYI SYL" +
"LABLE PUOYI SYLLABLE PUOPYI SYLLABLE POTYI SYLLABLE POXYI SYLLABLE POYI " +
"SYLLABLE POPYI SYLLABLE PUTYI SYLLABLE PUXYI SYLLABLE PUYI SYLLABLE PUPY" +
"I SYLLABLE PURXYI SYLLABLE PURYI SYLLABLE PYTYI SYLLABLE PYXYI SYLLABLE " +
"PYYI SYLLABLE PYPYI SYLLABLE PYRXYI SYLLABLE PYRYI SYLLABLE BBITYI SYLLA" +
"BLE BBIXYI SYLLABLE BBIYI SYLLABLE BBIPYI SYLLABLE BBIETYI SYLLABLE BBIE" +
"XYI SYLLABLE BBIEYI SYLLABLE BBIEPYI SYLLABLE BBATYI SYLLABLE BBAXYI SYL" +
"LABLE BBAYI SYLLABLE BBAPYI SYLLABLE BBUOXYI SYLLABLE BBUOYI SYLLABLE BB" +
"UOPYI SYLLABLE BBOTYI SYLLABLE BBOXYI SYLLABLE BBOYI SYLLABLE BBOPYI SYL" +
"LABLE BBEXYI SYLLABLE BBEYI SYLLABLE BBEPYI SYLLABLE BBUTYI SYLLABLE BBU" +
"XYI SYLLABLE BBUYI SYLLABLE BBUPYI SYLLABLE BBURXYI SYLLABLE BBURYI SYLL" +
"ABLE BBYTYI SYLLABLE BBYXYI SYLLABLE BBYYI SYLLABLE BBYPYI SYLLABLE NBIT" +
"YI SYLLABLE NBIXYI SYLLABLE NBIYI SYLLABLE NBIPYI SYLLABLE NBIEXYI SYLLA" +
"BLE NBIEYI SYLLABLE NBIEPYI SYLLABLE NBATYI SYLLABLE NBAXYI SYLLABLE NBA" +
"YI SYLLABLE NBAPYI SYLLABLE NBOTYI SYLLABLE NBOXYI SYLLABLE NBOYI SYLLAB" +
"LE NBOPYI SYLLABLE NBUTYI SYLLABLE NBUXYI SYLLABLE NBUYI SYLLABLE NBUPYI" +
" SYLLABLE NBURXYI SYLLABLE NBURYI SYLLABLE NBYTYI SYLLABLE NBYXYI SYLLAB" +
"LE NBYYI SYLLABLE NBYPYI SYLLABLE NBYRXYI SYLLABLE NBYRYI SYLLABLE HMITY" +
"I SYLLABLE HMIXYI SYLLABLE HMIYI SYLLABLE HMIPYI SYLLABLE HMIEXYI SYLLAB" +
"LE HMIEYI SYLLABLE HMIEPYI SYLLABLE HMATYI SYLLABLE HMAXYI SYLLABLE HMAY" +
"I SYLLABLE HMAPYI SYLLABLE HMUOXYI SYLLABLE HMUOYI SYLLABLE HMUOPYI SYLL" +
"ABLE HMOTYI SYLLABLE HMOXYI SYLLABLE HMOYI SYLLABLE HMOPYI SYLLABLE HMUT" +
"YI SYLLABLE HMUXYI SYLLABLE HMUYI SYLLABLE HMUPYI SYLLABLE HMURXYI SYLLA" +
"BLE HMURYI SYLLABLE HMYXYI SYLLABLE HMYYI SYLLABLE HMYPYI SYLLABLE HMYRX" +
"YI SYLLABLE HMYRYI SYLLABLE MITYI SYLLABLE MIXYI SYLLABLE MIYI SYLLABLE " +
"MIPYI SYLLABLE MIEXYI SYLLABLE MIEYI SYLLABLE MIEPYI SYLLABLE MATYI SYLL" +
"ABLE MAXYI SYLLABLE MAYI SYLLABLE MAPYI SYLLABLE MUOTYI SYLLABLE MUOXYI " +
"SYLLABLE MUOYI SYLLABLE MUOPYI SYLLABLE MOTYI SYLLABLE MOXYI SYLLABLE MO" +
"YI SYLLABLE MOPYI SYLLABLE MEXYI SYLLABLE MEYI SYLLABLE MUTYI SYLLABLE M") + ("" +
"UXYI SYLLABLE MUYI SYLLABLE MUPYI SYLLABLE MURXYI SYLLABLE MURYI SYLLABL" +
"E MYTYI SYLLABLE MYXYI SYLLABLE MYYI SYLLABLE MYPYI SYLLABLE FITYI SYLLA" +
"BLE FIXYI SYLLABLE FIYI SYLLABLE FIPYI SYLLABLE FATYI SYLLABLE FAXYI SYL" +
"LABLE FAYI SYLLABLE FAPYI SYLLABLE FOXYI SYLLABLE FOYI SYLLABLE FOPYI SY" +
"LLABLE FUTYI SYLLABLE FUXYI SYLLABLE FUYI SYLLABLE FUPYI SYLLABLE FURXYI" +
" SYLLABLE FURYI SYLLABLE FYTYI SYLLABLE FYXYI SYLLABLE FYYI SYLLABLE FYP" +
"YI SYLLABLE VITYI SYLLABLE VIXYI SYLLABLE VIYI SYLLABLE VIPYI SYLLABLE V" +
"IETYI SYLLABLE VIEXYI SYLLABLE VIEYI SYLLABLE VIEPYI SYLLABLE VATYI SYLL" +
"ABLE VAXYI SYLLABLE VAYI SYLLABLE VAPYI SYLLABLE VOTYI SYLLABLE VOXYI SY" +
"LLABLE VOYI SYLLABLE VOPYI SYLLABLE VEXYI SYLLABLE VEPYI SYLLABLE VUTYI " +
"SYLLABLE VUXYI SYLLABLE VUYI SYLLABLE VUPYI SYLLABLE VURXYI SYLLABLE VUR" +
"YI SYLLABLE VYTYI SYLLABLE VYXYI SYLLABLE VYYI SYLLABLE VYPYI SYLLABLE V" +
"YRXYI SYLLABLE VYRYI SYLLABLE DITYI SYLLABLE DIXYI SYLLABLE DIYI SYLLABL" +
"E DIPYI SYLLABLE DIEXYI SYLLABLE DIEYI SYLLABLE DIEPYI SYLLABLE DATYI SY" +
"LLABLE DAXYI SYLLABLE DAYI SYLLABLE DAPYI SYLLABLE DUOXYI SYLLABLE DUOYI" +
" SYLLABLE DOTYI SYLLABLE DOXYI SYLLABLE DOYI SYLLABLE DOPYI SYLLABLE DEX" +
"YI SYLLABLE DEYI SYLLABLE DEPYI SYLLABLE DUTYI SYLLABLE DUXYI SYLLABLE D" +
"UYI SYLLABLE DUPYI SYLLABLE DURXYI SYLLABLE DURYI SYLLABLE TITYI SYLLABL" +
"E TIXYI SYLLABLE TIYI SYLLABLE TIPYI SYLLABLE TIEXYI SYLLABLE TIEYI SYLL" +
"ABLE TIEPYI SYLLABLE TATYI SYLLABLE TAXYI SYLLABLE TAYI SYLLABLE TAPYI S" +
"YLLABLE TUOTYI SYLLABLE TUOXYI SYLLABLE TUOYI SYLLABLE TUOPYI SYLLABLE T" +
"OTYI SYLLABLE TOXYI SYLLABLE TOYI SYLLABLE TOPYI SYLLABLE TEXYI SYLLABLE" +
" TEYI SYLLABLE TEPYI SYLLABLE TUTYI SYLLABLE TUXYI SYLLABLE TUYI SYLLABL" +
"E TUPYI SYLLABLE TURXYI SYLLABLE TURYI SYLLABLE DDITYI SYLLABLE DDIXYI S" +
"YLLABLE DDIYI SYLLABLE DDIPYI SYLLABLE DDIEXYI SYLLABLE DDIEYI SYLLABLE " +
"DDIEPYI SYLLABLE DDATYI SYLLABLE DDAXYI SYLLABLE DDAYI SYLLABLE DDAPYI S" +
"YLLABLE DDUOXYI SYLLABLE DDUOYI SYLLABLE DDUOPYI SYLLABLE DDOTYI SYLLABL" +
"E DDOXYI SYLLABLE DDOYI SYLLABLE DDOPYI SYLLABLE DDEXYI SYLLABLE DDEYI S" +
"YLLABLE DDEPYI SYLLABLE DDUTYI SYLLABLE DDUXYI SYLLABLE DDUYI SYLLABLE D" +
"DUPYI SYLLABLE DDURXYI SYLLABLE DDURYI SYLLABLE NDITYI SYLLABLE NDIXYI S" +
"YLLABLE NDIYI SYLLABLE NDIPYI SYLLABLE NDIEXYI SYLLABLE NDIEYI SYLLABLE " +
"NDATYI SYLLABLE NDAXYI SYLLABLE NDAYI SYLLABLE NDAPYI SYLLABLE NDOTYI SY" +
"LLABLE NDOXYI SYLLABLE NDOYI SYLLABLE NDOPYI SYLLABLE NDEXYI SYLLABLE ND" +
"EYI SYLLABLE NDEPYI SYLLABLE NDUTYI SYLLABLE NDUXYI SYLLABLE NDUYI SYLLA" +
"BLE NDUPYI SYLLABLE NDURXYI SYLLABLE NDURYI SYLLABLE HNITYI SYLLABLE HNI" +
"XYI SYLLABLE HNIYI SYLLABLE HNIPYI SYLLABLE HNIETYI SYLLABLE HNIEXYI SYL" +
"LABLE HNIEYI SYLLABLE HNIEPYI SYLLABLE HNATYI SYLLABLE HNAXYI SYLLABLE H" +
"NAYI SYLLABLE HNAPYI SYLLABLE HNUOXYI SYLLABLE HNUOYI SYLLABLE HNOTYI SY" +
"LLABLE HNOXYI SYLLABLE HNOPYI SYLLABLE HNEXYI SYLLABLE HNEYI SYLLABLE HN" +
"EPYI SYLLABLE HNUTYI SYLLABLE NITYI SYLLABLE NIXYI SYLLABLE NIYI SYLLABL" +
"E NIPYI SYLLABLE NIEXYI SYLLABLE NIEYI SYLLABLE NIEPYI SYLLABLE NAXYI SY" +
"LLABLE NAYI SYLLABLE NAPYI SYLLABLE NUOXYI SYLLABLE NUOYI SYLLABLE NUOPY" +
"I SYLLABLE NOTYI SYLLABLE NOXYI SYLLABLE NOYI SYLLABLE NOPYI SYLLABLE NE" +
"XYI SYLLABLE NEYI SYLLABLE NEPYI SYLLABLE NUTYI SYLLABLE NUXYI SYLLABLE " +
"NUYI SYLLABLE NUPYI SYLLABLE NURXYI SYLLABLE NURYI SYLLABLE HLITYI SYLLA" +
"BLE HLIXYI SYLLABLE HLIYI SYLLABLE HLIPYI SYLLABLE HLIEXYI SYLLABLE HLIE" +
"YI SYLLABLE HLIEPYI SYLLABLE HLATYI SYLLABLE HLAXYI SYLLABLE HLAYI SYLLA" +
"BLE HLAPYI SYLLABLE HLUOXYI SYLLABLE HLUOYI SYLLABLE HLUOPYI SYLLABLE HL" +
"OXYI SYLLABLE HLOYI SYLLABLE HLOPYI SYLLABLE HLEXYI SYLLABLE HLEYI SYLLA" +
"BLE HLEPYI SYLLABLE HLUTYI SYLLABLE HLUXYI SYLLABLE HLUYI SYLLABLE HLUPY" +
"I SYLLABLE HLURXYI SYLLABLE HLURYI SYLLABLE HLYTYI SYLLABLE HLYXYI SYLLA" +
"BLE HLYYI SYLLABLE HLYPYI SYLLABLE HLYRXYI SYLLABLE HLYRYI SYLLABLE LITY" +
"I SYLLABLE LIXYI SYLLABLE LIYI SYLLABLE LIPYI SYLLABLE LIETYI SYLLABLE L" +
"IEXYI SYLLABLE LIEYI SYLLABLE LIEPYI SYLLABLE LATYI SYLLABLE LAXYI SYLLA" +
"BLE LAYI SYLLABLE LAPYI SYLLABLE LUOTYI SYLLABLE LUOXYI SYLLABLE LUOYI S" +
"YLLABLE LUOPYI SYLLABLE LOTYI SYLLABLE LOXYI SYLLABLE LOYI SYLLABLE LOPY" +
"I SYLLABLE LEXYI SYLLABLE LEYI SYLLABLE LEPYI SYLLABLE LUTYI SYLLABLE LU" +
"XYI SYLLABLE LUYI SYLLABLE LUPYI SYLLABLE LURXYI SYLLABLE LURYI SYLLABLE" +
" LYTYI SYLLABLE LYXYI SYLLABLE LYYI SYLLABLE LYPYI SYLLABLE LYRXYI SYLLA" +
"BLE LYRYI SYLLABLE GITYI SYLLABLE GIXYI SYLLABLE GIYI SYLLABLE GIPYI SYL" +
"LABLE GIETYI SYLLABLE GIEXYI SYLLABLE GIEYI SYLLABLE GIEPYI SYLLABLE GAT" +
"YI SYLLABLE GAXYI SYLLABLE GAYI SYLLABLE GAPYI SYLLABLE GUOTYI SYLLABLE " +
"GUOXYI SYLLABLE GUOYI SYLLABLE GUOPYI SYLLABLE GOTYI SYLLABLE GOXYI SYLL" +
"ABLE GOYI SYLLABLE GOPYI SYLLABLE GETYI SYLLABLE GEXYI SYLLABLE GEYI SYL") + ("" +
"LABLE GEPYI SYLLABLE GUTYI SYLLABLE GUXYI SYLLABLE GUYI SYLLABLE GUPYI S" +
"YLLABLE GURXYI SYLLABLE GURYI SYLLABLE KITYI SYLLABLE KIXYI SYLLABLE KIY" +
"I SYLLABLE KIPYI SYLLABLE KIEXYI SYLLABLE KIEYI SYLLABLE KIEPYI SYLLABLE" +
" KATYI SYLLABLE KAXYI SYLLABLE KAYI SYLLABLE KAPYI SYLLABLE KUOXYI SYLLA" +
"BLE KUOYI SYLLABLE KUOPYI SYLLABLE KOTYI SYLLABLE KOXYI SYLLABLE KOYI SY" +
"LLABLE KOPYI SYLLABLE KETYI SYLLABLE KEXYI SYLLABLE KEYI SYLLABLE KEPYI " +
"SYLLABLE KUTYI SYLLABLE KUXYI SYLLABLE KUYI SYLLABLE KUPYI SYLLABLE KURX" +
"YI SYLLABLE KURYI SYLLABLE GGITYI SYLLABLE GGIXYI SYLLABLE GGIYI SYLLABL" +
"E GGIEXYI SYLLABLE GGIEYI SYLLABLE GGIEPYI SYLLABLE GGATYI SYLLABLE GGAX" +
"YI SYLLABLE GGAYI SYLLABLE GGAPYI SYLLABLE GGUOTYI SYLLABLE GGUOXYI SYLL" +
"ABLE GGUOYI SYLLABLE GGUOPYI SYLLABLE GGOTYI SYLLABLE GGOXYI SYLLABLE GG" +
"OYI SYLLABLE GGOPYI SYLLABLE GGETYI SYLLABLE GGEXYI SYLLABLE GGEYI SYLLA" +
"BLE GGEPYI SYLLABLE GGUTYI SYLLABLE GGUXYI SYLLABLE GGUYI SYLLABLE GGUPY" +
"I SYLLABLE GGURXYI SYLLABLE GGURYI SYLLABLE MGIEXYI SYLLABLE MGIEYI SYLL" +
"ABLE MGATYI SYLLABLE MGAXYI SYLLABLE MGAYI SYLLABLE MGAPYI SYLLABLE MGUO" +
"XYI SYLLABLE MGUOYI SYLLABLE MGUOPYI SYLLABLE MGOTYI SYLLABLE MGOXYI SYL" +
"LABLE MGOYI SYLLABLE MGOPYI SYLLABLE MGEXYI SYLLABLE MGEYI SYLLABLE MGEP" +
"YI SYLLABLE MGUTYI SYLLABLE MGUXYI SYLLABLE MGUYI SYLLABLE MGUPYI SYLLAB" +
"LE MGURXYI SYLLABLE MGURYI SYLLABLE HXITYI SYLLABLE HXIXYI SYLLABLE HXIY" +
"I SYLLABLE HXIPYI SYLLABLE HXIETYI SYLLABLE HXIEXYI SYLLABLE HXIEYI SYLL" +
"ABLE HXIEPYI SYLLABLE HXATYI SYLLABLE HXAXYI SYLLABLE HXAYI SYLLABLE HXA" +
"PYI SYLLABLE HXUOTYI SYLLABLE HXUOXYI SYLLABLE HXUOYI SYLLABLE HXUOPYI S" +
"YLLABLE HXOTYI SYLLABLE HXOXYI SYLLABLE HXOYI SYLLABLE HXOPYI SYLLABLE H" +
"XEXYI SYLLABLE HXEYI SYLLABLE HXEPYI SYLLABLE NGIEXYI SYLLABLE NGIEYI SY" +
"LLABLE NGIEPYI SYLLABLE NGATYI SYLLABLE NGAXYI SYLLABLE NGAYI SYLLABLE N" +
"GAPYI SYLLABLE NGUOTYI SYLLABLE NGUOXYI SYLLABLE NGUOYI SYLLABLE NGOTYI " +
"SYLLABLE NGOXYI SYLLABLE NGOYI SYLLABLE NGOPYI SYLLABLE NGEXYI SYLLABLE " +
"NGEYI SYLLABLE NGEPYI SYLLABLE HITYI SYLLABLE HIEXYI SYLLABLE HIEYI SYLL" +
"ABLE HATYI SYLLABLE HAXYI SYLLABLE HAYI SYLLABLE HAPYI SYLLABLE HUOTYI S" +
"YLLABLE HUOXYI SYLLABLE HUOYI SYLLABLE HUOPYI SYLLABLE HOTYI SYLLABLE HO" +
"XYI SYLLABLE HOYI SYLLABLE HOPYI SYLLABLE HEXYI SYLLABLE HEYI SYLLABLE H" +
"EPYI SYLLABLE WATYI SYLLABLE WAXYI SYLLABLE WAYI SYLLABLE WAPYI SYLLABLE" +
" WUOXYI SYLLABLE WUOYI SYLLABLE WUOPYI SYLLABLE WOXYI SYLLABLE WOYI SYLL" +
"ABLE WOPYI SYLLABLE WEXYI SYLLABLE WEYI SYLLABLE WEPYI SYLLABLE ZITYI SY" +
"LLABLE ZIXYI SYLLABLE ZIYI SYLLABLE ZIPYI SYLLABLE ZIEXYI SYLLABLE ZIEYI" +
" SYLLABLE ZIEPYI SYLLABLE ZATYI SYLLABLE ZAXYI SYLLABLE ZAYI SYLLABLE ZA" +
"PYI SYLLABLE ZUOXYI SYLLABLE ZUOYI SYLLABLE ZUOPYI SYLLABLE ZOTYI SYLLAB" +
"LE ZOXYI SYLLABLE ZOYI SYLLABLE ZOPYI SYLLABLE ZEXYI SYLLABLE ZEYI SYLLA" +
"BLE ZEPYI SYLLABLE ZUTYI SYLLABLE ZUXYI SYLLABLE ZUYI SYLLABLE ZUPYI SYL" +
"LABLE ZURXYI SYLLABLE ZURYI SYLLABLE ZYTYI SYLLABLE ZYXYI SYLLABLE ZYYI " +
"SYLLABLE ZYPYI SYLLABLE ZYRXYI SYLLABLE ZYRYI SYLLABLE CITYI SYLLABLE CI" +
"XYI SYLLABLE CIYI SYLLABLE CIPYI SYLLABLE CIETYI SYLLABLE CIEXYI SYLLABL" +
"E CIEYI SYLLABLE CIEPYI SYLLABLE CATYI SYLLABLE CAXYI SYLLABLE CAYI SYLL" +
"ABLE CAPYI SYLLABLE CUOXYI SYLLABLE CUOYI SYLLABLE CUOPYI SYLLABLE COTYI" +
" SYLLABLE COXYI SYLLABLE COYI SYLLABLE COPYI SYLLABLE CEXYI SYLLABLE CEY" +
"I SYLLABLE CEPYI SYLLABLE CUTYI SYLLABLE CUXYI SYLLABLE CUYI SYLLABLE CU" +
"PYI SYLLABLE CURXYI SYLLABLE CURYI SYLLABLE CYTYI SYLLABLE CYXYI SYLLABL" +
"E CYYI SYLLABLE CYPYI SYLLABLE CYRXYI SYLLABLE CYRYI SYLLABLE ZZITYI SYL" +
"LABLE ZZIXYI SYLLABLE ZZIYI SYLLABLE ZZIPYI SYLLABLE ZZIETYI SYLLABLE ZZ" +
"IEXYI SYLLABLE ZZIEYI SYLLABLE ZZIEPYI SYLLABLE ZZATYI SYLLABLE ZZAXYI S" +
"YLLABLE ZZAYI SYLLABLE ZZAPYI SYLLABLE ZZOXYI SYLLABLE ZZOYI SYLLABLE ZZ" +
"OPYI SYLLABLE ZZEXYI SYLLABLE ZZEYI SYLLABLE ZZEPYI SYLLABLE ZZUXYI SYLL" +
"ABLE ZZUYI SYLLABLE ZZUPYI SYLLABLE ZZURXYI SYLLABLE ZZURYI SYLLABLE ZZY" +
"TYI SYLLABLE ZZYXYI SYLLABLE ZZYYI SYLLABLE ZZYPYI SYLLABLE ZZYRXYI SYLL" +
"ABLE ZZYRYI SYLLABLE NZITYI SYLLABLE NZIXYI SYLLABLE NZIYI SYLLABLE NZIP" +
"YI SYLLABLE NZIEXYI SYLLABLE NZIEYI SYLLABLE NZIEPYI SYLLABLE NZATYI SYL" +
"LABLE NZAXYI SYLLABLE NZAYI SYLLABLE NZAPYI SYLLABLE NZUOXYI SYLLABLE NZ" +
"UOYI SYLLABLE NZOXYI SYLLABLE NZOPYI SYLLABLE NZEXYI SYLLABLE NZEYI SYLL" +
"ABLE NZUXYI SYLLABLE NZUYI SYLLABLE NZUPYI SYLLABLE NZURXYI SYLLABLE NZU" +
"RYI SYLLABLE NZYTYI SYLLABLE NZYXYI SYLLABLE NZYYI SYLLABLE NZYPYI SYLLA" +
"BLE NZYRXYI SYLLABLE NZYRYI SYLLABLE SITYI SYLLABLE SIXYI SYLLABLE SIYI " +
"SYLLABLE SIPYI SYLLABLE SIEXYI SYLLABLE SIEYI SYLLABLE SIEPYI SYLLABLE S" +
"ATYI SYLLABLE SAXYI SYLLABLE SAYI SYLLABLE SAPYI SYLLABLE SUOXYI SYLLABL" +
"E SUOYI SYLLABLE SUOPYI SYLLABLE SOTYI SYLLABLE SOXYI SYLLABLE SOYI SYLL") + ("" +
"ABLE SOPYI SYLLABLE SEXYI SYLLABLE SEYI SYLLABLE SEPYI SYLLABLE SUTYI SY" +
"LLABLE SUXYI SYLLABLE SUYI SYLLABLE SUPYI SYLLABLE SURXYI SYLLABLE SURYI" +
" SYLLABLE SYTYI SYLLABLE SYXYI SYLLABLE SYYI SYLLABLE SYPYI SYLLABLE SYR" +
"XYI SYLLABLE SYRYI SYLLABLE SSITYI SYLLABLE SSIXYI SYLLABLE SSIYI SYLLAB" +
"LE SSIPYI SYLLABLE SSIEXYI SYLLABLE SSIEYI SYLLABLE SSIEPYI SYLLABLE SSA" +
"TYI SYLLABLE SSAXYI SYLLABLE SSAYI SYLLABLE SSAPYI SYLLABLE SSOTYI SYLLA" +
"BLE SSOXYI SYLLABLE SSOYI SYLLABLE SSOPYI SYLLABLE SSEXYI SYLLABLE SSEYI" +
" SYLLABLE SSEPYI SYLLABLE SSUTYI SYLLABLE SSUXYI SYLLABLE SSUYI SYLLABLE" +
" SSUPYI SYLLABLE SSYTYI SYLLABLE SSYXYI SYLLABLE SSYYI SYLLABLE SSYPYI S" +
"YLLABLE SSYRXYI SYLLABLE SSYRYI SYLLABLE ZHATYI SYLLABLE ZHAXYI SYLLABLE" +
" ZHAYI SYLLABLE ZHAPYI SYLLABLE ZHUOXYI SYLLABLE ZHUOYI SYLLABLE ZHUOPYI" +
" SYLLABLE ZHOTYI SYLLABLE ZHOXYI SYLLABLE ZHOYI SYLLABLE ZHOPYI SYLLABLE" +
" ZHETYI SYLLABLE ZHEXYI SYLLABLE ZHEYI SYLLABLE ZHEPYI SYLLABLE ZHUTYI S" +
"YLLABLE ZHUXYI SYLLABLE ZHUYI SYLLABLE ZHUPYI SYLLABLE ZHURXYI SYLLABLE " +
"ZHURYI SYLLABLE ZHYTYI SYLLABLE ZHYXYI SYLLABLE ZHYYI SYLLABLE ZHYPYI SY" +
"LLABLE ZHYRXYI SYLLABLE ZHYRYI SYLLABLE CHATYI SYLLABLE CHAXYI SYLLABLE " +
"CHAYI SYLLABLE CHAPYI SYLLABLE CHUOTYI SYLLABLE CHUOXYI SYLLABLE CHUOYI " +
"SYLLABLE CHUOPYI SYLLABLE CHOTYI SYLLABLE CHOXYI SYLLABLE CHOYI SYLLABLE" +
" CHOPYI SYLLABLE CHETYI SYLLABLE CHEXYI SYLLABLE CHEYI SYLLABLE CHEPYI S" +
"YLLABLE CHUXYI SYLLABLE CHUYI SYLLABLE CHUPYI SYLLABLE CHURXYI SYLLABLE " +
"CHURYI SYLLABLE CHYTYI SYLLABLE CHYXYI SYLLABLE CHYYI SYLLABLE CHYPYI SY" +
"LLABLE CHYRXYI SYLLABLE CHYRYI SYLLABLE RRAXYI SYLLABLE RRAYI SYLLABLE R" +
"RUOXYI SYLLABLE RRUOYI SYLLABLE RROTYI SYLLABLE RROXYI SYLLABLE RROYI SY" +
"LLABLE RROPYI SYLLABLE RRETYI SYLLABLE RREXYI SYLLABLE RREYI SYLLABLE RR" +
"EPYI SYLLABLE RRUTYI SYLLABLE RRUXYI SYLLABLE RRUYI SYLLABLE RRUPYI SYLL" +
"ABLE RRURXYI SYLLABLE RRURYI SYLLABLE RRYTYI SYLLABLE RRYXYI SYLLABLE RR" +
"YYI SYLLABLE RRYPYI SYLLABLE RRYRXYI SYLLABLE RRYRYI SYLLABLE NRATYI SYL" +
"LABLE NRAXYI SYLLABLE NRAYI SYLLABLE NRAPYI SYLLABLE NROXYI SYLLABLE NRO" +
"YI SYLLABLE NROPYI SYLLABLE NRETYI SYLLABLE NREXYI SYLLABLE NREYI SYLLAB" +
"LE NREPYI SYLLABLE NRUTYI SYLLABLE NRUXYI SYLLABLE NRUYI SYLLABLE NRUPYI" +
" SYLLABLE NRURXYI SYLLABLE NRURYI SYLLABLE NRYTYI SYLLABLE NRYXYI SYLLAB" +
"LE NRYYI SYLLABLE NRYPYI SYLLABLE NRYRXYI SYLLABLE NRYRYI SYLLABLE SHATY" +
"I SYLLABLE SHAXYI SYLLABLE SHAYI SYLLABLE SHAPYI SYLLABLE SHUOXYI SYLLAB" +
"LE SHUOYI SYLLABLE SHUOPYI SYLLABLE SHOTYI SYLLABLE SHOXYI SYLLABLE SHOY" +
"I SYLLABLE SHOPYI SYLLABLE SHETYI SYLLABLE SHEXYI SYLLABLE SHEYI SYLLABL" +
"E SHEPYI SYLLABLE SHUTYI SYLLABLE SHUXYI SYLLABLE SHUYI SYLLABLE SHUPYI " +
"SYLLABLE SHURXYI SYLLABLE SHURYI SYLLABLE SHYTYI SYLLABLE SHYXYI SYLLABL" +
"E SHYYI SYLLABLE SHYPYI SYLLABLE SHYRXYI SYLLABLE SHYRYI SYLLABLE RATYI " +
"SYLLABLE RAXYI SYLLABLE RAYI SYLLABLE RAPYI SYLLABLE RUOXYI SYLLABLE RUO" +
"YI SYLLABLE RUOPYI SYLLABLE ROTYI SYLLABLE ROXYI SYLLABLE ROYI SYLLABLE " +
"ROPYI SYLLABLE REXYI SYLLABLE REYI SYLLABLE REPYI SYLLABLE RUTYI SYLLABL" +
"E RUXYI SYLLABLE RUYI SYLLABLE RUPYI SYLLABLE RURXYI SYLLABLE RURYI SYLL" +
"ABLE RYTYI SYLLABLE RYXYI SYLLABLE RYYI SYLLABLE RYPYI SYLLABLE RYRXYI S" +
"YLLABLE RYRYI SYLLABLE JITYI SYLLABLE JIXYI SYLLABLE JIYI SYLLABLE JIPYI" +
" SYLLABLE JIETYI SYLLABLE JIEXYI SYLLABLE JIEYI SYLLABLE JIEPYI SYLLABLE" +
" JUOTYI SYLLABLE JUOXYI SYLLABLE JUOYI SYLLABLE JUOPYI SYLLABLE JOTYI SY" +
"LLABLE JOXYI SYLLABLE JOYI SYLLABLE JOPYI SYLLABLE JUTYI SYLLABLE JUXYI " +
"SYLLABLE JUYI SYLLABLE JUPYI SYLLABLE JURXYI SYLLABLE JURYI SYLLABLE JYT" +
"YI SYLLABLE JYXYI SYLLABLE JYYI SYLLABLE JYPYI SYLLABLE JYRXYI SYLLABLE " +
"JYRYI SYLLABLE QITYI SYLLABLE QIXYI SYLLABLE QIYI SYLLABLE QIPYI SYLLABL" +
"E QIETYI SYLLABLE QIEXYI SYLLABLE QIEYI SYLLABLE QIEPYI SYLLABLE QUOTYI " +
"SYLLABLE QUOXYI SYLLABLE QUOYI SYLLABLE QUOPYI SYLLABLE QOTYI SYLLABLE Q" +
"OXYI SYLLABLE QOYI SYLLABLE QOPYI SYLLABLE QUTYI SYLLABLE QUXYI SYLLABLE" +
" QUYI SYLLABLE QUPYI SYLLABLE QURXYI SYLLABLE QURYI SYLLABLE QYTYI SYLLA" +
"BLE QYXYI SYLLABLE QYYI SYLLABLE QYPYI SYLLABLE QYRXYI SYLLABLE QYRYI SY" +
"LLABLE JJITYI SYLLABLE JJIXYI SYLLABLE JJIYI SYLLABLE JJIPYI SYLLABLE JJ" +
"IETYI SYLLABLE JJIEXYI SYLLABLE JJIEYI SYLLABLE JJIEPYI SYLLABLE JJUOXYI" +
" SYLLABLE JJUOYI SYLLABLE JJUOPYI SYLLABLE JJOTYI SYLLABLE JJOXYI SYLLAB" +
"LE JJOYI SYLLABLE JJOPYI SYLLABLE JJUTYI SYLLABLE JJUXYI SYLLABLE JJUYI " +
"SYLLABLE JJUPYI SYLLABLE JJURXYI SYLLABLE JJURYI SYLLABLE JJYTYI SYLLABL" +
"E JJYXYI SYLLABLE JJYYI SYLLABLE JJYPYI SYLLABLE NJITYI SYLLABLE NJIXYI " +
"SYLLABLE NJIYI SYLLABLE NJIPYI SYLLABLE NJIETYI SYLLABLE NJIEXYI SYLLABL" +
"E NJIEYI SYLLABLE NJIEPYI SYLLABLE NJUOXYI SYLLABLE NJUOYI SYLLABLE NJOT" +
"YI SYLLABLE NJOXYI SYLLABLE NJOYI SYLLABLE NJOPYI SYLLABLE NJUXYI SYLLAB") + ("" +
"LE NJUYI SYLLABLE NJUPYI SYLLABLE NJURXYI SYLLABLE NJURYI SYLLABLE NJYTY" +
"I SYLLABLE NJYXYI SYLLABLE NJYYI SYLLABLE NJYPYI SYLLABLE NJYRXYI SYLLAB" +
"LE NJYRYI SYLLABLE NYITYI SYLLABLE NYIXYI SYLLABLE NYIYI SYLLABLE NYIPYI" +
" SYLLABLE NYIETYI SYLLABLE NYIEXYI SYLLABLE NYIEYI SYLLABLE NYIEPYI SYLL" +
"ABLE NYUOXYI SYLLABLE NYUOYI SYLLABLE NYUOPYI SYLLABLE NYOTYI SYLLABLE N" +
"YOXYI SYLLABLE NYOYI SYLLABLE NYOPYI SYLLABLE NYUTYI SYLLABLE NYUXYI SYL" +
"LABLE NYUYI SYLLABLE NYUPYI SYLLABLE XITYI SYLLABLE XIXYI SYLLABLE XIYI " +
"SYLLABLE XIPYI SYLLABLE XIETYI SYLLABLE XIEXYI SYLLABLE XIEYI SYLLABLE X" +
"IEPYI SYLLABLE XUOXYI SYLLABLE XUOYI SYLLABLE XOTYI SYLLABLE XOXYI SYLLA" +
"BLE XOYI SYLLABLE XOPYI SYLLABLE XYTYI SYLLABLE XYXYI SYLLABLE XYYI SYLL" +
"ABLE XYPYI SYLLABLE XYRXYI SYLLABLE XYRYI SYLLABLE YITYI SYLLABLE YIXYI " +
"SYLLABLE YIYI SYLLABLE YIPYI SYLLABLE YIETYI SYLLABLE YIEXYI SYLLABLE YI" +
"EYI SYLLABLE YIEPYI SYLLABLE YUOTYI SYLLABLE YUOXYI SYLLABLE YUOYI SYLLA" +
"BLE YUOPYI SYLLABLE YOTYI SYLLABLE YOXYI SYLLABLE YOYI SYLLABLE YOPYI SY" +
"LLABLE YUTYI SYLLABLE YUXYI SYLLABLE YUYI SYLLABLE YUPYI SYLLABLE YURXYI" +
" SYLLABLE YURYI SYLLABLE YYTYI SYLLABLE YYXYI SYLLABLE YYYI SYLLABLE YYP" +
"YI SYLLABLE YYRXYI SYLLABLE YYRYI RADICAL QOTYI RADICAL LIYI RADICAL KIT" +
"YI RADICAL NYIPYI RADICAL CYPYI RADICAL SSIYI RADICAL GGOPYI RADICAL GEP" +
"YI RADICAL MIYI RADICAL HXITYI RADICAL LYRYI RADICAL BBUTYI RADICAL MOPY" +
"I RADICAL YOYI RADICAL PUTYI RADICAL HXUOYI RADICAL TATYI RADICAL GAYI R" +
"ADICAL ZUPYI RADICAL CYTYI RADICAL DDURYI RADICAL BURYI RADICAL GGUOYI R" +
"ADICAL NYOPYI RADICAL TUYI RADICAL OPYI RADICAL JJUTYI RADICAL ZOTYI RAD" +
"ICAL PYTYI RADICAL HMOYI RADICAL YITYI RADICAL VURYI RADICAL SHYYI RADIC" +
"AL VEPYI RADICAL ZAYI RADICAL JOYI RADICAL NZUPYI RADICAL JJYYI RADICAL " +
"GOTYI RADICAL JJIEYI RADICAL WOYI RADICAL DUYI RADICAL SHURYI RADICAL LI" +
"EYI RADICAL CYYI RADICAL CUOPYI RADICAL CIPYI RADICAL HXOPYI RADICAL SHA" +
"TYI RADICAL ZURYI RADICAL SHOPYI RADICAL CHEYI RADICAL ZZIETYI RADICAL N" +
"BIEYI RADICAL KELISU LETTER BALISU LETTER PALISU LETTER PHALISU LETTER D" +
"ALISU LETTER TALISU LETTER THALISU LETTER GALISU LETTER KALISU LETTER KH" +
"ALISU LETTER JALISU LETTER CALISU LETTER CHALISU LETTER DZALISU LETTER T" +
"SALISU LETTER TSHALISU LETTER MALISU LETTER NALISU LETTER LALISU LETTER " +
"SALISU LETTER ZHALISU LETTER ZALISU LETTER NGALISU LETTER HALISU LETTER " +
"XALISU LETTER HHALISU LETTER FALISU LETTER WALISU LETTER SHALISU LETTER " +
"YALISU LETTER GHALISU LETTER ALISU LETTER AELISU LETTER ELISU LETTER EUL" +
"ISU LETTER ILISU LETTER OLISU LETTER ULISU LETTER UELISU LETTER UHLISU L" +
"ETTER OELISU LETTER TONE MYA TILISU LETTER TONE NA POLISU LETTER TONE MY" +
"A CYALISU LETTER TONE MYA BOLISU LETTER TONE MYA NALISU LETTER TONE MYA " +
"JEULISU PUNCTUATION COMMALISU PUNCTUATION FULL STOPVAI SYLLABLE EEVAI SY" +
"LLABLE EENVAI SYLLABLE HEEVAI SYLLABLE WEEVAI SYLLABLE WEENVAI SYLLABLE " +
"PEEVAI SYLLABLE BHEEVAI SYLLABLE BEEVAI SYLLABLE MBEEVAI SYLLABLE KPEEVA" +
"I SYLLABLE MGBEEVAI SYLLABLE GBEEVAI SYLLABLE FEEVAI SYLLABLE VEEVAI SYL" +
"LABLE TEEVAI SYLLABLE THEEVAI SYLLABLE DHEEVAI SYLLABLE DHHEEVAI SYLLABL" +
"E LEEVAI SYLLABLE REEVAI SYLLABLE DEEVAI SYLLABLE NDEEVAI SYLLABLE SEEVA" +
"I SYLLABLE SHEEVAI SYLLABLE ZEEVAI SYLLABLE ZHEEVAI SYLLABLE CEEVAI SYLL" +
"ABLE JEEVAI SYLLABLE NJEEVAI SYLLABLE YEEVAI SYLLABLE KEEVAI SYLLABLE NG" +
"GEEVAI SYLLABLE GEEVAI SYLLABLE MEEVAI SYLLABLE NEEVAI SYLLABLE NYEEVAI " +
"SYLLABLE IVAI SYLLABLE INVAI SYLLABLE HIVAI SYLLABLE HINVAI SYLLABLE WIV" +
"AI SYLLABLE WINVAI SYLLABLE PIVAI SYLLABLE BHIVAI SYLLABLE BIVAI SYLLABL" +
"E MBIVAI SYLLABLE KPIVAI SYLLABLE MGBIVAI SYLLABLE GBIVAI SYLLABLE FIVAI" +
" SYLLABLE VIVAI SYLLABLE TIVAI SYLLABLE THIVAI SYLLABLE DHIVAI SYLLABLE " +
"DHHIVAI SYLLABLE LIVAI SYLLABLE RIVAI SYLLABLE DIVAI SYLLABLE NDIVAI SYL" +
"LABLE SIVAI SYLLABLE SHIVAI SYLLABLE ZIVAI SYLLABLE ZHIVAI SYLLABLE CIVA" +
"I SYLLABLE JIVAI SYLLABLE NJIVAI SYLLABLE YIVAI SYLLABLE KIVAI SYLLABLE " +
"NGGIVAI SYLLABLE GIVAI SYLLABLE MIVAI SYLLABLE NIVAI SYLLABLE NYIVAI SYL" +
"LABLE AVAI SYLLABLE ANVAI SYLLABLE NGANVAI SYLLABLE HAVAI SYLLABLE HANVA" +
"I SYLLABLE WAVAI SYLLABLE WANVAI SYLLABLE PAVAI SYLLABLE BHAVAI SYLLABLE" +
" BAVAI SYLLABLE MBAVAI SYLLABLE KPAVAI SYLLABLE KPANVAI SYLLABLE MGBAVAI" +
" SYLLABLE GBAVAI SYLLABLE FAVAI SYLLABLE VAVAI SYLLABLE TAVAI SYLLABLE T" +
"HAVAI SYLLABLE DHAVAI SYLLABLE DHHAVAI SYLLABLE LAVAI SYLLABLE RAVAI SYL" +
"LABLE DAVAI SYLLABLE NDAVAI SYLLABLE SAVAI SYLLABLE SHAVAI SYLLABLE ZAVA" +
"I SYLLABLE ZHAVAI SYLLABLE CAVAI SYLLABLE JAVAI SYLLABLE NJAVAI SYLLABLE" +
" YAVAI SYLLABLE KAVAI SYLLABLE KANVAI SYLLABLE NGGAVAI SYLLABLE GAVAI SY" +
"LLABLE MAVAI SYLLABLE NAVAI SYLLABLE NYAVAI SYLLABLE OOVAI SYLLABLE OONV" +
"AI SYLLABLE HOOVAI SYLLABLE WOOVAI SYLLABLE WOONVAI SYLLABLE POOVAI SYLL") + ("" +
"ABLE BHOOVAI SYLLABLE BOOVAI SYLLABLE MBOOVAI SYLLABLE KPOOVAI SYLLABLE " +
"MGBOOVAI SYLLABLE GBOOVAI SYLLABLE FOOVAI SYLLABLE VOOVAI SYLLABLE TOOVA" +
"I SYLLABLE THOOVAI SYLLABLE DHOOVAI SYLLABLE DHHOOVAI SYLLABLE LOOVAI SY" +
"LLABLE ROOVAI SYLLABLE DOOVAI SYLLABLE NDOOVAI SYLLABLE SOOVAI SYLLABLE " +
"SHOOVAI SYLLABLE ZOOVAI SYLLABLE ZHOOVAI SYLLABLE COOVAI SYLLABLE JOOVAI" +
" SYLLABLE NJOOVAI SYLLABLE YOOVAI SYLLABLE KOOVAI SYLLABLE NGGOOVAI SYLL" +
"ABLE GOOVAI SYLLABLE MOOVAI SYLLABLE NOOVAI SYLLABLE NYOOVAI SYLLABLE UV" +
"AI SYLLABLE UNVAI SYLLABLE HUVAI SYLLABLE HUNVAI SYLLABLE WUVAI SYLLABLE" +
" WUNVAI SYLLABLE PUVAI SYLLABLE BHUVAI SYLLABLE BUVAI SYLLABLE MBUVAI SY" +
"LLABLE KPUVAI SYLLABLE MGBUVAI SYLLABLE GBUVAI SYLLABLE FUVAI SYLLABLE V" +
"UVAI SYLLABLE TUVAI SYLLABLE THUVAI SYLLABLE DHUVAI SYLLABLE DHHUVAI SYL" +
"LABLE LUVAI SYLLABLE RUVAI SYLLABLE DUVAI SYLLABLE NDUVAI SYLLABLE SUVAI" +
" SYLLABLE SHUVAI SYLLABLE ZUVAI SYLLABLE ZHUVAI SYLLABLE CUVAI SYLLABLE " +
"JUVAI SYLLABLE NJUVAI SYLLABLE YUVAI SYLLABLE KUVAI SYLLABLE NGGUVAI SYL" +
"LABLE GUVAI SYLLABLE MUVAI SYLLABLE NUVAI SYLLABLE NYUVAI SYLLABLE OVAI " +
"SYLLABLE ONVAI SYLLABLE NGONVAI SYLLABLE HOVAI SYLLABLE HONVAI SYLLABLE " +
"WOVAI SYLLABLE WONVAI SYLLABLE POVAI SYLLABLE BHOVAI SYLLABLE BOVAI SYLL" +
"ABLE MBOVAI SYLLABLE KPOVAI SYLLABLE MGBOVAI SYLLABLE GBOVAI SYLLABLE GB" +
"ONVAI SYLLABLE FOVAI SYLLABLE VOVAI SYLLABLE TOVAI SYLLABLE THOVAI SYLLA" +
"BLE DHOVAI SYLLABLE DHHOVAI SYLLABLE LOVAI SYLLABLE ROVAI SYLLABLE DOVAI" +
" SYLLABLE NDOVAI SYLLABLE SOVAI SYLLABLE SHOVAI SYLLABLE ZOVAI SYLLABLE " +
"ZHOVAI SYLLABLE COVAI SYLLABLE JOVAI SYLLABLE NJOVAI SYLLABLE YOVAI SYLL" +
"ABLE KOVAI SYLLABLE NGGOVAI SYLLABLE GOVAI SYLLABLE MOVAI SYLLABLE NOVAI" +
" SYLLABLE NYOVAI SYLLABLE EVAI SYLLABLE ENVAI SYLLABLE NGENVAI SYLLABLE " +
"HEVAI SYLLABLE HENVAI SYLLABLE WEVAI SYLLABLE WENVAI SYLLABLE PEVAI SYLL" +
"ABLE BHEVAI SYLLABLE BEVAI SYLLABLE MBEVAI SYLLABLE KPEVAI SYLLABLE KPEN" +
"VAI SYLLABLE MGBEVAI SYLLABLE GBEVAI SYLLABLE GBENVAI SYLLABLE FEVAI SYL" +
"LABLE VEVAI SYLLABLE TEVAI SYLLABLE THEVAI SYLLABLE DHEVAI SYLLABLE DHHE" +
"VAI SYLLABLE LEVAI SYLLABLE REVAI SYLLABLE DEVAI SYLLABLE NDEVAI SYLLABL" +
"E SEVAI SYLLABLE SHEVAI SYLLABLE ZEVAI SYLLABLE ZHEVAI SYLLABLE CEVAI SY" +
"LLABLE JEVAI SYLLABLE NJEVAI SYLLABLE YEVAI SYLLABLE KEVAI SYLLABLE NGGE" +
"VAI SYLLABLE NGGENVAI SYLLABLE GEVAI SYLLABLE GENVAI SYLLABLE MEVAI SYLL" +
"ABLE NEVAI SYLLABLE NYEVAI SYLLABLE NGVAI SYLLABLE LENGTHENERVAI COMMAVA" +
"I FULL STOPVAI QUESTION MARKVAI SYLLABLE NDOLE FAVAI SYLLABLE NDOLE KAVA" +
"I SYLLABLE NDOLE SOOVAI SYMBOL FEENGVAI SYMBOL KEENGVAI SYMBOL TINGVAI S" +
"YMBOL NIIVAI SYMBOL BANGVAI SYMBOL FAAVAI SYMBOL TAAVAI SYMBOL DANGVAI S" +
"YMBOL DOONGVAI SYMBOL KUNGVAI SYMBOL TONGVAI SYMBOL DO-OVAI SYMBOL JONGV" +
"AI DIGIT ZEROVAI DIGIT ONEVAI DIGIT TWOVAI DIGIT THREEVAI DIGIT FOURVAI " +
"DIGIT FIVEVAI DIGIT SIXVAI DIGIT SEVENVAI DIGIT EIGHTVAI DIGIT NINEVAI S" +
"YLLABLE NDOLE MAVAI SYLLABLE NDOLE DOCYRILLIC CAPITAL LETTER ZEMLYACYRIL" +
"LIC SMALL LETTER ZEMLYACYRILLIC CAPITAL LETTER DZELOCYRILLIC SMALL LETTE" +
"R DZELOCYRILLIC CAPITAL LETTER REVERSED DZECYRILLIC SMALL LETTER REVERSE" +
"D DZECYRILLIC CAPITAL LETTER IOTACYRILLIC SMALL LETTER IOTACYRILLIC CAPI" +
"TAL LETTER DJERVCYRILLIC SMALL LETTER DJERVCYRILLIC CAPITAL LETTER MONOG" +
"RAPH UKCYRILLIC SMALL LETTER MONOGRAPH UKCYRILLIC CAPITAL LETTER BROAD O" +
"MEGACYRILLIC SMALL LETTER BROAD OMEGACYRILLIC CAPITAL LETTER NEUTRAL YER" +
"CYRILLIC SMALL LETTER NEUTRAL YERCYRILLIC CAPITAL LETTER YERU WITH BACK " +
"YERCYRILLIC SMALL LETTER YERU WITH BACK YERCYRILLIC CAPITAL LETTER IOTIF" +
"IED YATCYRILLIC SMALL LETTER IOTIFIED YATCYRILLIC CAPITAL LETTER REVERSE" +
"D YUCYRILLIC SMALL LETTER REVERSED YUCYRILLIC CAPITAL LETTER IOTIFIED AC" +
"YRILLIC SMALL LETTER IOTIFIED ACYRILLIC CAPITAL LETTER CLOSED LITTLE YUS" +
"CYRILLIC SMALL LETTER CLOSED LITTLE YUSCYRILLIC CAPITAL LETTER BLENDED Y" +
"USCYRILLIC SMALL LETTER BLENDED YUSCYRILLIC CAPITAL LETTER IOTIFIED CLOS" +
"ED LITTLE YUSCYRILLIC SMALL LETTER IOTIFIED CLOSED LITTLE YUSCYRILLIC CA" +
"PITAL LETTER YNCYRILLIC SMALL LETTER YNCYRILLIC CAPITAL LETTER REVERSED " +
"TSECYRILLIC SMALL LETTER REVERSED TSECYRILLIC CAPITAL LETTER SOFT DECYRI" +
"LLIC SMALL LETTER SOFT DECYRILLIC CAPITAL LETTER SOFT ELCYRILLIC SMALL L" +
"ETTER SOFT ELCYRILLIC CAPITAL LETTER SOFT EMCYRILLIC SMALL LETTER SOFT E" +
"MCYRILLIC CAPITAL LETTER MONOCULAR OCYRILLIC SMALL LETTER MONOCULAR OCYR" +
"ILLIC CAPITAL LETTER BINOCULAR OCYRILLIC SMALL LETTER BINOCULAR OCYRILLI" +
"C CAPITAL LETTER DOUBLE MONOCULAR OCYRILLIC SMALL LETTER DOUBLE MONOCULA" +
"R OCYRILLIC LETTER MULTIOCULAR OCOMBINING CYRILLIC VZMETCOMBINING CYRILL" +
"IC TEN MILLIONS SIGNCOMBINING CYRILLIC HUNDRED MILLIONS SIGNCOMBINING CY" +
"RILLIC THOUSAND MILLIONS SIGNSLAVONIC ASTERISKCOMBINING CYRILLIC LETTER ") + ("" +
"UKRAINIAN IECOMBINING CYRILLIC LETTER ICOMBINING CYRILLIC LETTER YICOMBI" +
"NING CYRILLIC LETTER UCOMBINING CYRILLIC LETTER HARD SIGNCOMBINING CYRIL" +
"LIC LETTER YERUCOMBINING CYRILLIC LETTER SOFT SIGNCOMBINING CYRILLIC LET" +
"TER OMEGACOMBINING CYRILLIC KAVYKACOMBINING CYRILLIC PAYEROKCYRILLIC KAV" +
"YKACYRILLIC PAYEROKCYRILLIC CAPITAL LETTER DWECYRILLIC SMALL LETTER DWEC" +
"YRILLIC CAPITAL LETTER DZWECYRILLIC SMALL LETTER DZWECYRILLIC CAPITAL LE" +
"TTER ZHWECYRILLIC SMALL LETTER ZHWECYRILLIC CAPITAL LETTER CCHECYRILLIC " +
"SMALL LETTER CCHECYRILLIC CAPITAL LETTER DZZECYRILLIC SMALL LETTER DZZEC" +
"YRILLIC CAPITAL LETTER TE WITH MIDDLE HOOKCYRILLIC SMALL LETTER TE WITH " +
"MIDDLE HOOKCYRILLIC CAPITAL LETTER TWECYRILLIC SMALL LETTER TWECYRILLIC " +
"CAPITAL LETTER TSWECYRILLIC SMALL LETTER TSWECYRILLIC CAPITAL LETTER TSS" +
"ECYRILLIC SMALL LETTER TSSECYRILLIC CAPITAL LETTER TCHECYRILLIC SMALL LE" +
"TTER TCHECYRILLIC CAPITAL LETTER HWECYRILLIC SMALL LETTER HWECYRILLIC CA" +
"PITAL LETTER SHWECYRILLIC SMALL LETTER SHWECYRILLIC CAPITAL LETTER DOUBL" +
"E OCYRILLIC SMALL LETTER DOUBLE OCYRILLIC CAPITAL LETTER CROSSED OCYRILL" +
"IC SMALL LETTER CROSSED OMODIFIER LETTER CYRILLIC HARD SIGNMODIFIER LETT" +
"ER CYRILLIC SOFT SIGNCOMBINING CYRILLIC LETTER EFCOMBINING CYRILLIC LETT" +
"ER IOTIFIED EBAMUM LETTER ABAMUM LETTER KABAMUM LETTER UBAMUM LETTER KUB" +
"AMUM LETTER EEBAMUM LETTER REEBAMUM LETTER TAEBAMUM LETTER OBAMUM LETTER" +
" NYIBAMUM LETTER IBAMUM LETTER LABAMUM LETTER PABAMUM LETTER RIIBAMUM LE" +
"TTER RIEEBAMUM LETTER LEEEEBAMUM LETTER MEEEEBAMUM LETTER TAABAMUM LETTE" +
"R NDAABAMUM LETTER NJAEMBAMUM LETTER MBAMUM LETTER SUUBAMUM LETTER MUBAM" +
"UM LETTER SHIIBAMUM LETTER SIBAMUM LETTER SHEUXBAMUM LETTER SEUXBAMUM LE" +
"TTER KYEEBAMUM LETTER KETBAMUM LETTER NUAEBAMUM LETTER NUBAMUM LETTER NJ" +
"UAEBAMUM LETTER YOQBAMUM LETTER SHUBAMUM LETTER YUQBAMUM LETTER YABAMUM " +
"LETTER NSHABAMUM LETTER KEUXBAMUM LETTER PEUXBAMUM LETTER NJEEBAMUM LETT" +
"ER NTEEBAMUM LETTER PUEBAMUM LETTER WUEBAMUM LETTER PEEBAMUM LETTER FEEB" +
"AMUM LETTER RUBAMUM LETTER LUBAMUM LETTER MIBAMUM LETTER NIBAMUM LETTER " +
"REUXBAMUM LETTER RAEBAMUM LETTER KENBAMUM LETTER NGKWAENBAMUM LETTER NGG" +
"ABAMUM LETTER NGABAMUM LETTER SHOBAMUM LETTER PUAEBAMUM LETTER FUBAMUM L" +
"ETTER FOMBAMUM LETTER WABAMUM LETTER NABAMUM LETTER LIBAMUM LETTER PIBAM" +
"UM LETTER LOQBAMUM LETTER KOBAMUM LETTER MBENBAMUM LETTER RENBAMUM LETTE" +
"R MENBAMUM LETTER MABAMUM LETTER TIBAMUM LETTER KIBAMUM LETTER MOBAMUM L" +
"ETTER MBAABAMUM LETTER TETBAMUM LETTER KPABAMUM LETTER TENBAMUM LETTER N" +
"TUUBAMUM LETTER SAMBABAMUM LETTER FAAMAEBAMUM LETTER KOVUUBAMUM LETTER K" +
"OGHOMBAMUM COMBINING MARK KOQNDONBAMUM COMBINING MARK TUKWENTISBAMUM NJA" +
"EMLIBAMUM FULL STOPBAMUM COLONBAMUM COMMABAMUM SEMICOLONBAMUM QUESTION M" +
"ARKMODIFIER LETTER CHINESE TONE YIN PINGMODIFIER LETTER CHINESE TONE YAN" +
"G PINGMODIFIER LETTER CHINESE TONE YIN SHANGMODIFIER LETTER CHINESE TONE" +
" YANG SHANGMODIFIER LETTER CHINESE TONE YIN QUMODIFIER LETTER CHINESE TO" +
"NE YANG QUMODIFIER LETTER CHINESE TONE YIN RUMODIFIER LETTER CHINESE TON" +
"E YANG RUMODIFIER LETTER EXTRA-HIGH DOTTED TONE BARMODIFIER LETTER HIGH " +
"DOTTED TONE BARMODIFIER LETTER MID DOTTED TONE BARMODIFIER LETTER LOW DO" +
"TTED TONE BARMODIFIER LETTER EXTRA-LOW DOTTED TONE BARMODIFIER LETTER EX" +
"TRA-HIGH DOTTED LEFT-STEM TONE BARMODIFIER LETTER HIGH DOTTED LEFT-STEM " +
"TONE BARMODIFIER LETTER MID DOTTED LEFT-STEM TONE BARMODIFIER LETTER LOW" +
" DOTTED LEFT-STEM TONE BARMODIFIER LETTER EXTRA-LOW DOTTED LEFT-STEM TON" +
"E BARMODIFIER LETTER EXTRA-HIGH LEFT-STEM TONE BARMODIFIER LETTER HIGH L" +
"EFT-STEM TONE BARMODIFIER LETTER MID LEFT-STEM TONE BARMODIFIER LETTER L" +
"OW LEFT-STEM TONE BARMODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BARMODIFIE" +
"R LETTER DOT VERTICAL BARMODIFIER LETTER DOT SLASHMODIFIER LETTER DOT HO" +
"RIZONTAL BARMODIFIER LETTER LOWER RIGHT CORNER ANGLEMODIFIER LETTER RAIS" +
"ED UP ARROWMODIFIER LETTER RAISED DOWN ARROWMODIFIER LETTER RAISED EXCLA" +
"MATION MARKMODIFIER LETTER RAISED INVERTED EXCLAMATION MARKMODIFIER LETT" +
"ER LOW INVERTED EXCLAMATION MARKMODIFIER LETTER STRESS AND HIGH TONEMODI" +
"FIER LETTER STRESS AND LOW TONELATIN CAPITAL LETTER EGYPTOLOGICAL ALEFLA" +
"TIN SMALL LETTER EGYPTOLOGICAL ALEFLATIN CAPITAL LETTER EGYPTOLOGICAL AI" +
"NLATIN SMALL LETTER EGYPTOLOGICAL AINLATIN CAPITAL LETTER HENGLATIN SMAL" +
"L LETTER HENGLATIN CAPITAL LETTER TZLATIN SMALL LETTER TZLATIN CAPITAL L" +
"ETTER TRESILLOLATIN SMALL LETTER TRESILLOLATIN CAPITAL LETTER CUATRILLOL" +
"ATIN SMALL LETTER CUATRILLOLATIN CAPITAL LETTER CUATRILLO WITH COMMALATI" +
"N SMALL LETTER CUATRILLO WITH COMMALATIN LETTER SMALL CAPITAL FLATIN LET" +
"TER SMALL CAPITAL SLATIN CAPITAL LETTER AALATIN SMALL LETTER AALATIN CAP" +
"ITAL LETTER AOLATIN SMALL LETTER AOLATIN CAPITAL LETTER AULATIN SMALL LE") + ("" +
"TTER AULATIN CAPITAL LETTER AVLATIN SMALL LETTER AVLATIN CAPITAL LETTER " +
"AV WITH HORIZONTAL BARLATIN SMALL LETTER AV WITH HORIZONTAL BARLATIN CAP" +
"ITAL LETTER AYLATIN SMALL LETTER AYLATIN CAPITAL LETTER REVERSED C WITH " +
"DOTLATIN SMALL LETTER REVERSED C WITH DOTLATIN CAPITAL LETTER K WITH STR" +
"OKELATIN SMALL LETTER K WITH STROKELATIN CAPITAL LETTER K WITH DIAGONAL " +
"STROKELATIN SMALL LETTER K WITH DIAGONAL STROKELATIN CAPITAL LETTER K WI" +
"TH STROKE AND DIAGONAL STROKELATIN SMALL LETTER K WITH STROKE AND DIAGON" +
"AL STROKELATIN CAPITAL LETTER BROKEN LLATIN SMALL LETTER BROKEN LLATIN C" +
"APITAL LETTER L WITH HIGH STROKELATIN SMALL LETTER L WITH HIGH STROKELAT" +
"IN CAPITAL LETTER O WITH LONG STROKE OVERLAYLATIN SMALL LETTER O WITH LO" +
"NG STROKE OVERLAYLATIN CAPITAL LETTER O WITH LOOPLATIN SMALL LETTER O WI" +
"TH LOOPLATIN CAPITAL LETTER OOLATIN SMALL LETTER OOLATIN CAPITAL LETTER " +
"P WITH STROKE THROUGH DESCENDERLATIN SMALL LETTER P WITH STROKE THROUGH " +
"DESCENDERLATIN CAPITAL LETTER P WITH FLOURISHLATIN SMALL LETTER P WITH F" +
"LOURISHLATIN CAPITAL LETTER P WITH SQUIRREL TAILLATIN SMALL LETTER P WIT" +
"H SQUIRREL TAILLATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDERLATIN" +
" SMALL LETTER Q WITH STROKE THROUGH DESCENDERLATIN CAPITAL LETTER Q WITH" +
" DIAGONAL STROKELATIN SMALL LETTER Q WITH DIAGONAL STROKELATIN CAPITAL L" +
"ETTER R ROTUNDALATIN SMALL LETTER R ROTUNDALATIN CAPITAL LETTER RUM ROTU" +
"NDALATIN SMALL LETTER RUM ROTUNDALATIN CAPITAL LETTER V WITH DIAGONAL ST" +
"ROKELATIN SMALL LETTER V WITH DIAGONAL STROKELATIN CAPITAL LETTER VYLATI" +
"N SMALL LETTER VYLATIN CAPITAL LETTER VISIGOTHIC ZLATIN SMALL LETTER VIS" +
"IGOTHIC ZLATIN CAPITAL LETTER THORN WITH STROKELATIN SMALL LETTER THORN " +
"WITH STROKELATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDERLATIN" +
" SMALL LETTER THORN WITH STROKE THROUGH DESCENDERLATIN CAPITAL LETTER VE" +
"NDLATIN SMALL LETTER VENDLATIN CAPITAL LETTER ETLATIN SMALL LETTER ETLAT" +
"IN CAPITAL LETTER ISLATIN SMALL LETTER ISLATIN CAPITAL LETTER CONLATIN S" +
"MALL LETTER CONMODIFIER LETTER USLATIN SMALL LETTER DUMLATIN SMALL LETTE" +
"R LUMLATIN SMALL LETTER MUMLATIN SMALL LETTER NUMLATIN SMALL LETTER RUML" +
"ATIN LETTER SMALL CAPITAL RUMLATIN SMALL LETTER TUMLATIN SMALL LETTER UM" +
"LATIN CAPITAL LETTER INSULAR DLATIN SMALL LETTER INSULAR DLATIN CAPITAL " +
"LETTER INSULAR FLATIN SMALL LETTER INSULAR FLATIN CAPITAL LETTER INSULAR" +
" GLATIN CAPITAL LETTER TURNED INSULAR GLATIN SMALL LETTER TURNED INSULAR" +
" GLATIN CAPITAL LETTER TURNED LLATIN SMALL LETTER TURNED LLATIN CAPITAL " +
"LETTER INSULAR RLATIN SMALL LETTER INSULAR RLATIN CAPITAL LETTER INSULAR" +
" SLATIN SMALL LETTER INSULAR SLATIN CAPITAL LETTER INSULAR TLATIN SMALL " +
"LETTER INSULAR TMODIFIER LETTER LOW CIRCUMFLEX ACCENTMODIFIER LETTER COL" +
"ONMODIFIER LETTER SHORT EQUALS SIGNLATIN CAPITAL LETTER SALTILLOLATIN SM" +
"ALL LETTER SALTILLOLATIN CAPITAL LETTER TURNED HLATIN SMALL LETTER L WIT" +
"H RETROFLEX HOOK AND BELTLATIN LETTER SINOLOGICAL DOTLATIN CAPITAL LETTE" +
"R N WITH DESCENDERLATIN SMALL LETTER N WITH DESCENDERLATIN CAPITAL LETTE" +
"R C WITH BARLATIN SMALL LETTER C WITH BARLATIN SMALL LETTER C WITH PALAT" +
"AL HOOKLATIN SMALL LETTER H WITH PALATAL HOOKLATIN CAPITAL LETTER B WITH" +
" FLOURISHLATIN SMALL LETTER B WITH FLOURISHLATIN CAPITAL LETTER F WITH S" +
"TROKELATIN SMALL LETTER F WITH STROKELATIN CAPITAL LETTER VOLAPUK AELATI" +
"N SMALL LETTER VOLAPUK AELATIN CAPITAL LETTER VOLAPUK OELATIN SMALL LETT" +
"ER VOLAPUK OELATIN CAPITAL LETTER VOLAPUK UELATIN SMALL LETTER VOLAPUK U" +
"ELATIN CAPITAL LETTER G WITH OBLIQUE STROKELATIN SMALL LETTER G WITH OBL" +
"IQUE STROKELATIN CAPITAL LETTER K WITH OBLIQUE STROKELATIN SMALL LETTER " +
"K WITH OBLIQUE STROKELATIN CAPITAL LETTER N WITH OBLIQUE STROKELATIN SMA" +
"LL LETTER N WITH OBLIQUE STROKELATIN CAPITAL LETTER R WITH OBLIQUE STROK" +
"ELATIN SMALL LETTER R WITH OBLIQUE STROKELATIN CAPITAL LETTER S WITH OBL" +
"IQUE STROKELATIN SMALL LETTER S WITH OBLIQUE STROKELATIN CAPITAL LETTER " +
"H WITH HOOKLATIN CAPITAL LETTER REVERSED OPEN ELATIN CAPITAL LETTER SCRI" +
"PT GLATIN CAPITAL LETTER L WITH BELTLATIN CAPITAL LETTER SMALL CAPITAL I" +
"LATIN LETTER SMALL CAPITAL QLATIN CAPITAL LETTER TURNED KLATIN CAPITAL L" +
"ETTER TURNED TLATIN CAPITAL LETTER J WITH CROSSED-TAILLATIN CAPITAL LETT" +
"ER CHILATIN CAPITAL LETTER BETALATIN SMALL LETTER BETALATIN CAPITAL LETT" +
"ER OMEGALATIN SMALL LETTER OMEGALATIN CAPITAL LETTER U WITH STROKELATIN " +
"SMALL LETTER U WITH STROKELATIN CAPITAL LETTER GLOTTAL ALATIN SMALL LETT" +
"ER GLOTTAL ALATIN CAPITAL LETTER GLOTTAL ILATIN SMALL LETTER GLOTTAL ILA" +
"TIN CAPITAL LETTER GLOTTAL ULATIN SMALL LETTER GLOTTAL ULATIN CAPITAL LE" +
"TTER OLD POLISH OLATIN SMALL LETTER OLD POLISH OLATIN CAPITAL LETTER ANG" +
"LICANA WLATIN SMALL LETTER ANGLICANA WLATIN CAPITAL LETTER C WITH PALATA") + ("" +
"L HOOKLATIN CAPITAL LETTER S WITH HOOKLATIN CAPITAL LETTER Z WITH PALATA" +
"L HOOKLATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAYLATIN SMALL LETTER" +
" D WITH SHORT STROKE OVERLAYLATIN CAPITAL LETTER S WITH SHORT STROKE OVE" +
"RLAYLATIN SMALL LETTER S WITH SHORT STROKE OVERLAYLATIN CAPITAL LETTER C" +
"LOSED INSULAR GLATIN SMALL LETTER CLOSED INSULAR GLATIN SMALL LETTER DOU" +
"BLE THORNLATIN SMALL LETTER DOUBLE WYNNLATIN CAPITAL LETTER MIDDLE SCOTS" +
" SLATIN SMALL LETTER MIDDLE SCOTS SLATIN CAPITAL LETTER SIGMOID SLATIN S" +
"MALL LETTER SIGMOID SMODIFIER LETTER CAPITAL CMODIFIER LETTER CAPITAL FM" +
"ODIFIER LETTER CAPITAL QLATIN CAPITAL LETTER REVERSED HALF HLATIN SMALL " +
"LETTER REVERSED HALF HLATIN EPIGRAPHIC LETTER SIDEWAYS IMODIFIER LETTER " +
"CAPITAL H WITH STROKEMODIFIER LETTER SMALL LIGATURE OELATIN LETTER SMALL" +
" CAPITAL TURNED MLATIN EPIGRAPHIC LETTER REVERSED FLATIN EPIGRAPHIC LETT" +
"ER REVERSED PLATIN EPIGRAPHIC LETTER INVERTED MLATIN EPIGRAPHIC LETTER I" +
" LONGALATIN EPIGRAPHIC LETTER ARCHAIC MSYLOTI NAGRI LETTER ASYLOTI NAGRI" +
" LETTER ISYLOTI NAGRI SIGN DVISVARASYLOTI NAGRI LETTER USYLOTI NAGRI LET" +
"TER ESYLOTI NAGRI LETTER OSYLOTI NAGRI SIGN HASANTASYLOTI NAGRI LETTER K" +
"OSYLOTI NAGRI LETTER KHOSYLOTI NAGRI LETTER GOSYLOTI NAGRI LETTER GHOSYL" +
"OTI NAGRI SIGN ANUSVARASYLOTI NAGRI LETTER COSYLOTI NAGRI LETTER CHOSYLO" +
"TI NAGRI LETTER JOSYLOTI NAGRI LETTER JHOSYLOTI NAGRI LETTER TTOSYLOTI N" +
"AGRI LETTER TTHOSYLOTI NAGRI LETTER DDOSYLOTI NAGRI LETTER DDHOSYLOTI NA" +
"GRI LETTER TOSYLOTI NAGRI LETTER THOSYLOTI NAGRI LETTER DOSYLOTI NAGRI L" +
"ETTER DHOSYLOTI NAGRI LETTER NOSYLOTI NAGRI LETTER POSYLOTI NAGRI LETTER" +
" PHOSYLOTI NAGRI LETTER BOSYLOTI NAGRI LETTER BHOSYLOTI NAGRI LETTER MOS" +
"YLOTI NAGRI LETTER ROSYLOTI NAGRI LETTER LOSYLOTI NAGRI LETTER RROSYLOTI" +
" NAGRI LETTER SOSYLOTI NAGRI LETTER HOSYLOTI NAGRI VOWEL SIGN ASYLOTI NA" +
"GRI VOWEL SIGN ISYLOTI NAGRI VOWEL SIGN USYLOTI NAGRI VOWEL SIGN ESYLOTI" +
" NAGRI VOWEL SIGN OOSYLOTI NAGRI POETRY MARK-1SYLOTI NAGRI POETRY MARK-2" +
"SYLOTI NAGRI POETRY MARK-3SYLOTI NAGRI POETRY MARK-4SYLOTI NAGRI SIGN AL" +
"TERNATE HASANTANORTH INDIC FRACTION ONE QUARTERNORTH INDIC FRACTION ONE " +
"HALFNORTH INDIC FRACTION THREE QUARTERSNORTH INDIC FRACTION ONE SIXTEENT" +
"HNORTH INDIC FRACTION ONE EIGHTHNORTH INDIC FRACTION THREE SIXTEENTHSNOR" +
"TH INDIC QUARTER MARKNORTH INDIC PLACEHOLDER MARKNORTH INDIC RUPEE MARKN" +
"ORTH INDIC QUANTITY MARKPHAGS-PA LETTER KAPHAGS-PA LETTER KHAPHAGS-PA LE" +
"TTER GAPHAGS-PA LETTER NGAPHAGS-PA LETTER CAPHAGS-PA LETTER CHAPHAGS-PA " +
"LETTER JAPHAGS-PA LETTER NYAPHAGS-PA LETTER TAPHAGS-PA LETTER THAPHAGS-P" +
"A LETTER DAPHAGS-PA LETTER NAPHAGS-PA LETTER PAPHAGS-PA LETTER PHAPHAGS-" +
"PA LETTER BAPHAGS-PA LETTER MAPHAGS-PA LETTER TSAPHAGS-PA LETTER TSHAPHA" +
"GS-PA LETTER DZAPHAGS-PA LETTER WAPHAGS-PA LETTER ZHAPHAGS-PA LETTER ZAP" +
"HAGS-PA LETTER SMALL APHAGS-PA LETTER YAPHAGS-PA LETTER RAPHAGS-PA LETTE" +
"R LAPHAGS-PA LETTER SHAPHAGS-PA LETTER SAPHAGS-PA LETTER HAPHAGS-PA LETT" +
"ER APHAGS-PA LETTER IPHAGS-PA LETTER UPHAGS-PA LETTER EPHAGS-PA LETTER O" +
"PHAGS-PA LETTER QAPHAGS-PA LETTER XAPHAGS-PA LETTER FAPHAGS-PA LETTER GG" +
"APHAGS-PA LETTER EEPHAGS-PA SUBJOINED LETTER WAPHAGS-PA SUBJOINED LETTER" +
" YAPHAGS-PA LETTER TTAPHAGS-PA LETTER TTHAPHAGS-PA LETTER DDAPHAGS-PA LE" +
"TTER NNAPHAGS-PA LETTER ALTERNATE YAPHAGS-PA LETTER VOICELESS SHAPHAGS-P" +
"A LETTER VOICED HAPHAGS-PA LETTER ASPIRATED FAPHAGS-PA SUBJOINED LETTER " +
"RAPHAGS-PA SUPERFIXED LETTER RAPHAGS-PA LETTER CANDRABINDUPHAGS-PA SINGL" +
"E HEAD MARKPHAGS-PA DOUBLE HEAD MARKPHAGS-PA MARK SHADPHAGS-PA MARK DOUB" +
"LE SHADSAURASHTRA SIGN ANUSVARASAURASHTRA SIGN VISARGASAURASHTRA LETTER " +
"ASAURASHTRA LETTER AASAURASHTRA LETTER ISAURASHTRA LETTER IISAURASHTRA L" +
"ETTER USAURASHTRA LETTER UUSAURASHTRA LETTER VOCALIC RSAURASHTRA LETTER " +
"VOCALIC RRSAURASHTRA LETTER VOCALIC LSAURASHTRA LETTER VOCALIC LLSAURASH" +
"TRA LETTER ESAURASHTRA LETTER EESAURASHTRA LETTER AISAURASHTRA LETTER OS" +
"AURASHTRA LETTER OOSAURASHTRA LETTER AUSAURASHTRA LETTER KASAURASHTRA LE" +
"TTER KHASAURASHTRA LETTER GASAURASHTRA LETTER GHASAURASHTRA LETTER NGASA" +
"URASHTRA LETTER CASAURASHTRA LETTER CHASAURASHTRA LETTER JASAURASHTRA LE" +
"TTER JHASAURASHTRA LETTER NYASAURASHTRA LETTER TTASAURASHTRA LETTER TTHA" +
"SAURASHTRA LETTER DDASAURASHTRA LETTER DDHASAURASHTRA LETTER NNASAURASHT" +
"RA LETTER TASAURASHTRA LETTER THASAURASHTRA LETTER DASAURASHTRA LETTER D" +
"HASAURASHTRA LETTER NASAURASHTRA LETTER PASAURASHTRA LETTER PHASAURASHTR" +
"A LETTER BASAURASHTRA LETTER BHASAURASHTRA LETTER MASAURASHTRA LETTER YA" +
"SAURASHTRA LETTER RASAURASHTRA LETTER LASAURASHTRA LETTER VASAURASHTRA L" +
"ETTER SHASAURASHTRA LETTER SSASAURASHTRA LETTER SASAURASHTRA LETTER HASA" +
"URASHTRA LETTER LLASAURASHTRA CONSONANT SIGN HAARUSAURASHTRA VOWEL SIGN ") + ("" +
"AASAURASHTRA VOWEL SIGN ISAURASHTRA VOWEL SIGN IISAURASHTRA VOWEL SIGN U" +
"SAURASHTRA VOWEL SIGN UUSAURASHTRA VOWEL SIGN VOCALIC RSAURASHTRA VOWEL " +
"SIGN VOCALIC RRSAURASHTRA VOWEL SIGN VOCALIC LSAURASHTRA VOWEL SIGN VOCA" +
"LIC LLSAURASHTRA VOWEL SIGN ESAURASHTRA VOWEL SIGN EESAURASHTRA VOWEL SI" +
"GN AISAURASHTRA VOWEL SIGN OSAURASHTRA VOWEL SIGN OOSAURASHTRA VOWEL SIG" +
"N AUSAURASHTRA SIGN VIRAMASAURASHTRA SIGN CANDRABINDUSAURASHTRA DANDASAU" +
"RASHTRA DOUBLE DANDASAURASHTRA DIGIT ZEROSAURASHTRA DIGIT ONESAURASHTRA " +
"DIGIT TWOSAURASHTRA DIGIT THREESAURASHTRA DIGIT FOURSAURASHTRA DIGIT FIV" +
"ESAURASHTRA DIGIT SIXSAURASHTRA DIGIT SEVENSAURASHTRA DIGIT EIGHTSAURASH" +
"TRA DIGIT NINECOMBINING DEVANAGARI DIGIT ZEROCOMBINING DEVANAGARI DIGIT " +
"ONECOMBINING DEVANAGARI DIGIT TWOCOMBINING DEVANAGARI DIGIT THREECOMBINI" +
"NG DEVANAGARI DIGIT FOURCOMBINING DEVANAGARI DIGIT FIVECOMBINING DEVANAG" +
"ARI DIGIT SIXCOMBINING DEVANAGARI DIGIT SEVENCOMBINING DEVANAGARI DIGIT " +
"EIGHTCOMBINING DEVANAGARI DIGIT NINECOMBINING DEVANAGARI LETTER ACOMBINI" +
"NG DEVANAGARI LETTER UCOMBINING DEVANAGARI LETTER KACOMBINING DEVANAGARI" +
" LETTER NACOMBINING DEVANAGARI LETTER PACOMBINING DEVANAGARI LETTER RACO" +
"MBINING DEVANAGARI LETTER VICOMBINING DEVANAGARI SIGN AVAGRAHADEVANAGARI" +
" SIGN SPACING CANDRABINDUDEVANAGARI SIGN CANDRABINDU VIRAMADEVANAGARI SI" +
"GN DOUBLE CANDRABINDU VIRAMADEVANAGARI SIGN CANDRABINDU TWODEVANAGARI SI" +
"GN CANDRABINDU THREEDEVANAGARI SIGN CANDRABINDU AVAGRAHADEVANAGARI SIGN " +
"PUSHPIKADEVANAGARI GAP FILLERDEVANAGARI CARETDEVANAGARI HEADSTROKEDEVANA" +
"GARI SIGN SIDDHAMDEVANAGARI JAIN OMDEVANAGARI LETTER AYDEVANAGARI VOWEL " +
"SIGN AYKAYAH LI DIGIT ZEROKAYAH LI DIGIT ONEKAYAH LI DIGIT TWOKAYAH LI D" +
"IGIT THREEKAYAH LI DIGIT FOURKAYAH LI DIGIT FIVEKAYAH LI DIGIT SIXKAYAH " +
"LI DIGIT SEVENKAYAH LI DIGIT EIGHTKAYAH LI DIGIT NINEKAYAH LI LETTER KAK" +
"AYAH LI LETTER KHAKAYAH LI LETTER GAKAYAH LI LETTER NGAKAYAH LI LETTER S" +
"AKAYAH LI LETTER SHAKAYAH LI LETTER ZAKAYAH LI LETTER NYAKAYAH LI LETTER" +
" TAKAYAH LI LETTER HTAKAYAH LI LETTER NAKAYAH LI LETTER PAKAYAH LI LETTE" +
"R PHAKAYAH LI LETTER MAKAYAH LI LETTER DAKAYAH LI LETTER BAKAYAH LI LETT" +
"ER RAKAYAH LI LETTER YAKAYAH LI LETTER LAKAYAH LI LETTER WAKAYAH LI LETT" +
"ER THAKAYAH LI LETTER HAKAYAH LI LETTER VAKAYAH LI LETTER CAKAYAH LI LET" +
"TER AKAYAH LI LETTER OEKAYAH LI LETTER IKAYAH LI LETTER OOKAYAH LI VOWEL" +
" UEKAYAH LI VOWEL EKAYAH LI VOWEL UKAYAH LI VOWEL EEKAYAH LI VOWEL OKAYA" +
"H LI TONE PLOPHUKAYAH LI TONE CALYAKAYAH LI TONE CALYA PLOPHUKAYAH LI SI" +
"GN CWIKAYAH LI SIGN SHYAREJANG LETTER KAREJANG LETTER GAREJANG LETTER NG" +
"AREJANG LETTER TAREJANG LETTER DAREJANG LETTER NAREJANG LETTER PAREJANG " +
"LETTER BAREJANG LETTER MAREJANG LETTER CAREJANG LETTER JAREJANG LETTER N" +
"YAREJANG LETTER SAREJANG LETTER RAREJANG LETTER LAREJANG LETTER YAREJANG" +
" LETTER WAREJANG LETTER HAREJANG LETTER MBAREJANG LETTER NGGAREJANG LETT" +
"ER NDAREJANG LETTER NYJAREJANG LETTER AREJANG VOWEL SIGN IREJANG VOWEL S" +
"IGN UREJANG VOWEL SIGN EREJANG VOWEL SIGN AIREJANG VOWEL SIGN OREJANG VO" +
"WEL SIGN AUREJANG VOWEL SIGN EUREJANG VOWEL SIGN EAREJANG CONSONANT SIGN" +
" NGREJANG CONSONANT SIGN NREJANG CONSONANT SIGN RREJANG CONSONANT SIGN H" +
"REJANG VIRAMAREJANG SECTION MARKHANGUL CHOSEONG TIKEUT-MIEUMHANGUL CHOSE" +
"ONG TIKEUT-PIEUPHANGUL CHOSEONG TIKEUT-SIOSHANGUL CHOSEONG TIKEUT-CIEUCH" +
"ANGUL CHOSEONG RIEUL-KIYEOKHANGUL CHOSEONG RIEUL-SSANGKIYEOKHANGUL CHOSE" +
"ONG RIEUL-TIKEUTHANGUL CHOSEONG RIEUL-SSANGTIKEUTHANGUL CHOSEONG RIEUL-M" +
"IEUMHANGUL CHOSEONG RIEUL-PIEUPHANGUL CHOSEONG RIEUL-SSANGPIEUPHANGUL CH" +
"OSEONG RIEUL-KAPYEOUNPIEUPHANGUL CHOSEONG RIEUL-SIOSHANGUL CHOSEONG RIEU" +
"L-CIEUCHANGUL CHOSEONG RIEUL-KHIEUKHHANGUL CHOSEONG MIEUM-KIYEOKHANGUL C" +
"HOSEONG MIEUM-TIKEUTHANGUL CHOSEONG MIEUM-SIOSHANGUL CHOSEONG PIEUP-SIOS" +
"-THIEUTHHANGUL CHOSEONG PIEUP-KHIEUKHHANGUL CHOSEONG PIEUP-HIEUHHANGUL C" +
"HOSEONG SSANGSIOS-PIEUPHANGUL CHOSEONG IEUNG-RIEULHANGUL CHOSEONG IEUNG-" +
"HIEUHHANGUL CHOSEONG SSANGCIEUC-HIEUHHANGUL CHOSEONG SSANGTHIEUTHHANGUL " +
"CHOSEONG PHIEUPH-HIEUHHANGUL CHOSEONG HIEUH-SIOSHANGUL CHOSEONG SSANGYEO" +
"RINHIEUHJAVANESE SIGN PANYANGGAJAVANESE SIGN CECAKJAVANESE SIGN LAYARJAV" +
"ANESE SIGN WIGNYANJAVANESE LETTER AJAVANESE LETTER I KAWIJAVANESE LETTER" +
" IJAVANESE LETTER IIJAVANESE LETTER UJAVANESE LETTER PA CEREKJAVANESE LE" +
"TTER NGA LELETJAVANESE LETTER NGA LELET RASWADIJAVANESE LETTER EJAVANESE" +
" LETTER AIJAVANESE LETTER OJAVANESE LETTER KAJAVANESE LETTER KA SASAKJAV" +
"ANESE LETTER KA MURDAJAVANESE LETTER GAJAVANESE LETTER GA MURDAJAVANESE " +
"LETTER NGAJAVANESE LETTER CAJAVANESE LETTER CA MURDAJAVANESE LETTER JAJA" +
"VANESE LETTER NYA MURDAJAVANESE LETTER JA MAHAPRANAJAVANESE LETTER NYAJA" +
"VANESE LETTER TTAJAVANESE LETTER TTA MAHAPRANAJAVANESE LETTER DDAJAVANES") + ("" +
"E LETTER DDA MAHAPRANAJAVANESE LETTER NA MURDAJAVANESE LETTER TAJAVANESE" +
" LETTER TA MURDAJAVANESE LETTER DAJAVANESE LETTER DA MAHAPRANAJAVANESE L" +
"ETTER NAJAVANESE LETTER PAJAVANESE LETTER PA MURDAJAVANESE LETTER BAJAVA" +
"NESE LETTER BA MURDAJAVANESE LETTER MAJAVANESE LETTER YAJAVANESE LETTER " +
"RAJAVANESE LETTER RA AGUNGJAVANESE LETTER LAJAVANESE LETTER WAJAVANESE L" +
"ETTER SA MURDAJAVANESE LETTER SA MAHAPRANAJAVANESE LETTER SAJAVANESE LET" +
"TER HAJAVANESE SIGN CECAK TELUJAVANESE VOWEL SIGN TARUNGJAVANESE VOWEL S" +
"IGN TOLONGJAVANESE VOWEL SIGN WULUJAVANESE VOWEL SIGN WULU MELIKJAVANESE" +
" VOWEL SIGN SUKUJAVANESE VOWEL SIGN SUKU MENDUTJAVANESE VOWEL SIGN TALIN" +
"GJAVANESE VOWEL SIGN DIRGA MUREJAVANESE VOWEL SIGN PEPETJAVANESE CONSONA" +
"NT SIGN KERETJAVANESE CONSONANT SIGN PENGKALJAVANESE CONSONANT SIGN CAKR" +
"AJAVANESE PANGKONJAVANESE LEFT RERENGGANJAVANESE RIGHT RERENGGANJAVANESE" +
" PADA ANDAPJAVANESE PADA MADYAJAVANESE PADA LUHURJAVANESE PADA WINDUJAVA" +
"NESE PADA PANGKATJAVANESE PADA LINGSAJAVANESE PADA LUNGSIJAVANESE PADA A" +
"DEGJAVANESE PADA ADEG ADEGJAVANESE PADA PISELEHJAVANESE TURNED PADA PISE" +
"LEHJAVANESE PANGRANGKEPJAVANESE DIGIT ZEROJAVANESE DIGIT ONEJAVANESE DIG" +
"IT TWOJAVANESE DIGIT THREEJAVANESE DIGIT FOURJAVANESE DIGIT FIVEJAVANESE" +
" DIGIT SIXJAVANESE DIGIT SEVENJAVANESE DIGIT EIGHTJAVANESE DIGIT NINEJAV" +
"ANESE PADA TIRTA TUMETESJAVANESE PADA ISEN-ISENMYANMAR LETTER SHAN GHAMY" +
"ANMAR LETTER SHAN CHAMYANMAR LETTER SHAN JHAMYANMAR LETTER SHAN NNAMYANM" +
"AR LETTER SHAN BHAMYANMAR SIGN SHAN SAWMYANMAR MODIFIER LETTER SHAN REDU" +
"PLICATIONMYANMAR LETTER TAI LAING NYAMYANMAR LETTER TAI LAING FAMYANMAR " +
"LETTER TAI LAING GAMYANMAR LETTER TAI LAING GHAMYANMAR LETTER TAI LAING " +
"JAMYANMAR LETTER TAI LAING JHAMYANMAR LETTER TAI LAING DDAMYANMAR LETTER" +
" TAI LAING DDHAMYANMAR LETTER TAI LAING NNAMYANMAR TAI LAING DIGIT ZEROM" +
"YANMAR TAI LAING DIGIT ONEMYANMAR TAI LAING DIGIT TWOMYANMAR TAI LAING D" +
"IGIT THREEMYANMAR TAI LAING DIGIT FOURMYANMAR TAI LAING DIGIT FIVEMYANMA" +
"R TAI LAING DIGIT SIXMYANMAR TAI LAING DIGIT SEVENMYANMAR TAI LAING DIGI" +
"T EIGHTMYANMAR TAI LAING DIGIT NINEMYANMAR LETTER TAI LAING LLAMYANMAR L" +
"ETTER TAI LAING DAMYANMAR LETTER TAI LAING DHAMYANMAR LETTER TAI LAING B" +
"AMYANMAR LETTER TAI LAING BHACHAM LETTER ACHAM LETTER ICHAM LETTER UCHAM" +
" LETTER ECHAM LETTER AICHAM LETTER OCHAM LETTER KACHAM LETTER KHACHAM LE" +
"TTER GACHAM LETTER GHACHAM LETTER NGUECHAM LETTER NGACHAM LETTER CHACHAM" +
" LETTER CHHACHAM LETTER JACHAM LETTER JHACHAM LETTER NHUECHAM LETTER NHA" +
"CHAM LETTER NHJACHAM LETTER TACHAM LETTER THACHAM LETTER DACHAM LETTER D" +
"HACHAM LETTER NUECHAM LETTER NACHAM LETTER DDACHAM LETTER PACHAM LETTER " +
"PPACHAM LETTER PHACHAM LETTER BACHAM LETTER BHACHAM LETTER MUECHAM LETTE" +
"R MACHAM LETTER BBACHAM LETTER YACHAM LETTER RACHAM LETTER LACHAM LETTER" +
" VACHAM LETTER SSACHAM LETTER SACHAM LETTER HACHAM VOWEL SIGN AACHAM VOW" +
"EL SIGN ICHAM VOWEL SIGN IICHAM VOWEL SIGN EICHAM VOWEL SIGN UCHAM VOWEL" +
" SIGN OECHAM VOWEL SIGN OCHAM VOWEL SIGN AICHAM VOWEL SIGN AUCHAM VOWEL " +
"SIGN UECHAM CONSONANT SIGN YACHAM CONSONANT SIGN RACHAM CONSONANT SIGN L" +
"ACHAM CONSONANT SIGN WACHAM LETTER FINAL KCHAM LETTER FINAL GCHAM LETTER" +
" FINAL NGCHAM CONSONANT SIGN FINAL NGCHAM LETTER FINAL CHCHAM LETTER FIN" +
"AL TCHAM LETTER FINAL NCHAM LETTER FINAL PCHAM LETTER FINAL YCHAM LETTER" +
" FINAL RCHAM LETTER FINAL LCHAM LETTER FINAL SSCHAM CONSONANT SIGN FINAL" +
" MCHAM CONSONANT SIGN FINAL HCHAM DIGIT ZEROCHAM DIGIT ONECHAM DIGIT TWO" +
"CHAM DIGIT THREECHAM DIGIT FOURCHAM DIGIT FIVECHAM DIGIT SIXCHAM DIGIT S" +
"EVENCHAM DIGIT EIGHTCHAM DIGIT NINECHAM PUNCTUATION SPIRALCHAM PUNCTUATI" +
"ON DANDACHAM PUNCTUATION DOUBLE DANDACHAM PUNCTUATION TRIPLE DANDAMYANMA" +
"R LETTER KHAMTI GAMYANMAR LETTER KHAMTI CAMYANMAR LETTER KHAMTI CHAMYANM" +
"AR LETTER KHAMTI JAMYANMAR LETTER KHAMTI JHAMYANMAR LETTER KHAMTI NYAMYA" +
"NMAR LETTER KHAMTI TTAMYANMAR LETTER KHAMTI TTHAMYANMAR LETTER KHAMTI DD" +
"AMYANMAR LETTER KHAMTI DDHAMYANMAR LETTER KHAMTI DHAMYANMAR LETTER KHAMT" +
"I NAMYANMAR LETTER KHAMTI SAMYANMAR LETTER KHAMTI HAMYANMAR LETTER KHAMT" +
"I HHAMYANMAR LETTER KHAMTI FAMYANMAR MODIFIER LETTER KHAMTI REDUPLICATIO" +
"NMYANMAR LETTER KHAMTI XAMYANMAR LETTER KHAMTI ZAMYANMAR LETTER KHAMTI R" +
"AMYANMAR LOGOGRAM KHAMTI OAYMYANMAR LOGOGRAM KHAMTI QNMYANMAR LOGOGRAM K" +
"HAMTI HMMYANMAR SYMBOL AITON EXCLAMATIONMYANMAR SYMBOL AITON ONEMYANMAR " +
"SYMBOL AITON TWOMYANMAR LETTER AITON RAMYANMAR SIGN PAO KAREN TONEMYANMA" +
"R SIGN TAI LAING TONE-2MYANMAR SIGN TAI LAING TONE-5MYANMAR LETTER SHWE " +
"PALAUNG CHAMYANMAR LETTER SHWE PALAUNG SHATAI VIET LETTER LOW KOTAI VIET" +
" LETTER HIGH KOTAI VIET LETTER LOW KHOTAI VIET LETTER HIGH KHOTAI VIET L" +
"ETTER LOW KHHOTAI VIET LETTER HIGH KHHOTAI VIET LETTER LOW GOTAI VIET LE") + ("" +
"TTER HIGH GOTAI VIET LETTER LOW NGOTAI VIET LETTER HIGH NGOTAI VIET LETT" +
"ER LOW COTAI VIET LETTER HIGH COTAI VIET LETTER LOW CHOTAI VIET LETTER H" +
"IGH CHOTAI VIET LETTER LOW SOTAI VIET LETTER HIGH SOTAI VIET LETTER LOW " +
"NYOTAI VIET LETTER HIGH NYOTAI VIET LETTER LOW DOTAI VIET LETTER HIGH DO" +
"TAI VIET LETTER LOW TOTAI VIET LETTER HIGH TOTAI VIET LETTER LOW THOTAI " +
"VIET LETTER HIGH THOTAI VIET LETTER LOW NOTAI VIET LETTER HIGH NOTAI VIE" +
"T LETTER LOW BOTAI VIET LETTER HIGH BOTAI VIET LETTER LOW POTAI VIET LET" +
"TER HIGH POTAI VIET LETTER LOW PHOTAI VIET LETTER HIGH PHOTAI VIET LETTE" +
"R LOW FOTAI VIET LETTER HIGH FOTAI VIET LETTER LOW MOTAI VIET LETTER HIG" +
"H MOTAI VIET LETTER LOW YOTAI VIET LETTER HIGH YOTAI VIET LETTER LOW ROT" +
"AI VIET LETTER HIGH ROTAI VIET LETTER LOW LOTAI VIET LETTER HIGH LOTAI V" +
"IET LETTER LOW VOTAI VIET LETTER HIGH VOTAI VIET LETTER LOW HOTAI VIET L" +
"ETTER HIGH HOTAI VIET LETTER LOW OTAI VIET LETTER HIGH OTAI VIET MAI KAN" +
"GTAI VIET VOWEL AATAI VIET VOWEL ITAI VIET VOWEL UETAI VIET VOWEL UTAI V" +
"IET VOWEL ETAI VIET VOWEL OTAI VIET MAI KHITTAI VIET VOWEL IATAI VIET VO" +
"WEL UEATAI VIET VOWEL UATAI VIET VOWEL AUETAI VIET VOWEL AYTAI VIET VOWE" +
"L ANTAI VIET VOWEL AMTAI VIET TONE MAI EKTAI VIET TONE MAI NUENGTAI VIET" +
" TONE MAI THOTAI VIET TONE MAI SONGTAI VIET SYMBOL KONTAI VIET SYMBOL NU" +
"ENGTAI VIET SYMBOL SAMTAI VIET SYMBOL HO HOITAI VIET SYMBOL KOI KOIMEETE" +
"I MAYEK LETTER EMEETEI MAYEK LETTER OMEETEI MAYEK LETTER CHAMEETEI MAYEK" +
" LETTER NYAMEETEI MAYEK LETTER TTAMEETEI MAYEK LETTER TTHAMEETEI MAYEK L" +
"ETTER DDAMEETEI MAYEK LETTER DDHAMEETEI MAYEK LETTER NNAMEETEI MAYEK LET" +
"TER SHAMEETEI MAYEK LETTER SSAMEETEI MAYEK VOWEL SIGN IIMEETEI MAYEK VOW" +
"EL SIGN UUMEETEI MAYEK VOWEL SIGN AAIMEETEI MAYEK VOWEL SIGN AUMEETEI MA" +
"YEK VOWEL SIGN AAUMEETEI MAYEK CHEIKHANMEETEI MAYEK AHANG KHUDAMMEETEI M" +
"AYEK ANJIMEETEI MAYEK SYLLABLE REPETITION MARKMEETEI MAYEK WORD REPETITI" +
"ON MARKMEETEI MAYEK VOWEL SIGN VISARGAMEETEI MAYEK VIRAMAETHIOPIC SYLLAB" +
"LE TTHUETHIOPIC SYLLABLE TTHIETHIOPIC SYLLABLE TTHAAETHIOPIC SYLLABLE TT" +
"HEEETHIOPIC SYLLABLE TTHEETHIOPIC SYLLABLE TTHOETHIOPIC SYLLABLE DDHUETH" +
"IOPIC SYLLABLE DDHIETHIOPIC SYLLABLE DDHAAETHIOPIC SYLLABLE DDHEEETHIOPI" +
"C SYLLABLE DDHEETHIOPIC SYLLABLE DDHOETHIOPIC SYLLABLE DZUETHIOPIC SYLLA" +
"BLE DZIETHIOPIC SYLLABLE DZAAETHIOPIC SYLLABLE DZEEETHIOPIC SYLLABLE DZE" +
"ETHIOPIC SYLLABLE DZOETHIOPIC SYLLABLE CCHHAETHIOPIC SYLLABLE CCHHUETHIO" +
"PIC SYLLABLE CCHHIETHIOPIC SYLLABLE CCHHAAETHIOPIC SYLLABLE CCHHEEETHIOP" +
"IC SYLLABLE CCHHEETHIOPIC SYLLABLE CCHHOETHIOPIC SYLLABLE BBAETHIOPIC SY" +
"LLABLE BBUETHIOPIC SYLLABLE BBIETHIOPIC SYLLABLE BBAAETHIOPIC SYLLABLE B" +
"BEEETHIOPIC SYLLABLE BBEETHIOPIC SYLLABLE BBOLATIN SMALL LETTER BARRED A" +
"LPHALATIN SMALL LETTER A REVERSED-SCHWALATIN SMALL LETTER BLACKLETTER EL" +
"ATIN SMALL LETTER BARRED ELATIN SMALL LETTER E WITH FLOURISHLATIN SMALL " +
"LETTER LENIS FLATIN SMALL LETTER SCRIPT G WITH CROSSED-TAILLATIN SMALL L" +
"ETTER L WITH INVERTED LAZY SLATIN SMALL LETTER L WITH DOUBLE MIDDLE TILD" +
"ELATIN SMALL LETTER L WITH MIDDLE RINGLATIN SMALL LETTER M WITH CROSSED-" +
"TAILLATIN SMALL LETTER N WITH CROSSED-TAILLATIN SMALL LETTER ENG WITH CR" +
"OSSED-TAILLATIN SMALL LETTER BLACKLETTER OLATIN SMALL LETTER BLACKLETTER" +
" O WITH STROKELATIN SMALL LETTER OPEN O WITH STROKELATIN SMALL LETTER IN" +
"VERTED OELATIN SMALL LETTER TURNED OE WITH STROKELATIN SMALL LETTER TURN" +
"ED OE WITH HORIZONTAL STROKELATIN SMALL LETTER TURNED O OPEN-OLATIN SMAL" +
"L LETTER TURNED O OPEN-O WITH STROKELATIN SMALL LETTER STIRRUP RLATIN LE" +
"TTER SMALL CAPITAL R WITH RIGHT LEGLATIN SMALL LETTER R WITHOUT HANDLELA" +
"TIN SMALL LETTER DOUBLE RLATIN SMALL LETTER R WITH CROSSED-TAILLATIN SMA" +
"LL LETTER DOUBLE R WITH CROSSED-TAILLATIN SMALL LETTER SCRIPT RLATIN SMA" +
"LL LETTER SCRIPT R WITH RINGLATIN SMALL LETTER BASELINE ESHLATIN SMALL L" +
"ETTER U WITH SHORT RIGHT LEGLATIN SMALL LETTER U BAR WITH SHORT RIGHT LE" +
"GLATIN SMALL LETTER UILATIN SMALL LETTER TURNED UILATIN SMALL LETTER U W" +
"ITH LEFT HOOKLATIN SMALL LETTER CHILATIN SMALL LETTER CHI WITH LOW RIGHT" +
" RINGLATIN SMALL LETTER CHI WITH LOW LEFT SERIFLATIN SMALL LETTER X WITH" +
" LOW RIGHT RINGLATIN SMALL LETTER X WITH LONG LEFT LEGLATIN SMALL LETTER" +
" X WITH LONG LEFT LEG AND LOW RIGHT RINGLATIN SMALL LETTER X WITH LONG L" +
"EFT LEG WITH SERIFLATIN SMALL LETTER Y WITH SHORT RIGHT LEGMODIFIER BREV" +
"E WITH INVERTED BREVEMODIFIER LETTER SMALL HENGMODIFIER LETTER SMALL L W" +
"ITH INVERTED LAZY SMODIFIER LETTER SMALL L WITH MIDDLE TILDEMODIFIER LET" +
"TER SMALL U WITH LEFT HOOKLATIN SMALL LETTER SAKHA YATLATIN SMALL LETTER" +
" IOTIFIED ELATIN SMALL LETTER OPEN OELATIN SMALL LETTER UOLATIN SMALL LE" +
"TTER INVERTED ALPHAGREEK LETTER SMALL CAPITAL OMEGALATIN SMALL LETTER DZ") + ("" +
" DIGRAPH WITH RETROFLEX HOOKLATIN SMALL LETTER TS DIGRAPH WITH RETROFLEX" +
" HOOKLATIN SMALL LETTER TURNED R WITH MIDDLE TILDEMODIFIER LETTER SMALL " +
"TURNED WMODIFIER LETTER LEFT TACKMODIFIER LETTER RIGHT TACKCHEROKEE SMAL" +
"L LETTER ACHEROKEE SMALL LETTER ECHEROKEE SMALL LETTER ICHEROKEE SMALL L" +
"ETTER OCHEROKEE SMALL LETTER UCHEROKEE SMALL LETTER VCHEROKEE SMALL LETT" +
"ER GACHEROKEE SMALL LETTER KACHEROKEE SMALL LETTER GECHEROKEE SMALL LETT" +
"ER GICHEROKEE SMALL LETTER GOCHEROKEE SMALL LETTER GUCHEROKEE SMALL LETT" +
"ER GVCHEROKEE SMALL LETTER HACHEROKEE SMALL LETTER HECHEROKEE SMALL LETT" +
"ER HICHEROKEE SMALL LETTER HOCHEROKEE SMALL LETTER HUCHEROKEE SMALL LETT" +
"ER HVCHEROKEE SMALL LETTER LACHEROKEE SMALL LETTER LECHEROKEE SMALL LETT" +
"ER LICHEROKEE SMALL LETTER LOCHEROKEE SMALL LETTER LUCHEROKEE SMALL LETT" +
"ER LVCHEROKEE SMALL LETTER MACHEROKEE SMALL LETTER MECHEROKEE SMALL LETT" +
"ER MICHEROKEE SMALL LETTER MOCHEROKEE SMALL LETTER MUCHEROKEE SMALL LETT" +
"ER NACHEROKEE SMALL LETTER HNACHEROKEE SMALL LETTER NAHCHEROKEE SMALL LE" +
"TTER NECHEROKEE SMALL LETTER NICHEROKEE SMALL LETTER NOCHEROKEE SMALL LE" +
"TTER NUCHEROKEE SMALL LETTER NVCHEROKEE SMALL LETTER QUACHEROKEE SMALL L" +
"ETTER QUECHEROKEE SMALL LETTER QUICHEROKEE SMALL LETTER QUOCHEROKEE SMAL" +
"L LETTER QUUCHEROKEE SMALL LETTER QUVCHEROKEE SMALL LETTER SACHEROKEE SM" +
"ALL LETTER SCHEROKEE SMALL LETTER SECHEROKEE SMALL LETTER SICHEROKEE SMA" +
"LL LETTER SOCHEROKEE SMALL LETTER SUCHEROKEE SMALL LETTER SVCHEROKEE SMA" +
"LL LETTER DACHEROKEE SMALL LETTER TACHEROKEE SMALL LETTER DECHEROKEE SMA" +
"LL LETTER TECHEROKEE SMALL LETTER DICHEROKEE SMALL LETTER TICHEROKEE SMA" +
"LL LETTER DOCHEROKEE SMALL LETTER DUCHEROKEE SMALL LETTER DVCHEROKEE SMA" +
"LL LETTER DLACHEROKEE SMALL LETTER TLACHEROKEE SMALL LETTER TLECHEROKEE " +
"SMALL LETTER TLICHEROKEE SMALL LETTER TLOCHEROKEE SMALL LETTER TLUCHEROK" +
"EE SMALL LETTER TLVCHEROKEE SMALL LETTER TSACHEROKEE SMALL LETTER TSECHE" +
"ROKEE SMALL LETTER TSICHEROKEE SMALL LETTER TSOCHEROKEE SMALL LETTER TSU" +
"CHEROKEE SMALL LETTER TSVCHEROKEE SMALL LETTER WACHEROKEE SMALL LETTER W" +
"ECHEROKEE SMALL LETTER WICHEROKEE SMALL LETTER WOCHEROKEE SMALL LETTER W" +
"UCHEROKEE SMALL LETTER WVCHEROKEE SMALL LETTER YAMEETEI MAYEK LETTER KOK" +
"MEETEI MAYEK LETTER SAMMEETEI MAYEK LETTER LAIMEETEI MAYEK LETTER MITMEE" +
"TEI MAYEK LETTER PAMEETEI MAYEK LETTER NAMEETEI MAYEK LETTER CHILMEETEI " +
"MAYEK LETTER TILMEETEI MAYEK LETTER KHOUMEETEI MAYEK LETTER NGOUMEETEI M" +
"AYEK LETTER THOUMEETEI MAYEK LETTER WAIMEETEI MAYEK LETTER YANGMEETEI MA" +
"YEK LETTER HUKMEETEI MAYEK LETTER UNMEETEI MAYEK LETTER IMEETEI MAYEK LE" +
"TTER PHAMMEETEI MAYEK LETTER ATIYAMEETEI MAYEK LETTER GOKMEETEI MAYEK LE" +
"TTER JHAMMEETEI MAYEK LETTER RAIMEETEI MAYEK LETTER BAMEETEI MAYEK LETTE" +
"R JILMEETEI MAYEK LETTER DILMEETEI MAYEK LETTER GHOUMEETEI MAYEK LETTER " +
"DHOUMEETEI MAYEK LETTER BHAMMEETEI MAYEK LETTER KOK LONSUMMEETEI MAYEK L" +
"ETTER LAI LONSUMMEETEI MAYEK LETTER MIT LONSUMMEETEI MAYEK LETTER PA LON" +
"SUMMEETEI MAYEK LETTER NA LONSUMMEETEI MAYEK LETTER TIL LONSUMMEETEI MAY" +
"EK LETTER NGOU LONSUMMEETEI MAYEK LETTER I LONSUMMEETEI MAYEK VOWEL SIGN" +
" ONAPMEETEI MAYEK VOWEL SIGN INAPMEETEI MAYEK VOWEL SIGN ANAPMEETEI MAYE" +
"K VOWEL SIGN YENAPMEETEI MAYEK VOWEL SIGN SOUNAPMEETEI MAYEK VOWEL SIGN " +
"UNAPMEETEI MAYEK VOWEL SIGN CHEINAPMEETEI MAYEK VOWEL SIGN NUNGMEETEI MA" +
"YEK CHEIKHEIMEETEI MAYEK LUM IYEKMEETEI MAYEK APUN IYEKMEETEI MAYEK DIGI" +
"T ZEROMEETEI MAYEK DIGIT ONEMEETEI MAYEK DIGIT TWOMEETEI MAYEK DIGIT THR" +
"EEMEETEI MAYEK DIGIT FOURMEETEI MAYEK DIGIT FIVEMEETEI MAYEK DIGIT SIXME" +
"ETEI MAYEK DIGIT SEVENMEETEI MAYEK DIGIT EIGHTMEETEI MAYEK DIGIT NINEHAN" +
"GUL JUNGSEONG O-YEOHANGUL JUNGSEONG O-O-IHANGUL JUNGSEONG YO-AHANGUL JUN" +
"GSEONG YO-AEHANGUL JUNGSEONG YO-EOHANGUL JUNGSEONG U-YEOHANGUL JUNGSEONG" +
" U-I-IHANGUL JUNGSEONG YU-AEHANGUL JUNGSEONG YU-OHANGUL JUNGSEONG EU-AHA" +
"NGUL JUNGSEONG EU-EOHANGUL JUNGSEONG EU-EHANGUL JUNGSEONG EU-OHANGUL JUN" +
"GSEONG I-YA-OHANGUL JUNGSEONG I-YAEHANGUL JUNGSEONG I-YEOHANGUL JUNGSEON" +
"G I-YEHANGUL JUNGSEONG I-O-IHANGUL JUNGSEONG I-YOHANGUL JUNGSEONG I-YUHA" +
"NGUL JUNGSEONG I-IHANGUL JUNGSEONG ARAEA-AHANGUL JUNGSEONG ARAEA-EHANGUL" +
" JONGSEONG NIEUN-RIEULHANGUL JONGSEONG NIEUN-CHIEUCHHANGUL JONGSEONG SSA" +
"NGTIKEUTHANGUL JONGSEONG SSANGTIKEUT-PIEUPHANGUL JONGSEONG TIKEUT-PIEUPH" +
"ANGUL JONGSEONG TIKEUT-SIOSHANGUL JONGSEONG TIKEUT-SIOS-KIYEOKHANGUL JON" +
"GSEONG TIKEUT-CIEUCHANGUL JONGSEONG TIKEUT-CHIEUCHHANGUL JONGSEONG TIKEU" +
"T-THIEUTHHANGUL JONGSEONG RIEUL-SSANGKIYEOKHANGUL JONGSEONG RIEUL-KIYEOK" +
"-HIEUHHANGUL JONGSEONG SSANGRIEUL-KHIEUKHHANGUL JONGSEONG RIEUL-MIEUM-HI" +
"EUHHANGUL JONGSEONG RIEUL-PIEUP-TIKEUTHANGUL JONGSEONG RIEUL-PIEUP-PHIEU" +
"PHHANGUL JONGSEONG RIEUL-YESIEUNGHANGUL JONGSEONG RIEUL-YEORINHIEUH-HIEU") + ("" +
"HHANGUL JONGSEONG KAPYEOUNRIEULHANGUL JONGSEONG MIEUM-NIEUNHANGUL JONGSE" +
"ONG MIEUM-SSANGNIEUNHANGUL JONGSEONG SSANGMIEUMHANGUL JONGSEONG MIEUM-PI" +
"EUP-SIOSHANGUL JONGSEONG MIEUM-CIEUCHANGUL JONGSEONG PIEUP-TIKEUTHANGUL " +
"JONGSEONG PIEUP-RIEUL-PHIEUPHHANGUL JONGSEONG PIEUP-MIEUMHANGUL JONGSEON" +
"G SSANGPIEUPHANGUL JONGSEONG PIEUP-SIOS-TIKEUTHANGUL JONGSEONG PIEUP-CIE" +
"UCHANGUL JONGSEONG PIEUP-CHIEUCHHANGUL JONGSEONG SIOS-MIEUMHANGUL JONGSE" +
"ONG SIOS-KAPYEOUNPIEUPHANGUL JONGSEONG SSANGSIOS-KIYEOKHANGUL JONGSEONG " +
"SSANGSIOS-TIKEUTHANGUL JONGSEONG SIOS-PANSIOSHANGUL JONGSEONG SIOS-CIEUC" +
"HANGUL JONGSEONG SIOS-CHIEUCHHANGUL JONGSEONG SIOS-THIEUTHHANGUL JONGSEO" +
"NG SIOS-HIEUHHANGUL JONGSEONG PANSIOS-PIEUPHANGUL JONGSEONG PANSIOS-KAPY" +
"EOUNPIEUPHANGUL JONGSEONG YESIEUNG-MIEUMHANGUL JONGSEONG YESIEUNG-HIEUHH" +
"ANGUL JONGSEONG CIEUC-PIEUPHANGUL JONGSEONG CIEUC-SSANGPIEUPHANGUL JONGS" +
"EONG SSANGCIEUCHANGUL JONGSEONG PHIEUPH-SIOSHANGUL JONGSEONG PHIEUPH-THI" +
"EUTHCJK COMPATIBILITY IDEOGRAPH-F900CJK COMPATIBILITY IDEOGRAPH-F901CJK " +
"COMPATIBILITY IDEOGRAPH-F902CJK COMPATIBILITY IDEOGRAPH-F903CJK COMPATIB" +
"ILITY IDEOGRAPH-F904CJK COMPATIBILITY IDEOGRAPH-F905CJK COMPATIBILITY ID" +
"EOGRAPH-F906CJK COMPATIBILITY IDEOGRAPH-F907CJK COMPATIBILITY IDEOGRAPH-" +
"F908CJK COMPATIBILITY IDEOGRAPH-F909CJK COMPATIBILITY IDEOGRAPH-F90ACJK " +
"COMPATIBILITY IDEOGRAPH-F90BCJK COMPATIBILITY IDEOGRAPH-F90CCJK COMPATIB" +
"ILITY IDEOGRAPH-F90DCJK COMPATIBILITY IDEOGRAPH-F90ECJK COMPATIBILITY ID" +
"EOGRAPH-F90FCJK COMPATIBILITY IDEOGRAPH-F910CJK COMPATIBILITY IDEOGRAPH-" +
"F911CJK COMPATIBILITY IDEOGRAPH-F912CJK COMPATIBILITY IDEOGRAPH-F913CJK " +
"COMPATIBILITY IDEOGRAPH-F914CJK COMPATIBILITY IDEOGRAPH-F915CJK COMPATIB" +
"ILITY IDEOGRAPH-F916CJK COMPATIBILITY IDEOGRAPH-F917CJK COMPATIBILITY ID" +
"EOGRAPH-F918CJK COMPATIBILITY IDEOGRAPH-F919CJK COMPATIBILITY IDEOGRAPH-" +
"F91ACJK COMPATIBILITY IDEOGRAPH-F91BCJK COMPATIBILITY IDEOGRAPH-F91CCJK " +
"COMPATIBILITY IDEOGRAPH-F91DCJK COMPATIBILITY IDEOGRAPH-F91ECJK COMPATIB" +
"ILITY IDEOGRAPH-F91FCJK COMPATIBILITY IDEOGRAPH-F920CJK COMPATIBILITY ID" +
"EOGRAPH-F921CJK COMPATIBILITY IDEOGRAPH-F922CJK COMPATIBILITY IDEOGRAPH-" +
"F923CJK COMPATIBILITY IDEOGRAPH-F924CJK COMPATIBILITY IDEOGRAPH-F925CJK " +
"COMPATIBILITY IDEOGRAPH-F926CJK COMPATIBILITY IDEOGRAPH-F927CJK COMPATIB" +
"ILITY IDEOGRAPH-F928CJK COMPATIBILITY IDEOGRAPH-F929CJK COMPATIBILITY ID" +
"EOGRAPH-F92ACJK COMPATIBILITY IDEOGRAPH-F92BCJK COMPATIBILITY IDEOGRAPH-" +
"F92CCJK COMPATIBILITY IDEOGRAPH-F92DCJK COMPATIBILITY IDEOGRAPH-F92ECJK " +
"COMPATIBILITY IDEOGRAPH-F92FCJK COMPATIBILITY IDEOGRAPH-F930CJK COMPATIB" +
"ILITY IDEOGRAPH-F931CJK COMPATIBILITY IDEOGRAPH-F932CJK COMPATIBILITY ID" +
"EOGRAPH-F933CJK COMPATIBILITY IDEOGRAPH-F934CJK COMPATIBILITY IDEOGRAPH-" +
"F935CJK COMPATIBILITY IDEOGRAPH-F936CJK COMPATIBILITY IDEOGRAPH-F937CJK " +
"COMPATIBILITY IDEOGRAPH-F938CJK COMPATIBILITY IDEOGRAPH-F939CJK COMPATIB" +
"ILITY IDEOGRAPH-F93ACJK COMPATIBILITY IDEOGRAPH-F93BCJK COMPATIBILITY ID" +
"EOGRAPH-F93CCJK COMPATIBILITY IDEOGRAPH-F93DCJK COMPATIBILITY IDEOGRAPH-" +
"F93ECJK COMPATIBILITY IDEOGRAPH-F93FCJK COMPATIBILITY IDEOGRAPH-F940CJK " +
"COMPATIBILITY IDEOGRAPH-F941CJK COMPATIBILITY IDEOGRAPH-F942CJK COMPATIB" +
"ILITY IDEOGRAPH-F943CJK COMPATIBILITY IDEOGRAPH-F944CJK COMPATIBILITY ID" +
"EOGRAPH-F945CJK COMPATIBILITY IDEOGRAPH-F946CJK COMPATIBILITY IDEOGRAPH-" +
"F947CJK COMPATIBILITY IDEOGRAPH-F948CJK COMPATIBILITY IDEOGRAPH-F949CJK " +
"COMPATIBILITY IDEOGRAPH-F94ACJK COMPATIBILITY IDEOGRAPH-F94BCJK COMPATIB" +
"ILITY IDEOGRAPH-F94CCJK COMPATIBILITY IDEOGRAPH-F94DCJK COMPATIBILITY ID" +
"EOGRAPH-F94ECJK COMPATIBILITY IDEOGRAPH-F94FCJK COMPATIBILITY IDEOGRAPH-" +
"F950CJK COMPATIBILITY IDEOGRAPH-F951CJK COMPATIBILITY IDEOGRAPH-F952CJK " +
"COMPATIBILITY IDEOGRAPH-F953CJK COMPATIBILITY IDEOGRAPH-F954CJK COMPATIB" +
"ILITY IDEOGRAPH-F955CJK COMPATIBILITY IDEOGRAPH-F956CJK COMPATIBILITY ID" +
"EOGRAPH-F957CJK COMPATIBILITY IDEOGRAPH-F958CJK COMPATIBILITY IDEOGRAPH-" +
"F959CJK COMPATIBILITY IDEOGRAPH-F95ACJK COMPATIBILITY IDEOGRAPH-F95BCJK " +
"COMPATIBILITY IDEOGRAPH-F95CCJK COMPATIBILITY IDEOGRAPH-F95DCJK COMPATIB" +
"ILITY IDEOGRAPH-F95ECJK COMPATIBILITY IDEOGRAPH-F95FCJK COMPATIBILITY ID" +
"EOGRAPH-F960CJK COMPATIBILITY IDEOGRAPH-F961CJK COMPATIBILITY IDEOGRAPH-" +
"F962CJK COMPATIBILITY IDEOGRAPH-F963CJK COMPATIBILITY IDEOGRAPH-F964CJK " +
"COMPATIBILITY IDEOGRAPH-F965CJK COMPATIBILITY IDEOGRAPH-F966CJK COMPATIB" +
"ILITY IDEOGRAPH-F967CJK COMPATIBILITY IDEOGRAPH-F968CJK COMPATIBILITY ID" +
"EOGRAPH-F969CJK COMPATIBILITY IDEOGRAPH-F96ACJK COMPATIBILITY IDEOGRAPH-" +
"F96BCJK COMPATIBILITY IDEOGRAPH-F96CCJK COMPATIBILITY IDEOGRAPH-F96DCJK " +
"COMPATIBILITY IDEOGRAPH-F96ECJK COMPATIBILITY IDEOGRAPH-F96FCJK COMPATIB" +
"ILITY IDEOGRAPH-F970CJK COMPATIBILITY IDEOGRAPH-F971CJK COMPATIBILITY ID") + ("" +
"EOGRAPH-F972CJK COMPATIBILITY IDEOGRAPH-F973CJK COMPATIBILITY IDEOGRAPH-" +
"F974CJK COMPATIBILITY IDEOGRAPH-F975CJK COMPATIBILITY IDEOGRAPH-F976CJK " +
"COMPATIBILITY IDEOGRAPH-F977CJK COMPATIBILITY IDEOGRAPH-F978CJK COMPATIB" +
"ILITY IDEOGRAPH-F979CJK COMPATIBILITY IDEOGRAPH-F97ACJK COMPATIBILITY ID" +
"EOGRAPH-F97BCJK COMPATIBILITY IDEOGRAPH-F97CCJK COMPATIBILITY IDEOGRAPH-" +
"F97DCJK COMPATIBILITY IDEOGRAPH-F97ECJK COMPATIBILITY IDEOGRAPH-F97FCJK " +
"COMPATIBILITY IDEOGRAPH-F980CJK COMPATIBILITY IDEOGRAPH-F981CJK COMPATIB" +
"ILITY IDEOGRAPH-F982CJK COMPATIBILITY IDEOGRAPH-F983CJK COMPATIBILITY ID" +
"EOGRAPH-F984CJK COMPATIBILITY IDEOGRAPH-F985CJK COMPATIBILITY IDEOGRAPH-" +
"F986CJK COMPATIBILITY IDEOGRAPH-F987CJK COMPATIBILITY IDEOGRAPH-F988CJK " +
"COMPATIBILITY IDEOGRAPH-F989CJK COMPATIBILITY IDEOGRAPH-F98ACJK COMPATIB" +
"ILITY IDEOGRAPH-F98BCJK COMPATIBILITY IDEOGRAPH-F98CCJK COMPATIBILITY ID" +
"EOGRAPH-F98DCJK COMPATIBILITY IDEOGRAPH-F98ECJK COMPATIBILITY IDEOGRAPH-" +
"F98FCJK COMPATIBILITY IDEOGRAPH-F990CJK COMPATIBILITY IDEOGRAPH-F991CJK " +
"COMPATIBILITY IDEOGRAPH-F992CJK COMPATIBILITY IDEOGRAPH-F993CJK COMPATIB" +
"ILITY IDEOGRAPH-F994CJK COMPATIBILITY IDEOGRAPH-F995CJK COMPATIBILITY ID" +
"EOGRAPH-F996CJK COMPATIBILITY IDEOGRAPH-F997CJK COMPATIBILITY IDEOGRAPH-" +
"F998CJK COMPATIBILITY IDEOGRAPH-F999CJK COMPATIBILITY IDEOGRAPH-F99ACJK " +
"COMPATIBILITY IDEOGRAPH-F99BCJK COMPATIBILITY IDEOGRAPH-F99CCJK COMPATIB" +
"ILITY IDEOGRAPH-F99DCJK COMPATIBILITY IDEOGRAPH-F99ECJK COMPATIBILITY ID" +
"EOGRAPH-F99FCJK COMPATIBILITY IDEOGRAPH-F9A0CJK COMPATIBILITY IDEOGRAPH-" +
"F9A1CJK COMPATIBILITY IDEOGRAPH-F9A2CJK COMPATIBILITY IDEOGRAPH-F9A3CJK " +
"COMPATIBILITY IDEOGRAPH-F9A4CJK COMPATIBILITY IDEOGRAPH-F9A5CJK COMPATIB" +
"ILITY IDEOGRAPH-F9A6CJK COMPATIBILITY IDEOGRAPH-F9A7CJK COMPATIBILITY ID" +
"EOGRAPH-F9A8CJK COMPATIBILITY IDEOGRAPH-F9A9CJK COMPATIBILITY IDEOGRAPH-" +
"F9AACJK COMPATIBILITY IDEOGRAPH-F9ABCJK COMPATIBILITY IDEOGRAPH-F9ACCJK " +
"COMPATIBILITY IDEOGRAPH-F9ADCJK COMPATIBILITY IDEOGRAPH-F9AECJK COMPATIB" +
"ILITY IDEOGRAPH-F9AFCJK COMPATIBILITY IDEOGRAPH-F9B0CJK COMPATIBILITY ID" +
"EOGRAPH-F9B1CJK COMPATIBILITY IDEOGRAPH-F9B2CJK COMPATIBILITY IDEOGRAPH-" +
"F9B3CJK COMPATIBILITY IDEOGRAPH-F9B4CJK COMPATIBILITY IDEOGRAPH-F9B5CJK " +
"COMPATIBILITY IDEOGRAPH-F9B6CJK COMPATIBILITY IDEOGRAPH-F9B7CJK COMPATIB" +
"ILITY IDEOGRAPH-F9B8CJK COMPATIBILITY IDEOGRAPH-F9B9CJK COMPATIBILITY ID" +
"EOGRAPH-F9BACJK COMPATIBILITY IDEOGRAPH-F9BBCJK COMPATIBILITY IDEOGRAPH-" +
"F9BCCJK COMPATIBILITY IDEOGRAPH-F9BDCJK COMPATIBILITY IDEOGRAPH-F9BECJK " +
"COMPATIBILITY IDEOGRAPH-F9BFCJK COMPATIBILITY IDEOGRAPH-F9C0CJK COMPATIB" +
"ILITY IDEOGRAPH-F9C1CJK COMPATIBILITY IDEOGRAPH-F9C2CJK COMPATIBILITY ID" +
"EOGRAPH-F9C3CJK COMPATIBILITY IDEOGRAPH-F9C4CJK COMPATIBILITY IDEOGRAPH-" +
"F9C5CJK COMPATIBILITY IDEOGRAPH-F9C6CJK COMPATIBILITY IDEOGRAPH-F9C7CJK " +
"COMPATIBILITY IDEOGRAPH-F9C8CJK COMPATIBILITY IDEOGRAPH-F9C9CJK COMPATIB" +
"ILITY IDEOGRAPH-F9CACJK COMPATIBILITY IDEOGRAPH-F9CBCJK COMPATIBILITY ID" +
"EOGRAPH-F9CCCJK COMPATIBILITY IDEOGRAPH-F9CDCJK COMPATIBILITY IDEOGRAPH-" +
"F9CECJK COMPATIBILITY IDEOGRAPH-F9CFCJK COMPATIBILITY IDEOGRAPH-F9D0CJK " +
"COMPATIBILITY IDEOGRAPH-F9D1CJK COMPATIBILITY IDEOGRAPH-F9D2CJK COMPATIB" +
"ILITY IDEOGRAPH-F9D3CJK COMPATIBILITY IDEOGRAPH-F9D4CJK COMPATIBILITY ID" +
"EOGRAPH-F9D5CJK COMPATIBILITY IDEOGRAPH-F9D6CJK COMPATIBILITY IDEOGRAPH-" +
"F9D7CJK COMPATIBILITY IDEOGRAPH-F9D8CJK COMPATIBILITY IDEOGRAPH-F9D9CJK " +
"COMPATIBILITY IDEOGRAPH-F9DACJK COMPATIBILITY IDEOGRAPH-F9DBCJK COMPATIB" +
"ILITY IDEOGRAPH-F9DCCJK COMPATIBILITY IDEOGRAPH-F9DDCJK COMPATIBILITY ID" +
"EOGRAPH-F9DECJK COMPATIBILITY IDEOGRAPH-F9DFCJK COMPATIBILITY IDEOGRAPH-" +
"F9E0CJK COMPATIBILITY IDEOGRAPH-F9E1CJK COMPATIBILITY IDEOGRAPH-F9E2CJK " +
"COMPATIBILITY IDEOGRAPH-F9E3CJK COMPATIBILITY IDEOGRAPH-F9E4CJK COMPATIB" +
"ILITY IDEOGRAPH-F9E5CJK COMPATIBILITY IDEOGRAPH-F9E6CJK COMPATIBILITY ID" +
"EOGRAPH-F9E7CJK COMPATIBILITY IDEOGRAPH-F9E8CJK COMPATIBILITY IDEOGRAPH-" +
"F9E9CJK COMPATIBILITY IDEOGRAPH-F9EACJK COMPATIBILITY IDEOGRAPH-F9EBCJK " +
"COMPATIBILITY IDEOGRAPH-F9ECCJK COMPATIBILITY IDEOGRAPH-F9EDCJK COMPATIB" +
"ILITY IDEOGRAPH-F9EECJK COMPATIBILITY IDEOGRAPH-F9EFCJK COMPATIBILITY ID" +
"EOGRAPH-F9F0CJK COMPATIBILITY IDEOGRAPH-F9F1CJK COMPATIBILITY IDEOGRAPH-" +
"F9F2CJK COMPATIBILITY IDEOGRAPH-F9F3CJK COMPATIBILITY IDEOGRAPH-F9F4CJK " +
"COMPATIBILITY IDEOGRAPH-F9F5CJK COMPATIBILITY IDEOGRAPH-F9F6CJK COMPATIB" +
"ILITY IDEOGRAPH-F9F7CJK COMPATIBILITY IDEOGRAPH-F9F8CJK COMPATIBILITY ID" +
"EOGRAPH-F9F9CJK COMPATIBILITY IDEOGRAPH-F9FACJK COMPATIBILITY IDEOGRAPH-" +
"F9FBCJK COMPATIBILITY IDEOGRAPH-F9FCCJK COMPATIBILITY IDEOGRAPH-F9FDCJK " +
"COMPATIBILITY IDEOGRAPH-F9FECJK COMPATIBILITY IDEOGRAPH-F9FFCJK COMPATIB" +
"ILITY IDEOGRAPH-FA00CJK COMPATIBILITY IDEOGRAPH-FA01CJK COMPATIBILITY ID") + ("" +
"EOGRAPH-FA02CJK COMPATIBILITY IDEOGRAPH-FA03CJK COMPATIBILITY IDEOGRAPH-" +
"FA04CJK COMPATIBILITY IDEOGRAPH-FA05CJK COMPATIBILITY IDEOGRAPH-FA06CJK " +
"COMPATIBILITY IDEOGRAPH-FA07CJK COMPATIBILITY IDEOGRAPH-FA08CJK COMPATIB" +
"ILITY IDEOGRAPH-FA09CJK COMPATIBILITY IDEOGRAPH-FA0ACJK COMPATIBILITY ID" +
"EOGRAPH-FA0BCJK COMPATIBILITY IDEOGRAPH-FA0CCJK COMPATIBILITY IDEOGRAPH-" +
"FA0DCJK COMPATIBILITY IDEOGRAPH-FA0ECJK COMPATIBILITY IDEOGRAPH-FA0FCJK " +
"COMPATIBILITY IDEOGRAPH-FA10CJK COMPATIBILITY IDEOGRAPH-FA11CJK COMPATIB" +
"ILITY IDEOGRAPH-FA12CJK COMPATIBILITY IDEOGRAPH-FA13CJK COMPATIBILITY ID" +
"EOGRAPH-FA14CJK COMPATIBILITY IDEOGRAPH-FA15CJK COMPATIBILITY IDEOGRAPH-" +
"FA16CJK COMPATIBILITY IDEOGRAPH-FA17CJK COMPATIBILITY IDEOGRAPH-FA18CJK " +
"COMPATIBILITY IDEOGRAPH-FA19CJK COMPATIBILITY IDEOGRAPH-FA1ACJK COMPATIB" +
"ILITY IDEOGRAPH-FA1BCJK COMPATIBILITY IDEOGRAPH-FA1CCJK COMPATIBILITY ID" +
"EOGRAPH-FA1DCJK COMPATIBILITY IDEOGRAPH-FA1ECJK COMPATIBILITY IDEOGRAPH-" +
"FA1FCJK COMPATIBILITY IDEOGRAPH-FA20CJK COMPATIBILITY IDEOGRAPH-FA21CJK " +
"COMPATIBILITY IDEOGRAPH-FA22CJK COMPATIBILITY IDEOGRAPH-FA23CJK COMPATIB" +
"ILITY IDEOGRAPH-FA24CJK COMPATIBILITY IDEOGRAPH-FA25CJK COMPATIBILITY ID" +
"EOGRAPH-FA26CJK COMPATIBILITY IDEOGRAPH-FA27CJK COMPATIBILITY IDEOGRAPH-" +
"FA28CJK COMPATIBILITY IDEOGRAPH-FA29CJK COMPATIBILITY IDEOGRAPH-FA2ACJK " +
"COMPATIBILITY IDEOGRAPH-FA2BCJK COMPATIBILITY IDEOGRAPH-FA2CCJK COMPATIB" +
"ILITY IDEOGRAPH-FA2DCJK COMPATIBILITY IDEOGRAPH-FA2ECJK COMPATIBILITY ID" +
"EOGRAPH-FA2FCJK COMPATIBILITY IDEOGRAPH-FA30CJK COMPATIBILITY IDEOGRAPH-" +
"FA31CJK COMPATIBILITY IDEOGRAPH-FA32CJK COMPATIBILITY IDEOGRAPH-FA33CJK " +
"COMPATIBILITY IDEOGRAPH-FA34CJK COMPATIBILITY IDEOGRAPH-FA35CJK COMPATIB" +
"ILITY IDEOGRAPH-FA36CJK COMPATIBILITY IDEOGRAPH-FA37CJK COMPATIBILITY ID" +
"EOGRAPH-FA38CJK COMPATIBILITY IDEOGRAPH-FA39CJK COMPATIBILITY IDEOGRAPH-" +
"FA3ACJK COMPATIBILITY IDEOGRAPH-FA3BCJK COMPATIBILITY IDEOGRAPH-FA3CCJK " +
"COMPATIBILITY IDEOGRAPH-FA3DCJK COMPATIBILITY IDEOGRAPH-FA3ECJK COMPATIB" +
"ILITY IDEOGRAPH-FA3FCJK COMPATIBILITY IDEOGRAPH-FA40CJK COMPATIBILITY ID" +
"EOGRAPH-FA41CJK COMPATIBILITY IDEOGRAPH-FA42CJK COMPATIBILITY IDEOGRAPH-" +
"FA43CJK COMPATIBILITY IDEOGRAPH-FA44CJK COMPATIBILITY IDEOGRAPH-FA45CJK " +
"COMPATIBILITY IDEOGRAPH-FA46CJK COMPATIBILITY IDEOGRAPH-FA47CJK COMPATIB" +
"ILITY IDEOGRAPH-FA48CJK COMPATIBILITY IDEOGRAPH-FA49CJK COMPATIBILITY ID" +
"EOGRAPH-FA4ACJK COMPATIBILITY IDEOGRAPH-FA4BCJK COMPATIBILITY IDEOGRAPH-" +
"FA4CCJK COMPATIBILITY IDEOGRAPH-FA4DCJK COMPATIBILITY IDEOGRAPH-FA4ECJK " +
"COMPATIBILITY IDEOGRAPH-FA4FCJK COMPATIBILITY IDEOGRAPH-FA50CJK COMPATIB" +
"ILITY IDEOGRAPH-FA51CJK COMPATIBILITY IDEOGRAPH-FA52CJK COMPATIBILITY ID" +
"EOGRAPH-FA53CJK COMPATIBILITY IDEOGRAPH-FA54CJK COMPATIBILITY IDEOGRAPH-" +
"FA55CJK COMPATIBILITY IDEOGRAPH-FA56CJK COMPATIBILITY IDEOGRAPH-FA57CJK " +
"COMPATIBILITY IDEOGRAPH-FA58CJK COMPATIBILITY IDEOGRAPH-FA59CJK COMPATIB" +
"ILITY IDEOGRAPH-FA5ACJK COMPATIBILITY IDEOGRAPH-FA5BCJK COMPATIBILITY ID" +
"EOGRAPH-FA5CCJK COMPATIBILITY IDEOGRAPH-FA5DCJK COMPATIBILITY IDEOGRAPH-" +
"FA5ECJK COMPATIBILITY IDEOGRAPH-FA5FCJK COMPATIBILITY IDEOGRAPH-FA60CJK " +
"COMPATIBILITY IDEOGRAPH-FA61CJK COMPATIBILITY IDEOGRAPH-FA62CJK COMPATIB" +
"ILITY IDEOGRAPH-FA63CJK COMPATIBILITY IDEOGRAPH-FA64CJK COMPATIBILITY ID" +
"EOGRAPH-FA65CJK COMPATIBILITY IDEOGRAPH-FA66CJK COMPATIBILITY IDEOGRAPH-" +
"FA67CJK COMPATIBILITY IDEOGRAPH-FA68CJK COMPATIBILITY IDEOGRAPH-FA69CJK " +
"COMPATIBILITY IDEOGRAPH-FA6ACJK COMPATIBILITY IDEOGRAPH-FA6BCJK COMPATIB" +
"ILITY IDEOGRAPH-FA6CCJK COMPATIBILITY IDEOGRAPH-FA6DCJK COMPATIBILITY ID" +
"EOGRAPH-FA70CJK COMPATIBILITY IDEOGRAPH-FA71CJK COMPATIBILITY IDEOGRAPH-" +
"FA72CJK COMPATIBILITY IDEOGRAPH-FA73CJK COMPATIBILITY IDEOGRAPH-FA74CJK " +
"COMPATIBILITY IDEOGRAPH-FA75CJK COMPATIBILITY IDEOGRAPH-FA76CJK COMPATIB" +
"ILITY IDEOGRAPH-FA77CJK COMPATIBILITY IDEOGRAPH-FA78CJK COMPATIBILITY ID" +
"EOGRAPH-FA79CJK COMPATIBILITY IDEOGRAPH-FA7ACJK COMPATIBILITY IDEOGRAPH-" +
"FA7BCJK COMPATIBILITY IDEOGRAPH-FA7CCJK COMPATIBILITY IDEOGRAPH-FA7DCJK " +
"COMPATIBILITY IDEOGRAPH-FA7ECJK COMPATIBILITY IDEOGRAPH-FA7FCJK COMPATIB" +
"ILITY IDEOGRAPH-FA80CJK COMPATIBILITY IDEOGRAPH-FA81CJK COMPATIBILITY ID" +
"EOGRAPH-FA82CJK COMPATIBILITY IDEOGRAPH-FA83CJK COMPATIBILITY IDEOGRAPH-" +
"FA84CJK COMPATIBILITY IDEOGRAPH-FA85CJK COMPATIBILITY IDEOGRAPH-FA86CJK " +
"COMPATIBILITY IDEOGRAPH-FA87CJK COMPATIBILITY IDEOGRAPH-FA88CJK COMPATIB" +
"ILITY IDEOGRAPH-FA89CJK COMPATIBILITY IDEOGRAPH-FA8ACJK COMPATIBILITY ID" +
"EOGRAPH-FA8BCJK COMPATIBILITY IDEOGRAPH-FA8CCJK COMPATIBILITY IDEOGRAPH-" +
"FA8DCJK COMPATIBILITY IDEOGRAPH-FA8ECJK COMPATIBILITY IDEOGRAPH-FA8FCJK " +
"COMPATIBILITY IDEOGRAPH-FA90CJK COMPATIBILITY IDEOGRAPH-FA91CJK COMPATIB" +
"ILITY IDEOGRAPH-FA92CJK COMPATIBILITY IDEOGRAPH-FA93CJK COMPATIBILITY ID") + ("" +
"EOGRAPH-FA94CJK COMPATIBILITY IDEOGRAPH-FA95CJK COMPATIBILITY IDEOGRAPH-" +
"FA96CJK COMPATIBILITY IDEOGRAPH-FA97CJK COMPATIBILITY IDEOGRAPH-FA98CJK " +
"COMPATIBILITY IDEOGRAPH-FA99CJK COMPATIBILITY IDEOGRAPH-FA9ACJK COMPATIB" +
"ILITY IDEOGRAPH-FA9BCJK COMPATIBILITY IDEOGRAPH-FA9CCJK COMPATIBILITY ID" +
"EOGRAPH-FA9DCJK COMPATIBILITY IDEOGRAPH-FA9ECJK COMPATIBILITY IDEOGRAPH-" +
"FA9FCJK COMPATIBILITY IDEOGRAPH-FAA0CJK COMPATIBILITY IDEOGRAPH-FAA1CJK " +
"COMPATIBILITY IDEOGRAPH-FAA2CJK COMPATIBILITY IDEOGRAPH-FAA3CJK COMPATIB" +
"ILITY IDEOGRAPH-FAA4CJK COMPATIBILITY IDEOGRAPH-FAA5CJK COMPATIBILITY ID" +
"EOGRAPH-FAA6CJK COMPATIBILITY IDEOGRAPH-FAA7CJK COMPATIBILITY IDEOGRAPH-" +
"FAA8CJK COMPATIBILITY IDEOGRAPH-FAA9CJK COMPATIBILITY IDEOGRAPH-FAAACJK " +
"COMPATIBILITY IDEOGRAPH-FAABCJK COMPATIBILITY IDEOGRAPH-FAACCJK COMPATIB" +
"ILITY IDEOGRAPH-FAADCJK COMPATIBILITY IDEOGRAPH-FAAECJK COMPATIBILITY ID" +
"EOGRAPH-FAAFCJK COMPATIBILITY IDEOGRAPH-FAB0CJK COMPATIBILITY IDEOGRAPH-" +
"FAB1CJK COMPATIBILITY IDEOGRAPH-FAB2CJK COMPATIBILITY IDEOGRAPH-FAB3CJK " +
"COMPATIBILITY IDEOGRAPH-FAB4CJK COMPATIBILITY IDEOGRAPH-FAB5CJK COMPATIB" +
"ILITY IDEOGRAPH-FAB6CJK COMPATIBILITY IDEOGRAPH-FAB7CJK COMPATIBILITY ID" +
"EOGRAPH-FAB8CJK COMPATIBILITY IDEOGRAPH-FAB9CJK COMPATIBILITY IDEOGRAPH-" +
"FABACJK COMPATIBILITY IDEOGRAPH-FABBCJK COMPATIBILITY IDEOGRAPH-FABCCJK " +
"COMPATIBILITY IDEOGRAPH-FABDCJK COMPATIBILITY IDEOGRAPH-FABECJK COMPATIB" +
"ILITY IDEOGRAPH-FABFCJK COMPATIBILITY IDEOGRAPH-FAC0CJK COMPATIBILITY ID" +
"EOGRAPH-FAC1CJK COMPATIBILITY IDEOGRAPH-FAC2CJK COMPATIBILITY IDEOGRAPH-" +
"FAC3CJK COMPATIBILITY IDEOGRAPH-FAC4CJK COMPATIBILITY IDEOGRAPH-FAC5CJK " +
"COMPATIBILITY IDEOGRAPH-FAC6CJK COMPATIBILITY IDEOGRAPH-FAC7CJK COMPATIB" +
"ILITY IDEOGRAPH-FAC8CJK COMPATIBILITY IDEOGRAPH-FAC9CJK COMPATIBILITY ID" +
"EOGRAPH-FACACJK COMPATIBILITY IDEOGRAPH-FACBCJK COMPATIBILITY IDEOGRAPH-" +
"FACCCJK COMPATIBILITY IDEOGRAPH-FACDCJK COMPATIBILITY IDEOGRAPH-FACECJK " +
"COMPATIBILITY IDEOGRAPH-FACFCJK COMPATIBILITY IDEOGRAPH-FAD0CJK COMPATIB" +
"ILITY IDEOGRAPH-FAD1CJK COMPATIBILITY IDEOGRAPH-FAD2CJK COMPATIBILITY ID" +
"EOGRAPH-FAD3CJK COMPATIBILITY IDEOGRAPH-FAD4CJK COMPATIBILITY IDEOGRAPH-" +
"FAD5CJK COMPATIBILITY IDEOGRAPH-FAD6CJK COMPATIBILITY IDEOGRAPH-FAD7CJK " +
"COMPATIBILITY IDEOGRAPH-FAD8CJK COMPATIBILITY IDEOGRAPH-FAD9LATIN SMALL " +
"LIGATURE FFLATIN SMALL LIGATURE FILATIN SMALL LIGATURE FLLATIN SMALL LIG" +
"ATURE FFILATIN SMALL LIGATURE FFLLATIN SMALL LIGATURE LONG S TLATIN SMAL" +
"L LIGATURE STARMENIAN SMALL LIGATURE MEN NOWARMENIAN SMALL LIGATURE MEN " +
"ECHARMENIAN SMALL LIGATURE MEN INIARMENIAN SMALL LIGATURE VEW NOWARMENIA" +
"N SMALL LIGATURE MEN XEHHEBREW LETTER YOD WITH HIRIQHEBREW POINT JUDEO-S" +
"PANISH VARIKAHEBREW LIGATURE YIDDISH YOD YOD PATAHHEBREW LETTER ALTERNAT" +
"IVE AYINHEBREW LETTER WIDE ALEFHEBREW LETTER WIDE DALETHEBREW LETTER WID" +
"E HEHEBREW LETTER WIDE KAFHEBREW LETTER WIDE LAMEDHEBREW LETTER WIDE FIN" +
"AL MEMHEBREW LETTER WIDE RESHHEBREW LETTER WIDE TAVHEBREW LETTER ALTERNA" +
"TIVE PLUS SIGNHEBREW LETTER SHIN WITH SHIN DOTHEBREW LETTER SHIN WITH SI" +
"N DOTHEBREW LETTER SHIN WITH DAGESH AND SHIN DOTHEBREW LETTER SHIN WITH " +
"DAGESH AND SIN DOTHEBREW LETTER ALEF WITH PATAHHEBREW LETTER ALEF WITH Q" +
"AMATSHEBREW LETTER ALEF WITH MAPIQHEBREW LETTER BET WITH DAGESHHEBREW LE" +
"TTER GIMEL WITH DAGESHHEBREW LETTER DALET WITH DAGESHHEBREW LETTER HE WI" +
"TH MAPIQHEBREW LETTER VAV WITH DAGESHHEBREW LETTER ZAYIN WITH DAGESHHEBR" +
"EW LETTER TET WITH DAGESHHEBREW LETTER YOD WITH DAGESHHEBREW LETTER FINA" +
"L KAF WITH DAGESHHEBREW LETTER KAF WITH DAGESHHEBREW LETTER LAMED WITH D" +
"AGESHHEBREW LETTER MEM WITH DAGESHHEBREW LETTER NUN WITH DAGESHHEBREW LE" +
"TTER SAMEKH WITH DAGESHHEBREW LETTER FINAL PE WITH DAGESHHEBREW LETTER P" +
"E WITH DAGESHHEBREW LETTER TSADI WITH DAGESHHEBREW LETTER QOF WITH DAGES" +
"HHEBREW LETTER RESH WITH DAGESHHEBREW LETTER SHIN WITH DAGESHHEBREW LETT" +
"ER TAV WITH DAGESHHEBREW LETTER VAV WITH HOLAMHEBREW LETTER BET WITH RAF" +
"EHEBREW LETTER KAF WITH RAFEHEBREW LETTER PE WITH RAFEHEBREW LIGATURE AL" +
"EF LAMEDARABIC LETTER ALEF WASLA ISOLATED FORMARABIC LETTER ALEF WASLA F" +
"INAL FORMARABIC LETTER BEEH ISOLATED FORMARABIC LETTER BEEH FINAL FORMAR" +
"ABIC LETTER BEEH INITIAL FORMARABIC LETTER BEEH MEDIAL FORMARABIC LETTER" +
" PEH ISOLATED FORMARABIC LETTER PEH FINAL FORMARABIC LETTER PEH INITIAL " +
"FORMARABIC LETTER PEH MEDIAL FORMARABIC LETTER BEHEH ISOLATED FORMARABIC" +
" LETTER BEHEH FINAL FORMARABIC LETTER BEHEH INITIAL FORMARABIC LETTER BE" +
"HEH MEDIAL FORMARABIC LETTER TTEHEH ISOLATED FORMARABIC LETTER TTEHEH FI" +
"NAL FORMARABIC LETTER TTEHEH INITIAL FORMARABIC LETTER TTEHEH MEDIAL FOR" +
"MARABIC LETTER TEHEH ISOLATED FORMARABIC LETTER TEHEH FINAL FORMARABIC L" +
"ETTER TEHEH INITIAL FORMARABIC LETTER TEHEH MEDIAL FORMARABIC LETTER TTE") + ("" +
"H ISOLATED FORMARABIC LETTER TTEH FINAL FORMARABIC LETTER TTEH INITIAL F" +
"ORMARABIC LETTER TTEH MEDIAL FORMARABIC LETTER VEH ISOLATED FORMARABIC L" +
"ETTER VEH FINAL FORMARABIC LETTER VEH INITIAL FORMARABIC LETTER VEH MEDI" +
"AL FORMARABIC LETTER PEHEH ISOLATED FORMARABIC LETTER PEHEH FINAL FORMAR" +
"ABIC LETTER PEHEH INITIAL FORMARABIC LETTER PEHEH MEDIAL FORMARABIC LETT" +
"ER DYEH ISOLATED FORMARABIC LETTER DYEH FINAL FORMARABIC LETTER DYEH INI" +
"TIAL FORMARABIC LETTER DYEH MEDIAL FORMARABIC LETTER NYEH ISOLATED FORMA" +
"RABIC LETTER NYEH FINAL FORMARABIC LETTER NYEH INITIAL FORMARABIC LETTER" +
" NYEH MEDIAL FORMARABIC LETTER TCHEH ISOLATED FORMARABIC LETTER TCHEH FI" +
"NAL FORMARABIC LETTER TCHEH INITIAL FORMARABIC LETTER TCHEH MEDIAL FORMA" +
"RABIC LETTER TCHEHEH ISOLATED FORMARABIC LETTER TCHEHEH FINAL FORMARABIC" +
" LETTER TCHEHEH INITIAL FORMARABIC LETTER TCHEHEH MEDIAL FORMARABIC LETT" +
"ER DDAHAL ISOLATED FORMARABIC LETTER DDAHAL FINAL FORMARABIC LETTER DAHA" +
"L ISOLATED FORMARABIC LETTER DAHAL FINAL FORMARABIC LETTER DUL ISOLATED " +
"FORMARABIC LETTER DUL FINAL FORMARABIC LETTER DDAL ISOLATED FORMARABIC L" +
"ETTER DDAL FINAL FORMARABIC LETTER JEH ISOLATED FORMARABIC LETTER JEH FI" +
"NAL FORMARABIC LETTER RREH ISOLATED FORMARABIC LETTER RREH FINAL FORMARA" +
"BIC LETTER KEHEH ISOLATED FORMARABIC LETTER KEHEH FINAL FORMARABIC LETTE" +
"R KEHEH INITIAL FORMARABIC LETTER KEHEH MEDIAL FORMARABIC LETTER GAF ISO" +
"LATED FORMARABIC LETTER GAF FINAL FORMARABIC LETTER GAF INITIAL FORMARAB" +
"IC LETTER GAF MEDIAL FORMARABIC LETTER GUEH ISOLATED FORMARABIC LETTER G" +
"UEH FINAL FORMARABIC LETTER GUEH INITIAL FORMARABIC LETTER GUEH MEDIAL F" +
"ORMARABIC LETTER NGOEH ISOLATED FORMARABIC LETTER NGOEH FINAL FORMARABIC" +
" LETTER NGOEH INITIAL FORMARABIC LETTER NGOEH MEDIAL FORMARABIC LETTER N" +
"OON GHUNNA ISOLATED FORMARABIC LETTER NOON GHUNNA FINAL FORMARABIC LETTE" +
"R RNOON ISOLATED FORMARABIC LETTER RNOON FINAL FORMARABIC LETTER RNOON I" +
"NITIAL FORMARABIC LETTER RNOON MEDIAL FORMARABIC LETTER HEH WITH YEH ABO" +
"VE ISOLATED FORMARABIC LETTER HEH WITH YEH ABOVE FINAL FORMARABIC LETTER" +
" HEH GOAL ISOLATED FORMARABIC LETTER HEH GOAL FINAL FORMARABIC LETTER HE" +
"H GOAL INITIAL FORMARABIC LETTER HEH GOAL MEDIAL FORMARABIC LETTER HEH D" +
"OACHASHMEE ISOLATED FORMARABIC LETTER HEH DOACHASHMEE FINAL FORMARABIC L" +
"ETTER HEH DOACHASHMEE INITIAL FORMARABIC LETTER HEH DOACHASHMEE MEDIAL F" +
"ORMARABIC LETTER YEH BARREE ISOLATED FORMARABIC LETTER YEH BARREE FINAL " +
"FORMARABIC LETTER YEH BARREE WITH HAMZA ABOVE ISOLATED FORMARABIC LETTER" +
" YEH BARREE WITH HAMZA ABOVE FINAL FORMARABIC SYMBOL DOT ABOVEARABIC SYM" +
"BOL DOT BELOWARABIC SYMBOL TWO DOTS ABOVEARABIC SYMBOL TWO DOTS BELOWARA" +
"BIC SYMBOL THREE DOTS ABOVEARABIC SYMBOL THREE DOTS BELOWARABIC SYMBOL T" +
"HREE DOTS POINTING DOWNWARDS ABOVEARABIC SYMBOL THREE DOTS POINTING DOWN" +
"WARDS BELOWARABIC SYMBOL FOUR DOTS ABOVEARABIC SYMBOL FOUR DOTS BELOWARA" +
"BIC SYMBOL DOUBLE VERTICAL BAR BELOWARABIC SYMBOL TWO DOTS VERTICALLY AB" +
"OVEARABIC SYMBOL TWO DOTS VERTICALLY BELOWARABIC SYMBOL RINGARABIC SYMBO" +
"L SMALL TAH ABOVEARABIC SYMBOL SMALL TAH BELOWARABIC SYMBOL WASLA ABOVEA" +
"RABIC LETTER NG ISOLATED FORMARABIC LETTER NG FINAL FORMARABIC LETTER NG" +
" INITIAL FORMARABIC LETTER NG MEDIAL FORMARABIC LETTER U ISOLATED FORMAR" +
"ABIC LETTER U FINAL FORMARABIC LETTER OE ISOLATED FORMARABIC LETTER OE F" +
"INAL FORMARABIC LETTER YU ISOLATED FORMARABIC LETTER YU FINAL FORMARABIC" +
" LETTER U WITH HAMZA ABOVE ISOLATED FORMARABIC LETTER VE ISOLATED FORMAR" +
"ABIC LETTER VE FINAL FORMARABIC LETTER KIRGHIZ OE ISOLATED FORMARABIC LE" +
"TTER KIRGHIZ OE FINAL FORMARABIC LETTER KIRGHIZ YU ISOLATED FORMARABIC L" +
"ETTER KIRGHIZ YU FINAL FORMARABIC LETTER E ISOLATED FORMARABIC LETTER E " +
"FINAL FORMARABIC LETTER E INITIAL FORMARABIC LETTER E MEDIAL FORMARABIC " +
"LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORMARABIC LETTER UIGH" +
"UR KAZAKH KIRGHIZ ALEF MAKSURA MEDIAL FORMARABIC LIGATURE YEH WITH HAMZA" +
" ABOVE WITH ALEF ISOLATED FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH " +
"ALEF FINAL FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE ISOLATED FOR" +
"MARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE FINAL FORMARABIC LIGATURE " +
"YEH WITH HAMZA ABOVE WITH WAW ISOLATED FORMARABIC LIGATURE YEH WITH HAMZ" +
"A ABOVE WITH WAW FINAL FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U I" +
"SOLATED FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U FINAL FORMARABIC" +
" LIGATURE YEH WITH HAMZA ABOVE WITH OE ISOLATED FORMARABIC LIGATURE YEH " +
"WITH HAMZA ABOVE WITH OE FINAL FORMARABIC LIGATURE YEH WITH HAMZA ABOVE " +
"WITH YU ISOLATED FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU FINAL " +
"FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E ISOLATED FORMARABIC LIGA" +
"TURE YEH WITH HAMZA ABOVE WITH E FINAL FORMARABIC LIGATURE YEH WITH HAMZ") + ("" +
"A ABOVE WITH E INITIAL FORMARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA" +
" ABOVE WITH ALEF MAKSURA ISOLATED FORMARABIC LIGATURE UIGHUR KIRGHIZ YEH" +
" WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE UIGHUR KIR" +
"GHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA INITIAL FORMARABIC LETTER FA" +
"RSI YEH ISOLATED FORMARABIC LETTER FARSI YEH FINAL FORMARABIC LETTER FAR" +
"SI YEH INITIAL FORMARABIC LETTER FARSI YEH MEDIAL FORMARABIC LIGATURE YE" +
"H WITH HAMZA ABOVE WITH JEEM ISOLATED FORMARABIC LIGATURE YEH WITH HAMZA" +
" ABOVE WITH HAH ISOLATED FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH M" +
"EEM ISOLATED FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA " +
"ISOLATED FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH ISOLATED FORM" +
"ARABIC LIGATURE BEH WITH JEEM ISOLATED FORMARABIC LIGATURE BEH WITH HAH " +
"ISOLATED FORMARABIC LIGATURE BEH WITH KHAH ISOLATED FORMARABIC LIGATURE " +
"BEH WITH MEEM ISOLATED FORMARABIC LIGATURE BEH WITH ALEF MAKSURA ISOLATE" +
"D FORMARABIC LIGATURE BEH WITH YEH ISOLATED FORMARABIC LIGATURE TEH WITH" +
" JEEM ISOLATED FORMARABIC LIGATURE TEH WITH HAH ISOLATED FORMARABIC LIGA" +
"TURE TEH WITH KHAH ISOLATED FORMARABIC LIGATURE TEH WITH MEEM ISOLATED F" +
"ORMARABIC LIGATURE TEH WITH ALEF MAKSURA ISOLATED FORMARABIC LIGATURE TE" +
"H WITH YEH ISOLATED FORMARABIC LIGATURE THEH WITH JEEM ISOLATED FORMARAB" +
"IC LIGATURE THEH WITH MEEM ISOLATED FORMARABIC LIGATURE THEH WITH ALEF M" +
"AKSURA ISOLATED FORMARABIC LIGATURE THEH WITH YEH ISOLATED FORMARABIC LI" +
"GATURE JEEM WITH HAH ISOLATED FORMARABIC LIGATURE JEEM WITH MEEM ISOLATE" +
"D FORMARABIC LIGATURE HAH WITH JEEM ISOLATED FORMARABIC LIGATURE HAH WIT" +
"H MEEM ISOLATED FORMARABIC LIGATURE KHAH WITH JEEM ISOLATED FORMARABIC L" +
"IGATURE KHAH WITH HAH ISOLATED FORMARABIC LIGATURE KHAH WITH MEEM ISOLAT" +
"ED FORMARABIC LIGATURE SEEN WITH JEEM ISOLATED FORMARABIC LIGATURE SEEN " +
"WITH HAH ISOLATED FORMARABIC LIGATURE SEEN WITH KHAH ISOLATED FORMARABIC" +
" LIGATURE SEEN WITH MEEM ISOLATED FORMARABIC LIGATURE SAD WITH HAH ISOLA" +
"TED FORMARABIC LIGATURE SAD WITH MEEM ISOLATED FORMARABIC LIGATURE DAD W" +
"ITH JEEM ISOLATED FORMARABIC LIGATURE DAD WITH HAH ISOLATED FORMARABIC L" +
"IGATURE DAD WITH KHAH ISOLATED FORMARABIC LIGATURE DAD WITH MEEM ISOLATE" +
"D FORMARABIC LIGATURE TAH WITH HAH ISOLATED FORMARABIC LIGATURE TAH WITH" +
" MEEM ISOLATED FORMARABIC LIGATURE ZAH WITH MEEM ISOLATED FORMARABIC LIG" +
"ATURE AIN WITH JEEM ISOLATED FORMARABIC LIGATURE AIN WITH MEEM ISOLATED " +
"FORMARABIC LIGATURE GHAIN WITH JEEM ISOLATED FORMARABIC LIGATURE GHAIN W" +
"ITH MEEM ISOLATED FORMARABIC LIGATURE FEH WITH JEEM ISOLATED FORMARABIC " +
"LIGATURE FEH WITH HAH ISOLATED FORMARABIC LIGATURE FEH WITH KHAH ISOLATE" +
"D FORMARABIC LIGATURE FEH WITH MEEM ISOLATED FORMARABIC LIGATURE FEH WIT" +
"H ALEF MAKSURA ISOLATED FORMARABIC LIGATURE FEH WITH YEH ISOLATED FORMAR" +
"ABIC LIGATURE QAF WITH HAH ISOLATED FORMARABIC LIGATURE QAF WITH MEEM IS" +
"OLATED FORMARABIC LIGATURE QAF WITH ALEF MAKSURA ISOLATED FORMARABIC LIG" +
"ATURE QAF WITH YEH ISOLATED FORMARABIC LIGATURE KAF WITH ALEF ISOLATED F" +
"ORMARABIC LIGATURE KAF WITH JEEM ISOLATED FORMARABIC LIGATURE KAF WITH H" +
"AH ISOLATED FORMARABIC LIGATURE KAF WITH KHAH ISOLATED FORMARABIC LIGATU" +
"RE KAF WITH LAM ISOLATED FORMARABIC LIGATURE KAF WITH MEEM ISOLATED FORM" +
"ARABIC LIGATURE KAF WITH ALEF MAKSURA ISOLATED FORMARABIC LIGATURE KAF W" +
"ITH YEH ISOLATED FORMARABIC LIGATURE LAM WITH JEEM ISOLATED FORMARABIC L" +
"IGATURE LAM WITH HAH ISOLATED FORMARABIC LIGATURE LAM WITH KHAH ISOLATED" +
" FORMARABIC LIGATURE LAM WITH MEEM ISOLATED FORMARABIC LIGATURE LAM WITH" +
" ALEF MAKSURA ISOLATED FORMARABIC LIGATURE LAM WITH YEH ISOLATED FORMARA" +
"BIC LIGATURE MEEM WITH JEEM ISOLATED FORMARABIC LIGATURE MEEM WITH HAH I" +
"SOLATED FORMARABIC LIGATURE MEEM WITH KHAH ISOLATED FORMARABIC LIGATURE " +
"MEEM WITH MEEM ISOLATED FORMARABIC LIGATURE MEEM WITH ALEF MAKSURA ISOLA" +
"TED FORMARABIC LIGATURE MEEM WITH YEH ISOLATED FORMARABIC LIGATURE NOON " +
"WITH JEEM ISOLATED FORMARABIC LIGATURE NOON WITH HAH ISOLATED FORMARABIC" +
" LIGATURE NOON WITH KHAH ISOLATED FORMARABIC LIGATURE NOON WITH MEEM ISO" +
"LATED FORMARABIC LIGATURE NOON WITH ALEF MAKSURA ISOLATED FORMARABIC LIG" +
"ATURE NOON WITH YEH ISOLATED FORMARABIC LIGATURE HEH WITH JEEM ISOLATED " +
"FORMARABIC LIGATURE HEH WITH MEEM ISOLATED FORMARABIC LIGATURE HEH WITH " +
"ALEF MAKSURA ISOLATED FORMARABIC LIGATURE HEH WITH YEH ISOLATED FORMARAB" +
"IC LIGATURE YEH WITH JEEM ISOLATED FORMARABIC LIGATURE YEH WITH HAH ISOL" +
"ATED FORMARABIC LIGATURE YEH WITH KHAH ISOLATED FORMARABIC LIGATURE YEH " +
"WITH MEEM ISOLATED FORMARABIC LIGATURE YEH WITH ALEF MAKSURA ISOLATED FO" +
"RMARABIC LIGATURE YEH WITH YEH ISOLATED FORMARABIC LIGATURE THAL WITH SU" +
"PERSCRIPT ALEF ISOLATED FORMARABIC LIGATURE REH WITH SUPERSCRIPT ALEF IS") + ("" +
"OLATED FORMARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF ISOLATED F" +
"ORMARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORMARABIC LIGATURE SHA" +
"DDA WITH KASRATAN ISOLATED FORMARABIC LIGATURE SHADDA WITH FATHA ISOLATE" +
"D FORMARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORMARABIC LIGATURE SHA" +
"DDA WITH KASRA ISOLATED FORMARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF" +
" ISOLATED FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH FINAL FORMAR" +
"ABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN FINAL FORMARABIC LIGATURE Y" +
"EH WITH HAMZA ABOVE WITH MEEM FINAL FORMARABIC LIGATURE YEH WITH HAMZA A" +
"BOVE WITH NOON FINAL FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF " +
"MAKSURA FINAL FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH FINAL FO" +
"RMARABIC LIGATURE BEH WITH REH FINAL FORMARABIC LIGATURE BEH WITH ZAIN F" +
"INAL FORMARABIC LIGATURE BEH WITH MEEM FINAL FORMARABIC LIGATURE BEH WIT" +
"H NOON FINAL FORMARABIC LIGATURE BEH WITH ALEF MAKSURA FINAL FORMARABIC " +
"LIGATURE BEH WITH YEH FINAL FORMARABIC LIGATURE TEH WITH REH FINAL FORMA" +
"RABIC LIGATURE TEH WITH ZAIN FINAL FORMARABIC LIGATURE TEH WITH MEEM FIN" +
"AL FORMARABIC LIGATURE TEH WITH NOON FINAL FORMARABIC LIGATURE TEH WITH " +
"ALEF MAKSURA FINAL FORMARABIC LIGATURE TEH WITH YEH FINAL FORMARABIC LIG" +
"ATURE THEH WITH REH FINAL FORMARABIC LIGATURE THEH WITH ZAIN FINAL FORMA" +
"RABIC LIGATURE THEH WITH MEEM FINAL FORMARABIC LIGATURE THEH WITH NOON F" +
"INAL FORMARABIC LIGATURE THEH WITH ALEF MAKSURA FINAL FORMARABIC LIGATUR" +
"E THEH WITH YEH FINAL FORMARABIC LIGATURE FEH WITH ALEF MAKSURA FINAL FO" +
"RMARABIC LIGATURE FEH WITH YEH FINAL FORMARABIC LIGATURE QAF WITH ALEF M" +
"AKSURA FINAL FORMARABIC LIGATURE QAF WITH YEH FINAL FORMARABIC LIGATURE " +
"KAF WITH ALEF FINAL FORMARABIC LIGATURE KAF WITH LAM FINAL FORMARABIC LI" +
"GATURE KAF WITH MEEM FINAL FORMARABIC LIGATURE KAF WITH ALEF MAKSURA FIN" +
"AL FORMARABIC LIGATURE KAF WITH YEH FINAL FORMARABIC LIGATURE LAM WITH M" +
"EEM FINAL FORMARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORMARABIC LIG" +
"ATURE LAM WITH YEH FINAL FORMARABIC LIGATURE MEEM WITH ALEF FINAL FORMAR" +
"ABIC LIGATURE MEEM WITH MEEM FINAL FORMARABIC LIGATURE NOON WITH REH FIN" +
"AL FORMARABIC LIGATURE NOON WITH ZAIN FINAL FORMARABIC LIGATURE NOON WIT" +
"H MEEM FINAL FORMARABIC LIGATURE NOON WITH NOON FINAL FORMARABIC LIGATUR" +
"E NOON WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE NOON WITH YEH FINAL F" +
"ORMARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF FINAL FORMARABIC L" +
"IGATURE YEH WITH REH FINAL FORMARABIC LIGATURE YEH WITH ZAIN FINAL FORMA" +
"RABIC LIGATURE YEH WITH MEEM FINAL FORMARABIC LIGATURE YEH WITH NOON FIN" +
"AL FORMARABIC LIGATURE YEH WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE Y" +
"EH WITH YEH FINAL FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM INI" +
"TIAL FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH INITIAL FORMARABI" +
"C LIGATURE YEH WITH HAMZA ABOVE WITH KHAH INITIAL FORMARABIC LIGATURE YE" +
"H WITH HAMZA ABOVE WITH MEEM INITIAL FORMARABIC LIGATURE YEH WITH HAMZA " +
"ABOVE WITH HEH INITIAL FORMARABIC LIGATURE BEH WITH JEEM INITIAL FORMARA" +
"BIC LIGATURE BEH WITH HAH INITIAL FORMARABIC LIGATURE BEH WITH KHAH INIT" +
"IAL FORMARABIC LIGATURE BEH WITH MEEM INITIAL FORMARABIC LIGATURE BEH WI" +
"TH HEH INITIAL FORMARABIC LIGATURE TEH WITH JEEM INITIAL FORMARABIC LIGA" +
"TURE TEH WITH HAH INITIAL FORMARABIC LIGATURE TEH WITH KHAH INITIAL FORM" +
"ARABIC LIGATURE TEH WITH MEEM INITIAL FORMARABIC LIGATURE TEH WITH HEH I" +
"NITIAL FORMARABIC LIGATURE THEH WITH MEEM INITIAL FORMARABIC LIGATURE JE" +
"EM WITH HAH INITIAL FORMARABIC LIGATURE JEEM WITH MEEM INITIAL FORMARABI" +
"C LIGATURE HAH WITH JEEM INITIAL FORMARABIC LIGATURE HAH WITH MEEM INITI" +
"AL FORMARABIC LIGATURE KHAH WITH JEEM INITIAL FORMARABIC LIGATURE KHAH W" +
"ITH MEEM INITIAL FORMARABIC LIGATURE SEEN WITH JEEM INITIAL FORMARABIC L" +
"IGATURE SEEN WITH HAH INITIAL FORMARABIC LIGATURE SEEN WITH KHAH INITIAL" +
" FORMARABIC LIGATURE SEEN WITH MEEM INITIAL FORMARABIC LIGATURE SAD WITH" +
" HAH INITIAL FORMARABIC LIGATURE SAD WITH KHAH INITIAL FORMARABIC LIGATU" +
"RE SAD WITH MEEM INITIAL FORMARABIC LIGATURE DAD WITH JEEM INITIAL FORMA" +
"RABIC LIGATURE DAD WITH HAH INITIAL FORMARABIC LIGATURE DAD WITH KHAH IN" +
"ITIAL FORMARABIC LIGATURE DAD WITH MEEM INITIAL FORMARABIC LIGATURE TAH " +
"WITH HAH INITIAL FORMARABIC LIGATURE ZAH WITH MEEM INITIAL FORMARABIC LI" +
"GATURE AIN WITH JEEM INITIAL FORMARABIC LIGATURE AIN WITH MEEM INITIAL F" +
"ORMARABIC LIGATURE GHAIN WITH JEEM INITIAL FORMARABIC LIGATURE GHAIN WIT" +
"H MEEM INITIAL FORMARABIC LIGATURE FEH WITH JEEM INITIAL FORMARABIC LIGA" +
"TURE FEH WITH HAH INITIAL FORMARABIC LIGATURE FEH WITH KHAH INITIAL FORM" +
"ARABIC LIGATURE FEH WITH MEEM INITIAL FORMARABIC LIGATURE QAF WITH HAH I" +
"NITIAL FORMARABIC LIGATURE QAF WITH MEEM INITIAL FORMARABIC LIGATURE KAF") + ("" +
" WITH JEEM INITIAL FORMARABIC LIGATURE KAF WITH HAH INITIAL FORMARABIC L" +
"IGATURE KAF WITH KHAH INITIAL FORMARABIC LIGATURE KAF WITH LAM INITIAL F" +
"ORMARABIC LIGATURE KAF WITH MEEM INITIAL FORMARABIC LIGATURE LAM WITH JE" +
"EM INITIAL FORMARABIC LIGATURE LAM WITH HAH INITIAL FORMARABIC LIGATURE " +
"LAM WITH KHAH INITIAL FORMARABIC LIGATURE LAM WITH MEEM INITIAL FORMARAB" +
"IC LIGATURE LAM WITH HEH INITIAL FORMARABIC LIGATURE MEEM WITH JEEM INIT" +
"IAL FORMARABIC LIGATURE MEEM WITH HAH INITIAL FORMARABIC LIGATURE MEEM W" +
"ITH KHAH INITIAL FORMARABIC LIGATURE MEEM WITH MEEM INITIAL FORMARABIC L" +
"IGATURE NOON WITH JEEM INITIAL FORMARABIC LIGATURE NOON WITH HAH INITIAL" +
" FORMARABIC LIGATURE NOON WITH KHAH INITIAL FORMARABIC LIGATURE NOON WIT" +
"H MEEM INITIAL FORMARABIC LIGATURE NOON WITH HEH INITIAL FORMARABIC LIGA" +
"TURE HEH WITH JEEM INITIAL FORMARABIC LIGATURE HEH WITH MEEM INITIAL FOR" +
"MARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF INITIAL FORMARABIC LIGATURE Y" +
"EH WITH JEEM INITIAL FORMARABIC LIGATURE YEH WITH HAH INITIAL FORMARABIC" +
" LIGATURE YEH WITH KHAH INITIAL FORMARABIC LIGATURE YEH WITH MEEM INITIA" +
"L FORMARABIC LIGATURE YEH WITH HEH INITIAL FORMARABIC LIGATURE YEH WITH " +
"HAMZA ABOVE WITH MEEM MEDIAL FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WI" +
"TH HEH MEDIAL FORMARABIC LIGATURE BEH WITH MEEM MEDIAL FORMARABIC LIGATU" +
"RE BEH WITH HEH MEDIAL FORMARABIC LIGATURE TEH WITH MEEM MEDIAL FORMARAB" +
"IC LIGATURE TEH WITH HEH MEDIAL FORMARABIC LIGATURE THEH WITH MEEM MEDIA" +
"L FORMARABIC LIGATURE THEH WITH HEH MEDIAL FORMARABIC LIGATURE SEEN WITH" +
" MEEM MEDIAL FORMARABIC LIGATURE SEEN WITH HEH MEDIAL FORMARABIC LIGATUR" +
"E SHEEN WITH MEEM MEDIAL FORMARABIC LIGATURE SHEEN WITH HEH MEDIAL FORMA" +
"RABIC LIGATURE KAF WITH LAM MEDIAL FORMARABIC LIGATURE KAF WITH MEEM MED" +
"IAL FORMARABIC LIGATURE LAM WITH MEEM MEDIAL FORMARABIC LIGATURE NOON WI" +
"TH MEEM MEDIAL FORMARABIC LIGATURE NOON WITH HEH MEDIAL FORMARABIC LIGAT" +
"URE YEH WITH MEEM MEDIAL FORMARABIC LIGATURE YEH WITH HEH MEDIAL FORMARA" +
"BIC LIGATURE SHADDA WITH FATHA MEDIAL FORMARABIC LIGATURE SHADDA WITH DA" +
"MMA MEDIAL FORMARABIC LIGATURE SHADDA WITH KASRA MEDIAL FORMARABIC LIGAT" +
"URE TAH WITH ALEF MAKSURA ISOLATED FORMARABIC LIGATURE TAH WITH YEH ISOL" +
"ATED FORMARABIC LIGATURE AIN WITH ALEF MAKSURA ISOLATED FORMARABIC LIGAT" +
"URE AIN WITH YEH ISOLATED FORMARABIC LIGATURE GHAIN WITH ALEF MAKSURA IS" +
"OLATED FORMARABIC LIGATURE GHAIN WITH YEH ISOLATED FORMARABIC LIGATURE S" +
"EEN WITH ALEF MAKSURA ISOLATED FORMARABIC LIGATURE SEEN WITH YEH ISOLATE" +
"D FORMARABIC LIGATURE SHEEN WITH ALEF MAKSURA ISOLATED FORMARABIC LIGATU" +
"RE SHEEN WITH YEH ISOLATED FORMARABIC LIGATURE HAH WITH ALEF MAKSURA ISO" +
"LATED FORMARABIC LIGATURE HAH WITH YEH ISOLATED FORMARABIC LIGATURE JEEM" +
" WITH ALEF MAKSURA ISOLATED FORMARABIC LIGATURE JEEM WITH YEH ISOLATED F" +
"ORMARABIC LIGATURE KHAH WITH ALEF MAKSURA ISOLATED FORMARABIC LIGATURE K" +
"HAH WITH YEH ISOLATED FORMARABIC LIGATURE SAD WITH ALEF MAKSURA ISOLATED" +
" FORMARABIC LIGATURE SAD WITH YEH ISOLATED FORMARABIC LIGATURE DAD WITH " +
"ALEF MAKSURA ISOLATED FORMARABIC LIGATURE DAD WITH YEH ISOLATED FORMARAB" +
"IC LIGATURE SHEEN WITH JEEM ISOLATED FORMARABIC LIGATURE SHEEN WITH HAH " +
"ISOLATED FORMARABIC LIGATURE SHEEN WITH KHAH ISOLATED FORMARABIC LIGATUR" +
"E SHEEN WITH MEEM ISOLATED FORMARABIC LIGATURE SHEEN WITH REH ISOLATED F" +
"ORMARABIC LIGATURE SEEN WITH REH ISOLATED FORMARABIC LIGATURE SAD WITH R" +
"EH ISOLATED FORMARABIC LIGATURE DAD WITH REH ISOLATED FORMARABIC LIGATUR" +
"E TAH WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE TAH WITH YEH FINAL FOR" +
"MARABIC LIGATURE AIN WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE AIN WIT" +
"H YEH FINAL FORMARABIC LIGATURE GHAIN WITH ALEF MAKSURA FINAL FORMARABIC" +
" LIGATURE GHAIN WITH YEH FINAL FORMARABIC LIGATURE SEEN WITH ALEF MAKSUR" +
"A FINAL FORMARABIC LIGATURE SEEN WITH YEH FINAL FORMARABIC LIGATURE SHEE" +
"N WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE SHEEN WITH YEH FINAL FORMA" +
"RABIC LIGATURE HAH WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE HAH WITH " +
"YEH FINAL FORMARABIC LIGATURE JEEM WITH ALEF MAKSURA FINAL FORMARABIC LI" +
"GATURE JEEM WITH YEH FINAL FORMARABIC LIGATURE KHAH WITH ALEF MAKSURA FI" +
"NAL FORMARABIC LIGATURE KHAH WITH YEH FINAL FORMARABIC LIGATURE SAD WITH" +
" ALEF MAKSURA FINAL FORMARABIC LIGATURE SAD WITH YEH FINAL FORMARABIC LI" +
"GATURE DAD WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE DAD WITH YEH FINA" +
"L FORMARABIC LIGATURE SHEEN WITH JEEM FINAL FORMARABIC LIGATURE SHEEN WI" +
"TH HAH FINAL FORMARABIC LIGATURE SHEEN WITH KHAH FINAL FORMARABIC LIGATU" +
"RE SHEEN WITH MEEM FINAL FORMARABIC LIGATURE SHEEN WITH REH FINAL FORMAR" +
"ABIC LIGATURE SEEN WITH REH FINAL FORMARABIC LIGATURE SAD WITH REH FINAL" +
" FORMARABIC LIGATURE DAD WITH REH FINAL FORMARABIC LIGATURE SHEEN WITH J") + ("" +
"EEM INITIAL FORMARABIC LIGATURE SHEEN WITH HAH INITIAL FORMARABIC LIGATU" +
"RE SHEEN WITH KHAH INITIAL FORMARABIC LIGATURE SHEEN WITH MEEM INITIAL F" +
"ORMARABIC LIGATURE SEEN WITH HEH INITIAL FORMARABIC LIGATURE SHEEN WITH " +
"HEH INITIAL FORMARABIC LIGATURE TAH WITH MEEM INITIAL FORMARABIC LIGATUR" +
"E SEEN WITH JEEM MEDIAL FORMARABIC LIGATURE SEEN WITH HAH MEDIAL FORMARA" +
"BIC LIGATURE SEEN WITH KHAH MEDIAL FORMARABIC LIGATURE SHEEN WITH JEEM M" +
"EDIAL FORMARABIC LIGATURE SHEEN WITH HAH MEDIAL FORMARABIC LIGATURE SHEE" +
"N WITH KHAH MEDIAL FORMARABIC LIGATURE TAH WITH MEEM MEDIAL FORMARABIC L" +
"IGATURE ZAH WITH MEEM MEDIAL FORMARABIC LIGATURE ALEF WITH FATHATAN FINA" +
"L FORMARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORMORNATE LEFT PARENT" +
"HESISORNATE RIGHT PARENTHESISARABIC LIGATURE RAHIMAHU ALLAAHARABIC LIGAT" +
"URE RADI ALLAAHU ANHARABIC LIGATURE RADI ALLAAHU ANHAAARABIC LIGATURE RA" +
"DI ALLAAHU ANHUMARABIC LIGATURE RADI ALLAAHU ANHUMAAARABIC LIGATURE RADI" +
" ALLAAHU ANHUNNAARABIC LIGATURE SALLALLAAHU ALAYHI WA-AALIHARABIC LIGATU" +
"RE ALAYHI AS-SALAAMARABIC LIGATURE ALAYHIM AS-SALAAMARABIC LIGATURE ALAY" +
"HIMAA AS-SALAAMARABIC LIGATURE ALAYHI AS-SALAATU WAS-SALAAMARABIC LIGATU" +
"RE QUDDISA SIRRAHARABIC LIGATURE SALLALLAHU ALAYHI WAAALIHEE WA-SALLAMAR" +
"ABIC LIGATURE ALAYHAA AS-SALAAMARABIC LIGATURE TABAARAKA WA-TAAALAAARABI" +
"C LIGATURE RAHIMAHUM ALLAAHARABIC LIGATURE TEH WITH JEEM WITH MEEM INITI" +
"AL FORMARABIC LIGATURE TEH WITH HAH WITH JEEM FINAL FORMARABIC LIGATURE " +
"TEH WITH HAH WITH JEEM INITIAL FORMARABIC LIGATURE TEH WITH HAH WITH MEE" +
"M INITIAL FORMARABIC LIGATURE TEH WITH KHAH WITH MEEM INITIAL FORMARABIC" +
" LIGATURE TEH WITH MEEM WITH JEEM INITIAL FORMARABIC LIGATURE TEH WITH M" +
"EEM WITH HAH INITIAL FORMARABIC LIGATURE TEH WITH MEEM WITH KHAH INITIAL" +
" FORMARABIC LIGATURE JEEM WITH MEEM WITH HAH FINAL FORMARABIC LIGATURE J" +
"EEM WITH MEEM WITH HAH INITIAL FORMARABIC LIGATURE HAH WITH MEEM WITH YE" +
"H FINAL FORMARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA FINAL FORMAR" +
"ABIC LIGATURE SEEN WITH HAH WITH JEEM INITIAL FORMARABIC LIGATURE SEEN W" +
"ITH JEEM WITH HAH INITIAL FORMARABIC LIGATURE SEEN WITH JEEM WITH ALEF M" +
"AKSURA FINAL FORMARABIC LIGATURE SEEN WITH MEEM WITH HAH FINAL FORMARABI" +
"C LIGATURE SEEN WITH MEEM WITH HAH INITIAL FORMARABIC LIGATURE SEEN WITH" +
" MEEM WITH JEEM INITIAL FORMARABIC LIGATURE SEEN WITH MEEM WITH MEEM FIN" +
"AL FORMARABIC LIGATURE SEEN WITH MEEM WITH MEEM INITIAL FORMARABIC LIGAT" +
"URE SAD WITH HAH WITH HAH FINAL FORMARABIC LIGATURE SAD WITH HAH WITH HA" +
"H INITIAL FORMARABIC LIGATURE SAD WITH MEEM WITH MEEM FINAL FORMARABIC L" +
"IGATURE SHEEN WITH HAH WITH MEEM FINAL FORMARABIC LIGATURE SHEEN WITH HA" +
"H WITH MEEM INITIAL FORMARABIC LIGATURE SHEEN WITH JEEM WITH YEH FINAL F" +
"ORMARABIC LIGATURE SHEEN WITH MEEM WITH KHAH FINAL FORMARABIC LIGATURE S" +
"HEEN WITH MEEM WITH KHAH INITIAL FORMARABIC LIGATURE SHEEN WITH MEEM WIT" +
"H MEEM FINAL FORMARABIC LIGATURE SHEEN WITH MEEM WITH MEEM INITIAL FORMA" +
"RABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE " +
"DAD WITH KHAH WITH MEEM FINAL FORMARABIC LIGATURE DAD WITH KHAH WITH MEE" +
"M INITIAL FORMARABIC LIGATURE TAH WITH MEEM WITH HAH FINAL FORMARABIC LI" +
"GATURE TAH WITH MEEM WITH HAH INITIAL FORMARABIC LIGATURE TAH WITH MEEM " +
"WITH MEEM INITIAL FORMARABIC LIGATURE TAH WITH MEEM WITH YEH FINAL FORMA" +
"RABIC LIGATURE AIN WITH JEEM WITH MEEM FINAL FORMARABIC LIGATURE AIN WIT" +
"H MEEM WITH MEEM FINAL FORMARABIC LIGATURE AIN WITH MEEM WITH MEEM INITI" +
"AL FORMARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA FINAL FORMARABIC " +
"LIGATURE GHAIN WITH MEEM WITH MEEM FINAL FORMARABIC LIGATURE GHAIN WITH " +
"MEEM WITH YEH FINAL FORMARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSUR" +
"A FINAL FORMARABIC LIGATURE FEH WITH KHAH WITH MEEM FINAL FORMARABIC LIG" +
"ATURE FEH WITH KHAH WITH MEEM INITIAL FORMARABIC LIGATURE QAF WITH MEEM " +
"WITH HAH FINAL FORMARABIC LIGATURE QAF WITH MEEM WITH MEEM FINAL FORMARA" +
"BIC LIGATURE LAM WITH HAH WITH MEEM FINAL FORMARABIC LIGATURE LAM WITH H" +
"AH WITH YEH FINAL FORMARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA FIN" +
"AL FORMARABIC LIGATURE LAM WITH JEEM WITH JEEM INITIAL FORMARABIC LIGATU" +
"RE LAM WITH JEEM WITH JEEM FINAL FORMARABIC LIGATURE LAM WITH KHAH WITH " +
"MEEM FINAL FORMARABIC LIGATURE LAM WITH KHAH WITH MEEM INITIAL FORMARABI" +
"C LIGATURE LAM WITH MEEM WITH HAH FINAL FORMARABIC LIGATURE LAM WITH MEE" +
"M WITH HAH INITIAL FORMARABIC LIGATURE MEEM WITH HAH WITH JEEM INITIAL F" +
"ORMARABIC LIGATURE MEEM WITH HAH WITH MEEM INITIAL FORMARABIC LIGATURE M" +
"EEM WITH HAH WITH YEH FINAL FORMARABIC LIGATURE MEEM WITH JEEM WITH HAH " +
"INITIAL FORMARABIC LIGATURE MEEM WITH JEEM WITH MEEM INITIAL FORMARABIC " +
"LIGATURE MEEM WITH KHAH WITH JEEM INITIAL FORMARABIC LIGATURE MEEM WITH ") + ("" +
"KHAH WITH MEEM INITIAL FORMARABIC LIGATURE MEEM WITH JEEM WITH KHAH INIT" +
"IAL FORMARABIC LIGATURE HEH WITH MEEM WITH JEEM INITIAL FORMARABIC LIGAT" +
"URE HEH WITH MEEM WITH MEEM INITIAL FORMARABIC LIGATURE NOON WITH HAH WI" +
"TH MEEM INITIAL FORMARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA FINA" +
"L FORMARABIC LIGATURE NOON WITH JEEM WITH MEEM FINAL FORMARABIC LIGATURE" +
" NOON WITH JEEM WITH MEEM INITIAL FORMARABIC LIGATURE NOON WITH JEEM WIT" +
"H ALEF MAKSURA FINAL FORMARABIC LIGATURE NOON WITH MEEM WITH YEH FINAL F" +
"ORMARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA FINAL FORMARABIC LIG" +
"ATURE YEH WITH MEEM WITH MEEM FINAL FORMARABIC LIGATURE YEH WITH MEEM WI" +
"TH MEEM INITIAL FORMARABIC LIGATURE BEH WITH KHAH WITH YEH FINAL FORMARA" +
"BIC LIGATURE TEH WITH JEEM WITH YEH FINAL FORMARABIC LIGATURE TEH WITH J" +
"EEM WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE TEH WITH KHAH WITH YEH F" +
"INAL FORMARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA FINAL FORMARABI" +
"C LIGATURE TEH WITH MEEM WITH YEH FINAL FORMARABIC LIGATURE TEH WITH MEE" +
"M WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE JEEM WITH MEEM WITH YEH FI" +
"NAL FORMARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA FINAL FORMARABIC" +
" LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE SEE" +
"N WITH KHAH WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE SAD WITH HAH WIT" +
"H YEH FINAL FORMARABIC LIGATURE SHEEN WITH HAH WITH YEH FINAL FORMARABIC" +
" LIGATURE DAD WITH HAH WITH YEH FINAL FORMARABIC LIGATURE LAM WITH JEEM " +
"WITH YEH FINAL FORMARABIC LIGATURE LAM WITH MEEM WITH YEH FINAL FORMARAB" +
"IC LIGATURE YEH WITH HAH WITH YEH FINAL FORMARABIC LIGATURE YEH WITH JEE" +
"M WITH YEH FINAL FORMARABIC LIGATURE YEH WITH MEEM WITH YEH FINAL FORMAR" +
"ABIC LIGATURE MEEM WITH MEEM WITH YEH FINAL FORMARABIC LIGATURE QAF WITH" +
" MEEM WITH YEH FINAL FORMARABIC LIGATURE NOON WITH HAH WITH YEH FINAL FO" +
"RMARABIC LIGATURE QAF WITH MEEM WITH HAH INITIAL FORMARABIC LIGATURE LAM" +
" WITH HAH WITH MEEM INITIAL FORMARABIC LIGATURE AIN WITH MEEM WITH YEH F" +
"INAL FORMARABIC LIGATURE KAF WITH MEEM WITH YEH FINAL FORMARABIC LIGATUR" +
"E NOON WITH JEEM WITH HAH INITIAL FORMARABIC LIGATURE MEEM WITH KHAH WIT" +
"H YEH FINAL FORMARABIC LIGATURE LAM WITH JEEM WITH MEEM INITIAL FORMARAB" +
"IC LIGATURE KAF WITH MEEM WITH MEEM FINAL FORMARABIC LIGATURE LAM WITH J" +
"EEM WITH MEEM FINAL FORMARABIC LIGATURE NOON WITH JEEM WITH HAH FINAL FO" +
"RMARABIC LIGATURE JEEM WITH HAH WITH YEH FINAL FORMARABIC LIGATURE HAH W" +
"ITH JEEM WITH YEH FINAL FORMARABIC LIGATURE MEEM WITH JEEM WITH YEH FINA" +
"L FORMARABIC LIGATURE FEH WITH MEEM WITH YEH FINAL FORMARABIC LIGATURE B" +
"EH WITH HAH WITH YEH FINAL FORMARABIC LIGATURE KAF WITH MEEM WITH MEEM I" +
"NITIAL FORMARABIC LIGATURE AIN WITH JEEM WITH MEEM INITIAL FORMARABIC LI" +
"GATURE SAD WITH MEEM WITH MEEM INITIAL FORMARABIC LIGATURE SEEN WITH KHA" +
"H WITH YEH FINAL FORMARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORMA" +
"RABIC LIGATURE SALAAMUHU ALAYNAAARABIC LIGATURE SALLA USED AS KORANIC ST" +
"OP SIGN ISOLATED FORMARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOL" +
"ATED FORMARABIC LIGATURE ALLAH ISOLATED FORMARABIC LIGATURE AKBAR ISOLAT" +
"ED FORMARABIC LIGATURE MOHAMMAD ISOLATED FORMARABIC LIGATURE SALAM ISOLA" +
"TED FORMARABIC LIGATURE RASOUL ISOLATED FORMARABIC LIGATURE ALAYHE ISOLA" +
"TED FORMARABIC LIGATURE WASALLAM ISOLATED FORMARABIC LIGATURE SALLA ISOL" +
"ATED FORMARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAMARABIC LIGATURE JALL" +
"AJALALOUHOURIAL SIGNARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEMARABIC " +
"LIGATURE SUBHAANAHU WA TAAALAAARABIC LIGATURE AZZA WA JALLVARIATION SELE" +
"CTOR-1VARIATION SELECTOR-2VARIATION SELECTOR-3VARIATION SELECTOR-4VARIAT" +
"ION SELECTOR-5VARIATION SELECTOR-6VARIATION SELECTOR-7VARIATION SELECTOR" +
"-8VARIATION SELECTOR-9VARIATION SELECTOR-10VARIATION SELECTOR-11VARIATIO" +
"N SELECTOR-12VARIATION SELECTOR-13VARIATION SELECTOR-14VARIATION SELECTO" +
"R-15VARIATION SELECTOR-16PRESENTATION FORM FOR VERTICAL COMMAPRESENTATIO" +
"N FORM FOR VERTICAL IDEOGRAPHIC COMMAPRESENTATION FORM FOR VERTICAL IDEO" +
"GRAPHIC FULL STOPPRESENTATION FORM FOR VERTICAL COLONPRESENTATION FORM F" +
"OR VERTICAL SEMICOLONPRESENTATION FORM FOR VERTICAL EXCLAMATION MARKPRES" +
"ENTATION FORM FOR VERTICAL QUESTION MARKPRESENTATION FORM FOR VERTICAL L" +
"EFT WHITE LENTICULAR BRACKETPRESENTATION FORM FOR VERTICAL RIGHT WHITE L" +
"ENTICULAR BRAKCETPRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSISCOMBI" +
"NING LIGATURE LEFT HALFCOMBINING LIGATURE RIGHT HALFCOMBINING DOUBLE TIL" +
"DE LEFT HALFCOMBINING DOUBLE TILDE RIGHT HALFCOMBINING MACRON LEFT HALFC" +
"OMBINING MACRON RIGHT HALFCOMBINING CONJOINING MACRONCOMBINING LIGATURE " +
"LEFT HALF BELOWCOMBINING LIGATURE RIGHT HALF BELOWCOMBINING TILDE LEFT H" +
"ALF BELOWCOMBINING TILDE RIGHT HALF BELOWCOMBINING MACRON LEFT HALF BELO") + ("" +
"WCOMBINING MACRON RIGHT HALF BELOWCOMBINING CONJOINING MACRON BELOWCOMBI" +
"NING CYRILLIC TITLO LEFT HALFCOMBINING CYRILLIC TITLO RIGHT HALFPRESENTA" +
"TION FORM FOR VERTICAL TWO DOT LEADERPRESENTATION FORM FOR VERTICAL EM D" +
"ASHPRESENTATION FORM FOR VERTICAL EN DASHPRESENTATION FORM FOR VERTICAL " +
"LOW LINEPRESENTATION FORM FOR VERTICAL WAVY LOW LINEPRESENTATION FORM FO" +
"R VERTICAL LEFT PARENTHESISPRESENTATION FORM FOR VERTICAL RIGHT PARENTHE" +
"SISPRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKETPRESENTATION FORM FO" +
"R VERTICAL RIGHT CURLY BRACKETPRESENTATION FORM FOR VERTICAL LEFT TORTOI" +
"SE SHELL BRACKETPRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRAC" +
"KETPRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKETPRESENTAT" +
"ION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKETPRESENTATION FORM FO" +
"R VERTICAL LEFT DOUBLE ANGLE BRACKETPRESENTATION FORM FOR VERTICAL RIGHT" +
" DOUBLE ANGLE BRACKETPRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKETPR" +
"ESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKETPRESENTATION FORM FOR VE" +
"RTICAL LEFT CORNER BRACKETPRESENTATION FORM FOR VERTICAL RIGHT CORNER BR" +
"ACKETPRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKETPRESENTATIO" +
"N FORM FOR VERTICAL RIGHT WHITE CORNER BRACKETSESAME DOTWHITE SESAME DOT" +
"PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKETPRESENTATION FORM FOR " +
"VERTICAL RIGHT SQUARE BRACKETDASHED OVERLINECENTRELINE OVERLINEWAVY OVER" +
"LINEDOUBLE WAVY OVERLINEDASHED LOW LINECENTRELINE LOW LINEWAVY LOW LINES" +
"MALL COMMASMALL IDEOGRAPHIC COMMASMALL FULL STOPSMALL SEMICOLONSMALL COL" +
"ONSMALL QUESTION MARKSMALL EXCLAMATION MARKSMALL EM DASHSMALL LEFT PAREN" +
"THESISSMALL RIGHT PARENTHESISSMALL LEFT CURLY BRACKETSMALL RIGHT CURLY B" +
"RACKETSMALL LEFT TORTOISE SHELL BRACKETSMALL RIGHT TORTOISE SHELL BRACKE" +
"TSMALL NUMBER SIGNSMALL AMPERSANDSMALL ASTERISKSMALL PLUS SIGNSMALL HYPH" +
"EN-MINUSSMALL LESS-THAN SIGNSMALL GREATER-THAN SIGNSMALL EQUALS SIGNSMAL" +
"L REVERSE SOLIDUSSMALL DOLLAR SIGNSMALL PERCENT SIGNSMALL COMMERCIAL ATA" +
"RABIC FATHATAN ISOLATED FORMARABIC TATWEEL WITH FATHATAN ABOVEARABIC DAM" +
"MATAN ISOLATED FORMARABIC TAIL FRAGMENTARABIC KASRATAN ISOLATED FORMARAB" +
"IC FATHA ISOLATED FORMARABIC FATHA MEDIAL FORMARABIC DAMMA ISOLATED FORM" +
"ARABIC DAMMA MEDIAL FORMARABIC KASRA ISOLATED FORMARABIC KASRA MEDIAL FO" +
"RMARABIC SHADDA ISOLATED FORMARABIC SHADDA MEDIAL FORMARABIC SUKUN ISOLA" +
"TED FORMARABIC SUKUN MEDIAL FORMARABIC LETTER HAMZA ISOLATED FORMARABIC " +
"LETTER ALEF WITH MADDA ABOVE ISOLATED FORMARABIC LETTER ALEF WITH MADDA " +
"ABOVE FINAL FORMARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORMARABIC " +
"LETTER ALEF WITH HAMZA ABOVE FINAL FORMARABIC LETTER WAW WITH HAMZA ABOV" +
"E ISOLATED FORMARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORMARABIC LETTE" +
"R ALEF WITH HAMZA BELOW ISOLATED FORMARABIC LETTER ALEF WITH HAMZA BELOW" +
" FINAL FORMARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORMARABIC LETTER" +
" YEH WITH HAMZA ABOVE FINAL FORMARABIC LETTER YEH WITH HAMZA ABOVE INITI" +
"AL FORMARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORMARABIC LETTER ALEF " +
"ISOLATED FORMARABIC LETTER ALEF FINAL FORMARABIC LETTER BEH ISOLATED FOR" +
"MARABIC LETTER BEH FINAL FORMARABIC LETTER BEH INITIAL FORMARABIC LETTER" +
" BEH MEDIAL FORMARABIC LETTER TEH MARBUTA ISOLATED FORMARABIC LETTER TEH" +
" MARBUTA FINAL FORMARABIC LETTER TEH ISOLATED FORMARABIC LETTER TEH FINA" +
"L FORMARABIC LETTER TEH INITIAL FORMARABIC LETTER TEH MEDIAL FORMARABIC " +
"LETTER THEH ISOLATED FORMARABIC LETTER THEH FINAL FORMARABIC LETTER THEH" +
" INITIAL FORMARABIC LETTER THEH MEDIAL FORMARABIC LETTER JEEM ISOLATED F" +
"ORMARABIC LETTER JEEM FINAL FORMARABIC LETTER JEEM INITIAL FORMARABIC LE" +
"TTER JEEM MEDIAL FORMARABIC LETTER HAH ISOLATED FORMARABIC LETTER HAH FI" +
"NAL FORMARABIC LETTER HAH INITIAL FORMARABIC LETTER HAH MEDIAL FORMARABI" +
"C LETTER KHAH ISOLATED FORMARABIC LETTER KHAH FINAL FORMARABIC LETTER KH" +
"AH INITIAL FORMARABIC LETTER KHAH MEDIAL FORMARABIC LETTER DAL ISOLATED " +
"FORMARABIC LETTER DAL FINAL FORMARABIC LETTER THAL ISOLATED FORMARABIC L" +
"ETTER THAL FINAL FORMARABIC LETTER REH ISOLATED FORMARABIC LETTER REH FI" +
"NAL FORMARABIC LETTER ZAIN ISOLATED FORMARABIC LETTER ZAIN FINAL FORMARA" +
"BIC LETTER SEEN ISOLATED FORMARABIC LETTER SEEN FINAL FORMARABIC LETTER " +
"SEEN INITIAL FORMARABIC LETTER SEEN MEDIAL FORMARABIC LETTER SHEEN ISOLA" +
"TED FORMARABIC LETTER SHEEN FINAL FORMARABIC LETTER SHEEN INITIAL FORMAR" +
"ABIC LETTER SHEEN MEDIAL FORMARABIC LETTER SAD ISOLATED FORMARABIC LETTE" +
"R SAD FINAL FORMARABIC LETTER SAD INITIAL FORMARABIC LETTER SAD MEDIAL F" +
"ORMARABIC LETTER DAD ISOLATED FORMARABIC LETTER DAD FINAL FORMARABIC LET" +
"TER DAD INITIAL FORMARABIC LETTER DAD MEDIAL FORMARABIC LETTER TAH ISOLA" +
"TED FORMARABIC LETTER TAH FINAL FORMARABIC LETTER TAH INITIAL FORMARABIC") + ("" +
" LETTER TAH MEDIAL FORMARABIC LETTER ZAH ISOLATED FORMARABIC LETTER ZAH " +
"FINAL FORMARABIC LETTER ZAH INITIAL FORMARABIC LETTER ZAH MEDIAL FORMARA" +
"BIC LETTER AIN ISOLATED FORMARABIC LETTER AIN FINAL FORMARABIC LETTER AI" +
"N INITIAL FORMARABIC LETTER AIN MEDIAL FORMARABIC LETTER GHAIN ISOLATED " +
"FORMARABIC LETTER GHAIN FINAL FORMARABIC LETTER GHAIN INITIAL FORMARABIC" +
" LETTER GHAIN MEDIAL FORMARABIC LETTER FEH ISOLATED FORMARABIC LETTER FE" +
"H FINAL FORMARABIC LETTER FEH INITIAL FORMARABIC LETTER FEH MEDIAL FORMA" +
"RABIC LETTER QAF ISOLATED FORMARABIC LETTER QAF FINAL FORMARABIC LETTER " +
"QAF INITIAL FORMARABIC LETTER QAF MEDIAL FORMARABIC LETTER KAF ISOLATED " +
"FORMARABIC LETTER KAF FINAL FORMARABIC LETTER KAF INITIAL FORMARABIC LET" +
"TER KAF MEDIAL FORMARABIC LETTER LAM ISOLATED FORMARABIC LETTER LAM FINA" +
"L FORMARABIC LETTER LAM INITIAL FORMARABIC LETTER LAM MEDIAL FORMARABIC " +
"LETTER MEEM ISOLATED FORMARABIC LETTER MEEM FINAL FORMARABIC LETTER MEEM" +
" INITIAL FORMARABIC LETTER MEEM MEDIAL FORMARABIC LETTER NOON ISOLATED F" +
"ORMARABIC LETTER NOON FINAL FORMARABIC LETTER NOON INITIAL FORMARABIC LE" +
"TTER NOON MEDIAL FORMARABIC LETTER HEH ISOLATED FORMARABIC LETTER HEH FI" +
"NAL FORMARABIC LETTER HEH INITIAL FORMARABIC LETTER HEH MEDIAL FORMARABI" +
"C LETTER WAW ISOLATED FORMARABIC LETTER WAW FINAL FORMARABIC LETTER ALEF" +
" MAKSURA ISOLATED FORMARABIC LETTER ALEF MAKSURA FINAL FORMARABIC LETTER" +
" YEH ISOLATED FORMARABIC LETTER YEH FINAL FORMARABIC LETTER YEH INITIAL " +
"FORMARABIC LETTER YEH MEDIAL FORMARABIC LIGATURE LAM WITH ALEF WITH MADD" +
"A ABOVE ISOLATED FORMARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINA" +
"L FORMARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORMARABIC" +
" LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORMARABIC LIGATURE LAM W" +
"ITH ALEF WITH HAMZA BELOW ISOLATED FORMARABIC LIGATURE LAM WITH ALEF WIT" +
"H HAMZA BELOW FINAL FORMARABIC LIGATURE LAM WITH ALEF ISOLATED FORMARABI" +
"C LIGATURE LAM WITH ALEF FINAL FORMZERO WIDTH NO-BREAK SPACEFULLWIDTH EX" +
"CLAMATION MARKFULLWIDTH QUOTATION MARKFULLWIDTH NUMBER SIGNFULLWIDTH DOL" +
"LAR SIGNFULLWIDTH PERCENT SIGNFULLWIDTH AMPERSANDFULLWIDTH APOSTROPHEFUL" +
"LWIDTH LEFT PARENTHESISFULLWIDTH RIGHT PARENTHESISFULLWIDTH ASTERISKFULL" +
"WIDTH PLUS SIGNFULLWIDTH COMMAFULLWIDTH HYPHEN-MINUSFULLWIDTH FULL STOPF" +
"ULLWIDTH SOLIDUSFULLWIDTH DIGIT ZEROFULLWIDTH DIGIT ONEFULLWIDTH DIGIT T" +
"WOFULLWIDTH DIGIT THREEFULLWIDTH DIGIT FOURFULLWIDTH DIGIT FIVEFULLWIDTH" +
" DIGIT SIXFULLWIDTH DIGIT SEVENFULLWIDTH DIGIT EIGHTFULLWIDTH DIGIT NINE" +
"FULLWIDTH COLONFULLWIDTH SEMICOLONFULLWIDTH LESS-THAN SIGNFULLWIDTH EQUA" +
"LS SIGNFULLWIDTH GREATER-THAN SIGNFULLWIDTH QUESTION MARKFULLWIDTH COMME" +
"RCIAL ATFULLWIDTH LATIN CAPITAL LETTER AFULLWIDTH LATIN CAPITAL LETTER B" +
"FULLWIDTH LATIN CAPITAL LETTER CFULLWIDTH LATIN CAPITAL LETTER DFULLWIDT" +
"H LATIN CAPITAL LETTER EFULLWIDTH LATIN CAPITAL LETTER FFULLWIDTH LATIN " +
"CAPITAL LETTER GFULLWIDTH LATIN CAPITAL LETTER HFULLWIDTH LATIN CAPITAL " +
"LETTER IFULLWIDTH LATIN CAPITAL LETTER JFULLWIDTH LATIN CAPITAL LETTER K" +
"FULLWIDTH LATIN CAPITAL LETTER LFULLWIDTH LATIN CAPITAL LETTER MFULLWIDT" +
"H LATIN CAPITAL LETTER NFULLWIDTH LATIN CAPITAL LETTER OFULLWIDTH LATIN " +
"CAPITAL LETTER PFULLWIDTH LATIN CAPITAL LETTER QFULLWIDTH LATIN CAPITAL " +
"LETTER RFULLWIDTH LATIN CAPITAL LETTER SFULLWIDTH LATIN CAPITAL LETTER T" +
"FULLWIDTH LATIN CAPITAL LETTER UFULLWIDTH LATIN CAPITAL LETTER VFULLWIDT" +
"H LATIN CAPITAL LETTER WFULLWIDTH LATIN CAPITAL LETTER XFULLWIDTH LATIN " +
"CAPITAL LETTER YFULLWIDTH LATIN CAPITAL LETTER ZFULLWIDTH LEFT SQUARE BR" +
"ACKETFULLWIDTH REVERSE SOLIDUSFULLWIDTH RIGHT SQUARE BRACKETFULLWIDTH CI" +
"RCUMFLEX ACCENTFULLWIDTH LOW LINEFULLWIDTH GRAVE ACCENTFULLWIDTH LATIN S" +
"MALL LETTER AFULLWIDTH LATIN SMALL LETTER BFULLWIDTH LATIN SMALL LETTER " +
"CFULLWIDTH LATIN SMALL LETTER DFULLWIDTH LATIN SMALL LETTER EFULLWIDTH L" +
"ATIN SMALL LETTER FFULLWIDTH LATIN SMALL LETTER GFULLWIDTH LATIN SMALL L" +
"ETTER HFULLWIDTH LATIN SMALL LETTER IFULLWIDTH LATIN SMALL LETTER JFULLW" +
"IDTH LATIN SMALL LETTER KFULLWIDTH LATIN SMALL LETTER LFULLWIDTH LATIN S" +
"MALL LETTER MFULLWIDTH LATIN SMALL LETTER NFULLWIDTH LATIN SMALL LETTER " +
"OFULLWIDTH LATIN SMALL LETTER PFULLWIDTH LATIN SMALL LETTER QFULLWIDTH L" +
"ATIN SMALL LETTER RFULLWIDTH LATIN SMALL LETTER SFULLWIDTH LATIN SMALL L" +
"ETTER TFULLWIDTH LATIN SMALL LETTER UFULLWIDTH LATIN SMALL LETTER VFULLW" +
"IDTH LATIN SMALL LETTER WFULLWIDTH LATIN SMALL LETTER XFULLWIDTH LATIN S" +
"MALL LETTER YFULLWIDTH LATIN SMALL LETTER ZFULLWIDTH LEFT CURLY BRACKETF" +
"ULLWIDTH VERTICAL LINEFULLWIDTH RIGHT CURLY BRACKETFULLWIDTH TILDEFULLWI" +
"DTH LEFT WHITE PARENTHESISFULLWIDTH RIGHT WHITE PARENTHESISHALFWIDTH IDE" +
"OGRAPHIC FULL STOPHALFWIDTH LEFT CORNER BRACKETHALFWIDTH RIGHT CORNER BR") + ("" +
"ACKETHALFWIDTH IDEOGRAPHIC COMMAHALFWIDTH KATAKANA MIDDLE DOTHALFWIDTH K" +
"ATAKANA LETTER WOHALFWIDTH KATAKANA LETTER SMALL AHALFWIDTH KATAKANA LET" +
"TER SMALL IHALFWIDTH KATAKANA LETTER SMALL UHALFWIDTH KATAKANA LETTER SM" +
"ALL EHALFWIDTH KATAKANA LETTER SMALL OHALFWIDTH KATAKANA LETTER SMALL YA" +
"HALFWIDTH KATAKANA LETTER SMALL YUHALFWIDTH KATAKANA LETTER SMALL YOHALF" +
"WIDTH KATAKANA LETTER SMALL TUHALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUN" +
"D MARKHALFWIDTH KATAKANA LETTER AHALFWIDTH KATAKANA LETTER IHALFWIDTH KA" +
"TAKANA LETTER UHALFWIDTH KATAKANA LETTER EHALFWIDTH KATAKANA LETTER OHAL" +
"FWIDTH KATAKANA LETTER KAHALFWIDTH KATAKANA LETTER KIHALFWIDTH KATAKANA " +
"LETTER KUHALFWIDTH KATAKANA LETTER KEHALFWIDTH KATAKANA LETTER KOHALFWID" +
"TH KATAKANA LETTER SAHALFWIDTH KATAKANA LETTER SIHALFWIDTH KATAKANA LETT" +
"ER SUHALFWIDTH KATAKANA LETTER SEHALFWIDTH KATAKANA LETTER SOHALFWIDTH K" +
"ATAKANA LETTER TAHALFWIDTH KATAKANA LETTER TIHALFWIDTH KATAKANA LETTER T" +
"UHALFWIDTH KATAKANA LETTER TEHALFWIDTH KATAKANA LETTER TOHALFWIDTH KATAK" +
"ANA LETTER NAHALFWIDTH KATAKANA LETTER NIHALFWIDTH KATAKANA LETTER NUHAL" +
"FWIDTH KATAKANA LETTER NEHALFWIDTH KATAKANA LETTER NOHALFWIDTH KATAKANA " +
"LETTER HAHALFWIDTH KATAKANA LETTER HIHALFWIDTH KATAKANA LETTER HUHALFWID" +
"TH KATAKANA LETTER HEHALFWIDTH KATAKANA LETTER HOHALFWIDTH KATAKANA LETT" +
"ER MAHALFWIDTH KATAKANA LETTER MIHALFWIDTH KATAKANA LETTER MUHALFWIDTH K" +
"ATAKANA LETTER MEHALFWIDTH KATAKANA LETTER MOHALFWIDTH KATAKANA LETTER Y" +
"AHALFWIDTH KATAKANA LETTER YUHALFWIDTH KATAKANA LETTER YOHALFWIDTH KATAK" +
"ANA LETTER RAHALFWIDTH KATAKANA LETTER RIHALFWIDTH KATAKANA LETTER RUHAL" +
"FWIDTH KATAKANA LETTER REHALFWIDTH KATAKANA LETTER ROHALFWIDTH KATAKANA " +
"LETTER WAHALFWIDTH KATAKANA LETTER NHALFWIDTH KATAKANA VOICED SOUND MARK" +
"HALFWIDTH KATAKANA SEMI-VOICED SOUND MARKHALFWIDTH HANGUL FILLERHALFWIDT" +
"H HANGUL LETTER KIYEOKHALFWIDTH HANGUL LETTER SSANGKIYEOKHALFWIDTH HANGU" +
"L LETTER KIYEOK-SIOSHALFWIDTH HANGUL LETTER NIEUNHALFWIDTH HANGUL LETTER" +
" NIEUN-CIEUCHALFWIDTH HANGUL LETTER NIEUN-HIEUHHALFWIDTH HANGUL LETTER T" +
"IKEUTHALFWIDTH HANGUL LETTER SSANGTIKEUTHALFWIDTH HANGUL LETTER RIEULHAL" +
"FWIDTH HANGUL LETTER RIEUL-KIYEOKHALFWIDTH HANGUL LETTER RIEUL-MIEUMHALF" +
"WIDTH HANGUL LETTER RIEUL-PIEUPHALFWIDTH HANGUL LETTER RIEUL-SIOSHALFWID" +
"TH HANGUL LETTER RIEUL-THIEUTHHALFWIDTH HANGUL LETTER RIEUL-PHIEUPHHALFW" +
"IDTH HANGUL LETTER RIEUL-HIEUHHALFWIDTH HANGUL LETTER MIEUMHALFWIDTH HAN" +
"GUL LETTER PIEUPHALFWIDTH HANGUL LETTER SSANGPIEUPHALFWIDTH HANGUL LETTE" +
"R PIEUP-SIOSHALFWIDTH HANGUL LETTER SIOSHALFWIDTH HANGUL LETTER SSANGSIO" +
"SHALFWIDTH HANGUL LETTER IEUNGHALFWIDTH HANGUL LETTER CIEUCHALFWIDTH HAN" +
"GUL LETTER SSANGCIEUCHALFWIDTH HANGUL LETTER CHIEUCHHALFWIDTH HANGUL LET" +
"TER KHIEUKHHALFWIDTH HANGUL LETTER THIEUTHHALFWIDTH HANGUL LETTER PHIEUP" +
"HHALFWIDTH HANGUL LETTER HIEUHHALFWIDTH HANGUL LETTER AHALFWIDTH HANGUL " +
"LETTER AEHALFWIDTH HANGUL LETTER YAHALFWIDTH HANGUL LETTER YAEHALFWIDTH " +
"HANGUL LETTER EOHALFWIDTH HANGUL LETTER EHALFWIDTH HANGUL LETTER YEOHALF" +
"WIDTH HANGUL LETTER YEHALFWIDTH HANGUL LETTER OHALFWIDTH HANGUL LETTER W" +
"AHALFWIDTH HANGUL LETTER WAEHALFWIDTH HANGUL LETTER OEHALFWIDTH HANGUL L" +
"ETTER YOHALFWIDTH HANGUL LETTER UHALFWIDTH HANGUL LETTER WEOHALFWIDTH HA" +
"NGUL LETTER WEHALFWIDTH HANGUL LETTER WIHALFWIDTH HANGUL LETTER YUHALFWI" +
"DTH HANGUL LETTER EUHALFWIDTH HANGUL LETTER YIHALFWIDTH HANGUL LETTER IF" +
"ULLWIDTH CENT SIGNFULLWIDTH POUND SIGNFULLWIDTH NOT SIGNFULLWIDTH MACRON" +
"FULLWIDTH BROKEN BARFULLWIDTH YEN SIGNFULLWIDTH WON SIGNHALFWIDTH FORMS " +
"LIGHT VERTICALHALFWIDTH LEFTWARDS ARROWHALFWIDTH UPWARDS ARROWHALFWIDTH " +
"RIGHTWARDS ARROWHALFWIDTH DOWNWARDS ARROWHALFWIDTH BLACK SQUAREHALFWIDTH" +
" WHITE CIRCLEINTERLINEAR ANNOTATION ANCHORINTERLINEAR ANNOTATION SEPARAT" +
"ORINTERLINEAR ANNOTATION TERMINATOROBJECT REPLACEMENT CHARACTERREPLACEME" +
"NT CHARACTERLINEAR B SYLLABLE B008 ALINEAR B SYLLABLE B038 ELINEAR B SYL" +
"LABLE B028 ILINEAR B SYLLABLE B061 OLINEAR B SYLLABLE B010 ULINEAR B SYL" +
"LABLE B001 DALINEAR B SYLLABLE B045 DELINEAR B SYLLABLE B007 DILINEAR B " +
"SYLLABLE B014 DOLINEAR B SYLLABLE B051 DULINEAR B SYLLABLE B057 JALINEAR" +
" B SYLLABLE B046 JELINEAR B SYLLABLE B036 JOLINEAR B SYLLABLE B065 JULIN" +
"EAR B SYLLABLE B077 KALINEAR B SYLLABLE B044 KELINEAR B SYLLABLE B067 KI" +
"LINEAR B SYLLABLE B070 KOLINEAR B SYLLABLE B081 KULINEAR B SYLLABLE B080" +
" MALINEAR B SYLLABLE B013 MELINEAR B SYLLABLE B073 MILINEAR B SYLLABLE B" +
"015 MOLINEAR B SYLLABLE B023 MULINEAR B SYLLABLE B006 NALINEAR B SYLLABL" +
"E B024 NELINEAR B SYLLABLE B030 NILINEAR B SYLLABLE B052 NOLINEAR B SYLL" +
"ABLE B055 NULINEAR B SYLLABLE B003 PALINEAR B SYLLABLE B072 PELINEAR B S" +
"YLLABLE B039 PILINEAR B SYLLABLE B011 POLINEAR B SYLLABLE B050 PULINEAR ") + ("" +
"B SYLLABLE B016 QALINEAR B SYLLABLE B078 QELINEAR B SYLLABLE B021 QILINE" +
"AR B SYLLABLE B032 QOLINEAR B SYLLABLE B060 RALINEAR B SYLLABLE B027 REL" +
"INEAR B SYLLABLE B053 RILINEAR B SYLLABLE B002 ROLINEAR B SYLLABLE B026 " +
"RULINEAR B SYLLABLE B031 SALINEAR B SYLLABLE B009 SELINEAR B SYLLABLE B0" +
"41 SILINEAR B SYLLABLE B012 SOLINEAR B SYLLABLE B058 SULINEAR B SYLLABLE" +
" B059 TALINEAR B SYLLABLE B004 TELINEAR B SYLLABLE B037 TILINEAR B SYLLA" +
"BLE B005 TOLINEAR B SYLLABLE B069 TULINEAR B SYLLABLE B054 WALINEAR B SY" +
"LLABLE B075 WELINEAR B SYLLABLE B040 WILINEAR B SYLLABLE B042 WOLINEAR B" +
" SYLLABLE B017 ZALINEAR B SYLLABLE B074 ZELINEAR B SYLLABLE B020 ZOLINEA" +
"R B SYLLABLE B025 A2LINEAR B SYLLABLE B043 A3LINEAR B SYLLABLE B085 AULI" +
"NEAR B SYLLABLE B071 DWELINEAR B SYLLABLE B090 DWOLINEAR B SYLLABLE B048" +
" NWALINEAR B SYLLABLE B029 PU2LINEAR B SYLLABLE B062 PTELINEAR B SYLLABL" +
"E B076 RA2LINEAR B SYLLABLE B033 RA3LINEAR B SYLLABLE B068 RO2LINEAR B S" +
"YLLABLE B066 TA2LINEAR B SYLLABLE B087 TWELINEAR B SYLLABLE B091 TWOLINE" +
"AR B SYMBOL B018LINEAR B SYMBOL B019LINEAR B SYMBOL B022LINEAR B SYMBOL " +
"B034LINEAR B SYMBOL B047LINEAR B SYMBOL B049LINEAR B SYMBOL B056LINEAR B" +
" SYMBOL B063LINEAR B SYMBOL B064LINEAR B SYMBOL B079LINEAR B SYMBOL B082" +
"LINEAR B SYMBOL B083LINEAR B SYMBOL B086LINEAR B SYMBOL B089LINEAR B IDE" +
"OGRAM B100 MANLINEAR B IDEOGRAM B102 WOMANLINEAR B IDEOGRAM B104 DEERLIN" +
"EAR B IDEOGRAM B105 EQUIDLINEAR B IDEOGRAM B105F MARELINEAR B IDEOGRAM B" +
"105M STALLIONLINEAR B IDEOGRAM B106F EWELINEAR B IDEOGRAM B106M RAMLINEA" +
"R B IDEOGRAM B107F SHE-GOATLINEAR B IDEOGRAM B107M HE-GOATLINEAR B IDEOG" +
"RAM B108F SOWLINEAR B IDEOGRAM B108M BOARLINEAR B IDEOGRAM B109F COWLINE" +
"AR B IDEOGRAM B109M BULLLINEAR B IDEOGRAM B120 WHEATLINEAR B IDEOGRAM B1" +
"21 BARLEYLINEAR B IDEOGRAM B122 OLIVELINEAR B IDEOGRAM B123 SPICELINEAR " +
"B IDEOGRAM B125 CYPERUSLINEAR B MONOGRAM B127 KAPOLINEAR B MONOGRAM B128" +
" KANAKOLINEAR B IDEOGRAM B130 OILLINEAR B IDEOGRAM B131 WINELINEAR B IDE" +
"OGRAM B132LINEAR B MONOGRAM B133 AREPALINEAR B MONOGRAM B135 MERILINEAR " +
"B IDEOGRAM B140 BRONZELINEAR B IDEOGRAM B141 GOLDLINEAR B IDEOGRAM B142L" +
"INEAR B IDEOGRAM B145 WOOLLINEAR B IDEOGRAM B146LINEAR B IDEOGRAM B150LI" +
"NEAR B IDEOGRAM B151 HORNLINEAR B IDEOGRAM B152LINEAR B IDEOGRAM B153LIN" +
"EAR B IDEOGRAM B154LINEAR B MONOGRAM B156 TURO2LINEAR B IDEOGRAM B157LIN" +
"EAR B IDEOGRAM B158LINEAR B IDEOGRAM B159 CLOTHLINEAR B IDEOGRAM B160LIN" +
"EAR B IDEOGRAM B161LINEAR B IDEOGRAM B162 GARMENTLINEAR B IDEOGRAM B163 " +
"ARMOURLINEAR B IDEOGRAM B164LINEAR B IDEOGRAM B165LINEAR B IDEOGRAM B166" +
"LINEAR B IDEOGRAM B167LINEAR B IDEOGRAM B168LINEAR B IDEOGRAM B169LINEAR" +
" B IDEOGRAM B170LINEAR B IDEOGRAM B171LINEAR B IDEOGRAM B172LINEAR B IDE" +
"OGRAM B173 MONTHLINEAR B IDEOGRAM B174LINEAR B IDEOGRAM B176 TREELINEAR " +
"B IDEOGRAM B177LINEAR B IDEOGRAM B178LINEAR B IDEOGRAM B179LINEAR B IDEO" +
"GRAM B180LINEAR B IDEOGRAM B181LINEAR B IDEOGRAM B182LINEAR B IDEOGRAM B" +
"183LINEAR B IDEOGRAM B184LINEAR B IDEOGRAM B185LINEAR B IDEOGRAM B189LIN" +
"EAR B IDEOGRAM B190LINEAR B IDEOGRAM B191 HELMETLINEAR B IDEOGRAM B220 F" +
"OOTSTOOLLINEAR B IDEOGRAM B225 BATHTUBLINEAR B IDEOGRAM B230 SPEARLINEAR" +
" B IDEOGRAM B231 ARROWLINEAR B IDEOGRAM B232LINEAR B IDEOGRAM B233 SWORD" +
"LINEAR B IDEOGRAM B234LINEAR B IDEOGRAM B236LINEAR B IDEOGRAM B240 WHEEL" +
"ED CHARIOTLINEAR B IDEOGRAM B241 CHARIOTLINEAR B IDEOGRAM B242 CHARIOT F" +
"RAMELINEAR B IDEOGRAM B243 WHEELLINEAR B IDEOGRAM B245LINEAR B IDEOGRAM " +
"B246LINEAR B MONOGRAM B247 DIPTELINEAR B IDEOGRAM B248LINEAR B IDEOGRAM " +
"B249LINEAR B IDEOGRAM B251LINEAR B IDEOGRAM B252LINEAR B IDEOGRAM B253LI" +
"NEAR B IDEOGRAM B254 DARTLINEAR B IDEOGRAM B255LINEAR B IDEOGRAM B256LIN" +
"EAR B IDEOGRAM B257LINEAR B IDEOGRAM B258LINEAR B IDEOGRAM B259LINEAR B " +
"IDEOGRAM VESSEL B155LINEAR B IDEOGRAM VESSEL B200LINEAR B IDEOGRAM VESSE" +
"L B201LINEAR B IDEOGRAM VESSEL B202LINEAR B IDEOGRAM VESSEL B203LINEAR B" +
" IDEOGRAM VESSEL B204LINEAR B IDEOGRAM VESSEL B205LINEAR B IDEOGRAM VESS" +
"EL B206LINEAR B IDEOGRAM VESSEL B207LINEAR B IDEOGRAM VESSEL B208LINEAR " +
"B IDEOGRAM VESSEL B209LINEAR B IDEOGRAM VESSEL B210LINEAR B IDEOGRAM VES" +
"SEL B211LINEAR B IDEOGRAM VESSEL B212LINEAR B IDEOGRAM VESSEL B213LINEAR" +
" B IDEOGRAM VESSEL B214LINEAR B IDEOGRAM VESSEL B215LINEAR B IDEOGRAM VE" +
"SSEL B216LINEAR B IDEOGRAM VESSEL B217LINEAR B IDEOGRAM VESSEL B218LINEA" +
"R B IDEOGRAM VESSEL B219LINEAR B IDEOGRAM VESSEL B221LINEAR B IDEOGRAM V" +
"ESSEL B222LINEAR B IDEOGRAM VESSEL B226LINEAR B IDEOGRAM VESSEL B227LINE" +
"AR B IDEOGRAM VESSEL B228LINEAR B IDEOGRAM VESSEL B229LINEAR B IDEOGRAM " +
"VESSEL B250LINEAR B IDEOGRAM VESSEL B305AEGEAN WORD SEPARATOR LINEAEGEAN" +
" WORD SEPARATOR DOTAEGEAN CHECK MARKAEGEAN NUMBER ONEAEGEAN NUMBER TWOAE") + ("" +
"GEAN NUMBER THREEAEGEAN NUMBER FOURAEGEAN NUMBER FIVEAEGEAN NUMBER SIXAE" +
"GEAN NUMBER SEVENAEGEAN NUMBER EIGHTAEGEAN NUMBER NINEAEGEAN NUMBER TENA" +
"EGEAN NUMBER TWENTYAEGEAN NUMBER THIRTYAEGEAN NUMBER FORTYAEGEAN NUMBER " +
"FIFTYAEGEAN NUMBER SIXTYAEGEAN NUMBER SEVENTYAEGEAN NUMBER EIGHTYAEGEAN " +
"NUMBER NINETYAEGEAN NUMBER ONE HUNDREDAEGEAN NUMBER TWO HUNDREDAEGEAN NU" +
"MBER THREE HUNDREDAEGEAN NUMBER FOUR HUNDREDAEGEAN NUMBER FIVE HUNDREDAE" +
"GEAN NUMBER SIX HUNDREDAEGEAN NUMBER SEVEN HUNDREDAEGEAN NUMBER EIGHT HU" +
"NDREDAEGEAN NUMBER NINE HUNDREDAEGEAN NUMBER ONE THOUSANDAEGEAN NUMBER T" +
"WO THOUSANDAEGEAN NUMBER THREE THOUSANDAEGEAN NUMBER FOUR THOUSANDAEGEAN" +
" NUMBER FIVE THOUSANDAEGEAN NUMBER SIX THOUSANDAEGEAN NUMBER SEVEN THOUS" +
"ANDAEGEAN NUMBER EIGHT THOUSANDAEGEAN NUMBER NINE THOUSANDAEGEAN NUMBER " +
"TEN THOUSANDAEGEAN NUMBER TWENTY THOUSANDAEGEAN NUMBER THIRTY THOUSANDAE" +
"GEAN NUMBER FORTY THOUSANDAEGEAN NUMBER FIFTY THOUSANDAEGEAN NUMBER SIXT" +
"Y THOUSANDAEGEAN NUMBER SEVENTY THOUSANDAEGEAN NUMBER EIGHTY THOUSANDAEG" +
"EAN NUMBER NINETY THOUSANDAEGEAN WEIGHT BASE UNITAEGEAN WEIGHT FIRST SUB" +
"UNITAEGEAN WEIGHT SECOND SUBUNITAEGEAN WEIGHT THIRD SUBUNITAEGEAN WEIGHT" +
" FOURTH SUBUNITAEGEAN DRY MEASURE FIRST SUBUNITAEGEAN LIQUID MEASURE FIR" +
"ST SUBUNITAEGEAN MEASURE SECOND SUBUNITAEGEAN MEASURE THIRD SUBUNITGREEK" +
" ACROPHONIC ATTIC ONE QUARTERGREEK ACROPHONIC ATTIC ONE HALFGREEK ACROPH" +
"ONIC ATTIC ONE DRACHMAGREEK ACROPHONIC ATTIC FIVEGREEK ACROPHONIC ATTIC " +
"FIFTYGREEK ACROPHONIC ATTIC FIVE HUNDREDGREEK ACROPHONIC ATTIC FIVE THOU" +
"SANDGREEK ACROPHONIC ATTIC FIFTY THOUSANDGREEK ACROPHONIC ATTIC FIVE TAL" +
"ENTSGREEK ACROPHONIC ATTIC TEN TALENTSGREEK ACROPHONIC ATTIC FIFTY TALEN" +
"TSGREEK ACROPHONIC ATTIC ONE HUNDRED TALENTSGREEK ACROPHONIC ATTIC FIVE " +
"HUNDRED TALENTSGREEK ACROPHONIC ATTIC ONE THOUSAND TALENTSGREEK ACROPHON" +
"IC ATTIC FIVE THOUSAND TALENTSGREEK ACROPHONIC ATTIC FIVE STATERSGREEK A" +
"CROPHONIC ATTIC TEN STATERSGREEK ACROPHONIC ATTIC FIFTY STATERSGREEK ACR" +
"OPHONIC ATTIC ONE HUNDRED STATERSGREEK ACROPHONIC ATTIC FIVE HUNDRED STA" +
"TERSGREEK ACROPHONIC ATTIC ONE THOUSAND STATERSGREEK ACROPHONIC ATTIC TE" +
"N THOUSAND STATERSGREEK ACROPHONIC ATTIC FIFTY THOUSAND STATERSGREEK ACR" +
"OPHONIC ATTIC TEN MNASGREEK ACROPHONIC HERAEUM ONE PLETHRONGREEK ACROPHO" +
"NIC THESPIAN ONEGREEK ACROPHONIC HERMIONIAN ONEGREEK ACROPHONIC EPIDAURE" +
"AN TWOGREEK ACROPHONIC THESPIAN TWOGREEK ACROPHONIC CYRENAIC TWO DRACHMA" +
"SGREEK ACROPHONIC EPIDAUREAN TWO DRACHMASGREEK ACROPHONIC TROEZENIAN FIV" +
"EGREEK ACROPHONIC TROEZENIAN TENGREEK ACROPHONIC TROEZENIAN TEN ALTERNAT" +
"E FORMGREEK ACROPHONIC HERMIONIAN TENGREEK ACROPHONIC MESSENIAN TENGREEK" +
" ACROPHONIC THESPIAN TENGREEK ACROPHONIC THESPIAN THIRTYGREEK ACROPHONIC" +
" TROEZENIAN FIFTYGREEK ACROPHONIC TROEZENIAN FIFTY ALTERNATE FORMGREEK A" +
"CROPHONIC HERMIONIAN FIFTYGREEK ACROPHONIC THESPIAN FIFTYGREEK ACROPHONI" +
"C THESPIAN ONE HUNDREDGREEK ACROPHONIC THESPIAN THREE HUNDREDGREEK ACROP" +
"HONIC EPIDAUREAN FIVE HUNDREDGREEK ACROPHONIC TROEZENIAN FIVE HUNDREDGRE" +
"EK ACROPHONIC THESPIAN FIVE HUNDREDGREEK ACROPHONIC CARYSTIAN FIVE HUNDR" +
"EDGREEK ACROPHONIC NAXIAN FIVE HUNDREDGREEK ACROPHONIC THESPIAN ONE THOU" +
"SANDGREEK ACROPHONIC THESPIAN FIVE THOUSANDGREEK ACROPHONIC DELPHIC FIVE" +
" MNASGREEK ACROPHONIC STRATIAN FIFTY MNASGREEK ONE HALF SIGNGREEK ONE HA" +
"LF SIGN ALTERNATE FORMGREEK TWO THIRDS SIGNGREEK THREE QUARTERS SIGNGREE" +
"K YEAR SIGNGREEK TALENT SIGNGREEK DRACHMA SIGNGREEK OBOL SIGNGREEK TWO O" +
"BOLS SIGNGREEK THREE OBOLS SIGNGREEK FOUR OBOLS SIGNGREEK FIVE OBOLS SIG" +
"NGREEK METRETES SIGNGREEK KYATHOS BASE SIGNGREEK LITRA SIGNGREEK OUNKIA " +
"SIGNGREEK XESTES SIGNGREEK ARTABE SIGNGREEK AROURA SIGNGREEK GRAMMA SIGN" +
"GREEK TRYBLION BASE SIGNGREEK ZERO SIGNGREEK ONE QUARTER SIGNGREEK SINUS" +
"OID SIGNGREEK INDICTION SIGNNOMISMA SIGNROMAN SEXTANS SIGNROMAN UNCIA SI" +
"GNROMAN SEMUNCIA SIGNROMAN SEXTULA SIGNROMAN DIMIDIA SEXTULA SIGNROMAN S" +
"ILIQUA SIGNROMAN DENARIUS SIGNROMAN QUINARIUS SIGNROMAN SESTERTIUS SIGNR" +
"OMAN DUPONDIUS SIGNROMAN AS SIGNROMAN CENTURIAL SIGNASCIA SYMBOLGREEK SY" +
"MBOL TAU RHOPHAISTOS DISC SIGN PEDESTRIANPHAISTOS DISC SIGN PLUMED HEADP" +
"HAISTOS DISC SIGN TATTOOED HEADPHAISTOS DISC SIGN CAPTIVEPHAISTOS DISC S" +
"IGN CHILDPHAISTOS DISC SIGN WOMANPHAISTOS DISC SIGN HELMETPHAISTOS DISC " +
"SIGN GAUNTLETPHAISTOS DISC SIGN TIARAPHAISTOS DISC SIGN ARROWPHAISTOS DI" +
"SC SIGN BOWPHAISTOS DISC SIGN SHIELDPHAISTOS DISC SIGN CLUBPHAISTOS DISC" +
" SIGN MANACLESPHAISTOS DISC SIGN MATTOCKPHAISTOS DISC SIGN SAWPHAISTOS D" +
"ISC SIGN LIDPHAISTOS DISC SIGN BOOMERANGPHAISTOS DISC SIGN CARPENTRY PLA" +
"NEPHAISTOS DISC SIGN DOLIUMPHAISTOS DISC SIGN COMBPHAISTOS DISC SIGN SLI" +
"NGPHAISTOS DISC SIGN COLUMNPHAISTOS DISC SIGN BEEHIVEPHAISTOS DISC SIGN ") + ("" +
"SHIPPHAISTOS DISC SIGN HORNPHAISTOS DISC SIGN HIDEPHAISTOS DISC SIGN BUL" +
"LS LEGPHAISTOS DISC SIGN CATPHAISTOS DISC SIGN RAMPHAISTOS DISC SIGN EAG" +
"LEPHAISTOS DISC SIGN DOVEPHAISTOS DISC SIGN TUNNYPHAISTOS DISC SIGN BEEP" +
"HAISTOS DISC SIGN PLANE TREEPHAISTOS DISC SIGN VINEPHAISTOS DISC SIGN PA" +
"PYRUSPHAISTOS DISC SIGN ROSETTEPHAISTOS DISC SIGN LILYPHAISTOS DISC SIGN" +
" OX BACKPHAISTOS DISC SIGN FLUTEPHAISTOS DISC SIGN GRATERPHAISTOS DISC S" +
"IGN STRAINERPHAISTOS DISC SIGN SMALL AXEPHAISTOS DISC SIGN WAVY BANDPHAI" +
"STOS DISC SIGN COMBINING OBLIQUE STROKELYCIAN LETTER ALYCIAN LETTER ELYC" +
"IAN LETTER BLYCIAN LETTER BHLYCIAN LETTER GLYCIAN LETTER DLYCIAN LETTER " +
"ILYCIAN LETTER WLYCIAN LETTER ZLYCIAN LETTER THLYCIAN LETTER JLYCIAN LET" +
"TER KLYCIAN LETTER QLYCIAN LETTER LLYCIAN LETTER MLYCIAN LETTER NLYCIAN " +
"LETTER MMLYCIAN LETTER NNLYCIAN LETTER ULYCIAN LETTER PLYCIAN LETTER KKL" +
"YCIAN LETTER RLYCIAN LETTER SLYCIAN LETTER TLYCIAN LETTER TTLYCIAN LETTE" +
"R ANLYCIAN LETTER ENLYCIAN LETTER HLYCIAN LETTER XCARIAN LETTER ACARIAN " +
"LETTER P2CARIAN LETTER DCARIAN LETTER LCARIAN LETTER UUUCARIAN LETTER RC" +
"ARIAN LETTER LDCARIAN LETTER A2CARIAN LETTER QCARIAN LETTER BCARIAN LETT" +
"ER MCARIAN LETTER OCARIAN LETTER D2CARIAN LETTER TCARIAN LETTER SHCARIAN" +
" LETTER SH2CARIAN LETTER SCARIAN LETTER C-18CARIAN LETTER UCARIAN LETTER" +
" NNCARIAN LETTER XCARIAN LETTER NCARIAN LETTER TT2CARIAN LETTER PCARIAN " +
"LETTER SSCARIAN LETTER ICARIAN LETTER ECARIAN LETTER UUUUCARIAN LETTER K" +
"CARIAN LETTER K2CARIAN LETTER NDCARIAN LETTER UUCARIAN LETTER GCARIAN LE" +
"TTER G2CARIAN LETTER STCARIAN LETTER ST2CARIAN LETTER NGCARIAN LETTER II" +
"CARIAN LETTER C-39CARIAN LETTER TTCARIAN LETTER UUU2CARIAN LETTER RRCARI" +
"AN LETTER MBCARIAN LETTER MB2CARIAN LETTER MB3CARIAN LETTER MB4CARIAN LE" +
"TTER LD2CARIAN LETTER E2CARIAN LETTER UUU3COPTIC EPACT THOUSANDS MARKCOP" +
"TIC EPACT DIGIT ONECOPTIC EPACT DIGIT TWOCOPTIC EPACT DIGIT THREECOPTIC " +
"EPACT DIGIT FOURCOPTIC EPACT DIGIT FIVECOPTIC EPACT DIGIT SIXCOPTIC EPAC" +
"T DIGIT SEVENCOPTIC EPACT DIGIT EIGHTCOPTIC EPACT DIGIT NINECOPTIC EPACT" +
" NUMBER TENCOPTIC EPACT NUMBER TWENTYCOPTIC EPACT NUMBER THIRTYCOPTIC EP" +
"ACT NUMBER FORTYCOPTIC EPACT NUMBER FIFTYCOPTIC EPACT NUMBER SIXTYCOPTIC" +
" EPACT NUMBER SEVENTYCOPTIC EPACT NUMBER EIGHTYCOPTIC EPACT NUMBER NINET" +
"YCOPTIC EPACT NUMBER ONE HUNDREDCOPTIC EPACT NUMBER TWO HUNDREDCOPTIC EP" +
"ACT NUMBER THREE HUNDREDCOPTIC EPACT NUMBER FOUR HUNDREDCOPTIC EPACT NUM" +
"BER FIVE HUNDREDCOPTIC EPACT NUMBER SIX HUNDREDCOPTIC EPACT NUMBER SEVEN" +
" HUNDREDCOPTIC EPACT NUMBER EIGHT HUNDREDCOPTIC EPACT NUMBER NINE HUNDRE" +
"DOLD ITALIC LETTER AOLD ITALIC LETTER BEOLD ITALIC LETTER KEOLD ITALIC L" +
"ETTER DEOLD ITALIC LETTER EOLD ITALIC LETTER VEOLD ITALIC LETTER ZEOLD I" +
"TALIC LETTER HEOLD ITALIC LETTER THEOLD ITALIC LETTER IOLD ITALIC LETTER" +
" KAOLD ITALIC LETTER ELOLD ITALIC LETTER EMOLD ITALIC LETTER ENOLD ITALI" +
"C LETTER ESHOLD ITALIC LETTER OOLD ITALIC LETTER PEOLD ITALIC LETTER SHE" +
"OLD ITALIC LETTER KUOLD ITALIC LETTER EROLD ITALIC LETTER ESOLD ITALIC L" +
"ETTER TEOLD ITALIC LETTER UOLD ITALIC LETTER EKSOLD ITALIC LETTER PHEOLD" +
" ITALIC LETTER KHEOLD ITALIC LETTER EFOLD ITALIC LETTER ERSOLD ITALIC LE" +
"TTER CHEOLD ITALIC LETTER IIOLD ITALIC LETTER UUOLD ITALIC LETTER ESSOLD" +
" ITALIC NUMERAL ONEOLD ITALIC NUMERAL FIVEOLD ITALIC NUMERAL TENOLD ITAL" +
"IC NUMERAL FIFTYOLD ITALIC LETTER YEOLD ITALIC LETTER NORTHERN TSEOLD IT" +
"ALIC LETTER SOUTHERN TSEGOTHIC LETTER AHSAGOTHIC LETTER BAIRKANGOTHIC LE" +
"TTER GIBAGOTHIC LETTER DAGSGOTHIC LETTER AIHVUSGOTHIC LETTER QAIRTHRAGOT" +
"HIC LETTER IUJAGOTHIC LETTER HAGLGOTHIC LETTER THIUTHGOTHIC LETTER EISGO" +
"THIC LETTER KUSMAGOTHIC LETTER LAGUSGOTHIC LETTER MANNAGOTHIC LETTER NAU" +
"THSGOTHIC LETTER JERGOTHIC LETTER URUSGOTHIC LETTER PAIRTHRAGOTHIC LETTE" +
"R NINETYGOTHIC LETTER RAIDAGOTHIC LETTER SAUILGOTHIC LETTER TEIWSGOTHIC " +
"LETTER WINJAGOTHIC LETTER FAIHUGOTHIC LETTER IGGWSGOTHIC LETTER HWAIRGOT" +
"HIC LETTER OTHALGOTHIC LETTER NINE HUNDREDOLD PERMIC LETTER ANOLD PERMIC" +
" LETTER BUROLD PERMIC LETTER GAIOLD PERMIC LETTER DOIOLD PERMIC LETTER E" +
"OLD PERMIC LETTER ZHOIOLD PERMIC LETTER DZHOIOLD PERMIC LETTER ZATAOLD P" +
"ERMIC LETTER DZITAOLD PERMIC LETTER IOLD PERMIC LETTER KOKEOLD PERMIC LE" +
"TTER LEIOLD PERMIC LETTER MENOEOLD PERMIC LETTER NENOEOLD PERMIC LETTER " +
"VOOIOLD PERMIC LETTER PEEIOLD PERMIC LETTER REIOLD PERMIC LETTER SIIOLD " +
"PERMIC LETTER TAIOLD PERMIC LETTER UOLD PERMIC LETTER CHERYOLD PERMIC LE" +
"TTER SHOOIOLD PERMIC LETTER SHCHOOIOLD PERMIC LETTER YRYOLD PERMIC LETTE" +
"R YERUOLD PERMIC LETTER OOLD PERMIC LETTER OOOLD PERMIC LETTER EFOLD PER" +
"MIC LETTER HAOLD PERMIC LETTER TSIUOLD PERMIC LETTER VEROLD PERMIC LETTE" +
"R YEROLD PERMIC LETTER YERIOLD PERMIC LETTER YATOLD PERMIC LETTER IEOLD ") + ("" +
"PERMIC LETTER YUOLD PERMIC LETTER YAOLD PERMIC LETTER IACOMBINING OLD PE" +
"RMIC LETTER ANCOMBINING OLD PERMIC LETTER DOICOMBINING OLD PERMIC LETTER" +
" ZATACOMBINING OLD PERMIC LETTER NENOECOMBINING OLD PERMIC LETTER SIIUGA" +
"RITIC LETTER ALPAUGARITIC LETTER BETAUGARITIC LETTER GAMLAUGARITIC LETTE" +
"R KHAUGARITIC LETTER DELTAUGARITIC LETTER HOUGARITIC LETTER WOUGARITIC L" +
"ETTER ZETAUGARITIC LETTER HOTAUGARITIC LETTER TETUGARITIC LETTER YODUGAR" +
"ITIC LETTER KAFUGARITIC LETTER SHINUGARITIC LETTER LAMDAUGARITIC LETTER " +
"MEMUGARITIC LETTER DHALUGARITIC LETTER NUNUGARITIC LETTER ZUUGARITIC LET" +
"TER SAMKAUGARITIC LETTER AINUGARITIC LETTER PUUGARITIC LETTER SADEUGARIT" +
"IC LETTER QOPAUGARITIC LETTER RASHAUGARITIC LETTER THANNAUGARITIC LETTER" +
" GHAINUGARITIC LETTER TOUGARITIC LETTER IUGARITIC LETTER UUGARITIC LETTE" +
"R SSUUGARITIC WORD DIVIDEROLD PERSIAN SIGN AOLD PERSIAN SIGN IOLD PERSIA" +
"N SIGN UOLD PERSIAN SIGN KAOLD PERSIAN SIGN KUOLD PERSIAN SIGN GAOLD PER" +
"SIAN SIGN GUOLD PERSIAN SIGN XAOLD PERSIAN SIGN CAOLD PERSIAN SIGN JAOLD" +
" PERSIAN SIGN JIOLD PERSIAN SIGN TAOLD PERSIAN SIGN TUOLD PERSIAN SIGN D" +
"AOLD PERSIAN SIGN DIOLD PERSIAN SIGN DUOLD PERSIAN SIGN THAOLD PERSIAN S" +
"IGN PAOLD PERSIAN SIGN BAOLD PERSIAN SIGN FAOLD PERSIAN SIGN NAOLD PERSI" +
"AN SIGN NUOLD PERSIAN SIGN MAOLD PERSIAN SIGN MIOLD PERSIAN SIGN MUOLD P" +
"ERSIAN SIGN YAOLD PERSIAN SIGN VAOLD PERSIAN SIGN VIOLD PERSIAN SIGN RAO" +
"LD PERSIAN SIGN RUOLD PERSIAN SIGN LAOLD PERSIAN SIGN SAOLD PERSIAN SIGN" +
" ZAOLD PERSIAN SIGN SHAOLD PERSIAN SIGN SSAOLD PERSIAN SIGN HAOLD PERSIA" +
"N SIGN AURAMAZDAAOLD PERSIAN SIGN AURAMAZDAA-2OLD PERSIAN SIGN AURAMAZDA" +
"AHAOLD PERSIAN SIGN XSHAAYATHIYAOLD PERSIAN SIGN DAHYAAUSHOLD PERSIAN SI" +
"GN DAHYAAUSH-2OLD PERSIAN SIGN BAGAOLD PERSIAN SIGN BUUMISHOLD PERSIAN W" +
"ORD DIVIDEROLD PERSIAN NUMBER ONEOLD PERSIAN NUMBER TWOOLD PERSIAN NUMBE" +
"R TENOLD PERSIAN NUMBER TWENTYOLD PERSIAN NUMBER HUNDREDDESERET CAPITAL " +
"LETTER LONG IDESERET CAPITAL LETTER LONG EDESERET CAPITAL LETTER LONG AD" +
"ESERET CAPITAL LETTER LONG AHDESERET CAPITAL LETTER LONG ODESERET CAPITA" +
"L LETTER LONG OODESERET CAPITAL LETTER SHORT IDESERET CAPITAL LETTER SHO" +
"RT EDESERET CAPITAL LETTER SHORT ADESERET CAPITAL LETTER SHORT AHDESERET" +
" CAPITAL LETTER SHORT ODESERET CAPITAL LETTER SHORT OODESERET CAPITAL LE" +
"TTER AYDESERET CAPITAL LETTER OWDESERET CAPITAL LETTER WUDESERET CAPITAL" +
" LETTER YEEDESERET CAPITAL LETTER HDESERET CAPITAL LETTER PEEDESERET CAP" +
"ITAL LETTER BEEDESERET CAPITAL LETTER TEEDESERET CAPITAL LETTER DEEDESER" +
"ET CAPITAL LETTER CHEEDESERET CAPITAL LETTER JEEDESERET CAPITAL LETTER K" +
"AYDESERET CAPITAL LETTER GAYDESERET CAPITAL LETTER EFDESERET CAPITAL LET" +
"TER VEEDESERET CAPITAL LETTER ETHDESERET CAPITAL LETTER THEEDESERET CAPI" +
"TAL LETTER ESDESERET CAPITAL LETTER ZEEDESERET CAPITAL LETTER ESHDESERET" +
" CAPITAL LETTER ZHEEDESERET CAPITAL LETTER ERDESERET CAPITAL LETTER ELDE" +
"SERET CAPITAL LETTER EMDESERET CAPITAL LETTER ENDESERET CAPITAL LETTER E" +
"NGDESERET CAPITAL LETTER OIDESERET CAPITAL LETTER EWDESERET SMALL LETTER" +
" LONG IDESERET SMALL LETTER LONG EDESERET SMALL LETTER LONG ADESERET SMA" +
"LL LETTER LONG AHDESERET SMALL LETTER LONG ODESERET SMALL LETTER LONG OO" +
"DESERET SMALL LETTER SHORT IDESERET SMALL LETTER SHORT EDESERET SMALL LE" +
"TTER SHORT ADESERET SMALL LETTER SHORT AHDESERET SMALL LETTER SHORT ODES" +
"ERET SMALL LETTER SHORT OODESERET SMALL LETTER AYDESERET SMALL LETTER OW" +
"DESERET SMALL LETTER WUDESERET SMALL LETTER YEEDESERET SMALL LETTER HDES" +
"ERET SMALL LETTER PEEDESERET SMALL LETTER BEEDESERET SMALL LETTER TEEDES" +
"ERET SMALL LETTER DEEDESERET SMALL LETTER CHEEDESERET SMALL LETTER JEEDE" +
"SERET SMALL LETTER KAYDESERET SMALL LETTER GAYDESERET SMALL LETTER EFDES" +
"ERET SMALL LETTER VEEDESERET SMALL LETTER ETHDESERET SMALL LETTER THEEDE" +
"SERET SMALL LETTER ESDESERET SMALL LETTER ZEEDESERET SMALL LETTER ESHDES" +
"ERET SMALL LETTER ZHEEDESERET SMALL LETTER ERDESERET SMALL LETTER ELDESE" +
"RET SMALL LETTER EMDESERET SMALL LETTER ENDESERET SMALL LETTER ENGDESERE" +
"T SMALL LETTER OIDESERET SMALL LETTER EWSHAVIAN LETTER PEEPSHAVIAN LETTE" +
"R TOTSHAVIAN LETTER KICKSHAVIAN LETTER FEESHAVIAN LETTER THIGHSHAVIAN LE" +
"TTER SOSHAVIAN LETTER SURESHAVIAN LETTER CHURCHSHAVIAN LETTER YEASHAVIAN" +
" LETTER HUNGSHAVIAN LETTER BIBSHAVIAN LETTER DEADSHAVIAN LETTER GAGSHAVI" +
"AN LETTER VOWSHAVIAN LETTER THEYSHAVIAN LETTER ZOOSHAVIAN LETTER MEASURE" +
"SHAVIAN LETTER JUDGESHAVIAN LETTER WOESHAVIAN LETTER HA-HASHAVIAN LETTER" +
" LOLLSHAVIAN LETTER MIMESHAVIAN LETTER IFSHAVIAN LETTER EGGSHAVIAN LETTE" +
"R ASHSHAVIAN LETTER ADOSHAVIAN LETTER ONSHAVIAN LETTER WOOLSHAVIAN LETTE" +
"R OUTSHAVIAN LETTER AHSHAVIAN LETTER ROARSHAVIAN LETTER NUNSHAVIAN LETTE" +
"R EATSHAVIAN LETTER AGESHAVIAN LETTER ICESHAVIAN LETTER UPSHAVIAN LETTER") + ("" +
" OAKSHAVIAN LETTER OOZESHAVIAN LETTER OILSHAVIAN LETTER AWESHAVIAN LETTE" +
"R ARESHAVIAN LETTER ORSHAVIAN LETTER AIRSHAVIAN LETTER ERRSHAVIAN LETTER" +
" ARRAYSHAVIAN LETTER EARSHAVIAN LETTER IANSHAVIAN LETTER YEWOSMANYA LETT" +
"ER ALEFOSMANYA LETTER BAOSMANYA LETTER TAOSMANYA LETTER JAOSMANYA LETTER" +
" XAOSMANYA LETTER KHAOSMANYA LETTER DEELOSMANYA LETTER RAOSMANYA LETTER " +
"SAOSMANYA LETTER SHIINOSMANYA LETTER DHAOSMANYA LETTER CAYNOSMANYA LETTE" +
"R GAOSMANYA LETTER FAOSMANYA LETTER QAAFOSMANYA LETTER KAAFOSMANYA LETTE" +
"R LAANOSMANYA LETTER MIINOSMANYA LETTER NUUNOSMANYA LETTER WAWOSMANYA LE" +
"TTER HAOSMANYA LETTER YAOSMANYA LETTER AOSMANYA LETTER EOSMANYA LETTER I" +
"OSMANYA LETTER OOSMANYA LETTER UOSMANYA LETTER AAOSMANYA LETTER EEOSMANY" +
"A LETTER OOOSMANYA DIGIT ZEROOSMANYA DIGIT ONEOSMANYA DIGIT TWOOSMANYA D" +
"IGIT THREEOSMANYA DIGIT FOUROSMANYA DIGIT FIVEOSMANYA DIGIT SIXOSMANYA D" +
"IGIT SEVENOSMANYA DIGIT EIGHTOSMANYA DIGIT NINEOSAGE CAPITAL LETTER AOSA" +
"GE CAPITAL LETTER AIOSAGE CAPITAL LETTER AINOSAGE CAPITAL LETTER AHOSAGE" +
" CAPITAL LETTER BRAOSAGE CAPITAL LETTER CHAOSAGE CAPITAL LETTER EHCHAOSA" +
"GE CAPITAL LETTER EOSAGE CAPITAL LETTER EINOSAGE CAPITAL LETTER HAOSAGE " +
"CAPITAL LETTER HYAOSAGE CAPITAL LETTER IOSAGE CAPITAL LETTER KAOSAGE CAP" +
"ITAL LETTER EHKAOSAGE CAPITAL LETTER KYAOSAGE CAPITAL LETTER LAOSAGE CAP" +
"ITAL LETTER MAOSAGE CAPITAL LETTER NAOSAGE CAPITAL LETTER OOSAGE CAPITAL" +
" LETTER OINOSAGE CAPITAL LETTER PAOSAGE CAPITAL LETTER EHPAOSAGE CAPITAL" +
" LETTER SAOSAGE CAPITAL LETTER SHAOSAGE CAPITAL LETTER TAOSAGE CAPITAL L" +
"ETTER EHTAOSAGE CAPITAL LETTER TSAOSAGE CAPITAL LETTER EHTSAOSAGE CAPITA" +
"L LETTER TSHAOSAGE CAPITAL LETTER DHAOSAGE CAPITAL LETTER UOSAGE CAPITAL" +
" LETTER WAOSAGE CAPITAL LETTER KHAOSAGE CAPITAL LETTER GHAOSAGE CAPITAL " +
"LETTER ZAOSAGE CAPITAL LETTER ZHAOSAGE SMALL LETTER AOSAGE SMALL LETTER " +
"AIOSAGE SMALL LETTER AINOSAGE SMALL LETTER AHOSAGE SMALL LETTER BRAOSAGE" +
" SMALL LETTER CHAOSAGE SMALL LETTER EHCHAOSAGE SMALL LETTER EOSAGE SMALL" +
" LETTER EINOSAGE SMALL LETTER HAOSAGE SMALL LETTER HYAOSAGE SMALL LETTER" +
" IOSAGE SMALL LETTER KAOSAGE SMALL LETTER EHKAOSAGE SMALL LETTER KYAOSAG" +
"E SMALL LETTER LAOSAGE SMALL LETTER MAOSAGE SMALL LETTER NAOSAGE SMALL L" +
"ETTER OOSAGE SMALL LETTER OINOSAGE SMALL LETTER PAOSAGE SMALL LETTER EHP" +
"AOSAGE SMALL LETTER SAOSAGE SMALL LETTER SHAOSAGE SMALL LETTER TAOSAGE S" +
"MALL LETTER EHTAOSAGE SMALL LETTER TSAOSAGE SMALL LETTER EHTSAOSAGE SMAL" +
"L LETTER TSHAOSAGE SMALL LETTER DHAOSAGE SMALL LETTER UOSAGE SMALL LETTE" +
"R WAOSAGE SMALL LETTER KHAOSAGE SMALL LETTER GHAOSAGE SMALL LETTER ZAOSA" +
"GE SMALL LETTER ZHAELBASAN LETTER AELBASAN LETTER BEELBASAN LETTER CEELB" +
"ASAN LETTER CHEELBASAN LETTER DEELBASAN LETTER NDEELBASAN LETTER DHEELBA" +
"SAN LETTER EIELBASAN LETTER EELBASAN LETTER FEELBASAN LETTER GEELBASAN L" +
"ETTER GJEELBASAN LETTER HEELBASAN LETTER IELBASAN LETTER JEELBASAN LETTE" +
"R KEELBASAN LETTER LEELBASAN LETTER LLEELBASAN LETTER MEELBASAN LETTER N" +
"EELBASAN LETTER NAELBASAN LETTER NJEELBASAN LETTER OELBASAN LETTER PEELB" +
"ASAN LETTER QEELBASAN LETTER REELBASAN LETTER RREELBASAN LETTER SEELBASA" +
"N LETTER SHEELBASAN LETTER TEELBASAN LETTER THEELBASAN LETTER UELBASAN L" +
"ETTER VEELBASAN LETTER XEELBASAN LETTER YELBASAN LETTER ZEELBASAN LETTER" +
" ZHEELBASAN LETTER GHEELBASAN LETTER GHAMMAELBASAN LETTER KHECAUCASIAN A" +
"LBANIAN LETTER ALTCAUCASIAN ALBANIAN LETTER BETCAUCASIAN ALBANIAN LETTER" +
" GIMCAUCASIAN ALBANIAN LETTER DATCAUCASIAN ALBANIAN LETTER EBCAUCASIAN A" +
"LBANIAN LETTER ZARLCAUCASIAN ALBANIAN LETTER EYNCAUCASIAN ALBANIAN LETTE" +
"R ZHILCAUCASIAN ALBANIAN LETTER TASCAUCASIAN ALBANIAN LETTER CHACAUCASIA" +
"N ALBANIAN LETTER YOWDCAUCASIAN ALBANIAN LETTER ZHACAUCASIAN ALBANIAN LE" +
"TTER IRBCAUCASIAN ALBANIAN LETTER SHACAUCASIAN ALBANIAN LETTER LANCAUCAS" +
"IAN ALBANIAN LETTER INYACAUCASIAN ALBANIAN LETTER XEYNCAUCASIAN ALBANIAN" +
" LETTER DYANCAUCASIAN ALBANIAN LETTER CARCAUCASIAN ALBANIAN LETTER JHOXC" +
"AUCASIAN ALBANIAN LETTER KARCAUCASIAN ALBANIAN LETTER LYITCAUCASIAN ALBA" +
"NIAN LETTER HEYTCAUCASIAN ALBANIAN LETTER QAYCAUCASIAN ALBANIAN LETTER A" +
"ORCAUCASIAN ALBANIAN LETTER CHOYCAUCASIAN ALBANIAN LETTER CHICAUCASIAN A" +
"LBANIAN LETTER CYAYCAUCASIAN ALBANIAN LETTER MAQCAUCASIAN ALBANIAN LETTE" +
"R QARCAUCASIAN ALBANIAN LETTER NOWCCAUCASIAN ALBANIAN LETTER DZYAYCAUCAS" +
"IAN ALBANIAN LETTER SHAKCAUCASIAN ALBANIAN LETTER JAYNCAUCASIAN ALBANIAN" +
" LETTER ONCAUCASIAN ALBANIAN LETTER TYAYCAUCASIAN ALBANIAN LETTER FAMCAU" +
"CASIAN ALBANIAN LETTER DZAYCAUCASIAN ALBANIAN LETTER CHATCAUCASIAN ALBAN" +
"IAN LETTER PENCAUCASIAN ALBANIAN LETTER GHEYSCAUCASIAN ALBANIAN LETTER R" +
"ATCAUCASIAN ALBANIAN LETTER SEYKCAUCASIAN ALBANIAN LETTER VEYZCAUCASIAN " +
"ALBANIAN LETTER TIWRCAUCASIAN ALBANIAN LETTER SHOYCAUCASIAN ALBANIAN LET") + ("" +
"TER IWNCAUCASIAN ALBANIAN LETTER CYAWCAUCASIAN ALBANIAN LETTER CAYNCAUCA" +
"SIAN ALBANIAN LETTER YAYDCAUCASIAN ALBANIAN LETTER PIWRCAUCASIAN ALBANIA" +
"N LETTER KIWCAUCASIAN ALBANIAN CITATION MARKVITHKUQI CAPITAL LETTER AVIT" +
"HKUQI CAPITAL LETTER BBEVITHKUQI CAPITAL LETTER BEVITHKUQI CAPITAL LETTE" +
"R CEVITHKUQI CAPITAL LETTER CHEVITHKUQI CAPITAL LETTER DEVITHKUQI CAPITA" +
"L LETTER DHEVITHKUQI CAPITAL LETTER EIVITHKUQI CAPITAL LETTER EVITHKUQI " +
"CAPITAL LETTER FEVITHKUQI CAPITAL LETTER GAVITHKUQI CAPITAL LETTER HAVIT" +
"HKUQI CAPITAL LETTER HHAVITHKUQI CAPITAL LETTER IVITHKUQI CAPITAL LETTER" +
" IJEVITHKUQI CAPITAL LETTER JEVITHKUQI CAPITAL LETTER KAVITHKUQI CAPITAL" +
" LETTER LAVITHKUQI CAPITAL LETTER LLAVITHKUQI CAPITAL LETTER MEVITHKUQI " +
"CAPITAL LETTER NEVITHKUQI CAPITAL LETTER NJEVITHKUQI CAPITAL LETTER OVIT" +
"HKUQI CAPITAL LETTER PEVITHKUQI CAPITAL LETTER QAVITHKUQI CAPITAL LETTER" +
" REVITHKUQI CAPITAL LETTER SEVITHKUQI CAPITAL LETTER SHEVITHKUQI CAPITAL" +
" LETTER TEVITHKUQI CAPITAL LETTER THEVITHKUQI CAPITAL LETTER UVITHKUQI C" +
"APITAL LETTER VEVITHKUQI CAPITAL LETTER XEVITHKUQI CAPITAL LETTER YVITHK" +
"UQI CAPITAL LETTER ZEVITHKUQI SMALL LETTER AVITHKUQI SMALL LETTER BBEVIT" +
"HKUQI SMALL LETTER BEVITHKUQI SMALL LETTER CEVITHKUQI SMALL LETTER CHEVI" +
"THKUQI SMALL LETTER DEVITHKUQI SMALL LETTER DHEVITHKUQI SMALL LETTER EIV" +
"ITHKUQI SMALL LETTER EVITHKUQI SMALL LETTER FEVITHKUQI SMALL LETTER GAVI" +
"THKUQI SMALL LETTER HAVITHKUQI SMALL LETTER HHAVITHKUQI SMALL LETTER IVI" +
"THKUQI SMALL LETTER IJEVITHKUQI SMALL LETTER JEVITHKUQI SMALL LETTER KAV" +
"ITHKUQI SMALL LETTER LAVITHKUQI SMALL LETTER LLAVITHKUQI SMALL LETTER ME" +
"VITHKUQI SMALL LETTER NEVITHKUQI SMALL LETTER NJEVITHKUQI SMALL LETTER O" +
"VITHKUQI SMALL LETTER PEVITHKUQI SMALL LETTER QAVITHKUQI SMALL LETTER RE" +
"VITHKUQI SMALL LETTER SEVITHKUQI SMALL LETTER SHEVITHKUQI SMALL LETTER T" +
"EVITHKUQI SMALL LETTER THEVITHKUQI SMALL LETTER UVITHKUQI SMALL LETTER V" +
"EVITHKUQI SMALL LETTER XEVITHKUQI SMALL LETTER YVITHKUQI SMALL LETTER ZE" +
"LINEAR A SIGN AB001LINEAR A SIGN AB002LINEAR A SIGN AB003LINEAR A SIGN A" +
"B004LINEAR A SIGN AB005LINEAR A SIGN AB006LINEAR A SIGN AB007LINEAR A SI" +
"GN AB008LINEAR A SIGN AB009LINEAR A SIGN AB010LINEAR A SIGN AB011LINEAR " +
"A SIGN AB013LINEAR A SIGN AB016LINEAR A SIGN AB017LINEAR A SIGN AB020LIN" +
"EAR A SIGN AB021LINEAR A SIGN AB021FLINEAR A SIGN AB021MLINEAR A SIGN AB" +
"022LINEAR A SIGN AB022FLINEAR A SIGN AB022MLINEAR A SIGN AB023LINEAR A S" +
"IGN AB023MLINEAR A SIGN AB024LINEAR A SIGN AB026LINEAR A SIGN AB027LINEA" +
"R A SIGN AB028LINEAR A SIGN A028BLINEAR A SIGN AB029LINEAR A SIGN AB030L" +
"INEAR A SIGN AB031LINEAR A SIGN AB034LINEAR A SIGN AB037LINEAR A SIGN AB" +
"038LINEAR A SIGN AB039LINEAR A SIGN AB040LINEAR A SIGN AB041LINEAR A SIG" +
"N AB044LINEAR A SIGN AB045LINEAR A SIGN AB046LINEAR A SIGN AB047LINEAR A" +
" SIGN AB048LINEAR A SIGN AB049LINEAR A SIGN AB050LINEAR A SIGN AB051LINE" +
"AR A SIGN AB053LINEAR A SIGN AB054LINEAR A SIGN AB055LINEAR A SIGN AB056" +
"LINEAR A SIGN AB057LINEAR A SIGN AB058LINEAR A SIGN AB059LINEAR A SIGN A" +
"B060LINEAR A SIGN AB061LINEAR A SIGN AB065LINEAR A SIGN AB066LINEAR A SI" +
"GN AB067LINEAR A SIGN AB069LINEAR A SIGN AB070LINEAR A SIGN AB073LINEAR " +
"A SIGN AB074LINEAR A SIGN AB076LINEAR A SIGN AB077LINEAR A SIGN AB078LIN" +
"EAR A SIGN AB079LINEAR A SIGN AB080LINEAR A SIGN AB081LINEAR A SIGN AB08" +
"2LINEAR A SIGN AB085LINEAR A SIGN AB086LINEAR A SIGN AB087LINEAR A SIGN " +
"A100-102LINEAR A SIGN AB118LINEAR A SIGN AB120LINEAR A SIGN A120BLINEAR " +
"A SIGN AB122LINEAR A SIGN AB123LINEAR A SIGN AB131ALINEAR A SIGN AB131BL" +
"INEAR A SIGN A131CLINEAR A SIGN AB164LINEAR A SIGN AB171LINEAR A SIGN AB" +
"180LINEAR A SIGN AB188LINEAR A SIGN AB191LINEAR A SIGN A301LINEAR A SIGN" +
" A302LINEAR A SIGN A303LINEAR A SIGN A304LINEAR A SIGN A305LINEAR A SIGN" +
" A306LINEAR A SIGN A307LINEAR A SIGN A308LINEAR A SIGN A309ALINEAR A SIG" +
"N A309BLINEAR A SIGN A309CLINEAR A SIGN A310LINEAR A SIGN A311LINEAR A S" +
"IGN A312LINEAR A SIGN A313ALINEAR A SIGN A313BLINEAR A SIGN A313CLINEAR " +
"A SIGN A314LINEAR A SIGN A315LINEAR A SIGN A316LINEAR A SIGN A317LINEAR " +
"A SIGN A318LINEAR A SIGN A319LINEAR A SIGN A320LINEAR A SIGN A321LINEAR " +
"A SIGN A322LINEAR A SIGN A323LINEAR A SIGN A324LINEAR A SIGN A325LINEAR " +
"A SIGN A326LINEAR A SIGN A327LINEAR A SIGN A328LINEAR A SIGN A329LINEAR " +
"A SIGN A330LINEAR A SIGN A331LINEAR A SIGN A332LINEAR A SIGN A333LINEAR " +
"A SIGN A334LINEAR A SIGN A335LINEAR A SIGN A336LINEAR A SIGN A337LINEAR " +
"A SIGN A338LINEAR A SIGN A339LINEAR A SIGN A340LINEAR A SIGN A341LINEAR " +
"A SIGN A342LINEAR A SIGN A343LINEAR A SIGN A344LINEAR A SIGN A345LINEAR " +
"A SIGN A346LINEAR A SIGN A347LINEAR A SIGN A348LINEAR A SIGN A349LINEAR " +
"A SIGN A350LINEAR A SIGN A351LINEAR A SIGN A352LINEAR A SIGN A353LINEAR ") + ("" +
"A SIGN A354LINEAR A SIGN A355LINEAR A SIGN A356LINEAR A SIGN A357LINEAR " +
"A SIGN A358LINEAR A SIGN A359LINEAR A SIGN A360LINEAR A SIGN A361LINEAR " +
"A SIGN A362LINEAR A SIGN A363LINEAR A SIGN A364LINEAR A SIGN A365LINEAR " +
"A SIGN A366LINEAR A SIGN A367LINEAR A SIGN A368LINEAR A SIGN A369LINEAR " +
"A SIGN A370LINEAR A SIGN A371LINEAR A SIGN A400-VASLINEAR A SIGN A401-VA" +
"SLINEAR A SIGN A402-VASLINEAR A SIGN A403-VASLINEAR A SIGN A404-VASLINEA" +
"R A SIGN A405-VASLINEAR A SIGN A406-VASLINEAR A SIGN A407-VASLINEAR A SI" +
"GN A408-VASLINEAR A SIGN A409-VASLINEAR A SIGN A410-VASLINEAR A SIGN A41" +
"1-VASLINEAR A SIGN A412-VASLINEAR A SIGN A413-VASLINEAR A SIGN A414-VASL" +
"INEAR A SIGN A415-VASLINEAR A SIGN A416-VASLINEAR A SIGN A417-VASLINEAR " +
"A SIGN A418-VASLINEAR A SIGN A501LINEAR A SIGN A502LINEAR A SIGN A503LIN" +
"EAR A SIGN A504LINEAR A SIGN A505LINEAR A SIGN A506LINEAR A SIGN A508LIN" +
"EAR A SIGN A509LINEAR A SIGN A510LINEAR A SIGN A511LINEAR A SIGN A512LIN" +
"EAR A SIGN A513LINEAR A SIGN A515LINEAR A SIGN A516LINEAR A SIGN A520LIN" +
"EAR A SIGN A521LINEAR A SIGN A523LINEAR A SIGN A524LINEAR A SIGN A525LIN" +
"EAR A SIGN A526LINEAR A SIGN A527LINEAR A SIGN A528LINEAR A SIGN A529LIN" +
"EAR A SIGN A530LINEAR A SIGN A531LINEAR A SIGN A532LINEAR A SIGN A534LIN" +
"EAR A SIGN A535LINEAR A SIGN A536LINEAR A SIGN A537LINEAR A SIGN A538LIN" +
"EAR A SIGN A539LINEAR A SIGN A540LINEAR A SIGN A541LINEAR A SIGN A542LIN" +
"EAR A SIGN A545LINEAR A SIGN A547LINEAR A SIGN A548LINEAR A SIGN A549LIN" +
"EAR A SIGN A550LINEAR A SIGN A551LINEAR A SIGN A552LINEAR A SIGN A553LIN" +
"EAR A SIGN A554LINEAR A SIGN A555LINEAR A SIGN A556LINEAR A SIGN A557LIN" +
"EAR A SIGN A559LINEAR A SIGN A563LINEAR A SIGN A564LINEAR A SIGN A565LIN" +
"EAR A SIGN A566LINEAR A SIGN A568LINEAR A SIGN A569LINEAR A SIGN A570LIN" +
"EAR A SIGN A571LINEAR A SIGN A572LINEAR A SIGN A573LINEAR A SIGN A574LIN" +
"EAR A SIGN A575LINEAR A SIGN A576LINEAR A SIGN A577LINEAR A SIGN A578LIN" +
"EAR A SIGN A579LINEAR A SIGN A580LINEAR A SIGN A581LINEAR A SIGN A582LIN" +
"EAR A SIGN A583LINEAR A SIGN A584LINEAR A SIGN A585LINEAR A SIGN A586LIN" +
"EAR A SIGN A587LINEAR A SIGN A588LINEAR A SIGN A589LINEAR A SIGN A591LIN" +
"EAR A SIGN A592LINEAR A SIGN A594LINEAR A SIGN A595LINEAR A SIGN A596LIN" +
"EAR A SIGN A598LINEAR A SIGN A600LINEAR A SIGN A601LINEAR A SIGN A602LIN" +
"EAR A SIGN A603LINEAR A SIGN A604LINEAR A SIGN A606LINEAR A SIGN A608LIN" +
"EAR A SIGN A609LINEAR A SIGN A610LINEAR A SIGN A611LINEAR A SIGN A612LIN" +
"EAR A SIGN A613LINEAR A SIGN A614LINEAR A SIGN A615LINEAR A SIGN A616LIN" +
"EAR A SIGN A617LINEAR A SIGN A618LINEAR A SIGN A619LINEAR A SIGN A620LIN" +
"EAR A SIGN A621LINEAR A SIGN A622LINEAR A SIGN A623LINEAR A SIGN A624LIN" +
"EAR A SIGN A626LINEAR A SIGN A627LINEAR A SIGN A628LINEAR A SIGN A629LIN" +
"EAR A SIGN A634LINEAR A SIGN A637LINEAR A SIGN A638LINEAR A SIGN A640LIN" +
"EAR A SIGN A642LINEAR A SIGN A643LINEAR A SIGN A644LINEAR A SIGN A645LIN" +
"EAR A SIGN A646LINEAR A SIGN A648LINEAR A SIGN A649LINEAR A SIGN A651LIN" +
"EAR A SIGN A652LINEAR A SIGN A653LINEAR A SIGN A654LINEAR A SIGN A655LIN" +
"EAR A SIGN A656LINEAR A SIGN A657LINEAR A SIGN A658LINEAR A SIGN A659LIN" +
"EAR A SIGN A660LINEAR A SIGN A661LINEAR A SIGN A662LINEAR A SIGN A663LIN" +
"EAR A SIGN A664LINEAR A SIGN A701 ALINEAR A SIGN A702 BLINEAR A SIGN A70" +
"3 DLINEAR A SIGN A704 ELINEAR A SIGN A705 FLINEAR A SIGN A706 HLINEAR A " +
"SIGN A707 JLINEAR A SIGN A708 KLINEAR A SIGN A709 LLINEAR A SIGN A709-2 " +
"L2LINEAR A SIGN A709-3 L3LINEAR A SIGN A709-4 L4LINEAR A SIGN A709-6 L6L" +
"INEAR A SIGN A710 WLINEAR A SIGN A711 XLINEAR A SIGN A712 YLINEAR A SIGN" +
" A713 OMEGALINEAR A SIGN A714 ABBLINEAR A SIGN A715 BBLINEAR A SIGN A717" +
" DDLINEAR A SIGN A726 EYYYLINEAR A SIGN A732 JELINEAR A SIGN A800LINEAR " +
"A SIGN A801LINEAR A SIGN A802LINEAR A SIGN A803LINEAR A SIGN A804LINEAR " +
"A SIGN A805LINEAR A SIGN A806LINEAR A SIGN A807MODIFIER LETTER SMALL CAP" +
"ITAL AAMODIFIER LETTER SUPERSCRIPT TRIANGULAR COLONMODIFIER LETTER SUPER" +
"SCRIPT HALF TRIANGULAR COLONMODIFIER LETTER SMALL AEMODIFIER LETTER SMAL" +
"L CAPITAL BMODIFIER LETTER SMALL B WITH HOOKMODIFIER LETTER SMALL DZ DIG" +
"RAPHMODIFIER LETTER SMALL DZ DIGRAPH WITH RETROFLEX HOOKMODIFIER LETTER " +
"SMALL DZ DIGRAPH WITH CURLMODIFIER LETTER SMALL DEZH DIGRAPHMODIFIER LET" +
"TER SMALL D WITH TAILMODIFIER LETTER SMALL D WITH HOOKMODIFIER LETTER SM" +
"ALL D WITH HOOK AND TAILMODIFIER LETTER SMALL REVERSED EMODIFIER LETTER " +
"SMALL CLOSED REVERSED OPEN EMODIFIER LETTER SMALL FENG DIGRAPHMODIFIER L" +
"ETTER SMALL RAMS HORNMODIFIER LETTER SMALL CAPITAL GMODIFIER LETTER SMAL" +
"L G WITH HOOKMODIFIER LETTER SMALL CAPITAL G WITH HOOKMODIFIER LETTER SM" +
"ALL H WITH STROKEMODIFIER LETTER SMALL CAPITAL HMODIFIER LETTER SMALL HE" +
"NG WITH HOOKMODIFIER LETTER SMALL DOTLESS J WITH STROKE AND HOOKMODIFIER") + ("" +
" LETTER SMALL LS DIGRAPHMODIFIER LETTER SMALL LZ DIGRAPHMODIFIER LETTER " +
"SMALL L WITH BELTMODIFIER LETTER SMALL CAPITAL L WITH BELTMODIFIER LETTE" +
"R SMALL L WITH RETROFLEX HOOK AND BELTMODIFIER LETTER SMALL LEZHMODIFIER" +
" LETTER SMALL LEZH WITH RETROFLEX HOOKMODIFIER LETTER SMALL TURNED YMODI" +
"FIER LETTER SMALL TURNED Y WITH BELTMODIFIER LETTER SMALL O WITH STROKEM" +
"ODIFIER LETTER SMALL CAPITAL OEMODIFIER LETTER SMALL CLOSED OMEGAMODIFIE" +
"R LETTER SMALL QMODIFIER LETTER SMALL TURNED R WITH LONG LEGMODIFIER LET" +
"TER SMALL TURNED R WITH LONG LEG AND RETROFLEX HOOKMODIFIER LETTER SMALL" +
" R WITH TAILMODIFIER LETTER SMALL R WITH FISHHOOKMODIFIER LETTER SMALL C" +
"APITAL RMODIFIER LETTER SMALL TC DIGRAPH WITH CURLMODIFIER LETTER SMALL " +
"TS DIGRAPHMODIFIER LETTER SMALL TS DIGRAPH WITH RETROFLEX HOOKMODIFIER L" +
"ETTER SMALL TESH DIGRAPHMODIFIER LETTER SMALL T WITH RETROFLEX HOOKMODIF" +
"IER LETTER SMALL V WITH RIGHT HOOKMODIFIER LETTER SMALL CAPITAL YMODIFIE" +
"R LETTER GLOTTAL STOP WITH STROKEMODIFIER LETTER REVERSED GLOTTAL STOP W" +
"ITH STROKEMODIFIER LETTER BILABIAL CLICKMODIFIER LETTER DENTAL CLICKMODI" +
"FIER LETTER LATERAL CLICKMODIFIER LETTER ALVEOLAR CLICKMODIFIER LETTER R" +
"ETROFLEX CLICK WITH RETROFLEX HOOKMODIFIER LETTER SMALL S WITH CURLCYPRI" +
"OT SYLLABLE ACYPRIOT SYLLABLE ECYPRIOT SYLLABLE ICYPRIOT SYLLABLE OCYPRI" +
"OT SYLLABLE UCYPRIOT SYLLABLE JACYPRIOT SYLLABLE JOCYPRIOT SYLLABLE KACY" +
"PRIOT SYLLABLE KECYPRIOT SYLLABLE KICYPRIOT SYLLABLE KOCYPRIOT SYLLABLE " +
"KUCYPRIOT SYLLABLE LACYPRIOT SYLLABLE LECYPRIOT SYLLABLE LICYPRIOT SYLLA" +
"BLE LOCYPRIOT SYLLABLE LUCYPRIOT SYLLABLE MACYPRIOT SYLLABLE MECYPRIOT S" +
"YLLABLE MICYPRIOT SYLLABLE MOCYPRIOT SYLLABLE MUCYPRIOT SYLLABLE NACYPRI" +
"OT SYLLABLE NECYPRIOT SYLLABLE NICYPRIOT SYLLABLE NOCYPRIOT SYLLABLE NUC" +
"YPRIOT SYLLABLE PACYPRIOT SYLLABLE PECYPRIOT SYLLABLE PICYPRIOT SYLLABLE" +
" POCYPRIOT SYLLABLE PUCYPRIOT SYLLABLE RACYPRIOT SYLLABLE RECYPRIOT SYLL" +
"ABLE RICYPRIOT SYLLABLE ROCYPRIOT SYLLABLE RUCYPRIOT SYLLABLE SACYPRIOT " +
"SYLLABLE SECYPRIOT SYLLABLE SICYPRIOT SYLLABLE SOCYPRIOT SYLLABLE SUCYPR" +
"IOT SYLLABLE TACYPRIOT SYLLABLE TECYPRIOT SYLLABLE TICYPRIOT SYLLABLE TO" +
"CYPRIOT SYLLABLE TUCYPRIOT SYLLABLE WACYPRIOT SYLLABLE WECYPRIOT SYLLABL" +
"E WICYPRIOT SYLLABLE WOCYPRIOT SYLLABLE XACYPRIOT SYLLABLE XECYPRIOT SYL" +
"LABLE ZACYPRIOT SYLLABLE ZOIMPERIAL ARAMAIC LETTER ALEPHIMPERIAL ARAMAIC" +
" LETTER BETHIMPERIAL ARAMAIC LETTER GIMELIMPERIAL ARAMAIC LETTER DALETHI" +
"MPERIAL ARAMAIC LETTER HEIMPERIAL ARAMAIC LETTER WAWIMPERIAL ARAMAIC LET" +
"TER ZAYINIMPERIAL ARAMAIC LETTER HETHIMPERIAL ARAMAIC LETTER TETHIMPERIA" +
"L ARAMAIC LETTER YODHIMPERIAL ARAMAIC LETTER KAPHIMPERIAL ARAMAIC LETTER" +
" LAMEDHIMPERIAL ARAMAIC LETTER MEMIMPERIAL ARAMAIC LETTER NUNIMPERIAL AR" +
"AMAIC LETTER SAMEKHIMPERIAL ARAMAIC LETTER AYINIMPERIAL ARAMAIC LETTER P" +
"EIMPERIAL ARAMAIC LETTER SADHEIMPERIAL ARAMAIC LETTER QOPHIMPERIAL ARAMA" +
"IC LETTER RESHIMPERIAL ARAMAIC LETTER SHINIMPERIAL ARAMAIC LETTER TAWIMP" +
"ERIAL ARAMAIC SECTION SIGNIMPERIAL ARAMAIC NUMBER ONEIMPERIAL ARAMAIC NU" +
"MBER TWOIMPERIAL ARAMAIC NUMBER THREEIMPERIAL ARAMAIC NUMBER TENIMPERIAL" +
" ARAMAIC NUMBER TWENTYIMPERIAL ARAMAIC NUMBER ONE HUNDREDIMPERIAL ARAMAI" +
"C NUMBER ONE THOUSANDIMPERIAL ARAMAIC NUMBER TEN THOUSANDPALMYRENE LETTE" +
"R ALEPHPALMYRENE LETTER BETHPALMYRENE LETTER GIMELPALMYRENE LETTER DALET" +
"HPALMYRENE LETTER HEPALMYRENE LETTER WAWPALMYRENE LETTER ZAYINPALMYRENE " +
"LETTER HETHPALMYRENE LETTER TETHPALMYRENE LETTER YODHPALMYRENE LETTER KA" +
"PHPALMYRENE LETTER LAMEDHPALMYRENE LETTER MEMPALMYRENE LETTER FINAL NUNP" +
"ALMYRENE LETTER NUNPALMYRENE LETTER SAMEKHPALMYRENE LETTER AYINPALMYRENE" +
" LETTER PEPALMYRENE LETTER SADHEPALMYRENE LETTER QOPHPALMYRENE LETTER RE" +
"SHPALMYRENE LETTER SHINPALMYRENE LETTER TAWPALMYRENE LEFT-POINTING FLEUR" +
"ONPALMYRENE RIGHT-POINTING FLEURONPALMYRENE NUMBER ONEPALMYRENE NUMBER T" +
"WOPALMYRENE NUMBER THREEPALMYRENE NUMBER FOURPALMYRENE NUMBER FIVEPALMYR" +
"ENE NUMBER TENPALMYRENE NUMBER TWENTYNABATAEAN LETTER FINAL ALEPHNABATAE" +
"AN LETTER ALEPHNABATAEAN LETTER FINAL BETHNABATAEAN LETTER BETHNABATAEAN" +
" LETTER GIMELNABATAEAN LETTER DALETHNABATAEAN LETTER FINAL HENABATAEAN L" +
"ETTER HENABATAEAN LETTER WAWNABATAEAN LETTER ZAYINNABATAEAN LETTER HETHN" +
"ABATAEAN LETTER TETHNABATAEAN LETTER FINAL YODHNABATAEAN LETTER YODHNABA" +
"TAEAN LETTER FINAL KAPHNABATAEAN LETTER KAPHNABATAEAN LETTER FINAL LAMED" +
"HNABATAEAN LETTER LAMEDHNABATAEAN LETTER FINAL MEMNABATAEAN LETTER MEMNA" +
"BATAEAN LETTER FINAL NUNNABATAEAN LETTER NUNNABATAEAN LETTER SAMEKHNABAT" +
"AEAN LETTER AYINNABATAEAN LETTER PENABATAEAN LETTER SADHENABATAEAN LETTE" +
"R QOPHNABATAEAN LETTER RESHNABATAEAN LETTER FINAL SHINNABATAEAN LETTER S" +
"HINNABATAEAN LETTER TAWNABATAEAN NUMBER ONENABATAEAN NUMBER TWONABATAEAN") + ("" +
" NUMBER THREENABATAEAN NUMBER FOURNABATAEAN CRUCIFORM NUMBER FOURNABATAE" +
"AN NUMBER FIVENABATAEAN NUMBER TENNABATAEAN NUMBER TWENTYNABATAEAN NUMBE" +
"R ONE HUNDREDHATRAN LETTER ALEPHHATRAN LETTER BETHHATRAN LETTER GIMELHAT" +
"RAN LETTER DALETH-RESHHATRAN LETTER HEHATRAN LETTER WAWHATRAN LETTER ZAY" +
"NHATRAN LETTER HETHHATRAN LETTER TETHHATRAN LETTER YODHHATRAN LETTER KAP" +
"HHATRAN LETTER LAMEDHHATRAN LETTER MEMHATRAN LETTER NUNHATRAN LETTER SAM" +
"EKHHATRAN LETTER AYNHATRAN LETTER PEHATRAN LETTER SADHEHATRAN LETTER QOP" +
"HHATRAN LETTER SHINHATRAN LETTER TAWHATRAN NUMBER ONEHATRAN NUMBER FIVEH" +
"ATRAN NUMBER TENHATRAN NUMBER TWENTYHATRAN NUMBER ONE HUNDREDPHOENICIAN " +
"LETTER ALFPHOENICIAN LETTER BETPHOENICIAN LETTER GAMLPHOENICIAN LETTER D" +
"ELTPHOENICIAN LETTER HEPHOENICIAN LETTER WAUPHOENICIAN LETTER ZAIPHOENIC" +
"IAN LETTER HETPHOENICIAN LETTER TETPHOENICIAN LETTER YODPHOENICIAN LETTE" +
"R KAFPHOENICIAN LETTER LAMDPHOENICIAN LETTER MEMPHOENICIAN LETTER NUNPHO" +
"ENICIAN LETTER SEMKPHOENICIAN LETTER AINPHOENICIAN LETTER PEPHOENICIAN L" +
"ETTER SADEPHOENICIAN LETTER QOFPHOENICIAN LETTER ROSHPHOENICIAN LETTER S" +
"HINPHOENICIAN LETTER TAUPHOENICIAN NUMBER ONEPHOENICIAN NUMBER TENPHOENI" +
"CIAN NUMBER TWENTYPHOENICIAN NUMBER ONE HUNDREDPHOENICIAN NUMBER TWOPHOE" +
"NICIAN NUMBER THREEPHOENICIAN WORD SEPARATORLYDIAN LETTER ALYDIAN LETTER" +
" BLYDIAN LETTER GLYDIAN LETTER DLYDIAN LETTER ELYDIAN LETTER VLYDIAN LET" +
"TER ILYDIAN LETTER YLYDIAN LETTER KLYDIAN LETTER LLYDIAN LETTER MLYDIAN " +
"LETTER NLYDIAN LETTER OLYDIAN LETTER RLYDIAN LETTER SSLYDIAN LETTER TLYD" +
"IAN LETTER ULYDIAN LETTER FLYDIAN LETTER QLYDIAN LETTER SLYDIAN LETTER T" +
"TLYDIAN LETTER ANLYDIAN LETTER ENLYDIAN LETTER LYLYDIAN LETTER NNLYDIAN " +
"LETTER CLYDIAN TRIANGULAR MARKMEROITIC HIEROGLYPHIC LETTER AMEROITIC HIE" +
"ROGLYPHIC LETTER EMEROITIC HIEROGLYPHIC LETTER IMEROITIC HIEROGLYPHIC LE" +
"TTER OMEROITIC HIEROGLYPHIC LETTER YAMEROITIC HIEROGLYPHIC LETTER WAMERO" +
"ITIC HIEROGLYPHIC LETTER BAMEROITIC HIEROGLYPHIC LETTER BA-2MEROITIC HIE" +
"ROGLYPHIC LETTER PAMEROITIC HIEROGLYPHIC LETTER MAMEROITIC HIEROGLYPHIC " +
"LETTER NAMEROITIC HIEROGLYPHIC LETTER NA-2MEROITIC HIEROGLYPHIC LETTER N" +
"EMEROITIC HIEROGLYPHIC LETTER NE-2MEROITIC HIEROGLYPHIC LETTER RAMEROITI" +
"C HIEROGLYPHIC LETTER RA-2MEROITIC HIEROGLYPHIC LETTER LAMEROITIC HIEROG" +
"LYPHIC LETTER KHAMEROITIC HIEROGLYPHIC LETTER HHAMEROITIC HIEROGLYPHIC L" +
"ETTER SAMEROITIC HIEROGLYPHIC LETTER SA-2MEROITIC HIEROGLYPHIC LETTER SE" +
"MEROITIC HIEROGLYPHIC LETTER KAMEROITIC HIEROGLYPHIC LETTER QAMEROITIC H" +
"IEROGLYPHIC LETTER TAMEROITIC HIEROGLYPHIC LETTER TA-2MEROITIC HIEROGLYP" +
"HIC LETTER TEMEROITIC HIEROGLYPHIC LETTER TE-2MEROITIC HIEROGLYPHIC LETT" +
"ER TOMEROITIC HIEROGLYPHIC LETTER DAMEROITIC HIEROGLYPHIC SYMBOL VIDJMER" +
"OITIC HIEROGLYPHIC SYMBOL VIDJ-2MEROITIC CURSIVE LETTER AMEROITIC CURSIV" +
"E LETTER EMEROITIC CURSIVE LETTER IMEROITIC CURSIVE LETTER OMEROITIC CUR" +
"SIVE LETTER YAMEROITIC CURSIVE LETTER WAMEROITIC CURSIVE LETTER BAMEROIT" +
"IC CURSIVE LETTER PAMEROITIC CURSIVE LETTER MAMEROITIC CURSIVE LETTER NA" +
"MEROITIC CURSIVE LETTER NEMEROITIC CURSIVE LETTER RAMEROITIC CURSIVE LET" +
"TER LAMEROITIC CURSIVE LETTER KHAMEROITIC CURSIVE LETTER HHAMEROITIC CUR" +
"SIVE LETTER SAMEROITIC CURSIVE LETTER ARCHAIC SAMEROITIC CURSIVE LETTER " +
"SEMEROITIC CURSIVE LETTER KAMEROITIC CURSIVE LETTER QAMEROITIC CURSIVE L" +
"ETTER TAMEROITIC CURSIVE LETTER TEMEROITIC CURSIVE LETTER TOMEROITIC CUR" +
"SIVE LETTER DAMEROITIC CURSIVE FRACTION ELEVEN TWELFTHSMEROITIC CURSIVE " +
"FRACTION ONE HALFMEROITIC CURSIVE LOGOGRAM RMTMEROITIC CURSIVE LOGOGRAM " +
"IMNMEROITIC CURSIVE NUMBER ONEMEROITIC CURSIVE NUMBER TWOMEROITIC CURSIV" +
"E NUMBER THREEMEROITIC CURSIVE NUMBER FOURMEROITIC CURSIVE NUMBER FIVEME" +
"ROITIC CURSIVE NUMBER SIXMEROITIC CURSIVE NUMBER SEVENMEROITIC CURSIVE N" +
"UMBER EIGHTMEROITIC CURSIVE NUMBER NINEMEROITIC CURSIVE NUMBER TENMEROIT" +
"IC CURSIVE NUMBER TWENTYMEROITIC CURSIVE NUMBER THIRTYMEROITIC CURSIVE N" +
"UMBER FORTYMEROITIC CURSIVE NUMBER FIFTYMEROITIC CURSIVE NUMBER SIXTYMER" +
"OITIC CURSIVE NUMBER SEVENTYMEROITIC CURSIVE NUMBER ONE HUNDREDMEROITIC " +
"CURSIVE NUMBER TWO HUNDREDMEROITIC CURSIVE NUMBER THREE HUNDREDMEROITIC " +
"CURSIVE NUMBER FOUR HUNDREDMEROITIC CURSIVE NUMBER FIVE HUNDREDMEROITIC " +
"CURSIVE NUMBER SIX HUNDREDMEROITIC CURSIVE NUMBER SEVEN HUNDREDMEROITIC " +
"CURSIVE NUMBER EIGHT HUNDREDMEROITIC CURSIVE NUMBER NINE HUNDREDMEROITIC" +
" CURSIVE NUMBER ONE THOUSANDMEROITIC CURSIVE NUMBER TWO THOUSANDMEROITIC" +
" CURSIVE NUMBER THREE THOUSANDMEROITIC CURSIVE NUMBER FOUR THOUSANDMEROI" +
"TIC CURSIVE NUMBER FIVE THOUSANDMEROITIC CURSIVE NUMBER SIX THOUSANDMERO" +
"ITIC CURSIVE NUMBER SEVEN THOUSANDMEROITIC CURSIVE NUMBER EIGHT THOUSAND" +
"MEROITIC CURSIVE NUMBER NINE THOUSANDMEROITIC CURSIVE NUMBER TEN THOUSAN") + ("" +
"DMEROITIC CURSIVE NUMBER TWENTY THOUSANDMEROITIC CURSIVE NUMBER THIRTY T" +
"HOUSANDMEROITIC CURSIVE NUMBER FORTY THOUSANDMEROITIC CURSIVE NUMBER FIF" +
"TY THOUSANDMEROITIC CURSIVE NUMBER SIXTY THOUSANDMEROITIC CURSIVE NUMBER" +
" SEVENTY THOUSANDMEROITIC CURSIVE NUMBER EIGHTY THOUSANDMEROITIC CURSIVE" +
" NUMBER NINETY THOUSANDMEROITIC CURSIVE NUMBER ONE HUNDRED THOUSANDMEROI" +
"TIC CURSIVE NUMBER TWO HUNDRED THOUSANDMEROITIC CURSIVE NUMBER THREE HUN" +
"DRED THOUSANDMEROITIC CURSIVE NUMBER FOUR HUNDRED THOUSANDMEROITIC CURSI" +
"VE NUMBER FIVE HUNDRED THOUSANDMEROITIC CURSIVE NUMBER SIX HUNDRED THOUS" +
"ANDMEROITIC CURSIVE NUMBER SEVEN HUNDRED THOUSANDMEROITIC CURSIVE NUMBER" +
" EIGHT HUNDRED THOUSANDMEROITIC CURSIVE NUMBER NINE HUNDRED THOUSANDMERO" +
"ITIC CURSIVE FRACTION ONE TWELFTHMEROITIC CURSIVE FRACTION TWO TWELFTHSM" +
"EROITIC CURSIVE FRACTION THREE TWELFTHSMEROITIC CURSIVE FRACTION FOUR TW" +
"ELFTHSMEROITIC CURSIVE FRACTION FIVE TWELFTHSMEROITIC CURSIVE FRACTION S" +
"IX TWELFTHSMEROITIC CURSIVE FRACTION SEVEN TWELFTHSMEROITIC CURSIVE FRAC" +
"TION EIGHT TWELFTHSMEROITIC CURSIVE FRACTION NINE TWELFTHSMEROITIC CURSI" +
"VE FRACTION TEN TWELFTHSKHAROSHTHI LETTER AKHAROSHTHI VOWEL SIGN IKHAROS" +
"HTHI VOWEL SIGN UKHAROSHTHI VOWEL SIGN VOCALIC RKHAROSHTHI VOWEL SIGN EK" +
"HAROSHTHI VOWEL SIGN OKHAROSHTHI VOWEL LENGTH MARKKHAROSHTHI SIGN DOUBLE" +
" RING BELOWKHAROSHTHI SIGN ANUSVARAKHAROSHTHI SIGN VISARGAKHAROSHTHI LET" +
"TER KAKHAROSHTHI LETTER KHAKHAROSHTHI LETTER GAKHAROSHTHI LETTER GHAKHAR" +
"OSHTHI LETTER CAKHAROSHTHI LETTER CHAKHAROSHTHI LETTER JAKHAROSHTHI LETT" +
"ER NYAKHAROSHTHI LETTER TTAKHAROSHTHI LETTER TTHAKHAROSHTHI LETTER DDAKH" +
"AROSHTHI LETTER DDHAKHAROSHTHI LETTER NNAKHAROSHTHI LETTER TAKHAROSHTHI " +
"LETTER THAKHAROSHTHI LETTER DAKHAROSHTHI LETTER DHAKHAROSHTHI LETTER NAK" +
"HAROSHTHI LETTER PAKHAROSHTHI LETTER PHAKHAROSHTHI LETTER BAKHAROSHTHI L" +
"ETTER BHAKHAROSHTHI LETTER MAKHAROSHTHI LETTER YAKHAROSHTHI LETTER RAKHA" +
"ROSHTHI LETTER LAKHAROSHTHI LETTER VAKHAROSHTHI LETTER SHAKHAROSHTHI LET" +
"TER SSAKHAROSHTHI LETTER SAKHAROSHTHI LETTER ZAKHAROSHTHI LETTER HAKHARO" +
"SHTHI LETTER KKAKHAROSHTHI LETTER TTTHAKHAROSHTHI LETTER TTTAKHAROSHTHI " +
"LETTER VHAKHAROSHTHI SIGN BAR ABOVEKHAROSHTHI SIGN CAUDAKHAROSHTHI SIGN " +
"DOT BELOWKHAROSHTHI VIRAMAKHAROSHTHI DIGIT ONEKHAROSHTHI DIGIT TWOKHAROS" +
"HTHI DIGIT THREEKHAROSHTHI DIGIT FOURKHAROSHTHI NUMBER TENKHAROSHTHI NUM" +
"BER TWENTYKHAROSHTHI NUMBER ONE HUNDREDKHAROSHTHI NUMBER ONE THOUSANDKHA" +
"ROSHTHI FRACTION ONE HALFKHAROSHTHI PUNCTUATION DOTKHAROSHTHI PUNCTUATIO" +
"N SMALL CIRCLEKHAROSHTHI PUNCTUATION CIRCLEKHAROSHTHI PUNCTUATION CRESCE" +
"NT BARKHAROSHTHI PUNCTUATION MANGALAMKHAROSHTHI PUNCTUATION LOTUSKHAROSH" +
"THI PUNCTUATION DANDAKHAROSHTHI PUNCTUATION DOUBLE DANDAKHAROSHTHI PUNCT" +
"UATION LINESOLD SOUTH ARABIAN LETTER HEOLD SOUTH ARABIAN LETTER LAMEDHOL" +
"D SOUTH ARABIAN LETTER HETHOLD SOUTH ARABIAN LETTER MEMOLD SOUTH ARABIAN" +
" LETTER QOPHOLD SOUTH ARABIAN LETTER WAWOLD SOUTH ARABIAN LETTER SHINOLD" +
" SOUTH ARABIAN LETTER RESHOLD SOUTH ARABIAN LETTER BETHOLD SOUTH ARABIAN" +
" LETTER TAWOLD SOUTH ARABIAN LETTER SATOLD SOUTH ARABIAN LETTER KAPHOLD " +
"SOUTH ARABIAN LETTER NUNOLD SOUTH ARABIAN LETTER KHETHOLD SOUTH ARABIAN " +
"LETTER SADHEOLD SOUTH ARABIAN LETTER SAMEKHOLD SOUTH ARABIAN LETTER FEOL" +
"D SOUTH ARABIAN LETTER ALEFOLD SOUTH ARABIAN LETTER AYNOLD SOUTH ARABIAN" +
" LETTER DHADHEOLD SOUTH ARABIAN LETTER GIMELOLD SOUTH ARABIAN LETTER DAL" +
"ETHOLD SOUTH ARABIAN LETTER GHAYNOLD SOUTH ARABIAN LETTER TETHOLD SOUTH " +
"ARABIAN LETTER ZAYNOLD SOUTH ARABIAN LETTER DHALETHOLD SOUTH ARABIAN LET" +
"TER YODHOLD SOUTH ARABIAN LETTER THAWOLD SOUTH ARABIAN LETTER THETHOLD S" +
"OUTH ARABIAN NUMBER ONEOLD SOUTH ARABIAN NUMBER FIFTYOLD SOUTH ARABIAN N" +
"UMERIC INDICATOROLD NORTH ARABIAN LETTER HEHOLD NORTH ARABIAN LETTER LAM" +
"OLD NORTH ARABIAN LETTER HAHOLD NORTH ARABIAN LETTER MEEMOLD NORTH ARABI" +
"AN LETTER QAFOLD NORTH ARABIAN LETTER WAWOLD NORTH ARABIAN LETTER ES-2OL" +
"D NORTH ARABIAN LETTER REHOLD NORTH ARABIAN LETTER BEHOLD NORTH ARABIAN " +
"LETTER TEHOLD NORTH ARABIAN LETTER ES-1OLD NORTH ARABIAN LETTER KAFOLD N" +
"ORTH ARABIAN LETTER NOONOLD NORTH ARABIAN LETTER KHAHOLD NORTH ARABIAN L" +
"ETTER SADOLD NORTH ARABIAN LETTER ES-3OLD NORTH ARABIAN LETTER FEHOLD NO" +
"RTH ARABIAN LETTER ALEFOLD NORTH ARABIAN LETTER AINOLD NORTH ARABIAN LET" +
"TER DADOLD NORTH ARABIAN LETTER GEEMOLD NORTH ARABIAN LETTER DALOLD NORT" +
"H ARABIAN LETTER GHAINOLD NORTH ARABIAN LETTER TAHOLD NORTH ARABIAN LETT" +
"ER ZAINOLD NORTH ARABIAN LETTER THALOLD NORTH ARABIAN LETTER YEHOLD NORT" +
"H ARABIAN LETTER THEHOLD NORTH ARABIAN LETTER ZAHOLD NORTH ARABIAN NUMBE" +
"R ONEOLD NORTH ARABIAN NUMBER TENOLD NORTH ARABIAN NUMBER TWENTYMANICHAE" +
"AN LETTER ALEPHMANICHAEAN LETTER BETHMANICHAEAN LETTER BHETHMANICHAEAN L") + ("" +
"ETTER GIMELMANICHAEAN LETTER GHIMELMANICHAEAN LETTER DALETHMANICHAEAN LE" +
"TTER HEMANICHAEAN LETTER WAWMANICHAEAN SIGN UDMANICHAEAN LETTER ZAYINMAN" +
"ICHAEAN LETTER ZHAYINMANICHAEAN LETTER JAYINMANICHAEAN LETTER JHAYINMANI" +
"CHAEAN LETTER HETHMANICHAEAN LETTER TETHMANICHAEAN LETTER YODHMANICHAEAN" +
" LETTER KAPHMANICHAEAN LETTER XAPHMANICHAEAN LETTER KHAPHMANICHAEAN LETT" +
"ER LAMEDHMANICHAEAN LETTER DHAMEDHMANICHAEAN LETTER THAMEDHMANICHAEAN LE" +
"TTER MEMMANICHAEAN LETTER NUNMANICHAEAN LETTER SAMEKHMANICHAEAN LETTER A" +
"YINMANICHAEAN LETTER AAYINMANICHAEAN LETTER PEMANICHAEAN LETTER FEMANICH" +
"AEAN LETTER SADHEMANICHAEAN LETTER QOPHMANICHAEAN LETTER XOPHMANICHAEAN " +
"LETTER QHOPHMANICHAEAN LETTER RESHMANICHAEAN LETTER SHINMANICHAEAN LETTE" +
"R SSHINMANICHAEAN LETTER TAWMANICHAEAN ABBREVIATION MARK ABOVEMANICHAEAN" +
" ABBREVIATION MARK BELOWMANICHAEAN NUMBER ONEMANICHAEAN NUMBER FIVEMANIC" +
"HAEAN NUMBER TENMANICHAEAN NUMBER TWENTYMANICHAEAN NUMBER ONE HUNDREDMAN" +
"ICHAEAN PUNCTUATION STARMANICHAEAN PUNCTUATION FLEURONMANICHAEAN PUNCTUA" +
"TION DOUBLE DOT WITHIN DOTMANICHAEAN PUNCTUATION DOT WITHIN DOTMANICHAEA" +
"N PUNCTUATION DOTMANICHAEAN PUNCTUATION TWO DOTSMANICHAEAN PUNCTUATION L" +
"INE FILLERAVESTAN LETTER AAVESTAN LETTER AAAVESTAN LETTER AOAVESTAN LETT" +
"ER AAOAVESTAN LETTER ANAVESTAN LETTER AANAVESTAN LETTER AEAVESTAN LETTER" +
" AEEAVESTAN LETTER EAVESTAN LETTER EEAVESTAN LETTER OAVESTAN LETTER OOAV" +
"ESTAN LETTER IAVESTAN LETTER IIAVESTAN LETTER UAVESTAN LETTER UUAVESTAN " +
"LETTER KEAVESTAN LETTER XEAVESTAN LETTER XYEAVESTAN LETTER XVEAVESTAN LE" +
"TTER GEAVESTAN LETTER GGEAVESTAN LETTER GHEAVESTAN LETTER CEAVESTAN LETT" +
"ER JEAVESTAN LETTER TEAVESTAN LETTER THEAVESTAN LETTER DEAVESTAN LETTER " +
"DHEAVESTAN LETTER TTEAVESTAN LETTER PEAVESTAN LETTER FEAVESTAN LETTER BE" +
"AVESTAN LETTER BHEAVESTAN LETTER NGEAVESTAN LETTER NGYEAVESTAN LETTER NG" +
"VEAVESTAN LETTER NEAVESTAN LETTER NYEAVESTAN LETTER NNEAVESTAN LETTER ME" +
"AVESTAN LETTER HMEAVESTAN LETTER YYEAVESTAN LETTER YEAVESTAN LETTER VEAV" +
"ESTAN LETTER REAVESTAN LETTER LEAVESTAN LETTER SEAVESTAN LETTER ZEAVESTA" +
"N LETTER SHEAVESTAN LETTER ZHEAVESTAN LETTER SHYEAVESTAN LETTER SSHEAVES" +
"TAN LETTER HEAVESTAN ABBREVIATION MARKTINY TWO DOTS OVER ONE DOT PUNCTUA" +
"TIONSMALL TWO DOTS OVER ONE DOT PUNCTUATIONLARGE TWO DOTS OVER ONE DOT P" +
"UNCTUATIONLARGE ONE DOT OVER TWO DOTS PUNCTUATIONLARGE TWO RINGS OVER ON" +
"E RING PUNCTUATIONLARGE ONE RING OVER TWO RINGS PUNCTUATIONINSCRIPTIONAL" +
" PARTHIAN LETTER ALEPHINSCRIPTIONAL PARTHIAN LETTER BETHINSCRIPTIONAL PA" +
"RTHIAN LETTER GIMELINSCRIPTIONAL PARTHIAN LETTER DALETHINSCRIPTIONAL PAR" +
"THIAN LETTER HEINSCRIPTIONAL PARTHIAN LETTER WAWINSCRIPTIONAL PARTHIAN L" +
"ETTER ZAYININSCRIPTIONAL PARTHIAN LETTER HETHINSCRIPTIONAL PARTHIAN LETT" +
"ER TETHINSCRIPTIONAL PARTHIAN LETTER YODHINSCRIPTIONAL PARTHIAN LETTER K" +
"APHINSCRIPTIONAL PARTHIAN LETTER LAMEDHINSCRIPTIONAL PARTHIAN LETTER MEM" +
"INSCRIPTIONAL PARTHIAN LETTER NUNINSCRIPTIONAL PARTHIAN LETTER SAMEKHINS" +
"CRIPTIONAL PARTHIAN LETTER AYININSCRIPTIONAL PARTHIAN LETTER PEINSCRIPTI" +
"ONAL PARTHIAN LETTER SADHEINSCRIPTIONAL PARTHIAN LETTER QOPHINSCRIPTIONA" +
"L PARTHIAN LETTER RESHINSCRIPTIONAL PARTHIAN LETTER SHININSCRIPTIONAL PA" +
"RTHIAN LETTER TAWINSCRIPTIONAL PARTHIAN NUMBER ONEINSCRIPTIONAL PARTHIAN" +
" NUMBER TWOINSCRIPTIONAL PARTHIAN NUMBER THREEINSCRIPTIONAL PARTHIAN NUM" +
"BER FOURINSCRIPTIONAL PARTHIAN NUMBER TENINSCRIPTIONAL PARTHIAN NUMBER T" +
"WENTYINSCRIPTIONAL PARTHIAN NUMBER ONE HUNDREDINSCRIPTIONAL PARTHIAN NUM" +
"BER ONE THOUSANDINSCRIPTIONAL PAHLAVI LETTER ALEPHINSCRIPTIONAL PAHLAVI " +
"LETTER BETHINSCRIPTIONAL PAHLAVI LETTER GIMELINSCRIPTIONAL PAHLAVI LETTE" +
"R DALETHINSCRIPTIONAL PAHLAVI LETTER HEINSCRIPTIONAL PAHLAVI LETTER WAW-" +
"AYIN-RESHINSCRIPTIONAL PAHLAVI LETTER ZAYININSCRIPTIONAL PAHLAVI LETTER " +
"HETHINSCRIPTIONAL PAHLAVI LETTER TETHINSCRIPTIONAL PAHLAVI LETTER YODHIN" +
"SCRIPTIONAL PAHLAVI LETTER KAPHINSCRIPTIONAL PAHLAVI LETTER LAMEDHINSCRI" +
"PTIONAL PAHLAVI LETTER MEM-QOPHINSCRIPTIONAL PAHLAVI LETTER NUNINSCRIPTI" +
"ONAL PAHLAVI LETTER SAMEKHINSCRIPTIONAL PAHLAVI LETTER PEINSCRIPTIONAL P" +
"AHLAVI LETTER SADHEINSCRIPTIONAL PAHLAVI LETTER SHININSCRIPTIONAL PAHLAV" +
"I LETTER TAWINSCRIPTIONAL PAHLAVI NUMBER ONEINSCRIPTIONAL PAHLAVI NUMBER" +
" TWOINSCRIPTIONAL PAHLAVI NUMBER THREEINSCRIPTIONAL PAHLAVI NUMBER FOURI" +
"NSCRIPTIONAL PAHLAVI NUMBER TENINSCRIPTIONAL PAHLAVI NUMBER TWENTYINSCRI" +
"PTIONAL PAHLAVI NUMBER ONE HUNDREDINSCRIPTIONAL PAHLAVI NUMBER ONE THOUS" +
"ANDPSALTER PAHLAVI LETTER ALEPHPSALTER PAHLAVI LETTER BETHPSALTER PAHLAV" +
"I LETTER GIMELPSALTER PAHLAVI LETTER DALETHPSALTER PAHLAVI LETTER HEPSAL" +
"TER PAHLAVI LETTER WAW-AYIN-RESHPSALTER PAHLAVI LETTER ZAYINPSALTER PAHL" +
"AVI LETTER HETHPSALTER PAHLAVI LETTER YODHPSALTER PAHLAVI LETTER KAPHPSA") + ("" +
"LTER PAHLAVI LETTER LAMEDHPSALTER PAHLAVI LETTER MEM-QOPHPSALTER PAHLAVI" +
" LETTER NUNPSALTER PAHLAVI LETTER SAMEKHPSALTER PAHLAVI LETTER PEPSALTER" +
" PAHLAVI LETTER SADHEPSALTER PAHLAVI LETTER SHINPSALTER PAHLAVI LETTER T" +
"AWPSALTER PAHLAVI SECTION MARKPSALTER PAHLAVI TURNED SECTION MARKPSALTER" +
" PAHLAVI FOUR DOTS WITH CROSSPSALTER PAHLAVI FOUR DOTS WITH DOTPSALTER P" +
"AHLAVI NUMBER ONEPSALTER PAHLAVI NUMBER TWOPSALTER PAHLAVI NUMBER THREEP" +
"SALTER PAHLAVI NUMBER FOURPSALTER PAHLAVI NUMBER TENPSALTER PAHLAVI NUMB" +
"ER TWENTYPSALTER PAHLAVI NUMBER ONE HUNDREDOLD TURKIC LETTER ORKHON AOLD" +
" TURKIC LETTER YENISEI AOLD TURKIC LETTER YENISEI AEOLD TURKIC LETTER OR" +
"KHON IOLD TURKIC LETTER YENISEI IOLD TURKIC LETTER YENISEI EOLD TURKIC L" +
"ETTER ORKHON OOLD TURKIC LETTER ORKHON OEOLD TURKIC LETTER YENISEI OEOLD" +
" TURKIC LETTER ORKHON ABOLD TURKIC LETTER YENISEI ABOLD TURKIC LETTER OR" +
"KHON AEBOLD TURKIC LETTER YENISEI AEBOLD TURKIC LETTER ORKHON AGOLD TURK" +
"IC LETTER YENISEI AGOLD TURKIC LETTER ORKHON AEGOLD TURKIC LETTER YENISE" +
"I AEGOLD TURKIC LETTER ORKHON ADOLD TURKIC LETTER YENISEI ADOLD TURKIC L" +
"ETTER ORKHON AEDOLD TURKIC LETTER ORKHON EZOLD TURKIC LETTER YENISEI EZO" +
"LD TURKIC LETTER ORKHON AYOLD TURKIC LETTER YENISEI AYOLD TURKIC LETTER " +
"ORKHON AEYOLD TURKIC LETTER YENISEI AEYOLD TURKIC LETTER ORKHON AEKOLD T" +
"URKIC LETTER YENISEI AEKOLD TURKIC LETTER ORKHON OEKOLD TURKIC LETTER YE" +
"NISEI OEKOLD TURKIC LETTER ORKHON ALOLD TURKIC LETTER YENISEI ALOLD TURK" +
"IC LETTER ORKHON AELOLD TURKIC LETTER ORKHON ELTOLD TURKIC LETTER ORKHON" +
" EMOLD TURKIC LETTER ORKHON ANOLD TURKIC LETTER ORKHON AENOLD TURKIC LET" +
"TER YENISEI AENOLD TURKIC LETTER ORKHON ENTOLD TURKIC LETTER YENISEI ENT" +
"OLD TURKIC LETTER ORKHON ENCOLD TURKIC LETTER YENISEI ENCOLD TURKIC LETT" +
"ER ORKHON ENYOLD TURKIC LETTER YENISEI ENYOLD TURKIC LETTER YENISEI ANGO" +
"LD TURKIC LETTER ORKHON ENGOLD TURKIC LETTER YENISEI AENGOLD TURKIC LETT" +
"ER ORKHON EPOLD TURKIC LETTER ORKHON OPOLD TURKIC LETTER ORKHON ICOLD TU" +
"RKIC LETTER ORKHON ECOLD TURKIC LETTER YENISEI ECOLD TURKIC LETTER ORKHO" +
"N AQOLD TURKIC LETTER YENISEI AQOLD TURKIC LETTER ORKHON IQOLD TURKIC LE" +
"TTER YENISEI IQOLD TURKIC LETTER ORKHON OQOLD TURKIC LETTER YENISEI OQOL" +
"D TURKIC LETTER ORKHON AROLD TURKIC LETTER YENISEI AROLD TURKIC LETTER O" +
"RKHON AEROLD TURKIC LETTER ORKHON ASOLD TURKIC LETTER ORKHON AESOLD TURK" +
"IC LETTER ORKHON ASHOLD TURKIC LETTER YENISEI ASHOLD TURKIC LETTER ORKHO" +
"N ESHOLD TURKIC LETTER YENISEI ESHOLD TURKIC LETTER ORKHON ATOLD TURKIC " +
"LETTER YENISEI ATOLD TURKIC LETTER ORKHON AETOLD TURKIC LETTER YENISEI A" +
"ETOLD TURKIC LETTER ORKHON OTOLD TURKIC LETTER ORKHON BASHOLD HUNGARIAN " +
"CAPITAL LETTER AOLD HUNGARIAN CAPITAL LETTER AAOLD HUNGARIAN CAPITAL LET" +
"TER EBOLD HUNGARIAN CAPITAL LETTER AMBOLD HUNGARIAN CAPITAL LETTER ECOLD" +
" HUNGARIAN CAPITAL LETTER ENCOLD HUNGARIAN CAPITAL LETTER ECSOLD HUNGARI" +
"AN CAPITAL LETTER EDOLD HUNGARIAN CAPITAL LETTER ANDOLD HUNGARIAN CAPITA" +
"L LETTER EOLD HUNGARIAN CAPITAL LETTER CLOSE EOLD HUNGARIAN CAPITAL LETT" +
"ER EEOLD HUNGARIAN CAPITAL LETTER EFOLD HUNGARIAN CAPITAL LETTER EGOLD H" +
"UNGARIAN CAPITAL LETTER EGYOLD HUNGARIAN CAPITAL LETTER EHOLD HUNGARIAN " +
"CAPITAL LETTER IOLD HUNGARIAN CAPITAL LETTER IIOLD HUNGARIAN CAPITAL LET" +
"TER EJOLD HUNGARIAN CAPITAL LETTER EKOLD HUNGARIAN CAPITAL LETTER AKOLD " +
"HUNGARIAN CAPITAL LETTER UNKOLD HUNGARIAN CAPITAL LETTER ELOLD HUNGARIAN" +
" CAPITAL LETTER ELYOLD HUNGARIAN CAPITAL LETTER EMOLD HUNGARIAN CAPITAL " +
"LETTER ENOLD HUNGARIAN CAPITAL LETTER ENYOLD HUNGARIAN CAPITAL LETTER OO" +
"LD HUNGARIAN CAPITAL LETTER OOOLD HUNGARIAN CAPITAL LETTER NIKOLSBURG OE" +
"OLD HUNGARIAN CAPITAL LETTER RUDIMENTA OEOLD HUNGARIAN CAPITAL LETTER OE" +
"EOLD HUNGARIAN CAPITAL LETTER EPOLD HUNGARIAN CAPITAL LETTER EMPOLD HUNG" +
"ARIAN CAPITAL LETTER EROLD HUNGARIAN CAPITAL LETTER SHORT EROLD HUNGARIA" +
"N CAPITAL LETTER ESOLD HUNGARIAN CAPITAL LETTER ESZOLD HUNGARIAN CAPITAL" +
" LETTER ETOLD HUNGARIAN CAPITAL LETTER ENTOLD HUNGARIAN CAPITAL LETTER E" +
"TYOLD HUNGARIAN CAPITAL LETTER ECHOLD HUNGARIAN CAPITAL LETTER UOLD HUNG" +
"ARIAN CAPITAL LETTER UUOLD HUNGARIAN CAPITAL LETTER NIKOLSBURG UEOLD HUN" +
"GARIAN CAPITAL LETTER RUDIMENTA UEOLD HUNGARIAN CAPITAL LETTER EVOLD HUN" +
"GARIAN CAPITAL LETTER EZOLD HUNGARIAN CAPITAL LETTER EZSOLD HUNGARIAN CA" +
"PITAL LETTER ENT-SHAPED SIGNOLD HUNGARIAN CAPITAL LETTER USOLD HUNGARIAN" +
" SMALL LETTER AOLD HUNGARIAN SMALL LETTER AAOLD HUNGARIAN SMALL LETTER E" +
"BOLD HUNGARIAN SMALL LETTER AMBOLD HUNGARIAN SMALL LETTER ECOLD HUNGARIA" +
"N SMALL LETTER ENCOLD HUNGARIAN SMALL LETTER ECSOLD HUNGARIAN SMALL LETT" +
"ER EDOLD HUNGARIAN SMALL LETTER ANDOLD HUNGARIAN SMALL LETTER EOLD HUNGA" +
"RIAN SMALL LETTER CLOSE EOLD HUNGARIAN SMALL LETTER EEOLD HUNGARIAN SMAL") + ("" +
"L LETTER EFOLD HUNGARIAN SMALL LETTER EGOLD HUNGARIAN SMALL LETTER EGYOL" +
"D HUNGARIAN SMALL LETTER EHOLD HUNGARIAN SMALL LETTER IOLD HUNGARIAN SMA" +
"LL LETTER IIOLD HUNGARIAN SMALL LETTER EJOLD HUNGARIAN SMALL LETTER EKOL" +
"D HUNGARIAN SMALL LETTER AKOLD HUNGARIAN SMALL LETTER UNKOLD HUNGARIAN S" +
"MALL LETTER ELOLD HUNGARIAN SMALL LETTER ELYOLD HUNGARIAN SMALL LETTER E" +
"MOLD HUNGARIAN SMALL LETTER ENOLD HUNGARIAN SMALL LETTER ENYOLD HUNGARIA" +
"N SMALL LETTER OOLD HUNGARIAN SMALL LETTER OOOLD HUNGARIAN SMALL LETTER " +
"NIKOLSBURG OEOLD HUNGARIAN SMALL LETTER RUDIMENTA OEOLD HUNGARIAN SMALL " +
"LETTER OEEOLD HUNGARIAN SMALL LETTER EPOLD HUNGARIAN SMALL LETTER EMPOLD" +
" HUNGARIAN SMALL LETTER EROLD HUNGARIAN SMALL LETTER SHORT EROLD HUNGARI" +
"AN SMALL LETTER ESOLD HUNGARIAN SMALL LETTER ESZOLD HUNGARIAN SMALL LETT" +
"ER ETOLD HUNGARIAN SMALL LETTER ENTOLD HUNGARIAN SMALL LETTER ETYOLD HUN" +
"GARIAN SMALL LETTER ECHOLD HUNGARIAN SMALL LETTER UOLD HUNGARIAN SMALL L" +
"ETTER UUOLD HUNGARIAN SMALL LETTER NIKOLSBURG UEOLD HUNGARIAN SMALL LETT" +
"ER RUDIMENTA UEOLD HUNGARIAN SMALL LETTER EVOLD HUNGARIAN SMALL LETTER E" +
"ZOLD HUNGARIAN SMALL LETTER EZSOLD HUNGARIAN SMALL LETTER ENT-SHAPED SIG" +
"NOLD HUNGARIAN SMALL LETTER USOLD HUNGARIAN NUMBER ONEOLD HUNGARIAN NUMB" +
"ER FIVEOLD HUNGARIAN NUMBER TENOLD HUNGARIAN NUMBER FIFTYOLD HUNGARIAN N" +
"UMBER ONE HUNDREDOLD HUNGARIAN NUMBER ONE THOUSANDHANIFI ROHINGYA LETTER" +
" AHANIFI ROHINGYA LETTER BAHANIFI ROHINGYA LETTER PAHANIFI ROHINGYA LETT" +
"ER TAHANIFI ROHINGYA LETTER TTAHANIFI ROHINGYA LETTER JAHANIFI ROHINGYA " +
"LETTER CAHANIFI ROHINGYA LETTER HAHANIFI ROHINGYA LETTER KHAHANIFI ROHIN" +
"GYA LETTER FAHANIFI ROHINGYA LETTER DAHANIFI ROHINGYA LETTER DDAHANIFI R" +
"OHINGYA LETTER RAHANIFI ROHINGYA LETTER RRAHANIFI ROHINGYA LETTER ZAHANI" +
"FI ROHINGYA LETTER SAHANIFI ROHINGYA LETTER SHAHANIFI ROHINGYA LETTER KA" +
"HANIFI ROHINGYA LETTER GAHANIFI ROHINGYA LETTER LAHANIFI ROHINGYA LETTER" +
" MAHANIFI ROHINGYA LETTER NAHANIFI ROHINGYA LETTER WAHANIFI ROHINGYA LET" +
"TER KINNA WAHANIFI ROHINGYA LETTER YAHANIFI ROHINGYA LETTER KINNA YAHANI" +
"FI ROHINGYA LETTER NGAHANIFI ROHINGYA LETTER NYAHANIFI ROHINGYA LETTER V" +
"AHANIFI ROHINGYA VOWEL AHANIFI ROHINGYA VOWEL IHANIFI ROHINGYA VOWEL UHA" +
"NIFI ROHINGYA VOWEL EHANIFI ROHINGYA VOWEL OHANIFI ROHINGYA MARK SAKINHA" +
"NIFI ROHINGYA MARK NA KHONNAHANIFI ROHINGYA SIGN HARBAHAYHANIFI ROHINGYA" +
" SIGN TAHALAHANIFI ROHINGYA SIGN TANAHANIFI ROHINGYA SIGN TASSIHANIFI RO" +
"HINGYA DIGIT ZEROHANIFI ROHINGYA DIGIT ONEHANIFI ROHINGYA DIGIT TWOHANIF" +
"I ROHINGYA DIGIT THREEHANIFI ROHINGYA DIGIT FOURHANIFI ROHINGYA DIGIT FI" +
"VEHANIFI ROHINGYA DIGIT SIXHANIFI ROHINGYA DIGIT SEVENHANIFI ROHINGYA DI" +
"GIT EIGHTHANIFI ROHINGYA DIGIT NINERUMI DIGIT ONERUMI DIGIT TWORUMI DIGI" +
"T THREERUMI DIGIT FOURRUMI DIGIT FIVERUMI DIGIT SIXRUMI DIGIT SEVENRUMI " +
"DIGIT EIGHTRUMI DIGIT NINERUMI NUMBER TENRUMI NUMBER TWENTYRUMI NUMBER T" +
"HIRTYRUMI NUMBER FORTYRUMI NUMBER FIFTYRUMI NUMBER SIXTYRUMI NUMBER SEVE" +
"NTYRUMI NUMBER EIGHTYRUMI NUMBER NINETYRUMI NUMBER ONE HUNDREDRUMI NUMBE" +
"R TWO HUNDREDRUMI NUMBER THREE HUNDREDRUMI NUMBER FOUR HUNDREDRUMI NUMBE" +
"R FIVE HUNDREDRUMI NUMBER SIX HUNDREDRUMI NUMBER SEVEN HUNDREDRUMI NUMBE" +
"R EIGHT HUNDREDRUMI NUMBER NINE HUNDREDRUMI FRACTION ONE HALFRUMI FRACTI" +
"ON ONE QUARTERRUMI FRACTION ONE THIRDRUMI FRACTION TWO THIRDSYEZIDI LETT" +
"ER ELIFYEZIDI LETTER BEYEZIDI LETTER PEYEZIDI LETTER PHEYEZIDI LETTER TH" +
"EYEZIDI LETTER SEYEZIDI LETTER CIMYEZIDI LETTER CHIMYEZIDI LETTER CHHIMY" +
"EZIDI LETTER HHAYEZIDI LETTER XAYEZIDI LETTER DALYEZIDI LETTER ZALYEZIDI" +
" LETTER RAYEZIDI LETTER RHAYEZIDI LETTER ZAYEZIDI LETTER JAYEZIDI LETTER" +
" SINYEZIDI LETTER SHINYEZIDI LETTER SADYEZIDI LETTER DADYEZIDI LETTER TA" +
"YEZIDI LETTER ZEYEZIDI LETTER EYNYEZIDI LETTER XHEYNYEZIDI LETTER FAYEZI" +
"DI LETTER VAYEZIDI LETTER VA ALTERNATE FORMYEZIDI LETTER QAFYEZIDI LETTE" +
"R KAFYEZIDI LETTER KHAFYEZIDI LETTER GAFYEZIDI LETTER LAMYEZIDI LETTER M" +
"IMYEZIDI LETTER NUNYEZIDI LETTER UMYEZIDI LETTER WAWYEZIDI LETTER OWYEZI" +
"DI LETTER EWYEZIDI LETTER HAYYEZIDI LETTER YOTYEZIDI LETTER ETYEZIDI COM" +
"BINING HAMZA MARKYEZIDI COMBINING MADDA MARKYEZIDI HYPHENATION MARKYEZID" +
"I LETTER LAM WITH DOT ABOVEYEZIDI LETTER YOT WITH CIRCUMFLEX ABOVEARABIC" +
" SMALL LOW WORD SAKTAARABIC SMALL LOW WORD QASRARABIC SMALL LOW WORD MAD" +
"DAOLD SOGDIAN LETTER ALEPHOLD SOGDIAN LETTER FINAL ALEPHOLD SOGDIAN LETT" +
"ER BETHOLD SOGDIAN LETTER FINAL BETHOLD SOGDIAN LETTER GIMELOLD SOGDIAN " +
"LETTER HEOLD SOGDIAN LETTER FINAL HEOLD SOGDIAN LETTER WAWOLD SOGDIAN LE" +
"TTER ZAYINOLD SOGDIAN LETTER HETHOLD SOGDIAN LETTER YODHOLD SOGDIAN LETT" +
"ER KAPHOLD SOGDIAN LETTER LAMEDHOLD SOGDIAN LETTER MEMOLD SOGDIAN LETTER" +
" NUNOLD SOGDIAN LETTER FINAL NUNOLD SOGDIAN LETTER FINAL NUN WITH VERTIC") + ("" +
"AL TAILOLD SOGDIAN LETTER SAMEKHOLD SOGDIAN LETTER AYINOLD SOGDIAN LETTE" +
"R ALTERNATE AYINOLD SOGDIAN LETTER PEOLD SOGDIAN LETTER SADHEOLD SOGDIAN" +
" LETTER FINAL SADHEOLD SOGDIAN LETTER FINAL SADHE WITH VERTICAL TAILOLD " +
"SOGDIAN LETTER RESH-AYIN-DALETHOLD SOGDIAN LETTER SHINOLD SOGDIAN LETTER" +
" TAWOLD SOGDIAN LETTER FINAL TAWOLD SOGDIAN LETTER FINAL TAW WITH VERTIC" +
"AL TAILOLD SOGDIAN NUMBER ONEOLD SOGDIAN NUMBER TWOOLD SOGDIAN NUMBER TH" +
"REEOLD SOGDIAN NUMBER FOUROLD SOGDIAN NUMBER FIVEOLD SOGDIAN NUMBER TENO" +
"LD SOGDIAN NUMBER TWENTYOLD SOGDIAN NUMBER THIRTYOLD SOGDIAN NUMBER ONE " +
"HUNDREDOLD SOGDIAN FRACTION ONE HALFOLD SOGDIAN LIGATURE AYIN-DALETHSOGD" +
"IAN LETTER ALEPHSOGDIAN LETTER BETHSOGDIAN LETTER GIMELSOGDIAN LETTER HE" +
"SOGDIAN LETTER WAWSOGDIAN LETTER ZAYINSOGDIAN LETTER HETHSOGDIAN LETTER " +
"YODHSOGDIAN LETTER KAPHSOGDIAN LETTER LAMEDHSOGDIAN LETTER MEMSOGDIAN LE" +
"TTER NUNSOGDIAN LETTER SAMEKHSOGDIAN LETTER AYINSOGDIAN LETTER PESOGDIAN" +
" LETTER SADHESOGDIAN LETTER RESH-AYINSOGDIAN LETTER SHINSOGDIAN LETTER T" +
"AWSOGDIAN LETTER FETHSOGDIAN LETTER LESHSOGDIAN INDEPENDENT SHINSOGDIAN " +
"COMBINING DOT BELOWSOGDIAN COMBINING TWO DOTS BELOWSOGDIAN COMBINING DOT" +
" ABOVESOGDIAN COMBINING TWO DOTS ABOVESOGDIAN COMBINING CURVE ABOVESOGDI" +
"AN COMBINING CURVE BELOWSOGDIAN COMBINING HOOK ABOVESOGDIAN COMBINING HO" +
"OK BELOWSOGDIAN COMBINING LONG HOOK BELOWSOGDIAN COMBINING RESH BELOWSOG" +
"DIAN COMBINING STROKE BELOWSOGDIAN NUMBER ONESOGDIAN NUMBER TENSOGDIAN N" +
"UMBER TWENTYSOGDIAN NUMBER ONE HUNDREDSOGDIAN PUNCTUATION TWO VERTICAL B" +
"ARSSOGDIAN PUNCTUATION TWO VERTICAL BARS WITH DOTSSOGDIAN PUNCTUATION CI" +
"RCLE WITH DOTSOGDIAN PUNCTUATION TWO CIRCLES WITH DOTSSOGDIAN PUNCTUATIO" +
"N HALF CIRCLE WITH DOTOLD UYGHUR LETTER ALEPHOLD UYGHUR LETTER BETHOLD U" +
"YGHUR LETTER GIMEL-HETHOLD UYGHUR LETTER WAWOLD UYGHUR LETTER ZAYINOLD U" +
"YGHUR LETTER FINAL HETHOLD UYGHUR LETTER YODHOLD UYGHUR LETTER KAPHOLD U" +
"YGHUR LETTER LAMEDHOLD UYGHUR LETTER MEMOLD UYGHUR LETTER NUNOLD UYGHUR " +
"LETTER SAMEKHOLD UYGHUR LETTER PEOLD UYGHUR LETTER SADHEOLD UYGHUR LETTE" +
"R RESHOLD UYGHUR LETTER SHINOLD UYGHUR LETTER TAWOLD UYGHUR LETTER LESHO" +
"LD UYGHUR COMBINING DOT ABOVEOLD UYGHUR COMBINING DOT BELOWOLD UYGHUR CO" +
"MBINING TWO DOTS ABOVEOLD UYGHUR COMBINING TWO DOTS BELOWOLD UYGHUR PUNC" +
"TUATION BAROLD UYGHUR PUNCTUATION TWO BARSOLD UYGHUR PUNCTUATION TWO DOT" +
"SOLD UYGHUR PUNCTUATION FOUR DOTSCHORASMIAN LETTER ALEPHCHORASMIAN LETTE" +
"R SMALL ALEPHCHORASMIAN LETTER BETHCHORASMIAN LETTER GIMELCHORASMIAN LET" +
"TER DALETHCHORASMIAN LETTER HECHORASMIAN LETTER WAWCHORASMIAN LETTER CUR" +
"LED WAWCHORASMIAN LETTER ZAYINCHORASMIAN LETTER HETHCHORASMIAN LETTER YO" +
"DHCHORASMIAN LETTER KAPHCHORASMIAN LETTER LAMEDHCHORASMIAN LETTER MEMCHO" +
"RASMIAN LETTER NUNCHORASMIAN LETTER SAMEKHCHORASMIAN LETTER AYINCHORASMI" +
"AN LETTER PECHORASMIAN LETTER RESHCHORASMIAN LETTER SHINCHORASMIAN LETTE" +
"R TAWCHORASMIAN NUMBER ONECHORASMIAN NUMBER TWOCHORASMIAN NUMBER THREECH" +
"ORASMIAN NUMBER FOURCHORASMIAN NUMBER TENCHORASMIAN NUMBER TWENTYCHORASM" +
"IAN NUMBER ONE HUNDREDELYMAIC LETTER ALEPHELYMAIC LETTER BETHELYMAIC LET" +
"TER GIMELELYMAIC LETTER DALETHELYMAIC LETTER HEELYMAIC LETTER WAWELYMAIC" +
" LETTER ZAYINELYMAIC LETTER HETHELYMAIC LETTER TETHELYMAIC LETTER YODHEL" +
"YMAIC LETTER KAPHELYMAIC LETTER LAMEDHELYMAIC LETTER MEMELYMAIC LETTER N" +
"UNELYMAIC LETTER SAMEKHELYMAIC LETTER AYINELYMAIC LETTER PEELYMAIC LETTE" +
"R SADHEELYMAIC LETTER QOPHELYMAIC LETTER RESHELYMAIC LETTER SHINELYMAIC " +
"LETTER TAWELYMAIC LIGATURE ZAYIN-YODHBRAHMI SIGN CANDRABINDUBRAHMI SIGN " +
"ANUSVARABRAHMI SIGN VISARGABRAHMI SIGN JIHVAMULIYABRAHMI SIGN UPADHMANIY" +
"ABRAHMI LETTER ABRAHMI LETTER AABRAHMI LETTER IBRAHMI LETTER IIBRAHMI LE" +
"TTER UBRAHMI LETTER UUBRAHMI LETTER VOCALIC RBRAHMI LETTER VOCALIC RRBRA" +
"HMI LETTER VOCALIC LBRAHMI LETTER VOCALIC LLBRAHMI LETTER EBRAHMI LETTER" +
" AIBRAHMI LETTER OBRAHMI LETTER AUBRAHMI LETTER KABRAHMI LETTER KHABRAHM" +
"I LETTER GABRAHMI LETTER GHABRAHMI LETTER NGABRAHMI LETTER CABRAHMI LETT" +
"ER CHABRAHMI LETTER JABRAHMI LETTER JHABRAHMI LETTER NYABRAHMI LETTER TT" +
"ABRAHMI LETTER TTHABRAHMI LETTER DDABRAHMI LETTER DDHABRAHMI LETTER NNAB" +
"RAHMI LETTER TABRAHMI LETTER THABRAHMI LETTER DABRAHMI LETTER DHABRAHMI " +
"LETTER NABRAHMI LETTER PABRAHMI LETTER PHABRAHMI LETTER BABRAHMI LETTER " +
"BHABRAHMI LETTER MABRAHMI LETTER YABRAHMI LETTER RABRAHMI LETTER LABRAHM" +
"I LETTER VABRAHMI LETTER SHABRAHMI LETTER SSABRAHMI LETTER SABRAHMI LETT" +
"ER HABRAHMI LETTER LLABRAHMI LETTER OLD TAMIL LLLABRAHMI LETTER OLD TAMI" +
"L RRABRAHMI LETTER OLD TAMIL NNNABRAHMI VOWEL SIGN AABRAHMI VOWEL SIGN B" +
"HATTIPROLU AABRAHMI VOWEL SIGN IBRAHMI VOWEL SIGN IIBRAHMI VOWEL SIGN UB" +
"RAHMI VOWEL SIGN UUBRAHMI VOWEL SIGN VOCALIC RBRAHMI VOWEL SIGN VOCALIC ") + ("" +
"RRBRAHMI VOWEL SIGN VOCALIC LBRAHMI VOWEL SIGN VOCALIC LLBRAHMI VOWEL SI" +
"GN EBRAHMI VOWEL SIGN AIBRAHMI VOWEL SIGN OBRAHMI VOWEL SIGN AUBRAHMI VI" +
"RAMABRAHMI DANDABRAHMI DOUBLE DANDABRAHMI PUNCTUATION DOTBRAHMI PUNCTUAT" +
"ION DOUBLE DOTBRAHMI PUNCTUATION LINEBRAHMI PUNCTUATION CRESCENT BARBRAH" +
"MI PUNCTUATION LOTUSBRAHMI NUMBER ONEBRAHMI NUMBER TWOBRAHMI NUMBER THRE" +
"EBRAHMI NUMBER FOURBRAHMI NUMBER FIVEBRAHMI NUMBER SIXBRAHMI NUMBER SEVE" +
"NBRAHMI NUMBER EIGHTBRAHMI NUMBER NINEBRAHMI NUMBER TENBRAHMI NUMBER TWE" +
"NTYBRAHMI NUMBER THIRTYBRAHMI NUMBER FORTYBRAHMI NUMBER FIFTYBRAHMI NUMB" +
"ER SIXTYBRAHMI NUMBER SEVENTYBRAHMI NUMBER EIGHTYBRAHMI NUMBER NINETYBRA" +
"HMI NUMBER ONE HUNDREDBRAHMI NUMBER ONE THOUSANDBRAHMI DIGIT ZEROBRAHMI " +
"DIGIT ONEBRAHMI DIGIT TWOBRAHMI DIGIT THREEBRAHMI DIGIT FOURBRAHMI DIGIT" +
" FIVEBRAHMI DIGIT SIXBRAHMI DIGIT SEVENBRAHMI DIGIT EIGHTBRAHMI DIGIT NI" +
"NEBRAHMI SIGN OLD TAMIL VIRAMABRAHMI LETTER OLD TAMIL SHORT EBRAHMI LETT" +
"ER OLD TAMIL SHORT OBRAHMI VOWEL SIGN OLD TAMIL SHORT EBRAHMI VOWEL SIGN" +
" OLD TAMIL SHORT OBRAHMI LETTER OLD TAMIL LLABRAHMI NUMBER JOINERKAITHI " +
"SIGN CANDRABINDUKAITHI SIGN ANUSVARAKAITHI SIGN VISARGAKAITHI LETTER AKA" +
"ITHI LETTER AAKAITHI LETTER IKAITHI LETTER IIKAITHI LETTER UKAITHI LETTE" +
"R UUKAITHI LETTER EKAITHI LETTER AIKAITHI LETTER OKAITHI LETTER AUKAITHI" +
" LETTER KAKAITHI LETTER KHAKAITHI LETTER GAKAITHI LETTER GHAKAITHI LETTE" +
"R NGAKAITHI LETTER CAKAITHI LETTER CHAKAITHI LETTER JAKAITHI LETTER JHAK" +
"AITHI LETTER NYAKAITHI LETTER TTAKAITHI LETTER TTHAKAITHI LETTER DDAKAIT" +
"HI LETTER DDDHAKAITHI LETTER DDHAKAITHI LETTER RHAKAITHI LETTER NNAKAITH" +
"I LETTER TAKAITHI LETTER THAKAITHI LETTER DAKAITHI LETTER DHAKAITHI LETT" +
"ER NAKAITHI LETTER PAKAITHI LETTER PHAKAITHI LETTER BAKAITHI LETTER BHAK" +
"AITHI LETTER MAKAITHI LETTER YAKAITHI LETTER RAKAITHI LETTER LAKAITHI LE" +
"TTER VAKAITHI LETTER SHAKAITHI LETTER SSAKAITHI LETTER SAKAITHI LETTER H" +
"AKAITHI VOWEL SIGN AAKAITHI VOWEL SIGN IKAITHI VOWEL SIGN IIKAITHI VOWEL" +
" SIGN UKAITHI VOWEL SIGN UUKAITHI VOWEL SIGN EKAITHI VOWEL SIGN AIKAITHI" +
" VOWEL SIGN OKAITHI VOWEL SIGN AUKAITHI SIGN VIRAMAKAITHI SIGN NUKTAKAIT" +
"HI ABBREVIATION SIGNKAITHI ENUMERATION SIGNKAITHI NUMBER SIGNKAITHI SECT" +
"ION MARKKAITHI DOUBLE SECTION MARKKAITHI DANDAKAITHI DOUBLE DANDAKAITHI " +
"VOWEL SIGN VOCALIC RKAITHI NUMBER SIGN ABOVESORA SOMPENG LETTER SAHSORA " +
"SOMPENG LETTER TAHSORA SOMPENG LETTER BAHSORA SOMPENG LETTER CAHSORA SOM" +
"PENG LETTER DAHSORA SOMPENG LETTER GAHSORA SOMPENG LETTER MAHSORA SOMPEN" +
"G LETTER NGAHSORA SOMPENG LETTER LAHSORA SOMPENG LETTER NAHSORA SOMPENG " +
"LETTER VAHSORA SOMPENG LETTER PAHSORA SOMPENG LETTER YAHSORA SOMPENG LET" +
"TER RAHSORA SOMPENG LETTER HAHSORA SOMPENG LETTER KAHSORA SOMPENG LETTER" +
" JAHSORA SOMPENG LETTER NYAHSORA SOMPENG LETTER AHSORA SOMPENG LETTER EE" +
"HSORA SOMPENG LETTER IHSORA SOMPENG LETTER UHSORA SOMPENG LETTER OHSORA " +
"SOMPENG LETTER EHSORA SOMPENG LETTER MAESORA SOMPENG DIGIT ZEROSORA SOMP" +
"ENG DIGIT ONESORA SOMPENG DIGIT TWOSORA SOMPENG DIGIT THREESORA SOMPENG " +
"DIGIT FOURSORA SOMPENG DIGIT FIVESORA SOMPENG DIGIT SIXSORA SOMPENG DIGI" +
"T SEVENSORA SOMPENG DIGIT EIGHTSORA SOMPENG DIGIT NINECHAKMA SIGN CANDRA" +
"BINDUCHAKMA SIGN ANUSVARACHAKMA SIGN VISARGACHAKMA LETTER AACHAKMA LETTE" +
"R ICHAKMA LETTER UCHAKMA LETTER ECHAKMA LETTER KAACHAKMA LETTER KHAACHAK" +
"MA LETTER GAACHAKMA LETTER GHAACHAKMA LETTER NGAACHAKMA LETTER CAACHAKMA" +
" LETTER CHAACHAKMA LETTER JAACHAKMA LETTER JHAACHAKMA LETTER NYAACHAKMA " +
"LETTER TTAACHAKMA LETTER TTHAACHAKMA LETTER DDAACHAKMA LETTER DDHAACHAKM" +
"A LETTER NNAACHAKMA LETTER TAACHAKMA LETTER THAACHAKMA LETTER DAACHAKMA " +
"LETTER DHAACHAKMA LETTER NAACHAKMA LETTER PAACHAKMA LETTER PHAACHAKMA LE" +
"TTER BAACHAKMA LETTER BHAACHAKMA LETTER MAACHAKMA LETTER YYAACHAKMA LETT" +
"ER YAACHAKMA LETTER RAACHAKMA LETTER LAACHAKMA LETTER WAACHAKMA LETTER S" +
"AACHAKMA LETTER HAACHAKMA VOWEL SIGN ACHAKMA VOWEL SIGN ICHAKMA VOWEL SI" +
"GN IICHAKMA VOWEL SIGN UCHAKMA VOWEL SIGN UUCHAKMA VOWEL SIGN ECHAKMA VO" +
"WEL SIGN AICHAKMA VOWEL SIGN OCHAKMA VOWEL SIGN AUCHAKMA VOWEL SIGN OICH" +
"AKMA O MARKCHAKMA AU MARKCHAKMA VIRAMACHAKMA MAAYYAACHAKMA DIGIT ZEROCHA" +
"KMA DIGIT ONECHAKMA DIGIT TWOCHAKMA DIGIT THREECHAKMA DIGIT FOURCHAKMA D" +
"IGIT FIVECHAKMA DIGIT SIXCHAKMA DIGIT SEVENCHAKMA DIGIT EIGHTCHAKMA DIGI" +
"T NINECHAKMA SECTION MARKCHAKMA DANDACHAKMA DOUBLE DANDACHAKMA QUESTION " +
"MARKCHAKMA LETTER LHAACHAKMA VOWEL SIGN AACHAKMA VOWEL SIGN EICHAKMA LET" +
"TER VAAMAHAJANI LETTER AMAHAJANI LETTER IMAHAJANI LETTER UMAHAJANI LETTE" +
"R EMAHAJANI LETTER OMAHAJANI LETTER KAMAHAJANI LETTER KHAMAHAJANI LETTER" +
" GAMAHAJANI LETTER GHAMAHAJANI LETTER CAMAHAJANI LETTER CHAMAHAJANI LETT" +
"ER JAMAHAJANI LETTER JHAMAHAJANI LETTER NYAMAHAJANI LETTER TTAMAHAJANI L") + ("" +
"ETTER TTHAMAHAJANI LETTER DDAMAHAJANI LETTER DDHAMAHAJANI LETTER NNAMAHA" +
"JANI LETTER TAMAHAJANI LETTER THAMAHAJANI LETTER DAMAHAJANI LETTER DHAMA" +
"HAJANI LETTER NAMAHAJANI LETTER PAMAHAJANI LETTER PHAMAHAJANI LETTER BAM" +
"AHAJANI LETTER BHAMAHAJANI LETTER MAMAHAJANI LETTER RAMAHAJANI LETTER LA" +
"MAHAJANI LETTER VAMAHAJANI LETTER SAMAHAJANI LETTER HAMAHAJANI LETTER RR" +
"AMAHAJANI SIGN NUKTAMAHAJANI ABBREVIATION SIGNMAHAJANI SECTION MARKMAHAJ" +
"ANI LIGATURE SHRISHARADA SIGN CANDRABINDUSHARADA SIGN ANUSVARASHARADA SI" +
"GN VISARGASHARADA LETTER ASHARADA LETTER AASHARADA LETTER ISHARADA LETTE" +
"R IISHARADA LETTER USHARADA LETTER UUSHARADA LETTER VOCALIC RSHARADA LET" +
"TER VOCALIC RRSHARADA LETTER VOCALIC LSHARADA LETTER VOCALIC LLSHARADA L" +
"ETTER ESHARADA LETTER AISHARADA LETTER OSHARADA LETTER AUSHARADA LETTER " +
"KASHARADA LETTER KHASHARADA LETTER GASHARADA LETTER GHASHARADA LETTER NG" +
"ASHARADA LETTER CASHARADA LETTER CHASHARADA LETTER JASHARADA LETTER JHAS" +
"HARADA LETTER NYASHARADA LETTER TTASHARADA LETTER TTHASHARADA LETTER DDA" +
"SHARADA LETTER DDHASHARADA LETTER NNASHARADA LETTER TASHARADA LETTER THA" +
"SHARADA LETTER DASHARADA LETTER DHASHARADA LETTER NASHARADA LETTER PASHA" +
"RADA LETTER PHASHARADA LETTER BASHARADA LETTER BHASHARADA LETTER MASHARA" +
"DA LETTER YASHARADA LETTER RASHARADA LETTER LASHARADA LETTER LLASHARADA " +
"LETTER VASHARADA LETTER SHASHARADA LETTER SSASHARADA LETTER SASHARADA LE" +
"TTER HASHARADA VOWEL SIGN AASHARADA VOWEL SIGN ISHARADA VOWEL SIGN IISHA" +
"RADA VOWEL SIGN USHARADA VOWEL SIGN UUSHARADA VOWEL SIGN VOCALIC RSHARAD" +
"A VOWEL SIGN VOCALIC RRSHARADA VOWEL SIGN VOCALIC LSHARADA VOWEL SIGN VO" +
"CALIC LLSHARADA VOWEL SIGN ESHARADA VOWEL SIGN AISHARADA VOWEL SIGN OSHA" +
"RADA VOWEL SIGN AUSHARADA SIGN VIRAMASHARADA SIGN AVAGRAHASHARADA SIGN J" +
"IHVAMULIYASHARADA SIGN UPADHMANIYASHARADA OMSHARADA DANDASHARADA DOUBLE " +
"DANDASHARADA ABBREVIATION SIGNSHARADA SEPARATORSHARADA SANDHI MARKSHARAD" +
"A SIGN NUKTASHARADA VOWEL MODIFIER MARKSHARADA EXTRA SHORT VOWEL MARKSHA" +
"RADA SUTRA MARKSHARADA VOWEL SIGN PRISHTHAMATRA ESHARADA SIGN INVERTED C" +
"ANDRABINDUSHARADA DIGIT ZEROSHARADA DIGIT ONESHARADA DIGIT TWOSHARADA DI" +
"GIT THREESHARADA DIGIT FOURSHARADA DIGIT FIVESHARADA DIGIT SIXSHARADA DI" +
"GIT SEVENSHARADA DIGIT EIGHTSHARADA DIGIT NINESHARADA EKAMSHARADA SIGN S" +
"IDDHAMSHARADA HEADSTROKESHARADA CONTINUATION SIGNSHARADA SECTION MARK-1S" +
"HARADA SECTION MARK-2SINHALA ARCHAIC DIGIT ONESINHALA ARCHAIC DIGIT TWOS" +
"INHALA ARCHAIC DIGIT THREESINHALA ARCHAIC DIGIT FOURSINHALA ARCHAIC DIGI" +
"T FIVESINHALA ARCHAIC DIGIT SIXSINHALA ARCHAIC DIGIT SEVENSINHALA ARCHAI" +
"C DIGIT EIGHTSINHALA ARCHAIC DIGIT NINESINHALA ARCHAIC NUMBER TENSINHALA" +
" ARCHAIC NUMBER TWENTYSINHALA ARCHAIC NUMBER THIRTYSINHALA ARCHAIC NUMBE" +
"R FORTYSINHALA ARCHAIC NUMBER FIFTYSINHALA ARCHAIC NUMBER SIXTYSINHALA A" +
"RCHAIC NUMBER SEVENTYSINHALA ARCHAIC NUMBER EIGHTYSINHALA ARCHAIC NUMBER" +
" NINETYSINHALA ARCHAIC NUMBER ONE HUNDREDSINHALA ARCHAIC NUMBER ONE THOU" +
"SANDKHOJKI LETTER AKHOJKI LETTER AAKHOJKI LETTER IKHOJKI LETTER UKHOJKI " +
"LETTER EKHOJKI LETTER AIKHOJKI LETTER OKHOJKI LETTER AUKHOJKI LETTER KAK" +
"HOJKI LETTER KHAKHOJKI LETTER GAKHOJKI LETTER GGAKHOJKI LETTER GHAKHOJKI" +
" LETTER NGAKHOJKI LETTER CAKHOJKI LETTER CHAKHOJKI LETTER JAKHOJKI LETTE" +
"R JJAKHOJKI LETTER NYAKHOJKI LETTER TTAKHOJKI LETTER TTHAKHOJKI LETTER D" +
"DAKHOJKI LETTER DDHAKHOJKI LETTER NNAKHOJKI LETTER TAKHOJKI LETTER THAKH" +
"OJKI LETTER DAKHOJKI LETTER DDDAKHOJKI LETTER DHAKHOJKI LETTER NAKHOJKI " +
"LETTER PAKHOJKI LETTER PHAKHOJKI LETTER BAKHOJKI LETTER BBAKHOJKI LETTER" +
" BHAKHOJKI LETTER MAKHOJKI LETTER YAKHOJKI LETTER RAKHOJKI LETTER LAKHOJ" +
"KI LETTER VAKHOJKI LETTER SAKHOJKI LETTER HAKHOJKI LETTER LLAKHOJKI VOWE" +
"L SIGN AAKHOJKI VOWEL SIGN IKHOJKI VOWEL SIGN IIKHOJKI VOWEL SIGN UKHOJK" +
"I VOWEL SIGN EKHOJKI VOWEL SIGN AIKHOJKI VOWEL SIGN OKHOJKI VOWEL SIGN A" +
"UKHOJKI SIGN ANUSVARAKHOJKI SIGN VIRAMAKHOJKI SIGN NUKTAKHOJKI SIGN SHAD" +
"DAKHOJKI DANDAKHOJKI DOUBLE DANDAKHOJKI WORD SEPARATORKHOJKI SECTION MAR" +
"KKHOJKI DOUBLE SECTION MARKKHOJKI ABBREVIATION SIGNKHOJKI SIGN SUKUNKHOJ" +
"KI LETTER QAKHOJKI LETTER SHORT IKHOJKI VOWEL SIGN VOCALIC RMULTANI LETT" +
"ER AMULTANI LETTER IMULTANI LETTER UMULTANI LETTER EMULTANI LETTER KAMUL" +
"TANI LETTER KHAMULTANI LETTER GAMULTANI LETTER GHAMULTANI LETTER CAMULTA" +
"NI LETTER CHAMULTANI LETTER JAMULTANI LETTER JJAMULTANI LETTER NYAMULTAN" +
"I LETTER TTAMULTANI LETTER TTHAMULTANI LETTER DDAMULTANI LETTER DDDAMULT" +
"ANI LETTER DDHAMULTANI LETTER NNAMULTANI LETTER TAMULTANI LETTER THAMULT" +
"ANI LETTER DAMULTANI LETTER DHAMULTANI LETTER NAMULTANI LETTER PAMULTANI" +
" LETTER PHAMULTANI LETTER BAMULTANI LETTER BHAMULTANI LETTER MAMULTANI L" +
"ETTER YAMULTANI LETTER RAMULTANI LETTER LAMULTANI LETTER VAMULTANI LETTE") + ("" +
"R SAMULTANI LETTER HAMULTANI LETTER RRAMULTANI LETTER RHAMULTANI SECTION" +
" MARKKHUDAWADI LETTER AKHUDAWADI LETTER AAKHUDAWADI LETTER IKHUDAWADI LE" +
"TTER IIKHUDAWADI LETTER UKHUDAWADI LETTER UUKHUDAWADI LETTER EKHUDAWADI " +
"LETTER AIKHUDAWADI LETTER OKHUDAWADI LETTER AUKHUDAWADI LETTER KAKHUDAWA" +
"DI LETTER KHAKHUDAWADI LETTER GAKHUDAWADI LETTER GGAKHUDAWADI LETTER GHA" +
"KHUDAWADI LETTER NGAKHUDAWADI LETTER CAKHUDAWADI LETTER CHAKHUDAWADI LET" +
"TER JAKHUDAWADI LETTER JJAKHUDAWADI LETTER JHAKHUDAWADI LETTER NYAKHUDAW" +
"ADI LETTER TTAKHUDAWADI LETTER TTHAKHUDAWADI LETTER DDAKHUDAWADI LETTER " +
"DDDAKHUDAWADI LETTER RRAKHUDAWADI LETTER DDHAKHUDAWADI LETTER NNAKHUDAWA" +
"DI LETTER TAKHUDAWADI LETTER THAKHUDAWADI LETTER DAKHUDAWADI LETTER DHAK" +
"HUDAWADI LETTER NAKHUDAWADI LETTER PAKHUDAWADI LETTER PHAKHUDAWADI LETTE" +
"R BAKHUDAWADI LETTER BBAKHUDAWADI LETTER BHAKHUDAWADI LETTER MAKHUDAWADI" +
" LETTER YAKHUDAWADI LETTER RAKHUDAWADI LETTER LAKHUDAWADI LETTER VAKHUDA" +
"WADI LETTER SHAKHUDAWADI LETTER SAKHUDAWADI LETTER HAKHUDAWADI SIGN ANUS" +
"VARAKHUDAWADI VOWEL SIGN AAKHUDAWADI VOWEL SIGN IKHUDAWADI VOWEL SIGN II" +
"KHUDAWADI VOWEL SIGN UKHUDAWADI VOWEL SIGN UUKHUDAWADI VOWEL SIGN EKHUDA" +
"WADI VOWEL SIGN AIKHUDAWADI VOWEL SIGN OKHUDAWADI VOWEL SIGN AUKHUDAWADI" +
" SIGN NUKTAKHUDAWADI SIGN VIRAMAKHUDAWADI DIGIT ZEROKHUDAWADI DIGIT ONEK" +
"HUDAWADI DIGIT TWOKHUDAWADI DIGIT THREEKHUDAWADI DIGIT FOURKHUDAWADI DIG" +
"IT FIVEKHUDAWADI DIGIT SIXKHUDAWADI DIGIT SEVENKHUDAWADI DIGIT EIGHTKHUD" +
"AWADI DIGIT NINEGRANTHA SIGN COMBINING ANUSVARA ABOVEGRANTHA SIGN CANDRA" +
"BINDUGRANTHA SIGN ANUSVARAGRANTHA SIGN VISARGAGRANTHA LETTER AGRANTHA LE" +
"TTER AAGRANTHA LETTER IGRANTHA LETTER IIGRANTHA LETTER UGRANTHA LETTER U" +
"UGRANTHA LETTER VOCALIC RGRANTHA LETTER VOCALIC LGRANTHA LETTER EEGRANTH" +
"A LETTER AIGRANTHA LETTER OOGRANTHA LETTER AUGRANTHA LETTER KAGRANTHA LE" +
"TTER KHAGRANTHA LETTER GAGRANTHA LETTER GHAGRANTHA LETTER NGAGRANTHA LET" +
"TER CAGRANTHA LETTER CHAGRANTHA LETTER JAGRANTHA LETTER JHAGRANTHA LETTE" +
"R NYAGRANTHA LETTER TTAGRANTHA LETTER TTHAGRANTHA LETTER DDAGRANTHA LETT" +
"ER DDHAGRANTHA LETTER NNAGRANTHA LETTER TAGRANTHA LETTER THAGRANTHA LETT" +
"ER DAGRANTHA LETTER DHAGRANTHA LETTER NAGRANTHA LETTER PAGRANTHA LETTER " +
"PHAGRANTHA LETTER BAGRANTHA LETTER BHAGRANTHA LETTER MAGRANTHA LETTER YA" +
"GRANTHA LETTER RAGRANTHA LETTER LAGRANTHA LETTER LLAGRANTHA LETTER VAGRA" +
"NTHA LETTER SHAGRANTHA LETTER SSAGRANTHA LETTER SAGRANTHA LETTER HACOMBI" +
"NING BINDU BELOWGRANTHA SIGN NUKTAGRANTHA SIGN AVAGRAHAGRANTHA VOWEL SIG" +
"N AAGRANTHA VOWEL SIGN IGRANTHA VOWEL SIGN IIGRANTHA VOWEL SIGN UGRANTHA" +
" VOWEL SIGN UUGRANTHA VOWEL SIGN VOCALIC RGRANTHA VOWEL SIGN VOCALIC RRG" +
"RANTHA VOWEL SIGN EEGRANTHA VOWEL SIGN AIGRANTHA VOWEL SIGN OOGRANTHA VO" +
"WEL SIGN AUGRANTHA SIGN VIRAMAGRANTHA OMGRANTHA AU LENGTH MARKGRANTHA SI" +
"GN PLUTAGRANTHA LETTER VEDIC ANUSVARAGRANTHA LETTER VEDIC DOUBLE ANUSVAR" +
"AGRANTHA LETTER VOCALIC RRGRANTHA LETTER VOCALIC LLGRANTHA VOWEL SIGN VO" +
"CALIC LGRANTHA VOWEL SIGN VOCALIC LLCOMBINING GRANTHA DIGIT ZEROCOMBININ" +
"G GRANTHA DIGIT ONECOMBINING GRANTHA DIGIT TWOCOMBINING GRANTHA DIGIT TH" +
"REECOMBINING GRANTHA DIGIT FOURCOMBINING GRANTHA DIGIT FIVECOMBINING GRA" +
"NTHA DIGIT SIXCOMBINING GRANTHA LETTER ACOMBINING GRANTHA LETTER KACOMBI" +
"NING GRANTHA LETTER NACOMBINING GRANTHA LETTER VICOMBINING GRANTHA LETTE" +
"R PANEWA LETTER ANEWA LETTER AANEWA LETTER INEWA LETTER IINEWA LETTER UN" +
"EWA LETTER UUNEWA LETTER VOCALIC RNEWA LETTER VOCALIC RRNEWA LETTER VOCA" +
"LIC LNEWA LETTER VOCALIC LLNEWA LETTER ENEWA LETTER AINEWA LETTER ONEWA " +
"LETTER AUNEWA LETTER KANEWA LETTER KHANEWA LETTER GANEWA LETTER GHANEWA " +
"LETTER NGANEWA LETTER NGHANEWA LETTER CANEWA LETTER CHANEWA LETTER JANEW" +
"A LETTER JHANEWA LETTER NYANEWA LETTER NYHANEWA LETTER TTANEWA LETTER TT" +
"HANEWA LETTER DDANEWA LETTER DDHANEWA LETTER NNANEWA LETTER TANEWA LETTE" +
"R THANEWA LETTER DANEWA LETTER DHANEWA LETTER NANEWA LETTER NHANEWA LETT" +
"ER PANEWA LETTER PHANEWA LETTER BANEWA LETTER BHANEWA LETTER MANEWA LETT" +
"ER MHANEWA LETTER YANEWA LETTER RANEWA LETTER RHANEWA LETTER LANEWA LETT" +
"ER LHANEWA LETTER WANEWA LETTER SHANEWA LETTER SSANEWA LETTER SANEWA LET" +
"TER HANEWA VOWEL SIGN AANEWA VOWEL SIGN INEWA VOWEL SIGN IINEWA VOWEL SI" +
"GN UNEWA VOWEL SIGN UUNEWA VOWEL SIGN VOCALIC RNEWA VOWEL SIGN VOCALIC R" +
"RNEWA VOWEL SIGN VOCALIC LNEWA VOWEL SIGN VOCALIC LLNEWA VOWEL SIGN ENEW" +
"A VOWEL SIGN AINEWA VOWEL SIGN ONEWA VOWEL SIGN AUNEWA SIGN VIRAMANEWA S" +
"IGN CANDRABINDUNEWA SIGN ANUSVARANEWA SIGN VISARGANEWA SIGN NUKTANEWA SI" +
"GN AVAGRAHANEWA SIGN FINAL ANUSVARANEWA OMNEWA SIDDHINEWA DANDANEWA DOUB" +
"LE DANDANEWA COMMANEWA GAP FILLERNEWA ABBREVIATION SIGNNEWA DIGIT ZERONE" +
"WA DIGIT ONENEWA DIGIT TWONEWA DIGIT THREENEWA DIGIT FOURNEWA DIGIT FIVE") + ("" +
"NEWA DIGIT SIXNEWA DIGIT SEVENNEWA DIGIT EIGHTNEWA DIGIT NINENEWA DOUBLE" +
" COMMANEWA PLACEHOLDER MARKNEWA INSERTION SIGNNEWA SANDHI MARKNEWA LETTE" +
"R VEDIC ANUSVARANEWA SIGN JIHVAMULIYANEWA SIGN UPADHMANIYATIRHUTA ANJITI" +
"RHUTA LETTER ATIRHUTA LETTER AATIRHUTA LETTER ITIRHUTA LETTER IITIRHUTA " +
"LETTER UTIRHUTA LETTER UUTIRHUTA LETTER VOCALIC RTIRHUTA LETTER VOCALIC " +
"RRTIRHUTA LETTER VOCALIC LTIRHUTA LETTER VOCALIC LLTIRHUTA LETTER ETIRHU" +
"TA LETTER AITIRHUTA LETTER OTIRHUTA LETTER AUTIRHUTA LETTER KATIRHUTA LE" +
"TTER KHATIRHUTA LETTER GATIRHUTA LETTER GHATIRHUTA LETTER NGATIRHUTA LET" +
"TER CATIRHUTA LETTER CHATIRHUTA LETTER JATIRHUTA LETTER JHATIRHUTA LETTE" +
"R NYATIRHUTA LETTER TTATIRHUTA LETTER TTHATIRHUTA LETTER DDATIRHUTA LETT" +
"ER DDHATIRHUTA LETTER NNATIRHUTA LETTER TATIRHUTA LETTER THATIRHUTA LETT" +
"ER DATIRHUTA LETTER DHATIRHUTA LETTER NATIRHUTA LETTER PATIRHUTA LETTER " +
"PHATIRHUTA LETTER BATIRHUTA LETTER BHATIRHUTA LETTER MATIRHUTA LETTER YA" +
"TIRHUTA LETTER RATIRHUTA LETTER LATIRHUTA LETTER VATIRHUTA LETTER SHATIR" +
"HUTA LETTER SSATIRHUTA LETTER SATIRHUTA LETTER HATIRHUTA VOWEL SIGN AATI" +
"RHUTA VOWEL SIGN ITIRHUTA VOWEL SIGN IITIRHUTA VOWEL SIGN UTIRHUTA VOWEL" +
" SIGN UUTIRHUTA VOWEL SIGN VOCALIC RTIRHUTA VOWEL SIGN VOCALIC RRTIRHUTA" +
" VOWEL SIGN VOCALIC LTIRHUTA VOWEL SIGN VOCALIC LLTIRHUTA VOWEL SIGN ETI" +
"RHUTA VOWEL SIGN SHORT ETIRHUTA VOWEL SIGN AITIRHUTA VOWEL SIGN OTIRHUTA" +
" VOWEL SIGN SHORT OTIRHUTA VOWEL SIGN AUTIRHUTA SIGN CANDRABINDUTIRHUTA " +
"SIGN ANUSVARATIRHUTA SIGN VISARGATIRHUTA SIGN VIRAMATIRHUTA SIGN NUKTATI" +
"RHUTA SIGN AVAGRAHATIRHUTA GVANGTIRHUTA ABBREVIATION SIGNTIRHUTA OMTIRHU" +
"TA DIGIT ZEROTIRHUTA DIGIT ONETIRHUTA DIGIT TWOTIRHUTA DIGIT THREETIRHUT" +
"A DIGIT FOURTIRHUTA DIGIT FIVETIRHUTA DIGIT SIXTIRHUTA DIGIT SEVENTIRHUT" +
"A DIGIT EIGHTTIRHUTA DIGIT NINESIDDHAM LETTER ASIDDHAM LETTER AASIDDHAM " +
"LETTER ISIDDHAM LETTER IISIDDHAM LETTER USIDDHAM LETTER UUSIDDHAM LETTER" +
" VOCALIC RSIDDHAM LETTER VOCALIC RRSIDDHAM LETTER VOCALIC LSIDDHAM LETTE" +
"R VOCALIC LLSIDDHAM LETTER ESIDDHAM LETTER AISIDDHAM LETTER OSIDDHAM LET" +
"TER AUSIDDHAM LETTER KASIDDHAM LETTER KHASIDDHAM LETTER GASIDDHAM LETTER" +
" GHASIDDHAM LETTER NGASIDDHAM LETTER CASIDDHAM LETTER CHASIDDHAM LETTER " +
"JASIDDHAM LETTER JHASIDDHAM LETTER NYASIDDHAM LETTER TTASIDDHAM LETTER T" +
"THASIDDHAM LETTER DDASIDDHAM LETTER DDHASIDDHAM LETTER NNASIDDHAM LETTER" +
" TASIDDHAM LETTER THASIDDHAM LETTER DASIDDHAM LETTER DHASIDDHAM LETTER N" +
"ASIDDHAM LETTER PASIDDHAM LETTER PHASIDDHAM LETTER BASIDDHAM LETTER BHAS" +
"IDDHAM LETTER MASIDDHAM LETTER YASIDDHAM LETTER RASIDDHAM LETTER LASIDDH" +
"AM LETTER VASIDDHAM LETTER SHASIDDHAM LETTER SSASIDDHAM LETTER SASIDDHAM" +
" LETTER HASIDDHAM VOWEL SIGN AASIDDHAM VOWEL SIGN ISIDDHAM VOWEL SIGN II" +
"SIDDHAM VOWEL SIGN USIDDHAM VOWEL SIGN UUSIDDHAM VOWEL SIGN VOCALIC RSID" +
"DHAM VOWEL SIGN VOCALIC RRSIDDHAM VOWEL SIGN ESIDDHAM VOWEL SIGN AISIDDH" +
"AM VOWEL SIGN OSIDDHAM VOWEL SIGN AUSIDDHAM SIGN CANDRABINDUSIDDHAM SIGN" +
" ANUSVARASIDDHAM SIGN VISARGASIDDHAM SIGN VIRAMASIDDHAM SIGN NUKTASIDDHA" +
"M SIGN SIDDHAMSIDDHAM DANDASIDDHAM DOUBLE DANDASIDDHAM SEPARATOR DOTSIDD" +
"HAM SEPARATOR BARSIDDHAM REPETITION MARK-1SIDDHAM REPETITION MARK-2SIDDH" +
"AM REPETITION MARK-3SIDDHAM END OF TEXT MARKSIDDHAM SECTION MARK WITH TR" +
"IDENT AND U-SHAPED ORNAMENTSSIDDHAM SECTION MARK WITH TRIDENT AND DOTTED" +
" CRESCENTSSIDDHAM SECTION MARK WITH RAYS AND DOTTED CRESCENTSSIDDHAM SEC" +
"TION MARK WITH RAYS AND DOTTED DOUBLE CRESCENTSSIDDHAM SECTION MARK WITH" +
" RAYS AND DOTTED TRIPLE CRESCENTSSIDDHAM SECTION MARK DOUBLE RINGSIDDHAM" +
" SECTION MARK DOUBLE RING WITH RAYSSIDDHAM SECTION MARK WITH DOUBLE CRES" +
"CENTSSIDDHAM SECTION MARK WITH TRIPLE CRESCENTSSIDDHAM SECTION MARK WITH" +
" QUADRUPLE CRESCENTSSIDDHAM SECTION MARK WITH SEPTUPLE CRESCENTSSIDDHAM " +
"SECTION MARK WITH CIRCLES AND RAYSSIDDHAM SECTION MARK WITH CIRCLES AND " +
"TWO ENCLOSURESSIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURESSIDDH" +
"AM LETTER THREE-CIRCLE ALTERNATE ISIDDHAM LETTER TWO-CIRCLE ALTERNATE IS" +
"IDDHAM LETTER TWO-CIRCLE ALTERNATE IISIDDHAM LETTER ALTERNATE USIDDHAM V" +
"OWEL SIGN ALTERNATE USIDDHAM VOWEL SIGN ALTERNATE UUMODI LETTER AMODI LE" +
"TTER AAMODI LETTER IMODI LETTER IIMODI LETTER UMODI LETTER UUMODI LETTER" +
" VOCALIC RMODI LETTER VOCALIC RRMODI LETTER VOCALIC LMODI LETTER VOCALIC" +
" LLMODI LETTER EMODI LETTER AIMODI LETTER OMODI LETTER AUMODI LETTER KAM" +
"ODI LETTER KHAMODI LETTER GAMODI LETTER GHAMODI LETTER NGAMODI LETTER CA" +
"MODI LETTER CHAMODI LETTER JAMODI LETTER JHAMODI LETTER NYAMODI LETTER T" +
"TAMODI LETTER TTHAMODI LETTER DDAMODI LETTER DDHAMODI LETTER NNAMODI LET" +
"TER TAMODI LETTER THAMODI LETTER DAMODI LETTER DHAMODI LETTER NAMODI LET" +
"TER PAMODI LETTER PHAMODI LETTER BAMODI LETTER BHAMODI LETTER MAMODI LET") + ("" +
"TER YAMODI LETTER RAMODI LETTER LAMODI LETTER VAMODI LETTER SHAMODI LETT" +
"ER SSAMODI LETTER SAMODI LETTER HAMODI LETTER LLAMODI VOWEL SIGN AAMODI " +
"VOWEL SIGN IMODI VOWEL SIGN IIMODI VOWEL SIGN UMODI VOWEL SIGN UUMODI VO" +
"WEL SIGN VOCALIC RMODI VOWEL SIGN VOCALIC RRMODI VOWEL SIGN VOCALIC LMOD" +
"I VOWEL SIGN VOCALIC LLMODI VOWEL SIGN EMODI VOWEL SIGN AIMODI VOWEL SIG" +
"N OMODI VOWEL SIGN AUMODI SIGN ANUSVARAMODI SIGN VISARGAMODI SIGN VIRAMA" +
"MODI SIGN ARDHACANDRAMODI DANDAMODI DOUBLE DANDAMODI ABBREVIATION SIGNMO" +
"DI SIGN HUVAMODI DIGIT ZEROMODI DIGIT ONEMODI DIGIT TWOMODI DIGIT THREEM" +
"ODI DIGIT FOURMODI DIGIT FIVEMODI DIGIT SIXMODI DIGIT SEVENMODI DIGIT EI" +
"GHTMODI DIGIT NINEMONGOLIAN BIRGA WITH ORNAMENTMONGOLIAN ROTATED BIRGAMO" +
"NGOLIAN DOUBLE BIRGA WITH ORNAMENTMONGOLIAN TRIPLE BIRGA WITH ORNAMENTMO" +
"NGOLIAN BIRGA WITH DOUBLE ORNAMENTMONGOLIAN ROTATED BIRGA WITH ORNAMENTM" +
"ONGOLIAN ROTATED BIRGA WITH DOUBLE ORNAMENTMONGOLIAN INVERTED BIRGAMONGO" +
"LIAN INVERTED BIRGA WITH DOUBLE ORNAMENTMONGOLIAN SWIRL BIRGAMONGOLIAN S" +
"WIRL BIRGA WITH ORNAMENTMONGOLIAN SWIRL BIRGA WITH DOUBLE ORNAMENTMONGOL" +
"IAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENTTAKRI LETTER ATAKRI LETTER AA" +
"TAKRI LETTER ITAKRI LETTER IITAKRI LETTER UTAKRI LETTER UUTAKRI LETTER E" +
"TAKRI LETTER AITAKRI LETTER OTAKRI LETTER AUTAKRI LETTER KATAKRI LETTER " +
"KHATAKRI LETTER GATAKRI LETTER GHATAKRI LETTER NGATAKRI LETTER CATAKRI L" +
"ETTER CHATAKRI LETTER JATAKRI LETTER JHATAKRI LETTER NYATAKRI LETTER TTA" +
"TAKRI LETTER TTHATAKRI LETTER DDATAKRI LETTER DDHATAKRI LETTER NNATAKRI " +
"LETTER TATAKRI LETTER THATAKRI LETTER DATAKRI LETTER DHATAKRI LETTER NAT" +
"AKRI LETTER PATAKRI LETTER PHATAKRI LETTER BATAKRI LETTER BHATAKRI LETTE" +
"R MATAKRI LETTER YATAKRI LETTER RATAKRI LETTER LATAKRI LETTER VATAKRI LE" +
"TTER SHATAKRI LETTER SATAKRI LETTER HATAKRI LETTER RRATAKRI SIGN ANUSVAR" +
"ATAKRI SIGN VISARGATAKRI VOWEL SIGN AATAKRI VOWEL SIGN ITAKRI VOWEL SIGN" +
" IITAKRI VOWEL SIGN UTAKRI VOWEL SIGN UUTAKRI VOWEL SIGN ETAKRI VOWEL SI" +
"GN AITAKRI VOWEL SIGN OTAKRI VOWEL SIGN AUTAKRI SIGN VIRAMATAKRI SIGN NU" +
"KTATAKRI LETTER ARCHAIC KHATAKRI ABBREVIATION SIGNTAKRI DIGIT ZEROTAKRI " +
"DIGIT ONETAKRI DIGIT TWOTAKRI DIGIT THREETAKRI DIGIT FOURTAKRI DIGIT FIV" +
"ETAKRI DIGIT SIXTAKRI DIGIT SEVENTAKRI DIGIT EIGHTTAKRI DIGIT NINEAHOM L" +
"ETTER KAAHOM LETTER KHAAHOM LETTER NGAAHOM LETTER NAAHOM LETTER TAAHOM L" +
"ETTER ALTERNATE TAAHOM LETTER PAAHOM LETTER PHAAHOM LETTER BAAHOM LETTER" +
" MAAHOM LETTER JAAHOM LETTER CHAAHOM LETTER THAAHOM LETTER RAAHOM LETTER" +
" LAAHOM LETTER SAAHOM LETTER NYAAHOM LETTER HAAHOM LETTER AAHOM LETTER D" +
"AAHOM LETTER DHAAHOM LETTER GAAHOM LETTER ALTERNATE GAAHOM LETTER GHAAHO" +
"M LETTER BHAAHOM LETTER JHAAHOM LETTER ALTERNATE BAAHOM CONSONANT SIGN M" +
"EDIAL LAAHOM CONSONANT SIGN MEDIAL RAAHOM CONSONANT SIGN MEDIAL LIGATING" +
" RAAHOM VOWEL SIGN AAHOM VOWEL SIGN AAAHOM VOWEL SIGN IAHOM VOWEL SIGN I" +
"IAHOM VOWEL SIGN UAHOM VOWEL SIGN UUAHOM VOWEL SIGN EAHOM VOWEL SIGN AWA" +
"HOM VOWEL SIGN OAHOM VOWEL SIGN AIAHOM VOWEL SIGN AMAHOM SIGN KILLERAHOM" +
" DIGIT ZEROAHOM DIGIT ONEAHOM DIGIT TWOAHOM DIGIT THREEAHOM DIGIT FOURAH" +
"OM DIGIT FIVEAHOM DIGIT SIXAHOM DIGIT SEVENAHOM DIGIT EIGHTAHOM DIGIT NI" +
"NEAHOM NUMBER TENAHOM NUMBER TWENTYAHOM SIGN SMALL SECTIONAHOM SIGN SECT" +
"IONAHOM SIGN RULAIAHOM SYMBOL VIAHOM LETTER CAAHOM LETTER TTAAHOM LETTER" +
" TTHAAHOM LETTER DDAAHOM LETTER DDHAAHOM LETTER NNAAHOM LETTER LLADOGRA " +
"LETTER ADOGRA LETTER AADOGRA LETTER IDOGRA LETTER IIDOGRA LETTER UDOGRA " +
"LETTER UUDOGRA LETTER EDOGRA LETTER AIDOGRA LETTER ODOGRA LETTER AUDOGRA" +
" LETTER KADOGRA LETTER KHADOGRA LETTER GADOGRA LETTER GHADOGRA LETTER NG" +
"ADOGRA LETTER CADOGRA LETTER CHADOGRA LETTER JADOGRA LETTER JHADOGRA LET" +
"TER NYADOGRA LETTER TTADOGRA LETTER TTHADOGRA LETTER DDADOGRA LETTER DDH" +
"ADOGRA LETTER NNADOGRA LETTER TADOGRA LETTER THADOGRA LETTER DADOGRA LET" +
"TER DHADOGRA LETTER NADOGRA LETTER PADOGRA LETTER PHADOGRA LETTER BADOGR" +
"A LETTER BHADOGRA LETTER MADOGRA LETTER YADOGRA LETTER RADOGRA LETTER LA" +
"DOGRA LETTER VADOGRA LETTER SHADOGRA LETTER SSADOGRA LETTER SADOGRA LETT" +
"ER HADOGRA LETTER RRADOGRA VOWEL SIGN AADOGRA VOWEL SIGN IDOGRA VOWEL SI" +
"GN IIDOGRA VOWEL SIGN UDOGRA VOWEL SIGN UUDOGRA VOWEL SIGN VOCALIC RDOGR" +
"A VOWEL SIGN VOCALIC RRDOGRA VOWEL SIGN EDOGRA VOWEL SIGN AIDOGRA VOWEL " +
"SIGN ODOGRA VOWEL SIGN AUDOGRA SIGN ANUSVARADOGRA SIGN VISARGADOGRA SIGN" +
" VIRAMADOGRA SIGN NUKTADOGRA ABBREVIATION SIGNWARANG CITI CAPITAL LETTER" +
" NGAAWARANG CITI CAPITAL LETTER AWARANG CITI CAPITAL LETTER WIWARANG CIT" +
"I CAPITAL LETTER YUWARANG CITI CAPITAL LETTER YAWARANG CITI CAPITAL LETT" +
"ER YOWARANG CITI CAPITAL LETTER IIWARANG CITI CAPITAL LETTER UUWARANG CI" +
"TI CAPITAL LETTER EWARANG CITI CAPITAL LETTER OWARANG CITI CAPITAL LETTE") + ("" +
"R ANGWARANG CITI CAPITAL LETTER GAWARANG CITI CAPITAL LETTER KOWARANG CI" +
"TI CAPITAL LETTER ENYWARANG CITI CAPITAL LETTER YUJWARANG CITI CAPITAL L" +
"ETTER UCWARANG CITI CAPITAL LETTER ENNWARANG CITI CAPITAL LETTER ODDWARA" +
"NG CITI CAPITAL LETTER TTEWARANG CITI CAPITAL LETTER NUNGWARANG CITI CAP" +
"ITAL LETTER DAWARANG CITI CAPITAL LETTER ATWARANG CITI CAPITAL LETTER AM" +
"WARANG CITI CAPITAL LETTER BUWARANG CITI CAPITAL LETTER PUWARANG CITI CA" +
"PITAL LETTER HIYOWARANG CITI CAPITAL LETTER HOLOWARANG CITI CAPITAL LETT" +
"ER HORRWARANG CITI CAPITAL LETTER HARWARANG CITI CAPITAL LETTER SSUUWARA" +
"NG CITI CAPITAL LETTER SIIWARANG CITI CAPITAL LETTER VIYOWARANG CITI SMA" +
"LL LETTER NGAAWARANG CITI SMALL LETTER AWARANG CITI SMALL LETTER WIWARAN" +
"G CITI SMALL LETTER YUWARANG CITI SMALL LETTER YAWARANG CITI SMALL LETTE" +
"R YOWARANG CITI SMALL LETTER IIWARANG CITI SMALL LETTER UUWARANG CITI SM" +
"ALL LETTER EWARANG CITI SMALL LETTER OWARANG CITI SMALL LETTER ANGWARANG" +
" CITI SMALL LETTER GAWARANG CITI SMALL LETTER KOWARANG CITI SMALL LETTER" +
" ENYWARANG CITI SMALL LETTER YUJWARANG CITI SMALL LETTER UCWARANG CITI S" +
"MALL LETTER ENNWARANG CITI SMALL LETTER ODDWARANG CITI SMALL LETTER TTEW" +
"ARANG CITI SMALL LETTER NUNGWARANG CITI SMALL LETTER DAWARANG CITI SMALL" +
" LETTER ATWARANG CITI SMALL LETTER AMWARANG CITI SMALL LETTER BUWARANG C" +
"ITI SMALL LETTER PUWARANG CITI SMALL LETTER HIYOWARANG CITI SMALL LETTER" +
" HOLOWARANG CITI SMALL LETTER HORRWARANG CITI SMALL LETTER HARWARANG CIT" +
"I SMALL LETTER SSUUWARANG CITI SMALL LETTER SIIWARANG CITI SMALL LETTER " +
"VIYOWARANG CITI DIGIT ZEROWARANG CITI DIGIT ONEWARANG CITI DIGIT TWOWARA" +
"NG CITI DIGIT THREEWARANG CITI DIGIT FOURWARANG CITI DIGIT FIVEWARANG CI" +
"TI DIGIT SIXWARANG CITI DIGIT SEVENWARANG CITI DIGIT EIGHTWARANG CITI DI" +
"GIT NINEWARANG CITI NUMBER TENWARANG CITI NUMBER TWENTYWARANG CITI NUMBE" +
"R THIRTYWARANG CITI NUMBER FORTYWARANG CITI NUMBER FIFTYWARANG CITI NUMB" +
"ER SIXTYWARANG CITI NUMBER SEVENTYWARANG CITI NUMBER EIGHTYWARANG CITI N" +
"UMBER NINETYWARANG CITI OMDIVES AKURU LETTER ADIVES AKURU LETTER AADIVES" +
" AKURU LETTER IDIVES AKURU LETTER IIDIVES AKURU LETTER UDIVES AKURU LETT" +
"ER UUDIVES AKURU LETTER EDIVES AKURU LETTER ODIVES AKURU LETTER KADIVES " +
"AKURU LETTER KHADIVES AKURU LETTER GADIVES AKURU LETTER GHADIVES AKURU L" +
"ETTER NGADIVES AKURU LETTER CADIVES AKURU LETTER CHADIVES AKURU LETTER J" +
"ADIVES AKURU LETTER NYADIVES AKURU LETTER TTADIVES AKURU LETTER DDADIVES" +
" AKURU LETTER DDHADIVES AKURU LETTER NNADIVES AKURU LETTER TADIVES AKURU" +
" LETTER THADIVES AKURU LETTER DADIVES AKURU LETTER DHADIVES AKURU LETTER" +
" NADIVES AKURU LETTER PADIVES AKURU LETTER PHADIVES AKURU LETTER BADIVES" +
" AKURU LETTER BHADIVES AKURU LETTER MADIVES AKURU LETTER YADIVES AKURU L" +
"ETTER YYADIVES AKURU LETTER RADIVES AKURU LETTER LADIVES AKURU LETTER VA" +
"DIVES AKURU LETTER SHADIVES AKURU LETTER SSADIVES AKURU LETTER SADIVES A" +
"KURU LETTER HADIVES AKURU LETTER LLADIVES AKURU LETTER ZADIVES AKURU VOW" +
"EL SIGN AADIVES AKURU VOWEL SIGN IDIVES AKURU VOWEL SIGN IIDIVES AKURU V" +
"OWEL SIGN UDIVES AKURU VOWEL SIGN UUDIVES AKURU VOWEL SIGN EDIVES AKURU " +
"VOWEL SIGN AIDIVES AKURU VOWEL SIGN ODIVES AKURU SIGN ANUSVARADIVES AKUR" +
"U SIGN CANDRABINDUDIVES AKURU SIGN HALANTADIVES AKURU VIRAMADIVES AKURU " +
"PREFIXED NASAL SIGNDIVES AKURU MEDIAL YADIVES AKURU INITIAL RADIVES AKUR" +
"U MEDIAL RADIVES AKURU SIGN NUKTADIVES AKURU DOUBLE DANDADIVES AKURU GAP" +
" FILLERDIVES AKURU END OF TEXT MARKDIVES AKURU DIGIT ZERODIVES AKURU DIG" +
"IT ONEDIVES AKURU DIGIT TWODIVES AKURU DIGIT THREEDIVES AKURU DIGIT FOUR" +
"DIVES AKURU DIGIT FIVEDIVES AKURU DIGIT SIXDIVES AKURU DIGIT SEVENDIVES " +
"AKURU DIGIT EIGHTDIVES AKURU DIGIT NINENANDINAGARI LETTER ANANDINAGARI L" +
"ETTER AANANDINAGARI LETTER INANDINAGARI LETTER IINANDINAGARI LETTER UNAN" +
"DINAGARI LETTER UUNANDINAGARI LETTER VOCALIC RNANDINAGARI LETTER VOCALIC" +
" RRNANDINAGARI LETTER ENANDINAGARI LETTER AINANDINAGARI LETTER ONANDINAG" +
"ARI LETTER AUNANDINAGARI LETTER KANANDINAGARI LETTER KHANANDINAGARI LETT" +
"ER GANANDINAGARI LETTER GHANANDINAGARI LETTER NGANANDINAGARI LETTER CANA" +
"NDINAGARI LETTER CHANANDINAGARI LETTER JANANDINAGARI LETTER JHANANDINAGA" +
"RI LETTER NYANANDINAGARI LETTER TTANANDINAGARI LETTER TTHANANDINAGARI LE" +
"TTER DDANANDINAGARI LETTER DDHANANDINAGARI LETTER NNANANDINAGARI LETTER " +
"TANANDINAGARI LETTER THANANDINAGARI LETTER DANANDINAGARI LETTER DHANANDI" +
"NAGARI LETTER NANANDINAGARI LETTER PANANDINAGARI LETTER PHANANDINAGARI L" +
"ETTER BANANDINAGARI LETTER BHANANDINAGARI LETTER MANANDINAGARI LETTER YA" +
"NANDINAGARI LETTER RANANDINAGARI LETTER LANANDINAGARI LETTER VANANDINAGA" +
"RI LETTER SHANANDINAGARI LETTER SSANANDINAGARI LETTER SANANDINAGARI LETT" +
"ER HANANDINAGARI LETTER LLANANDINAGARI LETTER RRANANDINAGARI VOWEL SIGN ") + ("" +
"AANANDINAGARI VOWEL SIGN INANDINAGARI VOWEL SIGN IINANDINAGARI VOWEL SIG" +
"N UNANDINAGARI VOWEL SIGN UUNANDINAGARI VOWEL SIGN VOCALIC RNANDINAGARI " +
"VOWEL SIGN VOCALIC RRNANDINAGARI VOWEL SIGN ENANDINAGARI VOWEL SIGN AINA" +
"NDINAGARI VOWEL SIGN ONANDINAGARI VOWEL SIGN AUNANDINAGARI SIGN ANUSVARA" +
"NANDINAGARI SIGN VISARGANANDINAGARI SIGN VIRAMANANDINAGARI SIGN AVAGRAHA" +
"NANDINAGARI SIGN SIDDHAMNANDINAGARI HEADSTROKENANDINAGARI VOWEL SIGN PRI" +
"SHTHAMATRA EZANABAZAR SQUARE LETTER AZANABAZAR SQUARE VOWEL SIGN IZANABA" +
"ZAR SQUARE VOWEL SIGN UEZANABAZAR SQUARE VOWEL SIGN UZANABAZAR SQUARE VO" +
"WEL SIGN EZANABAZAR SQUARE VOWEL SIGN OEZANABAZAR SQUARE VOWEL SIGN OZAN" +
"ABAZAR SQUARE VOWEL SIGN AIZANABAZAR SQUARE VOWEL SIGN AUZANABAZAR SQUAR" +
"E VOWEL SIGN REVERSED IZANABAZAR SQUARE VOWEL LENGTH MARKZANABAZAR SQUAR" +
"E LETTER KAZANABAZAR SQUARE LETTER KHAZANABAZAR SQUARE LETTER GAZANABAZA" +
"R SQUARE LETTER GHAZANABAZAR SQUARE LETTER NGAZANABAZAR SQUARE LETTER CA" +
"ZANABAZAR SQUARE LETTER CHAZANABAZAR SQUARE LETTER JAZANABAZAR SQUARE LE" +
"TTER NYAZANABAZAR SQUARE LETTER TTAZANABAZAR SQUARE LETTER TTHAZANABAZAR" +
" SQUARE LETTER DDAZANABAZAR SQUARE LETTER DDHAZANABAZAR SQUARE LETTER NN" +
"AZANABAZAR SQUARE LETTER TAZANABAZAR SQUARE LETTER THAZANABAZAR SQUARE L" +
"ETTER DAZANABAZAR SQUARE LETTER DHAZANABAZAR SQUARE LETTER NAZANABAZAR S" +
"QUARE LETTER PAZANABAZAR SQUARE LETTER PHAZANABAZAR SQUARE LETTER BAZANA" +
"BAZAR SQUARE LETTER BHAZANABAZAR SQUARE LETTER MAZANABAZAR SQUARE LETTER" +
" TSAZANABAZAR SQUARE LETTER TSHAZANABAZAR SQUARE LETTER DZAZANABAZAR SQU" +
"ARE LETTER DZHAZANABAZAR SQUARE LETTER ZHAZANABAZAR SQUARE LETTER ZAZANA" +
"BAZAR SQUARE LETTER -AZANABAZAR SQUARE LETTER YAZANABAZAR SQUARE LETTER " +
"RAZANABAZAR SQUARE LETTER LAZANABAZAR SQUARE LETTER VAZANABAZAR SQUARE L" +
"ETTER SHAZANABAZAR SQUARE LETTER SSAZANABAZAR SQUARE LETTER SAZANABAZAR " +
"SQUARE LETTER HAZANABAZAR SQUARE LETTER KSSAZANABAZAR SQUARE FINAL CONSO" +
"NANT MARKZANABAZAR SQUARE SIGN VIRAMAZANABAZAR SQUARE SIGN CANDRABINDUZA" +
"NABAZAR SQUARE SIGN CANDRABINDU WITH ORNAMENTZANABAZAR SQUARE SIGN CANDR" +
"A WITH ORNAMENTZANABAZAR SQUARE SIGN ANUSVARAZANABAZAR SQUARE SIGN VISAR" +
"GAZANABAZAR SQUARE CLUSTER-INITIAL LETTER RAZANABAZAR SQUARE CLUSTER-FIN" +
"AL LETTER YAZANABAZAR SQUARE CLUSTER-FINAL LETTER RAZANABAZAR SQUARE CLU" +
"STER-FINAL LETTER LAZANABAZAR SQUARE CLUSTER-FINAL LETTER VAZANABAZAR SQ" +
"UARE INITIAL HEAD MARKZANABAZAR SQUARE CLOSING HEAD MARKZANABAZAR SQUARE" +
" MARK TSHEGZANABAZAR SQUARE MARK SHADZANABAZAR SQUARE MARK DOUBLE SHADZA" +
"NABAZAR SQUARE MARK LONG TSHEGZANABAZAR SQUARE INITIAL DOUBLE-LINED HEAD" +
" MARKZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARKZANABAZAR SQUARE SUB" +
"JOINERSOYOMBO LETTER ASOYOMBO VOWEL SIGN ISOYOMBO VOWEL SIGN UESOYOMBO V" +
"OWEL SIGN USOYOMBO VOWEL SIGN ESOYOMBO VOWEL SIGN OSOYOMBO VOWEL SIGN OE" +
"SOYOMBO VOWEL SIGN AISOYOMBO VOWEL SIGN AUSOYOMBO VOWEL SIGN VOCALIC RSO" +
"YOMBO VOWEL SIGN VOCALIC LSOYOMBO VOWEL LENGTH MARKSOYOMBO LETTER KASOYO" +
"MBO LETTER KHASOYOMBO LETTER GASOYOMBO LETTER GHASOYOMBO LETTER NGASOYOM" +
"BO LETTER CASOYOMBO LETTER CHASOYOMBO LETTER JASOYOMBO LETTER JHASOYOMBO" +
" LETTER NYASOYOMBO LETTER TTASOYOMBO LETTER TTHASOYOMBO LETTER DDASOYOMB" +
"O LETTER DDHASOYOMBO LETTER NNASOYOMBO LETTER TASOYOMBO LETTER THASOYOMB" +
"O LETTER DASOYOMBO LETTER DHASOYOMBO LETTER NASOYOMBO LETTER PASOYOMBO L" +
"ETTER PHASOYOMBO LETTER BASOYOMBO LETTER BHASOYOMBO LETTER MASOYOMBO LET" +
"TER TSASOYOMBO LETTER TSHASOYOMBO LETTER DZASOYOMBO LETTER ZHASOYOMBO LE" +
"TTER ZASOYOMBO LETTER -ASOYOMBO LETTER YASOYOMBO LETTER RASOYOMBO LETTER" +
" LASOYOMBO LETTER VASOYOMBO LETTER SHASOYOMBO LETTER SSASOYOMBO LETTER S" +
"ASOYOMBO LETTER HASOYOMBO LETTER KSSASOYOMBO SIGN JIHVAMULIYASOYOMBO SIG" +
"N UPADHMANIYASOYOMBO CLUSTER-INITIAL LETTER RASOYOMBO CLUSTER-INITIAL LE" +
"TTER LASOYOMBO CLUSTER-INITIAL LETTER SHASOYOMBO CLUSTER-INITIAL LETTER " +
"SASOYOMBO FINAL CONSONANT SIGN GSOYOMBO FINAL CONSONANT SIGN KSOYOMBO FI" +
"NAL CONSONANT SIGN NGSOYOMBO FINAL CONSONANT SIGN DSOYOMBO FINAL CONSONA" +
"NT SIGN NSOYOMBO FINAL CONSONANT SIGN BSOYOMBO FINAL CONSONANT SIGN MSOY" +
"OMBO FINAL CONSONANT SIGN RSOYOMBO FINAL CONSONANT SIGN LSOYOMBO FINAL C" +
"ONSONANT SIGN SHSOYOMBO FINAL CONSONANT SIGN SSOYOMBO FINAL CONSONANT SI" +
"GN -ASOYOMBO SIGN ANUSVARASOYOMBO SIGN VISARGASOYOMBO GEMINATION MARKSOY" +
"OMBO SUBJOINERSOYOMBO MARK TSHEGSOYOMBO MARK SHADSOYOMBO MARK DOUBLE SHA" +
"DSOYOMBO MARK PLUTASOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAMES" +
"OYOMBO HEAD MARK WITH MOON AND SUN AND FLAMESOYOMBO HEAD MARK WITH MOON " +
"AND SUNSOYOMBO TERMINAL MARK-1SOYOMBO TERMINAL MARK-2CANADIAN SYLLABICS " +
"NATTILIK HICANADIAN SYLLABICS NATTILIK HIICANADIAN SYLLABICS NATTILIK HO" +
"CANADIAN SYLLABICS NATTILIK HOOCANADIAN SYLLABICS NATTILIK HACANADIAN SY") + ("" +
"LLABICS NATTILIK HAACANADIAN SYLLABICS NATTILIK SHRICANADIAN SYLLABICS N" +
"ATTILIK SHRIICANADIAN SYLLABICS NATTILIK SHROCANADIAN SYLLABICS NATTILIK" +
" SHROOCANADIAN SYLLABICS NATTILIK SHRACANADIAN SYLLABICS NATTILIK SHRAAC" +
"ANADIAN SYLLABICS SPECANADIAN SYLLABICS SPICANADIAN SYLLABICS SPOCANADIA" +
"N SYLLABICS SPAPAU CIN HAU LETTER PAPAU CIN HAU LETTER KAPAU CIN HAU LET" +
"TER LAPAU CIN HAU LETTER MAPAU CIN HAU LETTER DAPAU CIN HAU LETTER ZAPAU" +
" CIN HAU LETTER VAPAU CIN HAU LETTER NGAPAU CIN HAU LETTER HAPAU CIN HAU" +
" LETTER GAPAU CIN HAU LETTER KHAPAU CIN HAU LETTER SAPAU CIN HAU LETTER " +
"BAPAU CIN HAU LETTER CAPAU CIN HAU LETTER TAPAU CIN HAU LETTER THAPAU CI" +
"N HAU LETTER NAPAU CIN HAU LETTER PHAPAU CIN HAU LETTER RAPAU CIN HAU LE" +
"TTER FAPAU CIN HAU LETTER CHAPAU CIN HAU LETTER APAU CIN HAU LETTER EPAU" +
" CIN HAU LETTER IPAU CIN HAU LETTER OPAU CIN HAU LETTER UPAU CIN HAU LET" +
"TER UAPAU CIN HAU LETTER IAPAU CIN HAU LETTER FINAL PPAU CIN HAU LETTER " +
"FINAL KPAU CIN HAU LETTER FINAL TPAU CIN HAU LETTER FINAL MPAU CIN HAU L" +
"ETTER FINAL NPAU CIN HAU LETTER FINAL LPAU CIN HAU LETTER FINAL WPAU CIN" +
" HAU LETTER FINAL NGPAU CIN HAU LETTER FINAL YPAU CIN HAU RISING TONE LO" +
"NGPAU CIN HAU RISING TONEPAU CIN HAU SANDHI GLOTTAL STOPPAU CIN HAU RISI" +
"NG TONE LONG FINALPAU CIN HAU RISING TONE FINALPAU CIN HAU SANDHI GLOTTA" +
"L STOP FINALPAU CIN HAU SANDHI TONE LONGPAU CIN HAU SANDHI TONEPAU CIN H" +
"AU SANDHI TONE LONG FINALPAU CIN HAU SANDHI TONE FINALPAU CIN HAU MID-LE" +
"VEL TONEPAU CIN HAU GLOTTAL STOP VARIANTPAU CIN HAU MID-LEVEL TONE LONG " +
"FINALPAU CIN HAU MID-LEVEL TONE FINALPAU CIN HAU LOW-FALLING TONE LONGPA" +
"U CIN HAU LOW-FALLING TONEPAU CIN HAU GLOTTAL STOPPAU CIN HAU LOW-FALLIN" +
"G TONE LONG FINALPAU CIN HAU LOW-FALLING TONE FINALPAU CIN HAU GLOTTAL S" +
"TOP FINALDEVANAGARI HEAD MARKDEVANAGARI HEAD MARK WITH HEADSTROKEDEVANAG" +
"ARI SIGN BHALEDEVANAGARI SIGN BHALE WITH HOOKDEVANAGARI SIGN EXTENDED BH" +
"ALEDEVANAGARI SIGN EXTENDED BHALE WITH HOOKDEVANAGARI SIGN WESTERN FIVE-" +
"LIKE BHALEDEVANAGARI SIGN WESTERN NINE-LIKE BHALEDEVANAGARI SIGN REVERSE" +
"D NINE-LIKE BHALEDEVANAGARI SIGN MINDUBHAIKSUKI LETTER ABHAIKSUKI LETTER" +
" AABHAIKSUKI LETTER IBHAIKSUKI LETTER IIBHAIKSUKI LETTER UBHAIKSUKI LETT" +
"ER UUBHAIKSUKI LETTER VOCALIC RBHAIKSUKI LETTER VOCALIC RRBHAIKSUKI LETT" +
"ER VOCALIC LBHAIKSUKI LETTER EBHAIKSUKI LETTER AIBHAIKSUKI LETTER OBHAIK" +
"SUKI LETTER AUBHAIKSUKI LETTER KABHAIKSUKI LETTER KHABHAIKSUKI LETTER GA" +
"BHAIKSUKI LETTER GHABHAIKSUKI LETTER NGABHAIKSUKI LETTER CABHAIKSUKI LET" +
"TER CHABHAIKSUKI LETTER JABHAIKSUKI LETTER JHABHAIKSUKI LETTER NYABHAIKS" +
"UKI LETTER TTABHAIKSUKI LETTER TTHABHAIKSUKI LETTER DDABHAIKSUKI LETTER " +
"DDHABHAIKSUKI LETTER NNABHAIKSUKI LETTER TABHAIKSUKI LETTER THABHAIKSUKI" +
" LETTER DABHAIKSUKI LETTER DHABHAIKSUKI LETTER NABHAIKSUKI LETTER PABHAI" +
"KSUKI LETTER PHABHAIKSUKI LETTER BABHAIKSUKI LETTER BHABHAIKSUKI LETTER " +
"MABHAIKSUKI LETTER YABHAIKSUKI LETTER RABHAIKSUKI LETTER LABHAIKSUKI LET" +
"TER VABHAIKSUKI LETTER SHABHAIKSUKI LETTER SSABHAIKSUKI LETTER SABHAIKSU" +
"KI LETTER HABHAIKSUKI VOWEL SIGN AABHAIKSUKI VOWEL SIGN IBHAIKSUKI VOWEL" +
" SIGN IIBHAIKSUKI VOWEL SIGN UBHAIKSUKI VOWEL SIGN UUBHAIKSUKI VOWEL SIG" +
"N VOCALIC RBHAIKSUKI VOWEL SIGN VOCALIC RRBHAIKSUKI VOWEL SIGN VOCALIC L" +
"BHAIKSUKI VOWEL SIGN EBHAIKSUKI VOWEL SIGN AIBHAIKSUKI VOWEL SIGN OBHAIK" +
"SUKI VOWEL SIGN AUBHAIKSUKI SIGN CANDRABINDUBHAIKSUKI SIGN ANUSVARABHAIK" +
"SUKI SIGN VISARGABHAIKSUKI SIGN VIRAMABHAIKSUKI SIGN AVAGRAHABHAIKSUKI D" +
"ANDABHAIKSUKI DOUBLE DANDABHAIKSUKI WORD SEPARATORBHAIKSUKI GAP FILLER-1" +
"BHAIKSUKI GAP FILLER-2BHAIKSUKI DIGIT ZEROBHAIKSUKI DIGIT ONEBHAIKSUKI D" +
"IGIT TWOBHAIKSUKI DIGIT THREEBHAIKSUKI DIGIT FOURBHAIKSUKI DIGIT FIVEBHA" +
"IKSUKI DIGIT SIXBHAIKSUKI DIGIT SEVENBHAIKSUKI DIGIT EIGHTBHAIKSUKI DIGI" +
"T NINEBHAIKSUKI NUMBER ONEBHAIKSUKI NUMBER TWOBHAIKSUKI NUMBER THREEBHAI" +
"KSUKI NUMBER FOURBHAIKSUKI NUMBER FIVEBHAIKSUKI NUMBER SIXBHAIKSUKI NUMB" +
"ER SEVENBHAIKSUKI NUMBER EIGHTBHAIKSUKI NUMBER NINEBHAIKSUKI NUMBER TENB" +
"HAIKSUKI NUMBER TWENTYBHAIKSUKI NUMBER THIRTYBHAIKSUKI NUMBER FORTYBHAIK" +
"SUKI NUMBER FIFTYBHAIKSUKI NUMBER SIXTYBHAIKSUKI NUMBER SEVENTYBHAIKSUKI" +
" NUMBER EIGHTYBHAIKSUKI NUMBER NINETYBHAIKSUKI HUNDREDS UNIT MARKMARCHEN" +
" HEAD MARKMARCHEN MARK SHADMARCHEN LETTER KAMARCHEN LETTER KHAMARCHEN LE" +
"TTER GAMARCHEN LETTER NGAMARCHEN LETTER CAMARCHEN LETTER CHAMARCHEN LETT" +
"ER JAMARCHEN LETTER NYAMARCHEN LETTER TAMARCHEN LETTER THAMARCHEN LETTER" +
" DAMARCHEN LETTER NAMARCHEN LETTER PAMARCHEN LETTER PHAMARCHEN LETTER BA" +
"MARCHEN LETTER MAMARCHEN LETTER TSAMARCHEN LETTER TSHAMARCHEN LETTER DZA" +
"MARCHEN LETTER WAMARCHEN LETTER ZHAMARCHEN LETTER ZAMARCHEN LETTER -AMAR" +
"CHEN LETTER YAMARCHEN LETTER RAMARCHEN LETTER LAMARCHEN LETTER SHAMARCHE") + ("" +
"N LETTER SAMARCHEN LETTER HAMARCHEN LETTER AMARCHEN SUBJOINED LETTER KAM" +
"ARCHEN SUBJOINED LETTER KHAMARCHEN SUBJOINED LETTER GAMARCHEN SUBJOINED " +
"LETTER NGAMARCHEN SUBJOINED LETTER CAMARCHEN SUBJOINED LETTER CHAMARCHEN" +
" SUBJOINED LETTER JAMARCHEN SUBJOINED LETTER NYAMARCHEN SUBJOINED LETTER" +
" TAMARCHEN SUBJOINED LETTER THAMARCHEN SUBJOINED LETTER DAMARCHEN SUBJOI" +
"NED LETTER NAMARCHEN SUBJOINED LETTER PAMARCHEN SUBJOINED LETTER PHAMARC" +
"HEN SUBJOINED LETTER BAMARCHEN SUBJOINED LETTER MAMARCHEN SUBJOINED LETT" +
"ER TSAMARCHEN SUBJOINED LETTER TSHAMARCHEN SUBJOINED LETTER DZAMARCHEN S" +
"UBJOINED LETTER WAMARCHEN SUBJOINED LETTER ZHAMARCHEN SUBJOINED LETTER Z" +
"AMARCHEN SUBJOINED LETTER YAMARCHEN SUBJOINED LETTER RAMARCHEN SUBJOINED" +
" LETTER LAMARCHEN SUBJOINED LETTER SHAMARCHEN SUBJOINED LETTER SAMARCHEN" +
" SUBJOINED LETTER HAMARCHEN SUBJOINED LETTER AMARCHEN VOWEL SIGN AAMARCH" +
"EN VOWEL SIGN IMARCHEN VOWEL SIGN UMARCHEN VOWEL SIGN EMARCHEN VOWEL SIG" +
"N OMARCHEN SIGN ANUSVARAMARCHEN SIGN CANDRABINDUMASARAM GONDI LETTER AMA" +
"SARAM GONDI LETTER AAMASARAM GONDI LETTER IMASARAM GONDI LETTER IIMASARA" +
"M GONDI LETTER UMASARAM GONDI LETTER UUMASARAM GONDI LETTER EMASARAM GON" +
"DI LETTER AIMASARAM GONDI LETTER OMASARAM GONDI LETTER AUMASARAM GONDI L" +
"ETTER KAMASARAM GONDI LETTER KHAMASARAM GONDI LETTER GAMASARAM GONDI LET" +
"TER GHAMASARAM GONDI LETTER NGAMASARAM GONDI LETTER CAMASARAM GONDI LETT" +
"ER CHAMASARAM GONDI LETTER JAMASARAM GONDI LETTER JHAMASARAM GONDI LETTE" +
"R NYAMASARAM GONDI LETTER TTAMASARAM GONDI LETTER TTHAMASARAM GONDI LETT" +
"ER DDAMASARAM GONDI LETTER DDHAMASARAM GONDI LETTER NNAMASARAM GONDI LET" +
"TER TAMASARAM GONDI LETTER THAMASARAM GONDI LETTER DAMASARAM GONDI LETTE" +
"R DHAMASARAM GONDI LETTER NAMASARAM GONDI LETTER PAMASARAM GONDI LETTER " +
"PHAMASARAM GONDI LETTER BAMASARAM GONDI LETTER BHAMASARAM GONDI LETTER M" +
"AMASARAM GONDI LETTER YAMASARAM GONDI LETTER RAMASARAM GONDI LETTER LAMA" +
"SARAM GONDI LETTER VAMASARAM GONDI LETTER SHAMASARAM GONDI LETTER SSAMAS" +
"ARAM GONDI LETTER SAMASARAM GONDI LETTER HAMASARAM GONDI LETTER LLAMASAR" +
"AM GONDI LETTER KSSAMASARAM GONDI LETTER JNYAMASARAM GONDI LETTER TRAMAS" +
"ARAM GONDI VOWEL SIGN AAMASARAM GONDI VOWEL SIGN IMASARAM GONDI VOWEL SI" +
"GN IIMASARAM GONDI VOWEL SIGN UMASARAM GONDI VOWEL SIGN UUMASARAM GONDI " +
"VOWEL SIGN VOCALIC RMASARAM GONDI VOWEL SIGN EMASARAM GONDI VOWEL SIGN A" +
"IMASARAM GONDI VOWEL SIGN OMASARAM GONDI VOWEL SIGN AUMASARAM GONDI SIGN" +
" ANUSVARAMASARAM GONDI SIGN VISARGAMASARAM GONDI SIGN NUKTAMASARAM GONDI" +
" SIGN CANDRAMASARAM GONDI SIGN HALANTAMASARAM GONDI VIRAMAMASARAM GONDI " +
"REPHAMASARAM GONDI RA-KARAMASARAM GONDI DIGIT ZEROMASARAM GONDI DIGIT ON" +
"EMASARAM GONDI DIGIT TWOMASARAM GONDI DIGIT THREEMASARAM GONDI DIGIT FOU" +
"RMASARAM GONDI DIGIT FIVEMASARAM GONDI DIGIT SIXMASARAM GONDI DIGIT SEVE" +
"NMASARAM GONDI DIGIT EIGHTMASARAM GONDI DIGIT NINEGUNJALA GONDI LETTER A" +
"GUNJALA GONDI LETTER AAGUNJALA GONDI LETTER IGUNJALA GONDI LETTER IIGUNJ" +
"ALA GONDI LETTER UGUNJALA GONDI LETTER UUGUNJALA GONDI LETTER EEGUNJALA " +
"GONDI LETTER AIGUNJALA GONDI LETTER OOGUNJALA GONDI LETTER AUGUNJALA GON" +
"DI LETTER YAGUNJALA GONDI LETTER VAGUNJALA GONDI LETTER BAGUNJALA GONDI " +
"LETTER BHAGUNJALA GONDI LETTER MAGUNJALA GONDI LETTER KAGUNJALA GONDI LE" +
"TTER KHAGUNJALA GONDI LETTER TAGUNJALA GONDI LETTER THAGUNJALA GONDI LET" +
"TER LAGUNJALA GONDI LETTER GAGUNJALA GONDI LETTER GHAGUNJALA GONDI LETTE" +
"R DAGUNJALA GONDI LETTER DHAGUNJALA GONDI LETTER NAGUNJALA GONDI LETTER " +
"CAGUNJALA GONDI LETTER CHAGUNJALA GONDI LETTER TTAGUNJALA GONDI LETTER T" +
"THAGUNJALA GONDI LETTER LLAGUNJALA GONDI LETTER JAGUNJALA GONDI LETTER J" +
"HAGUNJALA GONDI LETTER DDAGUNJALA GONDI LETTER DDHAGUNJALA GONDI LETTER " +
"NGAGUNJALA GONDI LETTER PAGUNJALA GONDI LETTER PHAGUNJALA GONDI LETTER H" +
"AGUNJALA GONDI LETTER RAGUNJALA GONDI LETTER SAGUNJALA GONDI VOWEL SIGN " +
"AAGUNJALA GONDI VOWEL SIGN IGUNJALA GONDI VOWEL SIGN IIGUNJALA GONDI VOW" +
"EL SIGN UGUNJALA GONDI VOWEL SIGN UUGUNJALA GONDI VOWEL SIGN EEGUNJALA G" +
"ONDI VOWEL SIGN AIGUNJALA GONDI VOWEL SIGN OOGUNJALA GONDI VOWEL SIGN AU" +
"GUNJALA GONDI SIGN ANUSVARAGUNJALA GONDI SIGN VISARGAGUNJALA GONDI VIRAM" +
"AGUNJALA GONDI OMGUNJALA GONDI DIGIT ZEROGUNJALA GONDI DIGIT ONEGUNJALA " +
"GONDI DIGIT TWOGUNJALA GONDI DIGIT THREEGUNJALA GONDI DIGIT FOURGUNJALA " +
"GONDI DIGIT FIVEGUNJALA GONDI DIGIT SIXGUNJALA GONDI DIGIT SEVENGUNJALA " +
"GONDI DIGIT EIGHTGUNJALA GONDI DIGIT NINEMAKASAR LETTER KAMAKASAR LETTER" +
" GAMAKASAR LETTER NGAMAKASAR LETTER PAMAKASAR LETTER BAMAKASAR LETTER MA" +
"MAKASAR LETTER TAMAKASAR LETTER DAMAKASAR LETTER NAMAKASAR LETTER CAMAKA" +
"SAR LETTER JAMAKASAR LETTER NYAMAKASAR LETTER YAMAKASAR LETTER RAMAKASAR" +
" LETTER LAMAKASAR LETTER VAMAKASAR LETTER SAMAKASAR LETTER AMAKASAR ANGK") + ("" +
"AMAKASAR VOWEL SIGN IMAKASAR VOWEL SIGN UMAKASAR VOWEL SIGN EMAKASAR VOW" +
"EL SIGN OMAKASAR PASSIMBANGMAKASAR END OF SECTIONKAWI SIGN CANDRABINDUKA" +
"WI SIGN ANUSVARAKAWI SIGN REPHAKAWI SIGN VISARGAKAWI LETTER AKAWI LETTER" +
" AAKAWI LETTER IKAWI LETTER IIKAWI LETTER UKAWI LETTER UUKAWI LETTER VOC" +
"ALIC RKAWI LETTER VOCALIC RRKAWI LETTER VOCALIC LKAWI LETTER VOCALIC LLK" +
"AWI LETTER EKAWI LETTER AIKAWI LETTER OKAWI LETTER KAKAWI LETTER KHAKAWI" +
" LETTER GAKAWI LETTER GHAKAWI LETTER NGAKAWI LETTER CAKAWI LETTER CHAKAW" +
"I LETTER JAKAWI LETTER JHAKAWI LETTER NYAKAWI LETTER TTAKAWI LETTER TTHA" +
"KAWI LETTER DDAKAWI LETTER DDHAKAWI LETTER NNAKAWI LETTER TAKAWI LETTER " +
"THAKAWI LETTER DAKAWI LETTER DHAKAWI LETTER NAKAWI LETTER PAKAWI LETTER " +
"PHAKAWI LETTER BAKAWI LETTER BHAKAWI LETTER MAKAWI LETTER YAKAWI LETTER " +
"RAKAWI LETTER LAKAWI LETTER WAKAWI LETTER SHAKAWI LETTER SSAKAWI LETTER " +
"SAKAWI LETTER HAKAWI LETTER JNYAKAWI VOWEL SIGN AAKAWI VOWEL SIGN ALTERN" +
"ATE AAKAWI VOWEL SIGN IKAWI VOWEL SIGN IIKAWI VOWEL SIGN UKAWI VOWEL SIG" +
"N UUKAWI VOWEL SIGN VOCALIC RKAWI VOWEL SIGN EKAWI VOWEL SIGN AIKAWI VOW" +
"EL SIGN EUKAWI SIGN KILLERKAWI CONJOINERKAWI DANDAKAWI DOUBLE DANDAKAWI " +
"PUNCTUATION SECTION MARKERKAWI PUNCTUATION ALTERNATE SECTION MARKERKAWI " +
"PUNCTUATION FLOWERKAWI PUNCTUATION SPACE FILLERKAWI PUNCTUATION DOTKAWI " +
"PUNCTUATION DOUBLE DOTKAWI PUNCTUATION TRIPLE DOTKAWI PUNCTUATION CIRCLE" +
"KAWI PUNCTUATION FILLED CIRCLEKAWI PUNCTUATION SPIRALKAWI PUNCTUATION CL" +
"OSING SPIRALKAWI DIGIT ZEROKAWI DIGIT ONEKAWI DIGIT TWOKAWI DIGIT THREEK" +
"AWI DIGIT FOURKAWI DIGIT FIVEKAWI DIGIT SIXKAWI DIGIT SEVENKAWI DIGIT EI" +
"GHTKAWI DIGIT NINELISU LETTER YHATAMIL FRACTION ONE THREE-HUNDRED-AND-TW" +
"ENTIETHTAMIL FRACTION ONE ONE-HUNDRED-AND-SIXTIETHTAMIL FRACTION ONE EIG" +
"HTIETHTAMIL FRACTION ONE SIXTY-FOURTHTAMIL FRACTION ONE FORTIETHTAMIL FR" +
"ACTION ONE THIRTY-SECONDTAMIL FRACTION THREE EIGHTIETHSTAMIL FRACTION TH" +
"REE SIXTY-FOURTHSTAMIL FRACTION ONE TWENTIETHTAMIL FRACTION ONE SIXTEENT" +
"H-1TAMIL FRACTION ONE SIXTEENTH-2TAMIL FRACTION ONE TENTHTAMIL FRACTION " +
"ONE EIGHTHTAMIL FRACTION THREE TWENTIETHSTAMIL FRACTION THREE SIXTEENTHS" +
"TAMIL FRACTION ONE FIFTHTAMIL FRACTION ONE QUARTERTAMIL FRACTION ONE HAL" +
"F-1TAMIL FRACTION ONE HALF-2TAMIL FRACTION THREE QUARTERSTAMIL FRACTION " +
"DOWNSCALING FACTOR KIIZHTAMIL SIGN NELTAMIL SIGN CEVITUTAMIL SIGN AAZHAA" +
"KKUTAMIL SIGN UZHAKKUTAMIL SIGN MUUVUZHAKKUTAMIL SIGN KURUNITAMIL SIGN P" +
"ATHAKKUTAMIL SIGN MUKKURUNITAMIL SIGN KAACUTAMIL SIGN PANAMTAMIL SIGN PO" +
"NTAMIL SIGN VARAAKANTAMIL SIGN PAARAMTAMIL SIGN KUZHITAMIL SIGN VELITAMI" +
"L WET CULTIVATION SIGNTAMIL DRY CULTIVATION SIGNTAMIL LAND SIGNTAMIL SAL" +
"T PAN SIGNTAMIL TRADITIONAL CREDIT SIGNTAMIL TRADITIONAL NUMBER SIGNTAMI" +
"L CURRENT SIGNTAMIL AND ODD SIGNTAMIL SPENT SIGNTAMIL TOTAL SIGNTAMIL IN" +
" POSSESSION SIGNTAMIL STARTING FROM SIGNTAMIL SIGN MUTHALIYATAMIL SIGN V" +
"AKAIYARAATAMIL PUNCTUATION END OF TEXTCUNEIFORM SIGN ACUNEIFORM SIGN A T" +
"IMES ACUNEIFORM SIGN A TIMES BADCUNEIFORM SIGN A TIMES GAN2 TENUCUNEIFOR" +
"M SIGN A TIMES HACUNEIFORM SIGN A TIMES IGICUNEIFORM SIGN A TIMES LAGAR " +
"GUNUCUNEIFORM SIGN A TIMES MUSHCUNEIFORM SIGN A TIMES SAGCUNEIFORM SIGN " +
"A2CUNEIFORM SIGN ABCUNEIFORM SIGN AB TIMES ASH2CUNEIFORM SIGN AB TIMES D" +
"UN3 GUNUCUNEIFORM SIGN AB TIMES GALCUNEIFORM SIGN AB TIMES GAN2 TENUCUNE" +
"IFORM SIGN AB TIMES HACUNEIFORM SIGN AB TIMES IGI GUNUCUNEIFORM SIGN AB " +
"TIMES IMINCUNEIFORM SIGN AB TIMES LAGABCUNEIFORM SIGN AB TIMES SHESHCUNE" +
"IFORM SIGN AB TIMES U PLUS U PLUS UCUNEIFORM SIGN AB GUNUCUNEIFORM SIGN " +
"AB2CUNEIFORM SIGN AB2 TIMES BALAGCUNEIFORM SIGN AB2 TIMES GAN2 TENUCUNEI" +
"FORM SIGN AB2 TIMES ME PLUS ENCUNEIFORM SIGN AB2 TIMES SHA3CUNEIFORM SIG" +
"N AB2 TIMES TAK4CUNEIFORM SIGN ADCUNEIFORM SIGN AKCUNEIFORM SIGN AK TIME" +
"S ERIN2CUNEIFORM SIGN AK TIMES SHITA PLUS GISHCUNEIFORM SIGN ALCUNEIFORM" +
" SIGN AL TIMES ALCUNEIFORM SIGN AL TIMES DIM2CUNEIFORM SIGN AL TIMES GIS" +
"HCUNEIFORM SIGN AL TIMES HACUNEIFORM SIGN AL TIMES KAD3CUNEIFORM SIGN AL" +
" TIMES KICUNEIFORM SIGN AL TIMES SHECUNEIFORM SIGN AL TIMES USHCUNEIFORM" +
" SIGN ALANCUNEIFORM SIGN ALEPHCUNEIFORM SIGN AMARCUNEIFORM SIGN AMAR TIM" +
"ES SHECUNEIFORM SIGN ANCUNEIFORM SIGN AN OVER ANCUNEIFORM SIGN AN THREE " +
"TIMESCUNEIFORM SIGN AN PLUS NAGA OPPOSING AN PLUS NAGACUNEIFORM SIGN AN " +
"PLUS NAGA SQUAREDCUNEIFORM SIGN ANSHECUNEIFORM SIGN APINCUNEIFORM SIGN A" +
"RADCUNEIFORM SIGN ARAD TIMES KURCUNEIFORM SIGN ARKABCUNEIFORM SIGN ASAL2" +
"CUNEIFORM SIGN ASHCUNEIFORM SIGN ASH ZIDA TENUCUNEIFORM SIGN ASH KABA TE" +
"NUCUNEIFORM SIGN ASH OVER ASH TUG2 OVER TUG2 TUG2 OVER TUG2 PAPCUNEIFORM" +
" SIGN ASH OVER ASH OVER ASHCUNEIFORM SIGN ASH OVER ASH OVER ASH CROSSING" +
" ASH OVER ASH OVER ASHCUNEIFORM SIGN ASH2CUNEIFORM SIGN ASHGABCUNEIFORM ") + ("" +
"SIGN BACUNEIFORM SIGN BADCUNEIFORM SIGN BAG3CUNEIFORM SIGN BAHAR2CUNEIFO" +
"RM SIGN BALCUNEIFORM SIGN BAL OVER BALCUNEIFORM SIGN BALAGCUNEIFORM SIGN" +
" BARCUNEIFORM SIGN BARA2CUNEIFORM SIGN BICUNEIFORM SIGN BI TIMES ACUNEIF" +
"ORM SIGN BI TIMES GARCUNEIFORM SIGN BI TIMES IGI GUNUCUNEIFORM SIGN BUCU" +
"NEIFORM SIGN BU OVER BU ABCUNEIFORM SIGN BU OVER BU UNCUNEIFORM SIGN BU " +
"CROSSING BUCUNEIFORM SIGN BULUGCUNEIFORM SIGN BULUG OVER BULUGCUNEIFORM " +
"SIGN BURCUNEIFORM SIGN BUR2CUNEIFORM SIGN DACUNEIFORM SIGN DAGCUNEIFORM " +
"SIGN DAG KISIM5 TIMES A PLUS MASHCUNEIFORM SIGN DAG KISIM5 TIMES AMARCUN" +
"EIFORM SIGN DAG KISIM5 TIMES BALAGCUNEIFORM SIGN DAG KISIM5 TIMES BICUNE" +
"IFORM SIGN DAG KISIM5 TIMES GACUNEIFORM SIGN DAG KISIM5 TIMES GA PLUS MA" +
"SHCUNEIFORM SIGN DAG KISIM5 TIMES GICUNEIFORM SIGN DAG KISIM5 TIMES GIR2" +
"CUNEIFORM SIGN DAG KISIM5 TIMES GUDCUNEIFORM SIGN DAG KISIM5 TIMES HACUN" +
"EIFORM SIGN DAG KISIM5 TIMES IRCUNEIFORM SIGN DAG KISIM5 TIMES IR PLUS L" +
"UCUNEIFORM SIGN DAG KISIM5 TIMES KAKCUNEIFORM SIGN DAG KISIM5 TIMES LACU" +
"NEIFORM SIGN DAG KISIM5 TIMES LUCUNEIFORM SIGN DAG KISIM5 TIMES LU PLUS " +
"MASH2CUNEIFORM SIGN DAG KISIM5 TIMES LUMCUNEIFORM SIGN DAG KISIM5 TIMES " +
"NECUNEIFORM SIGN DAG KISIM5 TIMES PAP PLUS PAPCUNEIFORM SIGN DAG KISIM5 " +
"TIMES SICUNEIFORM SIGN DAG KISIM5 TIMES TAK4CUNEIFORM SIGN DAG KISIM5 TI" +
"MES U2 PLUS GIR2CUNEIFORM SIGN DAG KISIM5 TIMES USHCUNEIFORM SIGN DAMCUN" +
"EIFORM SIGN DARCUNEIFORM SIGN DARA3CUNEIFORM SIGN DARA4CUNEIFORM SIGN DI" +
"CUNEIFORM SIGN DIBCUNEIFORM SIGN DIMCUNEIFORM SIGN DIM TIMES SHECUNEIFOR" +
"M SIGN DIM2CUNEIFORM SIGN DINCUNEIFORM SIGN DIN KASKAL U GUNU DISHCUNEIF" +
"ORM SIGN DISHCUNEIFORM SIGN DUCUNEIFORM SIGN DU OVER DUCUNEIFORM SIGN DU" +
" GUNUCUNEIFORM SIGN DU SHESHIGCUNEIFORM SIGN DUBCUNEIFORM SIGN DUB TIMES" +
" ESH2CUNEIFORM SIGN DUB2CUNEIFORM SIGN DUGCUNEIFORM SIGN DUGUDCUNEIFORM " +
"SIGN DUHCUNEIFORM SIGN DUNCUNEIFORM SIGN DUN3CUNEIFORM SIGN DUN3 GUNUCUN" +
"EIFORM SIGN DUN3 GUNU GUNUCUNEIFORM SIGN DUN4CUNEIFORM SIGN DUR2CUNEIFOR" +
"M SIGN ECUNEIFORM SIGN E TIMES PAPCUNEIFORM SIGN E OVER E NUN OVER NUNCU" +
"NEIFORM SIGN E2CUNEIFORM SIGN E2 TIMES A PLUS HA PLUS DACUNEIFORM SIGN E" +
"2 TIMES GARCUNEIFORM SIGN E2 TIMES MICUNEIFORM SIGN E2 TIMES SALCUNEIFOR" +
"M SIGN E2 TIMES SHECUNEIFORM SIGN E2 TIMES UCUNEIFORM SIGN EDINCUNEIFORM" +
" SIGN EGIRCUNEIFORM SIGN ELCUNEIFORM SIGN ENCUNEIFORM SIGN EN TIMES GAN2" +
"CUNEIFORM SIGN EN TIMES GAN2 TENUCUNEIFORM SIGN EN TIMES MECUNEIFORM SIG" +
"N EN CROSSING ENCUNEIFORM SIGN EN OPPOSING ENCUNEIFORM SIGN EN SQUAREDCU" +
"NEIFORM SIGN ERENCUNEIFORM SIGN ERIN2CUNEIFORM SIGN ESH2CUNEIFORM SIGN E" +
"ZENCUNEIFORM SIGN EZEN TIMES ACUNEIFORM SIGN EZEN TIMES A PLUS LALCUNEIF" +
"ORM SIGN EZEN TIMES A PLUS LAL TIMES LALCUNEIFORM SIGN EZEN TIMES ANCUNE" +
"IFORM SIGN EZEN TIMES BADCUNEIFORM SIGN EZEN TIMES DUN3 GUNUCUNEIFORM SI" +
"GN EZEN TIMES DUN3 GUNU GUNUCUNEIFORM SIGN EZEN TIMES HACUNEIFORM SIGN E" +
"ZEN TIMES HA GUNUCUNEIFORM SIGN EZEN TIMES IGI GUNUCUNEIFORM SIGN EZEN T" +
"IMES KASKALCUNEIFORM SIGN EZEN TIMES KASKAL SQUAREDCUNEIFORM SIGN EZEN T" +
"IMES KU3CUNEIFORM SIGN EZEN TIMES LACUNEIFORM SIGN EZEN TIMES LAL TIMES " +
"LALCUNEIFORM SIGN EZEN TIMES LICUNEIFORM SIGN EZEN TIMES LUCUNEIFORM SIG" +
"N EZEN TIMES U2CUNEIFORM SIGN EZEN TIMES UDCUNEIFORM SIGN GACUNEIFORM SI" +
"GN GA GUNUCUNEIFORM SIGN GA2CUNEIFORM SIGN GA2 TIMES A PLUS DA PLUS HACU" +
"NEIFORM SIGN GA2 TIMES A PLUS HACUNEIFORM SIGN GA2 TIMES A PLUS IGICUNEI" +
"FORM SIGN GA2 TIMES AB2 TENU PLUS TABCUNEIFORM SIGN GA2 TIMES ANCUNEIFOR" +
"M SIGN GA2 TIMES ASHCUNEIFORM SIGN GA2 TIMES ASH2 PLUS GALCUNEIFORM SIGN" +
" GA2 TIMES BADCUNEIFORM SIGN GA2 TIMES BAR PLUS RACUNEIFORM SIGN GA2 TIM" +
"ES BURCUNEIFORM SIGN GA2 TIMES BUR PLUS RACUNEIFORM SIGN GA2 TIMES DACUN" +
"EIFORM SIGN GA2 TIMES DICUNEIFORM SIGN GA2 TIMES DIM TIMES SHECUNEIFORM " +
"SIGN GA2 TIMES DUBCUNEIFORM SIGN GA2 TIMES ELCUNEIFORM SIGN GA2 TIMES EL" +
" PLUS LACUNEIFORM SIGN GA2 TIMES ENCUNEIFORM SIGN GA2 TIMES EN TIMES GAN" +
"2 TENUCUNEIFORM SIGN GA2 TIMES GAN2 TENUCUNEIFORM SIGN GA2 TIMES GARCUNE" +
"IFORM SIGN GA2 TIMES GICUNEIFORM SIGN GA2 TIMES GI4CUNEIFORM SIGN GA2 TI" +
"MES GI4 PLUS ACUNEIFORM SIGN GA2 TIMES GIR2 PLUS SUCUNEIFORM SIGN GA2 TI" +
"MES HA PLUS LU PLUS ESH2CUNEIFORM SIGN GA2 TIMES HALCUNEIFORM SIGN GA2 T" +
"IMES HAL PLUS LACUNEIFORM SIGN GA2 TIMES HI PLUS LICUNEIFORM SIGN GA2 TI" +
"MES HUB2CUNEIFORM SIGN GA2 TIMES IGI GUNUCUNEIFORM SIGN GA2 TIMES ISH PL" +
"US HU PLUS ASHCUNEIFORM SIGN GA2 TIMES KAKCUNEIFORM SIGN GA2 TIMES KASKA" +
"LCUNEIFORM SIGN GA2 TIMES KIDCUNEIFORM SIGN GA2 TIMES KID PLUS LALCUNEIF" +
"ORM SIGN GA2 TIMES KU3 PLUS ANCUNEIFORM SIGN GA2 TIMES LACUNEIFORM SIGN " +
"GA2 TIMES ME PLUS ENCUNEIFORM SIGN GA2 TIMES MICUNEIFORM SIGN GA2 TIMES " +
"NUNCUNEIFORM SIGN GA2 TIMES NUN OVER NUNCUNEIFORM SIGN GA2 TIMES PACUNEI") + ("" +
"FORM SIGN GA2 TIMES SALCUNEIFORM SIGN GA2 TIMES SARCUNEIFORM SIGN GA2 TI" +
"MES SHECUNEIFORM SIGN GA2 TIMES SHE PLUS TURCUNEIFORM SIGN GA2 TIMES SHI" +
"DCUNEIFORM SIGN GA2 TIMES SUMCUNEIFORM SIGN GA2 TIMES TAK4CUNEIFORM SIGN" +
" GA2 TIMES UCUNEIFORM SIGN GA2 TIMES UDCUNEIFORM SIGN GA2 TIMES UD PLUS " +
"DUCUNEIFORM SIGN GA2 OVER GA2CUNEIFORM SIGN GABACUNEIFORM SIGN GABA CROS" +
"SING GABACUNEIFORM SIGN GADCUNEIFORM SIGN GAD OVER GAD GAR OVER GARCUNEI" +
"FORM SIGN GALCUNEIFORM SIGN GAL GAD OVER GAD GAR OVER GARCUNEIFORM SIGN " +
"GALAMCUNEIFORM SIGN GAMCUNEIFORM SIGN GANCUNEIFORM SIGN GAN2CUNEIFORM SI" +
"GN GAN2 TENUCUNEIFORM SIGN GAN2 OVER GAN2CUNEIFORM SIGN GAN2 CROSSING GA" +
"N2CUNEIFORM SIGN GARCUNEIFORM SIGN GAR3CUNEIFORM SIGN GASHANCUNEIFORM SI" +
"GN GESHTINCUNEIFORM SIGN GESHTIN TIMES KURCUNEIFORM SIGN GICUNEIFORM SIG" +
"N GI TIMES ECUNEIFORM SIGN GI TIMES UCUNEIFORM SIGN GI CROSSING GICUNEIF" +
"ORM SIGN GI4CUNEIFORM SIGN GI4 OVER GI4CUNEIFORM SIGN GI4 CROSSING GI4CU" +
"NEIFORM SIGN GIDIMCUNEIFORM SIGN GIR2CUNEIFORM SIGN GIR2 GUNUCUNEIFORM S" +
"IGN GIR3CUNEIFORM SIGN GIR3 TIMES A PLUS IGICUNEIFORM SIGN GIR3 TIMES GA" +
"N2 TENUCUNEIFORM SIGN GIR3 TIMES IGICUNEIFORM SIGN GIR3 TIMES LU PLUS IG" +
"ICUNEIFORM SIGN GIR3 TIMES PACUNEIFORM SIGN GISALCUNEIFORM SIGN GISHCUNE" +
"IFORM SIGN GISH CROSSING GISHCUNEIFORM SIGN GISH TIMES BADCUNEIFORM SIGN" +
" GISH TIMES TAK4CUNEIFORM SIGN GISH TENUCUNEIFORM SIGN GUCUNEIFORM SIGN " +
"GU CROSSING GUCUNEIFORM SIGN GU2CUNEIFORM SIGN GU2 TIMES KAKCUNEIFORM SI" +
"GN GU2 TIMES KAK TIMES IGI GUNUCUNEIFORM SIGN GU2 TIMES NUNCUNEIFORM SIG" +
"N GU2 TIMES SAL PLUS TUG2CUNEIFORM SIGN GU2 GUNUCUNEIFORM SIGN GUDCUNEIF" +
"ORM SIGN GUD TIMES A PLUS KURCUNEIFORM SIGN GUD TIMES KURCUNEIFORM SIGN " +
"GUD OVER GUD LUGALCUNEIFORM SIGN GULCUNEIFORM SIGN GUMCUNEIFORM SIGN GUM" +
" TIMES SHECUNEIFORM SIGN GURCUNEIFORM SIGN GUR7CUNEIFORM SIGN GURUNCUNEI" +
"FORM SIGN GURUSHCUNEIFORM SIGN HACUNEIFORM SIGN HA TENUCUNEIFORM SIGN HA" +
" GUNUCUNEIFORM SIGN HALCUNEIFORM SIGN HICUNEIFORM SIGN HI TIMES ASHCUNEI" +
"FORM SIGN HI TIMES ASH2CUNEIFORM SIGN HI TIMES BADCUNEIFORM SIGN HI TIME" +
"S DISHCUNEIFORM SIGN HI TIMES GADCUNEIFORM SIGN HI TIMES KINCUNEIFORM SI" +
"GN HI TIMES NUNCUNEIFORM SIGN HI TIMES SHECUNEIFORM SIGN HI TIMES UCUNEI" +
"FORM SIGN HUCUNEIFORM SIGN HUB2CUNEIFORM SIGN HUB2 TIMES ANCUNEIFORM SIG" +
"N HUB2 TIMES HALCUNEIFORM SIGN HUB2 TIMES KASKALCUNEIFORM SIGN HUB2 TIME" +
"S LISHCUNEIFORM SIGN HUB2 TIMES UDCUNEIFORM SIGN HUL2CUNEIFORM SIGN ICUN" +
"EIFORM SIGN I ACUNEIFORM SIGN IBCUNEIFORM SIGN IDIMCUNEIFORM SIGN IDIM O" +
"VER IDIM BURCUNEIFORM SIGN IDIM OVER IDIM SQUAREDCUNEIFORM SIGN IGCUNEIF" +
"ORM SIGN IGICUNEIFORM SIGN IGI DIBCUNEIFORM SIGN IGI RICUNEIFORM SIGN IG" +
"I OVER IGI SHIR OVER SHIR UD OVER UDCUNEIFORM SIGN IGI GUNUCUNEIFORM SIG" +
"N ILCUNEIFORM SIGN IL TIMES GAN2 TENUCUNEIFORM SIGN IL2CUNEIFORM SIGN IM" +
"CUNEIFORM SIGN IM TIMES TAK4CUNEIFORM SIGN IM CROSSING IMCUNEIFORM SIGN " +
"IM OPPOSING IMCUNEIFORM SIGN IM SQUAREDCUNEIFORM SIGN IMINCUNEIFORM SIGN" +
" INCUNEIFORM SIGN IRCUNEIFORM SIGN ISHCUNEIFORM SIGN KACUNEIFORM SIGN KA" +
" TIMES ACUNEIFORM SIGN KA TIMES ADCUNEIFORM SIGN KA TIMES AD PLUS KU3CUN" +
"EIFORM SIGN KA TIMES ASH2CUNEIFORM SIGN KA TIMES BADCUNEIFORM SIGN KA TI" +
"MES BALAGCUNEIFORM SIGN KA TIMES BARCUNEIFORM SIGN KA TIMES BICUNEIFORM " +
"SIGN KA TIMES ERIN2CUNEIFORM SIGN KA TIMES ESH2CUNEIFORM SIGN KA TIMES G" +
"ACUNEIFORM SIGN KA TIMES GALCUNEIFORM SIGN KA TIMES GAN2 TENUCUNEIFORM S" +
"IGN KA TIMES GARCUNEIFORM SIGN KA TIMES GAR PLUS SHA3 PLUS ACUNEIFORM SI" +
"GN KA TIMES GICUNEIFORM SIGN KA TIMES GIR2CUNEIFORM SIGN KA TIMES GISH P" +
"LUS SARCUNEIFORM SIGN KA TIMES GISH CROSSING GISHCUNEIFORM SIGN KA TIMES" +
" GUCUNEIFORM SIGN KA TIMES GUR7CUNEIFORM SIGN KA TIMES IGICUNEIFORM SIGN" +
" KA TIMES IMCUNEIFORM SIGN KA TIMES KAKCUNEIFORM SIGN KA TIMES KICUNEIFO" +
"RM SIGN KA TIMES KIDCUNEIFORM SIGN KA TIMES LICUNEIFORM SIGN KA TIMES LU" +
"CUNEIFORM SIGN KA TIMES MECUNEIFORM SIGN KA TIMES ME PLUS DUCUNEIFORM SI" +
"GN KA TIMES ME PLUS GICUNEIFORM SIGN KA TIMES ME PLUS TECUNEIFORM SIGN K" +
"A TIMES MICUNEIFORM SIGN KA TIMES MI PLUS NUNUZCUNEIFORM SIGN KA TIMES N" +
"ECUNEIFORM SIGN KA TIMES NUNCUNEIFORM SIGN KA TIMES PICUNEIFORM SIGN KA " +
"TIMES RUCUNEIFORM SIGN KA TIMES SACUNEIFORM SIGN KA TIMES SARCUNEIFORM S" +
"IGN KA TIMES SHACUNEIFORM SIGN KA TIMES SHECUNEIFORM SIGN KA TIMES SHIDC" +
"UNEIFORM SIGN KA TIMES SHUCUNEIFORM SIGN KA TIMES SIGCUNEIFORM SIGN KA T" +
"IMES SUHURCUNEIFORM SIGN KA TIMES TARCUNEIFORM SIGN KA TIMES UCUNEIFORM " +
"SIGN KA TIMES U2CUNEIFORM SIGN KA TIMES UDCUNEIFORM SIGN KA TIMES UMUM T" +
"IMES PACUNEIFORM SIGN KA TIMES USHCUNEIFORM SIGN KA TIMES ZICUNEIFORM SI" +
"GN KA2CUNEIFORM SIGN KA2 CROSSING KA2CUNEIFORM SIGN KABCUNEIFORM SIGN KA" +
"D2CUNEIFORM SIGN KAD3CUNEIFORM SIGN KAD4CUNEIFORM SIGN KAD5CUNEIFORM SIG") + ("" +
"N KAD5 OVER KAD5CUNEIFORM SIGN KAKCUNEIFORM SIGN KAK TIMES IGI GUNUCUNEI" +
"FORM SIGN KALCUNEIFORM SIGN KAL TIMES BADCUNEIFORM SIGN KAL CROSSING KAL" +
"CUNEIFORM SIGN KAM2CUNEIFORM SIGN KAM4CUNEIFORM SIGN KASKALCUNEIFORM SIG" +
"N KASKAL LAGAB TIMES U OVER LAGAB TIMES UCUNEIFORM SIGN KASKAL OVER KASK" +
"AL LAGAB TIMES U OVER LAGAB TIMES UCUNEIFORM SIGN KESH2CUNEIFORM SIGN KI" +
"CUNEIFORM SIGN KI TIMES BADCUNEIFORM SIGN KI TIMES UCUNEIFORM SIGN KI TI" +
"MES UDCUNEIFORM SIGN KIDCUNEIFORM SIGN KINCUNEIFORM SIGN KISALCUNEIFORM " +
"SIGN KISHCUNEIFORM SIGN KISIM5CUNEIFORM SIGN KISIM5 OVER KISIM5CUNEIFORM" +
" SIGN KUCUNEIFORM SIGN KU OVER HI TIMES ASH2 KU OVER HI TIMES ASH2CUNEIF" +
"ORM SIGN KU3CUNEIFORM SIGN KU4CUNEIFORM SIGN KU4 VARIANT FORMCUNEIFORM S" +
"IGN KU7CUNEIFORM SIGN KULCUNEIFORM SIGN KUL GUNUCUNEIFORM SIGN KUNCUNEIF" +
"ORM SIGN KURCUNEIFORM SIGN KUR OPPOSING KURCUNEIFORM SIGN KUSHU2CUNEIFOR" +
"M SIGN KWU318CUNEIFORM SIGN LACUNEIFORM SIGN LAGABCUNEIFORM SIGN LAGAB T" +
"IMES ACUNEIFORM SIGN LAGAB TIMES A PLUS DA PLUS HACUNEIFORM SIGN LAGAB T" +
"IMES A PLUS GARCUNEIFORM SIGN LAGAB TIMES A PLUS LALCUNEIFORM SIGN LAGAB" +
" TIMES ALCUNEIFORM SIGN LAGAB TIMES ANCUNEIFORM SIGN LAGAB TIMES ASH ZID" +
"A TENUCUNEIFORM SIGN LAGAB TIMES BADCUNEIFORM SIGN LAGAB TIMES BICUNEIFO" +
"RM SIGN LAGAB TIMES DARCUNEIFORM SIGN LAGAB TIMES ENCUNEIFORM SIGN LAGAB" +
" TIMES GACUNEIFORM SIGN LAGAB TIMES GARCUNEIFORM SIGN LAGAB TIMES GUDCUN" +
"EIFORM SIGN LAGAB TIMES GUD PLUS GUDCUNEIFORM SIGN LAGAB TIMES HACUNEIFO" +
"RM SIGN LAGAB TIMES HALCUNEIFORM SIGN LAGAB TIMES HI TIMES NUNCUNEIFORM " +
"SIGN LAGAB TIMES IGI GUNUCUNEIFORM SIGN LAGAB TIMES IMCUNEIFORM SIGN LAG" +
"AB TIMES IM PLUS HACUNEIFORM SIGN LAGAB TIMES IM PLUS LUCUNEIFORM SIGN L" +
"AGAB TIMES KICUNEIFORM SIGN LAGAB TIMES KINCUNEIFORM SIGN LAGAB TIMES KU" +
"3CUNEIFORM SIGN LAGAB TIMES KULCUNEIFORM SIGN LAGAB TIMES KUL PLUS HI PL" +
"US ACUNEIFORM SIGN LAGAB TIMES LAGABCUNEIFORM SIGN LAGAB TIMES LISHCUNEI" +
"FORM SIGN LAGAB TIMES LUCUNEIFORM SIGN LAGAB TIMES LULCUNEIFORM SIGN LAG" +
"AB TIMES MECUNEIFORM SIGN LAGAB TIMES ME PLUS ENCUNEIFORM SIGN LAGAB TIM" +
"ES MUSHCUNEIFORM SIGN LAGAB TIMES NECUNEIFORM SIGN LAGAB TIMES SHE PLUS " +
"SUMCUNEIFORM SIGN LAGAB TIMES SHITA PLUS GISH PLUS ERIN2CUNEIFORM SIGN L" +
"AGAB TIMES SHITA PLUS GISH TENUCUNEIFORM SIGN LAGAB TIMES SHU2CUNEIFORM " +
"SIGN LAGAB TIMES SHU2 PLUS SHU2CUNEIFORM SIGN LAGAB TIMES SUMCUNEIFORM S" +
"IGN LAGAB TIMES TAGCUNEIFORM SIGN LAGAB TIMES TAK4CUNEIFORM SIGN LAGAB T" +
"IMES TE PLUS A PLUS SU PLUS NACUNEIFORM SIGN LAGAB TIMES UCUNEIFORM SIGN" +
" LAGAB TIMES U PLUS ACUNEIFORM SIGN LAGAB TIMES U PLUS U PLUS UCUNEIFORM" +
" SIGN LAGAB TIMES U2 PLUS ASHCUNEIFORM SIGN LAGAB TIMES UDCUNEIFORM SIGN" +
" LAGAB TIMES USHCUNEIFORM SIGN LAGAB SQUAREDCUNEIFORM SIGN LAGARCUNEIFOR" +
"M SIGN LAGAR TIMES SHECUNEIFORM SIGN LAGAR TIMES SHE PLUS SUMCUNEIFORM S" +
"IGN LAGAR GUNUCUNEIFORM SIGN LAGAR GUNU OVER LAGAR GUNU SHECUNEIFORM SIG" +
"N LAHSHUCUNEIFORM SIGN LALCUNEIFORM SIGN LAL TIMES LALCUNEIFORM SIGN LAM" +
"CUNEIFORM SIGN LAM TIMES KURCUNEIFORM SIGN LAM TIMES KUR PLUS RUCUNEIFOR" +
"M SIGN LICUNEIFORM SIGN LILCUNEIFORM SIGN LIMMU2CUNEIFORM SIGN LISHCUNEI" +
"FORM SIGN LUCUNEIFORM SIGN LU TIMES BADCUNEIFORM SIGN LU2CUNEIFORM SIGN " +
"LU2 TIMES ALCUNEIFORM SIGN LU2 TIMES BADCUNEIFORM SIGN LU2 TIMES ESH2CUN" +
"EIFORM SIGN LU2 TIMES ESH2 TENUCUNEIFORM SIGN LU2 TIMES GAN2 TENUCUNEIFO" +
"RM SIGN LU2 TIMES HI TIMES BADCUNEIFORM SIGN LU2 TIMES IMCUNEIFORM SIGN " +
"LU2 TIMES KAD2CUNEIFORM SIGN LU2 TIMES KAD3CUNEIFORM SIGN LU2 TIMES KAD3" +
" PLUS ASHCUNEIFORM SIGN LU2 TIMES KICUNEIFORM SIGN LU2 TIMES LA PLUS ASH" +
"CUNEIFORM SIGN LU2 TIMES LAGABCUNEIFORM SIGN LU2 TIMES ME PLUS ENCUNEIFO" +
"RM SIGN LU2 TIMES NECUNEIFORM SIGN LU2 TIMES NUCUNEIFORM SIGN LU2 TIMES " +
"SI PLUS ASHCUNEIFORM SIGN LU2 TIMES SIK2 PLUS BUCUNEIFORM SIGN LU2 TIMES" +
" TUG2CUNEIFORM SIGN LU2 TENUCUNEIFORM SIGN LU2 CROSSING LU2CUNEIFORM SIG" +
"N LU2 OPPOSING LU2CUNEIFORM SIGN LU2 SQUAREDCUNEIFORM SIGN LU2 SHESHIGCU" +
"NEIFORM SIGN LU3CUNEIFORM SIGN LUGALCUNEIFORM SIGN LUGAL OVER LUGALCUNEI" +
"FORM SIGN LUGAL OPPOSING LUGALCUNEIFORM SIGN LUGAL SHESHIGCUNEIFORM SIGN" +
" LUHCUNEIFORM SIGN LULCUNEIFORM SIGN LUMCUNEIFORM SIGN LUM OVER LUMCUNEI" +
"FORM SIGN LUM OVER LUM GAR OVER GARCUNEIFORM SIGN MACUNEIFORM SIGN MA TI" +
"MES TAK4CUNEIFORM SIGN MA GUNUCUNEIFORM SIGN MA2CUNEIFORM SIGN MAHCUNEIF" +
"ORM SIGN MARCUNEIFORM SIGN MASHCUNEIFORM SIGN MASH2CUNEIFORM SIGN MECUNE" +
"IFORM SIGN MESCUNEIFORM SIGN MICUNEIFORM SIGN MINCUNEIFORM SIGN MUCUNEIF" +
"ORM SIGN MU OVER MUCUNEIFORM SIGN MUGCUNEIFORM SIGN MUG GUNUCUNEIFORM SI" +
"GN MUNSUBCUNEIFORM SIGN MURGU2CUNEIFORM SIGN MUSHCUNEIFORM SIGN MUSH TIM" +
"ES ACUNEIFORM SIGN MUSH TIMES KURCUNEIFORM SIGN MUSH TIMES ZACUNEIFORM S" +
"IGN MUSH OVER MUSHCUNEIFORM SIGN MUSH OVER MUSH TIMES A PLUS NACUNEIFORM") + ("" +
" SIGN MUSH CROSSING MUSHCUNEIFORM SIGN MUSH3CUNEIFORM SIGN MUSH3 TIMES A" +
"CUNEIFORM SIGN MUSH3 TIMES A PLUS DICUNEIFORM SIGN MUSH3 TIMES DICUNEIFO" +
"RM SIGN MUSH3 GUNUCUNEIFORM SIGN NACUNEIFORM SIGN NA2CUNEIFORM SIGN NAGA" +
"CUNEIFORM SIGN NAGA INVERTEDCUNEIFORM SIGN NAGA TIMES SHU TENUCUNEIFORM " +
"SIGN NAGA OPPOSING NAGACUNEIFORM SIGN NAGARCUNEIFORM SIGN NAM NUTILLUCUN" +
"EIFORM SIGN NAMCUNEIFORM SIGN NAM2CUNEIFORM SIGN NECUNEIFORM SIGN NE TIM" +
"ES ACUNEIFORM SIGN NE TIMES UDCUNEIFORM SIGN NE SHESHIGCUNEIFORM SIGN NI" +
"CUNEIFORM SIGN NI TIMES ECUNEIFORM SIGN NI2CUNEIFORM SIGN NIMCUNEIFORM S" +
"IGN NIM TIMES GAN2 TENUCUNEIFORM SIGN NIM TIMES GAR PLUS GAN2 TENUCUNEIF" +
"ORM SIGN NINDA2CUNEIFORM SIGN NINDA2 TIMES ANCUNEIFORM SIGN NINDA2 TIMES" +
" ASHCUNEIFORM SIGN NINDA2 TIMES ASH PLUS ASHCUNEIFORM SIGN NINDA2 TIMES " +
"GUDCUNEIFORM SIGN NINDA2 TIMES ME PLUS GAN2 TENUCUNEIFORM SIGN NINDA2 TI" +
"MES NECUNEIFORM SIGN NINDA2 TIMES NUNCUNEIFORM SIGN NINDA2 TIMES SHECUNE" +
"IFORM SIGN NINDA2 TIMES SHE PLUS A ANCUNEIFORM SIGN NINDA2 TIMES SHE PLU" +
"S ASHCUNEIFORM SIGN NINDA2 TIMES SHE PLUS ASH PLUS ASHCUNEIFORM SIGN NIN" +
"DA2 TIMES U2 PLUS ASHCUNEIFORM SIGN NINDA2 TIMES USHCUNEIFORM SIGN NISAG" +
"CUNEIFORM SIGN NUCUNEIFORM SIGN NU11CUNEIFORM SIGN NUNCUNEIFORM SIGN NUN" +
" LAGAR TIMES GARCUNEIFORM SIGN NUN LAGAR TIMES MASHCUNEIFORM SIGN NUN LA" +
"GAR TIMES SALCUNEIFORM SIGN NUN LAGAR TIMES SAL OVER NUN LAGAR TIMES SAL" +
"CUNEIFORM SIGN NUN LAGAR TIMES USHCUNEIFORM SIGN NUN TENUCUNEIFORM SIGN " +
"NUN OVER NUNCUNEIFORM SIGN NUN CROSSING NUNCUNEIFORM SIGN NUN CROSSING N" +
"UN LAGAR OVER LAGARCUNEIFORM SIGN NUNUZCUNEIFORM SIGN NUNUZ AB2 TIMES AS" +
"HGABCUNEIFORM SIGN NUNUZ AB2 TIMES BICUNEIFORM SIGN NUNUZ AB2 TIMES DUGC" +
"UNEIFORM SIGN NUNUZ AB2 TIMES GUDCUNEIFORM SIGN NUNUZ AB2 TIMES IGI GUNU" +
"CUNEIFORM SIGN NUNUZ AB2 TIMES KAD3CUNEIFORM SIGN NUNUZ AB2 TIMES LACUNE" +
"IFORM SIGN NUNUZ AB2 TIMES NECUNEIFORM SIGN NUNUZ AB2 TIMES SILA3CUNEIFO" +
"RM SIGN NUNUZ AB2 TIMES U2CUNEIFORM SIGN NUNUZ KISIM5 TIMES BICUNEIFORM " +
"SIGN NUNUZ KISIM5 TIMES BI UCUNEIFORM SIGN PACUNEIFORM SIGN PADCUNEIFORM" +
" SIGN PANCUNEIFORM SIGN PAPCUNEIFORM SIGN PESH2CUNEIFORM SIGN PICUNEIFOR" +
"M SIGN PI TIMES ACUNEIFORM SIGN PI TIMES ABCUNEIFORM SIGN PI TIMES BICUN" +
"EIFORM SIGN PI TIMES BUCUNEIFORM SIGN PI TIMES ECUNEIFORM SIGN PI TIMES " +
"ICUNEIFORM SIGN PI TIMES IBCUNEIFORM SIGN PI TIMES UCUNEIFORM SIGN PI TI" +
"MES U2CUNEIFORM SIGN PI CROSSING PICUNEIFORM SIGN PIRIGCUNEIFORM SIGN PI" +
"RIG TIMES KALCUNEIFORM SIGN PIRIG TIMES UDCUNEIFORM SIGN PIRIG TIMES ZAC" +
"UNEIFORM SIGN PIRIG OPPOSING PIRIGCUNEIFORM SIGN RACUNEIFORM SIGN RABCUN" +
"EIFORM SIGN RICUNEIFORM SIGN RUCUNEIFORM SIGN SACUNEIFORM SIGN SAG NUTIL" +
"LUCUNEIFORM SIGN SAGCUNEIFORM SIGN SAG TIMES ACUNEIFORM SIGN SAG TIMES D" +
"UCUNEIFORM SIGN SAG TIMES DUBCUNEIFORM SIGN SAG TIMES HACUNEIFORM SIGN S" +
"AG TIMES KAKCUNEIFORM SIGN SAG TIMES KURCUNEIFORM SIGN SAG TIMES LUMCUNE" +
"IFORM SIGN SAG TIMES MICUNEIFORM SIGN SAG TIMES NUNCUNEIFORM SIGN SAG TI" +
"MES SALCUNEIFORM SIGN SAG TIMES SHIDCUNEIFORM SIGN SAG TIMES TABCUNEIFOR" +
"M SIGN SAG TIMES U2CUNEIFORM SIGN SAG TIMES UBCUNEIFORM SIGN SAG TIMES U" +
"MCUNEIFORM SIGN SAG TIMES URCUNEIFORM SIGN SAG TIMES USHCUNEIFORM SIGN S" +
"AG OVER SAGCUNEIFORM SIGN SAG GUNUCUNEIFORM SIGN SALCUNEIFORM SIGN SAL L" +
"AGAB TIMES ASH2CUNEIFORM SIGN SANGA2CUNEIFORM SIGN SARCUNEIFORM SIGN SHA" +
"CUNEIFORM SIGN SHA3CUNEIFORM SIGN SHA3 TIMES ACUNEIFORM SIGN SHA3 TIMES " +
"BADCUNEIFORM SIGN SHA3 TIMES GISHCUNEIFORM SIGN SHA3 TIMES NECUNEIFORM S" +
"IGN SHA3 TIMES SHU2CUNEIFORM SIGN SHA3 TIMES TURCUNEIFORM SIGN SHA3 TIME" +
"S UCUNEIFORM SIGN SHA3 TIMES U PLUS ACUNEIFORM SIGN SHA6CUNEIFORM SIGN S" +
"HAB6CUNEIFORM SIGN SHAR2CUNEIFORM SIGN SHECUNEIFORM SIGN SHE HUCUNEIFORM" +
" SIGN SHE OVER SHE GAD OVER GAD GAR OVER GARCUNEIFORM SIGN SHE OVER SHE " +
"TAB OVER TAB GAR OVER GARCUNEIFORM SIGN SHEG9CUNEIFORM SIGN SHENCUNEIFOR" +
"M SIGN SHESHCUNEIFORM SIGN SHESH2CUNEIFORM SIGN SHESHLAMCUNEIFORM SIGN S" +
"HIDCUNEIFORM SIGN SHID TIMES ACUNEIFORM SIGN SHID TIMES IMCUNEIFORM SIGN" +
" SHIMCUNEIFORM SIGN SHIM TIMES ACUNEIFORM SIGN SHIM TIMES BALCUNEIFORM S" +
"IGN SHIM TIMES BULUGCUNEIFORM SIGN SHIM TIMES DINCUNEIFORM SIGN SHIM TIM" +
"ES GARCUNEIFORM SIGN SHIM TIMES IGICUNEIFORM SIGN SHIM TIMES IGI GUNUCUN" +
"EIFORM SIGN SHIM TIMES KUSHU2CUNEIFORM SIGN SHIM TIMES LULCUNEIFORM SIGN" +
" SHIM TIMES MUGCUNEIFORM SIGN SHIM TIMES SALCUNEIFORM SIGN SHINIGCUNEIFO" +
"RM SIGN SHIRCUNEIFORM SIGN SHIR TENUCUNEIFORM SIGN SHIR OVER SHIR BUR OV" +
"ER BURCUNEIFORM SIGN SHITACUNEIFORM SIGN SHUCUNEIFORM SIGN SHU OVER INVE" +
"RTED SHUCUNEIFORM SIGN SHU2CUNEIFORM SIGN SHUBURCUNEIFORM SIGN SICUNEIFO" +
"RM SIGN SI GUNUCUNEIFORM SIGN SIGCUNEIFORM SIGN SIG4CUNEIFORM SIGN SIG4 " +
"OVER SIG4 SHU2CUNEIFORM SIGN SIK2CUNEIFORM SIGN SILA3CUNEIFORM SIGN SUCU") + ("" +
"NEIFORM SIGN SU OVER SUCUNEIFORM SIGN SUDCUNEIFORM SIGN SUD2CUNEIFORM SI" +
"GN SUHURCUNEIFORM SIGN SUMCUNEIFORM SIGN SUMASHCUNEIFORM SIGN SURCUNEIFO" +
"RM SIGN SUR9CUNEIFORM SIGN TACUNEIFORM SIGN TA ASTERISKCUNEIFORM SIGN TA" +
" TIMES HICUNEIFORM SIGN TA TIMES MICUNEIFORM SIGN TA GUNUCUNEIFORM SIGN " +
"TABCUNEIFORM SIGN TAB OVER TAB NI OVER NI DISH OVER DISHCUNEIFORM SIGN T" +
"AB SQUAREDCUNEIFORM SIGN TAGCUNEIFORM SIGN TAG TIMES BICUNEIFORM SIGN TA" +
"G TIMES GUDCUNEIFORM SIGN TAG TIMES SHECUNEIFORM SIGN TAG TIMES SHUCUNEI" +
"FORM SIGN TAG TIMES TUG2CUNEIFORM SIGN TAG TIMES UDCUNEIFORM SIGN TAK4CU" +
"NEIFORM SIGN TARCUNEIFORM SIGN TECUNEIFORM SIGN TE GUNUCUNEIFORM SIGN TI" +
"CUNEIFORM SIGN TI TENUCUNEIFORM SIGN TILCUNEIFORM SIGN TIRCUNEIFORM SIGN" +
" TIR TIMES TAK4CUNEIFORM SIGN TIR OVER TIRCUNEIFORM SIGN TIR OVER TIR GA" +
"D OVER GAD GAR OVER GARCUNEIFORM SIGN TUCUNEIFORM SIGN TUG2CUNEIFORM SIG" +
"N TUKCUNEIFORM SIGN TUMCUNEIFORM SIGN TURCUNEIFORM SIGN TUR OVER TUR ZA " +
"OVER ZACUNEIFORM SIGN UCUNEIFORM SIGN U GUDCUNEIFORM SIGN U U UCUNEIFORM" +
" SIGN U OVER U PA OVER PA GAR OVER GARCUNEIFORM SIGN U OVER U SUR OVER S" +
"URCUNEIFORM SIGN U OVER U U REVERSED OVER U REVERSEDCUNEIFORM SIGN U2CUN" +
"EIFORM SIGN UBCUNEIFORM SIGN UDCUNEIFORM SIGN UD KUSHU2CUNEIFORM SIGN UD" +
" TIMES BADCUNEIFORM SIGN UD TIMES MICUNEIFORM SIGN UD TIMES U PLUS U PLU" +
"S UCUNEIFORM SIGN UD TIMES U PLUS U PLUS U GUNUCUNEIFORM SIGN UD GUNUCUN" +
"EIFORM SIGN UD SHESHIGCUNEIFORM SIGN UD SHESHIG TIMES BADCUNEIFORM SIGN " +
"UDUGCUNEIFORM SIGN UMCUNEIFORM SIGN UM TIMES LAGABCUNEIFORM SIGN UM TIME" +
"S ME PLUS DACUNEIFORM SIGN UM TIMES SHA3CUNEIFORM SIGN UM TIMES UCUNEIFO" +
"RM SIGN UMBINCUNEIFORM SIGN UMUMCUNEIFORM SIGN UMUM TIMES KASKALCUNEIFOR" +
"M SIGN UMUM TIMES PACUNEIFORM SIGN UNCUNEIFORM SIGN UN GUNUCUNEIFORM SIG" +
"N URCUNEIFORM SIGN UR CROSSING URCUNEIFORM SIGN UR SHESHIGCUNEIFORM SIGN" +
" UR2CUNEIFORM SIGN UR2 TIMES A PLUS HACUNEIFORM SIGN UR2 TIMES A PLUS NA" +
"CUNEIFORM SIGN UR2 TIMES ALCUNEIFORM SIGN UR2 TIMES HACUNEIFORM SIGN UR2" +
" TIMES NUNCUNEIFORM SIGN UR2 TIMES U2CUNEIFORM SIGN UR2 TIMES U2 PLUS AS" +
"HCUNEIFORM SIGN UR2 TIMES U2 PLUS BICUNEIFORM SIGN UR4CUNEIFORM SIGN URI" +
"CUNEIFORM SIGN URI3CUNEIFORM SIGN URUCUNEIFORM SIGN URU TIMES ACUNEIFORM" +
" SIGN URU TIMES ASHGABCUNEIFORM SIGN URU TIMES BARCUNEIFORM SIGN URU TIM" +
"ES DUNCUNEIFORM SIGN URU TIMES GACUNEIFORM SIGN URU TIMES GALCUNEIFORM S" +
"IGN URU TIMES GAN2 TENUCUNEIFORM SIGN URU TIMES GARCUNEIFORM SIGN URU TI" +
"MES GUCUNEIFORM SIGN URU TIMES HACUNEIFORM SIGN URU TIMES IGICUNEIFORM S" +
"IGN URU TIMES IMCUNEIFORM SIGN URU TIMES ISHCUNEIFORM SIGN URU TIMES KIC" +
"UNEIFORM SIGN URU TIMES LUMCUNEIFORM SIGN URU TIMES MINCUNEIFORM SIGN UR" +
"U TIMES PACUNEIFORM SIGN URU TIMES SHECUNEIFORM SIGN URU TIMES SIG4CUNEI" +
"FORM SIGN URU TIMES TUCUNEIFORM SIGN URU TIMES U PLUS GUDCUNEIFORM SIGN " +
"URU TIMES UDCUNEIFORM SIGN URU TIMES URUDACUNEIFORM SIGN URUDACUNEIFORM " +
"SIGN URUDA TIMES UCUNEIFORM SIGN USHCUNEIFORM SIGN USH TIMES ACUNEIFORM " +
"SIGN USH TIMES KUCUNEIFORM SIGN USH TIMES KURCUNEIFORM SIGN USH TIMES TA" +
"K4CUNEIFORM SIGN USHXCUNEIFORM SIGN USH2CUNEIFORM SIGN USHUMXCUNEIFORM S" +
"IGN UTUKICUNEIFORM SIGN UZ3CUNEIFORM SIGN UZ3 TIMES KASKALCUNEIFORM SIGN" +
" UZUCUNEIFORM SIGN ZACUNEIFORM SIGN ZA TENUCUNEIFORM SIGN ZA SQUARED TIM" +
"ES KURCUNEIFORM SIGN ZAGCUNEIFORM SIGN ZAMXCUNEIFORM SIGN ZE2CUNEIFORM S" +
"IGN ZICUNEIFORM SIGN ZI OVER ZICUNEIFORM SIGN ZI3CUNEIFORM SIGN ZIBCUNEI" +
"FORM SIGN ZIB KABA TENUCUNEIFORM SIGN ZIGCUNEIFORM SIGN ZIZ2CUNEIFORM SI" +
"GN ZUCUNEIFORM SIGN ZU5CUNEIFORM SIGN ZU5 TIMES ACUNEIFORM SIGN ZUBURCUN" +
"EIFORM SIGN ZUMCUNEIFORM SIGN KAP ELAMITECUNEIFORM SIGN AB TIMES NUNCUNE" +
"IFORM SIGN AB2 TIMES ACUNEIFORM SIGN AMAR TIMES KUGCUNEIFORM SIGN DAG KI" +
"SIM5 TIMES U2 PLUS MASHCUNEIFORM SIGN DAG3CUNEIFORM SIGN DISH PLUS SHUCU" +
"NEIFORM SIGN DUB TIMES SHECUNEIFORM SIGN EZEN TIMES GUDCUNEIFORM SIGN EZ" +
"EN TIMES SHECUNEIFORM SIGN GA2 TIMES AN PLUS KAK PLUS ACUNEIFORM SIGN GA" +
"2 TIMES ASH2CUNEIFORM SIGN GE22CUNEIFORM SIGN GIGCUNEIFORM SIGN HUSHCUNE" +
"IFORM SIGN KA TIMES ANSHECUNEIFORM SIGN KA TIMES ASH3CUNEIFORM SIGN KA T" +
"IMES GISHCUNEIFORM SIGN KA TIMES GUDCUNEIFORM SIGN KA TIMES HI TIMES ASH" +
"2CUNEIFORM SIGN KA TIMES LUMCUNEIFORM SIGN KA TIMES PACUNEIFORM SIGN KA " +
"TIMES SHULCUNEIFORM SIGN KA TIMES TUCUNEIFORM SIGN KA TIMES UR2CUNEIFORM" +
" SIGN LAGAB TIMES GICUNEIFORM SIGN LU2 SHESHIG TIMES BADCUNEIFORM SIGN L" +
"U2 TIMES ESH2 PLUS LALCUNEIFORM SIGN LU2 TIMES SHUCUNEIFORM SIGN MESHCUN" +
"EIFORM SIGN MUSH3 TIMES ZACUNEIFORM SIGN NA4CUNEIFORM SIGN NINCUNEIFORM " +
"SIGN NIN9CUNEIFORM SIGN NINDA2 TIMES BALCUNEIFORM SIGN NINDA2 TIMES GICU" +
"NEIFORM SIGN NU11 ROTATED NINETY DEGREESCUNEIFORM SIGN PESH2 ASTERISKCUN" +
"EIFORM SIGN PIR2CUNEIFORM SIGN SAG TIMES IGI GUNUCUNEIFORM SIGN TI2CUNEI") + ("" +
"FORM SIGN UM TIMES MECUNEIFORM SIGN U UCUNEIFORM NUMERIC SIGN TWO ASHCUN" +
"EIFORM NUMERIC SIGN THREE ASHCUNEIFORM NUMERIC SIGN FOUR ASHCUNEIFORM NU" +
"MERIC SIGN FIVE ASHCUNEIFORM NUMERIC SIGN SIX ASHCUNEIFORM NUMERIC SIGN " +
"SEVEN ASHCUNEIFORM NUMERIC SIGN EIGHT ASHCUNEIFORM NUMERIC SIGN NINE ASH" +
"CUNEIFORM NUMERIC SIGN THREE DISHCUNEIFORM NUMERIC SIGN FOUR DISHCUNEIFO" +
"RM NUMERIC SIGN FIVE DISHCUNEIFORM NUMERIC SIGN SIX DISHCUNEIFORM NUMERI" +
"C SIGN SEVEN DISHCUNEIFORM NUMERIC SIGN EIGHT DISHCUNEIFORM NUMERIC SIGN" +
" NINE DISHCUNEIFORM NUMERIC SIGN FOUR UCUNEIFORM NUMERIC SIGN FIVE UCUNE" +
"IFORM NUMERIC SIGN SIX UCUNEIFORM NUMERIC SIGN SEVEN UCUNEIFORM NUMERIC " +
"SIGN EIGHT UCUNEIFORM NUMERIC SIGN NINE UCUNEIFORM NUMERIC SIGN ONE GESH" +
"2CUNEIFORM NUMERIC SIGN TWO GESH2CUNEIFORM NUMERIC SIGN THREE GESH2CUNEI" +
"FORM NUMERIC SIGN FOUR GESH2CUNEIFORM NUMERIC SIGN FIVE GESH2CUNEIFORM N" +
"UMERIC SIGN SIX GESH2CUNEIFORM NUMERIC SIGN SEVEN GESH2CUNEIFORM NUMERIC" +
" SIGN EIGHT GESH2CUNEIFORM NUMERIC SIGN NINE GESH2CUNEIFORM NUMERIC SIGN" +
" ONE GESHUCUNEIFORM NUMERIC SIGN TWO GESHUCUNEIFORM NUMERIC SIGN THREE G" +
"ESHUCUNEIFORM NUMERIC SIGN FOUR GESHUCUNEIFORM NUMERIC SIGN FIVE GESHUCU" +
"NEIFORM NUMERIC SIGN TWO SHAR2CUNEIFORM NUMERIC SIGN THREE SHAR2CUNEIFOR" +
"M NUMERIC SIGN THREE SHAR2 VARIANT FORMCUNEIFORM NUMERIC SIGN FOUR SHAR2" +
"CUNEIFORM NUMERIC SIGN FIVE SHAR2CUNEIFORM NUMERIC SIGN SIX SHAR2CUNEIFO" +
"RM NUMERIC SIGN SEVEN SHAR2CUNEIFORM NUMERIC SIGN EIGHT SHAR2CUNEIFORM N" +
"UMERIC SIGN NINE SHAR2CUNEIFORM NUMERIC SIGN ONE SHARUCUNEIFORM NUMERIC " +
"SIGN TWO SHARUCUNEIFORM NUMERIC SIGN THREE SHARUCUNEIFORM NUMERIC SIGN T" +
"HREE SHARU VARIANT FORMCUNEIFORM NUMERIC SIGN FOUR SHARUCUNEIFORM NUMERI" +
"C SIGN FIVE SHARUCUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS DISHCUNEIFO" +
"RM NUMERIC SIGN SHAR2 TIMES GAL PLUS MINCUNEIFORM NUMERIC SIGN ONE BURUC" +
"UNEIFORM NUMERIC SIGN TWO BURUCUNEIFORM NUMERIC SIGN THREE BURUCUNEIFORM" +
" NUMERIC SIGN THREE BURU VARIANT FORMCUNEIFORM NUMERIC SIGN FOUR BURUCUN" +
"EIFORM NUMERIC SIGN FIVE BURUCUNEIFORM NUMERIC SIGN THREE VARIANT FORM E" +
"SH16CUNEIFORM NUMERIC SIGN THREE VARIANT FORM ESH21CUNEIFORM NUMERIC SIG" +
"N FOUR VARIANT FORM LIMMUCUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU4" +
"CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU ACUNEIFORM NUMERIC SIGN F" +
"OUR VARIANT FORM LIMMU BCUNEIFORM NUMERIC SIGN SIX VARIANT FORM ASH9CUNE" +
"IFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN3CUNEIFORM NUMERIC SIGN SEVEN " +
"VARIANT FORM IMIN ACUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN BCUNEI" +
"FORM NUMERIC SIGN EIGHT VARIANT FORM USSUCUNEIFORM NUMERIC SIGN EIGHT VA" +
"RIANT FORM USSU3CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMUCUNEIFORM" +
" NUMERIC SIGN NINE VARIANT FORM ILIMMU3CUNEIFORM NUMERIC SIGN NINE VARIA" +
"NT FORM ILIMMU4CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU ACUNEIFOR" +
"M NUMERIC SIGN TWO ASH TENUCUNEIFORM NUMERIC SIGN THREE ASH TENUCUNEIFOR" +
"M NUMERIC SIGN FOUR ASH TENUCUNEIFORM NUMERIC SIGN FIVE ASH TENUCUNEIFOR" +
"M NUMERIC SIGN SIX ASH TENUCUNEIFORM NUMERIC SIGN ONE BAN2CUNEIFORM NUME" +
"RIC SIGN TWO BAN2CUNEIFORM NUMERIC SIGN THREE BAN2CUNEIFORM NUMERIC SIGN" +
" FOUR BAN2CUNEIFORM NUMERIC SIGN FOUR BAN2 VARIANT FORMCUNEIFORM NUMERIC" +
" SIGN FIVE BAN2CUNEIFORM NUMERIC SIGN FIVE BAN2 VARIANT FORMCUNEIFORM NU" +
"MERIC SIGN NIGIDAMINCUNEIFORM NUMERIC SIGN NIGIDAESHCUNEIFORM NUMERIC SI" +
"GN ONE ESHE3CUNEIFORM NUMERIC SIGN TWO ESHE3CUNEIFORM NUMERIC SIGN ONE T" +
"HIRD DISHCUNEIFORM NUMERIC SIGN TWO THIRDS DISHCUNEIFORM NUMERIC SIGN FI" +
"VE SIXTHS DISHCUNEIFORM NUMERIC SIGN ONE THIRD VARIANT FORM ACUNEIFORM N" +
"UMERIC SIGN TWO THIRDS VARIANT FORM ACUNEIFORM NUMERIC SIGN ONE EIGHTH A" +
"SHCUNEIFORM NUMERIC SIGN ONE QUARTER ASHCUNEIFORM NUMERIC SIGN OLD ASSYR" +
"IAN ONE SIXTHCUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE QUARTERCUNEIFORM NU" +
"MERIC SIGN ONE QUARTER GURCUNEIFORM NUMERIC SIGN ONE HALF GURCUNEIFORM N" +
"UMERIC SIGN ELAMITE ONE THIRDCUNEIFORM NUMERIC SIGN ELAMITE TWO THIRDSCU" +
"NEIFORM NUMERIC SIGN ELAMITE FORTYCUNEIFORM NUMERIC SIGN ELAMITE FIFTYCU" +
"NEIFORM NUMERIC SIGN FOUR U VARIANT FORMCUNEIFORM NUMERIC SIGN FIVE U VA" +
"RIANT FORMCUNEIFORM NUMERIC SIGN SIX U VARIANT FORMCUNEIFORM NUMERIC SIG" +
"N SEVEN U VARIANT FORMCUNEIFORM NUMERIC SIGN EIGHT U VARIANT FORMCUNEIFO" +
"RM NUMERIC SIGN NINE U VARIANT FORMCUNEIFORM PUNCTUATION SIGN OLD ASSYRI" +
"AN WORD DIVIDERCUNEIFORM PUNCTUATION SIGN VERTICAL COLONCUNEIFORM PUNCTU" +
"ATION SIGN DIAGONAL COLONCUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLONCUN" +
"EIFORM PUNCTUATION SIGN DIAGONAL QUADCOLONCUNEIFORM SIGN AB TIMES NUN TE" +
"NUCUNEIFORM SIGN AB TIMES SHU2CUNEIFORM SIGN AD TIMES ESH2CUNEIFORM SIGN" +
" BAD TIMES DISH TENUCUNEIFORM SIGN BAHAR2 TIMES AB2CUNEIFORM SIGN BAHAR2" +
" TIMES NICUNEIFORM SIGN BAHAR2 TIMES ZACUNEIFORM SIGN BU OVER BU TIMES N") + ("" +
"A2CUNEIFORM SIGN DA TIMES TAK4CUNEIFORM SIGN DAG TIMES KURCUNEIFORM SIGN" +
" DIM TIMES IGICUNEIFORM SIGN DIM TIMES U U UCUNEIFORM SIGN DIM2 TIMES UD" +
"CUNEIFORM SIGN DUG TIMES ANSHECUNEIFORM SIGN DUG TIMES ASHCUNEIFORM SIGN" +
" DUG TIMES ASH AT LEFTCUNEIFORM SIGN DUG TIMES DINCUNEIFORM SIGN DUG TIM" +
"ES DUNCUNEIFORM SIGN DUG TIMES ERIN2CUNEIFORM SIGN DUG TIMES GACUNEIFORM" +
" SIGN DUG TIMES GICUNEIFORM SIGN DUG TIMES GIR2 GUNUCUNEIFORM SIGN DUG T" +
"IMES GISHCUNEIFORM SIGN DUG TIMES HACUNEIFORM SIGN DUG TIMES HICUNEIFORM" +
" SIGN DUG TIMES IGI GUNUCUNEIFORM SIGN DUG TIMES KASKALCUNEIFORM SIGN DU" +
"G TIMES KURCUNEIFORM SIGN DUG TIMES KUSHU2CUNEIFORM SIGN DUG TIMES KUSHU" +
"2 PLUS KASKALCUNEIFORM SIGN DUG TIMES LAK-020CUNEIFORM SIGN DUG TIMES LA" +
"MCUNEIFORM SIGN DUG TIMES LAM TIMES KURCUNEIFORM SIGN DUG TIMES LUH PLUS" +
" GISHCUNEIFORM SIGN DUG TIMES MASHCUNEIFORM SIGN DUG TIMES MESCUNEIFORM " +
"SIGN DUG TIMES MICUNEIFORM SIGN DUG TIMES NICUNEIFORM SIGN DUG TIMES PIC" +
"UNEIFORM SIGN DUG TIMES SHECUNEIFORM SIGN DUG TIMES SI GUNUCUNEIFORM SIG" +
"N E2 TIMES KURCUNEIFORM SIGN E2 TIMES PAPCUNEIFORM SIGN ERIN2 XCUNEIFORM" +
" SIGN ESH2 CROSSING ESH2CUNEIFORM SIGN EZEN SHESHIG TIMES ASHCUNEIFORM S" +
"IGN EZEN SHESHIG TIMES HICUNEIFORM SIGN EZEN SHESHIG TIMES IGI GUNUCUNEI" +
"FORM SIGN EZEN SHESHIG TIMES LACUNEIFORM SIGN EZEN SHESHIG TIMES LALCUNE" +
"IFORM SIGN EZEN SHESHIG TIMES MECUNEIFORM SIGN EZEN SHESHIG TIMES MESCUN" +
"EIFORM SIGN EZEN SHESHIG TIMES SUCUNEIFORM SIGN EZEN TIMES SUCUNEIFORM S" +
"IGN GA2 TIMES BAHAR2CUNEIFORM SIGN GA2 TIMES DIM GUNUCUNEIFORM SIGN GA2 " +
"TIMES DUG TIMES IGI GUNUCUNEIFORM SIGN GA2 TIMES DUG TIMES KASKALCUNEIFO" +
"RM SIGN GA2 TIMES ERENCUNEIFORM SIGN GA2 TIMES GACUNEIFORM SIGN GA2 TIME" +
"S GAR PLUS DICUNEIFORM SIGN GA2 TIMES GAR PLUS NECUNEIFORM SIGN GA2 TIME" +
"S HA PLUS ACUNEIFORM SIGN GA2 TIMES KUSHU2 PLUS KASKALCUNEIFORM SIGN GA2" +
" TIMES LAMCUNEIFORM SIGN GA2 TIMES LAM TIMES KURCUNEIFORM SIGN GA2 TIMES" +
" LUHCUNEIFORM SIGN GA2 TIMES MUSHCUNEIFORM SIGN GA2 TIMES NECUNEIFORM SI" +
"GN GA2 TIMES NE PLUS E2CUNEIFORM SIGN GA2 TIMES NE PLUS GICUNEIFORM SIGN" +
" GA2 TIMES SHIMCUNEIFORM SIGN GA2 TIMES ZIZ2CUNEIFORM SIGN GABA ROTATED " +
"NINETY DEGREESCUNEIFORM SIGN GESHTIN TIMES UCUNEIFORM SIGN GISH TIMES GI" +
"SH CROSSING GISHCUNEIFORM SIGN GU2 TIMES IGI GUNUCUNEIFORM SIGN GUD PLUS" +
" GISH TIMES TAK4CUNEIFORM SIGN HA TENU GUNUCUNEIFORM SIGN HI TIMES ASH O" +
"VER HI TIMES ASHCUNEIFORM SIGN KA TIMES BUCUNEIFORM SIGN KA TIMES KACUNE" +
"IFORM SIGN KA TIMES U U UCUNEIFORM SIGN KA TIMES URCUNEIFORM SIGN LAGAB " +
"TIMES ZU OVER ZUCUNEIFORM SIGN LAK-003CUNEIFORM SIGN LAK-021CUNEIFORM SI" +
"GN LAK-025CUNEIFORM SIGN LAK-030CUNEIFORM SIGN LAK-050CUNEIFORM SIGN LAK" +
"-051CUNEIFORM SIGN LAK-062CUNEIFORM SIGN LAK-079 OVER LAK-079 GUNUCUNEIF" +
"ORM SIGN LAK-080CUNEIFORM SIGN LAK-081 OVER LAK-081CUNEIFORM SIGN LAK-09" +
"2CUNEIFORM SIGN LAK-130CUNEIFORM SIGN LAK-142CUNEIFORM SIGN LAK-210CUNEI" +
"FORM SIGN LAK-219CUNEIFORM SIGN LAK-220CUNEIFORM SIGN LAK-225CUNEIFORM S" +
"IGN LAK-228CUNEIFORM SIGN LAK-238CUNEIFORM SIGN LAK-265CUNEIFORM SIGN LA" +
"K-266CUNEIFORM SIGN LAK-343CUNEIFORM SIGN LAK-347CUNEIFORM SIGN LAK-348C" +
"UNEIFORM SIGN LAK-383CUNEIFORM SIGN LAK-384CUNEIFORM SIGN LAK-390CUNEIFO" +
"RM SIGN LAK-441CUNEIFORM SIGN LAK-449CUNEIFORM SIGN LAK-449 TIMES GUCUNE" +
"IFORM SIGN LAK-449 TIMES IGICUNEIFORM SIGN LAK-449 TIMES PAP PLUS LU3CUN" +
"EIFORM SIGN LAK-449 TIMES PAP PLUS PAP PLUS LU3CUNEIFORM SIGN LAK-449 TI" +
"MES U2 PLUS BACUNEIFORM SIGN LAK-450CUNEIFORM SIGN LAK-457CUNEIFORM SIGN" +
" LAK-470CUNEIFORM SIGN LAK-483CUNEIFORM SIGN LAK-490CUNEIFORM SIGN LAK-4" +
"92CUNEIFORM SIGN LAK-493CUNEIFORM SIGN LAK-495CUNEIFORM SIGN LAK-550CUNE" +
"IFORM SIGN LAK-608CUNEIFORM SIGN LAK-617CUNEIFORM SIGN LAK-617 TIMES ASH" +
"CUNEIFORM SIGN LAK-617 TIMES BADCUNEIFORM SIGN LAK-617 TIMES DUN3 GUNU G" +
"UNUCUNEIFORM SIGN LAK-617 TIMES KU3CUNEIFORM SIGN LAK-617 TIMES LACUNEIF" +
"ORM SIGN LAK-617 TIMES TARCUNEIFORM SIGN LAK-617 TIMES TECUNEIFORM SIGN " +
"LAK-617 TIMES U2CUNEIFORM SIGN LAK-617 TIMES UDCUNEIFORM SIGN LAK-617 TI" +
"MES URUDACUNEIFORM SIGN LAK-636CUNEIFORM SIGN LAK-648CUNEIFORM SIGN LAK-" +
"648 TIMES DUBCUNEIFORM SIGN LAK-648 TIMES GACUNEIFORM SIGN LAK-648 TIMES" +
" IGICUNEIFORM SIGN LAK-648 TIMES IGI GUNUCUNEIFORM SIGN LAK-648 TIMES NI" +
"CUNEIFORM SIGN LAK-648 TIMES PAP PLUS PAP PLUS LU3CUNEIFORM SIGN LAK-648" +
" TIMES SHESH PLUS KICUNEIFORM SIGN LAK-648 TIMES UDCUNEIFORM SIGN LAK-64" +
"8 TIMES URUDACUNEIFORM SIGN LAK-724CUNEIFORM SIGN LAK-749CUNEIFORM SIGN " +
"LU2 GUNU TIMES ASHCUNEIFORM SIGN LU2 TIMES DISHCUNEIFORM SIGN LU2 TIMES " +
"HALCUNEIFORM SIGN LU2 TIMES PAPCUNEIFORM SIGN LU2 TIMES PAP PLUS PAP PLU" +
"S LU3CUNEIFORM SIGN LU2 TIMES TAK4CUNEIFORM SIGN MI PLUS ZA7CUNEIFORM SI" +
"GN MUSH OVER MUSH TIMES GACUNEIFORM SIGN MUSH OVER MUSH TIMES KAKCUNEIFO") + ("" +
"RM SIGN NINDA2 TIMES DIM GUNUCUNEIFORM SIGN NINDA2 TIMES GISHCUNEIFORM S" +
"IGN NINDA2 TIMES GULCUNEIFORM SIGN NINDA2 TIMES HICUNEIFORM SIGN NINDA2 " +
"TIMES KESH2CUNEIFORM SIGN NINDA2 TIMES LAK-050CUNEIFORM SIGN NINDA2 TIME" +
"S MASHCUNEIFORM SIGN NINDA2 TIMES PAP PLUS PAPCUNEIFORM SIGN NINDA2 TIME" +
"S UCUNEIFORM SIGN NINDA2 TIMES U PLUS UCUNEIFORM SIGN NINDA2 TIMES URUDA" +
"CUNEIFORM SIGN SAG GUNU TIMES HACUNEIFORM SIGN SAG TIMES ENCUNEIFORM SIG" +
"N SAG TIMES SHE AT LEFTCUNEIFORM SIGN SAG TIMES TAK4CUNEIFORM SIGN SHA6 " +
"TENUCUNEIFORM SIGN SHE OVER SHECUNEIFORM SIGN SHE PLUS HUB2CUNEIFORM SIG" +
"N SHE PLUS NAM2CUNEIFORM SIGN SHE PLUS SARCUNEIFORM SIGN SHU2 PLUS DUG T" +
"IMES NICUNEIFORM SIGN SHU2 PLUS E2 TIMES ANCUNEIFORM SIGN SI TIMES TAK4C" +
"UNEIFORM SIGN TAK4 PLUS SAGCUNEIFORM SIGN TUM TIMES GAN2 TENUCUNEIFORM S" +
"IGN TUM TIMES THREE DISHCUNEIFORM SIGN UR2 INVERTEDCUNEIFORM SIGN UR2 TI" +
"MES UDCUNEIFORM SIGN URU TIMES DARA3CUNEIFORM SIGN URU TIMES LAK-668CUNE" +
"IFORM SIGN URU TIMES LU3CUNEIFORM SIGN ZA7CUNEIFORM SIGN ZU OVER ZU PLUS" +
" SARCUNEIFORM SIGN ZU5 TIMES THREE DISH TENUCYPRO-MINOAN SIGN CM001CYPRO" +
"-MINOAN SIGN CM002CYPRO-MINOAN SIGN CM004CYPRO-MINOAN SIGN CM005CYPRO-MI" +
"NOAN SIGN CM006CYPRO-MINOAN SIGN CM007CYPRO-MINOAN SIGN CM008CYPRO-MINOA" +
"N SIGN CM009CYPRO-MINOAN SIGN CM010CYPRO-MINOAN SIGN CM011CYPRO-MINOAN S" +
"IGN CM012CYPRO-MINOAN SIGN CM012BCYPRO-MINOAN SIGN CM013CYPRO-MINOAN SIG" +
"N CM015CYPRO-MINOAN SIGN CM017CYPRO-MINOAN SIGN CM019CYPRO-MINOAN SIGN C" +
"M021CYPRO-MINOAN SIGN CM023CYPRO-MINOAN SIGN CM024CYPRO-MINOAN SIGN CM02" +
"5CYPRO-MINOAN SIGN CM026CYPRO-MINOAN SIGN CM027CYPRO-MINOAN SIGN CM028CY" +
"PRO-MINOAN SIGN CM029CYPRO-MINOAN SIGN CM030CYPRO-MINOAN SIGN CM033CYPRO" +
"-MINOAN SIGN CM034CYPRO-MINOAN SIGN CM035CYPRO-MINOAN SIGN CM036CYPRO-MI" +
"NOAN SIGN CM037CYPRO-MINOAN SIGN CM038CYPRO-MINOAN SIGN CM039CYPRO-MINOA" +
"N SIGN CM040CYPRO-MINOAN SIGN CM041CYPRO-MINOAN SIGN CM044CYPRO-MINOAN S" +
"IGN CM046CYPRO-MINOAN SIGN CM047CYPRO-MINOAN SIGN CM049CYPRO-MINOAN SIGN" +
" CM050CYPRO-MINOAN SIGN CM051CYPRO-MINOAN SIGN CM052CYPRO-MINOAN SIGN CM" +
"053CYPRO-MINOAN SIGN CM054CYPRO-MINOAN SIGN CM055CYPRO-MINOAN SIGN CM056" +
"CYPRO-MINOAN SIGN CM058CYPRO-MINOAN SIGN CM059CYPRO-MINOAN SIGN CM060CYP" +
"RO-MINOAN SIGN CM061CYPRO-MINOAN SIGN CM062CYPRO-MINOAN SIGN CM063CYPRO-" +
"MINOAN SIGN CM064CYPRO-MINOAN SIGN CM066CYPRO-MINOAN SIGN CM067CYPRO-MIN" +
"OAN SIGN CM068CYPRO-MINOAN SIGN CM069CYPRO-MINOAN SIGN CM070CYPRO-MINOAN" +
" SIGN CM071CYPRO-MINOAN SIGN CM072CYPRO-MINOAN SIGN CM073CYPRO-MINOAN SI" +
"GN CM074CYPRO-MINOAN SIGN CM075CYPRO-MINOAN SIGN CM075BCYPRO-MINOAN SIGN" +
" CM076CYPRO-MINOAN SIGN CM078CYPRO-MINOAN SIGN CM079CYPRO-MINOAN SIGN CM" +
"080CYPRO-MINOAN SIGN CM081CYPRO-MINOAN SIGN CM082CYPRO-MINOAN SIGN CM083" +
"CYPRO-MINOAN SIGN CM084CYPRO-MINOAN SIGN CM085CYPRO-MINOAN SIGN CM086CYP" +
"RO-MINOAN SIGN CM087CYPRO-MINOAN SIGN CM088CYPRO-MINOAN SIGN CM089CYPRO-" +
"MINOAN SIGN CM090CYPRO-MINOAN SIGN CM091CYPRO-MINOAN SIGN CM092CYPRO-MIN" +
"OAN SIGN CM094CYPRO-MINOAN SIGN CM095CYPRO-MINOAN SIGN CM096CYPRO-MINOAN" +
" SIGN CM097CYPRO-MINOAN SIGN CM098CYPRO-MINOAN SIGN CM099CYPRO-MINOAN SI" +
"GN CM100CYPRO-MINOAN SIGN CM101CYPRO-MINOAN SIGN CM102CYPRO-MINOAN SIGN " +
"CM103CYPRO-MINOAN SIGN CM104CYPRO-MINOAN SIGN CM105CYPRO-MINOAN SIGN CM1" +
"07CYPRO-MINOAN SIGN CM108CYPRO-MINOAN SIGN CM109CYPRO-MINOAN SIGN CM110C" +
"YPRO-MINOAN SIGN CM112CYPRO-MINOAN SIGN CM114CYPRO-MINOAN SIGN CM301CYPR" +
"O-MINOAN SIGN CM302EGYPTIAN HIEROGLYPH A001EGYPTIAN HIEROGLYPH A002EGYPT" +
"IAN HIEROGLYPH A003EGYPTIAN HIEROGLYPH A004EGYPTIAN HIEROGLYPH A005EGYPT" +
"IAN HIEROGLYPH A005AEGYPTIAN HIEROGLYPH A006EGYPTIAN HIEROGLYPH A006AEGY" +
"PTIAN HIEROGLYPH A006BEGYPTIAN HIEROGLYPH A007EGYPTIAN HIEROGLYPH A008EG" +
"YPTIAN HIEROGLYPH A009EGYPTIAN HIEROGLYPH A010EGYPTIAN HIEROGLYPH A011EG" +
"YPTIAN HIEROGLYPH A012EGYPTIAN HIEROGLYPH A013EGYPTIAN HIEROGLYPH A014EG" +
"YPTIAN HIEROGLYPH A014AEGYPTIAN HIEROGLYPH A015EGYPTIAN HIEROGLYPH A016E" +
"GYPTIAN HIEROGLYPH A017EGYPTIAN HIEROGLYPH A017AEGYPTIAN HIEROGLYPH A018" +
"EGYPTIAN HIEROGLYPH A019EGYPTIAN HIEROGLYPH A020EGYPTIAN HIEROGLYPH A021" +
"EGYPTIAN HIEROGLYPH A022EGYPTIAN HIEROGLYPH A023EGYPTIAN HIEROGLYPH A024" +
"EGYPTIAN HIEROGLYPH A025EGYPTIAN HIEROGLYPH A026EGYPTIAN HIEROGLYPH A027" +
"EGYPTIAN HIEROGLYPH A028EGYPTIAN HIEROGLYPH A029EGYPTIAN HIEROGLYPH A030" +
"EGYPTIAN HIEROGLYPH A031EGYPTIAN HIEROGLYPH A032EGYPTIAN HIEROGLYPH A032" +
"AEGYPTIAN HIEROGLYPH A033EGYPTIAN HIEROGLYPH A034EGYPTIAN HIEROGLYPH A03" +
"5EGYPTIAN HIEROGLYPH A036EGYPTIAN HIEROGLYPH A037EGYPTIAN HIEROGLYPH A03" +
"8EGYPTIAN HIEROGLYPH A039EGYPTIAN HIEROGLYPH A040EGYPTIAN HIEROGLYPH A04" +
"0AEGYPTIAN HIEROGLYPH A041EGYPTIAN HIEROGLYPH A042EGYPTIAN HIEROGLYPH A0" +
"42AEGYPTIAN HIEROGLYPH A043EGYPTIAN HIEROGLYPH A043AEGYPTIAN HIEROGLYPH ") + ("" +
"A044EGYPTIAN HIEROGLYPH A045EGYPTIAN HIEROGLYPH A045AEGYPTIAN HIEROGLYPH" +
" A046EGYPTIAN HIEROGLYPH A047EGYPTIAN HIEROGLYPH A048EGYPTIAN HIEROGLYPH" +
" A049EGYPTIAN HIEROGLYPH A050EGYPTIAN HIEROGLYPH A051EGYPTIAN HIEROGLYPH" +
" A052EGYPTIAN HIEROGLYPH A053EGYPTIAN HIEROGLYPH A054EGYPTIAN HIEROGLYPH" +
" A055EGYPTIAN HIEROGLYPH A056EGYPTIAN HIEROGLYPH A057EGYPTIAN HIEROGLYPH" +
" A058EGYPTIAN HIEROGLYPH A059EGYPTIAN HIEROGLYPH A060EGYPTIAN HIEROGLYPH" +
" A061EGYPTIAN HIEROGLYPH A062EGYPTIAN HIEROGLYPH A063EGYPTIAN HIEROGLYPH" +
" A064EGYPTIAN HIEROGLYPH A065EGYPTIAN HIEROGLYPH A066EGYPTIAN HIEROGLYPH" +
" A067EGYPTIAN HIEROGLYPH A068EGYPTIAN HIEROGLYPH A069EGYPTIAN HIEROGLYPH" +
" A070EGYPTIAN HIEROGLYPH B001EGYPTIAN HIEROGLYPH B002EGYPTIAN HIEROGLYPH" +
" B003EGYPTIAN HIEROGLYPH B004EGYPTIAN HIEROGLYPH B005EGYPTIAN HIEROGLYPH" +
" B005AEGYPTIAN HIEROGLYPH B006EGYPTIAN HIEROGLYPH B007EGYPTIAN HIEROGLYP" +
"H B008EGYPTIAN HIEROGLYPH B009EGYPTIAN HIEROGLYPH C001EGYPTIAN HIEROGLYP" +
"H C002EGYPTIAN HIEROGLYPH C002AEGYPTIAN HIEROGLYPH C002BEGYPTIAN HIEROGL" +
"YPH C002CEGYPTIAN HIEROGLYPH C003EGYPTIAN HIEROGLYPH C004EGYPTIAN HIEROG" +
"LYPH C005EGYPTIAN HIEROGLYPH C006EGYPTIAN HIEROGLYPH C007EGYPTIAN HIEROG" +
"LYPH C008EGYPTIAN HIEROGLYPH C009EGYPTIAN HIEROGLYPH C010EGYPTIAN HIEROG" +
"LYPH C010AEGYPTIAN HIEROGLYPH C011EGYPTIAN HIEROGLYPH C012EGYPTIAN HIERO" +
"GLYPH C013EGYPTIAN HIEROGLYPH C014EGYPTIAN HIEROGLYPH C015EGYPTIAN HIERO" +
"GLYPH C016EGYPTIAN HIEROGLYPH C017EGYPTIAN HIEROGLYPH C018EGYPTIAN HIERO" +
"GLYPH C019EGYPTIAN HIEROGLYPH C020EGYPTIAN HIEROGLYPH C021EGYPTIAN HIERO" +
"GLYPH C022EGYPTIAN HIEROGLYPH C023EGYPTIAN HIEROGLYPH C024EGYPTIAN HIERO" +
"GLYPH D001EGYPTIAN HIEROGLYPH D002EGYPTIAN HIEROGLYPH D003EGYPTIAN HIERO" +
"GLYPH D004EGYPTIAN HIEROGLYPH D005EGYPTIAN HIEROGLYPH D006EGYPTIAN HIERO" +
"GLYPH D007EGYPTIAN HIEROGLYPH D008EGYPTIAN HIEROGLYPH D008AEGYPTIAN HIER" +
"OGLYPH D009EGYPTIAN HIEROGLYPH D010EGYPTIAN HIEROGLYPH D011EGYPTIAN HIER" +
"OGLYPH D012EGYPTIAN HIEROGLYPH D013EGYPTIAN HIEROGLYPH D014EGYPTIAN HIER" +
"OGLYPH D015EGYPTIAN HIEROGLYPH D016EGYPTIAN HIEROGLYPH D017EGYPTIAN HIER" +
"OGLYPH D018EGYPTIAN HIEROGLYPH D019EGYPTIAN HIEROGLYPH D020EGYPTIAN HIER" +
"OGLYPH D021EGYPTIAN HIEROGLYPH D022EGYPTIAN HIEROGLYPH D023EGYPTIAN HIER" +
"OGLYPH D024EGYPTIAN HIEROGLYPH D025EGYPTIAN HIEROGLYPH D026EGYPTIAN HIER" +
"OGLYPH D027EGYPTIAN HIEROGLYPH D027AEGYPTIAN HIEROGLYPH D028EGYPTIAN HIE" +
"ROGLYPH D029EGYPTIAN HIEROGLYPH D030EGYPTIAN HIEROGLYPH D031EGYPTIAN HIE" +
"ROGLYPH D031AEGYPTIAN HIEROGLYPH D032EGYPTIAN HIEROGLYPH D033EGYPTIAN HI" +
"EROGLYPH D034EGYPTIAN HIEROGLYPH D034AEGYPTIAN HIEROGLYPH D035EGYPTIAN H" +
"IEROGLYPH D036EGYPTIAN HIEROGLYPH D037EGYPTIAN HIEROGLYPH D038EGYPTIAN H" +
"IEROGLYPH D039EGYPTIAN HIEROGLYPH D040EGYPTIAN HIEROGLYPH D041EGYPTIAN H" +
"IEROGLYPH D042EGYPTIAN HIEROGLYPH D043EGYPTIAN HIEROGLYPH D044EGYPTIAN H" +
"IEROGLYPH D045EGYPTIAN HIEROGLYPH D046EGYPTIAN HIEROGLYPH D046AEGYPTIAN " +
"HIEROGLYPH D047EGYPTIAN HIEROGLYPH D048EGYPTIAN HIEROGLYPH D048AEGYPTIAN" +
" HIEROGLYPH D049EGYPTIAN HIEROGLYPH D050EGYPTIAN HIEROGLYPH D050AEGYPTIA" +
"N HIEROGLYPH D050BEGYPTIAN HIEROGLYPH D050CEGYPTIAN HIEROGLYPH D050DEGYP" +
"TIAN HIEROGLYPH D050EEGYPTIAN HIEROGLYPH D050FEGYPTIAN HIEROGLYPH D050GE" +
"GYPTIAN HIEROGLYPH D050HEGYPTIAN HIEROGLYPH D050IEGYPTIAN HIEROGLYPH D05" +
"1EGYPTIAN HIEROGLYPH D052EGYPTIAN HIEROGLYPH D052AEGYPTIAN HIEROGLYPH D0" +
"53EGYPTIAN HIEROGLYPH D054EGYPTIAN HIEROGLYPH D054AEGYPTIAN HIEROGLYPH D" +
"055EGYPTIAN HIEROGLYPH D056EGYPTIAN HIEROGLYPH D057EGYPTIAN HIEROGLYPH D" +
"058EGYPTIAN HIEROGLYPH D059EGYPTIAN HIEROGLYPH D060EGYPTIAN HIEROGLYPH D" +
"061EGYPTIAN HIEROGLYPH D062EGYPTIAN HIEROGLYPH D063EGYPTIAN HIEROGLYPH D" +
"064EGYPTIAN HIEROGLYPH D065EGYPTIAN HIEROGLYPH D066EGYPTIAN HIEROGLYPH D" +
"067EGYPTIAN HIEROGLYPH D067AEGYPTIAN HIEROGLYPH D067BEGYPTIAN HIEROGLYPH" +
" D067CEGYPTIAN HIEROGLYPH D067DEGYPTIAN HIEROGLYPH D067EEGYPTIAN HIEROGL" +
"YPH D067FEGYPTIAN HIEROGLYPH D067GEGYPTIAN HIEROGLYPH D067HEGYPTIAN HIER" +
"OGLYPH E001EGYPTIAN HIEROGLYPH E002EGYPTIAN HIEROGLYPH E003EGYPTIAN HIER" +
"OGLYPH E004EGYPTIAN HIEROGLYPH E005EGYPTIAN HIEROGLYPH E006EGYPTIAN HIER" +
"OGLYPH E007EGYPTIAN HIEROGLYPH E008EGYPTIAN HIEROGLYPH E008AEGYPTIAN HIE" +
"ROGLYPH E009EGYPTIAN HIEROGLYPH E009AEGYPTIAN HIEROGLYPH E010EGYPTIAN HI" +
"EROGLYPH E011EGYPTIAN HIEROGLYPH E012EGYPTIAN HIEROGLYPH E013EGYPTIAN HI" +
"EROGLYPH E014EGYPTIAN HIEROGLYPH E015EGYPTIAN HIEROGLYPH E016EGYPTIAN HI" +
"EROGLYPH E016AEGYPTIAN HIEROGLYPH E017EGYPTIAN HIEROGLYPH E017AEGYPTIAN " +
"HIEROGLYPH E018EGYPTIAN HIEROGLYPH E019EGYPTIAN HIEROGLYPH E020EGYPTIAN " +
"HIEROGLYPH E020AEGYPTIAN HIEROGLYPH E021EGYPTIAN HIEROGLYPH E022EGYPTIAN" +
" HIEROGLYPH E023EGYPTIAN HIEROGLYPH E024EGYPTIAN HIEROGLYPH E025EGYPTIAN" +
" HIEROGLYPH E026EGYPTIAN HIEROGLYPH E027EGYPTIAN HIEROGLYPH E028EGYPTIAN") + ("" +
" HIEROGLYPH E028AEGYPTIAN HIEROGLYPH E029EGYPTIAN HIEROGLYPH E030EGYPTIA" +
"N HIEROGLYPH E031EGYPTIAN HIEROGLYPH E032EGYPTIAN HIEROGLYPH E033EGYPTIA" +
"N HIEROGLYPH E034EGYPTIAN HIEROGLYPH E034AEGYPTIAN HIEROGLYPH E036EGYPTI" +
"AN HIEROGLYPH E037EGYPTIAN HIEROGLYPH E038EGYPTIAN HIEROGLYPH F001EGYPTI" +
"AN HIEROGLYPH F001AEGYPTIAN HIEROGLYPH F002EGYPTIAN HIEROGLYPH F003EGYPT" +
"IAN HIEROGLYPH F004EGYPTIAN HIEROGLYPH F005EGYPTIAN HIEROGLYPH F006EGYPT" +
"IAN HIEROGLYPH F007EGYPTIAN HIEROGLYPH F008EGYPTIAN HIEROGLYPH F009EGYPT" +
"IAN HIEROGLYPH F010EGYPTIAN HIEROGLYPH F011EGYPTIAN HIEROGLYPH F012EGYPT" +
"IAN HIEROGLYPH F013EGYPTIAN HIEROGLYPH F013AEGYPTIAN HIEROGLYPH F014EGYP" +
"TIAN HIEROGLYPH F015EGYPTIAN HIEROGLYPH F016EGYPTIAN HIEROGLYPH F017EGYP" +
"TIAN HIEROGLYPH F018EGYPTIAN HIEROGLYPH F019EGYPTIAN HIEROGLYPH F020EGYP" +
"TIAN HIEROGLYPH F021EGYPTIAN HIEROGLYPH F021AEGYPTIAN HIEROGLYPH F022EGY" +
"PTIAN HIEROGLYPH F023EGYPTIAN HIEROGLYPH F024EGYPTIAN HIEROGLYPH F025EGY" +
"PTIAN HIEROGLYPH F026EGYPTIAN HIEROGLYPH F027EGYPTIAN HIEROGLYPH F028EGY" +
"PTIAN HIEROGLYPH F029EGYPTIAN HIEROGLYPH F030EGYPTIAN HIEROGLYPH F031EGY" +
"PTIAN HIEROGLYPH F031AEGYPTIAN HIEROGLYPH F032EGYPTIAN HIEROGLYPH F033EG" +
"YPTIAN HIEROGLYPH F034EGYPTIAN HIEROGLYPH F035EGYPTIAN HIEROGLYPH F036EG" +
"YPTIAN HIEROGLYPH F037EGYPTIAN HIEROGLYPH F037AEGYPTIAN HIEROGLYPH F038E" +
"GYPTIAN HIEROGLYPH F038AEGYPTIAN HIEROGLYPH F039EGYPTIAN HIEROGLYPH F040" +
"EGYPTIAN HIEROGLYPH F041EGYPTIAN HIEROGLYPH F042EGYPTIAN HIEROGLYPH F043" +
"EGYPTIAN HIEROGLYPH F044EGYPTIAN HIEROGLYPH F045EGYPTIAN HIEROGLYPH F045" +
"AEGYPTIAN HIEROGLYPH F046EGYPTIAN HIEROGLYPH F046AEGYPTIAN HIEROGLYPH F0" +
"47EGYPTIAN HIEROGLYPH F047AEGYPTIAN HIEROGLYPH F048EGYPTIAN HIEROGLYPH F" +
"049EGYPTIAN HIEROGLYPH F050EGYPTIAN HIEROGLYPH F051EGYPTIAN HIEROGLYPH F" +
"051AEGYPTIAN HIEROGLYPH F051BEGYPTIAN HIEROGLYPH F051CEGYPTIAN HIEROGLYP" +
"H F052EGYPTIAN HIEROGLYPH F053EGYPTIAN HIEROGLYPH G001EGYPTIAN HIEROGLYP" +
"H G002EGYPTIAN HIEROGLYPH G003EGYPTIAN HIEROGLYPH G004EGYPTIAN HIEROGLYP" +
"H G005EGYPTIAN HIEROGLYPH G006EGYPTIAN HIEROGLYPH G006AEGYPTIAN HIEROGLY" +
"PH G007EGYPTIAN HIEROGLYPH G007AEGYPTIAN HIEROGLYPH G007BEGYPTIAN HIEROG" +
"LYPH G008EGYPTIAN HIEROGLYPH G009EGYPTIAN HIEROGLYPH G010EGYPTIAN HIEROG" +
"LYPH G011EGYPTIAN HIEROGLYPH G011AEGYPTIAN HIEROGLYPH G012EGYPTIAN HIERO" +
"GLYPH G013EGYPTIAN HIEROGLYPH G014EGYPTIAN HIEROGLYPH G015EGYPTIAN HIERO" +
"GLYPH G016EGYPTIAN HIEROGLYPH G017EGYPTIAN HIEROGLYPH G018EGYPTIAN HIERO" +
"GLYPH G019EGYPTIAN HIEROGLYPH G020EGYPTIAN HIEROGLYPH G020AEGYPTIAN HIER" +
"OGLYPH G021EGYPTIAN HIEROGLYPH G022EGYPTIAN HIEROGLYPH G023EGYPTIAN HIER" +
"OGLYPH G024EGYPTIAN HIEROGLYPH G025EGYPTIAN HIEROGLYPH G026EGYPTIAN HIER" +
"OGLYPH G026AEGYPTIAN HIEROGLYPH G027EGYPTIAN HIEROGLYPH G028EGYPTIAN HIE" +
"ROGLYPH G029EGYPTIAN HIEROGLYPH G030EGYPTIAN HIEROGLYPH G031EGYPTIAN HIE" +
"ROGLYPH G032EGYPTIAN HIEROGLYPH G033EGYPTIAN HIEROGLYPH G034EGYPTIAN HIE" +
"ROGLYPH G035EGYPTIAN HIEROGLYPH G036EGYPTIAN HIEROGLYPH G036AEGYPTIAN HI" +
"EROGLYPH G037EGYPTIAN HIEROGLYPH G037AEGYPTIAN HIEROGLYPH G038EGYPTIAN H" +
"IEROGLYPH G039EGYPTIAN HIEROGLYPH G040EGYPTIAN HIEROGLYPH G041EGYPTIAN H" +
"IEROGLYPH G042EGYPTIAN HIEROGLYPH G043EGYPTIAN HIEROGLYPH G043AEGYPTIAN " +
"HIEROGLYPH G044EGYPTIAN HIEROGLYPH G045EGYPTIAN HIEROGLYPH G045AEGYPTIAN" +
" HIEROGLYPH G046EGYPTIAN HIEROGLYPH G047EGYPTIAN HIEROGLYPH G048EGYPTIAN" +
" HIEROGLYPH G049EGYPTIAN HIEROGLYPH G050EGYPTIAN HIEROGLYPH G051EGYPTIAN" +
" HIEROGLYPH G052EGYPTIAN HIEROGLYPH G053EGYPTIAN HIEROGLYPH G054EGYPTIAN" +
" HIEROGLYPH H001EGYPTIAN HIEROGLYPH H002EGYPTIAN HIEROGLYPH H003EGYPTIAN" +
" HIEROGLYPH H004EGYPTIAN HIEROGLYPH H005EGYPTIAN HIEROGLYPH H006EGYPTIAN" +
" HIEROGLYPH H006AEGYPTIAN HIEROGLYPH H007EGYPTIAN HIEROGLYPH H008EGYPTIA" +
"N HIEROGLYPH I001EGYPTIAN HIEROGLYPH I002EGYPTIAN HIEROGLYPH I003EGYPTIA" +
"N HIEROGLYPH I004EGYPTIAN HIEROGLYPH I005EGYPTIAN HIEROGLYPH I005AEGYPTI" +
"AN HIEROGLYPH I006EGYPTIAN HIEROGLYPH I007EGYPTIAN HIEROGLYPH I008EGYPTI" +
"AN HIEROGLYPH I009EGYPTIAN HIEROGLYPH I009AEGYPTIAN HIEROGLYPH I010EGYPT" +
"IAN HIEROGLYPH I010AEGYPTIAN HIEROGLYPH I011EGYPTIAN HIEROGLYPH I011AEGY" +
"PTIAN HIEROGLYPH I012EGYPTIAN HIEROGLYPH I013EGYPTIAN HIEROGLYPH I014EGY" +
"PTIAN HIEROGLYPH I015EGYPTIAN HIEROGLYPH K001EGYPTIAN HIEROGLYPH K002EGY" +
"PTIAN HIEROGLYPH K003EGYPTIAN HIEROGLYPH K004EGYPTIAN HIEROGLYPH K005EGY" +
"PTIAN HIEROGLYPH K006EGYPTIAN HIEROGLYPH K007EGYPTIAN HIEROGLYPH K008EGY" +
"PTIAN HIEROGLYPH L001EGYPTIAN HIEROGLYPH L002EGYPTIAN HIEROGLYPH L002AEG" +
"YPTIAN HIEROGLYPH L003EGYPTIAN HIEROGLYPH L004EGYPTIAN HIEROGLYPH L005EG" +
"YPTIAN HIEROGLYPH L006EGYPTIAN HIEROGLYPH L006AEGYPTIAN HIEROGLYPH L007E" +
"GYPTIAN HIEROGLYPH L008EGYPTIAN HIEROGLYPH M001EGYPTIAN HIEROGLYPH M001A" +
"EGYPTIAN HIEROGLYPH M001BEGYPTIAN HIEROGLYPH M002EGYPTIAN HIEROGLYPH M00") + ("" +
"3EGYPTIAN HIEROGLYPH M003AEGYPTIAN HIEROGLYPH M004EGYPTIAN HIEROGLYPH M0" +
"05EGYPTIAN HIEROGLYPH M006EGYPTIAN HIEROGLYPH M007EGYPTIAN HIEROGLYPH M0" +
"08EGYPTIAN HIEROGLYPH M009EGYPTIAN HIEROGLYPH M010EGYPTIAN HIEROGLYPH M0" +
"10AEGYPTIAN HIEROGLYPH M011EGYPTIAN HIEROGLYPH M012EGYPTIAN HIEROGLYPH M" +
"012AEGYPTIAN HIEROGLYPH M012BEGYPTIAN HIEROGLYPH M012CEGYPTIAN HIEROGLYP" +
"H M012DEGYPTIAN HIEROGLYPH M012EEGYPTIAN HIEROGLYPH M012FEGYPTIAN HIEROG" +
"LYPH M012GEGYPTIAN HIEROGLYPH M012HEGYPTIAN HIEROGLYPH M013EGYPTIAN HIER" +
"OGLYPH M014EGYPTIAN HIEROGLYPH M015EGYPTIAN HIEROGLYPH M015AEGYPTIAN HIE" +
"ROGLYPH M016EGYPTIAN HIEROGLYPH M016AEGYPTIAN HIEROGLYPH M017EGYPTIAN HI" +
"EROGLYPH M017AEGYPTIAN HIEROGLYPH M018EGYPTIAN HIEROGLYPH M019EGYPTIAN H" +
"IEROGLYPH M020EGYPTIAN HIEROGLYPH M021EGYPTIAN HIEROGLYPH M022EGYPTIAN H" +
"IEROGLYPH M022AEGYPTIAN HIEROGLYPH M023EGYPTIAN HIEROGLYPH M024EGYPTIAN " +
"HIEROGLYPH M024AEGYPTIAN HIEROGLYPH M025EGYPTIAN HIEROGLYPH M026EGYPTIAN" +
" HIEROGLYPH M027EGYPTIAN HIEROGLYPH M028EGYPTIAN HIEROGLYPH M028AEGYPTIA" +
"N HIEROGLYPH M029EGYPTIAN HIEROGLYPH M030EGYPTIAN HIEROGLYPH M031EGYPTIA" +
"N HIEROGLYPH M031AEGYPTIAN HIEROGLYPH M032EGYPTIAN HIEROGLYPH M033EGYPTI" +
"AN HIEROGLYPH M033AEGYPTIAN HIEROGLYPH M033BEGYPTIAN HIEROGLYPH M034EGYP" +
"TIAN HIEROGLYPH M035EGYPTIAN HIEROGLYPH M036EGYPTIAN HIEROGLYPH M037EGYP" +
"TIAN HIEROGLYPH M038EGYPTIAN HIEROGLYPH M039EGYPTIAN HIEROGLYPH M040EGYP" +
"TIAN HIEROGLYPH M040AEGYPTIAN HIEROGLYPH M041EGYPTIAN HIEROGLYPH M042EGY" +
"PTIAN HIEROGLYPH M043EGYPTIAN HIEROGLYPH M044EGYPTIAN HIEROGLYPH N001EGY" +
"PTIAN HIEROGLYPH N002EGYPTIAN HIEROGLYPH N003EGYPTIAN HIEROGLYPH N004EGY" +
"PTIAN HIEROGLYPH N005EGYPTIAN HIEROGLYPH N006EGYPTIAN HIEROGLYPH N007EGY" +
"PTIAN HIEROGLYPH N008EGYPTIAN HIEROGLYPH N009EGYPTIAN HIEROGLYPH N010EGY" +
"PTIAN HIEROGLYPH N011EGYPTIAN HIEROGLYPH N012EGYPTIAN HIEROGLYPH N013EGY" +
"PTIAN HIEROGLYPH N014EGYPTIAN HIEROGLYPH N015EGYPTIAN HIEROGLYPH N016EGY" +
"PTIAN HIEROGLYPH N017EGYPTIAN HIEROGLYPH N018EGYPTIAN HIEROGLYPH N018AEG" +
"YPTIAN HIEROGLYPH N018BEGYPTIAN HIEROGLYPH N019EGYPTIAN HIEROGLYPH N020E" +
"GYPTIAN HIEROGLYPH N021EGYPTIAN HIEROGLYPH N022EGYPTIAN HIEROGLYPH N023E" +
"GYPTIAN HIEROGLYPH N024EGYPTIAN HIEROGLYPH N025EGYPTIAN HIEROGLYPH N025A" +
"EGYPTIAN HIEROGLYPH N026EGYPTIAN HIEROGLYPH N027EGYPTIAN HIEROGLYPH N028" +
"EGYPTIAN HIEROGLYPH N029EGYPTIAN HIEROGLYPH N030EGYPTIAN HIEROGLYPH N031" +
"EGYPTIAN HIEROGLYPH N032EGYPTIAN HIEROGLYPH N033EGYPTIAN HIEROGLYPH N033" +
"AEGYPTIAN HIEROGLYPH N034EGYPTIAN HIEROGLYPH N034AEGYPTIAN HIEROGLYPH N0" +
"35EGYPTIAN HIEROGLYPH N035AEGYPTIAN HIEROGLYPH N036EGYPTIAN HIEROGLYPH N" +
"037EGYPTIAN HIEROGLYPH N037AEGYPTIAN HIEROGLYPH N038EGYPTIAN HIEROGLYPH " +
"N039EGYPTIAN HIEROGLYPH N040EGYPTIAN HIEROGLYPH N041EGYPTIAN HIEROGLYPH " +
"N042EGYPTIAN HIEROGLYPH NL001EGYPTIAN HIEROGLYPH NL002EGYPTIAN HIEROGLYP" +
"H NL003EGYPTIAN HIEROGLYPH NL004EGYPTIAN HIEROGLYPH NL005EGYPTIAN HIEROG" +
"LYPH NL005AEGYPTIAN HIEROGLYPH NL006EGYPTIAN HIEROGLYPH NL007EGYPTIAN HI" +
"EROGLYPH NL008EGYPTIAN HIEROGLYPH NL009EGYPTIAN HIEROGLYPH NL010EGYPTIAN" +
" HIEROGLYPH NL011EGYPTIAN HIEROGLYPH NL012EGYPTIAN HIEROGLYPH NL013EGYPT" +
"IAN HIEROGLYPH NL014EGYPTIAN HIEROGLYPH NL015EGYPTIAN HIEROGLYPH NL016EG" +
"YPTIAN HIEROGLYPH NL017EGYPTIAN HIEROGLYPH NL017AEGYPTIAN HIEROGLYPH NL0" +
"18EGYPTIAN HIEROGLYPH NL019EGYPTIAN HIEROGLYPH NL020EGYPTIAN HIEROGLYPH " +
"NU001EGYPTIAN HIEROGLYPH NU002EGYPTIAN HIEROGLYPH NU003EGYPTIAN HIEROGLY" +
"PH NU004EGYPTIAN HIEROGLYPH NU005EGYPTIAN HIEROGLYPH NU006EGYPTIAN HIERO" +
"GLYPH NU007EGYPTIAN HIEROGLYPH NU008EGYPTIAN HIEROGLYPH NU009EGYPTIAN HI" +
"EROGLYPH NU010EGYPTIAN HIEROGLYPH NU010AEGYPTIAN HIEROGLYPH NU011EGYPTIA" +
"N HIEROGLYPH NU011AEGYPTIAN HIEROGLYPH NU012EGYPTIAN HIEROGLYPH NU013EGY" +
"PTIAN HIEROGLYPH NU014EGYPTIAN HIEROGLYPH NU015EGYPTIAN HIEROGLYPH NU016" +
"EGYPTIAN HIEROGLYPH NU017EGYPTIAN HIEROGLYPH NU018EGYPTIAN HIEROGLYPH NU" +
"018AEGYPTIAN HIEROGLYPH NU019EGYPTIAN HIEROGLYPH NU020EGYPTIAN HIEROGLYP" +
"H NU021EGYPTIAN HIEROGLYPH NU022EGYPTIAN HIEROGLYPH NU022AEGYPTIAN HIERO" +
"GLYPH O001EGYPTIAN HIEROGLYPH O001AEGYPTIAN HIEROGLYPH O002EGYPTIAN HIER" +
"OGLYPH O003EGYPTIAN HIEROGLYPH O004EGYPTIAN HIEROGLYPH O005EGYPTIAN HIER" +
"OGLYPH O005AEGYPTIAN HIEROGLYPH O006EGYPTIAN HIEROGLYPH O006AEGYPTIAN HI" +
"EROGLYPH O006BEGYPTIAN HIEROGLYPH O006CEGYPTIAN HIEROGLYPH O006DEGYPTIAN" +
" HIEROGLYPH O006EEGYPTIAN HIEROGLYPH O006FEGYPTIAN HIEROGLYPH O007EGYPTI" +
"AN HIEROGLYPH O008EGYPTIAN HIEROGLYPH O009EGYPTIAN HIEROGLYPH O010EGYPTI" +
"AN HIEROGLYPH O010AEGYPTIAN HIEROGLYPH O010BEGYPTIAN HIEROGLYPH O010CEGY" +
"PTIAN HIEROGLYPH O011EGYPTIAN HIEROGLYPH O012EGYPTIAN HIEROGLYPH O013EGY" +
"PTIAN HIEROGLYPH O014EGYPTIAN HIEROGLYPH O015EGYPTIAN HIEROGLYPH O016EGY" +
"PTIAN HIEROGLYPH O017EGYPTIAN HIEROGLYPH O018EGYPTIAN HIEROGLYPH O019EGY") + ("" +
"PTIAN HIEROGLYPH O019AEGYPTIAN HIEROGLYPH O020EGYPTIAN HIEROGLYPH O020AE" +
"GYPTIAN HIEROGLYPH O021EGYPTIAN HIEROGLYPH O022EGYPTIAN HIEROGLYPH O023E" +
"GYPTIAN HIEROGLYPH O024EGYPTIAN HIEROGLYPH O024AEGYPTIAN HIEROGLYPH O025" +
"EGYPTIAN HIEROGLYPH O025AEGYPTIAN HIEROGLYPH O026EGYPTIAN HIEROGLYPH O02" +
"7EGYPTIAN HIEROGLYPH O028EGYPTIAN HIEROGLYPH O029EGYPTIAN HIEROGLYPH O02" +
"9AEGYPTIAN HIEROGLYPH O030EGYPTIAN HIEROGLYPH O030AEGYPTIAN HIEROGLYPH O" +
"031EGYPTIAN HIEROGLYPH O032EGYPTIAN HIEROGLYPH O033EGYPTIAN HIEROGLYPH O" +
"033AEGYPTIAN HIEROGLYPH O034EGYPTIAN HIEROGLYPH O035EGYPTIAN HIEROGLYPH " +
"O036EGYPTIAN HIEROGLYPH O036AEGYPTIAN HIEROGLYPH O036BEGYPTIAN HIEROGLYP" +
"H O036CEGYPTIAN HIEROGLYPH O036DEGYPTIAN HIEROGLYPH O037EGYPTIAN HIEROGL" +
"YPH O038EGYPTIAN HIEROGLYPH O039EGYPTIAN HIEROGLYPH O040EGYPTIAN HIEROGL" +
"YPH O041EGYPTIAN HIEROGLYPH O042EGYPTIAN HIEROGLYPH O043EGYPTIAN HIEROGL" +
"YPH O044EGYPTIAN HIEROGLYPH O045EGYPTIAN HIEROGLYPH O046EGYPTIAN HIEROGL" +
"YPH O047EGYPTIAN HIEROGLYPH O048EGYPTIAN HIEROGLYPH O049EGYPTIAN HIEROGL" +
"YPH O050EGYPTIAN HIEROGLYPH O050AEGYPTIAN HIEROGLYPH O050BEGYPTIAN HIERO" +
"GLYPH O051EGYPTIAN HIEROGLYPH P001EGYPTIAN HIEROGLYPH P001AEGYPTIAN HIER" +
"OGLYPH P002EGYPTIAN HIEROGLYPH P003EGYPTIAN HIEROGLYPH P003AEGYPTIAN HIE" +
"ROGLYPH P004EGYPTIAN HIEROGLYPH P005EGYPTIAN HIEROGLYPH P006EGYPTIAN HIE" +
"ROGLYPH P007EGYPTIAN HIEROGLYPH P008EGYPTIAN HIEROGLYPH P009EGYPTIAN HIE" +
"ROGLYPH P010EGYPTIAN HIEROGLYPH P011EGYPTIAN HIEROGLYPH Q001EGYPTIAN HIE" +
"ROGLYPH Q002EGYPTIAN HIEROGLYPH Q003EGYPTIAN HIEROGLYPH Q004EGYPTIAN HIE" +
"ROGLYPH Q005EGYPTIAN HIEROGLYPH Q006EGYPTIAN HIEROGLYPH Q007EGYPTIAN HIE" +
"ROGLYPH R001EGYPTIAN HIEROGLYPH R002EGYPTIAN HIEROGLYPH R002AEGYPTIAN HI" +
"EROGLYPH R003EGYPTIAN HIEROGLYPH R003AEGYPTIAN HIEROGLYPH R003BEGYPTIAN " +
"HIEROGLYPH R004EGYPTIAN HIEROGLYPH R005EGYPTIAN HIEROGLYPH R006EGYPTIAN " +
"HIEROGLYPH R007EGYPTIAN HIEROGLYPH R008EGYPTIAN HIEROGLYPH R009EGYPTIAN " +
"HIEROGLYPH R010EGYPTIAN HIEROGLYPH R010AEGYPTIAN HIEROGLYPH R011EGYPTIAN" +
" HIEROGLYPH R012EGYPTIAN HIEROGLYPH R013EGYPTIAN HIEROGLYPH R014EGYPTIAN" +
" HIEROGLYPH R015EGYPTIAN HIEROGLYPH R016EGYPTIAN HIEROGLYPH R016AEGYPTIA" +
"N HIEROGLYPH R017EGYPTIAN HIEROGLYPH R018EGYPTIAN HIEROGLYPH R019EGYPTIA" +
"N HIEROGLYPH R020EGYPTIAN HIEROGLYPH R021EGYPTIAN HIEROGLYPH R022EGYPTIA" +
"N HIEROGLYPH R023EGYPTIAN HIEROGLYPH R024EGYPTIAN HIEROGLYPH R025EGYPTIA" +
"N HIEROGLYPH R026EGYPTIAN HIEROGLYPH R027EGYPTIAN HIEROGLYPH R028EGYPTIA" +
"N HIEROGLYPH R029EGYPTIAN HIEROGLYPH S001EGYPTIAN HIEROGLYPH S002EGYPTIA" +
"N HIEROGLYPH S002AEGYPTIAN HIEROGLYPH S003EGYPTIAN HIEROGLYPH S004EGYPTI" +
"AN HIEROGLYPH S005EGYPTIAN HIEROGLYPH S006EGYPTIAN HIEROGLYPH S006AEGYPT" +
"IAN HIEROGLYPH S007EGYPTIAN HIEROGLYPH S008EGYPTIAN HIEROGLYPH S009EGYPT" +
"IAN HIEROGLYPH S010EGYPTIAN HIEROGLYPH S011EGYPTIAN HIEROGLYPH S012EGYPT" +
"IAN HIEROGLYPH S013EGYPTIAN HIEROGLYPH S014EGYPTIAN HIEROGLYPH S014AEGYP" +
"TIAN HIEROGLYPH S014BEGYPTIAN HIEROGLYPH S015EGYPTIAN HIEROGLYPH S016EGY" +
"PTIAN HIEROGLYPH S017EGYPTIAN HIEROGLYPH S017AEGYPTIAN HIEROGLYPH S018EG" +
"YPTIAN HIEROGLYPH S019EGYPTIAN HIEROGLYPH S020EGYPTIAN HIEROGLYPH S021EG" +
"YPTIAN HIEROGLYPH S022EGYPTIAN HIEROGLYPH S023EGYPTIAN HIEROGLYPH S024EG" +
"YPTIAN HIEROGLYPH S025EGYPTIAN HIEROGLYPH S026EGYPTIAN HIEROGLYPH S026AE" +
"GYPTIAN HIEROGLYPH S026BEGYPTIAN HIEROGLYPH S027EGYPTIAN HIEROGLYPH S028" +
"EGYPTIAN HIEROGLYPH S029EGYPTIAN HIEROGLYPH S030EGYPTIAN HIEROGLYPH S031" +
"EGYPTIAN HIEROGLYPH S032EGYPTIAN HIEROGLYPH S033EGYPTIAN HIEROGLYPH S034" +
"EGYPTIAN HIEROGLYPH S035EGYPTIAN HIEROGLYPH S035AEGYPTIAN HIEROGLYPH S03" +
"6EGYPTIAN HIEROGLYPH S037EGYPTIAN HIEROGLYPH S038EGYPTIAN HIEROGLYPH S03" +
"9EGYPTIAN HIEROGLYPH S040EGYPTIAN HIEROGLYPH S041EGYPTIAN HIEROGLYPH S04" +
"2EGYPTIAN HIEROGLYPH S043EGYPTIAN HIEROGLYPH S044EGYPTIAN HIEROGLYPH S04" +
"5EGYPTIAN HIEROGLYPH S046EGYPTIAN HIEROGLYPH T001EGYPTIAN HIEROGLYPH T00" +
"2EGYPTIAN HIEROGLYPH T003EGYPTIAN HIEROGLYPH T003AEGYPTIAN HIEROGLYPH T0" +
"04EGYPTIAN HIEROGLYPH T005EGYPTIAN HIEROGLYPH T006EGYPTIAN HIEROGLYPH T0" +
"07EGYPTIAN HIEROGLYPH T007AEGYPTIAN HIEROGLYPH T008EGYPTIAN HIEROGLYPH T" +
"008AEGYPTIAN HIEROGLYPH T009EGYPTIAN HIEROGLYPH T009AEGYPTIAN HIEROGLYPH" +
" T010EGYPTIAN HIEROGLYPH T011EGYPTIAN HIEROGLYPH T011AEGYPTIAN HIEROGLYP" +
"H T012EGYPTIAN HIEROGLYPH T013EGYPTIAN HIEROGLYPH T014EGYPTIAN HIEROGLYP" +
"H T015EGYPTIAN HIEROGLYPH T016EGYPTIAN HIEROGLYPH T016AEGYPTIAN HIEROGLY" +
"PH T017EGYPTIAN HIEROGLYPH T018EGYPTIAN HIEROGLYPH T019EGYPTIAN HIEROGLY" +
"PH T020EGYPTIAN HIEROGLYPH T021EGYPTIAN HIEROGLYPH T022EGYPTIAN HIEROGLY" +
"PH T023EGYPTIAN HIEROGLYPH T024EGYPTIAN HIEROGLYPH T025EGYPTIAN HIEROGLY" +
"PH T026EGYPTIAN HIEROGLYPH T027EGYPTIAN HIEROGLYPH T028EGYPTIAN HIEROGLY" +
"PH T029EGYPTIAN HIEROGLYPH T030EGYPTIAN HIEROGLYPH T031EGYPTIAN HIEROGLY") + ("" +
"PH T032EGYPTIAN HIEROGLYPH T032AEGYPTIAN HIEROGLYPH T033EGYPTIAN HIEROGL" +
"YPH T033AEGYPTIAN HIEROGLYPH T034EGYPTIAN HIEROGLYPH T035EGYPTIAN HIEROG" +
"LYPH T036EGYPTIAN HIEROGLYPH U001EGYPTIAN HIEROGLYPH U002EGYPTIAN HIEROG" +
"LYPH U003EGYPTIAN HIEROGLYPH U004EGYPTIAN HIEROGLYPH U005EGYPTIAN HIEROG" +
"LYPH U006EGYPTIAN HIEROGLYPH U006AEGYPTIAN HIEROGLYPH U006BEGYPTIAN HIER" +
"OGLYPH U007EGYPTIAN HIEROGLYPH U008EGYPTIAN HIEROGLYPH U009EGYPTIAN HIER" +
"OGLYPH U010EGYPTIAN HIEROGLYPH U011EGYPTIAN HIEROGLYPH U012EGYPTIAN HIER" +
"OGLYPH U013EGYPTIAN HIEROGLYPH U014EGYPTIAN HIEROGLYPH U015EGYPTIAN HIER" +
"OGLYPH U016EGYPTIAN HIEROGLYPH U017EGYPTIAN HIEROGLYPH U018EGYPTIAN HIER" +
"OGLYPH U019EGYPTIAN HIEROGLYPH U020EGYPTIAN HIEROGLYPH U021EGYPTIAN HIER" +
"OGLYPH U022EGYPTIAN HIEROGLYPH U023EGYPTIAN HIEROGLYPH U023AEGYPTIAN HIE" +
"ROGLYPH U024EGYPTIAN HIEROGLYPH U025EGYPTIAN HIEROGLYPH U026EGYPTIAN HIE" +
"ROGLYPH U027EGYPTIAN HIEROGLYPH U028EGYPTIAN HIEROGLYPH U029EGYPTIAN HIE" +
"ROGLYPH U029AEGYPTIAN HIEROGLYPH U030EGYPTIAN HIEROGLYPH U031EGYPTIAN HI" +
"EROGLYPH U032EGYPTIAN HIEROGLYPH U032AEGYPTIAN HIEROGLYPH U033EGYPTIAN H" +
"IEROGLYPH U034EGYPTIAN HIEROGLYPH U035EGYPTIAN HIEROGLYPH U036EGYPTIAN H" +
"IEROGLYPH U037EGYPTIAN HIEROGLYPH U038EGYPTIAN HIEROGLYPH U039EGYPTIAN H" +
"IEROGLYPH U040EGYPTIAN HIEROGLYPH U041EGYPTIAN HIEROGLYPH U042EGYPTIAN H" +
"IEROGLYPH V001EGYPTIAN HIEROGLYPH V001AEGYPTIAN HIEROGLYPH V001BEGYPTIAN" +
" HIEROGLYPH V001CEGYPTIAN HIEROGLYPH V001DEGYPTIAN HIEROGLYPH V001EEGYPT" +
"IAN HIEROGLYPH V001FEGYPTIAN HIEROGLYPH V001GEGYPTIAN HIEROGLYPH V001HEG" +
"YPTIAN HIEROGLYPH V001IEGYPTIAN HIEROGLYPH V002EGYPTIAN HIEROGLYPH V002A" +
"EGYPTIAN HIEROGLYPH V003EGYPTIAN HIEROGLYPH V004EGYPTIAN HIEROGLYPH V005" +
"EGYPTIAN HIEROGLYPH V006EGYPTIAN HIEROGLYPH V007EGYPTIAN HIEROGLYPH V007" +
"AEGYPTIAN HIEROGLYPH V007BEGYPTIAN HIEROGLYPH V008EGYPTIAN HIEROGLYPH V0" +
"09EGYPTIAN HIEROGLYPH V010EGYPTIAN HIEROGLYPH V011EGYPTIAN HIEROGLYPH V0" +
"11AEGYPTIAN HIEROGLYPH V011BEGYPTIAN HIEROGLYPH V011CEGYPTIAN HIEROGLYPH" +
" V012EGYPTIAN HIEROGLYPH V012AEGYPTIAN HIEROGLYPH V012BEGYPTIAN HIEROGLY" +
"PH V013EGYPTIAN HIEROGLYPH V014EGYPTIAN HIEROGLYPH V015EGYPTIAN HIEROGLY" +
"PH V016EGYPTIAN HIEROGLYPH V017EGYPTIAN HIEROGLYPH V018EGYPTIAN HIEROGLY" +
"PH V019EGYPTIAN HIEROGLYPH V020EGYPTIAN HIEROGLYPH V020AEGYPTIAN HIEROGL" +
"YPH V020BEGYPTIAN HIEROGLYPH V020CEGYPTIAN HIEROGLYPH V020DEGYPTIAN HIER" +
"OGLYPH V020EEGYPTIAN HIEROGLYPH V020FEGYPTIAN HIEROGLYPH V020GEGYPTIAN H" +
"IEROGLYPH V020HEGYPTIAN HIEROGLYPH V020IEGYPTIAN HIEROGLYPH V020JEGYPTIA" +
"N HIEROGLYPH V020KEGYPTIAN HIEROGLYPH V020LEGYPTIAN HIEROGLYPH V021EGYPT" +
"IAN HIEROGLYPH V022EGYPTIAN HIEROGLYPH V023EGYPTIAN HIEROGLYPH V023AEGYP" +
"TIAN HIEROGLYPH V024EGYPTIAN HIEROGLYPH V025EGYPTIAN HIEROGLYPH V026EGYP" +
"TIAN HIEROGLYPH V027EGYPTIAN HIEROGLYPH V028EGYPTIAN HIEROGLYPH V028AEGY" +
"PTIAN HIEROGLYPH V029EGYPTIAN HIEROGLYPH V029AEGYPTIAN HIEROGLYPH V030EG" +
"YPTIAN HIEROGLYPH V030AEGYPTIAN HIEROGLYPH V031EGYPTIAN HIEROGLYPH V031A" +
"EGYPTIAN HIEROGLYPH V032EGYPTIAN HIEROGLYPH V033EGYPTIAN HIEROGLYPH V033" +
"AEGYPTIAN HIEROGLYPH V034EGYPTIAN HIEROGLYPH V035EGYPTIAN HIEROGLYPH V03" +
"6EGYPTIAN HIEROGLYPH V037EGYPTIAN HIEROGLYPH V037AEGYPTIAN HIEROGLYPH V0" +
"38EGYPTIAN HIEROGLYPH V039EGYPTIAN HIEROGLYPH V040EGYPTIAN HIEROGLYPH V0" +
"40AEGYPTIAN HIEROGLYPH W001EGYPTIAN HIEROGLYPH W002EGYPTIAN HIEROGLYPH W" +
"003EGYPTIAN HIEROGLYPH W003AEGYPTIAN HIEROGLYPH W004EGYPTIAN HIEROGLYPH " +
"W005EGYPTIAN HIEROGLYPH W006EGYPTIAN HIEROGLYPH W007EGYPTIAN HIEROGLYPH " +
"W008EGYPTIAN HIEROGLYPH W009EGYPTIAN HIEROGLYPH W009AEGYPTIAN HIEROGLYPH" +
" W010EGYPTIAN HIEROGLYPH W010AEGYPTIAN HIEROGLYPH W011EGYPTIAN HIEROGLYP" +
"H W012EGYPTIAN HIEROGLYPH W013EGYPTIAN HIEROGLYPH W014EGYPTIAN HIEROGLYP" +
"H W014AEGYPTIAN HIEROGLYPH W015EGYPTIAN HIEROGLYPH W016EGYPTIAN HIEROGLY" +
"PH W017EGYPTIAN HIEROGLYPH W017AEGYPTIAN HIEROGLYPH W018EGYPTIAN HIEROGL" +
"YPH W018AEGYPTIAN HIEROGLYPH W019EGYPTIAN HIEROGLYPH W020EGYPTIAN HIEROG" +
"LYPH W021EGYPTIAN HIEROGLYPH W022EGYPTIAN HIEROGLYPH W023EGYPTIAN HIEROG" +
"LYPH W024EGYPTIAN HIEROGLYPH W024AEGYPTIAN HIEROGLYPH W025EGYPTIAN HIERO" +
"GLYPH X001EGYPTIAN HIEROGLYPH X002EGYPTIAN HIEROGLYPH X003EGYPTIAN HIERO" +
"GLYPH X004EGYPTIAN HIEROGLYPH X004AEGYPTIAN HIEROGLYPH X004BEGYPTIAN HIE" +
"ROGLYPH X005EGYPTIAN HIEROGLYPH X006EGYPTIAN HIEROGLYPH X006AEGYPTIAN HI" +
"EROGLYPH X007EGYPTIAN HIEROGLYPH X008EGYPTIAN HIEROGLYPH X008AEGYPTIAN H" +
"IEROGLYPH Y001EGYPTIAN HIEROGLYPH Y001AEGYPTIAN HIEROGLYPH Y002EGYPTIAN " +
"HIEROGLYPH Y003EGYPTIAN HIEROGLYPH Y004EGYPTIAN HIEROGLYPH Y005EGYPTIAN " +
"HIEROGLYPH Y006EGYPTIAN HIEROGLYPH Y007EGYPTIAN HIEROGLYPH Y008EGYPTIAN " +
"HIEROGLYPH Z001EGYPTIAN HIEROGLYPH Z002EGYPTIAN HIEROGLYPH Z002AEGYPTIAN" +
" HIEROGLYPH Z002BEGYPTIAN HIEROGLYPH Z002CEGYPTIAN HIEROGLYPH Z002DEGYPT") + ("" +
"IAN HIEROGLYPH Z003EGYPTIAN HIEROGLYPH Z003AEGYPTIAN HIEROGLYPH Z003BEGY" +
"PTIAN HIEROGLYPH Z004EGYPTIAN HIEROGLYPH Z004AEGYPTIAN HIEROGLYPH Z005EG" +
"YPTIAN HIEROGLYPH Z005AEGYPTIAN HIEROGLYPH Z006EGYPTIAN HIEROGLYPH Z007E" +
"GYPTIAN HIEROGLYPH Z008EGYPTIAN HIEROGLYPH Z009EGYPTIAN HIEROGLYPH Z010E" +
"GYPTIAN HIEROGLYPH Z011EGYPTIAN HIEROGLYPH Z012EGYPTIAN HIEROGLYPH Z013E" +
"GYPTIAN HIEROGLYPH Z014EGYPTIAN HIEROGLYPH Z015EGYPTIAN HIEROGLYPH Z015A" +
"EGYPTIAN HIEROGLYPH Z015BEGYPTIAN HIEROGLYPH Z015CEGYPTIAN HIEROGLYPH Z0" +
"15DEGYPTIAN HIEROGLYPH Z015EEGYPTIAN HIEROGLYPH Z015FEGYPTIAN HIEROGLYPH" +
" Z015GEGYPTIAN HIEROGLYPH Z015HEGYPTIAN HIEROGLYPH Z015IEGYPTIAN HIEROGL" +
"YPH Z016EGYPTIAN HIEROGLYPH Z016AEGYPTIAN HIEROGLYPH Z016BEGYPTIAN HIERO" +
"GLYPH Z016CEGYPTIAN HIEROGLYPH Z016DEGYPTIAN HIEROGLYPH Z016EEGYPTIAN HI" +
"EROGLYPH Z016FEGYPTIAN HIEROGLYPH Z016GEGYPTIAN HIEROGLYPH Z016HEGYPTIAN" +
" HIEROGLYPH AA001EGYPTIAN HIEROGLYPH AA002EGYPTIAN HIEROGLYPH AA003EGYPT" +
"IAN HIEROGLYPH AA004EGYPTIAN HIEROGLYPH AA005EGYPTIAN HIEROGLYPH AA006EG" +
"YPTIAN HIEROGLYPH AA007EGYPTIAN HIEROGLYPH AA007AEGYPTIAN HIEROGLYPH AA0" +
"07BEGYPTIAN HIEROGLYPH AA008EGYPTIAN HIEROGLYPH AA009EGYPTIAN HIEROGLYPH" +
" AA010EGYPTIAN HIEROGLYPH AA011EGYPTIAN HIEROGLYPH AA012EGYPTIAN HIEROGL" +
"YPH AA013EGYPTIAN HIEROGLYPH AA014EGYPTIAN HIEROGLYPH AA015EGYPTIAN HIER" +
"OGLYPH AA016EGYPTIAN HIEROGLYPH AA017EGYPTIAN HIEROGLYPH AA018EGYPTIAN H" +
"IEROGLYPH AA019EGYPTIAN HIEROGLYPH AA020EGYPTIAN HIEROGLYPH AA021EGYPTIA" +
"N HIEROGLYPH AA022EGYPTIAN HIEROGLYPH AA023EGYPTIAN HIEROGLYPH AA024EGYP" +
"TIAN HIEROGLYPH AA025EGYPTIAN HIEROGLYPH AA026EGYPTIAN HIEROGLYPH AA027E" +
"GYPTIAN HIEROGLYPH AA028EGYPTIAN HIEROGLYPH AA029EGYPTIAN HIEROGLYPH AA0" +
"30EGYPTIAN HIEROGLYPH AA031EGYPTIAN HIEROGLYPH AA032EGYPTIAN HIEROGLYPH " +
"V011DEGYPTIAN HIEROGLYPH VERTICAL JOINEREGYPTIAN HIEROGLYPH HORIZONTAL J" +
"OINEREGYPTIAN HIEROGLYPH INSERT AT TOP STARTEGYPTIAN HIEROGLYPH INSERT A" +
"T BOTTOM STARTEGYPTIAN HIEROGLYPH INSERT AT TOP ENDEGYPTIAN HIEROGLYPH I" +
"NSERT AT BOTTOM ENDEGYPTIAN HIEROGLYPH OVERLAY MIDDLEEGYPTIAN HIEROGLYPH" +
" BEGIN SEGMENTEGYPTIAN HIEROGLYPH END SEGMENTEGYPTIAN HIEROGLYPH INSERT " +
"AT MIDDLEEGYPTIAN HIEROGLYPH INSERT AT TOPEGYPTIAN HIEROGLYPH INSERT AT " +
"BOTTOMEGYPTIAN HIEROGLYPH BEGIN ENCLOSUREEGYPTIAN HIEROGLYPH END ENCLOSU" +
"REEGYPTIAN HIEROGLYPH BEGIN WALLED ENCLOSUREEGYPTIAN HIEROGLYPH END WALL" +
"ED ENCLOSUREEGYPTIAN HIEROGLYPH MIRROR HORIZONTALLYEGYPTIAN HIEROGLYPH F" +
"ULL BLANKEGYPTIAN HIEROGLYPH HALF BLANKEGYPTIAN HIEROGLYPH LOST SIGNEGYP" +
"TIAN HIEROGLYPH HALF LOST SIGNEGYPTIAN HIEROGLYPH TALL LOST SIGNEGYPTIAN" +
" HIEROGLYPH WIDE LOST SIGNEGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP ST" +
"ARTEGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM STARTEGYPTIAN HIEROGLY" +
"PH MODIFIER DAMAGED AT STARTEGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP " +
"ENDEGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOPEGYPTIAN HIEROGLYPH MODIFI" +
"ER DAMAGED AT BOTTOM START AND TOP ENDEGYPTIAN HIEROGLYPH MODIFIER DAMAG" +
"ED AT START AND TOPEGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM ENDEGY" +
"PTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START AND BOTTOM ENDEGYPTIAN HI" +
"EROGLYPH MODIFIER DAMAGED AT BOTTOMEGYPTIAN HIEROGLYPH MODIFIER DAMAGED " +
"AT START AND BOTTOMEGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT ENDEGYPTIAN H" +
"IEROGLYPH MODIFIER DAMAGED AT TOP AND ENDEGYPTIAN HIEROGLYPH MODIFIER DA" +
"MAGED AT BOTTOM AND ENDEGYPTIAN HIEROGLYPH MODIFIER DAMAGEDANATOLIAN HIE" +
"ROGLYPH A001ANATOLIAN HIEROGLYPH A002ANATOLIAN HIEROGLYPH A003ANATOLIAN " +
"HIEROGLYPH A004ANATOLIAN HIEROGLYPH A005ANATOLIAN HIEROGLYPH A006ANATOLI" +
"AN HIEROGLYPH A007ANATOLIAN HIEROGLYPH A008ANATOLIAN HIEROGLYPH A009ANAT" +
"OLIAN HIEROGLYPH A010ANATOLIAN HIEROGLYPH A010AANATOLIAN HIEROGLYPH A011" +
"ANATOLIAN HIEROGLYPH A012ANATOLIAN HIEROGLYPH A013ANATOLIAN HIEROGLYPH A" +
"014ANATOLIAN HIEROGLYPH A015ANATOLIAN HIEROGLYPH A016ANATOLIAN HIEROGLYP" +
"H A017ANATOLIAN HIEROGLYPH A018ANATOLIAN HIEROGLYPH A019ANATOLIAN HIEROG" +
"LYPH A020ANATOLIAN HIEROGLYPH A021ANATOLIAN HIEROGLYPH A022ANATOLIAN HIE" +
"ROGLYPH A023ANATOLIAN HIEROGLYPH A024ANATOLIAN HIEROGLYPH A025ANATOLIAN " +
"HIEROGLYPH A026ANATOLIAN HIEROGLYPH A026AANATOLIAN HIEROGLYPH A027ANATOL" +
"IAN HIEROGLYPH A028ANATOLIAN HIEROGLYPH A029ANATOLIAN HIEROGLYPH A030ANA" +
"TOLIAN HIEROGLYPH A031ANATOLIAN HIEROGLYPH A032ANATOLIAN HIEROGLYPH A033" +
"ANATOLIAN HIEROGLYPH A034ANATOLIAN HIEROGLYPH A035ANATOLIAN HIEROGLYPH A" +
"036ANATOLIAN HIEROGLYPH A037ANATOLIAN HIEROGLYPH A038ANATOLIAN HIEROGLYP" +
"H A039ANATOLIAN HIEROGLYPH A039AANATOLIAN HIEROGLYPH A040ANATOLIAN HIERO" +
"GLYPH A041ANATOLIAN HIEROGLYPH A041AANATOLIAN HIEROGLYPH A042ANATOLIAN H" +
"IEROGLYPH A043ANATOLIAN HIEROGLYPH A044ANATOLIAN HIEROGLYPH A045ANATOLIA" +
"N HIEROGLYPH A045AANATOLIAN HIEROGLYPH A046ANATOLIAN HIEROGLYPH A046AANA") + ("" +
"TOLIAN HIEROGLYPH A046BANATOLIAN HIEROGLYPH A047ANATOLIAN HIEROGLYPH A04" +
"8ANATOLIAN HIEROGLYPH A049ANATOLIAN HIEROGLYPH A050ANATOLIAN HIEROGLYPH " +
"A051ANATOLIAN HIEROGLYPH A052ANATOLIAN HIEROGLYPH A053ANATOLIAN HIEROGLY" +
"PH A054ANATOLIAN HIEROGLYPH A055ANATOLIAN HIEROGLYPH A056ANATOLIAN HIERO" +
"GLYPH A057ANATOLIAN HIEROGLYPH A058ANATOLIAN HIEROGLYPH A059ANATOLIAN HI" +
"EROGLYPH A060ANATOLIAN HIEROGLYPH A061ANATOLIAN HIEROGLYPH A062ANATOLIAN" +
" HIEROGLYPH A063ANATOLIAN HIEROGLYPH A064ANATOLIAN HIEROGLYPH A065ANATOL" +
"IAN HIEROGLYPH A066ANATOLIAN HIEROGLYPH A066AANATOLIAN HIEROGLYPH A066BA" +
"NATOLIAN HIEROGLYPH A066CANATOLIAN HIEROGLYPH A067ANATOLIAN HIEROGLYPH A" +
"068ANATOLIAN HIEROGLYPH A069ANATOLIAN HIEROGLYPH A070ANATOLIAN HIEROGLYP" +
"H A071ANATOLIAN HIEROGLYPH A072ANATOLIAN HIEROGLYPH A073ANATOLIAN HIEROG" +
"LYPH A074ANATOLIAN HIEROGLYPH A075ANATOLIAN HIEROGLYPH A076ANATOLIAN HIE" +
"ROGLYPH A077ANATOLIAN HIEROGLYPH A078ANATOLIAN HIEROGLYPH A079ANATOLIAN " +
"HIEROGLYPH A080ANATOLIAN HIEROGLYPH A081ANATOLIAN HIEROGLYPH A082ANATOLI" +
"AN HIEROGLYPH A083ANATOLIAN HIEROGLYPH A084ANATOLIAN HIEROGLYPH A085ANAT" +
"OLIAN HIEROGLYPH A086ANATOLIAN HIEROGLYPH A087ANATOLIAN HIEROGLYPH A088A" +
"NATOLIAN HIEROGLYPH A089ANATOLIAN HIEROGLYPH A090ANATOLIAN HIEROGLYPH A0" +
"91ANATOLIAN HIEROGLYPH A092ANATOLIAN HIEROGLYPH A093ANATOLIAN HIEROGLYPH" +
" A094ANATOLIAN HIEROGLYPH A095ANATOLIAN HIEROGLYPH A096ANATOLIAN HIEROGL" +
"YPH A097ANATOLIAN HIEROGLYPH A097AANATOLIAN HIEROGLYPH A098ANATOLIAN HIE" +
"ROGLYPH A098AANATOLIAN HIEROGLYPH A099ANATOLIAN HIEROGLYPH A100ANATOLIAN" +
" HIEROGLYPH A100AANATOLIAN HIEROGLYPH A101ANATOLIAN HIEROGLYPH A101AANAT" +
"OLIAN HIEROGLYPH A102ANATOLIAN HIEROGLYPH A102AANATOLIAN HIEROGLYPH A103" +
"ANATOLIAN HIEROGLYPH A104ANATOLIAN HIEROGLYPH A104AANATOLIAN HIEROGLYPH " +
"A104BANATOLIAN HIEROGLYPH A104CANATOLIAN HIEROGLYPH A105ANATOLIAN HIEROG" +
"LYPH A105AANATOLIAN HIEROGLYPH A105BANATOLIAN HIEROGLYPH A106ANATOLIAN H" +
"IEROGLYPH A107ANATOLIAN HIEROGLYPH A107AANATOLIAN HIEROGLYPH A107BANATOL" +
"IAN HIEROGLYPH A107CANATOLIAN HIEROGLYPH A108ANATOLIAN HIEROGLYPH A109AN" +
"ATOLIAN HIEROGLYPH A110ANATOLIAN HIEROGLYPH A110AANATOLIAN HIEROGLYPH A1" +
"10BANATOLIAN HIEROGLYPH A111ANATOLIAN HIEROGLYPH A112ANATOLIAN HIEROGLYP" +
"H A113ANATOLIAN HIEROGLYPH A114ANATOLIAN HIEROGLYPH A115ANATOLIAN HIEROG" +
"LYPH A115AANATOLIAN HIEROGLYPH A116ANATOLIAN HIEROGLYPH A117ANATOLIAN HI" +
"EROGLYPH A118ANATOLIAN HIEROGLYPH A119ANATOLIAN HIEROGLYPH A120ANATOLIAN" +
" HIEROGLYPH A121ANATOLIAN HIEROGLYPH A122ANATOLIAN HIEROGLYPH A123ANATOL" +
"IAN HIEROGLYPH A124ANATOLIAN HIEROGLYPH A125ANATOLIAN HIEROGLYPH A125AAN" +
"ATOLIAN HIEROGLYPH A126ANATOLIAN HIEROGLYPH A127ANATOLIAN HIEROGLYPH A12" +
"8ANATOLIAN HIEROGLYPH A129ANATOLIAN HIEROGLYPH A130ANATOLIAN HIEROGLYPH " +
"A131ANATOLIAN HIEROGLYPH A132ANATOLIAN HIEROGLYPH A133ANATOLIAN HIEROGLY" +
"PH A134ANATOLIAN HIEROGLYPH A135ANATOLIAN HIEROGLYPH A135AANATOLIAN HIER" +
"OGLYPH A136ANATOLIAN HIEROGLYPH A137ANATOLIAN HIEROGLYPH A138ANATOLIAN H" +
"IEROGLYPH A139ANATOLIAN HIEROGLYPH A140ANATOLIAN HIEROGLYPH A141ANATOLIA" +
"N HIEROGLYPH A142ANATOLIAN HIEROGLYPH A143ANATOLIAN HIEROGLYPH A144ANATO" +
"LIAN HIEROGLYPH A145ANATOLIAN HIEROGLYPH A146ANATOLIAN HIEROGLYPH A147AN" +
"ATOLIAN HIEROGLYPH A148ANATOLIAN HIEROGLYPH A149ANATOLIAN HIEROGLYPH A15" +
"0ANATOLIAN HIEROGLYPH A151ANATOLIAN HIEROGLYPH A152ANATOLIAN HIEROGLYPH " +
"A153ANATOLIAN HIEROGLYPH A154ANATOLIAN HIEROGLYPH A155ANATOLIAN HIEROGLY" +
"PH A156ANATOLIAN HIEROGLYPH A157ANATOLIAN HIEROGLYPH A158ANATOLIAN HIERO" +
"GLYPH A159ANATOLIAN HIEROGLYPH A160ANATOLIAN HIEROGLYPH A161ANATOLIAN HI" +
"EROGLYPH A162ANATOLIAN HIEROGLYPH A163ANATOLIAN HIEROGLYPH A164ANATOLIAN" +
" HIEROGLYPH A165ANATOLIAN HIEROGLYPH A166ANATOLIAN HIEROGLYPH A167ANATOL" +
"IAN HIEROGLYPH A168ANATOLIAN HIEROGLYPH A169ANATOLIAN HIEROGLYPH A170ANA" +
"TOLIAN HIEROGLYPH A171ANATOLIAN HIEROGLYPH A172ANATOLIAN HIEROGLYPH A173" +
"ANATOLIAN HIEROGLYPH A174ANATOLIAN HIEROGLYPH A175ANATOLIAN HIEROGLYPH A" +
"176ANATOLIAN HIEROGLYPH A177ANATOLIAN HIEROGLYPH A178ANATOLIAN HIEROGLYP" +
"H A179ANATOLIAN HIEROGLYPH A180ANATOLIAN HIEROGLYPH A181ANATOLIAN HIEROG" +
"LYPH A182ANATOLIAN HIEROGLYPH A183ANATOLIAN HIEROGLYPH A184ANATOLIAN HIE" +
"ROGLYPH A185ANATOLIAN HIEROGLYPH A186ANATOLIAN HIEROGLYPH A187ANATOLIAN " +
"HIEROGLYPH A188ANATOLIAN HIEROGLYPH A189ANATOLIAN HIEROGLYPH A190ANATOLI" +
"AN HIEROGLYPH A191ANATOLIAN HIEROGLYPH A192ANATOLIAN HIEROGLYPH A193ANAT" +
"OLIAN HIEROGLYPH A194ANATOLIAN HIEROGLYPH A195ANATOLIAN HIEROGLYPH A196A" +
"NATOLIAN HIEROGLYPH A197ANATOLIAN HIEROGLYPH A198ANATOLIAN HIEROGLYPH A1" +
"99ANATOLIAN HIEROGLYPH A200ANATOLIAN HIEROGLYPH A201ANATOLIAN HIEROGLYPH" +
" A202ANATOLIAN HIEROGLYPH A202AANATOLIAN HIEROGLYPH A202BANATOLIAN HIERO" +
"GLYPH A203ANATOLIAN HIEROGLYPH A204ANATOLIAN HIEROGLYPH A205ANATOLIAN HI") + ("" +
"EROGLYPH A206ANATOLIAN HIEROGLYPH A207ANATOLIAN HIEROGLYPH A207AANATOLIA" +
"N HIEROGLYPH A208ANATOLIAN HIEROGLYPH A209ANATOLIAN HIEROGLYPH A209AANAT" +
"OLIAN HIEROGLYPH A210ANATOLIAN HIEROGLYPH A211ANATOLIAN HIEROGLYPH A212A" +
"NATOLIAN HIEROGLYPH A213ANATOLIAN HIEROGLYPH A214ANATOLIAN HIEROGLYPH A2" +
"15ANATOLIAN HIEROGLYPH A215AANATOLIAN HIEROGLYPH A216ANATOLIAN HIEROGLYP" +
"H A216AANATOLIAN HIEROGLYPH A217ANATOLIAN HIEROGLYPH A218ANATOLIAN HIERO" +
"GLYPH A219ANATOLIAN HIEROGLYPH A220ANATOLIAN HIEROGLYPH A221ANATOLIAN HI" +
"EROGLYPH A222ANATOLIAN HIEROGLYPH A223ANATOLIAN HIEROGLYPH A224ANATOLIAN" +
" HIEROGLYPH A225ANATOLIAN HIEROGLYPH A226ANATOLIAN HIEROGLYPH A227ANATOL" +
"IAN HIEROGLYPH A227AANATOLIAN HIEROGLYPH A228ANATOLIAN HIEROGLYPH A229AN" +
"ATOLIAN HIEROGLYPH A230ANATOLIAN HIEROGLYPH A231ANATOLIAN HIEROGLYPH A23" +
"2ANATOLIAN HIEROGLYPH A233ANATOLIAN HIEROGLYPH A234ANATOLIAN HIEROGLYPH " +
"A235ANATOLIAN HIEROGLYPH A236ANATOLIAN HIEROGLYPH A237ANATOLIAN HIEROGLY" +
"PH A238ANATOLIAN HIEROGLYPH A239ANATOLIAN HIEROGLYPH A240ANATOLIAN HIERO" +
"GLYPH A241ANATOLIAN HIEROGLYPH A242ANATOLIAN HIEROGLYPH A243ANATOLIAN HI" +
"EROGLYPH A244ANATOLIAN HIEROGLYPH A245ANATOLIAN HIEROGLYPH A246ANATOLIAN" +
" HIEROGLYPH A247ANATOLIAN HIEROGLYPH A248ANATOLIAN HIEROGLYPH A249ANATOL" +
"IAN HIEROGLYPH A250ANATOLIAN HIEROGLYPH A251ANATOLIAN HIEROGLYPH A252ANA" +
"TOLIAN HIEROGLYPH A253ANATOLIAN HIEROGLYPH A254ANATOLIAN HIEROGLYPH A255" +
"ANATOLIAN HIEROGLYPH A256ANATOLIAN HIEROGLYPH A257ANATOLIAN HIEROGLYPH A" +
"258ANATOLIAN HIEROGLYPH A259ANATOLIAN HIEROGLYPH A260ANATOLIAN HIEROGLYP" +
"H A261ANATOLIAN HIEROGLYPH A262ANATOLIAN HIEROGLYPH A263ANATOLIAN HIEROG" +
"LYPH A264ANATOLIAN HIEROGLYPH A265ANATOLIAN HIEROGLYPH A266ANATOLIAN HIE" +
"ROGLYPH A267ANATOLIAN HIEROGLYPH A267AANATOLIAN HIEROGLYPH A268ANATOLIAN" +
" HIEROGLYPH A269ANATOLIAN HIEROGLYPH A270ANATOLIAN HIEROGLYPH A271ANATOL" +
"IAN HIEROGLYPH A272ANATOLIAN HIEROGLYPH A273ANATOLIAN HIEROGLYPH A274ANA" +
"TOLIAN HIEROGLYPH A275ANATOLIAN HIEROGLYPH A276ANATOLIAN HIEROGLYPH A277" +
"ANATOLIAN HIEROGLYPH A278ANATOLIAN HIEROGLYPH A279ANATOLIAN HIEROGLYPH A" +
"280ANATOLIAN HIEROGLYPH A281ANATOLIAN HIEROGLYPH A282ANATOLIAN HIEROGLYP" +
"H A283ANATOLIAN HIEROGLYPH A284ANATOLIAN HIEROGLYPH A285ANATOLIAN HIEROG" +
"LYPH A286ANATOLIAN HIEROGLYPH A287ANATOLIAN HIEROGLYPH A288ANATOLIAN HIE" +
"ROGLYPH A289ANATOLIAN HIEROGLYPH A289AANATOLIAN HIEROGLYPH A290ANATOLIAN" +
" HIEROGLYPH A291ANATOLIAN HIEROGLYPH A292ANATOLIAN HIEROGLYPH A293ANATOL" +
"IAN HIEROGLYPH A294ANATOLIAN HIEROGLYPH A294AANATOLIAN HIEROGLYPH A295AN" +
"ATOLIAN HIEROGLYPH A296ANATOLIAN HIEROGLYPH A297ANATOLIAN HIEROGLYPH A29" +
"8ANATOLIAN HIEROGLYPH A299ANATOLIAN HIEROGLYPH A299AANATOLIAN HIEROGLYPH" +
" A300ANATOLIAN HIEROGLYPH A301ANATOLIAN HIEROGLYPH A302ANATOLIAN HIEROGL" +
"YPH A303ANATOLIAN HIEROGLYPH A304ANATOLIAN HIEROGLYPH A305ANATOLIAN HIER" +
"OGLYPH A306ANATOLIAN HIEROGLYPH A307ANATOLIAN HIEROGLYPH A308ANATOLIAN H" +
"IEROGLYPH A309ANATOLIAN HIEROGLYPH A309AANATOLIAN HIEROGLYPH A310ANATOLI" +
"AN HIEROGLYPH A311ANATOLIAN HIEROGLYPH A312ANATOLIAN HIEROGLYPH A313ANAT" +
"OLIAN HIEROGLYPH A314ANATOLIAN HIEROGLYPH A315ANATOLIAN HIEROGLYPH A316A" +
"NATOLIAN HIEROGLYPH A317ANATOLIAN HIEROGLYPH A318ANATOLIAN HIEROGLYPH A3" +
"19ANATOLIAN HIEROGLYPH A320ANATOLIAN HIEROGLYPH A321ANATOLIAN HIEROGLYPH" +
" A322ANATOLIAN HIEROGLYPH A323ANATOLIAN HIEROGLYPH A324ANATOLIAN HIEROGL" +
"YPH A325ANATOLIAN HIEROGLYPH A326ANATOLIAN HIEROGLYPH A327ANATOLIAN HIER" +
"OGLYPH A328ANATOLIAN HIEROGLYPH A329ANATOLIAN HIEROGLYPH A329AANATOLIAN " +
"HIEROGLYPH A330ANATOLIAN HIEROGLYPH A331ANATOLIAN HIEROGLYPH A332AANATOL" +
"IAN HIEROGLYPH A332BANATOLIAN HIEROGLYPH A332CANATOLIAN HIEROGLYPH A333A" +
"NATOLIAN HIEROGLYPH A334ANATOLIAN HIEROGLYPH A335ANATOLIAN HIEROGLYPH A3" +
"36ANATOLIAN HIEROGLYPH A336AANATOLIAN HIEROGLYPH A336BANATOLIAN HIEROGLY" +
"PH A336CANATOLIAN HIEROGLYPH A337ANATOLIAN HIEROGLYPH A338ANATOLIAN HIER" +
"OGLYPH A339ANATOLIAN HIEROGLYPH A340ANATOLIAN HIEROGLYPH A341ANATOLIAN H" +
"IEROGLYPH A342ANATOLIAN HIEROGLYPH A343ANATOLIAN HIEROGLYPH A344ANATOLIA" +
"N HIEROGLYPH A345ANATOLIAN HIEROGLYPH A346ANATOLIAN HIEROGLYPH A347ANATO" +
"LIAN HIEROGLYPH A348ANATOLIAN HIEROGLYPH A349ANATOLIAN HIEROGLYPH A350AN" +
"ATOLIAN HIEROGLYPH A351ANATOLIAN HIEROGLYPH A352ANATOLIAN HIEROGLYPH A35" +
"3ANATOLIAN HIEROGLYPH A354ANATOLIAN HIEROGLYPH A355ANATOLIAN HIEROGLYPH " +
"A356ANATOLIAN HIEROGLYPH A357ANATOLIAN HIEROGLYPH A358ANATOLIAN HIEROGLY" +
"PH A359ANATOLIAN HIEROGLYPH A359AANATOLIAN HIEROGLYPH A360ANATOLIAN HIER" +
"OGLYPH A361ANATOLIAN HIEROGLYPH A362ANATOLIAN HIEROGLYPH A363ANATOLIAN H" +
"IEROGLYPH A364ANATOLIAN HIEROGLYPH A364AANATOLIAN HIEROGLYPH A365ANATOLI" +
"AN HIEROGLYPH A366ANATOLIAN HIEROGLYPH A367ANATOLIAN HIEROGLYPH A368ANAT" +
"OLIAN HIEROGLYPH A368AANATOLIAN HIEROGLYPH A369ANATOLIAN HIEROGLYPH A370") + ("" +
"ANATOLIAN HIEROGLYPH A371ANATOLIAN HIEROGLYPH A371AANATOLIAN HIEROGLYPH " +
"A372ANATOLIAN HIEROGLYPH A373ANATOLIAN HIEROGLYPH A374ANATOLIAN HIEROGLY" +
"PH A375ANATOLIAN HIEROGLYPH A376ANATOLIAN HIEROGLYPH A377ANATOLIAN HIERO" +
"GLYPH A378ANATOLIAN HIEROGLYPH A379ANATOLIAN HIEROGLYPH A380ANATOLIAN HI" +
"EROGLYPH A381ANATOLIAN HIEROGLYPH A381AANATOLIAN HIEROGLYPH A382ANATOLIA" +
"N HIEROGLYPH A383 RA OR RIANATOLIAN HIEROGLYPH A383AANATOLIAN HIEROGLYPH" +
" A384ANATOLIAN HIEROGLYPH A385ANATOLIAN HIEROGLYPH A386ANATOLIAN HIEROGL" +
"YPH A386AANATOLIAN HIEROGLYPH A387ANATOLIAN HIEROGLYPH A388ANATOLIAN HIE" +
"ROGLYPH A389ANATOLIAN HIEROGLYPH A390ANATOLIAN HIEROGLYPH A391ANATOLIAN " +
"HIEROGLYPH A392ANATOLIAN HIEROGLYPH A393 EIGHTANATOLIAN HIEROGLYPH A394A" +
"NATOLIAN HIEROGLYPH A395ANATOLIAN HIEROGLYPH A396ANATOLIAN HIEROGLYPH A3" +
"97ANATOLIAN HIEROGLYPH A398ANATOLIAN HIEROGLYPH A399ANATOLIAN HIEROGLYPH" +
" A400ANATOLIAN HIEROGLYPH A401ANATOLIAN HIEROGLYPH A402ANATOLIAN HIEROGL" +
"YPH A403ANATOLIAN HIEROGLYPH A404ANATOLIAN HIEROGLYPH A405ANATOLIAN HIER" +
"OGLYPH A406ANATOLIAN HIEROGLYPH A407ANATOLIAN HIEROGLYPH A408ANATOLIAN H" +
"IEROGLYPH A409ANATOLIAN HIEROGLYPH A410 BEGIN LOGOGRAM MARKANATOLIAN HIE" +
"ROGLYPH A410A END LOGOGRAM MARKANATOLIAN HIEROGLYPH A411ANATOLIAN HIEROG" +
"LYPH A412ANATOLIAN HIEROGLYPH A413ANATOLIAN HIEROGLYPH A414ANATOLIAN HIE" +
"ROGLYPH A415ANATOLIAN HIEROGLYPH A416ANATOLIAN HIEROGLYPH A417ANATOLIAN " +
"HIEROGLYPH A418ANATOLIAN HIEROGLYPH A419ANATOLIAN HIEROGLYPH A420ANATOLI" +
"AN HIEROGLYPH A421ANATOLIAN HIEROGLYPH A422ANATOLIAN HIEROGLYPH A423ANAT" +
"OLIAN HIEROGLYPH A424ANATOLIAN HIEROGLYPH A425ANATOLIAN HIEROGLYPH A426A" +
"NATOLIAN HIEROGLYPH A427ANATOLIAN HIEROGLYPH A428ANATOLIAN HIEROGLYPH A4" +
"29ANATOLIAN HIEROGLYPH A430ANATOLIAN HIEROGLYPH A431ANATOLIAN HIEROGLYPH" +
" A432ANATOLIAN HIEROGLYPH A433ANATOLIAN HIEROGLYPH A434ANATOLIAN HIEROGL" +
"YPH A435ANATOLIAN HIEROGLYPH A436ANATOLIAN HIEROGLYPH A437ANATOLIAN HIER" +
"OGLYPH A438ANATOLIAN HIEROGLYPH A439ANATOLIAN HIEROGLYPH A440ANATOLIAN H" +
"IEROGLYPH A441ANATOLIAN HIEROGLYPH A442ANATOLIAN HIEROGLYPH A443ANATOLIA" +
"N HIEROGLYPH A444ANATOLIAN HIEROGLYPH A445ANATOLIAN HIEROGLYPH A446ANATO" +
"LIAN HIEROGLYPH A447ANATOLIAN HIEROGLYPH A448ANATOLIAN HIEROGLYPH A449AN" +
"ATOLIAN HIEROGLYPH A450ANATOLIAN HIEROGLYPH A450AANATOLIAN HIEROGLYPH A4" +
"51ANATOLIAN HIEROGLYPH A452ANATOLIAN HIEROGLYPH A453ANATOLIAN HIEROGLYPH" +
" A454ANATOLIAN HIEROGLYPH A455ANATOLIAN HIEROGLYPH A456ANATOLIAN HIEROGL" +
"YPH A457ANATOLIAN HIEROGLYPH A457AANATOLIAN HIEROGLYPH A458ANATOLIAN HIE" +
"ROGLYPH A459ANATOLIAN HIEROGLYPH A460ANATOLIAN HIEROGLYPH A461ANATOLIAN " +
"HIEROGLYPH A462ANATOLIAN HIEROGLYPH A463ANATOLIAN HIEROGLYPH A464ANATOLI" +
"AN HIEROGLYPH A465ANATOLIAN HIEROGLYPH A466ANATOLIAN HIEROGLYPH A467ANAT" +
"OLIAN HIEROGLYPH A468ANATOLIAN HIEROGLYPH A469ANATOLIAN HIEROGLYPH A470A" +
"NATOLIAN HIEROGLYPH A471ANATOLIAN HIEROGLYPH A472ANATOLIAN HIEROGLYPH A4" +
"73ANATOLIAN HIEROGLYPH A474ANATOLIAN HIEROGLYPH A475ANATOLIAN HIEROGLYPH" +
" A476ANATOLIAN HIEROGLYPH A477ANATOLIAN HIEROGLYPH A478ANATOLIAN HIEROGL" +
"YPH A479ANATOLIAN HIEROGLYPH A480ANATOLIAN HIEROGLYPH A481ANATOLIAN HIER" +
"OGLYPH A482ANATOLIAN HIEROGLYPH A483ANATOLIAN HIEROGLYPH A484ANATOLIAN H" +
"IEROGLYPH A485ANATOLIAN HIEROGLYPH A486ANATOLIAN HIEROGLYPH A487ANATOLIA" +
"N HIEROGLYPH A488ANATOLIAN HIEROGLYPH A489ANATOLIAN HIEROGLYPH A490ANATO" +
"LIAN HIEROGLYPH A491ANATOLIAN HIEROGLYPH A492ANATOLIAN HIEROGLYPH A493AN" +
"ATOLIAN HIEROGLYPH A494ANATOLIAN HIEROGLYPH A495ANATOLIAN HIEROGLYPH A49" +
"6ANATOLIAN HIEROGLYPH A497ANATOLIAN HIEROGLYPH A501ANATOLIAN HIEROGLYPH " +
"A502ANATOLIAN HIEROGLYPH A503ANATOLIAN HIEROGLYPH A504ANATOLIAN HIEROGLY" +
"PH A505ANATOLIAN HIEROGLYPH A506ANATOLIAN HIEROGLYPH A507ANATOLIAN HIERO" +
"GLYPH A508ANATOLIAN HIEROGLYPH A509ANATOLIAN HIEROGLYPH A510ANATOLIAN HI" +
"EROGLYPH A511ANATOLIAN HIEROGLYPH A512ANATOLIAN HIEROGLYPH A513ANATOLIAN" +
" HIEROGLYPH A514ANATOLIAN HIEROGLYPH A515ANATOLIAN HIEROGLYPH A516ANATOL" +
"IAN HIEROGLYPH A517ANATOLIAN HIEROGLYPH A518ANATOLIAN HIEROGLYPH A519ANA" +
"TOLIAN HIEROGLYPH A520ANATOLIAN HIEROGLYPH A521ANATOLIAN HIEROGLYPH A522" +
"ANATOLIAN HIEROGLYPH A523ANATOLIAN HIEROGLYPH A524ANATOLIAN HIEROGLYPH A" +
"525ANATOLIAN HIEROGLYPH A526ANATOLIAN HIEROGLYPH A527ANATOLIAN HIEROGLYP" +
"H A528ANATOLIAN HIEROGLYPH A529ANATOLIAN HIEROGLYPH A530BAMUM LETTER PHA" +
"SE-A NGKUE MFONBAMUM LETTER PHASE-A GBIEE FONBAMUM LETTER PHASE-A PON MF" +
"ON PIPAEMGBIEEBAMUM LETTER PHASE-A PON MFON PIPAEMBABAMUM LETTER PHASE-A" +
" NAA MFONBAMUM LETTER PHASE-A SHUENSHUETBAMUM LETTER PHASE-A TITA MFONBA" +
"MUM LETTER PHASE-A NZA MFONBAMUM LETTER PHASE-A SHINDA PA NJIBAMUM LETTE" +
"R PHASE-A PON PA NJI PIPAEMGBIEEBAMUM LETTER PHASE-A PON PA NJI PIPAEMBA" +
"BAMUM LETTER PHASE-A MAEMBGBIEEBAMUM LETTER PHASE-A TU MAEMBABAMUM LETTE") + ("" +
"R PHASE-A NGANGUBAMUM LETTER PHASE-A MAEMVEUXBAMUM LETTER PHASE-A MANSUA" +
"EBAMUM LETTER PHASE-A MVEUAENGAMBAMUM LETTER PHASE-A SEUNYAMBAMUM LETTER" +
" PHASE-A NTOQPENBAMUM LETTER PHASE-A KEUKEUTNDABAMUM LETTER PHASE-A NKIN" +
"DIBAMUM LETTER PHASE-A SUUBAMUM LETTER PHASE-A NGKUENZEUMBAMUM LETTER PH" +
"ASE-A LAPAQBAMUM LETTER PHASE-A LET KUTBAMUM LETTER PHASE-A NTAP MFAABAM" +
"UM LETTER PHASE-A MAEKEUPBAMUM LETTER PHASE-A PASHAEBAMUM LETTER PHASE-A" +
" GHEUAERAEBAMUM LETTER PHASE-A PAMSHAEBAMUM LETTER PHASE-A MON NGGEUAETB" +
"AMUM LETTER PHASE-A NZUN MEUTBAMUM LETTER PHASE-A U YUQ NAEBAMUM LETTER " +
"PHASE-A GHEUAEGHEUAEBAMUM LETTER PHASE-A NTAP NTAABAMUM LETTER PHASE-A S" +
"ISABAMUM LETTER PHASE-A MGBASABAMUM LETTER PHASE-A MEUNJOMNDEUQBAMUM LET" +
"TER PHASE-A MOOMPUQBAMUM LETTER PHASE-A KAFABAMUM LETTER PHASE-A PA LEER" +
"AEWABAMUM LETTER PHASE-A NDA LEERAEWABAMUM LETTER PHASE-A PETBAMUM LETTE" +
"R PHASE-A MAEMKPENBAMUM LETTER PHASE-A NIKABAMUM LETTER PHASE-A PUPBAMUM" +
" LETTER PHASE-A TUAEPBAMUM LETTER PHASE-A LUAEPBAMUM LETTER PHASE-A SONJ" +
"AMBAMUM LETTER PHASE-A TEUTEUWENBAMUM LETTER PHASE-A MAENYIBAMUM LETTER " +
"PHASE-A KETBAMUM LETTER PHASE-A NDAANGGEUAETBAMUM LETTER PHASE-A KUOQBAM" +
"UM LETTER PHASE-A MOOMEUTBAMUM LETTER PHASE-A SHUMBAMUM LETTER PHASE-A L" +
"OMMAEBAMUM LETTER PHASE-A FIRIBAMUM LETTER PHASE-A ROMBAMUM LETTER PHASE" +
"-A KPOQBAMUM LETTER PHASE-A SOQBAMUM LETTER PHASE-A MAP PIEETBAMUM LETTE" +
"R PHASE-A SHIRAEBAMUM LETTER PHASE-A NTAPBAMUM LETTER PHASE-A SHOQ NSHUT" +
" YUMBAMUM LETTER PHASE-A NYIT MONGKEUAEQBAMUM LETTER PHASE-A PAARAEBAMUM" +
" LETTER PHASE-A NKAARAEBAMUM LETTER PHASE-A UNKNOWNBAMUM LETTER PHASE-A " +
"NGGENBAMUM LETTER PHASE-A MAESIBAMUM LETTER PHASE-A NJAMBAMUM LETTER PHA" +
"SE-A MBANYIBAMUM LETTER PHASE-A NYETBAMUM LETTER PHASE-A TEUAENBAMUM LET" +
"TER PHASE-A SOTBAMUM LETTER PHASE-A PAAMBAMUM LETTER PHASE-A NSHIEEBAMUM" +
" LETTER PHASE-A MAEMBAMUM LETTER PHASE-A NYIBAMUM LETTER PHASE-A KAQBAMU" +
"M LETTER PHASE-A NSHABAMUM LETTER PHASE-A VEEBAMUM LETTER PHASE-A LUBAMU" +
"M LETTER PHASE-A NENBAMUM LETTER PHASE-A NAQBAMUM LETTER PHASE-A MBAQBAM" +
"UM LETTER PHASE-B NSHUETBAMUM LETTER PHASE-B TU MAEMGBIEEBAMUM LETTER PH" +
"ASE-B SIEEBAMUM LETTER PHASE-B SET TUBAMUM LETTER PHASE-B LOM NTEUMBAMUM" +
" LETTER PHASE-B MBA MAELEEBAMUM LETTER PHASE-B KIEEMBAMUM LETTER PHASE-B" +
" YEURAEBAMUM LETTER PHASE-B MBAARAEBAMUM LETTER PHASE-B KAMBAMUM LETTER " +
"PHASE-B PEESHIBAMUM LETTER PHASE-B YAFU LEERAEWABAMUM LETTER PHASE-B LAM" +
" NSHUT NYAMBAMUM LETTER PHASE-B NTIEE SHEUOQBAMUM LETTER PHASE-B NDU NJA" +
"ABAMUM LETTER PHASE-B GHEUGHEUAEMBAMUM LETTER PHASE-B PITBAMUM LETTER PH" +
"ASE-B TU NSIEEBAMUM LETTER PHASE-B SHET NJAQBAMUM LETTER PHASE-B SHEUAEQ" +
"TUBAMUM LETTER PHASE-B MFON TEUAEQBAMUM LETTER PHASE-B MBIT MBAAKETBAMUM" +
" LETTER PHASE-B NYI NTEUMBAMUM LETTER PHASE-B KEUPUQBAMUM LETTER PHASE-B" +
" GHEUGHENBAMUM LETTER PHASE-B KEUYEUXBAMUM LETTER PHASE-B LAANAEBAMUM LE" +
"TTER PHASE-B PARUMBAMUM LETTER PHASE-B VEUMBAMUM LETTER PHASE-B NGKINDI " +
"MVOPBAMUM LETTER PHASE-B NGGEU MBUBAMUM LETTER PHASE-B WUAETBAMUM LETTER" +
" PHASE-B SAKEUAEBAMUM LETTER PHASE-B TAAMBAMUM LETTER PHASE-B MEUQBAMUM " +
"LETTER PHASE-B NGGUOQBAMUM LETTER PHASE-B NGGUOQ LARGEBAMUM LETTER PHASE" +
"-B MFIYAQBAMUM LETTER PHASE-B SUEBAMUM LETTER PHASE-B MBEURIBAMUM LETTER" +
" PHASE-B MONTIEENBAMUM LETTER PHASE-B NYAEMAEBAMUM LETTER PHASE-B PUNGAA" +
"MBAMUM LETTER PHASE-B MEUT NGGEETBAMUM LETTER PHASE-B FEUXBAMUM LETTER P" +
"HASE-B MBUOQBAMUM LETTER PHASE-B FEEBAMUM LETTER PHASE-B KEUAEMBAMUM LET" +
"TER PHASE-B MA NJEUAENABAMUM LETTER PHASE-B MA NJUQABAMUM LETTER PHASE-B" +
" LETBAMUM LETTER PHASE-B NGGAAMBAMUM LETTER PHASE-B NSENBAMUM LETTER PHA" +
"SE-B MABAMUM LETTER PHASE-B KIQBAMUM LETTER PHASE-B NGOMBAMUM LETTER PHA" +
"SE-C NGKUE MAEMBABAMUM LETTER PHASE-C NZABAMUM LETTER PHASE-C YUMBAMUM L" +
"ETTER PHASE-C WANGKUOQBAMUM LETTER PHASE-C NGGENBAMUM LETTER PHASE-C NDE" +
"UAEREEBAMUM LETTER PHASE-C NGKAQBAMUM LETTER PHASE-C GHARAEBAMUM LETTER " +
"PHASE-C MBEEKEETBAMUM LETTER PHASE-C GBAYIBAMUM LETTER PHASE-C NYIR MKPA" +
"RAQ MEUNBAMUM LETTER PHASE-C NTU MBITBAMUM LETTER PHASE-C MBEUMBAMUM LET" +
"TER PHASE-C PIRIEENBAMUM LETTER PHASE-C NDOMBUBAMUM LETTER PHASE-C MBAA " +
"CABBAGE-TREEBAMUM LETTER PHASE-C KEUSHEUAEPBAMUM LETTER PHASE-C GHAPBAMU" +
"M LETTER PHASE-C KEUKAQBAMUM LETTER PHASE-C YU MUOMAEBAMUM LETTER PHASE-" +
"C NZEUMBAMUM LETTER PHASE-C MBUEBAMUM LETTER PHASE-C NSEUAENBAMUM LETTER" +
" PHASE-C MBITBAMUM LETTER PHASE-C YEUQBAMUM LETTER PHASE-C KPARAQBAMUM L" +
"ETTER PHASE-C KAABAMUM LETTER PHASE-C SEUXBAMUM LETTER PHASE-C NDIDABAMU" +
"M LETTER PHASE-C TAASHAEBAMUM LETTER PHASE-C NJUEQBAMUM LETTER PHASE-C T" +
"ITA YUEBAMUM LETTER PHASE-C SUAETBAMUM LETTER PHASE-C NGGUAEN NYAMBAMUM " +
"LETTER PHASE-C VEUXBAMUM LETTER PHASE-C NANSANAQBAMUM LETTER PHASE-C MA ") + ("" +
"KEUAERIBAMUM LETTER PHASE-C NTAABAMUM LETTER PHASE-C NGGUONBAMUM LETTER " +
"PHASE-C LAPBAMUM LETTER PHASE-C MBIRIEENBAMUM LETTER PHASE-C MGBASAQBAMU" +
"M LETTER PHASE-C NTEUNGBABAMUM LETTER PHASE-C TEUTEUXBAMUM LETTER PHASE-" +
"C NGGUMBAMUM LETTER PHASE-C FUEBAMUM LETTER PHASE-C NDEUTBAMUM LETTER PH" +
"ASE-C NSABAMUM LETTER PHASE-C NSHAQBAMUM LETTER PHASE-C BUNGBAMUM LETTER" +
" PHASE-C VEUAEPENBAMUM LETTER PHASE-C MBERAEBAMUM LETTER PHASE-C RUBAMUM" +
" LETTER PHASE-C NJAEMBAMUM LETTER PHASE-C LAMBAMUM LETTER PHASE-C TITUAE" +
"PBAMUM LETTER PHASE-C NSUOT NGOMBAMUM LETTER PHASE-C NJEEEEBAMUM LETTER " +
"PHASE-C KETBAMUM LETTER PHASE-C NGGUBAMUM LETTER PHASE-C MAESIBAMUM LETT" +
"ER PHASE-C MBUAEMBAMUM LETTER PHASE-C LUBAMUM LETTER PHASE-C KUTBAMUM LE" +
"TTER PHASE-C NJAMBAMUM LETTER PHASE-C NGOMBAMUM LETTER PHASE-C WUPBAMUM " +
"LETTER PHASE-C NGGUEETBAMUM LETTER PHASE-C NSOMBAMUM LETTER PHASE-C NTEN" +
"BAMUM LETTER PHASE-C KUOP NKAARAEBAMUM LETTER PHASE-C NSUNBAMUM LETTER P" +
"HASE-C NDAMBAMUM LETTER PHASE-C MA NSIEEBAMUM LETTER PHASE-C YAABAMUM LE" +
"TTER PHASE-C NDAPBAMUM LETTER PHASE-C SHUEQBAMUM LETTER PHASE-C SETFONBA" +
"MUM LETTER PHASE-C MBIBAMUM LETTER PHASE-C MAEMBABAMUM LETTER PHASE-C MB" +
"ANYIBAMUM LETTER PHASE-C KEUSEUXBAMUM LETTER PHASE-C MBEUXBAMUM LETTER P" +
"HASE-C KEUMBAMUM LETTER PHASE-C MBAA PICKETBAMUM LETTER PHASE-C YUWOQBAM" +
"UM LETTER PHASE-C NJEUXBAMUM LETTER PHASE-C MIEEBAMUM LETTER PHASE-C MUA" +
"EBAMUM LETTER PHASE-C SHIQBAMUM LETTER PHASE-C KEN LAWBAMUM LETTER PHASE" +
"-C KEN FATIGUEBAMUM LETTER PHASE-C NGAQBAMUM LETTER PHASE-C NAQBAMUM LET" +
"TER PHASE-C LIQBAMUM LETTER PHASE-C PINBAMUM LETTER PHASE-C PENBAMUM LET" +
"TER PHASE-C TETBAMUM LETTER PHASE-D MBUOBAMUM LETTER PHASE-D WAPBAMUM LE" +
"TTER PHASE-D NJIBAMUM LETTER PHASE-D MFONBAMUM LETTER PHASE-D NJIEEBAMUM" +
" LETTER PHASE-D LIEEBAMUM LETTER PHASE-D NJEUTBAMUM LETTER PHASE-D NSHEE" +
"BAMUM LETTER PHASE-D NGGAAMAEBAMUM LETTER PHASE-D NYAMBAMUM LETTER PHASE" +
"-D WUAENBAMUM LETTER PHASE-D NGKUNBAMUM LETTER PHASE-D SHEEBAMUM LETTER " +
"PHASE-D NGKAPBAMUM LETTER PHASE-D KEUAETMEUNBAMUM LETTER PHASE-D TEUTBAM" +
"UM LETTER PHASE-D SHEUAEBAMUM LETTER PHASE-D NJAPBAMUM LETTER PHASE-D SU" +
"EBAMUM LETTER PHASE-D KETBAMUM LETTER PHASE-D YAEMMAEBAMUM LETTER PHASE-" +
"D KUOMBAMUM LETTER PHASE-D SAPBAMUM LETTER PHASE-D MFEUTBAMUM LETTER PHA" +
"SE-D NDEUXBAMUM LETTER PHASE-D MALEERIBAMUM LETTER PHASE-D MEUTBAMUM LET" +
"TER PHASE-D SEUAEQBAMUM LETTER PHASE-D YENBAMUM LETTER PHASE-D NJEUAEMBA" +
"MUM LETTER PHASE-D KEUOT MBUAEBAMUM LETTER PHASE-D NGKEURIBAMUM LETTER P" +
"HASE-D TUBAMUM LETTER PHASE-D GHAABAMUM LETTER PHASE-D NGKYEEBAMUM LETTE" +
"R PHASE-D FEUFEUAETBAMUM LETTER PHASE-D NDEEBAMUM LETTER PHASE-D MGBOFUM" +
"BAMUM LETTER PHASE-D LEUAEPBAMUM LETTER PHASE-D NDONBAMUM LETTER PHASE-D" +
" MONIBAMUM LETTER PHASE-D MGBEUNBAMUM LETTER PHASE-D PUUTBAMUM LETTER PH" +
"ASE-D MGBIEEBAMUM LETTER PHASE-D MFOBAMUM LETTER PHASE-D LUMBAMUM LETTER" +
" PHASE-D NSIEEPBAMUM LETTER PHASE-D MBAABAMUM LETTER PHASE-D KWAETBAMUM " +
"LETTER PHASE-D NYETBAMUM LETTER PHASE-D TEUAENBAMUM LETTER PHASE-D SOTBA" +
"MUM LETTER PHASE-D YUWOQBAMUM LETTER PHASE-D KEUMBAMUM LETTER PHASE-D RA" +
"EMBAMUM LETTER PHASE-D TEEEEBAMUM LETTER PHASE-D NGKEUAEQBAMUM LETTER PH" +
"ASE-D MFEUAEBAMUM LETTER PHASE-D NSIEETBAMUM LETTER PHASE-D KEUPBAMUM LE" +
"TTER PHASE-D PIPBAMUM LETTER PHASE-D PEUTAEBAMUM LETTER PHASE-D NYUEBAMU" +
"M LETTER PHASE-D LETBAMUM LETTER PHASE-D NGGAAMBAMUM LETTER PHASE-D MFIE" +
"EBAMUM LETTER PHASE-D NGGWAENBAMUM LETTER PHASE-D YUOMBAMUM LETTER PHASE" +
"-D PAPBAMUM LETTER PHASE-D YUOPBAMUM LETTER PHASE-D NDAMBAMUM LETTER PHA" +
"SE-D NTEUMBAMUM LETTER PHASE-D SUAEBAMUM LETTER PHASE-D KUNBAMUM LETTER " +
"PHASE-D NGGEUXBAMUM LETTER PHASE-D NGKIEEBAMUM LETTER PHASE-D TUOTBAMUM " +
"LETTER PHASE-D MEUNBAMUM LETTER PHASE-D KUQBAMUM LETTER PHASE-D NSUMBAMU" +
"M LETTER PHASE-D TEUNBAMUM LETTER PHASE-D MAENJETBAMUM LETTER PHASE-D NG" +
"GAPBAMUM LETTER PHASE-D LEUMBAMUM LETTER PHASE-D NGGUOMBAMUM LETTER PHAS" +
"E-D NSHUTBAMUM LETTER PHASE-D NJUEQBAMUM LETTER PHASE-D GHEUAEBAMUM LETT" +
"ER PHASE-D KUBAMUM LETTER PHASE-D REN OLDBAMUM LETTER PHASE-D TAEBAMUM L" +
"ETTER PHASE-D TOQBAMUM LETTER PHASE-D NYIBAMUM LETTER PHASE-D RIIBAMUM L" +
"ETTER PHASE-D LEEEEBAMUM LETTER PHASE-D MEEEEBAMUM LETTER PHASE-D MBAMUM" +
" LETTER PHASE-D SUUBAMUM LETTER PHASE-D MUBAMUM LETTER PHASE-D SHIIBAMUM" +
" LETTER PHASE-D SHEUXBAMUM LETTER PHASE-D KYEEBAMUM LETTER PHASE-D NUBAM" +
"UM LETTER PHASE-D SHUBAMUM LETTER PHASE-D NTEEBAMUM LETTER PHASE-D PEEBA" +
"MUM LETTER PHASE-D NIBAMUM LETTER PHASE-D SHOQBAMUM LETTER PHASE-D PUQBA" +
"MUM LETTER PHASE-D MVOPBAMUM LETTER PHASE-D LOQBAMUM LETTER PHASE-D REN " +
"MUCHBAMUM LETTER PHASE-D TIBAMUM LETTER PHASE-D NTUUBAMUM LETTER PHASE-D" +
" MBAA SEVENBAMUM LETTER PHASE-D SAQBAMUM LETTER PHASE-D FAABAMUM LETTER ") + ("" +
"PHASE-E NDAPBAMUM LETTER PHASE-E TOONBAMUM LETTER PHASE-E MBEUMBAMUM LET" +
"TER PHASE-E LAPBAMUM LETTER PHASE-E VOMBAMUM LETTER PHASE-E LOONBAMUM LE" +
"TTER PHASE-E PAABAMUM LETTER PHASE-E SOMBAMUM LETTER PHASE-E RAQBAMUM LE" +
"TTER PHASE-E NSHUOPBAMUM LETTER PHASE-E NDUNBAMUM LETTER PHASE-E PUAEBAM" +
"UM LETTER PHASE-E TAMBAMUM LETTER PHASE-E NGKABAMUM LETTER PHASE-E KPEUX" +
"BAMUM LETTER PHASE-E WUOBAMUM LETTER PHASE-E SEEBAMUM LETTER PHASE-E NGG" +
"EUAETBAMUM LETTER PHASE-E PAAMBAMUM LETTER PHASE-E TOOBAMUM LETTER PHASE" +
"-E KUOPBAMUM LETTER PHASE-E LOMBAMUM LETTER PHASE-E NSHIEEBAMUM LETTER P" +
"HASE-E NGOPBAMUM LETTER PHASE-E MAEMBAMUM LETTER PHASE-E NGKEUXBAMUM LET" +
"TER PHASE-E NGOQBAMUM LETTER PHASE-E NSHUEBAMUM LETTER PHASE-E RIMGBABAM" +
"UM LETTER PHASE-E NJEUXBAMUM LETTER PHASE-E PEEMBAMUM LETTER PHASE-E SAA" +
"BAMUM LETTER PHASE-E NGGURAEBAMUM LETTER PHASE-E MGBABAMUM LETTER PHASE-" +
"E GHEUXBAMUM LETTER PHASE-E NGKEUAEMBAMUM LETTER PHASE-E NJAEMLIBAMUM LE" +
"TTER PHASE-E MAPBAMUM LETTER PHASE-E LOOTBAMUM LETTER PHASE-E NGGEEEEBAM" +
"UM LETTER PHASE-E NDIQBAMUM LETTER PHASE-E TAEN NTEUMBAMUM LETTER PHASE-" +
"E SETBAMUM LETTER PHASE-E PUMBAMUM LETTER PHASE-E NDAA SOFTNESSBAMUM LET" +
"TER PHASE-E NGGUAESHAE NYAMBAMUM LETTER PHASE-E YIEEBAMUM LETTER PHASE-E" +
" GHEUNBAMUM LETTER PHASE-E TUAEBAMUM LETTER PHASE-E YEUAEBAMUM LETTER PH" +
"ASE-E POBAMUM LETTER PHASE-E TUMAEBAMUM LETTER PHASE-E KEUAEBAMUM LETTER" +
" PHASE-E SUAENBAMUM LETTER PHASE-E TEUAEQBAMUM LETTER PHASE-E VEUAEBAMUM" +
" LETTER PHASE-E WEUXBAMUM LETTER PHASE-E LAAMBAMUM LETTER PHASE-E PUBAMU" +
"M LETTER PHASE-E TAAQBAMUM LETTER PHASE-E GHAAMAEBAMUM LETTER PHASE-E NG" +
"EUREUTBAMUM LETTER PHASE-E SHEUAEQBAMUM LETTER PHASE-E MGBENBAMUM LETTER" +
" PHASE-E MBEEBAMUM LETTER PHASE-E NZAQBAMUM LETTER PHASE-E NKOMBAMUM LET" +
"TER PHASE-E GBETBAMUM LETTER PHASE-E TUMBAMUM LETTER PHASE-E KUETBAMUM L" +
"ETTER PHASE-E YAPBAMUM LETTER PHASE-E NYI CLEAVERBAMUM LETTER PHASE-E YI" +
"TBAMUM LETTER PHASE-E MFEUQBAMUM LETTER PHASE-E NDIAQBAMUM LETTER PHASE-" +
"E PIEEQBAMUM LETTER PHASE-E YUEQBAMUM LETTER PHASE-E LEUAEMBAMUM LETTER " +
"PHASE-E FUEBAMUM LETTER PHASE-E GBEUXBAMUM LETTER PHASE-E NGKUPBAMUM LET" +
"TER PHASE-E KETBAMUM LETTER PHASE-E MAEBAMUM LETTER PHASE-E NGKAAMIBAMUM" +
" LETTER PHASE-E GHETBAMUM LETTER PHASE-E FABAMUM LETTER PHASE-E NTUMBAMU" +
"M LETTER PHASE-E PEUTBAMUM LETTER PHASE-E YEUMBAMUM LETTER PHASE-E NGGEU" +
"AEBAMUM LETTER PHASE-E NYI BETWEENBAMUM LETTER PHASE-E NZUQBAMUM LETTER " +
"PHASE-E POONBAMUM LETTER PHASE-E MIEEBAMUM LETTER PHASE-E FUETBAMUM LETT" +
"ER PHASE-E NAEBAMUM LETTER PHASE-E MUAEBAMUM LETTER PHASE-E GHEUAEBAMUM " +
"LETTER PHASE-E FU IBAMUM LETTER PHASE-E MVIBAMUM LETTER PHASE-E PUAQBAMU" +
"M LETTER PHASE-E NGKUMBAMUM LETTER PHASE-E KUTBAMUM LETTER PHASE-E PIETB" +
"AMUM LETTER PHASE-E NTAPBAMUM LETTER PHASE-E YEUAETBAMUM LETTER PHASE-E " +
"NGGUPBAMUM LETTER PHASE-E PA PEOPLEBAMUM LETTER PHASE-E FU CALLBAMUM LET" +
"TER PHASE-E FOMBAMUM LETTER PHASE-E NJEEBAMUM LETTER PHASE-E ABAMUM LETT" +
"ER PHASE-E TOQBAMUM LETTER PHASE-E OBAMUM LETTER PHASE-E IBAMUM LETTER P" +
"HASE-E LAQBAMUM LETTER PHASE-E PA PLURALBAMUM LETTER PHASE-E TAABAMUM LE" +
"TTER PHASE-E TAQBAMUM LETTER PHASE-E NDAA MY HOUSEBAMUM LETTER PHASE-E S" +
"HIQBAMUM LETTER PHASE-E YEUXBAMUM LETTER PHASE-E NGUAEBAMUM LETTER PHASE" +
"-E YUAENBAMUM LETTER PHASE-E YOQ SWIMMINGBAMUM LETTER PHASE-E YOQ COVERB" +
"AMUM LETTER PHASE-E YUQBAMUM LETTER PHASE-E YUNBAMUM LETTER PHASE-E KEUX" +
"BAMUM LETTER PHASE-E PEUXBAMUM LETTER PHASE-E NJEE EPOCHBAMUM LETTER PHA" +
"SE-E PUEBAMUM LETTER PHASE-E WUEBAMUM LETTER PHASE-E FEEBAMUM LETTER PHA" +
"SE-E VEEBAMUM LETTER PHASE-E LUBAMUM LETTER PHASE-E MIBAMUM LETTER PHASE" +
"-E REUXBAMUM LETTER PHASE-E RAEBAMUM LETTER PHASE-E NGUAETBAMUM LETTER P" +
"HASE-E NGABAMUM LETTER PHASE-E SHOBAMUM LETTER PHASE-E SHOQBAMUM LETTER " +
"PHASE-E FU REMEDYBAMUM LETTER PHASE-E NABAMUM LETTER PHASE-E PIBAMUM LET" +
"TER PHASE-E LOQBAMUM LETTER PHASE-E KOBAMUM LETTER PHASE-E MENBAMUM LETT" +
"ER PHASE-E MABAMUM LETTER PHASE-E MAQBAMUM LETTER PHASE-E TEUBAMUM LETTE" +
"R PHASE-E KIBAMUM LETTER PHASE-E MONBAMUM LETTER PHASE-E TENBAMUM LETTER" +
" PHASE-E FAQBAMUM LETTER PHASE-E GHOMBAMUM LETTER PHASE-F KABAMUM LETTER" +
" PHASE-F UBAMUM LETTER PHASE-F KUBAMUM LETTER PHASE-F EEBAMUM LETTER PHA" +
"SE-F REEBAMUM LETTER PHASE-F TAEBAMUM LETTER PHASE-F NYIBAMUM LETTER PHA" +
"SE-F LABAMUM LETTER PHASE-F RIIBAMUM LETTER PHASE-F RIEEBAMUM LETTER PHA" +
"SE-F MEEEEBAMUM LETTER PHASE-F TAABAMUM LETTER PHASE-F NDAABAMUM LETTER " +
"PHASE-F NJAEMBAMUM LETTER PHASE-F MBAMUM LETTER PHASE-F SUUBAMUM LETTER " +
"PHASE-F SHIIBAMUM LETTER PHASE-F SIBAMUM LETTER PHASE-F SEUXBAMUM LETTER" +
" PHASE-F KYEEBAMUM LETTER PHASE-F KETBAMUM LETTER PHASE-F NUAEBAMUM LETT" +
"ER PHASE-F NUBAMUM LETTER PHASE-F NJUAEBAMUM LETTER PHASE-F YOQBAMUM LET") + ("" +
"TER PHASE-F SHUBAMUM LETTER PHASE-F YABAMUM LETTER PHASE-F NSHABAMUM LET" +
"TER PHASE-F PEUXBAMUM LETTER PHASE-F NTEEBAMUM LETTER PHASE-F WUEBAMUM L" +
"ETTER PHASE-F PEEBAMUM LETTER PHASE-F RUBAMUM LETTER PHASE-F NIBAMUM LET" +
"TER PHASE-F REUXBAMUM LETTER PHASE-F KENBAMUM LETTER PHASE-F NGKWAENBAMU" +
"M LETTER PHASE-F NGGABAMUM LETTER PHASE-F SHOBAMUM LETTER PHASE-F PUAEBA" +
"MUM LETTER PHASE-F FOMBAMUM LETTER PHASE-F WABAMUM LETTER PHASE-F LIBAMU" +
"M LETTER PHASE-F LOQBAMUM LETTER PHASE-F KOBAMUM LETTER PHASE-F MBENBAMU" +
"M LETTER PHASE-F RENBAMUM LETTER PHASE-F MABAMUM LETTER PHASE-F MOBAMUM " +
"LETTER PHASE-F MBAABAMUM LETTER PHASE-F TETBAMUM LETTER PHASE-F KPABAMUM" +
" LETTER PHASE-F SAMBABAMUM LETTER PHASE-F VUEQMRO LETTER TAMRO LETTER NG" +
"IMRO LETTER YOMRO LETTER MIMMRO LETTER BAMRO LETTER DAMRO LETTER AMRO LE" +
"TTER PHIMRO LETTER KHAIMRO LETTER HAOMRO LETTER DAIMRO LETTER CHUMRO LET" +
"TER KEAAEMRO LETTER OLMRO LETTER MAEMMRO LETTER NINMRO LETTER PAMRO LETT" +
"ER OOMRO LETTER OMRO LETTER ROMRO LETTER SHIMRO LETTER THEAMRO LETTER EA" +
"MRO LETTER WAMRO LETTER EMRO LETTER KOMRO LETTER LANMRO LETTER LAMRO LET" +
"TER HAIMRO LETTER RIMRO LETTER TEKMRO DIGIT ZEROMRO DIGIT ONEMRO DIGIT T" +
"WOMRO DIGIT THREEMRO DIGIT FOURMRO DIGIT FIVEMRO DIGIT SIXMRO DIGIT SEVE" +
"NMRO DIGIT EIGHTMRO DIGIT NINEMRO DANDAMRO DOUBLE DANDATANGSA LETTER OZT" +
"ANGSA LETTER OCTANGSA LETTER OQTANGSA LETTER OXTANGSA LETTER AZTANGSA LE" +
"TTER ACTANGSA LETTER AQTANGSA LETTER AXTANGSA LETTER VZTANGSA LETTER VCT" +
"ANGSA LETTER VQTANGSA LETTER VXTANGSA LETTER EZTANGSA LETTER ECTANGSA LE" +
"TTER EQTANGSA LETTER EXTANGSA LETTER IZTANGSA LETTER ICTANGSA LETTER IQT" +
"ANGSA LETTER IXTANGSA LETTER UZTANGSA LETTER UCTANGSA LETTER UQTANGSA LE" +
"TTER UXTANGSA LETTER AWZTANGSA LETTER AWCTANGSA LETTER AWQTANGSA LETTER " +
"AWXTANGSA LETTER UIZTANGSA LETTER UICTANGSA LETTER UIQTANGSA LETTER UIXT" +
"ANGSA LETTER FINAL NGTANGSA LETTER LONG UEXTANGSA LETTER SHORT UEZTANGSA" +
" LETTER SHORT AWXTANGSA LETTER UECTANGSA LETTER UEZTANGSA LETTER UEQTANG" +
"SA LETTER UEXTANGSA LETTER UIUZTANGSA LETTER UIUCTANGSA LETTER UIUQTANGS" +
"A LETTER UIUXTANGSA LETTER MZTANGSA LETTER MCTANGSA LETTER MQTANGSA LETT" +
"ER MXTANGSA LETTER KATANGSA LETTER KHATANGSA LETTER GATANGSA LETTER NGAT" +
"ANGSA LETTER SATANGSA LETTER YATANGSA LETTER WATANGSA LETTER PATANGSA LE" +
"TTER NYATANGSA LETTER PHATANGSA LETTER BATANGSA LETTER MATANGSA LETTER N" +
"ATANGSA LETTER HATANGSA LETTER LATANGSA LETTER HTATANGSA LETTER TATANGSA" +
" LETTER DATANGSA LETTER RATANGSA LETTER NHATANGSA LETTER SHATANGSA LETTE" +
"R CATANGSA LETTER TSATANGSA LETTER GHATANGSA LETTER HTTATANGSA LETTER TH" +
"ATANGSA LETTER XATANGSA LETTER FATANGSA LETTER DHATANGSA LETTER CHATANGS" +
"A LETTER ZATANGSA DIGIT ZEROTANGSA DIGIT ONETANGSA DIGIT TWOTANGSA DIGIT" +
" THREETANGSA DIGIT FOURTANGSA DIGIT FIVETANGSA DIGIT SIXTANGSA DIGIT SEV" +
"ENTANGSA DIGIT EIGHTTANGSA DIGIT NINEBASSA VAH LETTER ENNIBASSA VAH LETT" +
"ER KABASSA VAH LETTER SEBASSA VAH LETTER FABASSA VAH LETTER MBEBASSA VAH" +
" LETTER YIEBASSA VAH LETTER GAHBASSA VAH LETTER DHIIBASSA VAH LETTER KPA" +
"HBASSA VAH LETTER JOBASSA VAH LETTER HWAHBASSA VAH LETTER WABASSA VAH LE" +
"TTER ZOBASSA VAH LETTER GBUBASSA VAH LETTER DOBASSA VAH LETTER CEBASSA V" +
"AH LETTER UWUBASSA VAH LETTER TOBASSA VAH LETTER BABASSA VAH LETTER VUBA" +
"SSA VAH LETTER YEINBASSA VAH LETTER PABASSA VAH LETTER WADDABASSA VAH LE" +
"TTER ABASSA VAH LETTER OBASSA VAH LETTER OOBASSA VAH LETTER UBASSA VAH L" +
"ETTER EEBASSA VAH LETTER EBASSA VAH LETTER IBASSA VAH COMBINING HIGH TON" +
"EBASSA VAH COMBINING LOW TONEBASSA VAH COMBINING MID TONEBASSA VAH COMBI" +
"NING LOW-MID TONEBASSA VAH COMBINING HIGH-LOW TONEBASSA VAH FULL STOPPAH" +
"AWH HMONG VOWEL KEEBPAHAWH HMONG VOWEL KEEVPAHAWH HMONG VOWEL KIBPAHAWH " +
"HMONG VOWEL KIVPAHAWH HMONG VOWEL KAUBPAHAWH HMONG VOWEL KAUVPAHAWH HMON" +
"G VOWEL KUBPAHAWH HMONG VOWEL KUVPAHAWH HMONG VOWEL KEBPAHAWH HMONG VOWE" +
"L KEVPAHAWH HMONG VOWEL KAIBPAHAWH HMONG VOWEL KAIVPAHAWH HMONG VOWEL KO" +
"OBPAHAWH HMONG VOWEL KOOVPAHAWH HMONG VOWEL KAWBPAHAWH HMONG VOWEL KAWVP" +
"AHAWH HMONG VOWEL KUABPAHAWH HMONG VOWEL KUAVPAHAWH HMONG VOWEL KOBPAHAW" +
"H HMONG VOWEL KOVPAHAWH HMONG VOWEL KIABPAHAWH HMONG VOWEL KIAVPAHAWH HM" +
"ONG VOWEL KABPAHAWH HMONG VOWEL KAVPAHAWH HMONG VOWEL KWBPAHAWH HMONG VO" +
"WEL KWVPAHAWH HMONG VOWEL KAABPAHAWH HMONG VOWEL KAAVPAHAWH HMONG CONSON" +
"ANT VAUPAHAWH HMONG CONSONANT NTSAUPAHAWH HMONG CONSONANT LAUPAHAWH HMON" +
"G CONSONANT HAUPAHAWH HMONG CONSONANT NLAUPAHAWH HMONG CONSONANT RAUPAHA" +
"WH HMONG CONSONANT NKAUPAHAWH HMONG CONSONANT QHAUPAHAWH HMONG CONSONANT" +
" YAUPAHAWH HMONG CONSONANT HLAUPAHAWH HMONG CONSONANT MAUPAHAWH HMONG CO" +
"NSONANT CHAUPAHAWH HMONG CONSONANT NCHAUPAHAWH HMONG CONSONANT HNAUPAHAW" +
"H HMONG CONSONANT PLHAUPAHAWH HMONG CONSONANT NTHAUPAHAWH HMONG CONSONAN") + ("" +
"T NAUPAHAWH HMONG CONSONANT AUPAHAWH HMONG CONSONANT XAUPAHAWH HMONG CON" +
"SONANT CAUPAHAWH HMONG MARK CIM TUBPAHAWH HMONG MARK CIM SOPAHAWH HMONG " +
"MARK CIM KESPAHAWH HMONG MARK CIM KHAVPAHAWH HMONG MARK CIM SUAMPAHAWH H" +
"MONG MARK CIM HOMPAHAWH HMONG MARK CIM TAUMPAHAWH HMONG SIGN VOS THOMPAH" +
"AWH HMONG SIGN VOS TSHAB CEEBPAHAWH HMONG SIGN CIM CHEEMPAHAWH HMONG SIG" +
"N VOS THIABPAHAWH HMONG SIGN VOS FEEMPAHAWH HMONG SIGN XYEEM NTXIVPAHAWH" +
" HMONG SIGN XYEEM RHOPAHAWH HMONG SIGN XYEEM TOVPAHAWH HMONG SIGN XYEEM " +
"FAIBPAHAWH HMONG SIGN VOS SEEVPAHAWH HMONG SIGN MEEJ SUABPAHAWH HMONG SI" +
"GN VOS NRUAPAHAWH HMONG SIGN IB YAMPAHAWH HMONG SIGN XAUSPAHAWH HMONG SI" +
"GN CIM TSOV ROGPAHAWH HMONG DIGIT ZEROPAHAWH HMONG DIGIT ONEPAHAWH HMONG" +
" DIGIT TWOPAHAWH HMONG DIGIT THREEPAHAWH HMONG DIGIT FOURPAHAWH HMONG DI" +
"GIT FIVEPAHAWH HMONG DIGIT SIXPAHAWH HMONG DIGIT SEVENPAHAWH HMONG DIGIT" +
" EIGHTPAHAWH HMONG DIGIT NINEPAHAWH HMONG NUMBER TENSPAHAWH HMONG NUMBER" +
" HUNDREDSPAHAWH HMONG NUMBER TEN THOUSANDSPAHAWH HMONG NUMBER MILLIONSPA" +
"HAWH HMONG NUMBER HUNDRED MILLIONSPAHAWH HMONG NUMBER TEN BILLIONSPAHAWH" +
" HMONG NUMBER TRILLIONSPAHAWH HMONG SIGN VOS LUBPAHAWH HMONG SIGN XYOOPA" +
"HAWH HMONG SIGN HLIPAHAWH HMONG SIGN THIRD-STAGE HLIPAHAWH HMONG SIGN ZW" +
"J THAJPAHAWH HMONG SIGN HNUBPAHAWH HMONG SIGN NQIGPAHAWH HMONG SIGN XIAB" +
"PAHAWH HMONG SIGN NTUJPAHAWH HMONG SIGN AVPAHAWH HMONG SIGN TXHEEJ CEEVP" +
"AHAWH HMONG SIGN MEEJ TSEEBPAHAWH HMONG SIGN TAUPAHAWH HMONG SIGN LOSPAH" +
"AWH HMONG SIGN MUSPAHAWH HMONG SIGN CIM HAIS LUS NTOG NTOGPAHAWH HMONG S" +
"IGN CIM CUAM TSHOOJPAHAWH HMONG SIGN CIM TXWVPAHAWH HMONG SIGN CIM TXWV " +
"CHWVPAHAWH HMONG SIGN CIM PUB DAWBPAHAWH HMONG SIGN CIM NRES TOSPAHAWH H" +
"MONG CLAN SIGN TSHEEJPAHAWH HMONG CLAN SIGN YEEGPAHAWH HMONG CLAN SIGN L" +
"ISPAHAWH HMONG CLAN SIGN LAUJPAHAWH HMONG CLAN SIGN XYOOJPAHAWH HMONG CL" +
"AN SIGN KOOPAHAWH HMONG CLAN SIGN HAWJPAHAWH HMONG CLAN SIGN MUASPAHAWH " +
"HMONG CLAN SIGN THOJPAHAWH HMONG CLAN SIGN TSABPAHAWH HMONG CLAN SIGN PH" +
"ABPAHAWH HMONG CLAN SIGN KHABPAHAWH HMONG CLAN SIGN HAMPAHAWH HMONG CLAN" +
" SIGN VAJPAHAWH HMONG CLAN SIGN FAJPAHAWH HMONG CLAN SIGN YAJPAHAWH HMON" +
"G CLAN SIGN TSWBPAHAWH HMONG CLAN SIGN KWMPAHAWH HMONG CLAN SIGN VWJMEDE" +
"FAIDRIN CAPITAL LETTER MMEDEFAIDRIN CAPITAL LETTER SMEDEFAIDRIN CAPITAL " +
"LETTER VMEDEFAIDRIN CAPITAL LETTER WMEDEFAIDRIN CAPITAL LETTER ATIUMEDEF" +
"AIDRIN CAPITAL LETTER ZMEDEFAIDRIN CAPITAL LETTER KPMEDEFAIDRIN CAPITAL " +
"LETTER PMEDEFAIDRIN CAPITAL LETTER TMEDEFAIDRIN CAPITAL LETTER GMEDEFAID" +
"RIN CAPITAL LETTER FMEDEFAIDRIN CAPITAL LETTER IMEDEFAIDRIN CAPITAL LETT" +
"ER KMEDEFAIDRIN CAPITAL LETTER AMEDEFAIDRIN CAPITAL LETTER JMEDEFAIDRIN " +
"CAPITAL LETTER EMEDEFAIDRIN CAPITAL LETTER BMEDEFAIDRIN CAPITAL LETTER C" +
"MEDEFAIDRIN CAPITAL LETTER UMEDEFAIDRIN CAPITAL LETTER YUMEDEFAIDRIN CAP" +
"ITAL LETTER LMEDEFAIDRIN CAPITAL LETTER QMEDEFAIDRIN CAPITAL LETTER HPME" +
"DEFAIDRIN CAPITAL LETTER NYMEDEFAIDRIN CAPITAL LETTER XMEDEFAIDRIN CAPIT" +
"AL LETTER DMEDEFAIDRIN CAPITAL LETTER OEMEDEFAIDRIN CAPITAL LETTER NMEDE" +
"FAIDRIN CAPITAL LETTER RMEDEFAIDRIN CAPITAL LETTER OMEDEFAIDRIN CAPITAL " +
"LETTER AIMEDEFAIDRIN CAPITAL LETTER YMEDEFAIDRIN SMALL LETTER MMEDEFAIDR" +
"IN SMALL LETTER SMEDEFAIDRIN SMALL LETTER VMEDEFAIDRIN SMALL LETTER WMED" +
"EFAIDRIN SMALL LETTER ATIUMEDEFAIDRIN SMALL LETTER ZMEDEFAIDRIN SMALL LE" +
"TTER KPMEDEFAIDRIN SMALL LETTER PMEDEFAIDRIN SMALL LETTER TMEDEFAIDRIN S" +
"MALL LETTER GMEDEFAIDRIN SMALL LETTER FMEDEFAIDRIN SMALL LETTER IMEDEFAI" +
"DRIN SMALL LETTER KMEDEFAIDRIN SMALL LETTER AMEDEFAIDRIN SMALL LETTER JM" +
"EDEFAIDRIN SMALL LETTER EMEDEFAIDRIN SMALL LETTER BMEDEFAIDRIN SMALL LET" +
"TER CMEDEFAIDRIN SMALL LETTER UMEDEFAIDRIN SMALL LETTER YUMEDEFAIDRIN SM" +
"ALL LETTER LMEDEFAIDRIN SMALL LETTER QMEDEFAIDRIN SMALL LETTER HPMEDEFAI" +
"DRIN SMALL LETTER NYMEDEFAIDRIN SMALL LETTER XMEDEFAIDRIN SMALL LETTER D" +
"MEDEFAIDRIN SMALL LETTER OEMEDEFAIDRIN SMALL LETTER NMEDEFAIDRIN SMALL L" +
"ETTER RMEDEFAIDRIN SMALL LETTER OMEDEFAIDRIN SMALL LETTER AIMEDEFAIDRIN " +
"SMALL LETTER YMEDEFAIDRIN DIGIT ZEROMEDEFAIDRIN DIGIT ONEMEDEFAIDRIN DIG" +
"IT TWOMEDEFAIDRIN DIGIT THREEMEDEFAIDRIN DIGIT FOURMEDEFAIDRIN DIGIT FIV" +
"EMEDEFAIDRIN DIGIT SIXMEDEFAIDRIN DIGIT SEVENMEDEFAIDRIN DIGIT EIGHTMEDE" +
"FAIDRIN DIGIT NINEMEDEFAIDRIN NUMBER TENMEDEFAIDRIN NUMBER ELEVENMEDEFAI" +
"DRIN NUMBER TWELVEMEDEFAIDRIN NUMBER THIRTEENMEDEFAIDRIN NUMBER FOURTEEN" +
"MEDEFAIDRIN NUMBER FIFTEENMEDEFAIDRIN NUMBER SIXTEENMEDEFAIDRIN NUMBER S" +
"EVENTEENMEDEFAIDRIN NUMBER EIGHTEENMEDEFAIDRIN NUMBER NINETEENMEDEFAIDRI" +
"N DIGIT ONE ALTERNATE FORMMEDEFAIDRIN DIGIT TWO ALTERNATE FORMMEDEFAIDRI" +
"N DIGIT THREE ALTERNATE FORMMEDEFAIDRIN COMMAMEDEFAIDRIN FULL STOPMEDEFA" +
"IDRIN SYMBOL AIVAMEDEFAIDRIN EXCLAMATION OHMIAO LETTER PAMIAO LETTER BAM") + ("" +
"IAO LETTER YI PAMIAO LETTER PLAMIAO LETTER MAMIAO LETTER MHAMIAO LETTER " +
"ARCHAIC MAMIAO LETTER FAMIAO LETTER VAMIAO LETTER VFAMIAO LETTER TAMIAO " +
"LETTER DAMIAO LETTER YI TTAMIAO LETTER YI TAMIAO LETTER TTAMIAO LETTER D" +
"DAMIAO LETTER NAMIAO LETTER NHAMIAO LETTER YI NNAMIAO LETTER ARCHAIC NAM" +
"IAO LETTER NNAMIAO LETTER NNHAMIAO LETTER LAMIAO LETTER LYAMIAO LETTER L" +
"HAMIAO LETTER LHYAMIAO LETTER TLHAMIAO LETTER DLHAMIAO LETTER TLHYAMIAO " +
"LETTER DLHYAMIAO LETTER KAMIAO LETTER GAMIAO LETTER YI KAMIAO LETTER QAM" +
"IAO LETTER QGAMIAO LETTER NGAMIAO LETTER NGHAMIAO LETTER ARCHAIC NGAMIAO" +
" LETTER HAMIAO LETTER XAMIAO LETTER GHAMIAO LETTER GHHAMIAO LETTER TSSAM" +
"IAO LETTER DZZAMIAO LETTER NYAMIAO LETTER NYHAMIAO LETTER TSHAMIAO LETTE" +
"R DZHAMIAO LETTER YI TSHAMIAO LETTER YI DZHAMIAO LETTER REFORMED TSHAMIA" +
"O LETTER SHAMIAO LETTER SSAMIAO LETTER ZHAMIAO LETTER ZSHAMIAO LETTER TS" +
"AMIAO LETTER DZAMIAO LETTER YI TSAMIAO LETTER SAMIAO LETTER ZAMIAO LETTE" +
"R ZSAMIAO LETTER ZZAMIAO LETTER ZZSAMIAO LETTER ARCHAIC ZZAMIAO LETTER Z" +
"ZYAMIAO LETTER ZZSYAMIAO LETTER WAMIAO LETTER AHMIAO LETTER HHAMIAO LETT" +
"ER BRIMIAO LETTER SYIMIAO LETTER DZYIMIAO LETTER TEMIAO LETTER TSEMIAO L" +
"ETTER RTEMIAO SIGN CONSONANT MODIFIER BARMIAO LETTER NASALIZATIONMIAO SI" +
"GN ASPIRATIONMIAO SIGN REFORMED VOICINGMIAO SIGN REFORMED ASPIRATIONMIAO" +
" VOWEL SIGN AMIAO VOWEL SIGN AAMIAO VOWEL SIGN AHHMIAO VOWEL SIGN ANMIAO" +
" VOWEL SIGN ANGMIAO VOWEL SIGN OMIAO VOWEL SIGN OOMIAO VOWEL SIGN WOMIAO" +
" VOWEL SIGN WMIAO VOWEL SIGN EMIAO VOWEL SIGN ENMIAO VOWEL SIGN ENGMIAO " +
"VOWEL SIGN OEYMIAO VOWEL SIGN IMIAO VOWEL SIGN IAMIAO VOWEL SIGN IANMIAO" +
" VOWEL SIGN IANGMIAO VOWEL SIGN IOMIAO VOWEL SIGN IEMIAO VOWEL SIGN IIMI" +
"AO VOWEL SIGN IUMIAO VOWEL SIGN INGMIAO VOWEL SIGN UMIAO VOWEL SIGN UAMI" +
"AO VOWEL SIGN UANMIAO VOWEL SIGN UANGMIAO VOWEL SIGN UUMIAO VOWEL SIGN U" +
"EIMIAO VOWEL SIGN UNGMIAO VOWEL SIGN YMIAO VOWEL SIGN YIMIAO VOWEL SIGN " +
"AEMIAO VOWEL SIGN AEEMIAO VOWEL SIGN ERRMIAO VOWEL SIGN ROUNDED ERRMIAO " +
"VOWEL SIGN ERMIAO VOWEL SIGN ROUNDED ERMIAO VOWEL SIGN AIMIAO VOWEL SIGN" +
" EIMIAO VOWEL SIGN AUMIAO VOWEL SIGN OUMIAO VOWEL SIGN NMIAO VOWEL SIGN " +
"NGMIAO VOWEL SIGN UOGMIAO VOWEL SIGN YUIMIAO VOWEL SIGN OGMIAO VOWEL SIG" +
"N OERMIAO VOWEL SIGN VWMIAO VOWEL SIGN IGMIAO VOWEL SIGN EAMIAO VOWEL SI" +
"GN IONGMIAO VOWEL SIGN UIMIAO TONE RIGHTMIAO TONE TOP RIGHTMIAO TONE ABO" +
"VEMIAO TONE BELOWMIAO LETTER TONE-2MIAO LETTER TONE-3MIAO LETTER TONE-4M" +
"IAO LETTER TONE-5MIAO LETTER TONE-6MIAO LETTER TONE-7MIAO LETTER TONE-8M" +
"IAO LETTER REFORMED TONE-1MIAO LETTER REFORMED TONE-2MIAO LETTER REFORME" +
"D TONE-4MIAO LETTER REFORMED TONE-5MIAO LETTER REFORMED TONE-6MIAO LETTE" +
"R REFORMED TONE-8TANGUT ITERATION MARKNUSHU ITERATION MARKOLD CHINESE HO" +
"OK MARKOLD CHINESE ITERATION MARKKHITAN SMALL SCRIPT FILLERVIETNAMESE AL" +
"TERNATE READING MARK CAVIETNAMESE ALTERNATE READING MARK NHAYTANGUT COMP" +
"ONENT-001TANGUT COMPONENT-002TANGUT COMPONENT-003TANGUT COMPONENT-004TAN" +
"GUT COMPONENT-005TANGUT COMPONENT-006TANGUT COMPONENT-007TANGUT COMPONEN" +
"T-008TANGUT COMPONENT-009TANGUT COMPONENT-010TANGUT COMPONENT-011TANGUT " +
"COMPONENT-012TANGUT COMPONENT-013TANGUT COMPONENT-014TANGUT COMPONENT-01" +
"5TANGUT COMPONENT-016TANGUT COMPONENT-017TANGUT COMPONENT-018TANGUT COMP" +
"ONENT-019TANGUT COMPONENT-020TANGUT COMPONENT-021TANGUT COMPONENT-022TAN" +
"GUT COMPONENT-023TANGUT COMPONENT-024TANGUT COMPONENT-025TANGUT COMPONEN" +
"T-026TANGUT COMPONENT-027TANGUT COMPONENT-028TANGUT COMPONENT-029TANGUT " +
"COMPONENT-030TANGUT COMPONENT-031TANGUT COMPONENT-032TANGUT COMPONENT-03" +
"3TANGUT COMPONENT-034TANGUT COMPONENT-035TANGUT COMPONENT-036TANGUT COMP" +
"ONENT-037TANGUT COMPONENT-038TANGUT COMPONENT-039TANGUT COMPONENT-040TAN" +
"GUT COMPONENT-041TANGUT COMPONENT-042TANGUT COMPONENT-043TANGUT COMPONEN" +
"T-044TANGUT COMPONENT-045TANGUT COMPONENT-046TANGUT COMPONENT-047TANGUT " +
"COMPONENT-048TANGUT COMPONENT-049TANGUT COMPONENT-050TANGUT COMPONENT-05" +
"1TANGUT COMPONENT-052TANGUT COMPONENT-053TANGUT COMPONENT-054TANGUT COMP" +
"ONENT-055TANGUT COMPONENT-056TANGUT COMPONENT-057TANGUT COMPONENT-058TAN" +
"GUT COMPONENT-059TANGUT COMPONENT-060TANGUT COMPONENT-061TANGUT COMPONEN" +
"T-062TANGUT COMPONENT-063TANGUT COMPONENT-064TANGUT COMPONENT-065TANGUT " +
"COMPONENT-066TANGUT COMPONENT-067TANGUT COMPONENT-068TANGUT COMPONENT-06" +
"9TANGUT COMPONENT-070TANGUT COMPONENT-071TANGUT COMPONENT-072TANGUT COMP" +
"ONENT-073TANGUT COMPONENT-074TANGUT COMPONENT-075TANGUT COMPONENT-076TAN" +
"GUT COMPONENT-077TANGUT COMPONENT-078TANGUT COMPONENT-079TANGUT COMPONEN" +
"T-080TANGUT COMPONENT-081TANGUT COMPONENT-082TANGUT COMPONENT-083TANGUT " +
"COMPONENT-084TANGUT COMPONENT-085TANGUT COMPONENT-086TANGUT COMPONENT-08" +
"7TANGUT COMPONENT-088TANGUT COMPONENT-089TANGUT COMPONENT-090TANGUT COMP") + ("" +
"ONENT-091TANGUT COMPONENT-092TANGUT COMPONENT-093TANGUT COMPONENT-094TAN" +
"GUT COMPONENT-095TANGUT COMPONENT-096TANGUT COMPONENT-097TANGUT COMPONEN" +
"T-098TANGUT COMPONENT-099TANGUT COMPONENT-100TANGUT COMPONENT-101TANGUT " +
"COMPONENT-102TANGUT COMPONENT-103TANGUT COMPONENT-104TANGUT COMPONENT-10" +
"5TANGUT COMPONENT-106TANGUT COMPONENT-107TANGUT COMPONENT-108TANGUT COMP" +
"ONENT-109TANGUT COMPONENT-110TANGUT COMPONENT-111TANGUT COMPONENT-112TAN" +
"GUT COMPONENT-113TANGUT COMPONENT-114TANGUT COMPONENT-115TANGUT COMPONEN" +
"T-116TANGUT COMPONENT-117TANGUT COMPONENT-118TANGUT COMPONENT-119TANGUT " +
"COMPONENT-120TANGUT COMPONENT-121TANGUT COMPONENT-122TANGUT COMPONENT-12" +
"3TANGUT COMPONENT-124TANGUT COMPONENT-125TANGUT COMPONENT-126TANGUT COMP" +
"ONENT-127TANGUT COMPONENT-128TANGUT COMPONENT-129TANGUT COMPONENT-130TAN" +
"GUT COMPONENT-131TANGUT COMPONENT-132TANGUT COMPONENT-133TANGUT COMPONEN" +
"T-134TANGUT COMPONENT-135TANGUT COMPONENT-136TANGUT COMPONENT-137TANGUT " +
"COMPONENT-138TANGUT COMPONENT-139TANGUT COMPONENT-140TANGUT COMPONENT-14" +
"1TANGUT COMPONENT-142TANGUT COMPONENT-143TANGUT COMPONENT-144TANGUT COMP" +
"ONENT-145TANGUT COMPONENT-146TANGUT COMPONENT-147TANGUT COMPONENT-148TAN" +
"GUT COMPONENT-149TANGUT COMPONENT-150TANGUT COMPONENT-151TANGUT COMPONEN" +
"T-152TANGUT COMPONENT-153TANGUT COMPONENT-154TANGUT COMPONENT-155TANGUT " +
"COMPONENT-156TANGUT COMPONENT-157TANGUT COMPONENT-158TANGUT COMPONENT-15" +
"9TANGUT COMPONENT-160TANGUT COMPONENT-161TANGUT COMPONENT-162TANGUT COMP" +
"ONENT-163TANGUT COMPONENT-164TANGUT COMPONENT-165TANGUT COMPONENT-166TAN" +
"GUT COMPONENT-167TANGUT COMPONENT-168TANGUT COMPONENT-169TANGUT COMPONEN" +
"T-170TANGUT COMPONENT-171TANGUT COMPONENT-172TANGUT COMPONENT-173TANGUT " +
"COMPONENT-174TANGUT COMPONENT-175TANGUT COMPONENT-176TANGUT COMPONENT-17" +
"7TANGUT COMPONENT-178TANGUT COMPONENT-179TANGUT COMPONENT-180TANGUT COMP" +
"ONENT-181TANGUT COMPONENT-182TANGUT COMPONENT-183TANGUT COMPONENT-184TAN" +
"GUT COMPONENT-185TANGUT COMPONENT-186TANGUT COMPONENT-187TANGUT COMPONEN" +
"T-188TANGUT COMPONENT-189TANGUT COMPONENT-190TANGUT COMPONENT-191TANGUT " +
"COMPONENT-192TANGUT COMPONENT-193TANGUT COMPONENT-194TANGUT COMPONENT-19" +
"5TANGUT COMPONENT-196TANGUT COMPONENT-197TANGUT COMPONENT-198TANGUT COMP" +
"ONENT-199TANGUT COMPONENT-200TANGUT COMPONENT-201TANGUT COMPONENT-202TAN" +
"GUT COMPONENT-203TANGUT COMPONENT-204TANGUT COMPONENT-205TANGUT COMPONEN" +
"T-206TANGUT COMPONENT-207TANGUT COMPONENT-208TANGUT COMPONENT-209TANGUT " +
"COMPONENT-210TANGUT COMPONENT-211TANGUT COMPONENT-212TANGUT COMPONENT-21" +
"3TANGUT COMPONENT-214TANGUT COMPONENT-215TANGUT COMPONENT-216TANGUT COMP" +
"ONENT-217TANGUT COMPONENT-218TANGUT COMPONENT-219TANGUT COMPONENT-220TAN" +
"GUT COMPONENT-221TANGUT COMPONENT-222TANGUT COMPONENT-223TANGUT COMPONEN" +
"T-224TANGUT COMPONENT-225TANGUT COMPONENT-226TANGUT COMPONENT-227TANGUT " +
"COMPONENT-228TANGUT COMPONENT-229TANGUT COMPONENT-230TANGUT COMPONENT-23" +
"1TANGUT COMPONENT-232TANGUT COMPONENT-233TANGUT COMPONENT-234TANGUT COMP" +
"ONENT-235TANGUT COMPONENT-236TANGUT COMPONENT-237TANGUT COMPONENT-238TAN" +
"GUT COMPONENT-239TANGUT COMPONENT-240TANGUT COMPONENT-241TANGUT COMPONEN" +
"T-242TANGUT COMPONENT-243TANGUT COMPONENT-244TANGUT COMPONENT-245TANGUT " +
"COMPONENT-246TANGUT COMPONENT-247TANGUT COMPONENT-248TANGUT COMPONENT-24" +
"9TANGUT COMPONENT-250TANGUT COMPONENT-251TANGUT COMPONENT-252TANGUT COMP" +
"ONENT-253TANGUT COMPONENT-254TANGUT COMPONENT-255TANGUT COMPONENT-256TAN" +
"GUT COMPONENT-257TANGUT COMPONENT-258TANGUT COMPONENT-259TANGUT COMPONEN" +
"T-260TANGUT COMPONENT-261TANGUT COMPONENT-262TANGUT COMPONENT-263TANGUT " +
"COMPONENT-264TANGUT COMPONENT-265TANGUT COMPONENT-266TANGUT COMPONENT-26" +
"7TANGUT COMPONENT-268TANGUT COMPONENT-269TANGUT COMPONENT-270TANGUT COMP" +
"ONENT-271TANGUT COMPONENT-272TANGUT COMPONENT-273TANGUT COMPONENT-274TAN" +
"GUT COMPONENT-275TANGUT COMPONENT-276TANGUT COMPONENT-277TANGUT COMPONEN" +
"T-278TANGUT COMPONENT-279TANGUT COMPONENT-280TANGUT COMPONENT-281TANGUT " +
"COMPONENT-282TANGUT COMPONENT-283TANGUT COMPONENT-284TANGUT COMPONENT-28" +
"5TANGUT COMPONENT-286TANGUT COMPONENT-287TANGUT COMPONENT-288TANGUT COMP" +
"ONENT-289TANGUT COMPONENT-290TANGUT COMPONENT-291TANGUT COMPONENT-292TAN" +
"GUT COMPONENT-293TANGUT COMPONENT-294TANGUT COMPONENT-295TANGUT COMPONEN" +
"T-296TANGUT COMPONENT-297TANGUT COMPONENT-298TANGUT COMPONENT-299TANGUT " +
"COMPONENT-300TANGUT COMPONENT-301TANGUT COMPONENT-302TANGUT COMPONENT-30" +
"3TANGUT COMPONENT-304TANGUT COMPONENT-305TANGUT COMPONENT-306TANGUT COMP" +
"ONENT-307TANGUT COMPONENT-308TANGUT COMPONENT-309TANGUT COMPONENT-310TAN" +
"GUT COMPONENT-311TANGUT COMPONENT-312TANGUT COMPONENT-313TANGUT COMPONEN" +
"T-314TANGUT COMPONENT-315TANGUT COMPONENT-316TANGUT COMPONENT-317TANGUT " +
"COMPONENT-318TANGUT COMPONENT-319TANGUT COMPONENT-320TANGUT COMPONENT-32") + ("" +
"1TANGUT COMPONENT-322TANGUT COMPONENT-323TANGUT COMPONENT-324TANGUT COMP" +
"ONENT-325TANGUT COMPONENT-326TANGUT COMPONENT-327TANGUT COMPONENT-328TAN" +
"GUT COMPONENT-329TANGUT COMPONENT-330TANGUT COMPONENT-331TANGUT COMPONEN" +
"T-332TANGUT COMPONENT-333TANGUT COMPONENT-334TANGUT COMPONENT-335TANGUT " +
"COMPONENT-336TANGUT COMPONENT-337TANGUT COMPONENT-338TANGUT COMPONENT-33" +
"9TANGUT COMPONENT-340TANGUT COMPONENT-341TANGUT COMPONENT-342TANGUT COMP" +
"ONENT-343TANGUT COMPONENT-344TANGUT COMPONENT-345TANGUT COMPONENT-346TAN" +
"GUT COMPONENT-347TANGUT COMPONENT-348TANGUT COMPONENT-349TANGUT COMPONEN" +
"T-350TANGUT COMPONENT-351TANGUT COMPONENT-352TANGUT COMPONENT-353TANGUT " +
"COMPONENT-354TANGUT COMPONENT-355TANGUT COMPONENT-356TANGUT COMPONENT-35" +
"7TANGUT COMPONENT-358TANGUT COMPONENT-359TANGUT COMPONENT-360TANGUT COMP" +
"ONENT-361TANGUT COMPONENT-362TANGUT COMPONENT-363TANGUT COMPONENT-364TAN" +
"GUT COMPONENT-365TANGUT COMPONENT-366TANGUT COMPONENT-367TANGUT COMPONEN" +
"T-368TANGUT COMPONENT-369TANGUT COMPONENT-370TANGUT COMPONENT-371TANGUT " +
"COMPONENT-372TANGUT COMPONENT-373TANGUT COMPONENT-374TANGUT COMPONENT-37" +
"5TANGUT COMPONENT-376TANGUT COMPONENT-377TANGUT COMPONENT-378TANGUT COMP" +
"ONENT-379TANGUT COMPONENT-380TANGUT COMPONENT-381TANGUT COMPONENT-382TAN" +
"GUT COMPONENT-383TANGUT COMPONENT-384TANGUT COMPONENT-385TANGUT COMPONEN" +
"T-386TANGUT COMPONENT-387TANGUT COMPONENT-388TANGUT COMPONENT-389TANGUT " +
"COMPONENT-390TANGUT COMPONENT-391TANGUT COMPONENT-392TANGUT COMPONENT-39" +
"3TANGUT COMPONENT-394TANGUT COMPONENT-395TANGUT COMPONENT-396TANGUT COMP" +
"ONENT-397TANGUT COMPONENT-398TANGUT COMPONENT-399TANGUT COMPONENT-400TAN" +
"GUT COMPONENT-401TANGUT COMPONENT-402TANGUT COMPONENT-403TANGUT COMPONEN" +
"T-404TANGUT COMPONENT-405TANGUT COMPONENT-406TANGUT COMPONENT-407TANGUT " +
"COMPONENT-408TANGUT COMPONENT-409TANGUT COMPONENT-410TANGUT COMPONENT-41" +
"1TANGUT COMPONENT-412TANGUT COMPONENT-413TANGUT COMPONENT-414TANGUT COMP" +
"ONENT-415TANGUT COMPONENT-416TANGUT COMPONENT-417TANGUT COMPONENT-418TAN" +
"GUT COMPONENT-419TANGUT COMPONENT-420TANGUT COMPONENT-421TANGUT COMPONEN" +
"T-422TANGUT COMPONENT-423TANGUT COMPONENT-424TANGUT COMPONENT-425TANGUT " +
"COMPONENT-426TANGUT COMPONENT-427TANGUT COMPONENT-428TANGUT COMPONENT-42" +
"9TANGUT COMPONENT-430TANGUT COMPONENT-431TANGUT COMPONENT-432TANGUT COMP" +
"ONENT-433TANGUT COMPONENT-434TANGUT COMPONENT-435TANGUT COMPONENT-436TAN" +
"GUT COMPONENT-437TANGUT COMPONENT-438TANGUT COMPONENT-439TANGUT COMPONEN" +
"T-440TANGUT COMPONENT-441TANGUT COMPONENT-442TANGUT COMPONENT-443TANGUT " +
"COMPONENT-444TANGUT COMPONENT-445TANGUT COMPONENT-446TANGUT COMPONENT-44" +
"7TANGUT COMPONENT-448TANGUT COMPONENT-449TANGUT COMPONENT-450TANGUT COMP" +
"ONENT-451TANGUT COMPONENT-452TANGUT COMPONENT-453TANGUT COMPONENT-454TAN" +
"GUT COMPONENT-455TANGUT COMPONENT-456TANGUT COMPONENT-457TANGUT COMPONEN" +
"T-458TANGUT COMPONENT-459TANGUT COMPONENT-460TANGUT COMPONENT-461TANGUT " +
"COMPONENT-462TANGUT COMPONENT-463TANGUT COMPONENT-464TANGUT COMPONENT-46" +
"5TANGUT COMPONENT-466TANGUT COMPONENT-467TANGUT COMPONENT-468TANGUT COMP" +
"ONENT-469TANGUT COMPONENT-470TANGUT COMPONENT-471TANGUT COMPONENT-472TAN" +
"GUT COMPONENT-473TANGUT COMPONENT-474TANGUT COMPONENT-475TANGUT COMPONEN" +
"T-476TANGUT COMPONENT-477TANGUT COMPONENT-478TANGUT COMPONENT-479TANGUT " +
"COMPONENT-480TANGUT COMPONENT-481TANGUT COMPONENT-482TANGUT COMPONENT-48" +
"3TANGUT COMPONENT-484TANGUT COMPONENT-485TANGUT COMPONENT-486TANGUT COMP" +
"ONENT-487TANGUT COMPONENT-488TANGUT COMPONENT-489TANGUT COMPONENT-490TAN" +
"GUT COMPONENT-491TANGUT COMPONENT-492TANGUT COMPONENT-493TANGUT COMPONEN" +
"T-494TANGUT COMPONENT-495TANGUT COMPONENT-496TANGUT COMPONENT-497TANGUT " +
"COMPONENT-498TANGUT COMPONENT-499TANGUT COMPONENT-500TANGUT COMPONENT-50" +
"1TANGUT COMPONENT-502TANGUT COMPONENT-503TANGUT COMPONENT-504TANGUT COMP" +
"ONENT-505TANGUT COMPONENT-506TANGUT COMPONENT-507TANGUT COMPONENT-508TAN" +
"GUT COMPONENT-509TANGUT COMPONENT-510TANGUT COMPONENT-511TANGUT COMPONEN" +
"T-512TANGUT COMPONENT-513TANGUT COMPONENT-514TANGUT COMPONENT-515TANGUT " +
"COMPONENT-516TANGUT COMPONENT-517TANGUT COMPONENT-518TANGUT COMPONENT-51" +
"9TANGUT COMPONENT-520TANGUT COMPONENT-521TANGUT COMPONENT-522TANGUT COMP" +
"ONENT-523TANGUT COMPONENT-524TANGUT COMPONENT-525TANGUT COMPONENT-526TAN" +
"GUT COMPONENT-527TANGUT COMPONENT-528TANGUT COMPONENT-529TANGUT COMPONEN" +
"T-530TANGUT COMPONENT-531TANGUT COMPONENT-532TANGUT COMPONENT-533TANGUT " +
"COMPONENT-534TANGUT COMPONENT-535TANGUT COMPONENT-536TANGUT COMPONENT-53" +
"7TANGUT COMPONENT-538TANGUT COMPONENT-539TANGUT COMPONENT-540TANGUT COMP" +
"ONENT-541TANGUT COMPONENT-542TANGUT COMPONENT-543TANGUT COMPONENT-544TAN" +
"GUT COMPONENT-545TANGUT COMPONENT-546TANGUT COMPONENT-547TANGUT COMPONEN" +
"T-548TANGUT COMPONENT-549TANGUT COMPONENT-550TANGUT COMPONENT-551TANGUT ") + ("" +
"COMPONENT-552TANGUT COMPONENT-553TANGUT COMPONENT-554TANGUT COMPONENT-55" +
"5TANGUT COMPONENT-556TANGUT COMPONENT-557TANGUT COMPONENT-558TANGUT COMP" +
"ONENT-559TANGUT COMPONENT-560TANGUT COMPONENT-561TANGUT COMPONENT-562TAN" +
"GUT COMPONENT-563TANGUT COMPONENT-564TANGUT COMPONENT-565TANGUT COMPONEN" +
"T-566TANGUT COMPONENT-567TANGUT COMPONENT-568TANGUT COMPONENT-569TANGUT " +
"COMPONENT-570TANGUT COMPONENT-571TANGUT COMPONENT-572TANGUT COMPONENT-57" +
"3TANGUT COMPONENT-574TANGUT COMPONENT-575TANGUT COMPONENT-576TANGUT COMP" +
"ONENT-577TANGUT COMPONENT-578TANGUT COMPONENT-579TANGUT COMPONENT-580TAN" +
"GUT COMPONENT-581TANGUT COMPONENT-582TANGUT COMPONENT-583TANGUT COMPONEN" +
"T-584TANGUT COMPONENT-585TANGUT COMPONENT-586TANGUT COMPONENT-587TANGUT " +
"COMPONENT-588TANGUT COMPONENT-589TANGUT COMPONENT-590TANGUT COMPONENT-59" +
"1TANGUT COMPONENT-592TANGUT COMPONENT-593TANGUT COMPONENT-594TANGUT COMP" +
"ONENT-595TANGUT COMPONENT-596TANGUT COMPONENT-597TANGUT COMPONENT-598TAN" +
"GUT COMPONENT-599TANGUT COMPONENT-600TANGUT COMPONENT-601TANGUT COMPONEN" +
"T-602TANGUT COMPONENT-603TANGUT COMPONENT-604TANGUT COMPONENT-605TANGUT " +
"COMPONENT-606TANGUT COMPONENT-607TANGUT COMPONENT-608TANGUT COMPONENT-60" +
"9TANGUT COMPONENT-610TANGUT COMPONENT-611TANGUT COMPONENT-612TANGUT COMP" +
"ONENT-613TANGUT COMPONENT-614TANGUT COMPONENT-615TANGUT COMPONENT-616TAN" +
"GUT COMPONENT-617TANGUT COMPONENT-618TANGUT COMPONENT-619TANGUT COMPONEN" +
"T-620TANGUT COMPONENT-621TANGUT COMPONENT-622TANGUT COMPONENT-623TANGUT " +
"COMPONENT-624TANGUT COMPONENT-625TANGUT COMPONENT-626TANGUT COMPONENT-62" +
"7TANGUT COMPONENT-628TANGUT COMPONENT-629TANGUT COMPONENT-630TANGUT COMP" +
"ONENT-631TANGUT COMPONENT-632TANGUT COMPONENT-633TANGUT COMPONENT-634TAN" +
"GUT COMPONENT-635TANGUT COMPONENT-636TANGUT COMPONENT-637TANGUT COMPONEN" +
"T-638TANGUT COMPONENT-639TANGUT COMPONENT-640TANGUT COMPONENT-641TANGUT " +
"COMPONENT-642TANGUT COMPONENT-643TANGUT COMPONENT-644TANGUT COMPONENT-64" +
"5TANGUT COMPONENT-646TANGUT COMPONENT-647TANGUT COMPONENT-648TANGUT COMP" +
"ONENT-649TANGUT COMPONENT-650TANGUT COMPONENT-651TANGUT COMPONENT-652TAN" +
"GUT COMPONENT-653TANGUT COMPONENT-654TANGUT COMPONENT-655TANGUT COMPONEN" +
"T-656TANGUT COMPONENT-657TANGUT COMPONENT-658TANGUT COMPONENT-659TANGUT " +
"COMPONENT-660TANGUT COMPONENT-661TANGUT COMPONENT-662TANGUT COMPONENT-66" +
"3TANGUT COMPONENT-664TANGUT COMPONENT-665TANGUT COMPONENT-666TANGUT COMP" +
"ONENT-667TANGUT COMPONENT-668TANGUT COMPONENT-669TANGUT COMPONENT-670TAN" +
"GUT COMPONENT-671TANGUT COMPONENT-672TANGUT COMPONENT-673TANGUT COMPONEN" +
"T-674TANGUT COMPONENT-675TANGUT COMPONENT-676TANGUT COMPONENT-677TANGUT " +
"COMPONENT-678TANGUT COMPONENT-679TANGUT COMPONENT-680TANGUT COMPONENT-68" +
"1TANGUT COMPONENT-682TANGUT COMPONENT-683TANGUT COMPONENT-684TANGUT COMP" +
"ONENT-685TANGUT COMPONENT-686TANGUT COMPONENT-687TANGUT COMPONENT-688TAN" +
"GUT COMPONENT-689TANGUT COMPONENT-690TANGUT COMPONENT-691TANGUT COMPONEN" +
"T-692TANGUT COMPONENT-693TANGUT COMPONENT-694TANGUT COMPONENT-695TANGUT " +
"COMPONENT-696TANGUT COMPONENT-697TANGUT COMPONENT-698TANGUT COMPONENT-69" +
"9TANGUT COMPONENT-700TANGUT COMPONENT-701TANGUT COMPONENT-702TANGUT COMP" +
"ONENT-703TANGUT COMPONENT-704TANGUT COMPONENT-705TANGUT COMPONENT-706TAN" +
"GUT COMPONENT-707TANGUT COMPONENT-708TANGUT COMPONENT-709TANGUT COMPONEN" +
"T-710TANGUT COMPONENT-711TANGUT COMPONENT-712TANGUT COMPONENT-713TANGUT " +
"COMPONENT-714TANGUT COMPONENT-715TANGUT COMPONENT-716TANGUT COMPONENT-71" +
"7TANGUT COMPONENT-718TANGUT COMPONENT-719TANGUT COMPONENT-720TANGUT COMP" +
"ONENT-721TANGUT COMPONENT-722TANGUT COMPONENT-723TANGUT COMPONENT-724TAN" +
"GUT COMPONENT-725TANGUT COMPONENT-726TANGUT COMPONENT-727TANGUT COMPONEN" +
"T-728TANGUT COMPONENT-729TANGUT COMPONENT-730TANGUT COMPONENT-731TANGUT " +
"COMPONENT-732TANGUT COMPONENT-733TANGUT COMPONENT-734TANGUT COMPONENT-73" +
"5TANGUT COMPONENT-736TANGUT COMPONENT-737TANGUT COMPONENT-738TANGUT COMP" +
"ONENT-739TANGUT COMPONENT-740TANGUT COMPONENT-741TANGUT COMPONENT-742TAN" +
"GUT COMPONENT-743TANGUT COMPONENT-744TANGUT COMPONENT-745TANGUT COMPONEN" +
"T-746TANGUT COMPONENT-747TANGUT COMPONENT-748TANGUT COMPONENT-749TANGUT " +
"COMPONENT-750TANGUT COMPONENT-751TANGUT COMPONENT-752TANGUT COMPONENT-75" +
"3TANGUT COMPONENT-754TANGUT COMPONENT-755TANGUT COMPONENT-756TANGUT COMP" +
"ONENT-757TANGUT COMPONENT-758TANGUT COMPONENT-759TANGUT COMPONENT-760TAN" +
"GUT COMPONENT-761TANGUT COMPONENT-762TANGUT COMPONENT-763TANGUT COMPONEN" +
"T-764TANGUT COMPONENT-765TANGUT COMPONENT-766TANGUT COMPONENT-767TANGUT " +
"COMPONENT-768KHITAN SMALL SCRIPT CHARACTER-18B00KHITAN SMALL SCRIPT CHAR" +
"ACTER-18B01KHITAN SMALL SCRIPT CHARACTER-18B02KHITAN SMALL SCRIPT CHARAC" +
"TER-18B03KHITAN SMALL SCRIPT CHARACTER-18B04KHITAN SMALL SCRIPT CHARACTE" +
"R-18B05KHITAN SMALL SCRIPT CHARACTER-18B06KHITAN SMALL SCRIPT CHARACTER-") + ("" +
"18B07KHITAN SMALL SCRIPT CHARACTER-18B08KHITAN SMALL SCRIPT CHARACTER-18" +
"B09KHITAN SMALL SCRIPT CHARACTER-18B0AKHITAN SMALL SCRIPT CHARACTER-18B0" +
"BKHITAN SMALL SCRIPT CHARACTER-18B0CKHITAN SMALL SCRIPT CHARACTER-18B0DK" +
"HITAN SMALL SCRIPT CHARACTER-18B0EKHITAN SMALL SCRIPT CHARACTER-18B0FKHI" +
"TAN SMALL SCRIPT CHARACTER-18B10KHITAN SMALL SCRIPT CHARACTER-18B11KHITA" +
"N SMALL SCRIPT CHARACTER-18B12KHITAN SMALL SCRIPT CHARACTER-18B13KHITAN " +
"SMALL SCRIPT CHARACTER-18B14KHITAN SMALL SCRIPT CHARACTER-18B15KHITAN SM" +
"ALL SCRIPT CHARACTER-18B16KHITAN SMALL SCRIPT CHARACTER-18B17KHITAN SMAL" +
"L SCRIPT CHARACTER-18B18KHITAN SMALL SCRIPT CHARACTER-18B19KHITAN SMALL " +
"SCRIPT CHARACTER-18B1AKHITAN SMALL SCRIPT CHARACTER-18B1BKHITAN SMALL SC" +
"RIPT CHARACTER-18B1CKHITAN SMALL SCRIPT CHARACTER-18B1DKHITAN SMALL SCRI" +
"PT CHARACTER-18B1EKHITAN SMALL SCRIPT CHARACTER-18B1FKHITAN SMALL SCRIPT" +
" CHARACTER-18B20KHITAN SMALL SCRIPT CHARACTER-18B21KHITAN SMALL SCRIPT C" +
"HARACTER-18B22KHITAN SMALL SCRIPT CHARACTER-18B23KHITAN SMALL SCRIPT CHA" +
"RACTER-18B24KHITAN SMALL SCRIPT CHARACTER-18B25KHITAN SMALL SCRIPT CHARA" +
"CTER-18B26KHITAN SMALL SCRIPT CHARACTER-18B27KHITAN SMALL SCRIPT CHARACT" +
"ER-18B28KHITAN SMALL SCRIPT CHARACTER-18B29KHITAN SMALL SCRIPT CHARACTER" +
"-18B2AKHITAN SMALL SCRIPT CHARACTER-18B2BKHITAN SMALL SCRIPT CHARACTER-1" +
"8B2CKHITAN SMALL SCRIPT CHARACTER-18B2DKHITAN SMALL SCRIPT CHARACTER-18B" +
"2EKHITAN SMALL SCRIPT CHARACTER-18B2FKHITAN SMALL SCRIPT CHARACTER-18B30" +
"KHITAN SMALL SCRIPT CHARACTER-18B31KHITAN SMALL SCRIPT CHARACTER-18B32KH" +
"ITAN SMALL SCRIPT CHARACTER-18B33KHITAN SMALL SCRIPT CHARACTER-18B34KHIT" +
"AN SMALL SCRIPT CHARACTER-18B35KHITAN SMALL SCRIPT CHARACTER-18B36KHITAN" +
" SMALL SCRIPT CHARACTER-18B37KHITAN SMALL SCRIPT CHARACTER-18B38KHITAN S" +
"MALL SCRIPT CHARACTER-18B39KHITAN SMALL SCRIPT CHARACTER-18B3AKHITAN SMA" +
"LL SCRIPT CHARACTER-18B3BKHITAN SMALL SCRIPT CHARACTER-18B3CKHITAN SMALL" +
" SCRIPT CHARACTER-18B3DKHITAN SMALL SCRIPT CHARACTER-18B3EKHITAN SMALL S" +
"CRIPT CHARACTER-18B3FKHITAN SMALL SCRIPT CHARACTER-18B40KHITAN SMALL SCR" +
"IPT CHARACTER-18B41KHITAN SMALL SCRIPT CHARACTER-18B42KHITAN SMALL SCRIP" +
"T CHARACTER-18B43KHITAN SMALL SCRIPT CHARACTER-18B44KHITAN SMALL SCRIPT " +
"CHARACTER-18B45KHITAN SMALL SCRIPT CHARACTER-18B46KHITAN SMALL SCRIPT CH" +
"ARACTER-18B47KHITAN SMALL SCRIPT CHARACTER-18B48KHITAN SMALL SCRIPT CHAR" +
"ACTER-18B49KHITAN SMALL SCRIPT CHARACTER-18B4AKHITAN SMALL SCRIPT CHARAC" +
"TER-18B4BKHITAN SMALL SCRIPT CHARACTER-18B4CKHITAN SMALL SCRIPT CHARACTE" +
"R-18B4DKHITAN SMALL SCRIPT CHARACTER-18B4EKHITAN SMALL SCRIPT CHARACTER-" +
"18B4FKHITAN SMALL SCRIPT CHARACTER-18B50KHITAN SMALL SCRIPT CHARACTER-18" +
"B51KHITAN SMALL SCRIPT CHARACTER-18B52KHITAN SMALL SCRIPT CHARACTER-18B5" +
"3KHITAN SMALL SCRIPT CHARACTER-18B54KHITAN SMALL SCRIPT CHARACTER-18B55K" +
"HITAN SMALL SCRIPT CHARACTER-18B56KHITAN SMALL SCRIPT CHARACTER-18B57KHI" +
"TAN SMALL SCRIPT CHARACTER-18B58KHITAN SMALL SCRIPT CHARACTER-18B59KHITA" +
"N SMALL SCRIPT CHARACTER-18B5AKHITAN SMALL SCRIPT CHARACTER-18B5BKHITAN " +
"SMALL SCRIPT CHARACTER-18B5CKHITAN SMALL SCRIPT CHARACTER-18B5DKHITAN SM" +
"ALL SCRIPT CHARACTER-18B5EKHITAN SMALL SCRIPT CHARACTER-18B5FKHITAN SMAL" +
"L SCRIPT CHARACTER-18B60KHITAN SMALL SCRIPT CHARACTER-18B61KHITAN SMALL " +
"SCRIPT CHARACTER-18B62KHITAN SMALL SCRIPT CHARACTER-18B63KHITAN SMALL SC" +
"RIPT CHARACTER-18B64KHITAN SMALL SCRIPT CHARACTER-18B65KHITAN SMALL SCRI" +
"PT CHARACTER-18B66KHITAN SMALL SCRIPT CHARACTER-18B67KHITAN SMALL SCRIPT" +
" CHARACTER-18B68KHITAN SMALL SCRIPT CHARACTER-18B69KHITAN SMALL SCRIPT C" +
"HARACTER-18B6AKHITAN SMALL SCRIPT CHARACTER-18B6BKHITAN SMALL SCRIPT CHA" +
"RACTER-18B6CKHITAN SMALL SCRIPT CHARACTER-18B6DKHITAN SMALL SCRIPT CHARA" +
"CTER-18B6EKHITAN SMALL SCRIPT CHARACTER-18B6FKHITAN SMALL SCRIPT CHARACT" +
"ER-18B70KHITAN SMALL SCRIPT CHARACTER-18B71KHITAN SMALL SCRIPT CHARACTER" +
"-18B72KHITAN SMALL SCRIPT CHARACTER-18B73KHITAN SMALL SCRIPT CHARACTER-1" +
"8B74KHITAN SMALL SCRIPT CHARACTER-18B75KHITAN SMALL SCRIPT CHARACTER-18B" +
"76KHITAN SMALL SCRIPT CHARACTER-18B77KHITAN SMALL SCRIPT CHARACTER-18B78" +
"KHITAN SMALL SCRIPT CHARACTER-18B79KHITAN SMALL SCRIPT CHARACTER-18B7AKH" +
"ITAN SMALL SCRIPT CHARACTER-18B7BKHITAN SMALL SCRIPT CHARACTER-18B7CKHIT" +
"AN SMALL SCRIPT CHARACTER-18B7DKHITAN SMALL SCRIPT CHARACTER-18B7EKHITAN" +
" SMALL SCRIPT CHARACTER-18B7FKHITAN SMALL SCRIPT CHARACTER-18B80KHITAN S" +
"MALL SCRIPT CHARACTER-18B81KHITAN SMALL SCRIPT CHARACTER-18B82KHITAN SMA" +
"LL SCRIPT CHARACTER-18B83KHITAN SMALL SCRIPT CHARACTER-18B84KHITAN SMALL" +
" SCRIPT CHARACTER-18B85KHITAN SMALL SCRIPT CHARACTER-18B86KHITAN SMALL S" +
"CRIPT CHARACTER-18B87KHITAN SMALL SCRIPT CHARACTER-18B88KHITAN SMALL SCR" +
"IPT CHARACTER-18B89KHITAN SMALL SCRIPT CHARACTER-18B8AKHITAN SMALL SCRIP") + ("" +
"T CHARACTER-18B8BKHITAN SMALL SCRIPT CHARACTER-18B8CKHITAN SMALL SCRIPT " +
"CHARACTER-18B8DKHITAN SMALL SCRIPT CHARACTER-18B8EKHITAN SMALL SCRIPT CH" +
"ARACTER-18B8FKHITAN SMALL SCRIPT CHARACTER-18B90KHITAN SMALL SCRIPT CHAR" +
"ACTER-18B91KHITAN SMALL SCRIPT CHARACTER-18B92KHITAN SMALL SCRIPT CHARAC" +
"TER-18B93KHITAN SMALL SCRIPT CHARACTER-18B94KHITAN SMALL SCRIPT CHARACTE" +
"R-18B95KHITAN SMALL SCRIPT CHARACTER-18B96KHITAN SMALL SCRIPT CHARACTER-" +
"18B97KHITAN SMALL SCRIPT CHARACTER-18B98KHITAN SMALL SCRIPT CHARACTER-18" +
"B99KHITAN SMALL SCRIPT CHARACTER-18B9AKHITAN SMALL SCRIPT CHARACTER-18B9" +
"BKHITAN SMALL SCRIPT CHARACTER-18B9CKHITAN SMALL SCRIPT CHARACTER-18B9DK" +
"HITAN SMALL SCRIPT CHARACTER-18B9EKHITAN SMALL SCRIPT CHARACTER-18B9FKHI" +
"TAN SMALL SCRIPT CHARACTER-18BA0KHITAN SMALL SCRIPT CHARACTER-18BA1KHITA" +
"N SMALL SCRIPT CHARACTER-18BA2KHITAN SMALL SCRIPT CHARACTER-18BA3KHITAN " +
"SMALL SCRIPT CHARACTER-18BA4KHITAN SMALL SCRIPT CHARACTER-18BA5KHITAN SM" +
"ALL SCRIPT CHARACTER-18BA6KHITAN SMALL SCRIPT CHARACTER-18BA7KHITAN SMAL" +
"L SCRIPT CHARACTER-18BA8KHITAN SMALL SCRIPT CHARACTER-18BA9KHITAN SMALL " +
"SCRIPT CHARACTER-18BAAKHITAN SMALL SCRIPT CHARACTER-18BABKHITAN SMALL SC" +
"RIPT CHARACTER-18BACKHITAN SMALL SCRIPT CHARACTER-18BADKHITAN SMALL SCRI" +
"PT CHARACTER-18BAEKHITAN SMALL SCRIPT CHARACTER-18BAFKHITAN SMALL SCRIPT" +
" CHARACTER-18BB0KHITAN SMALL SCRIPT CHARACTER-18BB1KHITAN SMALL SCRIPT C" +
"HARACTER-18BB2KHITAN SMALL SCRIPT CHARACTER-18BB3KHITAN SMALL SCRIPT CHA" +
"RACTER-18BB4KHITAN SMALL SCRIPT CHARACTER-18BB5KHITAN SMALL SCRIPT CHARA" +
"CTER-18BB6KHITAN SMALL SCRIPT CHARACTER-18BB7KHITAN SMALL SCRIPT CHARACT" +
"ER-18BB8KHITAN SMALL SCRIPT CHARACTER-18BB9KHITAN SMALL SCRIPT CHARACTER" +
"-18BBAKHITAN SMALL SCRIPT CHARACTER-18BBBKHITAN SMALL SCRIPT CHARACTER-1" +
"8BBCKHITAN SMALL SCRIPT CHARACTER-18BBDKHITAN SMALL SCRIPT CHARACTER-18B" +
"BEKHITAN SMALL SCRIPT CHARACTER-18BBFKHITAN SMALL SCRIPT CHARACTER-18BC0" +
"KHITAN SMALL SCRIPT CHARACTER-18BC1KHITAN SMALL SCRIPT CHARACTER-18BC2KH" +
"ITAN SMALL SCRIPT CHARACTER-18BC3KHITAN SMALL SCRIPT CHARACTER-18BC4KHIT" +
"AN SMALL SCRIPT CHARACTER-18BC5KHITAN SMALL SCRIPT CHARACTER-18BC6KHITAN" +
" SMALL SCRIPT CHARACTER-18BC7KHITAN SMALL SCRIPT CHARACTER-18BC8KHITAN S" +
"MALL SCRIPT CHARACTER-18BC9KHITAN SMALL SCRIPT CHARACTER-18BCAKHITAN SMA" +
"LL SCRIPT CHARACTER-18BCBKHITAN SMALL SCRIPT CHARACTER-18BCCKHITAN SMALL" +
" SCRIPT CHARACTER-18BCDKHITAN SMALL SCRIPT CHARACTER-18BCEKHITAN SMALL S" +
"CRIPT CHARACTER-18BCFKHITAN SMALL SCRIPT CHARACTER-18BD0KHITAN SMALL SCR" +
"IPT CHARACTER-18BD1KHITAN SMALL SCRIPT CHARACTER-18BD2KHITAN SMALL SCRIP" +
"T CHARACTER-18BD3KHITAN SMALL SCRIPT CHARACTER-18BD4KHITAN SMALL SCRIPT " +
"CHARACTER-18BD5KHITAN SMALL SCRIPT CHARACTER-18BD6KHITAN SMALL SCRIPT CH" +
"ARACTER-18BD7KHITAN SMALL SCRIPT CHARACTER-18BD8KHITAN SMALL SCRIPT CHAR" +
"ACTER-18BD9KHITAN SMALL SCRIPT CHARACTER-18BDAKHITAN SMALL SCRIPT CHARAC" +
"TER-18BDBKHITAN SMALL SCRIPT CHARACTER-18BDCKHITAN SMALL SCRIPT CHARACTE" +
"R-18BDDKHITAN SMALL SCRIPT CHARACTER-18BDEKHITAN SMALL SCRIPT CHARACTER-" +
"18BDFKHITAN SMALL SCRIPT CHARACTER-18BE0KHITAN SMALL SCRIPT CHARACTER-18" +
"BE1KHITAN SMALL SCRIPT CHARACTER-18BE2KHITAN SMALL SCRIPT CHARACTER-18BE" +
"3KHITAN SMALL SCRIPT CHARACTER-18BE4KHITAN SMALL SCRIPT CHARACTER-18BE5K" +
"HITAN SMALL SCRIPT CHARACTER-18BE6KHITAN SMALL SCRIPT CHARACTER-18BE7KHI" +
"TAN SMALL SCRIPT CHARACTER-18BE8KHITAN SMALL SCRIPT CHARACTER-18BE9KHITA" +
"N SMALL SCRIPT CHARACTER-18BEAKHITAN SMALL SCRIPT CHARACTER-18BEBKHITAN " +
"SMALL SCRIPT CHARACTER-18BECKHITAN SMALL SCRIPT CHARACTER-18BEDKHITAN SM" +
"ALL SCRIPT CHARACTER-18BEEKHITAN SMALL SCRIPT CHARACTER-18BEFKHITAN SMAL" +
"L SCRIPT CHARACTER-18BF0KHITAN SMALL SCRIPT CHARACTER-18BF1KHITAN SMALL " +
"SCRIPT CHARACTER-18BF2KHITAN SMALL SCRIPT CHARACTER-18BF3KHITAN SMALL SC" +
"RIPT CHARACTER-18BF4KHITAN SMALL SCRIPT CHARACTER-18BF5KHITAN SMALL SCRI" +
"PT CHARACTER-18BF6KHITAN SMALL SCRIPT CHARACTER-18BF7KHITAN SMALL SCRIPT" +
" CHARACTER-18BF8KHITAN SMALL SCRIPT CHARACTER-18BF9KHITAN SMALL SCRIPT C" +
"HARACTER-18BFAKHITAN SMALL SCRIPT CHARACTER-18BFBKHITAN SMALL SCRIPT CHA" +
"RACTER-18BFCKHITAN SMALL SCRIPT CHARACTER-18BFDKHITAN SMALL SCRIPT CHARA" +
"CTER-18BFEKHITAN SMALL SCRIPT CHARACTER-18BFFKHITAN SMALL SCRIPT CHARACT" +
"ER-18C00KHITAN SMALL SCRIPT CHARACTER-18C01KHITAN SMALL SCRIPT CHARACTER" +
"-18C02KHITAN SMALL SCRIPT CHARACTER-18C03KHITAN SMALL SCRIPT CHARACTER-1" +
"8C04KHITAN SMALL SCRIPT CHARACTER-18C05KHITAN SMALL SCRIPT CHARACTER-18C" +
"06KHITAN SMALL SCRIPT CHARACTER-18C07KHITAN SMALL SCRIPT CHARACTER-18C08" +
"KHITAN SMALL SCRIPT CHARACTER-18C09KHITAN SMALL SCRIPT CHARACTER-18C0AKH" +
"ITAN SMALL SCRIPT CHARACTER-18C0BKHITAN SMALL SCRIPT CHARACTER-18C0CKHIT" +
"AN SMALL SCRIPT CHARACTER-18C0DKHITAN SMALL SCRIPT CHARACTER-18C0EKHITAN") + ("" +
" SMALL SCRIPT CHARACTER-18C0FKHITAN SMALL SCRIPT CHARACTER-18C10KHITAN S" +
"MALL SCRIPT CHARACTER-18C11KHITAN SMALL SCRIPT CHARACTER-18C12KHITAN SMA" +
"LL SCRIPT CHARACTER-18C13KHITAN SMALL SCRIPT CHARACTER-18C14KHITAN SMALL" +
" SCRIPT CHARACTER-18C15KHITAN SMALL SCRIPT CHARACTER-18C16KHITAN SMALL S" +
"CRIPT CHARACTER-18C17KHITAN SMALL SCRIPT CHARACTER-18C18KHITAN SMALL SCR" +
"IPT CHARACTER-18C19KHITAN SMALL SCRIPT CHARACTER-18C1AKHITAN SMALL SCRIP" +
"T CHARACTER-18C1BKHITAN SMALL SCRIPT CHARACTER-18C1CKHITAN SMALL SCRIPT " +
"CHARACTER-18C1DKHITAN SMALL SCRIPT CHARACTER-18C1EKHITAN SMALL SCRIPT CH" +
"ARACTER-18C1FKHITAN SMALL SCRIPT CHARACTER-18C20KHITAN SMALL SCRIPT CHAR" +
"ACTER-18C21KHITAN SMALL SCRIPT CHARACTER-18C22KHITAN SMALL SCRIPT CHARAC" +
"TER-18C23KHITAN SMALL SCRIPT CHARACTER-18C24KHITAN SMALL SCRIPT CHARACTE" +
"R-18C25KHITAN SMALL SCRIPT CHARACTER-18C26KHITAN SMALL SCRIPT CHARACTER-" +
"18C27KHITAN SMALL SCRIPT CHARACTER-18C28KHITAN SMALL SCRIPT CHARACTER-18" +
"C29KHITAN SMALL SCRIPT CHARACTER-18C2AKHITAN SMALL SCRIPT CHARACTER-18C2" +
"BKHITAN SMALL SCRIPT CHARACTER-18C2CKHITAN SMALL SCRIPT CHARACTER-18C2DK" +
"HITAN SMALL SCRIPT CHARACTER-18C2EKHITAN SMALL SCRIPT CHARACTER-18C2FKHI" +
"TAN SMALL SCRIPT CHARACTER-18C30KHITAN SMALL SCRIPT CHARACTER-18C31KHITA" +
"N SMALL SCRIPT CHARACTER-18C32KHITAN SMALL SCRIPT CHARACTER-18C33KHITAN " +
"SMALL SCRIPT CHARACTER-18C34KHITAN SMALL SCRIPT CHARACTER-18C35KHITAN SM" +
"ALL SCRIPT CHARACTER-18C36KHITAN SMALL SCRIPT CHARACTER-18C37KHITAN SMAL" +
"L SCRIPT CHARACTER-18C38KHITAN SMALL SCRIPT CHARACTER-18C39KHITAN SMALL " +
"SCRIPT CHARACTER-18C3AKHITAN SMALL SCRIPT CHARACTER-18C3BKHITAN SMALL SC" +
"RIPT CHARACTER-18C3CKHITAN SMALL SCRIPT CHARACTER-18C3DKHITAN SMALL SCRI" +
"PT CHARACTER-18C3EKHITAN SMALL SCRIPT CHARACTER-18C3FKHITAN SMALL SCRIPT" +
" CHARACTER-18C40KHITAN SMALL SCRIPT CHARACTER-18C41KHITAN SMALL SCRIPT C" +
"HARACTER-18C42KHITAN SMALL SCRIPT CHARACTER-18C43KHITAN SMALL SCRIPT CHA" +
"RACTER-18C44KHITAN SMALL SCRIPT CHARACTER-18C45KHITAN SMALL SCRIPT CHARA" +
"CTER-18C46KHITAN SMALL SCRIPT CHARACTER-18C47KHITAN SMALL SCRIPT CHARACT" +
"ER-18C48KHITAN SMALL SCRIPT CHARACTER-18C49KHITAN SMALL SCRIPT CHARACTER" +
"-18C4AKHITAN SMALL SCRIPT CHARACTER-18C4BKHITAN SMALL SCRIPT CHARACTER-1" +
"8C4CKHITAN SMALL SCRIPT CHARACTER-18C4DKHITAN SMALL SCRIPT CHARACTER-18C" +
"4EKHITAN SMALL SCRIPT CHARACTER-18C4FKHITAN SMALL SCRIPT CHARACTER-18C50" +
"KHITAN SMALL SCRIPT CHARACTER-18C51KHITAN SMALL SCRIPT CHARACTER-18C52KH" +
"ITAN SMALL SCRIPT CHARACTER-18C53KHITAN SMALL SCRIPT CHARACTER-18C54KHIT" +
"AN SMALL SCRIPT CHARACTER-18C55KHITAN SMALL SCRIPT CHARACTER-18C56KHITAN" +
" SMALL SCRIPT CHARACTER-18C57KHITAN SMALL SCRIPT CHARACTER-18C58KHITAN S" +
"MALL SCRIPT CHARACTER-18C59KHITAN SMALL SCRIPT CHARACTER-18C5AKHITAN SMA" +
"LL SCRIPT CHARACTER-18C5BKHITAN SMALL SCRIPT CHARACTER-18C5CKHITAN SMALL" +
" SCRIPT CHARACTER-18C5DKHITAN SMALL SCRIPT CHARACTER-18C5EKHITAN SMALL S" +
"CRIPT CHARACTER-18C5FKHITAN SMALL SCRIPT CHARACTER-18C60KHITAN SMALL SCR" +
"IPT CHARACTER-18C61KHITAN SMALL SCRIPT CHARACTER-18C62KHITAN SMALL SCRIP" +
"T CHARACTER-18C63KHITAN SMALL SCRIPT CHARACTER-18C64KHITAN SMALL SCRIPT " +
"CHARACTER-18C65KHITAN SMALL SCRIPT CHARACTER-18C66KHITAN SMALL SCRIPT CH" +
"ARACTER-18C67KHITAN SMALL SCRIPT CHARACTER-18C68KHITAN SMALL SCRIPT CHAR" +
"ACTER-18C69KHITAN SMALL SCRIPT CHARACTER-18C6AKHITAN SMALL SCRIPT CHARAC" +
"TER-18C6BKHITAN SMALL SCRIPT CHARACTER-18C6CKHITAN SMALL SCRIPT CHARACTE" +
"R-18C6DKHITAN SMALL SCRIPT CHARACTER-18C6EKHITAN SMALL SCRIPT CHARACTER-" +
"18C6FKHITAN SMALL SCRIPT CHARACTER-18C70KHITAN SMALL SCRIPT CHARACTER-18" +
"C71KHITAN SMALL SCRIPT CHARACTER-18C72KHITAN SMALL SCRIPT CHARACTER-18C7" +
"3KHITAN SMALL SCRIPT CHARACTER-18C74KHITAN SMALL SCRIPT CHARACTER-18C75K" +
"HITAN SMALL SCRIPT CHARACTER-18C76KHITAN SMALL SCRIPT CHARACTER-18C77KHI" +
"TAN SMALL SCRIPT CHARACTER-18C78KHITAN SMALL SCRIPT CHARACTER-18C79KHITA" +
"N SMALL SCRIPT CHARACTER-18C7AKHITAN SMALL SCRIPT CHARACTER-18C7BKHITAN " +
"SMALL SCRIPT CHARACTER-18C7CKHITAN SMALL SCRIPT CHARACTER-18C7DKHITAN SM" +
"ALL SCRIPT CHARACTER-18C7EKHITAN SMALL SCRIPT CHARACTER-18C7FKHITAN SMAL" +
"L SCRIPT CHARACTER-18C80KHITAN SMALL SCRIPT CHARACTER-18C81KHITAN SMALL " +
"SCRIPT CHARACTER-18C82KHITAN SMALL SCRIPT CHARACTER-18C83KHITAN SMALL SC" +
"RIPT CHARACTER-18C84KHITAN SMALL SCRIPT CHARACTER-18C85KHITAN SMALL SCRI" +
"PT CHARACTER-18C86KHITAN SMALL SCRIPT CHARACTER-18C87KHITAN SMALL SCRIPT" +
" CHARACTER-18C88KHITAN SMALL SCRIPT CHARACTER-18C89KHITAN SMALL SCRIPT C" +
"HARACTER-18C8AKHITAN SMALL SCRIPT CHARACTER-18C8BKHITAN SMALL SCRIPT CHA" +
"RACTER-18C8CKHITAN SMALL SCRIPT CHARACTER-18C8DKHITAN SMALL SCRIPT CHARA" +
"CTER-18C8EKHITAN SMALL SCRIPT CHARACTER-18C8FKHITAN SMALL SCRIPT CHARACT" +
"ER-18C90KHITAN SMALL SCRIPT CHARACTER-18C91KHITAN SMALL SCRIPT CHARACTER") + ("" +
"-18C92KHITAN SMALL SCRIPT CHARACTER-18C93KHITAN SMALL SCRIPT CHARACTER-1" +
"8C94KHITAN SMALL SCRIPT CHARACTER-18C95KHITAN SMALL SCRIPT CHARACTER-18C" +
"96KHITAN SMALL SCRIPT CHARACTER-18C97KHITAN SMALL SCRIPT CHARACTER-18C98" +
"KHITAN SMALL SCRIPT CHARACTER-18C99KHITAN SMALL SCRIPT CHARACTER-18C9AKH" +
"ITAN SMALL SCRIPT CHARACTER-18C9BKHITAN SMALL SCRIPT CHARACTER-18C9CKHIT" +
"AN SMALL SCRIPT CHARACTER-18C9DKHITAN SMALL SCRIPT CHARACTER-18C9EKHITAN" +
" SMALL SCRIPT CHARACTER-18C9FKHITAN SMALL SCRIPT CHARACTER-18CA0KHITAN S" +
"MALL SCRIPT CHARACTER-18CA1KHITAN SMALL SCRIPT CHARACTER-18CA2KHITAN SMA" +
"LL SCRIPT CHARACTER-18CA3KHITAN SMALL SCRIPT CHARACTER-18CA4KHITAN SMALL" +
" SCRIPT CHARACTER-18CA5KHITAN SMALL SCRIPT CHARACTER-18CA6KHITAN SMALL S" +
"CRIPT CHARACTER-18CA7KHITAN SMALL SCRIPT CHARACTER-18CA8KHITAN SMALL SCR" +
"IPT CHARACTER-18CA9KHITAN SMALL SCRIPT CHARACTER-18CAAKHITAN SMALL SCRIP" +
"T CHARACTER-18CABKHITAN SMALL SCRIPT CHARACTER-18CACKHITAN SMALL SCRIPT " +
"CHARACTER-18CADKHITAN SMALL SCRIPT CHARACTER-18CAEKHITAN SMALL SCRIPT CH" +
"ARACTER-18CAFKHITAN SMALL SCRIPT CHARACTER-18CB0KHITAN SMALL SCRIPT CHAR" +
"ACTER-18CB1KHITAN SMALL SCRIPT CHARACTER-18CB2KHITAN SMALL SCRIPT CHARAC" +
"TER-18CB3KHITAN SMALL SCRIPT CHARACTER-18CB4KHITAN SMALL SCRIPT CHARACTE" +
"R-18CB5KHITAN SMALL SCRIPT CHARACTER-18CB6KHITAN SMALL SCRIPT CHARACTER-" +
"18CB7KHITAN SMALL SCRIPT CHARACTER-18CB8KHITAN SMALL SCRIPT CHARACTER-18" +
"CB9KHITAN SMALL SCRIPT CHARACTER-18CBAKHITAN SMALL SCRIPT CHARACTER-18CB" +
"BKHITAN SMALL SCRIPT CHARACTER-18CBCKHITAN SMALL SCRIPT CHARACTER-18CBDK" +
"HITAN SMALL SCRIPT CHARACTER-18CBEKHITAN SMALL SCRIPT CHARACTER-18CBFKHI" +
"TAN SMALL SCRIPT CHARACTER-18CC0KHITAN SMALL SCRIPT CHARACTER-18CC1KHITA" +
"N SMALL SCRIPT CHARACTER-18CC2KHITAN SMALL SCRIPT CHARACTER-18CC3KHITAN " +
"SMALL SCRIPT CHARACTER-18CC4KHITAN SMALL SCRIPT CHARACTER-18CC5KHITAN SM" +
"ALL SCRIPT CHARACTER-18CC6KHITAN SMALL SCRIPT CHARACTER-18CC7KHITAN SMAL" +
"L SCRIPT CHARACTER-18CC8KHITAN SMALL SCRIPT CHARACTER-18CC9KHITAN SMALL " +
"SCRIPT CHARACTER-18CCAKHITAN SMALL SCRIPT CHARACTER-18CCBKHITAN SMALL SC" +
"RIPT CHARACTER-18CCCKHITAN SMALL SCRIPT CHARACTER-18CCDKHITAN SMALL SCRI" +
"PT CHARACTER-18CCEKHITAN SMALL SCRIPT CHARACTER-18CCFKHITAN SMALL SCRIPT" +
" CHARACTER-18CD0KHITAN SMALL SCRIPT CHARACTER-18CD1KHITAN SMALL SCRIPT C" +
"HARACTER-18CD2KHITAN SMALL SCRIPT CHARACTER-18CD3KHITAN SMALL SCRIPT CHA" +
"RACTER-18CD4KHITAN SMALL SCRIPT CHARACTER-18CD5KATAKANA LETTER MINNAN TO" +
"NE-2KATAKANA LETTER MINNAN TONE-3KATAKANA LETTER MINNAN TONE-4KATAKANA L" +
"ETTER MINNAN TONE-5KATAKANA LETTER MINNAN TONE-7KATAKANA LETTER MINNAN T" +
"ONE-8KATAKANA LETTER MINNAN NASALIZED TONE-1KATAKANA LETTER MINNAN NASAL" +
"IZED TONE-2KATAKANA LETTER MINNAN NASALIZED TONE-3KATAKANA LETTER MINNAN" +
" NASALIZED TONE-4KATAKANA LETTER MINNAN NASALIZED TONE-5KATAKANA LETTER " +
"MINNAN NASALIZED TONE-7KATAKANA LETTER MINNAN NASALIZED TONE-8KATAKANA L" +
"ETTER ARCHAIC EHIRAGANA LETTER ARCHAIC YEHENTAIGANA LETTER A-1HENTAIGANA" +
" LETTER A-2HENTAIGANA LETTER A-3HENTAIGANA LETTER A-WOHENTAIGANA LETTER " +
"I-1HENTAIGANA LETTER I-2HENTAIGANA LETTER I-3HENTAIGANA LETTER I-4HENTAI" +
"GANA LETTER U-1HENTAIGANA LETTER U-2HENTAIGANA LETTER U-3HENTAIGANA LETT" +
"ER U-4HENTAIGANA LETTER U-5HENTAIGANA LETTER E-2HENTAIGANA LETTER E-3HEN" +
"TAIGANA LETTER E-4HENTAIGANA LETTER E-5HENTAIGANA LETTER E-6HENTAIGANA L" +
"ETTER O-1HENTAIGANA LETTER O-2HENTAIGANA LETTER O-3HENTAIGANA LETTER KA-" +
"1HENTAIGANA LETTER KA-2HENTAIGANA LETTER KA-3HENTAIGANA LETTER KA-4HENTA" +
"IGANA LETTER KA-5HENTAIGANA LETTER KA-6HENTAIGANA LETTER KA-7HENTAIGANA " +
"LETTER KA-8HENTAIGANA LETTER KA-9HENTAIGANA LETTER KA-10HENTAIGANA LETTE" +
"R KA-11HENTAIGANA LETTER KA-KEHENTAIGANA LETTER KI-1HENTAIGANA LETTER KI" +
"-2HENTAIGANA LETTER KI-3HENTAIGANA LETTER KI-4HENTAIGANA LETTER KI-5HENT" +
"AIGANA LETTER KI-6HENTAIGANA LETTER KI-7HENTAIGANA LETTER KI-8HENTAIGANA" +
" LETTER KU-1HENTAIGANA LETTER KU-2HENTAIGANA LETTER KU-3HENTAIGANA LETTE" +
"R KU-4HENTAIGANA LETTER KU-5HENTAIGANA LETTER KU-6HENTAIGANA LETTER KU-7" +
"HENTAIGANA LETTER KE-1HENTAIGANA LETTER KE-2HENTAIGANA LETTER KE-3HENTAI" +
"GANA LETTER KE-4HENTAIGANA LETTER KE-5HENTAIGANA LETTER KE-6HENTAIGANA L" +
"ETTER KO-1HENTAIGANA LETTER KO-2HENTAIGANA LETTER KO-3HENTAIGANA LETTER " +
"KO-KIHENTAIGANA LETTER SA-1HENTAIGANA LETTER SA-2HENTAIGANA LETTER SA-3H" +
"ENTAIGANA LETTER SA-4HENTAIGANA LETTER SA-5HENTAIGANA LETTER SA-6HENTAIG" +
"ANA LETTER SA-7HENTAIGANA LETTER SA-8HENTAIGANA LETTER SI-1HENTAIGANA LE" +
"TTER SI-2HENTAIGANA LETTER SI-3HENTAIGANA LETTER SI-4HENTAIGANA LETTER S" +
"I-5HENTAIGANA LETTER SI-6HENTAIGANA LETTER SU-1HENTAIGANA LETTER SU-2HEN" +
"TAIGANA LETTER SU-3HENTAIGANA LETTER SU-4HENTAIGANA LETTER SU-5HENTAIGAN" +
"A LETTER SU-6HENTAIGANA LETTER SU-7HENTAIGANA LETTER SU-8HENTAIGANA LETT") + ("" +
"ER SE-1HENTAIGANA LETTER SE-2HENTAIGANA LETTER SE-3HENTAIGANA LETTER SE-" +
"4HENTAIGANA LETTER SE-5HENTAIGANA LETTER SO-1HENTAIGANA LETTER SO-2HENTA" +
"IGANA LETTER SO-3HENTAIGANA LETTER SO-4HENTAIGANA LETTER SO-5HENTAIGANA " +
"LETTER SO-6HENTAIGANA LETTER SO-7HENTAIGANA LETTER TA-1HENTAIGANA LETTER" +
" TA-2HENTAIGANA LETTER TA-3HENTAIGANA LETTER TA-4HENTAIGANA LETTER TI-1H" +
"ENTAIGANA LETTER TI-2HENTAIGANA LETTER TI-3HENTAIGANA LETTER TI-4HENTAIG" +
"ANA LETTER TI-5HENTAIGANA LETTER TI-6HENTAIGANA LETTER TI-7HENTAIGANA LE" +
"TTER TU-1HENTAIGANA LETTER TU-2HENTAIGANA LETTER TU-3HENTAIGANA LETTER T" +
"U-4HENTAIGANA LETTER TU-TOHENTAIGANA LETTER TE-1HENTAIGANA LETTER TE-2HE" +
"NTAIGANA LETTER TE-3HENTAIGANA LETTER TE-4HENTAIGANA LETTER TE-5HENTAIGA" +
"NA LETTER TE-6HENTAIGANA LETTER TE-7HENTAIGANA LETTER TE-8HENTAIGANA LET" +
"TER TE-9HENTAIGANA LETTER TO-1HENTAIGANA LETTER TO-2HENTAIGANA LETTER TO" +
"-3HENTAIGANA LETTER TO-4HENTAIGANA LETTER TO-5HENTAIGANA LETTER TO-6HENT" +
"AIGANA LETTER TO-RAHENTAIGANA LETTER NA-1HENTAIGANA LETTER NA-2HENTAIGAN" +
"A LETTER NA-3HENTAIGANA LETTER NA-4HENTAIGANA LETTER NA-5HENTAIGANA LETT" +
"ER NA-6HENTAIGANA LETTER NA-7HENTAIGANA LETTER NA-8HENTAIGANA LETTER NA-" +
"9HENTAIGANA LETTER NI-1HENTAIGANA LETTER NI-2HENTAIGANA LETTER NI-3HENTA" +
"IGANA LETTER NI-4HENTAIGANA LETTER NI-5HENTAIGANA LETTER NI-6HENTAIGANA " +
"LETTER NI-7HENTAIGANA LETTER NI-TEHENTAIGANA LETTER NU-1HENTAIGANA LETTE" +
"R NU-2HENTAIGANA LETTER NU-3HENTAIGANA LETTER NE-1HENTAIGANA LETTER NE-2" +
"HENTAIGANA LETTER NE-3HENTAIGANA LETTER NE-4HENTAIGANA LETTER NE-5HENTAI" +
"GANA LETTER NE-6HENTAIGANA LETTER NE-KOHENTAIGANA LETTER NO-1HENTAIGANA " +
"LETTER NO-2HENTAIGANA LETTER NO-3HENTAIGANA LETTER NO-4HENTAIGANA LETTER" +
" NO-5HENTAIGANA LETTER HA-1HENTAIGANA LETTER HA-2HENTAIGANA LETTER HA-3H" +
"ENTAIGANA LETTER HA-4HENTAIGANA LETTER HA-5HENTAIGANA LETTER HA-6HENTAIG" +
"ANA LETTER HA-7HENTAIGANA LETTER HA-8HENTAIGANA LETTER HA-9HENTAIGANA LE" +
"TTER HA-10HENTAIGANA LETTER HA-11HENTAIGANA LETTER HI-1HENTAIGANA LETTER" +
" HI-2HENTAIGANA LETTER HI-3HENTAIGANA LETTER HI-4HENTAIGANA LETTER HI-5H" +
"ENTAIGANA LETTER HI-6HENTAIGANA LETTER HI-7HENTAIGANA LETTER HU-1HENTAIG" +
"ANA LETTER HU-2HENTAIGANA LETTER HU-3HENTAIGANA LETTER HE-1HENTAIGANA LE" +
"TTER HE-2HENTAIGANA LETTER HE-3HENTAIGANA LETTER HE-4HENTAIGANA LETTER H" +
"E-5HENTAIGANA LETTER HE-6HENTAIGANA LETTER HE-7HENTAIGANA LETTER HO-1HEN" +
"TAIGANA LETTER HO-2HENTAIGANA LETTER HO-3HENTAIGANA LETTER HO-4HENTAIGAN" +
"A LETTER HO-5HENTAIGANA LETTER HO-6HENTAIGANA LETTER HO-7HENTAIGANA LETT" +
"ER HO-8HENTAIGANA LETTER MA-1HENTAIGANA LETTER MA-2HENTAIGANA LETTER MA-" +
"3HENTAIGANA LETTER MA-4HENTAIGANA LETTER MA-5HENTAIGANA LETTER MA-6HENTA" +
"IGANA LETTER MA-7HENTAIGANA LETTER MI-1HENTAIGANA LETTER MI-2HENTAIGANA " +
"LETTER MI-3HENTAIGANA LETTER MI-4HENTAIGANA LETTER MI-5HENTAIGANA LETTER" +
" MI-6HENTAIGANA LETTER MI-7HENTAIGANA LETTER MU-1HENTAIGANA LETTER MU-2H" +
"ENTAIGANA LETTER MU-3HENTAIGANA LETTER MU-4HENTAIGANA LETTER ME-1HENTAIG" +
"ANA LETTER ME-2HENTAIGANA LETTER ME-MAHENTAIGANA LETTER MO-1HENTAIGANA L" +
"ETTER MO-2HENTAIGANA LETTER MO-3HENTAIGANA LETTER MO-4HENTAIGANA LETTER " +
"MO-5HENTAIGANA LETTER MO-6HENTAIGANA LETTER YA-1HENTAIGANA LETTER YA-2HE" +
"NTAIGANA LETTER YA-3HENTAIGANA LETTER YA-4HENTAIGANA LETTER YA-5HENTAIGA" +
"NA LETTER YA-YOHENTAIGANA LETTER YU-1HENTAIGANA LETTER YU-2HENTAIGANA LE" +
"TTER YU-3HENTAIGANA LETTER YU-4HENTAIGANA LETTER YO-1HENTAIGANA LETTER Y" +
"O-2HENTAIGANA LETTER YO-3HENTAIGANA LETTER YO-4HENTAIGANA LETTER YO-5HEN" +
"TAIGANA LETTER YO-6HENTAIGANA LETTER RA-1HENTAIGANA LETTER RA-2HENTAIGAN" +
"A LETTER RA-3HENTAIGANA LETTER RA-4HENTAIGANA LETTER RI-1HENTAIGANA LETT" +
"ER RI-2HENTAIGANA LETTER RI-3HENTAIGANA LETTER RI-4HENTAIGANA LETTER RI-" +
"5HENTAIGANA LETTER RI-6HENTAIGANA LETTER RI-7HENTAIGANA LETTER RU-1HENTA" +
"IGANA LETTER RU-2HENTAIGANA LETTER RU-3HENTAIGANA LETTER RU-4HENTAIGANA " +
"LETTER RU-5HENTAIGANA LETTER RU-6HENTAIGANA LETTER RE-1HENTAIGANA LETTER" +
" RE-2HENTAIGANA LETTER RE-3HENTAIGANA LETTER RE-4HENTAIGANA LETTER RO-1H" +
"ENTAIGANA LETTER RO-2HENTAIGANA LETTER RO-3HENTAIGANA LETTER RO-4HENTAIG" +
"ANA LETTER RO-5HENTAIGANA LETTER RO-6HENTAIGANA LETTER WA-1HENTAIGANA LE" +
"TTER WA-2HENTAIGANA LETTER WA-3HENTAIGANA LETTER WA-4HENTAIGANA LETTER W" +
"A-5HENTAIGANA LETTER WI-1HENTAIGANA LETTER WI-2HENTAIGANA LETTER WI-3HEN" +
"TAIGANA LETTER WI-4HENTAIGANA LETTER WI-5HENTAIGANA LETTER WE-1HENTAIGAN" +
"A LETTER WE-2HENTAIGANA LETTER WE-3HENTAIGANA LETTER WE-4HENTAIGANA LETT" +
"ER WO-1HENTAIGANA LETTER WO-2HENTAIGANA LETTER WO-3HENTAIGANA LETTER WO-" +
"4HENTAIGANA LETTER WO-5HENTAIGANA LETTER WO-6HENTAIGANA LETTER WO-7HENTA" +
"IGANA LETTER N-MU-MO-1HENTAIGANA LETTER N-MU-MO-2HIRAGANA LETTER ARCHAIC" +
" WUKATAKANA LETTER ARCHAIC YIKATAKANA LETTER ARCHAIC YEKATAKANA LETTER A") + ("" +
"RCHAIC WUHIRAGANA LETTER SMALL KOHIRAGANA LETTER SMALL WIHIRAGANA LETTER" +
" SMALL WEHIRAGANA LETTER SMALL WOKATAKANA LETTER SMALL KOKATAKANA LETTER" +
" SMALL WIKATAKANA LETTER SMALL WEKATAKANA LETTER SMALL WOKATAKANA LETTER" +
" SMALL NNUSHU CHARACTER-1B170NUSHU CHARACTER-1B171NUSHU CHARACTER-1B172N" +
"USHU CHARACTER-1B173NUSHU CHARACTER-1B174NUSHU CHARACTER-1B175NUSHU CHAR" +
"ACTER-1B176NUSHU CHARACTER-1B177NUSHU CHARACTER-1B178NUSHU CHARACTER-1B1" +
"79NUSHU CHARACTER-1B17ANUSHU CHARACTER-1B17BNUSHU CHARACTER-1B17CNUSHU C" +
"HARACTER-1B17DNUSHU CHARACTER-1B17ENUSHU CHARACTER-1B17FNUSHU CHARACTER-" +
"1B180NUSHU CHARACTER-1B181NUSHU CHARACTER-1B182NUSHU CHARACTER-1B183NUSH" +
"U CHARACTER-1B184NUSHU CHARACTER-1B185NUSHU CHARACTER-1B186NUSHU CHARACT" +
"ER-1B187NUSHU CHARACTER-1B188NUSHU CHARACTER-1B189NUSHU CHARACTER-1B18AN" +
"USHU CHARACTER-1B18BNUSHU CHARACTER-1B18CNUSHU CHARACTER-1B18DNUSHU CHAR" +
"ACTER-1B18ENUSHU CHARACTER-1B18FNUSHU CHARACTER-1B190NUSHU CHARACTER-1B1" +
"91NUSHU CHARACTER-1B192NUSHU CHARACTER-1B193NUSHU CHARACTER-1B194NUSHU C" +
"HARACTER-1B195NUSHU CHARACTER-1B196NUSHU CHARACTER-1B197NUSHU CHARACTER-" +
"1B198NUSHU CHARACTER-1B199NUSHU CHARACTER-1B19ANUSHU CHARACTER-1B19BNUSH" +
"U CHARACTER-1B19CNUSHU CHARACTER-1B19DNUSHU CHARACTER-1B19ENUSHU CHARACT" +
"ER-1B19FNUSHU CHARACTER-1B1A0NUSHU CHARACTER-1B1A1NUSHU CHARACTER-1B1A2N" +
"USHU CHARACTER-1B1A3NUSHU CHARACTER-1B1A4NUSHU CHARACTER-1B1A5NUSHU CHAR" +
"ACTER-1B1A6NUSHU CHARACTER-1B1A7NUSHU CHARACTER-1B1A8NUSHU CHARACTER-1B1" +
"A9NUSHU CHARACTER-1B1AANUSHU CHARACTER-1B1ABNUSHU CHARACTER-1B1ACNUSHU C" +
"HARACTER-1B1ADNUSHU CHARACTER-1B1AENUSHU CHARACTER-1B1AFNUSHU CHARACTER-" +
"1B1B0NUSHU CHARACTER-1B1B1NUSHU CHARACTER-1B1B2NUSHU CHARACTER-1B1B3NUSH" +
"U CHARACTER-1B1B4NUSHU CHARACTER-1B1B5NUSHU CHARACTER-1B1B6NUSHU CHARACT" +
"ER-1B1B7NUSHU CHARACTER-1B1B8NUSHU CHARACTER-1B1B9NUSHU CHARACTER-1B1BAN" +
"USHU CHARACTER-1B1BBNUSHU CHARACTER-1B1BCNUSHU CHARACTER-1B1BDNUSHU CHAR" +
"ACTER-1B1BENUSHU CHARACTER-1B1BFNUSHU CHARACTER-1B1C0NUSHU CHARACTER-1B1" +
"C1NUSHU CHARACTER-1B1C2NUSHU CHARACTER-1B1C3NUSHU CHARACTER-1B1C4NUSHU C" +
"HARACTER-1B1C5NUSHU CHARACTER-1B1C6NUSHU CHARACTER-1B1C7NUSHU CHARACTER-" +
"1B1C8NUSHU CHARACTER-1B1C9NUSHU CHARACTER-1B1CANUSHU CHARACTER-1B1CBNUSH" +
"U CHARACTER-1B1CCNUSHU CHARACTER-1B1CDNUSHU CHARACTER-1B1CENUSHU CHARACT" +
"ER-1B1CFNUSHU CHARACTER-1B1D0NUSHU CHARACTER-1B1D1NUSHU CHARACTER-1B1D2N" +
"USHU CHARACTER-1B1D3NUSHU CHARACTER-1B1D4NUSHU CHARACTER-1B1D5NUSHU CHAR" +
"ACTER-1B1D6NUSHU CHARACTER-1B1D7NUSHU CHARACTER-1B1D8NUSHU CHARACTER-1B1" +
"D9NUSHU CHARACTER-1B1DANUSHU CHARACTER-1B1DBNUSHU CHARACTER-1B1DCNUSHU C" +
"HARACTER-1B1DDNUSHU CHARACTER-1B1DENUSHU CHARACTER-1B1DFNUSHU CHARACTER-" +
"1B1E0NUSHU CHARACTER-1B1E1NUSHU CHARACTER-1B1E2NUSHU CHARACTER-1B1E3NUSH" +
"U CHARACTER-1B1E4NUSHU CHARACTER-1B1E5NUSHU CHARACTER-1B1E6NUSHU CHARACT" +
"ER-1B1E7NUSHU CHARACTER-1B1E8NUSHU CHARACTER-1B1E9NUSHU CHARACTER-1B1EAN" +
"USHU CHARACTER-1B1EBNUSHU CHARACTER-1B1ECNUSHU CHARACTER-1B1EDNUSHU CHAR" +
"ACTER-1B1EENUSHU CHARACTER-1B1EFNUSHU CHARACTER-1B1F0NUSHU CHARACTER-1B1" +
"F1NUSHU CHARACTER-1B1F2NUSHU CHARACTER-1B1F3NUSHU CHARACTER-1B1F4NUSHU C" +
"HARACTER-1B1F5NUSHU CHARACTER-1B1F6NUSHU CHARACTER-1B1F7NUSHU CHARACTER-" +
"1B1F8NUSHU CHARACTER-1B1F9NUSHU CHARACTER-1B1FANUSHU CHARACTER-1B1FBNUSH" +
"U CHARACTER-1B1FCNUSHU CHARACTER-1B1FDNUSHU CHARACTER-1B1FENUSHU CHARACT" +
"ER-1B1FFNUSHU CHARACTER-1B200NUSHU CHARACTER-1B201NUSHU CHARACTER-1B202N" +
"USHU CHARACTER-1B203NUSHU CHARACTER-1B204NUSHU CHARACTER-1B205NUSHU CHAR" +
"ACTER-1B206NUSHU CHARACTER-1B207NUSHU CHARACTER-1B208NUSHU CHARACTER-1B2" +
"09NUSHU CHARACTER-1B20ANUSHU CHARACTER-1B20BNUSHU CHARACTER-1B20CNUSHU C" +
"HARACTER-1B20DNUSHU CHARACTER-1B20ENUSHU CHARACTER-1B20FNUSHU CHARACTER-" +
"1B210NUSHU CHARACTER-1B211NUSHU CHARACTER-1B212NUSHU CHARACTER-1B213NUSH" +
"U CHARACTER-1B214NUSHU CHARACTER-1B215NUSHU CHARACTER-1B216NUSHU CHARACT" +
"ER-1B217NUSHU CHARACTER-1B218NUSHU CHARACTER-1B219NUSHU CHARACTER-1B21AN" +
"USHU CHARACTER-1B21BNUSHU CHARACTER-1B21CNUSHU CHARACTER-1B21DNUSHU CHAR" +
"ACTER-1B21ENUSHU CHARACTER-1B21FNUSHU CHARACTER-1B220NUSHU CHARACTER-1B2" +
"21NUSHU CHARACTER-1B222NUSHU CHARACTER-1B223NUSHU CHARACTER-1B224NUSHU C" +
"HARACTER-1B225NUSHU CHARACTER-1B226NUSHU CHARACTER-1B227NUSHU CHARACTER-" +
"1B228NUSHU CHARACTER-1B229NUSHU CHARACTER-1B22ANUSHU CHARACTER-1B22BNUSH" +
"U CHARACTER-1B22CNUSHU CHARACTER-1B22DNUSHU CHARACTER-1B22ENUSHU CHARACT" +
"ER-1B22FNUSHU CHARACTER-1B230NUSHU CHARACTER-1B231NUSHU CHARACTER-1B232N" +
"USHU CHARACTER-1B233NUSHU CHARACTER-1B234NUSHU CHARACTER-1B235NUSHU CHAR" +
"ACTER-1B236NUSHU CHARACTER-1B237NUSHU CHARACTER-1B238NUSHU CHARACTER-1B2" +
"39NUSHU CHARACTER-1B23ANUSHU CHARACTER-1B23BNUSHU CHARACTER-1B23CNUSHU C" +
"HARACTER-1B23DNUSHU CHARACTER-1B23ENUSHU CHARACTER-1B23FNUSHU CHARACTER-") + ("" +
"1B240NUSHU CHARACTER-1B241NUSHU CHARACTER-1B242NUSHU CHARACTER-1B243NUSH" +
"U CHARACTER-1B244NUSHU CHARACTER-1B245NUSHU CHARACTER-1B246NUSHU CHARACT" +
"ER-1B247NUSHU CHARACTER-1B248NUSHU CHARACTER-1B249NUSHU CHARACTER-1B24AN" +
"USHU CHARACTER-1B24BNUSHU CHARACTER-1B24CNUSHU CHARACTER-1B24DNUSHU CHAR" +
"ACTER-1B24ENUSHU CHARACTER-1B24FNUSHU CHARACTER-1B250NUSHU CHARACTER-1B2" +
"51NUSHU CHARACTER-1B252NUSHU CHARACTER-1B253NUSHU CHARACTER-1B254NUSHU C" +
"HARACTER-1B255NUSHU CHARACTER-1B256NUSHU CHARACTER-1B257NUSHU CHARACTER-" +
"1B258NUSHU CHARACTER-1B259NUSHU CHARACTER-1B25ANUSHU CHARACTER-1B25BNUSH" +
"U CHARACTER-1B25CNUSHU CHARACTER-1B25DNUSHU CHARACTER-1B25ENUSHU CHARACT" +
"ER-1B25FNUSHU CHARACTER-1B260NUSHU CHARACTER-1B261NUSHU CHARACTER-1B262N" +
"USHU CHARACTER-1B263NUSHU CHARACTER-1B264NUSHU CHARACTER-1B265NUSHU CHAR" +
"ACTER-1B266NUSHU CHARACTER-1B267NUSHU CHARACTER-1B268NUSHU CHARACTER-1B2" +
"69NUSHU CHARACTER-1B26ANUSHU CHARACTER-1B26BNUSHU CHARACTER-1B26CNUSHU C" +
"HARACTER-1B26DNUSHU CHARACTER-1B26ENUSHU CHARACTER-1B26FNUSHU CHARACTER-" +
"1B270NUSHU CHARACTER-1B271NUSHU CHARACTER-1B272NUSHU CHARACTER-1B273NUSH" +
"U CHARACTER-1B274NUSHU CHARACTER-1B275NUSHU CHARACTER-1B276NUSHU CHARACT" +
"ER-1B277NUSHU CHARACTER-1B278NUSHU CHARACTER-1B279NUSHU CHARACTER-1B27AN" +
"USHU CHARACTER-1B27BNUSHU CHARACTER-1B27CNUSHU CHARACTER-1B27DNUSHU CHAR" +
"ACTER-1B27ENUSHU CHARACTER-1B27FNUSHU CHARACTER-1B280NUSHU CHARACTER-1B2" +
"81NUSHU CHARACTER-1B282NUSHU CHARACTER-1B283NUSHU CHARACTER-1B284NUSHU C" +
"HARACTER-1B285NUSHU CHARACTER-1B286NUSHU CHARACTER-1B287NUSHU CHARACTER-" +
"1B288NUSHU CHARACTER-1B289NUSHU CHARACTER-1B28ANUSHU CHARACTER-1B28BNUSH" +
"U CHARACTER-1B28CNUSHU CHARACTER-1B28DNUSHU CHARACTER-1B28ENUSHU CHARACT" +
"ER-1B28FNUSHU CHARACTER-1B290NUSHU CHARACTER-1B291NUSHU CHARACTER-1B292N" +
"USHU CHARACTER-1B293NUSHU CHARACTER-1B294NUSHU CHARACTER-1B295NUSHU CHAR" +
"ACTER-1B296NUSHU CHARACTER-1B297NUSHU CHARACTER-1B298NUSHU CHARACTER-1B2" +
"99NUSHU CHARACTER-1B29ANUSHU CHARACTER-1B29BNUSHU CHARACTER-1B29CNUSHU C" +
"HARACTER-1B29DNUSHU CHARACTER-1B29ENUSHU CHARACTER-1B29FNUSHU CHARACTER-" +
"1B2A0NUSHU CHARACTER-1B2A1NUSHU CHARACTER-1B2A2NUSHU CHARACTER-1B2A3NUSH" +
"U CHARACTER-1B2A4NUSHU CHARACTER-1B2A5NUSHU CHARACTER-1B2A6NUSHU CHARACT" +
"ER-1B2A7NUSHU CHARACTER-1B2A8NUSHU CHARACTER-1B2A9NUSHU CHARACTER-1B2AAN" +
"USHU CHARACTER-1B2ABNUSHU CHARACTER-1B2ACNUSHU CHARACTER-1B2ADNUSHU CHAR" +
"ACTER-1B2AENUSHU CHARACTER-1B2AFNUSHU CHARACTER-1B2B0NUSHU CHARACTER-1B2" +
"B1NUSHU CHARACTER-1B2B2NUSHU CHARACTER-1B2B3NUSHU CHARACTER-1B2B4NUSHU C" +
"HARACTER-1B2B5NUSHU CHARACTER-1B2B6NUSHU CHARACTER-1B2B7NUSHU CHARACTER-" +
"1B2B8NUSHU CHARACTER-1B2B9NUSHU CHARACTER-1B2BANUSHU CHARACTER-1B2BBNUSH" +
"U CHARACTER-1B2BCNUSHU CHARACTER-1B2BDNUSHU CHARACTER-1B2BENUSHU CHARACT" +
"ER-1B2BFNUSHU CHARACTER-1B2C0NUSHU CHARACTER-1B2C1NUSHU CHARACTER-1B2C2N" +
"USHU CHARACTER-1B2C3NUSHU CHARACTER-1B2C4NUSHU CHARACTER-1B2C5NUSHU CHAR" +
"ACTER-1B2C6NUSHU CHARACTER-1B2C7NUSHU CHARACTER-1B2C8NUSHU CHARACTER-1B2" +
"C9NUSHU CHARACTER-1B2CANUSHU CHARACTER-1B2CBNUSHU CHARACTER-1B2CCNUSHU C" +
"HARACTER-1B2CDNUSHU CHARACTER-1B2CENUSHU CHARACTER-1B2CFNUSHU CHARACTER-" +
"1B2D0NUSHU CHARACTER-1B2D1NUSHU CHARACTER-1B2D2NUSHU CHARACTER-1B2D3NUSH" +
"U CHARACTER-1B2D4NUSHU CHARACTER-1B2D5NUSHU CHARACTER-1B2D6NUSHU CHARACT" +
"ER-1B2D7NUSHU CHARACTER-1B2D8NUSHU CHARACTER-1B2D9NUSHU CHARACTER-1B2DAN" +
"USHU CHARACTER-1B2DBNUSHU CHARACTER-1B2DCNUSHU CHARACTER-1B2DDNUSHU CHAR" +
"ACTER-1B2DENUSHU CHARACTER-1B2DFNUSHU CHARACTER-1B2E0NUSHU CHARACTER-1B2" +
"E1NUSHU CHARACTER-1B2E2NUSHU CHARACTER-1B2E3NUSHU CHARACTER-1B2E4NUSHU C" +
"HARACTER-1B2E5NUSHU CHARACTER-1B2E6NUSHU CHARACTER-1B2E7NUSHU CHARACTER-" +
"1B2E8NUSHU CHARACTER-1B2E9NUSHU CHARACTER-1B2EANUSHU CHARACTER-1B2EBNUSH" +
"U CHARACTER-1B2ECNUSHU CHARACTER-1B2EDNUSHU CHARACTER-1B2EENUSHU CHARACT" +
"ER-1B2EFNUSHU CHARACTER-1B2F0NUSHU CHARACTER-1B2F1NUSHU CHARACTER-1B2F2N" +
"USHU CHARACTER-1B2F3NUSHU CHARACTER-1B2F4NUSHU CHARACTER-1B2F5NUSHU CHAR" +
"ACTER-1B2F6NUSHU CHARACTER-1B2F7NUSHU CHARACTER-1B2F8NUSHU CHARACTER-1B2" +
"F9NUSHU CHARACTER-1B2FANUSHU CHARACTER-1B2FBDUPLOYAN LETTER HDUPLOYAN LE" +
"TTER XDUPLOYAN LETTER PDUPLOYAN LETTER TDUPLOYAN LETTER FDUPLOYAN LETTER" +
" KDUPLOYAN LETTER LDUPLOYAN LETTER BDUPLOYAN LETTER DDUPLOYAN LETTER VDU" +
"PLOYAN LETTER GDUPLOYAN LETTER RDUPLOYAN LETTER P NDUPLOYAN LETTER D SDU" +
"PLOYAN LETTER F NDUPLOYAN LETTER K MDUPLOYAN LETTER R SDUPLOYAN LETTER T" +
"HDUPLOYAN LETTER SLOAN DHDUPLOYAN LETTER DHDUPLOYAN LETTER KKDUPLOYAN LE" +
"TTER SLOAN JDUPLOYAN LETTER HLDUPLOYAN LETTER LHDUPLOYAN LETTER RHDUPLOY" +
"AN LETTER MDUPLOYAN LETTER NDUPLOYAN LETTER JDUPLOYAN LETTER SDUPLOYAN L" +
"ETTER M NDUPLOYAN LETTER N MDUPLOYAN LETTER J MDUPLOYAN LETTER S JDUPLOY" +
"AN LETTER M WITH DOTDUPLOYAN LETTER N WITH DOTDUPLOYAN LETTER J WITH DOT") + ("" +
"DUPLOYAN LETTER J WITH DOTS INSIDE AND ABOVEDUPLOYAN LETTER S WITH DOTDU" +
"PLOYAN LETTER S WITH DOT BELOWDUPLOYAN LETTER M SDUPLOYAN LETTER N SDUPL" +
"OYAN LETTER J SDUPLOYAN LETTER S SDUPLOYAN LETTER M N SDUPLOYAN LETTER N" +
" M SDUPLOYAN LETTER J M SDUPLOYAN LETTER S J SDUPLOYAN LETTER J S WITH D" +
"OTDUPLOYAN LETTER J NDUPLOYAN LETTER J N SDUPLOYAN LETTER S TDUPLOYAN LE" +
"TTER S T RDUPLOYAN LETTER S PDUPLOYAN LETTER S P RDUPLOYAN LETTER T SDUP" +
"LOYAN LETTER T R SDUPLOYAN LETTER WDUPLOYAN LETTER WHDUPLOYAN LETTER W R" +
"DUPLOYAN LETTER S NDUPLOYAN LETTER S MDUPLOYAN LETTER K R SDUPLOYAN LETT" +
"ER G R SDUPLOYAN LETTER S KDUPLOYAN LETTER S K RDUPLOYAN LETTER ADUPLOYA" +
"N LETTER SLOAN OWDUPLOYAN LETTER OADUPLOYAN LETTER ODUPLOYAN LETTER AOUD" +
"UPLOYAN LETTER IDUPLOYAN LETTER EDUPLOYAN LETTER IEDUPLOYAN LETTER SHORT" +
" IDUPLOYAN LETTER UIDUPLOYAN LETTER EEDUPLOYAN LETTER SLOAN EHDUPLOYAN L" +
"ETTER ROMANIAN IDUPLOYAN LETTER SLOAN EEDUPLOYAN LETTER LONG IDUPLOYAN L" +
"ETTER YEDUPLOYAN LETTER UDUPLOYAN LETTER EUDUPLOYAN LETTER XWDUPLOYAN LE" +
"TTER U NDUPLOYAN LETTER LONG UDUPLOYAN LETTER ROMANIAN UDUPLOYAN LETTER " +
"UHDUPLOYAN LETTER SLOAN UDUPLOYAN LETTER OOHDUPLOYAN LETTER OWDUPLOYAN L" +
"ETTER OUDUPLOYAN LETTER WADUPLOYAN LETTER WODUPLOYAN LETTER WIDUPLOYAN L" +
"ETTER WEIDUPLOYAN LETTER WOWDUPLOYAN LETTER NASAL UDUPLOYAN LETTER NASAL" +
" ODUPLOYAN LETTER NASAL IDUPLOYAN LETTER NASAL ADUPLOYAN LETTER PERNIN A" +
"NDUPLOYAN LETTER PERNIN AMDUPLOYAN LETTER SLOAN ENDUPLOYAN LETTER SLOAN " +
"ANDUPLOYAN LETTER SLOAN ONDUPLOYAN LETTER VOCALIC MDUPLOYAN AFFIX LEFT H" +
"ORIZONTAL SECANTDUPLOYAN AFFIX MID HORIZONTAL SECANTDUPLOYAN AFFIX RIGHT" +
" HORIZONTAL SECANTDUPLOYAN AFFIX LOW VERTICAL SECANTDUPLOYAN AFFIX MID V" +
"ERTICAL SECANTDUPLOYAN AFFIX HIGH VERTICAL SECANTDUPLOYAN AFFIX ATTACHED" +
" SECANTDUPLOYAN AFFIX ATTACHED LEFT-TO-RIGHT SECANTDUPLOYAN AFFIX ATTACH" +
"ED TANGENTDUPLOYAN AFFIX ATTACHED TAILDUPLOYAN AFFIX ATTACHED E HOOKDUPL" +
"OYAN AFFIX ATTACHED I HOOKDUPLOYAN AFFIX ATTACHED TANGENT HOOKDUPLOYAN A" +
"FFIX HIGH ACUTEDUPLOYAN AFFIX HIGH TIGHT ACUTEDUPLOYAN AFFIX HIGH GRAVED" +
"UPLOYAN AFFIX HIGH LONG GRAVEDUPLOYAN AFFIX HIGH DOTDUPLOYAN AFFIX HIGH " +
"CIRCLEDUPLOYAN AFFIX HIGH LINEDUPLOYAN AFFIX HIGH WAVEDUPLOYAN AFFIX HIG" +
"H VERTICALDUPLOYAN AFFIX LOW ACUTEDUPLOYAN AFFIX LOW TIGHT ACUTEDUPLOYAN" +
" AFFIX LOW GRAVEDUPLOYAN AFFIX LOW LONG GRAVEDUPLOYAN AFFIX LOW DOTDUPLO" +
"YAN AFFIX LOW CIRCLEDUPLOYAN AFFIX LOW LINEDUPLOYAN AFFIX LOW WAVEDUPLOY" +
"AN AFFIX LOW VERTICALDUPLOYAN AFFIX LOW ARROWDUPLOYAN SIGN O WITH CROSSD" +
"UPLOYAN THICK LETTER SELECTORDUPLOYAN DOUBLE MARKDUPLOYAN PUNCTUATION CH" +
"INOOK FULL STOPSHORTHAND FORMAT LETTER OVERLAPSHORTHAND FORMAT CONTINUIN" +
"G OVERLAPSHORTHAND FORMAT DOWN STEPSHORTHAND FORMAT UP STEPZNAMENNY COMB" +
"INING MARK GORAZDO NIZKO S KRYZHEM ON LEFTZNAMENNY COMBINING MARK NIZKO " +
"S KRYZHEM ON LEFTZNAMENNY COMBINING MARK TSATA ON LEFTZNAMENNY COMBINING" +
" MARK GORAZDO NIZKO ON LEFTZNAMENNY COMBINING MARK NIZKO ON LEFTZNAMENNY" +
" COMBINING MARK SREDNE ON LEFTZNAMENNY COMBINING MARK MALO POVYSHE ON LE" +
"FTZNAMENNY COMBINING MARK POVYSHE ON LEFTZNAMENNY COMBINING MARK VYSOKO " +
"ON LEFTZNAMENNY COMBINING MARK MALO POVYSHE S KHOKHLOM ON LEFTZNAMENNY C" +
"OMBINING MARK POVYSHE S KHOKHLOM ON LEFTZNAMENNY COMBINING MARK VYSOKO S" +
" KHOKHLOM ON LEFTZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON RIGH" +
"TZNAMENNY COMBINING MARK NIZKO S KRYZHEM ON RIGHTZNAMENNY COMBINING MARK" +
" TSATA ON RIGHTZNAMENNY COMBINING MARK GORAZDO NIZKO ON RIGHTZNAMENNY CO" +
"MBINING MARK NIZKO ON RIGHTZNAMENNY COMBINING MARK SREDNE ON RIGHTZNAMEN" +
"NY COMBINING MARK MALO POVYSHE ON RIGHTZNAMENNY COMBINING MARK POVYSHE O" +
"N RIGHTZNAMENNY COMBINING MARK VYSOKO ON RIGHTZNAMENNY COMBINING MARK MA" +
"LO POVYSHE S KHOKHLOM ON RIGHTZNAMENNY COMBINING MARK POVYSHE S KHOKHLOM" +
" ON RIGHTZNAMENNY COMBINING MARK VYSOKO S KHOKHLOM ON RIGHTZNAMENNY COMB" +
"INING MARK TSATA S KRYZHEMZNAMENNY COMBINING MARK MALO POVYSHE S KRYZHEM" +
"ZNAMENNY COMBINING MARK STRANNO MALO POVYSHEZNAMENNY COMBINING MARK POVY" +
"SHE S KRYZHEMZNAMENNY COMBINING MARK POVYSHE STRANNOZNAMENNY COMBINING M" +
"ARK VYSOKO S KRYZHEMZNAMENNY COMBINING MARK MALO POVYSHE STRANNOZNAMENNY" +
" COMBINING MARK GORAZDO VYSOKOZNAMENNY COMBINING MARK ZELOZNAMENNY COMBI" +
"NING MARK ONZNAMENNY COMBINING MARK RAVNOZNAMENNY COMBINING MARK TIKHAYA" +
"ZNAMENNY COMBINING MARK BORZAYAZNAMENNY COMBINING MARK UDARKAZNAMENNY CO" +
"MBINING MARK PODVERTKAZNAMENNY COMBINING MARK LOMKAZNAMENNY COMBINING MA" +
"RK KUPNAYAZNAMENNY COMBINING MARK KACHKAZNAMENNY COMBINING MARK ZEVOKZNA" +
"MENNY COMBINING MARK SKOBAZNAMENNY COMBINING MARK RAZSEKAZNAMENNY COMBIN" +
"ING MARK KRYZH ON LEFTZNAMENNY COMBINING TONAL RANGE MARK MRACHNOZNAMENN" +
"Y COMBINING TONAL RANGE MARK SVETLOZNAMENNY COMBINING TONAL RANGE MARK T") + ("" +
"RESVETLOZNAMENNY COMBINING MARK ZADERZHKAZNAMENNY COMBINING MARK DEMESTV" +
"ENNY ZADERZHKAZNAMENNY COMBINING MARK OTSECHKAZNAMENNY COMBINING MARK PO" +
"DCHASHIEZNAMENNY COMBINING MARK PODCHASHIE WITH VERTICAL STROKEZNAMENNY " +
"COMBINING MARK CHASHKAZNAMENNY COMBINING MARK CHASHKA POLNAYAZNAMENNY CO" +
"MBINING MARK OBLACHKOZNAMENNY COMBINING MARK SOROCHYA NOZHKAZNAMENNY COM" +
"BINING MARK TOCHKAZNAMENNY COMBINING MARK DVOETOCHIEZNAMENNY COMBINING A" +
"TTACHING VERTICAL OMETZNAMENNY COMBINING MARK CURVED OMETZNAMENNY COMBIN" +
"ING MARK KRYZHZNAMENNY COMBINING LOWER TONAL RANGE INDICATORZNAMENNY PRI" +
"ZNAK MODIFIER LEVEL-2ZNAMENNY PRIZNAK MODIFIER LEVEL-3ZNAMENNY PRIZNAK M" +
"ODIFIER DIRECTION FLIPZNAMENNY PRIZNAK MODIFIER KRYZHZNAMENNY PRIZNAK MO" +
"DIFIER ROGZNAMENNY NEUME KRYUKZNAMENNY NEUME KRYUK TIKHYZNAMENNY NEUME P" +
"ARAKLITZNAMENNY NEUME DVA V CHELNUZNAMENNY NEUME KLYUCHZNAMENNY NEUME ZA" +
"NOZHEKZNAMENNY NEUME STOPITSAZNAMENNY NEUME STOPITSA S OCHKOMZNAMENNY NE" +
"UME PEREVODKAZNAMENNY NEUME PEREVODKA NEPOSTOYANNAYAZNAMENNY NEUME STOPI" +
"TSA WITH SOROCHYA NOZHKAZNAMENNY NEUME CHELYUSTKAZNAMENNY NEUME PALKAZNA" +
"MENNY NEUME ZAPYATAYAZNAMENNY NEUME GOLUBCHIK BORZYZNAMENNY NEUME GOLUBC" +
"HIK TIKHYZNAMENNY NEUME GOLUBCHIK MRACHNYZNAMENNY NEUME GOLUBCHIK SVETLY" +
"ZNAMENNY NEUME GOLUBCHIK TRESVETLYZNAMENNY NEUME VRAKHIYA PROSTAYAZNAMEN" +
"NY NEUME VRAKHIYA MRACHNAYAZNAMENNY NEUME VRAKHIYA SVETLAYAZNAMENNY NEUM" +
"E VRAKHIYA TRESVETLAYAZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA PROSTAYAZNAMEN" +
"NY NEUME VRAKHIYA KLYUCHEVAYA MRACHNAYAZNAMENNY NEUME VRAKHIYA KLYUCHEVA" +
"YA SVETLAYAZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA TRESVETLAYAZNAMENNY NEUME" +
" DOUBLE ZAPYATAYAZNAMENNY NEUME REVERSED CHELYUSTKAZNAMENNY NEUME DERBIT" +
"SAZNAMENNY NEUME KHAMILOZNAMENNY NEUME CHASHKAZNAMENNY NEUME PODCHASHIEZ" +
"NAMENNY NEUME SKAMEYTSA MRACHNAYAZNAMENNY NEUME SKAMEYTSA SVETLAYAZNAMEN" +
"NY NEUME SKAMEYTSA TRESVETLAYAZNAMENNY NEUME SKAMEYTSA TIKHAYAZNAMENNY N" +
"EUME DEMESTVENNY KLYUCHZNAMENNY NEUME SKAMEYTSA KLYUCHEVAYA SVETLAYAZNAM" +
"ENNY NEUME SKAMEYTSA KLYUCHENEPOSTOYANNAYAZNAMENNY NEUME SKAMEYTSA KLYUC" +
"HEVAYA TIKHAYAZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA PROSTAYAZNAMENNY NEU" +
"ME SKAMEYTSA DVOECHELNAYA SVETLAYAZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA " +
"NEPOSTOYANNAYAZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA KLYUCHEVAYAZNAMENNY " +
"NEUME SLOZHITIEZNAMENNY NEUME SLOZHITIE S ZAPYATOYZNAMENNY NEUME SLOZHIT" +
"IE ZAKRYTOEZNAMENNY NEUME SLOZHITIE S KRYZHEMZNAMENNY NEUME KRYZHZNAMENN" +
"Y NEUME ROGZNAMENNY NEUME FITAZNAMENNY NEUME KOBYLAZNAMENNY NEUME ZMEYTS" +
"AZNAMENNY NEUME STATYAZNAMENNY NEUME STATYA S ZAPYATOYZNAMENNY NEUME STA" +
"TYA S KRYZHEMZNAMENNY NEUME STATYA S ZAPYATOY I KRYZHEMZNAMENNY NEUME ST" +
"ATYA S KRYZHEM I ZAPYATOYZNAMENNY NEUME STATYA ZAKRYTAYAZNAMENNY NEUME S" +
"TATYA ZAKRYTAYA S ZAPYATOYZNAMENNY NEUME STATYA S ROGOMZNAMENNY NEUME ST" +
"ATYA S DVUMYA ZAPYATYMIZNAMENNY NEUME STATYA S ZAPYATOY I PODCHASHIEMZNA" +
"MENNY NEUME POLKULIZMYZNAMENNY NEUME STATYA NEPOSTOYANNAYAZNAMENNY NEUME" +
" STRELA PROSTAYAZNAMENNY NEUME STRELA MRACHNOTIKHAYAZNAMENNY NEUME STREL" +
"A KRYZHEVAYAZNAMENNY NEUME STRELA POLUPOVODNAYAZNAMENNY NEUME STRELA POV" +
"ODNAYAZNAMENNY NEUME STRELA NEPOSTOYANNAYAZNAMENNY NEUME STRELA KLYUCHEP" +
"OVODNAYAZNAMENNY NEUME STRELA KLYUCHENEPOSTOYANNAYAZNAMENNY NEUME STRELA" +
" TIKHAYA PUTNAYAZNAMENNY NEUME STRELA DVOECHELNAYAZNAMENNY NEUME STRELA " +
"DVOECHELNOKRYZHEVAYAZNAMENNY NEUME STRELA DVOECHELNOPOVODNAYAZNAMENNY NE" +
"UME STRELA DVOECHELNAYA KLYUCHEVAYAZNAMENNY NEUME STRELA DVOECHELNOPOVOD" +
"NAYA KLYUCHEVAYAZNAMENNY NEUME STRELA GROMNAYA WITH SINGLE ZAPYATAYAZNAM" +
"ENNY NEUME STRELA GROMOPOVODNAYA WITH SINGLE ZAPYATAYAZNAMENNY NEUME STR" +
"ELA GROMNAYAZNAMENNY NEUME STRELA GROMOPOVODNAYAZNAMENNY NEUME STRELA GR" +
"OMOPOVODNAYA WITH DOUBLE ZAPYATAYAZNAMENNY NEUME STRELA GROMOKRYZHEVAYAZ" +
"NAMENNY NEUME STRELA GROMOKRYZHEVAYA POVODNAYAZNAMENNY NEUME MECHIKZNAME" +
"NNY NEUME MECHIK POVODNYZNAMENNY NEUME MECHIK KLYUCHEVOYZNAMENNY NEUME M" +
"ECHIK KLYUCHEPOVODNYZNAMENNY NEUME MECHIK KLYUCHENEPOSTOYANNYZNAMENNY NE" +
"UME STRELA TRYASOGLASNAYAZNAMENNY NEUME STRELA TRYASOPOVODNAYAZNAMENNY N" +
"EUME STRELA TRYASOSTRELNAYAZNAMENNY NEUME OSOKAZNAMENNY NEUME OSOKA SVET" +
"LAYAZNAMENNY NEUME OSOKA TRESVETLAYAZNAMENNY NEUME OSOKA KRYUKOVAYA SVET" +
"LAYAZNAMENNY NEUME OSOKA KLYUCHEVAYA SVETLAYAZNAMENNY NEUME OSOKA KLYUCH" +
"EVAYA NEPOSTOYANNAYAZNAMENNY NEUME STRELA KRYUKOVAYAZNAMENNY NEUME STREL" +
"A KRYUKOVAYA POVODNAYAZNAMENNY NEUME STRELA KRYUKOVAYA GROMNAYA WITH SIN" +
"GLE ZAPYATAYAZNAMENNY NEUME STRELA KRYUKOVAYA GROMOPOVODNAYA WITH SINGLE" +
" ZAPYATAYAZNAMENNY NEUME STRELA KRYUKOVAYA GROMNAYAZNAMENNY NEUME STRELA" +
" KRYUKOVAYA GROMOPOVODNAYAZNAMENNY NEUME STRELA KRYUKOVAYA GROMOPOVODNAY" +
"A WITH DOUBLE ZAPYATAYAZNAMENNY NEUME STRELA KRYUKOVAYA GROMOKRYZHEVAYAZ") + ("" +
"NAMENNY NEUME STRELA KRYUKOVAYA GROMOKRYZHEVAYA POVODNAYAZNAMENNY NEUME " +
"STRELA KRYUKOVAYA TRYASKAZNAMENNY NEUME KUFISMAZNAMENNY NEUME OBLAKOZNAM" +
"ENNY NEUME DUDAZNAMENNY NEUME NEMKAZNAMENNY NEUME PAUKBYZANTINE MUSICAL " +
"SYMBOL PSILIBYZANTINE MUSICAL SYMBOL DASEIABYZANTINE MUSICAL SYMBOL PERI" +
"SPOMENIBYZANTINE MUSICAL SYMBOL OXEIA EKFONITIKONBYZANTINE MUSICAL SYMBO" +
"L OXEIA DIPLIBYZANTINE MUSICAL SYMBOL VAREIA EKFONITIKONBYZANTINE MUSICA" +
"L SYMBOL VAREIA DIPLIBYZANTINE MUSICAL SYMBOL KATHISTIBYZANTINE MUSICAL " +
"SYMBOL SYRMATIKIBYZANTINE MUSICAL SYMBOL PARAKLITIKIBYZANTINE MUSICAL SY" +
"MBOL YPOKRISISBYZANTINE MUSICAL SYMBOL YPOKRISIS DIPLIBYZANTINE MUSICAL " +
"SYMBOL KREMASTIBYZANTINE MUSICAL SYMBOL APESO EKFONITIKONBYZANTINE MUSIC" +
"AL SYMBOL EXO EKFONITIKONBYZANTINE MUSICAL SYMBOL TELEIABYZANTINE MUSICA" +
"L SYMBOL KENTIMATABYZANTINE MUSICAL SYMBOL APOSTROFOSBYZANTINE MUSICAL S" +
"YMBOL APOSTROFOS DIPLIBYZANTINE MUSICAL SYMBOL SYNEVMABYZANTINE MUSICAL " +
"SYMBOL THITABYZANTINE MUSICAL SYMBOL OLIGON ARCHAIONBYZANTINE MUSICAL SY" +
"MBOL GORGON ARCHAIONBYZANTINE MUSICAL SYMBOL PSILONBYZANTINE MUSICAL SYM" +
"BOL CHAMILONBYZANTINE MUSICAL SYMBOL VATHYBYZANTINE MUSICAL SYMBOL ISON " +
"ARCHAIONBYZANTINE MUSICAL SYMBOL KENTIMA ARCHAIONBYZANTINE MUSICAL SYMBO" +
"L KENTIMATA ARCHAIONBYZANTINE MUSICAL SYMBOL SAXIMATABYZANTINE MUSICAL S" +
"YMBOL PARICHONBYZANTINE MUSICAL SYMBOL STAVROS APODEXIABYZANTINE MUSICAL" +
" SYMBOL OXEIAI ARCHAIONBYZANTINE MUSICAL SYMBOL VAREIAI ARCHAIONBYZANTIN" +
"E MUSICAL SYMBOL APODERMA ARCHAIONBYZANTINE MUSICAL SYMBOL APOTHEMABYZAN" +
"TINE MUSICAL SYMBOL KLASMABYZANTINE MUSICAL SYMBOL REVMABYZANTINE MUSICA" +
"L SYMBOL PIASMA ARCHAIONBYZANTINE MUSICAL SYMBOL TINAGMABYZANTINE MUSICA" +
"L SYMBOL ANATRICHISMABYZANTINE MUSICAL SYMBOL SEISMABYZANTINE MUSICAL SY" +
"MBOL SYNAGMA ARCHAIONBYZANTINE MUSICAL SYMBOL SYNAGMA META STAVROUBYZANT" +
"INE MUSICAL SYMBOL OYRANISMA ARCHAIONBYZANTINE MUSICAL SYMBOL THEMABYZAN" +
"TINE MUSICAL SYMBOL LEMOIBYZANTINE MUSICAL SYMBOL DYOBYZANTINE MUSICAL S" +
"YMBOL TRIABYZANTINE MUSICAL SYMBOL TESSERABYZANTINE MUSICAL SYMBOL KRATI" +
"MATABYZANTINE MUSICAL SYMBOL APESO EXO NEOBYZANTINE MUSICAL SYMBOL FTHOR" +
"A ARCHAIONBYZANTINE MUSICAL SYMBOL IMIFTHORABYZANTINE MUSICAL SYMBOL TRO" +
"MIKON ARCHAIONBYZANTINE MUSICAL SYMBOL KATAVA TROMIKONBYZANTINE MUSICAL " +
"SYMBOL PELASTONBYZANTINE MUSICAL SYMBOL PSIFISTONBYZANTINE MUSICAL SYMBO" +
"L KONTEVMABYZANTINE MUSICAL SYMBOL CHOREVMA ARCHAIONBYZANTINE MUSICAL SY" +
"MBOL RAPISMABYZANTINE MUSICAL SYMBOL PARAKALESMA ARCHAIONBYZANTINE MUSIC" +
"AL SYMBOL PARAKLITIKI ARCHAIONBYZANTINE MUSICAL SYMBOL ICHADINBYZANTINE " +
"MUSICAL SYMBOL NANABYZANTINE MUSICAL SYMBOL PETASMABYZANTINE MUSICAL SYM" +
"BOL KONTEVMA ALLOBYZANTINE MUSICAL SYMBOL TROMIKON ALLOBYZANTINE MUSICAL" +
" SYMBOL STRAGGISMATABYZANTINE MUSICAL SYMBOL GRONTHISMATABYZANTINE MUSIC" +
"AL SYMBOL ISON NEOBYZANTINE MUSICAL SYMBOL OLIGON NEOBYZANTINE MUSICAL S" +
"YMBOL OXEIA NEOBYZANTINE MUSICAL SYMBOL PETASTIBYZANTINE MUSICAL SYMBOL " +
"KOUFISMABYZANTINE MUSICAL SYMBOL PETASTOKOUFISMABYZANTINE MUSICAL SYMBOL" +
" KRATIMOKOUFISMABYZANTINE MUSICAL SYMBOL PELASTON NEOBYZANTINE MUSICAL S" +
"YMBOL KENTIMATA NEO ANOBYZANTINE MUSICAL SYMBOL KENTIMA NEO ANOBYZANTINE" +
" MUSICAL SYMBOL YPSILIBYZANTINE MUSICAL SYMBOL APOSTROFOS NEOBYZANTINE M" +
"USICAL SYMBOL APOSTROFOI SYNDESMOS NEOBYZANTINE MUSICAL SYMBOL YPORROIBY" +
"ZANTINE MUSICAL SYMBOL KRATIMOYPORROONBYZANTINE MUSICAL SYMBOL ELAFRONBY" +
"ZANTINE MUSICAL SYMBOL CHAMILIBYZANTINE MUSICAL SYMBOL MIKRON ISONBYZANT" +
"INE MUSICAL SYMBOL VAREIA NEOBYZANTINE MUSICAL SYMBOL PIASMA NEOBYZANTIN" +
"E MUSICAL SYMBOL PSIFISTON NEOBYZANTINE MUSICAL SYMBOL OMALONBYZANTINE M" +
"USICAL SYMBOL ANTIKENOMABYZANTINE MUSICAL SYMBOL LYGISMABYZANTINE MUSICA" +
"L SYMBOL PARAKLITIKI NEOBYZANTINE MUSICAL SYMBOL PARAKALESMA NEOBYZANTIN" +
"E MUSICAL SYMBOL ETERON PARAKALESMABYZANTINE MUSICAL SYMBOL KYLISMABYZAN" +
"TINE MUSICAL SYMBOL ANTIKENOKYLISMABYZANTINE MUSICAL SYMBOL TROMIKON NEO" +
"BYZANTINE MUSICAL SYMBOL EKSTREPTONBYZANTINE MUSICAL SYMBOL SYNAGMA NEOB" +
"YZANTINE MUSICAL SYMBOL SYRMABYZANTINE MUSICAL SYMBOL CHOREVMA NEOBYZANT" +
"INE MUSICAL SYMBOL EPEGERMABYZANTINE MUSICAL SYMBOL SEISMA NEOBYZANTINE " +
"MUSICAL SYMBOL XIRON KLASMABYZANTINE MUSICAL SYMBOL TROMIKOPSIFISTONBYZA" +
"NTINE MUSICAL SYMBOL PSIFISTOLYGISMABYZANTINE MUSICAL SYMBOL TROMIKOLYGI" +
"SMABYZANTINE MUSICAL SYMBOL TROMIKOPARAKALESMABYZANTINE MUSICAL SYMBOL P" +
"SIFISTOPARAKALESMABYZANTINE MUSICAL SYMBOL TROMIKOSYNAGMABYZANTINE MUSIC" +
"AL SYMBOL PSIFISTOSYNAGMABYZANTINE MUSICAL SYMBOL GORGOSYNTHETONBYZANTIN" +
"E MUSICAL SYMBOL ARGOSYNTHETONBYZANTINE MUSICAL SYMBOL ETERON ARGOSYNTHE" +
"TONBYZANTINE MUSICAL SYMBOL OYRANISMA NEOBYZANTINE MUSICAL SYMBOL THEMAT" +
"ISMOS ESOBYZANTINE MUSICAL SYMBOL THEMATISMOS EXOBYZANTINE MUSICAL SYMBO") + ("" +
"L THEMA APLOUNBYZANTINE MUSICAL SYMBOL THES KAI APOTHESBYZANTINE MUSICAL" +
" SYMBOL KATAVASMABYZANTINE MUSICAL SYMBOL ENDOFONONBYZANTINE MUSICAL SYM" +
"BOL YFEN KATOBYZANTINE MUSICAL SYMBOL YFEN ANOBYZANTINE MUSICAL SYMBOL S" +
"TAVROSBYZANTINE MUSICAL SYMBOL KLASMA ANOBYZANTINE MUSICAL SYMBOL DIPLI " +
"ARCHAIONBYZANTINE MUSICAL SYMBOL KRATIMA ARCHAIONBYZANTINE MUSICAL SYMBO" +
"L KRATIMA ALLOBYZANTINE MUSICAL SYMBOL KRATIMA NEOBYZANTINE MUSICAL SYMB" +
"OL APODERMA NEOBYZANTINE MUSICAL SYMBOL APLIBYZANTINE MUSICAL SYMBOL DIP" +
"LIBYZANTINE MUSICAL SYMBOL TRIPLIBYZANTINE MUSICAL SYMBOL TETRAPLIBYZANT" +
"INE MUSICAL SYMBOL KORONISBYZANTINE MUSICAL SYMBOL LEIMMA ENOS CHRONOUBY" +
"ZANTINE MUSICAL SYMBOL LEIMMA DYO CHRONONBYZANTINE MUSICAL SYMBOL LEIMMA" +
" TRION CHRONONBYZANTINE MUSICAL SYMBOL LEIMMA TESSARON CHRONONBYZANTINE " +
"MUSICAL SYMBOL LEIMMA IMISEOS CHRONOUBYZANTINE MUSICAL SYMBOL GORGON NEO" +
" ANOBYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON ARISTERABYZANTINE MUSI" +
"CAL SYMBOL GORGON PARESTIGMENON DEXIABYZANTINE MUSICAL SYMBOL DIGORGONBY" +
"ZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA KATOBYZANTINE MUS" +
"ICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA ANOBYZANTINE MUSICAL SYMBOL " +
"DIGORGON PARESTIGMENON DEXIABYZANTINE MUSICAL SYMBOL TRIGORGONBYZANTINE " +
"MUSICAL SYMBOL ARGONBYZANTINE MUSICAL SYMBOL IMIDIARGONBYZANTINE MUSICAL" +
" SYMBOL DIARGONBYZANTINE MUSICAL SYMBOL AGOGI POLI ARGIBYZANTINE MUSICAL" +
" SYMBOL AGOGI ARGOTERIBYZANTINE MUSICAL SYMBOL AGOGI ARGIBYZANTINE MUSIC" +
"AL SYMBOL AGOGI METRIABYZANTINE MUSICAL SYMBOL AGOGI MESIBYZANTINE MUSIC" +
"AL SYMBOL AGOGI GORGIBYZANTINE MUSICAL SYMBOL AGOGI GORGOTERIBYZANTINE M" +
"USICAL SYMBOL AGOGI POLI GORGIBYZANTINE MUSICAL SYMBOL MARTYRIA PROTOS I" +
"CHOSBYZANTINE MUSICAL SYMBOL MARTYRIA ALLI PROTOS ICHOSBYZANTINE MUSICAL" +
" SYMBOL MARTYRIA DEYTEROS ICHOSBYZANTINE MUSICAL SYMBOL MARTYRIA ALLI DE" +
"YTEROS ICHOSBYZANTINE MUSICAL SYMBOL MARTYRIA TRITOS ICHOSBYZANTINE MUSI" +
"CAL SYMBOL MARTYRIA TRIFONIASBYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS " +
"ICHOSBYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS LEGETOS ICHOSBYZANTINE M" +
"USICAL SYMBOL MARTYRIA LEGETOS ICHOSBYZANTINE MUSICAL SYMBOL MARTYRIA PL" +
"AGIOS ICHOSBYZANTINE MUSICAL SYMBOL ISAKIA TELOUS ICHIMATOSBYZANTINE MUS" +
"ICAL SYMBOL APOSTROFOI TELOUS ICHIMATOSBYZANTINE MUSICAL SYMBOL FANEROSI" +
"S TETRAFONIASBYZANTINE MUSICAL SYMBOL FANEROSIS MONOFONIASBYZANTINE MUSI" +
"CAL SYMBOL FANEROSIS DIFONIASBYZANTINE MUSICAL SYMBOL MARTYRIA VARYS ICH" +
"OSBYZANTINE MUSICAL SYMBOL MARTYRIA PROTOVARYS ICHOSBYZANTINE MUSICAL SY" +
"MBOL MARTYRIA PLAGIOS TETARTOS ICHOSBYZANTINE MUSICAL SYMBOL GORTHMIKON " +
"N APLOUNBYZANTINE MUSICAL SYMBOL GORTHMIKON N DIPLOUNBYZANTINE MUSICAL S" +
"YMBOL ENARXIS KAI FTHORA VOUBYZANTINE MUSICAL SYMBOL IMIFONONBYZANTINE M" +
"USICAL SYMBOL IMIFTHORONBYZANTINE MUSICAL SYMBOL FTHORA ARCHAION DEYTERO" +
"U ICHOUBYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI PABYZANTINE MUSICAL SYM" +
"BOL FTHORA DIATONIKI NANABYZANTINE MUSICAL SYMBOL FTHORA NAOS ICHOSBYZAN" +
"TINE MUSICAL SYMBOL FTHORA DIATONIKI DIBYZANTINE MUSICAL SYMBOL FTHORA S" +
"KLIRON DIATONON DIBYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI KEBYZANTINE " +
"MUSICAL SYMBOL FTHORA DIATONIKI ZOBYZANTINE MUSICAL SYMBOL FTHORA DIATON" +
"IKI NI KATOBYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI ANOBYZANTINE MUS" +
"ICAL SYMBOL FTHORA MALAKON CHROMA DIFONIASBYZANTINE MUSICAL SYMBOL FTHOR" +
"A MALAKON CHROMA MONOFONIASBYZANTINE MUSICAL SYMBOL FHTORA SKLIRON CHROM" +
"A VASISBYZANTINE MUSICAL SYMBOL FTHORA SKLIRON CHROMA SYNAFIBYZANTINE MU" +
"SICAL SYMBOL FTHORA NENANOBYZANTINE MUSICAL SYMBOL CHROA ZYGOSBYZANTINE " +
"MUSICAL SYMBOL CHROA KLITONBYZANTINE MUSICAL SYMBOL CHROA SPATHIBYZANTIN" +
"E MUSICAL SYMBOL FTHORA I YFESIS TETARTIMORIONBYZANTINE MUSICAL SYMBOL F" +
"THORA ENARMONIOS ANTIFONIABYZANTINE MUSICAL SYMBOL YFESIS TRITIMORIONBYZ" +
"ANTINE MUSICAL SYMBOL DIESIS TRITIMORIONBYZANTINE MUSICAL SYMBOL DIESIS " +
"TETARTIMORIONBYZANTINE MUSICAL SYMBOL DIESIS APLI DYO DODEKATABYZANTINE " +
"MUSICAL SYMBOL DIESIS MONOGRAMMOS TESSERA DODEKATABYZANTINE MUSICAL SYMB" +
"OL DIESIS DIGRAMMOS EX DODEKATABYZANTINE MUSICAL SYMBOL DIESIS TRIGRAMMO" +
"S OKTO DODEKATABYZANTINE MUSICAL SYMBOL YFESIS APLI DYO DODEKATABYZANTIN" +
"E MUSICAL SYMBOL YFESIS MONOGRAMMOS TESSERA DODEKATABYZANTINE MUSICAL SY" +
"MBOL YFESIS DIGRAMMOS EX DODEKATABYZANTINE MUSICAL SYMBOL YFESIS TRIGRAM" +
"MOS OKTO DODEKATABYZANTINE MUSICAL SYMBOL GENIKI DIESISBYZANTINE MUSICAL" +
" SYMBOL GENIKI YFESISBYZANTINE MUSICAL SYMBOL DIASTOLI APLI MIKRIBYZANTI" +
"NE MUSICAL SYMBOL DIASTOLI APLI MEGALIBYZANTINE MUSICAL SYMBOL DIASTOLI " +
"DIPLIBYZANTINE MUSICAL SYMBOL DIASTOLI THESEOSBYZANTINE MUSICAL SYMBOL S" +
"IMANSIS THESEOSBYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS DISIMOUBYZANTIN" +
"E MUSICAL SYMBOL SIMANSIS THESEOS TRISIMOUBYZANTINE MUSICAL SYMBOL SIMAN") + ("" +
"SIS THESEOS TETRASIMOUBYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOSBYZANTINE " +
"MUSICAL SYMBOL SIMANSIS ARSEOS DISIMOUBYZANTINE MUSICAL SYMBOL SIMANSIS " +
"ARSEOS TRISIMOUBYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TETRASIMOUBYZANT" +
"INE MUSICAL SYMBOL DIGRAMMA GGBYZANTINE MUSICAL SYMBOL DIFTOGGOS OUBYZAN" +
"TINE MUSICAL SYMBOL STIGMABYZANTINE MUSICAL SYMBOL ARKTIKO PABYZANTINE M" +
"USICAL SYMBOL ARKTIKO VOUBYZANTINE MUSICAL SYMBOL ARKTIKO GABYZANTINE MU" +
"SICAL SYMBOL ARKTIKO DIBYZANTINE MUSICAL SYMBOL ARKTIKO KEBYZANTINE MUSI" +
"CAL SYMBOL ARKTIKO ZOBYZANTINE MUSICAL SYMBOL ARKTIKO NIBYZANTINE MUSICA" +
"L SYMBOL KENTIMATA NEO MESOBYZANTINE MUSICAL SYMBOL KENTIMA NEO MESOBYZA" +
"NTINE MUSICAL SYMBOL KENTIMATA NEO KATOBYZANTINE MUSICAL SYMBOL KENTIMA " +
"NEO KATOBYZANTINE MUSICAL SYMBOL KLASMA KATOBYZANTINE MUSICAL SYMBOL GOR" +
"GON NEO KATOMUSICAL SYMBOL SINGLE BARLINEMUSICAL SYMBOL DOUBLE BARLINEMU" +
"SICAL SYMBOL FINAL BARLINEMUSICAL SYMBOL REVERSE FINAL BARLINEMUSICAL SY" +
"MBOL DASHED BARLINEMUSICAL SYMBOL SHORT BARLINEMUSICAL SYMBOL LEFT REPEA" +
"T SIGNMUSICAL SYMBOL RIGHT REPEAT SIGNMUSICAL SYMBOL REPEAT DOTSMUSICAL " +
"SYMBOL DAL SEGNOMUSICAL SYMBOL DA CAPOMUSICAL SYMBOL SEGNOMUSICAL SYMBOL" +
" CODAMUSICAL SYMBOL REPEATED FIGURE-1MUSICAL SYMBOL REPEATED FIGURE-2MUS" +
"ICAL SYMBOL REPEATED FIGURE-3MUSICAL SYMBOL FERMATAMUSICAL SYMBOL FERMAT" +
"A BELOWMUSICAL SYMBOL BREATH MARKMUSICAL SYMBOL CAESURAMUSICAL SYMBOL BR" +
"ACEMUSICAL SYMBOL BRACKETMUSICAL SYMBOL ONE-LINE STAFFMUSICAL SYMBOL TWO" +
"-LINE STAFFMUSICAL SYMBOL THREE-LINE STAFFMUSICAL SYMBOL FOUR-LINE STAFF" +
"MUSICAL SYMBOL FIVE-LINE STAFFMUSICAL SYMBOL SIX-LINE STAFFMUSICAL SYMBO" +
"L SIX-STRING FRETBOARDMUSICAL SYMBOL FOUR-STRING FRETBOARDMUSICAL SYMBOL" +
" G CLEFMUSICAL SYMBOL G CLEF OTTAVA ALTAMUSICAL SYMBOL G CLEF OTTAVA BAS" +
"SAMUSICAL SYMBOL C CLEFMUSICAL SYMBOL F CLEFMUSICAL SYMBOL F CLEF OTTAVA" +
" ALTAMUSICAL SYMBOL F CLEF OTTAVA BASSAMUSICAL SYMBOL DRUM CLEF-1MUSICAL" +
" SYMBOL DRUM CLEF-2MUSICAL SYMBOL MULTIPLE MEASURE RESTMUSICAL SYMBOL DO" +
"UBLE SHARPMUSICAL SYMBOL DOUBLE FLATMUSICAL SYMBOL FLAT UPMUSICAL SYMBOL" +
" FLAT DOWNMUSICAL SYMBOL NATURAL UPMUSICAL SYMBOL NATURAL DOWNMUSICAL SY" +
"MBOL SHARP UPMUSICAL SYMBOL SHARP DOWNMUSICAL SYMBOL QUARTER TONE SHARPM" +
"USICAL SYMBOL QUARTER TONE FLATMUSICAL SYMBOL COMMON TIMEMUSICAL SYMBOL " +
"CUT TIMEMUSICAL SYMBOL OTTAVA ALTAMUSICAL SYMBOL OTTAVA BASSAMUSICAL SYM" +
"BOL QUINDICESIMA ALTAMUSICAL SYMBOL QUINDICESIMA BASSAMUSICAL SYMBOL MUL" +
"TI RESTMUSICAL SYMBOL WHOLE RESTMUSICAL SYMBOL HALF RESTMUSICAL SYMBOL Q" +
"UARTER RESTMUSICAL SYMBOL EIGHTH RESTMUSICAL SYMBOL SIXTEENTH RESTMUSICA" +
"L SYMBOL THIRTY-SECOND RESTMUSICAL SYMBOL SIXTY-FOURTH RESTMUSICAL SYMBO" +
"L ONE HUNDRED TWENTY-EIGHTH RESTMUSICAL SYMBOL X NOTEHEADMUSICAL SYMBOL " +
"PLUS NOTEHEADMUSICAL SYMBOL CIRCLE X NOTEHEADMUSICAL SYMBOL SQUARE NOTEH" +
"EAD WHITEMUSICAL SYMBOL SQUARE NOTEHEAD BLACKMUSICAL SYMBOL TRIANGLE NOT" +
"EHEAD UP WHITEMUSICAL SYMBOL TRIANGLE NOTEHEAD UP BLACKMUSICAL SYMBOL TR" +
"IANGLE NOTEHEAD LEFT WHITEMUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT BLACKMUS" +
"ICAL SYMBOL TRIANGLE NOTEHEAD RIGHT WHITEMUSICAL SYMBOL TRIANGLE NOTEHEA" +
"D RIGHT BLACKMUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN WHITEMUSICAL SYMBOL T" +
"RIANGLE NOTEHEAD DOWN BLACKMUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT WHI" +
"TEMUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT BLACKMUSICAL SYMBOL MOON NOT" +
"EHEAD WHITEMUSICAL SYMBOL MOON NOTEHEAD BLACKMUSICAL SYMBOL TRIANGLE-ROU" +
"ND NOTEHEAD DOWN WHITEMUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN BLACKM" +
"USICAL SYMBOL PARENTHESIS NOTEHEADMUSICAL SYMBOL VOID NOTEHEADMUSICAL SY" +
"MBOL NOTEHEAD BLACKMUSICAL SYMBOL NULL NOTEHEADMUSICAL SYMBOL CLUSTER NO" +
"TEHEAD WHITEMUSICAL SYMBOL CLUSTER NOTEHEAD BLACKMUSICAL SYMBOL BREVEMUS" +
"ICAL SYMBOL WHOLE NOTEMUSICAL SYMBOL HALF NOTEMUSICAL SYMBOL QUARTER NOT" +
"EMUSICAL SYMBOL EIGHTH NOTEMUSICAL SYMBOL SIXTEENTH NOTEMUSICAL SYMBOL T" +
"HIRTY-SECOND NOTEMUSICAL SYMBOL SIXTY-FOURTH NOTEMUSICAL SYMBOL ONE HUND" +
"RED TWENTY-EIGHTH NOTEMUSICAL SYMBOL COMBINING STEMMUSICAL SYMBOL COMBIN" +
"ING SPRECHGESANG STEMMUSICAL SYMBOL COMBINING TREMOLO-1MUSICAL SYMBOL CO" +
"MBINING TREMOLO-2MUSICAL SYMBOL COMBINING TREMOLO-3MUSICAL SYMBOL FINGER" +
"ED TREMOLO-1MUSICAL SYMBOL FINGERED TREMOLO-2MUSICAL SYMBOL FINGERED TRE" +
"MOLO-3MUSICAL SYMBOL COMBINING AUGMENTATION DOTMUSICAL SYMBOL COMBINING " +
"FLAG-1MUSICAL SYMBOL COMBINING FLAG-2MUSICAL SYMBOL COMBINING FLAG-3MUSI" +
"CAL SYMBOL COMBINING FLAG-4MUSICAL SYMBOL COMBINING FLAG-5MUSICAL SYMBOL" +
" BEGIN BEAMMUSICAL SYMBOL END BEAMMUSICAL SYMBOL BEGIN TIEMUSICAL SYMBOL" +
" END TIEMUSICAL SYMBOL BEGIN SLURMUSICAL SYMBOL END SLURMUSICAL SYMBOL B" +
"EGIN PHRASEMUSICAL SYMBOL END PHRASEMUSICAL SYMBOL COMBINING ACCENTMUSIC" +
"AL SYMBOL COMBINING STACCATOMUSICAL SYMBOL COMBINING TENUTOMUSICAL SYMBO") + ("" +
"L COMBINING STACCATISSIMOMUSICAL SYMBOL COMBINING MARCATOMUSICAL SYMBOL " +
"COMBINING MARCATO-STACCATOMUSICAL SYMBOL COMBINING ACCENT-STACCATOMUSICA" +
"L SYMBOL COMBINING LOUREMUSICAL SYMBOL ARPEGGIATO UPMUSICAL SYMBOL ARPEG" +
"GIATO DOWNMUSICAL SYMBOL COMBINING DOITMUSICAL SYMBOL COMBINING RIPMUSIC" +
"AL SYMBOL COMBINING FLIPMUSICAL SYMBOL COMBINING SMEARMUSICAL SYMBOL COM" +
"BINING BENDMUSICAL SYMBOL COMBINING DOUBLE TONGUEMUSICAL SYMBOL COMBININ" +
"G TRIPLE TONGUEMUSICAL SYMBOL RINFORZANDOMUSICAL SYMBOL SUBITOMUSICAL SY" +
"MBOL ZMUSICAL SYMBOL PIANOMUSICAL SYMBOL MEZZOMUSICAL SYMBOL FORTEMUSICA" +
"L SYMBOL CRESCENDOMUSICAL SYMBOL DECRESCENDOMUSICAL SYMBOL GRACE NOTE SL" +
"ASHMUSICAL SYMBOL GRACE NOTE NO SLASHMUSICAL SYMBOL TRMUSICAL SYMBOL TUR" +
"NMUSICAL SYMBOL INVERTED TURNMUSICAL SYMBOL TURN SLASHMUSICAL SYMBOL TUR" +
"N UPMUSICAL SYMBOL ORNAMENT STROKE-1MUSICAL SYMBOL ORNAMENT STROKE-2MUSI" +
"CAL SYMBOL ORNAMENT STROKE-3MUSICAL SYMBOL ORNAMENT STROKE-4MUSICAL SYMB" +
"OL ORNAMENT STROKE-5MUSICAL SYMBOL ORNAMENT STROKE-6MUSICAL SYMBOL ORNAM" +
"ENT STROKE-7MUSICAL SYMBOL ORNAMENT STROKE-8MUSICAL SYMBOL ORNAMENT STRO" +
"KE-9MUSICAL SYMBOL ORNAMENT STROKE-10MUSICAL SYMBOL ORNAMENT STROKE-11MU" +
"SICAL SYMBOL HAUPTSTIMMEMUSICAL SYMBOL NEBENSTIMMEMUSICAL SYMBOL END OF " +
"STIMMEMUSICAL SYMBOL DEGREE SLASHMUSICAL SYMBOL COMBINING DOWN BOWMUSICA" +
"L SYMBOL COMBINING UP BOWMUSICAL SYMBOL COMBINING HARMONICMUSICAL SYMBOL" +
" COMBINING SNAP PIZZICATOMUSICAL SYMBOL PEDAL MARKMUSICAL SYMBOL PEDAL U" +
"P MARKMUSICAL SYMBOL HALF PEDAL MARKMUSICAL SYMBOL GLISSANDO UPMUSICAL S" +
"YMBOL GLISSANDO DOWNMUSICAL SYMBOL WITH FINGERNAILSMUSICAL SYMBOL DAMPMU" +
"SICAL SYMBOL DAMP ALLMUSICAL SYMBOL MAXIMAMUSICAL SYMBOL LONGAMUSICAL SY" +
"MBOL BREVISMUSICAL SYMBOL SEMIBREVIS WHITEMUSICAL SYMBOL SEMIBREVIS BLAC" +
"KMUSICAL SYMBOL MINIMAMUSICAL SYMBOL MINIMA BLACKMUSICAL SYMBOL SEMIMINI" +
"MA WHITEMUSICAL SYMBOL SEMIMINIMA BLACKMUSICAL SYMBOL FUSA WHITEMUSICAL " +
"SYMBOL FUSA BLACKMUSICAL SYMBOL LONGA PERFECTA RESTMUSICAL SYMBOL LONGA " +
"IMPERFECTA RESTMUSICAL SYMBOL BREVIS RESTMUSICAL SYMBOL SEMIBREVIS RESTM" +
"USICAL SYMBOL MINIMA RESTMUSICAL SYMBOL SEMIMINIMA RESTMUSICAL SYMBOL TE" +
"MPUS PERFECTUM CUM PROLATIONE PERFECTAMUSICAL SYMBOL TEMPUS PERFECTUM CU" +
"M PROLATIONE IMPERFECTAMUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PE" +
"RFECTA DIMINUTION-1MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE PERF" +
"ECTAMUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTAMUSICAL S" +
"YMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-1MUSICAL S" +
"YMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-2MUSICAL S" +
"YMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-3MUSICAL S" +
"YMBOL CROIXMUSICAL SYMBOL GREGORIAN C CLEFMUSICAL SYMBOL GREGORIAN F CLE" +
"FMUSICAL SYMBOL SQUARE BMUSICAL SYMBOL VIRGAMUSICAL SYMBOL PODATUSMUSICA" +
"L SYMBOL CLIVISMUSICAL SYMBOL SCANDICUSMUSICAL SYMBOL CLIMACUSMUSICAL SY" +
"MBOL TORCULUSMUSICAL SYMBOL PORRECTUSMUSICAL SYMBOL PORRECTUS FLEXUSMUSI" +
"CAL SYMBOL SCANDICUS FLEXUSMUSICAL SYMBOL TORCULUS RESUPINUSMUSICAL SYMB" +
"OL PES SUBPUNCTISMUSICAL SYMBOL KIEVAN C CLEFMUSICAL SYMBOL KIEVAN END O" +
"F PIECEMUSICAL SYMBOL KIEVAN FINAL NOTEMUSICAL SYMBOL KIEVAN RECITATIVE " +
"MARKMUSICAL SYMBOL KIEVAN WHOLE NOTEMUSICAL SYMBOL KIEVAN HALF NOTEMUSIC" +
"AL SYMBOL KIEVAN QUARTER NOTE STEM DOWNMUSICAL SYMBOL KIEVAN QUARTER NOT" +
"E STEM UPMUSICAL SYMBOL KIEVAN EIGHTH NOTE STEM DOWNMUSICAL SYMBOL KIEVA" +
"N EIGHTH NOTE STEM UPMUSICAL SYMBOL KIEVAN FLAT SIGNMUSICAL SYMBOL SORIM" +
"USICAL SYMBOL KORONGREEK VOCAL NOTATION SYMBOL-1GREEK VOCAL NOTATION SYM" +
"BOL-2GREEK VOCAL NOTATION SYMBOL-3GREEK VOCAL NOTATION SYMBOL-4GREEK VOC" +
"AL NOTATION SYMBOL-5GREEK VOCAL NOTATION SYMBOL-6GREEK VOCAL NOTATION SY" +
"MBOL-7GREEK VOCAL NOTATION SYMBOL-8GREEK VOCAL NOTATION SYMBOL-9GREEK VO" +
"CAL NOTATION SYMBOL-10GREEK VOCAL NOTATION SYMBOL-11GREEK VOCAL NOTATION" +
" SYMBOL-12GREEK VOCAL NOTATION SYMBOL-13GREEK VOCAL NOTATION SYMBOL-14GR" +
"EEK VOCAL NOTATION SYMBOL-15GREEK VOCAL NOTATION SYMBOL-16GREEK VOCAL NO" +
"TATION SYMBOL-17GREEK VOCAL NOTATION SYMBOL-18GREEK VOCAL NOTATION SYMBO" +
"L-19GREEK VOCAL NOTATION SYMBOL-20GREEK VOCAL NOTATION SYMBOL-21GREEK VO" +
"CAL NOTATION SYMBOL-22GREEK VOCAL NOTATION SYMBOL-23GREEK VOCAL NOTATION" +
" SYMBOL-24GREEK VOCAL NOTATION SYMBOL-50GREEK VOCAL NOTATION SYMBOL-51GR" +
"EEK VOCAL NOTATION SYMBOL-52GREEK VOCAL NOTATION SYMBOL-53GREEK VOCAL NO" +
"TATION SYMBOL-54GREEK INSTRUMENTAL NOTATION SYMBOL-1GREEK INSTRUMENTAL N" +
"OTATION SYMBOL-2GREEK INSTRUMENTAL NOTATION SYMBOL-4GREEK INSTRUMENTAL N" +
"OTATION SYMBOL-5GREEK INSTRUMENTAL NOTATION SYMBOL-7GREEK INSTRUMENTAL N" +
"OTATION SYMBOL-8GREEK INSTRUMENTAL NOTATION SYMBOL-11GREEK INSTRUMENTAL " +
"NOTATION SYMBOL-12GREEK INSTRUMENTAL NOTATION SYMBOL-13GREEK INSTRUMENTA") + ("" +
"L NOTATION SYMBOL-14GREEK INSTRUMENTAL NOTATION SYMBOL-17GREEK INSTRUMEN" +
"TAL NOTATION SYMBOL-18GREEK INSTRUMENTAL NOTATION SYMBOL-19GREEK INSTRUM" +
"ENTAL NOTATION SYMBOL-23GREEK INSTRUMENTAL NOTATION SYMBOL-24GREEK INSTR" +
"UMENTAL NOTATION SYMBOL-25GREEK INSTRUMENTAL NOTATION SYMBOL-26GREEK INS" +
"TRUMENTAL NOTATION SYMBOL-27GREEK INSTRUMENTAL NOTATION SYMBOL-29GREEK I" +
"NSTRUMENTAL NOTATION SYMBOL-30GREEK INSTRUMENTAL NOTATION SYMBOL-32GREEK" +
" INSTRUMENTAL NOTATION SYMBOL-36GREEK INSTRUMENTAL NOTATION SYMBOL-37GRE" +
"EK INSTRUMENTAL NOTATION SYMBOL-38GREEK INSTRUMENTAL NOTATION SYMBOL-39G" +
"REEK INSTRUMENTAL NOTATION SYMBOL-40GREEK INSTRUMENTAL NOTATION SYMBOL-4" +
"2GREEK INSTRUMENTAL NOTATION SYMBOL-43GREEK INSTRUMENTAL NOTATION SYMBOL" +
"-45GREEK INSTRUMENTAL NOTATION SYMBOL-47GREEK INSTRUMENTAL NOTATION SYMB" +
"OL-48GREEK INSTRUMENTAL NOTATION SYMBOL-49GREEK INSTRUMENTAL NOTATION SY" +
"MBOL-50GREEK INSTRUMENTAL NOTATION SYMBOL-51GREEK INSTRUMENTAL NOTATION " +
"SYMBOL-52GREEK INSTRUMENTAL NOTATION SYMBOL-53GREEK INSTRUMENTAL NOTATIO" +
"N SYMBOL-54COMBINING GREEK MUSICAL TRISEMECOMBINING GREEK MUSICAL TETRAS" +
"EMECOMBINING GREEK MUSICAL PENTASEMEGREEK MUSICAL LEIMMAKAKTOVIK NUMERAL" +
" ZEROKAKTOVIK NUMERAL ONEKAKTOVIK NUMERAL TWOKAKTOVIK NUMERAL THREEKAKTO" +
"VIK NUMERAL FOURKAKTOVIK NUMERAL FIVEKAKTOVIK NUMERAL SIXKAKTOVIK NUMERA" +
"L SEVENKAKTOVIK NUMERAL EIGHTKAKTOVIK NUMERAL NINEKAKTOVIK NUMERAL TENKA" +
"KTOVIK NUMERAL ELEVENKAKTOVIK NUMERAL TWELVEKAKTOVIK NUMERAL THIRTEENKAK" +
"TOVIK NUMERAL FOURTEENKAKTOVIK NUMERAL FIFTEENKAKTOVIK NUMERAL SIXTEENKA" +
"KTOVIK NUMERAL SEVENTEENKAKTOVIK NUMERAL EIGHTEENKAKTOVIK NUMERAL NINETE" +
"ENMAYAN NUMERAL ZEROMAYAN NUMERAL ONEMAYAN NUMERAL TWOMAYAN NUMERAL THRE" +
"EMAYAN NUMERAL FOURMAYAN NUMERAL FIVEMAYAN NUMERAL SIXMAYAN NUMERAL SEVE" +
"NMAYAN NUMERAL EIGHTMAYAN NUMERAL NINEMAYAN NUMERAL TENMAYAN NUMERAL ELE" +
"VENMAYAN NUMERAL TWELVEMAYAN NUMERAL THIRTEENMAYAN NUMERAL FOURTEENMAYAN" +
" NUMERAL FIFTEENMAYAN NUMERAL SIXTEENMAYAN NUMERAL SEVENTEENMAYAN NUMERA" +
"L EIGHTEENMAYAN NUMERAL NINETEENMONOGRAM FOR EARTHDIGRAM FOR HEAVENLY EA" +
"RTHDIGRAM FOR HUMAN EARTHDIGRAM FOR EARTHLY HEAVENDIGRAM FOR EARTHLY HUM" +
"ANDIGRAM FOR EARTHTETRAGRAM FOR CENTRETETRAGRAM FOR FULL CIRCLETETRAGRAM" +
" FOR MIREDTETRAGRAM FOR BARRIERTETRAGRAM FOR KEEPING SMALLTETRAGRAM FOR " +
"CONTRARIETYTETRAGRAM FOR ASCENTTETRAGRAM FOR OPPOSITIONTETRAGRAM FOR BRA" +
"NCHING OUTTETRAGRAM FOR DEFECTIVENESS OR DISTORTIONTETRAGRAM FOR DIVERGE" +
"NCETETRAGRAM FOR YOUTHFULNESSTETRAGRAM FOR INCREASETETRAGRAM FOR PENETRA" +
"TIONTETRAGRAM FOR REACHTETRAGRAM FOR CONTACTTETRAGRAM FOR HOLDING BACKTE" +
"TRAGRAM FOR WAITINGTETRAGRAM FOR FOLLOWINGTETRAGRAM FOR ADVANCETETRAGRAM" +
" FOR RELEASETETRAGRAM FOR RESISTANCETETRAGRAM FOR EASETETRAGRAM FOR JOYT" +
"ETRAGRAM FOR CONTENTIONTETRAGRAM FOR ENDEAVOURTETRAGRAM FOR DUTIESTETRAG" +
"RAM FOR CHANGETETRAGRAM FOR DECISIVENESSTETRAGRAM FOR BOLD RESOLUTIONTET" +
"RAGRAM FOR PACKINGTETRAGRAM FOR LEGIONTETRAGRAM FOR CLOSENESSTETRAGRAM F" +
"OR KINSHIPTETRAGRAM FOR GATHERINGTETRAGRAM FOR STRENGTHTETRAGRAM FOR PUR" +
"ITYTETRAGRAM FOR FULLNESSTETRAGRAM FOR RESIDENCETETRAGRAM FOR LAW OR MOD" +
"ELTETRAGRAM FOR RESPONSETETRAGRAM FOR GOING TO MEETTETRAGRAM FOR ENCOUNT" +
"ERSTETRAGRAM FOR STOVETETRAGRAM FOR GREATNESSTETRAGRAM FOR ENLARGEMENTTE" +
"TRAGRAM FOR PATTERNTETRAGRAM FOR RITUALTETRAGRAM FOR FLIGHTTETRAGRAM FOR" +
" VASTNESS OR WASTINGTETRAGRAM FOR CONSTANCYTETRAGRAM FOR MEASURETETRAGRA" +
"M FOR ETERNITYTETRAGRAM FOR UNITYTETRAGRAM FOR DIMINISHMENTTETRAGRAM FOR" +
" CLOSED MOUTHTETRAGRAM FOR GUARDEDNESSTETRAGRAM FOR GATHERING INTETRAGRA" +
"M FOR MASSINGTETRAGRAM FOR ACCUMULATIONTETRAGRAM FOR EMBELLISHMENTTETRAG" +
"RAM FOR DOUBTTETRAGRAM FOR WATCHTETRAGRAM FOR SINKINGTETRAGRAM FOR INNER" +
"TETRAGRAM FOR DEPARTURETETRAGRAM FOR DARKENINGTETRAGRAM FOR DIMMINGTETRA" +
"GRAM FOR EXHAUSTIONTETRAGRAM FOR SEVERANCETETRAGRAM FOR STOPPAGETETRAGRA" +
"M FOR HARDNESSTETRAGRAM FOR COMPLETIONTETRAGRAM FOR CLOSURETETRAGRAM FOR" +
" FAILURETETRAGRAM FOR AGGRAVATIONTETRAGRAM FOR COMPLIANCETETRAGRAM FOR O" +
"N THE VERGETETRAGRAM FOR DIFFICULTIESTETRAGRAM FOR LABOURINGTETRAGRAM FO" +
"R FOSTERINGCOUNTING ROD UNIT DIGIT ONECOUNTING ROD UNIT DIGIT TWOCOUNTIN" +
"G ROD UNIT DIGIT THREECOUNTING ROD UNIT DIGIT FOURCOUNTING ROD UNIT DIGI" +
"T FIVECOUNTING ROD UNIT DIGIT SIXCOUNTING ROD UNIT DIGIT SEVENCOUNTING R" +
"OD UNIT DIGIT EIGHTCOUNTING ROD UNIT DIGIT NINECOUNTING ROD TENS DIGIT O" +
"NECOUNTING ROD TENS DIGIT TWOCOUNTING ROD TENS DIGIT THREECOUNTING ROD T" +
"ENS DIGIT FOURCOUNTING ROD TENS DIGIT FIVECOUNTING ROD TENS DIGIT SIXCOU" +
"NTING ROD TENS DIGIT SEVENCOUNTING ROD TENS DIGIT EIGHTCOUNTING ROD TENS" +
" DIGIT NINEIDEOGRAPHIC TALLY MARK ONEIDEOGRAPHIC TALLY MARK TWOIDEOGRAPH" +
"IC TALLY MARK THREEIDEOGRAPHIC TALLY MARK FOURIDEOGRAPHIC TALLY MARK FIV") + ("" +
"ETALLY MARK ONETALLY MARK FIVEMATHEMATICAL BOLD CAPITAL AMATHEMATICAL BO" +
"LD CAPITAL BMATHEMATICAL BOLD CAPITAL CMATHEMATICAL BOLD CAPITAL DMATHEM" +
"ATICAL BOLD CAPITAL EMATHEMATICAL BOLD CAPITAL FMATHEMATICAL BOLD CAPITA" +
"L GMATHEMATICAL BOLD CAPITAL HMATHEMATICAL BOLD CAPITAL IMATHEMATICAL BO" +
"LD CAPITAL JMATHEMATICAL BOLD CAPITAL KMATHEMATICAL BOLD CAPITAL LMATHEM" +
"ATICAL BOLD CAPITAL MMATHEMATICAL BOLD CAPITAL NMATHEMATICAL BOLD CAPITA" +
"L OMATHEMATICAL BOLD CAPITAL PMATHEMATICAL BOLD CAPITAL QMATHEMATICAL BO" +
"LD CAPITAL RMATHEMATICAL BOLD CAPITAL SMATHEMATICAL BOLD CAPITAL TMATHEM" +
"ATICAL BOLD CAPITAL UMATHEMATICAL BOLD CAPITAL VMATHEMATICAL BOLD CAPITA" +
"L WMATHEMATICAL BOLD CAPITAL XMATHEMATICAL BOLD CAPITAL YMATHEMATICAL BO" +
"LD CAPITAL ZMATHEMATICAL BOLD SMALL AMATHEMATICAL BOLD SMALL BMATHEMATIC" +
"AL BOLD SMALL CMATHEMATICAL BOLD SMALL DMATHEMATICAL BOLD SMALL EMATHEMA" +
"TICAL BOLD SMALL FMATHEMATICAL BOLD SMALL GMATHEMATICAL BOLD SMALL HMATH" +
"EMATICAL BOLD SMALL IMATHEMATICAL BOLD SMALL JMATHEMATICAL BOLD SMALL KM" +
"ATHEMATICAL BOLD SMALL LMATHEMATICAL BOLD SMALL MMATHEMATICAL BOLD SMALL" +
" NMATHEMATICAL BOLD SMALL OMATHEMATICAL BOLD SMALL PMATHEMATICAL BOLD SM" +
"ALL QMATHEMATICAL BOLD SMALL RMATHEMATICAL BOLD SMALL SMATHEMATICAL BOLD" +
" SMALL TMATHEMATICAL BOLD SMALL UMATHEMATICAL BOLD SMALL VMATHEMATICAL B" +
"OLD SMALL WMATHEMATICAL BOLD SMALL XMATHEMATICAL BOLD SMALL YMATHEMATICA" +
"L BOLD SMALL ZMATHEMATICAL ITALIC CAPITAL AMATHEMATICAL ITALIC CAPITAL B" +
"MATHEMATICAL ITALIC CAPITAL CMATHEMATICAL ITALIC CAPITAL DMATHEMATICAL I" +
"TALIC CAPITAL EMATHEMATICAL ITALIC CAPITAL FMATHEMATICAL ITALIC CAPITAL " +
"GMATHEMATICAL ITALIC CAPITAL HMATHEMATICAL ITALIC CAPITAL IMATHEMATICAL " +
"ITALIC CAPITAL JMATHEMATICAL ITALIC CAPITAL KMATHEMATICAL ITALIC CAPITAL" +
" LMATHEMATICAL ITALIC CAPITAL MMATHEMATICAL ITALIC CAPITAL NMATHEMATICAL" +
" ITALIC CAPITAL OMATHEMATICAL ITALIC CAPITAL PMATHEMATICAL ITALIC CAPITA" +
"L QMATHEMATICAL ITALIC CAPITAL RMATHEMATICAL ITALIC CAPITAL SMATHEMATICA" +
"L ITALIC CAPITAL TMATHEMATICAL ITALIC CAPITAL UMATHEMATICAL ITALIC CAPIT" +
"AL VMATHEMATICAL ITALIC CAPITAL WMATHEMATICAL ITALIC CAPITAL XMATHEMATIC" +
"AL ITALIC CAPITAL YMATHEMATICAL ITALIC CAPITAL ZMATHEMATICAL ITALIC SMAL" +
"L AMATHEMATICAL ITALIC SMALL BMATHEMATICAL ITALIC SMALL CMATHEMATICAL IT" +
"ALIC SMALL DMATHEMATICAL ITALIC SMALL EMATHEMATICAL ITALIC SMALL FMATHEM" +
"ATICAL ITALIC SMALL GMATHEMATICAL ITALIC SMALL IMATHEMATICAL ITALIC SMAL" +
"L JMATHEMATICAL ITALIC SMALL KMATHEMATICAL ITALIC SMALL LMATHEMATICAL IT" +
"ALIC SMALL MMATHEMATICAL ITALIC SMALL NMATHEMATICAL ITALIC SMALL OMATHEM" +
"ATICAL ITALIC SMALL PMATHEMATICAL ITALIC SMALL QMATHEMATICAL ITALIC SMAL" +
"L RMATHEMATICAL ITALIC SMALL SMATHEMATICAL ITALIC SMALL TMATHEMATICAL IT" +
"ALIC SMALL UMATHEMATICAL ITALIC SMALL VMATHEMATICAL ITALIC SMALL WMATHEM" +
"ATICAL ITALIC SMALL XMATHEMATICAL ITALIC SMALL YMATHEMATICAL ITALIC SMAL" +
"L ZMATHEMATICAL BOLD ITALIC CAPITAL AMATHEMATICAL BOLD ITALIC CAPITAL BM" +
"ATHEMATICAL BOLD ITALIC CAPITAL CMATHEMATICAL BOLD ITALIC CAPITAL DMATHE" +
"MATICAL BOLD ITALIC CAPITAL EMATHEMATICAL BOLD ITALIC CAPITAL FMATHEMATI" +
"CAL BOLD ITALIC CAPITAL GMATHEMATICAL BOLD ITALIC CAPITAL HMATHEMATICAL " +
"BOLD ITALIC CAPITAL IMATHEMATICAL BOLD ITALIC CAPITAL JMATHEMATICAL BOLD" +
" ITALIC CAPITAL KMATHEMATICAL BOLD ITALIC CAPITAL LMATHEMATICAL BOLD ITA" +
"LIC CAPITAL MMATHEMATICAL BOLD ITALIC CAPITAL NMATHEMATICAL BOLD ITALIC " +
"CAPITAL OMATHEMATICAL BOLD ITALIC CAPITAL PMATHEMATICAL BOLD ITALIC CAPI" +
"TAL QMATHEMATICAL BOLD ITALIC CAPITAL RMATHEMATICAL BOLD ITALIC CAPITAL " +
"SMATHEMATICAL BOLD ITALIC CAPITAL TMATHEMATICAL BOLD ITALIC CAPITAL UMAT" +
"HEMATICAL BOLD ITALIC CAPITAL VMATHEMATICAL BOLD ITALIC CAPITAL WMATHEMA" +
"TICAL BOLD ITALIC CAPITAL XMATHEMATICAL BOLD ITALIC CAPITAL YMATHEMATICA" +
"L BOLD ITALIC CAPITAL ZMATHEMATICAL BOLD ITALIC SMALL AMATHEMATICAL BOLD" +
" ITALIC SMALL BMATHEMATICAL BOLD ITALIC SMALL CMATHEMATICAL BOLD ITALIC " +
"SMALL DMATHEMATICAL BOLD ITALIC SMALL EMATHEMATICAL BOLD ITALIC SMALL FM" +
"ATHEMATICAL BOLD ITALIC SMALL GMATHEMATICAL BOLD ITALIC SMALL HMATHEMATI" +
"CAL BOLD ITALIC SMALL IMATHEMATICAL BOLD ITALIC SMALL JMATHEMATICAL BOLD" +
" ITALIC SMALL KMATHEMATICAL BOLD ITALIC SMALL LMATHEMATICAL BOLD ITALIC " +
"SMALL MMATHEMATICAL BOLD ITALIC SMALL NMATHEMATICAL BOLD ITALIC SMALL OM" +
"ATHEMATICAL BOLD ITALIC SMALL PMATHEMATICAL BOLD ITALIC SMALL QMATHEMATI" +
"CAL BOLD ITALIC SMALL RMATHEMATICAL BOLD ITALIC SMALL SMATHEMATICAL BOLD" +
" ITALIC SMALL TMATHEMATICAL BOLD ITALIC SMALL UMATHEMATICAL BOLD ITALIC " +
"SMALL VMATHEMATICAL BOLD ITALIC SMALL WMATHEMATICAL BOLD ITALIC SMALL XM" +
"ATHEMATICAL BOLD ITALIC SMALL YMATHEMATICAL BOLD ITALIC SMALL ZMATHEMATI" +
"CAL SCRIPT CAPITAL AMATHEMATICAL SCRIPT CAPITAL CMATHEMATICAL SCRIPT CAP") + ("" +
"ITAL DMATHEMATICAL SCRIPT CAPITAL GMATHEMATICAL SCRIPT CAPITAL JMATHEMAT" +
"ICAL SCRIPT CAPITAL KMATHEMATICAL SCRIPT CAPITAL NMATHEMATICAL SCRIPT CA" +
"PITAL OMATHEMATICAL SCRIPT CAPITAL PMATHEMATICAL SCRIPT CAPITAL QMATHEMA" +
"TICAL SCRIPT CAPITAL SMATHEMATICAL SCRIPT CAPITAL TMATHEMATICAL SCRIPT C" +
"APITAL UMATHEMATICAL SCRIPT CAPITAL VMATHEMATICAL SCRIPT CAPITAL WMATHEM" +
"ATICAL SCRIPT CAPITAL XMATHEMATICAL SCRIPT CAPITAL YMATHEMATICAL SCRIPT " +
"CAPITAL ZMATHEMATICAL SCRIPT SMALL AMATHEMATICAL SCRIPT SMALL BMATHEMATI" +
"CAL SCRIPT SMALL CMATHEMATICAL SCRIPT SMALL DMATHEMATICAL SCRIPT SMALL F" +
"MATHEMATICAL SCRIPT SMALL HMATHEMATICAL SCRIPT SMALL IMATHEMATICAL SCRIP" +
"T SMALL JMATHEMATICAL SCRIPT SMALL KMATHEMATICAL SCRIPT SMALL LMATHEMATI" +
"CAL SCRIPT SMALL MMATHEMATICAL SCRIPT SMALL NMATHEMATICAL SCRIPT SMALL P" +
"MATHEMATICAL SCRIPT SMALL QMATHEMATICAL SCRIPT SMALL RMATHEMATICAL SCRIP" +
"T SMALL SMATHEMATICAL SCRIPT SMALL TMATHEMATICAL SCRIPT SMALL UMATHEMATI" +
"CAL SCRIPT SMALL VMATHEMATICAL SCRIPT SMALL WMATHEMATICAL SCRIPT SMALL X" +
"MATHEMATICAL SCRIPT SMALL YMATHEMATICAL SCRIPT SMALL ZMATHEMATICAL BOLD " +
"SCRIPT CAPITAL AMATHEMATICAL BOLD SCRIPT CAPITAL BMATHEMATICAL BOLD SCRI" +
"PT CAPITAL CMATHEMATICAL BOLD SCRIPT CAPITAL DMATHEMATICAL BOLD SCRIPT C" +
"APITAL EMATHEMATICAL BOLD SCRIPT CAPITAL FMATHEMATICAL BOLD SCRIPT CAPIT" +
"AL GMATHEMATICAL BOLD SCRIPT CAPITAL HMATHEMATICAL BOLD SCRIPT CAPITAL I" +
"MATHEMATICAL BOLD SCRIPT CAPITAL JMATHEMATICAL BOLD SCRIPT CAPITAL KMATH" +
"EMATICAL BOLD SCRIPT CAPITAL LMATHEMATICAL BOLD SCRIPT CAPITAL MMATHEMAT" +
"ICAL BOLD SCRIPT CAPITAL NMATHEMATICAL BOLD SCRIPT CAPITAL OMATHEMATICAL" +
" BOLD SCRIPT CAPITAL PMATHEMATICAL BOLD SCRIPT CAPITAL QMATHEMATICAL BOL" +
"D SCRIPT CAPITAL RMATHEMATICAL BOLD SCRIPT CAPITAL SMATHEMATICAL BOLD SC" +
"RIPT CAPITAL TMATHEMATICAL BOLD SCRIPT CAPITAL UMATHEMATICAL BOLD SCRIPT" +
" CAPITAL VMATHEMATICAL BOLD SCRIPT CAPITAL WMATHEMATICAL BOLD SCRIPT CAP" +
"ITAL XMATHEMATICAL BOLD SCRIPT CAPITAL YMATHEMATICAL BOLD SCRIPT CAPITAL" +
" ZMATHEMATICAL BOLD SCRIPT SMALL AMATHEMATICAL BOLD SCRIPT SMALL BMATHEM" +
"ATICAL BOLD SCRIPT SMALL CMATHEMATICAL BOLD SCRIPT SMALL DMATHEMATICAL B" +
"OLD SCRIPT SMALL EMATHEMATICAL BOLD SCRIPT SMALL FMATHEMATICAL BOLD SCRI" +
"PT SMALL GMATHEMATICAL BOLD SCRIPT SMALL HMATHEMATICAL BOLD SCRIPT SMALL" +
" IMATHEMATICAL BOLD SCRIPT SMALL JMATHEMATICAL BOLD SCRIPT SMALL KMATHEM" +
"ATICAL BOLD SCRIPT SMALL LMATHEMATICAL BOLD SCRIPT SMALL MMATHEMATICAL B" +
"OLD SCRIPT SMALL NMATHEMATICAL BOLD SCRIPT SMALL OMATHEMATICAL BOLD SCRI" +
"PT SMALL PMATHEMATICAL BOLD SCRIPT SMALL QMATHEMATICAL BOLD SCRIPT SMALL" +
" RMATHEMATICAL BOLD SCRIPT SMALL SMATHEMATICAL BOLD SCRIPT SMALL TMATHEM" +
"ATICAL BOLD SCRIPT SMALL UMATHEMATICAL BOLD SCRIPT SMALL VMATHEMATICAL B" +
"OLD SCRIPT SMALL WMATHEMATICAL BOLD SCRIPT SMALL XMATHEMATICAL BOLD SCRI" +
"PT SMALL YMATHEMATICAL BOLD SCRIPT SMALL ZMATHEMATICAL FRAKTUR CAPITAL A" +
"MATHEMATICAL FRAKTUR CAPITAL BMATHEMATICAL FRAKTUR CAPITAL DMATHEMATICAL" +
" FRAKTUR CAPITAL EMATHEMATICAL FRAKTUR CAPITAL FMATHEMATICAL FRAKTUR CAP" +
"ITAL GMATHEMATICAL FRAKTUR CAPITAL JMATHEMATICAL FRAKTUR CAPITAL KMATHEM" +
"ATICAL FRAKTUR CAPITAL LMATHEMATICAL FRAKTUR CAPITAL MMATHEMATICAL FRAKT" +
"UR CAPITAL NMATHEMATICAL FRAKTUR CAPITAL OMATHEMATICAL FRAKTUR CAPITAL P" +
"MATHEMATICAL FRAKTUR CAPITAL QMATHEMATICAL FRAKTUR CAPITAL SMATHEMATICAL" +
" FRAKTUR CAPITAL TMATHEMATICAL FRAKTUR CAPITAL UMATHEMATICAL FRAKTUR CAP" +
"ITAL VMATHEMATICAL FRAKTUR CAPITAL WMATHEMATICAL FRAKTUR CAPITAL XMATHEM" +
"ATICAL FRAKTUR CAPITAL YMATHEMATICAL FRAKTUR SMALL AMATHEMATICAL FRAKTUR" +
" SMALL BMATHEMATICAL FRAKTUR SMALL CMATHEMATICAL FRAKTUR SMALL DMATHEMAT" +
"ICAL FRAKTUR SMALL EMATHEMATICAL FRAKTUR SMALL FMATHEMATICAL FRAKTUR SMA" +
"LL GMATHEMATICAL FRAKTUR SMALL HMATHEMATICAL FRAKTUR SMALL IMATHEMATICAL" +
" FRAKTUR SMALL JMATHEMATICAL FRAKTUR SMALL KMATHEMATICAL FRAKTUR SMALL L" +
"MATHEMATICAL FRAKTUR SMALL MMATHEMATICAL FRAKTUR SMALL NMATHEMATICAL FRA" +
"KTUR SMALL OMATHEMATICAL FRAKTUR SMALL PMATHEMATICAL FRAKTUR SMALL QMATH" +
"EMATICAL FRAKTUR SMALL RMATHEMATICAL FRAKTUR SMALL SMATHEMATICAL FRAKTUR" +
" SMALL TMATHEMATICAL FRAKTUR SMALL UMATHEMATICAL FRAKTUR SMALL VMATHEMAT" +
"ICAL FRAKTUR SMALL WMATHEMATICAL FRAKTUR SMALL XMATHEMATICAL FRAKTUR SMA" +
"LL YMATHEMATICAL FRAKTUR SMALL ZMATHEMATICAL DOUBLE-STRUCK CAPITAL AMATH" +
"EMATICAL DOUBLE-STRUCK CAPITAL BMATHEMATICAL DOUBLE-STRUCK CAPITAL DMATH" +
"EMATICAL DOUBLE-STRUCK CAPITAL EMATHEMATICAL DOUBLE-STRUCK CAPITAL FMATH" +
"EMATICAL DOUBLE-STRUCK CAPITAL GMATHEMATICAL DOUBLE-STRUCK CAPITAL IMATH" +
"EMATICAL DOUBLE-STRUCK CAPITAL JMATHEMATICAL DOUBLE-STRUCK CAPITAL KMATH" +
"EMATICAL DOUBLE-STRUCK CAPITAL LMATHEMATICAL DOUBLE-STRUCK CAPITAL MMATH" +
"EMATICAL DOUBLE-STRUCK CAPITAL OMATHEMATICAL DOUBLE-STRUCK CAPITAL SMATH") + ("" +
"EMATICAL DOUBLE-STRUCK CAPITAL TMATHEMATICAL DOUBLE-STRUCK CAPITAL UMATH" +
"EMATICAL DOUBLE-STRUCK CAPITAL VMATHEMATICAL DOUBLE-STRUCK CAPITAL WMATH" +
"EMATICAL DOUBLE-STRUCK CAPITAL XMATHEMATICAL DOUBLE-STRUCK CAPITAL YMATH" +
"EMATICAL DOUBLE-STRUCK SMALL AMATHEMATICAL DOUBLE-STRUCK SMALL BMATHEMAT" +
"ICAL DOUBLE-STRUCK SMALL CMATHEMATICAL DOUBLE-STRUCK SMALL DMATHEMATICAL" +
" DOUBLE-STRUCK SMALL EMATHEMATICAL DOUBLE-STRUCK SMALL FMATHEMATICAL DOU" +
"BLE-STRUCK SMALL GMATHEMATICAL DOUBLE-STRUCK SMALL HMATHEMATICAL DOUBLE-" +
"STRUCK SMALL IMATHEMATICAL DOUBLE-STRUCK SMALL JMATHEMATICAL DOUBLE-STRU" +
"CK SMALL KMATHEMATICAL DOUBLE-STRUCK SMALL LMATHEMATICAL DOUBLE-STRUCK S" +
"MALL MMATHEMATICAL DOUBLE-STRUCK SMALL NMATHEMATICAL DOUBLE-STRUCK SMALL" +
" OMATHEMATICAL DOUBLE-STRUCK SMALL PMATHEMATICAL DOUBLE-STRUCK SMALL QMA" +
"THEMATICAL DOUBLE-STRUCK SMALL RMATHEMATICAL DOUBLE-STRUCK SMALL SMATHEM" +
"ATICAL DOUBLE-STRUCK SMALL TMATHEMATICAL DOUBLE-STRUCK SMALL UMATHEMATIC" +
"AL DOUBLE-STRUCK SMALL VMATHEMATICAL DOUBLE-STRUCK SMALL WMATHEMATICAL D" +
"OUBLE-STRUCK SMALL XMATHEMATICAL DOUBLE-STRUCK SMALL YMATHEMATICAL DOUBL" +
"E-STRUCK SMALL ZMATHEMATICAL BOLD FRAKTUR CAPITAL AMATHEMATICAL BOLD FRA" +
"KTUR CAPITAL BMATHEMATICAL BOLD FRAKTUR CAPITAL CMATHEMATICAL BOLD FRAKT" +
"UR CAPITAL DMATHEMATICAL BOLD FRAKTUR CAPITAL EMATHEMATICAL BOLD FRAKTUR" +
" CAPITAL FMATHEMATICAL BOLD FRAKTUR CAPITAL GMATHEMATICAL BOLD FRAKTUR C" +
"APITAL HMATHEMATICAL BOLD FRAKTUR CAPITAL IMATHEMATICAL BOLD FRAKTUR CAP" +
"ITAL JMATHEMATICAL BOLD FRAKTUR CAPITAL KMATHEMATICAL BOLD FRAKTUR CAPIT" +
"AL LMATHEMATICAL BOLD FRAKTUR CAPITAL MMATHEMATICAL BOLD FRAKTUR CAPITAL" +
" NMATHEMATICAL BOLD FRAKTUR CAPITAL OMATHEMATICAL BOLD FRAKTUR CAPITAL P" +
"MATHEMATICAL BOLD FRAKTUR CAPITAL QMATHEMATICAL BOLD FRAKTUR CAPITAL RMA" +
"THEMATICAL BOLD FRAKTUR CAPITAL SMATHEMATICAL BOLD FRAKTUR CAPITAL TMATH" +
"EMATICAL BOLD FRAKTUR CAPITAL UMATHEMATICAL BOLD FRAKTUR CAPITAL VMATHEM" +
"ATICAL BOLD FRAKTUR CAPITAL WMATHEMATICAL BOLD FRAKTUR CAPITAL XMATHEMAT" +
"ICAL BOLD FRAKTUR CAPITAL YMATHEMATICAL BOLD FRAKTUR CAPITAL ZMATHEMATIC" +
"AL BOLD FRAKTUR SMALL AMATHEMATICAL BOLD FRAKTUR SMALL BMATHEMATICAL BOL" +
"D FRAKTUR SMALL CMATHEMATICAL BOLD FRAKTUR SMALL DMATHEMATICAL BOLD FRAK" +
"TUR SMALL EMATHEMATICAL BOLD FRAKTUR SMALL FMATHEMATICAL BOLD FRAKTUR SM" +
"ALL GMATHEMATICAL BOLD FRAKTUR SMALL HMATHEMATICAL BOLD FRAKTUR SMALL IM" +
"ATHEMATICAL BOLD FRAKTUR SMALL JMATHEMATICAL BOLD FRAKTUR SMALL KMATHEMA" +
"TICAL BOLD FRAKTUR SMALL LMATHEMATICAL BOLD FRAKTUR SMALL MMATHEMATICAL " +
"BOLD FRAKTUR SMALL NMATHEMATICAL BOLD FRAKTUR SMALL OMATHEMATICAL BOLD F" +
"RAKTUR SMALL PMATHEMATICAL BOLD FRAKTUR SMALL QMATHEMATICAL BOLD FRAKTUR" +
" SMALL RMATHEMATICAL BOLD FRAKTUR SMALL SMATHEMATICAL BOLD FRAKTUR SMALL" +
" TMATHEMATICAL BOLD FRAKTUR SMALL UMATHEMATICAL BOLD FRAKTUR SMALL VMATH" +
"EMATICAL BOLD FRAKTUR SMALL WMATHEMATICAL BOLD FRAKTUR SMALL XMATHEMATIC" +
"AL BOLD FRAKTUR SMALL YMATHEMATICAL BOLD FRAKTUR SMALL ZMATHEMATICAL SAN" +
"S-SERIF CAPITAL AMATHEMATICAL SANS-SERIF CAPITAL BMATHEMATICAL SANS-SERI" +
"F CAPITAL CMATHEMATICAL SANS-SERIF CAPITAL DMATHEMATICAL SANS-SERIF CAPI" +
"TAL EMATHEMATICAL SANS-SERIF CAPITAL FMATHEMATICAL SANS-SERIF CAPITAL GM" +
"ATHEMATICAL SANS-SERIF CAPITAL HMATHEMATICAL SANS-SERIF CAPITAL IMATHEMA" +
"TICAL SANS-SERIF CAPITAL JMATHEMATICAL SANS-SERIF CAPITAL KMATHEMATICAL " +
"SANS-SERIF CAPITAL LMATHEMATICAL SANS-SERIF CAPITAL MMATHEMATICAL SANS-S" +
"ERIF CAPITAL NMATHEMATICAL SANS-SERIF CAPITAL OMATHEMATICAL SANS-SERIF C" +
"APITAL PMATHEMATICAL SANS-SERIF CAPITAL QMATHEMATICAL SANS-SERIF CAPITAL" +
" RMATHEMATICAL SANS-SERIF CAPITAL SMATHEMATICAL SANS-SERIF CAPITAL TMATH" +
"EMATICAL SANS-SERIF CAPITAL UMATHEMATICAL SANS-SERIF CAPITAL VMATHEMATIC" +
"AL SANS-SERIF CAPITAL WMATHEMATICAL SANS-SERIF CAPITAL XMATHEMATICAL SAN" +
"S-SERIF CAPITAL YMATHEMATICAL SANS-SERIF CAPITAL ZMATHEMATICAL SANS-SERI" +
"F SMALL AMATHEMATICAL SANS-SERIF SMALL BMATHEMATICAL SANS-SERIF SMALL CM" +
"ATHEMATICAL SANS-SERIF SMALL DMATHEMATICAL SANS-SERIF SMALL EMATHEMATICA" +
"L SANS-SERIF SMALL FMATHEMATICAL SANS-SERIF SMALL GMATHEMATICAL SANS-SER" +
"IF SMALL HMATHEMATICAL SANS-SERIF SMALL IMATHEMATICAL SANS-SERIF SMALL J" +
"MATHEMATICAL SANS-SERIF SMALL KMATHEMATICAL SANS-SERIF SMALL LMATHEMATIC" +
"AL SANS-SERIF SMALL MMATHEMATICAL SANS-SERIF SMALL NMATHEMATICAL SANS-SE" +
"RIF SMALL OMATHEMATICAL SANS-SERIF SMALL PMATHEMATICAL SANS-SERIF SMALL " +
"QMATHEMATICAL SANS-SERIF SMALL RMATHEMATICAL SANS-SERIF SMALL SMATHEMATI" +
"CAL SANS-SERIF SMALL TMATHEMATICAL SANS-SERIF SMALL UMATHEMATICAL SANS-S" +
"ERIF SMALL VMATHEMATICAL SANS-SERIF SMALL WMATHEMATICAL SANS-SERIF SMALL" +
" XMATHEMATICAL SANS-SERIF SMALL YMATHEMATICAL SANS-SERIF SMALL ZMATHEMAT" +
"ICAL SANS-SERIF BOLD CAPITAL AMATHEMATICAL SANS-SERIF BOLD CAPITAL BMATH") + ("" +
"EMATICAL SANS-SERIF BOLD CAPITAL CMATHEMATICAL SANS-SERIF BOLD CAPITAL D" +
"MATHEMATICAL SANS-SERIF BOLD CAPITAL EMATHEMATICAL SANS-SERIF BOLD CAPIT" +
"AL FMATHEMATICAL SANS-SERIF BOLD CAPITAL GMATHEMATICAL SANS-SERIF BOLD C" +
"APITAL HMATHEMATICAL SANS-SERIF BOLD CAPITAL IMATHEMATICAL SANS-SERIF BO" +
"LD CAPITAL JMATHEMATICAL SANS-SERIF BOLD CAPITAL KMATHEMATICAL SANS-SERI" +
"F BOLD CAPITAL LMATHEMATICAL SANS-SERIF BOLD CAPITAL MMATHEMATICAL SANS-" +
"SERIF BOLD CAPITAL NMATHEMATICAL SANS-SERIF BOLD CAPITAL OMATHEMATICAL S" +
"ANS-SERIF BOLD CAPITAL PMATHEMATICAL SANS-SERIF BOLD CAPITAL QMATHEMATIC" +
"AL SANS-SERIF BOLD CAPITAL RMATHEMATICAL SANS-SERIF BOLD CAPITAL SMATHEM" +
"ATICAL SANS-SERIF BOLD CAPITAL TMATHEMATICAL SANS-SERIF BOLD CAPITAL UMA" +
"THEMATICAL SANS-SERIF BOLD CAPITAL VMATHEMATICAL SANS-SERIF BOLD CAPITAL" +
" WMATHEMATICAL SANS-SERIF BOLD CAPITAL XMATHEMATICAL SANS-SERIF BOLD CAP" +
"ITAL YMATHEMATICAL SANS-SERIF BOLD CAPITAL ZMATHEMATICAL SANS-SERIF BOLD" +
" SMALL AMATHEMATICAL SANS-SERIF BOLD SMALL BMATHEMATICAL SANS-SERIF BOLD" +
" SMALL CMATHEMATICAL SANS-SERIF BOLD SMALL DMATHEMATICAL SANS-SERIF BOLD" +
" SMALL EMATHEMATICAL SANS-SERIF BOLD SMALL FMATHEMATICAL SANS-SERIF BOLD" +
" SMALL GMATHEMATICAL SANS-SERIF BOLD SMALL HMATHEMATICAL SANS-SERIF BOLD" +
" SMALL IMATHEMATICAL SANS-SERIF BOLD SMALL JMATHEMATICAL SANS-SERIF BOLD" +
" SMALL KMATHEMATICAL SANS-SERIF BOLD SMALL LMATHEMATICAL SANS-SERIF BOLD" +
" SMALL MMATHEMATICAL SANS-SERIF BOLD SMALL NMATHEMATICAL SANS-SERIF BOLD" +
" SMALL OMATHEMATICAL SANS-SERIF BOLD SMALL PMATHEMATICAL SANS-SERIF BOLD" +
" SMALL QMATHEMATICAL SANS-SERIF BOLD SMALL RMATHEMATICAL SANS-SERIF BOLD" +
" SMALL SMATHEMATICAL SANS-SERIF BOLD SMALL TMATHEMATICAL SANS-SERIF BOLD" +
" SMALL UMATHEMATICAL SANS-SERIF BOLD SMALL VMATHEMATICAL SANS-SERIF BOLD" +
" SMALL WMATHEMATICAL SANS-SERIF BOLD SMALL XMATHEMATICAL SANS-SERIF BOLD" +
" SMALL YMATHEMATICAL SANS-SERIF BOLD SMALL ZMATHEMATICAL SANS-SERIF ITAL" +
"IC CAPITAL AMATHEMATICAL SANS-SERIF ITALIC CAPITAL BMATHEMATICAL SANS-SE" +
"RIF ITALIC CAPITAL CMATHEMATICAL SANS-SERIF ITALIC CAPITAL DMATHEMATICAL" +
" SANS-SERIF ITALIC CAPITAL EMATHEMATICAL SANS-SERIF ITALIC CAPITAL FMATH" +
"EMATICAL SANS-SERIF ITALIC CAPITAL GMATHEMATICAL SANS-SERIF ITALIC CAPIT" +
"AL HMATHEMATICAL SANS-SERIF ITALIC CAPITAL IMATHEMATICAL SANS-SERIF ITAL" +
"IC CAPITAL JMATHEMATICAL SANS-SERIF ITALIC CAPITAL KMATHEMATICAL SANS-SE" +
"RIF ITALIC CAPITAL LMATHEMATICAL SANS-SERIF ITALIC CAPITAL MMATHEMATICAL" +
" SANS-SERIF ITALIC CAPITAL NMATHEMATICAL SANS-SERIF ITALIC CAPITAL OMATH" +
"EMATICAL SANS-SERIF ITALIC CAPITAL PMATHEMATICAL SANS-SERIF ITALIC CAPIT" +
"AL QMATHEMATICAL SANS-SERIF ITALIC CAPITAL RMATHEMATICAL SANS-SERIF ITAL" +
"IC CAPITAL SMATHEMATICAL SANS-SERIF ITALIC CAPITAL TMATHEMATICAL SANS-SE" +
"RIF ITALIC CAPITAL UMATHEMATICAL SANS-SERIF ITALIC CAPITAL VMATHEMATICAL" +
" SANS-SERIF ITALIC CAPITAL WMATHEMATICAL SANS-SERIF ITALIC CAPITAL XMATH" +
"EMATICAL SANS-SERIF ITALIC CAPITAL YMATHEMATICAL SANS-SERIF ITALIC CAPIT" +
"AL ZMATHEMATICAL SANS-SERIF ITALIC SMALL AMATHEMATICAL SANS-SERIF ITALIC" +
" SMALL BMATHEMATICAL SANS-SERIF ITALIC SMALL CMATHEMATICAL SANS-SERIF IT" +
"ALIC SMALL DMATHEMATICAL SANS-SERIF ITALIC SMALL EMATHEMATICAL SANS-SERI" +
"F ITALIC SMALL FMATHEMATICAL SANS-SERIF ITALIC SMALL GMATHEMATICAL SANS-" +
"SERIF ITALIC SMALL HMATHEMATICAL SANS-SERIF ITALIC SMALL IMATHEMATICAL S" +
"ANS-SERIF ITALIC SMALL JMATHEMATICAL SANS-SERIF ITALIC SMALL KMATHEMATIC" +
"AL SANS-SERIF ITALIC SMALL LMATHEMATICAL SANS-SERIF ITALIC SMALL MMATHEM" +
"ATICAL SANS-SERIF ITALIC SMALL NMATHEMATICAL SANS-SERIF ITALIC SMALL OMA" +
"THEMATICAL SANS-SERIF ITALIC SMALL PMATHEMATICAL SANS-SERIF ITALIC SMALL" +
" QMATHEMATICAL SANS-SERIF ITALIC SMALL RMATHEMATICAL SANS-SERIF ITALIC S" +
"MALL SMATHEMATICAL SANS-SERIF ITALIC SMALL TMATHEMATICAL SANS-SERIF ITAL" +
"IC SMALL UMATHEMATICAL SANS-SERIF ITALIC SMALL VMATHEMATICAL SANS-SERIF " +
"ITALIC SMALL WMATHEMATICAL SANS-SERIF ITALIC SMALL XMATHEMATICAL SANS-SE" +
"RIF ITALIC SMALL YMATHEMATICAL SANS-SERIF ITALIC SMALL ZMATHEMATICAL SAN" +
"S-SERIF BOLD ITALIC CAPITAL AMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL" +
" BMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL CMATHEMATICAL SANS-SERIF B" +
"OLD ITALIC CAPITAL DMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL EMATHEMA" +
"TICAL SANS-SERIF BOLD ITALIC CAPITAL FMATHEMATICAL SANS-SERIF BOLD ITALI" +
"C CAPITAL GMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL HMATHEMATICAL SAN" +
"S-SERIF BOLD ITALIC CAPITAL IMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL" +
" JMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL KMATHEMATICAL SANS-SERIF B" +
"OLD ITALIC CAPITAL LMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL MMATHEMA" +
"TICAL SANS-SERIF BOLD ITALIC CAPITAL NMATHEMATICAL SANS-SERIF BOLD ITALI" +
"C CAPITAL OMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PMATHEMATICAL SAN") + ("" +
"S-SERIF BOLD ITALIC CAPITAL QMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL" +
" RMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL SMATHEMATICAL SANS-SERIF B" +
"OLD ITALIC CAPITAL TMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL UMATHEMA" +
"TICAL SANS-SERIF BOLD ITALIC CAPITAL VMATHEMATICAL SANS-SERIF BOLD ITALI" +
"C CAPITAL WMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL XMATHEMATICAL SAN" +
"S-SERIF BOLD ITALIC CAPITAL YMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL" +
" ZMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL AMATHEMATICAL SANS-SERIF BOL" +
"D ITALIC SMALL BMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL CMATHEMATICAL " +
"SANS-SERIF BOLD ITALIC SMALL DMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL " +
"EMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL FMATHEMATICAL SANS-SERIF BOLD" +
" ITALIC SMALL GMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL HMATHEMATICAL S" +
"ANS-SERIF BOLD ITALIC SMALL IMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL J" +
"MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL KMATHEMATICAL SANS-SERIF BOLD " +
"ITALIC SMALL LMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL MMATHEMATICAL SA" +
"NS-SERIF BOLD ITALIC SMALL NMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OM" +
"ATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PMATHEMATICAL SANS-SERIF BOLD I" +
"TALIC SMALL QMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL RMATHEMATICAL SAN" +
"S-SERIF BOLD ITALIC SMALL SMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL TMA" +
"THEMATICAL SANS-SERIF BOLD ITALIC SMALL UMATHEMATICAL SANS-SERIF BOLD IT" +
"ALIC SMALL VMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL WMATHEMATICAL SANS" +
"-SERIF BOLD ITALIC SMALL XMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL YMAT" +
"HEMATICAL SANS-SERIF BOLD ITALIC SMALL ZMATHEMATICAL MONOSPACE CAPITAL A" +
"MATHEMATICAL MONOSPACE CAPITAL BMATHEMATICAL MONOSPACE CAPITAL CMATHEMAT" +
"ICAL MONOSPACE CAPITAL DMATHEMATICAL MONOSPACE CAPITAL EMATHEMATICAL MON" +
"OSPACE CAPITAL FMATHEMATICAL MONOSPACE CAPITAL GMATHEMATICAL MONOSPACE C" +
"APITAL HMATHEMATICAL MONOSPACE CAPITAL IMATHEMATICAL MONOSPACE CAPITAL J" +
"MATHEMATICAL MONOSPACE CAPITAL KMATHEMATICAL MONOSPACE CAPITAL LMATHEMAT" +
"ICAL MONOSPACE CAPITAL MMATHEMATICAL MONOSPACE CAPITAL NMATHEMATICAL MON" +
"OSPACE CAPITAL OMATHEMATICAL MONOSPACE CAPITAL PMATHEMATICAL MONOSPACE C" +
"APITAL QMATHEMATICAL MONOSPACE CAPITAL RMATHEMATICAL MONOSPACE CAPITAL S" +
"MATHEMATICAL MONOSPACE CAPITAL TMATHEMATICAL MONOSPACE CAPITAL UMATHEMAT" +
"ICAL MONOSPACE CAPITAL VMATHEMATICAL MONOSPACE CAPITAL WMATHEMATICAL MON" +
"OSPACE CAPITAL XMATHEMATICAL MONOSPACE CAPITAL YMATHEMATICAL MONOSPACE C" +
"APITAL ZMATHEMATICAL MONOSPACE SMALL AMATHEMATICAL MONOSPACE SMALL BMATH" +
"EMATICAL MONOSPACE SMALL CMATHEMATICAL MONOSPACE SMALL DMATHEMATICAL MON" +
"OSPACE SMALL EMATHEMATICAL MONOSPACE SMALL FMATHEMATICAL MONOSPACE SMALL" +
" GMATHEMATICAL MONOSPACE SMALL HMATHEMATICAL MONOSPACE SMALL IMATHEMATIC" +
"AL MONOSPACE SMALL JMATHEMATICAL MONOSPACE SMALL KMATHEMATICAL MONOSPACE" +
" SMALL LMATHEMATICAL MONOSPACE SMALL MMATHEMATICAL MONOSPACE SMALL NMATH" +
"EMATICAL MONOSPACE SMALL OMATHEMATICAL MONOSPACE SMALL PMATHEMATICAL MON" +
"OSPACE SMALL QMATHEMATICAL MONOSPACE SMALL RMATHEMATICAL MONOSPACE SMALL" +
" SMATHEMATICAL MONOSPACE SMALL TMATHEMATICAL MONOSPACE SMALL UMATHEMATIC" +
"AL MONOSPACE SMALL VMATHEMATICAL MONOSPACE SMALL WMATHEMATICAL MONOSPACE" +
" SMALL XMATHEMATICAL MONOSPACE SMALL YMATHEMATICAL MONOSPACE SMALL ZMATH" +
"EMATICAL ITALIC SMALL DOTLESS IMATHEMATICAL ITALIC SMALL DOTLESS JMATHEM" +
"ATICAL BOLD CAPITAL ALPHAMATHEMATICAL BOLD CAPITAL BETAMATHEMATICAL BOLD" +
" CAPITAL GAMMAMATHEMATICAL BOLD CAPITAL DELTAMATHEMATICAL BOLD CAPITAL E" +
"PSILONMATHEMATICAL BOLD CAPITAL ZETAMATHEMATICAL BOLD CAPITAL ETAMATHEMA" +
"TICAL BOLD CAPITAL THETAMATHEMATICAL BOLD CAPITAL IOTAMATHEMATICAL BOLD " +
"CAPITAL KAPPAMATHEMATICAL BOLD CAPITAL LAMDAMATHEMATICAL BOLD CAPITAL MU" +
"MATHEMATICAL BOLD CAPITAL NUMATHEMATICAL BOLD CAPITAL XIMATHEMATICAL BOL" +
"D CAPITAL OMICRONMATHEMATICAL BOLD CAPITAL PIMATHEMATICAL BOLD CAPITAL R" +
"HOMATHEMATICAL BOLD CAPITAL THETA SYMBOLMATHEMATICAL BOLD CAPITAL SIGMAM" +
"ATHEMATICAL BOLD CAPITAL TAUMATHEMATICAL BOLD CAPITAL UPSILONMATHEMATICA" +
"L BOLD CAPITAL PHIMATHEMATICAL BOLD CAPITAL CHIMATHEMATICAL BOLD CAPITAL" +
" PSIMATHEMATICAL BOLD CAPITAL OMEGAMATHEMATICAL BOLD NABLAMATHEMATICAL B" +
"OLD SMALL ALPHAMATHEMATICAL BOLD SMALL BETAMATHEMATICAL BOLD SMALL GAMMA" +
"MATHEMATICAL BOLD SMALL DELTAMATHEMATICAL BOLD SMALL EPSILONMATHEMATICAL" +
" BOLD SMALL ZETAMATHEMATICAL BOLD SMALL ETAMATHEMATICAL BOLD SMALL THETA" +
"MATHEMATICAL BOLD SMALL IOTAMATHEMATICAL BOLD SMALL KAPPAMATHEMATICAL BO" +
"LD SMALL LAMDAMATHEMATICAL BOLD SMALL MUMATHEMATICAL BOLD SMALL NUMATHEM" +
"ATICAL BOLD SMALL XIMATHEMATICAL BOLD SMALL OMICRONMATHEMATICAL BOLD SMA" +
"LL PIMATHEMATICAL BOLD SMALL RHOMATHEMATICAL BOLD SMALL FINAL SIGMAMATHE" +
"MATICAL BOLD SMALL SIGMAMATHEMATICAL BOLD SMALL TAUMATHEMATICAL BOLD SMA") + ("" +
"LL UPSILONMATHEMATICAL BOLD SMALL PHIMATHEMATICAL BOLD SMALL CHIMATHEMAT" +
"ICAL BOLD SMALL PSIMATHEMATICAL BOLD SMALL OMEGAMATHEMATICAL BOLD PARTIA" +
"L DIFFERENTIALMATHEMATICAL BOLD EPSILON SYMBOLMATHEMATICAL BOLD THETA SY" +
"MBOLMATHEMATICAL BOLD KAPPA SYMBOLMATHEMATICAL BOLD PHI SYMBOLMATHEMATIC" +
"AL BOLD RHO SYMBOLMATHEMATICAL BOLD PI SYMBOLMATHEMATICAL ITALIC CAPITAL" +
" ALPHAMATHEMATICAL ITALIC CAPITAL BETAMATHEMATICAL ITALIC CAPITAL GAMMAM" +
"ATHEMATICAL ITALIC CAPITAL DELTAMATHEMATICAL ITALIC CAPITAL EPSILONMATHE" +
"MATICAL ITALIC CAPITAL ZETAMATHEMATICAL ITALIC CAPITAL ETAMATHEMATICAL I" +
"TALIC CAPITAL THETAMATHEMATICAL ITALIC CAPITAL IOTAMATHEMATICAL ITALIC C" +
"APITAL KAPPAMATHEMATICAL ITALIC CAPITAL LAMDAMATHEMATICAL ITALIC CAPITAL" +
" MUMATHEMATICAL ITALIC CAPITAL NUMATHEMATICAL ITALIC CAPITAL XIMATHEMATI" +
"CAL ITALIC CAPITAL OMICRONMATHEMATICAL ITALIC CAPITAL PIMATHEMATICAL ITA" +
"LIC CAPITAL RHOMATHEMATICAL ITALIC CAPITAL THETA SYMBOLMATHEMATICAL ITAL" +
"IC CAPITAL SIGMAMATHEMATICAL ITALIC CAPITAL TAUMATHEMATICAL ITALIC CAPIT" +
"AL UPSILONMATHEMATICAL ITALIC CAPITAL PHIMATHEMATICAL ITALIC CAPITAL CHI" +
"MATHEMATICAL ITALIC CAPITAL PSIMATHEMATICAL ITALIC CAPITAL OMEGAMATHEMAT" +
"ICAL ITALIC NABLAMATHEMATICAL ITALIC SMALL ALPHAMATHEMATICAL ITALIC SMAL" +
"L BETAMATHEMATICAL ITALIC SMALL GAMMAMATHEMATICAL ITALIC SMALL DELTAMATH" +
"EMATICAL ITALIC SMALL EPSILONMATHEMATICAL ITALIC SMALL ZETAMATHEMATICAL " +
"ITALIC SMALL ETAMATHEMATICAL ITALIC SMALL THETAMATHEMATICAL ITALIC SMALL" +
" IOTAMATHEMATICAL ITALIC SMALL KAPPAMATHEMATICAL ITALIC SMALL LAMDAMATHE" +
"MATICAL ITALIC SMALL MUMATHEMATICAL ITALIC SMALL NUMATHEMATICAL ITALIC S" +
"MALL XIMATHEMATICAL ITALIC SMALL OMICRONMATHEMATICAL ITALIC SMALL PIMATH" +
"EMATICAL ITALIC SMALL RHOMATHEMATICAL ITALIC SMALL FINAL SIGMAMATHEMATIC" +
"AL ITALIC SMALL SIGMAMATHEMATICAL ITALIC SMALL TAUMATHEMATICAL ITALIC SM" +
"ALL UPSILONMATHEMATICAL ITALIC SMALL PHIMATHEMATICAL ITALIC SMALL CHIMAT" +
"HEMATICAL ITALIC SMALL PSIMATHEMATICAL ITALIC SMALL OMEGAMATHEMATICAL IT" +
"ALIC PARTIAL DIFFERENTIALMATHEMATICAL ITALIC EPSILON SYMBOLMATHEMATICAL " +
"ITALIC THETA SYMBOLMATHEMATICAL ITALIC KAPPA SYMBOLMATHEMATICAL ITALIC P" +
"HI SYMBOLMATHEMATICAL ITALIC RHO SYMBOLMATHEMATICAL ITALIC PI SYMBOLMATH" +
"EMATICAL BOLD ITALIC CAPITAL ALPHAMATHEMATICAL BOLD ITALIC CAPITAL BETAM" +
"ATHEMATICAL BOLD ITALIC CAPITAL GAMMAMATHEMATICAL BOLD ITALIC CAPITAL DE" +
"LTAMATHEMATICAL BOLD ITALIC CAPITAL EPSILONMATHEMATICAL BOLD ITALIC CAPI" +
"TAL ZETAMATHEMATICAL BOLD ITALIC CAPITAL ETAMATHEMATICAL BOLD ITALIC CAP" +
"ITAL THETAMATHEMATICAL BOLD ITALIC CAPITAL IOTAMATHEMATICAL BOLD ITALIC " +
"CAPITAL KAPPAMATHEMATICAL BOLD ITALIC CAPITAL LAMDAMATHEMATICAL BOLD ITA" +
"LIC CAPITAL MUMATHEMATICAL BOLD ITALIC CAPITAL NUMATHEMATICAL BOLD ITALI" +
"C CAPITAL XIMATHEMATICAL BOLD ITALIC CAPITAL OMICRONMATHEMATICAL BOLD IT" +
"ALIC CAPITAL PIMATHEMATICAL BOLD ITALIC CAPITAL RHOMATHEMATICAL BOLD ITA" +
"LIC CAPITAL THETA SYMBOLMATHEMATICAL BOLD ITALIC CAPITAL SIGMAMATHEMATIC" +
"AL BOLD ITALIC CAPITAL TAUMATHEMATICAL BOLD ITALIC CAPITAL UPSILONMATHEM" +
"ATICAL BOLD ITALIC CAPITAL PHIMATHEMATICAL BOLD ITALIC CAPITAL CHIMATHEM" +
"ATICAL BOLD ITALIC CAPITAL PSIMATHEMATICAL BOLD ITALIC CAPITAL OMEGAMATH" +
"EMATICAL BOLD ITALIC NABLAMATHEMATICAL BOLD ITALIC SMALL ALPHAMATHEMATIC" +
"AL BOLD ITALIC SMALL BETAMATHEMATICAL BOLD ITALIC SMALL GAMMAMATHEMATICA" +
"L BOLD ITALIC SMALL DELTAMATHEMATICAL BOLD ITALIC SMALL EPSILONMATHEMATI" +
"CAL BOLD ITALIC SMALL ZETAMATHEMATICAL BOLD ITALIC SMALL ETAMATHEMATICAL" +
" BOLD ITALIC SMALL THETAMATHEMATICAL BOLD ITALIC SMALL IOTAMATHEMATICAL " +
"BOLD ITALIC SMALL KAPPAMATHEMATICAL BOLD ITALIC SMALL LAMDAMATHEMATICAL " +
"BOLD ITALIC SMALL MUMATHEMATICAL BOLD ITALIC SMALL NUMATHEMATICAL BOLD I" +
"TALIC SMALL XIMATHEMATICAL BOLD ITALIC SMALL OMICRONMATHEMATICAL BOLD IT" +
"ALIC SMALL PIMATHEMATICAL BOLD ITALIC SMALL RHOMATHEMATICAL BOLD ITALIC " +
"SMALL FINAL SIGMAMATHEMATICAL BOLD ITALIC SMALL SIGMAMATHEMATICAL BOLD I" +
"TALIC SMALL TAUMATHEMATICAL BOLD ITALIC SMALL UPSILONMATHEMATICAL BOLD I" +
"TALIC SMALL PHIMATHEMATICAL BOLD ITALIC SMALL CHIMATHEMATICAL BOLD ITALI" +
"C SMALL PSIMATHEMATICAL BOLD ITALIC SMALL OMEGAMATHEMATICAL BOLD ITALIC " +
"PARTIAL DIFFERENTIALMATHEMATICAL BOLD ITALIC EPSILON SYMBOLMATHEMATICAL " +
"BOLD ITALIC THETA SYMBOLMATHEMATICAL BOLD ITALIC KAPPA SYMBOLMATHEMATICA" +
"L BOLD ITALIC PHI SYMBOLMATHEMATICAL BOLD ITALIC RHO SYMBOLMATHEMATICAL " +
"BOLD ITALIC PI SYMBOLMATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHAMATHEMATI" +
"CAL SANS-SERIF BOLD CAPITAL BETAMATHEMATICAL SANS-SERIF BOLD CAPITAL GAM" +
"MAMATHEMATICAL SANS-SERIF BOLD CAPITAL DELTAMATHEMATICAL SANS-SERIF BOLD" +
" CAPITAL EPSILONMATHEMATICAL SANS-SERIF BOLD CAPITAL ZETAMATHEMATICAL SA" +
"NS-SERIF BOLD CAPITAL ETAMATHEMATICAL SANS-SERIF BOLD CAPITAL THETAMATHE") + ("" +
"MATICAL SANS-SERIF BOLD CAPITAL IOTAMATHEMATICAL SANS-SERIF BOLD CAPITAL" +
" KAPPAMATHEMATICAL SANS-SERIF BOLD CAPITAL LAMDAMATHEMATICAL SANS-SERIF " +
"BOLD CAPITAL MUMATHEMATICAL SANS-SERIF BOLD CAPITAL NUMATHEMATICAL SANS-" +
"SERIF BOLD CAPITAL XIMATHEMATICAL SANS-SERIF BOLD CAPITAL OMICRONMATHEMA" +
"TICAL SANS-SERIF BOLD CAPITAL PIMATHEMATICAL SANS-SERIF BOLD CAPITAL RHO" +
"MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA SYMBOLMATHEMATICAL SANS-SERIF" +
" BOLD CAPITAL SIGMAMATHEMATICAL SANS-SERIF BOLD CAPITAL TAUMATHEMATICAL " +
"SANS-SERIF BOLD CAPITAL UPSILONMATHEMATICAL SANS-SERIF BOLD CAPITAL PHIM" +
"ATHEMATICAL SANS-SERIF BOLD CAPITAL CHIMATHEMATICAL SANS-SERIF BOLD CAPI" +
"TAL PSIMATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGAMATHEMATICAL SANS-SERIF" +
" BOLD NABLAMATHEMATICAL SANS-SERIF BOLD SMALL ALPHAMATHEMATICAL SANS-SER" +
"IF BOLD SMALL BETAMATHEMATICAL SANS-SERIF BOLD SMALL GAMMAMATHEMATICAL S" +
"ANS-SERIF BOLD SMALL DELTAMATHEMATICAL SANS-SERIF BOLD SMALL EPSILONMATH" +
"EMATICAL SANS-SERIF BOLD SMALL ZETAMATHEMATICAL SANS-SERIF BOLD SMALL ET" +
"AMATHEMATICAL SANS-SERIF BOLD SMALL THETAMATHEMATICAL SANS-SERIF BOLD SM" +
"ALL IOTAMATHEMATICAL SANS-SERIF BOLD SMALL KAPPAMATHEMATICAL SANS-SERIF " +
"BOLD SMALL LAMDAMATHEMATICAL SANS-SERIF BOLD SMALL MUMATHEMATICAL SANS-S" +
"ERIF BOLD SMALL NUMATHEMATICAL SANS-SERIF BOLD SMALL XIMATHEMATICAL SANS" +
"-SERIF BOLD SMALL OMICRONMATHEMATICAL SANS-SERIF BOLD SMALL PIMATHEMATIC" +
"AL SANS-SERIF BOLD SMALL RHOMATHEMATICAL SANS-SERIF BOLD SMALL FINAL SIG" +
"MAMATHEMATICAL SANS-SERIF BOLD SMALL SIGMAMATHEMATICAL SANS-SERIF BOLD S" +
"MALL TAUMATHEMATICAL SANS-SERIF BOLD SMALL UPSILONMATHEMATICAL SANS-SERI" +
"F BOLD SMALL PHIMATHEMATICAL SANS-SERIF BOLD SMALL CHIMATHEMATICAL SANS-" +
"SERIF BOLD SMALL PSIMATHEMATICAL SANS-SERIF BOLD SMALL OMEGAMATHEMATICAL" +
" SANS-SERIF BOLD PARTIAL DIFFERENTIALMATHEMATICAL SANS-SERIF BOLD EPSILO" +
"N SYMBOLMATHEMATICAL SANS-SERIF BOLD THETA SYMBOLMATHEMATICAL SANS-SERIF" +
" BOLD KAPPA SYMBOLMATHEMATICAL SANS-SERIF BOLD PHI SYMBOLMATHEMATICAL SA" +
"NS-SERIF BOLD RHO SYMBOLMATHEMATICAL SANS-SERIF BOLD PI SYMBOLMATHEMATIC" +
"AL SANS-SERIF BOLD ITALIC CAPITAL ALPHAMATHEMATICAL SANS-SERIF BOLD ITAL" +
"IC CAPITAL BETAMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL GAMMAMATHEMAT" +
"ICAL SANS-SERIF BOLD ITALIC CAPITAL DELTAMATHEMATICAL SANS-SERIF BOLD IT" +
"ALIC CAPITAL EPSILONMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ZETAMATH" +
"EMATICAL SANS-SERIF BOLD ITALIC CAPITAL ETAMATHEMATICAL SANS-SERIF BOLD " +
"ITALIC CAPITAL THETAMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL IOTAMATH" +
"EMATICAL SANS-SERIF BOLD ITALIC CAPITAL KAPPAMATHEMATICAL SANS-SERIF BOL" +
"D ITALIC CAPITAL LAMDAMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL MUMATH" +
"EMATICAL SANS-SERIF BOLD ITALIC CAPITAL NUMATHEMATICAL SANS-SERIF BOLD I" +
"TALIC CAPITAL XIMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMICRONMATHE" +
"MATICAL SANS-SERIF BOLD ITALIC CAPITAL PIMATHEMATICAL SANS-SERIF BOLD IT" +
"ALIC CAPITAL RHOMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA SYMBOL" +
"MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL SIGMAMATHEMATICAL SANS-SERIF" +
" BOLD ITALIC CAPITAL TAUMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL UPSI" +
"LONMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PHIMATHEMATICAL SANS-SERI" +
"F BOLD ITALIC CAPITAL CHIMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PSI" +
"MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGAMATHEMATICAL SANS-SERIF" +
" BOLD ITALIC NABLAMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHAMATHEMA" +
"TICAL SANS-SERIF BOLD ITALIC SMALL BETAMATHEMATICAL SANS-SERIF BOLD ITAL" +
"IC SMALL GAMMAMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL DELTAMATHEMATICA" +
"L SANS-SERIF BOLD ITALIC SMALL EPSILONMATHEMATICAL SANS-SERIF BOLD ITALI" +
"C SMALL ZETAMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ETAMATHEMATICAL SA" +
"NS-SERIF BOLD ITALIC SMALL THETAMATHEMATICAL SANS-SERIF BOLD ITALIC SMAL" +
"L IOTAMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL KAPPAMATHEMATICAL SANS-S" +
"ERIF BOLD ITALIC SMALL LAMDAMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL MU" +
"MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL NUMATHEMATICAL SANS-SERIF BOLD" +
" ITALIC SMALL XIMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMICRONMATHEMA" +
"TICAL SANS-SERIF BOLD ITALIC SMALL PIMATHEMATICAL SANS-SERIF BOLD ITALIC" +
" SMALL RHOMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL FINAL SIGMAMATHEMATI" +
"CAL SANS-SERIF BOLD ITALIC SMALL SIGMAMATHEMATICAL SANS-SERIF BOLD ITALI" +
"C SMALL TAUMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL UPSILONMATHEMATICAL" +
" SANS-SERIF BOLD ITALIC SMALL PHIMATHEMATICAL SANS-SERIF BOLD ITALIC SMA" +
"LL CHIMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PSIMATHEMATICAL SANS-SER" +
"IF BOLD ITALIC SMALL OMEGAMATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DI" +
"FFERENTIALMATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOLMATHEMATICAL" +
" SANS-SERIF BOLD ITALIC THETA SYMBOLMATHEMATICAL SANS-SERIF BOLD ITALIC ") + ("" +
"KAPPA SYMBOLMATHEMATICAL SANS-SERIF BOLD ITALIC PHI SYMBOLMATHEMATICAL S" +
"ANS-SERIF BOLD ITALIC RHO SYMBOLMATHEMATICAL SANS-SERIF BOLD ITALIC PI S" +
"YMBOLMATHEMATICAL BOLD CAPITAL DIGAMMAMATHEMATICAL BOLD SMALL DIGAMMAMAT" +
"HEMATICAL BOLD DIGIT ZEROMATHEMATICAL BOLD DIGIT ONEMATHEMATICAL BOLD DI" +
"GIT TWOMATHEMATICAL BOLD DIGIT THREEMATHEMATICAL BOLD DIGIT FOURMATHEMAT" +
"ICAL BOLD DIGIT FIVEMATHEMATICAL BOLD DIGIT SIXMATHEMATICAL BOLD DIGIT S" +
"EVENMATHEMATICAL BOLD DIGIT EIGHTMATHEMATICAL BOLD DIGIT NINEMATHEMATICA" +
"L DOUBLE-STRUCK DIGIT ZEROMATHEMATICAL DOUBLE-STRUCK DIGIT ONEMATHEMATIC" +
"AL DOUBLE-STRUCK DIGIT TWOMATHEMATICAL DOUBLE-STRUCK DIGIT THREEMATHEMAT" +
"ICAL DOUBLE-STRUCK DIGIT FOURMATHEMATICAL DOUBLE-STRUCK DIGIT FIVEMATHEM" +
"ATICAL DOUBLE-STRUCK DIGIT SIXMATHEMATICAL DOUBLE-STRUCK DIGIT SEVENMATH" +
"EMATICAL DOUBLE-STRUCK DIGIT EIGHTMATHEMATICAL DOUBLE-STRUCK DIGIT NINEM" +
"ATHEMATICAL SANS-SERIF DIGIT ZEROMATHEMATICAL SANS-SERIF DIGIT ONEMATHEM" +
"ATICAL SANS-SERIF DIGIT TWOMATHEMATICAL SANS-SERIF DIGIT THREEMATHEMATIC" +
"AL SANS-SERIF DIGIT FOURMATHEMATICAL SANS-SERIF DIGIT FIVEMATHEMATICAL S" +
"ANS-SERIF DIGIT SIXMATHEMATICAL SANS-SERIF DIGIT SEVENMATHEMATICAL SANS-" +
"SERIF DIGIT EIGHTMATHEMATICAL SANS-SERIF DIGIT NINEMATHEMATICAL SANS-SER" +
"IF BOLD DIGIT ZEROMATHEMATICAL SANS-SERIF BOLD DIGIT ONEMATHEMATICAL SAN" +
"S-SERIF BOLD DIGIT TWOMATHEMATICAL SANS-SERIF BOLD DIGIT THREEMATHEMATIC" +
"AL SANS-SERIF BOLD DIGIT FOURMATHEMATICAL SANS-SERIF BOLD DIGIT FIVEMATH" +
"EMATICAL SANS-SERIF BOLD DIGIT SIXMATHEMATICAL SANS-SERIF BOLD DIGIT SEV" +
"ENMATHEMATICAL SANS-SERIF BOLD DIGIT EIGHTMATHEMATICAL SANS-SERIF BOLD D" +
"IGIT NINEMATHEMATICAL MONOSPACE DIGIT ZEROMATHEMATICAL MONOSPACE DIGIT O" +
"NEMATHEMATICAL MONOSPACE DIGIT TWOMATHEMATICAL MONOSPACE DIGIT THREEMATH" +
"EMATICAL MONOSPACE DIGIT FOURMATHEMATICAL MONOSPACE DIGIT FIVEMATHEMATIC" +
"AL MONOSPACE DIGIT SIXMATHEMATICAL MONOSPACE DIGIT SEVENMATHEMATICAL MON" +
"OSPACE DIGIT EIGHTMATHEMATICAL MONOSPACE DIGIT NINESIGNWRITING HAND-FIST" +
" INDEXSIGNWRITING HAND-CIRCLE INDEXSIGNWRITING HAND-CUP INDEXSIGNWRITING" +
" HAND-OVAL INDEXSIGNWRITING HAND-HINGE INDEXSIGNWRITING HAND-ANGLE INDEX" +
"SIGNWRITING HAND-FIST INDEX BENTSIGNWRITING HAND-CIRCLE INDEX BENTSIGNWR" +
"ITING HAND-FIST THUMB UNDER INDEX BENTSIGNWRITING HAND-FIST INDEX RAISED" +
" KNUCKLESIGNWRITING HAND-FIST INDEX CUPPEDSIGNWRITING HAND-FIST INDEX HI" +
"NGEDSIGNWRITING HAND-FIST INDEX HINGED LOWSIGNWRITING HAND-CIRCLE INDEX " +
"HINGESIGNWRITING HAND-FIST INDEX MIDDLESIGNWRITING HAND-CIRCLE INDEX MID" +
"DLESIGNWRITING HAND-FIST INDEX MIDDLE BENTSIGNWRITING HAND-FIST INDEX MI" +
"DDLE RAISED KNUCKLESSIGNWRITING HAND-FIST INDEX MIDDLE HINGEDSIGNWRITING" +
" HAND-FIST INDEX UP MIDDLE HINGEDSIGNWRITING HAND-FIST INDEX HINGED MIDD" +
"LE UPSIGNWRITING HAND-FIST INDEX MIDDLE CONJOINEDSIGNWRITING HAND-FIST I" +
"NDEX MIDDLE CONJOINED INDEX BENTSIGNWRITING HAND-FIST INDEX MIDDLE CONJO" +
"INED MIDDLE BENTSIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED CUPPEDSIGNW" +
"RITING HAND-FIST INDEX MIDDLE CONJOINED HINGEDSIGNWRITING HAND-FIST INDE" +
"X MIDDLE CROSSEDSIGNWRITING HAND-CIRCLE INDEX MIDDLE CROSSEDSIGNWRITING " +
"HAND-FIST MIDDLE BENT OVER INDEXSIGNWRITING HAND-FIST INDEX BENT OVER MI" +
"DDLESIGNWRITING HAND-FIST INDEX MIDDLE THUMBSIGNWRITING HAND-CIRCLE INDE" +
"X MIDDLE THUMBSIGNWRITING HAND-FIST INDEX MIDDLE STRAIGHT THUMB BENTSIGN" +
"WRITING HAND-FIST INDEX MIDDLE BENT THUMB STRAIGHTSIGNWRITING HAND-FIST " +
"INDEX MIDDLE THUMB BENTSIGNWRITING HAND-FIST INDEX MIDDLE HINGED SPREAD " +
"THUMB SIDESIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED THUMB SIDESIGNWRI" +
"TING HAND-FIST INDEX UP MIDDLE HINGED THUMB CONJOINEDSIGNWRITING HAND-FI" +
"ST INDEX HINGED MIDDLE UP THUMB SIDESIGNWRITING HAND-FIST INDEX MIDDLE U" +
"P SPREAD THUMB FORWARDSIGNWRITING HAND-FIST INDEX MIDDLE THUMB CUPPEDSIG" +
"NWRITING HAND-FIST INDEX MIDDLE THUMB CIRCLEDSIGNWRITING HAND-FIST INDEX" +
" MIDDLE THUMB HOOKEDSIGNWRITING HAND-FIST INDEX MIDDLE THUMB HINGEDSIGNW" +
"RITING HAND-FIST THUMB BETWEEN INDEX MIDDLE STRAIGHTSIGNWRITING HAND-FIS" +
"T INDEX MIDDLE CONJOINED THUMB SIDESIGNWRITING HAND-FIST INDEX MIDDLE CO" +
"NJOINED THUMB SIDE CONJOINEDSIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED" +
" THUMB SIDE BENTSIGNWRITING HAND-FIST MIDDLE THUMB HOOKED INDEX UPSIGNWR" +
"ITING HAND-FIST INDEX THUMB HOOKED MIDDLE UPSIGNWRITING HAND-FIST INDEX " +
"MIDDLE CONJOINED HINGED THUMB SIDESIGNWRITING HAND-FIST INDEX MIDDLE CRO" +
"SSED THUMB SIDESIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB FORWAR" +
"DSIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED CUPPED THUMB FORWARDSIGNWR" +
"ITING HAND-FIST MIDDLE THUMB CUPPED INDEX UPSIGNWRITING HAND-FIST INDEX " +
"THUMB CUPPED MIDDLE UPSIGNWRITING HAND-FIST MIDDLE THUMB CIRCLED INDEX U" +
"PSIGNWRITING HAND-FIST MIDDLE THUMB CIRCLED INDEX HINGEDSIGNWRITING HAND") + ("" +
"-FIST INDEX THUMB ANGLED OUT MIDDLE UPSIGNWRITING HAND-FIST INDEX THUMB " +
"ANGLED IN MIDDLE UPSIGNWRITING HAND-FIST INDEX THUMB CIRCLED MIDDLE UPSI" +
"GNWRITING HAND-FIST INDEX MIDDLE THUMB CONJOINED HINGEDSIGNWRITING HAND-" +
"FIST INDEX MIDDLE THUMB ANGLED OUTSIGNWRITING HAND-FIST INDEX MIDDLE THU" +
"MB ANGLEDSIGNWRITING HAND-FIST MIDDLE THUMB ANGLED OUT INDEX UPSIGNWRITI" +
"NG HAND-FIST MIDDLE THUMB ANGLED OUT INDEX CROSSEDSIGNWRITING HAND-FIST " +
"MIDDLE THUMB ANGLED INDEX UPSIGNWRITING HAND-FIST INDEX THUMB HOOKED MID" +
"DLE HINGEDSIGNWRITING HAND-FLAT FOUR FINGERSSIGNWRITING HAND-FLAT FOUR F" +
"INGERS BENTSIGNWRITING HAND-FLAT FOUR FINGERS HINGEDSIGNWRITING HAND-FLA" +
"T FOUR FINGERS CONJOINEDSIGNWRITING HAND-FLAT FOUR FINGERS CONJOINED SPL" +
"ITSIGNWRITING HAND-CLAW FOUR FINGERS CONJOINEDSIGNWRITING HAND-FIST FOUR" +
" FINGERS CONJOINED BENTSIGNWRITING HAND-HINGE FOUR FINGERS CONJOINEDSIGN" +
"WRITING HAND-FLAT FIVE FINGERS SPREADSIGNWRITING HAND-FLAT HEEL FIVE FIN" +
"GERS SPREADSIGNWRITING HAND-FLAT FIVE FINGERS SPREAD FOUR BENTSIGNWRITIN" +
"G HAND-FLAT HEEL FIVE FINGERS SPREAD FOUR BENTSIGNWRITING HAND-FLAT FIVE" +
" FINGERS SPREAD BENTSIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD BENTS" +
"IGNWRITING HAND-FLAT FIVE FINGERS SPREAD THUMB FORWARDSIGNWRITING HAND-C" +
"UP FIVE FINGERS SPREADSIGNWRITING HAND-CUP FIVE FINGERS SPREAD OPENSIGNW" +
"RITING HAND-HINGE FIVE FINGERS SPREAD OPENSIGNWRITING HAND-OVAL FIVE FIN" +
"GERS SPREADSIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGEDSIGNWRITING H" +
"AND-FLAT FIVE FINGERS SPREAD HINGED THUMB SIDESIGNWRITING HAND-FLAT FIVE" +
" FINGERS SPREAD HINGED NO THUMBSIGNWRITING HAND-FLATSIGNWRITING HAND-FLA" +
"T BETWEEN PALM FACINGSSIGNWRITING HAND-FLAT HEELSIGNWRITING HAND-FLAT TH" +
"UMB SIDESIGNWRITING HAND-FLAT HEEL THUMB SIDESIGNWRITING HAND-FLAT THUMB" +
" BENTSIGNWRITING HAND-FLAT THUMB FORWARDSIGNWRITING HAND-FLAT SPLIT INDE" +
"X THUMB SIDESIGNWRITING HAND-FLAT SPLIT CENTRESIGNWRITING HAND-FLAT SPLI" +
"T CENTRE THUMB SIDESIGNWRITING HAND-FLAT SPLIT CENTRE THUMB SIDE BENTSIG" +
"NWRITING HAND-FLAT SPLIT LITTLESIGNWRITING HAND-CLAWSIGNWRITING HAND-CLA" +
"W THUMB SIDESIGNWRITING HAND-CLAW NO THUMBSIGNWRITING HAND-CLAW THUMB FO" +
"RWARDSIGNWRITING HAND-HOOK CURLICUESIGNWRITING HAND-HOOKSIGNWRITING HAND" +
"-CUP OPENSIGNWRITING HAND-CUPSIGNWRITING HAND-CUP OPEN THUMB SIDESIGNWRI" +
"TING HAND-CUP THUMB SIDESIGNWRITING HAND-CUP OPEN NO THUMBSIGNWRITING HA" +
"ND-CUP NO THUMBSIGNWRITING HAND-CUP OPEN THUMB FORWARDSIGNWRITING HAND-C" +
"UP THUMB FORWARDSIGNWRITING HAND-CURLICUE OPENSIGNWRITING HAND-CURLICUES" +
"IGNWRITING HAND-CIRCLESIGNWRITING HAND-OVALSIGNWRITING HAND-OVAL THUMB S" +
"IDESIGNWRITING HAND-OVAL NO THUMBSIGNWRITING HAND-OVAL THUMB FORWARDSIGN" +
"WRITING HAND-HINGE OPENSIGNWRITING HAND-HINGE OPEN THUMB FORWARDSIGNWRIT" +
"ING HAND-HINGESIGNWRITING HAND-HINGE SMALLSIGNWRITING HAND-HINGE OPEN TH" +
"UMB SIDESIGNWRITING HAND-HINGE THUMB SIDESIGNWRITING HAND-HINGE OPEN NO " +
"THUMBSIGNWRITING HAND-HINGE NO THUMBSIGNWRITING HAND-HINGE THUMB SIDE TO" +
"UCHING INDEXSIGNWRITING HAND-HINGE THUMB BETWEEN MIDDLE RINGSIGNWRITING " +
"HAND-ANGLESIGNWRITING HAND-FIST INDEX MIDDLE RINGSIGNWRITING HAND-CIRCLE" +
" INDEX MIDDLE RINGSIGNWRITING HAND-HINGE INDEX MIDDLE RINGSIGNWRITING HA" +
"ND-ANGLE INDEX MIDDLE RINGSIGNWRITING HAND-HINGE LITTLESIGNWRITING HAND-" +
"FIST INDEX MIDDLE RING BENTSIGNWRITING HAND-FIST INDEX MIDDLE RING CONJO" +
"INEDSIGNWRITING HAND-HINGE INDEX MIDDLE RING CONJOINEDSIGNWRITING HAND-F" +
"IST LITTLE DOWNSIGNWRITING HAND-FIST LITTLE DOWN RIPPLE STRAIGHTSIGNWRIT" +
"ING HAND-FIST LITTLE DOWN RIPPLE CURVEDSIGNWRITING HAND-FIST LITTLE DOWN" +
" OTHERS CIRCLEDSIGNWRITING HAND-FIST LITTLE UPSIGNWRITING HAND-FIST THUM" +
"B UNDER LITTLE UPSIGNWRITING HAND-CIRCLE LITTLE UPSIGNWRITING HAND-OVAL " +
"LITTLE UPSIGNWRITING HAND-ANGLE LITTLE UPSIGNWRITING HAND-FIST LITTLE RA" +
"ISED KNUCKLESIGNWRITING HAND-FIST LITTLE BENTSIGNWRITING HAND-FIST LITTL" +
"E TOUCHES THUMBSIGNWRITING HAND-FIST LITTLE THUMBSIGNWRITING HAND-HINGE " +
"LITTLE THUMBSIGNWRITING HAND-FIST LITTLE INDEX THUMBSIGNWRITING HAND-HIN" +
"GE LITTLE INDEX THUMBSIGNWRITING HAND-ANGLE LITTLE INDEX THUMB INDEX THU" +
"MB OUTSIGNWRITING HAND-ANGLE LITTLE INDEX THUMB INDEX THUMBSIGNWRITING H" +
"AND-FIST LITTLE INDEXSIGNWRITING HAND-CIRCLE LITTLE INDEXSIGNWRITING HAN" +
"D-HINGE LITTLE INDEXSIGNWRITING HAND-ANGLE LITTLE INDEXSIGNWRITING HAND-" +
"FIST INDEX MIDDLE LITTLESIGNWRITING HAND-CIRCLE INDEX MIDDLE LITTLESIGNW" +
"RITING HAND-HINGE INDEX MIDDLE LITTLESIGNWRITING HAND-HINGE RINGSIGNWRIT" +
"ING HAND-ANGLE INDEX MIDDLE LITTLESIGNWRITING HAND-FIST INDEX MIDDLE CRO" +
"SS LITTLESIGNWRITING HAND-CIRCLE INDEX MIDDLE CROSS LITTLESIGNWRITING HA" +
"ND-FIST RING DOWNSIGNWRITING HAND-HINGE RING DOWN INDEX THUMB HOOK MIDDL" +
"ESIGNWRITING HAND-ANGLE RING DOWN MIDDLE THUMB INDEX CROSSSIGNWRITING HA") + ("" +
"ND-FIST RING UPSIGNWRITING HAND-FIST RING RAISED KNUCKLESIGNWRITING HAND" +
"-FIST RING LITTLESIGNWRITING HAND-CIRCLE RING LITTLESIGNWRITING HAND-OVA" +
"L RING LITTLESIGNWRITING HAND-ANGLE RING LITTLESIGNWRITING HAND-FIST RIN" +
"G MIDDLESIGNWRITING HAND-FIST RING MIDDLE CONJOINEDSIGNWRITING HAND-FIST" +
" RING MIDDLE RAISED KNUCKLESSIGNWRITING HAND-FIST RING INDEXSIGNWRITING " +
"HAND-FIST RING THUMBSIGNWRITING HAND-HOOK RING THUMBSIGNWRITING HAND-FIS" +
"T INDEX RING LITTLESIGNWRITING HAND-CIRCLE INDEX RING LITTLESIGNWRITING " +
"HAND-CURLICUE INDEX RING LITTLE ONSIGNWRITING HAND-HOOK INDEX RING LITTL" +
"E OUTSIGNWRITING HAND-HOOK INDEX RING LITTLE INSIGNWRITING HAND-HOOK IND" +
"EX RING LITTLE UNDERSIGNWRITING HAND-CUP INDEX RING LITTLESIGNWRITING HA" +
"ND-HINGE INDEX RING LITTLESIGNWRITING HAND-ANGLE INDEX RING LITTLE OUTSI" +
"GNWRITING HAND-ANGLE INDEX RING LITTLESIGNWRITING HAND-FIST MIDDLE DOWNS" +
"IGNWRITING HAND-HINGE MIDDLESIGNWRITING HAND-FIST MIDDLE UPSIGNWRITING H" +
"AND-CIRCLE MIDDLE UPSIGNWRITING HAND-FIST MIDDLE RAISED KNUCKLESIGNWRITI" +
"NG HAND-FIST MIDDLE UP THUMB SIDESIGNWRITING HAND-HOOK MIDDLE THUMBSIGNW" +
"RITING HAND-FIST MIDDLE THUMB LITTLESIGNWRITING HAND-FIST MIDDLE LITTLES" +
"IGNWRITING HAND-FIST MIDDLE RING LITTLESIGNWRITING HAND-CIRCLE MIDDLE RI" +
"NG LITTLESIGNWRITING HAND-CURLICUE MIDDLE RING LITTLE ONSIGNWRITING HAND" +
"-CUP MIDDLE RING LITTLESIGNWRITING HAND-HINGE MIDDLE RING LITTLESIGNWRIT" +
"ING HAND-ANGLE MIDDLE RING LITTLE OUTSIGNWRITING HAND-ANGLE MIDDLE RING " +
"LITTLE INSIGNWRITING HAND-ANGLE MIDDLE RING LITTLESIGNWRITING HAND-CIRCL" +
"E MIDDLE RING LITTLE BENTSIGNWRITING HAND-CLAW MIDDLE RING LITTLE CONJOI" +
"NEDSIGNWRITING HAND-CLAW MIDDLE RING LITTLE CONJOINED SIDESIGNWRITING HA" +
"ND-HOOK MIDDLE RING LITTLE CONJOINED OUTSIGNWRITING HAND-HOOK MIDDLE RIN" +
"G LITTLE CONJOINED INSIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINEDS" +
"IGNWRITING HAND-HINGE INDEX HINGEDSIGNWRITING HAND-FIST INDEX THUMB SIDE" +
"SIGNWRITING HAND-HINGE INDEX THUMB SIDESIGNWRITING HAND-FIST INDEX THUMB" +
" SIDE THUMB DIAGONALSIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB CONJOIN" +
"EDSIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB BENTSIGNWRITING HAND-FIST" +
" INDEX THUMB SIDE INDEX BENTSIGNWRITING HAND-FIST INDEX THUMB SIDE BOTH " +
"BENTSIGNWRITING HAND-FIST INDEX THUMB SIDE INDEX HINGESIGNWRITING HAND-F" +
"IST INDEX THUMB FORWARD INDEX STRAIGHTSIGNWRITING HAND-FIST INDEX THUMB " +
"FORWARD INDEX BENTSIGNWRITING HAND-FIST INDEX THUMB HOOKSIGNWRITING HAND" +
"-FIST INDEX THUMB CURLICUESIGNWRITING HAND-FIST INDEX THUMB CURVE THUMB " +
"INSIDESIGNWRITING HAND-CLAW INDEX THUMB CURVE THUMB INSIDESIGNWRITING HA" +
"ND-FIST INDEX THUMB CURVE THUMB UNDERSIGNWRITING HAND-FIST INDEX THUMB C" +
"IRCLESIGNWRITING HAND-CUP INDEX THUMBSIGNWRITING HAND-CUP INDEX THUMB OP" +
"ENSIGNWRITING HAND-HINGE INDEX THUMB OPENSIGNWRITING HAND-HINGE INDEX TH" +
"UMB LARGESIGNWRITING HAND-HINGE INDEX THUMBSIGNWRITING HAND-HINGE INDEX " +
"THUMB SMALLSIGNWRITING HAND-ANGLE INDEX THUMB OUTSIGNWRITING HAND-ANGLE " +
"INDEX THUMB INSIGNWRITING HAND-ANGLE INDEX THUMBSIGNWRITING HAND-FIST TH" +
"UMBSIGNWRITING HAND-FIST THUMB HEELSIGNWRITING HAND-FIST THUMB SIDE DIAG" +
"ONALSIGNWRITING HAND-FIST THUMB SIDE CONJOINEDSIGNWRITING HAND-FIST THUM" +
"B SIDE BENTSIGNWRITING HAND-FIST THUMB FORWARDSIGNWRITING HAND-FIST THUM" +
"B BETWEEN INDEX MIDDLESIGNWRITING HAND-FIST THUMB BETWEEN MIDDLE RINGSIG" +
"NWRITING HAND-FIST THUMB BETWEEN RING LITTLESIGNWRITING HAND-FIST THUMB " +
"UNDER TWO FINGERSSIGNWRITING HAND-FIST THUMB OVER TWO FINGERSSIGNWRITING" +
" HAND-FIST THUMB UNDER THREE FINGERSSIGNWRITING HAND-FIST THUMB UNDER FO" +
"UR FINGERSSIGNWRITING HAND-FIST THUMB OVER FOUR RAISED KNUCKLESSIGNWRITI" +
"NG HAND-FISTSIGNWRITING HAND-FIST HEELSIGNWRITING TOUCH SINGLESIGNWRITIN" +
"G TOUCH MULTIPLESIGNWRITING TOUCH BETWEENSIGNWRITING GRASP SINGLESIGNWRI" +
"TING GRASP MULTIPLESIGNWRITING GRASP BETWEENSIGNWRITING STRIKE SINGLESIG" +
"NWRITING STRIKE MULTIPLESIGNWRITING STRIKE BETWEENSIGNWRITING BRUSH SING" +
"LESIGNWRITING BRUSH MULTIPLESIGNWRITING BRUSH BETWEENSIGNWRITING RUB SIN" +
"GLESIGNWRITING RUB MULTIPLESIGNWRITING RUB BETWEENSIGNWRITING SURFACE SY" +
"MBOLSSIGNWRITING SURFACE BETWEENSIGNWRITING SQUEEZE LARGE SINGLESIGNWRIT" +
"ING SQUEEZE SMALL SINGLESIGNWRITING SQUEEZE LARGE MULTIPLESIGNWRITING SQ" +
"UEEZE SMALL MULTIPLESIGNWRITING SQUEEZE SEQUENTIALSIGNWRITING FLICK LARG" +
"E SINGLESIGNWRITING FLICK SMALL SINGLESIGNWRITING FLICK LARGE MULTIPLESI" +
"GNWRITING FLICK SMALL MULTIPLESIGNWRITING FLICK SEQUENTIALSIGNWRITING SQ" +
"UEEZE FLICK ALTERNATINGSIGNWRITING MOVEMENT-HINGE UP DOWN LARGESIGNWRITI" +
"NG MOVEMENT-HINGE UP DOWN SMALLSIGNWRITING MOVEMENT-HINGE UP SEQUENTIALS" +
"IGNWRITING MOVEMENT-HINGE DOWN SEQUENTIALSIGNWRITING MOVEMENT-HINGE UP D" +
"OWN ALTERNATING LARGESIGNWRITING MOVEMENT-HINGE UP DOWN ALTERNATING SMAL") + ("" +
"LSIGNWRITING MOVEMENT-HINGE SIDE TO SIDE SCISSORSSIGNWRITING MOVEMENT-WA" +
"LLPLANE FINGER CONTACTSIGNWRITING MOVEMENT-FLOORPLANE FINGER CONTACTSIGN" +
"WRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT SMALLSIGNWRITING MOVEMENT-WAL" +
"LPLANE SINGLE STRAIGHT MEDIUMSIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAI" +
"GHT LARGESIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT LARGESTSIGNWRITI" +
"NG MOVEMENT-WALLPLANE SINGLE WRIST FLEXSIGNWRITING MOVEMENT-WALLPLANE DO" +
"UBLE STRAIGHTSIGNWRITING MOVEMENT-WALLPLANE DOUBLE WRIST FLEXSIGNWRITING" +
" MOVEMENT-WALLPLANE DOUBLE ALTERNATINGSIGNWRITING MOVEMENT-WALLPLANE DOU" +
"BLE ALTERNATING WRIST FLEXSIGNWRITING MOVEMENT-WALLPLANE CROSSSIGNWRITIN" +
"G MOVEMENT-WALLPLANE TRIPLE STRAIGHT MOVEMENTSIGNWRITING MOVEMENT-WALLPL" +
"ANE TRIPLE WRIST FLEXSIGNWRITING MOVEMENT-WALLPLANE TRIPLE ALTERNATINGSI" +
"GNWRITING MOVEMENT-WALLPLANE TRIPLE ALTERNATING WRIST FLEXSIGNWRITING MO" +
"VEMENT-WALLPLANE BEND SMALLSIGNWRITING MOVEMENT-WALLPLANE BEND MEDIUMSIG" +
"NWRITING MOVEMENT-WALLPLANE BEND LARGESIGNWRITING MOVEMENT-WALLPLANE COR" +
"NER SMALLSIGNWRITING MOVEMENT-WALLPLANE CORNER MEDIUMSIGNWRITING MOVEMEN" +
"T-WALLPLANE CORNER LARGESIGNWRITING MOVEMENT-WALLPLANE CORNER ROTATIONSI" +
"GNWRITING MOVEMENT-WALLPLANE CHECK SMALLSIGNWRITING MOVEMENT-WALLPLANE C" +
"HECK MEDIUMSIGNWRITING MOVEMENT-WALLPLANE CHECK LARGESIGNWRITING MOVEMEN" +
"T-WALLPLANE BOX SMALLSIGNWRITING MOVEMENT-WALLPLANE BOX MEDIUMSIGNWRITIN" +
"G MOVEMENT-WALLPLANE BOX LARGESIGNWRITING MOVEMENT-WALLPLANE ZIGZAG SMAL" +
"LSIGNWRITING MOVEMENT-WALLPLANE ZIGZAG MEDIUMSIGNWRITING MOVEMENT-WALLPL" +
"ANE ZIGZAG LARGESIGNWRITING MOVEMENT-WALLPLANE PEAKS SMALLSIGNWRITING MO" +
"VEMENT-WALLPLANE PEAKS MEDIUMSIGNWRITING MOVEMENT-WALLPLANE PEAKS LARGES" +
"IGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE SINGLESIGNWRITING TRAVEL-" +
"WALLPLANE ROTATION-WALLPLANE DOUBLESIGNWRITING TRAVEL-WALLPLANE ROTATION" +
"-WALLPLANE ALTERNATINGSIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE S" +
"INGLESIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE DOUBLESIGNWRITING " +
"TRAVEL-WALLPLANE ROTATION-FLOORPLANE ALTERNATINGSIGNWRITING TRAVEL-WALLP" +
"LANE SHAKINGSIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL SINGLESIGNWRITING TR" +
"AVEL-WALLPLANE ARM SPIRAL DOUBLESIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL " +
"TRIPLESIGNWRITING MOVEMENT-DIAGONAL AWAY SMALLSIGNWRITING MOVEMENT-DIAGO" +
"NAL AWAY MEDIUMSIGNWRITING MOVEMENT-DIAGONAL AWAY LARGESIGNWRITING MOVEM" +
"ENT-DIAGONAL AWAY LARGESTSIGNWRITING MOVEMENT-DIAGONAL TOWARDS SMALLSIGN" +
"WRITING MOVEMENT-DIAGONAL TOWARDS MEDIUMSIGNWRITING MOVEMENT-DIAGONAL TO" +
"WARDS LARGESIGNWRITING MOVEMENT-DIAGONAL TOWARDS LARGESTSIGNWRITING MOVE" +
"MENT-DIAGONAL BETWEEN AWAY SMALLSIGNWRITING MOVEMENT-DIAGONAL BETWEEN AW" +
"AY MEDIUMSIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY LARGESIGNWRITING MOV" +
"EMENT-DIAGONAL BETWEEN AWAY LARGESTSIGNWRITING MOVEMENT-DIAGONAL BETWEEN" +
" TOWARDS SMALLSIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS MEDIUMSIGNWR" +
"ITING MOVEMENT-DIAGONAL BETWEEN TOWARDS LARGESIGNWRITING MOVEMENT-DIAGON" +
"AL BETWEEN TOWARDS LARGESTSIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGH" +
"T SMALLSIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT MEDIUMSIGNWRITING" +
" MOVEMENT-FLOORPLANE SINGLE STRAIGHT LARGESIGNWRITING MOVEMENT-FLOORPLAN" +
"E SINGLE STRAIGHT LARGESTSIGNWRITING MOVEMENT-FLOORPLANE SINGLE WRIST FL" +
"EXSIGNWRITING MOVEMENT-FLOORPLANE DOUBLE STRAIGHTSIGNWRITING MOVEMENT-FL" +
"OORPLANE DOUBLE WRIST FLEXSIGNWRITING MOVEMENT-FLOORPLANE DOUBLE ALTERNA" +
"TINGSIGNWRITING MOVEMENT-FLOORPLANE DOUBLE ALTERNATING WRIST FLEXSIGNWRI" +
"TING MOVEMENT-FLOORPLANE CROSSSIGNWRITING MOVEMENT-FLOORPLANE TRIPLE STR" +
"AIGHT MOVEMENTSIGNWRITING MOVEMENT-FLOORPLANE TRIPLE WRIST FLEXSIGNWRITI" +
"NG MOVEMENT-FLOORPLANE TRIPLE ALTERNATING MOVEMENTSIGNWRITING MOVEMENT-F" +
"LOORPLANE TRIPLE ALTERNATING WRIST FLEXSIGNWRITING MOVEMENT-FLOORPLANE B" +
"ENDSIGNWRITING MOVEMENT-FLOORPLANE CORNER SMALLSIGNWRITING MOVEMENT-FLOO" +
"RPLANE CORNER MEDIUMSIGNWRITING MOVEMENT-FLOORPLANE CORNER LARGESIGNWRIT" +
"ING MOVEMENT-FLOORPLANE CHECKSIGNWRITING MOVEMENT-FLOORPLANE BOX SMALLSI" +
"GNWRITING MOVEMENT-FLOORPLANE BOX MEDIUMSIGNWRITING MOVEMENT-FLOORPLANE " +
"BOX LARGESIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG SMALLSIGNWRITING MOVEMEN" +
"T-FLOORPLANE ZIGZAG MEDIUMSIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG LARGESI" +
"GNWRITING MOVEMENT-FLOORPLANE PEAKS SMALLSIGNWRITING MOVEMENT-FLOORPLANE" +
" PEAKS MEDIUMSIGNWRITING MOVEMENT-FLOORPLANE PEAKS LARGESIGNWRITING TRAV" +
"EL-FLOORPLANE ROTATION-FLOORPLANE SINGLESIGNWRITING TRAVEL-FLOORPLANE RO" +
"TATION-FLOORPLANE DOUBLESIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLAN" +
"E ALTERNATINGSIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE SINGLESIGN" +
"WRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE DOUBLESIGNWRITING TRAVEL-FL" +
"OORPLANE ROTATION-WALLPLANE ALTERNATINGSIGNWRITING TRAVEL-FLOORPLANE SHA") + ("" +
"KINGSIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER SMALLSIGNWRITING MOVEME" +
"NT-WALLPLANE CURVE QUARTER MEDIUMSIGNWRITING MOVEMENT-WALLPLANE CURVE QU" +
"ARTER LARGESIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER LARGESTSIGNWRITI" +
"NG MOVEMENT-WALLPLANE CURVE HALF-CIRCLE SMALLSIGNWRITING MOVEMENT-WALLPL" +
"ANE CURVE HALF-CIRCLE MEDIUMSIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CI" +
"RCLE LARGESIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE LARGESTSIGNWR" +
"ITING MOVEMENT-WALLPLANE CURVE THREE-QUARTER CIRCLE SMALLSIGNWRITING MOV" +
"EMENT-WALLPLANE CURVE THREE-QUARTER CIRCLE MEDIUMSIGNWRITING MOVEMENT-WA" +
"LLPLANE HUMP SMALLSIGNWRITING MOVEMENT-WALLPLANE HUMP MEDIUMSIGNWRITING " +
"MOVEMENT-WALLPLANE HUMP LARGESIGNWRITING MOVEMENT-WALLPLANE LOOP SMALLSI" +
"GNWRITING MOVEMENT-WALLPLANE LOOP MEDIUMSIGNWRITING MOVEMENT-WALLPLANE L" +
"OOP LARGESIGNWRITING MOVEMENT-WALLPLANE LOOP SMALL DOUBLESIGNWRITING MOV" +
"EMENT-WALLPLANE WAVE CURVE DOUBLE SMALLSIGNWRITING MOVEMENT-WALLPLANE WA" +
"VE CURVE DOUBLE MEDIUMSIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE L" +
"ARGESIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE SMALLSIGNWRITING MO" +
"VEMENT-WALLPLANE WAVE CURVE TRIPLE MEDIUMSIGNWRITING MOVEMENT-WALLPLANE " +
"WAVE CURVE TRIPLE LARGESIGNWRITING MOVEMENT-WALLPLANE CURVE THEN STRAIGH" +
"TSIGNWRITING MOVEMENT-WALLPLANE CURVED CROSS SMALLSIGNWRITING MOVEMENT-W" +
"ALLPLANE CURVED CROSS MEDIUMSIGNWRITING ROTATION-WALLPLANE SINGLESIGNWRI" +
"TING ROTATION-WALLPLANE DOUBLESIGNWRITING ROTATION-WALLPLANE ALTERNATESI" +
"GNWRITING MOVEMENT-WALLPLANE SHAKINGSIGNWRITING MOVEMENT-WALLPLANE CURVE" +
" HITTING FRONT WALLSIGNWRITING MOVEMENT-WALLPLANE HUMP HITTING FRONT WAL" +
"LSIGNWRITING MOVEMENT-WALLPLANE LOOP HITTING FRONT WALLSIGNWRITING MOVEM" +
"ENT-WALLPLANE WAVE HITTING FRONT WALLSIGNWRITING ROTATION-WALLPLANE SING" +
"LE HITTING FRONT WALLSIGNWRITING ROTATION-WALLPLANE DOUBLE HITTING FRONT" +
" WALLSIGNWRITING ROTATION-WALLPLANE ALTERNATING HITTING FRONT WALLSIGNWR" +
"ITING MOVEMENT-WALLPLANE CURVE HITTING CHESTSIGNWRITING MOVEMENT-WALLPLA" +
"NE HUMP HITTING CHESTSIGNWRITING MOVEMENT-WALLPLANE LOOP HITTING CHESTSI" +
"GNWRITING MOVEMENT-WALLPLANE WAVE HITTING CHESTSIGNWRITING ROTATION-WALL" +
"PLANE SINGLE HITTING CHESTSIGNWRITING ROTATION-WALLPLANE DOUBLE HITTING " +
"CHESTSIGNWRITING ROTATION-WALLPLANE ALTERNATING HITTING CHESTSIGNWRITING" +
" MOVEMENT-WALLPLANE WAVE DIAGONAL PATH SMALLSIGNWRITING MOVEMENT-WALLPLA" +
"NE WAVE DIAGONAL PATH MEDIUMSIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL" +
" PATH LARGESIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING CEILING SMALLSI" +
"GNWRITING MOVEMENT-FLOORPLANE CURVE HITTING CEILING LARGESIGNWRITING MOV" +
"EMENT-FLOORPLANE HUMP HITTING CEILING SMALL DOUBLESIGNWRITING MOVEMENT-F" +
"LOORPLANE HUMP HITTING CEILING LARGE DOUBLESIGNWRITING MOVEMENT-FLOORPLA" +
"NE HUMP HITTING CEILING SMALL TRIPLESIGNWRITING MOVEMENT-FLOORPLANE HUMP" +
" HITTING CEILING LARGE TRIPLESIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTIN" +
"G CEILING SMALL SINGLESIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILI" +
"NG LARGE SINGLESIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING SMAL" +
"L DOUBLESIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING LARGE DOUBL" +
"ESIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING CEILING SMALLSIGNWRITING M" +
"OVEMENT-FLOORPLANE WAVE HITTING CEILING LARGESIGNWRITING ROTATION-FLOORP" +
"LANE SINGLE HITTING CEILINGSIGNWRITING ROTATION-FLOORPLANE DOUBLE HITTIN" +
"G CEILINGSIGNWRITING ROTATION-FLOORPLANE ALTERNATING HITTING CEILINGSIGN" +
"WRITING MOVEMENT-FLOORPLANE CURVE HITTING FLOOR SMALLSIGNWRITING MOVEMEN" +
"T-FLOORPLANE CURVE HITTING FLOOR LARGESIGNWRITING MOVEMENT-FLOORPLANE HU" +
"MP HITTING FLOOR SMALL DOUBLESIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTIN" +
"G FLOOR LARGE DOUBLESIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR T" +
"RIPLE SMALL TRIPLESIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR TRI" +
"PLE LARGE TRIPLESIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR SMALL" +
" SINGLESIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR LARGE SINGLESI" +
"GNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR SMALL DOUBLESIGNWRITING" +
" MOVEMENT-FLOORPLANE LOOP HITTING FLOOR LARGE DOUBLESIGNWRITING MOVEMENT" +
"-FLOORPLANE WAVE HITTING FLOOR SMALLSIGNWRITING MOVEMENT-FLOORPLANE WAVE" +
" HITTING FLOOR LARGESIGNWRITING ROTATION-FLOORPLANE SINGLE HITTING FLOOR" +
"SIGNWRITING ROTATION-FLOORPLANE DOUBLE HITTING FLOORSIGNWRITING ROTATION" +
"-FLOORPLANE ALTERNATING HITTING FLOORSIGNWRITING MOVEMENT-FLOORPLANE CUR" +
"VE SMALLSIGNWRITING MOVEMENT-FLOORPLANE CURVE MEDIUMSIGNWRITING MOVEMENT" +
"-FLOORPLANE CURVE LARGESIGNWRITING MOVEMENT-FLOORPLANE CURVE LARGESTSIGN" +
"WRITING MOVEMENT-FLOORPLANE CURVE COMBINEDSIGNWRITING MOVEMENT-FLOORPLAN" +
"E HUMP SMALLSIGNWRITING MOVEMENT-FLOORPLANE LOOP SMALLSIGNWRITING MOVEME" +
"NT-FLOORPLANE WAVE SNAKESIGNWRITING MOVEMENT-FLOORPLANE WAVE SMALLSIGNWR") + ("" +
"ITING MOVEMENT-FLOORPLANE WAVE LARGESIGNWRITING ROTATION-FLOORPLANE SING" +
"LESIGNWRITING ROTATION-FLOORPLANE DOUBLESIGNWRITING ROTATION-FLOORPLANE " +
"ALTERNATINGSIGNWRITING MOVEMENT-FLOORPLANE SHAKING PARALLELSIGNWRITING M" +
"OVEMENT-WALLPLANE ARM CIRCLE SMALL SINGLESIGNWRITING MOVEMENT-WALLPLANE " +
"ARM CIRCLE MEDIUM SINGLESIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE SMALL " +
"DOUBLESIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE MEDIUM DOUBLESIGNWRITING" +
" MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL SMALL SINGLESIGNWRITING MOV" +
"EMENT-FLOORPLANE ARM CIRCLE HITTING WALL MEDIUM SINGLESIGNWRITING MOVEME" +
"NT-FLOORPLANE ARM CIRCLE HITTING WALL LARGE SINGLESIGNWRITING MOVEMENT-F" +
"LOORPLANE ARM CIRCLE HITTING WALL SMALL DOUBLESIGNWRITING MOVEMENT-FLOOR" +
"PLANE ARM CIRCLE HITTING WALL MEDIUM DOUBLESIGNWRITING MOVEMENT-FLOORPLA" +
"NE ARM CIRCLE HITTING WALL LARGE DOUBLESIGNWRITING MOVEMENT-WALLPLANE WR" +
"IST CIRCLE FRONT SINGLESIGNWRITING MOVEMENT-WALLPLANE WRIST CIRCLE FRONT" +
" DOUBLESIGNWRITING MOVEMENT-FLOORPLANE WRIST CIRCLE HITTING WALL SINGLES" +
"IGNWRITING MOVEMENT-FLOORPLANE WRIST CIRCLE HITTING WALL DOUBLESIGNWRITI" +
"NG MOVEMENT-WALLPLANE FINGER CIRCLES SINGLESIGNWRITING MOVEMENT-WALLPLAN" +
"E FINGER CIRCLES DOUBLESIGNWRITING MOVEMENT-FLOORPLANE FINGER CIRCLES HI" +
"TTING WALL SINGLESIGNWRITING MOVEMENT-FLOORPLANE FINGER CIRCLES HITTING " +
"WALL DOUBLESIGNWRITING DYNAMIC ARROWHEAD SMALLSIGNWRITING DYNAMIC ARROWH" +
"EAD LARGESIGNWRITING DYNAMIC FASTSIGNWRITING DYNAMIC SLOWSIGNWRITING DYN" +
"AMIC TENSESIGNWRITING DYNAMIC RELAXEDSIGNWRITING DYNAMIC SIMULTANEOUSSIG" +
"NWRITING DYNAMIC SIMULTANEOUS ALTERNATINGSIGNWRITING DYNAMIC EVERY OTHER" +
" TIMESIGNWRITING DYNAMIC GRADUALSIGNWRITING HEADSIGNWRITING HEAD RIMSIGN" +
"WRITING HEAD MOVEMENT-WALLPLANE STRAIGHTSIGNWRITING HEAD MOVEMENT-WALLPL" +
"ANE TILTSIGNWRITING HEAD MOVEMENT-FLOORPLANE STRAIGHTSIGNWRITING HEAD MO" +
"VEMENT-WALLPLANE CURVESIGNWRITING HEAD MOVEMENT-FLOORPLANE CURVESIGNWRIT" +
"ING HEAD MOVEMENT CIRCLESIGNWRITING FACE DIRECTION POSITION NOSE FORWARD" +
" TILTINGSIGNWRITING FACE DIRECTION POSITION NOSE UP OR DOWNSIGNWRITING F" +
"ACE DIRECTION POSITION NOSE UP OR DOWN TILTINGSIGNWRITING EYEBROWS STRAI" +
"GHT UPSIGNWRITING EYEBROWS STRAIGHT NEUTRALSIGNWRITING EYEBROWS STRAIGHT" +
" DOWNSIGNWRITING DREAMY EYEBROWS NEUTRAL DOWNSIGNWRITING DREAMY EYEBROWS" +
" DOWN NEUTRALSIGNWRITING DREAMY EYEBROWS UP NEUTRALSIGNWRITING DREAMY EY" +
"EBROWS NEUTRAL UPSIGNWRITING FOREHEAD NEUTRALSIGNWRITING FOREHEAD CONTAC" +
"TSIGNWRITING FOREHEAD WRINKLEDSIGNWRITING EYES OPENSIGNWRITING EYES SQUE" +
"EZEDSIGNWRITING EYES CLOSEDSIGNWRITING EYE BLINK SINGLESIGNWRITING EYE B" +
"LINK MULTIPLESIGNWRITING EYES HALF OPENSIGNWRITING EYES WIDE OPENSIGNWRI" +
"TING EYES HALF CLOSEDSIGNWRITING EYES WIDENING MOVEMENTSIGNWRITING EYE W" +
"INKSIGNWRITING EYELASHES UPSIGNWRITING EYELASHES DOWNSIGNWRITING EYELASH" +
"ES FLUTTERINGSIGNWRITING EYEGAZE-WALLPLANE STRAIGHTSIGNWRITING EYEGAZE-W" +
"ALLPLANE STRAIGHT DOUBLESIGNWRITING EYEGAZE-WALLPLANE STRAIGHT ALTERNATI" +
"NGSIGNWRITING EYEGAZE-FLOORPLANE STRAIGHTSIGNWRITING EYEGAZE-FLOORPLANE " +
"STRAIGHT DOUBLESIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT ALTERNATINGSIGNWR" +
"ITING EYEGAZE-WALLPLANE CURVEDSIGNWRITING EYEGAZE-FLOORPLANE CURVEDSIGNW" +
"RITING EYEGAZE-WALLPLANE CIRCLINGSIGNWRITING CHEEKS PUFFEDSIGNWRITING CH" +
"EEKS NEUTRALSIGNWRITING CHEEKS SUCKEDSIGNWRITING TENSE CHEEKS HIGHSIGNWR" +
"ITING TENSE CHEEKS MIDDLESIGNWRITING TENSE CHEEKS LOWSIGNWRITING EARSSIG" +
"NWRITING NOSE NEUTRALSIGNWRITING NOSE CONTACTSIGNWRITING NOSE WRINKLESSI" +
"GNWRITING NOSE WIGGLESSIGNWRITING AIR BLOWING OUTSIGNWRITING AIR SUCKING" +
" INSIGNWRITING AIR BLOW SMALL ROTATIONSSIGNWRITING AIR SUCK SMALL ROTATI" +
"ONSSIGNWRITING BREATH INHALESIGNWRITING BREATH EXHALESIGNWRITING MOUTH C" +
"LOSED NEUTRALSIGNWRITING MOUTH CLOSED FORWARDSIGNWRITING MOUTH CLOSED CO" +
"NTACTSIGNWRITING MOUTH SMILESIGNWRITING MOUTH SMILE WRINKLEDSIGNWRITING " +
"MOUTH SMILE OPENSIGNWRITING MOUTH FROWNSIGNWRITING MOUTH FROWN WRINKLEDS" +
"IGNWRITING MOUTH FROWN OPENSIGNWRITING MOUTH OPEN CIRCLESIGNWRITING MOUT" +
"H OPEN FORWARDSIGNWRITING MOUTH OPEN WRINKLEDSIGNWRITING MOUTH OPEN OVAL" +
"SIGNWRITING MOUTH OPEN OVAL WRINKLEDSIGNWRITING MOUTH OPEN OVAL YAWNSIGN" +
"WRITING MOUTH OPEN RECTANGLESIGNWRITING MOUTH OPEN RECTANGLE WRINKLEDSIG" +
"NWRITING MOUTH OPEN RECTANGLE YAWNSIGNWRITING MOUTH KISSSIGNWRITING MOUT" +
"H KISS FORWARDSIGNWRITING MOUTH KISS WRINKLEDSIGNWRITING MOUTH TENSESIGN" +
"WRITING MOUTH TENSE FORWARDSIGNWRITING MOUTH TENSE SUCKEDSIGNWRITING LIP" +
"S PRESSED TOGETHERSIGNWRITING LIP LOWER OVER UPPERSIGNWRITING LIP UPPER " +
"OVER LOWERSIGNWRITING MOUTH CORNERSSIGNWRITING MOUTH WRINKLES SINGLESIGN" +
"WRITING MOUTH WRINKLES DOUBLESIGNWRITING TONGUE STICKING OUT FARSIGNWRIT" +
"ING TONGUE LICKING LIPSSIGNWRITING TONGUE TIP BETWEEN LIPSSIGNWRITING TO") + ("" +
"NGUE TIP TOUCHING INSIDE MOUTHSIGNWRITING TONGUE INSIDE MOUTH RELAXEDSIG" +
"NWRITING TONGUE MOVES AGAINST CHEEKSIGNWRITING TONGUE CENTRE STICKING OU" +
"TSIGNWRITING TONGUE CENTRE INSIDE MOUTHSIGNWRITING TEETHSIGNWRITING TEET" +
"H MOVEMENTSIGNWRITING TEETH ON TONGUESIGNWRITING TEETH ON TONGUE MOVEMEN" +
"TSIGNWRITING TEETH ON LIPSSIGNWRITING TEETH ON LIPS MOVEMENTSIGNWRITING " +
"TEETH BITE LIPSSIGNWRITING MOVEMENT-WALLPLANE JAWSIGNWRITING MOVEMENT-FL" +
"OORPLANE JAWSIGNWRITING NECKSIGNWRITING HAIRSIGNWRITING EXCITEMENTSIGNWR" +
"ITING SHOULDER HIP SPINESIGNWRITING SHOULDER HIP POSITIONSSIGNWRITING WA" +
"LLPLANE SHOULDER HIP MOVESIGNWRITING FLOORPLANE SHOULDER HIP MOVESIGNWRI" +
"TING SHOULDER TILTING FROM WAISTSIGNWRITING TORSO-WALLPLANE STRAIGHT STR" +
"ETCHSIGNWRITING TORSO-WALLPLANE CURVED BENDSIGNWRITING TORSO-FLOORPLANE " +
"TWISTINGSIGNWRITING UPPER BODY TILTING FROM HIP JOINTSSIGNWRITING LIMB C" +
"OMBINATIONSIGNWRITING LIMB LENGTH-1SIGNWRITING LIMB LENGTH-2SIGNWRITING " +
"LIMB LENGTH-3SIGNWRITING LIMB LENGTH-4SIGNWRITING LIMB LENGTH-5SIGNWRITI" +
"NG LIMB LENGTH-6SIGNWRITING LIMB LENGTH-7SIGNWRITING FINGERSIGNWRITING L" +
"OCATION-WALLPLANE SPACESIGNWRITING LOCATION-FLOORPLANE SPACESIGNWRITING " +
"LOCATION HEIGHTSIGNWRITING LOCATION WIDTHSIGNWRITING LOCATION DEPTHSIGNW" +
"RITING LOCATION HEAD NECKSIGNWRITING LOCATION TORSOSIGNWRITING LOCATION " +
"LIMBS DIGITSSIGNWRITING COMMASIGNWRITING FULL STOPSIGNWRITING SEMICOLONS" +
"IGNWRITING COLONSIGNWRITING PARENTHESISSIGNWRITING FILL MODIFIER-2SIGNWR" +
"ITING FILL MODIFIER-3SIGNWRITING FILL MODIFIER-4SIGNWRITING FILL MODIFIE" +
"R-5SIGNWRITING FILL MODIFIER-6SIGNWRITING ROTATION MODIFIER-2SIGNWRITING" +
" ROTATION MODIFIER-3SIGNWRITING ROTATION MODIFIER-4SIGNWRITING ROTATION " +
"MODIFIER-5SIGNWRITING ROTATION MODIFIER-6SIGNWRITING ROTATION MODIFIER-7" +
"SIGNWRITING ROTATION MODIFIER-8SIGNWRITING ROTATION MODIFIER-9SIGNWRITIN" +
"G ROTATION MODIFIER-10SIGNWRITING ROTATION MODIFIER-11SIGNWRITING ROTATI" +
"ON MODIFIER-12SIGNWRITING ROTATION MODIFIER-13SIGNWRITING ROTATION MODIF" +
"IER-14SIGNWRITING ROTATION MODIFIER-15SIGNWRITING ROTATION MODIFIER-16LA" +
"TIN SMALL LETTER FENG DIGRAPH WITH TRILLLATIN SMALL LETTER REVERSED SCRI" +
"PT GLATIN LETTER SMALL CAPITAL TURNED GLATIN SMALL LETTER REVERSED KLATI" +
"N LETTER SMALL CAPITAL L WITH BELTLATIN SMALL LETTER LEZH WITH RETROFLEX" +
" HOOKLATIN SMALL LETTER TURNED Y WITH BELTLATIN SMALL LETTER REVERSED EN" +
"GLATIN SMALL LETTER TURNED R WITH LONG LEG AND RETROFLEX HOOKLATIN SMALL" +
" LETTER T WITH HOOK AND RETROFLEX HOOKLATIN LETTER RETROFLEX CLICK WITH " +
"RETROFLEX HOOKLATIN SMALL LETTER ESH WITH DOUBLE BARLATIN SMALL LETTER E" +
"SH WITH DOUBLE BAR AND CURLLATIN SMALL LETTER TURNED T WITH CURLLATIN LE" +
"TTER INVERTED GLOTTAL STOP WITH CURLLATIN LETTER STRETCHED C WITH CURLLA" +
"TIN LETTER SMALL CAPITAL TURNED KLATIN SMALL LETTER L WITH FISHHOOKLATIN" +
" SMALL LETTER DEZH DIGRAPH WITH PALATAL HOOKLATIN SMALL LETTER L WITH BE" +
"LT AND PALATAL HOOKLATIN SMALL LETTER ENG WITH PALATAL HOOKLATIN SMALL L" +
"ETTER TURNED R WITH PALATAL HOOKLATIN SMALL LETTER R WITH FISHHOOK AND P" +
"ALATAL HOOKLATIN SMALL LETTER TESH DIGRAPH WITH PALATAL HOOKLATIN SMALL " +
"LETTER EZH WITH PALATAL HOOKLATIN SMALL LETTER DEZH DIGRAPH WITH RETROFL" +
"EX HOOKLATIN SMALL LETTER I WITH STROKE AND RETROFLEX HOOKLATIN SMALL LE" +
"TTER O WITH RETROFLEX HOOKLATIN SMALL LETTER TESH DIGRAPH WITH RETROFLEX" +
" HOOKLATIN SMALL LETTER C WITH RETROFLEX HOOKLATIN SMALL LETTER S WITH C" +
"URLLATIN SMALL LETTER D WITH MID-HEIGHT LEFT HOOKLATIN SMALL LETTER L WI" +
"TH MID-HEIGHT LEFT HOOKLATIN SMALL LETTER N WITH MID-HEIGHT LEFT HOOKLAT" +
"IN SMALL LETTER R WITH MID-HEIGHT LEFT HOOKLATIN SMALL LETTER S WITH MID" +
"-HEIGHT LEFT HOOKLATIN SMALL LETTER T WITH MID-HEIGHT LEFT HOOKCOMBINING" +
" GLAGOLITIC LETTER AZUCOMBINING GLAGOLITIC LETTER BUKYCOMBINING GLAGOLIT" +
"IC LETTER VEDECOMBINING GLAGOLITIC LETTER GLAGOLICOMBINING GLAGOLITIC LE" +
"TTER DOBROCOMBINING GLAGOLITIC LETTER YESTUCOMBINING GLAGOLITIC LETTER Z" +
"HIVETECOMBINING GLAGOLITIC LETTER ZEMLJACOMBINING GLAGOLITIC LETTER IZHE" +
"COMBINING GLAGOLITIC LETTER INITIAL IZHECOMBINING GLAGOLITIC LETTER ICOM" +
"BINING GLAGOLITIC LETTER DJERVICOMBINING GLAGOLITIC LETTER KAKOCOMBINING" +
" GLAGOLITIC LETTER LJUDIJECOMBINING GLAGOLITIC LETTER MYSLITECOMBINING G" +
"LAGOLITIC LETTER NASHICOMBINING GLAGOLITIC LETTER ONUCOMBINING GLAGOLITI" +
"C LETTER POKOJICOMBINING GLAGOLITIC LETTER RITSICOMBINING GLAGOLITIC LET" +
"TER SLOVOCOMBINING GLAGOLITIC LETTER TVRIDOCOMBINING GLAGOLITIC LETTER U" +
"KUCOMBINING GLAGOLITIC LETTER FRITUCOMBINING GLAGOLITIC LETTER HERUCOMBI" +
"NING GLAGOLITIC LETTER SHTACOMBINING GLAGOLITIC LETTER TSICOMBINING GLAG" +
"OLITIC LETTER CHRIVICOMBINING GLAGOLITIC LETTER SHACOMBINING GLAGOLITIC " +
"LETTER YERUCOMBINING GLAGOLITIC LETTER YERICOMBINING GLAGOLITIC LETTER Y") + ("" +
"ATICOMBINING GLAGOLITIC LETTER YUCOMBINING GLAGOLITIC LETTER SMALL YUSCO" +
"MBINING GLAGOLITIC LETTER YOCOMBINING GLAGOLITIC LETTER IOTATED SMALL YU" +
"SCOMBINING GLAGOLITIC LETTER BIG YUSCOMBINING GLAGOLITIC LETTER IOTATED " +
"BIG YUSCOMBINING GLAGOLITIC LETTER FITAMODIFIER LETTER CYRILLIC SMALL AM" +
"ODIFIER LETTER CYRILLIC SMALL BEMODIFIER LETTER CYRILLIC SMALL VEMODIFIE" +
"R LETTER CYRILLIC SMALL GHEMODIFIER LETTER CYRILLIC SMALL DEMODIFIER LET" +
"TER CYRILLIC SMALL IEMODIFIER LETTER CYRILLIC SMALL ZHEMODIFIER LETTER C" +
"YRILLIC SMALL ZEMODIFIER LETTER CYRILLIC SMALL IMODIFIER LETTER CYRILLIC" +
" SMALL KAMODIFIER LETTER CYRILLIC SMALL ELMODIFIER LETTER CYRILLIC SMALL" +
" EMMODIFIER LETTER CYRILLIC SMALL OMODIFIER LETTER CYRILLIC SMALL PEMODI" +
"FIER LETTER CYRILLIC SMALL ERMODIFIER LETTER CYRILLIC SMALL ESMODIFIER L" +
"ETTER CYRILLIC SMALL TEMODIFIER LETTER CYRILLIC SMALL UMODIFIER LETTER C" +
"YRILLIC SMALL EFMODIFIER LETTER CYRILLIC SMALL HAMODIFIER LETTER CYRILLI" +
"C SMALL TSEMODIFIER LETTER CYRILLIC SMALL CHEMODIFIER LETTER CYRILLIC SM" +
"ALL SHAMODIFIER LETTER CYRILLIC SMALL YERUMODIFIER LETTER CYRILLIC SMALL" +
" EMODIFIER LETTER CYRILLIC SMALL YUMODIFIER LETTER CYRILLIC SMALL DZZEMO" +
"DIFIER LETTER CYRILLIC SMALL SCHWAMODIFIER LETTER CYRILLIC SMALL BYELORU" +
"SSIAN-UKRAINIAN IMODIFIER LETTER CYRILLIC SMALL JEMODIFIER LETTER CYRILL" +
"IC SMALL BARRED OMODIFIER LETTER CYRILLIC SMALL STRAIGHT UMODIFIER LETTE" +
"R CYRILLIC SMALL PALOCHKACYRILLIC SUBSCRIPT SMALL LETTER ACYRILLIC SUBSC" +
"RIPT SMALL LETTER BECYRILLIC SUBSCRIPT SMALL LETTER VECYRILLIC SUBSCRIPT" +
" SMALL LETTER GHECYRILLIC SUBSCRIPT SMALL LETTER DECYRILLIC SUBSCRIPT SM" +
"ALL LETTER IECYRILLIC SUBSCRIPT SMALL LETTER ZHECYRILLIC SUBSCRIPT SMALL" +
" LETTER ZECYRILLIC SUBSCRIPT SMALL LETTER ICYRILLIC SUBSCRIPT SMALL LETT" +
"ER KACYRILLIC SUBSCRIPT SMALL LETTER ELCYRILLIC SUBSCRIPT SMALL LETTER O" +
"CYRILLIC SUBSCRIPT SMALL LETTER PECYRILLIC SUBSCRIPT SMALL LETTER ESCYRI" +
"LLIC SUBSCRIPT SMALL LETTER UCYRILLIC SUBSCRIPT SMALL LETTER EFCYRILLIC " +
"SUBSCRIPT SMALL LETTER HACYRILLIC SUBSCRIPT SMALL LETTER TSECYRILLIC SUB" +
"SCRIPT SMALL LETTER CHECYRILLIC SUBSCRIPT SMALL LETTER SHACYRILLIC SUBSC" +
"RIPT SMALL LETTER HARD SIGNCYRILLIC SUBSCRIPT SMALL LETTER YERUCYRILLIC " +
"SUBSCRIPT SMALL LETTER GHE WITH UPTURNCYRILLIC SUBSCRIPT SMALL LETTER BY" +
"ELORUSSIAN-UKRAINIAN ICYRILLIC SUBSCRIPT SMALL LETTER DZECYRILLIC SUBSCR" +
"IPT SMALL LETTER DZHEMODIFIER LETTER CYRILLIC SMALL ES WITH DESCENDERMOD" +
"IFIER LETTER CYRILLIC SMALL YERU WITH BACK YERMODIFIER LETTER CYRILLIC S" +
"MALL STRAIGHT U WITH STROKECOMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-" +
"UKRAINIAN INYIAKENG PUACHUE HMONG LETTER MANYIAKENG PUACHUE HMONG LETTER" +
" TSANYIAKENG PUACHUE HMONG LETTER NTANYIAKENG PUACHUE HMONG LETTER TANYI" +
"AKENG PUACHUE HMONG LETTER HANYIAKENG PUACHUE HMONG LETTER NANYIAKENG PU" +
"ACHUE HMONG LETTER XANYIAKENG PUACHUE HMONG LETTER NKANYIAKENG PUACHUE H" +
"MONG LETTER CANYIAKENG PUACHUE HMONG LETTER LANYIAKENG PUACHUE HMONG LET" +
"TER SANYIAKENG PUACHUE HMONG LETTER ZANYIAKENG PUACHUE HMONG LETTER NCAN" +
"YIAKENG PUACHUE HMONG LETTER NTSANYIAKENG PUACHUE HMONG LETTER KANYIAKEN" +
"G PUACHUE HMONG LETTER DANYIAKENG PUACHUE HMONG LETTER NYANYIAKENG PUACH" +
"UE HMONG LETTER NRANYIAKENG PUACHUE HMONG LETTER VANYIAKENG PUACHUE HMON" +
"G LETTER NTXANYIAKENG PUACHUE HMONG LETTER TXANYIAKENG PUACHUE HMONG LET" +
"TER FANYIAKENG PUACHUE HMONG LETTER RANYIAKENG PUACHUE HMONG LETTER QANY" +
"IAKENG PUACHUE HMONG LETTER YANYIAKENG PUACHUE HMONG LETTER NQANYIAKENG " +
"PUACHUE HMONG LETTER PANYIAKENG PUACHUE HMONG LETTER XYANYIAKENG PUACHUE" +
" HMONG LETTER NPANYIAKENG PUACHUE HMONG LETTER DLANYIAKENG PUACHUE HMONG" +
" LETTER NPLANYIAKENG PUACHUE HMONG LETTER HAHNYIAKENG PUACHUE HMONG LETT" +
"ER MLANYIAKENG PUACHUE HMONG LETTER PLANYIAKENG PUACHUE HMONG LETTER GAN" +
"YIAKENG PUACHUE HMONG LETTER RRANYIAKENG PUACHUE HMONG LETTER ANYIAKENG " +
"PUACHUE HMONG LETTER AANYIAKENG PUACHUE HMONG LETTER INYIAKENG PUACHUE H" +
"MONG LETTER UNYIAKENG PUACHUE HMONG LETTER ONYIAKENG PUACHUE HMONG LETTE" +
"R OONYIAKENG PUACHUE HMONG LETTER ENYIAKENG PUACHUE HMONG LETTER EENYIAK" +
"ENG PUACHUE HMONG LETTER WNYIAKENG PUACHUE HMONG TONE-BNYIAKENG PUACHUE " +
"HMONG TONE-MNYIAKENG PUACHUE HMONG TONE-JNYIAKENG PUACHUE HMONG TONE-VNY" +
"IAKENG PUACHUE HMONG TONE-SNYIAKENG PUACHUE HMONG TONE-GNYIAKENG PUACHUE" +
" HMONG TONE-DNYIAKENG PUACHUE HMONG SIGN FOR PERSONNYIAKENG PUACHUE HMON" +
"G SIGN FOR THINGNYIAKENG PUACHUE HMONG SIGN FOR LOCATIONNYIAKENG PUACHUE" +
" HMONG SIGN FOR ANIMALNYIAKENG PUACHUE HMONG SIGN FOR INVERTEBRATENYIAKE" +
"NG PUACHUE HMONG SIGN XW XWNYIAKENG PUACHUE HMONG SYLLABLE LENGTHENERNYI" +
"AKENG PUACHUE HMONG DIGIT ZERONYIAKENG PUACHUE HMONG DIGIT ONENYIAKENG P" +
"UACHUE HMONG DIGIT TWONYIAKENG PUACHUE HMONG DIGIT THREENYIAKENG PUACHUE") + ("" +
" HMONG DIGIT FOURNYIAKENG PUACHUE HMONG DIGIT FIVENYIAKENG PUACHUE HMONG" +
" DIGIT SIXNYIAKENG PUACHUE HMONG DIGIT SEVENNYIAKENG PUACHUE HMONG DIGIT" +
" EIGHTNYIAKENG PUACHUE HMONG DIGIT NINENYIAKENG PUACHUE HMONG LOGOGRAM N" +
"YAJNYIAKENG PUACHUE HMONG CIRCLED CATOTO LETTER PATOTO LETTER BATOTO LET" +
"TER TATOTO LETTER DATOTO LETTER KATOTO LETTER GATOTO LETTER MATOTO LETTE" +
"R NATOTO LETTER NGATOTO LETTER SATOTO LETTER CHATOTO LETTER YATOTO LETTE" +
"R WATOTO LETTER JATOTO LETTER HATOTO LETTER RATOTO LETTER LATOTO LETTER " +
"ITOTO LETTER BREATHY ITOTO LETTER IUTOTO LETTER BREATHY IUTOTO LETTER UT" +
"OTO LETTER ETOTO LETTER BREATHY ETOTO LETTER EOTOTO LETTER BREATHY EOTOT" +
"O LETTER OTOTO LETTER AETOTO LETTER BREATHY AETOTO LETTER ATOTO SIGN RIS" +
"ING TONEWANCHO LETTER AAWANCHO LETTER AWANCHO LETTER BAWANCHO LETTER CAW" +
"ANCHO LETTER DAWANCHO LETTER GAWANCHO LETTER YAWANCHO LETTER PHAWANCHO L" +
"ETTER LAWANCHO LETTER NAWANCHO LETTER PAWANCHO LETTER TAWANCHO LETTER TH" +
"AWANCHO LETTER FAWANCHO LETTER SAWANCHO LETTER SHAWANCHO LETTER JAWANCHO" +
" LETTER ZAWANCHO LETTER WAWANCHO LETTER VAWANCHO LETTER KAWANCHO LETTER " +
"OWANCHO LETTER AUWANCHO LETTER RAWANCHO LETTER MAWANCHO LETTER KHAWANCHO" +
" LETTER HAWANCHO LETTER EWANCHO LETTER IWANCHO LETTER NGAWANCHO LETTER U" +
"WANCHO LETTER LLHAWANCHO LETTER TSAWANCHO LETTER TRAWANCHO LETTER ONGWAN" +
"CHO LETTER AANGWANCHO LETTER ANGWANCHO LETTER INGWANCHO LETTER ONWANCHO " +
"LETTER ENWANCHO LETTER AANWANCHO LETTER NYAWANCHO LETTER UENWANCHO LETTE" +
"R YIHWANCHO TONE TUPWANCHO TONE TUPNIWANCHO TONE KOIWANCHO TONE KOINIWAN" +
"CHO DIGIT ZEROWANCHO DIGIT ONEWANCHO DIGIT TWOWANCHO DIGIT THREEWANCHO D" +
"IGIT FOURWANCHO DIGIT FIVEWANCHO DIGIT SIXWANCHO DIGIT SEVENWANCHO DIGIT" +
" EIGHTWANCHO DIGIT NINEWANCHO NGUN SIGNNAG MUNDARI LETTER ONAG MUNDARI L" +
"ETTER OPNAG MUNDARI LETTER OLNAG MUNDARI LETTER OYNAG MUNDARI LETTER ONG" +
"NAG MUNDARI LETTER ANAG MUNDARI LETTER AJNAG MUNDARI LETTER ABNAG MUNDAR" +
"I LETTER ANYNAG MUNDARI LETTER AHNAG MUNDARI LETTER INAG MUNDARI LETTER " +
"ISNAG MUNDARI LETTER IDDNAG MUNDARI LETTER ITNAG MUNDARI LETTER IHNAG MU" +
"NDARI LETTER UNAG MUNDARI LETTER UCNAG MUNDARI LETTER UDNAG MUNDARI LETT" +
"ER UKNAG MUNDARI LETTER URNAG MUNDARI LETTER ENAG MUNDARI LETTER ENNNAG " +
"MUNDARI LETTER EGNAG MUNDARI LETTER EMNAG MUNDARI LETTER ENNAG MUNDARI L" +
"ETTER ETTNAG MUNDARI LETTER ELLNAG MUNDARI SIGN OJODNAG MUNDARI SIGN MUH" +
"ORNAG MUNDARI SIGN TOYORNAG MUNDARI SIGN IKIRNAG MUNDARI SIGN SUTUHNAG M" +
"UNDARI DIGIT ZERONAG MUNDARI DIGIT ONENAG MUNDARI DIGIT TWONAG MUNDARI D" +
"IGIT THREENAG MUNDARI DIGIT FOURNAG MUNDARI DIGIT FIVENAG MUNDARI DIGIT " +
"SIXNAG MUNDARI DIGIT SEVENNAG MUNDARI DIGIT EIGHTNAG MUNDARI DIGIT NINEE" +
"THIOPIC SYLLABLE HHYAETHIOPIC SYLLABLE HHYUETHIOPIC SYLLABLE HHYIETHIOPI" +
"C SYLLABLE HHYAAETHIOPIC SYLLABLE HHYEEETHIOPIC SYLLABLE HHYEETHIOPIC SY" +
"LLABLE HHYOETHIOPIC SYLLABLE GURAGE HHWAETHIOPIC SYLLABLE HHWIETHIOPIC S" +
"YLLABLE HHWEEETHIOPIC SYLLABLE HHWEETHIOPIC SYLLABLE GURAGE MWIETHIOPIC " +
"SYLLABLE GURAGE MWEEETHIOPIC SYLLABLE GURAGE QWIETHIOPIC SYLLABLE GURAGE" +
" QWEEETHIOPIC SYLLABLE GURAGE QWEETHIOPIC SYLLABLE GURAGE BWIETHIOPIC SY" +
"LLABLE GURAGE BWEEETHIOPIC SYLLABLE GURAGE KWIETHIOPIC SYLLABLE GURAGE K" +
"WEEETHIOPIC SYLLABLE GURAGE KWEETHIOPIC SYLLABLE GURAGE GWIETHIOPIC SYLL" +
"ABLE GURAGE GWEEETHIOPIC SYLLABLE GURAGE GWEETHIOPIC SYLLABLE GURAGE FWI" +
"ETHIOPIC SYLLABLE GURAGE FWEEETHIOPIC SYLLABLE GURAGE PWIETHIOPIC SYLLAB" +
"LE GURAGE PWEEMENDE KIKAKUI SYLLABLE M001 KIMENDE KIKAKUI SYLLABLE M002 " +
"KAMENDE KIKAKUI SYLLABLE M003 KUMENDE KIKAKUI SYLLABLE M065 KEEMENDE KIK" +
"AKUI SYLLABLE M095 KEMENDE KIKAKUI SYLLABLE M076 KOOMENDE KIKAKUI SYLLAB" +
"LE M048 KOMENDE KIKAKUI SYLLABLE M179 KUAMENDE KIKAKUI SYLLABLE M004 WIM" +
"ENDE KIKAKUI SYLLABLE M005 WAMENDE KIKAKUI SYLLABLE M006 WUMENDE KIKAKUI" +
" SYLLABLE M126 WEEMENDE KIKAKUI SYLLABLE M118 WEMENDE KIKAKUI SYLLABLE M" +
"114 WOOMENDE KIKAKUI SYLLABLE M045 WOMENDE KIKAKUI SYLLABLE M194 WUIMEND" +
"E KIKAKUI SYLLABLE M143 WEIMENDE KIKAKUI SYLLABLE M061 WVIMENDE KIKAKUI " +
"SYLLABLE M049 WVAMENDE KIKAKUI SYLLABLE M139 WVEMENDE KIKAKUI SYLLABLE M" +
"007 MINMENDE KIKAKUI SYLLABLE M008 MANMENDE KIKAKUI SYLLABLE M009 MUNMEN" +
"DE KIKAKUI SYLLABLE M059 MENMENDE KIKAKUI SYLLABLE M094 MONMENDE KIKAKUI" +
" SYLLABLE M154 MUANMENDE KIKAKUI SYLLABLE M189 MUENMENDE KIKAKUI SYLLABL" +
"E M010 BIMENDE KIKAKUI SYLLABLE M011 BAMENDE KIKAKUI SYLLABLE M012 BUMEN" +
"DE KIKAKUI SYLLABLE M150 BEEMENDE KIKAKUI SYLLABLE M097 BEMENDE KIKAKUI " +
"SYLLABLE M103 BOOMENDE KIKAKUI SYLLABLE M138 BOMENDE KIKAKUI SYLLABLE M0" +
"13 IMENDE KIKAKUI SYLLABLE M014 AMENDE KIKAKUI SYLLABLE M015 UMENDE KIKA" +
"KUI SYLLABLE M163 EEMENDE KIKAKUI SYLLABLE M100 EMENDE KIKAKUI SYLLABLE " +
"M165 OOMENDE KIKAKUI SYLLABLE M147 OMENDE KIKAKUI SYLLABLE M137 EIMENDE ") + ("" +
"KIKAKUI SYLLABLE M131 INMENDE KIKAKUI SYLLABLE M135 INMENDE KIKAKUI SYLL" +
"ABLE M195 ANMENDE KIKAKUI SYLLABLE M178 ENMENDE KIKAKUI SYLLABLE M019 SI" +
"MENDE KIKAKUI SYLLABLE M020 SAMENDE KIKAKUI SYLLABLE M021 SUMENDE KIKAKU" +
"I SYLLABLE M162 SEEMENDE KIKAKUI SYLLABLE M116 SEMENDE KIKAKUI SYLLABLE " +
"M136 SOOMENDE KIKAKUI SYLLABLE M079 SOMENDE KIKAKUI SYLLABLE M196 SIAMEN" +
"DE KIKAKUI SYLLABLE M025 LIMENDE KIKAKUI SYLLABLE M026 LAMENDE KIKAKUI S" +
"YLLABLE M027 LUMENDE KIKAKUI SYLLABLE M084 LEEMENDE KIKAKUI SYLLABLE M07" +
"3 LEMENDE KIKAKUI SYLLABLE M054 LOOMENDE KIKAKUI SYLLABLE M153 LOMENDE K" +
"IKAKUI SYLLABLE M110 LONG LEMENDE KIKAKUI SYLLABLE M016 DIMENDE KIKAKUI " +
"SYLLABLE M017 DAMENDE KIKAKUI SYLLABLE M018 DUMENDE KIKAKUI SYLLABLE M08" +
"9 DEEMENDE KIKAKUI SYLLABLE M180 DOOMENDE KIKAKUI SYLLABLE M181 DOMENDE " +
"KIKAKUI SYLLABLE M022 TIMENDE KIKAKUI SYLLABLE M023 TAMENDE KIKAKUI SYLL" +
"ABLE M024 TUMENDE KIKAKUI SYLLABLE M091 TEEMENDE KIKAKUI SYLLABLE M055 T" +
"EMENDE KIKAKUI SYLLABLE M104 TOOMENDE KIKAKUI SYLLABLE M069 TOMENDE KIKA" +
"KUI SYLLABLE M028 JIMENDE KIKAKUI SYLLABLE M029 JAMENDE KIKAKUI SYLLABLE" +
" M030 JUMENDE KIKAKUI SYLLABLE M157 JEEMENDE KIKAKUI SYLLABLE M113 JEMEN" +
"DE KIKAKUI SYLLABLE M160 JOOMENDE KIKAKUI SYLLABLE M063 JOMENDE KIKAKUI " +
"SYLLABLE M175 LONG JOMENDE KIKAKUI SYLLABLE M031 YIMENDE KIKAKUI SYLLABL" +
"E M032 YAMENDE KIKAKUI SYLLABLE M033 YUMENDE KIKAKUI SYLLABLE M109 YEEME" +
"NDE KIKAKUI SYLLABLE M080 YEMENDE KIKAKUI SYLLABLE M141 YOOMENDE KIKAKUI" +
" SYLLABLE M121 YOMENDE KIKAKUI SYLLABLE M034 FIMENDE KIKAKUI SYLLABLE M0" +
"35 FAMENDE KIKAKUI SYLLABLE M036 FUMENDE KIKAKUI SYLLABLE M078 FEEMENDE " +
"KIKAKUI SYLLABLE M075 FEMENDE KIKAKUI SYLLABLE M133 FOOMENDE KIKAKUI SYL" +
"LABLE M088 FOMENDE KIKAKUI SYLLABLE M197 FUAMENDE KIKAKUI SYLLABLE M101 " +
"FANMENDE KIKAKUI SYLLABLE M037 NINMENDE KIKAKUI SYLLABLE M038 NANMENDE K" +
"IKAKUI SYLLABLE M039 NUNMENDE KIKAKUI SYLLABLE M117 NENMENDE KIKAKUI SYL" +
"LABLE M169 NONMENDE KIKAKUI SYLLABLE M176 HIMENDE KIKAKUI SYLLABLE M041 " +
"HAMENDE KIKAKUI SYLLABLE M186 HUMENDE KIKAKUI SYLLABLE M040 HEEMENDE KIK" +
"AKUI SYLLABLE M096 HEMENDE KIKAKUI SYLLABLE M042 HOOMENDE KIKAKUI SYLLAB" +
"LE M140 HOMENDE KIKAKUI SYLLABLE M083 HEEIMENDE KIKAKUI SYLLABLE M128 HO" +
"OUMENDE KIKAKUI SYLLABLE M053 HINMENDE KIKAKUI SYLLABLE M130 HANMENDE KI" +
"KAKUI SYLLABLE M087 HUNMENDE KIKAKUI SYLLABLE M052 HENMENDE KIKAKUI SYLL" +
"ABLE M193 HONMENDE KIKAKUI SYLLABLE M046 HUANMENDE KIKAKUI SYLLABLE M090" +
" NGGIMENDE KIKAKUI SYLLABLE M043 NGGAMENDE KIKAKUI SYLLABLE M082 NGGUMEN" +
"DE KIKAKUI SYLLABLE M115 NGGEEMENDE KIKAKUI SYLLABLE M146 NGGEMENDE KIKA" +
"KUI SYLLABLE M156 NGGOOMENDE KIKAKUI SYLLABLE M120 NGGOMENDE KIKAKUI SYL" +
"LABLE M159 NGGAAMENDE KIKAKUI SYLLABLE M127 NGGUAMENDE KIKAKUI SYLLABLE " +
"M086 LONG NGGEMENDE KIKAKUI SYLLABLE M106 LONG NGGOOMENDE KIKAKUI SYLLAB" +
"LE M183 LONG NGGOMENDE KIKAKUI SYLLABLE M155 GIMENDE KIKAKUI SYLLABLE M1" +
"11 GAMENDE KIKAKUI SYLLABLE M168 GUMENDE KIKAKUI SYLLABLE M190 GEEMENDE " +
"KIKAKUI SYLLABLE M166 GUEIMENDE KIKAKUI SYLLABLE M167 GUANMENDE KIKAKUI " +
"SYLLABLE M184 NGENMENDE KIKAKUI SYLLABLE M057 NGONMENDE KIKAKUI SYLLABLE" +
" M177 NGUANMENDE KIKAKUI SYLLABLE M068 PIMENDE KIKAKUI SYLLABLE M099 PAM" +
"ENDE KIKAKUI SYLLABLE M050 PUMENDE KIKAKUI SYLLABLE M081 PEEMENDE KIKAKU" +
"I SYLLABLE M051 PEMENDE KIKAKUI SYLLABLE M102 POOMENDE KIKAKUI SYLLABLE " +
"M066 POMENDE KIKAKUI SYLLABLE M145 MBIMENDE KIKAKUI SYLLABLE M062 MBAMEN" +
"DE KIKAKUI SYLLABLE M122 MBUMENDE KIKAKUI SYLLABLE M047 MBEEMENDE KIKAKU" +
"I SYLLABLE M188 MBEEMENDE KIKAKUI SYLLABLE M072 MBEMENDE KIKAKUI SYLLABL" +
"E M172 MBOOMENDE KIKAKUI SYLLABLE M174 MBOMENDE KIKAKUI SYLLABLE M187 MB" +
"UUMENDE KIKAKUI SYLLABLE M161 LONG MBEMENDE KIKAKUI SYLLABLE M105 LONG M" +
"BOOMENDE KIKAKUI SYLLABLE M142 LONG MBOMENDE KIKAKUI SYLLABLE M132 KPIME" +
"NDE KIKAKUI SYLLABLE M092 KPAMENDE KIKAKUI SYLLABLE M074 KPUMENDE KIKAKU" +
"I SYLLABLE M044 KPEEMENDE KIKAKUI SYLLABLE M108 KPEMENDE KIKAKUI SYLLABL" +
"E M112 KPOOMENDE KIKAKUI SYLLABLE M158 KPOMENDE KIKAKUI SYLLABLE M124 GB" +
"IMENDE KIKAKUI SYLLABLE M056 GBAMENDE KIKAKUI SYLLABLE M148 GBUMENDE KIK" +
"AKUI SYLLABLE M093 GBEEMENDE KIKAKUI SYLLABLE M107 GBEMENDE KIKAKUI SYLL" +
"ABLE M071 GBOOMENDE KIKAKUI SYLLABLE M070 GBOMENDE KIKAKUI SYLLABLE M171" +
" RAMENDE KIKAKUI SYLLABLE M123 NDIMENDE KIKAKUI SYLLABLE M129 NDAMENDE K" +
"IKAKUI SYLLABLE M125 NDUMENDE KIKAKUI SYLLABLE M191 NDEEMENDE KIKAKUI SY" +
"LLABLE M119 NDEMENDE KIKAKUI SYLLABLE M067 NDOOMENDE KIKAKUI SYLLABLE M0" +
"64 NDOMENDE KIKAKUI SYLLABLE M152 NJAMENDE KIKAKUI SYLLABLE M192 NJUMEND" +
"E KIKAKUI SYLLABLE M149 NJEEMENDE KIKAKUI SYLLABLE M134 NJOOMENDE KIKAKU" +
"I SYLLABLE M182 VIMENDE KIKAKUI SYLLABLE M185 VAMENDE KIKAKUI SYLLABLE M" +
"151 VUMENDE KIKAKUI SYLLABLE M173 VEEMENDE KIKAKUI SYLLABLE M085 VEMENDE") + ("" +
" KIKAKUI SYLLABLE M144 VOOMENDE KIKAKUI SYLLABLE M077 VOMENDE KIKAKUI SY" +
"LLABLE M164 NYINMENDE KIKAKUI SYLLABLE M058 NYANMENDE KIKAKUI SYLLABLE M" +
"170 NYUNMENDE KIKAKUI SYLLABLE M098 NYENMENDE KIKAKUI SYLLABLE M060 NYON" +
"MENDE KIKAKUI DIGIT ONEMENDE KIKAKUI DIGIT TWOMENDE KIKAKUI DIGIT THREEM" +
"ENDE KIKAKUI DIGIT FOURMENDE KIKAKUI DIGIT FIVEMENDE KIKAKUI DIGIT SIXME" +
"NDE KIKAKUI DIGIT SEVENMENDE KIKAKUI DIGIT EIGHTMENDE KIKAKUI DIGIT NINE" +
"MENDE KIKAKUI COMBINING NUMBER TEENSMENDE KIKAKUI COMBINING NUMBER TENSM" +
"ENDE KIKAKUI COMBINING NUMBER HUNDREDSMENDE KIKAKUI COMBINING NUMBER THO" +
"USANDSMENDE KIKAKUI COMBINING NUMBER TEN THOUSANDSMENDE KIKAKUI COMBININ" +
"G NUMBER HUNDRED THOUSANDSMENDE KIKAKUI COMBINING NUMBER MILLIONSADLAM C" +
"APITAL LETTER ALIFADLAM CAPITAL LETTER DAALIADLAM CAPITAL LETTER LAAMADL" +
"AM CAPITAL LETTER MIIMADLAM CAPITAL LETTER BAADLAM CAPITAL LETTER SINNYI" +
"IYHEADLAM CAPITAL LETTER PEADLAM CAPITAL LETTER BHEADLAM CAPITAL LETTER " +
"RAADLAM CAPITAL LETTER EADLAM CAPITAL LETTER FAADLAM CAPITAL LETTER IADL" +
"AM CAPITAL LETTER OADLAM CAPITAL LETTER DHAADLAM CAPITAL LETTER YHEADLAM" +
" CAPITAL LETTER WAWADLAM CAPITAL LETTER NUNADLAM CAPITAL LETTER KAFADLAM" +
" CAPITAL LETTER YAADLAM CAPITAL LETTER UADLAM CAPITAL LETTER JIIMADLAM C" +
"APITAL LETTER CHIADLAM CAPITAL LETTER HAADLAM CAPITAL LETTER QAAFADLAM C" +
"APITAL LETTER GAADLAM CAPITAL LETTER NYAADLAM CAPITAL LETTER TUADLAM CAP" +
"ITAL LETTER NHAADLAM CAPITAL LETTER VAADLAM CAPITAL LETTER KHAADLAM CAPI" +
"TAL LETTER GBEADLAM CAPITAL LETTER ZALADLAM CAPITAL LETTER KPOADLAM CAPI" +
"TAL LETTER SHAADLAM SMALL LETTER ALIFADLAM SMALL LETTER DAALIADLAM SMALL" +
" LETTER LAAMADLAM SMALL LETTER MIIMADLAM SMALL LETTER BAADLAM SMALL LETT" +
"ER SINNYIIYHEADLAM SMALL LETTER PEADLAM SMALL LETTER BHEADLAM SMALL LETT" +
"ER RAADLAM SMALL LETTER EADLAM SMALL LETTER FAADLAM SMALL LETTER IADLAM " +
"SMALL LETTER OADLAM SMALL LETTER DHAADLAM SMALL LETTER YHEADLAM SMALL LE" +
"TTER WAWADLAM SMALL LETTER NUNADLAM SMALL LETTER KAFADLAM SMALL LETTER Y" +
"AADLAM SMALL LETTER UADLAM SMALL LETTER JIIMADLAM SMALL LETTER CHIADLAM " +
"SMALL LETTER HAADLAM SMALL LETTER QAAFADLAM SMALL LETTER GAADLAM SMALL L" +
"ETTER NYAADLAM SMALL LETTER TUADLAM SMALL LETTER NHAADLAM SMALL LETTER V" +
"AADLAM SMALL LETTER KHAADLAM SMALL LETTER GBEADLAM SMALL LETTER ZALADLAM" +
" SMALL LETTER KPOADLAM SMALL LETTER SHAADLAM ALIF LENGTHENERADLAM VOWEL " +
"LENGTHENERADLAM GEMINATION MARKADLAM HAMZAADLAM CONSONANT MODIFIERADLAM " +
"GEMINATE CONSONANT MODIFIERADLAM NUKTAADLAM NASALIZATION MARKADLAM DIGIT" +
" ZEROADLAM DIGIT ONEADLAM DIGIT TWOADLAM DIGIT THREEADLAM DIGIT FOURADLA" +
"M DIGIT FIVEADLAM DIGIT SIXADLAM DIGIT SEVENADLAM DIGIT EIGHTADLAM DIGIT" +
" NINEADLAM INITIAL EXCLAMATION MARKADLAM INITIAL QUESTION MARKINDIC SIYA" +
"Q NUMBER ONEINDIC SIYAQ NUMBER TWOINDIC SIYAQ NUMBER THREEINDIC SIYAQ NU" +
"MBER FOURINDIC SIYAQ NUMBER FIVEINDIC SIYAQ NUMBER SIXINDIC SIYAQ NUMBER" +
" SEVENINDIC SIYAQ NUMBER EIGHTINDIC SIYAQ NUMBER NINEINDIC SIYAQ NUMBER " +
"TENINDIC SIYAQ NUMBER TWENTYINDIC SIYAQ NUMBER THIRTYINDIC SIYAQ NUMBER " +
"FORTYINDIC SIYAQ NUMBER FIFTYINDIC SIYAQ NUMBER SIXTYINDIC SIYAQ NUMBER " +
"SEVENTYINDIC SIYAQ NUMBER EIGHTYINDIC SIYAQ NUMBER NINETYINDIC SIYAQ NUM" +
"BER ONE HUNDREDINDIC SIYAQ NUMBER TWO HUNDREDINDIC SIYAQ NUMBER THREE HU" +
"NDREDINDIC SIYAQ NUMBER FOUR HUNDREDINDIC SIYAQ NUMBER FIVE HUNDREDINDIC" +
" SIYAQ NUMBER SIX HUNDREDINDIC SIYAQ NUMBER SEVEN HUNDREDINDIC SIYAQ NUM" +
"BER EIGHT HUNDREDINDIC SIYAQ NUMBER NINE HUNDREDINDIC SIYAQ NUMBER ONE T" +
"HOUSANDINDIC SIYAQ NUMBER TWO THOUSANDINDIC SIYAQ NUMBER THREE THOUSANDI" +
"NDIC SIYAQ NUMBER FOUR THOUSANDINDIC SIYAQ NUMBER FIVE THOUSANDINDIC SIY" +
"AQ NUMBER SIX THOUSANDINDIC SIYAQ NUMBER SEVEN THOUSANDINDIC SIYAQ NUMBE" +
"R EIGHT THOUSANDINDIC SIYAQ NUMBER NINE THOUSANDINDIC SIYAQ NUMBER TEN T" +
"HOUSANDINDIC SIYAQ NUMBER TWENTY THOUSANDINDIC SIYAQ NUMBER THIRTY THOUS" +
"ANDINDIC SIYAQ NUMBER FORTY THOUSANDINDIC SIYAQ NUMBER FIFTY THOUSANDIND" +
"IC SIYAQ NUMBER SIXTY THOUSANDINDIC SIYAQ NUMBER SEVENTY THOUSANDINDIC S" +
"IYAQ NUMBER EIGHTY THOUSANDINDIC SIYAQ NUMBER NINETY THOUSANDINDIC SIYAQ" +
" NUMBER LAKHINDIC SIYAQ NUMBER LAKHANINDIC SIYAQ LAKH MARKINDIC SIYAQ NU" +
"MBER KARORINDIC SIYAQ NUMBER KARORANINDIC SIYAQ NUMBER PREFIXED ONEINDIC" +
" SIYAQ NUMBER PREFIXED TWOINDIC SIYAQ NUMBER PREFIXED THREEINDIC SIYAQ N" +
"UMBER PREFIXED FOURINDIC SIYAQ NUMBER PREFIXED FIVEINDIC SIYAQ NUMBER PR" +
"EFIXED SIXINDIC SIYAQ NUMBER PREFIXED SEVENINDIC SIYAQ NUMBER PREFIXED E" +
"IGHTINDIC SIYAQ NUMBER PREFIXED NINEINDIC SIYAQ PLACEHOLDERINDIC SIYAQ F" +
"RACTION ONE QUARTERINDIC SIYAQ FRACTION ONE HALFINDIC SIYAQ FRACTION THR" +
"EE QUARTERSINDIC SIYAQ RUPEE MARKINDIC SIYAQ NUMBER ALTERNATE ONEINDIC S" +
"IYAQ NUMBER ALTERNATE TWOINDIC SIYAQ NUMBER ALTERNATE TEN THOUSANDINDIC ") + ("" +
"SIYAQ ALTERNATE LAKH MARKOTTOMAN SIYAQ NUMBER ONEOTTOMAN SIYAQ NUMBER TW" +
"OOTTOMAN SIYAQ NUMBER THREEOTTOMAN SIYAQ NUMBER FOUROTTOMAN SIYAQ NUMBER" +
" FIVEOTTOMAN SIYAQ NUMBER SIXOTTOMAN SIYAQ NUMBER SEVENOTTOMAN SIYAQ NUM" +
"BER EIGHTOTTOMAN SIYAQ NUMBER NINEOTTOMAN SIYAQ NUMBER TENOTTOMAN SIYAQ " +
"NUMBER TWENTYOTTOMAN SIYAQ NUMBER THIRTYOTTOMAN SIYAQ NUMBER FORTYOTTOMA" +
"N SIYAQ NUMBER FIFTYOTTOMAN SIYAQ NUMBER SIXTYOTTOMAN SIYAQ NUMBER SEVEN" +
"TYOTTOMAN SIYAQ NUMBER EIGHTYOTTOMAN SIYAQ NUMBER NINETYOTTOMAN SIYAQ NU" +
"MBER ONE HUNDREDOTTOMAN SIYAQ NUMBER TWO HUNDREDOTTOMAN SIYAQ NUMBER THR" +
"EE HUNDREDOTTOMAN SIYAQ NUMBER FOUR HUNDREDOTTOMAN SIYAQ NUMBER FIVE HUN" +
"DREDOTTOMAN SIYAQ NUMBER SIX HUNDREDOTTOMAN SIYAQ NUMBER SEVEN HUNDREDOT" +
"TOMAN SIYAQ NUMBER EIGHT HUNDREDOTTOMAN SIYAQ NUMBER NINE HUNDREDOTTOMAN" +
" SIYAQ NUMBER ONE THOUSANDOTTOMAN SIYAQ NUMBER TWO THOUSANDOTTOMAN SIYAQ" +
" NUMBER THREE THOUSANDOTTOMAN SIYAQ NUMBER FOUR THOUSANDOTTOMAN SIYAQ NU" +
"MBER FIVE THOUSANDOTTOMAN SIYAQ NUMBER SIX THOUSANDOTTOMAN SIYAQ NUMBER " +
"SEVEN THOUSANDOTTOMAN SIYAQ NUMBER EIGHT THOUSANDOTTOMAN SIYAQ NUMBER NI" +
"NE THOUSANDOTTOMAN SIYAQ NUMBER TEN THOUSANDOTTOMAN SIYAQ NUMBER TWENTY " +
"THOUSANDOTTOMAN SIYAQ NUMBER THIRTY THOUSANDOTTOMAN SIYAQ NUMBER FORTY T" +
"HOUSANDOTTOMAN SIYAQ NUMBER FIFTY THOUSANDOTTOMAN SIYAQ NUMBER SIXTY THO" +
"USANDOTTOMAN SIYAQ NUMBER SEVENTY THOUSANDOTTOMAN SIYAQ NUMBER EIGHTY TH" +
"OUSANDOTTOMAN SIYAQ NUMBER NINETY THOUSANDOTTOMAN SIYAQ MARRATANOTTOMAN " +
"SIYAQ ALTERNATE NUMBER TWOOTTOMAN SIYAQ ALTERNATE NUMBER THREEOTTOMAN SI" +
"YAQ ALTERNATE NUMBER FOUROTTOMAN SIYAQ ALTERNATE NUMBER FIVEOTTOMAN SIYA" +
"Q ALTERNATE NUMBER SIXOTTOMAN SIYAQ ALTERNATE NUMBER SEVENOTTOMAN SIYAQ " +
"ALTERNATE NUMBER EIGHTOTTOMAN SIYAQ ALTERNATE NUMBER NINEOTTOMAN SIYAQ A" +
"LTERNATE NUMBER TENOTTOMAN SIYAQ ALTERNATE NUMBER FOUR HUNDREDOTTOMAN SI" +
"YAQ ALTERNATE NUMBER SIX HUNDREDOTTOMAN SIYAQ ALTERNATE NUMBER TWO THOUS" +
"ANDOTTOMAN SIYAQ ALTERNATE NUMBER TEN THOUSANDOTTOMAN SIYAQ FRACTION ONE" +
" HALFOTTOMAN SIYAQ FRACTION ONE SIXTHARABIC MATHEMATICAL ALEFARABIC MATH" +
"EMATICAL BEHARABIC MATHEMATICAL JEEMARABIC MATHEMATICAL DALARABIC MATHEM" +
"ATICAL WAWARABIC MATHEMATICAL ZAINARABIC MATHEMATICAL HAHARABIC MATHEMAT" +
"ICAL TAHARABIC MATHEMATICAL YEHARABIC MATHEMATICAL KAFARABIC MATHEMATICA" +
"L LAMARABIC MATHEMATICAL MEEMARABIC MATHEMATICAL NOONARABIC MATHEMATICAL" +
" SEENARABIC MATHEMATICAL AINARABIC MATHEMATICAL FEHARABIC MATHEMATICAL S" +
"ADARABIC MATHEMATICAL QAFARABIC MATHEMATICAL REHARABIC MATHEMATICAL SHEE" +
"NARABIC MATHEMATICAL TEHARABIC MATHEMATICAL THEHARABIC MATHEMATICAL KHAH" +
"ARABIC MATHEMATICAL THALARABIC MATHEMATICAL DADARABIC MATHEMATICAL ZAHAR" +
"ABIC MATHEMATICAL GHAINARABIC MATHEMATICAL DOTLESS BEHARABIC MATHEMATICA" +
"L DOTLESS NOONARABIC MATHEMATICAL DOTLESS FEHARABIC MATHEMATICAL DOTLESS" +
" QAFARABIC MATHEMATICAL INITIAL BEHARABIC MATHEMATICAL INITIAL JEEMARABI" +
"C MATHEMATICAL INITIAL HEHARABIC MATHEMATICAL INITIAL HAHARABIC MATHEMAT" +
"ICAL INITIAL YEHARABIC MATHEMATICAL INITIAL KAFARABIC MATHEMATICAL INITI" +
"AL LAMARABIC MATHEMATICAL INITIAL MEEMARABIC MATHEMATICAL INITIAL NOONAR" +
"ABIC MATHEMATICAL INITIAL SEENARABIC MATHEMATICAL INITIAL AINARABIC MATH" +
"EMATICAL INITIAL FEHARABIC MATHEMATICAL INITIAL SADARABIC MATHEMATICAL I" +
"NITIAL QAFARABIC MATHEMATICAL INITIAL SHEENARABIC MATHEMATICAL INITIAL T" +
"EHARABIC MATHEMATICAL INITIAL THEHARABIC MATHEMATICAL INITIAL KHAHARABIC" +
" MATHEMATICAL INITIAL DADARABIC MATHEMATICAL INITIAL GHAINARABIC MATHEMA" +
"TICAL TAILED JEEMARABIC MATHEMATICAL TAILED HAHARABIC MATHEMATICAL TAILE" +
"D YEHARABIC MATHEMATICAL TAILED LAMARABIC MATHEMATICAL TAILED NOONARABIC" +
" MATHEMATICAL TAILED SEENARABIC MATHEMATICAL TAILED AINARABIC MATHEMATIC" +
"AL TAILED SADARABIC MATHEMATICAL TAILED QAFARABIC MATHEMATICAL TAILED SH" +
"EENARABIC MATHEMATICAL TAILED KHAHARABIC MATHEMATICAL TAILED DADARABIC M" +
"ATHEMATICAL TAILED GHAINARABIC MATHEMATICAL TAILED DOTLESS NOONARABIC MA" +
"THEMATICAL TAILED DOTLESS QAFARABIC MATHEMATICAL STRETCHED BEHARABIC MAT" +
"HEMATICAL STRETCHED JEEMARABIC MATHEMATICAL STRETCHED HEHARABIC MATHEMAT" +
"ICAL STRETCHED HAHARABIC MATHEMATICAL STRETCHED TAHARABIC MATHEMATICAL S" +
"TRETCHED YEHARABIC MATHEMATICAL STRETCHED KAFARABIC MATHEMATICAL STRETCH" +
"ED MEEMARABIC MATHEMATICAL STRETCHED NOONARABIC MATHEMATICAL STRETCHED S" +
"EENARABIC MATHEMATICAL STRETCHED AINARABIC MATHEMATICAL STRETCHED FEHARA" +
"BIC MATHEMATICAL STRETCHED SADARABIC MATHEMATICAL STRETCHED QAFARABIC MA" +
"THEMATICAL STRETCHED SHEENARABIC MATHEMATICAL STRETCHED TEHARABIC MATHEM" +
"ATICAL STRETCHED THEHARABIC MATHEMATICAL STRETCHED KHAHARABIC MATHEMATIC" +
"AL STRETCHED DADARABIC MATHEMATICAL STRETCHED ZAHARABIC MATHEMATICAL STR" +
"ETCHED GHAINARABIC MATHEMATICAL STRETCHED DOTLESS BEHARABIC MATHEMATICAL") + ("" +
" STRETCHED DOTLESS FEHARABIC MATHEMATICAL LOOPED ALEFARABIC MATHEMATICAL" +
" LOOPED BEHARABIC MATHEMATICAL LOOPED JEEMARABIC MATHEMATICAL LOOPED DAL" +
"ARABIC MATHEMATICAL LOOPED HEHARABIC MATHEMATICAL LOOPED WAWARABIC MATHE" +
"MATICAL LOOPED ZAINARABIC MATHEMATICAL LOOPED HAHARABIC MATHEMATICAL LOO" +
"PED TAHARABIC MATHEMATICAL LOOPED YEHARABIC MATHEMATICAL LOOPED LAMARABI" +
"C MATHEMATICAL LOOPED MEEMARABIC MATHEMATICAL LOOPED NOONARABIC MATHEMAT" +
"ICAL LOOPED SEENARABIC MATHEMATICAL LOOPED AINARABIC MATHEMATICAL LOOPED" +
" FEHARABIC MATHEMATICAL LOOPED SADARABIC MATHEMATICAL LOOPED QAFARABIC M" +
"ATHEMATICAL LOOPED REHARABIC MATHEMATICAL LOOPED SHEENARABIC MATHEMATICA" +
"L LOOPED TEHARABIC MATHEMATICAL LOOPED THEHARABIC MATHEMATICAL LOOPED KH" +
"AHARABIC MATHEMATICAL LOOPED THALARABIC MATHEMATICAL LOOPED DADARABIC MA" +
"THEMATICAL LOOPED ZAHARABIC MATHEMATICAL LOOPED GHAINARABIC MATHEMATICAL" +
" DOUBLE-STRUCK BEHARABIC MATHEMATICAL DOUBLE-STRUCK JEEMARABIC MATHEMATI" +
"CAL DOUBLE-STRUCK DALARABIC MATHEMATICAL DOUBLE-STRUCK WAWARABIC MATHEMA" +
"TICAL DOUBLE-STRUCK ZAINARABIC MATHEMATICAL DOUBLE-STRUCK HAHARABIC MATH" +
"EMATICAL DOUBLE-STRUCK TAHARABIC MATHEMATICAL DOUBLE-STRUCK YEHARABIC MA" +
"THEMATICAL DOUBLE-STRUCK LAMARABIC MATHEMATICAL DOUBLE-STRUCK MEEMARABIC" +
" MATHEMATICAL DOUBLE-STRUCK NOONARABIC MATHEMATICAL DOUBLE-STRUCK SEENAR" +
"ABIC MATHEMATICAL DOUBLE-STRUCK AINARABIC MATHEMATICAL DOUBLE-STRUCK FEH" +
"ARABIC MATHEMATICAL DOUBLE-STRUCK SADARABIC MATHEMATICAL DOUBLE-STRUCK Q" +
"AFARABIC MATHEMATICAL DOUBLE-STRUCK REHARABIC MATHEMATICAL DOUBLE-STRUCK" +
" SHEENARABIC MATHEMATICAL DOUBLE-STRUCK TEHARABIC MATHEMATICAL DOUBLE-ST" +
"RUCK THEHARABIC MATHEMATICAL DOUBLE-STRUCK KHAHARABIC MATHEMATICAL DOUBL" +
"E-STRUCK THALARABIC MATHEMATICAL DOUBLE-STRUCK DADARABIC MATHEMATICAL DO" +
"UBLE-STRUCK ZAHARABIC MATHEMATICAL DOUBLE-STRUCK GHAINARABIC MATHEMATICA" +
"L OPERATOR MEEM WITH HAH WITH TATWEELARABIC MATHEMATICAL OPERATOR HAH WI" +
"TH DALMAHJONG TILE EAST WINDMAHJONG TILE SOUTH WINDMAHJONG TILE WEST WIN" +
"DMAHJONG TILE NORTH WINDMAHJONG TILE RED DRAGONMAHJONG TILE GREEN DRAGON" +
"MAHJONG TILE WHITE DRAGONMAHJONG TILE ONE OF CHARACTERSMAHJONG TILE TWO " +
"OF CHARACTERSMAHJONG TILE THREE OF CHARACTERSMAHJONG TILE FOUR OF CHARAC" +
"TERSMAHJONG TILE FIVE OF CHARACTERSMAHJONG TILE SIX OF CHARACTERSMAHJONG" +
" TILE SEVEN OF CHARACTERSMAHJONG TILE EIGHT OF CHARACTERSMAHJONG TILE NI" +
"NE OF CHARACTERSMAHJONG TILE ONE OF BAMBOOSMAHJONG TILE TWO OF BAMBOOSMA" +
"HJONG TILE THREE OF BAMBOOSMAHJONG TILE FOUR OF BAMBOOSMAHJONG TILE FIVE" +
" OF BAMBOOSMAHJONG TILE SIX OF BAMBOOSMAHJONG TILE SEVEN OF BAMBOOSMAHJO" +
"NG TILE EIGHT OF BAMBOOSMAHJONG TILE NINE OF BAMBOOSMAHJONG TILE ONE OF " +
"CIRCLESMAHJONG TILE TWO OF CIRCLESMAHJONG TILE THREE OF CIRCLESMAHJONG T" +
"ILE FOUR OF CIRCLESMAHJONG TILE FIVE OF CIRCLESMAHJONG TILE SIX OF CIRCL" +
"ESMAHJONG TILE SEVEN OF CIRCLESMAHJONG TILE EIGHT OF CIRCLESMAHJONG TILE" +
" NINE OF CIRCLESMAHJONG TILE PLUMMAHJONG TILE ORCHIDMAHJONG TILE BAMBOOM" +
"AHJONG TILE CHRYSANTHEMUMMAHJONG TILE SPRINGMAHJONG TILE SUMMERMAHJONG T" +
"ILE AUTUMNMAHJONG TILE WINTERMAHJONG TILE JOKERMAHJONG TILE BACKDOMINO T" +
"ILE HORIZONTAL BACKDOMINO TILE HORIZONTAL-00-00DOMINO TILE HORIZONTAL-00" +
"-01DOMINO TILE HORIZONTAL-00-02DOMINO TILE HORIZONTAL-00-03DOMINO TILE H" +
"ORIZONTAL-00-04DOMINO TILE HORIZONTAL-00-05DOMINO TILE HORIZONTAL-00-06D" +
"OMINO TILE HORIZONTAL-01-00DOMINO TILE HORIZONTAL-01-01DOMINO TILE HORIZ" +
"ONTAL-01-02DOMINO TILE HORIZONTAL-01-03DOMINO TILE HORIZONTAL-01-04DOMIN" +
"O TILE HORIZONTAL-01-05DOMINO TILE HORIZONTAL-01-06DOMINO TILE HORIZONTA" +
"L-02-00DOMINO TILE HORIZONTAL-02-01DOMINO TILE HORIZONTAL-02-02DOMINO TI" +
"LE HORIZONTAL-02-03DOMINO TILE HORIZONTAL-02-04DOMINO TILE HORIZONTAL-02" +
"-05DOMINO TILE HORIZONTAL-02-06DOMINO TILE HORIZONTAL-03-00DOMINO TILE H" +
"ORIZONTAL-03-01DOMINO TILE HORIZONTAL-03-02DOMINO TILE HORIZONTAL-03-03D" +
"OMINO TILE HORIZONTAL-03-04DOMINO TILE HORIZONTAL-03-05DOMINO TILE HORIZ" +
"ONTAL-03-06DOMINO TILE HORIZONTAL-04-00DOMINO TILE HORIZONTAL-04-01DOMIN" +
"O TILE HORIZONTAL-04-02DOMINO TILE HORIZONTAL-04-03DOMINO TILE HORIZONTA" +
"L-04-04DOMINO TILE HORIZONTAL-04-05DOMINO TILE HORIZONTAL-04-06DOMINO TI" +
"LE HORIZONTAL-05-00DOMINO TILE HORIZONTAL-05-01DOMINO TILE HORIZONTAL-05" +
"-02DOMINO TILE HORIZONTAL-05-03DOMINO TILE HORIZONTAL-05-04DOMINO TILE H" +
"ORIZONTAL-05-05DOMINO TILE HORIZONTAL-05-06DOMINO TILE HORIZONTAL-06-00D" +
"OMINO TILE HORIZONTAL-06-01DOMINO TILE HORIZONTAL-06-02DOMINO TILE HORIZ" +
"ONTAL-06-03DOMINO TILE HORIZONTAL-06-04DOMINO TILE HORIZONTAL-06-05DOMIN" +
"O TILE HORIZONTAL-06-06DOMINO TILE VERTICAL BACKDOMINO TILE VERTICAL-00-" +
"00DOMINO TILE VERTICAL-00-01DOMINO TILE VERTICAL-00-02DOMINO TILE VERTIC" +
"AL-00-03DOMINO TILE VERTICAL-00-04DOMINO TILE VERTICAL-00-05DOMINO TILE ") + ("" +
"VERTICAL-00-06DOMINO TILE VERTICAL-01-00DOMINO TILE VERTICAL-01-01DOMINO" +
" TILE VERTICAL-01-02DOMINO TILE VERTICAL-01-03DOMINO TILE VERTICAL-01-04" +
"DOMINO TILE VERTICAL-01-05DOMINO TILE VERTICAL-01-06DOMINO TILE VERTICAL" +
"-02-00DOMINO TILE VERTICAL-02-01DOMINO TILE VERTICAL-02-02DOMINO TILE VE" +
"RTICAL-02-03DOMINO TILE VERTICAL-02-04DOMINO TILE VERTICAL-02-05DOMINO T" +
"ILE VERTICAL-02-06DOMINO TILE VERTICAL-03-00DOMINO TILE VERTICAL-03-01DO" +
"MINO TILE VERTICAL-03-02DOMINO TILE VERTICAL-03-03DOMINO TILE VERTICAL-0" +
"3-04DOMINO TILE VERTICAL-03-05DOMINO TILE VERTICAL-03-06DOMINO TILE VERT" +
"ICAL-04-00DOMINO TILE VERTICAL-04-01DOMINO TILE VERTICAL-04-02DOMINO TIL" +
"E VERTICAL-04-03DOMINO TILE VERTICAL-04-04DOMINO TILE VERTICAL-04-05DOMI" +
"NO TILE VERTICAL-04-06DOMINO TILE VERTICAL-05-00DOMINO TILE VERTICAL-05-" +
"01DOMINO TILE VERTICAL-05-02DOMINO TILE VERTICAL-05-03DOMINO TILE VERTIC" +
"AL-05-04DOMINO TILE VERTICAL-05-05DOMINO TILE VERTICAL-05-06DOMINO TILE " +
"VERTICAL-06-00DOMINO TILE VERTICAL-06-01DOMINO TILE VERTICAL-06-02DOMINO" +
" TILE VERTICAL-06-03DOMINO TILE VERTICAL-06-04DOMINO TILE VERTICAL-06-05" +
"DOMINO TILE VERTICAL-06-06PLAYING CARD BACKPLAYING CARD ACE OF SPADESPLA" +
"YING CARD TWO OF SPADESPLAYING CARD THREE OF SPADESPLAYING CARD FOUR OF " +
"SPADESPLAYING CARD FIVE OF SPADESPLAYING CARD SIX OF SPADESPLAYING CARD " +
"SEVEN OF SPADESPLAYING CARD EIGHT OF SPADESPLAYING CARD NINE OF SPADESPL" +
"AYING CARD TEN OF SPADESPLAYING CARD JACK OF SPADESPLAYING CARD KNIGHT O" +
"F SPADESPLAYING CARD QUEEN OF SPADESPLAYING CARD KING OF SPADESPLAYING C" +
"ARD ACE OF HEARTSPLAYING CARD TWO OF HEARTSPLAYING CARD THREE OF HEARTSP" +
"LAYING CARD FOUR OF HEARTSPLAYING CARD FIVE OF HEARTSPLAYING CARD SIX OF" +
" HEARTSPLAYING CARD SEVEN OF HEARTSPLAYING CARD EIGHT OF HEARTSPLAYING C" +
"ARD NINE OF HEARTSPLAYING CARD TEN OF HEARTSPLAYING CARD JACK OF HEARTSP" +
"LAYING CARD KNIGHT OF HEARTSPLAYING CARD QUEEN OF HEARTSPLAYING CARD KIN" +
"G OF HEARTSPLAYING CARD RED JOKERPLAYING CARD ACE OF DIAMONDSPLAYING CAR" +
"D TWO OF DIAMONDSPLAYING CARD THREE OF DIAMONDSPLAYING CARD FOUR OF DIAM" +
"ONDSPLAYING CARD FIVE OF DIAMONDSPLAYING CARD SIX OF DIAMONDSPLAYING CAR" +
"D SEVEN OF DIAMONDSPLAYING CARD EIGHT OF DIAMONDSPLAYING CARD NINE OF DI" +
"AMONDSPLAYING CARD TEN OF DIAMONDSPLAYING CARD JACK OF DIAMONDSPLAYING C" +
"ARD KNIGHT OF DIAMONDSPLAYING CARD QUEEN OF DIAMONDSPLAYING CARD KING OF" +
" DIAMONDSPLAYING CARD BLACK JOKERPLAYING CARD ACE OF CLUBSPLAYING CARD T" +
"WO OF CLUBSPLAYING CARD THREE OF CLUBSPLAYING CARD FOUR OF CLUBSPLAYING " +
"CARD FIVE OF CLUBSPLAYING CARD SIX OF CLUBSPLAYING CARD SEVEN OF CLUBSPL" +
"AYING CARD EIGHT OF CLUBSPLAYING CARD NINE OF CLUBSPLAYING CARD TEN OF C" +
"LUBSPLAYING CARD JACK OF CLUBSPLAYING CARD KNIGHT OF CLUBSPLAYING CARD Q" +
"UEEN OF CLUBSPLAYING CARD KING OF CLUBSPLAYING CARD WHITE JOKERPLAYING C" +
"ARD FOOLPLAYING CARD TRUMP-1PLAYING CARD TRUMP-2PLAYING CARD TRUMP-3PLAY" +
"ING CARD TRUMP-4PLAYING CARD TRUMP-5PLAYING CARD TRUMP-6PLAYING CARD TRU" +
"MP-7PLAYING CARD TRUMP-8PLAYING CARD TRUMP-9PLAYING CARD TRUMP-10PLAYING" +
" CARD TRUMP-11PLAYING CARD TRUMP-12PLAYING CARD TRUMP-13PLAYING CARD TRU" +
"MP-14PLAYING CARD TRUMP-15PLAYING CARD TRUMP-16PLAYING CARD TRUMP-17PLAY" +
"ING CARD TRUMP-18PLAYING CARD TRUMP-19PLAYING CARD TRUMP-20PLAYING CARD " +
"TRUMP-21DIGIT ZERO FULL STOPDIGIT ZERO COMMADIGIT ONE COMMADIGIT TWO COM" +
"MADIGIT THREE COMMADIGIT FOUR COMMADIGIT FIVE COMMADIGIT SIX COMMADIGIT " +
"SEVEN COMMADIGIT EIGHT COMMADIGIT NINE COMMADINGBAT CIRCLED SANS-SERIF D" +
"IGIT ZERODINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZEROCIRCLED ZERO WITH" +
" SLASHCIRCLED ANTICLOCKWISE ARROWCIRCLED DOLLAR SIGN WITH OVERLAID BACKS" +
"LASHPARENTHESIZED LATIN CAPITAL LETTER APARENTHESIZED LATIN CAPITAL LETT" +
"ER BPARENTHESIZED LATIN CAPITAL LETTER CPARENTHESIZED LATIN CAPITAL LETT" +
"ER DPARENTHESIZED LATIN CAPITAL LETTER EPARENTHESIZED LATIN CAPITAL LETT" +
"ER FPARENTHESIZED LATIN CAPITAL LETTER GPARENTHESIZED LATIN CAPITAL LETT" +
"ER HPARENTHESIZED LATIN CAPITAL LETTER IPARENTHESIZED LATIN CAPITAL LETT" +
"ER JPARENTHESIZED LATIN CAPITAL LETTER KPARENTHESIZED LATIN CAPITAL LETT" +
"ER LPARENTHESIZED LATIN CAPITAL LETTER MPARENTHESIZED LATIN CAPITAL LETT" +
"ER NPARENTHESIZED LATIN CAPITAL LETTER OPARENTHESIZED LATIN CAPITAL LETT" +
"ER PPARENTHESIZED LATIN CAPITAL LETTER QPARENTHESIZED LATIN CAPITAL LETT" +
"ER RPARENTHESIZED LATIN CAPITAL LETTER SPARENTHESIZED LATIN CAPITAL LETT" +
"ER TPARENTHESIZED LATIN CAPITAL LETTER UPARENTHESIZED LATIN CAPITAL LETT" +
"ER VPARENTHESIZED LATIN CAPITAL LETTER WPARENTHESIZED LATIN CAPITAL LETT" +
"ER XPARENTHESIZED LATIN CAPITAL LETTER YPARENTHESIZED LATIN CAPITAL LETT" +
"ER ZTORTOISE SHELL BRACKETED LATIN CAPITAL LETTER SCIRCLED ITALIC LATIN " +
"CAPITAL LETTER CCIRCLED ITALIC LATIN CAPITAL LETTER RCIRCLED CDCIRCLED W") + ("" +
"ZCOPYLEFT SYMBOLSQUARED LATIN CAPITAL LETTER ASQUARED LATIN CAPITAL LETT" +
"ER BSQUARED LATIN CAPITAL LETTER CSQUARED LATIN CAPITAL LETTER DSQUARED " +
"LATIN CAPITAL LETTER ESQUARED LATIN CAPITAL LETTER FSQUARED LATIN CAPITA" +
"L LETTER GSQUARED LATIN CAPITAL LETTER HSQUARED LATIN CAPITAL LETTER ISQ" +
"UARED LATIN CAPITAL LETTER JSQUARED LATIN CAPITAL LETTER KSQUARED LATIN " +
"CAPITAL LETTER LSQUARED LATIN CAPITAL LETTER MSQUARED LATIN CAPITAL LETT" +
"ER NSQUARED LATIN CAPITAL LETTER OSQUARED LATIN CAPITAL LETTER PSQUARED " +
"LATIN CAPITAL LETTER QSQUARED LATIN CAPITAL LETTER RSQUARED LATIN CAPITA" +
"L LETTER SSQUARED LATIN CAPITAL LETTER TSQUARED LATIN CAPITAL LETTER USQ" +
"UARED LATIN CAPITAL LETTER VSQUARED LATIN CAPITAL LETTER WSQUARED LATIN " +
"CAPITAL LETTER XSQUARED LATIN CAPITAL LETTER YSQUARED LATIN CAPITAL LETT" +
"ER ZSQUARED HVSQUARED MVSQUARED SDSQUARED SSSQUARED PPVSQUARED WCNEGATIV" +
"E CIRCLED LATIN CAPITAL LETTER ANEGATIVE CIRCLED LATIN CAPITAL LETTER BN" +
"EGATIVE CIRCLED LATIN CAPITAL LETTER CNEGATIVE CIRCLED LATIN CAPITAL LET" +
"TER DNEGATIVE CIRCLED LATIN CAPITAL LETTER ENEGATIVE CIRCLED LATIN CAPIT" +
"AL LETTER FNEGATIVE CIRCLED LATIN CAPITAL LETTER GNEGATIVE CIRCLED LATIN" +
" CAPITAL LETTER HNEGATIVE CIRCLED LATIN CAPITAL LETTER INEGATIVE CIRCLED" +
" LATIN CAPITAL LETTER JNEGATIVE CIRCLED LATIN CAPITAL LETTER KNEGATIVE C" +
"IRCLED LATIN CAPITAL LETTER LNEGATIVE CIRCLED LATIN CAPITAL LETTER MNEGA" +
"TIVE CIRCLED LATIN CAPITAL LETTER NNEGATIVE CIRCLED LATIN CAPITAL LETTER" +
" ONEGATIVE CIRCLED LATIN CAPITAL LETTER PNEGATIVE CIRCLED LATIN CAPITAL " +
"LETTER QNEGATIVE CIRCLED LATIN CAPITAL LETTER RNEGATIVE CIRCLED LATIN CA" +
"PITAL LETTER SNEGATIVE CIRCLED LATIN CAPITAL LETTER TNEGATIVE CIRCLED LA" +
"TIN CAPITAL LETTER UNEGATIVE CIRCLED LATIN CAPITAL LETTER VNEGATIVE CIRC" +
"LED LATIN CAPITAL LETTER WNEGATIVE CIRCLED LATIN CAPITAL LETTER XNEGATIV" +
"E CIRCLED LATIN CAPITAL LETTER YNEGATIVE CIRCLED LATIN CAPITAL LETTER ZR" +
"AISED MC SIGNRAISED MD SIGNRAISED MR SIGNCIRCLED CCCIRCLED C WITH OVERLA" +
"ID BACKSLASHCIRCLED HUMAN FIGURENEGATIVE SQUARED LATIN CAPITAL LETTER AN" +
"EGATIVE SQUARED LATIN CAPITAL LETTER BNEGATIVE SQUARED LATIN CAPITAL LET" +
"TER CNEGATIVE SQUARED LATIN CAPITAL LETTER DNEGATIVE SQUARED LATIN CAPIT" +
"AL LETTER ENEGATIVE SQUARED LATIN CAPITAL LETTER FNEGATIVE SQUARED LATIN" +
" CAPITAL LETTER GNEGATIVE SQUARED LATIN CAPITAL LETTER HNEGATIVE SQUARED" +
" LATIN CAPITAL LETTER INEGATIVE SQUARED LATIN CAPITAL LETTER JNEGATIVE S" +
"QUARED LATIN CAPITAL LETTER KNEGATIVE SQUARED LATIN CAPITAL LETTER LNEGA" +
"TIVE SQUARED LATIN CAPITAL LETTER MNEGATIVE SQUARED LATIN CAPITAL LETTER" +
" NNEGATIVE SQUARED LATIN CAPITAL LETTER ONEGATIVE SQUARED LATIN CAPITAL " +
"LETTER PNEGATIVE SQUARED LATIN CAPITAL LETTER QNEGATIVE SQUARED LATIN CA" +
"PITAL LETTER RNEGATIVE SQUARED LATIN CAPITAL LETTER SNEGATIVE SQUARED LA" +
"TIN CAPITAL LETTER TNEGATIVE SQUARED LATIN CAPITAL LETTER UNEGATIVE SQUA" +
"RED LATIN CAPITAL LETTER VNEGATIVE SQUARED LATIN CAPITAL LETTER WNEGATIV" +
"E SQUARED LATIN CAPITAL LETTER XNEGATIVE SQUARED LATIN CAPITAL LETTER YN" +
"EGATIVE SQUARED LATIN CAPITAL LETTER ZCROSSED NEGATIVE SQUARED LATIN CAP" +
"ITAL LETTER PNEGATIVE SQUARED ICNEGATIVE SQUARED PANEGATIVE SQUARED SANE" +
"GATIVE SQUARED ABNEGATIVE SQUARED WCSQUARE DJSQUARED CLSQUARED COOLSQUAR" +
"ED FREESQUARED IDSQUARED NEWSQUARED NGSQUARED OKSQUARED SOSSQUARED UP WI" +
"TH EXCLAMATION MARKSQUARED VSSQUARED THREE DSQUARED SECOND SCREENSQUARED" +
" TWO KSQUARED FOUR KSQUARED EIGHT KSQUARED FIVE POINT ONESQUARED SEVEN P" +
"OINT ONESQUARED TWENTY-TWO POINT TWOSQUARED SIXTY PSQUARED ONE HUNDRED T" +
"WENTY PSQUARED LATIN SMALL LETTER DSQUARED HCSQUARED HDRSQUARED HI-RESSQ" +
"UARED LOSSLESSSQUARED SHVSQUARED UHDSQUARED VODMASK WORK SYMBOLREGIONAL " +
"INDICATOR SYMBOL LETTER AREGIONAL INDICATOR SYMBOL LETTER BREGIONAL INDI" +
"CATOR SYMBOL LETTER CREGIONAL INDICATOR SYMBOL LETTER DREGIONAL INDICATO" +
"R SYMBOL LETTER EREGIONAL INDICATOR SYMBOL LETTER FREGIONAL INDICATOR SY" +
"MBOL LETTER GREGIONAL INDICATOR SYMBOL LETTER HREGIONAL INDICATOR SYMBOL" +
" LETTER IREGIONAL INDICATOR SYMBOL LETTER JREGIONAL INDICATOR SYMBOL LET" +
"TER KREGIONAL INDICATOR SYMBOL LETTER LREGIONAL INDICATOR SYMBOL LETTER " +
"MREGIONAL INDICATOR SYMBOL LETTER NREGIONAL INDICATOR SYMBOL LETTER OREG" +
"IONAL INDICATOR SYMBOL LETTER PREGIONAL INDICATOR SYMBOL LETTER QREGIONA" +
"L INDICATOR SYMBOL LETTER RREGIONAL INDICATOR SYMBOL LETTER SREGIONAL IN" +
"DICATOR SYMBOL LETTER TREGIONAL INDICATOR SYMBOL LETTER UREGIONAL INDICA" +
"TOR SYMBOL LETTER VREGIONAL INDICATOR SYMBOL LETTER WREGIONAL INDICATOR " +
"SYMBOL LETTER XREGIONAL INDICATOR SYMBOL LETTER YREGIONAL INDICATOR SYMB" +
"OL LETTER ZSQUARE HIRAGANA HOKASQUARED KATAKANA KOKOSQUARED KATAKANA SAS" +
"QUARED CJK UNIFIED IDEOGRAPH-624BSQUARED CJK UNIFIED IDEOGRAPH-5B57SQUAR") + ("" +
"ED CJK UNIFIED IDEOGRAPH-53CCSQUARED KATAKANA DESQUARED CJK UNIFIED IDEO" +
"GRAPH-4E8CSQUARED CJK UNIFIED IDEOGRAPH-591ASQUARED CJK UNIFIED IDEOGRAP" +
"H-89E3SQUARED CJK UNIFIED IDEOGRAPH-5929SQUARED CJK UNIFIED IDEOGRAPH-4E" +
"A4SQUARED CJK UNIFIED IDEOGRAPH-6620SQUARED CJK UNIFIED IDEOGRAPH-7121SQ" +
"UARED CJK UNIFIED IDEOGRAPH-6599SQUARED CJK UNIFIED IDEOGRAPH-524DSQUARE" +
"D CJK UNIFIED IDEOGRAPH-5F8CSQUARED CJK UNIFIED IDEOGRAPH-518DSQUARED CJ" +
"K UNIFIED IDEOGRAPH-65B0SQUARED CJK UNIFIED IDEOGRAPH-521DSQUARED CJK UN" +
"IFIED IDEOGRAPH-7D42SQUARED CJK UNIFIED IDEOGRAPH-751FSQUARED CJK UNIFIE" +
"D IDEOGRAPH-8CA9SQUARED CJK UNIFIED IDEOGRAPH-58F0SQUARED CJK UNIFIED ID" +
"EOGRAPH-5439SQUARED CJK UNIFIED IDEOGRAPH-6F14SQUARED CJK UNIFIED IDEOGR" +
"APH-6295SQUARED CJK UNIFIED IDEOGRAPH-6355SQUARED CJK UNIFIED IDEOGRAPH-" +
"4E00SQUARED CJK UNIFIED IDEOGRAPH-4E09SQUARED CJK UNIFIED IDEOGRAPH-904A" +
"SQUARED CJK UNIFIED IDEOGRAPH-5DE6SQUARED CJK UNIFIED IDEOGRAPH-4E2DSQUA" +
"RED CJK UNIFIED IDEOGRAPH-53F3SQUARED CJK UNIFIED IDEOGRAPH-6307SQUARED " +
"CJK UNIFIED IDEOGRAPH-8D70SQUARED CJK UNIFIED IDEOGRAPH-6253SQUARED CJK " +
"UNIFIED IDEOGRAPH-7981SQUARED CJK UNIFIED IDEOGRAPH-7A7ASQUARED CJK UNIF" +
"IED IDEOGRAPH-5408SQUARED CJK UNIFIED IDEOGRAPH-6E80SQUARED CJK UNIFIED " +
"IDEOGRAPH-6709SQUARED CJK UNIFIED IDEOGRAPH-6708SQUARED CJK UNIFIED IDEO" +
"GRAPH-7533SQUARED CJK UNIFIED IDEOGRAPH-5272SQUARED CJK UNIFIED IDEOGRAP" +
"H-55B6SQUARED CJK UNIFIED IDEOGRAPH-914DTORTOISE SHELL BRACKETED CJK UNI" +
"FIED IDEOGRAPH-672CTORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E09TO" +
"RTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E8CTORTOISE SHELL BRACKETE" +
"D CJK UNIFIED IDEOGRAPH-5B89TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRA" +
"PH-70B9TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6253TORTOISE SHELL" +
" BRACKETED CJK UNIFIED IDEOGRAPH-76D7TORTOISE SHELL BRACKETED CJK UNIFIE" +
"D IDEOGRAPH-52DDTORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557CIRCL" +
"ED IDEOGRAPH ADVANTAGECIRCLED IDEOGRAPH ACCEPTROUNDED SYMBOL FOR FUROUND" +
"ED SYMBOL FOR LUROUNDED SYMBOL FOR SHOUROUNDED SYMBOL FOR XIROUNDED SYMB" +
"OL FOR SHUANGXIROUNDED SYMBOL FOR CAICYCLONEFOGGYCLOSED UMBRELLANIGHT WI" +
"TH STARSSUNRISE OVER MOUNTAINSSUNRISECITYSCAPE AT DUSKSUNSET OVER BUILDI" +
"NGSRAINBOWBRIDGE AT NIGHTWATER WAVEVOLCANOMILKY WAYEARTH GLOBE EUROPE-AF" +
"RICAEARTH GLOBE AMERICASEARTH GLOBE ASIA-AUSTRALIAGLOBE WITH MERIDIANSNE" +
"W MOON SYMBOLWAXING CRESCENT MOON SYMBOLFIRST QUARTER MOON SYMBOLWAXING " +
"GIBBOUS MOON SYMBOLFULL MOON SYMBOLWANING GIBBOUS MOON SYMBOLLAST QUARTE" +
"R MOON SYMBOLWANING CRESCENT MOON SYMBOLCRESCENT MOONNEW MOON WITH FACEF" +
"IRST QUARTER MOON WITH FACELAST QUARTER MOON WITH FACEFULL MOON WITH FAC" +
"ESUN WITH FACEGLOWING STARSHOOTING STARTHERMOMETERBLACK DROPLETWHITE SUN" +
"WHITE SUN WITH SMALL CLOUDWHITE SUN BEHIND CLOUDWHITE SUN BEHIND CLOUD W" +
"ITH RAINCLOUD WITH RAINCLOUD WITH SNOWCLOUD WITH LIGHTNINGCLOUD WITH TOR" +
"NADOFOGWIND BLOWING FACEHOT DOGTACOBURRITOCHESTNUTSEEDLINGEVERGREEN TREE" +
"DECIDUOUS TREEPALM TREECACTUSHOT PEPPERTULIPCHERRY BLOSSOMROSEHIBISCUSSU" +
"NFLOWERBLOSSOMEAR OF MAIZEEAR OF RICEHERBFOUR LEAF CLOVERMAPLE LEAFFALLE" +
"N LEAFLEAF FLUTTERING IN WINDMUSHROOMTOMATOAUBERGINEGRAPESMELONWATERMELO" +
"NTANGERINELEMONBANANAPINEAPPLERED APPLEGREEN APPLEPEARPEACHCHERRIESSTRAW" +
"BERRYHAMBURGERSLICE OF PIZZAMEAT ON BONEPOULTRY LEGRICE CRACKERRICE BALL" +
"COOKED RICECURRY AND RICESTEAMING BOWLSPAGHETTIBREADFRENCH FRIESROASTED " +
"SWEET POTATODANGOODENSUSHIFRIED SHRIMPFISH CAKE WITH SWIRL DESIGNSOFT IC" +
"E CREAMSHAVED ICEICE CREAMDOUGHNUTCOOKIECHOCOLATE BARCANDYLOLLIPOPCUSTAR" +
"DHONEY POTSHORTCAKEBENTO BOXPOT OF FOODCOOKINGFORK AND KNIFETEACUP WITHO" +
"UT HANDLESAKE BOTTLE AND CUPWINE GLASSCOCKTAIL GLASSTROPICAL DRINKBEER M" +
"UGCLINKING BEER MUGSBABY BOTTLEFORK AND KNIFE WITH PLATEBOTTLE WITH POPP" +
"ING CORKPOPCORNRIBBONWRAPPED PRESENTBIRTHDAY CAKEJACK-O-LANTERNCHRISTMAS" +
" TREEFATHER CHRISTMASFIREWORKSFIREWORK SPARKLERBALLOONPARTY POPPERCONFET" +
"TI BALLTANABATA TREECROSSED FLAGSPINE DECORATIONJAPANESE DOLLSCARP STREA" +
"MERWIND CHIMEMOON VIEWING CEREMONYSCHOOL SATCHELGRADUATION CAPHEART WITH" +
" TIP ON THE LEFTBOUQUET OF FLOWERSMILITARY MEDALREMINDER RIBBONMUSICAL K" +
"EYBOARD WITH JACKSSTUDIO MICROPHONELEVEL SLIDERCONTROL KNOBSBEAMED ASCEN" +
"DING MUSICAL NOTESBEAMED DESCENDING MUSICAL NOTESFILM FRAMESADMISSION TI" +
"CKETSCAROUSEL HORSEFERRIS WHEELROLLER COASTERFISHING POLE AND FISHMICROP" +
"HONEMOVIE CAMERACINEMAHEADPHONEARTIST PALETTETOP HATCIRCUS TENTTICKETCLA" +
"PPER BOARDPERFORMING ARTSVIDEO GAMEDIRECT HITSLOT MACHINEBILLIARDSGAME D" +
"IEBOWLINGFLOWER PLAYING CARDSMUSICAL NOTEMULTIPLE MUSICAL NOTESSAXOPHONE" +
"GUITARMUSICAL KEYBOARDTRUMPETVIOLINMUSICAL SCORERUNNING SHIRT WITH SASHT" +
"ENNIS RACQUET AND BALLSKI AND SKI BOOTBASKETBALL AND HOOPCHEQUERED FLAGS") + ("" +
"NOWBOARDERRUNNERSURFERSPORTS MEDALTROPHYHORSE RACINGAMERICAN FOOTBALLRUG" +
"BY FOOTBALLSWIMMERWEIGHT LIFTERGOLFERRACING MOTORCYCLERACING CARCRICKET " +
"BAT AND BALLVOLLEYBALLFIELD HOCKEY STICK AND BALLICE HOCKEY STICK AND PU" +
"CKTABLE TENNIS PADDLE AND BALLSNOW CAPPED MOUNTAINCAMPINGBEACH WITH UMBR" +
"ELLABUILDING CONSTRUCTIONHOUSE BUILDINGSCITYSCAPEDERELICT HOUSE BUILDING" +
"CLASSICAL BUILDINGDESERTDESERT ISLANDNATIONAL PARKSTADIUMHOUSE BUILDINGH" +
"OUSE WITH GARDENOFFICE BUILDINGJAPANESE POST OFFICEEUROPEAN POST OFFICEH" +
"OSPITALBANKAUTOMATED TELLER MACHINEHOTELLOVE HOTELCONVENIENCE STORESCHOO" +
"LDEPARTMENT STOREFACTORYIZAKAYA LANTERNJAPANESE CASTLEEUROPEAN CASTLEWHI" +
"TE PENNANTBLACK PENNANTWAVING WHITE FLAGWAVING BLACK FLAGROSETTEBLACK RO" +
"SETTELABELBADMINTON RACQUET AND SHUTTLECOCKBOW AND ARROWAMPHORAEMOJI MOD" +
"IFIER FITZPATRICK TYPE-1-2EMOJI MODIFIER FITZPATRICK TYPE-3EMOJI MODIFIE" +
"R FITZPATRICK TYPE-4EMOJI MODIFIER FITZPATRICK TYPE-5EMOJI MODIFIER FITZ" +
"PATRICK TYPE-6RATMOUSEOXWATER BUFFALOCOWTIGERLEOPARDRABBITCATDRAGONCROCO" +
"DILEWHALESNAILSNAKEHORSERAMGOATSHEEPMONKEYROOSTERCHICKENDOGPIGBOARELEPHA" +
"NTOCTOPUSSPIRAL SHELLBUGANTHONEYBEELADY BEETLEFISHTROPICAL FISHBLOWFISHT" +
"URTLEHATCHING CHICKBABY CHICKFRONT-FACING BABY CHICKBIRDPENGUINKOALAPOOD" +
"LEDROMEDARY CAMELBACTRIAN CAMELDOLPHINMOUSE FACECOW FACETIGER FACERABBIT" +
" FACECAT FACEDRAGON FACESPOUTING WHALEHORSE FACEMONKEY FACEDOG FACEPIG F" +
"ACEFROG FACEHAMSTER FACEWOLF FACEBEAR FACEPANDA FACEPIG NOSEPAW PRINTSCH" +
"IPMUNKEYESEYEEARNOSEMOUTHTONGUEWHITE UP POINTING BACKHAND INDEXWHITE DOW" +
"N POINTING BACKHAND INDEXWHITE LEFT POINTING BACKHAND INDEXWHITE RIGHT P" +
"OINTING BACKHAND INDEXFISTED HAND SIGNWAVING HAND SIGNOK HAND SIGNTHUMBS" +
" UP SIGNTHUMBS DOWN SIGNCLAPPING HANDS SIGNOPEN HANDS SIGNCROWNWOMANS HA" +
"TEYEGLASSESNECKTIET-SHIRTJEANSDRESSKIMONOBIKINIWOMANS CLOTHESPURSEHANDBA" +
"GPOUCHMANS SHOEATHLETIC SHOEHIGH-HEELED SHOEWOMANS SANDALWOMANS BOOTSFOO" +
"TPRINTSBUST IN SILHOUETTEBUSTS IN SILHOUETTEBOYGIRLMANWOMANFAMILYMAN AND" +
" WOMAN HOLDING HANDSTWO MEN HOLDING HANDSTWO WOMEN HOLDING HANDSPOLICE O" +
"FFICERWOMAN WITH BUNNY EARSBRIDE WITH VEILPERSON WITH BLOND HAIRMAN WITH" +
" GUA PI MAOMAN WITH TURBANOLDER MANOLDER WOMANBABYCONSTRUCTION WORKERPRI" +
"NCESSJAPANESE OGREJAPANESE GOBLINGHOSTBABY ANGELEXTRATERRESTRIAL ALIENAL" +
"IEN MONSTERIMPSKULLINFORMATION DESK PERSONGUARDSMANDANCERLIPSTICKNAIL PO" +
"LISHFACE MASSAGEHAIRCUTBARBER POLESYRINGEPILLKISS MARKLOVE LETTERRINGGEM" +
" STONEKISSBOUQUETCOUPLE WITH HEARTWEDDINGBEATING HEARTBROKEN HEARTTWO HE" +
"ARTSSPARKLING HEARTGROWING HEARTHEART WITH ARROWBLUE HEARTGREEN HEARTYEL" +
"LOW HEARTPURPLE HEARTHEART WITH RIBBONREVOLVING HEARTSHEART DECORATIONDI" +
"AMOND SHAPE WITH A DOT INSIDEELECTRIC LIGHT BULBANGER SYMBOLBOMBSLEEPING" +
" SYMBOLCOLLISION SYMBOLSPLASHING SWEAT SYMBOLDROPLETDASH SYMBOLPILE OF P" +
"OOFLEXED BICEPSDIZZY SYMBOLSPEECH BALLOONTHOUGHT BALLOONWHITE FLOWERHUND" +
"RED POINTS SYMBOLMONEY BAGCURRENCY EXCHANGEHEAVY DOLLAR SIGNCREDIT CARDB" +
"ANKNOTE WITH YEN SIGNBANKNOTE WITH DOLLAR SIGNBANKNOTE WITH EURO SIGNBAN" +
"KNOTE WITH POUND SIGNMONEY WITH WINGSCHART WITH UPWARDS TREND AND YEN SI" +
"GNSEATPERSONAL COMPUTERBRIEFCASEMINIDISCFLOPPY DISKOPTICAL DISCDVDFILE F" +
"OLDEROPEN FILE FOLDERPAGE WITH CURLPAGE FACING UPCALENDARTEAR-OFF CALEND" +
"ARCARD INDEXCHART WITH UPWARDS TRENDCHART WITH DOWNWARDS TRENDBAR CHARTC" +
"LIPBOARDPUSHPINROUND PUSHPINPAPERCLIPSTRAIGHT RULERTRIANGULAR RULERBOOKM" +
"ARK TABSLEDGERNOTEBOOKNOTEBOOK WITH DECORATIVE COVERCLOSED BOOKOPEN BOOK" +
"GREEN BOOKBLUE BOOKORANGE BOOKBOOKSNAME BADGESCROLLMEMOTELEPHONE RECEIVE" +
"RPAGERFAX MACHINESATELLITE ANTENNAPUBLIC ADDRESS LOUDSPEAKERCHEERING MEG" +
"APHONEOUTBOX TRAYINBOX TRAYPACKAGEE-MAIL SYMBOLINCOMING ENVELOPEENVELOPE" +
" WITH DOWNWARDS ARROW ABOVECLOSED MAILBOX WITH LOWERED FLAGCLOSED MAILBO" +
"X WITH RAISED FLAGOPEN MAILBOX WITH RAISED FLAGOPEN MAILBOX WITH LOWERED" +
" FLAGPOSTBOXPOSTAL HORNNEWSPAPERMOBILE PHONEMOBILE PHONE WITH RIGHTWARDS" +
" ARROW AT LEFTVIBRATION MODEMOBILE PHONE OFFNO MOBILE PHONESANTENNA WITH" +
" BARSCAMERACAMERA WITH FLASHVIDEO CAMERATELEVISIONRADIOVIDEOCASSETTEFILM" +
" PROJECTORPORTABLE STEREOPRAYER BEADSTWISTED RIGHTWARDS ARROWSCLOCKWISE " +
"RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWSCLOCKWISE RIGHTWARDS AND LEFT" +
"WARDS OPEN CIRCLE ARROWS WITH CIRCLED ONE OVERLAYCLOCKWISE DOWNWARDS AND" +
" UPWARDS OPEN CIRCLE ARROWSANTICLOCKWISE DOWNWARDS AND UPWARDS OPEN CIRC" +
"LE ARROWSLOW BRIGHTNESS SYMBOLHIGH BRIGHTNESS SYMBOLSPEAKER WITH CANCELL" +
"ATION STROKESPEAKERSPEAKER WITH ONE SOUND WAVESPEAKER WITH THREE SOUND W" +
"AVESBATTERYELECTRIC PLUGLEFT-POINTING MAGNIFYING GLASSRIGHT-POINTING MAG" +
"NIFYING GLASSLOCK WITH INK PENCLOSED LOCK WITH KEYKEYLOCKOPEN LOCKBELLBE" +
"LL WITH CANCELLATION STROKEBOOKMARKLINK SYMBOLRADIO BUTTONBACK WITH LEFT") + ("" +
"WARDS ARROW ABOVEEND WITH LEFTWARDS ARROW ABOVEON WITH EXCLAMATION MARK " +
"WITH LEFT RIGHT ARROW ABOVESOON WITH RIGHTWARDS ARROW ABOVETOP WITH UPWA" +
"RDS ARROW ABOVENO ONE UNDER EIGHTEEN SYMBOLKEYCAP TENINPUT SYMBOL FOR LA" +
"TIN CAPITAL LETTERSINPUT SYMBOL FOR LATIN SMALL LETTERSINPUT SYMBOL FOR " +
"NUMBERSINPUT SYMBOL FOR SYMBOLSINPUT SYMBOL FOR LATIN LETTERSFIREELECTRI" +
"C TORCHWRENCHHAMMERNUT AND BOLTHOCHOPISTOLMICROSCOPETELESCOPECRYSTAL BAL" +
"LSIX POINTED STAR WITH MIDDLE DOTJAPANESE SYMBOL FOR BEGINNERTRIDENT EMB" +
"LEMBLACK SQUARE BUTTONWHITE SQUARE BUTTONLARGE RED CIRCLELARGE BLUE CIRC" +
"LELARGE ORANGE DIAMONDLARGE BLUE DIAMONDSMALL ORANGE DIAMONDSMALL BLUE D" +
"IAMONDUP-POINTING RED TRIANGLEDOWN-POINTING RED TRIANGLEUP-POINTING SMAL" +
"L RED TRIANGLEDOWN-POINTING SMALL RED TRIANGLELOWER RIGHT SHADOWED WHITE" +
" CIRCLEUPPER RIGHT SHADOWED WHITE CIRCLECIRCLED CROSS POMMEECROSS POMMEE" +
" WITH HALF-CIRCLE BELOWCROSS POMMEENOTCHED LEFT SEMICIRCLE WITH THREE DO" +
"TSNOTCHED RIGHT SEMICIRCLE WITH THREE DOTSSYMBOL FOR MARKS CHAPTERWHITE " +
"LATIN CROSSHEAVY LATIN CROSSCELTIC CROSSOM SYMBOLDOVE OF PEACEKAABAMOSQU" +
"ESYNAGOGUEMENORAH WITH NINE BRANCHESBOWL OF HYGIEIACLOCK FACE ONE OCLOCK" +
"CLOCK FACE TWO OCLOCKCLOCK FACE THREE OCLOCKCLOCK FACE FOUR OCLOCKCLOCK " +
"FACE FIVE OCLOCKCLOCK FACE SIX OCLOCKCLOCK FACE SEVEN OCLOCKCLOCK FACE E" +
"IGHT OCLOCKCLOCK FACE NINE OCLOCKCLOCK FACE TEN OCLOCKCLOCK FACE ELEVEN " +
"OCLOCKCLOCK FACE TWELVE OCLOCKCLOCK FACE ONE-THIRTYCLOCK FACE TWO-THIRTY" +
"CLOCK FACE THREE-THIRTYCLOCK FACE FOUR-THIRTYCLOCK FACE FIVE-THIRTYCLOCK" +
" FACE SIX-THIRTYCLOCK FACE SEVEN-THIRTYCLOCK FACE EIGHT-THIRTYCLOCK FACE" +
" NINE-THIRTYCLOCK FACE TEN-THIRTYCLOCK FACE ELEVEN-THIRTYCLOCK FACE TWEL" +
"VE-THIRTYRIGHT SPEAKERRIGHT SPEAKER WITH ONE SOUND WAVERIGHT SPEAKER WIT" +
"H THREE SOUND WAVESBULLHORNBULLHORN WITH SOUND WAVESRINGING BELLBOOKCAND" +
"LEMANTELPIECE CLOCKBLACK SKULL AND CROSSBONESNO PIRACYHOLEMAN IN BUSINES" +
"S SUIT LEVITATINGSLEUTH OR SPYDARK SUNGLASSESSPIDERSPIDER WEBJOYSTICKMAN" +
" DANCINGLEFT HAND TELEPHONE RECEIVERTELEPHONE RECEIVER WITH PAGERIGHT HA" +
"ND TELEPHONE RECEIVERWHITE TOUCHTONE TELEPHONEBLACK TOUCHTONE TELEPHONET" +
"ELEPHONE ON TOP OF MODEMCLAMSHELL MOBILE PHONEBACK OF ENVELOPESTAMPED EN" +
"VELOPEENVELOPE WITH LIGHTNINGFLYING ENVELOPEPEN OVER STAMPED ENVELOPELIN" +
"KED PAPERCLIPSBLACK PUSHPINLOWER LEFT PENCILLOWER LEFT BALLPOINT PENLOWE" +
"R LEFT FOUNTAIN PENLOWER LEFT PAINTBRUSHLOWER LEFT CRAYONLEFT WRITING HA" +
"NDTURNED OK HAND SIGNRAISED HAND WITH FINGERS SPLAYEDREVERSED RAISED HAN" +
"D WITH FINGERS SPLAYEDREVERSED THUMBS UP SIGNREVERSED THUMBS DOWN SIGNRE" +
"VERSED VICTORY HANDREVERSED HAND WITH MIDDLE FINGER EXTENDEDRAISED HAND " +
"WITH PART BETWEEN MIDDLE AND RING FINGERSWHITE DOWN POINTING LEFT HAND I" +
"NDEXSIDEWAYS WHITE LEFT POINTING INDEXSIDEWAYS WHITE RIGHT POINTING INDE" +
"XSIDEWAYS BLACK LEFT POINTING INDEXSIDEWAYS BLACK RIGHT POINTING INDEXBL" +
"ACK LEFT POINTING BACKHAND INDEXBLACK RIGHT POINTING BACKHAND INDEXSIDEW" +
"AYS WHITE UP POINTING INDEXSIDEWAYS WHITE DOWN POINTING INDEXSIDEWAYS BL" +
"ACK UP POINTING INDEXSIDEWAYS BLACK DOWN POINTING INDEXBLACK UP POINTING" +
" BACKHAND INDEXBLACK DOWN POINTING BACKHAND INDEXBLACK HEARTDESKTOP COMP" +
"UTERKEYBOARD AND MOUSETHREE NETWORKED COMPUTERSPRINTERPOCKET CALCULATORB" +
"LACK HARD SHELL FLOPPY DISKWHITE HARD SHELL FLOPPY DISKSOFT SHELL FLOPPY" +
" DISKTAPE CARTRIDGEWIRED KEYBOARDONE BUTTON MOUSETWO BUTTON MOUSETHREE B" +
"UTTON MOUSETRACKBALLOLD PERSONAL COMPUTERHARD DISKSCREENPRINTER ICONFAX " +
"ICONOPTICAL DISC ICONDOCUMENT WITH TEXTDOCUMENT WITH TEXT AND PICTUREDOC" +
"UMENT WITH PICTUREFRAME WITH PICTUREFRAME WITH TILESFRAME WITH AN XBLACK" +
" FOLDERFOLDEROPEN FOLDERCARD INDEX DIVIDERSCARD FILE BOXFILE CABINETEMPT" +
"Y NOTEEMPTY NOTE PAGEEMPTY NOTE PADNOTENOTE PAGENOTE PADEMPTY DOCUMENTEM" +
"PTY PAGEEMPTY PAGESDOCUMENTPAGEPAGESWASTEBASKETSPIRAL NOTE PADSPIRAL CAL" +
"ENDAR PADDESKTOP WINDOWMINIMIZEMAXIMIZEOVERLAPCLOCKWISE RIGHT AND LEFT S" +
"EMICIRCLE ARROWSCANCELLATION XINCREASE FONT SIZE SYMBOLDECREASE FONT SIZ" +
"E SYMBOLCOMPRESSIONOLD KEYROLLED-UP NEWSPAPERPAGE WITH CIRCLED TEXTSTOCK" +
" CHARTDAGGER KNIFELIPSSPEAKING HEAD IN SILHOUETTETHREE RAYS ABOVETHREE R" +
"AYS BELOWTHREE RAYS LEFTTHREE RAYS RIGHTLEFT SPEECH BUBBLERIGHT SPEECH B" +
"UBBLETWO SPEECH BUBBLESTHREE SPEECH BUBBLESLEFT THOUGHT BUBBLERIGHT THOU" +
"GHT BUBBLELEFT ANGER BUBBLERIGHT ANGER BUBBLEMOOD BUBBLELIGHTNING MOOD B" +
"UBBLELIGHTNING MOODBALLOT BOX WITH BALLOTBALLOT SCRIPT XBALLOT BOX WITH " +
"SCRIPT XBALLOT BOLD SCRIPT XBALLOT BOX WITH BOLD SCRIPT XLIGHT CHECK MAR" +
"KBALLOT BOX WITH BOLD CHECKWORLD MAPMOUNT FUJITOKYO TOWERSTATUE OF LIBER" +
"TYSILHOUETTE OF JAPANMOYAIGRINNING FACEGRINNING FACE WITH SMILING EYESFA" +
"CE WITH TEARS OF JOYSMILING FACE WITH OPEN MOUTHSMILING FACE WITH OPEN M") + ("" +
"OUTH AND SMILING EYESSMILING FACE WITH OPEN MOUTH AND COLD SWEATSMILING " +
"FACE WITH OPEN MOUTH AND TIGHTLY-CLOSED EYESSMILING FACE WITH HALOSMILIN" +
"G FACE WITH HORNSWINKING FACESMILING FACE WITH SMILING EYESFACE SAVOURIN" +
"G DELICIOUS FOODRELIEVED FACESMILING FACE WITH HEART-SHAPED EYESSMILING " +
"FACE WITH SUNGLASSESSMIRKING FACENEUTRAL FACEEXPRESSIONLESS FACEUNAMUSED" +
" FACEFACE WITH COLD SWEATPENSIVE FACECONFUSED FACECONFOUNDED FACEKISSING" +
" FACEFACE THROWING A KISSKISSING FACE WITH SMILING EYESKISSING FACE WITH" +
" CLOSED EYESFACE WITH STUCK-OUT TONGUEFACE WITH STUCK-OUT TONGUE AND WIN" +
"KING EYEFACE WITH STUCK-OUT TONGUE AND TIGHTLY-CLOSED EYESDISAPPOINTED F" +
"ACEWORRIED FACEANGRY FACEPOUTING FACECRYING FACEPERSEVERING FACEFACE WIT" +
"H LOOK OF TRIUMPHDISAPPOINTED BUT RELIEVED FACEFROWNING FACE WITH OPEN M" +
"OUTHANGUISHED FACEFEARFUL FACEWEARY FACESLEEPY FACETIRED FACEGRIMACING F" +
"ACELOUDLY CRYING FACEFACE WITH OPEN MOUTHHUSHED FACEFACE WITH OPEN MOUTH" +
" AND COLD SWEATFACE SCREAMING IN FEARASTONISHED FACEFLUSHED FACESLEEPING" +
" FACEDIZZY FACEFACE WITHOUT MOUTHFACE WITH MEDICAL MASKGRINNING CAT FACE" +
" WITH SMILING EYESCAT FACE WITH TEARS OF JOYSMILING CAT FACE WITH OPEN M" +
"OUTHSMILING CAT FACE WITH HEART-SHAPED EYESCAT FACE WITH WRY SMILEKISSIN" +
"G CAT FACE WITH CLOSED EYESPOUTING CAT FACECRYING CAT FACEWEARY CAT FACE" +
"SLIGHTLY FROWNING FACESLIGHTLY SMILING FACEUPSIDE-DOWN FACEFACE WITH ROL" +
"LING EYESFACE WITH NO GOOD GESTUREFACE WITH OK GESTUREPERSON BOWING DEEP" +
"LYSEE-NO-EVIL MONKEYHEAR-NO-EVIL MONKEYSPEAK-NO-EVIL MONKEYHAPPY PERSON " +
"RAISING ONE HANDPERSON RAISING BOTH HANDS IN CELEBRATIONPERSON FROWNINGP" +
"ERSON WITH POUTING FACEPERSON WITH FOLDED HANDSNORTH WEST POINTING LEAFS" +
"OUTH WEST POINTING LEAFNORTH EAST POINTING LEAFSOUTH EAST POINTING LEAFT" +
"URNED NORTH WEST POINTING LEAFTURNED SOUTH WEST POINTING LEAFTURNED NORT" +
"H EAST POINTING LEAFTURNED SOUTH EAST POINTING LEAFNORTH WEST POINTING V" +
"INE LEAFSOUTH WEST POINTING VINE LEAFNORTH EAST POINTING VINE LEAFSOUTH " +
"EAST POINTING VINE LEAFHEAVY NORTH WEST POINTING VINE LEAFHEAVY SOUTH WE" +
"ST POINTING VINE LEAFHEAVY NORTH EAST POINTING VINE LEAFHEAVY SOUTH EAST" +
" POINTING VINE LEAFNORTH WEST POINTING BUDSOUTH WEST POINTING BUDNORTH E" +
"AST POINTING BUDSOUTH EAST POINTING BUDHEAVY NORTH WEST POINTING BUDHEAV" +
"Y SOUTH WEST POINTING BUDHEAVY NORTH EAST POINTING BUDHEAVY SOUTH EAST P" +
"OINTING BUDHOLLOW QUILT SQUARE ORNAMENTHOLLOW QUILT SQUARE ORNAMENT IN B" +
"LACK SQUARESOLID QUILT SQUARE ORNAMENTSOLID QUILT SQUARE ORNAMENT IN BLA" +
"CK SQUARELEFTWARDS ROCKETUPWARDS ROCKETRIGHTWARDS ROCKETDOWNWARDS ROCKET" +
"SCRIPT LIGATURE ET ORNAMENTHEAVY SCRIPT LIGATURE ET ORNAMENTLIGATURE OPE" +
"N ET ORNAMENTHEAVY LIGATURE OPEN ET ORNAMENTHEAVY AMPERSAND ORNAMENTSWAS" +
"H AMPERSAND ORNAMENTSANS-SERIF HEAVY DOUBLE TURNED COMMA QUOTATION MARK " +
"ORNAMENTSANS-SERIF HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENTSANS-SERIF " +
"HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENTHEAVY INTERROBANG ORNAMENT" +
"SANS-SERIF INTERROBANG ORNAMENTHEAVY SANS-SERIF INTERROBANG ORNAMENTVERY" +
" HEAVY SOLIDUSVERY HEAVY REVERSE SOLIDUSCHECKER BOARDREVERSE CHECKER BOA" +
"RDROCKETHELICOPTERSTEAM LOCOMOTIVERAILWAY CARHIGH-SPEED TRAINHIGH-SPEED " +
"TRAIN WITH BULLET NOSETRAINMETROLIGHT RAILSTATIONTRAMTRAM CARBUSONCOMING" +
" BUSTROLLEYBUSBUS STOPMINIBUSAMBULANCEFIRE ENGINEPOLICE CARONCOMING POLI" +
"CE CARTAXIONCOMING TAXIAUTOMOBILEONCOMING AUTOMOBILERECREATIONAL VEHICLE" +
"DELIVERY TRUCKARTICULATED LORRYTRACTORMONORAILMOUNTAIN RAILWAYSUSPENSION" +
" RAILWAYMOUNTAIN CABLEWAYAERIAL TRAMWAYSHIPROWBOATSPEEDBOATHORIZONTAL TR" +
"AFFIC LIGHTVERTICAL TRAFFIC LIGHTCONSTRUCTION SIGNPOLICE CARS REVOLVING " +
"LIGHTTRIANGULAR FLAG ON POSTDOORNO ENTRY SIGNSMOKING SYMBOLNO SMOKING SY" +
"MBOLPUT LITTER IN ITS PLACE SYMBOLDO NOT LITTER SYMBOLPOTABLE WATER SYMB" +
"OLNON-POTABLE WATER SYMBOLBICYCLENO BICYCLESBICYCLISTMOUNTAIN BICYCLISTP" +
"EDESTRIANNO PEDESTRIANSCHILDREN CROSSINGMENS SYMBOLWOMENS SYMBOLRESTROOM" +
"BABY SYMBOLTOILETWATER CLOSETSHOWERBATHBATHTUBPASSPORT CONTROLCUSTOMSBAG" +
"GAGE CLAIMLEFT LUGGAGETRIANGLE WITH ROUNDED CORNERSPROHIBITED SIGNCIRCLE" +
"D INFORMATION SOURCEBOYS SYMBOLGIRLS SYMBOLCOUCH AND LAMPSLEEPING ACCOMM" +
"ODATIONSHOPPING BAGSBELLHOP BELLBEDPLACE OF WORSHIPOCTAGONAL SIGNSHOPPIN" +
"G TROLLEYSTUPAPAGODAHINDU TEMPLEHUTELEVATORWIRELESSPLAYGROUND SLIDEWHEEL" +
"RING BUOYHAMMER AND WRENCHSHIELDOIL DRUMMOTORWAYRAILWAY TRACKMOTOR BOATU" +
"P-POINTING MILITARY AIRPLANEUP-POINTING AIRPLANEUP-POINTING SMALL AIRPLA" +
"NESMALL AIRPLANENORTHEAST-POINTING AIRPLANEAIRPLANE DEPARTUREAIRPLANE AR" +
"RIVINGSATELLITEONCOMING FIRE ENGINEDIESEL LOCOMOTIVEPASSENGER SHIPSCOOTE" +
"RMOTOR SCOOTERCANOESLEDFLYING SAUCERSKATEBOARDAUTO RICKSHAWPICKUP TRUCKR" +
"OLLER SKATEALCHEMICAL SYMBOL FOR QUINTESSENCEALCHEMICAL SYMBOL FOR AIRAL") + ("" +
"CHEMICAL SYMBOL FOR FIREALCHEMICAL SYMBOL FOR EARTHALCHEMICAL SYMBOL FOR" +
" WATERALCHEMICAL SYMBOL FOR AQUAFORTISALCHEMICAL SYMBOL FOR AQUA REGIAAL" +
"CHEMICAL SYMBOL FOR AQUA REGIA-2ALCHEMICAL SYMBOL FOR AQUA VITAEALCHEMIC" +
"AL SYMBOL FOR AQUA VITAE-2ALCHEMICAL SYMBOL FOR VINEGARALCHEMICAL SYMBOL" +
" FOR VINEGAR-2ALCHEMICAL SYMBOL FOR VINEGAR-3ALCHEMICAL SYMBOL FOR SULFU" +
"RALCHEMICAL SYMBOL FOR PHILOSOPHERS SULFURALCHEMICAL SYMBOL FOR BLACK SU" +
"LFURALCHEMICAL SYMBOL FOR MERCURY SUBLIMATEALCHEMICAL SYMBOL FOR MERCURY" +
" SUBLIMATE-2ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE-3ALCHEMICAL SYMBOL F" +
"OR CINNABARALCHEMICAL SYMBOL FOR SALTALCHEMICAL SYMBOL FOR NITREALCHEMIC" +
"AL SYMBOL FOR VITRIOLALCHEMICAL SYMBOL FOR VITRIOL-2ALCHEMICAL SYMBOL FO" +
"R ROCK SALTALCHEMICAL SYMBOL FOR ROCK SALT-2ALCHEMICAL SYMBOL FOR GOLDAL" +
"CHEMICAL SYMBOL FOR SILVERALCHEMICAL SYMBOL FOR IRON OREALCHEMICAL SYMBO" +
"L FOR IRON ORE-2ALCHEMICAL SYMBOL FOR CROCUS OF IRONALCHEMICAL SYMBOL FO" +
"R REGULUS OF IRONALCHEMICAL SYMBOL FOR COPPER OREALCHEMICAL SYMBOL FOR I" +
"RON-COPPER OREALCHEMICAL SYMBOL FOR SUBLIMATE OF COPPERALCHEMICAL SYMBOL" +
" FOR CROCUS OF COPPERALCHEMICAL SYMBOL FOR CROCUS OF COPPER-2ALCHEMICAL " +
"SYMBOL FOR COPPER ANTIMONIATEALCHEMICAL SYMBOL FOR SALT OF COPPER ANTIMO" +
"NIATEALCHEMICAL SYMBOL FOR SUBLIMATE OF SALT OF COPPERALCHEMICAL SYMBOL " +
"FOR VERDIGRISALCHEMICAL SYMBOL FOR TIN OREALCHEMICAL SYMBOL FOR LEAD ORE" +
"ALCHEMICAL SYMBOL FOR ANTIMONY OREALCHEMICAL SYMBOL FOR SUBLIMATE OF ANT" +
"IMONYALCHEMICAL SYMBOL FOR SALT OF ANTIMONYALCHEMICAL SYMBOL FOR SUBLIMA" +
"TE OF SALT OF ANTIMONYALCHEMICAL SYMBOL FOR VINEGAR OF ANTIMONYALCHEMICA" +
"L SYMBOL FOR REGULUS OF ANTIMONYALCHEMICAL SYMBOL FOR REGULUS OF ANTIMON" +
"Y-2ALCHEMICAL SYMBOL FOR REGULUSALCHEMICAL SYMBOL FOR REGULUS-2ALCHEMICA" +
"L SYMBOL FOR REGULUS-3ALCHEMICAL SYMBOL FOR REGULUS-4ALCHEMICAL SYMBOL F" +
"OR ALKALIALCHEMICAL SYMBOL FOR ALKALI-2ALCHEMICAL SYMBOL FOR MARCASITEAL" +
"CHEMICAL SYMBOL FOR SAL-AMMONIACALCHEMICAL SYMBOL FOR ARSENICALCHEMICAL " +
"SYMBOL FOR REALGARALCHEMICAL SYMBOL FOR REALGAR-2ALCHEMICAL SYMBOL FOR A" +
"URIPIGMENTALCHEMICAL SYMBOL FOR BISMUTH OREALCHEMICAL SYMBOL FOR TARTARA" +
"LCHEMICAL SYMBOL FOR TARTAR-2ALCHEMICAL SYMBOL FOR QUICK LIMEALCHEMICAL " +
"SYMBOL FOR BORAXALCHEMICAL SYMBOL FOR BORAX-2ALCHEMICAL SYMBOL FOR BORAX" +
"-3ALCHEMICAL SYMBOL FOR ALUMALCHEMICAL SYMBOL FOR OILALCHEMICAL SYMBOL F" +
"OR SPIRITALCHEMICAL SYMBOL FOR TINCTUREALCHEMICAL SYMBOL FOR GUMALCHEMIC" +
"AL SYMBOL FOR WAXALCHEMICAL SYMBOL FOR POWDERALCHEMICAL SYMBOL FOR CALXA" +
"LCHEMICAL SYMBOL FOR TUTTYALCHEMICAL SYMBOL FOR CAPUT MORTUUMALCHEMICAL " +
"SYMBOL FOR SCEPTER OF JOVEALCHEMICAL SYMBOL FOR CADUCEUSALCHEMICAL SYMBO" +
"L FOR TRIDENTALCHEMICAL SYMBOL FOR STARRED TRIDENTALCHEMICAL SYMBOL FOR " +
"LODESTONEALCHEMICAL SYMBOL FOR SOAPALCHEMICAL SYMBOL FOR URINEALCHEMICAL" +
" SYMBOL FOR HORSE DUNGALCHEMICAL SYMBOL FOR ASHESALCHEMICAL SYMBOL FOR P" +
"OT ASHESALCHEMICAL SYMBOL FOR BRICKALCHEMICAL SYMBOL FOR POWDERED BRICKA" +
"LCHEMICAL SYMBOL FOR AMALGAMALCHEMICAL SYMBOL FOR STRATUM SUPER STRATUMA" +
"LCHEMICAL SYMBOL FOR STRATUM SUPER STRATUM-2ALCHEMICAL SYMBOL FOR SUBLIM" +
"ATIONALCHEMICAL SYMBOL FOR PRECIPITATEALCHEMICAL SYMBOL FOR DISTILLALCHE" +
"MICAL SYMBOL FOR DISSOLVEALCHEMICAL SYMBOL FOR DISSOLVE-2ALCHEMICAL SYMB" +
"OL FOR PURIFYALCHEMICAL SYMBOL FOR PUTREFACTIONALCHEMICAL SYMBOL FOR CRU" +
"CIBLEALCHEMICAL SYMBOL FOR CRUCIBLE-2ALCHEMICAL SYMBOL FOR CRUCIBLE-3ALC" +
"HEMICAL SYMBOL FOR CRUCIBLE-4ALCHEMICAL SYMBOL FOR CRUCIBLE-5ALCHEMICAL " +
"SYMBOL FOR ALEMBICALCHEMICAL SYMBOL FOR BATH OF MARYALCHEMICAL SYMBOL FO" +
"R BATH OF VAPOURSALCHEMICAL SYMBOL FOR RETORTALCHEMICAL SYMBOL FOR HOURA" +
"LCHEMICAL SYMBOL FOR NIGHTALCHEMICAL SYMBOL FOR DAY-NIGHTALCHEMICAL SYMB" +
"OL FOR MONTHALCHEMICAL SYMBOL FOR HALF DRAMALCHEMICAL SYMBOL FOR HALF OU" +
"NCELOT OF FORTUNEOCCULTATIONLUNAR ECLIPSEHAUMEAMAKEMAKEGONGGONGQUAOARORC" +
"USBLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLEBLACK UP-POINTING ISOSCELE" +
"S RIGHT TRIANGLEBLACK RIGHT-POINTING ISOSCELES RIGHT TRIANGLEBLACK DOWN-" +
"POINTING ISOSCELES RIGHT TRIANGLEBLACK SLIGHTLY SMALL CIRCLEMEDIUM BOLD " +
"WHITE CIRCLEBOLD WHITE CIRCLEHEAVY WHITE CIRCLEVERY HEAVY WHITE CIRCLEEX" +
"TREMELY HEAVY WHITE CIRCLEWHITE CIRCLE CONTAINING BLACK SMALL CIRCLEROUN" +
"D TARGETBLACK TINY SQUAREBLACK SLIGHTLY SMALL SQUARELIGHT WHITE SQUAREME" +
"DIUM WHITE SQUAREBOLD WHITE SQUAREHEAVY WHITE SQUAREVERY HEAVY WHITE SQU" +
"AREEXTREMELY HEAVY WHITE SQUAREWHITE SQUARE CONTAINING BLACK VERY SMALL " +
"SQUAREWHITE SQUARE CONTAINING BLACK MEDIUM SQUARESQUARE TARGETBLACK TINY" +
" DIAMONDBLACK VERY SMALL DIAMONDBLACK MEDIUM SMALL DIAMONDWHITE DIAMOND " +
"CONTAINING BLACK VERY SMALL DIAMONDWHITE DIAMOND CONTAINING BLACK MEDIUM" +
" DIAMONDDIAMOND TARGETBLACK TINY LOZENGEBLACK VERY SMALL LOZENGEBLACK ME") + ("" +
"DIUM SMALL LOZENGEWHITE LOZENGE CONTAINING BLACK SMALL LOZENGETHIN GREEK" +
" CROSSLIGHT GREEK CROSSMEDIUM GREEK CROSSBOLD GREEK CROSSVERY BOLD GREEK" +
" CROSSVERY HEAVY GREEK CROSSEXTREMELY HEAVY GREEK CROSSTHIN SALTIRELIGHT" +
" SALTIREMEDIUM SALTIREBOLD SALTIREHEAVY SALTIREVERY HEAVY SALTIREEXTREME" +
"LY HEAVY SALTIRELIGHT FIVE SPOKED ASTERISKMEDIUM FIVE SPOKED ASTERISKBOL" +
"D FIVE SPOKED ASTERISKHEAVY FIVE SPOKED ASTERISKVERY HEAVY FIVE SPOKED A" +
"STERISKEXTREMELY HEAVY FIVE SPOKED ASTERISKLIGHT SIX SPOKED ASTERISKMEDI" +
"UM SIX SPOKED ASTERISKBOLD SIX SPOKED ASTERISKHEAVY SIX SPOKED ASTERISKV" +
"ERY HEAVY SIX SPOKED ASTERISKEXTREMELY HEAVY SIX SPOKED ASTERISKLIGHT EI" +
"GHT SPOKED ASTERISKMEDIUM EIGHT SPOKED ASTERISKBOLD EIGHT SPOKED ASTERIS" +
"KHEAVY EIGHT SPOKED ASTERISKVERY HEAVY EIGHT SPOKED ASTERISKLIGHT THREE " +
"POINTED BLACK STARMEDIUM THREE POINTED BLACK STARTHREE POINTED BLACK STA" +
"RMEDIUM THREE POINTED PINWHEEL STARLIGHT FOUR POINTED BLACK STARMEDIUM F" +
"OUR POINTED BLACK STARFOUR POINTED BLACK STARMEDIUM FOUR POINTED PINWHEE" +
"L STARREVERSE LIGHT FOUR POINTED PINWHEEL STARLIGHT FIVE POINTED BLACK S" +
"TARHEAVY FIVE POINTED BLACK STARMEDIUM SIX POINTED BLACK STARHEAVY SIX P" +
"OINTED BLACK STARSIX POINTED PINWHEEL STARMEDIUM EIGHT POINTED BLACK STA" +
"RHEAVY EIGHT POINTED BLACK STARVERY HEAVY EIGHT POINTED BLACK STARHEAVY " +
"EIGHT POINTED PINWHEEL STARLIGHT TWELVE POINTED BLACK STARHEAVY TWELVE P" +
"OINTED BLACK STARHEAVY TWELVE POINTED PINWHEEL STARCIRCLED TRIANGLENEGAT" +
"IVE CIRCLED TRIANGLECIRCLED SQUARENEGATIVE CIRCLED SQUARENINE POINTED WH" +
"ITE STARLARGE ORANGE CIRCLELARGE YELLOW CIRCLELARGE GREEN CIRCLELARGE PU" +
"RPLE CIRCLELARGE BROWN CIRCLELARGE RED SQUARELARGE BLUE SQUARELARGE ORAN" +
"GE SQUARELARGE YELLOW SQUARELARGE GREEN SQUARELARGE PURPLE SQUARELARGE B" +
"ROWN SQUAREHEAVY EQUALS SIGNLEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEA" +
"DUPWARDS ARROW WITH SMALL TRIANGLE ARROWHEADRIGHTWARDS ARROW WITH SMALL " +
"TRIANGLE ARROWHEADDOWNWARDS ARROW WITH SMALL TRIANGLE ARROWHEADLEFTWARDS" +
" ARROW WITH MEDIUM TRIANGLE ARROWHEADUPWARDS ARROW WITH MEDIUM TRIANGLE " +
"ARROWHEADRIGHTWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEADDOWNWARDS ARROW " +
"WITH MEDIUM TRIANGLE ARROWHEADLEFTWARDS ARROW WITH LARGE TRIANGLE ARROWH" +
"EADUPWARDS ARROW WITH LARGE TRIANGLE ARROWHEADRIGHTWARDS ARROW WITH LARG" +
"E TRIANGLE ARROWHEADDOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEADLEFTWAR" +
"DS ARROW WITH SMALL EQUILATERAL ARROWHEADUPWARDS ARROW WITH SMALL EQUILA" +
"TERAL ARROWHEADRIGHTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEADDOWNWARD" +
"S ARROW WITH SMALL EQUILATERAL ARROWHEADLEFTWARDS ARROW WITH EQUILATERAL" +
" ARROWHEADUPWARDS ARROW WITH EQUILATERAL ARROWHEADRIGHTWARDS ARROW WITH " +
"EQUILATERAL ARROWHEADDOWNWARDS ARROW WITH EQUILATERAL ARROWHEADHEAVY LEF" +
"TWARDS ARROW WITH EQUILATERAL ARROWHEADHEAVY UPWARDS ARROW WITH EQUILATE" +
"RAL ARROWHEADHEAVY RIGHTWARDS ARROW WITH EQUILATERAL ARROWHEADHEAVY DOWN" +
"WARDS ARROW WITH EQUILATERAL ARROWHEADHEAVY LEFTWARDS ARROW WITH LARGE E" +
"QUILATERAL ARROWHEADHEAVY UPWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD" +
"HEAVY RIGHTWARDS ARROW WITH LARGE EQUILATERAL ARROWHEADHEAVY DOWNWARDS A" +
"RROW WITH LARGE EQUILATERAL ARROWHEADLEFTWARDS TRIANGLE-HEADED ARROW WIT" +
"H NARROW SHAFTUPWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFTRIGHTWARDS " +
"TRIANGLE-HEADED ARROW WITH NARROW SHAFTDOWNWARDS TRIANGLE-HEADED ARROW W" +
"ITH NARROW SHAFTLEFTWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFTUPWARDS" +
" TRIANGLE-HEADED ARROW WITH MEDIUM SHAFTRIGHTWARDS TRIANGLE-HEADED ARROW" +
" WITH MEDIUM SHAFTDOWNWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFTLEFTW" +
"ARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFTUPWARDS TRIANGLE-HEADED ARROW " +
"WITH BOLD SHAFTRIGHTWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFTDOWNWARDS" +
" TRIANGLE-HEADED ARROW WITH BOLD SHAFTLEFTWARDS TRIANGLE-HEADED ARROW WI" +
"TH HEAVY SHAFTUPWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFTRIGHTWARDS T" +
"RIANGLE-HEADED ARROW WITH HEAVY SHAFTDOWNWARDS TRIANGLE-HEADED ARROW WIT" +
"H HEAVY SHAFTLEFTWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFTUPWARD" +
"S TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFTRIGHTWARDS TRIANGLE-HEADED " +
"ARROW WITH VERY HEAVY SHAFTDOWNWARDS TRIANGLE-HEADED ARROW WITH VERY HEA" +
"VY SHAFTLEFTWARDS FINGER-POST ARROWUPWARDS FINGER-POST ARROWRIGHTWARDS F" +
"INGER-POST ARROWDOWNWARDS FINGER-POST ARROWLEFTWARDS SQUARED ARROWUPWARD" +
"S SQUARED ARROWRIGHTWARDS SQUARED ARROWDOWNWARDS SQUARED ARROWLEFTWARDS " +
"COMPRESSED ARROWUPWARDS COMPRESSED ARROWRIGHTWARDS COMPRESSED ARROWDOWNW" +
"ARDS COMPRESSED ARROWLEFTWARDS HEAVY COMPRESSED ARROWUPWARDS HEAVY COMPR" +
"ESSED ARROWRIGHTWARDS HEAVY COMPRESSED ARROWDOWNWARDS HEAVY COMPRESSED A" +
"RROWLEFTWARDS HEAVY ARROWUPWARDS HEAVY ARROWRIGHTWARDS HEAVY ARROWDOWNWA" +
"RDS HEAVY ARROWLEFTWARDS SANS-SERIF ARROWUPWARDS SANS-SERIF ARROWRIGHTWA") + ("" +
"RDS SANS-SERIF ARROWDOWNWARDS SANS-SERIF ARROWNORTH WEST SANS-SERIF ARRO" +
"WNORTH EAST SANS-SERIF ARROWSOUTH EAST SANS-SERIF ARROWSOUTH WEST SANS-S" +
"ERIF ARROWLEFT RIGHT SANS-SERIF ARROWUP DOWN SANS-SERIF ARROWWIDE-HEADED" +
" LEFTWARDS LIGHT BARB ARROWWIDE-HEADED UPWARDS LIGHT BARB ARROWWIDE-HEAD" +
"ED RIGHTWARDS LIGHT BARB ARROWWIDE-HEADED DOWNWARDS LIGHT BARB ARROWWIDE" +
"-HEADED NORTH WEST LIGHT BARB ARROWWIDE-HEADED NORTH EAST LIGHT BARB ARR" +
"OWWIDE-HEADED SOUTH EAST LIGHT BARB ARROWWIDE-HEADED SOUTH WEST LIGHT BA" +
"RB ARROWWIDE-HEADED LEFTWARDS BARB ARROWWIDE-HEADED UPWARDS BARB ARROWWI" +
"DE-HEADED RIGHTWARDS BARB ARROWWIDE-HEADED DOWNWARDS BARB ARROWWIDE-HEAD" +
"ED NORTH WEST BARB ARROWWIDE-HEADED NORTH EAST BARB ARROWWIDE-HEADED SOU" +
"TH EAST BARB ARROWWIDE-HEADED SOUTH WEST BARB ARROWWIDE-HEADED LEFTWARDS" +
" MEDIUM BARB ARROWWIDE-HEADED UPWARDS MEDIUM BARB ARROWWIDE-HEADED RIGHT" +
"WARDS MEDIUM BARB ARROWWIDE-HEADED DOWNWARDS MEDIUM BARB ARROWWIDE-HEADE" +
"D NORTH WEST MEDIUM BARB ARROWWIDE-HEADED NORTH EAST MEDIUM BARB ARROWWI" +
"DE-HEADED SOUTH EAST MEDIUM BARB ARROWWIDE-HEADED SOUTH WEST MEDIUM BARB" +
" ARROWWIDE-HEADED LEFTWARDS HEAVY BARB ARROWWIDE-HEADED UPWARDS HEAVY BA" +
"RB ARROWWIDE-HEADED RIGHTWARDS HEAVY BARB ARROWWIDE-HEADED DOWNWARDS HEA" +
"VY BARB ARROWWIDE-HEADED NORTH WEST HEAVY BARB ARROWWIDE-HEADED NORTH EA" +
"ST HEAVY BARB ARROWWIDE-HEADED SOUTH EAST HEAVY BARB ARROWWIDE-HEADED SO" +
"UTH WEST HEAVY BARB ARROWWIDE-HEADED LEFTWARDS VERY HEAVY BARB ARROWWIDE" +
"-HEADED UPWARDS VERY HEAVY BARB ARROWWIDE-HEADED RIGHTWARDS VERY HEAVY B" +
"ARB ARROWWIDE-HEADED DOWNWARDS VERY HEAVY BARB ARROWWIDE-HEADED NORTH WE" +
"ST VERY HEAVY BARB ARROWWIDE-HEADED NORTH EAST VERY HEAVY BARB ARROWWIDE" +
"-HEADED SOUTH EAST VERY HEAVY BARB ARROWWIDE-HEADED SOUTH WEST VERY HEAV" +
"Y BARB ARROWLEFTWARDS TRIANGLE ARROWHEADUPWARDS TRIANGLE ARROWHEADRIGHTW" +
"ARDS TRIANGLE ARROWHEADDOWNWARDS TRIANGLE ARROWHEADLEFTWARDS WHITE ARROW" +
" WITHIN TRIANGLE ARROWHEADUPWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEADR" +
"IGHTWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEADDOWNWARDS WHITE ARROW WIT" +
"HIN TRIANGLE ARROWHEADLEFTWARDS ARROW WITH NOTCHED TAILUPWARDS ARROW WIT" +
"H NOTCHED TAILRIGHTWARDS ARROW WITH NOTCHED TAILDOWNWARDS ARROW WITH NOT" +
"CHED TAILHEAVY ARROW SHAFT WIDTH ONEHEAVY ARROW SHAFT WIDTH TWO THIRDSHE" +
"AVY ARROW SHAFT WIDTH ONE HALFHEAVY ARROW SHAFT WIDTH ONE THIRDLEFTWARDS" +
" BOTTOM-SHADED WHITE ARROWRIGHTWARDS BOTTOM SHADED WHITE ARROWLEFTWARDS " +
"TOP SHADED WHITE ARROWRIGHTWARDS TOP SHADED WHITE ARROWLEFTWARDS LEFT-SH" +
"ADED WHITE ARROWRIGHTWARDS RIGHT-SHADED WHITE ARROWLEFTWARDS RIGHT-SHADE" +
"D WHITE ARROWRIGHTWARDS LEFT-SHADED WHITE ARROWLEFTWARDS BACK-TILTED SHA" +
"DOWED WHITE ARROWRIGHTWARDS BACK-TILTED SHADOWED WHITE ARROWLEFTWARDS FR" +
"ONT-TILTED SHADOWED WHITE ARROWRIGHTWARDS FRONT-TILTED SHADOWED WHITE AR" +
"ROWWHITE ARROW SHAFT WIDTH ONEWHITE ARROW SHAFT WIDTH TWO THIRDSARROW PO" +
"INTING UPWARDS THEN NORTH WESTARROW POINTING RIGHTWARDS THEN CURVING SOU" +
"TH WESTCIRCLED CROSS FORMEE WITH FOUR DOTSCIRCLED CROSS FORMEE WITH TWO " +
"DOTSCIRCLED CROSS FORMEELEFT HALF CIRCLE WITH FOUR DOTSLEFT HALF CIRCLE " +
"WITH THREE DOTSLEFT HALF CIRCLE WITH TWO DOTSLEFT HALF CIRCLE WITH DOTLE" +
"FT HALF CIRCLEDOWNWARD FACING HOOKDOWNWARD FACING NOTCHED HOOKDOWNWARD F" +
"ACING HOOK WITH DOTDOWNWARD FACING NOTCHED HOOK WITH DOTPINCHED FINGERSW" +
"HITE HEARTBROWN HEARTPINCHING HANDZIPPER-MOUTH FACEMONEY-MOUTH FACEFACE " +
"WITH THERMOMETERNERD FACETHINKING FACEFACE WITH HEAD-BANDAGEROBOT FACEHU" +
"GGING FACESIGN OF THE HORNSCALL ME HANDRAISED BACK OF HANDLEFT-FACING FI" +
"STRIGHT-FACING FISTHANDSHAKEHAND WITH INDEX AND MIDDLE FINGERS CROSSEDI " +
"LOVE YOU HAND SIGNFACE WITH COWBOY HATCLOWN FACENAUSEATED FACEROLLING ON" +
" THE FLOOR LAUGHINGDROOLING FACELYING FACEFACE PALMSNEEZING FACEFACE WIT" +
"H ONE EYEBROW RAISEDGRINNING FACE WITH STAR EYESGRINNING FACE WITH ONE L" +
"ARGE AND ONE SMALL EYEFACE WITH FINGER COVERING CLOSED LIPSSERIOUS FACE " +
"WITH SYMBOLS COVERING MOUTHSMILING FACE WITH SMILING EYES AND HAND COVER" +
"ING MOUTHFACE WITH OPEN MOUTH VOMITINGSHOCKED FACE WITH EXPLODING HEADPR" +
"EGNANT WOMANBREAST-FEEDINGPALMS UP TOGETHERSELFIEPRINCEMAN IN TUXEDOMOTH" +
"ER CHRISTMASSHRUGPERSON DOING CARTWHEELJUGGLINGFENCERMODERN PENTATHLONWR" +
"ESTLERSWATER POLOHANDBALLDIVING MASKWILTED FLOWERDRUM WITH DRUMSTICKSCLI" +
"NKING GLASSESTUMBLER GLASSSPOONGOAL NETRIFLEFIRST PLACE MEDALSECOND PLAC" +
"E MEDALTHIRD PLACE MEDALBOXING GLOVEMARTIAL ARTS UNIFORMCURLING STONELAC" +
"ROSSE STICK AND BALLSOFTBALLFLYING DISCCROISSANTAVOCADOCUCUMBERBACONPOTA" +
"TOCARROTBAGUETTE BREADGREEN SALADSHALLOW PAN OF FOODSTUFFED FLATBREADEGG" +
"GLASS OF MILKPEANUTSKIWIFRUITPANCAKESDUMPLINGFORTUNE COOKIETAKEOUT BOXCH" +
"OPSTICKSBOWL WITH SPOONCUP WITH STRAWCOCONUTBROCCOLIPIEPRETZELCUT OF MEA") + ("" +
"TSANDWICHCANNED FOODLEAFY GREENMANGOMOON CAKEBAGELSMILING FACE WITH SMIL" +
"ING EYES AND THREE HEARTSYAWNING FACESMILING FACE WITH TEARFACE WITH PAR" +
"TY HORN AND PARTY HATFACE WITH UNEVEN EYES AND WAVY MOUTHOVERHEATED FACE" +
"FREEZING FACENINJADISGUISED FACEFACE HOLDING BACK TEARSFACE WITH PLEADIN" +
"G EYESSARILAB COATGOGGLESHIKING BOOTFLAT SHOECRABLION FACESCORPIONTURKEY" +
"UNICORN FACEEAGLEDUCKBATSHARKOWLFOX FACEBUTTERFLYDEERGORILLALIZARDRHINOC" +
"EROSSHRIMPSQUIDGIRAFFE FACEZEBRA FACEHEDGEHOGSAUROPODT-REXCRICKETKANGARO" +
"OLLAMAPEACOCKHIPPOPOTAMUSPARROTRACCOONLOBSTERMOSQUITOMICROBEBADGERSWANMA" +
"MMOTHDODOSLOTHOTTERORANGUTANSKUNKFLAMINGOOYSTERBEAVERBISONSEALGUIDE DOGP" +
"ROBING CANEEMOJI COMPONENT RED HAIREMOJI COMPONENT CURLY HAIREMOJI COMPO" +
"NENT BALDEMOJI COMPONENT WHITE HAIRBONELEGFOOTTOOTHSUPERHEROSUPERVILLAIN" +
"SAFETY VESTEAR WITH HEARING AIDMOTORIZED WHEELCHAIRMANUAL WHEELCHAIRMECH" +
"ANICAL ARMMECHANICAL LEGCHEESE WEDGECUPCAKESALT SHAKERBEVERAGE BOXGARLIC" +
"ONIONFALAFELWAFFLEBUTTERMATE DRINKICE CUBEBUBBLE TEATROLLSTANDING PERSON" +
"KNEELING PERSONDEAF PERSONFACE WITH MONOCLEADULTCHILDOLDER ADULTBEARDED " +
"PERSONPERSON WITH HEADSCARFPERSON IN STEAMY ROOMPERSON CLIMBINGPERSON IN" +
" LOTUS POSITIONMAGEFAIRYVAMPIREMERPERSONELFGENIEZOMBIEBRAINORANGE HEARTB" +
"ILLED CAPSCARFGLOVESCOATSOCKSRED GIFT ENVELOPEFIRECRACKERJIGSAW PUZZLE P" +
"IECETEST TUBEPETRI DISHDNA DOUBLE HELIXCOMPASSABACUSFIRE EXTINGUISHERTOO" +
"LBOXBRICKMAGNETLUGGAGELOTION BOTTLESPOOL OF THREADBALL OF YARNSAFETY PIN" +
"TEDDY BEARBROOMBASKETROLL OF PAPERBAR OF SOAPSPONGERECEIPTNAZAR AMULETNE" +
"UTRAL CHESS KINGNEUTRAL CHESS QUEENNEUTRAL CHESS ROOKNEUTRAL CHESS BISHO" +
"PNEUTRAL CHESS KNIGHTNEUTRAL CHESS PAWNWHITE CHESS KNIGHT ROTATED FORTY-" +
"FIVE DEGREESBLACK CHESS KNIGHT ROTATED FORTY-FIVE DEGREESNEUTRAL CHESS K" +
"NIGHT ROTATED FORTY-FIVE DEGREESWHITE CHESS KING ROTATED NINETY DEGREESW" +
"HITE CHESS QUEEN ROTATED NINETY DEGREESWHITE CHESS ROOK ROTATED NINETY D" +
"EGREESWHITE CHESS BISHOP ROTATED NINETY DEGREESWHITE CHESS KNIGHT ROTATE" +
"D NINETY DEGREESWHITE CHESS PAWN ROTATED NINETY DEGREESBLACK CHESS KING " +
"ROTATED NINETY DEGREESBLACK CHESS QUEEN ROTATED NINETY DEGREESBLACK CHES" +
"S ROOK ROTATED NINETY DEGREESBLACK CHESS BISHOP ROTATED NINETY DEGREESBL" +
"ACK CHESS KNIGHT ROTATED NINETY DEGREESBLACK CHESS PAWN ROTATED NINETY D" +
"EGREESNEUTRAL CHESS KING ROTATED NINETY DEGREESNEUTRAL CHESS QUEEN ROTAT" +
"ED NINETY DEGREESNEUTRAL CHESS ROOK ROTATED NINETY DEGREESNEUTRAL CHESS " +
"BISHOP ROTATED NINETY DEGREESNEUTRAL CHESS KNIGHT ROTATED NINETY DEGREES" +
"NEUTRAL CHESS PAWN ROTATED NINETY DEGREESWHITE CHESS KNIGHT ROTATED ONE " +
"HUNDRED THIRTY-FIVE DEGREESBLACK CHESS KNIGHT ROTATED ONE HUNDRED THIRTY" +
"-FIVE DEGREESNEUTRAL CHESS KNIGHT ROTATED ONE HUNDRED THIRTY-FIVE DEGREE" +
"SWHITE CHESS TURNED KINGWHITE CHESS TURNED QUEENWHITE CHESS TURNED ROOKW" +
"HITE CHESS TURNED BISHOPWHITE CHESS TURNED KNIGHTWHITE CHESS TURNED PAWN" +
"BLACK CHESS TURNED KINGBLACK CHESS TURNED QUEENBLACK CHESS TURNED ROOKBL" +
"ACK CHESS TURNED BISHOPBLACK CHESS TURNED KNIGHTBLACK CHESS TURNED PAWNN" +
"EUTRAL CHESS TURNED KINGNEUTRAL CHESS TURNED QUEENNEUTRAL CHESS TURNED R" +
"OOKNEUTRAL CHESS TURNED BISHOPNEUTRAL CHESS TURNED KNIGHTNEUTRAL CHESS T" +
"URNED PAWNWHITE CHESS KNIGHT ROTATED TWO HUNDRED TWENTY-FIVE DEGREESBLAC" +
"K CHESS KNIGHT ROTATED TWO HUNDRED TWENTY-FIVE DEGREESNEUTRAL CHESS KNIG" +
"HT ROTATED TWO HUNDRED TWENTY-FIVE DEGREESWHITE CHESS KING ROTATED TWO H" +
"UNDRED SEVENTY DEGREESWHITE CHESS QUEEN ROTATED TWO HUNDRED SEVENTY DEGR" +
"EESWHITE CHESS ROOK ROTATED TWO HUNDRED SEVENTY DEGREESWHITE CHESS BISHO" +
"P ROTATED TWO HUNDRED SEVENTY DEGREESWHITE CHESS KNIGHT ROTATED TWO HUND" +
"RED SEVENTY DEGREESWHITE CHESS PAWN ROTATED TWO HUNDRED SEVENTY DEGREESB" +
"LACK CHESS KING ROTATED TWO HUNDRED SEVENTY DEGREESBLACK CHESS QUEEN ROT" +
"ATED TWO HUNDRED SEVENTY DEGREESBLACK CHESS ROOK ROTATED TWO HUNDRED SEV" +
"ENTY DEGREESBLACK CHESS BISHOP ROTATED TWO HUNDRED SEVENTY DEGREESBLACK " +
"CHESS KNIGHT ROTATED TWO HUNDRED SEVENTY DEGREESBLACK CHESS PAWN ROTATED" +
" TWO HUNDRED SEVENTY DEGREESNEUTRAL CHESS KING ROTATED TWO HUNDRED SEVEN" +
"TY DEGREESNEUTRAL CHESS QUEEN ROTATED TWO HUNDRED SEVENTY DEGREESNEUTRAL" +
" CHESS ROOK ROTATED TWO HUNDRED SEVENTY DEGREESNEUTRAL CHESS BISHOP ROTA" +
"TED TWO HUNDRED SEVENTY DEGREESNEUTRAL CHESS KNIGHT ROTATED TWO HUNDRED " +
"SEVENTY DEGREESNEUTRAL CHESS PAWN ROTATED TWO HUNDRED SEVENTY DEGREESWHI" +
"TE CHESS KNIGHT ROTATED THREE HUNDRED FIFTEEN DEGREESBLACK CHESS KNIGHT " +
"ROTATED THREE HUNDRED FIFTEEN DEGREESNEUTRAL CHESS KNIGHT ROTATED THREE " +
"HUNDRED FIFTEEN DEGREESWHITE CHESS EQUIHOPPERBLACK CHESS EQUIHOPPERNEUTR" +
"AL CHESS EQUIHOPPERWHITE CHESS EQUIHOPPER ROTATED NINETY DEGREESBLACK CH" +
"ESS EQUIHOPPER ROTATED NINETY DEGREESNEUTRAL CHESS EQUIHOPPER ROTATED NI") + ("" +
"NETY DEGREESWHITE CHESS KNIGHT-QUEENWHITE CHESS KNIGHT-ROOKWHITE CHESS K" +
"NIGHT-BISHOPBLACK CHESS KNIGHT-QUEENBLACK CHESS KNIGHT-ROOKBLACK CHESS K" +
"NIGHT-BISHOPXIANGQI RED GENERALXIANGQI RED MANDARINXIANGQI RED ELEPHANTX" +
"IANGQI RED HORSEXIANGQI RED CHARIOTXIANGQI RED CANNONXIANGQI RED SOLDIER" +
"XIANGQI BLACK GENERALXIANGQI BLACK MANDARINXIANGQI BLACK ELEPHANTXIANGQI" +
" BLACK HORSEXIANGQI BLACK CHARIOTXIANGQI BLACK CANNONXIANGQI BLACK SOLDI" +
"ERBALLET SHOESONE-PIECE SWIMSUITBRIEFSSHORTSTHONG SANDALLIGHT BLUE HEART" +
"GREY HEARTPINK HEARTDROP OF BLOODADHESIVE BANDAGESTETHOSCOPEX-RAYCRUTCHY" +
"O-YOKITEPARACHUTEBOOMERANGMAGIC WANDPINATANESTING DOLLSMARACASFLUTERINGE" +
"D PLANETCHAIRRAZORAXEDIYA LAMPBANJOMILITARY HELMETACCORDIONLONG DRUMCOIN" +
"CARPENTRY SAWSCREWDRIVERLADDERHOOKMIRRORWINDOWPLUNGERSEWING NEEDLEKNOTBU" +
"CKETMOUSE TRAPTOOTHBRUSHHEADSTONEPLACARDROCKMIRROR BALLIDENTIFICATION CA" +
"RDLOW BATTERYHAMSAFOLDING HAND FANHAIR PICKKHANDAFLYWORMBEETLECOCKROACHP" +
"OTTED PLANTWOODFEATHERLOTUSCORALEMPTY NESTNEST WITH EGGSHYACINTHJELLYFIS" +
"HWINGGOOSEANATOMICAL HEARTLUNGSPEOPLE HUGGINGPREGNANT MANPREGNANT PERSON" +
"PERSON WITH CROWNMOOSEDONKEYBLUEBERRIESBELL PEPPEROLIVEFLATBREADTAMALEFO" +
"NDUETEAPOTPOURING LIQUIDBEANSJARGINGER ROOTPEA PODMELTING FACESALUTING F" +
"ACEFACE WITH OPEN EYES AND HAND OVER MOUTHFACE WITH PEEKING EYEFACE WITH" +
" DIAGONAL MOUTHDOTTED LINE FACEBITING LIPBUBBLESSHAKING FACEHAND WITH IN" +
"DEX FINGER AND THUMB CROSSEDRIGHTWARDS HANDLEFTWARDS HANDPALM DOWN HANDP" +
"ALM UP HANDINDEX POINTING AT THE VIEWERHEART HANDSLEFTWARDS PUSHING HAND" +
"RIGHTWARDS PUSHING HANDBLOCK SEXTANT-1BLOCK SEXTANT-2BLOCK SEXTANT-12BLO" +
"CK SEXTANT-3BLOCK SEXTANT-13BLOCK SEXTANT-23BLOCK SEXTANT-123BLOCK SEXTA" +
"NT-4BLOCK SEXTANT-14BLOCK SEXTANT-24BLOCK SEXTANT-124BLOCK SEXTANT-34BLO" +
"CK SEXTANT-134BLOCK SEXTANT-234BLOCK SEXTANT-1234BLOCK SEXTANT-5BLOCK SE" +
"XTANT-15BLOCK SEXTANT-25BLOCK SEXTANT-125BLOCK SEXTANT-35BLOCK SEXTANT-2" +
"35BLOCK SEXTANT-1235BLOCK SEXTANT-45BLOCK SEXTANT-145BLOCK SEXTANT-245BL" +
"OCK SEXTANT-1245BLOCK SEXTANT-345BLOCK SEXTANT-1345BLOCK SEXTANT-2345BLO" +
"CK SEXTANT-12345BLOCK SEXTANT-6BLOCK SEXTANT-16BLOCK SEXTANT-26BLOCK SEX" +
"TANT-126BLOCK SEXTANT-36BLOCK SEXTANT-136BLOCK SEXTANT-236BLOCK SEXTANT-" +
"1236BLOCK SEXTANT-46BLOCK SEXTANT-146BLOCK SEXTANT-1246BLOCK SEXTANT-346" +
"BLOCK SEXTANT-1346BLOCK SEXTANT-2346BLOCK SEXTANT-12346BLOCK SEXTANT-56B" +
"LOCK SEXTANT-156BLOCK SEXTANT-256BLOCK SEXTANT-1256BLOCK SEXTANT-356BLOC" +
"K SEXTANT-1356BLOCK SEXTANT-2356BLOCK SEXTANT-12356BLOCK SEXTANT-456BLOC" +
"K SEXTANT-1456BLOCK SEXTANT-2456BLOCK SEXTANT-12456BLOCK SEXTANT-3456BLO" +
"CK SEXTANT-13456BLOCK SEXTANT-23456LOWER LEFT BLOCK DIAGONAL LOWER MIDDL" +
"E LEFT TO LOWER CENTRELOWER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOW" +
"ER RIGHTLOWER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER CENTRELOWER" +
" LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER RIGHTLOWER LEFT BLOCK DI" +
"AGONAL UPPER LEFT TO LOWER CENTRELOWER RIGHT BLOCK DIAGONAL UPPER MIDDLE" +
" LEFT TO UPPER CENTRELOWER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPP" +
"ER RIGHTLOWER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER CENTRELOWE" +
"R RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER RIGHTLOWER RIGHT BLOCK" +
" DIAGONAL LOWER LEFT TO UPPER CENTRELOWER RIGHT BLOCK DIAGONAL LOWER MID" +
"DLE LEFT TO UPPER MIDDLE RIGHTLOWER RIGHT BLOCK DIAGONAL LOWER CENTRE TO" +
" LOWER MIDDLE RIGHTLOWER RIGHT BLOCK DIAGONAL LOWER LEFT TO LOWER MIDDLE" +
" RIGHTLOWER RIGHT BLOCK DIAGONAL LOWER CENTRE TO UPPER MIDDLE RIGHTLOWER" +
" RIGHT BLOCK DIAGONAL LOWER LEFT TO UPPER MIDDLE RIGHTLOWER RIGHT BLOCK " +
"DIAGONAL LOWER CENTRE TO UPPER RIGHTLOWER LEFT BLOCK DIAGONAL UPPER CENT" +
"RE TO UPPER MIDDLE RIGHTLOWER LEFT BLOCK DIAGONAL UPPER LEFT TO UPPER MI" +
"DDLE RIGHTLOWER LEFT BLOCK DIAGONAL UPPER CENTRE TO LOWER MIDDLE RIGHTLO" +
"WER LEFT BLOCK DIAGONAL UPPER LEFT TO LOWER MIDDLE RIGHTLOWER LEFT BLOCK" +
" DIAGONAL UPPER CENTRE TO LOWER RIGHTLOWER LEFT BLOCK DIAGONAL UPPER MID" +
"DLE LEFT TO LOWER MIDDLE RIGHTUPPER RIGHT BLOCK DIAGONAL LOWER MIDDLE LE" +
"FT TO LOWER CENTREUPPER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOWER " +
"RIGHTUPPER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER CENTREUPPER R" +
"IGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER RIGHTUPPER RIGHT BLOCK DI" +
"AGONAL UPPER LEFT TO LOWER CENTREUPPER LEFT BLOCK DIAGONAL UPPER MIDDLE " +
"LEFT TO UPPER CENTREUPPER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPPER" +
" RIGHTUPPER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER CENTREUPPER L" +
"EFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER RIGHTUPPER LEFT BLOCK DIAG" +
"ONAL LOWER LEFT TO UPPER CENTREUPPER LEFT BLOCK DIAGONAL LOWER MIDDLE LE" +
"FT TO UPPER MIDDLE RIGHTUPPER LEFT BLOCK DIAGONAL LOWER CENTRE TO LOWER " +
"MIDDLE RIGHTUPPER LEFT BLOCK DIAGONAL LOWER LEFT TO LOWER MIDDLE RIGHTUP") + ("" +
"PER LEFT BLOCK DIAGONAL LOWER CENTRE TO UPPER MIDDLE RIGHTUPPER LEFT BLO" +
"CK DIAGONAL LOWER LEFT TO UPPER MIDDLE RIGHTUPPER LEFT BLOCK DIAGONAL LO" +
"WER CENTRE TO UPPER RIGHTUPPER RIGHT BLOCK DIAGONAL UPPER CENTRE TO UPPE" +
"R MIDDLE RIGHTUPPER RIGHT BLOCK DIAGONAL UPPER LEFT TO UPPER MIDDLE RIGH" +
"TUPPER RIGHT BLOCK DIAGONAL UPPER CENTRE TO LOWER MIDDLE RIGHTUPPER RIGH" +
"T BLOCK DIAGONAL UPPER LEFT TO LOWER MIDDLE RIGHTUPPER RIGHT BLOCK DIAGO" +
"NAL UPPER CENTRE TO LOWER RIGHTUPPER RIGHT BLOCK DIAGONAL UPPER MIDDLE L" +
"EFT TO LOWER MIDDLE RIGHTUPPER AND RIGHT AND LOWER TRIANGULAR THREE QUAR" +
"TERS BLOCKLEFT AND LOWER AND RIGHT TRIANGULAR THREE QUARTERS BLOCKUPPER " +
"AND LEFT AND LOWER TRIANGULAR THREE QUARTERS BLOCKLEFT AND UPPER AND RIG" +
"HT TRIANGULAR THREE QUARTERS BLOCKLEFT TRIANGULAR ONE QUARTER BLOCKUPPER" +
" TRIANGULAR ONE QUARTER BLOCKRIGHT TRIANGULAR ONE QUARTER BLOCKLOWER TRI" +
"ANGULAR ONE QUARTER BLOCKVERTICAL ONE EIGHTH BLOCK-2VERTICAL ONE EIGHTH " +
"BLOCK-3VERTICAL ONE EIGHTH BLOCK-4VERTICAL ONE EIGHTH BLOCK-5VERTICAL ON" +
"E EIGHTH BLOCK-6VERTICAL ONE EIGHTH BLOCK-7HORIZONTAL ONE EIGHTH BLOCK-2" +
"HORIZONTAL ONE EIGHTH BLOCK-3HORIZONTAL ONE EIGHTH BLOCK-4HORIZONTAL ONE" +
" EIGHTH BLOCK-5HORIZONTAL ONE EIGHTH BLOCK-6HORIZONTAL ONE EIGHTH BLOCK-" +
"7LEFT AND LOWER ONE EIGHTH BLOCKLEFT AND UPPER ONE EIGHTH BLOCKRIGHT AND" +
" UPPER ONE EIGHTH BLOCKRIGHT AND LOWER ONE EIGHTH BLOCKUPPER AND LOWER O" +
"NE EIGHTH BLOCKHORIZONTAL ONE EIGHTH BLOCK-1358UPPER ONE QUARTER BLOCKUP" +
"PER THREE EIGHTHS BLOCKUPPER FIVE EIGHTHS BLOCKUPPER THREE QUARTERS BLOC" +
"KUPPER SEVEN EIGHTHS BLOCKRIGHT ONE QUARTER BLOCKRIGHT THREE EIGHTHS BLO" +
"CKRIGHT FIVE EIGHTHS BLOCKRIGHT THREE QUARTERS BLOCKRIGHT SEVEN EIGHTHS " +
"BLOCKLEFT HALF MEDIUM SHADERIGHT HALF MEDIUM SHADEUPPER HALF MEDIUM SHAD" +
"ELOWER HALF MEDIUM SHADEINVERSE MEDIUM SHADEUPPER HALF BLOCK AND LOWER H" +
"ALF INVERSE MEDIUM SHADEUPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF B" +
"LOCKLEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCKCHECKER BOARD FIL" +
"LINVERSE CHECKER BOARD FILLHEAVY HORIZONTAL FILLUPPER LEFT TO LOWER RIGH" +
"T FILLUPPER RIGHT TO LOWER LEFT FILLUPPER AND LOWER TRIANGULAR HALF BLOC" +
"KLEFT AND RIGHT TRIANGULAR HALF BLOCKUPPER LEFT TRIANGULAR MEDIUM SHADEU" +
"PPER RIGHT TRIANGULAR MEDIUM SHADELOWER RIGHT TRIANGULAR MEDIUM SHADELOW" +
"ER LEFT TRIANGULAR MEDIUM SHADEBOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE " +
"TO MIDDLE LEFTBOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHTBO" +
"X DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO LOWER CENTREBOX DRAWINGS LIGHT " +
"DIAGONAL MIDDLE RIGHT TO LOWER CENTREBOX DRAWINGS LIGHT DIAGONAL UPPER C" +
"ENTRE TO MIDDLE LEFT TO LOWER CENTREBOX DRAWINGS LIGHT DIAGONAL UPPER CE" +
"NTRE TO MIDDLE RIGHT TO LOWER CENTREBOX DRAWINGS LIGHT DIAGONAL MIDDLE L" +
"EFT TO LOWER CENTRE TO MIDDLE RIGHTBOX DRAWINGS LIGHT DIAGONAL MIDDLE LE" +
"FT TO UPPER CENTRE TO MIDDLE RIGHTBOX DRAWINGS LIGHT DIAGONAL UPPER CENT" +
"RE TO MIDDLE LEFT AND MIDDLE RIGHT TO LOWER CENTREBOX DRAWINGS LIGHT DIA" +
"GONAL UPPER CENTRE TO MIDDLE RIGHT AND MIDDLE LEFT TO LOWER CENTREBOX DR" +
"AWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT TO LOWER CENTRE TO MI" +
"DDLE LEFTBOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT TO LOWE" +
"R CENTRE TO MIDDLE RIGHTBOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO UPPER" +
" CENTRE TO MIDDLE RIGHT TO LOWER CENTREBOX DRAWINGS LIGHT DIAGONAL MIDDL" +
"E RIGHT TO UPPER CENTRE TO MIDDLE LEFT TO LOWER CENTREBOX DRAWINGS LIGHT" +
" DIAGONAL DIAMONDBOX DRAWINGS LIGHT HORIZONTAL WITH VERTICAL STROKEARROW" +
"HEAD-SHAPED POINTERINVERSE CHECK MARKLEFT HALF RUNNING MANRIGHT HALF RUN" +
"NING MANINVERSE DOWNWARDS ARROW WITH TIP LEFTWARDSLEFTWARDS ARROW AND UP" +
"PER AND LOWER ONE EIGHTH BLOCKRIGHTWARDS ARROW AND UPPER AND LOWER ONE E" +
"IGHTH BLOCKDOWNWARDS ARROW AND RIGHT ONE EIGHTH BLOCKUPWARDS ARROW AND R" +
"IGHT ONE EIGHTH BLOCKLEFT HALF FOLDERRIGHT HALF FOLDERVOIDED GREEK CROSS" +
"RIGHT OPEN SQUARED DOTNEGATIVE DIAGONAL CROSSNEGATIVE DIAGONAL MIDDLE RI" +
"GHT TO LOWER CENTRENEGATIVE DIAGONAL DIAMONDWHITE HEAVY SALTIRE WITH ROU" +
"NDED CORNERSLEFT THIRD WHITE RIGHT POINTING INDEXMIDDLE THIRD WHITE RIGH" +
"T POINTING INDEXRIGHT THIRD WHITE RIGHT POINTING INDEXNEGATIVE SQUARED Q" +
"UESTION MARKSTICK FIGURESTICK FIGURE WITH ARMS RAISEDSTICK FIGURE LEANIN" +
"G LEFTSTICK FIGURE LEANING RIGHTSTICK FIGURE WITH DRESSWHITE UP-POINTING" +
" CHEVRONSEGMENTED DIGIT ZEROSEGMENTED DIGIT ONESEGMENTED DIGIT TWOSEGMEN" +
"TED DIGIT THREESEGMENTED DIGIT FOURSEGMENTED DIGIT FIVESEGMENTED DIGIT S" +
"IXSEGMENTED DIGIT SEVENSEGMENTED DIGIT EIGHTSEGMENTED DIGIT NINECJK COMP" +
"ATIBILITY IDEOGRAPH-2F800CJK COMPATIBILITY IDEOGRAPH-2F801CJK COMPATIBIL" +
"ITY IDEOGRAPH-2F802CJK COMPATIBILITY IDEOGRAPH-2F803CJK COMPATIBILITY ID" +
"EOGRAPH-2F804CJK COMPATIBILITY IDEOGRAPH-2F805CJK COMPATIBILITY IDEOGRAP") + ("" +
"H-2F806CJK COMPATIBILITY IDEOGRAPH-2F807CJK COMPATIBILITY IDEOGRAPH-2F80" +
"8CJK COMPATIBILITY IDEOGRAPH-2F809CJK COMPATIBILITY IDEOGRAPH-2F80ACJK C" +
"OMPATIBILITY IDEOGRAPH-2F80BCJK COMPATIBILITY IDEOGRAPH-2F80CCJK COMPATI" +
"BILITY IDEOGRAPH-2F80DCJK COMPATIBILITY IDEOGRAPH-2F80ECJK COMPATIBILITY" +
" IDEOGRAPH-2F80FCJK COMPATIBILITY IDEOGRAPH-2F810CJK COMPATIBILITY IDEOG" +
"RAPH-2F811CJK COMPATIBILITY IDEOGRAPH-2F812CJK COMPATIBILITY IDEOGRAPH-2" +
"F813CJK COMPATIBILITY IDEOGRAPH-2F814CJK COMPATIBILITY IDEOGRAPH-2F815CJ" +
"K COMPATIBILITY IDEOGRAPH-2F816CJK COMPATIBILITY IDEOGRAPH-2F817CJK COMP" +
"ATIBILITY IDEOGRAPH-2F818CJK COMPATIBILITY IDEOGRAPH-2F819CJK COMPATIBIL" +
"ITY IDEOGRAPH-2F81ACJK COMPATIBILITY IDEOGRAPH-2F81BCJK COMPATIBILITY ID" +
"EOGRAPH-2F81CCJK COMPATIBILITY IDEOGRAPH-2F81DCJK COMPATIBILITY IDEOGRAP" +
"H-2F81ECJK COMPATIBILITY IDEOGRAPH-2F81FCJK COMPATIBILITY IDEOGRAPH-2F82" +
"0CJK COMPATIBILITY IDEOGRAPH-2F821CJK COMPATIBILITY IDEOGRAPH-2F822CJK C" +
"OMPATIBILITY IDEOGRAPH-2F823CJK COMPATIBILITY IDEOGRAPH-2F824CJK COMPATI" +
"BILITY IDEOGRAPH-2F825CJK COMPATIBILITY IDEOGRAPH-2F826CJK COMPATIBILITY" +
" IDEOGRAPH-2F827CJK COMPATIBILITY IDEOGRAPH-2F828CJK COMPATIBILITY IDEOG" +
"RAPH-2F829CJK COMPATIBILITY IDEOGRAPH-2F82ACJK COMPATIBILITY IDEOGRAPH-2" +
"F82BCJK COMPATIBILITY IDEOGRAPH-2F82CCJK COMPATIBILITY IDEOGRAPH-2F82DCJ" +
"K COMPATIBILITY IDEOGRAPH-2F82ECJK COMPATIBILITY IDEOGRAPH-2F82FCJK COMP" +
"ATIBILITY IDEOGRAPH-2F830CJK COMPATIBILITY IDEOGRAPH-2F831CJK COMPATIBIL" +
"ITY IDEOGRAPH-2F832CJK COMPATIBILITY IDEOGRAPH-2F833CJK COMPATIBILITY ID" +
"EOGRAPH-2F834CJK COMPATIBILITY IDEOGRAPH-2F835CJK COMPATIBILITY IDEOGRAP" +
"H-2F836CJK COMPATIBILITY IDEOGRAPH-2F837CJK COMPATIBILITY IDEOGRAPH-2F83" +
"8CJK COMPATIBILITY IDEOGRAPH-2F839CJK COMPATIBILITY IDEOGRAPH-2F83ACJK C" +
"OMPATIBILITY IDEOGRAPH-2F83BCJK COMPATIBILITY IDEOGRAPH-2F83CCJK COMPATI" +
"BILITY IDEOGRAPH-2F83DCJK COMPATIBILITY IDEOGRAPH-2F83ECJK COMPATIBILITY" +
" IDEOGRAPH-2F83FCJK COMPATIBILITY IDEOGRAPH-2F840CJK COMPATIBILITY IDEOG" +
"RAPH-2F841CJK COMPATIBILITY IDEOGRAPH-2F842CJK COMPATIBILITY IDEOGRAPH-2" +
"F843CJK COMPATIBILITY IDEOGRAPH-2F844CJK COMPATIBILITY IDEOGRAPH-2F845CJ" +
"K COMPATIBILITY IDEOGRAPH-2F846CJK COMPATIBILITY IDEOGRAPH-2F847CJK COMP" +
"ATIBILITY IDEOGRAPH-2F848CJK COMPATIBILITY IDEOGRAPH-2F849CJK COMPATIBIL" +
"ITY IDEOGRAPH-2F84ACJK COMPATIBILITY IDEOGRAPH-2F84BCJK COMPATIBILITY ID" +
"EOGRAPH-2F84CCJK COMPATIBILITY IDEOGRAPH-2F84DCJK COMPATIBILITY IDEOGRAP" +
"H-2F84ECJK COMPATIBILITY IDEOGRAPH-2F84FCJK COMPATIBILITY IDEOGRAPH-2F85" +
"0CJK COMPATIBILITY IDEOGRAPH-2F851CJK COMPATIBILITY IDEOGRAPH-2F852CJK C" +
"OMPATIBILITY IDEOGRAPH-2F853CJK COMPATIBILITY IDEOGRAPH-2F854CJK COMPATI" +
"BILITY IDEOGRAPH-2F855CJK COMPATIBILITY IDEOGRAPH-2F856CJK COMPATIBILITY" +
" IDEOGRAPH-2F857CJK COMPATIBILITY IDEOGRAPH-2F858CJK COMPATIBILITY IDEOG" +
"RAPH-2F859CJK COMPATIBILITY IDEOGRAPH-2F85ACJK COMPATIBILITY IDEOGRAPH-2" +
"F85BCJK COMPATIBILITY IDEOGRAPH-2F85CCJK COMPATIBILITY IDEOGRAPH-2F85DCJ" +
"K COMPATIBILITY IDEOGRAPH-2F85ECJK COMPATIBILITY IDEOGRAPH-2F85FCJK COMP" +
"ATIBILITY IDEOGRAPH-2F860CJK COMPATIBILITY IDEOGRAPH-2F861CJK COMPATIBIL" +
"ITY IDEOGRAPH-2F862CJK COMPATIBILITY IDEOGRAPH-2F863CJK COMPATIBILITY ID" +
"EOGRAPH-2F864CJK COMPATIBILITY IDEOGRAPH-2F865CJK COMPATIBILITY IDEOGRAP" +
"H-2F866CJK COMPATIBILITY IDEOGRAPH-2F867CJK COMPATIBILITY IDEOGRAPH-2F86" +
"8CJK COMPATIBILITY IDEOGRAPH-2F869CJK COMPATIBILITY IDEOGRAPH-2F86ACJK C" +
"OMPATIBILITY IDEOGRAPH-2F86BCJK COMPATIBILITY IDEOGRAPH-2F86CCJK COMPATI" +
"BILITY IDEOGRAPH-2F86DCJK COMPATIBILITY IDEOGRAPH-2F86ECJK COMPATIBILITY" +
" IDEOGRAPH-2F86FCJK COMPATIBILITY IDEOGRAPH-2F870CJK COMPATIBILITY IDEOG" +
"RAPH-2F871CJK COMPATIBILITY IDEOGRAPH-2F872CJK COMPATIBILITY IDEOGRAPH-2" +
"F873CJK COMPATIBILITY IDEOGRAPH-2F874CJK COMPATIBILITY IDEOGRAPH-2F875CJ" +
"K COMPATIBILITY IDEOGRAPH-2F876CJK COMPATIBILITY IDEOGRAPH-2F877CJK COMP" +
"ATIBILITY IDEOGRAPH-2F878CJK COMPATIBILITY IDEOGRAPH-2F879CJK COMPATIBIL" +
"ITY IDEOGRAPH-2F87ACJK COMPATIBILITY IDEOGRAPH-2F87BCJK COMPATIBILITY ID" +
"EOGRAPH-2F87CCJK COMPATIBILITY IDEOGRAPH-2F87DCJK COMPATIBILITY IDEOGRAP" +
"H-2F87ECJK COMPATIBILITY IDEOGRAPH-2F87FCJK COMPATIBILITY IDEOGRAPH-2F88" +
"0CJK COMPATIBILITY IDEOGRAPH-2F881CJK COMPATIBILITY IDEOGRAPH-2F882CJK C" +
"OMPATIBILITY IDEOGRAPH-2F883CJK COMPATIBILITY IDEOGRAPH-2F884CJK COMPATI" +
"BILITY IDEOGRAPH-2F885CJK COMPATIBILITY IDEOGRAPH-2F886CJK COMPATIBILITY" +
" IDEOGRAPH-2F887CJK COMPATIBILITY IDEOGRAPH-2F888CJK COMPATIBILITY IDEOG" +
"RAPH-2F889CJK COMPATIBILITY IDEOGRAPH-2F88ACJK COMPATIBILITY IDEOGRAPH-2" +
"F88BCJK COMPATIBILITY IDEOGRAPH-2F88CCJK COMPATIBILITY IDEOGRAPH-2F88DCJ" +
"K COMPATIBILITY IDEOGRAPH-2F88ECJK COMPATIBILITY IDEOGRAPH-2F88FCJK COMP" +
"ATIBILITY IDEOGRAPH-2F890CJK COMPATIBILITY IDEOGRAPH-2F891CJK COMPATIBIL") + ("" +
"ITY IDEOGRAPH-2F892CJK COMPATIBILITY IDEOGRAPH-2F893CJK COMPATIBILITY ID" +
"EOGRAPH-2F894CJK COMPATIBILITY IDEOGRAPH-2F895CJK COMPATIBILITY IDEOGRAP" +
"H-2F896CJK COMPATIBILITY IDEOGRAPH-2F897CJK COMPATIBILITY IDEOGRAPH-2F89" +
"8CJK COMPATIBILITY IDEOGRAPH-2F899CJK COMPATIBILITY IDEOGRAPH-2F89ACJK C" +
"OMPATIBILITY IDEOGRAPH-2F89BCJK COMPATIBILITY IDEOGRAPH-2F89CCJK COMPATI" +
"BILITY IDEOGRAPH-2F89DCJK COMPATIBILITY IDEOGRAPH-2F89ECJK COMPATIBILITY" +
" IDEOGRAPH-2F89FCJK COMPATIBILITY IDEOGRAPH-2F8A0CJK COMPATIBILITY IDEOG" +
"RAPH-2F8A1CJK COMPATIBILITY IDEOGRAPH-2F8A2CJK COMPATIBILITY IDEOGRAPH-2" +
"F8A3CJK COMPATIBILITY IDEOGRAPH-2F8A4CJK COMPATIBILITY IDEOGRAPH-2F8A5CJ" +
"K COMPATIBILITY IDEOGRAPH-2F8A6CJK COMPATIBILITY IDEOGRAPH-2F8A7CJK COMP" +
"ATIBILITY IDEOGRAPH-2F8A8CJK COMPATIBILITY IDEOGRAPH-2F8A9CJK COMPATIBIL" +
"ITY IDEOGRAPH-2F8AACJK COMPATIBILITY IDEOGRAPH-2F8ABCJK COMPATIBILITY ID" +
"EOGRAPH-2F8ACCJK COMPATIBILITY IDEOGRAPH-2F8ADCJK COMPATIBILITY IDEOGRAP" +
"H-2F8AECJK COMPATIBILITY IDEOGRAPH-2F8AFCJK COMPATIBILITY IDEOGRAPH-2F8B" +
"0CJK COMPATIBILITY IDEOGRAPH-2F8B1CJK COMPATIBILITY IDEOGRAPH-2F8B2CJK C" +
"OMPATIBILITY IDEOGRAPH-2F8B3CJK COMPATIBILITY IDEOGRAPH-2F8B4CJK COMPATI" +
"BILITY IDEOGRAPH-2F8B5CJK COMPATIBILITY IDEOGRAPH-2F8B6CJK COMPATIBILITY" +
" IDEOGRAPH-2F8B7CJK COMPATIBILITY IDEOGRAPH-2F8B8CJK COMPATIBILITY IDEOG" +
"RAPH-2F8B9CJK COMPATIBILITY IDEOGRAPH-2F8BACJK COMPATIBILITY IDEOGRAPH-2" +
"F8BBCJK COMPATIBILITY IDEOGRAPH-2F8BCCJK COMPATIBILITY IDEOGRAPH-2F8BDCJ" +
"K COMPATIBILITY IDEOGRAPH-2F8BECJK COMPATIBILITY IDEOGRAPH-2F8BFCJK COMP" +
"ATIBILITY IDEOGRAPH-2F8C0CJK COMPATIBILITY IDEOGRAPH-2F8C1CJK COMPATIBIL" +
"ITY IDEOGRAPH-2F8C2CJK COMPATIBILITY IDEOGRAPH-2F8C3CJK COMPATIBILITY ID" +
"EOGRAPH-2F8C4CJK COMPATIBILITY IDEOGRAPH-2F8C5CJK COMPATIBILITY IDEOGRAP" +
"H-2F8C6CJK COMPATIBILITY IDEOGRAPH-2F8C7CJK COMPATIBILITY IDEOGRAPH-2F8C" +
"8CJK COMPATIBILITY IDEOGRAPH-2F8C9CJK COMPATIBILITY IDEOGRAPH-2F8CACJK C" +
"OMPATIBILITY IDEOGRAPH-2F8CBCJK COMPATIBILITY IDEOGRAPH-2F8CCCJK COMPATI" +
"BILITY IDEOGRAPH-2F8CDCJK COMPATIBILITY IDEOGRAPH-2F8CECJK COMPATIBILITY" +
" IDEOGRAPH-2F8CFCJK COMPATIBILITY IDEOGRAPH-2F8D0CJK COMPATIBILITY IDEOG" +
"RAPH-2F8D1CJK COMPATIBILITY IDEOGRAPH-2F8D2CJK COMPATIBILITY IDEOGRAPH-2" +
"F8D3CJK COMPATIBILITY IDEOGRAPH-2F8D4CJK COMPATIBILITY IDEOGRAPH-2F8D5CJ" +
"K COMPATIBILITY IDEOGRAPH-2F8D6CJK COMPATIBILITY IDEOGRAPH-2F8D7CJK COMP" +
"ATIBILITY IDEOGRAPH-2F8D8CJK COMPATIBILITY IDEOGRAPH-2F8D9CJK COMPATIBIL" +
"ITY IDEOGRAPH-2F8DACJK COMPATIBILITY IDEOGRAPH-2F8DBCJK COMPATIBILITY ID" +
"EOGRAPH-2F8DCCJK COMPATIBILITY IDEOGRAPH-2F8DDCJK COMPATIBILITY IDEOGRAP" +
"H-2F8DECJK COMPATIBILITY IDEOGRAPH-2F8DFCJK COMPATIBILITY IDEOGRAPH-2F8E" +
"0CJK COMPATIBILITY IDEOGRAPH-2F8E1CJK COMPATIBILITY IDEOGRAPH-2F8E2CJK C" +
"OMPATIBILITY IDEOGRAPH-2F8E3CJK COMPATIBILITY IDEOGRAPH-2F8E4CJK COMPATI" +
"BILITY IDEOGRAPH-2F8E5CJK COMPATIBILITY IDEOGRAPH-2F8E6CJK COMPATIBILITY" +
" IDEOGRAPH-2F8E7CJK COMPATIBILITY IDEOGRAPH-2F8E8CJK COMPATIBILITY IDEOG" +
"RAPH-2F8E9CJK COMPATIBILITY IDEOGRAPH-2F8EACJK COMPATIBILITY IDEOGRAPH-2" +
"F8EBCJK COMPATIBILITY IDEOGRAPH-2F8ECCJK COMPATIBILITY IDEOGRAPH-2F8EDCJ" +
"K COMPATIBILITY IDEOGRAPH-2F8EECJK COMPATIBILITY IDEOGRAPH-2F8EFCJK COMP" +
"ATIBILITY IDEOGRAPH-2F8F0CJK COMPATIBILITY IDEOGRAPH-2F8F1CJK COMPATIBIL" +
"ITY IDEOGRAPH-2F8F2CJK COMPATIBILITY IDEOGRAPH-2F8F3CJK COMPATIBILITY ID" +
"EOGRAPH-2F8F4CJK COMPATIBILITY IDEOGRAPH-2F8F5CJK COMPATIBILITY IDEOGRAP" +
"H-2F8F6CJK COMPATIBILITY IDEOGRAPH-2F8F7CJK COMPATIBILITY IDEOGRAPH-2F8F" +
"8CJK COMPATIBILITY IDEOGRAPH-2F8F9CJK COMPATIBILITY IDEOGRAPH-2F8FACJK C" +
"OMPATIBILITY IDEOGRAPH-2F8FBCJK COMPATIBILITY IDEOGRAPH-2F8FCCJK COMPATI" +
"BILITY IDEOGRAPH-2F8FDCJK COMPATIBILITY IDEOGRAPH-2F8FECJK COMPATIBILITY" +
" IDEOGRAPH-2F8FFCJK COMPATIBILITY IDEOGRAPH-2F900CJK COMPATIBILITY IDEOG" +
"RAPH-2F901CJK COMPATIBILITY IDEOGRAPH-2F902CJK COMPATIBILITY IDEOGRAPH-2" +
"F903CJK COMPATIBILITY IDEOGRAPH-2F904CJK COMPATIBILITY IDEOGRAPH-2F905CJ" +
"K COMPATIBILITY IDEOGRAPH-2F906CJK COMPATIBILITY IDEOGRAPH-2F907CJK COMP" +
"ATIBILITY IDEOGRAPH-2F908CJK COMPATIBILITY IDEOGRAPH-2F909CJK COMPATIBIL" +
"ITY IDEOGRAPH-2F90ACJK COMPATIBILITY IDEOGRAPH-2F90BCJK COMPATIBILITY ID" +
"EOGRAPH-2F90CCJK COMPATIBILITY IDEOGRAPH-2F90DCJK COMPATIBILITY IDEOGRAP" +
"H-2F90ECJK COMPATIBILITY IDEOGRAPH-2F90FCJK COMPATIBILITY IDEOGRAPH-2F91" +
"0CJK COMPATIBILITY IDEOGRAPH-2F911CJK COMPATIBILITY IDEOGRAPH-2F912CJK C" +
"OMPATIBILITY IDEOGRAPH-2F913CJK COMPATIBILITY IDEOGRAPH-2F914CJK COMPATI" +
"BILITY IDEOGRAPH-2F915CJK COMPATIBILITY IDEOGRAPH-2F916CJK COMPATIBILITY" +
" IDEOGRAPH-2F917CJK COMPATIBILITY IDEOGRAPH-2F918CJK COMPATIBILITY IDEOG" +
"RAPH-2F919CJK COMPATIBILITY IDEOGRAPH-2F91ACJK COMPATIBILITY IDEOGRAPH-2" +
"F91BCJK COMPATIBILITY IDEOGRAPH-2F91CCJK COMPATIBILITY IDEOGRAPH-2F91DCJ") + ("" +
"K COMPATIBILITY IDEOGRAPH-2F91ECJK COMPATIBILITY IDEOGRAPH-2F91FCJK COMP" +
"ATIBILITY IDEOGRAPH-2F920CJK COMPATIBILITY IDEOGRAPH-2F921CJK COMPATIBIL" +
"ITY IDEOGRAPH-2F922CJK COMPATIBILITY IDEOGRAPH-2F923CJK COMPATIBILITY ID" +
"EOGRAPH-2F924CJK COMPATIBILITY IDEOGRAPH-2F925CJK COMPATIBILITY IDEOGRAP" +
"H-2F926CJK COMPATIBILITY IDEOGRAPH-2F927CJK COMPATIBILITY IDEOGRAPH-2F92" +
"8CJK COMPATIBILITY IDEOGRAPH-2F929CJK COMPATIBILITY IDEOGRAPH-2F92ACJK C" +
"OMPATIBILITY IDEOGRAPH-2F92BCJK COMPATIBILITY IDEOGRAPH-2F92CCJK COMPATI" +
"BILITY IDEOGRAPH-2F92DCJK COMPATIBILITY IDEOGRAPH-2F92ECJK COMPATIBILITY" +
" IDEOGRAPH-2F92FCJK COMPATIBILITY IDEOGRAPH-2F930CJK COMPATIBILITY IDEOG" +
"RAPH-2F931CJK COMPATIBILITY IDEOGRAPH-2F932CJK COMPATIBILITY IDEOGRAPH-2" +
"F933CJK COMPATIBILITY IDEOGRAPH-2F934CJK COMPATIBILITY IDEOGRAPH-2F935CJ" +
"K COMPATIBILITY IDEOGRAPH-2F936CJK COMPATIBILITY IDEOGRAPH-2F937CJK COMP" +
"ATIBILITY IDEOGRAPH-2F938CJK COMPATIBILITY IDEOGRAPH-2F939CJK COMPATIBIL" +
"ITY IDEOGRAPH-2F93ACJK COMPATIBILITY IDEOGRAPH-2F93BCJK COMPATIBILITY ID" +
"EOGRAPH-2F93CCJK COMPATIBILITY IDEOGRAPH-2F93DCJK COMPATIBILITY IDEOGRAP" +
"H-2F93ECJK COMPATIBILITY IDEOGRAPH-2F93FCJK COMPATIBILITY IDEOGRAPH-2F94" +
"0CJK COMPATIBILITY IDEOGRAPH-2F941CJK COMPATIBILITY IDEOGRAPH-2F942CJK C" +
"OMPATIBILITY IDEOGRAPH-2F943CJK COMPATIBILITY IDEOGRAPH-2F944CJK COMPATI" +
"BILITY IDEOGRAPH-2F945CJK COMPATIBILITY IDEOGRAPH-2F946CJK COMPATIBILITY" +
" IDEOGRAPH-2F947CJK COMPATIBILITY IDEOGRAPH-2F948CJK COMPATIBILITY IDEOG" +
"RAPH-2F949CJK COMPATIBILITY IDEOGRAPH-2F94ACJK COMPATIBILITY IDEOGRAPH-2" +
"F94BCJK COMPATIBILITY IDEOGRAPH-2F94CCJK COMPATIBILITY IDEOGRAPH-2F94DCJ" +
"K COMPATIBILITY IDEOGRAPH-2F94ECJK COMPATIBILITY IDEOGRAPH-2F94FCJK COMP" +
"ATIBILITY IDEOGRAPH-2F950CJK COMPATIBILITY IDEOGRAPH-2F951CJK COMPATIBIL" +
"ITY IDEOGRAPH-2F952CJK COMPATIBILITY IDEOGRAPH-2F953CJK COMPATIBILITY ID" +
"EOGRAPH-2F954CJK COMPATIBILITY IDEOGRAPH-2F955CJK COMPATIBILITY IDEOGRAP" +
"H-2F956CJK COMPATIBILITY IDEOGRAPH-2F957CJK COMPATIBILITY IDEOGRAPH-2F95" +
"8CJK COMPATIBILITY IDEOGRAPH-2F959CJK COMPATIBILITY IDEOGRAPH-2F95ACJK C" +
"OMPATIBILITY IDEOGRAPH-2F95BCJK COMPATIBILITY IDEOGRAPH-2F95CCJK COMPATI" +
"BILITY IDEOGRAPH-2F95DCJK COMPATIBILITY IDEOGRAPH-2F95ECJK COMPATIBILITY" +
" IDEOGRAPH-2F95FCJK COMPATIBILITY IDEOGRAPH-2F960CJK COMPATIBILITY IDEOG" +
"RAPH-2F961CJK COMPATIBILITY IDEOGRAPH-2F962CJK COMPATIBILITY IDEOGRAPH-2" +
"F963CJK COMPATIBILITY IDEOGRAPH-2F964CJK COMPATIBILITY IDEOGRAPH-2F965CJ" +
"K COMPATIBILITY IDEOGRAPH-2F966CJK COMPATIBILITY IDEOGRAPH-2F967CJK COMP" +
"ATIBILITY IDEOGRAPH-2F968CJK COMPATIBILITY IDEOGRAPH-2F969CJK COMPATIBIL" +
"ITY IDEOGRAPH-2F96ACJK COMPATIBILITY IDEOGRAPH-2F96BCJK COMPATIBILITY ID" +
"EOGRAPH-2F96CCJK COMPATIBILITY IDEOGRAPH-2F96DCJK COMPATIBILITY IDEOGRAP" +
"H-2F96ECJK COMPATIBILITY IDEOGRAPH-2F96FCJK COMPATIBILITY IDEOGRAPH-2F97" +
"0CJK COMPATIBILITY IDEOGRAPH-2F971CJK COMPATIBILITY IDEOGRAPH-2F972CJK C" +
"OMPATIBILITY IDEOGRAPH-2F973CJK COMPATIBILITY IDEOGRAPH-2F974CJK COMPATI" +
"BILITY IDEOGRAPH-2F975CJK COMPATIBILITY IDEOGRAPH-2F976CJK COMPATIBILITY" +
" IDEOGRAPH-2F977CJK COMPATIBILITY IDEOGRAPH-2F978CJK COMPATIBILITY IDEOG" +
"RAPH-2F979CJK COMPATIBILITY IDEOGRAPH-2F97ACJK COMPATIBILITY IDEOGRAPH-2" +
"F97BCJK COMPATIBILITY IDEOGRAPH-2F97CCJK COMPATIBILITY IDEOGRAPH-2F97DCJ" +
"K COMPATIBILITY IDEOGRAPH-2F97ECJK COMPATIBILITY IDEOGRAPH-2F97FCJK COMP" +
"ATIBILITY IDEOGRAPH-2F980CJK COMPATIBILITY IDEOGRAPH-2F981CJK COMPATIBIL" +
"ITY IDEOGRAPH-2F982CJK COMPATIBILITY IDEOGRAPH-2F983CJK COMPATIBILITY ID" +
"EOGRAPH-2F984CJK COMPATIBILITY IDEOGRAPH-2F985CJK COMPATIBILITY IDEOGRAP" +
"H-2F986CJK COMPATIBILITY IDEOGRAPH-2F987CJK COMPATIBILITY IDEOGRAPH-2F98" +
"8CJK COMPATIBILITY IDEOGRAPH-2F989CJK COMPATIBILITY IDEOGRAPH-2F98ACJK C" +
"OMPATIBILITY IDEOGRAPH-2F98BCJK COMPATIBILITY IDEOGRAPH-2F98CCJK COMPATI" +
"BILITY IDEOGRAPH-2F98DCJK COMPATIBILITY IDEOGRAPH-2F98ECJK COMPATIBILITY" +
" IDEOGRAPH-2F98FCJK COMPATIBILITY IDEOGRAPH-2F990CJK COMPATIBILITY IDEOG" +
"RAPH-2F991CJK COMPATIBILITY IDEOGRAPH-2F992CJK COMPATIBILITY IDEOGRAPH-2" +
"F993CJK COMPATIBILITY IDEOGRAPH-2F994CJK COMPATIBILITY IDEOGRAPH-2F995CJ" +
"K COMPATIBILITY IDEOGRAPH-2F996CJK COMPATIBILITY IDEOGRAPH-2F997CJK COMP" +
"ATIBILITY IDEOGRAPH-2F998CJK COMPATIBILITY IDEOGRAPH-2F999CJK COMPATIBIL" +
"ITY IDEOGRAPH-2F99ACJK COMPATIBILITY IDEOGRAPH-2F99BCJK COMPATIBILITY ID" +
"EOGRAPH-2F99CCJK COMPATIBILITY IDEOGRAPH-2F99DCJK COMPATIBILITY IDEOGRAP" +
"H-2F99ECJK COMPATIBILITY IDEOGRAPH-2F99FCJK COMPATIBILITY IDEOGRAPH-2F9A" +
"0CJK COMPATIBILITY IDEOGRAPH-2F9A1CJK COMPATIBILITY IDEOGRAPH-2F9A2CJK C" +
"OMPATIBILITY IDEOGRAPH-2F9A3CJK COMPATIBILITY IDEOGRAPH-2F9A4CJK COMPATI" +
"BILITY IDEOGRAPH-2F9A5CJK COMPATIBILITY IDEOGRAPH-2F9A6CJK COMPATIBILITY" +
" IDEOGRAPH-2F9A7CJK COMPATIBILITY IDEOGRAPH-2F9A8CJK COMPATIBILITY IDEOG") + ("" +
"RAPH-2F9A9CJK COMPATIBILITY IDEOGRAPH-2F9AACJK COMPATIBILITY IDEOGRAPH-2" +
"F9ABCJK COMPATIBILITY IDEOGRAPH-2F9ACCJK COMPATIBILITY IDEOGRAPH-2F9ADCJ" +
"K COMPATIBILITY IDEOGRAPH-2F9AECJK COMPATIBILITY IDEOGRAPH-2F9AFCJK COMP" +
"ATIBILITY IDEOGRAPH-2F9B0CJK COMPATIBILITY IDEOGRAPH-2F9B1CJK COMPATIBIL" +
"ITY IDEOGRAPH-2F9B2CJK COMPATIBILITY IDEOGRAPH-2F9B3CJK COMPATIBILITY ID" +
"EOGRAPH-2F9B4CJK COMPATIBILITY IDEOGRAPH-2F9B5CJK COMPATIBILITY IDEOGRAP" +
"H-2F9B6CJK COMPATIBILITY IDEOGRAPH-2F9B7CJK COMPATIBILITY IDEOGRAPH-2F9B" +
"8CJK COMPATIBILITY IDEOGRAPH-2F9B9CJK COMPATIBILITY IDEOGRAPH-2F9BACJK C" +
"OMPATIBILITY IDEOGRAPH-2F9BBCJK COMPATIBILITY IDEOGRAPH-2F9BCCJK COMPATI" +
"BILITY IDEOGRAPH-2F9BDCJK COMPATIBILITY IDEOGRAPH-2F9BECJK COMPATIBILITY" +
" IDEOGRAPH-2F9BFCJK COMPATIBILITY IDEOGRAPH-2F9C0CJK COMPATIBILITY IDEOG" +
"RAPH-2F9C1CJK COMPATIBILITY IDEOGRAPH-2F9C2CJK COMPATIBILITY IDEOGRAPH-2" +
"F9C3CJK COMPATIBILITY IDEOGRAPH-2F9C4CJK COMPATIBILITY IDEOGRAPH-2F9C5CJ" +
"K COMPATIBILITY IDEOGRAPH-2F9C6CJK COMPATIBILITY IDEOGRAPH-2F9C7CJK COMP" +
"ATIBILITY IDEOGRAPH-2F9C8CJK COMPATIBILITY IDEOGRAPH-2F9C9CJK COMPATIBIL" +
"ITY IDEOGRAPH-2F9CACJK COMPATIBILITY IDEOGRAPH-2F9CBCJK COMPATIBILITY ID" +
"EOGRAPH-2F9CCCJK COMPATIBILITY IDEOGRAPH-2F9CDCJK COMPATIBILITY IDEOGRAP" +
"H-2F9CECJK COMPATIBILITY IDEOGRAPH-2F9CFCJK COMPATIBILITY IDEOGRAPH-2F9D" +
"0CJK COMPATIBILITY IDEOGRAPH-2F9D1CJK COMPATIBILITY IDEOGRAPH-2F9D2CJK C" +
"OMPATIBILITY IDEOGRAPH-2F9D3CJK COMPATIBILITY IDEOGRAPH-2F9D4CJK COMPATI" +
"BILITY IDEOGRAPH-2F9D5CJK COMPATIBILITY IDEOGRAPH-2F9D6CJK COMPATIBILITY" +
" IDEOGRAPH-2F9D7CJK COMPATIBILITY IDEOGRAPH-2F9D8CJK COMPATIBILITY IDEOG" +
"RAPH-2F9D9CJK COMPATIBILITY IDEOGRAPH-2F9DACJK COMPATIBILITY IDEOGRAPH-2" +
"F9DBCJK COMPATIBILITY IDEOGRAPH-2F9DCCJK COMPATIBILITY IDEOGRAPH-2F9DDCJ" +
"K COMPATIBILITY IDEOGRAPH-2F9DECJK COMPATIBILITY IDEOGRAPH-2F9DFCJK COMP" +
"ATIBILITY IDEOGRAPH-2F9E0CJK COMPATIBILITY IDEOGRAPH-2F9E1CJK COMPATIBIL" +
"ITY IDEOGRAPH-2F9E2CJK COMPATIBILITY IDEOGRAPH-2F9E3CJK COMPATIBILITY ID" +
"EOGRAPH-2F9E4CJK COMPATIBILITY IDEOGRAPH-2F9E5CJK COMPATIBILITY IDEOGRAP" +
"H-2F9E6CJK COMPATIBILITY IDEOGRAPH-2F9E7CJK COMPATIBILITY IDEOGRAPH-2F9E" +
"8CJK COMPATIBILITY IDEOGRAPH-2F9E9CJK COMPATIBILITY IDEOGRAPH-2F9EACJK C" +
"OMPATIBILITY IDEOGRAPH-2F9EBCJK COMPATIBILITY IDEOGRAPH-2F9ECCJK COMPATI" +
"BILITY IDEOGRAPH-2F9EDCJK COMPATIBILITY IDEOGRAPH-2F9EECJK COMPATIBILITY" +
" IDEOGRAPH-2F9EFCJK COMPATIBILITY IDEOGRAPH-2F9F0CJK COMPATIBILITY IDEOG" +
"RAPH-2F9F1CJK COMPATIBILITY IDEOGRAPH-2F9F2CJK COMPATIBILITY IDEOGRAPH-2" +
"F9F3CJK COMPATIBILITY IDEOGRAPH-2F9F4CJK COMPATIBILITY IDEOGRAPH-2F9F5CJ" +
"K COMPATIBILITY IDEOGRAPH-2F9F6CJK COMPATIBILITY IDEOGRAPH-2F9F7CJK COMP" +
"ATIBILITY IDEOGRAPH-2F9F8CJK COMPATIBILITY IDEOGRAPH-2F9F9CJK COMPATIBIL" +
"ITY IDEOGRAPH-2F9FACJK COMPATIBILITY IDEOGRAPH-2F9FBCJK COMPATIBILITY ID" +
"EOGRAPH-2F9FCCJK COMPATIBILITY IDEOGRAPH-2F9FDCJK COMPATIBILITY IDEOGRAP" +
"H-2F9FECJK COMPATIBILITY IDEOGRAPH-2F9FFCJK COMPATIBILITY IDEOGRAPH-2FA0" +
"0CJK COMPATIBILITY IDEOGRAPH-2FA01CJK COMPATIBILITY IDEOGRAPH-2FA02CJK C" +
"OMPATIBILITY IDEOGRAPH-2FA03CJK COMPATIBILITY IDEOGRAPH-2FA04CJK COMPATI" +
"BILITY IDEOGRAPH-2FA05CJK COMPATIBILITY IDEOGRAPH-2FA06CJK COMPATIBILITY" +
" IDEOGRAPH-2FA07CJK COMPATIBILITY IDEOGRAPH-2FA08CJK COMPATIBILITY IDEOG" +
"RAPH-2FA09CJK COMPATIBILITY IDEOGRAPH-2FA0ACJK COMPATIBILITY IDEOGRAPH-2" +
"FA0BCJK COMPATIBILITY IDEOGRAPH-2FA0CCJK COMPATIBILITY IDEOGRAPH-2FA0DCJ" +
"K COMPATIBILITY IDEOGRAPH-2FA0ECJK COMPATIBILITY IDEOGRAPH-2FA0FCJK COMP" +
"ATIBILITY IDEOGRAPH-2FA10CJK COMPATIBILITY IDEOGRAPH-2FA11CJK COMPATIBIL" +
"ITY IDEOGRAPH-2FA12CJK COMPATIBILITY IDEOGRAPH-2FA13CJK COMPATIBILITY ID" +
"EOGRAPH-2FA14CJK COMPATIBILITY IDEOGRAPH-2FA15CJK COMPATIBILITY IDEOGRAP" +
"H-2FA16CJK COMPATIBILITY IDEOGRAPH-2FA17CJK COMPATIBILITY IDEOGRAPH-2FA1" +
"8CJK COMPATIBILITY IDEOGRAPH-2FA19CJK COMPATIBILITY IDEOGRAPH-2FA1ACJK C" +
"OMPATIBILITY IDEOGRAPH-2FA1BCJK COMPATIBILITY IDEOGRAPH-2FA1CCJK COMPATI" +
"BILITY IDEOGRAPH-2FA1DLANGUAGE TAGTAG SPACETAG EXCLAMATION MARKTAG QUOTA" +
"TION MARKTAG NUMBER SIGNTAG DOLLAR SIGNTAG PERCENT SIGNTAG AMPERSANDTAG " +
"APOSTROPHETAG LEFT PARENTHESISTAG RIGHT PARENTHESISTAG ASTERISKTAG PLUS " +
"SIGNTAG COMMATAG HYPHEN-MINUSTAG FULL STOPTAG SOLIDUSTAG DIGIT ZEROTAG D" +
"IGIT ONETAG DIGIT TWOTAG DIGIT THREETAG DIGIT FOURTAG DIGIT FIVETAG DIGI" +
"T SIXTAG DIGIT SEVENTAG DIGIT EIGHTTAG DIGIT NINETAG COLONTAG SEMICOLONT" +
"AG LESS-THAN SIGNTAG EQUALS SIGNTAG GREATER-THAN SIGNTAG QUESTION MARKTA" +
"G COMMERCIAL ATTAG LATIN CAPITAL LETTER ATAG LATIN CAPITAL LETTER BTAG L" +
"ATIN CAPITAL LETTER CTAG LATIN CAPITAL LETTER DTAG LATIN CAPITAL LETTER " +
"ETAG LATIN CAPITAL LETTER FTAG LATIN CAPITAL LETTER GTAG LATIN CAPITAL L" +
"ETTER HTAG LATIN CAPITAL LETTER ITAG LATIN CAPITAL LETTER JTAG LATIN CAP") + ("" +
"ITAL LETTER KTAG LATIN CAPITAL LETTER LTAG LATIN CAPITAL LETTER MTAG LAT" +
"IN CAPITAL LETTER NTAG LATIN CAPITAL LETTER OTAG LATIN CAPITAL LETTER PT" +
"AG LATIN CAPITAL LETTER QTAG LATIN CAPITAL LETTER RTAG LATIN CAPITAL LET" +
"TER STAG LATIN CAPITAL LETTER TTAG LATIN CAPITAL LETTER UTAG LATIN CAPIT" +
"AL LETTER VTAG LATIN CAPITAL LETTER WTAG LATIN CAPITAL LETTER XTAG LATIN" +
" CAPITAL LETTER YTAG LATIN CAPITAL LETTER ZTAG LEFT SQUARE BRACKETTAG RE" +
"VERSE SOLIDUSTAG RIGHT SQUARE BRACKETTAG CIRCUMFLEX ACCENTTAG LOW LINETA" +
"G GRAVE ACCENTTAG LATIN SMALL LETTER ATAG LATIN SMALL LETTER BTAG LATIN " +
"SMALL LETTER CTAG LATIN SMALL LETTER DTAG LATIN SMALL LETTER ETAG LATIN " +
"SMALL LETTER FTAG LATIN SMALL LETTER GTAG LATIN SMALL LETTER HTAG LATIN " +
"SMALL LETTER ITAG LATIN SMALL LETTER JTAG LATIN SMALL LETTER KTAG LATIN " +
"SMALL LETTER LTAG LATIN SMALL LETTER MTAG LATIN SMALL LETTER NTAG LATIN " +
"SMALL LETTER OTAG LATIN SMALL LETTER PTAG LATIN SMALL LETTER QTAG LATIN " +
"SMALL LETTER RTAG LATIN SMALL LETTER STAG LATIN SMALL LETTER TTAG LATIN " +
"SMALL LETTER UTAG LATIN SMALL LETTER VTAG LATIN SMALL LETTER WTAG LATIN " +
"SMALL LETTER XTAG LATIN SMALL LETTER YTAG LATIN SMALL LETTER ZTAG LEFT C" +
"URLY BRACKETTAG VERTICAL LINETAG RIGHT CURLY BRACKETTAG TILDECANCEL TAGV" +
"ARIATION SELECTOR-17VARIATION SELECTOR-18VARIATION SELECTOR-19VARIATION " +
"SELECTOR-20VARIATION SELECTOR-21VARIATION SELECTOR-22VARIATION SELECTOR-" +
"23VARIATION SELECTOR-24VARIATION SELECTOR-25VARIATION SELECTOR-26VARIATI" +
"ON SELECTOR-27VARIATION SELECTOR-28VARIATION SELECTOR-29VARIATION SELECT" +
"OR-30VARIATION SELECTOR-31VARIATION SELECTOR-32VARIATION SELECTOR-33VARI" +
"ATION SELECTOR-34VARIATION SELECTOR-35VARIATION SELECTOR-36VARIATION SEL" +
"ECTOR-37VARIATION SELECTOR-38VARIATION SELECTOR-39VARIATION SELECTOR-40V" +
"ARIATION SELECTOR-41VARIATION SELECTOR-42VARIATION SELECTOR-43VARIATION " +
"SELECTOR-44VARIATION SELECTOR-45VARIATION SELECTOR-46VARIATION SELECTOR-" +
"47VARIATION SELECTOR-48VARIATION SELECTOR-49VARIATION SELECTOR-50VARIATI" +
"ON SELECTOR-51VARIATION SELECTOR-52VARIATION SELECTOR-53VARIATION SELECT" +
"OR-54VARIATION SELECTOR-55VARIATION SELECTOR-56VARIATION SELECTOR-57VARI" +
"ATION SELECTOR-58VARIATION SELECTOR-59VARIATION SELECTOR-60VARIATION SEL" +
"ECTOR-61VARIATION SELECTOR-62VARIATION SELECTOR-63VARIATION SELECTOR-64V" +
"ARIATION SELECTOR-65VARIATION SELECTOR-66VARIATION SELECTOR-67VARIATION " +
"SELECTOR-68VARIATION SELECTOR-69VARIATION SELECTOR-70VARIATION SELECTOR-" +
"71VARIATION SELECTOR-72VARIATION SELECTOR-73VARIATION SELECTOR-74VARIATI" +
"ON SELECTOR-75VARIATION SELECTOR-76VARIATION SELECTOR-77VARIATION SELECT" +
"OR-78VARIATION SELECTOR-79VARIATION SELECTOR-80VARIATION SELECTOR-81VARI" +
"ATION SELECTOR-82VARIATION SELECTOR-83VARIATION SELECTOR-84VARIATION SEL" +
"ECTOR-85VARIATION SELECTOR-86VARIATION SELECTOR-87VARIATION SELECTOR-88V" +
"ARIATION SELECTOR-89VARIATION SELECTOR-90VARIATION SELECTOR-91VARIATION " +
"SELECTOR-92VARIATION SELECTOR-93VARIATION SELECTOR-94VARIATION SELECTOR-" +
"95VARIATION SELECTOR-96VARIATION SELECTOR-97VARIATION SELECTOR-98VARIATI" +
"ON SELECTOR-99VARIATION SELECTOR-100VARIATION SELECTOR-101VARIATION SELE" +
"CTOR-102VARIATION SELECTOR-103VARIATION SELECTOR-104VARIATION SELECTOR-1" +
"05VARIATION SELECTOR-106VARIATION SELECTOR-107VARIATION SELECTOR-108VARI" +
"ATION SELECTOR-109VARIATION SELECTOR-110VARIATION SELECTOR-111VARIATION " +
"SELECTOR-112VARIATION SELECTOR-113VARIATION SELECTOR-114VARIATION SELECT" +
"OR-115VARIATION SELECTOR-116VARIATION SELECTOR-117VARIATION SELECTOR-118" +
"VARIATION SELECTOR-119VARIATION SELECTOR-120VARIATION SELECTOR-121VARIAT" +
"ION SELECTOR-122VARIATION SELECTOR-123VARIATION SELECTOR-124VARIATION SE" +
"LECTOR-125VARIATION SELECTOR-126VARIATION SELECTOR-127VARIATION SELECTOR" +
"-128VARIATION SELECTOR-129VARIATION SELECTOR-130VARIATION SELECTOR-131VA" +
"RIATION SELECTOR-132VARIATION SELECTOR-133VARIATION SELECTOR-134VARIATIO" +
"N SELECTOR-135VARIATION SELECTOR-136VARIATION SELECTOR-137VARIATION SELE" +
"CTOR-138VARIATION SELECTOR-139VARIATION SELECTOR-140VARIATION SELECTOR-1" +
"41VARIATION SELECTOR-142VARIATION SELECTOR-143VARIATION SELECTOR-144VARI" +
"ATION SELECTOR-145VARIATION SELECTOR-146VARIATION SELECTOR-147VARIATION " +
"SELECTOR-148VARIATION SELECTOR-149VARIATION SELECTOR-150VARIATION SELECT" +
"OR-151VARIATION SELECTOR-152VARIATION SELECTOR-153VARIATION SELECTOR-154" +
"VARIATION SELECTOR-155VARIATION SELECTOR-156VARIATION SELECTOR-157VARIAT" +
"ION SELECTOR-158VARIATION SELECTOR-159VARIATION SELECTOR-160VARIATION SE" +
"LECTOR-161VARIATION SELECTOR-162VARIATION SELECTOR-163VARIATION SELECTOR" +
"-164VARIATION SELECTOR-165VARIATION SELECTOR-166VARIATION SELECTOR-167VA" +
"RIATION SELECTOR-168VARIATION SELECTOR-169VARIATION SELECTOR-170VARIATIO" +
"N SELECTOR-171VARIATION SELECTOR-172VARIATION SELECTOR-173VARIATION SELE") + ("" +
"CTOR-174VARIATION SELECTOR-175VARIATION SELECTOR-176VARIATION SELECTOR-1" +
"77VARIATION SELECTOR-178VARIATION SELECTOR-179VARIATION SELECTOR-180VARI" +
"ATION SELECTOR-181VARIATION SELECTOR-182VARIATION SELECTOR-183VARIATION " +
"SELECTOR-184VARIATION SELECTOR-185VARIATION SELECTOR-186VARIATION SELECT" +
"OR-187VARIATION SELECTOR-188VARIATION SELECTOR-189VARIATION SELECTOR-190" +
"VARIATION SELECTOR-191VARIATION SELECTOR-192VARIATION SELECTOR-193VARIAT" +
"ION SELECTOR-194VARIATION SELECTOR-195VARIATION SELECTOR-196VARIATION SE" +
"LECTOR-197VARIATION SELECTOR-198VARIATION SELECTOR-199VARIATION SELECTOR" +
"-200VARIATION SELECTOR-201VARIATION SELECTOR-202VARIATION SELECTOR-203VA" +
"RIATION SELECTOR-204VARIATION SELECTOR-205VARIATION SELECTOR-206VARIATIO" +
"N SELECTOR-207VARIATION SELECTOR-208VARIATION SELECTOR-209VARIATION SELE" +
"CTOR-210VARIATION SELECTOR-211VARIATION SELECTOR-212VARIATION SELECTOR-2" +
"13VARIATION SELECTOR-214VARIATION SELECTOR-215VARIATION SELECTOR-216VARI" +
"ATION SELECTOR-217VARIATION SELECTOR-218VARIATION SELECTOR-219VARIATION " +
"SELECTOR-220VARIATION SELECTOR-221VARIATION SELECTOR-222VARIATION SELECT" +
"OR-223VARIATION SELECTOR-224VARIATION SELECTOR-225VARIATION SELECTOR-226" +
"VARIATION SELECTOR-227VARIATION SELECTOR-228VARIATION SELECTOR-229VARIAT" +
"ION SELECTOR-230VARIATION SELECTOR-231VARIATION SELECTOR-232VARIATION SE" +
"LECTOR-233VARIATION SELECTOR-234VARIATION SELECTOR-235VARIATION SELECTOR" +
"-236VARIATION SELECTOR-237VARIATION SELECTOR-238VARIATION SELECTOR-239VA" +
"RIATION SELECTOR-240VARIATION SELECTOR-241VARIATION SELECTOR-242VARIATIO" +
"N SELECTOR-243VARIATION SELECTOR-244VARIATION SELECTOR-245VARIATION SELE" +
"CTOR-246VARIATION SELECTOR-247VARIATION SELECTOR-248VARIATION SELECTOR-2" +
"49VARIATION SELECTOR-250VARIATION SELECTOR-251VARIATION SELECTOR-252VARI" +
"ATION SELECTOR-253VARIATION SELECTOR-254VARIATION SELECTOR-255VARIATION " +
"SELECTOR-256")
// Total table size 976280 bytes (953KiB); checksum: 1DCE15C5
// Code generated by "stringer -type=Kind"; DO NOT EDIT.
package width
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[Neutral-0]
_ = x[EastAsianAmbiguous-1]
_ = x[EastAsianWide-2]
_ = x[EastAsianNarrow-3]
_ = x[EastAsianFullwidth-4]
_ = x[EastAsianHalfwidth-5]
}
const _Kind_name = "NeutralEastAsianAmbiguousEastAsianWideEastAsianNarrowEastAsianFullwidthEastAsianHalfwidth"
var _Kind_index = [...]uint8{0, 7, 25, 38, 53, 71, 89}
func (i Kind) String() string {
if i < 0 || i >= Kind(len(_Kind_index)-1) {
return "Kind(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _Kind_name[_Kind_index[i]:_Kind_index[i+1]]
}
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.21
package width
// UnicodeVersion is the Unicode version from which the tables in this package are derived.
const UnicodeVersion = "15.0.0"
// lookup returns the trie value for the first UTF-8 encoding in s and
// the width in bytes of this encoding. The size will be 0 if s does not
// hold enough bytes to complete the encoding. len(s) must be greater than 0.
func (t *widthTrie) lookup(s []byte) (v uint16, sz int) {
c0 := s[0]
switch {
case c0 < 0x80: // is ASCII
return widthValues[c0], 1
case c0 < 0xC2:
return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
case c0 < 0xE0: // 2-byte UTF-8
if len(s) < 2 {
return 0, 0
}
i := widthIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c1), 2
case c0 < 0xF0: // 3-byte UTF-8
if len(s) < 3 {
return 0, 0
}
i := widthIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = widthIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c2), 3
case c0 < 0xF8: // 4-byte UTF-8
if len(s) < 4 {
return 0, 0
}
i := widthIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = widthIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
o = uint32(i)<<6 + uint32(c2)
i = widthIndex[o]
c3 := s[3]
if c3 < 0x80 || 0xC0 <= c3 {
return 0, 3 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c3), 4
}
// Illegal rune
return 0, 1
}
// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
// s must start with a full and valid UTF-8 encoded rune.
func (t *widthTrie) lookupUnsafe(s []byte) uint16 {
c0 := s[0]
if c0 < 0x80 { // is ASCII
return widthValues[c0]
}
i := widthIndex[c0]
if c0 < 0xE0 { // 2-byte UTF-8
return t.lookupValue(uint32(i), s[1])
}
i = widthIndex[uint32(i)<<6+uint32(s[1])]
if c0 < 0xF0 { // 3-byte UTF-8
return t.lookupValue(uint32(i), s[2])
}
i = widthIndex[uint32(i)<<6+uint32(s[2])]
if c0 < 0xF8 { // 4-byte UTF-8
return t.lookupValue(uint32(i), s[3])
}
return 0
}
// lookupString returns the trie value for the first UTF-8 encoding in s and
// the width in bytes of this encoding. The size will be 0 if s does not
// hold enough bytes to complete the encoding. len(s) must be greater than 0.
func (t *widthTrie) lookupString(s string) (v uint16, sz int) {
c0 := s[0]
switch {
case c0 < 0x80: // is ASCII
return widthValues[c0], 1
case c0 < 0xC2:
return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
case c0 < 0xE0: // 2-byte UTF-8
if len(s) < 2 {
return 0, 0
}
i := widthIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c1), 2
case c0 < 0xF0: // 3-byte UTF-8
if len(s) < 3 {
return 0, 0
}
i := widthIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = widthIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c2), 3
case c0 < 0xF8: // 4-byte UTF-8
if len(s) < 4 {
return 0, 0
}
i := widthIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = widthIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
o = uint32(i)<<6 + uint32(c2)
i = widthIndex[o]
c3 := s[3]
if c3 < 0x80 || 0xC0 <= c3 {
return 0, 3 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c3), 4
}
// Illegal rune
return 0, 1
}
// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
// s must start with a full and valid UTF-8 encoded rune.
func (t *widthTrie) lookupStringUnsafe(s string) uint16 {
c0 := s[0]
if c0 < 0x80 { // is ASCII
return widthValues[c0]
}
i := widthIndex[c0]
if c0 < 0xE0 { // 2-byte UTF-8
return t.lookupValue(uint32(i), s[1])
}
i = widthIndex[uint32(i)<<6+uint32(s[1])]
if c0 < 0xF0 { // 3-byte UTF-8
return t.lookupValue(uint32(i), s[2])
}
i = widthIndex[uint32(i)<<6+uint32(s[2])]
if c0 < 0xF8 { // 4-byte UTF-8
return t.lookupValue(uint32(i), s[3])
}
return 0
}
// widthTrie. Total size: 14912 bytes (14.56 KiB). Checksum: 4468b6cd178303d2.
type widthTrie struct{}
func newWidthTrie(i int) *widthTrie {
return &widthTrie{}
}
// lookupValue determines the type of block n and looks up the value for b.
func (t *widthTrie) lookupValue(n uint32, b byte) uint16 {
switch {
default:
return uint16(widthValues[n<<6+uint32(b)])
}
}
// widthValues: 105 blocks, 6720 entries, 13440 bytes
// The third block is the zero block.
var widthValues = [6720]uint16{
// Block 0x0, offset 0x0
0x20: 0x6001, 0x21: 0x6002, 0x22: 0x6002, 0x23: 0x6002,
0x24: 0x6002, 0x25: 0x6002, 0x26: 0x6002, 0x27: 0x6002, 0x28: 0x6002, 0x29: 0x6002,
0x2a: 0x6002, 0x2b: 0x6002, 0x2c: 0x6002, 0x2d: 0x6002, 0x2e: 0x6002, 0x2f: 0x6002,
0x30: 0x6002, 0x31: 0x6002, 0x32: 0x6002, 0x33: 0x6002, 0x34: 0x6002, 0x35: 0x6002,
0x36: 0x6002, 0x37: 0x6002, 0x38: 0x6002, 0x39: 0x6002, 0x3a: 0x6002, 0x3b: 0x6002,
0x3c: 0x6002, 0x3d: 0x6002, 0x3e: 0x6002, 0x3f: 0x6002,
// Block 0x1, offset 0x40
0x40: 0x6003, 0x41: 0x6003, 0x42: 0x6003, 0x43: 0x6003, 0x44: 0x6003, 0x45: 0x6003,
0x46: 0x6003, 0x47: 0x6003, 0x48: 0x6003, 0x49: 0x6003, 0x4a: 0x6003, 0x4b: 0x6003,
0x4c: 0x6003, 0x4d: 0x6003, 0x4e: 0x6003, 0x4f: 0x6003, 0x50: 0x6003, 0x51: 0x6003,
0x52: 0x6003, 0x53: 0x6003, 0x54: 0x6003, 0x55: 0x6003, 0x56: 0x6003, 0x57: 0x6003,
0x58: 0x6003, 0x59: 0x6003, 0x5a: 0x6003, 0x5b: 0x6003, 0x5c: 0x6003, 0x5d: 0x6003,
0x5e: 0x6003, 0x5f: 0x6003, 0x60: 0x6004, 0x61: 0x6004, 0x62: 0x6004, 0x63: 0x6004,
0x64: 0x6004, 0x65: 0x6004, 0x66: 0x6004, 0x67: 0x6004, 0x68: 0x6004, 0x69: 0x6004,
0x6a: 0x6004, 0x6b: 0x6004, 0x6c: 0x6004, 0x6d: 0x6004, 0x6e: 0x6004, 0x6f: 0x6004,
0x70: 0x6004, 0x71: 0x6004, 0x72: 0x6004, 0x73: 0x6004, 0x74: 0x6004, 0x75: 0x6004,
0x76: 0x6004, 0x77: 0x6004, 0x78: 0x6004, 0x79: 0x6004, 0x7a: 0x6004, 0x7b: 0x6004,
0x7c: 0x6004, 0x7d: 0x6004, 0x7e: 0x6004,
// Block 0x2, offset 0x80
// Block 0x3, offset 0xc0
0xe1: 0x2000, 0xe2: 0x6005, 0xe3: 0x6005,
0xe4: 0x2000, 0xe5: 0x6006, 0xe6: 0x6005, 0xe7: 0x2000, 0xe8: 0x2000,
0xea: 0x2000, 0xec: 0x6007, 0xed: 0x2000, 0xee: 0x2000, 0xef: 0x6008,
0xf0: 0x2000, 0xf1: 0x2000, 0xf2: 0x2000, 0xf3: 0x2000, 0xf4: 0x2000,
0xf6: 0x2000, 0xf7: 0x2000, 0xf8: 0x2000, 0xf9: 0x2000, 0xfa: 0x2000,
0xfc: 0x2000, 0xfd: 0x2000, 0xfe: 0x2000, 0xff: 0x2000,
// Block 0x4, offset 0x100
0x106: 0x2000,
0x110: 0x2000,
0x117: 0x2000,
0x118: 0x2000,
0x11e: 0x2000, 0x11f: 0x2000, 0x120: 0x2000, 0x121: 0x2000,
0x126: 0x2000, 0x128: 0x2000, 0x129: 0x2000,
0x12a: 0x2000, 0x12c: 0x2000, 0x12d: 0x2000,
0x130: 0x2000, 0x132: 0x2000, 0x133: 0x2000,
0x137: 0x2000, 0x138: 0x2000, 0x139: 0x2000, 0x13a: 0x2000,
0x13c: 0x2000, 0x13e: 0x2000,
// Block 0x5, offset 0x140
0x141: 0x2000,
0x151: 0x2000,
0x153: 0x2000,
0x15b: 0x2000,
0x166: 0x2000, 0x167: 0x2000,
0x16b: 0x2000,
0x171: 0x2000, 0x172: 0x2000, 0x173: 0x2000,
0x178: 0x2000,
0x17f: 0x2000,
// Block 0x6, offset 0x180
0x180: 0x2000, 0x181: 0x2000, 0x182: 0x2000, 0x184: 0x2000,
0x188: 0x2000, 0x189: 0x2000, 0x18a: 0x2000, 0x18b: 0x2000,
0x18d: 0x2000,
0x192: 0x2000, 0x193: 0x2000,
0x1a6: 0x2000, 0x1a7: 0x2000,
0x1ab: 0x2000,
// Block 0x7, offset 0x1c0
0x1ce: 0x2000, 0x1d0: 0x2000,
0x1d2: 0x2000, 0x1d4: 0x2000, 0x1d6: 0x2000,
0x1d8: 0x2000, 0x1da: 0x2000, 0x1dc: 0x2000,
// Block 0x8, offset 0x200
0x211: 0x2000,
0x221: 0x2000,
// Block 0x9, offset 0x240
0x244: 0x2000,
0x247: 0x2000, 0x249: 0x2000, 0x24a: 0x2000, 0x24b: 0x2000,
0x24d: 0x2000, 0x250: 0x2000,
0x258: 0x2000, 0x259: 0x2000, 0x25a: 0x2000, 0x25b: 0x2000, 0x25d: 0x2000,
0x25f: 0x2000,
// Block 0xa, offset 0x280
0x280: 0x2000, 0x281: 0x2000, 0x282: 0x2000, 0x283: 0x2000, 0x284: 0x2000, 0x285: 0x2000,
0x286: 0x2000, 0x287: 0x2000, 0x288: 0x2000, 0x289: 0x2000, 0x28a: 0x2000, 0x28b: 0x2000,
0x28c: 0x2000, 0x28d: 0x2000, 0x28e: 0x2000, 0x28f: 0x2000, 0x290: 0x2000, 0x291: 0x2000,
0x292: 0x2000, 0x293: 0x2000, 0x294: 0x2000, 0x295: 0x2000, 0x296: 0x2000, 0x297: 0x2000,
0x298: 0x2000, 0x299: 0x2000, 0x29a: 0x2000, 0x29b: 0x2000, 0x29c: 0x2000, 0x29d: 0x2000,
0x29e: 0x2000, 0x29f: 0x2000, 0x2a0: 0x2000, 0x2a1: 0x2000, 0x2a2: 0x2000, 0x2a3: 0x2000,
0x2a4: 0x2000, 0x2a5: 0x2000, 0x2a6: 0x2000, 0x2a7: 0x2000, 0x2a8: 0x2000, 0x2a9: 0x2000,
0x2aa: 0x2000, 0x2ab: 0x2000, 0x2ac: 0x2000, 0x2ad: 0x2000, 0x2ae: 0x2000, 0x2af: 0x2000,
0x2b0: 0x2000, 0x2b1: 0x2000, 0x2b2: 0x2000, 0x2b3: 0x2000, 0x2b4: 0x2000, 0x2b5: 0x2000,
0x2b6: 0x2000, 0x2b7: 0x2000, 0x2b8: 0x2000, 0x2b9: 0x2000, 0x2ba: 0x2000, 0x2bb: 0x2000,
0x2bc: 0x2000, 0x2bd: 0x2000, 0x2be: 0x2000, 0x2bf: 0x2000,
// Block 0xb, offset 0x2c0
0x2c0: 0x2000, 0x2c1: 0x2000, 0x2c2: 0x2000, 0x2c3: 0x2000, 0x2c4: 0x2000, 0x2c5: 0x2000,
0x2c6: 0x2000, 0x2c7: 0x2000, 0x2c8: 0x2000, 0x2c9: 0x2000, 0x2ca: 0x2000, 0x2cb: 0x2000,
0x2cc: 0x2000, 0x2cd: 0x2000, 0x2ce: 0x2000, 0x2cf: 0x2000, 0x2d0: 0x2000, 0x2d1: 0x2000,
0x2d2: 0x2000, 0x2d3: 0x2000, 0x2d4: 0x2000, 0x2d5: 0x2000, 0x2d6: 0x2000, 0x2d7: 0x2000,
0x2d8: 0x2000, 0x2d9: 0x2000, 0x2da: 0x2000, 0x2db: 0x2000, 0x2dc: 0x2000, 0x2dd: 0x2000,
0x2de: 0x2000, 0x2df: 0x2000, 0x2e0: 0x2000, 0x2e1: 0x2000, 0x2e2: 0x2000, 0x2e3: 0x2000,
0x2e4: 0x2000, 0x2e5: 0x2000, 0x2e6: 0x2000, 0x2e7: 0x2000, 0x2e8: 0x2000, 0x2e9: 0x2000,
0x2ea: 0x2000, 0x2eb: 0x2000, 0x2ec: 0x2000, 0x2ed: 0x2000, 0x2ee: 0x2000, 0x2ef: 0x2000,
// Block 0xc, offset 0x300
0x311: 0x2000,
0x312: 0x2000, 0x313: 0x2000, 0x314: 0x2000, 0x315: 0x2000, 0x316: 0x2000, 0x317: 0x2000,
0x318: 0x2000, 0x319: 0x2000, 0x31a: 0x2000, 0x31b: 0x2000, 0x31c: 0x2000, 0x31d: 0x2000,
0x31e: 0x2000, 0x31f: 0x2000, 0x320: 0x2000, 0x321: 0x2000, 0x323: 0x2000,
0x324: 0x2000, 0x325: 0x2000, 0x326: 0x2000, 0x327: 0x2000, 0x328: 0x2000, 0x329: 0x2000,
0x331: 0x2000, 0x332: 0x2000, 0x333: 0x2000, 0x334: 0x2000, 0x335: 0x2000,
0x336: 0x2000, 0x337: 0x2000, 0x338: 0x2000, 0x339: 0x2000, 0x33a: 0x2000, 0x33b: 0x2000,
0x33c: 0x2000, 0x33d: 0x2000, 0x33e: 0x2000, 0x33f: 0x2000,
// Block 0xd, offset 0x340
0x340: 0x2000, 0x341: 0x2000, 0x343: 0x2000, 0x344: 0x2000, 0x345: 0x2000,
0x346: 0x2000, 0x347: 0x2000, 0x348: 0x2000, 0x349: 0x2000,
// Block 0xe, offset 0x380
0x381: 0x2000,
0x390: 0x2000, 0x391: 0x2000,
0x392: 0x2000, 0x393: 0x2000, 0x394: 0x2000, 0x395: 0x2000, 0x396: 0x2000, 0x397: 0x2000,
0x398: 0x2000, 0x399: 0x2000, 0x39a: 0x2000, 0x39b: 0x2000, 0x39c: 0x2000, 0x39d: 0x2000,
0x39e: 0x2000, 0x39f: 0x2000, 0x3a0: 0x2000, 0x3a1: 0x2000, 0x3a2: 0x2000, 0x3a3: 0x2000,
0x3a4: 0x2000, 0x3a5: 0x2000, 0x3a6: 0x2000, 0x3a7: 0x2000, 0x3a8: 0x2000, 0x3a9: 0x2000,
0x3aa: 0x2000, 0x3ab: 0x2000, 0x3ac: 0x2000, 0x3ad: 0x2000, 0x3ae: 0x2000, 0x3af: 0x2000,
0x3b0: 0x2000, 0x3b1: 0x2000, 0x3b2: 0x2000, 0x3b3: 0x2000, 0x3b4: 0x2000, 0x3b5: 0x2000,
0x3b6: 0x2000, 0x3b7: 0x2000, 0x3b8: 0x2000, 0x3b9: 0x2000, 0x3ba: 0x2000, 0x3bb: 0x2000,
0x3bc: 0x2000, 0x3bd: 0x2000, 0x3be: 0x2000, 0x3bf: 0x2000,
// Block 0xf, offset 0x3c0
0x3c0: 0x2000, 0x3c1: 0x2000, 0x3c2: 0x2000, 0x3c3: 0x2000, 0x3c4: 0x2000, 0x3c5: 0x2000,
0x3c6: 0x2000, 0x3c7: 0x2000, 0x3c8: 0x2000, 0x3c9: 0x2000, 0x3ca: 0x2000, 0x3cb: 0x2000,
0x3cc: 0x2000, 0x3cd: 0x2000, 0x3ce: 0x2000, 0x3cf: 0x2000, 0x3d1: 0x2000,
// Block 0x10, offset 0x400
0x400: 0x4000, 0x401: 0x4000, 0x402: 0x4000, 0x403: 0x4000, 0x404: 0x4000, 0x405: 0x4000,
0x406: 0x4000, 0x407: 0x4000, 0x408: 0x4000, 0x409: 0x4000, 0x40a: 0x4000, 0x40b: 0x4000,
0x40c: 0x4000, 0x40d: 0x4000, 0x40e: 0x4000, 0x40f: 0x4000, 0x410: 0x4000, 0x411: 0x4000,
0x412: 0x4000, 0x413: 0x4000, 0x414: 0x4000, 0x415: 0x4000, 0x416: 0x4000, 0x417: 0x4000,
0x418: 0x4000, 0x419: 0x4000, 0x41a: 0x4000, 0x41b: 0x4000, 0x41c: 0x4000, 0x41d: 0x4000,
0x41e: 0x4000, 0x41f: 0x4000, 0x420: 0x4000, 0x421: 0x4000, 0x422: 0x4000, 0x423: 0x4000,
0x424: 0x4000, 0x425: 0x4000, 0x426: 0x4000, 0x427: 0x4000, 0x428: 0x4000, 0x429: 0x4000,
0x42a: 0x4000, 0x42b: 0x4000, 0x42c: 0x4000, 0x42d: 0x4000, 0x42e: 0x4000, 0x42f: 0x4000,
0x430: 0x4000, 0x431: 0x4000, 0x432: 0x4000, 0x433: 0x4000, 0x434: 0x4000, 0x435: 0x4000,
0x436: 0x4000, 0x437: 0x4000, 0x438: 0x4000, 0x439: 0x4000, 0x43a: 0x4000, 0x43b: 0x4000,
0x43c: 0x4000, 0x43d: 0x4000, 0x43e: 0x4000, 0x43f: 0x4000,
// Block 0x11, offset 0x440
0x440: 0x4000, 0x441: 0x4000, 0x442: 0x4000, 0x443: 0x4000, 0x444: 0x4000, 0x445: 0x4000,
0x446: 0x4000, 0x447: 0x4000, 0x448: 0x4000, 0x449: 0x4000, 0x44a: 0x4000, 0x44b: 0x4000,
0x44c: 0x4000, 0x44d: 0x4000, 0x44e: 0x4000, 0x44f: 0x4000, 0x450: 0x4000, 0x451: 0x4000,
0x452: 0x4000, 0x453: 0x4000, 0x454: 0x4000, 0x455: 0x4000, 0x456: 0x4000, 0x457: 0x4000,
0x458: 0x4000, 0x459: 0x4000, 0x45a: 0x4000, 0x45b: 0x4000, 0x45c: 0x4000, 0x45d: 0x4000,
0x45e: 0x4000, 0x45f: 0x4000,
// Block 0x12, offset 0x480
0x490: 0x2000,
0x493: 0x2000, 0x494: 0x2000, 0x495: 0x2000, 0x496: 0x2000,
0x498: 0x2000, 0x499: 0x2000, 0x49c: 0x2000, 0x49d: 0x2000,
0x4a0: 0x2000, 0x4a1: 0x2000, 0x4a2: 0x2000,
0x4a4: 0x2000, 0x4a5: 0x2000, 0x4a6: 0x2000, 0x4a7: 0x2000,
0x4b0: 0x2000, 0x4b2: 0x2000, 0x4b3: 0x2000, 0x4b5: 0x2000,
0x4bb: 0x2000,
0x4be: 0x2000,
// Block 0x13, offset 0x4c0
0x4f4: 0x2000,
0x4ff: 0x2000,
// Block 0x14, offset 0x500
0x501: 0x2000, 0x502: 0x2000, 0x503: 0x2000, 0x504: 0x2000,
0x529: 0xa009,
0x52c: 0x2000,
// Block 0x15, offset 0x540
0x543: 0x2000, 0x545: 0x2000,
0x549: 0x2000,
0x553: 0x2000, 0x556: 0x2000,
0x561: 0x2000, 0x562: 0x2000,
0x566: 0x2000,
0x56b: 0x2000,
// Block 0x16, offset 0x580
0x593: 0x2000, 0x594: 0x2000,
0x59b: 0x2000, 0x59c: 0x2000, 0x59d: 0x2000,
0x59e: 0x2000, 0x5a0: 0x2000, 0x5a1: 0x2000, 0x5a2: 0x2000, 0x5a3: 0x2000,
0x5a4: 0x2000, 0x5a5: 0x2000, 0x5a6: 0x2000, 0x5a7: 0x2000, 0x5a8: 0x2000, 0x5a9: 0x2000,
0x5aa: 0x2000, 0x5ab: 0x2000,
0x5b0: 0x2000, 0x5b1: 0x2000, 0x5b2: 0x2000, 0x5b3: 0x2000, 0x5b4: 0x2000, 0x5b5: 0x2000,
0x5b6: 0x2000, 0x5b7: 0x2000, 0x5b8: 0x2000, 0x5b9: 0x2000,
// Block 0x17, offset 0x5c0
0x5c9: 0x2000,
0x5d0: 0x200a, 0x5d1: 0x200b,
0x5d2: 0x200a, 0x5d3: 0x200c, 0x5d4: 0x2000, 0x5d5: 0x2000, 0x5d6: 0x2000, 0x5d7: 0x2000,
0x5d8: 0x2000, 0x5d9: 0x2000,
0x5f8: 0x2000, 0x5f9: 0x2000,
// Block 0x18, offset 0x600
0x612: 0x2000, 0x614: 0x2000,
0x627: 0x2000,
// Block 0x19, offset 0x640
0x640: 0x2000, 0x642: 0x2000, 0x643: 0x2000,
0x647: 0x2000, 0x648: 0x2000, 0x64b: 0x2000,
0x64f: 0x2000, 0x651: 0x2000,
0x655: 0x2000,
0x65a: 0x2000, 0x65d: 0x2000,
0x65e: 0x2000, 0x65f: 0x2000, 0x660: 0x2000, 0x663: 0x2000,
0x665: 0x2000, 0x667: 0x2000, 0x668: 0x2000, 0x669: 0x2000,
0x66a: 0x2000, 0x66b: 0x2000, 0x66c: 0x2000, 0x66e: 0x2000,
0x674: 0x2000, 0x675: 0x2000,
0x676: 0x2000, 0x677: 0x2000,
0x67c: 0x2000, 0x67d: 0x2000,
// Block 0x1a, offset 0x680
0x688: 0x2000,
0x68c: 0x2000,
0x692: 0x2000,
0x6a0: 0x2000, 0x6a1: 0x2000,
0x6a4: 0x2000, 0x6a5: 0x2000, 0x6a6: 0x2000, 0x6a7: 0x2000,
0x6aa: 0x2000, 0x6ab: 0x2000, 0x6ae: 0x2000, 0x6af: 0x2000,
// Block 0x1b, offset 0x6c0
0x6c2: 0x2000, 0x6c3: 0x2000,
0x6c6: 0x2000, 0x6c7: 0x2000,
0x6d5: 0x2000,
0x6d9: 0x2000,
0x6e5: 0x2000,
0x6ff: 0x2000,
// Block 0x1c, offset 0x700
0x712: 0x2000,
0x71a: 0x4000, 0x71b: 0x4000,
0x729: 0x4000,
0x72a: 0x4000,
// Block 0x1d, offset 0x740
0x769: 0x4000,
0x76a: 0x4000, 0x76b: 0x4000, 0x76c: 0x4000,
0x770: 0x4000, 0x773: 0x4000,
// Block 0x1e, offset 0x780
0x7a0: 0x2000, 0x7a1: 0x2000, 0x7a2: 0x2000, 0x7a3: 0x2000,
0x7a4: 0x2000, 0x7a5: 0x2000, 0x7a6: 0x2000, 0x7a7: 0x2000, 0x7a8: 0x2000, 0x7a9: 0x2000,
0x7aa: 0x2000, 0x7ab: 0x2000, 0x7ac: 0x2000, 0x7ad: 0x2000, 0x7ae: 0x2000, 0x7af: 0x2000,
0x7b0: 0x2000, 0x7b1: 0x2000, 0x7b2: 0x2000, 0x7b3: 0x2000, 0x7b4: 0x2000, 0x7b5: 0x2000,
0x7b6: 0x2000, 0x7b7: 0x2000, 0x7b8: 0x2000, 0x7b9: 0x2000, 0x7ba: 0x2000, 0x7bb: 0x2000,
0x7bc: 0x2000, 0x7bd: 0x2000, 0x7be: 0x2000, 0x7bf: 0x2000,
// Block 0x1f, offset 0x7c0
0x7c0: 0x2000, 0x7c1: 0x2000, 0x7c2: 0x2000, 0x7c3: 0x2000, 0x7c4: 0x2000, 0x7c5: 0x2000,
0x7c6: 0x2000, 0x7c7: 0x2000, 0x7c8: 0x2000, 0x7c9: 0x2000, 0x7ca: 0x2000, 0x7cb: 0x2000,
0x7cc: 0x2000, 0x7cd: 0x2000, 0x7ce: 0x2000, 0x7cf: 0x2000, 0x7d0: 0x2000, 0x7d1: 0x2000,
0x7d2: 0x2000, 0x7d3: 0x2000, 0x7d4: 0x2000, 0x7d5: 0x2000, 0x7d6: 0x2000, 0x7d7: 0x2000,
0x7d8: 0x2000, 0x7d9: 0x2000, 0x7da: 0x2000, 0x7db: 0x2000, 0x7dc: 0x2000, 0x7dd: 0x2000,
0x7de: 0x2000, 0x7df: 0x2000, 0x7e0: 0x2000, 0x7e1: 0x2000, 0x7e2: 0x2000, 0x7e3: 0x2000,
0x7e4: 0x2000, 0x7e5: 0x2000, 0x7e6: 0x2000, 0x7e7: 0x2000, 0x7e8: 0x2000, 0x7e9: 0x2000,
0x7eb: 0x2000, 0x7ec: 0x2000, 0x7ed: 0x2000, 0x7ee: 0x2000, 0x7ef: 0x2000,
0x7f0: 0x2000, 0x7f1: 0x2000, 0x7f2: 0x2000, 0x7f3: 0x2000, 0x7f4: 0x2000, 0x7f5: 0x2000,
0x7f6: 0x2000, 0x7f7: 0x2000, 0x7f8: 0x2000, 0x7f9: 0x2000, 0x7fa: 0x2000, 0x7fb: 0x2000,
0x7fc: 0x2000, 0x7fd: 0x2000, 0x7fe: 0x2000, 0x7ff: 0x2000,
// Block 0x20, offset 0x800
0x800: 0x2000, 0x801: 0x2000, 0x802: 0x200d, 0x803: 0x2000, 0x804: 0x2000, 0x805: 0x2000,
0x806: 0x2000, 0x807: 0x2000, 0x808: 0x2000, 0x809: 0x2000, 0x80a: 0x2000, 0x80b: 0x2000,
0x80c: 0x2000, 0x80d: 0x2000, 0x80e: 0x2000, 0x80f: 0x2000, 0x810: 0x2000, 0x811: 0x2000,
0x812: 0x2000, 0x813: 0x2000, 0x814: 0x2000, 0x815: 0x2000, 0x816: 0x2000, 0x817: 0x2000,
0x818: 0x2000, 0x819: 0x2000, 0x81a: 0x2000, 0x81b: 0x2000, 0x81c: 0x2000, 0x81d: 0x2000,
0x81e: 0x2000, 0x81f: 0x2000, 0x820: 0x2000, 0x821: 0x2000, 0x822: 0x2000, 0x823: 0x2000,
0x824: 0x2000, 0x825: 0x2000, 0x826: 0x2000, 0x827: 0x2000, 0x828: 0x2000, 0x829: 0x2000,
0x82a: 0x2000, 0x82b: 0x2000, 0x82c: 0x2000, 0x82d: 0x2000, 0x82e: 0x2000, 0x82f: 0x2000,
0x830: 0x2000, 0x831: 0x2000, 0x832: 0x2000, 0x833: 0x2000, 0x834: 0x2000, 0x835: 0x2000,
0x836: 0x2000, 0x837: 0x2000, 0x838: 0x2000, 0x839: 0x2000, 0x83a: 0x2000, 0x83b: 0x2000,
0x83c: 0x2000, 0x83d: 0x2000, 0x83e: 0x2000, 0x83f: 0x2000,
// Block 0x21, offset 0x840
0x840: 0x2000, 0x841: 0x2000, 0x842: 0x2000, 0x843: 0x2000, 0x844: 0x2000, 0x845: 0x2000,
0x846: 0x2000, 0x847: 0x2000, 0x848: 0x2000, 0x849: 0x2000, 0x84a: 0x2000, 0x84b: 0x2000,
0x850: 0x2000, 0x851: 0x2000,
0x852: 0x2000, 0x853: 0x2000, 0x854: 0x2000, 0x855: 0x2000, 0x856: 0x2000, 0x857: 0x2000,
0x858: 0x2000, 0x859: 0x2000, 0x85a: 0x2000, 0x85b: 0x2000, 0x85c: 0x2000, 0x85d: 0x2000,
0x85e: 0x2000, 0x85f: 0x2000, 0x860: 0x2000, 0x861: 0x2000, 0x862: 0x2000, 0x863: 0x2000,
0x864: 0x2000, 0x865: 0x2000, 0x866: 0x2000, 0x867: 0x2000, 0x868: 0x2000, 0x869: 0x2000,
0x86a: 0x2000, 0x86b: 0x2000, 0x86c: 0x2000, 0x86d: 0x2000, 0x86e: 0x2000, 0x86f: 0x2000,
0x870: 0x2000, 0x871: 0x2000, 0x872: 0x2000, 0x873: 0x2000,
// Block 0x22, offset 0x880
0x880: 0x2000, 0x881: 0x2000, 0x882: 0x2000, 0x883: 0x2000, 0x884: 0x2000, 0x885: 0x2000,
0x886: 0x2000, 0x887: 0x2000, 0x888: 0x2000, 0x889: 0x2000, 0x88a: 0x2000, 0x88b: 0x2000,
0x88c: 0x2000, 0x88d: 0x2000, 0x88e: 0x2000, 0x88f: 0x2000,
0x892: 0x2000, 0x893: 0x2000, 0x894: 0x2000, 0x895: 0x2000,
0x8a0: 0x200e, 0x8a1: 0x2000, 0x8a3: 0x2000,
0x8a4: 0x2000, 0x8a5: 0x2000, 0x8a6: 0x2000, 0x8a7: 0x2000, 0x8a8: 0x2000, 0x8a9: 0x2000,
0x8b2: 0x2000, 0x8b3: 0x2000,
0x8b6: 0x2000, 0x8b7: 0x2000,
0x8bc: 0x2000, 0x8bd: 0x2000,
// Block 0x23, offset 0x8c0
0x8c0: 0x2000, 0x8c1: 0x2000,
0x8c6: 0x2000, 0x8c7: 0x2000, 0x8c8: 0x2000, 0x8cb: 0x200f,
0x8ce: 0x2000, 0x8cf: 0x2000, 0x8d0: 0x2000, 0x8d1: 0x2000,
0x8e2: 0x2000, 0x8e3: 0x2000,
0x8e4: 0x2000, 0x8e5: 0x2000,
0x8ef: 0x2000,
0x8fd: 0x4000, 0x8fe: 0x4000,
// Block 0x24, offset 0x900
0x905: 0x2000,
0x906: 0x2000, 0x909: 0x2000,
0x90e: 0x2000, 0x90f: 0x2000,
0x914: 0x4000, 0x915: 0x4000,
0x91c: 0x2000,
0x91e: 0x2000,
// Block 0x25, offset 0x940
0x940: 0x2000, 0x942: 0x2000,
0x948: 0x4000, 0x949: 0x4000, 0x94a: 0x4000, 0x94b: 0x4000,
0x94c: 0x4000, 0x94d: 0x4000, 0x94e: 0x4000, 0x94f: 0x4000, 0x950: 0x4000, 0x951: 0x4000,
0x952: 0x4000, 0x953: 0x4000,
0x960: 0x2000, 0x961: 0x2000, 0x963: 0x2000,
0x964: 0x2000, 0x965: 0x2000, 0x967: 0x2000, 0x968: 0x2000, 0x969: 0x2000,
0x96a: 0x2000, 0x96c: 0x2000, 0x96d: 0x2000, 0x96f: 0x2000,
0x97f: 0x4000,
// Block 0x26, offset 0x980
0x993: 0x4000,
0x99e: 0x2000, 0x99f: 0x2000, 0x9a1: 0x4000,
0x9aa: 0x4000, 0x9ab: 0x4000,
0x9bd: 0x4000, 0x9be: 0x4000, 0x9bf: 0x2000,
// Block 0x27, offset 0x9c0
0x9c4: 0x4000, 0x9c5: 0x4000,
0x9c6: 0x2000, 0x9c7: 0x2000, 0x9c8: 0x2000, 0x9c9: 0x2000, 0x9ca: 0x2000, 0x9cb: 0x2000,
0x9cc: 0x2000, 0x9cd: 0x2000, 0x9ce: 0x4000, 0x9cf: 0x2000, 0x9d0: 0x2000, 0x9d1: 0x2000,
0x9d2: 0x2000, 0x9d3: 0x2000, 0x9d4: 0x4000, 0x9d5: 0x2000, 0x9d6: 0x2000, 0x9d7: 0x2000,
0x9d8: 0x2000, 0x9d9: 0x2000, 0x9da: 0x2000, 0x9db: 0x2000, 0x9dc: 0x2000, 0x9dd: 0x2000,
0x9de: 0x2000, 0x9df: 0x2000, 0x9e0: 0x2000, 0x9e1: 0x2000, 0x9e3: 0x2000,
0x9e8: 0x2000, 0x9e9: 0x2000,
0x9ea: 0x4000, 0x9eb: 0x2000, 0x9ec: 0x2000, 0x9ed: 0x2000, 0x9ee: 0x2000, 0x9ef: 0x2000,
0x9f0: 0x2000, 0x9f1: 0x2000, 0x9f2: 0x4000, 0x9f3: 0x4000, 0x9f4: 0x2000, 0x9f5: 0x4000,
0x9f6: 0x2000, 0x9f7: 0x2000, 0x9f8: 0x2000, 0x9f9: 0x2000, 0x9fa: 0x4000, 0x9fb: 0x2000,
0x9fc: 0x2000, 0x9fd: 0x4000, 0x9fe: 0x2000, 0x9ff: 0x2000,
// Block 0x28, offset 0xa00
0xa05: 0x4000,
0xa0a: 0x4000, 0xa0b: 0x4000,
0xa28: 0x4000,
0xa3d: 0x2000,
// Block 0x29, offset 0xa40
0xa4c: 0x4000, 0xa4e: 0x4000,
0xa53: 0x4000, 0xa54: 0x4000, 0xa55: 0x4000, 0xa57: 0x4000,
0xa76: 0x2000, 0xa77: 0x2000, 0xa78: 0x2000, 0xa79: 0x2000, 0xa7a: 0x2000, 0xa7b: 0x2000,
0xa7c: 0x2000, 0xa7d: 0x2000, 0xa7e: 0x2000, 0xa7f: 0x2000,
// Block 0x2a, offset 0xa80
0xa95: 0x4000, 0xa96: 0x4000, 0xa97: 0x4000,
0xab0: 0x4000,
0xabf: 0x4000,
// Block 0x2b, offset 0xac0
0xae6: 0x6000, 0xae7: 0x6000, 0xae8: 0x6000, 0xae9: 0x6000,
0xaea: 0x6000, 0xaeb: 0x6000, 0xaec: 0x6000, 0xaed: 0x6000,
// Block 0x2c, offset 0xb00
0xb05: 0x6010,
0xb06: 0x6011,
// Block 0x2d, offset 0xb40
0xb5b: 0x4000, 0xb5c: 0x4000,
// Block 0x2e, offset 0xb80
0xb90: 0x4000,
0xb95: 0x4000, 0xb96: 0x2000, 0xb97: 0x2000,
0xb98: 0x2000, 0xb99: 0x2000,
// Block 0x2f, offset 0xbc0
0xbc0: 0x4000, 0xbc1: 0x4000, 0xbc2: 0x4000, 0xbc3: 0x4000, 0xbc4: 0x4000, 0xbc5: 0x4000,
0xbc6: 0x4000, 0xbc7: 0x4000, 0xbc8: 0x4000, 0xbc9: 0x4000, 0xbca: 0x4000, 0xbcb: 0x4000,
0xbcc: 0x4000, 0xbcd: 0x4000, 0xbce: 0x4000, 0xbcf: 0x4000, 0xbd0: 0x4000, 0xbd1: 0x4000,
0xbd2: 0x4000, 0xbd3: 0x4000, 0xbd4: 0x4000, 0xbd5: 0x4000, 0xbd6: 0x4000, 0xbd7: 0x4000,
0xbd8: 0x4000, 0xbd9: 0x4000, 0xbdb: 0x4000, 0xbdc: 0x4000, 0xbdd: 0x4000,
0xbde: 0x4000, 0xbdf: 0x4000, 0xbe0: 0x4000, 0xbe1: 0x4000, 0xbe2: 0x4000, 0xbe3: 0x4000,
0xbe4: 0x4000, 0xbe5: 0x4000, 0xbe6: 0x4000, 0xbe7: 0x4000, 0xbe8: 0x4000, 0xbe9: 0x4000,
0xbea: 0x4000, 0xbeb: 0x4000, 0xbec: 0x4000, 0xbed: 0x4000, 0xbee: 0x4000, 0xbef: 0x4000,
0xbf0: 0x4000, 0xbf1: 0x4000, 0xbf2: 0x4000, 0xbf3: 0x4000, 0xbf4: 0x4000, 0xbf5: 0x4000,
0xbf6: 0x4000, 0xbf7: 0x4000, 0xbf8: 0x4000, 0xbf9: 0x4000, 0xbfa: 0x4000, 0xbfb: 0x4000,
0xbfc: 0x4000, 0xbfd: 0x4000, 0xbfe: 0x4000, 0xbff: 0x4000,
// Block 0x30, offset 0xc00
0xc00: 0x4000, 0xc01: 0x4000, 0xc02: 0x4000, 0xc03: 0x4000, 0xc04: 0x4000, 0xc05: 0x4000,
0xc06: 0x4000, 0xc07: 0x4000, 0xc08: 0x4000, 0xc09: 0x4000, 0xc0a: 0x4000, 0xc0b: 0x4000,
0xc0c: 0x4000, 0xc0d: 0x4000, 0xc0e: 0x4000, 0xc0f: 0x4000, 0xc10: 0x4000, 0xc11: 0x4000,
0xc12: 0x4000, 0xc13: 0x4000, 0xc14: 0x4000, 0xc15: 0x4000, 0xc16: 0x4000, 0xc17: 0x4000,
0xc18: 0x4000, 0xc19: 0x4000, 0xc1a: 0x4000, 0xc1b: 0x4000, 0xc1c: 0x4000, 0xc1d: 0x4000,
0xc1e: 0x4000, 0xc1f: 0x4000, 0xc20: 0x4000, 0xc21: 0x4000, 0xc22: 0x4000, 0xc23: 0x4000,
0xc24: 0x4000, 0xc25: 0x4000, 0xc26: 0x4000, 0xc27: 0x4000, 0xc28: 0x4000, 0xc29: 0x4000,
0xc2a: 0x4000, 0xc2b: 0x4000, 0xc2c: 0x4000, 0xc2d: 0x4000, 0xc2e: 0x4000, 0xc2f: 0x4000,
0xc30: 0x4000, 0xc31: 0x4000, 0xc32: 0x4000, 0xc33: 0x4000,
// Block 0x31, offset 0xc40
0xc40: 0x4000, 0xc41: 0x4000, 0xc42: 0x4000, 0xc43: 0x4000, 0xc44: 0x4000, 0xc45: 0x4000,
0xc46: 0x4000, 0xc47: 0x4000, 0xc48: 0x4000, 0xc49: 0x4000, 0xc4a: 0x4000, 0xc4b: 0x4000,
0xc4c: 0x4000, 0xc4d: 0x4000, 0xc4e: 0x4000, 0xc4f: 0x4000, 0xc50: 0x4000, 0xc51: 0x4000,
0xc52: 0x4000, 0xc53: 0x4000, 0xc54: 0x4000, 0xc55: 0x4000,
0xc70: 0x4000, 0xc71: 0x4000, 0xc72: 0x4000, 0xc73: 0x4000, 0xc74: 0x4000, 0xc75: 0x4000,
0xc76: 0x4000, 0xc77: 0x4000, 0xc78: 0x4000, 0xc79: 0x4000, 0xc7a: 0x4000, 0xc7b: 0x4000,
// Block 0x32, offset 0xc80
0xc80: 0x9012, 0xc81: 0x4013, 0xc82: 0x4014, 0xc83: 0x4000, 0xc84: 0x4000, 0xc85: 0x4000,
0xc86: 0x4000, 0xc87: 0x4000, 0xc88: 0x4000, 0xc89: 0x4000, 0xc8a: 0x4000, 0xc8b: 0x4000,
0xc8c: 0x4015, 0xc8d: 0x4015, 0xc8e: 0x4000, 0xc8f: 0x4000, 0xc90: 0x4000, 0xc91: 0x4000,
0xc92: 0x4000, 0xc93: 0x4000, 0xc94: 0x4000, 0xc95: 0x4000, 0xc96: 0x4000, 0xc97: 0x4000,
0xc98: 0x4000, 0xc99: 0x4000, 0xc9a: 0x4000, 0xc9b: 0x4000, 0xc9c: 0x4000, 0xc9d: 0x4000,
0xc9e: 0x4000, 0xc9f: 0x4000, 0xca0: 0x4000, 0xca1: 0x4000, 0xca2: 0x4000, 0xca3: 0x4000,
0xca4: 0x4000, 0xca5: 0x4000, 0xca6: 0x4000, 0xca7: 0x4000, 0xca8: 0x4000, 0xca9: 0x4000,
0xcaa: 0x4000, 0xcab: 0x4000, 0xcac: 0x4000, 0xcad: 0x4000, 0xcae: 0x4000, 0xcaf: 0x4000,
0xcb0: 0x4000, 0xcb1: 0x4000, 0xcb2: 0x4000, 0xcb3: 0x4000, 0xcb4: 0x4000, 0xcb5: 0x4000,
0xcb6: 0x4000, 0xcb7: 0x4000, 0xcb8: 0x4000, 0xcb9: 0x4000, 0xcba: 0x4000, 0xcbb: 0x4000,
0xcbc: 0x4000, 0xcbd: 0x4000, 0xcbe: 0x4000,
// Block 0x33, offset 0xcc0
0xcc1: 0x4000, 0xcc2: 0x4000, 0xcc3: 0x4000, 0xcc4: 0x4000, 0xcc5: 0x4000,
0xcc6: 0x4000, 0xcc7: 0x4000, 0xcc8: 0x4000, 0xcc9: 0x4000, 0xcca: 0x4000, 0xccb: 0x4000,
0xccc: 0x4000, 0xccd: 0x4000, 0xcce: 0x4000, 0xccf: 0x4000, 0xcd0: 0x4000, 0xcd1: 0x4000,
0xcd2: 0x4000, 0xcd3: 0x4000, 0xcd4: 0x4000, 0xcd5: 0x4000, 0xcd6: 0x4000, 0xcd7: 0x4000,
0xcd8: 0x4000, 0xcd9: 0x4000, 0xcda: 0x4000, 0xcdb: 0x4000, 0xcdc: 0x4000, 0xcdd: 0x4000,
0xcde: 0x4000, 0xcdf: 0x4000, 0xce0: 0x4000, 0xce1: 0x4000, 0xce2: 0x4000, 0xce3: 0x4000,
0xce4: 0x4000, 0xce5: 0x4000, 0xce6: 0x4000, 0xce7: 0x4000, 0xce8: 0x4000, 0xce9: 0x4000,
0xcea: 0x4000, 0xceb: 0x4000, 0xcec: 0x4000, 0xced: 0x4000, 0xcee: 0x4000, 0xcef: 0x4000,
0xcf0: 0x4000, 0xcf1: 0x4000, 0xcf2: 0x4000, 0xcf3: 0x4000, 0xcf4: 0x4000, 0xcf5: 0x4000,
0xcf6: 0x4000, 0xcf7: 0x4000, 0xcf8: 0x4000, 0xcf9: 0x4000, 0xcfa: 0x4000, 0xcfb: 0x4000,
0xcfc: 0x4000, 0xcfd: 0x4000, 0xcfe: 0x4000, 0xcff: 0x4000,
// Block 0x34, offset 0xd00
0xd00: 0x4000, 0xd01: 0x4000, 0xd02: 0x4000, 0xd03: 0x4000, 0xd04: 0x4000, 0xd05: 0x4000,
0xd06: 0x4000, 0xd07: 0x4000, 0xd08: 0x4000, 0xd09: 0x4000, 0xd0a: 0x4000, 0xd0b: 0x4000,
0xd0c: 0x4000, 0xd0d: 0x4000, 0xd0e: 0x4000, 0xd0f: 0x4000, 0xd10: 0x4000, 0xd11: 0x4000,
0xd12: 0x4000, 0xd13: 0x4000, 0xd14: 0x4000, 0xd15: 0x4000, 0xd16: 0x4000,
0xd19: 0x4016, 0xd1a: 0x4017, 0xd1b: 0x4000, 0xd1c: 0x4000, 0xd1d: 0x4000,
0xd1e: 0x4000, 0xd1f: 0x4000, 0xd20: 0x4000, 0xd21: 0x4018, 0xd22: 0x4019, 0xd23: 0x401a,
0xd24: 0x401b, 0xd25: 0x401c, 0xd26: 0x401d, 0xd27: 0x401e, 0xd28: 0x401f, 0xd29: 0x4020,
0xd2a: 0x4021, 0xd2b: 0x4022, 0xd2c: 0x4000, 0xd2d: 0x4010, 0xd2e: 0x4000, 0xd2f: 0x4023,
0xd30: 0x4000, 0xd31: 0x4024, 0xd32: 0x4000, 0xd33: 0x4025, 0xd34: 0x4000, 0xd35: 0x4026,
0xd36: 0x4000, 0xd37: 0x401a, 0xd38: 0x4000, 0xd39: 0x4027, 0xd3a: 0x4000, 0xd3b: 0x4028,
0xd3c: 0x4000, 0xd3d: 0x4020, 0xd3e: 0x4000, 0xd3f: 0x4029,
// Block 0x35, offset 0xd40
0xd40: 0x4000, 0xd41: 0x402a, 0xd42: 0x4000, 0xd43: 0x402b, 0xd44: 0x402c, 0xd45: 0x4000,
0xd46: 0x4017, 0xd47: 0x4000, 0xd48: 0x402d, 0xd49: 0x4000, 0xd4a: 0x402e, 0xd4b: 0x402f,
0xd4c: 0x4030, 0xd4d: 0x4017, 0xd4e: 0x4016, 0xd4f: 0x4017, 0xd50: 0x4000, 0xd51: 0x4000,
0xd52: 0x4031, 0xd53: 0x4000, 0xd54: 0x4000, 0xd55: 0x4031, 0xd56: 0x4000, 0xd57: 0x4000,
0xd58: 0x4032, 0xd59: 0x4000, 0xd5a: 0x4000, 0xd5b: 0x4032, 0xd5c: 0x4000, 0xd5d: 0x4000,
0xd5e: 0x4033, 0xd5f: 0x402e, 0xd60: 0x4034, 0xd61: 0x4035, 0xd62: 0x4034, 0xd63: 0x4036,
0xd64: 0x4037, 0xd65: 0x4024, 0xd66: 0x4035, 0xd67: 0x4025, 0xd68: 0x4038, 0xd69: 0x4038,
0xd6a: 0x4039, 0xd6b: 0x4039, 0xd6c: 0x403a, 0xd6d: 0x403a, 0xd6e: 0x4000, 0xd6f: 0x4035,
0xd70: 0x4000, 0xd71: 0x4000, 0xd72: 0x403b, 0xd73: 0x403c, 0xd74: 0x4000, 0xd75: 0x4000,
0xd76: 0x4000, 0xd77: 0x4000, 0xd78: 0x4000, 0xd79: 0x4000, 0xd7a: 0x4000, 0xd7b: 0x403d,
0xd7c: 0x401c, 0xd7d: 0x4000, 0xd7e: 0x4000, 0xd7f: 0x4000,
// Block 0x36, offset 0xd80
0xd85: 0x4000,
0xd86: 0x4000, 0xd87: 0x4000, 0xd88: 0x4000, 0xd89: 0x4000, 0xd8a: 0x4000, 0xd8b: 0x4000,
0xd8c: 0x4000, 0xd8d: 0x4000, 0xd8e: 0x4000, 0xd8f: 0x4000, 0xd90: 0x4000, 0xd91: 0x4000,
0xd92: 0x4000, 0xd93: 0x4000, 0xd94: 0x4000, 0xd95: 0x4000, 0xd96: 0x4000, 0xd97: 0x4000,
0xd98: 0x4000, 0xd99: 0x4000, 0xd9a: 0x4000, 0xd9b: 0x4000, 0xd9c: 0x4000, 0xd9d: 0x4000,
0xd9e: 0x4000, 0xd9f: 0x4000, 0xda0: 0x4000, 0xda1: 0x4000, 0xda2: 0x4000, 0xda3: 0x4000,
0xda4: 0x4000, 0xda5: 0x4000, 0xda6: 0x4000, 0xda7: 0x4000, 0xda8: 0x4000, 0xda9: 0x4000,
0xdaa: 0x4000, 0xdab: 0x4000, 0xdac: 0x4000, 0xdad: 0x4000, 0xdae: 0x4000, 0xdaf: 0x4000,
0xdb1: 0x403e, 0xdb2: 0x403e, 0xdb3: 0x403e, 0xdb4: 0x403e, 0xdb5: 0x403e,
0xdb6: 0x403e, 0xdb7: 0x403e, 0xdb8: 0x403e, 0xdb9: 0x403e, 0xdba: 0x403e, 0xdbb: 0x403e,
0xdbc: 0x403e, 0xdbd: 0x403e, 0xdbe: 0x403e, 0xdbf: 0x403e,
// Block 0x37, offset 0xdc0
0xdc0: 0x4037, 0xdc1: 0x4037, 0xdc2: 0x4037, 0xdc3: 0x4037, 0xdc4: 0x4037, 0xdc5: 0x4037,
0xdc6: 0x4037, 0xdc7: 0x4037, 0xdc8: 0x4037, 0xdc9: 0x4037, 0xdca: 0x4037, 0xdcb: 0x4037,
0xdcc: 0x4037, 0xdcd: 0x4037, 0xdce: 0x4037, 0xdcf: 0x400e, 0xdd0: 0x403f, 0xdd1: 0x4040,
0xdd2: 0x4041, 0xdd3: 0x4040, 0xdd4: 0x403f, 0xdd5: 0x4042, 0xdd6: 0x4043, 0xdd7: 0x4044,
0xdd8: 0x4040, 0xdd9: 0x4041, 0xdda: 0x4040, 0xddb: 0x4045, 0xddc: 0x4009, 0xddd: 0x4045,
0xdde: 0x4046, 0xddf: 0x4045, 0xde0: 0x4047, 0xde1: 0x400b, 0xde2: 0x400a, 0xde3: 0x400c,
0xde4: 0x4048, 0xde5: 0x4000, 0xde6: 0x4000, 0xde7: 0x4000, 0xde8: 0x4000, 0xde9: 0x4000,
0xdea: 0x4000, 0xdeb: 0x4000, 0xdec: 0x4000, 0xded: 0x4000, 0xdee: 0x4000, 0xdef: 0x4000,
0xdf0: 0x4000, 0xdf1: 0x4000, 0xdf2: 0x4000, 0xdf3: 0x4000, 0xdf4: 0x4000, 0xdf5: 0x4000,
0xdf6: 0x4000, 0xdf7: 0x4000, 0xdf8: 0x4000, 0xdf9: 0x4000, 0xdfa: 0x4000, 0xdfb: 0x4000,
0xdfc: 0x4000, 0xdfd: 0x4000, 0xdfe: 0x4000, 0xdff: 0x4000,
// Block 0x38, offset 0xe00
0xe00: 0x4000, 0xe01: 0x4000, 0xe02: 0x4000, 0xe03: 0x4000, 0xe04: 0x4000, 0xe05: 0x4000,
0xe06: 0x4000, 0xe07: 0x4000, 0xe08: 0x4000, 0xe09: 0x4000, 0xe0a: 0x4000, 0xe0b: 0x4000,
0xe0c: 0x4000, 0xe0d: 0x4000, 0xe0e: 0x4000, 0xe10: 0x4000, 0xe11: 0x4000,
0xe12: 0x4000, 0xe13: 0x4000, 0xe14: 0x4000, 0xe15: 0x4000, 0xe16: 0x4000, 0xe17: 0x4000,
0xe18: 0x4000, 0xe19: 0x4000, 0xe1a: 0x4000, 0xe1b: 0x4000, 0xe1c: 0x4000, 0xe1d: 0x4000,
0xe1e: 0x4000, 0xe1f: 0x4000, 0xe20: 0x4000, 0xe21: 0x4000, 0xe22: 0x4000, 0xe23: 0x4000,
0xe24: 0x4000, 0xe25: 0x4000, 0xe26: 0x4000, 0xe27: 0x4000, 0xe28: 0x4000, 0xe29: 0x4000,
0xe2a: 0x4000, 0xe2b: 0x4000, 0xe2c: 0x4000, 0xe2d: 0x4000, 0xe2e: 0x4000, 0xe2f: 0x4000,
0xe30: 0x4000, 0xe31: 0x4000, 0xe32: 0x4000, 0xe33: 0x4000, 0xe34: 0x4000, 0xe35: 0x4000,
0xe36: 0x4000, 0xe37: 0x4000, 0xe38: 0x4000, 0xe39: 0x4000, 0xe3a: 0x4000, 0xe3b: 0x4000,
0xe3c: 0x4000, 0xe3d: 0x4000, 0xe3e: 0x4000, 0xe3f: 0x4000,
// Block 0x39, offset 0xe40
0xe40: 0x4000, 0xe41: 0x4000, 0xe42: 0x4000, 0xe43: 0x4000, 0xe44: 0x4000, 0xe45: 0x4000,
0xe46: 0x4000, 0xe47: 0x4000, 0xe48: 0x4000, 0xe49: 0x4000, 0xe4a: 0x4000, 0xe4b: 0x4000,
0xe4c: 0x4000, 0xe4d: 0x4000, 0xe4e: 0x4000, 0xe4f: 0x4000, 0xe50: 0x4000, 0xe51: 0x4000,
0xe52: 0x4000, 0xe53: 0x4000, 0xe54: 0x4000, 0xe55: 0x4000, 0xe56: 0x4000, 0xe57: 0x4000,
0xe58: 0x4000, 0xe59: 0x4000, 0xe5a: 0x4000, 0xe5b: 0x4000, 0xe5c: 0x4000, 0xe5d: 0x4000,
0xe5e: 0x4000, 0xe5f: 0x4000, 0xe60: 0x4000, 0xe61: 0x4000, 0xe62: 0x4000, 0xe63: 0x4000,
0xe70: 0x4000, 0xe71: 0x4000, 0xe72: 0x4000, 0xe73: 0x4000, 0xe74: 0x4000, 0xe75: 0x4000,
0xe76: 0x4000, 0xe77: 0x4000, 0xe78: 0x4000, 0xe79: 0x4000, 0xe7a: 0x4000, 0xe7b: 0x4000,
0xe7c: 0x4000, 0xe7d: 0x4000, 0xe7e: 0x4000, 0xe7f: 0x4000,
// Block 0x3a, offset 0xe80
0xe80: 0x4000, 0xe81: 0x4000, 0xe82: 0x4000, 0xe83: 0x4000, 0xe84: 0x4000, 0xe85: 0x4000,
0xe86: 0x4000, 0xe87: 0x4000, 0xe88: 0x4000, 0xe89: 0x4000, 0xe8a: 0x4000, 0xe8b: 0x4000,
0xe8c: 0x4000, 0xe8d: 0x4000, 0xe8e: 0x4000, 0xe8f: 0x4000, 0xe90: 0x4000, 0xe91: 0x4000,
0xe92: 0x4000, 0xe93: 0x4000, 0xe94: 0x4000, 0xe95: 0x4000, 0xe96: 0x4000, 0xe97: 0x4000,
0xe98: 0x4000, 0xe99: 0x4000, 0xe9a: 0x4000, 0xe9b: 0x4000, 0xe9c: 0x4000, 0xe9d: 0x4000,
0xe9e: 0x4000, 0xea0: 0x4000, 0xea1: 0x4000, 0xea2: 0x4000, 0xea3: 0x4000,
0xea4: 0x4000, 0xea5: 0x4000, 0xea6: 0x4000, 0xea7: 0x4000, 0xea8: 0x4000, 0xea9: 0x4000,
0xeaa: 0x4000, 0xeab: 0x4000, 0xeac: 0x4000, 0xead: 0x4000, 0xeae: 0x4000, 0xeaf: 0x4000,
0xeb0: 0x4000, 0xeb1: 0x4000, 0xeb2: 0x4000, 0xeb3: 0x4000, 0xeb4: 0x4000, 0xeb5: 0x4000,
0xeb6: 0x4000, 0xeb7: 0x4000, 0xeb8: 0x4000, 0xeb9: 0x4000, 0xeba: 0x4000, 0xebb: 0x4000,
0xebc: 0x4000, 0xebd: 0x4000, 0xebe: 0x4000, 0xebf: 0x4000,
// Block 0x3b, offset 0xec0
0xec0: 0x4000, 0xec1: 0x4000, 0xec2: 0x4000, 0xec3: 0x4000, 0xec4: 0x4000, 0xec5: 0x4000,
0xec6: 0x4000, 0xec7: 0x4000, 0xec8: 0x2000, 0xec9: 0x2000, 0xeca: 0x2000, 0xecb: 0x2000,
0xecc: 0x2000, 0xecd: 0x2000, 0xece: 0x2000, 0xecf: 0x2000, 0xed0: 0x4000, 0xed1: 0x4000,
0xed2: 0x4000, 0xed3: 0x4000, 0xed4: 0x4000, 0xed5: 0x4000, 0xed6: 0x4000, 0xed7: 0x4000,
0xed8: 0x4000, 0xed9: 0x4000, 0xeda: 0x4000, 0xedb: 0x4000, 0xedc: 0x4000, 0xedd: 0x4000,
0xede: 0x4000, 0xedf: 0x4000, 0xee0: 0x4000, 0xee1: 0x4000, 0xee2: 0x4000, 0xee3: 0x4000,
0xee4: 0x4000, 0xee5: 0x4000, 0xee6: 0x4000, 0xee7: 0x4000, 0xee8: 0x4000, 0xee9: 0x4000,
0xeea: 0x4000, 0xeeb: 0x4000, 0xeec: 0x4000, 0xeed: 0x4000, 0xeee: 0x4000, 0xeef: 0x4000,
0xef0: 0x4000, 0xef1: 0x4000, 0xef2: 0x4000, 0xef3: 0x4000, 0xef4: 0x4000, 0xef5: 0x4000,
0xef6: 0x4000, 0xef7: 0x4000, 0xef8: 0x4000, 0xef9: 0x4000, 0xefa: 0x4000, 0xefb: 0x4000,
0xefc: 0x4000, 0xefd: 0x4000, 0xefe: 0x4000, 0xeff: 0x4000,
// Block 0x3c, offset 0xf00
0xf00: 0x4000, 0xf01: 0x4000, 0xf02: 0x4000, 0xf03: 0x4000, 0xf04: 0x4000, 0xf05: 0x4000,
0xf06: 0x4000, 0xf07: 0x4000, 0xf08: 0x4000, 0xf09: 0x4000, 0xf0a: 0x4000, 0xf0b: 0x4000,
0xf0c: 0x4000, 0xf10: 0x4000, 0xf11: 0x4000,
0xf12: 0x4000, 0xf13: 0x4000, 0xf14: 0x4000, 0xf15: 0x4000, 0xf16: 0x4000, 0xf17: 0x4000,
0xf18: 0x4000, 0xf19: 0x4000, 0xf1a: 0x4000, 0xf1b: 0x4000, 0xf1c: 0x4000, 0xf1d: 0x4000,
0xf1e: 0x4000, 0xf1f: 0x4000, 0xf20: 0x4000, 0xf21: 0x4000, 0xf22: 0x4000, 0xf23: 0x4000,
0xf24: 0x4000, 0xf25: 0x4000, 0xf26: 0x4000, 0xf27: 0x4000, 0xf28: 0x4000, 0xf29: 0x4000,
0xf2a: 0x4000, 0xf2b: 0x4000, 0xf2c: 0x4000, 0xf2d: 0x4000, 0xf2e: 0x4000, 0xf2f: 0x4000,
0xf30: 0x4000, 0xf31: 0x4000, 0xf32: 0x4000, 0xf33: 0x4000, 0xf34: 0x4000, 0xf35: 0x4000,
0xf36: 0x4000, 0xf37: 0x4000, 0xf38: 0x4000, 0xf39: 0x4000, 0xf3a: 0x4000, 0xf3b: 0x4000,
0xf3c: 0x4000, 0xf3d: 0x4000, 0xf3e: 0x4000, 0xf3f: 0x4000,
// Block 0x3d, offset 0xf40
0xf40: 0x4000, 0xf41: 0x4000, 0xf42: 0x4000, 0xf43: 0x4000, 0xf44: 0x4000, 0xf45: 0x4000,
0xf46: 0x4000,
// Block 0x3e, offset 0xf80
0xfa0: 0x4000, 0xfa1: 0x4000, 0xfa2: 0x4000, 0xfa3: 0x4000,
0xfa4: 0x4000, 0xfa5: 0x4000, 0xfa6: 0x4000, 0xfa7: 0x4000, 0xfa8: 0x4000, 0xfa9: 0x4000,
0xfaa: 0x4000, 0xfab: 0x4000, 0xfac: 0x4000, 0xfad: 0x4000, 0xfae: 0x4000, 0xfaf: 0x4000,
0xfb0: 0x4000, 0xfb1: 0x4000, 0xfb2: 0x4000, 0xfb3: 0x4000, 0xfb4: 0x4000, 0xfb5: 0x4000,
0xfb6: 0x4000, 0xfb7: 0x4000, 0xfb8: 0x4000, 0xfb9: 0x4000, 0xfba: 0x4000, 0xfbb: 0x4000,
0xfbc: 0x4000,
// Block 0x3f, offset 0xfc0
0xfc0: 0x4000, 0xfc1: 0x4000, 0xfc2: 0x4000, 0xfc3: 0x4000, 0xfc4: 0x4000, 0xfc5: 0x4000,
0xfc6: 0x4000, 0xfc7: 0x4000, 0xfc8: 0x4000, 0xfc9: 0x4000, 0xfca: 0x4000, 0xfcb: 0x4000,
0xfcc: 0x4000, 0xfcd: 0x4000, 0xfce: 0x4000, 0xfcf: 0x4000, 0xfd0: 0x4000, 0xfd1: 0x4000,
0xfd2: 0x4000, 0xfd3: 0x4000, 0xfd4: 0x4000, 0xfd5: 0x4000, 0xfd6: 0x4000, 0xfd7: 0x4000,
0xfd8: 0x4000, 0xfd9: 0x4000, 0xfda: 0x4000, 0xfdb: 0x4000, 0xfdc: 0x4000, 0xfdd: 0x4000,
0xfde: 0x4000, 0xfdf: 0x4000, 0xfe0: 0x4000, 0xfe1: 0x4000, 0xfe2: 0x4000, 0xfe3: 0x4000,
// Block 0x40, offset 0x1000
0x1000: 0x2000, 0x1001: 0x2000, 0x1002: 0x2000, 0x1003: 0x2000, 0x1004: 0x2000, 0x1005: 0x2000,
0x1006: 0x2000, 0x1007: 0x2000, 0x1008: 0x2000, 0x1009: 0x2000, 0x100a: 0x2000, 0x100b: 0x2000,
0x100c: 0x2000, 0x100d: 0x2000, 0x100e: 0x2000, 0x100f: 0x2000, 0x1010: 0x4000, 0x1011: 0x4000,
0x1012: 0x4000, 0x1013: 0x4000, 0x1014: 0x4000, 0x1015: 0x4000, 0x1016: 0x4000, 0x1017: 0x4000,
0x1018: 0x4000, 0x1019: 0x4000,
0x1030: 0x4000, 0x1031: 0x4000, 0x1032: 0x4000, 0x1033: 0x4000, 0x1034: 0x4000, 0x1035: 0x4000,
0x1036: 0x4000, 0x1037: 0x4000, 0x1038: 0x4000, 0x1039: 0x4000, 0x103a: 0x4000, 0x103b: 0x4000,
0x103c: 0x4000, 0x103d: 0x4000, 0x103e: 0x4000, 0x103f: 0x4000,
// Block 0x41, offset 0x1040
0x1040: 0x4000, 0x1041: 0x4000, 0x1042: 0x4000, 0x1043: 0x4000, 0x1044: 0x4000, 0x1045: 0x4000,
0x1046: 0x4000, 0x1047: 0x4000, 0x1048: 0x4000, 0x1049: 0x4000, 0x104a: 0x4000, 0x104b: 0x4000,
0x104c: 0x4000, 0x104d: 0x4000, 0x104e: 0x4000, 0x104f: 0x4000, 0x1050: 0x4000, 0x1051: 0x4000,
0x1052: 0x4000, 0x1054: 0x4000, 0x1055: 0x4000, 0x1056: 0x4000, 0x1057: 0x4000,
0x1058: 0x4000, 0x1059: 0x4000, 0x105a: 0x4000, 0x105b: 0x4000, 0x105c: 0x4000, 0x105d: 0x4000,
0x105e: 0x4000, 0x105f: 0x4000, 0x1060: 0x4000, 0x1061: 0x4000, 0x1062: 0x4000, 0x1063: 0x4000,
0x1064: 0x4000, 0x1065: 0x4000, 0x1066: 0x4000, 0x1068: 0x4000, 0x1069: 0x4000,
0x106a: 0x4000, 0x106b: 0x4000,
// Block 0x42, offset 0x1080
0x1081: 0x9012, 0x1082: 0x9012, 0x1083: 0x9012, 0x1084: 0x9012, 0x1085: 0x9012,
0x1086: 0x9012, 0x1087: 0x9012, 0x1088: 0x9012, 0x1089: 0x9012, 0x108a: 0x9012, 0x108b: 0x9012,
0x108c: 0x9012, 0x108d: 0x9012, 0x108e: 0x9012, 0x108f: 0x9012, 0x1090: 0x9012, 0x1091: 0x9012,
0x1092: 0x9012, 0x1093: 0x9012, 0x1094: 0x9012, 0x1095: 0x9012, 0x1096: 0x9012, 0x1097: 0x9012,
0x1098: 0x9012, 0x1099: 0x9012, 0x109a: 0x9012, 0x109b: 0x9012, 0x109c: 0x9012, 0x109d: 0x9012,
0x109e: 0x9012, 0x109f: 0x9012, 0x10a0: 0x9049, 0x10a1: 0x9049, 0x10a2: 0x9049, 0x10a3: 0x9049,
0x10a4: 0x9049, 0x10a5: 0x9049, 0x10a6: 0x9049, 0x10a7: 0x9049, 0x10a8: 0x9049, 0x10a9: 0x9049,
0x10aa: 0x9049, 0x10ab: 0x9049, 0x10ac: 0x9049, 0x10ad: 0x9049, 0x10ae: 0x9049, 0x10af: 0x9049,
0x10b0: 0x9049, 0x10b1: 0x9049, 0x10b2: 0x9049, 0x10b3: 0x9049, 0x10b4: 0x9049, 0x10b5: 0x9049,
0x10b6: 0x9049, 0x10b7: 0x9049, 0x10b8: 0x9049, 0x10b9: 0x9049, 0x10ba: 0x9049, 0x10bb: 0x9049,
0x10bc: 0x9049, 0x10bd: 0x9049, 0x10be: 0x9049, 0x10bf: 0x9049,
// Block 0x43, offset 0x10c0
0x10c0: 0x9049, 0x10c1: 0x9049, 0x10c2: 0x9049, 0x10c3: 0x9049, 0x10c4: 0x9049, 0x10c5: 0x9049,
0x10c6: 0x9049, 0x10c7: 0x9049, 0x10c8: 0x9049, 0x10c9: 0x9049, 0x10ca: 0x9049, 0x10cb: 0x9049,
0x10cc: 0x9049, 0x10cd: 0x9049, 0x10ce: 0x9049, 0x10cf: 0x9049, 0x10d0: 0x9049, 0x10d1: 0x9049,
0x10d2: 0x9049, 0x10d3: 0x9049, 0x10d4: 0x9049, 0x10d5: 0x9049, 0x10d6: 0x9049, 0x10d7: 0x9049,
0x10d8: 0x9049, 0x10d9: 0x9049, 0x10da: 0x9049, 0x10db: 0x9049, 0x10dc: 0x9049, 0x10dd: 0x9049,
0x10de: 0x9049, 0x10df: 0x904a, 0x10e0: 0x904b, 0x10e1: 0xb04c, 0x10e2: 0xb04d, 0x10e3: 0xb04d,
0x10e4: 0xb04e, 0x10e5: 0xb04f, 0x10e6: 0xb050, 0x10e7: 0xb051, 0x10e8: 0xb052, 0x10e9: 0xb053,
0x10ea: 0xb054, 0x10eb: 0xb055, 0x10ec: 0xb056, 0x10ed: 0xb057, 0x10ee: 0xb058, 0x10ef: 0xb059,
0x10f0: 0xb05a, 0x10f1: 0xb05b, 0x10f2: 0xb05c, 0x10f3: 0xb05d, 0x10f4: 0xb05e, 0x10f5: 0xb05f,
0x10f6: 0xb060, 0x10f7: 0xb061, 0x10f8: 0xb062, 0x10f9: 0xb063, 0x10fa: 0xb064, 0x10fb: 0xb065,
0x10fc: 0xb052, 0x10fd: 0xb066, 0x10fe: 0xb067, 0x10ff: 0xb055,
// Block 0x44, offset 0x1100
0x1100: 0xb068, 0x1101: 0xb069, 0x1102: 0xb06a, 0x1103: 0xb06b, 0x1104: 0xb05a, 0x1105: 0xb056,
0x1106: 0xb06c, 0x1107: 0xb06d, 0x1108: 0xb06b, 0x1109: 0xb06e, 0x110a: 0xb06b, 0x110b: 0xb06f,
0x110c: 0xb06f, 0x110d: 0xb070, 0x110e: 0xb070, 0x110f: 0xb071, 0x1110: 0xb056, 0x1111: 0xb072,
0x1112: 0xb073, 0x1113: 0xb072, 0x1114: 0xb074, 0x1115: 0xb073, 0x1116: 0xb075, 0x1117: 0xb075,
0x1118: 0xb076, 0x1119: 0xb076, 0x111a: 0xb077, 0x111b: 0xb077, 0x111c: 0xb073, 0x111d: 0xb078,
0x111e: 0xb079, 0x111f: 0xb067, 0x1120: 0xb07a, 0x1121: 0xb07b, 0x1122: 0xb07b, 0x1123: 0xb07b,
0x1124: 0xb07b, 0x1125: 0xb07b, 0x1126: 0xb07b, 0x1127: 0xb07b, 0x1128: 0xb07b, 0x1129: 0xb07b,
0x112a: 0xb07b, 0x112b: 0xb07b, 0x112c: 0xb07b, 0x112d: 0xb07b, 0x112e: 0xb07b, 0x112f: 0xb07b,
0x1130: 0xb07c, 0x1131: 0xb07c, 0x1132: 0xb07c, 0x1133: 0xb07c, 0x1134: 0xb07c, 0x1135: 0xb07c,
0x1136: 0xb07c, 0x1137: 0xb07c, 0x1138: 0xb07c, 0x1139: 0xb07c, 0x113a: 0xb07c, 0x113b: 0xb07c,
0x113c: 0xb07c, 0x113d: 0xb07c, 0x113e: 0xb07c,
// Block 0x45, offset 0x1140
0x1142: 0xb07d, 0x1143: 0xb07e, 0x1144: 0xb07f, 0x1145: 0xb080,
0x1146: 0xb07f, 0x1147: 0xb07e, 0x114a: 0xb081, 0x114b: 0xb082,
0x114c: 0xb083, 0x114d: 0xb07f, 0x114e: 0xb080, 0x114f: 0xb07f,
0x1152: 0xb084, 0x1153: 0xb085, 0x1154: 0xb084, 0x1155: 0xb086, 0x1156: 0xb084, 0x1157: 0xb087,
0x115a: 0xb088, 0x115b: 0xb089, 0x115c: 0xb08a,
0x1160: 0x908b, 0x1161: 0x908b, 0x1162: 0x908c, 0x1163: 0x908d,
0x1164: 0x908b, 0x1165: 0x908e, 0x1166: 0x908f, 0x1168: 0xb090, 0x1169: 0xb091,
0x116a: 0xb092, 0x116b: 0xb091, 0x116c: 0xb093, 0x116d: 0xb094, 0x116e: 0xb095,
0x117d: 0x2000,
// Block 0x46, offset 0x1180
0x11a0: 0x4000, 0x11a1: 0x4000, 0x11a2: 0x4000, 0x11a3: 0x4000,
0x11a4: 0x4000,
0x11b0: 0x4000, 0x11b1: 0x4000,
// Block 0x47, offset 0x11c0
0x11c0: 0x4000, 0x11c1: 0x4000, 0x11c2: 0x4000, 0x11c3: 0x4000, 0x11c4: 0x4000, 0x11c5: 0x4000,
0x11c6: 0x4000, 0x11c7: 0x4000, 0x11c8: 0x4000, 0x11c9: 0x4000, 0x11ca: 0x4000, 0x11cb: 0x4000,
0x11cc: 0x4000, 0x11cd: 0x4000, 0x11ce: 0x4000, 0x11cf: 0x4000, 0x11d0: 0x4000, 0x11d1: 0x4000,
0x11d2: 0x4000, 0x11d3: 0x4000, 0x11d4: 0x4000, 0x11d5: 0x4000, 0x11d6: 0x4000, 0x11d7: 0x4000,
0x11d8: 0x4000, 0x11d9: 0x4000, 0x11da: 0x4000, 0x11db: 0x4000, 0x11dc: 0x4000, 0x11dd: 0x4000,
0x11de: 0x4000, 0x11df: 0x4000, 0x11e0: 0x4000, 0x11e1: 0x4000, 0x11e2: 0x4000, 0x11e3: 0x4000,
0x11e4: 0x4000, 0x11e5: 0x4000, 0x11e6: 0x4000, 0x11e7: 0x4000, 0x11e8: 0x4000, 0x11e9: 0x4000,
0x11ea: 0x4000, 0x11eb: 0x4000, 0x11ec: 0x4000, 0x11ed: 0x4000, 0x11ee: 0x4000, 0x11ef: 0x4000,
0x11f0: 0x4000, 0x11f1: 0x4000, 0x11f2: 0x4000, 0x11f3: 0x4000, 0x11f4: 0x4000, 0x11f5: 0x4000,
0x11f6: 0x4000, 0x11f7: 0x4000,
// Block 0x48, offset 0x1200
0x1200: 0x4000, 0x1201: 0x4000, 0x1202: 0x4000, 0x1203: 0x4000, 0x1204: 0x4000, 0x1205: 0x4000,
0x1206: 0x4000, 0x1207: 0x4000, 0x1208: 0x4000, 0x1209: 0x4000, 0x120a: 0x4000, 0x120b: 0x4000,
0x120c: 0x4000, 0x120d: 0x4000, 0x120e: 0x4000, 0x120f: 0x4000, 0x1210: 0x4000, 0x1211: 0x4000,
0x1212: 0x4000, 0x1213: 0x4000, 0x1214: 0x4000, 0x1215: 0x4000,
// Block 0x49, offset 0x1240
0x1240: 0x4000, 0x1241: 0x4000, 0x1242: 0x4000, 0x1243: 0x4000, 0x1244: 0x4000, 0x1245: 0x4000,
0x1246: 0x4000, 0x1247: 0x4000, 0x1248: 0x4000,
// Block 0x4a, offset 0x1280
0x12b0: 0x4000, 0x12b1: 0x4000, 0x12b2: 0x4000, 0x12b3: 0x4000, 0x12b5: 0x4000,
0x12b6: 0x4000, 0x12b7: 0x4000, 0x12b8: 0x4000, 0x12b9: 0x4000, 0x12ba: 0x4000, 0x12bb: 0x4000,
0x12bd: 0x4000, 0x12be: 0x4000,
// Block 0x4b, offset 0x12c0
0x12c0: 0x4000, 0x12c1: 0x4000, 0x12c2: 0x4000, 0x12c3: 0x4000, 0x12c4: 0x4000, 0x12c5: 0x4000,
0x12c6: 0x4000, 0x12c7: 0x4000, 0x12c8: 0x4000, 0x12c9: 0x4000, 0x12ca: 0x4000, 0x12cb: 0x4000,
0x12cc: 0x4000, 0x12cd: 0x4000, 0x12ce: 0x4000, 0x12cf: 0x4000, 0x12d0: 0x4000, 0x12d1: 0x4000,
0x12d2: 0x4000, 0x12d3: 0x4000, 0x12d4: 0x4000, 0x12d5: 0x4000, 0x12d6: 0x4000, 0x12d7: 0x4000,
0x12d8: 0x4000, 0x12d9: 0x4000, 0x12da: 0x4000, 0x12db: 0x4000, 0x12dc: 0x4000, 0x12dd: 0x4000,
0x12de: 0x4000, 0x12df: 0x4000, 0x12e0: 0x4000, 0x12e1: 0x4000, 0x12e2: 0x4000,
0x12f2: 0x4000,
// Block 0x4c, offset 0x1300
0x1310: 0x4000, 0x1311: 0x4000,
0x1312: 0x4000, 0x1315: 0x4000,
0x1324: 0x4000, 0x1325: 0x4000, 0x1326: 0x4000, 0x1327: 0x4000,
0x1330: 0x4000, 0x1331: 0x4000, 0x1332: 0x4000, 0x1333: 0x4000, 0x1334: 0x4000, 0x1335: 0x4000,
0x1336: 0x4000, 0x1337: 0x4000, 0x1338: 0x4000, 0x1339: 0x4000, 0x133a: 0x4000, 0x133b: 0x4000,
0x133c: 0x4000, 0x133d: 0x4000, 0x133e: 0x4000, 0x133f: 0x4000,
// Block 0x4d, offset 0x1340
0x1340: 0x4000, 0x1341: 0x4000, 0x1342: 0x4000, 0x1343: 0x4000, 0x1344: 0x4000, 0x1345: 0x4000,
0x1346: 0x4000, 0x1347: 0x4000, 0x1348: 0x4000, 0x1349: 0x4000, 0x134a: 0x4000, 0x134b: 0x4000,
0x134c: 0x4000, 0x134d: 0x4000, 0x134e: 0x4000, 0x134f: 0x4000, 0x1350: 0x4000, 0x1351: 0x4000,
0x1352: 0x4000, 0x1353: 0x4000, 0x1354: 0x4000, 0x1355: 0x4000, 0x1356: 0x4000, 0x1357: 0x4000,
0x1358: 0x4000, 0x1359: 0x4000, 0x135a: 0x4000, 0x135b: 0x4000, 0x135c: 0x4000, 0x135d: 0x4000,
0x135e: 0x4000, 0x135f: 0x4000, 0x1360: 0x4000, 0x1361: 0x4000, 0x1362: 0x4000, 0x1363: 0x4000,
0x1364: 0x4000, 0x1365: 0x4000, 0x1366: 0x4000, 0x1367: 0x4000, 0x1368: 0x4000, 0x1369: 0x4000,
0x136a: 0x4000, 0x136b: 0x4000, 0x136c: 0x4000, 0x136d: 0x4000, 0x136e: 0x4000, 0x136f: 0x4000,
0x1370: 0x4000, 0x1371: 0x4000, 0x1372: 0x4000, 0x1373: 0x4000, 0x1374: 0x4000, 0x1375: 0x4000,
0x1376: 0x4000, 0x1377: 0x4000, 0x1378: 0x4000, 0x1379: 0x4000, 0x137a: 0x4000, 0x137b: 0x4000,
// Block 0x4e, offset 0x1380
0x1384: 0x4000,
// Block 0x4f, offset 0x13c0
0x13cf: 0x4000,
// Block 0x50, offset 0x1400
0x1400: 0x2000, 0x1401: 0x2000, 0x1402: 0x2000, 0x1403: 0x2000, 0x1404: 0x2000, 0x1405: 0x2000,
0x1406: 0x2000, 0x1407: 0x2000, 0x1408: 0x2000, 0x1409: 0x2000, 0x140a: 0x2000,
0x1410: 0x2000, 0x1411: 0x2000,
0x1412: 0x2000, 0x1413: 0x2000, 0x1414: 0x2000, 0x1415: 0x2000, 0x1416: 0x2000, 0x1417: 0x2000,
0x1418: 0x2000, 0x1419: 0x2000, 0x141a: 0x2000, 0x141b: 0x2000, 0x141c: 0x2000, 0x141d: 0x2000,
0x141e: 0x2000, 0x141f: 0x2000, 0x1420: 0x2000, 0x1421: 0x2000, 0x1422: 0x2000, 0x1423: 0x2000,
0x1424: 0x2000, 0x1425: 0x2000, 0x1426: 0x2000, 0x1427: 0x2000, 0x1428: 0x2000, 0x1429: 0x2000,
0x142a: 0x2000, 0x142b: 0x2000, 0x142c: 0x2000, 0x142d: 0x2000,
0x1430: 0x2000, 0x1431: 0x2000, 0x1432: 0x2000, 0x1433: 0x2000, 0x1434: 0x2000, 0x1435: 0x2000,
0x1436: 0x2000, 0x1437: 0x2000, 0x1438: 0x2000, 0x1439: 0x2000, 0x143a: 0x2000, 0x143b: 0x2000,
0x143c: 0x2000, 0x143d: 0x2000, 0x143e: 0x2000, 0x143f: 0x2000,
// Block 0x51, offset 0x1440
0x1440: 0x2000, 0x1441: 0x2000, 0x1442: 0x2000, 0x1443: 0x2000, 0x1444: 0x2000, 0x1445: 0x2000,
0x1446: 0x2000, 0x1447: 0x2000, 0x1448: 0x2000, 0x1449: 0x2000, 0x144a: 0x2000, 0x144b: 0x2000,
0x144c: 0x2000, 0x144d: 0x2000, 0x144e: 0x2000, 0x144f: 0x2000, 0x1450: 0x2000, 0x1451: 0x2000,
0x1452: 0x2000, 0x1453: 0x2000, 0x1454: 0x2000, 0x1455: 0x2000, 0x1456: 0x2000, 0x1457: 0x2000,
0x1458: 0x2000, 0x1459: 0x2000, 0x145a: 0x2000, 0x145b: 0x2000, 0x145c: 0x2000, 0x145d: 0x2000,
0x145e: 0x2000, 0x145f: 0x2000, 0x1460: 0x2000, 0x1461: 0x2000, 0x1462: 0x2000, 0x1463: 0x2000,
0x1464: 0x2000, 0x1465: 0x2000, 0x1466: 0x2000, 0x1467: 0x2000, 0x1468: 0x2000, 0x1469: 0x2000,
0x1470: 0x2000, 0x1471: 0x2000, 0x1472: 0x2000, 0x1473: 0x2000, 0x1474: 0x2000, 0x1475: 0x2000,
0x1476: 0x2000, 0x1477: 0x2000, 0x1478: 0x2000, 0x1479: 0x2000, 0x147a: 0x2000, 0x147b: 0x2000,
0x147c: 0x2000, 0x147d: 0x2000, 0x147e: 0x2000, 0x147f: 0x2000,
// Block 0x52, offset 0x1480
0x1480: 0x2000, 0x1481: 0x2000, 0x1482: 0x2000, 0x1483: 0x2000, 0x1484: 0x2000, 0x1485: 0x2000,
0x1486: 0x2000, 0x1487: 0x2000, 0x1488: 0x2000, 0x1489: 0x2000, 0x148a: 0x2000, 0x148b: 0x2000,
0x148c: 0x2000, 0x148d: 0x2000, 0x148e: 0x4000, 0x148f: 0x2000, 0x1490: 0x2000, 0x1491: 0x4000,
0x1492: 0x4000, 0x1493: 0x4000, 0x1494: 0x4000, 0x1495: 0x4000, 0x1496: 0x4000, 0x1497: 0x4000,
0x1498: 0x4000, 0x1499: 0x4000, 0x149a: 0x4000, 0x149b: 0x2000, 0x149c: 0x2000, 0x149d: 0x2000,
0x149e: 0x2000, 0x149f: 0x2000, 0x14a0: 0x2000, 0x14a1: 0x2000, 0x14a2: 0x2000, 0x14a3: 0x2000,
0x14a4: 0x2000, 0x14a5: 0x2000, 0x14a6: 0x2000, 0x14a7: 0x2000, 0x14a8: 0x2000, 0x14a9: 0x2000,
0x14aa: 0x2000, 0x14ab: 0x2000, 0x14ac: 0x2000,
// Block 0x53, offset 0x14c0
0x14c0: 0x4000, 0x14c1: 0x4000, 0x14c2: 0x4000,
0x14d0: 0x4000, 0x14d1: 0x4000,
0x14d2: 0x4000, 0x14d3: 0x4000, 0x14d4: 0x4000, 0x14d5: 0x4000, 0x14d6: 0x4000, 0x14d7: 0x4000,
0x14d8: 0x4000, 0x14d9: 0x4000, 0x14da: 0x4000, 0x14db: 0x4000, 0x14dc: 0x4000, 0x14dd: 0x4000,
0x14de: 0x4000, 0x14df: 0x4000, 0x14e0: 0x4000, 0x14e1: 0x4000, 0x14e2: 0x4000, 0x14e3: 0x4000,
0x14e4: 0x4000, 0x14e5: 0x4000, 0x14e6: 0x4000, 0x14e7: 0x4000, 0x14e8: 0x4000, 0x14e9: 0x4000,
0x14ea: 0x4000, 0x14eb: 0x4000, 0x14ec: 0x4000, 0x14ed: 0x4000, 0x14ee: 0x4000, 0x14ef: 0x4000,
0x14f0: 0x4000, 0x14f1: 0x4000, 0x14f2: 0x4000, 0x14f3: 0x4000, 0x14f4: 0x4000, 0x14f5: 0x4000,
0x14f6: 0x4000, 0x14f7: 0x4000, 0x14f8: 0x4000, 0x14f9: 0x4000, 0x14fa: 0x4000, 0x14fb: 0x4000,
// Block 0x54, offset 0x1500
0x1500: 0x4000, 0x1501: 0x4000, 0x1502: 0x4000, 0x1503: 0x4000, 0x1504: 0x4000, 0x1505: 0x4000,
0x1506: 0x4000, 0x1507: 0x4000, 0x1508: 0x4000,
0x1510: 0x4000, 0x1511: 0x4000,
0x1520: 0x4000, 0x1521: 0x4000, 0x1522: 0x4000, 0x1523: 0x4000,
0x1524: 0x4000, 0x1525: 0x4000,
// Block 0x55, offset 0x1540
0x1540: 0x4000, 0x1541: 0x4000, 0x1542: 0x4000, 0x1543: 0x4000, 0x1544: 0x4000, 0x1545: 0x4000,
0x1546: 0x4000, 0x1547: 0x4000, 0x1548: 0x4000, 0x1549: 0x4000, 0x154a: 0x4000, 0x154b: 0x4000,
0x154c: 0x4000, 0x154d: 0x4000, 0x154e: 0x4000, 0x154f: 0x4000, 0x1550: 0x4000, 0x1551: 0x4000,
0x1552: 0x4000, 0x1553: 0x4000, 0x1554: 0x4000, 0x1555: 0x4000, 0x1556: 0x4000, 0x1557: 0x4000,
0x1558: 0x4000, 0x1559: 0x4000, 0x155a: 0x4000, 0x155b: 0x4000, 0x155c: 0x4000, 0x155d: 0x4000,
0x155e: 0x4000, 0x155f: 0x4000, 0x1560: 0x4000,
0x156d: 0x4000, 0x156e: 0x4000, 0x156f: 0x4000,
0x1570: 0x4000, 0x1571: 0x4000, 0x1572: 0x4000, 0x1573: 0x4000, 0x1574: 0x4000, 0x1575: 0x4000,
0x1577: 0x4000, 0x1578: 0x4000, 0x1579: 0x4000, 0x157a: 0x4000, 0x157b: 0x4000,
0x157c: 0x4000, 0x157d: 0x4000, 0x157e: 0x4000, 0x157f: 0x4000,
// Block 0x56, offset 0x1580
0x1580: 0x4000, 0x1581: 0x4000, 0x1582: 0x4000, 0x1583: 0x4000, 0x1584: 0x4000, 0x1585: 0x4000,
0x1586: 0x4000, 0x1587: 0x4000, 0x1588: 0x4000, 0x1589: 0x4000, 0x158a: 0x4000, 0x158b: 0x4000,
0x158c: 0x4000, 0x158d: 0x4000, 0x158e: 0x4000, 0x158f: 0x4000, 0x1590: 0x4000, 0x1591: 0x4000,
0x1592: 0x4000, 0x1593: 0x4000, 0x1594: 0x4000, 0x1595: 0x4000, 0x1596: 0x4000, 0x1597: 0x4000,
0x1598: 0x4000, 0x1599: 0x4000, 0x159a: 0x4000, 0x159b: 0x4000, 0x159c: 0x4000, 0x159d: 0x4000,
0x159e: 0x4000, 0x159f: 0x4000, 0x15a0: 0x4000, 0x15a1: 0x4000, 0x15a2: 0x4000, 0x15a3: 0x4000,
0x15a4: 0x4000, 0x15a5: 0x4000, 0x15a6: 0x4000, 0x15a7: 0x4000, 0x15a8: 0x4000, 0x15a9: 0x4000,
0x15aa: 0x4000, 0x15ab: 0x4000, 0x15ac: 0x4000, 0x15ad: 0x4000, 0x15ae: 0x4000, 0x15af: 0x4000,
0x15b0: 0x4000, 0x15b1: 0x4000, 0x15b2: 0x4000, 0x15b3: 0x4000, 0x15b4: 0x4000, 0x15b5: 0x4000,
0x15b6: 0x4000, 0x15b7: 0x4000, 0x15b8: 0x4000, 0x15b9: 0x4000, 0x15ba: 0x4000, 0x15bb: 0x4000,
0x15bc: 0x4000, 0x15be: 0x4000, 0x15bf: 0x4000,
// Block 0x57, offset 0x15c0
0x15c0: 0x4000, 0x15c1: 0x4000, 0x15c2: 0x4000, 0x15c3: 0x4000, 0x15c4: 0x4000, 0x15c5: 0x4000,
0x15c6: 0x4000, 0x15c7: 0x4000, 0x15c8: 0x4000, 0x15c9: 0x4000, 0x15ca: 0x4000, 0x15cb: 0x4000,
0x15cc: 0x4000, 0x15cd: 0x4000, 0x15ce: 0x4000, 0x15cf: 0x4000, 0x15d0: 0x4000, 0x15d1: 0x4000,
0x15d2: 0x4000, 0x15d3: 0x4000,
0x15e0: 0x4000, 0x15e1: 0x4000, 0x15e2: 0x4000, 0x15e3: 0x4000,
0x15e4: 0x4000, 0x15e5: 0x4000, 0x15e6: 0x4000, 0x15e7: 0x4000, 0x15e8: 0x4000, 0x15e9: 0x4000,
0x15ea: 0x4000, 0x15eb: 0x4000, 0x15ec: 0x4000, 0x15ed: 0x4000, 0x15ee: 0x4000, 0x15ef: 0x4000,
0x15f0: 0x4000, 0x15f1: 0x4000, 0x15f2: 0x4000, 0x15f3: 0x4000, 0x15f4: 0x4000, 0x15f5: 0x4000,
0x15f6: 0x4000, 0x15f7: 0x4000, 0x15f8: 0x4000, 0x15f9: 0x4000, 0x15fa: 0x4000, 0x15fb: 0x4000,
0x15fc: 0x4000, 0x15fd: 0x4000, 0x15fe: 0x4000, 0x15ff: 0x4000,
// Block 0x58, offset 0x1600
0x1600: 0x4000, 0x1601: 0x4000, 0x1602: 0x4000, 0x1603: 0x4000, 0x1604: 0x4000, 0x1605: 0x4000,
0x1606: 0x4000, 0x1607: 0x4000, 0x1608: 0x4000, 0x1609: 0x4000, 0x160a: 0x4000,
0x160f: 0x4000, 0x1610: 0x4000, 0x1611: 0x4000,
0x1612: 0x4000, 0x1613: 0x4000,
0x1620: 0x4000, 0x1621: 0x4000, 0x1622: 0x4000, 0x1623: 0x4000,
0x1624: 0x4000, 0x1625: 0x4000, 0x1626: 0x4000, 0x1627: 0x4000, 0x1628: 0x4000, 0x1629: 0x4000,
0x162a: 0x4000, 0x162b: 0x4000, 0x162c: 0x4000, 0x162d: 0x4000, 0x162e: 0x4000, 0x162f: 0x4000,
0x1630: 0x4000, 0x1634: 0x4000,
0x1638: 0x4000, 0x1639: 0x4000, 0x163a: 0x4000, 0x163b: 0x4000,
0x163c: 0x4000, 0x163d: 0x4000, 0x163e: 0x4000, 0x163f: 0x4000,
// Block 0x59, offset 0x1640
0x1640: 0x4000, 0x1641: 0x4000, 0x1642: 0x4000, 0x1643: 0x4000, 0x1644: 0x4000, 0x1645: 0x4000,
0x1646: 0x4000, 0x1647: 0x4000, 0x1648: 0x4000, 0x1649: 0x4000, 0x164a: 0x4000, 0x164b: 0x4000,
0x164c: 0x4000, 0x164d: 0x4000, 0x164e: 0x4000, 0x164f: 0x4000, 0x1650: 0x4000, 0x1651: 0x4000,
0x1652: 0x4000, 0x1653: 0x4000, 0x1654: 0x4000, 0x1655: 0x4000, 0x1656: 0x4000, 0x1657: 0x4000,
0x1658: 0x4000, 0x1659: 0x4000, 0x165a: 0x4000, 0x165b: 0x4000, 0x165c: 0x4000, 0x165d: 0x4000,
0x165e: 0x4000, 0x165f: 0x4000, 0x1660: 0x4000, 0x1661: 0x4000, 0x1662: 0x4000, 0x1663: 0x4000,
0x1664: 0x4000, 0x1665: 0x4000, 0x1666: 0x4000, 0x1667: 0x4000, 0x1668: 0x4000, 0x1669: 0x4000,
0x166a: 0x4000, 0x166b: 0x4000, 0x166c: 0x4000, 0x166d: 0x4000, 0x166e: 0x4000, 0x166f: 0x4000,
0x1670: 0x4000, 0x1671: 0x4000, 0x1672: 0x4000, 0x1673: 0x4000, 0x1674: 0x4000, 0x1675: 0x4000,
0x1676: 0x4000, 0x1677: 0x4000, 0x1678: 0x4000, 0x1679: 0x4000, 0x167a: 0x4000, 0x167b: 0x4000,
0x167c: 0x4000, 0x167d: 0x4000, 0x167e: 0x4000,
// Block 0x5a, offset 0x1680
0x1680: 0x4000, 0x1682: 0x4000, 0x1683: 0x4000, 0x1684: 0x4000, 0x1685: 0x4000,
0x1686: 0x4000, 0x1687: 0x4000, 0x1688: 0x4000, 0x1689: 0x4000, 0x168a: 0x4000, 0x168b: 0x4000,
0x168c: 0x4000, 0x168d: 0x4000, 0x168e: 0x4000, 0x168f: 0x4000, 0x1690: 0x4000, 0x1691: 0x4000,
0x1692: 0x4000, 0x1693: 0x4000, 0x1694: 0x4000, 0x1695: 0x4000, 0x1696: 0x4000, 0x1697: 0x4000,
0x1698: 0x4000, 0x1699: 0x4000, 0x169a: 0x4000, 0x169b: 0x4000, 0x169c: 0x4000, 0x169d: 0x4000,
0x169e: 0x4000, 0x169f: 0x4000, 0x16a0: 0x4000, 0x16a1: 0x4000, 0x16a2: 0x4000, 0x16a3: 0x4000,
0x16a4: 0x4000, 0x16a5: 0x4000, 0x16a6: 0x4000, 0x16a7: 0x4000, 0x16a8: 0x4000, 0x16a9: 0x4000,
0x16aa: 0x4000, 0x16ab: 0x4000, 0x16ac: 0x4000, 0x16ad: 0x4000, 0x16ae: 0x4000, 0x16af: 0x4000,
0x16b0: 0x4000, 0x16b1: 0x4000, 0x16b2: 0x4000, 0x16b3: 0x4000, 0x16b4: 0x4000, 0x16b5: 0x4000,
0x16b6: 0x4000, 0x16b7: 0x4000, 0x16b8: 0x4000, 0x16b9: 0x4000, 0x16ba: 0x4000, 0x16bb: 0x4000,
0x16bc: 0x4000, 0x16bd: 0x4000, 0x16be: 0x4000, 0x16bf: 0x4000,
// Block 0x5b, offset 0x16c0
0x16c0: 0x4000, 0x16c1: 0x4000, 0x16c2: 0x4000, 0x16c3: 0x4000, 0x16c4: 0x4000, 0x16c5: 0x4000,
0x16c6: 0x4000, 0x16c7: 0x4000, 0x16c8: 0x4000, 0x16c9: 0x4000, 0x16ca: 0x4000, 0x16cb: 0x4000,
0x16cc: 0x4000, 0x16cd: 0x4000, 0x16ce: 0x4000, 0x16cf: 0x4000, 0x16d0: 0x4000, 0x16d1: 0x4000,
0x16d2: 0x4000, 0x16d3: 0x4000, 0x16d4: 0x4000, 0x16d5: 0x4000, 0x16d6: 0x4000, 0x16d7: 0x4000,
0x16d8: 0x4000, 0x16d9: 0x4000, 0x16da: 0x4000, 0x16db: 0x4000, 0x16dc: 0x4000, 0x16dd: 0x4000,
0x16de: 0x4000, 0x16df: 0x4000, 0x16e0: 0x4000, 0x16e1: 0x4000, 0x16e2: 0x4000, 0x16e3: 0x4000,
0x16e4: 0x4000, 0x16e5: 0x4000, 0x16e6: 0x4000, 0x16e7: 0x4000, 0x16e8: 0x4000, 0x16e9: 0x4000,
0x16ea: 0x4000, 0x16eb: 0x4000, 0x16ec: 0x4000, 0x16ed: 0x4000, 0x16ee: 0x4000, 0x16ef: 0x4000,
0x16f0: 0x4000, 0x16f1: 0x4000, 0x16f2: 0x4000, 0x16f3: 0x4000, 0x16f4: 0x4000, 0x16f5: 0x4000,
0x16f6: 0x4000, 0x16f7: 0x4000, 0x16f8: 0x4000, 0x16f9: 0x4000, 0x16fa: 0x4000, 0x16fb: 0x4000,
0x16fc: 0x4000, 0x16ff: 0x4000,
// Block 0x5c, offset 0x1700
0x1700: 0x4000, 0x1701: 0x4000, 0x1702: 0x4000, 0x1703: 0x4000, 0x1704: 0x4000, 0x1705: 0x4000,
0x1706: 0x4000, 0x1707: 0x4000, 0x1708: 0x4000, 0x1709: 0x4000, 0x170a: 0x4000, 0x170b: 0x4000,
0x170c: 0x4000, 0x170d: 0x4000, 0x170e: 0x4000, 0x170f: 0x4000, 0x1710: 0x4000, 0x1711: 0x4000,
0x1712: 0x4000, 0x1713: 0x4000, 0x1714: 0x4000, 0x1715: 0x4000, 0x1716: 0x4000, 0x1717: 0x4000,
0x1718: 0x4000, 0x1719: 0x4000, 0x171a: 0x4000, 0x171b: 0x4000, 0x171c: 0x4000, 0x171d: 0x4000,
0x171e: 0x4000, 0x171f: 0x4000, 0x1720: 0x4000, 0x1721: 0x4000, 0x1722: 0x4000, 0x1723: 0x4000,
0x1724: 0x4000, 0x1725: 0x4000, 0x1726: 0x4000, 0x1727: 0x4000, 0x1728: 0x4000, 0x1729: 0x4000,
0x172a: 0x4000, 0x172b: 0x4000, 0x172c: 0x4000, 0x172d: 0x4000, 0x172e: 0x4000, 0x172f: 0x4000,
0x1730: 0x4000, 0x1731: 0x4000, 0x1732: 0x4000, 0x1733: 0x4000, 0x1734: 0x4000, 0x1735: 0x4000,
0x1736: 0x4000, 0x1737: 0x4000, 0x1738: 0x4000, 0x1739: 0x4000, 0x173a: 0x4000, 0x173b: 0x4000,
0x173c: 0x4000, 0x173d: 0x4000,
// Block 0x5d, offset 0x1740
0x174b: 0x4000,
0x174c: 0x4000, 0x174d: 0x4000, 0x174e: 0x4000, 0x1750: 0x4000, 0x1751: 0x4000,
0x1752: 0x4000, 0x1753: 0x4000, 0x1754: 0x4000, 0x1755: 0x4000, 0x1756: 0x4000, 0x1757: 0x4000,
0x1758: 0x4000, 0x1759: 0x4000, 0x175a: 0x4000, 0x175b: 0x4000, 0x175c: 0x4000, 0x175d: 0x4000,
0x175e: 0x4000, 0x175f: 0x4000, 0x1760: 0x4000, 0x1761: 0x4000, 0x1762: 0x4000, 0x1763: 0x4000,
0x1764: 0x4000, 0x1765: 0x4000, 0x1766: 0x4000, 0x1767: 0x4000,
0x177a: 0x4000,
// Block 0x5e, offset 0x1780
0x1795: 0x4000, 0x1796: 0x4000,
0x17a4: 0x4000,
// Block 0x5f, offset 0x17c0
0x17fb: 0x4000,
0x17fc: 0x4000, 0x17fd: 0x4000, 0x17fe: 0x4000, 0x17ff: 0x4000,
// Block 0x60, offset 0x1800
0x1800: 0x4000, 0x1801: 0x4000, 0x1802: 0x4000, 0x1803: 0x4000, 0x1804: 0x4000, 0x1805: 0x4000,
0x1806: 0x4000, 0x1807: 0x4000, 0x1808: 0x4000, 0x1809: 0x4000, 0x180a: 0x4000, 0x180b: 0x4000,
0x180c: 0x4000, 0x180d: 0x4000, 0x180e: 0x4000, 0x180f: 0x4000,
// Block 0x61, offset 0x1840
0x1840: 0x4000, 0x1841: 0x4000, 0x1842: 0x4000, 0x1843: 0x4000, 0x1844: 0x4000, 0x1845: 0x4000,
0x184c: 0x4000, 0x1850: 0x4000, 0x1851: 0x4000,
0x1852: 0x4000, 0x1855: 0x4000, 0x1856: 0x4000, 0x1857: 0x4000,
0x185c: 0x4000, 0x185d: 0x4000,
0x185e: 0x4000, 0x185f: 0x4000,
0x186b: 0x4000, 0x186c: 0x4000,
0x1874: 0x4000, 0x1875: 0x4000,
0x1876: 0x4000, 0x1877: 0x4000, 0x1878: 0x4000, 0x1879: 0x4000, 0x187a: 0x4000, 0x187b: 0x4000,
0x187c: 0x4000,
// Block 0x62, offset 0x1880
0x18a0: 0x4000, 0x18a1: 0x4000, 0x18a2: 0x4000, 0x18a3: 0x4000,
0x18a4: 0x4000, 0x18a5: 0x4000, 0x18a6: 0x4000, 0x18a7: 0x4000, 0x18a8: 0x4000, 0x18a9: 0x4000,
0x18aa: 0x4000, 0x18ab: 0x4000,
0x18b0: 0x4000,
// Block 0x63, offset 0x18c0
0x18cc: 0x4000, 0x18cd: 0x4000, 0x18ce: 0x4000, 0x18cf: 0x4000, 0x18d0: 0x4000, 0x18d1: 0x4000,
0x18d2: 0x4000, 0x18d3: 0x4000, 0x18d4: 0x4000, 0x18d5: 0x4000, 0x18d6: 0x4000, 0x18d7: 0x4000,
0x18d8: 0x4000, 0x18d9: 0x4000, 0x18da: 0x4000, 0x18db: 0x4000, 0x18dc: 0x4000, 0x18dd: 0x4000,
0x18de: 0x4000, 0x18df: 0x4000, 0x18e0: 0x4000, 0x18e1: 0x4000, 0x18e2: 0x4000, 0x18e3: 0x4000,
0x18e4: 0x4000, 0x18e5: 0x4000, 0x18e6: 0x4000, 0x18e7: 0x4000, 0x18e8: 0x4000, 0x18e9: 0x4000,
0x18ea: 0x4000, 0x18eb: 0x4000, 0x18ec: 0x4000, 0x18ed: 0x4000, 0x18ee: 0x4000, 0x18ef: 0x4000,
0x18f0: 0x4000, 0x18f1: 0x4000, 0x18f2: 0x4000, 0x18f3: 0x4000, 0x18f4: 0x4000, 0x18f5: 0x4000,
0x18f6: 0x4000, 0x18f7: 0x4000, 0x18f8: 0x4000, 0x18f9: 0x4000, 0x18fa: 0x4000,
0x18fc: 0x4000, 0x18fd: 0x4000, 0x18fe: 0x4000, 0x18ff: 0x4000,
// Block 0x64, offset 0x1900
0x1900: 0x4000, 0x1901: 0x4000, 0x1902: 0x4000, 0x1903: 0x4000, 0x1904: 0x4000, 0x1905: 0x4000,
0x1907: 0x4000, 0x1908: 0x4000, 0x1909: 0x4000, 0x190a: 0x4000, 0x190b: 0x4000,
0x190c: 0x4000, 0x190d: 0x4000, 0x190e: 0x4000, 0x190f: 0x4000, 0x1910: 0x4000, 0x1911: 0x4000,
0x1912: 0x4000, 0x1913: 0x4000, 0x1914: 0x4000, 0x1915: 0x4000, 0x1916: 0x4000, 0x1917: 0x4000,
0x1918: 0x4000, 0x1919: 0x4000, 0x191a: 0x4000, 0x191b: 0x4000, 0x191c: 0x4000, 0x191d: 0x4000,
0x191e: 0x4000, 0x191f: 0x4000, 0x1920: 0x4000, 0x1921: 0x4000, 0x1922: 0x4000, 0x1923: 0x4000,
0x1924: 0x4000, 0x1925: 0x4000, 0x1926: 0x4000, 0x1927: 0x4000, 0x1928: 0x4000, 0x1929: 0x4000,
0x192a: 0x4000, 0x192b: 0x4000, 0x192c: 0x4000, 0x192d: 0x4000, 0x192e: 0x4000, 0x192f: 0x4000,
0x1930: 0x4000, 0x1931: 0x4000, 0x1932: 0x4000, 0x1933: 0x4000, 0x1934: 0x4000, 0x1935: 0x4000,
0x1936: 0x4000, 0x1937: 0x4000, 0x1938: 0x4000, 0x1939: 0x4000, 0x193a: 0x4000, 0x193b: 0x4000,
0x193c: 0x4000, 0x193d: 0x4000, 0x193e: 0x4000, 0x193f: 0x4000,
// Block 0x65, offset 0x1940
0x1970: 0x4000, 0x1971: 0x4000, 0x1972: 0x4000, 0x1973: 0x4000, 0x1974: 0x4000, 0x1975: 0x4000,
0x1976: 0x4000, 0x1977: 0x4000, 0x1978: 0x4000, 0x1979: 0x4000, 0x197a: 0x4000, 0x197b: 0x4000,
0x197c: 0x4000,
// Block 0x66, offset 0x1980
0x1980: 0x4000, 0x1981: 0x4000, 0x1982: 0x4000, 0x1983: 0x4000, 0x1984: 0x4000, 0x1985: 0x4000,
0x1986: 0x4000, 0x1987: 0x4000, 0x1988: 0x4000,
0x1990: 0x4000, 0x1991: 0x4000,
0x1992: 0x4000, 0x1993: 0x4000, 0x1994: 0x4000, 0x1995: 0x4000, 0x1996: 0x4000, 0x1997: 0x4000,
0x1998: 0x4000, 0x1999: 0x4000, 0x199a: 0x4000, 0x199b: 0x4000, 0x199c: 0x4000, 0x199d: 0x4000,
0x199e: 0x4000, 0x199f: 0x4000, 0x19a0: 0x4000, 0x19a1: 0x4000, 0x19a2: 0x4000, 0x19a3: 0x4000,
0x19a4: 0x4000, 0x19a5: 0x4000, 0x19a6: 0x4000, 0x19a7: 0x4000, 0x19a8: 0x4000, 0x19a9: 0x4000,
0x19aa: 0x4000, 0x19ab: 0x4000, 0x19ac: 0x4000, 0x19ad: 0x4000, 0x19ae: 0x4000, 0x19af: 0x4000,
0x19b0: 0x4000, 0x19b1: 0x4000, 0x19b2: 0x4000, 0x19b3: 0x4000, 0x19b4: 0x4000, 0x19b5: 0x4000,
0x19b6: 0x4000, 0x19b7: 0x4000, 0x19b8: 0x4000, 0x19b9: 0x4000, 0x19ba: 0x4000, 0x19bb: 0x4000,
0x19bc: 0x4000, 0x19bd: 0x4000, 0x19bf: 0x4000,
// Block 0x67, offset 0x19c0
0x19c0: 0x4000, 0x19c1: 0x4000, 0x19c2: 0x4000, 0x19c3: 0x4000, 0x19c4: 0x4000, 0x19c5: 0x4000,
0x19ce: 0x4000, 0x19cf: 0x4000, 0x19d0: 0x4000, 0x19d1: 0x4000,
0x19d2: 0x4000, 0x19d3: 0x4000, 0x19d4: 0x4000, 0x19d5: 0x4000, 0x19d6: 0x4000, 0x19d7: 0x4000,
0x19d8: 0x4000, 0x19d9: 0x4000, 0x19da: 0x4000, 0x19db: 0x4000,
0x19e0: 0x4000, 0x19e1: 0x4000, 0x19e2: 0x4000, 0x19e3: 0x4000,
0x19e4: 0x4000, 0x19e5: 0x4000, 0x19e6: 0x4000, 0x19e7: 0x4000, 0x19e8: 0x4000,
0x19f0: 0x4000, 0x19f1: 0x4000, 0x19f2: 0x4000, 0x19f3: 0x4000, 0x19f4: 0x4000, 0x19f5: 0x4000,
0x19f6: 0x4000, 0x19f7: 0x4000, 0x19f8: 0x4000,
// Block 0x68, offset 0x1a00
0x1a00: 0x2000, 0x1a01: 0x2000, 0x1a02: 0x2000, 0x1a03: 0x2000, 0x1a04: 0x2000, 0x1a05: 0x2000,
0x1a06: 0x2000, 0x1a07: 0x2000, 0x1a08: 0x2000, 0x1a09: 0x2000, 0x1a0a: 0x2000, 0x1a0b: 0x2000,
0x1a0c: 0x2000, 0x1a0d: 0x2000, 0x1a0e: 0x2000, 0x1a0f: 0x2000, 0x1a10: 0x2000, 0x1a11: 0x2000,
0x1a12: 0x2000, 0x1a13: 0x2000, 0x1a14: 0x2000, 0x1a15: 0x2000, 0x1a16: 0x2000, 0x1a17: 0x2000,
0x1a18: 0x2000, 0x1a19: 0x2000, 0x1a1a: 0x2000, 0x1a1b: 0x2000, 0x1a1c: 0x2000, 0x1a1d: 0x2000,
0x1a1e: 0x2000, 0x1a1f: 0x2000, 0x1a20: 0x2000, 0x1a21: 0x2000, 0x1a22: 0x2000, 0x1a23: 0x2000,
0x1a24: 0x2000, 0x1a25: 0x2000, 0x1a26: 0x2000, 0x1a27: 0x2000, 0x1a28: 0x2000, 0x1a29: 0x2000,
0x1a2a: 0x2000, 0x1a2b: 0x2000, 0x1a2c: 0x2000, 0x1a2d: 0x2000, 0x1a2e: 0x2000, 0x1a2f: 0x2000,
0x1a30: 0x2000, 0x1a31: 0x2000, 0x1a32: 0x2000, 0x1a33: 0x2000, 0x1a34: 0x2000, 0x1a35: 0x2000,
0x1a36: 0x2000, 0x1a37: 0x2000, 0x1a38: 0x2000, 0x1a39: 0x2000, 0x1a3a: 0x2000, 0x1a3b: 0x2000,
0x1a3c: 0x2000, 0x1a3d: 0x2000,
}
// widthIndex: 23 blocks, 1472 entries, 1472 bytes
// Block 0 is the zero block.
var widthIndex = [1472]uint8{
// Block 0x0, offset 0x0
// Block 0x1, offset 0x40
// Block 0x2, offset 0x80
// Block 0x3, offset 0xc0
0xc2: 0x01, 0xc3: 0x02, 0xc4: 0x03, 0xc5: 0x04, 0xc7: 0x05,
0xc9: 0x06, 0xcb: 0x07, 0xcc: 0x08, 0xcd: 0x09, 0xce: 0x0a, 0xcf: 0x0b,
0xd0: 0x0c, 0xd1: 0x0d,
0xe1: 0x02, 0xe2: 0x03, 0xe3: 0x04, 0xe4: 0x05, 0xe5: 0x06, 0xe6: 0x06, 0xe7: 0x06,
0xe8: 0x06, 0xe9: 0x06, 0xea: 0x07, 0xeb: 0x06, 0xec: 0x06, 0xed: 0x08, 0xee: 0x09, 0xef: 0x0a,
0xf0: 0x10, 0xf3: 0x13, 0xf4: 0x14,
// Block 0x4, offset 0x100
0x104: 0x0e, 0x105: 0x0f,
// Block 0x5, offset 0x140
0x140: 0x10, 0x141: 0x11, 0x142: 0x12, 0x144: 0x13, 0x145: 0x14, 0x146: 0x15, 0x147: 0x16,
0x148: 0x17, 0x149: 0x18, 0x14a: 0x19, 0x14c: 0x1a, 0x14f: 0x1b,
0x151: 0x1c, 0x152: 0x08, 0x153: 0x1d, 0x154: 0x1e, 0x155: 0x1f, 0x156: 0x20, 0x157: 0x21,
0x158: 0x22, 0x159: 0x23, 0x15a: 0x24, 0x15b: 0x25, 0x15c: 0x26, 0x15d: 0x27, 0x15e: 0x28, 0x15f: 0x29,
0x166: 0x2a,
0x16c: 0x2b, 0x16d: 0x2c,
0x17a: 0x2d, 0x17b: 0x2e, 0x17c: 0x0e, 0x17d: 0x0e, 0x17e: 0x0e, 0x17f: 0x2f,
// Block 0x6, offset 0x180
0x180: 0x30, 0x181: 0x31, 0x182: 0x32, 0x183: 0x33, 0x184: 0x34, 0x185: 0x35, 0x186: 0x36, 0x187: 0x37,
0x188: 0x38, 0x189: 0x39, 0x18a: 0x0e, 0x18b: 0x0e, 0x18c: 0x0e, 0x18d: 0x0e, 0x18e: 0x0e, 0x18f: 0x0e,
0x190: 0x0e, 0x191: 0x0e, 0x192: 0x0e, 0x193: 0x0e, 0x194: 0x0e, 0x195: 0x0e, 0x196: 0x0e, 0x197: 0x0e,
0x198: 0x0e, 0x199: 0x0e, 0x19a: 0x0e, 0x19b: 0x0e, 0x19c: 0x0e, 0x19d: 0x0e, 0x19e: 0x0e, 0x19f: 0x0e,
0x1a0: 0x0e, 0x1a1: 0x0e, 0x1a2: 0x0e, 0x1a3: 0x0e, 0x1a4: 0x0e, 0x1a5: 0x0e, 0x1a6: 0x0e, 0x1a7: 0x0e,
0x1a8: 0x0e, 0x1a9: 0x0e, 0x1aa: 0x0e, 0x1ab: 0x0e, 0x1ac: 0x0e, 0x1ad: 0x0e, 0x1ae: 0x0e, 0x1af: 0x0e,
0x1b0: 0x0e, 0x1b1: 0x0e, 0x1b2: 0x0e, 0x1b3: 0x0e, 0x1b4: 0x0e, 0x1b5: 0x0e, 0x1b6: 0x0e, 0x1b7: 0x0e,
0x1b8: 0x0e, 0x1b9: 0x0e, 0x1ba: 0x0e, 0x1bb: 0x0e, 0x1bc: 0x0e, 0x1bd: 0x0e, 0x1be: 0x0e, 0x1bf: 0x0e,
// Block 0x7, offset 0x1c0
0x1c0: 0x0e, 0x1c1: 0x0e, 0x1c2: 0x0e, 0x1c3: 0x0e, 0x1c4: 0x0e, 0x1c5: 0x0e, 0x1c6: 0x0e, 0x1c7: 0x0e,
0x1c8: 0x0e, 0x1c9: 0x0e, 0x1ca: 0x0e, 0x1cb: 0x0e, 0x1cc: 0x0e, 0x1cd: 0x0e, 0x1ce: 0x0e, 0x1cf: 0x0e,
0x1d0: 0x0e, 0x1d1: 0x0e, 0x1d2: 0x0e, 0x1d3: 0x0e, 0x1d4: 0x0e, 0x1d5: 0x0e, 0x1d6: 0x0e, 0x1d7: 0x0e,
0x1d8: 0x0e, 0x1d9: 0x0e, 0x1da: 0x0e, 0x1db: 0x0e, 0x1dc: 0x0e, 0x1dd: 0x0e, 0x1de: 0x0e, 0x1df: 0x0e,
0x1e0: 0x0e, 0x1e1: 0x0e, 0x1e2: 0x0e, 0x1e3: 0x0e, 0x1e4: 0x0e, 0x1e5: 0x0e, 0x1e6: 0x0e, 0x1e7: 0x0e,
0x1e8: 0x0e, 0x1e9: 0x0e, 0x1ea: 0x0e, 0x1eb: 0x0e, 0x1ec: 0x0e, 0x1ed: 0x0e, 0x1ee: 0x0e, 0x1ef: 0x0e,
0x1f0: 0x0e, 0x1f1: 0x0e, 0x1f2: 0x0e, 0x1f3: 0x0e, 0x1f4: 0x0e, 0x1f5: 0x0e, 0x1f6: 0x0e,
0x1f8: 0x0e, 0x1f9: 0x0e, 0x1fa: 0x0e, 0x1fb: 0x0e, 0x1fc: 0x0e, 0x1fd: 0x0e, 0x1fe: 0x0e, 0x1ff: 0x0e,
// Block 0x8, offset 0x200
0x200: 0x0e, 0x201: 0x0e, 0x202: 0x0e, 0x203: 0x0e, 0x204: 0x0e, 0x205: 0x0e, 0x206: 0x0e, 0x207: 0x0e,
0x208: 0x0e, 0x209: 0x0e, 0x20a: 0x0e, 0x20b: 0x0e, 0x20c: 0x0e, 0x20d: 0x0e, 0x20e: 0x0e, 0x20f: 0x0e,
0x210: 0x0e, 0x211: 0x0e, 0x212: 0x0e, 0x213: 0x0e, 0x214: 0x0e, 0x215: 0x0e, 0x216: 0x0e, 0x217: 0x0e,
0x218: 0x0e, 0x219: 0x0e, 0x21a: 0x0e, 0x21b: 0x0e, 0x21c: 0x0e, 0x21d: 0x0e, 0x21e: 0x0e, 0x21f: 0x0e,
0x220: 0x0e, 0x221: 0x0e, 0x222: 0x0e, 0x223: 0x0e, 0x224: 0x0e, 0x225: 0x0e, 0x226: 0x0e, 0x227: 0x0e,
0x228: 0x0e, 0x229: 0x0e, 0x22a: 0x0e, 0x22b: 0x0e, 0x22c: 0x0e, 0x22d: 0x0e, 0x22e: 0x0e, 0x22f: 0x0e,
0x230: 0x0e, 0x231: 0x0e, 0x232: 0x0e, 0x233: 0x0e, 0x234: 0x0e, 0x235: 0x0e, 0x236: 0x0e, 0x237: 0x0e,
0x238: 0x0e, 0x239: 0x0e, 0x23a: 0x0e, 0x23b: 0x0e, 0x23c: 0x0e, 0x23d: 0x0e, 0x23e: 0x0e, 0x23f: 0x0e,
// Block 0x9, offset 0x240
0x240: 0x0e, 0x241: 0x0e, 0x242: 0x0e, 0x243: 0x0e, 0x244: 0x0e, 0x245: 0x0e, 0x246: 0x0e, 0x247: 0x0e,
0x248: 0x0e, 0x249: 0x0e, 0x24a: 0x0e, 0x24b: 0x0e, 0x24c: 0x0e, 0x24d: 0x0e, 0x24e: 0x0e, 0x24f: 0x0e,
0x250: 0x0e, 0x251: 0x0e, 0x252: 0x3a, 0x253: 0x3b,
0x265: 0x3c,
0x270: 0x0e, 0x271: 0x0e, 0x272: 0x0e, 0x273: 0x0e, 0x274: 0x0e, 0x275: 0x0e, 0x276: 0x0e, 0x277: 0x0e,
0x278: 0x0e, 0x279: 0x0e, 0x27a: 0x0e, 0x27b: 0x0e, 0x27c: 0x0e, 0x27d: 0x0e, 0x27e: 0x0e, 0x27f: 0x0e,
// Block 0xa, offset 0x280
0x280: 0x0e, 0x281: 0x0e, 0x282: 0x0e, 0x283: 0x0e, 0x284: 0x0e, 0x285: 0x0e, 0x286: 0x0e, 0x287: 0x0e,
0x288: 0x0e, 0x289: 0x0e, 0x28a: 0x0e, 0x28b: 0x0e, 0x28c: 0x0e, 0x28d: 0x0e, 0x28e: 0x0e, 0x28f: 0x0e,
0x290: 0x0e, 0x291: 0x0e, 0x292: 0x0e, 0x293: 0x0e, 0x294: 0x0e, 0x295: 0x0e, 0x296: 0x0e, 0x297: 0x0e,
0x298: 0x0e, 0x299: 0x0e, 0x29a: 0x0e, 0x29b: 0x0e, 0x29c: 0x0e, 0x29d: 0x0e, 0x29e: 0x3d,
// Block 0xb, offset 0x2c0
0x2c0: 0x08, 0x2c1: 0x08, 0x2c2: 0x08, 0x2c3: 0x08, 0x2c4: 0x08, 0x2c5: 0x08, 0x2c6: 0x08, 0x2c7: 0x08,
0x2c8: 0x08, 0x2c9: 0x08, 0x2ca: 0x08, 0x2cb: 0x08, 0x2cc: 0x08, 0x2cd: 0x08, 0x2ce: 0x08, 0x2cf: 0x08,
0x2d0: 0x08, 0x2d1: 0x08, 0x2d2: 0x08, 0x2d3: 0x08, 0x2d4: 0x08, 0x2d5: 0x08, 0x2d6: 0x08, 0x2d7: 0x08,
0x2d8: 0x08, 0x2d9: 0x08, 0x2da: 0x08, 0x2db: 0x08, 0x2dc: 0x08, 0x2dd: 0x08, 0x2de: 0x08, 0x2df: 0x08,
0x2e0: 0x08, 0x2e1: 0x08, 0x2e2: 0x08, 0x2e3: 0x08, 0x2e4: 0x08, 0x2e5: 0x08, 0x2e6: 0x08, 0x2e7: 0x08,
0x2e8: 0x08, 0x2e9: 0x08, 0x2ea: 0x08, 0x2eb: 0x08, 0x2ec: 0x08, 0x2ed: 0x08, 0x2ee: 0x08, 0x2ef: 0x08,
0x2f0: 0x08, 0x2f1: 0x08, 0x2f2: 0x08, 0x2f3: 0x08, 0x2f4: 0x08, 0x2f5: 0x08, 0x2f6: 0x08, 0x2f7: 0x08,
0x2f8: 0x08, 0x2f9: 0x08, 0x2fa: 0x08, 0x2fb: 0x08, 0x2fc: 0x08, 0x2fd: 0x08, 0x2fe: 0x08, 0x2ff: 0x08,
// Block 0xc, offset 0x300
0x300: 0x08, 0x301: 0x08, 0x302: 0x08, 0x303: 0x08, 0x304: 0x08, 0x305: 0x08, 0x306: 0x08, 0x307: 0x08,
0x308: 0x08, 0x309: 0x08, 0x30a: 0x08, 0x30b: 0x08, 0x30c: 0x08, 0x30d: 0x08, 0x30e: 0x08, 0x30f: 0x08,
0x310: 0x08, 0x311: 0x08, 0x312: 0x08, 0x313: 0x08, 0x314: 0x08, 0x315: 0x08, 0x316: 0x08, 0x317: 0x08,
0x318: 0x08, 0x319: 0x08, 0x31a: 0x08, 0x31b: 0x08, 0x31c: 0x08, 0x31d: 0x08, 0x31e: 0x08, 0x31f: 0x08,
0x320: 0x08, 0x321: 0x08, 0x322: 0x08, 0x323: 0x08, 0x324: 0x0e, 0x325: 0x0e, 0x326: 0x0e, 0x327: 0x0e,
0x328: 0x0e, 0x329: 0x0e, 0x32a: 0x0e, 0x32b: 0x0e,
0x338: 0x3e, 0x339: 0x3f, 0x33c: 0x40, 0x33d: 0x41, 0x33e: 0x42, 0x33f: 0x43,
// Block 0xd, offset 0x340
0x37f: 0x44,
// Block 0xe, offset 0x380
0x380: 0x0e, 0x381: 0x0e, 0x382: 0x0e, 0x383: 0x0e, 0x384: 0x0e, 0x385: 0x0e, 0x386: 0x0e, 0x387: 0x0e,
0x388: 0x0e, 0x389: 0x0e, 0x38a: 0x0e, 0x38b: 0x0e, 0x38c: 0x0e, 0x38d: 0x0e, 0x38e: 0x0e, 0x38f: 0x0e,
0x390: 0x0e, 0x391: 0x0e, 0x392: 0x0e, 0x393: 0x0e, 0x394: 0x0e, 0x395: 0x0e, 0x396: 0x0e, 0x397: 0x0e,
0x398: 0x0e, 0x399: 0x0e, 0x39a: 0x0e, 0x39b: 0x0e, 0x39c: 0x0e, 0x39d: 0x0e, 0x39e: 0x0e, 0x39f: 0x45,
0x3a0: 0x0e, 0x3a1: 0x0e, 0x3a2: 0x0e, 0x3a3: 0x0e, 0x3a4: 0x0e, 0x3a5: 0x0e, 0x3a6: 0x0e, 0x3a7: 0x0e,
0x3a8: 0x0e, 0x3a9: 0x0e, 0x3aa: 0x0e, 0x3ab: 0x0e, 0x3ac: 0x0e, 0x3ad: 0x0e, 0x3ae: 0x0e, 0x3af: 0x0e,
0x3b0: 0x0e, 0x3b1: 0x0e, 0x3b2: 0x0e, 0x3b3: 0x46, 0x3b4: 0x47,
// Block 0xf, offset 0x3c0
0x3ff: 0x48,
// Block 0x10, offset 0x400
0x400: 0x0e, 0x401: 0x0e, 0x402: 0x0e, 0x403: 0x0e, 0x404: 0x49, 0x405: 0x4a, 0x406: 0x0e, 0x407: 0x0e,
0x408: 0x0e, 0x409: 0x0e, 0x40a: 0x0e, 0x40b: 0x4b,
// Block 0x11, offset 0x440
0x440: 0x4c, 0x443: 0x4d, 0x444: 0x4e, 0x445: 0x4f, 0x446: 0x50,
0x448: 0x51, 0x449: 0x52, 0x44c: 0x53, 0x44d: 0x54, 0x44e: 0x55, 0x44f: 0x56,
0x450: 0x57, 0x451: 0x58, 0x452: 0x0e, 0x453: 0x59, 0x454: 0x5a, 0x455: 0x5b, 0x456: 0x5c, 0x457: 0x5d,
0x458: 0x0e, 0x459: 0x5e, 0x45a: 0x0e, 0x45b: 0x5f, 0x45f: 0x60,
0x464: 0x61, 0x465: 0x62, 0x466: 0x0e, 0x467: 0x0e,
0x469: 0x63, 0x46a: 0x64, 0x46b: 0x65,
// Block 0x12, offset 0x480
0x496: 0x0b, 0x497: 0x06,
0x498: 0x0c, 0x49a: 0x0d, 0x49b: 0x0e, 0x49f: 0x0f,
0x4a0: 0x06, 0x4a1: 0x06, 0x4a2: 0x06, 0x4a3: 0x06, 0x4a4: 0x06, 0x4a5: 0x06, 0x4a6: 0x06, 0x4a7: 0x06,
0x4a8: 0x06, 0x4a9: 0x06, 0x4aa: 0x06, 0x4ab: 0x06, 0x4ac: 0x06, 0x4ad: 0x06, 0x4ae: 0x06, 0x4af: 0x06,
0x4b0: 0x06, 0x4b1: 0x06, 0x4b2: 0x06, 0x4b3: 0x06, 0x4b4: 0x06, 0x4b5: 0x06, 0x4b6: 0x06, 0x4b7: 0x06,
0x4b8: 0x06, 0x4b9: 0x06, 0x4ba: 0x06, 0x4bb: 0x06, 0x4bc: 0x06, 0x4bd: 0x06, 0x4be: 0x06, 0x4bf: 0x06,
// Block 0x13, offset 0x4c0
0x4c4: 0x08, 0x4c5: 0x08, 0x4c6: 0x08, 0x4c7: 0x09,
// Block 0x14, offset 0x500
0x500: 0x08, 0x501: 0x08, 0x502: 0x08, 0x503: 0x08, 0x504: 0x08, 0x505: 0x08, 0x506: 0x08, 0x507: 0x08,
0x508: 0x08, 0x509: 0x08, 0x50a: 0x08, 0x50b: 0x08, 0x50c: 0x08, 0x50d: 0x08, 0x50e: 0x08, 0x50f: 0x08,
0x510: 0x08, 0x511: 0x08, 0x512: 0x08, 0x513: 0x08, 0x514: 0x08, 0x515: 0x08, 0x516: 0x08, 0x517: 0x08,
0x518: 0x08, 0x519: 0x08, 0x51a: 0x08, 0x51b: 0x08, 0x51c: 0x08, 0x51d: 0x08, 0x51e: 0x08, 0x51f: 0x08,
0x520: 0x08, 0x521: 0x08, 0x522: 0x08, 0x523: 0x08, 0x524: 0x08, 0x525: 0x08, 0x526: 0x08, 0x527: 0x08,
0x528: 0x08, 0x529: 0x08, 0x52a: 0x08, 0x52b: 0x08, 0x52c: 0x08, 0x52d: 0x08, 0x52e: 0x08, 0x52f: 0x08,
0x530: 0x08, 0x531: 0x08, 0x532: 0x08, 0x533: 0x08, 0x534: 0x08, 0x535: 0x08, 0x536: 0x08, 0x537: 0x08,
0x538: 0x08, 0x539: 0x08, 0x53a: 0x08, 0x53b: 0x08, 0x53c: 0x08, 0x53d: 0x08, 0x53e: 0x08, 0x53f: 0x66,
// Block 0x15, offset 0x540
0x560: 0x11,
0x570: 0x09, 0x571: 0x09, 0x572: 0x09, 0x573: 0x09, 0x574: 0x09, 0x575: 0x09, 0x576: 0x09, 0x577: 0x09,
0x578: 0x09, 0x579: 0x09, 0x57a: 0x09, 0x57b: 0x09, 0x57c: 0x09, 0x57d: 0x09, 0x57e: 0x09, 0x57f: 0x12,
// Block 0x16, offset 0x580
0x580: 0x09, 0x581: 0x09, 0x582: 0x09, 0x583: 0x09, 0x584: 0x09, 0x585: 0x09, 0x586: 0x09, 0x587: 0x09,
0x588: 0x09, 0x589: 0x09, 0x58a: 0x09, 0x58b: 0x09, 0x58c: 0x09, 0x58d: 0x09, 0x58e: 0x09, 0x58f: 0x12,
}
// inverseData contains 4-byte entries of the following format:
//
// <length> <modified UTF-8-encoded rune> <0 padding>
//
// The last byte of the UTF-8-encoded rune is xor-ed with the last byte of the
// UTF-8 encoding of the original rune. Mappings often have the following
// pattern:
//
// A -> A (U+FF21 -> U+0041)
// B -> B (U+FF22 -> U+0042)
// ...
//
// By xor-ing the last byte the same entry can be shared by many mappings. This
// reduces the total number of distinct entries by about two thirds.
// The resulting entry for the aforementioned mappings is
//
// { 0x01, 0xE0, 0x00, 0x00 }
//
// Using this entry to map U+FF21 (UTF-8 [EF BC A1]), we get
//
// E0 ^ A1 = 41.
//
// Similarly, for U+FF22 (UTF-8 [EF BC A2]), we get
//
// E0 ^ A2 = 42.
//
// Note that because of the xor-ing, the byte sequence stored in the entry is
// not valid UTF-8.
var inverseData = [150][4]byte{
{0x00, 0x00, 0x00, 0x00},
{0x03, 0xe3, 0x80, 0xa0},
{0x03, 0xef, 0xbc, 0xa0},
{0x03, 0xef, 0xbc, 0xe0},
{0x03, 0xef, 0xbd, 0xe0},
{0x03, 0xef, 0xbf, 0x02},
{0x03, 0xef, 0xbf, 0x00},
{0x03, 0xef, 0xbf, 0x0e},
{0x03, 0xef, 0xbf, 0x0c},
{0x03, 0xef, 0xbf, 0x0f},
{0x03, 0xef, 0xbf, 0x39},
{0x03, 0xef, 0xbf, 0x3b},
{0x03, 0xef, 0xbf, 0x3f},
{0x03, 0xef, 0xbf, 0x2a},
{0x03, 0xef, 0xbf, 0x0d},
{0x03, 0xef, 0xbf, 0x25},
{0x03, 0xef, 0xbd, 0x1a},
{0x03, 0xef, 0xbd, 0x26},
{0x01, 0xa0, 0x00, 0x00},
{0x03, 0xef, 0xbd, 0x25},
{0x03, 0xef, 0xbd, 0x23},
{0x03, 0xef, 0xbd, 0x2e},
{0x03, 0xef, 0xbe, 0x07},
{0x03, 0xef, 0xbe, 0x05},
{0x03, 0xef, 0xbd, 0x06},
{0x03, 0xef, 0xbd, 0x13},
{0x03, 0xef, 0xbd, 0x0b},
{0x03, 0xef, 0xbd, 0x16},
{0x03, 0xef, 0xbd, 0x0c},
{0x03, 0xef, 0xbd, 0x15},
{0x03, 0xef, 0xbd, 0x0d},
{0x03, 0xef, 0xbd, 0x1c},
{0x03, 0xef, 0xbd, 0x02},
{0x03, 0xef, 0xbd, 0x1f},
{0x03, 0xef, 0xbd, 0x1d},
{0x03, 0xef, 0xbd, 0x17},
{0x03, 0xef, 0xbd, 0x08},
{0x03, 0xef, 0xbd, 0x09},
{0x03, 0xef, 0xbd, 0x0e},
{0x03, 0xef, 0xbd, 0x04},
{0x03, 0xef, 0xbd, 0x05},
{0x03, 0xef, 0xbe, 0x3f},
{0x03, 0xef, 0xbe, 0x00},
{0x03, 0xef, 0xbd, 0x2c},
{0x03, 0xef, 0xbe, 0x06},
{0x03, 0xef, 0xbe, 0x0c},
{0x03, 0xef, 0xbe, 0x0f},
{0x03, 0xef, 0xbe, 0x0d},
{0x03, 0xef, 0xbe, 0x0b},
{0x03, 0xef, 0xbe, 0x19},
{0x03, 0xef, 0xbe, 0x15},
{0x03, 0xef, 0xbe, 0x11},
{0x03, 0xef, 0xbe, 0x31},
{0x03, 0xef, 0xbe, 0x33},
{0x03, 0xef, 0xbd, 0x0f},
{0x03, 0xef, 0xbe, 0x30},
{0x03, 0xef, 0xbe, 0x3e},
{0x03, 0xef, 0xbe, 0x32},
{0x03, 0xef, 0xbe, 0x36},
{0x03, 0xef, 0xbd, 0x14},
{0x03, 0xef, 0xbe, 0x2e},
{0x03, 0xef, 0xbd, 0x1e},
{0x03, 0xef, 0xbe, 0x10},
{0x03, 0xef, 0xbf, 0x13},
{0x03, 0xef, 0xbf, 0x15},
{0x03, 0xef, 0xbf, 0x17},
{0x03, 0xef, 0xbf, 0x1f},
{0x03, 0xef, 0xbf, 0x1d},
{0x03, 0xef, 0xbf, 0x1b},
{0x03, 0xef, 0xbf, 0x09},
{0x03, 0xef, 0xbf, 0x0b},
{0x03, 0xef, 0xbf, 0x37},
{0x03, 0xef, 0xbe, 0x04},
{0x01, 0xe0, 0x00, 0x00},
{0x03, 0xe2, 0xa6, 0x1a},
{0x03, 0xe2, 0xa6, 0x26},
{0x03, 0xe3, 0x80, 0x23},
{0x03, 0xe3, 0x80, 0x2e},
{0x03, 0xe3, 0x80, 0x25},
{0x03, 0xe3, 0x83, 0x1e},
{0x03, 0xe3, 0x83, 0x14},
{0x03, 0xe3, 0x82, 0x06},
{0x03, 0xe3, 0x82, 0x0b},
{0x03, 0xe3, 0x82, 0x0c},
{0x03, 0xe3, 0x82, 0x0d},
{0x03, 0xe3, 0x82, 0x02},
{0x03, 0xe3, 0x83, 0x0f},
{0x03, 0xe3, 0x83, 0x08},
{0x03, 0xe3, 0x83, 0x09},
{0x03, 0xe3, 0x83, 0x2c},
{0x03, 0xe3, 0x83, 0x0c},
{0x03, 0xe3, 0x82, 0x13},
{0x03, 0xe3, 0x82, 0x16},
{0x03, 0xe3, 0x82, 0x15},
{0x03, 0xe3, 0x82, 0x1c},
{0x03, 0xe3, 0x82, 0x1f},
{0x03, 0xe3, 0x82, 0x1d},
{0x03, 0xe3, 0x82, 0x1a},
{0x03, 0xe3, 0x82, 0x17},
{0x03, 0xe3, 0x82, 0x08},
{0x03, 0xe3, 0x82, 0x09},
{0x03, 0xe3, 0x82, 0x0e},
{0x03, 0xe3, 0x82, 0x04},
{0x03, 0xe3, 0x82, 0x05},
{0x03, 0xe3, 0x82, 0x3f},
{0x03, 0xe3, 0x83, 0x00},
{0x03, 0xe3, 0x83, 0x06},
{0x03, 0xe3, 0x83, 0x05},
{0x03, 0xe3, 0x83, 0x0d},
{0x03, 0xe3, 0x83, 0x0b},
{0x03, 0xe3, 0x83, 0x07},
{0x03, 0xe3, 0x83, 0x19},
{0x03, 0xe3, 0x83, 0x15},
{0x03, 0xe3, 0x83, 0x11},
{0x03, 0xe3, 0x83, 0x31},
{0x03, 0xe3, 0x83, 0x33},
{0x03, 0xe3, 0x83, 0x30},
{0x03, 0xe3, 0x83, 0x3e},
{0x03, 0xe3, 0x83, 0x32},
{0x03, 0xe3, 0x83, 0x36},
{0x03, 0xe3, 0x83, 0x2e},
{0x03, 0xe3, 0x82, 0x07},
{0x03, 0xe3, 0x85, 0x04},
{0x03, 0xe3, 0x84, 0x10},
{0x03, 0xe3, 0x85, 0x30},
{0x03, 0xe3, 0x85, 0x0d},
{0x03, 0xe3, 0x85, 0x13},
{0x03, 0xe3, 0x85, 0x15},
{0x03, 0xe3, 0x85, 0x17},
{0x03, 0xe3, 0x85, 0x1f},
{0x03, 0xe3, 0x85, 0x1d},
{0x03, 0xe3, 0x85, 0x1b},
{0x03, 0xe3, 0x85, 0x09},
{0x03, 0xe3, 0x85, 0x0f},
{0x03, 0xe3, 0x85, 0x0b},
{0x03, 0xe3, 0x85, 0x37},
{0x03, 0xe3, 0x85, 0x3b},
{0x03, 0xe3, 0x85, 0x39},
{0x03, 0xe3, 0x85, 0x3f},
{0x02, 0xc2, 0x02, 0x00},
{0x02, 0xc2, 0x0e, 0x00},
{0x02, 0xc2, 0x0c, 0x00},
{0x02, 0xc2, 0x00, 0x00},
{0x03, 0xe2, 0x82, 0x0f},
{0x03, 0xe2, 0x94, 0x2a},
{0x03, 0xe2, 0x86, 0x39},
{0x03, 0xe2, 0x86, 0x3b},
{0x03, 0xe2, 0x86, 0x3f},
{0x03, 0xe2, 0x96, 0x0d},
{0x03, 0xe2, 0x97, 0x25},
}
// Total table size 15512 bytes (15KiB)
// 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.
package width
import (
"unicode/utf8"
"golang.org/x/text/transform"
)
type foldTransform struct {
transform.NopResetter
}
func (foldTransform) Span(src []byte, atEOF bool) (n int, err error) {
for n < len(src) {
if src[n] < utf8.RuneSelf {
// ASCII fast path.
for n++; n < len(src) && src[n] < utf8.RuneSelf; n++ {
}
continue
}
v, size := trie.lookup(src[n:])
if size == 0 { // incomplete UTF-8 encoding
if !atEOF {
err = transform.ErrShortSrc
} else {
n = len(src)
}
break
}
if elem(v)&tagNeedsFold != 0 {
err = transform.ErrEndOfSpan
break
}
n += size
}
return n, err
}
func (foldTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
for nSrc < len(src) {
if src[nSrc] < utf8.RuneSelf {
// ASCII fast path.
start, end := nSrc, len(src)
if d := len(dst) - nDst; d < end-start {
end = nSrc + d
}
for nSrc++; nSrc < end && src[nSrc] < utf8.RuneSelf; nSrc++ {
}
n := copy(dst[nDst:], src[start:nSrc])
if nDst += n; nDst == len(dst) {
nSrc = start + n
if nSrc == len(src) {
return nDst, nSrc, nil
}
if src[nSrc] < utf8.RuneSelf {
return nDst, nSrc, transform.ErrShortDst
}
}
continue
}
v, size := trie.lookup(src[nSrc:])
if size == 0 { // incomplete UTF-8 encoding
if !atEOF {
return nDst, nSrc, transform.ErrShortSrc
}
size = 1 // gobble 1 byte
}
if elem(v)&tagNeedsFold == 0 {
if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
return nDst, nSrc, transform.ErrShortDst
}
nDst += size
} else {
data := inverseData[byte(v)]
if len(dst)-nDst < int(data[0]) {
return nDst, nSrc, transform.ErrShortDst
}
i := 1
for end := int(data[0]); i < end; i++ {
dst[nDst] = data[i]
nDst++
}
dst[nDst] = data[i] ^ src[nSrc+size-1]
nDst++
}
nSrc += size
}
return nDst, nSrc, nil
}
type narrowTransform struct {
transform.NopResetter
}
func (narrowTransform) Span(src []byte, atEOF bool) (n int, err error) {
for n < len(src) {
if src[n] < utf8.RuneSelf {
// ASCII fast path.
for n++; n < len(src) && src[n] < utf8.RuneSelf; n++ {
}
continue
}
v, size := trie.lookup(src[n:])
if size == 0 { // incomplete UTF-8 encoding
if !atEOF {
err = transform.ErrShortSrc
} else {
n = len(src)
}
break
}
if k := elem(v).kind(); byte(v) == 0 || k != EastAsianFullwidth && k != EastAsianWide && k != EastAsianAmbiguous {
} else {
err = transform.ErrEndOfSpan
break
}
n += size
}
return n, err
}
func (narrowTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
for nSrc < len(src) {
if src[nSrc] < utf8.RuneSelf {
// ASCII fast path.
start, end := nSrc, len(src)
if d := len(dst) - nDst; d < end-start {
end = nSrc + d
}
for nSrc++; nSrc < end && src[nSrc] < utf8.RuneSelf; nSrc++ {
}
n := copy(dst[nDst:], src[start:nSrc])
if nDst += n; nDst == len(dst) {
nSrc = start + n
if nSrc == len(src) {
return nDst, nSrc, nil
}
if src[nSrc] < utf8.RuneSelf {
return nDst, nSrc, transform.ErrShortDst
}
}
continue
}
v, size := trie.lookup(src[nSrc:])
if size == 0 { // incomplete UTF-8 encoding
if !atEOF {
return nDst, nSrc, transform.ErrShortSrc
}
size = 1 // gobble 1 byte
}
if k := elem(v).kind(); byte(v) == 0 || k != EastAsianFullwidth && k != EastAsianWide && k != EastAsianAmbiguous {
if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
return nDst, nSrc, transform.ErrShortDst
}
nDst += size
} else {
data := inverseData[byte(v)]
if len(dst)-nDst < int(data[0]) {
return nDst, nSrc, transform.ErrShortDst
}
i := 1
for end := int(data[0]); i < end; i++ {
dst[nDst] = data[i]
nDst++
}
dst[nDst] = data[i] ^ src[nSrc+size-1]
nDst++
}
nSrc += size
}
return nDst, nSrc, nil
}
type wideTransform struct {
transform.NopResetter
}
func (wideTransform) Span(src []byte, atEOF bool) (n int, err error) {
for n < len(src) {
// TODO: Consider ASCII fast path. Special-casing ASCII handling can
// reduce the ns/op of BenchmarkWideASCII by about 30%. This is probably
// not enough to warrant the extra code and complexity.
v, size := trie.lookup(src[n:])
if size == 0 { // incomplete UTF-8 encoding
if !atEOF {
err = transform.ErrShortSrc
} else {
n = len(src)
}
break
}
if k := elem(v).kind(); byte(v) == 0 || k != EastAsianHalfwidth && k != EastAsianNarrow {
} else {
err = transform.ErrEndOfSpan
break
}
n += size
}
return n, err
}
func (wideTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
for nSrc < len(src) {
// TODO: Consider ASCII fast path. Special-casing ASCII handling can
// reduce the ns/op of BenchmarkWideASCII by about 30%. This is probably
// not enough to warrant the extra code and complexity.
v, size := trie.lookup(src[nSrc:])
if size == 0 { // incomplete UTF-8 encoding
if !atEOF {
return nDst, nSrc, transform.ErrShortSrc
}
size = 1 // gobble 1 byte
}
if k := elem(v).kind(); byte(v) == 0 || k != EastAsianHalfwidth && k != EastAsianNarrow {
if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
return nDst, nSrc, transform.ErrShortDst
}
nDst += size
} else {
data := inverseData[byte(v)]
if len(dst)-nDst < int(data[0]) {
return nDst, nSrc, transform.ErrShortDst
}
i := 1
for end := int(data[0]); i < end; i++ {
dst[nDst] = data[i]
nDst++
}
dst[nDst] = data[i] ^ src[nSrc+size-1]
nDst++
}
nSrc += size
}
return nDst, nSrc, nil
}
// 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.
//go:generate stringer -type=Kind
//go:generate go run gen.go gen_common.go gen_trieval.go
// Package width provides functionality for handling different widths in text.
//
// Wide characters behave like ideographs; they tend to allow line breaks after
// each character and remain upright in vertical text layout. Narrow characters
// are kept together in words or runs that are rotated sideways in vertical text
// layout.
//
// For more information, see https://unicode.org/reports/tr11/.
package width // import "golang.org/x/text/width"
import (
"unicode/utf8"
"golang.org/x/text/transform"
)
// TODO
// 1) Reduce table size by compressing blocks.
// 2) API proposition for computing display length
// (approximation, fixed pitch only).
// 3) Implement display length.
// Kind indicates the type of width property as defined in https://unicode.org/reports/tr11/.
type Kind int
const (
// Neutral characters do not occur in legacy East Asian character sets.
Neutral Kind = iota
// EastAsianAmbiguous characters that can be sometimes wide and sometimes
// narrow and require additional information not contained in the character
// code to further resolve their width.
EastAsianAmbiguous
// EastAsianWide characters are wide in its usual form. They occur only in
// the context of East Asian typography. These runes may have explicit
// halfwidth counterparts.
EastAsianWide
// EastAsianNarrow characters are narrow in its usual form. They often have
// fullwidth counterparts.
EastAsianNarrow
// Note: there exist Narrow runes that do not have fullwidth or wide
// counterparts, despite what the definition says (e.g. U+27E6).
// EastAsianFullwidth characters have a compatibility decompositions of type
// wide that map to a narrow counterpart.
EastAsianFullwidth
// EastAsianHalfwidth characters have a compatibility decomposition of type
// narrow that map to a wide or ambiguous counterpart, plus U+20A9 ₩ WON
// SIGN.
EastAsianHalfwidth
// Note: there exist runes that have a halfwidth counterparts but that are
// classified as Ambiguous, rather than wide (e.g. U+2190).
)
// TODO: the generated tries need to return size 1 for invalid runes for the
// width to be computed correctly (each byte should render width 1)
var trie = newWidthTrie(0)
// Lookup reports the Properties of the first rune in b and the number of bytes
// of its UTF-8 encoding.
func Lookup(b []byte) (p Properties, size int) {
v, sz := trie.lookup(b)
return Properties{elem(v), b[sz-1]}, sz
}
// LookupString reports the Properties of the first rune in s and the number of
// bytes of its UTF-8 encoding.
func LookupString(s string) (p Properties, size int) {
v, sz := trie.lookupString(s)
return Properties{elem(v), s[sz-1]}, sz
}
// LookupRune reports the Properties of rune r.
func LookupRune(r rune) Properties {
var buf [4]byte
n := utf8.EncodeRune(buf[:], r)
v, _ := trie.lookup(buf[:n])
last := byte(r)
if r >= utf8.RuneSelf {
last = 0x80 + byte(r&0x3f)
}
return Properties{elem(v), last}
}
// Properties provides access to width properties of a rune.
type Properties struct {
elem elem
last byte
}
func (e elem) kind() Kind {
return Kind(e >> typeShift)
}
// Kind returns the Kind of a rune as defined in Unicode TR #11.
// See https://unicode.org/reports/tr11/ for more details.
func (p Properties) Kind() Kind {
return p.elem.kind()
}
// Folded returns the folded variant of a rune or 0 if the rune is canonical.
func (p Properties) Folded() rune {
if p.elem&tagNeedsFold != 0 {
buf := inverseData[byte(p.elem)]
buf[buf[0]] ^= p.last
r, _ := utf8.DecodeRune(buf[1 : 1+buf[0]])
return r
}
return 0
}
// Narrow returns the narrow variant of a rune or 0 if the rune is already
// narrow or doesn't have a narrow variant.
func (p Properties) Narrow() rune {
if k := p.elem.kind(); byte(p.elem) != 0 && (k == EastAsianFullwidth || k == EastAsianWide || k == EastAsianAmbiguous) {
buf := inverseData[byte(p.elem)]
buf[buf[0]] ^= p.last
r, _ := utf8.DecodeRune(buf[1 : 1+buf[0]])
return r
}
return 0
}
// Wide returns the wide variant of a rune or 0 if the rune is already
// wide or doesn't have a wide variant.
func (p Properties) Wide() rune {
if k := p.elem.kind(); byte(p.elem) != 0 && (k == EastAsianHalfwidth || k == EastAsianNarrow) {
buf := inverseData[byte(p.elem)]
buf[buf[0]] ^= p.last
r, _ := utf8.DecodeRune(buf[1 : 1+buf[0]])
return r
}
return 0
}
// TODO for Properties:
// - Add Fullwidth/Halfwidth or Inverted methods for computing variants
// mapping.
// - Add width information (including information on non-spacing runes).
// Transformer implements the transform.Transformer interface.
type Transformer struct {
t transform.SpanningTransformer
}
// Reset implements the transform.Transformer interface.
func (t Transformer) Reset() { t.t.Reset() }
// Transform implements the transform.Transformer interface.
func (t Transformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
return t.t.Transform(dst, src, atEOF)
}
// Span implements the transform.SpanningTransformer interface.
func (t Transformer) Span(src []byte, atEOF bool) (n int, err error) {
return t.t.Span(src, atEOF)
}
// Bytes returns a new byte slice with the result of applying t to b.
func (t Transformer) Bytes(b []byte) []byte {
b, _, _ = transform.Bytes(t, b)
return b
}
// String returns a string with the result of applying t to s.
func (t Transformer) String(s string) string {
s, _, _ = transform.String(t, s)
return s
}
var (
// Fold is a transform that maps all runes to their canonical width.
//
// Note that the NFKC and NFKD transforms in golang.org/x/text/unicode/norm
// provide a more generic folding mechanism.
Fold Transformer = Transformer{foldTransform{}}
// Widen is a transform that maps runes to their wide variant, if
// available.
Widen Transformer = Transformer{wideTransform{}}
// Narrow is a transform that maps runes to their narrow variant, if
// available.
Narrow Transformer = Transformer{narrowTransform{}}
)
// TODO: Consider the following options:
// - Treat Ambiguous runes that have a halfwidth counterpart as wide, or some
// generalized variant of this.
// - Consider a wide Won character to be the default width (or some generalized
// variant of this).
// - Filter the set of characters that gets converted (the preferred approach is
// to allow applying filters to transforms).